作者:沈亚军
爱可生研发团队成员,负责公司 DMP 产品的后端开发,喜好太广,三天三夜都说不完,低调低调...
本文起源:原创投稿
*爱可生开源社区出品,原创内容未经受权不得随便应用,转载请分割小编并注明起源。
pod 是什么
Pod 是一组相互合作的容器,是咱们能够在 Kubernetes 中创立和治理的最小可部署单元。同一个 pod 内的容器共享网络和存储,并且作为一个整体被寻址和调度。当咱们在 Kubernetes 中创立一个 pod 会创立 pod 内的所有容器,并且将容器的所有资源都被调配到一个节点上。
为什么须要 pod
思考以下问题,为什么不间接在 kubernetes 部署容器?为什么须要把多个容器视作一个整体?为什么不应用同一个容器内运行多个过程的计划?
当一个利用蕴含多个过程且通过IPC
形式通信,须要运行在同一台主机。如果部署在 kubernetes 环境过程须要运行在容器内,所以可能思考计划之一是把多个过程运行在同一个容器内以实现相似在同一个主机的部署模式。然而 container 的设计是每个容器运行一个独自的过程,除非过程自身会创立多个子过程,当然如果你抉择在同一个容器内运行多个没有分割的过程的话,那么须要本人来治理其余过程,包含每个过程的生命周期(重启挂掉的过程)、日志的切割等。如果多个过程都在规范输入和规范谬误输入上输入日志,就会导致日志的凌乱,因而 docker 和 kubernetes 心愿咱们在一个容器内只运行一个过程。
排除在同一个容器内运行多个过程的计划后,咱们须要一个更高层级的组织构造实现把多个容器绑定在一起组成一个单元,这就是 pod 概念的由来,Pod 带来的益处:
- Pod 做为一个能够独立运行的服务单元,简化了利用部署的难度,以更高的抽象层次为利用部署管提供了极大的不便。
- Pod 做为最小的利用实例能够独立运行,因而能够不便的进行部署、程度扩大和膨胀、不便进行调度治理与资源的调配。
- Pod 中的容器共享雷同的数据和网络地址空间,Pod 之间也进行了对立的资源管理与调配。
pause 容器
因为容器之间是应用 Linux Namespace 和 cgroups 隔开的,所以 pod 的实现须要解决怎么去突破这个隔离。为了实现同 pod 的容器能够共享局部资源,引入了 pause 容器。 pause 容器的镜像十分小,运行着一个非常简单的过程。它简直不执行任何性能,启动后就永远把本人阻塞住。每个 Kubernetes Pod 都蕴含一个 pause 容器, pause 容器是 pod 内实现 namespace 共享的根底。
在 linux 环境下运行一个过程,该过程会继承父过程所有的namespace
,同时也能够应用unsharing
形式创立新的namespace
。如下应用unshare
形式运行 shell 并创立新的 PID、UTS、IPC 和 mount 命名空间。
sudo unshare --pid --uts --ipc --mount -f chroot rootfs /bin/sh
其余过程能够应用零碎调用setns
退出到新的命名空间,pod
的实现形式也是相似,通过如下命令演示如何手动创立一个繁难的pod
## 首先运行一个 pause 容器docker run -d --name pause -p 8880:80 --ipc=shareable gcr.io/google_containers/pause-amd64:3.0## 创立 nginx 容器,并将其退出到 pause 容器 net ipc 和 pid namespace$ cat <<EOF >> nginx.conferror_log stderr;events { worker_connections 1024; }http { access_log /dev/stdout combined; server { listen 80 default_server; server_name example.com www.example.com; location / { proxy_pass http://127.0.0.1:2368; } }}EOFdocker run -d --name nginx -v `pwd`/nginx.conf:/etc/nginx/nginx.conf --net=container:pause --ipc=container:pause --pid=container:pause nginx## 运行 ghost 容器 并将其退出到 pause 容器 network ipc 和 pid namespacedocker run -d --name ghost --net=container:pause --ipc=container:pause --pid=container:pause ghost
在 ghost 容器中应用 ps 能够看到 pause 和 nginx 过程,
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMANDroot 1 0.0 0.0 1032 4 ? Ss 10:06 0:00 /pauseroot 8 0.0 0.1 8864 3120 ? Ss 10:15 0:00 nginx: master process nginx -g daemon off;101 38 0.0 0.1 9312 3088 ? S 10:15 0:00 nginx: worker processnode 48 0.3 6.9 969996 142296 ? Ssl 10:18 0:09 node current/index.js
通过 localhost:8080 拜访 ghost 页面,那么应该可能看到 ghost 通过 Nginx 代理运行,因为 pause、nginx 和 ghost 容器之间共享 network namespace,如下图所示:
pod 罕用形式
pod 应用形式能够被分为两种类型:
- pod 内只运行一个容器。这种状况可把 pod 视为容器的包装器,kubernetes 通过治理 pod 形式治理容器;
- pod 内运行多个须要共享资源严密合作的容器。如下图所示,两个容器通过 Volume 共享文件,Filer Puller 从远端更新文件,Web Server 负责文件的展现。
是否把两个容器调配在不同或同一个 pod,通常须要思考以下几点:
- 它们是否有必要运行在同一个 kubernetes 节点?
- 它们代表一个整体,还是独立的组成部分?
- 它们是否有必要整体扩缩容?
Pod 的应用
创立 Pod
通过如下形式kubectl apply -f nginx-pod.yaml
创立 pod,并通过kubectl get pod
查看 pod 的状态,如下所示。
apiVersion: v1 kind: Podmetadata: name: nginx # pod 名称spec: containers: # 容器列表 - name: nginx # 容器名称 image: nginx:1.14.2 # 容器应用镜像 ports: # 容器端口映射 - containerPort: 80
执行kubectl describe pod nginx
查看 pod 的状态,如下所示展现了 pod 局部信息,Status
字段是 pod 在其生命周期中的一个摘要介绍,Running 示意 pod 处于失常运行状态
Name: nginxNamespace: default.....Start Time: Sat, 04 Jun 2022 09:24:36 +0000Labels: <none>.....Status: RunningIP: 10.42.1.139Containers: nginx: Container ID: docker://xxxx Image: nginx:1.14.2 Image ID: docker-pullable://.....
pod 的生命周期
Pod 创立实现后,遵循定义的生命周期,从 Pending 阶段开始,如果 pod 内至多一个容器启动失常,则进入 Running,而后依据 Pod 中的任何容器是否因故障终止而进入 Succeeded 或 Failed 阶段,pod 在其生命周期可能处于以下几种状态
- Pending: Pod 已被 Kubernetes 集群承受,但一个或多个容器尚未筹备好运行。这包含 Pod 期待调度所破费的工夫以及通过网络下载容器镜像所破费的工夫。
- Running: Pod 已绑定到一个节点,并且所有容器都已创立。至多有一个容器仍在运行,或者正在启动或重新启动过程中。
- Succeeded: Pod 中的所有容器都已胜利终止,不会重新启动。
- Failed:Pod 中的所有容器都已终止,并且至多有一个容器因故障而终止。也就是说,容器要么以非零状态退出,要么被零碎终止。
- Unknown: 因为某种原因,无奈获取 Pod 的状态。此阶段通常是因为与应该运行 Pod 的节点通信时出错而产生。
pod 创立流程
所有的 Kubernetes 组件 Controller, Scheduler, Kubelet 都应用 Watch 机制来监听 API Server,来获取对象变动的事件,创立 pod 的大抵流程如下:
- 用户通过 Kubectl 提交 Pod`形容文件到 API Server;
- API Server 将 Pod 对象的信息存入 Etcd;
- Pod 的创立会生成事件,返回给 API Server;
- Controller 监听到事件;
- Pod 如果须要要挂载盘,Controller 会查看是否有满足条件的 PV;
- 若满足条件的 PV,Controller 会绑定 Pod 和 PV,将绑定关系告知 API Server;
- API Server 将绑定信息写入 Etcd;
- 生成 Pod Update 事件;
- Scheduler 监听到 Pod Update 事件;
- Scheduler 会为 Pod 抉择 Node;
- 如有满足条件的 Node,Scheduler 会绑定 Pod 和 Node,并将绑定关系告知 API Server;
- API Server 将绑定信息写入 Etcd;
- 生成 Pod Update 事件;
- Kubelet 监听到 Pod Update 事件,创立 Pod;
- Kubelet 告知 CRI(容器运行时接口) 下载镜像;
- Kubelet 告知 CRI 运行容器;
- CRI 调用 Docker 运行容器;
- Kubelet 告知 Volume Manager,将盘挂在到 Node 同时挂载到 Pod;
- CRI 调用 CNI(容器网络接口) 配置容器网络;