百日半狂乱

Shut the fuck up and write some code!!

一人Hands-on: Manage Kubernetes Clusters on AWS Using Kops & WEB+DB PRESS Vol.99写経

Manage Kubernetes Clusters on AWS Using KopsWEB+DB PRESS Vol.99: 実践 Kubernetesを参考に一人Hhands-onをしてみた。

本当はGKEで触る方が良いと思いつつ、AWSの方が仕事で慣れているので入りやすい、re:Inventで参加するHands-onで万が一何言っているのかさっぱりわからない時のためのチートシート作成、の二つの理由でkopsでkubernetes入門を試みた。

以下、

  • 自分の記憶力を一切信用しない
  • コマンドの出力もなるべく記録
  • 途中の寄り道で見つけたことも記録

という方針でメモをとっているので記事が縦に長い。

Manage Kubernetes Clusters on AWS Using Kops

まずはAWS BlogでざっくりHands-on。

Install kops and kubectl commands

環境はmacbook

$ brew update && brew install kops

落ちてきたのはkops 1.7.1。

$ kops version
Version 1.7.1

kubectlが依存するコマンドとして同時に落ちてきた。

$ kubectl version
Client Version: version.Info{Major:"1", Minor:"8", GitVersion:"v1.8.4", GitCommit:"9befc2b8928a9426501d3bf62f72849d5cbcd5a3", GitTreeState:"clean", BuildDate:"2017-11-20T19:12:24Z", GoVersion:"go1.9.2", Compiler:"gc", Platform:"darwin/amd64"}
The connection to the server localhost:8080 was refused - did you specify the right host or port?

Preparation

十分な権限が与えられたIAM User(AmazonEC2FullAccess, AmazonRoute53FullAccess, AmazonS3FullAccess, IAMFullAccess, AmazonVPCFullAccess)と、stateの管理に必要なs3 bucketを事前に準備。

$ aws s3api create-bucket --bucket kubernetes-aws-hands-on --create-bucket-configuration LocationConstraint=ap-northeast-1

s3 bucketのversioningが推奨されている。

$ aws s3api put-bucket-versioning --bucket kubernetes-aws-hands-on --versioning-configuration Status=Enabled
$ aws s3api get-bucket-versioning --bucket kubernetes-aws-hands-on

必要な環境変数を設定(--stateオプションで指定すればいらない気もする)。

$ export KOPS_STATE_STORE=s3://kubernetes-aws-hands-on

kops 1.6.2から有効なgossip-based clusterであれば事前のDNSの設定が不要なので、kopsでclusterを作るのに必要な事前準備は基本IAMとS3の二つだけ。

Create the Kubernetes cluster

チュートリアルに従って何も考えずにいきなりclusterを作った。

cluster名の末尾に .k8s.local を付けるとgossip-based clusterが作成される。

$ kops create cluster \
--name cluster.kubernetes-aws-hands-on.k8s.local \
--zones ap-northeast-1a \
--state s3://kubernetes-aws-hands-on \
--yes
I1126 14:16:31.697037    1638 create_cluster.go:659] Inferred --cloud=aws from zone "ap-northeast-1a"
I1126 14:16:31.697727    1638 create_cluster.go:845] Using SSH public key: /Users/toshiya.doi/.ssh/id_rsa.pub
I1126 14:16:33.459717    1638 subnets.go:183] Assigned CIDR 172.20.32.0/19 to subnet ap-northeast-1a
I1126 14:16:36.709709    1638 apply_cluster.go:420] Gossip DNS: skipping DNS validation
I1126 14:16:36.895550    1638 executor.go:91] Tasks: 0 done / 67 total; 32 can run
I1126 14:16:37.248916    1638 vfs_castore.go:422] Issuing new certificate: "kubelet"
I1126 14:16:37.338015    1638 vfs_castore.go:422] Issuing new certificate: "kube-controller-manager"
I1126 14:16:37.377434    1638 vfs_castore.go:422] Issuing new certificate: "kubecfg"
I1126 14:16:37.534278    1638 vfs_castore.go:422] Issuing new certificate: "kops"
I1126 14:16:37.537790    1638 vfs_castore.go:422] Issuing new certificate: "kube-scheduler"
I1126 14:16:37.576212    1638 vfs_castore.go:422] Issuing new certificate: "kube-proxy"
I1126 14:16:38.618135    1638 executor.go:91] Tasks: 32 done / 67 total; 13 can run
I1126 14:16:39.465811    1638 executor.go:91] Tasks: 45 done / 67 total; 18 can run
I1126 14:16:40.048097    1638 launchconfiguration.go:327] waiting for IAM instance profile "nodes.cluster.kubernetes-aws-hands-on.k8s.local" to be ready
I1126 14:16:40.245749    1638 launchconfiguration.go:327] waiting for IAM instance profile "masters.cluster.kubernetes-aws-hands-on.k8s.local" to be ready
I1126 14:16:50.423912    1638 launchconfiguration.go:327] waiting for IAM instance profile "masters.cluster.kubernetes-aws-hands-on.k8s.local" to be ready
I1126 14:17:00.870220    1638 executor.go:91] Tasks: 63 done / 67 total; 3 can run
I1126 14:17:02.627267    1638 vfs_castore.go:422] Issuing new certificate: "master"
I1126 14:17:03.018893    1638 executor.go:91] Tasks: 66 done / 67 total; 1 can run
I1126 14:17:03.728216    1638 executor.go:91] Tasks: 67 done / 67 total; 0 can run
I1126 14:17:04.185106    1638 update_cluster.go:247] Exporting kubecfg for cluster
Kops has set your kubectl context to cluster.kubernetes-aws-hands-on.k8s.local

Cluster is starting.  It should be ready in a few minutes.

Suggestions:
 * validate cluster: kops validate cluster
 * list nodes: kubectl get nodes --show-labels
 * ssh to the master: ssh -i ~/.ssh/id_rsa admin@api.cluster.kubernetes-aws-hands-on.k8s.local
The admin user is specific to Debian. If not using Debian please use the appropriate user based on your OS.
 * read about installing addons: https://github.com/kubernetes/kops/blob/master/docs/addons.md

~/.kube/config にパスワードを含むclusterの設定が書き込まれた。

Gossip DNSを使っているので、hostnameを各インスタンスに発行されたpublic DNSに書き換えることでmaster, nodeそれぞれのインスタンスsshログインできる。

e.g.

$ ssh -i ~/.ssh/id_rsa admin@ec2-52-68-181-176.ap-northeast-1.compute.amazonaws.com

デフォルトでmaster * 1 (m3.medium), node * 2 (t2.medium)のkunernetes clusterが出来上がる。

$ kops validate cluster --state=s3://kubernetes-aws-hands-on
Using cluster from kubectl context: cluster.kubernetes-aws-hands-on.k8s.local

Validating cluster cluster.kubernetes-aws-hands-on.k8s.local

INSTANCE GROUPS
NAME            ROLE    MACHINETYPE MIN MAX SUBNETS
master-ap-northeast-1a  Master  m3.medium   1  1  ap-northeast-1a
nodes           Node    t2.medium   2  2  ap-northeast-1a

NODE STATUS
NAME                        ROLE    READY
ip-172-20-47-66.ap-northeast-1.compute.internal    master  True
ip-172-20-52-56.ap-northeast-1.compute.internal    node    True
ip-172-20-59-5.ap-northeast-1.compute.internal node    True

Your cluster cluster.kubernetes-aws-hands-on.k8s.local is ready

デフォルトだとHands-on用途としては無駄にデカいEBS volumeが生成されてしまう。早く消したくなる。

master: 84GB (20GB * 2 + 64GB * 1)

admin@ip-172-20-47-66:~$ df -h
Filesystem      Size  Used Avail Use% Mounted on
udev             10M     0   10M   0% /dev
tmpfs           754M  952K  753M   1% /run
/dev/xvda1       60G  3.2G   55G   6% /
tmpfs           1.9G     0  1.9G   0% /dev/shm
tmpfs           5.0M     0  5.0M   0% /run/lock
tmpfs           1.9G     0  1.9G   0% /sys/fs/cgroup
/dev/xvdc       3.9G  8.1M  3.7G   1% /mnt
/dev/xvdu        20G   70M   19G   1% /mnt/master-vol-04baa1de194c8499a
/dev/xvdv        20G   48M   19G   1% /mnt/master-vol-0a67db7ecd67379a4

node: 128GB for each

admin@ip-172-20-59-5:~$ df -h
Filesystem      Size  Used Avail Use% Mounted on
udev             10M     0   10M   0% /dev
tmpfs           791M  740K  791M   1% /run
/dev/xvda1      120G  2.8G  112G   3% /
tmpfs           2.0G     0  2.0G   0% /dev/shm
tmpfs           5.0M     0  5.0M   0% /run/lock
tmpfs           2.0G     0  2.0G   0% /sys/fs/cgroup

寄り道: Check aws resources generated by kops create cluster

CloudTrailで kops create cluster が何をやったかを観察してみた(後述するように --yes オプションを付けなければリソースを作らずに terraform plan 的な出力を見ることができる。また、これも後述するように、terraform configurationsを生成して実際に terraform plan を叩くこともできた... orz)。

今回初めてCloudTrailのcliを叩いたけど、クラウド上で何が起こっているのか知りたい癖を持つ人間には、見ているだけで気持ちが良い結果が返ってくる。

とりあえず結果をば保存して、jqで中身を見てみる。

$ aws cloudtrail lookup-events --lookup-attributes --start-time '1511673397.0' > resources_by_kops_create_cluster_2017_11_26.json

kops create cluster 一発で70回超のAPIコールがあった(作成されたリソースが必要に応じて別途呼び出したAPIコールを含む)。

$ cat resources_by_kops_create_cluster_2017_11_26.json | jq '.[][].EventName' | wc -l
      72

IAMに求められる権限が示す通り、極基本的なリソースで構成されているのがわかる。

$ cat resources_by_kops_create_cluster_2017_11_26.json | jq '.[][].EventName' | sort | uniq -c
   2 "AddRoleToInstanceProfile"
   1 "AddTags"
   1 "AssociateDhcpOptions"
   1 "AssociateRouteTable"
   1 "AttachInternetGateway"
   1 "AttachLoadBalancers"
   2 "AttachVolume"
  10 "AuthorizeSecurityGroupIngress"
   1 "ConfigureHealthCheck"
   2 "CreateAutoScalingGroup"
   1 "CreateDhcpOptions"
   2 "CreateInstanceProfile"
   1 "CreateInternetGateway"
   2 "CreateLaunchConfiguration"
   1 "CreateLoadBalancer"
   2 "CreateNetworkInterface"
   2 "CreateRole"
   4 "CreateRoute"
   1 "CreateRouteTable"
   3 "CreateSecurityGroup"
   1 "CreateSubnet"
  14 "CreateTags"
   2 "CreateVolume"
   1 "CreateVpc"
   1 "ImportKeyPair"
   3 "ModifyInstanceAttribute"
   1 "ModifyLoadBalancerAttributes"
   2 "ModifyVpcAttribute"
   2 "PutRolePolicy"
   2 "RegisterInstancesWithLoadBalancer"
   2 "RunInstances"

:memo: リソースID一覧

$ cat resources_by_kops_create_cluster_2017_11_26.json | jq '.[][] | {EventName: .EventName, Resources: .Resources}'

:memo: Details

$ cat resources_by_kops_create_cluster_2017_11_26.json | jq '.[][].CloudTrailEvent' -r | jq . | less

upgrade kubernetes

kubernetesのバージョンアップはkopsコマンドで行うことができる。

$ kops upgrade cluster \
--name cluster.kubernetes-aws-hands-on.k8s.local \
--state s3://kubernetes-aws-hands-on \
--yes

No upgrade required

rolling-update

$ kops rolling-update cluster \
--name cluster.kubernetes-aws-hands-on.k8s.local \
--state s3://kubernetes-aws-hands-on \
--yes
NAME            STATUS  NEEDUPDATE  READY   MIN MAX NODES
master-ap-northeast-1a  Ready   0      1  1  1  1
nodes           Ready   0      2  2  2  2

No rolling-update required.

delete the kubernetes cluster

--yes オプションを付けなければ、削除されるリソースの一覧が表示されるので、事前にレビューできる。

$ kops delete cluster --name cluster.kubernetes-aws-hands-on.k8s.local --state=s3://kubernetes-aws-hands-on
TYPE            NAME                                                    ID
autoscaling-config  master-ap-northeast-1a.masters.cluster.kubernetes-aws-hands-on.k8s.local-20171126051639            master-ap-northeast-1a.masters.cluster.kubernetes-aws-hands-on.k8s.local-20171126051639
autoscaling-config  nodes.cluster.kubernetes-aws-hands-on.k8s.local-20171126051639                     nodes.cluster.kubernetes-aws-hands-on.k8s.local-20171126051639
autoscaling-group   master-ap-northeast-1a.masters.cluster.kubernetes-aws-hands-on.k8s.local                master-ap-northeast-1a.masters.cluster.kubernetes-aws-hands-on.k8s.local
autoscaling-group   nodes.cluster.kubernetes-aws-hands-on.k8s.local                             nodes.cluster.kubernetes-aws-hands-on.k8s.local
dhcp-options        cluster.kubernetes-aws-hands-on.k8s.local                               dopt-12999576
iam-instance-profile    masters.cluster.kubernetes-aws-hands-on.k8s.local                           masters.cluster.kubernetes-aws-hands-on.k8s.local
iam-instance-profile    nodes.cluster.kubernetes-aws-hands-on.k8s.local                             nodes.cluster.kubernetes-aws-hands-on.k8s.local
iam-role        masters.cluster.kubernetes-aws-hands-on.k8s.local                           masters.cluster.kubernetes-aws-hands-on.k8s.local
iam-role        nodes.cluster.kubernetes-aws-hands-on.k8s.local                             nodes.cluster.kubernetes-aws-hands-on.k8s.local
instance        master-ap-northeast-1a.masters.cluster.kubernetes-aws-hands-on.k8s.local                i-093f61862830a553e
instance        nodes.cluster.kubernetes-aws-hands-on.k8s.local                             i-041d3c4c5ae0e2126
instance        nodes.cluster.kubernetes-aws-hands-on.k8s.local                             i-05bcfe5e3740c9ec7
internet-gateway    cluster.kubernetes-aws-hands-on.k8s.local                               igw-a9f54ccd
keypair         kubernetes.cluster.kubernetes-aws-hands-on.k8s.local-0a:80:6c:39:7a:a8:96:9d:af:f8:ba:5e:4d:bd:61:6f    kubernetes.cluster.kubernetes-aws-hands-on.k8s.local-0a:80:6c:39:7a:a8:96:9d:af:f8:ba:5e:4d:bd:61:6f
load-balancer       api.cluster.kubernetes-aws-hands-on.k8s.local                               api-cluster-kubernetes-aw-f1jv4s
route-table     cluster.kubernetes-aws-hands-on.k8s.local                               rtb-d93659be
security-group      api-elb.cluster.kubernetes-aws-hands-on.k8s.local                           sg-4e708937
security-group      masters.cluster.kubernetes-aws-hands-on.k8s.local                           sg-95728bec
security-group      nodes.cluster.kubernetes-aws-hands-on.k8s.local                             sg-78748d01
subnet          ap-northeast-1a.cluster.kubernetes-aws-hands-on.k8s.local                       subnet-cf109886
volume          a.etcd-events.cluster.kubernetes-aws-hands-on.k8s.local                         vol-0a67db7ecd67379a4
volume          a.etcd-main.cluster.kubernetes-aws-hands-on.k8s.local                           vol-04baa1de194c8499a
vpc         cluster.kubernetes-aws-hands-on.k8s.local                               vpc-ff52a698

削除を実行すると関連するリソース全てが綺麗さっぱり消えてなくなる。s3 bucketの中は空になった。

$ kops delete cluster --name cluster.kubernetes-aws-hands-on.k8s.local --state=s3://kubernetes-aws-hands-on --yes

ここまでがAWS blogにある内容。

お金をかけずに kops Hands-on

kopsでは、キャッシュのevictionを避けるために、デフォルトのEBS Volumeのサイズは意図的に大きく設定されている。

しかし、Hands-on用途としては無駄にデカい。 helpにかなり具体的な kops create cluster 実行例が記述されているので、一回helpを見てinstance typeやEBS volumeのsize指定方法を確認してからclusterを作った方が節約になる。

$ kops create cluster --help

--yes オプションなしで実行すると、作成予定のリソース一覧が表示され、Cluster configurationがs3 bucket内に生成される。

kops create cluster cluster.kubernetes-aws-hands-on.k8s.local \
  --state s3://kubernetes-aws-hands-on \
  --kubernetes-version 1.7.10 \
  --node-count 2 \
  --zones "ap-northeast-1a,ap-northeast-1c" \
  --node-size t2.micro \
  --master-size t2.micro \
  --master-zones ap-northeast-1a \
  --master-volume-size 8 \
  --node-volume-size 8
  ...略...
Must specify --yes to apply changes

Cluster configuration has been created.

Suggestions:
 * list clusters with: kops get cluster
 * edit this cluster with: kops edit cluster cluster.kubernetes-aws-hands-on.k8s.local
 * edit your node instance group: kops edit ig --name=cluster.kubernetes-aws-hands-on.k8s.local nodes
 * edit your master instance group: kops edit ig --name=cluster.kubernetes-aws-hands-on.k8s.local master-ap-northeast-1a

Finally configure your cluster with: kops update cluster cluster.kubernetes-aws-hands-on.k8s.local --yes

とりあえずインスタンスタイプと指定できるEBS Volumeサイズを最小にしてみた(∼∼etcd用に生成されるEBS Volume(20GB * 2)のサイズ変更方法がわからなかった∼∼ Slackで聞いてみたら、月3ドルを節約しようとしてるの?と突っ込まれてしまった。2つで6ドル…。)。またkopsがサポート/推奨するkubernetes versionはここにリストアップされている。

以降の変更は上記Suggestionsにある通り kops editkops update で行う。--yes なしで kops update cluster を実行することでs3にあるconfigの更新できる。カスタマイズが完了したら、 --yes を付けて実際にcluster作成もしくは作成済みclusterの更新を行う。

リソースは作っていなくても、kops的にはclusterの設定が(s3 bucket内に)存在している認識なので、kops create cluster からやり直したければ kops delete cluster でs3 bucket内の設定ファイルの削除を行う。

$ kops delete cluster --name cluster.kubernetes-aws-hands-on.k8s.local --state=s3://kubernetes-aws-hands-on --yes

寄り道: terraform planが見たい

kops create clusterkops update cluster--target terraform を指定すれば、terraform configurationsを生成できる。 

Ref. https://github.com/kubernetes/kops/blob/master/docs/terraform.md

$ kops update cluster cluster.kubernetes-aws-hands-on.k8s.local --state s3://kubernetes-aws-hands-on --target terraform
...略...
Terraform output has been placed into out/terraform
Run these commands to apply the configuration:
   cd out/terraform
   terraform plan
   terraform apply

Suggestions:
 * validate cluster: kops validate cluster
 * list nodes: kubectl get nodes --show-labels
 * ssh to the master: ssh -i ~/.ssh/id_rsa admin@api.cluster.kubernetes-aws-hands-on.k8s.local
The admin user is specific to Debian. If not using Debian please use the appropriate user based on your OS.
 * read about installing addons: https://github.com/kubernetes/kops/blob/master/docs/addons.md
$ cd ./out/terraform
$ terraform init
$ terraform plan
...略...
Plan: 41 to add, 0 to change, 0 to destroy.

見慣れたPlanが出力されて安心。kopsの範囲外のリソースも一緒にterraformで管理するためのオプションだと思うが、kopsが生成するコードに自前のコードを合わせるような感じになりそうで、clusterの状態変化が激しい場合は、運用がそんなに楽じゃない気もする。実際に活用している例はあるのだろうか。

Play with kops command

その他、kops関連メモ。

instance groups

kops独自の概念がある。

kops has the concept of "instance groups", which are a group of similar machines. On AWS, they map to an AutoScalingGroup. Ref. https://github.com/kubernetes/kops/blob/master/docs/instance_groups.md

Getting Started with kops on GCE

gcloud のさらにラッパーになろうとしているのだろうか? gcloudが十分役割を果たしているような...?

Ref. https://github.com/kubernetes/kops/blob/master/docs/tutorial/gce.md

kops get

$ kops get --name cluster.kubernetes-aws-hands-on.k8s.local
Cluster
NAME                        CLOUD   ZONES
cluster.kubernetes-aws-hands-on.k8s.local   aws ap-northeast-1a

Instance Groups
NAME            ROLE    MACHINETYPE MIN MAX SUBNETS
master-ap-northeast-1a  Master  m3.medium   1  1  ap-northeast-1a
nodes           Node    t2.medium   2  2  ap-northeast-1a
$ kops get --name cluster.kubernetes-aws-hands-on.k8s.local -o yaml

Cluster add-ons

Ref. https://github.com/kubernetes/kops/tree/master/vendor/k8s.io/kubernetes/cluster/addons

Installing Kubernetes Addons

ダッシュボードが簡単に作れた。

Ref. https://github.com/kubernetes/kops/blob/master/docs/addons.md

kubectl create -f https://raw.githubusercontent.com/kubernetes/kops/master/addons/kubernetes-dashboard/v1.7.1.yaml

ここではgossip-based clusterなので、ドキュメント通りのURLだと名前解決できなかった。実際のURLとパスワードは以下で取得できる。

$ kubectl config view --minify

Private Docker Registry in Kubernetes

未着手

Ref. https://github.com/kubernetes/kops/tree/master/vendor/k8s.io/kubernetes/cluster/addons/registry

Play with kubectl command

clusterがkopsで作成できたのでここからが本題。

cluster作成後はServer側のバージョンも表示される。

$ kubectl version
Client Version: version.Info{Major:"1", Minor:"8", GitVersion:"v1.8.4", GitCommit:"9befc2b8928a9426501d3bf62f72849d5cbcd5a3", GitTreeState:"clean", BuildDate:"2017-11-20T19:12:24Z", GoVersion:"go1.9.2", Compiler:"gc", Platform:"darwin/amd64"}
Server Version: version.Info{Major:"1", Minor:"7", GitVersion:"v1.7.10", GitCommit:"bebdeb749f1fa3da9e1312c4b08e439c404b3136", GitTreeState:"clean", BuildDate:"2017-11-03T16:31:49Z", GoVersion:"go1.8.3", Compiler:"gc", Platform:"linux/amd64"}

その他、GKEとは内容が異なるので、出力を雑に記録。

$ kubectl get nodes
NAME                                              STATUS    ROLES     AGE       VERSION
ip-172-20-47-66.ap-northeast-1.compute.internal   Ready     master    3h        v1.7.10
ip-172-20-52-56.ap-northeast-1.compute.internal   Ready     node      3h        v1.7.10
ip-172-20-59-5.ap-northeast-1.compute.internal    Ready     node      3h        v1.7.10
$ kubectl -n kube-system get po
NAME                                                                      READY     STATUS    RESTARTS   AGE
dns-controller-3497129722-vzgwc                                           1/1       Running   0          3h
etcd-server-events-ip-172-20-47-66.ap-northeast-1.compute.internal        1/1       Running   0          3h
etcd-server-ip-172-20-47-66.ap-northeast-1.compute.internal               1/1       Running   0          3h
kube-apiserver-ip-172-20-47-66.ap-northeast-1.compute.internal            1/1       Running   0          3h
kube-controller-manager-ip-172-20-47-66.ap-northeast-1.compute.internal   1/1       Running   0          3h
kube-dns-1311260920-ls7bb                                                 3/3       Running   0          3h
kube-dns-1311260920-p1px7                                                 3/3       Running   0          3h
kube-dns-autoscaler-1818915203-92fwn                                      1/1       Running   0          3h
kube-proxy-ip-172-20-47-66.ap-northeast-1.compute.internal                1/1       Running   0          3h
kube-proxy-ip-172-20-52-56.ap-northeast-1.compute.internal                1/1       Running   0          3h
kube-proxy-ip-172-20-59-5.ap-northeast-1.compute.internal                 1/1       Running   0          3h
kube-scheduler-ip-172-20-47-66.ap-northeast-1.compute.internal            1/1       Running   0          3h
$ kubectl cluster-info
Kubernetes master is running at https://api-cluster-kubernetes-aw-f1jv4s-1847301451.ap-northeast-1.elb.amazonaws.com
KubeDNS is running at https://api-cluster-kubernetes-aw-f1jv4s-1847301451.ap-northeast-1.elb.amazonaws.com/api/v1/namespaces/kube-system/services/kube-dns/proxy

To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.

WEB+DB PRESS Vol.99: 実践 Kubernetesの写経

kubectl が叩けて一通り喜んだところで、読んだだけで放置になっていたWEB+DB PRESS Vol.99の"実践 Kubernetes"を写経することにした。記事はGKE上にkubernetes clusterを構築しているけど、ここではkubectlでやることは同じと信じてkopsで立てたclusterを使って写経する。

寄り道: CrashLoopBackOff

最初 library/hello-worldで横着しようとしたら、コンテナが常駐サービスじゃないのでCrashLoopBackOffなるエラーが出た。調べたらset the Pod RestartPolicy to "OnFailure".と言われていた。これを設定しようと思ったらReplicationControllerの設定が要りそうなので、今は觀念して記事に従うことに。

$ kubectl get pods
NAME          READY     STATUS             RESTARTS   AGE
hello-world   0/1       CrashLoopBackOff   5          3m

エラーの詳細は以下で確認できる。podのデバッグはまず これを叩く感じ?

kubectl describe pod hello-world

寄り道: GCBにimageをpushする

GKEも触るつもりなので、物が揃っている今のうちにGCBにコンテナイメージの作成だけしておく。

記事掲載時と比べるとUIがだいぶ変わっているが、とにかくAPI dashboardのページに行ってGoogle Compute Engine API, Google Container Engine API, Google Cloud Container Builder APIをEnableにしておく。

gcloudコマンドをインストール。これもネット上の過去記事と比べると結構変わっているようで、今は以下の手順でautocompletionの設定までやれる(/usr/local/bin/ に配置した場合)。

$ /usr/local/bin/google-cloud-sdk/install.sh
$ echo 'source /usr/local/bin/google-cloud-sdk/completion.zsh.inc' >> ~/.zshrc
$ echo 'source /usr/local/bin/google-cloud-sdk/path.zsh.inc' >> ~/.zshrc
$ source ~/.zshrc
$ which gcloud
/usr/local/bin/google-cloud-sdk/bin/gcloud
$ gcloud components update

All components are up to date.

Ref. https://cloud.google.com/sdk/docs/quickstart-mac-os-x

gcloud initでログイン認証、プロジェクト指定、リージョン設定を済ませることができた。

$ gcloud init

submitする。末尾のカンマでカレントディレクトリを指定するのを忘れない。

$ cat cloudbuild.yaml
steps:
- name: 'gcr.io/cloud-builders/go:alpine'
  env: ['PROJECT_ROOT=kubernetes-hands-on']
  args: ['build', '-o', 'hello-world', 'main.go']
- name: 'gcr.io/cloud-builders/docker'
  env: ['PROJECT_ROOT=kubernetes-hands-on']
  args: ['build', '--tag=asia.gcr.io/$PROJECT_ID/wdpress/hello-world', '.']
images: ['asia.gcr.io/$PROJECT_ID/wdpress/hello-world']
$ go fmt main.go
$ gcloud container builds submit --config=cloudbuild.yaml .
$ gcloud container builds list
$ gcloud container builds describe [ID]

確認でbuilds describe叩こうとしたらIDまで自動補完された。便利。

ECRにimageをpushする

kopsで立ち上げたインスタンスにはECRへのアクセス権限がデフォルトで付与されているので、ECRをコンテナのrepositoryに使える。ECRはGCBと違ってimageのpushにgoとdockerが手元に必要になる。

$ GOOS=linux GOARCH=amd64 go build -o hello-world main.go
$ aws ecr create-repository --repository-name kubernetes-hands-on
$ export ECR_REPO=[Repository URI]
$ docker build --tag $ECR_REPO ./
$ docker images
$ aws ecr get-login --no-include-email
$ docker push $ECR_REPO
$ aws ecr list-images --repository-name kubernetes-hands-on

初めてのcreate pod

ECRへのpushまで済んでしまえば、後は素直にRepository URIをpodの定義を書くだけで良い。

apiVersion: v1
kind: Pod
metadata:
  name: hello-world
spec:
  containers:
    - image: [Repository URI]
      imagePullPolicy: Always
      name: hellow-world

Ref. https://kubernetes.io/docs/concepts/containers/images/#using-aws-ec2-container-registry

やっとpodがRunningになった。

$ kubectl create -f pod.yaml
$ kubectl get pods
NAME          READY     STATUS    RESTARTS   AGE
hello-world   1/1       Running   0          1m
$ kubectl port-forward hello-world 8080

:tada:

$ curl http://localhost:8080/
Hello World!%

遊んだ後はpodを消す。このコマンドも全部自動補完された。あらゆる局面でtab連打して良いっぽい。

$ kubectl delete pod hello-world

ここからが面白いってところで時間切れ。残りは現地で消化したい。

kops所感

思った以上に丁寧に作り込まれていて使いやすかった。dryrunあるし、helpが丁寧だし、実行後の出力に毎回次何すべきかを具体的なコマンド付きで提示してくれるのは気が利いてる。ただ、生成された大量のリソースをどうするのかはやっぱり気になる。まぁまだコードの管理はどうするかとか長期運用した場合どうかとか全然見えてないし、何とも言えない。GKEだともっとオールインワン感あるんだろうか?

与太話

このブログ記事のネタになった参加予定のHands-onは人気らしくREPEATとして同じ内容のセッションが二つ追加されている。

全体でみた時にkubernetesのセッションが14個なのに対して、Amazon ECSが関わるセッションが95個ある。serverless関連はもっと多いと思う。

ここまで書いてKubernetes Essentials for AWS と言うセッションが5つもリピートされていることに気がついた。

SKL64-R - [REPEAT] Kubernetes Essentials for AWS AWS offers a powerful platform to run Kuberentes in the cloud. In this skill session, you'll learn best practices for configuring, running, and scaling containers using Kubernetes on AWS. See how to setup Kubernetes to take advantage of the performance and scale of AWS, including deep integrations with existing AWS services.

既存のサービスと密に連携可能なkubernetesプラットフォーム...??AWSはマネージドサービスを含む広義のserverless推し、コンテナ関連はECS推し、を貫いている印象があったけど、今年の8/9にCloud Native Computing Foundation参加したし、そろそろ大きな発表があってもおかしくないのではないかなと個人的に邪推している。どんな形であっても発表が楽しみ。