Kubernetes 1.31: Fine-grained SupplementalGroups control

この記事ではKubernetes 1.31の新機能である、Pod内のコンテナにおける補助グループ制御の改善機能について説明します。

動機: コンテナイメージ内の/etc/groupに定義される暗黙的なグループ情報

この挙動は多くのKubernetesクラスターのユーザー、管理者にとってあまり知られていないかもしれませんが、Kubernetesは、デフォルトでは、Podで定義された情報に加えて、コンテナイメージ内の/etc/groupのグループ情報を マージ します。

例を見てみましょう。このPodはsecurityContextでrunAsUser=1000runAsGroup=3000supplementalGroups=4000を指定しています。

apiVersion: v1
kind: Pod
metadata:
  name: implicit-groups
spec:
  securityContext:
    runAsUser: 1000
    runAsGroup: 3000
    supplementalGroups: [4000]
  containers:
  - name: ctr
    image: registry.k8s.io/e2e-test-images/agnhost:2.45
    command: [ "sh", "-c", "sleep 1h" ]
    securityContext:
      allowPrivilegeEscalation: false

ctrコンテナでidコマンドを実行すると何が出力されるでしょうか?

# Podを作成してみましょう。
$ kubectl apply -f https://k8s.io/blog/2024-08-22-Fine-grained-SupplementalGroups-control/implicit-groups.yaml

# Podのコンテナが実行されていることを確認します。
$ kubectl get pod implicit-groups

# idコマンドを確認します。
$ kubectl exec implicit-groups -- id

出力は次のようになるでしょう。

uid=1000 gid=3000 groups=3000,4000,50000

Podマニフェストには50000は一切定義されていないにもかかわらず、補助グループ(groupsフィールド)に含まれているグループID50000は一体どこから来るのでしょうか? 答えはコンテナイメージの/etc/groupファイルです。

コンテナイメージの/etc/groupの内容が下記のようになっていることが確認できるでしょう。

$ kubectl exec implicit-groups -- cat /etc/group
...
user-defined-in-image:x:1000:
group-defined-in-image:x:50000:user-defined-in-image

なるほど!コンテナのプライマリユーザーであるユーザー(1000)がグループ(50000)に属していることが最後のエントリから確認出来ました。

このように、コンテナイメージ上の/etc/groupで定義される、コンテナのプライマリユーザーのグループ情報は、Podからの情報に加えて 暗黙的にマージ されます。ただし、この挙動は、現在のCRI実装がDockerから引き継いだ設計上の決定であり、コミュニティはこれまでこの挙動について再検討することはほとんどありませんでした。

何が悪いのか?

コンテナイメージの/etc/groupから 暗黙的にマージ されるグループ情報は、特にボリュームアクセスを行う際に、セキュリティ上の懸念を引き起こすことがあります(詳細はkubernetes/kubernetes#112879を参照してください)。なぜなら、Linuxにおいて、ファイルパーミッションはuid/gidで制御されているからです。更に悪いことに、/etc/groupに由来する暗黙的なgidは、マニフェストにグループ情報の手がかりが無いため、ポリシーエンジン等でチェック・検知をすることが出来ません。これはKubernetesセキュリティの観点からも懸念となります。

PodにおけるFine-grained(きめ細かい) SupplementalGroups control: SupplementaryGroupsPolicy

この課題を解決するために、Kubernetes 1.31はPodの.spec.securityContextに、新しくsupplementalGroupsPolicyフィールドを追加します。

このフィールドは、Pod内のコンテナプロセスに付与される補助グループを決定するを方法を制御できるようにします。有効なポリシーは次の2つです。

  • Merge: /etc/groupで定義されている、コンテナのプライマリユーザーが所属するグループ情報をマージします。指定されていない場合、このポリシーがデフォルトです(後方互換性を考慮して既存の挙動と同様)。

  • Strict: fsGroupsupplementalGroupsrunAsGroupフィールドで指定されたグループIDのみ補助グループに指定されます。つまり、/etc/groupで定義された、コンテナのプライマリユーザーのグループ情報はマージされません。

では、どのようにStrictポリシーが動作するか見てみましょう。

apiVersion: v1
kind: Pod
metadata:
  name: strict-supplementalgroups-policy
spec:
  securityContext:
    runAsUser: 1000
    runAsGroup: 3000
    supplementalGroups: [4000]
    supplementalGroupsPolicy: Strict
  containers:
  - name: ctr
    image: registry.k8s.io/e2e-test-images/agnhost:2.45
    command: [ "sh", "-c", "sleep 1h" ]
    securityContext:
      allowPrivilegeEscalation: false
# Podを作成してみましょう。
$ kubectl apply -f https://k8s.io/blog/2024-08-22-Fine-grained-SupplementalGroups-control/strict-supplementalgroups-policy.yaml

# Podのコンテナが実行されていることを確認します。
$ kubectl get pod strict-supplementalgroups-policy

# プロセスのユーザー、グループ情報を確認します。
kubectl exec -it strict-supplementalgroups-policy -- id

出力はこのようになります。

uid=1000 gid=3000 groups=3000,4000

Strictポリシーによってグループ50000groupsから除外されているのが確認できました!

このように、確実にsupplementalGroupsPolicy: Strictを設定する(ポリシーエンジン等によって強制する)ことで、暗黙的な補助グループを回避することが可能になります。

Podステータスにおける付与されたユーザー、グループ情報の確認

この機能は、Podのstatus.containerStatuses[].user.linuxフィールドでコンテナの最初のプロセスに付与されたユーザー、グループ情報を公開しています。暗黙的なグループIDが付与されているかどうかを確認するのに便利でしょう。

...
status:
  containerStatuses:
  - name: ctr
    user:
      linux:
        gid: 3000
        supplementalGroups:
        - 3000
        - 4000
        uid: 1000
...

この機能を利用するには

supplementalGroupsPolicyフィールドを有効化するには、下記のコンポーネントを利用する必要があります。

  • Kubernetes: v1.31以降、かつ、SupplementalGroupsPolicyフィーチャーゲートが有効化されていること。v1.31現在、このフィーチャーゲートはアルファです。
  • CRI実装:
    • containerd: v2.0以降
    • CRI-O: v1.31以降

ノードの.status.features.supplementalGroupsPolicyフィールドでこの機能が利用可能かどうか確認出来ます。

apiVersion: v1
kind: Node
...
status:
  features:
    supplementalGroupsPolicy: true

将来の展望

Kubernetes SIG Nodeは、この機能が将来的なKubernetesのリリースでベータ版に昇格し、最終的には一般提供(GA)されることを望んでおり、期待しています。そうなれば、ユーザーはもはや機能ゲートを手動で有効にする必要がなくなります。

supplementalGroupsPolicyが指定されていない場合は、後方互換性のためにMergeポリシーが適用されます。

より学ぶには?

参加するには?

この機能はSIG Nodeコミュニティによって推進されています。コミュニティに参加して、上記の機能やそれ以外のアイデアやフィードバックを共有してください。皆さんからのご意見をお待ちしています!

Kubernetes v1.31: キャッシュからの整合性のある読み込みによるクラスターパフォーマンスの向上

Kubernetesはコンテナ化されたアプリケーションの堅牢なオーケストレーションで知られていますが、クラスターの規模が拡大するにつれて、コントロールプレーンへの負荷がボトルネックとなる可能性があります。 特に大きな課題となっていたのは、etcdデータストアからのデータ読み込みの厳密な整合性を保証することです。 これを実現するには、リソースを大量に消費するクォーラム読み込みが必要でした。

本日、Kubernetesコミュニティは、大きな改善を発表できることを嬉しく思います。 Kubernetes v1.31において、「キャッシュからの整合性のある読み込み」がベータ版に移行しました。

なぜ整合性のある読み込みが重要なのか

Kubernetes コンポーネントがクラスターの最新状態を正確に把握するためには、整合性のある読み込みが不可欠です。 整合性のある読み込みを保証することで、Kubernetesの操作の正確性と信頼性が維持され、各コンポーネントは最新の情報に基づいて適切な判断を下すことができます。 しかし、大規模なクラスターでは、そのためのデータの取得と処理がパフォーマンスのボトルネックとなるおそれがあります。 特に、結果のフィルタリングを伴うリクエストでこの問題が顕著になります。 Kubernetesはetcd内で名前空間ごとにデータを直接フィルタリングできますが、ラベルやフィールドセレクタによるその他のフィルタリングでは、データセット全体をetcdから取得し、Kubernetes APIサーバーがメモリ上でフィルタリングを行う必要があります。 この問題は、特にkubeletなどのコンポーネントに大きな影響を与えます。 kubeletは自身のノードにスケジュールされたPodのみをリストするだけで足りるところを、これまでの仕組みでは、APIサーバーとetcdがクラスター内のすべてのPodを処理する必要がありました。

ブレイクスルー: 信頼性の高いキャッシング

Kubernetesは、読み込み操作を最適化するために、以前からWatchキャッシュを使用してきました。 Watchキャッシュはクラスターの状態のスナップショットを保存し、etcdのWatchを通じて更新情報を受け取ります。 しかし、これまではキャッシュが完全に最新の状態であることを保証できなかったため、整合性のある読み込みを直接提供することができませんでした。

「キャッシュからの整合性のある読み込み」機能は、etcdの進捗通知のメカニズムを活用してこの問題に対処します。 この通知により、Watchキャッシュは自身とetcdを比較し、データが最新かどうかを把握できます。 整合性のある読み込みが要求されると、システムはまずWatchキャッシュの内容が最新かどうかを確認します。 キャッシュが最新でない場合、システムはキャッシュの内容が完全に更新されたと確認できるまで、etcdに進捗通知を問い合わせ続けます。 そして準備が整うと、要求されたデータはキャッシュから直接読み取られ効率的に提供されます。 このため、特にetcdから大量のデータを取得する必要があるような場面で、パフォーマンスを大幅に向上させることができます。 以上のようにして、データをフィルタリングするリクエストをキャッシュから処理できるようになり、etcdから読み取る必要のあるメタデータは最小限に抑えられます。

重要な注意点: この機能を利用するには、Kubernetesクラスタでetcdバージョン3.4.31以降または3.5.13以降を実行している必要があります。 古いバージョンのetcdを使用している場合、etcdから直接整合性のある読み込みを行う方式に自動で切り替わります。

体感できるパフォーマンスの向上

この一見単純な変更は、Kubernetesのパフォーマンスとスケーラビリティに大きな影響を与えます。

  • etcdの負荷軽減: Kubernetes v1.31では、etcdの作業負荷を軽減し、他の重要な操作のためにリソースを解放できます。
  • レイテンシの短縮: キャッシュからの読み込みは、etcdからデータを取得して処理するよりもはるかに高速です。 これはコンポーネントへの応答が迅速になり、クラスター全体の応答性が向上することを意味します。
  • スケーラビリティの向上: etcdの負荷軽減により、コントロールプレーンはパフォーマンスを犠牲にすることなくより多くのリクエストを処理できるようになるため、 数千ものノードとPodを持つような大規模なクラスターでは、最も大きなメリットが得られます。

5,000ノードのスケーラビリティテスト結果: 5,000ノードのクラスタで行われた最近のスケーラビリティテストでは、キャッシュからの整合性のある読み込みを有効にすることで、以下のような目覚ましい改善が見られました。

  • kube-apiserverのCPU使用率が 30%削減
  • etcdのCPU使用率が 25%削減
  • PodのLISTリクエストの99パーセンタイルレイテンシが最大 3分の1に短縮 (5秒から1.5秒)

今後の予定

ベータ版への移行により、キャッシュからの整合性のある読み込みはデフォルトで有効になり、サポートされているetcdバージョンを実行しているすべてのKubernetesユーザーにシームレスなパフォーマンス向上を提供します。

私たちの旅はこれで終わりではありません。 Kubernetesコミュニティは、将来的にさらにパフォーマンスを最適化するために、Watchキャッシュでのページネーションのサポートを積極的に検討しています。

はじめ方

Kubernetes v1.31にアップグレードし、etcdバージョン3.4.31以降または3.5.13以降を使用していることを確認するのが、キャッシュからの整合性のある読み込みのメリットを体験する最も簡単な方法です。 ご質問やフィードバックがある場合は、Kubernetesコミュニティまでお気軽にお問い合わせください。

キャッシュからの整合性のある読み込みによって、あなたのKubernetes体験がどう変わったか、ぜひ教えてください!

この機能への貢献に対して、@ah8ad3 と @p0lyn0mial に特別な感謝を捧げます。

Kubernetes v1.31: Elli

編集者: Matteo Bianchi, Yigit Demirbas, Abigail McCarthy, Edith Puclla, Rashan Smith

Kubernetes v1.31: Elliのリリースを発表します!

これまでのリリースと同様に、Kubernetes v1.31では新たなGA、ベータ、アルファの機能が導入されています。 継続的に高品質なリリースを提供できていることは、私たちの開発サイクルの強さと、活発なコミュニティのサポートを示すものです。 今回のリリースでは、45の機能強化が行われました。 そのうち、11の機能がGAに昇格し、22の機能がベータに移行し、12の機能がアルファとして導入されています。

リリースのテーマとロゴ

Kubernetes v1.31のリリーステーマは"Elli"です。

Kubernetes v1.31のElliは、優しい心を持つ愛らしい犬で、かわいらしい船乗りの帽子をかぶっています。 これは、多様で大きなKubernetesコントリビューターファミリーへの遊び心あふれる敬意を表しています。

Kubernetes v1.31は、プロジェクトが10周年を祝った後の初めてのリリースです。 Kubernetesは誕生以来、長い道のりを歩んできました。 そして今もなお、各リリースで新たな方向に進化し続けています。 10年という節目を迎え、これを実現させた数え切れないほどのKubernetesコントリビューターたちの努力、献身、技術、知恵、そして地道な作業を振り返ると、深い感銘を受けずにはいられません。

プロジェクトの運営には膨大な労力が必要ですが、それにもかかわらず、熱意と笑顔を持って何度も貢献し、コミュニティの一員であることに誇りを感じる人々が絶えません。 新旧問わずコントリビューターから見られるこの「魂」こそが、活気に満ちた、まさに「喜びにあふれた」コミュニティの証なのです。

Kubernetes v1.31のElliは、まさにこの素晴らしい精神を祝福する存在なのです! Kubernetesの輝かしい次の10年に、みんなで乾杯しましょう!

GAに昇格した機能のハイライト

これは、v1.31のリリースに伴いGAとなった改善点の一部です。

AppArmorのサポートがGAに

KubernetesのAppArmorサポートがGAになりました。 コンテナのsecurityContext内のappArmorProfile.typeフィールドを設定することで、AppArmorを使用してコンテナを保護できます。 Kubernetes v1.30より前では、AppArmorはアノテーションで制御されていましたが、v1.30からはフィールドを使用して制御されるようになりました。 そのためアノテーションの使用をやめ、appArmorProfile.typeフィールドの使用に移行することをお勧めします。

詳細については、AppArmorのチュートリアルをご覧ください。 この機能は、SIG NodeによってKEP #24の一環として開発しました。

kube-proxyによる外部からの接続の安定性改善

kube-proxyを使用した外部からの接続の安定性が、v1.31で大きく改善されました。 Kubernetesのロードバランサーに関する一般的な課題の1つに、トラフィックの損失を防ぐための各コンポーネント間の連携があります。 この機能では、kube-proxyに新たな仕組みを導入し、type: LoadBalancerexternalTrafficPolicy: Clusterを設定したサービスで公開される終了予定のNodeに対して、ロードバランサーが接続をスムーズに切り替えられるようにしています。 また、クラウドプロバイダーとKubernetesのロードバランサー実装における推奨プラクティスも確立しました。

この機能を利用するには、kube-proxyがクラスタ上でデフォルトのサービスプロキシとして動作し、ロードバランサーが接続の切り替えをサポートしている必要があります。 特別な設定は不要で、v1.30からkube-proxyにデフォルトで組み込まれており、v1.31で正式にGAとなりました。

詳しくは、仮想IPとサービスプロキシのドキュメントをご覧ください。

この機能は、SIG NetworkKEP #3836の一環として開発しました。

永続ボリュームの状態変化時刻の記録機能が正式リリース

永続ボリュームの状態変化時刻を記録する機能が、v1.31で正式にリリースされました。 この機能により、PersistentVolumeの状態が最後に変わった時刻を保存するPersistentVolumeStatusフィールドが追加されます。 機能が有効になると、すべてのPersistentVolumeオブジェクトに.status.lastTransitionTimeという新しいフィールドが設けられ、ボリュームの状態が最後に変わった時刻が記録されます。 ただし、この変更はすぐには反映されません。 Kubernetes v1.31にアップグレードした後、PersistentVolumeが更新され、状態(PendingBoundReleased)が初めて変わったときに、新しいフィールドに時刻が記録されます。 この機能により、PersistentVolumeがPendingからBoundに変わるまでの時間を測定できるようになります。 また、様々な指標やSLOの設定にも活用できます。

詳しくは、永続ボリュームのドキュメントをご覧ください。

この機能は、SIG StorageKEP #3762の一環として開発しました。

ベータに昇格した機能のハイライト

これは、v1.31のリリースに伴いベータとなった改善点の一部です。

kube-proxyでのnftablesバックエンドの導入

v1.31では、nftablesバックエンドがベータとして登場しました。 この機能はNFTablesProxyModeという設定で制御され、現在はデフォルトで有効になっています。

nftables APIは、iptables APIの次世代版として開発され、より高いパフォーマンスと拡張性を提供します。 nftablesプロキシモードは、iptablesモードと比べてサービスエンドポイントの変更をより迅速かつ効率的に処理できます。 また、カーネル内でのパケット処理も効率化されています(ただし、この効果は数万のサービスを持つ大規模クラスタでより顕著になります)。

Kubernetes v1.31の時点では、nftablesモードはまだ新しい機能のため、すべてのネットワークプラグインとの互換性が確認されているわけではありません。 お使いのネットワークプラグインのドキュメントで対応状況を確認してください。 このプロキシモードはLinux Nodeのみで利用可能で、カーネル5.13以降が必要です。 移行を検討する際は、特にNodePortサービスに関連する一部の機能が、iptablesモードとnftablesモードで完全に同じように動作しない点に注意が必要です。 デフォルト設定の変更が必要かどうかは、移行ガイドで確認してください。

この機能は、SIG NetworkKEP #3866の一環として開発しました。

永続ボリュームのreclaimポリシーに関する変更

Kubernetes v1.31では、PersistentVolumeのreclaimポリシーを常に尊重する機能がベータになりました。 この機能強化により、関連するPersistentVolumeClaim(PVC)が削除された後でも、PersistentVolume(PV)のreclaimポリシーが確実に適用されるようになり、ボリュームの漏洩を防止します。

これまでは、PVとPVCのどちらが先に削除されたかによって、特定の条件下でPVに設定されたreclaimポリシーが無視されることがありました。 その結果、reclaimポリシーが"Delete"に設定されていても、外部インフラの対応するストレージリソースが削除されないケースがありました。 これにより、一貫性の欠如やリソースのリークが発生する可能性がありました。

この機能の導入により、PVとPVCの削除順序に関係なく、reclaimポリシーの"Delete"が確実に実行され、バックエンドインフラから基盤となるストレージオブジェクトが削除されることがKubernetesによって保証されるようになりました。

この機能は、SIG StorageKEP #2644の一環として開発しました。

バインドされたサービスアカウントトークンの改善

ServiceAccountTokenNodeBinding機能が、v1.31でベータに昇格しました。 この機能により、PodではなくNodeにのみバインドされたトークンを要求できるようになりました。 このトークンには、Node情報が含まれており、トークンが使用される際にNodeの存在を検証します。 詳しくは、バインドされたサービスアカウントトークンのドキュメントをご覧ください。

この機能は、SIG AuthKEP #4193の一環として開発しました。

複数のサービスCIDRのサポート

v1.31では、複数のサービスCIDRを持つクラスターのサポートがベータになりました(デフォルトでは無効)。

Kubernetesクラスターには、IPアドレスを使用する複数のコンポーネントがあります: Node、Pod、そしてServiceです。 NodeとPodのIP範囲は、それぞれインフラストラクチャやネットワークプラグインに依存するため、動的に変更できます。 しかし、サービスのIP範囲は、クラスター作成時にkube-apiserverのハードコードされたフラグとして定義されていました。 長期間運用されているクラスターや大規模なクラスターでは、管理者が割り当てられたサービスCIDR範囲を拡張、縮小、あるいは完全に置き換える必要があり、IPアドレスの枯渇が問題となっていました。 これらの操作は正式にサポートされておらず、複雑で繊細なメンテナンス作業を通じて行われ、しばしばクラスタのダウンタイムを引き起こしていました。 この新機能により、ユーザーとクラスター管理者はダウンタイムなしでサービスCIDR範囲を動的に変更できるようになります。

この機能の詳細については、仮想IPとサービスプロキシのドキュメントページをご覧ください。

この機能は、SIG NetworkKEP #1880の一環として開発しました。

サービスのトラフィック分散機能

サービスのトラフィック分散機能が、v1.31でベータとなり、デフォルトで有効になりました。

SIG Networkingは、サービスネットワーキングにおける最適なユーザー体験とトラフィック制御機能を見出すため、何度も改良を重ねてきました。 その結果、サービス仕様にtrafficDistributionフィールドを実装しました。 このフィールドは、ルーティングの決定を行う際に、基盤となる実装が考慮すべき指針として機能します。

この機能の詳細については、1.30リリースブログをお読みいただくか、サービスのドキュメントページをご覧ください。

この機能は、SIG NetworkKEP #4444の一環として開発しました。

Kubernetes VolumeAttributesClassによるボリューム修正機能

VolumeAttributesClass APIが、v1.31でベータになります。 VolumeAttributesClassは、プロビジョニングされたIOのような動的なボリュームパラメータを修正するための、Kubernetes独自の汎用APIを提供します。 これにより、プロバイダーがサポートしている場合、ワークロードはコストとパフォーマンスのバランスを取るために、オンラインでボリュームを垂直スケーリングできるようになります。 この機能は、Kubernetes 1.29からアルファとして提供されていました。

この機能は、SIG Storageが主導し、KEP #3751の一環として開発しました。

アルファとして導入された新機能

これは、v1.31のリリースでアルファとして導入された主な改善点の一部です。

アクセラレータなどのハードウェア管理を改善する新しいDRA API

Kubernetes v1.31では、動的リソース割り当て(DRA)APIとその設計が更新されました。 この更新の主な焦点は構造化パラメータにあります。 これにより、リソース情報とリクエストがKubernetesとクライアントに対して透明になり、クラスタのオートスケーリングなどの機能の実装が可能になります。 kubeletのDRAサポートも更新され、kubeletとコントロールプレーン間のバージョンの違いに対応できるようになりました。 構造化パラメータにより、スケジューラはPodのスケジューリング時にResourceClaimを割り当てます。 DRAドライバコントローラによる割り当ては、現在「クラシックDRA」と呼ばれる方法でも引き続きサポートされています。

Kubernetes v1.31では、クラシックDRAにDRAControlPlaneControllerという別のフィーチャーゲートが用意されており、これを明示的に有効にする必要があります。 このコントロールプレーンコントローラーを使用することで、DRAドライバは構造化パラメータではまだサポートされていない割り当てポリシーを実装できます。

この機能は、SIG NodeKEP #3063の一環として開発しました。

イメージボリュームのサポート

Kubernetesコミュニティは、将来的に人工知能(AI)や機械学習(ML)のユースケースをより多く実現することを目指しています。

これらのユースケースを実現するための要件の1つは、Open Container Initiative(OCI)互換のイメージやアーティファクト(OCIオブジェクトと呼ばれる)を、ネイティブのボリュームソースとして直接サポートすることです。 これにより、ユーザーはOCI標準に集中でき、OCIレジストリを使用してあらゆるコンテンツを保存・配布できるようになります。

そこで、v1.31では、OCIイメージをPod内のボリュームとして使用できる新しいアルファ機能が追加されました。 この機能により、ユーザーはPod内でイメージ参照をボリュームとして指定し、それをコンテナ内のボリュームマウントとして再利用できます。 この機能を試すには、ImageVolumeフィーチャーゲートを有効にする必要があります。

この機能は、SIG NodeSIG StorageKEP #4639の一環として開発しました。

Podステータスを通じたデバイスの健全性情報の公開

Podステータスを通じてデバイスの健全性情報を公開する機能が、v1.31で新しいアルファ機能として追加されました。デフォルトでは無効になっています。

Kubernetes v1.31以前では、Podが故障したデバイスと関連付けられているかどうかを知る方法は、PodResources APIを使用することでした。

この機能を有効にすると、各Pod の.status内の各コンテナステータスにallocatedResourcesStatusフィールドが追加されます。 allocatedResourcesStatusフィールドは、コンテナに割り当てられた各デバイスの健全性情報を報告します。

この機能は、SIG NodeKEP #4680の一環として開発しました。

セレクターに基づいたより細かな認可

この機能により、Webhookオーソライザーや将来の(現在は設計されていない)ツリー内オーソライザーが、ラベルやフィールドセレクターを使用するリクエストに限り、listwatchリクエストを許可できるようになります。 例えば、オーソライザーは次のような表現が可能になります: このユーザーはすべてのPodをリストできないが、.spec.nodeNameが特定の値に一致するPodはリストできる。 あるいは、ユーザーが名前空間内のconfidential: trueとラベル付けされていないすべてのSecretを監視することを許可する。 CRDフィールドセレクター(これもv1.31でベータに移行)と組み合わせることで、より安全なNodeごとの拡張機能を作成することが可能になります。

この機能は、SIG AuthKEP #4601の一環として開発しました。

匿名APIアクセスへの制限

AnonymousAuthConfigurableEndpointsフィーチャーゲートを有効にすることで、ユーザーは認証設定ファイルを使用して、匿名リクエストがアクセスできるエンドポイントを設定できるようになりました。 これにより、匿名ユーザーにクラスタへの広範なアクセスを与えてしまうようなRBAC設定ミスから、ユーザー自身を守ることができます。

この機能は、SIG AuthKEP #4633の一環として開発しました。

1.31における機能の昇格、非推奨化、および削除

GAへの昇格

ここでは、GA(一般提供とも呼ばれる)に昇格したすべての機能を紹介します。新機能やアルファからベータへの昇格を含む完全な更新リストについては、リリースノートをご覧ください。

このリリースでは、以下の11個の機能強化がGAに昇格しました:

非推奨化と削除

Kubernetesの開発と成熟に伴い、プロジェクト全体の健全性のために、機能が非推奨化、削除、またはより良いものに置き換えられる場合があります。 このプロセスの詳細については、Kubernetesの非推奨化と削除のポリシーをご覧ください。

cgroup v1のメンテナンスモードへの移行

Kubernetesがコンテナオーケストレーションの変化に適応し続ける中、コミュニティはv1.31でcgroup v1のサポートをメンテナンスモードに移行することを決定しました。 この変更は、業界全体のcgroup v2への移行と歩調を合わせており、機能性、拡張性、そしてより一貫性のあるインターフェースの向上を提供します。 Kubernetesのメンテナンスモードとは、cgroup v1サポートに新機能が追加されないことを意味します。 重要なセキュリティ修正は引き続き提供されますが、バグ修正はベストエフォートとなり、重大なバグは可能な場合修正されますが、一部の問題は未解決のままとなる可能性があります。

できるだけ早くcgroup v2への移行を開始することをお勧めします。 この移行はアーキテクチャに依存し、基盤となるオペレーティングシステムとコンテナランタイムがcgroup v2をサポートしていることを確認し、ワークロードとアプリケーションがcgroup v2で正しく機能することを検証するためのテストを含みます。

問題が発生した場合は、issueを作成して報告してください。

この機能は、SIG NodeKEP #4569の一環として開発しました。

SHA-1署名サポートに関する注意事項

go1.18(2022年3月リリース)以降、crypto/x509ライブラリはSHA-1ハッシュ関数で署名された証明書を拒否するようになりました。 SHA-1は安全でないことが確立されており、公的に信頼された認証局は2015年以降SHA-1証明書を発行していません。 Kubernetesのコンテキストでは、アグリケーションAPIサーバーやWebhookに使用される私的な認証局を通じてSHA-1ハッシュ関数で署名されたユーザー提供の証明書が依然として存在する可能性があります。 SHA-1ベースの証明書を使用している場合は、環境にGODEBUG=x509sha1=1を設定することで、明示的にそのサポートを有効にする必要があります。

GoのGODEBUGの互換性ポリシーに基づき、x509sha1 GODEBUGとSHA-1証明書のサポートは、go1.24で完全に削除される予定です。 go1.24は2025年前半にリリースされる予定です。 SHA-1証明書に依存している場合は、できるだけ早く移行を開始してください。

SHA-1サポートの終了時期、Kubernetesリリースがgo1.24を採用する計画、およびメトリクスと監査ログを通じてSHA-1証明書の使用を検出する方法の詳細については、Kubernetes issue #125689をご覧ください。

Nodeのstatus.nodeInfo.kubeProxyVersionフィールドの非推奨化(KEP 4004)

Kubernetes v1.31では、Nodeの.status.nodeInfo.kubeProxyVersionフィールドが非推奨となり、将来のリリースで削除される予定です。 このフィールドの値が正確ではなかった(そして現在も正確ではない)ため、非推奨化されています。 このフィールドはkubeletによって設定されますが、kubeletはkube-proxyのバージョンやkube-proxyが実行されているかどうかについて信頼できる情報を持っていません。

v1.31では、DisableNodeKubeProxyVersionフィーチャーゲートがデフォルトでtrueに設定され、kubeletは関連するNodeの.status.kubeProxyVersionフィールドを設定しなくなります。

クラウドプロバイダーとの全てのインツリー統合の削除

以前の記事で強調したように、クラウドプロバイダー統合の最後に残っていたインツリーサポートがv1.31リリースの一部として削除されました。 これは、クラウドプロバイダーと統合できなくなったという意味ではありません。 ただし、外部統合を使用する推奨アプローチを必ず使用する必要があります。 一部の統合はKubernetesプロジェクトの一部であり、他はサードパーティのソフトウェアです。

この節目は、Kubernetes v1.26から始まった、全てのクラウドプロバイダー統合のKubernetesコアからの外部化プロセスの完了を示しています(KEP-2395)。 この変更により、Kubernetesは真にベンダー中立なプラットフォームに近づきます。

クラウドプロバイダー統合の詳細については、v1.29 クラウドプロバイダー統合機能のブログ記事をお読みください。 インツリーのコード削除に関する追加の背景については、(v1.29 非推奨化ブログ)をご確認ください。

後者のブログには、v1.29以降のバージョンに移行する必要があるユーザーにとって有用な情報も含まれています。

インツリープロバイダーのフィーチャーゲートの削除

Kubernetes v1.31では、以下のアルファフィーチャーゲートが削除されました: InTreePluginAWSUnregisterInTreePluginAzureDiskUnregisterInTreePluginAzureFileUnregisterInTreePluginGCEUnregisterInTreePluginOpenStackUnregister、およびInTreePluginvSphereUnregister。 これらのフィーチャーゲートは、実際にコードベースから削除することなく、インツリーのボリュームプラグインが削除されたシナリオのテストを容易にするために導入されました。 Kubernetes 1.30でこれらのインツリーのボリュームプラグインが非推奨となったため、これらのフィーチャーゲートは冗長となり、もはや目的を果たさなくなりました。 唯一残っているCSIの移行ゲートはInTreePluginPortworxUnregisterで、これはPortworxのCSI移行が完了し、そのツリー内ボリュームプラグインの削除準備が整うまでアルファのままとなります。

kubeletの--keep-terminated-pod-volumesコマンドラインフラグの削除

2017年に非推奨となったkubeletのフラグ--keep-terminated-pod-volumesが、v1.31リリースの一部として削除されました。

詳細については、Pull Request #122082をご覧ください。

CephFSボリュームプラグインの削除

CephFSボリュームプラグインがこのリリースで削除され、cephfsボリュームタイプは機能しなくなりました。

代わりに、サードパーティのストレージドライバーとしてCephFS CSIドライバーを使用することをお勧めします。 クラスターバージョンをv1.31にアップグレードする前にCephFSボリュームプラグインを使用していた場合は、新しいドライバーを使用するようにアプリケーションを再デプロイする必要があります。

CephFSボリュームプラグインは、v1.28で正式に非推奨とマークされていました。

Ceph RBDボリュームプラグインの削除

v1.31リリースでは、Ceph RBDボリュームプラグインとそのCSI移行サポートが削除され、rbdボリュームタイプは機能しなくなりました。

代わりに、クラスターでRBD CSIドライバーを使用することをお勧めします。 クラスターバージョンをv1.31にアップグレードする前にCeph RBDボリュームプラグインを使用していた場合は、新しいドライバーを使用するようにアプリケーションを再デプロイする必要があります。

Ceph RBDボリュームプラグインは、v1.28で正式に非推奨とマークされていました。

kube-schedulerにおける非CSIボリューム制限プラグインの非推奨化

v1.31リリースでは、すべての非CSIボリューム制限スケジューラープラグインが非推奨となり、デフォルトプラグインから既に非推奨となっているいくつかのプラグインが削除されます。 これには以下が含まれます:

  • AzureDiskLimits
  • CinderLimits
  • EBSLimits
  • GCEPDLimits

これらのボリュームタイプはCSIに移行されているため、代わりにNodeVolumeLimitsプラグインを使用することをお勧めします。 NodeVolumeLimitsプラグインは、削除されたプラグインと同じ機能を処理できます。 スケジューラーの設定で明示的にこれらのプラグインを使用している場合は、非推奨のプラグインをNodeVolumeLimitsプラグインに置き換えてください。 AzureDiskLimitsCinderLimitsEBSLimitsGCEPDLimitsプラグインは将来のリリースで削除される予定です。

これらのプラグインは、Kubernetes v1.14以降非推奨となっていたため、デフォルトのスケジューラープラグインリストから削除されます。

リリースノートとアップグレードに必要なアクション

Kubernetes v1.31リリースの詳細については、リリースノートをご確認ください。

SchedulerQueueingHintsが有効な場合、スケジューラーはQueueingHintを使用するようになりました

スケジューラーに、Pod/Updatedイベントに登録されたQueueingHintを使用して、以前スケジュール不可能だったPodの更新がそれらをスケジュール可能にしたかどうかを判断するサポートが追加されました。 この新機能は、フィーチャーゲートSchedulerQueueingHintsが有効な場合に動作します。

これまで、スケジュール不可能なPodが更新された場合、スケジューラは常にPodをキュー(activeQ / backoffQ)に戻していました。 しかし、Podへのすべての更新がPodをスケジュール可能にするわけではありません。 特に、現在の多くのスケジューリング制約が不変であることを考慮すると、そうではありません。 新しい動作では、スケジュール不可能なPodが更新されると、スケジューリングキューはQueueingHint(s)を使用して、その更新がPodをスケジュール可能にする可能性があるかどうかをチェックします。 少なくとも1つのQueueingHintがQueueを返した場合にのみ、それらをactiveQまたはbackoffQに再度キューイングします。

カスタムスケジューラープラグイン開発者向けの必要なアクション: プラグインからの拒否が、スケジュールされていないPod自体の更新によって解決される可能性がある場合、プラグインはPod/Updateイベントに対するQueueingHintを実装する必要があります。 例えばschedulable=falseラベルを持つPodを拒否するカスタムプラグインを開発したとします。 schedulable=falseラベルを持つPodは、schedulable=falseラベルが削除されるとスケジュール可能になります。このプラグインはPod/Updateイベントに対するQueueingHintを実装し、スケジュールされていないPodでそのようなラベルの変更が行われた場合にQueueを返すようにします。 詳細については、Pull Request #122234をご覧ください。

kubeletの--keep-terminated-pod-volumesコマンドラインフラグの削除

2017年に非推奨となったkubeletのフラグ--keep-terminated-pod-volumesが、v1.31リリースの一部として削除されました。

詳細については、Pull Request #122082をご覧ください。

入手方法

Kubernetes v1.31は、GitHubまたはKubernetesダウンロードページからダウンロードできます。

Kubernetesを始めるには、対話式のチュートリアルをチェックするか、minikubeを使用してローカルKubernetesクラスタを実行してください。 また、kubeadmを使用して簡単にv1.31をインストールすることもできます。

リリースチーム

Kubernetesは、そのコミュニティのサポート、献身、そして懸命な努力に支えられて実現しています。 各リリースチームは、皆様が頼りにしているKubernetesリリースを構成する多くの要素を構築するために協力して働く、献身的なコミュニティボランティアで構成されています。 これには、コード自体からドキュメンテーション、プロジェクト管理に至るまで、コミュニティのあらゆる分野から専門的なスキルを持つ人々が必要です。

私たちは、Kubernetes v1.31リリースをコミュニティに提供するために多くの時間を費やしてくださったリリースチーム全体に感謝の意を表します。 リリースチームのメンバーは、初めてShadowとして参加する人から、複数のリリースサイクルを経験したベテランのチームリーダーまで多岐にわたります。 特に、リリースリーダーのAngelos Kolaitisには特別な感謝の意を表します。 リリースサイクルを成功に導き、チーム全体をサポートし、各メンバーが最大限に貢献できる環境を整えると同時に、リリースプロセスの改善にも取り組んでくれました。

プロジェクトの進捗速度

CNCF K8s DevStatsプロジェクトは、Kubernetesと様々なサブプロジェクトの進捗に関する興味深いデータポイントを集計しています。 これには、個人の貢献から貢献している企業の数まで、このエコシステムの進化に関わる取り組みの深さと広さを示す様々な情報が含まれています。

14週間(5月7日から8月13日まで)続いたv1.31リリースサイクルでは、113の異なる企業と528の個人がKubernetesに貢献しました。

クラウドネイティブエコシステム全体では、379の企業から合計2268人の貢献者がいます。 これは、前回のリリースサイクルと比較して、貢献者数が驚異の63%増加しました!

このデータの出典:

ここでいう貢献とは、コミットの作成、コードレビュー、コメント、IssueやPRの作成、PRのレビュー(ブログやドキュメントを含む)、またはIssueやPRへのコメントを指します。

貢献に興味がある方は、このページを訪れて始めてください。

Kubernetesプロジェクトとコミュニティ全体の進捗速度についてもっと知りたい方は、DevStatsをチェックしてください。

イベント情報

2024年8月から11月にかけて開催予定のKubernetesとクラウドネイティブ関連のイベントをご紹介します。KubeCon、KCD、その他世界各地で開催される注目のカンファレンスが含まれています。Kubernetesコミュニティの最新情報を入手し、交流を深めましょう。

2024年8月

2024年9月

2024年10月

2024年11月

次期リリースに関するウェビナーのお知らせ

2024年9月12日(木)午前10時(太平洋時間)に開催されるKubernetes v1.31リリースチームメンバーによるウェビナーにご参加ください。このリリースの主要な機能や、アップグレード計画に役立つ非推奨化および削除された機能について学ぶことができます。 詳細および登録については、CNCFオンラインプログラムサイトのイベントページをご覧ください。

参加方法

Kubernetesに関わる最も簡単な方法は、あなたの興味に合ったSpecial Interest Groups(SIG)のいずれかに参加することです。 Kubernetesコミュニティに向けて何か発信したいことはありますか? 毎週のコミュニティミーティングや、以下のチャンネルであなたの声を共有してください。 継続的なフィードバックとサポートに感謝いたします。

  • 最新情報はX(旧Twitter)の@Kubernetesioをフォローしてください
  • Discussでコミュニティディスカッションに参加してください
  • Slackでコミュニティに参加してください
  • Stack Overflowで質問したり、回答したりしてください
  • あなたのKubernetesに関するストーリーを共有してください
  • Kubernetesの最新情報はブログでさらに詳しく読むことができます
  • Kubernetesリリースチームについてもっと学んでください

SIG Nodeの紹介

コンテナオーケストレーションの世界で、Kubernetesは圧倒的な存在感を示しており、世界中で最も複雑で動的なアプリケーションの一部を動かしています。 その裏では、Special Interest Groups(SIG)のネットワークがKubernetesの革新と安定性を牽引しています。

今日は、SIG NodeのメンバーであるMatthias BertschyGunju KimSergey Kanzhelevにお話を伺い、彼らの役割、課題、そしてSIG Node内の注目すべき取り組みについて光を当てていきます。

複数の回答者による共同回答の場合は、回答者全員のイニシャルで表記します。

自己紹介

Arpit: 本日はお時間をいただき、ありがとうございます。まず、自己紹介とSIG Node内での役割について簡単に教えていただけますか?

Matthias: Matthias Bertschyと申します。フランス人で、フランスアルプスの近く、ジュネーブ湖のそばに住んでいます。2017年からKubernetesのコントリビューターとして活動し、SIG Nodeのレビュアー、そしてProwのメンテナーを務めています。現在は、ARMOというセキュリティスタートアップでシニアKubernetes開発者として働いています。ARMOは、KubescapeというプロジェクトをCNCFに寄贈しました。

ジュネーブ湖とアルプス

Gunju: Gunju Kimと申します。NAVERでソフトウェアエンジニアとして働いており、検索サービス用のクラウドプラットフォームの開発に注力しています。2021年から空き時間を使ってKubernetesプロジェクトにコントリビュートしています。

Sergey: Sergey Kanzhelevと申します。3年間KubernetesとGoogle Kubernetes Engineに携わり、長年オープンソースプロジェクトに取り組んできました。現在はSIG Nodeの議長を務めています。

SIG Nodeについて

Arpit: ありがとうございます!Kubernetesエコシステム内でのSIG Nodeの責任について、読者の方々に概要を説明していただけますか?

M/G/S: SIG NodeはKubernetesで最初に、あるいは最初期に設立されたSIGの1つです。このSIGは、KubernetesとNodeリソースとのすべてのやり取り、そしてNode自体のメンテナンスに責任を持っています。これはかなり広範囲に及び、SIGはKubernetesのコードベースの大部分を所有しています。この広範な所有権のため、SIG NodeはSIG Network、SIG Storage、SIG Securityなど他のSIGと常に連絡を取り合っており、Kubernetesの新機能や開発のほとんどが何らかの形でSIG Nodeに関わっています。

Arpit: SIG NodeはKubernetesのパフォーマンスと安定性にどのように貢献していますか?

M/G/S: Kubernetesは、安価なハードウェアを搭載した小型の物理VMから、大規模なAI/ML最適化されたGPU搭載Nodeまで、さまざまなサイズと形状のNodeで動作します。Nodeは数か月オンラインのままの場合もあれば、クラウドプロバイダーの余剰コンピューティングで実行されているため、短命で任意のタイミングでプリエンプトされる可能性もあります。

Node上のKubernetesエージェントであるkubeletは、これらすべての環境で確実に動作する必要があります。 近年、kubeletの操作パフォーマンスの重要性が増しています。 その理由は二つあります。 一つは、Kubernetesが通信や小売業などの分野で、より小規模なNodeで使用されるようになってきており、可能な限り小さなリソース消費(フットプリント)で動作することが求められているからです。 もう一つは、AI/MLワークロードでは各Nodeが非常に高価なため、操作の遅延がわずか1秒でも計算コストに大きな影響を与える可能性があるからです。

課題と機会

Arpit: SIG Nodeが今後直面すると予想される課題や可能性について、どのようなものがあるでしょうか?

M/G/S: Kubernetesが誕生から10年を迎え、次の10年に向かう中で、新しい種類のワークロードへの対応が強く求められています。SIG Nodeはこの取り組みで重要な役割を果たすことになるでしょう。後ほど詳しく説明しますが、サイドカーのKEPは、こうした新しいタイプのワークロードをサポートするための取り組みの一例です。

今後数年間の主な課題は、既存の機能の品質と後方互換性を維持しつつ、いかに革新を続けていくかということです。 SIG Nodeは、これからもKubernetesの開発において中心的な役割を担い続けるでしょう。

Arpit: SIG Nodeで現在取り組んでいる研究や開発分野の中で、特に注目しているものはありますか?

M/G/S: 新しいタイプのワークロードへの対応は、私たちにとって非常に興味深い分野です。最近取り組んでいるサイドカーコンテナの研究はその好例といえるでしょう。サイドカーは、アプリケーションの中核となるコードを変更することなく、その機能を拡張できる柔軟なソリューションを提供します。

Arpit: SIG Nodeを維持する上で直面した課題と、それをどのように克服したかを教えてください。

M/G/S: SIG Nodeが直面する最大の課題は、その広範な責任範囲と数多くの機能要望への対応です。この課題に取り組むため、私たちは新たなレビュアーの参加を積極的に呼びかけています。また、常にプロセスの改善に努め、フィードバックに迅速に対応できる体制を整えています。さらに、各リリースの後にはSIG Nodeのミーティングでフィードバックセッションを開催し、問題点や改善が必要な分野を特定し、具体的な行動計画を立てています。

Arpit: SIG Nodeが現在注目している技術や、Kubernetesへの導入を検討している新しい機能などはありますか?

M/G/S: SIG Nodeは、Kubernetesが依存しているさまざまなコンポーネントの開発に積極的に関与し、その進展を注意深く見守っています。これには、コンテナランタイム(containerdCRI-Oなど)やOSの機能が含まれます。例えば、現在 cgroup v1 の廃止と削除が迫っていますが、これに対してKubernetesユーザーが円滑に移行できるよう、SIG NodeとKubernetesプロジェクト全体で取り組んでいます。また、containerdがバージョン2.0をリリースする予定ですが、これには非推奨機能の削除が含まれており、Kubernetesユーザーにも影響が及ぶと考えられます。

Arpit: SIG Nodeのメンテナーとしての経験の中で、特に誇りに思う思い出深い経験や成果を共有していただけますか?

Mathias: 最高の瞬間は、私の最初のKEP(startupProbeの導入)がついにGA(General Availability)に昇格したときだと思います。また、私の貢献がコントリビューターによって日々使用されているのを見るのも楽しいです。例えば、スカッシュコミットにもかかわらずLGTMを保持するために使用されるGitHubツリーハッシュを含むコメントなどです。

サイドカーコンテナ

Arpit: Kubernetesの文脈におけるサイドカーコンテナの概念とその進化について、もう少し詳しく教えていただけますか?

M/G/S: サイドカーコンテナの概念は、Kubernetesが複合コンテナのアイデアを導入した2015年にさかのぼります。同じPod内でメインのアプリケーションコンテナと並行して実行されるこれらの追加コンテナは、コアのコードベースを変更することなくアプリケーションの機能を拡張・強化する方法として見られていました。サイドカーの初期の採用者はカスタムスクリプトと設定を使用して管理していましたが、このアプローチは一貫性とスケーラビリティの面で課題がありました。

Arpit: サイドカーコンテナが特に有益な具体的なユースケースや例を共有していただけますか?

M/G/S: サイドカーコンテナは、さまざまな方法でアプリケーションの機能を強化するために使用できる多用途なツールです:

  • ロギングとモニタリング: サイドカーコンテナを使用して、Pod内の主要アプリケーションコンテナからログとメトリクスを収集し、中央のロギングおよびモニタリングシステムに送信できます。
  • トラフィックのフィルタリングとルーティング: サイドカーコンテナを使用して、Pod内の主要アプリケーションコンテナとの間のトラフィックをフィルタリングおよびルーティングできます。
  • 暗号化と復号化: サイドカーコンテナを使用して、Pod内の主要アプリケーションコンテナと外部サービスの間で流れるデータを暗号化および復号化できます。
  • データ同期: サイドカーコンテナを使用して、Pod内の主要アプリケーションコンテナと外部データベースやサービスの間でデータを同期できます。
  • フォールトインジェクション: サイドカーコンテナを使用して、Pod内の主要アプリケーションコンテナに障害を注入し、障害に対する耐性をテストできます。

Arpit: 提案によると、一部の企業がサイドカー機能を追加したKubernetesのフォークを使用しているそうです。この機能の採用状況やコミュニティの関心度について、何か見解をお聞かせいただけますか?

M/G/S: 採用率を測定する具体的な指標はありませんが、KEPはコミュニティから大きな関心を集めています。特にIstioのようなサービスメッシュベンダーは、アルファテストフェーズに積極的に参加しました。KEPの可視性は、多数のブログ投稿、インタビュー、講演、ワークショップを通じてさらに実証されています。KEPは、ネットワークプロキシ、ロギングシステム、セキュリティ対策など、KubernetesのPod内のメインコンテナと並行して追加機能を提供する需要の増加に対応しています。コミュニティは、この機能の広範な採用を促進するために、既存のワークロードに対する容易な移行パスを提供することの重要性を認識しています。

Arpit: 本番環境でサイドカーコンテナを使用している企業の注目すべき例や成功事例はありますか?

M/G/S: 本番環境での広範な採用を期待するにはまだ早すぎます。1.29リリースは2024年1月11日からGoogle Kubernetes Engine(GKE)で利用可能になったばかりで、ユニバーサルインジェクターを介して効果的に有効化し使用する方法に関する包括的なドキュメントがまだ必要です。人気のあるサービスメッシュプラットフォームであるIstioも、ネイティブサイドカーを有効にするための適切なドキュメントが不足しているため、開発者がこの新機能を使い始めるのが難しくなっています。しかし、ネイティブサイドカーのサポートが成熟し、ドキュメントが改善されるにつれて、本番環境でのこの技術のより広範な採用が期待できます。

Arpit: 提案では、サイドカー機能を実現するために初期化したコンテナにrestartPolicyフィールドを導入することが示されています。この方法で、先ほど挙げられた課題をどのように解決できるのか、詳しく教えていただけますか?

M/G/S: 初期化したコンテナにrestartPolicyフィールドを導入する提案は、既存のインフラストラクチャを活用し、サイドカーの管理を簡素化することで、概説された課題に対処します。このアプローチは、Podの仕様に新しいフィールドを追加することを避け、管理しやすさを保ちつつ、さらなる複雑さを回避します。既存の初期化したコンテナのメカニズムを利用することで、サイドカーはPodの起動時に通常の初期化コンテナと並行して実行でき、一貫した初期化の順序を確保します。ささらに、サイドカー用の初期化コンテナの再起動ポリシーをAlwaysに設定することで、メインアプリケーションコンテナが終了した後も、ロギングやモニタリングなどの継続的なサービスをワークロードの終了まで維持できます。

Arpit: 初期化したコンテナにrestartPolicyフィールドを導入することは、既存のKubernetes設定との後方互換性にどのような影響を与えますか?

M/G/S: 初期化したコンテナにrestartPolicyフィールドを導入しても、既存のKubernetes設定との後方互換性は維持されます。既存の初期化したコンテナは従来通りに機能し続け、新しいrestartPolicyフィールドは、明示的にサイドカーとして指定された初期化したコンテナにのみ適用されます。このアプローチにより、既存のアプリケーションやデプロイメントが新機能によって中断されることはなく、同時にサイドカーをより効果的に定義および管理する方法が提供されます。

SIG Nodeへの貢献

Arpit: 新しいメンバー、特に初心者が貢献するのに最適な方法は何でしょうか?

M/G/S: 新しいメンバーや初心者は、サイドカーに関するKEP(Kubernetes Enhancement Proposal)に対して、以下の方法で貢献できます:

  • 認知度の向上: サイドカーの利点と使用例を紹介するコンテンツを作成します。これにより、他の人々にこの機能の理解を深めてもらい、採用を促すことができます。
  • フィードバックの提供: サイドカーの使用経験(良い点も悪い点も)を共有してください。このフィードバックは、機能の改善や使いやすさの向上に役立ちます。
  • ユースケースの共有: 本番環境でサイドカーを使用している場合は、その経験を他の人と共有してください。実際の使用例を示すことで、この機能の価値を実証し、他の人々の採用を促進できます。
  • ドキュメントの改善: この機能のドキュメントの明確化や拡充にご協力ください。より分かりやすいドキュメントは、他の人々がサイドカーを理解し、活用する助けになります。

サイドカーに関するKEP以外にも、SIG Nodeではより多くの貢献者を必要としている分野があります:

  • テストカバレッジの向上: SIG Nodeでは、Kubernetesコンポーネントのテストカバレッジを継続的に改善する方法を模索しています。

  • CI(継続的インテグレーション)の維持: SIG Nodeは、Kubernetesコンポーネントが様々な状況下で期待通りに動作することを確認するため、一連のエンドツーエンド(e2e)テストを管理しています。

結論

SIG Nodeは、Kubernetesの発展において重要な役割を果たしています。 クラウドネイティブ・コンピューティングの絶えず変化する環境の中で、Kubernetesの信頼性と適応性を確保し続けています。 Matthias、Gunju、Sergeyといった献身的なメンバーが先頭に立ち、SIG Nodeは革新の最前線に立ち続けています。 彼らの努力により、Kubernetesは新たな地平を目指して前進し続けているのです。

Kubernetesの10年間の歴史

KCSEU 2024 group photo

10年前の2014年6月6日、Kubernetesの最初のコミットがGitHubにプッシュされました。 Go、Bash、Markdownで書かれた250のファイルと47,501行のコードを含むその最初のコミットが、今日のKubernetesプロジェクトの始まりでした。 それから10年後の今日、Kubernetesが44か国から8,000社以上の企業88,000人以上のコントリビューターを有する、これまでで最大のオープンソースプロジェクトの一つに成長するとは誰が予想したでしょうか。

KCSCN 2019

このマイルストーンはKubernetesだけでなく、そこから生まれたクラウドネイティブエコシステムにとっても重要なものです。 CNCFには約200のプロジェクトがあり、240,000人以上のコントリビューターからのコントリビューションがあります。 また、より広いエコシステムの中でも数千人のコントリビューターがいます。 Kubernetesが今日の姿になれたのは、彼らや700万人以上の開発者、さらに多くのユーザーコミュニティがエコシステムを形作る手助けをしてくれたおかげです。

Kubernetesの始まり - 技術の収束

Kubernetesの元となるアイディアは、(2013年に登場した)最初のコミットや最初のプロトタイプの前から存在していました。 2000年代初頭、ムーアの法則が有効に機能していました。 コンピューティングハードウェアは非常に速い速度でますます強力になり、それに対応してアプリケーションもますます複雑化していきました。 このハードウェアのコモディティ化とアプリケーションの複雑化の組み合わせにより、ソフトウェアをハードウェアからさらに抽象化する必要が生じ、解決策が現れ始めました。

当時の多くの企業と同様にGoogleも急速に拡大しており、同社のエンジニアたちはLinuxカーネル内での隔離の形態を作り出すというアイデアに興味を持っていました。 Googleのエンジニア、Rohit Sethはそのコンセプトを2006年のメールで説明しました。

ワークロードのメモリやタスクなどのシステムリソースの使用を追跡し、課金する構造を示すためにコンテナという用語を使用します。

The future of Linux containers

2013年3月、PyConでSolomon Hykesが行った5分間のライトニングトークThe future of Linux Containersでは、Linuxコンテナを作成および使用するためのオープンソースツールである「Docker」が紹介されました。 DockerはLinuxコンテナに使いやすさをもたらし、これまで以上に多くのユーザーが利用できるようになりました。 Dockerの人気が急上昇し、Linuxコンテナの抽象化を誰もが利用できるようにしたことで、アプリケーションをより移植性が高く、再現性のある方法で実行できるようになりました。 しかし、依然としてスケールの問題は残っていました。

Googleのアプリケーションオーケストレーションをスケールで管理するBorgシステムは、2000年代半ばにLinuxコンテナを採用しました。 その後、GoogleはOmegaと呼ばれるシステムの新バージョンの開発も開始しました。 BorgとOmegaシステムに精通していたGoogleのエンジニアたちは、Dockerによって駆動するコンテナ化の人気を目の当たりにしました。 そしてBrendan Burnsのブログで説明されているように、オープンソースのコンテナオーケストレーションシステムの必要性だけでなく、その「必然性」を認識しました。 この認識は2013年秋にJoe Beda、Brendan Burns、Craig McLuckie、Ville Aikas、Tim Hockin、Dawn Chen、Brian Grant、Daniel Smithを含む小さなチームにKubernetesのプロジェクトを始めるインスピレーションを与えました。

Kubernetesの10年間

KubeCon EU 2017

Kubernetesの歴史は2014年6月6日のその歴史的なコミットと、2014年6月10日のDockerCon 2014でのGoogleエンジニアEric Brewerによる基調講演(およびそれに対応するGoogleブログ)でのプロジェクト発表から始まります。

その後の1年間で、主にGoogleとRed Hatからのコントリビューターによる小さなコミュニティがプロジェクトに取り組み、2015年7月21日にバージョン1.0のリリースに至りました。 1.0と同時に、GoogleはKubernetesをLinux Foundationの新たに設立された部門であるCloud Native Computing Foundation (CNCF)に寄贈することを発表しました。

1.0に到達したものの、Kubernetesプロジェクトは依然として使いにくく理解しにくいものでした。 KubernetesのコントリビューターであるKelsey Hightowerはプロジェクトの使いやすさの欠点に特に注目し、2016年7月7日に彼の有名な"Kubernetes the Hard Way"ガイドの最初のコミットをプッシュしました。

プロジェクトは最初の1.0リリース以来大きく変わり、いくつかの大きな成果を経験しました。 たとえば、1.16でのCustom Resource Definition (CRD)のGAや、1.23での完全なデュアルスタックサポートの開始などです。 また、1.22での広く使用されているベータ版APIの削除や、Dockershimの廃止から学んだコミュニティの「教訓」もあります。

1.0以降の注目すべきアップデート、マイルストーン、およびイベントには以下のものがあります。

  • 2016年12月 - Kubernetes 1.5でCRIの最初のサポートとアルファ版Windowsノードサポートによるランタイムプラグイン機能が導入されました。また、OpenAPIが初めて登場し、クライアントが拡張されたAPIを認識できるようになりました。
    • このリリースでは、StatefulSetとPodDisruptionBudgetがベータ版で導入されました。
  • 2017年4月 - ロールベースアクセス制御(RBAC)の導入。
  • 2017年6月 - Kubernetes 1.7でThirdPartyResource (TPR)がCustomResourceDefinition (CRD)に置き換えられました。
  • 2017年12月 - Kubernetes 1.9ではWorkload APIがGA(一般提供)となりました。リリースブログには「Kubernetesで最もよく使用されるオブジェクトの一つであるDeploymentとReplicaSetは、1年以上の実際の使用とフィードバックを経て安定しました」と書かれています。
  • 2018年12月 - Kubernetes 1.13でContainer Storage Interface (CSI)がGAに達しました。また最小限のクラスターをブートストラップするためのkubeadmツールがGAに達し、CoreDNSがデフォルトのDNSサーバーとなりました。
  • 2019年9月 - Kubernetes 1.16でCustom Resource DefinitionがGAに達しました。
  • 2020年8月 - Kubernetes 1.19でリリースのサポート期間が1年に延長されました。
  • 2020年12月 - Kubernetes 1.20でDockershimが廃止されました。
  • 2021年4月 - Kubernetesのリリース頻度が変更され、年間4回から3回に減少されました。
  • 2021年7月 - 広く使用されているベータ版APIがKubernetes 1.22で削除されました。
  • 2022年5月 - Kubernetes 1.24でベータ版APIがデフォルトで無効にされ、アップグレードの競合を減らすとともにDockershimが削除されました。その結果、多くのユーザーの混乱を引き起こしました(その後、コミュニケーションを改善しました)。
  • 2022年12月 - Kubernetes 1.26ではAI/ML/バッチワークロードのサポートを強化するための大規模なバッチおよびJob APIのオーバーホールが行われました。

PS: プロジェクトがどれだけ進化したか自分で見てみたいですか? コミュニティメンバーのCarlos Santana、Amim Moises Salum Knabben、James Spurinが作成したKubernetes 1.0クラスターを立ち上げるためのチュートリアルをチェックしてみてください。


Kubernetesには数え切れないほどの拡張するポイントがあります。 もともとはDocker専用に設計されていましたが、現在ではCRI標準に準拠する任意のコンテナランタイムをプラグインできます。 他にもストレージ用のCSIやネットワーキング用のCNIなどのインターフェースがあります。 そしてこれはできることのほんの一部に過ぎません。 過去10年間で新しいパターンがいくつも登場しました。 例えば、Custom Resource Definition (CRD)を使用してサードパーティのコントローラーをサポートすることができます。 これは現在Kubernetesエコシステムの大きな一部となっています。

このプロジェクトを構築するコミュニティも、この10年間で非常に大きくなりました。 DevStatsを使用すると、この10年間でKubernetesを世界で2番目に大きなオープンソースプロジェクトにした驚異的なコントリビューションの量を確認できます。

  • 88,474人のコントリビューター
  • 15,121人のコードコミッター
  • 4,228,347件のコントリビューション
  • 158,530件のIssue
  • 311,787件のPull Request

今日のKubernetes

KubeCon NA 2023

初期の頃からこのプロジェクトは技術的能力、利用状況、およびコントリビューションの面で驚異的な成長を遂げてきました。 プロジェクトは今もなおユーザーにより良いサービスを提供するために積極的に改善に取り組んでいます。

次回の1.31リリースでは、長期にわたる重要なプロジェクトの完成を祝います。 それはインツリークラウドプロバイダーのコードの削除です。 このKubernetesの歴史上最大のマイグレーションでは、約150万行のコードが削除され、コアコンポーネントのバイナリサイズが約40%削減されました。 プロジェクトの初期には、拡張性が成功の鍵であることは明らかでした。 しかし、その拡張性をどのように実現するかは常に明確ではありませんでした。 このマイグレーションにより、Kubernetesの核となるコードベースからさまざまなベンダー固有の機能が削除されました。 ベンダー固有の機能は、今後はCustom Resource Definition (CRD)Gateway APIなどの他のプラグイン拡張機能やパターンによってよりよく提供されるようになります。

Kubernetesは、膨大なユーザーベースにサービスを提供する上で新たな課題にも直面しており、コミュニティはそれに適応しています。 その一例が、新しいコミュニティ所有のregistry.k8s.ioへのイメージホスティングの移行です。 ユーザーに事前コンパイル済みのバイナリイメージを提供するためのエグレスの帯域幅とコストは非常に大きなものとなっています。 この新しいレジストリの変更により、コミュニティはこれらの便利なイメージをよりコスト効率およびパフォーマンス効率の高い方法で提供し続けることができます。 必ずブログ記事をチェックし、registry.k8s.ioを使用するように更新してください!

Kubernetesの未来

10年が経ち、Kubernetesの未来は依然として明るく見えます。 コミュニティはユーザー体験の改善とプロジェクトの持続可能性を向上させる変更を優先しています。 アプリケーション開発の世界は進化し続けており、Kubernetesもそれに合わせて変化していく準備ができています。

2024年にはAIの登場がかつてニッチなワークロードタイプを重要なものへと変えました。 分散コンピューティングとワークロードスケジューリングは常に人工知能(AI)、機械学習(ML)、および高性能コンピューティング(HPC)ワークロードのリソース集約的なニーズと密接に関連してきました。 コントリビューターは、新しく開発されたワークロードのニーズとそれらにKubernetesがどのように最適に対応できるかに注目しています。 新しいServing Working Groupは、コミュニティがこれらのワークロードのニーズに対処するためにどのように組織化されているかの一例です。 今後数年でKubernetesがさまざまな種類のハードウェアを管理する能力や、ハードウェア全体でチャンクごとに実行される大規模なバッチスタイルのワークロードのスケジューリング能力に関して改善が見られるでしょう。

Kubernetesを取り巻くエコシステムは成長し続け、進化していきます。 将来的にはインツリーベンダーコードのマイグレーションやレジストリの変更など、プロジェクトの持続可能性を維持するための取り組みがますます重要になるでしょう。

Kubernetesの次の10年は、ユーザーとエコシステム、そして何よりもそれに貢献する人々によって導かれるでしょう。 コミュニティは新しいコントリビューターを歓迎しています。 コントリビューションに関する詳細は、新しいコントリビューター向けのガイドで確認できます。

Kubernetesの未来を一緒に築いていくことを楽しみにしています!

KCSNA 2023

Kubernetes史上最大の移行作業を完了

Kubernetes v1.7以降、Kubernetesプロジェクトは、クラウドプロバイダーとの統合機能をKubernetesのコアコンポーネントから分離するという野心的な目標を追求してきました(KEP-2395)。 この統合機能はKubernetesの初期の開発と成長に重要な役割を果たしつつも、2つの重要な要因によってその分離が推進されました。 1つは、何百万行ものGoコードにわたってすべてのクラウドプロバイダーのネイティブサポートを維持することの複雑さが増大していたこと、もう1つは、Kubernetesを真にベンダーニュートラルなプラットフォームとして確立したいという願望です。

多くのリリースを経て、すべてのクラウドプロバイダー統合が、Kubernetesのコアリポジトリから外部プラグインに正常に移行されたことを喜ばしく思います。 当初の目的を達成したことに加えて、約150万行のコードを削除し、コアコンポーネントのバイナリサイズを約40%削減することで、Kubernetesを大幅に合理化しました。

この移行は、影響を受けるコンポーネントが多数あり、Google Cloud、AWS、Azure、OpenStack、vSphereの5つの初期クラウドプロバイダーの組み込み統合に依存していた重要なコードパスがあったため、複雑で長期にわたる作業となりました。 この移行を成功させるために、私たちは4つの新しいサブシステムを一から構築する必要がありました。

  1. クラウドコントローラーマネージャー (KEP-2392)
  2. APIサーバーネットワークプロキシ (KEP-1281)
  3. kubeletクレデンシャルプロバイダープラグイン (KEP-2133)
  4. CSIを使用するストレージの移行 (KEP-625)

各サブシステムは、組み込み機能と同等の機能を実現するために不可欠であり、安全で信頼できる移行パスを使用して各サブシステムをGAレベルの成熟度にするために、いくつかのリリースが必要でした。 以下に、各サブシステムの詳細を説明します。

クラウドコントローラーマネージャー

クラウドコントローラーマネージャーは、この取り組みで導入された最初の外部コンポーネントであり、kube-controller-managerkubeletのうち、クラウドAPIと直接やり取りする機能を置き換えるものです。 この重要なコンポーネントは、ノードが実行されているクラウドのリージョンとゾーンを示すメタデータラベルや、クラウドプロバイダーのみが知っているIPアドレスを適用することにより、ノードを初期化する役割を担っています。 さらに、LoadBalancerタイプのServiceに対してクラウドロードバランサーをプロビジョニングするサービスコントローラーも実行します。

Kubernetesのコンポーネント

詳細については、Kubernetesドキュメントのクラウドコントローラーマネージャーを参照してください。

APIサーバーネットワークプロキシ

2018年にSIG API Machineryと共同で開始されたAPIサーバーネットワークプロキシプロジェクトは、kube-apiserver内のSSHトンネラー機能を置き換えることを目的としていました。 このトンネラーは、Kubernetesのコントロールプレーンとノードとのトラフィックを安全にプロキシするために使用されていましたが、これらのSSHトンネルを確立するために、kube-apiserver内に組み込まれたプロバイダー固有の実装の詳細に大きく依存していました。

現在、APIサーバーネットワークプロキシは、kube-apiserver内のGAレベルの拡張ポイントとなっています。 これは、APIサーバーからノードへのトラフィックを安全なプロキシを介してルーティングできる汎用的なプロキシメカニズムを提供し、APIサーバーが実行されているクラウドプロバイダーを認識する必要がなくなりました。 このプロジェクトでは、本番環境での採用が進んでいるKonnectivityプロジェクトも導入されました。

APIサーバーネットワークプロキシの詳細については、READMEを参照してください。

kubeletのクレデンシャルプロバイダープラグイン

kubeletのクレデンシャルプロバイダープラグインは、Google Cloud、AWS、またはAzureでホストされているイメージレジストリのクレデンシャルを動的に取得するkubeletの組み込み機能を置き換えるために開発されました。 従来の機能は便利で、kubeletがGCR、ECR、またはACRからイメージを取得するための短期間のトークンをシームレスに取得できるようにしていました。 しかし、Kubernetesの他の領域と同様に、これをサポートするには、kubeletが異なるクラウド環境とAPIについて特定の知識を持つ必要がありました。

2019年に導入されたクレデンシャルプロバイダープラグインメカニズムは、kubeletが様々なクラウドでホストされているイメージのクレデンシャルを動的に提供するプラグインバイナリを実行するための汎用的な拡張ポイントを提供します。 この拡張性により、kubeletの短期間のトークンを取得する機能が、最初の3つのクラウドプロバイダーを超えて拡張されました。

詳細については、認証されたイメージプルのためのkubeletクレデンシャルプロバイダーを参照してください。

ストレージプラグインのKubernetesコアからCSIへの移行

Container Storage Interface(CSI)は、Kubernetesやそのほかのコンテナオーケストレーターにおいてブロックおよびファイルストレージシステムを管理するためのコントロールプレーン標準であり、1.13でGAになりました。 これは、Kubernetesに直接組み込まれていたボリュームプラグインを、Kubernetesクラスター内のPodとして実行できるドライバーに置き換えるために設計されました。 これらのドライバーは、Kubernetes APIを介してkube-controller-managerストレージコントローラーと通信し、ローカルのgRPCエンドポイントを介してkubeletと通信します。 現在、すべての主要なクラウドとストレージベンダーにわたって100以上のCSIドライバーが利用可能であり、Kubernetesでステートフルなワークロードが現実のものとなっています。

ただし、KubernetesコアのボリュームAPIの既存のすべてのユーザーをどのように扱うかという大きな課題が残っていました。 APIの後方互換性を維持するために、Kubernetesコアのボリューム APIを同等のCSI APIに変換するAPIトランスレーション層をコントローラーに組み込みました。 これにより、すべてのストレージ操作をCSIドライバーにリダイレクトすることができ、APIを削除せずにKubernetesコアのボリュームプラグインのコードを削除する道が開けました。

Kubernetesコアのストレージの移行の詳細については、Kubernetes In-Tree to CSI Volume Migration Moves to Betaを参照してください。

今後の展望

この移行は、ここ数年のSIG Cloud Providerがもっとも注力してきたことでした。 この重要なマイルストーンを達成したことで、これまでに構築してきた外部サブシステムを活用して、Kubernetesとクラウドプロバイダーをより良く統合するための新しい革新的な方法を模索する取り組みにシフトしていきます。 これには、クラスター内のノードがパブリッククラウドとプライベートクラウドの両方で実行できるハイブリッド環境でKubernetesをより賢くすることや、外部プロバイダーの開発者が統合の取り組みを簡素化・合理化するためのより良いツールとフレームワークを提供することが含まれます。

新機能やツール、フレームワークの開発が進む一方で、SIG Cloud Providerはテストの重要性も忘れてはいません。 SIGの将来の活動のもう1つの重点分野は、より多くのプロバイダーを含めるためのクラウドコントローラーテストの改善です。 この取り組みの最終目標は、できるだけ多くのプロバイダーを含むテストフレームワークを作成し、Kubernetesコミュニティに対して、Kubernetes環境に関する最高レベルの信頼性を提供することです。

v1.29より前のバージョンのKubernetesを使用していて、まだ外部クラウドプロバイダーに移行していない場合は、以前のブログ記事Kubernetes 1.29: Cloud Provider Integrations Are Now Separate Componentsを確認することをおすすめします。 この記事では、私たちが行った変更について詳細な情報を提供し、外部プロバイダーへの移行方法についてガイダンスを提供しています。 v1.31以降、Kubernetesコアのクラウドプロバイダーは永続的に無効化され、Kubernetesのコアコンポーネントから削除されます。

貢献に興味がある方は、隔週のSIGミーティングにぜひご参加ください!

Gateway API v1.1: サービスメッシュ、GRPCRoute、そして更なる進化

Gateway API logo

昨年10月のGateway APIの正式リリース後、Kubernetes SIG NetworkはGateway APIのv1.1リリースを発表しました。 このリリースでは、いくつかの機能が 標準機能 (GA)に昇格しています。 特にサービスメッシュとGRPCRouteのサポートが含まれます。 また、セッション維持とクライアント証明書の検証を含む新しい実験的機能も導入しています。

新機能

GAへの昇格

このリリースでは、4つの待望の機能が標準機能に昇格しました。 これにより、これらの機能は実験的な段階を卒業したことになります。 GAへの昇格が行われたということは、APIの設計に対する高い信頼性を示すとともに、後方互換性を保証するものです。 他のKubernetes APIと同様に、GAへ昇格した機能も時間とともに後方互換性を保ちながら進化していきます。 今後もこれらの新機能のさらなる改良と改善が行われることを期待しています。 これらの仕組みについて詳しくは、Gateway APIのバージョニングポリシーをご覧ください。

サービスメッシュのサポート

Gateway APIのサービスメッシュサポートにより、サービスメッシュユーザーは同じAPIを使用してIngressトラフィックとメッシュトラフィックを管理することが可能になります。 これにより同じポリシーとルーティングインターフェースを再利用することができます。 また、Gateway API v1.1では、HTTPRouteなどのルートがServiceをparentRefとして持つことができるようになり、特定のサービスへのトラフィックの動作を制御できます。 詳細については、Gateway APIのサービスメッシュドキュメントをお読みいただくか、Gateway APIの実装リストをご覧ください。

例えば、アプリケーションのコールグラフの深部にあるワークロードに対して、HTTPRouteを使用してカナリアデプロイメントを行うことができます。 以下はその例です:

apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: color-canary
  namespace: faces
spec:
  parentRefs:
    - name: color
      kind: Service
      group: ""
      port: 80
  rules:
  - backendRefs:
    - name: color
      port: 80
      weight: 50
    - name: color2
      port: 80
      weight: 50

これにより、名前空間faces内のcolorサービスに送信されるトラフィックが、元のcolorサービスとcolor2サービスの間で50対50に分割されます。 この設定は移植性が高く、あるメッシュから別のメッシュへ簡単に移行できます。

GRPCRoute

すでにGRPCRouteの実験的機能バージョンを使用している場合、使用しているコントローラーがGRPCRoute v1をサポートするようアップデートされるまで、標準バージョンのGRPCRouteへのアップグレードは控えることをお勧めします。 それまでは、v1alpha2v1の両方のAPIバージョンを含むv1.1の実験的チャンネルバージョンのGRPCRouteにアップグレードしても問題ありません。

ParentReference Port

ParentReferenceにportフィールドが追加されました。 これにより、リソースをGatewayのリスナー、Service、あるいは他の親リソース(実装によって異なります)に関連付けることができるようになりました。 ポートにバインドすることで、複数のリスナーに一度に関連付けることも可能です。

例えば、HTTPRouteをGatewayの特定のリスナーに関連付ける際、リスナー名ではなくリスナーのポートを指定できるようになりました。 これにより、一つまたは複数の特定のリスナーに関連付けることができます。

詳細については、Gatewayへの関連付けを参照してください。

適合性プロファイルとレポート

適合性レポートのAPIが拡張され、実装の動作モードを指定するmodeフィールドと、Gateway APIのチャネル(標準版または実験的機能版)をしめすgatewayAPIChannelが追加されました。 gatewayAPIVersiongatewayAPIChannelは、テスト結果の簡単な説明とともに、テストスイートの仕組みによって自動的に入力されるようになりました。 レポートの構成がより体系的に整理され、実装者はテストの実行方法に関する情報を追加し、再現手順を提供できるようになりました。

実験的機能版チャンネルへの新機能追加

Gatewayのクライアント証明書の検証

Gatewayの各リスナーでクライアント証明書の検証が設定できるようになりました。 これは、tls内に新しく追加されたfrontendValidationフィールドによって実現されています。 このフィールドでは、クライアントが提示する証明書を検証するための信頼アンカーとして使用できるCA証明書のリストを設定できます。

以下の例は、ConfigMapのfoo-example-com-ca-certに保存されているCA証明書を使用して、Gatewayリスナーのfoo-httpsに接続するクライアントの証明書を検証する方法を示しています。

apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: client-validation-basic
spec:
  gatewayClassName: acme-lb
  listeners:
    name: foo-https
    protocol: HTTPS
    port: 443
    hostname: foo.example.com
  tls:
    certificateRefs:
      kind: Secret
      group: ""
      name: foo-example-com-cert
    frontendValidation:
      caCertificateRefs:
        kind: ConfigMap
        group: ""
        name: foo-example-com-ca-cert

セッション維持とBackendLBPolicy

Gateway APIにセッション維持機能が導入されました。 これは新しいポリシー(BackendLBPolicy)によってサービスレベルで設定でき、さらにHTTPRouteとGRPCRoute内のフィールドを使用してルートレベルでも設定可能です。 BackendLBPolicyとルートレベルのAPIは、セッションのタイムアウト、セッション名、セッションタイプ、クッキーの有効期間タイプなど、同じセッション維持の設定を提供します。

以下は、fooサービスにクッキーベースのセッション維持を有効にするBackendLBPolicyの設定例です。 セッション名をfoo-sessionに設定し、絶対タイムアウトとアイドルタイムアウトを定義し、クッキーをセッションクッキーとして設定しています:

apiVersion: gateway.networking.k8s.io/v1alpha2
kind: BackendLBPolicy
metadata:
  name: lb-policy
  namespace: foo-ns
spec:
  targetRefs:
  - group: core
    kind: service
    name: foo
  sessionPersistence:
    sessionName: foo-session
    absoluteTimeout: 1h
    idleTimeout: 30m
    type: Cookie
    cookieConfig:
      lifetimeType: Session

その他の変更点

TLS関連用語の明確化

API全体でTLS関連の用語を統一する取り組みの一環として、BackendTLSPolicyに互換性のない変更を加えました。 これにより、新しいAPIバージョン(v1alpha3)が導入されました。 既存のv1alpha2を使用している場合は、データのバックアップや古いバージョンのアンインストールなど、適切な対応が必要です。

v1alpha2のBackendTLSPolicyフィールドへの参照は、v1alpha3に更新する必要があります。 主な変更点は以下の通りです:

  • targetReftargetRefsに変更(複数のターゲットへの適用が可能に)
  • tlsvalidationに変更
  • tls.caCertRefsvalidation.caCertificateRefsに変更
  • tls.wellKnownCACertsvalidation.wellKnownCACertificatesに変更

このリリースに含まれるすべての変更点については、v1.1.0リリースノートをご覧ください。

Gateway APIの背景

Gateway APIのアイデアは、2019年のKubeCon San Diegoで次世代のIngress APIとして最初に提案されました。 それ以来、すばらしいコミュニティが形成され、おそらくKubernetes史上最も協力的なAPIを開発してきました。 これまでに200人以上がこのAPIに貢献しており、その数は今も増え続けています。

メンテナーは、リポジトリへのコミット、議論、アイデア、あるいは一般的なサポートなど、あらゆる形でGateway APIに貢献してくださった 全ての方々 に感謝の意を表します。 このように献身的で活発なコミュニティのサポートなしでは、ここまで到達することはできませんでした。

実際に使ってみましょう

Gateway APIの特徴として、最新版を使用するためにKubernetesそのものを最新にする必要がありません。 Kubernetes 1.26以降であれば、このバージョンのGateway APIをすぐに利用開始できます。

APIを試すには、スタートガイドをご覧ください。

開発に参加しませんか

Ingressやサービスメッシュ向けのKubernetesルーティングAPIの未来を形作るチャンスがたくさんあります。

関連するKubernetesブログ記事

DIY: Kubernetesで自分だけのクラウドを構築しよう(パート3)

Kubernetesの中でKubernetesを実行するという最も興味深いフェーズに近づいています。 この記事では、KamajiやCluster APIなどのテクノロジーとそれらのKubeVirtとの統合について説明します。

以前の議論では、ベアメタル上でのKubernetesの準備と、Kubernetesを仮想マシン管理システムに変える方法について説明しました。 この記事では、上記のすべてを使用して、本格的な管理対象のKubernetesを構築し、ワンクリックで仮想Kubernetesクラスターを実行する方法を説明して、シリーズを締めくくります。

まず、Cluster APIについて詳しく見ていきましょう。

Cluster API

Cluster APIは、Kubernetesの拡張機能で、別のKubernetesクラスター内でカスタムリソースとしてKubernetesクラスターを管理できるようにするものです。

Cluster APIの主な目的は、Kubernetesクラスターの基本的なエンティティを記述し、そのライフサイクルを管理するための統一されたインターフェースを提供することです。 これにより、クラスターの作成、更新、削除のプロセスを自動化し、スケーリングとインフラストラクチャの管理を簡素化できます。

Cluster APIのコンテキストでは、管理クラスターテナントクラスターの2つの用語があります。

  • 管理クラスターは、他のクラスターのデプロイと管理に使用されるKubernetesクラスターです。 このクラスターには、必要なすべてのCluster APIコンポーネントが含まれており、テナントクラスターの記述、作成、更新を担当します。多くの場合、この目的でのみ使用されます。
  • テナントクラスターは、ユーザークラスターまたはCluster APIを使用してデプロイされたクラスターです。 これらは、管理クラスターで関連するリソースを記述することで作成されます。その後、エンドユーザーがアプリケーションとサービスをデプロイするために使用されます。

テナントクラスターは、物理的に管理クラスターと同じインフラストラクチャ上で実行する必要は必ずしもないことを理解することが重要です。 むしろ多くの場合、それらは別の場所で実行されています。

Cluster APIを使用した管理KubernetesクラスターとテナントKubernetesクラスターの相互作用を示す図

Cluster APIを使用した管理KubernetesクラスターとテナントKubernetesクラスターの相互作用を示す図

Cluster APIは、その動作のために プロバイダー の概念を利用します。 プロバイダーは、作成されるクラスターの特定のコンポーネントを担当する個別のコントローラーです。 Cluster API内にはいくつかの種類のプロバイダーがあります。 主なものは次のとおりです。

  • インフラストラクチャプロバイダー: 仮想マシンや物理サーバーなどのコンピューティングインフラストラクチャを提供する役割を担います。
  • コントロールプレーンプロバイダー: kube-apiserver、kube-scheduler、kube-controller-managerなどのKubernetesコントロールプレーンを提供します。
  • ブートストラッププロバイダー: 作成される仮想マシンやサーバー用のcloud-init設定の生成に使用されます。

始めるには、Cluster API自体と各種プロバイダーを1つずつインストールする必要があります。 サポートされているプロバイダーの完全なリストはプロジェクトのドキュメントで確認できます。

インストールにはclusterctlユーティリティや、より宣言的な方法としてCluster API Operatorを使用できます。

プロバイダーの選択

インフラストラクチャプロバイダー

KubeVirtを使用してKubernetesクラスターを実行するにはKubeVirt Infrastructure Providerをインストールする必要があります。 これにより、Cluster APIが動作する管理クラスターと同じ場所で、ワーカーノード用の仮想マシンをデプロイできるようになります。

コントロールプレーンプロバイダー

Kamajiプロジェクトは、管理クラスター内のコンテナとしてテナントクラスターのKubernetesコントロールプレーンを実行するためのソリューションを提供しています。 このアプローチには、いくつかの重要な利点があります。

  • 費用対効果: コントロールプレーンをコンテナで実行することで、クラスターごとに個別のコントロールプレーンノードを使用する必要がなくなり、インフラストラクチャのコストを大幅に削減できます。
  • 安定性: 複雑な多層デプロイメント方式を排除することでアーキテクチャを簡素化できます。 仮想マシンを順次起動してからその中にetcdとKubernetesコンポーネントをインストールするのではなく、Kubernetes内で通常のアプリケーションとしてデプロイおよび実行され、オペレーターによって管理されるシンプルなコントロールプレーンがあります。
  • セキュリティ: クラスターのコントロールプレーンはエンドユーザーから隠されており、そのコンポーネントが侵害される可能性を減らし、クラスターの証明書ストアへのユーザーアクセスを排除します。ユーザーに見えないコントロールプレーンを構成するこのアプローチは、クラウドプロバイダーによって頻繁に使用されています。

ブートストラッププロバイダー

Kubeadmをブートストラッププロバイダーとして使用します。 これは、Cluster APIでクラスターを準備するための標準的な方法です。 このプロバイダーは、Cluster API自体の一部として開発されています。kubeletとkubeadmがインストールされた準備済みのシステムイメージのみが必要で、cloud-initとignitionの形式でコンフィグを生成できます。

Talos LinuxもCluster API経由でのプロビジョニングをサポートしており、そのためのプロバイダー用意されていることは注目に値します。 前回の記事では、ベアメタルノードで管理クラスターをセットアップするためにTalos Linuxを使用する方法について説明しましたが、テナントクラスターをプロビジョニングするには、Kamaji+Kubeadmのアプローチの方が優れています。 コンテナへのKubernetesコントロールプレーンのデプロイを容易にするため、コントロールプレーンインスタンス用に個別の仮想マシンを用意する必要無くなります。 これにより、管理が簡素化され、コストが削減されます。

動作の仕組み

Cluster APIの主要なオブジェクトはClusterリソースで、他のすべてのリソースの親となります。 通常、このリソースは他の2つのリソースを参照します。 コントロールプレーンを記述するリソースとインフラストラクチャを記述するリソースです。 それぞれが個別のプロバイダーによって管理されます。

Clusterとは異なり、これら2つのリソースは標準化されておらず、そのリソースの種類は使用している特定のプロバイダーに依存します。

Cluster APIにおけるClusterリソースとそれがリンクするリソースの関係を示す図

Cluster APIにおけるClusterリソースとそれがリンクするリソースの関係を示す図

Cluster APIには、MachineDeploymentという名前のリソースもあります。 これは物理サーバーか仮想マシンかにかかわらずノードのグループを記述するものです。 このリソースは、Deployment、ReplicaSet、Podなどの標準のKubernetesリソースと同様に機能し、ノードのグループを宣言的に記述し、自動的にスケーリングするためのメカニズムを提供します。

つまり、MachineDeploymentリソースを使用すると、クラスターのノードを宣言的に記述でき、指定されたパラメーターと要求されたレプリカ数に応じて、ノードの作成、削除、更新を自動化できます。

Cluster APIにおけるClusterリソースとその子リソースの関係を示す図

Cluster APIにおけるMachineDeploymentリソースとその子リソースの関係を示す図

マシンを作成するために、MachineDeploymentは、マシン自体を生成するためのテンプレートと、そのcloud-init設定を生成するためのテンプレートを参照します。

Cluster APIにおけるClusterリソースとそれがリンクするリソースの関係を示す図

Cluster APIにおけるMachineDeploymentリソースとそれがリンクするリソースの関係を示す図

Cluster APIを使用して新しいKubernetesクラスターをデプロイするには、以下のリソースのセットを準備する必要があります。

  • 一般的なClusterリソース
  • Kamajiが運用するコントロールプレーンを担当するKamajiControlPlaneリソース
  • KubeVirt内のクラスター設定を記述するKubevirtClusterリソース
  • 仮想マシンテンプレートを担当するKubevirtMachineTemplateリソース
  • トークンとcloud-initの生成を担当するKubeadmConfigTemplateリソース
  • いくつかのワーカーを作成するための少なくとも1つのMachineDeployment

クラスターの仕上げ

ほとんどの場合これで十分ですが、使用するプロバイダーによっては、他のリソースも必要になる場合があります。 プロバイダーの種類ごとに作成されるリソースの例は、Kamajiプロジェクトのドキュメントで確認できます。

この段階ですでに使用可能なテナントKubernetesクラスターができていますが、これまでのところ、APIワーカーとあらゆるKubernetesクラスターのインストールに標準で含まれるいくつかのコアプラグイン(kube-proxyCoreDNS)しか含まれていません。 完全に統合するには、さらにいくつかのコンポーネントをインストールする必要があります。

追加のコンポーネントをインストールするには、個別のCluster API Add-on Provider for Helmや、前の記事で説明したFluxCDを使用できます。

FluxCDでリソースを作成する際、Cluster APIによって生成されたkubeconfigを参照することでターゲットクラスターを指定できます。 そうするとインストールは直接そのクラスターに対して実行されます。 このように、FluxCDは管理クラスターとユーザーテナントクラスターの両方でリソースを管理するための汎用ツールになります。

管理クラスターとテナントKubernetesクラスターの両方にコンポーネントをインストールできるfluxcdの相互作用スキームを示す図

管理クラスターとテナントKubernetesクラスターの両方にコンポーネントをインストールできるfluxcdの相互作用スキームを示す図

ここで議論されているコンポーネントとは何でしょうか?一般的に、そのセットには以下が含まれます。

CNIプラグイン

テナントKubernetesクラスター内のPod間の通信を確保するには、CNIプラグインをデプロイする必要があります。 このプラグインは、Pod同士が相互に通信できるようにする仮想ネットワークを作成し、従来はクラスターのワーカーノード上にDaemonsetとしてデプロイされます。 適切だと思うCNIプラグインを選んでインストールできます。

ネストされたKubernetesクラスターのスキームにおいて、テナントKubernetesクラスター内にインストールされたCNIプラグインを示す図

ネストされたKubernetesクラスターのスキームにおいて、テナントKubernetesクラスター内にインストールされたCNIプラグインを示す図

クラウドコントローラーマネージャー

この一部レスポンスについては、以下のようにMarkdown記法を修正するのが良いと思います。

クラウドコントローラーマネージャー(CCM)の主な役割は、Kubernetes をクラウドインフラストラクチャプロバイダーの環境(この場合は、テナントKubernetesのすべてのワーカーがプロビジョニングされている管理Kubernetesクラスター)と統合することです。 CCMが実行するタスクは次のとおりです。

  1. LoadBalancer タイプのサービスが作成されると、CCM はクラウドロードバランサーの作成プロセスを開始します。これにより、トラフィックが Kubernetes クラスターに誘導されます。
  2. クラウドインフラストラクチャからノードが削除された場合、CCM はクラスターからもそのノードを確実に削除し、クラスターの現在の状態を維持します。
  3. CCM を使用する場合、ノードは特別な taint (node.cloudprovider.kubernetes.io/uninitialized) を付けてクラスターに追加されます。これにより、必要に応じて追加のビジネスロジックを処理できます。初期化が正常に完了すると、この taint がノードから削除されます。

クラウドプロバイダーによっては、CCM がテナントクラスターの内部と外部の両方で動作する場合があります。

KubeVirt Cloud Providerは、外部の親管理クラスターにインストールするように設計されています。 したがって、テナントクラスターでLoadBalancerタイプのサービスを作成すると親クラスターでLoadBalancerサービスの作成が開始され、トラフィックがテナントクラスターに誘導されます。

ネストされたKubernetesクラスターのスキームにおいて、テナントKubernetesクラスターの外部にインストールされたCloud Controller Managerと、それが管理する親から子へのKubernetesクラスター間のサービスのマッピングを示す図

ネストされたKubernetesクラスターのスキームにおいて、テナントKubernetesクラスターの外部にインストールされたCloud Controller Managerと、それが管理する親から子へのKubernetesクラスター間のサービスのマッピングを示す図

CSIドライバー

Container Storage Interface(CSI)は、Kubernetesでストレージを操作するために、2つの主要な部分に分かれています。

  • csi-controller: このコンポーネントは、クラウドプロバイダーのAPIと対話して、ボリュームの作成、削除、アタッチ、デタッチ、およびサイズ変更を行う責任があります。
  • csi-node: このコンポーネントは各ノードで実行され、kubeletから要求されたPodへのボリュームのマウントを容易にします。

KubeVirt CSI Driverを使用するコンテキストでは、ユニークな機会が生まれます。 KubeVirtの仮想マシンは管理KubernetesクラスターでKubernetesのフル機能のAPIが利用できる環境で実行されるため、ユーザーのテナントクラスターの外部でcsi-controllerを実行する道が開かれます。 このアプローチはKubeVirtコミュニティで人気があり、いくつかの重要な利点があります。

  • セキュリティ: この方法では、エンドユーザーからクラウドの内部APIを隠し、Kubernetesインターフェースを介してのみリソースへのアクセスを提供します。これにより、ユーザークラスターから管理クラスターへの直接アクセスのリスクが軽減されます。
  • シンプルさと利便性: ユーザーは自分のクラスターで追加のコントローラーを管理する必要がないため、アーキテクチャが簡素化され、管理の負担が軽減されます。

ただし、csi-nodeは、各ノードのkubeletと直接やり取りするため、必然的にテナントクラスター内で実行する必要があります。 このコンポーネントは、Podへのボリュームのマウントとマウント解除を担当し、クラスターノードで直接発生するプロセスとの緊密な統合が必要です。

KubeVirt CSIドライバーは、ボリュームの要求のためのプロキシとして機能します。 テナントクラスター内でPVCが作成されると、管理クラスターにPVCが作成され、作成されたPVが仮想マシンに接続されます。

ネストされたKubernetesクラスターのスキームにおいて、テナントKubernetesクラスターの内部と外部の両方にインストールされたCSIプラグインのコンポーネントと、それが管理する親から子へのKubernetesクラスター間の永続ボリュームのマッピングを示す図

ネストされたKubernetesクラスターのスキームにおいて、テナントKubernetesクラスターの内部と外部の両方にインストールされたCSIプラグインのコンポーネントと、それが管理する親から子へのKubernetesクラスター間の永続ボリュームのマッピングを示す図

クラスターオートスケーラー

クラスターオートスケーラーは、さまざまなクラウドAPIと連携できる汎用的なコンポーネントであり、Cluster APIとの統合は利用可能な機能の1つに過ぎません。 適切に設定するには、2つのクラスターへのアクセスが必要です。 テナントクラスターではPodを追跡し、新しいノードを追加する必要性を判断し、管理するKubernetesクラスター(管理Kubernetesクラスター)ではMachineDeploymentリソースと対話し、レプリカ数を調整します。

Cluster Autoscalerは通常テナントKubernetesクラスター内で実行されますが、今回のケースでは、前述と同じ理由からクラスター外にインストールすることをお勧めします。 このアプローチは、テナントクラスターのユーザーが管理クラスターの管理APIにアクセスできないようにするため、メンテナンスがより簡単で、より安全です。

ネストされたKubernetesクラスターのスキームにおいて、テナントKubernetesクラスターの外部にインストールされたCloud Controller Managerを示す図

ネストされたKubernetesクラスターのスキームにおいて、テナントKubernetesクラスターの外部にインストールされたCluster Autoscalerを示す図

Konnectivity

もう1つ追加のコンポーネントについて言及したいと思います。 Konnectivityです。 後でテナントKubernetesクラスターでwebhookとAPIアグリゲーションレイヤーを動作させるために、おそらくこれが必要になるでしょう。 このトピックについては、私の以前の記事で詳しく説明しています。

上記のコンポーネントとは異なり、Kamajiでは、Konnectivityを簡単に有効にし、kube-proxyやCoreDNSと並んで、テナントクラスターのコアコンポーネントの1つとして管理できます。

まとめ

これで、動的スケーリング、ボリュームの自動プロビジョニング、ロードバランサーの機能を備えた、完全に機能するKubernetesクラスターができました。

今後は、テナントクラスターからのメトリクスやログの収集を検討するとよいでしょうが、それはこの記事の範囲を超えています。

もちろん、Kubernetesクラスターをデプロイするために必要なコンポーネントはすべて、1つのHelmチャートにパッケージ化し、統一されたアプリケーションとしてデプロイできます。 これは、オープンなPaaSプラットフォームであるCozystackで、ボタンをクリックするだけで管理対象のKubernetesクラスターのデプロイを整理する方法そのものです。 Cozystackでは、記事で説明したすべてのテクノロジーを無料で試すことができます。

DIY: Kubernetesで自分だけのクラウドを構築しよう(パート2)

Kubernetesエコシステムだけを使って自分だけのクラウドを構築する方法について、一連の記事を続けています。 前回の記事では、Talos LinuxとFlux CDをベースにした基本的なKubernetes ディストリビューションの準備方法を説明しました。 この記事では、Kubernetesにおけるさまざまな仮想化テクノロジーをいくつか紹介し、主にストレージとネットワークを中心に、Kubernetes内で仮想マシンを実行するために必要な環境を整えます。

KubeVirt、LINSTOR、Kube-OVNなどのテクノロジーについて取り上げる予定です。

しかし最初に、仮想マシンが必要な理由と、クラウドの構築にDockerコンテナを使用するだけでは不十分である理由を説明しましょう。 その理由は、コンテナが十分なレベルの分離を提供していないことにあります。 状況は年々改善されていますが、コンテナのサンドボックスから脱出してシステムの特権を昇格させる脆弱性が見つかることがよくあります。

一方、Kubernetesはもともとマルチテナントシステムとして設計されていなかったため、基本的な使用パターンでは、独立したプロジェクトや開発チームごとに別々のKubernetesクラスターを作成することが一般的です。

仮想マシンは、クラウド環境でテナント同士を分離するための主要な手段です。 仮想マシン内では、ユーザーは管理者権限でコードやプログラムを実行できますが、これは他のテナントや環境自体に影響を与えません。 つまり、仮想マシンはハードマルチテナンシー分離を実現し、テナント間で信頼関係がない環境でも安全に実行できます。

Kubernetes における仮想化テクノロジー

Kubernetesの世界に仮想化をもたらすテクノロジーはいくつかありますが、KubeVirtKata Containersが最も一般的です。 ただし、これらの動作方式は異なることを理解しておく必要があります。

Kata Containersは、CRI(Container Runtime Interface)を実装しており、標準のコンテナを仮想マシン内で実行することで、追加の分離レベルを提供します。 ただし、これらは同一のKubernetesクラスター内で動作します。

コンテナを仮想マシン内で実行することにより、Kata Containersがコンテナの分離を確保する方法を示す図

コンテナを仮想マシン内で実行することにより、Kata Containersがコンテナの分離を確保する方法を示す図

KubeVirtは、Kubernetes APIを使用して従来の仮想マシンを実行できます。 KubeVirtの仮想マシンは、コンテナ内の通常のLinuxプロセスとして実行されます。 つまり、KubeVirtでは、コンテナが仮想マシン(QEMU)プロセスを実行するためのサンドボックスとして使用されます。 これは、以下の図で、KubeVirtにおける仮想マシンのライブマイグレーションの実装方法を見ると明らかです。 マイグレーションが必要な場合、仮想マシンはあるコンテナから別のコンテナに移動します。

KubeVirtにおいて、仮想マシンがあるコンテナから別のコンテナへライブマイグレーションする様子を示す図

KubeVirtにおいて、仮想マシンがあるコンテナから別のコンテナへライブマイグレーションする様子を示す図

Cloud-Hypervisorを使用した軽量な仮想化を実装し、初期からCluster APIを使用した仮想Kubernetesクラスターの実行に重点を置いている代替プロジェクトVirtinkもあります。

私たちの目標を考慮して、この分野で最も一般的なプロジェクトであるKubeVirtを使用することに決めました。 さらに、私たちはKubeVirtに関する豊富な専門知識を持ち、すでに多くの貢献をしています。

KubeVirtはインストールが簡単で、containerDisk機能を使用してすぐに仮想マシンを実行できます。 この機能により、VMイメージをコンテナイメージレジストリから直接OCIイメージとして保存および配布できます。 containerDiskを使用した仮想マシンは、Kubernetesワーカーノードやその他の状態の永続化を必要としない仮想マシンの作成に適しています。

永続データを管理するために、KubeVirtは別のツールであるContainerized Data Importer(CDI)を提供しています。 CDIを使用すると、PVCのクローンを作成し、ベースイメージからデータを取り込むことができます。 CDIは、仮想マシンの永続ボリュームを自動的にプロビジョニングする場合や、テナントKubernetesクラスターからの永続ボリューム要求を処理するために使用されるKubeVirt CSIドライバーにも必要となります。

しかし最初に、これらのデータをどこにどのように保存するかを決める必要があります。

Kubernetes上の仮想マシン用ストレージ

CSI(Container Storage Interface)の導入により、Kubernetesと統合できる幅広いテクノロジーが利用可能になりました。 実際、KubeVirtはCSIインターフェースを完全に活用しており、仮想化のためのストレージの選択肢はKubernetes自体のストレージの選択肢と密接に連携しています。 しかし、考慮すべき細かな差異があります。 通常、標準のファイルシステムを使用するコンテナとは異なり、仮想マシンにはブロックデバイスの方が効率的です。

KubernetesのCSIインターフェースでは、ファイルシステムとブロックデバイスの両方のタイプのボリュームを要求できますが、使用しているストレージバックエンドがこれをサポートしていることを確認することが重要です。

仮想マシンにブロックデバイスを使用すると、ファイルシステムなどの追加の抽象化レイヤーが不要になるため、パフォーマンスが向上し、ほとんどの場合で ReadWriteMany モードの使用が可能になります。 このモードでは、複数のノードから同時にボリュームにアクセスできるため、KubeVirtにおける仮想マシンのライブマイグレーションを有効にするための重要な機能です。

ストレージシステムは、外部または内部(ハイパーコンバージドインフラストラクチャの場合)にすることができます。 多くの場合、外部ストレージを使用するとデータが計算ノードから分離して保存されるため、システム全体の安定性が向上します。

計算ノードと通信する外部データストレージを示す図

計算ノードと通信する外部データストレージを示す図

外部ストレージソリューションは、エンタープライズシステムでよく使用されています。 このようなストレージは、多くの場合運用を担当する外部ベンダーによって提供されるためです。 Kubernetesとの統合には、クラスターにインストールされる小さなコンポーネントであるCSIドライバーのみが関与します。 このドライバーは、このストレージにボリュームをプロビジョニングし、Kubernetesによって実行されるPodにそれらをアタッチする役割を担います。 ただし、このようなストレージソリューションは、純粋にオープンソースのテクノロジーを使用して実装することもできます。 人気のあるソリューションの1つは、democratic-csiドライバーを使用したTrueNASです。

コンピュートノード上で実行されるローカルデータストレージを示す図

コンピュートノード上で実行されるローカルデータストレージを示す図

一方、ハイパーコンバージドシステムは、多くの場合、ローカルストレージ(レプリケーションが不要な場合)と、Rook/CephOpenEBSLonghornLINSTORなどのソフトウェアデファインドストレージを使用して実装されます。 これらは、多くの場合、Kubernetesに直接インストールされます。

コンピュートノード上で実行されるクラスター化データストレージを示す図

コンピュートノード上で実行されるクラスター化データストレージを示す図

ハイパーコンバージドシステムには利点があります。 たとえば、データの局所性です。 データがローカルに保存されている場合、そのデータへのアクセスは高速になります。 しかし、このようなシステムは通常、管理と保守がより難しいという欠点があります。

Ænixでは、追加の外部ストレージを購入してセットアップする必要なく使用でき、速度とリソースの利用の点で最適な、すぐに使える解決策を提供したいと考えていました。 LINSTORがその解決策となりました。 バックエンドとして業界で人気のある実績あるテクノロジーであるLVMやZFSを使用していることで、データが安全に保存されていることに自信が持てます。 DRDBベースのレプリケーションは信じられないほど高速で、少ない計算リソースしか消費しません。

Kubernetes上でLINSTORをインストールするには、PiraeusプロジェクトがKubeVirtで使用できる既製のブロックストレージをすでに提供しています。

Kubernetes上の仮想マシン用ネットワーク

Kubernetesのネットワークアーキテクチャは同じようなインターフェースであるCNIを持っているにもかかわらず、実際にはより複雑で、通常、互いに直接接続されていない多くの独立したコンポーネントで構成されています。 実際、Kubernetesのネットワークは以下に説明する4つのレイヤーに分割できます。

ノードネットワーク (データセンターネットワーク)

ノードが相互に接続されるネットワークです。 このネットワークは通常、Kubernetesによって管理されませんが、これがないと何も機能しないため、重要なネットワークです。 実際には、ベアメタルインフラストラクチャには通常、複数のこのようなネットワークがあります。 例えば、ノード間通信用の1つ、ストレージレプリケーション用の2つ目、外部アクセス用の3つ目などです。

Kubernetesのネットワーク構成におけるノードネットワーク(データセンターネットワーク)の役割を示す図

Kubernetesのネットワーク構成におけるノードネットワーク(データセンターネットワーク)の役割を示す図

ノード間の物理ネットワークの相互作用の設定は、ほとんどの状況でKubernetesが既存のネットワークインフラストラクチャを利用するため、この記事の範囲を超えています。

Podネットワーク

これは、CNIプラグインによって提供されるネットワークです。 CNIプラグインの役割は、クラスター内のすべてのコンテナとノード間の透過的な接続を確保することです。 ほとんどのCNIプラグインは、各ノードで使用するためにIPアドレスの個別のブロックが割り当てられるフラットネットワークを実装しています。

Kubernetesのネットワーク構成におけるPodネットワーク(CNIプラグイン)の役割を示す図

Kubernetesのネットワーク構成におけるPodネットワーク(CNIプラグイン)の役割を示す図

実際には、クラスターにはMultusによって管理される複数のCNIプラグインを持つことができます。 このアプローチは、RancherOpenShiftなどのKubeVirtベースの仮想化ソリューションでよく使用されます。 プライマリCNIプラグインはKubernetesサービスとの統合に使用され、追加のCNIプラグインはプライベートネットワーク(VPC)の実装やデータセンターの物理ネットワークとの統合に使用されます。

デフォルトのCNIプラグインは、ブリッジまたは物理インターフェースの接続に使用できます。 さらに、パフォーマンスを向上させるために設計されたmacvtap-cniなどの専用プラグインもあります。

Kubernetes内で仮想マシンを実行する際に注意すべきもう1つの側面は、特にMultusによって提供されるセカンダリインターフェースに対するIPAM(IPアドレス管理)の必要性です。 これは通常、インフラストラクチャ内で動作するDHCPサーバーによって管理されます。 さらに、仮想マシンのMACアドレスの割り当ては、Kubemacpoolによって管理できます。

私たちのプラットフォームでは、別の方法を選択し、Kube-OVNに完全に頼ることにしました。 このCNIプラグインは、もともとOpenStack用に開発されたOVN(Open Virtual Network)をベースにしています。 Kube-OVNはKubernetes内の仮想マシン用の完全なネットワークソリューションを提供します。 IPとMACアドレスを管理するためのカスタムリソースを備え、ノード間でIPアドレスを保持したままライブマイグレーションをサポートし、テナント間の物理ネットワーク分離用のVPCの作成を可能にします。

Kube-OVNでは、名前空間全体に個別のサブネットを割り当てたり、Multusを使用して追加のネットワークインターフェースとして接続したりできます。

サービスネットワーク

CNIプラグインに加えて、Kubernetesにはサービスネットワークもあります。これは主にサービスディスカバリーに必要です。 従来の仮想マシンとは異なり、KubernetesはもともとランダムなアドレスでPodを実行するように設計されています。 そして、サービスネットワークは、トラフィックを常に正しいPodに誘導する便利な抽象化(安定したIPアドレスとDNS名)を提供します。 仮想マシンのIPは通常静的であるにもかかわらず、このアプローチはクラウド内の仮想マシンでも一般的に使用されています。

Kubernetesのネットワーク構成におけるサービスネットワーク(サービスネットワークプラグイン)の役割を示す図

Kubernetesのネットワーク構成におけるサービスネットワーク(サービスネットワークプラグイン)の役割を示す図

Kubernetesでのサービスネットワークの実装は、サービスネットワークプラグインによって処理されます。 標準の実装はkube-proxyと呼ばれ、ほとんどのクラスターで使用されています。 しかし最近では、この機能はCNIプラグインの一部として提供されることがあります。 最も先進的な実装は、Ciliumプロジェクトによって提供されており、kube-proxyの代替モードで実行できます。

CiliumはeBPFテクノロジーに基づいており、Linuxネットワークスタックを効率的にオフロードできるため、iptablesベースの従来の方法と比較してパフォーマンスとセキュリティが向上します。

実際には、CiliumとKube-OVNを簡単に統合することが可能です。 これにより、仮想マシン向けにシームレスでマルチテナントのネットワーキングを提供する統合ソリューションを実現することができます。 また、高度なネットワークポリシーと統合されたサービスネットワーク機能も提供されます。

外部トラフィックのロードバランサー

この段階で、Kubernetes内で仮想マシンを実行するために必要なものはすべて揃っています。 しかし、実際にはもう1つ必要なものがあります。 クラスターの外部からサービスにアクセスする必要がまだあり、外部ロードバランサーがこれを整理するのに役立ちます。

ベアメタルのKubernetesクラスターには、いくつかの利用可能なロードバランサーがあります。 MetalLBkube-vipLoxiLBがあり、またCiliumKube-OVNにはビルトインの実装が提供されています。

外部ロードバランサーの役割は、外部から利用可能な安定したアドレスを提供し、外部トラフィックをサービスネットワークに誘導することです。 サービスネットワークプラグインは、通常どおりそれをPodと仮想マシンに誘導します。

Kubernetesのネットワーク構成における外部ロードバランサーの役割

Kubernetesのネットワーク構成における外部ロードバランサーの役割を示す図

ほとんどの場合、ベアメタル上でのロードバランサーの設定は、クラスター内のノードにフローティングIPアドレスを作成し、ARP/NDPまたはBGPプロトコルを使用してそれを外部にアナウンスすることによって実現されます。

さまざまなオプションを検討した結果、MetalLBが最もシンプルで信頼性の高いソリューションであると判断しましたが、MetalLBの使用のみを厳密に強制しているわけではありません。

もう1つの利点は、L2モードでは、MetalLBスピーカーがメンバーリストプロトコルを使用してライブネスチェックを実行することにより、ネイバーの状態を継続的にチェックすることです。 これにより、Kubernetesコントロールプレーンとは独立して機能するフェイルオーバーが可能になります。

まとめ

ここまでが、Kubernetesにおける仮想化、ストレージ、ネットワークの概要になります。 ここで取り上げたテクノロジーは、Cozystackプラットフォームで利用可能であり、制限なくお試しいただけるよう事前に設定されています。

次の記事では、この上にボタンをクリックするだけで、完全に機能するKubernetesクラスターのプロビジョニングをどのように実装できるかを詳しく説明します。

DIY: Kubernetesで自分だけのクラウドを構築しよう(パート1)

Ænixでは、Kubernetesに対する深い愛着があり、近いうちにすべての最新テクノロジーがKubernetesの驚くべきパターンを活用し始めることを夢見ています。 自分だけのクラウドを構築することを考えたことはありませんか?きっと考えたことがあるでしょう。 しかし、快適なKubernetesエコシステムを離れることなく、最新のテクノロジーとアプローチのみを使ってそれを実現することは可能でしょうか? Cozystackの開発における私たちの経験は、その点を深く掘り下げる必要がありました。 自分だけのクラウドを構築することを考えたことはありませんか?

Kubernetesはこの目的のために設計されたものではなく、ベアメタルサーバー用にOpenStackを使用し、意図したとおりにその内部でKubernetesを実行すればよいのではないかと主張する人もいるかもしれません。 しかし、そうすることで、単に責任があなたの手からOpenStack管理者の手に移っただけです。 これにより、少なくとも1つの巨大で複雑なシステムがエコシステムに追加されることになります。

なぜ物事を複雑にするのでしょうか? 結局のところ、Kubernetesにはテナント用のKubernetesクラスターを実行するために必要なものがすべて揃っています。

Kubernetesをベースにしたクラウドプラットフォームの開発における私たちの経験を共有したいと思います。 私たち自身が使用しており、あなたの注目に値すると信じているオープンソースプロジェクトを紹介します。

この一連の記事では、オープンソースのテクノロジーのみを使用して、ベアメタルから管理されたKubernetesを準備する方法についての私たちの物語をお伝えします。 データセンターの準備、仮想マシンの実行、ネットワークの分離、フォールトトレラントなストレージのセットアップといった基本的なレベルから、動的なボリュームのプロビジョニング、ロードバランサー、オートスケーリングを備えた本格的なKubernetesクラスターのプロビジョニングまでを扱います。

この記事から、いくつかのパートで構成されるシリーズを開始します:

  • パート1: 自分のクラウドの基礎を準備する。ベアメタル上でのKubernetesの準備と運用における課題、およびインフラストラクチャをプロビジョニングするための既成のレシピ。
  • パート2: ネットワーク、ストレージ、仮想化。Kubernetesを仮想マシン起動のためのツールにする方法とそのために必要なもの。
  • パート3: Cluster APIと、ボタンを押すだけでKubernetesクラスターのプロビジョニングを開始する方法。オートスケーリング、ボリュームの動的プロビジョニング、ロードバランサーの仕組み。

さまざまなテクノロジーをできるだけ独立して説明しようと思いますが、同時に、私たちの経験と、なぜある解決策に至ったのかを共有します。

まず、Kubernetesの主な利点と、それがクラウドリソースの使用へのアプローチをどのように変えたかを理解しましょう。

クラウドとベアメタルでは、Kubernetesの使い方が異なることを理解することが重要です。

クラウド上のKubernetes

クラウド上でKubernetesを運用する場合、永続ボリューム、クラウドロードバランサー、ノードのプロビジョニングプロセスを気にする必要はありません。 これらはすべて、Kubernetesオブジェクトの形式であなたのリクエストを受け入れるクラウドプロバイダーによって処理されます。 つまり、サーバー側は完全にあなたから隠されており、クラウドプロバイダーがどのように正確に実装しているかを知る必要はありません。 それはあなたの責任範囲ではないからです。

クラウド上のKubernetesを示す図。ロードバランシングとストレージはクラスターの外部で行われています

クラウド上のKubernetesを示す図。ロードバランシングとストレージはクラスターの外部で行われています

Kubernetesは、どこでも同じように機能する便利な抽象化を提供しているため、あらゆるクラウドのKubernetes上にアプリケーションをデプロイできます。

クラウドでは、Kubernetesコントロールプレーン、仮想マシン、永続ボリューム、ロードバランサーなど、いくつかの個別のエンティティを持つことが非常に一般的です。 これらのエンティティを使用することで、高度に動的な環境を作成できます。

Kubernetesのおかげで、仮想マシンは今やクラウドリソースを利用するための単なるユーティリティエンティティとしてのみ見られるようになりました。 もはや仮想マシンの中にデータを保存することはありません。 仮想マシンをすべて削除して、アプリケーションを壊すことなく再作成できます。 Kubernetesコントロールプレーンは、クラスター内で何が実行されるべきかについての情報を保持し続けます。 ロードバランサーは、新しいノードにトラフィックを送信するためにエンドポイントを変更するだけで、ワークロードにトラフィックを送信し続けます。 そして、データはクラウドが提供する外部の永続ボリュームに安全に保存されます。

このアプローチは、クラウドでKubernetesを使用する際の基本です。 その理由はかなり明白です。 システムが単純であるほど安定性が高くなり、このシンプルさのためにクラウドでKubernetesを選択するのです。

ベアメタル上のKubernetes

クラウドでKubernetesを使用することは本当に簡単で便利ですが、ベアメタルへのインストールについては同じことが言えません。 ベアメタルの世界では、Kubernetesは逆に非常に複雑になります。 まず、ネットワーク全体、バックエンドストレージ、クラウドバランサーなどは、通常、クラスターの外部ではなく内部で実行されるためです。 その結果、このようなシステムは更新と保守がはるかに難しくなります。

ベアメタル上のKubernetesを示す図。ロードバランシングとストレージはクラスターの内部で行われています

ベアメタル上のKubernetesを示す図。ロードバランシングとストレージはクラスターの内部で行われています

ご自身で判断してみてください。 クラウドでは、通常、ノードを更新するために仮想マシンを削除する(またはkubectl delete nodeを使用する)だけで、イミュータブルなイメージに基づいて新しいノードを作成することをノード管理ツールに任せることができます。 新しいノードはクラスターに参加し、Kubernetesの世界で非常にシンプルでよく使われるパターンに従って、ノードとして「そのまま動作」します。 多くのクラスターでは、安価なスポットインスタンスを利用できるため、数分ごとに新しい仮想マシンをオーダーしています。 しかし、物理サーバーを使用している場合は、簡単に削除して再作成することはできません。 まず、物理サーバーはクラスターサービスを実行していたり、データを保存していたりすることが多いため、その更新プロセスははるかに複雑になるからです。

この問題を解決するアプローチはさまざまです。 kubeadm、kubespray、k3sが行うようなインプレースアップデートから、Cluster APIとMetal3を通じた物理ノードのプロビジョニングの完全な自動化まで幅広くあります。

私は、Talos Linuxが提供するハイブリッドアプローチが気に入っています。 このアプローチでは、システム全体が単一の設定ファイルで記述されます。 このファイルのほとんどのパラメーターは、Kubernetesコントロールプレーンコンポーネントのバージョンを含め、ノードを再起動または再作成することなく適用できます。 それでも、Kubernetesの宣言的な性質を最大限に保持しています。 このアプローチは、ベアメタルノードを更新する際のクラスターサービスへの不要な影響を最小限に抑えます。 ほとんどの場合、マイナーアップデートの際に仮想マシンを移行したり、クラスターファイルシステムを再構築したりする必要はありません。

将来のクラウドの基盤を準備する

さて、自分だけのクラウドを構築することに決めたとしましょう。 まずは基盤となるレイヤーが必要です。 サーバーにKubernetesをインストールする方法だけでなく、それをどのように更新し、維持していくかについても考える必要があります。 カーネルの更新、必要なモジュールのインストール、パッケージやセキュリティパッチなどについても考えなければならないことを考慮してください。 クラウド上の既製のKubernetesを使用する際に気にする必要のないことをはるかに多く考えなければなりません。

もちろん、UbuntuやDebianのような標準的なディストリビューションを使用できますし、Flatcar Container Linux、Fedora Core、Talos Linuxのような特殊なディストリビューションを検討することもできます。 それぞれに長所と短所があります。

私たちのことですか? Ænixでは、ZFS、DRBD、OpenvSwitchなどのかなり特殊なカーネルモジュールを使用しているので、必要なモジュールをすべて事前に含んだシステムイメージを形成する方法を選びました。 この場合、Talos Linuxが私たちにとって最も便利であることがわかりました。 たとえば、次のような設定で、必要なカーネルモジュールをすべて含むシステムイメージを構築するのに十分です:

arch: amd64
platform: metal
secureboot: false
version: v1.6.4
input:
  kernel:
    path: /usr/install/amd64/vmlinuz
  initramfs:
    path: /usr/install/amd64/initramfs.xz
  baseInstaller:
    imageRef: ghcr.io/siderolabs/installer:v1.6.4
  systemExtensions:
    - imageRef: ghcr.io/siderolabs/amd-ucode:20240115
    - imageRef: ghcr.io/siderolabs/amdgpu-firmware:20240115
    - imageRef: ghcr.io/siderolabs/bnx2-bnx2x:20240115
    - imageRef: ghcr.io/siderolabs/i915-ucode:20240115
    - imageRef: ghcr.io/siderolabs/intel-ice-firmware:20240115
    - imageRef: ghcr.io/siderolabs/intel-ucode:20231114
    - imageRef: ghcr.io/siderolabs/qlogic-firmware:20240115
    - imageRef: ghcr.io/siderolabs/drbd:9.2.6-v1.6.4
    - imageRef: ghcr.io/siderolabs/zfs:2.1.14-v1.6.4
output:
  kind: installer
  outFormat: raw

dockerコマンドラインツールを使用して、OSイメージをビルドします:

cat config.yaml | docker run --rm -i -v /dev:/dev --privileged "ghcr.io/siderolabs/imager:v1.6.4" -

その結果、必要なものがすべて含まれたDockerコンテナイメージが得られます。 このイメージを使用して、サーバーにTalos Linuxをインストールできます。 同じことができます。このイメージには、必要なすべてのファームウェアとカーネルモジュールが含まれます。

しかし、新しく形成されたイメージをノードにどのように配信するかという問題が発生します。

しばらくの間、PXEブートのアイデアについて考えていました。 たとえば、2年前に記事を書いたKubefarmプロジェクトは、完全にこのアプローチを使用して構築されました。 しかし残念ながら、他のクラスターを保持する最初の親クラスターをデプロイするのに役立つわけではありません。 そこで今回、PXEアプローチを使用して同じことを行うのに役立つソリューションを用意しました。

基本的に必要なのは、コンテナ内で一時的なDHCPPXEサーバーを実行することだけです。 そうすれば、ノードはあなたのイメージから起動し、Debianベースの簡単なスクリプトを使用して、ノードのブートストラップに役立てることができます。

asciicast

talos-bootstrapスクリプトのソースコードはGitHubで入手できます。

このスクリプトを使用すると、ベアメタル上に5分でKubernetesをデプロイし、それにアクセスするためのkubeconfigを取得できます。 しかし、まだ多くの未解決の問題が残っています。

システムコンポーネントの配信

この段階では、さまざまなワークロードを実行できるKubernetesクラスターがすでに手に入っています。 しかし、まだ完全に機能しているわけではありません。 つまり、ネットワークとストレージを設定する必要があるだけでなく、仮想マシンを実行するためのKubeVirtや、監視スタックやその他のシステム全体のコンポーネントなど、必要なクラスター拡張機能をインストールする必要があります。

従来、これはHelmチャートをクラスターにインストールすることで解決されています。 ローカルでhelm installコマンドを実行することで実現できますが、アップデートを追跡したい場合や、複数のクラスターを持っていてそれらを均一に保ちたい場合、このアプローチは不便になります。 実際には、これを宣言的に行う方法はたくさんあります。 これを解決するには、最高のGitOpsプラクティスを使用することをお勧めします。 つまり、ArgoCDやFluxCDのようなツールを指します。

ArgoCDはグラフィカルインターフェースと中央コントロールプレーンを備えているため開発目的には便利ですが、一方でFluxCDはKubernetesディストリビューションの作成により適しています。 FluxCDを使用すると、どのチャートをどのパラメーターで起動すべきかを指定し、依存関係を記述できます。 そうすれば、FluxCDがすべてを処理してくれます。

新しく作成したクラスターにFluxCDを1回インストールし、適切に設定することをお勧めします。 これにより、FluxCDは必要不可欠なコンポーネントをすべて自動的にデプロイできるようになり、クラスターを目的の状態にアップグレードできます。 たとえば、私たちのプラットフォームをインストールすると、システムコンポーネントとともに次の事前設定されたHelmチャートが表示されます:

NAMESPACE                        NAME                        AGE    READY   STATUS
cozy-cert-manager                cert-manager                4m1s   True    Release reconciliation succeeded
cozy-cert-manager                cert-manager-issuers        4m1s   True    Release reconciliation succeeded
cozy-cilium                      cilium                      4m1s   True    Release reconciliation succeeded
cozy-cluster-api                 capi-operator               4m1s   True    Release reconciliation succeeded
cozy-cluster-api                 capi-providers              4m1s   True    Release reconciliation succeeded
cozy-dashboard                   dashboard                   4m1s   True    Release reconciliation succeeded
cozy-fluxcd                      cozy-fluxcd                 4m1s   True    Release reconciliation succeeded
cozy-grafana-operator            grafana-operator            4m1s   True    Release reconciliation succeeded
cozy-kamaji                      kamaji                      4m1s   True    Release reconciliation succeeded
cozy-kubeovn                     kubeovn                     4m1s   True    Release reconciliation succeeded
cozy-kubevirt-cdi                kubevirt-cdi                4m1s   True    Release reconciliation succeeded
cozy-kubevirt-cdi                kubevirt-cdi-operator       4m1s   True    Release reconciliation succeeded
cozy-kubevirt                    kubevirt                    4m1s   True    Release reconciliation succeeded
cozy-kubevirt                    kubevirt-operator           4m1s   True    Release reconciliation succeeded
cozy-linstor                     linstor                     4m1s   True    Release reconciliation succeeded
cozy-linstor                     piraeus-operator            4m1s   True    Release reconciliation succeeded
cozy-mariadb-operator            mariadb-operator            4m1s   True    Release reconciliation succeeded
cozy-metallb                     metallb                     4m1s   True    Release reconciliation succeeded
cozy-monitoring                  monitoring                  4m1s   True    Release reconciliation succeeded
cozy-postgres-operator           postgres-operator           4m1s   True    Release reconciliation succeeded
cozy-rabbitmq-operator           rabbitmq-operator           4m1s   True    Release reconciliation succeeded
cozy-redis-operator              redis-operator              4m1s   True    Release reconciliation succeeded
cozy-telepresence                telepresence                4m1s   True    Release reconciliation succeeded
cozy-victoria-metrics-operator   victoria-metrics-operator   4m1s   True    Release reconciliation succeeded

まとめ

結果として、誰にでも提供できる高い再現性を持つ環境を実現でき、意図したとおりに動作することがわかります。 これは、実際にCozystackプロジェクトが行っていることであり、あなた自身が無料で試すことができます。

次の記事では、仮想マシンを実行するためのKubernetesの準備方法ボタンをクリックするだけでKubernetesクラスターを実行する方法について説明します。 ご期待ください。きっと面白いはずです!

Kubernetes v1.30をそっと覗く

Kubernetes v1.30のおもしろい変更点をざっと見る

新しい年であり、新しいKubernetesのリリースです。 リリースサイクルの半分が終了し、v1.30ではかなりの数の興味深くおもしろい機能強化が行われます。 アルファ版の真新しい機能から、安定版へと進む既存の機能、そして待望の改良まで、このリリースには誰もが注目するものがあります!

正式リリースまでのつなぎとして、このリリースで我々がもっとも期待している機能強化をそっと覗いてみましょう!

Kubernetes v1.30の主な変更点

動的なリソース割り当てのための構造化パラメーター (KEP-4381)

動的なリソース割り当て(DRA)はv1.26でアルファ機能としてKubernetesに追加されました。 これは、サードパーティリソースへのアクセスを要求するための従来のデバイスプラグインAPIに代わるものを定義しています。 設計上、動的なリソース割り当て(DRA)では、Kubernetesの中心部に完全に不透明なリソースのパラメーターが使用されます。 このアプローチは、クラスターオートスケーラーや、Podのグループ(Jobスケジューラーなど)に対して決定を下す必要がある上位コントローラーにとって問題となります。 時間経過に伴う要求(claim)の割り当てや割り当て解除の効果をシミュレートできないのです。 これを行うための情報は、サードパーティのDRAドライバーのみが保有しています。

動的なリソース割り当て(DRA)の構造化パラメーターは、これらの要求(claim)パラメーターの不透明さがより少ないフレームワークを構築することによって、この問題に対処するための従来の実装の拡張になります。 すべての要求(claim)パラメーターのセマンティクスを自分で処理する代わりに、ドライバーはKubernetesによって事前定義された特定の"構造化モデル"を使用してリソースを記述し、管理できます。 これにより、この"構造化モデル"を認識しているコンポーネントは、サードパーティのコントローラーに委託することなく、これらのリソースに関する意思決定を行えます。 たとえば、スケジューラーは動的なリソース割り当て(DRA)ドライバーとやり取りを行うことなく、要求(claim)を迅速に割り当てることができます。 今回のリリースでは、さまざまな"構造化モデル"を実現するために必要なフレームワークの定義と"名前付きリソース"モデルの実装を中心に作業が行われました。 このモデルでは、個々のリソース・インスタンスをリストアップすることができ、従来のデバイスプラグインAPIと比較して、属性によってそれらのインスタンスを個別に選択する機能が追加されています。

Nodeのメモリスワップのサポート (KEP-2400)

Kubernetes v1.30では、Linux Nodeにおけるメモリスワップのサポートが、システムの安定性を向上させることに重点を置いて、その動作方法に大きな変更が加えられました。 以前のKubernetesバージョンでは、NodeSwapフィーチャーゲートはデフォルトで無効化されており、有効化された場合、デフォルトの動作としてUnlimitedSwap動作が使用されていました。 より良い安定性を達成するために、(Nodeの安定性を損なう可能性のある)UnlimitedSwap動作はv1.30で削除されます。

更新された、まだベータ版のLinux Nodeでのスワップのサポートは、デフォルトで利用できるようになります。 ただし、デフォルトの動作は、NoSwap(UnlimitedSwapではない)モードに設定されたNodeを実行することになります。 NoSwapモードでは、kubeletはスワップ領域が有効化されたNodeでの実行をサポートしますが、Podはページファイルを一切使用しません。 そのNodeでkubeletを実行するには、--fail-swap-on=falseを設定する必要があります。 ただ、大きな変更とはこのことではなく、もう1つのモードであるLimitedSwapです。 このモードでは、kubeletは実際にそのNodeのページファイルを使用し、Podが仮想メモリの一部をページアウトできるようにします。 コンテナ(およびその親Pod)はメモリ制限を超えてスワップにアクセスすることはできませんが、利用可能な場合はスワップ領域を使用できます。

KubernetesのNode Special Interest Group (SIG Node)は、エンドユーザー、貢献者、およびより広いKubernetesコミュニティからのフィードバックに基づいて、改訂された実装の使用方法を理解できるようにドキュメントも更新します。

KubernetesにおけるLinux Nodeのスワップ・サポートの詳細については、前回のブログ記事またはNodeのスワップ・ドキュメントを読んでください。

Podでユーザー名前空間のサポート (KEP-127)

ユーザー名前空間は、2024年1月に公開されたCVE-2024-21626を含むHigh/Criticalと評価された複数のCVEを防止、または緩和するために、Podをより適切に分離するLinux専用の機能です。 Kubernetes 1.30では、ユーザー名前空間のサポートがベータ版に移行し、ボリュームのあるPodとないPod、カスタムUID/GID範囲などがサポートされるようになりました!

構造化された認可設定 (KEP-3221)

構造化された認可設定のサポートはベータ版に移行し、デフォルトで有効になります。 この機能は、失敗時に明示的に拒否するなどのきめ細かな制御を可能にしたり、特定の順序でリクエストを検証する明確に定義されたパラメーターを持つ複数のWebhookによる認可チェーンの作成を可能にします。 設定ファイルのアプローチでは、リクエストがWebhookへ渡される前にCELルールを指定して事前にフィルタリングすることも可能で、不要なリクエストを防ぐのに役立ちます。 また、設定ファイルが変更されると、APIサーバーは自動的に認可チェーンを再読み込みします。

--authorization-configコマンドライン引数を使用して、その認可設定へのパスを指定する必要があります。 設定ファイルの代わりにコマンドラインフラグを使い続けたい場合、そのまま機能し続けます。 複数のWebhook、失敗ポリシー、事前フィルタールールなどの新しい認可Webhook機能にアクセスするには、--authorization-configファイルにオプションを記述するように切り替えます。 Kubernetes 1.30からは、設定ファイルのフォーマットがベータ段階であり、フィーチャーゲートがデフォルトで有効になっているため、--authorization-configを指定する必要があるだけです。 すべての可能な値を含む設定例は、認可ドキュメントで提供されています。 詳細については、認可ドキュメントを読んでください。

コンテナリソースをもとにしたPodの自動スケーリング (KEP-1610)

ContainerResourceメトリクスに基づく水平Pod自動スケーリングは、v1.30で安定版に移行します。 HorizontalPodAutoscalerのこの新しい動作により、Pod全体のリソース使用量ではなく、個々のコンテナのリソース使用量に基づいて自動スケーリングを設定できるようになります。 詳細については以前の記事を参照するか、コンテナリソースメトリクスを読んでください。

アドミッション・コントロールに対するCEL (KEP-3488)

Kubernetesのアドミッション・コントロールにCommon Expression Language (CEL)を統合することで、アドミッション・リクエストを評価するよりダイナミックで表現力豊かな方法が導入されます。 この機能により、複雑できめ細かなポリシーがKubernetes APIを通じて直接定義・適用できるようになり、パフォーマンスや柔軟性を損なうことなく、セキュリティとガバナンスの機能が強化されます。

CELがKubernetesのアドミッション・コントロールに追加されたことで、クラスター管理者はWebhookベースのアクセス・コントローラーに頼ることなく、クラスターの望ましい状態やポリシーに対してAPIリクエストの内容を評価できる複雑なルールを作成できます。 このレベルの制御は、クラスター運用の効率性、セキュリティ、整合性を維持するために極めて重要であり、Kubernetes環境をより堅牢にし、さまざまなユースケースや要件へ適応できるようにします。 アドミッション・コントロールにCELを使用する詳細については、ValidatingAdmissionPolicyのAPIドキュメントを参照してください。

私たちと同じようにこのリリースを楽しみにしていただければ幸いです。数週間後の公式のリリース記事で、さらなるハイライトをお見逃しなく!

CRI-O: OCIレジストリからのseccompプロファイルの適用

seccompはセキュアなコンピューティングモードを意味し、Linuxカーネルのバージョン2.6.12以降の機能として提供されました。 これは、プロセスの特権をサンドボックス化し、ユーザースペースからカーネルへの呼び出しを制限するために使用できます。 Kubernetesでは、ノードに読み込まれたseccompプロファイルをPodやコンテナに自動的に適用することができます。

しかし、Kubernetesでseccompプロファイルを配布することは大きな課題です。 なぜなら、JSONファイルがワークロードが実行可能なすべてのノードで利用可能でなければならないからです。 Security Profiles Operatorなどのプロジェクトは、クラスター内でデーモンとして実行することでこの問題を解決しています。 この設定から、コンテナランタイムがこの配布プロセスの一部を担当できるかどうかが興味深い点です。

通常、ランタイムはローカルパスからプロファイルを適用します。たとえば:

apiVersion: v1
kind: Pod
metadata:
  name: pod
spec:
  containers:
    - name: container
      image: nginx:1.25.3
      securityContext:
        seccompProfile:
          type: Localhost
          localhostProfile: nginx-1.25.3.json

プロファイルnginx-1.25.3.jsonはkubeletのルートディレクトリ内にseccompディレクトリを追加して利用可能でなければなりません。 これは、ディスク上のプロファイルのデフォルトの場所が/var/lib/kubelet/seccomp/nginx-1.25.3.jsonになることを指しています。 プロファイルが利用できない場合、ランタイムは次のようにコンテナの作成に失敗します。

kubectl get pods
NAME   READY   STATUS                 RESTARTS   AGE
pod    0/1     CreateContainerError   0          38s
kubectl describe pod/pod | tail
Tolerations:                 node.kubernetes.io/not-ready:NoExecute op=Exists for 300s
                             node.kubernetes.io/unreachable:NoExecute op=Exists for 300s
Events:
  Type     Reason     Age                 From               Message
  ----     ------     ----                ----               -------
  Normal   Scheduled  117s                default-scheduler  Successfully assigned default/pod to 127.0.0.1
  Normal   Pulling    117s                kubelet            Pulling image "nginx:1.25.3"
  Normal   Pulled     111s                kubelet            Successfully pulled image "nginx:1.25.3" in 5.948s (5.948s including waiting)
  Warning  Failed     7s (x10 over 111s)  kubelet            Error: setup seccomp: unable to load local profile "/var/lib/kubelet/seccomp/nginx-1.25.3.json": open /var/lib/kubelet/seccomp/nginx-1.25.3.json: no such file or directory
  Normal   Pulled     7s (x9 over 111s)   kubelet            Container image "nginx:1.25.3" already present on machine

Localhostプロファイルを手動で配布する必要があるという大きな障害は、多くのエンドユーザーがRuntimeDefaultに戻るか、さらにはUnconfined(seccompが無効になっている)でワークロードを実行することになる可能性が高いということです。

CRI-Oが救世主

KubernetesのコンテナランタイムCRI-Oは、カスタムアノテーションを使用してさまざまな機能を提供しています。 v1.30のリリースでは、アノテーションの新しい集合であるseccomp-profile.kubernetes.cri-o.io/PODseccomp-profile.kubernetes.cri-o.io/<CONTAINER>のサポートが追加されました。 これらのアノテーションを使用すると、以下を指定することができます:

  • 特定のコンテナ用のseccompプロファイルは、次のように使用されます:seccomp-profile.kubernetes.cri-o.io/<CONTAINER> (例:seccomp-profile.kubernetes.cri-o.io/webserver: 'registry.example/example/webserver:v1')
  • Pod内のすべてのコンテナに対するseccompプロファイルは、コンテナ名の接尾辞を使用せず、予約された名前PODを使用して次のように使用されます:seccomp-profile.kubernetes.cri-o.io/POD
  • イメージ全体のseccompプロファイルは、イメージ自体がアノテーションseccomp-profile.kubernetes.cri-o.io/PODまたはseccomp-profile.kubernetes.cri-o.io/<CONTAINER>を含んでいる場合に使用されます

CRI-Oは、ランタイムがそれを許可するように構成されている場合、およびUnconfinedとして実行されるワークロードに対してのみ、そのアノテーションを尊重します。 それ以外のすべてのワークロードは、引き続きsecurityContextからの値を優先して使用します。

アノテーション単体では、プロファイルの配布にはあまり役立ちませんが、それらの参照方法が役立ちます! たとえば、OCIアーティファクトを使用して、通常のコンテナイメージのようにseccompプロファイルを指定できるようになりました。

apiVersion: v1
kind: Pod
metadata:
  name: pod
  annotations:
    seccomp-profile.kubernetes.cri-o.io/POD: quay.io/crio/seccomp:v2
spec: 

イメージquay.io/crio/seccomp:v2には、実際のプロファイル内容を含むseccomp.jsonファイルが含まれています。 ORASSkopeoなどのツールを使用して、イメージの内容を検査できます。

oras pull quay.io/crio/seccomp:v2
Downloading 92d8ebfa89aa seccomp.json
Downloaded  92d8ebfa89aa seccomp.json
Pulled [registry] quay.io/crio/seccomp:v2
Digest: sha256:f0205dac8a24394d9ddf4e48c7ac201ca7dcfea4c554f7ca27777a7f8c43ec1b
jq . seccomp.json | head
{
  "defaultAction": "SCMP_ACT_ERRNO",
  "defaultErrnoRet": 38,
  "defaultErrno": "ENOSYS",
  "archMap": [
    {
      "architecture": "SCMP_ARCH_X86_64",
      "subArchitectures": [
        "SCMP_ARCH_X86",
        "SCMP_ARCH_X32"
# イメージのプレーンマニフェストを調べる
skopeo inspect --raw docker://quay.io/crio/seccomp:v2 | jq .
{
  "schemaVersion": 2,
  "mediaType": "application/vnd.oci.image.manifest.v1+json",
  "config":
    {
      "mediaType": "application/vnd.cncf.seccomp-profile.config.v1+json",
      "digest": "sha256:ca3d163bab055381827226140568f3bef7eaac187cebd76878e0b63e9e442356",
      "size": 3,
    },
  "layers":
    [
      {
        "mediaType": "application/vnd.oci.image.layer.v1.tar",
        "digest": "sha256:92d8ebfa89aa6dd752c6443c27e412df1b568d62b4af129494d7364802b2d476",
        "size": 18853,
        "annotations": { "org.opencontainers.image.title": "seccomp.json" },
      },
    ],
  "annotations": { "org.opencontainers.image.created": "2024-02-26T09:03:30Z" },
}

イメージマニフェストには、特定の必要な構成メディアタイプ(application/vnd.cncf.seccomp-profile.config.v1+json)への参照と、seccomp.jsonファイルを指す単一のレイヤー(application/vnd.oci.image.layer.v1.tar)が含まれています。 それでは、この新機能を試してみましょう!

特定のコンテナやPod全体に対してアノテーションを使用する

CRI-Oは、アノテーションを利用する前に適切に構成する必要があります。 これを行うには、ランタイムの allowed_annotations配列にアノテーションを追加します。 これは、次のようなドロップイン構成/etc/crio/crio.conf.d/10-crun.confを使用して行うことができます:

[crio.runtime]
default_runtime = "crun"

[crio.runtime.runtimes.crun]
allowed_annotations = [
    "seccomp-profile.kubernetes.cri-o.io",
]

それでは、CRI-Oを最新のmainコミットから実行します。 これは、ソースからビルドするか、静的バイナリバンドルを使用するか、プレリリースパッケージを使用することで行うことができます。

これを実証するために、local-up-cluster.shを使って単一ノードのKubernetesクラスターをセットアップし、コマンドラインからcrioバイナリを実行しました。 クラスターが起動して実行されているので、seccomp Unconfinedとして実行されているアノテーションのないPodを試してみましょう:

cat pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: pod
spec:
  containers:
    - name: container
      image: nginx:1.25.3
      securityContext:
        seccompProfile:
          type: Unconfined
kubectl apply -f pod.yaml

ワークロードが起動して実行中です:

kubectl get pods
NAME   READY   STATUS    RESTARTS   AGE
pod    1/1     Running   0          15s

crictlを使用してコンテナを検査しても、seccompプロファイルが適用されていないことがわかります:

export CONTAINER_ID=$(sudo crictl ps --name container -q)
sudo crictl inspect $CONTAINER_ID | jq .info.runtimeSpec.linux.seccomp
null

では、Podを変更して、コンテナにプロファイルquay.io/crio/seccomp:v2を適用します:

apiVersion: v1
kind: Pod
metadata:
  name: pod
  annotations:
    seccomp-profile.kubernetes.cri-o.io/container: quay.io/crio/seccomp:v2
spec:
  containers:
    - name: container
      image: nginx:1.25.3

新しいseccompプロファイルを適用するには、Podを削除して再作成する必要があります。 再作成のみが新しいseccompプロファイルを適用するためです:

kubectl delete pod/pod
pod "pod" deleted
kubectl apply -f pod.yaml
pod/pod created

CRI-Oのログには、ランタイムがアーティファクトを取得したことが示されます:

WARN[…] Allowed annotations are specified for workload [seccomp-profile.kubernetes.cri-o.io]
INFO[…] Found container specific seccomp profile annotation: seccomp-profile.kubernetes.cri-o.io/container=quay.io/crio/seccomp:v2  id=26ddcbe6-6efe-414a-88fd-b1ca91979e93 name=/runtime.v1.RuntimeService/CreateContainer
INFO[…] Pulling OCI artifact from ref: quay.io/crio/seccomp:v2  id=26ddcbe6-6efe-414a-88fd-b1ca91979e93 name=/runtime.v1.RuntimeService/CreateContainer
INFO[…] Retrieved OCI artifact seccomp profile of len: 18853  id=26ddcbe6-6efe-414a-88fd-b1ca91979e93 name=/runtime.v1.RuntimeService/CreateContainer

And the container is finally using the profile:

そして、コンテナは最終的にプロファイルを使用しています:

export CONTAINER_ID=$(sudo crictl ps --name container -q)
sudo crictl inspect $CONTAINER_ID | jq .info.runtimeSpec.linux.seccomp | head
{
  "defaultAction": "SCMP_ACT_ERRNO",
  "defaultErrnoRet": 38,
  "architectures": [
    "SCMP_ARCH_X86_64",
    "SCMP_ARCH_X86",
    "SCMP_ARCH_X32"
  ],
  "syscalls": [
    {

ユーザーが接尾辞/containerを予約名/PODに置き換えると、Pod内のすべてのコンテナに対して同じことが機能します。 たとえば:

apiVersion: v1
kind: Pod
metadata:
  name: pod
  annotations:
    seccomp-profile.kubernetes.cri-o.io/POD: quay.io/crio/seccomp:v2
spec:
  containers:
    - name: container
      image: nginx:1.25.3

コンテナイメージにアノテーションを使用する

特定のワークロードにOCIアーティファクトとしてseccompプロファイルを指定する機能は素晴らしいですが、ほとんどのユーザーはseccompプロファイルを公開されたコンテナイメージに関連付けたいと考えています。 これは、コンテナイメージ自体に適用されるメタデータであるコンテナイメージアノテーションを使用して行うことができます。 たとえば、Podmanを使用して、イメージのビルド中に直接イメージアノテーションを追加することができます:

podman build \
    --annotation seccomp-profile.kubernetes.cri-o.io=quay.io/crio/seccomp:v2 \
    -t quay.io/crio/nginx-seccomp:v2 .

プッシュされたイメージには、そのアノテーションが含まれます:

skopeo inspect --raw docker://quay.io/crio/nginx-seccomp:v2 |
    jq '.annotations."seccomp-profile.kubernetes.cri-o.io"'
"quay.io/crio/seccomp:v2"

そのイメージを使用して、CRI-OのテストPod定義に組み込む場合:

apiVersion: v1
kind: Pod
metadata:
  name: pod
  # Podのアノテーションが設定されていません
spec:
  containers:
    - name: container
      image: quay.io/crio/nginx-seccomp:v2

その後、CRI-Oのログには、イメージのアノテーションが評価され、プロファイルが適用されたことが示されます:

kubectl delete pod/pod
pod "pod" deleted
kubectl apply -f pod.yaml
pod/pod created
INFO[…] Found image specific seccomp profile annotation: seccomp-profile.kubernetes.cri-o.io=quay.io/crio/seccomp:v2  id=c1f22c59-e30e-4046-931d-a0c0fdc2c8b7 name=/runtime.v1.RuntimeService/CreateContainer
INFO[…] Pulling OCI artifact from ref: quay.io/crio/seccomp:v2  id=c1f22c59-e30e-4046-931d-a0c0fdc2c8b7 name=/runtime.v1.RuntimeService/CreateContainer
INFO[…] Retrieved OCI artifact seccomp profile of len: 18853  id=c1f22c59-e30e-4046-931d-a0c0fdc2c8b7 name=/runtime.v1.RuntimeService/CreateContainer
INFO[…] Created container 116a316cd9a11fe861dd04c43b94f45046d1ff37e2ed05a4e4194fcaab29ee63: default/pod/container  id=c1f22c59-e30e-4046-931d-a0c0fdc2c8b7 name=/runtime.v1.RuntimeService/CreateContainer
export CONTAINER_ID=$(sudo crictl ps --name container -q)
sudo crictl inspect $CONTAINER_ID | jq .info.runtimeSpec.linux.seccomp | head
{
  "defaultAction": "SCMP_ACT_ERRNO",
  "defaultErrnoRet": 38,
  "architectures": [
    "SCMP_ARCH_X86_64",
    "SCMP_ARCH_X86",
    "SCMP_ARCH_X32"
  ],
  "syscalls": [
    {

コンテナイメージの場合、アノテーションseccomp-profile.kubernetes.cri-o.ioseccomp-profile.kubernetes.cri-o.io/PODと同様に扱われ、Pod全体に適用されます。 さらに、この機能は、イメージにコンテナ固有のアノテーションを使用する場合にも機能します。 たとえば、コンテナの名前がcontainer1の場合:

skopeo inspect --raw docker://quay.io/crio/nginx-seccomp:v2-container |
    jq '.annotations."seccomp-profile.kubernetes.cri-o.io/container1"'
"quay.io/crio/seccomp:v2"

この機能の素晴らしい点は、ユーザーが特定のコンテナイメージ用のseccompプロファイルを作成し、同じレジストリ内に並べて保存できることです。 イメージをプロファイルにリンクすることで、アプリケーション全体のライフサイクルを通じてそれらを維持する柔軟性が提供されます。

ORASを使用してプロファイルをプッシュする

OCIオブジェクトを作成してseccompプロファイルを含めるには、ORASを使用する場合、もう少し作業が必要です。 将来的には、Podmanなどのツールが全体のプロセスをより簡略化することを期待しています。 現時点では、コンテナレジストリがOCI互換である必要があります。 これはQuay.ioの場合も同様です。 CRI-Oは、seccompプロファイルオブジェクトがコンテナイメージメディアタイプ(application/vnd.cncf.seccomp-profile.config.v1+json)を持っていることを期待していますが、ORASはデフォルトでapplication/vnd.oci.empty.v1+jsonを使用します。 これを実現するために、次のコマンドを実行できます:

echo "{}" > config.json
oras push \
    --config config.json:application/vnd.cncf.seccomp-profile.config.v1+json \
     quay.io/crio/seccomp:v2 seccomp.json

結果として得られるイメージには、CRI-Oが期待するmediaTypeが含まれています。 ORASは単一のレイヤーseccomp.json をレジストリにプッシュします。 プロファイルの名前はあまり重要ではありません。 CRI-Oは最初のレイヤーを選択し、それがseccompプロファイルとして機能するかどうかを確認します。

将来の作業

CRI-OはOCIアーティファクトを通常のファイルと同様に内部で管理しています。 これにより、それらを移動したり、使用されなくなった場合に削除したり、seccompプロファイル以外のデータを利用したりする利点が得られます。 これにより、OCIアーティファクトをベースにしたCRI-Oの将来の拡張が可能になります。 また、OCIアーティファクトの中に複数のレイヤーを持つことを考える上で、seccompプロファイルの積層も可能になります。 v1.30.xリリースではUnconfinedワークロードのみがサポートされているという制限は、将来CRI-Oが解決したい課題です。 セキュリティを損なうことなく、全体的なユーザーエクスペリエンスを簡素化することが、コンテナワークロードにおけるseccompの成功の鍵となるようです。

CRI-Oのメンテナーは、新機能に関するフィードバックや提案を歓迎します! このブログ投稿を読んでいただき、ぜひKubernetesのSlackチャンネル#crioを通じてメンテナーに連絡したり、GitHubリポジトリでIssueを作成したりしてください。

Kubernetesブッククラブを覗く

Kubernetesとそれを取り巻く技術のエコシステム全体を学ぶことは、課題がないわけではありません。 このインタビューでは、AWSのCarlos Santanaさんに、コミュニティベースの学習体験を利用するために、彼がどのようにしてKubernetesブッククラブを作ったのか、その会がどのような活動をするのか、そしてどのようにして参加するのかについて伺います。

KubeCon NA 2023で話すCarlos Santanaさん

Frederico Muñoz (FSM): こんにちはCarlosさん、時間をとってくれてありがとう。 まずはじめに、ご自身のことを少し教えていただけますか?

Carlos Santana (CS): もちろんです。 6年前に本番環境でKubernetesをデプロイした経験が、Knativeに参加するきっかけとなり、その後リリースチームを通じてKubernetesに貢献しました。 アップストリームのKubernetesでの作業は、私がオープンソースで得た最高の経験のひとつです。 過去2年間、AWSのシニア・スペシャリスト・ソリューション・アーキテクトとしての役割で、私は大企業がKubernetes上に内部開発者プラットフォーム(IDP)を構築することを支援してきました。 今後、私のオープンソースへの貢献は、ArgoCrossplaneBackstageのようなCNCFのプロジェクトやCNOEを対象にしています。

ブッククラブの創設

FSM: それであなたがKubernetesに辿り着いたわけですが、その時点でブッククラブを始めた動機は何だったのでしょうか?

CS: Kubernetesブッククラブのアイデアは、TGIKのライブ配信での何気ない提案から生まれました。 私にとって、それは単に本を読むということ以上に、学習コミュニティを作るということでした。 このプラットフォームは知識の源であるだけでなく、特にパンデミックの困難な時期にはサポートシステムでもありました。 この取り組みが、メンバーたちの対処と成長に役立っていることを目の当たりにして、喜ばしいと思っています。 最初の本Production Kubernetesは、2021年3月5日に始めて36週間かかりました。 現在は、1冊の本をカバーするのにそれほど時間はかからず、1週間に1章か2章です。

FSM: Kubernetesブッククラブの仕組みについて教えてください。どのように本を選び、どのように読み進めるのですか?

CS: 私たちは、グループの関心とニーズに基づいて本を共同で選んでいます。 この実践的なアプローチは、メンバー、とくに初心者が複雑な概念をより簡単に理解するのに役立ちます。 毎週2つのシリーズがあり、EMEAのタイムゾーンのものと、私がUSで組織しているものです。 各オーガナイザーは共同ホストと協力してSlack上で本を選び、各章の議論するために、数週間に渡りホストのラインナップを整えます。

FSM: 私の記憶が間違っていなければ、Kubernetesブッククラブは17冊目に突入しています。 物事を活発に保つための秘密のレシピがあるのですか?

CS: ブッククラブを活発で魅力的なものに保つ秘訣は、いくつかの重要な要素にあります。

まず、一貫性が重要です。 休みの日やKubeConのような大きなイベントの時だけミーティングをキャンセルして、定期的なスケジュールを維持するよう努力しています。 この規則性は、メンバーの参加を維持し、信頼できるコミュニティを築くのに役立っています。

次に、セッションを面白く、対話式のものにすることが重要です。 たとえば、ミートアップ中にポップアップ・クイズを頻繁に導入します。これはメンバーの理解度をテストするだけでなく、楽しみの要素も加えています。 このアプローチによって内容の関連性が維持され、理論的な概念が実社会のシナリオでどのように適用されるかをメンバーが理解するのに役立ちます。

ブッククラブで扱うトピック

FSM: 書籍の主なトピックは、Kubernetes、GitOps、セキュリティ、SRE、オブザーバビリティになっています。 これはとくに人気という観点で、Cloud Native Landscapeの反映でしょうか?

CS: 私たちの旅は『Production Kubernetes』から始まり、実用的な本番環境向けのソリューションに焦点を当てる方向性を設定しました。 それ以来、私たちはCNCF Landscapeのさまざまな側面を掘り下げ、異なるテーマに沿って本を揃えています。 各テーマは、それがセキュリティであれ、オブザーバビリティであれ、サービスメッシュであれ、コミュニティ内の関連性と需要にもとづいて選択されています。 たとえば、Kubernetes認定に関する最近のテーマでは、書籍の著者を積極的なホストとして参加させ、彼らの専門知識で議論を充実させました。

FSM: プロジェクトに最近変化があったことは知っています。Cloud Native Community GroupとしてCNCFに統合されたことです。 この変更について少しお話いただけますか?

CS: CNCFはブッククラブをCloud Native Community Groupとして快く受け入れてくれました。 これは私たちの運営を合理化し、影響範囲を拡大する重要な進展です。 この連携はKubernetes Community Days (KCD)のミートアップで使用されているものと同様に、管理機能の強化に役立っています。 現在では、メンバーシップ、イベントのスケジューリング、メーリングリスト、Webカンファレンスの開催、セッションの記録など、より強固な体制が整っています。

FSM: CNCFとの関わりは、この半年間のKubernetesブッククラブの成長やエンゲージメントにどのような影響を与えましたか?

CS: 半年前にCNCFコミュニティの一員になって以来、Kubernetesブッククラブでは大きな定量的な変化を目の当たりにしてきました。 会員数は600人以上に急増し、この間に40以上のイベントを企画・実施することに成功しました。 さらに期待されるのは、1回のイベントに平均30人が参加するという安定した動員数です。 この成長とエンゲージメントは、コミュニティにおける影響やKubernetesブッククラブの影響範囲に関して、私たちのCNCF加盟が肯定的な影響である明確な指標です。

ブッククラブに参加する

FSM: 参加を希望する人は、どうすればいいのでしょうか?

CS: 参加するためには3つの段階があります。

FSM: 素晴らしい、ありがとうございます!最後に何かコメントをお願いします。

CS: Kubernetesブッククラブは、単に本について議論する専門家のグループというだけではなく、それ以上です。 それは、Neependra Khareさん、Eric Smallingさん、Sevi Karakulakさん、Chad M. Crowellさん、そしてWalid (CNJ) Shaariさんの主催と企画を手伝ってくれる素晴らしいボランティアであり、活気のあるコミュニティです。 KubeConで私たちを見て、Kubernetesブッククラブのステッカーをゲットしてください!

Kubernetesでコンテナを別ファイルシステムに格納する設定方法

Kubernetesクラスターの稼働、運用する上でよくある問題は、ディスク容量が不足することです。 ノードがプロビジョニングされる際には、コンテナイメージと実行中のコンテナのために十分なストレージスペースを確保することが重要です。 通常、コンテナランタイム/varに書き込みます。 これは別のパーティションとして、ルートファイルシステム上に配置できます。 CRI-Oはデフォルトで、コンテナとイメージを/var/lib/containersに書き込みますが、containerdはコンテナとイメージを/var/lib/containerdに書き込みます。

このブログ記事では、コンテナランタイムがデフォルトのパーティションとは別にコンテンツを保存する方法に注目したいと思います。 これにより、Kubernetesの設定をより柔軟に行うことができ、デフォルトのファイルシステムはそのままに、コンテナストレージ用に大きなディスクを追加する方法が提供されます。

もう少し説明が必要な領域は、Kubernetesがディスクに書き込む場所/内容です。

Kubernetesディスク使用状況を理解する

Kubernetesには永続(persistent)データと一時(ephemeral)データがあります。 kubeletとローカルのKubernetes固有ストレージのベースパスは設定可能ですが、通常は/var/lib/kubeletと想定されています。 Kubernetesのドキュメントでは、これは時々ルートファイルシステムまたはノードファイルシステムと呼ばれます。 このデータの大部分は、次のようにカテゴリー分けされます。

  • エフェメラルストレージ
  • ログ
  • コンテナランタイム

ルート/ノード・ファイルシステムは/ではなく、/var/lib/kubeletがあるディスクのため、ほとんどのPOSIXシステムとは異なります。

エフェメラルストレージ

Podやコンテナは、動作に一時的または短期的なローカルストレージを必要とする場合があります。 エフェメラルストレージの寿命は個々のPodの寿命を超えず、エフェメラルストレージはPod間で共有することはできません。

ログ

デフォルトでは、Kubernetesは各実行中のコンテナのログを/var/log内のファイルとして保存します。 これらのログは一時的であり、ポッドが実行されている間に大きくなりすぎないようにkubeletによって監視されます。

各ノードのログローテーション設定をカスタマイズしてこれらのログのサイズを管理し、ノードローカルストレージに依存しないためにログの配信を設定することができます(サードパーティーのソリューションを使用)。

コンテナランタイム

コンテナランタイムには、コンテナとイメージのための2つの異なるストレージ領域があります。

  • 読み取り専用レイヤー:イメージは通常、コンテナが実行されている間に変更されないため、読み取り専用レイヤーとして表されます。読み取り専用レイヤーには、複数のレイヤーが組み合わされて単一の読み取り専用レイヤーになることがあります。コンテナがファイルシステムに書き込んでいる場合、コンテナの上にはエフェメラルストレージを提供する薄いレイヤーがあります。

  • 書き込み可能レイヤー:コンテナランタイムによっては、ローカルの書き込みがレイヤー化された書き込みメカニズム(たとえば、Linux上のoverlayfsやWindows上のCimFS)として実装されることがあります。これは書き込み可能レイヤーと呼ばれます。ローカルの書き込みは、コンテナイメージの完全なクローンで初期化された書き込み可能なファイルシステムを使用する場合もあります。これは、ハイパーバイザ仮想化に基づく一部のランタイムで使用されます。

コンテナランタイムのファイルシステムには、読み取り専用レイヤーと書き込み可能レイヤーの両方が含まれます。これはKubernetesドキュメントではimagefsと見なされています。

コンテナランタイムの構成

CRI-O

CRI-Oは、コンテナランタイムが永続データと一時データをどのように保存するかを制御するためのTOML形式のストレージ構成ファイルを使用します。 CRI-Oはストレージライブラリを利用します。 一部のLinuxディストリビューションには、ストレージに関するマニュアルエントリ(man 5 containers-storage.conf)があります。 ストレージの主な設定は、/etc/containers/storage.confにあり、一時データの場所やルートディレクトリを制御することができます。 ルートディレクトリは、CRI-Oが永続データを保存する場所です。

[storage]
# Default storage driver
driver = "overlay"
# Temporary storage location
runroot = "/var/run/containers/storage"
# Primary read/write location of container storage
graphroot = "/var/lib/containers/storage"
  • graphroot
    • コンテナランタイムから保存される永続データを指します
    • SELinuxが有効になっている場合、これは/var/lib/containers/storageと一致させる必要があります
  • runroot
    • コンテナに対する一時的な読み書きアクセスを提供します
    • これは一時ファイルシステムに配置することを推奨します

ここでは、/var/lib/containers/storageに合うようにgraphrootディレクトリのラベルを変更する簡単な方法を紹介します:

semanage fcontext -a -e /var/lib/containers/storage <YOUR-STORAGE-PATH>
restorecon -R -v <YOUR-STORAGE-PATH>

containerd

コンテナランタイムであるcontainerdは、永続データと一時データの保存先を制御するためのTOML形式の構成ファイルを使用します。構成ファイルのデフォルトパスは、/etc/containerd/config.tomlにあります。

containerdストレージの関連フィールドは、rootstateです。

  • root
    • containerdのメタデータのルートディレクトリ
    • デフォルトは/var/lib/containerdです
    • また、OSがそれを要求する場合は、ルートにSELinuxラベルも必要です
  • state
    • containerdの一時データ
    • デフォルトは、/run/containerdです

Kubernetesノードの圧迫による退避

Kubernetesは、コンテナファイルシステムがノードファイルシステムと分離されているかどうかを自動的に検出します。 ファイルシステムを分離する場合、Kubernetesはノードファイルシステムとコンテナランタイムファイルシステムの両方を監視する責任があります。 Kubernetesドキュメントでは、ノードファイルシステムとコンテナランタイムファイルシステムをそれぞれnodefsとimagefsと呼んでいます。 nodefsまたはimagefsのいずれかがディスク容量不足になると、ノード全体がディスク圧迫があると見なされます。 Kubernetesは、まず未使用のコンテナやイメージを削除してスペースを回収し、その後にポッドを追い出すことでスペースを再利用します。 nodefsとimagefsの両方を持つノードでは、kubeletはimagefs上の未使用のコンテナイメージをガベージコレクトし、nodefsからは終了したポッドとそれらのコンテナを削除します。 nodefsのみが存在する場合、Kubernetesのガベージコレクションには、終了したコンテナ、ポッド、そして未使用のイメージが含まれます。

Kubernetesでは、ディスクがいっぱいかどうかを判断するためのより多くの構成が可能です。 kubelet内の退避マネージャーには、関連する閾値を制御するいくつかの構成設定があります。 ファイルシステムの場合、関連する測定値はnodefs.availablenodefs.inodesfreeimagefs.available、およびimagefs.inodesfreeです。 コンテナランタイム用に専用のディスクがない場合、imagefsは無視されます。

ユーザーは、既存のデフォルト値を使用できます:

  • memory.available < 100MiB
  • nodefs.available < 10%
  • imagefs.available < 15%
  • nodefs.inodesFree < 5% (Linuxノード)

Kubernetesでは、kubeletの構成ファイル内のEvictionHardEvictionSoftにユーザー定義の値を設定することができます。

EvictionHard 限界値を定義します。これらの限界値を超えると、Grace Periodなしでポッドが追い出されます。

EvictionSoft 限界値を定義します。これらの限界値を超えると、Grace Periodが設定されたシグナルごとにポッドが追い出されます。

EvictionHardの値を指定すると、デフォルト値が置き換えられます。 したがって、すべてのシグナルを設定することが重要です。

たとえば、次に示すkubeletの設定は、退避シグナルと猶予期間オプションを設定するために使用できます。

apiVersion: kubelet.config.k8s.io/v1beta1
kind: KubeletConfiguration
address: "192.168.0.8"
port: 20250
serializeImagePulls: false
evictionHard:
    memory.available:  "100Mi"
    nodefs.available:  "10%"
    nodefs.inodesFree: "5%"
    imagefs.available: "15%"
    imagefs.inodesFree: "5%"
evictionSoft:
    memory.available:  "100Mi"
    nodefs.available:  "10%"
    nodefs.inodesFree: "5%"
    imagefs.available: "15%"
    imagefs.inodesFree: "5%"
evictionSoftGracePeriod:
    memory.available:  "1m30s"
    nodefs.available:  "2m"
    nodefs.inodesFree: "2m"
    imagefs.available: "2m"
    imagefs.inodesFree: "2m"
evictionMaxPodGracePeriod: 60s

問題点

Kubernetesプロジェクトでは、退避のデフォルト設定を使用するか、退避に関連するすべてのフィールドを設定することをお勧めしています。 デフォルト設定を使用するか、独自のevictionHard設定を指定できます。 シグナルの設定を忘れると、Kubernetesはそのリソースを監視しません。 管理者やユーザーが遭遇する可能性のある一般的な設定ミスの1つは、新しいファイルシステムを/var/lib/containers/storageまたは/var/lib/containerdにマウントすることです。 Kubernetesは別のファイルシステムを検出するため、これを行った場合はimagefs.inodesfreeimagefs.availableが必要に応じて設定に一致していることを確認する必要があります。

もう一つの混乱の領域は、イメージファイルシステムをノードに定義した場合でも、エフェメラルストレージの報告が変わらないことです。 イメージファイルシステム(imagefs)は、コンテナイメージのレイヤーを保存するために使用されます。 コンテナが自分自身のルートファイルシステムに書き込む場合、そのローカルな書き込みはコンテナイメージのサイズには含まれません。 コンテナランタイムがこれらのローカルな変更を保存する場所は、ランタイムによって定義されますが、通常はイメージファイルシステムです。 Pod内のコンテナがファイルシステムをバックエンドとするemptyDirボリュームに書き込んでいる場合、これはノードファイルシステムからスペースを使用します。 kubeletは常に、nodefsで表されるファイルシステムに基づいてエフェメラルストレージの容量と割り当てを報告します。 これは、実際には一時的な書き込みがイメージファイルシステムに行われている場合に混乱の原因となる可能性があります。

今後の課題

KEP-4191に取り組むことで、エフェメラルの報告の制限を解消し、コンテナランタイムにより多くの構成オプションを提供することが期待されています。 この提案では、Kubernetesは書き込み可能なレイヤーが読み取り専用のレイヤー(イメージ)と分離されているかどうかを検出します。 これにより、書き込み可能なレイヤーを含むすべてのエフェメラルストレージを同じディスクに配置することが可能になります。 また、イメージ用に別のディスクを使用することも可能になります。

参加するためにはどうすればよいですか?

参加したい場合は、KubernetesのSIG Nodeに参加することができます。

フィードバックを共有したい場合は、Slackチャンネルの#sig-nodeで行うことができます。 まだそのSlackワークスペースに参加していない場合は、https://slack.k8s.io/から招待状を取得できます。

素晴らしいレビューを提供し、貴重な洞察を共有し、トピックのアイデアを提案してくれたすべてのコントリビューターに特別な感謝を捧げます。

  • Peter Hunt
  • Mrunal Patel
  • Ryan Phillips
  • Gaurav Singh

SIG Releaseスポットライト(リリース・チーム・サブプロジェクト)

リリース・スペシャル・インタレスト・グループ(SIG Release)は、Kubernetesが4ヶ月ごとに最先端の機能とバグ修正でその刃を研ぐ場所です。Kubernetesのような大きなプロジェクトが、新バージョンをリリースするまでのタイムラインをどのように効率的に管理しているのか、またリリースチームの内部はどのようになっているのか、考えたことはありますか?このような疑問に興味がある方、もっと知りたい方、SIG Releaseの仕事に関わりたい方は、ぜひ読んでみてください!

SIG ReleaseはKubernetesの開発と進化において重要な役割を担っています。その主な責任は、Kubernetesの新バージョンのリリースプロセスを管理することです。通常3〜4ヶ月ごとの定期的なリリースサイクルで運営されています。このサイクルの間、Kubernetesリリースチームは他のSIGやコントリビューターと密接に連携し、円滑でうまく調整されたリリースを保証します。これには、リリーススケジュールの計画、コードフリーズとテストフェーズの期限の設定、バイナリ、ドキュメント、リリースノートなどのリリース成果物の作成が含まれます。

さらに読み進める前に、SIG Releaseにはリリース・エンジニアリングとリリース・チームという2つのサブプロジェクトがあることに注意してください。

このブログ記事では、Nitish KumarがSIG Releaseのテクニカル・リーダーであるVerónica López (PlanetScale)にインタビューし、Release Teamサブプロジェクトにスポットライトを当て、リリース・プロセスがどのように見えるか、そして参加する方法について説明します。

  1. 最初の計画から最終的なリリースまで、Kubernetesの新バージョンの典型的なリリースプロセスはどのようなものですか?スムーズなリリースを保証するために使用している特定の方法論やツールはありますか?

    Kubernetesの新バージョンのリリースプロセスは、十分に構造化されたコミュニティ主導の取り組みです。私たちが従う特定の方法論やツールはありませんが、物事を整理しておくための一連の手順を記載したカレンダーはあります。完全なリリースプロセスは次のようになります:

  • リリースチームの立ち上げ: 新しいリリースのさまざまなコンポーネントの管理を担当するKubernetesコミュニティのボランティアを含むリリースチームの結成から始めます。これは通常、前のリリースが終了する前に行われます。チームが結成されると、リリースチームリーダーとブランチマネージャーが通常の成果物のカレンダーを提案する間に、新しいメンバーがオンボードされます。例として、SIG Releaseのリポジトリに作成されたv1.29チーム結成のissueを見てください。コントリビューターがリリースチームの一員になるには、通常リリースシャドウプログラムを通りますが、それがSIG Releaseに参加する唯一の方法というわけではありません。

  • 初期段階: 各リリースサイクルの最初の数週間で、SIG ReleaseはKubernetes機能強化提案(KEPs)で概説された新機能や機能強化の進捗を熱心に追跡します。これらの機能のすべてがまったく新しいものではありませんが、多くの場合、アルファ段階から始まり、その後ベータ段階に進み、最終的には安定したステータスに到達します。

  • 機能の成熟段階: 通常、コミュニティからのフィードバックを集めるため、実験的な新機能を含むアルファ・リリースを2、3回行い、その後、機能がより安定し、バグの修正が中心となるベータ・リリースを2、3回行います。この段階でのユーザーからのフィードバックは非常に重要で、この段階で発生する可能性のあるバグやその他の懸念に対処するために、追加のベータ・リリースを作成しなければならないこともあります。これがクリアされると、実際のリリースの前にリリース候補(RC)を作成します。このサイクルを通じて、リリースノートやユーザーガイドなどのドキュメントの更新や改善に努めます。

  • 安定化段階: 新リリースの数週間前にコードフリーズを実施し、この時点以降は新機能の追加を禁止します。メインリリースと並行して、私たちはKubernetesの古い公式サポートバージョンのパッチを毎月作成し続けているので、Kubernetesバージョンのライフサイクルはその後数ヶ月に及ぶと言えます。完全なリリースサイクル全体を通して、リリースノートやユーザーガイドを含むドキュメントの更新と改善に努めます。

    リリースチームのオンボーディング; 初期段階; 機能の成熟段階; 安定化段階
  1. 各リリースで安定性と新機能の導入のバランスをどのように扱っていますか?どのような基準で、どの機能をリリースに含めるかを決定するのですか?

    終わりのないミッションですが、重要なのは私たちのプロセスとガイドラインを尊重することだと考えています。私たちのガイドラインは、このプロジェクトに豊富な知識と経験をもたらしてくれるコミュニティの何十人ものメンバーから、何時間にもわたって議論とフィードバックを重ねた結果です。もし厳格なガイドラインがなかったら、私たちの注意を必要とするもっと生産的な議題に時間を使う代わりに、同じ議論を何度も繰り返してしまうでしょう。すべての重要な例外は、チームメンバーの大半の合意を必要とするため、品質を確保することができます。

    何がリリースになるかを決定するプロセスは、リリースチームがワークフローを引き継ぐずっと前から始まっています。各SIGと経験豊富なコントリビューターが、機能や変更を含めるかどうかを決定します。その後、リリースチームが、それらの貢献がドキュメント、テスト、後方互換性などの要件を満たしていることを確認し、正式に許可します。同様のプロセスは月例パッチリリースのチェリーピックでも行われ、完全なKEPを必要とするPRや、影響を受けるすべてのブランチを含まない修正は受け入れないという厳しいポリシーがあります。

  2. Kubernetesの開発とリリース中に遭遇した最も大きな課題は何ですか?これらの課題をどのように克服しましたか?

    リリースのサイクルごとに、さまざまな課題が発生します。新たに発見されたCVE(Common Vulnerabilities and Exposures)のような土壇場の問題に取り組んだり、内部ツール内のバグを解決したり、以前のリリースの機能によって引き起こされた予期せぬリグレッションに対処したりすることもあります。私たちがしばしば直面するもう1つの障害は、私たちのチームは大規模ですが、私たちのほとんどがボランティアベースで貢献していることです。時には人手が足りないと感じることもありますが、私たちは常に組織化し、うまくやりくりしています。

  3. 新しい貢献者として、SIG Releaseに参加するための理想的な道はどのようなものでしょうか?誰もが自分のタスクに忙殺されているコミュニティで、効果的に貢献するために適切なタスクを見つけるにはどうすればいいのでしょうか?

    オープンソースコミュニティへの関わり方は人それぞれです。SIG Releaseは、リリースを出荷できるように自分たちでツールを書くという、自分勝手なチームです。SIG K8s Infraのような他のSIGとのコラボレーションも多いのですが、私たちが使用するツールはすべて、コストを削減しつつ、私たちの大規模な技術的ニーズに合わせて作られたものでなければなりません。このため、「単に」リリースを作成するだけでなく、さまざまなタイプのプロジェクトを手伝ってくれるボランティアを常に探しています。

    私たちの現在のプロジェクトでは、Goプログラミング、Kubernetes内部の理解、Linuxパッケージング、サプライチェーンセキュリティ、テクニカルライティング、一般的なオープンソースプロジェクトのメンテナンスなどのスキルが必要です。このスキルセットは、プロジェクトの成長とともに常に進化しています。

    理想的な道筋として、私たちはこう提案します:

    • どのように機能が管理されているか、リリースカレンダー、リリースチームの全体的な構造など、コードに慣れる。
    • Slack(#sig-release)などのKubernetesコミュニティのコミュニケーションチャンネルに参加する。
    • コミュニティ全員が参加できるSIG Releaseウィークリーミーティングに参加する。これらのミーティングに参加することは、あなたのスキルセットや興味に関連すると思われる進行中のプロジェクトや将来のプロジェクトについて学ぶ素晴らしい方法です。

    経験豊富な貢献者は皆、かつてあなたのような立場にあったことを忘れないでください。遠慮せずに質問し、議論に参加し、貢献するための小さな一歩を踏み出しましょう。

    SIG Releaseに関する質問
  4. リリースシャドウプログラムとは何ですか?また、他の様々なSIGに含まれるシャドウプログラムとの違いは何ですか?

    リリースシャドウプログラムは、Kubernetesのリリースサイクルを通して、リリースチームの経験豊富なメンバーをシャドウイングする機会を提供します。これは、Kubernetesのリリースに必要な、サブチームにまたがるすべての困難な仕事を見るまたとないチャンスです。多くの人は、私たちの仕事は3ヶ月ごとにリリースを切ることだけだと思っていますが、それは氷山の一角にすぎません。

    私たちのプログラムは通常、特定のKubernetesリリースサイクルに沿っており、それは約3ヶ月の予測可能なタイムラインを持っています。このプログラムではKubernetesの新機能を書くことはありませんが、リリースチームは新リリースと何千人ものコントリビューターとの最後のステップであるため、高い責任感が求められます。

  5. 一般的に、次のKubernetesリリースのリリースシャドウ/リリースリードとしてボランティアに参加する人に求める資格は何ですか?

    どの役割もある程度の技術的能力を必要としますが、Goの実践的な経験やKubernetes APIに精通していることを必要とするものもあれば、技術的な内容を明確かつ簡潔に伝えるのが得意な人を必要とするものもあります。技術的な専門知識よりも、熱意とコミットメントを重視しています。もしあなたが正しい姿勢を持っていて、Kubernetesやリリース・エンジニアリングの仕事を楽しんでいることが伝われば、たとえそれがあなたが余暇を利用して立ち上げた個人的なプロジェクトであったとしても、チームは必ずあなたを指導します。セルフスターターであること、そして質問をすることを恐れないことは、私たちのチームであなたを大きく前進させます。

  6. リリースシャドープログラムに何度も不合格になった人に何を勧めますか?

    応募し続けることです。

    リリースサイクルごとに応募者数が飛躍的に増えているため、選ばれるのが難しくなり、落胆することもありますが、不採用になったからといって、あなたに才能がないというわけではないことを知っておいてください。すべての応募者を受け入れることは現実的に不可能です、しかし、ここに私たちが提案する代替案があります。:

    毎週開催されるKubernetes SIGのリリースミーティングに参加して、自己紹介をし、チームや私たちが取り組んでいるプロジェクトに慣れてください。

    リリースチームはSIG Releaseに参加する方法の1つですが、私たちは常に手伝ってくれる人を探しています。繰り返しになりますが、一定の技術的な能力に加えて、私たちが最も求めている特性は、信頼できる人であり、それには時間が必要です。

    SIG Releaseのモチベーション
  7. リリースチームがKubernetes v1.28に特に期待している進行中の取り組みや今後の機能について教えてください。これらの進歩は、Kubernetesの長期的なビジョンとどのように整合しているのでしょうか?

    Kubernetesのパッケージをコミュニティインフラ上でついに公開できることに興奮しています。数年前からやりたいと思っていたことですが、移行する前に整えなければならない技術的な意味合いが多いプロジェクトです。それが終われば、生産性を向上させ、ワークフロー全体をコントロールできるようになります。

最後に

さて、この対談はここで終わりですが、学習はこれで終わりではありません。このインタビューが、SIG Releaseが何をしているのか、そしてどのように手助けを始めたらいいのか、ある程度わかっていただけたと思います。重要なこととして、この記事はSIG Releaseの最初のサブプロジェクトであるリリース・チームを取り上げています。次回のSIG Releaseのスポットライトブログでは、Release Engineeringサブプロジェクトにスポットライトを当て、その活動内容や参加方法について紹介します。最後に、SIG Releaseの運営方法についてより深く理解するために、SIG Release憲章をご覧ください。

フォレンジックコンテナ分析

前回投稿したKubernetesにおけるフォレンジックコンテナチェックポイント処理では、Kubernetesでのチェックポイントの作成や、それがどのようにセットアップされ、どのように使用されるのかを紹介しました。 機能の名前はフォレンジックコンテナチェックポイントですが、Kubernetesによって作成されたチェックポイントの実際の分析方法については、詳細を説明しませんでした。 この記事では、チェックポイントがどのように分析されるのかについての詳細を提供します。

チェックポイントの作成はまだKubernetesでalpha機能であり、この記事ではその機能が将来どのように動作するのかについてのプレビューを提供します。

準備

チェックポイント作成のサポートを有効にするためのKubernetesの設定方法や、基盤となるCRI実装方法についての詳細はKubernetesにおけるフォレンジックコンテナチェックポイント処理を参照してください。

一例として、この記事内でチェックポイントを作成し分析するコンテナイメージ(quay.io/adrianreber/counter:blog)を準備しました。 このコンテナはコンテナ内でファイルを作成することができ、後でチェックポイント内で探したい情報をメモリーに格納しておくこともできます。

コンテナを実行するためにはPodが必要であり、この例では下記のPodマニフェストを使用します。

apiVersion: v1
kind: Pod
metadata:
  name: counters
spec:
  containers:
  - name: counter
    image: quay.io/adrianreber/counter:blog

この結果、counterと呼ばれるコンテナがcountersと呼ばれるPod内で実行されます。

一度コンテナが実行されると、コンテナで下記アクションが行えます。

$ kubectl get pod counters --template '{{.status.podIP}}'
10.88.0.25
$ curl 10.88.0.25:8088/create?test-file
$ curl 10.88.0.25:8088/secret?RANDOM_1432_KEY
$ curl 10.88.0.25:8088

最初のアクセスはコンテナ内でtest-fileという内容でtest-fileと呼ばれるファイルを作成します。 次のアクセスで、コンテナのメモリー内のどこかにシークレット情報(RANDOM_1432_KEY)を記憶します。 最後のアクセスは内部のログファイルに1行追加するだけです。

チェックポイントを分析する前の最後のステップは、チェックポイントを作成することをKubernetesに指示することです。 前回の記事で説明したように、これにはkubelet限定のチェックポイントAPIエンドポイントへのアクセスを必要とします。

default名前空間内のcountersという名前のPod内のcounterという名前のコンテナに対して、kubelet APIエンドポイントが次の場所で到達可能です。

# Podが実行されているNode上で実行する
curl -X POST "https://localhost:10250/checkpoint/default/counters/counter"

厳密には、kubeletの自己署名証明書を許容しkubelet チェックポイントAPIの使用を認可するために、下記のcurlコマンドのオプションが必要です。

--insecure --cert /var/run/kubernetes/client-admin.crt --key /var/run/kubernetes/client-admin.key

チェックポイントの作成が終了すると、/var/lib/kubelet/checkpoints/checkpoint-<pod-name>_<namespace-name>-<container-name>-<timestamp>.tarでチェックポイントが利用可能になります。

この記事の後述のステップでは、チェックポイントアーカイブを分析する際にcheckpoint.tarという名前を使用します。

checkpointctlを使用したチェックポイントアーカイブの分析

チェックポイントが作成したコンテナに関するいくつかの初期情報を得るためには、このようにcheckpointctlを使用します。

$ checkpointctl show checkpoint.tar --print-stats
+-----------+----------------------------------+--------------+---------+---------------------+--------+------------+------------+-------------------+
| CONTAINER |              IMAGE               |      ID      | RUNTIME |       CREATED       | ENGINE |     IP     | CHKPT SIZE | ROOT FS DIFF SIZE |
+-----------+----------------------------------+--------------+---------+---------------------+--------+------------+------------+-------------------+
| counter   | quay.io/adrianreber/counter:blog | 059a219a22e5 | runc    | 2023-03-02T06:06:49 | CRI-O  | 10.88.0.23 | 8.6 MiB    | 3.0 KiB           |
+-----------+----------------------------------+--------------+---------+---------------------+--------+------------+------------+-------------------+
CRIU dump statistics
+---------------+-------------+--------------+---------------+---------------+---------------+
| FREEZING TIME | FROZEN TIME | MEMDUMP TIME | MEMWRITE TIME | PAGES SCANNED | PAGES WRITTEN |
+---------------+-------------+--------------+---------------+---------------+---------------+
| 100809 us     | 119627 us   | 11602 us     | 7379 us       |          7800 |          2198 |
+---------------+-------------+--------------+---------------+---------------+---------------+

これによって、チェックポイントアーカイブ内のチェックポイントについてのいくつかの情報が、すでに取得できています。 コンテナの名前やコンテナランタイムやコンテナエンジンについての情報を見ることができます。 チェックポイントのサイズ(CHKPT SIZE)もリスト化されます。 これは大部分がチェックポイントに含まれるメモリーページのサイズですが、コンテナ内の全ての変更されたファイルのサイズ(ROOT FS DIFF SIZE)についての情報もあります。

追加のパラメーター--print-statsはチェックポイントアーカイブ内の情報を復号化し、2番目のテーブル(CRIU dump statistics)で表示します。 この情報はチェックポイント作成中に収集され、CRIUがコンテナ内のプロセスをチェックポイントするために必要な時間と、チェックポイント作成中に分析され書き込まれたメモリーページ数の概要を示します。

より深く掘り下げる

checkpointctlの助けを借りて、チェックポイントアーカイブについてのハイレベルな情報を得ることができます。 チェックポイントアーカイブをさらに分析するには、それを展開する必要があります。 チェックポイントアーカイブはtarアーカイブであり、tar xf checkpoint.tarの助けを借りて展開可能です。

チェックポイントアーカイブを展開すると、下記のファイルやディレクトリが作成されます。

  • bind.mounts - このファイルにはバインドマウントについての情報が含まれており、復元中に全ての外部ファイルとディレクトリを正しい場所にマウントするために必要になります。
  • checkpoint/ - このディレクトリにはCRIUによって作成された実際のチェックポイントが含まれています。
  • config.dumpspec.dump - これらのファイルには、復元中に必要とされるコンテナについてのメタデータが含まれています。
  • dump.log - このファイルにはチェックポイント作成中に作成されたCRIUのデバッグ出力が含まれています。
  • stats-dump - このファイルには、checkpointctl--print-statsでダンプ統計情報を表示するために使用するデータが含まれています。
  • rootfs-diff.tar - このファイルには、コンテナのファイルシステム上で変更された全てのファイルが含まれています。

ファイルシステムの変更 - rootfs-diff.tar

コンテナのチェックポイントをさらに分析するための最初のステップは、コンテナ内で変更されたファイルを見ることです。 これはrootfs-diff.tarファイルを参照することで行えます。

$ tar xvf rootfs-diff.tar
home/counter/logfile
home/counter/test-file

これでコンテナ内で変更されたファイルを調べられます。

$ cat home/counter/logfile
10.88.0.1 - - [02/Mar/2023 06:07:29] "GET /create?test-file HTTP/1.1" 200 -
10.88.0.1 - - [02/Mar/2023 06:07:40] "GET /secret?RANDOM_1432_KEY HTTP/1.1" 200 -
10.88.0.1 - - [02/Mar/2023 06:07:43] "GET / HTTP/1.1" 200 -
$ cat home/counter/test-file
test-file 

このコンテナのベースになっているコンテナイメージ(quay.io/adrianreber/counter:blog)と比較すると、コンテナが提供するサービスへの全てのアクセス情報を含んだlogfileや予想通り作成されたtest-fileファイルを確認することができます。

rootfs-diff.tarの助けを借りることで、作成または変更された全てのファイルを、コンテナのベースイメージと比較して検査することが可能です。

チェックポイント処理したプロセスを分析する - checkpoint/

ディレクトリcheckpoint/はコンテナ内でプロセスをチェックポイントしている間にCRIUによって作成されたデータを含んでいます。 ディレクトリcheckpoint/の内容は、CRIUの一部として配布されているCRITツールを使用して分析できるさまざまなイメージファイルで構成されています。

まず、コンテナの内部プロセスの概要を取得してみましょう。

$ crit show checkpoint/pstree.img | jq .entries[].pid
1
7
8

この出力はコンテナのPID名前空間の内部に3つのプロセス(PIDが1と7と8)があることを意味しています。

これはコンテナのPID名前空間の内部からの視界を表示しているだけです。 復元中に正確にそれらのPIDが再作成されます。 コンテナのPID名前空間の外部からPIDは復元後に変更されます。

次のステップは、それらの3つのプロセスについての追加情報を取得することです。

$ crit show checkpoint/core-1.img | jq .entries[0].tc.comm
"bash"
$ crit show checkpoint/core-7.img | jq .entries[0].tc.comm
"counter.py"
$ crit show checkpoint/core-8.img | jq .entries[0].tc.comm
"tee"

これは、コンテナ内の3つのプロセスがbashcounter.py(Pythonインタプリター)とteeであることを意味しています。 プロセスの親子関係についての詳細は、checkpoint/pstree.imgに分析するデータがさらにあります。

ここまでで収集した情報をまだ実行中のコンテナと比較してみましょう。

$ crictl inspect --output go-template --template "{{(index .info.pid)}}" 059a219a22e56
722520
$ ps auxf | grep -A 2 722520
fedora    722520  \_ bash -c /home/counter/counter.py 2>&1 | tee /home/counter/logfile
fedora    722541      \_ /usr/bin/python3 /home/counter/counter.py
fedora    722542      \_ /usr/bin/coreutils --coreutils-prog-shebang=tee /usr/bin/tee /home/counter/logfile
$ cat /proc/722520/comm
bash
$ cat /proc/722541/comm
counter.py
$ cat /proc/722542/comm
tee

この出力では、まずコンテナ内の最初のプロセスのPIDを取得しています。 そしてコンテナを実行しているシステム上で、そのPIDと子プロセスを探しています。 3つのプロセスが表示され、最初のものはコンテナPID名前空間の中でPID 1である"bash"です。 次に/proc/<PID>/commを見ると、チェックポイントイメージと正確に同じ値を見つけることができます。

覚えておく重要なことは、チェックポイントはコンテナのPID名前空間内の視界が含まれていることです。 なぜなら、これらの情報はプロセスを復元するために重要だからです。

critがコンテナについて教えてくれる最後の例は、UTS名前空間に関する情報です。

$ crit show checkpoint/utsns-12.img
{
    "magic": "UTSNS",
    "entries": [
        {
            "nodename": "counters",
            "domainname": "(none)"
        }
    ]
}

UTS名前空間内のホストネームがcountersであることを教えてくれます。

チェックポイント作成中に収集された各リソースCRIUについて、checkpoint/ディレクトリは対応するイメージファイルを含んでいます。 このイメージファイルはcritを使用することで分析可能です。

メモリーページを見る

CRITを使用して復号化できるCRIUからの情報に加えて、CRIUがディスクに書き込んだ生のメモリーページを含んでいるファイルもあります。

$ ls  checkpoint/pages-*
checkpoint/pages-1.img  checkpoint/pages-2.img  checkpoint/pages-3.img

最初にコンテナを使用した際に、メモリー内のどこかにランダムキー(RANDOM_1432_KEY)を保存しました。 見つけることができるかどうか見てみましょう。

$ grep -ao RANDOM_1432_KEY checkpoint/pages-*
checkpoint/pages-2.img:RANDOM_1432_KEY

そして実際に、私のデータがあります。 この方法で、コンテナ内のプロセスの全てのメモリーページの内容を簡単に見ることができます。 しかし、チェックポイントアーカイブにアクセスできるなら誰でも、コンテナのプロセスのメモリー内に保存された全ての情報にアクセスできることを覚えておくことも重要です。

さらなる分析のためにgdbを使用する

チェックポイントイメージを見るための他の方法はgdbです。 CRIUリポジトリは、チェックポイントをコアダンプファイルに変換するcoredumpスクリプトを含んでいます。

$ /home/criu/coredump/coredump-python3
$ ls -al core*
core.1  core.7  core.8

coredump-python3スクリプトを実行すると、チェックポイントイメージがコンテナ内の各プロセスに対し1つのコアダンプファイルに変換されます。 gdbを使用してプロセスの詳細を見ることもできます。

$ echo info registers | gdb --core checkpoint/core.1 -q

[New LWP 1]

Core was generated by `bash -c /home/counter/counter.py 2>&1 | tee /home/counter/logfile'.

#0  0x00007fefba110198 in ?? ()
(gdb)
rax            0x3d                61
rbx            0x8                 8
rcx            0x7fefba11019a      140667595587994
rdx            0x0                 0
rsi            0x7fffed9c1110      140737179816208
rdi            0xffffffff          4294967295
rbp            0x1                 0x1
rsp            0x7fffed9c10e8      0x7fffed9c10e8
r8             0x1                 1
r9             0x0                 0
r10            0x0                 0
r11            0x246               582
r12            0x0                 0
r13            0x7fffed9c1170      140737179816304
r14            0x0                 0
r15            0x0                 0
rip            0x7fefba110198      0x7fefba110198
eflags         0x246               [ PF ZF IF ]
cs             0x33                51
ss             0x2b                43
ds             0x0                 0
es             0x0                 0
fs             0x0                 0
gs             0x0                 0

この例では、チェックポイント中の全てのレジストリの値を見ることができ、コンテナのPID 1のプロセスの完全なコマンドライン(bash -c /home/counter/counter.py 2>&1 | tee /home/counter/logfile)を見ることもできます。

まとめ

コンテナチェックポイントを作成することで、コンテナを停止することやチェックポイントが作成されたことを知ることなく、実行中のコンテナのチェックポイントを作成することが可能です。 Kubernetesにおいてコンテナのチェックポイントを作成した結果がチェックポイントアーカイブです。 checkpointctltarcritgdbのような異なるツールを使用して、チェックポイントを分析できます。 grepのようなシンプルなツールでさえ、チェックポイントアーカイブ内の情報を見つけることが可能です。

この記事で示したチェックポイントの分析方法のさまざまな例は出発点にすぎません。 この記事ではチェックポイントの分析を始める方法を紹介しましたが、要件によってはかなり詳細に特定の物事を見ることも可能です。

参加するためにはどうすればよいですか?

SIG Nodeにはいくつかの方法でアクセスできます。

Kubernetes 1.26: PodDisruptionBudgetによって保護された不健全なPodに対する退避ポリシー

アプリケーションの中断がその可用性に影響を与えないようにすることは、簡単な作業ではありません。 先月リリースされたKubernetes v1.26では、PodDisruptionBudget (PDB) に 不健全なPodの退避ポリシー を指定して、ノード管理操作中に可用性を維持できるようになりました。 この記事では、アプリケーション所有者が中断をより柔軟に管理できるようにするために、PDBにどのような変更が導入されたのかを詳しく説明します。

これはどのような問題を解決しますか?

APIによって開始されるPodの退避では、PodDisruptionBudget(PDB)が考慮されます。 これは、退避によるPodへの自発的な中断の要求は保護されたアプリケーションを中断してはならず、 PDBの.status.currentHealthy.status.desiredHealthyを下回ってはいけないことを意味します。 Unhealthyな実行中のPodはPDBステータスにはカウントされませんが、 これらの退避はアプリケーションが中断されない場合にのみ可能です。 これにより、中断されたアプリケーションやまだ開始されていないアプリケーションが、退避によって追加のダウンタイムが発生することなく、できるだけ早く可用性を達成できるようになります。

残念ながら、これは手動の介入なしでノードをドレインしたいクラスター管理者にとって問題を引き起こします。 (バグまたは構成ミスにより)PodがCrashLoopBackOff状態になっているアプリケーション、または単に準備ができていないPodがあるアプリケーションが誤動作している場合、このタスクはさらに困難になります。 アプリケーションのすべてのPodが正常でない場合、PDBの違反により退避リクエストは失敗します。その場合、ノードのドレインは進行できません。

一方で、次の目的で従来の動作に依存するユーザーもいます。

  • 基盤となるリソースまたはストレージを保護しているPodの削除によって引き起こされるデータ損失を防止する
  • アプリケーションに対して可能な限り最高の可用性を実現する

Kubernetes 1.26では、PodDisruptionBudget APIに新しい実験的フィールド.spec.unhealthyPodEvictionPolicyが導入されました。 このフィールドを有効にすると、これらの要件の両方をサポートできるようになります。

どのように機能しますか?

APIによって開始される退避は、Podの安全な終了をトリガーするプロセスです。 このプロセスは、APIを直接呼び出すか、kubectl drainコマンドを使用するか、クラスター内の他のアクターを使用して開始できます。 このプロセス中に、十分な数のPodが常にクラスター内で実行されていることを確認するために、すべてのPodの削除が適切なPDBと照合されます。

次のポリシーにより、PDBの作成者は、プロセスが不健全なPodを処理する方法をより詳細に制御できるようになります。

IfHealthyBudgetAlwaysAllowの2つのポリシーから選択できます。

前者のIfHealthyBudgetは、従来の動作に従って、デフォルトで得られる最高の可用性を実現します。 不健全なPodは、アプリケーションが利用可能な最小数の.status.desiredHealthyだけPodがある場合にのみ中断できます。

PDBのspec.unhealthyPodEvictionPolicyフィールドをAlwaysAllowに設定することにより、アプリケーションにとってベストエフォートの可用性を選択することになります。 このポリシーを使用すると、不健全なPodをいつでも削除できます。これにより、クラスターの保守とアップグレードが容易になります。

多くの場合、AlwaysAllowがより良い選択であると考えられますが、一部の重要なワークロードでは、 不健全なPodであってもノードドレインやAPIによって開始される他の形式の退避から保護する方が望ましい場合もあります。

どのように利用できますか?

これはアルファ機能であるため、kube-apiserverに対してコマンドライン引数--feature-gates=PDBUnhealthyPodEvictionPolicy=trueを指定して PDBUnhealthyPodEvictionPolicyフィーチャーゲートを有効にする必要があります。

ここに例を示します。クラスターでフィーチャーゲートを有効にし、プレーンなWebサーバーを実行するDeploymentをすでに定義していると仮定します。 そのDeploymentのPodにapp: nginxというラベルを付けました。 回避可能な中断を制限したいと考えており、このアプリにはベストエフォートの可用性で十分であることがわかっています。 WebサーバーのPodが不健全な場合でも、退避を許可することにしました。 不健全なPodを排除するためのAlwaysAllowポリシーを使用して、このアプリケーションを保護するPDBを作成します。

apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
  name: nginx-pdb
spec:
  selector:
    matchLabels:
      app: nginx
  maxUnavailable: 1
  unhealthyPodEvictionPolicy: AlwaysAllow

もっと学ぶには?

どうすれば参加できますか?

フィードバックがある場合は、Slackの#sig-apps チャンネル(必要な場合は https://slack.k8s.io/ にアクセスして招待を受けてください)、またはSIG Appsメーリングリストにご連絡ください。kubernetes-sig-apps@googlegroups.com

Kubernetesにおけるフォレンジックコンテナチェックポイント処理

フォレンジックコンテナチェックポイント処理はCheckpoint/Restore In Userspace (CRIU)に基づいており、コンテナがチェックポイントされていることを認識することなく、実行中のコンテナのステートフルコピーを作成することができます。 コンテナのコピーは、元のコンテナに気づかれることなく、サンドボックス環境で複数回の分析やリストアが可能です。 フォレンジックコンテナチェックポイント処理はKubernetes v1.25でalpha機能として導入されました。

どのように機能しますか?

CRIUを使用してコンテナのチェックポイントやリストアを行うことが可能です。 CRIUはruncやcrun、CRI-O、containerdと統合されており、Kubernetesで実装されているフォレンジックコンテナチェックポイント処理は、既存のCRIU統合を使用します。

なぜ重要なのか?

CRIUと対応する統合機能を使用することで、後でフォレンジック分析を行うために、ディスク上で実行中のコンテナに関する全ての情報と状態を取得することが可能です。 フォレンジック分析は、疑わしいコンテナを停止したり影響を与えることなく検査するために重要となる場合があります。 コンテナが本当に攻撃を受けている場合、攻撃者はコンテナを検査する処理を検知するかもしれません。 チェックポイントを取得しサンドボックス環境でコンテナを分析することは、元のコンテナや、おそらく攻撃者にも検査を認識されることなく、コンテナを検査することができる可能性があります。

フォレンジックコンテナチェックポイント処理のユースケースに加えて、内部状態を失うことなく、あるノードから他のノードにコンテナを移行することも可能です。 特に初期化時間の長いステートフルコンテナの場合、チェックポイントからリストアすることは再起動後の時間が節約されるか、起動時間がより早くなる可能性があります。

コンテナチェックポイント処理を利用するには?

機能はフィーチャーゲートで制限されているため、新しい機能を使用する前にContainerCheckpointを有効にしてください。

ランタイムがコンテナチェックポイント処理をサポートしている必要もあります。

  • containerd: サポートは現在検討中です。詳細はcontainerdプルリクエスト#6965を見てください。
  • CRI-O: v1.25はフォレンジックコンテナチェックポイント処理をサポートしています。

CRI-Oでの使用例

CRI-Oとの組み合わせでフォレンジックコンテナチェックポイント処理を使用するためには、ランタイムをコマンドラインオプション--enable-criu-support=trueで起動する必要があります。 Kubernetesでは、ContainerCheckpointフィーチャーゲートを有効にしたクラスターを実行する必要があります。 チェックポイント処理の機能はCRIUによって提供されているため、CRIUをインストールすることも必要となります。 通常、runcやcrunはCRIUに依存しているため、自動的にインストールされます。

執筆時点ではチェックポイント機能はCRI-OやKubernetesにおいてalpha機能としてみなされており、セキュリティ影響がまだ検討中であることに言及することも重要です。

コンテナとPodが実行されると、チェックポイントを作成することが可能になります。 チェックポイント処理kubeletレベルでのみ公開されています。 コンテナをチェックポイントするためには、コンテナが実行されているノード上でcurlを実行し、チェックポイントをトリガーします。

curl -X POST "https://localhost:10250/checkpoint/namespace/podId/container"

default名前空間内のcountersと呼ばれるPod内のcounterと呼ばれるコンテナに対し、kubelet APIエンドポイントが次の場所で到達可能です。

curl -X POST "https://localhost:10250/checkpoint/default/counters/counter"

厳密には、kubeletの自己署名証明書を許容し、kubeletチェックポイントAPIの使用を認可するために、下記のcurlコマンドのオプションが必要です。

--insecure --cert /var/run/kubernetes/client-admin.crt --key /var/run/kubernetes/client-admin.key

このkubelet APIが実行されると、CRI-Oからチェックポイントの作成をリクエストします。 CRI-Oは低レベルランタイム(例えばrunc)からチェックポイントをリクエストします。 そのリクエストを確認すると、runcは実際のチェックポイントを行うためにcriuツールを呼び出します。

チェックポイント処理が終了すると、チェックポイントは/var/lib/kubelet/checkpoints/checkpoint-<pod-name>_<namespace-name>-<container-name>-<timestamp>.tarで利用可能になります。

その後、そのtarアーカイブを使用してコンテナを別の場所にリストアできます。

Kubernetesの外部でチェックポイントしたコンテナをリストアする(CRI-Oを使用)

チェックポイントtarアーカイブを使用すると、CRI-Oのサンドボックスインスタンス内のKubernetesの外部にコンテナをリストア可能です。 リストア中のより良いユーザエクスペリエンスのために、main CRI-O GitHubブランチからCRI-Oのlatestバージョンを使用することを推奨します。 CRI-O v1.25を使用している場合、コンテナを開始する前にKubernetesが作成する特定のディレクトリを手動で作成する必要があります。

Kubernetesの外部にコンテナをリストアするための最初のステップは、crictlを使用してPodサンドボックスを作成することです。

crictl runp pod-config.json

次に、さきほどチェックポイントしたコンテナを新しく作成したPodサンドボックスにリストアします。

crictl create <POD_ID> container-config.json pod-config.json

container-config.jsonのレジストリでコンテナイメージを指定する代わりに、前に作成したチェックポイントアーカイブへのパスを指定する必要があります。

{
  "metadata": {
      "name": "counter"
  },
  "image":{
      "image": "/var/lib/kubelet/checkpoints/<checkpoint-archive>.tar"
  }
}

次に、そのコンテナを開始するためにcrictl start <CONTAINER_ID>を実行すると、さきほどチェックポイントしたコンテナのコピーが実行されているはずです。

Kubernetes内でチェックポイントしたコンテナをリストアする

先ほどチェックポイントしたコンテナをKubernetes内で直接リストアするためには、レジストリにプッシュできるイメージにチェックポイントアーカイブを変換する必要があります。

ローカルのチェックポイントアーカイブを変換するための方法として、buildahを使用した下記のステップが考えられます。

newcontainer=$(buildah from scratch)
buildah add $newcontainer /var/lib/kubelet/checkpoints/checkpoint-<pod-name>_<namespace-name>-<container-name>-<timestamp>.tar /
buildah config --annotation=io.kubernetes.cri-o.annotations.checkpoint.name=<container-name> $newcontainer
buildah commit $newcontainer checkpoint-image:latest
buildah rm $newcontainer

出来上がったイメージは標準化されておらず、CRI-Oとの組み合わせでのみ動作します。 このイメージはalphaにも満たないフォーマットであると考えてください。 このようなチェックポイントイメージのフォーマットを標準化するための議論が進行中です。 これはまだ標準化されたイメージフォーマットではなく、CRI-Oを--enable-criu-support=trueで起動した場合のみ動作することを忘れないでください。 CRIUサポートでCRI-Oを起動することのセキュリティ影響はまだ明確ではなく、そのため、イメージフォーマットだけでなく機能も気を付けて使用するべきです。

さて、そのイメージをコンテナイメージレジストリにプッシュする必要があります。 例えば以下のような感じです。

buildah push localhost/checkpoint-image:latest container-image-registry.example/user/checkpoint-image:latest

このチェックポイントイメージ(container-image-registry.example/user/checkpoint-image:latest)をリストアするために、イメージはPodの仕様(Specification)に記載する必要があります。 以下はマニフェストの例です。

apiVersion: v1
kind: Pod
metadata:
  namePrefix: example-
spec:
  containers:
  - name: <container-name>
    image: container-image-registry.example/user/checkpoint-image:latest
  nodeName: <destination-node>

Kubernetesは新しいPodをノード上にスケジュールします。 そのノード上のKubeletは、registry/user/checkpoint-image:latestとして指定されたイメージをもとに、コンテナを作成し開始するようにコンテナランタイム(この例ではCRI-O)に指示をします。 CRI-Oはregistry/user/checkpoint-image:latestがコンテナイメージでなく、チェックポイントデータへの参照であることを検知します。 その時、コンテナを作成し開始する通常のステップの代わりに、CRI-Oはチェックポイントデータをフェッチし、指定されたチェックポイントからコンテナをリストアします。

Pod内のアプリケーションはチェックポイントを取得しなかったかのように実行し続けます。 コンテナ内では、アプリケーションはチェックポイントからリストアされず通常起動したコンテナのような見た目や動作をします。

これらのステップで、あるノードで動作しているPodを、別のノードで動作している新しい同等のPodに置き換えることができ、そのPod内のコンテナの状態を失うことはないです。

どのように参加すればよいですか?

SIG Nodeにはいくつかの手段でアクセスすることができます。

さらなる読み物

コンテナチェックポイントの分析方法に関する詳細は後続のブログForensic container analysisを参照してください。

更新: dockershimの削除に関するFAQ

この記事は2020年の後半に投稿されたオリジナルの記事Dockershim Deprecation FAQの更新版です。 この記事にはv1.24のリリースに関する更新を含みます。


この文書では、Kubernetesからの dockershim の削除に関するよくある質問について説明します。 この削除はKubernetes v1.20リリースの一部としてはじめて発表されたものです。 Kubernetes v1.24のリリースにおいてdockershimは実際にKubernetesから削除されました。

これが何を意味するかについては、ブログ記事Don't Panic: Kubernetes and Dockerをご覧ください。

dockershim削除の影響範囲を確認するをお読みいただくことで、 dockershimの削除があなたやあなたの組織に与える影響をご判断いただけます。

Kubernetes 1.24リリースに至るまでの間、Kubernetesコントリビューターはこの移行を円滑に行えるようにするために尽力してきました。

dockershimはなぜKubernetesから削除されたのですか?

Kubernetesの初期のバージョンは、特定のコンテナランタイム上でのみ動作しました。 Docker Engineです。その後、Kubernetesは他のコンテナランタイムと連携するためのサポートを追加しました。 オーケストレーター(Kubernetesなど)と多くの異なるコンテナランタイムの間の相互運用を可能にするため、 CRI標準が作成されました。 Docker Engineはそのインターフェース(CRI)を実装していないため、Kubernetesプロジェクトは移行を支援する特別なコードを作成し、 その dockershim コードをKubernetes自身の一部としました。

dockershimコードは常に一時的な解決策であることを意図されていました(このためshimと名付けられています)。 コミュニティでの議論や計画については、dockershimの削除によるKubernetes改良の提案にてお読みいただけます。

実際、dockershimのメンテナンスはKubernetesメンテナーにとって大きな負担になっていました。

さらに、dockershimとほとんど互換性のなかった機能、たとえばcgroups v2やユーザーネームスペースなどが、 これらの新しいCRIランタイムに実装されています。Kubernetesからdockershimを削除することで、これらの分野でのさらなる開発が可能になります。

Dockerとコンテナは同じものですか?

DockerはLinuxのコンテナパターンを普及させ、その基盤技術の発展に寄与してきましたが、 Linuxのコンテナ技術そのものはかなり以前から存在しています。 また、コンテナエコシステムはDockerを超えてより広範に発展してきました。 OCIやCRIのような標準は、Dockerの機能の一部を置き換えたり、既存の機能を強化したりすることで、 私達のエコシステムの多くのツールの成長と繁栄を助けてきました。

既存のコンテナイメージは引き続き使えるのですか?

はい、docker buildから生成されるイメージは、全てのCRI実装で動作します。 既存のイメージも全く同じように動作します。

プライベートイメージについてはどうでしょうか?

はい、すべてのCRIランタイムはKubernetesで使われているものと同一のpull secretsをサポートしており、 PodSpecまたはService Accountを通して利用できます。

Kubernetes 1.23でDocker Engineを引き続き使用できますか?

はい、1.20で変更されたのは、Docker Engineランタイムを使用している場合に警告ログがkubelet起動時に出るようになったことだけです。 この警告は、1.23までのすべてのバージョンで表示されます。 dockershimの削除はKubernetes 1.24で行われました。

Kubernetes v1.24以降を実行している場合は、Docker Engineを引き続きコンテナランタイムとして利用できますか?をご覧ください。 (CRIがサポートされているKubernetesリリースを使用している場合、dockershimから切り替えることができることを忘れないでください。 リリースv1.24からはKubernetesにdockershimが含まれなくなったため、必ず切り替えなければなりません)。

どのCRIの実装を使うべきでしょうか?

これは難しい質問で、様々な要素に依存します。 もしDocker Engineがうまく動いているのであれば、containerdに移行するのは比較的簡単で、 性能もオーバーヘッドも確実に改善されるでしょう。 しかし、他の選択のほうがあなたの環境により適合する場合もありますので、 CNCF landscapeにあるすべての選択肢を検討されることをおすすめします。

Docker Engineを引き続きコンテナランタイムとして利用できますか?

第一に、ご自身のPCで開発やテスト用途でDockerを使用している場合、何も変わることはありません。 Kubernetesでどのコンテナランタイムを使っていても、Dockerをローカルで使い続けることができます。 コンテナではこのような相互運用性を実現できます。

MirantisとDockerは、Kubernetesから内蔵のdockershimが削除された後も、 Docker Engineの代替アダプターを維持することにコミットしています。 代替アダプターの名前はcri-dockerdです。

cri-dockerdをインストールして、kubeletをDocker Engineに接続するために使用することができます。 詳細については、Migrate Docker Engine nodes from dockershim to cri-dockerdを読んでください。

今現在でプロダクション環境に他のランタイムを使用している例はあるのでしょうか?

Kubernetesプロジェクトが生み出したすべての成果物(Kubernetesバイナリ)は、リリースごとに検証されています。

また、kindプロジェクトは以前からcontainerdを使っており、プロジェクトのユースケースにおいて安定性が向上してきています。 kindとcontainerdは、Kubernetesコードベースの変更を検証するために毎日何回も利用されています。 他の関連プロジェクトも同様のパターンを追っており、他のコンテナランタイムの安定性と使いやすさが示されています。 例として、OpenShift 4.xは2019年6月以降、CRI-Oランタイムをプロダクション環境で使っています。

他の事例や参考資料はについては、 containerdとCRI-O(Cloud Native Computing Foundation (CNCF)の2つのコンテナランタイム)の採用例をご覧ください。

OCIという単語をよく見るのですが、これは何ですか?

OCIはOpen Container Initiativeの略で、コンテナツールとテクノロジー間の数多くのインターフェースの標準化を行った団体です。 彼らはコンテナイメージをパッケージするための標準仕様(OCI image-spec)と、 コンテナを実行するための標準仕様(OCI runtime-spec)をメンテナンスしています。 また、runcという形でruntime-specの実装もメンテナンスしており、 これはcontainerdCRI-Oの両方でデフォルトの下位ランタイムとなっています。 CRIはこれらの低レベル仕様に基づいて、コンテナを管理するためのエンドツーエンドの標準を提供します。

CRI実装を変更する際に注意すべきことは何ですか?

DockerとほとんどのCRI(containerdを含む)において、下位で使用されるコンテナ化コードは同じものですが、 いくつかの細かい違いが存在します。移行する際に考慮すべき一般的な事項は次のとおりです。

  • ログ設定
  • ランタイムリソースの制限
  • ノード構成スクリプトでdockerコマンドやコントロールソケット経由でDocker Engineを使用しているもの
  • kubectlのプラグインでdocker CLIまたはDocker Engineコントロールソケットが必要なもの
  • KubernetesプロジェクトのツールでDocker Engineへの直接アクセスが必要なもの(例:廃止されたkube-imagepullerツール)
  • registry-mirrorsやinsecureレジストリなどの機能の設定
  • その他の支援スクリプトやデーモンでDocker Engineが利用可能であることを想定していてKubernetes外で実行されるもの(モニタリング・セキュリティエージェントなど)
  • GPUまたは特別なハードウェア、そしてランタイムおよびKubernetesとそれらハードウェアの統合方法

あなたがKubernetesのリソース要求/制限やファイルベースのログ収集DaemonSetを使用しているのであれば、それらは問題なく動作し続けますが、 dockerdの設定をカスタマイズしていた場合は、それを新しいコンテナランタイムに適合させる必要があるでしょう。

他に注意することとしては、システムメンテナンスを実行するようなものや、コンテナ内でイメージをビルドするようなものが動作しなくなります。 前者の場合は、crictlツールをdrop-inの置き換えとして使用できます(docker cliからcrictlへのマッピングを参照)。 後者の場合は、imgbuildahkanikobuildkit-cli-for-kubectlのようなDockerを必要としない新しいコンテナビルドの選択肢を使用できます。

containerdを使っているのであれば、ドキュメントを参照して、移行するのにどのような構成が利用可能かを確認するところから始めるといいでしょう。

containerdとCRI-OをKubernetesで使用する方法に関しては、コンテナランタイムに関するKubernetesのドキュメントを参照してください。

さらに質問がある場合どうすればいいでしょうか?

ベンダーサポートのKubernetesディストリビューションを使用している場合、彼らの製品に対するアップグレード計画について尋ねることができます。 エンドユーザーの質問に関しては、エンドユーザーコミュニティフォーラムに投稿してください。

dockershimの削除に関する決定については、専用のGitHub issueで議論することができます。

変更点に関するより詳細な技術的な議論は、待ってください、DockerはKubernetesで非推奨になったのですか?という素晴らしいブログ記事も参照してください。

dockershimを使っているかどうかを検出できるツールはありますか?

はい!Detector for Docker Socket (DDS)というkubectlプラグインをインストールすることであなたのクラスターを確認していただけます。 DDSは、アクティブなKubernetesワークロードがDocker Engineソケット(docker.sock)をボリュームとしてマウントしているかを検出できます。 さらなる詳細と使用パターンについては、DDSプロジェクトのREADMEを参照してください。

ハグしていただけますか?

はい、私達は引き続きいつでもハグに応じています。🤗🤗🤗

Don't Panic: Kubernetes and Docker

Kubernetesはv1.20より新しいバージョンで、コンテナランタイムとしてDockerをサポートしません

パニックを起こす必要はありません。これはそれほど抜本的なものではないのです。

概要: ランタイムとしてのDockerは、Kubernetesのために開発されたContainer Runtime Interface(CRI)を利用しているランタイムを選んだ結果としてサポートされなくなります。しかし、Dockerによって生成されたイメージはこれからも、今までもそうだったように、みなさんのクラスターで使用可能です。

もし、あなたがKubernetesのエンドユーザーであるならば、多くの変化はないでしょう。これはDockerの死を意味するものではありませんし、開発ツールとして今後Dockerを使用するべきでない、使用することは出来ないと言っているのでもありません。Dockerはコンテナを作成するのに便利なツールですし、docker buildコマンドで作成されたイメージはKubernetesクラスター上でこれからも動作可能なのです。

もし、GKE、EKS、AKSといったマネージドKubernetesサービス(それらはデフォルトでcontainerdを使用しています)を使っているのなら、ワーカーノードがサポート対象のランタイムを使用しているか、Dockerのサポートが将来のK8sバージョンで切れる前に確認しておく必要があるでしょう。 もし、ノードをカスタマイズしているのなら、環境やRuntimeの仕様に合わせて更新する必要があるでしょう。サービスプロバイダーと確認し、アップグレードのための適切なテストと計画を立ててください。

もし、ご自身でClusterを管理しているのなら、やはり問題が発生する前に必要な対応を行う必要があります。v1.20の時点で、Dockerの使用についての警告メッセージが表示されるようになります。将来のKubernetesリリース(現在の計画では2021年下旬のv1.22)でDockerのRuntimeとしての使用がサポートされなくなれば、containerdやCRI-Oといった他のサポート対象のRuntimeに切り替える必要があります。切り替える際、そのRuntimeが現在使用しているDocker Daemonの設定をサポートすることを確認してください。(Loggingなど)

では、なぜ混乱が生じ、誰もが恐怖に駆られているのか。

ここで議論になっているのは2つの異なる場面についてであり、それが混乱の原因になっています。Kubernetesクラスターの内部では、Container runtimeと呼ばれるものがあり、それはImageをPullし起動する役目を持っています。Dockerはその選択肢として人気があります(他にはcontainerdやCRI-Oが挙げられます)が、しかしDockerはそれ自体がKubernetesの一部として設計されているわけではありません。これが問題の原因となっています。

お分かりかと思いますが、ここで”Docker”と呼んでいるものは、ある1つのものではなく、その技術的な体系の全体であり、その一部には"containerd"と呼ばれるものもあり、これはそれ自体がハイレベルなContainer runtimeとなっています。Dockerは素晴らしいもので、便利です。なぜなら、多くのUXの改善がされており、それは人間が開発を行うための操作を簡単にしているのです。しかし、それらはKubernetesに必要なものではありません。Kubernetesは人間ではないからです。 このhuman-friendlyな抽象化レイヤーが作られたために、結果としてはKubernetesクラスターはDockershimと呼ばれるほかのツールを使い、本当に必要な機能つまりcontainerdを利用してきました。これは素晴らしいとは言えません。なぜなら、我々がメンテする必要のあるものが増えますし、それは問題が発生する要因ともなります。今回の変更で実際に行われることというのは、Dockershimを最も早い場合でv1.23のリリースでkubeletから除外することです。その結果として、Dockerのサポートがなくなるということなのです。 ここで、containerdがDockerに含まれているなら、なぜDockershimが必要なのかと疑問に思われる方もいるでしょう。

DockerはCRI(Container Runtime Interface)に準拠していません。もしそうであればshimは必要ないのですが、現実はそうでありません。 しかし、これは世界の終わりでありません、心配しないでください。みなさんはContainer runtimeをDockerから他のサポート対象であるContainer runtimeに切り替えるだけでよいのです。

1つ注意すべきことは、クラスターで行われる処理のなかでDocker socket(/var/run/docker.sock)に依存する部分がある場合、他のRuntimeへ切り替えるとこの部分が働かなくなるでしょう。このパターンはしばしばDocker in Dockerと呼ばれます。このような場合の対応方法はたくさんあります。kanikoimgbuildahなどです。

では開発者にとって、この変更は何を意味するのか。これからもDockerfileを使ってよいのか。これからもDockerでビルドを行ってよいのか。

この変更は、Dockerを直接操作している多くのみなさんとは別の場面に影響を与えるでしょう。 みなさんが開発を行う際に使用しているDockerと、Kubernetesクラスターの内部で使われているDocker runtimeは関係ありません。これがわかりにくいことは理解しています。開発者にとって、Dockerはこれからも便利なものであり、このアナウンスがあった前と変わらないでしょう。DockerでビルドされたImageは、決してDockerでだけ動作するというわけではありません。それはOCI(Open Container Initiative) Imageと呼ばれるものです。あらゆるOCI準拠のImageは、それを何のツールでビルドしたかによらず、Kubernetesから見れば同じものなのです。containerdCRI-Oも、そのようなImageをPullし、起動することが出来ます。 これがコンテナの仕様について、共通の仕様を策定している理由なのです。

さて、この変更は決定しています。いくつかの問題は発生するかもしてませんが、決して壊滅的なものではなく、ほとんどの場合は良い変化となるでしょう。Kubernetesをどのように使用しているかによりますが、この変更が特に何の影響も及ぼさない人もいるでしょうし、影響がとても少ない場合もあります。長期的に見れば、物事を簡単にするのに役立つものです。 もし、この問題がまだわかりにくいとしても、心配しないでください。Kubernetesでは多くのものが変化しており、その全てに完璧に精通している人など存在しません。 経験の多寡や難易度にかかわらず、どんなことでも質問してください。我々の目標は、全ての人が将来の変化について、可能な限りの知識と理解を得られることです。 このブログが多くの質問の答えとなり、不安を和らげることができればと願っています。

別の情報をお探しであれば、dockershimの削除に関するFAQを参照してください。