皆さんこんにちは。先日、ついにAWSのAmazon EKSが一般公開されましたね。現時点ではまだオレゴンとバージニア北部でしか使えませんが、今回は検証の為、ユーザーズガイドに沿って実際にクラスタを作成し、ゲストブックアプリケーションをデプロイしてみたいと思います。
尚、各種作業におけるKubernetesと、AWSの従来のリソースについての詳細説明は省略していますのでご了承下さい。
準備
AWS CLI
ドキュメントではマネジメントコンソールを使っていますが、今回はCLIを使っていきたいと思います。基礎的な部分なのでインストール方法は省略します。(ドキュメントはこちら)
今回使ったバージョンは次の通りです:
$ aws --version
aws-cli/1.15.42 Python/2.7.10 Darwin/17.6.0 botocore/1.10.42
また、今回はずっとオレゴン(us-west-2)で作業するので、環境変数をセットしておきます。
$ export AWS_DEFAULT_REGION=us-west-2
kubectl
今回は、Docker for Mac (18.05.0-ce-mac67
, Channel: edge) に同梱されている物を使いました。バージョンは次の通りです:
$ kubectl version --short --client
Client Version: v1.10.3
Heptio Authenticator
Amazon EKSでは、クラスタとの認証にIAMを使うようですが、これにはHeptio Authenticatorと言うツールが必要なのでインストールします。
ドキュメントではいくつかのインストール方法が紹介されていますが、今回はシンプルにcurlでダウンロードし、実行権限を与えた上でPATHの効いてるディレクトリに放り込む事にしました:
$ cd /tmp
$ curl -o heptio-authenticator-aws https://amazon-eks.s3-us-west-2.amazonaws.com/1.10.3/2018-06-05/bin/darwin/amd64/heptio-authenticator-aws
$ chmod +x heptio-authenticator-aws
$ mv heptio-authenticator-aws /usr/local/bin
実際にコマンドを叩いてみます:
$ heptio-authenticator-aws
A tool to authenticate to Kubernetes using AWS IAM credentials
Usage:
heptio-authenticator-aws [command]
Available Commands:
help Help about any command
init Pre-generate certificate, private key, and kubeconfig files for the server.
server Run a webhook validation server suitable that validates tokens using AWS IAM
token Authenticate using AWS IAM and get token for Kubernetes
verify Verify a token for debugging purpose
Flags:
-i, --cluster-id ID Specify the cluster ID, a unique-per-cluster identifier for your heptio-authenticator-aws installation.
-c, --config filename Load configuration from filename
-h, --help help for heptio-authenticator-aws
Use "heptio-authenticator-aws [command] --help" for more information about a command.
usageが表示されました。
IAM Role
EKSサービスがクラスタの操作時にAWSの他のサービスを操作できるように、予めEKSサービス用のRoleを作り、 AmazonEKSClusterPolicy
とAmazonEKSServicePolicy
をアタッチする必要があります。
CLIでさくっと作っていきます:
$ aws iam create-role --role-name eks-role --assume-role-policy-document '{"Version":"2012-10-17","Statement":[{"Action":"sts:AssumeRole","Effect":"Allow","Principal":{"Service":"eks.amazonaws.com"}}]}'
{
"Role": {
"AssumeRolePolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Action": "sts:AssumeRole",
"Effect": "Allow",
"Principal": {
"Service": "eks.amazonaws.com"
}
}
]
},
"RoleId": "AROBILD2LKDSSJCCIADME",
"CreateDate": "2018-06-25T07:31:28.966Z",
"RoleName": "eks-service-role",
"Path": "/",
"Arn": "arn:aws:iam::000000000000:role/eks-service-role"
}
}
$ aws iam attach-role-policy --role-name eks-service-role --policy-arn arn:aws:iam::aws:policy/AmazonEKSClusterPolicy
$ aws iam attach-role-policy --role-name eks-service-role --policy-arn arn:aws:iam::aws:policy/AmazonEKSServicePolicy
今回は eks-service-role
と言う名前を付ける事にしました。尚、RoleのARNは後ほど使うので控えておきます。
VPC
Kubernetesクラスタを展開するVPCを用意する必要がありますが、今回は面倒なのでアカウント作成時にデフォルトで作られている物を使用する事にしました。
EC2のキーペア
KubernetesのWorkerノードとして動作するEC2インスタンス用のSSHキーペアを用意する必要がありますが、今回も適当な物を使う事にしたので作成方法については割愛します。
クラスタを作る
次にクラスタを作っていきます。因みに、クラスタは1個につき、1時間あたりUS$0.2課金されます。残念ながら、GKEと違って無料じゃないようですね。
クラスタの作成にもCLIを使って作っていきます。使用するインターフェースはeks create-clusterです。
使い方をざっくり説明すると、
--name
,--role-arn
,--resources-vpc-config
オプションは必須--name
にはクラスタ名を指定。ユニークである必要がある--role-arn
には先程作ったRole(eks-service-role
)のARNを指定--resources-vpc-config
にはVPCのサブネットIDと、セキュリティグループのIDを指定(複数指定可)- サブネットは最低2個以上指定する必要がある
- 今回はデフォルトVPCのus-west-2aと2bのサブネットと、VPCのデフォルトのセキュリティグループを使用した
その他、--kubernetes-version
でKubernetesのバージョンを指定したりできますが、今回は必要最低限のオプションのみで実行しました。因みに、サブネットは us-west-2a
と us-west-2b
の物、セキュリティグループにはVPCのデフォルトの物を指定しました。
(当たり前ですが、現時点で利用できない東京リージョン等を指定するとエンドポイントが無いと怒られます)
実行すると、作成したクラスタの詳細が表示されます:
$ aws eks create-cluster \
--name my-cluster \
--role-arn arn:aws:iam::000000000000:role/eks-service-role \
--resources-vpc-config "subnetIds=subnet-0164f46a,subnet-057c0a4c,securityGroupIds=sg-03ebe152"
{
"cluster": {
"status": "CREATING",
"name": "my-cluster",
"certificateAuthority": {},
"roleArn": "arn:aws:iam::000000000000:role/eks-service-role",
"resourcesVpcConfig": {
"subnetIds": [
"subnet-0164f46a",
"subnet-057c0a4c"
],
"vpcId": "vpc-013a2508",
"securityGroupIds": [
"sg-03ebe152"
]
},
"version": "1.10",
"arn": "arn:aws:eks:us-west-2:000000000000:cluster/my-cluster",
"createdAt": 1529826773.192
}
}
この時点で結果のJSONを見ると、cluster.status
は “CREATING” の状態だと言う事が分かります。これが “ACTIVE” になると、クラスタが利用できるようになります。(因みに結構時間かかります。現時点でのバージョンでは、通常10分未満で完了するようです)
また、上のJSONと同様の物がeks describe-clusterで取得可能ですので、下記を実行して “ACTIVE” になるまで待ちましょう(--name
に取得したいクラスタ名を指定します):
$ aws eks describe-cluster --name my-cluster --query cluster.status
"ACTIVE"
ACTIVEになったら、後ほど必要になるKubernetes APIのエンドポイントURLと、認証用のCA証明書を控えておきます。これらも、describe-clusterで取得可能です:
$ aws eks describe-cluster --name my-cluster --query cluster.endpoint --output text
https://5C1485ACC29FAA5A16E7E77A4491F4E8.yl4.us-west-2.eks.amazonaws.com
$ aws eks describe-cluster --name my-cluster --query cluster.certificateAuthority.data --output text
(base64 message)...
続いて、クラスタの設定をします。ドキュメントに記載の通り、以下のYAMLの <endpoint-url>
と <base64-encoded-ca-cert>
の部分を先程控えておいた値に、 <cluster-name>
をクラスタ名に置き換えて、 ~/.kube/config-my-eks-cluster
に保存します。
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"
- "<cluster-name>"
# - "-r"
# - "<role-arn>"
その後、$KUBECONFIG
環境変数に上記の設定ファイルを適用しておきます:
$ export KUBECONFIG=$KUBECONFIG:~/.kube/config-my-eks-cluster
ここまでできたら、 kubectl
を使ってクラスタとやり取りが行えます。試しにServiceの状態を確認してみましょう:
$ kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.100.0.1 <none> 443/TCP 3h
無事にクラスタとのやり取りができました。
Workerノードを起動・登録する
クラスタが無事にできたので、次にWorkerノードを登録します。WorkerノードはEC2インスタンスとなりますので、インスタンスタイプに応じた課金が行われます。
ドキュメントでは、CloudFormationを使ってノードのオートスケーリンググループ等のリソースを作成していたので、今回はそれを使っていきます。
https://amazon-eks.s3-us-west-2.amazonaws.com/1.10.3/2018-06-05/amazon-eks-nodegroup.yaml をテンプレートとし、それぞれ以下のパラメータを設定します:
- Stack name: CloudFormationのスタック名。適当な名前 (
eks-my-cluster-worker-nodes
) を設定 - Cluster name: 今回作ったEKSクラスタの名前
- ClusterControlPlaneSecurityGroup: クラスタ生成時に使ったセキュリティグループのID
- NodeGroupName: オートスケーリンググループ関連のリソースのNameのプレフィックスとして使われる模様。これも適当な名前 (
eks-my-cluster-worker
) を設定 - NodeAutoScalingGroupMinSize: オートスケーリングの最小数
- NodeAutoScalingGroupMaxSize: オートスケーリングの最大数
- NodeInstanceType: EC2インスタンスのインスタンスタイプ
- NodeImageId: EC2インスタンスの起動イメージ, 今回はオレゴンなので
ami-73a6e20b
(バージニア北部はami-dea4d5a1
) - KeyName: EC2インスタンスへSSHログインする為のキーペア名。予め準備しておいた物を使う
- VpcId: クラスタ作成時に指定したサブネットが属するVPCのID
- Subnets: クラスタ作成時に指定したサブネットID
ここでもCLIを使います。インターフェースはcloudformation create-stackです:
$ aws cloudformation create-stack \
--template-body https://amazon-eks.s3-us-west-2.amazonaws.com/1.10.3/2018-06-05/amazon-eks-nodegroup.yaml \
--stack-name eks-my-cluster-worker-nodes \
--capabilities CAPABILITY_IAM \
--parameters \
ParameterKey=ClusterName,ParameterValue=my-cluster \
ParameterKey=ClusterControlPlaneSecurityGroup,ParameterValue=sg-03ebe152 \
ParameterKey=NodeGroupName,ParameterValue=eks-my-cluster-worker \
ParameterKey=NodeAutoScalingGroupMinSize,ParameterValue=1 \
ParameterKey=NodeAutoScalingGroupMaxSize,ParameterValue=2 \
ParameterKey=NodeInstanceType,ParameterValue=t2.small \
ParameterKey=NodeImageId,ParameterValue=ami-73a6e20b \
ParameterKey=KeyName,ParameterValue=issei \
ParameterKey=VpcId,ParameterValue=vpc-013a2508 \
ParameterKey=Subnets,ParameterValue=\"subnet-0164f46a,subnet-057c0a4c\"
{ "StackId": "arn:aws:cloudformation:us-west-2:000000000000:stack/eks-my-cluster-worker-nodes/c7e20620-7822-11e8-bfa6-50a68a0e32ba" }
作成されたスタックの、 NodeInstanceRole
と言う論理IDが名付けられたリソースのIAM RoleのARNが後ほど必要になるので、控えておきます。これにはcloudformation describe-stack-resourcesとiam get-roleインターフェースを組み合わせると取得できます(--stack-name
スタック名、--logical-resource-id
に論理リソースIDを指定):
$ aws iam get-role --role-name $(aws cloudformation describe-stack-resources --stack-name eks-my-cluster-worker-nodes --logical-resource-id NodeInstanceRole --query "StackResources[0].PhysicalResourceId" --output text) --query Role.Arn --output text
arn:aws:iam::000000000000:role/eks-my-cluster-worker-nodes-NodeInstanceRole-CTP7DO7ST83A
起動したWorkerをクラスタに追加する為には、更にAWS AuthenticatorのConfigMapを設定する必要があります。まずはテンプレートをDLします:
$ curl -O https://amazon-eks.s3-us-west-2.amazonaws.com/1.10.3/2018-06-05/aws-auth-cm.yaml
エディタでこのファイルを開き、 <ARN of instance role (not instance profile)>
の部分を、先程のIAM RoleのARNで置き換えます。
# aws-auth-cm.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: aws-auth
namespace: kube-system
data:
mapRoles: |
- rolearn: <ARN of instance role (not instance profile)>
username: system:node:{{EC2PrivateDNSName}}
groups:
- system:bootstrappers
- system:nodes
その後、ConfigMapをクラスタに適用します:
$ kubectl apply -f aws-auth-cm.yaml
configmap "aws-auth" created
しばらくすると、WorkerノードのステータスがREADYになります:
$ kubectl get nodes
NAME STATUS ROLES AGE VERSION
ip-172-31-34-76.us-west-2.compute.internal Ready <none> 1m v1.10.3
ip-172-31-43-90.us-west-2.compute.internal Ready <none> 1m v1.10.3
ゲストブックアプリケーションを作成する
クラスタの準備が整ったので、いよいよアプリケーションをデプロイしてみます。
ここからはちょっと駆け足でいきます。
アプリケーションに必要なレプリケーションコントローラーやサービス等のオブジェクトを適用していきます。インターネット上に公開されている設定YAMLファイルを直接適用できる所がKubernetesの良い所です:
$ kubectl apply -f https://raw.githubusercontent.com/kubernetes/kubernetes/v1.10.3/examples/guestbook-go/redis-master-controller.json
replicationcontroller "redis-master" created
$ kubectl apply -f https://raw.githubusercontent.com/kubernetes/kubernetes/v1.10.3/examples/guestbook-go/redis-master-controller.json
replicationcontroller "redis-master" created
$ kubectl apply -f https://raw.githubusercontent.com/kubernetes/kubernetes/v1.10.3/examples/guestbook-go/redis-master-service.json
service "redis-master" created
$ kubectl apply -f https://raw.githubusercontent.com/kubernetes/kubernetes/v1.10.3/examples/guestbook-go/redis-slave-controller.json
replicationcontroller "redis-slave" created
$ kubectl apply -f https://raw.githubusercontent.com/kubernetes/kubernetes/v1.10.3/examples/guestbook-go/redis-slave-service.json
service "redis-slave" created
$ kubectl apply -f https://raw.githubusercontent.com/kubernetes/kubernetes/v1.10.3/examples/guestbook-go/guestbook-controller.json
replicationcontroller "guestbook" created
$ kubectl apply -f https://raw.githubusercontent.com/kubernetes/kubernetes/v1.10.3/examples/guestbook-go/guestbook-service.json
service "guestbook" created
その後、guestbook
サービスのEXTERNAL-IPが割り当てられるまで待ちます:
$ kubectl get services -o wide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
guestbook LoadBalancer 10.100.121.35 a6aa2e574778911e894530228d4e0b41-1287580158.us-west-2.elb.amazonaws.com 3000:32209/TCP 2m app=guestbook
kubernetes ClusterIP 10.100.0.1 <none> 443/TCP 36m <none>
redis-master ClusterIP 10.100.237.173 <none> 6379/TCP 2m app=redis,role=master
redis-slave ClusterIP 10.100.168.148 <none>
割り当てられたら、アクセスが可能です。 http://a143abb3b782711e890be021a4e4ac58-425821813.us-west-2.elb.amazonaws.com:3000/ を開いてみると、無事ゲストブックアプリケーションが開かれました。
クリーンナップ
無事にアプリケーションをデプロイできたので、作ったリソースを削除していきます。
クラスタからゲストブックアプリケーションの為にデプロイしたオブジェクトを削除:
$ kubectl delete \
rc/redis-master \
rc/redis-slave \
rc/guestbook \
svc/redis-master \
svc/redis-slave \
svc/guestbook
Workerノードのオートスケーリンググループを削除:
$ aws cloudformation delete-stack --stack-name eks-my-cluster-worker-nodes
EKSクラスタを削除:
$ aws eks delete-cluster --name my-cluster
感想
GKEに比べると、クラスタの構築は大変な印象がありました。また、GKEがクラスタの料金を無料としている一方で、EKSは少額なものの、課金されてしまう点も無視はできません。
そう言った意味でも、自社開発であるAmazon ECSの方が(クラスタ構築自体の)敷居は低いように思います。しかし、世の中の流れ的にKubernetesがデファクトとなっていますし、クラスタ構築後の手軽さや手堅さを考えると、今後も積極的にKubernetesを使いたいと思います。なのでAmazon EKSの今後の改善に期待。(と言うか早く東京に来てくれ)