K8S 之 Pod

摘要

Pod 介绍

  • Pod 是可以在 Kubernetes 中创建和管理的、最小的可部署的计算单元。

  • Pod(就像在豌豆荚中)是一组(一个或多个) 容器,这些容器共享存储、网络、以及怎样运行这些容器的规约。

  • Pod 中的内容总是并置(colocated)的并且一同调度,在共享的上下文中运行。

  • Kubernetes 集群中的 Pod 主要有两种用法:

    • 运行单个容器的 Pod: "每个 Pod 一个容器"模型是最常见的 Kubernetes 用例,在这种情况下,可以将 Pod 看作单个容器的包装器,并且 Kubernetes 直接管理 Pod,而不是容器。
    • 运行多个协同工作的容器的 Pod: Pod 可以封装由紧密耦合且需要共享资源的多个并置容器组成的应用,这些位于同一位置的容器构成一个内聚单元。

Pod 管理

Pod 创建

  • run 创建

1
2
3
4
5
kubectl run nginx --image=nginx
# 输出 yaml
kubectl run nginx --image=nginx --dry-run=client -o yaml > pod.yaml
# 通过 yaml 文件创建
kubectl apply -f pod.yaml
  • pod.yaml 文件说明

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
apiVersion: v1                   # 必填。指定使用的 API 版本,Pod 是核心资源,使用 v1
kind: Pod # 必填。资源类型:Pod
metadata:
creationTimestamp: null # ✅ 可省略。由 Kubernetes 系统自动填充
labels:
run: nginx # ⚠️ 可省略,但建议保留。用于标识 Pod,可供 Service/Selector 匹配
name: nginx # 必填。Pod 的名称,命名空间中唯一
spec:
containers:
- image: nginx # 必填。容器使用的镜像
name: nginx # 必填。容器名称,在同一个 Pod 内必须唯一
resources: {} # ✅ 可省略。未设置 CPU/内存请求或限制时可以不写
dnsPolicy: ClusterFirst # ⚠️ 可省略。默认就是 ClusterFirst,仅在自定义 DNS 设置时需要写
restartPolicy: Always # ⚠️ 可省略。Pod 默认策略是 Always,除非你是 Job 场景
status: {} # ✅ 可省略。由 Kubernetes 控制器动态填充,不需要手动定义
  • Pod 通常不是直接使用 run 创建的,而是使用工作负载资源创建的,如 Deployment, StatefulSet, DaemonSet。

1
2
3
4
5
6
# 创建 Pod
kubectl create deployment nginx --image=nginx
# 生成 yaml 文件,不真的执行创建
kubectl create deployment nginx --image=nginx --dry-run=client -o yaml > deployment.yaml
# 通过 yaml 文件创建
kubectl apply -f deployment.yaml
  • deployment.yaml 文件说明

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
apiVersion: apps/v1                  # 指定使用的 API 版本,这里是 apps/v1,适用于 Deployment 资源
kind: Deployment # Kubernetes 资源类型,这里是部署(Deployment)
metadata:
creationTimestamp: null # ✅ 可省略,通常由系统自动填充
labels:
app: nginx # 标签,用于标识资源,可与 selector 匹配
name: nginx # 资源名称,必须唯一(在同一命名空间下)
spec: # 配置项
replicas: 1 # 副本数,表示希望运行多少个 Pod 实例
selector: # 选择器,指定要管理的 Pod
matchLabels: # 标签选择器
app: nginx # 选择器,指定 Deployment 管理哪些 Pod(标签必须与 template 中匹配)
strategy: {} # ✅ 可省略,表示使用默认的滚动更新策略
template: # 模板,定义 Pod 的内容
metadata:
creationTimestamp: null # ✅ 可省略,由系统自动填充
labels:
app: nginx # Pod 的标签,必须与 selector 中的 matchLabels 一致
spec:
containers:
- image: nginx # 容器使用的镜像,这里是官方的 nginx 镜像
name: nginx # 容器的名称
resources: {} # ✅ 可省略,表示未设置资源请求/限制
status: {} # ✅ 可省略,状态信息由 Kubernetes 系统自动生成

小贴士

  • yaml 文件中,出现了 metadata.labels,spec.selector.matchLabels 以及 template.metadata.labels,三者是什么关系?
  1. metadata.labels(Deployment 的标签)

给 Deployment 本身 打的标签, 和 Pod 没有直接管理关系
常用于资源分组、查找(比如:kubectl get deploy -l app=nginx)

1
2
3
metadata:
labels:
app: nginx # 属于这个 Deployment 的“标签”,只是标识它自己
  1. spec.selector.matchLabels(选择器)

指定 Deployment 要管理哪些 Pod
必须精确匹配 Pod 的标签
决定 Deployment 会不会“接管”某些 Pod

1
2
3
4
spec:
selector:
matchLabels:
app: nginx
  1. template.metadata.labels(模板中的 Pod 标签)

Pod 模板中定义的标签
Deployment 按这个模板创建 Pod
必须与 matchLabels 完全一致,否则会报错

1
2
3
4
template:
metadata:
labels:
app: nginx # Pod 的标签,必须与 selector 匹配!

🔁 关系图示意:

1
2
3
4
5
6
7
Deployment

├─ metadata.labels Deployment 本身的标签(非关键)

├─ spec.selector.matchLabels ─┐

└─ spec.template.metadata.labels 必须匹配 selector,才能让 Pod Deployment 管理

查看 Pod

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 查看 Pod,默认显示 default 命名空间下的 Pod
kubectl get pods
# 查看 kube-system 命名空间下的 Pod
kubectl get pods -n kube-system
# 查看所有命名空间下的 Pod
kubectl get pods -A
# -o wide: 显示 Pod 的详细信息,此时会看到 pod 的 IP 地址、节点名称等信息
kubectl get pods -o wide
# 显示 Pod 的标签
kubectl get pod --show-labels
# 按 Pod 的标签进程查询
kubectl get pod -l <label_name>=<label_value>
# 持续查看 Pod 的状态,当 pod 状态发生改变时,会实时显示
kubectl get pods -w
## 状态类型
- Pending: Pod 尚未就绪
- ContainerCreating: Pod 正在创建容器
- Running: Pod 正在运行
- Error: Pod 运行错误
- Terminating: Pod 正在删除
- Completed: Pod 执行完成

查看 Pod 详情

  • 当 pod 运行错误时,可以通过该命令查看 pod 的详情,找到错误原因

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
kubectl describe pod <pod-name>
kubectl describe pod <pod-name> -n <namespace-name>

## 排查原因时主要观察最后的 Events,从上到下就是 Pod 的运行过程
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
# 被调度器分配到 k8s-worker2 节点
Normal Scheduled 4s default-scheduler Successfully assigned default/nginx to k8s-worker2
# 开始拉取镜像
Normal Pulling <invalid> kubelet Pulling image "nginx"
# 镜像拉取成功
Normal Pulled <invalid> kubelet Successfully pulled image "nginx" in 2.067s (2.067s including waiting). Image size: 72225394 bytes.
# 开始创建容器
Normal Created <invalid> kubelet Created container: nginx
# 容器启动成功
Normal Started <invalid> kubelet Started container nginx

进入容器

1
2
# kubectl exec -it <pod-name> -n <namespace-name> -- <command>
kubectl exec -it nginx -- /bin/bash

删除 Pod

1
2
kubectl delete pod <pod-name>
kubectl delete pod <pod-name> -n <namespace-name>

查看 Pod 日志

1
2
3
kubectl logs <pod-name>
kubectl logs pod/<pod-name>
kubectl logs pod/<pod-name> -n <namespace-name>

访问 Pod

  • 我们刚刚创建了一个nginx的pod,该如何访问呢?

1
2
3
4
5
6
7
# 获取pod的ip
$ k get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx 1/1 Running 0 12m 10.244.126.8 k8s-worker2 <none> <none>

# 在任意节点上访问,nginx 默认端口是80
$ curl 10.244.126.8
  • 暂时我们还不能通过节点的 IP 访问 Pod,因为 Pod 运行在容器网络中,等我后面讲解 deployment 和 service 之后,会介绍如何通过 service 访问

一个 Pod 运行多个容器

  • yaml 文件

1
2
3
4
5
6
7
8
9
10
apiVersion: v1
kind: Pod
metadata:
name: multi-pod
spec:
containers:
- name: nginx
image: nginx
- name: tomcat
image: tomcat
  • 运行 pod

1
kubectl apply -f multi_pod.yaml
  • 查看运行结果

1
2
3
4
# 这里看到,READY 里有两个,表示两个容器都运行成功
$ kubectl get pods -owide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
multi-pod 2/2 Running 0 118s 10.244.194.81 k8s-worker1 <none> <none>
  • 访问nginx和tomcat

1
2
3
4
# 访问nginx,ngxin默认端口是80
curl http://10.244.194.81
# 访问tomcat,tomcat默认端口是8080,因为tomcat的webapp是空的,所以看到404就说明正常
curl http://10.244.194.81:8080
  • 进入容器执行命令

1
2
3
4
5
6
7
# 进入nginx容器,-c 指定容器名称
kubectl exec -it multi-pod -c nginx -- /bin/bash
## 进入nginx容器后访问tomcat可以正常访问,说明同一个pod中的容器共享资源
curl http://localhost:8080

# 进入tomcat容器
kubectl exec -it multi-pod -c tomcat -- /bin/bash