【云原生Kubernetes】08-Pod中的Init容器
文章目录
简介
理解 Init 容器
- 每个 Pod中可以包含多个容器, 应用运行在这些容器里面,同时 Pod 也可以有一个或多个先于应用容器启动的 Init 容器。
Init 容器与普通的容器非常像,除了如下两点:
- 它们总是运行到完成。
- 每个都必须在下一个启动之前成功完成。
-
如果 Pod 的 Init 容器失败,kubelet 会不断地重启该 Init 容器直到该容器成功为止。 然而,如果 Pod 对应的
restartPolicy
值为 “Never”,并且 Pod 的 Init 容器失败, 则 Kubernetes 会将整个 Pod 状态设置为失败。 -
如果为一个 Pod 指定了多个 Init 容器,这些容器会按顺序逐个运行。 每个 Init 容器必须运行成功,下一个才能够运行。当所有的 Init 容器运行完成时, Kubernetes 才会为 Pod 初始化应用容器并像平常一样运行。
与普通容器的不同之处:
- Init 容器支持应用容器的全部字段和特性,包括资源限制、数据卷和安全设置。 然而,Init 容器对资源请求和限制的处理稍有不同;
- Init 容器不支持
lifecycle
、livenessProbe
、readinessProbe
和startupProbe
, 因为它们必须在 Pod 就绪之前运行完成。
Init容器使用场景
因为 Init 容器具有与应用容器分离的单独镜像,其启动相关代码具有如下优势:
-
Init 容器可以包含一些安装过程中应用容器中不存在的实用工具或个性化代码。 例如,没有必要仅为了在安装过程中使用类似
sed
、awk
、python
或dig
这样的工具而去FROM
一个镜像来生成一个新的镜像。 -
应用镜像的创建者和部署者可以各自独立工作,而没有必要联合构建一个单独的应用镜像。
-
与同一 Pod 中的多个应用容器相比,Init 容器能以不同的文件系统视图运行。因此,Init 容器可以被赋予访问应用容器不能访问的 Secret 的权限。
-
由于 Init 容器必须在应用容器启动之前运行完成,因此 Init 容器提供了一种机制来阻塞或延迟应用容器的启动,直到满足了一组先决条件。 一旦前置条件满足,Pod 内的所有的应用容器会并行启动。
-
Init 容器可以安全地运行实用程序或自定义代码,而在其他方式下运行这些实用程序或自定义代码可能会降低应用容器镜像的安全性。 通过将不必要的工具分开,你可以限制应用容器镜像的被攻击范围。
创建包含Init容器的Pod
apiVersion: v1
kind: Pod
metadata:
name: init-demo
spec:
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
volumeMounts:
- name: workdir
mountPath: /usr/share/nginx/html
# 这些容器在 Pod 初始化期间运行
initContainers:
- name: install
image: busybox:1.28
command:
- wget
- "-O"
- "/work-dir/index.html"
- http://info.cern.ch
volumeMounts:
- name: workdir
mountPath: "/work-dir"
dnsPolicy: Default
volumes:
- name: workdir
emptyDir: {}
apiVersion: v1
kind: Pod
metadata:
name: myapp-pod
labels:
app.kubernetes.io/name: 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 two-init.yaml
- 检查其Pod状态:
[root@master pod]# kubectl get pods myapp-pod
NAME READY STATUS RESTARTS AGE
myapp-pod 0/1 Init:0/2 0 2s
[root@master pod]#
- 如需查看 Pod 内 Init 容器的日志,请执行:
kubectl logs myapp-pod -c init-myservice # 查看第一个 Init 容器
kubectl logs myapp-pod -c init-mydb # 查看第二个 Init 容器
创建这些 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 apply -f services.yaml
- 这样你将能看到这些 Init 容器执行完毕,随后
my-app
的 Pod 进入Running
状态:
[root@master pod]# kubectl get pods myapp-pod
NAME READY STATUS RESTARTS AGE
myapp-pod 1/1 Running 0 15m
[root@master pod]#
具体行为
资源
在给定的 Init 容器执行顺序下,资源使用适用于如下规则:
- 所有 Init 容器上定义的任何特定资源的 limit 或 request 的最大值,作为 Pod 有效初始 request/limit。 如果任何资源没有指定资源限制,这被视为最高限制。
- Pod 对资源的有效 limit/request是如下两者中的较大者:
- 所有应用容器对某个资源的 limit/request 之和;
- 对某个资源的有效初始 limit/request。
- 基于有效 limit/request 完成调度,这意味着 Init 容器能够为初始化过程预留资源, 这些资源在 Pod 生命周期过程中并没有被使用。
- Pod 的 有效 QoS 层,与 Init 容器和应用容器的一样。
Pod 重启的原因
调试Init容器
- 检查 Init 容器的状态
- 显示你的 Pod 的状态
kubectl get pod <pod-name>
如,状态 Init:1/2 表明两个 Init 容器中的一个已经成功完成:
NAME READY STATUS RESTARTS AGE
<pod-name> 0/1 Init:1/2 0 7s
- 获取 Init 容器详情
- Init 容器运行的更多详情
kubectl describe pod <pod-name>
- 与 Pod 名称一起传递 Init 容器名称,以访问容器的日志。
kubectl logs <pod-name> -c <init-container-2>
理解 Pod 的状态
以 Init:
开头的 Pod 状态汇总了 Init 容器执行的状态。 下表介绍调试 Init 容器时可能看到的一些状态值示例。
状态 | 含义 |
---|---|
Init:N/M | Pod 包含 M 个 Init 容器,其中 N 个已经运行完成。 |
Init:Error | Init 容器已执行失败。 |
Init:CrashLoopBackOff | Init 容器执行总是失败。 |
Pending | Pod 还没有开始执行 Init 容器。正在被调度 |
PodInitializingor Running | Pod 已经完成执行 Init 容器。 |