コンセプト 本セクションは、Kubernetesシステムの各パートと、クラスター を表現するためにKubernetesが使用する抽象概念について学習し、Kubernetesの仕組みをより深く理解するのに役立ちます。
概要 Kubernetesを機能させるには、Kubernetes API オブジェクト を使用して、実行したいアプリケーションやその他のワークロード、使用するコンテナイメージ、レプリカ(複製)の数、どんなネットワークやディスクリソースを利用可能にするかなど、クラスターの desired state (望ましい状態)を記述します。desired state (望ましい状態)をセットするには、Kubernetes APIを使用してオブジェクトを作成します。通常はコマンドラインインターフェース kubectl
を用いてKubernetes APIを操作しますが、Kubernetes APIを直接使用してクラスターと対話し、desired state (望ましい状態)を設定、または変更することもできます。
一旦desired state (望ましい状態)を設定すると、Pod Lifecycle Event Generator(PLEG )を使用したKubernetes コントロールプレーン が機能し、クラスターの現在の状態をdesired state (望ましい状態)に一致させます。そのためにKubernetesはさまざまなタスク(たとえば、コンテナの起動または再起動、特定アプリケーションのレプリカ数のスケーリング等)を自動的に実行します。Kubernetesコントロールプレーンは、クラスターで実行されている以下のプロセスで構成されています。
Kubernetesオブジェクト Kubernetesには、デプロイ済みのコンテナ化されたアプリケーションやワークロード、関連するネットワークとディスクリソース、クラスターが何をしているかに関するその他の情報といった、システムの状態を表現する抽象が含まれています。これらの抽象は、Kubernetes APIのオブジェクトによって表現されます。詳細については、Kubernetesオブジェクトについて知る をご覧ください。
基本的なKubernetesのオブジェクトは次のとおりです。
Kubernetesには、コントローラー に依存して基本オブジェクトを構築し、追加の機能と便利な機能を提供する高レベルの抽象化も含まれています。これらには以下のものを含みます:
Kubernetesコントロールプレーン Kubernetesマスターや kubeletプロセスといったKubernetesコントロールプレーンのさまざまなパーツは、Kubernetesがクラスターとどのように通信するかを統制します。コントロールプレーンはシステム内のすべてのKubernetesオブジェクトの記録を保持し、それらのオブジェクトの状態を管理するために継続的制御ループを実行します。コントロールプレーンの制御ループは常にクラスターの変更に反応し、システム内のすべてのオブジェクトの実際の状態が、指定した状態に一致するように動作します。
たとえば、Kubernetes APIを使用してDeploymentを作成する場合、システムには新しいdesired state (望ましい状態)が提供されます。Kubernetesコントロールプレーンは、そのオブジェクトの作成を記録します。そして、要求されたアプリケーションの開始、およびクラスターノードへのスケジューリングにより指示を完遂します。このようにしてクラスターの実際の状態を望ましい状態に一致させます。
Kubernetesマスター Kubernetesのマスターは、クラスターの望ましい状態を維持する責務を持ちます。kubectl
コマンドラインインターフェースを使用するなどしてKubernetesとやり取りするとき、ユーザーは実際にはクラスターにあるKubernetesのマスターと通信しています。
「マスター」とは、クラスター状態を管理するプロセスの集合を指します。通常これらのプロセスは、すべてクラスター内の単一ノードで実行されます。このノードはマスターとも呼ばれます。マスターは、可用性と冗長性のために複製することもできます。
Kubernetesノード クラスターのノードは、アプリケーションとクラウドワークフローを実行するマシン(VM、物理サーバーなど)です。Kubernetesのマスターは各ノードを制御します。運用者自身がノードと直接対話することはほとんどありません。
次の項目 コンセプトページを追加したい場合は、
ページテンプレートの使用
のコンセプトページタイプとコンセプトテンプレートに関する情報を確認してください。
1 - 概要 Kubernetesは、宣言的な構成管理と自動化を促進し、コンテナ化されたワークロードやサービスを管理するための、ポータブルで拡張性のあるオープンソースのプラットフォームです。Kubernetesは巨大で急速に成長しているエコシステムを備えており、それらのサービス、サポート、ツールは幅広い形で利用可能です。
このページでは、Kubernetesの概要について説明します。
Kubernetesは、宣言的な構成管理と自動化を促進し、コンテナ化されたワークロードやサービスを管理するための、ポータブルで拡張性のあるオープンソースのプラットフォームです。Kubernetesは巨大で急速に成長しているエコシステムを備えており、それらのサービス、サポート、ツールは幅広い形で利用可能です。
Kubernetesの名称は、ギリシャ語に由来し、操舵手やパイロットを意味しています。
"K"と"s"の間にある8つの文字を数えることから、K8sが略語として使われています。
Googleは2014年にKubernetesプロジェクトをオープンソース化しました。
Kubernetesは、本番環境で大規模なワークロードを稼働させたGoogleの15年以上の経験 と、コミュニティからの最高のアイディアや実践を組み合わせています。
過去を振り返ってみると 過去を振り返って、Kubernetesがなぜこんなに便利なのかを見てみましょう。
仮想化ができる前の時代におけるデプロイ (Traditional deployment): 初期の頃は、組織は物理サーバー上にアプリケーションを実行させていました。物理サーバー上でアプリケーションのリソース制限を設定する方法がなかったため、リソースの割当問題が発生していました。例えば、複数のアプリケーションを実行させた場合、ひとつのアプリケーションがリソースの大半を消費してしまうと、他のアプリケーションのパフォーマンスが低下してしまうことがありました。この解決方法は、それぞれのアプリケーションを別々の物理サーバーで動かすことでした。しかし、リソースが十分に活用できなかったため、拡大しませんでした。また組織にとって多くの物理サーバーを維持することは費用がかかりました。
仮想化を使ったデプロイ (Virtualized deployment): ひとつの解決方法として、仮想化が導入されました。1台の物理サーバーのCPU上で、複数の仮想マシン(VM)を実行させることができるようになりました。仮想化によりアプリケーションをVM毎に隔離する事ができ、ひとつのアプリケーションの情報が他のアプリケーションから自由にアクセスさせないといったセキュリティレベルを提供することができます。
仮想化により、物理サーバー内のリソース使用率が向上し、アプリケーションの追加や更新が容易になり、ハードウェアコストの削減などスケーラビリティが向上します。仮想化を利用すると、物理リソースのセットを使い捨て可能な仮想マシンのクラスターとして提示することができます。
各VMは、仮想ハードウェア上で各自のOSを含んだ全コンポーネントを実行する完全なマシンです。
コンテナを使ったデプロイ (Container deployment): コンテナはVMと似ていますが、アプリケーション間でオペレーティング・システム(OS)を共有できる緩和された分離特性を持っています。そのため、コンテナは軽量だといわれます。VMと同じように、コンテナは各自のファイルシステム、CPUの共有、メモリー、プロセス空間等を持っています。基盤のインフラストラクチャから分離されているため、クラウドやOSディストリビューションを越えて移動することが可能です。
コンテナは、その他にも次のようなメリットを提供するため、人気が高まっています。
アジャイルアプリケーションの作成とデプロイ: VMイメージの利用時と比較して、コンテナイメージ作成の容易さと効率性が向上します。 継続的な開発、インテグレーションとデプロイ: 信頼できる頻繁なコンテナイメージのビルドと、素早く簡単にロールバックすることが可能なデプロイを提供します。(イメージが不変であれば) 開発者と運用者の関心を分離: アプリケーションコンテナイメージの作成は、デプロイ時ではなく、ビルド/リリース時に行います。それによって、インフラストラクチャとアプリケーションを分離します。 可観測性: OSレベルの情報とメトリクスだけではなく、アプリケーションの稼働状態やその他の警告も表示します。 開発、テスト、本番環境を越えた環境の一貫性: クラウドで実行させるのと同じようにノートPCでも実行させる事ができます。 クラウドとOSディストリビューションの可搬性: Ubuntu、RHEL、CoreOS上でも、オンプレミスも、主要なパブリッククラウドでも、それ以外のどんな環境でも、実行できます。 アプリケーション中心の管理: 仮想マシン上でOSを実行するから、論理リソースを使用してOS上でアプリケーションを実行するへと抽象度のレベルを向上させます。 疎結合、分散化、拡張性、柔軟性のあるマイクロサービス: アプリケーションを小さく、同時にデプロイと管理が可能な独立した部品に分割されます。1台の大きな単一目的のマシン上に実行するモノリシックなスタックではありません。 リソースの分割: アプリケーションのパフォーマンスが予測可能です。 リソースの効率的な利用: 高い効率性と集約性が可能です。 Kubernetesが必要な理由と提供する機能 コンテナは、アプリケーションを集約して実行する良い方法です。本番環境では、アプリケーションを実行しダウンタイムが発生しないように、コンテナを管理する必要があります。例えば、コンテナがダウンした場合、他のコンテナを起動する必要があります。このような動作がシステムに組込まれていると、管理が簡単になるのではないでしょうか?
そこを助けてくれるのがKubernetesです! Kubernetesは分散システムを弾力的に実行するフレームワークを提供してくれます。あなたのアプリケーションのためにスケーリングとフェイルオーバーの面倒を見てくれて、デプロイのパターンなどを提供します。例えば、Kubernetesはシステムにカナリアデプロイを簡単に管理することができます。
Kubernetesは以下を提供します。
サービスディスカバリーと負荷分散
Kubernetesは、DNS名または独自のIPアドレスを使ってコンテナを公開することができます。コンテナへのトラフィックが多い場合は、Kubernetesは負荷分散し、ネットワークトラフィックを振り分けることができるため、デプロイが安定します。ストレージ オーケストレーション
Kubernetesは、ローカルストレージやパブリッククラウドプロバイダーなど、選択したストレージシステムを自動でマウントすることができます。自動化されたロールアウトとロールバック
Kubernetesを使うとデプロイしたコンテナのあるべき状態を記述することができ、制御されたスピードで実際の状態をあるべき状態に変更することができます。例えば、アプリケーションのデプロイのために、新しいコンテナの作成や既存コンテナの削除、新しいコンテナにあらゆるリソースを適用する作業を、Kubernetesで自動化できます。自動ビンパッキング
コンテナ化されたタスクを実行するノードのクラスターをKubernetesへ提供します。各コンテナがどれくらいCPUやメモリー(RAM)を必要とするのかをKubernetesに宣言することができます。Kubernetesはコンテナをノードにあわせて調整することができ、リソースを最大限に活用してくれます。自己修復
Kubernetesは、処理が失敗したコンテナを再起動し、コンテナを入れ替え、定義したヘルスチェックに応答しないコンテナを強制終了します。処理の準備ができるまでは、クライアントに通知しません。機密情報と構成管理
Kubernetesは、パスワードやOAuthトークン、SSHキーなどの機密の情報を保持し、管理することができます。機密情報をデプロイし、コンテナイメージを再作成することなくアプリケーションの構成情報を更新することができます。スタック構成の中で機密情報を晒してしまうこともありません。Kubernetesにないもの Kubernetesは、従来型の全部入りなPaaS(Platform as a Service)のシステムではありません。Kubernetesはハードウェアレベルではなく、コンテナレベルで動作するため、デプロイ、スケーリング、負荷分散といったPaaSが提供するのと共通の機能をいくつか提供し、またユーザーはロギングやモニタリング及びアラートを行うソリューションを統合できます。また一方、Kubernetesはモノリシックでなく、標準のソリューションは選択が自由で、追加と削除が容易な構成になっています。Kubernetesは開発プラットフォーム構築のためにビルディングブロックを提供しますが、重要な部分はユーザーの選択と柔軟性を維持しています。
Kubernetesは...
サポートするアプリケーションの種類を制限しません。Kubernetesは、ステートレス、ステートフルやデータ処理のワークロードなど、非常に多様なワークロードをサポートすることを目的としています。アプリケーションがコンテナで実行できるのであれば、Kubernetes上で問題なく実行できるはずです。 ソースコードのデプロイやアプリケーションのビルドは行いません。継続的なインテグレーション、デリバリー、デプロイ(CI/CD)のワークフローは、技術的な要件だけでなく組織の文化や好みで決められます。 ミドルウェア(例:メッセージバス)、データ処理フレームワーク(例:Spark)、データベース(例:MySQL)、キャッシュ、クラスターストレージシステム(例:Ceph)といったアプリケーションレベルの機能を組み込んで提供しません。それらのコンポーネントは、Kubernetes上で実行することもできますし、Open Service Broker のようなポータブルメカニズムを経由してKubernetes上で実行されるアプリケーションからアクセスすることも可能です。 ロギング、モニタリングやアラートを行うソリューションは指定しません。PoCとしていくつかのインテグレーションとメトリクスを収集し出力するメカニズムを提供します。 構成言語/システム(例:Jsonnet)の提供も指示もしません。任意の形式の宣言型仕様の対象となる可能性のある宣言型APIを提供します。 統合的なマシンの構成、メンテナンス、管理、または自己修復を行うシステムは提供も採用も行いません。 さらに、Kubernetesは単なるオーケストレーションシステムではありません。実際には、オーケストレーションの必要性はありません。オーケストレーションの技術的な定義は、「最初にAを実行し、次にB、その次にCを実行」のような定義されたワークフローの実行です。対照的にKubernetesは、現在の状態から提示されたあるべき状態にあわせて継続的に維持するといった、独立していて構成可能な制御プロセスのセットを提供します。AからCへどのように移行するかは問題ではありません。集中管理も必要ありません。これにより、使いやすく、より強力で、堅牢で、弾力性と拡張性があるシステムが実現します。 次の項目 1.1 - Kubernetesのコンポーネント Kubernetesクラスターはコントロールプレーンのコンポーネントとノードと呼ばれるマシン群で構成されています。
Kubernetesをデプロイすると、クラスターが展開されます。
Kubernetesクラスターは、 コンテナ化されたアプリケーションを実行する、ノード と呼ばれるワーカーマシンの集合です。すべてのクラスターには少なくとも1つのワーカーノードがあります。
ワーカーノードは、アプリケーションのコンポーネントであるPodをホストします。マスターノードは、クラスター内のワーカーノードとPodを管理します。複数のマスターノードを使用して、クラスターにフェイルオーバーと高可用性を提供します。
ワーカーノードは、アプリケーションワークロードのコンポーネントであるPod をホストします。コントロールプレーン は、クラスター内のワーカーノードとPodを管理します。本番環境では、コントロールプレーンは複数のコンピューターを使用し、クラスターは複数のノードを使用し、耐障害性や高可用性を提供します。
このドキュメントでは、Kubernetesクラスターが機能するために必要となるさまざまなコンポーネントの概要を説明します。
Kubernetesクラスターを構成するコンポーネント
コントロールプレーンコンポーネント コントロールプレーンコンポーネントは、クラスターに関する全体的な決定(スケジューリングなど)を行います。また、クラスターイベントの検出および応答を行います(たとえば、deploymentのreplicas
フィールドが満たされていない場合に、新しい Pod を起動する等)。
コントロールプレーンコンポーネントはクラスター内のどのマシンでも実行できますが、シンプルにするため、セットアップスクリプトは通常、すべてのコントロールプレーンコンポーネントを同じマシンで起動し、そのマシンではユーザーコンテナを実行しません。
複数のマシンにまたがって実行されるコントロールプレーンのセットアップ例については、kubeadmを使用した高可用性クラスターの構築 を参照してください。
kube-apiserver APIサーバーは、Kubernetes APIを外部に提供するKubernetesコントロールプレーン のコンポーネントです。
APIサーバーはKubernetesコントロールプレーンのフロントエンドになります。
Kubernetes APIサーバーの主な実装はkube-apiserver です。
kube-apiserverは水平方向にスケールするように設計されています—つまり、インスタンスを追加することでスケールが可能です。
複数のkube-apiserverインスタンスを実行することで、インスタンス間でトラフィックを分散させることが可能です。
etcd 一貫性、高可用性を持ったキーバリューストアで、Kubernetesの全てのクラスター情報の保存場所として利用されています。
etcdをKubernetesのデータストアとして使用する場合、必ずデータのバックアップ プランを作成して下さい。
公式ドキュメント でetcdに関する詳細な情報を見つけることができます。
kube-scheduler コントロールプレーン上で動作するコンポーネントで、新しく作られたPod にノード が割り当てられているか監視し、割り当てられていなかった場合にそのPodを実行するノードを選択します。
スケジューリングの決定は、PodあるいはPod群のリソース要求量、ハードウェア/ソフトウェア/ポリシーによる制約、アフィニティおよびアンチアフィニティの指定、データの局所性、ワークロード間の干渉、有効期限などを考慮して行われます。
kube-controller-manager コントロールプレーン上で動作するコンポーネントで、複数のコントローラー プロセスを実行します。
論理的には、各コントローラー は個別のプロセスですが、複雑さを減らすために一つの実行ファイルにまとめてコンパイルされ、単一のプロセスとして動きます。
コントローラーには以下が含まれます。
ノードコントローラー:ノードがダウンした場合の通知と対応を担当します。 Jobコントローラー:単発タスクを表すJobオブジェクトを監視し、そのタスクを実行して完了させるためのPodを作成します。 EndpointSliceコントローラー:EndpointSliceオブジェクトを作成します(つまり、ServiceとPodを紐付けます)。 ServiceAccountコントローラー:新規の名前空間に対して、デフォルトのServiceAccountを作成します。 cloud-controller-manager クラウド特有の制御ロジックを組み込むKubernetesの
control plane コンポーネントです。クラウドコントロールマネージャーは、クラスターをクラウドプロバイダーAPIをリンクし、クラスターのみで相互作用するコンポーネントからクラウドプラットフォームで相互作用するコンポーネントを分離します。
cloud-controller-managerは、クラウドプロバイダー固有のコントローラーのみを実行します。
Kubernetesをオンプレミスあるいは個人のPC内での学習環境で動かす際には、クラスターにcloud controller managerはありません。
kube-controller-managerと同様に、cloud-controller-managerは複数の論理的に独立したコントロールループをシングルバイナリにまとめ、一つのプロセスとして動作します。パフォーマンスを向上させるあるいは障害に耐えるために水平方向にスケールする(一つ以上のコピーを動かす)ことができます。
次の各コントローラーは、それぞれ以下に示すような目的のためにクラウドプロバイダーへの依存関係を持つことができるようになっています。
Nodeコントローラー: ノードが応答を停止した後、クラウドで当該ノードが削除されたかどうかを判断するため Route コントローラー: 基盤となるクラウドインフラのルートを設定するため Service コントローラー: クラウドプロバイダーのロードバランサーの作成、更新、削除を行うため ノードコンポーネント ノードコンポーネントはすべてのノードで実行され、稼働中のPodの管理やKubernetesの実行環境を提供します。
kubelet クラスター内の各ノード で実行されるエージェントです。各コンテナ がPod で実行されていることを保証します。
kubeletは、さまざまなメカニズムを通じて提供されるPodSpecのセットを取得し、それらのPodSpecに記述されているコンテナが正常に実行されている状態を保証します。kubeletは、Kubernetesが作成したものではないコンテナは管理しません。
kube-proxy kube-proxyはクラスター内の各node で動作しているネットワークプロキシで、KubernetesのService コンセプトの一部を実装しています。
kube-proxy は、Nodeのネットワークルールをメンテナンスします。これらのネットワークルールにより、クラスターの内部または外部のネットワークセッションからPodへのネットワーク通信が可能になります。
kube-proxyは、オペレーティングシステムにパケットフィルタリング層があり、かつ使用可能な場合、パケットフィルタリング層を使用します。それ以外の場合は自身でトラフィックを転送します。
コンテナランタイム コンテナランタイムは、コンテナの実行を担当するソフトウェアです。
Kubernetesは次の複数のコンテナランタイムをサポートします。
Docker 、containerd 、CRI-O 、
および全ての
Kubernetes CRI (Container Runtime Interface)
実装です。
アドオン アドオンはクラスター機能を実装するためにKubernetesリソース(DaemonSet 、Deployment など)を使用します。
アドオンはクラスターレベルの機能を提供しているため、アドオンのリソースで名前空間が必要なものはkube-system
名前空間に属します。
いくつかのアドオンについて以下で説明します。より多くの利用可能なアドオンのリストは、アドオン をご覧ください。
DNS クラスターDNS以外のアドオンは必須ではありませんが、すべてのKubernetesクラスターはクラスターDNS を持つべきです。多くの使用例がクラスターDNSを前提としています。
クラスターDNSは、環境内の他のDNSサーバーに加えて、KubernetesサービスのDNSレコードを提供するDNSサーバーです。
Kubernetesによって開始されたコンテナは、DNS検索にこのDNSサーバーを自動的に含めます。
Web UI (ダッシュボード) ダッシュボード は、Kubernetesクラスター用の汎用WebベースUIです。これによりユーザーはクラスターおよびクラスター内で実行されているアプリケーションについて、管理およびトラブルシューティングを行うことができます。
コンテナリソース監視 コンテナリソース監視 は、コンテナに関する一般的な時系列メトリックを中央データベースに記録します。また、そのデータを閲覧するためのUIを提供します。
クラスターレベルのロギング クラスターレベルのロギング メカニズムは、コンテナのログを、検索/参照インターフェースを備えた中央ログストアに保存します。
次の項目 1.2 - Kubernetes API Kubernetes APIを使用すると、Kubernetes内のオブジェクトの状態をクエリで操作できます。 Kubernetesのコントロールプレーンの中核は、APIサーバーとそれが公開するHTTP APIです。ユーザー、クラスターのさまざまな部分、および外部コンポーネントはすべて、APIサーバーを介して互いに通信します。
Kubernetesの中核である control plane はAPI server です。
APIサーバーは、エンドユーザー、クラスターのさまざまな部分、および外部コンポーネントが相互に通信できるようにするHTTP APIを公開します。
Kubernetes APIを使用すると、Kubernetes API内のオブジェクトの状態をクエリで操作できます(例:Pod、Namespace、ConfigMap、Events)。
ほとんどの操作は、APIを使用しているkubectl コマンドラインインターフェースもしくはkubeadm のような別のコマンドラインツールを通して実行できます。
RESTコールを利用して直接APIにアクセスすることも可能です。
Kubernetes APIを利用してアプリケーションを書いているのであれば、client libraries の利用を考えてみてください。
OpenAPI 仕様 完全なAPIの詳細は、OpenAPI を使用して文書化されています。
OpenAPI V2 Kubernetes APIサーバーは、/openapi/v2
エンドポイントを介してOpenAPI v2仕様を提供します。
次のように要求ヘッダーを使用して、応答フォーマットを要求できます。
OpenAPI v2クエリの有効なリクエストヘッダー値 ヘッダー 取りうる値 備考 Accept-Encoding
gzip
このヘッダーを使わないことも可能 Accept
application/com.github.proto-openapi.spec.v2@v1.0+protobuf
主にクラスター内での使用 application/json
デフォルト *
application/json
を提供
Kubernetesは、他の手段として主にクラスター間の連携用途向けのAPIに、Protocol buffersをベースにしたシリアライズフォーマットを実装しています。このフォーマットに関しては、Kubernetes Protobuf serialization デザイン提案を参照してください。また、各スキーマのInterface Definition Language(IDL)ファイルは、APIオブジェクトを定義しているGoパッケージ内に配置されています。
OpenAPI V3 FEATURE STATE:
Kubernetes v1.24 [beta]
Kubernetes v1.32では、OpenAPI v3によるAPI仕様をベータサポートとして提供しています。これは、デフォルトで有効化されているベータ機能です。kube-apiserverのOpenAPIV3
というfeature gate を切ることにより、このベータ機能を無効化することができます。
/openapi/v3
が、全ての利用可能なグループやバージョンの一覧を閲覧するためのディスカバリーエンドポイントとして提供されています。このエンドポイントは、JSONのみを返却します。利用可能なグループやバージョンは、次のような形式で提供されます。
{
"paths": {
...,
"api/v1": {
"serverRelativeURL": "/openapi/v3/api/v1?hash=CC0E9BFD992D8C59AEC98A1E2336F899E8318D3CF4C68944C3DEC640AF5AB52D864AC50DAA8D145B3494F75FA3CFF939FCBDDA431DAD3CA79738B297795818CF"
},
"apis/admissionregistration.k8s.io/v1": {
"serverRelativeURL": "/openapi/v3/apis/admissionregistration.k8s.io/v1?hash=E19CC93A116982CE5422FC42B590A8AFAD92CDE9AE4D59B5CAAD568F083AD07946E6CB5817531680BCE6E215C16973CD39003B0425F3477CFD854E89A9DB6597"
},
....
}
}
クライアントサイドのキャッシングを改善するために、相対URLはイミュータブルな(不変の)OpenAPI記述を指しています。
また、APIサーバーも、同様の目的で適切なHTTPキャッシュヘッダー(Expires
には1年先の日付、Cache-Control
にはimmutable
)をセットします。廃止されたURLが使用された場合、APIサーバーは最新のURLへのリダイレクトを返します。
Kubernetes APIサーバーは、/openapi/v3/apis/<group>/<version>?hash=<hash>
のエンドポイントにて、KubernetesのグループバージョンごとにOpenAPI v3仕様を公開しています。
受理されるリクエストヘッダーについては、以下の表の通りです。
OpenAPI v3において有効なリクエストヘッダー ヘッダー 取りうる値 備考 Accept-Encoding
gzip
このヘッダーを使わないことも可能 Accept
application/com.github.proto-openapi.spec.v3@v1.0+protobuf
主にクラスター内での使用 application/json
デフォルト *
application/json
を提供
永続性 KubernetesはAPIリソースの観点からシリアル化された状態をetcd に書き込むことで保存します。
APIグループとバージョニング フィールドの削除やリソース表現の再構成を簡単に行えるようにするため、Kubernetesは複数のAPIバージョンをサポートしており、/api/v1
や/apis/rbac.authorization.k8s.io/v1alpha1
のように、それぞれ異なるAPIのパスが割り当てられています。
APIが、システムリソースと動作について明確かつ一貫したビューを提供し、サポート終了、実験的なAPIへのアクセス制御を有効にするために、リソースまたはフィールドレベルではなく、APIレベルでバージョンが行われます。
APIの発展や拡張を簡易に行えるようにするため、Kubernetesは有効もしくは無効 を行えるAPIグループ を実装しました。
APIリソースは、APIグループ、リソースタイプ、ネームスペース(namespacedリソースのための)、名前によって区別されます。APIサーバーは、APIバージョン間の変換を透過的に処理します。すべてのバージョンの違いは、実際のところ同じ永続データとして表現されます。APIサーバーは、同じ基本的なデータを複数のAPIバージョンで提供することができます。
例えば、同じリソースでv1
とv1beta1
の2つのバージョンが有ることを考えてみます。
v1beta1
バージョンのAPIを利用しオブジェクトを最初に作成したとして、v1beta1
バージョンが非推奨となり削除されるまで、v1beta1
もしくはv1
どちらのAPIバージョンを利用してもオブジェクトのread、update、deleteができます。
その時点では、v1
APIを使用してオブジェクトの修正やアクセスを継続することが可能です。
APIの変更 成功を収めているシステムはすべて、新しいユースケースの出現や既存の変化に応じて成長し、変化する必要があります。
したがって、Kubernetesには、Kubernetes APIを継続的に変更および拡張できる設計機能があります。
Kubernetesプロジェクトは、既存のクライアントとの互換性を破壊 しないこと 、およびその互換性を一定期間維持して、他のプロジェクトが適応する機会を提供することを目的としています。
基本的に、新しいAPIリソースと新しいリソースフィールドは追加することができます。
リソースまたはフィールドを削除するには、API非推奨ポリシー に従ってください。
Kubernetesは、通常はAPIバージョンv1
として、公式のKubernetes APIが一度一般提供(GA)に達した場合、互換性を維持することを強く確約します。
さらに、Kubernetesは、公式Kubernetes APIの beta APIバージョン経由で永続化されたデータとの互換性を維持します。
そして、機能が安定したときにGA APIバージョン経由でデータを変換してアクセスできることを保証します。
beta APIを採用した場合、APIが卒業(Graduate)したら、後続のbetaまたはstable APIに移行する必要があります。
これを行うのに最適な時期は、オブジェクトが両方のAPIバージョンから同時にアクセスできるbeta APIの非推奨期間中です。
beta APIが非推奨期間を終えて提供されなくなったら、代替APIバージョンを使用する必要があります。
備考: Kubernetesは、 alpha APIバージョンについても互換性の維持に注力しますが、いくつかの事情により不可である場合もあります。
alpha APIバージョンを使っている場合、クラスターをアップグレードする時にKubernetesのリリースノートを確認してください。
APIが互換性のない方法で変更された場合は、アップグレードをする前に既存のalphaオブジェクトをすべて削除する必要があります。APIバージョンレベルの定義に関する詳細はAPIバージョンのリファレンス を参照してください。
APIの拡張 Kubernetes APIは2つの方法で拡張できます。
カスタムリソース は、APIサーバーが選択したリソースAPIをどのように提供するかを宣言的に定義します。アグリゲーションレイヤー を実装することでKubernetes APIを拡張することもできます。次の項目 1.3 - Kubernetesオブジェクトを利用する Kubernetesオブジェクトは、Kubernetes上で永続的なエンティティです。Kubernetesはこれらのエンティティを使い、クラスターの状態を表現します。 Kubernetesオブジェクトモデルと、これらのオブジェクトの利用方法について学びます。
1.3.1 - Kubernetesオブジェクトを理解する このページでは、KubernetesオブジェクトがKubernetes APIでどのように表現されているか、またそれらを.yaml
フォーマットでどのように表現するかを説明します。
Kubernetesオブジェクトを理解する Kubernetesオブジェクト は、Kubernetes上で永続的なエンティティです。Kubernetesはこれらのエンティティを使い、クラスターの状態を表現します。具体的に言うと、下記のような内容が表現できます:
どのようなコンテナ化されたアプリケーションが稼働しているか(またそれらはどのノード上で動いているか) それらのアプリケーションから利用可能なリソース アプリケーションがどのように振る舞うかのポリシー、例えば再起動、アップグレード、耐障害性ポリシーなど Kubernetesオブジェクトは「意図の記録」です。一度オブジェクトを作成すると、Kubernetesは常にそのオブジェクトが存在し続けるように動きます。オブジェクトを作成することで、Kubernetesに対し効果的にあなたのクラスターのワークロードがこのようになっていて欲しいと伝えているのです。これが、あなたのクラスターの望ましい状態 です。
Kubernetesオブジェクトを操作するには、作成、変更、または削除に関わらずKubernetes API を使う必要があるでしょう。例えばkubectl
コマンドラインインターフェースを使った場合、このCLIが処理に必要なKubernetes API命令を、あなたに代わり発行します。あなたのプログラムからクライアントライブラリ を利用し、直接Kubernetes APIを利用することも可能です。
オブジェクトのspec(仕様)とstatus(状態) ほとんどのKubernetesオブジェクトは、オブジェクトの設定を管理する2つの入れ子になったオブジェクトのフィールドを持っています。それはオブジェクト spec
とオブジェクト status
です。spec
を持っているオブジェクトに関しては、オブジェクト作成時にspec
を設定する必要があり、望ましい状態としてオブジェクトに持たせたい特徴を記述する必要があります。
status
オブジェクトはオブジェクトの 現在の状態 を示し、その情報はKubernetesシステムとそのコンポーネントにより提供、更新されます。Kubernetesコントロールプレーン は、あなたから指定された望ましい状態と現在の状態が一致するよう常にかつ積極的に管理をします。
例えば、KubernetesのDeploymentはクラスター上で稼働するアプリケーションを表現するオブジェクトです。Deploymentを作成するとき、アプリケーションの複製を3つ稼働させるようDeploymentのspecで指定するかもしれません。KubernetesはDeploymentのspecを読み取り、指定されたアプリケーションを3つ起動し、現在の状態がspecに一致するようにします。もしこれらのインスタンスでどれかが落ちた場合(statusが変わる)、Kubernetesはspecと、statusの違いに反応し、修正しようとします。この場合は、落ちたインスタンスの代わりのインスタンスを立ち上げます。
spec、status、metadataに関するさらなる情報は、Kubernetes API Conventions をご確認ください。
Kubernetesオブジェクトを記述する Kubernetesでオブジェクトを作成する場合、オブジェクトの基本的な情報(例えば名前)と共に、望ましい状態を記述したオブジェクトのspecを渡さなければいけません。KubernetesAPIを利用しオブジェクトを作成する場合(直接APIを呼ぶか、kubectl
を利用するかに関わらず)、APIリクエストはそれらの情報をJSON形式でリクエストのBody部に含んでいなければなりません。
ここで、KubernetesのDeploymentに必要なフィールドとオブジェクトのspecを記載した.yaml
ファイルの例を示します:
apiVersion : apps/v1 # for versions before 1.9.0 use apps/v1beta2
kind : Deployment
metadata :
name : nginx-deployment
spec :
selector :
matchLabels :
app : nginx
replicas : 2 # tells deployment to run 2 pods matching the template
template :
metadata :
labels :
app : nginx
spec :
containers :
- name : nginx
image : nginx:1.14.2
ports :
- containerPort : 80
上に示した.yaml
ファイルを利用してDeploymentを作成するには、kubectl
コマンドラインインターフェースに含まれているkubectl apply
コマンドに.yaml
ファイルを引数に指定し、実行します。ここで例を示します:
kubectl apply -f https://k8s.io/examples/application/deployment.yaml --record
出力結果は、下記に似た形になります:
deployment.apps/nginx-deployment created
必須フィールド Kubernetesオブジェクトを.yaml
ファイルに記載して作成する場合、下記に示すフィールドに値をセットしておく必要があります:
apiVersion
- どのバージョンのKubernetesAPIを利用してオブジェクトを作成するかkind
- どの種類のオブジェクトを作成するかmetadata
- オブジェクトを一意に特定するための情報、文字列のname
、UID
、また任意のnamespace
が該当するspec
- オブジェクトの望ましい状態spec
の正確なフォーマットは、Kubernetesオブジェクトごとに異なり、オブジェクトごとに特有な入れ子のフィールドを持っています。Kubernetes API リファレンス が、Kubernetesで作成できる全てのオブジェクトに関するspecのフォーマットを探すのに役立ちます。
例えば、Pod
オブジェクトに関するspec
のフォーマットはPodSpec v1 core を、またDeployment
オブジェクトに関するspec
のフォーマットはDeploymentSpec v1 apps をご確認ください。
次の項目 1.3.2 - Kubernetesオブジェクト管理 kubectl
コマンドラインツールは、Kubernetesオブジェクトを作成、管理するためにいくつかの異なる方法をサポートしています。
このドキュメントでは、それらの異なるアプローチごとの概要を提供します。
Kubectlを使ったオブジェクト管理の詳細は、Kubectl book を参照してください。
管理手法
警告: Kubernetesのオブジェクトは、いずれか一つの手法で管理してください。
同じオブジェクトに対して、複数の手法を組み合わせた場合、未定義の挙動をもたらします。管理手法 何を対象にするか 推奨環境 サポートライター 学習曲線 命令型コマンド 現行のオブジェクト 開発用プロジェクト 1+ 緩やか 命令型オブジェクト設定 個々のファイル 本番用プロジェクト 1 中程度 宣言型オブジェクト設定 ファイルのディレクトリ 本番用プロジェクト 1+ 急
命令型コマンド 命令型コマンドを使う場合、ユーザーはクラスター内の現行のオブジェクトに対して処理を行います。
ユーザーはkubectl
コマンドに処理内容を引数、もしくはフラグで指定します。
これはKubernetesの使い始め、またはクラスターに対して一度限りのタスクを行う際の最も簡単な手法です。
なぜなら、この手法は現行のオブジェクトに対して直接操作ができ、以前の設定履歴は提供されないからです。
例 Deploymentオブジェクトを作成し、nginxコンテナの単一インスタンスを起動します:
kubectl run nginx --image nginx
同じことを異なる構文で行います:
kubectl create deployment nginx --image nginx
トレードオフ オブジェクト設定手法に対する長所:
コマンドは簡潔、簡単に学ぶことができ、そして覚えやすいです コマンドではクラスターの設定を変えるのに、わずか1ステップしか必要としません オブジェクト設定手法に対する短所:
コマンドは変更レビュープロセスと連携しません コマンドは変更に伴う監査証跡を提供しません コマンドは現行がどうなっているかという情報を除き、レコードのソースを提供しません コマンドはオブジェクトを作成するためのテンプレートを提供しません 命令型オブジェクト設定 命令型オブジェクト設定では、kubectlコマンドに処理内容(create、replaceなど)、任意のフラグ、そして最低1つのファイル名を指定します。
指定されたファイルは、YAMLまたはJSON形式でオブジェクトの全ての定義情報を含んでいなければいけません。
オブジェクト定義の詳細は、APIリファレンス を参照してください。
警告: 命令型のreplace
コマンドは、既存の構成情報を新しく提供された設定に置き換え、設定ファイルに無いオブジェクトの全ての変更を削除します。
このアプローチは、構成情報が設定ファイルとは無関係に更新されるリソースタイプでは使用しないでください。
例えば、タイプがLoadBalancer
のServiceオブジェクトにおけるexternalIPs
フィールドは、設定ファイルとは無関係に、クラスターによって更新されます。例 設定ファイルに定義されたオブジェクトを作成します:
kubectl create -f nginx.yaml
設定ファイルに定義されたオブジェクトを削除します:
kubectl delete -f nginx.yaml -f redis.yaml
設定ファイルに定義された情報で、現行の設定を上書き更新します:
kubectl replace -f nginx.yaml
トレードオフ 命令型コマンド手法に対する長所:
オブジェクト設定をGitのような、ソースコード管理システムに格納することができます オブジェクト設定の変更内容をプッシュする前にレビュー、監査証跡を残すようなプロセスと連携することができます オブジェクト設定は新しいオブジェクトを作る際のテンプレートを提供します 命令型コマンド手法に対する短所:
オブジェクト設定ではオブジェクトスキーマの基礎的な理解が必要です オブジェクト設定ではYAMLファイルを書くという、追加のステップが必要です 宣言型オブジェクト設定手法に対する長所:
命令型オブジェクト設定の振る舞いは、よりシンプルで簡単に理解ができます Kubernetesバージョン1.5においては、命令型オブジェクト設定の方がより成熟しています 宣言型オブジェクト設定手法に対する短所:
命令型オブジェクト設定は各ファイルごとに設定を書くには最も適していますが、ディレクトリには適していません 現行オブジェクトの更新は設定ファイルに対して反映しなければなりません。反映されない場合、次の置き換え時に更新内容が失われてしまいます 宣言型オブジェクト設定 宣言型オブジェクト設定を利用する場合、ユーザーはローカルに置かれている設定ファイルを操作します。
しかし、ユーザーはファイルに対する操作内容を指定しません。作成、更新、そして削除といった操作はオブジェクトごとにkubectl
が検出します。
この仕組みが、異なるオブジェクトごとに異なる操作をディレクトリに対して行うことを可能にしています。
備考: 宣言型オブジェクト設定は、他の人が行った変更が設定ファイルにマージされなかったとしても、それらの変更を保持します。
これは、replace
API操作のように、全てのオブジェクト設定を置き換えるわけではなく、patch
API操作による、変更箇所のみの更新が可能にしています。例 config
ディレクトリ配下にある全てのオブジェクト設定ファイルを処理し、作成、または現行オブジェクトへのパッチを行います。
まず、diff
でどのような変更が行われるかを確認した後に適用します:
kubectl diff -f configs/
kubectl apply -f configs/
再帰的にディレクトリを処理します:
kubectl diff -R -f configs/
kubectl apply -R -f configs/
トレードオフ 命令型オブジェクト設定手法に対する長所:
現行オブジェクトに直接行われた変更が、それらが設定ファイルに反映されていなかったとしても、保持されます 宣言型オブジェクト設定は、ディレクトリごとの処理をより良くサポートしており、自動的にオブジェクトごとに操作のタイプ(作成、パッチ、削除)を検出します 命令型オブジェクト設定手法に対する短所:
宣言型オブジェクト設定は、デバッグ、そして想定外の結果が出たときに理解するのが困難です 差分を利用した一部のみの更新は、複雑なマージ、パッチの操作が必要です 次の項目 1.3.3 - オブジェクトの名前とID クラスター内の各オブジェクトには、そのタイプのリソースに固有の名前 があります。すべてのKubernetesオブジェクトには、クラスター全体で一意のUID もあります。
たとえば、同じ名前空間 内にmyapp-1234
という名前のPodは1つしか含められませんが、myapp-1234
という名前の1つのPodと1つのDeploymentを含めることができます。
ユーザーが一意ではない属性を付与するために、Kubernetesはラベル とアノテーション を提供しています。
名前 クライアントから提供され、リソースURL内のオブジェクトを参照する文字列です。例えば/api/v1/pods/何らかの名前
のようになります。
同じ種類のオブジェクトは、同じ名前を同時に持つことはできません。しかし、オブジェクトを削除することで、旧オブジェクトと同じ名前で新しいオブジェクトを作成できます。
次の3つの命名規則がよく使われます。
DNSサブドメイン名 ほとんどのリソースタイプには、RFC 1123 で定義されているDNSサブドメイン名として使用できる名前が必要です。
つまり、名前は次のとおりでなければなりません:
253文字以内 英小文字、数字、「-」または「.」のみを含む 英数字で始まる 英数字で終わる DNSラベル名 一部のリソースタイプでは、RFC 1123 で定義されているDNSラベル標準に従う名前が必要です。
つまり、名前は次のとおりでなければなりません:
63文字以内 英小文字、数字または「-」のみを含む 英数字で始まる 英数字で終わる パスセグメント名 一部のリソースタイプでは、名前をパスセグメントとして安全にエンコードできるようにする必要があります。
つまり、名前を「.」や「..」にすることはできず、名前に「/」または「%」を含めることはできません。
以下は、nginx-demo
という名前のPodのマニフェストの例です。
apiVersion : v1
kind : Pod
metadata :
name : nginx-demo
spec :
containers :
- name : nginx
image : nginx:1.14.2
ports :
- containerPort : 80
備考: 一部のリソースタイプには、名前に追加の制限があります。UID オブジェクトを一意に識別するためのKubernetesが生成する文字列です。
Kubernetesクラスターの生存期間中にわたって生成された全てのオブジェクトは、異なるUIDを持っています。これは類似のエンティティの、同一時間軸での存在を区別するのが目的です。
Kubernetes UIDは、UUIDのことを指します。
UUIDは、ISO/IEC 9834-8およびITU-T X.667として標準化されています。
次の項目 1.3.4 - ラベル(Labels)とセレクター(Selectors) ラベル(Labels) はPodなどのオブジェクトに割り当てられたキーとバリューのペアです。 ラベルはユーザーに関連した意味のあるオブジェクトの属性を指定するために使われることを目的としています。しかしKubernetesのコアシステムに対して直接的にその意味を暗示するものではありません。 ラベルはオブジェクトのサブセットを選択し、グルーピングするために使うことができます。また、ラベルはオブジェクトの作成時に割り当てられ、その後いつでも追加、修正ができます。 各オブジェクトはキーとバリューのラベルのセットを定義できます。各キーは、単一のオブジェクトに対してはユニークである必要があります。
"metadata" : {
"labels" : {
"key1" : "value1" ,
"key2" : "value2"
}
}
ラベルは効率的な検索・閲覧を可能にし、UIやCLI上での利用に最適です。
識別用途でない情報は、アノテーション を用いて記録されるべきです。
ラベルを使う動機 ラベルは、クライアントにそのマッピング情報を保存することを要求することなく、ユーザー独自の組織構造をシステムオブジェクト上で疎結合にマッピングできます。
サービスデプロイメントとバッチ処理のパイプラインは多くの場合、多次元のエンティティとなります(例: 複数のパーティション、Deployment、リリーストラック、ティアー、ティアー毎のマイクロサービスなど) 管理は分野横断的な操作が必要になることが多く、それによって厳密な階層表現、特にユーザーによるものでなく、インフラストラクチャーによって定義された厳格な階層のカプセル化が破られます。
ラベルの例:
"release" : "stable"
, "release" : "canary"
"environment" : "dev"
, "environment" : "qa"
, "environment" : "production"
"tier" : "frontend"
, "tier" : "backend"
, "tier" : "cache"
"partition" : "customerA"
, "partition" : "customerB"
"track" : "daily"
, "track" : "weekly"
これらは単によく使われるラベルの例です。ユーザーは自由に規約を決めることができます。
ラベルのキーは、ある1つのオブジェクトに対してユニークである必要があることは覚えておかなくてはなりません。
構文と文字セット ラベルは、キーとバリューのベアです。正しいラベルキーは2つのセグメントを持ちます。 それは/
によって分割されたオプショナルなプレフィックスと名前です。 名前セグメントは必須で、63文字以下である必要があり、文字列の最初と最後は英数字([a-z0-9A-Z]
)で、文字列の間ではこれに加えてダッシュ(-
)、アンダースコア(_
)、ドット(.
)を使うことができます。 プレフィックスはオプションです。もしプレフィックスが指定されていた場合、プレフィックスはDNSサブドメイン形式である必要があり、それはドット(.
)で区切られたDNSラベルのセットで、253文字以下である必要があり、最後にスラッシュ(/
)が続きます。
もしプレフィックスが省略された場合、ラベルキーはそのユーザーに対してプライベートであると推定されます。 エンドユーザーのオブジェクトにラベルを追加するような自動化されたシステムコンポーネント(例: kube-scheduler
kube-controller-manager
kube-apiserver
kubectl
やその他のサードパーティツール)は、プレフィックスを指定しなくてはなりません。
kubernetes.io/
とk8s.io/
プレフィックスは、Kubernetesコアコンポーネントのために予約されています。
正しいラベル値は63文字以下の長さで、空文字か、もしくは開始と終了が英数字([a-z0-9A-Z]
)で、文字列の間がダッシュ(-
)、アンダースコア(_
)、ドット(.
)と英数字である文字列を使うことができます。
例えば、environment: production
とapp: nginx
の2つのラベルを持つPodの設定ファイルは下記のようになります。
apiVersion : v1
kind : Pod
metadata :
name : label-demo
labels :
environment : production
app : nginx
spec :
containers :
- name : nginx
image : nginx:1.14.2
ports :
- containerPort : 80
ラベルセレクター 名前とUID とは異なり、ラベルはユニーク性を提供しません。通常、多くのオブジェクトが同じラベルを保持することを想定します。
ラベルセレクター を介して、クライアントとユーザーはオブジェクトのセットを指定できます。ラベルセレクターはKubernetesにおいてコアなグルーピング機能となります。
Kubernetes APIは現在2タイプのセレクターをサポートしています。 それは等価ベース(equality-based) と集合ベース(set-based) です。 単一のラベルセレクターは、コンマ区切りの複数の要件(requirements) で構成されています。 複数の要件がある場合、コンマセパレーターは論理積 AND (&&
)オペレーターと同様にふるまい、全ての要件を満たす必要があります。
空文字の場合や、指定なしのセレクターに関するセマンティクスは、コンテキストに依存します。
そしてセレクターを使うAPIタイプは、それらのセレクターの妥当性とそれらが示す意味をドキュメントに記載するべきです。
備考: ReplicaSetなど、いくつかのAPIタイプにおいて、2つのインスタンスのラベルセレクターは単一の名前空間において重複してはいけません。重複していると、コントローラーがそれらのラベルセレクターがコンフリクトした操作とみなし、どれだけの数のレプリカを稼働させるべきか決めることができなくなります。
注意: 等価ベース、集合ベースともに、論理OR (||
) オペレーターは存在しません。フィルターステートメントが意図した通りになっていることを確認してください。等価ベース(Equality-based) の要件(requirement)等価ベース(Equality-based) もしくは不等ベース(Inequality-based) の要件は、ラベルキーとラベル値によるフィルタリングを可能にします。 要件に一致したオブジェクトは、指定されたラベルの全てを満たさなくてはいけませんが、それらのオブジェクトはさらに追加のラベルも持つことができます。 そして等価ベースの要件においては、3つの種類のオペレーターの利用が許可されています。=
、==
、!=
となります。 最初の2つのオペレーター(=
、==
)は等価(Equality) を表現し(この2つは単なる同義語)、最後の1つ(!=
)は不等(Inequality) を意味します。 例えば
environment = production
tier != frontend
最初の例は、キーがenvironment
で、値がproduction
である全てのリソースを対象にします。 次の例は、キーがtier
で、値がfrontend
とは異なるリソースと、tier
という名前のキーを持たない全てのリソースを対象にします。 コンマセパレーター,
を使って、production
の中から、frontend
のものを除外するようにフィルターすることもできます。environment=production,tier!=frontend
等価ベースのラベル要件の1つの使用シナリオとして、PodにおけるNodeの選択要件を指定するケースがあります。 例えば、下記のサンプルPodは、ラベルaccelerator=nvidia-tesla-p100
をもったNodeを選択します。
apiVersion : v1
kind : Pod
metadata :
name : cuda-test
spec :
containers :
- name : cuda-test
image : "registry.k8s.io/cuda-vector-add:v0.1"
resources :
limits :
nvidia.com/gpu : 1
nodeSelector :
accelerator : nvidia-tesla-p100
集合ベース(Set-based) の要件(requirement)集合ベース(Set-based) のラベルの要件は値のセットによってキーをフィルタリングします。in
、notin
、exists
の3つのオペレーターをサポートしています(キーを特定するのみ)。
例えば:
environment in (production, qa)
tier notin (frontend, backend)
partition
!partition
最初の例では、キーがenvironment
で、値がproduction
かqa
に等しいリソースを全て選択します。 第2の例では、キーがtier
で、値がfrontend
とbackend
以外のもの、そしてtier
キーを持たないリソースを全て選択します。 第3の例では、partition
というキーをもつラベルを全て選択し、値はチェックしません。 第4の例では、partition
というキーを持たないラベルを全て選択し、値はチェックしません。 同様に、コンマセパレーターは、AND オペレーターと同様にふるまいます。そのため、partition
とenvironment
キーの値がともにqa
でないラベルを選択するには、partition,environment notin (qa)
と記述することで可能です。集合ベース のラベルセレクターは、environment=production
という記述がenvironment in (production)
と等しいため、一般的な等価形式となります。 !=
とnotin
も同様に等価となります。
集合ベース の要件は、等価ベース の要件と混在できます。 例えば:partition in (customerA, customerB),environment!=qa
.
API LISTとWATCHによるフィルタリング LISTとWATCHオペレーションは、単一のクエリパラメーターを使うことによって返されるオブジェクトのセットをフィルターするためのラベルセレクターを指定できます。集合ベース と等価ベース のどちらの要件も許可されています(ここでは、URLクエリストリング内で出現します)。
等価ベース での要件: ?labelSelector=environment%3Dproduction,tier%3Dfrontend
集合ベース での要件: ?labelSelector=environment+in+%28production%2Cqa%29%2Ctier+in+%28frontend%29
上記の2つの形式のラベルセレクターはRESTクライアントを介してリストにしたり、もしくは確認するために使われます。 例えば、kubectl
によってapiserver
をターゲットにし、等価ベース の要件でフィルターすると以下のように書けます。
kubectl get pods -l environment = production,tier= frontend
もしくは、集合ベース の要件を指定すると以下のようになります。
kubectl get pods -l 'environment in (production),tier in (frontend)'
すでに言及したように、集合ベース の要件は、等価ベース の要件より表現力があります。 例えば、値に対する OR オペレーターを実装して以下のように書けます。
kubectl get pods -l 'environment in (production, qa)'
もしくは、notin オペレーターを介して、否定マッチングによる制限もできます。
kubectl get pods -l 'environment,environment notin (frontend)'
APIオブジェクトに参照を設定する Service
と ReplicationController
のような、いくつかのKubernetesオブジェクトでは、ラベルセレクターをPod のような他のリソースのセットを指定するのにも使われます。
ServiceとReplicationController Service
が対象とするPodの集合は、ラベルセレクターによって定義されます。 同様に、ReplicationController
が管理するべきPod数についてもラベルセレクターを使って定義されます。
それぞれのオブジェクトに対するラベルセレクターはマップを使ってjson
もしくはyaml
形式のファイルで定義され、等価ベース のセレクターのみサポートされています。
"selector" : {
"component" : "redis" ,
}
もしくは
selector :
component : redis
このセレクター(それぞれjson
またはyaml
形式)は、component=redis
またはcomponent in (redis)
と等価です。
集合ベース の要件指定をサポートするリソースJob
やDeployment
、ReplicaSet
やDaemonSet
などの比較的新しいリソースは、集合ベース での要件指定もサポートしています。
selector :
matchLabels :
component : redis
matchExpressions :
- {key: tier, operator: In, values : [cache]}
- {key: environment, operator: NotIn, values : [dev]}
matchLabels
は、{key,value}
ペアのマップです。matchLabels
内の単一の{key,value}
は、matchExpressions
の要素と等しく、それは、key
フィールドがキー名で、operator
が"In"で、values
配列は単に"値"を保持します。matchExpressions
はPodセレクター要件のリストです。対応しているオペレーターはIn
、NotIn
、Exists
とDoesNotExist
です。values
のセットは、In
とNotIn
オペレーターにおいては空文字を許容しません。matchLabels
とmatchExpressions
の両方によって指定された全ての要件指定はANDで判定されます。つまり要件にマッチするには指定された全ての要件を満たす必要があります。
Nodeのセットを選択する ラベルを選択するための1つのユースケースはPodがスケジュールできるNodeのセットを制限することです。 さらなる情報に関しては、Node選定 のドキュメントを参照してください。
1.3.5 - Namespace(名前空間) Kubernetesは、同一の物理クラスター上で複数の仮想クラスターの動作をサポートします。
この仮想クラスターをNamespaceと呼びます。
複数のNamespaceを使う時 Namespaceは、複数のチーム・プロジェクトにまたがる多くのユーザーがいる環境での使用を目的としています。
数人から数十人しかユーザーのいないクラスターに対して、あなたはNamespaceを作成したり、考える必要は全くありません。
Kubernetesが提供するNamespaceの機能が必要となった時に、Namespaceの使用を始めてください。
Namespaceは名前空間のスコープを提供します。リソース名は単一のNamespace内ではユニークである必要がありますが、Namespace全体ではその必要はありません。Namespaceは相互にネストすることはできず、各Kubernetesリソースは1つのNamespaceにのみ存在できます。
Namespaceは、複数のユーザーの間でクラスターリソースを分割する方法です。(これはリソースクォータ を介して分割します。)
同じアプリケーションの異なるバージョンなど、少し違うリソースをただ分割するだけに、複数のNamespaceを使う必要はありません。
同一のNamespace内でリソースを区別するためにはラベル を使用してください。
Namespaceを利用する Namespaceの作成と削除方法はNamespaceの管理ガイドドキュメント に記載されています。
備考: プレフィックスkube-
を持つNamespaceは、KubernetesシステムのNamespaceとして予約されているため利用は避けてください。Namespaceの表示 ユーザーは、以下の方法で単一クラスター内の現在のNamespaceの一覧を表示できます。
NAME STATUS AGE
default Active 1d
kube-node-lease Active 1d
kube-system Active 1d
kube-public Active 1d
Kubernetesの起動時には4つの初期Namespaceが作成されています。
default
他にNamespaceを持っていないオブジェクトのためのデフォルトNamespacekube-system
Kubernetesシステムによって作成されたオブジェクトのためのNamespacekube-public
このNamespaceは自動的に作成され、全てのユーザーから読み取り可能です。(認証されていないユーザーも含みます。)
このNamespaceは、リソースをクラスター全体を通じてパブリックに表示・読み取り可能にするため、ほとんどクラスターによって使用される用途で予約されます。 このNamespaceのパブリックな側面は単なる慣例であり、要件ではありません。kube-node-lease
クラスターのスケールに応じたノードハートビートのパフォーマンスを向上させる各ノードに関連したLeaseオブジェクトのためのNamespace。Namespaceの設定 現在のリクエストのNamespaceを設定するには、--namespace
フラグを使用します。
例:
kubectl run nginx --image= nginx --namespace= <insert-namespace-name-here>
kubectl get pods --namespace= <insert-namespace-name-here>
Namespace設定の永続化 ユーザーはあるコンテキストのその後のコマンドで使うために、コンテキスト内で永続的にNamespaceを保存できます。
kubectl config set-context --current --namespace= <insert-namespace-name-here>
# Validate it
kubectl config view --minify | grep namespace:
NamespaceとDNS ユーザーがService を作成するとき、Serviceは対応するDNSエントリ を作成します。
このエントリは<service-name>.<namespace-name>.svc.cluster.local
という形式になり、これはもしあるコンテナがただ<service-name>
を指定していた場合、Namespace内のローカルのServiceに対して名前解決されます。
これはデベロップメント、ステージング、プロダクションといった複数のNamespaceをまたいで同じ設定を使う時に効果的です。
もしユーザーがNamespaceをまたいでアクセスしたい時、 完全修飾ドメイン名(FQDN)を指定する必要があります。
すべてのオブジェクトはNamespaceに属しているとは限らない ほとんどのKubernetesリソース(例えば、Pod、Service、ReplicationControllerなど)はいくつかのNamespaceにあります。
しかしNamespaceのリソースそれ自体は単一のNamespace内にありません。
そしてNode やPersistentVolumeのような低レベルのリソースはどのNamespaceにも属していません。
どのKubernetesリソースがNamespaceに属しているか、属していないかを見るためには、以下のコマンドで確認できます。
# Namespaceに属しているもの
kubectl api-resources --namespaced= true
# Namespaceに属していないもの
kubectl api-resources --namespaced= false
次の項目 1.3.6 - アノテーション(Annotations) ユーザーは、識別用途でない任意のメタデータをオブジェクトに割り当てるためにアノテーションを使用できます。ツールやライブラリなどのクライアントは、このメタデータを取得できます。
オブジェクトにメタデータを割り当てる ユーザーは、Kubernetesオブジェクトに対してラベルやアノテーションの両方またはどちらか一方を割り当てることができます。
ラベルはオブジェクトの選択や、特定の条件を満たしたオブジェクトの集合を探すことに使うことができます。
それと対照的に、アノテーションはオブジェクトを識別、または選択するために使用されません。
アノテーション内のメタデータは大小様々で、構造化されているものや、そうでないものも設定でき、ラベルでは許可されていない文字も含むことができます。
アノテーションは、ラベルと同様に、キーとバリューのマップとなります。
"metadata" : {
"annotations" : {
"key1" : "value1" ,
"key2" : "value2"
}
}
下記は、アノテーション内で記録できる情報の例です。
宣言的設定レイヤーによって管理されているフィールド。これらのフィールドをアノテーションとして割り当てることで、クライアントもしくはサーバによってセットされたデフォルト値、オートサイジングやオートスケーリングシステムによってセットされたフィールドや、自動生成のフィールドなどと区別することができます。
ビルド、リリースやタイムスタンプのようなイメージの情報、リリースID、gitのブランチ、PR番号、イメージハッシュ、レジストリアドレスなど
ロギング、監視、分析用のポインタ、もしくは監査用リポジトリ
デバッグ目的で使用されるためのクライアントライブラリやツールの情報。例えば、名前、バージョン、ビルド情報など。
他のエコシステムのコンポーネントからの関連オブジェクトのURLなど、ユーザーやツール、システムの出所情報。
軽量ロールアウトツールのメタデータ。 例えば設定やチェックポイントなど。
情報をどこで確認できるかを示すためのもの。例えばチームのウェブサイト、責任者の電話番号や、ページャー番号やディレクトリエンティティなど。
システムのふるまいの変更や、標準ではない機能を利用可能にするために、エンドユーザーがシステムに対して指定する値
アノテーションを使用するかわりに、ユーザーはこのようなタイプの情報を外部のデータベースやディレクトリに保存することもできます。しかし、それによりデプロイ、管理、イントロスペクションを行うためのクライアンライブラリやツールの生成が非常に難しくなります。
構文と文字セット アノテーション はキーとバリューのペアです。有効なアノテーションのキーの形式は2つのセグメントがあります。
プレフィックス(オプション)と名前で、それらはスラッシュ/
で区切られます。
名前セグメントは必須で、63文字以下である必要があり、文字列の最初と最後は英数字([a-z0-9A-Z]
)と、文字列の間にダッシュ(-
)、アンダースコア(_
)、ドット(.
)を使うことができます。
プレフィックスはオプションです。もしプレフィックスが指定されていた場合、プレフィックスはDNSサブドメイン形式である必要があり、それはドット(.
)で区切られたDNSラベルのセットで、253文字以下である必要があり、最後にスラッシュ(/
)が続きます。
もしプレフィックスが除外された場合、アノテーションキーはそのユーザーに対してプライベートであると推定されます。
エンドユーザーのオブジェクトにアノテーションを追加するような自動化されたシステムコンポーネント(例: kube-scheduler
kube-controller-manager
kube-apiserver
kubectl
やその他のサードパーティツール)は、プレフィックスを指定しなくてはなりません。
kubernetes.io/
とk8s.io/
プレフィックスは、Kubernetesコアコンポーネントのために予約されています。
たとえば、imageregistry: https://hub.docker.com/
というアノテーションが付いたPodの構成ファイルは次のとおりです:
apiVersion : v1
kind : Pod
metadata :
name : annotations-demo
annotations :
imageregistry : "https://hub.docker.com/"
spec :
containers :
- name : nginx
image : nginx:1.14.2
ports :
- containerPort : 80
次の項目 ラベルとセレクター について学習してください。
1.3.7 - フィールドセレクター(Field Selectors) フィールドセレクター(Field Selectors) は、1つかそれ以上のリソースフィールドの値を元にKubernetesリソースを選択 するためのものです。 フィールドセレクタークエリの例は以下の通りです。
metadata.name=my-service
metadata.namespace!=default
status.phase=Pending
下記のkubectl
コマンドは、status.phase
フィールドの値がRunning
である全てのPodを選択します。
kubectl get pods --field-selector status.phase= Running
備考: フィールドセレクターは本質的にリソースの フィルター となります。デフォルトでは、セレクター/フィルターが指定されていない場合は、全てのタイプのリソースが取得されます。これは、kubectl
クエリのkubectl get pods
とkubectl get pods --field-selector ""
が同じであることを意味します。サポートされているフィールド サポートされているフィールドセレクターはKubernetesリソースタイプによって異なります。全てのリソースタイプはmetadata.name
とmetadata.namespace
フィールドをサポートしています。サポートされていないフィールドセレクターの使用をするとエラーとなります。 例えば以下の通りです。
kubectl get ingress --field-selector foo.bar= baz
Error from server (BadRequest): Unable to find "ingresses" that match label selector "", field selector "foo.bar=baz": "foo.bar" is not a known field selector: only "metadata.name", "metadata.namespace"
サポートされているオペレーター ユーザーは、=
、==
や!=
といったオペレーターをフィールドセレクターと組み合わせて使用できます。(=
と==
は同義) 例として、下記のkubectl
コマンドはdefault
ネームスペースに属していない全てのKubernetes Serviceを選択します。
kubectl get services --all-namespaces --field-selector metadata.namespace!= default
連結されたセレクター ラベル や他のセレクターと同様に、フィールドセレクターはコンマ区切りのリストとして連結することができます。 下記のkubectl
コマンドは、status.phase
がRunning
でなく、かつspec.restartPolicy
フィールドがAlways
に等しいような全てのPodを選択します。
kubectl get pods --field-selector= status.phase!= Running,spec.restartPolicy= Always
複数のリソースタイプ ユーザーは複数のリソースタイプにまたがったフィールドセレクターを利用できます。 下記のkubectl
コマンドは、default
ネームスペースに属していない全てのStatefulSetとServiceを選択します。
kubectl get statefulsets,services --field-selector metadata.namespace!= default
1.3.8 - ファイナライザー(Finalizers) ファイナライザーは、削除対象としてマークされたリソースを完全に削除する前に、特定の条件が満たされるまでKubernetesを待機させるための名前空間付きのキーです。
ファイナライザーは、削除されたオブジェクトが所有していたリソースをクリーンアップするようにコントローラー に警告します。
Kubernetesにファイナライザーが指定されたオブジェクトを削除するように指示すると、Kubernetes APIはそのオブジェクトに.metadata.deletionTimestamp
を追加し削除対象としてマークして、ステータスコード202
(HTTP "Accepted")を返します。
コントロールプレーンやその他のコンポーネントがファイナライザーによって定義されたアクションを実行している間、対象のオブジェクトは終了中の状態のまま残っています。
それらのアクションが完了したら、そのコントローラーは関係しているファイナライザーを対象のオブジェクトから削除します。
metadata.finalizers
フィールドが空になったら、Kubernetesは削除が完了したと判断しオブジェクトを削除します。
ファイナライザーはリソースのガベージコレクション を管理するために使うことができます。
例えば、コントローラーが対象のリソースを削除する前に関連するリソースやインフラをクリーンアップするためにファイナライザーを定義することができます。
ファイナライザーを利用すると、対象のリソースを削除する前に特定のクリーンアップを行うようにコントローラー に警告することで、ガベージコレクション を管理することができます。
大抵の場合ファイナライザーは実行されるコードを指定することはありません。
その代わり、一般的にはアノテーションのように特定のリソースに関するキーのリストになります。
Kubernetesはいくつかのファイナライザーを自動的に追加しますが、自分で追加することもできます。
ファイナライザーはどのように動作するか マニフェストファイルを使ってリソースを作るとき、metadata.finalizers
フィールドの中でファイナライザーを指定することができます。
リソースを削除しようとするとき、削除リクエストを扱うAPIサーバーはfinalizers
フィールドの値を確認し、以下のように扱います。
削除を開始した時間をオブジェクトのmetadata.deletionTimestamp
フィールドに設定します。 metadata.finalizers
フィールドが空になるまでオブジェクトが削除されるのを阻止します。ステータスコード202
(HTTP "Accepted")を返します。 ファイナライザーを管理しているコントローラーは、オブジェクトの削除がリクエストされたことを示すmetadata.deletionTimestamp
がオブジェクトに設定されたことを検知します。
するとコントローラーはリソースに指定されたファイナライザーの要求を満たそうとします。
ファイナライザーの条件が満たされるたびに、そのコントローラーはリソースのfinalizers
フィールドの対象のキーを削除します。
finalizers
フィールドが空になったとき、deletionTimestamp
フィールドが設定されたオブジェクトは自動的に削除されます。管理外のリソース削除を防ぐためにファイナライザーを利用することもできます。
ファイナライザーの一般的な例はkubernetes.io/pv-protection
で、これは PersistentVolume
オブジェクトが誤って削除されるのを防ぐためのものです。
PersistentVolume
オブジェクトをPodが利用中の場合、Kubernetesはpv-protection
ファイナライザーを追加します。
PersistentVolume
を削除しようとするとTerminating
ステータスになりますが、ファイナライザーが存在しているためコントローラーはボリュームを削除することができません。
PodがPersistentVolume
の利用を停止するとKubernetesはpv-protection
ファイナライザーを削除し、コントローラーがボリュームを削除します。
オーナーリファレンス、ラベル、ファイナライザー ラベル のように、
オーナーリファレンス はKubernetesのオブジェクト間の関係性を説明しますが、利用される目的が異なります。
コントローラー がPodのようなオブジェクトを管理するとき、関連するオブジェクトのグループの変更を追跡するためにラベルを利用します。
例えば、Job がいくつかのPodを作成するとき、JobコントローラーはそれらのPodにラベルを付け、クラスター内の同じラベルを持つPodの変更を追跡します。
Jobコントローラーは、Podを作成したJobを指すオーナーリファレンス もそれらのPodに追加します。
Podが実行されているときにJobを削除すると、Kubernetesはオーナーリファレンス(ラベルではない)を使って、クリーンアップする必要のあるPodをクラスター内から探し出します。
また、Kubernetesは削除対象のリソースのオーナーリファレンスを認識して、ファイナライザーを処理します。
状況によっては、ファイナライザーが依存オブジェクトの削除をブロックしてしまい、対象のオーナーオブジェクトが完全に削除されず予想以上に長時間残ってしまうことがあります。
このような状況では、対象のオーナーと依存オブジェクトの、ファイナライザーとオーナーリファレンスを確認して問題を解決する必要があります。
備考: オブジェクトが削除中の状態で詰まってしまった場合、削除を続行するために手動でファイナライザーを削除することは避けてください。
通常、ファイナライザーは理由があってリソースに追加されているものであるため、強制的に削除してしまうとクラスターで何らかの問題を引き起こすことがあります。
そのファイナライザーの目的を理解しているかつ、別の方法で達成できる場合にのみ行うべきです(例えば、依存オブジェクトを手動で削除するなど)。次の項目 1.3.9 - オーナーと従属 Kubernetesでは、いくつかのオブジェクトは他のオブジェクトのオーナー になっています。
例えば、ReplicaSet はPodの集合のオーナーです。
これらの所有されているオブジェクトはオーナーに従属 しています。
オーナーシップはいくつかのリソースでも使われているラベルとセレクター とは仕組みが異なります。
例として、EndpointSlice
オブジェクトを作成するServiceオブジェクトを考えてみます。
Serviceはラベルを使ってどのEndpointSlice
がどのServiceに利用されているかをコントロールプレーンに判断させています。
ラベルに加えて、Serviceの代わりに管理される各EndpointSlice
はオーナーリファレンスを持ちます。
オーナーリファレンスは、Kubernetesの様々な箇所で管理外のオブジェクトに干渉してしまうのを避けるのに役立ちます。
オブジェクト仕様におけるオーナーリファレンス 従属オブジェクトはオーナーオブジェクトを参照するためのmetadata.ownerReferences
フィールドを持っています。
有効なオーナーリファレンスは従属オブジェクトと同じ名前空間に存在するオブジェクトの名前とUIDで構成されます。
KubernetesはReplicaSet、DaemonSet、Deployment、Job、CronJob、ReplicationControllerのようなオブジェクトの従属オブジェクトに、自動的に値を設定します。
このフィールドの値を手動で変更することで、これらの関係性を自分で設定することもできます。
ただし、通常はその必要はなく、Kubernetesが自動で管理するようにすることができます。
従属オブジェクトは、オーナーオブジェクトが削除されたときにガベージコレクションをブロックするかどうかを管理する真偽値を取るownerReferences.blockOwnerDeletion
フィールドも持っています。
Kubernetesは、コントローラー
(例:Deploymentコントローラー)がmetadata.ownerReferences
フィールドに値を設定している場合、自動的にこのフィールドをtrue
に設定します。
blockOwnerDeletion
フィールドに手動で値を設定することで、どの従属オブジェクトがガベージコレクションをブロックするかを設定することもできます。
Kubernetesのアドミッションコントローラーはオーナーの削除権限に基づいて、ユーザーが従属リソースのこのフィールドを変更できるかを管理しています。
これにより、認証されていないユーザーがオーナーオブジェクトの削除を遅らせることを防ぎます。
備考: 名前空間をまたぐオーナーリファレンスは仕様により許可されていません。
名前空間付き従属オブジェクトには、クラスタースコープ、または名前空間付きのオーナーを指定することができます。名前空間付きオーナーは必ず 従属オブジェクトと同じ名前空間に存在していなければなりません。
そうでない場合、オーナーリファレンスはないものとして扱われ、全てのオーナーがいなくなった時点で従属オブジェクトは削除対象となります。
クラスタースコープの従属オブジェクトはクラスタースコープのオーナーのみ指定できます。
v1.20以降では、クラスタースコープの従属オブジェクトが名前空間付きのオブジェクトをオーナーとした場合、
解決できないオーナーリファレンスを持っているものとして扱われ、ガベージコレクションの対象とすることができません。
v1.20以降で、ガベージコレクターが無効な名前空間またぎのownerReference
や名前空間付きのオーナーに依存するクラスタースコープのオブジェクトなどを検知した場合、OwnerRefInvalidNamespace
を理由とした警告のEventを出し、involvedObject
で無効な従属オブジェクトを報告します。
kubectl get events -A --field-selector=reason=OwnerRefInvalidNamespace
を実行することで、この種類のEventを確認することができます。
オーナーシップとファイナライザー Kubernetesでリソースを削除するとき、APIサーバーはリソースを管理するコントローラーにファイナライザールール を処理させることができます。
ファイナライザー はクラスターが正しく機能するために必要なリソースを誤って削除してしまうことを防ぎます。
例えば、まだPodが使用中のPersistentVolume
を削除しようとするとき、PersistentVolume
が持っているkubernetes.io/pv-protection
ファイナライザーにより、削除は即座には行われません。
その代わり、Kubernetesがファイナライザーを削除するまでボリュームはTerminating
ステータスのまま残り、PersistentVolume
がPodにバインドされなくなった後で削除が行われます。
またKubernetesはフォアグラウンド、孤立したオブジェクトのカスケード削除 を行ったとき、オーナーリソースにファイナライザーを追加します。
フォアグラウンド削除では、foreground
ファイナライザーを追加し、オーナーを削除する前にコントローラーがownerReferences.blockOwnerDeletion=true
を持っている従属リソースを削除するようにします。
孤立したオブジェクトの削除を行う場合、Kubernetesはorphan
ファイナライザーを追加し、オーナーオブジェクトを削除した後にコントローラーが従属リソースを無視するようにします。
次の項目 1.3.10 - 推奨ラベル(Recommended Labels) ユーザーはkubectlやダッシュボード以外に、多くのツールでKubernetesオブジェクトの管理と可視化ができます。共通のラベルセットにより、全てのツールにおいて解釈可能な共通のマナーに沿ってオブジェクトを表現することで、ツールの相互運用を可能にします。
ツール化に対するサポートに加えて、推奨ラベルはクエリ可能な方法でアプリケーションを表現します。
メタデータは、アプリケーション のコンセプトを中心に構成されています。KubernetesはPaaS(Platform as a Service)でなく、アプリケーションの公式な概念を持たず、またそれを強制することはありません。
そのかわり、アプリケーションは、非公式で、メタデータによって表現されています。単一のアプリケーションが有する項目に対する定義は厳密に決められていません。
備考: ラベルには推奨ラベルというものがあります。それらのラベルはアプリケーションの管理を容易にします。しかしコア機能のツール化において必須のものではありません。共有されたラベルとアノテーションは、app.kubernetes.io
という共通のプレフィックスを持ちます。プレフィックスの無いラベルはユーザーに対してプライベートなものになります。その共有されたプレフィックスは、共有ラベルがユーザーのカスタムラベルに干渉しないことを保証します。
ラベル これらの推奨ラベルの利点を最大限得るためには、全てのリソースオブジェクトに対して推奨ラベルが適用されるべきです。
キー 説明 例 型 app.kubernetes.io/name
アプリケーション名 mysql
文字列 app.kubernetes.io/instance
アプリケーションのインスタンスを特定するための固有名 mysql-abcxzy
文字列 app.kubernetes.io/version
アプリケーションの現在のバージョン (例: セマンティックバージョン、リビジョンのハッシュなど) 5.7.21
文字列 app.kubernetes.io/component
アーキテクチャ内のコンポーネント database
文字列 app.kubernetes.io/part-of
このアプリケーションによって構成される上位レベルのアプリケーション wordpress
文字列 app.kubernetes.io/managed-by
このアプリケーションの操作を管理するために使われているツール helm
文字列
これらのラベルが実際にどう使われているかを表すために、下記のStatefulSetのオブジェクトを考えましょう。
apiVersion : apps/v1
kind : StatefulSet
metadata :
labels :
app.kubernetes.io/name : mysql
app.kubernetes.io/instance : mysql-abcxzy
app.kubernetes.io/version : "5.7.21"
app.kubernetes.io/component : database
app.kubernetes.io/part-of : wordpress
app.kubernetes.io/managed-by : helm
アプリケーションとアプリケーションのインスタンス 単一のアプリケーションは、Kubernetesクラスター内で、いくつかのケースでは同一の名前空間に対して1回または複数回インストールされることがあります。
例えば、WordPressは複数のウェブサイトがあれば、それぞれ別のWordPressが複数回インストールされることがあります。
アプリケーション名と、アプリケーションのインスタンス名はそれぞれ別に記録されます。
例えば、WordPressはapp.kubernetes.io/name
にwordpress
と記述され、インスタンス名に関してはapp.kubernetes.io/instance
にwordpress-abcxzy
と記述されます。この仕組みはアプリケーションと、アプリケーションのインスタンスを特定可能にします。全てのアプリケーションインスタンスは固有の名前を持たなければなりません。
ラベルの使用例 ここでは、ラベルの異なる使用例を示します。これらの例はそれぞれシステムの複雑さが異なります。
シンプルなステートレスサービス Deployment
とService
オブジェクトを使って、シンプルなステートレスサービスをデプロイするケースを考えます。下記の2つのスニペットはラベルが最もシンプルな形式においてどのように使われるかをあらわします。
下記のDeployment
は、アプリケーションを稼働させるポッドを管理するのに使われます。
apiVersion : apps/v1
kind : Deployment
metadata :
labels :
app.kubernetes.io/name : myservice
app.kubernetes.io/instance : myservice-abcxzy
...
下記のService
は、アプリケーションを公開するために使われます。
apiVersion : v1
kind : Service
metadata :
labels :
app.kubernetes.io/name : myservice
app.kubernetes.io/instance : myservice-abcxzy
...
データベースを使ったウェブアプリケーション 次にもう少し複雑なアプリケーションについて考えます。データベース(MySQL)を使ったウェブアプリケーション(WordPress)で、Helmを使ってインストールします。
下記のスニペットは、このアプリケーションをデプロイするために使うオブジェクト設定の出だし部分です。
はじめに下記のDeployment
は、WordPressのために使われます。
apiVersion : apps/v1
kind : Deployment
metadata :
labels :
app.kubernetes.io/name : wordpress
app.kubernetes.io/instance : wordpress-abcxzy
app.kubernetes.io/version : "4.9.4"
app.kubernetes.io/managed-by : helm
app.kubernetes.io/component : server
app.kubernetes.io/part-of : wordpress
...
下記のService
は、WordPressを公開するために使われます。
apiVersion : v1
kind : Service
metadata :
labels :
app.kubernetes.io/name : wordpress
app.kubernetes.io/instance : wordpress-abcxzy
app.kubernetes.io/version : "4.9.4"
app.kubernetes.io/managed-by : helm
app.kubernetes.io/component : server
app.kubernetes.io/part-of : wordpress
...
MySQLはStatefulSet
として公開され、MySQL自身と、MySQLが属する親アプリケーションのメタデータを持ちます。
apiVersion : apps/v1
kind : StatefulSet
metadata :
labels :
app.kubernetes.io/name : mysql
app.kubernetes.io/instance : mysql-abcxzy
app.kubernetes.io/version : "5.7.21"
app.kubernetes.io/managed-by : helm
app.kubernetes.io/component : database
app.kubernetes.io/part-of : wordpress
...
このService
はMySQLをWordPressアプリケーションの一部として公開します。
apiVersion : v1
kind : Service
metadata :
labels :
app.kubernetes.io/name : mysql
app.kubernetes.io/instance : mysql-abcxzy
app.kubernetes.io/version : "5.7.21"
app.kubernetes.io/managed-by : helm
app.kubernetes.io/component : database
app.kubernetes.io/part-of : wordpress
...
MySQLのStatefulSet
とService
により、MySQLとWordPressに関するより広範な情報が含まれていることに気づくでしょう。
2 - クラスターのアーキテクチャ Kubernetesの背後にあるアーキテクチャのコンセプト。
Kubernetesクラスターのアーキテクチャ
2.1 - ノード Kubernetesはコンテナを Node 上で実行されるPodに配置することで、ワークロードを実行します。
ノードはクラスターによりますが、1つのVMまたは物理的なマシンです。
各ノードはPod やそれを制御するコントロールプレーン を実行するのに必要なサービスを含んでいます。
通常、1つのクラスターで複数のノードを持ちます。学習用途やリソースの制限がある環境では、1ノードかもしれません。
1つのノード上のコンポーネント には、kubelet 、コンテナランタイム 、kube-proxy が含まれます。
管理 ノードをAPIサーバー に加えるには2つの方法があります:
ノード上のkubeletが、コントロールプレーンに自己登録する。 あなた、もしくは他のユーザーが手動でNodeオブジェクトを追加する。 Nodeオブジェクトの作成、もしくはノード上のkubeletによる自己登録の後、コントロールプレーンはNodeオブジェクトが有効かチェックします。例えば、下記のjsonマニフェストでノードを作成してみましょう:
{
"kind" : "Node" ,
"apiVersion" : "v1" ,
"metadata" : {
"name" : "10.240.79.157" ,
"labels" : {
"name" : "my-first-k8s-node"
}
}
}
Kubernetesは内部的にNodeオブジェクトを作成します。 APIサーバーに登録したkubeletがノードのmetadata.name
フィールドが一致しているか検証します。ノードが有効な場合、つまり必要なサービスがすべて実行されている場合は、Podを実行する資格があります。それ以外の場合、該当ノードが有効になるまではいかなるクラスターの活動に対しても無視されます。
備考: Kubernetesは無効なNodeのオブジェクトを保持し、それが有効になるまで検証を続けます。
ヘルスチェックを止めるためには、あなた、もしくはコントローラー が明示的にNodeを削除する必要があります。
Nodeオブジェクトの名前は有効なDNSサブドメイン名 である必要があります。
ノードの自己登録 kubeletのフラグ --register-node
がtrue(デフォルト)のとき、kubeletは自分自身をAPIサーバーに登録しようとします。これはほとんどのディストリビューションで使用されている推奨パターンです。
自己登録については、kubeletは以下のオプションを伴って起動されます:
--kubeconfig
- 自分自身をAPIサーバーに対して認証するための資格情報へのパス--cloud-provider
- 自身に関するメタデータを読むためにクラウドプロバイダー と会話する方法--register-node
- 自身をAPIサーバーに自動的に登録--register-with-taints
- 与えられたtaint のリストでノードを登録します (カンマ区切りの <key>=<value>:<effect>
)。register-node
がfalseの場合、このオプションは機能しません
--node-ip
- ノードのIPアドレス--node-labels
- ノードをクラスターに登録するときに追加するLabel (NodeRestriction許可プラグイン によって適用されるラベルの制限を参照)--node-status-update-frequency
- kubeletがノードのステータスをマスターにPOSTする頻度の指定ノード認証モード およびNodeRestriction許可プラグイン が有効になっている場合、kubeletは自分自身のノードリソースを作成/変更することのみ許可されています。
手動によるノード管理 クラスター管理者はkubectl を使用してNodeオブジェクトを作成および変更できます。
管理者が手動でNodeオブジェクトを作成したい場合は、kubeletフラグ --register-node = false
を設定してください。
管理者は--register-node
の設定に関係なくNodeオブジェクトを変更することができます。
例えば、ノードにラベルを設定し、それをunschedulableとしてマークすることが含まれます。
ノード上のラベルは、スケジューリングを制御するためにPod上のノードセレクターと組み合わせて使用できます。
例えば、Podをノードのサブセットでのみ実行する資格があるように制限します。
ノードをunschedulableとしてマークすると、新しいPodがそのノードにスケジュールされるのを防ぎますが、ノード上の既存のPodには影響しません。
これは、ノードの再起動などの前の準備ステップとして役立ちます。
ノードにスケジュール不可能のマークを付けるには、次のコマンドを実行します:
備考: DaemonSet によって作成されたPodはノード上のunschedulable属性を考慮しません。
これは、再起動の準備中にアプリケーションからアプリケーションが削除されている場合でも、DaemonSetがマシンに属していることを前提としているためです。
ノードのステータス ノードのステータスは以下の情報を含みます:
kubectl
を使用し、ノードのステータスや詳細を確認できます:
kubectl describe node <ノード名をここに挿入>
出力情報の各箇所について、以下で説明します。
Addresses これらのフィールドの使い方は、お使いのクラウドプロバイダーやベアメタルの設定内容によって異なります。
HostName: ノードのカーネルによって伝えられたホスト名です。kubeletの--hostname-override
パラメーターによって上書きすることができます。 ExternalIP: 通常は、外部にルーティング可能(クラスターの外からアクセス可能)なノードのIPアドレスです。 InternalIP: 通常は、クラスター内でのみルーティング可能なノードのIPアドレスです。 Conditions conditions
フィールドは全てのRunning
なノードのステータスを表します。例として、以下のような状態を含みます:
ノードのConditionと、各condition適用時の概要 ノードのCondition 概要 Ready
ノードの状態が有効でPodを配置可能な場合にTrue
になります。ノードの状態に問題があり、Podが配置できない場合にFalse
になります。ノードコントローラーが、node-monitor-grace-period
で設定された時間内(デフォルトでは40秒)に該当ノードと疎通できない場合、Unknown
になります。 DiskPressure
ノードのディスク容量が圧迫されているときにTrue
になります。圧迫とは、ディスクの空き容量が少ないことを指します。それ以外のときはFalse
です。 MemoryPressure
ノードのメモリが圧迫されているときにTrue
になります。圧迫とは、メモリの空き容量が少ないことを指します。それ以外のときはFalse
です。 PIDPressure
プロセスが圧迫されているときにTrue
になります。圧迫とは、プロセス数が多すぎることを指します。それ以外のときはFalse
です。 NetworkUnavailable
ノードのネットワークが適切に設定されていない場合にTrue
になります。それ以外のときはFalse
です。
備考: コマンドラインを使用してcordonされたNodeを表示する場合、ConditionはSchedulingDisabled
を含みます。
SchedulingDisabled
はKubernetesのAPIにおけるConditionではありません;その代わり、cordonされたノードはUnschedulableとしてマークされます。Nodeの状態は、Nodeリソースの.status
の一部として表現されます。例えば、正常なノードの場合は以下のようなjson構造が表示されます。
"conditions" : [
{
"type" : "Ready" ,
"status" : "True" ,
"reason" : "KubeletReady" ,
"message" : "kubelet is posting ready status" ,
"lastHeartbeatTime" : "2019-06-05T18:38:35Z" ,
"lastTransitionTime" : "2019-06-05T11:41:27Z"
}
]
Ready conditionがpod-eviction-timeout
(kube-controller-manager に渡された引数)に設定された時間を超えてもUnknown
やFalse
のままになっている場合、該当ノード上にあるPodはノードコントローラーによって削除がスケジュールされます。デフォルトの退役のタイムアウトの時間は5分 です。ノードが到達不能ないくつかの場合においては、APIサーバーが該当ノードのkubeletと疎通できない状態になっています。その場合、APIサーバーがkubeletと再び通信を確立するまでの間、Podの削除を行うことはできません。削除がスケジュールされるまでの間、削除対象のPodは切り離されたノードの上で稼働を続けることになります。
ノードコントローラーはクラスター内でPodが停止するのを確認するまでは強制的に削除しないようになりました。到達不能なノード上で動いているPodはTerminating
またはUnknown
のステータスになります。Kubernetesが基盤となるインフラストラクチャーを推定できない場合、クラスター管理者は手動でNodeオブジェクトを削除する必要があります。KubernetesからNodeオブジェクトを削除すると、そのノードで実行されているすべてのPodオブジェクトがAPIサーバーから削除され、それらの名前が解放されます。
ノードのライフサイクルコントローラーがconditionを表したtaint を自動的に生成します。
スケジューラーがPodをノードに割り当てる際、ノードのtaintを考慮します。Podが許容するtaintは例外です。
詳細は条件によるtaintの付与 を参照してください。
CapacityとAllocatable ノードで利用可能なリソース(CPU、メモリ、およびノードでスケジュールできる最大Pod数)について説明します。
capacityブロック内のフィールドは、ノードが持っているリソースの合計量を示します。
allocatableブロックは、通常のPodによって消費されるノード上のリソースの量を示します。
CapacityとAllocatableについて深く知りたい場合は、ノード上でどのようにコンピュートリソースが予約されるか を読みながら学ぶことができます。
Info カーネルのバージョン、Kubernetesのバージョン(kubeletおよびkube-proxyのバージョン)、(使用されている場合)Dockerのバージョン、OS名など、ノードに関する一般的な情報です。
この情報はノードからkubeletを通じて取得され、Kubernetes APIに公開されます。
ノードのハートビート ハートビートは、Kubernetesノードから送信され、ノードが利用可能か判断するのに役立ちます。
以下の2つのハートビートがあります:
Nodeの.status
の更新 Lease object です。
各ノードはkube-node-lease
というnamespace に関連したLeaseオブジェクトを持ちます。
Leaseは軽量なリソースで、クラスターのスケールに応じてノードのハートビートにおけるパフォーマンスを改善します。kubeletがNodeStatus
とLeaseオブジェクトの作成および更新を担当します。
kubeletは、ステータスに変化があったり、設定した間隔の間に更新がない時にNodeStatus
を更新します。NodeStatus
更新のデフォルト間隔は5分です。(到達不能の場合のデフォルトタイムアウトである40秒よりもはるかに長いです) kubeletは10秒間隔(デフォルトの更新間隔)でLeaseオブジェクトの生成と更新を実施します。Leaseの更新はNodeStatus
の更新とは独立されて行われます。Leaseの更新が失敗した場合、kubeletは200ミリ秒から始まり7秒を上限とした指数バックオフでリトライします。 ノードコントローラー ノードコントローラー は、ノードのさまざまな側面を管理するKubernetesのコントロールプレーンコンポーネントです。
ノードコントローラーは、ノードの存続期間中に複数の役割を果たします。1つ目は、ノードが登録されたときにCIDRブロックをノードに割り当てることです(CIDR割り当てがオンになっている場合)。
2つ目は、ノードコントローラーの内部ノードリストをクラウドの利用可能なマシンのリストと一致させることです。
クラウド環境で実行している場合、ノードに異常があると、ノードコントローラーはクラウドプロバイダーにそのNodeのVMがまだ使用可能かどうかを問い合わせます。
使用可能でない場合、ノードコントローラーはノードのリストから該当ノードを削除します。
3つ目は、ノードの状態を監視することです。
ノードが到達不能(例えば、ノードがダウンしているなどので理由で、ノードコントローラーがハートビートの受信を停止した場合)になると、ノードコントローラーは、NodeStatusのNodeReady conditionをConditionUnknownに変更する役割があります。その後も該当ノードが到達不能のままであった場合、Graceful Terminationを使って全てのPodを退役させます。デフォルトのタイムアウトは、ConditionUnknownの報告を開始するまで40秒、その後Podの追い出しを開始するまで5分に設定されています。
ノードコントローラーは、--node-monitor-period
に設定された秒数ごとに各ノードの状態をチェックします。
信頼性 ほとんどの場合、排除の速度は1秒あたり--node-eviction-rate
に設定された数値(デフォルトは秒間0.1)です。つまり、10秒間に1つ以上のPodをノードから追い出すことはありません。
特定のアベイラビリティーゾーン内のノードのステータスが異常になると、ノード排除の挙動が変わります。ノードコントローラーは、ゾーン内のノードの何%が異常(NodeReady条件がConditionUnknownまたはConditionFalseである)であるかを同時に確認します。
異常なノードの割合が少なくとも --healthy-zone-threshold
に設定した値を下回る場合(デフォルトは0.55)であれば、退役率は低下します。クラスターが小さい場合(すなわち、 --large-cluster-size-threshold
の設定値よりもノード数が少ない場合。デフォルトは50)、退役は停止し、そうでない場合、退役率は秒間で--secondary-node-eviction-rate
の設定値(デフォルトは0.01)に減少します。
これらのポリシーがアベイラビリティーゾーンごとに実装されているのは、1つのアベイラビリティーゾーンがマスターから分割される一方、他のアベイラビリティーゾーンは接続されたままになる可能性があるためです。
クラスターが複数のクラウドプロバイダーのアベイラビリティーゾーンにまたがっていない場合、アベイラビリティーゾーンは1つだけです(クラスター全体)。
ノードを複数のアベイラビリティゾーンに分散させる主な理由は、1つのゾーン全体が停止したときにワークロードを正常なゾーンに移動できることです。
したがって、ゾーン内のすべてのノードが異常である場合、ノードコントローラーは通常のレート --node-eviction-rate
で退役します。
コーナーケースは、すべてのゾーンが完全にUnhealthyである(すなわち、クラスター内にHealthyなノードがない)場合です。
このような場合、ノードコントローラーはマスター接続に問題があると見なし、接続が回復するまですべての退役を停止します。
ノードコントローラーは、Podがtaintを許容しない場合、 NoExecute
のtaintを持つノード上で実行されているPodを排除する責務もあります。
さらに、ノードコントローラーはノードに到達できない、または準備ができていないなどのノードの問題に対応するtaint を追加する責務があります。これはスケジューラーが、問題のあるノードにPodを配置しない事を意味しています。
ノードのキャパシティ Nodeオブジェクトはノードのリソースキャパシティ(CPUの数とメモリの量)を監視します。
自己登録 したノードは、Nodeオブジェクトを作成するときにキャパシティを報告します。
手動によるノード管理 を実行している場合は、ノードを追加するときにキャパシティを設定する必要があります。
Kubernetesスケジューラー は、ノード上のすべてのPodに十分なリソースがあることを確認します。スケジューラーは、ノード上のコンテナが要求するリソースの合計がノードキャパシティ以下であることを確認します。
これは、kubeletによって管理されたすべてのコンテナを含みますが、コンテナランタイムによって直接開始されたコンテナやkubeletの制御外で実行されているプロセスは含みません。
ノードのトポロジー
FEATURE STATE:
Kubernetes v1.16 [alpha]
TopologyManager
の
フィーチャーゲート を有効にすると、
kubeletはリソースの割当を決定する際にトポロジーのヒントを利用できます。
詳細は、
ノードのトポロジー管理ポリシーを制御する を参照してください。
ノードの正常終了 FEATURE STATE:
Kubernetes v1.21 [beta]
kubeletは、ノードのシステムシャットダウンを検出すると、ノード上で動作しているPodを終了させます。
Kubelet は、ノードのシャットダウン時に、ポッドが通常の通常のポッド終了プロセス に従うようにします。
Graceful Node Shutdownはsystemdに依存しているため、systemd inhibitor locks を
利用してノードのシャットダウンを一定時間遅らせることができます。
Graceful Node Shutdownは、v1.21でデフォルトで有効になっているGracefulNodeShutdown
フィーチャーゲート で制御されます。
なお、デフォルトでは、後述の設定オプションShutdownGracePeriod
およびShutdownGracePeriodCriticalPods
の両方がゼロに設定されているため、Graceful node shutdownは有効になりません。この機能を有効にするには、この2つのkubeletの設定を適切に設定し、ゼロ以外の値を設定する必要があります。
Graceful shutdownでは、kubeletは以下の2段階でPodを終了させます。
そのノード上で動作している通常のPodを終了させます。 そのノード上で動作しているcritical pods を終了させます。 Graceful Node Shutdownには、2つのKubeletConfiguration
オプションを設定します。:
ShutdownGracePeriod
:ノードがシャットダウンを遅らせるべき合計期間を指定します。これは、通常のPodとcritical pods の両方のPod終了の合計猶予期間です。 ShutdownGracePeriodCriticalPods
:ノードのシャットダウン時にcritical pods を終了させるために使用する期間を指定します。この値は、ShutdownGracePeriodよりも小さくする必要があります。 例えば、ShutdownGracePeriod=30s
、ShutdownGracePeriodCriticalPods=10s
とすると、
kubeletはノードのシャットダウンを30秒遅らせます。シャットダウンの間、最初の20(30-10)秒は通常のポッドを優雅に終了させるために確保され、
残りの10秒は重要なポッドを終了させるために確保されることになります。
備考: Graceful Node Shutdown中にPodが退避された場合、それらのPodの.status
はFailed
になります。
kubectl get pods
を実行すると、退避させられたPodのステータスが Shutdown
と表示されます。
また、kubectl describe pod
を実行すると、ノードのシャットダウンのためにPodが退避されたことがわかります。
Status: Failed
Reason: Shutdown
Message: Node is shutting, evicting pods
失敗したポッドオブジェクトは、明示的に削除されるか、GCによってクリーンアップ されるまで保存されます。
これは、ノードが突然終了した場合とは異なった振る舞いです。
ノードの非正常終了 FEATURE STATE:
Kubernetes v1.26 [beta]
コマンドがkubeletのinhibitor locksメカニズムをトリガーしない場合や、ShutdownGracePeriodやShutdownGracePeriodCriticalPodsが適切に設定されていないといったユーザーによるミス等が原因で、ノードがシャットダウンしたことをkubeletのNode Shutdownマネージャーが検知できないことがあります。詳細は上記セクションノードの正常終了 を参照ください。
ノードのシャットダウンがkubeletのNode Shutdownマネージャーに検知されない場合、StatefulSetを構成するPodはシャットダウン状態のノード上でterminating状態のままになってしまい、他の実行中のノードに移動することができなくなってしまいます。これは、ノードがシャットダウンしているため、その上のkubeletがPodを削除できず、それにより、StatefulSetが新しいPodを同じ名前で作成できなくなってしまうためです。Podがボリュームを使用している場合、VolumeAttachmentsはシャットダウン状態のノードによって削除されないため、Podが使用しているボリュームは他の実行中のノードにアタッチすることができなくなってしまいます。その結果として、StatefulSet上で実行中のアプリケーションは適切に機能しなくなってしまいます。シャットダウンしていたノードが復旧した場合、そのノード上のPodはkubeletに削除され、他の実行中のノード上に作成されます。また、シャットダウン状態のノードが復旧できなかった場合は、そのノード上のPodは永久にterminating状態のままとなります。
上記の状況を脱却するには、ユーザーが手動でNoExecute
またはNoSchedule
effectを設定してnode.kubernetes.io/out-of-service
taintをノードに付与することで、故障中の状態に設定することができます。kube-controller-manager
において NodeOutOfServiceVolumeDetach
フィーチャーゲート が有効になっており、かつノードがtaintによって故障中としてマークされている場合は、ノードに一致するtolerationがないPodは強制的に削除され、ノード上のterminating状態のPodに対するボリュームデタッチ操作が直ちに実行されます。これにより、故障中のノード上のPodを異なるノード上にすばやく復旧させることが可能になります。
non-graceful shutdownの間に、Podは以下の2段階で終了します:
一致するout-of-service
tolerationを持たないPodを強制的に削除する。 上記のPodに対して即座にボリュームデタッチ操作を行う。 備考: node.kubernetes.io/out-of-service
taintを付与する前に、ノードがシャットダウンしているか電源がオフになっていることを確認してください(再起動中ではないこと)。Podの別ノードへの移動後、シャットダウンしていたノードが回復した場合は、ユーザーが手動で付与したout-of-service taintをユーザー自ら手動で削除する必要があります。 スワップメモリの管理 FEATURE STATE:
Kubernetes v1.22 [alpha]
Kubernetes 1.22以前では、ノードはスワップメモリの使用をサポートしておらず、ノード上でスワップが検出された場合、
kubeletはデフォルトで起動に失敗していました。1.22以降では、スワップメモリのサポートをノードごとに有効にすることができます。
ノードでスワップを有効にするには、kubeletの NodeSwap
フィーチャーゲート を有効にし、
--fail-swap-on
コマンドラインフラグまたはfailSwapOn
KubeletConfiguration を false に設定する必要があります。
ユーザーはオプションで、ノードがスワップメモリをどのように使用するかを指定するために、memorySwap.swapBehavior
を設定することもできます。ノードがスワップメモリをどのように使用するかを指定します。例えば、以下のようになります。
memorySwap :
swapBehavior : LimitedSwap
swapBehaviorで使用できる設定オプションは以下の通りです。:
LimitedSwap
: Kubernetesのワークロードが、使用できるスワップ量に制限を設けます。Kubernetesが管理していないノード上のワークロードは、依然としてスワップを使用できます。UnlimitedSwap
: Kubernetesのワークロードが使用できるスワップ量に制限を設けません。システムの限界まで、要求されただけのスワップメモリを使用することができます。memorySwap
の設定が指定されておらず、フィーチャーゲート が有効な場合、デフォルトのkubeletはLimitedSwap
の設定と同じ動作を適用します。
LimitedSwap
設定の動作は、ノードがコントロールグループ(「cgroups」とも呼ばれる)のv1とv2のどちらで動作しているかによって異なります。
Kubernetesのワークロードでは、メモリとスワップを組み合わせて使用することができ、ポッドのメモリ制限が設定されている場合はその制限まで使用できます。
cgroupsv1: Kubernetesのワークロードは、メモリとスワップを組み合わせて使用することができ、ポッドのメモリ制限が設定されている場合はその制限まで使用できます。cgroupsv2: Kubernetesのワークロードは、スワップメモリを使用できません。詳しくは、KEP-2400 と
design proposal をご覧いただき、テストにご協力、ご意見をお聞かせください。
次の項目 2.2 - ノードとコントロールプレーン間の通信 本ドキュメントは、APIサーバー とKubernetesクラスター 間の通信経路をまとめたものです。
その目的は、信頼できないネットワーク上(またはクラウドプロバイダー上の完全なパブリックIP)でクラスターが実行できるよう、ユーザーがインストールをカスタマイズしてネットワーク構成を強固にできるようにすることです。
ノードからコントロールプレーンへの通信 Kubernetesには「ハブアンドスポーク」というAPIパターンがあります。ノード(またはノードが実行するPod)からのすべてのAPIの使用は、APIサーバーで終了します。他のコントロールプレーンコンポーネントは、どれもリモートサービスを公開するようには設計されていません。APIサーバーは、1つ以上の形式のクライアント認証 が有効になっている状態で、セキュアなHTTPSポート(通常は443)でリモート接続をリッスンするように設定されています。
特に匿名リクエスト やサービスアカウントトークン が許可されている場合は、1つ以上の認可 形式を有効にする必要があります。
ノードは、有効なクライアント認証情報とともに、APIサーバーに安全に接続できるように、クラスターのパブリックルート証明書 でプロビジョニングされる必要があります。適切なやり方は、kubeletに提供されるクライアント認証情報が、クライアント証明書の形式であることです。kubeletクライアント証明書の自動プロビジョニングについては、kubelet TLSブートストラップ を参照してください。
APIサーバーに接続したいPod は、サービスアカウントを利用することで、安全に接続することができます。これにより、Podのインスタンス化時に、Kubernetesはパブリックルート証明書と有効なBearerトークンを自動的にPodに挿入します。
kubernetes
サービス(デフォルト
の名前空間)は、APIサーバー上のHTTPSエンドポイントに(kube-proxy
経由で)リダイレクトされる仮想IPアドレスで構成されます。
また、コントロールプレーンのコンポーネントは、セキュアなポートを介してAPIサーバーとも通信します。
その結果、ノードやノード上で動作するPodからコントロールプレーンへの接続は、デフォルトでセキュアであり、信頼されていないネットワークやパブリックネットワークを介して実行することができます。
コントロールプレーンからノードへの通信 コントロールプレーン(APIサーバー)からノードへの主要な通信経路は2つあります。
1つ目は、APIサーバーからクラスター内の各ノードで実行されるkubelet プロセスへの通信経路です。
2つ目は、APIサーバーの プロキシ 機能を介した、APIサーバーから任意のノード、Pod、またはサービスへの通信経路です。
APIサーバーからkubeletへの通信 APIサーバーからkubeletへの接続は、以下の目的で使用されます:
Podのログの取得。 実行中のPodへのアタッチ(通常はkubectl
を使用)。 kubeletのポート転送機能の提供。 これらの接続は、kubeletのHTTPSエンドポイントで終了します。デフォルトでは、APIサーバーはkubeletのサービング証明書を検証しないため、接続は中間者攻撃の対象となり、信頼されていないネットワークやパブリックネットワークを介して実行するのは安全ではありません 。
この接続を検証するには、--kubelet-certificate-authority
フラグを使用して、kubeletのサービング証明書を検証するために使用するルート証明書バンドルを、APIサーバーに提供します。
それができない場合は、信頼できないネットワークやパブリックネットワークを介した接続を回避するため、必要に応じてAPIサーバーとkubeletの間でSSHトンネル を使用します。
最後に、kubelet APIを保護するために、Kubelet認証/認可 を有効にする必要があります。
APIサーバーからノード、Pod、サービスへの通信 APIサーバーからノード、Pod、またはサービスへの接続は、デフォルトで平文のHTTP接続になるため、認証も暗号化もされません。API URL内のノード、Pod、サービス名にhttps:
を付けることで、セキュアなHTTPS接続を介して実行できますが、HTTPSエンドポイントから提供された証明書を検証したり、クライアント認証情報を提供したりすることはありません。そのため、接続の暗号化はされますが、完全性の保証はありません。これらの接続を、信頼されていないネットワークやパブリックネットワークを介して実行するのは、現在のところ安全ではありません 。
SSHトンネル Kubernetesは、コントロールプレーンからノードへの通信経路を保護するために、SSHトンネル をサポートしています。この構成では、APIサーバーがクラスター内の各ノードへのSSHトンネルを開始(ポート22でリッスンしているSSHサーバーに接続)し、kubelet、ノード、Pod、またはサービス宛てのすべてのトラフィックをトンネル経由で渡します。
このトンネルにより、ノードが稼働するネットワークの外部にトラフィックが公開されないようになります。
備考: SSHトンネルは現在非推奨であるため、自分が何をしているのか理解していないのであれば、使用すべきではありません。この通信経路の代替となるものとして、
Konnectivityサービス があります。
Konnectivityサービス FEATURE STATE:
Kubernetes v1.18 [beta]
SSHトンネルの代替として、Konnectivityサービスは、コントロールプレーンからクラスターへの通信に、TCPレベルのプロキシを提供します。Konnectivityサービスは、コントロールプレーンネットワークのKonnectivityサーバーと、ノードネットワークのKonnectivityエージェントの、2つの部分で構成されています。
Konnectivityエージェントは、Konnectivityサーバーへの接続を開始し、ネットワーク接続を維持します。
Konnectivityサービスを有効にすると、コントロールプレーンからノードへのトラフィックは、すべてこの接続を経由するようになります。
Konnectivityサービスのセットアップ に従って、クラスターにKonnectivityサービスをセットアップしてください。
次の項目 2.3 - リース しばしば分散システムでは共有リソースをロックしたりノード間の活動を調整する機構として"リース"が必要になります。
Kubernetesでは、"リース"のコンセプトはcoordination.k8s.io
APIグループのLease
オブジェクトに表されていて、ノードのハートビートやコンポーネントレベルのリーダー選出といったシステムにとって重要な機能に利用されています。
ノードハートビート Kubernetesでは、kubeletのノードハートビートをKubernetes APIサーバーに送信するのにLease APIが使われています。
各Node
ごとに、kube-node-lease
名前空間にノードとマッチする名前のLease
オブジェクトが存在します。
内部的には、kubeletのハートビートはこのLease
オブジェクトに対するUPDATEリクエストであり、Leaseのspec.renewTime
フィールドを更新しています。
Kubernetesのコントロールプレーンはこのフィールドのタイムスタンプを見て、Node
が利用可能かを判断しています。
詳しくはNode Leaseオブジェクト をご覧ください。
リーダー選出 Kubernetesでは、あるコンポーネントのインスタンスが常に一つだけ実行されていることを保証するためにもリースが利用されています。
これはkube-controller-manager
やkube-scheduler
といったコントロールプレーンのコンポーネントで、一つのインスタンスのみがアクティブに実行され、その他のインスタンスをスタンバイ状態とする必要があるような冗長構成を組むために利用されています。
APIサーバーのアイデンティティー FEATURE STATE:
Kubernetes v1.26 [beta]
Kubernetes v1.26から、各kube-apiserver
はLease APIを利用して自身のアイデンティティーをその他のシステムに向けて公開するようになりました。
それ自体は特に有用ではありませんが、何台のkube-apiserver
がKubernetesコントロールプレーンを稼働させているのかをクライアントが知るためのメカニズムを提供します。
kube-apiserverリースが存在することで、各kube-apiserver間の調整が必要となる可能性がある将来の機能が使えるようになります。
kube-system
名前空間のapiserver-<sha256-hash>
という名前のリースオブジェクトを確認することで、各kube-apiserverが所有しているLeaseを確認することができます。
また、k8s.io/component=kube-apiserver
ラベルセレクターを利用することもできます。
$ kubectl -n kube-system get lease -l k8s.io/component= kube-apiserver
NAME HOLDER AGE
apiserver-c4vwjftbvpc5os2vvzle4qg27a kube-apiserver-c4vwjftbvpc5os2vvzle4qg27a_9cbf54e5-1136-44bd-8f9a-1dcd15c346b4 5m33s
apiserver-dz2dqprdpsgnm756t5rnov7yka kube-apiserver-dz2dqprdpsgnm756t5rnov7yka_84f2a85d-37c1-4b14-b6b9-603e62e4896f 4m23s
apiserver-fyloo45sdenffw2ugwaz3likua kube-apiserver-fyloo45sdenffw2ugwaz3likua_c5ffa286-8a9a-45d4-91e7-61118ed58d2e 4m43s
リースの名前に使われているSHA256ハッシュはkube-apiserverのOSホスト名に基づいています。各kube-apiserverはクラスター内で一意なホスト名を使用するように構成する必要があります。
同じホスト名を利用する新しいkube-apiserverインスタンスは、新しいリースオブジェクトを作成せずに、既存のLeaseを新しいインスタンスのアイデンティティーを利用して引き継ぎます。
kube-apiserverが使用するホスト名はkubernetes.io/hostname
ラベルの値で確認できます。
$ kubectl -n kube-system get lease kube-apiserver-c4vwjftbvpc5os2vvzle4qg27a -o yaml
apiVersion : coordination.k8s.io/v1
kind : Lease
metadata :
creationTimestamp : "2022-11-30T15:37:15Z"
labels :
k8s.io/component : kube-apiserver
kubernetes.io/hostname : kind-control-plane
name : kube-apiserver-c4vwjftbvpc5os2vvzle4qg27a
namespace : kube-system
resourceVersion : "18171"
uid : d6c68901-4ec5-4385-b1ef-2d783738da6c
spec :
holderIdentity : kube-apiserver-c4vwjftbvpc5os2vvzle4qg27a_9cbf54e5-1136-44bd-8f9a-1dcd15c346b4
leaseDurationSeconds : 3600
renewTime : "2022-11-30T18:04:27.912073Z"
すでに存在しなくなったkube-apiserverの期限切れリースは、1時間後に新しいkube-apiserverによってガベージコレクションされます。
2.4 - コントローラー ロボット工学やオートメーションの分野において、 制御ループ とは、あるシステムの状態を制御する終了状態のないループのことです。
ここでは、制御ループの一例として、部屋の中にあるサーモスタットを挙げます。
あなたが温度を設定すると、それはサーモスタットに 目的の状態(desired state) を伝えることになります。実際の部屋の温度は 現在の状態 です。サーモスタットは、装置をオンまたはオフにすることによって、現在の状態を目的の状態に近づけるように動作します。
Kubernetesにおいて、コントローラーは
クラスター の状態を監視し、必要に応じて変更を加えたり要求したりする制御ループです。それぞれのコントローラーは現在のクラスターの状態を望ましい状態に近づけるように動作します。
コントローラーパターン コントローラーは少なくとも1種類のKubernetesのリソースを監視します。これらのオブジェクト には目的の状態を表すspecフィールドがあります。リソースのコントローラーは、現在の状態を目的の状態に近づける責務を持ちます。
コントローラーは自分自身でアクションを実行する場合もありますが、KubernetesではコントローラーがAPIサーバー に意味のある副作用を持つメッセージを送信することが一般的です。以下では、このような例を見ていきます。
APIサーバー経由でコントロールする Job コントローラーはKubernetesのビルトインのコントローラーの一例です。ビルトインのコントローラーは、クラスターのAPIサーバーとやりとりをして状態を管理します。
Jobは、1つ以上のPod を起動して、タスクを実行した後に停止する、Kubernetesのリソースです。
(1度スケジュール されると、Podオブジェクトはkubeletに対する目的の状態の一部になります。)
Jobコントローラーが新しいタスクを見つけると、その処理が完了するように、クラスター上のどこかで、一連のNode上のkubeletが正しい数のPodを実行することを保証します。ただし、Jobコントローラーは、自分自身でPodやコンテナを実行することはありません。代わりに、APIサーバーに対してPodの作成や削除を依頼します。コントロールプレーン 上の他のコンポーネントが(スケジュールして実行するべき新しいPodが存在するという)新しい情報を基に動作することによって、最終的に目的の処理が完了します。
新しいJobが作成されたとき、目的の状態は、そのJobが完了することです。JobコントローラーはそのJobに対する現在の状態を目的の状態に近づけるようにします。つまり、そのJobが行ってほしい処理を実行するPodを作成し、Jobが完了に近づくようにします。
コントローラーは、コントローラーを設定するオブジェクトも更新します。たとえば、あるJobが完了した場合、Jobコントローラーは、JobオブジェクトにFinished
というマークを付けます。
(これは、部屋が設定温度になったことを示すために、サーモスタットがランプを消灯するのに少し似ています。)
直接的なコントロール Jobとは対照的に、クラスターの外部に変更を加える必要があるコントローラーもあります。
たとえば、クラスターに十分な数のNode が存在することを保証する制御ループの場合、そのコントローラーは、必要に応じて新しいNodeをセットアップするために、現在のクラスターの外部とやりとりをする必要があります。
外部の状態とやりとりをするコントローラーは、目的の状態をAPIサーバーから取得した後、外部のシステムと直接通信し、現在の状態を目的の状態に近づけます。
(クラスター内のノードを水平にスケールさせるコントローラー が実際に存在します。)
ここで重要な点は、コントローラーが目的の状態を実現するために変更を加えてから、現在の状態をクラスターのAPIサーバーに報告することです。他の制御ループは、その報告されたデータを監視し、独自のアクションを実行できます。
サーモスタットの例では、部屋が非常に寒い場合、別のコントローラーが霜防止ヒーターをオンにすることもあります。Kubernetesクラスターを使用すると、コントロールプレーンは、Kubernetesを拡張して 実装することにより、IPアドレス管理ツールやストレージサービス、クラウドプロバイダーAPI、およびその他のサービスと間接的に連携します。
目的の状態 vs 現在の状態 Kubernetesはシステムに対してクラウドネイティブな見方をするため、常に変化し続けるような状態を扱えるように設計されています。
処理を実行したり、制御ループが故障を自動的に修正したりしているどの時点でも、クラスターは変化中である可能性があります。つまり、クラスターは決して安定した状態にならない可能性があるということです。
コントローラーがクラスターのために実行されていて、有用な変更が行われるのであれば、全体的な状態が安定しているかどうかは問題にはなりません。
設計 設計理念として、Kubernetesは多数のコントローラーを使用しており、各コントローラーはクラスターの状態の特定の側面をそれぞれ管理しています。最もよくあるパターンは、特定の制御ループ(コントローラー)が目的の状態として1種類のリソースを使用し、目的の状態を実現することを管理するために別の種類のリソースを用意するというものです。たとえば、Jobのコントローラーは、Jobオブジェクト(新しい処理を見つけるため)およびPodオブジェクト(Jobを実行し、処理が完了したか確認するため)を監視します。この場合、なにか別のものがJobを作成し、JobコントローラーはPodを作成します。
相互にリンクされた単一のモノリシックな制御ループよりは、複数の単純なコントローラーが存在する方が役に立ちます。コントローラーは故障することがあるため、Kubernetesは故障を許容するように設計されています。
備考: 同じ種類のオブジェクトを作成または更新するコントローラーが、複数存在する場合があります。実際には、Kubernetesコントローラーは、自分が制御するリソースに関連するリソースにのみ注意を払うように作られています。
たとえば、DeploymentとJobがありますが、これらは両方ともPodを作成するものです。しかし、JobコントローラーはDeploymentが作成したPodを削除することはありません。各コントローラーが2つのPodを区別できる情報(ラベル )が存在するためです。
コントローラーを実行する方法 Kubernetesには、kube-controller-manager 内部で動作する一組のビルトインのコントローラーが用意されています。これらビルトインのコントローラーは、コアとなる重要な振る舞いを提供します。
DeploymentコントローラーとJobコントローラーは、Kubernetes自体の一部として同梱されているコントローラーの例です(それゆえ「ビルトイン」のコントローラーと呼ばれます)。Kubernetesは回復性のあるコントロールプレーンを実行できるようにしているため、ビルトインのコントローラーの一部が故障しても、コントロールプレーンの別の部分が作業を引き継いでくれます。
Kubernetesを拡張するためにコントロールプレーンの外で動作するコントローラーもあります。もし望むなら、新しいコントローラーを自分で書くこともできます。自作のコントローラーをPodセットとして動作させたり、Kubernetesの外部で動作させることもできます。どのような動作方法が最も適しているかは、そのコントローラーがどのようなことを行うのかに依存します。
次の項目 2.5 - クラウドコントローラーマネージャー FEATURE STATE:
Kubernetes v1.11 [beta]
クラウドインフラストラクチャー技術により、パブリック、プライベート、ハイブリッドクラウド上でKubernetesを動かすことができます。Kubernetesは、コンポーネント間の密なつながりが不要な自動化されたAPI駆動インフラストラクチャーを信条としています。
cloud-controller-managerは クラウド特有の制御ロジックを組み込むKubernetesのcontrol plane コンポーネントです。クラウドコントロールマネージャーは、クラスターをクラウドプロバイダーAPIをリンクし、クラスターのみで相互作用するコンポーネントからクラウドプラットフォームで相互作用するコンポーネントを分離します。
Kubernetesと下のクラウドインフラストラクチャー間の相互運用ロジックを分離することで、cloud-controller-managerコンポーネントはクラウドプロバイダを主なKubernetesプロジェクトと比較し異なるペースで機能をリリース可能にします。
cloud-controller-managerは、プラグイン機構を用い、異なるクラウドプロバイダーに対してそれぞれのプラットフォームとKubernetesの結合を可能にする構成になっています。
設計
クラウドコントローラーマネージャーは、複製されたプロセスの集合としてコントロールプレーンで実行されます。(通常、Pod内のコンテナとなります)各cloud-controller-managerは、シングルプロセスで複数のcontrollers を実装します。
備考: コントロールプレーンの一部ではなく、Kubernetesの
addon としてクラウドコントローラーマネージャーを実行することもできます。
クラウドコントローラーマネージャーの機能 クラウドコントローラーマネージャーのコントローラーは以下を含んでいます。
ノードコントローラー ノードコントローラーは、クラウドインフラストラクチャーで新しいサーバーが作成された際に、Node オブジェクトを作成する責務を持ちます。ノードコントローラーは、クラウドプロバイダーのテナント内で動作しているホストの情報を取得します。ノードコントローラーは下記に示す機能を実行します:
Nodeオブジェクトを、コントローラーがクラウドプロバイダーAPIを通じて見つけた各サーバーで初期化する Nodeオブジェクトに、ノードがデプロイされているリージョンや利用可能なリソース(CPU、メモリなど)のようなクラウド特有な情報を注釈付けやラベル付けをする ノードのホスト名とネットワークアドレスを取得する ノードの正常性を検証する。ノードが応答しなくなった場合、クラウドプロバイダーのAPIを利用しサーバーがdeactivated / deleted / terminatedであるかを確認する。クラウドからノードが削除されていた場合、KubernetesクラスターからNodeオブジェクトを削除する いくつかのクラウドプロバイダーは、これをノードコントローラーと個別のノードライフサイクルコントローラーに分けて実装しています。
ルートコントローラー ルートコントローラーは、クラスター内の異なるノード上で稼働しているコンテナが相互に通信できるように、クラウド内のルートを適切に設定する責務を持ちます。
クラウドプロバイダーによっては、ルートコントローラーはPodネットワークのIPアドレスのブロックを割り当てることもあります。
サービスコントローラー Services は、マネージドロードバランサー、IPアドレスネットワークパケットフィルタや対象のヘルスチェックのようなクラウドインフラストラクチャーコンポーネントのインテグレーションを行います。サービスコントローラーは、ロードバランサーや他のインフラストラクチャーコンポーネントを必要とするServiceリソースを宣言する際にそれらのコンポーネントを設定するため、クラウドプロバイダーのAPIと対話します。
認可 このセクションでは、クラウドコントローラーマネージャーが操作を行うために様々なAPIオブジェクトに必要な権限を分類します。
ノードコントローラー ノードコントローラーはNodeオブジェクトのみに対して働きます。Nodeオブジェクトに対して、readとmodifyの全権限が必要です。
v1/Node
:
Get List Create Update Patch Watch Delete ルートコントローラー ルートコントローラーは、Nodeオブジェクトの作成を待ち受け、ルートを適切に設定します。Nodeオブジェクトについて、get権限が必要です。
v1/Node
:
サービスコントローラー サービスコントローラーは、Serviceオブジェクトの作成、更新、削除イベントを待ち受け、その後、サービスのEndpointを適切に設定します。
サービスにアクセスするため、list、watchの権限が必要です。サービスを更新するため、patch、updateの権限が必要です。
サービスのEndpointリソースを設定するため、create、list、get、watchそしてupdateの権限が必要です。
v1/Service
:
その他 クラウドコントローラーマネージャーのコア機能の実装は、Eventオブジェクトのcreate権限と、セキュアな処理を保証するため、ServiceAccountのcreate権限が必要です。
v1/Event
:
v1/ServiceAccount
:
クラウドコントローラーマネージャーのRBAC ClusterRoleはこのようになります:
apiVersion : rbac.authorization.k8s.io/v1
kind : ClusterRole
metadata :
name : cloud-controller-manager
rules :
- apiGroups :
- ""
resources :
- events
verbs :
- create
- patch
- update
- apiGroups :
- ""
resources :
- nodes
verbs :
- '*'
- apiGroups :
- ""
resources :
- nodes/status
verbs :
- patch
- apiGroups :
- ""
resources :
- services
verbs :
- list
- patch
- update
- watch
- apiGroups :
- ""
resources :
- serviceaccounts
verbs :
- create
- apiGroups :
- ""
resources :
- persistentvolumes
verbs :
- get
- list
- update
- watch
- apiGroups :
- ""
resources :
- endpoints
verbs :
- create
- get
- list
- watch
- update
次の項目 Cloud Controller Manager Administration
はクラウドコントラーマネージャーの実行と管理を説明しています。
どのようにあなた自身のクラウドコントローラーマネージャーが実装されるのか、もしくは既存プロジェクトの拡張について知りたいですか?
クラウドコントローラーマネージャーは、いかなるクラウドからもプラグインとしての実装を許可するためにGoインターフェースを使います。具体的には、kubernetes/cloud-provider の cloud.go
で定義されているCloudProvider
を使います。
本ドキュメントでハイライトした共有コントローラー(Node、Route、Service)の実装と共有クラウドプロバイダーインターフェースに沿ったいくつかの足場は、Kubernetesコアの一部です。クラウドプロバイダに特化した実装は、Kubernetesのコアの外部として、またCloudProvider
インターフェースを実装します。
プラグイン開発ついての詳細な情報は、Developing Cloud Controller Manager を見てください。
2.6 - cgroup v2について Linuxでは、コントロールグループ がプロセスに割り当てられるリソースを制限しています。
コンテナ化されたワークロードの、CPU/メモリーの要求と制限を含むPodとコンテナのリソース管理 を強制するために、
kubelet と基盤となるコンテナランタイムはcgroupをインターフェースとして接続する必要があります。
Linuxではcgroup v1とcgroup v2の2つのバージョンのcgroupがあります。
cgroup v2は新世代のcgroup
APIです。
cgroup v2とは何か? FEATURE STATE:
Kubernetes v1.25 [stable]
cgroup v2はLinuxのcgroup
APIの次のバージョンです。
cgroup v2はリソース管理機能を強化した統合制御システムを提供しています。
以下のように、cgroup v2はcgroup v1からいくつかの点を改善しています。
統合された単一階層設計のAPI より安全なコンテナへのサブツリーの移譲 Pressure Stall Information などの新機能強化されたリソース割り当て管理と複数リソース間の隔離異なるタイプのメモリー割り当ての統一(ネットワークメモリー、カーネルメモリーなど) ページキャッシュの書き戻しといった、非即時のリソース変更 Kubernetesのいくつかの機能では、強化されたリソース管理と隔離のためにcgroup v2のみを使用しています。
例えば、MemoryQoS 機能はメモリーQoSを改善し、cgroup v2の基本的な機能に依存しています。
cgroup v2を使う cgroup v2を使うおすすめの方法は、デフォルトでcgroup v2が有効で使うことができるLinuxディストリビューションを使うことです。
あなたのディストリビューションがcgroup v2を使っているかどうかを確認するためには、Linux Nodeのcgroupバージョンを特定する を参照してください。
必要要件 cgroup v2を使うには以下のような必要要件があります。
OSディストリビューションでcgroup v2が有効であること Linuxカーネルバージョンが5.8以上であること コンテナランタイムがcgroup v2をサポートしていること。例えば、 kubeletとコンテナランタイムがsystemd cgroupドライバー を使うように設定されていること Linuxディストリビューションのcgroup v2サポート cgroup v2を使っているLinuxディストリビューションの一覧はcgroup v2ドキュメント をご覧ください。
Container-Optimized OS (M97以降) Ubuntu (21.10以降, 22.04以降推奨) Debian GNU/Linux (Debian 11 bullseye以降) Fedora (31以降) Arch Linux (April 2021以降) RHEL and RHEL-like distributions (9以降) あなたのディストリビューションがcgroup v2を使っているかどうかを確認するためには、あなたのディストリビューションのドキュメントを参照するか、Linux Nodeのcgroupバージョンを特定する の説明に従ってください。
カーネルのcmdlineの起動時引数を修正することで、手動であなたのLinuxディストリビューションのcgroup v2を有効にすることもできます。
あなたのディストリビューションがGRUBを使っている場合は、
/etc/default/grub
の中のGRUB_CMDLINE_LINUX
にsystemd.unified_cgroup_hierarchy=1
を追加し、sudo update-grub
を実行してください。
ただし、おすすめの方法はデフォルトですでにcgroup v2が有効になっているディストリビューションを使うことです。
cgroup v2への移行 cgroup v2に移行するには、必要要件 を満たすことを確認し、
cgroup v2がデフォルトで有効であるカーネルバージョンにアップグレードします。
kubeletはOSがcgroup v2で動作していることを自動的に検出し、それに応じて処理を行うため、追加設定は必要ありません。
ノード上やコンテナ内からユーザーが直接cgroupファイルシステムにアクセスしない限り、cgroup v2に切り替えたときのユーザー体験に目立った違いはないはずです。
cgroup v2はcgroup v1とは違うAPIを利用しているため、cgroupファイルシステムに直接アクセスしているアプリケーションはcgroup v2をサポートしている新しいバージョンに更新する必要があります。例えば、
サードパーティーの監視またはセキュリティエージェントはcgroupファイルシステムに依存していることがあります。
エージェントをcgroup v2をサポートしているバージョンに更新してください。 Podやコンテナを監視するためにcAdvisor をスタンドアローンのDaemonSetとして起動している場合、v0.43.0以上に更新してください。 Javaアプリケーションをデプロイする場合は、完全にcgroup v2をサポートしているバージョンを利用してください: uber-go/automaxprocs パッケージを利用している場合は、利用するバージョンがv1.5.1以上であることを確認してください。Linux Nodeのcgroupバージョンを特定する cgroupバージョンは利用されているLinuxディストリビューションと、OSで設定されているデフォルトのcgroupバージョンに依存します。
あなたのディストリビューションがどちらのcgroupバージョンを利用しているのかを確認するには、stat -fc %T /sys/fs/cgroup/
コマンドをノード上で実行してください。
stat -fc %T /sys/fs/cgroup/
cgroup v2では、cgroup2fs
と出力されます。
cgroup v1では、tmpfs
と出力されます。
次の項目 2.7 - コンテナランタイムインターフェース(CRI) CRIは、クラスターコンポーネントを再コンパイルすることなく、kubeletがさまざまなコンテナランタイムを使用できるようにするプラグインインターフェースです。
kubelet がPod とそのコンテナを起動できるように、クラスター内の各ノードで動作するcontainer runtime が必要です。
kubeletとContainerRuntime間の通信のメインプロトコルです。
Kubernetes Container Runtime Interface(CRI)は、クラスターコンポーネント kubelet とcontainer runtime 間の通信用のメインgRPC プロトコルを定義します。
API FEATURE STATE:
Kubernetes v1.23 [stable]
kubeletは、gRPCを介してコンテナランタイムに接続するときにクライアントとして機能します。ランタイムおよびイメージサービスエンドポイントは、コンテナランタイムで使用可能である必要があります。コンテナランタイムは、--image-service-endpoint
コマンドラインフラグ を使用して、kubelet内で個別に設定できます。
Kubernetes v1.32の場合、kubeletはCRI v1
の使用を優先します。
コンテナランタイムがCRIのv1
をサポートしていない場合、kubeletはサポートされている古いバージョンのネゴシエーションを試みます。
kubelet v1.32はCRI v1alpha2
をネゴシエートすることもできますが、このバージョンは非推奨と見なされます。
kubeletがサポートされているCRIバージョンをネゴシエートできない場合、kubeletはあきらめて、ノードとして登録されません。
アップグレード Kubernetesをアップグレードする場合、kubeletはコンポーネントの再起動時に最新のCRIバージョンを自動的に選択しようとします。
それが失敗した場合、フォールバックは上記のように行われます。
コンテナランタイムがアップグレードされたためにgRPCリダイヤルが必要な場合は、コンテナランタイムも最初に選択されたバージョンをサポートする必要があります。
そうでない場合、リダイヤルは失敗することが予想されます。これには、kubeletの再起動が必要です。
次の項目 2.8 - ガベージコレクション ガベージコレクションは、Kubernetesがクラスターリソースをクリーンアップするために使用するさまざまなメカニズムの総称です。これにより、次のようなリソースのクリーンアップが可能になります:
オーナーの依存関係 Kubernetesの多くのオブジェクトは、owner reference を介して相互にリンクしています。
owner referenceは、どのオブジェクトが他のオブジェクトに依存しているかをコントロールプレーンに通知します。
Kubernetesは、owner referenceを使用して、コントロールプレーンやその他のAPIクライアントに、オブジェクトを削除する前に関連するリソースをクリーンアップする機会を提供します。
ほとんどの場合、Kubernetesはowner referenceを自動的に管理します。
Ownershipは、一部のリソースでも使用されるラベルおよびセレクター メカニズムとは異なります。
たとえば、EndpointSlice
オブジェクトを作成するService を考えます。
Serviceはラベル を使用して、コントロールプレーンがServiceに使用されているEndpointSlice
オブジェクトを判別できるようにします。
ラベルに加えて、Serviceに代わって管理される各EndpointSlice
には、owner referenceがあります。
owner referenceは、Kubernetesのさまざまな部分が制御していないオブジェクトへの干渉を回避するのに役立ちます。
備考: namespace間のowner referenceは、設計上許可されていません。
namespaceの依存関係は、クラスタースコープまたはnamespaceのオーナーを指定できます。
namespaceのオーナーは、依存関係と同じnamespaceに存在する必要があります 。
そうでない場合、owner referenceは不在として扱われ、すべてのオーナーが不在であることが確認されると、依存関係は削除される可能性があります。
クラスタースコープの依存関係は、クラスタースコープのオーナーのみを指定できます。
v1.20以降では、クラスタースコープの依存関係がnamespaceを持つkindをオーナーとして指定している場合、それは解決できないowner referenceを持つものとして扱われ、ガベージコレクションを行うことはできません。
V1.20以降では、ガベージコレクタは無効な名前空間間のownerReference
、またはnamespaceのkindを参照するownerReference
をもつクラスター・スコープの依存関係を検出した場合、無効な依存関係のOwnerRefInvalidNamespace
とinvolvedObject
を理由とする警告イベントが報告されます。
以下のコマンドを実行すると、そのようなイベントを確認できます。
kubectl get events -A --field-selector=reason=OwnerRefInvalidNamespace
カスケード削除 Kubernetesは、ReplicaSetを削除したときに残されたPodなど、owner referenceがなくなったオブジェクトをチェックして削除します。
オブジェクトを削除する場合、カスケード削除と呼ばれるプロセスで、Kubernetesがオブジェクトの依存関係を自動的に削除するかどうかを制御できます。
カスケード削除には、次の2つのタイプがあります。
フォアグラウンドカスケード削除 バックグラウンドカスケード削除 また、Kubernetes finalizer を使用して、ガベージコレクションがowner referenceを持つリソースを削除する方法とタイミングを制御することもできます。
フォアグラウンドカスケード削除 フォアグラウンドカスケード削除では、削除するオーナーオブジェクトは最初に削除進行中 の状態になります。
この状態では、オーナーオブジェクトに次のことが起こります。
Kubernetes APIサーバーは、オブジェクトのmetadata.deletionTimestamp
フィールドを、オブジェクトに削除のマークが付けられた時刻に設定します。 Kubernetes APIサーバーは、metadata.finalizers
フィールドをforegroundDeletion
に設定します。 オブジェクトは、削除プロセスが完了するまで、KubernetesAPIを介して表示されたままになります。 オーナーオブジェクトが削除進行中の状態に入ると、コントローラーは依存関係を削除します。
すべての依存関係オブジェクトを削除した後、コントローラーはオーナーオブジェクトを削除します。
この時点で、オブジェクトはKubernetesAPIに表示されなくなります。
フォアグラウンドカスケード削除中に、オーナーの削除をブロックする依存関係は、ownerReference.blockOwnerDeletion=true
フィールドを持つ依存関係のみです。
詳細については、フォアグラウンドカスケード削除の使用 を参照してください。
バックグラウンドカスケード削除 バックグラウンドカスケード削除では、Kubernetes APIサーバーがオーナーオブジェクトをすぐに削除し、コントローラーがバックグラウンドで依存オブジェクトをクリーンアップします。
デフォルトでは、フォアグラウンド削除を手動で使用するか、依存オブジェクトを孤立させることを選択しない限り、Kubernetesはバックグラウンドカスケード削除を使用します。
詳細については、バックグラウンドカスケード削除の使用 を参照してください。
孤立した依存関係 Kubernetesがオーナーオブジェクトを削除すると、残された依存関係はorphan オブジェクトと呼ばれます。
デフォルトでは、Kubernetesは依存関係オブジェクトを削除します。この動作をオーバーライドする方法については、オーナーオブジェクトの削除と従属オブジェクトの孤立 を参照してください。
未使用のコンテナとイメージのガベージコレクション kubelet は未使用のイメージに対して5分ごとに、未使用のコンテナに対して1分ごとにガベージコレクションを実行します。
外部のガベージコレクションツールは、kubeletの動作を壊し、存在するはずのコンテナを削除する可能性があるため、使用しないでください。
未使用のコンテナとイメージのガベージコレクションのオプションを設定するには、設定ファイル を使用してkubeletを調整し、KubeletConfiguration
リソースタイプを使用してガベージコレクションに関連するパラメーターを変更します。
コンテナイメージのライフサイクル Kubernetesは、kubeletの一部であるイメージマネージャー を通じて、cadvisor の協力を得て、すべてのイメージのライフサイクルを管理します。kubeletは、ガベージコレクションを決定する際に、次のディスク使用制限を考慮します。
HighThresholdPercent
LowThresholdPercent
設定されたHighThresholdPercent
値を超えるディスク使用量はガベージコレクションをトリガーします。
ガベージコレクションは、最後に使用された時間に基づいて、最も古いものから順にイメージを削除します。
kubeletは、ディスク使用量がLowThresholdPercent
値に達するまでイメージを削除します。
コンテナのガベージコレクション kubeletは、次の変数に基づいて未使用のコンテナをガベージコレクションします。
MinAge
: kubeletがガベージコレクションできるコンテナの最低期間。0
を設定すると無効化されます。MaxPerPodContainer
: 各Podが持つことができるデッドコンテナの最大数。0
未満に設定すると無効化されます。MaxContainers
: クラスターが持つことができるデッドコンテナの最大数。0
未満に設定すると無効化されます。これらの変数に加えて、kubeletは、通常、最も古いものから順に、定義されていない削除されたコンテナをガベージコレクションします。
MaxPerPodContainer
とMaxContainers
は、Podごとのコンテナの最大数(MaxPerPodContainer
)を保持すると、グローバルなデッドコンテナの許容合計(MaxContainers
)を超える状況で、互いに競合する可能性があります。
この状況では、kubeletはMaxPerPodContainer
を調整して競合に対処します。最悪のシナリオは、MaxPerPodContainer
を1にダウングレードし、最も古いコンテナを削除することです。
さらに、削除されたPodが所有するコンテナは、MinAge
より古くなると削除されます。
備考: kubeletがガベージコレクションするのは、自分が管理するコンテナのみです。ガベージコレクションの設定 これらのリソースを管理するコントローラーに固有のオプションを設定することにより、リソースのガベージコレクションを調整できます。次のページは、ガベージコレクションを設定する方法を示しています。
次の項目 3 - コンテナ アプリケーションとランタイムの依存関係を一緒にパッケージ化するための技術
実行するそれぞれのコンテナは繰り返し使用可能です。依存関係を含めて標準化されており、どこで実行しても同じ動作が得られることを意味しています。
コンテナは基盤となるホストインフラからアプリケーションを切り離します。これにより、さまざまなクラウドやOS環境下でのデプロイが容易になります。
コンテナイメージ コンテナイメージ はすぐに実行可能なソフトウェアパッケージで、アプリケーションの実行に必要なものをすべて含んています。コードと必要なランタイム、アプリケーションとシステムのライブラリ、そして必須な設定項目のデフォルト値を含みます。
設計上、コンテナは不変で、既に実行中のコンテナのコードを変更することはできません。コンテナ化されたアプリケーションがあり変更したい場合は、変更を含んだ新しいイメージをビルドし、コンテナを再作成して、更新されたイメージから起動する必要があります。
コンテナランタイム コンテナランタイムは、コンテナの実行を担当するソフトウェアです。
Kubernetesは次の複数のコンテナランタイムをサポートします。
Docker 、containerd 、CRI-O 、
および全ての
Kubernetes CRI (Container Runtime Interface)
実装です。
次の項目 3.1 - イメージ コンテナイメージはアプリケーションと依存関係のあるすべてソフトウェアをカプセル化したバイナリデータを表します。コンテナイメージはスタンドアロンで実行可能なソフトウェアをひとつにまとめ、ランタイム環境に関する想定を明確に定義しています。
アプリケーションのコンテナイメージを作成し、一般的にはPod で参照する前にレジストリへPushします。
このページではコンテナイメージの概要を説明します。
イメージの名称 コンテナイメージは、pause
、example/mycontainer
、またはkube-apiserver
のような名前が通常つけられます。
イメージにはレジストリのホスト名も含めることができ(例:fictional.registry.example/imagename
)、さらにポート番号も含めることが可能です(例:fictional.registry.example:10443/imagename
)。
レジストリのホスト名を指定しない場合は、KubernetesはDockerパブリックレジストリを意味していると見なします。
イメージ名の後に、タグ を追加することができます(docker
やpodman
のようなコマンドを利用した場合と同様)。
タグによって同じイメージの異なるバージョンを識別できます。
イメージタグは大文字と小文字、数値、アンダースコア(_
)、ピリオド(.
)とマイナス(-
)で構成されます。
イメージタグでは区切り記号(_
、-
、.
)を指定できる追加ルールがあります。
タグを指定しない場合は、Kubernetesはlatest
タグを指定したと見なします。
イメージの更新 Deployment 、StatefulSet 、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
でも効率的です。
コンテナランタイムは、イメージレイヤーが既にノード上に存在することを認識できるので、再度ダウンロードする必要がありません。
備考: 本番環境でコンテナをデプロイする場合は、:latest
タグの使用を避けるべきです。
実行中のイメージのバージョンを追跡するのが難しく、正しくロールバックすることがより困難になるためです。
かわりに、v1.42.0
のような特定できるタグを指定してください。
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
が設定される備考: コンテナのimagePullPolicy
の値は、そのオブジェクトが最初に 作成 されたときに常に設定され、イメージのタグが後で変更された場合でも更新されません。
例えば、タグが:latest
でない イメージを使ってDeploymentを生成した場合、後でDeploymentのイメージを:latest
タグに変更しても、imagePullPolicy
はAlways
に更新されません。オブジェクトのPullポリシーは、初期作成後に手動で変更する必要があります。
必要なイメージをPullする 常に強制的にPullしたい場合は、以下のいずれかを行ってください。
コンテナのimagePullPolicy
にAlways
を設定する。 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分)に達するまで、試行するごとに遅延を増加させます。
イメージインデックスを使ったマルチアーキテクチャイメージ コンテナレジストリはバイナリイメージの提供だけでなく、コンテナイメージインデックス も提供する事ができます。イメージインデックスはコンテナのアーキテクチャ固有バージョンに関する複数のイメージマニフェスト を指すことができます。イメージインデックスの目的はイメージの名前(例:pause
、example/mycontainer
、kube-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したイメージ
備考: Node構成を制御できる場合、この方法が適しています。
クラウドプロバイダーがNodeを管理し自動的に設定を置き換える場合は、確実に機能できません。デフォルトでは、kubeletは指定されたレジストリからそれぞれのイメージをPullしようとします。
また一方では、コンテナのimagePullPolicy
プロパティにIfNotPresent
やNever
が設定されている場合、ローカルのイメージが使用されます。(それぞれに対して、優先的またはか排他的に)
レジストリ認証の代替として事前に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は自分自身のNamespace内にあるimage pull secretsのみが参照可能であるため、この作業はNemespace毎に1回行う必要があります。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
に組み合わせて利用できます。認証情報はマージされます。
ユースケース プライベートレジストリを設定するためのソリューションはいくつかあります。ここでは、いくつかの一般的なユースケースと推奨される解決方法を示します。
クラスターに独自仕様でない(例えば、オープンソース)イメージだけを実行する。イメージを非公開にする必要がないパブリックレジストリのパブリックイメージを利用する設定は必要ない クラウドプロバイダーによっては、可用性の向上とイメージをPullする時間を短くする為に、自動的にキャッシュやミラーされたパプリックイメージが提供される 社外には非公開の必要があるが、すべてのクラスター利用者には見せてよい独自仕様のイメージをクラスターで実行しているホストされたプライペートレジストリを使用プライベートレジストリにアクセスする必要があるノードには、手動設定が必要となる場合がある または、オープンな読み取りアクセスを許可したファイヤーウォールの背後で内部向けプライベートレジストリを実行する イメージへのアクセスを制御できるホストされたコンテナイメージレジストリサービスを利用するNodeを手動設定するよりもクラスターのオートスケーリングのほうがうまく機能する また、Node設定変更を自由にできないクラスターではimagePullSecrets
を使用する 独自仕様のイメージを含むクラスターで、いくつかは厳格なアクセス制御が必要である それぞれのテナントが独自のプライベートレジストリを必要とするマルチテナントのクラスターであるAlwaysPullImagesアドミッションコントローラー が有効化を確認する必要がある。さもないと、すべてのテナントの全Podが全部のイメージにアクセスできてしまう可能性がある認証が必要なプライベートレジストリを実行する それぞれのテナントでレジストリ認証を生成し、Secretへ設定し、各テナントのNamespaceに追加する テナントは、Secretを各NamespaceのimagePullSecretsへ追加する 複数のレジストリへのアクセスが必要な場合、それぞれのレジストリ毎にひとつのSecretを作成する事ができます。
次の項目 3.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.3 - ランタイムクラス(Runtime Class) FEATURE STATE:
Kubernetes v1.20 [stable]
このページではRuntimeClassリソースと、runtimeセクションのメカニズムについて説明します。
RuntimeClassはコンテナランタイムの設定を選択するための機能です。そのコンテナランタイム設定はPodのコンテナを稼働させるために使われます。
RuntimeClassを使う動機 異なるPodに異なるRuntimeClassを設定することで、パフォーマンスとセキュリティのバランスをとることができます。例えば、ワークロードの一部に高レベルの情報セキュリティ保証が必要な場合、ハードウェア仮想化を使用するコンテナランタイムで実行されるようにそれらのPodをスケジュールすることを選択できます。その後、追加のオーバーヘッドを犠牲にして、代替ランタイムをさらに分離することでメリットが得られます。
RuntimeClassを使用して、コンテナランタイムは同じで設定が異なるPodを実行することもできます。
セットアップ ノード上でCRI実装を設定する。(ランタイムに依存) 対応するRuntimeClassリソースを作成する。 1. ノード上でCRI実装を設定する RuntimeClassを通じて利用可能な設定はContainer Runtime Interface (CRI)の実装依存となります。
ユーザーの環境のCRI実装の設定方法は、対応するドキュメント(下記 )を参照ください。
備考: RuntimeClassは、クラスター全体で同じ種類のノード設定であることを仮定しています。(これは全てのノードがコンテナランタイムに関して同じ方法で構成されていることを意味します)。
設定が異なるノードをサポートするには、
スケジューリング を参照してください。
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の書き込み操作(create/update/patch/delete)はクラスター管理者のみに制限されることを推奨します。
これはたいていデフォルトで有効となっています。さらなる詳細に関しては
Authorization
Overview を参照してください。
使用例 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ランタイムのセットアップに関するさらなる詳細は、コンテナランタイム を参照してください。
ランタイムハンドラーは、/etc/containerd/config.toml
にあるcontainerdの設定ファイルにより設定されます。
正しいハンドラーは、そのruntime
セクションで設定されます。
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.${HANDLER_NAME}]
詳細はcontainerdの設定に関するドキュメント を参照してください。
ランタイムハンドラーは、/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内部で使用されるオーバーヘッドを確保することができます。
次の項目 3.4 - コンテナライフサイクルフック このページでは、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管理システムはフックアクションにしたがってハンドラーを実行します。
httpGet
とtcpSocket
はkubeletプロセスによって実行され、exec
はコンテナの中で実行されます。
フックハンドラーの呼び出しは、コンテナを含むPodのコンテキスト内で同期しています。
これは、PostStart
フックの場合、コンテナのENTRYPOINTとフックは非同期に起動することを意味します。
しかし、フックの実行に時間がかかりすぎたりハングしたりすると、コンテナはrunning
状態になることができません。
PreStop
フックはコンテナを停止するシグナルから非同期で実行されるのではなく、TERMシグナルが送られる前に実行を完了する必要があります。
もしPreStop
フックが実行中にハングした場合、PodはTerminating
状態になり、
terminationGracePeriodSeconds
の時間切れで強制終了されるまで続きます。
この猶予時間は、PreStop
フックが実行され正常にコンテナを停止できるまでの合計時間に適用されます。
例えばterminationGracePeriodSeconds
が60で、フックの終了に55秒かかり、シグナルを受信した後にコンテナを正常に停止させるのに10秒かかる場合、コンテナは正常に停止する前に終了されてしまいます。terminationGracePeriodSeconds
が、これら2つの実行にかかる合計時間(55+10)よりも短いからです。
PostStart
またはPreStop
フックが失敗した場合、コンテナは強制終了します。
ユーザーはフックハンドラーをできるだけ軽量にするべきです。
ただし、コンテナを停止する前に状態を保存するなどの場合は、長時間のコマンド実行が必要なケースもあります。
フック配信保証 フックの配信は 少なくとも1回 を意図しています。これはフックがPostStart
やPreStop
のような任意のイベントに対して複数回呼ばれることがあることを意味します。
これを正しく処理するのはフックの実装次第です。
通常、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
次の項目 4 - ワークロード Kubernetesにおけるデプロイ可能な最小のオブジェクトであるPodと、高レベルな抽象化がPodの実行を助けることを理解します。
ワークロードとは、Kubernetes上で実行中のアプリケーションです。
ワークロードが1つのコンポーネントからなる場合でも、複数のコンポーネントが協調して動作する場合でも、KubernetesではそれらはPod の集合として実行されます。Kubernetesでは、Podはクラスター上で実行中のコンテナ の集合として表されます。
Podには定義されたライフサイクルがあります。たとえば、一度Podがクラスター上で実行中になると、そのPodが実行中のノード 上で深刻な障害が起こったとき、そのノード上のすべてのPodは停止してしまうことになります。Kubernetesではそのようなレベルの障害を最終的なものとして扱うため、たとえノードが後で復元したとしても、ユーザーは新しいPodを作成し直す必要があります。
しかし、生活をかなり楽にするためには、それぞれのPodを直接管理する必要はありません。ワークロードリソース を利用すれば、あなたの代わりにPodの集合の管理を行ってもらえます。これらのリソースはあなたが指定した状態に一致するようにコントローラー を設定し、正しい種類のPodが正しい数だけ実行中になることを保証してくれます。
ワークロードリソースには、次のような種類があります。
多少関連のある2種類の補助的な概念もあります。
次の項目 各リソースについて読む以外にも、以下のページでそれぞれのワークロードに関連する特定のタスクについて学ぶことができます。
アプリケーションが実行できるようになったら、インターネット上で公開したくなるかもしれません。その場合には、Service として公開したり、ウェブアプリケーションだけの場合、Ingress を使用することができます。
コードを設定から分離するKubernetesのしくみについて学ぶには、設定 を読んでください。
4.1 - Pod Pod は、Kubernetes内で作成・管理できるコンピューティングの最小のデプロイ可能なユニットです。
Pod (Podという名前は、たとえばクジラの群れ(pod of whales)やえんどう豆のさや(pea pod)などの表現と同じような意味です)は、1つまたは複数のコンテナ のグループであり、ストレージやネットワークの共有リソースを持ち、コンテナの実行方法に関する仕様を持っています。同じPodに含まれるリソースは、常に同じ場所で同時にスケジューリングされ、共有されたコンテキストの中で実行されます。Podはアプリケーションに特化した「論理的なホスト」をモデル化します。つまり、1つのPod内には、1つまたは複数の比較的密に結合されたアプリケーションコンテナが含まれます。クラウド外の文脈で説明すると、アプリケーションが同じ物理ホストや同じバーチャルマシンで実行されることが、クラウドアプリケーションの場合には同じ論理ホスト上で実行されることに相当します。
アプリケーションコンテナと同様に、Podでも、Podのスタートアップ時に実行されるinitコンテナ を含めることができます。また、クラスターで利用できる場合には、エフェメラルコンテナ を注入してデバッグすることもできます。
Podとは何か? 備考: KubernetesはDockerだけでなく複数の
コンテナランタイム をサポートしていますが、
Docker が最も一般的に知られたランタイムであるため、Docker由来の用語を使ってPodを説明するのが理解の助けとなります。
Podの共有コンテキストは、Dockerコンテナを隔離するのに使われているのと同じ、Linuxのnamespaces、cgroups、場合によっては他の隔離技術の集合を用いて作られます。Podのコンテキスト内では、各アプリケーションが追加の準隔離技術を適用することもあります。
Dockerの概念を使って説明すると、Podは共有の名前空間と共有ファイルシステムのボリュームを持つDockerコンテナのグループに似ています。
Podを使用する 以下は、nginx:1.14.2
イメージが実行されるコンテナからなるPodの例を記載しています。
apiVersion : v1
kind : Pod
metadata :
name : nginx
spec :
containers :
- name : nginx
image : nginx:1.14.2
ports :
- containerPort : 80
上記のようなPodを作成するには、以下のコマンドを実行します:
kubectl apply -f https://k8s.io/examples/pods/simple-pod.yaml
Podは通常、直接作成されず、ワークロードリソースで作成されます。ワークロードリソースでPodを作成する方法の詳細については、Podを利用する を参照してください。
Podを管理するためのワークロードリソース 通常、たとえ単一のコンテナしか持たないシングルトンのPodだとしても、自分でPodを直接作成する必要はありません。その代わりに、Deployment やJob などのワークロードリソースを使用してPodを作成します。もしPodが状態を保持する必要がある場合は、StatefulSet リソースを使用することを検討してください。
Kubernetesクラスター内のPodは、主に次の2種類の方法で使われます。
単一のコンテナを稼働させるPod 。「1Pod1コンテナ」構成のモデルは、Kubernetesでは最も一般的なユースケースです。このケースでは、ユーザーはPodを単一のコンテナのラッパーとして考えることができます。Kubernetesはコンテナを直接管理するのではなく、Podを管理します。
協調して稼働させる必要がある複数のコンテナを稼働させるPod 。単一のPodは、密に結合してリソースを共有する必要があるような、同じ場所で稼働する複数のコンテナからなるアプリケーションをカプセル化することもできます。これらの同じ場所で稼働するコンテナ群は、単一のまとまりのあるサービスのユニットを構成します。たとえば、1つのコンテナが共有ボリュームからファイルをパブリックに配信し、別のサイドカー コンテナがそれらのファイルを更新するという構成が考えられます。Podはこれらの複数のコンテナ、ストレージリソース、一時的なネットワークIDなどを、単一のユニットとしてまとめます。
備考: 複数のコンテナを同じ場所で同時に管理するように単一のPod内にグループ化するのは、比較的高度なユースケースです。このパターンを使用するのは、コンテナが密に結合しているような特定のインスタンス内でのみにするべきです。各Podは、与えられたアプリケーションの単一のインスタンスを稼働するためのものです。もしユーザーのアプリケーションを水平にスケールさせたい場合(例: 複数インスタンスを稼働させる)、複数のPodを使うべきです。1つのPodは各インスタンスに対応しています。Kubernetesでは、これは一般的にレプリケーション と呼ばれます。レプリケーションされたPodは、通常ワークロードリソースと、それに対応するコントローラー によって、作成・管理されます。
Kubernetesがワークロードリソースとそのコントローラーを活用して、スケーラブルで自動回復するアプリケーションを実装する方法については、詳しくはPodとコントローラー を参照してください。
Podが複数のコンテナを管理する方法 Podは、まとまりの強いサービスのユニットを構成する、複数の協調する(コンテナとして実行される)プロセスをサポートするために設計されました。単一のPod内の複数のコンテナは、クラスター内の同じ物理または仮想マシン上で、自動的に同じ場所に配置・スケジューリングされます。コンテナ間では、リソースや依存関係を共有したり、お互いに通信したり、停止するときにはタイミングや方法を協調して実行できます。
たとえば、あるコンテナが共有ボリューム内のファイルを配信するウェブサーバーとして動作し、別の「サイドカー」コンテナがリモートのリソースからファイルをアップデートするような構成が考えられます。この構成を以下のダイアグラムに示します。
Podによっては、appコンテナ に加えてinitコンテナ を持っている場合があります。initコンテナはappコンテナが起動する前に実行・完了するコンテナです。
Podは、Podを構成する複数のコンテナに対して、ネットワーク とストレージ の2種類の共有リソースを提供します。
Podを利用する 通常Kubernetesでは、たとえ単一のコンテナしか持たないシングルトンのPodだとしても、個別のPodを直接作成することはめったにありません。その理由は、Podがある程度一時的で使い捨てできる存在として設計されているためです。Podが作成されると(あなたが直接作成した場合でも、コントローラー が間接的に作成した場合でも)、新しいPodはクラスター内のノード 上で実行されるようにスケジューリングされます。Podは、実行が完了するか、Podオブジェクトが削除されるか、リソース不足によって強制退去 されるか、ノードが停止するまで、そのノード上にとどまります。
備考: Pod内のコンテナの再起動とPodの再起動を混同しないでください。Podはプロセスではなく、コンテナが実行するための環境です。Podは削除されるまでは残り続けます。Podオブジェクトのためのマニフェストを作成したときは、指定したPodの名前が有効なDNSサブドメイン名 であることを確認してください。
Pod OS FEATURE STATE:
Kubernetes v1.25 [stable]
.spec.os.name
フィールドでwindows
かlinux
のいずれかを設定し、Podを実行させたいOSを指定する必要があります。Kubernetesは今のところ、この2つのOSだけサポートしています。将来的には増える可能性があります。
Kubernetes v1.32では、このフィールドに設定した値はPodのスケジューリング に影響を与えません。.spec.os.name
を設定することで、Pod OSに権限を認証することができ、バリデーションにも使用されます。kubeletが実行されているノードのOSが、指定されたPod OSと異なる場合、kubeletはPodの実行を拒否します。
Podセキュリティの標準 もこのフィールドを使用し、指定したOSと関係ないポリシーの適用を回避しています。
Podとコンテナコントローラー ワークロードリソースは、複数のPodを作成・管理するために利用できます。リソースに対応するコントローラーが、複製やロールアウトを扱い、Podの障害時には自動回復を行います。たとえば、あるノードに障害が発生した場合、コントローラーはそのノードの動作が停止したことを検知し、代わりのPodを作成します。そして、スケジューラーが代わりのPodを健全なノード上に配置します。
以下に、1つ以上のPodを管理するワークロードリソースの一例をあげます。
Podテンプレート workload リソース向けのコントローラーは、PodをPodテンプレート を元に作成し、あなたの代わりにPodを管理してくれます。
PodTemplateはPodを作成するための仕様で、Deployment 、Job 、DaemonSet などのワークロードリソースの中に含まれています。
ワークロードリソースに対応する各コントローラーは、ワークロードオブジェクト内にあるPodTemplate
を使用して実際のPodを作成します。PodTemplate
は、アプリを実行するために使われるワークロードリソースがどんな種類のものであれ、その目的の状態の一部を構成するものです。
以下は、単純なJobのマニフェストの一例で、1つのコンテナを実行するtemplate
があります。Pod内のコンテナはメッセージを出力した後、一時停止します。
apiVersion : batch/v1
kind : Job
metadata :
name : hello
spec :
template :
# これがPodテンプレートです
spec :
containers :
- name : hello
image : busybox:1.28
command : ['sh' , '-c' , 'echo "Hello, Kubernetes!" && sleep 3600' ]
restartPolicy : OnFailure
# Podテンプレートはここまでです
Podテンプレートを修正するか新しいPodに切り替えたとしても、すでに存在するPodには直接の影響はありません。ワークロードリソース内のPodテンプレートを変更すると、そのリソースは更新されたテンプレートを使用して代わりとなるPodを作成する必要があります。
たとえば、StatefulSetコントローラーは、各StatefulSetごとに、実行中のPodが現在のPodテンプレートに一致することを保証します。Podテンプレートを変更するためにStatefulSetを編集すると、StatefulSetは更新されたテンプレートを元にした新しいPodを作成するようになります。最終的に、すべての古いPodが新しいPodで置き換えられ、更新は完了します。
各ワークロードリソースは、Podテンプレートへの変更を処理するための独自のルールを実装しています。特にStatefulSetについて更に詳しく知りたい場合は、StatefulSetの基本チュートリアル内のアップデート戦略 を読んでください。
ノード上では、kubelet はPodテンプレートに関する詳細について監視や管理を直接行うわけではありません。こうした詳細は抽象化されています。こうした抽象化や関心の分離のおかげでシステムのセマンティクスが単純化され、既存のコードを変更せずにクラスターの動作を容易に拡張できるようになっているのです。
Podの更新と取替 前のセクションで述べたように、ワークロードリソースのPodテンプレートが変更されると、コントローラーは既存のPodを更新したりパッチを適用したりするのではなく、更新されたテンプレートに基づいて新しいPodを作成します。
KubernetesはPodを直接管理することを妨げません。実行中のPodの一部のフィールドをその場で更新することが可能です。しかし、patch
とreplace
といった、Podのアップデート操作にはいくつかの制限があります:
Podのメタデータのほとんどは固定されたものです。たとえばnamespace
、name
、uid
またはcreationTimestamp
フィールドは変更できません。generation
フィールドは特別で、現在の値を増加させる更新のみを受け付けます。
metadata.deletionTimestamp
が設定されている場合、metadata.finalizers
リストに新しい項目を追加することはできません。
Podの更新ではspec.containers[*].image
、spec.initContainers[*].image
、spec.activeDeadlineSeconds
またはspec.tolerations
以外のフィールドを変更してはなりません。
spec.tolerations
については新しい項目のみを追加することができます。
spec.activeDeadlineSeconds
フィールドを更新する場合、2種類の更新が可能です:
未割り当てのフィールドに正の数を設定する 現在の値から負の数でない、より小さい数に更新する リソースの共有と通信 Podは、データの共有と構成するコンテナ間での通信を可能にします。
Pod内のストレージ Podでは、共有ストレージであるボリューム の集合を指定できます。Pod内のすべてのコンテナは共有ボリュームにアクセスできるため、それら複数のコンテナでデータを共有できるようになります。また、ボリュームを利用すれば、Pod内のコンテナの1つに再起動が必要になった場合にも、Pod内の永続化データを保持し続けられるようにできます。Kubernetesの共有ストレージの実装方法とPodで利用できるようにする方法に関するさらに詳しい情報は、ストレージ を読んでください。
Podネットワーク 各Podには、各アドレスファミリーごとにユニークなIPアドレスが割り当てられます。Pod内のすべてのコンテナは、IPアドレスとネットワークポートを含むネットワーク名前空間を共有します。Podの中では(かつその場合にのみ )、そのPod内のコンテナはlocalhost
を使用して他のコンテナと通信できます。Podの内部にあるコンテナがPodの外部にある エンティティと通信する場合、(ポートなどの)共有ネットワークリソースの使い方をコンテナ間で調整しなければなりません。Pod内では、コンテナはIPアドレスとポートの空間を共有するため、localhost
で他のコンテナにアクセスできます。また、Pod内のコンテナは、SystemVのセマフォやPOSIXの共有メモリなど、標準のプロセス間通信を使って他のコンテナと通信することもできます。異なるPod内のコンテナは異なるIPアドレスを持つため、特別な設定をしない限り、OSレベルIPCで通信することはできません。異なるPod上で実行中のコンテナ間でやり取りをしたい場合は、IPネットワークを使用して通信できます。
Pod内のコンテナは、システムのhostnameがPodに設定したname
と同一であると考えます。ネットワークについての詳しい情報は、ネットワーク で説明しています。
コンテナの特権モード Linuxでは、Pod内のどんなコンテナも、privileged
フラグをコンテナのspecのsecurity context に設定することで、特権モード(privileged mode)を有効にできます。これは、ネットワークスタックの操作やハードウェアデバイスへのアクセスなど、オペレーティングシステムの管理者の権限が必要なコンテナの場合に役に立ちます。
WindowsHostProcessContainers
機能を有効にしたクラスターの場合、Pod仕様のsecurityContextにwindowsOptions.hostProcess
フラグを設定することで、Windows HostProcess Pod を作成することが可能です。これらのPod内のすべてのコンテナは、Windows HostProcessコンテナとして実行する必要があります。HostProcess Podはホスト上で直接実行され、Linuxの特権コンテナで行われるような管理作業を行うのにも使用できます。
備考: この設定を有効にするには、
コンテナランタイム が特権コンテナの概念をサポートしていなければなりません。
static Pod static Pod は、APIサーバー には管理されない、特定のノード上でkubeletデーモンによって直接管理されるPodのことです。大部分のPodはコントロールプレーン(たとえばDeployment )によって管理されますが、static Podの場合はkubeletが各static Podを直接管理します(障害時には再起動します)。
static Podは常に特定のノード上の1つのKubelet に紐付けられます。static Podの主な用途は、セルフホストのコントロールプレーンを実行すること、言い換えると、kubeletを使用して個別のコントロールプレーンコンポーネント を管理することです。
kubeletは自動的にKubernetes APIサーバー上に各static Podに対応するミラーPod の作成を試みます。つまり、ノード上で実行中のPodはAPIサーバー上でも見えるようになるけれども、APIサーバー上から制御はできないということです。
コンテナのProbe Probe はkubeletがコンテナに対して行う定期診断です。診断を実行するために、kubeletはさまざまなアクションを実行できます:
ExecAction
(コンテナランタイムの助けを借りて実行)TCPSocketAction
(kubeletにより直接チェック)HTTPGetAction
(kubeletにより直接チェック)更に詳しく知りたい場合は、PodのライフサイクルドキュメントにあるProbe を読んでください。
次の項目 Kubernetesが共通のPod APIを他のリソース内(たとえばStatefulSet やDeployment など)にラッピングしている理由の文脈を理解するためには、Kubernetes以前から存在する以下のような既存技術について読むのが助けになります。
4.1.1 - Podのライフサイクル このページではPodのライフサイクルについて説明します。Podは定義されたライフサイクルに従い Pending
フェーズ から始まり、少なくとも1つのプライマリーコンテナが正常に開始した場合はRunning
を経由し、次に失敗により終了したコンテナの有無に応じて、Succeeded
またはFailed
フェーズを経由します。
Podの実行中、kubeletはコンテナを再起動して、ある種の障害を処理できます。Pod内で、Kubernetesはさまざまなコンテナのステータス を追跡して、回復させるためのアクションを決定します。
Kubernetes APIでは、Podには仕様と実際のステータスの両方があります。Podオブジェクトのステータスは、PodのCondition のセットで構成されます。カスタムのReadiness情報 をPodのConditionデータに挿入することもできます。
Podはその生存期間に1回だけスケジューリング されます。PodがNodeにスケジュール(割り当て)されると、Podは停止または終了 するまでそのNode上で実行されます。
Podのライフタイム 個々のアプリケーションコンテナと同様に、Podは(永続的ではなく)比較的短期間の存在と捉えられます。Podが作成されると、一意のID(UID )が割り当てられ、(再起動ポリシーに従って)終了または削除されるまでNodeで実行されるようにスケジュールされます。ノード が停止した場合、そのNodeにスケジュールされたPodは、タイムアウト時間の経過後に削除 されます。
Pod自体は、自己修復しません。Podがnode にスケジュールされ、その後に失敗した場合、Podは削除されます。同様に、リソースの不足またはNodeのメンテナンスによりPodはNodeから立ち退きます。Kubernetesは、比較的使い捨てのPodインスタンスの管理作業を処理する、controller と呼ばれる上位レベルの抽象化を使用します。
特定のPod(UIDで定義)は新しいNodeに"再スケジュール"されません。代わりに、必要に応じて同じ名前で、新しいUIDを持つ同一のPodに置き換えることができます。
volume など、Podと同じ存続期間を持つものがあると言われる場合、それは(そのUIDを持つ)Podが存在する限り存在することを意味します。そのPodが何らかの理由で削除された場合、たとえ同じ代替物が作成されたとしても、関連するもの(例えばボリューム)も同様に破壊されて再作成されます。
Podの図 file puller(ファイル取得コンテナ)とWebサーバーを含むマルチコンテナのPod。コンテナ間の共有ストレージとして永続ボリュームを使用しています。
Podのフェーズ Podのstatus
項目はPodStatus オブジェクトで、それはphase
のフィールドがあります。
Podのフェーズは、そのPodがライフサイクルのどの状態にあるかを、簡単かつ高レベルにまとめたものです。このフェーズはコンテナやPodの状態を包括的にまとめることを目的としたものではなく、また包括的なステートマシンでもありません。
Podの各フェーズの値と意味は厳重に守られています。ここに記載されているもの以外にphase
の値は存在しないと思ってください。
これらがphase
の取りうる値です。
値 概要 Pending
PodがKubernetesクラスターによって承認されましたが、1つ以上のコンテナがセットアップされて稼働する準備ができていません。これには、スケジュールされるまでの時間と、ネットワーク経由でイメージをダウンロードするための時間などが含まれます。 Running
PodがNodeにバインドされ、すべてのコンテナが作成されました。少なくとも1つのコンテナがまだ実行されているか、開始または再起動中です。 Succeeded
Pod内のすべてのコンテナが正常に終了し、再起動されません。 Failed
Pod内のすべてのコンテナが終了し、少なくとも1つのコンテナが異常終了しました。つまり、コンテナはゼロ以外のステータスで終了したか、システムによって終了されました。 Unknown
何らかの理由によりPodの状態を取得できませんでした。このフェーズは通常はPodのホストとの通信エラーにより発生します。
備考: Podの削除中に、kubectlコマンドには
Terminating
が出力されることがあります。この
Terminating
ステータスは、Podのフェーズではありません。Podには、正常に終了するための期間を与えられており、デフォルトは30秒です。
--force
フラグを使用して、
Podを強制的に削除する ことができます。
Nodeが停止するか、クラスターの残りの部分から切断された場合、Kubernetesは失われたNode上のすべてのPodのPhase
をFailedに設定するためのポリシーを適用します。
コンテナのステータス Pod全体のフェーズ と同様に、KubernetesはPod内の各コンテナの状態を追跡します。container lifecycle hooks を使用して、コンテナのライフサイクルの特定のポイントで実行するイベントをトリガーできます。
Podがscheduler によってNodeに割り当てられると、kubeletはcontainer runtime を使用してコンテナの作成を開始します。コンテナの状態はWaiting
、Running
またはTerminated
の3ついずれかです。
Podのコンテナの状態を確認するにはkubectl describe pod [POD_NAME]
のコマンドを使用します。Pod内のコンテナごとにStateの項目として表示されます。
各状態の意味は次のとおりです。
Waiting
コンテナがRunning
またはTerminated
のいずれの状態でもない場合コンテナはWaiting
の状態になります。Waiting状態のコンテナは引き続きコンテナイメージレジストリからイメージを取得したりSecret を適用したりするなど必要な操作を実行します。Waiting
状態のコンテナを持つPodに対してkubectl
コマンドを使用すると、そのコンテナがWaiting
の状態である理由の要約が表示されます。
Running
Running
状態はコンテナが問題なく実行されていることを示します。postStart
フックが構成されていた場合、それはすでに実行が完了しています。Running
状態のコンテナを持つPodに対してkubectl
コマンドを使用すると、そのコンテナがRunning
状態になった時刻が表示されます。
Terminated
Terminated
状態のコンテナは実行されて、完了したときまたは何らかの理由で失敗したことを示します。Terminated
状態のコンテナを持つPodに対してkubectl
コマンドを使用すると、いずれにせよ理由と終了コード、コンテナの開始時刻と終了時刻が表示されます。
コンテナがTerminated
に入る前にpreStop
フックがあれば実行されます。
コンテナの再起動ポリシー Podのspec
には、Always、OnFailure、またはNeverのいずれかの値を持つrestartPolicy
フィールドがあります。デフォルト値はAlwaysです。
restartPolicy
は、Pod内のすべてのコンテナに適用されます。restartPolicy
は、同じNode上のkubeletによるコンテナの再起動のみを参照します。Pod内のコンテナが終了した後、kubeletは5分を上限とする指数バックオフ遅延(10秒、20秒、40秒...)でコンテナを再起動します。コンテナが10分間実行されると、kubeletはコンテナの再起動バックオフタイマーをリセットします。
PodのCondition PodにはPodStatusがあります。それにはPodが成功したかどうかの情報を持つPodCondition の配列が含まれています。kubeletは、下記のPodConditionを管理します:
PodScheduled
: PodがNodeにスケジュールされました。PodHasNetwork
: (アルファ版機能; 明示的に有効 にしなければならない) Podサンドボックスが正常に作成され、ネットワークの設定が完了しました。ContainersReady
: Pod内のすべてのコンテナが準備できた状態です。Initialized
: すべてのInitコンテナ が正常に終了しました。Ready
: Podはリクエストを処理でき、一致するすべてのサービスの負荷分散プールに追加されます。フィールド名 内容 type
このPodの状態の名前です。 status
その状態が適用可能かどうか示します。可能な値は"True
"、"False
"、"Unknown
"のうちのいずれかです。 lastProbeTime
Pod Conditionが最後に確認されたときのタイムスタンプが表示されます。 lastTransitionTime
最後にPodのステータスの遷移があった際のタイムスタンプが表示されます。 reason
最後の状態遷移の理由を示す、機械可読のアッパーキャメルケースのテキストです。 message
ステータスの遷移に関する詳細を示す人間向けのメッセージです。
PodのReadiness FEATURE STATE:
Kubernetes v1.14 [stable]
追加のフィードバックやシグナルをPodStatus:Pod readiness に注入できるようにします。これを使用するには、Podのspec
でreadinessGates
を設定して、kubeletがPodのReadinessを評価する追加の状態のリストを指定します。
ReadinessゲートはPodのstatus.conditions
フィールドの現在の状態によって決まります。KubernetesがPodのstatus.conditions
フィールドでそのような状態を発見できない場合、ステータスはデフォルトでFalse
になります。
以下はその例です。
Kind : Pod
...
spec :
readinessGates :
- conditionType : "www.example.com/feature-1"
status :
conditions :
- type : Ready # これはビルトインのPodCondition
status : "False"
lastProbeTime : null
lastTransitionTime : 2018-01-01T00:00:00Z
- type : "www.example.com/feature-1" # 追加のPodCondition
status : "False"
lastProbeTime : null
lastTransitionTime : 2018-01-01T00:00:00Z
containerStatuses :
- containerID : docker://abcd...
ready : true
...
PodのConditionは、Kubernetesのlabel key format に準拠している必要があります。
PodのReadinessの状態 kubectl patch
コマンドはオブジェクトステータスのパッチ適用をまだサポートしていません。Podにこれらのstatus.conditions
を設定するには、アプリケーションとoperators はPATCH
アクションを使用する必要があります。Kubernetes client library を使用して、PodのReadinessのためにカスタムのPodのConditionを設定するコードを記述できます。
カスタムのPodのConditionが導入されるとPodは次の両方の条件に当てはまる場合のみ 準備できていると評価されます:
Pod内のすべてのコンテナが準備完了している。 ReadinessGates
で指定された条件が全てTrue
である。Podのコンテナは準備完了ですが、少なくとも1つのカスタムのConditionが欠落しているか「False」の場合、kubeletはPodのCondition をContainersReady
に設定します。
PodのネットワークのReadiness FEATURE STATE:
Kubernetes v1.25 [alpha]
Podがノードにスケジュールされた後、kubeletによって承認され、任意のボリュームがマウントされる必要があります。これらのフェーズが完了すると、kubeletはコンテナランタイム(コンテナランタイムインターフェース(CRI) を使用)と連携して、ランタイムサンドボックスのセットアップとPodのネットワークを構成します。もしPodHasNetworkCondition
フィーチャーゲート が有効になっている場合、kubeletは、Podがこの初期化の節目に到達したかどうかをPodのstatus.conditions
フィールドにあるPodHasNetwork
状態を使用して報告します。
ネットワークが設定されたランタイムサンドボックスがPodにないことを検出すると、PodHasNetwork
状態は、kubelet によってFalse
に設定されます。これは、以下のシナリオで発生します:
Podのライフサイクルの初期で、kubeletがコンテナランタイムを使用してPodのサンドボックスのセットアップをまだ開始していないとき Podのライフサイクルの後期で、Podのサンドボックスが以下のどちらかの原因で破壊された場合:Podを退去させず、ノードが再起動する コンテナランタイムの隔離に仮想マシンを使用している場合、Podサンドボックスの仮想マシンが再起動し、新しいサンドボックスと新しいコンテナネットワーク設定を作成する必要があります ランタイムプラグインによるサンドボックスの作成とPodのネットワーク設定が正常に完了すると、kubeletによってPodHasNetwork
状態がTrue
に設定されます。PodHasNetwork
状態がTrue
に設定された後、kubeletはコンテナイメージの取得とコンテナの作成を開始することができます。
initコンテナを持つPodの場合、initコンテナが正常に完了すると(ランタイムプラグインによるサンドボックスの作成とネットワーク設定が正常に行われた後に発生)、kubeletはInitialized
状態をTrue
に設定します。initコンテナがないPodの場合、サンドボックスの作成およびネットワーク設定が開始する前にkubeletはInitialized
状態をTrue
に設定します。
コンテナのProbe Probe はkubelet により定期的に実行されるコンテナの診断です。診断を行うために、kubeletはコンテナ内でコードを実行するか、ネットワークリクエストします。
チェックのメカニズム probeを使ってコンテナをチェックする4つの異なる方法があります。
各probeは、この4つの仕組みのうち1つを正確に定義する必要があります:
exec
コンテナ内で特定のコマンドを実行します。コマンドがステータス0で終了した場合に診断を成功と見なします。 grpc
gRPC を使ってリモートプロシージャコールを実行します。
ターゲットは、gRPC health checks を実装する必要があります。
レスポンスのstatus
がSERVING
の場合に診断を成功と見なします。
gRPCはアルファ版の機能のため、GRPCContainerProbe
フィーチャーゲート が
有効の場合のみ利用可能です。httpGet
PodのIPアドレスに対して、指定されたポートとパスでHTTP GET
のリクエストを送信します。
レスポンスのステータスコードが200以上400未満の際に診断を成功とみなします。 tcpSocket
PodのIPアドレスに対して、指定されたポートでTCPチェックを行います。
そのポートが空いていれば診断を成功とみなします。
オープンしてすぐにリモートシステム(コンテナ)が接続を切断した場合、健全な状態としてカウントします。 Probeの結果 各Probe 次の3つのうちの一つの結果を持ちます:
Success
コンテナの診断が成功しました。 Failure
コンテナの診断が失敗しました。 Unknown
コンテナの診断自体が失敗しました(何も実行する必要はなく、kubeletはさらにチェックを行います)。 Probeの種類 kubeletは3種類のProbeを実行中のコンテナで行い、また反応することができます:
livenessProbe
コンテナが動いているかを示します。
livenessProbeに失敗すると、kubeletはコンテナを殺します、そしてコンテナはrestart policy に従います。
コンテナにlivenessProbeが設定されていない場合、デフォルトの状態はSuccess
です。 readinessProbe
コンテナがリクエスト応答する準備ができているかを示します。
readinessProbeに失敗すると、エンドポイントコントローラーにより、ServiceからそのPodのIPアドレスが削除されます。
initial delay前のデフォルトのreadinessProbeの初期値はFailure
です。
コンテナにreadinessProbeが設定されていない場合、デフォルトの状態はSuccess
です。 startupProbe
コンテナ内のアプリケーションが起動したかどうかを示します。
startupProbeが設定された場合、完了するまでその他のすべてのProbeは無効になります。
startupProbeに失敗すると、kubeletはコンテナを殺します、そしてコンテナはrestart policy に従います。
コンテナにstartupProbeが設定されていない場合、デフォルトの状態はSuccess
です。 livenessProbe、readinessProbeまたはstartupProbeを設定する方法の詳細については、Liveness Probe、Readiness ProbeおよびStartup Probeを使用する を参照してください。
livenessProbeをいつ使うべきか? FEATURE STATE:
Kubernetes v1.0 [stable]
コンテナ自体に問題が発生した場合や状態が悪くなった際にクラッシュすることができればlivenessProbeは不要です。
この場合kubeletが自動でPodのrestartPolicy
に基づいたアクションを実行します。
Probeに失敗したときにコンテナを殺したり再起動させたりするには、livenessProbeを設定しrestartPolicy
をAlwaysまたはOnFailureにします。
readinessProbeをいつ使うべきか? FEATURE STATE:
Kubernetes v1.0 [stable]
Probeが成功したときにのみPodにトラフィックを送信したい場合は、readinessProbeを指定します。
この場合readinessProbeはlivenessProbeと同じになる可能性がありますが、readinessProbeが存在するということは、Podがトラフィックを受けずに開始され、Probe成功が開始した後でトラフィックを受け始めることになります。
コンテナがメンテナンスのために停止できるようにするには、livenessProbeとは異なる、特定のエンドポイントを確認するreadinessProbeを指定することができます。
アプリがバックエンドサービスと厳密な依存関係にある場合、livenessProbeとreadinessProbeの両方を実装することができます。アプリ自体が健全であればlivenessProbeはパスしますが、readinessProbeはさらに、必要なバックエンドサービスが利用可能であるかどうかをチェックします。これにより、エラーメッセージでしか応答できないPodへのトラフィックの転送を避けることができます。
コンテナの起動中に大きなデータ、構成ファイル、またはマイグレーションを読み込む必要がある場合は、startupProbe を使用できます。ただし、失敗したアプリと起動データを処理中のアプリの違いを検出したい場合は、readinessProbeを使用した方が良いかもしれません。
備考: Podが削除されたときにリクエストを来ないようにするためには必ずしもreadinessProbeが必要というわけではありません。Podの削除時にはreadinessProbeが存在するかどうかに関係なくPodは自動的に自身をunreadyにします。Pod内のコンテナが停止するのを待つ間Podはunreadyのままです。startupProbeをいつ使うべきか? FEATURE STATE:
Kubernetes v1.20 [stable]
startupProbeは、サービスの開始に時間がかかるコンテナを持つPodに役立ちます。livenessProbeの間隔を長く設定するのではなく、コンテナの起動時に別のProbeを構成して、livenessProbeの間隔よりも長い時間を許可できます。
コンテナの起動時間が、initialDelaySeconds + failureThreshold x periodSeconds
よりも長い場合は、livenessProbeと同じエンドポイントをチェックするためにstartupProbeを指定します。periodSeconds
のデフォルトは10秒です。次に、failureThreshold
をlivenessProbeのデフォルト値を変更せずにコンテナが起動できるように、十分に高い値を設定します。これによりデッドロックを防ぐことができます。
Podの終了 Podは、クラスター内のNodeで実行中のプロセスを表すため、不要になったときにそれらのプロセスを正常に終了できるようにすることが重要です(対照的なケースは、KILLシグナルで強制終了され、クリーンアップする機会がない場合)。
ユーザーは削除を要求可能であるべきで、プロセスがいつ終了するかを知ることができなければなりませんが、削除が最終的に完了することも保証できるべきです。ユーザーがPodの削除を要求すると、システムはPodが強制終了される前に意図された猶予期間を記録および追跡します。強制削除までの猶予期間がある場合、kubelet 正常な終了を試みます。
通常、コンテナランタイムは各コンテナのメインプロセスにTERMシグナルを送信します。多くのコンテナランタイムは、コンテナイメージで定義されたSTOPSIGNAL値を尊重し、TERMシグナルの代わりにこれを送信します。猶予期間が終了すると、プロセスにKILLシグナルが送信され、PodはAPI server から削除されます。プロセスの終了を待っている間にkubeletかコンテナランタイムの管理サービスが再起動されると、クラスターは元の猶予期間を含めて、最初からリトライされます。
フローの例は下のようになります。
ユーザーがデフォルトの猶予期間(30秒)でPodを削除するためにkubectl
コマンドを送信する。 API server内のPodは、猶予期間を越えるとPodが「死んでいる」と見なされるように更新される。 削除中のPodに対してkubectl describe
コマンドを使用すると、Podは「終了中」と表示される。 Podが実行されているNode上で、Podが終了しているとマークされている(正常な終了期間が設定されている)とkubeletが認識するとすぐに、kubeletはローカルでPodの終了プロセスを開始します。Pod内のコンテナの1つがpreStop
フック を定義している場合は、コンテナの内側で呼び出される。猶予期間が終了した後もpreStop
フックがまだ実行されている場合は、一度だけ猶予期間を延長される(2秒)。
備考: preStop
フックが完了するまでにより長い時間が必要な場合は、terminationGracePeriodSeconds
を変更する必要があります。 kubeletはコンテナランタイムをトリガーして、コンテナ内のプロセス番号1にTERMシグナルを送信する。
備考: Pod内のすべてのコンテナが同時にTERMシグナルを受信するわけではなく、シャットダウンの順序が問題になる場合はそれぞれにpreStop
フックを使用して同期することを検討する。 kubeletが正常な終了を開始すると同時に、コントロールプレーンは、終了中のPodをEndpointSlice(およびEndpoints)オブジェクトから削除します。これらのオブジェクトは、selector が設定されたService を表します。ReplicaSets とその他のワークロードリソースは、終了中のPodを有効なサービス中のReplicaSetとして扱いません。ゆっくりと終了するPodは、(サービスプロキシのような)ロードバランサーが終了猶予期間が始まる とエンドポイントからそれらのPodを削除するので、トラフィックを継続して処理できません。 猶予期間が終了すると、kubeletは強制削除を開始する。コンテナランタイムは、Pod内でまだ実行中のプロセスにSIGKILL
を送信する。kubeletは、コンテナランタイムが非表示のpause
コンテナを使用している場合、そのコンテナをクリーンアップします。 kubeletは猶予期間を0(即時削除)に設定することでAPI server上のPodの削除を終了する。 API serverはPodのAPIオブジェクトを削除し、クライアントからは見えなくなります。 Podの強制削除
注意: 強制削除は、Podによっては潜在的に危険な場合があるため、慎重に実行する必要があります。デフォルトでは、すべての削除は30秒以内に正常に行われます。kubectl delete
コマンドは、ユーザーがデフォルト値を上書きして独自の値を指定できるようにする --grace-period=<seconds>
オプションをサポートします。
--grace-period
を0
に設定した場合、PodはAPI serverから即座に強制的に削除されます。PodがNode上でまだ実行されている場合、その強制削除によりkubeletがトリガーされ、すぐにクリーンアップが開始されます。
備考: 強制削除を実行するために --grace-period=0
と共に --force
というフラグを追加で指定する必要があります。強制削除が実行されると、API serverは、Podが実行されていたNode上でPodが停止されたというkubeletからの確認を待ちません。API内のPodは直ちに削除されるため、新しいPodを同じ名前で作成できるようになります。Node上では、すぐに終了するように設定されるPodは、強制終了される前にわずかな猶予期間が与えられます。
注意: 即時削除では、実行中のリソースの終了を待ちません。
リソースはクラスター上で無期限に実行し続ける可能性があります。StatefulSetのPodについては、StatefulSetからPodを削除するためのタスクのドキュメント を参照してください。
終了したPodのガベージコレクション 失敗したPodは人間またはcontroller が明示的に削除するまで存在します。
コントロールプレーンは終了状態のPod(SucceededまたはFailedのphase
を持つ)の数が設定された閾値(kube-controller-manager内のterminated-pod-gc-threshold
によって定義される)を超えたとき、それらのPodを削除します。これはPodが作成されて時間とともに終了するため、リソースリークを避けます。
次の項目 4.1.2 - Initコンテナ このページでは、Initコンテナについて概観します。Initコンテナとは、Pod 内でアプリケーションコンテナの前に実行される特別なコンテナです。
Initコンテナにはアプリケーションコンテナのイメージに存在しないセットアップスクリプトやユーティリティーを含めることができます。
Initコンテナは、Podの仕様のうちcontainers
という配列(これがアプリケーションコンテナを示します)と並べて指定します。
Initコンテナを理解する 単一のPod は、Pod内にアプリケーションを実行している複数のコンテナを持つことができますが、同様に、アプリケーションコンテナが起動する前に実行されるInitコンテナも1つ以上持つことができます。
Initコンテナは下記の項目をのぞいて、通常のコンテナと全く同じものとなります。
Initコンテナは常に完了するまで稼働します。 各Initコンテナは、次のInitコンテナが稼働する前に正常に完了しなくてはなりません。 もしあるPodの単一のInitコンテナが失敗した場合、Kubeletは成功するまで何度もそのInitコンテナを再起動します。しかし、もしそのPodのrestartPolicy
がNeverで、そのPodの起動時にInitコンテナが失敗した場合、KubernetesはそのPod全体を失敗として扱います。
PodにInitコンテナを指定するためには、Podの仕様 にinitContainers
フィールドをcontainer
アイテムの配列として追加してください(アプリケーションのcontainers
フィールドとそのコンテンツに似ています)。
詳細については、APIリファレンスのContainer を参照してください。
Initコンテナのステータスは、.status.initContainerStatuses
フィールドにコンテナのステータスの配列として返されます(.status.containerStatuses
と同様)。
通常のコンテナとの違い Initコンテナは、リソースリミット、ボリューム、セキュリティ設定などのアプリケーションコンテナの全てのフィールドと機能をサポートしています。しかし、Initコンテナに対するリソースリクエストやリソースリミットの扱いは異なります。リソース にて説明します。
また、InitコンテナはそのPodの準備ができる前に完了しなくてはならないため、lifecycle
、livenessProbe
、readinessProbe
およびstartupProbe
をサポートしていません。
複数のInitコンテナを単一のPodに対して指定した場合、KubeletはそれらのInitコンテナを1つずつ順番に実行します。各Initコンテナは、次のInitコンテナが稼働する前に正常終了しなくてはなりません。全てのInitコンテナの実行が完了すると、KubeletはPodのアプリケーションコンテナを初期化し、通常通り実行します。
Initコンテナを使用する Initコンテナはアプリケーションコンテナのイメージとは分離されているため、コンテナの起動に関連したコードにおいていくつかの利点があります。
Initコンテナはアプリケーションのイメージに存在しないセットアップ用のユーティリティーやカスタムコードを含むことができます。例えば、セットアップ中にsed
、awk
、python
や、dig
のようなツールを使うためだけに、別のイメージを元にしてアプリケーションイメージを作る必要がなくなります。 アプリケーションイメージをビルドする役割とデプロイする役割は、共同で単一のアプリケーションイメージをビルドする必要がないため、それぞれ独立して実施することができます。 Initコンテナは同一Pod内のアプリケーションコンテナと別のファイルシステムビューで稼働することができます。その結果、アプリケーションコンテナがアクセスできないSecret に対するアクセス権限を得ることができます。 Initコンテナはアプリケーションコンテナが開始する前に完了するまで実行されるため、Initコンテナを使用することで、特定の前提条件が満たされるまでアプリケーションコンテナの起動をブロックしたり遅らせることができます。前提条件が満たされると、Pod内の全てのアプリケーションコンテナを並行して起動することができます。 Initコンテナはアプリケーションコンテナイメージの安全性を低下させるようなユーティリティーやカスタムコードを安全に実行することができます。不必要なツールを分離しておくことで、アプリケーションコンテナイメージのアタックサーフィスを制限することができます。 例 Initコンテナを活用する方法について、いくつかのアイデアを次に示します。
シェルコマンドを使って単一のService が作成されるのを待機する。
for i in { 1..100} ; do sleep 1; if nslookup myservice; then exit 0; fi ; done ; exit 1
以下のようなコマンドを使って下位のAPIからPodの情報をリモートサーバに登録する。
curl -X POST http://$MANAGEMENT_SERVICE_HOST :$MANAGEMENT_SERVICE_PORT /register -d 'instance=$(<POD_NAME>)&ip=$(<POD_IP>)'
以下のようなコマンドを使ってアプリケーションコンテナの起動を待機する。
gitリポジトリをVolume にクローンする。
いくつかの値を設定ファイルに配置し、メインのアプリケーションコンテナのための設定ファイルを動的に生成するためのテンプレートツールを実行する。例えば、そのPodのPOD_IP
の値を設定ファイルに配置し、Jinjaを使ってメインのアプリケーションコンテナの設定ファイルを生成する。
Initコンテナの具体的な使用方法 下記の例は2つのInitコンテナを含むシンプルなPodを定義しています。
1つ目のInitコンテナはmyservies
の起動を、2つ目のInitコンテナはmydb
の起動をそれぞれ待ちます。両方のInitコンテナの実行が完了すると、Podはspec
セクションにあるアプリケーションコンテナを実行します。
apiVersion : v1
kind : Pod
metadata :
name : myapp-pod
labels :
app.kubernetes.io/name : MyApp
spec :
containers :
- name : myapp-container
image : busybox:1.28
command : ['sh' , '-c' , 'echo The app is running! && sleep 3600' ]
initContainers :
- name : init-myservice
image : busybox:1.28
command : ['sh' , '-c' , "until nslookup myservice.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local; do echo waiting for myservice; sleep 2; done" ]
- name : init-mydb
image : busybox:1.28
command : ['sh' , '-c' , "until nslookup mydb.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local; do echo waiting for mydb; sleep 2; done" ]
次のコマンドを実行して、このPodを開始できます。
kubectl apply -f myapp.yaml
実行結果は下記のようになります。
pod/myapp-pod created
そして次のコマンドでステータスを確認します。
kubectl get -f myapp.yaml
実行結果は下記のようになります。
NAME READY STATUS RESTARTS AGE
myapp-pod 0/1 Init:0/2 0 6m
より詳細な情報は次のコマンドで確認します。
kubectl describe -f myapp.yaml
実行結果は下記のようになります。
Name: myapp-pod
Namespace: default
[...]
Labels: app.kubernetes.io/name=MyApp
Status: Pending
[...]
Init Containers:
init-myservice:
[...]
State: Running
[...]
init-mydb:
[...]
State: Waiting
Reason: PodInitializing
Ready: False
[...]
Containers:
myapp-container:
[...]
State: Waiting
Reason: PodInitializing
Ready: False
[...]
Events:
FirstSeen LastSeen Count From SubObjectPath Type Reason Message
--------- -------- ----- ---- ------------- -------- ------ -------
16s 16s 1 {default-scheduler } Normal Scheduled Successfully assigned myapp-pod to 172.17.4.201
16s 16s 1 {kubelet 172.17.4.201} spec.initContainers{init-myservice} Normal Pulling pulling image "busybox"
13s 13s 1 {kubelet 172.17.4.201} spec.initContainers{init-myservice} Normal Pulled Successfully pulled image "busybox"
13s 13s 1 {kubelet 172.17.4.201} spec.initContainers{init-myservice} Normal Created Created container with docker id 5ced34a04634; Security:[seccomp=unconfined]
13s 13s 1 {kubelet 172.17.4.201} spec.initContainers{init-myservice} Normal Started Started container with docker id 5ced34a04634
このPod内のInitコンテナのログを確認するためには、次のコマンドを実行します。
kubectl logs myapp-pod -c init-myservice # 1つ目のInitコンテナを調査する
kubectl logs myapp-pod -c init-mydb # 2つ目のInitコンテナを調査する
この時点で、これらのInitコンテナはmydb
とmyservice
という名前のServiceの検出を待機しています。
これらのServiceを検出させるための構成は以下の通りです。
---
apiVersion : v1
kind : Service
metadata :
name : myservice
spec :
ports :
- protocol : TCP
port : 80
targetPort : 9376
---
apiVersion : v1
kind : Service
metadata :
name : mydb
spec :
ports :
- protocol : TCP
port : 80
targetPort : 9377
mydb
およびmyservice
というServiceを作成するために、以下のコマンドを実行します。
kubectl apply -f services.yaml
実行結果は下記のようになります。
service/myservice created
service/mydb created
Initコンテナが完了し、myapp-pod
というPodがRunning状態に移行したことが確認できます。
kubectl get -f myapp.yaml
実行結果は下記のようになります。
NAME READY STATUS RESTARTS AGE
myapp-pod 1/1 Running 0 9m
このシンプルな例を独自のInitコンテナを作成する際の参考にしてください。次の項目 にさらに詳細な使用例に関するリンクがあります。
Initコンテナのふるまいに関する詳細 Podの起動時に、kubeletはネットワークおよびストレージの準備が整うまで、Initコンテナを実行可能な状態にしません。また、kubeletはPodのspecに定義された順番に従ってPodのInitコンテナを起動します。
各Initコンテナは次のInitコンテナが起動する前に正常に終了しなくてはなりません。もしあるInitコンテナがランタイムにより起動失敗した場合、もしくはエラーで終了した場合、そのPodのrestartPolicy
の値に従ってリトライされます。しかし、もしPodのrestartPolicy
がAlways
に設定されていた場合、InitコンテナのrestartPolicy
はOnFailure
が適用されます。
Podは全てのInitコンテナが完了するまでReady
状態となりません。Initコンテナ上のポートはServiceによって集約されません。初期化中のPodのステータスはPending
となりますが、Initialized
という値はtrueとなります。
もしそのPodを再起動 するとき、または再起動されたとき、全てのInitコンテナは必ず再度実行されます。
Initコンテナの仕様の変更は、コンテナイメージのフィールドのみに制限されています。
Initコンテナのイメージフィールド値を変更すると、そのPodは再起動されます。
Initコンテナは何度も再起動、リトライおよび再実行可能なため、べき等(Idempotent)である必要があります。特に、EmptyDirs
にファイルを書き込むコードは、書き込み先のファイルがすでに存在している可能性を考慮に入れる必要があります。
Initコンテナはアプリケーションコンテナの全てのフィールドを持っています。しかしKubernetesは、Initコンテナが完了と異なる状態を定義できないためreadinessProbe
が使用されることを禁止しています。これはバリデーションの際に適用されます。
Initコンテナがずっと失敗し続けたままの状態を防ぐために、PodにactiveDeadlineSeconds
を設定してください。activeDeadlineSeconds
の設定はInitコンテナが実行中の時間にも適用されます。しかしactiveDeadlineSeconds
はInitコンテナが終了した後でも効果があるため、チームがアプリケーションをJobとしてデプロイする場合にのみ使用することが推奨されています。
すでに正しく動作しているPodはactiveDeadlineSeconds
を設定すると強制終了されます。
Pod内の各アプリケーションコンテナとInitコンテナの名前はユニークである必要があります。他のコンテナと同じ名前を共有していた場合、バリデーションエラーが返されます。
リソース Initコンテナの順序と実行を考えるとき、リソースの使用に関して下記のルールが適用されます。
全てのInitコンテナの中で定義された最も高いリソースリクエストとリソースリミットが、有効なinitリクエスト/リミット になります。いずれかのリソースでリミットが設定されていない場合、これが最上級のリミットとみなされます。 Podのリソースの有効なリクエスト/リミット は、下記の2つの中のどちらか高い方となります。リソースに対する全てのアプリケーションコンテナのリクエスト/リミットの合計 リソースに対する有効なinitリクエスト/リミット スケジューリングは有効なリクエスト/リミットに基づいて実行されます。つまり、InitコンテナはPodの生存中には使用されない初期化用のリソースを確保することができます。 Podの有効なQoS(quality of service)ティアー は、Initコンテナとアプリケーションコンテナで同様です。 クォータとリミットは有効なPodリクエストとリミットに基づいて適用されます。
Podレベルのコントロールグループ(cgroups)は、スケジューラーと同様に、有効なPodリクエストとリミットに基づいています。
Podの再起動の理由 以下の理由によりPodは再起動し、Initコンテナの再実行も引き起こす可能性があります。
そのPodのインフラストラクチャーコンテナが再起動された場合。これはあまり起きるものでなく、Nodeに対するルート権限を持ったユーザーにより行われることがあります。 restartPolicy
がAlways
と設定されているPod内の全てのコンテナが停止され、強制的に再起動が行われたことで、ガベージコレクションによりInitコンテナの完了記録が失われた場合。Kubernetes v1.20以降では、initコンテナのイメージが変更されたり、ガベージコレクションによってinitコンテナの完了記録が失われたりした場合でも、Podは再起動されません。以前のバージョンを使用している場合は、対応バージョンのドキュメントを参照してください。
次の項目 4.1.3 - サイドカーコンテナ FEATURE STATE:
Kubernetes v1.29 [beta]
サイドカーコンテナは、メインのアプリケーションコンテナと同じPod 内で実行されるセカンダリーコンテナです。
これらのコンテナは、主要なアプリケーションコードを直接変更することなく、ロギング、モニタリング、セキュリティ、データの同期などの追加サービスや機能を提供することにより、アプリケーションコンテナの機能を強化または拡張するために使用されます。
サイドカーコンテナの有効化 Kubernetes 1.29でデフォルトで有効化されたSidecarContainers
という名前の フィーチャーゲート により、
PodのinitContainers
フィールドに記載されているコンテナのrestartPolicy
を指定することができます。
これらの再起動可能な サイドカー コンテナは、同じポッド内の他のinitコンテナ やメインのアプリケーションコンテナとは独立しています。
これらは、メインアプリケーションコンテナや他のinitコンテナに影響を与えることなく、開始、停止、または再起動することができます。
サイドカーコンテナとPodのライフサイクル もしinitコンテナがrestartPolicy
をAlways
に設定して作成された場合、それはPodのライフサイクル全体にわたって起動し続けます。
これは、メインアプリケーションコンテナから分離されたサポートサービスを実行するのに役立ちます。
このinitコンテナにreadinessProbe
が指定されている場合、その結果はPodのready
状態を決定するために使用されます。
これらのコンテナはinitコンテナとして定義されているため、他のinitコンテナと同様に順序に関する保証を受けることができ、複雑なPodの初期化フローに他のinitコンテナと混在させることができます。
通常のinitコンテナと比較して、initContainers
内で定義されたサイドカーは、開始した後も実行を続けます。
これは、.spec.initContainers
にPod用の複数のエントリーがある場合に重要です。
サイドカースタイルのinitコンテナが実行中になった後(kubeletがそのinitコンテナのstarted
ステータスをtrueに設定した後)、kubeletは順序付けられた.spec.initContainers
リストから次のinitコンテナを開始します。
そのステータスは、コンテナ内でプロセスが実行されておりStartup Probeが定義されていない場合、あるいはそのstartupProbe
が成功するとtrueになります。
以下は、サイドカーを含む2つのコンテナを持つDeploymentの例です:
apiVersion : apps/v1
kind : Deployment
metadata :
name : myapp
labels :
app : myapp
spec :
replicas : 1
selector :
matchLabels :
app : myapp
template :
metadata :
labels :
app : myapp
spec :
containers :
- name : myapp
image : alpine:latest
command : ['sh' , '-c' , 'while true; do echo "logging" >> /opt/logs.txt; sleep 1; done' ]
volumeMounts :
- name : data
mountPath : /opt
initContainers :
- name : logshipper
image : alpine:latest
restartPolicy : Always
command : ['sh' , '-c' , 'tail -F /opt/logs.txt' ]
volumeMounts :
- name : data
mountPath : /opt
volumes :
- name : data
emptyDir : {}
この機能は、サイドカーコンテナがメインコンテナが終了した後もジョブが完了するのを妨げないため、サイドカーを持つジョブを実行するのにも役立ちます。
以下は、サイドカーを含む2つのコンテナを持つJobの例です:
apiVersion : batch/v1
kind : Job
metadata :
name : myjob
spec :
template :
spec :
containers :
- name : myjob
image : alpine:latest
command : ['sh' , '-c' , 'echo "logging" > /opt/logs.txt' ]
volumeMounts :
- name : data
mountPath : /opt
initContainers :
- name : logshipper
image : alpine:latest
restartPolicy : Always
command : ['sh' , '-c' , 'tail -F /opt/logs.txt' ]
volumeMounts :
- name : data
mountPath : /opt
restartPolicy : Never
volumes :
- name : data
emptyDir : {}
通常のコンテナとの違い サイドカーコンテナは、同じPod内の通常のコンテナと並行して実行されます。
しかし、主要なアプリケーションロジックを実行するわけではなく、メインのアプリケーションにサポート機能を提供します。
サイドカーコンテナは独自の独立したライフサイクルを持っています。
通常のコンテナとは独立して開始、停止、再起動することができます。
これは、メインアプリケーションに影響を与えることなく、サイドカーコンテナを更新、スケール、メンテナンスできることを意味します。
サイドカーコンテナは、メインのコンテナと同じネットワークおよびストレージの名前空間を共有します。
このような配置により、密接に相互作用し、リソースを共有することができます。
initコンテナとの違い サイドカーコンテナは、メインのコンテナと並行して動作し、その機能を拡張し、追加サービスを提供します。
サイドカーコンテナは、メインアプリケーションコンテナと並行して実行されます。
Podのライフサイクル全体を通じてアクティブであり、メインコンテナとは独立して開始および停止することができます。
Initコンテナ とは異なり、サイドカーコンテナはライフサイクルを制御するためのProbe をサポートしています。
これらのコンテナは、メインアプリケーションコンテナと直接相互作用することができ、同じネットワーク名前空間、ファイルシステム、環境変数を共有します。追加の機能を提供するために緊密に連携して動作します。
コンテナ内のリソース共有 Initコンテナ、サイドカーコンテナ、アプリケーションコンテナの順序と実行を考えるとき、リソースの使用に関して下記のルールが適用されます。
全てのInitコンテナの中で定義された最も高いリソースリクエストとリソースリミットが、有効なinitリクエスト/リミット になります。いずれかのリソースでリミットが設定されていない場合、これが最上級のリミットとみなされます。 Podのリソースの有効なリクエスト/リミット は、Podのオーバーヘッド と次のうち大きい方の合計になります。リソースに対する全てのアプリケーションコンテナとサイドカーコンテナのリクエスト/リミットの合計 リソースに対する有効なinitリクエスト/リミット スケジューリングは有効なリクエスト/リミットに基づいて実行されます。つまり、InitコンテナはPodの生存中には使用されない初期化用のリソースを確保することができます。 Podの有効なQoS(quality of service)ティアー は、Initコンテナ、サイドカーコンテナ、アプリケーションコンテナで同様です。 クォータとリミットは有効なPodリクエストとリミットに基づいて適用されます。
Podレベルのコントロールグループ(cgroups)は、スケジューラーと同様に、有効なPodリクエストとリミットに基づいています。
次の項目 4.1.4 - Disruption このガイドは、高可用性アプリケーションを構築したいと考えており、そのために、Podに対してどのような種類のDisruptionが発生する可能性があるか理解する必要がある、アプリケーション所有者を対象としたものです。
また、クラスターのアップグレードやオートスケーリングなどのクラスターの操作を自動化したいクラスター管理者も対象にしています。
自発的なDisruptionと非自発的なDisruption Podは誰か(人やコントローラー)が破壊するか、避けることができないハードウェアまたはシステムソフトウェアエラーが発生するまで、消えることはありません。
これらの不可避なケースをアプリケーションに対する非自発的なDisruption と呼びます。
例えば:
ノードのバックエンドの物理マシンのハードウェア障害 クラスター管理者が誤ってVM(インスタンス)を削除した クラウドプロバイダーまたはハイパーバイザーの障害によってVMが消えた カーネルパニック クラスターネットワークパーティションが原因でクラスターからノードが消えた ノードのリソース不足 によるPodの退避 リソース不足を除いて、これら条件は全て、大半のユーザーにとって馴染みのあるものでしょう。
これらはKubernetesに固有のものではありません。
それ以外のケースのことを自発的なDisruption と呼びます。
これらはアプリケーションの所有者によって起こされたアクションと、クラスター管理者によって起こされたアクションの両方を含みます。
典型的なアプリケーションの所有者によるアクションには次のものがあります:
Deploymentやその他のPodを管理するコントローラーの削除 再起動を伴うDeployment内のPodのテンプレートの更新 Podの直接削除(例:アクシデントによって) クラスター管理者のアクションには、次のようなものが含まれます:
修復やアップグレードのためのノードのドレイン 。 クラスターのスケールダウンのためにクラスターからノードをドレインする(クラスター自動スケーリング について学ぶ)。 そのノードに別のものを割り当てることができるように、ノードからPodを削除する。 これらのアクションはクラスター管理者によって直接実行されるか、クラスター管理者やクラスターをホスティングしているプロバイダーによって自動的に実行される可能性があります。
クラスターに対して自発的なDisruptionの要因となるものが有効になっているかどうかについては、クラスター管理者に聞くか、クラウドプロバイダーに相談または配布文書を参照してください。
有効になっているものが何もなければ、Pod Disruption Budgetの作成はスキップすることができます。
注意: 全ての自発的なDisruptionがPod Disruption Budgetによる制約を受けるわけではありません。
例えばDeploymentやPodの削除はPod Disruption Budgetをバイパスします。Disruptionへの対応 非自発的なDisruptionを軽減する方法をいくつか紹介します:
Podは必要なリソースを要求 するようにする。 高可用性が必要な場合はアプリケーションをレプリケートする。(レプリケートされたステートレス およびステートフル アプリケーションの実行について学ぶ。) レプリケートされたアプリケーションを実行する際にさらに高い可用性を得るには、(アンチアフィニティ を使って)ラックを横断して、または(マルチゾーンクラスター を使用している場合には)ゾーンを横断してアプリケーションを分散させる。 自発的なDisruptionの頻度は様々です。
基本的なKubernetesクラスターでは、自動で発生する自発的なDisruptionはありません(ユーザーによってトリガーされたものだけです)。
しかし、クラスター管理者やホスティングプロバイダーが何か追加のサービスを実行して自発的なDisruptionが発生する可能性があります。
例えば、ノード上のソフトウェアアップデートのロールアウトは自発的なDisruptionの原因となります。
また、クラスター(ノード)自動スケーリングの実装の中には、ノードのデフラグとコンパクト化のために自発的なDisruptionを伴うものがあります。
クラスタ管理者やホスティングプロバイダーは、自発的なDisruptionがある場合、どの程度のDisruptionが予想されるかを文書化しているはずです。
Podのspecの中でPriorityClassesを使用している 場合など、特定の設定オプションによっても自発的(および非自発的)なDisruptionを引き起こす可能性があります。
Pod Disruption Budget FEATURE STATE:
Kubernetes v1.21 [stable]
Kubernetesは、自発的なDisruptionが頻繁に発生する場合でも、可用性の高いアプリケーションの運用を支援する機能を提供しています。
アプリケーションの所有者として、各アプリケーションに対してPodDisruptionBudget (PDB)を作成することができます。
PDBは、レプリカを持っているアプリケーションのうち、自発的なDisruptionによって同時にダウンするPodの数を制限します。
例えば、クォーラムベースのアプリケーションでは、実行中のレプリカの数がクォーラムに必要な数を下回らないようにする必要があります。
Webフロントエンドは、負荷に対応するレプリカの数が、全体に対して一定の割合を下回らないようにしたいかもしれません。
クラスター管理者やホスティングプロバイダーは、直接PodやDeploymentを削除するのではなく、Eviction API を呼び出す、PodDisruptionBudgetsに配慮したツールを使用すべきです。
例えば、kubectl drain
サブコマンドはノードを休止中とマークします。
kubectl drain
を実行すると、ツールは休止中としたノード上の全てのPodを退避しようとします。
kubectl
があなたの代わりに送信する退避要求は一時的に拒否される可能性があるため、ツールは対象のノード上の全てのPodが終了するか、設定可能なタイムアウト時間に達するまで、全ての失敗した要求を定期的に再試行します。
PDBはアプリケーションの意図したレプリカ数に対して、許容できるレプリカの数を指定します。
例えば.spec.replicas: 5
を持つDeploymentは常に5つのPodを持つことが想定されます。
PDBが同時に4つまでを許容する場合、Eviction APIは1度に(2つではなく)1つのPodの自発的なDisruptionを許可します。
アプリケーションを構成するPodのグループは、アプリケーションのコントローラー(Deployment、StatefulSetなど)が使用するものと同じラベルセレクターを使用して指定されます。
"意図した"Podの数は、これらのPodを管理するワークロードリソースの.spec.replicas
から計算されます。
コントロールプレーンはPodの.metadata.ownerReferences
を調べることで、所有しているワークロードリソースを見つけます。
非自発的なDisruption はPDBによって防ぐことができません;
しかし、予算にはカウントされます。
アプリケーションのローリングアップデートによって削除または利用できなくなったPodはDisruptionの予算にカウントされますが、ローリングアップグレードを実行している時は(DeploymentやStatefulSetなどの)ワークロードリソースはPDBによって制限されません。
代わりに、アプリケーションのアップデート中の障害のハンドリングは、個々のワークロードリソースに対するspecで設定されます。
ノードのドレイン中に動作がおかしくなったアプリケーションの退避をサポートするために、Unhealthy Pod Eviction Policy にAlwaysAllow
を設定することを推奨します。
既定の動作は、ドレインを継続する前にアプリケーションPodがhealthy な状態になるまで待機します。
Eviction APIを使用してPodを退避した場合、PodSpec で設定したterminationGracePeriodSeconds
に従って正常に終了 します。
PodDisruptionBudgetの例 node-1
からnode-3
まで3つのノードがあるクラスターを考えます。
クラスターにはいくつかのアプリケーションが動いています。
それらのうちの1つは3つのレプリカを持ち、最初はpod-a
、pod-b
そしてpod-c
と名前が付いています。
もう一つ、これとは独立したPDBなしのpod-x
と呼ばれるものもあります。
初期状態ではPodは次のようにレイアウトされています:
node-1 node-2 node-3 pod-a available pod-b available pod-c available pod-x available
3つのPodはすべてDeploymentの一部で、これらはまとめて1つのPDBを持ち、3つのPodのうちの少なくとも2つが常に存在していることを要求します。
例えばクラスター管理者がカーネルのバグを修正するために、再起動して新しいカーネルバージョンにしたいとします。
クラスター管理者はまず、kubectl drain
コマンドを使ってnode-1
をドレインしようとします。
ツールはpod-a
とpod-x
を退避しようとします。
これはすぐに成功します。
2つのPodは同時にterminating
状態になります。
これにより、クラスターは次のような状態になります:
node-1 draining node-2 node-3 pod-a terminating pod-b available pod-c available pod-x terminating
DeploymentはPodの1つが終了中であることに気づき、pod-d
という代わりのPodを作成します。
node-1
はcordonされたため、別のノードに展開されます。
また、pod-x
の代わりとしてpod-y
も作られました。
(備考: StatefulSetの場合、pod-a
はpod-0
のように呼ばれ、代わりのPodが作成される前に完全に終了する必要があります。
この代わりのPodは、UIDは異なりますが、同じpod-0
という名前になります。
それを除けば、本例はStatefulSetにも当てはまります。)
現在、クラスターは次のような状態になっています:
node-1 draining node-2 node-3 pod-a terminating pod-b available pod-c available pod-x terminating pod-d starting pod-y
ある時点でPodは終了し、クラスターはこのようになります:
node-1 drained node-2 node-3 pod-b available pod-c available pod-d starting pod-y
この時点で、せっかちなクラスター管理者がnode-2
かnode-3
をドレインしようとすると、Deploymentの利用可能なPodは2つしかなく、また、PDBによって最低2つのPodが要求されているため、drainコマンドはブロックされます。
しばらくすると、pod-d
が使用可能になります。
クラスターの状態はこのようになります:
node-1 drained node-2 node-3 pod-b available pod-c available pod-d available pod-y
ここでクラスター管理者がnode-2
をドレインしようとします。
drainコマンドは2つのPodをなんらかの順番で退避しようとします。
例えば最初にpod-b
、次にpod-d
とします。
pod-b
については退避に成功します。
しかしpod-d
を退避しようとすると、Deploymentに対して利用可能なPodは1つしか残らないため、退避は拒否されます。
Deploymentはpod-b
の代わりとしてpod-e
を作成します。
クラスターにはpod-e
をスケジューリングする十分なリソースがないため、ドレインは再びブロックされます。
クラスターは次のような状態になります:
node-1 drained node-2 node-3 no node pod-b terminating pod-c available pod-e pending pod-d available pod-y
この時点で、クラスター管理者はアップグレードを継続するためにクラスターにノードを追加する必要があります。
KubernetesがどのようにDisruptionの発生率を変化させているかについては、次のようなものから知ることができます:
いくつのレプリカをアプリケーションが必要としているか インスタンスのグレースフルシャットダウンにどれくらいの時間がかかるか 新しいインスタンスのスタートアップにどれくらいの時間がかかるか コントローラーの種類 クラスターリソースのキャパシティ Pod Disruption Condition FEATURE STATE:
Kubernetes v1.26 [beta]
備考: この機能を使用するためには、クラスターで
フィーチャーゲート PodDisruptionConditions
を有効にする必要があります。
有効にすると、専用のPod DisruptionTarget
Condition が追加されます。
これはPodがDisruption によって削除されようとしていることを示すものです。
Conditionのreason
フィールドにて、追加で以下のいずれかをPodの終了の理由として示します:
PreemptionByScheduler
Podはより高い優先度を持つ新しいPodを収容するために、スケジューラーによってプリエンプトされる 予定です。
詳細についてはPodの優先度とプリエンプション を参照してください。 DeletionByTaintManager
Podが許容しないNoExecute
taintによって、Podは(kube-controller-manager
の中のノードライフサイクルコントローラーである)Taintマネージャーによって削除される予定です。
taint ベースの退避を参照してください。 EvictionByEvictionAPI
PodはKubernetes APIを使用して退避するように マークされました。 DeletionByPodGC
すでに存在しないノードに紐づいているPodのため、Podのガベージコレクション によって削除される予定です。 TerminationByKubelet
node-pressureによる退避 またはGraceful Node Shutdown のため、Podはkubeletによって終了させられました。
備考: PodのDisruptionは一時停止する場合があります。
コントロールプレーンは同じPodに対するDisruptionを継続するために再試行するかもしれませんが、保証はされていません。
その結果、DisruptionTarget
ConditionはPodに付与されるかもしれませんが、実際にはPodは削除されていない可能性があります。
そのような状況の場合、しばらくすると、Pod Disruption Conditionはクリアされます。フィーチャーゲートPodDisruptionConditions
を有効にすると、Podのクリーンアップと共に、Podガベージコレクタ(PodGC)が非終了フェーズにあるPodを失敗とマークします。
(Podガベージコレクション も参照してください)。
Job(またはCronJob)を使用している場合、JobのPod失敗ポリシー の一部としてこれらのPod Disruption Conditionを使用したいと思うかもしれません。
クラスターオーナーとアプリケーションオーナーロールの分離 多くの場合、クラスター管理者とアプリケーションオーナーは、互いの情報を一部しか持たない別の役割であると考えるのが便利です。
このような責任の分離は、次のようなシナリオで意味を持つことがあります:
多くのアプリケーションチームでKubernetesクラスターを共有していて、役割の専門化が自然に行われている場合 クラスター管理を自動化するためにサードパーティのツールやサービスを使用している場合 Pod Disruption Budgetはロール間のインターフェースを提供することによって、この役割の分離をサポートします。
もしあなたの組織でこのような責任の分担がなされていない場合は、Pod Disruption Budgetを使用する必要はないかもしれません。
クラスターで破壊的なアクションを実行する方法 あなたがクラスターの管理者で、ノードやシステムソフトウェアのアップグレードなど、クラスター内のすべてのノードに対して破壊的なアクションを実行する必要がある場合、次のような選択肢があります:
アップグレードの間のダウンタイムを許容する。 もう一つの完全なレプリカクラスターにフェールオーバーする。ダウンタイムはありませんが、重複するノードと、切り替えを調整する人的労力の両方のコストがかかる可能性があります。 Disruptionに耐性のあるアプリケーションを書き、PDBを使用する。ダウンタイムはありません。 リソースの重複は最小限です。 クラスター管理をより自動化できます。 Disruptionに耐えうるアプリケーションを書くことは大変ですが、自発的なDisruptionに耐えうるようにするための作業は、非自発的なDisruptionに耐えうるために必要な作業とほぼ重複しています。 次の項目 4.1.5 - エフェメラルコンテナ FEATURE STATE:
Kubernetes v1.16 [alpha]
このページでは、特別な種類のコンテナであるエフェメラルコンテナの概要を説明します。エフェメラルコンテナは、トラブルシューティングなどのユーザーが開始するアクションを実行するために、すでに存在するPod 内で一時的に実行するコンテナです。エフェメラルコンテナは、アプリケーションの構築ではなく、serviceの調査のために利用します。
警告: エフェメラルコンテナは初期のアルファ状態であり、本番クラスターには適しません。
Kubernetesの非推奨ポリシー に従って、このアルファ機能は、将来大きく変更されたり、完全に削除される可能性があります。
エフェメラルコンテナを理解する Pod は、Kubernetesのアプリケーションの基本的なビルディングブロックです。Podは破棄可能かつ置き換え可能であることが想定されているため、一度Podが作成されると新しいコンテナを追加することはできません。その代わりに、通常はDeployment を使用してPodを削除して置き換えます。
たとえば、再現困難なバグのトラブルシューティングなどのために、すでに存在するPodの状態を調査する必要が出てくることがあります。このような場合、既存のPod内でエフェメラルコンテナを実行することで、Podの状態を調査したり、任意のコマンドを実行したりできます。
エフェメラルコンテナとは何か? エフェメラルコンテナは、他のコンテナと異なり、リソースや実行が保証されず、自動的に再起動されることも決してないため、アプリケーションを構築する目的には適しません。エフェメラルコンテナは、通常のコンテナと同じContainerSpec
で記述されますが、多くのフィールドに互換性がなかったり、使用できなくなっています。
エフェメラルコンテナはポートを持つことができないため、ports
、livenessProbe
、readinessProbe
などは使えなくなっています。 Podリソースの割り当てはイミュータブルであるため、resources
の設定が禁止されています。 利用が許可されているフィールドの一覧については、EphemeralContainerのリファレンスドキュメント を参照してください。 エフェメラルコンテナは、直接pod.spec
に追加するのではなく、API内の特別なephemeralcontainers
ハンドラを使用して作成します。そのため、エフェメラルコンテナをkubectl edit
を使用して追加することはできません。
エフェメラルコンテナをPodに追加した後は、通常のコンテナのようにエフェメラルコンテナを変更または削除することはできません。
エフェメラルコンテナの用途 エフェメラルコンテナは、コンテナがクラッシュしてしまったり、コンテナイメージにデバッグ用ユーティリティが同梱されていない場合など、kubectl exec
では不十分なときにインタラクティブなトラブルシューティングを行うために役立ちます。
特に、distrolessイメージ を利用すると、攻撃対象領域を減らし、バグや脆弱性を露出する可能性を減らせる最小のコンテナイメージをデプロイできるようになります。distrolessイメージにはシェルもデバッグ用のユーティリティも含まれないため、kubectl exec
のみを使用してdistrolessイメージのトラブルシューティングを行うのは困難です。
エフェメラルコンテナを利用する場合には、他のコンテナ内のプロセスにアクセスできるように、プロセス名前空間の共有 を有効にすると便利です。
エフェメラルコンテナを利用してトラブルシューティングを行う例については、デバッグ用のエフェメラルコンテナを使用してデバッグする を参照してください。
Ephemeral containers API 備考: このセクションの例を実行するには、
EphemeralContainers
フィーチャーゲート を有効にして、Kubernetesクライアントとサーバーのバージョンをv1.16以上にする必要があります。
このセクションの例では、API内でエフェメラルコンテナを表示する方法を示します。通常は、APIを直接呼び出すのではなく、kubectl alpha debug
やその他のkubectl
プラグイン を使用して、これらのステップを自動化します。
エフェメラルコンテナは、Podのephemeralcontainers
サブリソースを使用して作成されます。このサブリソースは、kubectl --raw
を使用して確認できます。まずはじめに、以下にEphemeralContainers
リストとして追加するためのエフェメラルコンテナを示します。
{
"apiVersion" : "v1" ,
"kind" : "EphemeralContainers" ,
"metadata" : {
"name" : "example-pod"
},
"ephemeralContainers" : [{
"command" : [
"sh"
],
"image" : "busybox" ,
"imagePullPolicy" : "IfNotPresent" ,
"name" : "debugger" ,
"stdin" : true ,
"tty" : true ,
"terminationMessagePolicy" : "File"
}]
}
すでに実行中のexample-pod
のエフェメラルコンテナを更新するには、次のコマンドを実行します。
kubectl replace --raw /api/v1/namespaces/default/pods/example-pod/ephemeralcontainers -f ec.json
このコマンドを実行すると、新しいエフェメラルコンテナのリストが返されます。
{
"kind" :"EphemeralContainers" ,
"apiVersion" :"v1" ,
"metadata" :{
"name" :"example-pod" ,
"namespace" :"default" ,
"selfLink" :"/api/v1/namespaces/default/pods/example-pod/ephemeralcontainers" ,
"uid" :"a14a6d9b-62f2-4119-9d8e-e2ed6bc3a47c" ,
"resourceVersion" :"15886" ,
"creationTimestamp" :"2019-08-29T06:41:42Z"
},
"ephemeralContainers" :[
{
"name" :"debugger" ,
"image" :"busybox" ,
"command" :[
"sh"
],
"resources" :{
},
"terminationMessagePolicy" :"File" ,
"imagePullPolicy" :"IfNotPresent" ,
"stdin" :true ,
"tty" :true
}
]
}
新しく作成されたエフェメラルコンテナの状態を確認するには、kubectl describe
を使用します。
kubectl describe pod example-pod
...
Ephemeral Containers:
debugger:
Container ID: docker://cf81908f149e7e9213d3c3644eda55c72efaff67652a2685c1146f0ce151e80f
Image: busybox
Image ID: docker-pullable://busybox@sha256:9f1003c480699be56815db0f8146ad2e22efea85129b5b5983d0e0fb52d9ab70
Port: <none>
Host Port: <none>
Command:
sh
State: Running
Started: Thu, 29 Aug 2019 06:42:21 +0000
Ready: False
Restart Count: 0
Environment: <none>
Mounts: <none>
...
新しいエフェメラルコンテナとやりとりをするには、他のコンテナと同じように、kubectl attach
、kubectl exec
、kubectl logs
などのコマンドが利用できます。例えば、次のようなコマンドが実行できます。
kubectl attach -it example-pod -c debugger
4.1.6 - ユーザー名前空間 FEATURE STATE:
Kubernetes v1.30 [beta]
このページでは、KubernetesのPodにおけるユーザー名前空間 について説明します。
ユーザー名前空間はホストのユーザーとコンテナ内プロセスが利用するユーザーを隔離するものです。
ユーザー名前空間を使うと、コンテナ内でrootとして稼働するプロセスを、ホスト側の異なる(root以外の)ユーザーとして実行することができます。
言い換えれば、ユーザー名前空間内部のリソースの操作に特権をもつプロセスは、名前空間の外側では非特権のプロセスとなっています。
ホストや他のPodに危害を及ぼす、侵害されたコンテナによる被害を軽減するために、この機能を用いることができます。
HIGH ないしは CRITICAL にレートされたいくつかの脆弱性 は、ユーザー名前空間が有効な場合には悪用できないものでした。
ユーザー名前空間は、将来の脆弱性を緩和することも期待できます。
始める前に 備考: このセクションでは、Kubernetesが必要とする機能を提供するサードパーティープロジェクトにリンクしています。これらのプロジェクトはアルファベット順に記載されていて、Kubernetesプロジェクトの作者は責任を持ちません。このリストにプロジェクトを追加するには、変更を提出する前に
content guide をお読みください。
詳細はこちら。 この機能はLinux固有であり、Linuxのファイルシステムでidmapマウントがサポートされている必要があります。
ノード上で/var/lib/kubelet/pods/
(ないしはそのカスタムディレクトリとして設定した場所)でidmapマウントがサポートされている必要があります。 Podのボリュームとして使われる全てのファイルシステムがidmapマウントをサポートしている必要があります。 これは、最低でもLinux 6.3以降を利用していて、かつidmapマウントをサポートするtmpfsが必要であることを意味します。
一般的に、いくつかのKubernetesの機能はtmpfsを利用しています。
(デフォルトでは、PodがサービスアカウントトークンやSecretをマウントする時にtmpfsを使っていたりします)。
Linux 6.3でidmapマウントをサポートするポピュラーなファイルシステムはbtrfs、ext4、xfs、fat、tmpfs、overlayfsです。
さらに、コンテナランタイムとその基盤であるOCIランタイムもユーザー名前空間をサポートしている必要があります。
次のOCIランタイムではサポートが提供されています。
crun バージョン1.9以上 (推奨バージョンは1.13以上).runc バージョン1.2以上
備考: いくつかのOCIランタイムには、LinuxのPodでユーザー名前空間を利用するのに必要なサポートが含まれていません。
マネージドKubernetesを利用している場合やOCIランタイムをパッケージとしてダウンロードしてセットアップした場合には、クラスタ内のノードがユーザー名前空間をサポートしない可能性があります。Kubernetesでユーザー名前空間を利用する際、Podでこの機能を使うためにはCRIコンテナランタイム も必要です。
containerd: バージョン2.0以上ではコンテナのユーザー名前空間をサポート。 CRI-O: バージョン1.25以上でコンテナのユーザー名前空間をサポート。 ユーザー名前空間のサポート状況については、GitHubのissue で確認できます。
導入 Linuxの機能であるユーザー名前空間を用いると、コンテナのユーザーをホスト側の異なるユーザーにマップすることができます。
さらに言えば、ユーザー名前空間においてPodに付与されたケーパビリティ(capability)は、ユーザー名前空間内においてのみ有効で、外側では無効です。
Podはpod.spec.hostUsers
フィールドをfalse
に設定することで、ユーザー名前空間を使えるようになります。
kubeletはPodに対応する(ホストの)UID/GIDを選択した上で、同一ノードの2つ以上のPodが同じ対応関係にならないよう保証するようにしつつ、ユーザーをマップします。
pod.spec
におけるrunAsUser
やrunAsGroup
、fsGroup
などのフィールドはコンテナ内のユーザーを指すものです。
この機能が有効化された場合、UID/GIDとして正しい値の範囲は0-65535です。
これはファイルとプロセスに対して適用されます。
(runAsUser
やrunAsGroup
など)。
この範囲を超えるUID/GIDを利用するファイルはオーバーフローしたID(一般的には65534)に所属するように見えるでしょう。
(/proc/sys/kernel/overflowuid
と/proc/sys/kernel/overflowgid
で設定されます)。
ただし、これらのファイルは65534のユーザー/グループで稼働するプロセスであっても、編集することはできません。
rootとして動かす必要があるアプリケーションであっても、ホストにおける他のユーザー名前空間や他のリソースに対してアクセスしないものの多くは、ユーザー名前空間を有効化しても動かせますし、アプリケーションを修正しなくても問題なく動作するでしょう。
Podにおけるユーザー名前空間を理解する いくつかのコンテナランタイム(Docker Engineやcontainer、CRI-Oなど)は、デフォルトでユーザー名前空間を利用するように設定されています。
これらのランタイムとその他の既存技術を組み合わせて使うことも可能です。
(例えば、Kata ContainerはLinux名前空間の代わりにVMを利用します)。
このページの内容はLinux名前空間を隔離に使うコンテナランタイムに適用できるものです。
Podを作成する時、デフォルトでは、Podの隔離にいくつかの新しい名前空間が利用されます。
(コンテナネットワークの隔離のためのネットワーク名前空間、プロセスの見える範囲を隔離するためのPID名前空間など)。
ユーザー名前空間を利用する場合には、コンテナ内のユーザーをノードのユーザーと隔離します。
これは、コンテナがrootとしてプロセスを動かせる一方で、ホスト上では非rootユーザーとしてマップされていることを意味します。
コンテナ内部のプロセスはrootとして動作しているものと思っていることでしょう。
(したがって、apt
やyum
などは問題なく動作します)。
しかし、実際には、このプロセスにホスト上での特権はありません。
これを検証するには、例えばホスト上でps aux
を実行することで、コンテナのプロセスがどのユーザーを使用しているかを確認するとよいでしょう。
ps
が示すユーザーは、コンテナ内でid
を実行した場合に示されるユーザーとは異なっているはずです。
この分離によって、ホスト上で「起こせること」を制限できます。例えばコンテナ内プロセスのホストへのエスケープを処理する場合にこの制限が有効に働きます。
コンテナはホスト上で非特権のユーザーとして動作しているため、ホスト上でできることが制限されているのです。
さらに言えば、それぞれのPodのユーザーは、ホスト上においては異なるユーザーにマップされており、UID/GIDは重複しません。
他のPodに対してできることさえも制限されているのです。
Podに付与されたケーパビリティについても、Podのユーザー名前空間に制限されており、名前空間の外部においてはほとんどが効力を持たず、いくつかのケーパビリティは外部では完全に無効です。
2つの例を挙げます:
CAP_SYS_MODULE
がユーザー名前空間を使うPodに付与されている場合、Podはカーネルモジュールをロードできません。CAP_SYS_ADMIN
はPodのユーザー名前空間の内部のみに制限され、名前空間の外部では無効です。コンテナブレークアウトのケースについて考えてみます。
この場合、ユーザー名前空間を使用せずにコンテナをrootで稼働させていると、ノードのroot権限が取得されます。
さらに、ケーパビリティがコンテナに付与されていた場合には、そのケーパビリティはホスト上でも有効となっています。
ユーザー名前空間を利用していれば、これらはいずれも成立しません。
ユーザー名前空間を使う場合に何が変わるのかについて詳しく知りたい場合には、man 7 user_namespaces
を参照してください。
ユーザー名前空間をサポートするノードを設定する ほとんどのLinuxディストリビューションで標準的なUIDである0-65535の範囲については、kubeletはホストのファイルやプロセスがこの範囲のUIDを利用しているものとみなし、デフォルトではこれよりも上のUID/GIDの値をPodに紐付けます。
言い換えれば、0-65535の範囲のIDをPodで使うことはできません。
このアプローチにより、PodとホストのUID/GIDが重複することを防ぎます。
Podによる潜在的な任意のファイル読み出しの脆弱性であるCVE-2021-25741 のような脆弱性の影響を緩和する上で、UID/GIDの重複を防ぐことは重要です。
PodとホストのUID/GIDが重複しなければ、Podができることは限定されます。
(PodのUID/GIDはホスト上のファイル所有者やグループと一致することがないのです)。
kubeletはPodに割り当てるユーザーIDとグループIDの範囲を変更することが可能です。カスタムの範囲を設定するには、ノードが次の条件を満たす必要があります。
ユーザーkubelet
がシステム上に存在していること(他のユーザー名を使うことはできません) getsubids
バイナリ(shadow-utils の一部)がインストールされており、kubeletバイナリが参照するPATH
に入っていることkubelet
ユーザーのsubordinate UID/GID (man 5 subuid
およびman 5 subgid
を参照)これはsubordinate UID/GIDの範囲に関する設定のみを示しており、kubelet
を実行するユーザーは変更しません。
ユーザーkubelet
に割り当てるsubordinate IDの範囲に関しては、いくつかの制約に従う必要があります。
subordinate UIDの起点(つまりPodのUID範囲の開始位置)が65536の倍数に設定されていて、かつ65536以上であること( 必須 )。
言い換えると、0-65535の範囲をPodのUIDとして使うことはできません。
偶発的にインセキュアな設定がなされることを防ぐために、kubeletはこの制約を強制します。
subordinate UID/GIDの個数が65536の倍数であること(必須)。
subordinate UID/GIDの個数は最低でも65536 x <最大Pod数>
であること(必須)。
<最大Pod数>
はノードで稼働できるPodの数の最大値を表します。
UIDとGIDとして同じ個数を割り当てること(必須)。
他のユーザーに対して、GIDの範囲と合致しないUID範囲を指定することは問題ありません。
割り当てられたUID/GID範囲は他の割当と重複しないこと(推奨)。
subordinate UID/GIDの設定は単一行でなされること(必須)。
同一のユーザーに対して複数のUID/GID範囲を定義することはできません。
例えば、ユーザーkubelet
のエントリについて、/etc/subuid
と/etc/subgid
に次のように定義することができます。
# フォーマットは次の通り
# name:firstID:count
# この例における意味
# - firstIDは65536 (とりうる最小の値)
# - countは110 (デフォルトの制限値) * 65536
kubelet:65536:7208960
Podセキュリティのアドミッション検証への統合 FEATURE STATE:
Kubernetes v1.29 [alpha]
ユーザー名前空間を有効化したLinuxのPodでは、KubernetesはPod Security Standards で制御されるアプリケーションの制限を緩和します。
この挙動はエンドユーザーの早期オプトインを可能にするためのUserNamespacesPodSecurityStandards
フィーチャーゲート で制御することが可能です。
このフィーチャーゲートを使う場合、クラスタ管理者はユーザー名前空間が全てのノードで有効化されていることを確実にする必要があります。
フィーチャーゲートを有効化した上でユーザー名前空間を使うPodを作成する場合、_Baseline_ないしは_Restricted_Podセキュリティ基準のセキュリティコンテキストが強制されていても、以下のフィールドによる制約がなされません。
spec.securityContext.runAsNonRoot
spec.containers[*].securityContext.runAsNonRoot
spec.initContainers[*].securityContext.runAsNonRoot
spec.ephemeralContainers[*].securityContext.runAsNonRoot
spec.securityContext.runAsUser
spec.containers[*].securityContext.runAsUser
spec.initContainers[*].securityContext.runAsUser
spec.ephemeralContainers[*].securityContext.runAsUser
制限 Podでユーザー名前空間を利用する際には、他のホスト名前空間を利用することはできません。
特にhostUsers: false
を設定している場合、次の値を設定することはできません。
hostNetwork: true
hostIPC: true
hostPID: true
次の項目
4.2 - ワークロードリソース 4.2.1 - Deployment Deployment はPod とReplicaSet の宣言的なアップデート機能を提供します。
Deploymentにおいて 理想的な状態 を記述すると、Deploymentコントローラー は指定された頻度で現在の状態を理想的な状態に変更します。Deploymentを定義することによって、新しいReplicaSetを作成したり、既存のDeploymentを削除して新しいDeploymentで全てのリソースを適用できます。
備考: Deploymentによって作成されたReplicaSetを管理しないでください。ご自身のユースケースが以下の項目に含まれない場合、メインのKubernetesリポジトリーにIssueを作成することを検討してください。ユースケース 以下の項目はDeploymentの典型的なユースケースです。
Deploymentの作成 以下はDeploymentの例です。これはnginx
Podのレプリカを3つ持つReplicaSetを作成します。
apiVersion : apps/v1
kind : Deployment
metadata :
name : nginx-deployment
labels :
app : nginx
spec :
replicas : 3
selector :
matchLabels :
app : nginx
template :
metadata :
labels :
app : nginx
spec :
containers :
- name : nginx
image : nginx:1.14.2
ports :
- containerPort : 80
この例では、
.metadata.name
フィールドで指定されたnginx-deployment
という名前のDeploymentが作成されます。
このDeploymentは.spec.replicas
フィールドで指定された通り、3つのレプリカPodを作成します。
.spec.selector
フィールドは、Deploymentが管理するPodのラベルを定義します。ここでは、Podテンプレートにて定義されたラベル(app: nginx
)を選択しています。しかし、PodTemplate自体がそのルールを満たす限り、さらに洗練された方法でセレクターを指定することができます。
備考: `.spec.selector.matchLabels`フィールドはキーバリューペアのマップです。
`matchLabels`マップにおいて、{key, value}というペアは、keyというフィールドの値が"key"で、その演算子が"In"で、値の配列が"value"のみ含むような`matchExpressions`の要素と等しくなります。
`matchLabels`と`matchExpressions`の両方が設定された場合、条件に一致するには両方とも満たす必要があります。
.spec.template
フィールドは、以下のサブフィールドを持ちます。:
Podは.metadata.labels
フィールドによって指定されたapp: nginx
というラベルがつけられます。 PodTemplate、または.spec
フィールドは、Podがnginx
という名前でDocker Hub にあるnginx
のバージョン1.14.2が動くコンテナを1つ動かすことを示します。 1つのコンテナを作成し、.spec.containers[0].name
フィールドを使ってnginx
という名前をつけます。 作成を始める前に、Kubernetesクラスターが稼働していることを確認してください。
上記のDeploymentを作成するためには以下のステップにしたがってください:
以下のコマンドを実行してDeploymentを作成してください。 kubectl apply -f https://k8s.io/examples/controllers/nginx-deployment.yaml
Deploymentが作成されたことを確認するために、kubectl get deployments
を実行してください。 Deploymentがまだ作成中の場合、コマンドの実行結果は以下のとおりです。
NAME READY UP-TO-DATE AVAILABLE AGE
nginx-deployment 0/3 0 0 1s
クラスターにてDeploymentを調査するとき、以下のフィールドが出力されます。
NAME
は、クラスター内にあるDeploymentの名前一覧です。READY
は、ユーザーが使用できるアプリケーションのレプリカの数です。使用可能な数/理想的な数の形式で表示されます。UP-TO-DATE
は、理想的な状態を満たすためにアップデートが完了したレプリカの数です。AVAILABLE
は、ユーザーが利用可能なレプリカの数です。AGE
は、アプリケーションが稼働してからの時間です。.spec.replicas
フィールドの値によると、理想的なレプリカ数は3であることがわかります。
Deploymentのロールアウトステータスを確認するために、kubectl rollout status deployment.v1.apps/nginx-deployment
を実行してください。 コマンドの実行結果は以下のとおりです。
Waiting for rollout to finish: 2 out of 3 new replicas have been updated...
deployment "nginx-deployment" successfully rolled out
数秒後、再度kubectl get deployments
を実行してください。
コマンドの実行結果は以下のとおりです。 NAME READY UP-TO-DATE AVAILABLE AGE
nginx-deployment 3/3 3 3 18s
Deploymentが3つ全てのレプリカを作成して、全てのレプリカが最新(Podが最新のPodテンプレートを含んでいる)になり、利用可能となっていることを確認してください。
Deploymentによって作成されたReplicaSet(rs
)を確認するにはkubectl get rs
を実行してください。コマンドの実行結果は以下のとおりです: NAME DESIRED CURRENT READY AGE
nginx-deployment-75675f5897 3 3 3 18s
ReplicaSetの出力には次のフィールドが表示されます:
NAME
は、名前空間内にあるReplicaSetの名前の一覧です。DESIRED
は、アプリケーションの理想的な レプリカ の値です。これはDeploymentを作成したときに定義したもので、これが 理想的な状態 と呼ばれるものです。CURRENT
は現在実行されているレプリカの数です。READY
は、ユーザーが使用できるアプリケーションのレプリカの数です。AGE
は、アプリケーションが稼働してからの時間です。ReplicaSetの名前は[Deployment名]-[ランダム文字列]
という形式になることに注意してください。ランダム文字列はランダムに生成され、pod-template-hashをシードとして使用します。
各Podにラベルが自動的に付けられるのを確認するにはkubectl get pods --show-labels
を実行してください。
コマンドの実行結果は以下のとおりです: NAME READY STATUS RESTARTS AGE LABELS
nginx-deployment-75675f5897-7ci7o 1/1 Running 0 18s app=nginx,pod-template-hash=75675f5897
nginx-deployment-75675f5897-kzszj 1/1 Running 0 18s app=nginx,pod-template-hash=75675f5897
nginx-deployment-75675f5897-qqcnn 1/1 Running 0 18s app=nginx,pod-template-hash=75675f5897
作成されたReplicaSetはnginx
Podを3つ作成することを保証します。
備考: Deploymentに対して適切なセレクターとPodテンプレートのラベルを設定する必要があります(このケースではapp: nginx
)。
ラベルやセレクターを他のコントローラーと重複させないでください(他のDeploymentやStatefulSetを含む)。Kubernetesはユーザーがラベルを重複させることを阻止しないため、複数のコントローラーでセレクターの重複が発生すると、コントローラー間で衝突し予期せぬふるまいをすることになります。
pod-template-hashラベル
注意: このラベルを変更しないでください。pod-template-hash
ラベルはDeploymentコントローラーによってDeploymentが作成し適用した各ReplicaSetに対して追加されます。
このラベルはDeploymentが管理するReplicaSetが重複しないことを保証します。このラベルはReplicaSetのPodTemplate
をハッシュ化することにより生成され、生成されたハッシュ値はラベル値としてReplicaSetセレクター、Podテンプレートラベル、ReplicaSetが作成した全てのPodに対して追加されます。
Deploymentの更新
備考: Deploymentのロールアウトは、DeploymentのPodテンプレート(この場合.spec.template
)が変更された場合にのみトリガーされます。例えばテンプレートのラベルもしくはコンテナイメージが更新された場合です。Deploymentのスケールのような更新では、ロールアウトはトリガーされません。Deploymentを更新するには以下のステップに従ってください。
nginxのPodで、nginx:1.14.2
イメージの代わりにnginx:1.16.1
を使うように更新します。
kubectl set image deployment.v1.apps/nginx-deployment nginx = nginx:1.16.1
または単に次のコマンドを使用します。
kubectl set image deployment/nginx-deployment nginx = nginx:1.16.1
実行結果は以下のとおりです。
deployment.apps/nginx-deployment image updated
また、Deploymentを編集
して、.spec.template.spec.containers[0].image
をnginx:1.14.2
からnginx:1.16.1
に変更することができます。
kubectl edit deployment.v1.apps/nginx-deployment
実行結果は以下のとおりです。
deployment.apps/nginx-deployment edited
ロールアウトのステータスを確認するには、以下のコマンドを実行してください。
kubectl rollout status deployment.v1.apps/nginx-deployment
実行結果は以下のとおりです。
Waiting for rollout to finish: 2 out of 3 new replicas have been updated...
もしくは
deployment "nginx-deployment" successfully rolled out
更新されたDeploymentのさらなる情報を取得するには、以下を確認してください。
ロールアウトが成功したあと、kubectl get deployments
を実行してDeploymentを確認できます。
実行結果は以下のとおりです。
NAME READY UP-TO-DATE AVAILABLE AGE
nginx-deployment 3/3 3 3 36s
Deploymentが新しいReplicaSetを作成してPodを更新させたり、新しいReplicaSetのレプリカを3にスケールアップさせたり、古いReplicaSetのレプリカを0にスケールダウンさせるのを確認するにはkubectl get rs
を実行してください。
実行結果は以下のとおりです。
NAME DESIRED CURRENT READY AGE
nginx-deployment-1564180365 3 3 3 6s
nginx-deployment-2035384211 0 0 0 36s
get pods
を実行させると、新しいPodのみ確認できます。
実行結果は以下のとおりです。
NAME READY STATUS RESTARTS AGE
nginx-deployment-1564180365-khku8 1/1 Running 0 14s
nginx-deployment-1564180365-nacti 1/1 Running 0 14s
nginx-deployment-1564180365-z9gth 1/1 Running 0 14s
次にPodを更新させたいときは、DeploymentのPodテンプレートを再度更新するだけです。
Deploymentは、Podが更新されている間に特定の数のPodのみ停止状態になることを保証します。デフォルトでは、目標とするPod数の少なくとも75%が稼働状態であることを保証します(25% max unavailable)。
また、DeploymentはPodが更新されている間に、目標とするPod数を特定の数まで超えてPodを稼働させることを保証します。デフォルトでは、目標とするPod数に対して最大でも125%を超えてPodを稼働させることを保証します(25% max surge)。
例えば、上記で説明したDeploymentの状態を注意深く見ると、最初に新しいPodが作成され、次に古いPodが削除されるのを確認できます。十分な数の新しいPodが稼働するまでは、Deploymentは古いPodを削除しません。また十分な数の古いPodが削除しない限り新しいPodは作成されません。少なくとも2つのPodが利用可能で、最大でもトータルで4つのPodが利用可能になっていることを保証します。
Deploymentの詳細情報を取得します。
kubectl describe deployments
実行結果は以下のとおりです。
Name: nginx-deployment
Namespace: default
CreationTimestamp: Thu, 30 Nov 2017 10:56:25 +0000
Labels: app=nginx
Annotations: deployment.kubernetes.io/revision=2
Selector: app=nginx
Replicas: 3 desired | 3 updated | 3 total | 3 available | 0 unavailable
StrategyType: RollingUpdate
MinReadySeconds: 0
RollingUpdateStrategy: 25% max unavailable, 25% max surge
Pod Template:
Labels: app=nginx
Containers:
nginx:
Image: nginx:1.16.1
Port: 80/TCP
Environment: <none>
Mounts: <none>
Volumes: <none>
Conditions:
Type Status Reason
---- ------ ------
Available True MinimumReplicasAvailable
Progressing True NewReplicaSetAvailable
OldReplicaSets: <none>
NewReplicaSet: nginx-deployment-1564180365 (3/3 replicas created)
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal ScalingReplicaSet 2m deployment-controller Scaled up replica set nginx-deployment-2035384211 to 3
Normal ScalingReplicaSet 24s deployment-controller Scaled up replica set nginx-deployment-1564180365 to 1
Normal ScalingReplicaSet 22s deployment-controller Scaled down replica set nginx-deployment-2035384211 to 2
Normal ScalingReplicaSet 22s deployment-controller Scaled up replica set nginx-deployment-1564180365 to 2
Normal ScalingReplicaSet 19s deployment-controller Scaled down replica set nginx-deployment-2035384211 to 1
Normal ScalingReplicaSet 19s deployment-controller Scaled up replica set nginx-deployment-1564180365 to 3
Normal ScalingReplicaSet 14s deployment-controller Scaled down replica set nginx-deployment-2035384211 to 0
最初にDeploymentを作成した時、ReplicaSet(nginx-deployment-2035384211)を作成してすぐにレプリカ数を3にスケールするのを確認できます。Deploymentを更新すると新しいReplicaSet(nginx-deployment-1564180365)を作成してレプリカ数を1にスケールアップし、古いReplicaSeetを2にスケールダウンさせます。これは常に最低でも2つのPodが利用可能で、かつ最大4つのPodが作成されている状態にするためです。Deploymentは同じローリングアップ戦略に従って新しいReplicaSetのスケールアップと古いReplicaSetのスケールダウンを続けます。最終的に新しいReplicaSetを3にスケールアップさせ、古いReplicaSetを0にスケールダウンさせます。
ロールオーバー (リアルタイムでの複数のPodの更新) Deploymentコントローラーにより、新しいDeploymentが観測される度にReplicaSetが作成され、理想とするレプリカ数のPodを作成します。Deploymentが更新されると、既存のReplicaSetが管理するPodのラベルが.spec.selector
にマッチするが、テンプレートが.spec.template
にマッチしない場合はスケールダウンされます。最終的に、新しいReplicaSetは.spec.replicas
の値にスケールアップされ、古いReplicaSetは0にスケールダウンされます。
Deploymentのロールアウトが進行中にDeploymentを更新すると、Deploymentは更新する毎に新しいReplicaSetを作成してスケールアップさせ、以前にスケールアップしたReplicaSetのロールオーバーを行います。Deploymentは更新前のReplicaSetを古いReplicaSetのリストに追加し、スケールダウンを開始します。
例えば、5つのレプリカを持つnginx:1.14.2
のDeploymentを作成し、nginx:1.14.2
の3つのレプリカが作成されているときに5つのレプリカを持つnginx:1.16.1
に更新します。このケースではDeploymentは作成済みのnginx:1.14.2
の3つのPodをすぐに削除し、nginx:1.16.1
のPodの作成を開始します。nginx:1.14.2
の5つのレプリカを全て作成するのを待つことはありません。
ラベルセレクターの更新 通常、ラベルセレクターを更新することは推奨されません。事前にラベルセレクターの使い方を計画しておきましょう。いかなる場合であっても更新が必要なときは十分に注意を払い、変更時の影響範囲を把握しておきましょう。
備考: apps/v1
API バージョンにおいて、Deploymentのラベルセレクターは作成後に不変となります。セレクターの追加は、Deployment Specのテンプレートラベルも新しいラベルで更新する必要があります。そうでない場合はバリデーションエラーが返されます。この変更は重複がない更新となります。これは新しいセレクターは古いセレクターを持つReplicaSetとPodを選択せず、結果として古い全てのReplicaSetがみなし子状態になり、新しいReplicaSetを作成することを意味します。 セレクターの更新により、セレクターキー内の既存の値が変更されます。これにより、セレクターの追加と同じふるまいをします。 セレクターの削除により、Deploymentのセレクターから存在している値を削除します。これはPodテンプレートのラベルに関する変更を要求しません。既存のReplicaSetはみなし子状態にならず、新しいReplicaSetは作成されませんが、削除されたラベルは既存のPodとReplicaSetでは残り続けます。 Deploymentのロールバック 例えば、クラッシュループ状態などのようにDeploymentが不安定な場合においては、Deploymentをロールバックしたくなることがあります。Deploymentの全てのロールアウト履歴は、いつでもロールバックできるようにデフォルトでシステムに保持されています(リビジョン履歴の上限は設定することで変更可能です)。
備考: Deploymentのリビジョンは、Deploymentのロールアウトがトリガーされた時に作成されます。これはDeploymentのPodテンプレート(.spec.template
)が変更されたときのみ新しいリビジョンが作成されることを意味します。Deploymentのスケーリングなど、他の種類の更新においてはDeploymentのリビジョンは作成されません。これは手動もしくはオートスケーリングを同時に行うことができるようにするためです。これは過去のリビジョンにロールバックするとき、DeploymentのPodテンプレートの箇所のみロールバックされることを意味します。nginx:1.16.1
の代わりにnginx:1.161
というイメージに更新して、Deploymentの更新中にタイプミスをしたと仮定します。
kubectl set image deployment/nginx-deployment nginx = nginx:1.161
実行結果は以下のとおりです。
deployment.apps/nginx-deployment image updated
このロールアウトはうまくいきません。ロールアウトのステータスを見るとそれを確認できます。
kubectl rollout status deployment.v1.apps/nginx-deployment
実行結果は以下のとおりです。
Waiting for rollout to finish: 1 out of 3 new replicas have been updated...
ロールアウトのステータスの確認は、Ctrl-Cを押すことで停止できます。ロールアウトがうまく行かないときは、Deploymentのステータス を読んでさらなる情報を得てください。
古いレプリカ数(nginx-deployment-1564180365
and nginx-deployment-2035384211
)が2になっていることを確認でき、新しいレプリカ数(nginx-deployment-3066724191)は1になっています。
実行結果は以下のとおりです。
NAME DESIRED CURRENT READY AGE
nginx-deployment-1564180365 3 3 3 25s
nginx-deployment-2035384211 0 0 0 36s
nginx-deployment-3066724191 1 1 0 6s
作成されたPodを確認していると、新しいReplicaSetによって作成された1つのPodはコンテナイメージのpullに失敗し続けているのがわかります。
実行結果は以下のとおりです。
NAME READY STATUS RESTARTS AGE
nginx-deployment-1564180365-70iae 1/1 Running 0 25s
nginx-deployment-1564180365-jbqqo 1/1 Running 0 25s
nginx-deployment-1564180365-hysrc 1/1 Running 0 25s
nginx-deployment-3066724191-08mng 0/1 ImagePullBackOff 0 6s
備考: Deploymentコントローラーは、この悪い状態のロールアウトを自動的に停止し、新しいReplicaSetのスケールアップを止めます。これはユーザーが指定したローリングアップデートに関するパラメーター(特に`maxUnavailable`)に依存します。デフォルトではKubernetesがこの値を25%に設定します。
Deploymentの詳細情報を取得します。
kubectl describe deployment
実行結果は以下のとおりです。
Name: nginx-deployment
Namespace: default
CreationTimestamp: Tue, 15 Mar 2016 14:48:04 -0700
Labels: app=nginx
Selector: app=nginx
Replicas: 3 desired | 1 updated | 4 total | 3 available | 1 unavailable
StrategyType: RollingUpdate
MinReadySeconds: 0
RollingUpdateStrategy: 25% max unavailable, 25% max surge
Pod Template:
Labels: app=nginx
Containers:
nginx:
Image: nginx:1.161
Port: 80/TCP
Host Port: 0/TCP
Environment: <none>
Mounts: <none>
Volumes: <none>
Conditions:
Type Status Reason
---- ------ ------
Available True MinimumReplicasAvailable
Progressing True ReplicaSetUpdated
OldReplicaSets: nginx-deployment-1564180365 (3/3 replicas created)
NewReplicaSet: nginx-deployment-3066724191 (1/1 replicas created)
Events:
FirstSeen LastSeen Count From SubObjectPath Type Reason Message
--------- -------- ----- ---- ------------- -------- ------ -------
1m 1m 1 {deployment-controller } Normal ScalingReplicaSet Scaled up replica set nginx-deployment-2035384211 to 3
22s 22s 1 {deployment-controller } Normal ScalingReplicaSet Scaled up replica set nginx-deployment-1564180365 to 1
22s 22s 1 {deployment-controller } Normal ScalingReplicaSet Scaled down replica set nginx-deployment-2035384211 to 2
22s 22s 1 {deployment-controller } Normal ScalingReplicaSet Scaled up replica set nginx-deployment-1564180365 to 2
21s 21s 1 {deployment-controller } Normal ScalingReplicaSet Scaled down replica set nginx-deployment-2035384211 to 1
21s 21s 1 {deployment-controller } Normal ScalingReplicaSet Scaled up replica set nginx-deployment-1564180365 to 3
13s 13s 1 {deployment-controller } Normal ScalingReplicaSet Scaled down replica set nginx-deployment-2035384211 to 0
13s 13s 1 {deployment-controller } Normal ScalingReplicaSet Scaled up replica set nginx-deployment-3066724191 to 1
これを修正するために、Deploymentを安定した状態の過去のリビジョンに更新する必要があります。
Deploymentのロールアウト履歴の確認 ロールアウトの履歴を確認するには、以下の手順に従って下さい。
最初に、Deploymentのリビジョンを確認します。
kubectl rollout history deployment.v1.apps/nginx-deployment
実行結果は以下のとおりです。
deployments "nginx-deployment"
REVISION CHANGE-CAUSE
1 kubectl apply --filename=https://k8s.io/examples/controllers/nginx-deployment.yaml
2 kubectl set image deployment.v1.apps/nginx-deployment nginx=nginx:1.16.1
3 kubectl set image deployment.v1.apps/nginx-deployment nginx=nginx:1.161
CHANGE-CAUSE
はリビジョンの作成時にDeploymentのkubernetes.io/change-cause
アノテーションからリビジョンにコピーされます。以下の方法によりCHANGE-CAUSE
メッセージを指定できます。
kubectl annotate deployment.v1.apps/nginx-deployment kubernetes.io/change-cause="image updated to 1.16.1"
の実行によりアノテーションを追加します。リソースのマニフェストを手動で編集します。 各リビジョンの詳細を確認するためには以下のコマンドを実行してください。
kubectl rollout history deployment.v1.apps/nginx-deployment --revision= 2
実行結果は以下のとおりです。
deployments "nginx-deployment" revision 2
Labels: app=nginx
pod-template-hash=1159050644
Annotations: kubernetes.io/change-cause=kubectl set image deployment.v1.apps/nginx-deployment nginx=nginx:1.16.1
Containers:
nginx:
Image: nginx:1.16.1
Port: 80/TCP
QoS Tier:
cpu: BestEffort
memory: BestEffort
Environment Variables: <none>
No volumes.
過去のリビジョンにロールバックする 現在のリビジョンから過去のリビジョン(リビジョン番号2)にロールバックさせるには、以下の手順に従ってください。
現在のリビジョンから過去のリビジョンにロールバックします。
kubectl rollout undo deployment.v1.apps/nginx-deployment
実行結果は以下のとおりです。
deployment.apps/nginx-deployment rolled back
その他に、--to-revision
を指定することにより特定のリビジョンにロールバックできます。
kubectl rollout undo deployment.v1.apps/nginx-deployment --to-revision= 2
実行結果は以下のとおりです。
deployment.apps/nginx-deployment rolled back
ロールアウトに関連したコマンドのさらなる情報はkubectl rollout
を参照してください。
Deploymentが過去の安定したリビジョンにロールバックされました。Deploymentコントローラーによって、リビジョン番号2にロールバックするDeploymentRollback
イベントが作成されたのを確認できます。
ロールバックが成功し、Deploymentが正常に稼働していることを確認するために、以下のコマンドを実行してください。
kubectl get deployment nginx-deployment
実行結果は以下のとおりです。
NAME READY UP-TO-DATE AVAILABLE AGE
nginx-deployment 3/3 3 3 30m
Deploymentの詳細情報を取得します。
kubectl describe deployment nginx-deployment
実行結果は以下のとおりです。
Name: nginx-deployment
Namespace: default
CreationTimestamp: Sun, 02 Sep 2018 18:17:55 -0500
Labels: app=nginx
Annotations: deployment.kubernetes.io/revision=4
kubernetes.io/change-cause=kubectl set image deployment.v1.apps/nginx-deployment nginx=nginx:1.16.1
Selector: app=nginx
Replicas: 3 desired | 3 updated | 3 total | 3 available | 0 unavailable
StrategyType: RollingUpdate
MinReadySeconds: 0
RollingUpdateStrategy: 25% max unavailable, 25% max surge
Pod Template:
Labels: app=nginx
Containers:
nginx:
Image: nginx:1.16.1
Port: 80/TCP
Host Port: 0/TCP
Environment: <none>
Mounts: <none>
Volumes: <none>
Conditions:
Type Status Reason
---- ------ ------
Available True MinimumReplicasAvailable
Progressing True NewReplicaSetAvailable
OldReplicaSets: <none>
NewReplicaSet: nginx-deployment-c4747d96c (3/3 replicas created)
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal ScalingReplicaSet 12m deployment-controller Scaled up replica set nginx-deployment-75675f5897 to 3
Normal ScalingReplicaSet 11m deployment-controller Scaled up replica set nginx-deployment-c4747d96c to 1
Normal ScalingReplicaSet 11m deployment-controller Scaled down replica set nginx-deployment-75675f5897 to 2
Normal ScalingReplicaSet 11m deployment-controller Scaled up replica set nginx-deployment-c4747d96c to 2
Normal ScalingReplicaSet 11m deployment-controller Scaled down replica set nginx-deployment-75675f5897 to 1
Normal ScalingReplicaSet 11m deployment-controller Scaled up replica set nginx-deployment-c4747d96c to 3
Normal ScalingReplicaSet 11m deployment-controller Scaled down replica set nginx-deployment-75675f5897 to 0
Normal ScalingReplicaSet 11m deployment-controller Scaled up replica set nginx-deployment-595696685f to 1
Normal DeploymentRollback 15s deployment-controller Rolled back deployment "nginx-deployment" to revision 2
Normal ScalingReplicaSet 15s deployment-controller Scaled down replica set nginx-deployment-595696685f to 0
Deploymentのスケーリング 以下のコマンドを実行させてDeploymentをスケールできます。
kubectl scale deployment.v1.apps/nginx-deployment --replicas= 10
実行結果は以下のとおりです。
deployment.apps/nginx-deployment scaled
クラスター内で水平Podオートスケーラー が有効になっていると仮定します。ここでDeploymentのオートスケーラーを設定し、稼働しているPodのCPU使用量に基づいて、稼働させたいPodのレプリカ数の最小値と最大値を設定できます。
kubectl autoscale deployment.v1.apps/nginx-deployment --min= 10 --max= 15 --cpu-percent= 80
実行結果は以下のとおりです。
deployment.apps/nginx-deployment scaled
比例スケーリング Deploymentのローリングアップデートは、同時に複数のバージョンのアプリケーションの稼働をサポートします。ユーザーやオートスケーラーがローリングアップデートをロールアウト中(更新中もしくは一時停止中)のDeploymentに対して行うと、Deploymentコントローラーはリスクを削減するために既存のアクティブなReplicaSetのレプリカのバランシングを行います。これを比例スケーリング と呼びます。
レプリカ数が10、maxSurge =3、maxUnavailable =2であるDeploymentが稼働している例です。
Deployment内で10のレプリカが稼働していることを確認します。
実行結果は以下のとおりです。
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
nginx-deployment 10 10 10 10 50s
クラスター内で、解決できない新しいイメージに更新します。
kubectl set image deployment.v1.apps/nginx-deployment nginx = nginx:sometag
実行結果は以下のとおりです。
deployment.apps/nginx-deployment image updated
イメージの更新は新しいReplicaSet nginx-deployment-1989198191へのロールアウトを開始させます。しかしロールアウトは、上述したmaxUnavailable
の要求によりブロックされます。ここでロールアウトのステータスを確認します。
実行結果は以下のとおりです。
NAME DESIRED CURRENT READY AGE
nginx-deployment-1989198191 5 5 0 9s
nginx-deployment-618515232 8 8 8 1m
次にDeploymentのスケーリングをするための新しい要求が発生します。オートスケーラーはDeploymentのレプリカ数を15に増やします。Deploymentコントローラーは新しい5つのレプリカをどこに追加するか決める必要がでてきます。比例スケーリングを使用していない場合、5つのレプリカは全て新しいReplicaSetに追加されます。比例スケーリングでは、追加されるレプリカは全てのReplicaSetに分散されます。比例割合が大きいものはレプリカ数の大きいReplicaSetとなり、比例割合が低いときはレプリカ数の小さいReplicaSetとなります。残っているレプリカはもっとも大きいレプリカ数を持つReplicaSetに追加されます。レプリカ数が0のReplicaSetはスケールアップされません。
上記の例では、3つのレプリカが古いReplicaSetに追加され、2つのレプリカが新しいReplicaSetに追加されました。ロールアウトの処理では、新しいレプリカ数のPodが正常になったと仮定すると、最終的に新しいReplicaSetに全てのレプリカを移動させます。これを確認するためには以下のコマンドを実行して下さい。
実行結果は以下のとおりです。
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
nginx-deployment 15 18 7 8 7m
ロールアウトのステータスでレプリカがどのように各ReplicaSetに追加されるか確認できます。
実行結果は以下のとおりです。
NAME DESIRED CURRENT READY AGE
nginx-deployment-1989198191 7 7 0 7m
nginx-deployment-618515232 11 11 11 7m
Deployment更新の一時停止と再開 ユーザーは1つ以上の更新処理をトリガーする前に更新の一時停止と再開ができます。これにより、不必要なロールアウトを実行することなく一時停止と再開を行う間に複数の修正を反映できます。
例えば、作成直後のDeploymentを考えます。
Deploymentの詳細情報を確認します。
実行結果は以下のとおりです。
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
nginx 3 3 3 3 1m
ロールアウトのステータスを確認します。
実行結果は以下のとおりです。
NAME DESIRED CURRENT READY AGE
nginx-2142116321 3 3 3 1m
以下のコマンドを実行して更新処理の一時停止を行います。
kubectl rollout pause deployment.v1.apps/nginx-deployment
実行結果は以下のとおりです。
deployment.apps/nginx-deployment paused
次にDeploymentのイメージを更新します。
kubectl set image deployment.v1.apps/nginx-deployment nginx = nginx:1.16.1
実行結果は以下のとおりです。
deployment.apps/nginx-deployment image updated
新しいロールアウトが開始されていないことを確認します。
kubectl rollout history deployment.v1.apps/nginx-deployment
実行結果は以下のとおりです。
deployments "nginx"
REVISION CHANGE-CAUSE
1 <none>
Deploymentの更新に成功したことを確認するためにロールアウトのステータスを確認します。
実行結果は以下のとおりです。
NAME DESIRED CURRENT READY AGE
nginx-2142116321 3 3 3 2m
更新は何度でも実行できます。例えば、Deploymentが使用するリソースを更新します。
kubectl set resources deployment.v1.apps/nginx-deployment -c= nginx --limits= cpu = 200m,memory= 512Mi
実行結果は以下のとおりです。
deployment.apps/nginx-deployment resource requirements updated
一時停止する前の初期状態では更新処理は機能しますが、Deploymentが一時停止されている間は新しい更新処理は反映されません。
最後に、Deploymentの稼働を再開させ、新しいReplicaSetが更新内容を全て反映させているのを確認します。
kubectl rollout resume deployment.v1.apps/nginx-deployment
実行結果は以下のとおりです。
deployment.apps/nginx-deployment resumed
更新処理が完了するまでロールアウトのステータスを確認します。
実行結果は以下のとおりです。
NAME DESIRED CURRENT READY AGE
nginx-2142116321 2 2 2 2m
nginx-3926361531 2 2 0 6s
nginx-3926361531 2 2 1 18s
nginx-2142116321 1 2 2 2m
nginx-2142116321 1 2 2 2m
nginx-3926361531 3 2 1 18s
nginx-3926361531 3 2 1 18s
nginx-2142116321 1 1 1 2m
nginx-3926361531 3 3 1 18s
nginx-3926361531 3 3 2 19s
nginx-2142116321 0 1 1 2m
nginx-2142116321 0 1 1 2m
nginx-2142116321 0 0 0 2m
nginx-3926361531 3 3 3 20s
最新のロールアウトのステータスを確認します。
実行結果は以下のとおりです。
NAME DESIRED CURRENT READY AGE
nginx-2142116321 0 0 0 2m
nginx-3926361531 3 3 3 28s
備考: Deploymentの稼働を再開させない限り、一時停止したDeploymentをロールバックすることはできません。Deploymentのステータス Deploymentは、そのライフサイクルの間に様々な状態に遷移します。新しいReplicaSetへのロールアウト中は進行中 になり、その後は完了 し、また失敗 にもなります。
Deploymentの更新処理 以下のタスクが実行中のとき、KubernetesはDeploymentの状態を 進行中 にします。
Deploymentが新しいReplicaSetを作成します。 Deploymentが新しいReplicaSetをスケールアップさせています。 Deploymentが古いReplicaSetをスケールダウンさせています。 新しいPodが準備中もしくは利用可能な状態になります(少なくともMinReadySeconds の間は準備中になります)。 kubectl rollout status
を実行すると、Deploymentの進行状態を確認できます。
Deploymentの更新処理の完了 Deploymentが以下の状態になったとき、KubernetesはDeploymentのステータスを 完了 にします。
Deploymentの全てのレプリカが、指定された最新のバージョンに更新されます。これは指定した更新処理が完了したことを意味します。 Deploymentの全てのレプリカが利用可能になります。 Deploymentの古いレプリカが1つも稼働していません。 kubectl rollout status
を実行して、Deploymentの更新が完了したことを確認できます。ロールアウトが正常に完了するとkubectl rollout status
の終了コードが0で返されます。
kubectl rollout status deployment.v1.apps/nginx-deployment
実行結果は以下のとおりです。
Waiting for rollout to finish: 2 of 3 updated replicas are available...
deployment "nginx-deployment" successfully rolled out
そしてkubectl rollout
の終了ステータスが0となります(成功です):
0
Deploymentの更新処理の失敗 新しいReplicaSetのデプロイが完了せず、更新処理が止まる場合があります。これは主に以下の要因によるものです。
不十分なリソースの割り当て ReadinessProbeの失敗 コンテナイメージの取得ができない 不十分なパーミッション リソースリミットのレンジ アプリケーションランタイムの設定の不備 このような状況を検知する1つの方法として、Deploymentのリソース定義でデッドラインのパラメーターを指定します(.spec.progressDeadlineSeconds
)。.spec.progressDeadlineSeconds
はDeploymentの更新が停止したことを示す前にDeploymentコントローラーが待つ秒数を示します。
以下のkubectl
コマンドでリソース定義にprogressDeadlineSeconds
を設定します。これはDeploymentの更新が止まってから10分後に、コントローラーが失敗を通知させるためです。
kubectl patch deployment.v1.apps/nginx-deployment -p '{"spec":{"progressDeadlineSeconds":600}}'
実行結果は以下のとおりです。
deployment.apps/nginx-deployment patched
一度デッドラインを超過すると、DeploymentコントローラーはDeploymentの.status.conditions
に以下のDeploymentConditionを追加します。
Type=Progressing Status=False Reason=ProgressDeadlineExceeded ステータスの状態に関するさらなる情報はKubernetes APIの規則 を参照してください。
備考: Kubernetesは停止状態のDeploymentに対して、ステータス状態を報告する以外のアクションを実行しません。高レベルのオーケストレーターはこれを利用して、状態に応じて行動できます。例えば、前のバージョンへのDeploymentのロールバックが挙げられます。
備考: Deploymentを停止すると、Kubernetesは指定したデッドラインを超えたかどうかチェックしません。
ロールアウトの途中でもDeploymentを安全に一時停止でき、デッドラインを超えたイベントをトリガーすることなく再開できます。設定したタイムアウトの秒数が小さかったり、一時的なエラーとして扱える他の種類のエラーが原因となり、Deploymentで一時的なエラーが出る場合があります。例えば、リソースの割り当てが不十分な場合を考えます。Deploymentの詳細情報を確認すると、以下のセクションが表示されます。
kubectl describe deployment nginx-deployment
実行結果は以下のとおりです。
<...>
Conditions:
Type Status Reason
---- ------ ------
Available True MinimumReplicasAvailable
Progressing True ReplicaSetUpdated
ReplicaFailure True FailedCreate
<...>
kubectl get deployment nginx-deployment -o yaml
を実行すると、Deploymentのステータスは以下のようになります。
status:
availableReplicas: 2
conditions:
- lastTransitionTime: 2016-10-04T12:25:39Z
lastUpdateTime: 2016-10-04T12:25:39Z
message: Replica set "nginx-deployment-4262182780" is progressing.
reason: ReplicaSetUpdated
status: "True"
type: Progressing
- lastTransitionTime: 2016-10-04T12:25:42Z
lastUpdateTime: 2016-10-04T12:25:42Z
message: Deployment has minimum availability.
reason: MinimumReplicasAvailable
status: "True"
type: Available
- lastTransitionTime: 2016-10-04T12:25:39Z
lastUpdateTime: 2016-10-04T12:25:39Z
message: 'Error creating: pods "nginx-deployment-4262182780-" is forbidden: exceeded quota:
object-counts, requested: pods=1, used: pods=3, limited: pods=2'
reason: FailedCreate
status: "True"
type: ReplicaFailure
observedGeneration: 3
replicas: 2
unavailableReplicas: 2
最後に、一度Deploymentの更新処理のデッドラインを越えると、KubernetesはDeploymentのステータスと進行中の状態を更新します。
Conditions:
Type Status Reason
---- ------ ------
Available True MinimumReplicasAvailable
Progressing False ProgressDeadlineExceeded
ReplicaFailure True FailedCreate
Deploymentか他のリソースコントローラーのスケールダウンを行うか、使用している名前空間内でリソースの割り当てを増やすことで、リソースの割り当て不足の問題に対処できます。割り当て条件を満たすと、DeploymentコントローラーはDeploymentのロールアウトを完了させ、Deploymentのステータスが成功状態になるのを確認できます(Status=True
とReason=NewReplicaSetAvailable
)。
Conditions:
Type Status Reason
---- ------ ------
Available True MinimumReplicasAvailable
Progressing True NewReplicaSetAvailable
Status=True
のType=Available
は、Deploymentが最小可用性の状態であることを意味します。最小可用性は、Deploymentの更新戦略において指定されているパラメーターにより決定されます。Status=True
のType=Progressing
は、Deploymentのロールアウトの途中で、更新処理が進行中であるか、更新処理が完了し、必要な最小数のレプリカが利用可能であることを意味します(各TypeのReason項目を確認してください。このケースでは、Reason=NewReplicaSetAvailable
はDeploymentの更新が完了したことを意味します)。
kubectl rollout status
を実行してDeploymentが更新に失敗したかどうかを確認できます。kubectl rollout status
はDeploymentが更新処理のデッドラインを超えたときに0以外の終了コードを返します。
kubectl rollout status deployment.v1.apps/nginx-deployment
実行結果は以下のとおりです。
Waiting for rollout to finish: 2 out of 3 new replicas have been updated...
error: deployment "nginx" exceeded its progress deadline
そしてkubectl rollout
の終了ステータスが1となります(エラーを示しています):
1
失敗したDeploymentの操作 更新完了したDeploymentに適用した全てのアクションは、更新失敗したDeploymentに対しても適用されます。スケールアップ、スケールダウンができ、前のリビジョンへのロールバックや、Deploymentのテンプレートに複数の更新を適用させる必要があるときは一時停止もできます。
古いリビジョンのクリーンアップポリシー Deploymentが管理する古いReplicaSetをいくつ保持するかを指定するために、.spec.revisionHistoryLimit
フィールドを設定できます。この値を超えた古いReplicaSetはバックグラウンドでガーベージコレクションの対象となって削除されます。デフォルトではこの値は10です。
備考: このフィールドを明示的に0に設定すると、Deploymentの全ての履歴を削除します。従って、Deploymentはロールバックできません。カナリアパターンによるデプロイ Deploymentを使って一部のユーザーやサーバーに対してリリースのロールアウトをしたい場合、リソースの管理 に記載されているカナリアパターンに従って、リリース毎に1つずつ、複数のDeploymentを作成できます。
Deployment Specの記述 他の全てのKubernetesの設定と同様に、Deploymentは.apiVersion
、.kind
や.metadata
フィールドを必要とします。
設定ファイルの利用に関する情報はアプリケーションのデプロイ を参照してください。コンテナの設定に関してはリソースを管理するためのkubectlの使用 を参照してください。
Deploymentオブジェクトの名前は、有効なDNSサブドメイン名 でなければなりません。
Deploymentは.spec
セクション も必要とします。
Podテンプレート .spec.template
と.spec.selector
は.spec
における必須のフィールドです。
.spec.template
はPodテンプレート です。これは.spec内でネストされていないことと、apiVersion
やkind
を持たないことを除いてはPod と同じスキーマとなります。
Podの必須フィールドに加えて、Deployment内のPodテンプレートでは適切なラベルと再起動ポリシーを設定しなくてはなりません。ラベルは他のコントローラーと重複しないようにしてください。ラベルについては、セレクター を参照してください。
.spec.template.spec.restartPolicy
がAlways
に等しいときのみ許可されます。これはテンプレートで指定されていない場合のデフォルト値です。
レプリカ数 .spec.replias
は理想的なPodの数を指定するオプションのフィールドです。デフォルトは1です。
セレクター .spec.selector
は必須フィールドで、Deploymentによって対象とされるPodのラベルセレクター を指定します。
.spec.selector
は.spec.template.metadata.labels
と一致している必要があり、一致しない場合はAPIによって拒否されます。
apps/v1
バージョンにおいて、.spec.selector
と.metadata.labels
が指定されていない場合、.spec.template.metadata.labels
の値に初期化されません。そのため.spec.selector
と.metadata.labels
を明示的に指定する必要があります。またapps/v1
のDeploymentにおいて.spec.selector
は作成後に不変になります。
Deploymentのテンプレートが.spec.template
と異なる場合や、.spec.replicas
の値を超えてPodが稼働している場合、Deploymentはセレクターに一致するラベルを持つPodを削除します。Podの数が理想状態より少ない場合Deploymentは.spec.template
をもとに新しいPodを作成します。
備考: Deploymentのセレクターに一致するラベルを持つPodを直接作成したり、他のDeploymentやReplicaSetやReplicationControllerによって作成するべきではありません。作成してしまうと、最初のDeploymentがラベルに一致する新しいPodを作成したとみなされます。こうなったとしても、Kubernetesは処理を止めません。セレクターが重複する複数のコントローラーを持つとき、そのコントローラーは互いに競合状態となり、正しくふるまいません。
更新戦略 .spec.strategy
は古いPodから新しいPodに置き換える際の更新戦略を指定します。.spec.strategy.type
は"Recreate"もしくは"RollingUpdate"を指定できます。デフォルトは"RollingUpdate"です。
Deploymentの再作成 .spec.strategy.type==Recreate
と指定されているとき、既存の全てのPodは新しいPodが作成される前に削除されます。
備考: これは更新のための作成の前にPodを停止する事を保証するだけです。Deploymentを更新する場合、古いリビジョンのPodは全てすぐに停止されます。削除に成功するまでは、新しいリビジョンのPodは作成されません。手動でPodを削除すると、ライフサイクルがReplicaSetに制御されているのですぐに置き換えが実施されます(たとえ古いPodがまだ停止中のステータスでも)。Podに"高々この程度の"保証を求めるならば
StatefulSet の使用を検討してください。
Deploymentのローリングアップデート .spec.strategy.type==RollingUpdate
と指定されているとき、DeploymentはローリングアップデートによりPodを更新します。ローリングアップデートの処理をコントロールするためにmaxUnavailable
とmaxSurge
を指定できます。
Max Unavailable .spec.strategy.rollingUpdate.maxUnavailable
はオプションのフィールドで、更新処理において利用不可となる最大のPod数を指定します。値は絶対値(例: 5)を指定するか、理想状態のPodのパーセンテージを指定します(例: 10%)。パーセンテージを指定した場合、絶対値は小数切り捨てされて計算されます。.spec.strategy.rollingUpdate.maxSurge
が0に指定されている場合、この値を0にできません。デフォルトでは25%です。
例えば、この値が30%と指定されているとき、ローリングアップデートが開始すると古いReplicaSetはすぐに理想状態の70%にスケールダウンされます。一度新しいPodが稼働できる状態になると、古いReplicaSetはさらにスケールダウンされ、続いて新しいReplicaSetがスケールアップされます。この間、利用可能なPodの総数は理想状態のPodの少なくとも70%以上になるように保証されます。
Max Surge .spec.strategy.rollingUpdate.maxSurge
はオプションのフィールドで、理想状態のPod数を超えて作成できる最大のPod数を指定します。値は絶対値(例: 5)を指定するか、理想状態のPodのパーセンテージを指定します(例: 10%)。パーセンテージを指定した場合、絶対値は小数切り上げで計算されます。MaxUnavailable
が0に指定されている場合、この値を0にできません。デフォルトでは25%です。
例えば、この値が30%と指定されているとき、ローリングアップデートが開始すると新しいReplicaSetはすぐに更新されます。このとき古いPodと新しいPodの総数は理想状態の130%を超えないように更新されます。一度古いPodが削除されると、新しいReplicaSetはさらにスケールアップされます。この間、利用可能なPodの総数は理想状態のPodに対して最大130%になるように保証されます。
Progress Deadline Seconds .spec.progressDeadlineSeconds
はオプションのフィールドで、システムがDeploymentの更新に失敗 したと判断するまでに待つ秒数を指定します。更新に失敗したと判断されたとき、リソースのステータスはType=Progressing
、Status=False
かつReason=ProgressDeadlineExceeded
となるのを確認できます。DeploymentコントローラーはDeploymentの更新のリトライし続けます。デフォルト値は600です。今後、自動的なロールバックが実装されたとき、更新失敗状態になるとすぐにDeploymentコントローラーがロールバックを行うようになります。
この値が指定されているとき、.spec.minReadySeconds
より大きい値を指定する必要があります。
Min Ready Seconds .spec.minReadySeconds
はオプションのフィールドで、新しく作成されたPodが利用可能となるために、最低どれくらいの秒数コンテナがクラッシュすることなく稼働し続ければよいかを指定するものです。デフォルトでは0です(Podは作成されるとすぐに利用可能と判断されます)。Podが利用可能と判断された場合についてさらに学ぶためにContainer Probes を参照してください。
リビジョン履歴の保持上限 Deploymentのリビジョン履歴は、Deploymentが管理するReplicaSetに保持されています。
.spec.revisionHistoryLimit
はオプションのフィールドで、ロールバック可能な古いReplicaSetの数を指定します。この古いReplicaSetはetcd
内のリソースを消費し、kubectl get rs
の出力結果を見にくくします。Deploymentの各リビジョンの設定はReplicaSetに保持されます。このため一度古いReplicaSetが削除されると、そのリビジョンのDeploymentにロールバックすることができなくなります。デフォルトでは10もの古いReplicaSetが保持されます。しかし、この値の最適値は新しいDeploymentの更新頻度と安定性に依存します。
さらに詳しく言うと、この値を0にすると、0のレプリカを持つ古い全てのReplicaSetが削除されます。このケースでは、リビジョン履歴が完全に削除されているため新しいDeploymentのロールアウトを元に戻すことができません。
paused .spec.paused
はオプションのboolean値で、Deploymentの一時停止と再開のための値です。一時停止されているものと、そうでないものとの違いは、一時停止されているDeploymentはPodTemplateSpecのいかなる変更があってもロールアウトがトリガーされないことです。デフォルトではDeploymentは一時停止していない状態で作成されます。
4.2.2 - ReplicaSet ReplicaSetの目的は、どのような時でも安定したレプリカPodのセットを維持することです。これは、理想的なレプリカ数のPodが利用可能であることを保証するものとして使用されます。
ReplicaSetがどのように動くか ReplicaSetは、ReplicaSetが対象とするPodをどう特定するかを示すためのセレクターや、稼働させたいPodのレプリカ数、Podテンプレート(理想のレプリカ数の条件を満たすために作成される新しいPodのデータを指定するために用意されるもの)といったフィールドとともに定義されます。ReplicaSetは、指定された理想のレプリカ数にするためにPodの作成と削除を行うことにより、その目的を達成します。ReplicaSetが新しいPodを作成するとき、ReplicaSetはそのPodテンプレートを使用します。
ReplicaSetがそのPod群と連携するためのリンクは、Podのmetadata.ownerReferences というフィールド(現在のオブジェクトが所有されているリソースを指定する)を介して作成されます。ReplicaSetによって所持された全てのPodは、それらのownerReferences
フィールドにReplicaSetを特定する情報を保持します。このリンクを通じて、ReplicaSetは管理しているPodの状態を把握したり、その後の実行計画を立てます。
ReplicaSetは、そのセレクターを使用することにより、所有するための新しいPodを特定します。もしownerReference
フィールドの値を持たないPodか、ownerReference
フィールドの値が コントローラー でないPodで、そのPodがReplicaSetのセレクターとマッチした場合に、そのPodは即座にそのReplicaSetによって所有されます。
ReplicaSetを使うとき ReplicaSetはどんな時でも指定された数のPodのレプリカが稼働することを保証します。しかし、DeploymentはReplicaSetを管理する、より上位レベルの概念で、Deploymentはその他の多くの有益な機能と共に、宣言的なPodのアップデート機能を提供します。それゆえ、我々はユーザーが独自のアップデートオーケストレーションを必要としたり、アップデートを全く必要としないような場合を除いて、ReplicaSetを直接使うよりも代わりにDeploymentを使うことを推奨します。
これは、ユーザーがReplicaSetのオブジェクトを操作する必要が全く無いことを意味します。
代わりにDeploymentを使用して、spec
セクションにユーザーのアプリケーションを定義してください。
ReplicaSetの使用例 apiVersion : apps/v1
kind : ReplicaSet
metadata :
name : frontend
labels :
app : guestbook
tier : frontend
spec :
# ケースに応じてレプリカを修正する
replicas : 3
selector :
matchLabels :
tier : frontend
template :
metadata :
labels :
tier : frontend
spec :
containers :
- name : php-redis
image : gcr.io/google_samples/gb-frontend:v3
上記のマニフェストをfrontend.yaml
ファイルに保存しKubernetesクラスターに適用すると、マニフェストに定義されたReplicaSetとそれが管理するPod群を作成します。
kubectl apply -f http://k8s.io/examples/controllers/frontend.yaml
ユーザーはデプロイされた現在のReplicaSetの情報も取得できます。
そして、ユーザーが作成したfrontendリソースについての情報も取得できます。
NAME DESIRED CURRENT READY AGE
frontend 3 3 3 6s
ユーザーはまたReplicaSetの状態も確認できます。
kubectl describe rs/frontend
その結果は以下のようになります。
Name: frontend
Namespace: default
Selector: tier=frontend
Labels: app=guestbook
tier=frontend
Annotations: kubectl.kubernetes.io/last-applied-configuration:
{"apiVersion":"apps/v1","kind":"ReplicaSet","metadata":{"annotations":{},"labels":{"app":"guestbook","tier":"frontend"},"name":"frontend",...
Replicas: 3 current / 3 desired
Pods Status: 3 Running / 0 Waiting / 0 Succeeded / 0 Failed
Pod Template:
Labels: tier=frontend
Containers:
php-redis:
Image: gcr.io/google_samples/gb-frontend:v3
Port: <none>
Host Port: <none>
Environment: <none>
Mounts: <none>
Volumes: <none>
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal SuccessfulCreate 117s replicaset-controller Created pod: frontend-wtsmm
Normal SuccessfulCreate 116s replicaset-controller Created pod: frontend-b2zdv
Normal SuccessfulCreate 116s replicaset-controller Created pod: frontend-vcmts
そして最後に、ユーザーはReplicaSetによって作成されたPodもチェックできます。
表示されるPodに関する情報は以下のようになります。
NAME READY STATUS RESTARTS AGE
frontend-b2zdv 1/1 Running 0 6m36s
frontend-vcmts 1/1 Running 0 6m36s
frontend-wtsmm 1/1 Running 0 6m36s
ユーザーはまた、それらのPodのownerReferences
がfrontend
ReplicaSetに設定されていることも確認できます。
これを確認するためには、稼働しているPodの中のどれかのyamlファイルを取得します。
kubectl get pods frontend-b2zdv -o yaml
その表示結果は、以下のようになります。そのfrontend
ReplicaSetの情報がmetadata
のownerReferences
フィールドにセットされています。
apiVersion : v1
kind : Pod
metadata :
creationTimestamp : "2020-02-12T07:06:16Z"
generateName : frontend-
labels :
tier : frontend
name : frontend-b2zdv
namespace : default
ownerReferences :
- apiVersion : apps/v1
blockOwnerDeletion : true
controller : true
kind : ReplicaSet
name : frontend
uid : f391f6db-bb9b-4c09-ae74-6a1f77f3d5cf
...
テンプレートなしのPodの所有 ユーザーが問題なくベアPod(Bare Pod: ここではPodテンプレート無しのPodのこと)を作成しているとき、そのベアPodがユーザーのReplicaSetの中のいずれのセレクターともマッチしないことを確認することを強く推奨します。
この理由として、ReplicaSetは、所有対象のPodがReplicaSetのテンプレートによって指定されたPodのみに限定されていないからです(ReplicaSetは前のセクションで説明した方法によって他のPodも所有できます)。
前のセクションで取り上げたfrontend
ReplicaSetと、下記のマニフェストのPodをみてみます。
apiVersion : v1
kind : Pod
metadata :
name : pod1
labels :
tier : frontend
spec :
containers :
- name : hello1
image : gcr.io/google-samples/hello-app:2.0
---
apiVersion : v1
kind : Pod
metadata :
name : pod2
labels :
tier : frontend
spec :
containers :
- name : hello2
image : gcr.io/google-samples/hello-app:1.0
これらのPodはownerReferences
に何のコントローラー(もしくはオブジェクト)も指定されておらず、そしてfrontend
ReplicaSetにマッチするセレクターをもっており、これらのPodは即座にfrontend
ReplicaSetによって所有されます。
このfrontend
ReplicaSetがデプロイされ、初期のPodレプリカがレプリカ数の要求を満たすためにセットアップされた後で、ユーザーがそのPodを作成することを考えます。
kubectl apply -f http://k8s.io/examples/pods/pod-rs.yaml
新しいPodはそのReplicaSetによって所有され、そのReplicaSetのレプリカ数が、設定された理想のレプリカ数を超えた場合すぐにそれらのPodは削除されます。
下記のコマンドでPodを取得できます。
その表示結果で、新しいPodがすでに削除済みか、削除中のステータスになっているのを確認できます。
NAME READY STATUS RESTARTS AGE
frontend-b2zdv 1/1 Running 0 10m
frontend-vcmts 1/1 Running 0 10m
frontend-wtsmm 1/1 Running 0 10m
pod1 0/1 Terminating 0 1s
pod2 0/1 Terminating 0 1s
もしユーザーがそのPodを最初に作成する場合
kubectl apply -f http://k8s.io/examples/pods/pod-rs.yaml
そしてその後にfrontend
ReplicaSetを作成すると、
kubectl apply -f http://k8s.io/examples/controllers/frontend.yaml
ユーザーはそのReplicaSetが作成したPodを所有し、さらにもともと存在していたPodと今回新たに作成されたPodの数が、理想のレプリカ数になるまでPodを作成するのを確認できます。
ここでまたPodの状態を取得します。
取得結果は下記のようになります。
NAME READY STATUS RESTARTS AGE
frontend-hmmj2 1/1 Running 0 9s
pod1 1/1 Running 0 36s
pod2 1/1 Running 0 36s
この方法で、ReplicaSetはテンプレートで指定されたもの以外のPodを所有することができます。
ReplicaSetのマニフェストを記述する。 他の全てのKubernetes APIオブジェクトのように、ReplicaSetはapiVersion
、kind
とmetadata
フィールドを必要とします。
ReplicaSetでは、kind
フィールドの値はReplicaSet
です。
ReplicaSetオブジェクトの名前は、有効な
DNSサブドメイン名 である必要があります。
また、ReplicaSetは.spec
セクション も必須です。
Pod テンプレート .spec.template
はラベルを持つことが必要なPodテンプレート です。先ほど作成したfrontend.yaml
の例では、tier: frontend
というラベルを1つ持っています。
他のコントローラーがこのPodを所有しようとしないためにも、他のコントローラーのセレクターでラベルを上書きしないように注意してください。
テンプレートの再起動ポリシー のためのフィールドである.spec.template.spec.restartPolicy
はAlways
のみ許可されていて、そしてそれがデフォルト値です。
Pod セレクター .spec.selector
フィールドはラベルセレクター です。
先ほど 議論したように、ReplicaSetが所有するPodを指定するためにそのラベルが使用されます。
先ほどのfrontend.yaml
の例では、そのセレクターは下記のようになっていました
matchLabels :
tier : frontend
そのReplicaSetにおいて、.spec.template.metadata.labels
フィールドの値はspec.selector
と一致しなくてはならず、一致しない場合はAPIによって拒否されます。
備考: 2つのReplicaSetが同じ.spec.selector
の値を設定しているが、それぞれ異なる.spec.template.metadata.labels
と.spec.template.spec
フィールドの値を持っていたとき、それぞれのReplicaSetはもう一方のReplicaSetによって作成されたPodを無視します。レプリカ数について ユーザーは.spec.replicas
フィールドの値を設定することにより、いくつのPodを同時に稼働させるか指定できます。そのときReplicaSetはレプリカ数がこの値に達するまでPodを作成、または削除します。
もしユーザーが.spec.replicas
を指定しない場合、デフォルト値として1がセットされます。
ReplicaSetを利用する ReplicaSetとPodの削除 ReplicaSetとそれが所有する全てのPod削除したいときは、kubectl delete
コマンドを使ってください。ガベージコレクター がデフォルトで自動的に全ての依存するPodを削除します。
REST APIもしくはclient-go
ライブラリーを使用するとき、ユーザーは-d
オプションでpropagationPolicy
をBackground
かForeground
と指定しなくてはなりません。例えば下記のように実行します。
kubectl proxy --port= 8080
curl -X DELETE 'localhost:8080/apis/apps/v1/namespaces/default/replicasets/frontend' \
> -d '{"kind":"DeleteOptions","apiVersion":"v1","propagationPolicy":"Foreground"}' \
> -H "Content-Type: application/json"
ReplicaSetのみを削除する ユーザーはkubectl delete
コマンドで--cascade=false
オプションを付けることにより、所有するPodに影響を与えることなくReplicaSetを削除できます。
REST APIもしくはclient-go
ライブラリーを使用するとき、ユーザーは-d
オプションでpropagationPolicy
をOrphan
と指定しなくてはなりません。
例えば下記のように実行します:
kubectl proxy --port= 8080
curl -X DELETE 'localhost:8080/apis/apps/v1/namespaces/default/replicasets/frontend' \
> -d '{"kind":"DeleteOptions","apiVersion":"v1","propagationPolicy":"Orphan"}' \
> -H "Content-Type: application/json"
一度元のReplicaSetが削除されると、ユーザーは新しいものに置き換えるため新しいReplicaSetを作ることができます。新旧のReplicaSetの.spec.selector
の値が同じである間、新しいReplicaSetは古いReplicaSetで稼働していたPodを取り入れます。
しかし、存在するPodが新しく異なるPodテンプレートとマッチさせようとするとき、この仕組みは機能しません。
ReplicaSetはローリングアップデートを直接サポートしないため、ユーザーのコントロール下においてPodを新しいspecにアップデートしたい場合は、Deployment を使用してください。
PodをReplicaSetから分離させる ユーザーはPodのラベルを変更することにより、ReplicaSetからそのPodを削除できます。この手法はデバッグや、データ修復などのためにサービスからPodを削除したいときに使用できます。
この方法で削除されたPodは自動的に新しいものに置き換えられます。(レプリカ数は変更されないものと仮定します。)
ReplicaSetのスケーリング ReplicaSetは、ただ.spec.replicas
フィールドを更新することによって簡単にスケールアップまたはスケールダウンできます。ReplicaSetコントローラーは、ラベルセレクターにマッチするような指定した数のPodが利用可能であり、操作可能であることを保証します。
スケールダウンする場合、ReplicaSetコントローラーは以下の一般的なアルゴリズムに基づき、利用可能なPodをソートし、スケールダウンするPodの優先順位を付け、削除するPodを選択します:
保留している(またはスケジュール不可な)Podが先にスケールダウンされます。 controller.kubernetes.io/pod-deletion-cost
アノテーションが設定されている場合、値の小さいPodが優先されます。レプリカ数の多いノード上のPodが、レプリカ数の少ないノード上のPodより優先されます。 Podの作成時間が異なる場合、より新しく作成されたPodが古いPodより優先されます(LogarithmicScaleDown
フィーチャーゲート が有効の場合、作成時間は整数対数スケールでバケット化されます)。 上記条件のすべてに該当する場合は、ランダム選択となります。
Pod削除コスト FEATURE STATE:
Kubernetes v1.22 [beta]
controller.kubernetes.io/pod-deletion-cost
アノテーションを使用すると、ReplicaSetをスケールダウンする際に、どのPodを最初に削除するかについて、ユーザーが優先順位を設定することができます。
アノテーションはPodに設定する必要があり、範囲は[-2147483648, 2147483647]になります。同じReplicaSetに属する他のPodと比較して、Podを削除する際のコストを表しています。削除コストの低いPodは、削除コストの高いPodより優先的に削除されます。
このアノテーションを設定しないPodは暗黙的に0と設定され、負の値は許容されます。
無効な値はAPIサーバーによって拒否されます。
この機能はbeta版で、デフォルトで有効になっています。kube-apiserverとkube-controller-managerでフィーチャーゲート PodDeletionCost
を設定することで無効にすることができます。
備考: これはベストエフォートで実行されているもので、Pod削除の順番を保証するものではありません。 ユーザーは、メトリック値に基づいてアノテーションを更新するなど、頻繁に更新することは避けるべきです。APIサーバー上で大量のPodの更新操作を発生させることになるためです。 使用事例 アプリケーションの異なるPodは、異なる使用レベルになる可能性があります。スケールダウンする場合、アプリケーションは使用率の低いPodを削除することを優先しています。Podを頻繁に更新することを避けるため、アプリケーションはスケールダウンする前に一度controller.kubernetes.io/pod-deletion-cost
を更新する必要があります(アノテーションをPod使用レベルに比例する値に設定します)。Spark DeploymentのドライバーPodのように、アプリケーション自体がスケールダウンを制御する場合も機能します。
HorizontalPodAutoscaler(HPA)のターゲットとしてのReplicaSet ReplicaSetはまた、Horizontal Pod Autoscalers (HPA) のターゲットにもなることができます。
これはつまりReplicaSetがHPAによってオートスケールされうることを意味します。
ここではHPAが、前の例で作成したReplicaSetをターゲットにする例を示します。
apiVersion : autoscaling/v1
kind : HorizontalPodAutoscaler
metadata :
name : frontend-scaler
spec :
scaleTargetRef :
kind : ReplicaSet
name : frontend
minReplicas : 3
maxReplicas : 10
targetCPUUtilizationPercentage : 50
このマニフェストをhpa-rs.yaml
に保存し、Kubernetesクラスターに適用すると、レプリケートされたPodのCPU使用量にもとづいてターゲットのReplicaSetをオートスケールするHPAを作成します。
kubectl apply -f https://k8s.io/examples/controllers/hpa-rs.yaml
同様のことを行うための代替案として、kubectl autoscale
コマンドも使用できます。(こちらの方がより簡単です。)
kubectl autoscale rs frontend --max= 10 --min= 3 --cpu-percent= 50
ReplicaSetの代替案 Deployment (推奨) Deployment
はReplicaSetを所有することのできるオブジェクトで、宣言的なサーバサイドのローリングアップデートを介してReplicaSetとPodをアップデートできます。
ReplicaSetは単独で使用可能ですが、現在では、ReplicaSetは主にPodの作成、削除とアップデートを司るためのメカニズムとしてDeploymentによって使用されています。ユーザーがDeploymentを使用するとき、Deploymentによって作成されるReplicaSetの管理について心配する必要はありません。DeploymentはReplicaSetを所有し、管理します。
このため、もしユーザーがReplicaSetを必要とするとき、Deploymentの使用を推奨します。
ベアPod(Bare Pods) ユーザーがPodを直接作成するケースとは異なり、ReplicaSetはNodeの故障やカーネルのアップグレードといった破壊的なNodeのメンテナンスなど、どのような理由に限らず削除または停止されたPodを置き換えます。
このため、我々はもしユーザーのアプリケーションが単一のPodのみ必要とする場合でもReplicaSetを使用することを推奨します。プロセスのスーパーバイザーについても同様に考えると、それは単一Node上での独立したプロセスの代わりに複数のNodeにまたがった複数のPodを監視します。
ReplicaSetは、KubeletのようなNode上のいくつかのエージェントに対して、ローカルのコンテナ再起動を移譲します。
Job PodをPodそれ自身で停止させたいような場合(例えば、バッチ用のジョブなど)は、ReplicaSetの代わりにJob
を使用してください。
DaemonSet マシンの監視やロギングなど、マシンレベルの機能を提供したい場合は、ReplicaSetの代わりにDaemonSet
を使用してください。
これらのPodはマシン自体のライフタイムに紐づいています: そのPodは他のPodが起動する前に、そのマシン上で稼働される必要があり、マシンが再起動またはシャットダウンされるときには、安全に停止されます。
ReplicationController ReplicaSetはReplicationControllers の後継となるものです。
この2つは、ReplicationControllerがラベルについてのユーザーガイド に書かれているように、集合ベース(set-based)のセレクター要求をサポートしていないことを除いては、同じ目的を果たし、同じようにふるまいます。 このように、ReplicaSetはReplicationControllerよりも好まれます。
次の項目 4.2.3 - StatefulSet StatefulSetはステートフルなアプリケーションを管理するためのワークロードAPIです。
StatefulSetはPod のデプロイとスケーリングを管理し、それらのPodの順序と一意性を保証 します。
Deployment のように、StatefulSetは指定したコンテナのspecに基づいてPodを管理します。Deploymentとは異なり、StatefulSetは各Podにおいて管理が大変な同一性を維持します。これらのPodは同一のspecから作成されますが、それらは交換可能ではなく、リスケジュール処理をまたいで維持される永続的な識別子を持ちます。
ワークロードに永続性を持たせるためにストレージボリュームを使いたい場合は、解決策の1つとしてStatefulSetが利用できます。StatefulSet内の個々のPodは障害の影響を受けやすいですが、永続化したPodの識別子は既存のボリュームと障害によって置換された新しいPodの紐付けを簡単にします。
StatefulSetの使用 StatefulSetは下記の1つ以上の項目を要求するアプリケーションにおいて最適です。
安定した一意のネットワーク識別子 安定した永続ストレージ 規則的で安全なデプロイとスケーリング 規則的で自動化されたローリングアップデート 上記において安定とは、Podのスケジュール(または再スケジュール)をまたいでも永続的であることと同義です。
もしアプリケーションが安定したネットワーク識別子と規則的なデプロイや削除、スケーリングを全く要求しない場合、ユーザーはステートレスなレプリカのセットを提供するワークロードを使ってアプリケーションをデプロイするべきです。
Deployment やReplicaSet のようなコントローラーはこのようなステートレスな要求に対して最適です。
制限事項 提供されたPodのストレージは、要求されたstorage class
にもとづいてPersistentVolume Provisioner によってプロビジョンされるか、管理者によって事前にプロビジョンされなくてはなりません。 StatefulSetの削除もしくはスケールダウンをすることにより、StatefulSetに関連したボリュームは削除されません 。 これはデータ安全性のためで、関連するStatefulSetのリソース全てを自動的に削除するよりもたいてい有効です。 StatefulSetは現在、Podのネットワークアイデンティティーに責務をもつためにHeadless Service を要求します。ユーザーはこのServiceを作成する責任があります。 StatefulSetは、StatefulSetが削除されたときにPodの停止を行うことを保証していません。StatefulSetにおいて、規則的で安全なPodの停止を行う場合、削除のために事前にそのStatefulSetの数を0にスケールダウンさせることが可能です。 デフォルト設定のPod管理ポリシー (OrderedReady
)によってローリングアップデート を行う場合、修復のための手動介入 を要求するようなブロークンな状態に遷移させることが可能です。 コンポーネント 下記の例は、StatefulSetのコンポーネントのデモンストレーションとなります。
apiVersion : v1
kind : Service
metadata :
name : nginx
labels :
app : nginx
spec :
ports :
- port : 80
name : web
clusterIP : None
selector :
app : nginx
---
apiVersion : apps/v1
kind : StatefulSet
metadata :
name : web
spec :
selector :
matchLabels :
app : nginx # .spec.template.metadata.labelsの値と一致する必要があります
serviceName : "nginx"
replicas : 3 # by default is 1
template :
metadata :
labels :
app : nginx # .spec.selector.matchLabelsの値と一致する必要があります
spec :
terminationGracePeriodSeconds : 10
containers :
- name : nginx
image : registry.k8s.io/nginx-slim:0.8
ports :
- containerPort : 80
name : web
volumeMounts :
- name : www
mountPath : /usr/share/nginx/html
volumeClaimTemplates :
- metadata :
name : www
spec :
accessModes : [ "ReadWriteOnce" ]
storageClassName : "my-storage-class"
resources :
requests :
storage : 1Gi
上記の例では、
nginxという名前のHeadlessServiceは、ネットワークドメインをコントロールするために使われます。 webという名前のStatefulSetは、specで3つのnginxコンテナのレプリカを持ち、そのコンテナはそれぞれ別のPodで稼働するように設定されています。 volumeClaimTemplatesは、PersistentVolumeプロビジョナーによってプロビジョンされたPersistentVolume を使って安定したストレージを提供します。 StatefulSetの名前は有効な名前 である必要があります。
Podセレクター ユーザーは、StatefulSetの.spec.template.metadata.labels
のラベルと一致させるため、StatefulSetの.spec.selector
フィールドをセットしなくてはなりません。Kubernetes1.8以前では、.spec.selector
フィールドは省略された場合デフォルト値になります。Kubernetes1.8とそれ以降のバージョンでは、ラベルに一致するPodセレクターの指定がない場合はStatefulSetの作成時にバリデーションエラーになります。
Podアイデンティティー StatefulSetのPodは、順番を示す番号、安定したネットワークアイデンティティー、安定したストレージからなる一意なアイデンティティーを持ちます。
そのアイデンティティーはどのNode上にスケジュール(もしくは再スケジュール)されるかに関わらず、そのPodに紐付きます。
順序インデックス N個のレプリカをもったStatefulSetにおいて、StatefulSet内の各Podは、0からはじまりN-1までの整数値を順番に割り当てられ、そのStatefulSetにおいては一意となります。
安定したネットワークID StatefulSet内の各Podは、そのStatefulSet名とPodの順序番号から派生してホストネームが割り当てられます。
作成されたホストネームの形式は$(StatefulSet名)-$(順序番号)
となります。先ほどの上記の例では、web-0,web-1,web-2
という3つのPodが作成されます。
StatefulSetは、PodのドメインをコントロールするためにHeadless Service を使うことができます。
このHeadless Serviceによって管理されたドメインは$(Service名).$(ネームスペース).svc.cluster.local
形式となり、"cluster.local"というのはそのクラスターのドメインとなります。
各Podが作成されると、Podは$(Pod名).$(管理するServiceドメイン名)
に一致するDNSサブドメインを取得し、管理するServiceはStatefulSetのserviceName
で定義されます。
クラスターでのDNSの設定方法によっては、新たに起動されたPodのDNS名をすぐに検索できない場合があります。
この動作は、クラスター内の他のクライアントが、Podが作成される前にそのPodのホスト名に対するクエリーをすでに送信していた場合に発生する可能性があります。
(DNSでは通常)ネガティブキャッシュは、Podの起動後でも、少なくとも数秒間、以前に失敗したルックアップの結果が記憶され、再利用されることを意味します。
Podが作成された後、速やかにPodを検出する必要がある場合は、いくつかのオプションがあります。
DNSルックアップに依存するのではなく、Kubernetes APIに直接(例えばwatchを使って)問い合わせる。 Kubernetes DNS プロバイダーのキャッシュ時間を短縮する(これは現在30秒キャッシュされるようになっているCoreDNSのConfigMapを編集することを意味しています。)。 制限事項 セクションで言及したように、ユーザーはPodのネットワークアイデンティティーのためにHeadless Service を作成する責任があります。
ここで、クラスタードメイン、Service名、StatefulSet名の選択と、それらがStatefulSetのPodのDNS名にどう影響するかの例をあげます。
Cluster Domain Service (ns/name) StatefulSet (ns/name) StatefulSet Domain Pod DNS Pod Hostname cluster.local default/nginx default/web nginx.default.svc.cluster.local web-{0..N-1}.nginx.default.svc.cluster.local web-{0..N-1} cluster.local foo/nginx foo/web nginx.foo.svc.cluster.local web-{0..N-1}.nginx.foo.svc.cluster.local web-{0..N-1} kube.local foo/nginx foo/web nginx.foo.svc.kube.local web-{0..N-1}.nginx.foo.svc.kube.local web-{0..N-1}
備考: クラスタードメインは
その他の設定 がされない限り、
cluster.local
にセットされます。
安定したストレージ StatefulSetで定義された各VolumeClaimTemplateに対して、各Podは1つのPersistentVolumeClaimを受け取ります。上記のnginxの例において、各Podはmy-storage-class
というStorageClassをもち、1GiBのストレージ容量を持った単一のPersistentVolumeを受け取ります。もしStorageClassが指定されていない場合、デフォルトのStorageClassが使用されます。PodがNode上にスケジュール(もしくは再スケジュール)されたとき、そのvolumeMounts
はPersistentVolume Claimに関連したPersistentVolumeをマウントします。
注意点として、PodのPersistentVolume Claimと関連したPersistentVolumeは、PodやStatefulSetが削除されたときに削除されません。
削除する場合は手動で行わなければなりません。
Podのネームラベル StatefulSet コントローラー がPodを作成したとき、Podの名前として、statefulset.kubernetes.io/pod-name
にラベルを追加します。このラベルによってユーザーはServiceにStatefulSet内の指定したPodを割り当てることができます。
デプロイとスケーリングの保証 N個のレプリカをもつStatefulSetにおいて、Podがデプロイされるとき、それらのPodは{0..N-1}の番号で順番に作成されます。 Podが削除されるとき、それらのPodは{N-1..0}の番号で降順に削除されます。 Podに対してスケーリングオプションが適用される前に、そのPodの前の順番の全てのPodがRunningかつReady状態になっていなくてはなりません。 Podが停止される前に、そのPodの番号より大きい番号を持つの全てのPodは完全にシャットダウンされていなくてはなりません。 StatefulSetはpod.Spec.TerminationGracePeriodSeconds
を0に指定すべきではありません。これは不安全で、やらないことを強く推奨します。さらなる説明としては、StatefulSetのPodの強制削除 を参照してください。
上記の例のnginxが作成されたとき、3つのPodはweb-0
、web-1
、web-2
の順番でデプロイされます。web-1
はweb-0
がRunningかつReady状態 になるまでは決してデプロイされないのと、同様にweb-2
はweb-1
がRunningかつReady状態にならないとデプロイされません。もしweb-0
がweb-1
がRunningかつReady状態になった後だが、web-2
が起動する前に失敗した場合、web-2
はweb-0
の再起動が成功し、RunningかつReady状態にならないと再起動されません。
もしユーザーがreplicas=1
といったようにStatefulSetにパッチをあてることにより、デプロイされたものをスケールすることになった場合、web-2
は最初に停止されます。web-1
はweb-2
が完全にシャットダウンされ削除されるまでは、停止されません。もしweb-0
が、web-2
が完全に停止され削除された後だが、web-1
の停止の前に失敗した場合、web-1
はweb-0
がRunningかつReady状態になるまでは停止されません。
Podの管理ポリシー Kubernetes1.7とそれ以降のバージョンでは、StatefulSetは.spec.podManagementPolicy
フィールドを介して、Podの一意性とアイデンティティーを保証します。
OrderedReadyなPod管理 OrderedReady
なPod管理はStatefulSetにおいてデフォルトです。これはデプロイとスケーリングの保証 に記載されている項目の振る舞いを実装します。
並行なPod管理 Parallel
なPod管理は、StatefulSetコントローラーに対して、他のPodが起動や停止される前にそのPodが完全に起動し準備完了になるか停止するのを待つことなく、Podが並行に起動もしくは停止するように指示します。
アップデートストラテジー Kubernetes1.7とそれ以降のバージョンにおいて、StatefulSetの.spec.updateStrategy
フィールドで、コンテナの自動のローリングアップデートの設定やラベル、リソースのリクエストとリミットや、StatefulSet内のPodのアノテーションを指定できます。
OnDelete OnDelete
というアップデートストラテジーは、レガシーな(Kubernetes1.6以前)振る舞いとなります。StatefulSetの.spec.updateStrategy.type
がOnDelete
にセットされていたとき、そのStatefulSetコントローラーはStatefulSet内でPodを自動的に更新しません。StatefulSetの.spec.template
項目の修正を反映した新しいPodの作成をコントローラーに支持するためには、ユーザーは手動でPodを削除しなければなりません。
RollingUpdate RollingUpdate
というアップデートストラテジーは、StatefulSet内のPodに対する自動化されたローリングアップデートの機能を実装します。これは.spec.updateStrategy
フィールドが未指定の場合のデフォルトのストラテジーです。StatefulSetの.spec.updateStrategy.type
がRollingUpdate
にセットされたとき、そのStatefulSetコントローラーは、StatefulSet内のPodを削除し、再作成します。これはPodの停止(Podの番号の降順)と同じ順番で、一度に1つのPodを更新します。コントローラーは、その前のPodの状態がRunningかつReady状態になるまで次のPodの更新を待ちます。
パーティション RollingUpdate
というアップデートストラテジーは、.spec.updateStrategy.rollingUpdate.partition
を指定することにより、パーティションに分けることができます。もしパーティションが指定されていたとき、そのパーティションの値と等しいか、大きい番号を持つPodが更新されます。パーティションの値より小さい番号を持つPodは更新されず、たとえそれらのPodが削除されたとしても、それらのPodは以前のバージョンで再作成されます。もしStatefulSetの.spec.updateStrategy.rollingUpdate.partition
が、.spec.replicas
より大きい場合、.spec.template
への更新はPodに反映されません。
多くのケースの場合、ユーザーはパーティションを使う必要はありませんが、もし一部の更新を行う場合や、カナリー版のバージョンをロールアウトする場合や、段階的ロールアウトを行う場合に最適です。
強制ロールバック デフォルトのPod管理ポリシー (OrderedReady
)によるローリングアップデート を行う際、修復のために手作業が必要な状態にすることが可能です。
もしユーザーが、決してRunningかつReady状態にならないような設定になるようにPodテンプレートを更新した場合(例えば、不正なバイナリや、アプリケーションレベルの設定エラーなど)、StatefulSetはロールアウトを停止し、待機します。
この状態では、Podテンプレートを正常な状態に戻すだけでは不十分です。既知の問題 によって、StatefulSetは元の正常な状態へ戻す前に、壊れたPodがReady状態(決して起こりえない)に戻るのを待ち続けます。
そのテンプレートを戻したあと、ユーザーはまたStatefulSetが異常状態で稼働しようとしていたPodをすべて削除する必要があります。StatefulSetはその戻されたテンプレートを使ってPodの再作成を始めます。
次の項目 4.2.4 - DaemonSet DaemonSet は全て(またはいくつか)のNodeが単一のPodのコピーを稼働させることを保証します。Nodeがクラスターに追加されるとき、PodがNode上に追加されます。Nodeがクラスターから削除されたとき、それらのPodはガーベージコレクターにより除去されます。DaemonSetの削除により、DaemonSetが作成したPodもクリーンアップします。
DaemonSetのいくつかの典型的な使用例は以下の通りです。
クラスターのストレージデーモンを全てのNode上で稼働させる。 ログ集計デーモンを全てのNode上で稼働させる。 Nodeのモニタリングデーモンを全てのNode上で稼働させる。 シンプルなケースとして、各タイプのデーモンにおいて、全てのNodeをカバーする1つのDaemonSetが使用されるケースがあります。さらに複雑な設定では、単一のタイプのデーモン用ですが、異なるフラグや、異なるハードウェアタイプに対するメモリー、CPUリクエストを要求する複数のDaemonSetを使用するケースもあります。
DaemonSet Specの記述 DaemonSetの作成 ユーザーはYAMLファイル内でDaemonSetの設定を記述することができます。例えば、下記のdaemonset.yaml
ファイルではfluentd-elasticsearch
というDockerイメージを稼働させるDaemonSetの設定を記述します。
apiVersion : apps/v1
kind : DaemonSet
metadata :
name : fluentd-elasticsearch
namespace : kube-system
labels :
k8s-app : fluentd-logging
spec :
selector :
matchLabels :
name : fluentd-elasticsearch
template :
metadata :
labels :
name : fluentd-elasticsearch
spec :
tolerations :
- key : node-role.kubernetes.io/master
operator : Exists
effect : NoSchedule
containers :
- name : fluentd-elasticsearch
image : quay.io/fluentd_elasticsearch/fluentd:v2.5.2
resources :
limits :
memory : 200Mi
requests :
cpu : 100m
memory : 200Mi
volumeMounts :
- name : varlog
mountPath : /var/log
- name : varlibdockercontainers
mountPath : /var/lib/docker/containers
readOnly : true
terminationGracePeriodSeconds : 30
volumes :
- name : varlog
hostPath :
path : /var/log
- name : varlibdockercontainers
hostPath :
path : /var/lib/docker/containers
YAMLファイルに基づいてDaemonSetを作成します。
kubectl apply -f https://k8s.io/examples/controllers/daemonset.yaml
必須のフィールド 他の全てのKubernetesの設定と同様に、DaemonSetはapiVersion
、kind
とmetadata
フィールドが必須となります。設定ファイルの活用法に関する一般的な情報は、ステートレスアプリケーションの稼働 、kubectlを用いたオブジェクトの管理 といったドキュメントを参照ください。
DaemonSetオブジェクトの名前は、有効な
DNSサブドメイン名 である必要があります。
また、DaemonSetにおいて.spec
セクションも必須となります。
Podテンプレート .spec.template
は.spec
内での必須のフィールドの1つです。
.spec.template
はPodテンプレート となります。これはフィールドがネストされていて、apiVersion
やkind
をもたないことを除いては、Pod のテンプレートと同じスキーマとなります。
Podに対する必須のフィールドに加えて、DaemonSet内のPodテンプレートは適切なラベルを指定しなくてはなりません(Podセレクター の項目を参照ください)。
DaemonSet内のPodテンプレートでは、RestartPolicy
フィールドを指定せずにデフォルトのAlways
を使用するか、明示的にAlways
を設定するかのどちらかである必要があります。
Podセレクター .spec.selector
フィールドはPodセレクターとなります。これはJob の.spec.selector
と同じものです。
ユーザーは.spec.template
のラベルにマッチするPodセレクターを指定しなくてはいけません。
また、一度DaemonSetが作成されると、その.spec.selector
は変更不可能になります。Podセレクターの変更は、意図しないPodの孤立を引き起こし、ユーザーにとってやっかいなものとなります。
.spec.selector
は2つのフィールドからなるオブジェクトです。
matchLabels
- ReplicationController の.spec.selector
と同じように機能します。matchExpressions
- キーと、値のリストとさらにはそれらのキーとバリューに関連したオペレーターを指定することにより、より洗練された形式のセレクターを構成できます。上記の2つが指定された場合は、2つの条件をANDでどちらも満たすものを結果として返します。
spec.selector
は.spec.template.metadata.labels
とマッチしなければなりません。この2つの値がマッチしない設定をした場合、APIによってリジェクトされます。
選択したNode上でPodを稼働させる もしユーザーが.spec.template.spec.nodeSelector
を指定したとき、DaemonSetコントローラーは、そのnode selector にマッチするNode上にPodを作成します。同様に、もし.spec.template.spec.affinity
を指定したとき、DaemonSetコントローラーはnode affinity にマッチするNode上にPodを作成します。
もしユーザーがどちらも指定しないとき、DaemonSetコントローラーは全てのNode上にPodを作成します。
Daemon Podがどのようにスケジューリングされるか DaemonSetは、全ての利用可能なNodeがPodのコピーを稼働させることを保証します。DaemonSetコントローラーは対象となる各Nodeに対してPodを作成し、ターゲットホストに一致するようにPodのspec.affinity.nodeAffinity
フィールドを追加します。Podが作成されると、通常はデフォルトのスケジューラーが引き継ぎ、.spec.nodeName
を設定することでPodをターゲットホストにバインドします。新しいNodeに適合できない場合、デフォルトスケジューラーは新しいPodの優先度 に基づいて、既存Podのいくつかを先取り(退避)させることがあります。
ユーザーは、DaemonSetの.spec.template.spec.schedulerName
フィールドを設定することにより、DaemonSetのPodに対して異なるスケジューラーを指定することができます。
.spec.template.spec.affinity.nodeAffinity
フィールド(指定された場合)で指定された元のNodeアフィニティは、DaemonSetコントローラーが対象Nodeを評価する際に考慮されますが、作成されたPod上では対象Nodeの名前と一致するNodeアフィニティに置き換わります。
nodeAffinity :
requiredDuringSchedulingIgnoredDuringExecution :
nodeSelectorTerms :
- matchFields :
- key : metadata.name
operator : In
values :
- target-host-name
TaintとToleration DaemonSetコントローラーはDaemonSet Podに一連のToleration を自動的に追加します:
DaemonSetのPodテンプレートで定義すれば、DaemonSetのPodに独自のTolerationを追加することも可能です。
DaemonSetコントローラーはnode.kubernetes.io/unschedulable:NoSchedule
のTolerationを自動的に設定するため、Kubernetesは スケジューリング不可能 としてマークされているNodeでDaemonSet Podを実行することが可能です。
クラスターのネットワーク のような重要なNodeレベルの機能をDaemonSetで提供する場合、KubernetesがDaemonSet PodをNodeが準備完了になる前に配置することは有用です。
例えば、その特別なTolerationがなければ、ネットワークプラグインがそこで実行されていないためにNodeが準備完了としてマークされず、同時にNodeがまだ準備完了でないためにそのNode上でネットワークプラグインが実行されていないというデッドロック状態に陥ってしまう可能性があるのです。
Daemon Podとのコミュニケーション DaemonSet内のPodとのコミュニケーションをする際に考えられるパターンは以下の通りです:
Push : DaemonSet内のPodは統計データベースなどの他のサービスに対して更新情報を送信するように設定されます。クライアントは持っていません。NodeIPとKnown Port : PodがNodeIPを介して疎通できるようにするため、DaemonSet内のPodはhostPort
を使用できます。慣例により、クライアントはNodeIPのリストとポートを知っています。DNS : 同じPodセレクターを持つHeadlessService を作成し、endpoints
リソースを使ってDaemonSetを探すか、DNSから複数のAレコードを取得します。Service : 同じPodセレクターを持つServiceを作成し、複数のうちのいずれかのNode上のDaemonに疎通させるためにそのServiceを使います。(特定のNodeにアクセスする方法はありません。)DaemonSetの更新 もしNodeラベルが変更されたとき、そのDaemonSetは直ちに新しくマッチしたNodeにPodを追加し、マッチしなくなったNodeからPodを削除します。
ユーザーはDaemonSetが作成したPodを修正可能です。しかし、Podは全てのフィールドの更新を許可していません。また、DaemonSetコントローラーは次のNode(同じ名前でも)が作成されたときにオリジナルのテンプレートを使ってPodを作成します。
ユーザーはDaemonSetを削除可能です。kubectl
コマンドで--cascade=orphan
を指定するとDaemonSetのPodはNode上に残り続けます。その後、同じセレクターで新しいDaemonSetを作成すると、新しいDaemonSetは既存のPodを再利用します。PodでDaemonSetを置き換える必要がある場合は、updateStrategy
に従ってそれらを置き換えます。
ユーザーはDaemonSet上でローリングアップデートの実施 が可能です。
DaemonSetの代替案 Initスクリプト Node上で直接起動することにより(例: init
、upstartd
、systemd
を使用する)、デーモンプロセスを稼働することが可能です。この方法は非常に良いですが、このようなプロセスをDaemonSetを介して起動することはいくつかの利点があります。
アプリケーションと同じ方法でデーモンの監視とログの管理ができる。 デーモンとアプリケーションで同じ設定用の言語とツール(例: Podテンプレート、kubectl
)を使える。 リソースリミットを使ったコンテナ内でデーモンを稼働させることにより、デーモンとアプリケーションコンテナの分離性が高まります。ただし、これはPod内ではなく、コンテナ内でデーモンを稼働させることでも可能です。 ベアPod 特定のNode上で稼働するように指定したPodを直接作成することは可能です。しかし、DaemonSetはNodeの故障やNodeの破壊的なメンテナンスやカーネルのアップグレードなど、どのような理由に限らず、削除されたもしくは停止されたPodを置き換えます。このような理由で、ユーザーはPod単体を作成するよりもむしろDaemonSetを使うべきです。
静的Pod Kubeletによって監視されているディレクトリに対してファイルを書き込むことによって、Podを作成することが可能です。これは静的Pod と呼ばれます。DaemonSetと違い、静的Podはkubectlや他のKubernetes APIクライアントで管理できません。静的PodはApiServerに依存しておらず、クラスターの自立起動時に最適です。また、静的Podは将来的には廃止される予定です。
Deployment DaemonSetは、Podの作成し、そのPodが停止されることのないプロセスを持つことにおいてDeployment と同様です(例: webサーバー、ストレージサーバー)。
フロントエンドのようなServiceのように、どのホスト上にPodが稼働するか制御するよりも、レプリカ数をスケールアップまたはスケールダウンしたりローリングアップデートする方が重要であるような、状態をもたないServiceに対してDeploymentを使ってください。
DaemonSetがNodeレベルの機能を提供し、他のPodがその特定のNodeで正しく動作するようにする場合、Podのコピーが全てまたは特定のホスト上で常に稼働していることが重要な場合にDaemonSetを使ってください。
例えば、ネットワークプラグイン には、DaemonSetとして動作するコンポーネントが含まれていることがよくあります。DaemonSetコンポーネントは、それが動作しているNodeでクラスターネットワークが動作していることを確認します。
次の項目 4.2.5 - Job Jobは一つ以上のPodを作成し、指定された数のPodが正常に終了するまで、Podの実行を再試行し続けます。Podが正常に終了すると、Jobは成功したPodの数を追跡します。指定された完了数に達すると、そのタスク(つまりJob)は完了したとみなされます。Jobを削除すると、作成されたPodも一緒に削除されます。Jobを一時停止すると、再開されるまで、稼働しているPodは全部削除されます。
単純なケースを言うと、確実に一つのPodが正常に完了するまで実行されるよう、一つのJobオブジェクトを作成します。
一つ目のPodに障害が発生したり、(例えばノードのハードウェア障害またノードの再起動が原因で)削除されたりすると、Jobオブジェクトは新しいPodを作成します。
Jobで複数のPodを並列で実行することもできます。
スケジュールに沿ってJob(単一のタスクか複数タスク並列のいずれか)を実行したい場合は CronJob を参照してください。
実行例 下記にJobの定義例を記載しています。πを2000桁まで計算して出力するJobで、完了するまで約10秒かかります。
apiVersion : batch/v1
kind : Job
metadata :
name : pi
spec :
template :
spec :
containers :
- name : pi
image : perl:5.34.0
command : ["perl" , "-Mbignum=bpi" , "-wle" , "print bpi(2000)" ]
restartPolicy : Never
backoffLimit : 4
このコマンドで実行できます:
kubectl apply -f https://kubernetes.io/examples/controllers/job.yaml
実行結果はこのようになります:
job.batch/pi created
kubectl
でJobの状態を確認できます:
Name: pi
Namespace: default
Selector: batch.kubernetes.io/controller-uid= c9948307-e56d-4b5d-8302-ae2d7b7da67c
Labels: batch.kubernetes.io/controller-uid= c9948307-e56d-4b5d-8302-ae2d7b7da67c
batch.kubernetes.io/job-name= pi
...
Annotations: batch.kubernetes.io/job-tracking: ""
Parallelism: 1
Completions: 1
Start Time: Mon, 02 Dec 2019 15:20:11 +0200
Completed At: Mon, 02 Dec 2019 15:21:16 +0200
Duration: 65s
Pods Statuses: 0 Running / 1 Succeeded / 0 Failed
Pod Template:
Labels: batch.kubernetes.io/controller-uid= c9948307-e56d-4b5d-8302-ae2d7b7da67c
batch.kubernetes.io/job-name= pi
Containers:
pi:
Image: perl:5.34.0
Port: <none>
Host Port: <none>
Command:
perl
-Mbignum= bpi
-wle
print bpi( 2000)
Environment: <none>
Mounts: <none>
Volumes: <none>
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal SuccessfulCreate 21s job-controller Created pod: pi-xf9p4
Normal Completed 18s job-controller Job completed
apiVersion: batch/v1
kind: Job
metadata:
annotations: batch.kubernetes.io/job-tracking: ""
...
creationTimestamp: "2022-11-10T17:53:53Z"
generation: 1
labels:
batch.kubernetes.io/controller-uid: 863452e6-270d-420e-9b94-53a54146c223
batch.kubernetes.io/job-name: pi
name: pi
namespace: default
resourceVersion: "4751"
uid: 204fb678-040b-497f-9266-35ffa8716d14
spec:
backoffLimit: 4
completionMode: NonIndexed
completions: 1
parallelism: 1
selector:
matchLabels:
batch.kubernetes.io/controller-uid: 863452e6-270d-420e-9b94-53a54146c223
suspend: false
template:
metadata:
creationTimestamp: null
labels:
batch.kubernetes.io/controller-uid: 863452e6-270d-420e-9b94-53a54146c223
batch.kubernetes.io/job-name: pi
spec:
containers:
- command:
- perl
- -Mbignum= bpi
- -wle
- print bpi( 2000)
image: perl:5.34.0
imagePullPolicy: IfNotPresent
name: pi
resources: {}
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
dnsPolicy: ClusterFirst
restartPolicy: Never
schedulerName: default-scheduler
securityContext: {}
terminationGracePeriodSeconds: 30
status:
active: 1
ready: 0
startTime: "2022-11-10T17:53:57Z"
uncountedTerminatedPods: {}
Jobの完了したPodを確認するには、kubectl get pods
を使います。
Jobに属するPodの一覧を機械可読形式で出力するには、下記のコマンドを使います:
pods = $( kubectl get pods --selector= batch.kubernetes.io/job-name= pi --output= jsonpath = '{.items[*].metadata.name}' )
echo $pods
出力結果はこのようになります:
pi-5rwd7
ここのセレクターはJobのセレクターと同じです。--output=jsonpath
オプションは、返されたリストからPodのnameフィールドを指定するための表現です。
その中の一つのPodの標準出力を確認するには:
Jobの標準出力を確認するもう一つの方法は:
出力結果はこのようになります:
3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679821480865132823066470938446095505822317253594081284811174502841027019385211055596446229489549303819644288109756659334461284756482337867831652712019091456485669234603486104543266482133936072602491412737245870066063155881748815209209628292540917153643678925903600113305305488204665213841469519415116094330572703657595919530921861173819326117931051185480744623799627495673518857527248912279381830119491298336733624406566430860213949463952247371907021798609437027705392171762931767523846748184676694051320005681271452635608277857713427577896091736371787214684409012249534301465495853710507922796892589235420199561121290219608640344181598136297747713099605187072113499999983729780499510597317328160963185950244594553469083026425223082533446850352619311881710100031378387528865875332083814206171776691473035982534904287554687311595628638823537875937519577818577805321712268066130019278766111959092164201989380952572010654858632788659361533818279682303019520353018529689957736225994138912497217752834791315155748572424541506959508295331168617278558890750983817546374649393192550604009277016711390098488240128583616035637076601047101819429555961989467678374494482553797747268471040475346462080466842590694912933136770289891521047521620569660240580381501935112533824300355876402474964732639141992726042699227967823547816360093417216412199245863150302861829745557067498385054945885869269956909272107975093029553211653449872027559602364806654991198818347977535663698074265425278625518184175746728909777727938000816470600161452491921732172147723501414419735685481613611573525521334757418494684385233239073941433345477624168625189835694855620992192221842725502542568876717904946016534668049886272327917860857843838279679766814541009538837863609506800642251252051173929848960841284886269456042419652850222106611863067442786220391949450471237137869609563643719172874677646575739624138908658326459958133904780275901
Job spec(仕様)の書き方 他のKubernetesオブジェクト設定ファイルと同様に、JobにもapiVersion
、kind
またはmetadata
フィールドが必要です。
コントロールプレーンがJobのために新しいPodを作成するとき、Jobの.metadata.name
はそれらのPodに名前をつけるための基礎の一部になります。Jobの名前は有効なDNSサブドメイン名 である必要がありますが、これはPodのホスト名に予期しない結果をもたらす可能性があります。最高の互換性を得るためには、名前はDNSラベル のより限定的な規則に従うべきです。名前がDNSサブドメインの場合でも、名前は63文字以下でなければなりません。
Jobには.spec
セクション も必要です。
Jobラベル Jobラベルのjob-name
とcontroller-uid
の接頭辞はbatch.kubernetes.io/
となります。
Podテンプレート .spec.template
は.spec
の唯一の必須フィールドです。
.spec.template
はpodテンプレート です。ネストされていることとapiVersion
やkind
フィールドが不要になったことを除いて、仕様の定義がPod と全く同じです。
Podの必須フィールドに加えて、Job定義ファイルにあるPodテンプレートでは、適切なラベル(podセレクター を参照)と適切な再起動ポリシーを指定する必要があります。
RestartPolicy
はNever
かOnFailure
のみ設定可能です。
Podセレクター .spec.selector
フィールドはオプションです。ほとんどの場合はむしろ指定しないほうがよいです。
独自のPodセレクターを指定 セクションを参照してください。
Jobの並列実行 Jobで実行するのに適したタスクは主に3種類あります:
非並列Job通常、Podに障害が発生しない限り、一つのPodのみが起動されます。 Podが正常に終了すると、Jobはすぐに完了します。 固定の完了数 を持つ並列Job:.spec.completions
に0以外の正の値を指定します。Jobは全体的なタスクを表し、.spec.completions
個のPodが成功すると、Jobの完了となります。 .spec.completionMode="Indexed"
を利用する場合、各Podは0から.spec.completions-1
までの範囲内のインデックスがアサインされます。ワークキュー を利用した並列Job:.spec.completions
の指定をしない場合、デフォルトは.spec.parallelism
となります。Pod間で調整する、または外部サービスを使う方法で、それぞれ何のタスクに着手するかを決めます。例えば、一つのPodはワークキューから最大N個のタスクを一括で取得できます。 各Podは他のPodがすべて終了したかどうか、つまりJobが完了したかどうかを単独で判断できます。 Jobに属する 任意 のPodが正常に終了すると、新しいPodは作成されません。 一つ以上のPodが正常に終了し、すべてのPodが終了すると、Jobは正常に完了します。 一つのPodが正常に終了すると、他のPodは同じタスクの作業を行ったり、出力を書き込んだりすることはできません。すべてのPodが終了プロセスに進む必要があります。 非並列 Jobの場合、.spec.completions
と.spec.parallelism
の両方を未設定のままにしておくことも可能です。未設定の場合、両方がデフォルトで1になります。
完了数固定 Jobの場合、.spec.completions
を必要完了数に設定する必要があります。
.spec.parallelism
を設定してもいいですし、未設定の場合、デフォルトで1になります。
ワークキュー 並列Jobの場合、.spec.completions
を未設定のままにし、.spec.parallelism
を非負の整数に設定する必要があります。
各種類のJobの使用方法の詳細については、Jobパターン セクションを参照してください。
並列処理の制御 必要並列数(.spec.parallelism
)は任意の非負の値に設定できます。
未設定の場合は、デフォルトで1になります。
0に設定した際には、増加するまでJobは一時停止されます。
実際の並列数(任意の瞬間に実行されているPod数)は、さまざまな理由により、必要並列数と異なる可能性があります:
完了数固定 Jobの場合、実際に並列して実行されるPodの数は、残りの完了数を超えることはありません。 .spec.parallelism
の値が高い場合は無視されます。ワークキュー Jobの場合、任意のPodが成功すると、新しいPodは作成されません。ただし、残りのPodは終了まで実行し続けられます。Jobコントローラー の応答する時間がなかった場合。 Jobコントローラーが何らかの理由で(ResourceQuota
の不足、権限の不足など)、Podを作成できない場合、
実際の並列数は必要並列数より少なくなる可能性があります。 同じJobで過去に発生した過度のPod障害が原因で、Jobコントローラーは新しいPodの作成を抑制することがあります。 Podがグレースフルシャットダウンされた場合、停止するのに時間がかかります。 完了モード FEATURE STATE:
Kubernetes v1.24 [stable]
完了数固定 Job、つまり.spec.completions
の値がnullではないJobは.spec.completionMode
で完了モードを指定できます:
NonIndexed
(デフォルト): .spec.completions
個のPodが成功した場合、Jobの完了となります。言い換えれば、各Podの完了状態は同質です。ここで要注意なのは、.spec.completions
の値がnullの場合、暗黙的にNonIndexed
として指定されることです。
Indexed
: Jobに属するPodはそれぞれ、0から.spec.completions-1
の範囲内の完了インデックスを取得できます。インデックスは下記の三つの方法で取得できます。
Podアノテーションbatch.kubernetes.io/job-completion-index
。 Podホスト名の一部として、$(job-name)-$(index)
の形式になっています。
インデックス付きJob(Indexed Job)とService を一緒に使用すると、Jobに属するPodはお互いにDNSを介して確定的ホスト名で通信できます。この設定方法の詳細はPod間通信を使用したJob を参照してください。 コンテナ化されたタスクの環境変数JOB_COMPLETION_INDEX
。 各インデックスに1つずつ正常に完了したPodがあると、Jobは完了したとみなされます。このモードの使い方については、静的な処理の割り当てを使用した並列処理のためのインデックス付きJob を参照してください。
備考: めったに発生しませんが、同じインデックスに対して複数のPodが起動することがあります。(Nodeの障害、kubeletの再起動、Podの立ち退きなど)。この場合、正常に完了した最初のPodだけ完了数にカウントされ、Jobのステータスが更新されます。同じインデックスに対して実行中または完了した他のPodは、検出されるとJobコントローラーによって削除されます。Podとコンテナの障害対策 Pod内のコンテナは、その中のプロセスが0以外の終了コードで終了した、またはメモリ制限を超えたためにコンテナが強制終了されたなど、様々な理由で失敗することがあります。この場合、もし.spec.template.spec.restartPolicy = "OnFailure"
と設定すると、Podはノード上に残りますが、コンテナは再実行されます。そのため、プログラムがローカルで再起動した場合の処理を行うか、.spec.template.spec.restartPolicy = "Never"
と指定する必要があります。
restartPolicy
の詳細についてはPodのライフサイクル を参照してください。
Podがノードからキックされた(ノードがアップグレード、再起動、削除されたなど)、または.spec.template.spec.restartPolicy = "Never"
と設定されたときにPodに属するコンテナが失敗したなど、様々な理由でPod全体が故障することもあります。Podに障害が発生すると、Jobコントローラーは新しいPodを起動します。つまりアプリケーションは新しいPodで再起動された場合の処理を行う必要があります。特に、過去に実行した際に生じた一時ファイル、ロック、不完全な出力などを処理する必要があります。
デフォルトでは、それぞれのPodの失敗は.spec.backoffLimit
にカウントされます。詳しくはPod失敗のバックオフポリシー をご覧ください。しかし、JobのPod失敗ポリシー を設定することで、Pod失敗の処理をカスタマイズすることができます。
.spec.parallelism = 1
、.spec.completions = 1
と.spec.template.spec.restartPolicy = "Never"
を指定しても、同じプログラムが2回起動されることもありますので注意してください。
.spec.parallelism
と.spec.completions
を両方とも2以上指定した場合、複数のPodが同時に実行される可能性があります。そのため、Podは並行処理を行えるようにする必要があります。
フィーチャーゲート のPodDisruptionConditions
とJobPodFailurePolicy
の両方が有効で、.spec.podFailurePolicy
フィールドが設定されている場合、Jobコントローラーは終了するPod(.metadata.deletionTimestamp
フィールドが設定されているPod)を、そのPodが終了する(.status.phase
がFailed
またはSucceeded
になる)までは失敗とはみなしません。ただし、Jobコントローラーは、終了が明らかになるとすみやかに代わりのPodを作成します。Podが終了すると、Jobコントローラーはこの終了したPodを考慮に入れて、該当のJobの.backoffLimit
と.podFailurePolicy
を評価します。
これらの要件のいずれかが満たされていない場合、Jobコントローラーは、そのPodが後にphase: "Succeeded"
で終了する場合でも、終了するPodを即時に失敗として数えます。
Pod失敗のバックオフポリシー 設定の論理エラーなどにより、Jobが数回再試行した後に失敗状態にしたい場合があります。.spec.backoffLimit
を設定すると、失敗したと判断するまでの再試行回数を指定できます。バックオフ制限はデフォルトで6に設定されています。Jobに属していて失敗したPodはJobコントローラーにより再作成され、バックオフ遅延は指数関数的に増加し(10秒、20秒、40秒…)、最大6分まで増加します。
再実行回数の算出方法は以下の2通りです:
.status.phase = "Failed"
で設定されたPod数を計算します。restartPolicy = "OnFailure"
と設定された場合、.status.phase
がPending
またはRunning
であるPodに属するすべてのコンテナで再試行する回数を計算します。どちらかの計算が.spec.backoffLimit
に達した場合、Jobは失敗とみなされます。
JobTrackingWithFinalizers
機能が無効な場合、
失敗したPodの数は、API内にまだ存在するPodのみに基づいています。
備考: restartPolicy = "OnFailure"
が設定されたJobはバックオフ制限に達すると、属するPodは全部終了されるので注意してください。これにより、Jobの実行ファイルのデバッグ作業が難しくなる可能性があります。失敗したJobからの出力が不用意に失われないように、Jobのデバッグ作業をする際はrestartPolicy = "Never"
を設定するか、ロギングシステムを使用することをお勧めします。Pod失敗ポリシー FEATURE STATE:
Kubernetes v1.26 [beta]
備考: クラスターで
JobPodFailurePolicy
フィーチャーゲート が有効になっている場合のみ、Jobに対してPod失敗ポリシーを設定することができます。さらにPod失敗ポリシーでPodの中断条件を検知して処理できるように、
PodDisruptionConditions
フィーチャーゲートを有効にすることが推奨されます。(
Podの中断条件 を参照してください)。どちらのフィーチャーゲートもKubernetes 1.27で利用可能です。
.spec.podFailurePolicy
フィールドで定義されるPod失敗ポリシーを使用すると、コンテナの終了コードとPodの条件に基づいてクラスターがPodの失敗を処理できるようになります。
状況によっては、Podの失敗を処理するときに、Jobの.spec.backoffLimit
に基づいたPod失敗のバックオフポリシー が提供する制御よりも、Podの失敗処理に対してより良い制御を求めるかもしれません。これらはいくつかの使用例です:
不要なPodの再起動を回避してワークロードの実行コストを最適化するために、Podの1つがソフトウェアバグを示す終了コードで失敗するとすぐにJobを終了させることができます。 中断が発生してもJobが完了するように、中断によって発生したPodの失敗(preemption 、APIを起点とした退避 、taint を起点とした立ち退き)を無視し、.spec.backoffLimit
のリトライ回数にカウントしないようにすることができます。 上記のユースケースを満たすために、.spec.podFailurePolicy
フィールドでPod失敗ポリシーを設定できます。このポリシーは、コンテナの終了コードとPodの条件に基づいてPodの失敗を処理できます。
以下は、podFailurePolicy
を定義するJobのマニフェストです:
apiVersion : batch/v1
kind : Job
metadata :
name : job-pod-failure-policy-example
spec :
completions : 12
parallelism : 3
template :
spec :
restartPolicy : Never
containers :
- name : main
image : docker.io/library/bash:5
command : ["bash" ] # example command simulating a bug which triggers the FailJob action
args :
- -c
- echo "Hello world!" && sleep 5 && exit 42
backoffLimit : 6
podFailurePolicy :
rules :
- action : FailJob
onExitCodes :
containerName : main # optional
operator: In # one of : In, NotIn
values : [42 ]
- action: Ignore # one of : Ignore, FailJob, Count
onPodConditions :
- type : DisruptionTarget # indicates Pod disruption
上記の例では、Pod失敗ポリシーの最初のルールは、main
コンテナが42の終了コードで失敗した場合、そのJobを失敗とマークすることを指定しています。以下は特に main
コンテナに関するルールです:
終了コード0はコンテナが成功したことを意味します。 終了コード42はJob全体 が失敗したことを意味します。 それ以外の終了コードは、コンテナが失敗したこと、つまりPod全体が失敗したことを示します。再起動の合計回数がbackoffLimit
未満であれば、Podは再作成されます。backoffLimit
に達した場合、Job全体 が失敗したことになります。
備考: PodテンプレートはrestartPolicy.Never
を指定しているため、kubeletはその特定のPodのmain
コンテナを再起動しません。Pod失敗ポリシーの2つ目のルールでは、DisruptionTarget
という条件で失敗したPodに対してIgnoreアクションを指定することで、Podの中断が.spec.backoffLimit
によるリトライの制限にカウントされないようにします。
備考: Pod失敗ポリシーまたはPod失敗のバックオフポリシーのいずれかによってJobが失敗し、そのJobが複数のPodを実行している場合、KubernetesはそのJob内の保留中または実行中のすべてのPodを終了します。これらはAPIの要件と機能です:
.spec.podFailurePolicy
フィールドをJobに使いたい場合は、.spec.restartPolicy
をNever
に設定してそのJobのPodテンプレートも定義する必要があります。spec.podFailurePolicy.rules
で指定したPod失敗ポリシーのルールが順番に評価されます。あるPodの失敗がルールに一致すると、残りのルールは無視されます。Pod失敗に一致するルールがない場合は、デフォルトの処理が適用されます。spec.podFailurePolicy.rules[*].onExitCodes.containerName
を指定することで、ルールを特定のコンテナに制限することができます。指定しない場合、ルールはすべてのコンテナに適用されます。指定する場合は、Pod テンプレート内のコンテナ名またはinitContainer
名のいずれかに一致する必要があります。Pod失敗ポリシーがspec.podFailurePolicy.rules[*].action
にマッチしたときに実行されるアクションを指定できます。指定可能な値は以下のとおりです。FailJob
: PodのJobをFailed
としてマークし、実行中の Pod をすべて終了させる必要があることを示します。Ignore
: .spec.backoffLimit
のカウンターは加算されず、代替のPodが作成すべきであることを示します。Count
: Podがデフォルトの方法で処理されるべきであることを示します。.spec.backoffLimit
のカウンターが加算されます。 備考: PodFailurePolicy
を使用すると、Jobコントローラーは
Failed
フェーズのPodのみにマッチします。削除タイムスタンプを持つPodで、終了フェーズ(
Failed
または
Succeeded
)にないものは、まだ終了中と見なされます。これは、終了中Podは終了フェーズに達するまで
追跡ファイナライザー を保持することを意味します。Kubernetes 1.27以降、Kubeletは削除されたPodを終了フェーズに遷移させます(参照:
Podのフェーズ )。これにより、削除されたPodはJobコントローラーによってファイナライザーが削除されます。
Jobの終了とクリーンアップ Jobが完了すると、それ以上Podは作成されませんが、通常 Podが削除されることもありません。
これらを残しておくと、完了したPodのログを確認でき、エラーや警告などの診断出力を確認できます。
またJobオブジェクトはJob完了後も残っているため、状態を確認することができます。古いJobの状態を把握した上で、削除するかどうかはユーザー次第です。Jobを削除するにはkubectl
(例:kubectl delete jobs/pi
またはkubectl delete -f ./job.yaml
)を使います。kubectl
でJobを削除する場合、Jobが作成したPodも全部削除されます。
デフォルトでは、Podが失敗しない(restartPolicy=Never
)またはコンテナがエラーで終了しない(restartPolicy=OnFailure
)限り、Jobは中断されることなく実行されます。.spec.backoffLimit
に達するとそのJobは失敗と見なされ、実行中のPodはすべて終了します。
Jobを終了させるもう一つの方法は、活動期間を設定することです。
Jobの.spec.activeDeadlineSeconds
フィールドに秒数を設定することで、活動期間を設定できます。
Podがいくつ作成されても、activeDeadlineSeconds
はJobの存続する時間に適用されます。
JobがactiveDeadlineSeconds
に達すると、実行中のすべてのPodは終了され、Jobの状態はtype: Failed
になり、理由はreason: DeadlineExceeded
になります。
ここで要注意なのは、Jobの.spec.activeDeadlineSeconds
は.spec.backoffLimit
よりも優先されます。したがって、失敗して再試行しているPodが一つ以上持っているJobは、backoffLimit
に達していなくても、activeDeadlineSeconds
で指定された設定時間に達すると、追加のPodをデプロイしなくなります。
例えば:
apiVersion : batch/v1
kind : Job
metadata :
name : pi-with-timeout
spec :
backoffLimit : 5
activeDeadlineSeconds : 100
template :
spec :
containers :
- name : pi
image : perl:5.34.0
command : ["perl" , "-Mbignum=bpi" , "-wle" , "print bpi(2000)" ]
restartPolicy : Never
Job仕様と、Jobに属するPodテンプレートの仕様 は両方ともactiveDeadlineSeconds
フィールドを持っているので注意してください。適切なレベルで設定していることを確認してください。
またrestartPolicy
はJob自体ではなく、Podに適用されることも注意してください: Jobの状態はtype: Failed
になると、自動的に再起動されることはありません。
つまり、.spec.activeDeadlineSeconds
と.spec.backoffLimit
によって引き起こされるJob終了メカニズムは、永久的なJob失敗につながり、手動で介入して解決する必要があります。
終了したJobの自動クリーンアップ 終了したJobは通常システムに残す必要はありません。残ったままにしておくとAPIサーバーに負担をかけることになります。Jobが上位コントローラーにより直接管理されている場合、例えばCronJobs の場合、Jobは指定された容量ベースのクリーンアップポリシーに基づき、CronJobによりクリーンアップされます。
終了したJobのTTLメカニズム FEATURE STATE:
Kubernetes v1.23 [stable]
終了したJob(状態がComplete
かFailed
になったJob)を自動的にクリーンアップするもう一つの方法は
TTLコントローラー より提供されたTTLメカニズムです。.spec.ttlSecondsAfterFinished
フィールドを指定することで、終了したリソースをクリーンアップすることができます。
TTLコントローラーでJobをクリーンアップする場合、Jobはカスケード的に削除されます。つまりJobを削除する際に、Jobに属しているオブジェクト、例えばPodなども一緒に削除されます。Jobが削除される場合、Finalizerなどの、Jobのライフサイクル保証は守られることに注意してください。
例えば:
apiVersion : batch/v1
kind : Job
metadata :
name : pi-with-ttl
spec :
ttlSecondsAfterFinished : 100
template :
spec :
containers :
- name : pi
image : perl:5.34.0
command : ["perl" , "-Mbignum=bpi" , "-wle" , "print bpi(2000)" ]
restartPolicy : Never
Job pi-with-ttl
は終了してからの100
秒後に自動的に削除されるようになっています。
このフィールドに0
を設定すると、Jobは終了後すぐに自動削除の対象になります。このフィールドに何も設定しないと、Jobが終了してもTTLコントローラーによるクリーンアップはされません。
備考: ttlSecondsAfterFinished
フィールドを設定することが推奨されます。管理されていないJob(CronJobなどの、他のワークロードAPIを経由せずに、直接作成したJob)はorphanDependents
というデフォルトの削除ポリシーがあるため、Jobが完全に削除されても、属しているPodが残ってしまうからです。
コントロールプレーン は最終的に、失敗または完了して削除されたJobに属するPodをガベージコレクション しますが、Podが残っていると、クラスターのパフォーマンスが低下することがあり、最悪の場合、この低下によりクラスターがオフラインになることがあります。
LimitRanges とリソースクォータ で、指定する名前空間が消費できるリソースの量に上限を設定することができます。
Jobパターン Jobオブジェクトは、Podの確実な並列実行をサポートするために使用されます。科学技術計算でよく見られるような、密接に通信を行う並列処理をサポートするようには設計されていません。独立だが関連性のある一連の作業項目 の並列処理をサポートします。例えば送信すべき電子メール、レンダリングすべきフレーム、トランスコードすべきファイル、スキャンすべきNoSQLデータベースのキーの範囲、などです。
複雑なシステムでは、異なる作業項目のセットが複数存在する場合があります。ここでは、ユーザーが一斉に管理したい作業項目のセットが一つだけの場合 — つまりバッチJob だけを考えます。
並列計算にはいくつかのパターンがあり、それぞれに長所と短所があります。
トレードオフの関係にあるのは:
各作業項目に1つのJobオブジェクト vs. すべての作業項目に1つのJobオブジェクト。 後者は大量の作業項目を処理する場合に適しています。 前者は大量のJobオブジェクトを管理するため、ユーザーとシステムにオーバーヘッドをかけることになります。 作成されるPod数が作業項目数と等しい、 vs. 各Podが複数の作業項目を処理する。
前者は通常、既存のコードやコンテナへの変更が少なくて済みます。
後者は上記と同じ理由で、大量の作業項目を処理する場合に適しています。 ワークキューを利用するアプローチもいくつかあります。それを使うためには、キューサービスを実行し、既存のプログラムやコンテナにワークキューを利用させるための改造を行う必要があります。
他のアプローチは既存のコンテナ型アプリケーションに適用しやすいです。 ここでは、上記のトレードオフをまとめてあり、それぞれ2~4列目に対応しています。
またパターン名のところは、例やより詳しい説明が書いてあるページへのリンクになっています。
.spec.completions
で完了数を指定する場合、Jobコントローラーより作成された各Podは同一のspec
を持ちます。これは、このタスクのすべてのPodが同じコマンドライン、同じイメージ、同じボリューム、そして(ほぼ)同じ環境変数を持つことを意味します。これらのパターンは、Podが異なる作業をするためのさまざまな配置方法になります。
この表は、各パターンで必要な.spec.parallelism
と.spec.completions
の設定を示しています。
ここで、W
は作業項目の数を表しています。
高度な使い方 Jobの一時停止 FEATURE STATE:
Kubernetes v1.24 [stable]
Jobが作成されると、JobコントローラーはJobの要件を満たすために直ちにPodの作成を開始し、Jobが完了するまで作成し続けます。しかし、Jobの実行を一時的に中断して後で再開したい場合、または一時停止状態のJobを再開し、再開時間は後でカスタムコントローラーに判断させたい場合はあると思います。
Jobを一時停止するには、Jobの.spec.suspend
フィールドをtrueに修正し、後でまた再開したい場合にはfalseに修正すればよいです。
.spec.suspend
をtrueに設定してJobを作成すると、一時停止状態のままで作成されます。
一時停止状態のJobを再開すると、.status.startTime
フィールドの値は現在時刻にリセットされます。これはつまり、Jobが一時停止して再開すると、.spec.activeDeadlineSeconds
タイマーは停止してリセットされることになります。
Jobを中断すると、状態がCompleted
ではない実行中のPodはすべてSIGTERMシグナルを受信して終了されます 。Podのグレースフル終了の猶予期間がカウントダウンされ、この期間内に、Podはこのシグナルを処理しなければなりません。場合により、その後のために処理状況を保存したり、変更を元に戻したりする処理が含まれます。この方法で終了したPodはcompletions
数にカウントされません。
下記は一時停止状態のままで作成されたJobの定義例になります:
kubectl get job myjob -o yaml
apiVersion : batch/v1
kind : Job
metadata :
name : myjob
spec :
suspend : true
parallelism : 1
completions : 5
template :
spec :
...
コマンドラインを使ってJobにパッチを当てることで、Jobの一時停止状態を切り替えることもできます。
活動中のJobを一時停止する:
kubectl patch job/myjob --type= strategic --patch '{"spec":{"suspend":true}}'
一時停止中のJobを再開する:
kubectl patch job/myjob --type= strategic --patch '{"spec":{"suspend":false}}'
Jobのstatusセクションで、Jobが停止中なのか、過去に停止したことがあるかを判断できます:
kubectl get jobs/myjob -o yaml
apiVersion : batch/v1
kind : Job
# .metadata and .spec omitted
status :
conditions :
- lastProbeTime : "2021-02-05T13:14:33Z"
lastTransitionTime : "2021-02-05T13:14:33Z"
status : "True"
type : Suspended
startTime : "2021-02-05T13:13:48Z"
Jobのcondition.typeが"Suspended"で、statusが"True"になった場合、Jobは一時停止中になります。lastTransitionTime
フィールドで、どのぐらい中断されたかを判断できます。statusが"False"になった場合、Jobは一時停止状態でしたが、今は実行されていることになります。conditionが書いていない場合、Jobは一度も停止していないことになります。
Jobが一時停止して再開した場合、Eventsも作成されます:
kubectl describe jobs/myjob
Name: myjob
...
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal SuccessfulCreate 12m job-controller Created pod: myjob-hlrpl
Normal SuccessfulDelete 11m job-controller Deleted pod: myjob-hlrpl
Normal Suspended 11m job-controller Job suspended
Normal SuccessfulCreate 3s job-controller Created pod: myjob-jvb44
Normal Resumed 3s job-controller Job resumed
最後の4つのイベント、特に"Suspended"と"Resumed"のイベントは、.spec.suspend
フィールドの値を切り替えた直接の結果です。この2つのイベントの間に、Podは作成されていないことがわかりますが、Jobが再開されるとすぐにPodの作成も再開されました。
可変スケジューリング命令 FEATURE STATE:
Kubernetes v1.27 [stable]
ほとんどの場合、並列Jobは、すべてのPodが同じゾーン、またはすべてのGPUモデルxかyのいずれかであるが、両方の混在ではない、などの制約付きで実行することが望ましいです。
suspend フィールドは、これらの機能を実現するための第一歩です。Suspendは、カスタムキューコントローラーがJobをいつ開始すべきかを決定することができます。しかし、Jobの一時停止が解除されると、カスタムキューコントローラーは、Job内のPodの実際の配置場所には影響を与えません。
この機能により、Jobが開始する前にスケジューリング命令を更新でき、カスタムキューコントローラーがPodの配置に影響を与えることができるようになります。同時に実際のPodからNodeへの割り当てをkube-schedulerにオフロードする能力を提供します。これは一時停止されたJobの中で、一度も一時停止解除されたことのないJobに対してのみ許可されます。
JobのPodテンプレートで更新可能なフィールドはnodeAffinity、nodeSelector、tolerations、labelsとannotations、スケジューリングゲート です。
独自のPodセレクターを指定 Jobオブジェクトを作成する際には通常、.spec.selector
を指定しません。Jobが作成された際に、システムのデフォルトロジックは、他のJobと重ならないようなセレクターの値を選択し、このフィールドに追加します。
しかし、場合によっては、この自動設定されたセレクターをオーバーライドする必要があります。そのためには、Jobの.spec.selector
を指定します。
その際には十分な注意が必要です。そのJobの他のPodと重なったラベルセレクターを指定し、無関係のPodにマッチした場合、無関係のJobのPodが削除されたり、無関係のPodが完了されてもこのJobの完了数とカウントしたり、片方または両方のJobがPodの作成または完了までの実行を拒否する可能性があります。
一意でないセレクターを選択した場合、他のコントローラー(例えばReplicationController)や属しているPodが予測できない挙動をする可能性があります。Kubernetesは.spec.selector
を間違って設定しても止めることはしません。
下記はこの機能の使用例を紹介しています。
old
と名付けたJobがすでに実行されていると仮定します。既存のPodをそのまま実行し続けてほしい一方で、作成する残りのPodには別のテンプレートを使用し、そのJobには新しい名前を付けたいとしましょう。これらのフィールドは更新できないため、Jobを直接更新できません。そのため、kubectl delete jobs/old --cascade=orphan
で、属しているPodが実行されたまま 、old
Jobを削除します。削除する前に、どのセレクターを使用しているかをメモしておきます:
kubectl get job old -o yaml
出力結果はこのようになります:
kind : Job
metadata :
name : old
...
spec :
selector :
matchLabels :
batch.kubernetes.io/controller-uid : a8f3d00d-c6d2-11e5-9f87-42010af00002
...
次に、new
という名前で新しくJobを作成し、同じセレクターを明示的に指定します。既存のPodもbatch.kubernetes.io/controller-uid=a8f3d00d-c6d2-11e5-9f87-42010af00002
ラベルが付いているので、同じくnew
Jobによってコントロールされます。
通常システムが自動的に生成するセレクターを使用しないため、新しいJobで manualSelector: true
を指定する必要があります。
kind : Job
metadata :
name : new
...
spec :
manualSelector : true
selector :
matchLabels :
batch.kubernetes.io/controller-uid : a8f3d00d-c6d2-11e5-9f87-42010af00002
...
新しいJobはa8f3d00d-c6d2-11e5-9f87-42010af00002
ではなく、別のuidを持つことになります。manualSelector: true
を設定することで、自分は何をしているかを知っていて、またこのミスマッチを許容することをシステムに伝えます。
FinalizerによるJob追跡 FEATURE STATE:
Kubernetes v1.26 [stable]
備考: JobTrackingWithFinalizers
機能が無効になっている時に作成されたJobについては、コントロールプレーンを1.26にアップグレードしても、ファイナライザーを使用してJobを追跡しません。コントロールプレーンは任意のJobに属するPodを追跡し、そのPodがAPIサーバーから削除されたかどうか認識します。そのためJobコントローラーはファイナライザーbatch.kubernetes.io/job-tracking
を持つPodを作成します。コントローラーがファイナライザーを削除するのは、PodがJobステータスに反映された後なので、他のコントローラーやユーザがPodを削除することができます。
Kubernetes 1.26にアップグレードする前、またはフィーチャーゲートJobTrackingWithFinalizers
が有効になる前に作成されたJobは、Podファイナライザーを使用せずに追跡されます。Jobコントローラー は、クラスターに存在するPodのみに基づいて、succeeded
Podとfailed
Podのステータスカウンタを更新します。クラスターからPodが削除されると、コントロールプレーンはJobの進捗を見失う可能性があります。
Jobがbatch.kubernetes.io/job-tracking
というアノテーションを持っているかどうかをチェックすることで、コントロールプレーンがPodファイナライザーを使ってJobを追跡しているかどうかを判断できます。Jobからこのアノテーションを手動で追加したり削除したりしてはいけません 。代わりに、JobがPodファイナライザーを使用して追跡されていることを確認するために、Jobを再作成することができます。
静的なインデックス付きJob FEATURE STATE:
Kubernetes v1.27 [beta]
.spec.parallelism
と.spec.compleitions
の両方を、.spec.parallelism
== .spec.compleitions
となるように変更することで、インデックス付きJobを増減させることができます。APIサーバ のElasticIndexedJob
フィーチャーゲート が無効になっている場合、.spec.compleitions
は不変です。
静的なインデックス付きJobの使用例としては、MPI、Horovod、Ray、PyTorchトレーニングジョブなど、インデックス付きJobのスケーリングを必要とするバッチワークロードがあります。
代替案 単なるPod Podが動作しているノードが再起動または故障した場合、Podは終了し、再起動されません。しかし、終了したPodを置き換えるため、Jobが新しいPodを作成します。このため、たとえアプリケーションが1つのPodしか必要としない場合でも、単なるPodではなくJobを使用することをお勧めします。
Replication Controller JobはReplication Controllers を補完するものです。
Replication Controllerは、終了することが想定されていないPod(Webサーバーなど)を管理し、Jobは終了することが想定されているPod(バッチタスクなど)を管理します。
Podのライフサイクル で説明したように、Job
はRestartPolicy
がOnFailure
かNever
と設定されているPodにのみ 適用されます。(注意:RestartPolicy
が設定されていない場合、デフォルト値はAlways
になります)
シングルJobによるコントローラーPodの起動 もう一つのパターンは、一つのJobが一つPodを作り、そのPodがカスタムコントローラーのような役割を果たし、他のPodを作ります。これは最も柔軟性がありますが、使い始めるにはやや複雑で、Kubernetesとの統合もあまりできません。
このパターンの一例としては、Sparkマスターコントローラーを起動し、sparkドライバーを実行してクリーンアップするスクリプトを実行するPodをJobで起動する(sparkの例 を参照)が挙げられます。
この方法のメリットは、全処理過程でJobオブジェクトが完了する保証がありながらも、どのPodを作成し、どのように作業を割り当てるかを完全に制御できることです。
次の項目 Pods について学ぶ。Jobのさまざまな実行方法について学ぶ: 終了したJobの自動クリーンアップ のリンクから、クラスターが完了または失敗したJobをどのようにクリーンアップするかをご確認ください。Job
はKubernetes REST APIの一部です。JobのAPIを理解するために、
Job オブジェクトの定義をお読みください。UNIXツールのcron
と同様に、スケジュールに基づいて実行される一連のJobを定義するために使用できるCronJob
についてお読みください。 段階的な例 に基づいて、PodFailurePolicy
を使用して、回復可能なPod失敗と回復不可能なPod失敗の処理を構成する方法を練習します。 4.2.6 - 終了したリソースのためのTTLコントローラー(TTL Controller for Finished Resources) FEATURE STATE:
Kubernetes v1.12 [alpha]
TTLコントローラーは実行を終えたリソースオブジェクトのライフタイムを制御するためのTTL (time to live) メカニズムを提供します。 TTLコントローラーは現在Job のみ扱っていて、将来的にPodやカスタムリソースなど、他のリソースの実行終了を扱えるように拡張される予定です。
α版の免責事項: この機能は現在α版の機能で、kube-apiserverとkube-controller-managerのFeature Gate のTTLAfterFinished
を有効にすることで使用可能です。
TTLコントローラー TTLコントローラーは現在Jobに対してのみサポートされています。クラスターオペレーターはこの例 のように、Jobの.spec.ttlSecondsAfterFinished
フィールドを指定することにより、終了したJob(完了した
もしくは失敗した
)を自動的に削除するためにこの機能を使うことができます。 TTLコントローラーは、そのリソースが終了したあと指定したTTLの秒数後に削除できるか推定します。言い換えると、そのTTLが期限切れになると、TTLコントローラーがリソースをクリーンアップするときに、そのリソースに紐づく従属オブジェクトも一緒に連続で削除します。注意点として、リソースが削除されるとき、ファイナライザーのようなライフサイクルに関する保証は尊重されます。
TTL秒はいつでもセット可能です。下記はJobの.spec.ttlSecondsAfterFinished
フィールドのセットに関するいくつかの例です。
Jobがその終了後にいくつか時間がたった後に自動的にクリーンアップできるように、そのリソースマニフェストにこの値を指定します。 この新しい機能を適用させるために、存在していてすでに終了したリソースに対してこのフィールドをセットします。 リソース作成時に、このフィールドを動的にセットするために、管理webhookの変更 をさせます。クラスター管理者は、終了したリソースに対して、このTTLポリシーを強制するために使うことができます。 リソースが終了した後に、このフィールドを動的にセットしたり、リソースステータスやラベルなどの値に基づいて異なるTTL値を選択するために、管理webhookの変更 をさせます。 注意 TTL秒の更新 注意点として、Jobの.spec.ttlSecondsAfterFinished
フィールドといったTTL期間はリソースが作成された後、もしくは終了した後に変更できます。しかし、一度Jobが削除可能(TTLの期限が切れたとき)になると、それがたとえTTLを伸ばすような更新に対してAPIのレスポンスで成功したと返されたとしても、そのシステムはJobが稼働し続けることをもはや保証しません。
タイムスキュー(Time Skew) TTLコントローラーが、TTL値が期限切れかそうでないかを決定するためにKubernetesリソース内に保存されたタイムスタンプを使うため、この機能はクラスター内のタイムスキュー(時刻のずれ)に対してセンシティブとなります。タイムスキューは、誤った時間にTTLコントローラーに対してリソースオブジェクトのクリーンアップしてしまうことを引き起こすものです。
Kubernetesにおいてタイムスキューを避けるために、全てのNode上でNTPの稼働を必須とします(#6159 を参照してください)。クロックは常に正しいものではありませんが、Node間におけるその差はとても小さいものとなります。TTLに0でない値をセットするときにこのリスクに対して注意してください。
次の項目 4.2.7 - CronJob FEATURE STATE:
Kubernetes v1.8 [beta]
CronJob は繰り返しのスケジュールによってJob を作成します。
CronJob オブジェクトとは crontab (cron table)ファイルでみられる一行のようなものです。
Cron 形式で記述された指定のスケジュールの基づき、定期的にジョブが実行されます。
注意: すべてのCronJob スケジュール
: 時刻はジョブが開始されたkube-controller-manager のタイムゾーンに基づいています。
コントロールプレーンがkube-controller-managerをPodもしくは素のコンテナで実行している場合、CronJobコントローラーのタイムゾーンとして、kube-controller-managerコンテナに設定されたタイムゾーンを使用します。
CronJobリソースのためのマニフェストを作成する場合、その名前が有効なDNSサブドメイン名 か確認してください。
名前は52文字を超えることはできません。これはCronJobコントローラーが自動的に、与えられたジョブ名に11文字を追加し、ジョブ名の長さは最大で63文字以内という制約があるためです。
CronJob CronJobは、バックアップの実行やメール送信のような定期的であったり頻発するタスクの作成に役立ちます。
CronJobは、クラスターがアイドル状態になりそうなときにJobをスケジューリングするなど、特定の時間に個々のタスクをスケジュールすることもできます。
例 このCronJobマニフェスト例は、毎分ごとに現在の時刻とhelloメッセージを表示します。
apiVersion : batch/v1
kind : CronJob
metadata :
name : hello
spec :
schedule : "* * * * *"
jobTemplate :
spec :
template :
spec :
containers :
- name : hello
image : busybox
command :
- /bin/sh
- -c
- date; echo Hello from the Kubernetes cluster
restartPolicy : OnFailure
(Running Automated Tasks with a CronJob ではこの例をより詳しく説明しています。).
CronJobの制限 cronジョブは一度のスケジュール実行につき、 おおよそ 1つのジョブオブジェクトを作成します。ここで おおよそ と言っているのは、ある状況下では2つのジョブが作成される、もしくは1つも作成されない場合があるためです。通常、このようなことが起こらないようになっていますが、完全に防ぐことはできません。したがって、ジョブは 冪等 であるべきです。
startingDeadlineSeconds
が大きな値、もしくは設定されていない(デフォルト)、そして、concurrencyPolicy
をAllow
に設定している場合には、少なくとも一度、ジョブが実行されることを保証します。
最後にスケジュールされた時刻から現在までの間に、CronJobコントローラー はどれだけスケジュールが間に合わなかったのかをCronJobごとにチェックします。もし、100回以上スケジュールが失敗していると、ジョブは開始されずに、ログにエラーが記録されます。
Cannot determine if job needs to be started. Too many missed start time (> 100). Set or decrease .spec.startingDeadlineSeconds or check clock skew.
startingDeadlineSeconds
フィールドが設定されると(nil
ではない)、最後に実行された時刻から現在までではなく、startingDeadlineSeconds
の値から現在までで、どれだけジョブを逃したのかをコントローラーが数えます。 startingDeadlineSeconds
が200
の場合、過去200秒間にジョブが失敗した回数を記録します。
スケジュールされた時間にCronJobが作成できないと、失敗したとみなされます。たとえば、concurrencyPolicy
がForbid
に設定されている場合、前回のスケジュールがまだ実行中にCronJobをスケジュールしようとすると、CronJobは作成されません。
例として、CronJobが08:30:00
を開始時刻として1分ごとに新しいJobをスケジュールするように設定され、startingDeadlineSeconds
フィールドが設定されていない場合を想定します。CronJobコントローラーが08:29:00
から10:21:00
の間にダウンしていた場合、スケジューリングを逃したジョブの数が100を超えているため、ジョブは開始されません。
このコンセプトをさらに掘り下げるために、CronJobが08:30:00
から1分ごとに新しいJobを作成し、startingDeadlineSeconds
が200秒に設定されている場合を想定します。CronJobコントローラーが前回の例と同じ期間(08:29:00
から10:21:00
まで)にダウンしている場合でも、10:22:00時点でJobはまだ動作しています。このようなことは、過去200秒間(言い換えると、3回の失敗)に何回スケジュールが間に合わなかったをコントローラーが確認するときに発生します。これは最後にスケジュールされた時間から今までのものではありません。
CronJobはスケジュールに一致するJobの作成にのみ関与するのに対して、JobはJobが示すPod管理を担います。
次の項目 Cron表現形式 では、CronJobのschedule
フィールドのフォーマットを説明しています。
cronジョブの作成や動作の説明、CronJobマニフェストの例については、Running automated tasks with cron jobs を見てください。
4.3 - 自動スケーリングによって、何らかのかたちでワークロードを自動的に更新できます。これによりクラスターはリソース要求の変化に対してより弾力的かつ効率的に対応できるようになります。
Kubernetesでは、現在のリソース要求に応じてワークロードをスケールできます。
これによりクラスターはリソース要求の変化に対してより弾力的かつ効率的に対応できるようになります。
ワークロードをスケールするとき、ワークロードによって管理されるレプリカ数を増減したり、レプリカで使用可能なリソースをインプレースで調整できます。
ひとつ目のアプローチは 水平スケーリング と呼ばれ、一方でふたつ目のアプローチは 垂直スケーリング と呼ばれます。
ユースケースに応じて、ワークロードをスケールするには手動と自動の方法があります。
ワークロードを手動でスケーリングする Kubernetesはワークロードの 手動スケーリング をサポートします。
水平スケーリングは kubectl
CLIを使用して行うことができます。
垂直スケーリングの場合、ワークロードのリソース定義を パッチ適用 する必要があります。
両方の戦略の例については以下をご覧ください。
ワークロードを自動でスケーリングする Kubernetesはワークロードの 自動スケーリング もサポートしており、これがこのページの焦点です。
Kubernetesにおける オートスケーリング の概念は一連のPodを管理するオブジェクト(例えばDeployment )を自動的に更新する機能を指します。
ワークロードを水平方向にスケーリングする Kubernetesにおいて、 HorizontalPodAutoscaler (HPA)を使用してワークロードを水平方向に自動的にスケールできます。
これはKubernetes APIリソースおよびコントローラー として実装されておりCPUやメモリ使用率のような観測されたリソース使用率と一致するようにワークロードのレプリカ 数を定期的に調整します。
Deployment用のHorizontalPodAutoscalerを構成するウォークスルーチュートリアル があります。
ワークロードを垂直方向にスケーリングする FEATURE STATE:
Kubernetes v1.25 [stable]
VerticalPodAutoscaler (VPA)を使用してワークロードを垂直方向に自動的にスケールできます。
HPAと異なり、VPAはデフォルトでKubernetesに付属していませんが、GitHubで 見つかる別のプロジェクトです。
インストールすることにより、管理されたレプリカのリソースを どのように いつ スケールするのかを定義するワークロードのCustomResourceDefinitions (CRDs)を作成できるようになります。
現時点では、VPAは4つの異なるモードで動作できます:
VPAの異なるモード モード 説明 Auto
現在、Recreate
は将来インプレースアップデートに変更される可能性があります Recreate
VPAはPod作成時にリソースリクエストを割り当てるだけでなく、要求されたリソースが新しい推奨事項と大きく異なる場合にそれらを削除することによって既存のPod上でリソースリクエストを更新します Initial
VPAはPod作成時にリソースリクエストを割り当て、後から変更することはありません Off
VPAはPodのリソース要件を自動的に変更しません。推奨事項は計算され、VPAオブジェクトで検査できます
インプレースリサイズの要件 FEATURE STATE:
Kubernetes v1.27 [alpha]
Pod またはそのコンテナ を再起動せずに インプレースでワークロードをリサイズするには、Kubernetesバージョン1.27以降が必要です。
さらに、InPlaceVerticalScaling
フィーチャーゲートを有効にする必要があります。
InPlacePodVerticalScaling
: Podリソースの再作成なしで垂直オートスケーリングができる機能を有効にします。
クラスターサイズに基づく自動スケーリング クラスターのサイズに基づいてスケールする必要があるワークロード(例えばcluster-dns
や他のシステムコンポーネント)の場合は、Cluster Proportional Autoscaler を使用できます。
VPAと同じように、これはKubernetesのコア部分ではありませんが、独自のGitHubプロジェクトとしてホストされています。
Cluster Proportional Autoscalerはスケジュール可能なノード とコアの数を監視し、それに応じてターゲットワークロードのレプリカ数をスケールします。
レプリカ数を同じままにする必要がある場合、Cluster Proportional Vertical Autoscaler を使用してクラスターサイズに応じてワークロードを垂直方向にスケールできます。
このプロジェクトは現在ベータ版 でありGitHubで見つけることができます。
Cluster Proportional Autoscalerがワークロードのレプリカ数をスケールする一方で、Cluster Proportional Vertical Autoscalerはクラスター内のノードおよび/またはコアの数に基づいてワークロード(例えばDeploymentやDaemonSet)のリソース要求を調整します。
イベント駆動型自動スケーリング 例えばKubernetes Event Driven Autoscaler
(KEDA ) を使用して、イベントに基づいてワークロードをスケールすることもできます。
KEDAは例えばキューのメッセージ数などの処理するべきイベント数に基づいてワークロードをスケールするCNCF graduatedプロジェクトです。様々なイベントソースに合わせて選択できる幅広いアダプターが存在します。
スケジュールに基づく自動スケーリング ワークロードををスケールするためのもう一つの戦略は、例えばオフピークの時間帯にリソース消費を削減するために、スケーリング操作をスケジュールする ことです。
イベント駆動型オートスケーリングと同様に、そのような動作はKEDAをCron
スケーラー と組み合わせて使用することで実現できます。
Cron
スケーラーによりワークロードをスケールインまたはスケールアウトするためのスケジュール(およびタイムゾーン)を定義できます。
クラスターのインフラストラクチャーのスケーリング ワークロードのスケーリングだけではニーズを満たすのに十分でない場合は、クラスターのインフラストラクチャー自体をスケールすることもできます。
クラスターのインフラストラクチャーのスケーリングは通常ノード の追加または削除を意味します。
詳しくはクラスターの自動スケーリング を読んでください。
次の項目 5 - Service、負荷分散とネットワーキング Kubernetesにおけるネットワーキングの概念とリソース。
Kubernetesのネットワーキングは4つの懸念事項に対処します。
Pod内のコンテナは、ネットワーキングを利用してループバック経由の通信を行います。 クラスターネットワーキングは、異なるPod間の通信を提供します。 Serviceリソースは、Pod内で動作しているアプリケーションへクラスターの外部から到達可能なように露出を許可します。 Serviceを利用して、クラスター内部のみで使用するServiceの公開も可能です。 5.1 - Service KubernetesにおけるServiceとは、 クラスター内で1つ以上のPod として実行されているネットワークアプリケーションを公開する方法です。
Kubernetesでは、なじみのないサービスディスカバリーのメカニズムを使用するためにユーザーがアプリケーションの修正をする必要はありません。
KubernetesはPodにそれぞれのIPアドレス割り振りや、Podのセットに対する単一のDNS名を提供したり、それらのPodのセットに対する負荷分散が可能です。
Serviceを利用する動機 Kubernetes Pod はクラスターの状態に合わせて作成され削除されます。Podは揮発的なリソースです。
Deployment をアプリケーションを稼働させるために使用すると、Podを動的に作成・削除してくれます。
各Podはそれ自身のIPアドレスを持ちます。しかしDeploymentでは、ある時点において同時に稼働しているPodのセットは、その後のある時点において稼働しているPodのセットとは異なる場合があります。
この仕組みはある問題を引き起こします。もし、あるPodのセット(ここでは"バックエンド"と呼びます)がクラスター内で他のPodのセット(ここでは"フロントエンド"と呼びます)に対して機能を提供する場合、フロントエンドのPodがワークロードにおけるバックエンドを使用するために、バックエンドのPodのIPアドレスを探し出したり、記録し続けるためにはどうすればよいでしょうか?
ここで Service について説明します。
Serviceリソース Kubernetesにおいて、ServiceはPodの論理的なセットや、そのPodのセットにアクセスするためのポリシーを定義します(このパターンはよくマイクロサービスと呼ばることがあります)。
ServiceによってターゲットとされたPodのセットは、たいてい セレクター によって定義されます。
その他の方法について知りたい場合はセレクターなしのService を参照してください。
例えば、3つのレプリカが稼働しているステートレスな画像処理用のバックエンドを考えます。これらのレプリカは代替可能です。— フロントエンドはバックエンドが何であろうと気にしません。バックエンドのセットを構成する実際のPodのセットが変更された際、フロントエンドクライアントはその変更を気にしたり、バックエンドのPodのセットの情報を記録しておく必要はありません。
Serviceによる抽象化は、クライアントからバックエンドのPodの管理する責務を分離することを可能にします。
クラウドネイティブのサービスディスカバリー アプリケーション内でサービスディスカバリーのためにKubernetes APIが使える場合、ユーザーはエンドポイントをAPI Server に問い合わせることができ、またService内のPodのセットが変更された時はいつでも更新されたエンドポイントの情報を取得できます。
非ネイティブなアプリケーションのために、KubernetesはアプリケーションとバックエンドPodの間で、ネットワークポートやロードバランサーを配置する方法を提供します。
Serviceの定義 KubernetesのServiceはPodと同様にRESTのオブジェクトです。他のRESTオブジェクトと同様に、ユーザーはServiceの新しいインスタンスを作成するためにAPIサーバーに対してServiceの定義をPOST
できます。Serviceオブジェクトの名前は、有効なDNSラベル名 である必要があります。
例えば、TCPで9376番ポートで待ち受けていて、app=Myapp
というラベルをもつPodのセットがあるとします。
apiVersion : v1
kind : Service
metadata :
name : my-service
spec :
selector :
app : MyApp
ports :
- protocol : TCP
port : 80
targetPort : 9376
この定義では、"my-service"という名前のついた新しいServiceオブジェクトを作成します。これはapp=Myapp
ラベルのついた各Pod上でTCPの9376番ポートをターゲットとします。
Kubernetesは、このServiceに対してIPアドレス("clusterIP"とも呼ばれます)を割り当てます。これはServiceのプロキシによって使用されます(下記の仮想IPとServiceプロキシ を参照ください)。
Serviceセレクターのコントローラーはセレクターに一致するPodを継続的にスキャンし、“my-service”という名前のEndpointsオブジェクトに対して変更をPOSTします。
備考: Serviceはport
からtargetPort
へのマッピングを行います。デフォルトでは、利便性のためにtargetPort
フィールドはport
フィールドと同じ値で設定されます。Pod内のポートの定義は名前を設定でき、ServiceのtargetPort
属性にてその名前を参照できます。これは単一の設定名をもつService内で、複数の種類のPodが混合していたとしても有効で、異なるポート番号を介することによって利用可能な、同一のネットワークプロトコルを利用します。
この仕組みはServiceをデプロイしたり、設定を追加する場合に多くの点でフレキシブルです。例えば、バックエンドソフトウェアにおいて、次のバージョンでPodが公開するポート番号を変更するときに、クライアントの変更なしに行えます。
ServiceのデフォルトプロトコルはTCPです。また、他のサポートされているプロトコル も利用可能です。
多くのServiceが、1つ以上のポートを公開する必要があるように、Kubernetesは1つのServiceオブジェクトに対して複数のポートの定義をサポートしています。
各ポート定義は同一のprotocol
または異なる値を設定できます。
セレクターなしのService Serviceは多くの場合、KubernetesのPodに対するアクセスを抽象化しますが、他の種類のバックエンドも抽象化できます。
例えば:
プロダクション環境で外部のデータベースクラスターを利用したいが、テスト環境では、自身のクラスターが持つデータベースを利用したい場合 Serviceを、異なるNamespace のServiceや他のクラスターのServiceに向ける場合 ワークロードをKubernetesに移行するとき、アプリケーションに対する処理をしながら、バックエンドの一部をKubernetesで実行する場合 このような場合において、ユーザーはPodセレクターなしで Serviceを定義できます。
apiVersion : v1
kind : Service
metadata :
name : my-service
spec :
ports :
- protocol : TCP
port : 80
targetPort : 9376
このServiceはセレクターがないため、対応するEndpointsオブジェクトは自動的に作成されません。
ユーザーはEndpointsオブジェクトを手動で追加することにより、向き先のネットワークアドレスとポートを手動でマッピングできます。
apiVersion : v1
kind : Endpoints
metadata :
name : my-service
subsets :
- addresses :
- ip : 192.0.2.42
ports :
- port : 9376
Endpointsオブジェクトの名前は、有効なDNSサブドメイン名 である必要があります。
備考: Endpointsのipは、loopback (127.0.0.0/8 for IPv4, ::1/128 for IPv6), や
link-local (169.254.0.0/16 and 224.0.0.0/24 for IPv4, fe80::/64 for IPv6)に設定することができません。
kube-proxy が仮想IPを最終的な到達先に設定することをサポートしていないため、Endpointsのipアドレスは他のKubernetes ServiceのClusterIPにすることができません。
セレクターなしのServiceへのアクセスは、セレクターをもっているServiceと同じようにふるまいます。上記の例では、トラフィックはYAMLファイル内で192.0.2.42:9376
(TCP)で定義された単一のエンドポイントにルーティングされます。
ExternalName Serviceはセレクターの代わりにDNS名を使用する特殊なケースのServiceです。さらなる情報は、このドキュメントの後で紹介するExternalName を参照ください。
エンドポイントスライス FEATURE STATE:
Kubernetes v1.17 [beta]
エンドポイントスライスは、Endpointsに対してよりスケーラブルな代替手段を提供できるAPIリソースです。概念的にはEndpointsに非常に似ていますが、エンドポイントスライスを使用すると、ネットワークエンドポイントを複数のリソースに分割できます。デフォルトでは、エンドポイントスライスは、100個のエンドポイントに到達すると「いっぱいである」と見なされ、その時点で追加のエンドポイントスライスが作成され、追加のエンドポイントが保存されます。
エンドポイントスライスは、エンドポイントスライスのドキュメント にて詳しく説明されている追加の属性と機能を提供します。
アプリケーションプロトコル FEATURE STATE:
Kubernetes v1.19 [beta]
AppProtocol
フィールドによってServiceの各ポートに対して特定のアプリケーションプロトコルを指定することができます。
この値は、対応するEndpointsオブジェクトとEndpointSliceオブジェクトに反映されます。
仮想IPとサービスプロキシ Kubernetesクラスターの各Nodeはkube-proxy
を稼働させています。kube-proxy
はExternalName
タイプ以外のService
用に仮想IPを実装する責務があります。
なぜ、DNSラウンドロビンを使わないのでしょうか。 ここで湧き上がる質問として、なぜKubernetesは内部のトラフィックをバックエンドへ転送するためにプロキシに頼るのでしょうか。
他のアプローチはどうなのでしょうか。例えば、複数のAバリュー(もしくはIPv6用にAAAAバリューなど)をもつDNSレコードを設定し、ラウンドロビン方式で名前を解決することは可能でしょうか。
Serviceにおいてプロキシを使う理由はいくつかあります。
DNSの実装がレコードのTTLをうまく扱わず、期限が切れた後も名前解決の結果をキャッシュするという長い歴史がある。 いくつかのアプリケーションではDNSルックアップを1度だけ行い、その結果を無期限にキャッシュする。 アプリケーションとライブラリーが適切なDNS名の再解決を行ったとしても、DNSレコード上の0もしくは低い値のTTLがDNSに負荷をかけることがあり、管理が難しい。 user-spaceプロキシモード このモードでは、kube-proxyはServiceやEndpointsオブジェクトの追加・削除をチェックするために、Kubernetes Masterを監視します。
各Serviceは、ローカルのNode上でポート(ランダムに選ばれたもの)を公開します。この"プロキシポート"に対するどのようなリクエストも、そのServiceのバックエンドPodのどれか1つにプロキシされます(Endpointsを介して通知されたPodに対して)。
kube-proxyは、どのバックエンドPodを使うかを決める際にServiceのSessionAffinity
項目の設定を考慮に入れます。
最後に、user-spaceプロキシはServiceのclusterIP
(仮想IP)とport
に対するトラフィックをキャプチャするiptablesルールをインストールします。
そのルールは、トラフィックをバックエンドPodにプロキシするためのプロキシポートにリダイレクトします。
デフォルトでは、user-spaceモードにおけるkube-proxyはラウンドロビンアルゴリズムによってバックエンドPodを選択します。
iptables
プロキシモードこのモードでは、kube-proxyはServiceやEndpointsオブジェクトの追加・削除のチェックのためにKubernetesコントロールプレーンを監視します。
各Serviceでは、そのServiceのclusterIP
とport
に対するトラフィックをキャプチャするiptablesルールをインストールし、そのトラフィックをServiceのあるバックエンドのセットに対してリダイレクトします。
各Endpointsオブジェクトは、バックエンドのPodを選択するiptablesルールをインストールします。
デフォルトでは、iptablesモードにおけるkube-proxyはバックエンドPodをランダムで選択します。
トラフィックのハンドリングのためにiptablesを使用すると、システムのオーバーヘッドが少なくなります。これは、トラフィックがLinuxのnetfilterによってuser-spaceとkernel-spaceを切り替える必要がないためです。
このアプローチは、オーバーヘッドが少ないことに加えて、より信頼できる方法でもあります。
kube-proxyがiptablesモードで稼働し、最初に選択されたPodが応答しない場合、そのコネクションは失敗します。
これはuser-spaceモードでの挙動と異なります: user-spaceモードにおいては、kube-proxyは最初のPodに対するコネクションが失敗したら、自動的に他のバックエンドPodに対して再接続を試みます。
iptablesモードのkube-proxyが正常なバックエンドPodのみをリダイレクト対象とするために、PodのReadinessProbe を使用してバックエンドPodが正常に動作しているか確認できます。これは、ユーザーがkube-proxyを介して、コネクションに失敗したPodに対してトラフィックをリダイレクトするのを除外することを意味します。
IPVSプロキシモード FEATURE STATE:
Kubernetes v1.11 [stable]
ipvs
モードにおいて、kube-proxyはServiceとEndpointsオブジェクトを監視し、IPVSルールを作成するためにnetlink
インターフェースを呼び出し、定期的にKubernetesのServiceとEndpointsとIPVSルールを同期させます。
このコントロールループはIPVSのステータスが理想的な状態になることを保証します。
Serviceにアクセスするとき、IPVSはトラフィックをバックエンドのPodに向けます。
IPVSプロキシモードはiptablesモードと同様に、netfilterのフック関数に基づいています。ただし、基礎となるデータ構造としてハッシュテーブルを使っているのと、kernel-spaceで動作します。
これは、IPVSモードにおけるkube-proxyはiptablesモードに比べてより低いレイテンシーでトラフィックをリダイレクトし、プロキシのルールを同期する際にはよりパフォーマンスがよいことを意味します。
他のプロキシモードと比較して、IPVSモードはより高いネットワークトラフィックのスループットをサポートしています。
IPVSはバックエンドPodに対するトラフィックのバランシングのために多くのオプションを下記のとおりに提供します。
rr
: ラウンドロビンlc
: 最低コネクション数(オープンされているコネクション数がもっとも小さいもの)dh
: 送信先IPによって割り当てられたハッシュ値をもとに割り当てる(Destination Hashing)sh
: 送信元IPによって割り当てられたハッシュ値をもとに割り当てる(Source Hashing)sed
: 見込み遅延が最小なものnq
: キューなしスケジューリング備考: IPVSモードでkube-proxyを稼働させるためには、kube-proxyを稼働させる前にNode上でIPVSを有効にしなければなりません。
kube-proxyはIPVSモードで起動する場合、IPVSカーネルモジュールが利用可能かどうかを確認します。
もしIPVSカーネルモジュールが見つからなかった場合、kube-proxyはiptablesモードで稼働するようにフォールバックされます。
このダイアグラムのプロキシモデルにおいて、ServiceのIP:Portに対するトラフィックは、クライアントがKubernetesのServiceやPodについて何も知ることなく適切にバックエンドにプロキシされています。
特定のクライアントからのコネクションが、毎回同一のPodにリダイレクトされるようにするためには、service.spec.sessionAffinity
に"ClientIP"を設定することにより、クライアントのIPアドレスに基づいたSessionAffinityを選択することができます(デフォルトは"None")。
また、service.spec.sessionAffinityConfig.clientIP.timeoutSeconds
を適切に設定することにより、セッションのタイムアウト時間を設定できます(デフォルトではこの値は18,000で、3時間となります)。
複数のポートを公開するService いくつかのServiceにおいて、ユーザーは1つ以上のポートを公開する必要があります。Kubernetesは、Serviceオブジェクト上で複数のポートを定義するように設定できます。
Serviceで複数のポートを使用するとき、どのポートかを明確にするために、複数のポート全てに対して名前をつける必要があります。
例えば:
apiVersion : v1
kind : Service
metadata :
name : my-service
spec :
selector :
app : MyApp
ports :
- name : http
protocol : TCP
port : 80
targetPort : 9376
- name : https
protocol : TCP
port : 443
targetPort : 9377
備考: KubernetesのPod名と同様に、ポート名は小文字の英数字と-
のみ含める必要があります。また、ポート名の最初と最後の文字は英数字である必要があります。
例えば、123-abc
やweb
という名前は有効で、123_abc
や-web
は無効です。
ユーザー所有のIPアドレスを選択する Service
を作成するリクエストの一部として、ユーザー所有のclusterIPアドレスを指定することができます。
これを行うためには.spec.clusterIP
フィールドにセットします。
使用例として、もしすでに再利用したいDNSエントリーが存在していた場合や、特定のIPアドレスを設定されたレガシーなシステムや、IPの再設定が難しい場合です。
ユーザーが指定したIPアドレスは、そのAPIサーバーのために設定されているservice-cluster-ip-range
というCIDRレンジ内の有効なIPv4またはIPv6アドレスである必要があります。
もし無効なclusterIPアドレスの値を設定してServiceを作成した場合、問題があることを示すためにAPIサーバーはHTTPステータスコード422を返します。
サービスディスカバリー Kubernetesは、Serviceオブジェクトを見つけ出すために2つの主要なモードをサポートしています。 - それは環境変数とDNSです。
環境変数 PodがNode上で稼働するとき、kubeletはアクティブな各Serviceに対して、環境変数のセットを追加します。
これはDocker links互換性 のある変数(
makeLinkVariables関数 を確認してください)や、より簡単な{SVCNAME}_SERVICE_HOST
や、{SVCNAME}_SERVICE_PORT
変数をサポートします。この変数名で使われるService名は大文字に変換され、-
は_
に変換されます。
例えば、TCPポート6379番を公開していて、さらにclusterIPが10.0.0.11に割り当てられているredis-master
というServiceは、下記のような環境変数を生成します。
REDIS_MASTER_SERVICE_HOST = 10.0.0.11
REDIS_MASTER_SERVICE_PORT = 6379
REDIS_MASTER_PORT = tcp://10.0.0.11:6379
REDIS_MASTER_PORT_6379_TCP = tcp://10.0.0.11:6379
REDIS_MASTER_PORT_6379_TCP_PROTO = tcp
REDIS_MASTER_PORT_6379_TCP_PORT = 6379
REDIS_MASTER_PORT_6379_TCP_ADDR = 10.0.0.11
備考: Serviceにアクセスする必要のあるPodがあり、クライアントであるそのPodに対して環境変数を使ってポートとclusterIPを公開する場合、クライアントのPodが存在する前に Serviceを作成しなくてはなりません。
そうでない場合、クライアントのPodはそれらの環境変数を作成しません。
ServiceのclusterIPを発見するためにDNSのみを使う場合、このような問題を心配する必要はありません。
DNS ユーザーはアドオン を使ってKubernetesクラスターにDNS Serviceをセットアップできます(常にセットアップすべきです)。
CoreDNSなどのクラスター対応のDNSサーバーは新しいServiceや、各Service用のDNSレコードのセットのためにKubernetes APIを常に監視します。
もしクラスターを通してDNSが有効になっている場合、全てのPodはDNS名によって自動的にServiceに対する名前解決をするようにできるはずです。
例えば、Kubernetesのmy-ns
というNamespace内でmy-service
というServiceがある場合、KubernetesコントロールプレーンとDNS Serviceが協調して動作し、my-service.my-ns
というDNSレコードを作成します。
my-ns
というNamespace内のPodはmy-service
という名前で簡単に名前解決できるはずです(my-service.my-ns
でも動作します)。
他のNamespace内でのPodはmy-service.my-ns
といった形で指定しなくてはなりません。これらのDNS名は、そのServiceのclusterIPに名前解決されます。
Kubernetesは名前付きのポートに対するDNS SRV(Service)レコードもサポートしています。もしmy-service.my-ns
というServiceがhttp
という名前のTCPポートを持っていた場合、IPアドレスと同様に、http
のポート番号を探すために_http._tcp.my-service.my-ns
というDNS SRVクエリを実行できます。
KubernetesのDNSサーバーはExternalName
Serviceにアクセスする唯一の方法です。
DNS Pods と Service にてExternalName
による名前解決に関するさらなる情報を確認できます。
Headless Service 場合によっては、負荷分散と単一のService IPは不要です。このケースにおいて、clusterIP(.spec.clusterIP
)の値を"None"
に設定することにより、"Headless"とよばれるServiceを作成できます。
ユーザーは、Kubernetesの実装と紐づくことなく、他のサービスディスカバリーのメカニズムと連携するためにHeadless Serviceを使用できます。
例えば、ユーザーはこのAPI上でカスタムオペレーター を実装することができます。
このService
においては、clusterIPは割り当てられず、kube-proxyはこのServiceをハンドリングしないのと、プラットフォームによって行われるはずの
ロードバランシングやプロキシとしての処理は行われません。DNSがどのように自動で設定されるかは、定義されたServiceが定義されたラベルセレクターを持っているかどうかに依存します。
ラベルセレクターの利用 ラベルセレクターを定義したHeadless Serviceにおいて、EndpointsコントローラーはAPIにおいてEndpoints
レコードを作成し、Service
のバックエンドにあるPod
へのIPを直接指し示すためにDNS設定を修正します。
ラベルセレクターなしの場合 ラベルセレクターを定義しないHeadless Serviceにおいては、EndpointsコントローラーはEndpoints
レコードを作成しません。
しかしDNSのシステムは下記の2つ両方を探索し、設定します。
ExternalName
タイプのServiceに対するCNAMEレコード他の全てのServiceタイプを含む、Service名を共有している全てのEndpoints
レコード Serviceの公開 (Serviceのタイプ) ユーザーのアプリケーションのいくつかの部分において(例えば、frontendsなど)、ユーザーのクラスターの外部にあるIPアドレス上でServiceを公開したい場合があります。
KubernetesのServiceTypes
によって、ユーザーがどのような種類のServiceを使いたいかを指定することが可能です。
デフォルトではClusterIP
となります。
Type
項目の値と、そのふるまいは以下のようになります。
また、Serviceを公開するためにIngress も利用可能です。IngressはServiceのタイプではありませんが、クラスターに対するエントリーポイントとして動作します。
Ingressは同一のIPアドレスにおいて、複数のServiceを公開するように、ユーザーの設定した転送ルールを1つのリソースにまとめることができます。
NodePort タイプ もしtype
フィールドの値をNodePort
に設定すると、Kubernetesコントロールプレーンは--service-node-port-range
フラグによって指定されたレンジのポート(デフォルト: 30000-32767)を割り当てます。
各Nodeはそのポート(各Nodeで同じポート番号)への通信をServiceに転送します。
作成したServiceは、.spec.ports[*].nodePort
フィールド内に割り当てられたポートを記述します。
もしポートへの通信を転送する特定のIPを指定したい場合、特定のIPブロックをkube-proxyの--nodeport-address
フラグで指定できます。これはKubernetes v1.10からサポートされています。
このフラグは、コンマ区切りのIPブロックのリスト(例: 10.0.0./8, 192.0.2.0/25)を使用し、kube-proxyがこのNodeに対してローカルとみなすべきIPアドレスの範囲を指定します。
例えば、--nodeport-addresses=127.0.0.0/8
というフラグによってkube-proxyを起動した時、kube-proxyはNodePort Serviceのためにループバックインターフェースのみ選択します。--nodeport-addresses
のデフォルト値は空のリストになります。これはkube-proxyがNodePort Serviceに対して全てのネットワークインターフェースを利用可能とするべきということを意味します(これは以前のKubernetesのバージョンとの互換性があります)。
もしポート番号を指定したい場合、nodePort
フィールドに値を指定できます。コントロールプレーンは指定したポートを割り当てるか、APIトランザクションが失敗したことを知らせるかのどちらかになります。
これは、ユーザーが自分自身で、ポート番号の衝突に関して気をつける必要があることを意味します。
また、ユーザーは有効なポート番号を指定する必要があり、NodePortの使用において、設定された範囲のポートを指定する必要があります。
NodePortの使用は、Kubernetesによって完全にサポートされていないようなユーザー独自の負荷分散を設定をするための有効な方法や、1つ以上のNodeのIPを直接公開するための方法となりえます。
注意点として、このServiceは<NodeIP>:spec.ports[*].nodePort
と、.spec.clusterIP:spec.ports[*].port
として疎通可能です。
(もしkube-proxyにおいて--nodeport-addressses
が設定された場合、はフィルターされたNodeIPとなります。)
例えば:
apiVersion : v1
kind : Service
metadata :
name : my-service
spec :
type : NodePort
selector :
app : MyApp
ports :
# デフォルトでは利便性のため、 `targetPort` は `port` と同じ値にセットされます。
- port : 80
targetPort : 80
# 省略可能なフィールド
# デフォルトでは利便性のため、Kubernetesコントロールプレーンはある範囲から1つポートを割り当てます(デフォルト値の範囲:30000-32767)
nodePort : 30007
LoadBalancer タイプ 外部のロードバランサーをサポートするクラウドプロバイダー上で、type
フィールドにLoadBalancer
を設定すると、Service用にロードバランサーがプロビジョニングされます。
実際のロードバランサーの作成は非同期で行われ、プロビジョンされたバランサーの情報は、Serviceの.status.loadBalancer
フィールドに記述されます。
例えば:
apiVersion : v1
kind : Service
metadata :
name : my-service
spec :
selector :
app : MyApp
ports :
- protocol : TCP
port : 80
targetPort : 9376
clusterIP : 10.0.171.239
type : LoadBalancer
status :
loadBalancer :
ingress :
- ip : 192.0.2.127
外部のロードバランサーからのトラフィックはバックエンドのPodに直接転送されます。クラウドプロバイダーはどのようにそのリクエストをバランシングするかを決めます。
LoadBalancerタイプのサービスで複数のポートが定義されている場合、すべてのポートが同じプロトコルである必要があり、さらにそのプロトコルはTCP
、UDP
、SCTP
のいずれかである必要があります。
いくつかのクラウドプロバイダーにおいて、loadBalancerIP
の設定をすることができます。このようなケースでは、そのロードバランサーはユーザーが指定したloadBalancerIP
に対してロードバランサーを作成します。
もしloadBalancerIP
フィールドの値が指定されていない場合、そのロードバランサーはエフェメラルなIPアドレスに対して作成されます。もしユーザーがloadBalancerIP
を指定したが、使っているクラウドプロバイダーがその機能をサポートしていない場合、そのloadBalancerIP
フィールドに設定された値は無視されます。
備考: もしSCTPを使っている場合、
LoadBalancer
タイプのServiceに関する
使用上の警告 を参照してください。
内部のロードバランサー 複雑な環境において、同一の(仮想)ネットワークアドレスブロック内のServiceからのトラフィックを転送する必要がでてきます。
Split-HorizonなDNS環境において、ユーザーは2つのServiceを外部と内部の両方からのトラフィックをエンドポイントに転送させる必要がでてきます。
ユーザーは、Serviceに対して下記のアノテーションを1つ追加することでこれを実現できます。
追加するアノテーションは、ユーザーが使っているクラウドプロバイダーに依存しています。
[...]
metadata :
name : my-service
annotations :
networking.gke.io/load-balancer-type : "Internal"
[...]
[...]
metadata :
name : my-service
annotations :
service.beta.kubernetes.io/aws-load-balancer-internal : 0.0.0.0 /0
[...]
[...]
metadata :
name : my-service
annotations :
service.beta.kubernetes.io/azure-load-balancer-internal : "true"
[...]
[...]
metadata :
name : my-service
annotations :
service.kubernetes.io/ibm-load-balancer-cloud-provider-ip-type : "private"
[...]
[...]
metadata :
name : my-service
annotations :
service.beta.kubernetes.io/openstack-internal-load-balancer : "true"
[...]
[...]
metadata :
name : my-service
annotations :
service.beta.kubernetes.io/cce-load-balancer-internal-vpc : "true"
[...]
[...]
metadata :
annotations :
service.kubernetes.io/qcloud-loadbalancer-internal-subnetid : subnet-xxxxx
[...]
AWSにおけるTLSのサポート AWS上で稼働しているクラスターにおいて、部分的なTLS/SSLのサポートをするには、LoadBalancer
Serviceに対して3つのアノテーションを追加できます。
metadata :
name : my-service
annotations :
service.beta.kubernetes.io/aws-load-balancer-ssl-cert : arn:aws:acm:us-east-1:123456789012:certificate/12345678-1234-1234-1234-123456789012
1つ目は、使用する証明書のARNです。これはIAMにアップロードされたサードパーティーが発行した証明書か、AWS Certificate Managerで作成された証明書になります。
metadata :
name : my-service
annotations :
service.beta.kubernetes.io/aws-load-balancer-backend-protocol : (https|http|ssl|tcp)
2つ目のアノテーションはPodが利用するプロトコルを指定するものです。HTTPSとSSLの場合、ELBはそのPodが証明書を使って暗号化されたコネクションを介して自分自身のPodを認証すると推測します。
HTTPとHTTPSでは、レイヤー7でのプロキシを選択します。ELBはユーザーとのコネクションを切断し、リクエストを転送するときにリクエストヘッダーをパースして、X-Forwarded-For
ヘッダーにユーザーのIPを追加します(Podは接続相手のELBのIPアドレスのみ確認可能です)。
TCPとSSLでは、レイヤー4でのプロキシを選択します。ELBはヘッダーの値を変更せずにトラフィックを転送します。
いくつかのポートがセキュアに保護され、他のポートではセキュアでないような混合した環境において、下記のようにアノテーションを使うことができます。
metadata :
name : my-service
annotations :
service.beta.kubernetes.io/aws-load-balancer-backend-protocol : http
service.beta.kubernetes.io/aws-load-balancer-ssl-ports : "443,8443"
上記の例では、もしServiceが80
、443
、8443
と3つのポートを含んでいる場合、443
と8443
はSSL証明書を使いますが、80
では単純にHTTPでのプロキシとなります。
Kubernetes v1.9以降のバージョンからは、Serviceのリスナー用にHTTPSやSSLと事前定義されたAWS SSLポリシー を使用できます。
どのポリシーが使用できるかを確認するために、aws
コマンドラインツールを使用できます。
aws elb describe-load-balancer-policies --query 'PolicyDescriptions[].PolicyName'
ユーザーは"service.beta.kubernetes.io/aws-load-balancer-ssl-negotiation-policy
"というアノテーションを使用することにより、複数のポリシーの中からどれか1つを指定できます。
例えば:
metadata :
name : my-service
annotations :
service.beta.kubernetes.io/aws-load-balancer-ssl-negotiation-policy : "ELBSecurityPolicy-TLS-1-2-2017-01"
AWS上でのPROXYプロトコルのサポート AWS上で稼働するクラスターでPROXY protocol のサポートを有効にするために、下記のServiceのアノテーションを使用できます。
metadata :
name : my-service
annotations :
service.beta.kubernetes.io/aws-load-balancer-proxy-protocol : "*"
Kubernetesバージョン1.3.0からは、このアノテーションを使用するとELBによってプロキシされた全てのポートが対象になり、そしてそれ以外の場合は構成されません。
AWS上でのELBのアクセスログ AWS上でのELB Service用のアクセスログを管理するためにはいくつかのアノテーションが使用できます。
service.beta.kubernetes.io/aws-load-balancer-access-log-enabled
というアノテーションはアクセスログを有効にするかを設定できます。
service.beta.kubernetes.io/aws-load-balancer-access-log-emit-interval
というアノテーションはアクセスログをパブリッシュするためのインターバル(分)を設定できます。
ユーザーはそのインターバルで5分もしくは60分で設定できます。
service.beta.kubernetes.io/aws-load-balancer-access-log-s3-bucket-name
というアノテーションはロードバランサーのアクセスログが保存されるAmazon S3のバケット名を設定できます。
service.beta.kubernetes.io/aws-load-balancer-access-log-s3-bucket-prefix
というアノテーションはユーザーが作成したAmazon S3バケットの論理的な階層を指定します。
metadata :
name : my-service
annotations :
service.beta.kubernetes.io/aws-load-balancer-access-log-enabled : "true"
# ロードバランサーのアクセスログが有効かどうか。
service.beta.kubernetes.io/aws-load-balancer-access-log-emit-interval : "60"
# アクセスログをパブリッシュするためのインターバル(分)。ユーザーはそのインターバルで5分もしくは60分で設定できます。
service.beta.kubernetes.io/aws-load-balancer-access-log-s3-bucket-name : "my-bucket"
# ロードバランサーのアクセスログが保存されるAmazon S3のバケット名。
service.beta.kubernetes.io/aws-load-balancer-access-log-s3-bucket-prefix : "my-bucket-prefix/prod"
# ユーザーが作成したAmazon S3バケットの論理的な階層。例えば: `my-bucket-prefix/prod`
AWSでの接続の中断 古いタイプのELBでの接続の中断は、service.beta.kubernetes.io/aws-load-balancer-connection-draining-enabled
というアノテーションを"true"
に設定することで管理できます。
service.beta.kubernetes.io/aws-load-balancer-connection-draining-timeout
というアノテーションで、インスタンスを登録解除するまえに既存の接続をオープンにし続けるための最大時間(秒)を指定できます。
metadata :
name : my-service
annotations :
service.beta.kubernetes.io/aws-load-balancer-connection-draining-enabled : "true"
service.beta.kubernetes.io/aws-load-balancer-connection-draining-timeout : "60"
他のELBアノテーション 古いタイプのELBを管理するためのアノテーションは他にもあり、下記で紹介します。
metadata :
name : my-service
annotations :
service.beta.kubernetes.io/aws-load-balancer-connection-idle-timeout : "60"
# ロードバランサーによってクローズされる前にアイドル状態(コネクションでデータは送信されない)になれる秒数
service.beta.kubernetes.io/aws-load-balancer-cross-zone-load-balancing-enabled : "true"
# ゾーンを跨いだロードバランシングが有効かどうか
service.beta.kubernetes.io/aws-load-balancer-additional-resource-tags : "environment=prod,owner=devops"
# ELBにおいて追加タグとして保存されるキー・バリューのペアのコンマ区切りのリスト
service.beta.kubernetes.io/aws-load-balancer-healthcheck-healthy-threshold : ""
# バックエンドへのトラフィックが正常になったと判断するために必要なヘルスチェックの連続成功数
# デフォルトでは2 この値は2から10の間で設定可能
service.beta.kubernetes.io/aws-load-balancer-healthcheck-unhealthy-threshold : "3"
# バックエンドへのトラフィックが異常になったと判断するために必要なヘルスチェックの連続失敗数
# デフォルトでは6 この値は2から10の間で設定可能
service.beta.kubernetes.io/aws-load-balancer-healthcheck-interval : "20"
# 各インスタンスのヘルスチェックのおよそのインターバル(秒)
# デフォルトでは10 この値は5から300の間で設定可能
service.beta.kubernetes.io/aws-load-balancer-healthcheck-timeout : "5"
# ヘルスチェックが失敗したと判断されるレスポンスタイムのリミット(秒)
# この値はservice.beta.kubernetes.io/aws-load-balancer-healthcheck-intervalの値以下である必要があります。
# デフォルトでは5 この値は2から60の間で設定可能
service.beta.kubernetes.io/aws-load-balancer-security-groups : "sg-53fae93f"
# ELBが作成される際に追加されるセキュリティグループのリスト
# service.beta.kubernetes.io/aws-load-balancer-extra-security-groupsアノテーションと異なり
# 元々ELBに付与されていたセキュリティグループを置き換えることになります。
service.beta.kubernetes.io/aws-load-balancer-extra-security-groups : "sg-53fae93f,sg-42efd82e"
# ELBに追加される予定のセキュリティーグループのリスト
service.beta.kubernetes.io/aws-load-balancer-target-node-labels : "ingress-gw,gw-name=public-api"
# ロードバランサーがターゲットノードを指定する際に利用するキーバリューのペアのコンマ区切りリストです。
AWSでのNetwork Load Balancerのサポート FEATURE STATE:
Kubernetes v1.15 [beta]
AWSでNetwork Load Balancerを使用するには、値をnlb
に設定してアノテーションservice.beta.kubernetes.io/aws-load-balancer-type
を付与します。
metadata :
name : my-service
annotations :
service.beta.kubernetes.io/aws-load-balancer-type : "nlb"
備考: NLBは特定のインスタンスクラスでのみ稼働します。サポートされているインスタンスタイプを確認するためには、ELBに関する
AWS documentation を参照してください。
古いタイプのElastic Load Balancersとは異なり、Network Load Balancers (NLBs)はクライアントのIPアドレスをNodeに転送します。
もしServiceの.spec.externalTrafficPolicy
の値がCluster
に設定されていた場合、クライアントのIPアドレスは末端のPodに伝播しません。
.spec.externalTrafficPolicy
をLocal
に設定することにより、クライアントIPアドレスは末端のPodに伝播します。しかし、これにより、トラフィックの分配が不均等になります。
特定のLoadBalancer Serviceに紐づいたPodがないNodeでは、自動的に割り当てられた.spec.healthCheckNodePort
に対するNLBのターゲットグループのヘルスチェックが失敗し、トラフィックを全く受信しません。
均等なトラフィックの分配を実現するために、DaemonSetの使用や、同一のNodeに配備しないようにPodのanti-affinity を設定します。
また、内部のロードバランサー のアノテーションとNLB Serviceを使用できます。
NLBの背後にあるインスタンスに対してクライアントのトラフィックを転送するために、Nodeのセキュリティーグループは下記のようなIPルールに従って変更されます。
Rule Protocol Port(s) IpRange(s) IpRange Description ヘルスチェック TCP NodePort(s) (.spec.healthCheckNodePort
for .spec.externalTrafficPolicy = Local
) VPC CIDR kubernetes.io/rule/nlb/health=<loadBalancerName> クライアントのトラフィック TCP NodePort(s) .spec.loadBalancerSourceRanges
(デフォルト: 0.0.0.0/0
)kubernetes.io/rule/nlb/client=<loadBalancerName> MTUによるサービスディスカバリー ICMP 3,4 .spec.loadBalancerSourceRanges
(デフォルト: 0.0.0.0/0
)kubernetes.io/rule/nlb/mtu=<loadBalancerName>
どのクライアントIPがNLBにアクセス可能かを制限するためには、loadBalancerSourceRanges
を指定してください。
spec :
loadBalancerSourceRanges :
- "143.231.0.0/16"
備考: もし.spec.loadBalancerSourceRanges
が設定されていない場合、KubernetesはNodeのセキュリティーグループに対して0.0.0.0/0
からのトラフィックを許可します。
もしNodeがパブリックなIPアドレスを持っていた場合、NLBでないトラフィックも修正されたセキュリティーグループ内の全てのインスタンスにアクセス可能になってしまうので注意が必要です。Tencent Kubernetes Engine(TKE)におけるその他のCLBアノテーション 以下に示すように、TKEでCloud Load Balancerを管理するためのその他のアノテーションがあります。
metadata :
name : my-service
annotations :
# 指定したノードでロードバランサーをバインドします
service.kubernetes.io/qcloud-loadbalancer-backends-label : key in (value1, value2)
# 既存のロードバランサーのID
service.kubernetes.io/tke-existed-lbid : lb-6swtxxxx
# ロードバランサー(LB)のカスタムパラメーターは、LBタイプの変更をまだサポートしていません
service.kubernetes.io/service.extensiveParameters : ""
# LBリスナーのカスタムパラメーター
service.kubernetes.io/service.listenerParameters : ""
# ロードバランサーのタイプを指定します
# 有効な値: classic(Classic Cloud Load Balancer)またはapplication(Application Cloud Load Balancer)
service.kubernetes.io/loadbalance-type : xxxxx
# パブリックネットワーク帯域幅の課金方法を指定します
# 有効な値: TRAFFIC_POSTPAID_BY_HOUR(bill-by-traffic)およびBANDWIDTH_POSTPAID_BY_HOUR(bill-by-bandwidth)
service.kubernetes.io/qcloud-loadbalancer-internet-charge-type : xxxxxx
# 帯域幅の値を指定します(値の範囲:[1-2000] Mbps)。
service.kubernetes.io/qcloud-loadbalancer-internet-max-bandwidth-out : "10"
# この注釈が設定されている場合、ロードバランサーはポッドが実行されているノードのみを登録します
# そうでない場合、すべてのノードが登録されます
service.kubernetes.io/local-svc-only-bind-node-with-pod : true
ExternalName タイプ ExternalNameタイプのServiceは、ServiceをDNS名とマッピングし、my-service
やcassandra
というような従来のラベルセレクターとはマッピングしません。
ユーザーはこれらのServiceにおいてspec.externalName
フィールドの値を指定します。
このServiceの定義では、例えばprod
というNamespace内のmy-service
というServiceをmy.database.example.com
にマッピングします。
apiVersion : v1
kind : Service
metadata :
name : my-service
namespace : prod
spec :
type : ExternalName
externalName : my.database.example.com
備考: ExternalNameはIpv4のアドレスの文字列のみ受け付けますが、IPアドレスではなく、数字で構成されるDNS名として受け入れます。
IPv4アドレスに似ているExternalNamesはCoreDNSもしくはIngress-Nginxによって名前解決されず、これはExternalNameは正規のDNS名を指定することを目的としているためです。
IPアドレスをハードコードする場合、
Headless Service の使用を検討してください。
my-service.prod.svc.cluster.local
というホストをルックアップするとき、クラスターのDNS Serviceはmy.database.example.com
という値をもつCNAME
レコードを返します。
my-service
へのアクセスは、他のServiceと同じ方法ですが、再接続する際はプロキシや転送を介して行うよりも、DNSレベルで行われることが決定的に異なる点となります。
後にユーザーが使用しているデータベースをクラスター内に移行することになった場合は、Podを起動させ、適切なラベルセレクターやEndpointsを追加し、Serviceのtype
を変更します。
警告: HTTPやHTTPSなどの一般的なプロトコルでExternalNameを使用する際に問題が発生する場合があります。ExternalNameを使用する場合、クラスター内のクライアントが使用するホスト名は、ExternalNameが参照する名前とは異なります。
ホスト名を使用するプロトコルの場合、この違いによりエラーまたは予期しない応答が発生する場合があります。HTTPリクエストがオリジンサーバーが認識しないHost:
ヘッダーを持っていたなら、TLSサーバーはクライアントが接続したホスト名に一致する証明書を提供できません。
External IPs もし1つ以上のクラスターNodeに転送するexternalIPが複数ある場合、Kubernetes ServiceはexternalIPs
に指定したIPで公開されます。
そのexternalIP(到達先のIPとして扱われます)のServiceのポートからトラフィックがクラスターに入って来る場合、ServiceのEndpointsのどれか1つに対して転送されます。
externalIPs
はKubernetesによって管理されず、それを管理する責任はクラスターの管理者にあります。
Serviceのspecにおいて、externalIPs
は他のどのServiceTypes
と併用して設定できます。
下記の例では、"my-service
"は"198.51.100.32:80
" (externalIP:port
)のクライアントからアクセス可能です。
apiVersion : v1
kind : Service
metadata :
name : my-service
spec :
selector :
app : MyApp
ports :
- name : http
protocol : TCP
port : 80
targetPort : 9376
externalIPs :
- 80.11.12.10
Serviceの欠点 仮想IP用にuserspaceモードのプロキシを使用すると、小規模もしくは中規模のスケールでうまく稼働できますが、1000以上のServiceがあるようなとても大きなクラスターではうまくスケールしません。
これについては、Serviceのデザインプロポーザル にてさらなる詳細を確認できます。
userspaceモードのプロキシの使用は、Serviceにアクセスするパケットの送信元IPアドレスが不明瞭になります。
これは、いくつかの種類のネットワークフィルタリング(ファイアウォールによるフィルタリング)を不可能にします。
iptablesプロキシモードはクラスター内の送信元IPを不明瞭にはしませんが、依然としてロードバランサーやNodePortへ疎通するクライアントに影響があります。
Type
フィールドはネストされた機能としてデザインされています。 - 各レベルの値は前のレベルに対して追加します。
これは全てのクラウドプロバイダーにおいて厳密に要求されていません(例: Google Compute EngineはLoadBalancer
を動作させるためにNodePort
を割り当てる必要はありませんが、AWSではその必要があります)が、現在のAPIでは要求しています。
仮想IPの実装について これより前の情報は、ただServiceを使いたいという多くのユーザーにとっては有益かもしれません。しかし、その裏側では多くのことが行われており、理解する価値があります。
衝突の回避 Kubernetesの主要な哲学のうちの一つは、ユーザーは、ユーザー自身のアクションによるミスでないものによって、ユーザーのアクションが失敗するような状況に晒されるべきでないことです。
Serviceリソースの設計において、これはユーザーの指定したポートが衝突する可能性がある場合はそのポートのServiceを作らないことを意味します。これは障害を分離することとなります。
Serviceのポート番号を選択できるようにするために、我々はどの2つのServiceでもポートが衝突しないことを保証します。
Kubernetesは各Serviceに、それ自身のIPアドレスを割り当てることで実現しています。
各Serviceが固有のIPを割り当てられるのを保証するために、内部のアロケーターは、Serviceを作成する前に、etcd内のグローバルの割り当てマップをアトミックに更新します。
そのマップオブジェクトはServiceのIPアドレスの割り当てのためにレジストリー内に存在しなくてはならず、そうでない場合は、Serviceの作成時にIPアドレスが割り当てられなかったことを示すエラーメッセージが表示されます。
コントロールプレーンにおいて、バックグラウンドのコントローラーはそのマップを作成する責務があります(インメモリーのロックが使われていた古いバージョンのKubernetesからのマイグレーションをサポートすることも必要です)。
また、Kubernetesは(例えば、管理者の介入によって)無効な割り当てがされているかをチェックすることと、現時点でどのServiceにも使用されていない割り当て済みIPアドレスのクリーンアップのためにコントローラーを使用します。
ServiceのIPアドレス 実際に固定された向き先であるPodのIPアドレスとは異なり、ServiceのIPは実際には単一のホストによって応答されません。
その代わり、kube-proxyは必要な時に透過的にリダイレクトされる仮想 IPアドレスを定義するため、iptables(Linuxのパケット処理ロジック)を使用します。
クライアントがVIPに接続する時、そのトラフィックは自動的に適切なEndpointsに転送されます。
Service用の環境変数とDNSは、Serviceの仮想IPアドレス(とポート)の面において、自動的に生成されます。
kube-proxyは3つの微妙に異なった動作をするプロキシモード— userspace、iptablesとIPVS — をサポートしています。
Userspace 例として、上記で記述されている画像処理のアプリケーションを考えます。
バックエンドのServiceが作成されたとき、KubernetesのMasterは仮想IPを割り当てます。例えば10.0.0.1などです。
そのServiceのポートが1234で、そのServiceはクラスター内の全てのkube-proxyインスタンスによって監視されていると仮定します。
kube-proxyが新しいServiceを見つけた時、kube-proxyは新しいランダムポートをオープンし、その仮想IPアドレスの新しいポートにリダイレクトするようにiptablesを更新し、そのポート上で新しい接続を待ち受けを開始します。
クライアントがServiceの仮想IPアドレスに接続したとき、iptablesルールが有効になり、そのパケットをプロキシ自身のポートにリダイレクトします。
その"Service プロキシ"はバックエンドPodの対象を選択し、クライアントのトラフィックをバックエンドPodに転送します。
これはServiceのオーナーは、衝突のリスクなしに、求めるどのようなポートも選択できることを意味します。
クライアントは単純にそのIPとポートに対して接続すればよく、実際にどのPodにアクセスしているかを意識しません。
iptables また画像処理のアプリケーションについて考えます。バックエンドServiceが作成された時、そのKubernetesコントロールプレーンは仮想IPアドレスを割り当てます。例えば10.0.0.1などです。
Serviceのポートが1234で、そのServiceがクラスター内のすべてのkube-proxyインスタンスによって監視されていると仮定します。
kube-proxyが新しいServiceを見つけた時、kube-proxyは仮想IPから各Serviceのルールにリダイレクトされるような、iptablesルールのセットをインストールします。
Service毎のルールは、トラフィックをバックエンドにリダイレクト(Destination NATを使用)しているEndpoints毎のルールに対してリンクしています。
クライアントがServiceの仮想IPアドレスに対して接続しているとき、そのiptablesルールが有効になります。
バックエンドのPodが選択され(SessionAffinityに基づくか、もしくはランダムで選択される)、パケットはバックエンドにリダイレクトされます。
userspaceモードのプロキシとは異なり、パケットは決してuserspaceにコピーされず、kube-proxyは仮想IPのために稼働される必要はなく、またNodeでは変更されていないクライアントIPからトラフィックがきます。
このように同じ基本的なフローは、NodePortまたはLoadBalancerを介してトラフィックがきた場合に、実行され、ただクライアントIPは変更されます。
IPVS iptablesの処理は、大規模なクラスターの場合劇的に遅くなります。例としてはServiceが10,000ほどある場合です。
IPVSは負荷分散のために設計され、カーネル内のハッシュテーブルに基づいています。そのためIPVSベースのkube-proxyによって、多数のServiceがある場合でも一貫して高パフォーマンスを実現できます。
次第に、IPVSベースのkube-proxyは負荷分散のアルゴリズムはさらに洗練されています(最小接続数、位置ベース、重み付け、永続性など)。
APIオブジェクト ServiceはKubernetesのREST APIにおいてトップレベルのリソースです。ユーザーはそのAPIオブジェクトに関して、Service API object でさらなる情報を確認できます。
サポートされているプロトコル TCP ユーザーはどの種類のServiceにおいてもTCPを利用できます。これはデフォルトのネットワークプロトコルです。
UDP ユーザーは多くのServiceにおいてUDPを利用できます。 type=LoadBalancerのServiceにおいては、UDPのサポートはこの機能を提供しているクラウドプロバイダーに依存しています。
HTTP もしクラウドプロバイダーがサポートしている場合、ServiceのEndpointsに転送される外部のHTTP/HTTPSでのリバースプロキシをセットアップするために、LoadBalancerモードでServiceを作成可能です。
備考: ユーザーはまた、HTTP/HTTPS Serviceを公開するために、Serviceの代わりに
Ingress を利用することもできます。
PROXY プロトコル もしクラウドプロバイダーがサポートしている場合、Kubernetesクラスターの外部のロードバランサーを設定するためにLoadBalancerモードでServiceを利用できます。これはPROXY protocol がついた接続を転送します。
ロードバランサーは、最初の一連のオクテットを送信します。
下記のような例となります。
PROXY TCP4 192.0.2.202 10.0.42.7 12345 7\r\n
クライアントからのデータのあとに追加されます。
SCTP FEATURE STATE:
Kubernetes v1.19 [beta]
KubernetesはService、Endpoints、EndpointSlice、NetworkPolicyとPodの定義においてprotocol
フィールドの値でSCTPをサポートしています。ベータ版の機能のため、この機能はデフォルトで有効になっています。SCTPをクラスターレベルで無効にするには、クラスター管理者はAPI ServerにおいてSCTPSupport
フィーチャーゲート を--feature-gates=SCTPSupport=false,…
と設定して無効にする必要があります。
そのフィーチャーゲートが有効になった時、ユーザーはService、Endpoints、EndpointSlice、NetworkPolicy、またはPodのprotocol
フィールドにSCTP
を設定できます。
Kubernetesは、TCP接続と同様に、SCTPアソシエーションに応じてネットワークをセットアップします。
警告 マルチホームSCTPアソシエーションのサポート 警告: マルチホームSCTPアソシエーションのサポートは、複数のインターフェースとPodのIPアドレスの割り当てをサポートできるCNIプラグインを要求します。
マルチホームSCTPアソシエーションにおけるNATは、対応するカーネルモジュール内で特別なロジックを要求します。
type=LoadBalancer Service について
警告: クラウドプロバイダーのロードバランサーの実装がプロトコルとしてSCTPをサポートしている場合は、type
がLoadBalancerで protocol
がSCTPの場合でのみサービスを作成できます。
そうでない場合、Serviceの作成要求はリジェクトされます。現時点でのクラウドのロードバランサーのプロバイダー(Azure、AWS、CloudStack、GCE、OpenStack)は全てSCTPのサポートをしていません。Windows
警告: SCTPはWindowsベースのNodeではサポートされていません。Userspace kube-proxy
警告: kube-proxyはuserspaceモードにおいてSCTPアソシエーションの管理をサポートしません。次の項目 5.2 - Ingress
FEATURE STATE:
Kubernetes v1.19 [stable]
クラスター内のServiceに対する外部からのアクセス(主にHTTP)を管理するAPIオブジェクトです。
Ingressは負荷分散、SSL終端、名前ベースの仮想ホスティングの機能を提供します。
用語 簡単のために、このガイドでは次の用語を定義します。
ノード: Kubernetes内のワーカーマシンで、クラスターの一部です。 クラスター: Kubernetesによって管理されているコンテナ化されたアプリケーションを実行させるノードの集合です。この例や、多くのKubernetesによるデプロイでは、クラスター内のノードはインターネットに公開されていません。 エッジルーター: クラスターでファイアウォールのポリシーを強制するルーターです。クラウドプロバイダーが管理するゲートウェイや、物理的なハードウェアの一部である場合もあります。 クラスターネットワーク: 物理的または論理的な繋がりの集合で、Kubernetesのネットワークモデル によって、クラスター内でのコミュニケーションを司るものです。 Service: ラベル セレクターを使ったPodの集合を特定するKubernetes Service です。特に指定がない限り、Serviceはクラスターネットワーク内でのみ疎通可能な仮想IPを持つものとして扱われます。 Ingressとは何か Ingress はクラスター外からクラスター内Service へのHTTPとHTTPSのルートを公開します。トラフィックのルーティングはIngressリソース上で定義されるルールによって制御されます。
全てのトラフィックを単一のServiceに送る単純なIngressの例を示します。
図. Ingress
IngressはServiceに対して、外部疎通できるURL、負荷分散トラフィック、SSL/TLS終端の機能や、名前ベースの仮想ホスティングを提供するように設定できます。Ingressコントローラー は通常はロードバランサーを使用してIngressの機能を実現しますが、エッジルーターや、追加のフロントエンドを構成してトラフィックの処理を支援することもできます。
Ingressは任意のポートやプロトコルを公開しません。HTTPやHTTPS以外のServiceをインターネットに公開する場合、Service.Type=NodePort やService.Type=LoadBalancer のServiceタイプを一般的には使用します。
Ingressを使用する上での前提条件 Ingressを提供するためにはIngressコントローラー が必要です。Ingressリソースを作成するのみでは何の効果もありません。
ingress-nginx のようなIngressコントローラーのデプロイが必要な場合があります。いくつかのIngressコントローラー の中から選択してください。
理想的には、全てのIngressコントローラーはリファレンスの仕様を満たすはずです。しかし実際には、各Ingressコントローラーは微妙に異なる動作をします。
備考: Ingressコントローラーのドキュメントを確認して、選択する際の注意点について理解してください。Ingressリソース Ingressリソースの最小構成の例は以下のとおりです。
apiVersion : networking.k8s.io/v1
kind : Ingress
metadata :
name : minimal-ingress
annotations :
nginx.ingress.kubernetes.io/rewrite-target : /
spec :
ingressClassName : nginx-example
rules :
- http :
paths :
- path : /testpath
pathType : Prefix
backend :
service :
name : test
port :
number : 80
IngressにはapiVersion
、kind
、metadata
やspec
フィールドが必要です。Ingressオブジェクトの名前は、有効なDNSサブドメイン名 である必要があります。設定ファイルに関する一般的な情報は、アプリケーションのデプロイ 、コンテナの設定 、リソースの管理 を参照してください。Ingressでは、Ingressコントローラーに依存しているいくつかのオプションの設定をするためにアノテーションを一般的に使用します。例としては、rewrite-targetアノテーション などがあります。Ingressコントローラー の種類が異なれば、サポートするアノテーションも異なります。サポートされているアノテーションについて学ぶためには、使用するIngressコントローラーのドキュメントを確認してください。
Ingress Spec は、ロードバランサーやプロキシサーバーを設定するために必要な全ての情報を持っています。最も重要なものとして、外部からくる全てのリクエストに対して一致したルールのリストを含みます。IngressリソースはHTTP(S)トラフィックに対してのルールのみサポートしています。
ingressClassName
が省略された場合、デフォルトのIngressClass を定義する必要があります。
デフォルトのIngressClass
を定義しなくても動作するIngressコントローラーがいくつかあります。例えば、Ingress-NGINXコントローラーはフラグ
--watch-ingress-without-class
で設定できます。ただし、下記 のようにデフォルトのIngressClass
を指定することを推奨します 。
Ingressのルール 各HTTPルールは以下の情報を含みます。
オプションで設定可能なホスト名。上記のリソースの例では、ホスト名が指定されていないので、そのルールは指定されたIPアドレスを経由する全てのインバウンドHTTPトラフィックに適用されます。ホスト名が指定されていると(例: foo.bar.com)、そのルールは指定されたホストに対して適用されます。 パスのリスト(例: /testpath
)。各パスにはservice.name
とservice.port.name
またはservice.port.number
で定義されるバックエンドが関連づけられます。ロードバランサーがトラフィックを関連づけられたServiceに転送するために、外部からくるリクエストのホスト名とパスが条件と一致させる必要があります。 バックエンドはServiceドキュメント に書かれているようなService名とポート名の組み合わせ、またはCRD によるカスタムリソースバックエンド です。Ingressで設定されたホスト名とパスのルールに一致するHTTP(とHTTPS)のリクエストは、リスト内のバックエンドに対して送信されます。 Ingressコントローラーでは、defaultBackend
が設定されていることがあります。これはSpec内で指定されているパスに一致しないようなリクエストのためのバックエンドです。
デフォルトのバックエンド ルールが設定されていないIngressは、全てのトラフィックを単一のデフォルトのバックエンドに転送します。.spec.defaultBackend
はその場合にリクエストを処理するバックエンドになります。defaultBackend
は、Ingressコントローラー のオプション設定であり、Ingressリソースでは指定されていません。.spec.rules
を設定しない場合、.spec.defaultBackend
の設定は必須です。defaultBackend
が設定されていない場合、どのルールにもマッチしないリクエストの処理は、Ingressコントローラーに任されます(このケースをどう処理するかは、お使いのIngressコントローラーのドキュメントを参照してください)。
HTTPリクエストがIngressオブジェクトのホスト名とパスの条件に1つも一致しない時、そのトラフィックはデフォルトのバックエンドに転送されます。
リソースバックエンド Resource
バックエンドはIngressオブジェクトと同じnamespaceにある他のKubernetesリソースを指すObjectRefです。
Resource
はServiceの設定とは排他であるため、両方を指定するとバリデーションに失敗します。
<