创建和管理Pod
文章目录
- 创建和管理Pod
- @[toc]
- 一、什么是Pod
- 1.Pod 的核心定义
- 2.Pod 的组成与结构
- 3.Pod 的生命周期
- 4.Pod 的使用场景
- 5.高级特性
- 二、Pod与容器
- 1. 为什么使用 Pod 作为 Kubernetes 的最小部署单元?
- 2. 单一容器 Pod
- 3. 多容器 Pod
- 4. 初始化容器(Init Containers)
- 三、Pod的定义
- 四、Pod的生命周期
- 1.Pod 生命周期的阶段
- 2.关键流程与机制
- 3.Pod 的重启策略
- 4.Pod 的状况(Conditions)
- 5.设计建议与最佳实践
- 6.示例:完整生命周期配置
- 五、Pod的健康检查机制
- 六、创建多容器Pod
- 七、为Pod及其容器设置资源配额
- 1.了解资源配额的设置方法
- 2.为Pod容器设置CPU和内存配额
- 3.测试资源配额超限
- 八、实现pod容器的健康检查
文章目录
- 创建和管理Pod
- @[toc]
- 一、什么是Pod
- 1.Pod 的核心定义
- 2.Pod 的组成与结构
- 3.Pod 的生命周期
- 4.Pod 的使用场景
- 5.高级特性
- 二、Pod与容器
- 1. 为什么使用 Pod 作为 Kubernetes 的最小部署单元?
- 2. 单一容器 Pod
- 3. 多容器 Pod
- 4. 初始化容器(Init Containers)
- 三、Pod的定义
- 四、Pod的生命周期
- 1.Pod 生命周期的阶段
- 2.关键流程与机制
- 3.Pod 的重启策略
- 4.Pod 的状况(Conditions)
- 5.设计建议与最佳实践
- 6.示例:完整生命周期配置
- 五、Pod的健康检查机制
- 六、创建多容器Pod
- 七、为Pod及其容器设置资源配额
- 1.了解资源配额的设置方法
- 2.为Pod容器设置CPU和内存配额
- 3.测试资源配额超限
- 八、实现pod容器的健康检查
Kubernetes将Pod而不是单个容器作为最小的可部署单元。如果要部署应用程序,则必须将它作为容器部署在Pod中。尽管应用程序可以在容器中运行,但在Kubernetes中,容器必须是Pod的一部分。实际使用中很少直接创建Pod,而是使用高层级的负载均衡资源及其控制器来管理Pod副本。但是,工作负载资源使用Pod模板来创建相应的Pod,仍然涉及Pod的配置,因此我们有必要掌握Pod的创建和管理方法。
一、什么是Pod
Pod 是 Kubernetes 中最小的可部署和可管理的计算单元,用于封装一个或多个紧密关联的容器,并为其提供共享的运行环境。以下是关于 Pod 的核心要点:
1.Pod 的核心定义
- 最小部署单元
Pod 是 Kubernetes 中创建和管理的最小逻辑单元,代表集群中运行的一个应用实例。每个 Pod 包含一个或多个容器(如 Docker 容器),这些容器共享以下资源:- 网络命名空间:同一 Pod 内的容器共享 IP 地址和端口范围,可通过
localhost
直接通信。 - 存储卷:挂载到 Pod 的存储卷(如
emptyDir
、configMap
)可被所有容器共享。 - 运行时上下文:包括环境变量、资源配额等。
- 网络命名空间:同一 Pod 内的容器共享 IP 地址和端口范围,可通过
- Pod 与容器的关系
- 单容器 Pod:最常见的模式,将单个容器视为一个独立服务单元。
- 多容器 Pod:适用于需要紧密协作的场景(如主应用容器 + 日志收集 Sidecar 容器),但需谨慎设计以避免过度耦合。
2.Pod 的组成与结构
-
核心组件
- 容器:运行应用代码的主容器或辅助容器(如 Init 容器)。
- Pause 容器:每个 Pod 启动的第一个容器(又称根容器),负责管理共享命名空间、回收僵尸进程,并为其他容器提供稳定的网络和存储基础。
- 元数据:包括名称、标签(Labels)、命名空间(Namespace)等标识信息。
-
YAML 定义示例
apiVersion: v1 kind: Pod metadata:name: nginx-podlabels:app: web spec:containers:- name: nginximage: nginx:latestports:- containerPort: 80- name: sidecarimage: busyboxcommand: ["sh", "-c", "tail -f /dev/null"]
- 通过
kubectl explain pod
可查询字段的详细说明。
- 通过
3.Pod 的生命周期
-
阶段与状态
Pod 的生命周期包括以下阶段和状态:状态 描述 Pending Pod 已提交但未完成调度或容器镜像下载 Running 容器已创建且至少有一个在运行 Succeeded 所有容器正常终止(退出码为 0) Failed 至少一个容器异常终止(退出码非 0) Unknown 无法获取状态(通常因节点通信故障) -
关键流程
- 创建流程:用户提交请求 → API Server 存储至 etcd → 调度器分配节点 → kubelet 启动容器。
- 终止流程:发送删除指令 → 执行
preStop
钩子 → 发送 SIGTERM 信号 → 强制终止(宽限期后)。
4.Pod 的使用场景
- 典型场景
- Web 服务:单容器运行 Nginx、Tomcat 等。
- 批处理任务:通过
Job
或CronJob
运行一次性任务。 - 微服务协作:多容器协同处理(如主服务 + 监控 Sidecar)。
- 最佳实践
- 避免直接创建 Pod:通过
Deployment
、StatefulSet
等控制器管理 Pod,实现自愈、滚动更新等功能。 - 资源限制:为容器设置 CPU/内存的
requests
和limits
,防止资源争抢。 - 健康检查:配置
livenessProbe
和readinessProbe
确保应用可用性。
- 避免直接创建 Pod:通过
5.高级特性
- Init 容器
在应用容器启动前执行初始化任务(如等待数据库就绪),按顺序执行且必须成功。 - 静态 Pod
由节点上的 kubelet 直接管理,无需通过 API Server,适用于集群组件(如 etcd、kube-apiserver)。 - 镜像拉取策略
通过imagePullPolicy
控制镜像更新逻辑(Always
、IfNotPresent
、Never
)。
Pod 是 Kubernetes 编排能力的基石,通过抽象容器间的共享环境简化了复杂应用的部署。理解其生命周期、组成及使用场景,是设计高可用、可扩展服务的关键。
二、Pod与容器
以下是关于 Pod 与容器 的简要介绍,基于您提出的四个方面:
1. 为什么使用 Pod 作为 Kubernetes 的最小部署单元?
- 抽象容器间的共享环境:Pod 封装多个容器并共享网络、存储等资源,解决容器间需要协作的场景(如直接通过
localhost
通信)。 - 简化调度:Kubernetes 以 Pod 为粒度调度到节点,避免直接管理单个容器带来的复杂性。
- 生命周期一致性:Pod 内所有容器同时启停,确保关联服务(如主应用和日志收集 Sidecar)的协同运行。
2. 单一容器 Pod
-
场景:适用于单个容器即可完成任务的简单应用(如运行一个 Nginx Web 服务器)。
-
优势:部署简单,资源占用少,是 Kubernetes 最常见的使用模式。
-
示例
apiVersion: v1 kind: Pod metadata:name: nginx spec:containers:- name: nginximage: nginx:latest
3. 多容器 Pod
-
场景
:需要紧密协作的容器组,例如:
- 主应用 + Sidecar:主容器处理业务逻辑,Sidecar 负责日志收集、监控或代理(如 Istio 的服务网格)。
- 数据共享:多个容器挂载同一存储卷,处理同一批数据(如处理文件的转换器与上传器)。
-
优势:共享网络和存储,减少跨容器通信开销。
-
示例
spec:containers:- name: appimage: my-app- name: log-agentimage: fluentdvolumeMounts:- name: logsmountPath: /var/logvolumes:- name: logsemptyDir: {}
4. 初始化容器(Init Containers)
-
作用:在主容器启动前执行初始化任务(如下载依赖、等待数据库就绪),且必须成功退出后才会启动主容器。
-
特点
- 按顺序执行,前一个 Init 容器成功后才执行下一个。
- 与主容器隔离,不共享文件系统(需通过 Volume 显式共享)。
-
示例
spec:initContainers:- name: init-dbimage: busyboxcommand: ['sh', '-c', 'until nslookup mysql-service; do echo waiting; sleep 2; done']containers:- name: appimage: my-app
- Pod 作为最小单元:提供容器间的资源共享与协同管理能力。
- 单容器 Pod:简单应用的首选。
- 多容器 Pod:适用于需紧密协作的复杂场景。
- 初始化容器:确保主容器启动前的依赖条件就绪。
三、Pod的定义
以下是基于 YAML 配置文件 的 Pod 定义详解:
Pod 的 YAML 定义核心字段
apiVersion: v1 # Kubernetes API 版本(Pod 属于核心 API,固定为 v1)
kind: Pod # 资源类型标识,此处为 Pod
metadata: # 元数据,描述 Pod 的标识信息name: my-pod # Pod 名称(同一命名空间内唯一)namespace: default # 所属命名空间(默认为 default)labels: # 标签,用于资源筛选和关联app: webenv: dev
spec: # Pod 的具体配置规则containers: # 容器列表(必填,至少一个容器)- name: nginx # 容器名称(Pod 内唯一)image: nginx:1.25 # 容器镜像地址(必填)imagePullPolicy: IfNotPresent # 镜像拉取策略(Always/Never/IfNotPresent)ports: # 容器暴露的端口(可选,仅用于文档说明,不实际控制端口开放)- containerPort: 80protocol: TCPresources: # 资源限制与请求requests:memory: "128Mi"cpu: "0.5"limits:memory: "256Mi"cpu: "1"volumeMounts: # 挂载存储卷到容器内路径- name: logs-volumemountPath: /var/log/nginxvolumes: # 定义 Pod 级别的存储卷(供所有容器挂载)- name: logs-volumeemptyDir: {} # 使用临时空目录作为存储卷
关键字段说明
metadata
(元数据)
name
:Pod 的唯一名称(命名规则:小写字母、数字或-
,不能以数字开头)。namespace
:Pod 所属的命名空间(默认default
)。labels
:键值对标签,用于筛选和管理 Pod(如kubectl get pods -l app=web
)。
spec
(规格配置)
-
containers
:定义 Pod 中的容器列表(核心配置):
-
name
:容器名称(同一 Pod 内唯一)。 -
image
:容器镜像地址(如nginx:latest
、my-registry/app:v1
)。 -
imagePullPolicy
:镜像拉取策略:
Always
:总是从仓库拉取(默认策略,当镜像标签为latest
时)。IfNotPresent
:本地不存在时拉取。Never
:仅使用本地镜像。
-
ports
:声明容器监听的端口(仅用于文档,实际端口由容器进程决定)。 -
resources
:资源配额(避免资源争抢):
requests
:容器启动的最低资源需求(调度依据)。limits
:容器运行时的资源上限(超过会被终止或限制)。
-
volumes
与volumeMounts
volumes
:定义 Pod 级别的存储卷(如emptyDir
、configMap
、persistentVolumeClaim
)。volumeMounts
:将存储卷挂载到容器的指定路径(如日志目录、配置文件)。
完整示例:多容器 Pod
apiVersion: v1
kind: Pod
metadata:name: web-applabels:app: frontend
spec:containers:- name: nginximage: nginx:1.25ports:- containerPort: 80volumeMounts:- name: configmountPath: /etc/nginx/conf.d- name: log-collectorimage: fluentd:latestvolumeMounts:- name: logsmountPath: /var/log/nginxvolumes:- name: configconfigMap: # 使用 ConfigMap 存储 Nginx 配置name: nginx-config- name: logsemptyDir: {} # 临时存储卷(Pod 删除后数据丢失)
操作步骤
-
保存配置到文件(如
pod.yaml
)。 -
创建 Pod:
kubectl apply -f pod.yaml
-
查看 Pod 状态:
kubectl get pods -o wide kubectl describe pod web-app
注意事项
- 避免直接创建 Pod:推荐使用
Deployment
或StatefulSet
管理 Pod(支持滚动更新、自愈)。 - 调试工具:使用
kubectl explain pod
查看字段详细说明。
四、Pod的生命周期
Pod 是 Kubernetes 中最小的可调度单元,其生命周期从创建到终止涉及多个关键阶段和机制。以下是 Pod 生命周期的核心要点及详细说明:
1.Pod 生命周期的阶段
Pod 的状态通过 Phase
字段描述,主要分为以下五个阶段:
阶段 | 描述 |
---|---|
Pending | Pod 已提交但未完成调度或容器镜像下载,可能因资源不足、调度延迟或节点故障导致。 |
Running | Pod 已调度到节点,且至少有一个容器正在运行(包括初始化容器完成后的主容器)。 |
Succeeded | 所有容器正常终止(退出码为 0),适用于一次性任务(如批处理作业)。 |
Failed | 至少有一个容器异常终止(退出码非 0 或资源耗尽),且不再重启。 |
Unknown | 无法获取 Pod 状态,通常因节点通信故障或 API Server 不可达。 |
2.关键流程与机制
- 创建流程
- 调度与绑定
- API Server 接收创建请求后,由调度器(Scheduler)选择合适节点并绑定。
- 调度门控(SchedulingGates):通过
.spec.schedulingGates
可延迟调度,直到条件满足(如依赖资源就绪)。
- 容器初始化
- Init 容器:按顺序执行且必须成功,用于预加载数据、等待依赖服务等。
- 网络与存储准备:创建沙箱环境(Pause 容器),挂载存储卷并配置网络。
- 运行阶段
- 主容器启动
- PostStart 钩子:在容器启动后执行(如写入日志或初始化脚本)。
- 探针机制
- Liveness Probe:检测容器是否存活,失败则重启容器。
- Readiness Probe:检测容器是否就绪,失败则从服务端点(Endpoint)移除流量。
- 资源管理
- 通过
resources
字段设置 CPU/内存的请求(requests
)和上限(limits
),防止资源争抢。
- 通过
- 终止流程
- 优雅终止
- SIGTERM 信号:通知容器执行清理操作(如关闭数据库连接)。
- 宽限期:默认 30 秒(可配置
terminationGracePeriodSeconds
),超时后强制终止。 - SIGKILL 信号:强制终止未响应的容器并释放资源(如网络端口、存储卷)。
- 垃圾回收:删除 Pod 后,关联资源(如临时存储卷)由 Kubernetes 自动清理。
3.Pod 的重启策略
通过 .spec.restartPolicy
定义容器异常退出时的处理方式:
策略 | 描述 |
---|---|
Always | 始终重启容器(默认策略,适用于长期运行的服务) |
OnFailure | 仅在容器异常退出(非零状态码)时重启,适用于任务型作业 |
Never | 不重启容器,依赖上层控制器(如 Deployment)管理 Pod 生命周期 |
示例配置:
spec:restartPolicy: OnFailurecontainers:- name: appimage: my-app
4.Pod 的状况(Conditions)
Pod 的详细状态通过 Conditions
字段细化:
状况类型 | 描述 |
---|---|
PodScheduled | Pod 已成功调度到节点 |
Initialized | 所有 Init 容器执行完毕 |
ContainersReady | 所有主容器已就绪 |
Ready | Pod 可接收流量(需 Readiness Probe 通过) |
5.设计建议与最佳实践
- 避免直接管理 Pod:使用控制器(如 Deployment、StatefulSet)实现自愈、滚动更新和扩缩容。
- 合理使用探针
- Liveness Probe 防止僵尸进程,Readiness Probe 避免流量涌入未就绪的容器。
- 优化资源配额:设置
requests
和limits
避免资源争抢,提升集群稳定性。 - 优雅终止配置:通过
preStop
钩子确保服务平滑下线(如通知注册中心)。
6.示例:完整生命周期配置
apiVersion: v1
kind: Pod
metadata:name: lifecycle-demo
spec:initContainers:- name: init-dbimage: busyboxcommand: ["sh", "-c", "until nslookup mysql; do sleep 2; done"]containers:- name: nginximage: nginx:latestlifecycle:postStart:exec:command: ["/bin/sh", "-c", "echo 'Started at $(date)' > /usr/share/nginx/html/start.html"]preStop:exec:command: ["nginx", "-s", "quit"]readinessProbe:httpGet:path: /port: 80initialDelaySeconds: 5periodSeconds: 10livenessProbe:tcpSocket:port: 80initialDelaySeconds: 15periodSeconds: 20terminationGracePeriodSeconds: 60
Pod 的生命周期管理是 Kubernetes 编排能力的核心,涵盖调度、初始化、健康检查、优雅终止等关键机制。理解各阶段的触发条件和配置方法,能够有效提升应用的稳定性和可维护性。实际应用中需结合控制器和探针机制,实现自动化运维和故障恢复。
五、Pod的健康检查机制
探针类型 | 作用 | 失败处理 | 探测方式(示例) | 关键参数(示例) |
---|---|---|---|---|
Liveness Probe | 检测容器是否存活(如进程崩溃、死锁)。 | 重启容器 | httpGet 、exec 、tcpSocket | initialDelaySeconds: 15 periodSeconds: 10 failureThreshold: 3 |
Readiness Probe | 检测容器是否就绪(可接收流量)。 | 从 Service 流量中移除该 Pod | httpGet: path=/ready | successThreshold: 1 timeoutSeconds: 5 |
Startup Probe | 检测应用是否完成启动(允许启动慢的服务)。 | 重启容器,直到成功后才执行其他探针 | tcpSocket: port=8080 | failureThreshold: 30 periodSeconds: 5 (允许最长 30×5=150秒启动时间) |
补充说明
- 优先级:
Startup Probe
>Liveness Probe
&Readiness Probe
。 - 参数默认值
initialDelaySeconds
: 0(立即探测)periodSeconds
: 10(每10秒探测一次)timeoutSeconds
: 1(超时1秒视为失败)failureThreshold
: 3(连续失败3次标记为异常)
- 适用场景
- Liveness Probe:防止僵尸进程(如应用死锁但进程仍在运行)。
- Readiness Probe:避免流量涌入未初始化完成的容器(如数据库连接未建立)。
- Startup Probe:为启动缓慢的应用(如 Java 服务)预留足够初始化时间。
六、创建多容器Pod
下面创建一个包含两个容器的pod,两个容器共享一个用于它们之间通信的卷。
(1)创建pod配置文件
[root@master ~]# vim two-containers-pod.yaml
[root@master ~]# cat two-containers-pod.yaml
apiVersion: v1
kind: Pod
metadata:name: two-containers-pod
spec:# Pod级配置restartPolicy: Nevervolumes: # 定义共享数据的卷- name: shared-dataemptyDir: {}containers:# 第1个容器配置- name: nginx-containerimage: nginxvolumeMounts: # 挂载共享卷- name: shared-datamountPath: /usr/share/nginx/html # 挂载路径# 第2个容器配置- name: busybox-containerimage: busyboxvolumeMounts: # 挂载共享卷- name: shared-datamountPath: /pod-data # 挂载路径# 容器启动命令及参数command: ["/bin/sh"] args: ["-c", "echo Hello from the busybox container > /pod-data/index.html"]
[root@master ~]#
该配置文件中为pod定义了一个名为shared-data的共享卷,这是emptyDir类型的卷,只要Pod存在,该卷就一直存在,只有Pod被删除时改卷才会被删除。
两个容器都挂载该卷。第1个容器运行nginx服务器,共享卷的挂载路径是/usr/share/nginx/html;
第2个容器运行BusyBox系统,共享卷挂载路径是/pod-data。
需要注意的是,第2个容器运行容器启动命令,将消息写入指定的index.html文件后会终止运行。由于与第1个容器共享卷,该文件会被写入nginx服务器的根目录下。
(2)基于上述配置文件创建Pod。
[root@master ~]# kubectl apply -f two-containers-pod.yaml
pod/two-containers-pod created
(3)查看Pod及其容器的信息,以YAML格式输出
[root@master ~]# kubectl get pod two-containers-pod --output=yaml
apiVersion: v1
kind: Pod
metadata:annotations:cni.projectcalico.org/containerID: 105c87f280ac172e6204ec63850269d8fe691d1588220ad58cec5c515eef2fcfcni.projectcalico.org/podIP: 10.244.166.142/32cni.projectcalico.org/podIPs: 10.244.166.142/32kubectl.kubernetes.io/last-applied-configuration: |{"apiVersion":"v1","kind":"Pod","metadata":{"annotations":{},"name":"two-containers-pod","namespace":"default"},"spec":{"containers":[{"image":"nginx","name":"nginx-container","volumeMounts":[{"mountPath":"/usr/share/nginx/html","name":"shared-data"}]},{"args":["-c","echo Hello from the busybox container \u003e /pod-data/index.html"],"command":["/bin/sh"],"image":"busybox","name":"busybox-container","volumeMounts":[{"mountPath":"/pod-data","name":"shared-data"}]}],"restartPolicy":"Never","volumes":[{"emptyDir":{},"name":"shared-data"}]}}creationTimestamp: "2025-03-30T11:52:36Z"name: two-containers-podnamespace: defaultresourceVersion: "23136"uid: b8fb5a02-6fe9-4dfc-a096-c1e4d2a49370
spec:containers:- image: nginximagePullPolicy: Alwaysname: nginx-containerresources: {}terminationMessagePath: /dev/termination-logterminationMessagePolicy: FilevolumeMounts:- mountPath: /usr/share/nginx/htmlname: shared-data- mountPath: /var/run/secrets/kubernetes.io/serviceaccountname: kube-api-access-mr94treadOnly: true- args:- -c- echo Hello from the busybox container > /pod-data/index.htmlcommand:- /bin/shimage: busyboximagePullPolicy: Alwaysname: busybox-containerresources: {}terminationMessagePath: /dev/termination-logterminationMessagePolicy: FilevolumeMounts:- mountPath: /pod-dataname: shared-data- mountPath: /var/run/secrets/kubernetes.io/serviceaccountname: kube-api-access-mr94treadOnly: truednsPolicy: ClusterFirstenableServiceLinks: truenodeName: node1preemptionPolicy: PreemptLowerPrioritypriority: 0restartPolicy: NeverschedulerName: default-schedulersecurityContext: {}serviceAccount: defaultserviceAccountName: defaultterminationGracePeriodSeconds: 30tolerations:- effect: NoExecutekey: node.kubernetes.io/not-readyoperator: ExiststolerationSeconds: 300- effect: NoExecutekey: node.kubernetes.io/unreachableoperator: ExiststolerationSeconds: 300volumes:- emptyDir: {}name: shared-data- name: kube-api-access-mr94tprojected:defaultMode: 420sources:- serviceAccountToken:expirationSeconds: 3607path: token- configMap:items:- key: ca.crtpath: ca.crtname: kube-root-ca.crt- downwardAPI:items:- fieldRef:apiVersion: v1fieldPath: metadata.namespacepath: namespace
status:conditions:- lastProbeTime: nulllastTransitionTime: "2025-03-30T11:52:36Z"status: "True"type: Initialized- lastProbeTime: nulllastTransitionTime: "2025-03-30T11:52:36Z"message: 'containers with unready status: [busybox-container]'reason: ContainersNotReadystatus: "False"type: Ready- lastProbeTime: nulllastTransitionTime: "2025-03-30T11:52:36Z"message: 'containers with unready status: [busybox-container]'reason: ContainersNotReadystatus: "False"type: ContainersReady- lastProbeTime: nulllastTransitionTime: "2025-03-30T11:52:36Z"status: "True"type: PodScheduledcontainerStatuses:- containerID: docker://7ac5b9a00e3b01b3f15cd8c3f4c234f02fc39152aa393a13d86cb43a92a09dd8image: busybox:latestimageID: docker-pullable://busybox@sha256:37f7b378a29ceb4c551b1b5582e27747b855bbfaa73fa11914fe0df028dc581flastState: {}name: busybox-containerready: falserestartCount: 0started: falsestate:terminated: //终止containerID: docker://7ac5b9a00e3b01b3f15cd8c3f4c234f02fc39152aa393a13d86cb43a92a09dd8exitCode: 0finishedAt: "2025-03-30T11:52:52Z"reason: CompletedstartedAt: "2025-03-30T11:52:52Z"- containerID: docker://0bce9a982c62efc5d22ca94d4a770a3690d1a62b2cb98c35141986b8b9d4f4b5image: nginx:latestimageID: docker-pullable://nginx@sha256:124b44bfc9ccd1f3cedf4b592d4d1e8bddb78b51ec2ed5056c52d3692baebc19lastState: {}name: nginx-containerready: truerestartCount: 0started: truestate:running: //正在运行startedAt: "2025-03-30T11:52:39Z"hostIP: 192.168.10.31phase: RunningpodIP: 10.244.166.142podIPs:- ip: 10.244.166.142qosClass: BestEffortstartTime: "2025-03-30T11:52:36Z"
可以发现,busybox容器已经被终止,而nginx容器依然在运行
(4)进入nginx容器的Shell环境,使用curl命令向nginx服务器发起请求
[root@master ~]# kubectl exec -it two-containers-pod -c nginx-container -- /bin/bash
root@two-containers-pod:/# curl localhost
Hello from the busybox container
root@two-containers-pod:/# exit
exit
由于busybox容器在nginx容器的根目录下创建了index.html文件,所以这里能够访问该文件。
(5)使用curl命令向Pod的IP地址发起请求,也能访问该index.html文件。
[root@master ~]# curl 10.244.166.142
Hello from the busybox container
[root@master ~]#
(6)执行kubectl delete -f命令删除该pod
[root@master ~]# kubectl delete -f two-containers-pod.yaml
pod "two-containers-pod" deleted
[root@master ~]# kubectl get pod two-containers-pod --output=yaml
Error from server (NotFound): pods "two-containers-pod" not found
七、为Pod及其容器设置资源配额
定义Pod时可以根据需要为每个容器设置所需要的资源数量,也就是资源配额,以免容器占用大量资源导致其他容器无法运行。
1.了解资源配额的设置方法
Kubermetes 使用.spec.resources字段为容器设置资源配额,该字段包括以下两个子字段,用于设置资源配额的上下限。
- requests:设置容器需要的资源的最小值(请求资源),如果环境资源不够,容器将无法启动
- limits:限制容器运行时可用资源的最大值(限制资源),当容器占用的资源超过该值时会被终止,并重启。
实际应用中主要设置CPU和内存这两种资源。CPU资源以CPU为单位,1个CPU等于个物理 CPU核或者一个虚拟核。CPU资源的CPU数可以是整数和小数,也可以用毫核(m)为单位表示。1个CPU等于1000m,Kuberetes不允许设置精度小于1m的CPU资源。内存资源以字节为单位,可以使用普通的整数,或者带有E、P、T、G、M、k等数量单位的数;也可以使用对应的2的幂数,如Ei、Pi、Ti、Gi、Mi、Ki。
2.为Pod容器设置CPU和内存配额
下面创建两个容器的pod,并为每个容器分别设置CPU和内存配额,其中第2个容器使用stress程序做压力测试。stress是Linux的一个压力测试工具,可以对CPU、内存、磁盘等做压力测试。
(1)创建pod配置文件
[root@master ~]# vim resources-limit-pod.yaml
[root@master ~]# cat resources-limit-pod.yaml
apiVersion: v1
kind: Pod
metadata:name: resources-limit-pod
spec:containers:- name: nginximage: nginxresources: # 资源配额limits: # 限制资源(上限)cpu: 200m # CPU限制memory: 400Mi # 内存限制requests: # 请求资源(下限)cpu: 100mmemory: 200Mi- name: stressimage: polinux/stressresources: # 资源配额limits: # 限制资源(上限)memory: "200Mi"requests: # 请求资源(下限)memory: "100Mi"command: ["stress"]args: ["--vm", "1", "--vm-bytes", "150M", "--vm-hang", "1"]
最后两行是第2个容器的启动命令,表示执行stress命令压满150MB内存。–vm选项用于指定进程数量,–vm-bytes选项表示分配的内存量,–vm-hang选项表示内存分配多长时间后释放掉,单位是秒。
(2)基于该配置文件创建pod
[root@master ~]# kubectl apply -f resources-limit-pod.yaml
pod/resources-limit-pod created
(3)验证pod中的容器是否已经运行,可以发现两个容器都能正常运行
[root@master ~]# kubectl get pod
NAME READY STATUS RESTARTS AGE
resources-limit-pod 2/2 Running 0 3m15s
(4)查看pod相关详细信息,可以发现,两个容器的cpu和内存配置限制与定义相同。
[root@master ~]# kubectl get pod resources-limit-pod --output=yaml
apiVersion: v1
kind: Pod
metadata:annotations:cni.projectcalico.org/containerID: 0132686d82d318297fc120bdc1aa9eb0b9220c6bdd8671e58a96df1c52c4ddb5cni.projectcalico.org/podIP: 10.244.166.143/32cni.projectcalico.org/podIPs: 10.244.166.143/32kubectl.kubernetes.io/last-applied-configuration: |{"apiVersion":"v1","kind":"Pod","metadata":{"annotations":{},"name":"resources-limit-pod","namespace":"default"},"spec":{"containers":[{"image":"nginx","name":"nginx","resources":{"limits":{"cpu":"200m","memory":"400Mi"},"requests":{"cpu":"100m","memory":"200Mi"}}},{"args":["--vm","1","--vm-bytes","150M","--vm-hang","1"],"command":["stress"],"image":"polinux/stress","name":"stress","resources":{"limits":{"memory":"200Mi"},"requests":{"memory":"100Mi"}}}]}}creationTimestamp: "2025-03-30T12:15:00Z"name: resources-limit-podnamespace: defaultresourceVersion: "25229"uid: 43751441-ee62-465b-80e8-85e9f5f693fd
spec:containers:- image: nginximagePullPolicy: Alwaysname: nginxresources:limits:cpu: 200mmemory: 400Mirequests:cpu: 100mmemory: 200MiterminationMessagePath: /dev/termination-logterminationMessagePolicy: FilevolumeMounts:- mountPath: /var/run/secrets/kubernetes.io/serviceaccountname: kube-api-access-lsjhlreadOnly: true- args:- --vm- "1"- --vm-bytes- 150M- --vm-hang- "1"command:- stressimage: polinux/stressimagePullPolicy: Alwaysname: stressresources:limits:memory: 200Mirequests:memory: 100MiterminationMessagePath: /dev/termination-logterminationMessagePolicy: FilevolumeMounts:- mountPath: /var/run/secrets/kubernetes.io/serviceaccountname: kube-api-access-lsjhlreadOnly: truednsPolicy: ClusterFirstenableServiceLinks: truenodeName: node1preemptionPolicy: PreemptLowerPrioritypriority: 0restartPolicy: AlwaysschedulerName: default-schedulersecurityContext: {}serviceAccount: defaultserviceAccountName: defaultterminationGracePeriodSeconds: 30tolerations:- effect: NoExecutekey: node.kubernetes.io/not-readyoperator: ExiststolerationSeconds: 300- effect: NoExecutekey: node.kubernetes.io/unreachableoperator: ExiststolerationSeconds: 300volumes:- name: kube-api-access-lsjhlprojected:defaultMode: 420sources:- serviceAccountToken:expirationSeconds: 3607path: token- configMap:items:- key: ca.crtpath: ca.crtname: kube-root-ca.crt- downwardAPI:items:- fieldRef:apiVersion: v1fieldPath: metadata.namespacepath: namespace
status:conditions:- lastProbeTime: nulllastTransitionTime: "2025-03-30T12:15:00Z"status: "True"type: Initialized- lastProbeTime: nulllastTransitionTime: "2025-03-30T12:15:50Z"status: "True"type: Ready- lastProbeTime: nulllastTransitionTime: "2025-03-30T12:15:50Z"status: "True"type: ContainersReady- lastProbeTime: nulllastTransitionTime: "2025-03-30T12:15:00Z"status: "True"type: PodScheduledcontainerStatuses:- containerID: docker://6b98d30bc2f6a52f5902b68125adacb9efe76bfd15651ffc8549fc9fe57299b3image: nginx:latestimageID: docker-pullable://nginx@sha256:124b44bfc9ccd1f3cedf4b592d4d1e8bddb78b51ec2ed5056c52d3692baebc19lastState: {}name: nginxready: truerestartCount: 0started: truestate:running:startedAt: "2025-03-30T12:15:06Z"- containerID: docker://799b744bea3112ae168924495b22689d54c3133f2393c9217f4f9d53f8e6e974image: polinux/stress:latestimageID: docker-pullable://polinux/stress@sha256:b6144f84f9c15dac80deb48d3a646b55c7043ab1d83ea0a697c09097aaad21aalastState: {}name: stressready: truerestartCount: 0started: truestate:running:startedAt: "2025-03-30T12:15:50Z"hostIP: 192.168.10.31phase: RunningpodIP: 10.244.166.143podIPs:- ip: 10.244.166.143qosClass: BurstablestartTime: "2025-03-30T12:15:00Z"
[root@master ~]#
(5)删除该pod以恢复实验环境
[root@master ~]# kubectl delete -f resources-limit-pod.yaml
pod "resources-limit-pod" deleted
[root@master ~]# kubectl get pod
No resources found in default namespace.
[root@master ~]# kubectl get pod resources-limit-pod --output=yaml
Error from server (NotFound): pods "resources-limit-pod" not found
3.测试资源配额超限
当节点拥有足够多的可用资源时,容器可以使用其请求的资源。但是,容器不允许使用超过其限制的资源。如果给容器分配的资源超过其限制,该容器会成为被终止的候选容器。如果容器继续消耗超出其限制的资源,则会被终止。下面进行测试和验证。
(1)修改以上pod配置文件,将最后一行改为
args: ["--vm", "1", "--vm-bytes", "500M", "--vm-hang", "1"]
stress容器会尝试分配500MB的内存,远高于其200MB的限制。
(2)保存该配置文件,重新基于该文件创建pod
[root@master ~]# cp resources-limit-pod.yaml resources-limit-pod-new.yml
[root@master ~]# vi resources-limit-pod-new.yml
[root@master ~]# cat resources-limit-pod-new.yml
apiVersion: v1
kind: Pod
metadata:name: resources-limit-pod
spec:containers:- name: nginximage: nginxresources: # 资源配额limits: # 限制资源(上限)cpu: 200m # CPU限制memory: 400Mi # 内存限制requests: # 请求资源(下限)cpu: 100mmemory: 200Mi- name: stressimage: polinux/stressresources: # 资源配额limits: # 限制资源(上限)memory: "200Mi"requests: # 请求资源(下限)memory: "100Mi"command: ["stress"]args: ["--vm", "1", "--vm-bytes", "500M", "--vm-hang", "1"]
[root@master ~]# kubectl apply -f resources-limit-pod-new.yml
pod/resources-limit-pod created
(3)执行以下命令监视Pod的状态
[root@master ~]# kubectl get pod -w
NAME READY STATUS RESTARTS AGE
resources-limit-pod 1/2 OOMKilled 2 (30s ago) 49s
resources-limit-pod 1/2 CrashLoopBackOff 2 (16s ago) 53s
resources-limit-pod 1/2 OOMKilled 3 (31s ago) 68s
resources-limit-pod 1/2 CrashLoopBackOff 3 (16s ago) 84s
resources-limit-pod 1/2 OOMKilled 4 (47s ago) 115s
resources-limit-pod 1/2 CrashLoopBackOff 4 (15s ago) 2m9s
resources-limit-pod 1/2 OOMKilled 5 (95s ago) 3m29s
resources-limit-pod 1/2 CrashLoopBackOff 5 (14s ago) 3m43s
^C[root@master ~]#
等候一段时间,按ctrl+c组合键终止。
输出结果表明,该pod中有一个容器(stress)被终止、重启、再终止、再重启,默认终止的容器可以被重启,就像其他任何类型的容器运行时是吧一样。另一个容器(nginx)始终处于正常运行状态。
(4)查看pod详细信息
[root@master ~]# kubectl describe pod resources-limit-pod
Name: resources-limit-pod
Namespace: default
Priority: 0
Service Account: default
Node: node1/192.168.10.31
Start Time: Sun, 30 Mar 2025 20:33:58 +0800
Labels: <none>
Annotations: cni.projectcalico.org/containerID: be049fbfabe0d5ecf16f33fa74bbcd5672757e255e0e6a39dbd00a1240f87f7bcni.projectcalico.org/podIP: 10.244.166.144/32cni.projectcalico.org/podIPs: 10.244.166.144/32
Status: Running
IP: 10.244.166.144
IPs:IP: 10.244.166.144
Containers:nginx:Container ID: docker://8696e221f38e5a6c771d51831d6ed86d21d21a94714a06d7706ae1cb860b744dImage: nginxImage ID: docker-pullable://nginx@sha256:124b44bfc9ccd1f3cedf4b592d4d1e8bddb78b51ec2ed5056c52d3692baebc19Port: <none>Host Port: <none>State: RunningStarted: Sun, 30 Mar 2025 20:34:00 +0800Ready: TrueRestart Count: 0Limits:cpu: 200mmemory: 400MiRequests:cpu: 100mmemory: 200MiEnvironment: <none>Mounts:/var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-69nzk (ro)stress:Container ID: docker://09e63ba04e8a8771bec9b61a0240b1660a99bf8ac42e491e42269b7ea72c9595Image: polinux/stressImage ID: docker-pullable://polinux/stress@sha256:b6144f84f9c15dac80deb48d3a646b55c7043ab1d83ea0a697c09097aaad21aaPort: <none>Host Port: <none>Command:stressArgs:--vm1--vm-bytes500M--vm-hang1State: WaitingReason: CrashLoopBackOffLast State: TerminatedReason: OOMKilledExit Code: 1Started: Sun, 30 Mar 2025 20:37:27 +0800Finished: Sun, 30 Mar 2025 20:37:27 +0800Ready: FalseRestart Count: 5Limits:memory: 200MiRequests:memory: 100MiEnvironment: <none>Mounts:/var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-69nzk (ro)
Conditions:Type StatusInitialized True Ready False ContainersReady False PodScheduled True
Volumes:kube-api-access-69nzk:Type: Projected (a volume that contains injected data from multiple sources)TokenExpirationSeconds: 3607ConfigMapName: kube-root-ca.crtConfigMapOptional: <nil>DownwardAPI: true
QoS Class: Burstable
Node-Selectors: <none>
Tolerations: node.kubernetes.io/not-ready:NoExecute op=Exists for 300snode.kubernetes.io/unreachable:NoExecute op=Exists for 300s
Events:Type Reason Age From Message---- ------ ---- ---- -------Normal Scheduled 4m32s default-scheduler Successfully assigned default/resources-limit-pod to node1Normal Pulling 4m31s kubelet Pulling image "nginx"Normal Pulled 4m30s kubelet Successfully pulled image "nginx" in 1.209s (1.209s including waiting)Normal Created 4m30s kubelet Created container nginxNormal Started 4m30s kubelet Started container nginxNormal Pulled 4m22s kubelet Successfully pulled image "polinux/stress" in 8.251s (8.251s including waiting)Normal Pulled 4m14s kubelet Successfully pulled image "polinux/stress" in 7.913s (7.913s including waiting)Normal Pulled 3m55s kubelet Successfully pulled image "polinux/stress" in 3.821s (3.821s including waiting)Normal Pulling 3m26s (x4 over 4m30s) kubelet Pulling image "polinux/stress"Normal Created 3m24s (x4 over 4m22s) kubelet Created container stressNormal Started 3m24s (x4 over 4m22s) kubelet Started container stressWarning BackOff 3m24s (x5 over 4m12s) kubelet Back-off restarting failed container stress in pod resources-limit-pod_default(f3f8166f-7ba2-4e1a-b967-a406b51430fb)Normal Pulled 3m24s kubelet Successfully pulled image "polinux/stress" in 2.069s (2.069s including waiting)
[root@master ~]#
结果表明它由于内存溢出而被"杀掉"
(5)删除该pod以恢复实验环境
[root@master ~]# kubectl delete -f resources-limit-pod-new.yml
pod "resources-limit-pod" deleted
[root@master ~]# kubectl get pod
No resources found in default namespace.
八、实现pod容器的健康检查
kubernetes提供的存活探测器用于实现健康检查,通过检测容器的响应是否正常来决定是否重启容器。pod定义存活探测器,可以让kubernetes自动感知pod是否正常运行。这里以HTTP GET方式为例示范pod容器健康检查的实现方法。
(1)创建pod配置文件
[root@master ~]# vim liveness-probe-pod.yaml
[root@master ~]# cat liveness-probe-pod.yaml
apiVersion: v1
kind: Pod
metadata:name: liveness-probe-pod
spec:containers:- name: liveness-probeimage: nginxlivenessProbe: # 定义存活探测器httpGet:path: /port: 80initialDelaySeconds: 10 # 容器启动后10秒开始探测timeoutSeconds: 2 #容器必须在2秒内做出相应反馈给探测器,否则视为探测失败periodSeconds: 30 # 探测周期,每30秒探测一次successThreshold: 1 # 连续探测1次成功表示成功failureThreshold: 3 # 连续探测3次失败表示失败
[root@master ~]#
探测器向容器的80端口发送HTTP GET请求,如果请求不成功,kubernetes会重启容器。文件中对探测器做了定制,容器启动的10秒后开始探测,如果2秒内容器没有做出回应则被认为探测失败。每30秒做一次探测,再连续探测失败3次后重启容器。
(2)基于配置文件创建pod
[root@master ~]# kubectl apply -f liveness-probe-pod.yaml
pod/liveness-probe-pod created
(3)查看该pod详细信息
[root@master ~]# kubectl get pod
NAME READY STATUS RESTARTS AGE
liveness-probe-pod 1/1 Running 0 118s
[root@master ~]# kubectl describe pod liveness-probe-pod
Name: liveness-probe-pod
Namespace: default
Priority: 0
Service Account: default
Node: node1/192.168.10.31
Start Time: Sun, 30 Mar 2025 20:47:08 +0800
Labels: <none>
Annotations: cni.projectcalico.org/containerID: 711ec9d867e754f658537ac8e0ea66e51a41db795cd55aab978ec7dd8654e502cni.projectcalico.org/podIP: 10.244.166.145/32cni.projectcalico.org/podIPs: 10.244.166.145/32
Status: Running
IP: 10.244.166.145
IPs:IP: 10.244.166.145
Containers:liveness-probe:Container ID: docker://6159e1ef29854643decf37b0df2cd4d5d82f6e316e476ae07118bbc7d725178bImage: nginxImage ID: docker-pullable://nginx@sha256:124b44bfc9ccd1f3cedf4b592d4d1e8bddb78b51ec2ed5056c52d3692baebc19Port: <none>Host Port: <none>State: RunningStarted: Sun, 30 Mar 2025 20:47:11 +0800Ready: TrueRestart Count: 0Liveness: http-get http://:80/ delay=10s timeout=2s period=30s #success=1 #failure=3Environment: <none>Mounts:/var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-pw9z2 (ro)
Conditions:Type StatusInitialized True Ready True ContainersReady True PodScheduled True
Volumes:kube-api-access-pw9z2:Type: Projected (a volume that contains injected data from multiple sources)TokenExpirationSeconds: 3607ConfigMapName: kube-root-ca.crtConfigMapOptional: <nil>DownwardAPI: true
QoS Class: BestEffort
Node-Selectors: <none>
Tolerations: node.kubernetes.io/not-ready:NoExecute op=Exists for 300snode.kubernetes.io/unreachable:NoExecute op=Exists for 300s
Events:Type Reason Age From Message---- ------ ---- ---- -------Normal Scheduled 2m14s default-scheduler Successfully assigned default/liveness-probe-pod to node1Normal Pulling 2m14s kubelet Pulling image "nginx"Normal Pulled 2m12s kubelet Successfully pulled image "nginx" in 2.054s (2.054s including waiting)Normal Created 2m12s kubelet Created container liveness-probeNormal Started 2m12s kubelet Started container liveness-probe
[root@master ~]#
可以发现,该pod当前处于正常运行状态(running),重启次数(Restart Count)为0,表面目前没有重启,容器一直处于健康状态。如果重启次数大于0,则说明已经重启,容器曾有过"不健康"的历史。
(4)删除该pod以恢复实验环境
[root@master ~]# kubectl delete pod liveness-probe-pod
pod "liveness-probe-pod" deleted
[root@master ~]# kubectl get pod
No resources found in default namespace.
以上示范的是常见的探测方法,其具体机制是向容器发送HTTP GET请求,如果探测器收到“2xx”或“3xx”信息,说明容器是健康的。
环境变量是pod容器运行环境中设定的一个变量,便于对容器进行灵活的配置。创建pod时,可以通过配置文件的.spec.env和.spec.envFrom字段来设置环境变量。