これは、このセクションの複数ページの印刷可能なビューです。 印刷するには、ここをクリックしてください.
Podとコンテナの設定
- 1: コンテナおよびPodへのメモリーリソースの割り当て
- 2: コンテナおよびPodへのCPUリソースの割り当て
- 3: Windows Podとコンテナに対するGMSAの設定
- 4: コンテナに割り当てるCPUとメモリ容量を変更する
- 5: PodにQuality of Serviceを設定する
- 6: 拡張リソースをコンテナに割り当てる
- 7: ストレージにボリュームを使用するPodを構成する
- 8: ストレージにProjectedボリュームを使用するようPodを設定する
- 9: Podとコンテナにセキュリティコンテキストを設定する
- 10: Podにサービスアカウントを設定する
- 11: イメージをプライベートレジストリから取得する
- 12: Liveness Probe、Readiness ProbeおよびStartup Probeを使用する
- 13: Podをノードに割り当てる
- 14: Node Affinityを利用してPodをノードに割り当てる
- 15: Pod初期化の設定
- 16: コンテナライフサイクルイベントへのハンドラー紐付け
- 17: Podを構成してConfigMapを使用する
- 18: Pod内のコンテナ間でプロセス名前空間を共有する
- 19: Podでユーザー名前空間を使用する
- 20: static Podを作成する
- 21: 名前空間のラベルを使用してPodセキュリティスタンダードを強制する
- 22: PodSecurityPolicyからビルトインのPodセキュリティアドミッションコントローラーに移行する
1 - コンテナおよびPodへのメモリーリソースの割り当て
このページでは、メモリーの 要求 と 制限 をコンテナに割り当てる方法について示します。コンテナは要求されたメモリーを確保することを保証しますが、その制限を超えるメモリーの使用は許可されません。
始める前に
Kubernetesクラスターが必要、かつそのクラスターと通信するためにkubectlコマンドラインツールが設定されている必要があります。 このチュートリアルは、コントロールプレーンのホストとして動作していない少なくとも2つのノードを持つクラスターで実行することをおすすめします。 まだクラスターがない場合、minikubeを使って作成するか、 以下のいずれかのKubernetesプレイグラウンドも使用できます:
バージョンを確認するには次のコマンドを実行してください: kubectl version.
クラスターの各ノードには、少なくとも300MiBのメモリーが必要になります。
このページのいくつかの手順では、クラスターにてmetrics-serverサービスを実行する必要があります。すでにmetrics-serverが動作している場合、これらの手順をスキップできます。
Minikubeを動作させている場合、以下のコマンドによりmetrics-serverを有効にできます:
minikube addons enable metrics-server
metrics-serverが実行されているか、もしくはリソースメトリクスAPI (metrics.k8s.io) の別のプロバイダーが実行されていることを確認するには、以下のコマンドを実行してください:
kubectl get apiservices
リソースメトリクスAPIが利用可能であれば、出力には metrics.k8s.io への参照が含まれます。
NAME
v1beta1.metrics.k8s.io
namespaceの作成
この練習で作成するリソースがクラスター内で分離されるよう、namespaceを作成します。
kubectl create namespace mem-example
メモリーの要求と制限を指定する
コンテナにメモリーの要求を指定するには、コンテナのリソースマニフェストにresources:requestsフィールドを追記します。メモリーの制限を指定するには、resources:limitsを追記します。
この練習では、一つのコンテナをもつPodを作成します。コンテナに100MiBのメモリー要求と200MiBのメモリー制限を与えます。Podの設定ファイルは次のようになります:
apiVersion: v1
kind: Pod
metadata:
name: memory-demo
namespace: mem-example
spec:
containers:
- name: memory-demo-ctr
image: polinux/stress
resources:
limits:
memory: "200Mi"
requests:
memory: "100Mi"
command: ["stress"]
args: ["--vm", "1", "--vm-bytes", "150M", "--vm-hang", "1"]
設定ファイルのargsセクションでは、コンテナ起動時の引数を与えます。"--vm-bytes", "150M"という引数では、コンテナに150MiBのメモリーを割り当てます。
Podを作成してください:
kubectl apply -f https://k8s.io/examples/pods/resource/memory-request-limit.yaml --namespace=mem-example
Podのコンテナが起動していることを検証してください:
kubectl get pod memory-demo --namespace=mem-example
Podの詳細な情報を確認してください:
kubectl get pod memory-demo --output=yaml --namespace=mem-example
この出力では、Pod内の一つのコンテナに100MiBのメモリー要求と200MiBのメモリー制限があることを示しています。
...
resources:
limits:
memory: 200Mi
requests:
memory: 100Mi
...
kubectl topを実行し、Podのメトリクスを取得してください:
kubectl top pod memory-demo --namespace=mem-example
この出力では、Podが約162,900,000バイト(約150MiB)のメモリーを使用していることを示しています。Podの100MiBの要求を超えていますが、200MiBの制限には収まっています。
NAME CPU(cores) MEMORY(bytes)
memory-demo <something> 162856960
Podを削除してください:
kubectl delete pod memory-demo --namespace=mem-example
コンテナのメモリー制限を超える
ノードに利用可能なメモリーがある場合、コンテナはメモリー要求を超えることができます。しかしながら、メモリー制限を超えて使用することは許可されません。コンテナが制限を超えてメモリーを確保しようとした場合、そのコンテナは終了候補となります。コンテナが制限を超えてメモリーを消費し続ける場合、コンテナは終了されます。終了したコンテナを再起動できる場合、ほかのランタイムの失敗時と同様に、kubeletがコンテナを再起動させます。
この練習では、制限を超えてメモリーを確保しようとするPodを作成します。以下に50MiBのメモリー要求と100MiBのメモリー制限を与えたコンテナを持つ、Podの設定ファイルを示します:
apiVersion: v1
kind: Pod
metadata:
name: memory-demo-2
namespace: mem-example
spec:
containers:
- name: memory-demo-2-ctr
image: polinux/stress
resources:
requests:
memory: "50Mi"
limits:
memory: "100Mi"
command: ["stress"]
args: ["--vm", "1", "--vm-bytes", "250M", "--vm-hang", "1"]
設定ファイルのargsセクションでは、コンテナに250MiBのメモリーを割り当てており、これは100MiBの制限を十分に超えています。
Podを作成してください:
kubectl apply -f https://k8s.io/examples/pods/resource/memory-request-limit-2.yaml --namespace=mem-example
Podの詳細な情報を確認してください:
kubectl get pod memory-demo-2 --namespace=mem-example
この時点で、コンテナは起動中か強制終了されているでしょう。コンテナが強制終了されるまで上記のコマンドをくり返し実行してください:
NAME READY STATUS RESTARTS AGE
memory-demo-2 0/1 OOMKilled 1 24s
コンテナステータスの詳細な情報を取得してください:
kubectl get pod memory-demo-2 --output=yaml --namespace=mem-example
この出力では、コンテナがメモリー不足 (OOM) により強制終了されたことを示しています。
lastState:
terminated:
containerID: docker://65183c1877aaec2e8427bc95609cc52677a454b56fcb24340dbd22917c23b10f
exitCode: 137
finishedAt: 2017-06-20T20:52:19Z
reason: OOMKilled
startedAt: null
この練習のコンテナはkubeletによって再起動されます。次のコマンドを数回くり返し実行し、コンテナが強制終了と再起動を続けていることを確認してください:
kubectl get pod memory-demo-2 --namespace=mem-example
この出力では、コンテナが強制終了され、再起動され、再度強制終了および再起動が続いていることを示しています:
kubectl get pod memory-demo-2 --namespace=mem-example
NAME READY STATUS RESTARTS AGE
memory-demo-2 0/1 OOMKilled 1 37s
kubectl get pod memory-demo-2 --namespace=mem-example
NAME READY STATUS RESTARTS AGE
memory-demo-2 1/1 Running 2 40s
Podの履歴について詳細な情報を確認してください:
kubectl describe pod memory-demo-2 --namespace=mem-example
この出力では、コンテナの開始とその失敗が繰り返されていることを示しています:
... Normal Created Created container with id 66a3a20aa7980e61be4922780bf9d24d1a1d8b7395c09861225b0eba1b1f8511
... Warning BackOff Back-off restarting failed container
クラスターのノードの詳細な情報を確認してください:
kubectl describe nodes
この出力には、メモリー不足の状態のためコンテナが強制終了された記録が含まれます:
Warning OOMKilling Memory cgroup out of memory: Kill process 4481 (stress) score 1994 or sacrifice child
Podを削除してください:
kubectl delete pod memory-demo-2 --namespace=mem-example
ノードよりも大きいメモリー要求を指定する
メモリー要求と制限はコンテナと関連づけられていますが、Podにメモリー要求と制限が与えられていると考えるとわかりやすいでしょう。Podのメモリー要求は、Pod内のすべてのコンテナのメモリー要求の合計となります。同様に、Podのメモリー制限は、Pod内のすべてのコンテナのメモリー制限の合計となります。
Podのスケジューリングは要求に基づいています。Podはノード上で動作するうえで、そのメモリー要求に対してノードに十分利用可能なメモリーがある場合のみスケジュールされます。
この練習では、クラスター内のノードのキャパシティを超える大きさのメモリー要求を与えたPodを作成します。以下に1000GiBのメモリー要求を与えた一つのコンテナを持つ、Podの設定ファイルを示します。これは、クラスター内のノードのキャパシティを超える可能性があります。
apiVersion: v1
kind: Pod
metadata:
name: memory-demo-3
namespace: mem-example
spec:
containers:
- name: memory-demo-3-ctr
image: polinux/stress
resources:
limits:
memory: "1000Gi"
requests:
memory: "1000Gi"
command: ["stress"]
args: ["--vm", "1", "--vm-bytes", "150M", "--vm-hang", "1"]
Podを作成してください:
kubectl apply -f https://k8s.io/examples/pods/resource/memory-request-limit-3.yaml --namespace=mem-example
Podの状態を確認してください:
kubectl get pod memory-demo-3 --namespace=mem-example
この出力では、Podのステータスが待機中であることを示しています。つまり、Podがどのノードに対しても実行するようスケジュールされておらず、いつまでも待機状態のままであることを表しています:
kubectl get pod memory-demo-3 --namespace=mem-example
NAME READY STATUS RESTARTS AGE
memory-demo-3 0/1 Pending 0 25s
イベントを含むPodの詳細な情報を確認してください:
kubectl describe pod memory-demo-3 --namespace=mem-example
この出力では、ノードのメモリー不足のためコンテナがスケジュールされないことを示しています:
Events:
... Reason Message
------ -------
... FailedScheduling No nodes are available that match all of the following predicates:: Insufficient memory (3).
メモリーの単位
メモリーリソースはバイト単位で示されます。メモリーをE、P、T、G、M、K、Ei、Pi、Ti、Gi、Mi、Kiという接尾辞とともに、整数型または固定小数点整数で表現できます。たとえば、以下はおおよそ同じ値を表します:
128974848, 129e6, 129M , 123Mi
Podを削除してください:
kubectl delete pod memory-demo-3 --namespace=mem-example
メモリー制限を指定しない場合
コンテナのメモリー制限を指定しない場合、次のいずれかの状態となります:
-
コンテナのメモリー使用量に上限がない状態となります。コンテナは実行中のノードで利用可能なすべてのメモリーを使用でき、その後OOM Killerが呼び出される可能性があります。さらに、OOM killの場合、リソース制限のないコンテナは強制終了される可能性が高くなります。
-
メモリー制限を与えられたnamespaceでコンテナを実行されると、コンテナにはデフォルトの制限値が自動的に指定されます。クラスターの管理者はLimitRangeによってメモリー制限のデフォルト値を指定できます。
メモリー要求と制限のモチベーション
クラスターで動作するコンテナにメモリー要求と制限を設定することで、クラスターのノードで利用可能なメモリーリソースを効率的に使用することができます。Podのメモリー要求を低く保つことで、Podがスケジュールされやすくなります。メモリー要求よりも大きい制限を与えることで、次の2つを実現できます:
- Podは利用可能なメモリーを、突発的な活動(バースト)に使用することができます。
- バースト中のPodのメモリー使用量は、適切な量に制限されます。
クリーンアップ
namespaceを削除してください。これにより、今回のタスクで作成したすべてのPodが削除されます:
kubectl delete namespace mem-example
次の項目
アプリケーション開発者向け
クラスター管理者向け
2 - コンテナおよびPodへのCPUリソースの割り当て
このページでは、CPUの request と limit をコンテナに割り当てる方法について示します。コンテナは設定された制限を超えてCPUを使用することはできません。システムにCPUの空き時間がある場合、コンテナには要求されたCPUを割り当てられます。
始める前に
Kubernetesクラスターが必要、かつそのクラスターと通信するためにkubectlコマンドラインツールが設定されている必要があります。 このチュートリアルは、コントロールプレーンのホストとして動作していない少なくとも2つのノードを持つクラスターで実行することをおすすめします。 まだクラスターがない場合、minikubeを使って作成するか、 以下のいずれかのKubernetesプレイグラウンドも使用できます:
バージョンを確認するには次のコマンドを実行してください: kubectl version.
タスク例を実行するには、クラスターに少なくとも利用可能な1 CPUが必要です。
このページのいくつかの手順では、クラスターにてmetrics-serverサービスを実行する必要があります。すでにmetrics-serverが動作している場合、これらの手順をスキップできます。
Minikubeを動作させている場合、以下のコマンドによりmetrics-serverを有効にできます:
minikube addons enable metrics-server
metrics-serverが実行されているか、もしくはリソースメトリクスAPI (metrics.k8s.io) の別のプロバイダーが実行されていることを確認するには、以下のコマンドを実行してください:
kubectl get apiservices
リソースメトリクスAPIが利用可能であれば、出力には metrics.k8s.io への参照が含まれます。
NAME
v1beta1.metrics.k8s.io
namespaceの作成
この練習で作成するリソースがクラスター内で分離されるよう、Namespaceを作成します。
kubectl create namespace cpu-example
CPUの要求と制限を指定する
コンテナにCPUの要求を指定するには、コンテナのリソースマニフェストにresources:requestsフィールドを追記します。CPUの制限を指定するには、resources:limitsを追記します。
この練習では、一つのコンテナをもつPodを作成します。コンテナに0.5 CPUの要求と1 CPUの制限を与えます。Podの設定ファイルは次のようになります:
apiVersion: v1
kind: Pod
metadata:
name: cpu-demo
namespace: cpu-example
spec:
containers:
- name: cpu-demo-ctr
image: vish/stress
resources:
limits:
cpu: "1"
requests:
cpu: "0.5"
args:
- -cpus
- "2"
設定ファイルのargsセクションでは、コンテナ起動時の引数を与えます。-cpus "2"という引数では、コンテナに2 CPUを割り当てます。
Podを作成してください:
kubectl apply -f https://k8s.io/examples/pods/resource/cpu-request-limit.yaml --namespace=cpu-example
Podのコンテナが起動していることを検証してください:
kubectl get pod cpu-demo --namespace=cpu-example
Podの詳細な情報を確認してください:
kubectl get pod cpu-demo --output=yaml --namespace=cpu-example
この出力では、Pod内の一つのコンテナに500ミリCPUの要求と1 CPUの制限があることを示しています。
resources:
limits:
cpu: "1"
requests:
cpu: 500m
kubectl topを実行し、Podのメトリクスを取得してください:
kubectl top pod cpu-demo --namespace=cpu-example
この出力では、Podが974ミリCPUを使用していることを示しています。Podの設定で指定した1 CPUの制限よりわずかに小さい値です。
NAME CPU(cores) MEMORY(bytes)
cpu-demo 974m <something>
-cpu "2"を設定することで、コンテナが2 CPU利用しようとすることを思い出してください。しかしながら、コンテナは約1 CPUしか使用することができません。コンテナが制限よりも多くのCPUリソースを利用しようとしているため、コンテナのCPUの利用が抑制されています。
備考:
CPUの使用量が1.0未満である理由の可能性して、ノードに利用可能なCPUリソースが十分にないことが挙げられます。この練習における必要条件として、クラスターに少なくとも利用可能な1 CPUが必要であることを思い出してください。1 CPUのノード上でコンテナを実行させる場合、指定したコンテナのCPU制限にかかわらず、コンテナは1 CPU以上使用することはできません。CPUの単位
CPUリソースは CPU の単位で示されます。Kubernetesにおいて1つのCPUは次に等しくなります:
- 1 AWS vCPU
- 1 GCPコア
- 1 Azure vCore
- ハイパースレッディングが有効なベアメタルIntelプロセッサーの1スレッド
小数値も利用可能です。0.5 CPUを要求するコンテナには、1 CPUを要求するコンテナの半分のCPUが与えられます。mというミリを表す接尾辞も使用できます。たとえば、100m CPU、100 milliCPU、0.1 CPUはすべて同じです。1m以上の精度は指定できません。
CPUはつねに絶対量として要求され、決して相対量としては要求されません。0.1はシングルコア、デュアルコア、48コアCPUのマシンで同じ量となります。
Podを削除してください:
kubectl delete pod cpu-demo --namespace=cpu-example
ノードよりも大きいCPU要求を指定する
CPU要求と制限はコンテナと関連づけられていますが、PodにCPU要求と制限が与えられていると考えるとわかりやすいでしょう。PodのCPU要求は、Pod内のすべてのコンテナのCPU要求の合計となります。同様に、PodのCPU制限は、Pod内のすべてのコンテナのCPU制限の合計となります。
Podのスケジューリングはリソースの要求量に基づいています。Podはノード上で動作するうえで、そのCPU要求に対してノードに十分利用可能なCPUリソースがある場合のみスケジュールされます。
この練習では、クラスター内のノードのキャパシティを超える大きさのCPU要求を与えたPodを作成します。以下に100 CPUの要求を与えた一つのコンテナを持つ、Podの設定ファイルを示します。これは、クラスター内のノードのキャパシティを超える可能性があります。
apiVersion: v1
kind: Pod
metadata:
name: cpu-demo-2
namespace: cpu-example
spec:
containers:
- name: cpu-demo-ctr-2
image: vish/stress
resources:
limits:
cpu: "100"
requests:
cpu: "100"
args:
- -cpus
- "2"
Podを作成してください:
kubectl apply -f https://k8s.io/examples/pods/resource/cpu-request-limit-2.yaml --namespace=cpu-example
Podの状態を確認してください:
kubectl get pod cpu-demo-2 --namespace=cpu-example
この出力では、Podのステータスが待機中であることを示しています。つまり、Podがどのノードに対しても実行するようスケジュールされておらず、いつまでも待機状態のままであることを表しています:
NAME READY STATUS RESTARTS AGE
cpu-demo-2 0/1 Pending 0 7m
イベントを含むPodの詳細な情報を確認してください:
kubectl describe pod cpu-demo-2 --namespace=cpu-example
この出力では、ノードのCPU不足のためコンテナがスケジュールされないことを示しています:
Events:
Reason Message
------ -------
FailedScheduling No nodes are available that match all of the following predicates:: Insufficient cpu (3).
Podを削除してください:
kubectl delete pod cpu-demo-2 --namespace=cpu-example
CPU制限を指定しない場合
コンテナのCPU制限を指定しない場合、次のいずれかの状態となります:
-
コンテナのCPUリソースの使用量に上限がない状態となります。コンテナは実行中のノードで利用可能なすべてのCPUを使用できます。
-
CPU制限を与えられたnamespaceでコンテナを実行されると、コンテナにはデフォルトの制限値が自動的に指定されます。クラスターの管理者はLimitRangeによってCPU制限のデフォルト値を指定できます。
CPU要求と制限のモチベーション
クラスターで動作するコンテナにCPU要求と制限を設定することで、クラスターのノードで利用可能なCPUリソースを効率的に使用することができます。PodのCPU要求を低く保つことで、Podがスケジュールされやすくなります。CPU要求よりも大きい制限を与えることで、次の2つを実現できます:
- Podは利用可能なCPUリソースを、突発的な活動(バースト)に使用することができます。
- バースト中のPodのCPUリソース量は、適切な量に制限されます。
クリーンアップ
namespaceを削除してください:
kubectl delete namespace cpu-example
次の項目
アプリケーション開発者向け
クラスター管理者向け
3 - Windows Podとコンテナに対するGMSAの設定
このページでは、Windowsノード上で動作するPodとコンテナに対するグループ管理サービスアカウント(GMSA)の設定方法を示します。 グループ管理サービスアカウントは特別な種類のActive Directoryアカウントで、パスワードの自動管理、簡略化されたサービスプリンシパル名(SPN)の管理、および管理を他の管理者に委任する機能を複数のサーバーに提供します。
Kubernetesでは、GMSA資格情報仕様は、Kubernetesクラスター全体をスコープとするカスタムリソースとして設定されます。 WindowsのPodおよびPod内の個々のコンテナは、他のWindowsサービスとやり取りする際に、ドメインベースの機能(例えばKerberos認証)に対してGMSAを使用するように設定できます。
始める前に
Kubernetesクラスターが必要で、kubectlコマンドラインツールがクラスターと通信できるように設定されている必要があります。
クラスターにはWindowsワーカーノードを持つことが求められます。
このセクションでは、各クラスターに対して一度だけ実施する必要がある一連の初期ステップについて説明します:
GMSACredentialSpec CRDのインストール
カスタムリソースタイプGMSACredentialSpecを定義するために、GMSA資格情報仕様リソースに対するCustomResourceDefinition(CRD)をクラスター上で設定する必要があります。
GMSA CRDのYAMLをダウンロードし、gmsa-crd.yamlとして保存します。
次に、kubectl apply -f gmsa-crd.yamlを実行してCRDをインストールします。
GMSAユーザーを検証するためのWebhookのインストール
Podまたはコンテナレベルで参照するGMSA資格情報仕様を追加および検証するために、Kubernetesクラスター上で2つのWebhookを設定する必要があります:
-
Mutating Webhookは、(Podの仕様から名前で指定された)GMSAへの参照を、JSON形式の完全な資格情報仕様としてPodのspecの中へ展開します。
-
Validating Webhookは、すべてのGMSAへの参照に対して、Podサービスアカウントによる利用が認可されているか確認します。
上記Webhookと関連するオブジェクトをインストールするためには、次の手順が必要です:
-
証明書と鍵のペアを作成します(Webhookコンテナがクラスターと通信できるようにするために使用されます)
-
上記の証明書を含むSecretをインストールします。
-
コアとなるWebhookロジックのためのDeploymentを作成します。
-
Deploymentを参照するValidating WebhookとMutating Webhookの設定を作成します。
上で述べたGMSA Webhookと関連するオブジェクトを展開、構成するためのスクリプトがあります。
スクリプトは、--dry-run=serverオプションをつけることで、クラスターに対して行われる変更内容をレビューすることができます。
Webhookと関連するオプジェクトを(適切なパラメーターを渡すことで)手動で展開するためのYAMLテンプレートもあります。
Active DirectoryにGMSAとWindowsノードを構成する
Windows GMSAのドキュメントに記載されている通り、Kubernetes内のPodがGMSAを使用するために設定できるようにする前に、Active Directory内に目的のGMSAを展開する必要があります。 Windows GMSAのドキュメントに記載されている通り、(Kubernetesクラスターの一部である)Windowsワーカーノードは、目的のGMSAに関連づけられたシークレット資格情報にアクセスできるように、Active Directory内で設定されている必要があります。
GMSA資格情報仕様リソースの作成
(前述の通り)GMSACredentialSpec CRDをインストールすると、GMSA資格情報仕様を含むカスタムリソースを設定できます。 GMSA資格情報仕様には、シークレットや機密データは含まれません。 それは、コンテナランタイムが目的のコンテナのGMSAをWindowsに対して記述するために使用できる情報です。 GMSA資格情報仕様は、PowerShellスクリプトのユーティリティを使用して、YAMLフォーマットで生成することができます。
以下は、GMSA資格情報仕様をJSON形式で手動で生成し、その後それをYAMLに変換する手順です:
-
CredentialSpecモジュールをインポートします:
ipmo CredentialSpec.psm1 -
New-CredentialSpecを使用してJSONフォーマットの資格情報仕様を作成します。 WebApp1という名前のGMSA資格情報仕様を作成するには、New-CredentialSpec -Name WebApp1 -AccountName WebApp1 -Domain $(Get-ADDomain -Current LocalComputer)を実行します -
Get-CredentialSpecを使用して、JSONファイルのパスを表示します。 -
credspecファイルをJSON形式からYAML形式に変換し、Kubernetesで設定可能なGMSACredentialSpecカスタムリソースにするために、必要なヘッダーフィールドである
apiVersion、kind、metadata、credspecを記述します。
次のYAML設定は、gmsa-WebApp1という名前のGMSA資格情報仕様を記述しています:
apiVersion: windows.k8s.io/v1
kind: GMSACredentialSpec
metadata:
name: gmsa-WebApp1 # これは任意の名前で構いませんが、参照時に使用されます
credspec:
ActiveDirectoryConfig:
GroupManagedServiceAccounts:
- Name: WebApp1 # GMSAアカウントのユーザー名
Scope: CONTOSO # NETBIOSドメイン名
- Name: WebApp1 # GMSAアカウントのユーザー名
Scope: contoso.com # DNSドメイン名
CmsPlugins:
- ActiveDirectory
DomainJoinConfig:
DnsName: contoso.com # DNSドメイン名
DnsTreeName: contoso.com # DNSルートドメイン名
Guid: 244818ae-87ac-4fcd-92ec-e79e5252348a # GUID
MachineAccountName: WebApp1 # GMSAアカウントのユーザー名
NetBiosName: CONTOSO # NETBIOSドメイン名
Sid: S-1-5-21-2126449477-2524075714-3094792973 # GMSAのSID
上記の資格情報仕様リソースはgmsa-Webapp1-credspec.yamlとして保存され、次のコマンドを使用してクラスターに適用されます: kubectl apply -f gmsa-Webapp1-credspec.yml
指定されたGMSA資格情報仕様上にRBACを有効にするためのクラスターロールの設定
各GMSA資格情報仕様リソースに対して、クラスターロールを定義する必要があります。
これは特定のGMSAリソース上のuse verbを、通常はサービスアカウントであるsubjectに対して認可します。
次の例は、前述のgmsa-WebApp1資格情報仕様の利用を認可するクラスターロールを示しています。
ファイルをgmsa-webapp1-role.yamlとして保存し、kubectl apply -f gmsa-webapp1-role.yamlを使用して適用します。
# credspecを読むためのロールを作成
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: webapp1-role
rules:
- apiGroups: ["windows.k8s.io"]
resources: ["gmsacredentialspecs"]
verbs: ["use"]
resourceNames: ["gmsa-WebApp1"]
指定されたGMSA credspecを使用するためのサービスアカウントへのロールの割り当て
(Podに対して設定される)サービスアカウントを、上で作成したクラスターロールに結びつける必要があります。
これによって、要求されたGMSA資格情報仕様のリソースの利用をサービスアカウントに対して認可できます。
以下は、上で作成した資格情報仕様リソースgmsa-WebApp1を使うために、既定のサービスアカウントに対してクラスターロールwebapp1-roleを割り当てる方法を示しています。
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: allow-default-svc-account-read-on-gmsa-WebApp1
namespace: default
subjects:
- kind: ServiceAccount
name: default
namespace: default
roleRef:
kind: ClusterRole
name: webapp1-role
apiGroup: rbac.authorization.k8s.io
Podのspec内で参照するGMSA資格情報仕様の設定
PodのspecのフィールドsecurityContext.windowsOptions.gmsaCredentialSpecNameは、要求されたGMSA資格情報仕様のカスタムリソースに対する参照を、Podのspec内で指定するために使用されます。
これは、Podのspec内の全てのコンテナに対して、指定されたGMSAを使用するように設定します。
gmsa-WebApp1を参照するために追加された注釈を持つPodのspecのサンプルです:
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
run: with-creds
name: with-creds
namespace: default
spec:
replicas: 1
selector:
matchLabels:
run: with-creds
template:
metadata:
labels:
run: with-creds
spec:
securityContext:
windowsOptions:
gmsaCredentialSpecName: gmsa-webapp1
containers:
- image: mcr.microsoft.com/windows/servercore/iis:windowsservercore-ltsc2019
imagePullPolicy: Always
name: iis
nodeSelector:
kubernetes.io/os: windows
Podのspec内の個々のコンテナも、コンテナ毎のsecurityContext.windowsOptions.gmsaCredentialSpecNameフィールドを使用することで、要求されたGMSA credspecを指定することができます。
設定例:
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
run: with-creds
name: with-creds
namespace: default
spec:
replicas: 1
selector:
matchLabels:
run: with-creds
template:
metadata:
labels:
run: with-creds
spec:
containers:
- image: mcr.microsoft.com/windows/servercore/iis:windowsservercore-ltsc2019
imagePullPolicy: Always
name: iis
securityContext:
windowsOptions:
gmsaCredentialSpecName: gmsa-Webapp1
nodeSelector:
kubernetes.io/os: windows
(上記のような)GMSAフィールドが入力されたPod specがクラスターに適用されると、次の一連のイベントが発生します:
-
Mutating WebhookがGMSA資格情報仕様リソースへの全ての参照を解決し、GMSA資格情報仕様の内容を展開します。
-
Validating Webhookは、Podに関連付けられたサービスアカウントが、指定されたGMSA資格情報仕様上の
useverbに対して認可されていることを保証します。 -
コンテナランタイムは、指定されたGMSA資格情報仕様で各Windowsコンテナを設定します。 それによってコンテナはGMSAのIDがActive Directory内にあることを仮定でき、そのIDを使用してドメイン内のサービスにアクセスできます。
ホスト名またはFQDNを使用してネットワーク共有に対して認証する
PodからSMB共有へのホスト名やFQDNを使用した接続で問題が発生した際に、IPv4アドレスではSMB共有にアクセスすることはできる場合には、次のレジストリキーがWindowsノード上で設定されているか確認してください。
reg add "HKLM\SYSTEM\CurrentControlSet\Services\hns\State" /v EnableCompartmentNamespace /t REG_DWORD /d 1
その後、動作の変更を反映させるために、実行中のPodを再作成する必要があります。 このレジストリキーがどのように使用されるかについてのより詳細な情報は、こちらを参照してください。
トラブルシューティング
自分の環境でGMSAがうまく動作しない時に実行できるトラブルシューティングステップがあります。
まず、credspecがPodに渡されたことを確認します。
そのためには、Podのひとつにexecで入り、nltest.exe /parentdomainコマンドの出力をチェックする必要があります。
以下の例では、Podはcredspecを正しく取得できませんでした:
kubectl exec -it iis-auth-7776966999-n5nzr powershell.exe
nltest.exe /parentdomainの結果は次のようなエラーになります:
Getting parent domain failed: Status = 1722 0x6ba RPC_S_SERVER_UNAVAILABLE
Podが正しくcredspecを取得したら、次にドメインと正しく通信できることを確認します。 まずはPodの中から、ドメインのルートを見つけるために、手短にnslookupを実行します。
これから3つのことがわかります:
- PodがDCまで到達できる
- DCがPodに到達できる
- DNSが正しく動作している
DNSと通信のテストをパスしたら、次にPodがドメインとセキュアチャネル通信を構築することができるか確認する必要があります。
そのためには、再びexecを使用してPodの中に入り、nltest.exe /queryコマンドを実行します。
nltest.exe /query
結果は次のように出力されます:
I_NetLogonControl failed: Status = 1722 0x6ba RPC_S_SERVER_UNAVAILABLE
これは、Podがなんらかの理由で、credspec内で指定されたアカウントを使用してドメインにログオンできなかったことを示しています。 次のコマンドを実行してセキュアチャネルを修復してみてください:
nltest /sc_reset:domain.example
コマンドが成功したら、このような出力を確認することができます:
Flags: 30 HAS_IP HAS_TIMESERV
Trusted DC Name \\dc10.domain.example
Trusted DC Connection Status Status = 0 0x0 NERR_Success
The command completed successfully
もし上記によってエラーが解消された場合は、次のライフサイクルフックをPodのspecに追加することで、手順を自動化できます。 エラーが解消されなかった場合は、credspecをもう一度調べ、正しく完全であることを確認する必要があります。
image: registry.domain.example/iis-auth:1809v1
lifecycle:
postStart:
exec:
command: ["powershell.exe","-command","do { Restart-Service -Name netlogon } while ( $($Result = (nltest.exe /query); if ($Result -like '*0x0 NERR_Success*') {return $true} else {return $false}) -eq $false)"]
imagePullPolicy: IfNotPresent
Podのspecに上記のlifecycleセクションを追加すると、nltest.exe /queryコマンドがエラーとならずに終了するまでnetlogonサービスを再起動するために、Podは一連のコマンドを実行します。
4 - コンテナに割り当てるCPUとメモリ容量を変更する
More information about this feature
This is a stable feature in Kubernetes, and has been since version v1.35. It was first available in the v1.27 release. You can no longer disable or opt out of this feature or behavior (it is locked); if you explicitly set a value for the associated feature gate InPlacePodVerticalScaling, Kubernetes ignores it but does not report any error.
このページはQuality of Serviceに馴染みのある読者を前提としています。
このページでは、稼働中のPodやコンテナを再起動することなく、コンテナに割り当てられるCPUやメモリ容量を変更(リサイズ)するための方法を示します。
Kubernetesノードは、PodのContainerに指定したrequestsに基づいてPodにリソースを割り当て、limitsに基づいてPodのリソース使用量を制限します。
稼働中のPodのリソース割当を変更するには、 InPlacePodVerticalScaling フィーチャーゲートを有効化する必要があります。
代替手法としては、Podを削除した上で、異なるリソース要求を有するPodをワークロードコントローラー に作成させることもできます。
稼働中のPodのリソースを変更するために
- Containerの
requestsとlimitsはCPUおよびメモリリソースに対して 可変 なものとなっています。 - Podステータスの
containerStatusesにおけるallocatedResourcesフィールドは、PodのContainerに割り当てられたリソースを反映します。 - Podステータスの
containerStatusesにおけるresourcesフィールドは、稼働中Containerに設定済みの実際のリソース要求(requests)とリソース制限(limits)を反映しており、これらの値はコンテナランタイムが通知したものです。 - Podステータスの
resizeフィールドは直前の適用待ちのリサイズ要求を示します。 このフィールドの値には次のようなものがあります。Proposed: リサイズ要求の受理を表し、リクエストが検証済みかつ記録済み であることを示します。InProgress: リサイズ要求がノードによって受理され、Podのコンテナに対する 適用が進行中であることを示します。Deferred: リサイズ要求が現時点では通っていないことを示します。 他のPodが除去されてノードの資源が開放されたら、リサイズが承認されるかもしれません。Infeasible: ノードがリサイズ要求に対応できないことを示すシグナルです。 Podに対してノードが割り当て可能なリソースの最大値を上回るリサイズ要求がある時に 発生する可能性があります。
始める前に
Kubernetesクラスターが必要、かつそのクラスターと通信するためにkubectlコマンドラインツールが設定されている必要があります。 このチュートリアルは、コントロールプレーンのホストとして動作していない少なくとも2つのノードを持つクラスターで実行することをおすすめします。 まだクラスターがない場合、minikubeを使って作成するか、 以下のいずれかのKubernetesプレイグラウンドも使用できます:
作業するKubernetesサーバーは次のバージョン以降のものである必要があります: 1.27.バージョンを確認するには次のコマンドを実行してください: kubectl version.
クラスターのコントロールプレーンを含む全ノードでInPlacePodVerticalScaling フィーチャーゲートが有効化されている必要があります。
コンテナリサイズポリシー
リサイズポリシーはPodにおけるコンテナのCPUやメモリリソースを取り扱うためのきめ細かい制御を可能にします。 例えば、アプリケーションを再起動せずにコンテナのCPUリソースのリサイズを行える場合でも、メモリのリサイズについてはアプリケーションとコンテナの再起動が必要となる場合があります。
これを実現するために、ユーザーはContainerの仕様に resizePolicy を指定できるようになっています。
以下の再起動ポリシーをCPUやメモリのリサイズの際に指定できます。
NotRequired: 稼働中のコンテナリソースをリサイズします。RestartContainer: コンテナを再起動させ、再起動時に新しいリソースを適用します。
resizePolicy[*].restartPolicy が指定されない場合のデフォルトは、NotRequiredです。
備考:
PodのrestartPolicyがNeverである場合、Podの全コンテナの再起動ポリシーがNotRequiredである必要があります。以下のPodの例は、ContainerのCPUのリサイズは再起動なしで実施させ、メモリのリサイズにはコンテナの再起動を要求するものです。
apiVersion: v1
kind: Pod
metadata:
name: qos-demo-5
namespace: qos-example
spec:
containers:
- name: qos-demo-ctr-5
image: nginx
resizePolicy:
- resourceName: cpu
restartPolicy: NotRequired
- resourceName: memory
restartPolicy: RestartContainer
resources:
limits:
memory: "200Mi"
cpu: "700m"
requests:
memory: "200Mi"
cpu: "700m"
備考:
この例の requests ないしは limits が CPUとメモリの 両方を 変化させる場合、 メモリのリサイズが生じるので、コンテナは再起動します。リソース要求やリソース制限のあるPodを作成する
リソース要求やリソース制限をPodのコンテナに指定することで、保証(Guaranteed)ないしは バースト可能(Burstable)なQuality of ServiceクラスのPodを作成することができます。
次のような単一のコンテナを含むPodのマニフェストを考えてみましょう。
apiVersion: v1
kind: Pod
metadata:
name: qos-demo-5
namespace: qos-example
spec:
containers:
- name: qos-demo-ctr-5
image: nginx
resources:
limits:
memory: "200Mi"
cpu: "700m"
requests:
memory: "200Mi"
cpu: "700m"
Podをqos-example Namespace に作成します。
kubectl create namespace qos-example
kubectl create -f https://k8s.io/examples/pods/qos/qos-pod-5.yaml
このPodは保証QoSクラスに区分され、700mのCPU、200Miのメモリを要求します。
Podの詳細な情報を見てみましょう。
kubectl get pod qos-demo-5 --output=yaml --namespace=qos-example
resizePolicy[*].restartPolicyの値がデフォルトのNotRequiredになっていることに気づいたでしょうか。
これはCPUとメモリがコンテナ稼働中にリサイズできることを示しています。
spec:
containers:
...
resizePolicy:
- resourceName: cpu
restartPolicy: NotRequired
- resourceName: memory
restartPolicy: NotRequired
resources:
limits:
cpu: 700m
memory: 200Mi
requests:
cpu: 700m
memory: 200Mi
...
containerStatuses:
...
name: qos-demo-ctr-5
ready: true
...
allocatedResources:
cpu: 700m
memory: 200Mi
resources:
limits:
cpu: 700m
memory: 200Mi
requests:
cpu: 700m
memory: 200Mi
restartCount: 0
started: true
...
qosClass: Guaranteed
Podのリソースを更新する
要求CPUを0.8CPUに増やしてみます。 これは手動でも指定できますし、VerticalPodAutoscaler(VPA)などを用いて自動的に検出/適用することもできます。
備考:
Podのリソース要求やリソース制限を変更して希望の容量に合わせることはできますが、Pod作成時に指定したQoSクラスを変更することはできません。PodのContainerのCPU要求とCPU制限をいずれも800mに指定するパッチを当ててみます。
kubectl -n qos-example patch pod qos-demo-5 --patch '{"spec":{"containers":[{"name":"qos-demo-ctr-5", "resources":{"requests":{"cpu":"800m"}, "limits":{"cpu":"800m"}}}]}}'
Podへのパッチが当たったら、Podの詳細情報を参照してみましょう。
kubectl get pod qos-demo-5 --output=yaml --namespace=qos-example
以下のPod仕様は更新済みのCPU要求とCPU制限を反映しています。
spec:
containers:
...
resources:
limits:
cpu: 800m
memory: 200Mi
requests:
cpu: 800m
memory: 200Mi
...
containerStatuses:
...
allocatedResources:
cpu: 800m
memory: 200Mi
resources:
limits:
cpu: 800m
memory: 200Mi
requests:
cpu: 800m
memory: 200Mi
restartCount: 0
started: true
期待する新しいCPU要求を反映する形で allocatedResources の値が更新されていることを確認しておきましょう。
これはノードがCPUリソースの追加要求に対応できたことを示しています。
Containerの状態においてはCPUリソースの値が更新されており、新しいCPUリソースが適用されたことを示しています。
ContainerのrestartCountは変化しておらず、コンテナのCPUリソースがコンテナの再起動なしで変更されたことを示しています。
クリーンアップ
名前空間を削除しましょう。
kubectl delete namespace qos-example
次の項目
アプリケーション開発者向け
クラスター管理者向け
5 - PodにQuality of Serviceを設定する
このページでは、特定のQuality of Service (QoS)クラスをPodに割り当てるための設定方法を示します。Kubernetesは、Podのスケジューリングおよび退役を決定するためにQoSクラスを用います。
始める前に
Kubernetesクラスターが必要、かつそのクラスターと通信するためにkubectlコマンドラインツールが設定されている必要があります。 このチュートリアルは、コントロールプレーンのホストとして動作していない少なくとも2つのノードを持つクラスターで実行することをおすすめします。 まだクラスターがない場合、minikubeを使って作成するか、 以下のいずれかのKubernetesプレイグラウンドも使用できます:
バージョンを確認するには次のコマンドを実行してください: kubectl version.
QoSクラス
KubernetesはPodの作成時に次のいずれかのQoSクラスをPodに割り当てます:
- Guaranteed
- Burstable
- BestEffort
namespaceの作成
この演習で作成するリソースがクラスター内で分離されるよう、namespaceを作成します。
kubectl create namespace qos-example
GuaranteedのQoSクラスを割り当てたPodを作成する
PodにGuaranteedのQoSクラスを与えるには、以下が必要になります:
- Pod内のすべてのコンテナにメモリーの制限と要求が与えられており、同じ値であること。
- Pod内のすべてのコンテナにCPUの制限と要求が与えられており、同じ値であること。
以下に1つのコンテナをもつPodの設定ファイルを示します。コンテナには200MiBのメモリー制限とリクエストを与え、700ミリCPUの制限と要求を与えます。
apiVersion: v1
kind: Pod
metadata:
name: qos-demo
namespace: qos-example
spec:
containers:
- name: qos-demo-ctr
image: nginx
resources:
limits:
memory: "200Mi"
cpu: "700m"
requests:
memory: "200Mi"
cpu: "700m"
Podを作成してください:
kubectl apply -f https://k8s.io/examples/pods/qos/qos-pod.yaml --namespace=qos-example
Podの詳細な情報を確認してください:
kubectl get pod qos-demo --namespace=qos-example --output=yaml
この出力では、KubernetesがPodにGuaranteed QoSクラスを与えたことを示しています。Podのコンテナにメモリー制限と一致するメモリー要求があり、CPU制限と一致するCPU要求があることも確認できます。
spec:
containers:
...
resources:
limits:
cpu: 700m
memory: 200Mi
requests:
cpu: 700m
memory: 200Mi
...
status:
qosClass: Guaranteed
備考:
コンテナにメモリー制限を指定し、メモリー要求を指定していない場合は、Kubernetesは自動的にメモリー制限と一致するメモリー要求を割り当てます。同様に、コンテナにCPU制限を指定し、CPU要求を指定していない場合は、Kubernetesは自動的にCPU制限と一致するCPU要求を割り当てます。Podを削除してください:
kubectl delete pod qos-demo --namespace=qos-example
BurstableのQoSクラスを割り当てたPodを作成する
次のような場合に、Burstable QoSクラスがPodに与えられます:
- PodがGuaranteed QoSクラスの基準に満たない場合。
- Pod内の1つ以上のコンテナがメモリーまたはCPUの要求を与えられている場合。
以下に1つのコンテナをもつPodの設定ファイルを示します。コンテナには200MiBのメモリー制限と100MiBのメモリー要求を与えます。
apiVersion: v1
kind: Pod
metadata:
name: qos-demo-2
namespace: qos-example
spec:
containers:
- name: qos-demo-2-ctr
image: nginx
resources:
limits:
memory: "200Mi"
requests:
memory: "100Mi"
Podを作成してください:
kubectl apply -f https://k8s.io/examples/pods/qos/qos-pod-2.yaml --namespace=qos-example
Podの詳細な情報を確認してください:
kubectl get pod qos-demo-2 --namespace=qos-example --output=yaml
この出力では、KubernetesがPodにBurstable QoSクラスを与えたことを示しています。
spec:
containers:
- image: nginx
imagePullPolicy: Always
name: qos-demo-2-ctr
resources:
limits:
memory: 200Mi
requests:
memory: 100Mi
...
status:
qosClass: Burstable
Podを削除してください:
kubectl delete pod qos-demo-2 --namespace=qos-example
BestEffortのQoSクラスを割り当てたPodを作成する
PodにBestEffort QoSクラスを与えるには、Pod内のコンテナにはメモリーやCPUの制限や要求を指定してはなりません。
以下に1つのコンテナをもつPodの設定ファイルを示します。コンテナにはメモリーやCPUの制限や要求がありません:
apiVersion: v1
kind: Pod
metadata:
name: qos-demo-3
namespace: qos-example
spec:
containers:
- name: qos-demo-3-ctr
image: nginx
Podを作成してください:
kubectl apply -f https://k8s.io/examples/pods/qos/qos-pod-3.yaml --namespace=qos-example
Podの詳細な情報を確認してください:
kubectl get pod qos-demo-3 --namespace=qos-example --output=yaml
この出力では、KubernetesがPodにBestEffort QoSクラスを与えたことを示しています。
spec:
containers:
...
resources: {}
...
status:
qosClass: BestEffort
Podを削除してください:
kubectl delete pod qos-demo-3 --namespace=qos-example
2つのコンテナを含むPodを作成する
以下に2つのコンテナをもつPodの設定ファイルを示します。一方のコンテナは200MiBのメモリー要求を指定し、もう一方のコンテナには要求や制限を指定しません。
apiVersion: v1
kind: Pod
metadata:
name: qos-demo-4
namespace: qos-example
spec:
containers:
- name: qos-demo-4-ctr-1
image: nginx
resources:
requests:
memory: "200Mi"
- name: qos-demo-4-ctr-2
image: redis
このPodがBurstable QoSクラスの基準を満たしていることに注目してください。つまり、Guaranteed QoSクラスの基準に満たしておらず、一方のコンテナにはメモリー要求を与えられています。
Podを作成してください:
kubectl apply -f https://k8s.io/examples/pods/qos/qos-pod-4.yaml --namespace=qos-example
Podの詳細な情報を確認してください:
kubectl get pod qos-demo-4 --namespace=qos-example --output=yaml
この出力では、KubernetesがPodにBurstable QoSクラスを与えたことを示しています:
spec:
containers:
...
name: qos-demo-4-ctr-1
resources:
requests:
memory: 200Mi
...
name: qos-demo-4-ctr-2
resources: {}
...
status:
qosClass: Burstable
Podを削除してください:
kubectl delete pod qos-demo-4 --namespace=qos-example
クリーンアップ
namespaceを削除してください:
kubectl delete namespace qos-example
次の項目
アプリケーション開発者向け
クラスター管理者向け
6 - 拡張リソースをコンテナに割り当てる
このページでは、拡張リソースをコンテナに割り当てる方法について説明します。
始める前に
Kubernetesクラスターが必要、かつそのクラスターと通信するためにkubectlコマンドラインツールが設定されている必要があります。 このチュートリアルは、コントロールプレーンのホストとして動作していない少なくとも2つのノードを持つクラスターで実行することをおすすめします。 まだクラスターがない場合、minikubeを使って作成するか、 以下のいずれかのKubernetesプレイグラウンドも使用できます:
バージョンを確認するには次のコマンドを実行してください: kubectl version.
この練習を始める前に、Nodeに拡張リソースをアドバタイズするの練習を行ってください。これにより、Nodeの1つがドングルリソースをアドバタイズするように設定されます。
拡張リソースをPodに割り当てる
拡張リソースをリクエストするには、コンテナのマニフェストにresources:requestsフィールドを含めます。拡張リソースは、*.kubernetes.io/以外の任意のドメインで完全修飾されます。有効な拡張リソース名は、example.com/fooという形式になります。ここで、example.comはあなたの組織のドメインで、fooは記述的なリソース名で置き換えます。
1つのコンテナからなるPodの構成ファイルを示します。
apiVersion: v1
kind: Pod
metadata:
name: extended-resource-demo
spec:
containers:
- name: extended-resource-demo-ctr
image: nginx
resources:
requests:
example.com/dongle: 3
limits:
example.com/dongle: 3
構成ファイルでは、コンテナが3つのdongleをリクエストしていることがわかります。
次のコマンドでPodを作成します。
kubectl apply -f https://k8s.io/examples/pods/resource/extended-resource-pod.yaml
Podが起動したことを確認します。
kubectl get pod extended-resource-demo
Podの説明を表示します。
kubectl describe pod extended-resource-demo
dongleのリクエストが表示されます。
Limits:
example.com/dongle: 3
Requests:
example.com/dongle: 3
2つ目のPodの作成を試みる
以下に、1つのコンテナを持つPodの構成ファイルを示します。コンテナは2つのdongleをリクエストします。
apiVersion: v1
kind: Pod
metadata:
name: extended-resource-demo-2
spec:
containers:
- name: extended-resource-demo-2-ctr
image: nginx
resources:
requests:
example.com/dongle: 2
limits:
example.com/dongle: 2
Kubernetesは、2つのdongleのリクエストを満たすことができません。1つ目のPodが、利用可能な4つのdongleのうち3つを使用してしまっているためです。
Podを作成してみます。
kubectl apply -f https://k8s.io/examples/pods/resource/extended-resource-pod-2.yaml
Podの説明を表示します。
kubectl describe pod extended-resource-demo-2
出力にはPodがスケジュールできないことが示されます。2つのdongleが利用できるNodeが存在しないためです。
Conditions:
Type Status
PodScheduled False
...
Events:
...
... Warning FailedScheduling pod (extended-resource-demo-2) failed to fit in any node
fit failure summary on nodes : Insufficient example.com/dongle (1)
Podのステータスを表示します。
kubectl get pod extended-resource-demo-2
出力には、Podは作成されたものの、Nodeにスケジュールされなかったことが示されています。PodはPending状態になっています。
NAME READY STATUS RESTARTS AGE
extended-resource-demo-2 0/1 Pending 0 6m
クリーンアップ
この練習で作成したPodを削除します。
kubectl delete pod extended-resource-demo
kubectl delete pod extended-resource-demo-2
次の項目
アプリケーション開発者向け
クラスター管理者向け
7 - ストレージにボリュームを使用するPodを構成する
このページでは、ストレージにボリュームを使用するPodを構成する方法を示します。
コンテナのファイルシステムは、コンテナが存在する間のみ存続します。 そのため、コンテナが終了して再起動すると、ファイルシステムの変更は失われます。 コンテナに依存しない、より一貫したストレージを実現するには、ボリュームを使用できます。 これは、キーバリューストア(Redisなど)やデータベースなどのステートフルアプリケーションにとって特に重要です。
始める前に
Kubernetesクラスターが必要、かつそのクラスターと通信するためにkubectlコマンドラインツールが設定されている必要があります。 このチュートリアルは、コントロールプレーンのホストとして動作していない少なくとも2つのノードを持つクラスターで実行することをおすすめします。 まだクラスターがない場合、minikubeを使って作成するか、 以下のいずれかのKubernetesプレイグラウンドも使用できます:
バージョンを確認するには次のコマンドを実行してください: kubectl version.
Podのボリュームを構成する
この演習では、1つのコンテナを実行するPodを作成します。 今回作成するPodには、コンテナが終了して再起動した場合でもPodの寿命が続くemptyDirタイプのボリュームがあります。 これがPodの設定ファイルです:
apiVersion: v1
kind: Pod
metadata:
name: redis
spec:
containers:
- name: redis
image: redis
volumeMounts:
- name: redis-storage
mountPath: /data/redis
volumes:
- name: redis-storage
emptyDir: {}
-
Podを作成します:
kubectl apply -f https://k8s.io/examples/pods/storage/redis.yaml -
Podのコンテナが実行されていることを確認し、Podへの変更を監視します:
kubectl get pod redis --watch出力は次のようになります:
NAME READY STATUS RESTARTS AGE redis 1/1 Running 0 13s -
別のターミナルで、実行中のコンテナへのシェルを取得します:
kubectl exec -it redis -- /bin/bash -
シェルで、
/data/redisに移動し、ファイルを作成します:root@redis:/data# cd /data/redis/ root@redis:/data/redis# echo Hello > test-file -
シェルで、実行中のプロセスを一覧表示します:
root@redis:/data/redis# apt-get update root@redis:/data/redis# apt-get install procps root@redis:/data/redis# ps aux出力はこのようになります:
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND redis 1 0.1 0.1 33308 3828 ? Ssl 00:46 0:00 redis-server *:6379 root 12 0.0 0.0 20228 3020 ? Ss 00:47 0:00 /bin/bash root 15 0.0 0.0 17500 2072 ? R+ 00:48 0:00 ps aux -
シェルで、Redisプロセスを終了します:
root@redis:/data/redis# kill <pid>ここで
<pid>はRedisプロセスID(PID)です。 -
元の端末で、Redis Podへの変更を監視します。最終的には、このようなものが表示されます:
NAME READY STATUS RESTARTS AGE redis 1/1 Running 0 13s redis 0/1 Completed 0 6m redis 1/1 Running 1 6m
この時点で、コンテナは終了して再起動しました。
これは、Redis PodのrestartPolicyがAlwaysであるためです。
-
再起動されたコンテナへのシェルを取得します:
kubectl exec -it redis -- /bin/bash -
シェルで
/data/redisに移動し、test-fileがまだ存在することを確認します。root@redis:/data/redis# cd /data/redis/ root@redis:/data/redis# ls test-file -
この演習用に作成したPodを削除します:
kubectl delete pod redis
次の項目
8 - ストレージにProjectedボリュームを使用するようPodを設定する
このページでは、projected(投影)ボリュームを使用して、既存の複数のボリュームソースを同一ディレクトリ内にマウントする方法を説明します。
現在、secret、configMap、downwardAPIおよびserviceAccountTokenボリュームを投影できます。
備考:
serviceAccountTokenはボリュームタイプではありません。始める前に
Kubernetesクラスターが必要、かつそのクラスターと通信するためにkubectlコマンドラインツールが設定されている必要があります。 このチュートリアルは、コントロールプレーンのホストとして動作していない少なくとも2つのノードを持つクラスターで実行することをおすすめします。 まだクラスターがない場合、minikubeを使って作成するか、 以下のいずれかのKubernetesプレイグラウンドも使用できます:
バージョンを確認するには次のコマンドを実行してください: kubectl version.
ProjectedボリュームをPodに設定する
この課題では、ローカルファイルからユーザーネームおよびパスワードのSecretを作成します。
次に、単一のコンテナを実行するPodを作成し、projectedボリュームを使用してそれぞれのSecretを同じ共有ディレクトリにマウントします。
以下にPodの設定ファイルを示します:
apiVersion: v1
kind: Pod
metadata:
name: test-projected-volume
spec:
containers:
- name: test-projected-volume
image: busybox
args:
- sleep
- "86400"
volumeMounts:
- name: all-in-one
mountPath: "/projected-volume"
readOnly: true
volumes:
- name: all-in-one
projected:
sources:
- secret:
name: user
- secret:
name: pass
-
Secretを作成します:
# ユーザーネームおよびパスワードを含むファイルを作成します: echo -n "admin" > ./username.txt echo -n "1f2d1e2e67df" > ./password.txt # これらのファイルからSecretを作成します: kubectl create secret generic user --from-file=./username.txt kubectl create secret generic pass --from-file=./password.txt -
Podを作成します:
kubectl apply -f https://k8s.io/examples/pods/storage/projected.yaml -
Pod内のコンテナが実行されていることを確認するため、Podの変更を監視します:
kubectl get --watch pod test-projected-volume出力は次のようになります:
NAME READY STATUS RESTARTS AGE test-projected-volume 1/1 Running 0 14s -
別の端末にて、実行中のコンテナへのシェルを取得します:
kubectl exec -it test-projected-volume -- /bin/sh -
シェル内にて、投影されたソースを含む
projected-volumeディレクトリが存在することを確認します:ls /projected-volume/
クリーンアップ
PodおよびSecretを削除します:
kubectl delete pod test-projected-volume
kubectl delete secret user pass
次の項目
projectedボリュームについてさらに学ぶ- all-in-oneボリュームのデザインドキュメントを読む
9 - Podとコンテナにセキュリティコンテキストを設定する
セキュリティコンテキストはPod・コンテナの特権やアクセスコントロールの設定を定義します。 セキュリティコンテキストの設定には以下のものが含まれますが、これらに限定はされません。
-
任意アクセス制御: user ID (UID) と group ID (GID)に基づいて、ファイルなどのオブジェクトに対する許可を行います。
-
Security Enhanced Linux (SELinux): オブジェクトにセキュリティラベルを付与します。
-
特権または非特権として実行します。
-
Linux Capabilities: rootユーザーのすべての特権ではなく、一部の特権をプロセスに与えます。
-
AppArmor: プロファイルを用いて、個々のプログラムのcapabilityを制限します。
-
Seccomp: プロセスのシステムコールを限定します。
-
allowPrivilegeEscalation: あるプロセスが親プロセスよりも多くの特権を得ることができるかを制御します。 この真偽値は、コンテナプロセスにno_new_privsフラグが設定されるかどうかを直接制御します。 コンテナが以下の場合、allowPrivilegeEscalationは常にtrueになります。- コンテナが特権で動いている
CAP_SYS_ADMINを持っている
-
readOnlyRootFilesystem: コンテナのルートファイルシステムが読み取り専用でマウントされます。
上記の項目は全てのセキュリティコンテキスト設定を記載しているわけではありません。 より広範囲なリストはSecurityContextを確認してください。
始める前に
Kubernetesクラスターが必要、かつそのクラスターと通信するためにkubectlコマンドラインツールが設定されている必要があります。 このチュートリアルは、コントロールプレーンのホストとして動作していない少なくとも2つのノードを持つクラスターで実行することをおすすめします。 まだクラスターがない場合、minikubeを使って作成するか、 以下のいずれかのKubernetesプレイグラウンドも使用できます:
バージョンを確認するには次のコマンドを実行してください: kubectl version.
Podにセキュリティコンテキストを設定する
Podにセキュリティ設定を行うには、Podの設定にsecurityContextフィールドを追加してください。
securityContextフィールドはPodSecurityContextオブジェクトが入ります。
Podに設定したセキュリティ設定はPod内の全てのコンテナに適用されます。こちらはsecurityContextとemptyDirボリュームを持ったPodの設定ファイルです。
apiVersion: v1
kind: Pod
metadata:
name: security-context-demo
spec:
securityContext:
runAsUser: 1000
runAsGroup: 3000
fsGroup: 2000
supplementalGroups: [4000]
volumes:
- name: sec-ctx-vol
emptyDir: {}
containers:
- name: sec-ctx-demo
image: busybox:1.28
command: [ "sh", "-c", "sleep 1h" ]
volumeMounts:
- name: sec-ctx-vol
mountPath: /data/demo
securityContext:
allowPrivilegeEscalation: false設定ファイルの中のrunAsUserフィールドは、Pod内のコンテナに対して全てのプロセスをユーザーID 1000で実行するように指定します。
runAsGroupフィールドはPod内のコンテナに対して全てのプロセスをプライマリーグループID 3000で実行するように指定します。このフィールドが省略されたときは、コンテナのプライマリーグループIDはroot(0)になります。runAsGroupが指定されている場合、作成されたファイルもユーザー1000とグループ3000の所有物になります。
またfsGroupも指定されているため、全てのコンテナ内のプロセスは補助グループID 2000にも含まれます。/data/demoボリュームとこのボリュームに作成されたファイルはグループID 2000になります。加えて、supplementalGroupsフィールドが指定されている場合、全てのコンテナ内のプロセスは指定されている補助グループIDにも含まれます。もしこのフィールドが指定されていない場合、空を意味します。
Podを作成してみましょう。
kubectl apply -f https://k8s.io/examples/pods/security/security-context.yaml
Podのコンテナが実行されていることを確認します。
kubectl get pod security-context-demo
実行中のコンテナでshellを取ります。
kubectl exec -it security-context-demo -- sh
shellで、実行中のプロセスの一覧を確認します。
ps
runAsUserで指定した値である、ユーザー1000でプロセスが実行されていることが確認できます。
PID USER TIME COMMAND
1 1000 0:00 sleep 1h
6 1000 0:00 sh
...
shellで/dataに入り、ディレクトリの一覧を確認します。
cd /data
ls -l
fsGroupで指定した値であるグループID 2000で/data/demoディレクトリが作成されていることが確認できます。
drwxrwsrwx 2 root 2000 4096 Jun 6 20:08 demo
shellで/data/demoに入り、ファイルを作成します。
cd demo
echo hello > testfile
/data/demoディレクトリでファイルの一覧を確認します。
ls -l
fsGroupで指定した値であるグループID 2000でtestfileが作成されていることが確認できます。
-rw-r--r-- 1 1000 2000 6 Jun 6 20:08 testfile
以下のコマンドを実行してください。
id
出力はこのようになります。
uid=1000 gid=3000 groups=2000,3000,4000
出力からrunAsGroupフィールドと同じくgidが3000になっていることが確認できるでしょう。runAsGroupが省略された場合、gidは0(root)になり、そのプロセスはグループroot(0)とグループroot(0)に必要なグループパーミッションを持つグループが所有しているファイルを操作することができるようになります。また、groupsの出力に、gidに加えて、fsGroups、supplementalGroupsフィールドで指定したグループIDも含まれていることも確認できるでしょう。
shellから抜けましょう。
exit
コンテナイメージ内の/etc/groupから暗黙的にマージされるグループ情報
Kubernetesは、デフォルトでは、Podで定義された情報に加えて、コンテナイメージ内の/etc/groupのグループ情報をマージします。
apiVersion: v1
kind: Pod
metadata:
name: security-context-demo
spec:
securityContext:
runAsUser: 1000
runAsGroup: 3000
supplementalGroups: [4000]
containers:
- name: sec-ctx-demo
image: registry.k8s.io/e2e-test-images/agnhost:2.45
command: [ "sh", "-c", "sleep 1h" ]
securityContext:
allowPrivilegeEscalation: false
このPodはsecurity contextでrunAsUser、runAsGroup、supplementalGroupsフィールドが指定されています。しかし、コンテナ内のプロセスには、コンテナイメージ内の/etc/groupに定義されたグループIDが、補助グループとして付与されていることが確認できるでしょう。
Podを作成してみましょう。
kubectl apply -f https://k8s.io/examples/pods/security/security-context-5.yaml
Podのコンテナが実行されていることを確認します。
kubectl get pod security-context-demo
実行中のコンテナでshellを取ります。
kubectl exec -it security-context-demo -- sh
プロセスのユーザー、グループ情報を確認します。
id
出力はこのようになります。
uid=1000 gid=3000 groups=3000,4000,50000
groupsにグループID50000が含まれていることが確認できるでしょう。これは、ユーザー(uid=1000)がコンテナイメージで定義されており、コンテナイメージ内の/etc/groupでグループ(gid=50000)に所属しているためです。
コンテナイメージの/etc/groupの内容を確認してみましょう。
cat /etc/group
ユーザー1000がグループ50000に所属していることが確認できるでしょう。
...
user-defined-in-image:x:1000:
group-defined-in-image:x:50000:user-defined-in-image
shellから抜けましょう。
exit
備考:
暗黙的にマージされる 補助グループはボリュームアクセスを行う際にセキュリティ上の懸念を引き起こすことがあります(詳細はkubernetes/kubernetes#112879を参照してください)。回避したい場合、次節を参照してください。Podにfine-grained(きめ細かい) SupplementalGroups controlを設定する
この機能はkubeletとkube-apiserverにSupplementalGroupsPolicy
フィーチャーゲートを設定し、Podの.spec.securityContext.supplementalGroupsPolicyフィールドを指定することで利用できます。
supplementalGroupsPolicyフィールドは、Pod内のコンテナプロセスに付与される補助グループを、どのように決定するかを定義します。有効な値は次の2つです。
-
Merge:/etc/groupで定義されている、コンテナのプライマリユーザーが所属するグループをマージします。指定されていない場合、このポリシーがデフォルトです。 -
Strict:fsGroup、supplementalGroups、runAsGroupフィールドで指定されたグループのみ補助グループに指定されます。つまり、/etc/groupで定義された、コンテナのプライマリユーザーのグループ情報はマージされません。
この機能が有効な場合、.status.containerStatuses[].user.linuxフィールドで、コンテナの最初のプロセスに付与されたユーザー、グループ情報が確認出来ます。暗黙的なグループIDが付与されているかどうかを確認するのに便利でしょう。
apiVersion: v1
kind: Pod
metadata:
name: security-context-demo
spec:
securityContext:
runAsUser: 1000
runAsGroup: 3000
supplementalGroups: [4000]
supplementalGroupsPolicy: Strict
containers:
- name: sec-ctx-demo
image: registry.k8s.io/e2e-test-images/agnhost:2.45
command: [ "sh", "-c", "sleep 1h" ]
securityContext:
allowPrivilegeEscalation: false
このPodマニフェストはsupplementalGroupsPolicy=Strictを指定しています。/etc/groupに定義されているグループ情報が、コンテナ内のプロセスの補助グループにマージされないことが確認できるでしょう。
Podを作成してみましょう。
kubectl apply -f https://k8s.io/examples/pods/security/security-context-6.yaml
Podのコンテナが実行されていることを確認します。
kubectl get pod security-context-demo
プロセスのユーザー、グループ情報を確認します。
kubectl exec -it security-context-demo -- id
出力はこのようになります。
uid=1000 gid=3000 groups=3000,4000
Podのステータスを確認します。
kubectl get pod security-context-demo -o yaml
status.containerStatuses[].user.linuxフィールドでコンテナの最初のプロセスに付与されたユーザー、グループ情報が確認出来ます。
...
status:
containerStatuses:
- name: sec-ctx-demo
user:
linux:
gid: 3000
supplementalGroups:
- 3000
- 4000
uid: 1000
...
備考:
status.containerStatuses[].user.linuxフィールドで公開されているユーザー、グループ情報は、コンテナの最初のプロセスに、最初に付与された 情報であることに注意してください。
もしそのプロセスが、自身のユーザー、グループ情報を変更できるシステムコール(例えば setuid(2),
setgid(2),
setgroups(2)等)を実行する権限を持っている場合、プロセス自身で動的に変更が可能なためです。
つまり、実際にプロセスに付与されているユーザー、グループ情報は動的に変化します。利用可能な実装
下記のコンテナランタイムがfine-grained(きめ細かい) SupplementalGroups controlを実装しています。
CRI実装:
- containerd v2.0以降
- CRI-O v1.31以降
ノードのステータスでこの機能が利用可能かどうか確認出来ます。
apiVersion: v1
kind: Node
...
status:
features:
supplementalGroupsPolicy: true
備考:
アルファリリース(v1.31, v1.32)では、SupplementalGroupsPolicy=Strictを指定されたPodが、この機能をサポートされていないノード(.status.features.supplementalGroupsPolicy=falseなノード)にスケジュールされた場合、そのPodのSupplementalGroupsPolicyはMergeに暗黙的にフォールバックされていました。
しかし、ベータリリース(v1.33)以降は、ポリシーをより厳格に強制するため、そのようなPodの作成は、ノードによるポリシーの強制が不可能なためkubeletによって拒否されます。Podの作成が拒否された場合、下記のようなreason=SupplementalGroupsPolicyNotSupportedを持つWarningイベントが作成されます。
apiVersion: v1
kind: Event
...
type: Warning
reason: SupplementalGroupsPolicyNotSupported
message: "SupplementalGroupsPolicy=Strict is not supported in this node"
involvedObject:
apiVersion: v1
kind: Pod
...
Podのボリュームパーミッションと所有権変更ポリシーを設定する
デフォルトでは、Kubernetesはボリュームがマウントされたときに、PodのsecurityContextで指定されたfsGroupに合わせて再帰的に各ボリュームの中の所有権とパーミッションを変更します。
大きなボリュームでは所有権の確認と変更に時間がかかり、Podの起動が遅くなります。
securityContextの中のfsGroupChangePolicyフィールドを設定することで、Kubernetesがボリュームの所有権・パーミッションの確認と変更をどう行うかを管理することができます。
fsGroupChangePolicy - fsGroupChangePolicyは、ボリュームがPod内部で公開される前に所有権とパーミッションを変更するための動作を定義します。
このフィールドはfsGroupで所有権とパーミッションを制御することができるボリュームタイプにのみ適用されます。このフィールドは以下の2つの値を取ります。
- OnRootMismatch: ルートディレクトリのパーミッションと所有権がボリュームに設定したパーミッションと一致しない場合のみ、パーミッションと所有権を変更します。ボリュームの所有権とパーミッションを変更するのにかかる時間が短くなる可能性があります。
- Always: ボリュームがマウントされたときに必ずパーミッションと所有権を変更します。
例:
securityContext:
runAsUser: 1000
runAsGroup: 3000
fsGroup: 2000
fsGroupChangePolicy: "OnRootMismatch"
CSIドライバーにボリュームパーミッションと所有権を移譲する
VOLUME_MOUNT_GROUP NodeServiceCapabilityをサポートしているContainer Storage Interface (CSI)ドライバーをデプロイした場合、securityContextのfsGroupで指定された値に基づいてKubernetesの代わりにCSIドライバーがファイルの所有権とパーミッションの設定処理を行います。
この場合Kubernetesは所有権とパーミッションの設定を行わないためfsGroupChangePolicyは無効となり、CSIで指定されている通りドライバーはfsGroupに従ってボリュームをマウントすると考えられるため、ボリュームはfsGroupに従って読み取り・書き込み可能になります。
コンテナにセキュリティコンテキストを設定する
コンテナに対してセキュリティ設定を行うには、コンテナマニフェストにsecurityContextフィールドを含めてください。securityContextフィールドにはSecurityContextオブジェクトが入ります。
コンテナに指定したセキュリティ設定は個々のコンテナに対してのみ反映され、Podレベルの設定を上書きします。コンテナの設定はPodのボリュームに対しては影響しません。
こちらは一つのコンテナを持つPodの設定ファイルです。PodもコンテナもsecurityContextフィールドを含んでいます。
apiVersion: v1
kind: Pod
metadata:
name: security-context-demo-2
spec:
securityContext:
runAsUser: 1000
containers:
- name: sec-ctx-demo-2
image: gcr.io/google-samples/node-hello:1.0
securityContext:
runAsUser: 2000
allowPrivilegeEscalation: falsePodを作成します。
kubectl apply -f https://k8s.io/examples/pods/security/security-context-2.yaml
Podのコンテナが実行されていることを確認します。
kubectl get pod security-context-demo-2
実行中のコンテナでshellを取ります。
kubectl exec -it security-context-demo-2 -- sh
shellの中で、実行中のプロセスの一覧を表示します。
ps aux
ユーザー2000として実行されているプロセスが表示されました。これはコンテナのrunAsUserで指定された値です。Podで指定された値である1000を上書きしています。
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
2000 1 0.0 0.0 4336 764 ? Ss 20:36 0:00 /bin/sh -c node server.js
2000 8 0.1 0.5 772124 22604 ? Sl 20:36 0:00 node server.js
...
shellから抜けます。
exit
コンテナにケーパビリティを設定する
Linuxケーパビリティを用いると、プロセスに対してrootユーザーの全権を渡すことなく特定の権限を与えることができます。
コンテナに対してLinuxケーパビリティを追加したり削除したりするには、コンテナマニフェストのsecurityContextセクションのcapabilitiesフィールドに追加してください。
まず、capabilitiesフィールドを含まない場合どうなるかを見てみましょう。
こちらはコンテナに対してケーパビリティを渡していない設定ファイルです。
apiVersion: v1
kind: Pod
metadata:
name: security-context-demo-3
spec:
containers:
- name: sec-ctx-3
image: gcr.io/google-samples/node-hello:1.0Podを作成します。
kubectl apply -f https://k8s.io/examples/pods/security/security-context-3.yaml
Podが実行されていることを確認します。
kubectl get pod security-context-demo-3
実行中のコンテナでshellを取ります。
kubectl exec -it security-context-demo-3 -- sh
shellの中で、実行中のプロセスの一覧を表示します。
ps aux
コンテナのプロセスID(PID)が出力されます。
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.0 4336 796 ? Ss 18:17 0:00 /bin/sh -c node server.js
root 5 0.1 0.5 772124 22700 ? Sl 18:17 0:00 node server.js
shellの中で、プロセス1のステータスを確認します。
cd /proc/1
cat status
プロセスのケーパビリティビットマップが表示されます。
...
CapPrm: 00000000a80425fb
CapEff: 00000000a80425fb
...
ケーパビリティビットマップのメモを取った後、shellから抜けます。
exit
次に、追加のケーパビリティを除いて上と同じ設定のコンテナを実行します。
こちらは1つのコンテナを実行するPodの設定ファイルです。
CAP_NET_ADMINとCAP_SYS_TIMEケーパビリティを設定に追加しました。
apiVersion: v1
kind: Pod
metadata:
name: security-context-demo-4
spec:
containers:
- name: sec-ctx-4
image: gcr.io/google-samples/node-hello:1.0
securityContext:
capabilities:
add: ["NET_ADMIN", "SYS_TIME"]Podを作成します。
kubectl apply -f https://k8s.io/examples/pods/security/security-context-4.yaml
実行中のコンテナでshellを取ります。
kubectl exec -it security-context-demo-4 -- sh
shellの中で、プロセス1のケーパビリティを確認します。
cd /proc/1
cat status
プロセスのケーパビリティビットマップが表示されます。
...
CapPrm: 00000000aa0435fb
CapEff: 00000000aa0435fb
...
2つのコンテナのケーパビリティを比較します。
00000000a80425fb
00000000aa0435fb
1つ目のコンテナのケーパビリティビットマップでは、12, 25ビット目がクリアされています。2つ目のコンテナでは12, 25ビット目がセットされています。12ビット目はCAP_NET_ADMIN、25ビット目はCAP_SYS_TIMEです。
ケーパビリティの定数の定義はcapability.hを確認してください。
備考:
Linuxケーパビリティの定数はCAP_XXX形式です。
ただしコンテナのマニフェストでケーパビリティを記述する際は、定数のCAP_の部分を省いてください。
例えば、CAP_SYS_TIMEを追加したい場合はケーパビリティにSYS_TIMEを追加してください。コンテナにSeccompプロフィールを設定する
コンテナにSeccompプロフィールを設定するには、Pod・コンテナマニフェストのsecurityContextにseccompProfileフィールドを追加してください。
seccompProfileフィールドはSeccompProfileオブジェクトで、typeとlocalhostProfileで構成されています。
typeではRuntimeDefault、Unconfined、Localhostが有効です。
localhostProfileはtype: Localhostのときのみ指定可能です。こちらはノード上で事前に設定されたプロファイルのパスを示していて、kubeletのSeccompプロファイルの場所(--root-dirフラグで設定したもの)からの相対パスです。
こちらはノードのコンテナランタイムのデフォルトプロフィールをSeccompプロフィールとして設定した例です。
...
securityContext:
seccompProfile:
type: RuntimeDefault
こちらは<kubelet-root-dir>/seccomp/my-profiles/profile-allow.jsonで事前に設定したファイルをSeccompプロフィールに設定した例です。
...
securityContext:
seccompProfile:
type: Localhost
localhostProfile: my-profiles/profile-allow.json
コンテナにAppArmorプロフィールを設定する
コンテナにAppArmorプロフィールを設定するには、securityContextセクションにappAormorProfileフィールドを含めてください。
appAormerProfileフィールドには、typeフィールドとlocalhostProfileフィールドから構成されるAppArmorProfileオブジェクトが入ります。typeフィールドの有効なオプションはRuntimeDefault(デフォルト)、Unconfined、Localhostです。
localhostProfileはtypeがLocalhostのときには必ず設定しなければなりません。この値はノードで事前に設定されたプロフィール名を示します。Podは事前にどのノードにスケジュールされるかわからないため、指定されたプロフィールはPodがスケジュールされ得る全てのノードにロードされている必要があります。カスタムプロフィールをセットアップする方法はSetting up nodes with profilesを参照してください。
注意: containers[*].securityContext.appArmorProfile.typeが明示的にRuntimeDefaultに設定されている場合は、もしノードでAppArmorが有効化されていなければ、Podの作成は許可されません。
しかし、containers[*].securityContext.appArmorProfile.typeが設定されていない場合、AppArmorが有効化されていれば、デフォルト(RuntimeDefault)が適用されます。もし、AppArmorが無効化されている場合は、Podの作成は許可されますが、コンテナにはRuntimeDefaultプロフィールの制限は適用されません。
これは、AppArmorプロフィールとして、ノードのコンテナランタイムのデフォルトプロフィールを設定する例です。
...
containers:
- name: container-1
securityContext:
appArmorProfile:
type: RuntimeDefault
これは、AppArmorプロフィールとして、k8s-apparmor-example-deny-writeという名前で事前に設定されたプロフィールを設定する例です。
...
containers:
- name: container-1
securityContext:
appArmorProfile:
type: Localhost
localhostProfile: k8s-apparmor-example-deny-write
より詳細な内容についてはRestrict a Container's Access to Resources with AppArmorを参照してください。
コンテナにSELinuxラベルをつける
コンテナにSELinuxラベルをつけるには、Pod・コンテナマニフェストのsecurityContextセクションにseLinuxOptionsフィールドを追加してください。
seLinuxOptionsフィールドはSELinuxOptionsオブジェクトが入ります。
こちらはSELinuxレベルを適用する例です。
...
securityContext:
seLinuxOptions:
level: "s0:c123,c456"
備考:
SELinuxラベルを適用するには、ホストOSにSELinuxセキュリティモジュールが含まれている必要があります。効率的なSELinuxのボリューム再ラベル付け
More information about this feature
This is a stable feature in
備考:
Kubernetes v1.27で、ReadWriteOncePod アクセスモードを使用するボリューム(およびPersistentVolumeClaim)にのみ、この機能の限定的な機能が早期提供されています。
Alphaフィーチャーとして、SELinuxMountフィーチャーゲートを有効にすることで、以下で説明するように、他の種類のPersistentVolumeClaimにもパフォーマンス改善の範囲を広げる事ができます。
デフォルトでは、コンテナランタイムは全てのPodのボリュームの全てのファイルに再帰的にSELinuxラベルを付与します。処理速度を上げるために、Kubernetesはマウントオプションで-o context=<label>を使うことでボリュームのSELinuxラベルを即座に変更することができます。
この高速化の恩恵を受けるには、以下の全ての条件を満たす必要があります。
- Alphaフィーチャーゲートの
ReadWriteOncePodとSELinuxMountReadWriteOncePodを有効にすること - Podが適用可能な
accessModesでPersistentVolumeClaimを使うこと- ボリュームが
accessModes: ["ReadWriteOncePod"]を持ち、フィーチャーゲートSELinuxMountReadWriteOncePodが有効であること - または、ボリュームが他のアクセスモードを使用し、フィーチャーゲート
SELinuxMountReadWriteOncePodとSELinuxMountの両方が有効であること
- ボリュームが
- Pod(またはPersistentVolumeClaimを使っている全てのコンテナ)に
seLinuxOptionsが設定されていること - 対応するPersistentVolumeが以下のいずれかであること
- レガシーのin-treeボリュームの場合、
iscs、rbd、fcボリュームタイプであること - または、CSIドライバーを使用するボリュームで、そのCSIドライバーがCSIドライバーインスタンスで
spec.seLinuxMount: trueを指定したときに-o contextでマウントを行うとアナウンスしていること
- レガシーのin-treeボリュームの場合、
それ以外のボリュームタイプでは、コンテナランタイムはボリュームに含まれる全てのinode(ファイルやディレクトリ)に対してSELinuxラベルを再帰的に変更します。 ボリューム内のファイルやディレクトリが増えるほど、ラベリングにかかる時間は増加します。
/procファイルシステムへのアクセスを管理する
More information about this feature
This is a stable feature in Kubernetes, and has been since version v1.36. It was first available in the v1.12 release. You can no longer disable or opt out of this feature or behavior (it is locked); if you explicitly set a value for the associated feature gate ProcMountType, Kubernetes ignores it but does not report any error.
OCI runtime specificationに準拠するランタイムでは、コンテナはデフォルトで、いくつかの複数のパスはマスクされ、かつ、読み取り専用のモードで実行されます。 その結果、コンテナのマウントネームスペース内にはこれらのパスが存在し、あたかもコンテナが隔離されたホストであるかのように機能しますが、コンテナプロセスはそれらのパスに書き込むことはできません。 マスクされるパスおよび読み取り専用のパスのリストは次のとおりです。
-
マスクされるパス:
/proc/asound/proc/acpi/proc/kcore/proc/keys/proc/latency_stats/proc/timer_list/proc/timer_stats/proc/sched_debug/proc/scsi/sys/firmware/sys/devices/virtual/powercap
-
読み取り専用のパス:
/proc/bus/proc/fs/proc/irq/proc/sys/proc/sysrq-trigger
一部のPodでは、デフォルトでパスがマスクされるのを回避したい場合があります。このようなケースで最も一般的なのは、Kubernetesコンテナ(Pod内のコンテナ)内でコンテナを実行しようとする場合です。
securityContextのprocMountフィールドを使用すると、コンテナの/procをUnmaskedにしたり、コンテナプロセスによって読み書き可能な状態でマウントすることができます。この設定は、/proc以外の/sys/firmwareにも適用されます。
...
securityContext:
procMount: Unmasked
備考:
procMountをUnmaskedに設定するには、Podのspec.hostUsersの値がfalseである必要があります。
つまり、Unmaskedな/procやUnmaskedな/sysを使用したいコンテナは、user namespace内で動作している必要があります。
Kubernetes v1.12からv1.29までは、この要件は強制されません。議論
PodのセキュリティコンテキストはPodのコンテナや、適用可能であればPodのボリュームに対しても適用されます。
特にfsGroupとseLinuxOptionsは以下のようにボリュームに対して適用されます。
-
fsGroup: 所有権管理をサポートしているボリュームはfsGroupで指定されているGIDで所有権・書き込み権限が設定されます。詳しくはOwnership Management design documentを確認してください。 -
seLinuxOptions: SELinuxラベリングをサポートしているボリュームではseLinuxOptionsで指定されているラベルでアクセス可能になるように貼り直されます。通常、levelセクションのみ設定する必要があります。 これはPod内の全てのボリュームとコンテナに対しMulti-Category Security (MCS)ラベルを設定します。
警告:
Podに対してMCSラベルを指定すると、同じラベルを持つ全てのPodがボリュームにアクセスすることができます。 Pod内の保護が必要な場合、それぞれのPodに対して一意なMCSラベルを割り当ててください。クリーンアップ
Podを削除します。
kubectl delete pod security-context-demo
kubectl delete pod security-context-demo-2
kubectl delete pod security-context-demo-3
kubectl delete pod security-context-demo-4
次の項目
- PodSecurityContext
- SecurityContext
- 最新の強化されたセキュリティでDockerを調整する
- Security Contexts design document
- Ownership Management design document
- PodSecurity Admission
- AllowPrivilegeEscalation design document
- Linuxのセキュリティについてさらに知りたい場合は、Overview of Linux Kernel Security Featuresを確認してください(注: 一部の情報は古くなっています)。
- Linux pods向けのUser Namespacesについて確認してください。
- Masked Paths in the OCI Runtime Specification
10 - Podにサービスアカウントを設定する
Kubernetesは、クラスター内で実行されるクライアント、またはクラスターのコントロールプレーンと何らかの関係を持つクライアントが、APIサーバーに対して認証を行うために、2つの異なる方法を提供しています。
サービスアカウント は、Pod内で実行されるプロセスにアイデンティティを提供し、ServiceAccountオブジェクトにマッピングされます。 APIサーバーに対して認証を行う際、あなたは特定の ユーザー として自分自身を識別します。 Kubernetesはユーザーという概念を認識していますが、Kubernetes自体はUser APIを持っていません。
このタスクガイドでは、Kubernetes APIに存在するServiceAccountについて説明します。 このガイドでは、PodにServiceAccountを設定する方法をいくつか示します。
始める前に
Kubernetesクラスターが必要、かつそのクラスターと通信するためにkubectlコマンドラインツールが設定されている必要があります。 このチュートリアルは、コントロールプレーンのホストとして動作していない少なくとも2つのノードを持つクラスターで実行することをおすすめします。 まだクラスターがない場合、minikubeを使って作成するか、 以下のいずれかのKubernetesプレイグラウンドも使用できます:
デフォルトのサービスアカウントを使用してAPIサーバーにアクセスする
PodがAPIサーバーに接続する際、Podは特定のServiceAccount(例: default)として認証を行います。
それぞれの名前空間には、常に少なくとも1つのServiceAccountが存在します。
すべてのKubernetes名前空間には、少なくとも1つのServiceAccountが含まれています。
それは、その名前空間のデフォルトのServiceAccountであり、defaultという名前が付けられています。
Podを作成する際にServiceAccountを指定しない場合、Kubernetesは自動的にその名前空間内に、defaultという名前のServiceAccountを割り当てます。
作成したPodの詳細を取得するには、たとえば下記を実行します:
kubectl get pods/<podname> -o yaml
出力には、spec.serviceAccountNameフィールドが表示されます。
Podを作成する際にこの値を指定しない場合、Kubernetesは自動的にこの値を設定します。
Pod内で実行されているアプリケーションは、自動的にマウントされたサービスアカウントの認証情報を使用して、Kubernetes APIにアクセスできます。 詳細については、クラスターへのアクセスを参照してください。
PodがServiceAccountとして認証を行う場合、そのアクセスレベルは、使用する認可プラグインとポリシーに依存します。
ファイナライザーが設定されている場合でも、Podが削除されるとAPI認証情報は自動的に取り消されます。
具体的には、Podに設定された.metadata.deletionTimestamp(削除タイムスタンプは通常、削除リクエストが受け入れられた時刻にPodの終了猶予期間を加えた時刻です)から60秒後にAPI認証情報が取り消されます。
API認証情報の自動マウントをオプトアウトする
kubeletが、ServiceAccountのAPI認証情報を自動的にマウントしないようにしたい場合、デフォルトの挙動をオプトアウトできます。
サービスアカウントに対して、automountServiceAccountToken: falseを設定することで、/var/run/secrets/kubernetes.io/serviceaccount/tokenへのAPI認証情報の自動マウントをオプトアウトできます。
例:
apiVersion: v1
kind: ServiceAccount
metadata:
name: build-robot
automountServiceAccountToken: false
...
また、特定のPodに対してAPI認証情報の自動マウントをオプトアウトすることもできます:
apiVersion: v1
kind: Pod
metadata:
name: my-pod
spec:
serviceAccountName: build-robot
automountServiceAccountToken: false
...
ServiceAccountとPodの.specの両方がautomountServiceAccountTokenの値を指定している場合、Podの仕様が優先されます。
複数のServiceAccountを使用する
すべての名前空間には、少なくとも1つのServiceAccountが存在します。
それは、defaultという名前のデフォルトのServiceAccountリソースです。
現在の名前空間内のすべてのServiceAccountリソースを次のコマンドで一覧表示できます:
kubectl get serviceaccounts
出力は以下のようになります:
NAME SECRETS AGE
default 1 1d
次のように、追加のServiceAccountオブジェクトを作成できます:
kubectl apply -f - <<EOF
apiVersion: v1
kind: ServiceAccount
metadata:
name: build-robot
EOF
ServiceAccountオブジェクトの名前は、有効なDNSサブドメイン名である必要があります。
次のように、サービスアカウントオブジェクトの完全なダンプを取得する場合:
kubectl get serviceaccounts/build-robot -o yaml
出力は以下のようになります:
apiVersion: v1
kind: ServiceAccount
metadata:
creationTimestamp: 2019-06-16T00:12:34Z
name: build-robot
namespace: default
resourceVersion: "272500"
uid: 721ab723-13bc-11e5-aec2-42010af0021e
認可プラグインを使用して、サービスアカウントに権限を設定できます。
デフォルト以外のサービスアカウントを使用するには、Podのspec.serviceAccountNameフィールドを、使用したいServiceAccountの名前に設定します。
serviceAccountNameフィールドは、Podを作成する際、または新しいPodのテンプレート内でのみ設定できます。
既に存在するPodの.spec.serviceAccountNameフィールドは更新できません。
備考:
.spec.serviceAccountフィールドは、.spec.serviceAccountNameの非推奨のエイリアスです。
ワークロードリソースからこれらのフィールドを削除したい場合は、Podテンプレートで両方のフィールドを明示的に空に設定してください。クリーンアップ
上記の例でbuild-robot ServiceAccountを作成した場合、次のコマンドを実行してクリーンアップできます:
kubectl delete serviceaccount/build-robot
ServiceAccountのAPIトークンを手動で作成する
前述のように、「build-robot」という名前の既存のサービスアカウントがあるとします。
kubectlを使用して、そのServiceAccountの期限付きAPIトークンを取得できます:
kubectl create token build-robot
このコマンドの出力は、そのServiceAccountとして認証するために使用できるトークンです。
kubectl create tokenの--durationコマンドライン引数を使用して、特定のトークン期間を要求できます(発行されるトークンの実際の期間は短くなる場合や、長くなる場合もあります)。
More information about this feature
This is a stable feature in Kubernetes, and has been since version v1.33. It was first available in the v1.29 release. You can no longer disable or opt out of this feature or behavior (it is locked); if you explicitly set a value for the associated feature gate ServiceAccountTokenNodeBinding, Kubernetes ignores it but does not report any error.
kubectl v1.31以降を使用すると、ノードに直接バインドされたサービスアカウントトークンを作成できます:
kubectl create token build-robot --bound-object-kind Node --bound-object-name node-001 --bound-object-uid 123...456
トークンは、有効期限が切れるか、関連するノードまたはサービスアカウントが削除されるまで有効です。
備考:
Kubernetes v1.22以前のバージョンでは、Kubernetes APIにアクセスするための長期的な認証情報が自動的に作成されていました。 この古いメカニズムは、実行中のPodにマウントされるトークンSecretの作成に基づいていました。 Kubernetes v1.37を含む最近のバージョンでは、API認証情報はTokenRequest APIを使用して直接取得され、projected volumeを使用してPodにマウントされます。 この方法で取得されたトークンには有効期限があり、マウント先のPodが削除されると自動的に無効になります。
サービスアカウント用のトークンSecretを手動で作成することも可能です。 例えば、有効期限のないトークンが必要な場合などです。 ただし、APIにアクセスするためのトークンを取得するには、TokenRequestサブリソースを使用することを推奨します。
ServiceAccount用の長期間有効なAPIトークンを手動で作成する
ServiceAccount用のAPIトークンを取得したい場合は、特別なアノテーションkubernetes.io/service-account.nameを持つ新しいSecretを作成します。
kubectl apply -f - <<EOF
apiVersion: v1
kind: Secret
metadata:
name: build-robot-secret
annotations:
kubernetes.io/service-account.name: build-robot
type: kubernetes.io/service-account-token
EOF
Secretを表示するには、次のコマンドを使用します:
kubectl get secret/build-robot-secret -o yaml
Secretに「build-robot」ServiceAccount用のAPIトークンが含まれていることが確認できます。
設定したアノテーションにより、コントロールプレーンはそのServiceAccount用のトークンを自動的に生成し、関連するSecretに保存します。 また、コントロールプレーンは削除されたServiceAccount用のトークンをクリーンアップします。
kubectl describe secrets/build-robot-secret
出力は以下のようになります:
Name: build-robot-secret
Namespace: default
Labels: <none>
Annotations: kubernetes.io/service-account.name: build-robot
kubernetes.io/service-account.uid: da68f9c6-9d26-11e7-b84e-002dc52800da
Type: kubernetes.io/service-account-token
Data
====
ca.crt: 1338 bytes
namespace: 7 bytes
token: ...
備考:
tokenの内容はここでは省略されています。
ターミナルやコンピューターの画面が覗き見される可能性がある場所で、kubernetes.io/service-account-token Secretの内容を表示しないよう注意してください。
関連するSecretを持つServiceAccountを削除すると、KubernetesコントロールプレーンはそのSecretから長期的なトークンを自動的にクリーンアップします。
備考:
ServiceAccountを表示するには、次のコマンドを使用します:
kubectl get serviceaccount build-robot -o yaml
ServiceAccount APIオブジェクトの.secretsフィールドにbuild-robot-secret Secretは表示されません。
このフィールドには自動生成されたSecretのみが入力されるためです。
サービスアカウントにImagePullSecretを追加する
まず、imagePullSecretを作成します。 次に、作成されたことを確認します。 以下は、その例です:
-
PodでのImagePullSecretの指定で説明されているように、imagePullSecretを作成します。
kubectl create secret docker-registry myregistrykey --docker-server=<レジストリ名> \ --docker-username=DUMMY_USERNAME --docker-password=DUMMY_DOCKER_PASSWORD \ --docker-email=DUMMY_DOCKER_EMAIL -
作成されたことを確認します。
kubectl get secrets myregistrykey出力は以下のようになります:
NAME TYPE DATA AGE myregistrykey kubernetes.io/.dockerconfigjson 1 1d
サービスアカウントにイメージプルシークレットを追加する
次に、名前空間のデフォルトのサービスアカウントを変更して、このSecretをimagePullSecretとして使用するようにします。
kubectl patch serviceaccount default -p '{"imagePullSecrets": [{"name": "myregistrykey"}]}'
オブジェクトを手動で編集することでも同じ結果を得られます:
kubectl edit serviceaccount/default
sa.yamlファイルの出力は以下のようになります:
使用しているテキストエディターが開き、以下のような設定が表示されます:
apiVersion: v1
kind: ServiceAccount
metadata:
creationTimestamp: 2021-07-07T22:02:39Z
name: default
namespace: default
resourceVersion: "243024"
uid: 052fb0f4-3d50-11e5-b066-42010af0d7b6
エディターを使用して、resourceVersionキーが記述されている行を削除し、imagePullSecrets:の行を追加して保存します。
uidの値は変更しないでおきます。
これらの変更を行うと、編集後のServiceAccountは以下のようになります:
apiVersion: v1
kind: ServiceAccount
metadata:
creationTimestamp: 2021-07-07T22:02:39Z
name: default
namespace: default
uid: 052fb0f4-3d50-11e5-b066-42010af0d7b6
imagePullSecrets:
- name: myregistrykey
新しいPodにimagePullSecretが設定されていることを確認する
現在の名前空間に、デフォルトのServiceAccountを使用して新しいPodが作成されると、新しいPodのspec.imagePullSecretsフィールドが自動的に設定されます:
kubectl run nginx --image=<レジストリ名>/nginx --restart=Never
kubectl get pod nginx -o=jsonpath='{.spec.imagePullSecrets[0].name}{"\n"}'
出力は以下のようになります:
myregistrykey
ServiceAccountトークンボリューム投影
備考:
トークンリクエスト投影を有効化して使用するには、kube-apiserverに以下の各コマンドライン引数を指定する必要があります:
--service-account-issuer- サービスアカウントトークン発行者の識別子を定義します。
--service-account-issuer引数は複数回指定でき、発行者をダウンタイムなしで変更するのに役立ちます。 このフラグを複数回指定した場合、最初のものがトークンの生成に使用され、すべてが受け入れ可能な発行者の判定に使用されます。--service-account-issuerを複数回指定するには、Kubernetes v1.22以降を実行する必要があります。 --service-account-key-file- ServiceAccountトークンの検証に使用される、PEMエンコードされたX.509秘密鍵または公開鍵(RSAまたはECDSA)を含むファイルのパスを指定します。 指定したファイルには複数の鍵を含めることができ、フラグは異なるファイルで複数回指定できます。 複数回指定された場合、指定された鍵のいずれかで署名されたトークンは、Kubernetes APIサーバーによって有効と見なされます。
--service-account-signing-key-file- サービスアカウントトークン発行者の現在の秘密鍵を含むファイルのパスを指定します。 発行者はこの秘密鍵を使用して発行されたIDトークンに署名します。
--api-audiences(省略可能)- ServiceAccountトークンのオーディエンスを定義します。
サービスアカウントトークン認証機能は、APIに対して使用されるトークンが、これらのオーディエンスの少なくとも1つにバインドされていることを検証します。
api-audiencesを複数回指定した場合、指定したオーディエンスのいずれかに対応するトークンは、Kubernetes APIサーバーによって有効と見なされます。--service-account-issuerコマンドライン引数を指定しても--api-audiencesを設定しない場合、コントロールプレーンはデフォルトで発行者URLのみを含むオーディエンスリストを使用します。
kubeletも、ServiceAccountトークンをPodに投影できます。 トークンの望ましいプロパティ(オーディエンスや有効期間など)を指定できます。 これらのプロパティは、デフォルトのServiceAccountトークンでは設定 できません。 また、PodまたはServiceAccountのいずれかが削除されると、トークンはAPIに対して無効になります。
この挙動は、ServiceAccountTokenと呼ばれる投影ボリュームタイプを使用してPodのspecで設定できます。
この投影ボリュームのトークンはJSON Web Token(JWT)です。 このトークンのJSONペイロードは明確に定義されたスキーマに従い、以下はPodにバインドされたトークンのペイロードの例です:
{
"aud": [ # リクエストされたオーディエンス、または明示的にリクエストされない場合はAPIサーバーのデフォルトオーディエンスと一致
"https://kubernetes.default.svc"
],
"exp": 1731613413,
"iat": 1700077413,
"iss": "https://kubernetes.default.svc", # --service-account-issuerフラグに渡された最初の値と一致
"jti": "ea28ed49-2e11-4280-9ec5-bc3d1d84661a",
"kubernetes.io": {
"namespace": "kube-system",
"node": {
"name": "127.0.0.1",
"uid": "58456cb0-dd00-45ed-b797-5578fdceaced"
},
"pod": {
"name": "coredns-69cbfb9798-jv9gn",
"uid": "778a530c-b3f4-47c0-9cd5-ab018fb64f33"
},
"serviceaccount": {
"name": "coredns",
"uid": "a087d5a0-e1dd-43ec-93ac-f13d89cd13af"
},
"warnafter": 1700081020
},
"nbf": 1700077413,
"sub": "system:serviceaccount:kube-system:coredns"
}
サービスアカウントトークン投影を使用してPodを起動する
オーディエンスがvaultで、有効期間が2時間のトークンをPodに提供するには、以下のようなPodマニフェストを定義します:
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
containers:
- image: nginx
name: nginx
volumeMounts:
- mountPath: /var/run/secrets/tokens
name: vault-token
serviceAccountName: build-robot
volumes:
- name: vault-token
projected:
sources:
- serviceAccountToken:
path: vault-token
expirationSeconds: 7200
audience: vault
Podを作成します:
kubectl create -f https://k8s.io/examples/pods/pod-projected-svc-token.yaml
kubeletは、Podに代わってトークンをリクエストして保存し、設定可能なファイルパスでPodがトークンを利用できるようにします。 また、トークンの有効期限が近づくと更新します。 kubeletは、トークンの全生存時間(TTL)の80%を経過した場合、または24時間を経過した場合に、積極的にトークンのローテーションをリクエストします。
トークンがローテーションされた際にトークンを再読み込みするのは、アプリケーション側の責任です。 多くの場合、実際の有効期限を追跡しなくても、定期的に(例えば5分ごとに)トークンを読み込むだけで十分です。
サービスアカウント発行者のディスカバリ
クラスター内のServiceAccountに対してトークン投影を有効にしている場合、ディスカバリ機能も利用できます。 Kubernetesは、クライアントが アイデンティティプロバイダー として連携できる方法を提供し、1つ以上の外部システムが リライングパーティ として機能できます。
備考:
発行者URLはOIDC Discovery仕様に準拠している必要があります。
実際には、これはhttpsスキームを使用する必要があり、{service-account-issuer}/.well-known/openid-configurationでOpenIDプロバイダー設定を提供する必要があることを意味します。
URLが準拠していない場合、ServiceAccount発行者のディスカバリエンドポイントは登録されず、アクセスできません。
有効にすると、Kubernetes APIサーバーはHTTP経由でOpenIDプロバイダー設定ドキュメントを公開します。
設定ドキュメントは/.well-known/openid-configurationで公開されます。
OpenIDプロバイダー設定は、ディスカバリドキュメント と呼ばれることもあります。
Kubernetes APIサーバーは、関連するJSON Web Key Set(JWKS)もHTTP経由で/openid/v1/jwksで公開します。
備考:
/.well-known/openid-configurationや/openid/v1/jwksで提供される応答は、OIDC互換となるように設計されていますが、厳密にはOIDC準拠ではありません。
これらのドキュメントには、Kubernetesサービスアカウントトークンの検証を実行するために必要なパラメーターのみが含まれています。RBACを使用するクラスターには、system:service-account-issuer-discoveryというデフォルトのClusterRoleが含まれています。
デフォルトのClusterRoleBindingは、このロールをsystem:serviceaccountsグループに割り当てます。
すべてのServiceAccountは暗黙的にこのグループに属しています。
これにより、クラスター上で実行されているPodは、マウントされたサービスアカウントトークンを介してサービスアカウントディスカバリドキュメントにアクセスできます。
管理者は、セキュリティ要件や連携する予定の外部システムに応じて、さらにsystem:authenticatedまたはsystem:unauthenticatedにロールをバインドすることもできます。
JWKS応答には、リライングパーティがKubernetesサービスアカウントトークンを検証するために使用できる公開鍵が含まれています。
リライングパーティは、まずOpenIDプロバイダー設定をクエリし、応答内のjwks_uriフィールドを使用してJWKSを見つけます。
多くの場合、Kubernetes APIサーバーはパブリックインターネット上では利用できませんが、APIサーバーからのキャッシュされた応答を提供するパブリックエンドポイントをユーザーまたはサービスプロバイダーが利用可能にすることができます。
これらの場合、APIサーバーに--service-account-jwks-uriフラグを渡すことで、OpenIDプロバイダー設定内のjwks_uriをオーバーライドして、APIサーバーのアドレスではなくパブリックエンドポイントを指すようにすることができます。
発行者URLと同様に、JWKS URIもhttpsスキームを使用する必要があります。
次の項目
以下も参照してください:
- サービスアカウントのクラスター管理者ガイドを読む
- Kubernetesでの認可について読む
- Secretについて読む
- または、Secretを使用して認証情報を安全に配布する方法を学ぶ
- ただし、ServiceAccountとして認証するためにSecretを使用することは非推奨であることに注意してください。 推奨される代替方法はServiceAccountトークンボリューム投影です。
- 投影ボリュームについて読む
- OIDCディスカバリの背景については、Service Account signing key retrieval Kubernetes Enhancement Proposalを読む
- OIDC Discovery仕様を読む
11 - イメージをプライベートレジストリから取得する
このページでは、Secretを用いるPodを作成するためにイメージをプライベートコンテナイメージレジストリもしくはリポジトリから取得する方法について説明します。 多くのプライベートレジストリが存在しますが、このタスクではDocker Hubをレジストリの一例として使用します。
始める前に
-
Kubernetesクラスターが必要、かつそのクラスターと通信するためにkubectlコマンドラインツールが設定されている必要があります。 このチュートリアルは、コントロールプレーンのホストとして動作していない少なくとも2つのノードを持つクラスターで実行することをおすすめします。 まだクラスターがない場合、minikubeを使って作成するか、 以下のいずれかのKubernetesプレイグラウンドも使用できます:
-
この演習を行うためには、
dockerコマンドラインツールと自身のDocker IDが必要です。 -
別のプライベートコンテナレジストリを使用している場合は、そのレジストリのコマンドラインツールとログイン情報が必要です。
Docker Hubにログインする
ラップトップ(ローカル環境)上では、プライベートイメージを取得するためにレジストリに認証する必要があります。
dockerツールを使用してDocker Hubにログインしてください。詳細はDocker IDアカウントの Sign in セクションを参照してください。
docker login
プロンプトが表示されたら、Docker IDと使用したい認証情報(アクセストークンまたはDocker IDのパスワード)を入力してください。
ログインプロセスは、認証トークンを保持するconfig.jsonファイルを作成または更新します。Kubernetesがこのファイルを解釈する方法を確認してください。
以下のようにconfig.jsonファイルを確認します:
cat ~/.docker/config.json
出力には以下のような部分が含まれています:
{
"auths": {
"https://index.docker.io/v1/": {
"auth": "c3R...zE2"
}
}
}
備考:
Dockerの認証情報ストアを使用している場合、authエントリの代わりに、ストア名を値とするcredsStoreエントリが表示されます。
この場合、Secretを直接作成できます。
コマンドライン上で認証情報を入力してSecretを作成するを参照してください。既存の認証情報を用いるSecretを作成する
Kubernetesクラスターはプライベートイメージを取得するためのレジストリとの認証にkubernetes.io/dockerconfigjsonタイプのSecretを使用します。
既にdocker loginを実行済みの場合、その認証情報をKubernetesにコピーできます:
kubectl create secret generic regcred \
--from-file=.dockerconfigjson=<path/to/.docker/config.json> \
--type=kubernetes.io/dockerconfigjson
新しいSecretをカスタマイズする必要がある場合(例えば、新しいSecretにNamespaceやLabelを設定する場合)は、保存する前にSecretをカスタマイズできます。 必ず以下を行ってください:
data項目の名前を.dockerconfigjsonに設定する- Dockerの設定ファイルをbase64エンコードし、その文字列を分割せずに
data[".dockerconfigjson"]の値として貼り付ける typeをkubernetes.io/dockerconfigjsonに設定する
Secretをカスタマイズする場合のマニフェストの例:
apiVersion: v1
kind: Secret
metadata:
name: myregistrykey
namespace: awesomeapps
data:
.dockerconfigjson: UmVhbGx5IHJlYWxseSByZWVlZWVlZWVlZWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGx5eXl5eXl5eXl5eXl5eXl5eXl5eSBsbGxsbGxsbGxsbGxsbG9vb29vb29vb29vb29vb29vb29vb29vb29vb25ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubmdnZ2dnZ2dnZ2dnZ2dnZ2dnZ2cgYXV0aCBrZXlzCg==
type: kubernetes.io/dockerconfigjson
error: no objects passed to createをエラーメッセージとして受け取った場合、base64エンコードされた文字列が無効である可能性があります。
Secret "myregistrykey" is invalid: data[.dockerconfigjson]: invalid value ...をエラーメッセージとして受け取った場合は、data内のbase64エンコードされた文字列は正常にデコードされたものの、.docker/config.jsonファイルとして読み込むことができなかったことを意味します。
コマンドライン上で認証情報を入力してSecretを作成する
このSecretをregcredという名前で作成します:
kubectl create secret docker-registry regcred --docker-server=<your-registry-server> --docker-username=<your-name> --docker-password=<your-pword> --docker-email=<your-email>
ここでは:
<your-registry-server>は、プライベートDockerレジストリのFQDN(完全修飾ドメイン名)です。 Docker Hubを使用する場合は、https://index.docker.io/v1/を設定して下さい。<your-name>は、Dockerのユーザー名です。<your-pword>は、Dockerのパスワードです。<your-email>は、Dockerのメールアドレスです。
Dockerレジストリの認証情報がSecretとしてregcredという名前でクラスターに正常に設定されました。
備考:
コマンドラインで認証情報を入力すると、認証情報が保護されていない状態でシェルの履歴に保存される可能性があり、またkubectl実行中はPCの他のユーザーがそれらの認証情報を閲覧できる可能性があります。regcredSecretを確認する
作成したregcredSecretの内容を理解するために、まずYAML形式でSecretを表示します:
kubectl get secret regcred --output=yaml
出力は以下のようになります:
apiVersion: v1
kind: Secret
metadata:
...
name: regcred
...
data:
.dockerconfigjson: eyJodHRwczovL2luZGV4L ... J0QUl6RTIifX0=
type: kubernetes.io/dockerconfigjson
.dockerconfigjsonフィールドの値は、Docker認証情報をbase64でエンコードしたものです。
.dockerconfigjsonフィールドの内容を理解するために、認証情報のデータを読解可能な形式に変換します:
kubectl get secret regcred --output="jsonpath={.data.\.dockerconfigjson}" | base64 --decode
出力は以下のようになります:
{"auths":{"your.private.registry.example.com":{"username":"janedoe","password":"xxxxxxxxxxx","email":"jdoe@example.com","auth":"c3R...zE2"}}}
authフィールドの内容を理解するために、base64エンコードされたデータを読解可能な形式に変換します:
echo "c3R...zE2" | base64 --decode
出力はユーザー名とパスワードが:で連結された以下のような形式になります:
janedoe:xxxxxxxxxxx
Secretのdataには、ローカルの~/.docker/config.jsonファイルと同様の認証トークンが含まれていることが分かります。
クラスターにregcredという名前のSecretとしてDockerの認証情報が正常に設定されました。
作成したSecretを利用するPodを作成する
以下はregcredという名前のDockerの認証情報へのアクセスが必要なPodのマニフェストの例です:
apiVersion: v1
kind: Pod
metadata:
name: private-reg
spec:
containers:
- name: private-reg-container
image: <your-private-image>
imagePullSecrets:
- name: regcred
上記のファイルをあなたのコンピューターにダウンロードします:
curl -L -o my-private-reg-pod.yaml https://k8s.io/examples/pods/private-reg-pod.yaml
my-private-reg-pod.yamlファイル内の<your-private-image>を、以下のようなプライベートレジストリのイメージのパスに置き換えてください:
your.private.registry.example.com/janedoe/jdoe-private:v1
プライベートレジストリからイメージを取得するために、Kubernetesは認証情報を必要とします。
設定ファイル内のimagePullSecretsフィールドは、Kubernetesがregcredという名前のSecretから認証情報を取得することを指定します。
以下のようにして作成したSecretを使用するPodを作成し、Podが実行されていることを確認します:
kubectl apply -f my-private-reg-pod.yaml
kubectl get pod private-reg
備考:
イメージプルシークレットをPod(またはDeployment、あるいはPodテンプレートを使用するその他のオブジェクト)で使用するには、適切なSecretが正しいNamespaceに存在することを確認する必要があります。 使用するNamespaceは、Podを定義したNamespaceと同一である必要があります。また、PodのステータスがImagePullBackOffになり起動に失敗した場合は、Podのイベントを確認してください:
kubectl describe pod private-reg
もしFailedToRetrieveImagePullSecretという理由を持つイベントが表示された場合は、Kubernetesが指定された名前のSecret(この例ではregcred)を見つけることができないことを示します。
指定したSecretが存在し、その名前が正しく記載されていることを確認してください。
Events:
... Reason ... Message
------ -------
... FailedToRetrieveImagePullSecret ... Unable to retrieve some image pull secrets (<regcred>); attempting to pull the image may not succeed.
複数のレジストリ上のイメージを利用する
1つのPodは複数のコンテナを持つことができ、各コンテナのイメージは異なるレジストリから取得できます。
1つのPodで複数のimagePullSecretsを使用でき、それぞれに複数の認証情報を含めることができます。
レジストリに一致する各認証情報を使用してイメージの取得が試行されます。 レジストリに一致する認証情報がない場合、認証なしで、またはカスタムランタイム固有の設定を使用してイメージの取得が試行されます。
次の項目
- Secretについてさらに学ぶ。
- プライベートレジストリを使用する方法についてさらに学ぶ。
- イメージプルシークレットをサービスアカウントへ追加するについてさらに学ぶ。
- kubectl create secret docker-registryを参照する。
- Podのコンテナの定義内の
imagePullSecretsフィールドを参照する。
12 - Liveness Probe、Readiness ProbeおよびStartup Probeを使用する
このページでは、Liveness Probe、Readiness ProbeおよびStartup Probeの使用方法について説明します。
kubeletは、Liveness Probeを使用して、コンテナをいつ再起動するかを認識します。 例えば、アプリケーション自体は起動しているが、処理を継続することができないデッドロック状態を検知することができます。 このような状態のコンテナを再起動することで、バグがある場合でもアプリケーションの可用性を高めることができます。
kubeletは、Readiness Probeを使用して、コンテナがトラフィックを受け入れられる状態であるかを認識します。 Podが準備ができていると見なされるのは、Pod内の全てのコンテナの準備が整ったときです。 一例として、このシグナルはServiceのバックエンドとして使用されるPodを制御するときに使用されます。 Podの準備ができていない場合、そのPodはServiceのロードバランシングから切り離されます。
kubeletは、Startup Probeを使用して、コンテナアプリケーションの起動が完了したかを認識します。 Startup Probeを使用している場合、Startup Probeが成功するまでは、Liveness Probeと Readiness Probeによるチェックを無効にし、これらがアプリケーションの起動に干渉しないようにします。 例えば、これを起動が遅いコンテナの起動チェックとして使用することで、起動する前にkubeletによって 強制終了されることを防ぐことができます。
始める前に
Kubernetesクラスターが必要、かつそのクラスターと通信するためにkubectlコマンドラインツールが設定されている必要があります。 このチュートリアルは、コントロールプレーンのホストとして動作していない少なくとも2つのノードを持つクラスターで実行することをおすすめします。 まだクラスターがない場合、minikubeを使って作成するか、 以下のいずれかのKubernetesプレイグラウンドも使用できます:
バージョンを確認するには次のコマンドを実行してください: kubectl version.
コマンド実行によるLiveness Probeを定義する
長期間実行されているアプリケーションの多くは、再起動されるまで回復できないような異常な状態になることがあります。 Kubernetesはこのような状況を検知し、回復するためのLiveness Probeを提供します。
この演習では、registry.k8s.io/busyboxイメージのコンテナを起動するPodを作成します。
Podの構成ファイルは次の通りです。
apiVersion: v1
kind: Pod
metadata:
labels:
test: liveness
name: liveness-exec
spec:
containers:
- name: liveness
image: registry.k8s.io/busybox
args:
- /bin/sh
- -c
- touch /tmp/healthy; sleep 30; rm -f /tmp/healthy; sleep 600
livenessProbe:
exec:
command:
- cat
- /tmp/healthy
initialDelaySeconds: 5
periodSeconds: 5
この構成ファイルでは、Podは一つのContainerを起動します。
periodSecondsフィールドは、kubeletがLiveness Probeを5秒おきに行うように指定しています。
initialDelaySecondsフィールドは、kubeletが最初のProbeを実行する前に5秒間待機するように指示しています。
Probeの動作としては、kubeletはcat /tmp/healthyを対象のコンテナ内で実行します。
このコマンドが成功し、リターンコード0が返ると、kubeletはコンテナが問題なく動いていると判断します。
リターンコードとして0以外の値が返ると、kubeletはコンテナを終了し、再起動を行います。
このコンテナは、起動すると次のコマンドを実行します:
/bin/sh -c "touch /tmp/healthy; sleep 30; rm -f /tmp/healthy; sleep 600"
コンテナが起動してから初めの30秒間は/tmp/healthyファイルがコンテナ内に存在します。
そのため初めの30秒間はcat /tmp/healthyコマンドは成功し、正常なリターンコードが返ります。
その後30秒が経過すると、cat /tmp/healthyコマンドは異常なリターンコードを返します。
このPodを起動してください:
kubectl apply -f https://k8s.io/examples/pods/probe/exec-liveness.yaml
30秒間以内に、Podのイベントを確認します。
kubectl describe pod liveness-exec
この出力結果は、Liveness Probeがまだ失敗していないことを示しています。
FirstSeen LastSeen Count From SubobjectPath Type Reason Message
--------- -------- ----- ---- ------------- -------- ------ -------
24s 24s 1 {default-scheduler } Normal Scheduled Successfully assigned liveness-exec to worker0
23s 23s 1 {kubelet worker0} spec.containers{liveness} Normal Pulling pulling image "registry.k8s.io/busybox"
23s 23s 1 {kubelet worker0} spec.containers{liveness} Normal Pulled Successfully pulled image "registry.k8s.io/busybox"
23s 23s 1 {kubelet worker0} spec.containers{liveness} Normal Created Created container with docker id 86849c15382e; Security:[seccomp=unconfined]
23s 23s 1 {kubelet worker0} spec.containers{liveness} Normal Started Started container with docker id 86849c15382e
35秒後に、Podのイベントをもう一度確認します:
kubectl describe pod liveness-exec
出力結果の最後に、Liveness Probeが失敗していることを示すメッセージが表示されます。これによりコンテナは強制終了し、再作成されました。
FirstSeen LastSeen Count From SubobjectPath Type Reason Message
--------- -------- ----- ---- ------------- -------- ------ -------
37s 37s 1 {default-scheduler } Normal Scheduled Successfully assigned liveness-exec to worker0
36s 36s 1 {kubelet worker0} spec.containers{liveness} Normal Pulling pulling image "registry.k8s.io/busybox"
36s 36s 1 {kubelet worker0} spec.containers{liveness} Normal Pulled Successfully pulled image "registry.k8s.io/busybox"
36s 36s 1 {kubelet worker0} spec.containers{liveness} Normal Created Created container with docker id 86849c15382e; Security:[seccomp=unconfined]
36s 36s 1 {kubelet worker0} spec.containers{liveness} Normal Started Started container with docker id 86849c15382e
2s 2s 1 {kubelet worker0} spec.containers{liveness} Warning Unhealthy Liveness probe failed: cat: can't open '/tmp/healthy': No such file or directory
さらに30秒後、コンテナが再起動していることを確認します:
kubectl get pod liveness-exec
出力結果から、RESTARTSがインクリメントされていることを確認します:
NAME READY STATUS RESTARTS AGE
liveness-exec 1/1 Running 1 1m
HTTPリクエストによるLiveness Probeを定義する
別の種類のLiveness Probeでは、HTTP GETリクエストを使用します。
次の構成ファイルは、registry.k8s.io/e2e-test-images/agnhostイメージを使用したコンテナを起動するPodを作成します。
apiVersion: v1
kind: Pod
metadata:
labels:
test: liveness
name: liveness-http
spec:
containers:
- name: liveness
image: registry.k8s.io/e2e-test-images/agnhost:2.40
args:
- liveness
livenessProbe:
httpGet:
path: /healthz
port: 8080
httpHeaders:
- name: Custom-Header
value: Awesome
initialDelaySeconds: 3
periodSeconds: 3
この構成ファイルでは、Podは一つのContainerを起動します。
periodSecondsフィールドは、kubeletがLiveness Probeを3秒おきに行うように指定しています。
initialDelaySecondsフィールドは、kubeletが最初のProbeを実行する前に3秒間待機するように指示しています。
Probeの動作としては、kubeletは8080ポートをリッスンしているコンテナ内のサーバーに対してHTTP GETリクエストを送ります。
サーバー内の/healthzパスに対するハンドラーが正常なリターンコードを応答した場合、
kubeletはコンテナが問題なく動いていると判断します。
異常なリターンコードを応答すると、kubeletはコンテナを終了し、再起動を行います。
200以上400未満のコードは成功とみなされ、その他のコードは失敗とみなされます。
server.go にてサーバーのソースコードを確認することができます。
コンテナが生きている初めの10秒間は、/healthzハンドラーが200ステータスを返します。
その後、ハンドラーは500ステータスを返します。
http.HandleFunc("/healthz", func(w http.ResponseWriter, r *http.Request) {
duration := time.Now().Sub(started)
if duration.Seconds() > 10 {
w.WriteHeader(500)
w.Write([]byte(fmt.Sprintf("error: %v", duration.Seconds())))
} else {
w.WriteHeader(200)
w.Write([]byte("ok"))
}
})
kubeletは、コンテナが起動してから3秒後からヘルスチェックを行います。 そのため、初めのいくつかのヘルスチェックは成功します。しかし、10秒経過するとヘルスチェックは失敗し、kubeletはコンテナを終了し、再起動します。
HTTPリクエストのチェックによるLiveness Probeを試すには、以下のようにPodを作成します:
kubectl apply -f https://k8s.io/examples/pods/probe/http-liveness.yaml
10秒後、Podのイベントを表示して、Liveness Probeが失敗し、コンテナが再起動されていることを確認します。
kubectl describe pod liveness-http
v1.13以前(v1.13を含む)のリリースにおいては、Podが起動しているノードに環境変数http_proxy
(または HTTP_PROXY)が設定されている場合、HTTPリクエストのLiveness Probeは設定されたプロキシを使用します。
v1.13より後のリリースにおいては、ローカルHTTPプロキシ環境変数の設定はHTTPリクエストのLiveness Probeに影響しません。
TCPによるLiveness Probeを定義する
3つ目のLiveness ProbeはTCPソケットを使用するタイプです。 この構成においては、kubeletは指定したコンテナのソケットを開くことを試みます。 コネクションが確立できる場合はコンテナを正常とみなし、失敗する場合は異常とみなします。
apiVersion: v1
kind: Pod
metadata:
name: goproxy
labels:
app: goproxy
spec:
containers:
- name: goproxy
image: registry.k8s.io/goproxy:0.1
ports:
- containerPort: 8080
readinessProbe:
tcpSocket:
port: 8080
initialDelaySeconds: 5
periodSeconds: 10
livenessProbe:
tcpSocket:
port: 8080
initialDelaySeconds: 15
periodSeconds: 20
見ての通り、TCPによるチェックの構成はHTTPによるチェックと非常に似ています。
この例では、Readiness ProbeとLiveness Probeを両方使用しています。
kubeletは、コンテナが起動してから5秒後に最初のReadiness Probeを開始します。
これはgoproxyコンテナの8080ポートに対して接続を試みます。
このProbeが成功すると、Podは準備ができていると通知されます。kubeletはこのチェックを10秒ごとに行います。
この構成では、Readiness Probeに加えてLiveness Probeが含まれています。
kubeletは、コンテナが起動してから15秒後に最初のLiveness Probeを実行します。
Readiness Probeと同様に、これはgoproxyコンテナの8080ポートに対して接続を試みます。
Liveness Probeが失敗した場合、コンテナは再起動されます。
TCPのチェックによるLiveness Probeを試すには、以下のようにPodを作成します:
kubectl apply -f https://k8s.io/examples/pods/probe/tcp-liveness-readiness.yaml
15秒後、Podのイベントを表示し、Liveness Probeが行われていることを確認します:
kubectl describe pod goproxy
名前付きポートを使用する
HTTPまたはTCPによるProbeにおいて、ContainerPort で定義した名前付きポートを使用することができます。
ports:
- name: liveness-port
containerPort: 8080
livenessProbe:
httpGet:
path: /healthz
port: liveness-port
Startup Probeを使用して、起動の遅いコンテナを保護する
場合によっては、最初の初期化において追加の起動時間が必要になるようなレガシーアプリケーションを扱う必要があります。 そのような場合、デッドロックに対する迅速な反応を損なうことなくLiveness Probeのパラメーターを設定することは難しい場合があります。
これに対する解決策の一つは、Liveness Probeと同じ構成のコマンドを用いるか、HTTPまたはTCPによるチェックを使用したStartup Probeをセットアップすることです。
その際、failureThreshold * periodSecondsで計算される時間を、起動時間として想定される最も遅いケースをカバーできる十分な長さに設定します。
上記の例は、次のようになります:
ports:
- name: liveness-port
containerPort: 8080
livenessProbe:
httpGet:
path: /healthz
port: liveness-port
failureThreshold: 1
periodSeconds: 10
startupProbe:
httpGet:
path: /healthz
port: liveness-port
failureThreshold: 30
periodSeconds: 10
Startup Probeにより、アプリケーションは起動が完了するまでに最大5分間の猶予(30 * 10 = 300秒)が与えられます。
Startup Probeに一度成功すると、その後はLiveness Probeが引き継ぎ、コンテナのデッドロックに対して迅速に反応します。
Startup Probeが成功しない場合、コンテナは300秒後に終了し、その後はPodのrestartPolicyに従います。
Readiness Probeを定義する
アプリケーションは一時的にトラフィックを処理できないことが起こり得ます。 例えば、アプリケーションは起動時に大きなデータまたは構成ファイルを読み込む必要がある場合や、起動後に外部サービスに依存している場合があります。 このような場合、アプリケーション自体を終了させたくはありませんが、このアプリケーションに対してリクエストも送信したくないと思います。 Kubernetesは、これらの状況を検知して緩和するための機能としてReadiness Probeを提供します。 これにより、準備ができていないことを報告するコンテナを含むPodは、KubernetesのServiceを通してトラフィックを受信しないようになります。
備考:
Readiness Probeは、コンテナの全てのライフサイクルにおいて実行されます。Readiness ProbeはLiveness Probeと同様に構成します。
唯一の違いはreadinessProbeフィールドをlivenessProbeフィールドの代わりに利用することだけです。
readinessProbe:
exec:
command:
- cat
- /tmp/healthy
initialDelaySeconds: 5
periodSeconds: 5
HTTPおよびTCPによるReadiness Probeの構成もLiveness Probeと同じです。
Readiness ProbeとLiveness Probeは同じコンテナで同時に使用できます。 両方使用することで、準備できていないコンテナへのトラフィックが到達しないようにし、コンテナが失敗したときに再起動することができます。
Probeの構成
Probe には、 Liveness ProbeおよびReadiness Probeのチェック動作をより正確に制御するために使用できるフィールドがあります:
initialDelaySeconds: コンテナが起動してから、Liveness ProbeまたはReadiness Probeが開始されるまでの秒数。デフォルトは0秒。最小値は0。periodSeconds: Probeが実行される頻度(秒数)。デフォルトは10秒。最小値は1。 コンテナが起動してから準備が整うまでの間、periodSecondsで指定した間隔とは異なるタイミングでReadiness Probeが実行される場合があります。 これは、Podをより早く準備完了の状態に移行させるためです。timeoutSeconds: Probeがタイムアウトになるまでの秒数。デフォルトは1秒。最小値は1。successThreshold: 一度Probeが失敗した後、次のProbeが成功したとみなされるための最小連続成功数。 デフォルトは1。Liveness ProbeおよびStartup Probeには1を設定する必要があります。最小値は1。failureThreshold: Probeが失敗した場合、KubernetesはfailureThresholdに設定した回数までProbeを試行します。 Liveness Probeにおいて、試行回数に到達することはコンテナを再起動することを意味します。 Readiness Probeの場合は、Podが準備できていない状態として通知されます。デフォルトは3。最小値は1。
HTTPによるProbe
には、httpGetにて設定できる追加のフィールドがあります:
host: 接続先ホスト名。デフォルトはPod IP。おそらくはこのフィールドの代わりにhttpHeaders内の"Host"を代わりに使用することになります。scheme: ホストへの接続で使用するスキーマ(HTTP または HTTPS)。デフォルトは HTTP。path: HTTPサーバーへアクセスする際のパスhttpHeaders: リクエスト内のカスタムヘッダー。HTTPでは重複したヘッダーが許可されています。port: コンテナにアクセスする際のポートの名前または番号。ポート番号の場合、1から65535の範囲内である必要があります。
HTTPによるProbeの場合、kubeletは指定したパスとポートに対するHTTPリクエストを送ることでチェックを行います。
httpGetのオプションであるhostフィールドでアドレスが上書きされない限り、kubeletはPodのIPアドレスに対してProbeを送ります。
schemeフィールドにHTTPSがセットされている場合、kubeletは証明書の検証を行わずにHTTPSリクエストを送ります。
ほとんどのシナリオにおいては、hostフィールドを使用する必要はありません。次のシナリオは使用する場合の一例です。
仮にコンテナが127.0.0.1をリッスンしており、かつPodのhostNetworkフィールドがtrueだとします。
その場合においては、httpGetフィールド内のhostには127.0.0.1をセットする必要があります。
より一般的なケースにおいてPodが仮想ホストに依存している場合は、おそらくhostフィールドではなく、httpHeadersフィールド内のHostヘッダーを使用する必要があります。
TCPによるProbeの場合、kubeletはPodの中ではなく、ノードに対してコネクションを確立するProbeを実行します。
kubeletはServiceの名前を解決できないため、hostパラメーター内でServiceの名前を使用することはできません。
次の項目
- Container Probesについてもっと学ぶ
また、次のAPIリファレンスも参考にしてください:
13 - Podをノードに割り当てる
このページでは、KubernetesのPodをKubernetesクラスター上の特定のノードに割り当てる方法を説明します。
始める前に
Kubernetesクラスターが必要、かつそのクラスターと通信するためにkubectlコマンドラインツールが設定されている必要があります。 このチュートリアルは、コントロールプレーンのホストとして動作していない少なくとも2つのノードを持つクラスターで実行することをおすすめします。 まだクラスターがない場合、minikubeを使って作成するか、 以下のいずれかのKubernetesプレイグラウンドも使用できます:
バージョンを確認するには次のコマンドを実行してください: kubectl version.
ラベルをノードに追加する
-
クラスター内のノードのリストをラベル付きで表示します。
kubectl get nodes --show-labels出力は次のようになります。
NAME STATUS ROLES AGE VERSION LABELS worker0 Ready <none> 1d v1.13.0 ...,kubernetes.io/hostname=worker0 worker1 Ready <none> 1d v1.13.0 ...,kubernetes.io/hostname=worker1 worker2 Ready <none> 1d v1.13.0 ...,kubernetes.io/hostname=worker2 -
ノードの1つを選択して、ラベルを追加します。
kubectl label nodes <your-node-name> disktype=ssdここで、
<your-node-name>は選択したノードの名前です。 -
選択したノードに
disktype=ssdラベルがあることを確認します。kubectl get nodes --show-labels出力は次のようになります。
NAME STATUS ROLES AGE VERSION LABELS worker0 Ready <none> 1d v1.13.0 ...,disktype=ssd,kubernetes.io/hostname=worker0 worker1 Ready <none> 1d v1.13.0 ...,kubernetes.io/hostname=worker1 worker2 Ready <none> 1d v1.13.0 ...,kubernetes.io/hostname=worker2上の出力を見ると、
worker0にdisktype=ssdというラベルがあることがわかります。
選択したノードにスケジューリングされるPodを作成する
以下のPodの構成ファイルには、nodeSelectorにdisktype: ssdを持つPodが書かれています。これにより、Podはdisktype: ssdというラベルを持っているノードにスケジューリングされるようになります。
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
env: test
spec:
containers:
- name: nginx
image: nginx
imagePullPolicy: IfNotPresent
nodeSelector:
disktype: ssd
-
構成ファイルを使用して、選択したノードにスケジューリングされるPodを作成します。
kubectl apply -f https://k8s.io/examples/pods/pod-nginx.yaml -
Podが選択したノード上で実行されているをことを確認します。
kubectl get pods --output=wide出力は次のようになります。
NAME READY STATUS RESTARTS AGE IP NODE nginx 1/1 Running 0 13s 10.200.0.4 worker0
特定のノードにスケジューリングされるPodを作成する
nodeNameという設定を使用して、Podを特定のノードにスケジューリングすることもできます。
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
nodeName: foo-node # 特定のノードにPodをスケジューリングする
containers:
- name: nginx
image: nginx
imagePullPolicy: IfNotPresent
構成ファイルを使用して、foo-nodeにだけスケジューリングされるPodを作成します。
次の項目
14 - Node Affinityを利用してPodをノードに割り当てる
このページでは、Node Affinityを利用して、PodをKubernetesクラスター内の特定のノードに割り当てる方法を説明します。
始める前に
Kubernetesクラスターが必要、かつそのクラスターと通信するためにkubectlコマンドラインツールが設定されている必要があります。 このチュートリアルは、コントロールプレーンのホストとして動作していない少なくとも2つのノードを持つクラスターで実行することをおすすめします。 まだクラスターがない場合、minikubeを使って作成するか、 以下のいずれかのKubernetesプレイグラウンドも使用できます:
作業するKubernetesサーバーは次のバージョン以降のものである必要があります: v1.10.バージョンを確認するには次のコマンドを実行してください: kubectl version.
ノードにラベルを追加する
-
クラスター内のノードを一覧表示して、ラベルを確認します。
kubectl get nodes --show-labels出力は次のようになります。
NAME STATUS ROLES AGE VERSION LABELS worker0 Ready <none> 1d v1.13.0 ...,kubernetes.io/hostname=worker0 worker1 Ready <none> 1d v1.13.0 ...,kubernetes.io/hostname=worker1 worker2 Ready <none> 1d v1.13.0 ...,kubernetes.io/hostname=worker2 -
ノードを選択して、ラベルを追加します。
kubectl label nodes <your-node-name> disktype=ssdここで、
<your-node-name>は選択したノードの名前で置換します。 -
選択したノードに
disktype=ssdラベルがあることを確認します。kubectl get nodes --show-labels出力は次のようになります。
NAME STATUS ROLES AGE VERSION LABELS worker0 Ready <none> 1d v1.13.0 ...,disktype=ssd,kubernetes.io/hostname=worker0 worker1 Ready <none> 1d v1.13.0 ...,kubernetes.io/hostname=worker1 worker2 Ready <none> 1d v1.13.0 ...,kubernetes.io/hostname=worker2この出力を見ると、
worker0ノードにdisktype=ssdというラベルが追加されたことがわかります。
required node affinityを使用してPodをスケジューリングする
以下に示すマニフェストには、requiredDuringSchedulingIgnoredDuringExecutionにdisktype: ssdというnode affinityを使用したPodが書かれています。このように書くと、Podはdisktype=ssdというラベルを持つノードにだけスケジューリングされるようになります。
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: disktype
operator: In
values:
- ssd
containers:
- name: nginx
image: nginx
imagePullPolicy: IfNotPresent
-
マニフェストを適用して、選択したノード上にスケジューリングされるPodを作成します。
kubectl apply -f https://k8s.io/examples/pods/pod-nginx-required-affinity.yaml -
Podが選択したノード上で実行されていることを確認します。
kubectl get pods --output=wide出力は次のようになります。
NAME READY STATUS RESTARTS AGE IP NODE nginx 1/1 Running 0 13s 10.200.0.4 worker0
preferred node affinityを使用してPodをスケジューリングする
以下に示すマニフェストには、preferredDuringSchedulingIgnoredDuringExecutionにdisktype: ssdというnode affinityを使用したPodが書かれています。このように書くと、Podはdisktype=ssdというラベルを持つノードに優先的にスケジューリングされるようになります。
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
affinity:
nodeAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 1
preference:
matchExpressions:
- key: disktype
operator: In
values:
- ssd
containers:
- name: nginx
image: nginx
imagePullPolicy: IfNotPresent
-
マニフェストを適用して、選択したノード上にスケジューリングされるPodを作成します。
kubectl apply -f https://k8s.io/examples/pods/pod-nginx-preferred-affinity.yaml -
Podが選択したノード上で実行されていることを確認します。
kubectl get pods --output=wide出力は次のようになります。
NAME READY STATUS RESTARTS AGE IP NODE nginx 1/1 Running 0 13s 10.200.0.4 worker0
次の項目
Node Affinityについてさらに学ぶ。
15 - Pod初期化の設定
このページでは、アプリケーションコンテナが実行される前に、Initコンテナを使用してPodを初期化する方法を示します。
始める前に
Kubernetesクラスターが必要、かつそのクラスターと通信するためにkubectlコマンドラインツールが設定されている必要があります。 このチュートリアルは、コントロールプレーンのホストとして動作していない少なくとも2つのノードを持つクラスターで実行することをおすすめします。 まだクラスターがない場合、minikubeを使って作成するか、 以下のいずれかのKubernetesプレイグラウンドも使用できます:
バージョンを確認するには次のコマンドを実行してください: kubectl version.
Initコンテナを持つPodを作成する
この演習では、アプリケーションコンテナが1つ、Initコンテナが1つのPodを作成します。 Initコンテナはアプリケーションコンテナが実行される前に完了します。
Podの設定ファイルは次の通りです:
apiVersion: v1
kind: Pod
metadata:
name: init-demo
spec:
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
volumeMounts:
- name: workdir
mountPath: /usr/share/nginx/html
# These containers are run during pod initialization
initContainers:
- name: install
image: busybox
command:
- wget
- "-O"
- "/work-dir/index.html"
- http://kubernetes.io
volumeMounts:
- name: workdir
mountPath: "/work-dir"
dnsPolicy: Default
volumes:
- name: workdir
emptyDir: {}
設定ファイルを確認すると、PodはInitコンテナとアプリケーションコンテナが共有するボリュームを持っています。
Initコンテナは共有ボリュームを/work-dirにマウントし、アプリケーションコンテナは共有ボリュームを/usr/share/nginx/htmlにマウントします。
Initコンテナは以下のコマンドを実行してから終了します:
wget -O /work-dir/index.html http://info.cern.ch
Initコンテナは、nginxサーバーのルートディレクトリのindex.htmlファイルに書き込むことに注意してください。
Podを作成します:
kubectl apply -f https://k8s.io/examples/pods/init-containers.yaml
nginxコンテナが実行中であることを確認します:
kubectl get pod init-demo
次の出力はnginxコンテナが実行中であることを示します:
NAME READY STATUS RESTARTS AGE
init-demo 1/1 Running 0 1m
init-demo Podで実行中のnginxコンテナのシェルを取得します:
kubectl exec -it init-demo -- /bin/bash
シェルで、nginxサーバーにGETリクエストを送信します:
root@nginx:~# apt-get update
root@nginx:~# apt-get install curl
root@nginx:~# curl localhost
出力は、Initコンテナが書き込んだウェブページをnginxが提供していることを示します:
<html><head></head><body><header>
<title>http://info.cern.ch</title>
</header>
<h1>http://info.cern.ch - home of the first website</h1>
...
<li><a href="http://info.cern.ch/hypertext/WWW/TheProject.html">Browse the first website</a></li>
...
次の項目
- 同じPod内で実行されているコンテナ間の通信についてもっと学ぶ。
- Initコンテナについてもっと学ぶ。
- ボリュームについてもっと学ぶ。
- Initコンテナのデバッグについてもっと学ぶ。
16 - コンテナライフサイクルイベントへのハンドラー紐付け
このページでは、コンテナのライフサイクルイベントにハンドラーを紐付けする方法を説明します。KubernetesはpostStartとpreStopイベントをサポートしています。Kubernetesはコンテナの起動直後にpostStartイベントを送信し、コンテナの終了直前にpreStopイベントを送信します。
始める前に
Kubernetesクラスターが必要、かつそのクラスターと通信するためにkubectlコマンドラインツールが設定されている必要があります。 このチュートリアルは、コントロールプレーンのホストとして動作していない少なくとも2つのノードを持つクラスターで実行することをおすすめします。 まだクラスターがない場合、minikubeを使って作成するか、 以下のいずれかのKubernetesプレイグラウンドも使用できます:
バージョンを確認するには次のコマンドを実行してください: kubectl version.
postStartハンドラーとpreStopハンドラーを定義する
この課題では、1つのコンテナを持つPodを作成します。コンテナには、postStartイベントとpreStopイベントのハンドラーがあります。
これがPodの設定ファイルです:
apiVersion: v1
kind: Pod
metadata:
name: lifecycle-demo
spec:
containers:
- name: lifecycle-demo-container
image: nginx
lifecycle:
postStart:
exec:
command: ["/bin/sh", "-c", "echo Hello from the postStart handler > /usr/share/message"]
preStop:
exec:
command: ["/usr/sbin/nginx","-s","quit"]
設定ファイルでは、postStartコマンドがmessageファイルをコンテナの/usr/shareディレクトリに書き込むことがわかります。preStopコマンドはnginxを適切にシャットダウンします。これは、障害のためにコンテナが終了している場合に役立ちます。
Podを作成します:
kubectl apply -f https://k8s.io/examples/pods/lifecycle-events.yaml
Pod内のコンテナが実行されていることを確認します:
kubectl get pod lifecycle-demo
Pod内で実行されているコンテナでシェルを実行します:
kubectl exec -it lifecycle-demo -- /bin/bash
シェルで、postStartハンドラーがmessageファイルを作成したことを確認します:
root@lifecycle-demo:/# cat /usr/share/message
出力は、postStartハンドラーによって書き込まれたテキストを示しています。
Hello from the postStart handler
議論
コンテナが作成された直後にKubernetesはpostStartイベントを送信します。 ただし、コンテナのエントリーポイントが呼び出される前にpostStartハンドラーが呼び出されるという保証はありません。postStartハンドラーはコンテナのコードに対して非同期的に実行されますが、postStartハンドラーが完了するまでコンテナのKubernetesによる管理はブロックされます。postStartハンドラーが完了するまで、コンテナのステータスはRUNNINGに設定されません。
Kubernetesはコンテナが終了する直前にpreStopイベントを送信します。 コンテナのKubernetesによる管理は、Podの猶予期間が終了しない限り、preStopハンドラーが完了するまでブロックされます。詳細はPodのライフサイクルを参照してください。
備考:
Kubernetesは、Podが 終了 したときにのみpreStopイベントを送信します。 これは、Podが 完了 したときにpreStopフックが呼び出されないことを意味します。 この制限はissue #55087で追跡されています。次の項目
- コンテナライフサイクルフックの詳細
- Podのライフサイクルの詳細
参照
17 - Podを構成してConfigMapを使用する
ConfigMapを使用すると、設定をイメージのコンテンツから切り離して、コンテナ化されたアプリケーションの移植性を維持できます。このページでは、ConfigMapを作成し、ConfigMapに保存されているデータを使用してPodを構成する一連の使用例を示します。
始める前に
Kubernetesクラスターが必要、かつそのクラスターと通信するためにkubectlコマンドラインツールが設定されている必要があります。 このチュートリアルは、コントロールプレーンのホストとして動作していない少なくとも2つのノードを持つクラスターで実行することをおすすめします。 まだクラスターがない場合、minikubeを使って作成するか、 以下のいずれかのKubernetesプレイグラウンドも使用できます:
バージョンを確認するには次のコマンドを実行してください: kubectl version.
ConfigMapを作成する
kubectl create configmapまたはkustomization.yamlのConfigMap generatorを使用すると、ConfigMapを作成できます。kubectlがkustomization.yamlをサポートをしているのは1.14からである点に注意してください。
kubectl create configmapを使用してConfigMapを作成する
kubectl create configmapを使用してConfigMapをディレクトリ、ファイル、またはリテラル値から作成します:
kubectl create configmap <map-name> <data-source>
<map-name>の部分はConfigMapに割り当てる名前で、<data-source>はデータを取得するディレクトリ、ファイル、またはリテラル値です。ConfigMapの名前は有効なDNSサブドメイン名である必要があります。
ファイルをベースにConfigMapを作成する場合、<data-source> のキーはデフォルトでファイル名になり、値はデフォルトでファイルの中身になります。
kubectl describeまたは
kubectl getを使用すると、ConfigMapに関する情報を取得できます。
ディレクトリからConfigMapを作成する
kubectl create configmapを使用すると、同一ディレクトリ内にある複数のファイルから1つのConfigMapを作成できます。ディレクトリをベースにConfigMapを作成する場合、kubectlはディレクトリ内でベース名が有効なキーであるファイルを識別し、それらのファイルを新たなConfigMapにパッケージ化します。ディレクトリ内にある通常のファイルでないものは無視されます(例: サブディレクトリ、シンボリックリンク、デバイス、パイプなど)。
例えば:
# ローカルディレクトリを作成します
mkdir -p configure-pod-container/configmap/
# `configure-pod-container/configmap/`ディレクトリにサンプルファイルをダウンロードします
wget https://kubernetes.io/examples/configmap/game.properties -O configure-pod-container/configmap/game.properties
wget https://kubernetes.io/examples/configmap/ui.properties -O configure-pod-container/configmap/ui.properties
# ConfigMapを作成します
kubectl create configmap game-config --from-file=configure-pod-container/configmap/
上記のコマンドは各ファイルをパッケージ化します。この場合、configure-pod-container/configmap/ ディレクトリのgame.properties と ui.propertiesをgame-config ConfigMapにパッケージ化します。 以下のコマンドを使用すると、ConfigMapの詳細を表示できます:
kubectl describe configmaps game-config
出力結果は以下のようになります:
Name: game-config
Namespace: default
Labels: <none>
Annotations: <none>
Data
====
game.properties:
----
enemies=aliens
lives=3
enemies.cheat=true
enemies.cheat.level=noGoodRotten
secret.code.passphrase=UUDDLRLRBABAS
secret.code.allowed=true
secret.code.lives=30
ui.properties:
----
color.good=purple
color.bad=yellow
allow.textmode=true
how.nice.to.look=fairlyNice
configure-pod-container/configmap/ ディレクトリのgame.properties と ui.properties ファイルはConfigMapのdataセクションに表示されます。
kubectl get configmaps game-config -o yaml
出力結果は以下のようになります:
apiVersion: v1
kind: ConfigMap
metadata:
creationTimestamp: 2016-02-18T18:52:05Z
name: game-config
namespace: default
resourceVersion: "516"
uid: b4952dc3-d670-11e5-8cd0-68f728db1985
data:
game.properties: |
enemies=aliens
lives=3
enemies.cheat=true
enemies.cheat.level=noGoodRotten
secret.code.passphrase=UUDDLRLRBABAS
secret.code.allowed=true
secret.code.lives=30
ui.properties: |
color.good=purple
color.bad=yellow
allow.textmode=true
how.nice.to.look=fairlyNice
ファイルからConfigMapを作成する
kubectl create configmapを使用して、個別のファイルまたは複数のファイルからConfigMapを作成できます。
例えば、
kubectl create configmap game-config-2 --from-file=configure-pod-container/configmap/game.properties
は、以下のConfigMapを生成します:
kubectl describe configmaps game-config-2
出力結果は以下のようになります:
Name: game-config-2
Namespace: default
Labels: <none>
Annotations: <none>
Data
====
game.properties:
----
enemies=aliens
lives=3
enemies.cheat=true
enemies.cheat.level=noGoodRotten
secret.code.passphrase=UUDDLRLRBABAS
secret.code.allowed=true
secret.code.lives=30
--from-file引数を複数回渡し、ConfigMapを複数のデータソースから作成できます。
kubectl create configmap game-config-2 --from-file=configure-pod-container/configmap/game.properties --from-file=configure-pod-container/configmap/ui.properties
以下のコマンドを使用すると、ConfigMapgame-config-2の詳細を表示できます:
kubectl describe configmaps game-config-2
出力結果は以下のようになります:
Name: game-config-2
Namespace: default
Labels: <none>
Annotations: <none>
Data
====
game.properties:
----
enemies=aliens
lives=3
enemies.cheat=true
enemies.cheat.level=noGoodRotten
secret.code.passphrase=UUDDLRLRBABAS
secret.code.allowed=true
secret.code.lives=30
ui.properties:
----
color.good=purple
color.bad=yellow
allow.textmode=true
how.nice.to.look=fairlyNice
--from-env-fileオプションを利用してConfigMapをenv-fileから作成します。例えば:
# Env-filesは環境編集のリストを含んでいます。
# 以下のシンタックスルールが適用されます:
# envファイルの各行はVAR=VALの形式である必要がある。
# #で始まる行 (例えばコメント)は無視される。
# 空の行は無視される。
# クオーテーションマークは特別な扱いは処理をしない(例えばConfigMapの値の一部になる).
# `configure-pod-container/configmap/`ディレクトリにサンプルファイルをダウンロードします
wget https://kubernetes.io/examples/configmap/game-env-file.properties -O configure-pod-container/configmap/game-env-file.properties
# env-file `game-env-file.properties`は以下のようになります
cat configure-pod-container/configmap/game-env-file.properties
enemies=aliens
lives=3
allowed="true"
# このコメントと上記の空の行は無視されます
kubectl create configmap game-config-env-file \
--from-env-file=configure-pod-container/configmap/game-env-file.properties
は、以下のConfigMapを生成します:
kubectl get configmap game-config-env-file -o yaml
出力結果は以下のようになります:
apiVersion: v1
kind: ConfigMap
metadata:
creationTimestamp: 2017-12-27T18:36:28Z
name: game-config-env-file
namespace: default
resourceVersion: "809965"
uid: d9d1ca5b-eb34-11e7-887b-42010a8002b8
data:
allowed: '"true"'
enemies: aliens
lives: "3"
注意:
--from-env-fileを複数回渡してConfigMapを複数のデータソースから作成する場合、最後のenv-fileのみが使用されます。--from-env-fileを複数回渡す場合の挙動は以下のように示されます:
# `configure-pod-container/configmap/`ディレクトリにサンブルファイルをダウンロードします
wget https://kubernetes.io/examples/configmap/ui-env-file.properties -O configure-pod-container/configmap/ui-env-file.properties
# ConfigMapを作成します
kubectl create configmap config-multi-env-files \
--from-env-file=configure-pod-container/configmap/game-env-file.properties \
--from-env-file=configure-pod-container/configmap/ui-env-file.properties
は、以下のConfigMapを生成します:
kubectl get configmap config-multi-env-files -o yaml
出力結果は以下のようになります:
apiVersion: v1
kind: ConfigMap
metadata:
creationTimestamp: 2017-12-27T18:38:34Z
name: config-multi-env-files
namespace: default
resourceVersion: "810136"
uid: 252c4572-eb35-11e7-887b-42010a8002b8
data:
color: purple
how: fairlyNice
textmode: "true"
ファイルからConfigMap作成する場合は使用するキーを定義する
--from-file引数を使用する場合、ConfigMapのdata セクションでキーにファイル名以外を定義できます:
kubectl create configmap game-config-3 --from-file=<my-key-name>=<path-to-file>
<my-key-name>の部分はConfigMapで使うキー、<path-to-file> はキーで表示したいデータソースファイルの場所です。
例えば:
kubectl create configmap game-config-3 --from-file=game-special-key=configure-pod-container/configmap/game.properties
は、以下のConfigMapを生成します:
kubectl get configmaps game-config-3 -o yaml
出力結果は以下のようになります:
apiVersion: v1
kind: ConfigMap
metadata:
creationTimestamp: 2016-02-18T18:54:22Z
name: game-config-3
namespace: default
resourceVersion: "530"
uid: 05f8da22-d671-11e5-8cd0-68f728db1985
data:
game-special-key: |
enemies=aliens
lives=3
enemies.cheat=true
enemies.cheat.level=noGoodRotten
secret.code.passphrase=UUDDLRLRBABAS
secret.code.allowed=true
secret.code.lives=30
リテラル値からConfigMapを作成する
--from-literal引数を指定してkubectl create configmapを使用すると、コマンドラインからリテラル値を定義できます:
kubectl create configmap special-config --from-literal=special.how=very --from-literal=special.type=charm
複数のキーバリューペアを渡せます。CLIに提供された各ペアは、ConfigMapのdataセクションで別のエントリーとして表示されます。
kubectl get configmaps special-config -o yaml
出力結果は以下のようになります:
apiVersion: v1
kind: ConfigMap
metadata:
creationTimestamp: 2016-02-18T19:14:38Z
name: special-config
namespace: default
resourceVersion: "651"
uid: dadce046-d673-11e5-8cd0-68f728db1985
data:
special.how: very
special.type: charm
ジェネレーターからConfigMapを作成する
kubectlはkustomization.yamlを1.14からサポートしています。
ジェネレーターからConfigMapを作成して適用すると、APIサーバー上でオブジェクトを作成できます。ジェネレーターはディレクトリ内のkustomization.yamlで指定する必要があリます。
ファイルからConfigMapを生成する
例えば、ファイルconfigure-pod-container/configmap/game.propertiesからConfigMapを生成するには、
# ConfigMapGeneratorを含むkustomization.yamlファイルを作成する
cat <<EOF >./kustomization.yaml
configMapGenerator:
- name: game-config-4
files:
- configure-pod-container/configmap/game.properties
EOF
ConfigMapを作成するためにkustomizationディレクトリを適用します。
kubectl apply -k .
configmap/game-config-4-m9dm2f92bt created
ConfigMapが作成されたことを以下のようにチェックできます:
kubectl get configmap
NAME DATA AGE
game-config-4-m9dm2f92bt 1 37s
kubectl describe configmaps/game-config-4-m9dm2f92bt
Name: game-config-4-m9dm2f92bt
Namespace: default
Labels: <none>
Annotations: kubectl.kubernetes.io/last-applied-configuration:
{"apiVersion":"v1","data":{"game.properties":"enemies=aliens\nlives=3\nenemies.cheat=true\nenemies.cheat.level=noGoodRotten\nsecret.code.p...
Data
====
game.properties:
----
enemies=aliens
lives=3
enemies.cheat=true
enemies.cheat.level=noGoodRotten
secret.code.passphrase=UUDDLRLRBABAS
secret.code.allowed=true
secret.code.lives=30
Events: <none>
生成されたConfigMapの名前は、コンテンツをハッシュ化したサフィックスを持つことに注意してください。これにより、コンテンツが変更されるたびに新しいConfigMapが生成されます。
ファイルからConfigMapを生成する場合に使用するキーを定義する
ConfigMapジェネレーターで使用するキーはファイルの名前以外を定義できます。
例えば、ファイルconfigure-pod-container/configmap/game.propertiesからキーgame-special-keyを持つConfigMapを作成する場合
# ConfigMapGeneratorを含むkustomization.yamlファイルを作成する
cat <<EOF >./kustomization.yaml
configMapGenerator:
- name: game-config-5
files:
- game-special-key=configure-pod-container/configmap/game.properties
EOF
kustomizationディレクトリを適用してConfigMapを作成します。
kubectl apply -k .
configmap/game-config-5-m67dt67794 created
リテラルからConfigMapを作成する
リテラルspecial.type=charmとspecial.how=veryからConfigMapを作成する場合は、
以下のようにkustomization.yamlのConfigMapジェネレーターで指定できます。
# ConfigMapGeneratorを含むkustomization.yamlファイルを作成します
cat <<EOF >./kustomization.yaml
configMapGenerator:
- name: special-config-2
literals:
- special.how=very
- special.type=charm
EOF
kustomizationディレクトリを適用してConfigMapを作成します。
kubectl apply -k .
configmap/special-config-2-c92b5mmcf2 created
ConfigMapデータを使用してコンテナ環境変数を定義する
単一のConfigMapのデータを使用してコンテナ環境変数を定義する
-
ConfigMapに環境変数をキーバリューペアとして定義します:
kubectl create configmap special-config --from-literal=special.how=very -
ConfigMapに定義された値
special.howをPod specificationの環境変数SPECIAL_LEVEL_KEYに割り当てます。
apiVersion: v1
kind: Pod
metadata:
name: dapi-test-pod
spec:
containers:
- name: test-container
image: registry.k8s.io/busybox
command: [ "/bin/sh", "-c", "env" ]
env:
# 環境変数を定義します
- name: SPECIAL_LEVEL_KEY
valueFrom:
configMapKeyRef:
# SPECIAL_LEVEL_KEYに割り当てる値をConfigMapが保持します
name: special-config
# 値に紐付けるキーを指定します
key: special.how
restartPolicy: Never
Podを作成します:
kubectl create -f https://kubernetes.io/examples/pods/pod-single-configmap-env-variable.yaml
すると、Podの出力結果に環境変数SPECIAL_LEVEL_KEY=veryが含まれています。
複数のConfigMapのデータを使用してコンテナ環境変数を定義する
-
先ほどの例の通り、まずはConfigMapを作成します。
apiVersion: v1 kind: ConfigMap metadata: name: special-config namespace: default data: special.how: very --- apiVersion: v1 kind: ConfigMap metadata: name: env-config namespace: default data: log_level: INFOConfigMapを作成します:
kubectl create -f https://kubernetes.io/examples/configmap/configmaps.yaml
-
Pod specificationの環境変数を定義します
apiVersion: v1 kind: Pod metadata: name: dapi-test-pod spec: containers: - name: test-container image: registry.k8s.io/busybox command: [ "/bin/sh", "-c", "env" ] env: - name: SPECIAL_LEVEL_KEY valueFrom: configMapKeyRef: name: special-config key: special.how - name: LOG_LEVEL valueFrom: configMapKeyRef: name: env-config key: log_level restartPolicy: NeverPodを作成します:
kubectl create -f https://kubernetes.io/examples/pods/pod-multiple-configmap-env-variable.yaml
すると、Podの出力結果に環境変数SPECIAL_LEVEL_KEY=very and LOG_LEVEL=INFOが含まれています。
ConfigMapの全てのキーバリューペアをコンテナ環境変数として構成する
備考:
この機能はKubernetes v1.6以降で利用可能です。-
複数のキーバリューペアを含むConfigMapを作成します。
apiVersion: v1 kind: ConfigMap metadata: name: special-config namespace: default data: SPECIAL_LEVEL: very SPECIAL_TYPE: charmConfigMapを作成します:
kubectl create -f https://kubernetes.io/examples/configmap/configmap-multikeys.yaml
envFromを利用して全てのConfigMapのデータをコンテナ環境変数として定義します。ConfigMapからのキーがPodの環境変数名になります。
apiVersion: v1
kind: Pod
metadata:
name: dapi-test-pod
spec:
containers:
- name: test-container
image: registry.k8s.io/busybox
command: [ "/bin/sh", "-c", "env" ]
envFrom:
- configMapRef:
name: special-config
restartPolicy: Never
Podを作成します:
kubectl create -f https://kubernetes.io/examples/pods/pod-configmap-envFrom.yaml
すると、Podの出力結果は環境変数SPECIAL_LEVEL=veryとSPECIAL_TYPE=charmが含まれています。
PodのコマンドでConfigMapに定義した環境変数を使用する
ConfigMapに環境変数を定義し、Pod specificationのcommand セクションで$(VAR_NAME)Kubernetes置換構文を介して使用できます。
例えば以下のPod specificationは
apiVersion: v1
kind: Pod
metadata:
name: dapi-test-pod
spec:
containers:
- name: test-container
image: registry.k8s.io/busybox
command: [ "/bin/echo", "$(SPECIAL_LEVEL_KEY) $(SPECIAL_TYPE_KEY)" ]
env:
- name: SPECIAL_LEVEL_KEY
valueFrom:
configMapKeyRef:
name: special-config
key: SPECIAL_LEVEL
- name: SPECIAL_TYPE_KEY
valueFrom:
configMapKeyRef:
name: special-config
key: SPECIAL_TYPE
restartPolicy: Never
以下コマンドの実行で作成され、
kubectl create -f https://kubernetes.io/examples/pods/pod-configmap-env-var-valueFrom.yaml
test-containerコンテナで以下の出力結果を表示します:
kubectl logs dapi-test-pod
very charm
ボリュームにConfigMapデータを追加する
ファイルからConfigMapを作成するで説明したように、--from-fileを使用してConfigMapを作成する場合は、ファイル名がConfigMapのdataセクションに保存されるキーになり、ファイルのコンテンツがキーの値になります。
このセクションの例は以下に示されているspecial-configと名付けれたConfigMapについて言及したものです。
apiVersion: v1
kind: ConfigMap
metadata:
name: special-config
namespace: default
data:
SPECIAL_LEVEL: very
SPECIAL_TYPE: charm
ConfigMapを作成します:
kubectl create -f https://kubernetes.io/examples/configmap/configmap-multikeys.yaml
ConfigMapに保存されているデータをボリュームに入力する
ConfigMap名をPod specificationのvolumesセクション配下に追加します。
これによりConfigMapデータがvolumeMounts.mountPathで指定されたディレクトリに追加されます (このケースでは、/etc/configに)。commandセクションはConfigMapのキーに合致したディレクトリファイルを名前別でリスト表示します。
apiVersion: v1
kind: Pod
metadata:
name: dapi-test-pod
spec:
containers:
- name: test-container
image: registry.k8s.io/busybox
command: [ "/bin/sh", "-c", "ls /etc/config/" ]
volumeMounts:
- name: config-volume
mountPath: /etc/config
volumes:
- name: config-volume
configMap:
# コンテナに追加するファイルを含むConfigMapの名前を提供する
name: special-config
restartPolicy: Never
Podを作成します:
kubectl create -f https://kubernetes.io/examples/pods/pod-configmap-volume.yaml
Podが稼働していると、ls /etc/config/は以下の出力結果を表示します:
SPECIAL_LEVEL
SPECIAL_TYPE
注意:
/etc/config/ディレクトリに何かファイルがある場合、それらは削除されます。備考:
テキストデータはUTF-8文字エンコーディングを使用しているファイルとして公開されます。他の文字エンコーディングを使用する場合は、バイナリデータを使用してください。ConfigMapデータをボリュームの特定のパスに追加する
pathフィールドを利用して特定のConfigMapのアイテム向けに希望のファイルパスを指定します。
このケースではSPECIAL_LEVELアイテムが/etc/config/keysのconfig-volumeボリュームにマウントされます。
apiVersion: v1
kind: Pod
metadata:
name: dapi-test-pod
spec:
containers:
- name: test-container
image: registry.k8s.io/busybox
command: [ "/bin/sh","-c","cat /etc/config/keys" ]
volumeMounts:
- name: config-volume
mountPath: /etc/config
volumes:
- name: config-volume
configMap:
name: special-config
items:
- key: SPECIAL_LEVEL
path: keys
restartPolicy: Never
Podを作成します:
kubectl create -f https://kubernetes.io/examples/pods/pod-configmap-volume-specific-key.yaml
Podが稼働していると、 cat /etc/config/keysは以下の出力結果を表示します:
very
注意:
先ほどのように、/etc/config/ ディレクトリのこれまでのファイルは全て削除されますキーを特定のパスとファイルアクセス許可に投影する
キーをファイル単位で特定のパスとアクセス許可に投影できます。Secretのユーザーガイドで構文が解説されています。
マウントされたConfigMapは自動的に更新される
ボリュームで使用されているConfigMapが更新されている場合、投影されているキーも同じく結果的に更新されます。kubeletは定期的な同期ごとにマウントされているConfigMapが更新されているかチェックします。しかし、これはローカルのttlを基にしたキャッシュでConfigMapの現在の値を取得しています。その結果、新しいキーがPodに投影されてからConfigMapに更新されるまでのトータルの遅延はkubeletで、kubeletの同期期間(デフォルトで1分) + ConfigMapキャッシュのttl(デフォルトで1分)の長さになる可能性があります。Podのアノテーションを1つ更新すると即時のリフレッシュをトリガーできます。
備考:
ConfigMapをsubPathボリュームとして利用するコンテナはConfigMapの更新を受け取りません。ConfigMapとPodsを理解する
ConfigMap APIリソースは構成情報をキーバリューペアとして保存します。データはPodで利用したり、コントローラーなどのシステムコンポーネントに提供できます。ConfigMapはSecretに似ていますが、機密情報を含まない文字列を含まない操作する手段を提供します。ユーザーとシステムコンポーネントはどちらも構成情報をConfigMapに保存できます。
備考:
ConfigMapはプロパティーファイルを参照するべきであり、置き換えるべきではありません。ConfigMapをLinuxの/etcディレクトリとそのコンテンツのように捉えましょう。例えば、Kubernetes VolumeをConfigMapから作成した場合、ConfigMapのデータアイテムはボリューム内で個別のファイルとして表示されます。ConfigMapのdataフィールドは構成情報を含みます。下記の例のように、シンプルに個別のプロパティーを--from-literalで定義、または複雑に構成ファイルまたはJSON blobsを--from-fileで定義できます。
apiVersion: v1
kind: ConfigMap
metadata:
creationTimestamp: 2016-02-18T19:14:38Z
name: example-config
namespace: default
data:
# --from-literalを使用してシンプルにプロパティーを定義する例
example.property.1: hello
example.property.2: world
# --from-fileを使用して複雑にプロパティーを定義する例
example.property.file: |-
property.1=value-1
property.2=value-2
property.3=value-3
制限事項
-
ConfigMapはPod specificationを参照させる前に作成する必要があります(ConfigMapを"optional"として設定しない限り)。存在しないConfigMapを参照させた場合、Podは起動しません。同様にConfigMapに存在しないキーを参照させた場合も、Podは起動しません。
-
ConfigMapで
envFromを使用して環境変数を定義した場合、無効と判断されたキーはスキップされます。Podは起動されますが、無効な名前はイベントログに(InvalidVariableNames)と記録されます。ログメッセージはスキップされたキーごとにリスト表示されます。例えば:kubectl get events出力結果は以下のようになります:
LASTSEEN FIRSTSEEN COUNT NAME KIND SUBOBJECT TYPE REASON SOURCE MESSAGE 0s 0s 1 dapi-test-pod Pod Warning InvalidEnvironmentVariableNames {kubelet, 127.0.0.1} Keys [1badkey, 2alsobad] from the EnvFrom configMap default/myconfig were skipped since they are considered invalid environment variable names. -
ConfigMapは特定のNamespaceに属します。ConfigMapは同じ名前空間に属するPodからのみ参照できます。
-
static podsはKubeletがサポートしていないため、ConfigMapに使用できません。
次の項目
- 実践例ConfigMapを使ったRedisの設定を続けて読む。
18 - Pod内のコンテナ間でプロセス名前空間を共有する
このページでは、プロセス名前空間を共有するPodを構成する方法を示します。 プロセス名前空間の共有が有効になっている場合、コンテナ内のプロセスは、そのPod内の他のすべてのコンテナに表示されます。
この機能を使用して、ログハンドラーサイドカーコンテナなどの協調コンテナを構成したり、シェルなどのデバッグユーティリティを含まないコンテナイメージをトラブルシューティングしたりできます。
始める前に
Kubernetesクラスターが必要、かつそのクラスターと通信するためにkubectlコマンドラインツールが設定されている必要があります。 このチュートリアルは、コントロールプレーンのホストとして動作していない少なくとも2つのノードを持つクラスターで実行することをおすすめします。 まだクラスターがない場合、minikubeを使って作成するか、 以下のいずれかのKubernetesプレイグラウンドも使用できます:
作業するKubernetesサーバーは次のバージョン以降のものである必要があります: v1.10.バージョンを確認するには次のコマンドを実行してください: kubectl version.
Podを構成する
プロセス名前空間の共有は、v1.PodSpecのshareProcessNamespaceフィールドを使用して有効にします。
例:
-
クラスターにPod
nginxを作成します:kubectl apply -f https://k8s.io/examples/pods/share-process-namespace.yaml -
shellコンテナにアタッチしてpsを実行します:kubectl exec -it nginx -c shell -- /bin/shコマンドプロンプトが表示されない場合は、Enterキーを押してみてください。
/ # ps ax PID USER TIME COMMAND 1 root 0:00 /pause 8 root 0:00 nginx: master process nginx -g daemon off; 14 101 0:00 nginx: worker process 15 root 0:00 sh 21 root 0:00 ps ax
他のコンテナのプロセスにシグナルを送ることができます。
たとえば、ワーカープロセスを再起動するには、SIGHUPをnginxに送信します。
この操作にはSYS_PTRACE機能が必要です。
/ # kill -HUP 8
/ # ps ax
PID USER TIME COMMAND
1 root 0:00 /pause
8 root 0:00 nginx: master process nginx -g daemon off;
15 root 0:00 sh
22 101 0:00 nginx: worker process
23 root 0:00 ps ax
/proc/$pid/rootリンクを使用して別のコンテナイメージにアクセスすることもできます。
/ # head /proc/8/root/etc/nginx/nginx.conf
user nginx;
worker_processes 1;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
プロセス名前空間の共有について理解する
Podは多くのリソースを共有するため、プロセスの名前空間も共有することになります。 ただし、一部のコンテナイメージは他のコンテナから分離されることが期待されるため、これらの違いを理解することが重要です:
-
コンテナプロセスは PID 1ではなくなります。 一部のコンテナイメージは、PID 1なしで起動することを拒否し(たとえば、
systemdを使用するコンテナ)、kill -HUP 1などのコマンドを実行してコンテナプロセスにシグナルを送信します。 共有プロセス名前空間を持つPodでは、kill -HUP 1はPodサンドボックスにシグナルを送ります。(上の例では/pause) -
プロセスはPod内の他のコンテナに表示されます。 これには、引数または環境変数として渡されたパスワードなど、
/procに表示されるすべての情報が含まれます。 これらは、通常のUnixアクセス許可によってのみ保護されます。 -
コンテナファイルシステムは、
/proc/$pid/rootリンクを介してPod内の他のコンテナに表示されます。 これによりデバッグが容易になりますが、ファイルシステム内の秘密情報はファイルシステムのアクセス許可によってのみ保護されることも意味します。
19 - Podでユーザー名前空間を使用する
More information about this feature
This is a stable feature in Kubernetes, and has been since version v1.36. It was first available in the v1.28 release. You can no longer disable or opt out of this feature or behavior (it is locked); if you explicitly set a value for the associated feature gate UserNamespacesSupport, Kubernetes ignores it but does not report any error.
このページでは、Podにユーザー名前空間を設定する方法について説明します。 これにより、コンテナ内で実行されるユーザーをホスト上のユーザーから分離できます。
コンテナ内でrootとして実行されているプロセスは、ホスト上では別の(root以外の)ユーザーとして実行できます。 つまり、そのプロセスはユーザー名前空間内の操作に対しては完全な権限を持ちますが、名前空間外の操作に対しては権限を持ちません。
この機能を使うことで、コンテナが侵害された場合にホストや同じノード上の他のPodへの被害を軽減できます。 ユーザー名前空間が有効であれば悪用できなかったとされる、HIGHまたはCRITICALと評価されたセキュリティ脆弱性がいくつかあります。 ユーザー名前空間は将来の脆弱性の一部も軽減することが期待されています。
ユーザー名前空間を使用しない場合、rootとして実行されているコンテナが侵害されてホストに到達すると、ノード上でroot権限を持つことになります。 また、コンテナに何らかのケーパビリティが付与されていた場合、そのケーパビリティはホスト上でも有効です。 ユーザー名前空間を使用する場合、これらはいずれも当てはまりません。
始める前に
Kubernetesクラスターが必要、かつそのクラスターと通信するためにkubectlコマンドラインツールが設定されている必要があります。 このチュートリアルは、コントロールプレーンのホストとして動作していない少なくとも2つのノードを持つクラスターで実行することをおすすめします。 まだクラスターがない場合、minikubeを使って作成するか、 以下のいずれかのKubernetesプレイグラウンドも使用できます:
作業するKubernetesサーバーは次のバージョン以降のものである必要があります: v1.25.バージョンを確認するには次のコマンドを実行してください: kubectl version.
- ノードのOSがLinuxであること
- ホスト上でコマンドを実行できること
- Podにexecで入れること
UserNamespacesSupportフィーチャーゲートを有効にすること
備考:
ユーザー名前空間を有効にするフィーチャーゲートは、ステートレスなPodのみがサポートされていた頃はUserNamespacesStatelessPodsSupportという名前でした。
Kubernetes v1.25からv1.27のみがUserNamespacesStatelessPodsSupportを認識します。使用するクラスターには、Podでユーザー名前空間を使用するための要件を満たすノードが少なくとも1つ含まれている必要があります。
ノードが混在しており、一部のノードのみがPodのユーザー名前空間をサポートしている場合は、ユーザー名前空間を使用するPodが適切なノードにスケジュールされるようにする必要もあります。
ユーザー名前空間を使用するPodを実行する
Podのユーザー名前空間は、.specのhostUsersフィールドをfalseに設定することで有効になります。
例:
apiVersion: v1
kind: Pod
metadata:
name: userns
spec:
hostUsers: false
containers:
- name: shell
command: ["sleep", "infinity"]
image: debian
-
クラスター上にPodを作成します:
kubectl apply -f https://k8s.io/examples/pods/user-namespaces-stateless.yaml -
Pod内でexecし、
readlink /proc/self/ns/userを実行します:kubectl exec -ti userns -- bash
次のコマンドを実行します:
readlink /proc/self/ns/user
出力は次のようになります:
user:[4026531837]
さらに次を実行します:
cat /proc/self/uid_map
出力は次のようになります:
0 833617920 65536
次に、ホスト上でシェルを開き、同じコマンドを実行します。
readlinkコマンドは、プロセスが実行されているユーザー名前空間を表示します。
ホスト上とコンテナ内で実行した場合、異なる値になるはずです。
コンテナ内のuid_mapファイルの最後の数値は65536である必要があります。
ホスト上ではそれより大きい数値になります。
kubeletをユーザー名前空間内で実行している場合は、Pod内でコマンドを実行した出力を、ホスト上で次のコマンドを実行した出力と比較する必要があります:
readlink /proc/$pid/ns/user
$pidはkubeletのPIDに置き換えてください。
20 - static Podを作成する
Static Podとは、APIサーバーが監視せず、特定のノード上のkubeletデーモンによって直接管理されるPodです。 コントロールプレーンに管理されるPod(たとえばDeploymentなど)とは異なり、kubeletがそれぞれのstatic Podを監視(および障害時には再起動)します。
Static Podは、常に特定のノード上の1つのKubeletに紐付けられます。
kubeletは、各static Podに対して、自動的にKubernetes APIサーバー上にミラーPodの作成を試みます。 つまり、ノード上で実行中のPodはAPIサーバーから検出されますが、APIサーバー自身から制御されることはないということです。 Pod名は、先頭にハイフンを付けたノードのホスト名がサフィックスとして追加されます。
備考:
複数ノードからなるKubernetesクラスターを実行していて、Podをすべてのノード上で実行するためにstatic Podを使用している場合、おそらくstatic Podの代わりにDaemonSetを使用するべきでしょう。備考:
static Podは、エフェメラルコンテナをサポートしません。始める前に
Kubernetesクラスターが必要、かつそのクラスターと通信するためにkubectlコマンドラインツールが設定されている必要があります。 このチュートリアルは、コントロールプレーンのホストとして動作していない少なくとも2つのノードを持つクラスターで実行することをおすすめします。 まだクラスターがない場合、minikubeを使って作成するか、 以下のいずれかのKubernetesプレイグラウンドも使用できます:
バージョンを確認するには次のコマンドを実行してください: kubectl version.
このページの説明では、Podを実行するためにCRI-Oを使用しており、ノード上のOSがFedoraであることを前提としています。 他のディストリビューションやKubernetesのインストール方法によっては、操作が異なる場合があります。
static Podを作成する
static Podは、ファイルシステム上でホストされた設定ファイルまたはウェブ上でホストされた設定ファイルを使用して設定できます。
ファイルシステム上でホストされたstatic Podマニフェスト
マニフェストは、JSONまたはYAML形式の標準のPod定義で、特定のディレクトリに置きます。
kubeletの設定ファイルの中で、staticPodPath: <ディレクトリの場所>というフィールドを使用すると、kubeletがこのディレクトリを定期的にスキャンして、YAML/JSONファイルが作成/削除されるたびに、static Podの作成/削除が行われるようになります。
指定したディレクトリをスキャンする際、kubeletはドットから始まる名前のファイルを無視することに注意してください。
注意:
kubeletは、static Podディレクトリ内のドットで始まらないすべてのファイルを処理します。 ファイルの拡張子によるフィルタリングは行われません。 例えば、cp kube-apiserver.yaml kube-apiserver.yaml.backupを実行してマニフェストのバックアップを作成した場合、kubeletは両方のファイルを読み込み、それぞれからstatic Podを作成しようとします。
2つのファイルが同じ名前のPodを定義している場合、その結果の動作は未定義であり、バックアップの古いspecが現在のマニフェストの代わりに気づかないうちに有効になる可能性があります。
バックアップを作成する場合は、static Podディレクトリの外(例えば/etc/kubernetes/backup/)に保存してください。例として、単純なウェブサーバーをstatic Podとして実行する方法を示します:
-
static Podを実行したいノードを選択します。 この例では、
my-node1です。ssh my-node1 -
ディレクトリを選び(ここでは
/etc/kubernetes/manifestsとします)、ここにウェブサーバーのPodの定義を置きます。 たとえば、/etc/kubernetes/manifests/static-web.yamlに置きます:# このコマンドは、kubeletが実行中のノード上で実行してください mkdir -p /etc/kubernetes/manifests/ cat <<EOF >/etc/kubernetes/manifests/static-web.yaml apiVersion: v1 kind: Pod metadata: name: static-web labels: role: myrole spec: containers: - name: web image: nginx ports: - name: web containerPort: 80 protocol: TCP EOF -
そのノードのkubeletで、kubelet設定ファイルの
staticPodPathの値を設定します。 詳細については、設定ファイルによるkubeletパラメーターの設定を参照してください。別の非推奨の方法として、コマンドライン引数を使用して、そのノードのkubeletがstatic Podマニフェストをローカルで検索するように設定する方法があります。 非推奨のアプローチを使用するには、
--pod-manifest-path=/etc/kubernetes/manifests/引数を指定してkubeletを起動します。 -
kubeletを再起動します。 Fedoraの場合、次のコマンドを実行します:
# このコマンドは、kubeletが実行中のノード上で実行してください systemctl restart kubelet
ウェブ上でホストされたstatic Podマニフェスト
kubeletは、--manifest-url=<URL>引数で指定されたファイルを定期的にダウンロードし、Podの定義が含まれたJSON/YAMLファイルとして解釈します。
kubeletは、ファイルシステム上でホストされたマニフェストでの動作方法と同じように、定期的にマニフェストを再取得します。
static Podのリスト中に変更が見つかると、kubeletがその変更を適用します。
このアプローチを採用する場合、次のように設定します:
-
YAMLファイルを作成し、kubeletにファイルのURLを渡せるようにするために、ウェブサーバー上に保存します。
apiVersion: v1 kind: Pod metadata: name: static-web labels: role: myrole spec: containers: - name: web image: nginx ports: - name: web containerPort: 80 protocol: TCP -
選択したノード上のkubeletを
--manifest-url=<manifest-url>を使用して実行することで、このウェブ上のマニフェストを使用するように設定します。 Fedoraの場合、/etc/kubernetes/kubeletに次の行が含まれるように編集します:KUBELET_ARGS="--cluster-dns=10.254.0.10 --cluster-domain=kube.local --manifest-url=<マニフェストのURL>" -
kubeletを再起動します。 Fedoraの場合、次のコマンドを実行します:
# このコマンドは、kubeletが実行中のノード上で実行してください systemctl restart kubelet
static Podの動作を観察する
kubeletが起動すると、定義されたすべてのstatic Podが自動的に起動されます。 static Podを設定してkubeletを再起動したため、すでに新しいstatic Podが実行中になっているはずです。
次のコマンドを(ノード上で)実行することで、(static Podを含む)実行中のコンテナを確認できます:
# このコマンドは、kubeletが実行中のノード上で実行してください
crictl ps
出力は次のようになります:
CONTAINER IMAGE CREATED STATE NAME ATTEMPT POD ID
129fd7d382018 docker.io/library/nginx@sha256:... 11 minutes ago Running web 0 34533c6729106
備考:
crictlは、イメージのURIとSHA-256チェックサムを出力します。
NAMEは次のような形式になります:
docker.io/library/nginx@sha256:0d17b565c37bcbd895e9d92315a05c1c3c9a29f762b011a10c54a66cd53c9b31APIサーバー上では、ミラーPodを確認できます:
kubectl get pods
NAME READY STATUS RESTARTS AGE
static-web-my-node1 1/1 Running 0 2m
備考:
kubeletにAPIサーバー上のミラーPodを作成する権限があることを確認してください。 もし権限がない場合、APIサーバーによって作成のリクエストが拒否されてしまいます。static Podに付けたラベルはミラーPodに伝播します。 ミラーPodに付けたラベルは、通常のPodと同じようにセレクターなどから利用できます。
もしkubectlを使用してAPIサーバーからミラーPodを削除しようとしても、kubeletはstatic Podを削除しません。
kubectl delete pod static-web-my-node1
pod "static-web-my-node1" deleted
Podはまだ実行中であることがわかります。
kubectl get pods
NAME READY STATUS RESTARTS AGE
static-web-my-node1 1/1 Running 0 4s
kubeletが動いているノードに戻って、コンテナを手動で停止してみてください。 しばらくすると、kubeletがそれに気づき、Podを自動的に再起動します。
# このコマンドは、kubeletが実行中のノード上で実行してください
crictl stop 129fd7d382018 # 実際のコンテナIDと置き換えてください
sleep 20
crictl ps
CONTAINER IMAGE CREATED STATE NAME ATTEMPT POD ID
89db4553e1eeb docker.io/library/nginx@sha256:... 19 seconds ago Running web 1 34533c6729106
適切なコンテナを特定したら、crictlを使用してそのコンテナのログを取得できます:
# このコマンドは、コンテナが実行中のノード上で実行してください
crictl logs <container_id>
10.240.0.48 - - [16/Nov/2022:12:45:49 +0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.47.0" "-"
10.240.0.48 - - [16/Nov/2022:12:45:50 +0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.47.0" "-"
10.240.0.48 - - [16/Nove/2022:12:45:51 +0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.47.0" "-"
crictlを使ったデバッグの詳細については、crictlによるKubernetesノードのデバッグを参照してください。
static Podの動的な追加と削除
実行中のkubeletは設定ディレクトリ(この例では/etc/kubernetes/manifests)の変更を定期的にスキャンし、このディレクトリ内にファイルが追加/削除されると、Podの追加/削除を行います。
# これは、ファイルシステムでホストされているstatic Podの設定を使用していることを前提としています
# このコマンドは、コンテナが実行中のノード上で実行してください
#
mv /etc/kubernetes/manifests/static-web.yaml /tmp
sleep 20
crictl ps
# nginxコンテナが実行されていないことを確認できます
mv /tmp/static-web.yaml /etc/kubernetes/manifests/
sleep 20
crictl ps
CONTAINER IMAGE CREATED STATE NAME ATTEMPT POD ID
f427638871c35 docker.io/library/nginx@sha256:... 19 seconds ago Running web 1 34533c6729106
次の項目
21 - 名前空間のラベルを使用してPodセキュリティスタンダードを強制する
名前空間にラベルを付与することで、Podセキュリティスタンダードを強制できます。 privileged、baseline、restrictedの3つのポリシーはセキュリティの幅広い範囲をカバーしており、Podセキュリティアドミッションコントローラーによって実装されています。
始める前に
Podセキュリティアドミッションは、Kubernetes v1.23でベータとしてデフォルトで利用可能になりました。 バージョン1.25以降、Podセキュリティアドミッションは正式リリース(GA)されています。
バージョンを確認するには次のコマンドを実行してください: kubectl version.
名前空間のラベルを使用してbaseline Podセキュリティスタンダードを要求する
以下のマニフェストは、my-baseline-namespaceという名前空間を定義します。
この名前空間は:
baselineポリシーの要件を満たさないPodを ブロック します。restrictedポリシーの要件を満たさないPodが作成された場合、ユーザー向けの警告を生成し、監査アノテーションを追加します。baselineおよびrestrictedポリシーのバージョンをv1.37に固定します。
apiVersion: v1
kind: Namespace
metadata:
name: my-baseline-namespace
labels:
pod-security.kubernetes.io/enforce: baseline
pod-security.kubernetes.io/enforce-version: v1.37
# 望ましい`enforce`レベルに設定しています。
pod-security.kubernetes.io/audit: restricted
pod-security.kubernetes.io/audit-version: v1.37
pod-security.kubernetes.io/warn: restricted
pod-security.kubernetes.io/warn-version: v1.37
kubectl labelを使用して既存の名前空間にラベルを付与する
備考:
enforceポリシー(またはバージョン)のラベルが追加または変更されると、アドミッションプラグインは名前空間内の各Podを新しいポリシーに対してテストします。
違反は警告としてユーザーに返されます。名前空間に対するセキュリティプロファイルの変更を最初に評価する際は、--dry-runフラグを使用すると便利です。
Podセキュリティスタンダードのチェックは dry run モードでも実行されるため、実際にポリシーを更新することなく、新しいポリシーが既存のPodにどのように適用されるかを確認できます。
kubectl label --dry-run=server --overwrite ns --all \
pod-security.kubernetes.io/enforce=baseline
すべての名前空間に適用する
Podセキュリティスタンダードを使い始める場合、最初のステップとしてすべての名前空間にbaselineのようなより厳格なレベルの監査アノテーションを設定するのが適切です:
kubectl label --overwrite ns --all \
pod-security.kubernetes.io/audit=baseline \
pod-security.kubernetes.io/warn=baseline
ここではenforceレベルを設定していないことに注意してください。 これにより、まだ明示的に評価されていない名前空間を区別できます。 enforceレベルが明示的に設定されていない名前空間は、次のコマンドで一覧表示できます:
kubectl get namespaces --selector='!pod-security.kubernetes.io/enforce'
単一の名前空間に適用する
特定の名前空間を更新することもできます。
次のコマンドはmy-existing-namespaceにenforce=restrictedポリシーを追加し、restrictedポリシーのバージョンをv1.37に固定します。
kubectl label --overwrite ns my-existing-namespace \
pod-security.kubernetes.io/enforce=restricted \
pod-security.kubernetes.io/enforce-version=v1.37
22 - PodSecurityPolicyからビルトインのPodセキュリティアドミッションコントローラーに移行する
このページはPodSecurityPolicyからビルトインのPodセキュリティアドミッションコントローラーに移行するための手順について説明します。
この手順は、auditモードやwarnモードとdry-runを組み合わせて用いることで効率的に実施できますが、Podを変更するPSPを利用している場合には難しいものになるかも知れません。
始める前に
作業するKubernetesサーバーは次のバージョン以降のものである必要があります: v1.22.
バージョンを確認するには次のコマンドを実行してください: kubectl version.
Kubernetesバージョン1.37以外が稼働している場合には、実際に走っているKubernetesのバージョンのドキュメントに切り替えて読んだほうが良いかもしれません。
このページはPod Security Admissionの基本コンセプトに馴染みのある方を対象にしています。
アプローチの全体像
PodSecurityPolicyをPod Security Admissionに移行する場合、とりうる戦略は複数存在します。 以下のステップは、実運用環境の停止やセキュリティギャップが生じるリスクを最小化することを目標とする場合の、1つの移行手順の例です。
- Pod Security Admissionがあなたのユースケースに適合するかどうかを判断する
- Namespaceの権限をレビューする
- PodSecurityPolicyをシンプルにして標準化する
- Namespaceを更新する
- 適切なPodのセキュリティ水準を特定する
- Podのセキュリティ水準を検証する
- Podのセキュリティ水準を強制する
- PodSecurityPolicyをバイパスする
- Namespaceの作成プロセスをレビューする
- PodSecurityPolicyを無効化する
0. Pod Security Admissionが正しい選択かどうかを判断する
Pod Security Admissionは、複数のセキュリティ水準の標準的な集合をクラスター全体にわたって提供するもので、そのまま使うだけで最も一般的なセキュリティ要求を満たせるように設計されました。 しかし、PodSecurityPolicyよりも柔軟性に乏しい作りとなっています。 特に、以下の機能はPodSecurityPolicyではサポートされているものの、Pod Security Admissionではサポートされていません。
- デフォルトのsecurity constraintsの設定 - Pod Security AdmissionはValidating Admission Controllerであるため、Podを検証する前にPodを変更しません。 あなたがPSPにおけるdefault security constraintsに依存している場合、ワークロードを修正したり、Mutating Admission Webhookを使ったりして、Pod Securityの制約を満たせるような変更を実施することが必要です。 詳細は、後で述べるPodSecurityPolicyをシンプルにして標準化するを参照してください。
- ポリシー定義のきめ細やかな制御 - Pod Security Admissionは3つのセキュリティ水準のみをサポートします。 特定の制約条件についてさらなる制御が必要な場合には、ポリシーを強制するためにValidating Admission Webhookを使う必要があります。
- sub-namespaceの粒度のポリシー - PodSecurityPolicyは、個々のNamespace内部で異なるサービスアカウントやユーザーに対する異なるポリシーの紐付けが可能です。 この手法にはいくつもの落とし穴があるため推奨されませんが、どうしてもこの性質が必要な場合は、サードパーティーのWebhookをPSPの代わりに利用する必要があるでしょう。 ただし、Pod Security Admissionで静的な適用除外設定をしており、特定のユーザーやRuntimeClassを完全に適用除外とする必要がある場合には、サードパーティーWebhookは必要ないかもしれません。
あなたの全ての要求を満たせない場合であっても、Pod Security Admissionは他のポリシー強制メカニズムに対する 補完的な 仕組みとなるよう設計されており、他のアドミッションWebhookと併用する場合にも有益なフォールバック機構を提供します。
1. Namespaceの権限をレビューする
Pod Security AdmissionはNamespaceのラベルで制御します。 これはNamespaceを更新(もしくは作成やパッチ)できる人物が、同じNamespaceのPodセキュリティ標準を修正できることを意味しており、強固な制限ポリシーを迂回するために利用される可能性があります。 ここから先に進む前に、信頼済みの特権的なユーザーのみがNamespaceに関する権限を有することを確実にしておきましょう。
2. PodSecurityPolicyをシンプルにして標準化する
この節では、Podを変更するPodSecurityPolicyの定義を減らしていき、Podセキュリティ標準のスコープ外のオプションを除去します。
ポリシーの修正前に、編集対象のオリジナルのPodSecurityPolicyについて、オフラインコピーを作成しておくことを推奨します。
複製したPSPの名前には異なる文字を追加しておくべきです。
(例えば名前の先頭に0を追加するなど)。
この段階ではKubernetesに新しいポリシーは作成しないでください。
ポリシーの作成については、この後の更新したポリシーをロールアウトするで説明します。
2.a Podの変更のみを行うフィールドを排除する
あるPodSecurityPolicyがPodを変更する場合、最後にPodSecurityPolicyをオフにした時点で、あなたのPodのセキュリティ水準の要件に適合しないPodが残ってしまう可能性があります。 こうした問題を回避するために、PSPを無効化する前に、PSPによるPodの変更処理を排除しておく必要があります。 残念なことに、PSPはPodを変更する設定項目(mutating field)とPodの検証を行う設定項目(validating field)をきれいに分離できていないため、簡単に移行できるわけではありません。
手始めに、Podの検証処理を損なわないような形で、Pod変更のみを行う設定項目を除去することができます。 PSPでPodの変更のみを行うフィールドは次のとおりです。 (PodSecurityPolicyとPodセキュリティ標準の対応関係にも一覧があります)。
.spec.defaultAllowPrivilegeEscalation.spec.runtimeClass.defaultRuntimeClassName.metadata.annotations['seccomp.security.alpha.kubernetes.io/defaultProfileName'].metadata.annotations['apparmor.security.beta.kubernetes.io/defaultProfileName'].spec.defaultAddCapabilities- 技術的にはPodを変更する設定とPodを検証する設定を兼ねているため、Podを変更せずに同じ検証処理を行える.spec.allowedCapabilitiesにマージすべきです。
注意:
これらのフィールドを除去することにより、必須のフィールドが設定されないワークロードが生じて、問題が発生する可能性があります。 更新したポリシーをロールアウトするを参照して変更を安全にロールアウトするための方法を確認することをお勧めします。2.b. Podセキュリティ標準が対応できないオプションを排除する
PodSecurityPolicyにはPodセキュリティ標準でカバーできない設定項目があります。 このようなオプションを強制する必要がある場合、(この記事のスコープ外の話題ですが)、Pod Security AdmissionをアドミッションWebhookで補強する必要があるでしょう。
まず、Podセキュリティ標準がカバーしない、純粋にPodの検証のみを行う設定項目は除去できます。 この条件に該当するフィールドは以下のとおりです。 (PodSecurityPolicyとPodセキュリティ標準の対応関係には"no opinion"と表記されています)。
.spec.allowedHostPaths.spec.allowedFlexVolumes.spec.allowedCSIDrivers.spec.forbiddenSysctls.spec.runtimeClass
以下のようなPOSIX/UNIXグループの制御に関するフィールドも除去できます。
注意:
いずれかのフィールドがMustRunAs戦略を使っている場合、Podを変更している可能性があります!
これらのフィールドを除去することで、必須のグループ設定がなされていないワークロードが生じ、問題が発生する可能性があります。
更新したポリシーをロールアウトするを参照して、変更を安全にロールアウトするための方法を確認することをお勧めします。.spec.runAsGroup.spec.supplementalGroups.spec.fsGroup
その他のPod変更に関わるフィールドはPodセキュリティ標準を正確にサポートするためには必要なものであるため、ケースバイケースでの取り扱いが求められるでしょう。
.spec.requiredDropCapabilities- RestrictedプロフィールでdropALLするために必要です。.spec.seLinux- (MustRunAsルールがある場合のみPodを変更)Baseline/RestrictedでSELinux関連の要件を強制するために必要です。.spec.runAsUser- (RunAsAnyルールがある場合にはPodを変更しない)RestrictedプロフィールでRunAsNonRootを強制するために必要です。.spec.allowPrivilegeEscalation- (falseの場合にはPodを変更)Restrictedプロフィールで必要です。
2.c. 更新したPSPをロールアウトする
ここからは、クラスターに対して更新したポリシーをロールアウトしていきます。 必須のフィールドが設定されないワークロードを発生させるような変更設定を除去した上で、注意深く進めてください。
更新する個別のPodSecurityPolicyについては
-
オリジナルのPSPが適用されている稼働中のPodを特定してください。
kubernetes.io/pspアノテーションを使うとよいでしょう。 例えば、kubectlを次のように実行します。PSP_NAME="original" #確認したいPSPの名称を入力します kubectl get pods --all-namespaces -o jsonpath="{range .items[?(@.metadata.annotations.kubernetes\.io\/psp=='$PSP_NAME')]}{.metadata.namespace} {.metadata.name}{'\n'}{end}" -
オリジナルのPod specと稼働中のPodを比較して、PodSecurityPolicyがPodを変更したのかどうかを判定してください。 ワークロードリソースが作成したPodについては、Pod specをコントローラーリソースのPodTemplateと比較するとよいでしょう。 変更箇所を特定したら、オリジナルのPodないしはPodTemplateが期待する設定内容となるように更新する必要があります。 レビューが必要なフィールドは以下のとおりです。
.metadata.annotations['container.apparmor.security.beta.kubernetes.io/*'](* をコンテナ名で置き換えてください).spec.runtimeClassName.spec.securityContext.fsGroup.spec.securityContext.seccompProfile.spec.securityContext.seLinuxOptions.spec.securityContext.supplementalGroups.spec.containers[*]ないしは.spec.initContainers[*]配下のコンテナのspecについては次の通り:.securityContext.allowPrivilegeEscalation.securityContext.capabilities.add.securityContext.capabilities.drop.securityContext.readOnlyRootFilesystem.securityContext.runAsGroup.securityContext.runAsNonRoot.securityContext.runAsUser.securityContext.seccompProfile.securityContext.seLinuxOptions
-
新しくPodSecurityPolicyを作成してください。 任意のRoleないしはClusterRoleに全てのPSPを
useする権限を付与すれば、新しいPSPが使われるようになる代わりに、既存のPod変更型のPSPは使われなくなります。 -
認可メカニズムを更新し、新しいPSPへのアクセス権限を付与してください。 これはRBACの更新を意味しており、オリジナルのPSPに対して
use権限があるRoleやClusterRoleを更新し、新しいPSPに対するuse権限を追加付与することにほかなりません。 -
設定を検証しましょう。 多少の猶予期間を設けて、手順1のコマンドに戻り、まだオリジナルのPSPを使っているPodがあるかどうかを見極めましょう。 新規のポリシーのロールアウト後、ポリシーの検証前にPodの再作成が必要となることに注意してください。
-
(オプション)オリジナルのPSPがすでに使われていないことがはっきりしたら、削除しておいてもよいでしょう。
3. Namespaceを更新する
以下の手順はクラスターの全てのNamespaceで実施する必要があります。
この手順に示されている$NAMESPACE変数を使ったコマンドは、更新対象のNamespaceを参照するものです。
3.a. 適切なPodのセキュリティ水準を特定する
Podセキュリティ標準(Pod Security Standards, PSS)のレビューを始めます。 PSSには3つの異なるセキュリティ水準があることに慣れておきましょう。
NamespaceにおけるPodのセキュリティ水準を決定する方法はいくつかあります。
- Namespaceのセキュリティ要求を満たすように決める - 対象のNamespaceで求められるアクセスレベルについて熟知しているのであれば、新しいクラスターに対して実施するのと同様のやり方で、Namespaceの要件に基づいた適切なアクセス水準を選べるはずです。
- 既存のPodSecurityPolicyに基づいて決める - PodSecurityPolicyとPodセキュリティ標準の対応関係のレファレンスを用いることで、それぞれのPSPをPodセキュリティ標準の各セキュリティ水準に対応させることができます。 PSPがPodセキュリティ標準に対応しない場合は、あえて制限の多いレベルにするか、それともPSPと同等程度に許容的なセキュリティ水準に留めておくか、あなたが決定する必要があるかも知れません。
- 既存のPodを見て決める - 下記のPodのセキュリティ水準を検証するの手順を用いると、BaselineおよびRestrictedレベルの両方について、既存のワークロードに対して十分許容的なものかどうかをテストした上で、妥当で最小特権なセキュリティ水準を選択することが可能です。
注意:
上述の選択肢2と3は 既存の Podに基づいて実施するものであるため、現時点で稼働していないワークロードを取りこぼす可能性があります。 例えば、CronJobやレプリカ数0のワークロード、ロールアウトされていないその他のワークロードなどがこうしたものに該当します。3.b. Podのセキュリティ水準を検証する
Namespaceに対するPodのセキュリティ水準を選択したら(ないしは複数検討したら)、まずはテストにかけてみると良いでしょう(Privilegedレベルを用いる場合にはこのステップを省略できます)。 Podセキュリティにはプロファイルの安全なロールアウトを支援するいくつかのツールがあります。
まず紹介するのは、ポリシーのdry-runです。 新たなポリシーを実際に適用せずに、適用予定のポリシーに対してNamespaceで現在稼働しているPodを評価することができます。
# $LEVELはdry-run対象のセキュリティ水準。"baseline"か"restricted"のいずれかの値をとる。
kubectl label --dry-run=server --overwrite ns $NAMESPACE pod-security.kubernetes.io/enforce=$LEVEL
このコマンドは、 現存する Podがセキュリティ水準の要求に適合しなかった場合、警告を返します。
次の選択肢であるauditモードは、稼働していないワークロードを捕捉する上で有用です。 auditモードは(enforcingモードとは対象的に)、Podがポリシーを侵害した場合、その実行を禁止せずに監査ログに記録するため、いくらかの猶予期間の後でログをレビューすることができます。 warningモードはこれと同じような動作をしますが、ユーザーに対して即座に警告を返します。 Namespaceの監査レベルは次のコマンドで設定できます。
kubectl label --overwrite ns $NAMESPACE pod-security.kubernetes.io/audit=$LEVEL
上記いずれかのアプローチが予期せぬポリシー侵害をもたらす場合、侵害的なワークロードがポリシー要求を充足するように更新するか、NamespaceのPodのセキュリティ水準を引き下げる必要があります。
3.c. Podのセキュリティ水準を強制する
選択済みのセキュリティ水準をNamespaceに対して安全に強制できることの確証がもてたら、セキュリティ水準を強制するためにNamespaceを更新します。
kubectl label --overwrite ns $NAMESPACE pod-security.kubernetes.io/enforce=$LEVEL
3.d. PodSecurityPolicyを迂回する
ここまでくれば、 特権PSP をNamespaceの全てのServiceAccountに紐づけて、NamespaceレベルでPodSecurityPolicyを迂回できます。
kubectl apply -f privileged-psp.yaml
kubectl create clusterrole privileged-psp --verb use --resource podsecuritypolicies.policy --resource-name privileged
# Namespace単位での無効化
kubectl create -n $NAMESPACE rolebinding disable-psp --clusterrole privileged-psp --group system:serviceaccounts:$NAMESPACE
特権PSPはPodを変更しません。 PSPのアドミッションコントローラーはPodを変更しないPSPを優先的に利用するため、PodがPodSecurityPolicyによって変更されたり制限されたりしないことが保証できます。
このようにNamespace単位でPodSecurityPolicyを無効化することの利点としては、問題が発生した際にRoleBindingを削除するだけで変更を簡単にロールバックできることです。 もちろん、既存のPodSecurityPolicyが残っていることは確認しておきましょう。
# PodSecurityPolicyの無効化を一旦やめる
kubectl delete -n $NAMESPACE rolebinding disable-psp
4. Namespace作成プロセスをレビューする
この時点で、Pod Security Admissionを強制するための既存Namespaceの更新が完了しています。 新たなNamespaceに対して適切なPodセキュリティプロファイルを確実に適用できるよう、新規にNamespaceを作るための手順とポリシーについても必ず更新しておくべきです。
ラベルのないNamespaceに対するデフォルトの強制、監査、警告レベルを適用するために、Pod Securityアドミッションコントローラーを静的に定義することもできます。 詳しくはアドミッションコントローラーを設定するを読んでください。
5. PodSecurityPolicyを無効化する
PodSecurityPolicyを無効化する準備が整いました。 これを実施するには、APIサーバーのアドミッションコントローラー設定を修正する必要があります。 (アドミッションコントローラーを無効化する方法)
PodSecurityPolicyアドミッションコントローラーが無効化されていることを確認するには、PodSecurityPolicyへのアクセス権限を有しないユーザーになりすましたアクセスや、APIサーバーのログを検証するなどといった、手動のテストを実施するとよいでしょう。 また、APIサーバーの起動時のログには、ロード済みのアドミッションコントローラーの一覧が表示されます。
I0218 00:59:44.903329 13 plugins.go:158] Loaded 16 mutating admission controller(s) successfully in the following order: NamespaceLifecycle,LimitRanger,ServiceAccount,NodeRestriction,TaintNodesByCondition,Priority,DefaultTolerationSeconds,ExtendedResourceToleration,PersistentVolumeLabel,DefaultStorageClass,StorageObjectInUseProtection,RuntimeClass,DefaultIngressClass,MutatingAdmissionWebhook.
I0218 00:59:44.903350 13 plugins.go:161] Loaded 14 validating admission controller(s) successfully in the following order: LimitRanger,ServiceAccount,PodSecurity,Priority,PersistentVolumeClaimResize,RuntimeClass,CertificateApproval,CertificateSigning,CertificateSubjectRestriction,DenyServiceExternalIPs,ValidatingAdmissionWebhook,ResourceQuota.
(Validating Admission Controllerの中に)PodSecurityが確認できるはずです。
また、いずれの行もPodSecurityPolicyを含まないはずです。
PSPアドミッションコントローラーを無効化したら、(また、ロールバックが必要ないと判断するのに十分な時間が経過したら)、PodSecurityPolicyと関連するRoleやClusterRole、ClusterRoleBindingを削除してもよいでしょう。 (他の無関係な権限付与に使われていないことを確認しておいてください)。