308 lines
18 KiB
Markdown
308 lines
18 KiB
Markdown
|
<h1><center>Kubernetes资源对象Pod</center></h1>
|
|||
|
|
|||
|
著作:行癫 <盗版必究>
|
|||
|
|
|||
|
------
|
|||
|
|
|||
|
## 一:Pod基本概念
|
|||
|
|
|||
|
#### 1.认识pod
|
|||
|
|
|||
|
Pod直译是豆荚,可以把容器想像成豆荚里的豆子,把一个或多个关系紧密的豆子包在一起就是豆荚(一个Pod)。在Kubernetes中我们不会直接操作容器,而是把容器包装成Pod再进行管理;Pod是Kubernetes进行创建、调度和管理的最小单位;Pod运行于Node节点上, 若干相关容器的组合;Pod内包含的容器运行在同一宿主机上,使用相同的网络命名空间、IP地址和端口,能够通过localhost进行通信;Pod可以指定一组共享存储。Volumes Pod中。Pod中的所有容器都可以访问共享卷,从而使这些容器可以共享数据;Pod 就是 k8s 世界里的"应用";而一个应用,可以由多个容器组成。
|
|||
|
|
|||
|
![img](https://docimg10.docs.qq.com/image/v42rJlcMcT5SyfEdxFC-pQ?w=499&h=428)
|
|||
|
|
|||
|
![img](Kubernetes%E8%B5%84%E6%BA%90%E5%AF%B9%E8%B1%A1Pod.assets/NYEY9Y5PKwaGws3MLskAkQ.png)
|
|||
|
|
|||
|
**注意:**
|
|||
|
|
|||
|
重启 Pod 中的容器不应与重启 Pod 混淆。Pod 本身不运行,而是作为容器运行的环境,并且一直保持到被删除为止;Pod本身无法自我修复。如果将Pod调度到发生故障的节点,或者调度操作本身失败,则将Pod删除;同样,由于缺乏资源或Node维护,Pod无法幸免。Kubernetes使用称为Controller的更高级别的抽象来处理管理相对易用的Pod实例的工作。因此,虽然可以直接使用Pod,但在Kubernetes中使用Controller管理Pod更为常见。
|
|||
|
|
|||
|
#### 2.pause容器
|
|||
|
|
|||
|
作用:负责同一个pod的容器通信
|
|||
|
|
|||
|
每个Pod中都有一个pause容器,pause容器做为Pod的网络接入点,Pod中其他的容器会使用容器映射模式启动并接入到这个pause容器;属于同一个Pod的所有容器共享网络的namespace;一个Pod里的容器与另外主机上的Pod容器能够直接通信。
|
|||
|
|
|||
|
#### 3.Pods and Controllers
|
|||
|
|
|||
|
Controller可以为您创建和管理多个Pod,以处理复制和推出并在集群范围内提供自我修复功能。例如,如果某个节点发生故障,则控制器会将这个Node上的所有Pod重新调度到其他节点上。
|
|||
|
|
|||
|
#### 4.Pod 模板
|
|||
|
|
|||
|
Pod 模板是包含在其他对象中的 Pod 规范,例如 Replication Controllers、 Jobs、和 DaemonSets。 控制器使用 Pod 模板来制作实际使用的 Pod。 下面的示例是一个简单的 Pod 清单,它包含一个打印消息的容器。
|
|||
|
|
|||
|
```yaml
|
|||
|
apiVersion: v1
|
|||
|
kind: Pod
|
|||
|
metadata:
|
|||
|
name: myapp-pod
|
|||
|
labels:
|
|||
|
app: myapp
|
|||
|
spec:
|
|||
|
containers:
|
|||
|
- name: myapp-container
|
|||
|
image: busybox
|
|||
|
command: ['sh', '-c', 'echo Hello Kubernetes! && sleep 3600']
|
|||
|
```
|
|||
|
|
|||
|
#### 5.Pod 的终止
|
|||
|
|
|||
|
Pod 代表在集群中的节点上运行的进程,所以当不再需要这些进程时,允许这些进程优雅地终止是非常重要的,用户应该能够请求删除并且知道进程何时终止,但是也能够确保删除最终完成。当用户请求删除 Pod 时,系统会记录在允许强制删除 Pod 之前所期望的宽限期,并向每个容器中的主进程发送 TERM 信号。一旦过了宽限期,KILL 信号就发送到这些进程,然后就从 API 服务器上删除 Pod。如果 Kubelet 或容器管理器在等待进程终止时发生重启,则终止操作将以完整的宽限期进行重试。
|
|||
|
|
|||
|
**终止流程:**
|
|||
|
|
|||
|
用户发送命令删除 Pod,使用的是默认的宽限期(30秒)
|
|||
|
|
|||
|
API 服务器中的 Pod 会随着宽限期规定的时间进行更新,过了这个时间 Pod 就会被认为已 “死亡”
|
|||
|
|
|||
|
当使用客户端命令查询 Pod 状态时,Pod 显示为 “Terminating”
|
|||
|
|
|||
|
当 Kubelet 看到 Pod 由于步骤2中设置的时间而被标记为 terminating 状态时,它就开始执行关闭 Pod 流程
|
|||
|
|
|||
|
给 Pod 内的进程发送 TERM 信号((和第3步同步进行)从服务的端点列表中删除 Pod,Pod也不再被视为副本控制器的运行状态的 Pod 集的一部分。当负载平衡器(如服务代理)将 Pod 从轮换中移除时,关闭迟缓的 Pod 将不能继续为流量服务)
|
|||
|
|
|||
|
当宽限期结束后,Pod 中运行的任何进程都将被用 SIGKILL 杀死
|
|||
|
|
|||
|
Kubelet 将通过设置宽限期为0(立即删除)来完成删除 API 服务器上的 Pod。Pod 从 API 中消失,从客户端不再可见
|
|||
|
|
|||
|
#### 6.使用Pod
|
|||
|
|
|||
|
下面是一个 Pod 示例,它由一个运行镜像 `nginx:1.20.1` 的容器组成
|
|||
|
|
|||
|
```shell
|
|||
|
[root@master ~]# vim nginx.yaml
|
|||
|
apiVersion: v1
|
|||
|
kind: Pod
|
|||
|
metadata:
|
|||
|
name: nginx
|
|||
|
spec:
|
|||
|
containers:
|
|||
|
- name: nginx
|
|||
|
image: nginx:1.20.1
|
|||
|
ports:
|
|||
|
- containerPort: 80
|
|||
|
```
|
|||
|
|
|||
|
要创建上面显示的 Pod,请运行以下命令:
|
|||
|
|
|||
|
```shell
|
|||
|
[root@master ~]# kubectl apply -f nginx.yaml
|
|||
|
```
|
|||
|
|
|||
|
#### 7.用于管理 pod 的工作负载资源
|
|||
|
|
|||
|
通常你不需要直接创建 Pod,甚至单实例 Pod。 相反,你会使用诸如 Deployment或 Job 这类工作负载资源 来创建 Pod。如果 Pod 需要跟踪状态, 可以考虑 StatefulSet 资源。
|
|||
|
|
|||
|
**Kubernetes 集群中的 Pod 主要有两种用法:**
|
|||
|
|
|||
|
运行单个容器的 Pod。"每个 Pod 一个容器"模型是最常见的 Kubernetes 用例; 在这种情况下,可以将 Pod 看作单个容器的包装器,并且 Kubernetes 直接管理 Pod,而不是容器
|
|||
|
|
|||
|
运行多个协同工作的容器的 Pod。 Pod 可能封装由多个紧密耦合且需要共享资源的共处容器组成的应用程序。 这些位于同一位置的容器可能形成单个内聚的服务单元 —— 一个容器将文件从共享卷提供给公众, 而另一个单独的容器则刷新或更新这些文件。 Pod 将这些容器和存储资源打包为一个可管理的实体。
|
|||
|
|
|||
|
每个 Pod 都旨在运行给定应用程序的单个实例。如果希望横向扩展应用程序(例如,运行多个实例 以提供更多的资源),则应该使用多个 Pod,每个实例使用一个 Pod。 在 Kubernetes 中,这通常被称为 *副本(Replication)*。 通常使用一种工作负载资源及其[控制器](https://kubernetes.io/zh/docs/concepts/architecture/controller/) 来创建和管理一组 Pod 副本。
|
|||
|
|
|||
|
#### 8.Pod 怎样管理多个容器
|
|||
|
|
|||
|
Pod 被设计成支持形成内聚服务单元的多个协作过程(形式为容器)。 Pod 中的容器被自动安排到集群中的同一物理机或虚拟机上,并可以一起进行调度。 容器之间可以共享资源和依赖、彼此通信、协调何时以及何种方式终止自身。
|
|||
|
|
|||
|
例如,你可能有一个容器,为共享卷中的文件提供 Web 服务器支持,以及一个单独的容器负责从远端更新这些文件,如下图所示:
|
|||
|
|
|||
|
<img src="Kubernetes%E8%B5%84%E6%BA%90%E5%AF%B9%E8%B1%A1Pod.assets/image-20220501135545030.png" alt="image-20220501135545030" style="zoom:50%;" />
|
|||
|
|
|||
|
有些 Pod 具有 Init 容器和 应用容器。 Init 容器会在启动应用容器之前运行并完成。
|
|||
|
|
|||
|
Pod 天生地为其成员容器提供了两种共享资源:网络和 存储。
|
|||
|
|
|||
|
## 二:Pod生命周期
|
|||
|
|
|||
|
Pod 遵循一个预定义的生命周期,起始于 `Pending`阶段,至少其中有一个主要容器正常启动,则进入 `Running`,之后取决于 Pod 中是否有容器以 失败状态结束而进入 `Succeeded` 或者 `Failed` 阶段。
|
|||
|
|
|||
|
在 Pod 运行期间,`kubelet` 能够重启容器以处理一些失效场景。 在 Pod 内部,Kubernetes 跟踪不同容器的状态并确定使 Pod 重新变得健康所需要采取的动作。
|
|||
|
|
|||
|
Pod 在其生命周期中只会被调度一次。 一旦 Pod 被调度(分派)到某个节点,Pod 会一直在该节点运行,直到 Pod 停止或者被终止。
|
|||
|
|
|||
|
#### 1.Pod 生命期
|
|||
|
|
|||
|
和一个个独立的应用容器一样,Pod 也被认为是相对临时性(而不是长期存在)的实体。 Pod 会被创建、赋予一个唯一的 ID(UID), 并被调度到节点,并在终止(根据重启策略)或删除之前一直运行在该节点。
|
|||
|
|
|||
|
如果一个[节点](https://kubernetes.io/zh/docs/concepts/architecture/nodes/)死掉了,调度到该节点 的 Pod 也被计划在给定超时期限结束后删除。
|
|||
|
|
|||
|
Pod 自身不具有自愈能力。如果 Pod 被调度到某节点而该节点之后失效,Pod 会被删除;类似地,Pod 无法在因节点资源 耗尽或者节点维护而被驱逐期间继续存活。Kubernetes 使用一种高级抽象 来管理这些相对而言可随时丢弃的 Pod 实例,称作控制器。
|
|||
|
|
|||
|
任何给定的 Pod (由 UID 定义)从不会被“重新调度(rescheduled)”到不同的节点; 相反,这一 Pod 可以被一个新的、几乎完全相同的 Pod 替换掉。 如果需要,新 Pod 的名字可以不变,但是其 UID 会不同。
|
|||
|
|
|||
|
如果某物声称其生命期与某 Pod 相同,例如存储[卷](https://kubernetes.io/zh/docs/concepts/storage/volumes/), 这就意味着该对象在此 Pod (UID 亦相同)存在期间也一直存在。 如果 Pod 因为任何原因被删除,甚至某完全相同的替代 Pod 被创建时, 这个相关的对象(例如这里的卷)也会被删除并重建。
|
|||
|
|
|||
|
一个包含多个容器的 Pod 包含一个用来拉取文件的程序和一个 Web 服务器, 均使用持久卷作为容器间共享的存储。
|
|||
|
|
|||
|
#### 2.Pod 阶段
|
|||
|
|
|||
|
Pod 的 `status` 字段是一个PodStatus对象,其中包含一个 `phase` 字段。
|
|||
|
|
|||
|
Pod 的阶段(Phase)是 Pod 在其生命周期中所处位置的简单宏观概述。 该阶段并不是对容器或 Pod 状态的综合汇总,也不是为了成为完整的状态机。
|
|||
|
|
|||
|
Pod 阶段的数量和含义是严格定义的。 除了本文档中列举的内容外,不应该再假定 Pod 有其他的 `phase` 值。
|
|||
|
|
|||
|
| 取值 | 描述 |
|
|||
|
| :---------------: | :----------------------------------------------------------: |
|
|||
|
| Pending(悬决) | Pod 已被 Kubernetes 系统接受,但有一个或者多个容器尚未创建亦未运行;此阶段包括等待 Pod 被调度的时间和通过网络下载镜像的时间。 |
|
|||
|
| Running(运行中) | Pod 已经绑定到了某个节点,Pod 中所有的容器都已被创建。至少有一个容器仍在运行,或者正处于启动或重启状态。 |
|
|||
|
| Succeeded(成功) | Pod 中的所有容器都已成功终止,并且不会再重启。 |
|
|||
|
| Failed(失败) | Pod 中的所有容器都已终止,并且至少有一个容器是因为失败终止。也就是说,容器以非 0 状态退出或者被系统终止。 |
|
|||
|
| Unknown(未知) | 因为某些原因无法取得 Pod 的状态。这种情况通常是因为与 Pod 所在主机通信失败。 |
|
|||
|
|
|||
|
如果某节点死掉或者与集群中其他节点失联,Kubernetes 会实施一种策略,将失去的节点上运行的所有 Pod 的 `phase` 设置为 `Failed`。
|
|||
|
|
|||
|
#### 3.容器状态
|
|||
|
|
|||
|
Kubernetes 会跟踪 Pod 中每个容器的状态,就像它跟踪 Pod 总体上的阶段一样。 你可以使用容器生命周期回调来在容器生命周期中的特定时间点触发事件。
|
|||
|
|
|||
|
一旦调度器将 Pod 分派给某个节点,`kubelet` 就通过容器运行时开始为 Pod 创建容器。 容器的状态有三种:
|
|||
|
|
|||
|
Waiting(等待)
|
|||
|
|
|||
|
如果容器并不处在 `Running` 或 `Terminated` 状态之一,它就处在 `Waiting` 状态。 处于 `Waiting` 状态的容器仍在运行它完成启动所需要的操作:例如,从某个容器镜像 仓库拉取容器镜像,或者向容器应用Secret数据等等。 当你使用 `kubectl` 来查询包含 `Waiting` 状态的容器的 Pod 时,你也会看到一个 Reason 字段,其中给出了容器处于等待状态的原因。
|
|||
|
|
|||
|
Running(运行中)
|
|||
|
|
|||
|
`Running` 状态表明容器正在执行状态并且没有问题发生。 如果配置了 `postStart` 回调,那么该回调已经执行且已完成。 如果你使用 `kubectl` 来查询包含 `Running` 状态的容器的 Pod 时,你也会看到 关于容器进入 `Running` 状态的信息。
|
|||
|
|
|||
|
Terminated(已终止)
|
|||
|
|
|||
|
处于 `Terminated` 状态的容器已经开始执行并且或者正常结束或者因为某些原因失败。 如果你使用 `kubectl` 来查询包含 `Terminated` 状态的容器的 Pod 时,你会看到 容器进入此状态的原因、退出代码以及容器执行期间的起止时间;如果容器配置了 `preStop` 回调,则该回调会在容器进入 `Terminated` 状态之前执行。
|
|||
|
|
|||
|
#### 4.容器重启策略
|
|||
|
|
|||
|
Pod 的 `spec` 中包含一个 `restartPolicy` 字段,其可能取值包括 Always、OnFailure 和 Never。默认值是 Always。
|
|||
|
|
|||
|
`restartPolicy` 适用于 Pod 中的所有容器。`restartPolicy` 仅针对同一节点上 `kubelet` 的容器重启动作。当 Pod 中的容器退出时,`kubelet` 会按指数回退 方式计算重启的延迟(10s、20s、40s、...),其最长延迟为 5 分钟。 一旦某容器执行了 10 分钟并且没有出现问题,`kubelet` 对该容器的重启回退计时器执行重置操作。
|
|||
|
|
|||
|
#### 5.Pod 状况
|
|||
|
|
|||
|
Pod 有一个 PodStatus 对象,其中包含一个PodConditions数组。Pod 可能通过也可能未通过其中的一些状况测试。
|
|||
|
|
|||
|
PodScheduled:Pod 已经被调度到某节点
|
|||
|
|
|||
|
ContainersReady:Pod 中所有容器都已就绪
|
|||
|
|
|||
|
Initialized:所有的Init 容器都已成功完成
|
|||
|
|
|||
|
Ready:Pod 可以为请求提供服务,并且应该被添加到对应服务的负载均衡池中
|
|||
|
|
|||
|
| 字段名称 | 描述 |
|
|||
|
| :----------------: | :----------------------------------------------------------: |
|
|||
|
| type | Pod 状况的名称 |
|
|||
|
| status | 表明该状况是否适用,可能的取值有 "`True`", "`False`" 或 "`Unknown`" |
|
|||
|
| lastProbeTime | 上次探测 Pod 状况时的时间戳 |
|
|||
|
| lastTransitionTime | Pod 上次从一种状态转换到另一种状态时的时间戳 |
|
|||
|
| reason | 机器可读的、驼峰编码(UpperCamelCase)的文字,表述上次状况变化的原因 |
|
|||
|
| message | 人类可读的消息,给出上次状态转换的详细信息 |
|
|||
|
|
|||
|
#### 6.Pod详细信息
|
|||
|
|
|||
|
```shell
|
|||
|
[root@master xingdian]# kubectl describe pod xingdian
|
|||
|
Name: xingdian
|
|||
|
Namespace: default
|
|||
|
Priority: 0
|
|||
|
Node: node-1/10.0.0.221
|
|||
|
Start Time: Sun, 01 May 2022 14:28:09 +0800
|
|||
|
Labels: <none>
|
|||
|
Annotations: <none>
|
|||
|
Status: Pending
|
|||
|
IP:
|
|||
|
IPs: <none>
|
|||
|
Containers:
|
|||
|
xingdian-nginx:
|
|||
|
Container ID:
|
|||
|
Image: nginx:1.20.1
|
|||
|
Image ID:
|
|||
|
Port: 80/TCP
|
|||
|
Host Port: 0/TCP
|
|||
|
State: Waiting
|
|||
|
Reason: ContainerCreating
|
|||
|
Ready: False
|
|||
|
Restart Count: 0
|
|||
|
Environment: <none>
|
|||
|
Mounts:
|
|||
|
/var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-q6bcr (ro)
|
|||
|
Conditions:
|
|||
|
Type Status
|
|||
|
Initialized True
|
|||
|
Ready False
|
|||
|
ContainersReady False
|
|||
|
PodScheduled True
|
|||
|
Volumes:
|
|||
|
kube-api-access-q6bcr:
|
|||
|
Type: Projected (a volume that contains injected data from multiple sources)
|
|||
|
TokenExpirationSeconds: 3607
|
|||
|
ConfigMapName: kube-root-ca.crt
|
|||
|
ConfigMapOptional: <nil>
|
|||
|
DownwardAPI: true
|
|||
|
QoS Class: BestEffort
|
|||
|
Node-Selectors: <none>
|
|||
|
Tolerations: node.kubernetes.io/not-ready:NoExecute op=Exists for 300s
|
|||
|
node.kubernetes.io/unreachable:NoExecute op=Exists for 300s
|
|||
|
Events:
|
|||
|
Type Reason Age From Message
|
|||
|
---- ------ ---- ---- -------
|
|||
|
Normal Pulling 16s kubelet Pulling image "nginx:1.20.1"
|
|||
|
Normal Scheduled 12s default-scheduler Successfully assigned default/xingdian to node-1
|
|||
|
=================================================================================
|
|||
|
[root@master xingdian]# kubectl describe pod xingdian
|
|||
|
Name: xingdian
|
|||
|
Namespace: default
|
|||
|
Priority: 0
|
|||
|
Node: node-1/10.0.0.221
|
|||
|
Start Time: Sun, 01 May 2022 14:28:09 +0800
|
|||
|
Labels: <none>
|
|||
|
Annotations: <none>
|
|||
|
Status: Running
|
|||
|
IP: 10.244.2.3
|
|||
|
IPs:
|
|||
|
IP: 10.244.2.3
|
|||
|
Containers:
|
|||
|
xingdian-nginx:
|
|||
|
Container ID: docker://f60ad0e3e13844c294ba8fd05757667ad04a4d28dc48d2289abfc66d405ab06c
|
|||
|
Image: nginx:1.20.1
|
|||
|
Image ID: docker-pullable://nginx@sha256:a98c2360dcfe44e9987ed09d59421bb654cb6c4abe50a92ec9c912f252461483
|
|||
|
Port: 80/TCP
|
|||
|
Host Port: 0/TCP
|
|||
|
State: Running
|
|||
|
Started: Sun, 01 May 2022 14:29:32 +0800
|
|||
|
Ready: True
|
|||
|
Restart Count: 0
|
|||
|
Environment: <none>
|
|||
|
Mounts:
|
|||
|
/var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-q6bcr (ro)
|
|||
|
Conditions:
|
|||
|
Type Status
|
|||
|
Initialized True
|
|||
|
Ready True
|
|||
|
ContainersReady True
|
|||
|
PodScheduled True
|
|||
|
Volumes:
|
|||
|
kube-api-access-q6bcr:
|
|||
|
Type: Projected (a volume that contains injected data from multiple sources)
|
|||
|
TokenExpirationSeconds: 3607
|
|||
|
ConfigMapName: kube-root-ca.crt
|
|||
|
ConfigMapOptional: <nil>
|
|||
|
DownwardAPI: true
|
|||
|
QoS Class: BestEffort
|
|||
|
Node-Selectors: <none>
|
|||
|
Tolerations: node.kubernetes.io/not-ready:NoExecute op=Exists for 300s
|
|||
|
node.kubernetes.io/unreachable:NoExecute op=Exists for 300s
|
|||
|
Events:
|
|||
|
Type Reason Age From Message
|
|||
|
---- ------ ---- ---- -------
|
|||
|
Normal Pulling 97s kubelet Pulling image "nginx:1.20.1"
|
|||
|
Normal Scheduled 93s default-scheduler Successfully assigned default/xingdian to node-1
|
|||
|
Normal Pulled 14s kubelet Successfully pulled image "nginx:1.20.1" in 1m22.663436038s
|
|||
|
Normal Created 14s kubelet Created container xingdian-nginx
|
|||
|
Normal Started 14s kubelet Started container xingdian-nginx
|
|||
|
```
|
|||
|
|
|||
|
|
|||
|
|