ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Kubernetes Init 容器深度解析:kubernetes-handbook 中的概念、配置与实战指南

Kubernetes Init 容器深度解析:kubernetes-handbook 中的概念、配置与实战指南 教程云原生容器编排【免费下载链接】kubernetes-handbookKubernetes 架构与生态从云原生到 AI 原生基础设施的构建指南项目地址https://gitcode.com/gh_mirrors/ku/kubernetes-handbook点击查看免费下载Init 容器Init Containers是 Kubernetes 中一类专用的容器它们在应用容器启动之前按顺序运行完成常用于承载应用镜像中不适合包含的初始化工具与安装脚本。本文以 kubernetes-handbook 的 concepts/init-containers.md 为骨架系统讲解 Init 容器的核心概念、两种声明语法、具体执行行为、资源计算规则与版本兼容性并结合仓库中 dashboard、Redis StatefulSet、Istio/SOFAMesh 等真实清单文件给出可直接复制使用的实战示例。读完本文你将掌握 Init 容器的完整配置方法、调试手段以及利用其做依赖等待、配置生成、证书准备、网络劫持等场景的实现方案。理解 Init 容器Pod 是 Kubernetes 中可以创建的最小部署单元一个 Pod 中可以运行多个容器应用运行在这些普通容器中同时Pod 也可以拥有一个或多个先于应用容器启动的 Init 容器。从声明方式上看Init 容器与普通容器非常相似但存在两点本质区别Init 容器总是运行到成功完成为止每个 Init 容器都必须在下一个 Init 容器启动之前成功完成。如果 Pod 的某个 Init 容器失败Kubernetes 会不断重启该 Pod直到 Init 容器成功为止。唯一的例外是如果 Pod 对应的restartPolicy为Never失败后不会重新启动。在 PodSpec 中通过initContainers字段以v1.Container类型对象的 JSON 数组形式声明 Init 容器与应用的containers数组并列。Init 容器的状态在status.initContainerStatuses字段中以容器状态数组的格式返回结构类似status.containerStatuses字段。与普通容器的不同之处Init 容器支持应用容器的全部字段和特性包括资源限制resource limits、数据卷volumes和安全设置security settings。但有两点例外资源请求和限制的处理稍有不同遵循独立的有效初始请求/限制计算规则见下文资源小节不支持 Readiness Probe因为 Init 容器必须在 Pod 就绪之前运行完成它无法定义不同于完成completion状态的就绪readiness状态这一点会在 API 验证阶段被强制检查。当为一个 Pod 指定了多个 Init 容器时这些容器会按顺序一次运行一个只有当前面的 Init 容器运行成功才会启动下一个。当所有 Init 容器都运行完成后Kubernetes 才初始化 Pod 并启动应用容器。Init 容器能做什么因为 Init 容器使用与应用程序容器分离的单独镜像它们的启动相关代码具有如下优势隔离敏感工具Init 容器可以包含并运行实用工具但出于安全考虑不建议将这些工具放进应用程序容器镜像中。按需安装依赖可以包含使用工具和定制化代码来完成安装而不必把这些工具打进应用镜像。例如创建镜像时没必要FROM另一个镜像只需要在安装过程中使用sed、awk、python或dig这类工具即可。职责分离应用程序镜像可以分离出创建和部署的角色而不必强行联合构建一个包含全部工具链的单一镜像。独立的文件系统视图与权限边界Init 容器使用独立的 Linux Namespace相对应用程序容器拥有不同的文件系统视图。因此它们可以具有访问 Secret 的权限而应用程序容器则不能。天然的启动屏障Init 容器必须在应用容器启动之前运行完成而应用容器是并行运行的所以 Init 容器提供了一种简单的阻塞或延迟应用容器启动的方法直到满足一组先决条件。典型用途示例下面列举 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 仓库到数据卷将代码或资源在启动前同步进共享 Volume。动态生成配置文件将配置值例如 POD_IP写入配置文件运行模板工具如 Jinja为主应用容器生成配置。真实仓库中的 Init 容器实战kubernetes-handbook 仓库的 manifests 目录中保留了多个使用 Init 容器的真实清单可作为上述用途的印证证书准备dashboard在 manifests/dashboard-1.7.1/kubernetes-dashboard.yaml 中kubernetes-dashboard-init容器将证书写入共享卷kubernetes-dashboard-certs的/certs目录随后主容器kubernetes-dashboard以--tls-key-file/certs/dashboard.key和--tls-cert-file/certs/dashboard.crt参数读取该证书实现了先准备凭证、再启动服务的经典初始化模式。集群成员引导Redis StatefulSet在 manifests/openebs/redis-statefulset.yml 中一个 StatefulSet 定义了install和bootstrap两个 Init 容器前者把 Redis 二进制安装进共享opt卷后者通过peer-finder工具配合-on-start脚本完成集群成员发现与引导随后主容器才启动redis-server。这正好对应安装依赖 等待先决条件两类用途也展示了 Init 容器按顺序执行的价值。使用 Init 容器两种声明语法Kubernetes 1.5 注解annotation语法下面是 Kubernetes 1.5 版本的 YAML 文件展示了一个具有 2 个 Init 容器的简单 Pod。第一个等待myservice启动第二个等待mydb启动一旦这两个 Service 都启动完成Pod 才开始启动apiVersion: v1 kind: Pod metadata: name: myapp-pod labels: app: myapp annotations: pod.beta.kubernetes.io/init-containers: [ { name: init-myservice, image: busybox, command: [sh, -c, until nslookup myservice; do echo waiting for myservice; sleep 2; done;] }, { name: init-mydb, image: busybox, command: [sh, -c, until nslookup mydb; do echo waiting for mydb; sleep 2; done;] } ] spec: containers: - name: myapp-container image: busybox command: [sh, -c, echo The app is running! sleep 3600]Kubernetes 1.6 标准字段语法这是 Kubernetes 1.6 版本引入的新语法将 Init 容器的声明直接放入spec.initContainers字段中老的 annotation 语法仍然可以使用但推荐使用新语法apiVersion: v1 kind: Pod metadata: name: myapp-pod labels: app: myapp spec: containers: - name: myapp-container image: busybox command: [sh, -c, echo The app is running! sleep 3600] initContainers: - name: init-myservice image: busybox command: [sh, -c, until nslookup myservice; do echo waiting for myservice; sleep 2; done;] - name: init-mydb image: busybox command: [sh, -c, until nslookup mydb; do echo waiting for mydb; sleep 2; done;]注意版本兼容性问题1.5 版本的注解语法在 1.6 和 1.7 版本中仍然可以使用但推荐使用 1.6 版本的新语法。Kubernetes 1.8 以后的版本只支持新语法。在 Kubernetes 1.6 版本中Init 容器在 API 中新建了一个字段虽然仍可使用 beta 注解但在未来发行版中注解将会被废弃。配套的 Service 定义下面的 YAML 展示了mydb和myservice两个 Service供上述 Init 容器的nslookup探测使用kind: Service apiVersion: v1 metadata: name: myservice spec: ports: - protocol: TCP port: 80 targetPort: 9376 --- kind: Service apiVersion: v1 metadata: name: mydb spec: ports: - protocol: TCP port: 80 targetPort: 9377启动与调试命令这个 Pod 可以使用下面的命令进行启动和调试$ kubectl create -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: appmyapp 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:[seccompunconfined] 13s 13s 1 {kubelet 172.17.4.201} spec.initContainers{init-myservice} Normal Started Started container with docker id 5ced34a04634 $ kubectl logs myapp-pod -c init-myservice # Inspect the first init container $ kubectl logs myapp-pod -c init-mydb # Inspect the second init container一旦启动了mydb和myservice这两个 Service可以看到 Init 容器完成、myapp-pod进入 Running 状态$ kubectl create -f services.yaml service myservice created service mydb created $ kubectl get -f myapp.yaml NAME READY STATUS RESTARTS AGE myapp-pod 1/1 Running 0 9m从上面的输出可以提炼出三个关键的排障入口STATUS列中的Init:0/2表示 2 个 Init 容器已完成 0 个是判断初始化进度的第一信号kubectl describe的Events中SubObjectPath字段如spec.initContainers{init-myservice}精确指向当前处于活动状态的 Init 容器配合Pulling/Pulled/Created/Started事件序列可以定位卡在哪一步kubectl logs myapp-pod -c init-container-name用-c指定容器名可以单独查看某个 Init 容器的日志。这个例子非常简单但它足以启发我们创建自己的 Init 容器。Init 容器的具体行为在 Pod 启动过程中Init 容器会按顺序在网络和数据卷初始化之后启动。每个容器必须在下一个容器启动之前成功退出如果因为运行时错误或失败退出导致容器启动失败kubelet 会根据 Pod 的restartPolicy指定的策略进行重试。需要注意即使restartPolicy设置为AlwaysInit 容器失败时也是以Always策略重启而不是直接拉起应用容器。其他关键行为如下就绪与端口在所有 Init 容器成功之前Pod 不会变成Ready状态Init 容器的端口不会在 Service 中进行聚合。正在初始化中的 Pod 处于Pending状态但Initializing状态会被置为 true。重启后重跑如果 Pod 重启所有 Init 容器必须重新执行。字段修改限制对 Init 容器 spec 的修改被限制在image字段修改其他字段都不会生效。更改 Init 容器的 image 字段等价于重启该 Pod。幂等性要求因为 Init 容器可能被重启、重试或重新执行所以 Init 容器的代码应该是幂等的。特别是当写入EmptyDir卷中的文件时代码应对输出文件可能已经存在做好准备例如先删除或覆盖而不是追加导致重复内容。探测限制Init 容器具有应用容器的所有字段除了readinessProbe——Init 容器无法定义不同于完成completion状态的就绪状态这会在验证过程中强制执行。超时兜底在 Pod 上使用activeDeadlineSeconds在容器上使用livenessProbe可以避免 Init 容器一直失败相当于为 Init 容器设置一个活跃期限。命名唯一性Pod 中每个 app 容器和 Init 容器的名称必须唯一与任何其他容器共享同一个名称会在验证时抛出错误。资源Resources计算规则为 Init 容器指定顺序和执行逻辑时资源使用遵循以下规则在所有 Init 容器上定义的任何特殊资源请求或限制的最大值即有效初始请求/限制effective initial request/limitPod 对资源的有效请求/限制要高于以下两者所有应用容器对某个资源的请求/限制之和对某个资源的有效初始请求/限制调度基于有效请求/限制完成这意味着 Init 容器能够为初始化预留资源这些资源在 Pod 生命周期过程中并未被实际使用初始化完成后即释放给调度Pod 的有效 QoS 层是 Init 容器和应用容器相同的 QoS 层。配额quota和限制limit基于有效 Pod 请求和限制来应用Pod 级别的 cgroups 也与调度器一样基于有效 Pod 请求和限制来配置。这一规则的意义在于Init 容器峰值资源需求可能远超应用容器的稳态需求例如初始化时需要克隆大仓库、编译或拷贝数据Kubernetes 会以所有 Init 容器中的最大值来参与调度决策避免因初始化瞬间资源不足而导致调度失败或 OOM。Pod 重启导致 Init 容器重新执行的原因Pod 重启会导致 Init 容器重新执行主要有如下几个原因用户更新 PodSpec 导致 Init 容器镜像改变——注意应用容器镜像的变更只会重启应用容器不会触发 Init 容器重跑Pod 基础设施容器被重启——这不多见但某些具有 root 权限可访问 Node 的人可能会这样做restartPolicy为Always时的强制重启——Pod 中所有容器被终止并强制重启此时由于垃圾收集可能导致 Init 容器完整的记录丢失从而触发重跑。与 Service Mesh 的结合Init 容器做网络劫持Init 容器先于应用容器执行 拥有独立安全上下文的特性是 Service Mesh 数据面注入的核心实现手段。在 kubernetes-handbook 的 Service Mesh 清单中可以找到两个典型证据在 manifests/istio/productpage-v1-istio.json 中名为init的容器使用docker.io/istio/init:0.1镜像以-p 15001 -u 1337参数运行并通过securityContext.capabilities.add: [NET_ADMIN]获取网络管理能力——它正是利用 iptables 规则在应用容器启动前完成出/入流量劫持为后续 Sidecar 代理接管流量做准备。在 manifests/sofa-mesh/sofa-mesh-demo.yaml 的 Sidecar 注入模板中istio-init容器的参数监听端口-p、运行用户-u 1337、拦截模式-m、出入站 IP 范围-i/-x、出入站端口-b/-d全部由模板引擎根据 Pod 的 annotation 动态生成展示了 Init 容器在自动注入场景中的灵活参数化能力。更深层的原理是Init 容器共享 Pod 的网络命名空间Net Namespace因此它修改的 iptables 规则在应用容器启动后依然生效这正是在应用容器看不到任何初始化痕迹、但流量已被接管的原因。相关的 Service Mesh 流量劫持机制可进一步阅读 understand-sidecar-injection-and-traffic-hijack-in-istio-service-mesh.md。支持与兼容性API Server 版本为1.6 或更高版本的集群通过使用spec.initContainers字段来支持 Init 容器。之前的版本可以使用 alpha 和 beta 注解支持 Init 容器。spec.initContainers字段也被加入到 alpha 和 beta 注解中所以Kubernetes 1.3.0 或更高版本可以执行 Init 容器并且 1.6 版本的 API Server 能够安全地回退到 1.5.x 版本而不会使已创建的 Pod 失去 Init 容器的功能。归纳成一张兼容性速查表Kubernetes 版本Init 容器支持方式说明1.3.0 ~ 1.5.xalpha / beta 注解通过pod.beta.kubernetes.io/init-containers注解声明1.6 ~ 1.7注解 spec.initContainers字段新字段引入注解仍可用但已标记废弃趋势1.8仅spec.initContainers字段注解语法不再支持从仓库的索引结构看Init 容器位于 SUMMARY.md 中 concepts核心概念章节与 Pod、Pod 生命周期、Pod Hook 等文档共同构成了理解 Pod 运行机制的知识链路。实际使用时建议将 Init 容器与 Volume 与存储、ConfigMap、Secret 结合完成配置注入与数据准备的完整闭环。总结Init 容器是 Kubernetes 中一种先决条件容器按顺序执行、必须成功、失败即重启restartPolicy: Never除外这使它天然适合依赖等待、工具隔离、配置生成、证书准备与网络劫持等初始化场景。使用时需牢记三个要点代码保持幂等可能被重跑、共享 Pod 网络与数据卷初始化成果可见于应用容器、资源按所有 Init 容器最大值参与调度初始化峰值需纳入容量规划。声明语法上优先使用spec.initContainers字段1.6避免使用已被废弃的 beta 注解。结合 kubernetes-handbook 仓库中的 dashboard、Redis StatefulSet 与 Istio/SOFAMesh 清单你可以快速在自己的集群中落地上述模式。赞分享教程云原生容器编排【免费下载链接】kubernetes-handbookKubernetes 架构与生态从云原生到 AI 原生基础设施的构建指南项目地址https://gitcode.com/gh_mirrors/ku/kubernetes-handbook点击查看免费下载相关推荐Kubernetes Pod 开销详解概念与配置指南Kubernetes Pod 开销详解概念与配置指南 什么是 Pod 开销 在 Kubernetes 集群中运行 Pod 时除了容器本身所需的资源外Po文档教程云原生Kubernetes Handbook配置 Pod 的 liveness 与 readiness 探针实战指南Kubernetes Handbook配置 Pod 的 liveness 与 readiness 探针实战指南 本指南基于 kubernetes handbo教程云原生容器编排如何快速上手ALMA-13B5分钟完成安装与基础翻译测试如何快速上手ALMA 13B5分钟完成安装与基础翻译测试 ALMA 13B是一款基于先进语言模型的翻译工具Advanced Language Model b上一篇JWT安全配置终极指南10个关键步骤确保你的应用无懈可击下一篇Airbyte Productboard 声明式 Source 连接器深度解析基于 Low-Code CDK 的 Manifest-only 实现创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表