企业级运维之云原生与Kubernets实战课程
第一章第3讲 理解Pod和容器设计
视频地址:https://developer.aliyun.com/learning/course/913/detail/14498
摘要:本节课主要介绍Pod概念、Pod解决的问题、Pod启动流程、Pod生命周期管理、Pod中服务探活和K8s常用的命令。
一、为什么需要Pod
1. 思考:Pod是什么?
Kubernetes = 操作系统(如Linux)
容器 = 进程(Linux线程)
Pod = ?
Pod就是进程组 (Linux线程组)
2. Pod容器的主程序
Pod中可能包含了不止一个容器,容器之间哪个是主程序?它们之间会互相控制吗?
假如Pod中存在两个容器A和B,容器通过Namespace和Cgroup进行进程隔离,那么容器A和B在自己的命名空间下,都会认为自己是主程序,Pid为1。
- ps -ef:查看进程,可以看到进程Pid为1的进程为system,其他进程都是通过这个父进程进行启动的;
- pstree -t -p 加上进程号:查看进程树结构;
- kubectl get pod:查看默认命名空间下的Pod;
- kubectl get ns:查看所有的命名空间;
- kubectl get pod -A:查看所有命名空间下的Pod;
- kubectl get pod -n default -o wide:可以查看默认命名空间下Pod运行在哪个节点上;
- kubeclt describe pod 跟上Pod名称:查看Pod的信息;
- docker inspect 加上运行镜像ID:查看容器在宿主机上的进程,可以得出容器A和容器B没有关联性,没有父子进程和相互依赖关系。
3. Pod对容器的管理
- Pod使用声明式结构,通过Pod的yaml格式声明了容器A和容器B,用这种方式去管理K8s的Pod。
- 一个Pod中存在容器A和容器B,两个容器有相同的网络命名空间和IPC命名空间,实现了网络命名空间和IPC命名空间的互通,查看命令:kubectl exec -it-c 加上应用名字 --bash
二、Pod要解决的问题
容器之间原本是被Linux Namespace和Cgroup隔离开的,如何让一个Pod里的多个容器之间,最高效的共享某些资源和数据?
1. 共享网络
Pod是逻辑上的概念,没有以Pod的维度在宿主机上运行,它所有的进程都是以容器维度在宿主机上运行,而网络的命名空间的实现是以Pod在宿主机上运行时,通过运行pause的小容器来共享同一个网络命名空间,实现不同容器之间的通信。
比如说在Kubernetes里,容器A和容器B要共享Network Namespace,它会在每个Pod里,额外起一个Infra container小容器,来共享整个Pod的Network Namespace。
2. 共享存储
apiversion:v1
kind:Pod
metadata:
name:two-containers
spec:
restartPolicy:Never
volumes:
-name:shared-data
hostPath:
path:/data
containers:
-name:nginx-container
image:nginx
volumeMounts:
-name:shared-data
mountPath/usr/share/nginx/html
-name:debian-container
image:debian
volumeMounts:
-name:shared-data
mountPath:/pod-data
command:["/bin/sh"]
args:["-c","echo Hello from the debian container>/
pod-data/indexhtml"]
shared-data对应在宿主机上的目录会被同时绑定挂载进了上述两个容器当中。
三、Pod的启动流程
所有的应用都是在Pod上运行的,应用在更新时会遇到一些未知的问题,如:502错误、进程不可用、流量打到了Terminating状态的Pod、已被删除的Pod或正在启动的Pod上,如何在生产环境实现平滑的升级,避免更新升级时出现的问题,可以从SVC维度或者Pod维度去解决这个问题。
下面探讨一下从Pod维度实现平滑的升级,如何让Pod正常完成启动后才承受流量。
1. Pod启动流程
a. initial container:依次运行直到成功才会退出进入下个环节,作用是准备环境。
b. 多个init:如果失败,会根据设置的restartpolicy进行判断。
c. Main container:通过poststart运行预先设定的命令,准备程序需要的环境,如果收到了要终止容器的通知,可以通过设置prestop相关指令,合理化的终止,从业务上是连续的并没有中断。
2. 探针
Pod正常启动后,如何判断能否让该容器承受流量呢?K8s提供了readnessProbe和LivenessProbe探针:
- readnessProbe就绪检查达到一定的符合条件Pod才会加到 SVC(VIP)的后端,才可以承受业务流量;
- LivenessProbe存活检查,设定一定的业务维度探测手段,如果pod正常的,可以承受业务流量,如果不正常就会把Pod剔除掉;
- 如果同时设置两种探针,是都生效运行的,如果LivenessProbe设置不合理,有一种可能readnessProbe还未成功,LivenessProbe就已经失败,导致容器被剔除,一直重启;
- 还有一个startupProbe启动探针,如果该探针没有检测成功,其他探针则不会运行。
探针的作用:
- 运行某些命令
- 检测tcp端口
- 通过http get请求探测
判断条件:
可以设置多久做一次探测,探测成功多少次认为探针检查成功,及连续探测多少次失败才认为探针失败,进行相应动作处理。
四、Pod的Yaml文件讲解
ApiVersion:K8s标准;
Kind:定义类型;
Metadata:元数据信息;
Lables:为Pod打标签;
Name:为Pod命名;
Namespace:部署的命名空间;
Spec:在这里进行设置容器信息,可以设置initContainers(特权容器);
initContainers:可以定义容器镜像,镜像拉取策略,环境初始化准备;
ImagePullPolicy:可以为Always总是拉取镜像,或IfNotPresent如果本地不存在拉取镜像;
VolumeMounts:设置mountPath挂载路径和挂载方式(如hostpath宿主机挂载);
Lifecycle:设置生命周期,prestop设置容器退出前执行的操作;
Resources:设置资源限制,limit设置最大使用内存和CPU大小,request设置最小运行内存和CPU大小;
StartupProbe:设置启动探针,设置探测的路径和端口及探测方式、延迟探测时间、探测频率及次数;
ReadinessProbe及livenessProbe也是可以设置探针进行服务探活,设置方式和StartupProbe类似。
通过K8s常用命令(如kubectl describe pod、get、apply等)可以看到Pod的运行状态、Namespace、节点及Pod IP、启动时间等信息;可以查看到容器ID进而到宿主机上通过该ID找到运行的容器,查看到容器启动命令及容器init containers后的状态、状态码,通过退出状态码找到原因;查看到资源的限制情况及生命周期设置、挂载卷情况;QoS表示服务的优先级,由bestoiiort、Burstatble、guaranleed依次升高。
在容器内资源限制目录/proc/sys/fs/cgroup,可以查看包括对CPU、内存的限制,如果CPU和内存超出了限制,会导致Pod级别的OOM(内存泄露),而非系统级别的OOM,有时候流量打到SVC后端,Pod响应很慢,也是因为资源超限导致。
五、本节小结
1.Pod是什么维度,为什么需要Pod,Pod是逻辑还是物理。
2.Pod中容器在宿主机上是怎么体现的包括进程,cqroup,namespace,Pod的启动过程,启动中的探针,探针设置包括readiness、livesness、startup,pod根据规则对容器进行相应的处理。
3.Pod生命周期管理(poststart和prestop)。
4.K8s常见命令kubelet,get,apply。
下节课主要讲解Pod管理,Pod怎么通过IP暴露服务,管理有哪些型,SVC类型。

