k8s-nodeshell实现
对于node我们一般会禁止ssh登录,但有时又不得不登录到node节点查看和debug,这时就可以通过node-shell的方式获得对应node的root shell。
安装:
https://github.com/kvaps/kubectl-node-shell/tree/master
使用curl进行安装。
curl -LO https://github.com/kvaps/kubectl-node-shell/raw/master/kubectl-node_shell
chmod +x ./kubectl-node_shell
sudo mv ./kubectl-node_shell /usr/local/bin/kubectl-node_shell
使用
# Get standard bash shell
kubectl node-shell <node>
# Use X-mode (mount /host, and do not enter host namespace)
kubectl node-shell -x <node>
# Execute custom command
kubectl node-shell <node> -- echo 123
# Use stdin
cat /etc/passwd | kubectl node-shell <node> -- sh -c 'cat > /tmp/passwd'
# Run oneliner script
kubectl node-shell <node> -- sh -c 'cat /tmp/passwd; rm -f /tmp/passwd'
原理:
其实就是一个bash脚本,所做的就是起一个特权容器,然后使用nsenter进入到宿主机,从而获取到root shell。
nsenter就是namespace enter的意思,它可以进入到目标程序所在的namespace中,因此可以用来调试容器程序。我们都知道目前存在的几个namespace,比如网络,用户,pid等,nsenter都有对应的参数可以指定,从而进入该namespace。
对于容器中有bash程序的场景,我们通过exec的方式就能进入容器内部,此时并不需要nsenter,但是对于那些没有bash程序的,就没法通过exec进入容器了,我们首先通过docker inspect获得对应容器的pid,然后通过nsenter进入utc、net、和pid namespace,这样我们就能使用宿主机的调试工具,比如tcpdump,ip等命令。
扩展
创建nodeshell的daemonset:
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: nsenter-daemonset
namespace: default
labels:
app: nsenter
spec:
selector:
matchLabels:
app: nsenter
template:
metadata:
labels:
app: nsenter
spec:
hostPID: true
hostNetwork: true
tolerations:
- key: "CriticalAddonsOnly"
operator: "Exists"
- effect: "NoExecute"
operator: "Exists"
containers:
- name: nsenter
image: docker.io/library/alpine
securityContext:
privileged: true
stdin: true
stdinOnce: true
tty: true
command: [ "nsenter", "--target", "1", "--mount", "--uts", "--ipc", "--net", "--pid", "--", "bash", "-l" ]
resources:
limits:
cpu: "100m"
memory: "256Mi"
requests:
cpu: "100m"
memory: "256Mi"
nodeSelector:
kubernetes.io/hostname: node1
创建nodeshell的pod:
kubectl --namespace= xxx run --image docker.io/library/alpine --restart=Never '--overrides={
"spec": {
"nodeName": "node1", #更改nodename
"hostPID": true,
"hostNetwork": true,
"containers": [
{
"securityContext": {
"privileged": true
},
"image": "docker.io/library/alpine",
"name": "nsenter",
"stdin": true,
"stdinOnce": true,
"tty": true,
"command": [ "nsenter", "--target", "1", "--mount", "--uts", "--ipc", "--net", "--pid", "--", "bash", "-l" ],
"resources": {
"limits": {
"cpu": "100m",
"memory": "256Mi"
},
"requests": {
"cpu": "100m",
"memory": "256Mi"
}
}
}
],
"tolerations": [
{
"key": "CriticalAddonsOnly",
"operator": "Exists"
},
{
"effect": "NoExecute",
"operator": "Exists"
}
]
}
}' --labels= -t -i nsenter-h3m5fy