开发者学堂课程【企业级运维之云原生与 Kubernets 实战课程:理解 Pod 和容器设计 】学习笔记,与课程紧密联系,让用户快速学习知识。
课程地址:https://developer.aliyun.com/learning/course/913/detail/14498
理解 Pod 和容器设计
摘要:本节课主要介绍 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 类型。