Kubernetes 之 Pod 基本原理
Pod 的定义
Pod是 Kubernetes 中的最小调度单元,k8s是通过定义一个Pod的资源,然后在Pod里面运行容器,容器需要指定一个镜像,这样就可以用来运行具体的服务。一个Pod封装一个容器,也可以封装多个容器。其类似于豌豆荚,容器则是里面的豆子。Pod 里的容器共享存储、网络等。我们可以把整个 pod 看作一台虚拟机,每个容器相当于运行在虚拟机的进程。Pod 是需要被调度到 k8s 集群的工作节点来运行的,具体调度到哪个节点,是根据 k8s scheduler 调度器实现的。
Pod 的网络
Pod 是有 IP 地址的,由网络插件(calico、flannel、weave)分配的 IP ,每个 Pod 都被分配唯一的 IP 地址。在 k8s 中,启动 Pod 时,会先启动⼀个 pause 的容器,然后将后续的所有容器都链接到这个 pause 的容器,以实现⽹络共享。
Pod 的存储
创建 Pod 的时候可以指定挂载的存储卷。 Pod 中的所有容器都可以访问共享卷,允许这些容器共享数据。 Pod 只要挂载持久化数据卷,Pod 重启之后这些数据还是会存在的。
Pod 多容器特性
- 所有容器共享一个 IP 地址和网络端口,意味着容器之间可以通过
localhost
高效访问,但容器之间不能有端口冲突 - 容器之间共享存储卷,可以通过文件系统交互信息。通常用来实现收集业务日志
Pod 创建方式
在 k8s 中,所有的资源都可以使用一个 yaml 文件来创建,创建 Pod 则可以使用 yaml 配置文件或者使用kubectl run
在命令行创建 Pod(不常用且不推荐)。使用 yaml 文件创建 Pod 有两种方式:自主式创建 Pod (不推荐)和控制管理器创建 Pod (控制管理器例如 Replicaset、Deployment、Job、CronJob、Daemonset、Statefulset),下面是两者的对比:
-
创建 Pod 之前,使用 Dockerfile 文件创建用于测试的镜像文件和
nginx.conf
文件,并编译镜像-
创建
dockerfile
文件FROM alpine:latest RUN apk update && apk add nginx curl && mkdir "/usr/share/nginx/html" RUN echo "hello world" > "/usr/share/nginx/html/index.html" COPY nginx.conf /etc/nginx/nginx.conf EXPOSE 80 CMD ["nginx", "-g", "daemon off;"]
-
创建
nginx.conf
文件worker_processes 1; events { worker_connections 1024; } http { include /etc/nginx/mime.types; default_type application/octet-stream; server { listen 80; server_name localhost; location / { root /usr/share/nginx/html; index index.html index.htm; } } }
-
编译镜像
docker build -t curl-nginx:1.0 .
-
-
导出镜像,并导入 k8s 集群工作节点
# 导出镜像 docker save curl-nginx:1.0 -o curl-nginx.tar # 导入镜像 ctr -n=k8s.io images import curl-nginx.tar # 查看镜像 crictl images
-
自主式创建 Pod,
curl-nginx-self.yaml
文件如下:apiVersion: v1 kind: Pod metadata: name: curl-nginx-test namespace: default labels: app: nginx spec: containers: - name: curl-nginx ports: - containerPort: 80 image: curl-nginx:1.0 imagePullPolicy: IfNotPresent
-
创建、查看并删除 Pod
# 创建 Pod root@k8s-master1:~# kubectl apply -f curl-nginx-self.yaml pod/curl-nginx-test created # 查看 Pod root@k8s-worker2:~# kubectl get pods -owide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES curl-nginx-test 1/1 Running 0 7m35s 10.244.194.68 k8s-worker1 <none> <none> # 进入 Pod 容器进行测试 root@k8s-worker2:~# kubectl exec curl-nginx-test -- curl 10.244.194.68:80 % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 12 100 12 0 0 6884 0 --:--:-- --:--:-- --:--:-- 12000 hello world # 删除 Pod root@k8s-worker2:~# kubectl delete pod/curl-nginx-test pod "curl-nginx-test" deleted
-
控制管理器 Deployment 创建 Pod 的 yaml 文件如下:
apiVersion: apps/v1 kind: Deployment metadata: name: nginx-test labels: app: nginx-deploy spec: selector: matchLabels: app: nginx replicas: 2 template: metadata: labels: app: nginx spec: containers: - name: curl-nginx image: curl-nginx:1.0 imagePullPolicy: IfNotPresent ports: - containerPort: 80
-
创建、查看并删除 Pod
root@k8s-master1:~# kubectl apply -f curl-nginx-deploy.yaml deployment.apps/nginx-test created # 删除其中一个 Pod root@k8s-master1:~# kubectl get pods -l app=nginx -owide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES nginx-test-f8b6fbd9c-hc5vj 1/1 Running 0 3m34s 10.244.126.3 k8s-worker2 <none> <none> nginx-test-f8b6fbd9c-xnf6p 1/1 Running 0 3m34s 10.244.194.69 k8s-worker1 <none> <none> root@k8s-master1:~# kubectl delete pod/nginx-test-f8b6fbd9c-xnf6p pod "nginx-test-f8b6fbd9c-xnf6p" deleted # 自动恢复 Pod root@k8s-master1:~# kubectl get pods -l app=nginx -owide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES nginx-test-f8b6fbd9c-hc5vj 1/1 Running 0 4m22s 10.244.126.3 k8s-worker2 <none> <none> nginx-test-f8b6fbd9c-stmnc 1/1 Running 0 4s 10.244.194.70 k8s-worker1 <none> <none> # 删除所有 Pod root@k8s-master1:~# kubectl delete pods -l app=nginx pod "nginx-test-f8b6fbd9c-hc5vj" deleted pod "nginx-test-f8b6fbd9c-stmnc" deleted
自主式创建 Pod 缺陷
- Pod 被误删后不能自主恢复
- 不能弹性伸缩,进行均衡负载
Pod 创建流程
- 通过 kubectl 命令向 Apiserver 提交创建 Pod 的请求,Apiserver 接收到 Pod 创建请求后,会将 Pod 的属性信息 metadata 写入 etcd 数据库
- Apiserver 触发 watch 机制准备创建 Pod,信息转发给调度器 Scheduler,调度器使用调度算法选择工作节点,调度器将工作节点信息给 Apiserver ,Apiserver 将绑定的工作节点信息写入 etcd 数据库
- Apiserver 又通过 watch 机制,调用 kubelet,创建 Pod ,调用容器运行时 containerd 创建并启动 Pod 内的容器
- 容器创建完成之后反馈给 kubelet,kubelet 又将 Pod 的状态信息给 Apiserver,Apiserver 又将 Pod 的状态信息写入 etcd 数据库