Workloadsリソース
連載の第3回目で、Kubernetes のリソースには、大きく分けて5つの種類があることをお話しました。今回と次回の2回に渡って、そのうちの1つであるWorkloadsリソースについて解説します。
5種類に大別できるKubernetesのリソース
リソースの分類 | 内容 |
Workloadsリソース | コンテナの実行に関するリソース |
Discovery&LBリソース | コンテナを外部公開するようなエンドポイントを提供するリソース |
Config&Storageリソース | 設定・機密情報・永続化ボリュームなどに関するリソース |
Clusterリソース | セキュリティやクォータなどに関するリソース |
Metadataリソース | リソースを操作する系統のリソース |
Workloadsリソースは、クラスタ上にコンテナを起動させるのに利用するリソースです。内部的に利用されているものを除いて利用者が直接利用するものとしては、全部で8種類のWorkloadsリソースが存在します。
- Pod
- ReplicationController
- ReplicaSet
- Deployment(今回はここまで解説します)
- DaemonSet
- StatefulSet
- Job
- CronJob
Pod
Kubernetes では Workloads リソースの最小単位として、「Pod」とよばれるリソースが存在します。Pod は1つ以上のコンテナから構成されており、ネットワークは隔離されておらず、IP Addressなどは共有しています。言い換えると、2つのコンテナが入ったPodを作成した場合、2つのコンテナが同一のIP Addressを持つこととなります。そのため、Pod内のコンテナはお互いにlocalhost宛で通信することが可能です。
Pod内のNetwork Namespaceの共有
多くの場合は1つのPodに1つのコンテナを含んでいますが、Proxyの役割をするコンテナ、設定値の動的な書き換えを行うコンテナ、ローカルキャッシュ用のコンテナ、SSL終端用のコンテナなどをPod内に入れておくことで2コンテナ以上を内包したPodが利用されることもあります。このようにメインのコンテナに加えて、補助的な役割を担うコンテナを内包した形から、補助するサブコンテナのことを「サイドカー」と呼ぶこともあります。
コンテナのサイドカーパターン
Podの作成
簡単なPodのサンプルを動作させてみます。まず設定ファイルですが、下記のようなファイルからsample-podを作成します。sample-pod内にnginx:1.12イメージを使ったコンテナが1つ入っている形になっており、80番ポートを開放するだけのシンプルなPodです。
リスト1:サンプルのPodを作成するpod_sample.yml
07 | - name: nginx-container |
設定ファイルを元にPodを作成します。
リスト2:pod_sample.ymlからPodを作成
1 | $ kubectl apply -f ./pod_sample.yml |
2 | pod "sample-pod" created |
それでは、起動したPodを確認してみましょう。
リスト3:起動したPodの情報を確認
2 | NAME READY STATUS RESTARTS AGE |
3 | sample-pod 1/1 Running 0 20s |
正しくコンテナが動作していることがわかります。また、リソースのもう少し詳細な情報を取得するには「--output wide(-o wide)」オプションを追加します。
リスト4:より詳細な情報を出力する
1 | $ kubectl get pods --output wide |
2 | NAME READY STATUS RESTARTS AGE IP NODE |
3 | sample-pod 1/1 Running 0 59s 10.8.0.5 gke-k8s-default-pool-9c2aa160-d2pl |
2つのコンテナを内包したPodの作成
下記は2つのコンテナを内包したPodの例です。
リスト5:2つのコンテナを内包するPodを作成する2pod_sample.yml
07 | - name: nginx-container-112 |
11 | - name: nginx-container-113 |
正常に起動すると、下記のように2/2でRunning状態になっていることが確認できます。
リスト6:2つのコンテナがRunning状態に
2 | NAME READY STATUS RESTARTS AGE |
3 | sample-2pod 2/2 Running 0 9s |
では、下記のようにcontainerPortを両方とも80番ポートに設定して、わざと衝突させた場合はどうなるでしょうか。
リスト7:ポートを同じ番号に設定した場合(抜粋)
04 | - name: nginx-container-112 |
08 | - name: nginx-container-113 |
実際に作成後に起動してみると、2つ目のコンテナは起動していないことがわかります。PodはNetwork名前空間を共有しているため、通常のVM上で80ポートをbindするサービスを2つ起動できないのと同じ状態になります。Pod内ではcontainerPortが衝突しないようにしましょう。
リスト8:2つめのコンテナの起動に失敗している
01 | $ kubectl apply -f ./2pod_sample.yml |
02 | pod "sample-2pod" created |
05 | NAME READY STATUS RESTARTS AGE |
06 | sample-2pod 1/2 Error 0 10s |
08 | $ kubectl logs sample-2pod nginx-container-113 |
09 | 2018/03/21 04:45:33 [emerg] 1#1: bind() to 0.0.0.0:80 failed (98: Address already in use) |
10 | nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address already in use) |
コンテナへのログイン
実際にコンテナに入って確認するには「kubectl exec」でbashを実行します。
リスト9:コンテナ内のbashを実行
1 | $ kubectl exec -it sample-pod /bin/bash |
疑似端末を生成し(-t)、標準入力をパススルー(-i)しながら/bin/bashを起動することで、あたかもコンテナにsshログインしているような状態となります。
コンテナ内を確認してみても、正しくプロセスが動作しているようです。
リスト10:コンテナ内でプロセスを確認
01 | root@sample-pod:/# ip a | grep inet |
02 | inet 127.0.0.1/8 scope host lo |
03 | inet 10.8.0.5/24 scope global eth0 |
05 | root@sample-pod:/# ss -napt | grep LISTEN |
06 | LISTEN 0 128 *:80 *:* users:(("nginx",pid=6,fd=6)) |
08 | root@sample-pod:/# ps aux |
09 | USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND |
10 | root 1 0.0 0.0 1020 4 ? Ss 12:46 0:00 /pause |
11 | root 6 0.0 0.0 31680 2868 ? Ss 12:46 0:00 nginx: master process nginx -g daemon off; |
12 | nginx 11 0.0 0.0 32072 1688 ? S 12:46 0:00 nginx: worker process |
13 | root 31 0.0 0.0 20240 1984 pts/0 Ss 13:19 0:00 bash |
14 | root 48 0.0 0.0 17492 1148 pts/0 R+ 13:21 0:00 ps aux |
この他にも「kubectl exec -it sample-pod some-command」のように、色々なコマンドを実行することが可能です。
ReplicaSet/ReplicationController
ReplicaSet/ReplicationControllerはPodのレプリカを生成し、指定した数のPodを維持し続けるリソースです。
ReplicaSetリソース
当初Podのレプリカを生成するリソースはReplicationControllerという名前でしたが、Kubernetesのコンポーネントを彷彿とさせるように紛らわしかった過去の経緯から、ReplicaSetと名前を変え、合わせて一部機能の追加が行われました。細かいですが、ReplicationControllerではequality-based selectorでしたが、ReplicaSetではより強化されたset-based selectorを利用することで、柔軟なレプリケーションの設定が可能となりました。
ReplicationControllerは今後廃止の流れになっているため、基本的にはReplicaSetを利用するようにして下さい。
ReplicaSet の作成
簡単なReplicaSetのサンプルを動作させてみます。まず設定ファイルですが、下記のようなファイルから、sample-rsを作成します。spec.templateの部分には複製するPodの定義を書いておく形になります。今回の例では先ほどの単体で作成したPodを、「replicas=3」でスケールさせたReplicaSetを作成します。
リスト11:サンプルのReplicaSetを作成するrs_sample.yml
16 | - name: nginx-container |
設定ファイルを元にReplicaSetを作成します。
リスト12:ReplicaSetを作成
1 | $ kubectl apply -f ./rs_sample.yml |
2 | replicaset "sample-rs" created |
ReplicaSetを確認してみると、Podが3つ起動していることを確認できます。
リスト13:正しくPodが3つ起動している
1 | $ kubectl get rs -o wide |
2 | NAME DESIRED CURRENT READY AGE CONTAINERS IMAGES SELECTOR |
3 | sample-rs 3 3 3 50s nginx-container nginx:1.12 app=sample-app |
実際にラベルを指定してPodを確認してみても、3つ起動していることが確認できます。
リスト14:より詳細な情報を表示
1 | $ kubectl get pod -l app=sample-app -o wide |
2 | NAME READY STATUS RESTARTS AGE IP NODE |
3 | sample-rs-cnvm5 1/1 Running 0 21s 10.8.1.6 gke-k8s-default-pool-9c2aa160-9f6b |
4 | sample-rs-ttlsk 1/1 Running 0 21s 10.8.0.8 gke-k8s-default-pool-9c2aa160-d2pl |
5 | sample-rs-wxtl8 1/1 Running 0 21s 10.8.2.8 gke-k8s-default-pool-9c2aa160-v5v4 |
また、ReplicaSetが生成するPodは、[ReplicaSet名]−[乱数]で命名されています。
ReplicaSetの命名規則
Podの停止とオートヒーリング
ReplicaSetでは、ノードやPodに障害が発生した場合でも、Pod数を指定された数になるように別のノードでコンテナを起動してくれるため、障害時の影響を低減できます。これがKubernetesの大事なコンセプトの1つである「オートヒーリング」と呼ばれるものです。
ReplicaSet のオートヒーリング
オートヒーリングを確認するため、試しにPodを1つ削除してみましょう。
リスト15:Podを1つ削除する
1 | $ kubectl delete pod sample-rs-cnvm5 |
2 | pod "sample-rs-cnvm5" deleted |
再度Podを確認すると、ReplicaSetによってすぐにPodが新規に作成されていることがわかります。
リスト16:Podの数は3つに戻っている
1 | $ kubectl get pod -o wide |
2 | NAME READY STATUS RESTARTS AGE IP NODE |
3 | sample-rs-2qnnv 1/1 Running 0 15s 10.8.1.7 gke-k8s-default-pool-9c2aa160-9f6b |
4 | sample-rs-ttlsk 1/1 Running 0 1m 10.8.0.8 gke-k8s-default-pool-9c2aa160-d2pl |
5 | sample-rs-wxtl8 1/1 Running 0 1m 10.8.2.8 gke-k8s-default-pool-9c2aa160-v5v4 |
ReplicaSetのPodの増減は「kubectl describe rs」とすることで履歴を確認できます。
リスト17:Podの増減を確認
01 | $ kubectl describe rs sample-rs |
04 | Selector: app=sample-app |
07 | Replicas: 3 current / 3 desired |
08 | Pods Status: 3 Running / 0 Waiting / 0 Succeeded / 0 Failed |
10 | Labels: app=sample-app |
19 | Type Reason Age From Message |
20 | ---- ------ ---- ---- ------- |
21 | Normal SuccessfulCreate 2m replicaset-controller Created pod: sample-rs-ttlsk |
22 | Normal SuccessfulCreate 2m replicaset-controller Created pod: sample-rs-wxtl8 |
23 | Normal SuccessfulCreate 2m replicaset-controller Created pod: sample-rs-cnvm5 |
24 | Normal SuccessfulCreate 43s replicaset-controller Created pod: sample-rs-2qnnv |
LabelとRepicaSet
ReplicaSetは、KubernetesがPodの監視を行うことで数を調整しています。監視は、特定のラベルがつけられたPodの数をカウントする形で実現しています。レプリカ数が不足している場合はtemplateからPodを生成し、レプリカ数が過剰な場合はラベルにマッチするPodのうち1つを削除します。
ラベルによるReplicaSetのレプリカ数維持
カウントされるPodのラベルは、下記のspec.selectorの部分で指定しています。
また、上記のReplicaSetのtemplateの例では、spec.template.metadata.labelsの部分に「app:sample-app」の設定が入っており、app:sample-appラベルが付与された状態で Pod が生成されるため、レプリカ数としてカウントされることになります。
リスト19:作成されるPodのラベルはここで指定されている
もしわざとspec.selectorとspec.template.metadata.labelsを一致させないようにするとどうなるでしょう? 下記のリストのように不一致にすると、レプリカ数を増やそうとPodが永遠に作り続けられてしまうため、エラーが出て作成できないようになっています。
リスト20:エラーが出るように変更されたsample_rs
16 | - name: nginx-container |
リスト21:エラーメッセージ
1 | The ReplicaSet "sample-rs" is invalid: spec.template.metadata.labels: Invalid value: map[string]string{"app":"sample-app-fail"}: `selector` does not match template `labels` |
また、同じラベルを持つPodをReplicaSets外で立てた場合は、どうなるでしょう? 下記のようなlabelを持つsample-podを作成して、試してみます。
リスト22:同じラベルを持つPodをReplicaSets外で立てるための設定ファイル
09 | - name: nginx-container |
作成後にPodの状態を見てみます。「kubectl get pods -L ...」のオプションを利用することで、各Podの指定したlabelも表示することが可能です。ラベルが重複している場合、ReplicaSetはPodを増やしすぎたと誤認し、4つのPodのうち1つの停止を試みます。今回の例では最後に作成したPodが削除されているだけですが、場合によっては既存のPodが削除されることもあるため、注意が必要です。
リスト23:ReplicaSet外で立てたPodが停止されている
2 | NAME READY STATUS RESTARTS AGE APP |
3 | sample-pod 0/1 Terminating 0 8s sample-app |
4 | sample-rs-2qnnv 1/1 Running 0 7m sample-app |
5 | sample-rs-ttlsk 1/1 Running 0 7m sample-app |
6 | sample-rs-wxtl8 1/1 Running 0 7m sample-app |
Kubernetesの動作に熟知するまでは、Labelはユニークにつけるようにするのが適切でしょう。1つのコンテナに複数のLabelを付与することも可能なため、下記のようにルールを決めてラベリングするようにしましょう。
リスト24:Labelは1つのコンテナに複数付与できる
Podのスケーリング
ReplicaSetの設定を変更し、Podの数を変更してみましょう。方法は下記の2つがあります。
- yaml configを書き換えて「kubectl apply -f FILENAME」を実行する
- kubectl scaleコマンドを利用してスケール処理を行う
今回は「kubectl scale」を使ってスケーリングを行ってみます。scaleコマンドでスケール処理を行えるWorkloadsリソースは、Deployment、Job、ReplicaSet、ReplicationControllerの4種類のみです。
リスト25:scaleコマンドでスケーリング
1 | $ kubectl scale rs sample-rs --replicas 5 |
2 | replicaset "sample-rs" scaled |
ReplicaSetの状態を確認すると、Podが増えているのがわかります。
リスト26:Podが5つに増えている
2 | NAME DESIRED CURRENT READY AGE |