Podのカーネルパラメータ(sysctl)を変更する方法について調べたまとめ。ICP v3.1.0で確認。
大きくは以下の方法がある。
- PodのsecurityContextで設定
- Init Containerで設定
カーネルパラメータについて
上記のドキュメントによると以下とのこと。
-
sysctl
にはnamespaced
なものとそうでないものがある- Pod毎に
sysctl
を設定できるのはnamespaced
なもののみ -
namespaced sysctl
ではないものはnode-level sysctl
という
- Pod毎に
-
namespaced sysctl
にはsafe
なものとunsafe
なものがある- 大部分は必ずしも
safe
とは考えられず、safe sysctl
は今のところ以下のみkernel.shm_rmid_forced
net.ipv4.ip_local_port_range
-
net.ipv4.tcp_syncookies
(kernel version 4.4以下ではnamespaced
ではない)
- 大部分は必ずしも
知られているnamespaced sysctl
のリストは以下だがLinux Kernelのバージョンアップにより変わる可能性がある。
- kernel.shm*,
- kernel.msg*,
- kernel.sem,
- fs.mqueue.*,
- net.*.
あるいはコンテナの中の/proc/sys
以下にファイルがあるかでもnamespaced
かどうかは確認できるかもしれない。net.core.somaxconn
はnamespaced
でありファイルがある。ホストOSでカーネルパラメータを変更してもPodのカーネルパラメータはそれとは別になる。
ubuntu@icp31-single:~/workspace/helm-study$ kubectl get po
NAME READY STATUS RESTARTS AGE
test-liberty-7d8f7497b9-cs5mn 1/1 Running 0 1m
test-liberty-7d8f7497b9-ctlqs 1/1 Running 0 1m
test-mysql-cfc8c8c86-9rv7b 1/1 Running 2 9d
test-mysql-init-7hbzf 0/1 Completed 1 9d
ubuntu@icp31-single:~/workspace/helm-study$ cat /proc/sys/net/core/somaxconn
256
ubuntu@icp31-single:~/workspace/helm-study$ kubectl exec -it test-liberty-7d8f7497b9-cs5mn -- cat /proc/sys/net/core/somaxconn
128
ubuntu@icp31-single:~/workspace/helm-study$
以下ではnet.core.somaxconn
を512
に変更する方法を試す。
PodのsecurityContextで設定
上記のドキュメントに記載されている方法で、以下のようにPodのspec.securityContext.sysctls
で設定できる。ただし、IBM Cloud Private 3.1のようにPodSecurityPolicyのAdmissionControlが有効な場合、PodSecurityPolicyを適切に設定する必要がある。紛らわしいが、PodのsecurityContextとPodSecurityPolicyは別の設定であるので注意。
spec:
securityContext:
sysctls:
- name: net.core.somaxconn
value: "512"
PodSecurityPolicyのAdmissionControlの有効化(Minikube)
Minikubeの場合はデフォルトの状態ではPodSecurityPolicyのAdmissionControlは設定されていないためPodSecurityPolicyの設定は不要。AdmissionControlはAPI Serverの設定で有効にすることができる。Minikubeのバージョンにより与えるべき引数が異なるかもしれないので注意。
minikube start --extra-config=apiserver.enable-admission-plugins=Initializers,NamespaceLifecycle,LimitRanger,ServiceAccount,DefaultStorageClass,DefaultTolerationSeconds,NodeRestriction,MutatingAdmissionWebhook,ValidatingAdmissionWebhook,ResourceQuota,PodSecurityPolicy
-
/etc/kubernetes/manifests/kube-apiserver.yaml
でデフォルトAPI Serverの--enable-admission-plugins
の設定値を確認し、PodSecurityPolicy
を追加
PodSecurityPolicyの作成
ICP v3.1.0ではデフォルトでdefault
とprivileged
の2つのPodSecurityPolicyがあり、それらを利用可能にしているClusterRoleがそれぞれあり、それらをバインディングしているClusterRoleBindingがある。
(補足)
ICP v3.1.1ではibm-restricted-psp
やibm-restricted-psp
などのPodSecurityPolicyに変わっている。
ubuntu@icp31-single:~$ kubectl get psp
NAME PRIV CAPS SELINUX RUNASUSER FSGROUP SUPGROUP READONLYROOTFS VOLUMES
default false RunAsAny RunAsAny RunAsAny RunAsAny false *
privileged true * RunAsAny RunAsAny RunAsAny RunAsAny false *
ubuntu@icp31-single:~$ kubectl get clusterrole default privileged
NAME AGE
default 24d
privileged 24d
ubuntu@icp31-single:~$
ubuntu@icp31-single:~$ kubectl get clusterrolebinding | grep psp
default-psp-users 24d
privileged-psp-users 24d
ubuntu@icp31-single:~$
今回はallowedUnsafeSysctls
の設定を追加したPodSecurityPolicyを新たに作成する。default
のPodSecurityPolicyで設定されていた内容に追加する形で作成する。
apiVersion: policy/v1beta1
kind: PodSecurityPolicy
metadata:
name: somaxconn-psp
spec:
spec:
allowPrivilegeEscalation: true
fsGroup:
rule: RunAsAny
runAsUser:
rule: RunAsAny
seLinux:
rule: RunAsAny
supplementalGroups:
rule: RunAsAny
volumes:
- '*'
allowedUnsafeSysctls:
- net.core.somaxconn
kubectl apply -f somaxconn-psp.yaml
ClusterRoleの作成
作成したPodSecurityPolicyを利用可能なClusterRoleを作成する。
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: somaxconn-clusterrole
rules:
- apiGroups:
- extensions
resourceNames:
- somaxconn-psp
resources:
- podsecuritypolicies
verbs:
- use
kubectl apply -f somaxconn-clusterrole.yaml
ClusterRoleBindingの作成
ClusterRoleをバインドする先のServiceAccountを作成する。今回はsugi
というNamespaceにpsp-user
というServiceAccountを作成する。
kubectl create sa psp-user -n sugi
ClusterRoleを作成したServiceAccountにバインドするClusterRoleBindingを作成する。
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: somaxconn-clusterrolebinding
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: somaxconn-clusterrole
subjects:
- kind: ServiceAccount
name: psp-user
namespace: sugi
kubectl apply -f somaxconn-clusterrolebinding.yaml
もしNamespaceの全てのServiceAccountにバインドする場合は以下のようにする。
subjects:
- apiGroup: rbac.authorization.k8s.io
kind: Group
name: system:serviceaccounts:sugi
その他、バインドの設定例は以下のドキュメントを参照。
デプロイテスト
ここまでの設定で一応Podがスケジュールされるようになる。PodSecurityPolicyの設定が適切でない場合は、PodがPending
等になるわけではなく、そもそそもスケジュールされないことに注意。
PodのSpecでserviceAccountName
を指定した以下のマニフェストを適用する。
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: liberty
name: liberty
spec:
replicas: 1
selector:
matchLabels:
app: liberty
template:
metadata:
labels:
app: liberty
spec:
serviceAccountName: psp-user
securityContext:
sysctls:
- name: net.core.somaxconn
value: "512"
containers:
- name: websphere-liberty
image: websphere-liberty
kubectl apply -f liberty.yaml -n sugi
しかしこれを適用すると以下のようにSysctlForbidden
となってしまう。Kubeletがsysctlを許可していないため。
ubuntu@icp31-single:~$ kubectl get po
NAME READY STATUS RESTARTS AGE
liberty-655cdb8456-66llz 0/1 SysctlForbidden 0 5s
liberty-655cdb8456-8frdd 0/1 SysctlForbidden 0 2s
liberty-655cdb8456-cszcm 0/1 SysctlForbidden 0 4s
liberty-655cdb8456-d9c2n 0/1 SysctlForbidden 0 5s
liberty-655cdb8456-h4d6t 0/1 SysctlForbidden 0 5s
liberty-655cdb8456-hbwn6 0/1 SysctlForbidden 0 2s
liberty-655cdb8456-hgzjj 0/1 Pending 0 1s
liberty-655cdb8456-k7262 0/1 SysctlForbidden 0 5s
liberty-655cdb8456-knfxs 0/1 SysctlForbidden 0 3s
liberty-655cdb8456-mmmgj 0/1 SysctlForbidden 0 3s
liberty-655cdb8456-qgzpc 0/1 SysctlForbidden 0 4s
liberty-655cdb8456-t527w 0/1 SysctlForbidden 0 4s
liberty-655cdb8456-tnq6x 0/1 SysctlForbidden 0 5s
liberty-655cdb8456-vtbxt 0/1 SysctlForbidden 0 2s
ubuntu@icp31-single:~$
Kubeletの設定変更
securityContextでunsafe sysctls
を設定したPodを起動するには各ノードのKubeletの設定で許可をする必要がある。Kubeletの起動オプションを変更する。
ICPの場合は各ノードのKubeletのSystemdユニットファイル/etc/systemd/system/kubelet.service
に--allowed-unsafe-sysctls=net.core.somaxconn
を追加し、デーモンを再起動する。
[Unit]
Description=Kubelet Service
Documentation=https://github.com/kubernetes/kubernetes
[Service]
EnvironmentFile=-/etc/environment
ExecStart=/opt/kubernetes/hyperkube kubelet \
--cadvisor-port=0 \
--docker-disable-shared-pid \
--bootstrap-kubeconfig=/etc/cfc/kubelet/kubelet-bootstrap-config \
--kubeconfig=/etc/cfc/kubelet/kubelet-config \
--cert-dir=/etc/cfc/kubelet \
--config=/etc/cfc/kubelet/kubelet-service-config \
--dynamic-config-dir=/etc/cfc/kubelet/kubelet-dynamic-config \
--network-plugin=cni \
--hostname-override=10.0.0.142 \
--node-ip=10.0.0.142 \
--pod-infra-container-image=ibmcom/pause:3.1 \
--node-labels=role=master,master=true,node-role.kubernetes.io/master=true,proxy=true,node-role.kubernetes.io/proxy=true,node-role.kubernetes.io/worker=true,etcd=true,node-role.kubernetes.io/etcd=true,management=true,node-role.kubernetes.io/management=true, \
--register-with-taints= \
--keep-terminated-pod-volumes=false \
--allowed-unsafe-sysctls=net.core.somaxconn
Restart=always
RestartSec=10
[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl stop kubelet
sudo systemctl start kubelet
稼働確認
これでデプロイすればPodがちゃんと稼働して、カーネルパラメータが変更されていることが確認できる。
kubectl apply -f liberty.yaml
$ kubectl exec -it liberty-655cdb8456-gbg9d -- cat /proc/sys/net/core/somaxconn
512
$
Init Containerで設定
以下のようにICPのNginx Ingress Controllerのマニフェストを確認すると、Init Containerを使ってパラメータを変更している。Pod内でカーネルパラメータは共通であり、Init Containerでの変更が実際のContainerでも引き継がれるようだ。
$ kubectl get ds -n kube-system nginx-ingress-controller -o yaml --export
apiVersion: extensions/v1beta1
kind: DaemonSet
(省略)
initContainers:
- command:
- sh
- -c
- sysctl -w net.core.somaxconn=32768; sysctl -w net.ipv4.ip_local_port_range="32768
65535"
image: ibmcom/defaultbackend:1.2.1
imagePullPolicy: IfNotPresent
name: sysctl
resources: {}
securityContext:
privileged: true
(省略)
この方法の場合、Kubeletの設定変更は不要だが、Init Containerでsysctl
コマンドを実行するためprivileged: true
を設定しているため、(PodSecurityPolicyが有効な環境では)PodSecurityPolicyの設定は必要。privileged: true
なのはInit Containerだけで、実際のコンテナは普通の権限で動作する。
PodSecurityPolicy
今回はICP v3.1.0のデフォルトで存在するprivileged
というPodSecurityPolicyが利用可能なprivileged
というClusterRoleを、sugi
というNamespaceのdefault
というServiceAccount(特に指定しない場合にPodに設定されるServiceAccount)にバインドする。
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: privileged-clusterrolebinding
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: privileged
subjects:
- kind: ServiceAccount
name: default
namespace: sugi
kubectl apply -f privileged-clusterrolebinding.yaml
(補足)
ClusterRoleをバインドする先がNamespace単位のリソースであるServiceAccountなので、ClusterRoleBindingではなく以下のようなRoleBindingを作成してもよい。
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: privileged-rolebinding
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: privileged
subjects:
- kind: ServiceAccount
name: default
稼働確認
libertyをデプロイする。
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: liberty
name: liberty
spec:
replicas: 1
selector:
matchLabels:
app: liberty
template:
metadata:
labels:
app: liberty
spec:
initContainers:
- name: init-sysctl
image: busybox
securityContext:
privileged: true
command:
- sh
- -c
- |
sysctl -w net.core.somaxconn=512
containers:
- name: websphere-liberty
image: websphere-liberty
kubectl apply -f liberty.yaml -n sugi
確認する。ちゃんと変更されている。
ubuntu@icp31-single:~/workspace/sysctl$ kubectl exec -it liberty-57c69978fd-4mf8b -- cat /proc/sys/net/core/somaxconn
512
ubuntu@icp31-single:~/workspace/sysctl$