k8s中如何用DaemonSet在大量节点上执行脚本
如何使用DaemonSet执行特权代码
简单点说,最低有三个条件。
spec.hostPID
is true.spec.containers.securityContext.privileged
is true.- 镜像里有
nsenter
.
条件1主要是为了让你能找到host的mnt namespace,然后你用条件3里的nsenter
来在这个namespace里执行代码。就像这样。
/usr/bin/nsenter -m/proc/1/ns/mnt bash /runOnHost.sh
host上如何执行脚本
nsenter
在host namespace下执行的时候,是不访问容器内文件系统的(或者很麻烦)。所以在host上执行脚本,最简单的办法就是拷过去。
cp /srv/runOnHost.sh /host/runOnHost.sh
/usr/bin/nsenter -m/proc/1/ns/mnt bash /runOnHost.sh
rm /host/runOnHost.sh
这就引出了一个新要求。如果要复制文件,pod需要挂载host文件系统。
containers:
volumeMounts:
- mountPath: /host
name: host-mount
volumes:
- hostPath:
path: /
type: ""
name: host-mount
如何访问网络
注意,虽然我们进入了host的mnt namespace,但是network用的还是容器的。如果你的代码不需要网络,或者容器网络就能工作,那很好。如果需要host网络,那么需要设置spec.hostNetwork
为true。
最简化镜像
很幸运的是,ubuntu官方镜像带了bash
和nsenter
,因此不单独pack一个image来执行脚本是可能的。
- 使用ubuntu镜像。
- 用文件目录创建一个ConfigMap。
- 在DaemonSet里引用这个ConfigMap并且mount。
containers:
volumeMounts:
- mountPath: /srv
name: scripts
volumes:
- configMap:
defaultMode: 0755
name: rce-testing
name: scripts
Put all together
runOnHost.sh: 随意
runOnPod.sh:
#!/bin/bash
cp /srv/runOnHost.sh /host/runOnHost.sh
/usr/bin/nsenter -m/proc/1/ns/mnt bash /runOnHost.sh
rm /host/runOnHost.sh
sleep 864000000
用以下命令生成一个ConfigMap,内容是上述两个文件。
kubectl create configmap rce-testing --from-file=srv/
rce-testing.yaml:
apiVersion: apps/v1
kind: DaemonSet
metadata:
labels:
app: rce-testing
name: rce-testing
spec:
selector:
matchLabels:
app: rce-testing
template:
metadata:
labels:
app: rce-testing
spec:
hostPID: true
hostNetwork: true
containers:
- name: ubuntu
image: ubuntu
imagePullPolicy: IfNotPresent
command:
- /bin/bash
args:
- /srv/runOnPod.sh
securityContext:
privileged: true
volumeMounts:
- mountPath: /srv
name: scripts
- mountPath: /host
name: host-mount
volumes:
- configMap:
defaultMode: 0755
name: rce-testing
name: scripts
- hostPath:
path: /
type: ""
name: host-mount
其他注意事项
PodSecurityPolicy可能会阻止你开特权pod,注意解锁。