1 - Kubernetesとは何か?

Kubernetesは、宣言的な構成管理と自動化を促進し、コンテナ化されたワークロードやサービスを管理するための、ポータブルで拡張性のあるオープンソースのプラットフォームです。Kubernetesは巨大で急速に成長しているエコシステムを備えており、それらのサービス、サポート、ツールは幅広い形で利用可能です。

このページでは、Kubernetesの概要について説明します。

Kubernetesは、宣言的な構成管理と自動化を促進し、コンテナ化されたワークロードやサービスを管理するための、ポータブルで拡張性のあるオープンソースのプラットフォームです。Kubernetesは巨大で急速に成長しているエコシステムを備えており、それらのサービス、サポート、ツールは幅広い形で利用可能です。

Kubernetesの名称は、ギリシャ語に由来し、操舵手やパイロットを意味しています。Googleは2014年にKubernetesプロジェクトをオープンソース化しました。Kubernetesは、本番環境で大規模なワークロードを稼働させたGoogleの15年以上の経験と、コミュニティからの最高のアイディアや実践を組み合わせています。

過去を振り返ってみると

過去を振り返って、Kubernetesがなぜこんなに便利なのかを見てみましょう。

Deployment evolution

仮想化ができる前の時代におけるデプロイ (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へどのように移行するかは問題ではありません。集中管理も必要ありません。これにより、使いやすく、より強力で、堅牢で、弾力性と拡張性があるシステムが実現します。

次の項目

2 - Kubernetesのコンポーネント

Kubernetesクラスターはコントロールプレーンやノードと呼ばれるマシン群といったコンポーネントからなります。

Kubernetesをデプロイすると、クラスターが展開されます。

Kubernetesクラスターは、 コンテナ化されたアプリケーションを実行する、ノードと呼ばれるワーカーマシンの集合です。すべてのクラスターには少なくとも1つのワーカーノードがあります。

ワーカーノードは、アプリケーションのコンポーネントであるPodをホストします。マスターノードは、クラスター内のワーカーノードとPodを管理します。複数のマスターノードを使用して、クラスターにフェイルオーバーと高可用性を提供します。 ワーカーノードは、アプリケーションワークロードのコンポーネントであるPodをホストします。コントロールプレーンは、クラスター内のワーカーノードとPodを管理します。本番環境では、コントロールプレーンは複数のコンピューターを使用し、クラスターは複数のノードを使用し、耐障害性や高可用性を提供します。

このドキュメントでは、Kubernetesクラスターが機能するために必要となるさまざまなコンポーネントの概要を説明します。

すべてのコンポーネントが結び付けられたKubernetesクラスターの図を次に示します。

Kubernetesのコンポーネント

コントロールプレーンコンポーネント

コントロールプレーンコンポーネントは、クラスターに関する全体的な決定(スケジューリングなど)を行います。また、クラスターイベントの検出および応答を行います(たとえば、deploymentのreplicasフィールドが満たされていない場合に、新しい Pod を起動する等)。

コントロールプレーンコンポーネントはクラスター内のどのマシンでも実行できますが、シンプルにするため、セットアップスクリプトは通常、すべてのコントロールプレーンコンポーネントを同じマシンで起動し、そのマシンではユーザーコンテナを実行しません。 マルチマスター VMセットアップの例については、高可用性クラスターの構築 を参照してください。

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

コントロールプレーン上で動作するコンポーネントで、複数のコントローラープロセスを実行します。

論理的には、各コントローラーは個別のプロセスですが、複雑さを減らすために一つの実行ファイルにまとめてコンパイルされ、単一のプロセスとして動きます。

コントローラーには以下が含まれます。

  • ノードコントローラー:ノードがダウンした場合の通知と対応を担当します。
  • レプリケーションコントローラー:システム内の全レプリケーションコントローラーオブジェクトについて、Podの数を正しく保つ役割を持ちます。
  • エンドポイントコントローラー:エンドポイントオブジェクトを注入します(つまり、ServiceとPodを紐付けます)。
  • サービスアカウントとトークンコントローラー:新規の名前空間に対して、デフォルトアカウントとAPIアクセストークンを作成します。

cloud-controller-manager

クラウド特有の制御ロジックを組み込むKubernetesのcontrol planeコンポーネントです。クラウドコントロールマネージャーは、クラスターをクラウドプロバイダーAPIをリンクし、クラスタのみで相互作用するコンポーネントからクラウドプラットフォームで相互作用するコンポーネントを分離します。

cloud-controller-managerは、クラウドプロバイダー固有のコントローラーのみを実行します。 KubernetesをオンプレミスあるいはPC内での学習環境で動かす際には、クラスターにcloud container managerはありません。

kube-controller-managerを使用すると、cloud-controller-managerは複数の論理的に独立したコントロールループをシングルバイナリにまとめ、これが一つのプロセスとして動作します。パフォーマンスを向上させるあるいは障害に耐えるために水平方向にスケールする(一つ以上のコピーを動かす)ことができます。

次のコントローラーには、クラウドプロバイダーへの依存関係を持つ可能性があります。

  • ノードコントローラー:ノードが応答を停止した後、クラウドで削除されたかどうかを判断するため、クラウドプロバイダーをチェックします。
  • ルーティングコントローラー:基盤であるクラウドインフラでルーティングを設定します。
  • サービスコントローラー:クラウドプロバイダーのロードバランサーの作成、更新、削除を行います。

ノードコンポーネント

ノードコンポーネントはすべてのノードで実行され、稼働中のPodの管理やKubernetesの実行環境を提供します。

kubelet

クラスター内の各ノードで実行されるエージェントです。各コンテナPodで実行されていることを保証します。

kubeletは、さまざまなメカニズムを通じて提供されるPodSpecのセットを取得し、それらのPodSpecに記述されているコンテナが正常に実行されている状態を保証します。kubeletは、Kubernetesが作成したものではないコンテナは管理しません。

kube-proxy

kube-proxyはクラスター内の各nodeで動作しているネットワークプロキシで、KubernetesのServiceコンセプトの一部を実装しています。

kube-proxyは、Nodeのネットワークルールをメンテナンスします。これらのネットワークルールにより、クラスターの内部または外部のネットワークセッションからPodへのネットワーク通信が可能になります。

kube-proxyは、オペレーティングシステムにパケットフィルタリング層があり、かつ使用可能な場合、パケットフィルタリング層を使用します。それ以外の場合は自身でトラフィックを転送します。

コンテナランタイム

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

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

アドオン

アドオンはクラスター機能を実装するためにKubernetesリソース(DaemonSetDeploymentなど)を使用します。 アドオンはクラスターレベルの機能を提供しているため、アドオンのリソースで名前空間が必要なものはkube-system名前空間に属します。

いくつかのアドオンについて以下で説明します。より多くの利用可能なアドオンのリストは、アドオン をご覧ください。

DNS

クラスターDNS以外のアドオンは必須ではありませんが、すべてのKubernetesクラスターはクラスターDNSを持つべきです。多くの使用例がクラスターDNSを前提としています。

クラスターDNSは、環境内の他のDNSサーバーに加えて、KubernetesサービスのDNSレコードを提供するDNSサーバーです。

Kubernetesによって開始されたコンテナは、DNS検索にこのDNSサーバーを自動的に含めます。

Web UI (ダッシュボード)

ダッシュボードは、Kubernetesクラスター用の汎用WebベースUIです。これによりユーザーはクラスターおよびクラスター内で実行されているアプリケーションについて、管理およびトラブルシューティングを行うことができます。

コンテナリソース監視

コンテナリソース監視は、コンテナに関する一般的な時系列メトリックを中央データベースに記録します。また、そのデータを閲覧するためのUIを提供します。

クラスターレベルログ

クラスターレベルログメカニズムは、コンテナのログを、検索/参照インターフェイスを備えた中央ログストアに保存します。

次の項目

3 - Kubernetes API

Kubernetes APIを使用すると、Kubernetes内のオブジェクトの状態をクエリで操作できます。 Kubernetesのコントロールプレーンの中核は、APIサーバーとそれが公開するHTTP APIです。ユーザー、クラスターのさまざまな部分、および外部コンポーネントはすべて、APIサーバーを介して互いに通信します。

Kubernetesの中核である control planeAPI 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.25では、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バージョンで提供することができます。

例えば、同じリソースでv1v1beta1の2つのバージョンが有ることを考えてみます。v1beta1バージョンのAPIを利用しオブジェクトを最初に作成したとして、v1beta1もしくはv1どちらのAPIバージョンを利用してもオブジェクトのread、update、deleteができます。

APIの変更

成功を収めているシステムはすべて、新しいユースケースの出現や既存の変化に応じて成長し、変化する必要があります。 したがって、Kubernetesには、Kubernetes APIを継続的に変更および拡張できる設計機能があります。 Kubernetesプロジェクトは、既存のクライアントとの互換性を破壊 しないこと 、およびその互換性を一定期間維持して、他のプロジェクトが適応する機会を提供することを目的としています。

基本的に、新しいAPIリソースと新しいリソースフィールドは追加することができます。 リソースまたはフィールドを削除するには、API非推奨ポリシーに従ってください。

Kubernetesは、公式のKubernetes APIが一度一般提供(GA)に達した場合、通常はv1APIバージョンです、互換性を維持することを強い責任があります。さらに、Kubernetesは beta についても可能な限り互換性を維持し続けます。ベータAPIを採用した場合、その機能が安定版になったあとでも、APIを利用してクラスタを操作し続けることができます。

APIバージョンレベルの定義に関する詳細はAPIバージョンのリファレンスを参照してください。

APIの拡張

Kubernetes APIは2つの方法で拡張できます。

  1. カスタムリソースは、APIサーバーが選択したリソースAPIをどのように提供するかを宣言的に定義します。
  2. アグリゲーションレイヤーを実装することでKubernetes APIを拡張することもできます。

次の項目

  • 自分自身でカスタムリソース定義を追加してKubernetes APIを拡張する方法について学んでください。
  • Kubernetes APIのアクセス制御では、クラスターがAPIアクセスの認証と承認を管理する方法を説明しています。
  • APIリファレンスを読んで、APIエンドポイント、リソースタイプやサンプルについて学んでください。
  • APIの変更から、互換性のある変更とは何か, どのようにAPIを変更するかについて学んでください。

4 - Kubernetesオブジェクトを利用する

Kubernetesオブジェクトは、Kubernetes上で永続的なエンティティです。Kubernetesはこれらのエンティティを使い、クラスターの状態を表現します。 Kubernetesオブジェクトモデルと、これらのオブジェクトの利用方法について学びます。

4.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 - オブジェクトを一意に特定するための情報、文字列のnameUID、また任意のnamespaceが該当する
  • spec - オブジェクトの望ましい状態

specの正確なフォーマットは、Kubernetesオブジェクトごとに異なり、オブジェクトごとに特有な入れ子のフィールドを持っています。Kubernetes API リファレンスが、Kubernetesで作成できる全てのオブジェクトに関するspecのフォーマットを探すのに役立ちます。 例えば、Podオブジェクトに関するspecのフォーマットはPodSpec v1 coreを、またDeploymentオブジェクトに関するspecのフォーマットはDeploymentSpec v1 appsをご確認ください。

次の項目

  • 最も重要、かつ基本的なKubernetesオブジェクト群を学びましょう、例えば、Podです。
  • Kubernetesのコントローラーを学びましょう。
  • Using the Kubernetes APIはこのページでは取り上げていない他のAPIについて説明します。

4.2 - Kubernetesオブジェクト管理

kubectlコマンドラインツールは、Kubernetesオブジェクトを作成、管理するためにいくつかの異なる方法をサポートしています。 このドキュメントでは、それらの異なるアプローチごとの概要を提供します。 Kubectlを使ったオブジェクト管理の詳細は、Kubectl bookを参照してください。

管理手法

管理手法 何を対象にするか 推奨環境 サポートライター 学習曲線
命令型コマンド 現行のオブジェクト 開発用プロジェクト 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リファレンスを参照してください。

設定ファイルに定義されたオブジェクトを作成します:

kubectl create -f nginx.yaml

設定ファイルに定義されたオブジェクトを削除します:

kubectl delete -f nginx.yaml -f redis.yaml

設定ファイルに定義された情報で、現行の設定を上書き更新します:

kubectl replace -f nginx.yaml

トレードオフ

命令型コマンド手法に対する長所:

  • オブジェクト設定をGitのような、ソースコード管理システムに格納することができます
  • オブジェクト設定の変更内容をプッシュする前にレビュー、監査証跡を残すようなプロセスと連携することができます
  • オブジェクト設定は新しいオブジェクトを作る際のテンプレートを提供します

命令型コマンド手法に対する短所:

  • オブジェクト設定ではオブジェクトスキーマの基礎的な理解が必要です
  • オブジェクト設定ではYAMLファイルを書くという、追加のステップが必要です

宣言型オブジェクト設定手法に対する長所:

  • 命令型オブジェクト設定の振る舞いは、よりシンプルで簡単に理解ができます
  • Kubernetesバージョン1.5においては、命令型オブジェクト設定の方がより成熟しています

宣言型オブジェクト設定手法に対する短所:

  • 命令型オブジェクト設定は各ファイルごとに設定を書くには最も適していますが、ディレクトリには適していません
  • 現行オブジェクトの更新は設定ファイルに対して反映しなければなりません。反映されない場合、次の置き換え時に更新内容が失われてしまいます

宣言型オブジェクト設定

宣言型オブジェクト設定を利用する場合、ユーザーはローカルに置かれている設定ファイルを操作します。 しかし、ユーザーはファイルに対する操作内容を指定しません。作成、更新、そして削除といった操作はオブジェクトごとにkubectlが検出します。 この仕組みが、異なるオブジェクトごとに異なる操作をディレクトリに対して行うことを可能にしています。

configディレクトリ配下にある全てのオブジェクト設定ファイルを処理し、作成、または現行オブジェクトへのパッチを行います。 まず、diffでどのような変更が行われるかを確認した後に適用します:

kubectl diff -f configs/
kubectl apply -f configs/

再帰的にディレクトリを処理します:

kubectl diff -R -f configs/
kubectl apply -R -f configs/

トレードオフ

命令型オブジェクト設定手法に対する長所:

  • 現行オブジェクトに直接行われた変更が、それらが設定ファイルに反映されていなかったとしても、保持されます
  • 宣言型オブジェクト設定は、ディレクトリごとの処理をより良くサポートしており、自動的にオブジェクトごとに操作のタイプ(作成、パッチ、削除)を検出します

命令型オブジェクト設定手法に対する短所:

  • 宣言型オブジェクト設定は、デバッグ、そして想定外の結果が出たときに理解するのが困難です
  • 差分を利用した一部のみの更新は、複雑なマージ、パッチの操作が必要です

次の項目

4.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として標準化されています。

次の項目

4.4 - Namespace(名前空間)

Kubernetesは、同一の物理クラスター上で複数の仮想クラスターの動作をサポートします。 この仮想クラスターをNamespaceと呼びます。

複数のNamespaceを使う時

Namespaceは、複数のチーム・プロジェクトにまたがる多くのユーザーがいる環境での使用を目的としています。 数人から数十人しかユーザーのいないクラスターに対して、あなたはNamespaceを作成したり、考える必要は全くありません。 Kubernetesが提供するNamespaceの機能が必要となった時に、Namespaceの使用を始めてください。

Namespaceは名前空間のスコープを提供します。リソース名は単一のNamespace内ではユニークである必要がありますが、Namespace全体ではその必要はありません。Namespaceは相互にネストすることはできず、各Kubernetesリソースは1つのNamespaceにのみ存在できます。

Namespaceは、複数のユーザーの間でクラスターリソースを分割する方法です。(これはリソースクォータを介して分割します。)

同じアプリケーションの異なるバージョンなど、少し違うリソースをただ分割するだけに、複数のNamespaceを使う必要はありません。 同一のNamespace内でリソースを区別するためにはラベルを使用してください。

Namespaceを利用する

Namespaceの作成と削除方法はNamespaceの管理ガイドドキュメントに記載されています。

Namespaceの表示

ユーザーは、以下の方法で単一クラスター内の現在のNamespaceの一覧を表示できます。

kubectl get 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を持っていないオブジェクトのためのデフォルトNamespace
  • kube-system Kubernetesシステムによって作成されたオブジェクトのためのNamespace
  • kube-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

次の項目

4.5 - ラベル(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: productionapp: 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タイプは、それらのセレクターの妥当性とそれらが示す意味をドキュメントに記載するべきです。

等価ベース(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: "k8s.gcr.io/cuda-vector-add:v0.1"
      resources:
        limits:
          nvidia.com/gpu: 1
  nodeSelector:
    accelerator: nvidia-tesla-p100

集合ベース(Set-based) の要件(requirement)

集合ベース(Set-based) のラベルの要件は値のセットによってキーをフィルタリングします。
innotinexistsの3つのオペレーターをサポートしています(キーを特定するのみ)。

例えば:

environment in (production, qa)
tier notin (frontend, backend)
partition
!partition
  • 最初の例では、キーがenvironmentで、値がproductionqaに等しいリソースを全て選択します。
  • 第2の例では、キーがtierで、値がfrontendbackend以外のもの、そしてtierキーを持たないリソースを全て選択します。
  • 第3の例では、partitionというキーをもつラベルを全て選択し、値はチェックしません。
  • 第4の例では、partitionというキーを持たないラベルを全て選択し、値はチェックしません。

同様に、コンマセパレーターは、AND オペレーターと同様にふるまいます。そのため、partitionenvironmentキーの値がともに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)'

もしくは、exists オペレーターを介して、否定マッチングによる制限もできます。

kubectl get pods -l 'environment,environment notin (frontend)'

APIオブジェクトに参照を設定する

ServiceReplicationControllerのような、いくつかのKubernetesオブジェクトでは、ラベルセレクターをPodのような他のリソースのセットを指定するのにも使われます。

ServiceとReplicationController

Serviceが対象とするPodの集合は、ラベルセレクターによって定義されます。
同様に、ReplicationControllerが管理するべきPod数についてもラベルセレクターを使って定義されます。

それぞれのオブジェクトに対するラベルセレクターはマップを使ってjsonもしくはyaml形式のファイルで定義され、等価ベース のセレクターのみサポートされています。

"selector": {
    "component" : "redis",
}

もしくは

selector:
    component: redis

このセレクター(それぞれjsonまたはyaml形式)は、component=redisまたはcomponent in (redis)と等価です。

集合ベース の要件指定をサポートするリソース

JobDeploymentReplicaSetDaemonSetなどの比較的新しいリソースは、集合ベース での要件指定もサポートしています。

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セレクター要件のリストです。対応しているオペレーターはInNotInExistsDoesNotExistです。valuesのセットは、InNotInオペレーターにおいては空文字を許容しません。
matchLabelsmatchExpressionsの両方によって指定された全ての要件指定はANDで判定されます。つまり要件にマッチするには指定された全ての要件を満たす必要があります。

Nodeのセットを選択する

ラベルを選択するための1つのユースケースはPodがスケジュールできるNodeのセットを制限することです。
さらなる情報に関しては、Node選定 のドキュメントを参照してください。

4.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

次の項目

ラベルとセレクターについて学習してください。

4.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

サポートされているフィールド

サポートされているフィールドセレクターはKubernetesリソースタイプによって異なります。全てのリソースタイプはmetadata.namemetadata.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.phaseRunnningでなく、かつ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

4.8 - 推奨ラベル(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/namewordpressと記述され、インスタンス名に関してはapp.kubernetes.io/instancewordpress-abcxzyと記述されます。この仕組みはアプリケーションと、アプリケーションのインスタンスを特定可能にします。全てのアプリケーションインスタンスは固有の名前を持たなければなりません。

ラベルの使用例

ここでは、ラベルの異なる使用例を示します。これらの例はそれぞれシステムの複雑さが異なります。

シンプルなステートレスサービス

DeploymentServiceオブジェクトを使って、シンプルなステートレスサービスをデプロイするケースを考えます。下記の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のStatefulSetServiceにより、MySQLとWordPressに関するより広範な情報が含まれていることに気づくでしょう。