kakakakakku blog

Weekly Tech Blog: Keep on Learning!

AWS で Kubernetes クラスタを構築して学ぶワークショップ「aws-workshop-for-kubernetes」

Kubernetes を学ぶため,AWS から公式に公開されているワークショップ資料「aws-workshop-for-kubernetes」を試した.Kubernetes を学ぶためのコンテンツが網羅的にあるため,今回はワークショップの紹介と,実際に試した一部のコンテンツをまとめたいと思う.既に Kubernetes を詳しく知っている人であれば早く進められるかもしれないけど,Kubernetes 初心者だと,理解しながら進めることになるので,全コンテンツを終えるのはかなりの時間が必要になる気がする.ワークショップ資料は全て GitHub に公開されていて,誤植などがあれば,プルリクエストを送ることもできる.

github.com

なお,ワークショップ資料は AWS Technical Evangelists の「グプタ先生」がメインで作成されていて,それだけでもうモチベーションが上がる!

aws.amazon.com

aws-workshop-for-kubernetes 紹介

「aws-workshop-for-kubernetes」には,大きく3種類の「コース」がある.まずは「Standard」を試して,次に「Developer」か「Operations」に進むようになっている.

ワークショップ資料には計27個の「コンテンツ」があり,「コース」ごとに「コンテンツ」が割り当てられている.一部の「コンテンツ」はどの「コース」にも割り当てられていなかったりもするので,以下に割り当て表を作ってみた.気になる「コンテンツ」だけを試すこともできる.かなり,幅広く Kubernetes を学べるようになっている.

コンテンツ Standard コース Developer コース Operations コース
101: Start Here
102: Create a Kubernetes cluster using kops
103: Introduction to the Kubernetes CLI
201: Monitoring a Kubernetes Cluster
202: Leveraging a Service Mesh
203: Upgrading a Kubernetes Cluster
204: Logging with an EFK Stack
205: Autoscaling a Kubernetes Cluster
206: Deploy Kubernetes with Terraform and CloudFormation
301: Setting up a Local Development Environment
302: Service Discovery for Microservices
303: Updating Applications on Kubernetes
304: Scaling Applications on Kubernetes
305: Tracing Applications with Jaeger and X-Ray
306: Manage Applications with Helm
307: Store Persistent Data with StatefulSets and PVs
308: Cicd Workflows
309: Deploying a Chart Repository
310: Applying Chaos Engineering
401: ConfigMaps and Secrets
402: Authentication, Authorization, and Access
403: Admission Control for Kubernetes on AWS
404: Network Policies
405: Ingress Controllers
406: CoreDNS
501: Best Practices
502: For Further Reading

所要時間と料金

README を読むと,以下のように書いてあったけど,個人的にはもっと時間が掛かると思う(Kubernetes の理解度による).

  • Standard
    • 少なくとも2時間
  • Developer
    • 少なくとも4時間
  • Operations
    • 少なくとも4時間

We recommend at least 2 hours to complete the workshop. We recommend at least 4 hours for each of the extended paths.

さらに Kubernetes クラスタを Multi-Master で構築すると,インスタンス数も増えるため,料金もそこそこになる.README には「1日 $20 以下」と書いてあった.

You will incur charges as you go through these workshop guides as it will exceed the limits of AWS free tier. An estimate of charges (<$20/day) can be seen at this simple monthly calculator

101: Start Here

まず,開発環境として Cloud9 を使うため,CloudFormation で構築をする.東京リージョンでは Cloud9 が使えないため,今回はバージニアリージョンにした.また「新規 VPC」と「既存 VPC」から選べるため,今回は「既存 VPC」を選んだ.スタックを書く必要はなく「Deploy to AWS」を押すだけで,テンプレートが指定された状態で起動する.「サブネット」を指定したら,あとは特に何も指定せず,ポチポチと「次へ」を押せば,Cloud9 にアクセスできるようになる.

f:id:kakku22:20180402205107p:plain

次に,Cloud9 のターミナルで以下のスクリプトを実行する.

$ aws s3 cp s3://aws-kubernetes-artifacts/lab-ide-build.sh . && \
chmod +x lab-ide-build.sh && \
. ./lab-ide-build.sh

実行すると kubectl / kops をインストールすることができる.例えば kubectl だと以下のように確認できる.まだ Kubernetes クラスタを構築していないので kubectl get nodes がエラーになるのは問題なし.

$ which kubectl
/usr/local/bin/kubectl
$ kubectl get nodes
The connection to the server localhost:8080 was refused - did you specify the right host or port?

102: Create a Kubernetes cluster using kops

次に Kubernetes クラスタを管理するためのツール kops を使って,Kubernetes クラスタを構築する.なお,今回はクラスタ名の接尾辞を example.cluster.k8s.local にする.

github.com

Kubernetes クラスタの構成には,以下の2種類がある.例えば「ローリングアップデート」など,一部の機能に制約があるため,ワークショップでは「Multi-Master Cluster」で構築することが推奨になっていた.

  • Single-Master Cluster
  • Multi-Master Cluster

kops でクラスタを構築するときの $AWS_AVAILABILITY_ZONES には,リージョンごとの AZ を設定している.

$ echo $AWS_AVAILABILITY_ZONES
us-east-1a,us-east-1b,us-east-1c,us-east-1d,us-east-1e,us-east-1f

次に kops で「Multi-Master Cluster」を構築する.今回は3台のマスターノードと5台のワーカーノードにした.

$ kops create cluster \
  --name example.cluster.k8s.local \
  --master-count 3 \
  --node-count 5 \
  --zones $AWS_AVAILABILITY_ZONES \
  --yes

すると,構築が開始されて kops validate cluster で,状況を確認することができる.全ノード Ready になると,以下のような結果になる.AZ もキレイに分散されている.

$ kops validate cluster
Using cluster from kubectl context: example.cluster.k8s.local

Validating cluster example.cluster.k8s.local

INSTANCE GROUPS
NAME                    ROLE    MACHINETYPE     MIN     MAX     SUBNETS
master-us-east-1a       Master  m3.medium       1       1       us-east-1a
master-us-east-1b       Master  m3.medium       1       1       us-east-1b
master-us-east-1c       Master  c4.large        1       1       us-east-1c
nodes                   Node    t2.medium       5       5       us-east-1a,us-east-1b,us-east-1c,us-east-1d,us-east-1e,us-east-1f

NODE STATUS
NAME                            ROLE    READY
ip-172-20-126-120.ec2.internal  node    True
ip-172-20-127-95.ec2.internal   master  True
ip-172-20-154-201.ec2.internal  node    True
ip-172-20-187-147.ec2.internal  node    True
ip-172-20-206-67.ec2.internal   node    True
ip-172-20-48-37.ec2.internal    node    True
ip-172-20-52-159.ec2.internal   master  True
ip-172-20-76-97.ec2.internal    master  True

Pod Failures in kube-system
NAME
kube-dns-7f56f9f8c7-qxxbd

Validation Failed
Ready Master(s) 3 out of 3.
Ready Node(s) 5 out of 5.

your kube-system pods are NOT healthy example.cluster.k8s.local

構築後にコンテキストを確認した.

$ kubectl config get-contexts
CURRENT   NAME                        CLUSTER                     AUTHINFO                    NAMESPACE
*         example.cluster.k8s.local   example.cluster.k8s.local   example.cluster.k8s.local 

$ kubectl config current-context
example.cluster.k8s.local

103: Introduction to the Kubernetes CLI

103 では,kubectl を使って,Kubernetes の基本的なコンセプトを学んだ.

kubectl get nodes

まずは kubectl get nodes で,今回は Multi-Master でクラスタを構築したため,3台のマスターノードと5台のワーカーノードを確認することができた.

$ kubectl get nodes
NAME                             STATUS    ROLES     AGE       VERSION
ip-172-20-126-120.ec2.internal   Ready     node      7m        v1.8.7
ip-172-20-127-95.ec2.internal    Ready     master    8m        v1.8.7
ip-172-20-154-201.ec2.internal   Ready     node      7m        v1.8.7
ip-172-20-187-147.ec2.internal   Ready     node      7m        v1.8.7
ip-172-20-206-67.ec2.internal    Ready     node      7m        v1.8.7
ip-172-20-48-37.ec2.internal     Ready     node      7m        v1.8.7
ip-172-20-52-159.ec2.internal    Ready     master    8m        v1.8.7
ip-172-20-76-97.ec2.internal     Ready     master    6m        v1.8.7

次に Kubernetes クラスタの中に nginx のポッドを起動する.ポッドだけではなく,デプロイメントも確認することができた.

$ kubectl run nginx --image=nginx
deployment.apps "nginx" created

$ kubectl get deployments
NAME      DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
nginx     1         1         1            1           10s

$ kubectl get pods
NAME                    READY     STATUS    RESTARTS   AGE
nginx-7c87f569d-vwxjw   1/1       Running   0          30s

さらに docker exec のように kubectl exec でポッドの中に入ることもできた.最後は kubectl delete でデプロイメントごと削除をした.

$ kubectl exec -it nginx-7c87f569d-vwxjw /bin/bash
root@nginx-7c87f569d-vwxjw:/# ls -al /etc/nginx/conf.d/default.conf 
-rw-r--r-- 2 root root 1093 Mar 20 10:03 /etc/nginx/conf.d/default.conf
root@nginx-7c87f569d-vwxjw:/# exit

$ kubectl delete deployment/nginx
deployment.extensions "nginx" deleted

他にも

  • ポッド作成
  • デプロイメント作成
  • サービス作成

なども試した.デーモンセット,ジョブあたりは,今回は割愛した.

201: Monitoring a Kubernetes Cluster

次は Kubernetes のモニタリングを3種類学んだ.

  • Kubernetes Dashboard
  • Heapster, InfluxDB and Grafana
  • Prometheus, Node exporter and Grafana

まずは Kubernetes Dashboard をインストールした.

$ kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/master/src/deploy/recommended/kubernetes-dashboard.yaml
secret "kubernetes-dashboard-certs" created
serviceaccount "kubernetes-dashboard" created
role.rbac.authorization.k8s.io "kubernetes-dashboard-minimal" created
rolebinding.rbac.authorization.k8s.io "kubernetes-dashboard-minimal" created

deployment.apps "kubernetes-dashboard" created
service "kubernetes-dashboard" created

次に Cloud9 で Kubernetes Dashboard を起動すると,ターミナルが待機状態になるので,プロキシの URL にアクセスする.認証ではトークンが必要になるため kubectlsecret を取得する.

$ kubectl proxy --address 0.0.0.0 --accept-hosts '.*' --port 8080

# https://ENVIRONMENT_ID.vfs.cloud9.REGION_ID.amazonaws.com/api/v1/namespaces/kube-system/services/https:kubernetes-dashboard:/proxy/ にアクセスする

$ kubectl -n kube-system get secret
$ kubectl -n kube-system describe secret default-token-9znml  

すると,Kubernetes Dashboard にアクセスすることができて,ノード一覧などを確認することができた.

f:id:kakku22:20180402205259p:plain

f:id:kakku22:20180402205311p:plain

Heapster は今回は試さず,Kubernetes のモニタリングで導入事例もよく聞く Prometheus + Grafana を試した.ここはコンテンツの通りに進めることができた.

202: Leveraging a Service Mesh

次は Kubernetes で,サービスメッシュを実現するために,2種類のサービスを試した.

  • Linkerd
  • Istio

Linkerd

まず,Linkerd をインストールした.

$ kubectl apply -f https://raw.githubusercontent.com/linkerd/linkerd-examples/master/k8s-daemonset/k8s/linkerd.yml
configmap "l5d-config" created
daemonset.extensions "l5d" created
service "l5d" created

$ kubectl get pods
NAME        READY     STATUS    RESTARTS   AGE
l5d-bd6w4   2/2       Running   0          28s
l5d-l47gd   2/2       Running   0          28s
l5d-ldhxd   2/2       Running   0          28s
l5d-t6c2k   2/2       Running   0          28s
l5d-vrhm7   2/2       Running   0          28s

$ kubectl get svc
NAME         TYPE           CLUSTER-IP      EXTERNAL-IP        PORT(S)                                        AGE
kubernetes   ClusterIP      100.64.0.1      <none>             443/TCP                                        32m
l5d          LoadBalancer   100.65.92.151   a2a9d866b34c4...   4140:31859/TCP,4141:32072/TCP,9990:30369/TCP   48s

$ LINKERD_ELB=$(kubectl get svc l5d -o jsonpath="{.status.loadBalancer.ingress[0].*}")
$ echo http://$LINKERD_ELB:9990

# URL にアクセスをする

次に,Linkerd のデモとして,2種類のマイクロサービス helloworld を起動し,お互いにリクエストを飛ばしてみた.

$ kubectl apply -f https://raw.githubusercontent.com/linkerd/linkerd-examples/master/k8s-daemonset/k8s/hello-world.yml
replicationcontroller "hello" created
service "hello" created
replicationcontroller "world-v1" created
service "world-v1" created

$ http_proxy=$LINKERD_ELB:4140 curl -s http://hello
Hello (100.96.3.5) world (100.96.3.6)!!

すると,マイクロサービス間のリクエストを Linkerd でモニタリングすることができた.

f:id:kakku22:20180402212846p:plain

Istio

次に Istio で,同じく kubectl apply でインストールをした.

$ curl -L https://git.io/getLatestIstio | sh -
$ cd istio-0.6.0

$ istioctl version
Version: 0.6.0
GitRevision: 2cb09cdf040a8573330a127947b11e5082619895
User: root@a28f609ab931
Hub: docker.io/istio
GolangVersion: go1.9
BuildStatus: Clean

$ kubectl apply -f install/kubernetes/istio.yaml

$ kubectl get all --namespace istio-system

NAME                             READY     STATUS              RESTARTS   AGE
istio-ca-cd9dfbdbb-vc8mb         1/1       Running             0          11s
istio-ingress-84c7ddcb7f-g9kmb   0/1       ContainerCreating   0          12s
istio-mixer-67d9bd59cb-8swld     0/3       ContainerCreating   0          16s
istio-pilot-5dd75b8f7f-qfp22     0/2       ContainerCreating   0          13s

NAME            TYPE           CLUSTER-IP       EXTERNAL-IP        PORT(S)                                                            AGE
istio-ingress   LoadBalancer   100.66.156.34    a858a858a34c5...   80:32168/TCP,443:31401/TCP                                         13s
istio-mixer     ClusterIP      100.69.49.254    <none>             9091/TCP,15004/TCP,9093/TCP,9094/TCP,9102/TCP,9125/UDP,42422/TCP   16s
istio-pilot     ClusterIP      100.68.195.148   <none>             15003/TCP,8080/TCP,9093/TCP,443/TCP                                13s

NAME            DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
istio-ca        1         1         1            1           12s
istio-ingress   1         1         1            0           12s
istio-mixer     1         1         1            0           16s
istio-pilot     1         1         1            0           13s

NAME                       DESIRED   CURRENT   READY     AGE
istio-ca-cd9dfbdbb         1         1         1         12s
istio-ingress-84c7ddcb7f   1         1         0         12s
istio-mixer-67d9bd59cb     1         1         0         16s
istio-pilot-5dd75b8f7f     1         1         0         13s

NAME            DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
istio-ca        1         1         1            1           12s
istio-ingress   1         1         1            0           12s
istio-mixer     1         1         1            0           16s
istio-pilot     1         1         1            0           13s

NAME                       DESIRED   CURRENT   READY     AGE
istio-ca-cd9dfbdbb         1         1         1         12s
istio-ingress-84c7ddcb7f   1         1         0         12s
istio-mixer-67d9bd59cb     1         1         0         16s
istio-pilot-5dd75b8f7f     1         1         0         13s

次に,書籍のレビューを管理するサンプルアプリを起動し,Ingress のエンドポイントにアクセスをする.

$ kubectl apply -f <(istioctl kube-inject -f samples/bookinfo/kube/bookinfo.yaml)
service "details" created
deployment.extensions "details-v1" created
service "ratings" created
deployment.extensions "ratings-v1" created
service "reviews" created
deployment.extensions "reviews-v1" created
deployment.extensions "reviews-v2" created
deployment.extensions "reviews-v3" created
service "productpage" created
deployment.extensions "productpage-v1" created
ingress.extensions "gateway" created

$ ISTIO_INGRESS=$(kubectl get ingress gateway -o jsonpath="{.status.loadBalancer.ingress[0].*}")
echo http://$ISTIO_INGRESS/productpage

# URL にアクセスをする

マイクロサービスに,星付きのレビュー(v3)と星なしのレビュー(v1)があり,Envoy で加重ルーティングをしている.よって,リクエストを繰り返すと,星の有無が変わるというデモを試すことができた.

$ kubectl create -f samples/bookinfo/kube/route-rule-all-v1.yaml
routerule.config.istio.io "productpage-default" created
routerule.config.istio.io "reviews-default" created
routerule.config.istio.io "ratings-default" created
routerule.config.istio.io "details-default" created

$ kubectl replace -f samples/bookinfo/kube/route-rule-reviews-50-v3.yaml
routerule.config.istio.io "reviews-default" replaced

f:id:kakku22:20180402205504p:plain

試し終わったら

Kubernetes クラスターを削除しないと,特に Multi-Master の場合はインスタンスが多く起動しているため,予想以上に料金が発生してしまう.よって,試し終わったら,必ず削除する.削除も kops でできる.

$ kops get cluster
NAME                            CLOUD   ZONES
example.cluster.k8s.local       aws     us-east-1a,us-east-1b,us-east-1c,us-east-1d,us-east-1e,us-east-1f

$ kops delete cluster example.cluster.k8s.local --yes

まとめ

  • 「aws-workshop-for-kubernetes」を試した
  • 計27個の「コンテンツ」があり,充実しているので,Kubernetes 初心者じゃなくても楽しめる
  • 大きく3種類の「コース」があるのも良かった
  • 今回は「Standard コース」の途中までを試した

合わせて読む

もう少し Kubernetes の知識を増やしてからワークショップを試した方が理解が深まりそうなので,以下の2冊を購入した.さっそく読んでみて,読み終わったら,もう1度ワークショップを再開する予定.

入門 Kubernetes

入門 Kubernetes

  • 作者: Kelsey Hightower,Brendan Burns,Joe Beda,松浦隼人
  • 出版社/メーカー: オライリージャパン
  • 発売日: 2018/03/22
  • メディア: 単行本(ソフトカバー)
  • この商品を含むブログを見る

コンテナ・ベース・オーケストレーション Docker/Kubernetesで作るクラウド時代のシステム基盤

コンテナ・ベース・オーケストレーション Docker/Kubernetesで作るクラウド時代のシステム基盤

  • 作者: 橋本直哉,須江信洋,前佛雅人,境川章一郎,佐藤聖規,山田修司,青山尚暉,市川豊,平岡大祐,福田潔,矢野哲朗
  • 出版社/メーカー: 翔泳社
  • 発売日: 2018/03/15
  • メディア: 単行本(ソフトカバー)
  • この商品を含むブログを見る

AWS re:Invent 2017 : Mastering Kubernetes on AWS (CON308)

去年の re:Invent 2017 でグプタ先生の講演動画が公開されている.Kubernetes の構築(Minikube / Kops / EKS),Kubernetes における継続的デリバリー,IAM 管理,ロギングなど,多岐にわたる話が聞けてすごく良かった.グプタ先生が熱血すぎて英語が早すぎるけど(笑)講演の最後に「aws-workshop-for-kubernetes」の紹介も入っていて,どんな目的でワークショップ資料を作ったのか?などを聞くことができる.

www.youtube.com