はじめに
kubeletの--protect-kernel-defaults
をいじっていたときにいろいろみたことのまとめです。
事の起こり
- kubeadmで構築したKubernetesクラスタを対象にKubernetes CIS Benchmarkの確認中、下記項目を見つける。
- 4.2.6 Ensure that the --protect-kernel-defaults argument is set to true
- とりあえず
--protect-kernel-defaults
をtrue
にして起動してみたが、kubelet自体がエラーで立ち上がらない。 - kernel tuningすればよさそうだが、ドキュメントにどれ直せばよいかがなかったのでソース読んで調べてみることに
--protect-kernel-defaultsとは
動きは下記
-
false
- kubelet起動時にkernelパラメータの変更処理を行う。
-
true
- kubelet起動時にkernelパラメータのチェックを行い、想定と異なっていた際はエラーを出力して終了
「じゃあkubeletが想定するパラメータってなんじゃい」というのが調査対象です。
調査
setupNode
とりあえずProtectKernelDefaults
で検索。
それっぽい部分が見つかりました。
func (cm *containerManagerImpl) setupNode(activePods ActivePodsFunc) error {
f, err := validateSystemRequirements(cm.mountUtil)
if err != nil {
return err
}
if !f.cpuHardcapping {
cm.status.SoftRequirements = fmt.Errorf("CPU hardcapping unsupported")
}
b := KernelTunableModify
if cm.GetNodeConfig().ProtectKernelDefaults {
b = KernelTunableError
}
if err := setupKernelTunables(b); err != nil {
return err
}
setupKernelTunables
にもぐってみます。
setupKernelTunables
func setupKernelTunables(option KernelTunableBehavior) error {
desiredState := map[string]int{
utilsysctl.VMOvercommitMemory: utilsysctl.VMOvercommitMemoryAlways,
utilsysctl.VMPanicOnOOM: utilsysctl.VMPanicOnOOMInvokeOOMKiller,
utilsysctl.KernelPanic: utilsysctl.KernelPanicRebootTimeout,
utilsysctl.KernelPanicOnOops: utilsysctl.KernelPanicOnOopsAlways,
utilsysctl.RootMaxKeys: utilsysctl.RootMaxKeysSetting,
utilsysctl.RootMaxBytes: utilsysctl.RootMaxBytesSetting,
}
sysctl := utilsysctl.New()
errList := []error{}
for flag, expectedValue := range desiredState {
val, err := sysctl.GetSysctl(flag)
if err != nil {
errList = append(errList, err)
continue
}
if val == expectedValue {
continue
}
switch option {
case KernelTunableError:
errList = append(errList, fmt.Errorf("invalid kernel flag: %v, expected value: %v, actual value: %v", flag, expectedValue, val))
case KernelTunableWarn:
klog.V(2).Infof("Invalid kernel flag: %v, expected value: %v, actual value: %v", flag, expectedValue, val)
case KernelTunableModify:
klog.V(2).Infof("Updating kernel flag: %v, expected value: %v, actual value: %v", flag, expectedValue, val)
err = sysctl.SetSysctl(flag, expectedValue)
if err != nil {
errList = append(errList, err)
}
}
}
return utilerrors.NewAggregate(errList)
}
desiredState
の項目についてsysctl.GetSysctl
で取得した値とを比較して同じであればcontinue
、異なっていたらエラーを返しているようです。
utilsysctl
ありました。このパラメータ通りにkernel tuningをしたうえで--protect-kernel-defaults
をtrue
にすれば良いでしょう。
const (
sysctlBase = "/proc/sys"
// VMOvercommitMemory refers to the sysctl variable responsible for defining
// the memory over-commit policy used by kernel.
VMOvercommitMemory = "vm/overcommit_memory"
// VMPanicOnOOM refers to the sysctl variable responsible for defining
// the OOM behavior used by kernel.
VMPanicOnOOM = "vm/panic_on_oom"
// KernelPanic refers to the sysctl variable responsible for defining
// the timeout after a panic for the kernel to reboot.
KernelPanic = "kernel/panic"
// KernelPanicOnOops refers to the sysctl variable responsible for defining
// the kernel behavior when an oops or BUG is encountered.
KernelPanicOnOops = "kernel/panic_on_oops"
// RootMaxKeys refers to the sysctl variable responsible for defining
// the maximum number of keys that the root user (UID 0 in the root user namespace) may own.
RootMaxKeys = "kernel/keys/root_maxkeys"
// RootMaxBytes refers to the sysctl variable responsible for defining
// the maximum number of bytes of data that the root user (UID 0 in the root user namespace)
// can hold in the payloads of the keys owned by root.
RootMaxBytes = "kernel/keys/root_maxbytes"
// VMOvercommitMemoryAlways represents that kernel performs no memory over-commit handling.
VMOvercommitMemoryAlways = 1
// VMPanicOnOOMInvokeOOMKiller represents that kernel calls the oom_killer function when OOM occurs.
VMPanicOnOOMInvokeOOMKiller = 0
// KernelPanicOnOopsAlways represents that kernel panics on kernel oops.
KernelPanicOnOopsAlways = 1
// KernelPanicRebootTimeout is the timeout seconds after a panic for the kernel to reboot.
KernelPanicRebootTimeout = 10
// RootMaxKeysSetting is the maximum number of keys that the root user (UID 0 in the root user namespace) may own.
// Needed since docker creates a new key per container.
RootMaxKeysSetting = 1000000
// RootMaxBytesSetting is the maximum number of bytes of data that the root user (UID 0 in the root user namespace)
// can hold in the payloads of the keys owned by root.
// Allocate 25 bytes per key * number of MaxKeys.
RootMaxBytesSetting = RootMaxKeysSetting * 25
)
パラメータ | kubeletを動かす上で必要な値 |
---|---|
vm/overcommit_memory | 1 |
vm/panic_on_oom | 0 |
kernel/panic | 1 |
kernel/panic_on_oops | 10 |
kernel/keys/root_maxkeys | 1000000 |
kernel/keys/root_maxbytes | root_max_keys * 25 |
まとめ
マネージドK8sはこのあたりを気にする必要がないので良いですね。
おまけ
cat > /etc/sysctl.d/90-kubelet.conf << EOF
vm.overcommit_memory=1
kernel.panic=10
kernel.panic_on_oops=1
EOF
sysctl -p /etc/sysctl.d/90-kubelet.conf
上記ではovercommit_memory
/panic
/panic_on_oops
を修正すればいいよとのことですが。
調べた結果と比べるとpanic_on_oom
/root_maxkeys
/root_maxbytes
については言及がない様子。
気になったのでこれについても調べてみたところ、どうやらkubeletの要求値とデフォルトが一緒だから問題になっていなかったようです。
https://www.kernel.org/doc/Documentation/sysctl/vm.txt
https://www.man7.org/linux/man-pages/man7/keyrings.7.html