kubernetes
ibmcloud
IBM-Cloud

k8s pod 概要について自習ノート

Kubernetesの利点を生かしたシステムを作るには Pod と Controller を良く理解していないと出来ないと感じたので、詳細に入り過ぎず、鳥瞰的に理解する様に勉強したメモです。 もちろん、間違い、勘違い、誤訳など、いろいろ含むと思いますので、指摘いただけると幸いです。

概要

Kubernetes Concepts Pod Overviewの自分の知識獲得のための超意訳です。 間違いや誤訳を含んでいるかもしれませんので、自己責任で参照願います。

pod とは

podは、Kubernetesの最も小さい基本的な構成単位で、podはクラスタ上のプロセスを代表しています。

本題とは関係ない話ですが、podとは何の略かな? Point of Derivery なのかなとか思っていたんですが、どうも、えんどう豆の莢や、飛行機のジェットエンジンを翼や胴体に固定するための容れ物を意味する言葉を当てはめて使っている様です。

スクリーンショット 2017-12-04 14.17.14.png

Kubernetes の pod のイメージは次の様になります。

スクリーンショット 2017-12-04 14.41.29.png

Podは、一つまたは複数のアプリケーションのコンテナを内包し、ストレージ・リソース、一意のIPアドレスをカプセル化した一つのユニットです。そして、Dockerコンテナは最も一般的ですが、他のコンテナ・ランタイムもサポートしています。

ポッドに内包するコンテナ数と用途

ポッドは、内包するコンテナの数で2つに分類できます。

  • 一つのコンテナを実行するポッド
  • 複数のコンテナを実行するポッド

一つのコンテナのポッドは、最も一般的なものです。 Kubernetesは、コンテナを直接管理するのではなくpodを管理する点がポイントです。
複数のコンテナを実行するポッドでは、二つのコンテナはストレージを共有して一つの論理ホストとして動作する用途に利用します。

<実装に関する参考資料>

ポッドのユースケース

ポッドは特定アプリの一つのインスタンスを実行する目的で利用する。水平分散(スケールアウト)する場合は、レプリケーションの数を指定してポッドの数を増やします。

ポッドが複数のコンテナを管理する方法

  • ポッドは、一貫したサービス単位を形成する複数の協調プロセス(コンテナとして)をサポートします。
  • ポッド内のコンテナは、クラスタ内の同じマシンの同じ場所に配置され、リソースと依存関係を共有し、相互に通信し、いつ、どのように終了するかを調整します。
  • 複数のコンテナを1つのポッドにグループ化することは、比較的高度な使用例です。 このパターンは、容器がしっかりと結合している特定の場合にのみ使用してください。

ポッド内のリソース共有

ポッド内のコンテナは、ネットワークとストレージを共有します。

ネットワーキング

各ポッドには一意のIPアドレスが割り当てられます。 Podのすべてのコンテナは、IPアドレスとネットワークポートを含むネットワーク名前空間を共有します。 そして、ポッド内のコンテナ同士は、localhostを使用して相互に通信できます。 このため共存するコンテナ同士でポートのアサインを調整する必要があります。

ストレージ

ポッドは、共有ストレージボリュームのセットを指定できます。 ポッド内の全てのコンテナは、共有ボリュームにアクセスでき、データを共有できます。 コンテナを再起動する必要がある場合には、共有ストレージに書き込むことでデータを永続化できます。 Kubernetesが共有ストレージをPodに実装する方法の詳細については、Volumesを参照してください。

<実装に関する参考資料>

ポッドの役割

ポッドは、コンテナが実行され、削除されるまで存続する環境です。 ポッドが作成されるとクラスタ内のノード上で実行されるように割当てられます。 ポッドは、プロセスが終了するか、ポッドオブジェクトが削除されるか、リソースが不足してポッドが取り除かれるか、ノードが失敗するまで、ノードに残ります。

ポッドは、自己回復をしません。 ポッドのあるノードが障害が発生した場合、またはスケジューリングが失敗した場合は、ポッドは削除されます。 同様に、ノードのメンテナンスやリソース不足が発生した場合、ポッドを追い出すことをしません。 Kubernetesは、コントローラと呼ばれるより高いレベルの抽象化された機能を使用して、回復や再割り当てを実施します。

ポッドとコントローラ

コントローラは、レプリケーションとロールアウトを処理し、クラスタスコープで自己修復機能を提供する。また、複数のポッドを作成および管理できます。

例えば、ノードが停止した場合、コントローラは、異なるノード上で、自動的に同一のポッドを代替を起動します。

1つまたは複数のポッドを含むコントローラの例を次に示します。

 * デプロイ
 * ステートフルセット
 * デーモンセット
 
一般にコントローラは、担当するポッドを作成するために、ポッドテンプレートを使用します

<実装に関する参考資料>

ポッドテンプレート

ポッドテンプレートは、レプリケーション・コントローラ、ジョブ、およびデーモンセットなどのポッド仕様です。 コントローラは、ポッドテンプレートを使用して実際のポッドを作成します。 以下のサンプルは、メッセージを出力するコンテナを含むポッドの簡単なマニフェストです。

apiVersion: v1
kind: Pod
metadata:
name: myapp-pod
  labels:
    app: myapp
spec:
  containers:
  - name: myapp-container
    image: busybox
    command: ['sh', '-c', 'echo Hello Kubernetes! && sleep 3600']

すべてのレプリカの現在の希望の状態を指定するのではありません。 後でテンプレートを変更したり、新しいテンプレートに切り替えることさえも、すでに作成されたポッドには直接影響しません。 同様に、レプリケーションコントローラによって作成されたポッドは、その後に直接更新される可能性があります。 これは、ポッドは、意図的に比較され、望ましい状態を設定します。


ポッド詳細

Kubernetes Concepts Podsの自分の知識獲得のための超意訳です。 間違いや誤訳を含んでいるかもしれませんので、自己責任で参照願います。

ポッドとは何ですか?

ポッド(エンドウ豆のポッドのように)は、共有ストレージ や ネットワークを持つ、1つ以上のコンテナが存在するグループであり、コンテナを実行する方法の仕様です。 ポッドのコンテナは、常に同じ場所に配置され、共同スケジュールされ、共有されたコンテキストで実行されます。 ポッドは、アプリケーション固有の「論理ホスト」(比較的密接に結合された1つまたは複数のアプリケーション・コンテナを含む)を同じ物理マシンまたは仮想マシンで実行します。

ポッドの共有コンテキストは、Linuxネームスペース、cgroup、および、潜在的別の隔離面のセットで、Dockerコンテナを隔離するものと同じものです。 ポッドのコンテキスト内では、個々のアプリケーションにさらにサブアイソレーションが適用される場合があります。

ポッド内のコンテナはIPアドレスとポートスペースを共有し、localhostを介して互いに検索できます。 また、SystemVセマフォやPOSIX共有メモリなどの標準プロセス間通信を使用して、互いに通信することもできます。 しかし、異なるポッドは異なるIPアドレスがあり、コンテナは標準プロセス間通信を利用して通信することはできません。

ポッド内のアプリケーションも共有ボリュームにアクセスできます。共有ボリュームはポッドの一部として定義され、各アプリケーションのファイルシステムにマウントできるようになります。

ポッドは、共有名前空間と共有ボリュームを持つDockerコンテナのグループとしてモデル化されています。 DockerではPID名前空間の共有はまだ実装されていません。

個々のアプリケーションコンテナと同様に、ポッドは一時的な実体と見なされます。 ポッドのライフサイクルで説明したように、ポッドは作成され、一意のID(UID)が割り当てられ、ノードが終了するまで(再起動ポリシーに従って)または削除されるまでノードにスケジュールされます。 ノードが消滅した場合、そのノードに割り当てられたポッドは、タイムアウト期間後に削除予定になります。 指定されたポッド(UIDによって定義されたもの)は新しいノードに「再スケジューリング」されません。 その代わりに、同一のポッドで置き換えることができます(必要に応じて同じ名前でも新しいUIDを使用します)(詳細はレプリケーションコントローラを参照してください)。 (将来、上位APIがポッドの移行をサポートする可能性があります)。

何らかの理由でそのポッドが削除された場合、関連するボリュームなども、また破棄されて新たに作成されます。
マルチコンテナ・ポッドは、永続ボリュームをコンテナ間のストレージに利用します。

ポッドを採用する動機

管理

  • ポッドは、一貫したサービス単位を形成する複数の協調プロセスのパターンのモデルで、アプリケーションの配備と管理を簡素化します。
  • 展開、水平スケーリング、および複製の単位として機能
  • コロケーション、終了など共有運命、調整された複製、リソース共有、および依存性管理は、ポッド内のコンテナに対して自動的に処理

リソース共有とコミュニケーション

  • ポッドは、データ共有とその構成要素間の通信を可能にする
  • ホスト名は、ポッドの名前が、コンテナに設定されます。
  • ポッドは共有ストレージボリュームのセットを指定します。 ボリュームを使用すると、コンテナの再起動後もデータが存続し、ポッド内のアプリケーション間でデータを共有することができます。

ポッドの活用

ポッドは、垂直統合アプリケーションスタック(LAMPなど)をホストするために使用できますが、主な動機は、次のような共同管理ヘルパー・プログラムをサポートすることです。個々のポッドは、一般的に同じアプリケーションの複数のインスタンスを実行するためのものではありません。

     1 コンテンツ管理システム、ファイルおよびデータローダ、ローカルキャッシュマネージャなど
     2 ログとチェックポイントのバックアップ、圧縮、回転、スナップショットなど
     3 データ変更ウォッチャー、ログ・テイラー、ロギング・モニター・アダプター、イベント・パブリッシャーなど
     4 プロキシ、ブリッジ、およびアダプタ
     5 コントローラ、マネージャ、コンフィギュレータ、およびアップデータ

詳しい説明は、「分散システムツールキット:コンポジットコンテナのパターン」を参照してください。

ポッドに代わる代替策に対する考察

単一の(Docker)コンテナで複数のプログラムを実行するだけではどうですか?

  • 透明性
    ポッド内のコンテナをインフラストラクチャに見えるようにすることで、インフラストラクチャはプロセス管理やリソース監視などのコンテナにサービスを提供できます。これにより、ユーザーの利便性が向上します。

  • 疎結合
    コンテナのバージョン管理、再構築、再展開は個別に行うことができます。 Kubernetesは、いつか個々のコンテナのライブアップデートをサポートするかもしれません。

  • 使い易さ
    ユーザーは独自のプロセスマネージャを実行する必要はなく、シグナルや終了コードの伝播などを心配する必要はありません。

  • 効率
    インフラストラクチャはより多くの責任を負うので、コンテナは軽量化できます。

アフィニティベースのコンテナスケジューリングをサポートしないのはなぜですか?

このアプローチは、共同設置場所を提供しますが、リソース共有、IPC、保証された運命の共有、管理の簡素化など、ポッドの利点のほとんどを提供しません。

ポッドの耐久性(またはその欠如)

ポッドは耐久性のある実体として扱われることを意図していません。障害のスケジューリング、ノードの障害、またはリソースの不足やノードの保守の場合など、他の退避のスケジューリングにも耐えられません。

コントローラは、クラスタスコープ、レプリケーションおよびロールアウト管理などの自己修復機能を提供します。 一般的に、ユーザーはポッドを直接作成する必要はありません。単一構成の場合でも、デプロイメントなどで、コントローラを使用する必要があります。

Borg、Marathon、Aurora、およびTupperwareを含むクラスタスケジューリングシステムでは、プライマリユーザ向けプリミティブとしての集合APIの使用が比較的一般的です。

ポッドは、下記を容易にする基本要素を公開されています。

  • スケジューラとコントローラのプラガブル性
  • コントローラーAPIを使用してポッドレベルの操作を「プロキシ」する必要なく、ポッドレベルの操作をサポート
  • ブートストラッピングなど、コントローラのライフタイムとポッドライフタイムのデカップリング
  • コントローラとサービスの疎結合 - エンドポイントコントローラがポッドを監視する
  • クラスタレベルの機能を備えたkebeletレベルのクリーンな構成 - Kubeletは効果的「ポッドコントローラ」です
  • 計画された退避、イメージ・プリフェッチ、またはライブポッドの移行の場合など、削除の前に確実に削除の前にポッドを置き換えることを期待する高可用性アプリケーション

StatefulSetコントローラには、ステートフルポッドのファースト・クラスのサポートがあります。ステートフルポッドを使用するベストプラクティスは、レプリカ1と対応するサービスを持つレプリケーションコントローラを作成することです。このMySQLデプロイの例を参照してください。

ポッドの終了

ポッドはクラスタ内のノード上で実行中のプロセスのため、不要になったときに正常終了するようにすることが重要です。

ユーザーがポッドの削除を要求すると、ポッドを強制終了させる前にシステムは意図した猶予期間を記録し、TERMシグナルは各コンテナーのメインプロセスに送信されます。 猶予期間が終了すると、KILLシグナルがプロセスに送信され、ポッドが削除されます。

プロセスが終了するのを待っている間にKubeletまたはコンテナマネージャが再起動された場合、終了は完全な猶予期間で再試行されます。

終了の流れ例:

  1. ユーザーがPodを削除するコマンドを送信し、デフォルトの猶予期間(30秒)
  2. APIサーバーのポッドは、ポッドが猶予期間とともに「dead」とみなされる時間を更新します。
  3. ポッドは、クライアント・コマンドにリストで「Terminating」と表示されます。 ポッドのシャットダウンプロセスが開始されます。
  4. ポッドでpreStopフックが定義されている場合は、ポッド内で呼び出されます。猶予期間が経過してもpreStopフックが実行されている場合は、2秒間の猶予期間を短くしてステップ2を呼び出します。
  5. ポッド内のプロセスにTERMシグナルが送信されます。 ポッドはサービスのエンドポイントリストから削除され、もはやレプリケーションコントローラ用の実行中のポッドのセットの一部とはみなされません。ロードバランサ(サービスプロキシなど)がローテーションからそれらを削除するので、シャットダウンが遅くなるポッドは、トラフィックを処理し続けることができます。
  6. 猶予期間が終了すると、Podで実行中のプロセスはKILLシグナルで強制終了されます。
  7. Kubeletは、猶予期間0(即時削除)を設定して、APIサーバー上のPodの削除を完了します。 PodはAPIから消え、クライアントからは見えなくなります。

デフォルトでは、すべての削除は30秒以内が正常です。 kubectl deleteコマンドは、 -grace-period = オプションをサポートしています。これにより、ユーザはデフォルトを上書きして、独自の値を指定できます。 値0 forceはポッドを削除します。

ポッドの強制削除

ポッドの強制的な削除は、クラスタ状態とetcdから直ちに削除として定義されます。 強制削除が実行されると、apiserverは、kubeletからのノードでポッドが終了した確認を待ません。 API内のポッドはすぐに削除されるので、新しいポッドを同じ名前で作成することができます。 ノードでは、すぐに終了するように設定されているポッドには強制的に小さな猶予期間が与えられてから強制終了されます。

強制削除は、一部のポッドでは潜在的に危険であり、慎重に実行する必要があります。 StatefulSetポッドの場合は、StatefulSetからポッドを削除するためのタスクのドキュメントを参照してください。

ポッドコンテナの特権モード

Kubernetes v1.1より、ポッド内のどのコンテナでも、コンテナ仕様のSecurityContextの特権フラグを使用して特権モードを有効にすることができます。これは、ネットワークスタックの操作やデバイスへのアクセスなど、Linuxの機能を使用したいコンテナに便利です。コンテナ内のプロセスは、コンテナ外のプロセスで使用できる権限とほぼ同じ権限を取得します。

APIオブジェクト

Podは、Kubernetes REST APIのトップレベルのリソースです。 APIオブジェクトの詳細については、Pod APIオブジェクトを参照してください。

ポッドのライフサイクル

Kubernetes Concepts Pod Lifecycleの自分の知識獲得のための超意訳です。

ポッド フェーズ

ポッドのフェーズは、ポッドがライフサイクルのどこにあるかを簡単かつ高レベルでまとめたものです。

Pending:ポッドは、Kubernetesシステムで承認されましたが、1つ以上のコンテナ・イメージが作成されていません。 これには、スケジュールされる前の時間だけでなく、ネットワークを介してイメージをダウンロードする時間も含まれますが、時間がかかることがあります。

  • Running:ノードにバインドされ、すべてのコンテナが作成されました。 少なくとも1つのコンテナがまだ実行されているか、開始または再起動中です。
  • Succeeded:ポッド内のすべてのコンテナが正常に終了し、再起動されません。
  • Failed:ポッド内のすべてのコンテナが終了し、少なくとも1つのコンテナが失敗して終了しました。 つまり、コンテナはゼロ以外のステータスで終了したか、システムによって終了しました。
  • Unknown:何らかの理由により、通常、ポッドのホストと通信する際のエラーのために、ポッドの状態を取得できませんでした。

<実装に関する参考資料>

ポッドの状態

ポッドには PodStatus があり、PodConditionsの配列を持っています。 PodCondition配列の各要素には、型フィールドと状態フィールドがあります。 タイプフィールドは文字列で、可能な値はPodScheduled、Ready、Initialized、Unschedulableです。 ステータスフィールドは文字列で、可能な値はTrue、False、およびUnknownです。

コンテナ プローブ

プローブとは、コンテナ上のkubeletによって定期的に実行される診断です。 診断を実行するために、kubeletはコンテナによって実装されたハンドラを呼び出します。 ハンドラには次の3種類があります。

  • ExecAction:コンテナ内で指定されたコマンドを実行します。 コマンドがステータスコード0で終了すると、診断は成功したとみなされます。
  • TCPSocketAction:指定されたポート上のコンテナのIPアドレスに対してTCPチェックを実行します。 ポートが開いている場合、診断は成功したと見なされます。
  • HTTPGetAction:指定されたポートとパス上のコンテナのIPアドレスに対するHTTP Get要求を実行します。 レスポンスのステータスコードが200以上400未満の場合、診断は成功したとみなされます。

各プローブには、次の3つの結果のいずれかがあります。

  • 成功:コンテナが診断に合格
  • 失敗:コンテナが診断に失敗
  • 不明:診断が失敗したため対処は不要

kubeletは、オプションで、実行中のコンテナ上の2種類のプローブを実行して反応することができます。

  • livenessProbe:コンテナが実行中かどうかを示します。 livenessプローブが失敗した場合、kubeletはコンテナを強制終了し、コンテナは再起動ポリシーを受けます。 コンテナが活性プローブを提供しない場合、デフォルトの状態は成功です。
  • readinessProbe:コンテナがリクエストを処理できる状態かどうかを示します。 準備検査が失敗した場合、エンドポイントコントローラは、Podに一致するすべてのサービスのエンドポイントからPodのIPアドレスを削除します。 最初の遅延の前のデフォルトの準備状態は失敗です。 コンテナが準備プローブを提供しない場合、デフォルトの状態は成功です。

<実装に関する参考資料>

どんな時に Liveness または Readiness プローブを利用するか?

問題が発生した場合や不健全になった場合に、コンテナ内のプロセスが独自にクラッシュする可能性がある場合は、必ずしもlivenessプローブが必要なわけではありません。 kubeletは、PodのrestartPolicyに従って自動的に正しいアクションを実行します。

プローブが失敗した場合にコンテナを強制終了して再起動するには、livenessプローブを指定し、restartPolicyに、Always または OnFailureに指定します。

プローブが成功したときにのみトラフィックをPodに通したい場合は、readinessプローブを指定します。この場合、readinessプローブはlivenessプローブと同じでも構いませんが、スペック内にreadinessプローブにすることは、プローブが何のトラフィックも受信せずに開始し、プローブが成功した後にトラフィックを受信することを意味します。

コンテナがメンテナンスのために落ちるようにするには、livenessプローブとは異なる準備状況に特有のエンドポイントをチェックするreadinessプローブを指定します。

Podが削除されたときにリクエストを排除できるようにするには、必ずしもreadinessプローブが必要ではありません。削除時には、readinessプローブが存在するかどうかにかかわらず、Podは自動的に未処理状態になります。 ポッドは、コンテナが停止するのを待っている間は、未完了状態のままです。

ポッドとコンテナのステータス

ポッドコンテナステータスの詳細については、PodStatusおよび ContainerStatus を参照してください。 ポッドのステータスとして報告される情報は、その時点のContainerStateによって異なります。

再起動のポリシー

PodSpecには、Always、OnFailure、Neverの値を持つrestartPolicyフィールドがあります。 デフォルト値はAlwaysです。 restartPolicyは、ポッド内のすべてのコンテナに適用されます。 restartPolicyは、同じノード上のkubeletによるコンテナの再起動のみを参照します。 失敗したkubeletによって再起動されたコンテナは、5分でキャップされた指数バックオフ遅延(10秒、20秒、40秒...)で再開され、10分間の実行が成功するとリセットされます。 Podsドキュメントで説明したように、ノードにバインドされると、Podは決して別のノードにリバウンドされません。

ポッドの生存期間

一般に、ポッドは誰かがそれらを削除するまで消えません、これを実行するのは人間またはコントローラです。 このルールの唯一の例外は、フェーズが成功または失敗したポッドが、マスタによって決められた期間を過ぎて自動的に破棄されることです。

3種類のコントローラーを使用できます。

  • バッチ計算など、終了が予想されるポッドには JOB を使用します。ジョブは、restartFolicyが OnFailure または Never のポッドにのみ適しています。

  • ウェブサーバーなど終了する予定のないポッドには、ReplicationControllerReplicaSet、または Deployment を使用します。 ReplicationControllerは、restartPolicy が、Always のポッドにのみ適しています。

  • マシンごとに1つずつ実行する必要があるPodのDaemonSetは、マシン固有のシステムサービスを提供するため、使用してください。

3種類のコントローラーにはすべて、PodTemplateが含まれています。ポッドを直接作成するのではなく、適切なコントローラを作成してポッドを作成させることをお勧めします。これは、ポッドだけではマシンの障害に耐えられるものではなく、コントローラーがそのためにあります。

ノードが消滅したり、クラスタの他のノードから切断された場合、Kubernetesは、失われたノード上のすべてのPodのフェーズを失敗に設定するポリシーを適用します。

<実装に関する参考資料>

参考資料

[1] Kubernetes Concepts Pod Overview
[2] Kubernetes Concepts Pods
[3] Kubernetes Concepts Pod Lifecycle
[4] Kubernetes Concepts Init Containers
[5] Kubernetes Concepts Pod Preset
[6] Kubernetes Concepts Disruptions