🌟

Kubernetesのオブジェクトについて ~マニフェストを添えて~

2022/04/03に公開

記事の目的

kubernetes(以下k8s)を触り始めるにあたり、Podなどの概念を理解していなかったので、リソース操作の基本的なオブジェクトの概要、マニフェストの書き方についてまとめておく。

オブジェクトについて

k8sのクラスターを表現するためのエンティティ。
k8sはオブジェクトで定義した状態を、コントロールプレーンが常に現在の状態の差分を埋め、理想の状態に管理します。
オブジェクトの操作方法は基本的にはkubectlコマンドを通して、マニフェストに記載したオブジェクトの状態を操作することが可能です。

オブジェクトでは以下のような状態を管理することができます。下の例はあくまでk8sでできることの一部であることに注意してください。

  • どのようなコンテナ化されたアプリケーションをデプロイするか
  • デプロイしたアプリのヒーリング機能
  • アプリのアップデート戦略

次の章からこれらの機能について具体的にどのオブジェクトを操作することで実現できるのかをまとめていきます。

なお、オブジェクトの説明については各章で説明の記載をしていますが、kubectl explain <object>で確認することが可能です。
たとえば、Podのspecフィールドにどのような項目を指定できるかなどはkubectl explain pods.specで確認することができます。

Pod

Podはk8sで管理できる最小のデプロイ可能な単位。
Podは1つ以上のコンテナを持ち、ストレージ、ネットワークのリソースを共有。
また、コンテナには実行方法に関するルールが指定可能です。

Pod内のコンテナは、コントロールプレーンによって、クラスター内の同じホスト上に自動的に配置、スケジュールされます。

基本的にはPodは直接デプロイされるものではありません。代わりにDeploymentやJobなどのワークロードリソースと呼ばれるものを使用してPodの作成を行います。

Podを直接デプロイする場合のマニフェストは以下の通り。

apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  containers:
  - name: nginx
    image: nginx:1.18-alpine
    ports:
    - containerPort: 80
項目 説明
apiVersion オブジェクトが定義されているバージョン
kind オブジェトを表す文字列
metadata オブジェクトのメタデータ
metadata.name ネームスペース内で自身を表す一意な文字列
spec Podのふるまいを定義する
spec.containers Podで動作するコンテナの一覧。少なくとも1つの要素を持つ
spec.containers[].name DNS_LABELとしてのPod内でユニークな名前
spec.containers[].image Dockerイメージ名
spec.containers[].ports コンテナから公開するポート
spec.containers[].ports[].containerPort PodのIPアドレスで公開するポート番号

ReplicaSet

Podを指定した個数で維持することを目的としたオブジェクト。
Podの個数維持はk8sのセルフヒーリング機能で実現しています。

通常、DeploymentというReplicaSetにPodのアップデート機能を追加したオブジェクトを介してPodの個数維持を定義するため、アップデート機能を必要としない限りはReplicaSetを直接使うことは基本的にはないとおもいます。

ReplicaSetを作成するマニフェストは以下の通りです。

apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: replicaset-nginx
spec:
  replicas: 2
  selector:
    matchLabels:
      app: replicaset-nginx
  template:
    metadata:
      labels:
        app: replicaset-nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.18-alpine
        ports:
        - containerPort: 80
項目 説明
apiVersion オブジェクトが定義されているバージョン
kind オブジェトを表す文字列
metadata オブジェクトのメタデータ
metadata.name ネームスペース内で自身を表す一意な文字列
spec ReplicaSetのふるまいを定義する
spec.replicas 希望したいPod数
spec.selector ReplicaSetでスケールさせたいPodに一致させるためのクエリ。replica countと一致する必要がある
spec.selector.matchLabels スケールさせたいPodが持つラベルを指定。複数指定可能で、それらはAND条件
spec.template Pod章のspec配下の説明と同じ

Deployment

DeploymentはReplicaSetの機能に、Podのアップデート機能を追加したもの。

Deploymentを利用することで、ReplicaSetを作成したり、既存のDeploymentを新しいDeploymentにアップデートすることが可能になります。
アップデートではイメージなどの更新が走った際に、更新ルールにのっとってPodが順に切り替わっていきます。
試しにdeploymentをデプロイしたマニフェストのイメージなどのバージョンを変更して再度applyしなおすと、Podが切り替わっていく様子がkubectl get podsを通して確認できます。
アップデートの方法はいくつかの方法が存在し、マニフェストのspec.strategyで指定可能です。

Deploymentのマニフェストは以下の通りです。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: deployment-nginx
  labels:
    name: nginx
spec:
  replicas: 2
  selector:
    matchLabels:
      app: deployment-nginx
  template:
    metadata:
      labels:
        app: deployment-nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.21-alpine
        ports:
        - containerPort: 80
項目 説明
apiVersion オブジェクトが定義されているバージョン
kind オブジェトを表す文字列
metadata オブジェクトのメタデータ
metadata.name ネームスペース内で自身を表す一意な文字列
metadata.labesl オブジェクトに付与するラベル
spec Deploymentのふるまいを定義する
spec.replicas 希望したいPod数
spec.selector Podに付与されたラベルを指定。これと一致するPodを持つReplicaSetをDeploymentで管理する
spec.selector.matchLabels スケールさせたいPodが持つラベルを指定。複数指定可能で、それらはAND条件
spec.template Pod章のspec配下の説明と同じ

Service

Podの集合に対して、ネットワークサービスとして公開するためのオブジェクト。

PodはそれぞれにIPアドレスが割り当てられますが、状況によってはPodは削除され再作成されます。
このとき、再作成されたPodのIPアドレスはもともとのPodのIPアドレスは異なってきます。
ServiceはこのPodの特定のために、セレクター機能を使うことで解決します。下のマニフェスト例ではspec.selectorapp: deployment-nginxのラベルを持つPodに対してservice-nginxという名前でアクセス可能になります。

また、Pod以外への通信も抽象化可能です。この場合、セレクターによる指定ではなくEndpointsオブジェクトを明示的に組み合わせることでk8s以外のコンポーネントへの通信も抽象化できます。

Serviceのマニフェストは以下の通りです。

apiVersion: v1
kind: Service
metadata:
  name: service-nginx
spec:
  selector:
    app: deployment-nginx
  ports:
    - protocol: TCP
      port: 8080
      targetPort: 80
項目 説明
apiVersion オブジェクトが定義されているバージョン
kind オブジェトを表す文字列
metadata オブジェクトのメタデータ
metadata.name ネームスペース内で自身を表す一意な文字列
spec Serviceのふるまいを定義する
spec.selector Podに付与されたラベルを指定。これと一致するPodを持つPodに対してServiceが通信を転送する
spec.ports サービスによって展開されるポートのリスト
spec.ports[].protocol Serviceで扱うプロトコル
spec.ports[].port Serviceによって公開したいPod側のポート
spec.ports[].targetPort portへの通信で、外部からアクセスする際に使用する外部のポート

ConfigMap

ConfigMapは他のオブジェクトが参照するためのデータを保存するためのオブジェクト。

dataセクション配下にkey-valueの形式でデータを定義することで、PodからConfigMapのmetadata.nameをもとにボリュームにマウントすることが可能になります。
また、ConfigMapを使ってデータをPodに読ませることで、ConfigMapで変更した内容を自動的にPodに知らせることができ、Podの再起動なしにデータの更新が可能となります。

では実際にマニフェストを作成し、PodにConfigMapを使って設定ファイルなどを読み込ませていきます。
今回はnginxの設定ファイル、htmlファイルをConfigMapで管理し、nginxのPodにマウントさせます。

apiVersion: v1
kind: ConfigMap
metadata:
  name: configmap-sample
data:
  nginx.config: |
    pid /var/run/nginx.pid;

    events {
        worker_connections 3;
    }

    http {
        server {
            root /usr/share/nginx/html;
        }
    }
  nginx.html: |
    <!DOCTYPE html>
    <html>
      <head>
        <title>Welcome to nginx!</title>
      </head>
      <body>
        <h1>Nginx Home Page for ConfigMap!</h1>
        <p>This page is nginx page for sample of ConfigMap.</p>
        <p>My Profile</p>
        <p><a href="https://github.com/tamago0224">My Github</a>
        <p><a href="https://twitter.com/tamago_0224">My Twitter</a>
      </body>
    </html>
---
apiVersion: v1
kind: Pod
metadata:
  name: configmap-sample-pod
  labels:
    app: configmap-sample-pod
spec:
  containers:
    - name: nginx-pod
      image: nginx:1.23
      volumeMounts:
        - name: nginx-config
          mountPath: "/etc/nginx"
          readOnly: true
        - name: nginx-data
          mountPath: "/usr/share/nginx/html"
          readOnly: true
  volumes:
    - name: nginx-config
      configMap:
        name: configmap-sample
        items:
          - key: "nginx.config"
            path: "nginx.conf"
    - name: nginx-data
      configMap:
        name: configmap-sample
        items:
          - key: "nginx.html"
            path: "index.html"
---
apiVersion: v1
kind: Service
metadata:
  name: configmap-service-nginx
spec:
  selector:
    app: configmap-sample-pod
  ports:
    - protocol: TCP
      port: 8080
      targetPort: 80

上記マニフェストには3つのyamlドキュメントが含まれています。

1つ目はConfigMapのドキュメントで、ここではnginxが読み込む設定を定義しています。
2つ目はPodのドキュメントで、ConfigMapで定義した設定をPodに読み込ませるためのnginxのPodの定義を記載しています。
3つ目はServiceのドキュメントで、こちらは2つ目作成したPodをデバック用のコンテナからcurlでnginxの応答を確認するために、Serviceオブジェクトを使ってPod外からアクセスするためのものです。

今回の目的としてはConfigMapを使ってPodとどう連携させるのかが中心となるので、1つ目、2つ目のドキュメントについて確認していきます。

まずはConfigMapの設定項目について

項目 説明
apiVersion オブジェクトが定義されているバージョン
kind オブジェクトを表す文字列
metadata オブジェクトのメタデータ
metadata.name ネームスペース内で自身を表す一意な文字列。Podのvolumesセクションで指定する際に使われる
data データをkey-valueで指定するセクション。valueにnon-UTF8な者がある場合はbinaryDataを使うこと

次にPodの設定項目について。PodはPodでも扱ったため、そこで取り扱わなかった部分について記載する

項目 説明
spec.containers.volumeMounts コンテナへマウントするための設定を記載する項目
spec.containers.volumeMounts.name 一致するボリュームの名前
spec.containers.volumeMounts.mountPath ボリュームをマウントするコンテナ内のパス
spec.containers.volumeMounts.readOnly マウントしたボリュームがread-onlyかどうか
spec.volumes Podからアクセス可能な名前付きのボリュームを定義する項目
spec.volumes.name Pod内で一意なDNS_LABELの形式を持った名前
spec.volumes.configMap コンテナに展開するボリュームタイプ。今回はConfigMap
spec.volumes.configMap.name Podで参照するための名前
spec.volumes.configMap.items ConfigMapで定義されているファイルを個別に追加するための項目
spec.volumes.configMap.items[].key ConfigMapで定義したkey
spec.volumes.configMap.items[].path keyのvalueの内容を展開するパス先

Secret

Secretは少量の機密情報を含んだオブジェクトです。
Secretを用いることで、アプリケーションコードに機密情報を含める必要がなくなります。

Secretの使い方はConfigMapとほぼ同じで、Secretのオブジェクトをマニフェストなどで定義し、PodからコンテナにSecretで定義した情報をマウントします。

ConfigMapと異なるところは主に2点ほどあると思います。

  1. typeを指定することで、Secretオブジェクトのシナリオを想定
  2. dataで指定するkey-valueのvalueはbase64でエンコードされたもの

dataについてはbase64でエンコードできない場合はstringDataを代わりに使うなどすることができます。

実際のマニフェストを用意してデプロイしてみます。
上の説明でもあった1. のtypeについては一般的なシナリオ、デフォルトでもあるOpaqueを使います。
また、base64エンコードして記載しているのでわかりにくいですが、今回利用する値はConfigMapで指定したものと同じものになります。

apiVersion: v1
kind: Secret
metadata:
  name: secret-sample
data:
  nginx.config: cGlkIC92YXIvcnVuL25naW54LnBpZDsKCmV2ZW50cyB7CiAgICB3b3JrZXJfY29ubmVjdGlvbnMgMzsKfQoKaHR0cCB7CiAgICBzZXJ2ZXIgewogICAgICAgIHJvb3QgL3Vzci9zaGFyZS9uZ2lueC9odG1sOwogICAgfQp9Cg==
  nginx.html: PCFET0NUWVBFIGh0bWw+CjxodG1sPgogICAgPGhlYWQ+CiAgICAgICAgPHRpdGxlPldlbGNvbWUgdG8gbmdpbnghPC90aXRsZT4KICAgIDwvaGVhZD4KICAgIDxib2R5PgogICAgICAgIDxoMT5OZ2lueCBIb21lIFBhZ2UgZm9yIENvbmZpZ01hcCE8L2gxPgogICAgICAgIDxwPlRoaXMgcGFnZSBpcyBuZ2lueCBwYWdlIGZvciBzYW1wbGUgb2YgQ29uZmlnTWFwLjwvcD4KICAgICAgICA8cD5NeSBQcm9maWxlPC9wPgogICAgICAgIDxwPjxhIGhyZWY9Imh0dHBzOi8vZ2l0aHViLmNvbS90YW1hZ28wMjI0Ij5NeSBHaXRodWI8L2E+PC9wPgogICAgICAgIDxwPjxhIGhyZWY9Imh0dHBzOi8vdHdpdHRlci5jb20vdGFtYWdvXzAyMjQiPk15IFR3aXR0ZXI8L2E+PC9wPgogICAgPC9ib2R5Pgo8L2h0bWw+Cg==
---
apiVersion: v1
kind: Pod
metadata:
  name: secret-sample-pod
  labels:
    app: secret-sample-pod
spec:
  containers:
    - name: nginx-pod
      image: nginx:1.23
      volumeMounts:
        - name: nginx-config
          mountPath: "/etc/nginx"
          readOnly: true
        - name: nginx-data
          mountPath: "/usr/share/nginx/html"
          readOnly: true
  volumes:
    - name: nginx-config
      secret:
        secretName: secret-sample
        items:
          - key: nginx.config
            path: nginx.conf
    - name: nginx-data
      secret:
        secretName: secret-sample
        items:
          - key: nginx.html
            path: index.html
---
apiVersion: v1
kind: Service
metadata:
  name: secret-service-nginx
spec:
  selector:
    app: secret-sample-pod
  ports:
    - protocol: TCP
      port: 8080
      targetPort: 80

ConfigMapとほぼほぼ同じなので、異なる項目のみ抽出して表にまとめます。

項目 説明
spec.volumes[].secret コンテナに展開するボリュームタイプ。今回はSecret
spec.volumes[].secret.secretName Podにマウントさせたい同じnamespace内に存在するSecretの名前

そのほかはConfigMapで説明した内容と同じです。

参考資料

GitHubで編集を提案

Discussion