コンテンツにスキップ

Kubernetesリソース@Kubernetes

はじめに

本サイトにつきまして、以下をご認識のほど宜しくお願いいたします。


01. Kubernetesリソースとオブジェクト

Kubernetesリソース

Kubernetes上でアプリケーションを稼働させる概念のこと。


Kubernetesオブジェクト

マニフェストによって量産されたKubernetesリソースのインスタンスのこと。


スコープ

所属するNamespace内のみにリクエストを送信できるNamespacedスコープなKubernetesリソースと、Cluster全体にリクエストを送信できるClusterスコープなKubernetesリソースがある。

namespaced-scope_vs_cluster-scoped


02. Workload系リソース

Workload系リソースとは

コンテナの実行に関する機能を提供する。


DaemonSet

▼ DaemonSetとは

Node上のPodの個数を維持管理する。

Podの負荷に合わせてPodの自動水平スケーリングを実行しない (HorizontalPodAutoscalerが必要である) 。

ただしReplicaSetとは異なり、Node内でPodを1つだけ維持管理する。

Nodeで1つだけ稼働させる必要のあるプロセス (例:kube-proxy、CNI、FluentBit、datadogエージェント、cAdvisorエージェント、Prometheusの一部のExporter、など) のために使用される。

こういったプロセスが稼働するコンテナは、Node内の全てのコンテナからデータを収集し、可観測性のためのデータセットを整備する。

▼ Pod数の固定

DaemonSetは、Node内でPodを1つだけ維持管理する。

そのため、例えばClusterネットワーク内に複数のNodeが存在していて、いずれかのNodeが停止したとしても、稼働中のNode内のPodを増やすことはない。

▼ DaemonSet配下のPodへの通信

  • NodePort Service
  • ClusterIP Service
  • PodでのhostPort
  • など...


Deployment

▼ Deploymentとは

ReplicaSetを操作し、Clusterネットワーク内のPodのレプリカ数を維持管理する。

Podの負荷に合わせてPodの自動水平スケーリングを実行しない (HorizontalPodAutoscalerが必要である) 。

ただしStatefulSetとは異なり、ストレートレス (例:アプリコンテナ) なコンテナを含むPodを冗長化することに適する。

▼ ReplicaSetの置き換えが起こる条件

Deploymentでは、以下の設定値の変更で、ReplicaSetの置き換えが起こる。

条件 説明
.spec.replicasキーの変更 レプリカ数 (.spec.replicasキー) の変更の場合は、Deploymentは既存のReplicaSetをそのままにし、Podのレプリカ数のみを変更する。
.spec.templateキー配下の任意の変更 PodTemplate (.spec.templateキー) を変更した場合、Deploymentは新しいReplicaSetを作成し、これを古いReplicaSetと置き換える。

kubernetes_deployment_replace_replicaset

▼ Podのレプリカ数の維持

Deploymentは、Cluster内のPodのレプリカ数を指定された数だけ維持する。

そのため、例えばCluster内に複数のNodeが存在していて、いずれかのNodeが停止した場合、稼働中のNode内でレプリカ数を維持するようにPod数を増やす。


Job

▼ Jobとは

単発的なバッチ処理を定義したい場合、Jobを使用する。

もう一度実行したい場合は、Jobを削除する必要がある。

複数のPodを作成 (SuccessfulCreate) し、指定された数のPodを正常に削除 (SuccessfulDelete) する。

デフォルトでは、ログの確認のためにPodは削除されず、Jobが削除されて初めてPodも削除される。

.spec.ttlSecondsAfterFinishedキーを使用すると、Podのみを自動削除できるようになる。

定期的に実行する場合、CronJobのテンプレートとして定義する。

▼ DBマイグレーション

Jobを使用して、DBにマイグレーションを実行する。

GitOpsツール (例:ArgoCDなど) によっては、アノテーションを使用してApply前にJobをフックさせられる。

apiVersion: batch/v1
kind: Job
metadata:
  namespace: foo
  name: foo-migration-job
spec:
  backoffLimit: 0
  template:
    spec:
      containers:
        - name: foo-app
          image: foo-app:1.0.0
          command: ["<マイグレーションを実行するためのコマンド>"]
          envFrom:
            - secretRef:
                # DBの接続情報 (ホスト、ユーザー名、パスワード) はSecretに設定しておく。
                name: foo-secret
      restartPolicy: Never


CronJob

▼ CronJobとは

定期的なバッチ処理を定義したい場合、CronJobを使用する。

CronJob配下のJobは、決まった時間にならないと実行されない。

任意の時間に実行するためには、CronJobを指定し、これの配下で一時的にJobを作成する。

$ kubectl create job test-job --from=cronjob/foo-cron-job -n foo

ただし、動作確認後はCronJobにJobを作らせたいので、そのJobは削除する。

$ kubectl delete job test-job -n foo


Node

▼ Nodeとは

Kubernetesリソースを配置するサーバーのこと。

▼ ライフサイクルフェーズ

フェーズ名 説明
Ready NodeがPodをスケジューリング可能な状態であることを表す。
NotReady NodeがPodをスケジューリング不可能な状態であることを表す。


Pod

▼ Podとは

コンテナの最小グループ単位のこと。

Podを単位として、コンテナ起動/停止や水平スケールアウト/スケールインを実行する。

*例*

PHP-FPMコンテナとNginxコンテナを稼働させる場合、これら同じPod内に配置する。

kubernetes_pod_php-fpm_nginx

▼ 例外的なコントロールプレーンNode上のPod

脆弱性の観点で、デフォルトではコントロールプレーンNodeにPodはスケジューリングされない。

これは、コントロールプレーンNodeにはTaint (node-role.kubernetes.io/master:NoSchedule) が設定されているためである。

一方で、Nodeにはこれがないため、Podをスケジューリングさせられる。

# コントロールプレーンNodeの場合
$ kubectl describe node <コントロールプレーンNode名> | grep -i taint

Taints: node-role.kubernetes.io/master:NoSchedule # スケジューリングさせないTaint

# ワーカーNodeの場合
$ kubectl describe node <ワーカーNode名> | grep -i taint

Taints: <none>

ただし、セルフマネージドなコントロールプレーンNodeを採用している場合に、全てのコントロールプレーンNodeでTaintを解除すれば、Podを起動させられる。

コントロールプレーンNodeがマネージドではない環境 (オンプレミス環境、ベアメタル環境、など) では、コントロールプレーンNodeにDaemonSetによるPodをスケジューリングさせることがある。

$ kubectl taint node --all node-role.kubernetes.io/master:NoSchedule-

▼ Podのライフサイクルフェーズ

Podは、マニフェストの.status.phaseキーにライフサイクルのフェーズを持つ。

status:
  phase: Running
フェーズ名 説明 補足
Completed Pod内の全てのコンテナが正常に終了した。 Job配下のPodでよく見られるフェーズである。
ContainerCreating Pod内にInitContainerがない場合の理由である。コンテナイメージをプルし、コンテナを作成している。
CrashLoopBackOff Podが、一連のフェーズ (Runningフェーズ、Waitingフェーズ、Failedフェーズ) を繰り返している。
CreateContainerError Pod内のコンテナの作成に失敗した。
ErrImagePull Pod内のコンテナイメージのプルに失敗した。
Error Pod内のいずれかのコンテナが異常に終了した。 Job配下のPodの場合はErrorになっても、次のPodが作成される。Jobの.spec.ttlSecondsAfterFinishedキーを設定していなければ、ErrorのPodがしばらく残り続けるが、もし新しいPodがCompletedになれば問題ない。
Failed Pod内の全てのコンテナの起動が完了し、その後に異常に停止した。
ImagePullBackOff Pod内のコンテナイメージのプルに失敗した。
OOMKilled Podのメモリの空きサイズが足らず、コンテナが強制的に終了された。
Pending PodがNodeにスケジューリングされたが、Pod内の全てのコンテナの起動がまだ完了していない。
PodInitializing Pod内にInitContainerがある場合の理由である。コンテナイメージをプルし、コンテナを作成している。
PostStartHookError PodのPostStartフックに失敗した。
Running Pod内の全てのコンテナの起動が完了し、実行中である。 コンテナの起動が完了すればRunningフェーズになるが、コンテナ内でビルトインサーバーを起動するようなアプリケーション (例:フレームワークのビルトインサーバー機能) の場合は、RunningフェーズであってもReadyコンディションではないことに注意する。
Succeed Pod内の全てのコンテナの起動が完了し、その後に正常に停止した。
Unknown NodeとPodの間の通信に異常があり、NodeがPodから情報を取得できなかった。

▼ Podのコンディション

Podのライフサイクルのフェーズは、.status.conditionsキーにフェーズの詳細を持つ。

status:
  phase: Running
  conditions:
    - lastProbeTime: null
      lastTransitionTime: "2022-12-01T18:00:06Z"
      status: "True"
      type: Initialized
    - lastProbeTime: null
      lastTransitionTime: "2022-12-01T18:00:49Z"
      status: "True"
      type: Ready
    - lastProbeTime: null
      lastTransitionTime: "2022-12-01T18:00:49Z"
      status: "True"
      type: ContainersReady
    - lastProbeTime: null
      lastTransitionTime: "2022-12-01T18:00:02Z"
      status: "True"
      type: PodScheduled

例えばRunningフェーズであっても、Readyコンディションになっていない可能性がある。

そのため、Podが正常であると見なすためには、『Runningフェーズ』かつ『Readyコンディション』である必要がある。

各フェーズのコンディション名 説明
PodScheduled NodeへのPodのスケジューリングが完了した。
ContainersReady 全てのコンテナの起動が完了し、加えてコンテナ内のアプリケーションやミドルウェアの準備が完了している。
Initialized 全てのinitコンテナの起動が完了した。
Ready Pod全体の準備が完了した。

▼ Podの最後のフェーズの理由

Podは、.status.reasonキーに、最後のフェーズの理由を値として持つ。

status:
  phase: Failed
  reason: Evicted
理由 説明
Completed コンテナが正常に終了した。InitContainerの実行後に見られる。
Evicted Nodeのハードウェアリソース不足のため、Podが退避対象となった。Evictedが理由の場合、Failedフェーズが最後となる。
Unknown 原因が不明である。

▼ CrashLoopBackOffのデバッグ

PodがCrashLoopBackOffになっている場合、以下を確認すると良い。

  • kubectl logsコマンドで、該当のコンテナのエラーログを確認する。
  • kubectl describe nodesコマンドで、PodをスケジューリングさせているNodeを指定し、該当のPodがCPUとメモリの要求量に異常がないかを確認する。
  • kubectl describe podsコマンドで、該当のPodがCrashLoopBackOffになる原因を確認する。ContainersのLastStateの項目で、メッセージを確認できる。これは、kubectl logsコマンドと同じ内容である。

▼ Podを安全に削除する方法

Podの終了プロセスが始まると、以下の一連のプロセスも開始する。

  • Workload (例:Deployment、DaemonSet、StatefulSet、Job、など) が古いPodを切り離す。
  • Serviceとkube-proxyが古いPodの宛先情報を削除する。
  • コンテナを停止する。

これらのプロセスはそれぞれ独立して実施され、ユーザーは制御できない。

例えば、Serviceとkube-proxyがPodの宛先情報を削除する前にPodが削除してしまうと、ServiceからPodへのコネクションを途中で切断することになってしまう。

また、コンテナを停止する前にPodを終了してしまうと、コンテナを強制的に終了することになり、ログにエラーが出力されてしまう。

そのため、Serviceとkube-proxyの処理後にPodを終了できるように、ユーザーがPodの.spec.containers[*].lifecycle.preStopキーに任意の秒数を設定し、コンテナに待機処理 (例:sleepコマンド) を実行させる必要がある。

また、コンテナの正常な終了後にPodを終了できるように、.spec.terminationGracePeriodSecondsキーに任意の秒数を設定し、Podの終了に伴う一連のプロセスの完了を待機する必要がある。

これらの適切な秒数は、ユーザーがそのシステムに応じて調節するしかない。

.spec.terminationGracePeriodSecondsキーを長めに設定し、.spec.containers[*].lifecycle.preStopキーの秒数も含めて、全てが完了した上でPodを終了可能にする。

pod_terminating_process

(1)

クライアントは、kubectlコマンドがを使用して、Podを終了するリクエストをkube-apiserverに送信する。

(2)

PodのマニフェストにdeletionTimestampキーが追加され、PodがTerminatingフェーズとなり、削除プロセスを開始する。

(3)

Podの.spec.terminationGracePeriodSecondsキーに応じて、Podの終了プロセス完了の待機時間を開始する。

(4)

最初にpreStopフックが起動し、.spec.containers[*].lifecycle.preStopキーで設定した待機処理をコンテナが実行する。

(5)

DeploymentがPodを切り離す。また、Serviceとkube-proxyがPodの宛先情報を削除する。

(6)

.spec.containers[*].lifecycle.preStopキーによるコンテナの待機処理が終了する。

(7)

待機処理が終了したため、kubeletは、コンテナランタイムを介して、Pod内のコンテナにSIGTERMシグナルを送信する。

これにより、コンテナの停止処理が開始する。

(8)

.spec.terminationGracePeriodSecondsキーによるPodの終了プロセス完了の待機時間が終了する。

この段階でもコンテナが停止していない場合は、コンテナにSIGKILLシグナルが送信され、コンテナを強制的に終了することになる。

(9)

Podが削除される。この段階でDeploymentや、Serviceとkube-proxyの処理が完了していない場合は、コネクションを途中で強制的に切断することになる。

▼ ハードウェアリソースの割り当て

そのPodに割り当てられたハードウェアリソース (CPU、メモリ) を、Pod内のコンテナが分け合って使用する。

単位
m:millicores 1コア = 1000ユニット = 1000m
Mi:mebibyte 1Mi = 1.04858MB

▼ クライアントがPod内のログを参照できる仕組み

(1)

クライアント (特にkubectlコマンド実行者) がkubectl logsコマンドを実行する。

(2)

kube-apiserverが、/logs/pods/<ログへのパス>エンドポイントにリクエストを送信する。

(3)

kubeletはリクエストを受信し、Nodeの/var/logディレクトリを読み込む。Nodeの/var/log/pods/<Namespace名>_<Pod名>_<UID>/container/<数字>.logファイルは、Pod内のコンテナの/var/lib/docker/container/<ID>/<ID>-json.logファイルへのシンボリックリンクになっているため、kubeletを介して、コンテナのログを確認できる。補足として、削除されたPodのログは、引き続き/var/log/podsディレクトリ配下に保管されている。

kubernetes_pod_logging

補足として、DaemonSetとして稼働するFluentdは、Nodeの/var/logディレクトリを読み込むことにより、Pod内のコンテナのログを収集する。

▼ 待ち受けるポート番号の確認

Pod内のコンテナ内でnetstatコマンドを実行することにより、コンテナが待ち受けるポート番号を確認できる。

$ kubectl exec foo-istiod -n istio-system -- netstat -tulpn

Active Internet connections (only servers)

Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
tcp        0      0 127.0.0.1:9876          0.0.0.0:*               LISTEN      1/pilot-discovery
tcp6       0      0 :::15017                :::*                    LISTEN      1/pilot-discovery
tcp6       0      0 :::8080                 :::*                    LISTEN      1/pilot-discovery
tcp6       0      0 :::15010                :::*                    LISTEN      1/pilot-discovery
tcp6       0      0 :::15012                :::*                    LISTEN      1/pilot-discovery
tcp6       0      0 :::15014                :::*                    LISTEN      1/pilot-discovery

▼ バルーンPod (OverProvisioning Pod)

『OverProvisioning Pod』ともいう。

NodeにバルーンPodをスケジューリングさせ、Nodeに常に余剰なリソース (例:CPU/メモリの容量) を確保できる。

バルーンPodの優先度は最低にしておく。

バルーンPodは優先度が低いため、他のPodをNodeに優先してスケジューリングできる。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: foo-balloon
spec:
  # ゾーンが3つあるため、ゾーン間で移動するようにレプリカ数を3つにする
  replicas: 3
  selector:
    matchLabels:
      app: balloon
  template:
    metadata:
      labels:
        app: balloon
    spec:
      containers:
        - args:
            - infinity
          command:
            - sleep
          image: ubuntu
          name: ubuntu
          resources:
            requests:
              cpu: 1000m
              memory: 2048Mi
      priorityClassName: foo-balloon
      terminationGracePeriodSeconds: 0
      # Podを同じゾーンにスケジューリングさせない
      topologySpreadConstraints:
        - labelSelector:
            matchLabels:
              app: balloon
          maxSkew: 1
          topologyKey: topology.kubernetes.io/zone
          whenUnsatisfiable: DoNotSchedule
apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
  name: foo-balloon
preemptionPolicy: Never
value: -10
description: Priority class for balloon


ReplicaSet

▼ ReplicaSetとは

Node上のPod数を維持管理する。

Podの負荷に合わせてPodの自動水平スケーリングを実行しない (HorizontalPodAutoscalerが必要である) 。

DaemonSetとは異なり、Podを指定した個数に維持管理できる。

ReplicaSetを直接的に操作するのではなく、Deployment使用してこれを行うことが推奨される。

▼ PodTemplate

Podの鋳型として動作する。

ReplicaSetは、PodTemplateを用いてPodのレプリカを作成する。


StatefulSet

▼ StatefulSetとは

ReplicaSetを操作し、Podの個数を維持管理する。

Podの負荷に合わせてPodを自動水平スケーリングを実行しない (HorizontalPodAutoscalerが必要である) 。

Deploymentとは異なり、ストレートフルなコンテナ (例:dbコンテナ) を含むPodを扱える。

Podが削除されてもPersistentVolumeClaimsは削除されないため、新しいPodにも同じPersistentVolumeを継続的にマウントできる。

▼ ライフサイクル

StatefulSetは、DeploymentやReplicaSetとは異なり、同時にPodを作成しない。

作成中のPodがReady状態になってから、次のPodを作成し始める。

そのためDeploymentやReplicaSetと比べて、全てのPodが揃うのに時間がかかる。


DeploymentとStatefulSetとの違い

▼ 設定値

StatefulSetでは、一部の設定変更が禁止されている。

The StatefulSet "foo-pod" is invalid: spec: Forbidden: updates to statefulset spec for fields other than 'replicas', 'template', 'updateStrategy' and 'minReadySeconds' are forbidden

▼ PersistentVolume

Deployment配下のPodは、全てが同じPersistentVolumeClaimを共有する。

そのため、Podに紐づくPersistentVolumeは同じになる。

一方でStatefulSet配下のPodは、別々のPersistentVolumeClaimを使用する。

そのため、Podに紐づくPersistentVolumeは別々になる。

Podが別のNodeに再スケジューリングされても、Podに同じPersistentVolumeをマウントできる。

Podが削除されてもPersistentVolumeClaimsは削除されないため、新しいPodも同じPersistentVolumeをマウントできる。

kubernetes_deployment_persistent-volume


03. ネットワーク系リソース

ネットワーク系リソースとは

Cluster内のネットワークを制御する。


EndpointSlice

▼ EndpointSliceとは

各Service配下に存在する。Serviceでルーティング先のPodの宛先情報を分割して管理し、Podの増減に合わせて、Podの宛先情報を追加/削除する。

kube-proxyによるサービスディスカバリーのために、Podの宛先情報を提供する。

Kubernetesのv1.6より前はEndpointsが使用されていた。

しかし、EndpointsではPodの宛先情報を一括管理しなければならず、これを分割して管理できるように、Endpointsの代わりとしてEndpointSliceが導入された。

kubernetes_endpoint-slices


Gateway

▼ Gatewayとは

Gatewayは、L4/L7プロトコルの通信の受信ルールを定義し、またL4/L7ロードバランサーとして通信をルーティングする。

▼ Ingressとの違い

L7プロトコルの受信ルールしか定義できないIngressとは異なり、L4プロトコルの受信ルールも定義できる。

また、Gateway自体がL4/L7ロードバランサーとしても機能する。


GatewayClass

▼ GatewayClassとは

Gatewayの実体として使用するツールを指定する。


Ingress

▼ Ingressとは

Ingressは、L7プロトコルの通信の受信ルールを定義する。

Ingressを使用する場合、宛先のServiceは、Cluster IP Serviceとする。

NodePort ServiceやLoadBalancer Serviceと同様に、外部からのリクエストを受信する方法の1つである。

kubernetes_ingress

▼ Gatewayとの違い

L7プロトコルの通信のみを処理できる。

また、Ingressそれ自体はルールのみを持ち、Ingressコントローラーがロードバランサーとして機能する。

▼ パスベースルーティング

パスの値に基づいて、Serviceにルーティングする。

kubernetes_ingress_path

▼ ホストベースルーティング

Hostヘッダー値に基づいて、Serviceにルーティングする。

本番環境では、ドメインを指定した各種ダッシュボードにリクエストを送信できる必要がある。

kubernetes_ingress_host


IngressClass

▼ IngressClassとは

Ingressコントローラーの実体として使用するツールを指定する。


Ingressコントローラー

▼ Ingressコントローラー

Ingressコントローラーは、L7ロードバランサーとしてPodに通信をルーティングする。

Node外から通信を受信し、Ingressに定義されたルールに応じて、単一/複数のServiceにルーティングする。

クラウドプロバイダー (例:AWS) では、Ingressコントローラー状況下でIngressを作成すると、Ingressの設定値に応じたL7ロードバランサー (例:AWS ALBとAWSターゲットグループ) を自動的にプロビジョニングする。

ただし、クラウドプロバイダーによっては、IngressコントローラーとClusterIP Serviceを仲介するカスタムリソース (例:AWS TargetGroupBindings、など) を提供している場合がある。

この場合、クラウドプロバイダーのリソースとKubernetesが疎結合になり、責務の境界を明確化できる。


Service

▼ Serviceとは

Serviceは、L4ロードバランサーとしてPodに通信をルーティングする。

kube-proxyが更新したNode上で稼働するiptablesを使用し、また負荷分散方式によるルーティング先Podの決定に基づいて、Podに通信をルーティングする。

DaemonSetやJobで使用する例は少ないが、Podさえあれば全てのWorkload (例:Deployment、DaemonSet、StatefulSet、Job、など) でServiceを使用できる。

マイクロサービスアーキテクチャのコンポーネントである『Service』とは区別する。

kubernetes_kube-proxy_service

▼ ClusterIP Service

kubernetes_clusterip-service

L4ロードバランサーとして、Serviceに対する通信を、Cluster-IPを介してPodにルーティングする。

Cluster-IPはServiceの.spec.clusterIPキーで指定しない限りランダムで決まり、Podの/etc/resolv.confファイルに記載されている。

Pod内に複数のコンテナがある場合、各コンテナに同じ内容の/etc/resolv.confファイルが配置される。

$ kubectl exec -it <Pod名> -c <コンテナ名> -- bash

[root@<Pod名>] $ cat /etc/resolv.conf

nameserver *.*.*.* # ClusterネットワークのIPアドレス
search default.svc.cluster.local svc.cluster.local cluster.local
options ndots:5 # 名前解決時のローカルドメインの優先度

Cluster-IPはNode外から宛先として指定できないため、通信にIngressを必要とする。

パブリックネットワーク
⬇⬆︎︎
# L7ロードバランサー
Ingressコントローラー (例:Nginx Ingressコントローラー、AWS Load Balancerコントローラー、など)
⬇⬆︎︎
# L4ロードバランサー
ClusterIP Service
⬇⬆︎︎
Pod

Ingressが無いとClusterネットワーク内からのみしかアクセスできず、安全である。

一方でもしIngressを使用する場合、LoadBalancer Serviceと同様にして (レイヤーは異なるが) 、PodのIPアドレスを宛先とするL7ロードバランサー (例:AWS ALBとAWSターゲットグループ) を自動的にプロビジョニングする。

そのため、クラウドプロバイダーのリソースとKubernetesリソースが密結合になり、責務の境界が曖昧になってしまう。

▼ NodePort Service

kubernetes_nodeport-service

L4ロードバランサーとして、Serviceに対する通信を、NodeのNICの宛先情報 (IPアドレス、ポート番号) 、Cluster-IP、を介してPodにルーティングする。

NodeのNICの宛先情報は、Node外から宛先IPアドレスとして指定できるため、通信にIngressを必要としない。

パブリックネットワーク
⬇⬆︎︎
# L4ロードバランサー
NodePort Service
⬇⬆︎︎
Pod

パブリックプロバイダーのLB (例:AWS ALB) を別に置いても良い (このLBは、Ingressコントローラー由来ではない) 。

パブリックネットワーク
⬇⬆︎︎
AWS Route53
⬇⬆︎︎
# L7ロードバランサー
AWS ALB
⬇⬆︎︎
# L4ロードバランサー
NodePort Service
⬇⬆︎︎
Pod

ただし、NodePort Serviceは内部的にCluster-IPを使っている。

そのため、Ingressを作成するとNodePort ServiceのCluster-IPを介してPodにルーティングする。

この場合、NodeのIPアドレスとIngressの両方がNodeの通信の入り口となり、入口が無闇に増えるため、やめた方が良い。

パブリックネットワーク
⬇⬆︎︎
# L7ロードバランサー
Ingressコントローラー (例:Nginx Ingressコントローラー、AWS Load Balancerコントローラー)
⬇⬆︎︎
# L4ロードバランサー
ClusterIP Service (実体はNodePort Service)
⬇⬆︎︎
Pod

NodeのNICの宛先情報は、Nodeの作成方法 (例:AWS EC2、Google Cloud GCE、VMWare) に応じて、確認方法が異なる。

Serviceのポート番号と紐づくNodeのNICのポート番号はデフォルトではランダムであるため、NodeのNICのポート番号を固定する必要がある。

1個のNodeのポート番号につき、1個のServiceとしか紐付けられず、Serviceが増えていってしまうため、実際の運用にやや不向きである。

この場合、クラウドプロバイダーのリソースとKubernetesが疎結合になり、責務の境界を明確化できる。

▼ LoadBalancer Service

kubernetes_loadbalancer-service

L4ロードバランサーとして、Serviceに対する通信を、External-IP、NodeのNICの宛先情報 (IPアドレス、ポート番号)、Cluster-IPを介してPodにルーティングする。

External-IPはNode外から宛先IPアドレスとして指定できる。

そのため、通信にIngressを必要としないが、外部のロードバランサーのみが宛先IPアドレスを指定できる。

パブリックネットワーク
⬇⬆︎︎
AWS Route53
⬇⬆︎︎
# L4ロードバランサー
LoadBalancer ServiceによるAWS NLB
⬇⬆︎︎
Pod

クラウドプロバイダー (例:AWS) では、LoadBalancer Serviceを作成すると、External-IPを宛先とするL4ロードバランサー (例:AWS NLBとAWSターゲットグループ) を自動的にプロビジョニングする。

クラウドプロバイダーのリソースとKubernetesリソースが密結合になり、責務の境界が曖昧になってしまう。

なお、注意点として、IngressコントローラーはL7ロードバランサーを自動的にプロビジョニングする。

▼ ExternalName Service

Cluster内DNS名とCluster外CNAMEレコードを対応づけ、Serviceに対する通信を対象にルーティングする。

CoreDNSの代わりとして使用できる。

例えば、foo-db-serviceというExternalName Serviceを作成したとする。

ここ場合、foo-db-service.default.svc.cluster.localを指定すると、指定したCNAMEレコードに問い合わせるようになる。

kubernetes_externalname-service

▼ Headless Service

Serviceに対する通信を、そのままPodにルーティングする。

StatefulSet配下のPodにルーティングする場合に特に役立つ。

Podが複数ある場合は、ラウンドロビン方式でIPアドレスが返却されるため、負荷の高いPodにルーティングされる可能性があり、負荷分散には向いていない。

$ dig <Serviceの完全修飾ドメイン名>

;; QUESTION SECTION:
;<Serviceの完全修飾ドメイン名>. IN   A

;; ANSWER SECTION:
<Serviceの完全修飾ドメイン名>. 30 IN A       10.8.0.30
<Serviceの完全修飾ドメイン名>. 30 IN A       10.8.1.34
<Serviceの完全修飾ドメイン名>. 30 IN A       10.8.2.55

また、Headless ServiceからStatefulSetにルーティングする場合は、唯一、Podで直接的に名前解決できるようになる。

$ dig <Pod名>.<Serviceの完全修飾ドメイン名>

;; QUESTION SECTION:
;<Pod名>.<Serviceの完全修飾ドメイン名>. IN A

;; ANSWER SECTION:
<Pod名>.<Serviceの完全修飾ドメイン名>. 30 IN A 10.8.0.30


03-04. Serviceの仕組み

パケットの処理方法

kube-proxy_iptables

Serviceは、パケットのL4に関するヘッダーの持つ情報を見て、PodにL4ロードバランシングする。

受信したリクエストをパケットとして処理していく流れを見ていく。

(1)

ここでは、ClusterIP Serviceを例に挙げる。

10.0.0.10というIPアドレスを持つClusterIP Serviceがいるとする。

$ kubectl get svc kube-dns -n kube-system

NAME       TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)         AGE
kube-dns   ClusterIP   10.0.0.10    <none>        53/UDP,53/TCP   12d
(2)

kube-proxyでiptablesを確認すると、受信したリクエストをパケットとして処理していく流れを確認できる。

KUBE-SERVICESターゲット配下にはKUBE-SVCターゲットがいる。

KUBE-SVCターゲットは、ClusterIP Serviceである。

$ kubectl exec -it kube-proxy-wf7qw -n kube-system -- iptables -nL -t nat --line-numbers

Chain KUBE-SERVICES (2 references)
num  target                     prot opt source               destination

...

5    KUBE-MARK-MASQ             udp  --  !172.16.10.0/24      10.0.0.10            /* kube-system/kube-dns:dns cluster IP */ udp dpt:53
# Serviceにルーティングするための設定
6    KUBE-SVC-TCOU7JCQXEZGVUNU  udp  --  0.0.0.0/0            10.0.0.10            /* kube-system/kube-dns:dns cluster IP */ udp dpt:53

...
(2)

KUBE-SVCターゲット配下にはKUBE-SEPターゲットがいる。

statistic mode random probabilityに応じて、パケットをKUBE-SEPのターゲットいずれかに振り分ける。

# KUBE-SVC
Chain KUBE-SVC-TCOU7JCQXEZGVUNU (1 references)

num  target                     prot opt source               destination
1    KUBE-SEP-K7EZDDI5TWNJA7RX  all  --  0.0.0.0/0            0.0.0.0/0            /* kube-system/kube-dns:dns */ statistic mode random probability 0.50000000000
2    KUBE-SEP-JTVLMQFBDVPXUWUS  all  --  0.0.0.0/0            0.0.0.0/0            /* kube-system/kube-dns:dns */

(3) KUBE-SEPのターゲットに応じて、異なるDNATターゲットを持つ。

 `DNAT`ターゲットは、Podである。

 kube-proxyはDNAT処理を実行し、パケットの宛先IPアドレス (ServiceのIPアドレス) をPodのIPアドレスに変換する。

 ここでは、パケットの宛先IPアドレスを`172.16.10.9`と`172.16.10.42`に変換する。
Chain KUBE-SEP-K7EZDDI5TWNJA7RX (1 references)

num  target          prot  opt  source           destination
1    KUBE-MARK-MASQ  all   --   172.16.10.42     0.0.0.0/0            /* kube-system/kube-dns:dns */
2    DNAT            udp   --   0.0.0.0/0        0.0.0.0/0            /* kube-system/kube-dns:dns */ udp to:172.16.10.42:53

Chain KUBE-SEP-JTVLMQFBDVPXUWUS (1 references)
num  target          prot  opt  source           destination
1    KUBE-MARK-MASQ  all   --   172.16.10.9      0.0.0.0/0            /* kube-system/kube-dns:dns */
2    DNAT            udp   --    0.0.0.0/0       0.0.0.0/0            /* kube-system/kube-dns:dns */ udp to:172.16.10.9:53

(4) 宛先のPodのIPアドレスを確認すると、DNAT処理の変換後のIPアドレスと一致している。

$ kubectl get po -n kube-system -o wide -l k8s-app=kube-dns

NAME                     READY   STATUS    RESTARTS   AGE    IP             NODE                                NOMINATED NODE   READINESS GATES
coredns-69c47794-6xnlq   1/1     Running   0          18h    172.16.10.9    aks-nodepool1-19344272-vmss000000   <none>           <none>
coredns-69c47794-cgn9k   1/1     Running   0          7d9h   172.16.10.42   aks-nodepool1-19344272-vmss000001   <none>           <none>


04. Clusterリソース

Clusterリソースとは

Cluster全体に渡る機能を提供する。


Namespace

▼ Namespaceとは

各Kubernetesリソースの影響範囲を制御するための領域のこと。

Namespaceが異なれば、.metadata.labelsキーに同じ値 (例:同じ名前、など) を設定できる。

▼ 初期Namespace

名前 説明
default 任意のKubernetesリソースを配置する。
kube-node-lease Kubernetesリソースのうちで、特にLeaseを配置する。
kube-public 全てのクライアント (kubectlクライアント、Kubernetesリソース) に公開しても良いKubernetesリソースを配置する。
kube-system Kubernetesが自動的に作成したKubernetesリソースを配置する。ユーザーが設定する必要はない。

▼ NamespaceがTerminatingのままになる

以下の方法で対処する。


05. 設定系リソース

設定系リソースとは

コンテナで使用する変数、ファイル、ボリュームに関する機能を提供する。


ConfigMap

▼ ConfigMapとは

コンテナで使用する機密ではない変数やファイルをマップ型で保持できる。

改行することにより、設定ファイルも値に格納できる。

▼ 機密ではない変数の例

変数 何のために使用するのか
DBホスト名 コンテナがDBに接続する時に、DBのホスト名として使用する。
DBポート番号 コンテナがDBに接続する時に、DBのポート番号として使用する。
DB接続タイムアウト コンテナがDBに接続する時に、タイムアウト時間として使用する。
DB接続再試行数 コンテナがDBに接続する時に、再試行の回数として使用する。
タイムゾーン コンテナ内のタイムゾーンとして使用する。
... ...


Secret

▼ Secretとは

コンテナで使用する機密な変数やファイルをキーバリュー型で永続化する。

永続化されている間はbase64方式でエンコードされており、デコードした上で、変数やファイルとして対象のPodに出力する。

▼ 機密ではない変数の例

変数 何のために使用するのか
DBユーザー名 コンテナがDBに接続する時に、DBユーザーのユーザー名として使用する。
DBパスワード コンテナがDBに接続する時に、DBユーザーのパスワードとして使用する。
... ...

▼ コンテナイメージプルのパラメーターとして

Podの起動時に、kubectlコマンドが実行され、コンテナイメージをプルする。

Secretに永続化された値を復号化し、kubectlコマンドにパラメーターとして出力できる。

▼ コンテナの環境変数として

永続化された値を復号化し、Pod内のコンテナに環境変数として出力できる。


06. ストレージ系リソース

ストレージ系リソースの種類

Kubernetesで作成できるストレージは、作成場所で種類を分けられる。

kubernetes_storage_resource_types

ストレージの種類 Volume PersistentVolume
Pod内ストレージ EmptyDir なし
Node内ストレージ HostPath HostPath、Local
Node外ストレージ 外部ストレージ 外部ストレージ


PersistentVolume

▼ PersistentVolumeとは

storage_class

Node上のストレージ上にVolumeを作成する。

Node上のPod間でVolumeを共有でき、同一Pod内のコンテナ間でもVolumeを共有できる。

PodがPersistentVolumeを使用するためには、PersistentVolumeClaimにPersistentVolumeを要求させておき、PodでこのPersistentVolumeClaimを指定する必要がある。

アプリケーションのディレクトリ名を変更した場合は、PersistentVolumeを再作成しないと、アプリケーション内のディレクトリの読み出しでパスを解決できない場合がある。

DockerのVolumeとは独立した機能であることに注意する。

▼ PersistentVolumeの使用率の確認方法 (CrashLoopBackOffでない場合)

Pod内でdfコマンドを実行することにより、PersistentVolumeの使用率を確認できる。

出力結果で、ファイルシステム全体の使用率を確認する。

$ kubectl exec -n prometheus foo-pod -- df -hT

ただし、CrashLoopBackOffなどが理由で、コンテナがそもそも起動しない場合、この方法で確認できない。

また、Grafanaのkubernetes-mixinsには、起動中のPodのPersistentVolumeの使用率を可視化できるダッシュボードがある。

▼ PersistentVolumeの使用率の確認方法 (CrashLoopBackOffの場合)

ここでは、Prometheusを例に挙げる。

(1)

PrometheusのPodに紐づくPersistentVolumeは、最大200Giを要求していることがわかる。

$ kubectl get pvc foo-prometheus-pvc -n prometheus
NAME                 STATUS   VOLUME      CAPACITY   ACCESS MODES   STORAGECLASS    AGE
foo-prometheus-pvc   Bound    pvc-*****   200Gi      RWO            gp3-encrypted   181d
(2)

Node内 (AWS EKSのEC2ワーカーNodeの場合) で、Podに紐づくPersistentVolumeがマウントされているディレクトリを確認する。

$ ls -la /var/lib/kubelet/plugins/kubernetes.io/aws-ebs/mounts/aws/<リージョン>/vol-*****/prometheus-db/

-rw-r--r--  1 ec2-user 2000         0 Jun 24 17:07 00004931
-rw-r--r--  1 ec2-user 2000         0 Jun 24 17:09 00004932
-rw-r--r--  1 ec2-user 2000         0 Jun 24 17:12 00004933

...

drwxrwsr-x  2 ec2-user 2000      4096 Jun 20 18:00 checkpoint.00002873.tmp
drwxrwsr-x  2 ec2-user 2000      4096 Jun 21 02:00 checkpoint.00002898
drwxrwsr-x  2 ec2-user 2000      4096 Jun 21 04:00 checkpoint.00002911.tmp
(3)

dfコマンドで、ストレージの使用率を確認する。Nodeにマウントされているデータサイズを確認すると、197Gとなっている。 PersistentVolumeに対してデータサイズが大きすぎることがわかる。

$ df -h /var/lib/kubelet/plugins/kubernetes.io/aws-ebs/mounts/aws/ap-northeast-1a/vol-*****/prometheus-db/

Filesystem      Size  Used Avail Use% Mounted on
/dev/nvme8n1    197G  197G     0 100% /var/lib/kubelet/plugins/kubernetes.io/aws-ebs/mounts/aws/ap-northeast-1a/vol-*****

▼ HostPath (本番環境で非推奨)

Nodeのストレージ上にVolumeを作成し、これをコンテナにバインドマウントする。

機能としては、Volumeの一種であるHostPathと同じである。

マルチNodeには対応していないため、本番環境では非推奨である。

▼ Local (本番環境で推奨)

Node上にVolumeを作成し、これをコンテナにバインドマウントする。

マルチNodeに対応している (明言されているわけではく、HostPathとの明確な違いがよくわからない) 。

▼ 外部サービスのVolume

外部サービス (例:AWS EBS、NFS、など) が提供するVolumeをコンテナにマウントする。

StorageClassとPersistentVolumeClaimを介して、PersistentVolumeと外部サービスを紐付け、Volumeとしてコンテナにマウントする。

また、外部ストレージを使用する場合には、CSIドライバーも必要である。

storage_class


Volume

▼ Volumeとは

storage_class

既存 (例:NFS、iSCSI、Ceph、など) のボリュームをそのままKubernetesのVolumeとして使用する。

Podの.spec.volumesキーで指定する。

# Podに接続する
$ kubectl exec -it <Pod名> -c <コンテナ名> -- bash

# ストレージを表示する
[root@<Pod名>:/var/www/html] $ df -h

Filesystem      Size  Used Avail Use% Mounted on
overlay          59G   36G   20G  65% /
tmpfs            64M     0   64M   0% /dev
tmpfs           3.9G     0  3.9G   0% /sys/fs/cgroup
/dev/vda1        59G   36G   20G  65% /etc/hosts
shm              64M     0   64M   0% /dev/shm
overlay          59G   36G   20G  65% /var/www/foo # 作成したボリューム
tmpfs           7.8G   12K  7.8G   1% /run/secrets/kubernetes.io/serviceaccount
tmpfs           3.9G     0  3.9G   0% /proc/acpi
tmpfs           3.9G     0  3.9G   0% /sys/firmware

Podが持つVolumeの一覧は、kubectl describeコマンドで確認できる。

$ kubectl describe pod

...

Volumes:
  foo-volume:
    Type:       EmptyDir (a temporary directory that shares a pod's lifetime)
    Medium:
    SizeLimit:  <unset>
  bar-volume:
    Type:       EmptyDir (a temporary directory that shares a pod's lifetime)
    Medium:
    SizeLimit:  <unset>
  baz-volume:
    Type:      ConfigMap (a volume populated by a ConfigMap)
    Name:      baz-cm
    Optional:  false

▼ DockerのVolumeとの違い

Dockerのボリュームとは独立した機能であることに注意する。

▼ HostPath (本番環境で非推奨)

Node上の既存のストレージ上にVolumeを作成し、コンテナにバインドマウントする。

バインドマウントはNodeとPod内のコンテナ間で実行され、同一Node上のPod間でこのVolumeを共有でき、同一Pod内のコンテナ間でもVolumeを共有できる。

また、Podが削除されてもこのVolumeは削除されない。

HostPathは非推奨である。

# Node内でdockerコマンドを実行
$ docker inspect <コンテナID>

    {

        ...

        "HostConfig": {
            "Binds": [
                "/data:/var/www/foo",
                "/var/lib/kubelet/pods/<PodのUUID>/volumes/kubernetes.io~projected/kube-api-access-*****:/var/run/secrets/kubernetes.io/serviceaccount:ro",
                "/var/lib/kubelet/pods/<PodのUUID>/etc-hosts:/etc/hosts",
                "/var/lib/kubelet/pods/<PodのUUID>/containers/foo/*****:/dev/termination-log"
            ],

            ...
        },

        ...

        "Mounts": [

            ...

            {
                "Type": "bind", # バインドマウントが使用されている。
                "Source": "/data",
                "Destination": "/var/www/foo",
                "Mode": "",
                "RW": "true",
                "Propagation": "rprivate"
            },

            ...
        ]
    }

▼ EmptyDir

Podの既存のストレージ上にVolume (/var/lib/kubelet/pods/<PodのUUID>/volumes/kubernetes.io~empty-dir/ディレクトリ) を作成し、コンテナにボリュームマウントする。

同一Node上のPod間でこのVolumeを共有できず、同一Pod内のコンテナ間ではVolumeを共有できる。

また、Podが削除されるとこのVolumeも同時に削除されてしまう。

保持期間を設定できるツール (例:Prometheus、Victoria Metrics、など) にて、PodのVolumeをEmptyDirとしている場合、Podを保持期間より先に削除すると、保持期間を待たずにVolumeを削除することになってしまう。

▼ 外部サービスのVolume

外部サービス (例:AWS EBS、NFS、など) が提供するVolumeをコンテナにマウントする。

同一Node上のPod間でこのVolumeを共有でき、同一Pod内のコンテナ間でもVolumeを共有できる。

また、Podが削除されてもこのVolumeは削除されない。

▼ Volumeの代わりにPersistentVolumeを使用する

Podの.spec.volumesキーでPersistentVolumeClaimを宣言すれば、Volumeの代わりにPersistentVolumeを使用できる。


06-02. ストレージ要求系

PersistentVolumeClaim

▼ PersistentVolumeClaimとは

設定された条件に基づいて、Kubernetesで作成済みのPersistentVolumeを要求し、指定したKubernetesリソースに割り当てる。

storage_class

▼ 削除できない

PersistentVolumeClaimを削除しようとすると、.metadata.finalizersキー配下にkubernetes.io/pvc-protection値が設定され、削除できなくなることがある。

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  finalizers:
    - kubernetes.io/pvc-protection
  name: foo-persistent-volume-claim
spec: ...

この場合、kubectl editコマンドなどで.metadata.finalizersキーを空配列に編集と、削除できるようになる。

$ kubectl edit pvc <PersistentVolumeClaim名>
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  finalizers: []
  name: foo-persistent-volume-claim
spec: ...

▼ node affinity conflict

PersistentVolumeClaimは、annotationキー配下のvolume.kubernetes.io/selected-nodeキーで、紐づくPersistentVolumeが配置されているNode名を指定している。

PersistentVolumeClaimは、条件に応じてPersistentVolumeを探す。

しかし、PersistentVolumeClaimが volume.kubernetes.io/selected-node キーで指定するNodeと、PodをスケジューリングさせているNodeが異なるAZであると、以下のエラーになってしまう。

N node(s) had volume node affinity conflict, N node(s) didn't match Pod's node affinity/selector

これが起こる原因は様々ある (例:Nodeの再作成時にPodのあるNodeのAZが変わる、AWSのスポットインスタンスで特定のAZにしかNodeが作成されない)。

*解決例*

ここでは、Nodeの再作成でPodのあるNodeのAZが変わった場合の解決策を記載する。

AWSのスポットインスタンスで特定のAZにしかNodeが作成されない問題では対処できない。

例えば、もともとaゾーンにいるPodがNodeの再作成で再スケジューリングされ、cゾーンになったとする。

しかし、Podに紐づくPersistentVolumeClaimは元々のaゾーンのNodeのPersistentVolumeを指定したままになっており、cゾーンのPodはaゾーンのPersistentVolumeを指定できないため、volume node affinity conflictになる。

以下の手順で、PersistentVolumeClaimとこれを指定するPodの両方を再作成し、PersistentVolumeClaimはPodと同じゾーンのPersistentVolumeを指定可能にする。

注意点として、何らかの理由 (例:スポットインスタンス) で、特定のAZにNodeを配置できない場合、この手順では解決できない。

(1)

起動できないPodをいずれのNodeでスケジューリングさせようとしているのか確認する。

$ kubectl describe pod <Pod名> -o wide | grep Node:
(2)

Nodeのあるゾーンを確認する。

$ kubectl describe node <PodのあるNode名> | grep topology.kubernetes.io
(3)

PersistentVolumeClaimのvolume.kubernetes.io/selected-nodeキーで、PodがいずれのNodeのPersistentVolumeを指定しているかを確認する。

このNode名をメモしておく。

$ kubectl describe pvc <PVC名> -n prometheus | grep selected-node
(4)

Nodeのあるゾーンを確認する。

$ kubectl describe node ip-*-*-*-*.ap-northeast-1.compute.internal | grep zone
(5)

(1)と(4)の手順で確認したNodeのゾーンが異なるゾーンであることを確認する。

(6)

PersistentVolumeClaimを削除する。

この時PersistentVolumeは削除されないため、保管データは削除されない。

(7)

StatefulSet自体を再作成する。

(8)

StatefulSetがPersistentVolumeClaimを新しく作成する。

(9)

PersistentVolumeClaimが、Podと同じゾーンのPersistentVolumeを指定できるようになる。

▼ サイズを拡張する

PVCの値が変われば、使用するPVを変えられる。

--cascadeオプションでPodを残してStatefulSetを

$ kubectl patch prometheus foo --patch '{"spec": {"paused": "true", "storage": {"volumeClaimTemplate": {"spec": {"resources": {"requests": {"storage":"10Gi"}}}}}}}' --type merge

$ kubectl delete statefulset -l operator.prometheus.io/name=foo-operator --cascade=orphan


StorageClass

▼ StorageClassとは

Kubernetes外部でプロビジョニングされたストレージ (例:AWS EBS、Azure Disk、など) を要求し、これをVolumeとしてPersistentVolumeClaimに提供する。

そのため、PersistentVolumeも合わせて作成する必要がある。

StorageClassを使用する場合は、PersistentVolumeClaimではなくStorageClass側でreclaimPolicyキーとして設定する。

storage_class

▼ AWS EBSを要求する場合

reclaimPolicyDeleteになっているPersistentVolumeClaimを削除すれば、StorageClassがAWS EBSもよしなに削除してくれる。



07. 認証系リソース

CertificateSigningRequest

▼ CertificateSigningRequestとは

認証局に対するSSL証明書の要求 (openssl x509コマンド) を宣言的に設定する。

別途、秘密鍵から証明書署名要求を作成し、これをパラメーターとして設定する必要がある。


ServiceAccount

▼ ServiceAccountとは

kubernetes_authorization

kube-apiserverが、リクエストの送信元を認証可能にする。

kube-apiserverが、Kubernetesリソース (特にPod) を認証可能にする。

別途、RoleBindingやClusterRoleBindingを使用してKubernetesリソースに認可スコープを設定する必要がある。

標準のKubernetesリソースには自動的にServiceAccountが設定される。

▼ ServiceAccountの仕組み

ServiceAccountは、ServiceAccount本体、service-account-controller、token-controller、service-account-admission-controller、といったコンポーネントから構成されている。

コンポーネント
service-account-controller Namespace内にdefaultというServiceAccountを自動的に作成する。
token-controller ServiceAccount用のSecretの作成をポーリングし、Secretにトークン文字列を追加する。一方で、Secretの削除をポーリングし、ServiceAccountからSecretの指定を削除する。また、ServiceAccountの削除をポーリングし、token-controllerはSecretのトークン文字列を自動的に削除する。
service-account-admission-controller AdmissionWebhookの仕組みの中で、Podの作成時に、Volume上の/var/run/secrets/kubernetes.io/serviceaccountディレクトリをコンテナにマウントする。トークンの文字列は、/var/run/secrets/kubernetes.io/serviceaccount/tokenファイルに記載されている。

▼ ServiceAccountのユーザー名

特にServiceAccountには、より正確な定義のユーザー名がある。

ServiceAccountのユーザー名は、system:serviceaccount:<Namespace名>:<ServiceAccount名>で定義されている。

これは、RoleBindingやClusterBindingの定義時に使用できる。


UserAccount

▼ UserAccountとは

kubernetes_authorization

kube-apiserverが、リクエストの送信元を認証可能にする。

kube-apiserverが、クライアントを認証可能にする。別途、RoleBindingやClusterRoleBindingを使用して、クライアントに認可スコープを設定する必要がある。

クライアントの認証に必要なクライアント証明書は、kubeconfigファイルに登録する必要がある。


User/Group

クラウド上のユーザーやグループをKubernetes上で使用する場合、User/Groupで指定する。


08. 認可系リソース

Role、ClusterRole

▼ Role

NamespacedスコープなKubernetesリソースやカスタムリソース (Namespaceを設定できるKubernetesリソース) に関する認可スコープを設定する。

kubernetes_authorization

▼ ClusterRoleとは

ClusterスコープなKubernetesリソースやカスタムリソース (Namespaceを設定できないKubernetesリソース) に関する認可スコープを設定する。

kubernetes_authorization

▼ RBAC:Role-based access control

Role、ClusterRole、を使用して認可スコープを制御する仕組みのこと。


RoleBinding

▼ ClusterRoleBinding

ClusterRoleを、UserAccount / ServiceAccount / Groupに紐付ける。

注意点として、ClusterRoleのみの紐付けに使用できる。

▼ RoleBinding

RoleやClusterRoleを、UserAccount / ServiceAccount / Groupに紐付ける。

注意点として、RoleとClusterRoleの両方の紐付けに使用できる。

もしRoleを紐づけた場合は、そのUserAccount / ServiceAccount / Groupは、NamespacedスコープのKubernetesリソースやカスタムリソースに関する権限を得る。

もしClusterRoleを紐づけた場合は、そのUserAccount / ServiceAccount / Groupは、ClusterスコープのKubernetesリソースやカスタムリソースに関する権限を得る。


09. ポリシー系リソース

NetworkPolicy

▼ NetworkPolicyとは

Pod間通信でのインバウンド/アウトバウンド通信の送受信ルールを設定する。

▼ Ingressの場合

他のPodからの受信する通信のルールを設定する。

Ingressとは関係がないことに注意する。

▼ Egressの場合

他のPodに送信する通信のルールを設定する。