Open211

Kubernetes - 2024

Tsubasa NagasawaTsubasa Nagasawa

2024/1/5

  • Kubernetes 1.30 のリリースサイクルは 1/8 から開始 (google group)
    • KEP フリーズ: 2/9
    • コードフリーズ: 3/6
    • KubeCon EU: 3/19-
    • テスト / Docs フリーズ: 3/26
      • Docs フリーズはドキュメントも大事ということで今回から始まった
      • 期限を超える場合は例外申請が必要
    • リリース予定日: 4/17
Tsubasa NagasawaTsubasa Nagasawa

2024/1/8

  • In Place Pod Vertical Scaling で Pod のリソース要求と上限を patch で変更すると、ノードの割り当て可能なリソースを超えてもエラーにならない。patch でエラーを返すようにするか、他の Pod を Evict して割り当てられるようにするか、オプションで挙動を変えられるようにするか。再起動して別のノードで起動するって挙動もありえるし、考えることが多くて難しそう (k/k#122602)
Tsubasa NagasawaTsubasa Nagasawa

2024/1/10

  • 今までなぜかノードの Eviction Hard (過負荷状態のノードを救うために Pod を追い出す機能) の発動条件に nodefs の inode の空きが少なくなったらの条件はあったけど、imagefs の inode の空きが少なくなったらの条件はなかった。今までは nodefs と imagefs が同じディスクのファイルシステムだったので問題なかった。ただ、KEP-4191 でコンテナイメージ用のファイルシステムを別のディスクのファイルシステムに変更できるようになるから、imagefs の inode の空きもちゃんと見るようにする (k/k#121834)
Tsubasa NagasawaTsubasa Nagasawa

2024/1/11

  • Kubernetes 1.27 で Evented PLEG (Pod Lifecycle Event Generator) がベータに昇格した。コンテナランタイム側のサポートが必要なのでデフォルト無効だったけど、Kubelet が Pod を重複して起動しようとしたり致命的なバグがあるので、1.30 でアルファに降格されようとしている珍しいケース。1.27, 1.28, 1.29 にも cherry-pick 済み (k/k#122697)
    • 元々ベータ昇格の条件としてすぐにパフォーマンス改善やテストのカバレッジを上げると約束していたけど、結局実装されなかったため
Tsubasa NagasawaTsubasa Nagasawa

2024/1/12

  • GKE の Rapid channel で 1.29 が使えるようになっている。年末年始挟んだので、upstream のリリースから通常より少し遅め (release note)
    • 1.29 で Validating Admission Policy も Beta API を有効にすることで使えるようになってる
    • 1.29 で Sidecar containers の機能がベータになっているので、initContainers で指定すると起動しっぱなしにもなる
Tsubasa NagasawaTsubasa Nagasawa

2024/1/13

  • Google から xDS Adapter for Cilium という提案が上げられている (google docs)
    • GKE は Dataplane v2 の追加設定として xDS の導入を計画していて、同様の機能は Cilium でも有用だと思うから upstream への追加しようと思っているらしい
    • xDS Adapter の実装による恩恵
      • クラスタ外の Service / Endpoint へのリクエストのルーティング
      • Topology Aware Routing などの高度なルーティング設定のサポート
    • ユーザーが Topology Aware Routing に期待する挙動として、各ゾーンの容量に対してまず同一ゾーンの Endpoint で埋めていき、溢れた Endpoint を次に近いゾーンで埋めていくというのがある
      • Kubernetes が容量に対して Endpoint を埋めていく時にデータプレーン (e.g. Cilium) から配置に対するフィードバックがなく、適切に容量を埋め切ったかどうかがよく分からない
      • 仮にデータプレーンからフィードバックがあったとしても、中央集権的なオーケストレーターがいないと徐々に増えるフィードバックのイベントが多すぎて Thundering herd 問題を引き起こしてしまう
      • エンドポイントのルーティングに対する変更は Service / EndpointSlice など Kubernetes API サーバーを経由して取得する必要があり、オーバーヘッドになる。重み付けや Topology Aware Routing のために容量を調整しようにもコストが掛かる。Endpoint の重み付けを調整するには API 経由で EndpointSlice に情報を書き込む必要がある。Endpoint / Node が大量にあるクラスタではパフォーマンスに影響してしまう。
    • 上記の問題を解決するために xDS が有効
      • LRS (Load Reporting Service) が中央集権的なコントロールプレーンに対して負荷の状況を報告できる
      • Delta xDS で Kubernetes API が返す情報より少ない、更新のあったエンドポイントの情報だけを返すことができ、Kubernetes API サーバへの負荷も下げることができる
    • ローカルの Kubernetes クラスタ以外からのエンドポイントに対してのルーティング
      • Multi-Cluster Service で実現できるが、以下の実装がよく使われている
        • 別のクラスタに Service / EndpointSlice を作成して、エンドポイントの情報をミラーする必要がある
        • クラスタに中にゲートウェイを用意して、別のクラスタからのリクエストを受け取ってよしなにルーティングする
      • xDS はローカルクラスタだろうが外部のクラスタだろうが関係なくエンドポイントの情報を取り扱えるので上記の実装よりも効率的になる
    • Cilium が Kubernetes 以外にも xDS からエンドポイントの情報を受け取れるようにする
      • エンドポイントの情報が重複してしまった場合は、Kubernetes から取得した方を優先的に使う
      • 同一の Service が Kubernetes と xDS の両方からエンドポイントの情報を取得できる場合、Kubernetes API 経由で取得した Service の情報が優先されて xDS で取得した情報は使われない (重複したよの警告は出すかも?)
    • xDS のサポートは Cilium に現状ある KVStore の機能と似たような形になる
      • Cilium が新しいバックエンド (xDS) から情報を取得できるようになるだけ
      • 今は Kubernetes API と KVStore から取得できているので、そこに新しくオプションを追加し、全てのデータストアで利用できるように共通のインターフェイスを定義しておく
    • 最初は Cluster IP のルーティングに必要な Cilium のフィールドを xDS API とマッピングする。必要に応じて API のマッピングを増やしていく
      • e.g.) FrontendAddress (Cilium) -> filter_chain_match.prefix_ranges (xDS)
    • GKE の場合は xDS サーバとして Traffic Director を使うだろうから Traffic Director にエンドポイントの情報を登録するエージェントが動く感じかな?KEP-4188 で Kubelet で公開した情報を各ノードで動作するエージェントが Traffic Director に登録するとか?流石に Traffic Director の API のレート制限に引っかかりそう?
Tsubasa NagasawaTsubasa Nagasawa

2024/1/14

  • DaemonSet を複数のインスタンスサイズのノードが混在した環境で起動すると、リソース割り当てが環境に依らず静的に設定される。ノードの割り当て可能なリソースや Pod 数などに応じて動的に DaemonSet の Pod のリソース割り当てを変更する機能が欲しいという要望。今でもノードのラベルを使って Affinity ルールで実現できなくはないけど、インスタンスサイズが複数あると大変。提案者は時間がなくて KEP のプロセスは難しそうらしいので、誰かやってくれるなららしい。Pod In-place Vertical Scaling の機能を使って調整するのが現実的? (k/k#122753)
  • Kubernetes 1.28 で kube-scheduler のメモリ使用量の高騰の報告がある (k/k#122661, k/k#122725)
    • QueueingHint 関連の既知のリグレッションで 1.28.4 でデフォルトで機能を無効化してるからそれ以降は起きないはず (k/k#120622)
    • Kubernetes 1.29 で StatefulSet の Pod を Evict すると RecreatingTerminatedPod のイベントが重複して大量に発生する問題。以前の Pod のフェーズ変更で StatefulSet が Graceful Node Shutdown 発動後に Succeeded フェーズでスタックして起動してこなくなる問題の修正のリグレッションみたい (k/k#122709)
Tsubasa NagasawaTsubasa Nagasawa

2024/1/15

  • Preemption された Pod 数のメトリクスに PriorityClass のラベルを付与しようとしたけど、メトリクスが Stable なのでラベルの追加が許されない。ラベルが付いただけの別のメトリクスをこのためだけに追加するのは、既存のメトリクスと混乱するし、Stable なメトリクスを非推奨化して移行を促すことができるのか分からないので難しい。一旦追加はなしでユーザーから要望があれば考えることに (k/k#122357)
Tsubasa NagasawaTsubasa Nagasawa

2024/1/16

  • Kubernetes 1.30 から kubectl get cronjob の結果にタイムゾーン列が追加される (k/k#122231)
  • kubectl debug で事前定義のプロファイルじゃなくて、JSON 形式でコンテナのスペックを渡せる (変更したい箇所だけ?) カスタムプロファイルの機能は 1.30 でアルファを目指すみたい (comment - kubernetes/enhancements#4292)
  • 長いことベータ機能で居座っていた kubectl debug が 1.30 で GA を目指す (kubernetes/enhancements#4408)
Tsubasa NagasawaTsubasa Nagasawa

2024/1/17

  • Kubernetes Network Interface (KNI) (slide, blog)
    • KNI の目指すところ
      • CNI は Kubernetes 専用の仕組みではないので、CNI の上にレイヤーを置いて gRPC で Kubernetes 向けのネットワーク関連の操作ができる API (インターフェイス) を作りたい
      • CNI の仕組みができて 8 年経っているので再考したい
        • 現在は CNI の処理の結果の中で IP アドレスしか使われていないけど、他の情報も使いたい
        • CNI 2.0 の議論の中で Kubernetes 向けの機能の議論もある
      • クラウドとかネットワーク関連のハードウェアと良い感じに連携できるようにしたい
      • 単なるインターフェイスではなくエコシステムにしたい
    • 現在は kubelet から CRI を通して指示 (SyncPod / KillPod など) することで、コンテナランタイム (e.g. containerd) が sandbox コンテナを作成したとにネットワークネームスペースを作成して CNI plugin を呼び出して (e.g. CNI ADD / DEL) Pod のネットワークを設定している
      • kubelet (CRI client) <-> コンテナランタイム (CRI plugin) <-> CNI plugin
    • kubelet から CRI に加えて KNI を通して指示できるようになり、コンテナのセットアップとネットワークのセットアップを分離
      • KNI から gRPC 経由で KNI ネットワークランタイムに指示し、KNI ネットワークランタイムが CNI plugin を呼び出す
        • Attach / Update / Detach Query Pod or Node / Verify などなど
      • KNI ネットワークランタイムはコンテナランタイム内に埋め込むこともできるし、コンテナランタイムとは別のプロセスとして実装することもできるが、デーモンとして起動
      • ネットワークランタイム API の実装方法は様々でカスタムリソースや Kubernetes のオブジェクトを参照して Pod ネットワークを構成するコントローラーを埋め込んでも良く拡張は自由
    • Kubernetes のネットワークの制御がこれまでよりもしやすく、プラグイン的な実装も可能になる
      • NAT 排除したい、ECMP Anycast でのルーティング、BGP や TOR との連携、複数ネットワークなど色々と拡張性がある
      • Pod とノードのネットワークのセットアップ処理を分離できる
      • Kubernetes 本体への変更を減らすことができる
        • KNI 自体への変更は Kubernetes コア機能に比べて影響も少ない
Tsubasa NagasawaTsubasa Nagasawa

2024/1/19

  • Argo CD で脆弱性が修正されてる。昔から CSRF の危険性については言われてきたけど、最近のブラウザは Cookie の SameSite 属性が指定されていないと Lax 扱いになるから、優先度をあげて対応してなかったっぽい。ただ、オリジンが同一の親ドメインだと当然問題になる。Argo CD は CORS のプリフライトリクエストの Content-Type ヘッダーを検証しておらず、攻撃が成功してしまう。攻撃者が text/plain とかを指定してブラウザに対して機密情報を含んでないよと嘘をついてプリフライトリクエストが回避できちゃうから。今回の修正で、GET 以外のメソッドで Content-Type が application/json 以外のリクエストを受け付けなくしたので、プリフライトリクエストがバイパスできなくなる (GitHub Security Advisory)
Tsubasa NagasawaTsubasa Nagasawa

2024/1/20

  • KEP-4420: Retry Generate Name (kubernetes/enhancements#4421)
    • GenerateName を使ってリソースを作成し時に、ランダム文字列が衝突する問題の緩和策
    • 現在は 27 文字からランダムに 5 つの文字を選択してランダム文字列を生成しているので、27^5 = 14,348,907 のランダム文字列が生成可能
    • クラスタ内にあるカスタムリソースの数は多く共 100,000 - 1,000,000 個なので、ランダム文字列が枯渇する問題は今のところ大丈夫
    • ただ、ランダム文字列が衝突する可能性は高く、5 文字のランダム文字列だと、500 個の名前を生成する場合に 0.1% の確率で衝突し、5,000 個の名前を作成する場合だと 50% の確率で衝突してしまう
    • リソース名が衝突した場合に 409 Conflict を返すようにしているが、本番環境で動作している多くのクライアントが 409 の場合に再処理する実装にはなっていない
    • Generate Name でリソースを作成する場合に、ランダム文字列が衝突すると 7 回までリトライして新しいランダム文字列の生成を試みる
      • 7 回なのは 7 回繰り返すと、1,000,000 個の名前の生成でやっと衝突する可能性が 0.1% になる程度に抑えられるから
      • ランダム文字列の長さを増やす場合、11 文字まで増やさないと ~1,000,000 個の名前の衝突を 0.1% 程度まで抑えることができない
        • ランダム文字列の数に依存した実装をしているサードパーティ製のツールもあるので簡単に増えせない
    • リトライすると kube-apiserver のレスポンス時間に影響してしまう
      • 特に Validating Admission Webhook などを介する場合は、Admission Webhook にリトライの度にリクエストが流れるのでその分余計に時間が掛かる
      • ただ、そもそもリソース名の衝突はエッジケースで確率的にも起きにくいので、レスポンス時間の悪化は無視できるはず
Tsubasa NagasawaTsubasa Nagasawa

2024/1/21

  • KEP-4330: Compatibility versions (kubernetes/enhancements#4395)
    • WG-LTS で去年提案のあった Rust のエディション的な概念を導入する話
    • Kubernetes のコントロールプレーンのコンポーネントに --compatibility-version の起動オプションを追加し、Kubernetes のバージョン更新をより細かいステップに分けて安全に行えるようにする
    • 互換性バージョンは Kubernetes のコントロールプレーンのバイナリのバージョンとは完全に独立したもので、以前の Kubernetes バージョンの挙動 (API や機能など) を再現することができる
    • Kubernetes のバージョンを N から N+1 に更新するときに、より細かい粒度で更新できるようになると、N にはないが N+1 にはあるようなデータを柔軟に取り扱えるようになる
      • 1.30 から 1.31 に更新する場合、互換性バージョンを 1.30 に設定する場合を考える。クラスタ管理者は 1.31 で追加された機能に伴うデータを etcd に書き込むことなしに、1.31 の各コンポーネントのバイナリの挙動に問題ないかを確認できる。その後で互換性バージョンを 1.31 に更新すれば新しい機能を有効化して検証ができる。
    • KEP-4330 がベータに昇格した時点で、互換性バージョンのスキューポリシーを N-3 に拡張予定
      • コントロールプレーンのバイナリバージョンをスキップして更新が可能に
      • 1.28 -> 1.31 への更新を考える
        • コントロールプレーンのバイナリバージョンと互換性バージョンが 1.28 から開始
        • コントロールプレーンのバイナリバージョンを 1.31 に更新、互換性バージョンは 1.28 のまま
        • コントロールプレーンのバイナリバージョンは 1.31 のまま、互換性バージョンを 1.29 に更新
        • コントロールプレーンのバイナリバージョンは 1.31 のまま、互換性バージョンを 1.30 に更新
        • コントロールプレーンのバイナリバージョンは 1.31 のまま、互換性バージョンを 1.31 に更新
      • 互換性バージョンを更新しないので、クライアントが新しい API や機能を利用することはなく、バイナリバージョンの更新で問題が起きないことを確認できる
      • 更新ステップの粒度が細かくなるので、Kubernetes の更新を管理しているシステムがどこで問題が起きたのか特定しやすく、対処を実施しやすい
      • バイナリバージョンを変えることなく、互換性バージョンを戻すだけで切り戻しができる
    • API や機能、ストレージバージョン (etcd 内に保存される時のオブジェクトのバージョン)、CEL などが過去の Kubernetes のリリースバージョンと同じ挙動をするためのメタデータの追加
    • Kubernetes の互換性バージョンを N とした時に、Kubernetes のバージョン N のコンフォーマンステストを追加することを確認
    • 互換性バージョンに N が設定された Kubernetes のバイナリは API や機能、ストレージバージョン、CEL などに変更を加えず、N-1 にロールバックできるようにする
    • --compatibility-version<major.minor> 形式で指定 (e.g. 1.31)
    • FeatureGate に変更が入り、機能毎にバージョンを追跡できる仕組みが追加される
      • コンポーネントが起動するとその互換性バージョンでの FeatureGate の定義をもとに機能を有効 / 無効化、アルファ / ベータ / GA を選択

        map[Feature]VersionedSpecs{
        		featureA: VersionedSpecs{
        			{Version: mustParseVersion("1.27"), Default: false, PreRelease: Beta},
        			{Version: mustParseVersion("1.28"), Default: true, PreRelease: GA},
        		},
        }
        
      • 1.28 で GA or 削除された機能を考えると、1.30 までは FeatureGate による機能の ON/OFF のコードが残っていて、削除された機能の場合もコードは残っている状態だが、1.31 で FeatureGate & 機能のコードが削除される (N-3 のバージョンスキューポリシーの拡張)

      • 同一のステージ (e.g. ベータ) でも大きな変更が入った場合に、実装者は Feature Gate の互換性バージョンの情報を用いて挙動を変更することもできる

        • バグ修正を cherry-pick する場合に、バグの互換性を維持するための機能ではない
        if feature_gate.Enabled(FeatureA) && feature_gate.CompatibilityVersion() <= "1.28" {implementation 1}
        if feature_gate.Enabled(FeatureA) && feature_gate.CompatibilityVersion() >= "1.29" {implementation 2}
        
  • container_memory_working_set_bytes はカーネルによって解放されないメモリ使用量と必ずしも一致しない。例えば、Pod 内の複数のコンテナが emptyDir を共有していて、あるコンテナが emptyDir のファイルに書き込んで、別のコンテナがファイルを継続的に読み取っている場合、時間の経過とともにアクティブなファイルキャッシュ (total_active_file) が増えて、container_memory_working_set_bytes の値が増えてしまう。この状態で、プロセスが解放できないメモリ使用量を使おうとすると、カーネルがアクティブなファイルキャッシュを解放して total_active_file は減っていく。container_memory_working_set_bytes の値にはアクティブでないファイルキャッシュの値は含まれていないが、アクティブなファイルキャッシュ (total_active_file) の値が含まれている。カーネルは cgroup のメモリ上限の ~90% 程度で推移するようにゆっくりとページキャッシュを解放していくので、継続的にファイルに読み書きしているプロセスで、container_memory_working_set_bytes を解放できないメモリ使用量の指標に使うとアラートの設定が難しい。新しく container_memory_non_evictable_set のメトリクスを追加して、両方のファイルキャッシュを差し引いた値を返すようにする (google/cadvisor#3445)
Tsubasa NagasawaTsubasa Nagasawa

2024/1/23

  • AWS の EKS チームで EKS Anywhere に関わっていた人が Sidero Labs (Talos Linux) に移ってる (X)
Tsubasa NagasawaTsubasa Nagasawa

2024/1/24

  • 前に言ってた Kubernetes の PR / Issue コメントでメンテナを攻撃するユーザーの発言集を共有してガス抜きと自省するセッションが KubeCon EU 2024 で予定されている!スピーカーの 2 人ともユーモアあるから楽しそう (link)
Tsubasa NagasawaTsubasa Nagasawa

2024/1/26

  • Argo CD v2.10.0 で Server-Side Diff の機能がベータで入るみたい。差分表示に Server-Side Apply の Dry Run モードを使うオプションが選択できるようになる。API conversion のエラー (v1beta1 で作っていて v1 に更新した場合の差分が見られない問題) が解決されて、Validating Webhook の検証エラーも差分の時点で表示されるようになる。毎回 Server-Side Apply が実行されると API server に対して負荷になるので Server-Side Diff の結果をキャッシュして Application の Refresh や変更時などだけ再取得する (argoproj/argo-cd#13663)
  • Argo CD v2.10.0 で差分更新のために定期的に Git リポジトリをポーリングする間隔に Jitter を設定してタイミングをずらせるようになるみたい。timeout.reconciliation を 0 にして、Git Webhook でプッシュ時にイベントベースで Refresh させる方が良いけどその構成が取れない場合は、Git リポジトリへの負荷の低減になりそう (argoproj/argo-cd#16820)
Tsubasa NagasawaTsubasa Nagasawa

2024/1/27

  • EKS のコントロールプレーンを更新したら EKS マネージドアドオンも自動で更新して欲しい。AWS の人が良いねとは言ってるけど、やるとは言ってないな (comment - aws/containers-roadmap#2109)

  • Sidecar containers でメインのコンテナが停止中にサイドカーコンテナが異常終了したら再起動する機能は別の KEP にして対応する方針にしたのかな (kubernetes/enhancements#4438)

  • コンテナイメージの圧縮で Zstandard を使うと、gzip に比べて zstd の解凍の速度が 3 倍くらい早いからコンテナの起動も早くなるかもらしい。Image Streaming と互換性がないから一緒には使えない。コンテナ起動時にほぼ全てのイメージレイヤーが必要ならこの方法が向いている (blog)

  • KEP-4447: Promote Policy Reports API to a Kubernetes SIG API (kubernetes/enhancements#4448)

    • PolicyReport API が WG-Policy のリポジトリの下で開発されてきたけど、利用プロジェクトも増えてきたことだし kubernetes-sigs の正式なプロジェクトに昇格させたい
    • PolicyReport API は Falco, OPA / Gatekeeper, Keyverno, ... などのポリシー管理ツールの結果をクラスタ管理者やユーザーに報告するための仕組み
      • カスタムリソースとしては PolicyReport (ユーザー向け) と ClusterPolicyReport (クラスタ管理者向け)
      • Summary にポリシーの結果毎の集計が合って、Results に実際にあるリソースに対してどういう結果でメッセージも表示できたり
      • 以下の例にはないけど、scope / scopeSelectorで対象のリソースを絞ったりもできる
    • クラスタ管理者としてプラットフォームの利用ユーザーの動向を知るのには使えそう
      • 何か新しいポリシーを今後強制しようと思った時に、一旦違反しても警告だけ表示するようにしておいて、実際にどれくらいのユーザーがこのポリシーに違反しているのかを集計して、Results の詳細を見てどのリソースでどう言う使い方をしていて違反になっているかの傾向も分かるので便利そう。ポリシー違反の件数自体はメトリクスでも見れそうだけど、詳細もってなると把握しづらいと思うので。
    • 利用ユーザー側にもレポートとして報告できるので、教育するのにも使えそう
    apiVersion: wgpolicyk8s.io/v1beta1
    kind: PolicyReport
    metadata:
      name: sample-v1beta1-cr
      annotations:
        name: Sample CR
    configuration:
      limits:
        maxResults: 100
        statusFilter:
          - pass
          - fail
          - skip
    source: kyverno
    summary:
      pass: 1
      fail: 0
      warn: 0
      error: 0
      skip: 0
    results:
      - category: Pod Security Standards (Baseline)
        message: validation rule 'adding-capabilities' passed.
        policy: disallow-capabilities
        resources:
        - apiVersion: v1
          kind: Pod
          name: kyverno-6d88f6dcdd-k6bc5
          namespace: nirmata
          uid: 3407b31a-b0bb-4716-a443-f4aa15662ef2
        result: pass
        rule: adding-capabilities
        scored: true
        severity: medium
        source: kyverno
        timestamp:
          nanos: 0
          seconds: 1679565894
    
Tsubasa NagasawaTsubasa Nagasawa

2024/1/28

  • Validating Admission Policy でパラメータをカスタムリソースから参照している場合に、kube-apiserver を再起動するとポリシーに違反しているかに依らず必ずエラーになるバグの修正の PR。informer の作成がポリシーの resync 時に行われるが、ポリシーに変更がない場合に resync をスキップしていたのが原因。kube-apiserver が再起動した後にパラメータを渡すためのカスタムリソースの informer が作られるまでリトライするように修正 (k/k#123003)
Tsubasa NagasawaTsubasa Nagasawa

2024/1/31

  • EKS も GKE と同じで Pod に対する Mutating Admission Webhook で Kubernetes のライブラリのバージョンが古く Sidecar container 用の新しいフィールド (initContainers の restartPolicy) を握りつぶしていて 1.29 でベータに昇格したのに使えなくなってた (aws/amazon-eks-pod-identity-webhook#209)
Tsubasa NagasawaTsubasa Nagasawa

2024/2/1

  • EKS の AWS VPC CNI plugin で Network Policy を利用するの、内向きのルールでポート番号じゃなくてポート名を指定すると動作しないので注意です。再現手順渡したら修正の PR を上げてくれたので、しばらくすると直りそう。ただ、コントロールプレーンで動作しているコンポーネントなので EKS の新しいプラットフォームバージョンまで待たないといけなそう (aws/amazon-network-policy-controller-k8s#71)
Tsubasa NagasawaTsubasa Nagasawa

2024/2/3

  • Pod にマウントしている ConfigMap / Secret のファイルが作成されないことがある問題 (k/k#122807)
    • Pod が ConfigMap / Secret などのデータディレクトリをマウントする場合、タイムスタンプ付きのディレクトリ (e.g. ..2024_02_03_00_00_32.149716995) にデータを書き込んで、内部データディレクトリ (..data) にシンボリックリンクを作る。実際のファイルは内部データディレクトリ内のファイルへのシンボリックリンク (foo -> ..data/foo) になっている。
    • データを更新する場合の流れ
      1. 新しくマウントするファイルパスのバリデーション
      2. 内部データディレクトリ (..data) のシンボリックリンクを読むことで現在の参照先のタイムスタンプ付きのディレクトリを確認
      3. タイムスタンプ付きのディレクトリの中のファイルを見て回って削除すべきファイルを探す
      4. 新しくマウントするファイルの中身を現在のタイムスタンプ付きのディレクトリ内のファイルと比較して、更新が必要かを確認
      5. 更新が必要な場合は、新しいタイムスタンプ付きのデータディレクトリを作成
      6. 新しいタイムスタンプ付きのデータディレクトリにファイルを書き込む
      7. 新しいタイムスタンプ付きのデータディレクトリに書き込んだファイルの所有者の変更や権限を設定
      8. 新しいタイムスタンプ付きのディレクトリから ..data_tmp の一時的な内部ディレクトリに対してシンボリックリンクを作成
      9. ..data_tmp の一時的な内部ディレクトリを ..data に名前を変更
      10. 新しく作成されたファイルなど必要なら各ファイルから内部ディレクトリ内のファイルへのシンボリックリンクを作成 (e.g. bar -> ..data/bar)
      11. 削除されたファイルの内部ディレクトリ内のファイルへのシンボリックリンクを削除
      12. 古いタイムスタンプ付きのディレクトリを削除
    • この一連の処理の中で、新しくファイルを書き込む必要があって 9. と 10. の間で Kubelet が再起動すると正しくシンボリックリンクが作成されない問題の修正の PR。これまでは 4. でファイルの比較をして更新が不要と判断したら処理が終わっていたが、ファイルを更新する必要がなくても 10. からの処理は必ず通る様に変更している。
Tsubasa NagasawaTsubasa Nagasawa

2024/2/4

  • EKS 1.29 に更新後にノードのディスク使用量が増えたりで Kubelet がイメージ GC を発動し、Sandbox container (pause container) のイメージが GC されてそれ以降 Pod が起動できなくなるやばい問題。EKS で使っている pause コンテナイメージ (602401143452.dkr.ecr.us-west-2.amazonaws.com/eks/pause:3.5) が Private な ECR に格納されていて認証が必要で落として来れなくなる。これまでは AMI の中に ctr pull でコンテナイメージを事前キャッシュとして含んでいたが、ctr pull だとイメージがピン留め (ピン留めすると Kubelet の GC の対象外となる) されておらず、CRI を経由する必要があった。containerd の CRI API を経由するために crictl でイメージをプルする形に変更してピン留めされるようにしている。1.29 に上げてるところまだないと思いますが、修正版の AMI (v20240202) がリリースされているので更新するか、ワークアラウンド (DaemonSet で pause のコンテナイメージを使用する Pod を起動しておいて GC されないようにする) を入れないとですね (awslabs/amazon-eks-ami#1597)
    • ピン留めの機能の cherry-pick は 1.7.3 だから EKS の AMI に同梱されていた containerd だとそもそもハンドリングできなかった。ただ、containerd 1.7.10 まで CRI のピン留め周りの実装が期待通りに動いていなかったっぽいので、AMI も containerd 1.7.2 から 1.7.11 まで更新しているっぽい (containerd/containerd#9381)
    • Kubernetes 1.28 以前は --pod-infra-container-image で指定したコンテナイメージは Kubelet によって GC されなかった。Kubernetes 1.29 からで Kubelet で管理していた Sandbox container のコンテナイメージの管理を CRI (e.g. containerd, CRI-O) 管理に移行した。その影響でこれまで Kubelet が Sandbox container のイメージを管理していた処理をコードベースから削除して、CRI (containerd) 側でピン留めして管理する方式に強制的に切り替えたのが原因。containerd / CRI-O の古いマイナーバージョンにも cherry-pick しているから大丈夫という話だったけど、古いマイナーバージョンの古いパッチバージョンを使っていたら壊れる。--pod-infra-container-image のフラグの非推奨化と処理の削除が同時に行われたのも良くなかったのかも (k/k#118544)
    • GKE の COS は定期的に containerd のバージョンを上げていっているので影響なし。ピン留め周りで Google の人が関わっているのもありそう (cos release notes)
    • Bottlerocket の AMI を使っている場合はまだ修正されていないようなのでワークアラウンドで DaemonSet を起動する必要がありそう (pause コンテナは CRI API からは見えず使っていても削除されちゃうので、明示的に pause コンテナのイメージを使った Pod を起動して消えないようにする) (bottlerocket-os/bottlerocket#3745)
Tsubasa NagasawaTsubasa Nagasawa

2024/2/6

  • MetalLB v0.14.2 で node.kubernetes.io/exclude-from-external-load-balancers のラベルが付いたノードを Service type LoadBalancer の紐付け対象から外すようになり、kind でシングルノードのクラスタを作るとコントロールプレーンとデータプレーンが同一ノードで動くので MetalLB が期待通りに動作しなくなる問題。ノードから手動でラベルを外すのが現状のワークアラウンドで、今後 kind 側で自動的にラベルを削除してくれるようになりそう (kubernetes-sigs/kind#3506)
  • Weaveworks が事業閉鎖。OSS プロジェクトは影響なく継続できるようにするみたいで、Flux は既に他と話し合ってるみたい。Cortex とか eksctl とか大丈夫かな (X)
Tsubasa NagasawaTsubasa Nagasawa

2024/2/7

  • 1.26.6-gke.1900 以降でコネクションの確立に断続的に失敗することが低確率であって、症状が発生してから数日で直るらしい。記載されている GKE のバージョン以降に更新すると問題は起きなくなる。コントロールプレーンとの接続の話なのかワークロードの話なのかよく分からん (release note)
Tsubasa NagasawaTsubasa Nagasawa

2024/2/8

  • KEP-4444: Routing Preference for Service (kubernetes/enhancements#4445)
    • Topology Keys (廃止済み) や Topology Aware Routing の後継の機能で Topology Aware Routing を置き換える予定
    • Topology Keys
      • 同一ノード -> 同一ゾーン -> どこでも、といったルーティングの順序付けをユーザーが柔軟に行えた
      • エンドポイントの過負荷などを考慮してデータプレーンからのフィードバックを元に賢くルーティングを行うことができなかった
      • Topology Keys という名前なのでトポロジー以外の要素でルーティングを決めるといった使い方が敬遠されていたかも
      • 順序付けを自由に行える弊害として、同一ゾーンや同一リージョンと言った使い方を超えて現実的に実装の難しい設定を要求することができてしまう
    • Topology Aware Routing
      • Service に service.kubernetes.io/topology-mode の annotation を指定することで、データプレーンの実装に従ってルーティングが行える
      • 当初、モードとして Auto 以外を指定できないようにした背景は、ユーザーにとって最も理想的で賢いルーティングをデータプレーンが決められるようにするため
      • 賢いルーティングの弊害として、ユーザーによる制御ができず、ルーティングの決定をユーザーが予測することさえ難しくなってしまった
      • 安全性とゾーンベースのルーティングの両立を目指して実装しようとしたが、両方を効果的に実現することはできなかった
      • ユーザーの中にはエンドポイントの過負荷よりも同一ゾーン内でのルーティングによるパフォーマンスの最適化や予測可能性が大事と思う人もいた
    • InternalTrafficPolicy
      • Service の internalTrafficPolicy を Local に指定することで、Pod からのリクエストが同一ノード上の Pod にのみ向かうようになる
      • フェイルオーバーの仕組みがないため、同一ノードに Pod が存在しないとパケットは DROP される
      • InternalTrafficPolicy が提案された当初は PreferLocal ポリシーの実装も検討されていたが破棄された
      • Topology Keys 亡き後、同一ノード -> 同一ゾーン -> どこでもといったフェイルオーバーが可能なルーティングを実現する手段はない
      • Routing Preference for Service でも最初は上記のルーティングを実現できないが、将来的に実装が可能なように考慮した設計を目指す
    • KEP-4444 でやらないこと
      • ユーザーが指定できるのはルーティングのヒントや優先度であって、ルーティングを厳密に保証できる訳ではない
      • Kubernetes Service で指定できる設定は実装によって解釈が異なることがあり、実装者は Kubernetes の標準的なルーティングの設定を全てサポートしなければならないといった制約もない
      • 既存の internalTrafficPolicy や extenalTrafficPolicy を置き換えるものではなく、あくまで補間し合うもの
    • Kubernetes Service に新しく routingPreference のフィールドを追加する (フィールド名は確定ではなく、変更の可能性が高い)
      • routingPreference としてサポート予定 (決定ではない) の値
        • Default: ルーティングの優先度を指定せず、実装に任せたベストエフォート
        • Close: クライアントに最も近いトポロジーを考慮してルーティングを行う
          • 同じノード、ラック、ゾーンあるいはリージョンなどトポロジーの近さの解釈は実装によって異なる可能性がある
      • 実装者は独自の <domain>/<heuristicName> の値を使って、標準的なルーティング以外を実装することも可能
      • データプレーンの実装が進むにつれて最初の解釈から変わる可能性もある
        • e.g.) 最初は同一ゾーンだけを考慮していたが、その後で過負荷も考慮した賢いルーティングに実装が変わった
    • kube-proxy の実装に関しては Default は現在の実装から変化はなく、Close に関しても既存の Topology Aware Routing のヒントや EndpointSlice を使って同じように実装して過負荷を考慮しないシンプルなものになる予定
      • コントロールプレーン (kube-controller-manager の中の EndpointSlice controller) は routingPreference を見て EndpointSlice にヒントを埋め込む
      • データプレーン (kube-proxy) は EndpointSlice のヒントや xTP (internalTrafficPolicy / externalTrafficPolicy) を見てルーティングを決定する
      • コントロールプレーンとデータプレーンはそれ以外のフィールドを考慮しない
    • Topology Aware Routing の場合はイベントだけだったけど、今回は Service の status にルーティングに関する情報が追加される予定
      • RoutingPreferenceAccepted: コントロールプレーンが routingPreference の値をパースして問題がない場合に設定される
      • RoutingPreferenceProgrammed: EndpointSlice コントローラーが routingPreference に従って EndpointSlice のヒントを生成できた場合に設定される
      • 現状はデータプレーンが EndpointSlice のヒントを見て設定したことを示す status はないが、将来的に RoutingPreferenceHonored とかで追加される可能性がある
      • routingPreference を指定しつつ、xTP にも Local が指定された場合は xTP: Local のルーティングが優先される
Tsubasa NagasawaTsubasa Nagasawa

2024/2/9

  • EKS 1.29 で pause のコンテナイメージが GC される問題、Bottlerocket の方でも修正版がリリースされた (v1.19.1)
  • Weaveworks の事業閉鎖に対する AWS の声明 (aws/containers-roadmap#2280)
    • Weaveworks 今までありがとう
    • eksctl は AWS が引き継いで引き続き開発していく
    • 今の高頻度なリリースサイクルは変えない予定
    • eksctl のリポジトリは 2024 年の後半に aws 組織に移す予定
  • Kubernetes 1.27 でアルファ機能として入った KEP-1287 In-place Update of Pod Resources の機能を使って、起動時に CPU を使う JVM 系のアプリケーションの起動時間を早くする kube-startup-cpu-boost を開発した話。Pod のスケジュール時に起動時に必要なリソースを割り当てておいて、起動が終わってから Pod の再起動なしでリソース割り当てを少なくする。リソース割り当てを減らすタイミングは固定の時間指定もできるし、Pod がリクエストを処理できる状態 (Pod condition の Ready が True になったら) になったらといった指定もできる。KEP-1287 はまだまだ不安定 & 機能不足で Kubernetes 1.30 でもアルファのままなので、使えるの当分先ですが (blog)
  • Kubernetes 1.30 の KEP Freeze 発動 (mailing list)
Tsubasa NagasawaTsubasa Nagasawa

2024/2/11

  • EKS で kube-proxy とか vpc-cni とかのアドオンがインストールされていないベアな Kubernetes クラスタを作るオプションを開発中らしい。GKE と棲み分けできていて良いとは思うけど、みんな本当にコアなアドオンまで Helm とかで自前管理したいのかな…。マネージドアドオンの更新すら面倒だけど (comment - aws/containers-roadmap#923)
Tsubasa NagasawaTsubasa Nagasawa

2024/2/14

  • KEP-1287: In-Place Update of Pod Resources の機能を使って Pod 内のコンテナのリソース上限 (resources.limits) を再起動なしに更新しようとしても、cgroup 内にプロセスがいる状態で CPU でもメモリでも cgroup の上限 (Pod 内の実行中のコンテナの resources.limits の合計か initContainers の合計の大きい方) を増やせないので、Pod を再起動して cgroup を作り直す必要がある。これはカーネルの制約。逆に Pod レベルのリソース上限の合計を減らす場合は再起動する必要がない (comment - k/k#122760)
  • etcd の中のバイナリエンコードされたオブジェクトを YAML / JSON / Protobuf に変換して表示したり逆にバイナリエンコードしたりできるツールが etcd-io に寄贈されている (kubernetes/org#4754, etcd-io/auger)
Tsubasa NagasawaTsubasa Nagasawa

2024/2/15

  • GKE で In-tree CSI から Compute Engine persistent disk CSI Driver で作った PVC / PV へのデータの移行方法。Effortless とかいうから期待したけど、GKE Backup でバックアップ取得してリストアしているだけだった。当然ダウンタイムは発生。新規のクラスタだとないだろうけど、前に VictoriaMetrics の数 TB あるデータを vmbackup / vmrestore で Compute Engine persistent disk CSI Driver に移行したな (blog)
Tsubasa NagasawaTsubasa Nagasawa

2024/2/16

  • EKS のマネージドノードグループ、セルフマネージドノードグループ、 Karpenter ノードのカスタム AMI で AL2023 のテックプレビューが開始。systemd cgroup v2 に移行している (X)
Tsubasa NagasawaTsubasa Nagasawa

2024/2/17

  • 個人的に気になる KubeCon 2024 Europe のセッション
    • 全体的に LLM の運用とか活用、マルチクラウド / マルチクラスタ、Platform Engineering、FinOps 関連の話が多め?
    • No 'Soup' for You! Enforcing Network Policies for Host Processes via eBPF - Vinay Kulkarni, eBay
      • 現在の Network Policy は L3 / L4 レイヤーの情報 (Pod の CIDR) を使ってアクセスを制御しているが、ホスト上で動作しているコンポーネント (e.g. kubelet) や hostNetwork を使っている Pod だと制御が難しい。そういったコンポーネントは L7 レベルの認証でセキュリティを担保するのが基本だけど、パフォーマンス影響がある。eBPF を使ってカーネルレベルで処理できるようにしてみた話。パケット毎にホスト上のプロセスの情報を送信して効率的にネットワークを制御する方法をデモを交えながら紹介する。KEP-1287: In-place Pod Vertical Scaling を実装した人で過去の KubeCon で eBPF を使って CPU 負荷の高いコマンド実行のイベントをトリガーにリソース割り当てを調整する話 (Resize Your Pods In-Place With Deterministic eBPF Triggers) をしてた人なので難しい話だろうけど楽しそう
    • Precision Matters: Scheduling GPU Workloads on Kubernetes - Amit Kumar & Gaurav Kumar, Uber
      • Uber の到着時間予測やマッチング、カスタマーサポートの自動化を AI / ML ワークロードで処理しており、Compute Team が GPU on Kubernetes を管理している。NVIDIA Device Plugin と cAdvisor の GPU メトリクスを利用して GPU リソースをどう提供しているか、CPU と GPU の両方が使われるクラスタで GPU の SKUs を考慮したスケジューリングや負荷ベース / ビンパッキングによる効率的なスケジューリングをどう実現しているかを紹介。また、GPU の共有やトポロジを考慮したスケジューリング、AMD や Intel などの異なる GPU のサポートなど将来的にやりたいことについても話す。
    • How Spotify Re-Created Our Entire Backend Without Skipping a Beat - Nick Rutigliano & Daniel de Repentigny, Spotify
      • 既存の Kubernetes クラスタを再作成して 50万台の Pod を移行する必要があり、ダウンタイムが発生すると全世界で報道されるような状況なら何から始めるか?Spotify の Platform Engineer チームが Kubernetes クラスタをゼロから作り直して、ダウンタイムなしでアプリケーション開発者にも影響を与えず、数万台のノードに跨る数百万台の Pod をどのように移行したかの話。移行作業の計画から実行までの流れやその過程で発生した障害についても触れる。この移行を実現できたアーキテクチャの詳細と制限、将来同じような移行作業を行う人たちはこうすべきという助言も。
    • Sharing Is Caring: GPU Sharing and CDI in Device Plugins - Evan Lezar, NVIDIA & David Porter, Google
      • Dynamic Resource Allocation (DRA) や Device Plugins に統合された Container Device Interface (CDI) の話。コスト削減のために使用効率の向上が必要となっている今、GPU の time-slicing や MIG、MPS など GPU のリソース共有を CDI でどう実現されているかを紐解く。
    • Introducing ClusterInventory and ClusterFeature API - Eduardo Arango Gutierrez, NVIDIA & Ryan Zhang, Microsoft
      • SIG-multicluster で話が進んでいる ClusterInventory / ClusterFeature API の話。ClusterInventory API で多様なツールをクラスタに統合・管理しながら、ClusterFeature API でクラスタ固有の機能や属性を公開する。クラスタ間でインストールされているツールの互換性や移行などこれらの API でマルチクラスタ運用がどう変わるか見ていく。ClusterInventory / ClusterFeature API を実装したカスタムコントローラーのデモもあるみたい。
    • Mastering GPU Management in Kubernetes Using the Operator Pattern - Shiva Krishna Merla & Kevin Klues, NVIDIA
      • LLMs を Kubernetes で動かせるようになってきたけど、GPU の利用は必須。GPU を Kubernetes で利用しようと思うと、カーネルドライバーのインストールやコンテナランタイム、デバイスプラグイン、監視などいろんな知識が必要。GPU のソフトウェアスタックのインストールからライフサイクル管理、更新、監視/復旧の 4 つのフェーズに分けることができる。基本的な GPU のセットアップから高度な利用までを Operator パターンで実装するメリットについて NVIDIA GPU Operator を元に紹介。Kevein Klues さんの深い話楽しみ、いつの間にか NVIDIA の Distinguished Engineer になってる
    • OCI as a Standard for ML Artifact Storage and Retrieval - Peyman Norouzi & Eric Koepfle, Bloomberg LP
      • Bloomberg で OCI レジストリに ML のアセットを保存して配布している話。OCI Distribution Specification のレイヤー構造やバージョンやメタデータを使えば、ML のアセット固有の問題も解決できる。Bloomberg では OCI Artifacts をプラットフォームに組み込んでおり、モデルのビルドから配布まで行っているのでそこで学んだことを共有するセッション。
    • DRAcon: Demystifying Dynamic Resource Allocation - from Myths to Facts - Kevin Klues, NVIDIA & Patrick Ohly, Intel
      • KubeCon NA 2023 は DRA がキーノートで出てきたり、Tim Hockin が KubeCon ではなく DRAcon に参加したようだと発言するなど大きな話題を呼んだ。Patrick さんと Kevein Klues さんによる Dynamic Resource Allocation (DRA) の詳細の話。1.26 でアルファ機能として追加されたが、1.29 でもアルファ機能のまま。ベータに昇格するにはコミュニティからの今の実装で良いのか、GPU 以外のユースケース、、Cluster Autoscaler 連携の問題の解決方法に関してフィードバックが必要。
    • Disintegrated Telemetry: The Pains of Monitoring Asynchronous Workflows - Johannes Tax, Grafana Labs
      • メッセージやイベントを介してやり取りする非同期処理のワークフローのテレメトリを収集しようとすると、メトリクスやトレースがバラバラになってメッセージやイベントの一生や影響を推測しづらい。分散トレーシングの世界だとこの問題に親子関係による強い相関や紐付けによる弱い相関で対処できるとしているが、どちらも問題があるので要件によって最善の方法を選ぶしかなく、その選択に役立つ洞察も紹介する。W3C の Context Propagation の草案にメッセージプロトコルの話も盛り込まれていて、OpenTelemetry で定義されたメッセージ向けのセマンティック制約の話も。
    • Dealing with eBPF’s Observability Data Deluge - Anna Kapuścińska, Isovalent
      • eBPF が自動計装やオーバーヘッドの少なさ、完全な可観測性から Observability 界隈でバズっているけど、完全な可観測性を実現するためにシステムから大量のデータを収集している。干し草の山から針を見つけようにも eBPF が更に干し草の山を作る事態になる。実際の運用経験をもとに、データの奔流に対処するための方法を掘り下げる。アプリケーションの監視やセキュリティ領域での利用事例を取り上げて、共通点やベンチマークの結果を紹介。
    • This Won’t Hurt a Bit: Taking Kubernetes to 3,000+ Dental Offices Simply and Securely - Bogdan Mitrea Kevin Reeuwijk, Dentsply Sirona
      • 3000+ の歯医者さん向けの口腔内スキャナー製品の中で Kubernetes が動いている話。GitOps でデバイス管理して、トラブルシューティングやソフトウェアの更新もリモートから行い、スキャン結果をシームレスにクラウド側に転送。低消費電力デバイス上でどう動かしているか、セキュリティの担保どうやっているかの話も。Edge Kubernetes はどこまで行くのか...
    • Squeeze Your K8s: How We Adopt Time-Series Forecasting Models in FinOps Practices? - He Li, Shopee; Nicholas Kwan, Sea Limited
      • Kubernetes は静的に CPU / メモリのリソース割り当てを指定する機能はあるが、過剰割り当てによるクラスタ全体での使用率の低下を生む。調査によるとほとんどの Kubernetes クラスタの平均 CPU 使用率は 20% 未満だった。1.27 から In-place Resource Resize の機能が使えるようになったが、Pod のリソース使用量を正確に予測して割り当て分を完全に使わせるのは難しい。Shopee での FinOps に時系列予測モデルをどう適用したかの事例。時系列予測モデルを使って、長期 / 短期的なスケジューリングを予測しているか、Kubernetes 向けにどうチューニングしているか、サービスのレイテンシに影響せずにオーバーコミットをするにはどうするかなど。
    • Reducing Cross-Zone Egress at Spotify with Custom gRPC Load Balancing - Aleksandar Mitic & Yannick Epstein, Spotify
      • Spotify のインフラコストの大部分がクラウドのゾーンを跨いだ Egress 課金。gRPC の負荷分散アルゴリズムを Open Request Cost Aggregation (ORCA) によるサーバ側のメトリクスを使って、耐障害性やパフォーマンスを維持しつつ賢くルーティングできるようにした話
    • To Infinity and Beyond: Seamless Autoscaling with in-Place Resource Resize for Kubernetes Pods - Aya Ozawa, CloudNatix Inc. & Kohei Ota, Apple
      • inductor さんと ladicle さんの Kubernetes の現状のリソース管理の辛みと In-place Resource Resize の利点の話
    • Lightning Talk: Expand Your Kubernetes Horizons with Multiple Service CIDRs: A Game-Changer for Network Management - Antonio Ojea, Google
      • アントニオさんの KEP-1880: Multiple Service CIDR の話。Service に割り当てる IP 範囲をクラスタ作成後に変更できる機能
    • Lightning Talk: Help! My Envoy Sidecar Is Consuming 8GBs of Memory! - Krzysztof Słonka, Kong
      • 大規模なメッシュを構成している Envoy のサイドカーコンテナが 8 GB のメモリ消費と 30% の CPU 時間を消費していた例をもとに、delta-xds や on-demand-xds などの設定の増分更新のアルゴリズムを解説し、Envoy のリソース消費が高くなった原因を説明する。Kuma、Istio、Consul でこの状況を改善する方法も紹介。
Tsubasa NagasawaTsubasa Nagasawa

2024/2/18

  • Kubernetes では Finalizer でリソースの削除を一時的に止めることはできても、リソースの削除を保護することはできない。Deletion Timestamp が付いたリソースに Finalizer が設定されていても、リソースがいずれ消えることには変わりない。KEP-2839 でリソース削除を保護する仕組みを追加しようとしたが、進展がないなので、Crossplane はリソース削除できないようにするために Usage ってカスタムリソースと KEP-2839 がやる予定だった仕組みを使って独自に実装したみたい。ただ、Crossplane のように依存関係の深いリソースを削除しようとすると、子リソースが消えるまで削除保護で守られ、結果的に親リソースの GC の ExponentialBackoff が 15 分とか長くなっちゃって消えるのに時間がかかる。リソースに変更を加えたら GC の Backoff をリセットできないかの要望 (comment - kubernetes/enhancements#2840)
    • Crossplane の各種クラウドプロバイダーのリソースの所有者 (OwnerReference) に Usage がなって、Usage が消えるまでリソースが GC されないようにする
    • リソースに使用中のラベル crossplane.io/in-use: true を付与する
    • Validating Admission Webhook で使用中のラベルが付与されたリソースに対して DELETE が発行されると 409 Conflict を返す
Tsubasa NagasawaTsubasa Nagasawa

2024/2/20

  • CPU ワークロードと GPU ワークロードが混在しているクラスタだと CPU ワークロード (e.g. 推論システム) はノードに分散して起動させたいけど、GPU ワークロード (e.g. 学習システム) は集約したいから NodeResourceFit scheduler plugin に複数の戦略を設定できるようにしたい要望 (k/k#119849)
    • 以下の方法で回避可能だけど、マネージド Kubernetes だと無理なところは無理だからノード毎 (e.g. CPU or GPU ノード) に NodeResourceFit の戦略を変えられると嬉しいけど、スケジューラーのスコア付の部分は確かにややこしくなりそう
      • セカンダリスケジューラーを用意して CPU / GPU ノードで NodeResourceFit の設定を変える
      • スケジューラーを BinPacking にしておいて、CPU ワークロードに Topology Spread Constraints を強制
  • OpenMetrics はアーカイブされて、Prometheus にアセットなどをマージする予定で進んでいる。Prometheus 形式のメトリクスをベースに標準化を目指したけど、OpenTelemetry のメトリクス形式が主流で、Prometheus も v3 (KubeCon 2024 NA でお披露目予定) で OpenTelemetry メトリクスのサポートを安定化して ingest の機能をデフォルトで有効にする予定らしいのでやむなし (comment - cncf/toc#1242)
Tsubasa NagasawaTsubasa Nagasawa

2024/2/21

  • GKE の Image Streaming でバグがあって現状 Fix がリリースされていないみたいなのでバージョン上げないようにしないと (release notes)
  • 1.26.6-gke.1900 以降でコネクションの確立に断続的に失敗することが低確率であって、症状が発生してから数日で直るらしい問題 (release notes) の upstream の Issue はこれっぽい (k/k#123024)
    • いまだに原因が分かってないけど、GKE 1.26+ で Cloud Provider を in-tree から out-of-tree に移行したら、稀にノードの Provider ID が設定されていない状態でノードが Ready 状態になり、Ingress や Gateway がエンドポイントの登録処理を進められずにアプリでダウンタイムが発生する可能性がある。Provider ID が設定されていないとノードオブジェクトが更新されなくなるので、Topology Aware Routing のゾーン情報の生成にも影響がでる。Provider ID が設定されていないのにノードが Ready 状態になってるのおかしくない?って話みたい。GKE 以外でも out-of-tree の Cloud Provider を使っているところだと発生しうる。
    • 修正版の GKE バージョンは in-tree の Cloud Provider を使うように変更したのかな、それとも Provider ID が設定されるまで Ready 状態にならないように何か変えた?
    • Topology Aware Routing でノードが Ready 状態の時にゾーンのラベルが存在するという仮定はまずくないって別の Issue。k/k#123024 の状態が発生すると、EndpointSlice controller はゾーンのヒントの情報を全ての EndpointSlice から削除して、ノードにその後でゾーンのラベルが追加されても EndpointSlice のヒントは復活しない。Pod が起動したり停止したり EndpointSlice に変更があるとヒントが復活する。Spot インスタンスの利用など、ノードの再作成が激しいと起こりやすい。両方とも GKE の中の人が挙げている Issue で、GKE の中の人がコメントし合っているので緊急度が高そう。ヒントがなくなってもゾーン跨いだ通信が発生するだけで、通信への影響はなさそう?Provider ID がないと Ingress / Gateway のエンドポイントの登録処理が進まない方が影響は大きそう (k/k#123401)
    • 久しぶりにやばいバグでお祭り感がある
    • ノードに Provider ID が追加されたら NEG コントローラーの処理をトリガーするの最近追加されていて、1.27 にも cherry-pick されている。ノードが Ready 状態になった後で Provider ID が追加されたら登録処理を再開できるようにしている? (kubernetes/ingress-gce#2438, kubernetes/ingress-gce#2439)
    • ゾーンの情報を Provider ID から取得しているから空っぽだとどうしようもないのか。ゾーンの情報がないとどのゾーンの NEG に登録するか分からないし (source)
    • で、アントニオさんのこの PR で Provider ID が設定されていない場合はノードの taint を外してノードを Ready 状態にしないようにしているのかな (k/k#123331)
    • dims さんが cc しているから AWS の人もこの問題に気付いている (comment - k/k#123331)
Tsubasa NagasawaTsubasa Nagasawa

2024/2/22

  • Descheduler のメンテナの方に Spinnaker のパイプラインの実行時に突然権限エラーが発生する問題の根本原因を解決したか聞かれたけど、当時は spin-clouddriver-caching を再起動するしかなかったな...。Zendesk はまだ Spinnaker を使っていて、この辛い問題もまだ存在するらしい (comment - spinnaker/spinnaker#6542)
Tsubasa NagasawaTsubasa Nagasawa

2024/2/23

  • また、GKE の Dataplane v2 の Cilium を魔改造している。本家の Cilium CNI に fast-start-namespaces なんてオプションないけど、設定できるようにしようとしている。テストケースで kube-system と default が指定されているけど、何のセットアップを優先しようとしているのか (GoogleCloudPlatform/netd#277)
  • Pod の Lofecycle Hook (e.g. PreStop hook) のアクションで sleep 指定できるようになるの Kubernetes 1.30 でベータに昇格してデフォルト有効になるから、このまま問題起きなければ使えるようになりそう。コンテナイメージの中に sleep のバイナリ含めなくてよくなるやつです (k/k#122456)
Tsubasa NagasawaTsubasa Nagasawa

2024/2/24

  • Kubernetes 1.29 / 1.30 が containerd のどのバージョンと互換性があるのか記載して欲しいという Issue。containerd v2.0 は beta.2 までリリース済みで、Container Runtime Meetup#5 で徳永さんが正式版は今年中に出てきそうと言っていた。ただ、この Issue の書き方だと containerd v2.0 と Kuberneter 1.30 のリリースが衝突して検証時間が十分に取れないことを心配している。RC もまだ出ていないし、4/17 までに containerd v2 が出てくる可能性は少ない?あとは containerd v1.7 のサポート延長の話で、これは徳永さんも触れていたけど最終的にサポート期間が containerd v1.6 の EOL (最速で 2025/2/15) まで延長された。ただ、Kubernetes 1.29 の EOL (2025/2/28) より前なので、Kubernetes 側の移行パスを考慮できていないのではという話になっている。特にクラウドプロバイダーによっては Kubernetes のマイナーバージョンのサポート期間を 2 年に延長しているケースがあるので、現状だと例えば Kubernetes 1.29 のパッチバージョンで containerd v2 に移行するとかいう無茶をやらないといけない (containerd/containerd#9866, slack)
    • containerd v1.7 のサポート期間延長の話 (containerd/containerd#9833)
    • 各クラウドプロバイダーが containerd v2 に移行する Kubernetes のバージョンは結構慎重に様子を見ないとバグ踏む可能性が高そう
Tsubasa NagasawaTsubasa Nagasawa

2024/2/25

  • Linkerd が 2.15 以降でリリースの方法を変えて、CNCF の Graduated プロジェクトとして問題があるのではの議論。GitHub 上でのソースコードの公開はそのままだけど、リリース資材は配布されなくなる。安定版は Linkerd の CLI や Helm chart でインストール可能だが、2024/5/24 以降に安定版の 50 人以上の会社での本番利用が有償になる。安定版とは別にエッジリリース (開発中の最新のコードなので破壊的変更の可能性あり) があって、これは GitHub で OSS として公開されるので無償で使えるし、Apache v2 ライセンスなので商用利用可能。OSS であることには変わりないけど、Linkerd のメンテナが元々の開発元の Buoyant しかいなかったりで Graduated プロジェクトの基準を満たしていないのではって話も出ている (cncf/toc#1262)
    • 大企業のタダ乗りがやっぱ原因かな (blog)
    • The reality is that for the past eight years, billion-dollar businesses have been built on these public stable Linkerd releases without any reason to fund the project or contribute back in any way. That's not a moral judgment or a statement of fairness, but it is a statement of fact. If we want Linkerd to grow and improve dramatically, as we all do—we need to fix that now. This change is key to unlocking that opportunity for us.

Tsubasa NagasawaTsubasa Nagasawa

2024/3/1

  • 何でも良いけどあるリソースのオブジェクト (~ 50KB) を 100 qps で書き込みながら、resourceVersion="" を指定 (etcd から直接読み取る) して 100 並列で watch すると etcd と kube-apiserver のメモリ使用量が高くなりコントロールプレーンが落ちちゃうらしい。Google Cloud で顧客から報告があって調べていて、AWS でも同様の報告があって別の Issue が立てられている。api-server と etcd の間の gRPC の stream を複数の watch で共有しているから過負荷な watch がいると他の watch が十分に stream を使えなくなってエラーが出て壊れる。壊れると watch を再度繋ごうとするが、大量に壊れた watch がいると新しい接続は即座に close されてしまう。で、また再接続を続けることで API Priority and Fairness (APF) による 409 を引き起こすことにもなる (kubernetes/kubernetes#123448)
    • gRPC のメタデータにユニークな値を付けることで明示的に watch stream を共有しないようにする hack があってそれを利用しているっぽいけど、RPC 増えるとそれはそれでメモリ使用量増えないのかな (k/k#123532, comment - k/k#123448)
    • 1 つの stream で watch を共有すると CPU 効率を高めることができるけど、その分スループットは stream の利用者で共有だから低くなるよと。当たり前か。で、今回のメモリ使用量が増えているのはスループットを超えたことで watch が壊れ再接続を繰り返していることが原因なので、watch が壊れないようにすれば緩和できるよねってことか (comment - k/k#123448)
Tsubasa NagasawaTsubasa Nagasawa

2024/3/2

  • Kubernetes がモノレポでのビルドや依存関係の管理を Go の Workspaces 機能を使う形に移行した。これまでは staging リポジトリと modules の共生のために GOPATH を hack して使っていたが、Go の開発チームがそれを好ましく思わずに作ってくれたのが Workspaces の機能 (google groups)
Tsubasa NagasawaTsubasa Nagasawa

2024/3/3

  • まだ ContainerCheckpoint の CRI API を実装しているコンテナランタイムは CRI-O だけだけど、KEP-2008: Container Checkpoint がこのまま何もなければ Kubernetes 1.30 でついにベータに昇格。kubectl checkpoint で操作できるようになる予定なので、サブリソースを分けて node/checkpoint の権限が必要に。ただ、node/proxy の権限があると kubectl proxy で kubelet の checkpoint の API を直接叩けてバイパスできちゃうので、RBAC は正しく制限しないと (k/k#123215)
  • kube-scheduler の Filter 拡張点を実行した結果ノードの候補が残らなかったときに、詳細を diagnosis に書き込む処理が毎回排他ロックを掛けている問題。スケジュール予定の Pod の数 * 既存のノード数のロックが掛かって処理が遅くなるので、排他ロックを掛けなくても良いように修正。報告者のケースだと 9k ノードで 500 Pods/sec で起動するらしい (バッチ処理系だろうけど凄い規模) のでボトルネックになっていた。プロファイルをとって調査したみたいで、修正後に大幅に Pending 状態の Pod の数が減っている (=スケジュール時間が改善された) (k/k#123609)
Tsubasa NagasawaTsubasa Nagasawa

2024/3/4

  • Kubernetes 1.28 で Prometheus Adapter を利用していると OpenAPI のパスが重複エラーになる問題。Prometheus Adapter と metrics-server が同一のパスで /metrics.k8s.io/v1beta1 で異なる OpenAPI のエンドポイントを提供しているのが原因らしい。Prometheus Adapter が Aggregated Discovery の登録方法を間違えている (/metrics.k8s.io/v1beta1/... の登録はあるが、/metrics.k8s.io/ の登録がない) のと Kubernetes 側も登録されている Aggregated Discovery のバリデーションが甘いというのがあったらしい (k/k#122668)
Tsubasa NagasawaTsubasa Nagasawa

2024/3/5

  • kubectl 1.30 から kubectl debug に —custom のフラグが追加されて変更したい箇所の ContainerSpec を JSON 形式で渡すと元の Debug Container 起動時に設定を上書き可能になる。結局事前定義のプロファイルだと、すべてのユースケースをサポートできないので自由にカスタマイズできるオプションが追加された (k/k#120346)
Tsubasa NagasawaTsubasa Nagasawa

2024/3/6

  • Kubernetes 1.30 で Topology Aware Routing の後継の KEP-4444: Service Traffic Distribution がアルファ機能で入りそう。Topology Aware Routing はゾーン毎に Endpoint (Pod) の数に偏りがあるとノードの CPU 数で補正されていたけど、その補正がない純粋な同一ゾーンでのルーティングになる。同一ゾーン内に Endpoint がない場合は、別のゾーンの Endpoint にフォールバックする。Service に新たに追加されるフィールド名は結局 trafficDistribution になり、デフォルトは nil で指定なし扱い。アルファの段階だと PreferClose を指定できるだけで、データプレーン (e.g. kube-proxy, Cilium, …) によって解釈は異なる。kube-proxy の場合は↑で書いた挙動になる。(k/k#123487)
  • ExecProbeTimeout の FeatureGate を Kubernetes 1.30 で完全に消して無効化できないようにしようとしている。GKE ではデフォルト有効なところを FeatureGate で明示的に無効化しているのは知らない人多そう。LivenessProbe の ExecProbe の処理がタイムアウトするようになると急に Pod が再起動し始めて困る顧客が結構いる。ExecProbe の実装を変えろ以外に移行パスがないから、Google としても顧客に強く言えなかったんだろうな。AWS と RedHat Microsoft の人が FeatureGate で明示的に無効化しているユーザーなんていないだろうと思って消す気満々で進めていたら、Google の人が止めに入ってて面白い。顧客影響あるしすぐに消す必要もないでしょって (k/k#123574)
    • ExecProbeTimeout は本来バグで Probe で Exec を指定した場合だけタイムアウトが無視されちゃってたんですよね。で、バグに依存しちゃったユーザーがいて破壊的変更になっちゃうパターンなので本当に難しいですよね。
      KEP-1972: kubelet exec probe timeouts の提案と実装も Google の人だし、提案の時点で一部のユーザーにとっては破壊的変更だってことは書かれているので、移行パスを準備できずに放置してたっぽいです。タイムアウトの時間を超えた場合に警告の Event を書き込むようにしてユーザーに実装を確認するよう周知して、数バージョン待って削除とかしかやりようがなさそう
Tsubasa NagasawaTsubasa Nagasawa

2024/3/10

  • Ephemeral Storage の上限を超えて使い続けるとしばらくして Pod が Evict されるけど、Pod の状態が ContainerStatusUnknown になっちゃう問題。Evict された後に Pod を削除するときに、①コンテナランタイムがコンテナを停止 (このタイミングでは削除はしない)、② コンテナランタイムからコンテナの状態を取得して Pod の状態を更新する。①と②の間でコンテナ削除のタイミングで競合が起こり、コンテナの状態を取得しようにも既に消えていて ContainerStatusUnknown になる。Pod の状態は Failed になっているので、Pod IP が再利用されようが実害はないが、Otel collector では問題があるらしいが詳細は不明 (k/k#122160)
  • GKE の Ingress / Gateway API の 502 / 503 エラーの対処法のドキュメントの記載がかなり詳しくなっている。最近だと BackendService の Drain Timeout が Ingress / Gateway API で設定できるようになったので設定すると 503 を回避できる。preStop Hook で sleep と併せれば 502 エラーも回避できる。Backend Service の Drain Timeout の値はリクエストの処理時間の 1.5 から 2 倍が目安。 BackendService の Drain Timeout を設定しない場合と設定する場合で挙動が異なる。BackendService の Drain Timeout を設定しない場合は NEG controller が Endpoint を NEG から Detach するまでの時間差を気にする必要がある。BackendService の Drain Timeout を設定する場合は、Drain 開始までの時間差 + Drain Timeout を考慮する必要がある。Drain 開始までの時間差は 1 分を見た方が良いってあるけど、preStopHook >= Backend Service Drain Timeout + Drain Latency だとすると preStopHook の sleep の時間結構長くなっちゃうじゃん (docs)
Tsubasa NagasawaTsubasa Nagasawa

2024/3/11

  • EKS の vpc-cni の v1.16.3 に CPU 使用率が高く張り付くバグがあるので注意です。EKS のマネージドアドオンを利用している場合、東京リージョンに v1.16.4-eksbuild.2 がもうロールアウトされているのでそちらに切り替えると良さそう(aws/amazon-vpc-cni-k8s#2807)
Tsubasa NagasawaTsubasa Nagasawa

2024/3/15

  • Karpenter を EKS Access Entry API での認証に移行するときに system:bootstrappers の Kubernetes Group の紐付けが必要ない理由 (comment - aws/karpenter-provider-aws#5369)
    • TLS Bootstrap の処理で使用するトークンを取得するための権限が入っているが、EKS は証明書ベースの認証を許可しておらず、IAM を使って認証するのでこの権限は不要
      • Kubernetes API サーバに Bootstrap トークンで一時認証をして証明書署名要求 (CSR) を送信し、コントロールプレーンで CSR リクエストに署名する流れで使う
    • kubelet サービング証明書の要求で使う権限も含まれているが、EKS では eks:node-bootstrapper という ClusterRoleBinding があり、system:nodes の Kubernetes Group が kubelet のサービング証明書の要求ができるように許可しているので不要
    • system:nodes の Kubernetes Group に紐付いた IAM ロールを用意すれば良い (EKS ノードに紐付けた IAM ロールを Karpenter でも共有して使っている場合は、自動的に system:nodes の Kubernetes Group と紐づくのでこの対応も不要)
Tsubasa NagasawaTsubasa Nagasawa

2024/3/18

  • kubectl run -it で Pod を起動してインタラクティブにコマンドを実行すると実行結果も含めて Pod のログとして書き込まれてしまう件について、せめて kubectl run -it 実行時に警告文を表示しようという Issue。kubectl run -it --rm の組み合わせはやりがちなので気をつけないと (k/k#123967)
❯ kubectl run -it --rm debugger --image alpine -- ash
If you don't see a command prompt, try pressing enter.
/ # ls
bin           home          mnt           product_uuid  sbin          tmp
dev           lib           opt           root          srv           usr
etc           media         proc          run           sys           var
/ # pwd
/
# Pod のログ
❯ stern .
+ debugger › debugger
/ # ls
^[[3;23Rdebugger debugger bin           home          mnt           product_uuid  sbin          tmp
debugger debugger dev           lib           opt           root          srv           usr
debugger debugger etc           media         proc          run           sys           var
debugger debugger / # pwd
debugger debugger /
  • 調査で API トークンとか DB のパスワードとかコンソールに書き込むと kubectl logs や Cloud Logging とかで見れちゃう。例えば、以下のコマンドとか叩くとまずい

    curl -u username:mypass http://example.com/
    
  • kubectl run の後で kubectl exec の場合は大丈夫

    kubectl run debugger --image alpine --command -- sleep infinity
    kubectl exec -it debugger -- ash
    
Tsubasa NagasawaTsubasa Nagasawa

2024/3/19

  • readinessProbe は successThreshold を 1 以外に設定できるけど、startupProbe と livenessProbe は successThreshold を 1 以外に設定できても良くないという要望に対する答え (comment - k/k#106025)
    • Pod 起動直後の unknown 状態と probe に一度でも成功した後で失敗した trouble 状態は別物として考える
    • Pod 起動直後の unknown 状態での successThreshold は alive と判定するまでの閾値なので意味はありそう
    • Pod が trouble 状態になると、successThreshold の閾値がハードルとなって alive / trouble を行ったり来たりする可能性があるが、その間は Pod が再起動されることはない
      • successThreshold が 5 で failureThreashold が 3 の場合、trouble 状態から 4 回 probe に連続成功していても trouble 状態のまま
      • 現状の successThreshold が 1 で固定の場合でも、trouble 状態か alive 状態かという違いだけで probe に失敗している間は閾値の回数を超えない限り Pod が再起動されることはない
    • trouble 状態の時は probe の失敗の回数をリセットしないのはどうか
      • successThreshold が 5 で failureThreashold が 3 の場合を考える
      • alive 状態から 1 度 probe に失敗して trouble 状態に遷移し probe の失敗回数が 1 となる
      • 次の probe に成功すると成功回数が 1 となるが、trouble 状態のまま
      • そもまま probe に成功して成功回数が 4 回となってもまだ trouble 状態のまま
      • probe に失敗すると失敗回数が 2 となり、成功回数がリセットされる
      • また probe に連続で 4 回成功すると、成功回数が 4 回で失敗回数が 2 回
      • 次の probe に成功すると alive 状態に遷移するし、失敗すると失敗回数が 3 回となるので Pod が再起動される
+-----------+     +---------+                 +-------+
|           |     |         |                 |       |
| (re)start |---->| unknown |--(succeed 1x)-->| alive |<---+
|           |     |         |                 |       |    |
+-----------+     +---------+                 +-------+    |
     ^                 |                          |        |
     +--(fail 3x)------+                      (fail 1x)    |
     |              +---------+                   |        |
     |              |         |<------------------+        |
     +--(fail 2x)---| trouble |                            |
                    |         |--------(succeed 1x)--------+
                    +---------+
Tsubasa NagasawaTsubasa Nagasawa

2024/3/23

  • How Spotify Re-Created Our Entire Backend Without Skipping a Beat (youtube)
    • Spotify は 3,200+ のマイクロサービスがピーク時に 40,000+ VM (コア数は 1M+、メモリは 4 PB+) 上で 500,000 Pod が動作し、1.5 TB/s の通信が発生する
    • Spotify は複数 Kubernetes クラスタでのマルチテナント構成で、同じクラスタをずっと in-place で更新し続けてきた
      • クラスタ数は僕らが思っているより少ないらしい
    • 開発者は基本的に Golden Path (チュートリアル) に従って本番環境にアプリケーションをデプロイしているが、半分くらいは Golden Path から外れたサービスやパフォーマンスの最適化のために設定が異なるサービス、定期実行のジョブなどがある
      • 開発者は namespace レベルで Kubernetes API を叩くことができるので、Golden Path に従っていないサービスもデプロイできてしまう
    • Spotify ではこれまで Compute as the Product の考え方でプラットフォームを提供してきた
      • Kubernetes のことをそれほど気にしない開発者は Golden Path に従ってサービスをデプロイできれば良い
      • 最適化のために YAML を触りたいユーザーもいる
      • Operator を書いたり、専用のクラスタが欲しいといった Cluster as the Product を望むユーザー層もいるが、それらはサポートしていなかった
        • namespace 内での権限しかないからクラスタワイドな CRD とかのリソースを作れない感じかな?
    • Cluster as the Product のユースケースにも対応するため、既存のクラスタを再作成することにした
      • Compute as the Product と Cluster as the Product で求められるものが違う
      • Kubernetes API へのアクセス方法やクラスタ更新などの考え方が変わってくるし、ガバナンスの適用が難しくなったり、GPU などのアクセラレータを使いたいといった要望にも対応する必要がある
      • 逆に SLA やコスト効率に関しては同レベルのものが必要だったりする
        • 信頼性を高めるということはコストも掛かるので、コストを取るか信頼性を取るかはプラットフォームを作っていく上で重要な判断材料
    • 新しいクラスタのアーキテクチャ検討
      • Global Load Balancer を前段に置いてリージョン内に複数の Kubernetes クラスタを作ってサービスを動かし、ユーザーから近いリージョンのサービスに接続できるようにする
      • 同一リージョン内に複数の Kubernetes クラスタがあるが、同一リージョン内のクラスタ間通信は Headless Service を介して行える
        • クラスタ間通信を実現するためのサービス検出の仕組み (Headless Service に Pod IP を紐付ける処理) はクラスタ外でやっているらしい
        • これにより、新しくクラスタを追加しても既存のクラスタのあるサービスから別のサービスへの接続ができる
      • 複数クラスタ化を実現するためには homogeneous なクラスタにする必要がある
        • コア API (クラスタ更新のケース?) やカスタムリソース、GPU などのアクセラレータがクラスタに関わらず利用できなければならない
        • サービスのデプロイツールや監視・アラートのツールが複数クラスタ対応する必要がある
    • 既存のクラスタで動作するワークロードの対応
      • Backstage のソフトウェアカタログでどういうワークロードが動いているか分かる
        • プラットフォームチームは全てのワークロードの全ての要件を把握しているわけではないので、特殊な要件のあるサービスは Backstage で詳細を確認して移行をサポートする
      • 新規のサービスに関しては Golden Path のテンプレートを更新して、利用している言語やフレームワーク向けの最適な Kubernetes の設定を提供する
      • 既存の昔から動いているようなサービスの設定変更 (e.g. HPA の挙動、API の非推奨化) は 内製の Fleet 管理ツールで動的に反映する
      • Keyverno でガバナンスの適用と動的な設定の差し込みを行う
        • クラスタやリージョン固有の設定を Keyverno の Admission Webhook の機能で注入している
    • サービス影響のない移行の自動化
      • 手動でやると人的ミスがあるし、自動化してもコードのバグがあるかもしれないので、安全に移行する仕組みが大事
      • 移行の各ステージで冪等性を担保
        • サービス毎にクラスタを跨ぐ移行を開始しても大丈夫かをチェック
        • 移行作業中にサービスのコード変更が入らないように一時的にサービスのバージョンを固定化
        • コストは掛かるが、新旧のクラスタにサービスをデプロイ
        • 新旧のクラスタでトラフィックを切り替え
        • 旧クラスタのリソースを削除
        • サービスのバージョン固定を外す
      • クラスタ切り替えを決めたのはプラットフォームチームなので開発者の対応は必要ない形で移行できるようにした
    • 質問コーナー
      • Keyverno をどう利用しているかもう少し詳しく
        • 180 のリージョンでサービスを展開しているので、リージョン毎に法令が違って配信できるコンテンツも違うのでそういった設定を Mutating Admission Webhook で差し込んでいる
        • Validating Admission Webhook の機能で requests.memory == limits.memory などのベストプラクティスの確認
      • どうやって開発者の関与なしに移行を完了できた?
        • 各種デプロイのツールは各サービスのソースコードのあるリポジトリへのアクセス権限を持っていて、API 経由でサービスのデプロイもできるので、それを移行ツールでトリガーするだけで良かったし、終わったら Backstage でユーザーにお知らせした
      • Headless Service でのマルチクラスタの疎通はどうやったか?
        • サービス検出の機能がクラスタ外にあるけど、それ以外のネットワークの詳細は話せない
        • この感じ MultiCluster Services は使っていなさそう?
      • Kubernetes 上で動かしているデータベースも移行したのか?
        • データベースはマネージドサービスを使っていて移行していない
      • 移行前のチェックって何を確認していたの?
        • サービスの正常性の確認、サービスが正常な状態じゃなかったら開発者に通知して正常になってから移行していた
      • Kubernetes クラスタはどこで動いている?ベアメタルや仮想マシン上?
        • Google Cloud を使っているのでオンプレではなく、GKE
      • CD 関連でマルチクラスタへのデプロイやクラスタ移行にどういうツールを使ったか?
        • 内製のツールが多いが、Config Sync や Argo CD などの OSS のツールも使っている
      • Cluster as the product に関して、クラスタの管理者権限をユーザーに渡すことになるが、安定性や信頼性との線引きをどうしているか?
        • 専用の Kubernetes クラスタを使いたいユーザーは Kubernetes に関する深い知識を持っているので、ある程度信頼している。クラスタの更新に関しては Compute チームのメンバーが面倒を見たりはしているみたい。今の規模ならこれでも上手くいっている
Tsubasa NagasawaTsubasa Nagasawa

2024/3/26

Space-Age GitOps: The Rise of the Humble Pull Request - Zach Aller & Michael Crenshaw, Intuit

  • GitOps による CD のフローの中で変更の提案、プロモーション、変更の切り戻しを Argo CD と PR をベースに改善したい話
    • 変更を提案して、(レビューを受けて)、変更がデプロイされて、変更を dev -> stg -> prd とプロモーションして、メトリクスやログを関して問題が起きたら切り戻すのが一連の CD のフロー
    • GitOps による CD のフローの中で Argo CD は変更のデプロイの部分を担っている
  • Helm の values ファイルや Kustomize の overlay などの設定が一部変更された PR を出されても、実際にどういう差分になるのか分からず、approve して良いか分からない
    • ローカル環境に PR の変更をフェッチしてきて、マニフェストを生成してみて確認してみる
    • Argo CD の自動同期の機能を OFF にして、Argo CD の UI で差分を確認する (会場でも笑いが出ていたようなので結構みんなやっているみたい)
  • Jenkins などで dev -> stg -> prd 環境へのプロモーションのワークフローを組んでも、開発者が知らなくても良いプラットフォームの実装の多くを見せてしまっており、問題が起きた時にどう対処して良いか分からない
  • プロモーション中に変更を切り戻しに関して、Argo Rollouts を使っていても分かるのは Pod に対する変更のみで、Service のラベルセレクタの間違った変更が加わったりすると検知はできない
    • Argo CD の History and Rollback の画面から変更を切り戻そうにも、過去のどのコミットが正常な状態なのか UI から分からないので、切り戻し先のコミットを特定するのに時間が掛かる
    • 問題が起きた PR のコミットを revert しようにも、生成されるマニフェストの差分は表示されないので本当に正しいのかよく分からない
  • 上記の問題を解決するために Argo CD に追加する機能の案
    • Argo CD の Controller がメインのブランチを元に各環境のブランチを作成し、そこに生成したマニフェストを置く
    • 開発者が PR を作成すると、各環境のブランチに対してマニフェストを生成して差分のリンクを PR のコメントに貼ってくれる
    • 開発者が差分を見て問題ないことが確認できたら、PR をマージする
    • PR をマージすると Controller が各環境毎にプロモーション用の PR を作成する (マージしたコミットの Git ハッシュを PR タイトルに含む)
      • PR は本来 3 つ (dev/stg/prd) 作成されるが、dev 環境の PR は既に自動でマージされている状態
    • PR のコミットステータスを使って徐々に環境にプロモーションされるようになっている
      • stg 環境へのプロモーションは dev 環境への反映で問題が起きないかをコミットステータスを使って待っている状態
    • コミットステータスでのチェックは色々とカスタマイズできる
      • e.g.) 変更がマネージャーに承認されている
      • e.g.) マニフェストの静的解析をパスしている
    • Argo CD のプロモーションの画面 (スクショの中の画面はかなりラフなモック) で今どこまで進んでいるか確認できる
    • プロモーション中に問題が起きた時の切り戻しも Controller が自動的に PR を作成してくれる
      • PR の中にマニフェストの差分があるので確認してマージすれば良い
  • 質問コーナー
    • Kargo との違いは何?
      • Kargo は CI パイプラインを使って、Kustomize や Helm を使って新しいバージョンのイメージタグを埋め込む戦略
      • 今回の提案は複雑な CI パイプラインを開発者に見せずに、既存の触り慣れたインターフェイス (Git や GitHub など) でやれないかという話
      • Kargo は今回の Argo CD への提案と相反する訳ではないし、共存もできるかもしれない
    • 環境毎にブランチを分ける必要があるの?
      • 人間 (開発者) はディレクトリ毎に環境を分ける運用で良い
      • Argo CD の Controller が環境毎に生成したマニフェストを含んだブランチを作成するだけ
Tsubasa NagasawaTsubasa Nagasawa

2024/3/27

Pod Scheduling Readiness の仕様に関する指摘

KubeVirt の人が .spec.nodeName が指定された Pod に Pod Scheduling Readiness を差し込めないのなんでか聞いている (comment - kubernetes/enhancements#3521)

  • 特定の namespace に Pod が作成されたときに Mutating Webhook で Pod Scheduling Readiness を差し込むようにしたが、ある Operator が Pod の .spec.nodeName を指定した Pod を作り、その Pod にも Mutating Webhook で Pod Scheduling Readiness を差し込もうとしてエラーになったっぽい
  • Pod の .spec.nodeName にノード名を指定すると、Pod のスケジュールは終わっていて指定したノードで起動する準備ができていることを意味するけど、Pod Scheduling Readiness が指定されると Pod はまだスケジュールの準備ができていないことを意味するので矛盾しちゃう
  • どのノードでスケジュールするか決まっているなら .spec.nodeName は本来 .status.nodeName にするべきでは?.spec.nodeName で指定できちゃうと、ユーザーがこのノードで起動したいという意図でこのフィールド使っちゃうじゃん -> 特定のノードで起動したい場合は Node Affinity の NodeSelectorTerm でmetadata.name にノード名を値として指定するようにしましょう (DaemonSet もそうしている)
  • 歴史的に status フィールドはどこかからリストアできる情報だけを置く場所として使われていた時期があり、nodeName はどこからもリストアできない情報なので .spec.nodeName となった。今は status フィールドにしかない情報も多くあるので .status.nodeName であるべきかもしれないけど破壊的変更になるから無理
  • 破壊的変更を気にしなくて良いなら .spec.nodeName は強い RBAC で守られるべきだけど、難しい。.spec.nodeName は Kubernetes の初期からあり、RBAC は Kubernetes 1.6 から入ったので最初から考慮するのはそもそも無理だった
  • .spec.nodeName は一度設定されると値を消すことができない
  • .spec.nodeName を明示的に指定すると kube-scheduler と競合してスケジューリングの結果に影響することがある。DaemonSet が NodeAffinity を使っているのもこれが理由
  • .spec.nodeName が指定されていてもノードの割り当て可能なリソースを超えてリソース要求を指定すると、OutOfCPU になって Pod が起動できないじゃん -> 最終的に kubelet の Admission でノードで起動できるか判定されて拒否されることはある。ただ、結果がどうであれそのノードで Pod を起動しようとはしている
  • kubelet も自身のノードで起動する Pod を監視する (watch する) 時に .spec.nodeName で絞っているから、.spec.nodeName が指定された時点でそのノードにスケジュールはされているし、そのノードで Pod を起動し始める
Tsubasa NagasawaTsubasa Nagasawa

2024/3/29

SIG-etcd での etcd-operator の開発

新興の etcd-operator (aenix-io/etcd-operator) が SIG-etcd のサブプロジェクトに名乗りを上げている (kubernetes/community#7796)

  • 先週の KubeCon EU で etcd-operator 開発を再始動しようという議論があったらしい
    ロシア語圏の方たちが中心になって数週間前から開発が始まった etcd-operator のメンバーがせっかく作るならいろんなユースケースを取り込みたいということで声を上げたみたい
  • etcd-operator は色々なところで開発されていて Kubernetes 上で動かすなら coreos/etcd-operator が機能的には優れていたけど、結構前にアーカイブ済み。ただ、IBM などフォークして開発を続けているクラウドプロバイダーもあるらしい
  • OpenShift は openshift/cluster-etcd-operator を作っていて RHEL / CoreOS のホスト上で static Pods として動く単体の etcd のライフサイクル管理のためのもので、OpenShift のインフラや API に強く依存している
  • 他にも Gardener (SAP) が Gardener 向けの etcd-operator を作ったり、すでに開発が止まっている個人プロジェクトがいくつかある状態
  • それとは別に SIG-cluster-lifecycle が etcdadm というツールを開発していて、kOps で使われてきた etcd-manager とまた別の本番利用可能な状態の etcdadm を合体したもので、Kubernetes 以外でも動くので Operator とは言えないし、Kubernetes 以外で動くのが強み (GKE はこれ使ってそう?)
  • どのツールも etcd を熟知しているメンテナが関わっていないし、ツールの開発者も etcd のコミュニティに積極的に関わってきていないのが問題 (たぶん品質の話とコミュニティの要望が含まれていないオレオレ実装ばかりってことを言いたそう)
  • 新興の etcd-operator よりも成熟したプロジェクトをベースにした方がいいのではという指摘があるが、SIG-etcd のメンバーの一人はどのプロジェクトをベースにするとかは関係なく etcd のメンテナが関わること、etcd コミュニティの声を聞きながら開発が進められることが重要というスタンス
  • 今後の SIG-etcd のミーティングでどのプロジェクトをベースに進めるか議論していくみたい。Datadog が内部で使っている etcd-operator を OSS 化してベースにする案もあるらしい
Tsubasa NagasawaTsubasa Nagasawa

2024/3/30

kind with GPU

NVIDIA の klueska さんがいろいろ試してできた kind のコードベースに変更を加えずに NVIDIA GPU を使うためのサンプルリポジトリ (klueska/kind-with-gpus-examples)

GKE の Workload Identity 連携の改善

GKE の Workload Identity 連携が改善されて Google Cloud のサービスアカウントを作らずに Kubernetes のサービスアカウントを直接メンバーとして権限を紐づけられるようになったらしい (X)

Tsubasa NagasawaTsubasa Nagasawa

2024/3/31

NetworkPolicy の参照実装

アントニオさんの新作の Kubernetes の Network Policy の E2E テストで使う用のシンプルな Network Policy の参照実装。今は Kubernetes の CI で Network Policy の挙動を確認するために Calico が使われているが、サードパーティのツールだとデバックが難しいので自作している (aojea/kube-netpol, k/k#124117)

  • 一般的な Network Policy の実装は、Network Policy の API リソースを解釈するコントロールプレーンと iptables や nftables のルール、eBPF のフックの差し込みや eBPF Map を管理するエージェントに分かれる
  • kube-netpol は Node 上で動作するエージェントのみで、パケットのフィルタリングの処理をユーザー空間で行うという違いがある
  • kube-netpol は iptables の Filter テーブルの FORWARD / OUTPUT チェイン (パケットが Node から外に出る前のフック) にルールを追加して、NFQUEUE にパケットを渡すようにする
  • kube-netpol は NFQUEUE に接続して、フィルタリングの処理を登録する
    • 現状はヘッダーの情報のみでフィルタリングし、ペイロードの情報は使わない
  • フィルタリングの処理の中で渡されたパケットの IP や TCP / UDP / SCTP ヘッダーから 5-tuple をパースし、Network Policy で許可されているか検証して ACCEPT / DROP を判定する
    • ACCEPT の場合は後続のチェインの処理を継続する
  • Network Policy の CIDR 指定も名前付きポートも対応しているみたいだし、一通り動作しそう
  • Pod Informer に Pod IP でインデックスを貼って Pod IP から対象の Pod の情報を効率的に参照できるようにしている
    • ソース IP から送信元の Pod の情報を、宛先 IP から送信先の Pod の情報をそれぞれ取得し、Pod の情報から namespace 内の全ての Network Policy を取得して、許可されているか確認していく
  • Pod 間でネットワークのやり取りを開始する最初のパケットに対して 5-tuple の抽出 -> Network Policy で許可されているかのチェックが入り、それ以降は conntrack の仕組みでバイパスできるのでパフォーマンスに凄く影響するということはないらしい
  • とはいえ、Network Policy が設定されているされているいないに関わらず、パケットのフィルタリングをユーザー空間で行なっているので、初回のパケットはパフォーマンス影響を受ける
    • E2E テストで挙動を確認するためなら十分だし実装がシンプル
    • NFQUEUE にパケットを渡すのを Network Policy が設定されている Pod に制限すると今の実装よりパフォーマンス改善できる
Tsubasa NagasawaTsubasa Nagasawa

2024/4/1

External Secrets Operator で利用するプロバイダーが選択式になる予定

External Secrets Operator で利用するシークレット管理サービスの設定のみをインストール & Controller もクライアントを初期化するようになるっぽい (external-secrets/external-secrets#2655)

  • ユーザーはこれまで通り SecretStore の .spec.provider にプロバイダーの設定を書く
  • External Secrets Operator で SecretStore / ClusterSecretStore の .spec.provider を読み取って内部的にそれぞれのプロバイダー毎にクラスタレベルの Provider カスタムリソース (e.g. gitlabs.providers.external-secrets.io) に変換し、認証情報などの設定を保存する
  • SecretStore / ClusterSecretStore に .spec.providerRef のフィールドが新しく追加されて、External Secrets Operator がクライアントの初期化時にその設定を読み取る
    • 互換性担保のため、SecretStore / ClusterSecretStore に .spec.providerRef が設定されていない場合は、.spec.provider からプロバイダーを特定して .spec.providerRef を設定
  • SecretStore / ClusterSecretStore からプロバイダーの設定をカスタムリソースに分離することで、プロバイダーの追加や認証方法の追加などで SecretStore / ClusterSecretStore に変更を加えなくて済む
    • External Secrets Operator の対応プロバイダーは今後も増えるる中でコア機能を GA していくために必要な分離
  • 利用しているサービスのクライアントを初期化するだけに変わるので、メモリのフットプリントを減らせる
  • 将来的に SecretStore の廃止か SecretStore の .spec.provider は検討しているみたい
Tsubasa NagasawaTsubasa Nagasawa

2024/4/2

EKS での Amazon Linux 2023 のバグ

EKS で Amazon Linux 2023 への切り替えを検証中に、一部の Pod が Kubernetes の API サーバへの接続でタイムアウトして起動できなくなっていたのバグだったみたいで、awslabs/amazon-eks-ami#1738 の修正が入ると直るらしい。systemd.network と VPC CNI plugin で管理している設定が競合して VPC CNI plugin が設定したセカンダリ ENI のルーティングルールとかを上書きしたりしちゃうみたい?EKS 利用している方はまだ Amazon Linux 2023 の AMI に切り替えない方が良いです。(awslabs/amazon-eks-ami#1737)

EKS の Network Policy で名前付きポートの指定で動作しない問題が解消

https://zenn.dev/link/comments/902ecc684f8652 の修正が最新の EKS のプラットフォームバージョンにロールアウトされて問題なく動作するようになった。

Tsubasa NagasawaTsubasa Nagasawa

2024/4/3

WG-Serving の立ち上げ

Making Kubernetes great for accelerated workloads: a serving working group

  • 大規模モデル (Generative AI) のアクセラレータ (e.g. GPU) を利用した推論用のワークロードの改善を目的とした WG-Serving ができる
  • Kubernetes で大規模モデル (Generative AI) 向けの学習や推論のワークロードを動かす需要は高く、ここ数年間は WG-Batch で学習のための大規模バッチ処理の改善が進められ、SIG-Node を中心に Dynamic Resource Allocation (DRA) の開発が推進されてきた
  • 推論に関しての議論は発散しがちで、最優先で検討もされて来なかったので、WG-Serving を立ち上げてシンプルで安定性のある、効率的にアクセラレータを利用した推論のワークロード議論を進めていきたい
  • LLM のワークロードは Node とほぼ同じリソース割り当てで 1:1 でデプロイされたり、1 台で複数のノードに跨って実行されることが多いため、Node のスケールアウトが必要で通常の Web アプリに比べてワークロードの起動に時間が掛かる
  • 現状の GenAI の推論のワークロードは StatefulSet を使っていることが多いが、推論のワークロードの要求を満たすために設計されたリソースではない
  • WG-Serving に関しては KubeCon EU で議論があったらしい
  • WG-Serving の目的
    • 他の様々な SIG や WG に寄せられた推論のワークロードに対する要望をまとめつつ、コミュニティからも推論のワークロードの要件を集める
    • Kubernetes のコントローラに手を加えて、アクセラレータ利用の改善や推論やモデルの提供でよく使われるフレームワークへの対応を進める
    • kServe や Seldon, Kaito などの既存のエコシステムと連携して、既存の Kubernetes の共有の問題点を特定して改善まで持っていく
      • Kueue が様々なバッチ処理向けのフレームワークのスケジューリング部分を抽象化したように
    • 推論のワークロードの管理や自動スケール、負荷分散を改善するプロジェクトを新しく立ち上げる
  • WG-Serving のユースケース
    • 複数の Node に跨って推論のワークロードを実行するために LeaderWorkerSet という新しいカスタムリソースとコントローラーが提案されている
    • アクセラレータを利用した推論のワークロードの自動スケールはコストの観点で非常に重要だが、対応が十分ではないし、何より起動までに時間が掛かる
    • 検証環境で推論のワークロードを動かすときに、中断は許容できないけど、使っていない時は 0 台にスケールインしたいとかアクセラレータを共有してリソース効率を高めたいといった要望がある
    • アクセラレータを複数のクラウドで同じように利用するのが難しい
    • アクセラレータを利用した大規模なワークロードは中断に脆く、起動は遅いので、中断に対してより保護的な仕組みが求められている
  • WG-Serving に関わる SIG は SIG-Apps を主として、SIG-Architecture, SIG-Node, SIG-Scheduling, SIG-Autoscaling, SIG-Network, SIG-Storage と多岐に渡る

WG-Accelerator-Management の立ち上げ

WG-Creation-Request: WG Accelerator Management

  • 業界内でもアクセラレータの効率的な利用が求められる中、Kubernetes におけるアクセラレータ利用の改善が急務なので、WG を立ち上げて既存の API やモデル、スケジューリングのアルゴリズム、自動スケールなどを再検討する
  • これまでは WG-Batch の中で Dynamic Resource Alloaction (DRA) の KEP を中心に取り組んできたが、AI の推論サーバなどバッチ処理以外のワークロードでもアクセラレータは利用されるので、WG-Batch や WG-Serving と協力して要望を聞きながら進めていく
  • KubeCon Europe 2024 で議論があったらしく、バッチ処理以外でアクセラレータを利用している人たちからコンタクトがあり、一緒に改善していこうと協力的だったので WG を立ち上げることに
  • WG-Serving とは違って低レベルの API の提供や抽象化を目指し、バッチ処理や推論のワークロードでアクセラレータを設定、共有できるようにすることに集中する
  • WG が解決する課題
    • アクセラレータのリソースプールをワークロード間で効率的に共有したり、個々のデバイスを分割して効率的に共有できるように
    • クラスタの詳細に立ち入らずに (管理者がどうクラスタをプロビジョニングしているかによらず)、利用者がアクセラレータを利用したワークロードを実行できるように
    • スケジューラがワークロードを動かす Node を正確に選べるように
    • 自動スケールや自動プロビジョニングのツールがワークロードを起動するのにどの Node をスケール or 作成すれば良いか事前に予測できるように
    • 「Pod が Node で動く」から「ワークロードがリソースのキャパシティを消費する」に転換させ、複数の Pod をアクセラレータを持った複数の Node で起動できるようにする
    • ハードウェアの故障によるワークロードの中断を最小限に抑える
    • アクセラレータの分割による断片化の問題を解決する
    • 上記の課題を解決するために、既存の API を良い感じに拡張したシンプルな API として提供し、簡単に移行できるようにする
Tsubasa NagasawaTsubasa Nagasawa

2024/4/4

Pod の CrashLoopBackoff の改善の動き

Pod の CrashLoopBackoff の Backoff の間隔の調整とか特定の exit code で挙動を変えたいとか、Pod ステータスの restartCount を初期化したいとかいろいろと要望が上がっている件、Google の人が KEP 準備中で v1.31 でアルファ機能として入れるのを目標に動き出しているみたい (comment - k/k#57291)

Tsubasa NagasawaTsubasa Nagasawa

2024/4/5

containerd 1.17.4 / 1.6.30 の exec に関するリグレッション

containerd 1.7.14 / 1.6.30 で同一の Pod / コンテナに対して kubectl exec / kubelet の execProbe を並列で実行するとハングすることがあるリグレッションが起きている (containerd/containerd#10036)

  • EKS の Bottlerocket の最新の AMI が containerd 1.6.30 に更新していて readinessProbe / livenessProbe で execProbe を設定している Pod で kubelet からのヘルスチェックに失敗する問題が報告されている。Karpenter の Drift 検出の機能で AMI が置き換えられて何件か報告が上がっている (bottlerocket-os/bottlerocket#3866, bottlerocket-os/bottlerocket#3867)
  • AL2 / AL2023 の AMI の containerd のバージョンは 1.7.11 なので影響は受けていない (awslabs/amazon-eks-ami)

containerd/containerd#9999 で修正の PR がマージされて、1.7.15 / 1.6.31 としてリリース済み

Kubernetes の kind の E2E テストで問題に気付けていて偉い (k/k#124185)

Tsubasa NagasawaTsubasa Nagasawa

2024/4/6

Amazon Linux 2023 の AMI のバグ修正

https://zenn.dev/link/comments/1468dd87cb7814 で書いた Amazon Linux 2023 の AMI を使った時に Kubernetes の API サーバとの通信に失敗する Pod が出る問題の修正が無事にマージされて、修正を含んだ AMI がリリースされました (comment - awslabs/amazon-eks-ami#1737)

EKS 1.29 on Fargate の名前解決の問題が解消

https://zenn.dev/link/comments/0d3372e8c04399 で書いた EKS 1.29 on Fargate の名前解決の問題の修正が全ての EKS クラスタにロールアウトされたそうです。(comment - aws/containers-roadmap#2281)

KEP-4569: Deprecate support for cgroup v1

ついに cgroup v1 の非推奨に向けた KEP が上がりました。Dockershim の削除以来の大きな変更かつ長期的な取り組みになりそうです。(kubernetes/enhancements#4572)

  • cgroup v2 の方が cgroup v1 よりも機能が豊富でインターフェイスの統一性もある
  • Linux ディストリビューションやコンテナランタイムの多くが cgroup v2 をサポートするようになったので cgroup v1 の非推奨化を進めていく
  • クラウドプロバイダーの利用者の多くがまだ cgroup v1 を利用しており、オンプレ環境なども含めると cgroup v2 への移行は進んでいない
  • cgroup v2 への移行パスや移行時に直面した一般的なバグの共有などをドキュメント化して cgroup v2 への移行を促進する
  • Kubernetes v1.31 からkubelet に cgroup のどのバージョンを利用しているかのメトリクスを追加し、kubelet の起動時に cgroup v1 の非推奨の警告ログを書き込むようにする
  • RemovedCgroupV1 の FeatureGate を追加し、ON の場合に cgroup v1 の Node で kubelet が起動できないようにできる
    • アルファ段階ではデフォルトで無効化
  • Kubernetes の CI の多くがまだ cgroup v1 でしか動いていないので、cgroup v2 に移行しつつも cgroup v1 の CI も別途残すことで cgroup v1 起因のバグに気づけるようにしなければならない
Tsubasa NagasawaTsubasa Nagasawa

2024/4/8

kubelet の RunOnce / Standalone モードが実装された背景

kubelet には RunOnce と Standalone という余り知られていない 2 つの実行モードがあって、SIG-Node の定例でその背景の話が少し出てる (Kubernetes SIG Node 20240326)

  • kubelet の RunOnce モードは static Pods (staticPodPath で指定したディレクトリのマニフェスト) を起動して、終了するのを待って終わったら exit するだけのモード
    • 10 年くらい前に RunOnce モードの機能が k/k#1534 で入ってからコードは大きく変わっておらず、ここ 4, 5 年の Pod のライフサイクル関連の機能 (Init / Sidecar containers) はサポートしていないし、Pod のボリュームマウントも正しく動作していないらしい
    • 2017 年に RunOnce モードを非推奨化する動きが k/k#47184 であったが、利用しているユーザーがいて議論も上手く進まず非推奨化されなかった
    • 期待通りに動いていないし、簡単なユニットテスト程度でテストもほぼなく、今だと Podman の機能で podman kube play があって RunOnce モードの置き換えになるから RunOnce モードを今度こそ非推奨化したい (k/k#124030)
  • Kubernetes の最古参の一人の Dawn Chen によると、RunOnce モードは Kubernetes が正式にアナウンスされる以前に追加されたもので、Docker にコンテナを起動する機能があり、Kubernetes はコンテナよりも Pod の概念 (当時はコンテナマニフェストと呼ばれていた) を浸透させたくて単一の Pod を実行する RunOnce モードが作られた
  • kubelet の Standalone モードは RunOnce モードと違って API サーバと通信しないだけで、Pod のライフサイクル管理などの機能は通常の kubelet のモードと同じ
    • GKE だとコントロールプレーンのコンポーネントを動かすために使っていて、他のディストリビューションでも使っているところはあるかもしれない
  • Dawn Chen によると、kubelet の Standalone モードは Kubernetes クラスタではなく、シングルノードの Kubernetes で複数の Pod を起動するために追加された機能
  • RunOnce モードに関しては KEP を作って通常の非推奨化のプロセスを進めていき、Standalone モードに関してはコントロールプレーンのコンポーネントの実行以外のユースケースを集めながら必要かどうかも含めて慎重に議論が必要
Tsubasa NagasawaTsubasa Nagasawa

2024/4/10

Karpenter と Volume のマルチアタッチエラー

Karpenter を v0.32.0 以降に更新すると Node を停止する際に Karpenter が付与する taint に破壊的変更 (node.kubernetes.io/unschedulable から karpenter.sh/disruption:NoSchedule=disrupting に切り替え) があり、AWS EBS CSI driver < 1.29.0 だと停止する Node 上のボリュームを正常にアンマウントできない。そのせいで、kube-controller-manager (KCM) の Volume Attach / Detach controller が別の Node で起動した Pod のボリュームをマウントしようとしてマルチアタッチエラーが 6 分間+ (強制的にデタッチされるまでの間) 発生して Pod の起動が遅れる。AWS EBS CSI driver の Pod は PreStop hook で Node が drain されている場合のみ Node に紐付いている全ての VolumeAttachments を削除して Node にマウントされていたボリュームをアンマウントする。ただ、Node が drain されているかの判断に Node の taint (node.kubernetes.io/unschedulable) を見ており、Karpenter が新しく使う taint を考慮しておらず影響を受けた。AWS EBS CSI driver を 1.29.0 以降に更新すると、AWS EBS CSI driver の Pod が PreStop hook で Node にマウントされているボリュームをアンマウントするかの判断に Karpenter の新しい taint も考慮されるようになるため、正常にアンマウントされる。(kubernetes-sigs/aws-ebs-csi-driver#1969)

Karpenter の Node だと上記の修正を含んだ AWS EBS CSI driver v1.29.0+ に更新しても、ボリュームのマルチアタッチエラーが 6 分間+発生する事象が報告されている。これは Karpenter が EC2 インスタンスを削除するよりも前に (EC2 インスタンスの停止の API が成功したらすぐに) Node オブジェクトから finalizer を削除して Node オブジェクトが消えているからで、AWS EBS CSI Driver の PreStop の処理の中で Node の情報を取得して drain 中かの判断をしているが、Node オブジェクトが見つからず途中でエラーとなり、ボリュームのアンマウントの処理が正常に実行されていないことが原因らしい。(comment - kubernetes-sigs/aws-ebs-csi-driver#1955)

Karpenter 本体の方にリトライ可能なエラーの実装が入り、おそらくこれを使って Karpenter の AWS プロバイダー側で EC2 インスタンスの停止の API を呼び出した後で EC2 インスタンスが停止状態でない場合にリトライ可能なエラーを返し、reconcile の処理を繰り返してインスタンスの状態が停止されるまで待つ予定っぽい。(kubernetes-sigs/karpenter#1164)

こうすることで Node の finalizer が削除されるのが Node (EC2 インスタンス) を完全に停止した後になるので、AWS EBS CSI Driver の PreStop 中には少なくとも Node オブジェクトが消えることはなくなる。Karpenter の開発の人が v0.37.0 で修正を入れる予定と言っているので、それまでは稀に発生しそう。Karpenter の最新バージョンが v0.35 なので v0.36.0 の間違いかと思ったけど、Karpenter 本体に v0.36.0 でリトライ可能なエラーの実装が入り、そこから Karpenter の AWS プロバイダーの実装が入ることになるので v0.37.0 にズレる感じ?

Amazon Linux 2023 での Graceful Node Shutdown の有効化

EKS で Spot インスタンスを利用している場合は、Graceful Node Shutdown を明示的に有効にしないと Node から正常にボリュームがアンマウントされない。
EKS の Node は Graceful Node Shutdown がデフォルトで有効になっておらず、ユーザーデータで明示的に有効にしないといけない。AL2 で Graceful Node Shutdown を有効化する手順は FAQ に記載がある。
AL2023 の場合は、kubelet の設定のカスタマイズの方法が変わっているためユーザーデータの変更が必要で comment - kubernetes-sigs/karpenter#944 に書かれている。

Tsubasa NagasawaTsubasa Nagasawa

2024/4/12

Kubernetes 1.30 リリース直前でのメトリクスのラベル変更

Kubernetes の API server のメトリクスの apiserver_storage_size_bytes で etcd の ID が入るラベルを cluster にしており、Kubernetes 1.30 でこのメトリクスがアルファから GA に昇格した。Cortex とか Mimir で冗長構成のために複数の Prometheus から同じメトリクスを書き込んで重複排除する時に cluster のラベルを使うらしくて衝突する報告があり、Kubernetes 1.30 のリリースが近いので急いでラベルを変更してマージされた。他のバージョンにも cherry-pick される予定 (kubernetes/kubernetes#124283)

EKS 1.30 以降の組み込みの StorageClass の変更

EKS 1.30 からクラスタ作成時に存在する gp2 タイプの StorageClass から storageclass.kubernetes.io/is-default-class の annotation が消えてデフォルトで使われる StorageClass としてマークされなくなるらしい。既存のクラスタに影響はなく、新規に作成したクラスタのみ影響がある。デフォルトの StorageClass は gp3 タイプかつ allowVolumeExpansion を有効化したやつを新しく作って annotation を差し替えてデフォルトを切り替えたけど、切り替えていなくてデフォルトの StorageClass があることに依存している (PVC で annotation or spec.storageClassName を指定していない) 場合は注意した方が良さそう (comment - aws/containers-roadmap#1330)

EKS 1.30 以降の Node に AZ ID のラベルを追加

少し前に AWS の人が kube-cloud-controller-manager (KCCM) にカスタムのラベルを Node に付与できるようにしたのが Kubernetes 1.30 で使えるようになるので、AZ ID が Node のラベル (topology.k8s.aws/zone-id) に加わる。アカウント毎に AZ 名と物理 AZ がランダムに紐付く概念は Google Cloud や Azure にはない (OCI にはあるらしい) ので、Kubernetes 公式のラベルではない。このラベルを使うことで、複数の AWS アカウントに複数の EKS クラスタがあり、EKS クラスタ間で通信する場合に同じ AZ ID に Pod をスケジュールさせて同一の物理 AZ 間の Pod で通信させたりがやりやすくなる (comment - aws/containers-roadmap#1638)

ベアな EKS クラスタを作成する機能の進捗

VPC CNI とか kube-proxy とか CoreDNS とか余計なものがインストールされていない、コントロールプレーンだけセットアップされた EKS クラスタを作成する機能がそろそろ来るらしい (comment - aws/containers-roadmap#186)

AWS CLI で EKS の利用可能なバージョンを確認する機能

AWS CLI で現在利用可能な EKS クラスタのバージョン一覧を表示する機能を開発中らしい。マイナーバージョン毎に今のプラットフォームバージョンがいくつとか EOL がいつかも見れるみたい (comment - aws/containers-roadmap/#982)

AWS の Cost Explorer で EKS の Pod レベルの課金状況を見る機能

Cost Explorer で Pod (?) のコストを見れるようになる機能を開発中みたい。Namespace でグループ化の Issue が重複でクローズされているから見れるようにもなる感じ?(comment - aws/containers-roadmap#2018)

Tsubasa NagasawaTsubasa Nagasawa

2024/4/14

ReplicaSet のスケールダウンで Pod 間のスケジュール制約を考慮

sanposhi さんが ReplicaSet controller が PodAffinity や PodTopologySpreadConstraints を考慮して Pod を削除する仕組みの追加を提案している (k/k#124306)

  • ReplicaSet controller が Pod を削除する際に、Pod の起動時間やステータス、再起動の回数などを考慮して削除するが、PodAffinity や PodTopologySpreadConstraints を考慮して Pod を削除しない
  • PodAffinity や PodTopologySpreadConstraints を常に満たした Pod の配置を実現するには Descheduler などを導入する必要がある
  • ReplicaSet controller に ScaleDownPlugin のインターフェイスを生やして、スケールダウンの要素 / 観点毎に plugin を作成して Score 関数を実装する
  • ReplicaSet controller が ReplicaSet 内の Pod をいくつ削除すべきか計算し、各 Score 関数を実行、最も得点の高かった Pod を削除する
    • Score 関数には candidatesToDelete (各 plugin を実行した後の得点を保持) と relatedPods (ReplicaSet に紐づいた Pod 全て) を渡し、Score で得点付けした後の Pod と合計得点を返す
    • 既存のスケールダウンのロジックに関しても ScaleDownPlugin として実装予定
  • PodAffinity の場合は、削除候補の Pod が実行されている Node で PodAffinity と一致する Pod が存在しない場合に高得点にするロジックになる
  • PodTopologySpread の場合は、relatedPods を PodTopologySpreadConstraints のドメイン毎にグループ化し、それぞれのドメイン毎に Pod の合計得点を足し合わせ、各ドメインの合計得点が同じくらいになるように得点を正規化する
    • ドメイン A が 600 点 (PodA: 100, PodB: 200, PodC: 300)、ドメイン B が 300 点 (PodD: 100, PodE: 100, PodF: 100)、ドメイン C が 3000 点 (PodG: 500, PodH: 1000, PodI: 1500) の場合に Pod を 3 つ削除しないといけないとすると、ドメイン C の Pod が 3 つ削除されることになる
    • PodTopologySpread の plugin が得点をドメイン B の 300 点で正規化して、ドメイン A が 300 点 (PodA: 50, PodB: 100, PodC: 150)、ドメイン B が 300 点 (PodD: 100, PodE: 100, PodF: 100)、ドメイン C が 300 点 (PodG: 50, PodH: 100, PodI: 150) となり、ドメイン C の Pod だけが削除されるのを防げる
    • PodC, PodI 以外に 100 点の Pod を 1 つ削除する必要があるので、ドメイン C の Pod が 2 つ削除される可能性はある
  • 現在の実装よりもスケールダウンに時間が掛かるようになるが、スケールダウンの処理が遅れてもそこまで困ることはないはず
Tsubasa NagasawaTsubasa Nagasawa

2024/4/15

lobuhi/kindscaler

kind で起動した Kubernetes クラスタに後から control-plane と worker ノードを追加・削除するスクリプト

EBS CSI Driver のマルチアタッチの修正の続き

Karpenter と Volume のマルチアタッチエラー で取り上げた件の続報。

EBS CSI Driver の PreStop hook の処理で Node が存在しない場合にエラーを返していた問題は、Node が存在しない時は Node が停止中と判断して VolumeAttachments が削除されるのを待つように修正された。(kubernetes-sigs/aws-ebs-csi-driver#2007) ついでに Cluster Autoscaler の taint が Node に付与されている場合も Node が停止中と判断するようになっている。次のリリースにこの修正が取り込まれる予定。注意点として、この修正により EBS CSI driver の Pod が Karpenter によって drain されなければならない。そうしないと、Karpenter が Node を削除する (finalizer を外す) 前に PreStop hook の処理をトリガーできない。なので、現状のデフォルトで設定されている全ての taints に耐性を持つ tolerations を外す (node.tolerateAllTaints=false にする) 必要がある。

EBS CSI driver が全ての taints に耐性を持つ tolerations がある場合にもこの問題を修正しようと思うと、Karpenter 側で Node を削除する前にボリュームがアンマウントされるまで待つ必要がある。(comment - kubernetes-sigs/karpenter#944)

ボリュームがアンマウントされたかを判断する方法を考えていたら、ちょうど upstream の Kubernetes でも PVC の削除保護の機能で PV が Node からアンマウントされたことを待ってから削除保護を外したいらしく、最初は今の Karpenter と同様に Pod のフェーズが Succeeded or Failed に遷移するのを待っていた。ただ、アンマウントの処理は Pod のフェーズとは関係なく非同期に行われるので、別の方法を考えるべきとなっていた。(comment - k/k#123320)

で、upstream の方は Pod の Condition に新しくボリュームのアンマウントなどが完了したことを知らせる PodTerminated (名前は変わりそう) を追加する KEP-4576: Condition PodTerminated added for pod が上がっていて、これが true となっていたら削除保護を外すようにするみたい。Karpenter / Cluster Autoscaler もこの機能が使えそうだし、KEP のユースケースに挙げてみるのどう?ってコメントしておいた。(comment - kubernetes-sigs/karpenter#944)

Tsubasa NagasawaTsubasa Nagasawa

2024/4/16

kube-proxy の iptables vs nftables のパフォーマンス比較

アントニオさんによる kube-proxy の iptables モードと nftables モード (アルファ機能) のパフォーマンス比較 (kube-proxy nftables and iptables vs a Service with 100k endpoints)

  • iptables のパフォーマンスの制約の主な原因は以下の 2 つある
    • コネクションを確立するための最初のパケットで iptables のルールを線形探索しないといけない
    • iptables のルールを変更する際に iptables save / restore で iptables の全てのルールの行を扱うことでプログラミングレイテンシが発生する
  • Linux カーネルの開発者は iptables の後継として nftables を開発し、上記で述べたパフォーマンスのボトルネックの改善を目指した
  • 他にも理由はあるものの Kubernetes も KEP-3866: Add an nftables-based kube-proxy backend で kube-proxy の nftables モードを開発している
  • パフォーマンス比較の方法
    • 単一の Service を作成して Endpoints を 100k 手動で紐付け (Pod の作成は不要)、kube-proxy のプログラミングレイテンシを計測する
    • Pod が紐付いた別の Service を作成して、Service 経由でリクエストを投げてこの Servie のルールが最初に作成した Service のルールの後に評価される様子を確認する
    • GCE VM (n2d-standard-48) で kind v0.22.0 で Kubernetes 1.29.2 のクラスタを作成して検証
  • Service に Endpoints を 100k 手動で紐づけるのはセレクタなしの Service を作って 1000 Endpoints を詰め込んだ EndpointSlices を手動で 100 個作成している
  • iptables の場合
    • iptables のプログラミングレイテンシは kube-proxy のログで確認できて iptables restore の処理で 90 秒掛かっており、CPU もフルで消費している
    • 追加で Pod が紐付いた Service を作成して ab で負荷をかけるとタイムアウトが発生した
  • nftables の場合
    • nftables のプログラミングレイテンシも kube-proxy のログで確認できて最大で 11 秒掛かっており、top で CPU 使用率を見ても高くなっている様子はない
    • 追加で Pod が紐付いた Service を作成して ab で負荷をかけても接続確立までに要した時間は 6 ms ± 2.2 ms と影響は見られない
  • Dan さん (kube-proxy の nftables モードの実装者) からの指摘いくつか
    • iptables モードで追加の Service を作成して負荷を掛けた場合の ab のタイムアウトが何か分からないけど、iptables のプログラミングレイテンシである 90 秒間待ってから負荷を掛けた?
    • iptables モードでプログラミングレイテンシに 90 秒掛かっているが、KEP-3453: Minimizing iptables-restore input size が効く状態ならもう少し早くなりそう
    • nftables モードで接続確立の時間に影響はなかったが、iptables モードでもタイムアウトが発生しない状態で実施すれば同じく影響はないはず。Endpoints のルールがいくらあろうが、トップレベルのテーブルの探索 (Service のルール) には影響しないからで、実験するなら 100k Service に 100k Endpoints がぶら下がっている状況の方が良い
    • iptables モードのルールのフル同期で 90 秒と比較しても、nftables モードはまだ部分的な同期などの最適が入っていない状態でプログラミングレイテンシが 11 秒なのはすごく良い

OCI ランタイム仕様での cgroup v1 の非推奨化の議論

OCI のランタイム仕様の方で cgroup v1 の非推奨に向けて足並み揃えようって動きがありますね。Container Plumbing Days で NTT の須田さんが議題に挙げたとか。cgroup v1 の非推奨の発表はいつやるか (Linux ディストリビューションの発表より前かなど)、低レベル・高レベル含めたコンテナランタイム全体で一緒に発表するか、各プロジェクトの非推奨に向けた取り組みはどうなっているかなど確認するみたいです。Kubernetes でも cgroup v1 の非推奨化の動きがあるが、タイミングは異なる可能性もある。NTT の須田さんは cgroup v1 のサポートは 2029 年 (cgroup v1 を使っている各 Linux ディストリビューションの EoL が進んだタイミング) まで少なくとも続け、2030 年以降にユーザーに聞いてどうするか判断するのが良いというスタンスみたい (opencontainers/runtime-spec#1251)

Kubernetes 1.28 + cgroup v2 の memory.oom.group の被害者

また Kubernetes 1.28 + cgroup v2 の memory.oom.group の被害者が... (k/k#117793)

  • Celonis で先週 Kubernetes 1.28 に更新したことで OOM が多発して障害が発生した
  • CPU とメモリ負荷の高いワークロードを動かしていて 10k CPU コアと 80 TiB のメモリを使っている
  • データモデル (> 100k) をインメモリに読み込んでクエリを実行するタイプのワークロードで、Pod 内に管理プロセスがいてデータモデル毎に別プロセスで処理する。複数の Pod のプロセスを管理するオーケストレーターの Pod (?) もいる。
  • Kubernetes 1.28 に更新するまでは、Pod 内の 1 つのプロセスが OOM で死んでもオーケストレーターが別のプロセスをスケジュールし、同一の Pod 内の他のプロセスが提供するデータモデルに影響はなかった
    メモリ効率も高く数万のモデルを数台の Node で動的に提供することができた
  • こんなことしないでプロセスを Pod 単位で起動した方が良いというかもしれないが、100k ものデータモデルを提供するために Pod を 100k 起動するのはリソース効率的にも現実的ではない
  • cgroup v1 に戻るのは長い目で見ると最善の選択ではなく、Kubernetes や systemd、Bottlerocket で cgroup v1 のサポート停止の議論が始まっている
  • 今の設定が大多数にとって嬉しいのは分かるが、これまで動作していたものが動作しなくなるのは問題ではないか
  • kubelet にオプションを追加する案も、コンテナレベルで memory.oom.group を無効化するオプションもリリースからユーザーが利用できるようになるまで時間が掛かる
  • kubelet にオプションを追加しつつ Kubernetes 1.28 や 1.29 に例外的に backport し、コンテナレベルの設定の追加を進めるなど何かしら対応できないか?
Tsubasa NagasawaTsubasa Nagasawa

2024/4/17

Kubernetes の enforce-mountable-secrets の脆弱性

CVE-2024-3177: Bypassing mountable secrets policy imposed by the ServiceAccount admission plugin

  • Kubernetes の脆弱性報告は Placeholder の Issue を作成して後から詳細を書く形
  • 2024/4/16 に Placeholder の Issue が作成された
  • コードフリーズしているにも関わらず特に説明なくマージされ、既に各バージョンに cherry-pick されているので k/k#124322 関係かなと予想していたら当たった
  • Pod でマウントする Secret を制限する機能が envFrom のバリデーションがなくて参照できちゃってた脆弱性

Kubernetes の cgroup v1 の非推奨化に向けた議論の結末

Kubernetes の cgroup v1 の非推奨化は表現を変えて機能追加を行わないメンテナンスモードに (comment - kubernetes/enhancements#4572)

  • Kubernetes としては古い Linux ディストリビューションの利用者やすぐに cgroup v2 に移行できないユーザーなどを含めた広いユーザー層の互換性を守ることが重要
  • 非推奨化という言葉が混乱を招き、cgroup v1 の機能を継続的にサポートするという意図が伝わりづらい
  • Kubernetes の cgroup v1 サポートに対する機能追加は停止して、想定していた機能追加が完了した状態であるフィーチャーコンプリートに
  • 既存の機能に対するテストは残してリグレッションは検知できる状態にして、何があれば SIG-Node が対応する
  • cgroup v1 絡みのバグ修正はベストエフォートで対応する。脆弱性は優先度を上げて対応するが、影響の大きなバグ修正は SIG-Node 内で相談して取り組むか決める、カーネル側で大きな変更を要するバグは cgroup v1 のままで対応するのが難しいかもしれない
  • SIG-Node としてはフィーチャーコンプリートの状態で十分に時間が経ったあとに正式な非推奨化のアナウンスを別途行う
  • この決断で Kubernetes としては cgroup v2 関連の機能に投資していくという本来の意図が伝わり、cgroup v2 への移行が進むことを期待している
  • ベンダー側も特別対応で cgroup v1 のコードベースを自前でメンテする必要もなくなる
Tsubasa NagasawaTsubasa Nagasawa

2024/4/18

kube-scheduler の QueuingHints の機能の開発の今後

kube-scheduler の QueuingHints の機能の開発に今後も投資するかどうかの議論が始まりました。(k/k#118893 (comment))

  • QueuingHints は activeQ に Pod を移動するのイベントを Pod の追加とか更新とかの荒い粒度じゃなくて plugin 毎に特定の条件を満たしたイベントに制限する機能
  • SchedulingHints のフレームワークが実装され、現在各 plugin の QueuingHints の実装を進めている
  • PreFilter や Filter を実装した plugin で QueuingHints を実装することになるが、全てのイベントを網羅して実装するのは大変でメンテナンスコストも高い
  • activeQ に無駄に Pod を移動させないことでスループットの向上を目指したが、イベントをフィルタリングする処理が重くパフォーマンスに影響する
  • QueuingHints が何も有効でない場合にメモリ使用量が 1.5 倍になることが観測されている
  • 上記の問題から 1. 機能を削除する 2. QueuingHints のフレームワークに変更を加えてインメモリでのイベントの保持数に上限を設けるなど改善する 3. QueuingHints のフィルタリングの中で複数のオブジェクトを参照するなど複雑な処理をやめさせる、からどうするかを決めたい

Kubernetes 1.30 リリース

Kubernetes 1.30 が予定通りリリースされました。リリーステーマは幸せとか可愛いを表す UwU と Kubernetes を合わせた Uwubernetes。Kubernetes のコントリビュータの多くがお金をもらってやっているのではない。単に楽しいから、問題を解決したいから、何かを学びたいとから、コミュニティが好きだからと理由は様々ある。リリースロゴは、コントリビュータや Kubernetes のリリース作業に関わる人、Kubernetes クラスタを動かしている人に向けた贈り物という意味合いだとか (blog)

Kubernetes 1.30 での client-go の破壊的変更

Kubernetes 1.30 で client-go のleaderelection のパッケージのメトリクスのインターフェイス名に破壊的変更があり、controller-runtime 側でまだ 1.30 対応のリリースがないせいで、downstream のプロジェクトで 1.30 対応できない祭りが起きている (k/k#122069 (comment))

  • 修正の PR が出て新しくインターフェイスを作って元のインターフェイスを wire してるけど、1.30 リリースされたばっかりだしどうなるか (k/k#124372)
  • 何回目かの外部に公開したインターフェイスの破壊的変更なので、そういう変更に対して API レビューを必須にできるように linter か presubmit のジョブで検知して kind/api-change のラベルを付けようとしている (k/k#124380)
Tsubasa NagasawaTsubasa Nagasawa

2024/4/20

component-base/logs の slog バックエンド

component-base/logs 0.31.0 以降は Go >= 1.21 でビルドした場合 klog のバックエンドとして slog がデフォルトで使われるようになる (k/k#120696)

[Kubernetes 1.31] kube-proxy の nftables モードがベータ昇格予定

Kubernetes 1.31 で kube-proxy の nftables モードがベータに昇格。デフォルトで有効になるが、kube-proxy の --proxy-mode=nftables で指定しないと有効にはならない (k/k#124383)

アントニオさんの Network Policy の参照実装の寄贈

2024/3/31 で紹介したアントニオさんの Network Policy の参照実装の kube-netpol は SIG-Network に寄贈されて予定通り Kubernetes の CI で使われる (kubernetes/org#4856)

Tsubasa NagasawaTsubasa Nagasawa

2024/4/21

EKS の Access Entry の事前定義ポリシーの改善

EKS の Access Entry の事前定義のポリシーに AmazonEKSAdminViewPolicy が追加されたらしい。既存の AmazonEKSViewPolicy だと Secret などの一部のリソースの読み取り権限がなかったので別で Admin ポリシーが追加された (aws/containers-roadmap#2244 (comment))

[Kubernetes 1.27-1.29] PV の NodeAffinity のバグ

Kubernetes 1.27-1.29 で PV の NodeAffinity に kubernetes.io/hostname のラベルでフィルターを掛けていて、かつ存在しないノード名を含む場合に Pod のスケジュールが必ず失敗するバグ。Kubernetes 1.30 で別の問題を修正したときに、意図せずこの問題も修正されたみたい。あまり使っている人いなさそうだけど (k/k#123465 (comment))

Tsubasa NagasawaTsubasa Nagasawa

2024/4/22

[Kubernetes 1.31] Service のフィールドセレクタのサポート

Service の Informer cache で .spec.clusterIP.spec.type のフィールドセレクタに対応したので、メモリ使用量を抑えられる。Kubernetes 1.30 で入る予定がテストが Flaky になり revert されたものが 1.31 で入る形。kubelet が Service の環境変数をコンテナに埋め込むために Informer cache を使っており、kube-proxy も Service にラベルを付与するためかな Informer cache を使っている。ただ、どちらも Headless Service の処理では不要なのに無駄に watch していた。大規模クラスタで Kubeflow のジョブを実行した時に大量の Headless Service (10,000+) が作られて API サーバとの通信でのネットワーク帯域を逼迫させたり負荷が掛かっていた。Service type Loadbalancer の場合に LB を作る系のコントローラーも Informer cache で監視する Service を減らせるのでメモリ使用量を減らせる (k/k#123905)

Tsubasa NagasawaTsubasa Nagasawa

2024/4/23

Descheduling Framework

結構前から議論されてきた Descheduler のフレームワーク化 (Descheduling framework) の話が Descheduler プロジェクト内の KEP に (kubernetes-sigs/descheduler#1372)

  • Descheduler はここ数年広く使われてきて安定してきたが、既存の機能への影響や破壊的変更の懸念などから新しい機能を入れづらくなっている
    • Descheduler の設定は v1alpha1 で破壊的変更は許容できる段階だが、敢えて破壊的変更を避けている
  • 新しい機能の要望やバグ報告が現在活動しているメンテナのキャパを超えており、継続的にコントリビュートしている訳ではないユーザーが実装した新しい機能の面倒をメンテナが見る羽目にもなっている
  • Descheduler を真の意味で安定化させるために、Descheduler を利用可能なコンポーネントの集合からライブラリに昇華させる
    • kube-scheduler の Scheduler Framework の概念を元にしているが、実装に関しては大きく異なる
  • Descheduler のメンテナは Pod の Eviction ロジックを独自に書くフレームワークの開発に集中し、サードパーティの開発者がそれぞれのユースケース毎に機能を実装してメンテできるようにする
    • kube-scheduler の out-of-tree の Scheduler plugin みたいな立ち位置
  • Kubernetes の非推奨化のプロセスに準拠して、フレームワークの開発が既存の Descheduler の機能に影響しない形で進め、Descheduler のコンテナイメージもこれまで通り提供する
  • 現在提案されているユースケースへの対応
    • イベント駆動の Pod の Eviction
      • 現状は Deployment で定期的に Eviction の処理を実行するか、CronJob で定期実行するか
      • イベント駆動でより効率・最適に Pod の Eviction を行いたいが、どのイベントで Eviction を実行するかは機能・戦略による
      • 開発者が自分たちのユースケースにあったイベントで Eviction を実行できるようにフレームワークを作る
    • 独自の Pod の Eviction のロジック
      • 現状は Descheduler 内で Pod や Node をフィルターする処理を持っている
      • フレームワークでは Kubernetes のあらゆるリソースのフィルターやソートの機能を公開する
      • それにより、例えば PVC が紐づいた Pod の Eviction の仕組みはこうするなどカスタマイズできる
    • Descheduler の設定 (Config API) の拡張
      • サードパーティの開発者が実装した機能には挙動を調整するための独自の設定を書けるようにしないといけない
  • Descheduling Cycle の中に拡張点を設けて、plugin 毎に必要な拡張点を実装する形
    • Scheduling Framework と同じで拡張点を実装しない選択も取れる
  • 拡張点は現在、高レベルな Deschedule / Balance と低レベルな PreSort / Filter / Sort を設ける予定
    • 高レベルな拡張点の中で低レベルな拡張点が実行される
    • 高レベルな拡張点
      • Deschedule: 各 Pod を独立で処理して Evict する Pod を決める拡張点
      • Balance: 2 つ以上の Pod を考慮して Pod の配置を調整する拡張点
    • 低レベルな拡張点
      • PreSort: 高レベルな拡張点の処理の最初で Pod をソートする拡張点
      • Filter: Evict する直前に 候補の Pod をフィルタリングする拡張点 (Pod をいつ Evict するかを決める)
      • Sort: Evict する前に Evict 対象の Pod をソートする拡張点
  • Descheduling Cycle は Deschedule -> Balance の順番で固定
    • Deschedule / Balance の中に PreScore / Filter / Sort 拡張点がある (実装しない選択も取れる)
    • Descheduler Plugin は Deschedule / Balance のどちらかを実装 or 両方実装するパターンもあり
  • 既存の Descheduler で実装されている戦略とのマッピング
    • Deschedule: RemoveFailedPods, RemovePodsViolatingNodeAffinity, RemovePodsViolatingNodeTaints, RemovePodsViolatingInterPodAntiAffinity, RemovePodsViolatingInterPodAntiAffinity, RemovePodsHavingTooManyRestarts
    • Balancer: RemoveDuplicatePods, RemovePodsViolatingTopologySpreadConstraint, LowNodeUtilization, HighNodeUtilization
  • Descheduling Profile は対象の Pod を変えたり (e.g. 特定の namespace やラベルセレクタ)、同一の戦略でも plugin の設定を変えて、複数回実行できる最小単位
    • kube-scheduler の Scheduling Profile では Pod の .spec.schedulerName でどの scheduler (Profile) を使うか選択できるが、Descheduling Profile を Pod 単位で設定はできないので、対象の Pod を変えるのは Descheduling Profile の設定の中で変えるしかない
  • Descheduling Cycle の処理の流れ
    • Descheduler Cycle の中で Deschedule / Balance それぞれのプロファイルに Node の一覧を渡す
    • Deschedule のプロファイルを全て実行してから Balance のプロファイルを実行する
    • Evict 対象の Pod が選出されたらなる早で Evict する
    • Descheduling Cycle 毎に Evict された Pod の数を追跡しているので、Evict の上限の Pod 数が設定されている場合にその数に到達したら Descheduling Cycle を早めに終わることもある
    • 指定するプロファイルの順番は Evict したい Pod の優先度で指定する必要がある
  • DeschedulerPolicy でプロファイルを指定する
    • KubeSchedulerConfiguration に設定の記述の方法は似ている
  • KEP-4563: Evacuation API との連携も視野に入れている
Tsubasa NagasawaTsubasa Nagasawa

2024/4/24

FeatureGate をどの段階から始めるかの指標

Kubernetes で稀にある FeatureGate で Alpha をスキップして Beta から始まる変更の判断基準の言語化 (kubernetes/community#7828)

  • API の変更を含む機能は必ず Alpha -> Beta -> GA の段階を踏むこと
  • やりたいことを実現できるか不明な場合やすごく複雑な場合、不具合やエッジケースのリスクがある場合、パフォーマンスやスケーラビリティに関する影響がある場合は Alpha -> Beta -> GA の段階を踏むべき
  • 可能な限り複雑さを減らし、パフォーマンスやスケーラビリティへの影響も抑えてはいるが、とはいえ重大なリスク (e.g. ユーザー影響のある挙動の変更やエッジケース) を伴う場合は、Alpha を飛ばして Beta から始めても良い (Beta の品質を満たしているなら) が、大規模な本番環境での実績やさまざまな使われ方をして問題がないことが確認できるまではデフォルトで無効にすべき
    より一般化すると、以前動いていた機能が場合によっては動かなくなる可能性があるなら、デフォルトで機能を無効にすべき
  • 変更箇所は小さくリスクも少ないが、新しい設定オプションを追加せずに (互換性の観点から設定オプションを追加してしまうと非推奨化と削除が面倒になる) Feature Gate を使って機能を無効化できるようにしたい場合は Alpha を飛ばして Beta から始まっても良く (Beta の品質を満たしているなら)、最初からデフォルト有効でも良い
  • ある程度のリスクを孕むバグの修正で Feature Gate で無効化できるようにしたい場合は、Feature Gate が Beta から始まり最初からデフォルト有効を推奨する。一方で、バグ修正により機能が"削除"された (=挙動が変更された) と捉えられる可能性がある場合は機能の非推奨化を進めることも選択肢の一つだが、どちらにしろバグ修正を無効化できるようにすることが重要
Tsubasa NagasawaTsubasa Nagasawa

2024/4/25

ExexProbe のタイムアウトが効かないことがある問題

以下の例だと 5 秒経過してもタイムアウトにならずに 45 秒待ってしまう (containerd/containerd#10094 (comment))

  • ExecProbe は containerd だと ExecSync の中で setns でコマンドを実行する
  • setns で実行したコマンドの結果は標準出力に書き込まれるが、setns から shim までは pipe でデータを流し、shim から CRI plugin までは FIFO (名前付きパイプ) でデータを流す
  • containerd としては標準出力に書き込んだログを取りこぼしたくないので、pipe を通して書き込む側が pipe をクローズするまでは待つようになっている。pipe がクローズされると shim の読み取り側が EOF を受け取り、FIFO もクローズする
  • setns で実行したプロセスは子プロセスを持つ可能性があり、以下の例だと sleep 45 がそれに当たる
  • sub-cgroup が設定されていないので子プロセスの状態を全て追跡できず、ExecProbe がタイムアウト時間を過ぎると setns の親プロセスである sh は殺されるが、sleep は殺せずに残る。それにより pipe もクローズできずに掴み続け、45 秒経過するまで待ってしまう
  • sub-cgroup を導入する以外に良い方法がないが、containerd には drain_exec_sync_io_timeout という設定がありこれを良い感じの時間に設定することで子プロセスが処理を終えるのを待つ必要がなくなる
      readinessProbe:
        timeoutSeconds: 5
        exec:
          command: ['sh', '-c', 'date >> /probe/readiness-log.txt && sleep 45']
Tsubasa NagasawaTsubasa Nagasawa

2024/4/26

kubernetes-sigs/secrets-store-sync-controller

SIG-Auth が新しく kubernetes-sigs/secrets-store-sync-controller のリポジトリを作ろうとしている (kubernetes/org#4902)

  • Secrets Store CSI Driver には外部のシークレット管理サービスから秘密情報を Kubernetes の Secrets に同期する機能がある
    • 設計思想的に Pod にマウントした秘密情報を Secret に同期する必要があって、Pod を作らないと Secret に同期できないという制約から使いづらい
    • kubernetes-sigs/secrets-store-csi-driver#298 で Issue も上がっていて要望も多いが、Secrets Store CSI Driver が生まれた背景的に Secret を介さずに tmpfs としてマウントした秘密情報を Pod がファイルや環境変数から読み込めるというのがあるので難しい
  • Secrets Store CSI Driver のスコープから外れているので、プロジェクトは分離してコードは一部共有する形で Secret に同期するコントローラーを開発する流れっぽい?
  • 新しく SecretProviderClass と SecretSync のカスタムリソースが追加される
    • SecretProviderClass に外部のシークレット管理サービスの provider 名や固有のパラメータを指定する
    • SecretSync に実際に作成する Secret の情報を記載する
      • Secret の spec が埋め込まれていて、外部のシークレット管理サービスからフェッチしてくる時の権限を付与した Service Account の指定やどの SecretProviderClass を利用するかも指定する
  • 対応するシークレット管理サービスの provider は選択できて、Secrets Store Sync controller の sidecar として起動する感じ?
  • SIG-Auth が開発するのでセキュリティ的な懸念とかちゃんと考慮されるだろうし、コントローラーの質も高くはなりそうだけど、External Secrets Operator がいる中でどれくらい普及するかな...

Argo CD の Ignore Difference の機能の DoS 脆弱性

Argo CD の Application の Ignore Differences の機能で jqPathExpressions を指定している場合に、悪意のある条件を書くと OOM させることができる脆弱性が見つかっている。Argo CD v2.10.8, v2.9.13, v2.8.17 で修正済み (GHSA-9m6p-x4h2-6frq)

  • until で絶対一致しない条件で loop させてリストを徐々に増やしていってじわじわ殺すの面白い。
  • Argo CD 側の修正としては jqPathExpressions の評価にタイムアウト値を儲けてデフォルト 1 秒を超えるとエラーを返すようにしている。
ignoreDifferences:
- group: apps
  kind: Deployment
  jqPathExpressions: 
  - 'until(true == false; [.] + [1])'
Tsubasa NagasawaTsubasa Nagasawa

2024/4/27

addon-resizer をコントロールプレーンで動かすモード

GKE の metrics-server のサイドカーとしてデプロイされている addon-resizer (a.k.a. nanny) をコントロールプレーンで動かせるようにする変更 (kubernetes/autoscaler#6764)

  • セキュリティを堅牢にするために GKE のコントロールプレーンのノードで addon-resizer を動かしたい
  • Kubernetes API サーバの in-cluster の認証情報以外に kubeconfig を渡せるようにしているのとリーダー選出の機能が入っているのと ConfigMap から addon-resizer の設定を読み込めるようにしている
  • --run-on-master (名前は変わりそう) のフラグを指定するとコントロールプレーンで動作するようになる
    • フラグの説明文に思いっきり GKE って書くのどうなの...
    • Whether the addon-resizer is running on GKE master VMs.

  • リーダー選出で RunOrDie を使っているので にリーダー選出に失敗すると死ぬ形になっていてコントロールプレーンのノードで CrashLoopBackoff するのどうなのって言われているけど、社内の例に従って実装しているって言ってて気になる
    • GKE のコントロールプレーンのコンポーネントは kubelet の Standalone モードで動いているからプロセスが停止すると再起動されちゃうはず
  • addon-resizer が暴走して CPU 使用率が 100% に張り付くみたいなこともあったし、コントロールプレーンに行ってくれるなら嬉しい
Tsubasa NagasawaTsubasa Nagasawa

2024/4/29

Pod のリソース要求を計算する関数の外部公開

Pod のリソース要求を計算する関数を component-helper に移して外部公開して、downstream のプロジェクトで利用できるようにする動きがある。kubectl や LimitRange の Admission Controller でも同じ関数のコピーを自分たちで管理している。最近だと Sidecar container の追加でリソース割り当ての計算方法が変わったり、downstream で同じ関数をメンテするのは大変だからライブラリ化しておきたい (k/k#124537)

WG-Serving の最初の定例ミーティング

https://www.youtube.com/watch?v=Ri4rQNoRBko

  • serving ワークロードの定義は?
    • Pod の restartPolicy が Always の場合は serving ワークロード、restartPolicy が OnFailure or Never の場合は batch ワークロード
    • restartPolicy が Never の Pod で inference ワークロードを動かしている場合や StatefulSet で batch ワークロードを動かしている場合もあるので 一概にそうと言えないこともあるが簡潔に違いを表すなら上記の定義
  • KServe などのプロジェクトと協力して Kubernetes 上で inference ワークロードを動かすための標準化を進めるか StatefulSet の成功 (StatefulSet に改善を加えることで Kubernetes 上でデータストアを動かす Operator がたくさん生まれた) のように inference ワークロードを動かす上での運用上の懸念などを標準化するか
    • 1 つの Operator が全てのユースケースを満たせる訳もなく、inference ワークロードはこう動かすものみたいな押し付けもやりたくない
    • 設定とコードの分離による ConfigMap のロールアウトの仕組みはいろいろとあったり、Gateway API のような緩い標準化 (Gateway API 以外の選択も取れる) など選択の自由が重要
  • スケジューラーだと Volcano や Kueue などそれぞれが独自の概念を導入しており、標準化されたインターフェイスがないのでプラットフォームに取り込むのが大変だったので、WG-Serving はまずインターフェイスやコンポーネントを標準化して欲しい
    • コンセンサスを取りながら標準化を進めてみても良いが、Kueue が Kubernetes 上になかったキューイングの仕組みを作って他のプロジェクトが連携したように、Kaito の PreSet や KServe の ServingRuntime が連携できる低レイヤーの何かを作るのもアリ
    • WG-Batch は低レイヤーな Job API を改善して Kueue をその上に作った。経験上、上のレイヤーに行けば行くほどコンセンサスを取りづらくなるので、他のプロジェクトが組み合わせを考えられるような基本要素を作ることと LeaderWorkerSet (LWS) のような一部のユースケースを満たすものをその上に作ってあげるのが良さそう
    • 高レイヤーなところでの標準化よりは低レイヤーな基本要素を作る方がコンセンサスは得やすいし、複雑なユースケースにも対応しやすい
    • Deployment や StatefulSet や HPA などの既存の基本要素の改善とモデルの提供やトラフィックの振り分けなどを実現できる基本要素を新しく作る
    • HPA に CPU やメモリ以外に GPU を指標として使えるようにしたり、inference ワークロードと Web アプリケーションの違いとして inference ワークロードは負荷が高ければ高いほどレイテンシが改善する傾向にあるのでゆっくりスケールする仕組みのフィードバックはできそう
  • WG-Device-Management としては DRA に既存の Claim ベースの厳密なリソース要求の仕組み以外にも、スペックの高い GPU が 1 つもしくはスペックの低い GPU を複数欲しいみたいな優先順位を要求して使えるような仕組みも考えている。パフォーマンスが少し落ちても問題ないから難しいことは考えずにとにかくワークロードを動かしたい人向けの UX の改善?
Tsubasa NagasawaTsubasa Nagasawa

2024/4/30

KEP-4603: Tune CrashLoopBackoff

  • Google の人 (SIG Multi-cluster の人🤔) が予告通り KEP を上げて、Kubernetes 1.31 でアルファ機能入りを目指すみたい
  • CrashLoopBackoff は起動時や実行中に問題の起きたコンテナを再起動する間隔を緩めて kubelet に負荷を掛けないようにする仕組み
  • コンテナを再起動するまでの時間は回数毎に Exponential back-off で増えて (e.g. 10s -> 20s -> 40s, ...) いき、5 分が上限となっている
  • コンテナが起動に成功した後に 10 分間何も問題がなければ Exponential back-off の時間はリセットされる
  • 解決したいユースケースとして Agones の GameServer と AI / ML のバッチ処理を挙げている (Google が推してる 2 つの領域だから解決したいのかな)
    • Agones でゲームセッション (e.g. マルチプレイのサーバのプロセス) を再作成 (= Pod の再作成) はコストが高いので、Pod の中でメインのプロセス (= コンテナ) を再起動して効率的にゲームセッションを再利用したい
    • GameServer (Pod) の中から Agones SDK の Shutdown を実行しちゃうと Pod の再作成からになるので、新たに Agones SDK に Restart を用意してプロセスを再起動できるようにしたいが、 CrashLoopBackoff になるとバックオフ時間待たされて即座に再起動できない
    • AI / ML のバッチ処理でも同様に複数の Pod を起動して並列処理を実行した時に、コードの問題ではなくインフラ側の問題 (e.g. livenessProbe の一時的な失敗) でコンテナが再作成されると、すぐに処理を再開したいのにバックオフ時間待たされる可能性がある
    • ネットワークや GPU などの断続的な問題によりコンテナが再起動を繰り返すことがあるので、処理の再開に最長の 5 分待たされることはありうる
    • Istio やログ転送などのサイドカーコンテナでも同様に早く再起動して処理を再開したいケースはある
  • Pod の再起動時に kubelet がやること
    • コンテナイメージを再度ダウンロードし直す可能性 (ネットワーク帯域やディスク IO への負荷、他のイメージのダウンロードの阻害)
    • コンテナランタイム経由で古いコンテナを削除する
    • 必要なら秘密情報や設定を再度ダウンロード
    • コンテナランタイム経由でコンテナを再作成する
    • コンテナが起動するまで startupProbe を実行する (readinessProbe より高頻度に実行される可能性があり、kubelet に負荷が掛かる)
    • アプリケーションの起動処理 (IO に負荷が掛かりやすい)
    • コンテナの起動に関わるログの書き込み (ディスク IO への負荷と大量のログの書き込み)
  • 起動失敗の理由によってコンテナ単位でバックオフの挙動を上書きできるようにし、Node の安定性を維持できる経験的に安全なデフォルト値も用意する予定
    • コンテナ単位での設定に関しては大多数のワークロードが設定を変更する必要がないデフォルト値を用意し、かつシンプルな UX にする予定
    • 元々の目的である Node の安定性を維持できるように完全にユーザーがカスタマイズできないようにする
    • 上書き可能になる予定の起動失敗の理由は以下の通り
      • コンテナイメージのダウンロードに失敗した
      • プロセスが exit code 0 以外で終了した
      • livenessProbe の失敗や OOMKill、kubelet のランタイム側の問題で再起動された
      • プロセスが exit code 0 で正常終了した
  • 実装の詳細はまだ書かれていないのでここまで
Tsubasa NagasawaTsubasa Nagasawa

2024/5/1

Kubernetes のバージョンスキューポリシーの誤った解釈

Kubernetes のバージョンスキューポリシーでは、kube-controller-manager も kube-scheduler も kubelet や他のコンポーネントも Aggregated API server (e.g. metrics-server) でさえも kube-apiserver のバージョンを超えて動作は保証されていない。バージョン更新時に kube-apiserver は新しいバージョンの kube-apiserver とやり取りすることがある (e.g. FlowControl, Admission Webhook) ので例外的に -1 のスキューが保証されている。Kubernetes のクライアントライブラリを 1.30 に更新したコントローラーが 1.29 の kube-apiserver で動作が保証されている訳ではない。報告だと Custom Metrics の Adapter を書くためのライブラリが Kubernetes クライアントのバージョンを 1.29 に更新し、Prometheus Adapter がライブラリのバージョンを上げ、Kubernetes 1.28 にデプロイしたら動作しなくなった。Kubernetes 1.28 には API Priority & Fairness (APF) で使う FlowControl の v1 リソースがない(APF は Kubernetes 1.29 で GA) にも関わらず、Aggregated API server のライブラリが FlowControl v1 に依存するようになり起動できなくなった感じ (k/k#124533)

Tsubasa NagasawaTsubasa Nagasawa

2024/5/2

GKE が Kubernetes 1.30 をサポート開始

GKE の Rapid channel に 1.30 がきてた。Kubernetes の upstream での 1.30 のリリースが 4/17 なので 2 週間遅れ。相変わらずメジャークラウドの中だと最速 (relase notes)

Helmfile v1.0.0 への動き

久々に Helmfile v1.0.0 への動きがあり、(v1.0.0-rc.0) がリリースされた。このまま次のリリースで v1.0.0 に行くのかな?以前予定していた Helmfile 1.0 での破壊的変更

Tsubasa NagasawaTsubasa Nagasawa

2024/5/3

GKE での RDMA 対応の動き

GKE の Pod に RDMA 対応の NIC を刺せるようになりそう。Pod のマルチネットワークとセットかな。AI / ML で複数 Pod で分散処理するときのネットワーク通信を高速化したいとか (kubernetes/cloud-provider-gcp#681)

Tsubasa NagasawaTsubasa Nagasawa

2024/5/5

KEP-4563: Evacuation API

  • Evacuation API を導入して、Pod を別の Node に移動させる際に協調的に Pod を退避 (削除) できるようにする
    • Pod の所有者 (controller) が協調しない場合は、既存の API ベースの Pod Eviction の仕組みで Pod を退避する
  • kubectl drain や Descheduler, Cluster Autoscaler などの Pod の退避の仕組みを改善するのが狙い
  • 現状、Pod の退避からアプリを守るには PDB を設定するしかない
    • 複数台の Pod を起動できる単純なアプリの場合は問題ない
    • 1 台しか起動していないアプリ (e.g. HA 構成にできない、コストを安く抑えたい) では PDB で minAvailable: 1maxUnavailable: 0 を設定してしまうと Node のメンテナンスを途中で止めてしまう
    • HPA が設定されたアプリでピーク時間外に 1 台までスケールインする場合に PDB が上記のように設定されていると同様に Node のメンテナンスが途中で止まってしまう
  • Graceful Node Shutdown の機能により DaemonSet を安全に停止できるようになったが、.spec.terminationGracePeriodSeconds が必ず守られる保証はなく、アプリが途中で停止してしまう可能性がある
    • アプリが安全に停止するまでの時間はアプリの実装によって変わってくる
  • Descheduler はすぐに退避できないアプリの退避を先延ばしにすることができず、誤った Pod 群を退避させてしまうことがある
  • Evacuation (退避) は以下のコンポーネント間の決まり事 (契約) で、Evacuation API と controller により遂行される
    • Evacuation Instigator
      • Node maintenance controller や Descheduler, Cluster Autoscaler などの退避対象の Pod に影響を与えるアプリや controller のこと
      • Evacuation Instigator の責務は自身が定めたルールに従って退避する Pod を決めてその意思を伝えることで、Evacuation が不要になったら意思を取り下げる
      • 同一の Pod に複数の Evacuation Instigator が退避の要求を送ることがあるので、Instigator は意思を協調し合う必要がある
      • ある Pod に対して全ての Evacuation Instigator が意思を取り下げるまでは Pod の退避は取り下げられるな
    • Evacuee と Evacuator
      • 全ての Pod が Evacuee (退避者) になりうる。Evacuator は Pod の所有者や controller のこと
      • 1 つの Pod に対して複数の Evacuator がいてもよいが、どの Pod を担当しているか知らせる必要がある
      • Evacuator は Pod の退避を拒否して、他の Evacuator や Evacuation controller によって退避が実行されるまで待つことができる
      • Evacuation を開始して定期的に退避の意思に答えて、退避が実行中であることを知らせることができる。Evacuation (退避) は Evacuator に委ねられており、さまざまな形態が存在する
        • データ (永続的なデータと一時的なデータの両方) を別の Node に移動させる
        • Pod が保持するリソースのお掃除と解放を待つ
        • 重要な処理の完了を待つ
        • Pod の安全でない削除 (gracePeriodSeconds=0)
        • PDB に守られた Pod の削除
      • Evacuation の処理は最終的に Evacuator が Pod を削除するか、Evacuation controller がトリガーした Eviction により終了する
    • Evacuation controller
      • Evacuation (退避) の契約を遂行する役目で、Evacuation Instigators 間で重複したコードの実装を避けることもできる
      • Evacuation Instigators からの Evacuation の要求を検知して、Evacuator が Evacuees を問題なく退避しているかを定期的にチェックする
      • Evacuator による退避の進捗報告が止まったら、別の Evacuator を割り当て処理を続けさせるが、
      • Evacuator がこれ以上いない場合は Evication API で Pod を退避する
  • Evacuation Instigator が Pod を退避する必要があると判断したら、Evacuation リソースを作成する
    • ${POD_UID}-${POD_NAME_PREFIX} の名前で Evacuation リソースを作成
    • Evacuation リソースの .spec.podRef で退避対象の Pod 名と UID を指定する
    • .spec.progressDeadlineSeconds を設定し、Evacuator がその時間内に Pod の退避の進捗を報告しない場合に別の Evacuator にフォールバックする
    • Evacuation リソースに Finalizer を設定し、Instigators の退避の意思を追跡したり、Evacuation の処理が完了した後に結果を処理できるようにしたり、Evacuation リソースが不用意に削除されるのを防ぐ
    • Evacuation が不要になったら Evacuation Instigators が自身を Evacuation リソースの Finalizer から削除する
  • Evacuator の種類は partial と knowledgeable と controller と fallback の 4 種類ある
    • partial は Evacuation プロセスの一部を処理するだけで、残りを他の Evacuator が処理することになるので Pod を停止しない
    • knowledgeable は StatefulSet や Deployment などの controller よりもより適切かつ安全に Pod を退避できる
    • controller は一般的な方法で Pod を安全に退避できる
    • fallback は他の Evacuator の処理が失敗した場合にフォールバックして実行する Pod の退避
  • Evacuator は Pod の annotation に上記の 4 つの役割のどれかと優先度を指定する
    • evacuation.coordination.k8s.io/priority_${EVACUATOR_CLASS}: ${PRIORITY}/${ROLE} の annotation を使用
    • 1 つの Pod に対して複数の Evacuator が処理することもでき、その場合は複数の annotation が指定される
  • Evacuation controller は定期的に Pod の annotation を見て Evacuation リソースの .spec.evacuators を更新し、優先度の最も高い Evacuation Class を .status.activeEvacuatorClass に設定する
  • Evacuation controller は Pod が停止したか .status.evacuationProgressTimestamp から .spec.progressDeadlineSeconds の時間が経過した (= Evacuation リソースの .status.evacuationProgressTimestamp の更新がなく進捗報告がない) ら、.status.activeEvacuatorClass を次に優先度が高い Evacuator に変更する
Tsubasa NagasawaTsubasa Nagasawa

2024/5/7

Kubernetes 1.30 での kube-scheduler のパフォーマンスのリグレッション

Kubernetes 1.30 で Filter 拡張点の実行前に候補の Node を scheduler のスナップショットから取得する処理で無駄にメモリを確保していてスケジューラーのスループットが悪くなっている (5k 個の DaemonSet のスケジュールが 300 qps を下回っている) リグレッション (k/k#124709)

master で修正済みでパフォーマンステストをかけて様子を見て必要なら別の修正も加える予定だが、そっちは out-of-tree の Scheduler Plugin で対応が必要になる破壊的変更なので cherry-pick が難しい?(k/k#124714)

Tsubasa NagasawaTsubasa Nagasawa

2024/5/8

Carvel の今後

VMware Tanzu でも使われているマニフェストのパッケージ管理ツールの Carvel が Broadcom / VMware のレイオフによりメンテナが 3 人 (4 人?) まで減ったらしい。今後も開発は続けていく予定 (cncf/toc#1314)

Tsubasa NagasawaTsubasa Nagasawa

2024/5/9

クラウドプロバイダー固有の実装の排除

何年も掛けて Kubernetes の in-tree に存在していた GCP や AWS や Azure、vSphere などの cloud provider の実装や GCP / Azure の credential provider の実装を削除したおかげで Kubernetes のバイナリサイズが抑えられた。vendor 配下が 1:1 でバイナリサイズに繋がる訳ではないけど、それでも Azure SDK とかやっぱり重い (k/k#76506 (comment))

Argo CD v2.11.0 のリグレッション

Argo CD v2.11.0 は Multiple Sources (外部の Helm chart + private な Git リポジトリで管理している values ファイル) の Application を同期できなくなるリグレッションがあるので注意 (argoproj/argo-cd#18120)

Tsubasa NagasawaTsubasa Nagasawa

2024/5/10

ProvisioningRequest API の動き

AI / ML 用途などで複数の Pod をグループで起動できるように事前に必要な台数の Node を確保する ProvisioningRequest の動向

  • ProvisioningRequest (API はベータからスタート) の実装は既に Cluster Autoscaler に入っているが、1.30 では有効にされずオプションも削除されているので有効化するにはオプションを削除した PR を revert してセルフビルドが必要 (release notes)
  • Cluster Autoscaler が ProvisioningRequest の公開を延期したのは Karpenter で同様の機能の実装を待つため。Karpenter の開発の人は ProvisioningRequest の API が既にベータなので API の変更なしに Karpenter 側で実装できるか分からないという感じ (GKE の NAP がサポートしているので Karpenter で実装できなくはないはず)。Cluster Autoscaler としても API をまだ正式に公開していないので Karpenter 側の要望で変更を加えることはできる。ただ、ProvisioningRequest 自体は拡張性が高い API で ProvisioningClass によって実装が変わる方式。Karpenter 向けの ProvisioningClass を実装すれば良いだけのはず。EKS の PM も ProvisioningRequest には興味があるので AEP を読みながら Cluster Autoscaler の開発の人とも協力して実装できるか議論を進めていく予定。ProvisioningRequest の API がベータからスタートしたのは GKE の Cluster Autoscaler の ProvisioningRequest 連携の機能 (GKE の Dynamic Workload Scheduler) を開発するときに内部でフィードバックを受けていたからで当時は Karpenter を SIG-Autoscaling に寄贈する話も Cluster Autoscaler と機能を調整する話もなかったので仕方ない (SIG Autoscaling Alignment for 20240423)
  • 現状 Cluster Autoscaler に実装されているのは check-capacity の Provisioning Class のみで、Node をスケールした後に Pending 状態の Pod を配置できる十分な空きがあるかを 1 度だけ確認するモード。それとは別に atomic-scale-up の Provisioning Class の実装が進められていて、こちらは Node をスケールしようとして失敗しても指定した時間の間で定期的に再試行して Node が確保できるのを待つモード (kubernetes/autoscaler#6815)
Tsubasa NagasawaTsubasa Nagasawa

2024/5/11

Karpenter v1 API & Roadmap Proposal

Karpenter API の v1 昇格時に予定されている変更

  • 2023/10 に Karpenter の API が v1beta1 に昇格して数ヶ月経過したが、API は安定しているので v1 に昇格して問題なさそう
  • v1 に昇格すると新しく v2 を導入する以外に API に破壊的変更を加えられなくなる
  • v1 に昇格する際に API グループ (karpenter.sh) やリソースの種類 (e.g. NodePool, NodeClaim, ...) に変更はなく、Conversion Webhook でリソースのストレージバージョンを変換するので Karpenter 更新時にユーザー側で対応は不要。ただし、当然ユーザー側でマニフェストの v1 API への移行は必要。
  • v1 API への移行パス
    • NodePool や NodeClaim などの CRD の versions セクションに v1 を追加
    • Karpenter のコントローラーを v1 API を使うように変更し、Conversion Webhook により v1beta1 は v1 に解釈されて処理される
    • ユーザーが v1beta1 のマニフェストを v1 に更新
    • Karpenter は次のマイナーバージョンで CRD の versions セクションから v1beta1 を削除し、Conversion Webhook の提供もやめる
      • v1beta1 を導入した時のマイナーバージョンと同じでバージョンをスキップして更新してはいけない
  • NodePool API の変更点
    • デフォルト値に関しては v1beta1 から変更なし
    • kubectl getkubectl get -owide 時の表示に破壊的変更あり
    • NodePool や NodeClaim で指定できた spec.template.spec.kubelet は EC2NodeClass に移動
    • status サブリソースの Condition は再考される
    • consolidateAfter のフィールドを consolidationPolicy: WhenEmpty 以外でも指定できるようにする & デフォルト値を指定
    • nodeClassRef フィールドを指定する際に name だけでなく、apiVersionkind の指定も必須に。Azure や kwok などの他のプロバイダーもサポートするようになったため。また、apiVersiongroup に変更され、karpenter.sh/v1beta1 などの値を指定する形となる
    • NodePool の API スキーマから spec.template.resource.requests のフィールドを削除。Karpenter controller が Pod のリソース割り当ての合計を NodeClaim の resource.requests に記録している。現状 NodeClaim の spec で指定可能なものは NodePool の spec.template に含めるようになっている。Validation でユーザーが指定できないようになっている内部的なフィールドなので影響はない。
  • NodeClaim API の変更点
    • kubectl getkubectl get -owide 時の表示に破壊的変更あり
    • NodeClaim の spec 配下を immutable に変更。現状も NodeClaim を後からユーザーが変更したところで NodeClaim のライフサイクルを管理しているコントローラーは何も処理をしないので挙動としては変わらない。CRD に CEL のルールを設定して immutable に変更予定
  • EC2NodeClass API の変更点
    • kubectl getkubectl get -owide 時の表示に破壊的変更あり
    • amiFamily を指定する際に amiSelectorTerms の指定を必須 & amiFamilybootstrapMode に名前を変更。現状は必須ではなく amiFamily だけを指定した場合の自動的に最新の AMI に更新されるが、本番環境だと危険で Karpenter としても AMI のピン留めを推奨している。とはいえ、eksctl や MNG の挙動とも異なるのでユーザーが間違って使ってしまう可能性がある。
  • spec.template.spec.kubelet のフィールドが NodePool から EC2NodeClass に移動。当初はクラウドプロバイダーによらず設定できる想定だったが、AKS も kwok も kubelet の設定を NodePool で変更する機能はないので AWS 固有の CRD である EC2NodeClass に移動。
  • Pod から IMDS へのアクセスはセキュリティ上危険なのでデフォルト無効に。既存の EC2NodeClass には影響せず、新規に作成した EC2NodeClass に強制される。
  • ラベルや annotation、インスタンスのタグの変更
    • Node レベルの annotation の karpenter.sh/do-not-consolidate を削除。Consolidation の機能以外でも動作する karpenter.sh/do-not-disrupt の annotation があるのでそちらを使う形に。
    • Pod レベルの annotation の karpenter.sh/do-not-evict を削除。こちらも karpenter.sh/do-not-disrupt の annotation に取って代わる形。
    • EC2 のインスタンスに付与されるタグである karpenter.sh/managed-by を削除。Karpenter が Machine から NodeClaim へ移行した際に使われたタグで、移行が完了したかどうかを判断するために使われていた。既に不要となっているので削除予定。

Karpenter v1 に向けたロードマップ

  • 監視のためのメトリクスやログ、Events、status サブリソースの conditions などを安定化させる
    Node を停止する際に karpenter.sh/disruption=disrupting:NoSchedule の taint を付与しているが、それとは別に停止の候補となった Node にも karpenter.sh/disruption=candidate:NoSchedule の taint を付与したい。TTL 経過した Node や Drift を検知した Node にこの taint を付与することで、karpenter.sh/do-not-disrupt の annotation が付与された Pod が停止予定の同じ Node にスケジュールされるのを防ぐことができる。
  • Node 停止時に DaemonSet の Pod や Node Lease が正常に停止・解放できないことがある問題の修正。Karpenter は Node を停止する時にクラウド側の API を叩いてインスタンスを停止しようとする。API 呼び出しが成功するとすぐに Node の finalizer も外しているため、Node オブジェクトが削除される。インスタンス停止の API により kubelet が DaemonSet の Pod を停止し始め最後に Node Lease を削除するが、クラウド側でインスタンスを正常に停止できない場合でも Node オブジェクトが削除される可能性がある。インスタンスを完全に停止してから Node の finalizer を外すように変更することで、Node の Graceful Shutdown の処理を保証できる。Node Lease に関しても現状 Karpenter のコントローラーで削除の処理を行なっているので、kubelet に処理を委譲できるようになり、削除の処理や必要な権限を削除できる。
  • Karpenter は現在 NodePool や EC2NodeClass の設定から差分のある Node を NodePool や EC2NodeClass のフィールドのハッシュ値と NodeClaim のハッシュ値を比較して検出している。新しくフィールドを追加してユーザーが値を設定する場合は問題なく動作するが、デフォルト値が設定されている値をユーザーが指定するようになった場合に上手く動作しない。ハッシュ値の計算ロジックに破壊的変更を安全に加えられる仕組みを実装する。
  • Ubuntu の amiFamily (bootstrapMode) のサポートを削除。EKS は MNG や SMNG で Ubuntu を正式にサポートしていないので、Kapenter でも同様の扱いとする。Ubuntu の AMI を継続して使いたい場合には、カスタムの amiFamilyamiSelectorTerms を駆使することで実現可能。
  • Consolidation は直列に処理され、TTL を経過した Node、Drift 検出した Node、スカスカな Node、複数の Node を考慮して停止できる Node がないかそれぞれ評価する。Consolidation 時には Pod の scheduling をシミュレーションし、Node を削除したり置き換えることでコストが抑えられないか検証する。現在の Consolidation の処理だと各フェーズで停止する Node を決定して 15 秒待ってから再度停止して問題ないか検証して Node を停止する。これにより余りに積極的に Node を停止しないようにバランスをとっている。ただ、各フェーズを直列で処理するため、あるフェーズで 15 秒待つと他のフェーズの評価を進められなくなる。NodePool に spec.consolidateAfter のフィールドを追加して Node 停止まで指定した時間待つように変更し、この待ち時間が他のフェーズの評価をブロックしないように変更する。
  • kubernetes-sigs/karpenter のライブラリの新しいバージョンのリリースと aws/karpenter-provider-aws のコンテナイメージや Helm chart の新しいバージョンのリリースが連動しているのを辞める。kubernetes-sigs/karpenter のライブラリのバージョンは独立して更新できるようバージョン戦略を考え、破壊的変更やそれ以外を依存するプロジェクトに伝える仕組みを用意する。
  • NodeClaim に関する概念的なドキュメントを用意する。ユーザーが NodeClaim を理解することで、Node が停止する条件を確認したり、Node の起動に失敗した原因を知ることができる。
  • knative/pkg ライブラリへの依存を削除。Admission Webhook 用の証明書のローテーションの機能などで使っていたが、CRD の CEL ルールによるバリデーションに移行したので不要になった。また、ライブラリにタグが振られていなく、サポートする Kubernetes のバージョン (client-go のバージョン) も knative/pkg 側に合わせる必要があった。
  • Drift 検出の機能の安定化。ベータに昇格してから特にフィードバックもないので GA する。
  • Karpenter の ConfigMap によるログ設定 (これも knative/pkg の機能) のサポートを削除

Cluster Autoscaler / Karpenter で safe-to-evict/do-not-disrupt annotation を共通化

現状、2 つの Node Autoscaler のプロジェクトで移動させても良い or 移動させるとダメな Pod を指定するために違う annotation が使用されています。これを node-autoscaling.kubernetes.io/safe-to-evict=false に統一する案があげられています。(k/k#124800)

  • Cluster Autoscaler: cluster-autoscaler.kubernetes.io/safe-to-evict=true/false
  • Karpenter: karpenter.sh/do-not-disrupt=true

現状、cluster-autoscaler.kubernetes.io/safe-to-evict=true と同等の annotation は Karpenter に存在しません。そのため、Karpenter に Pod レベルの Consolidation をブロックする機能が入るまで、node-autoscaling.kubernetes.io/safe-to-evict=true の annotation は動作しません。Cluster Autoscaler の既存の annotation をベースにしているのは do-not-disrupt=false が二重否定となって理解しづらいからのようです。Cluster Autoscaler や Karpenter の既存の annotation は非推奨となり、将来的に削除される予定のようなので仮にこの PR がマージされるとユーザー側で移行が必要になります。議論が固まったら `Karpenter v1 API の提案にもこの annotation の変更が正式に組み込まれる予定です。(kubernetes-sigs/karpenter#1222)

Tsubasa NagasawaTsubasa Nagasawa

2024/5/12

Kubernetes のネットワーク関連の Conformance テスト

Kubernetes 1.29 で Service で同一のポート番号で TCP / UDP の異なるプロトコルを公開できるか確認する (逆に TCP だけ公開している場合は UDP では接続できない) テストが Conformance テストに昇格したけど、Cilium が対応していないので問題になっている。Cilium 側に修正の提案を共有していて修正自体もマージする予定だったけど PR マージまでは持って行けず、その状態で Conformance テスト昇格の PR が先にマージされてしまった。そのせいで Cilium を使っている Kubernetes ディストロが準拠していないことに (k/k#120069 (comment))

  • 2019 年から Cilium のバグはあるし、修正の PR を投げているので誰かが代わりに実装を続けることもできたけどまだマージされていない状態なので、SIG-Network としてはこのために Conformance テストから外すのはどうなのってスタンスらしい (k/k#120069)
  • Cilium + kube-proxy 利用の場合は Conformance テストに通るらしい (k/k#120069 (comment))
Tsubasa NagasawaTsubasa Nagasawa

2024/5/14

kind v0.23.0 がリリース

kind v0.23.0 がリリースされたので、ローカル環境でもセルフビルドなしで Kubernetes 1.30.0 のクラスタを作成できるようになった (release note)

kubectl port-forward 時のポート番号の補完

kubectl v1.31 から kubectl port-forward 時に Pod のコンテナポートや Service のポート番号が補完できるようになる (k/k#124683)

kubectl logs に --all-pods を追加

kubectl v1.31 から kubectl logs に —all-pods フラグが追加される。Service や Deployment、StatefulSet などに指定されたラベルセレクタで対象の Pod を選択してログを表示する。—-all-pods フラグを指定する場合は自動的に —-prefix フラグが有効になり、ログの行の先頭に [pod/foo/foo-container] が付与される (k/k#124732)

kubectl logs svc/foo —-all-pods
kubectl logs deploy/foo —-all-pods
Tsubasa NagasawaTsubasa Nagasawa

2024/5/16

EKS の CoreDNS マネージドアドオン

EKS の CoreDNS アドオンで Cluster Proportional Autoscaler による自動スケールを有効化するオプションが追加された。デフォルト値は以下になっていて、ユーザーは変更できなくて、内部の経験則で調整していく感じ?(aws/containers-roadmap#1458 (comment))

"coresPerReplica":256,"nodesPerReplica":16
Tsubasa NagasawaTsubasa Nagasawa

2024/5/17

Eviction 発生時に Pod が早く停止するように変更

リソースの逼迫や Ephemeral Storage の上限を超えた Pod を Evict するときに Eviction gracePeriodSeconds を 0 で上書きしていたけど、これによりすぐに Evict されずに terminationGracePeriodSeconds 待つ挙動になっていた。gracePeriodSeconds を 1 秒で上書きするように変更して早く停止ようになる。同様に kubectl delete —force の場合も同様に 1 秒で上書きして早く停止するようになる (k/k#124063)

kube-apiserver で panic が発生するバグの修正

マルチクラスタに Pod をスケジュールするプロジェクト (admiraltyio/admiralty) が中央集権的なクラスタに作られた Pod を各クラスタにミラーするときにバグにより initContainers のステータスが存在しないことがあるらしく、Pod を表示しようとすると API server が panic になって死ぬっぽい。Kubernetes 1.28 からのリグレッションで Sidecar containers 関連の変更の影響かな。Issue なしで liggitt さんが対応しているということは GKE のユーザーが API server 壊したかな (k/k#124906)

argocd-image-updater の最新リリース

久々に argocd-image-updater の最新バージョンリリースされた。活発って訳でもないけどレビューの動きがあるのと、メンテナが一人増えてそう (v0.13.0)

Tsubasa NagasawaTsubasa Nagasawa

2024/5/18

KEP-4633: Only allow anonymous auth for health endpoints

  • Kubernetes はデフォルトで匿名ユーザーが API を呼び出すことが可能で、認証されていない匿名ユーザーは system:unauthenticated グループの system:anonymous ユーザーとして扱われる
  • デフォルトで匿名ユーザーが呼び出せる API は制限されており、Kubernetes のバージョンやヘルスチェックのみである
  • 匿名ユーザー自体は kube-apiserver の --anonymous-auth フラグで無効化することが可能だが、マネージド Kubernetes の多くが Kubernetes API server の前段の LB から匿名ユーザーで Kubernetes のヘルスチェックのエンドポイント (e.g. /healthz, /readyz, /livez) を叩いて正常性を監視しており、安易に無効化できない
    • GKE と EKS は匿名ユーザーが有効になっていて、AKS だけ無効に設定している
  • ヘルスチェック以外にも kubeadm や Rancher などが system:unauthenticated グループに権限を付与してクラスタの初期化処理を行なっていたり、CI / CD のメトリクスを収集するため (?) に権限を付与しているユーザーもいる
  • ユーザーが誤って system:unauthenticated グループに cluster-admin の ClusterRole など強い権限を紐付けてクラスタを掌握されるセキュリティ事故が発生したこともある
  • GKE では 1.28 以降 system:unauthenticated グループに cluster-admin の ClusterRole を紐付けようとすると Admission Webhook で拒否するようになっている
  • KEP-4633 では kube-apiserver に新しく --anonymous-auth-health-only のオプションを追加して、ヘルスチェック以外の API 呼び出しを禁止にできるようにする
  • ヘルスチェックの API はリクエストに verbose パラメータを埋め込んでも機密情報を返したりはしないので外部から API を叩けても問題ないはずで、マネージド Kubernetes のプロバイダーも LB の設定を変更することなしに匿名ユーザーを無効化可能
  • ヘルスチェック以外の API に関しては system:unauthenticated グループに権限が紐づけられていても 401 Unauthorized を返す

v1.30: kube-scheduler crashes with: Observed a panic: "integer divide by zero"

Kubernetes 1.27-1.30 の最新のパッチバージョンが影響を受けている可能性のある kube-scheduler のリグレッションが報告されている

  • Issue だと 1.30 での報告だが、原因として疑われているバグ修正の変更が 1.27-1.30 の最新のパッチバージョンに含まれていて、2 日前にリリースされたばかり
    • リリースされたばかりなのでマネージド Kubernetes で利用しているところはまだないはず
    • Google の人は既に問題に気づいているので、GKE でこのパッチバージョンがそのまま使われることはないはず (GKE はよく独自に重要な修正を含めているのでこのパッチバージョンに修正を含めた形で使う可能性はある)
  • Zalando が AWS 上に自前で Kubernetes クラスタを運用していて、Kubernetes のコントロールプレーンを更新するときにコントロールプレーン用の EC2 インスタンスの台数を 1 -> 2 に増やして、新しいコントロールプレーンが Ready 状態になったら古い EC2 インスタンスを削除して 2 -> 1 台に戻している
  • 古い Node (EC2 インスタンス) が削除されている時に kube-controller-manager が DaemonSet の Pod を作成すると、稀に削除中の Node が NodeAffinity で指定された Pod を作成してしまうことがある
    • DaemonSet controller は NodeAffinity の requiredDuringSchedulingIgnoredDuringExecution で Node 名を設定した Pod を作成することで各 Node に Pod を配置している
  • Node が削除された後に kube-scheduler がその DaemonSet の Pod をスケジュールしようとして、すでに Node が存在しなくてランタイムエラー (integer divide by zero) が発生して kube-scheduler が強制終了する
  • Issue に priority/critical-urgent のラベルが追加されているので緊急度が高い
  • リグレッションの原因として疑われている PR
  • 修正の PR は既にマージ済みで他のバージョンにも cherry-pick 予定 (k/k#124933)
Tsubasa NagasawaTsubasa Nagasawa

2024/5/20

KEP-4639: adding OCI VolumeSource

Red Hat の人が Pod の VolumeSource で OCI イメージや OCI Artifacts をサポートしてファイルシステムとしてマウントできるようにする KEP を上げてる。LLM のモデルを OCI Artifacts として配布する話しもあったし、その延長なのかな。他のユースケースに CI / CD で使うバイナリをコンテナイメージ化して Pod の中にマウントできるとパイプラインを簡素化できるとかあるけどどうなの。実装の詳細は書かれていないので不明。Volume Populator や CSI ドライバとして実装する方が良くないって突っ込みもある。ただ、SIG-Node とコンテナランタイムの人たちは乗り気。

Tsubasa NagasawaTsubasa Nagasawa

2024/5/22

コンテナイメージのプルの中断

コンテナイメージをプルしている間の Pod を削除しても Pod が起動されてしまう問題。重いコンテナイメージをプルしている途中の Pod を削除しても Pod が Running 状態になり、その後停止して Succeeded 状態に遷移する。(k/k#125050)

似たような方法でコンテナイメージのプル待ちのキューを詰まらせることができてしまう問題。現状、コンテナランタイムは Pod が削除されてもコンテナイメージのプルを中断しない。この挙動を利用して、攻撃者が特定の Node に大量の重いコンテナイメージを利用する Pod を一時的に起動して強制削除 (--force) を繰り返すことでコンテナイメージのダウンロード待ちのキューを詰まらせて、本来起動したい Pod のコンテナイメージのプルを阻害することができてしまう。(k/k#122905)

Pod の標準出力のログが Ephemeral Storage の使用量に含まれている理由

現状 Pod 内のコンテナが標準出力に書き込んだログが Pod の Ephemeral Storage の使用量として請求される仕組みになっている。Ephemeral Storage のリソース上限を指定しつつ、コンテナがログを大量に標準出力に書き込むと Pod は Evict される。将来的に Pod の台数が増えても kubelet やコンテナランタイムの負荷が線型に増えないようにしたいという野望があるらしく、Pod の標準出力のログは Node 単位での請求とはなっていない。究極的には Pod が使用したコストは全て Pod が背負うようにしたいらしい。(k/k#124333 (comment))

KEP-4650: StatefulSet Support for Updating Volume Claim Template

2018 年から 3 回 KEP の PR が引き継がれ、その度にマージまで持っていけなかった StatefulSet の volumeClaimTemplate の .spec.resources.request.storage (と最近追加された .spec.volumeAttributesClassName) を後から更新できるようにする KEP の最新作です。前回の KEP から実装は大きく変わっていて、StatefulSet の API に新しくフィールドが 2 つ追加される & status にもいくつかフィールドが追加される & 細かい挙動まで考慮できてなさそうなので、また物言いが凄くて頓挫しそうな予感

Tsubasa NagasawaTsubasa Nagasawa

2024/5/23

EKS の CoreDNS の Cluster Proportional Autoscaler (CPA) の話

EKS の CoreDNS で最近設定できるようになった Cluster Proportional Autoscaler (CPA) は upstream の実装をいじって設定を抽象化しているのか。独自実装なので、将来的に Node の台数だけじゃなくて、CoreDNS のコンテナのメトリクス (metrics-server 経由での CPU やメモリ使用率) でも水平方向にスケールできるようにもできる (aws/containers-roadmap#1458 (comment))

krustlet のアーカイブの動き

krustlet (Kubernetes 上で WASM module を動かすための kubelet の実装) はコア開発者たちが Deis Labs (MS) から Fermyon (Spin 開発しているところ) や wasmCloud に移って開発が止まっていたけど、CNCF に連絡して正式にアーカイブする流れみたい。oci-distribution の Rust の crate だけ他のプロジェクトでも使われているから ORAS の組織に移動するっぽい。AKS で WASM module を動かす機能は昔は krustlet を使っていたけど、既に deislabs/containerd-wasm-shims を使う形に移行済みでそっちに投資しているからやむなし (krustlet/krustlet#758)

kind の Node イメージのビルドの改善

次のバージョンの kind から Node のコンテナイメージを gzip 圧縮された Kubernetes の資材からビルド可能に (kubernetes-sigs/kind#3614)。これまでは、ローカル環境に Kubernetes のソースコードをダウンロードしてバイナリのビルドからコンテナイメージのビルドまで実行する必要があったが、その必要がなくなる。新しい Kubernetes のバージョンがリリースされた時に kind でのサポートが遅れることが多いが、ビルドしやすくなったことで新しいバージョンをローカルで試すハードルが下がる。自前で Kubernetes のバイナリをビルドする CI / CD パイプラインがあるなら、kind での Node のイメージのビルドと連携しやすくなる。

Kubernetes のリリース資材の置き場 (https://dl.k8s.io) からバイナリをダウンロードしてビルド

kind build node-image v1.30.0
# 以下と同義
kind build node-image --type release v1.30.0

実行結果

❯ kind build node-image v1.30.0
Detected build type: "release"
Building using release "v1.30.0" artifacts
Starting to build Kubernetes
Downloading "https://dl.k8s.io/v1.30.0/kubernetes-server-linux-arm64.tar.gz"
Finished building Kubernetes
Building node image ...
Building in container: kind-build-1716450217-785337277
Image "kindest/node:latest" build completed.

Kubernetes のリモートのリリースの資材置き場を直接指定する場合

kind build node-image https://dl.k8s.io/v1.30.0/kubernetes-server-linux-arm64.tar.gz
# 以下と同義
kind build node-image --type url https://dl.k8s.io/v1.30.0/kubernetes-server-linux-arm64.tar.gz

Kubernetes のローカルの gzip 圧縮された Kubernetes の資材からビルド

kind build node-image $HOME/Downloads/kubernetes-server-linux-amd64.tar.gz
# 以下と同義
kind build node-image --type file $HOME/Downloads/kubernetes-server-linux-amd64.tar.gz

これを発展させて kind のベースイメージのビルド時にも containerd, runc, critools, cni-plugins などをビルドせずにリモートから資材をダウンロードできるようにして、ビルドを高速化したい要望も上がっている (kubernetes-sigs/kind#3626)。

PodSpec の変更と Pod の再起動

PodSpec の中のコンテナ定義の name と image 以外のフィールドの変更でコンテナが再起動しないようにする修正 (k/k#124220)

  • InPlacePodVerticalScaling の機能を有効化するとコンテナ定義が更新されて新しく resizePolicy のデフォルト値が埋め込まれ、kubelet が PodSpec の変更を検知して起動中の全てのコンテナを再起動してしまう問題の修正
  • この再起動の問題を回避するには現状 PodSpec に新しくフィールドを追加する場合にデフォルト値を指定せずに nil 扱いする必要があるが、アルファ機能からベータ機能へ昇格する条件の中で新しく追加したフィールドのデフォルト値を埋め込む必要があるので、いずれ避けられない
  • 同様に Feature Gate を ON / OFF すると指定していたフィールドが認識されなくなるので、コンテナ定義に違いが出てしまう
  • PodSpec の変更を検知する処理の中でコンテナ定義の変更を検知するために、コンテナ定義と ContainerStatus のそれぞれのハッシュ値を比較する
    • 期待する設定 (コンテナ定義) と実際の設定 (ContainerStatus) のハッシュ値に変更がある場合はコンテナ定義に変更があったとみなせる
  • ハッシュ値を生成するためのコンテナ定義のフィールドを name と image のみでに変更した
    • Pod UID やイメージ ID などをハッシュ対象にする必要はない
    • ContainerStatus から比較対象のコンテナのハッシュ値を取得する際に Pod UID で参照するので、仮に Pod が再作成されて Pod UID が変わっても ContainerStatus でヒットしなくなるだけなので気にしなくて良い
  • 今後 PodSpec に新しくフィールドを追加しやすくなる
    • KEP-3619: Fine-grained SupplementalGroups control の実装で everpeace さんが PodSecurityPolicy に SupplementalGroupsPolicy のフィールドを追加しようとしていて、PodSpec の比較の修正が入ったらデフォルト値を埋め込めるようになる話をしていたが、バージョンスキューの関係で n-3 を守らないといけないので Kubernetes 1.34 まではデフォルト値を埋め込められない (k/k#117842 (comment))
Tsubasa NagasawaTsubasa Nagasawa

2024/5/25

Node Swap の機能で tmpfs を除外

KEP-2400 の Pod が Node 上の Swap メモリを使えるようにする機能で ConfigMap / Secret などの tmpfs を利用したメモリ上に保持するボリュームの場合に、中身を Swap 領域に退避されないようにする機能の追加。kubelet の failSwapOn の設定が無効の場合、tmpfs の noswap オプションを指定して tmpfs に書き込まれた内容が Swap 領域に退避されないようにする。Node で tmpfs の noswap オプションが使えるかどうかは実際に noswap オプションを有効化した tmpfs を一時領域に作成して確かめている。確かめ終わったら作成した tmpfs をお掃除している (k/k#124060)

EKS 1.30 リリースと影響のある変更

upstream の Kubernetes 1.30 は API 削除や大きな破壊的変更がなかったみたいな話が出ていましたが、EKS 1.30 は EKS 固有の変更により対応が必要な場合がある (EKS 1.30)

  • 1.30 からマネージドノードグループを新規に作る場合は、デフォルトで AL2023 を使うようになるので、cgroup v2 に移行できない場合は明示的に AL2 の指定が必要。既存のマネージドノードグループは影響なし
  • 予告していたように 1.30 から新しく作成した EKS クラスタでデフォルトの StorageClass がなくなる。以前は自動的に作成された gp2 の名前の StorageClass にデフォルトの StorageClass としてマークするための annotation が付いていたが、付かなくなる。gp2 の StorageClass 自体はあるので、PVC などで明示的に指定している場合は対応不要。Amazon EBS CSI driver のマネージドアドオンの v1.31.0 以降からデフォルトの StorageClass を作成するオプションが追加されているので、それを有効化するでも良い。既存の EKS クラスタでデフォルトの StorageClass がなくなることはなく、影響があるのは新規作成の場合のみ
  • EKS クラスタの最小限で必要な IAM ポリシーに ec2:DescribeAvailabilityZones の権限が実追加された。AmazonEKSClusterPolicy を使わずにカスタムで最小のポリシーを作成している場合は対応が必要。これは 1.30 から topology.k8s.aws/zone-id のラベルが Node に付与されるようになる影響。AWS プロジェクト毎にゾーン名とゾーン ID のマッピングが異なるので、クロスアカウントで物理的に近い場所に Pod を配置したいユースケースのために追加された
Tsubasa NagasawaTsubasa Nagasawa

2024/5/28

WG-etcd-operator の立ち上げ

KubeCon EU 2024 辺りで話に上がっていた etcd-operator の話。SIG-etcd が投資する etcd-operator の開発に向けた要件やユースケース集め、既存の etcd-operator の評価と選定、開発のロードマップ策定のための WG-etcd-operator が発足しそう。初めは etcd-operator の機能のスコープを狭めて、単一もしくは複数のメンバーを含む etcd クラスタの作成、etcd クラスタのスケールアウトとスケールイン、パッチバージョンとマイナーバージョンの更新を目指すみたい (kubernetes/community#7917)

GKE の L4 LB のトラフィックの重み付け

GKE の Service type LoadBalancer + eTP=Local な場合に Maglev による重み付け分散をサポートする予定っぽい。重み付けをユーザーが指定できなさそうなのと eTP=Local な場合だけということは、おそらく Node 上の Pod の数で自動的に重み付けする感じ?(kubernetes/ingress-gce#2562)

Tsubasa NagasawaTsubasa Nagasawa

2024/5/29

kubelet の並列イメージプルの問題

kubelet の並列イメージプルを有効にした場合に、Node 上にスケジュールされた Pod が同一のコンテナイメージを参照していて並列で同じコンテナイメージをプルしようとする問題。同じコンテナイメージのプルで並列数が消費されて、他のコンテナイメージのプルが結局止まってしまう。特に同じ initContainer を複数の種類の Pod で使っている場合に、この問題が起こりやすい (k/k#125164)

修正の PR (k/k#125192)。kubelet の並列プルの機能を有効にすると、kubelet は並列数だけ goroutine を起動してイメージプルの処理を実行する。コンテナイメージ毎に (正確にはプルする ImageSpec の情報毎に) Broker を作成して、既に別の goroutine が同一のコンテナイメージをプルしている場合は、結果が channel 経由で共有されてくるのを待つ。どの goroutine からもまだプルされていないコンテナイメージの場合は、今からこのコンテナイメージをプルするよと記録してからコンテナイメージをプルする。コンテナイメージのプルが終わったら Broker を経由して同じコンテナイメージのプルを待っている人たちに結果を channel 経由で渡して、Broker を停止する。

Tsubasa NagasawaTsubasa Nagasawa

2024/5/30

KEP-3618: Fine-grained SupplementalGroups control のマージ 🎉

everpeace さんが取り組んでいた KEP-3618 の Kubernetes 側の API 追加がマージされてた。すごい。(k/k#117842)

OCI イメージ内で指定したユーザーやグループ ID を PodSecurityContext の RunAsUser、RunAsGroup や SupplementalGroups で上書きできるはずが、実際は OCI イメージ内で定義されたグループ ID も一緒に紐付いてしまう問題。Pod API の PodSecurityContext に新しくSupplementalGroupsPolicy が追加される。破壊的変更を防ぐために、指定がないと既存の挙動と同じ Merge になる。Strict を指定することで OCI イメージ内で指定したグループ ID が紐づかなくなる。Kubernetes 側には API 追加があるだけで、コンテナランタイム側に実際の処理は入る。containerd は PR が上がっていてレビュー中。

Kubernetes における Go 1.23 の破壊的変更の通知

Go の開発チームが直々に Kubernetes のコード修正が必要なことを教えてくれている。(k/k#125170)

Kubernetes で Go が互換性を保証していない外部公開の関数 (testing.MainStart) が使われていて、Go 1.23 でインターフェイスに変更 (実装の必要なメソッドが増える) あって将来的にビルドに失敗するよってことで Issue を上げてくれている。Go の開発に関わっている方が修正の PR (k/k#125176) もあげてくれてた。Go 自身を除けば Go で書かれた最も大きなコードベースだと思うので、Go の開発の人も Kubernetes で影響が出ないか気を遣ってくれている。

// MainStart is meant for use by tests generated by 'go test'.
// It is not meant to be called directly and is not subject to the Go 1 compatibility document.
// It may change signature from release to release.
Tsubasa NagasawaTsubasa Nagasawa

2024/6/1

高速なイメージのダウンロードのために OCI イメージ仕様で何ができるか

OCI イメージフォーマット (イメージ仕様) でサイズの大きなイメージのパフォーマンス改善の議論の中で Linux カーネルの開発者で有名な GKH が召喚されてた (opencontainers/image-spec#1190 (comment))

  • OCI Artifacts が仕様として入ったのでコンテナイメージ以外も配布可能になり、そろそろ以前の OCI v2 の議論を復活させても良いのでは?が議論の始まり
  • OCI イメージ仕様の v1 では読み取り専用のイメージレイヤーは tar でまとめて gzip 圧縮しているだけ
  • 数年前に OCI イメージ仕様の読み取り専用のイメージレイヤーに Enhanced Read-Only File System (EROFS) を利用したら?と GKH が指摘していた (mailing list)
  • EROFS は Android で高速な読み取り専用のファイルシステムを実現するために SquashFS の置き換えとして開発され、コンテナイメージや AI / ML のモデルでも有用であるとされている
  • 「EROFS は利用規模含めて Linux カーネル内でどの程度サポートされているか?推奨される最小の Linux バージョンはいくつか?」という質問の返しが 「10 億台以上とまではいかないが、数億台のデバイス (Android) で毎日使われている。非常に良くサポートされていてオススメ。"最小の Linux カーネルのバージョン"に関しては、カーネルのどの機能を使うにしても Linux カーネルの最新の stable バージョンを使うべき。古いカーネルのバージョンを使うことは推奨されない :)」で笑った。Linux カーネルの開発者にこういう聞き方をしちゃうとそういう返しになるよね
Tsubasa NagasawaTsubasa Nagasawa

2024/6/2

続: kube-scheduler のパフォーマンス劣化のリグレッション

kube-scheduler のリグレッションの修正の後でも Google の内部で行なっている kube-scheduler のパフォーマンステストの結果が悪いらしく、別の方法での修正を試みる PR (k/k#125197)

Google の内部で行なっている kube-scheduler のパフォーマンステストの中に 15k Node で 6 つの DaemonSet を起動するテスト (合計 90k Pod を作成) があって、スループットが悪化している。

  • ベースライン: ~470 pods/s
  • 現在: ~70 pods/s

kube-scheduler の Filter 拡張点で除外された Node がどの plugin で拒否されたかを記録する diagnosis の構造体の NodeToStatusMap への insert の処理が遅いらしく、insert の処理が可能な限り減るようにスケジュールを再試行しても Pod を配置できない Node (UnschedulableAndUnresolvable) の情報を NodeToStatusMap に保存しないように変更している。

2024/6/4更新

  • 修正の PR (k/k#125197) がマージされて、sanposhi さんが scheduler_perf に 15k Node / 30k Pods のテストを追加してスループットが戻っていることを確認済み (k/k#124709 (comment))
  • NodeToStatusMap に追加されるのが Unschedulable の場合だけになったので、Filter 拡張点で評価された Node の数を計算するロジックを単純化できるようになったのでその修正の PR (k/k#125303)
  • kube-scheduler の DaemonSet のスケジュールのパフォーマンス劣化の修正も他のマイナーバージョンに cherry-pick されているのでこれで解決っぽい
Tsubasa NagasawaTsubasa Nagasawa

2023/6/3

TCP oom による Pod へのリクエストのタイムアウト

TCP oom が発生した Node 上の Pod への通信がタイムアウトすることがあるが、kubelet は Node の正常性チェックに TCP oom が発生したかを考慮しないため Node は正常な状態のままになる問題 (k/k#62334)

  • 稀に特定の Node の調子が悪くなって livenessProbe がタイムアウトで失敗しまくるの実はこれが原因だったり?

  • TCP oom が発生すると dmesg に TCP: out of memory -- consider tuning tcp_mem が書き込まれる

  • node-exporter を使っているなら netstat のメトリクスの node_netstat_TcpExt_TCPMemoryPressures を見れば発生したかが検知できそう

  • でかいファイルのやり取りを行なっていると送信バッファが埋まりやすく、TCP oom が発生しやすくなる

  • 発生した場合は、グローバルなカーネルパラメータの net.ipv4.tcp_mem を増やすと良い

  • 現在 TCP ソケットの送信・受信バッファとして割り当てているページサイズを収集したい場合は、node-exporter で以下の設定を追加すれば良い

    --collector.sysctl
    --collector.sysctl.include=net.ipv4.tcp_mem:min,pressure,max
    
  • net.ipv4.tcp_rmemnet.ipv4.tcp_wmem は network namespace 単位で設定が可能なため、Pod の SecurityContext で sysctl で設定できるようにしようとしている PR もある (k/k#125270)

Tsubasa NagasawaTsubasa Nagasawa

2023/6/4

KEP-4572: Move cgroup v1 support into maintenance mode (マージされたので改めて)

  • Kubernetes における cgroup v1 のサポートをメンテナンスモードに移行する
    • 各ベンダーが Linux カーネルのリソース管理や隔離の機能を cgroup v2 に移行する動きと歩調を合わせる形
  • Linux カーネルのコミュニティは cgroup v2 の開発に注力しており、systemd が cgroup v1 のサポートを段階的に終了する動きがあるため、Kubernetes も無視できない状況になってきた
  • Kubernetes としては cgroup v1 のサポートをメンテナンスモードに切り替えること (= cgroup v1 のサポートを続けること) で、互換性を考慮しながら cgroup v2 の恩恵を受けられるよう開発を進められる
  • cgroup v1 の長期的なサポートを望む人たちもいるとは思うが、この KEP は大きな転換期を意味することには注意が必要
    • Linux カーネルや systemd などの重要なシステムや Kubernetes の依存コンポーネントが cgroup v2 に移行しており、Kubernetes もそれらに対応・順応する必要がある
  • KEP-4572 でやること
    • cgroup v1 に関連する新しい機能の追加をやめる。cgroup v1 に関連する既存の機能は実装が完了しており、安定化しているものとする。
    • 既存の機能の動作を保証するために E2E テストは継続する
    • cgroup v1 に関連する重大な CVE の修正パッチは適用する
    • バグの修正はベストエフォートで対応する。脆弱性の修正が優先度高く、重大なバグに関しては解決策が存在すれば対応される可能性がある
    • 大きな変更が必要となるバグは、現状の cgroup v1 のサポートを壊す可能性があるため、解決できるとは限らない
    • cgroup v2 への移行をスムーズに行えるように、移行ガイドを提供する
    • Kubernetes の cgroup v2 サポートの既知のバグ修正に取り組み、cgroup v2 サポートの安定性を向上させる
  • KEP-4572 では cgroup v1 のサポートの削除は行わず、将来的に別の KEP で進められることになる
  • 新しく kubelet_cgroup_version のメトリクスを追加し、cgroup v1 を利用している場合は 1 を cgroup v2 を利用している場合は 2 を返す
    • kubelet が起動時にホストマシンがどの cgroup のバージョンを利用しているか確かめてメトリクスとして公開する
  • Kubernetes 1.31 から cgroup v1 を利用しているホストマシンで動作する kubelet の起動ログに警告メッセージが表示されるようになり、Node の Kubernetes イベントを作成して同様に警告メッセージを通知する
  • kubelet に新しく cgroup v1 のサポートを無効化するオプション (--disable-cgroupv1-support) を追加する (デフォルトで無効)
    • Kubernetes の CI で true を設定し、新規のテストが cgroup v2 を有効化したマシンで実行されるようにするためのもの
    • 明示的に false を設定して、cgroup v1 が有効なマシンで実行することもできる
  • cgroup v1 である前提で書かれているコードを cgroup v2 前提の処理に書き換える
  • cgroup v1 と cgroup v2 の処理が入り混じっているコードに関しても処理をそれぞれ分離して、メンテナンスしやすくする
  • 通常の KEP のプロセスとは異なり、最初から GA として入る機能
    • 最初から GA に行くことになるが、cgroup v2 サポートの既存のバグを全て修正するとあり、無理だったら 1.31 で機能は入らないかも?

大規模クラスタでの EndpointSlice controller 起因の OOM の発生

EndpointSlice controller の Node のトポロジーの情報の更新の処理スループットを改善して kube-controller-manager (KCM) で OOM が発生しないようにする修正の PR (k/k#125294)

  • kube-controller-manager が Node の Informer cache を通じて Node の追加・更新・削除などのイベントを監視するため、大規模なクラスタ (大量の Node がいるクラスタ) だと KCM が OOMKill される可能性がある
  • EndpointSlice controller の Shared Informer に登録したイベント駆動の処理が遅く、大量の Node でイベントが発生することでワークキューが詰まってメモリ使用量が高くなり最終的に OOM が発生してしまう
  • EndpointSlice controller に Node のトポロジーの情報を更新する専用のワークキューを作成し、ワークキューに固定のキーでタスクを積む
    • Node のトポロジーの情報の更新が頻繁に起きないようにレート制限を掛け、KCM のワークキューがパンクすることを防いで OOM を回避できるようにした
    • トポロジーの情報を更新する処理の中で Node の一覧を取得して計算しているので、固定のキーが使える (逆に言うと Node の一覧を取得してトポロジーを計算しているので処理が重い)
  • 見かけない Google の方が修正の PR をあげていて、GKE で問題が起きたっぽい
Tsubasa NagasawaTsubasa Nagasawa

2023/6/6

Job の Pod 削除時の歪な status

Job controller が Pod を削除するときに、Informer cache に反映されるまで Job の .status.ready の更新が遅れる問題。.status.ready を見て判断するような Job の停止や中断に影響したり、Pod を過剰に停止する可能性もある。.status.active はすぐに反映されているようで、Job の並列数を 2 -> 1 に変更した後で、ready が 2 台で active が 1 台、terminating が 0 台 (terminating が 0 台なのは k/k#125175 で修正される予定) のような歪な状態が起きている (k/k#125185)

Tsubasa NagasawaTsubasa Nagasawa

2024/6/8

KEP-1287: In-Place Pod Vertical Scaling の今後

KEP-1287: In-Place Pod Vertical Scaling はエッジケースのバグ報告が多数あって対応が間に合わないのでベータ昇格は Kubernetes 1.32 に見送り。最初 Kubernetes 1.31 でベータ昇格を目指そうとしてたけど流石に無理だった (kubernetes/enhancements#4704 (comment))

  • kubelet_container_resize_requests_total のメトリクスを新たに追加して kubelet が観測したリソース割り当て変更のリクエスト数の合計を追跡できる
    • メトリクスのラベルとして state が追加され、リサイズの状態毎のリクエスト数を追えるようになる
    • proposed: リサイズ要求の初期状態
    • infeasible: リサイズ要求が完了していない状態
    • deferred: リサイズ要求が完了せずリトライ待ちの状態
    • completed: リサイズ要求が完了した状態 (spec.Resources == status.Allocated == status.Resources)
    • canceled: リサイズ要求が完了する前に Pod が停止したか、新しいリサイズ要求が開始されたか

KEP 4420: Retry Generate Name のベータ昇格に向けた動き

KEP 4420: Retry Generate Name は Kubernetes 1.31 でベータ昇格予定 (kubernetes/enhancements#4697)

  • Deployment や DaemonSet などを含む metadata.generateName のフィールドを指定してランダム文字列を含むリソースを作成した場合にリソース名が衝突したら、8 回まで kube-apiserver の内部でリソースの作成をリトライしてくれる機能
    • 元々ランダム文字列を 5 文字から 10 文字に増やす案もあったが、5 文字のランダム文字列に依存している処理を書いたコードが意外と多くあって破壊的変更になる
    • 8 回リトライするとランダム文字列が 11 文字の場合と同じ衝突確率になるので選ばれた
  • ベータ昇格で特に大きな変更はなし

KEP-4004: Deprecate status.nodeInfo.kubeProxyVersion field のベータ昇格の動き

KEP-4004: Deprecate status.nodeInfo.kubeProxyVersion field も Kubernetes 1.31 でベータ昇格予定 (kubernetes/enhancements#4625)

  • kubelet が Node の status.nodeInfo.kubeProxyVersion に kube-proxy のバージョンを指定しているが、kubelet は実際に利用されている kube-proxy の情報を取得している訳ではなく、kubelet のバージョンを指定している
  • kube-proxy を利用しない Service Proxy の実装も使われ始めているので、混乱の元になる
  • 元々は in-tree の Google Cloud 向けの kube-cloud-controller-manager (KCCM) の実装が Kubernetes 1.7.0 のバグを回避するために kube-proxy のバージョンをチェックして挙動を変えるために利用していた
    Service type LoadBalancer で作成した LB のヘルスチェックに kube-proxy (hostNetwork: true) が 10256 番ポートで公開しているヘルスチェックを利用するようになったが、Node Problem Detector を systemd で動かしているときに公開するポート番号も当時は同じ 10256 番ポートで (1.7.2 から 20256 番ポートを利用するようになった) 衝突する問題があった。kube-proxy のバージョンが 1.7.2 以降でないと KCCM が動作しない制約を設けるために status.nodeInfo.kubeProxyVersion の情報を利用していた
  • kubelet が Node の status.nodeInfo.kubeProxyVersion を設定しないようにする変更で、ベータ昇格時に大きな変更はなし

KEP-4706: Deprecate and remove kustomize from kubectl

  • まだ KEP の PR は上がっておらず Issue のみ、一応 Kubernetes 1.31 を目指しているが間に合うかは怪しい
  • SIG-CLI の録画から (youtube)
    • KubeCon EU 2024 から議論を始めていたが、kubectl から kustomize 連携の機能を削除する
    • kustomize のプロジェクトが廃止になる訳ではなく、kustomize は kubectl 同梱でなく独立したバイナリとして使う形に
    • kubectl から kustomize 関連の依存ライブラリを削除できたり、kubectl 同梱の kustomize のバージョン管理 (kubectl と kustomize でリリースサイクルが異なるので) からも解放される
  • KEP の PR が上がってから議論が始まるので確定ではないが、少なくとも SIG-CLI の中で反対意見はないし同梱を辞める方向で動きそうなので、kubectl 同梱の kustomize を使っている場合 (ほぼないと思うが) は kustomize の独立したバイナリを使うように移行した方が良さそう

Karpenter に Headroom API を追加する提案

Karpenter 版の ProvisioningRequest API として Headroom API を追加する提案 (Google Docs)

  • 2023/6 に Cluster Autoscaler (CAS) で ProvisioningRequest API が提案され、2023/9 にマージされた
  • ProvisioningRequest API は当初から Kueue と連携しており、CAS のメンテナは ProvisioningRequest API をベータ昇格しようとしている
  • ProvisioningRequest API が提案された時、Karpenter プロジェクトもその存在に気付いてはいたが、全てのユースケースに対応できているか疑問だった & Karpenter の SIG-Autoscaling への寄贈や Karpenter の v1beta1 API 対応で忙しかった
  • Karpenter プロジェクトでも ProvisioningRequest API で満たせる要望やそうでない要望がいくつか挙げられている
  • ProvisioningRequest API で実現可能なユースケースをまとめ、現状の API だと実現できない Karpenterチームが求めているユースケースを洗い出し、ProvisioningRequest API が GA するまでに CAS と Karpenter で API を擦り合わせたいので、現状の API の課題を言語化したドキュメント
  • 最終的な目標は CAS と Karpenter が SIG-Autoscaling として ProvisioningRequest / Headroom API の概念を統一し (Node の自動スケールに関する共通の概念をまとめる動きがある)、2 つのプロジェクトの要件を満たす API に昇華して、Volcano や Kueue などが CAS / Karpenter と連携する際に 1 度対応すれば良くなるようにしたい
  • ProvisioningRequest API は CAS 独自の機能で、Pod のスケジュール前に Node を事前にプロビジョニングしてクラスタに追加する機能
    • 事前に Node を払い出すので Pod スケジュールのレイテンシを抑えられ、アトミック操作 (必要な台数の Node が払い出せなかったそれまでに作った Node を削除する) として Node をスケールアウトできる
  • ProvisioningRequest API で実現可能なユースケース
    • Pod のリソース要求を元に事前に Node を余剰で起動して、プールとして保持しておき、Pod の起動時間を短縮したい
    • Pod が存在しない場合でも最低限必要な Node の台数を確保しておくことで、Pod を 0 台から起動する場合でも高速に起動できるようにしたい。ProvisioningRequest API で指定した最低限必要なリソース要求を超えた場合は、普段と同じように Pod がスケジュールされる
    • AI / ML の学習などバッチ処理の Pod を必要な台数だけ必ず起動したい場合に、アトミック処理で Node をスケールしたい。必要な台数の Node を確保できない場合は、それまでに起動した Node を停止したい
    • クラスタ内の利用可能なリソース容量に基づいて Pod のグループをスケジュールできるか事前に検証したい
  • Karpenter が求めている ProvisioningRequest API で実現できないユースケース
    • ProvisioningRequest API は Pod (アプリケーション) のリソース要求を元に事前に Node を起動するが、Karpenter のプロジェクトではユーザーが特定のリソース容量の Node を事前に起動しておきたいユースケースがある
    • クラスタ管理者がアプリケーションの詳細を知らなくても、余分に確保しておきたい Node の台数を指定して (e.g. あるインスタンスタイプの Node を 10 台) 起動しておきたい
    • 必要最低限の Node の台数を起動しておくことで、0 台からスケールする Pod がすぐに起動できるようにしたい
    • ProvisioningRequest API を拡張して上記の"静的な容量"の Node を確保しておくユースケースを実現できないか?
  • ProvisioningRequest API は PodTemplate の参照 (PodTemplate は別で作成が必要) と必要な Pod の台数をリスト形式で指定することで Node を確保する
  • Karpenter が提案する Headroom API は ProvisioningRequest API と同様の Pod を元に余剰 Node を確保する機能と特定のスペックの Node を何台欲しいといった形で余剰 Node を確保する機能がある
    • ProvisioningRequest API と違って PodTemplate を Headroom API の中に inline で記述する形で、更に 1 Headroom API に 1 つの PodTemplate しか記述できない
    • ProvisioningRequest API では Pod に cluster-autoscaler.kubernetes.io/consume-provisioning-request の annotation に ProvisioningRequest の名前を指定することで、scheduler が ProvisioningRequest を利用している Pod を特定できるようにしているが、Headroom API では Headroom API で指定したラベルセレクタで対象の Pod を選択する形を取っている
    • ProvisioningRequest API では Node のスケールアウト時に必要な台数を確保できないと既存の Node を削除するアトミック処理 (all or nothing) となっているが、Headroom API では現状は all or nothing のサポートがない
      • Karpenter としては SIG-Scheduling が進めている Gang Scheduling の議論で合意形成が取れたらそれに従って all or nothing のサポートを実装したい
    • ProvisioningRequest API では check-capacity モードと呼ばれる既存のクラスタの容量で希望する Pod の台数を起動できるか CAS がシミュレーションを実行して ProvisioningRequest の status に結果を記録する機能があるが、Karpentar ではサポートされていない
      • Karpenter としては宣言的に Pod を起動できるか確認するよりも HTTP ベースの API で結果を教えてくれる方が良いのでは?というスタンスみたい
    • ProvisioningRequest API は ProvisioningClass や AdditionalParameters、AdditionalStatus といった拡張可能な仕組みがあって、check-capacity モードや atomic-scale-up モードや今後増えるかもしれないモードをユーザーが選択できるようにしているが、Karpenter ではサポートしていない
      • Karpenter としては不要な拡張性は取り入れたくないスタンスのようで本当に必要なのか聞いている
Tsubasa NagasawaTsubasa Nagasawa

2024/6/9

KEP-4010: Add HEAD Request Probes Support の難しさ

KEP-4010: Add HEAD Request Probes Support で Probe に新しく HEAD リクエストを送れる httpHead アクションを追加する提案が以前から上がっているが、費用対効果の観点から Tim Hockin は懐疑的。(kubernetes/enhancements#4012 (comment))

API サーバ側で Probe に新しく httpHead アクションを追加するとユーザーが指定できるようになる。ただし、Kubernetes は n-3 のバージョン差異の縛りがあるので、1.31 のコントロールプレーンと 1.28 の Node の組み合わせもありうる。(とはいえ、Sidecar containers の機能など毎回バージョン差異を考慮して機能を入れていない印象。) その場合、kubelet は当然 httpHead のアクションを解釈できないのでエラーとなって Pod が Ready 状態にならなくなる。エラーを回避しようと思うと、周りくどい方法を取るしかない。Kubernetes 1.31 で kubelet にヘルスチェックとして HEAD リクエストを送る処理を追加し、Kubernetes 1.34 まで待ってから API に変更を加えて Probe のアクションとして httpHead を追加する。ただ、Ingress controller の考慮も必要。Ingress controller が Pod の readinessProbe をみて LB のヘルスチェックを設定しようとするが、LB の多くが HEAD リクエストをサポートしていないので、その場合にどうするか?GET リクエストに暗黙的に変換するのは良くないはずだが、他に良い方法も思い付かない。アプリの実装者が GET リクエストの軽量なエンドポイントを実装し、少ないメッセージを返す方がよっぽど現実的。なので、費用対効果の観点から KEP-4010 の実装には懐疑的みたい

kube-proxy の nftables モードのパフォーマンス

Red Hat の人が kube-proxy の iptables モード vs nftables モードのパフォーマンスをテストしていて、ネットワークプログラミングレイテンシ (ルールの更新に掛かる時間) と実際のパケットの処理に掛かる時間の両方を見ている。(kubernetes/enhancements#4663 (comment))

nftables モードでネットワークプログラミングレイテンシの悪化が見られているようで、原因はまだ完全に分かっていない。ユーザー空間でのルールのパースなどが原因という訳ではなく、カーネル内で実際にルールが再読み込みされる時に遅くなっていそう。既存の Linux ディストリビューションの iptables は内部的に nft ベースに置き換わっているので、kube-proxy の nftables モードの時にだけ遅くなるのはおかしい。ただ、nftables モードにのみ実装されている set 型のデータ構造に要素を追加する操作などが遅くなっている可能性はある。パケットの処理に掛かる時間に関しては顕著な改善は見られなかった。kube-proxy が作成する程度のルールの数では iptables モードの頃から nat テーブルの線型探索がパケットの処理に影響するほど遅いとは言われたことがなかったので、これは予想通りの結果。filter テーブルに関しては iptables モードの頃からパケット処理に影響が出たことがあった。ただ、徐々に遅くなるというよりは急に壊れる系の問題だったので nftables モードで同様の問題が起きないかは確認する必要がある。

Tsubasa NagasawaTsubasa Nagasawa

2024/6/10

Cilium の Traffic Distribution のサポート

Cilium の kube-proxy なしのモードで Kubernetes 1.30 でアルファ機能として入った KEP-4444: Traffic Distribution for Services に対応 (cilium/cilium#32678)

KEP-4444 の前身の Topology Aware Routing の機能は既に Cilium でも使えたので、その処理に Service の spec.trafficDistribution も考慮するように変更を加えただけ。EndpointSlice に Hint を追加するのはあくまで EndpointSlice controller で、KEP-4444 の場合は Zone 毎の Endpoint の数だけを考慮するシンプルなもの (Topology Aware Routing のように Zone 毎の CPU 数での補正は入らない)。KEP-4444 では EndpointSlice の Hint に依存しない独自の実装を追加することも可能だが、Cilium では対応予定なし。KEP-4444 は Kubernetes 1.31 でベータ昇格予定でデフォルト有効になるので、Google の Rob Scott さんが対応を入れた。GKE の Dataplane v2 でも使えるようになるはず。(GKE が使っている Cilium は既に Google さんが一部手を加えているので、upstream の Cilium に入らなくても GKE では使えるようになってたかも)

KEP-2837: Pod Level Resource Specifications

  • PodSpec のリソース割り当てはコンテナレベルで設定するようになっており、コンテナ毎にリソース要求と上限を指定する
  • kube-scheduler はコンテナ毎のリソース要求を合計して Pod を配置するのに最適な Node を見つける
  • kubelet はリソース要求と上限を Pod レベルとコンテナレベルの cgroup の設定にそれぞれ変換して設定するが、現状の Pod API では Pod レベルのリソース要求は指定できないので Pod 全体でのリソース管理がやりづらい
  • KEP-2837 では Pod API に CPU やメモリなどの通常リソースの要求と制限を指定できるようにする
  • 複数のコンテナを持つ Pod でコンテナ毎のリソース使用量が予測しづらい場合やバーストしがちなワークロードの場合に、リソース要求や上限を設定し辛く、リソースを余計に割り当ててリソース枯渇が起きないようにしがち
  • Pod レベルのリソース要求や上限が設定できると、Pod 全体で必要なリソースを設定するだけで良く、コンテナ単位で厳密に割り当てる苦労から解放され、cgroup の制限がコンテナ全体に緩められるのでバーストしがちなワークロードのリソース効率が高くなる
  • Pod レベルとコンテナレベルのリソース要求や上限は併用可能
    リモート開発環境の Pod が IDE や LSP (Language Server Protocol)、ターミナルやそれ以外のツールをサイドカーコンテナとして 1 つの Pod 内で起動する場合に、Pod レベルと IDE のコンテナのリソース要求や上限だけを設定するといった使い方が可能
  • 通常は idle 状態だけど定期的にバーストするワークロードのコンテナが複数ある Pod でリソース上限を設定しようと思うと、バースト時の最大のリソース消費を元に各コンテナのリソース上限を設定する必要があるが、Pod レベルのリソース上限が設定できるとバースト時の最大のリソース消費の合計よりも低い値を設定することができる
  • Pod レベルの cgroup の設定は既にあって、コンテナランタイムに親の cgroup の設定を渡している (これが Pod レベルの cgroup に当たる) ので新しい概念ではなく、cgroup の構造が変わることはない
  • Pod レベルのリソース要求はコンテナレベルのリソース要求の合計と同じか大きい値でなければならない
  • Pod レベルのリソース上限はコンテナレベルのリソース上限の合計に依存せず好きな値が設定可能
    • Pod 内のそれぞれのコンテナの最大の使用量の合計は高いが、ピークが必ずしも同時に発生しない場合に有用
  • Pod レベルでリソース要求だけ設定して、コンテナレベルでリソース上限だけを設定した場合にどうなる?
  • Pod レベルとコンテナレベルでリソース要求が設定されている場合、kube-scheduler は Pod レベルのリソース要求を優先して Node を決める
  • Pod レベルとコンテナレベルでリソースが指定されている場合、QoS は Pod レベルのリソースを優先して判断される
  • Pod レベルのリソース要求とリソース上限が同じ値の場合、コンテナレベルのリソースの指定がどうであれ Guaranteed QoS として扱われる
  • Pod レベルのリソースが設定されていなくて、コンテナレベルのリソースが全て同じ値で設定されている場合も Guaranteed QoS として扱われる
  • Init Containers と Sidecar Containers がある場合のリソースの計算式は変わる予定だが、どう変えるかは検討中
Tsubasa NagasawaTsubasa Nagasawa

2024/6/11

KEP-4706: Deprecate and remove kustomize from kubectl

  • kustomize の開発が始まってすぐに kubectl に組み込まれることになったが、当時は宣言的なリソース管理の幅を広げる思惑があった
  • それ以降いろいろなツールが開発され、kubectl の役割として一つのツールだけを推すのは良くない
  • kubectl と kustomize はリリースサイクルが異なるので、kubectl に同梱された kustomize は最新ではなく問題になる可能性がある
  • kustomize の依存ライブラリの一部は Kubernetes プロジェクトとしても問題視しているものがあり、kubectl から kustomize を削除できると kubectl のバイナリサイズの削減も期待できる
  • Kubernetes 1.31 で kubectl kustomize と kubectl の —kustomize フラグ、kubectl version の kustomize の情報の非推奨をアナウンスする。使用すると警告メッセージが出るようになる & KUBECTL_LEGACY_KUSTOMIZE の環境変数が追加されて kustomize の機能をオフにしたいユーザーは false にすると挙動を確かめられる。この時点では KUBECTL_LEGACY_KUSTOMIZE がデフォルトで有効なので kubectl で kustomize の機能は使える。
  • Kubernetes 1.31-1.33 まではユーザーからのフィードバックを受けつつ、krew で kustomize をインストールできるようにする
  • Kubernetes の機能の非推奨や削除のルールに従って、Kubernetes 1.34-1.35 で kubectl からデフォルトで kustomize を無効化する。KUBECTL_LEGACY_KUSTOMIZE の環境変数をデフォルトで無効にする。
  • 2026 年の初頭に予定されている Kubernetes 1.36 で KUBECTL_LEGACY_KUSTOMIZE の環境変数を切り替えられないようにロックして、1.37 で kubectl から kustomize の機能を完全に削除する予定
Tsubasa NagasawaTsubasa Nagasawa

2024/6/13

Pod の Service Account に ConfigMap / Secret の読み取り権限が不要な理由

Pod が ConfigMap / Secret を環境変数やファイルとしてマウントするときに Pod の ServiceAccount に ConfigMap / Secret の読み取り権限は不要。kubelet が代わりに ConfigMap / Secret の中身を読んで環境変数などに設定しているからというのが建前だけど、言われてみると同じ namespace なら無条件に ConfigMap / Secret を参照できるの違和感が (kubernetes/enhancements#4524 (comment))

Tsubasa NagasawaTsubasa Nagasawa

2024/6/14

KEP-3619: Fine-grained SupplementalGroups control

KEP-3619: Fine-grained SupplementalGroups control の containerd 側の実装がマージされた。Kubernetes 側に E2E テストを実装する PR も上がっていたので、CI で KEP-3619 に対応した containerd が使えるようになるのを待つ感じ?CRI-O の実装は Red Hat の人がやってくれるらしいとこの前 everpeace さんが言ってた。

kubectl 同梱の kustomize の機能の非推奨かへの物言い

kubectl 同梱の kustomize の機能を非推奨化して削除する話は Jordan Liggitt や Tim Hockin から強い反発があるのでまた二転三転しそう (kubernetes/enhancements#4706)

Tsubasa NagasawaTsubasa Nagasawa

2024/6/16

kube-scheduler の Scheduling Gates 周りの問題

kube-scheduler で少し前に Scheduling Gates が有効な Pod が大量にいる時のスケジュールのパフォーマンス劣化を解消したけど、それによりまた新たな問題が (k/k#125223 (comment))。

PreEnqueue 拡張点で Pod 以外のリソースの変更によりスケジュール可能かの結果が変わる場合に問題になる。例えば、DRA で ResourceClaimTemplate を使って ResourceClaim を払い出して Pod に紐づける場合、Pod 作成時にはまだ ResourceClaim が作成されていないので PreEnqueue 拡張点で弾かれて unschedulable pods に留まる。その後で controller が ResourceClaim を作成して、Pod の status を更新する。Pod の status が更新されたので、再度 activeQ に移動できるか確認するが、Pod 更新のイベントであって ResourceClaim 追加のイベントではないので PreEnqueue 拡張点で再度弾かれる。やっと ResourceClaim 追加のイベントを検知するが、今度はパフォーマンス劣化を解消した修正 (PreEnqueue 拡張点で弾かれた Pod は activeQ に移動しない) のせいで unschedulable pods から一生出られなくなる。

Tsubasa NagasawaTsubasa Nagasawa

2024/6/18

aws/eks-pod-identity-agent

AWS が EKS Pod Identity エージェントの実装を OSS として公開。

hostNetwork が有効な DaemonSet として動いて、initContainer でインターフェイスを作成して固定のリンクローカルアドレス (169.254.170.23) を割り当てる。メインのコンテナではそのインターフェイスを使って 80 番ポートでサーバを起動する。EKS のコントロールプレーンで動いている EKS Pod Identity Webhook (Mutating Webhook) が namespace と Service Account のペアが書かれた JSON 形式のファイルを動的に読み込んで、Pod が対象の Service Account を参照していたら新しく AWS SDK に追加されたコンテナ認証情報プロバイダーを利用できるように環境変数を差し込む。差し込まれた環境変数の中でも AWS_CONTAINER_CREDENTIALS_FULL_URI に Pod Identity エージェントが公開しているサーバの固定のリンクローカルアドレスが指定された URL を埋め込む (e.g. http://169.254.170.23/v1/credentials)。また、AWS_CONTAINER_AUTHORIZATION_TOKEN_FILE の環境変数にコンテナ内に Token Request Projection の機能 (Token Request API で発行したトークンを Projected Volume として Pod に自動的にマウントする機能) を使ってマウントした Service Account の認証トークンのパスを埋め込む。Token Request API で発行するトークンには aud claim の値として pods.eks.amazonaws.com が設定される。起動した Pod はマウントされた Service Account の認証トークンを使って EKS Pod Identity エージェントに IAM の認証情報と交換するよう依頼する。EKS Pod Identity エージェントは EKS Auth API を呼び出して Service Account の JWT トークンとクラスタ名を渡す。EKS Auth API は JWT トークンに紐付いているロールを検証する。この時に検証するのが事前に EKS Auth の中の CreatePodIdentityAssociation API で紐付けた Kubernetes の Service Account と IAM ロールの紐付けの情報。EKS Auth API は Assume 先の Role の一時的な認証トークンを発行して、Assume 先の Role の情報などと一緒に返す。EKS Pod Identity エージェントはこの認証トークンをキャッシュして、有効期限が切れるまでは使い回す。Pod はこの認証トークンを使って AWS の API を呼び出す。

GKE の Workload Identity の場合は Pod 内の iptables のルールで GCE のメタデータサーバへの通信を metadata-server の DaemonSet の Pod への通信にリダイレクトするので、hostNetwork が有効な Pod だと Workload Identity の機能が使えない制約があったけどそういうのはなさそう。ただ、前から言われているように AWS SDK がコンテナ認証情報プロバイダーをサポートしていないとダメ。それと、Pod Identity エージェントが hostNetwork 有効かつリンクローカルアドレスではあるものの 80 番ポートで公開しているので、別のプロセスが 0.0.0.0:80 でサービスを公開しようとすると問題になる。HAProxy や Nginx の Ingress controller で問題が起きた報告もあったくらい (aws/containers-roadmap#2356)

Tsubasa NagasawaTsubasa Nagasawa

2024/6/19

containerd v2.0.0 RC + KEP-127: User Namespaces 併用時の問題

containerd v2.0.0 RC + runc 1.2.0 RC を使った事前検証がちょこちょこ始まっている。KEP-127: User Namespaces の機能を有効にした状態で containerd を再起動すると全ての Pod の PodSandbox から CNI の情報が全て消える。その状態で kubelet を再起動すると、起動時に PodSandbox の情報を確認してネットワークの情報が消えていることに気付き PodSandbox を再作成 (Pod を再起動) してしまう問題の報告 (containerd/containerd#10363)

Tsubasa NagasawaTsubasa Nagasawa

2024/6/21

kubectl wait に新しく --wait-for-creation フラグを追加

kubectl 1.31 から実行時に存在しないリソースに対して kubectl wait で特定の状態に遷移するのを待てるようになる。以前は存在しないリソースに対して実行するとエラーになっていた。--wait-for-creation のオプションを false に設定して以前の挙動に戻すこともできる。

更新

  • —timeout=0 の場合の挙動も変わるということで一旦 revert された (k/k#125630)
  • —wait-for-creation のデフォルト値を無効にした新しい PR (k/k#125632)
Tsubasa NagasawaTsubasa Nagasawa

2024/6/22

Service を経由したヘアピントラフィックに対する NetworkPolicy の挙動

NetworkPolicy で同一 namespace 内での通信を許可していて、Pod が Service を介して自分自身へ接続する (hairpin 接続) の場合に NetworkPolicy の実装によって (この場合は Antrea) は想定通りに動作せず、タイムアウトになってしまう問題

  • NetworkPolicy の実装者は Pod A から Pod A への通信は NetworkPolicy にかかわらず許可すべき
  • Pod A から Pod A への通信が NetworkPolicy で明示的に拒否されている場合は、Pod A -> ClusterIP -> Pod A の通信を許可するか拒否するか実装者が決める必要がある
  • Pod A -> Pod A の通信が NetworkPolicy で許可されている場合は Pod A -> ClusterIP -> Pod A も許可すべき。仮に Pod A が Node IP で SNAT される場合かつ Node IP -> Pod A が拒否されていても許可すべき。この挙動は実質的に kubelet -> Pod A の通信を暗黙的に許可している現状の抜け穴によるもの。
Tsubasa NagasawaTsubasa Nagasawa

2024/6/23

Node Lifecycle Controller が Unhealthy な Node 上で動いている Pod を NotReady 状態にマークしない問題

Graceful Node Shutdown 時に Node の状態が Unhealthy (Ready=False) になるが、その Node で実行している Pod が NotReady 状態に遷移しない問題

  • kube-controller-manager (KCM) の中の Node Lifecycle controller は Node の状態をデフォルト 5 秒間隔 (nodeMonitorPeriod で変更可能) で監視して、Node の状態に応じて NoScheduleNoExecute などの Taint を追加したり、その Node 上で動作している Pod を NotReady 状態に変更したりする
  • 現在の実装では nodeMonitorGracePeriod の時間 (デフォルトで 40 秒) を過ぎても Node Lease (kubelet による Node のハートビートの仕組み) が更新されなかった時 (= 何らかの問題で kubelet が停止し起動できなくなった場合) にだけ Pod を NotReady 状態に変更する
  • Node が Unhealthy 状態に遷移しても、kubelet が Node Lease を更新できている間は、その Node 上で動作している Pod は NotReady 状態にならない
  • kubelet が一時的に停止した場合などは今の挙動で問題ないが、Graceful Node Shutdown 時に問題になる
  • Graceful Node Shutdown は Node を安全に停止する仕組みではあるが、Spot インスタンスなどを利用していて十分な時間が残されていない場合や kubelet が何らかの原因で Node の状態を更新できなかった場合など、Node 上で動作している全ての Pod を安全に停止できない可能性がある
  • Graceful Node Shutdown の機能では Node を停止する前に Node の状態を Unhealthy に変更するが、Node Lifecycle controller の現在の実装ではその Node 上で動作している Pod を NotReady 状態に変更しない
    • Graceful Node Shutdown の機能により Node 上の Pod を完全に停止できなかった場合に、Terminating 状態に遷移せずに Node が停止した後に Completed or Failed 状態に遷移する Pod が出てくる
    • Node の停止処理が開始したら Endpoint / EndpointSlice からその Pod の情報を削除して欲しいが、削除されずリクエストが流れて接続エラーになる報告がある (k/k#116965)
  • Node Lifecycle controller が Node の状態が Unhealthy になった時にその Node 上で動作する Pod を NotReady 状態に変更できると上記の問題を解消できるが、一時的に Node が Unhealthy 状態になった場合は今の挙動のままにしたい

[Kubernete 1.30] kube-apiserver の watch のデバッグ用途のログが実行直後に書き込まれる問題

Kubernetes 1.30 のリグレッションで kube-apiserver の HTTP レスポンスの詳細なログの内容がおかしくなっている問題の報告と修正

  • リソースに対する watch リクエストは長時間続くことが多く、watch リクエストを処理するハンドラを直列で実行すると watch リクエストの処理に必要ない事前処理の情報までスタック上に残ってしまい、メモリ効率が悪くなる
  • Kubernetes 1.30 から watch リクエストの処理を別の goroutine に逃したことで、スタック上の不要なメモリを解放できるようになった
    • 5000 個の watch リクエストを処理している kube-apiserver でメモリ使用量が 150 MiB 程度削減できるようになった
  • Kubernetes 1.30 の実装の変更時に APIServingWithRoutine の FeatureGate が導入されているが、デフォルト有効なので明示的に無効にしない限り影響が出る
  • kube-apiserver は API リクエスト (Kubernetes リソースに対する CRUD) のパスやレイテンシ、HTTP スタータスコード、APF の情報などの詳細をログとして書き込みデバッグしやすくしている
  • Kubernetes 1.30 以降でリソースの watch リクエストに対するデバッグ用のログが HTTP ステータスコードの情報が空 (resp=0) だったり、レイテンシも実際の watch リクエストの時間ではなく短い値 (watch リクエストの処理を開始するまでに掛かった時間) を埋め込むようになってしまった
    • watch リクエストの処理を別の goroutine に逃した際に、watch リクエストの処理を開始した後ですぐにログを書き込むようになったのが原因
  • watch リクエストを処理するタスクが完了してから別の処理を実行できる仕組みを追加して、watch リクエストの処理が終わった後でログを書き込むように修正しようとしている (k/k#125626)
    • 現在書き込んでいる watch リクエストの初期化に掛かる時間を知りたかったら、apf_execution_time で大体の傾向が分かる (同じ値では当然ない)
Tsubasa NagasawaTsubasa Nagasawa

2024/6/24

KEP-4639: adding OCI VolumeSource

  • Pod の VolumeSource で OCI イメージや OCI Artifacts を指定できるようにする KEP
    • コンテナイメージ内に資材を含める必要がなくなり、脆弱性の攻撃範囲を減らしたり、コンテナイメージのビルドをシンプルにできる
  • OCI イメージは Kubernetes や CRI で広くサポートされてきたが、OCI Artifacts のサポートのために対応が必要
    • コンテナランタイム側で新しい mediaType を解釈できるようにしたり、ダウンロードした OCI Artifacts のライフサイクル管理、OCI Artifacts の Referres API によるマニフェストの参照のサポートやセキュリティ対策などが必要
  • Kubernetes として OCI イメージや OCI Artifacts を VolumeSource として指定できるようになると、OCI 標準に準拠したあらゆるコンテンツを OCI レジストリから配布できるようになり、コンテナイメージを実行する以外のユースケースに対応できる

KEP-4639 で目指すこと

  • VolumeSource に新しいタイプを追加して、OCI イメージや OCI Artifacts を指定可能にする
  • Pod 内の複数のコンテナでファイルを簡単に共有できるようにする
  • ランタイム側で OCI Artifacts のファイルやディレクトリをどうマウントするべきかのガイドラインを提供する

KEP-4639 で目指さないこと

  • 既存の VolumeSource のタイプを置き換えない
  • Pod 内の複数のコンテナ間でディレクトリを共有する以外の OCI オブジェクトの取り扱いは範囲外
  • 現状は単一のファイルとしてマウントするだけで、ディレクトリとしてマウントする機能は範囲外
  • CRI-O や containerd などで OCI Artifacts をディレクトリとしてどう展開するかは議論する予定だが、mediaType やアトリビュートをベースに独自の処理を加えることは今は考えず今後検討したい
    • OCI Artifacts として ML のモデルをどういう形で保存してどう配布するかを特定のプロバイダーの実装に制限したくない
    • VM の qcow 形式を OCI Artifacts として保存できるが、ランタイム側でそういったフォーマットを認識して正しく処理するのは少なくともアルファの段階では範囲外としたい
  • manifest list はコンテナイメージで現状サポートしているアーキテクチャの選択に限定し、モデルの量子化やフォーマット、それ以外のアトリビュートによる選択は今後考える
    • アルファの段階では量子化されたモデルやフォーマット、アトリビュート毎に VolumeSource を指定すること

KEP-4639 のユースケース

  • コンテナイメージの中に設定ファイルを含めることなく、Pod 内の複数のコンテナで設定ファイルを共有できるようにしたい
    • OCI オブジェクトとしてファイルを保存して配布できるようにしたい
    • コンテナイメージをダウンロードした時と同じ認証情報を使って設定ファイルをダウンロードしたい
    • コンテナイメージと同様に pullPolicy: Always を指定することで、設定ファイルに動的な latest タグを指定し、Pod を再起動するだけで新しい設定を反映できるようにしたい
  • DevOps エンジニアがバイナリアーティファクトを OCI Artifacts として配布し、CI / CD のパイプラインの中でそのバイナリを OCI オブジェクトとしてマウントして Pod 内から参照できるようにしたい
  • データサイエンティストや MLOps エンジニアがモデルサーバ内に巨大な機械学習のモデルをマウントできるようにし、コンテナイメージの中にモデルを同梱する必要がなくなるようにしたい
  • セキュリティエンジニアが製品として購入した OS やスキャナのバージョンに依存しないシグネチャをコンテナイメージ内に含めず (ライセンス的に含めて公開すると問題になる)、別の OCI オブジェクトとしてマウントしてマルウェア検知できるようにしたい

用語集

OCI Image

  • OCI イメージ仕様に従って作成したコンテナイメージで、コンテナイメージを実行するために必要なファイルシステムやメタデータが同梱されている
  • tarball で圧縮された複数のレイヤーとレイヤーの一覧を表すマニフェスト、環境変数やエントリーポイントなどの設定ファイルを含む

OCI Artifacts

  • OCI イメージ形式を用いて保存・配布できるコンテンツのことで、コンテナイメージだけではなくて Helm chart や Wasm module、機械学習のモデルなども含む
  • コンテナイメージと同じマニフェストやレイヤー構造をとるが、レイヤー内にコンテナイメージとは異なるデータを含んだり、mediaType を使うことがある

OCI オブジェクト

  • OCI イメージや OCI Artifacts の両方を包含する言い方。OCI 仕様に準拠したオブジェクトでコンテナランタイムによってファイルやファイルシステムとして扱われる

実装の詳細

  • OCI イメージを直接マウントできると攻撃範囲を増やすことになるので、信頼できるレジストリ以外からダウンロードできないようにするなど対応が必要。パストラバーサル攻撃にも注意が必要で、コンテナランタイムはレイヤーのマージやシンボリックリンクの取り扱いなどを既存のコンテナイメージの実装を再利用して対応するべき。

  • VolumeSource に新しく OCI タイプを追加し、reference は必須で OCI Artifacts を指定する。pullPolicy はオプションでデフォルトは IfNotPresent

    • pullPolicy に関してはコンテナイメージと違って Pod レベルでしか指定できない & マウントした内容を更新したい場合は Pod レベルで再起動が必要
    apiVersion: v1
    kind: Pod
    metadata:
      name: example-pod
    spec:
      volumes:
      - name: oci-volume
        oci:
          reference: "example.com/my-image:latest"
          pullPolicy: IfNotPresent
      containers:
      - name: my-container
        image: busybox
        volumeMounts:
        - mountPath: /data
          name: oci-volume
    
  • コンテナランタイム側で新しい mediaType を認識して処理できるようにし、コンテナイメージと同様に効率的・安全に OCI Artifacts を保存できるようにする

  • ホストマシンに保存された OCI Artifacts はコンテナイメージと同様に kubelet の GC でライフサイクルを管理する

    • 参照している Pod がいたら削除しないなど
  • アルファ時点ではサポートしないが、subject フィールドを含んだ OCI Artifacts にも対応予定

    • Referrers API を使って別の OCI Artifacts のマニフェストを参照する仕組み (e.g. SBOM で対象のプラットフォームのイメージを参照するとか) もアルファ以降に議論していく
  • CRI の RPC は既存のコンテナイメージと同じ API を再利用する予定、ImageSpec や PullImageResponse などにはマウントに関わる情報が追加される

    • kubelet が CRI を介してコンテナランタイムの PullImage の RPC を呼び出す
    • コンテナランタイムが OCI オブジェクトをファイルシステムとしてマウントし、kubelet にマウントポイントの情報を返す
    • kubelet が CRI を介してコンテナランタイムの CreateContainer の RPC を呼び出す時にマウントポイントの情報を一緒に渡す
    • コンテナランタイムはマウントポイントの情報を使ってコンテナ内に bind mount で指定されたパスにファイルをマウントする
    • コンテナランタイムは Pod 起動時に OCI オブジェクトをマウントしたり、Pod 停止時にアンマウントするなどのライフサイクルを管理する
    • kubelet が OCI オブジェクトを GC する時はコンテナランタイムを通して OCI オブジェクトが利用中かどうかを確認してから削除する
  • kubelet はコンテナランタイムから返却されたマウントポイントに正しくファイルがマウントされているかを確認することで、コンテナランタイムが新しい VolumeSource をサポートしているかを判断する

    • VolumeSource をサポートしていないコンテナランタイムを利用している場合は Pod の起動に失敗する
  • コンテナランタイムが OCI オブジェクトをファイルとしてマウントする際に、セキュリティ上の理由からデフォルトで noexecro の mount オプションを指定する

  • コンテナランタイムが返却するマウントポイントは単一のディレクトリになっていて、その中に解凍 & マージされたレイヤーファイルが含まれている

    • OCI Artifacts の中に複数のレイヤーが存在する場合はマージしたもの (重複したファイルがある場合は上位のレイヤーの内容で上書きする) を保存する
  • 以下のようなディレクトリ構造の場合、それぞれのファイルは別々のレイヤーとして扱う

    ./
    ├── dir/
    │  └── file
    └── file
    
    # layer0
    tar cfvz layer0.tar dir
    # layer1
    tar cfvz layer1.tar file
    
  • コンテナランタイムが OCI Artifacts をプルする時には mount=true オプションを指定する

    sudo crictl pull --mount localhost:5000/image:v1
    
  • マージされたそれぞれのレイヤーは以下のようなディレクトリ構成をとる

    /var/lib/containers/storage/overlay/7ee9a1dcea9f152b10590871e55e485b249cd42ea912111ff9f99ab663c1001a/merged
    ├── dir
    │   └── file
    └── file
    
    2 directories, 2 files
    

CSI plugin としてなぜ実装しないのか?

  • CSI plugin として実装する方法は既に存在するが、CSI driver を新たにインストールしたり更新したり運用コストが高くなりがちなのと、CSI driver に依存すると実装がベンダー毎に異なったり一般化できなくなる
  • CSI plugin として実装した場合、OCI Artifacts のライフサイクル管理を独自実装しなければならなくなるが、kubelet は既にコンテナイメージ (OCI イメージ) のライフサイクル管理を実装しており、再利用可能
    • 並列プルの実装や並列プル数の制限、コンテナイメージの GC の処理、プル関連のメトリクスなどが再利用・改善できる
  • プルが頻繁に行われたり、大規模なデータをダウンロードする際などにオーバーヘッドが生じてしまう
Tsubasa NagasawaTsubasa Nagasawa

2024/6/25

コンテナランタイム停止時の kubectl logs のコネクションの切断について

Kubernetes 1.30 時点で kubectl logs を実行中にコンテナランタイム (containerd / CRI-O) が停止すると streaming RPC のコネクションが切断される。kubelet はコンテナのログが書き込まれるのを待つループの中で CRI の ContainerStatus API を呼び出してコンテナが正常に動作しているかを確認している。そのため、コンテナランタイム (CRI API を受け取る部分) が停止するとコンテナの状態が取得できないので kubectl logs が切断されてしまう。ただし、containerd も CRI-O もコンテナランタイムが停止したからと言って実行中のコンテナが停止する訳ではない。なので、コンテナランタイムが停止している時 (ContainerStatus API を呼び出した時に Unavailable のステータスコードが返ってくる場合) には暗黙的にコンテナが生きているとしてコネクションを切断しないように変更した。どちらにしろ、コンテナランタイムが再起動して復旧した後にも ContainerStatus API は定期的に呼び出されるので、仮にそのコンテナが停止していたらその段階で気付いてコネクションを切断できるので問題ないという判断 (k/k#124025)

kubectl exec / attach の場合は、kubelet はコンテナの正常性チェックを行っていないので、切断するかはコンテナランタイム側の実装に委ねられている。そもそも kubectl logs と違って client <-> kubelet <-> container runtime <-> container でコネクションを張る必要があるので、container runtime が再起動すると container runtime <-> container 間の streaming RPC が切断されてしまう。CRI-O の場合はコンテナとは別に Rust 製の container monitoring (conmon) というプロセスがいるらしく、そちらでコネクション管理するようにすれば container runtime が停止しても耐えられるのではという話になっているみたい (cri-o/cri-o#7826)

Server Side Apply で空の map 型の変更を反映すると更新イベントとして扱われる問題

コアリソースに対して Server Side Apply 時に map 型のフィールドで annotation: {} のように空の map を含んだ変更を反映すると、必ず resourceVersion が更新されて更新イベントとして扱われてる問題の修正がマージされた (k/k#125317)

Kubernetes 1.31 からは resourceVersion は更新されずにオブジェクトに変更がないとして扱われる。annotation:annotation: null の場合には変更がないものとして扱われていて、annotation: {} の場合だけ挙動がおかしかったのが修正された。コアリソースの場合のみで CRD には影響しない。影響があるのは map 型のフィールドだけで構造体 (e.g. emptyDir: {}) の場合には影響しない。この副作用としてコアリソースの中にフィールドが nil (値がない) なのと {} (空) を使い分けているものがないかどうかだが、オプションな map 型しかないので影響しない。

Kubernetes 1.31 HEAD のクライアント証明書周りの問題の報告

GKE で k/k の 1.31 (未リリース) の最新 (?) のコミットでテストをしているようで、kubelet が提出する CSR の中身がおかしくなっているらしい (k/k#124554 (comment))。kubelet は kube-apiserver とやり取りするためにクライアント TLS 証明書が必要。kubeadm join を実行すると Node の bootstrap 処理の中で kubelet が CSR を提出して自動で承認されたら証明書が作られる

Tsubasa NagasawaTsubasa Nagasawa

2024/6/26

Kubernetes のリリースサイクルの中での開発期間の延長

Kubernetes の Slack のスレッドでのやり取り

Kubernetes 1.29 - 1.31 のここ最近の Kubernetes の開発期間 (KEP フリーズからコードフリーズまで) は休日を除くと 18 日しかなく、今回のリリースサイクルだと US で休日が 3 日間あるらしく実質 15 日しかないらしい。更にコードフリーズからテストフリーズまでの期間が 1.29-1.30 で 2 週間、1.31 で 3 週間あるらしく、テストコードは後回しで機能追加だけマージされるケースが増えて良くない。コードフリーズからテストフリーズまでの期間は以前は 1 週間だったけど、1.29 辺りからおかしくなって (1.31 はなぜか更に増えた)、それが常態化していたらしい。リリースチームの機転もあり、現在の 1.31 のリリースサイクルからコードフリーズからテストフリーズまでの期間を 1 週間に戻すことになり、開発期間に余裕ができた。そもそもコードフリーズとテストフリーズは同日にして、リリース日までの 1 週間を Soak 時間として安定か様子を見守る方が良くないという話になっていて、Kubernetes 1.32 のリリースサイクルから変更できるように動くみたい。

最近 Flaky なテストが多く、時間がないのにその対応に時間を取られていて大変そう。git bisect で Go の gRPC のライブラリのバージョン更新が原因で Flaky になったと分かったが、gRPC のバージョン更新を revert しても頻度は落ちるが Flaky なままな Unit テスト (k/k#125575 (comment))

Tsubasa NagasawaTsubasa Nagasawa

2024/6/28

ベアな EKS クラスタを作成するオプションの追加

EKS クラスタで Amazon VPC CNI, CoreDNS と kube-proxy を含まないクラスタを作れるようになったので Cilium の kube-proxy の置き換えとかセットアップしやすくなっている (aws/containers-roadmap#923 (comment))

Tsubasa NagasawaTsubasa Nagasawa

2024/6/29

kubectl の client-side apply のリソース作成時と更新時の挙動の違い

kubectl の client-side apply でリソースを更新する時にフィールドに null を指定すると値を消すことができたが、client-side apply でリソースを作成する時にフィールドに null を指定してもその値を消すことができなかった問題の修正。リソース作成 (CREATE) と更新 (PATCH) で挙動が違うので問題になっていた。(k/k#125646)

例えば、kubectl apply でリソースを作成する時に resources.requests.cpu のようにデフォルト値がないフィールドに null を指定するとそのフィールドに値は設定されないはずだが、Go の初期値 (0) が指定されていた。terminationMessagePolicy のようにデフォルト値が File となっているフィールドに null を指定してもデフォルト値の File が埋め込まれるだけ。
Kubernetes 1.31 より前の挙動は以下だけど、Kubernetes 1.31 以降は resources.requests.cpu の値が空になる

cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
  name: my-dep-null
spec:
  containers:
    - name: nginx
      image: registry.k8s.io/nginx:1.7.9
      resources:
        requests:
          memory: "64Mi"
          cpu: null
      terminationMessagePolicy: null
EOF

❯ kubectl get pods my-dep-null -ojsonpath='{.spec.containers[0].resources.requests.cpu}'
0
❯ kubectl get pods my-dep-null -ojsonpath='{.spec.containers[0].terminationMessagePolicy}'
File
Tsubasa NagasawaTsubasa Nagasawa

2024/6/30

kubectl 1.31 から kubectl exec [POD] [COMMAND] がエラーとなる

kubectl 1.31 から数年前に非推奨になって警告ログも出ていた kubectl exec [POD] [COMMAND] が機能しなくなる。kubectl exec [POD] — [COMMAND] に移行が必要 (k/k#125437)

Tsubasa NagasawaTsubasa Nagasawa

2024/7/1

kubelet が Priority を考慮して Pod を起動しない問題

kubelet が再起動すると Node 上で動いていた Pod が再起動されるけど、その時に Pod の Priority は考慮されず、Pod の作成時刻 (CreationTimestamp) の早い順にソートされて起動される。Priority の高い Pod が先に起動していないといけない場合に、Priority の低い Pod が先に起動してしまって再起動を繰り返すことがある問題。kubelet の再起動に関わらず通常の Node のスケールアウト時にも問題になりそうだし、Pod の起動が早くても起動完了が早いことは保証されないはずなので質問してみた。(k/k#125815)

Kubernetes 1.31 で KEP-1880: Multiple Service CIDRs がベータ昇格

バージョンの異なる kube-apiserver が動いている場合やロールバックのことを考慮して、既存と IPAddress オブジェクトを利用した処理の両方が動作する dural-write モードが実装されている。DisableAllocatorDualWrite の Feature Flag も導入されていて dural-write の挙動を ON / OFF できる。Multiple CIDRs の機能のプロモーションも特殊で 1.31 でベータ昇格時はデフォルトで無効。MultiCIDRServiceAllocatorDisableAllocatorDualWrite の Feature Gate を 1 つずらしで徐々にステージを上げていって問題が起きないようにしている

Tsubasa NagasawaTsubasa Nagasawa

2024/7/2

ESK の Pod Identity Webhook をすり抜けるためのラベル

EKS の Pod Identity Webhook (IRSA とか Pod Identity で使われている Mutating Webhook) で eks.amazonaws.com/skip-pod-identity-webhook: "" (値は何でも良い) のラベルを付与すると Mutating Webhook をすり抜けられるようになる (aws/amazon-eks-pod-identity-webhook#216)

  • kops などを使って AWS 上に Kubernetes クラスタを自前で立てる時にすり抜けられないと困るらしい。Cilium を起動しないと CNI のセットアップができないので Pod が起動できず、Pod Identity Webhook が起動できない循環依存の状態になる

    • Cilium は Pod Identity が不要なので、eks.amazonaws.com/skip-pod-identity-webhook: "" のラベルを付与することで Pod Identity Webhook が起動しているかに関わらず起動できるようになる
    • Mutating Admission Webhook の設定で failurePolicy: Ignore に設定することもできるが、Pod Identity Webhook に問題が起きた時に IRSA や Pod Identity が必要な Pod が必要な設定 (トークンを Projected Volume としてマウントしたり環境変数を設定したり) の差し込みなしで起動できてしまうのも問題 (EKS は failurePolicy: Ignore になっている)
    • 既存で eks.amazonaws.com/skip-containers の annotation を設定するとコンマ区切りで指定したコンテナに対する差し込みをスキップできるが、これはあくまで Pod Identity Webhook の処理の中で行なっていることなので、Pod Identity Webhook が起動していないと処理できない
    • マネージドな EKS クラスタを使っている場合は、Pod Identity Webhook はコントロールプレーンで動作しているので循環依存の影響は受けない
  • EKS 上で Pod を作成すると Pod Identity Webhook を必ず通るのでスループットに少なからず影響したり、Sidecar containers のような新しい機能を利用する場合に Pod Identity Webhook が対応した Kubernetes client を利用していないと新しく追加されたフィールドが揉み消されたりするので、eks.amazonaws.com/skip-pod-identity-webhook: "" で回避できるというのは知っておいても良いかも

  • まだ EKS クラスタには設定されていないけど、順次反映されていくっぽい

    ❯ kubectl get mutatingwebhookconfigurations.admissionregistration.k8s.io pod-identity-webhook -ojsonpath='{.webhooks[0].objectSelector}'
    {}
    

Docker Engine 27 で kind クラスタが起動できない問題

Docker Engine 27 の IPv6 周りの変更の影響か (?)、kind でクラスタを立てると何故か IPv6 クラスタとして立ち上がってかつ起動できなくなっているらしい (kubernetes-sigs/kind#3677)

存在しない namespace に対する操作時の不親切なメッセージの意図

存在しない namespace に対して kubectl get pods などを実行しても不親切なメッセージ (No resources found) を返しているのは意図的。その namespace に対する操作権限がないのかリソースが存在しないのかを見分けられないようにしている。エラーメッセージに情報を持たせすぎると逆に情報がリークしてしまう (k/k#125840 (comment))

Tsubasa NagasawaTsubasa Nagasawa

2024/7/4

VictoriaMetrics の Exemplar をサポートしない宣言

VictoriaMetrics は Prometheus の Exemplar をサポートしないことにしたらしい (VictoriaMetrics/VictoriaMetrics#1169 (comment))

  • Prometheus に Exemplar の機能が入って 3 年が経つが、未だに広く利用はされていないし、実験的な機能のまま
  • VictoriaMetrics に Exemplar のサポートを入れるには内部的にそこそこの変更が必要で、一度リリースしてしまうと今後もメンテナンスが必要
  • Prometheus では Exemplar をメモリ上に保持するため、Prometheus が再起動すると情報は失われる
  • Prometheus SDK の Exemplar 関連の API が使いづらく、アプリからメトリクスと一緒に Exemplar を公開するのは容易ではない
  • Exemplar をサポートしているのは Histgram 型のメトリクスのみで、他の Counter や Gauge、Summary 型のメトリクスではサポートしていない
  • Grafana での Prometheus の Exemplar のサポートは十分でなく、histgram_quantile() のクエリでのみサポートしている。Grafana 内部で利用している Prometheus の Exemplar 向けのクエリの API も実験的なもので、クエリの結果をグラフ上にドットとして表示するだけ。Histgram 形式のグラフに大量のアプリケーションから取得した Exemplar のドットを表示するとすごく見辛いし、Prometheus / Grafana のどちらも表示するドットをフィルタリングする機能を持っていない。大規模なシステムの本番環境での利用に向いていないのでは?
  • Exemplar はトレースに紐づいている。トレースは負荷の高くないシステムだと低コスト (ストレージ料金とトレースの生成によるパフォーマンス影響) だが、負荷の高いシステムだと高コスト。収集したトレースを調べて得られるものよりも対価の方が高くつく
  • 上記の理由から Exemplar が近い将来本番利用可能になるとは思えない
  • Grafana のグラフから Exemplar のドットをクリックして関連するトレースやログが見れるだけなのに、Exemplar はメトリクスとトレースとログを関連付ける銀の弾丸だと思われている
  • 代替案があるかというとあって、時系列やラベルに基づいてメトリクスとトレースとログを関連付ければ良い
    • 例えば、jobinstance などのメトリクスのラベルをログやトレースにも付与すると、これらのラベルやメトリクスのグラフで確認した異常のあった時間帯から関連づけられる
  • 1 クリックでメトリクスとログとトレースの相関が分かるようにするために、コストや使いづらさを許容すべきなのか?

かなりポジショントークが入っているけど、言いたいことは分かる...。Prometheus のメトリクスの公開フォーマットの中にトレースを埋め込む都合上、トレースのドットはメトリクスを収集した時点での最新のトレースの情報。なので、それが興味のあるトレースではない可能性の方が高くて本番環境で使えるかって言われると微妙な感じはしてた。

Tsubasa NagasawaTsubasa Nagasawa

2024/7/5

kubectl 1.31 の破壊的変更が続く

kubectl 1.31 で kubectl run と drain の非推奨になってだいぶ経つオプションが完全に削除された。kubectl 1.31 での破壊的変更が多くて心配。kubectl drain の —delete-local-data はまだスクリプトとか古い記事を参考に使っている人いそうだな… (k/k#125842)

Kubernetes 1.31 で KEP-4444: Service Traffic Distribution がベータ昇格

Kubernetes 1.31 で KEP-4444: Service Traffic Distribution (Topology Aware Routing の後継) がベータ昇格でデフォルト有効なので使えるようになる予定 (k/k#125838)

Tsubasa NagasawaTsubasa Nagasawa

2024/7/6

kubelet による Priority を考慮した Pod の起動

kubelet が Pod を Priority 順でソートして起動する PR が上がっている。いろいろと質問ガン無視で PR だけ上げているので、すぐにマージされることはなさそう。既存の挙動を変える根拠が弱い気がするし、少なくとも KEP を書くようには言われそう (k/k#125918)

Tsubasa NagasawaTsubasa Nagasawa

2024/7/7

KEP-3960: Sleep Action for PreStop Hook

KEP-3960: Sleep Action for PreStop Hook で設計上は sleep: 0 に設定できるとあるけど、実際には sleep を 0 に設定すると 0 より大きな値を指定しろとバリデーションエラーになる問題。Mutating Admission Webhook で preStop hook を設定していない Pod に sleep action を差し込んでいる人がいて、preStop hook の差し込みが不要な場合にダミーの preStop hook (exec action で true コマンドを実行) を指定してもらっているらしい。余り良くない方法で、ラベルで Mutating Admission Webhook の対象から外す方が良い。ただ、言い分はわかるので修正しても良いけど KEP と FeatureGate が必要。問題なのは sleep action を 0 に設定した Pod がいる状態で、古い Kubernetes のバージョンにロールバックしたすると、その Pod がバリデーションエラーになる。sleep action を 0 に設定する機能を FeatureGate で守り、アルファ段階を挟むことで安全にロールバックできる (kubernetes/enhancements#3960 (comment))

Tsubasa NagasawaTsubasa Nagasawa

2024/7/8

upstream 主導の CRD によるコア API リソースの拡張

Gateway API はコア API リソースの拡張を upstream 主導で CRD として実装した先駆者でうまくいった例。Network Policy も既に同じ道を歩んでいて、Multi-Network、Multi Cluster Service、WG-Serving の AI Gateway など同じ方法を取ろうとしているプロジェクトがいくつかある。Gateway API の経験をもとに開発の進め方やユーザーへの提供方法、ユーザの利用方法などを標準化していく動きがある (google groups)

Tsubasa NagasawaTsubasa Nagasawa

2024/7/9

KubeRay が GKE アドオンに

GKE で KubeRay ベースの Ray Operator がアドオンとして利用できるようになった。KubeRay くらいならアドオンじゃなくて自分で管理で良い気がするけど (release notes)

Tsubasa NagasawaTsubasa Nagasawa

2024/7/11

gitRepo の VolumeSource の悪用を防ぐ動き

非推奨となっている gitRepo の VolumeSource で新しく脆弱性が見つかったので、Pod Security Standard のベースラインのポリシーで gitRepo を参照した Pod の作成を禁止して悪用を防ぐ PR (k/k#126016)

  • gitRepo の VolumeSource では repositoryrevision (optional) と directory (optional) が指定でき、directory でリポジトリのクローン先のサブディレクトリを指定可能
  • 元々、2018 年に Git CLI で submodule の初期化時に任意のコードを実行できる Remote Code Execution (RCE) の脆弱性が見つかって、Kubernetes の gitRepo の VolumeSource でも指定が必須でない directory フィールドに --recurse-submodules の引数を指定することで Kubernetes の Pod の中からホストの root 権限で任意のコマンドを実行できた
  • この問題を機に Kubernetes のメンテナは gitRepo の VolumeSource を非推奨化し、initContainers と emptyDir を併用してクローンすることを推奨した
  • gitRepo の VolumeSource の実装では git clone コマンドを実行後に revision が指定されているとクローンしたディレクトリに cd して git checkout を実行する
  • 新しく見つかった Kubernetes 固有の脆弱性
    • .git の中身だけを含んだ Git リポジトリを用意、git checkout の hook を仕込んでおく

    • directorysomething/.git などを指定して、repository に .git の中身だけを含んだ Git リポジトリの URL を指定する

    • something/.git/.git のディレクトリも作成されるが、Git CLI 的には something/.git を認識して something が通常のリポジトリの中身だと勘違いする

    • gitRepo の Volume driver は git checkout のコマンドを something のディレクトリで実行してしまい、checkout hook により任意のコマンドを実行できてしまう

      volumes:
      - name: gitvolume
        gitRepo:
          directory: something/.git
          repository: https://github.com/irsl/g.git
          revision: main
      

[Kubernetes 1.31] cgroup v1 のメンテナンスモードへの移行

cgroup v1 がメンテナンスモードに移行したことを伝える警告ログと Event、利用している cgroup のバージョンを値として返すメトリクスを追加する PR がマージされたので、予定通り Kubernetes 1.31 から cgroup v2 への移行に向けた長い道のりが始まりそう (k/k#125328)

Tsubasa NagasawaTsubasa Nagasawa

2024/7/13

Validating Admission Policy 関連のリソースの作成順による罠

Validating Admission Policy (VAP) でカスタムパラメータを利用している場合に、Policy / PolicyBinding を Params (e.g. Custom Resource) よりも先に作成するとカスタムパラメータとして参照しているリソースが見つからないエラーになる問題。カスタムパラメータのリソースを検知するためのキャッシュの更新が 30 秒間隔なのが原因のよう (k/k#124237)

Tsubasa NagasawaTsubasa Nagasawa

2024/7/14

cAdvisor のディスク使用量のスキャンによる CPU 負荷の高騰

1 Node あたり 200 Pod 程度動かしていると Node 上で一番 CPU 使用率が高いプロセスが kubelet で、定期的に +200% 程度スパイクするらしい。CPU プロファイルを取得して詳細に調べてみると ncdu が原因なことが分かり、CPU 時間の8割がディレクトリを再起的に見てサイズを取得している処理だったそう。現状ハードコードされていて変更できないディスク関連のメトリクス使用量のスキャンの間隔を 1 分から変更できるようにしたい要望。新たに KEP が必要なのと、kubelet が公開しているメトリクス (e.g. Summary API) を cAdvisor からではなく CRI 経由でコンテナランタイムから直接取得する KEP-2371 があるので足並みを揃える必要がある。ただ、KEP-2371 だとディスク関連のメトリクスは対象外で cAdvisor が完全に消えるわけではない (k/k#123340 (comment))

Tsubasa NagasawaTsubasa Nagasawa

2024/7/15

kubelet の設定で cgroup v2 の group oom kill を無効化

うたもくさんが宣言通り cgroup v2 の group oom kill を kubelet の設定で無効化する PR を引き継いでた。まだ WIP で以前の PR を引き継いで少し修正を加えただけっぽい (k/k#126096)

Tsubasa NagasawaTsubasa Nagasawa

2024/7/17

Kubernetes: Disrupted pods should be eagerly removed from endpoints

Graceful Node Shutdown や Pod Eviction で中断される Pod を早めに Endpoint から除外する議論

  • Graceful Node Shutdown の処理が始まった Node で動いている Pod や Eviction で追い出される Pod は Pod が停止するまで LB から Endpoint が外れず、その Pod に接続しているクライアントなどでエラーが発生してしまう
    • 既に存在しない Pod にリクエストが流れることで接続拒否や 5xx 系のエラーが発生する
  • Graceful Node Shutdown やそれ以外の通常とは異なる Pod の停止時に、kubelet がコンテナを停止する前に Pod を Endpoint から外すよう合図を送らないことが原因
  • Endpoint の情報を参照する LB は結果整合性であり、EndpointSlice から Pod が削除されるタイミングと削除された Pod の情報が反映されるタイミングに時間差があり、kube-proxy だと O(1s)、外部の LB や DNS だと O(60s) のオーダーで時間差が発生する
    • 現状は Pod に preStop hook を設定して停止処理の開始を遅らせたり、ワークロード側で SIGTERM を受け取ってから一定時間接続を維持できるようにすることで、この時間差に対応している
    • 接続を維持する時間は環境毎に実験して決め打ちしており、時間が長ければ長いほど安全
  • 中断されることが分かっている Pod はなる早で Endpoints から外れるべきで、結果整合性な LB が接続先の更新を反映する猶予を作るべき
    • Readiness probe は遅行指標。この問題を解決するには先行指標が必要
  • Pod が通常のライフサイクルとは異なる要因で停止する場合、なる早で明確な合図を送り、Endpoints controller が Pod を接続先の情報から除外できるようにしたい
    • Pod に deletionTimestamp が設定されてコントロールプレーン (KCM) が Pod を停止する場合も、Pod Eviction のソフトリミットを超えて kubelet により安全に停止される場合も、ハードリミットを超えて kubelet により強制的に停止される場合も、挙動に一貫性は持たせるべき
  • Pod が Ready 状態かを示す condition が先行指標となるか?
    • Pod が Ready 状態になると LB はその Pod に対してトラフィックを流す
    • Readiness probe が設定されていない Pod は常に Ready 状態となる
    • Pod の Ready 状態を先行指標として使うなら、Graceful Node Shutdown が発動した際にワークロードが返しているヘルスチェックの結果を無視して、Pod を NotReady 状態 (PodReady の condition を false) に変更することになる
    • Graceful Node Shutdown が発動しても Ready 状態のまま Pod を残したいユースケースがあるので、上記の変更は許容できない
    • Pod の Ready 状態と Pod の中断はお互いに干渉してはいけない
      • Pod が Ready 状態かはユーザーが定義した指標で、LB 以外の別のコンポーネントがこの情報を使っている可能性があるので、ヘルスチェックの結果を無視して Ready 状態を上書きしてはいけない
  • deletionTimestamp を設定して Pod を安全に削除するのは先行指標となるか?
    • 不要な Pod があれば DELETE API を呼び出すことで、kubelet が安全に Pod を停止してくれる
    • DELETE API を呼び出しても Pod に deletionTimestamp が設定されるだけで、実際に Pod が削除される訳ではない
    • 安全に停止中の Pod は kubelet によりいずれ削除されることになり、Node controller やクラスタ管理者が Pod を NotReady 状態にするための合図を送ることができる
    • 既に Endpoints controller は Pod に deletionTimestamp が設定されたことを合図に、なる早で Endpoints から Pod を削除するようにしている
    • EndpointSlice に関しても同様の挙動だが、Endpoint 毎に停止中かを知らせる状態 (conditions.terminating) があり、NotReady 状態の Pod と停止中だが Ready 状態な Pod を判別できる
    • Node の中断といっても Pod が一時的に影響を受けるだけのケースも含まれるので、Graceful Node Shutdown で deletionTimestamp を先行指標として利用できないことがある
    • Spot VM のように一時的に利用していた Node が停止する場合、Pod のライフサイクルはそこで終わるので、なる早で Pod を削除することは許容できる
    • 今の Kubernetes では、Node が今後も停止したままなのか一時的な中断なのかを区別できないので、Node が停止する時に Pod を必ず削除することはできない
    • Kubernetes の controller はユーザーがその挙動を opt-in で設定しない限り、Pod を削除するべきではない
    • Graceful Node Shutdown が発動した場合に Pod を必ず停止状態に遷移すると、Node が一時的に中断するだけの場合に潜在的なバグに繋がる可能性がある
  • Pod の DisruptionTarget の状態 (Pod が中断の対象かどうか) が先行指標となるか?
    • Kubernetes 1.31 で GA に昇格する予定の Pod Failure Policy の機能で Pod に新しく状態が追加され、Pod がなぜ中断されるのかが分かるようになった
    • 何かしらの中断 (e.g. Graceful Node Shutdown や Preemption、Pod Eviction の一部) が予想されると controller や kubelet が API 経由で Pod に対して DisruptionTarget の状態を設定し、reasonmessage で中断の原因が分かる
    • Job controller は DisruptionTarget の状態を見て、ワークロード起因の中断ではないから Job を再試行しても良いと判断できるようになる
    • 現状の実装だと DisruptionTarget の状態の書き込みが遅れるため、先行指標としては利用できないが、この制約を緩和することは可能
    • ただし、KEP では DisruptionTarget の状態を設定する対象を限定しているため、それらをカバーするとなると別の先行指標が必要になる
  • 新しく Pod の停止待ち状態 (PendingTermination) を追加すると先行指標となるか?
    • kubelet が Pod の停止処理を開始した状態を新しく追加することで、Pod Eviction などの中断や Job の activeDeadlineSeconds を超過したかが把握しやすくなり、Pod Failure Policy の補完としても使える
    • Pod の状態を新しく追加することで、他にも Pod が利用していたリソースをすべて解放したかを知らせるためにも使える
      • Pod が全てのリソースを解放して、Pod のフェーズが停止状態 (Succeeded or Failed) に遷移したら、PendingTermination の状態を true から false に変更する
      • KEP-4577 で Volume のアンマウントに絞って解決するのではなく、幅広い問題の解決にも繋がる
  • 現在提案されている実装は 2 つのフェーズに分かれており、フェーズ 1 で DisruptionTarget を合図として使えるようにして、フェーズ 2 で新しい Pod の停止待ち状態 (PendingTermination) を追加する
  • フェーズ 1 では Pod が停止状態に入ったら、kubelet がなる早で DisruptionTarget の状態を更新するように変更する
    • Endpoint / EndpointSlice controller は Pod の DisruptionTarget の状態が設定されているかを見て、設定されている場合は Pod が近いうちに停止されると判断してなる早で Endpoint から削除する
    • EndpointSlice controller は Pod の DisruptionTarget の状態が true なら conditions.terminating を true に変更する
    • DisruptionTarget の状態が設定されていないか値が false に設定されているなら conditions.terminating を false に変更し、Pod が Ready 状態の間はリクエストを流す
      • conditions.terminating の値が true <-> false で遷移すると既存の意味合いが変わるという指摘があるので影響範囲を調べる予定らしい
    • フェーズ 1 の新しい挙動は FeatureGate で守られるがデフォルトで有効にして恩恵を受けやすいようにする予定
  • フェーズ 2 では既存の KEP を拡張するか新しい KEP を作成して、PendingTermination の状態とその挙動を明確にする
    • kubelet が管理するステートマシンの中で Pod の停止が始まると、停止の理由に関係なく全ての Pod で PendingTermination の状態を持つことになる
    • Node の再起動などで kubelet が再起動し、Pod が停止した理由が分からなくなると、PendingTermination の状態は削除される
    • Endpoint / EndpointSlice controller が Pod の状態を見て、DisruptionTarget の状態か PendingTermination の状態が true に設定されていたら、Pod は停止中と判断してリクエストを流さないようにする
    • フェーズ 2 でも FeatureGate を追加する予定で、Pod の状態の設定と Endpoint / EndpointSlice などのその情報を使う側の挙動を ON / OFF できるようにする
Tsubasa NagasawaTsubasa Nagasawa

2024/7/19

GKE も Kubernetes の延長サポートを開始

GKE で最大 24 ヶ月の延長サポートが提供されるようになります。リリースチャンネルに新しく Extended channel が追加され、Extended channel に登録されたクラスタで延長サポートが利用可能です。 (twitter)

Tsubasa NagasawaTsubasa Nagasawa

2024/7/22

KEP-4006 : Transition from SPDY to WebSockets のリグレッション

kubectl 1.30 で kubeconfig の clusters.cluster.proxy-url に HTTPS プロキシを設定すると kubectl exec / attach/ cp / port-forward が正常に動作しなくなるリグレッション (k/k#126231)

HTTP プロキシだと動作するが、HTTPS プロキシだと動作しない。kubectl 1.30 から kubectl (client) <-> kube-apiserver の双方向の通信がデフォルトで SPDY から WebSocket に変わったことが原因。現状のワークアラウンドは KUBECTL_REMOTE_COMMAND_WEBSOCKETS: false の環境変数を設定して強制的に SPDY の実装を使うようにするしかない。Kubernetes が利用している WebSocket のライブラリ (gorilla/websocket) が HTTPS プロキシをサポートしておらず、kubectl 1.30 でデフォルト有効になったため顕在化した。今回入った修正は一時的なもので WebSocket で繋げようとして HTTPS プロキシをサポートしていないよのエラーが出たら SPDY の実装に自動的にフォールバックする。gorilla/websocket で HTTPS プロキシ対応の PR が上がっているので、利用できるようになったら一時的なフォールバックの仕組みをなくす予定。

Tsubasa NagasawaTsubasa Nagasawa

2024/7/24

kind で Network Policy がネイティブにサポート

kind がデフォルトで利用している kindnetd (kindnet ベースのホスト側のルーティングをセットアップしたり、CNI の設定を置いたりする DaemonSet) に以前アントニオさんが作った Network Policy の実装がライブラリとして組み込まれたので何も入れなくても Network Policy が使えるようになる。最初は別の DaemonSet として以前実装したやつを動かして設定で ON / OFF できるようにする予定だったけど、Network Policy は基本ルールを作らないと有効にはならないから ON /OFF できなくても問題ないはず (kubernetes-sigs/kind#3612)

Tsubasa NagasawaTsubasa Nagasawa

2024/7/26

Validating Admission Policy の Tips

Validating Admission Policy でオブジェクトの DELETE に対してルールを書く時は object じゃなくて oldObject から情報を引っ張ってくる必要がある。request.operation で DELETE とそれ以外で三項演算子で oldObject か object を渡すようにする。ServiceAccountTokenPodNodeInfo の FeatureGate が有効になっていると request.userInfo.extra の中の authentication.kubernetes.io/node-name にリクエストの送信元の Pod が動いている Node 名の情報が含まれるので、特定のリソースが (e.g. GPU) が紐付いた Node 上の driver からのみ許可するみたいな使い方を DRA だとしている(comment - k/k#124711)

GPU を利用した Job の停止時のエッジケース

Device plugin で GPU を利用している Job の実行が完了して Pod の状態は Succeeded に遷移して Job controller が Pod から finalizer を外して Pod が GC されるのを待っている状態を考える。タイミングよく kubelet が再起動すると、Device plugin の Pod が Node 上の kubelet に再接続して、GPU の状態を確認しようとするが、Pod は既に停止しているので GPU が利用可能な状態かが分からずに、Pod が kubelet の Admission に失敗して Succeeded から Failed の状態に遷移することがある問題。既に Succeeded or Failed に遷移した Pod を kubelet が Admission しないようにする修正の PR は上がっていて、Google の人たちでリレーしているので GKE で報告があった系かな (k/k#126341)

Tsubasa NagasawaTsubasa Nagasawa

2024/7/28

k/k の kind を使った E2E テストを実行する CI が...

upatream の Kubernetes の CI で kind 上で E2E テストを実行するジョブがあり、test-infra のリグレッションの影響でテストケースが何も実行されていなかった結構まずい問題。canary のジョブがあって事前に変更を確認していたけど、通常のジョブと差分があって見落とした形。原因となっていた PR は revert されて修正済み。実行できていなかったテストがあるけど、問題はなかったっぽい? (k/k#126401)

Tsubasa NagasawaTsubasa Nagasawa

2024/7/29

Sidecar Containers の機能によるリグレッションの報告

Sidecar Containers の機能が有効で複数の Init Containers を起動した時に、コンテナランタイムでエラーが起きると最後の Init Container が ContainerCreated の状態でスタックして起動しなくなるリグレッションが Gardener の開発の人から報告されている (k/k#126440)

Sysdig の Kubernetes の新機能の記事

Sysdig が出している Kubernetes の新機能のブログ記事を読んでいる人多いと思うのですが、結構ガバガバなので気を付けた方が良いです...!

この辺りは 1.31 に入らない

  • #4706 kubectl から kustomize を非推奨にして削除
  • #3104 kubectlユーザープリファレンスをクラスタ構成から分離
  • #3314 ブロックボリュームの CSI 差分スナップショット
  • #3962 ミューテーティングアドミッションポリシー

これも入らない

セキュリティをさらに強化するために、ポッドレベルのリソースリミットがNet New から Alpha に移行し、Kubernetes のリソース制約と同様の機能を提供して、運用効率と堅牢なセキュリティのバランスをうまく取っています。

他にも面白い (怖い) 機能が入る予定なのですが、抜けていたり

Tsubasa NagasawaTsubasa Nagasawa

2024/7/31

続: Karpenter v1 に向けた API の変更とロードマップ

Karpenter v1 に向けた API の変更とロードマップの RFC がマージされてた (kubernetes-sigs/karpenter#1222)
AWS 固有の内容については karpenter-provider-aws に移動された (aws/karpenter-provider-aws#6604)

以前書いた内容からの変更点

  • NodePool に spec.template.spec.terminationGracePeriod を追加する予定で、Node を drain する時に PDB や karpenter.sh/do-not-disrupt の annotation が付いた Pod によってスタックしないように指定した時間が経過したら強制的に Pod を停止する

  • NodePool の spec.disruption.expireAfterspec.template.spec.expireAfter に移動。NodeClaim のリソースが Node のライフサイクルを管理するので、NodeClaim を作成するテンプレートである NodePool の spec.template で設定できるようにする

  • Karpenter は karpenter.sh/unregistered:NoExecute の taints を付けた状態で Node をクラスタに参加させて、NodePool に設定されたラベルや annotation、taints を追加してから karpenter.sh/unregistered:NoExecute の taints を外すようになる。Node に Pod がスケジュールされないようにした状態で設定を伝搬するようになるので、以前のように Pod のスケジュール時にラベルや taints などが存在しない可能性があるのを防げる

  • NodePool に spec.disruption.budgets[*].reasons が追加されて、Underutilized や Drifted などの中断の原因によって Disruption Budgets の挙動を変更して中断を制限できる

  • EC2NodeClass の amiFamilybootstrapMode に変更する予定だったのが、amiFamily のまま残る。ただ、amiSelectorTerm の指定が必須になって、新しく alias のフィールドが追加されて以下のように設定できるらしい

    amiSelectorTerms:
    # 特定のバージョンでピン留めする場合
    - alias: al2023@v20240625
    # 既存の amiFamily のみを指定した場合と同じで最新に追従する
    - alias: al2023@latest
    
  • Karpenter (AWS) の controller の Deployment の Topology Spread Constraints のデフォルト値が DoNotSchedule のハード要件に変更される。ゾーン障害への耐性を上げるため。ユーザーが手動で ScheduleAnyways に変更することは可能

Karpenter の AWS Provider は絶賛 v1 API やロードマップの実装が進んでいるので今年中にリリースする予定なのかな

Tsubasa NagasawaTsubasa Nagasawa

2024/8/1

[Kubernetes 1.31] CRD の caBundle のバリデーションが厳しくなったことによる破壊的変更

Kubernetes 1.31.0-rc.0 で CRD の Conversion Webhook で使用する caBundle に Cg== (\n の Base64 エンコード) のようなダミーな値を指定して作成した後で、caBundle を正常な値に変更せずに再適用するとエラーになる報告 (slack, k/k#125569 (comment))

  • CRD や API Service、Admission Webhook の caBundle は optional なフィールドのため、指定しなくてもリソースは作成可能
  • Kubernetes 1.13 の時代に Admission Webhook の caBundle のフィールドが誤って必須となっており、クライアント側でのバリデーションでエラーとなる問題 (k/k#69590) が報告された
  • この問題は Kubernetes 1.13 の時に k/k#70138 で修正されたが、当時 controller-tools のライブラリではダミーな値を指定するワークアラウンドを入れ、cert-manager などが後から caBundle の値を正しい証明書に入れ替える方法を取った
  • kubebuilder が controller-tools のこのワークアラウンドを Admission Webhook ではなく、CRD の Conversion Webhook の生成処理の中で caBundle に適用した
  • 2020 年に controller-tools はこのワークアラウンドをコードベースから削除し、kubebuilder も同様にコード生成からこの処理が削除された
  • この流れで CRD や API Service、Admission Webhook の caBundle の指定が必須だと勘違いしてしまった人たち (e.g. VMware Tanzu) が影響を受けているらしく、マニフェストから caBundle のダミーな値を削除する対応を取っているよう
Tsubasa NagasawaTsubasa Nagasawa

2024/8/4

kube-proxy: initialization check race leads to stale UDP conntrack

大規模な Service のあるクラスタで kube-proxy が再起動した直後に古い conntrack の情報により、UDP のトラフィックが闇に消えることがある問題が AKS から報告されている

  • クライアントが kube-dns の ClusterIP に対して同一のソケットから継続的にリクエストを投げている状態で、kube-proxy の更新などで再起動した場合に発生
  • クライアントは同一の送信元 IP アドレスとポート番号で継続的にリクエストを投げているので、conntrack のエントリは消えない
  • クラスタ内で Service が 2000 個ある状態で、同一のソケットからリクエストを投げつつ conntrack のエントリを削除していると問題が再現可能
  • kube-proxy の中の Service / EndpointSlice の Shared Informer のキャッシュが温まるまで待つ HasSynced() の処理は、登録されているイベントハンドラの処理が完了するまで待つわけではないので、iptables の同期処理を開始するときにキャッシュが不完全な可能性がある。登録したイベントハンドラに対して HasSynced() して処理を待つ必要があるらしい
  • kube-proxy は通常 Endpoint の数が 0 から 1 かそれ以上に変化すると、古い conntrack エントリを削除する。kube-proxy が再起動した直後にキャッシュが不完全なため、kube-dns が再起動して Endpoint の数が 0 から 1 に変化した際に、古い conntrack のエントリを削除しない。それ以降は kube-dns の Endpoint の数に変化がないので、古い conntrack の情報が残り、それを参照することで再送のない UDP パケットが闇に消える
  • kube-proxy の Service / EndpointSlice の Shared Informer でイベントハンドラに対して HasSynced() を実行する

修正の PR が上がっており、再現手順でバグが再発しないことを確認できたらしい

Tsubasa NagasawaTsubasa Nagasawa

2024/8/6

Slow FSGroup recursive permission changes cause customer confusion

NFS を利用する際に SecurityContext の fsGroup を設定することで、Linux の従来のユーザー ID ベースのファイル権限とコンテナ環境を結びつけて動かすことはできる。ただ、fsGroup を設定すると大規模なボリューム (数 TB) を Node にマウントする際に再帰的に chown + chmod の処理を実行するため重く、数時間から数日掛かることもある。fsGroupChangePolicy: onRootMismatch を設定することで、所有者と権限が異なる場合だけ変更するようになるので時間を短縮できることはあるが、それでも時間は掛かる。時間が凄く掛かるので、kubelet のログを改善してユーザーが状態を把握できるようにしたい要望。例えば、全体の何%の処理が完了したらログを書き込むなど

Tsubasa NagasawaTsubasa Nagasawa

2024/8/9

Karpenter provider Cluster API proof of concept demo

SIG-Cloud-Provider の Red Hat の方が開発した PoC でソースコードは emiko/karpenter-provider-cluster-api にある。デモ動画は Karpenter provider Cluster API proof of concept demo にある。kubernetes/org#5097 で kubernetes-sigs 配下に寄贈する話も始まっている。

  • Cluster API Kubemark Provider を利用して kind で管理クラスタとワークロードクラスタを作成
    • Kubemark は負荷試験での利用を想定した仮想的なクラスタで Node 上に Pod を実際に動かす訳ではない
  • MachineDeployment にラベル (node.cluster.x-k8s.io/karpenter-member) を設定することで Karpenter 管理の Node かを判別する
  • Karpenter が MachineDeployment に設定された Cluster API 用の annotation を見て、作成する Machine (Node) のスペックや何台までスケールするか、Node 当たりの Pod 数などを把握する
    • cluster.x-k8s.io/cluster-api-autoscaler-node-group-max-size
    • cluster.x-k8s.io/cluster-api-autoscaler-node-group-min-size
    • capacity.cluster-autoscaler.kubernetes.io/memory
    • capacity.cluster-autoscaler.kubernetes.io/cpu
    • capacity.cluster-autoscaler.kubernetes.io/maxPods
  • MachineDeployment の capacity.cluster-autoscaler.kubernetes.io/labels のラベルで設定したキーと値が Node のラベルとして伝搬されるので、この情報を使って Karpenter NodePool で制約を掛けることもできる
    • Karpenter が Pending 状態の Pod を見て Node をスケールするときに、どの MachineDeployment をスケールするかを選択 (フィルター) する条件として使える
  • Karpenter と Cluster API Provider のカスタムリソース (e.g. NodePool, ClusterAPINodeClass) はワークロードクラスタにデプロイする
    • デモだとローカルで Karpenter のプロセスを起動しているが、実際にはワークロードクラスタで動かすことになりそう
  • Karpenter はワークロードクラスタにあるカスタムリソース以外にも管理クラスタにある Cluster API 関連のカスタムリソースも参照しないといけないので、管理クラスタの kubeconfig を渡せるオプションが追加されている
Tsubasa NagasawaTsubasa Nagasawa

2024/8/14

Kubernetes 1.31 のリリース

Kubernetes 1.31 が予定通りリリースされました。リリースロゴは可愛く陽気で心優しい犬のエリーで Kubernetes のコントリビュータに遊び心のあるウィンクをしている。Kubernetes が 10 周年を迎えて初めてのリリースで、プロジェクトの運営が大変にも関わらず、熱意や誇りを持った笑顔なコントリビュータが後を絶たず、その精神こそが活気のある陽気なコミュニティの証で、エリーはそれを祝福しているのだとか (blog)

KEP-4006: Transition from SPDY to WebSockets の特定条件でのメモリリーク

KEP-4006: Transition from SPDY to WebSockets により、kubectl >= 1.30 で exec / attach / proxy のプロトコルがデフォルトで SPDY から WebSocket に変わっていて、Kubernetes のコントロールプレーンが <= 1.29 でコンテナランタイムとして containerd を使っている場合にメモリリークが発生する問題。Kubernetes のバージョンと kubectl が同じであれば問題は起きない (k/k#126608, containerd/containerd#10568)

KEP-4006 では kubectl <-> API サーバの通信でのプロトコルの変更だけで、API サーバ <-> kubelet <-> containerd の通信のプロトコルに変更はないが、それは Kubernetes 1.30 以降のコントロールプレーンの話。Kubernetes <= 1.29 の場合、API サーバは WebSocket の通信を理解できず、そのまま裏側の kubelet にリクエストをプロキシしてしまう。containerd には WebSocket の実装が既に入っているが、デフォルトで無効になっており SPDY を利用している。そのため、kubelet が WebSocket の通信を受け取っても正しく処理できずに 403 を返し、それを受け取った kubectl が SPDY にフォールバックして再度接続しようとする。403 になった WebSocket の接続が containerd で正しく切断されずに goroutine がリークしてしまっていて問題を引き起こしている。containerd は Kubernetes の WebSocket のライブラリに依存しており、containerd 1.6 / 1.7 が依存するライブラリのバージョンが古いままになっていた。なので、WebSocket の接続を正しく切断する修正も含まれておらず、問題が起きていた。ライブラリのバージョンを更新するなら次のバージョン (2.0) のタイミングにしないと危険なので、containerd 1.6 / 1.7 向けに Kubernetes 1.31 の WebSocket の実装のコードをコピーしてきて一時的に利用するように修正済み。

GKE のカスタムコンピューティングクラス

1.30.3-gke.1451000 以降で使えるらしいけど、便利そう。Reckoner で在庫不足時用に n2 / n2d の NodePool を作ってるけど、これに置き換えで良さそう (X)

Tsubasa NagasawaTsubasa Nagasawa

2024/8/15

Mountpoint S3 CSI driver での Pod レベルの権限対応

Mountpoint S3 CSI driver で Pod レベルで権限を渡してマウントする S3 バケットを制限する機能を開発中ではあるらしい (awslabs/mountpoint-s3-csi-driver#111 (comment))

Karpenter 1.0.0 での EBS ボリュームのマルチアタッチ問題の修正

Karpenter 1.0.0 に入っている変更により Node が停止する時に EBS ボリュームを正常にアンマウントできるようになったらしい。今までは Node の停止により別の Node で Pod が起動するときに 6+ 分間のマルチアタッチエラーですぐには起動できない問題が発生していた。停止処理に入った Node 上で動いている Pod が利用している PV 用の VolumeAttachment のリソースが全て削除されるのを待ってから、Node の finalizer を削除するように修正されている (kubernetes-sigs/aws-ebs-csi-driver#1955 (comment))

Tsubasa NagasawaTsubasa Nagasawa

2024/8/16

Istio 1.23 で Istio Operator が正式に非推奨化

stio 1.23 で Istio Operator が正式に非推奨化されて、1.24 のリリースから含まれなくなるらしい (blog)

Compromised container can trigger OOM with kubectl cp

kubectl cp コマンドの実行により侵害されているコンテナで OOMKill を引き起こせる問題

kubectl cp コマンドは内部的にコンテナに exec して書き込み先のパスがディレクトリかどうかを test コマンドを実行して確認している。事前に攻撃者がコンテナ内に exec して test バイナリの中身を printf "#!/bin/sh\ncat /dev/zero" > /usr/bin/test などで書き換えた状態で、利用者がコンテナ内にファイルをコピーしようとするとディレクトリのチェックの処理がハングする。/dev/zero は null 文字列を書き込み続けるだけだが、現状 test バイナリを実行するときに標準出力と標準エラーを streaming で返す実装になっているため、クラスタ管理者のローカル環境のメモリ使用量が徐々に増加する。で、最終的に OOMKill が発生する。利用者のローカル環境のネットワークが高速だと、null 文字列の圧縮効率が良いのでより早く OOMKill が発生するらしい。

Tsubasa NagasawaTsubasa Nagasawa

2024/8/18

CVE-2024-7646: Ingress-nginx Annotation Validation Bypass

Ingress Nginx controller で Ingress を作成できるユーザーが controller が利用している Service Account のクレデンシャルを取得できてしまう CVE が見つかっている。nginx.ingress.kubernetes.io/auth-tls-verify-client の annotation のバリデーションが甘く、正規表現で ^$ を含んでいないので許可されている値 (e.g. on) 以外に任意の文字列を埋め込むことができた。\r の後に任意のコマンドを埋め込むことで取得できるみたいだが、詳細までは書かれていなかった

Tsubasa NagasawaTsubasa Nagasawa

2024/8/20

Pod のリソース枯渇のエラーの原因

Pod がリソース枯渇のエラー (OutOfCpu, OutOfMemory, OutOfPods) で起動できない場合に static Pods が原因の可能性がある (kubernetes/website#47264)

  • kube-scheduler は Pod のリソース要求と Node の利用可能なリソース容量を見比べてどの Node に Pod をスケジュールするか決める
  • kubelet には static Pods という概念があって Node 上の特定のパス (e.g. /etc/kubernetes/manifests) にマニフェストを置くと kubelet がその Pod を起動して直接管理する。kubelet は API サーバに mirror Pods を作成して、static Pods の状態を同期する。kubelet 以外が mirror Pods を更新・削除しても static Pods には影響しない
  • static Pods は kubelet が管理しているので、kubelet が mirror Pods を作成するまでは API サーバや kube-scheduler は static Pods の存在を検知できない
    • => kube-scheduler が static Pods のリソース要求を把握できない時間が存在する
  • 上記のラグが存在するので、以下のエッジケースが考えられる
    • Node 上に kubelet が起動して自身を API サーバに登録してクラスタに参加する
    • kubelet が Node 上で利用可能なリソースの容量を API サーバに報告する (Node のステータス経由で)
    • kubelet が /etc/kubernetes/manifests 配下のマニフェストをもとに static Pods を起動する
    • kube-scheduler が Pod を Node に配置する。この時、Node の割り当て済みのリソースが割り当て可能なリソース容量に近く、カツカツな状態とする
      • kube-scheduler は static Pods の存在をまだ検知できていないので、static Pods のリソース要求は考慮されていない
    • kubelet が mirror Pods を作成して、Node の割り当て可能なリソースの計算に static Pods のリソース要求を含める
    • kube-scheduler が配置した Pod のリソース要求と static Pods のリソース要求の合計が Node の割り当て可能なリソース容量を超えると Pod は起動できずに OutOfCpuOutOfMemory の状態になる
    • ReplicaSet controller などは要求された台数の Pod が起動できないことに気づいて、新しい Pod を起動しようとするので最終的に Pod は起動できる
    • OutOfCpuOutOfMemory 状態に鳴ってしまった Pod は kube-controller-manager (KCM) の GC controller がお掃除してくれる
  • アントニオさんと別の Google の人が相談して修正を検討しているらしい
    • kubelet が static Pods (mirror Pods) のリソース要求を Node の割り当て可能なリソース容量に含めるまで待ってから Node の状態を Ready にする案とかが上がっているのでそうなる?
Tsubasa NagasawaTsubasa Nagasawa

2024/8/22

[Argo CD v2.12] AppProject 毎にリポジトリの認証情報を設定できる機能による影響

Argo CD v2.12.0 で AppProject 毎に異なるリポジトリ (e.g. Git リポジトリ、OCI レジストリ) の認証情報を使える機能が入ったのですが、リポジトリの認証情報を保存した Secret に project を埋め込んでいる場合、その project と一致しない AppProject でリポジトリの認証情報を利用すると SSH agent requested but SSH_AUTH_SOCK not-specified のエラーになる破壊的変更があります。これまではリポジトリの認証情報を保存した Secret の URL のみ見て一致する場合にその認証情報を使っていたのですが、厳密に project もチェックされるようになっています。マルチテナント環境かつモノレポで複数の AppProject が混在しているリポジトリの認証情報を保存している Secret からは project の指定 (e.g. default を指定している場合など) を削除しないといけないので注意 (argoproj/argo-cd#19587 (comment))

Tsubasa NagasawaTsubasa Nagasawa

2024/8/25

kubectl port-foward の UDP 対応への道のり

kubectl port-forward での UDP サポートが長らく要望として上がっているけど、kubelet だけじゃなくてコンテナランタイム側 (e.g. containerd, CRI-O) での変更も必要なのですぐには実現できない (k/k#47862 (comment))

  • コンテナランタイムの実装では、ポートフォワードする際に対象の Pod の network namespace (Pod Sandbox) に netns で入って net.Dial で対象のサーバとの接続を確立する
  • ポートフォワードで UDP をサポートするには以下の対応が必要
    • コンテナランタイムにポートフォワードのプロトコルが何かを伝える仕組みが必要
    • 上記の仕組みをもとに tcp4 , tcp6 といったプロトコルをハードコードしている部分を UDP 向けに改修が必要
  • すぐに実現は難しいので Ephemeral Containers の機能と socat を使って TCP 通信を介して UDP にトンネルするコンテナを起動するワークアラウンド
    • UDP to TCP サーバ (ローカルマシン) <-- port-foward --> TCP to UDP サーバ (Ephemeral Container) <-- localhost --> UDP サーバ (対象のコンテナ)
    • 対象のコンテナが UDP サーバを 80 番ポートで公開している想定
    • tcp-listen の 1234 番ポートは適当な値なので適宜修正して良い
    • fork オプションは接続が切断されても通信を受け取るプロセスが停止しないようにするためで、max-children=1 が併用されているので同時に接続できるのは 1 クライアントのみ
    • ruseaddr オプションは SO_REUSEADDR を有効にして TIME_WAIT などでセッションが残っている場合に bind エラーにならないようにするため
POD_NAME=
kubectl debug ${POD_NAME} --image=alpine/socat -- socat tcp-listen:1234,fork,reuseaddr,max-children=1 UDP4:127.0.0.1:80
# 1234 番ポートに対してポートフォワード
kubectl port-forward ${POD_NAME} 1234
# 別のウィンドウで socat で UDP で受け取ったパケットを TCP にトンネルするサーバを起動
socat UDP4-LISTEN:8080 tcp4:127.0.0.1:1234,fork
# 後はローカル環境から UDP パケットを送るだけ
echo "hostname" | nc -u 127.0.0.1 8080
Tsubasa NagasawaTsubasa Nagasawa

2024/8/27

GKE 1.31 対応のスピード

GKE に 1.31 がとっくに来てた。upstream のリソースからついに 1 週間で対応になっていて早い (release notes)

Evented PLEG が抱える問題と Sidecar containers によるリグレッション修正

Sidecar Containers の機能追加により Init containers が起動中にコンテナランタイムが停止すると起動できなくなるリグレッションがあって、Init container の状態が ContainerCreated の場合に再起動する修正の PR が上がっていて、レビューしていたら学びがあった。kubelet がコンテナを起動するときはコンテナランタイムに対して CreateContainer と StartContainer の 2 つの CRI を呼び出す。kubelet は Pod Lifecycle Event Generator (PLEG) の仕組みを使って Pod の状態を把握して理想の状態に近づける。現在デフォルトで使われている PLEG は Generic PLEG と呼ばれるもので、kubelet が頻繁にコンテナランタイムに対して relist (ListContainers の CRI を定期的に呼び出す) を行って現在のコンテナの状態 (e.g. ContainerStarted, ContainerChanged) を PodStatus に記録する。Node に大量の Pod がいるとこの relist の処理が重いので、KEP-3386: Evented PLEG が提案されていて、今はアルファの機能 (1.27 でデフォルト無効のままベータに昇格したけど、致命的なバグがあって 1.30 でアルファに戻った)。Evented PLEG の場合は、コンテナランタイムと kubelet が GRPC streaming で繋がってコンテナランタイムが kubelet にイベントを送る。ただし、イベントを取りこぼす可能性があるので、Generic PLEG も間隔を延ばして併用はする。で、CreateContainer と StartContainer の CRI は kubelet の中の同じ関数 (startContainer) の中で呼び出されていて、Generic PLEG だとポーリング間隔のせいか正常にコンテナが起動する場合は ContainerCreated の状態は検知されない。検知される場合はコンテナランタイム側で問題があって起動できない状態だと思って良いので、今の通常のコンテナの実装だと ContainerCreated の状態のときは問答無用でコンテナを再起動する。この処理が Init container のケースで抜けていてリグレッションは起きていた。ただ、Evented PLEG が有効な場合は、生成されるイベントはコンテナランタイムが返すので正常系でも ContainerCreated の状態は検知される。そのせいで、正常に起動しようとしているコンテナが再起動される問題が発生した。これが Evented PLEG のベータ昇格を阻害している問題で修正の PR が上がっている。だからこの修正も同じ問題を引き起こすことになるよって最近 PLEG や In-Place Pod Update 関連でよく見かける日本の方 (富士通で Red Hat と一緒に OpenShift の開発やっているみたい) に教えてもらった。(k/k#126543 (comment))

kubectl 1.31 の describe service のリグレッション

kubectl 1.31 で kubectl describe service をすると Ready 状態じゃない Endpoint まで表示されてしまうリグレッションの修正の PR。kubectl 1.31 で kubectl describe service の Endpoints の情報を EndpointSlices から取得するように変更した際に Endpoint の状態をチェックするのを忘れていたことが原因。Endpoints だと Ready 状態と NotReady 状態のアドレスが別々の slice に別れているので、単純に Ready 状態のアドレスの slice を参照すれば良いけど、EndpointSlices の場合はアドレスの slice とは別に Conditions の slice があって、Ready / NotReady な状態のアドレスが混在しているので逐一 Conditions のチェックが必要。SIG-Network もこの仕様に何度か自らハマっているらしい (k/k#126932)

Tsubasa NagasawaTsubasa Nagasawa

2024/8/29

Kubernetes 1.31 の Windows Node のリグレッション

Kubernetes 1.31 の Windows Node で kubelet を再起動すると起動できなくなるクリティカルな問題。kubelet が停止時に Device plugin とのやり取りに使う Unix ドメインソケットのファイルをお掃除する処理が動かなくなって、起動時に既に存在するファイルを作ろうとして死ぬのが原因。Go の標準ライブラリの os.ModeSocket が正しく設定されない問題があって、以前は Unix ドメインソケットか確認せずにファイルを消していたけど、os.ModeSocket の挙動が修正されたのでちゃんと確認するように変更したら、やっぱり期待通りに動いていなかったみたい。Node E2E テストでカバーしていたけど、Windows Node では実行できないので気付けなかったらしい。(k/k#126965)

client-go の自動リトライ

client-go で API サーバに対して GET リクエストを送るときに HTTP2 のコネクションが切断された時に自動的にリトライする修正。古いバージョンの client-go に backport するか話し合っていたけど、独自にリトライ処理を実装している場合に API サーバに負荷を掛ける可能性があるらしく見送りそう。client-go は内部的にリトライが可能な場合にリトライする実装になっていて、書き込みの発生しない GET リクエストやネットワークの問題によるサーバ側からの切断や EOF エラー、Retry-After のヘッダーが付与されている 5XX 系のエラーの場合は自動的にリトライする。ただ、このことを知らずに client-go の上に独自のリトライ処理を実装しているケースがあって、API サーバに負荷を掛けることになる (k/k#126954)

Tsubasa NagasawaTsubasa Nagasawa

2024/9/1

containerd 1.7.14 のリグレッション

containerd 1.7.14 のバグでコンテナが Running 状態だけど実際にはコンテナのプロセスが動いていないことがある問題。コンテナの init プロセスの終了と liveness probe / lifecycle hook の exec コマンドの実行の間で競合することがあり、コンテナのイベントを取りこぼしてライフサイクルを正しく遷移できなくなるらしい。EKS は最新の 8/28 の AMI で containerd のバージョンを 1.7.11 にもどした。AL2023 だと 8/7 以降の AMI で問題が起きることがある。Google の人も再現テストを作ったり修正をレビューしているので気付いて GKE でも何かしら対策はしてそう (containerd/containerd#10589, awslabs/amazon-eks-ami#1933)

Tsubasa NagasawaTsubasa Nagasawa

2024/9/2

kube-scheduler の Queueing Hints のパフォーマンス改善の結果

kube-scheduler の Queueing Hints が ON / OFF の場合のパフォーマンス比較。Scheduling Gate を利用している Pod が大量にいてスケジュール待ちの状態のときは、(Pod をスケジュールできるかもしれない) イベントが発生した時に unschedulable pods から activeQ へ移動させる処理をスキップするので、スループットはかなり改善している。ただ、Unschedulable な状態の Pod が大量にいる場合は、若干スループットが落ちている。DRA の時もスループットが悪化しているけど、何が原因だろう。Structured Parameters の場合なのかな (k/k#122597 (comment))

Endpoint のオブジェクトが更新されなくなる問題

Kubernetes 1.28.12 / 1.29.7 / 1.30.3 / 1.31.0 で影響のあるリグレッションで、エッジケースで Endpoint のオブジェクトが更新されなくなる問題。ただ、3 人から報告があるので何かしらのツールでそういう処理がある?(k/k#126578 (comment))

EKS を利用しているユーザーからの報告で Mutating Admission Webhook で Endpoints に対してラベル (e.g. dummy-k: value) を追加している場合に起こるらしい

  1. Mutating Admission Webhook が Endpoints の作成イベントに反応してラベルを差し込む
  2. Endpoints controller の syncServices() の処理の中で Service のラベルと Endpoints のラベルを比較し、Service のラベルにない dummy-k: value を削除
  3. Mutating Admission Webhook が Endpoints の更新イベントに反応してラベルを再度付与する。Endpoints の更新リクエストの中でラベルを差し込むため、オブジェクトの resourceVersion は更新されない
  4. Endpoints controller の修正 (リグレッションの原因) により、Endpoints が古い状態かを resourceVersion を用いて判断するようになった。Pod の状態が短時間で変化する場合に、Informer キャッシュの状態が最新でないことで Endpoints の更新が遅れる問題を解消するため。そのせいで、syncService() の処理の中で Endpoints が新規に作成されていない場合に、現在の resourceVersion を古いバージョンとして扱い、Endpoints オブジェクトの状態の更新がエラーとなってリトライする。
  5. ただ、いくら処理をリトライしても、Pod の状態に変更があって Endpoints が更新されても、Mutating Admission Webhook がいる限り resourceVersion に変更がなく、Service にはないラベルを差し込める。Endpoints が更新されなくなる

Mutating Admission Webhook を利用している場合、resourceVersion を更新せずに変更を差し込めるため、resourceVersion は同じでもオブジェクトに違いが生じてしまう可能性があるので注意が必要

Tsubasa NagasawaTsubasa Nagasawa

2024/9/5

kube-proxy の conntrack バイナリ依存の排除

kube-proxy が UDP の古い conntrack エントリを手動でお掃除する処理 (UDP パケットがブラックホールに飲み込まれないようにするため) で conntrack のバイナリに依存していたのが netlink の Go ライブラリに依存するように改善された。kube-proxy のイメージの中に conntrack のバイナリが不要になる。(k/k#126847)

ただ、この変更はイメージサイズを減らすのが本来の目的じゃなくて、UDP の conntrack エントリ関連のバグ報告がなかなか減らない (何かを直したと思ってしばらくするとまた別のエッジケースの報告がある) ので、conntrack テーブルをイベントベースじゃなくて定期的に reconcile する処理を実装しようという動きがあってその事前作業。(k/k#126130)

reconcile する時に全ての conntrack エントリを取ってくるとパフォーマンス的に問題なので、カーネル側で特定のパケットのフローに関わる conntrack エントリのみに絞れるらしくそれで削除したい。なので、netlink のライブラリに ConntrackDeleteFilters を追加して conntrack エントリを効率的に削除できるようにした。(vishvananda/netlink#989)

Tsubasa NagasawaTsubasa Nagasawa

2024/9/8

QHints の Node イベント発生時の重複した処理の排除

QHints が有効な場合に Node の EventHandler 経由で発火する preCheck が実行されなくなる PR。QHints の実装がほぼ終わったので、重複した処理となっている preCheck の処理を実行しないようにする (k/k#127109)

Node 関連の scheduler plugin の QHints で監視する Node イベントの整理

QHints が preCheck の時に実行されなくなったけど、in-tree の scheduler plugin で監視している Node のイベントは以前と変わらない。QHints が有効な場合は Node のイベントの中で無視できるものが出てくるので、除外する PR。(k/k#127220)

特に Node の Taints に関わるイベントを契機に QHints の処理を実行したい plugin の場合、本来 Node が追加された時のイベントを契機に処理したいが、 preCheck の処理の中で Node が Ready 状態ではないイベントが除外されていた。そのため、Node の Taints に関わるイベントが一部欠落してしまい、本来なら Pod をスケジュール可能になるイベントを取りこぼしていた。ワークアラウンドとして、UpdateNodeTaint のイベントを監視することで Node の Taints の変更のイベントを検知できるようにしていた。QHints が有効な場合に preCheck が実行されなくなり、Node 追加時のイベントが除外されなくなったので、 UpdateNodeTaint のイベントの監視が不要になる。

Tsubasa NagasawaTsubasa Nagasawa

2024/9/11

kubectl 同梱の kustomize 非推奨化の議論の続き

kubectl に同梱されている kustomize を非推奨化する KEP は Kubernetes 1.32 のサイクルでも動かなそうな雰囲気。非推奨化して依存関係を無くすに足る動機付けがないと厳しい。go embed で事前にビルドしたバイナリを各アーキテクチャ向けの kubectl に同梱して、ライブラリとしての依存を無くす案もある。kubectl kustomize を実行したときだけ、/tmp に埋め込んだバイナリをコピーして実行するが、それはそれでセキュリティ的にどうなのかという (kubernetes/enhancements#4706 (comment))

Tsubasa NagasawaTsubasa Nagasawa

2024/9/12

コンテナ単位で Pod の正常性に影響するしないを制御する機能の議論

複数のコンテナがいる Pod でメイン以外のコンテナがエラー終了した場合でも Pod 自体を NotReady 状態にしないことはできないかの議論。コンテナの状態に関わらず true を必ず返す Probe を追加する案 (Probe はコンテナがエラー状態の場合は実行されないのでその辺りも帰る必要がある) やコンテナの状態を Pod の状態に含めないフィールド (e.g. participateInPodReadiness: false) を追加する案などが挙がっている。過去の Issue が浮上してきたのを見て思い付きで議論しているだけで、KEP にする気はないみたい (k/k#127276)

Tsubasa NagasawaTsubasa Nagasawa

2024/9/15

OCI Volume Source のプルと通常のイメージプルの競合

通常のコンテナイメージと OCI Volume Source で kubelet のイメージプルを現状共有しているので大規模な言語モデルのダウンロードが通常のコンテナイメージのダウンロードをブロックする可能性があるのではの指摘。特にデフォルトで kubelet のイメージプルが直列なので。コンテナイメージのダウンロードにはカウントしないようにする? (kubernetes/enhancements#4639 (comment))

Tsubasa NagasawaTsubasa Nagasawa

2024/9/18

IBM Acquires Kubecost to Broaden Hybrid Cloud Cost Management Capabilities

Kubecost が IBM に買収された

Add instanceExistsGracePeriod to cloud-node-lifecycle-controller

EKS の Cloud Node Lifecycle Controller が作成されたばかりの Node の裏側の EC2 インスタンスの情報を ec2:DescribeInstances で取得する際に情報が取れないことがあり、Node Lifecycle Controller が誤って Node を削除してしまう問題の修正の PR。Node だけ削除されるので、裏側の EC2 インスタンスが残ってしまう。EKS で低確率で発生しているらしく、手動で EC2 インスタンスの削除が必要になるっぽい

Tsubasa NagasawaTsubasa Nagasawa

2024/9/21

#2410 [EKS] [request]: Support for Kubernetes 1.31

EKS 1.31 のリリースが遅れていて、またユーザーから不満が。GKE も AKS も 1.31 をサポート済みなのに、EKS だけサポートが遅れている。EKS のコントロールプレーンの運用にお金を払っているのに、リリースのタイムラインがはっきりしなくて EKS 更新の計画を立てづらい。せっかく container-roadmap のリポジトリがあるのに AWS の中の人が Issue でどういう状況か記載してくれないなど

ファイルシステムが高い負荷な時の Pod の起動の遅れ

Node 上でファイルシステムのマウントとアンマウントを繰り返して負荷を掛けつつ Pod を作成すると、runc が systemd を使ってコンテナ用の cgroup のセットアップする処理でタイムアウトが発生し、Pod の起動が遅れる問題。同様に Pod の停止も遅れる。runc から systemd の呼び出し部分でタイムアウトの伝搬が正しく行われていないのが原因で通常よりも待ちが発生しているらしい (k/k#120103 (comment))

Tsubasa NagasawaTsubasa Nagasawa

2024/9/23

#127548 eviction manager fails to prioritize Hostpath Volume Pods for Eviction Under DiskPressure

Node 上に hostPath volume を利用した Pod とそれ以外の通常の Pod が動いているとする。hostPath volume を利用した Pod が Node 上のディスクを食い潰して、Node が DiskPressure 状態に陥ると、kubelet が Pod を Evict して Node を正常な状態に戻そうとする。この場合、hostPath volume を利用した Pod を優先的に Evict するべきだが、実際には無関係な Pod と system の Pod の次に候補として上がっている問題。そもそも、DiskPressure が発生した時の原因調査しようとしても、Node 単位のディスク容量は高くなっているが、コンテナ単位のディスク使用量は低くなっているので、hostPath volume のメトリクスがどう計測されているか知らないと原因の特定が難しい点も何とかしたいらしい。いつもの Google の人からの報告なので、GKE の利用者が踏んだっぽい

Data loss in root overlayfs and other container mounts when using user namespaces

User namespaces の機能を有効にしたコンテナを起動して、何かしらの方法で idmapped mount の処理に負荷をかけた状態でコンテナを停止すると、ホスト上にあるそのコンテナイメージ (コンテナの rootfs) の一部が誤って削除され、それ以降壊れたイメージを使ってコンテナが起動できなくなる問題。Issue には hostPath でマウントしたディレクトリも消えるかもという憶測が書かれているが、ボリュームを削除する処理は実装した覚えがないから消えないはずらしい

Tsubasa NagasawaTsubasa Nagasawa

2024/9/27

#127137 support set default dns ndots in kubelet

本当かはわからないけど、数十万 Node に数百万 Pod がいる超大規模 Kubernetes クラスタの話しが。超大規模クラスタで クラスタ DNS を中央集権的に管理しているらしく、名前解決の負荷が高いから Pod レベルじゃなくて Node レベルでも ndots を設定させてくれという要望。Mutating Webhook があるからそっちでやった方が良いという話にはなっている。ただ、kubelet の clusterDNS のオプションを設定しない場合もホスト上の /etc/resolve.conf が使われるので、実質 Node レベルの設定を使うこともできる。

Tsubasa NagasawaTsubasa Nagasawa

2024/9/30

Otel Collector の k8sattributes processor のメモリ使用量の高騰

OpenTelemetry Collector のメモリ使用量が 6 GiB を超えていて原因は何だろうと思っていたら、k8sattributes processor が ReplicaSet の情報をインメモリにキャッシュしているのが原因でした。通常の環境だとここまで増えないのですが、ある namespace に ReplicaSet が 60,000 個くらい残っていてそれが影響してそう。ReplicaSet を消して良いか分からないので、ここにあるワークアラウンドを適用したら 100 MiB ちょいまで落ち着きました。(open-telemetry/opentelemetry-collector-contrib (comment))

Tsubasa NagasawaTsubasa Nagasawa

2024/10/1

Karpenter が起動するインスタンスタイプの制限

Karpenter が起動する Node を制限していないと t3.nano でインスタンスタイプが作られ、割り当て可能なリソースが少なく swap on になっているので Kubelet が起動に失敗して EKS クラスタに Node が Join できなくなる。karpenter.k8s.aws/instance-size とかでちゃんと制限を入れておかないとダメ (docs)

requirements:
- key: karpenter.k8s.aws/instance-category
  operator: In
  values: ["t"]
- key: karpenter.k8s.aws/instance-family
  operator: In
  values: ["t3", "t3a"]
- key: karpenter.sh/capacity-type
  operator: In
  values: ["on-demand"]
- key: karpenter.k8s.aws/instance-size
  operator: NotIn
  values:
  - micro
  - nano
Tsubasa NagasawaTsubasa Nagasawa

2024/10/2

#127780 Fix deleted UDP endpoint detection

Kubernetes 1.29 で不要な UDP の conntrack エントリが残ってパケットが闇に消える可能性のあるエッジケースを修正したときに混入したリグレッションの修正。これまでは Endpoint の ready condition (リクエストを受け付けられる状態か) が true かチェックする処理があったが、それが上記の修正の時に誤って削除された。それにより、停止中の Pod の Endpoint オブジェクトの ready condition が true から false に変化した場合に検知できず、UDP パケットが闇に消えることがある。現状は ready condition の遷移がなく、Endpoint が直接消える場合は検知できているのでエッジケースではある。再現手順だとクラスタ DNS と kube-proxy を同時に停止しつつ、UDP パケットを同じ送信元ポートで送り続けると発生していた。クラスタ DNS など UDP を利用する Pod が再起動した場合に起きる可能性があり、Node に異常が起きた場合に可能性が高くなりそう

#33569 Test the upcoming containerd 2.0.0 (rc5)

Kubernetes の upstream でも containerd 2.0.0-rc5 がインストールされた環境で一部のテストが実行され始め、問題なく動いているっぽい。しばらくこのまま動かして Flaky なテストがないかも調べる感じかな

Tsubasa NagasawaTsubasa Nagasawa

2024/10/3

#125070 Ensure volumes are unmounted during graceful node shutdown

Kubernetes 1.32 から Graceful Node Shutdown で Persistent Volume が Node から可能な限り安全にアンマウントされるようになる。Graceful Node Shutdown が発生すると通常の Pod が停止されてから critical Pod (system-cluster-critical や system-node-critical の Priority が指定された Pod) が停止される。kubelet が通常の Pod を停止するとき、その Pod が利用している Volume を CSI deiver が Node からアンマウントするまでは待たない。そのため、GCE PD CSI driver や EBS CSI driver などの critical Pod が先に停止してしまい、Volume のアンマウント処理が正常に行われない可能性がある。今回の改善で kubelet が Graceful Shutdown で Node を停止する時に Volume がアンマウントされるかをベストエフォート (Pod 停止の猶予時間を超えるとタイムアウトしてエラーを返しそれ以降の処理を継続) で待つようになる

Tsubasa NagasawaTsubasa Nagasawa

2024/10/4

echo test >/proc/$PID/fd/0 の活用

PID 1 のプロセスの標準出力 (fd/1) や標準エラー (fd/2) に書き込むのは、Kubernetes で readiness / liveness などの Probe のデバッグをする時に使いますね。通常 Probe のログは見えないので、無理やりコンテナのエントリポイントの標準出力にリダイレクトして書き込んでコンテナログとして見えるようにする (slide)

Tsubasa NagasawaTsubasa Nagasawa

2024/10/5

Mountpoint S3 の Pod レベルの柔軟な権限指定

Mountpoint S3 CSI Driver v1.9.0 でマウント先の Pod の IRSA を利用して柔軟に認証できるようになった。以前は CSI Driver の Pod に強い権限を付与する必要があり、マルチテナント環境だと権限が乱用される可能性があった。CSIDriver の podInfoOnMount を有効にすることで、NodePublishVolumeRequest にマウント先の Pod の情報が埋め込まれるようになる。その中に ServiceAccount のトークンも含まれるので、Mountpoint S3 CSI Driver の DaemonSet がそちらを使って S3 を操作するようになる (awslabs/mountpoint-s3-csi-driver#111 (comment))

Tsubasa NagasawaTsubasa Nagasawa

2024/10/8

[Cluster Autoscaler] VolumeBinding に失敗した Node のスケールインがブロックされる問題

Cluster Autoscaler はスケジュールできない状態の Pod を見つけると、Node をスケールアウトする事で Pod がスケジュール可能になるかをシミュレーションする。シミュレーションの結果、スケジュール可能となる Pod と Node のペアの情報を ClusterSnapshot に保存し、スケールインの判断の時にこの情報を使って Pod を配置する予定の Node がスケールインされないようにする。Cluster Autoscaler が新しく Node をスケールアウトし、Pod がその Node にスケジュールされ、PVC の動的プロビジョニングで問題が起きて時間がかかり、VolumeBinding plugin の処理がタイムアウトした場合、Pod は SchedulerError でスケジュールに失敗し、再スケジュールを繰り返す。Cluster Autoscaler の現状の実装だと SchedulerError 状態の Pod をスケジュールできない状態だと正しく判別できない。そのせいで、この Pod に対して再度シミュレーションが実行されず、ClusterSnapshot に Pod とスケジュール先の Node の情報が残ったままになってしまう。スケールインを検証する際にこの情報によって、PVC の動的プロビジョニングにタイムアウトした Node のスケールインがブロックされる問題 (kubernetes/autoscaler#7343)

Tsubasa NagasawaTsubasa Nagasawa

2024/10/10

コンテナランタイムと Kubernetes の新機能の関係性

everpeace さんの KEP-3619 のベータ昇格の判断が引き金で、コンテナランタイムの実装に依存した Kubernetes の新機能のベータ昇格のタイミングの議論が。containerd 2.0 がなかなかリリースされない (KubeCon NA のタイミングを目指しているとか) ので、Kubernetes 1.32 でコンテナランタイムの実装に依存した新機能をベータ昇格しても良いのかどうか。元々、CRI-O と containerd の 2 つのコンテナランタイムの実装で新機能が動作することが一つの条件ではあったけど、containerd 2.0 のリリースのタイミングが読めないので困っている感じ。CRI の RuntimeHandlerFeatures と RuntimeFeature (everpeace さんが KEP-3619 の導入の中で追加したやつ) を使って、コンテナランタイムが新機能をサポートしているかを CRI 経由で Kubelet が把握できるようになり、コンテナランタイム側で実装が必須ではなくなっているので、待たなくても良いのでは論も (mailing list)

Kubernetes における .io の TLD が消えるかも問題の議論

.io の TLD が消えるかも問題に Kubernetes がどう対応するか議論している Issue。.io を利用しているのは Kubernetes のウェブサイトや Go のパッケージのエイリアス、API グループ、annotation やラベルの suffix などなど影響範囲が大きい。そもそもまだなくなると決まったわけではなく、なくなるにしても 3 年の猶予期間はある。そもそも、元のサイトが余計に煽りすぎって話にはなっている。ただ、大移行を考えると長くはない。.io のような ccTLD を使うのがリスクなのはその通りなので、何ができるか考えている感じ。Kubernetes としては .dev の gTLD も所有しているので、ウェブサイト系は既存のコントリビュータ向けのサイトと同じ kubernetes.devk8s.dev に移行する?(k/k#127966)

Tsubasa NagasawaTsubasa Nagasawa

2024/10/11

Aldo さんが WG-Batch のリードから降りる

Aldo さん SIG-Apps と WG-Batch だけじゃなくて SIG-Scheduling からも離れちゃうのかな。最近、レビューを他の人に任せてる感じあるし不穏 (mailing list)

OCI Volume Source のベータ昇格のタイミング

containerd 2.0 は KubeCon 開催前にリリース予定で、2.0 以降はマイナーバージョンのリリースサイクルが年 2 回に戻る予定。OCI Volume Source の機能の containerd の実装はマージされかけているが、ホストマシン側にある OCI イメージのボリュームの GC の部分をどうするのが良いか決める必要がある。Kubernetes 的には containerd の実装が入らないことには OCI Volume Source のベータ昇格は難しいというスタンスなので、1.32 でのベータ昇格は難しいかな (kubernetes/enhancements#4897 (comment))

Tsubasa NagasawaTsubasa Nagasawa

2024/10/12

Sidecar Containers を Service + 名前付きポートで外部公開できないバグ

Sidecar containers を Service で外部公開する時に Service の ports に名前付きポート (e.g. http) を指定しても期待通りに動かない問題。EndpointSlice controller が利用している Pod の名前付きポートをポート番号に変換する処理で Restartable init containers が考慮されていなかったのが原因。(k/k#127976)

Restartable Init Containers と Regular containers で同じ名前付きポートを指定している場合は、Regular containers のポート番号が優先される。Regular containers の中で同じポート名を指定すると、最初に一致したポート名のポート番号が使われる。同じ名前で名前付きポートを指定できてしまう部分は今更変更できないので、警告メッセージを返すようにする PR (k/k#128016)

Kubernetes の CVE の予約

Kubernetes でまた CVE 報告用の Issue が 2 つ予約されている (k/k#128006, k/k#128007)

  • 1 つは Cluster API の Proxmox プロバイダーで使っている Packer で焼いたイメージの中にビルド用のユーザーが残っていた問題っぽい。公開前だけど丁寧に PR がリンクされて、Issue がクローズされてた
  • もう 1 つも Cluster API の VM イメージ関連で、SSH パスワードが固定値で入っているのをランダム生成されるように変更されてた
Tsubasa NagasawaTsubasa Nagasawa

2024/10/14

kube-apiserver Memory Leak with gogo/protobuf Unmarshal

Kubernetes API サーバのメモリ使用量が高騰している報告があるから覗いたら Kubernetes 1.17 だった。本番環境で動いていて 1.28+ のサポート範囲内のバージョンに更新できないらしく、Kubernetes 1.17 以降のメモリ周りの改善の変更を取り込もうとしてる。絶対的にそっちの方が大変な気が…。改善された変更を教えてって言ってるけど沢山あるから難しいし、リファクタも入っているから単純に cherry-pick も出来ないし。何なら今実装中の KEP-3157: WatchList まで取り込もうとしてそうで怖い…

Tsubasa NagasawaTsubasa Nagasawa

2024/10/16

Mountpoint S3 の prefetch のメモリ使用量の改善

Mountpoint S3 は S3 からオブジェクトを読み取る前にインメモリ上に保持 (prefetch) しておいて、インメモリから中身を読み取ることでシーケンシャルリードのスループットを最適化している。内部的に prefetch window size というパラメータで Mountpoint S3 がインメモリ上に事前に読み込むデータのサイズを指定可能で、処理するファイル毎に値も変更できる。これまではホスト上で利用可能なメモリ容量を考慮せずに処理するファイル毎に最大 3 GiB まで消費していたので、並列で複数のオブジェクトを読み込む場合にホスト上のメモリが枯渇することがあった。Mountpoint S3 v1.10.0 からホスト上で利用可能なメモリ容量から自動的に prefetch window size の値を調整して、良い感じに prefetch できるようになった。枯渇しないようにメモリ使用量の上限 (デフォルトでホストの全メモリ容量の 95%) も設定されているっぽい (awslabs/mountpoint-s3#1013)

Tsubasa NagasawaTsubasa Nagasawa

2024/10/18

KEP-3386: Evented PLEG の複雑性

kubelet の Pod Lifecycle Event Generator (PLEG) の仕組みとして、コンテナランタイムに定期的にポーリングして Pod の追加や更新や削除のイベントを検知する Generic PLEG とコンテナランタイムが CRI API 経由で渡すイベントを使ってより効率的に生成する Evented PLEG の機能がアルファであるけど、Evented PLEG 専用の処理が Generic PLEG にも侵食していてレビューしづらいので実装を消すかもらしい。Evented PLEG は kubelet には早すぎる最適化な気がするし、バグもまだまだあって有志で対応している状態だから厳しそう

Support for expanded 'operators' (e.g. In) in field selectors

複数の namespace に跨ってリソースを list / watch する controller を実装するとき、現状だとクラスタ全体のリソースを取得してクライアント側で特定の namespace だけにフィルターする必要がある。これを API サーバ側でできないか以前に考えたけど、etcd にネイティブでそういう機能がないのと、当時の etcd 連携の実装だとcontroller からの要求ごとに全 namespace に対する watch を API サーバと etcd の間で張ってインメモリで特定の namespace にフィルターする必要があってメモリ使用量の高騰する懸念があった。ただ、最近 KEP-2340: Consistent read from cache や KEP-4568: Resilient watch cache initialization、KEP-4358: Custom Resource field selectors の機能が入っているし、そろそろこの機能も入れられるんじゃないかという議論。ラベルセレクタと違ってフィールドセレクタはユーザーがある程度好きに指定できるので入力のバリデーションが重くなるとか、namespace で制限する時に metadata.name in(foo, bar) 的な記法をサポートしたいのでどうするのが良いか話し合っている感じ

Tsubasa NagasawaTsubasa Nagasawa

2024/10/19

Clasic DRA の実装の削除

Classic DRA (Kubernetes 1.29 以前の PodSchedulingContext を介して kubelet と kube-scheduler がやり取りする仕組み) の実装が削除された。Kubernetes 1.32 から Structured Parameter のみになる予定 (k/k#128003)

Tsubasa NagasawaTsubasa Nagasawa

2024/10/20

Use image pull error in message during back-off

Pod が ImagePullBackoff 状態になった時のメッセージにコンテナプル時の実際のエラーを含める改善

コンテナイメージが何かしらの理由でプルできない場合のエラーは、CRI 経由で定義されているエラー (e.g. RegistryUnavailable, SignatureValidationFailed) と一般的なエラー (e.g. ErrImagePull) に分かれる。で、Pod のステータスにはイメージプル時の実際のエラーと ImagePullBackoff が交互に表示される。

NAME   READY   STATUS                      RESTARTS   AGE
pod    0/1     SignatureValidationFailed   0          10s
or
NAME   READY   STATUS             RESTARTS   AGE
pod    0/1     ImagePullBackOff   0          18s

ImagePullBackoffImagePullBackoff の Event が最後に更新された時刻から再思考まで時間が経過していない場合に表示されるため、ユーザーから見える時間は長い。ただ、ImagePullBackOff のメッセージは Back-off pulling image... という汎用的な内容なので原因が特定しづらい。そのため、ImagePullBackoff のメッセージにコンテナイメージのプルに失敗した時のエラーメッセージを追記する形に改善された。

{
  "waiting": {
    "message": "Back-off pulling image \"quay.io/crio/unsigned:latest\": SignatureValidationFailed: image pull failed for quay.io/crio/unsigned:latest because the signature validation failed: Source
 image rejected: A signature was required, but no signature exists",
    "reason": "ImagePullBackOff"
  }
}
Tsubasa NagasawaTsubasa Nagasawa

2024/10/21

kube-controller-manager re-allocating already used PodCIDR (v1.31)

Kubernetes 1.31 で kube-controller-manager が新しい Node に既に他の Node で割り当て済みな PodCIDR を割り当ててしまう問題が Zalando の人から報告されている。Node が Ready 状態にならずに 10 分後に停止するが、その影響で Flannel が Node に割り当てられた Pod CIDR をルーティングテーブルから削除してしまい、重複した PodCIDR が割り当てられた Pod に通信できなくなる。原因は Karpenter が Node を停止しようとした時に、PDB が設定された Pod によって Node の停止が長時間ブロックされることによるもの。Node は deletionTimestamp が設定されているが、finalizer によって削除がブロックされている状態。Kubernetes 1.31 で kube-controller-manager の Node IPAM controller の CPU 使用率の高騰を修正する際に、誤ってバグが混入した形。Kubernetes 1.31 より前は Node の削除イベントを検知して PodCIDR を開放していたが、Node に deletionTimestamp が設定された場合にもその Node が利用している PodCIDR が解放されるように変更してしまった。重複した PodCIDR が割り当てられる状況は、クラスタの規模が大きく Node の増減が激しい場合や逆にクラスタの規模が小さく PodCIDR の範囲も狭い場合に起こりうる?Zalando は EKS じゃなくて自前で EC2 上に構築しているけど、cloud-provider-aws を使っていたり、EKS と似た構成だから EKS でも影響はありそう。CNI の実装にもよりそうで、Flannel と VPC CNI plugin で違うので影響ないかもだけど。GKE は独自の IPAM controller を cloud-provider-gcp で実装しているので影響ない?今のところ 1 件しか報告がないけど、結構やばそうだから EKS を本番運用している場合は、修正版がリリースされるまで 1.31 に更新しない方が安全そう。

UPDATE: k/k#128305 で修正されて cherry-pick 待ち

Tsubasa NagasawaTsubasa Nagasawa

2024/10/24

Kubernetes の依存ライブラリとしての runc

Kubernetes のライブラリの依存関係に runc が入っていて、libcontainer の Go の wrapper を cgroupfs や systemd で cgroup v1 / v2 を管理している処理で利用している。runc としても API として外部に公開したくないパッケージを internal 以下に移動させたい動きがあるのと、Kubernetes としても runc のリリースサイクルに合わせる必要があるので新しい機能の利用がブロックされがちで辛い。Kubernetes で libcontainer の一部をフォークする案も出たが、変更に追従するのが大変らしくおすすめできないとのこと。runc から libcontainer/cgroups のライブラリを外に出して、opencpntainers の GitHub 組織の下に新しくリポジトリを作って置こうとしている。それを runc と Kubernetes のメンバーでメンテして利用する形 (k/k#128157 (comment))

Tsubasa NagasawaTsubasa Nagasawa

2024/10/25

Cloud Provider のインターフェイスに 7 年以上前から存在する HasClusterID の用途が何なのか今の SIG-Cloud-Provider の人たちも分からないので、SIG-Cloud-Provider に興味のある人に歴史を調べさせようとしている Issue。ClusterID 自体もどこにも使われておらず、どう実装するのが正解なのか分からない状態。最近 SIG-Multi-Cluster が提案しているマルチクラスタ管理における ClusterID とは無関係。

Tsubasa NagasawaTsubasa Nagasawa

2024/10/26

scheduler: Improve CSILimits plugin accuracy by using VolumeAttachments

PV をマウントした Pod が停止する時に Volume が正常にアンマウントされるまでに時間が掛かることがある。scheduler の CSILimit plugin (Node にマウントできるボリュームの数を超えていないか確認して Pod をスケジュール) が Pod から取得した情報のみを考慮しているため、停止した Pod でボリュームがまだ Node にマウントされている場合に過剰に Pod をスケジュールしてしまうことがあり。実際に起きても時間経過で自動復旧するが、EBS だと変なエラーメッセージを返すので UX が悪い。ボリュームがアンマウントされたかは VolumeAttachment を見れば分かるので、追加でボリュームをカウントするようにした修正。

Tsubasa NagasawaTsubasa Nagasawa

2024/10/30

When containers use memory backed tmpfs and hit a OOM limit they will keep OOM on restarts.

emptyDir で medium: Memory を指定して Pod にマウントすると tmpfs (インメモリのファイルシステム) に書き込まれ、ホスト上のディスクには書き込まれなくなる。tmpfs の利用上限を指定する機能 (SizeMemoryBackedVolumes) が Kuberneres 1.22 からベータで止まっていて Kubernetes 1.32 で GA に昇格する予定。tmpfs に書き込まれたデータはディスク上にフラッシュできないので解放できず、dirty な anonymous ページとして扱われる。コンテナにメモリ上限が設定されていて、tmpfs への書き込みがその上限を超えると OOMKill されることになるが、コンテナが再起動しても tmpfs の利用領域は解放されずに次のコンテナの cgroup に引き継がれる。そのため、最終的にコンテナが起動できなくなってスタックする問題。SizeMemoryBackedVolumes のレビュー中に指摘されて発覚した。コンテナが再起動する時に tmpfs の利用領域を強制的に開放してあげれば良いが、emptyDir のライフサイクルはコンテナではなく Pod に従うのでコンテナの再起動で中身が消えるのはおかしいのと、Pod 内の複数のコンテナで emptyDir を共有している場合に中身が急に消えるのは困るのではないかという指摘もあり、なかなか難しそう

Tsubasa NagasawaTsubasa Nagasawa

2024/10/31

Cedar access controls for Kubernetes

AWS が昨年公開したポリシー言語の Cedar を使って、Kubernetes の認証と認可をまとめて管理するツール。Kubernetes の RBAC と VAP / OPA / Kyverno によるポリシー制御を同一の言語で表現するのが目的みたい。Kubernetes 組み込みの RBAC による認可はスループットを下げないために、リクエストされたオブジェクトをシリアライズして中身を見るといったことはしておらず、リソースの種類や操作などを見ているだけ。Cedar Access Control は Kubernetes の RBAC では実現できない特定のラベルが付与されたリソースに対する操作を制限することもできる。ただ、そのために Kubernetes 1.31 時点でアルファの AuthorizeWithSelectors の機能を利用しているので安定化するまでは本番運用は難しそう。内部的には Authorization Webhook と Validating Admission Webhook を実装していて、Policy のカスタムリソースの中に Cedar のルールを生で書く感じ。現状は content フィールドに直書きしたルールをカスタムリソース反映時に問題がないか validation は走らなそうなので、ルールのデバッグとかやりやすいのかは気になる。VAP も Authorizer の検証できるけど、あれはあくまでリクエストしたユーザーが特定のリソースの操作を RBAC で許可されているか見るだけだから違うのかな。結局 Authorization / Admission Webhook のサーバを動かす必要がある手間を考えると、Authorization Webhook も CEL で書けるようになったら解決しそうではある。

Tsubasa NagasawaTsubasa Nagasawa

2024/11/2

Add --concurrent-daemonset-syncs argument to kube-controller-manager

DaemonSet controller が DaemonSet のオブジェクトを並列で処理するための worker のデフォルト値が 2 でハードコートされていて、kube-controller-manager の起動オプションでも変更できない問題。起動オプションがそもそも存在しなかったので、追加する PR がマージされた。Google の人の報告と修正で、大規模クラスタで大量の Node が起動したときに CNI plugin の設定ファイルの配置などを行っている DaemonSet の Pod (おそらく GKE の netd) が起動に時間がかかり、Node が時間内に Ready 状態にならずにエラーになる問題が発生したらしい。DaemonSet controller の worker が他の DaemonSet の Pod の処理に使われてスループットが落ちていたのが原因。並列処理数を増やして解消できたらしい。2 年前にも同じような報告があったみたいだけど、逆にほとんどの場合で並列数 2 で大丈夫だったんだっていう。GKE だとこのフラグを使ってデフォルト値を上書きするのかな。大規模か大規模じゃないかはクラスタ作成時に分からないので変えるなら一括で変えるのかな

Tsubasa NagasawaTsubasa Nagasawa

2024/11/3

KubeCon NA 2024 の個人的に気になるセッション (前編)

Lightning Talk: Evaluating Scheduler Efficiency for AI/ML Jobs Using Custom Resource Metrics - Dmitry Shmulevich, NVIDIA

Kubernetes 上で動作するコンテナの CPU やメモリなど通常のリソースの使用量に関しては Metrics Server が Metrics API として公開している。ただ、GPU などのカスタムリソースは Pod の resources として指定はできても Metrics Server が使用量を公開してくれたりはしないので、Pod や Node レベルでどの程度の使用量があるかは確認できない。なので、Prometheus Node Resource Exporter を開発して、カスタムリソース (おそらく GPU だけ) の使用量を公開し、公開したメトリクス (Node の GPU 使用量の指標) を使って Pod の配置を決定する Scheduler Plugin を開発した。GPU を利用する大量の AI / ML の Job を実行して、開発した Scheduler Plugin が効率的に Pod を配置できるかを検証した結果を NVIDIA の人が共有してくれるセッション。LT で収まる内容なのか謎。

Lightning Talk: Minimizing Data Loss Within the OpenTelemetry (OTel) Collector - Alex Kats, Capital One

OpenTelemetry Collector の contrib に最近入った新しい Failover Connector について実装者が解説してくれる LT。OpenTelemetry Collector から外部のデータストアにテレメトリのデータを送る際、外部のデータストアに異常があるとテレメトリのデータが欠損する可能性がある。テレメトリのデータの転送状況 (リトライ含む) を追跡する際に使っている Sending Queue の中身をディスク上に保存する Persistent Queue を設定することで、長期間データが送れない場合に OpenTelemetry Collector が再起動してもデータ欠損が起きない仕組みは既にあるが、リトライ上限を超えた場合に欠損するなど問題はある。新しく追加された Failover Connector を利用すると、転送先の正常性を見て動的にフェイルオーバーしてくれる。分析用だと一部のテレメトリのデータだけ別の場所保存するのは現実的ではないから、監査用とかで必ずどこかに保存しないといけない場合には有効かも?LT だから時間的に微妙だけど OpenTelemetry Collector の可用性の話も軽くしてくれそうだから良いかも

Lightning Talk: Running Kind Clusters with GPU Support Using Nvkind - Evan Lezar, NVIDIA

以前 Slack で紹介した klueska さんの Running kind clusters with GPUs がいつの間にか nvkind という名前になっていて、その紹介の LT。最初は kind に GPU サポートを追加しようとしていたけど、現状は難しくて nvkind という形になっているのでその背景と、今後 kind にネイティブに GPU サポートを追加するにはどうしたら良いかの議論。CI とかローカル開発とかで GPU が使える Kubernetes クラスタを手軽に作りたい要望は結構あると思う。登壇者の elezar さんは NVIDIA の人で GPU Operator とか NVIDIA の device plugin を開発していたり、Kubernetes の upstream でも CDI とか DRA 関連で見かける方。

Lightning Talk: Future-Proofing Kubernetes: Impact of Storage Version Migration and Meaning of Resource Version (RV) - Nilekh Chaudhari, Microsoft

最近開発が進んでいる KEP-4192: Move Storage Version Migrator in-tree の話を実装者から。Kubernetes API サーバが etcd に Kubernetes オブジェクトを保存する際に暗号化やストレージバージョンの変更によるスキーマの更新が行われる。ただし、これらはあくまで保存時の挙動なので、既存のオブジェクトに関しては変更がない限り暗号化もスキーマの更新も行われない。kubectl でオブジェクトを変更なしで更新 (kubectl get <resource> | kubectl replace -) して強制的に反映させるのがよくあるやり方。ただ、手動で実施が必要なので運用コストが高いのと大量のデータを含んでいるような Kubernetes オブジェクトでスループットに影響が出る (?) など問題がある。GKE や EKS などは恐らく kube-storage-version-migrator をコントロールプレーンで動かしていて、定期的に更新が必要なオブジェクトを特定して更新している。で、KEP-4192 はこの Storge Version Migrator を Kubernetes のコア機能に移動させるというもので、その辺りの内部の話をしてくれそう。マネージド Kubernetes だと気にしなくても良いけど自前運用の場合は考慮した方が良さそうなのと、この辺り詳しくないので聞いておきたい。

Lightning Talk: Safer Cluster Upgrades with Mixed Version Proxy - Richa Banker, Google

最近開発が進んでいる KEP-4020: Unknown Version Interoperability Proxy の話を実装者から。Kubernetes クラスタを更新する際に、コントロールプレーンを冗長化していると新旧のバージョンが同時に動作することになる。Kubernetes クラスタの更新中にクライアントがリクエストを送るとどのバージョンの API サーバがリクエストを受け取ったかによって利用可能なリソースに違いが出てくる。この問題を解決するために、API Server の Aggregation Layer に新しく仕組みを追加して、自分が処理できないリソースに対するリクエストを受け取った場合に他の処理可能な API サーバにプロキシする機能。セッションではこの辺りの実装の詳細や今後のロードマップについても話があるみたい。Kubernetes のマネージドサービスを利用していると気にする機会が少ない機能ではあるけど、Kubernetes API サーバにとっても大きな変更ではあってそろそろベータ昇格を目指しているようなのでキャッチアップしておきたい。

Unlocking Cost Savings & New Possibilities: Your Guide to Prometheus Remote Write 2.0 - Callum Styan, Grafana Labs & Bartłomiej Płotka, Google

Prometheus Remote Write v2 の話を実装者から。保存期間の短く設定された Prometheus から Thanos、Cortex や VictoriaMetrics などの長期保存用のストレージに書き込む場合や Prometheus を Agent モードで動かしてリモートにしかデータを保存しない場合に使うプロトコルで、v1 に比べて機能がいくつか追加されているのと、データの転送コストも最大で 60% 低減したらしい。仕様を眺めると、リモートにメトリクスを送る際に使う Protobuf のスキーマ定義が新しく追加されて、v1 の同等の Protobuf スキーマが非推奨化されている。データ圧縮に Snappy を利用している部分などは変わってなさそうだが、データ構造が最適化されている。特に String Interning を利用している点が転送コストの改善に繋がっていそう。メトリクスのラベルなど基本的に変更がない文字列を時系列データ毎にで何度もシリアライズしてパースするのは非効率。重複する文字列は 1 度処理したものを参照する形に置き換えることで、転送する Egress のデータ量や転送側と受信側両方の CPU、メモリ使用量なども大きく改善できる。新しいデータ構造は Exemplar もネイティブで対応しているみたい。セッションの中ではベンチマークの結果や他の方法との比較なども紹介される。

Automated Multi-Cloud, Multi-Flavor Kubernetes Cluster Upgrades Using Operators - Ziyuan Chen, Databricks

Databricks では EKS / AKS / GKE / セルフマネージド Kubernetes など 1000 以上のクラスタを動かしている。で、それらのクラスタを管理するために Kubernetes Operator を開発して、Node のベースイメージや Kubernetes のバージョンの更新、設定変更などを毎月行っている。Kubernetes Operator を使って無停止でクラスタを Blue / Green でローリング更新 (クラスタレベルの Blue / Green?) しており、PDB (クラスタを跨いで?) やクラスタ毎に設定されたメンテナンス時間を考慮したり、Node の drain を遅らせたり、ワークロード固有の処理を注入する仕組みなどがある。ロールバックも容易 (問題が起きたら自動でロールバックする訳ではない?) で、運用コストを最小限に抑えているとあるので、やっぱり手動オペレーションはある程度あるのかな。おかげで脆弱性の修正やインフラの設定変更の反映が素早く容易に行える。セッションでは controller-runtime を利用した Operator の開発を通しての学び (e.g. 宣言的な API の設計方法、マルチクラウドで一貫した動作をどう実現するか) を共有してくれるらしい。

Better Pod Availability: A Survey of the Many Ways to Manage Workload Disruptions - Zach Loafman, Google

Agones のメンテナの方によるセッション。Kubernetes における Pod の中断に関連するオプション (e.g. PDB や Cluster Autoscaler の safe-to-evict の annotation や terminationGracePeriodSeconds など) を正確に設定するのは難しい。Pod の中断に関わる Kubernetes 組み込みの機能の挙動と課題、Agones でどのように Pod の中断を処理しているかを紹介する。Agones では GameServer のカスタムリソースでこの辺りの挙動を良い感じに wrap しているのでその辺りの話をしてくれるみたい。Agones 自体はゲーム向けに作られているけど、過去に状態を持つバッチ処理に使おうとしている人がいたくらいだし、通常のアプリケーションの設定にも応用が効くと思う。

Platform Performance Optimization for AI - a Resource Management Perspective - Antti Kervinen, Intel & Dixita Narang, Google

Node 上のリソース管理が LLM のパフォーマンスにどの程度影響するか。パフォーマンスを最適化するために Node レベルでどういう設定が可能か。LLM のスループットとレイテンシの改善の間にどういったトレードオフがあるか。実例をもとにデータの収集から分析、可視化を含む LLM のパフォーマンス最適化の方法を教えてくれるらしい。例えば、PyTorch のアプリケーションのコードやコンテナイメージをいじらずに計装する方法や重いベンチマークを再実行せずに計測する対象を変える方法、パーセンタイルのような数値ではなく可視化することで何が得られるかなど。諸々調整することで Node 当たりの (LLM の文脈での) トークンのスループットが 3.5 倍に改善されたらしい。ndixita さんは Memory QoS とか最近だと KEP-2873: Pod Level Resources などの実装をやってる方。

From Observability to Performance - Nadia Pinaeva, Red Hat & Antonio Ojea, Google

今年のアントニオさんのセッション。Kubernetes における Service を介した通信の改善にどういうメトリクスを参考にしたら良いかの話。アプリケーションに影響するパラメータの紹介から Kubernetes クラスタ上に Prometheus や Grafana などのツールをインストールすることなくパフォーマンスを計測して分析する方法、パフォーマンスのボトルネックの特定や対処の方法などを紹介してくれる。クラスタ管理者以外にも SRE や DevOps 向けとあるからどのレベルの話をしてくれるか...。前に kube-proxy Subtleties: Debugging an Intermittent Connection Reset の Kubernetes ブログを称賛してたからこの辺りの話も出てきそうな予感

Deep Dive Into Generic Control Planes and Kcp - Stefan Schimanski, Upbound & Mangirdas Judeikis, Cast AI

Kubernetes に依存せずに Kubernetes API サーバの仕組みを利用して API ベースの SaaS サービスなどを構築できるようにする Generic Control Planes に関する話。Generic Control Planes の利用方法や Kubernetes のコア API 以外を拡張する方法、ConfigMap / Secrets などのコアリソースや ResourceQuota / RBAC をなどの仕組みを制御する方法などを紹介してくれる。kcp も含め Generic Control Planes の話はちょこちょこ出てくるし、Kubernetes の upstream にそれ用の PR が結構マージされたので現状を把握しておきたい。

Life of a Packet: Ambient Edition - John Howard, Solo.io & Keith Mattix, Microsoft

以前に Kubernetes の Pod 間や Service を介した通信に関する Life of a Packet の Istio Ambient Mesh 版。Istio のコアメンテナの John Howard さんいつの間にか Google 辞めて Solo.io の人になっている。

Watching the Watchers: How We Do Continuous Reliability at Grafana Labs - Nicole van der Hoeven, Grafana Labs

Grafana Labs の中で Grafana Cloud を構成する複雑なマイクロサービスを運用していて Grafana スタック (Mimir, Loki, ...) などをドッグフーディングしている。Mimir クラスタで 1.3 B のタイムシリーズを保持し、324 TB / day のログの書き込みに耐えるために Loki をどうスケールさせているか、Grafana Cloud を監視するための Grafana ダッシュボードの紹介など。登壇者が Grafana Labs の Developer Advocate なのでどの程度深い話をしてくれるのかは分からないけど面白そう

Squashing Trampoline Pods: The Future of Securely Enabling Hardware Extensions - Joe Betz, Google & David Eads, Red Hat

Node が掌握された時に別の Node に波及しないように守る必要がある。Node 単位で動作するエージェントを開発したり、運用する場合に Validating Admission Policy や Service Account Token Node Claims (KEP-4193: Bound service account token improvements) や KEP-4358: CRD Field SelectorKEP-4601: Authorize with Field and Label Selectors などの機能を利用してどう堅牢にできるかを紹介するセッション。DRA も参考にしていた demonstrate VAP restricting action per-node の話も出てきそう

Cooperative Scheduling for Stateful Systems - Michael Youssef & Zhantong Shang, LinkedIn

LinkedIn で基盤を Kubernetes クラスタに移行する際に StatefulSet の機能だと状態を持った重要なシステムを運用するのは難しいと感じ、LiStatefulSet のカスタムリソースを設計した。LiStatefulSet は Kubernetes の Node ではなく、ベアメタル上でワークロードを動かし、ApplicationClusterManager という内製 (?) のポリシーエンジンで安全性の確認 (ヘルスチェック?) やデプロイ方法をカスタマイズできるようにしている。ApplicationClusterManager で Kubernetes におけるワークロードのライフサイクル管理と協調が可能らしいが、概要だけ見てもよく分からないので気になる。

Kubernetes WG Device Management - Advancing K8s Support for GPUs - John Belamaric, Google; Patrick Ohly, Intel; Kevin Klues, NVIDIA

恒例の DRA の話。Kubernetes 1.32 でベータ昇格予定なのである程度デザインは固まってきたけど、DRA 関連の KEP が新たに生えてきたりでまだまだ混沌としている。

Tsubasa NagasawaTsubasa Nagasawa

2024/11/4

KubeCon NA 2024 の個人的に気になるセッション (前編)

Kubernetes Workspaces: Enhancing Multi-Tenancy with Intelligent Apiserver Proxying - James Munnelly & Andrea Tosatto, Apple

単一の Kubernetes クラスタ上にマルチテナント環境を構築すると、cluster-wide な List / Watch や複数の namespace に跨った RBAC などが利用できず、Kubernetes Operator の設定が複雑になる。結果として、Cluster-as-a-Service (KaaS) として提供した場合と比べて制約が多くなる。そのため、Kubernetes の API サーバのプロキシを開発して、workspace の概念 (名前は kcp から拝借) を導入して cluster-wide な処理をその workspace が操作を許可している複数 namespace に変換してリモートの Kubernetes クラスタに対して実行するようにしてみた。その辺りの話と Kubernetes にどういう変更や最適化を加えるとこのユースケースをより良くできるかの議論。vcluster とかとは違ったアプローチで興味がある。

Evolving Reddit’s Infrastructure via Principled Platform Abstractions - Karan Thukral & Harvey Xia, Reddit

Reddit のインフラ基盤は組織と共に成長していき、短期的で限定的な課題の解消が主だった。エンジニア組織が拡大していく中でインフラ基盤をスケールさせるにはプラットフォームの抽象化とサービスチームで面倒が見れるような標準化が必要。2021 年からインフラ基盤の再考が始まり、アプリ開発者とインフラエンジニアの両方にとって持続可能なシステムをインフラ基盤の上に構築できるようにする取り組みが始まった。人が介在するこれまでの非効率なインフラ管理から、サービスチームが自分たちで運用できる効率的なインフラ基盤への歩みを紹介する。Kubernetes を共通のコントロールプレーンとして利用し、よく設計されたインターフェイスを通して拡張することで個別の要件にも対応する。Reddit はめちゃくちゃ進んだことをしているイメージはないけど、堅実で現実的で参考になる話があるかも?

Solving the Kubernetes Networking API Rubik's Cube - Doug Smith & Surya Seetharaman, Red Hat; Shane Utt, Kong; Lior Lieberman, Google

KEP-4817: DRA: Resource Claim Status with possible standardized network interface dataKEP-4410: Kubernetes Network ReImagined (KNI) の話。AI / ML の文脈で DRA や KNI (KNI は特に話が進んでいないので正直あまり聞かない) のワードを聞いたことがあるかもしれないが、AI / ML 向けに最適化されたマルチネットワークや CNI にどう関わっているか。DRA は現状 GPU に関する話がメインだけど、一応ネットワークデバイスの動的割り当てについても議論 (e.g. Classic DRA のユースケースとして上がっていたり) がある。CNI は現状コンテナランタイム側の実装に埋まっていて Kubernetes の API としては標準化されていないので、KNI として標準化する動きがある。この辺りの話や何を目指しているのかを整理して、コントリビュータを増やして進めていきたいって感じか。

How the Tables Have Turned: Kubernetes Says Goodbye to Iptables - Casey Davenport, Tigera & Dan Winship, Red Hat

kube-proxy の nftables 対応と Calico の nftables ベースの NetworkPolicy の実装の話。Kubernetes における iptables 利用の歴史と現状、nftables を利用することで得られる機能やパフォーマンス改善、eBPF より nftables の方が良いのではと思う理由など。Dan さんが喋るので深い話が聞けて面白そう。

Distributed Cache Empowers AI/ML Workloads on Kubernetes Cluster - Yuichiro Ueno & Toru Komatsu, Preferred Networks, Inc.

PFN さんの分散キャッシュシステムの話。元のブログ記事から 1 年経っているし新しい話も聞けるかも

One Inventory to Rule Them All: Standardizing Multicluster Management - Corentin Debains, Google & Ryan Zhang, Microsoft

SIG-Multicluster が最近取り組んでいる KEP-4322: ClusterProfile の話。マルチクラスタ管理のツールはいくつか出てきているが、マルチクラスタ管理のツールやパターンは標準化されておらず、コミュニティからも標準化の声が上がっている。ClusterProfile API はマルチクラスタ管理のベースとなる機能で、クラスタの状態やクラスタが持つ機能 (e.g. GPU が使える) を公開できる仕組み。既存のマルチクラスタ管理のツールが ClusterProfile API のインターフェイスを基に実装することで、ユーザーはツール毎に異なる裏側の実装は気にせずに導入できる。セッションではマルチクラスタ管理の課題や ClusterProfile API の詳細、Kueue や Argo CD、Argo Workflows を利用した実例を紹介する。実例が気になる。

Exceeded Your Validation Cost Budget? Now What? - Joel Speed, Red Hat

CEL で複雑なバリデーションのルールを書くと実行時に掛かるコストを気にしないといけない。API サーバがオーバーロードしないように保護する仕組み。API サーバ側でルールの評価に掛かるコストが見積もられ、上限を超えると反映時にエラーになるので、ルールを見直す必要がある。セッションでは CEL の基本的な話から、コスト上限を超える単純なルールをもとに原因を突き止めて修正する方法を紹介する。CEL のルールのデバッグ方法とかちゃんと知らないので興味がある。

Which GPU Sharing Strategy Is Right for You? a Comprehensive Benchmark Study Using DRA - Kevin Klues & Yuan Chen, NVIDIA

klueska さんの DRA のセッション。GPU を共有する方法はいくつかある (MIG, MPS, TIme-slicing) ので、DRA を使ってそれぞれの方法がどういう時に適しているのかをベンチマークの結果とともに共有してくれる。将来的な改善の話や実際のアプリケーションを使ってのデモもある。

Understanding Kubernetes Networking in 30 Minutes - Ricardo Katz, Broadcom & James Strong, Isovalent at Cisco

Kubernetes のネットワークの基本的な話。pause コンテナが存在する理由や Pod 間通信がどう実現されているか、kube-proxy や CNI の重要性など。最近こういうセッションなかったと思うし、Kubernetes のネットワークは複雑なので初心者に良さそう。

Pod は CPU やメモリ以外に GPU やネットワークデバイスなどを利用できるようになってきているが、効率的にリソースを使用したり、複雑なデバイスの要件があると現状の Kubernetes ではエッジケースにハマることがある。SIG-Node の Chair / Tech Lead の 2 人が Kubernetes が抱えている課題と現在取り組んでいる改善について紹介するセッション。Sergey さんも喋るので KEP-4680: Add Resource Health Status to the Pod Status for Deveice Plugin and DRA の話もあるかな。

Serveless Computing の概念は 2016 年に本格的に普及し始め、2019 年にピークを迎えて下火になっていった。で、2022 年に再度浮上し始めて今も関心を集めている。デザインパターンとして Serverless が何を意味するのか、その後で利点や成功例を紹介し、特に Kubernetes における Serverless 技術の現状と未来について話す。WebAssembly は Kubernetes 上で Serverless を実現するためのランタイム技術であり、AWS Lambda や他の競合製品を上回るパフォーマンスを叩き出している。おそらく Why Serverless is Trending Again のブログ記事をベースにしたセッションで新しい話はなさそうだけど。

The Path to Helm 4 - Matt Farina, SUSE & Andrew Block, Red Hat

Helm 4 に向けた話。Helm は 2015 年に開発が始まって、Kubernetes と一緒に成熟してきた。Helm は世界中のコミュニティや組織で利用されており、安定性や効率性が重要。そのため、Helm 3 が 2019 年にリリースされてから 5 年間、セマンティックバージョンに従って CLI や API に破壊的変更を加えないように頑張ってきた。ただ、Kubernetes が進化を遂げる中で Helm が安定性を維持したまま機能を追加するのが難しくなっている。ある時点で破壊的変更を受け入れる必要が出てくる。こういった理由から Helm は将来のプロジェクトの方向性を決める Helm 4 の開発に着手している。セッションでは Helm の安定性を維持するための仕組みや対策、Helmが新しいメジャーバージョンに進む理由、Helm 4 の主な機能、Helm 4 リリース後の Helm 3 のサポートについて紹介する。Helm 4 の議論は KubeCon EU 2024 から始まっていて、The Road to Helm 4 のブログでも紹介され、HIP-0012: Helm 4 Development Process に現状の開発の流れやタイムラインがまとまっている。Helm 3 の開発に透明性がないと批判を受けて Helm 4 では透明性のためにこの HIP を作ったみたい。予定では 2024/11 の KubeCon NA でキックオフがあって、2025/8 にコードフリーズ、KubeCon NA 2025 で Helm 4 をお披露目。Helm 3 の EoL は Helm 4 のリリース後の 6-8 ヶ月後を予定。Helm 4 で破壊的変更を予定しているが、大部分は Helm 3 と互換性がある状態を維持し、移行手順などは準備する。Helm 3 で作成した Helm chart や Helm リリースは Helm 4 でも引き続き操作できるようにする予定。Helm CLI の破壊的変更に関しては慎重に判断する予定。

Pod Power: Liberating Kubernetes Users from Container Resource Micromanagement - Dixita Narang, Google & Peter Hunt, Red Hat

KEP-2837: Pod level resources の話。動的な世界である Kubernetes において効率的なリソース管理はパフォーマンスやコストの最適化にとって重要である。昔から Kubernetes ではコンテナ毎にリソース割り当てや上限を指定してきた。これにより細かい調整が可能ではあったが、複数コンテナを含む場合に手間となり、意図しない挙動となることがあった。セッションではコンテナレベルのリソース割り当ての課題について議論し、現在開発が進められている Pod レベルでリソース割り当てや上限を設定できる機能について紹介する。既存のコンテナレベルのリソース割り当てと併用することで Init Containers や Sidecar Containers を含んだ Pod のリソース割り当てを柔軟に設定でき、リソース使用量も最適化できる。Pod レベルで指定できることでリソース使用量が最適化できる理由とかすぐにはピンと来ないと思うので、発表の後の質問が多くなりそう。

Achieving and Maintaining a Healthy CI with Zero Test Flakes - Antonio Ojea, Michelle Shepardson & Benjamin Elder, Google

すごくニッチなセッションだけど、SIG-Testing による Kubernetes の CI で Flaky なテストを 0 にする取り組みについてのセッション。ソフトウェア開発が急速に進む中で、効率的に実行でき安定した CI のパイプラインは重要。Flaky なテストは遅れやストレスを生み、コードベースに対する信頼性を損ねる。セッションでは Kubernetes プロジェクトが Flaky なテストを無くすために取っている戦略、ベストプラクティス、ツール群を紹介する。Flaky なテストは 0 ではないけど、すぐに Issue 化されて関係者に連絡が行き、有志が根本原因を特定して Issue にまとめたり、修正の PR を投げたりするので仕組みは参考になると思う。

Upgrade Safely: Avoid the Pitfalls of Kubernetes Versioning - Rob Scott, Google

クラスタや controller を更新した後に壊れ、その原因が何らかのバージョンの不一致だったことはあるか?Ingress を v1 に更新した時みたいに新しい API バージョンに更新するときの苦しみを覚えているか?リリースノートで機能や API が非推奨になったのを見て心がざわついたことはないか?そういった経験のあるユーザー向けのセッションで、Kubernetes のバージョニングは思っているより複雑で勘違いされやすいので、ストレージバージョンから Feature Gates に至るまでバージョニングの概念について説明する。また、クラスタや controller を安全に更新する方法やバージョニングの理解が浅いことでクラスタが壊れたり、ダウンタイムが発生する例を紹介する。API や controller の実装者が今後このような変更を引き起こさないために何がきるかを議論する。Gateway API のプロジェクトを引っ張ってきた Rob Scott さんのセッションなのでその辺りの経験の話がメインかな?

Topology Aware Routing: Understanding the Tradeoffs - Rob Scott, Google

Kubernetes 1.31 でベータ昇格した KEP-4444: Traffic Distribution の話。Topology Aware Routing の3度目の正直の機能。過去の歴史と反省ってあるので、柔軟にし過ぎた問題と CPU コア数で補正を掛けてしまった問題も出てくるかな。Traffic Distribution の現在の実装と将来的にどう改善できるか、どういう場合に利用すべきでどういう場合に利用すべきでないかを例を交えながら紹介する。最後に Cluster Autoscaler や LB、Ingress / Gateway API、Multi-Cluster Service にどう影響するかも説明する。最後のは現状 Topology Aware Routing には PreferNode の機能しかなくて、最初の Service Topology の頃のように Node -> Zone -> Region -> All にフォールバックする仕組みはないよって話かな。

Tsubasa NagasawaTsubasa Nagasawa

2024/11/4

cgroup v2 の group oom kill の裏話

Linux コミュニティに cgroup の group oom kill の機能を提案したの Dawn Chen と Tim Hockin なんだ。Kubernetes が生まれる数年前に提案していたけど、実際に機能として入ったのは cgroup v2 の時。cgroup v1 の時代にメモリ使用量が上限を超えたプロセスだけが OOMKill される挙動に依存してアプリケーションが開発されてしまったので、時すでに遅しで cgroup v2 でもデフォルト有効になっていない (k/k#126096 (comment))

Tsubasa NagasawaTsubasa Nagasawa

2024/11/6

proxy/conntrack: reconciler

kube-proxy の iptables / ipvs / nftables どのモードでも動作する UDP conntrack reconciler の機能が Kubernetes 1.32 に入った。これまでは更新されたり削除された Service / Endpoint の情報をもとに conntrack テーブルの古い情報を削除していた。Kubernetes 1.32 から同様のイベントを検知した場合に conntrack テーブル内のエントリをダンプして、Endpoint が serving 状態でない (停止中の Pod が readinessProbe を通過していない = Pod 内のプロセスはリクエストを受け付けられない) 場合にのみエントリを削除する。例えば、conntrack エントリの中で DNAT 前の送信先の IP が Service の IP でリプライ時の送信元 IP (UDP サーバ) が serving 状態の Endpoint の一覧に含まれていない場合はエントリを削除するといった感じ。結構大きな変更だけど、FeatureGate などはなく実装が変わっているのでリグレッションが怖い。UDP 使っている人少ないし、そもそも現状でもエッジケースで壊れているから良いのかな

containerd 2.0.0 のリリース

release notes

Tsubasa NagasawaTsubasa Nagasawa

2024/11/7

Kubernetes 1.32 で DRA がベータ昇格

また議論があったみたいだけど、新規の Beta API を含む機能は API と FeatureGate の両方がデフォルトで無効。GKE の場合は、Beta API を有効化するフラグがあって有効化すると API と FeatureGate の両方が有効になる。FeatureGate に関しては GKE が判断した例外以外はデフォルトで有効になるが、Beta API を有効化する必要がある機能に関しては例外扱いっぽい。(k/k#127511 (comment))
EKS で同じことができない理由はないと軽く噛み付くアントニオさん (k/k#127511 (comment))

so this should not be a problem at least in the GKE side, but I don't see why EKS can not do the same

kubelet: new kubelet config option for disabling group oom kill

うたもくさんが引き継いで取り組んでいた kubelet の設定で cgroup v2 の group oom kill を無効化する PR が無事にマージされました。このままテストが Flaky にならなければ Kubernetes 1.32 で設定可能になります。

1 コンテナ内で複数のプロセスを起動しているパターン (e.g. Web Server の worker, JupyterLab などの実験環境) でプロセスがメモリ上限を超えて OOMKill される時に kubelet の cgroup v1 モードだとそのプロセスだけが殺されてましたが、kubelet の cgroup v2 モードだと cgroup 内のプロセスが全て殺される挙動になっていました。cgroup v2 から group oom kill の設定が追加され、Kubernetes 1.28 から kubelet はこれを問答無用で有効化するようになっていたので、cgroup v1 -> cgroup v2 に移行できないユーザーが出ていました。Google の人たちが Kubernetes 1.32 に必ず入れたいムーブをしていたので、顧客に移行できない人たちがいたんだと思います。PFN さんも Kubernetes にパッチを当てて group oom kill を無効化していると言っていたので、うたもくさんがお仕事で取り組んでいた感じです。

Tsubasa NagasawaTsubasa Nagasawa

2024/11/9

KEP-2837: Pod Level Resources

KEP-2837: Pod Level Resources もコードフリーズ後に滑り込みでマージされた。1.32 でアルファ機能として入る予定で、Pod レベルでリソース割り当てを指定する機能。Pod リソース、スケジューラー、QoS、cgroup の設定、oom_score_adj の計算方法、Limit Range、ResourceQuota、kubectl describe と幅広く変更が入るのでリグレッションが怖いけど、基本的に FeatureGate で守られているから大丈夫なはず。Pod とコンテナの requests / limits の組み合わせがかなり複雑に見えるけど、コンテナレベルの requests が設定されていて Pod レベルの requests が設定されていない場合は Pod レベルの requests にコンテナレベルの requests の値がデフォルト値で埋め込まれたり、基本的に requests のデフォルト値が埋められることがあるくらい

Tsubasa NagasawaTsubasa Nagasawa

2024/11/11

[FG:InPlacePodVerticalScaling] Handle edge cases around CPU MinShares

Kubernetes の Pod の CPU 要求で 1 core or 1000m を指定すると cpu.shres の値は 1024 に換算される。Pod の CPU 要求を 1m に設定すると cpu.shares の値は 2 に繰り上げられる。これは Linux カーネルが MinShares の値である 2 に繰り上げるから。In-place Pod Vertical Scaling が有効な場合、Pod status に実際に割り当てたリソースの情報を格納しており、1m で要求すると 2m の値が格納される。リソース要求した値と割り当てられた値に違いがあるので、Pod のリサイズの処理が延々と続いてしまう問題の修正。Pod のリソース要求で MinShares より小さい値が指定された場合は要求した CPU core 数と実際に割り当てられた CPU core 数が同じ値だと特別に解釈するように変更

Tsubasa NagasawaTsubasa Nagasawa

2024/11/13

Additional access check for exec into a Pod using WebSocket

kubectl 1.31 から kubectl exec / port-forward などを実行した時に API サーバとの通信が SPDY から WebSocket に置き換わったが、その影響で pods/exec の RBAC の挙動に変化が出た話。ブログ記事にあるように SPDY 時代だと pods/exec の create verb が許可されていないと権限エラーで Pod に exec できなかったが、WebSocket の場合は pods/execget verb の権限があれば exec できてしまう。RBAC の verb は HTTP メソッドをマッピングした上で
list / watch を拡張したもの。WebSocket の仕様上 GET メソッドでリクエストを投げないといけないため、get の verb で exec できてしまう。直感的には create の verb がないといけない感じがするが、仕様で決まっているので仕方ない。そもそも pods/exec の権限を渡さなければ良いだけだし、Kubernetes 側では変える気は無い感じ。RBAC 以外の方法で制限したいなら Admission Webhook で pods/exec のサブリソースに対する CONNECT の操作の時に拒否すると良い

VictoriaLogs v1.0.0

クラスタモードはまだ実装されていないけど、VictoriaLogs が v1.0.0 で GA している

Tsubasa NagasawaTsubasa Nagasawa

2024/11/14

[FG:InPlacePodVerticalScaling] Graduate to Beta

Kubernetes 1.32 で In-place Pod Vertical Scaling の機能がベータ昇格し、デフォルト有効になります。コードフリーズ後に例外申請が通って間に合った形です。resize subresource が追加されて Pod のリソース割り当てを変えられるようになってます。現状は QoS Class が変わるようなリソース割り当ての変更はできません。リサイズに時間がかかる問題など結構な数のバグ修正が入っていますが、Restartable Init containers がリサイズに対応していなかったり、いくつかの細かい機能は GA に先延ばしになったようです

Google Kubernetes Engine supports 65,000-node clusters | Google Cloud Blog

GKE は Kubernetes オブジェクトの KV ストアとして etcd をやめて Spanner を使うようになった。Google の人が KEP-4743: Kubernetes-etcd interface で etcd の安定性向上のために何かやっているなと思ってたら、そうじゃなくてこのためか

Tsubasa NagasawaTsubasa Nagasawa

2024/11/16

Watch one object by name?

考えたことがなかったけど、単一の Kubernetes オブジェクトを watch したい時は field selector で .metadata.name を指定してあげれば良いのか。watch で Kubernetes オブジェクトの特定のフィールドだけ監視するとかはできないから、キャッシュに入れる前に Transformer で不要なフィールドを落とすしかない

Tsubasa NagasawaTsubasa Nagasawa

2024/11/17

From Observability to Performance - Nadia Pinaeva, Red Hat & Antonio Ojea, Google

  • Kubernetes Service の仕組みの話が簡単にあって、そのあとでアントニオさんがよく引用している RFC-1925 のネットワークは光速を超えない話
  • Pod 間通信でパケットが通るユーザースペースとカーネルスペースのパス。iptables だろうが eBPF だろうが通るパスに違いはなくてパケットのフィルタリングや NAT などの処理を実行する場所と処理のパフォーマンスに違いがあるだけ。
  • ただ、eBPF だと近道があって全てのパスを通る必要はない。で、nftables も flowtables を使うと近道を通れる。ここで出てくる flowtables の話は現在アントニオさんが取り組んでいる PR の話
  • ネットワークのパフォーマンスの計測は難しい。綺麗な環境で現実的でないワークロードや設定の上でベンチマークを実行して計測することに意味はあるか?クラスタの中で起きている全ての出来事を計測できないので、ちゃんと SLI を定義して計測してみた。SLI は 4 つあって、データプレーン (e.g. kube-proxy) がネットワークの設定を更新するのに掛かるレイテンシ、クライアントがバックエンドに最初に送ったパケットのレイテンシ (クライアントがパケットを送った時間とサーバからの応答を受け取った時間の差)、クライアントがバックエンドに送った一連のパケットの処理に掛かった時間、データ転送のスループット。
  • 4 つの SLI の元となるメトリクスは netlink のソケットに繋いで conntrack が生成するイベントを監視してメトリクスを生成し、Prometheus 形式で公開。最初のパケットのレイテンシはパケットが conntrack テーブルに記録された時刻と SEEN_REPLY 状態に遷移した時の時刻の差。コネクションが終了するまでの時間 (一連のパケットの処理が終わるまでの時間) は最初に conntrack テーブルに記録された時刻と TCP_FIN 状態に遷移した時刻の差。スループットは正確ではないけどコネクションが終了するまでに送られた合計バイト数を時間で割ったもので代用。
  • iptables と nftables のパフォーマンス比較を行った。ベンチマークでは Service A と Service B を用意して、Service A に 100,000 個のダミーな Endpoint をぶら下げて、Service B に実際に Apache Beam (ab) で負荷を掛けるサーバを 1 台ぶら下げた。iptables はルールを更新する際に全てのルールを dump / save しないといけないのと、ルールを線形探索して一致するものを探すので性能が悪い予想をしていた。負荷を掛けてみると、iptables モードの場合に ab がタイムアウトし、nftables モードの場合はタイムアウトが発生せず、予想した通りの結果になっているように見えた。
  • 実際には確証バイアスが掛かった状態でベンチマークを実行していたため、ベンチマークの前提に問題があることに気付けていなかった。Service A の線形探索が終わってから Service B のルールの評価に進む想定だったが、kube-proxy の実装では Service 毎に chain があって、まずはそこで一致するかを見る。最初から Service にぶら下がっている Endpoint を全て線形探索する訳ではない。結果として、100,001 個のルールを見るのではなく、Service A と Service B のどちらかという 2 通りを見るだけのベンチマークとなっていた。
    • Dan さんから指摘されていたこと
  • じゃあ、iptables モードで ab がタイムアウトしていた理由は何か?kube-proxy の sync_proxy_rules_iptables_total のメトリクス (kube-proxy が作成した iptables のルールの数) を見てみると、一気にルールの数が跳ね上がっていて kube-proxy がすぐにルールを追加したように見えた。kube-proxy の sync_proxy_rules_duration_seconds のメトリクス (iptables のルールを同期するのに掛かる時間) を見ても最長でも 2 秒で悪くないように見える。ただ、kube-proxy の CPU 使用率のメトリクスを見てみると、20 分くらい 100% に張り付いていて実際にルールの同期にそれくらいの時間が掛かっていたようだった。じゃあ、最初の 2 つの kube-proxy のメトリクスは何を見ていたのか?kube-proxy は追加や削除の必要なルールをまとめて巨大なトランザクションとして iptables コマンドを実行する実装になっていて、最初のメトリクスはこのトランザクションが開始される直前までに積み上がったルールの数。2 つ目のメトリクスは積み上がったルールを同期するのに掛かった時間でルールを線形探索する時間 (20 分) は含まれていなかった。最終的に設定を反映するのに掛かる時間は nftables の場合 1 分 15 秒程度で、iptables の場合 20 分以上だった。確証バイアス良くない。
  • ベンチマークの方法を変えてもう少し正確に計測してみた。今度は Service の数を 5k, 10k, 30k と増やしつつ、ab を使って 10 個の worker で 1000 並列で 15k リクエストを投げた。iptables と nftables で最初のパケットの返答が返ってくるまでの時間はどちらが速いと思うか?nftables の方が速いと思うかもしれないが、現状の実装だと iptables の方が速い。全てのケースで nftables が速いと思い込んではいけない。これは kube-proxy の iptables モードに Dan さんが対象の Service の chain のルールだけを部分的に同期する機能を実装しているから。計測していた当時は nftables モードでまだ同等の機能がマージされておらず、毎回フルで全ての Service のルールを同期しているのでまだ遅い。Kubernetes 1.31 で既に nftables の部分的に同期する機能はマージ済み。この改善により 10k Service に 2 つずつ Endpoint をぶら下げて同期すると 25 分 -> 9 分に改善、この状態で 1 つ Service を追加して同期するのに掛かる時間は 8 分から 141 ms に大幅に改善。
  • 最初のパケットのレイテンシは iptables モードだと線形で増加していく予想だったが、なぜかレイテンシが低くなる結果に。これは conntrack のエントリが作成された時点のタイムスタンプだと思っていた nf_conntrack_tstamp が実は conntrack エントリが confirm() された時点でのタイムスタンプだったことによるもの。パケットのパスの中の Postrouting hook の conntrack の処理を通った時刻だった。要するに最初のパケットのレイテンシを正確に計測できていなかった。Linux カーネルの開発者に頼んで新しく Prerouting の conntrack を通った時点で記録するイベントを追加して貰って、その値を使って計測してみたら線形で増加する様子が確認できた。ab で測定したレイテンシのメトリクスと見比べても傾向は同じで線形に増加していたので、合っていそう。
  • コネクションが終了するまでの時間とスループットに関しても説明があったけどここまで
  • SLI / SLO についてはこの PR で SIG-Scalability がまとめていたドキュメントに追加されていて、kube-proxy のベンチマークが perf-tests に追加される予定らしい (kubernetes/community#8142)
  • flowtables を使うの KEP になってた (kubernetes/enhancements#4963)
Tsubasa NagasawaTsubasa Nagasawa

2024/11/19

kube-proxy nftables test are flaky

Kubernetes 1.31 でベータ昇格した kube-proxy の nftables モードの部分的な同期の処理でバグがあるっぽく、テストが Flaky になっている。まだ他で参照されている chain を消そうとしていて EBUSY のエラーになることがある。nftables のルールの中にある service-ips の map 型のデータ構造から Service IP のエントリが消えていて、Service の chain が残っているだけならパケットがその chain に到達するルートがないので影響はない。ただ、service-ips の map にエントリが残っていて同じ Service IP が再利用されると影響が出てしまう可能性がある。

EDIT: 影響ありそうで GA のブロッカーになった (k/k#128829 (comment))

Tsubasa NagasawaTsubasa Nagasawa

2024/11/20

Amazon EKS enhances Kubernetes control plane observability | Amazon Web Services

EKS の kube-scheduler と kube-controller-manager のメトリクスの一部がデフォルトで CloudWatch Metrics に保存されて、EKS コンソールから見れるようになる。Prometheus 形式で公開したエンドポイントも用意してくれていて、これは metrics-server と同じように Kubernetes の Aggregation Layer を実装して、API サーバに新しく kube-scheduler と kube-controller-manager のメトリクスを公開する API を生やしてそこから取得できるようにしてくれてる。スケジューラーの細かいメトリクスが見れるのは大規模なクラスタとかスケジュール効率気にする場合は良さそう