📝

Kubernetes 1.22: SIG-Node (kubelet) 変更内容

2021/09/01に公開

Kubernetes 1.22が先月リリースされました。
SIG-Node関連の変更をCHANGELOGからまとめています。
📝 の部分は、私のコメントです。

What's New

Kubernetesノードのスワップサポート

Kubernetes 1.22のリリースでは、スワップメモリを使用してノードを実行するためのアルファサポートが利用可能になりました。この変更により、管理者はLinuxノードでスワップを構成することを選択でき、ブロックストレージの一部を追加の仮想メモリとして扱います。

📝 メモ

KEP: https://github.com/kubernetes/enhancements/blob/master/keps/sig-node/2400-node-swap/README.md

ついにKubernetesでスワップが使えるようになりました。Podからスワップがどのように使われるかはSwapBehaviorという設定で決まります。

  • SwapBehaviorLimitedSwap(デフォルト)の場合
    • cgroups v1では、メモリとスワップの合計がresources.limits.memoryを超えないように制限される
    • cgroups v2では、スワップが使えない
      • これはcgroups v2では、メモリとスワップの上限設定が独立しており、メモリとスワップをあわせた量で制限できないため
  • SwapBehaviorUnlimitedSwapの場合
    • 制限なくスワップが使える(ホストシステムのスワップすべてを使える)

なお、今回のスワップサポートはノード単位の制御であり、Pod単位でスワップの利用をコントロールすることはできません。KEPによれば、BetaまでにPod単位でのスワップ量の制御をいれたいとのことです。

クラスター全体のseccompのデフォルト

新しいフィーチャーゲート(アルファ)SeccompDefaultが、対応するコマンドラインフラグ--seccomp-defaultおよびkubeletの設定とともにkubeletに追加されました。両方が有効になっている場合、seccompプロファイルを明示的に設定していないポッドのkubeletの動作が変わります。
クラスタ全体のseccompのデフォルトでは、kubeletはデフォルトで UnconfinedではなくRuntimeDefaultseccompプロファイルを使用します。これにより、Kubernetesデプロイメントのデフォルトのクラスター全体のワークロードセキュリティを強化できます。セキュリティ管理者は、ワークロードにデフォルトでseccompが設定され、より安心して眠れるようになります。

この機能の詳細については、公式のseccompチュートリアルを参照してください。

📝 メモ

KEP: https://github.com/kubernetes/enhancements/tree/34fa3dd/keps/sig-node/2413-seccomp-by-default

seccompはプロセスが呼べるシステムコールを制限するLinuxカーネルのセキュリティ機構です。このseccompプロファイルのデフォルトを設定できるようになりました。
seccompプロファイルにRuntimeDefaultを指定すると、コンテナランタイムのデフォルトプロファイルが使われるようになります。例えば、containerdの場合、デフォルトプロファイルはここで定義されており、capabilityの設定などに応じて動的に決定していることがわかります。

PSP (PodSecurityPolicy)でもデフォルトのseccompプロファイルの設定が可能ですが、PSPは廃止予定となっています。

メモリリソースのQoS

もともと、Kubernetesはcgroups v1 APIを使用していました。この設計では、PodのQoSクラスはCPUリソース(cpu_sharesなど)にのみ適用されます。 Kubernetes cgroup managerは、cgroups v1でmemory.limit_in_bytesを使用してコンテナーのメモリ容量を制限し、oom_scoresを使用して、メモリ不足イベントが発生した場合にコンテナープロセスを強制終了する順序を設定します。この実装には欠点があります。Guaranteed Podの場合、メモリを完全に予約できず、ページキャッシュがリサイクルされるリスクがあります。Burstable Podの場合、メモリをオーバーコミットする(requestlimit未満に設定する)と、Linuxカーネルがメモリ不足状態を検出したときにコンテナが強制終了されるリスクが高まります。

アルファ機能として、Kubernetes v1.22はcgroups v2 APIを使用してメモリの割り当てと分離を制御できます。この機能は、メモリリソースの競合がある場合に、ワークロードとノードの可用性を向上させるように設計されています。

📝 メモ

PR: https://github.com/kubernetes/kubernetes/pull/102970
KEP: https://github.com/kubernetes/enhancements/tree/master/keps/sig-node/2570-memory-qos
カーネルのcgroup v2ドキュメント: https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v2.html
cgroup v2を利用できる環境で、メモリリソースの柔軟な制御が可能になりました。
これまで、Kubernetesでのメモリリソースの制御はlimits.memoryの上限設定のみで、超えた際にOOMが発生するだけでした。これにはいくつかの問題がありました:

  • コンテナのメモリリクエストは完全にreserveされているわけではないので、page cacheがリサイクルされる可能性がある
  • メモリを使い果たしつつある時に頻繁にアロケーションレイテンシが発生する
  • メモリのオーバーコミットはスロットルされない
  • (Podではない)ノードリソースのメモリは完全には守られていない

これまでのメモリ上限(memory.max)に加え、cgroup v2
で追加されたmemory.high, memory.minの2つのパラメータを設定することで、これらの課題を解決しようとしています。

  • memory.high: メモリリソースのスロットル。この値よりメモリを使うと、プロセスはスロットルされ、メモリが回収されます(put under heavy reclaim pressure)
    • メモリを回収するとは、(dirtyなpage cacheを書き出して、)page cacheを開放したり、スワップアウトしたりすることを指している?
    • この値は、デフォルトではlimits.memory (node allocatable memory if no limit) * 0.8になります。すなわち、limits.memoryの8割を超えるとスロットルがかかるようになります。この係数0.8はMemoryThrottlingFactorというkubeletの設定で変更可能です。
  • memory.min: cgroupが常に維持すべきメモリ量を設定できます。例えば、システムがメモリが回収する必要があるときでも、memory.minで設定した分は維持されます。memory.minを適切に設定することで、ページキャッシュがリサイクルされないようにできます。
    • この値は、requests.memoryの値が設定されます。すなわち、requests == limitsのようなGuaranteed Podの場合、ページキャッシュがリサイクルされることはなくなります。

この機能はアルファのため、利用するにはMemoryQoSフィチャーゲートを有効にする必要があります。

既知の問題点

複数のコンテナを持つGuaranteed PodでCPUとメモリマネージャーが正しく機能していません

複数のコンテナーを持つGuaranteedポッドが、CPU、メモリ、およびデバイスマネージャーの設定された割り当てで正しく機能しないというリグレッションバグが見つかりました。修正は今後のリリースで利用可能になります

緊急アップグレードノート

アップグレード前に必ず読んでください

  • デフォルトのStreamingProxyRedirectsは無効になっています。マスターとノードの間に2以上のバージョンスキューがあり、古いノードが --redirect-container-streamingを有効にしていた場合、これはそれらを壊します。この場合でも、StreamingProxyRedirectsを手動で有効にすることができます。 (#101647@pacoxu

種類別の変更

非推奨

-PodUnknownフェーズは非推奨になりました。(#95286@SergeyKanzhelev

  • Dynamic Kubelet Configurationは非推奨になり、フラグ--dynamic-config-dirが使用されるとkubeletは警告を表示します。フィーチャーゲートDynamicKubeletConfigはデフォルトで無効になっているため、明示的に有効にする必要があります。(#102966@SergeyKanzhelev)[SIG Cloud Provider, Instrumentation and Node]

APIの変更

  • WindowsでHostProcessコンテナのアルファサポートを追加(#99576@marosset)[SIG API Machinery, Apps, Node, Testing, Windows]
  • 新しいkubeletのアルファ機能SeccompDefaultを追加しました。この機能により、Pod/コンテナのSecurityContextまたはPodのアノテーションで他に何も指定されていない場合に、RuntimeDefault(以前のruntime/default)seccompプロファイルにフォールバックできます。この機能を使用するには、フィーチャーゲートを有効にし、kubeletオプションSeccompDefault--seccomp-default)をtrueに設定します。(#101943, @saschagrunert)[SIG Node]
  • スワップのサポート(アルファ)は、NodeSwapEnabledフィーチャーフラグを使用してKubernetesノードで有効にできるようになりました。詳細については、KEP-2400を参照してください。(#102823@ehashman
  • エフェメラルコンテナで、ポッドとは異なる securityContextを設定できるようになりました。クラスター管理者は、クラスターでこの機能を有効にする前に、セキュリティポリシーコントローラーがEphemeralContainersをサポートしていることを確認する必要があります。(#99023@verb
  • cgroups v2(Alpha)によるメモリのQoSサポートの導入。MemoryQoS機能は現在アルファ版です。これにより、cgroups v2で実行されているkubeletは、コンテナ、Pod、およびQoSレベルでメモリQoSを設定して、より良いメモリ品質を保護および保証できます。この機能は、フィーチャーゲートMemory QoSを介して有効にできます。 (#102970@borgerli
  • NodeSwapEnabledフィーチャーフラグの名前がNodeSwapに変更されました
    このフラグは1.22.0-beta.1リリースでのみ使用可能であり、今後は新しいフラグを使用する必要があります。(#103553@ehashman)[SIG Node]

Feature

  • system-cluster-critical Podは低いOOMスコアを取得するべきではありません。

    現在のところ、system-node-criticalポッドとsystem-cluster-criticalポッドの両方のOOMスコアは-997であり、OOMKilledされる最後のプロセスの1つになっています。定義上、ノードがリソース不足であり、system-node-critical Podを再スケジュールできない場合でも、system-cluster-critical Podを他の場所でスケジュールできます。これが、system-node-criticalsystem-cluster-criticalよりも高い優先度値を持つ理由です。この変更により、system-node-critical優先度クラスのみが低いOOMScoreを持つことができます。

    必要なアクション
    ユーザーがPodを最後にOOMKilledにする必要があり、Podがsystem-cluster-criticalプライオリティクラスの場合は、既存の動作を維持するためにsystem-node-criticalプライオリティクラスに変更する必要があります(#99729@ravisantoshgudimetla

    • 📝 system-cluster-criticalはクラスタ全体で動くPodにつかうプライオリティクラスなので、Preemptされても他のノードで動く余地があるのに対し、system-node-criticalはそのノードで動く必要があるため、system-node-criticalを優先するという変更です。
  • cgroup v2をサポートするために、CRIにunified mapを追加します。 https://github.com/opencontainers/runtime-spec/blob/master/config-linux.md#unified を参照してください。 (#102578@payall4u

  • ユーザー名前空間でkubeletを実行するためのサポートを有効にするフィーチャーゲートKubeletInUserNamespaceを追加します。

    kubeletを実行する前に、ユーザー名前空間を作成する必要があります。
    CRIなどのすべてのノードコンポーネントは、同じユーザー名前空間で実行されている必要があります。

    フィーチャーゲートが有効になっている場合、kubeletは次のsysctl値の設定中に発生するエラーを無視します: vm.overcommit_memory vm.panic_on_oomkernel.panic kernel.panic_on_oopskernel.keys.root_maxkeyskernel.keys.root_maxbytes(これらのsysctl値は、コンテナーではなく、ホスト用です)

    kubeletは、/dev/kmsgを開く際のエラーも無視します。
    このフィーチャーゲートにより、kube-proxyはRLIMIT_NOFILEの設定中にエラーを無視することもできます。

    このフィーチャーゲートは、ルートレスDocker / Podman内でkindまたはminikubeを使用してKubernetesを実行する場合に特に便利です。(#92863@AkihiroSuda)[SIG Network, Node and Testing]

  • net.ipv4.ip_unprivileged_port_startを安全なsysctlとして扱います。(#103326@pacoxu

  • メモリマネージャ機能はベータ版に移行し、デフォルトで有効になっています。(#101947@cynepco3hahue

  • メモリ上のEmptyDirボリュームは、ホスト上のポッド割り当て可能メモリと、オプションの明示的なユーザー指定値の小さい方がサイズの上限として設定されます。 (#101048, @dims)
    - HugePageStorageMediumSize機能はGAに移行し、無条件に有効になります。コンテナレベルで複数のサイズのHuge Pageリソースを無条件に使用できるようにします。 (#99144, @bart0sh)

  • SetHostnameAsFQDNはGAに移行するため、無条件に無効になります。 (#101294, @javidiaz)

  • PodリソースAPIは、メモリマネージャフィーチャーゲートが有効で、メモリマネージャーポリシーが静的である場合に、メモリマネージャメトリックを提供します。 (#101030, @cynepco3hahue)

Bug or Regression

  • DBusの再起動後でもGracefulNodeShutdownが動くようにします( (#100369, @wzshiming)
  • execプローブが timeoutSecondsよりも長くかかる場合に、dockershimでもExecProbeTimeout=falsekubeletフィーチャーゲートが考慮されるようにします。 (#100200, @jackfrancis)
  • Podの起動時またはシャットダウン時のkubeletの競合状態を修正します。これにより、Podのシャットダウンに時間がかかる場合があります。 (#102344, @smarterclayton) [SIG Apps, Node, Storage and Testing]
  • systemd cgroupドライバーを使用する場合のリソースの制御を修正しました (#102147, @kolyshkin)
  • PostStartフックエラーのランタイムコンテナステータスを修正しました。 (#100608, @pacoxu)
  • タイムアウトしたポートフォワードストリームでkubeletがパニックする問題を修正しました。 (#102489, @saschagrunert)
  • 長時間実行され、頻繁に使用される接続の「ポートフォワード」メモリリークが修正されました。 (#99839, @saschagrunert)
  • コンテナの最初の再起動後に startupProbeが機能しなくなるバグを修正しました。 (#101093, @wzshiming)
  • 複数のPodを削除するときに、Graceful terminationが動作するようになりました。 (#100101, @deads2k)
  • Kubelet:ノードリストと kube-apiserverの同期を待機するときのパフォーマンスを改善します。 (#99336, @neolit123)
  • Kubelet:PodIPの戻り値は、Downward APIと pod.status.PodIPsフィールドで同じになりました (#103307, @aojea)
  • cpusetのパースで、"1--3"や"10-6"などの無効な入力が正しく検出されるようになりました。 (#100565, @lack)
  • 以前にRunningだったことがkubeletに認識されているポッドは、Pendingに戻らないようにする必要があります。kubeletは終了を推測します。 (#102821, @ehashman)
  • imagefs.minReclaimが設定されているときにKubeletが DiskPressureでスタックするのを防ぎます (#99095, @maxlaverse)
  • AppArmorホストバリデーションから/sbin/apparmor_parserのチェックを削除しました。
    これにより、バイナリを別のパスに置くディストリビューションでAppArmorを使用できます。 (#97968, @saschagrunert) [SIG Node and Testing]
  • フェーズも変更されない限り、Podステータスのreasonフィールドとmessageフィールドはリセットされなくなりました。 (#103785, @smarterclayton) [SIG Node]
  • Graceful Node Shutdown Podの終了理由とメッセージを更新しました。
    Graceful Node Shutdown Podの拒否理由とメッセージを更新しました。 (#102840, @Kissy)

Other (Cleanup or Flake)

  • 非推奨期間の後、Kubeletの --chaos-chanceフラグが削除されました。 (#101057, @wangyysde) [SIG Node]
  • 非推奨のrunAsGroupフィーチャーゲートは削除されました。これは、runAsGroup機能が1.21でGAに移行したためです。 (#101581, @carlory)

Discussion