eksctl: AWS EKSクラスタが簡単に構築できるツール

以前EKSクラスタを自前（AWS公式手順からシェル化して）で作っていたときに非常に面倒くさい手作業だと思ったら、こんな素晴らしいものが出てきました。

![eksctl.png](https://qiita-image-store.s3.amazonaws.com/0/260796/910e6de3-e0b1-d315-87dc-a3f07fee1783.png)

> [https://eksctl.io/](https://eksctl.io/)

1コマンドでEKSクラスタが作れます！

Goで開発されていて、裏でAWSの公式CloudFormationテンプレートを使っています。

* VPCを新規作成
* デフォルトで`us-west-2`リージョンを利用
* デフォルトで`m5.large`ノードの2台構成
* デフォルトEKS AMIを利用
* 面白いクラスタ名の自動生成（例： “fabulous-mushroom-1527688624”）

## 事前準備（Mac OSX）

* AWS API credentialsが設定済みであること（`~/.aws/`配下のものか、環境変数か）
* [kubectl CLI v1.10以上](https://kubernetes.io/docs/tasks/tools/install-kubectl/#install-with-homebrew-on-macos)
* [heptio-authenticator-aws](https://github.com/heptio/authenticator)

## ツールをインストールする

```shell:
> curl --silent --location "https://github.com/weaveworks/eksctl/releases/download/latest_release/eksctl_Darwin_amd64.tar.gz" | tar xz -C /tmp
> sudo mv /tmp/eksctl /usr/local/bin
```

## EKSクラスタを作る

すべてデフォルトでも困らない方に：

```shell:
eksctl create cluster
```

個人的によく使いそうな実行方法：

```shell:
eksctl create cluster \
       --cluster-name my-eks-cluster \
       --nodes 3 \
       --nodes-min 3 \
       --nodes-max 5 \
       --node-type t2.medium \
       --region us-west-2
```

構築はおおよそ15分かかります、ビールでも飲んで寛ぎます。

```shell:
2018-06-14T22:33:44+09:00 [ℹ]  importing SSH public key "/Users/jb/.ssh/id_rsa.pub" as "EKS-my-eks-cluster"
2018-06-14T22:33:45+09:00 [ℹ]  creating EKS cluster "my-eks-cluster" in "us-west-2" region
2018-06-14T22:33:45+09:00 [ℹ]  creating ServiceRole stack "EKS-my-eks-cluster-ServiceRole"
2018-06-14T22:33:45+09:00 [ℹ]  creating VPC stack "EKS-my-eks-cluster-VPC"
2018-06-14T22:34:26+09:00 [✔]  created ServiceRole stack "EKS-my-eks-cluster-ServiceRole"
2018-06-14T22:34:46+09:00 [✔]  created VPC stack "EKS-my-eks-cluster-VPC"
2018-06-14T22:34:46+09:00 [ℹ]  creating control plane "my-eks-cluster"
2018-06-14T22:44:29+09:00 [✔]  created control plane "my-eks-cluster"
2018-06-14T22:44:29+09:00 [ℹ]  creating DefaultNodeGroup stack "EKS-my-eks-cluster-DefaultNodeGroup"
2018-06-14T22:48:11+09:00 [✔]  created DefaultNodeGroup stack "EKS-my-eks-cluster-DefaultNodeGroup"
2018-06-14T22:48:11+09:00 [✔]  all EKS cluster "my-eks-cluster" resources has been created
2018-06-14T22:48:11+09:00 [ℹ]  wrote "/Users/jb/.kube/eksctl/clusters/my-eks-cluster"
2018-06-14T22:48:16+09:00 [ℹ]  the cluster has 0 nodes
2018-06-14T22:48:16+09:00 [ℹ]  waiting for at least 3 nodes to become ready
2018-06-14T22:48:40+09:00 [ℹ]  the cluster has 5 nodes
2018-06-14T22:48:40+09:00 [ℹ]  node "ip-192-168-120-156.us-west-2.compute.internal" is ready
2018-06-14T22:48:40+09:00 [ℹ]  node "ip-192-168-149-93.us-west-2.compute.internal" is ready
2018-06-14T22:48:40+09:00 [ℹ]  node "ip-192-168-152-22.us-west-2.compute.internal" is not ready
2018-06-14T22:48:40+09:00 [ℹ]  node "ip-192-168-200-174.us-west-2.compute.internal" is ready
2018-06-14T22:48:40+09:00 [ℹ]  node "ip-192-168-94-154.us-west-2.compute.internal" is ready
2018-06-14T22:48:43+09:00 [ℹ]  all command should work, try ' --kubeconfig /Users/jb/.kube/eksctl/clusters/my-eks-cluster get nodes'
2018-06-14T22:48:43+09:00 [ℹ]  EKS cluster "my-eks-cluster" in "us-west-2" region is ready
```

## クラスタ情報を確認する

```shell:
> eksctl get cluster
2018-06-14T22:52:03+09:00 [ℹ]  cluster = {
  Arn: "arn:aws:eks:us-west-2:315358830128:cluster/my-eks-cluster",
  CertificateAuthority: {
    Data: "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUN5RENDQWJDZ0F3SUJBZ0lCQURBTkJna3Foa2lHOXcwQkFRc0ZBREFWTVJNd0VRWURWUVFERXdwcmRXSmwKY201bGRHVnpNQjRYRFRFNE1EWXhOREV6TkRFek9Wb1hEVEk0TURZeE1URXpOREV6T1Zvd0ZURVRNQkVHQTFVRQpBeE1LYTNWaVpYSnVaWFJsY3pDQ0FTSXdEUVlKS29aSWh2Y05BUUVCQlFBRGdnRVBBRENDQVFvQ2dnRUJBTmJIClBUellSKzhYbys3cEtWN093cWo5RjF1L1RPMXNFbFQzOEl4THlkcnRMTFJRMzhjcGt5NHBUamVhVkkvb0ZMZ0IKSXV1YWdPTy9TQWpITy9Oek5oVERuakJMb0ZUVGkvcGlWUjVMa091NTQvL25aRllyeE9mRUxaRjFLSHlzMlR3YwpOYjNrRkZJOXpZSlhCQkZDSFNOSWNrZXp6dFB6TkZJREhoQ2Q2VFZGbVFScXJuZ1BiRUw2MnFLRVNHa2NuN05qClp2cjJnTHo1eWZSQjVPTFllNy9zVkE2ZllUZW51TzY3dUtBQmUyMHlndGVCc253MWJaSis1SWFpRm9lbHVpamIKbENVSnNMSTZScStRVWlOOVlhZ1k3ZHJjdXQzS2trbGRmK2dvUjdWb0NvbUJGaFUvNzE0TWhXZGxacE1NQ21wbgpRZXJMNFQ1d3V0SWdFN3A2RHlFQ0F3RUFBYU1qTUNFd0RnWURWUjBQQVFIL0JBUURBZ0trTUE4R0ExVWRFd0VCCi93UUZNQU1CQWY4d0RRWUpLb1pJaHZjTkFRRUxCUUFEZ2dFQkFMb1FWL3ZmakFEemt2TTlHNmh0RGgwWXFmTDYKT2VBVjZNaW8xZUZKajBQQUE2dm8rVk5zYkdvUkpXd2VTcXQ2dE1tUnVBVUQ2ODBkdnAwU1ZBU01mWGdhRlFsMwpFeWlKa2tIM1ZBbnpEcmRZM0k5cnhLSnl3Umc5ZlRNNzVjOE90YlRaR3F1b09aZFh4Q0dXcmI0UU85WEJndkJmCmt0WFpuamQ3ai9nekplMG84cXZ1YjZxd2g0QlVkaDd5dUV5ZGM0eWZ3bmpUQ2lKMC95bG9PWEJhak9sYzZBTWcKbThEeXpkRXVhSnZUMWNIY1RKV01YV01QellwSk5iZ3lMQitjUSsxRHNwWjY3a3lERDN6dUtZcGlPNjlsSHZRUgpLeXl4VS9XaHhSVEhZSzZnY1FCWXlDMjc0cXR3M0VtdU5adlJMdkJRUk8wOEVFa0NsYlRMWkI2WFYxdz0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo="
  },
  CreatedAt: 2018-06-14 13:34:48 +0000 UTC,
  Endpoint: "https://DA348BD1270E56FE6268B41927F2F7D8.sk1.us-west-2.eks.amazonaws.com",
  Name: "my-eks-cluster",
  ResourcesVpcConfig: {
    SecurityGroupIds: ["sg-4ed98c3f"],
    SubnetIds: ["subnet-0a3f5173","subnet-5a4fc711","subnet-7c2f6b26"],
    VpcId: "vpc-a4f1e4dd"
  },
  RoleArn: "arn:aws:iam::315358830128:role/EKS-my-eks-cluster-Servic-AWSServiceRoleForAmazonE-WBO1JT0SGWZ",
  Status: "ACTIVE",
  Version: "1.10"
}
2018-06-14T22:52:04+09:00 [ℹ]  stack = {
  Capabilities: ["CAPABILITY_IAM"],
  CreationTime: 2018-06-14 13:44:30.566 +0000 UTC,
  Description: "Amazon EKS - Node Group",
  DisableRollback: false,
  EnableTerminationProtection: false,
  Outputs: [{
      Description: "The node instance role",
      OutputKey: "NodeInstanceRole",
      OutputValue: "arn:aws:iam::315358830128:role/EKS-my-eks-cluster-DefaultNodeGro-NodeInstanceRole-M8OUEPUMZP19"
    }],
  Parameters: [
    {
      ParameterKey: "KeyName",
      ParameterValue: "EKS-my-eks-cluster"
    },
    {
      ParameterKey: "NodeImageId",
      ParameterValue: "ami-73a6e20b"
    },
    {
      ParameterKey: "Subnets",
      ParameterValue: "subnet-0a3f5173,subnet-5a4fc711,subnet-7c2f6b26"
    },
    {
      ParameterKey: "NodeGroupName",
      ParameterValue: "default"
    },
    {
      ParameterKey: "ClusterControlPlaneSecurityGroup",
      ParameterValue: "sg-4ed98c3f"
    },
    {
      ParameterKey: "VpcId",
      ParameterValue: "vpc-a4f1e4dd"
    },
    {
      ParameterKey: "NodeAutoScalingGroupMinSize",
      ParameterValue: "3"
    },
    {
      ParameterKey: "ClusterName",
      ParameterValue: "my-eks-cluster"
    },
    {
      ParameterKey: "NodeInstanceType",
      ParameterValue: "t2.medium"
    },
    {
      ParameterKey: "NodeAutoScalingGroupMaxSize",
      ParameterValue: "5"
    }
  ],
  RollbackConfiguration: {

  },
  StackId: "arn:aws:cloudformation:us-west-2:315358830128:stack/EKS-my-eks-cluster-DefaultNodeGroup/10378320-6fd9-11e8-a9e7-50d5ca789e4a",
  StackName: "EKS-my-eks-cluster-DefaultNodeGroup",
  StackStatus: "CREATE_COMPLETE",
  Tags: [{
      Key: "eksctl.cluster.k8s.io/v1alpha1/cluster-name",
      Value: "my-eks-cluster"
    }]
}
2018-06-14T22:52:04+09:00 [ℹ]  stack = {
  CreationTime: 2018-06-14 13:33:45.911 +0000 UTC,
  Description: "Amazon EKS Sample VPC",
  DisableRollback: false,
  EnableTerminationProtection: false,
  Outputs: [{
      Description: "Security group for the cluster control plane communication with worker nodes",
      OutputKey: "SecurityGroups",
      OutputValue: "sg-4ed98c3f"
    },{
      Description: "The VPC Id",
      OutputKey: "VpcId",
      OutputValue: "vpc-a4f1e4dd"
    },{
      Description: "All subnets in the VPC",
      OutputKey: "SubnetIds",
      OutputValue: "subnet-0a3f5173,subnet-5a4fc711,subnet-7c2f6b26"
    }],
  Parameters: [
    {
      ParameterKey: "Subnet01Block",
      ParameterValue: "192.168.64.0/18"
    },
    {
      ParameterKey: "VpcBlock",
      ParameterValue: "192.168.0.0/16"
    },
    {
      ParameterKey: "Subnet03Block",
      ParameterValue: "192.168.192.0/18"
    },
    {
      ParameterKey: "Subnet02Block",
      ParameterValue: "192.168.128.0/18"
    }
  ],
  RollbackConfiguration: {

  },
  StackId: "arn:aws:cloudformation:us-west-2:315358830128:stack/EKS-my-eks-cluster-VPC/8ffa08a0-6fd7-11e8-a68e-50d5ca0184d2",
  StackName: "EKS-my-eks-cluster-VPC",
  StackStatus: "CREATE_COMPLETE",
  Tags: [{
      Key: "eksctl.cluster.k8s.io/v1alpha1/cluster-name",
      Value: "my-eks-cluster"
    }]
}
2018-06-14T22:52:04+09:00 [ℹ]  stack = {
  Capabilities: ["CAPABILITY_IAM"],
  CreationTime: 2018-06-14 13:33:45.679 +0000 UTC,
  Description: "Amazon EKS Service Role",
  DisableRollback: false,
  EnableTerminationProtection: false,
  Outputs: [{
      Description: "The role that EKS will use to create AWS resources for Kubernetes clusters",
      ExportName: "EKS-my-eks-cluster-ServiceRole-RoleArn",
      OutputKey: "RoleArn",
      OutputValue: "arn:aws:iam::315358830128:role/EKS-my-eks-cluster-Servic-AWSServiceRoleForAmazonE-WBO1JT0SGWZ"
    }],
  RollbackConfiguration: {

  },
  StackId: "arn:aws:cloudformation:us-west-2:315358830128:stack/EKS-my-eks-cluster-ServiceRole/8fd71750-6fd7-11e8-96e7-503aca41a061",
  StackName: "EKS-my-eks-cluster-ServiceRole",
  StackStatus: "CREATE_COMPLETE",
  Tags: [{
      Key: "eksctl.cluster.k8s.io/v1alpha1/cluster-name",
      Value: "my-eks-cluster"
    }]
}
```

ローカルにもこんなkubeconfigファイルが生成されました。

```shell:
> cat ~/.kube/eksctl/clusters/my-eks-cluster 
apiVersion: v1
clusters:
- cluster:
    certificate-authority-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUN5RENDQWJDZ0F3SUJBZ0lCQURBTkJna3Foa2lHOXcwQkFRc0ZBREFWTVJNd0VRWURWUVFERXdwcmRXSmwKY201bGRHVnpNQjRYRFRFNE1EWXhOREV6TkRFek9Wb1hEVEk0TURZeE1URXpOREV6T1Zvd0ZURVRNQkVHQTFVRQpBeE1LYTNWaVpYSnVaWFJsY3pDQ0FTSXdEUVlKS29aSWh2Y05BUUVCQlFBRGdnRVBBRENDQVFvQ2dnRUJBTmJIClBUellSKzhYbys3cEtWN093cWo5RjF1L1RPMXNFbFQzOEl4THlkcnRMTFJRMzhjcGt5NHBUamVhVkkvb0ZMZ0IKSXV1YWdPTy9TQWpITy9Oek5oVERuakJMb0ZUVGkvcGlWUjVMa091NTQvL25aRllyeE9mRUxaRjFLSHlzMlR3YwpOYjNrRkZJOXpZSlhCQkZDSFNOSWNrZXp6dFB6TkZJREhoQ2Q2VFZGbVFScXJuZ1BiRUw2MnFLRVNHa2NuN05qClp2cjJnTHo1eWZSQjVPTFllNy9zVkE2ZllUZW51TzY3dUtBQmUyMHlndGVCc253MWJaSis1SWFpRm9lbHVpamIKbENVSnNMSTZScStRVWlOOVlhZ1k3ZHJjdXQzS2trbGRmK2dvUjdWb0NvbUJGaFUvNzE0TWhXZGxacE1NQ21wbgpRZXJMNFQ1d3V0SWdFN3A2RHlFQ0F3RUFBYU1qTUNFd0RnWURWUjBQQVFIL0JBUURBZ0trTUE4R0ExVWRFd0VCCi93UUZNQU1CQWY4d0RRWUpLb1pJaHZjTkFRRUxCUUFEZ2dFQkFMb1FWL3ZmakFEemt2TTlHNmh0RGgwWXFmTDYKT2VBVjZNaW8xZUZKajBQQUE2dm8rVk5zYkdvUkpXd2VTcXQ2dE1tUnVBVUQ2ODBkdnAwU1ZBU01mWGdhRlFsMwpFeWlKa2tIM1ZBbnpEcmRZM0k5cnhLSnl3Umc5ZlRNNzVjOE90YlRaR3F1b09aZFh4Q0dXcmI0UU85WEJndkJmCmt0WFpuamQ3ai9nekplMG84cXZ1YjZxd2g0QlVkaDd5dUV5ZGM0eWZ3bmpUQ2lKMC95bG9PWEJhak9sYzZBTWcKbThEeXpkRXVhSnZUMWNIY1RKV01YV01QellwSk5iZ3lMQitjUSsxRHNwWjY3a3lERDN6dUtZcGlPNjlsSHZRUgpLeXl4VS9XaHhSVEhZSzZnY1FCWXlDMjc0cXR3M0VtdU5adlJMdkJRUk8wOEVFa0NsYlRMWkI2WFYxdz0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=
    server: https://DA348BD1270E56FE6268B41927F2F7D8.sk1.us-west-2.eks.amazonaws.com
  name: my-eks-cluster.us-west-2.eksctl.io
contexts:
- context:
    cluster: my-eks-cluster.us-west-2.eksctl.io
    user: arn:aws:iam::315358830128:root@my-eks-cluster.us-west-2.eksctl.io
  name: arn:aws:iam::315358830128:root@my-eks-cluster.us-west-2.eksctl.io
current-context: arn:aws:iam::315358830128:root@my-eks-cluster.us-west-2.eksctl.io
kind: Config
preferences: {}
users:
- name: arn:aws:iam::315358830128:root@my-eks-cluster.us-west-2.eksctl.io
  user:
    exec:
      apiVersion: client.authentication.k8s.io/v1alpha1
      args:
      - token
      - -i
      - my-eks-cluster
      command: heptio-authenticator-aws
      env: null
```

このファイルをコピーして、`KUBECONFIG`変数に設定します。

```shell:
> cp -p  ~/.kube/eksctl/clusters/my-eks-cluster ./kubeconfig
> set -x KUBECONFIG ./kubeconfig
> kubectl get nodes
NAME                                            STATUS    ROLES     AGE       VERSION
ip-192-168-120-156.us-west-2.compute.internal   Ready     <none>    24m       v1.10.3
ip-192-168-149-93.us-west-2.compute.internal    Ready     <none>    24m       v1.10.3
ip-192-168-152-22.us-west-2.compute.internal    Ready     <none>    23m       v1.10.3
ip-192-168-200-174.us-west-2.compute.internal   Ready     <none>    24m       v1.10.3
ip-192-168-94-154.us-west-2.compute.internal    Ready     <none>    24m       v1.10.3

> kubectl get svc
NAME         TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
kubernetes   ClusterIP   10.100.0.1   <none>        443/TCP   29m
```

これでコマンドラインでも利用可能になりました！

## クラスタを削除する

```shell:
> eksctl delete cluster --cluster-name my-eks-cluster
2018-06-14T23:17:42+09:00 [ℹ]  deleting EKS cluster "my-eks-cluster"
2018-06-14T23:17:45+09:00 [✔]  all EKS cluster "my-eks-cluster" resource will be deleted (if in doubt, check CloudFormation console)
```

削除はバックグラウンド処理のようです。