AWS
CloudFormation
aws-cli
kubernetes
eks

Getting Started with Amazon EKSが長いので自動化してみた

はじめに

EKSがGAになったので、早速 Getting Started with Amazon EKS をやってみました。

EKSの構築が完了してアプリケーションをデプロイできるようになるまでには、IAMロールを作成して、VPCを作成して、Masterを起動して、Workerを起動して、ConfigMapを作成して...と、たくさんのステップが必要で非常に面倒です。

今後は勉強用に気軽にEKSを起動できるよう、AWS CLIを使ったシェルスクリプトでEKSの構築を自動化しました。

前提

事前準備

以下の3つは Getting Started with Amazon EKS に従ってインストール済みとします。

  • kubectl
  • AWS CLI
  • heptio-authenticator-aws

環境

動作確認した環境は以下の通りです。

  • OS
    • macOS High Sierra バージョン 10.13.3
  • Bash
    • GNU bash version 3.2.57(1)-release (x86_64-apple-darwin17)
  • kubectl
    • v1.10.2
  • AWS CLI
    • 1.15.351
  • heptio-authenticator-aws
    • 1.10.3

自動化した内容

以下、ソースコードの抜粋です。

IAMロールの作成

AWS CLIで作成するようにしました。

aws iam create-role \
    --role-name $EKS_ROLE_NAME \
    --assume-role-policy-document file://$POLICY_FILE

aws iam attach-role-policy \
    --role-name $EKS_ROLE_NAME \
    --policy-arn arn:aws:iam::aws:policy/AmazonEKSClusterPolicy

aws iam attach-role-policy \
    --role-name $EKS_ROLE_NAME \
    --policy-arn arn:aws:iam::aws:policy/AmazonEKSServicePolicy

SSHキーペアの作成

AWS CLIで作成するようにしました。

aws ec2 create-key-pair \
    --key-name $EKS_KEY_NAME \
    --query 'KeyMaterial' \
    --output text \
    > $EKS_KEY_FILE

chmod 600 $EKS_KEY_FILE

VPCの作成

Getting Started with Amazon EKS に記載されているCloudFormationテンプレートをAWS CLIから呼び出すようにしました。

aws cloudformation create-stack \
    --stack-name $EKS_VPC_STACK_NAME \
    --template-body https://amazon-eks.s3-us-west-2.amazonaws.com/1.10.3/2018-06-05/amazon-eks-vpc-sample.yaml \
    --parameters \
        ParameterKey=VpcBlock,ParameterValue=$VPC_BLOCK \
        ParameterKey=Subnet01Block,ParameterValue=$SUBNET_01_BLOCK \
        ParameterKey=Subnet02Block,ParameterValue=$SUBNET_02_BLOCK \
        ParameterKey=Subnet03Block,ParameterValue=$SUBNET_03_BLOCK

Masterの作成

こちらも Getting Started with Amazon EKS に記載されているCloudFormationテンプレートをAWS CLIから呼び出すようにしました。
パラメータはVPC構築時のOutputsを使うようにしました。

ROLE_ARN=$(aws iam get-role \
    --role-name $EKS_ROLE_NAME \
    --query 'Role.Arn' \
    | sed -E 's/.(.*)./\1/')

SUBNET_IDS=$(aws cloudformation describe-stacks \
    --stack-name $EKS_VPC_STACK_NAME \
    --query 'Stacks[0].Outputs[?OutputKey==`SubnetIds`].[OutputValue][0][0]' \
    | sed -E 's/.(.*)./\1/')

SECURITY_GROUP_IDS=$(aws cloudformation describe-stacks \
    --stack-name $EKS_VPC_STACK_NAME \
    --query 'Stacks[0].Outputs[?OutputKey==`SecurityGroups`].[OutputValue][0][0]' \
    | sed -E 's/.(.*)./\1/')

aws eks create-cluster \
    --name $EKS_CLUSTER_NAME \
    --role-arn $ROLE_ARN \
    --resources-vpc-config subnetIds=$SUBNET_IDS,securityGroupIds=$SECURITY_GROUP_IDS

Workerの作成

こちらも Getting Started with Amazon EKS に記載されているCloudFormationテンプレートをAWS CLIから呼び出すようにしました。
パラメータはVPC構築時とMaster構築時のOutputsを使うようにしました。

CLUSTER_CONTROL_PLANE_SECURITY_GROUP=$(aws cloudformation describe-stacks \
    --stack-name $EKS_VPC_STACK_NAME \
    --query 'Stacks[0].Outputs[?OutputKey==`SecurityGroups`].[OutputValue][0][0]' \
    | sed -E 's/.(.*)./\1/')

VPC_ID=$(aws cloudformation describe-stacks \
    --stack-name $EKS_VPC_STACK_NAME \
    --query 'Stacks[0].Outputs[?OutputKey==`VpcId`].[OutputValue][0][0]' \
    | sed -E 's/.(.*)./\1/')

SUBNETS=$(aws cloudformation describe-stacks \
    --stack-name $EKS_VPC_STACK_NAME \
    --query 'Stacks[0].Outputs[?OutputKey==`SubnetIds`].[OutputValue][0][0]')

aws cloudformation create-stack \
    --stack-name $EKS_WORKER_STACK_NAME \
    --template-body https://amazon-eks.s3-us-west-2.amazonaws.com/1.10.3/2018-06-05/amazon-eks-nodegroup.yaml \
    --parameters \
        ParameterKey=ClusterName,ParameterValue=$EKS_CLUSTER_NAME \
        ParameterKey=ClusterControlPlaneSecurityGroup,ParameterValue=$CLUSTER_CONTROL_PLANE_SECURITY_GROUP \
        ParameterKey=NodeGroupName,ParameterValue=$NODE_GROUP_NAME \
        ParameterKey=NodeAutoScalingGroupMinSize,ParameterValue=$NODE_AUTO_SCALING_GROUP_MIN_SIZE \
        ParameterKey=NodeAutoScalingGroupMaxSize,ParameterValue=$NODE_AUTO_SCALING_GROUP_MAX_SIZE \
        ParameterKey=NodeInstanceType,ParameterValue=$NODE_INSTANCE_TYPE \
        ParameterKey=NodeImageId,ParameterValue=$NODE_IMAGE_ID \
        ParameterKey=KeyName,ParameterValue=$EKS_KEY_NAME \
        ParameterKey=VpcId,ParameterValue=$VPC_ID \
        ParameterKey=Subnets,ParameterValue=$SUBNETS \
    --capabilities CAPABILITY_IAM

kubectlの設定

Master構築時のOutputsから設定ファイルを作るようにしました。

ENDPOINT_URL=`aws eks describe-cluster \
    --name $EKS_CLUSTER_NAME \
    --query cluster.endpoint`

BASE64_ENCODED_CA_CERT=`aws eks describe-cluster \
    --name $EKS_CLUSTER_NAME \
    --query cluster.certificateAuthority.data`

mkdir -p ~/.kube

cat << EOT > $EKS_KUBE_CONFIG_FILE
apiVersion: v1
clusters:
- cluster:
    server: $ENDPOINT_URL
    certificate-authority-data: $BASE64_ENCODED_CA_CERT
  name: kubernetes
contexts:
- context:
    cluster: kubernetes
    user: aws
  name: aws
current-context: aws
kind: Config
preferences: {}
users:
- name: aws
  user:
    exec:
      apiVersion: client.authentication.k8s.io/v1alpha1
      command: heptio-authenticator-aws
      args:
        - "token"
        - "-i"
        - "$EKS_CLUSTER_NAME"
        # - "-r"
        # - "<role-arn>"
EOT

ConfigMapの作成

Worker構築時のOutputsから設定ファイルを作るようにしました。

ROLE_ARN=$(aws cloudformation describe-stacks \
    --stack-name $EKS_WORKER_STACK_NAME \
    --query 'Stacks[0].Outputs[0].OutputValue' \
    | sed -E 's/.(.*)./\1/')

cat << EOT | kubectl apply -f -
apiVersion: v1
kind: ConfigMap
metadata:
  name: aws-auth
  namespace: kube-system
data:
  mapRoles: |
    - rolearn: $ROLE_ARN
      username: system:node:{{EC2PrivateDNSName}}
      groups:
        - system:bootstrappers
        - system:nodes
EOT

まとめ

以上をまとめて、以下のコマンドでEKSの構築が完了するようになりました。

$ source set-env.sh
$ ./launch.sh

15分ほど待てば、Workerの設定まで完了します。

$ kubectl get node
NAME                                           STATUS    ROLES     AGE       VERSION
ip-192-168-111-33.us-west-2.compute.internal   Ready     <none>    7m        v1.10.3
ip-192-168-152-30.us-west-2.compute.internal   Ready     <none>    7m        v1.10.3
ip-192-168-250-1.us-west-2.compute.internal    Ready     <none>    7m        v1.10.3

ついでに廃棄も1コマンドにしました。

./cleanup.sh

ソースコードの全容は以下です。
https://github.com/os1ma/eks-sample/tree/master/getting-started-with-amazon-eks

課題

ひとまず動くように作った程度なので、課題がいくつもあります。

  • 例外処理やロールバックがない
  • Serviceのtype LoadBalancerを削除せずにEKSを削除してしまうと、ELBとSecurity Groupが残ってしまい、VPCの削除がうまくいかない
    • EKSを削除する前に関連するリソースを削除する処理を入れたい
  • 命名にランダムな文字列などをつけていないので、名前が競合してしまう可能性がある
    • 特に、~/.kube/config-$EKS_CLUSTER_NAMEは既存のファイルを上書きしないよう注意が必要

  1. 2018/06/09の時点ではHomebrewでEKSに対応しているバージョンをインストールできなかったので、pipでインストールしました