Kubernetes:炉膛的生活

注意事项 佩雷夫 :这是Red Hat OpenShift团队的Michael Hausenblas撰写的这篇小文章(但很宽敞!),我们非常喜欢,以至于它被发现后几乎立即被添加到我们的Kubernetes内部知识库中。 并且由于其中提供的信息显然将对更广泛的俄语IT社区有用,因此我们很乐意发布其翻译。



您可能已经猜到了,该出版物的标题是1998年皮克斯动画片《虫虫的生活》 (在俄罗斯的票房中被称为“电影冒险”或“昆虫的生命”- 大约翻译的引用,的确如此:在蚂蚁之间Kubernetes与工人和壁炉有很多共同点。 我们将从实用的角度仔细研究炉膛的整个生命周期,尤其是在启动和关闭时影响行为的方式以及检查应用程序状态的正确方法。

不管您是在自己之下创建,还是更好地通过诸如DeploymentDaemonSetStatefulSet之类的控制器创建, Under都可以处于以下阶段之一:

  • 待处理 :API服务器创建了一个pod资源,并将其保存在etcd中,但尚未计划,并且未从注册表中收到其容器的图像;
  • 运行 (运行):将under分配给该节点,并且所有容器均由kubelet创建;
  • 成功 (成功完成):所有炉膛容器的操作已成功完成,并且不会重新启动;
  • 失败 :炉膛中的所有容器已停止运行,并且至少一个容器发生了故障;
  • 未知 :通常,由于与kubelet交互时发生错误,API Server无法查询炉床的状态。

当执行kubectl get pod ,请注意STATUS列可以显示其他(这五个除外)消息-例如, Init:0/1CrashLoopBackOff 。 这是因为该阶段只是炉膛总体状态的一部分。 找出确切发生的一个好方法是运行kubectl describe pod/$PODNAME并查看下面的kubectl describe pod/$PODNAME条目Events: 她显示了相关操作的列表:容器图像已收到,已计划,容器处于“ 不良”状态。

现在来看一个从开始到结束的炉膛生命周期的特定示例,如下图所示:



发生什么事了 步骤如下:

  1. 这没有在图中显示,但是在开始时启动一个特殊的基础容器,并设置其余容器加入的名称空间。
  2. 启动的第一个用户定义容器是init容器 ; 它可以用于初始化任务。
  3. 接下来,同时启动主容器和启动后挂钩。 在我们的情况下,这会在4秒后发生。 为每个容器定义了挂钩
  4. 然后,在第7秒,再次对每个容器进行活动性和就绪性测试。
  5. 在第11秒,当击杀船底时,会触发一个预停钩,并在宽限期过后杀死主集装箱。 请注意,实际上,广告连播完成过程稍微复杂一些。

我如何得出上述顺序及其时间安排? 为此,我们使用了以下Deployment ,它是专门为跟踪事件的顺序而创建的(它本身不是很有用):

 kind: Deployment apiVersion: apps/v1beta1 metadata: name: loap spec: replicas: 1 template: metadata: labels: app: loap spec: initContainers: - name: init image: busybox command: ['sh', '-c', 'echo $(date +%s): INIT >> /loap/timing'] volumeMounts: - mountPath: /loap name: timing containers: - name: main image: busybox command: ['sh', '-c', 'echo $(date +%s): START >> /loap/timing; sleep 10; echo $(date +%s): END >> /loap/timing;'] volumeMounts: - mountPath: /loap name: timing livenessProbe: exec: command: ['sh', '-c', 'echo $(date +%s): LIVENESS >> /loap/timing'] readinessProbe: exec: command: ['sh', '-c', 'echo $(date +%s): READINESS >> /loap/timing'] lifecycle: postStart: exec: command: ['sh', '-c', 'echo $(date +%s): POST-START >> /loap/timing'] preStop: exec: command: ['sh', '-c', 'echo $(date +%s): PRE-HOOK >> /loap/timing'] volumes: - name: timing hostPath: path: /tmp/loap 

请注意,为了在主容器工作时强制关闭Pod,我运行了以下命令:

 $ kubectl scale deployment loap --replicas=0 

我们查看了正在发生的特定事件序列,现在可以继续进行-进入炉床生命周期管理领域的实践。 它们如下:

  • 使用初始化容器准备正常操作的炉床。 例如,要获取外部数据,请在数据库中创建表,或者等待它所依赖的服务的可用性。 如有必要,您可以创建许多初始化容器,并且所有它们必须在启动常规容器之前成功完成。
  • 始终添加livenessProbereadinessProbekubelet欧姆使用第一个来了解是否以及何时重新启动容器, 部署欧姆来确定滚动更新是否成功。 服务使用第二个参数确定到子节点的通信方向。 如果未定义这些样本,则两个样本的kubelet均假定它们已成功完成。 这导致两个结果:a)无法应用重新启动策略 ,b)炉膛中的容器立即从它们所面临的服务接收流量,即使它们仍在忙于启动过程。
  • 使用挂钩正确初始化容器并完全销毁它。 例如,这在应用程序运行时非常有用,该应用程序的源代码您无权访问或无法修改,但需要一些初始化或完成准备工作(例如,清除数据库连接)。 请注意,使用service时 ,关闭API服务器,端点控制器和kube-proxy可能需要一些时间(例如,从iptables中删除相应的条目)。 因此,终止您的工作可能会影响应用程序的请求。 通常,要解决此问题,只需一个带有睡眠调用的钩子就足够了。
  • 为了调试需求和总体理解为什么停止工作,应用程序可以写入/dev/termination-log ,并且可以使用kubectl describe pod …查看消息。 这些默认设置可通过terminationMessagePath和/或使用子规范中的TerminationMessagePolicy进行更改-有关更多详细信息,请参见API参考

该出版物未讨论初始化程序 (有关 初始化程序的 一些详细信息,请参见本材料的末尾- 大约翻译 。 这是Kubernetes 1.7中引入的全新概念。 初始化程序在控制平面(API Server)中工作,而不是在kubelet上下文中工作,并且可用于丰富炉膛,例如,使用小车容器或强制执行安全策略。 另外,未考虑PodPresets ,将来可以用更灵活的初始化器概念代替它。

译者的PS


另请参阅我们的博客:

Source: https://habr.com/ru/post/zh-CN415393/


All Articles