边车容器
Kubernetes v1.29 [beta]
边车容器是与主应用容器在同一个 Pod 中运行的辅助容器。 这些容器通过提供额外的服务或功能(如日志记录、监控、安全性或数据同步)来增强或扩展主应用容器的功能, 而无需直接修改主应用代码。
通常,一个 Pod 中只有一个应用容器。 例如,如果你有一个需要本地 Web 服务器的 Web 应用, 则本地 Web 服务器以边车容器形式运行,而 Web 应用本身以应用容器形式运行。
Kubernetes 中的边车容器
Kubernetes 将边车容器作为 Init 容器的一个特例来实现, Pod 启动后,边车容器仍保持运行状态。 本文档使用术语"常规 Init 容器"来明确指代仅在 Pod 启动期间运行的容器。
如果你的集群启用了 SidecarContainers
特性门控
(该特性自 Kubernetes v1.29 起默认启用),你可以为 Pod 的 initContainers
字段中列出的容器指定 restartPolicy
。
这些可重新启动的边车(Sidecar) 容器独立于其他 Init 容器以及同一 Pod 内的主应用容器,
这些容器可以启动、停止和重新启动,而不会影响主应用容器和其他 Init 容器。
你还可以运行包含多个未标记为 Init 或边车容器的 Pod。
如果作为一个整体而言,某个 Pod 中的所有容器都要运行,但你不需要控制哪些容器先启动或停止,那么这种设置是合适的。
如果你使用的是不支持容器级 restartPolicy
字段的旧版本 Kubernetes,你也可以这样做。
应用示例
下面是一个包含两个容器的 Deployment 示例,其中一个容器是边车形式:
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp
labels:
app: myapp
spec:
replicas: 1
selector:
matchLabels:
app: myapp
template:
metadata:
labels:
app: myapp
spec:
containers:
- name: myapp
image: alpine:latest
command: ['sh', '-c', 'while true; do echo "logging" >> /opt/logs.txt; sleep 1; done']
volumeMounts:
- name: data
mountPath: /opt
initContainers:
- name: logshipper
image: alpine:latest
restartPolicy: Always
command: ['sh', '-c', 'tail -F /opt/logs.txt']
volumeMounts:
- name: data
mountPath: /opt
volumes:
- name: data
emptyDir: {}
边车容器和 Pod 生命周期
如果创建 Init 容器时将 restartPolicy
设置为 Always
,
则它将在整个 Pod 的生命周期内启动并持续运行。这对于运行与主应用容器分离的支持服务非常有帮助。
如果为此 Init 容器指定了 readinessProbe
,其结果将用于确定 Pod 的 ready
状态。
由于这些容器被定义为 Init 容器,所以它们享有与其他 Init 容器相同的顺序和按序执行保证, 从而允许将边车容器与常规 Init 容器混合使用,支持复杂的 Pod 初始化流程。
与常规 Init 容器相比,在 initContainers
中定义的边车容器在启动后继续运行。
当 Pod 的 .spec.initContainers
中有多个条目时,这一点非常重要。
在边车风格的 Init 容器运行后(kubelet 将该 Init 容器的 started
状态设置为 true),
kubelet 启动 .spec.initContainers
这一有序列表中的下一个 Init 容器。
该状态要么因为容器中有一个正在运行的进程且没有定义启动探针而变为 true,
要么是其 startupProbe
成功而返回的结果。
在 Pod 终止时, kubelet 会推迟终止边车容器,直到主应用容器已完全停止。边车容器随后将按照它们在 Pod 规约中出现的相反顺序被关闭。 这种方法确保了在不再需要边车服务之前这些边车继续发挥作用,以支持 Pod 内的其他容器。
带边车容器的 Job
如果你定义 Job 时使用基于 Kubernetes 风格 Init 容器的边车容器, 各个 Pod 中的边车容器不会阻止 Job 在主容器结束后进入完成状态。
以下是一个具有两个容器的 Job 示例,其中一个是边车:
apiVersion: batch/v1
kind: Job
metadata:
name: myjob
spec:
template:
spec:
containers:
- name: myjob
image: alpine:latest
command: ['sh', '-c', 'echo "logging" > /opt/logs.txt']
volumeMounts:
- name: data
mountPath: /opt
initContainers:
- name: logshipper
image: alpine:latest
restartPolicy: Always
command: ['sh', '-c', 'tail -F /opt/logs.txt']
volumeMounts:
- name: data
mountPath: /opt
restartPolicy: Never
volumes:
- name: data
emptyDir: {}
与应用容器的区别
边车容器与同一 Pod 中的应用容器并行运行。不过边车容器不执行主应用逻辑,而是为主应用提供支持功能。
边车容器具有独立的生命周期。它们可以独立于应用容器启动、停止和重启。 这意味着你可以更新、扩展或维护边车容器,而不影响主应用。
边车容器与主容器共享相同的网络和存储命名空间。这种共存使它们能够紧密交互并共享资源。
从 Kubernetes 的角度来看,边车容器的体面终止(Graceful Termination)相对不那么重要。
当其他容器耗尽了分配的体面终止时间后,边车容器将会比预期更快地接收到 SIGTERM
,随后是 SIGKILL
。
因此,在 Pod 终止时,边车容器退出码不为 0
(0
表示成功退出)是正常的,
通常应该被外部工具忽略。
与 Init 容器的区别
边车容器与主容器并行工作,扩展其功能并提供附加服务。
边车容器与主应用容器同时运行。它们在整个 Pod 的生命周期中都处于活动状态,并且可以独立于主容器启动和停止。 与 Init 容器不同, 边车容器支持探针来控制其生命周期。
边车容器可以直接与主应用容器交互,因为与 Init 容器一样, 它们总是与应用容器共享相同的网络,并且还可以选择共享卷(文件系统)。
Init 容器在主容器启动之前停止,因此 Init 容器无法与 Pod 中的应用容器交换消息。
所有数据传递都是单向的(例如,Init 容器可以将信息放入 emptyDir
卷中)。
容器内的资源共享
假如执行顺序为 Init 容器、边车容器和应用容器,则关于资源用量适用以下规则:
- 所有 Init 容器上定义的任何特定资源的 limit 或 request 的最大值,作为 Pod 有效初始 request/limit。 如果任何资源没有指定资源限制,则被视为最高限制。
- Pod 对资源的 有效 limit/request 是如下两者中的较大者:
- 所有应用容器对某个资源的 limit/request 之和
- Init 容器中对某个资源的有效 limit/request
- 系统基于有效的 limit/request 完成调度,这意味着 Init 容器能够为初始化过程预留资源, 而这些资源在 Pod 的生命周期中不再被使用。
- Pod 的 有效 QoS 级别,对于 Init 容器和应用容器而言是相同的。
配额和限制适用于 Pod 的有效请求和限制值。
边车容器和 Linux Cgroup
在 Linux 上,Pod Cgroup 的资源分配基于 Pod 级别的有效资源请求和限制,这一点与调度器相同。
接下来
- 了解如何采用边车容器。
- 阅读关于原生边车容器的博文。
- 阅读如何创建具有 Init 容器的 Pod。
- 了解探针类型: 存活态探针、就绪态探针、启动探针。
- 了解 Pod 开销。