LoginSignup
26
12

More than 3 years have passed since last update.

Podのカーネルパラメータを変更する

Last updated at Posted at 2018-11-14

Podのカーネルパラメータ(sysctl)を変更する方法について調べたまとめ。ICP v3.1.0で確認。

大きくは以下の方法がある。

  • PodのsecurityContextで設定
  • Init Containerで設定

カーネルパラメータについて

上記のドキュメントによると以下とのこと。

  • sysctlにはnamespacedなものとそうでないものがある
    • Pod毎にsysctlを設定できるのはnamespacedなもののみ
    • namespaced sysctlではないものはnode-level sysctlという
  • 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.somaxconnnamespacedでありファイルがある。ホスト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.somaxconn512に変更する方法を試す。

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ではデフォルトでdefaultprivilegedの2つのPodSecurityPolicyがあり、それらを利用可能にしているClusterRoleがそれぞれあり、それらをバインディングしているClusterRoleBindingがある。

(補足)
ICP v3.1.1ではibm-restricted-pspibm-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で設定されていた内容に追加する形で作成する。

somaxconn-psp.yaml
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を作成する。

somaxconn-clusterrole.yaml
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を作成する。

somaxconn-clusterrolebinding.yaml
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を指定した以下のマニフェストを適用する。

liberty.yam
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を追加し、デーモンを再起動する。

/etc/systemd/system/kubelet.service
[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)にバインドする。

privileged-clusterrolebinding.yaml
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を作成してもよい。

privileged-rolebinding.yaml
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をデプロイする。

liberty.yaml
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$

参考リンク

26
12
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
26
12