一、PodInitializing
PodInitializing作为Kubernetes中的一个生命周期钩子,用来对Pod做初始化操作。PodInitializing允许其他容器在容器生命周期钩子(Pod lifecycle hook)被调用之前运行自己的指定初始化容器。这个容器可以执行任意用户指定的操作,并且只在pod创建的时候运行一次。
这时候就要用到podinit了。PodInit是一种简单的解决方案,在Kubernetes pod对象的生命周期管理中,我们向容器中添加了一个额外的容器。这个容器仅仅在Pod第一次启动时运行一次,然后退出。它完成一些特定的初始化任务,并且这些任务旨在在其他容器之前运行。
同时,如果主容器(即正常应用运行的容器)从故障中恢复,则没有必要再次运行初始化容器。因此,PodInit使用一个注释来跟踪每个容器的状态。当容器成功地写出到本地文件系统时,PodInit在启动时通过查询注释来检查容器是否运行过。
二、查看podinit日志
1、查看podinit日志文件路径
cat /var/log/pods/${pod_namespace}_${pod_name}_${container_name}/init.log
2、监听podinit日志
kubectl logs -n $pod_namespace $pod_name $container_name -c $container_name --follow | grep PODINIT-TRACE-LOG
3、查看podinit容器日志
kubectl logs -n $pod_namespace $pod_name $container_name -c podinit
三、podinit实现原理
PodInit使用一个init container来完成特定的初始化任务。Pod的其余部分被保留,仅在Init容器完成后才运行。使用kubelet中的PodAdmitHandler(以及PodAdmitFunc)来修改PodSpec以包含一个额外的初始化容器。
实现podinit需要以下步骤:
1、构建一个健壮的镜像,该镜像应该包含podinit可执行文件。
# Dockerfile FROM alpine:3.7 RUN apk add --no-cache tini ADD pod init ENTRYPOINT ["/sbin/tini", "-g", "--", "/pod"]
2、创建init容器
apiVersion: v1 kind: Pod metadata: labels: run: nginx name: nginx spec: containers: - image: nginx name: nginx volumeMounts: - name: shared-data mountPath: /usr/share/nginx/html initContainers: - image: busybox name: install command: - cp - -a - /mnt/data/. /usr/share/nginx/html volumeMounts: - name: shared-data mountPath: /mnt/data volumes: - name: shared-data emptyDir: {}
3、podinit代码示例:
#!/bin/sh -eu export PODINIT_LOG_LOCATION=${PODINIT_LOG_LOCATION:-'/var/log/pod-init.log'} echo "PODINIT-TRACE-LOG: pod namespace: $POD_NAMESPACE" >> $PODINIT_LOG_LOCATION echo "PODINIT-TRACE-LOG: pod name: $POD_NAME" >> $PODINIT_LOG_LOCATION echo "PODINIT-TRACE-LOG: container name: $CONTAINER_NAME" >> $PODINIT_LOG_LOCATION # We are using this file to store the pod name and container name which are # initialized by this init container so that if this init container crashes # or fails, we don't re-run the init container. INIT_FILE=/mnt/pod-init.data INIT_MARKER="pod-init" if [ ! -f ${INIT_FILE} ]; then echo "PODINIT-TRACE-LOG: Creating init file ${INIT_FILE} in container ${CONTAINER_NAME}" >> $PODINIT_LOG_LOCATION echo "${INIT_MARKER}" > ${INIT_FILE} else echo "PODINIT-TRACE-LOG: Initialization already executed in container ${CONTAINER_NAME}" >> $PODINIT_LOG_LOCATION fi
四、podinit使用例子
1、podinit示例:
apiVersion: v1 kind: Pod metadata: name: myapp spec: initContainers: - name: init-myservice image: busybox command: ['sh','-c', 'echo Initializing... && sleep 3600'] env: - name: POD_NAME valueFrom: fieldRef: fieldPath: metadata.name - name: POD_NAMESPACE valueFrom: fieldRef: fieldPath: metadata.namespace containers: - name: myapp image: busybox command: ['sh','-c', 'echo Sleeping... && sleep 3600'] env: - name: POD_NAME valueFrom: fieldRef: fieldPath: metadata.name - name: POD_NAMESPACE valueFrom: fieldRef: fieldPath: metadata.namespace
2、podinit搭配kubernetes-csi使用:
apiVersion: v1 kind: Pod metadata: name: myapp spec: initContainers: - name: init-myservice image: my-image env: - name: POD_NAME valueFrom: fieldRef: fieldPath: metadata.name - name: POD_NAMESPACE valueFrom: fieldRef: fieldPath: metadata.namespace command: ['sh','-c','/bin/podinit $MY_PARAM && $MY_VOLUME_SCRIPT'] volumeMounts: - name: my-volume mountPath: /mnt/data containers: - name: myapp image: busybox command: ['sh','-c', 'echo Sleeping... && sleep 3600'] env: - name: POD_NAME valueFrom: fieldRef: fieldPath: metadata.name - name: POD_NAMESPACE valueFrom: fieldRef: fieldPath: metadata.namespace volumeMounts: - name: my-volume mountPath: /mnt/data volumes: - name: my-volume emptyDir: {}
以上两个例子展示了podinit的使用场景,一个是与busybox一起使用,一个是与kubernetes-csi一起使用。这也充分说明了podinit的灵活性,开发人员可以自由发挥他的想象力。