これは、このセクションの複数ページの印刷可能なビューです。 印刷するには、ここをクリックしてください.

このページの通常のビューに戻る.

コンテナ

アプリケーションとランタイムの依存関係を一緒にパッケージ化するための技術

実行するそれぞれのコンテナは繰り返し使用可能です。依存関係を含めて標準化されており、どこで実行しても同じ動作が得られることを意味しています。

コンテナは基盤となるホストインフラからアプリケーションを切り離します。これにより、さまざまなクラウドやOS環境下でのデプロイが容易になります。

コンテナイメージ

コンテナイメージはすぐに実行可能なソフトウェアパッケージで、アプリケーションの実行に必要なものをすべて含んています。コードと必要なランタイム、アプリケーションとシステムのライブラリ、そして必須な設定項目のデフォルト値を含みます。

設計上、コンテナは不変で、既に実行中のコンテナのコードを変更することはできません。コンテナ化されたアプリケーションがあり変更したい場合は、変更を含んだ新しいイメージをビルドし、コンテナを再作成して、更新されたイメージから起動する必要があります。

コンテナランタイム

コンテナランタイムは、コンテナの実行を担当するソフトウェアです。

Kubernetesは次の複数のコンテナランタイムをサポートします。 DockercontainerdCRI-O、 および全ての Kubernetes CRI (Container Runtime Interface) 実装です。

次の項目

1 - イメージ

コンテナイメージは、アプリケーションおよびそのすべてのソフトウェア依存関係を含むバイナリデータを表します。 コンテナイメージは、スタンドアロンで実行可能なソフトウェアバンドルで、動作するためのランタイム環境が明確に規定されているのが特徴です。

通常、アプリケーションのコンテナイメージを作成してレジストリにプッシュし、その後、Podから参照します。

このページでは、コンテナイメージの概要を説明します。

イメージ名

コンテナイメージは通常、pauseexample/mycontainer、またはkube-apiserverのような名前がつけられます。 イメージには、レジストリのホスト名を含めることもできます。たとえば、fictional.registry.example/imagenameのようになります。また、同じようにポート番号を含めることもでき、その場合はfictional.registry.example:10443/imagenameのようになります。

レジストリのホスト名を指定しない場合、KubernetesはDockerパブリックレジストリを意味しているものと見なします。 この挙動は、コンテナランタイムの設定でデフォルトのイメージレジストリを指定することで変更できます。

イメージ名の後には、タグダイジェスト を追加できます(これはdockerpodmanなどのコマンドを使う場合と同様です)。 タグは、同じ系列のイメージの異なるバージョンを識別するために使用します。 ダイジェストは、イメージの特定のバージョンに対する一意の識別子であり、イメージの内容に基づくハッシュで構成され、変更不可能です。 タグは異なるイメージを指すように移動が可能ですが、ダイジェストは固定です。

イメージタグには、小文字および大文字のアルファベット、数字、アンダースコア(_)、ピリオド(.)、ハイフン(-)を使用できます。 タグの長さは最大128文字で、次の正規表現パターンに従う必要があります: [a-zA-Z0-9_][a-zA-Z0-9._-]{0,127}。 この仕様の詳細や検証用の正規表現については、OCI Distribution Specificationを参照してください。 タグを指定しない場合、Kubernetesはlatestタグを指定したものと見なします。

イメージダイジェストは、ハッシュアルゴリズム(sha256など)とハッシュ値で構成されます。 たとえば、sha256:1ff6c18fbef2045af6b9c16bf034cc421a29027b800e4f9b68ae9b1cb3e9ae07のようになります。 ダイジェスト形式の詳細について詳しく知りたい場合は、OCI Image Specificationを参照してください。

Kubernetesで使用可能なイメージ名の例は次のとおりです:

  • busybox — イメージ名のみで、タグやダイジェストは指定されていません。KubernetesはDockerパブリックレジストリとlatestタグを使用します。docker.io/library/busybox:latestと同等です。
  • busybox:1.32.0 — タグ付きのイメージ名。KubernetesはDockerパブリックレジストリを使用します。docker.io/library/busybox:1.32.0と同等です。
  • registry.k8s.io/pause:latest — カスタムレジストリとlatestタグを指定したイメージ名。
  • registry.k8s.io/pause:3.5 — カスタムレジストリと非latestタグを指定したイメージ名。
  • registry.k8s.io/pause@sha256:1ff6c18fbef2045af6b9c16bf034cc421a29027b800e4f9b68ae9b1cb3e9ae07 — ダイジェストを含むイメージ名。
  • registry.k8s.io/pause:3.5@sha256:1ff6c18fbef2045af6b9c16bf034cc421a29027b800e4f9b68ae9b1cb3e9ae07 — タグとダイジェストの両方を含むイメージ名。プル時にはダイジェストのみが使用されます。

イメージの更新

PodTemplateを含むDeploymentStatefulSet、Pod、またはその他のオブジェクトを初めて作成する際に、プルポリシーが明示的に指定されていない場合、デフォルトでそのPod内のすべてのコンテナのプルポリシーはIfNotPresentに設定されます。 このポリシーでは、対象のイメージがすでに存在する場合、kubeletはそのイメージのプルをスキップします。

イメージプルポリシー

コンテナのimagePullPolicyとイメージのタグの両方が、kubeletが指定されたイメージのプル(ダウンロード)を試みる タイミング に影響します。

以下は、imagePullPolicyに設定できる値とその効果の一覧です。

IfNotPresent
イメージがローカルにまだ存在しない場合にのみプルされます。
Always
kubeletがコンテナを起動するたびに、コンテナイメージレジストリに問い合わせ、イメージ名をイメージダイジェストに解決します。 kubeletがそのダイジェストに完全一致するイメージをローカルにキャッシュしている場合は、そのキャッシュされたイメージを使用します。存在しない場合は、kubeletは解決されたダイジェストのイメージをプルし、そのイメージを使ってコンテナを起動します。
Never
kubeletは、イメージを取得しようとしません。何らかの理由でローカルにイメージがすでに存在する場合、kubeletはコンテナを起動しようとします。それ以外の場合、起動に失敗します。 詳細は、事前にプルされたイメージを参照してください。

レジストリに確実にアクセスできるのであれば、基盤となるイメージプロバイダーのキャッシュセマンティクスによりimagePullPolicy: Alwaysでも効率的です。 コンテナランタイムは、イメージレイヤーがすでにノード上に存在することを認識できるので、再度ダウンロードする必要がありません。

Podがいつも同じバージョンのコンテナイメージを使用するようにするためには、イメージのダイジェストを指定します。<image-name>:<tag><image-name>@<digest>に置き換えてください(たとえば、image@sha256:45b23dee08af5e43a7fea6c4cf9c25ccf269ee113168c19722f87876677c5cb2)。

イメージタグを使用している場合、レジストリ側でそのタグが指すコードが変更されると、古いコードと新しいコードを実行するPodが混在する可能性があります。 イメージダイジェストは特定のバージョンのイメージを一意に識別するため、Kubernetesは特定のイメージ名とダイジェストが指定されたコンテナを起動するたびに同じコードを実行します。 イメージをダイジェストで指定することで、実行するコードのバージョンが固定され、レジストリ側の変更によってバージョンが混在する事態を防ぐことができます。

サードパーティー製のアドミッションコントローラーの中には、Pod(およびPodTemplate)の作成時にそれらを変更し、実行されるワークロードがタグではなくイメージのダイジェストに基づいて定義されるようにするものがあります。 レジストリでどのようなタグの変更があっても、すべてのワークロードが必ず同じコードを実行するようにしたい場合に有用かもしれません。

デフォルトのイメージプルポリシー

あなた(またはコントローラー)が新しいPodをAPIサーバーに送信すると、特定の条件が満たされた場合に、クラスターはimagePullPolicyフィールドを設定します。

  • imagePullPolicyフィールドを省略し、かつコンテナイメージにダイジェストを指定した場合、imagePullPolicyには自動的にIfNotPresentに設定される。
  • imagePullPolicyフィールドを省略し、コンテナイメージのタグに:latestを指定した場合、imagePullPolicyには自動的にAlwaysが設定される。
  • imagePullPolicyフィールドを省略し、コンテナイメージのタグを指定しなかった場合、imagePullPolicyには自動的にAlwaysが設定される。
  • imagePullPolicyフィールドを省略し、コンテナイメージのタグに:latest以外を指定した場合、imagePullPolicyには自動的にIfNotPresentが設定される。

イメージプルを強制する

常に強制的にプルしたい場合は、以下のいずれかを実行できます:

  • コンテナのimagePullPolicyAlwaysを設定する。
  • imagePullPolicyを省略し、使用するイメージのタグに:latestを指定する(KubernetesはPodを送信する際にポリシーをAlwaysに設定します)。
  • imagePullPolicyと使用するイメージのタグを省略する(KubernetesはPodを送信する際にポリシーをAlwaysに設定します)。
  • AlwaysPullImagesアドミッションコントローラーを有効にする。

ImagePullBackOff

kubeletがコンテナランタイムを使ってPodのコンテナの作成を開始するとき、ImagePullBackOffのためにコンテナがWaiting状態になる可能性があります。

ImagePullBackOff状態は、Kubernetesがコンテナイメージをプルできず、コンテナを開始できないことを意味します(イメージ名が無効である、imagePullSecret無しでプライベートレジストリからプルしたなどの理由のため)。BackOffは、バックオフの遅延を増加させながらKubernetesがイメージをプルしようとし続けることを示します。

Kubernetesは、組み込まれた制限である300秒(5分)に達するまで、試行するごとに遅延を増加させます。

ランタイムクラスごとのイメージプル

FEATURE STATE: Kubernetes v1.29 [alpha] (enabled by default: false)
Kubernetesには、PodのRuntimeClassに基づいてイメージをプルするアルファ機能のサポートが含まれています。

RuntimeClassInImageCriApiフィーチャーゲートを有効にすると、kubeletはイメージ名やダイジェストだけでなく、イメージ名とランタイムハンドラーのタプルでコンテナイメージを参照するようになります。 コンテナランタイム は、選択されたランタイムハンドラーに基づいて動作を変更する可能性があります。 ランタイムクラスに応じたイメージプルを行う機能は、Windows Hyper-VコンテナのようなVMベースのコンテナにおいて有用です。

直列・並列イメージプル

デフォルトでは、kubeletはイメージを直列にプルします。 言い換えれば、kubeletはイメージサービスに対して一度に1つのイメージプル要求しか送信しません。 他のイメージプル要求は、処理中の要求が完了するまで待機する必要があります。

ノードは、イメージのプルを他のノードと独立して判断します。そのため、イメージプルを直列で実行していても、異なるノード上では同じイメージを並列でプルすることが可能です。

並列イメージプルを有効にしたい場合は、kubeletの設定serializeImagePullsフィールドをfalseに設定します。 serializeImagePullsをfalseにすると、イメージプル要求は即座にイメージサービスへ送信され、複数のイメージが同時にプルされるようになります。

並列イメージプルを有効にする場合は、使用しているコンテナランタイムのイメージサービスが並列プルに対応していることを確認してください。

なお、kubeletは1つのPodに対して複数のイメージを並列でプルすることはありません。 たとえば、1つのPodがinitコンテナとアプリケーションコンテナを持つ場合、その二つのコンテナのイメージプルは並列化されません。 しかし、異なるPodがそれぞれ異なるイメージを使用しており、並列イメージプル機能が有効になっている場合、kubeletはその2つの異なるPodのためにイメージを並列でプルします。

最大並行イメージプル数

FEATURE STATE: Kubernetes v1.32 [beta]

serializeImagePullsがfalseに設定されている場合、kubeletはデフォルトで同時にプルできるイメージ数に制限を設けません。 並行でプルできるイメージ数を制限したい場合は、kubeletの設定でmaxParallelImagePullsフィールドを指定します。 maxParallelImagePullsn を設定すると、同時にプルできるイメージは最大で n 件となり、n 件を超えるイメージプルは、少なくとも1件のイメージプルが完了するまで待機する必要があります。

並列イメージプルを有効にしている場合、同時プル数を制限することで、イメージのプルによるネットワーク帯域やディスクI/Oの過剰な消費を防ぐことができます。

maxParallelImagePullsには1以上の正の整数を指定できます。 maxParallelImagePullsを2以上に設定する場合は、serializeImagePullsをfalseに設定する必要があります。 無効なmaxParallelImagePullsの設定を行うと、kubeletは起動に失敗します。

イメージインデックスを用いたマルチアーキテクチャイメージ

コンテナレジストリはバイナリイメージの提供だけでなく、コンテナイメージインデックスも提供可能です。 イメージインデックスはコンテナのアーキテクチャ固有バージョンに関する複数のイメージマニフェストを指すことができます。 イメージには(たとえばpauseexample/mycontainerkube-apiserverなどの)名前を付け、各システムが自身のマシンアーキテクチャに適したバイナリイメージを取得できるようにする、という考え方です。

Kubernetesプロジェクトでは、通常、リリースごとに-$(ARCH)というサフィックスを含む名前でコンテナイメージを作成します。 後方互換性のために、従来の形式のサフィックス付きイメージも生成されます。 たとえば、pauseという名前のイメージは、サポートされているすべてのアーキテクチャ向けのマニフェストを含むマルチアーキテクチャ対応のイメージですが、pause-amd64は旧来の構成や、サフィックス付きのイメージ名をハードコードしているYAMLファイルとの互換性のために用意されたイメージです。

プライベートレジストリの使用

プライベートレジストリでは、イメージの検索やプルを行うために認証が必要となる場合があります。 認証情報は、以下のいくつかの方法で提供できます:

これらのオプションについて、以下で詳しく説明します。

PodでimagePullSecretsを指定する

Kubernetesは、Podに対してコンテナイメージレジストリ用のキーを指定できます。 すべてのimagePullSecretsは、そのPodと同じNamespace内に存在するSecretでなければなりません。 これらのSecretは、型がkubernetes.io/dockercfgまたはkubernetes.io/dockerconfigjsonである必要があります。

ノードを構成してプライベートレジストリに対して認証を行う

認証情報の具体的な設定手順は、使用するコンテナランタイムやレジストリによって異なります。 最も正確な情報については、使用しているソリューションのドキュメントを参照してください。

プライベートコンテナイメージレジストリの構成例については、イメージをプライベートレジストリから取得するを参照してください。 この例では、Docker Hubのプライベートレジストリを使用しています。

kubelet credential providerによる認証付きイメージプル

kubeletを構成して、プラグインバイナリを呼び出し、コンテナイメージのレジストリ認証情報を動的に取得させることができます。 これは、プライベートレジストリ用の認証情報を取得するための最も堅牢かつ柔軟な方法ですが、有効化するにはkubeletレベルでの設定が必要です。

この手法は、プライベートレジストリにホストされたコンテナイメージを必要とするStatic Podを実行する際に特に有用です。 ServiceAccountSecretを使ってプライベートレジストリの認証情報を提供することは、Static Podの仕様で不可能です。 Static Podは、その仕様として他のAPIリソースへの参照を含めることが できない ためです。

詳細については、kubelet image credential providerを設定するを参照してください。

config.jsonの解釈

config.jsonの解釈は、元のDockerの実装とKubernetesにおける解釈で異なります。 Dockerでは、authsキーにはルートURLしか指定できませんが、Kubernetesではワイルドカード形式のURLや接頭辞一致のパスも許容されます。 唯一の制約は、ワイルドカード(*)を使用する場合、各サブドメインに対して.を含める必要があるという点です。 一致するサブドメインの数は、指定されたワイルドカードパターンの数(*.)と一致している必要があります。 例:

  • *.kubernetes.ioは、kubernetes.ioには一致 しません が、abc.kubernetes.ioには一致します。
  • *.*.kubernetes.ioは、abc.kubernetes.ioには一致 しません が、abc.def.kubernetes.ioには一致します。
  • prefix.*.ioは、prefix.kubernetes.ioに一致します。
  • *-good.kubernetes.ioは、prefix-good.kubernetes.ioに一致します。

つまり、次のようなconfig.jsonは有効です:

{
    "auths": {
        "my-registry.example/images": { "auth": "…" },
        "*.my-registry.example/images": { "auth": "…" }
    }
}

イメージプル操作では、すべての有効なパターンに対して、認証情報がCRIコンテナランタイムに渡されます。 たとえば、次のようなコンテナイメージ名は正常にマッチします。

  • my-registry.example/images
  • my-registry.example/images/my-image
  • my-registry.example/images/another-image
  • sub.my-registry.example/images/my-image

しかし、次のようなコンテナイメージ名はマッチ しません

  • a.sub.my-registry.example/images/my-image
  • a.b.sub.my-registry.example/images/my-image

kubeletは、見つかった各認証情報に対してイメージプルを順番に実行します。 つまり、config.json内に異なるパスに対する複数のエントリを含めることも可能です。

{
    "auths": {
        "my-registry.example/images": {
            "auth": "…"
        },
        "my-registry.example/images/subpath": {
            "auth": "…"
        }
    }
}

このとき、コンテナがmy-registry.example/images/subpath/my-imageというイメージをプルするよう指定している場合、kubeletは、いずれかの認証元で失敗した場合でも、両方の認証情報を使ってイメージのダウンロードを試みます。

事前にプルされたイメージ

デフォルトでは、kubeletは指定されたレジストリからそれぞれのイメージをプルしようとします。 ただし、コンテナのimagePullPolicyプロパティがIfNotPresentまたはNeverに設定されている場合は、ローカルのイメージが(それぞれ優先的に、あるいは専用で)使用されます。

レジストリ認証の代替として事前にプルされたイメージを利用したい場合、クラスターのすべてのノードが同じ事前にプルされたイメージを持っていることを確認する必要があります。

これは、特定のイメージをあらかじめロードしておくことで高速化したり、プライベートレジストリへの認証の代替手段として利用したりすることができます。

kubelet credential providerの利用と同様に、 事前にプルされたイメージは、プライベートレジストリにホストされたイメージに依存するStatic Podを起動する場合にも適しています。

イメージプルの認証情報の検証を保証する

FEATURE STATE: Kubernetes v1.33 [alpha] (enabled by default: false)

クラスターでKubeletEnsureSecretPulledImagesフィーチャーゲートが有効になっている場合、Kubernetesは、プルに認証が必要なすべてのイメージに対して、たとえそのイメージがノード上にすでに存在していても、認証情報を検証します。 この検証により、Podが要求するイメージのうち、指定された認証情報で正常にプルされなかったものは、レジストリから再度プルする必要があることが保証されます。 さらに、以前に成功したイメージプルと同じ認証情報を使用する場合には、再プルは不要で、レジストリにアクセスせずローカルで検証が行われます(該当のイメージがローカルに存在する場合)。 この動作は、kubeletの設定におけるimagePullCredentialsVerificationPolicyフィールドによって制御されます。

この設定は、イメージがすでにノード上に存在する場合に、イメージプルの認証情報を検証する必要があるかどうかの挙動を制御します:

  • NeverVerify: このフィーチャーゲートが無効な場合と同じ動作を模倣します。イメージがローカルに存在する場合、イメージプルの認証情報は検証されません。
  • NeverVerifyPreloadedImages: kubeletの外部でプルされたイメージは検証されませんが、それ以外のすべてのイメージについては認証情報が検証されます。これがデフォルトの動作です。
  • NeverVerifyAllowListedImages: kubeletの外部でプルされたイメージと、kubelet設定内で指定されたpreloadedImagesVerificationAllowlistに記載されたイメージは検証されません。
  • AlwaysVerify: すべてのイメージは、使用前に認証情報の検証が行われます。

この検証は、事前にプルされたイメージ、ノード全体のSecretを使用してプルされたイメージ、PodレベルのSecretを使用してプルされたイメージに適用されます。

Docker設定を用いたSecretの作成

レジストリに対して認証を行うには、ユーザー名、レジストリのパスワード、クライアントのメールアドレス、およびレジストリのホスト名を把握しておく必要があります。 プレースホルダーを適切な値に置換したうえで、以下のコマンドを実行してください。

kubectl create secret docker-registry <name> \
  --docker-server=<docker-registry-server> \
  --docker-username=<docker-user> \
  --docker-password=<docker-password> \
  --docker-email=<docker-email>

すでにDockerの認証情報ファイルを持っている場合は、上記のコマンドを使用する代わりに、その認証情報ファイルをKubernetesのSecretとしてインポートすることができます。 既存のDocker認証情報に基づいてSecretを作成するに、その設定方法が説明されています。

これは、複数のプライベートコンテナレジストリを使用している場合に特に有用です。 kubectl create secret docker-registryで作成されるSecretは、単一のプライベートレジストリにしか対応していないためです。

PodでimagePullSecretsを参照する

次に、Pod定義にimagePullSecretsセクションを追加することで、そのSecretを参照するPodを作成できます。 imagePullSecrets配列の各要素は、同じNamespace内の1つのSecretのみを参照できます。

たとえば、以下のように記述します:

cat <<EOF > pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: foo
  namespace: awesomeapps
spec:
  containers:
    - name: foo
      image: janedoe/awesomeapp:v1
  imagePullSecrets:
    - name: myregistrykey
EOF

cat <<EOF >> ./kustomization.yaml
resources:
- pod.yaml
EOF

この作業は、プライベートレジストリを使用する各Podごとに実施する必要があります。

ただし、ServiceAccountリソースの中でimagePullSecretsセクションを指定することで、この手順を自動化することが可能です。 詳細な手順については、ServiceAccountにImagePullSecretsを追加するを参照してください。

また、各ノードにある.docker/config.jsonと併用することもできます。 これらの認証情報はマージされて使用されます。

ユースケース

プライベートレジストリを構成するにはいくつかの手段があります。 ここでは、いくつかの一般的なユースケースと推奨される解決方法を示します。

  1. 非専有(たとえば、オープンソースの)イメージだけを実行し、イメージを非公開にする必要がないクラスターの場合

    • パブリックレジストリのパブリックイメージを利用する。
      • 設定は必要ない。
      • 一部のクラウドプロバイダーは、パブリックイメージを自動的にキャッシュまたはミラーリングすることで、可用性を向上させ、イメージのプルにかかる時間を短縮する。
  2. 社外には非公開にすべきだが、クラスターユーザー全員には見える必要がある専有イメージを実行しているクラスターの場合

    • ホスティング型のプライペートレジストリを使用する。
      • プライベートレジストリにアクセスする必要があるノードには、手動設定が必要となる場合がある。
    • または、ファイアウォールの内側で内部向けのプライベートレジストリを実行し、読み取りアクセスを開放して運用する。
      • Kubernetesの設定は必要ない。
    • イメージへのアクセスを制御できるホスティング型のコンテナイメージレジストリサービスを利用する。
      • ノードを手動で構成する場合よりも、ノードのオートスケーリングと組み合わせた方がうまく機能する。
    • あるいは、ノードの構成を変更するのが困難なクラスターでは、imagePullSecretsを使用する。
  3. 一部に、より厳格なアクセス制御を必要とする専有イメージを含むクラスターの場合

    • AlwaysPullImagesアドミッションコントローラーが有効化されていることを確認する。これが無効な場合、すべてのPodがすべてのイメージにアクセスできてしまう可能性がある。
    • 機密データはイメージ内に含める代わりに、Secretリソースに移行する。
  4. それぞれのテナントが独自のプライベートレジストリを必要とするマルチテナントのクラスターである場合

    • AlwaysPullImagesアドミッションコントローラーが有効化されていることを確認する。これが無効な場合、すべてのPodがすべてのイメージにアクセスできてしまう可能性がある。
    • 認証が必要なプライベートレジストリを運用する。
    • 各テナントごとにレジストリの認証情報を生成し、それをSecretに保存して、各テナントのNamespaceへ配布する。
    • テナントは、そのSecretを各NamespaceのimagePullSecretsに追加する。

複数のレジストリへのアクセスが必要な場合、レジストリごとに1つのSecretを作成する事ができます。

レガシーな組み込みkubelet credential provider

古いバージョンのKubernetesでは、kubeletがクラウドプロバイダーの認証情報と直接統合されていました。 これにより、イメージレジストリの認証情報を動的に取得することが可能でした。

このkubelet credential provider統合には、以下の3つの組み込み実装がありました: ACR(Azure Container Registry)、ECR(Elastic Container Registry)、GCR(Google Container Registry)です。

Kubernetesバージョン1.26以降では、このレガシーな仕組みは削除されたため、以下のいずれかの対応が必要です:

  • 各ノードにkubelet image credential providerを構成する
  • imagePullSecretsと少なくとも1つのSecretを使用して、イメージプルの認証情報を指定する

次の項目

2 - コンテナ環境

このページでは、コンテナ環境で利用可能なリソースについて説明します。

コンテナ環境

Kubernetesはコンテナにいくつかの重要なリソースを提供します。

  • イメージと1つ以上のボリュームの組み合わせのファイルシステム
  • コンテナ自体に関する情報
  • クラスター内の他のオブジェクトに関する情報

コンテナ情報

コンテナの ホスト名 は、コンテナが実行されているPodの名前です。 ホスト名はhostnameコマンドまたはlibcのgethostname関数呼び出しにより利用可能です。

Podの名前と名前空間はdownward APIを通じて環境変数として利用可能です。

Pod定義からのユーザー定義の環境変数もコンテナで利用できます。 コンテナイメージで静的に指定されている環境変数も同様です。

クラスター情報

コンテナの作成時に実行されていたすべてのサービスのリストは、環境変数として使用できます。 このリストは、新しいコンテナのPodおよびKubernetesコントロールプレーンサービスと同じ名前空間のサービスに制限されます。

bar という名前のコンテナに対応する foo という名前のサービスの場合、以下の変数が定義されています。

FOO_SERVICE_HOST=<サービスが実行されているホスト>
FOO_SERVICE_PORT=<サービスが実行されているポート>

サービスは専用のIPアドレスを持ち、DNSアドオンが有効の場合、DNSを介してコンテナで利用可能です。

次の項目

3 - ランタイムクラス(Runtime Class)

FEATURE STATE: Kubernetes v1.20 [stable]

このページではRuntimeClassリソースと、runtimeセクションのメカニズムについて説明します。

RuntimeClassはコンテナランタイムの設定を選択するための機能です。そのコンテナランタイム設定はPodのコンテナを稼働させるために使われます。

RuntimeClassを使う動機

異なるPodに異なるRuntimeClassを設定することで、パフォーマンスとセキュリティのバランスをとることができます。例えば、ワークロードの一部に高レベルの情報セキュリティ保証が必要な場合、ハードウェア仮想化を使用するコンテナランタイムで実行されるようにそれらのPodをスケジュールすることを選択できます。その後、追加のオーバーヘッドを犠牲にして、代替ランタイムをさらに分離することでメリットが得られます。

RuntimeClassを使用して、コンテナランタイムは同じで設定が異なるPodを実行することもできます。

セットアップ

  1. ノード上でCRI実装を設定する。(ランタイムに依存)
  2. 対応するRuntimeClassリソースを作成する。

1. ノード上でCRI実装を設定する

RuntimeClassを通じて利用可能な設定はContainer Runtime Interface (CRI)の実装依存となります。 ユーザーの環境のCRI実装の設定方法は、対応するドキュメント(下記)を参照ください。

RuntimeClassの設定は、RuntimeClassによって参照されるハンドラー名を持ちます。そのハンドラーは有効なDNSラベル名でなくてはなりません。

2. 対応するRuntimeClassリソースを作成する

ステップ1にて設定する各項目は、関連するハンドラー 名を持ちます。それはどの設定かを指定するものです。各ハンドラーにおいて、対応するRuntimeClassオブジェクトが作成されます。

そのRuntimeClassリソースは現時点で2つの重要なフィールドを持ちます。それはRuntimeClassの名前(metadata.name)とハンドラー(handler)です。そのオブジェクトの定義は下記のようになります。

# RuntimeClassはnode.k8s.ioというAPIグループで定義されます。
apiVersion: node.k8s.io/v1
kind: RuntimeClass
metadata:
  # RuntimeClass名
  # RuntimeClassはネームスペースなしのリソースです。
  name: myclass
# 対応するCRI設定
handler: myconfiguration

RuntimeClassオブジェクトの名前はDNSサブドメイン名に従う必要があります。

使用例

RuntimeClassがクラスターに対して設定されると、PodSpecでruntimeClassNameを指定して使用できます。 例えば

apiVersion: v1
kind: Pod
metadata:
  name: mypod
spec:
  runtimeClassName: myclass
  # ...

これは、kubeletに対してPodを稼働させるためのRuntimeClassを使うように指示します。もし設定されたRuntimeClassが存在しない場合や、CRIが対応するハンドラーを実行できない場合、そのPodはFailedというフェーズになります。 エラーメッセージに関しては対応するイベントを参照して下さい。

もしruntimeClassNameが指定されていない場合、デフォルトのRuntimeHandlerが使用され、これはRuntimeClassの機能が無効であるときのふるまいと同じものとなります。

CRIの設定

CRIランタイムのセットアップに関するさらなる詳細は、コンテナランタイムを参照してください。

containerd

ランタイムハンドラーは、/etc/containerd/config.tomlにあるcontainerdの設定ファイルにより設定されます。 正しいハンドラーは、そのruntimeセクションで設定されます。

[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.${HANDLER_NAME}]

詳細はcontainerdの設定に関するドキュメントを参照してください。

CRI-O

ランタイムハンドラーは、/etc/crio/crio.confにあるCRI-Oの設定ファイルにより設定されます。 正しいハンドラーはcrio.runtime tableで設定されます。

[crio.runtime.runtimes.${HANDLER_NAME}]
  runtime_path = "${PATH_TO_BINARY}"

詳細はCRI-Oの設定に関するドキュメントを参照してください。

スケジューリング

FEATURE STATE: Kubernetes v1.16 [beta]

RuntimeClassのschedulingフィールドを指定することで、設定されたRuntimeClassをサポートするノードにPodがスケジューリングされるように制限することができます。 schedulingが設定されていない場合、このRuntimeClassはすべてのノードでサポートされていると仮定されます。

特定のRuntimeClassをサポートしているノードへPodが配置されることを保証するために、各ノードはruntimeclass.scheduling.nodeSelectorフィールドによって選択される共通のラベルを持つべきです。 RuntimeClassのnodeSelectorはアドミッション機能によりPodのnodeSelectorに統合され、効率よくノードを選択します。 もし設定が衝突した場合は、Pod作成は拒否されるでしょう。

もしサポートされているノードが他のRuntimeClassのPodが稼働しないようにtaint付与されていた場合、RuntimeClassに対してtolerationsを付与することができます。 nodeSelectorと同様に、tolerationsはPodのtolerationsにアドミッション機能によって統合され、効率よく許容されたノードを選択します。

ノードの選択とtolerationsについての詳細はノード上へのPodのスケジューリングを参照してください。

Podオーバーヘッド

FEATURE STATE: Kubernetes v1.24 [stable]

Podが稼働する時に関連する オーバーヘッド リソースを指定できます。オーバーヘッドを宣言すると、クラスター(スケジューラーを含む)がPodとリソースに関する決定を行うときにオーバーヘッドを考慮することができます。

PodのオーバーヘッドはRuntimeClass内のoverheadフィールドによって定義されます。 このフィールドを使用することで、RuntimeClassを使用して稼働するPodのオーバーヘッドを指定することができ、Kubernetes内部で使用されるオーバーヘッドを確保することができます。

次の項目

4 - コンテナライフサイクルフック

このページでは、kubeletにより管理されるコンテナがコンテナライフサイクルフックフレームワークを使用して、管理ライフサイクル中にイベントによって引き起こされたコードを実行する方法について説明します。

概要

Angularなどのコンポーネントライフサイクルフックを持つ多くのプログラミング言語フレームワークと同様に、Kubernetesはコンテナにライフサイクルフックを提供します。 フックにより、コンテナは管理ライフサイクル内のイベントを認識し、対応するライフサイクルフックが実行されたときにハンドラーに実装されたコードを実行できます。

コンテナフック

コンテナに公開されている2つのフックがあります。

PostStart

このフックはコンテナが作成された直後に実行されます。 しかし、フックがコンテナのENTRYPOINTの前に実行されるという保証はありません。 ハンドラーにパラメーターは渡されません。

PreStop

このフックは、APIからの要求、またはliveness/startup probeの失敗、プリエンプション、リソース競合などの管理イベントが原因でコンテナが終了する直前に呼び出されます。コンテナがすでに終了状態または完了状態にある場合にはPreStopフックの呼び出しは失敗し、コンテナを停止するTERMシグナルが送信される前にフックは完了する必要があります。PreStopフックが実行される前にPodの終了猶予期間のカウントダウンが開始されるので、ハンドラーの結果に関わらず、コンテナはPodの終了猶予期間内に最終的に終了します。 ハンドラーにパラメーターは渡されません。

終了動作の詳細な説明は、Termination of Podsにあります。

フックハンドラーの実装

コンテナは、フックのハンドラーを実装して登録することでそのフックにアクセスできます。 コンテナに実装できるフックハンドラーは3種類あります。

  • Exec - コンテナのcgroupsと名前空間の中で、 pre-stop.shのような特定のコマンドを実行します。 コマンドによって消費されたリソースはコンテナに対してカウントされます。
  • HTTP - コンテナ上の特定のエンドポイントに対してHTTP要求を実行します。
  • Sleep - 指定された期間コンテナを一時停止します。これは、PodLifecycleSleepActionフィーチャーゲートによりデフォルトで有効になっているベータ機能です。

フックハンドラーの実行

コンテナライフサイクル管理フックが呼び出されると、Kubernetes管理システムはフックアクションにしたがってハンドラーを実行します。 httpGettcpSocket(非推奨です)、およびsleepはkubeletプロセスによって実行され、execはコンテナの中で実行されます。

フックハンドラーの呼び出しは、コンテナを含むPodのコンテキスト内で同期しています。 これは、PostStartフックの場合、コンテナのENTRYPOINTとフックは非同期に起動することを意味します。 しかし、フックの実行に時間がかかりすぎたりハングしたりすると、コンテナはrunning状態になることができません。

PreStopフックはコンテナを停止するシグナルから非同期で実行されるのではなく、TERMシグナルが送られる前に実行を完了する必要があります。 もしPreStopフックが実行中にハングした場合、PodはTerminating状態になり、 terminationGracePeriodSecondsの時間切れで強制終了されるまで続きます。 この猶予時間は、PreStopフックが実行され正常にコンテナを停止できるまでの合計時間に適用されます。 例えばterminationGracePeriodSecondsが60で、フックの終了に55秒かかり、シグナルを受信した後にコンテナを正常に停止させるのに10秒かかる場合、コンテナは正常に停止する前に終了されてしまいます。terminationGracePeriodSecondsが、これら2つの実行にかかる合計時間(55+10)よりも短いからです。

PostStartまたはPreStopフックが失敗した場合、コンテナは強制終了します。

ユーザーはフックハンドラーをできるだけ軽量にするべきです。 ただし、コンテナを停止する前に状態を保存するなどの場合は、長時間のコマンド実行が必要なケースもあります。

フック配信保証

フックの配信は 少なくとも1回 を意図しています。これはフックがPostStartPreStopのような任意のイベントに対して複数回呼ばれることがあることを意味します。 これを正しく処理するのはフックの実装次第です。

通常、1回の配信のみが行われます。 たとえば、HTTPフックレシーバーがダウンしていてトラフィックを受け取れない場合、再送信は試みられません。 ただし、まれに二重配信が発生することがあります。 たとえば、フックの送信中にkubeletが再起動した場合、kubeletが起動した後にフックが再送信される可能性があります。

フックハンドラーのデバッグ

フックハンドラーのログは、Podのイベントには表示されません。 ハンドラーが何らかの理由で失敗した場合は、イベントをブロードキャストします。 PostStartの場合、これはFailedPostStartHookイベントで、PreStopの場合、これはFailedPreStopHookイベントです。 失敗のFailedPreStopHookイベントを自分自身で生成する場合には、lifecycle-events.yamlファイルに対してpostStartのコマンドを"badcommand"に変更し、適用してください。 kubectl describe pod lifecycle-demoを実行した結果のイベントの出力例を以下に示します。

Events:
  Type     Reason               Age              From               Message
  ----     ------               ----             ----               -------
  Normal   Scheduled            7s               default-scheduler  Successfully assigned default/lifecycle-demo to ip-XXX-XXX-XX-XX.us-east-2...
  Normal   Pulled               6s               kubelet            Successfully pulled image "nginx" in 229.604315ms
  Normal   Pulling              4s (x2 over 6s)  kubelet            Pulling image "nginx"
  Normal   Created              4s (x2 over 5s)  kubelet            Created container lifecycle-demo-container
  Normal   Started              4s (x2 over 5s)  kubelet            Started container lifecycle-demo-container
  Warning  FailedPostStartHook  4s (x2 over 5s)  kubelet            Exec lifecycle hook ([badcommand]) for Container "lifecycle-demo-container" in Pod "lifecycle-demo_default(30229739-9651-4e5a-9a32-a8f1688862db)" failed - error: command 'badcommand' exited with 126: , message: "OCI runtime exec failed: exec failed: container_linux.go:380: starting container process caused: exec: \"badcommand\": executable file not found in $PATH: unknown\r\n"
  Normal   Killing              4s (x2 over 5s)  kubelet            FailedPostStartHook
  Normal   Pulled               4s               kubelet            Successfully pulled image "nginx" in 215.66395ms
  Warning  BackOff              2s (x2 over 3s)  kubelet            Back-off restarting failed container

次の項目