PR
この連載が書籍になりました!『Kubernetes完全ガイド

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

2018年3月28日(水)
青山 真也
連載の3回目となる今回は、ユーザーが利用できるWorkloadsリソース8種類のうち4種類を紹介する。

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の共有

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

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を維持し続けるリソースです。

ReplicaSetリソース

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

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名]−[乱数]で命名されています。

ReplicaSetの命名規則

ReplicaSetの命名規則

Podの停止とオートヒーリング

ReplicaSetでは、ノードやPodに障害が発生した場合でも、Pod数を指定された数になるように別のノードでコンテナを起動してくれるため、障害時の影響を低減できます。これがKubernetesの大事なコンセプトの1つである「オートヒーリング」と呼ばれるものです。

ReplicaSet のオートヒーリング

ReplicaSet のオートヒーリング

オートヒーリングを確認するため、試しに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つを削除します。

ラベルによるReplicaSetのレプリカ数維持

ラベルによるReplicaSetのレプリカ数維持

カウントされる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.selectorspec.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
株式会社サイバーエージェント アドテク本部 Strategic Infrastructure Agency

2016年入社。OpenStackを使ったプライベートクラウドやGKE互換なコンテナプラットフォームをゼロから構築し、国内カンファレンスでのKeynoteに登壇。
その後、世界で2番目にCertified Kubernetes Application Developer、138番目にCertified Kubernetes Administratorの認定資格を取得。
現在はKubernetesやOpenStackなどOSSへのコントリビュート活動をはじめ、CNCF公式のCloud Native Meetup TokyoのOrganizerやJapan Container Daysの運営などコミュニティ活動にも従事している。

連載バックナンバー

仮想化/コンテナ技術解説
第9回

KubernetesのConfig&Storageリソース(その2)

2018/6/6
連載9回目となる今回は、Config&Storageリソースのうち、PersistentVolumeClaimについて解説する。
仮想化/コンテナ技術解説
第8回

KubernetesのConfig&Storageリソース(その1)

2018/5/31
今回と次回の2回に渡って、5種類に大別されるKubernetesのリソースのうち、Config&Storageリソースを解説する。
仮想化/コンテナ技術解説
第7回

KubernetesのDiscovery&LBリソース(その2)

2018/5/16
前回に引き続き、Discovery&LBリソースのServiceとIngressを紹介する。

Think IT会員サービス無料登録受付中

Think ITでは、より付加価値の高いコンテンツを会員サービスとして提供しています。会員登録を済ませてThink ITのWebサイトにログインすることでさまざまな限定特典を入手できるようになります。

Think IT会員サービスの概要とメリットをチェック

他にもこの記事が読まれています