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

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

コンテナ

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

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

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

コンテナイメージ

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

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

コンテナランタイム

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

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

次の項目

1 - コンテナの概要

コンテナは、アプリケーションの(コンパイルされた)コードと、実行時に必要な依存関係をパッケージ化するための技術です。実行する各コンテナは再現性があります。依存関係を含めることによる標準化は、どこで実行しても同じ動作が得られることを意味します。

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

コンテナイメージ

コンテナイメージは、アプリケーションを実行するために必要なすべてのものを含んだ、すぐに実行可能なソフトウェアパッケージです。コードとそれが必要とする任意のランタイム、アプリケーションとシステムのライブラリ、および必須の設定のデフォルト値が含まれています。

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

コンテナランタイム

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

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

次の項目

2 - イメージ

コンテナイメージはアプリケーションと依存関係のあるすべてソフトウェアをカプセル化したバイナリデータを表します。コンテナイメージはスタンドアロンで実行可能なソフトウェアをひとつにまとめ、ランタイム環境に関する想定を明確に定義しています。

アプリケーションのコンテナイメージを作成し、一般的にはPodで参照する前にレジストリへPushします。

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

イメージの名称

コンテナイメージは、pauseexample/mycontainer、またはkube-apiserverのような名前が通常つけられます。 イメージにはレジストリのホスト名も含めることができ(例:fictional.registry.example/imagename)、さらにポート番号も含めることが可能です(例:fictional.registry.example:10443/imagename)。

レジストリのホスト名を指定しない場合は、KubernetesはDockerパブリックレジストリを意味していると見なします。

イメージ名の後に、タグ を追加することができます(dockerpodmanのようなコマンドを利用した場合と同様)。 タグによって同じイメージの異なるバージョンを識別できます。

イメージタグは大文字と小文字、数値、アンダースコア(_)、ピリオド(.)とマイナス(-)で構成されます。 イメージタグでは区切り記号(_-.)を指定できる追加ルールがあります。 タグを指定しない場合は、Kubernetesはlatestタグを指定したと見なします。

イメージの更新

DeploymentStatefulSet、Pod、またはPodテンプレートを含むその他のオブジェクトを最初に作成するとき、デフォルトでは、Pod内のすべてのコンテナのPullポリシーは、明示的に指定されていない場合、IfNotPresentに設定されます。

イメージがすでに存在する場合、このポリシーはkubeletにイメージのPullをスキップさせます。

イメージPullポリシー

コンテナのimagePullPolicyとイメージのタグは、kubeletが指定されたイメージをPull(ダウンロード)しようとする時に影響します。

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

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

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

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

イメージタグを使用する場合、イメージレジストリがそのイメージのタグが表すコードを変更すると、新旧のコードを実行するPodが混在することになるかもしれません。 イメージダイジェストは特定のバージョンのイメージを一意に識別するため、Kubernetesは特定のイメージ名とダイジェストが指定されたコンテナを起動するたびに同じコードを実行します。 イメージをダイジェストで指定することは、レジストリの変更でそのようなバージョンの混在を起こさないように、実行するコードを固定します。

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

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

新しいPodがAPIサーバに送信されると、クラスターは特定の条件が満たされたときにimagePullPolicyフィールドを設定します。

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

必要なイメージをPullする

常に強制的にPullしたい場合は、以下のいずれかを行ってください。

  • コンテナのimagePullPolicyAlwaysを設定する。
  • imagePullPolicyを省略し、使用するイメージに:latestタグ使用する。Pod生成時に、KubernetesがポリシーにAlwaysを設定する。
  • imagePullPolicyと使用するイメージのタグを省略する。Pod生成時に、KubernetesがポリシーにAlwaysを設定する。
  • AlwaysPullImagesアドミッションコントローラーを有効にする。

ImagePullBackOff

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

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

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

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

コンテナレジストリはバイナリイメージの提供だけでなく、コンテナイメージインデックスも提供する事ができます。イメージインデックスはコンテナのアーキテクチャ固有バージョンに関する複数のイメージマニフェストを指すことができます。イメージインデックスの目的はイメージの名前(例:pauseexample/mycontainerkube-apiserver)をもたせ、様々なシステムが使用しているマシンアーキテクチャにあう適切なバイナリイメージを取得できることです。

Kubernetes自身は、通常コンテナイメージに-$(ARCH)のサフィックスを持つ名前をつけます。下位互換の為にサフィックス付きの古い仕様のイメージを生成してください。その目的は、pauseのようなすべてのアーキテクチャのマニフェストを持つイメージと、サフィックスのあるイメージをハードコードしていた可能性のある古い仕様の設定やYAMLファイルと下位互換があるpause-amd64のようなイメージを生成することです。

プライベートレジストリを使用する方法

プライベートレジストリではイメージを読み込む為にキーが必要になる場合があります。
認証情報はいくつかの方法で提供できます。

  • プライベートレジストリへの認証をNodeに設定する
    • すべてのPodがプライベートレジストリを読み取ることができる
    • クラスター管理者によるNodeの設定が必要
  • 事前にPullされたイメージ
    • すべてのPodがNode上にキャッシュされたイメージを利用できる
    • セットアップするためにはすべてのNodeに対するrootアクセスが必要
  • PodでImagePullSecretsを指定する
    • キーを提供したPodのみがプライベートレジストリへアクセスできる
  • ベンダー固有またはローカルエクステンション
    • カスタムNode構成を使っている場合、あなた(または、あなたのクラウドプロバイダー)はコンテナレジストリへの認証の仕組みを組み込むことができる

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

プライベートレジストリへの認証をNodeに設定する

認証情報を設定するための具体的な手順は、使用するコンテナランタイムとレジストリに依存します。最も正確な情報として、ソリューションのドキュメントを参照する必要があります。

プライベートなコンテナイメージレジストリを設定する例として、プライベートレジストリからイメージをPullするタスクを参照してください。その例では、Docker Hubのプライベートレジストリを使用しています。

config.jsonの解釈

config.jsonの解釈は、Dockerのオリジナルの実装とKubernetesの解釈で異なります。 Dockerでは、authsキーはルートURLしか指定できませんが、Kubernetesではプレフィックスのマッチしたパスだけでなく、グロブパターンのURLも指定できます。 以下のようなconfig.jsonが有効であるということです。

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

ルートURL(*my-registry.io)は、以下の構文でマッチングされます:

pattern:
    { term }

term:
    '*'         セパレーター以外の任意の文字列にマッチする
    '?'         セパレーター以外の任意の一文字にマッチする
    '[' [ '^' ] { character-range } ']'
                文字クラス (空であってはならない)
    c           文字 c とマッチする (c != '*', '?', '\\', '[')
    '\\' c      文字 c とマッチする

character-range:
    c           文字 c とマッチする (c != '\\', '-', ']')
    '\\' c      文字 c とマッチする
    lo '-' hi   lo <= c <= hi の文字 c とマッチする

イメージのPull操作では、有効なパターンごとに認証情報をCRIコンテナランタイムに渡すようになりました。例えば、以下のようなコンテナイメージ名は正常にマッチングされます。

  • my-registry.io/images
  • my-registry.io/images/my-image
  • my-registry.io/images/another-image
  • sub.my-registry.io/images/my-image
  • a.sub.my-registry.io/images/my-image

kubeletは、見つかったすべての認証情報に対してイメージのPullを順次実行します。これは、次のようにconfig.jsonに複数のエントリーを書くことも可能であることを意味します。

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

コンテナがmy-registry.io/images/subpath/my-imageをPullするイメージとして指定した場合、kubeletが認証ソースの片方からダウンロードに失敗すると、両方の認証ソースからダウンロードを試みます。

事前にPullしたイメージ

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

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

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

すべてのPodは事前にPullしたイメージへの読み取りアクセス権をもちます。

PodでimagePullSecretsを指定する

KubernetesはPodでのコンテナイメージレジストリキーの指定をサポートしています。

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 Secretsとしてインポートすることができます。 既存のDocker認証情報に基づいてSecretを作成する で、この設定方法を説明します.

これは複数のプライベートコンテナレジストリを使用している場合に特に有効です。kubectl create secret docker-registryはひとつのプライベートレジストリにのみ機能するSecretを作成するからです。

PodのimagePullSecretsを参照する方法

これで、imagePullSecretsセクションをPod定義へ追加することでSecretを参照するPodを作成できます。

例:

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を指定することで自動化することができます。

詳細の手順は、ImagePullSecretsをService Accountに追加するをクリックしてください。

これを各Nodeの.docker/config.jsonに組み合わせて利用できます。認証情報はマージされます。

ユースケース

プライベートレジストリを設定するためのソリューションはいくつかあります。ここでは、いくつかの一般的なユースケースと推奨される解決方法を示します。

  1. クラスターに独自仕様でない(例えば、オープンソース)イメージだけを実行する。イメージを非公開にする必要がない
    • パブリックレジストリのパブリックイメージを利用する
      • 設定は必要ない
      • クラウドプロバイダーによっては、可用性の向上とイメージをPullする時間を短くする為に、自動的にキャッシュやミラーされたパプリックイメージが提供される
  2. 社外には非公開の必要があるが、すべてのクラスター利用者には見せてよい独自仕様のイメージをクラスターで実行している
    • ホストされたプライペートレジストリを使用
      • プライベートレジストリにアクセスする必要があるノードには、手動設定が必要となる場合がある
    • または、オープンな読み取りアクセスを許可したファイヤーウォールの背後で内部向けプライベートレジストリを実行する
      • Kubernetesの設定は必要ない
    • イメージへのアクセスを制御できるホストされたコンテナイメージレジストリサービスを利用する
      • Nodeを手動設定するよりもクラスターのオートスケーリングのほうがうまく機能する
    • また、Node設定変更を自由にできないクラスターではimagePullSecretsを使用する
  3. 独自仕様のイメージを含むクラスターで、いくつかは厳格なアクセス制御が必要である
    • AlwaysPullImagesアドミッションコントローラーが有効化かを確認する必要がある。さもないと、全部のPodがすべてのイメージへのアクセスができてしまう可能性がある
    • 機密データはイメージに含めてしまうのではなく、"Secret"リソースに移行する
  4. それぞれのテナントが独自のプライベートレジストリを必要とするマルチテナントのクラスターである
    • AlwaysPullImagesアドミッションコントローラーが有効化を確認する必要がある。さもないと、すべてのテナントの全Podが全部のイメージにアクセスできてしまう可能性がある
    • 認証が必要なプライベートレジストリを実行する
    • それぞれのテナントでレジストリ認証を生成し、Secretへ設定し、各テナントのNamespaceに追加する
    • テナントは、Secretを各NamespaceのimagePullSecretsへ追加する

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

次の項目

3 - コンテナ環境

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

コンテナ環境

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

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

コンテナ情報

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

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

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

クラスター情報

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

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

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

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

次の項目

4 - ランタイムクラス(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ランタイムのセットアップに関するさらなる詳細は、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内部で使用されるオーバーヘッドを確保することができます。

次の項目

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

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

概要

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

コンテナフック

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

PostStart

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

PreStop

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

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

フックハンドラーの実装

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

  • Exec - コンテナのcgroupsと名前空間の中で、 pre-stop.shのような特定のコマンドを実行します。 コマンドによって消費されたリソースはコンテナに対してカウントされます。
  • HTTP - コンテナ上の特定のエンドポイントに対してHTTP要求を実行します。

フックハンドラーの実行

コンテナライフサイクル管理フックが呼び出されると、Kubernetes管理システムはフックアクションにしたがってハンドラーを実行します。 httpGettcpSocketは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

次の項目