《深入剖析kubernetes》学习笔记(2)——Pod
13. Pod基础
- Pod基本概念
- Pod只是一个逻辑概念,是一组共享了某些资源的容器
- Pod 里的所有容器,共享的是同一个 Network Namespace,并且可以声明共享同一个 Volume
- Pod 的实现需要使用一个中间容器,叫做infra容器;在一个 Pod 中,Infra 容器永远都是第一个被创建的容器,而其他用户定义的容器,则通过 Join Network Namespace 的方式,与 Infra 容器关联在一起
- 如何理解容器的“单进程模型”?
- 容器中PID=1的进程就是应用本身,其他进程均是该进程的子进程
- 并不是说容器中只能运行一个进程,而是容器无法管理多个进程
- 对于同一个Pod里的容器A与容器B而言:
- 它们可以直接使用 localhost 进行通信;
- 它们看到的网络设备跟 Infra 容器看到的完全一样;
- 一个 Pod 只有一个 IP,也就是这个 Pod 的 Network Namespace 对应的 IP ;
- 其他的所有网络资源,都是一个 Pod 一份,并且被该 Pod 中的所有容器共享;
- Pod 的生命周期只跟 Infra 容器一致,而与容器 A 和 B 无关。
- 如何理解Pod的本质?
- Pod,实际上是在扮演传统基础设施里“虚拟机”的角色;而容器,则是这个虚拟机里运行的用户程序。
- sidecar模式,在Pod中启动一个辅助容器,完成一些独立于主进程(主容器)的工作,例如
- WAR 包与 Web 服务器
- 容器的日志收集
- Pod中的Init container:
- 在Pod的yaml中,在spec.initContainers字段下定义
- spec.initContainers中定义的容器比spec.containers下的容器优先,并按顺序逐一启动
- 直到sepc.initcontainers容器都启动并退出,用户容器才会启动
- 为什么需要Pod?
- 解决具有“超亲密关系”的容器的调度问题
- 容器设计模式,参考谷歌论文Design Patterns for Container-based Distributed Systems
14 深入Pod(1)
-
凡是调度、网络、存储,以及安全相关的属性,基本上是 Pod 级别的,常见字段:
- spec.nodeSelector:指定Pod运行在什么样的节点上
- spec.nodeName:该字段由调度器负责设置,一旦被赋值则认为该Pod已经完成调度
- spec.hostAliases:定义Pod中Host文件(/etc/hosts)的内容
-
凡是跟容器的 Linux Namespace 相关的属性,也一定是 Pod 级别的
- Pod的设计就是令其中的容器尽可能多地共享linux namespace,仅保留必要地隔离和限制,从而让Pod尽可能像是一个虚拟机
- spec.shareProcessNamespace:true意味着该Pod下的容器共享PID Namespace
-
凡是Pod中的容器要共享宿主机的 Namespace,也一定是 Pod 级别的定义
- spec.hostNetwork: true 共享宿主机网络
- spec.hostIPC: true 直接与宿主机进行IPC通信【补充进程间通信知识】
- spec.hostPID: true 共享宿主机PID namespace,可以看到宿主机上所有进程
-
两个关于容器的常用属性:
- ImagePullPolicy,取值有Always, Never, IfNotPresent
- Lifecycle,定义容器生命周期钩子,用于在容器状态变化时触发某些操作
-
Pod对象的生命周期,pod.status.phase定义了pod当前状态Status,可能状态有:
- pending,pod的api对象已经被创建并保存在etcd中,但有些容器没能顺利创建
- running, pod已经调度成功
- succeeded,pod中所有容器正常运行结束,已经退出
- failed,pod中有容器以不正常状态退出
-
Pod的细分状态Conditions,常见的有
- PodScheduled, Unschedulable, Ready, Initialized
15. 深入Pod(2)
-
投射数据卷(Projected Volume),为容器提供预先定义好的数据,有四种
-
Secret:存储在etcd中的加密数据,容器以volume挂载的方式访问到;一旦etcd中数据更新,volume里的内容也同步更新(由kubelet组件定时维护,可能会有延时)。
spec: containers: ...... volumeMounts: - name: mysql-cred mountPath: "/projected-volume" readOnly: true volumes: - name: mysql-cred projected: sources: - secret: name: user - secret: name: pass
上述yaml则将secret衷地user和pass对象,投射到了容器的/project-volume目录下
-
ConfigMap,存储的是不需要加密的配置信息,用法与Secret基本相同
-
Downward API,让Pod 里的容器能够直接获取到这个 Pod API 对象本身的信息,例如
... spec: containers: - name: client-container ..... volumeMounts: - name: podinfo mountPath: /etc/podinfo readOnly: false volumes: - name: podinfo projected: sources: - downwardAPI: items: - path: "labels" fieldRef: fieldPath: metadata.labels
当前 Pod 的 Labels 字段的值,就会被 Kubernetes 自动挂载成为容器里的 /etc/podinfo/labels 文件
Downward API只能提供容器启动前就可以确定的信息
Secret、ConfigMap,以及 Downward API 定义的信息,一般也都可以通过环境变量的方式获取,但是通过环境变量获取不具备自动更新的能力,因此仍应尽量使用Projected Volume
-
ServiceAccountToken, 是一个特殊的Secret对象,保存着Service Account的授权信息和文件,明确了对kubernetes API的操作权限。
每一个Pod在创建时,kubernetes自动在sepc.volumes字段添加了一个默认的ServiceAccountToken,并给每个容器添加了队以ingVolumeMounts字段。(也可以设置不添加该字段)
把 Kubernetes 客户端以容器的方式运行在集群里,然后使用 default Service Account 自动授权的方式,被称作“InClusterConfig”
-
-
单 Pod 的 Deployment 与一个 Pod 最主要的区别:
- 单个pod——一旦一个 Pod 与一个节点(Node)绑定,除非这个绑定发生了变化(pod.spec.node 字段被修改),否则它永远都不会离开这个节点。这也就意味着,如果这个宿主机宕机了,这个 Pod 也不会主动迁移到其他节点上去
- 单 Pod 的 Deployment —— Pod 重新创建后可能出现在其他的可用节点
-
容器的探针(Probe)
- 有三种执行探针的方法:
- 执行Exec语句,看命令是否以状态0退出,例如
cat /tmp/healthy
- 执行TCP请求,看特定端口是否打开
- 执行HTTP Get方法,看返回结果是否在200到400之间
- 执行Exec语句,看命令是否以状态0退出,例如
- 每种探针都有三种可能的结果:
- Success,容器通过诊断
- Failure,容器没有通过诊断
- Unknown,诊断操作执行失败
- kubelet可以执行或响应以下三种探针
- livenessProbe,判断容器是否处在running状态,若失败,根据恢复机制判断是否重启
- readinessProbe,判断容器是否ready,若失败,将从各Service中移除该Pod的IP地址
- startupProbe,判断容器中应用是否已经启动,如果有该探针,则其他探针均失效,直到该探针的结果为success;若失败,根据恢复机制判断是否重启
- 有三种执行探针的方法:
-
Pod的恢复机制
- 单个Pod的恢复,永远只发生在当前节点上
- 定义在pod.spec.restartPolicy字段下,有如下取值方式:
- Always(默认取值),表示任何情况下容器不在运行(running)状态,就自动重启容器;
- OnFailure,只在容器异常时才自动重启容器
- Never,永远不会重启容器
- 恢复机制、Pod的状态、Pod中容器的状态三者关系原则:
- 只要 Pod 的 restartPolicy 指定的策略允许重启异常的容器(比如:Always),那么这个 Pod 就会保持 Running 状态,并进行容器重启。否则,Pod 就会进入 Failed 状态 。
- 对于包含多个容器的 Pod,只有它里面所有的容器都进入异常状态后,Pod 才会进入 Failed 状态。在此之前,Pod 都是 Running 状态。
-
关于Pod和容器的状态、探针、恢复机制的内容比较细碎,具体可以参考官方文档
-
PodPreset对象
- 作用于其spec.selector 所定义的Pod对象,为其追加内容
- 会在Pod API对象创建之前追加在pod定义中,不会影响Pod控制器(例如deployment)的定义
- 多个PodPreset对一个Pod进行修改时,kubernetes会自动合并各PodPreset的修改,并忽略其中的冲突字段