pod manifest 可以指定在 pod 启动时和 pod 的正常容器启动之前运行的容器列表。这些容器旨在初始化 pod,并被恰当的称为 *init 容器*。如下图所示,它们一个接一个地运行,并且必须在 Pod 的主容器启动之前都成功完成。
初始化容器类似于 pod 的常规容器,但它们不会并行运行 - 一次只能运行一个初始化容器。
通常将初始化容器添加到 pod 以实现以下目的:
您可以在主容器本身中执行这些操作,但使用 init 容器有时是更好的选择,并且还有其他优势。让我们看看为什么。
使用 init 容器执行初始化任务不需要重新构建主容器映像,并且允许单个 init 容器映像在许多不同的应用程序中重用。如果您想将相同的特定于基础架构的初始化代码注入所有 pod,这将特别有用。使用 init 容器还可以确保在任何(可能是多个)主容器启动之前完成此初始化。
另一个重要原因是安全性。通过将攻击者可能用来破坏集群的工具或数据从主容器移动到初始化容器,可以减少 pod 的攻击面。
例如,假设 pod 必须向外部系统注册。Pod 需要某种秘密令牌来针对该系统进行身份验证。如果注册过程由主容器执行,则此秘密令牌必须存在于其文件系统中。如果在主容器中运行的应用程序存在允许攻击者读取文件系统上的任意文件的漏洞,则攻击者可能能够获得此令牌。通过从 init 容器执行注册,令牌必须仅在 init 容器的文件系统中可用,攻击者无法轻易破坏。
在 pod 清单中,init 容器在 spec 部分的字段 initContainers
中定义,就像在其字段 containers
中定义常规容器一样。
让我们看一个将两个 init 容器添加到 kiada pod 的示例。第一个 init 容器模拟一个初始化过程。它运行 5 秒,同时将几行文本打印到标准输出。
第二个 init 容器通过使用 ping
命令检查是否可以从 pod 内访问特定 IP 地址来执行网络连接测试。IP 地址默认为 1.1.1.1 ,可通过命令行参数进行配置。
提示
检查特定 IP 地址是否可访问的 init 容器可用于阻止应用程序启动,直到它所依赖的服务可用。
pod.kiada-init.yaml
其内容如下表所示。
apiVersion: v1
kind: Pod
metadata:
name: kiada-init
spec:
initContainers: # 初始化容器 需要配置在 `initContainers` 字段中 ,它们顺序运行
- name: init-demo # 第一个运行的初始化容器
image: luksa/init-demo:0.1
- name: network-check # 第二个运行的初始化容器
image: luksa/network-connectivity-checker:0.1
containers: # pod 的常规容器,他们并行运行
- name: kiada
image: luksa/kiada:0.2
stdin: true
ports:
- name: http
containerPort: 8080
- name: envoy
image: luksa/kiada-ssl-proxy:0.1
ports:
- name: https
containerPort: 8443
- name: admin
containerPort: 9901
如您所见,init 容器的定义不多。只为每个容器指定 name
和 image
就足够了。
注意
容器名称在所有初始化容器和常规容器的集合中必须是唯一的。
在从清单文件创建 pod 之前,请在单独的终端中运行以下命令,以便查看 pod 的状态如何随着 init 和常规容器的启动而变化:
kubectl get pods -w
您还需要使用以下命令在另一个终端中观看事件:
kubectl get events -w
准备就绪后,通过运行 apply 命令创建 pod:
kubectl apply -f pod.kiada-init.yaml
当 pod 启动时,检查 kubectl get events -w
命令显示的事件:
kubectl get events -w
# output
LAST SEEN TYPE REASON OBJECT MESSAGE
116s Normal Scheduled pod/kiada-init Successfully assigned default/kiada-init to kind-worker2
115s Normal Pulling pod/kiada-init Pulling image "luksa/init-demo:0.1"
109s Normal Pulled pod/kiada-init Successfully pulled image "luksa/init-demo:0.1" in 6.320223336s
109s Normal Created pod/kiada-init Created container init-demo
109s Normal Started pod/kiada-init Started container init-demo # 第一个 init 容器运行完成
102s Normal Pulling pod/kiada-init Pulling image "luksa/network-connectivity-checker:0.1"
97s Normal Pulled pod/kiada-init Successfully pulled image "luksa/network-connectivity-checker:0.1" in 5.338029002s
97s Normal Created pod/kiada-init Created container network-check
97s Normal Started pod/kiada-init Started container network-check # 第二个 init 容器运行完成
96s Normal Pulling pod/kiada-init Pulling image "luksa/kiada:0.2"
69s Normal Pulled pod/kiada-init Successfully pulled image "luksa/kiada:0.2" in 26.998945804s
69s Normal Created pod/kiada-init Created container kiada
69s Normal Started pod/kiada-init Started container kiada # 并行启动主容器
69s Normal Pulling pod/kiada-init Pulling image "luksa/kiada-ssl-proxy:0.1"
58s Normal Pulled pod/kiada-init Successfully pulled image "luksa/kiada-ssl-proxy:0.1" in 11.18325113s
58s Normal Created pod/kiada-init Created container envoy
58s Normal Started pod/kiada-init Started container envoy # 并行启动主容器
该清单显示了容器的启动顺序。init-demo
容器首先启动。完成后,network-check
启动容器,完成后,启动两个主容器kiada
和envoy
。
现在检查另一个终端中 pod 状态的转换。它们应该如下所示:
kubectl get pods -w
# output
NAME READY STATUS RESTARTS AGE
kiada-init 0/2 Pending 0 0s
kiada-init 0/2 Pending 0 0s
kiada-init 0/2 Init:0/2 0 0s
kiada-init 0/2 Init:0/2 0 7s
kiada-init 0/2 Init:1/2 0 12s
kiada-init 0/2 PodInitializing 0 18s
kiada-init 2/2 Running 0 51s
如清单所示,当 init 容器运行时,pod 的状态显示已完成的 init 容器数和总数。当所有 init 容器都完成后,pod 的状态显示为 PodInitializing
。至此,拉取了主要容器的镜像。当容器启动时,状态变为Running
。
与常规容器一样,您可以在正在运行的 init 容器中运行其他命令,kubectl exec
并使用 kubectl logs
显示日志。
每个 init 容器都可以写入的标准和错误输出的捕获方式与常规容器完全相同。可以使用 kubectl logs
命令显示 init 容器的日志,方法 -c
是在容器运行时或完成后使用选项指定容器的名称。network-check
要显示 pod 中容器的日志 kiada-init
,请运行下一个命令:
kubectl logs kiada-init -c network-check
# output
Checking network connectivity to 1.1.1.1 ...
Host appears to be reachable
日志显示 network-check
init 容器运行没有错误。
您可以使用该 kubectl exec
命令在 init 容器中运行 shell 或不同的命令,就像在常规容器中一样,但您只能在 init 容器终止之前执行此操作。如果您想自己尝试,请从 pod.kiada-init-slow.yaml
文件创建一个 pod,使 init-demo
容器运行 60 秒。当 pod 启动时,使用以下命令在容器中运行一个 shell:
kubectl exec -it kiada-init-slow -c init-demo -- sh
您可以使用 shell 从内部探索容器,但时间很短。当容器的主进程在 60 秒后退出时,shell 进程也被终止。
您通常只有在无法及时完成并且想要查找原因时才会进入正在运行的 init 容器。在正常操作期间,init 容器会在您运行 kubectl exec
命令之前终止。
好好学习,天天向上