Kubernetes pod的生命周期
本文翻译自:Kubernetes: Lifecycle of a Pod
原文出处:Kubernetes: Lifecycle of a Pod - DZone Integration
参考:Container Lifecycle Hooks | Kubernetes
查看 Kubernetes pod 的生命周期可以帮助了解可以在流行的容器软件中调度的最小工作单元发生了什么。
在 Kubernetes 中,Pod 是能被调度的最小工作单元。
一个 Pod 封装了一个应用的容器,存贮资源,唯一的网络 IP 和管理容器运行的其他选项。
理想情况下,Pod 并不会被集群直接部署,而是用更高层次的抽象层。应用通常通过更高层的资源对象部署,比如:Deployments, Replication Sets, Daemon Sets, Stateful Sets 或者 Jobs。和 Pod 进行交互主要用来解决问题,因此深入 Pod 是很重要的。
Pod 的状态
整个 Pod 的声明周期中,可以达到以下状态:
- Pending:Pod 被 Kubernetes 系统接收(accepted),但是没有其容器还没有被完全创建。
- Running:Pod 被调度到某一个 Node 上,所有的容器都被创建并且至少有一个容器是 Running 状态。
- Succeeded:Pod 中所有的容器都以状态 0 退出并且不会重启。
- Failed:Pod 中所有的容器都已经退出,但是至少有一个容器退出状态不为 0。
- CrashLoopBackoff:容器启动失败并且会被不断重试。
pod的生命周期
Pod对象自从其创建开始至其终止退出的时间范围称为其生命周期。在这段时间中,Pod会处于多种不同的状态,并执行一些操作。
其中,创建主容器(main container)为必需的操作,其他可选的操作还包括运行初始化容器(init container)、容器启动后钩子(post start hook)、容器的存活性探测(liveness probe)、就绪性探测(readiness probe)以及容器终止前钩子(pre stop hook)等,这些操作是否执行则取决于Pod的定义。如下图所示:
Pod 的实现需要使用一个中间容器,这个容器叫作 Infra 容器。在这个 Pod 中,Infra 容器永远都是第一个被创建的容器,而其他用户定义的容器,则通过 Join Network Namespace 的方式,与 Infra 容器关联在一起。
在 Pod 中,所有 Init Container 定义的容器,都会比 spec.containers 定义的用户容器先启动。并且,Init Container 容器会按顺序逐一启动,而直到它们都启动并且退出了,用户容器才会启动。
Pod 的生命周期
Pod的status字段是一个PodStatus的对象,PodStatus中有一个phase字段。无论是手动创建还是通过Deployment等控制器创建,Pod对象总是应该处于其生命进程中以下几个阶段(phase)之一。
挂起(Pending):API Server创建了pod资源对象已存入etcd中,但它尚未被调度完成,或者仍处于从仓库下载镜像的过程中。
运行中(Running):Pod已经被调度至某节点,并且所有容器都已经被kubelet创建完成。
成功(Succeeded):Pod中的所有容器都已经成功终止并且不会被重启
失败(Failed):Pod中的所有容器都已终止了,并且至少有一个容器是因为失败终止。即容器以非0状态退出或者被系统禁止。
未知(Unknown):Api Server无法正常获取到Pod对象的状态信息,通常是由于无法与所在工作节点的kubelet通信所致。
注意:当一个 Pod 被删除时,它会Terminating被一些 kubectl 命令显示为。此Terminating状态不是 Pod 阶段之一。Pod 默认的正常终止的期限,默认为 30 秒。您可以使用该标志--force来强行终止pod。
容器的诞生
现在我们来看看导致一个容器创建的所有事件。
用户通过kubectl或其他API客户端提交了Pod Spec给API Server。
API Server尝试着将Pod对象的相关信息存入etcd中,待写入操作执行完成,API Server即会返回确认信息至客户端。
API Server开始反映etcd中的状态变化。
所有的kubernetes组件均使用“watch”机制来跟踪检查API Server上的相关的变动。
kube-scheduler(调度器)通过其“watcher”觉察到API Server创建了新的Pod对象但尚未绑定至任何工作节点。(在管理节点上面还有两个重要组件,schedule,用户创建pod会被,会被apiserver接收到,apiserver就会告诉schedule有这么一个调度需求去做调度,schedule就会去做调度,先看你的pod需要多少资源,也就是你的需求是什么,然后去看集群里面资源利用状况,这个资源状况哪里来的呢?每个节点上面有个kubelet,第一它会将资源信息上报,报告每个节点的健康状况和资源使用情况,apiserver接收到这些请求之后,同样将数据存放到etcd里面,同时schedule能够接受到变化的请求,所以shcedule是知道集群整个资源利用情况的。)
kube-scheduler为Pod对象挑选一个工作节点并将结果信息更新至API Server。
调度结果信息由API Server更新至etcd存储系统,而且API Server也开始反映此Pod对象的调度结果。
Pod被调度到的目标工作节点上的kubelet尝试在当前节点上调用Docker启动容器,并将容器的结果状态返回送至API Server。
API Server将Pod状态信息存入etcd系统中。
在etcd确认写入操作成功完成后,API Server将确认信息发送至相关的kubelet,事件将通过它被接受。
或者下面步骤也可以
- kubectl 或者其他 API 客户端提交 Pod spec 到 API server。
- API server 会将 Pod 对象写到 etcd 数据存储中。一旦写操作成功,一个 ack 将会被发送回 API server 和客户端。
- 现在 API server 反映了 etcd 的状态变化。
- 所有的 Kubernetes 组件通过 watch API 保持对 API server 相关变化的检测。
- 当前情况下,kube-scheduler(通过 watcher)发现一个新的 Pod 通过 API server 被创建,但是还没有绑定到任何一个 node。
- Kube-scheduler 会给当前新创建的 Pod 分配一个 node,并跟新 API server。
- “Pod 被分配到某个节点” 这个变化将会被传递给 etcd 数据存储。API server 也会在其 Pod project 上体现出节点分配。
- 每个节点上的 Kubelet 也会运行 watcher,对 API server 持续监控。在目标 node 上,kubelet 知道一个新的 Pod 已经分配。
- Kubelet 在 node 上通过调用 Docker 启动 Pod,并且将跟新的容器状态发送回 API server。
- API server 将 Pod 状态持久化到 etcd 中。h
- 一旦 etcd 发送成功写操作的 ack 到 API server,API server 会回复 Kubelet 一个 ack,表示事件已经被接收。
删除 Pod的逻辑
当发起一个删除 Pod 的指令时 Pod 的删除逻辑是这样的:
调用 kube-apiserver 发起删除 Pod 请求,如果删除 Pod 时没有设置 grace period 参数那么就会使用 30 秒的默认值,否则就会使用用户指定的 grace period 进行优雅下线
kube-apiserver 接受到这个请求以后给相应的 Pod 标记为“删除状态”。其实 Pod 没有“删除状态”,此时 Pod 的 status 还是 Running 状态,所谓的“删除状态”只是 deletionTimestamp 和 deletionGracePeriodSeconds 字段会被设置,这时候 kubelet 或者 kube-proxy 监听到这样的 Pod 就会认为此 Pod 已经不能提供服务了,然后开始做相应的清理操作。
此时如果通过 Dashbord 查看 Pod 的状态是 Terminating ,其实 Terminating 也不是 Pod status 的字段的值。只是因为设置了 deletionTimestamp 和 deletionGracePeriodSeconds 字段所以 Dashbord 就会把 Pod 标记为 Terminating 状态。
(和第三条同时发生)当 kube-proxy 监听到 Pod 处于 Terminatiing 状态时就把 Pod 从 Service 的 EndPoint 中摘掉,这样对外暴露的服务就摘掉了这个 Pod,防止新的请求发送到这个 Pod 上来
kubelet 监测到 Pod 处于 Terminating 状态的话会下线 Pod, 超时时间和删除 Pod 时指定的 grace period 一致(如果没设置默认是 30 秒)
PreStop 执行完以后还有第二步杀死容器,第二部也有超时时间,这个超时时间是 grace period 减去 PreStop 耗时。如果执行 PreStop 超时或者 grace period 减去 PreStop 耗时剩余的时间不够两秒(甚至可能是负数) kubelet 会强制设置成两秒。第二部的超时时间暂且称之为 tm2, kubelet 停止容器时执行的是 docker stop -t tm2 命令。所以 tm2 的逻辑是:首先发送 term 信号到容器的一号进程,如果容器在 tm2 时间内没有停止就强制发送 kill 信号杀死容器
kubelet 执行完 PreStop 和杀死容器两步以后会回调 kube-apiserver,把 Pod 从 kube-apiserver 中删除,这次的删除是真的删除,这时候通过 API 就再也看不到这个 Pod 的信息了
Pod 生命周期中的活动
初始容器
初始容器是运行在主应用程序启动之前的容器。他们有两个重要的特征:
- 总是运行至完成状态
- 每一个初始容器都必须在下一个启动之前完成
初始容器能在主容器启动之前做一些必要的初始化操作。
比如:拷贝配置文件和修改配置。初始容器使用不同的 Linux 命名空间,所以他们有不同的文件系统视图,所以他们可以被允许访问可能不适合在主应用程序内共享的秘密。
Lifecycle Hooks
kubelet 可以运行被Container Lifecycle Hooks触发的代码。这允许用户在容器生命周期指定事件期间运行指定的代码。
存在两个被暴露出来的 hook:
- PostStart:这种 hook 在容器后立即运行,但是没有办法保证在容器的 ENTRYPOINT 之后运行。
- PreStop:这种 hook 在容器终止前被执行,是阻塞的,意味着必须在删除容器的调用之前完成 hook 的执行。
上面提到的两种 hook 都不能带参数。
容器可以通过实现的和注册该 hook 的 handler 来访问 hook。有两种类型的 hook handler 可以被容器应用:
- Exec:在 Container 的 cgroups 和名称空间内执行特定命令,例如
pre-stop.sh
,命令执行的资源消耗算在容器内。 - HTTP:对容器上指定的 endpoint 执行 HTTP 请求。
容器探针
除了 Lifecycle hooks 之外,在 Pod 生命周期中发生的另一个重要事情就是容器探针的执行。
容器探针是由容器上的 kubelet 执行的诊断。 kubelet 可以在运行容器上运行两种探针:
- livenessProbe:指示容器是否正在运行。如果活动探测失败,则 kubelet 会杀死容器,并且容器会受到其重新启动策略的影响。
- readnessProbe:指示容器是否已准备好为请求提供服务。如果此探测失败,则 endpoint controller 将从与 Pod 匹配的所有服务的端点列表中删除容器 IP。
有三种方式实现一个探针:
- ExecAction:在容器内部执行命令。如果命令返回 0,则为诊断成功。
- TCPSocketAction:对容器 IP 和指定端口执行 TCP 套接字检查。如果端口打开,则诊断被认为是成功的。
- HTTPGetAction:使用指定的端口和路径对容器 IP 执行 HTTP GET 操作。如果响应的状态代码在 200 到 400 之间,则认为诊断成功。
容器的终止
- 用户执行一个命令删除一个 Pod
- API 服务器中的 Pod 对象将随着 Pod 被认为 “死亡”(默认为 30 秒)的时间以及宽限期而更新。
- 下面的行为将会并行执行:
- 在客户端命令中列出时,状态为 “Terminating”。
- 当 Kubelet 看到因为设置了第二点中的时间而将 Pod 标记为终止时,它开始 pod 关闭过程。
- 端点控制器监视即将删除的 pod,因此从该 pod 提供服务的所有端点中删除该 pod。
- 如果 Pod 已经定义了 preStop hook,并且在 Pod 内被调用。如果 preStop hook 在 Grace time 超时后,任然为运行状态,然后用小的(2 秒)扩展宽限期调用步骤 2。
- Kubelet 向 Docker 发送 TERM 信号。
- 当 Grace period 超时,任何运行在 Pod 上的进程都会被 SIGKILL 杀死。
- Kubelet 将通过设置宽限期 0(立即删除)完成删除 API 服务器上的 Pod。 Pod 从 API 中消失,不再从客户端可见。
总结
这篇文章的想法来自 Kubernetes 创始人 Joe Beda 的精彩文章,他解释了 Kubernetes 架构的主要组成部分和 watch 概念,这对于理解 APIServer 如何工作和 etcd 功能以及 Pod 的诞生至关重要。
我们可以看到有多种方式来控制在 POD 的生命周期内发生的事件。
初始容器可以帮助移除与容器引导相关的许多复杂性,从而帮助保持主容器内的逻辑简单。
类似地,启动 preStart lifecycle hook 可以帮助运行容器启动后需要运行的任何代码(例如向监视系统或服务网格注册)。
liveness probe 和 readness probe 有助于在开始危害任何客户之前移除坏的 Pod。
优雅的 shutdown 可以作为一个 pre-stop lifecycle hook 运行,允许更优雅的退出。了解上述控制机制有助于更好地设计 Pod 和支持使用案例。
Kubernetes pod的生命周期相关推荐
- kubernetes Pod Lifecycle生命周期与livenessProbe、 readinessProbe探测方法
kuberenetes pod Liveness, Readiness and Startup Probes tags: Pod,探针,健康检测 文章目录 kuberenetes pod Livene ...
- Kubernetes Pod的生命周期(Lifecycle)
文章目录 Pod Lifecle Pod的阶段:Pod phase 容器的状态:Container states 容器的探针:Container probes 重启策略:restartPolicy P ...
- Kubernetes CKA认证运维工程师笔记-Kubernetes应用程序生命周期管理
Kubernetes CKA认证运维工程师笔记-Kubernetes应用程序生命周期管理 1. 在Kubernetes中部署应用流程 2. 使用Deployment部署Java应用 2.1 Pod与D ...
- Kubernetes中Pod的生命周期
Pod生命周期之Init容器 Init容器 Pod能够具有多个容器,应用运行在容器里面,但是它可能有一个或多个先于应用容器启动的Init容器 Init容器于普通的容器非常像,除了如下两点: Init容 ...
- Kubernetes中Sidecar生命周期管理
背景 在多个容器的Pod中,通常业务容器需要依赖sidecar.启动时sidecar需要先启动,退出时sidecar需要在业务容器退出后再退出.k8s目前对于sidecar的生命周期比较有争议,见is ...
- K8s Pod 钩子生命周期
lifecycle: postStart: #启动指令 exec:command: ["/bin/sh", "-c", "xxx"] pre ...
- Kubernetes Pod 所需要掌握的一切
文章目录 pod 简介 kubectl apply 创建 pod 创建一个 nginx pod 创建一个 执行命令的 pod kubectl create 创建 pod kubectl run 创建 ...
- 容器编排技术 -- Kubernetes Pod 生命周期
容器编排技术 -- Kubernetes Pod 生命周期 1 Pod phase 2 Pod 状态 3 容器探针 3.1 该什么时候使用存活(liveness)和就绪(readiness)探针? 4 ...
- Kubernetes之Pod生命周期详解
简述 Kubernetes 是一种用于在一组主机上运行和协同容器化应用程序的系统,提供应用部署.规划.更新维护的机制.应用运行在 kubernetes 集群之上,实现服务的扩容.缩容,执行滚动更新以及 ...
最新文章
- win7查看电脑上openCV的版本
- 怎么将jsp中var报错_招聘中不得将全日制作为限制性条件,怎么就不公平了?
- SAP MM MIGO界面里的'Delivery completed'标记
- Linux下命令行(二)之文本处理基础
- aspx页面与ascx控件脚本冲突的问题
- 操作系统(九)进程控制
- uni-app启动微信开发者工具
- 浅谈传统企业网络运营那些事儿
- wordpress阿里百秀主题v7.7
- iOS开发,多个button数组,每个数组只能选中5项,多个数组只能选择3个。
- 如何使用 SQL Server FILESTREAM 存储非结构化数据?
- iwlist/iwconfig/iw命令
- PDF文件转化成mobi格式,亲测kindle或者iReader可用!
- 光学显微镜分辨率极限
- python笔记003
- 20220904小红书笔试
- Git-fatal: unable to access ‘https://gitlab.XX.git/‘: Could not resolve host: gitlab.XX.com.cn
- stm32——中断优先级管理
- Mac--键盘输入的技巧
- 多重纹理——像素着色器