目录
0. 为什么叫 Pod
Pod 这个词原意是“豌豆荚”,后来又延伸出“舱室”“太空舱”等含义。豌豆荚内部包含着一些豌豆本体。
运行在容器里的应用具有良好的隔离性,能够让开发者方便地管理依赖也一定程度上保证了应用的安全性。这种隔离性带来了一些麻烦。因为很少有应用是完全独立运行的,经常需要几个进程互相协作才能完成任务,比如一个简单的博客应用也需要博客应用本身和数据库协作提供服务。还有一些特殊的情况,多个应用结合得非常紧密以至于无法把它们拆开。比如,有的应用运行前需要其他应用帮它初始化一些配置,还有就是日志代理,它必须读取另一个应用存储在本地磁盘的文件再转发出去。这些应用如果被强制分离成两个容器,切断联系,就无法正常工作了。
为了解决这样多应用联合运行的问题,同时还要不破坏容器的隔离,就需要在容器外面再建立一个“收纳舱”,让多个容器既保持相对独立,又能够小范围共享网络、存储等资源。Pod 的概念也就呼之欲出了,容器正是“豆荚”里那些小小的“豌豆”,你可以在 Pod 的 YAML 里看到,“spec.containers”字段其实是一个数组,里面允许定义多个容器。
1. Pod 是 Kubernetes 中的核心对象
Pod 是对容器的“打包”,Pod 中的容器总是能够一起被调度,一起运行。Pod 这个抽象的整体属于 Kubernetes 管理,Pod 可以在不触碰底层容器的情况下任意定制。可以说,有了 Pod,Kubernetes 在集群级别上的管理就会变得得心应手。
Kubernetes 让 Pod 去编排处理容器,然后把 Pod 作为应用调度部署的最小单位,Pod 也因此成为了 Kubernetes 世界里的“原子”(当然这个“原子”内部是有结构的),基于 Pod 就可以构建出更多更复杂的业务形态了。
这张图现在已经不能全面地描述 Kubernetes 的资源对象了,但是我们还是可以从图中看出 Kubernetes 资源都是直接或者间接通过 Pod 实现,Pod 确实是 Kubernetes 的核心对象。
2. 使用 YAML 描述 Pod
提示:上篇提到我们可以使用
kubectl explain
查看任意字段的详细说明
Pod 是 API 对象,它必然有 apiVersion
kind
metadata
spec
四个基本的组成部分。对于一个 Pod 来说,apiVersion
和 kind
是固定值 v1
和 Pod
。一般来说,matadata
里面应该有 name
和 label
两个字段。
在 Kubernetes 里,Pod 必须要有一个名字,这也是 Kubernetes 里所有资源对象的一个约定。name 只是一个基本的标识,信息有限,所以 labels 字段就派上了用处。它可以添加任意数量的 Key-Value,给 Pod“贴”上归类的标签,结合 name 就更方便识别和管理了。
下面我们描述一个简单的 Pod:
apiVersion: v1
kind: Pod
metadata:
name: busy-pod
labels:
owner: backend-dev-team
env: dev
region: north
tier: back
“metadata”一般写上 name 和 labels 就足够了,而“spec”字段由于需要管理、维护 Pod 这个 Kubernetes 的基本调度单元,里面有非常多的关键信息。其中至关重要的是 container
。还有 restartPolicy
hostname
等字段,可以使用 kubectl explain
查询。
containers
是一个数组,里面的每一个元素又是一个 container
对象,也就是容器。和 Pod 一样,container 对象也必须要有一个 name 表示名字,然后当然还要有一个 image 字段来说明它使用的镜像,这两个字段是必须要有的,否则 Kubernetes 会报告数据验证错误。
下面是几个基本的 container
对象的字段:
-
ports
- 列出容器对外暴露的端口 -
imagePullPolicy
- 指定镜像拉取的策略,可以是Always
Never
IfNotPresent
-
env
- 定义 Pod 的环境变量,运行时指定 -
command
- 容器启动时要执行的命令,类似 dockerfile 里的 EntryPoint -
args
- command 运行时的参数
下面是为 busy-pod
编写的 spec:
spec:
containers:
- image: busybox:latest
name: busy
imagePullPolicy: IfNotPresent
env:
- name: os
value: "ubuntu"
- name: debug
value: "on"
command:
- /bin/echo
args:
- "$(os), $(debug)"
3. 使用 kubectl
操作 Pod
$ kubectl apply -f busy-pod.yml
$ kubectl delete -f busy-pod.yml
也可以使用 name
$ kebectl delete pod nusy-pod
我们可以用命令 kubectl logs
,它会把 Pod 的标准输出流信息展示给我们看,在这里就会显示出预设的两个环境变量的值:
$ kubectl logs busy-pod
我们可以使用下面的命令查看 Pod 的状态
$ kubelet get pods
刚才生成的 Pod 的状态是 CrashLoopBackOff
,我们用下面的命令仔细检查下 Pod 的状态
$ kubectl describe pod busy-pod
Name: busy-pod
Namespace: default
Priority: 0
Service Account: default
Node: minikube/192.168.49.2
Start Time: Thu, 29 Sep 2022 10:32:56 +0800
Labels: env=dev
owner=backend-dev-team
region=north
tier=back
Annotations: <none>
Status: Running
IP: 172.17.0.3
IPs:
IP: 172.17.0.3
Containers:
busy:
Container ID: docker://3dc27aa07b30f65887c7d525e4aa60eb633250963fa8f2db4f995a94452f3e07
Image: busybox:latest
Image ID: docker-pullable://busybox@sha256:ad9bd57a3a57cc95515c537b89aaa69d83a6df54c4050fcf2b41ad367bec0cd5
Port: <none>
Host Port: <none>
Command:
/bin/echo
Args:
$(os), $(debug)
State: Waiting
Reason: CrashLoopBackOff
Last State: Terminated
Reason: Completed
Exit Code: 0
Started: Thu, 29 Sep 2022 10:38:55 +0800
Finished: Thu, 29 Sep 2022 10:38:55 +0800
Ready: False
Restart Count: 6
Environment:
os: ubuntu
debug: on
Mounts:
/var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-d2k7b (ro)
Conditions:
Type Status
Initialized True
Ready False
ContainersReady False
PodScheduled True
Volumes:
kube-api-access-d2k7b:
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 Scheduled 9m48s default-scheduler Successfully assigned default/busy-pod to minikube
Normal Pulling 9m47s kubelet Pulling image "busybox:latest"
Normal Pulled 9m34s kubelet Successfully pulled image "busybox:latest" in 13.564367044s
Normal Created 8m (x5 over 9m34s) kubelet Created container busy
Normal Started 8m (x5 over 9m33s) kubelet Started container busy
Normal Pulled 8m (x4 over 9m33s) kubelet Container image "busybox:latest" already present on machine
Warning BackOff 4m44s (x24 over 9m32s) kubelet Back-off restarting failed container
需要关注的是末尾的 Events
,它显示的是 Pod 运行过程中的一些关键节点事件。对于这个 busy-pod,因为它只执行了一条 echo 命令就退出了,而 Kubernetes 默认会重启 Pod,所以就会进入一个反复停止 - 启动的循环错误状态。
另外,kubectl 也提供与 docker 类似的 cp 和 exec 命令,kubectl cp 可以把本地文件拷贝进 Pod,kubectl exec 是进入 Pod 内部执行 Shell 命令,用法也差不多。
$ kubectl cp example.txt busy-pod:/tmp
$ kubectl exec -it ngx-pod -- sh
扩展
-
Pod 管理了多个进程,也可以理解为 Linux 里的“进程组”这个概念。Pod 也可以被成为“容器组”,或者“逻辑主机”;
-
Pod 内部有一个名为
infra
的容器,它实际上代表 Pod,维护 Pod 内多容器共享的主机名、网络和存储。infra
容器的镜像叫pause
,只有不到 500 KB; -
metadata
里面的标签不能随意写,必须符合域名规范(FQDN); -
kubectl get pods
里面的 READY 一栏显示的是 Pod 内的容器状态,格式是x/y
,表示总共定义 y 个容器,其中 x 个是正常的。