EKSでMattermostを構築した話：1. VPC作成編

## 今回、作成するもの
- CustomerVPC
- 踏み台サーバ

## CustomerVPCの作成
- 実はこのVPC、最初はeksctlでVPCとEKSクラスターをまとめて作成したのですが、ワーカーノードのインスタンスタイプを当初予定したタイプとは違う内容で作ってしまったので、ワーカーノードだけ作成し直そうとした時に、eksctlでワーカーノードだけ作り直すってできるんだっけ？って事になりました。
- 対応方法はありそうでしたが、あまり時間もなかったので、EKSクラスターを削除してもう一度eksctlを実行する方針をとるようにしました。
- しかし、この時に既に踏み台サーバも作成していたので、EKSクラスターを削除するために踏み台サーバも削除しないといけないことになり(VPC内に`利用しているEC2=踏み台サーバ`がいるのでVPCが削除できない)、何この密結合っていうことになりました。

### VPCはCloudFormationで作成
- ということで上記の密結合を避けるためにVPCはCloudFormationで作成ということにしました。
- <details><summary>サンプルCloudFormationテンプレート (クリックして展開できます)</summary><div>

```yaml
AWSTemplateFormatVersion: "2010-09-09"

Description: 
  VPC, 3 private Subnets, 3 public subnets, NAT Gateway, Internet Gateway and Route Tables Create

# ------------------------------------------------------------#
# Input Parameters
# ------------------------------------------------------------# 

Parameters:
  EnvironmentName:
    Description: An environment name that is prefixed to resource names
    Type: String

  VpcCIDR:
    Description: Please enter the IP range (CIDR notation) for this VPC
    Type: String
    Default: 10.0.0.0/16

  PublicSubnet1CIDR:
    Description: Please enter the IP range (CIDR notation) for the public subnet in the first Availability Zone
    Type: String
    Default: 10.0.10.0/24

  PublicSubnet2CIDR:
    Description: Please enter the IP range (CIDR notation) for the public subnet in the second Availability Zone
    Type: String
    Default: 10.0.11.0/24

  PublicSubnet3CIDR:
    Description: Please enter the IP range (CIDR notation) for the public subnet in the third Availability Zone
    Type: String
    Default: 10.0.12.0/24

  PrivateSubnet1CIDR:
    Description: Please enter the IP range (CIDR notation) for the private subnet in the first Availability Zone
    Type: String
    Default: 10.0.20.0/24

  PrivateSubnet2CIDR:
    Description: Please enter the IP range (CIDR notation) for the private subnet in the second Availability Zone
    Type: String
    Default: 10.0.21.0/24

  PrivateSubnet3CIDR:
    Description: Please enter the IP range (CIDR notation) for the private subnet in the third Availability Zone
    Type: String
    Default: 10.0.22.0/24


Resources:
# ------------------------------------------------------------#
# VPC
# ------------------------------------------------------------# 
  VPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: !Ref VpcCIDR
      EnableDnsSupport: true
      EnableDnsHostnames: true
      Tags:
        - Key: Name
          Value: !Ref EnvironmentName

  InternetGateway:
    Type: AWS::EC2::InternetGateway
    Properties:
      Tags:
        - Key: Name
          Value: !Ref EnvironmentName

  InternetGatewayAttachment:
    Type: AWS::EC2::VPCGatewayAttachment
    Properties:
      InternetGatewayId: !Ref InternetGateway
      VpcId: !Ref VPC

  NoIngressSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupName: "no-ingress-sg"
      GroupDescription: "Security group with no ingress rule"
      VpcId: !Ref VPC
      
  NatGatewayEIP:
    Type: AWS::EC2::EIP
    DependsOn: InternetGatewayAttachment
    Properties:
      Domain: vpc

  NatGateway:
    Type: AWS::EC2::NatGateway
    Properties:
      AllocationId: !GetAtt NatGatewayEIP.AllocationId
      SubnetId: !Ref PublicSubnet1
      
# ------------------------------------------------------------#
# PublicSubnet
# ------------------------------------------------------------# 
  PublicSubnet1:
    Type: AWS::EC2::Subnet
    DependsOn: InternetGatewayAttachment
    Properties:
      VpcId: !Ref VPC
      AvailabilityZone: !Select [ 0, !GetAZs "" ]
      CidrBlock: !Ref PublicSubnet1CIDR
      MapPublicIpOnLaunch: true
      Tags:
        - Key: Name
          Value: !Sub ${EnvironmentName} Public Subnet (AZ1)

  PublicSubnet2:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref VPC
      AvailabilityZone: !Select [ 1, !GetAZs  "" ]
      CidrBlock: !Ref PublicSubnet2CIDR
      MapPublicIpOnLaunch: true
      Tags:
        - Key: Name
          Value: !Sub ${EnvironmentName} Public Subnet (AZ2)

  PublicSubnet3:      
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref VPC
      AvailabilityZone: !Select [ 2, !GetAZs  "" ]
      CidrBlock: !Ref PublicSubnet3CIDR
      MapPublicIpOnLaunch: true
      Tags:
        - Key: Name
          Value: !Sub ${EnvironmentName} Public Subnet (AZ3)

# ------------------------------------------------------------#
# PrivateSubnet
# ------------------------------------------------------------# 
  PrivateSubnet1:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref VPC
      AvailabilityZone: !Select [ 0, !GetAZs  "" ]
      CidrBlock: !Ref PrivateSubnet1CIDR
      MapPublicIpOnLaunch: false
      Tags:
        - Key: Name
          Value: !Sub ${EnvironmentName} Private Subnet (AZ1)

  PrivateSubnet2:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref VPC
      AvailabilityZone: !Select [ 1, !GetAZs  "" ]
      CidrBlock: !Ref PrivateSubnet2CIDR
      MapPublicIpOnLaunch: false
      Tags:
        - Key: Name
          Value: !Sub ${EnvironmentName} Private Subnet (AZ2)

  PrivateSubnet3:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref VPC
      AvailabilityZone: !Select [ 2, !GetAZs  "" ]
      CidrBlock: !Ref PrivateSubnet3CIDR
      MapPublicIpOnLaunch: false
      Tags:
        - Key: Name
          Value: !Sub ${EnvironmentName} Private Subnet (AZ3)

# ------------------------------------------------------------#
# RouteTable
# ------------------------------------------------------------# 
  PublicRouteTable:
    Type: AWS::EC2::RouteTable
    DependsOn: InternetGatewayAttachment
    Properties:
      VpcId: !Ref VPC
      Tags:
        - Key: Name
          Value: !Sub ${EnvironmentName} Public Routes

  PrivateRouteTable1:
    Type: AWS::EC2::RouteTable
    DependsOn : NatGateway
    Properties:
      VpcId: !Ref VPC
      Tags:
        - Key: Name
          Value: !Sub ${EnvironmentName} Private Routes (AZ1)

  PrivateRouteTable2:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref VPC
      Tags:
        - Key: Name
          Value: !Sub ${EnvironmentName} Private Routes (AZ2)

  PrivateRouteTable3:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref VPC
      Tags:
        - Key: Nasme
          Value: !Sub ${EnvironmentName} Private Routes (AZ3)

# ------------------------------------------------------------#
# Routing
# ------------------------------------------------------------# 
  DefaultPublicRoute:
    Type: AWS::EC2::Route
    DependsOn: InternetGatewayAttachment
    Properties:
      RouteTableId: !Ref PublicRouteTable
      DestinationCidrBlock: 0.0.0.0/0
      GatewayId: !Ref InternetGateway

  DefaultPrivateRoute1:
    Type: AWS::EC2::Route
    Properties:
      RouteTableId: !Ref PrivateRouteTable1
      DestinationCidrBlock: 0.0.0.0/0
      NatGatewayId: !Ref NatGateway

# ------------------------------------------------------------#
# RouteTable Associate
# ------------------------------------------------------------# 
  PublicSubnet1RouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      RouteTableId: !Ref PublicRouteTable
      SubnetId: !Ref PublicSubnet1

  PublicSubnet2RouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      RouteTableId: !Ref PublicRouteTable
      SubnetId: !Ref PublicSubnet2

  PublicSubnet3RouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      RouteTableId: !Ref PublicRouteTable
      SubnetId: !Ref PublicSubnet3

  PrivateSubnet1RouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      RouteTableId: !Ref PrivateRouteTable1
      SubnetId: !Ref PrivateSubnet1

  PrivateSubnet2RouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      RouteTableId: !Ref PrivateRouteTable1
      SubnetId: !Ref PrivateSubnet2

  PrivateSubnet3RouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      RouteTableId: !Ref PrivateRouteTable1
      SubnetId: !Ref PrivateSubnet3

# ------------------------------------------------------------#
# Outputs
# ------------------------------------------------------------# 
Outputs:
  VPC:
    Description: A reference to the created VPC
    Value: !Ref VPC

  PublicSubnets:
    Description: A list of the public subnets
    Value: !Join [ ",", [ !Ref PublicSubnet1, !Ref PublicSubnet2, !Ref PublicSubnet3 ]]

  PrivateSubnets:
    Description: A list of the private subnets
    Value: !Join [ ",", [ !Ref PrivateSubnet1, !Ref PrivateSubnet2 , !Ref PrivateSubnet3]]

  PublicSubnet1:
    Description: A reference to the public subnet in the 1st Availability Zone
    Value: !Ref PublicSubnet1

  PublicSubnet2:
    Description: A reference to the public subnet in the 2nd Availability Zone
    Value: !Ref PublicSubnet2

  PublicSubnet3:
    Description: A reference to the public subnet in the 1st Availability Zone
    Value: !Ref PublicSubnet3

  PrivateSubnet1:
    Description: A reference to the private subnet in the 1st Availability Zone
    Value: !Ref PrivateSubnet1

  PrivateSubnet2:
    Description: A reference to the private subnet in the 2nd Availability Zone
    Value: !Ref PrivateSubnet2

  PrivateSubnet3:
    Description: A reference to the private subnet in the 2nd Availability Zone
    Value: !Ref PrivateSubnet3

  NoIngressSecurityGroup:
    Description: Security group with no ingress rule
    Value: !Ref NoIngressSecurityGroup
```

</div></details>

### ちなみにCustomerVPCとは？
- 以下の公式の情報にありますが、EKSクラスターを作成すると以下のような構成ができあがります。
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/415280/44ba36ed-11a3-919e-f8eb-16cca6044c3d.png)
    - [Amazon EKS ワーカーノードの謎を解くクラスターネットワーク | Amazon Web Services ブログ](https://aws.amazon.com/jp/blogs/news/de-mystifying-cluster-networking-for-amazon-eks-worker-nodes/)
        - 今回CloudFormationで作成した`CustomerVPC`はワーカーノードが動くVPCってことですね。図の右下にあるVPCです。ここを作成しました。

### 補足
- 今回のCloudFormationでは設定していないのですが、以下の参考URLにあるようにPublicSubnetとPrivateSubnetを区別するためのタグ付けはしておいた方がいいなと思いました。
- PublicSubnet用のタグ

```
Tags:  
- Key: kubernetes.io/role/elb  
  Value: 1  
```

- PrivateSubnet用のタグ

```
Tags:
  - Key: kubernetes.io/role/internal-elb
    Value: 1
```

- 参考URL
    - [「eksctl」コマンドを使ったAmazon EKS構築入門 | Developers.IO](https://dev.classmethod.jp/articles/getting-started-amazon-eks-with-eksctl/)
    - 上記参考URLの`「eksctl」コマンドの使い方 (応用編)`という箇所にeksctlとCloudFormationの使い分けパターンの記載がありとても参考になります！
    - 今回の対応は`応用編のパターン1`に当てはまると思います。

## 踏み台サーバの作成
- 今回は`Ubuntu 18.04.5 LTS`を利用しています
- この踏み台サーバにRancherをインストールしました。
- Rancherを使うことでアプリケーションを動かした時にどんなpodが動いているかや、どんなボリュームができているか等をGUIで見られるようになり、便利さを感じました。
    - 踏み台サーバ作成時には上記の便利さは知る由もなかったのですが、この後の手順でMattermostを動かしていく上で、その便利さを実感したというのが正直なところです。

### Rancherのインストール 
- 以下のコマンドでインストールしました。以下のドキュメントを参考にしてます。
    - [Rancher Docs: Installing Docker](https://rancher.com/docs/rancher/v2.x/en/installation/requirements/installing-docker/)
    - [Rancher Docs: Installing Rancher on a Single Node Using Docker](https://rancher.com/docs/rancher/v2.x/en/installation/other-installation-methods/single-node-docker/)

```bash
curl https://releases.rancher.com/install-docker/19.03.sh | sh
sudo usermod -aG docker ubuntu

docker run -d --restart=unless-stopped \
  -p 80:80 -p 443:443 \
  -v /host/rancher:/var/lib/rancher \
  -v /var/log/rancher/auditlog:/var/log/auditlog \
  -e AUDIT_LEVEL=1 \
  rancher/rancher:v2.4.3
```

## まとめ
- ということでまずはEKS用のVPCと踏み台の作成を行いました。次はEKSクラスターを作成していきたいと思います。

## 関連記事
- [EKSでMattermostを構築した話：0.概要編 - Qiita](https://qiita.com/tnagano1981/items/555301cecd3ed309fa43)
- [EKSでMattermostを構築した話：2. EKSクラスター作成編 - Qiita](https://qiita.com/tnagano1981/items/fc5d96ddf9a3b5c4fb03)
- [EKSでMattermostを構築した話：3-1. EKSクラスターでアプリケーションを稼働させる前にセットアップしておくべきツール編 - Qiita](https://qiita.com/tnagano1981/items/c91d27fa2e286a96b6ff)