临时容器

510 阅读5分钟

了解临时容器

特性状态: Kubernetes v1.23 [beta]

Pod是Kubernetes应用程序的基本构建块,由于Pod是一次性并且是可替代的,因此一旦Pod创建,就无法将容器加入到Pod中。取而代之的是,通常使用Deployment以受控的方式来删除并替换Pod。

有时有必要检查现有Pod的状态,例如,对于难以复现的故障进行排查。在这些场景中,可以在现有的Pod中运行临时容器来检查其状态并运行任意命令。

临时容器与其他容器不同之处在于,他们缺少对资源或执行的保证,并且永远不会自动重启,因此不适用于构建应用程序。临时容器使用与常规容器相同的containerSpec节来描述,但许多字段是不兼容和不允许的。

  • 临时容器没有端口配置,因此像ports,livenessProbe,readinessProbe这样的字段是不允许的。
  • Pod资源分配是不可变的,因此resources配置是不允许的。
  • 有关允许字段的完整列表,请参见 EphemeralContainer 参考文档

临时容器是使用API中的一种特殊的ephemeralcontainers处理器进行创建的,而不是直接添加到pod.spec段,因此不能使用kubectl edit来添加一个临时容器。

与常规容器一样,将临时容器添加到Pod后,将不能更改或删除临时容器。

临时容器的用途

当由于容器崩溃或容器镜像不包含调试工具而导致 kubectl exec 无用时, 临时容器对于交互式故障排查很有用。

尤其是,Distroless 镜像 允许用户部署最小的容器镜像,从而减少攻击面并减少故障和漏洞的暴露。 由于 distroless 镜像不包含 Shell 或任何的调试工具,因此很难单独使用 kubectl exec 命令进行故障排查。

使用临时容器时,启用进程命名空间共享很有帮助,可以查看到其他容器中的进程。

在Pod中的容器之间共享进程命名空间

特性状态: Kubernetes v1.17 [stable]

当启用进程命名空间共享时,容器中的进程对该Pod中的所有其他容器都是可见的。

可以使用此功能来配置协作容器,比如日志处理sidecar容器,或者对那些不包含诸如shell等调试实用工具的进行故障排查。

配置Pod

进程命名空间共享使用v1.PodSpec中的ShareProcessNamespace字段启用。例如:

# share-process-namespace.yaml

apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  shareProcessNamespace: true
  containers:
  - name: nginx
    image: nginx
  - name: shell
    image: busybox:1.28
    securityContext:
      capabilities:
        add:
        - SYS_PTRACE
    stdin: true
    tty: true

在集群中创建nginx Pod:

kubectl apply -f share-process-namespace.yaml

等待Pod的状态为running后,获取容器shell,执行ps:

kubectl attach -it nginx -c shell

如果没有看到命令提示符,请按enter

/ # ps ax
PID   USER     TIME  COMMAND
    1 65535     0:00 /pause
    7 root      0:00 nginx: master process nginx -g daemon off;
   15 root      0:00 sh
   45 101       0:00 nginx: worker process
   46 101       0:00 nginx: worker process
   47 root      0:00 ps ax

这时候可以在其他容器中对进程发出信号,例如发送SIGHUP到nginx以重启工作进程,这需要SYS_PTRACE功能:

/ # kill -HUP 7
/ # ps ax
PID   USER     TIME  COMMAND
    1 65535     0:00 /pause
    7 root      0:00 nginx: master process nginx -g daemon off;
   15 root      0:00 sh
   48 101       0:00 nginx: worker process
   49 101       0:00 nginx: worker process
   50 root      0:00 ps ax

设置可以使用/poc/$pod/root链接访问另一个容器镜像。

/ # head /proc/7/root/etc/nginx/nginx.conf

user  nginx;
worker_processes  auto;

error_log  /var/log/nginx/error.log notice;
pid        /var/run/nginx.pid;


events {
    worker_connections  1024;
理解进程命名空间共享

Pod 共享许多资源,因此它们共享进程命名空间是很有意义的。 不过,有些容器镜像可能希望与其他容器隔离,因此了解这些差异很重要:

  1. 容器进程不再具有 PID 1。 在没有 PID 1 的情况下,一些容器镜像拒绝启动(例如,使用 systemd 的容器),或者拒绝执行 kill -HUP 1 之类的命令来通知容器进程。在具有共享进程命名空间的 pod 中,kill -HUP 1 将通知 pod 沙箱(在上面的例子中是 /pause)。
  2. 进程对 pod 中的其他容器可见。 这包括 /proc 中可见的所有信息,例如作为参数或环境变量传递的密码。这些仅受常规 Unix 权限的保护。
  3. 容器文件系统通过 /proc/$pid/root 链接对 pod 中的其他容器可见。 这使调试更加容易,但也意味着文件系统安全性只受文件系统权限的保护。

使用临时容器来调试运行中的Pod

特性状态 :Kubernetes v1.23 [beta]

当由于容器崩溃或容器镜像不包含调试程序(例如无发行版镜像等) 而导致 kubectl exec 无法运行时,临时容器对于排除交互式故障很有用。

可以使用kubectl debug命令来给正在运行中的Pod增加一个临时容器,首先像示例中一样创建一个Pod:

kubectl run ephemeral-demo --image=k8s.gcr.io/parse:3.6 --restart=Never

说明

本节示例中使用pause容器镜像,因为它不包含调试程序,但是这个方法用于所有容器镜像。

如果尝试使用kubectl exec来创建一个shell,将会看到一个错误,因为这个容器中没有shell。

$ kubectl exec -it ephemeral-demo -- sh

OCI runtime exec failed: exec failed: container_linux.go:380: starting container process caused: exec: "sh": executable file not found in $PATH: unknown
command terminated with exit code 126

这时候就可以使用kubectl debug添加调试容器。如果指定-i或者--interactive参数,kubectl将自动挂接到临时容器的控制台。

$ kubectl debug -it ephemeral-demo --image=busybox:1.28 --target=ephemeral-demo

Targeting container "ephemeral-demo". If you don't see processes from this container it may be because the container runtime doesn't support this feature.
Defaulting debug container name to debugger-f9xj9.
If you don't see a command prompt, try pressing enter.
/ #

此命令添加了一个新的busybox容器并将其挂接到ephemeral-demo--target参数指定另一个容器的进程命名空间。这是必须的,因为kubectl run不能在它创建的Pod中启用共享进程命名空间。

说明:

容器运行时必须支持--target参数,如果不支持,则临时容器可能不会启动,或者可能使用隔离的进程命名空间启动,以便ps不限时其他容器内的进程。

可以使用kubectl describe查看新创建的临时容器的状态,最后使用kubectl delete来移除已经结束掉的Pod。

参考链接

kubernetes.io/zh-cn/docs/…

kubernetes.io/zh-cn/docs/…

kubernetes.io/zh-cn/docs/…