第四章 K8s管理应用程序生命周期(下)
1、Pod对象
1.1 Pod 的基本概念
Pod 是 Kubernetes 中最基本和最重要的概念之一,是一个逻辑抽象概念,Kubernetes创建和管理的最小单元, 一个Pod由一个容器或多个容器组成。它简化了容器的部署、管理和扩展。通过 Pod可以轻松地将应用程序的不同组件组织在一起,确保它们共享资源和网络环境。
Pod 的主要特点:
① 容器共享网络和存储
- 共享网络命名空间:Pod 中的所有容器共享同一个网络命名空间,这意味着它们可以使用 localhost 相互通信。
- 共享存储卷:Pod 中的容器可以共享存储卷,便于数据交换和持久化。
② 生命周期管理
- Pod 生命周期:Pod 的生命周期由 Kubernetes 管理,包括创建、运行、更新和终止。
- 健康检查:Kubernetes 可以通过健康检查(Liveness Probes 和 Readiness Probes)自动管理Pod 的健康状态。
③ 自动调度
- 节点调度:Kubernetes 自动将 Pod 调度到集群中的适当节点上,基于资源需求、策略和约束条件。
- 高可用性和容错:如果节点发生故障,Kubernetes 会自动将 Pod 重新调度到其他节点上,确保服务的高可用性。
1.2 Pod 存在的意义
Pod主要用法:
- 主容器(Main Container):主要应用程序容器,通常是一个长时间运行的服务。又或者是运行单个容器,最常见的用法可以将Pod看做是单 个容器的抽象封装;
- 辅助容器(Sidecar Container):辅助容器,用于支持主容器的功能,如日志收集、监控代理等。又或者是运行多个容器: 通过在Pod中定义专门容器来执行主业务容器需要的辅助工作,这样好处是将辅助功能同主业务 容器解耦,实现独立发布和能力重用。
如某些场景下,有部分代码考虑是否在源代码的基础上增加,随着用户量的上升可能导致源代码的臃肿。前期可以将非核心的功能进行解耦出来,对以后业务的扩展会有很多帮助,例如:
• 日志收集
• 应用监控
1.3 Pod 资源共享实现机制
① 共享网络:将业务容器网络加入到“负责网络的容器 infa container”实现网络共享
解释:该网络容器会在创建Pod之前先创建,创建完成后其它容器会加入到这个容器实现网络共享,因为都在同一个网络协议栈(容器共享网络命名空间)
补充:Pod为k8s中的最小调度单元,所以一个Pod中如果存在多个容器,使用的IP,即POD IP,也是唯一的一个IP,可以通过这个IP访问Pod里面任何一个容器,IP是共享的。
共享网络YAML示例:
# kubectl apply -f pod-net-test.yaml
apiVersion: v1
kind: Pod
metadata:labels:app: testname: pod-net-test namespace: default
spec:containers:- image: busybox name: bscommand: ["/bin/sh","-c","sleep 12h"]- image: nginxname: web
# 测试
# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod-net-test 2/2 Running 0 42m 10.244.114.27 k8s-node2-1-73 <none> <none># 进入容器
# kubectl exec -it pod-net-test -- bash //默认会进入其中一个
Defaulted container "web" out of: web, bs# 指定容器进入
# kubectl exec -it pod-net-test -c web -- bash
root@pod-net-test:/# curl -i 127.0.0.1 //访问容器本地IP,可获得Nginx信息# kubectl exec -it pod-net-test -c bs -- sh //busybox不支持bash终端
/ # wget 127.0.0.1 //可获得Nginx的index.html页面
/ # netstat -nlptu | grep 80
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN -
tcp 0 0 :::80 :::* LISTEN -
结论:在 bs 容器中可看到监听 80端口,但是没有相关服务进程,通过127.0.0.1访问,即可得到nginx容器的index.html 页面
② 共享存储:容器通过数据卷共享数据
共享存储YAML示例:
# kubectl apply -f pod-volume-test.yaml
apiVersion: v1
kind: Pod
metadata:labels:app: testname: pod-volume-test namespace: default
spec:containers:- image: busybox name: testcommand: ["/bin/sh","-c","sleep 12h"]volumeMounts: # 数据卷挂载- name: log # 指定挂载的数据卷名称mountPath: /data # 数据卷挂载到容器中的路径- image: nginxname: webvolumeMounts:- name: logmountPath: /usr/share/nginx/htmlvolumes: # 定义数据卷- name: log # 数据卷名称emptyDir: {} # 数据卷类型
# 测试
# kubectl get pods
NAME READY STATUS RESTARTS AGEpod-volume-test 2/2 Running 0 17m
# 进入rs容器创建文件
[root@k8s-master-1-71 ~]# kubectl exec -it pod-volume-test -c bs -- sh
/ # cd /data/;touch 1.txt
# 进入web容器查看
# kubectl exec -it pod-volume-test -c web -- bashroot@pod-volume-test:/# ls /usr/share/nginx/html/1.txt
1.4 Pod 的生命周期
① Pod 创建
- 用户通过 YAML 文件或命令行工具(如 kubectl)创建 Pod。
- Kubernetes 调度器将 Pod 分配到合适的节点上。
② 运行
- 容器启动:节点上的容器运行时(如 Docker)启动 Pod 中的容器。
- 健康检查:Kubernetes 定期检查容器的健康状态,确保它们正常运行。
③ 更新
滚动更新:通过更新 Pod 的定义,Kubernetes 可以滚动更新容器镜像或配置。
示例:kubectl set image pod/multi-container-pod web=nginx:1.19.10
④ Pod 终止:
- 用户可以通过命令行工具删除 Pod,或者 Kubernetes 根据策略自动删除 Pod。
- 删除 Pod 时,Kubernetes 会清理相关的资源,如容器和存储卷
1.5 管理命令
1)创建Pod
- 命令:kubectl run --image=nginx
- 导出YAML:kubectl run --image=nginx --dry-run=clinet -o yaml > xxx.yaml
# kubectl apply -f pod.yaml
apiVersion: v1
kind: Pod
metadata:name: my-pod
spec:containers:- name: container1image: nginx- name: container2image: centos
注意:kubectl create deployment 是通过控制器去创建Pod,受控制器管理,可控制副本数,而kubectl run只能创建一个Pod,不具备控制器有的升级、回滚、扩容、多副本的特性
2)查看Pod
- 命令:kubectl get pods
- 命令:kubectl get pods -o wide
- 命令:kubectl describe pod
3)查看日志
- 命令:kubectl logs [-c CONTAINER]
- 命令:kubectl logs [-c CONTAINER] -f //-f 实时查看
# kubectl logs pod-volume-test
# kubectl logs pod-volume-test -c web
# kubectl logs pod-volume-test -c web -f
4)进入容器终端
- 命令:kubectl exec -it [-c CONTAINER] -- bash
5)通过expose暴露Pod
- 命令:kubectl expose pod --port=service端口 --target-port=应用服务端口 --type=NodePort
# kubectl expose pod pod-net-test --port=80 --target-port=80 --type=NodePort
# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 16d
pod-net-test NodePort 10.108.168.104 <none> 80:31513/TCP 19s
6)删除Pod
- 命令:kubectl delete pod
# kubectl delete pods pod-volume-test
pod "pod-volume-test" deleted
2、应用自修复(重启策略+健康检查)
背景:在kubectl get pods时,提示STATUS是Running状态,只能告知创建者Pod创建成功,但不代表Pod容器服务是正常的,为了进一步解决,提供了重启策略+健康检查
1)重启策略(restartPolicy):
- Always:当容器终止退出后,总是重启容器,默认策略(场景:常驻进程,即始终保持运行,例如nginx、mysql,服务挂掉即重启容器)
- OnFailure:当容器异常退出(退出状态码非0)时,才重启容器(场景:周期性进程,即隔一段时间运行一次,例如数据库备份)
- Never:当容器终止退出,从不重启容器(场景:临时性进程,即偶尔执行一次,没有规律即不能用定时任务去执行,一般为人为或别的程序驱动,例如数据离线处理,如果再重启一次对上一次任务的数据产生冲突等)
在Pod的YAML文件中可以看到字段:restartPolicy:Always
2)健康检查有以下3种类型(Probe探针):
- livenessProbe(存活检查):如果检查失败,将杀死容器,根据Pod 的restartPolicy来操作。(重建的容器还是原来的容器,非副本集拉起的容器)
- readinessProbe(就绪检查):如果检查失败,Kubernetes会把 Pod从service endpoints负载均衡中剔除。(只是从LB剔除不是删除节点)
- startupProbe(启动检查):启动检查成功才由存活检查接手,用于保护 慢启动容器,防止启动慢的容器检查没通过不断重启
支持以下三种检查方法:
- ① httpGet:发送HTTP模拟请求,返回200-400范围状态码为成功。(准确度比较高)
- ② exec:执行Shell命令返回状态码是0为成功。
- ③ tcpSocket:发起TCP Socket建立成功。
官网:Configure Liveness, Readiness and Startup Probes | Kubernetes
示例1:模拟httpGet请求检查方法
# kubectl apply -f probe-demo.yaml
apiVersion: v1
kind: Pod
metadata:name: probe-demo
spec:containers:- name: webimage: nginxlivenessProbe: # 存活检查,重启容器httpGet:path: /port: 80initialDelaySeconds: 5 # 启动容器后多少秒健康检查periodSeconds: 10 # 以后每间隔多少秒检查一次readinessProbe: # 就绪检查,从Service中剔除容器httpGet:path: /port: 80initialDelaySeconds: 5 # 启动容器后多少秒健康检查periodSeconds: 10 # 以后每间隔多少秒检查一次
注:livenessProbe与readinessProbe的配置参数一样
# 通过创建Pod方式测试
[root@k8s-master-1-71 ~]# kubectl apply -f probe-demo.yaml[root@k8s-master-1-71 ~]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
probe-demo 1/1 Running 0 16m 10.244.114.28 k8s-node2-1-73 <none> <none>[root@k8s-master-1-71 ~]# kubectl expose pods probe-demo --port=80 --target-port=80 --type=NodePort[root@k8s-master-1-71 ~]# kubectl get service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
probe-demo NodePort 10.99.233.38 <none> 80:30168/TCP 83s# 打开两个终端进行观察,通过删除Pod的默认首页导致服务挂掉,模拟测试 readinessProbe就绪检查
# 终端1:
[root@k8s-master-1-71 ~]# kubectl get ep -w //-w 实时查看service后端关联的Pod IP
# 终端2:
[root@k8s-master-1-71 ~]# kubectl exec -it probe-demo -- bash
root@probe-demo:/# rm -rf /usr/share/nginx/html/index.html
root@probe-demo:/# command terminated with exit code 137 //删除后,readiness就绪检查检测到服务异常,讲当前容器自动退出并剔除Service,根据livenessProbe会按照restartPolicy策略重启容器
# 终端1:可以看到当时probe-demo的Pod,又重新拉起了一个Pod,如图所示:
[root@k8s-master-1-71 ~]# kubectl get pods
NAME READY STATUS RESTARTS AGEprobe-demo 1/1 Running 1 (33s ago) 22m //查看Pod信息时,也可以明显发现有一次RESTARTS的重启记录# 查看日志,可发现同一时间会有2条健康检查日志,因为健康检查功能是独立的
[root@k8s-master-1-71 ~]# kubectl logs probe-demo
192.168.1.73 - - [04/Mar/2023:23:29:11 +0000] "GET / HTTP/1.1" 200 615 "-" "kube-probe/1.26" "-"
192.168.1.73 - - [04/Mar/2023:23:29:11 +0000] "GET / HTTP/1.1" 200 615 "-" "kube-probe/1.26" "-"
192.168.1.73 - - [04/Mar/2023:23:29:14 +0000] "GET / HTTP/1.1" 200 615 "-" "kube-probe/1.26" "-"
192.168.1.73 - - [04/Mar/2023:23:29:14 +0000] "GET / HTTP/1.1" 200 615 "-" "kube-probe/1.26" "-"
...
示例2:执行Shell命令的检查方法
livenessProbe:exec:command:- cat- /tmp/healthy
示例3:端口探测的检查方法
livenessProbe:tcpSocket:port: 80
3、环境变量
创建 Pod 时,可以为其下的容器设置环境变量。
应用场景:
- 容器内应用程序获取Pod信息(通过环境变量将 Pod 信息呈现给容器)
- 容器内应用程序通过用户定义的变量改变默认行为
变量值几种定义方式:
- 自定义变量值
- 变量值从Pod属性获取
- 变量值从Secret、ConfigMap获取
示例:通过YAML文件定义变量,将变量注入到Pod容器当中:自定义变量、POD属性获取
网址参考:通过环境变量将 Pod 信息呈现给容器 | Kubernetes
apiVersion: v1
kind: Pod
metadata:name: pod-envars
spec:containers:- name: testimage: busyboxcommand: [ "sh", "-c", "sleep 36000"]env:# 变量值从Pod属性获取- name: MY_NODE_NAMEvalueFrom:fieldRef:fieldPath: spec.nodeName- name: MY_POD_NAMEvalueFrom:fieldRef:fieldPath: metadata.name- name: MY_POD_NAMESPACEvalueFrom:fieldRef:fieldPath: metadata.namespace- name: MY_POD_IPvalueFrom:fieldRef:fieldPath: status.podIP- name: ABC # 自定义变量值value: "123456"
注意:自定义变量时,如果value的值是字符串,需要使用引号
# 测试:进入容器
[root@k8s-master-1-71 ~]# kubectl exec -it pod-envars -- sh
/ # env //查看我当前有的环境变量
/ # env | grep ABC
ABC=123456
/ # echo $MY_NODE_NAME
k8s-node2-1-73
/ # echo $MY_POD_NAME
pod-envars
/ # echo $MY_POD_NAMESPACE
default
/ # echo $MY_POD_IP
10.244.114.30
4、Init container
Init Container:顾名思义,用于初始化工作,执行完就结束,可以理解为一次性任务。
- 支持大部分应用容器配置,但不支持健康检查
- 优先于应用容器执行
应用场景:
- 环境检查:例如确保应用容器依赖的服务启动后再启动应用容器
- 初始化配置:例如给应用容器准备配置文件
示例:部署一个web网站,网站程序没有打到镜像中,而是希望从代码 仓库中动态拉取放到应用容器中。
apiVersion: v1
kind: Pod
metadata:name: init-demo
spec:initContainers: # 初始化容器(将网页进行下载到共享存储中)- name: downloadimage: busyboxcommand:- wget- "-O"- "/opt/index.html"- http://www.aliangedu.cnvolumeMounts:- name: wwwrootmountPath: /optcontainers: # 主容器- name: nginximage: nginxvolumeMounts:- name: wwwrootmountPath: /usr/share/nginx/htmlvolumes:- name: wwwrootemptyDir: {}
# 测试
[root@k8s-master-1-71 ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
init-demo 1/1 Running 0 38s
# 解释:初始化容器完成任务就消失
[root@k8s-master-1-71 ~]# kubectl label pods init-demo app=web[root@k8s-master-1-71 ~]# kubectl expose pods init-demo --port=80 --target-port=80 --type=NodePort
[root@k8s-master-1-71 ~]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
init-demo NodePort 10.98.174.76 <none> 80:31590/TCP 25s[root@k8s-master-1-71 ~]# curl 192.168.1.71:31590<title>阿良教育「官网」-专业DevOps、云计算运维、Kubernetes容器运维、云原生、Golang运维开发培训机构!</title>
...
回顾:目前接触的Pod中会有以下几种类型的容器:
- Infrastructure Container:基础容器 (维护整个Pod网络空间,共享网络命名空间)
- InitContainers:初始化容器 (先于业务容器开始执行)
- Containers:业务容器 (并行启动)
5、静态Pod
背景:Kubeadm搭建集群就是用Pod启动组件,而在不搭建完整的k8s集群之前就可以创建Pod,即静态Pod。
静态Pod特点:
- 静态Pod由特定节点上的kubelet管理维护
- 不能使用控制器
- Pod名称标识当前节点名称(即在哪个节点创建就有当前节点的名称标识)
在kubelet配置文件启用静态Pod的参数:
vi /var/lib/kubelet/config.yaml
...
staticPodPath: /etc/kubernetes/manifests
...
注:将部署的Pod yaml放到/etc/kubernetes/manifests目录会由kubelet自动创建。
测试:
[root@k8s-node1-1-72 ~]# cd /etc/kubernetes/manifests/[root@k8s-node1-1-72 manifests]# kubectl run web-test --image=nginx -o yaml --dry-run=client > web-test.yaml[root@k8s-node1-1-72 manifests]# ls
web-test.yaml
[root@k8s-node1-1-72 manifests]# kubectl get pods
NAME READY STATUS RESTARTS AGEweb-test-k8s-node1-1-72 1/1 Running 0 108s# 删除静态Pod
[root@k8s-node1-1-72 manifests]# rm -rf web-test.yaml
[root@k8s-node1-1-72 manifests]# kubectl get pods
NAME READY STATUS RESTARTS AGE
init-demo 1/1 Running 0 24m
课后作业
1、创建一个pod,其中运行着nginx、redis、memcached、consul 4个容器
2、在节点上配置kubelet托管启动一个pod
- 节点:k8s-node1
- pod名称:web
- 镜像:nginx
3、检查容器中文件是否创建,如果没有被检测到pod重启
- 文件路径:/tmp/test.sock
小结:
本篇为 【Kubernetes CKA认证 Day4】的学习笔记,希望这篇笔记可以让您初步了解到 Pod是什么、Pod常用管理命令、重启策略及健康检查、创建 Pod 时可以为其下的容器设置环境变量等;课后还有扩展实践,不妨跟着我的笔记步伐亲自实践一下吧!
Tip:毕竟两个人的智慧大于一个人的智慧,如果你不理解本章节的内容或需要相关笔记、视频,可私信小安,请不要害羞和回避,可以向他人请教,花点时间直到你真正的理解。