一、Pod简述
Pod是k8s
(下文Kubernetes简称k8s)的一个抽象概念,Pod本身不是容器。但Pod是由一个或多个容器组成。是 k8s 项目中最小原子调度单位。如果把k8s比作操作系统,那么容器就是进程,而Pod的话就是进程组的概念。
二、Namespace共享原理
同一个Pod里的所有容器,共享的是同一个Nettwork Namespace,并且可以声明同一个Volume
在 Kubernetes 项目里,Pod 的实现需要使用一个中间容器,这个容器叫作 Infra
容器。在这个 Pod 中,Infra 容器永远都是第一个被创建的容器,而其他用户定义的容器,则通过 Join Network Namespace 的方式,与 Infra 容器关联在一起。这样的组织关系,可以用下面这样一个示意图来表达:
Infra容器 全称infrastucture container(又叫Pause)基础容器,作为init pod存在,所有当我们创建Pod是都会看到一个Pause容器被创建。现在我们终于知道pause类型镜像(k8s.gcr.io/pause:3.2)的作用是什么。
三、Init容器
1.理解
Init 容器是一种特殊容器,在 Pod 内的应用容器启动之前运行。
**每个Pod中可以包含很多容器,但是有的容器可能依赖某一个功能或特性,需要提前启动一个容器为它提供服务。就像我们使用yum安装一些服务时,会有很多依赖项,如果我们没有安装这个依赖,这个服务会始终安装失败。我们的pod也是,如果Pod的Init容器启动失败,kubelet会不断重启Init容器直到成功,并且Pod的Init容器失败,整个Pod状态也会设置为失败,就像安装依赖一样。**
2.示例
例子定义了一个具有 1 个 Init 容器的简单 Pod。 init
容器拉去k8s页面存放到nginx默认路径,当Init容器运行过程中,Pod的状态为Init:0/1
,init容器启动成功后,pod状态变为Running
1>创建nginx-init.yaml文件
---
apiVersion: v1
kind: Pod
metadata:
name: nginx-init
spec:
initContainers:
- name: install
image: busybox
command:
- wget
- "-O"
- "/work-dir/index.html"
- http://kubernetes.io
volumeMounts:
- name: workdir
mountPath: "/work-dir"
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
volumeMounts:
- name: workdir
mountPath: /usr/share/nginx/html
volumes:
- name: workdir
emptyDir: {}
2>通过运行下面命令启动Pod:
[root@ycloud ~]# kubectl apply -f nginx-init.yaml
pod/myapp-pod created
3>验证
[root@ycloud ~]# kubectl get po -owide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-init 1/1 Running 0 13m 100.111.212.6 ycloud <none> <none>
[root@ycloud ~]# curl 100.111.212.6
<!doctype html><html lang=en class=no-js><head class=live-site><meta name=ROBOTS content="INDEX, FOLLOW">
.....
四、生命周期
Pod的生命周期变化主要体现在status
变化,最初状态为Pending
阶段,至少要有一个应用容器启动成功后,则进入Running
,之后取决于 Pod 中是否有容器以 失败状态结束而进入 Succeeded
或者 Failed
阶段。
- Pending。这个状态意味着,Pod 的 YAML 文件已经提交给了 Kubernetes,API 对象已经被创建并保存在 Etcd 当中。但是,这个 Pod 里有些容器因为某种原因而不能被顺利创建。比如,调度不成功。
- Running。这个状态下,Pod 已经调度成功,跟一个具体的节点绑定。它包含的容器都已经创建成功,并且至少有一个正在运行中。
- Succeeded。这个状态意味着,Pod 里的所有容器都正常运行完毕,并且已经退出了。这种情况在运行一次性任务时最为常见。
- Failed。这个状态下,Pod 里至少有一个容器以不正常的状态(非 0 的返回码)退出。这个状态的出现,意味着你得想办法 Debug 这个容器的应用,比如查看 Pod 的 Events 和日志。
- Unknown。这是一个异常状态,意味着 Pod 的状态不能持续地被 kubelet 汇报给 kube-apiserver,这很有可能是主从节点(Master 和 Kubelet)间的通信出现了问题。
五、容器状态
Kubernetes 会跟踪 Pod 中每个容器的状态,就像它跟踪 Pod 总体上的阶段一样。 你可以使用容器生命周期回调 来在容器生命周期中的特定时间点触发事件。
一旦调度器将 Pod 分派给某个节点,kubelet
就通过 容器运行时 开始为 Pod 创建容器。 容器的状态有三种:Waiting
(等待)、Running
(运行中)和 Terminated
(已终止)。
六、Pod使用过程中的重要字段:
凡是调度、网络、存储,以及安全相关的属性,基本上是 Pod 级别的。
1.NodeSelector:是一个供用户将 Pod 与 Node 进行绑定的字段.
apiVersion: v1
kind: Pod
...
spec:
nodeSelector:
disktype: ssd
指明Pod永远只能运行在携带“disktype: ssd”标签的节点上;否则会调度失败
2.HostAliases:定义了 Pod 的 hosts 文件(比如 /etc/hosts)的内容
apiVersion: v1
kind: Pod
...
spec:
hostAliases:
- ip: "10.1.2.3"
hostnames:
- "foo.remote"
- "bar.remote"
...
在Pod的YAML文件中,我们添加了一组映射关系。
如果我们咋pod启动之后进入pod内去手动添加hosts文件,这样有一个弊端就是当pod重启后,文件将重载。
cat /etc/hosts
# Kubernetes-managed hosts file.
127.0.0.1 localhost
...
10.244.135.10 hostaliases-pod
10.1.2.3 foo.remote
10.1.2.3 bar.remote
3.凡是跟容器的 Linux Namespace 相关的属性,也一定是 Pod 级别的
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
shareProcessNamespace: true
containers:
- name: nginx
image: nginx
- name: shell
image: busybox
stdin: true
tty: true
shareProcessNamespace: true
意味着这个Pod里的容器要共享PID Namespace
[root@ycloud kubernetes]# kubectl apply -f shareproccessnamespace.yaml
pod/nginx created
---
[root@ycloud kubernetes]# kubectl exec -it nginx -c shell -- /bin/sh
/ # ps ax
PID USER TIME COMMAND
1 root 0:00 /pause
8 root 0:00 nginx: master process nginx -g daemon off;
39 101 0:00 nginx: worker process
40 101 0:00 nginx: worker process
41 101 0:00 nginx: worker process
42 101 0:00 nginx: worker process
43 root 0:00 sh
57 root 0:00 /bin/sh
64 root 0:00 ps ax
/ #
可以看到,在这个容器里,我们不仅可以看到它本身的 ps ax 指令,还可以看到 nginx 容器的进程,以及 Infra 容器的 /pause 进程。这就意味着,整个 Pod 里的每个容器的进程,对于所有容器来说都是可见的:它们共享了同一个 PID Namespace。
4.Pod中的容器共享主机的Namespace
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
hostNetwork: true
hostIPC: true
hostPID: true
containers:
- name: nginx
image: nginx
- name: shell
image: busybox
stdin: true
tty: true
在这个 Pod 中,我定义了共享宿主机的 Network、IPC 和 PID Namespace。这就意味着,这个 Pod 里的所有容器,会直接使用宿主机的网络、直接与宿主机进行 IPC 通信、看到宿主机里正在运行的所有进程。
5.Lifecycle处理
k8s 支持 postStart 和 preStop 事件。 当一个容器启动后,k8s 将立即发送 postStart 事件;在容器被终结之前, k8s 将发送一个 preStop 事件。容器可以为每个事件指定一个处理程序。
apiVersion: v1
kind: Pod
metadata:
name: lifecycle-demo
spec:
containers:
- name: lifecycle-demo-container
image: nginx
lifecycle:
postStart:
exec:
command: ["/bin/sh", "-c", "echo Hello from the postStart handler > /usr/share/message"]
preStop:
exec:
command: ["/bin/sh","-c","nginx -s quit; while killall -0 nginx; do sleep 1; done"]
你可以看到 postStart 命令在容器的 /usr/share
目录下写入文件 message
。 命令 preStop 负责终止 nginx 服务。当因为失效而导致容器终止
[root@ycloud ~]# kubectl exec -it lifecycle-demo -- cat /usr/share/message
Hello from the postStart handler
k8s 在容器结束前立即发送 preStop 事件。除非 Pod 宽限期限超时,k8s 的容器管理逻辑 会一直阻塞等待 preStop 处理函数执行完毕。
总结
这篇文章中,主要讲解了pod对象,一些重要字段,分析了Pod Namespace共享原理以及Pod的生命周期。
Pod对象是k8s中比较核心的一个概念,在后面的控制器学习中都会用到。
参考文献
https://time.geekbang.org/column/article/40366
https://kubernetes.io/zh-cn/docs/concepts/workloads/pods/
https://kubernetes.io/zh-cn/docs/tasks/configure-pod-container/