KubernetesのWorkloadsリソース(その1)

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宛で通信することが可能です。
多くの場合は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
apiVersion: v1
kind: Pod
metadata:
  name: sample-pod
spec:
  containers:
    - name: nginx-container
      image: nginx:1.12
      ports:
      - containerPort: 80
設定ファイルを元にPodを作成します。
リスト2:pod_sample.ymlからPodを作成
$ kubectl apply -f ./pod_sample.yml pod "sample-pod" created
それでは、起動したPodを確認してみましょう。
リスト3:起動したPodの情報を確認
$ kubectl get pods NAME READY STATUS RESTARTS AGE sample-pod 1/1 Running 0 20s
正しくコンテナが動作していることがわかります。また、リソースのもう少し詳細な情報を取得するには「--output wide(-o wide)」オプションを追加します。
リスト4:より詳細な情報を出力する
$ 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の例です。
リスト5:2つのコンテナを内包するPodを作成する2pod_sample.yml
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状態になっていることが確認できます。
リスト6:2つのコンテナがRunning状態に
$ kubectl get pods NAME READY STATUS RESTARTS AGE sample-2pod 2/2 Running 0 9s
では、下記のようにcontainerPortを両方とも80番ポートに設定して、わざと衝突させた場合はどうなるでしょうか。
リスト7:ポートを同じ番号に設定した場合(抜粋)
…(省略)…
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が衝突しないようにしましょう。
リスト8:2つめのコンテナの起動に失敗している
$ 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を実行します。
リスト9:コンテナ内のbashを実行
$ kubectl exec -it sample-pod /bin/bash
疑似端末を生成し(-t)、標準入力をパススルー(-i)しながら/bin/bashを起動することで、あたかもコンテナにsshログインしているような状態となります。
コンテナ内を確認してみても、正しくプロセスが動作しているようです。
リスト10:コンテナ内でプロセスを確認
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を作成します。
リスト11:サンプルのReplicaSetを作成するrs_sample.yml
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を作成します。
リスト12:ReplicaSetを作成
$ kubectl apply -f ./rs_sample.yml replicaset "sample-rs" created
ReplicaSetを確認してみると、Podが3つ起動していることを確認できます。
リスト13:正しく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つ起動していることが確認できます。
リスト14:より詳細な情報を表示
$ 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つ削除してみましょう。
リスト15:Podを1つ削除する
$ kubectl delete pod sample-rs-cnvm5 pod "sample-rs-cnvm5" deleted
再度Podを確認すると、ReplicaSetによってすぐにPodが新規に作成されていることがわかります。
リスト16:Podの数は3つに戻っている
$ 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」とすることで履歴を確認できます。
リスト17:Podの増減を確認
$ 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の部分で指定しています。
リスト18:カウントされるPodのラベルを指定
  selector:
    matchLabels:
      app: sample-app
また、上記のReplicaSetのtemplateの例では、spec.template.metadata.labelsの部分に「app:sample-app」の設定が入っており、app:sample-appラベルが付与された状態で Pod が生成されるため、レプリカ数としてカウントされることになります。
リスト19:作成されるPodのラベルはここで指定されている
      labels:
        app: sample-app
もしわざとspec.selectorとspec.template.metadata.labelsを一致させないようにするとどうなるでしょう? 下記のリストのように不一致にすると、レプリカ数を増やそうとPodが永遠に作り続けられてしまうため、エラーが出て作成できないようになっています。
リスト20:エラーが出るように変更されたsample_rs
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
リスト21:エラーメッセージ
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外で立てるための設定ファイル
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が削除されることもあるため、注意が必要です。
リスト23:ReplicaSet外で立てた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を付与することも可能なため、下記のようにルールを決めてラベリングするようにしましょう。
リスト24:Labelは1つのコンテナに複数付与できる
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種類のみです。
リスト25:scaleコマンドでスケーリング
$ kubectl scale rs sample-rs --replicas 5 replicaset "sample-rs" scaled
ReplicaSetの状態を確認すると、Podが増えているのがわかります。
リスト26:Podが5つに増えている
$ 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で実行する
 











