介绍
初始化容器(Init Container)在 Pod 中的主应用容器启动之前运行。每个初始化容器必须成功完成,Kubernetes 才会启动下一个初始化容器或任何常规容器。这使得初始化容器非常适合用于准备文件、检查依赖项或执行一些不应在应用运行期间持续存在的简单设置任务。
在本实验中,你将添加一个初始化容器,它会将启动文件写入共享的 emptyDir 卷中,确认应用容器能够读取该文件,检查初始化容器的完成状态和日志,然后将相同的模式应用于 Deployment 模板中。
准备初始化容器命名空间
在此步骤中,你将准备一个干净的命名空间,用于练习初始化容器。
首先进入 /home/labex/project 目录。你将在此目录中编写 Pod 和 Deployment 的清单文件。
mkdir -p /home/labex/project
cd /home/labex/project
检查 Kubernetes API 服务器是否可访问。如果虚拟机刚启动且节点尚未就绪,请等待几秒钟后再运行该命令。
kubectl get nodes --request-timeout=5s
预期输出包含:
NAME STATUS ROLES AGE VERSION
labex-v135 Ready control-plane ... v1.35...
初始化容器在 Pod 内部运行,因此在创建工作负载之前,请确保集群网络 Pod 已就绪。
kubectl wait --namespace kube-system --for=condition=Ready pod -l k8s-app=calico-node --timeout=120s
预期输出:
pod/calico-node-... condition met
创建一个名为 ckad-prep-init 的命名空间:
kubectl create namespace ckad-prep-init
将此命名空间设置为当前上下文的命名空间:
kubectl config set-context --current --namespace=ckad-prep-init
确认当前命名空间:
kubectl config view --minify --output 'jsonpath={..namespace}'; echo
预期输出:
ckad-prep-init
在应用启动前准备共享数据
在此步骤中,你将创建一个 Pod,其中的初始化容器会在应用容器启动前准备好一个文件。
emptyDir 卷在 Pod 被分配到节点时创建,并由同一 Pod 中的容器共享。初始化容器和应用容器都将此卷挂载到 /work 目录。初始化容器写入 /work/startup.txt,然后退出。只有在它成功退出后,Kubernetes 才会启动应用容器。
创建 init-file-pod.yaml:
cat > init-file-pod.yaml <<'EOF'
apiVersion: v1
kind: Pod
metadata:
name: init-file-demo
labels:
app: init-file-demo
spec:
terminationGracePeriodSeconds: 0
volumes:
- name: shared-work
emptyDir: {}
initContainers:
- name: prepare-startup-file
image: busybox:1.36
command:
- /bin/sh
- -c
- 'echo init-started; echo prepared-by-init > /work/startup.txt; echo init-finished'
volumeMounts:
- name: shared-work
mountPath: /work
containers:
- name: app
image: busybox:1.36
command:
- /bin/sh
- -c
- 'echo app-started; cat /work/startup.txt; sleep 3600'
volumeMounts:
- name: shared-work
mountPath: /work
EOF
应用清单:
kubectl apply -f init-file-pod.yaml
预期输出:
pod/init-file-demo created
等待 Pod 就绪:
kubectl wait --for=condition=Ready pod/init-file-demo --timeout=120s
预期输出:
pod/init-file-demo condition met
从应用容器内部读取文件。这证明了初始化容器在应用启动前已在共享卷上准备好了数据。
kubectl exec init-file-demo -c app -- cat /work/startup.txt
预期输出:
prepared-by-init
检查初始化容器的状态和日志
在此步骤中,你将检查初始化容器在应用容器运行前已完成的证据。
初始化容器显示在 .status.initContainerStatuses 下,而常规容器显示在 .status.containerStatuses 下。初始化容器应该有一个 Completed 原因,因为它已成功退出。
kubectl get pod init-file-demo -o 'jsonpath={.status.initContainerStatuses[0].name}{" "}{.status.initContainerStatuses[0].state.terminated.reason}{"\n"}'
预期输出:
prepare-startup-file Completed
现在检查常规应用容器的状态。它应该是就绪且正在运行的。
kubectl get pod init-file-demo -o 'jsonpath={.status.containerStatuses[0].name}{" "}{.status.containerStatuses[0].ready}{" "}{.status.containerStatuses[0].state.running.startedAt}{"\n"}'
预期输出包含:
app true ...
读取初始化容器的日志。即使初始化容器已经完成,其日志仍然可以通过 kubectl logs -c 查看。
kubectl logs init-file-demo -c prepare-startup-file
预期输出:
init-started
init-finished
读取应用容器的日志。应用在初始化容器写入文件后启动,因此其日志中包含了准备好的值。
kubectl logs init-file-demo -c app
预期输出包含:
app-started
prepared-by-init
将初始化容器添加到 Deployment
在此步骤中,你将在 Deployment 模板中使用相同的初始化容器模式。
对于应用工作负载,通常将初始化容器放置在控制器的 Pod 模板中,而不是创建独立的 Pod。当 Deployment 创建 Pod 时,Kubernetes 会为从该模板创建的每个 Pod 首先运行初始化容器。
创建 init-deployment.yaml:
cat > init-deployment.yaml <<'EOF'
apiVersion: apps/v1
kind: Deployment
metadata:
name: init-web
spec:
replicas: 1
selector:
matchLabels:
app: init-web
template:
metadata:
labels:
app: init-web
spec:
terminationGracePeriodSeconds: 0
volumes:
- name: web-content
emptyDir: {}
initContainers:
- name: render-index
image: busybox:1.36
command:
- /bin/sh
- -c
- 'echo deployment-init > /site/index.txt'
volumeMounts:
- name: web-content
mountPath: /site
containers:
- name: web
image: busybox:1.36
command:
- /bin/sh
- -c
- 'cat /site/index.txt; sleep 3600'
volumeMounts:
- name: web-content
mountPath: /site
EOF
应用 Deployment:
kubectl apply -f init-deployment.yaml
预期输出:
deployment.apps/init-web created
等待 Deployment 可用:
kubectl wait --for=condition=Available deployment/init-web --timeout=120s
预期输出:
deployment.apps/init-web condition met
查找由 Deployment 创建的 Pod:
web_pod="$(kubectl get pods -l app=init-web -o 'jsonpath={.items[0].metadata.name}')"
echo "$web_pod"
预期输出显示生成的 Pod 名称:
init-web-...
读取该 Pod 中应用容器的日志:
kubectl logs "$web_pod" -c web
预期输出:
deployment-init
检查 Deployment 创建的 Pod 中初始化容器的完成状态:
kubectl get pod "$web_pod" -o 'jsonpath={.status.initContainerStatuses[0].name}{" "}{.status.initContainerStatuses[0].state.terminated.reason}{"\n"}'
预期输出:
render-index Completed
总结
你已成功将初始化容器添加到 Pod 和 Deployment 模板中。你使用了 emptyDir 卷与应用容器共享准备好的文件,检查了已完成的初始化容器状态,读取了初始化容器和应用容器的日志,并确认了相同的模式同样适用于由控制器管理的应用 Pod。


