KubernetesのWorkloadsリソース(その1)
Workloadsリソース
連載の第3回目で、Kubernetes のリソースには、大きく分けて5つの種類があることをお話しました。今回と次回の2回に渡って、そのうちの1つであるWorkloadsリソースについて解説します。
リソースの分類 | 内容 |
---|---|
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宛で通信することが可能です。
多くの場合は1つのPodに1つのコンテナを含んでいますが、Proxyの役割をするコンテナ、設定値の動的な書き換えを行うコンテナ、ローカルキャッシュ用のコンテナ、SSL終端用のコンテナなどをPod内に入れておくことで2コンテナ以上を内包したPodが利用されることもあります。このようにメインのコンテナに加えて、補助的な役割を担うコンテナを内包した形から、補助するサブコンテナのことを「サイドカー」と呼ぶこともあります。
Podの作成
簡単なPodのサンプルを動作させてみます。まず設定ファイルですが、下記のようなファイルからsample-podを作成します。sample-pod内にnginx:1.12イメージを使ったコンテナが1つ入っている形になっており、80番ポートを開放するだけのシンプルなPodです。
apiVersion: v1 kind: Pod metadata: name: sample-pod spec: containers: - name: nginx-container image: nginx:1.12 ports: - containerPort: 80
設定ファイルを元にPodを作成します。
$ kubectl apply -f ./pod_sample.yml pod "sample-pod" created
それでは、起動したPodを確認してみましょう。
$ kubectl get pods NAME READY STATUS RESTARTS AGE sample-pod 1/1 Running 0 20s
正しくコンテナが動作していることがわかります。また、リソースのもう少し詳細な情報を取得するには「--output wide(-o wide)」オプションを追加します。
$ kubectl get pods --output wide NAME READY STATUS RESTARTS AGE IP NODE sample-pod 1/1 Running 0 59s 10.8.0.5 gke-k8s-default-pool-9c2aa160-d2pl
2つのコンテナを内包したPodの作成
下記は2つのコンテナを内包したPodの例です。
apiVersion: v1 kind: Pod metadata: name: sample-2pod spec: containers: - name: nginx-container-112 image: nginx:1.12 ports: - containerPort: 80 - name: nginx-container-113 image: nginx:1.13 ports: - containerPort: 8080
正常に起動すると、下記のように2/2でRunning状態になっていることが確認できます。
$ kubectl get pods NAME READY STATUS RESTARTS AGE sample-2pod 2/2 Running 0 9s
では、下記のようにcontainerPortを両方とも80番ポートに設定して、わざと衝突させた場合はどうなるでしょうか。
…(省略)… spec: containers: - name: nginx-container-112 image: nginx:1.12 ports: - containerPort: 80 - name: nginx-container-113 image: nginx:1.13 ports: - containerPort: 80
実際に作成後に起動してみると、2つ目のコンテナは起動していないことがわかります。PodはNetwork名前空間を共有しているため、通常のVM上で80ポートをbindするサービスを2つ起動できないのと同じ状態になります。Pod内ではcontainerPortが衝突しないようにしましょう。
$ kubectl apply -f ./2pod_sample.yml pod "sample-2pod" created $ kubectl get pods NAME READY STATUS RESTARTS AGE sample-2pod 1/2 Error 0 10s $ kubectl logs sample-2pod nginx-container-113 2018/03/21 04:45:33 [emerg] 1#1: bind() to 0.0.0.0:80 failed (98: Address already in use) nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address already in use)
コンテナへのログイン
実際にコンテナに入って確認するには「kubectl exec」でbashを実行します。
$ kubectl exec -it sample-pod /bin/bash
疑似端末を生成し(-t)、標準入力をパススルー(-i)しながら/bin/bashを起動することで、あたかもコンテナにsshログインしているような状態となります。
コンテナ内を確認してみても、正しくプロセスが動作しているようです。
root@sample-pod:/# ip a | grep inet inet 127.0.0.1/8 scope host lo inet 10.8.0.5/24 scope global eth0 root@sample-pod:/# ss -napt | grep LISTEN LISTEN 0 128 *:80 *:* users:(("nginx",pid=6,fd=6)) root@sample-pod:/# ps aux USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND root 1 0.0 0.0 1020 4 ? Ss 12:46 0:00 /pause root 6 0.0 0.0 31680 2868 ? Ss 12:46 0:00 nginx: master process nginx -g daemon off; nginx 11 0.0 0.0 32072 1688 ? S 12:46 0:00 nginx: worker process root 31 0.0 0.0 20240 1984 pts/0 Ss 13:19 0:00 bash 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を維持し続けるリソースです。
当初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を作成します。
apiVersion: apps/v1 kind: ReplicaSet metadata: name: sample-rs spec: replicas: 3 selector: matchLabels: app: sample-app template: metadata: labels: app: sample-app spec: containers: - name: nginx-container image: nginx:1.12 ports: - containerPort: 80
設定ファイルを元にReplicaSetを作成します。
$ kubectl apply -f ./rs_sample.yml replicaset "sample-rs" created
ReplicaSetを確認してみると、Podが3つ起動していることを確認できます。
$ kubectl get rs -o wide NAME DESIRED CURRENT READY AGE CONTAINERS IMAGES SELECTOR sample-rs 3 3 3 50s nginx-container nginx:1.12 app=sample-app
実際にラベルを指定してPodを確認してみても、3つ起動していることが確認できます。
$ kubectl get pod -l app=sample-app -o wide NAME READY STATUS RESTARTS AGE IP NODE sample-rs-cnvm5 1/1 Running 0 21s 10.8.1.6 gke-k8s-default-pool-9c2aa160-9f6b sample-rs-ttlsk 1/1 Running 0 21s 10.8.0.8 gke-k8s-default-pool-9c2aa160-d2pl sample-rs-wxtl8 1/1 Running 0 21s 10.8.2.8 gke-k8s-default-pool-9c2aa160-v5v4
また、ReplicaSetが生成するPodは、[ReplicaSet名]−[乱数]で命名されています。
Podの停止とオートヒーリング
ReplicaSetでは、ノードやPodに障害が発生した場合でも、Pod数を指定された数になるように別のノードでコンテナを起動してくれるため、障害時の影響を低減できます。これがKubernetesの大事なコンセプトの1つである「オートヒーリング」と呼ばれるものです。
オートヒーリングを確認するため、試しにPodを1つ削除してみましょう。
$ kubectl delete pod sample-rs-cnvm5 pod "sample-rs-cnvm5" deleted
再度Podを確認すると、ReplicaSetによってすぐにPodが新規に作成されていることがわかります。
$ kubectl get pod -o wide NAME READY STATUS RESTARTS AGE IP NODE sample-rs-2qnnv 1/1 Running 0 15s 10.8.1.7 gke-k8s-default-pool-9c2aa160-9f6b sample-rs-ttlsk 1/1 Running 0 1m 10.8.0.8 gke-k8s-default-pool-9c2aa160-d2pl sample-rs-wxtl8 1/1 Running 0 1m 10.8.2.8 gke-k8s-default-pool-9c2aa160-v5v4
ReplicaSetのPodの増減は「kubectl describe rs」とすることで履歴を確認できます。
$ kubectl describe rs sample-rs Name: sample-rs Namespace: default Selector: app=sample-app Labels: app=sample-app Annotations: <none> Replicas: 3 current / 3 desired Pods Status: 3 Running / 0 Waiting / 0 Succeeded / 0 Failed Pod Template: Labels: app=sample-app Containers: nginx-container: Image: nginx:1.12 Port: 80/TCP Environment: <none> Mounts: <none> Volumes: <none> Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal SuccessfulCreate 2m replicaset-controller Created pod: sample-rs-ttlsk Normal SuccessfulCreate 2m replicaset-controller Created pod: sample-rs-wxtl8 Normal SuccessfulCreate 2m replicaset-controller Created pod: sample-rs-cnvm5 Normal SuccessfulCreate 43s replicaset-controller Created pod: sample-rs-2qnnv
LabelとRepicaSet
ReplicaSetは、KubernetesがPodの監視を行うことで数を調整しています。監視は、特定のラベルがつけられたPodの数をカウントする形で実現しています。レプリカ数が不足している場合はtemplateからPodを生成し、レプリカ数が過剰な場合はラベルにマッチするPodのうち1つを削除します。
カウントされるPodのラベルは、下記のspec.selectorの部分で指定しています。
selector: matchLabels: app: sample-app
また、上記のReplicaSetのtemplateの例では、spec.template.metadata.labelsの部分に「app:sample-app」の設定が入っており、app:sample-appラベルが付与された状態で Pod が生成されるため、レプリカ数としてカウントされることになります。
labels: app: sample-app
もしわざとspec.selectorとspec.template.metadata.labelsを一致させないようにするとどうなるでしょう? 下記のリストのように不一致にすると、レプリカ数を増やそうとPodが永遠に作り続けられてしまうため、エラーが出て作成できないようになっています。
apiVersion: apps/v1 kind: ReplicaSet metadata: name: sample-rs spec: replicas: 3 selector: matchLabels: app: sample-app template: metadata: labels: app: sample-app-fail spec: containers: - name: nginx-container image: nginx:1.12 ports: - containerPort: 80
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を作成して、試してみます。
apiVersion: v1 kind: Pod metadata: name: sample-pod labels: app: sample-app spec: containers: - name: nginx-container image: nginx:1.13 ports: - containerPort: 80
作成後にPodの状態を見てみます。「kubectl get pods -L ...」のオプションを利用することで、各Podの指定したlabelも表示することが可能です。ラベルが重複している場合、ReplicaSetはPodを増やしすぎたと誤認し、4つのPodのうち1つの停止を試みます。今回の例では最後に作成したPodが削除されているだけですが、場合によっては既存のPodが削除されることもあるため、注意が必要です。
$ kubectl get pods -L NAME READY STATUS RESTARTS AGE APP sample-pod 0/1 Terminating 0 8s sample-app sample-rs-2qnnv 1/1 Running 0 7m sample-app sample-rs-ttlsk 1/1 Running 0 7m sample-app sample-rs-wxtl8 1/1 Running 0 7m sample-app
Kubernetesの動作に熟知するまでは、Labelはユニークにつけるようにするのが適切でしょう。1つのコンテナに複数のLabelを付与することも可能なため、下記のようにルールを決めてラベリングするようにしましょう。
labels: env: dev codename: system_a role: web-front
Podのスケーリング
ReplicaSetの設定を変更し、Podの数を変更してみましょう。方法は下記の2つがあります。
- yaml configを書き換えて「kubectl apply -f FILENAME」を実行する
- kubectl scaleコマンドを利用してスケール処理を行う
今回は「kubectl scale」を使ってスケーリングを行ってみます。scaleコマンドでスケール処理を行えるWorkloadsリソースは、Deployment、Job、ReplicaSet、ReplicationControllerの4種類のみです。
$ kubectl scale rs sample-rs --replicas 5 replicaset "sample-rs" scaled
ReplicaSetの状態を確認すると、Podが増えているのがわかります。
$ kubectl get rs NAME DESIRED CURRENT READY AGE sample-rs 5 5 5 13m
連載バックナンバー
Think ITメルマガ会員登録受付中
全文検索エンジンによるおすすめ記事
- KubernetesのWorkloadsリソース(その2)
- KubernetesのDiscovery&LBリソース(その2)
- Oracle Cloud Hangout Cafe Season7 #1「Kubnernetes 超入門」(2023年6月7日開催)
- KubernetesのConfig&Storageリソース(その1)
- Kubernetes上のコンテナをIngressでインターネットに公開するまで
- ドメインを考慮した柔軟なPodの配置を実現する「Balancer」
- KubernetesのDiscovery&LBリソース(その1)
- Kubernetesの基礎
- Oracle Cloud Hangout Cafe Season5 #3「Kubernetes のセキュリティ」(2022年3月9日開催)
- KubernetesのマニフェストをMagnumで実行する