Open lihongjie0209 opened 3 years ago
每个 Pod 中可以包含多个容器, 应用运行在这些容器里面,同时 Pod 也可以有一个或多个先于应用容器启动的 Init 容器。
Init 容器与普通的容器非常像,除了如下两点:
如果 Pod 的 Init 容器失败,kubelet 会不断地重启该 Init 容器直到该容器成功为止。 然而,如果 Pod 对应的 restartPolicy 值为 "Never",Kubernetes 不会重新启动 Pod。
restartPolicy
为 Pod 设置 Init 容器需要在 Pod 的 spec 中添加 initContainers 字段, 该字段以 Container 类型对象数组的形式组织,和应用的 containers 数组同级相邻。 Init 容器的状态在 status.initContainerStatuses 字段中以容器状态数组的格式返回 (类似 status.containerStatuses 字段)。
spec
initContainers
containers
status.initContainerStatuses
status.containerStatuses
Init 容器支持应用容器的全部字段和特性,包括资源限制、数据卷和安全设置。 然而,Init 容器对资源请求和限制的处理稍有不同,在下面资源节有说明。
同时 Init 容器不支持 lifecycle、livenessProbe、readinessProbe 和 startupProbe, 因为它们必须在 Pod 就绪之前运行完成。
lifecycle
livenessProbe
readinessProbe
startupProbe
如果为一个 Pod 指定了多个 Init 容器,这些容器会按顺序逐个运行。 每个 Init 容器必须运行成功,下一个才能够运行。当所有的 Init 容器运行完成时, Kubernetes 才会为 Pod 初始化应用容器并像平常一样运行。
因为 Init 容器具有与应用容器分离的单独镜像,其启动相关代码具有如下优势:
sed
awk
python
dig
FROM
下面是一些如何使用 Init 容器的想法:
等待一个 Service 完成创建,通过类似如下 shell 命令:
for i in {1..100}; do sleep 1; if dig myservice; then exit 0; fi; exit 1
注册这个 Pod 到远程服务器,通过在命令中调用 API,类似如下:
curl -X POST http://$MANAGEMENT_SERVICE_HOST:$MANAGEMENT_SERVICE_PORT/register \ -d 'instance=$(<POD_NAME>)&ip=$(<POD_IP>)'
在启动应用容器之前等一段时间,使用类似命令:
sleep 60
克隆 Git 仓库到卷中。
将配置值放到配置文件中,运行模板工具为主应用容器动态地生成配置文件。 例如,在配置文件中存放 POD_IP 值,并使用 Jinja 生成主应用配置文件。
POD_IP
下面的例子定义了一个具有 2 个 Init 容器的简单 Pod。 第一个等待 myservice 启动, 第二个等待 mydb 启动。 一旦这两个 Init容器 都启动完成,Pod 将启动 spec 节中的应用容器。
myservice
mydb
apiVersion: v1 kind: Pod metadata: name: myapp-pod labels: app: myapp spec: containers: - name: myapp-container image: busybox:1.28 command: ['sh', '-c', 'echo The app is running! && sleep 3600'] initContainers: - name: init-myservice image: busybox:1.28 command: ['sh', '-c', "until nslookup myservice.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local; do echo waiting for myservice; sleep 2; done"] - name: init-mydb image: busybox:1.28 command: ['sh', '-c', "until nslookup mydb.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local; do echo waiting for mydb; sleep 2; done"]
你通过运行下面的命令启动 Pod:
kubectl apply -f myapp.yaml pod/myapp-pod created
使用下面的命令检查其状态:
kubectl get -f myapp.yaml NAME READY STATUS RESTARTS AGE myapp-pod 0/1 Init:0/2 0 6m
或者查看更多详细信息:
kubectl describe -f myapp.yaml Name: myapp-pod Namespace: default [...] Labels: app=myapp Status: Pending [...] Init Containers: init-myservice: [...] State: Running [...] init-mydb: [...] State: Waiting Reason: PodInitializing Ready: False [...] Containers: myapp-container: [...] State: Waiting Reason: PodInitializing Ready: False [...] Events: FirstSeen LastSeen Count From SubObjectPath Type Reason Message --------- -------- ----- ---- ------------- -------- ------ ------- 16s 16s 1 {default-scheduler } Normal Scheduled Successfully assigned myapp-pod to 172.17.4.201 16s 16s 1 {kubelet 172.17.4.201} spec.initContainers{init-myservice} Normal Pulling pulling image "busybox" 13s 13s 1 {kubelet 172.17.4.201} spec.initContainers{init-myservice} Normal Pulled Successfully pulled image "busybox" 13s 13s 1 {kubelet 172.17.4.201} spec.initContainers{init-myservice} Normal Created Created container with docker id 5ced34a04634; Security:[seccomp=unconfined] 13s 13s 1 {kubelet 172.17.4.201} spec.initContainers{init-myservice} Normal Started Started container with docker id 5ced34a04634
如需查看 Pod 内 Init 容器的日志,请执行:
kubectl logs myapp-pod -c init-myservice # 查看第一个 Init 容器 kubectl logs myapp-pod -c init-mydb # 查看第二个 Init 容器
在这一刻,Init 容器将会等待至发现名称为 mydb 和 myservice 的 Service。
如下为创建这些 Service 的配置文件:
--- apiVersion: v1 kind: Service metadata: name: myservice spec: ports: - protocol: TCP port: 80 targetPort: 9376 --- apiVersion: v1 kind: Service metadata: name: mydb spec: ports: - protocol: TCP port: 80 targetPort: 9377
创建 mydb 和 myservice 服务的命令:
kubectl create -f services.yaml service "myservice" created service "mydb" created
这样你将能看到这些 Init 容器执行完毕,随后 my-app 的 Pod 进入 Running 状态:
my-app
Running
kubectl get -f myapp.yaml NAME READY STATUS RESTARTS AGE myapp-pod 1/1 Running 0 9m
理解 Init 容器
每个 Pod 中可以包含多个容器, 应用运行在这些容器里面,同时 Pod 也可以有一个或多个先于应用容器启动的 Init 容器。
Init 容器与普通的容器非常像,除了如下两点:
如果 Pod 的 Init 容器失败,kubelet 会不断地重启该 Init 容器直到该容器成功为止。 然而,如果 Pod 对应的
restartPolicy
值为 "Never",Kubernetes 不会重新启动 Pod。为 Pod 设置 Init 容器需要在 Pod 的
spec
中添加initContainers
字段, 该字段以 Container 类型对象数组的形式组织,和应用的containers
数组同级相邻。 Init 容器的状态在status.initContainerStatuses
字段中以容器状态数组的格式返回 (类似status.containerStatuses
字段)。与普通容器的不同之处
Init 容器支持应用容器的全部字段和特性,包括资源限制、数据卷和安全设置。 然而,Init 容器对资源请求和限制的处理稍有不同,在下面资源节有说明。
同时 Init 容器不支持
lifecycle
、livenessProbe
、readinessProbe
和startupProbe
, 因为它们必须在 Pod 就绪之前运行完成。如果为一个 Pod 指定了多个 Init 容器,这些容器会按顺序逐个运行。 每个 Init 容器必须运行成功,下一个才能够运行。当所有的 Init 容器运行完成时, Kubernetes 才会为 Pod 初始化应用容器并像平常一样运行。
使用 Init 容器
因为 Init 容器具有与应用容器分离的单独镜像,其启动相关代码具有如下优势:
sed
、awk
、python
或dig
这样的工具而去FROM
一个镜像来生成一个新的镜像。示例
下面是一些如何使用 Init 容器的想法:
等待一个 Service 完成创建,通过类似如下 shell 命令:
注册这个 Pod 到远程服务器,通过在命令中调用 API,类似如下:
在启动应用容器之前等一段时间,使用类似命令:
克隆 Git 仓库到卷中。
将配置值放到配置文件中,运行模板工具为主应用容器动态地生成配置文件。 例如,在配置文件中存放
POD_IP
值,并使用 Jinja 生成主应用配置文件。使用 Init 容器的情况
下面的例子定义了一个具有 2 个 Init 容器的简单 Pod。 第一个等待
myservice
启动, 第二个等待mydb
启动。 一旦这两个 Init容器 都启动完成,Pod 将启动spec
节中的应用容器。你通过运行下面的命令启动 Pod:
使用下面的命令检查其状态:
或者查看更多详细信息:
如需查看 Pod 内 Init 容器的日志,请执行:
在这一刻,Init 容器将会等待至发现名称为
mydb
和myservice
的 Service。如下为创建这些 Service 的配置文件:
创建
mydb
和myservice
服务的命令:这样你将能看到这些 Init 容器执行完毕,随后
my-app
的 Pod 进入Running
状态: