Kubernetes之Pods

  参考官方文档:https://kubernetes.io/zh/docs/concepts/workloads/pods/

  理解Pod

  Pod是Kubernetes应用程序的基本执行单元,即它是Kubernetes对象模型中创建或部署的最小和最简单的单元。Pod表示在集群上运行的进程。

  Pod 封装了应用程序容器(或者在某些情况下封装多个容器)、存储资源、唯一网络 IP 以及控制容器应该如何运行的选项。Pod 表示部署单元,Kubernetes 中应用程序的单个实例,它可能由单个 容器 或少量紧密耦合并共享资源的容器组成。

  Docker是Kubernetes Pod中最常用的容器,但Pod也能智齿其他的容器。

  Kubernetes集群中的Pod可被用于以下两个主要用途:

  • 运行单个容器的Pod:每个Pod一个容器模型是最常见的Kubernetes用例,在这种情况下,可以将Pod看做单个容器的包装器,并且Kubernetes直接管理Pod,而不是容器
  • 运行多个协同工作的Pod:Pod 可能封装由多个紧密耦合且需要共享资源的共处容器组成的应用程序。 这些位于同一位置的容器可能形成单个内聚的服务单元。一个容器将文件从共享卷提供给公众,而另一个单独的“挂斗”(sidecar)容器则刷新或更新这些文件。Pod 将这些容器和存储资源打包为一个可管理的实体。

  每个 Pod 表示运行给定应用程序的单个实例。如果希望横向扩展应用程序(例如,运行多个实例),则应该使用多个 Pod,每个应用实例使用一个 Pod 。在Kubernetes中,这通常称为副本。通常使用一个称为控制的抽象来创建和管理一组副本Pod。

  Pod怎样管理多个容器

  Pod 被设计成支持形成内聚服务单元的多个协作过程(作为容器)。 Pod 中的容器被自动的安排到集群中的同一物理或虚拟机上,并可以一起进行调度。 容器可以共享资源和依赖、彼此通信、协调何时以及何种方式终止它们。

  注意,在单个 Pod 中将多个并置和共同管理的容器分组是一个相对高级的使用方式。 只在容器紧密耦合的特定实例中使用此模式。 例如,您可能有一个充当共享卷中文件的 Web 服务器的容器,以及一个单独的 sidecar 容器,该容器从远端更新这些文件,如下图所示:

   有些Pod具有初始容器和应用容器。初始容器和应用容器。初始容器会在启动应用容器之前运行完成。

  Pod为其组成容器提供两种共享资源:网络和存储。

  网络

  每个Pod分配一个唯一的IP地址。Pod中的每个容器共享网络命名空间,包括IP地址和网络端口。Pod内容器可以使用localhost互相通信。当Pod中容器与Pod之外的实体通信时,他们必须协调如何使用共享的网络资源(例如端口)。

  存储

  一个Pod可以指定一组共享存储卷。Pod中所有容器都可以访问共享卷,允许这些容器共享数据。卷还允许Pod的持久数据保留下来,以防其中容器需要重新启动。

   使用Pod

  你很少在 Kubernetes 中直接创建单独的 Pod,甚至是单个存在的 Pod。 这是因为 Pod 被设计成了相对短暂的一次性的实体。 当 Pod 由您创建或者间接地由控制器创建时,它被调度在集群中的 节点上运行。 Pod 会保持在该节点上运行,直到进程被终止、Pod 对象被删除、Pod 因资源不足而被 驱逐 或者节点失效为止。

  注意:重启Pod中的容器不应与重启Pod混淆。Pod本身不运行,而是作为容器运行的环境,并且一直保持到被删除为止。

  Pod 本身并不能自愈。 如果 Pod 被调度到失败的节点,或者如果调度操作本身失败,则删除该 Pod;同样,由于缺乏资源或进行节点维护,Pod 在被驱逐后将不再生存。 Kubernetes 使用了一个更高级的称为 控制器 的抽象,由它处理相对可丢弃的 Pod 实例的管理工作。 因此,虽然可以直接使用 Pod,但在 Kubernetes 中,更为常见的是使用控制器管理 Pod。

  Pod和控制器

  控制器可以创建和管理多个Pod,管理副本和上线,并在集群范围内提供自修复能力。例如,一个节点失败,控制器可以在不同的节点上调度一样的替身;自动替换Pod。包含一个或多个Pod控制器的一些实例包括

  •  Deployment
  •    StatefulSet
  •    DaemonSet

  控制器通常使用提供的Pod模板来创建它所负责的Pod。

  Pod模板是包含在其他对象的Pod规范,例如Replication Controller,Jobs和DaemonSets。控制器使用Pod模板来制作实际使用的Pod。下面的示例是一个简单的 Pod 清单,它包含一个打印消息的容器。

# cat pod1.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: myapp-pod
  labels:
    app: myapp
spec:
  containers:
  - name: myapp-container
    image: busybox
    command: ['sh','-c','echo Hello Kuberneter! && sleep 3600']

   该Pod使用镜像busybox创建容器以后运行echo Hello Kuberneter!输出,sleep是保证容器运行完毕不立即结束

  创建Pod

kubectl apply -f pod1.yaml 

   查看创建的Pod

   日志输出

# kubectl logs myapp-pod
Hello Kuberneter!

   设计Pod的目的

  管理

  Pod是形成内聚服务单元的多个协作过程模式的模型。他们提供了一个比他们应用组合成集合更高级的抽象,从而简化了应用的部署和管理。Pod可以用作部署,水平扩展和制作副本的最小单元。在Pod中,系统自动处理多个容器在并置运行(协同调度)、生命期共享(例如,终止),协同复制、资源共享和依赖项管理。

  资源共享和通信

  Pod使它的组成容器间能够进行数据共享和通信。

  Pod中的应用都使用相同的网络命名空间(相同IP和端口空间),并且能过互相发现并使用localhost进行通信。因此,在 Pod 中的应用必须协调它们的端口使用情况。每个 Pod 在扁平的共享网络空间中具有一个 IP 地址,该空间通过网络与其他物理计算机和 Pod 进行全面通信。

  Pod中的容器获取的系统主机名与为Pod配置的name相同。

  Pod除了定义了Pod中运行的应用程序之外,Pod还指定了一组共享存储卷。该共享存储卷能使数据在容器重新启动后继续保留,并能在 Pod 内的应用程序之间共享。

  使用Pod

  Pod 可以用于托管垂直集成的应用程序栈(例如,LAMP),但最主要的目的是支持位于同一位置的、共同管理的工具程序,例如:

  • 内容管理系统、文件和数据加载器、本地缓存管理器等。
  • 日志和检查点备份、压缩、旋转、快照等。
  • 数据更改监视器、日志跟踪器、日志和监视适配器、事件发布器等。
  • 代理、桥接器和适配器
  • 控制器、管理器、配置器和更新器

  通常,不会用单个 Pod 来运行同一应用程序的多个实例。

  为什么不在单个(Docker)容器中运行多个程序?

  1. 透明度。Pod 内的容器对基础设施可见,使得基础设施能够向这些容器提供服务,例如流程管理和资源监控。这为用户提供了许多便利。
  2. 解耦软件依赖关系。可以独立地对单个容器进行版本控制、重新构建和重新部署。Kubernetes 有一天甚至可能支持单个容器的实时更新。
  3. 易用性。用户不需要运行他们自己的进程管理器、也不用担心信号和退出代码传播等。
  4. 效率。因为基础结构承担了更多的责任,所以容器可以变得更加轻量化。

  Pod的持久性或稀缺性

  不得将 Pod 视为持久实体。它们无法在调度失败、节点故障或其他驱逐策略(例如由于缺乏资源或在节点维护的情况下)中生存。

  一般来说,用户不需要直接创建 Pod。他们几乎都是使用控制器进行创建,即使对于单例的 Pod 创建也一样使用控制器,例如 Deployments。 控制器提供集群范围的自修复以及副本数和滚动管理。 像 StatefulSet 这样的控制器还可以提供支持有状态的 Pod。

  Pod的终止

  因为 Pod 代表在集群中的节点上运行的进程,所以当不再需要这些进程时(与被 KILL 信号粗暴地杀死并且没有机会清理相比),允许这些进程优雅地终止是非常重要的。 用户应该能够请求删除并且知道进程何时终止,但是也能够确保删除最终完成。当用户请求删除 Pod 时,系统会记录在允许强制删除 Pod 之前所期望的宽限期,并向每个容器中的主进程发送 TERM 信号。一旦过了宽限期,KILL 信号就发送到这些进程,然后就从 API 服务器上删除 Pod。如果 Kubelet 或容器管理器在等待进程终止时发生重启,则终止操作将以完整的宽限期进行重试。

  流程示意

  

  1. 用户发送命令删除 Pod,使用的是默认的宽限期(30秒)
  2. API 服务器中的 Pod 会随着宽限期规定的时间进行更新,过了这个时间 Pod 就会被认为已 “死亡”。
  3. 当使用客户端命令查询 Pod 状态时,Pod 显示为 “Terminating”。
  4. (和第 3 步同步进行)当 Kubelet 看到 Pod 由于步骤 2 中设置的时间而被标记为 terminating 状态时,它就开始执行关闭 Pod 流程。
    1. 如果 Pod 定义了 preStop 钩子,就在 Pod 内部调用它。如果宽限期结束了,但是 preStop 钩子还在运行,那么就用小的(2 秒)扩展宽限期调用步骤 2。
    2. 给 Pod 内的进程发送 TERM 信号。请注意,并不是所有 Pod 中的容器都会同时收到 TERM 信号,如果它们关闭的顺序很重要,则每个容器可能都需要一个 preStop 钩子。
  5. (和第 3 步同步进行)从服务的端点列表中删除 Pod,Pod 也不再被视为副本控制器的运行状态的 Pod 集的一部分。因为负载均衡器(如服务代理)会将其从轮换中删除,所以缓慢关闭的 Pod 无法继续为流量提供服务。
  6. 当宽限期到期时,仍在 Pod 中运行的所有进程都会被 SIGKILL 信号杀死。
  7. kubelet 将通过设置宽限期为 0 (立即删除)来完成在 API 服务器上删除 Pod 的操作。该 Pod 从 API 服务器中消失,并且在客户端中不再可见。

  默认情况下,所有删除操作宽限期是 30 秒。kubectl delete 命令支持 --grace-period=<seconds> 选项,允许用户覆盖默认值并声明他们自己的宽限期。设置为 0 会强制删除 Pod。您必须指定一个附加标志 --force 和 --grace-period=0 才能执行强制删除操作。

  Pod的强制删除

  强制删除 Pod 被定义为从集群状态与 etcd 中立即删除 Pod。当执行强制删除时,API 服务器并不会等待 kubelet 的确认信息,该 Pod 已在所运行的节点上被终止了。强制执行删除操作会从 API 服务器中立即清除 Pod, 因此可以用相同的名称创建一个新的 Pod。在节点上,设置为立即终止的 Pod 还是会在被强制删除前设置一个小的宽限期。强制删除对某些 Pod 可能具有潜在危险,因此应该谨慎地执行。

原文地址:https://www.cnblogs.com/minseo/p/12523052.html