"Google Kubernetes Engine(GKE)"を使って"Kubernetes"について勉強した際の内容を自分用のメモとしてまとめました
"Kubernetesクラスタ"内のノードについて
"Kubernetesクラスタ"は大きく2種類のノードで構成されます
- Control Planeとなる**
マスターノード** - コンテナ実行環境となる**
ワーカーノード**
"Google Kubernetes Engine(GKE)"では、マスターノード側はフルマネージド提供され課金対象にもなりません。そのためワーカーノードのみ作成すれば、すぐに"Kubernetesクラスタ"環境を利用することが可能です。
"Kubernetesクラスタ"内のオブジェクトについて
"Kubernetesクラスタ"上のオブジェクトは、Ingress、Service、Podの3つのレイヤーに別けることができます

出典: Kubernetes NodePort vs LoadBalancer vs Ingress? When should I use what?
https://medium.com/google-cloud/kubernetes-nodeport-vs-loadbalancer-vs-ingress-when-should-i-use-what-922f010849e0
| 種類 | 説明 |
|---|---|
| Ingress | ”Kubernetesクラスタの外部からのトラフィック”を制御する**"L7アプリケーションデリバリーコントローラー(ADC)"**です。”Ingress”は”ワーカーノード”とは別の場所に、"Google Kubernetes Engine(GKE)"環境においては、"Google Cloud Load Balancing"ベースのソフトウェア定義として作成されます。 |
| Service | ”Ingressからのトラフィック”もしくは”同一Kubernetesクラスタ内部からのトラフィック”を制御する**”L4ロードバランサー”**です。 |
| Pod | ”ワーカーノード”上に作成する**”コンテナ”と”ボリューム”**です。”Pod”のデプロイ方式を管理するためのオブジェクト(ワークロード)として別途”Deployment”、”StatefulSet”、”DaemonSet”、”CronJob”といったオブジェクトがありますが、これらの説明については後述します。”Pod”内の永続的ボリュームを管理するオブジェクトとして”PersistentVolumeClaim”がありますが、こちらの説明についても後述します。 |
"GKE"を使って次の3つを実施し"Kubernetesクラスタ"上にWordpressのシステムを構築することを通じて"Kubernetesクラスタ"の仕組みを理解することを目指します
- スタティックなグローバルIPアドレスを1つ割り当てた**
Ingress**の作成 -
HorizontalPodAutoscaler(HPA)を使った**オートスケールするWebサーバーのPodとService**の作成 -
StatefulSetを使った**永続的なDBMS(MySQL)のPodとService**の作成
1. "Google Kubernetes Engine(GKE)"上にワーカーノードのクラスタを作成する
まず、ワーカーノードのクラスタの作成を"Google Cloud Platform(GCP)"のWebコンソールから行います。
□手順1-1: "Google Cloud Platform(GCP)"のWebコンソールにログインします
□手順1-2: ナビゲーションメニューからGoogle Kubernetes Engine>クラスタを選択します
□手順1-3: 画面右上のCloud Shellアイコンをクリックします
□手順1-4: 画面下にCloud Shellが表示されるまでしばらく待ちます
□手順1-5: gcloud config setコマンドでregionの設定を行います
asia-northeast1(東京リージョン)を指定します
$ gcloud config set compute/region "asia-northeast1"
Updated property [compute/region].
□手順1-6: 続けてgcloud config setコマンドでzoneの設定を行います
$ gcloud config set compute/zone "asia-northeast1-a"
Updated property [compute/zone].
□手順1-6: cloud container clusters createコマンドでワーカーノードのクラスタを作成します
my-worker-node-cluseterという名前で作成します
$ gcloud container clusters create "my-worker-node-cluseter"
□手順1-7: ワーカーノードのクラスタが作成されるまでしばく待ちます
□手順1-8: kubectl get allコマンドを実行してワーカーノードのクラスタが作成されたことを確認します
$ kubectl get all
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/kubernetes ClusterIP 10.15.240.1 <none> 443/TCP 91s
上記のように表示されれば、ワーカーノードのクラスタ作成は完了です
参考: gcloud compute instances listコマンドで個別のワーカーノードの情報を確認することができます
$ gcloud compute instances list
NAME ZONE MACHINE_TYPE PREEMPTIBLE INTERNAL_IP EXTERNAL_IP STATUS
gke-my-worker-node-cluse-default-pool-924284ce-bm6s asia-northeast1-a n1-standard-1 10.146.0.15 35.243.112.157 RUNNING
gke-my-worker-node-cluse-default-pool-924284ce-kpcs asia-northeast1-a n1-standard-1 10.146.0.16 104.198.83.208 RUNNING
gke-my-worker-node-cluse-default-pool-924284ce-td1m asia-northeast1-a n1-standard-1 10.146.0.17 104.198.120.68 RUNNING
2. Manifestの作成と適用
"Kubernetesクラスタ"上に作成する各種オブジェクトについては、コマンドで個別に作成することも可能ですがManifestと呼ばれるYAML形式のファイルを作成することにより一括した管理が可能になります
このManifestの作成単位についてはいろいろ考え方があると思いますが、ここでは、ワーカーノードの外に作成されるIngressについては独立して1つ作成し、ワーカーノード上に作成されるその他のオブジェクトについてはServiceの単位で作成したいと思います
□手順2-1: gcloud compute address createコマンドでGCP上にIngressに割り当てるためのスタティックなグローバルIPアドレスを1つ作成します
$ gcloud compute addresses create "my-ingress-address" --global
Created [https://www.googleapis.com/compute/v1/projects/proud-command-246805/global/addresses/my-ingress-address].
□手順2-2: gcloud compute address listコマンドで割り当てられたスタティックなグローバルIPアドレスを確認します
$ gcloud compute addresses list
NAME ADDRESS/RANGE TYPE PURPOSE NETWORK REGION SUBNET STATUS
my-ingress-address XXX.XXX.XXX.XXX EXTERNAL RESERVED
□手順2-3: Manifestを配置するためのディレクトリを作成してカレントディレクトリを移動します
$ export MANIFESTS_PATH=$HOME/my-manifests
$ mkdir -p $MANIFESTS_PATH
$ cd $MANIFESTS_PATH
$ pwd
□手順2-4: kubectl create namespaceコマンドでnamespaceを作成します
my-wordpressという名前でnamespaceを作成します
$ kubectl create namespace "my-wordpress"
namespace/my-wordpress created
$ kubectl get namespace
NAME STATUS AGE
default Active 24m
kube-public Active 24m
kube-system Active 24m
my-wordpress Active 22s
□手順2-5: この後のコマンドの実行を簡略化するためにkubectl config set-contextコマンドでデフォルトで使用するnamespaceを設定します
$ kubectl config set-context $(kubectl config current-context) --namespace="my-wordpress"
Context "gke_proud-command-246805_asia-northeast1-a_my-worker-node-cluseter" modified.
□手順2-6: まずnamespace名のディレクトリを作成します
$ mkdir -p $MANIFESTS_PATH/my-wordpress
□手順2-7: 作成したディレクトリ下にIngressのManifest(my-ingress.yaml)を作成します
このManifestでは、Ingressのオブジェクトのみを定義しています
$ vi $MANIFESTS_PATH/my-wordpress/my-ingress.yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: my-ingress # このIngressの名前を定義します
namespace: my-wordpress
annotations:
kubernetes.io/ingress.global-static-ip-name: my-ingress-address # 割り当てるスタティックIPアドレスを定義します
spec:
rules:
- http:
paths:
- path: /*
backend: # バックエンドのServiceとポート番号を定義します
serviceName: web-service
servicePort: 80
□手順2-8: 続いて、Webサーバー側のServiceのManifest(web-service.yaml)を作成します
このManifestでは、ServiceとDeployment、HorizontalPodAutoscalerの3種類のオブジェクトを定義しています
Deploymentはステートレス(非永続的)なPodを管理するためのオブジェクトです
HorizontalPodAutoscalerはPodのオートスケールを定義するためのオブジェクトです
HorizontalPodAutoscalerは指定したメトリックを30秒間隔で監視し、targetAverageValueで指定した値未満になるようPod数をminReplicasおよびmaxReplicasの間で自動調整します
$ vi $MANIFESTS_PATH/my-wordpress/web-service.yaml
apiVersion: v1
kind: Service
metadata:
name: web-service # このServiceの名前を定義します
namespace: my-wordpress
labels: # このServiceに付与するラベルを定義します
ServiceName: web-service
Environment: development
spec:
type: NodePort # Kubernetesクラスタ外部からのトラフィックも許可する場合はNodePortを設定します
ports: # Serviceが使用するポート番号(port)と紐づけを行うPod側のポート番号(targetPort)、Node側のポート番号(nodePort)を定義します
- port: 80
targetPort: 80
nodePort: 30080
protocol: TCP
selector: # このServiceに紐づけるPodをPodに付与したラベルで定義します
ServiceName: web-service
Environment: development
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-deployment # このDeploymentの名前を定義します
namespace: my-wordpress
labels: # このDeploymentに付与するラベルを定義します
ServiceName: web-service
Environment: development
spec:
replicas: 3 # 作成するPod数を定義します
selector:
matchLabels: # 作成するPodに付与するラベルを定義します
ServiceName: web-service
Environment: development
template:
metadata:
labels: # spec: -> selector: -> matchLabels: と同じ内容を記載する必要があります
ServiceName: web-service
Environment: development
spec:
containers:
- name: web-container # 作成するPodのコンテナ名を定義します
ports: # 作成するPodのコンテナで開放するポート情報を定義します
- name: http
containerPort: 80
protocol: TCP
resources:
requests: # コンテナデプロイ時に必要とするリソースを定義します(リソースが足りない場合デプロイはエラーになります)
cpu: 100m # 1vCPU = 1,000m を意味します
memory: 256Mi
limits: # コンテナリソースの上限を定義します(ノードのメモリが枯渇しないようにrequestsと同値を設定します)
memory: 256Mi
image: wordpress:5.2-apache # 作成するPodのコンテナ作成時に使用するDockerイメージを定義します
env: # 作成するPodのコンテナに設定する環境変数を定義します
- name: WORDPRESS_DB_HOST
value: "db-service:3306"
- name: WORDPRESS_DB_USER
value: "wordpress"
- name: WORDPRESS_DB_PASSWORD
value: "wordpress!"
- name: WORDPRESS_DB_NAME
value: "wordpress"
livenessProbe: # ヘルスチェックに使用する情報を定義します
httpGet:
path: /readme.html
port: 80
scheme: HTTP
initialDelaySeconds: 10
periodSeconds: 3
readinessProbe: # ヘルスチェックに使用する情報を定義します
httpGet:
path: /readme.html
port: 80
scheme: HTTP
initialDelaySeconds: 10
periodSeconds: 3
---
apiVersion: autoscaling/v2beta1
kind: HorizontalPodAutoscaler
metadata:
name: web-deployment-horizontal-pod-autoscaler
namespace: my-wordpress
spec:
scaleTargetRef: # オートスケールの対象とするDeploymentの名前を定義します
apiVersion: apps/v1
kind: Deployment
name: web-deployment
minReplicas: 3
maxReplicas: 10
metrics: # オートスケールのトリガーとするメトリックを定義します
- type: Pods
pods: # Pod 1台あたり 100 HTTP Requests per Second 以下になるよう調整します
metricName: http_requests
targetAverageValue: 100
参考: HorizontalPodAutoscalerで監視対象として設定するメトリックについて
監視対象として指定するメトリックの種類については、"HTTP Requests per Second"などRED Methodに基づいたものの方が良いと個人的に考えています
コンテナの性質上、CPU使用率/メモリ使用率などUSE Methodに基づいた監視対象メトリックのリソースが不足する場合は、ワーカーノードをオートスケールするように設定した方が良いと考えます
The RED Method: How to Instrument Your Services
https://grafana.com/blog/2018/08/02/the-red-method-how-to-instrument-your-services/
The USE Method
http://www.brendangregg.com/usemethod.html
□手順2-9: DB(MySQL)側のServiceのManifest(db-service.yaml)を作成します
このManifestでは、``ServiceとStatefulSet`、`PersistentVolumeClaim`の3種類のオブジェクトを定義します
StatefulSetはDeploymentとは異なりステートフル(永続的)なPodを管理するためのオブジェクトです
永続化を行う際に使用するストレージ領域についてはPersistentVolumeClaimというオブジェクトで定義します
$ vi $MANIFESTS_PATH/my-wordpress/db-service.yaml
apiVersion: v1
kind: Service
metadata:
name: db-service # このServiceの名前を定義します
namespace: my-wordpress
labels: # このServiceに付与するラベルを定義します
ServiceName: db-service
Environment: development
spec:
type: ClusterIP # Kubernetesクラスタ内のトラフィックのみ許可する場合はClusterIPを設定します
ports: # Serviceが使用するポート番号(port)と紐づけを行うPod側のポート番号(targetPort)を定義します
- port: 3306
targetPort: 3306
protocol: TCP
selector: # このServiceに紐づけるPodをPodに付与したラベルで定義します
ServiceName: db-service
Environment: development
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: db-statefulset # このStatefulSetの名前を定義します
namespace: my-wordpress
labels: # このStatefulSetに付与するラベルを定義します
ServiceName: db-service
Environment: development
spec:
replicas: 1 # 作成するPod数を定義します
serviceName: db-service # このStatefulSetに紐付けるServiceを定義します
selector:
matchLabels: # 作成するPodに付与するラベルを定義します
ServiceName: db-service
Environment: development
template:
metadata:
labels: # spec: -> selector: -> matchLabels: に記載した内容と同じ内容を記載する必要があります
ServiceName: db-service
Environment: development
spec:
volumes:
- name: db-persistent-volume # このPodのボリューム名を定義します
persistentVolumeClaim:
claimName: db-persistent-volume-claim # このPodのボリュームに紐づけるPersistentVolumeClaimを定義します
containers:
- name: db-container # 作成するPodのコンテナ名を定義します
ports: # 作成するPodのコンテナで開放するポート情報を定義します
- name: mysql
containerPort: 3306
protocol: TCP
resources:
requests: # コンテナデプロイ時に必要とするリソースを定義します(リソースが足りない場合デプロイはエラーになります)
cpu: 100m # 1vCPU = 1,000m を意味します
memory: 512Mi
limits: # コンテナリソースの上限を定義します(ノードのメモリが枯渇しないようにrequestsと同値を設定します)
memory: 512Mi
image: mysql:5.6 # 作成するPodのコンテナ作成時に使用するDockerイメージを定義します
env: # 作成するPodのコンテナに設定する環境変数を定義します
- name: MYSQL_ROOT_PASSWORD
value: "somewordpress"
- name: MYSQL_DATABASE
value: "wordpress"
- name: MYSQL_USER
value: "wordpress"
- name: MYSQL_PASSWORD
value: "wordpress!"
volumeMounts: # このPodのコンテナが使用するボリューム名とマウントポイントを定義します
- name: db-persistent-volume
mountPath: /var/lib/mysql
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: db-persistent-volume-claim # このPersistentVolumeClaimの名前を定義します
namespace: my-wordpress
labels: # このPersistentVolumeClaimに付与するラベルを定義します
ServiceName: db-service
Environment: development
spec:
accessModes:
- ReadWriteOnce # Read/Writeは単一Podからのみ許可することを意味します
resources:
requests:
storage: 20Gi # 作成するボリュームのサイズを定義します
□手順2-10: kubectl applyコマンドで、db-service関連のオブジェクトから作成します
$ kubectl apply -f $MANIFESTS_PATH/my-wordpress/db-service.yaml
□手順2-11: kubectl get allコマンドでオブジェクトが作成されたことを確認します
$ kubectl get all
NAME READY STATUS RESTARTS AGE
pod/db-statefulset-0 1/1 Running 0 46s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/db-service ClusterIP 10.15.241.248 <none> 3306/TCP 47s
NAME DESIRED CURRENT AGE
statefulset.apps/db-statefulset 1 1 47s
参考: StatefulSetは、ナビゲーションメニューのGoogle Kubernetes Engine>ワークロードから確認することができます
参考: Serviceは、ナビゲーションメニューのGoogle Kubernetes Engine>ServiceとIngressから確認することができます
参考: PersistentVolumeClaimは、ナビゲーションメニューのGoogle Kubernetes Engine>ストレージから確認することができます
□手順2-12: kubectl runコマンドを使ってテンポラリのPodを作成しServiceとの接続確認を行います
Serviceに割り当てられているClusterIPへは"Kubernetesクラスタ"内部からのみ疎通可能です
kubectl runコマンドを使えばテンポラリのPodを簡単に作成できるので、これを用いて接続確認を行います
$ kubectl run "mysql-client-pod" --image=mysql:5.6 --rm --restart=Never -it -- mysql -h "db-service" -u "wordpress" -p'wordpress!'
If you don't see a command prompt, try pressing enter.
mysql> quit
Bye
pod "mysql-client-pod" deleted
□手順2-13: 続いて、web-service関連のオブジェクトを作成します
$ kubectl apply -f $MANIFESTS_PATH/my-wordpress/web-service.yaml
□手順2-14: kubectl get allコマンドでオブジェクトが作成されたことを確認します
$ kubectl get all
NAME READY STATUS RESTARTS AGE
pod/db-statefulset-0 1/1 Running 0 29m
pod/web-deployment-5f4f68bf87-4vvnx 1/1 Running 0 16m
pod/web-deployment-5f4f68bf87-h2pr4 1/1 Running 0 16m
pod/web-deployment-5f4f68bf87-r5kjt 1/1 Running 0 16m
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/db-service ClusterIP 10.15.241.248 <none> 3306/TCP 29m
service/web-service NodePort 10.15.249.35 <none> 80:30080/TCP 16m
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
deployment.apps/web-deployment 3 3 3 3 16m
NAME DESIRED CURRENT READY AGE
replicaset.apps/web-deployment-5f4f68bf87 3 3 3 16m
NAME DESIRED CURRENT AGE
statefulset.apps/db-statefulset 1 1 29m
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
horizontalpodautoscaler.autoscaling/web-deployment-horizontal-pod-autoscaler Deployment/web-deployment <unknown>/10 3 10 3 43s
参考: Deploymentは、ナビゲーションメニューのGoogle Kubernetes Engine>ワークロードからが確認することができます
参考: Serviceは、ナビゲーションメニューのGoogle Kubernetes Engine>ServiceとIngressから確認することができます
□手順2-15: kubectl runコマンドを使ってテンポラリのPodを作成しServiceとの接続確認を行います
Webサーバー側についても同様にkubectl runコマンドを使ってテンポラリのPodを作成して接続確認を行います
$ kubectl run "curl-pod" --image=amazonlinux:2 --rm --restart=Never -it -- curl -I -Ss "http://web-service.my-wordpress.svc.cluster.local/readme.html"
HTTP/1.1 200 OK
Date: Fri, 09 Aug 2019 08:50:50 GMT
Server: Apache/2.4.38 (Debian)
Last-Modified: Mon, 08 Apr 2019 22:59:56 GMT
ETag: "1d17-5860ccb887300"
Accept-Ranges: bytes
Content-Length: 7447
Vary: Accept-Encoding
Content-Type: text/html
pod "curl-pod" deleted
□手順2-16: kubectl applyコマンドでIngress(my-ingress)を作成します
$ kubectl apply -f $MANIFESTS_PATH/my-wordpress/my-ingress.yaml
ingress.extensions/my-ingress created
□手順2-17: kubectl get ingressコマンドでIngressが作成されたことを確認します
"Google Kubernetes Engine(GKE)"環境において、Ingressの実体は、"Google Cloud Load Balancing"ベースのソフトウェア定義です
そのため、Ingressの作成には5分ほど要します
次に示すようにIPアドレスが割りてられるまで待つ必要があります
$ kubectl get ingress
NAME HOSTS ADDRESS PORTS AGE
my-ingress * 35.244.156.32 80 4m39s
参考: Ingressは、ナビゲーションメニューのGoogle Kubernetes Engine>ServiceとIngressから確認することができます
□手順2-18: ナビゲーションメニューからKubernetes Engine>Service と Ingressを選択します
□手順2-19: my-ingress列のエンドポイント欄部分をクリックして"Wordpress"の初期設定画面が表示されれば成功です
以上、Google Kubernetes Engine(GKE)上を使って "Wordpress" のシステムを構築するまでの手順でした
ここまでの手順が上手くいかなかった場合のトラブルシューティングの方法をいくつか記載しておきますので、参考にしてください
参考: kubectl port-forwardコマンドを使ったトラブルシューティング
Serviceに割り当てられたClusterIPへは"Kubernetesクラスタ"内部からのみしか接続できませんので、Ingress側の問題との切り分けを行う際はポートフォワーディングの設定が有効です
kubectl port-forwardコマンドでServiceに対してポートフォワーディングを設定します
$ kubectl port-forward service/web-service 8080:80
Cloud Shellの右上にあるウェブでプレビューアイコンをクリック後プレビューのポート:8080を選択します
"ポートフォワーディング"によりWebブラウザから直接ServiceのClusterIPに対してアクセスが可能になりました
参考: Podのトラブルシューティング
kubectl logsコマンドを使用することでPod個別のログメッセージを確認できます
$ kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE
db-statefulset-0 1/1 Running 0 159m 10.12.2.7 gke-my-worker-node-cluse-default-pool-924284ce-kpcs <none>
web-deployment-5f4f68bf87-4vvnx 1/1 Running 0 146m 10.12.2.15 gke-my-worker-node-cluse-default-pool-924284ce-kpcs <none>
web-deployment-5f4f68bf87-h2pr4 1/1 Running 0 146m 10.12.2.14 gke-my-worker-node-cluse-default-pool-924284ce-kpcs <none>
web-deployment-5f4f68bf87-r5kjt 1/1 Running 0 146m 10.12.1.5 gke-my-worker-node-cluse-default-pool-924284ce-td1m <none>
$ kubectl logs <Pod Name>
:
中略
:
より詳細な調査が必要な場合は、kubectl excecコマンドを使用することでPodに直接bashでログインすることができます
$ kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE
db-statefulset-0 1/1 Running 0 159m 10.12.2.7 gke-my-worker-node-cluse-default-pool-924284ce-kpcs <none>
web-deployment-5f4f68bf87-4vvnx 1/1 Running 0 146m 10.12.2.15 gke-my-worker-node-cluse-default-pool-924284ce-kpcs <none>
web-deployment-5f4f68bf87-h2pr4 1/1 Running 0 146m 10.12.2.14 gke-my-worker-node-cluse-default-pool-924284ce-kpcs <none>
web-deployment-5f4f68bf87-r5kjt 1/1 Running 0 146m 10.12.1.5 gke-my-worker-node-cluse-default-pool-924284ce-td1m <none>
$ kubectl exec <Pod Name> -it -- bash
root@<Pod Name>:/#h
3. Podのアップデートとロールバック
"Kubernetes"では、各Podの"Dockerイメージ"を簡単にアップデートしたりロールバックしたりすることが可能です
□手順3-1: sedコマンドを使ってManifest上のDockerイメージの値をwordpress:5.2-apacheからwordpress:5.2.2-apacheに書き換えます
sed -i -e "s/wordpress:5.2-apache/wordpress:5.2.2-apache/g" $MANIFESTS_PATH/my-wordpress/web-service.yaml
□手順3-2: kubectl applyコマンドで修正したManifestを上書き適用します
$ kubectl apply -f $MANIFESTS_PATH/my-wordpress/web-service.yaml
service/web-service unchanged
deployment.apps/web-deployment configured
horizontalpodautoscaler.autoscaling/web-deployment-horizontal-pod-autoscaler configured
□手順3-3: kubectl get podsコマンドでPodの状態を確認します
$ kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE
db-statefulset-0 1/1 Running 0 3h24m 10.12.2.7 gke-my-worker-node-cluse-default-pool-924284ce-kpcs <none>
web-deployment-5b7f866c47-c4b6w 0/1 ContainerCreating 0 24s <none> gke-my-worker-node-cluse-default-pool-924284ce-bm6s <none>
web-deployment-5b7f866c47-swvvb 1/1 Running 0 41s 10.12.2.24 gke-my-worker-node-cluse-default-pool-924284ce-kpcs <none>
web-deployment-5f4f68bf87-h2pr4 1/1 Running 0 3h11m 10.12.2.14 gke-my-worker-node-cluse-default-pool-924284ce-kpcs <none>
web-deployment-5f4f68bf87-r5kjt 1/1 Running 0 3h11m 10.12.1.5 gke-my-worker-node-cluse-default-pool-924284ce-td1m <none>
元々あった3つのPodはそのままで4つめのPodが作成されています
□手順3-4: しばらく待って、もう一度kubectl get podsコマンドでPodの状態を確認します
$ kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE
db-statefulset-0 1/1 Running 0 3h26m 10.12.2.7 gke-my-worker-node-cluse-default-pool-924284ce-kpcs <none>
web-deployment-5b7f866c47-c4b6w 1/1 Running 0 2m29s 10.12.0.7 gke-my-worker-node-cluse-default-pool-924284ce-bm6s <none>
web-deployment-5b7f866c47-qjg84 1/1 Running 0 112s 10.12.2.25 gke-my-worker-node-cluse-default-pool-924284ce-kpcs <none>
web-deployment-5b7f866c47-swvvb 1/1 Running 0 2m46s 10.12.2.24 gke-my-worker-node-cluse-default-pool-924284ce-kpcs <none>
Podの名前を確認するとすべてのPodが差し替えられた事がわかります
□手順3-5: kubectl rollout historyコマンドを実行します
$ kubectl rollout history deployment web-deployment
deployment.extensions/web-deployment
REVISION CHANGE-CAUSE
1 <none>
2 <none>
□手順3-5: kubectl rollout historyコマンドで1つ目のRevisionの情報を確認します
$ kubectl rollout history deployment web-deployment --revision 1
deployment.extensions/web-deployment with revision #1
Pod Template:
Labels: Environment=development
ServiceName=web-service
pod-template-hash=5f4f68bf87
Containers:
web-container:
Image: wordpress:5.2-apache
Port: 80/TCP
Host Port: 0/TCP
Limits:
memory: 256Mi
Requests:
cpu: 100m
memory: 256Mi
Liveness: http-get http://:80/readme.html delay=10s timeout=1s period=3s #success=1 #failure=3
Readiness: http-get http://:80/readme.html delay=10s timeout=1s period=3s #success=1 #failure=3
Environment:
WORDPRESS_DB_HOST: db-service:3306
WORDPRESS_DB_USER: wordpress
WORDPRESS_DB_PASSWORD: wordpress!
WORDPRESS_DB_NAME: wordpress
Mounts: <none>
Volumes: <none>
Dockerイメージとしてwordpress:5.2-apacheを使用していたことが確認できます
□手順3-6: 同様に2つ目のRevisionの詳細を確認します
$ kubectl rollout history deployment web-deployment --revision 2
deployment.extensions/web-deployment with revision #2
Pod Template:
Labels: Environment=development
ServiceName=web-service
pod-template-hash=5b7f866c47
Containers:
web-container:
Image: wordpress:5.2.2-apache
Port: 80/TCP
Host Port: 0/TCP
Limits:
memory: 256Mi
Requests:
cpu: 100m
memory: 256Mi
Liveness: http-get http://:80/readme.html delay=10s timeout=1s period=3s #success=1 #failure=3
Readiness: http-get http://:80/readme.html delay=10s timeout=1s period=3s #success=1 #failure=3
Environment:
WORDPRESS_DB_HOST: db-service:3306
WORDPRESS_DB_USER: wordpress
WORDPRESS_DB_PASSWORD: wordpress!
WORDPRESS_DB_NAME: wordpress
Mounts: <none>
Volumes: <none>
使用しているDockerイメージがwordpress:5.2.2-apacheに変更されていることが確認できます
□手順3-7: kubectl rollout undoコマンドを実行しロールバックを行います
$ kubectl rollout undo deployment web-deployment --to-revision 1
deployment.extensions/web-deployment
□手順3-8: kubectl rollout historyコマンドを実行します
$ kubectl rollout history deployment web-deployment
deployment.extensions/web-deployment
REVISION CHANGE-CAUSE
2 <none>
3 <none>
Revision 1が無くなってRevision 3が追加されています
□手順3-9: kubectl get podsコマンドでPodの状態を確認します
kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE
db-statefulset-0 1/1 Running 0 3h40m 10.12.2.7 gke-my-worker-node-cluse-default-pool-924284ce-kpcs <none>
web-deployment-5f4f68bf87-4ztjn 1/1 Running 0 5m39s 10.12.2.27 gke-my-worker-node-cluse-default-pool-924284ce-kpcs <none>
web-deployment-5f4f68bf87-m8wtz 1/1 Running 0 5m50s 10.12.2.26 gke-my-worker-node-cluse-default-pool-924284ce-kpcs <none>
web-deployment-5f4f68bf87-nfwbz 1/1 Running 0 6m4s 10.12.1.6 gke-my-worker-node-cluse-default-pool-924284ce-td1m <none>
Podの名前を確認するとすべてのPodがまた差し替えられた事がわかります
□手順3‐10: kubectl rollout historyコマンドで3つ目のRevisionの情報を確認します
$ kubectl rollout history deployment web-deployment --revision 3
deployment.extensions/web-deployment with revision #3
Pod Template:
Labels: Environment=development
ServiceName=web-service
pod-template-hash=5f4f68bf87
Containers:
web-container:
Image: wordpress:5.2-apache
Port: 80/TCP
Host Port: 0/TCP
Limits:
memory: 256Mi
Requests:
cpu: 100m
memory: 256Mi
Liveness: http-get http://:80/readme.html delay=10s timeout=1s period=3s #success=1 #failure=3
Readiness: http-get http://:80/readme.html delay=10s timeout=1s period=3s #success=1 #failure=3
Environment:
WORDPRESS_DB_HOST: db-service:3306
WORDPRESS_DB_USER: wordpress
WORDPRESS_DB_PASSWORD: wordpress!
WORDPRESS_DB_NAME: wordpress
Mounts: <none>
Volumes: <none>
使用しているDockerイメージがwordpress:5.2-apacheに戻っていることを確認できます
Podの"Dockerイメージ"を簡単にアップデートしたりロールバックしたりできることを確認できました
4. Pod障害時の挙動確認
Pod障害時の挙動について確認してみます。まずDeploymentによって作成された非永続的なPodが障害になったときの挙動について確認します
□手順4‐1: kubectl get podsコマンドで現在稼働しているPodの情報を確認します
$ kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE
db-statefulset-0 1/1 Running 0 3h44m 10.12.2.7 gke-my-worker-node-cluse-default-pool-924284ce-kpcs <none>
web-deployment-5f4f68bf87-4ztjn 1/1 Running 0 9m41s 10.12.2.27 gke-my-worker-node-cluse-default-pool-924284ce-kpcs <none>
web-deployment-5f4f68bf87-m8wtz 1/1 Running 0 9m52s 10.12.2.26 gke-my-worker-node-cluse-default-pool-924284ce-kpcs <none>
web-deployment-5f4f68bf87-nfwbz 1/1 Running 0 10m 10.12.1.6 gke-my-worker-node-cluse-default-pool-924284ce-td1m <none>
□手順4‐2: kubectl delete pod <Pod Name>コマンドでリストの一番下のPodを削除してみます
$ kubectl delete pod "web-deployment-5f4f68bf87-nfwbz"
pod "web-deployment-5f4f68bf87-nfwbz" deleted
□手順4‐3: kubectl get podsコマンドで直後のPodの状態を確認します
$ kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE
db-statefulset-0 1/1 Running 0 3h47m 10.12.2.7 gke-my-worker-node-cluse-default-pool-924284ce-kpcs <none>
web-deployment-5f4f68bf87-4ztjn 1/1 Running 0 11m 10.12.2.27 gke-my-worker-node-cluse-default-pool-924284ce-kpcs <none>
web-deployment-5f4f68bf87-m8wtz 1/1 Running 0 12m 10.12.2.26 gke-my-worker-node-cluse-default-pool-924284ce-kpcs <none>
web-deployment-5f4f68bf87-sst4v 1/1 Running 0 41s 10.12.2.28 gke-my-worker-node-cluse-default-pool-924284ce-kpcs <none>
すぐに新しいPodが別の名前で再作成されたことが確認できました。続いてStatefulSetによって作成された永続的なPodが障害になった場合の挙動について確認します
□手順4‐4: kubectl delete podコマンドでdb-statefulset-0を削除してみます
$ kubectl delete pod "db-statefulset-0"
pod "db-statefulset-0" deleted
□手順4‐5: kubectl get podsコマンドでPodの状態を確認します
$ kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE
db-statefulset-0 1/1 Running 0 59s 10.12.2.29 gke-my-worker-node-cluse-default-pool-924284ce-kpcs <none>
web-deployment-5f4f68bf87-4ztjn 1/1 Running 0 14m 10.12.2.27 gke-my-worker-node-cluse-default-pool-924284ce-kpcs <none>
web-deployment-5f4f68bf87-m8wtz 1/1 Running 0 15m 10.12.2.26 gke-my-worker-node-cluse-default-pool-924284ce-kpcs <none>
web-deployment-5f4f68bf87-sst4v 1/1 Running 0 3m41s 10.12.2.28 gke-my-worker-node-cluse-default-pool-924284ce-kpcs <none>
StatefulSetによって作成されたPodについては、Deploymentの時とは異なり同じ名前のPodが再作成されることが確認できました
5. ワーカーノード障害時の挙動確認
最後に、ワーカーノード障害時の挙動について確認してみます
□手順5‐1: kubectl get podsコマンドで現在稼働しているPodの情報を確認します
$ kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE
db-statefulset-0 1/1 Running 0 6m51s 10.12.2.29 gke-my-worker-node-cluse-default-pool-924284ce-kpcs <none>
web-deployment-5f4f68bf87-4ztjn 1/1 Running 0 20m 10.12.2.27 gke-my-worker-node-cluse-default-pool-924284ce-kpcs <none>
web-deployment-5f4f68bf87-cddpk 1/1 Running 0 2m 10.12.1.7 gke-my-worker-node-cluse-default-pool-924284ce-td1m <none>
web-deployment-5f4f68bf87-dvfns 1/1 Running 0 51s 10.12.2.31 gke-my-worker-node-cluse-default-pool-924284ce-kpcs <none>
□手順5‐2: StatefulSetによって作成されたPodが稼働しているワーカーノードにログインします
$ gcloud compute ssh "gke-my-worker-node-cluse-default-pool-924284ce-kpcs"
WARNING: The public SSH key file for gcloud does not exist.
WARNING: The private SSH key file for gcloud does not exist.
WARNING: You do not have an SSH key for gcloud.
WARNING: SSH keygen will be executed to generate a key.
This tool needs to create the directory [/home/kukita_keisuke/.ssh]
before being able to generate SSH keys.
Do you want to continue (Y/n)? Y
Generating public/private rsa key pair.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/kukita_keisuke/.ssh/google_compute_engine.
Your public key has been saved in /home/kukita_keisuke/.ssh/google_compute_engine.pub.
The key fingerprint is:
SHA256:FUxUU0YJTt5ObFMLIacFwiDU1kKz0ZAhqHeRiid6Eo8 kukita_keisuke@cs-6000-devshell-vm-e9163938-594a-4670-8c13-1d9ca474820d
The key's randomart image is:
+---[RSA 2048]----+
| o++BO=++*O=..|
| . oo=++o===o..|
| o . o.. ..o *. |
|.+ + . . + . |
|.++ . S . |
|E o |
| o |
| |
| |
+----[SHA256]-----+
Did you mean zone [asia-east1-b] for instance:
gke-my-worker-node-cluse-default-pool-924284ce-kpcs] (Y/n)? n
No zone specified. Using zone [asia-northeast1-a] for instance: [gke-my-worker-node-cluse-default-pool-924284ce-kpcs].
Updating project ssh metadata...⠶Updated [https://www.googleapis.com/compute/v1/projects/proud-command-246805].
Updating project ssh metadata...done.
Waiting for SSH key to propagate.
Warning: Permanently added 'compute.147868497783857976' (ED25519) to the list of known hosts.
Welcome to Kubernetes v1.12.8-gke.10!
You can find documentation for Kubernetes at:
http://docs.kubernetes.io/
The source for this release can be found at:
/home/kubernetes/kubernetes-src.tar.gz
Or you can download it at:
https://storage.googleapis.com/kubernetes-release-gke/release/v1.12.8-gke.10/kubernetes-src.tar.gz
It is based on the Kubernetes source at:
https://github.com/kubernetes/kubernetes/tree/v1.12.8-gke.10
For Kubernetes copyright and licensing information, see:
/home/kubernetes/LICENSES
□手順5‐3: ワーカーノードを再起動します
$ sudo /sbin/shutdown -r now
Connection to 104.198.83.208 closed by remote host.
Connection to 104.198.83.208 closed.
ERROR: (gcloud.compute.ssh) [/usr/bin/ssh] exited with return code [255].
□手順5‐4: kubectl get podsコマンドでPodの状態を確認します
$ kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE
db-statefulset-0 1/1 Running 1 18m 10.12.2.36 gke-my-worker-node-cluse-default-pool-924284ce-kpcs <none>
web-deployment-5f4f68bf87-4ztjn 1/1 Running 2 32m 10.12.2.35 gke-my-worker-node-cluse-default-pool-924284ce-kpcs <none>
web-deployment-5f4f68bf87-cddpk 1/1 Running 0 13m 10.12.1.7 gke-my-worker-node-cluse-default-pool-924284ce-td1m <none>
web-deployment-5f4f68bf87-dvfns 1/1 Running 2 12m 10.12.2.32 gke-my-worker-node-cluse-default-pool-924284ce-kpcs <none>
ワーカーノード障害時にも各Podは自動的に復旧されることが確認できます
おまけ: "Google Kubernetes Engine(GKE)" では1つの "Ingress" で "namespace" が異なる "Service" を登録できない?
"1つのグローバルIPアドレス"(≒1つのIngress)で複数のServiceへのトラフィックを管理することが可能だというのがIngressのメリットでもあります
この場合、namespaceは分けて管理したくなるのですが、"Google Kubernetes Engine(GKE)"側の制約として NG のようです(Kubernetes側の仕様としては問題ないです)
当初は以下のようなManifestを作成し、IngressとServiceとは異なるnamespaceを使って管理することを考えていました
$ vi $MANIFESTS_PATH/default/my-ingress.yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: my-ingress # このIngressの名前を定義します
namespace: default # Ingressのnamespaceはdefaultにします
annotations:
kubernetes.io/ingress.global-static-ip-name: my-ingress-address # 割り当てるスタティックIPアドレスを定義します
spec:
rules:
- http:
paths:
- path: /*
backend: # バックエンドのServiceとポート番号を定義します
serviceName: web-service
servicePort: 80
---
apiVersion: v1
kind: Service
metadata:
name: web-service
namespace: default # Ingressは同じ名前空間のServiceのみバックエンドとして登録可能です
labels: # このServiceに付与するラベルを定義します
ServiceName: web-service
Environment: development
spec:
type: ExternalName # ExternalName(外部名)は異なるnamespace上のServiceとリンクするために使用します
externalName: web-service.my-wordpress.svc.cluster.local # リンク先のServiceを指定します
ports:
- port: 80
targetPort: 80
protocol: TCP
ところがこの方法でIngressを作成すると下記のようなエラーメッセージが出力されてしまいました
error while evaluating the ingress spec: service "default/web-service" is type "ExternalName", expected "NodePort" or "LoadBalancer"
どうやらこれは、現時点での"Google Kubernetes Engine(GKE)"の制約↓のようですので、改善を期待したいところです
Cross-namespace Ingress #17088
https://github.com/kubernetes/kubernetes/issues/17088
以上、Google Kubernetes Engine(GKE)"を使って"Kubernetes"について勉強した際の内容でした
今回は、DeploymentとStatefulSetを中心に動きを確認してみましたが、Podを管理するためのオブジェクトとしては、他にも DaemonSet、CronJobといったものがあるため、別の記事としてまとめていきたいと思います