kubernetesのWorkloadリソースについて整理してみた
はじめに
一年前まではkubernetes(主にGKE)の構築・運用を行っていましたが、ここ一年くらい全く触らなくなってしまったので、復習もかねて再入門したいと思います。
今回は、kubernetesの基礎にあたるWorkloadリソースについて整理します。
動作環境
本記事の検証環境は以下の通りです。
- クラウド:Google Cloud
- サービス:GKE
- GKEバージョン:1.27.11-gke.1062001
Workloadsカテゴリ
Workloadsカテゴリに所属するリソースは、kubernetesクラスタ上にコンテナを起動させるために利用します。以下、8種類のリソースがあります。
- Pod
- ReplicationController
- ReplicaSet
- Deployment
- DeamonSet
- StatefulSet
- Job
- CronJob
各Workloadカテゴリに分類されるリソースの階層関係
Pod
Workloadsリソースの最小単位はPodと呼ばれるリソースです。Podは1つ以上のコンテナから構成されており、同じPod内に存在するコンテナ同士はIPアドレスを共有します。そのため、Pod内のコンテナ間の通信にはlocalhostが利用できます。IPアドレスが同じなため、Pod内のコンテナそれぞれはポート番号が重複してはいけません。
Podを作成するmanifestファイル
apiVersion: v1
kind: Pod
metadata:
name: pod
spec:
containers:
- name: nginx-container
image: nginx:1.26
ports:
- containerPort: 80
Podを作成するmanifestファイルの適用
$ vi pod.yaml
$ kubectl apply -f pod.yaml
pod/pod created
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
pod 1/1 Running 0 23s
ReplicationController/ReplicaSet
ReplicationController/ReplicaSetは、Podのレプリカを作成し、指定した数のPodを維持し続けるリソースです。以前はReplicationControllerがPodのレプリカを作成するために用いられていましたが、現在はReplicaSetが利用されており、ReplicationControllerは廃止の流れになっています。
ReplicaSetでは、ノードやPodに障害が発生した場合でも、Podの数がReplicaSetで指定した数を満たすように別のノード上でPodを起動してくれます。この機能をセルフヒーリングと言います。
また、ReplicaSetで指定するPodの数を増減させることによって、容易にPodをスケーリングさせることもできます。
ReplicaSetを作成するmanifestファイル
apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: replicaset
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx-container
image: nginx:1.26
ports:
- containerPort: 80
ReplicaSetは特定のラベルがつけられたPodの数をカウントすることでPodの数を調整しています。
spec.template.metadata.labelsの部分に対応する「app:nginx」がPodに付与されるラベルで、spec.selector.matchLabelsの部分に対応する「app:nginx」でReplicaSetで制御するPodを指定しています。
ReplicaSetを作成するmanifestファイルの適用
$ vi replicaset.yaml
$ kubectl apply -f replicaset.yaml
replicaset.apps/replicaset created
$ kubectl get replicasets
NAME DESIRED CURRENT READY AGE
replicaset 3 3 3 19s
$ kubectl get replicasets -o wide
NAME DESIRED CURRENT READY AGE CONTAINERS IMAGES SELECTOR
replicaset 3 3 3 27s nginx-container nginx:1.26 app=nginx
$ kubectl get pods -l app=nginx -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
replicaset-fxp5p 1/1 Running 0 50s 192.168.1.20 gke-gke-cluster-node-pool-f7c3c726-4lxr <none> <none>
replicaset-krf5z 1/1 Running 0 50s 192.168.1.19 gke-gke-cluster-node-pool-f7c3c726-4lxr <none> <none>
replicaset-pvtdd 1/1 Running 0 50s 192.168.1.18 gke-gke-cluster-node-pool-f7c3c726-4lxr <none> <none>
セルフヒーリングの確認
Pod名が「replicaset-fxp5p」のPodを1つ手動で削除してみます。
削除後すぐにPodを確認すると、ReplicaSetによって別名のPodが再作成されていることが確認できました。
このセルフヒーリングの機能によってPod数が指定の数に保たれます。
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
replicaset-fxp5p 1/1 Running 0 7m43s
replicaset-krf5z 1/1 Running 0 7m43s
replicaset-pvtdd 1/1 Running 0 7m43s
$ kubectl delete pods replicaset-fxp5p
pod "replicaset-fxp5p" deleted
$ kubectl get pods -l app=nginx -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
replicaset-8p4l4 1/1 Running 0 4s 192.168.1.21 gke-gke-cluster-node-pool-f7c3c726-4lxr <none> <none>
replicaset-krf5z 1/1 Running 0 7m58s 192.168.1.19 gke-gke-cluster-node-pool-f7c3c726-4lxr <none> <none>
replicaset-pvtdd 1/1 Running 0 7m58s 192.168.1.18 gke-gke-cluster-node-pool-f7c3c726-4lxr <none> <none>
Deployment
Deploymentは、複数のReplicaSetを管理することで、ローリングアップデートやロールバックなどを実現するリソースです。Deployment→ReplicaSet→Podと3層の親子構造になっています。Deploymentのローリングアップデートの仕組みとしては以下のフローになります。
- 新しいReplicaSetを作成
- 新しいReplicaSet上のレプリカ数(Pod数)を徐々に増やす
- 古いReplicaSet上のレプリカ数(Pod数)を徐々に減らす
- (2、3)を繰り返す
- 古いReplicaSetはレプリカ数0で保持する
Deploymentはkubernetes上でもっとも推奨されているコンテナの起動方法になります。Pod単体でデプロイした場合は、Podに障害があった場合は再作成されませんし、ReplicaSetでデプロイした場合は、ローリングアップデート等の機能を利用することができません。
Deploymentを作成するmanifestファイル
apiVersion: apps/v1
kind: Deployment
metadata:
name: deployment
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx-container
image: nginx:1.26
ports:
- containerPort: 80
Deploymentを作成するmanifestファイルの適用
$ vi deployment.yaml
$ kubectl apply -f deployment.yaml
deployment.apps/deployment created
$ kubectl get deployment -o wide
NAME READY UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES SELECTOR
deployment 3/3 3 3 74s nginx-container nginx:1.26 app=nginx
$ kubectl get replicaset -o wide
NAME DESIRED CURRENT READY AGE CONTAINERS IMAGES SELECTOR
deployment-5b4699b5f 3 3 3 83s nginx-container nginx:1.26 app=nginx,pod-template-hash=5b4699b5f
$ kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
deployment-5b4699b5f-dn754 1/1 Running 0 89s 192.168.1.22 gke-gke-cluster-node-pool-f7c3c726-4lxr <none> <none>
deployment-5b4699b5f-vw88s 1/1 Running 0 89s 192.168.1.23 gke-gke-cluster-node-pool-f7c3c726-4lxr <none> <none>
deployment-5b4699b5f-z5lgq 1/1 Running 0 89s 192.168.1.24 gke-gke-cluster-node-pool-f7c3c726-4lxr <none> <none>
DaemonSet
DaemonSetは、各kubenetesノード上で1つずつPodを配置するリソースです。ReplicaSetでは、各kubenetesノード上に合計N個のPodを配置しますが、全てのkubenetesノード上に確実にPodが配置されるとも限りません。DaemonSetでは、レプリカ数は指定できず、1つのノードにPodを複数配置することもできません。ノードが増えた場合は、DaemonSetのPodは自動的にノード上に起動されます。用途としてはログをホスト単位で収集したり、Datadogエージェント等すべてのノード上で必ずどうさせたいプロセスのために利用されます。
DeamonSetを作成するmanifestファイル
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: daemonset
spec:
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx-container
image: nginx:1.26
ports:
- containerPort: 80
DeamonSetを作成するmanifestファイルの適用
$ vi daemonset.yaml
$ kubectl apply -f daemonset.yaml
daemonset.apps/daemonset created
$ kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
daemonset-x427q 1/1 Running 0 12s 192.168.1.26 gke-gke-cluster-node-pool-f7c3c726-4lxr <none> <none>
deploymentやreplicasetと異なり、レプリカ数を特に指定していませんが、ノードに対して1つPodが立ち上がるような動作になります。
StatefulSet
StatefulSetは、データベースコンテナ等ステートフルなワークロードに対応するためのリソースです。主な特徴として、
- 作成されるPod名のサフィックスは数字のインデックスが付与されたものになる。
- statefulset-0、statefulset-1
- Pod名が変わらない
- データを永続化するためにの仕組みがある。
- PersistentVolumeを使用している場合は、StatefulSetのPodが再起動した際にも同じディスクを利用して再作成される。
StatefulSetを作成するmanifestファイル
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: statefulset
spec:
serviceName: statefulset
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx-container
image: nginx:1.26
ports:
- containerPort: 80
volumeMounts:
- name: www
mountPath: /usr/share/nginx/html
volumeClaimTemplates:
- metadata:
name: www
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1G
StatefulSetを作成するmanifestファイルの適用
$ vi statefulset.yaml
$ kubectl delete -f daemonset.yaml
daemonset.apps "daemonset" deleted
$ kubectl apply -f statefulset.yaml
statefulset.apps/statefulset created
$ kubectl get statefulsets
NAME READY AGE
statefulset 3/3 6m57s
$ kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
statefulset-0 1/1 Running 0 7m11s 192.168.1.27 gke-gke-cluster-node-pool-f7c3c726-4lxr <none> <none>
statefulset-1 1/1 Running 0 6m55s 192.168.1.28 gke-gke-cluster-node-pool-f7c3c726-4lxr <none> <none>
statefulset-2 1/1 Running 0 6m40s 192.168.1.29 gke-gke-cluster-node-pool-f7c3c726-4lxr <none> <none>
$ kubectl get persistentvolumeclaims
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
www-statefulset-0 Bound pvc-06ae1ba3-7153-4b25-9d7c-bec00d1a459e 1Gi RWO standard-rwo 7m34s
www-statefulset-1 Bound pvc-ec72faac-a870-4ee8-9497-4ed3bc6f5cc5 1Gi RWO standard-rwo 7m18s
www-statefulset-2 Bound pvc-d7e80ae7-5572-45b9-a93b-0dc73c461ad4 1Gi RWO standard-rwo 7m3s
$ kubectl get persistentvolume
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pvc-06ae1ba3-7153-4b25-9d7c-bec00d1a459e 1Gi RWO Delete Bound default/www-statefulset-0 standard-rwo 7m52s
pvc-d7e80ae7-5572-45b9-a93b-0dc73c461ad4 1Gi RWO Delete Bound default/www-statefulset-2 standard-rwo 7m21s
pvc-ec72faac-a870-4ee8-9497-4ed3bc6f5cc5 1Gi RWO Delete Bound default/www-statefulset-1 standard-rwo
Job
Jobは、コンテナを利用して一度限りの処理を実行させるリソースです。ReplicaSetではPodが停止することは予期せぬエラーですが、Jobの場合は、Podの停止が正常終了として期待される用途に向いています。バッチ処理などで利用されます。一度だけ実行するタスクにも利用できますし、並列実行するタスクにも利用することができます。
Jobを作成するmanifestファイル
apiVersion: batch/v1
kind: Job
metadata:
name: job
spec:
completions: 1
parallelism: 1
backoffLimit: 10
template:
spec:
containers:
- name: tools-container
image: amsy810/tools:v2.0
command: ["sleep"]
args: ["60"]
restartPolicy: Never
Jobを作成するmanifestファイルの適用
$ vi job.yaml
$ kubectl apply -f job.yaml
job.batch/job created
$ kubectl get jobs
NAME COMPLETIONS DURATION AGE
job 0/1 7s 7s
$ kubectl get pods -o wide --watch
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
job-6nnnc 0/1 ContainerCreating 0 16s <none> gke-gke-cluster-node-pool-f7c3c726-4lxr <none> <none>
job-6nnnc 1/1 Running 0 16s 192.168.1.30 gke-gke-cluster-node-pool-f7c3c726-4lxr <none> <none>
job-6nnnc 0/1 Completed 0 77s 192.168.1.30 gke-gke-cluster-node-pool-f7c3c726-4lxr <none> <none>
job-6nnnc 0/1 Completed 0 78s <none> gke-gke-cluster-node-pool-f7c3c726-4lxr <none> <none>
job-6nnnc 0/1 Completed 0 79s 192.168.1.30 gke-gke-cluster-node-pool-f7c3c726-4lxr <none> <none>
job-6nnnc 0/1 Completed 0 79s 192.168.1.30 gke-gke-cluster-node-pool-f7c3c726-4lxr <none> <none>
$ kubectl get jobs
NAME COMPLETIONS DURATION AGE
job 1/1 79s 103s
CronJob
CronJobは、CronのようにスケジューリングされたJobを実行したい場合に利用します。CronJobがJobを管理し、JobがPodを管理するような3層の親子関係になっています。定期的なバッチ処理で利用する場合はJobよりもCronJobを利用します。
CronJobを作成するmanifestファイル
apiVersion: batch/v1
kind: CronJob
metadata:
name: cronjob
spec:
schedule: "*/1 * * * *"
concurrencyPolicy: Allow
startingDeadlineSeconds: 30
successfulJobsHistoryLimit: 5
failedJobsHistoryLimit: 3
suspend: false
jobTemplate:
spec:
completions: 1
parallelism: 1
backoffLimit: 0
template:
spec:
containers:
- name: tools-container
image: amsy810/random-exit:v2.0
restartPolicy: Never
CronJobを作成するmanifestファイルの適用
$ vi cronjob.yaml
$ kubectl apply -f cronjob.yaml
cronjob.batch/cronjob created
$ kubectl get cronjobs
NAME SCHEDULE SUSPEND ACTIVE LAST SCHEDULE AGE
cronjob */1 * * * * False 0 <none> 9s
$ kubectl get jobs -o wide --watch
NAME COMPLETIONS DURATION AGE CONTAINERS IMAGES SELECTOR
cronjob-28592599 0/1 12s 12s tools-container amsy810/random-exit:v2.0 batch.kubernetes.io/controller-uid=4b9f79f5-6194-4470-9bdf-261223737c3c
cronjob-28592600 0/1 0s tools-container amsy810/random-exit:v2.0 batch.kubernetes.io/controller-uid=a1748ca6-47c3-4264-abd2-ad533436459d
cronjob-28592600 0/1 0s 0s tools-container amsy810/random-exit:v2.0 batch.kubernetes.io/controller-uid=a1748ca6-47c3-4264-abd2-ad533436459d
cronjob-28592600 0/1 3s 3s tools-container amsy810/random-exit:v2.0 batch.kubernetes.io/controller-uid=a1748ca6-47c3-4264-abd2-ad533436459d
cronjob-28592600 1/1 3s 3s tools-container amsy810/random-exit:v2.0 batch.kubernetes.io/controller-uid=a1748ca6-47c3-4264-abd2-ad533436459d
Discussion