Kubernetesについて理解を深めるため、を実際に動かしてみてその構成や挙動を整理してみました。
Kubernetesとは
Kubernetesとは、宣言的な構成管理と自動化を促進し、コンテナ化されたワークロードやサービスを管理するための、ポータブルで拡張性のあるオープンソースのプラットフォームです。
参考:https://kubernetes.io/ja/docs/concepts/overview/what-is-kubernetes/
Composeのように単一のDockerホスト上でコンテナ群を動かすのではなく、冗長性を得るため複数のホストを束ねてクラスタを構築し、その上で冗長化されたコンテナを動かします。
このようにKubernetesの登場により、複数のDockerなどのコンテナの管理や自動化が進み、この仕組みは「コンテナオーケストレーション」と呼ばれています。
サッカーの例えがわかりやすい
といってもなかなかイメージがつかないところ、Docker/Kubernetes超入門という本でKubernetsをサッカーで例えており、わかりやすくイメージしやすくなりました。
サッカーで例えるとコンテナが選手だとすると、Kubernetesは監督にあたります。グラウンドの正しい位置に選手(コンテナ)を配置し、チーム(アプリ)として連携を取れる形を作ります。
それだけでなく、怪我した選手(調子の悪いコンテナ)の交代や選手(コンテナ)をを減らしたり増やしたり(これはサッカーのルールから外れるが。。)などの仕事をします。
エンジニアはチームオーナーとして監督(Kubernetes)に「こういう方針でいきます」と頼んでおけばあとは任せておけるといった感じです。
Kubernetesの構成
参考:Docker/Kubernetes超入門
Kubernetesの構成は主に図の左側のコントロールプレーンと右側のデータプレーンにわかれます。大まかな担当は左側のマスターノードが頭脳として使われ、右側のワーカーノードは処理する肉体として使われます。
また、Kubernetesでシステムを構築する場合は、Kubernetes上だけで構築するのではなく右の図にある仮想マシンやクラウドが提供するマネージドサービスなども併用して開発するのが一般的です。
サービスやポッドのところは実際に動かしながら理解を深めていきます。
実際に触ってみる
というわけで実際にKubernetesを触っていきます。Docker Desktopが既にインストールされていれば環境設定から「Enable Kubernetes」にチェックを入れて有効化するだけで使えます。
マニフェストファイルを使ってNginxを動かす
Kubernetesのアプリ展開はマニフェストファイルと呼ばれる構成ファイルで行われるのが一般的です。今回はDocker/Kubernetes超入門の本を参考にポッドのマニフェストとそれを外部に公開するサービスのマニフェストを使ってNginxを展開します。
マニフェストファイルはYAML形式で記述します。それぞれの意味は以下のようになっています。
- apiVersion: マニフェストのバージョン
- kind: リソースの種類
- metadata: リソース名などのメタデータ
- spec: リソースの詳細
・pod.yml
1 2 3 4 5 6 7 8 9 10 11 12 13 | apiVersion: v1 kind: Pod metadata: name: web-pod labels: svc2pod: web spec: containers: - name: nginx image: nginx:1.17.6-alpine ports: - name: http containerPort: 80 |
サービスのマニフェストも上の部分はポッドと同じですが、重要なのはspecの下にある「selector」で、これを使ってサービスが接続するポッドを指定します。
先程ポッドのマニフェストで定義した「svc2pod: web」を指定し、このサービスの接続先を定義します。
selectorの下の「ports」は外部に公開するポートと接続先のポートを指定しています。portがKubernetes内部から接続で利用するポートでnodePortがホスト外から接続で利用するポートです。
・service.yml
1 2 3 4 5 6 7 8 9 10 11 12 | apiVersion: v1 kind: Service metadata: name: web-service spec: selector: svc2pod: web ports: - port: 80 targetPort: http nodePort: 30000 type: NodePort |
リソースを展開する
作成したマニフェストファイルを元にリソースを展開していきます。展開コマンドでは「kubectl apply -f」コマンドを使うのが一般的です
1 2 3 4 5 | $ kubectl apply -f pod.yml pod/web-pod created $ kubectl apply -f service.yml service/web-service created |
サービスリソースを確認するとweb-serviceが立ち上がっていることが確認できます。
1 2 3 | $ kubectl get services NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE web-service NodePort 10.99.80.170 <none> 80:30000/TCP 67s |
nodePortで指定したポートを指定し、http://127.0.0.1:30000/にアクセスするとNginxのページを見ることができます。
デプロイメントを試してみる
実際の運用ではポッドを機能拡張したデプロイメントというリソースを使うことが一般的なようなため、実際に動かして試してみます。
デプロイメントは内部に下位リソースとしてレプリカセットというリソースを持ち、それが水平スケールや自動復旧機能を担当します。デプロイメントの主要機能としては、ポッドのアップグレードで、バージョンアップなど発生した際に古いポッドを入れ替えてくれます。
Docker/Kubernetes超入門の本を参考に動かしてみます。
spec.replicasフィールドで指定された通り、5つのレプリカPodを作成します。
spec.strategy.rollingUpdateフィールドでPodの数を指定した個数ずつ増減させてアップデートしていきます。
spec.strategy.typeにRollingUpdateと指定し、spec.strategy.rollingUpdateにmaxSurgeとmaxUnavailableを指定します。
- maxSurge: replicasで指定した数よりも増やしていい最大Pod数(デフォルト値25%・絶対値 or %を設定)
- maxUnavailable: replicasで指定した数よりも減らしていい最大Pod数(デフォルト値25%・絶対値 or %を設定)
・db.yml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | apiVersion: v1 kind: Service metadata: name: db spec: selector: pod: db ports: - port: 6379 targetPort: redis type: ClusterIP --- apiVersion: v1 kind: Pod metadata: name: db labels: pod: db spec: containers: - name: db image: redis:5.0.6-alpine3.10 ports: - name: redis containerPort: 6379 |
・app.yml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | apiVersion: apps/v1 kind: Deployment metadata: name: app spec: replicas: 5 strategy: rollingUpdate: maxSurge: 50% maxUnavailable: 0% selector: matchLabels: pod: app template: metadata: name: app labels: pod: app spec: containers: - name: app image: sample/app ports: - name: http containerPort: 80 env: - name: REDIS_HOST value: db --- apiVersion: v1 kind: Service metadata: name: app spec: selector: pod: app ports: - port: 8080 targetPort: http nodePort: 30000 type: NodePort |
kubectl applyで展開し、ポッドを確認すると5つ起動していることが確認できます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | $ kubectl apply -f app.yml -f db.yml deployment.apps/app created service/app created service/db created pod/db created $ kubectl get po NAME READY STATUS RESTARTS AGE app-975c58898-7rzxk 1/1 Running 0 6m18s app-975c58898-clwxx 1/1 Running 0 6m18s app-975c58898-lqfdl 1/1 Running 0 6m18s app-975c58898-r64gw 1/1 Running 0 6m18s app-975c58898-s6jl4 1/1 Running 0 6m18s db 1/1 Running 0 12m $ kubectl get replicaset NAME DESIRED CURRENT READY AGE app-975c58898 5 5 5 6m |
デプロイメントの詳細情報は以下のコマンドで取得できます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | $ kubectl describe deployment app Name: app Namespace: default CreationTimestamp: Sun, 14 Nov 2021 07:15:16 +0900 Labels: <none> Annotations: deployment.kubernetes.io/revision: 1 Selector: pod=app Replicas: 5 desired | 5 updated | 5 total | 5 available | 0 unavailable StrategyType: RollingUpdate MinReadySeconds: 0 RollingUpdateStrategy: 0% max unavailable, 50% max surge Pod Template: Labels: pod=app Containers: app: Image: sample/app Port: 80/TCP Host Port: 0/TCP Environment: REDIS_HOST: db Mounts: <none> Volumes: <none> Conditions: Type Status Reason ---- ------ ------ Available True MinimumReplicasAvailable Progressing True NewReplicaSetAvailable OldReplicaSets: <none> NewReplicaSet: app-975c58898 (5/5 replicas created) Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal ScalingReplicaSet 17m deployment-controller Scaled up replica set app-975c58898 to 5 |