Pod の sysctl でエラー: net.netfilter.nf_conntrack_max を Kubernetes 環境で扱うポイント

sysctl -w net.netfilter.nf_conntrack_max=262000 を Pod の initContainer で実行したらエラーになった。

sysctl: error setting key 'net.netfilter.nf_conntrack_max': Permission denied

同じ net.* でも、net.core.somaxconn はエラーにならない。

https://kubernetes.io/docs/tasks/administer-cluster/sysctl-cluster に原因が書かれているのだが、なかなか読み解くのに時間がかかったので、簡単にまとめておく。

結論

net.netfilter.nf_conntrack_maxnode-level sysctls に分類される特殊なパラメーターで、 Node 上で直接設定するか、DaemonSet を利用する必要がある。

sysctl を Kubernetes で使うには

基本ルール

  • sysctl インターフェースを使えば、カーネルパラメーターを変更できる。Kubernetes では、Pod から変更可能なパラメーターとそうでないものがある。
  • Kubernetes はこれらのカーネルパラメーターを以下の2つの軸で分類している
    1. safe / unsafe
      • Kubernetes が「安全」と判断したパラメーターのみ、Pod から変更可能
      • unsafe な sysctl パラメーターを変更したい場合、allowed-unsafe-sysctls フラグで明示的に許可を与える必要がある
    2. namespaced / unnamespaced
      • namespaced: Pod 内でスコープが閉じる(他のPodに影響しない)。
      • unnamespaced: Node 全体に影響を与えるため、node-level sysctls と呼ばれ、Pod からの変更はできない。

なぜ net.netfilter.nf_conntrack_max は変更できないのか?

  • net.netfilter.nf_conntrack_maxnode-level sysctls に分類されていて、Node 全体で共有されるパラメーターなので、Pod から変更できない。

読み解くのが難しかった記述

Kubernetes ドキュメントには以下の記述がある:

The following sysctls are known to be namespaced.

Those net.* that can be set in container networking namespace. However, there are exceptions (e.g., net.netfilter.nf_conntrack_max and net.netfilter.nf_conntrack_expect_max can be set in container networking namespace but are unnamespaced before Linux 5.12.2).

最初、ここの意味がわからなかったので変更経緯を見た。 この記述を最初に読んだとき、「namespaced に見えるけど実際は違う」 という部分が直感的に理解しにくかったので、Linux カーネルの変更履歴を確認した。

Linux 5.12.2 より前

  • net.netfilter.nf_conntrack_max にはバグがあり、Pod からは変更できるが、Node 全体に影響を与える unnamespaced な挙動をしていた。
  • この挙動を修正するために パッチ が適用された。

Linux 5.12.2 以降

  • このパッチにより、net.netfilter.nf_conntrack_max は Pod から変更できなくなり、一貫した unnamespaced パラメーターとして扱われるようになった。
  • 結果、現在の環境では、Pod から操作しようとするとエラーになる

ドキュメントが間違っているわけではないけど、もう少し言葉を足してもいいかなと思うのでした。終わり。