Amazon EKSことはじめ

やたらControl Planeの作成にハマったので備忘録

環境

使うのはMacとDocker。
あとローカルのAWS CLIのクレデンシャル

  • mac OS Sierra
    • 10.12.5
  • docker 18.03
    • Docker version 18.03.1-ce, build 9ee9f40
  • aws-cli 1.15.30
    • EKS対応は 1.15.32 から
    • 18/06/06時点では brewのstableだと1.15.30で、 $ aws eks は使えない。
    • // あとで $ brew install awscli --HEAD とかやったら 1.15.33 が落ちてきたのでこれでいいのでは

ローカルの作業環境にDockerを使う。

先述したとおり、awscliのEKS対応は1.15.32から。
別途GKEも触っていてkubectlのバージョン合わせるのめんどうだったりとかで、ならば脳死でDocker内でawscliとkubectlを動かす戦法。
作ったEKS触るためのDocker環境はDockerHubへ上げたのでよしなに
yohgi/eks-cli - Docker Hub

$ docker run -v /Users/`whoami`/.aws:/root/.aws -it yohgi/eks-cli ash # ~/.aws を投げ込む
# aws --version
aws-cli/1.15.33 Python/3.6.5 Linux/4.9.87-linuxkit-aufs botocore/1.10.33
# kubectl version
Client Version: version.Info{Major:"1", Minor:"10", GitVersion:"v1.10.3", GitCommit:"2bba0127d85d5a46ab4b778548be28623b32d0b0", GitTreeState:"clean", BuildDate:"2018-05-28T20:16:17Z", GoVersion:"go1.9.3", Compiler:"gc", Platform:"linux/amd64"}

Dockerfileは以下

FROM python:3-alpine

RUN pip install awscli && \
    apk add --update curl jq && \
    cd /usr/local/bin && \
    curl -LO https://amazon-eks.s3-us-west-2.amazonaws.com/1.10.3/2018-06-05/bin/linux/amd64/heptio-authenticator-aws && \
    chmod +x ./heptio-authenticator-aws && \
    curl -LO https://amazon-eks.s3-us-west-2.amazonaws.com/1.10.3/2018-06-05/bin/linux/amd64/kubectl && \
    chmod +x ./kubectl && \
    mkdir /root/.kube && { \
      echo 'apiVersion: v1'; \
      echo 'clusters:';  \
      echo '- cluster:'; \
      echo '    server: <endpoint-url>'; \
      echo '    certificate-authority-data: <base64-encoded-ca-cert>'; \
      echo '  name: kubernetes'; \
      echo 'contexts:'; \
      echo '- context:'; \
      echo '    cluster: kubernetes'; \
      echo '    user: aws'; \
      echo '  name: aws'; \
      echo 'current-context: aws'; \
      echo 'kind: Config'; \
      echo 'preferences: {}'; \
      echo 'users:'; \
      echo '- name: aws'; \
      echo '  user:'; \
      echo '    exec:'; \
      echo '      apiVersion: client.authentication.k8s.io/v1alpha1'; \
      echo '      command: heptio-authenticator-aws'; \
      echo '      args:'; \
      echo '        - "token"'; \
      echo '        - "-i"'; \
      echo '        - "<cluster-name>"'; \
      echo '        # - "-r"'; \
      echo '        # - "<role-arn>"'; \
    } | tee /root/.kube/config

ENV KUBECONFIG "/root/.kube/config"

https://hub.docker.com/r/yohgi/eks-cli/

ローカルでAWS CLIを使っていない場合。

  1. IAMでAdminポリシーを持ったIAMユーザーを作成し、アクセスキーを取得。
  2. dockerに入り $ docker run -it yohgi/eks-cli ashaws cliの認証を実行 $ aws configure する。認証後は $ aws s3 ls などで動作確認すると良いと思われ。

EKSを触る

公式の Getting Started を参考に作成
また、今回作る各種リソース名は「test-cluster」と命名。
EKSはオレゴンバージニアしか対応してないので、オレゴンでゴニョる。バージニアで作成する場合はAMIだけ注意

やること

  1. クラスター用IAM Roleの作成
  2. EKS用VPCの作成
  3. クラスター(Control Plane)の作成
  4. kubectlの設定
  5. Nodeの作成
  6. 適当にコンテナを走らせる

できるもの

f:id:y-ohgi:20180607045620p:plain あとセキュリティグループがわちゃわちゃと

1. クラスター用IAM Roleの作成

# cat <<EOL > policy.json
{
  "Version": "2012-10-17",
    "Statement": [
        {
            "Action": "sts:AssumeRole",
            "Effect": "Allow",
            "Principal": {
                "Service": "eks.amazonaws.com"
            }
        }
    ]
}
# aws iam create-role --role-name test-cluster --assume-role-policy-document file://policy.json
# aws iam attach-role-policy --role-name test-cluster --policy-arn arn:aws:iam::aws:policy/AmazonEKSClusterPolicy
# aws iam attach-role-policy --role-name test-cluster --policy-arn arn:aws:iam::aws:policy/AmazonEKSServicePolicy

roleが作成されたか確認

# aws iam list-attached-role-policies --role-name test-cluster
{
    "AttachedPolicies": [
        {
            "PolicyName": "AmazonEKSClusterPolicy",
            "PolicyArn": "arn:aws:iam::aws:policy/AmazonEKSClusterPolicy"
        },
        {
            "PolicyName": "AmazonEKSServicePolicy",
            "PolicyArn": "arn:aws:iam::aws:policy/AmazonEKSServicePolicy"
        }
    ]
}

2. EKS用VPCの作成

公式で提供されているCloudFormationを使用してネットワークを作成。
VPCを1つとSubnet3つ、そしてCluster用セキュリティーグループを作成してくれる。Subnetは3つともPublic Subnet。

# aws cloudformation create-stack --stack-name test-cluster --template-url https://amazon-eks.s3-us-west-2.amazonaws.com/1.10.3/2018-06-05/amazon-eks-vpc-sample.yaml

Getting Started with Amazon EKS - Amazon EKS

3. クラスターの作成

先程作成したCloudFormationのスタック作成完了後、クラスターの作成を行う。

# export EKS_SUBNETS=$(aws cloudformation describe-stacks --stack-name test-cluster --query 'Stacks[0].Outputs[?OutputKey==`SubnetIds`][].OutputValue' --output text)
# export EKS_CLUSTER_SG=$(aws cloudformation describe-stacks --stack-name test-cluster --query 'Stacks[0].Outputs[?OutputKey==`SecurityGroups`][].OutputValue' --output text)
# export EKS_CLUSTER_ROLE=$(aws iam get-role --role-name test-cluster --query 'Role.Arn' --output text)
# aws eks create-cluster --name test-cluster --role-arn ${EKS_CLUSTER_ROLE} --resources-vpc-config subnetIds=${EKS_SUBNETS},securityGroupIds=${EKS_CLUSTER_SG}

クラスターの作成にはそこそこ時間かかる模様。

2018/06/06: オレゴンリージョンのGUIで作成した場合

kubectlがKubernetesへ接続できず動かない模様。18年6月6日現在ではまだGUIからの作成は非対応っぽい。

# kubectl get all
The connection to the server localhost:8080 was refused - did you specify the right host or port?

4. kubectlの設定

/root/.kube/configKubernetesの認証情報を記述する。

# export EKS_CLUSTER_NAME=$(aws eks describe-cluster --name test-cluster --query 'cluster.name' --output text)
# export EKS_CLUSTER_ENDPINT_URL=$(aws eks describe-cluster --name test-cluster --query 'cluster.endpoint' --output text)
# export EKS_CLUSTER_CREDENTIAL=$(aws eks describe-cluster --name test-cluster --query 'cluster.certificateAuthority.data' --output text)
# sed -i -e "s|server: <endpoint-url>|server: $EKS_CLUSTER_ENDPINT_URL|g" .kube/config
# sed -i -e "s|certificate-authority-data: <base64-encoded-ca-cert>|certificate-authority-data: $EKS_CLUSTER_CREDENTIAL|g" .kube/config
# sed -i -e "s|- \"<cluster-name>\"|- \"$EKS_CLUSTER_NAME\"|g" .kube/config

Control Planeへ接続できることを確認。

# kubectl get all
NAME                 TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
service/kubernetes   ClusterIP   10.100.0.1   <none>        443/TCP   2h

5. Nodeの作成

Node用キーペアの作成

念の為作っておく。

# aws ec2 create-key-pair --key-name test-cluster --query 'KeyMaterial' --output text > /tmp/test-cluster.pem

作成しただけだとコンテナ内にしか秘密鍵がないので、ローカルからコンテナへcpコマンドを打ち、秘密鍵を退避させる。

$ docker cp $(docker ps | grep  yohgi/eks-cli | awk '{print $1}'):/tmp/test-cluster.pem ~/.ssh/test-cluster.pem

CloudFormationでNodeの作成

公式のCloudFormationを用いて作成。
セキュリティグループの作成と、AutoScalingGroupを用いてWorkerNode用のEC2を3つ立てるテンプレート。

バージニア北部の場合は NodeImageId を変更する必要あり。

export EKS_NODE_KEYPAIR=test-cluster # さっき作ったキーペア
export EKS_NODE_AMI=ami-73a6e20b # 使用するリージョンのAMIを指定
export EKS_CLUSTER_NAME=$(aws eks describe-cluster --name test-cluster --query 'cluster.name' --output text)
export EKS_CLUSTER_SG=$(aws cloudformation describe-stacks --stack-name test-cluster --query 'Stacks[0].Outputs[?OutputKey==`SecurityGroups`][].OutputValue' --output text)
export EKS_VPCID=$(aws cloudformation describe-stacks --stack-name test-cluster --query 'Stacks[0].Outputs[?OutputKey==`VpcId`][].OutputValue' --output text)
export EKS_SUBNETS=$(aws cloudformation describe-stacks --stack-name test-cluster --query 'Stacks[0].Outputs[?OutputKey==`SubnetIds`][].OutputValue' --output text)
aws cloudformation create-stack \
  --stack-name test-cluster-nodegroup \
  --template-url https://amazon-eks.s3-us-west-2.amazonaws.com/1.10.3/2018-06-05/amazon-eks-nodegroup.yaml \
  --capabilities CAPABILITY_NAMED_IAM \
  --parameters \
    ParameterKey=ClusterName,ParameterValue=$EKS_CLUSTER_NAME \
    ParameterKey=ClusterControlPlaneSecurityGroup,ParameterValue=$EKS_CLUSTER_SG \
    ParameterKey=NodeGroupName,ParameterValue=${EKS_CLUSTER_NAME}-nodegroup \
    ParameterKey=NodeImageId,ParameterValue=$EKS_NODE_AMI \
    ParameterKey=KeyName,ParameterValue=$EKS_NODE_KEYPAIR \
    ParameterKey=VpcId,ParameterValue=$EKS_VPCID \
    ParameterKey=Subnets,ParameterValue=\"$EKS_SUBNETS\"

あとあとコピペするのがめんどうになるので今回は先頭の # は排除した。
上記コマンドもコンテナ内から実行。

EC2をEKS Clusterへ参加させる

# export EKS_NODE_ROLE=$(aws cloudformation describe-stacks --stack-name test-cluster-nodegroup --query 'Stacks[0].Outputs[?OutputKey==`NodeInstanceRole`].OutputValue' --output text)
# curl -sSL https://amazon-eks.s3-us-west-2.amazonaws.com/1.10.3/2018-06-05/aws-auth-cm.yaml | sed -e "s|rolearn: <ARN of instance role (not instance profile)>|rolearn: $EKS_NODE_ROLE|g" | kubectl apply -f -

Control PlaneがWorker NodeとしてEC2を認識したかの確認

# kubectl get configmap -n kube-system
NAME         DATA      AGE
aws-auth     1         57s
kube-dns     0         2h
kube-proxy   1         2h
# kubectl get nodes --watch
NAME                                            STATUS    ROLES     AGE       VERSION
ip-192-168-140-149.us-west-2.compute.internal   Ready     <none>    1m        v1.10.3
ip-192-168-232-3.us-west-2.compute.internal     Ready     <none>    1m        v1.10.3
ip-192-168-83-147.us-west-2.compute.internal    Ready     <none>    1m        v1.10.3

Control Planeの作成完了 🎉

6. 適当にコンテナを走らせる

nginxを雑に走らせて port forwardで動作確認

# kubectl run nginx --image=nginx --port 80
# kubectl port-forward `kubectl get pod | grep nginx | awk '{print $1}'` 8080:80 &
# curl -D -  -o /dev/null -s localhost:8080
Handling connection for 8080
HTTP/1.1 200 OK
Server: nginx/1.15.0
Date: Wed, 06 Jun 2018 18:53:47 GMT
Content-Type: text/html
Content-Length: 612
Last-Modified: Tue, 05 Jun 2018 12:00:18 GMT
Connection: keep-alive
ETag: "5b167b52-264"
Accept-Ranges: bytes

ヘッダーにnginxを確認して満足。

雑記

後発だけどGKEほど抽象化してくれていないので、コンテナを走らせるまでが泥臭いなぁと
ネットワーク周りをControl Plane含め自分で定義していくあたりココらへんをしっかり学びたい

参考