Pod与Pod控制器(K8s核心实战详解)
一、Pod 介绍
Pod是k8s集群进行调度的最小单元,k8s会将Pod调度到集群中的节点上运行,一个Pod中可以存在一个或多个容器,这些容器共享Pod中的存储、网络等资源,所以我们可以把Pod看做一个抽象的逻辑主机,来为容器提供一个运行的环境。
二、静态 Pod
在k8s中,静态Pod也称之为无控制器管理的自主式Pod,这种Pod不由k8s的控制平面(如kube-apiserver、kube-scheduler、kube-controller-manager)进行管理, 而是由对应节点上的kubelet进程负责管理,这意味着它们不受k8s的自动调度、健康检查或重启策略的控制, 因此通常不建议在生产环境中广泛使用静态Pod。
案例:创建一个Nginx的静态Pod
参考地址:kubernetes.io/zh-cn/docs/…
资源文档查询方法:kubectl explain pod
cat static-web.yaml
apiVersion: v1
kind: Pod
metadata:
name: static-web
spec:
containers:
- name: web
image: nginx:1.18.0
# 创建Pod
kubectl create -f static-web.yaml
# 查看Pod信息
kubectl get pod
# 删除Pod
kubectl delete pod static-web
三、Pod 资源清单
在k8s中基本所有资源的一级属性都是一样的,主要分为五部分:
apiVersion//资源版本,由k8s内部定义,版本号可以通过资源对应文档查询kind//资源类型,由k8s内部定义,类型可以通过资源对应文档查询metadata//元数据,主要是指定资源标识与说明,常用的有name、namespace、labels等spec//定义资源详细配置信息,这是资源对象中最重要的一部分status//资源状态信息,里边的内容不需要定义,由资源自动生成
Pod配置参考地址:kubernetes.io/zh-cn/docs/…
以下是比较详细的资源清单介绍
KIND: Pod #资源类型
VERSION: v1 #资源版本
FIELDS: #资源可配置的属性,如下
apiVersion: v1 #必选的一级属性,版本号,例如v1
kind: Pod #必选的一级属性,资源类型,例如Pod
metadata: #必选的一级属性,元数据
name: #资源名称
namespace: test #资源所属的名称空间,例如dev,默认为default名称空间
labels: #自定义标签列表
- name: #标签名称
spec: #必选的一级属性
containers: #Pod中容器列表
- name: #容器名称
image: #容器镜像名称
imagePullPolicy: #镜像的拉取策略
command: #容器的启动命令列表,如不指定,使用打包时使用的启动命令
args: #容器的启动命令参数列表
workingDir: #容器的工作目录
volumeMounts: #挂载到容器内部的存储卷配置
- name: #引用pod定义的共享存储卷的名称
mountPath: #存储卷在容器内mount的绝对路径,应少于512字节
readOnly: #是否为只读模式
ports: #需要暴露的端口号列表
- name: #端口的名称
containerPort: #容器需要监听的端口号
hostPort: #容器所在的主机需要监听的端口号,默认与Container相同
protocol: #端口协议,支持TCP/UDP,默认为TCP
env: #容器运行前需要设置的环境变量列表
- name: #环境变量名称
value: #环境变量的值
resources: #资源限制和请求的设置
limits: #资源最大限制的设置
CPU: #CPU资源限制,单位为core数,将用于docker run --cpu-shares参数
memory: #内存资源限制,单位可以为Mib/Gib,将用于docker run --memory参数
requests: #资源最小请求的设置
CPU: #CPU请求,容器启动的初始可用数量
memory: #内存请求,容器启动的初始可用数量
lifecycle: #生命周期钩子
postStart: #容器启动后立即执行此钩子,如果执行失败,会根据重启策略进行重启
preStop: #容器终止前执行此钩子,无论结果如何,容器都会终止
livenessProbe: #对Pod内个容器健康检查设置,当探测容器无响应后将自动重启该容器
tcpSocket: #对Pod内容器健康检查方式
initialDelaySeconds: #容器启动完成后,首次探测时间,单位为秒
timeoutSeconds: #对容器健康检查探测等待相应的超时时间,单位秒,默认1秒
periodSeconds: #对容器监控检查的定期探测时间设置,单位秒,默认10秒一次
restartPolicy: #Pod的重启策略
nodeName: #设置pod调度到指定的node节点上
nodeSelector: #设置Pod调度到指定的label的node节点上
imagePullSecrets: #拉取镜像时,使用secret名称,以key:secretkey格式指定
hostNetwork: #是否使用主机网络模式,默认为false,如果设置为true,表示使用宿主机网络
volumes: #在该Pod上定义共享存储卷列表
- name: #共享存储卷名称
emptyDir: #类型为emptyDir的存储卷
hostPath: #类型为hostPath的存储卷
path: #Pod所在宿主机的目录
secret: #类型为secret的存储卷,挂载secret对象到容器内部
configMap: #类型为configMap的存储卷,挂载configMap对象到容器内部
四、Pod 控制器
参考地址:kubernetes.io/zh-cn/docs/…
在k8s中,Pod控制器(Controller)用于管理和控制Pod的生命周期、副本数和状态。Pod控制器的主要作用包括以下几个方面:
- 副本管理:Pod控制器可以定义和管理Pod的副本数,确保指定数量的Pod副本在集群中运行。
- 自愈性和健康检查:Pod控制器通过监视Pod的健康状态来实现自愈性。如果Pod出现故障或终止,控制器会自动重启或创建新的Pod,以确保应用程序的高可用性和可靠性。
- 扩展性:使用Pod控制器,可以通过调整副本数来扩展应用程序。通过增加副本数,可以实现应对高负载的能力,并在负载减少时自动缩减副本数,从而实现资源的有效利用。
- 版本管理:Pod控制器还负责应用程序的滚动更新和版本回退。
- Pod调度规则:通过Pod控制器,可以确保Pod被调度到指定的节点上,以满足特殊的部署策略。
1. ReplicaSet 控制器
ReplicaSet(RS)控制器具备副本管理、自愈性和健康检查、扩展性、Pod调度规则等功能。
案例:通过RS控制器创建3个Nginx Pod
参考地址:kubernetes.io/zh-cn/docs/… 资源文档查询方法:kubectl explain rs
# cat rs-nginx.yml
apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: rs-nginx
namespace: test
spec:
replicas: 3 #创建pod的副本数量,默认为1
selector: #标签选择器,通过标签指定RS管理哪些pod
matchLabels: #标签类型(key-value)
app: rs-nginx #匹配pod的标签(表示RS管理带有此标签的Pod)
template: #pod的配置模板,通过模板创建Pod
metadata: #定义模板元数据信息
labels: #定义标签
app: rs-nginx #标签名称(与selector中的标签保持一致)
spec: #定义容器的详细配置
containers: #定义容器列表
- name: nginx #定义容器名称
image: nginx:1.18.0 #定义容器镜像
# 创建pod
kubectl create -f rs-nginx.yml
# 查看pod信息
kubectl get po -n test
# 查看pod控制器信息
kubectl get rs -o wide -n test
DESIRED //期望的pod副本数量
CURRENT //当前的pod副本数量
READY //已经准备好提供服务的副本数量
# 查看Pod详细信息
kubectl describe pod -n test
案例:通过RS控制器实现Pod数量的扩缩容功能
# 方式1:通过vim编辑配置文件来调整Pod的副本数,然后通过apply更新资源对象配置
# 方式2:通过命令行直接修改 kubectl scale rs rs-nginx -n test --replicas=4
# 方式3:通过edit(实时修改)更新资源对象的配置(资源配置文件不会跟着发生变化)
kubectl edit rs rs-nginx -n test
...
spec:
replicas: 6 #修改pod的副本数
# 查看pod信息
kubectl get pod -n test
删除RS方式
# 命令删除方式
kubectl delete rs rs-nginx -n test
# 查看rs信息
kubectl get rs -n test
# 配置文件删除方式
kubectl delete -f rs-nginx.yml
2. Deployment 控制器
Deployment(deploy)控制器是在RS控制器的基础上进行进一步扩展和增强的一种控制器,提供了更高级的功能和更便捷的应用程序管理方式。Deployment控制器的主要功能包括:
- 具备RS所有功能:通过控制RS来实现对Pod的副本管理、自愈性和健康检查、扩展性、Pod调度规则等功能。
- 滚动更新:Deployment控制器支持应用程序的滚动更新, 确保应用程序在更新过程中的平滑过渡,避免服务中断。
- 版本管理:Deployment控制器可以管理应用程序的不同版本,可以轻松地进行版本切换和回滚。
案例:通过 Deployment 控制器创建3个Nginx Pod
参考地址:kubernetes.io/zh-cn/docs/… 资源文档查询方法:kubectl explain deploy
# cat deploy-nginx.yml
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy-nginx
namespace: test
spec:
replicas: 3 #创建pod的副本数量,默认为1
selector: #标签选择器
matchLabels: #标签类型(key-value)
app: deploy-nginx #匹配pod的标签(表示deploy管理带有此标签的Pod)
template: #pod的配置模板,通过模板创建pod
metadata: #定义模板元数据信息
labels: #定义标签
app: deploy-nginx #标签名称(与select中的标签保持一致)
spec:
containers:
- name: nginx
image: nginx:1.17.0
# 创建deploy
kubectl create -f deploy-nginx.yml
# 查看deploy信息
kubectl get deploy -n test
kubectl get deploy -n test -o wide
UP-TO-DATE //最新版本的pod数量
AVAILABLE //当前可用的pod数量
# 查看rs信息,deploy通过控制rs管理pod,所以rs控制器也会被创建出来(rs的名称在deploy基础上随机生成)
kubectl get rs -n test
# 查看pod信息(pod名称是在rs基础上随机添加生成)
kubectl get po -n test
# 查看Pod标签
kubectl get pod -n test --show-labels
五、Pod 生命周期
Pod 的生命周期分为几个阶段,主要用来让用户理解Pod的当前状态和问题所在:
Pending:Pod 已经被系统接受,但是它需要完成一些准备工作才能运行。这些工作包括分配到指定节点上,下载容器镜像等。简单来说,这个阶段就是 Pod 的"准备"阶段。Running:Pod 已经被分配到节点上,同时Pod中的所有容器都已经创建。至少有一个容器在运行、或处于启动、重启状态,这个阶段可以被看作是 Pod 的"运行"阶段。Succeeded:Pod 的所有容器都已经成功完成了它们的任务并且都成功地终止了,并且不会再重启。这意味着,Pod 已经完成了它的生命周期并且不再需要。这个阶段看作是 Pod 的"完成"阶段。Failed:Pod 中的所有容器都已经停止,但是至少有一个容器是因为失败而停止的。这意味着 Pod 在尝试完成它的任务时遇到了一些问题。这个阶段可以被看作是 Pod 的"失败"阶段。Unknown:系统不能确定 Pod 的状态。通常是因为与Pod所在的主机通讯失败导致。这个阶段可以被看作是 Pod 的"未知"阶段。CrashLoopBackOff:这个状态通常意味着Pod 中的一个或多个容器在启动后立即崩溃,系统在重新启动它,但是连续多次尝试都失败了。
六、Pod 镜像拉取策略
imagePullPolicy 属性用于设置镜像拉取策略,k8s支持三种拉取策略:
Always//总是从远程仓库拉取镜像IfNotPresent//本地有则使用本地镜像,本地没有则从远程仓库拉取镜像Never//只使用本地镜像,从不去远程仓库拉取,本地如果没有就报错
默认值说明:如果镜像 tag 为具体版本号,默认策略是 IfNotPresent ,如果镜像标签为 latest,默认策略是Always
案例1:指定镜像拉取策略为 Never
# cat deploy-nginx.yml
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy-nginx
namespace: test
spec:
replicas: 1
selector:
matchLabels:
app: deploy-nginx
template:
metadata:
labels:
app: deploy-nginx
spec:
containers:
- name: nginx
image: nginx:1.20.0 #指定一个本地不存在的镜像版本
imagePullPolicy: Never #设置镜像拉取策略
# 更新pod配置
kubectl apply -f deploy-nginx.yml
# 查看pod信息
kubectl get pod -n test
# 查看pod详细信息
kubectl describe pod -n test
案例2:指定镜像拉取策略为 IfNotPresent
# cat deploy-nginx.yml
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy-nginx
namespace: test
spec:
replicas: 1
selector:
matchLabels:
app: deploy-nginx
template:
metadata:
labels:
app: deploy-nginx
spec:
containers:
- name: nginx
image: nginx:1.20.0
imagePullPolicy: IfNotPresent #设置镜像拉取策略
# 更新pod配置
kubectl apply -f deploy_nginx.yml
# 查看pod信息
kubectl get pod -n test
# 查看pod详细信息
kubectl describe pod -n test
七、Pod 端口设置
ports 属性用于配置容器需要暴露的端口列表,支持的属性:
containerPort//容器要监听的端口(不定义,采用默认端口)name//端口名称,如果指定,必须保证名称在该pod中是唯一的(可以省略)protocol//端口协议,支持TCP、UDP,默认为TCP
案例:创建Pod并指定容器暴露80端口
资源文档查询方法:kubectl explain pod.spec.containers.ports
# cat deploy-nginx.yml
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy-nginx
namespace: test
spec:
replicas: 1
selector:
matchLabels:
app: deploy-nginx
template:
metadata:
labels:
app: deploy-nginx
spec:
containers:
- name: nginx
image: nginx:1.20.0
imagePullPolicy: IfNotPresent
ports: #定义容器端口
- containerPort: 80 #端口(必须为列表类型)
protocol: TCP #端口协议
# 更新pod配置
kubectl apply -f deploy-nginx.yml
# 查看pod信息
kubectl get pod -n test
# 查看pod详细信息
kubectl describe pod -n test
...
Port: 80/TCP
# 访问pod中的容器需要访问pod的IP加容器端口
curl 10.244.2.30:80
八、Pod 资源配额
resources 属性用于限制Pod中的容器对系统的资源的使用量,避免容器出现问题大量吞噬系统资源,k8s目前提供了对内存和CPU的资源限制,当我们对Pod中的容器配置资源限额以后,如果容器超出资源使用量,k8s则会认为该容器出现故障,则重新启动该容器。
resources 支持的属性:
limits//限制容器资源上限,当容器超出该使用量时,容器会被终止,并进行重启。requests//限制容器需要的最小资源,如果环境资源不够,容器将无法启动,如果不定义,默认与limits相等。
案例:设置容器的内存与CPU资源限额
参考地址:kubernetes.io/zh-cn/docs/… 资源文档查询方法:kubectl explain pod.spec.containers.resources
# cat deploy-nginx.yml
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy-nginx
namespace: test
spec:
replicas: 1
selector:
matchLabels:
app: deploy-nginx
template:
metadata:
labels:
app: deploy-nginx
spec:
containers:
- name: nginx
image: nginx:1.20.0
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
protocol: TCP
resources: #定义资源限额
limits: #资源上限
cpu: "1" #表示一核心CPU资源
memory: "128M" #内存单位可以使用G、M等形式
requests: #资源下限
cpu: "0.5" #表示0.5核心CPU资源
memory: "64M" #所需最低内存资源(如果不足64M,容器无法启动)
# 更新pod配置
kubectl apply -f deploy-nginx.yml
# 查看pod信息
kubectl get pod -n test
# 查看pod详细信息
kubectl describe pod -n test
...
Limits:
cpu: 500m
memory: 128Mi
Requests:
cpu: 250m
memory: 64Mi
九、Pod 多容器创建方式
案例:将nginx与tomcat放在同一个Pod中运行
# cat vim deploy-nginx.yml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
namespace: test
spec:
replicas: 1
selector:
matchLabels:
app: deploy-nginx
template:
metadata:
labels:
app: deploy-nginx
spec:
containers:
- name: nginx
image: nginx:1.18.0
imagePullPolicy: IfNotPresent
ports:
- name: web-nginx
containerPort: 80
protocol: "TCP"
resources:
limits:
cpu: "500m"
memory: "128Mi"
requests:
cpu: "250m"
memory: "64Mi"
# 通过-name再定义一个容器的配置
- name: tomcat
image: tomcat:8.5-jre10-slim
imagePullPolicy: IfNotPresent
ports:
- name: web-tomcat
containerPort: 8080
protocol: "TCP"
resources:
limits:
cpu: "500m"
memory: "128Mi"
requests:
cpu: "250m"
memory: "64Mi"
# 更新Pod配置
kubectl apply -f deploy-nginx.yml
# 查看Pod信息
kubectl get pod -n test
十、进入Pod中容器 & 执行命令
1. 进入容器
格式:kubectl exec -it -n 命名空间 pod名称 -c 容器名称 -- /bin/bash
提示:-c 为可选项,如果是1个pod中只有1个容器,则不用指定,如果是1个pod中有多个容器,不指定默认为第1个容器。
# 进入nginx容器
kubectl exec -it -n test deploy-nginx-579696c576-jfqz6 -c nginx -- /bin/bash
# 进入tomcat容器
kubectl exec -it -n test deploy-nginx-579696c576-jfqz6 -c tomcat -- /bin/bash
2. 执行命令
格式: kubectl exec -n 名称空间 pod名 -c 容器名 -- 命令
提示:没有 -it 选项
# 对nginx容器执行命令
kubectl exec -n test deploy-nginx-579696c576-jfqz6 -c nginx -- ls /opt
# 对tomcat容器执行命令
kubectl exec -n test deploy-nginx-579696c576-jfqz6 -c tomcat -- ls /opt
十一、Pod 环境变量
env 属性是用于设置容器环境变量的列表,环境变量的定义要根据容器具体需求定义,本章节只讲解如何定义环境变量,env支持的属性:
name//定义环境变量名称value//定义变量值
案例:为MySQL添加环境变量设置root密码
资源文档查询方法:kubectl explain pod.spec.containers.env
# cat vim mysql.yml
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy-mysql
namespace: test
spec:
replicas: 1
selector:
matchLabels:
app: deploy-mysql
template:
metadata:
labels:
app: deploy-mysql
spec:
containers:
- name: mysql
image: mysql:5.7
imagePullPolicy: IfNotPresent
ports:
- containerPort: 3306
protocol: TCP
env: #定义环境变量
- name: "MYSQL_ROOT_PASSWORD" #变量名称(必须为列表类型)
value: "123456" #变量值
# 更新Pod配置
kubectl create -f mysql.yml
# 查看Pod信息
kubectl get pod -n test
# 查看Pod详细信息
kubectl describe pod -n test
# 删除Pod
kubectl delete -f mysql.yml
十二、Pod 调度策略
在默认情况下,一个Pod被调度到哪个Node节点运行,是由Scheduler组件采用相应的算法计算出来的,这个过程是不受人工控制的,但是在实际工作中,我们想要控制某些Pod调度到指定的Node节点,就需要用到Pod调度,k8s提供了四种调度方式:
- 自动调度 //由Scheduler对Pod进行调度,不受人工干预。
- 定向调度 //人为的将Pod调度到指定的节点。
- 亲和性调度 //人为的将Pod调度到指定的节点。
- 反亲和性调度 //人为的将Pod调度到指定的节点。
1. Pod定向调度
定向调度是通过在pod上声明 nodeName 或者 node Selector 将pod调度到指定的节点上
nodeName//根据节点名称, 可以强制将Pod调度到指定的节点上。node Selector//根据节点的标签,可以强制将Pod调度到指定的节点上。
定向调度属于强制调度,即使指定的Node节点不存在,也会向该节点进行调度,只不过pod运行失败而已。
案例1:通过 NodeName 调度到 worker01节点
参考地址:kubernetes.io/zh-cn/docs/… 资源文档查询方式:kubectl explain pod.spec.nodeName
# cat deploy-nginx.yml
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy-nginx
namespace: test
spec:
replicas: 1
selector:
matchLabels:
app: deploy-nginx
template:
metadata:
labels:
app: deploy-nginx
spec:
nodeName: worker01 #定义调度策略,并指定集群节点名称
containers:
- name: nginx
image: nginx:1.20.0
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
protocol: TCP
# 更新pod配置
kubectl apply -f deploy-nginx.yml
# 查看pod信息
kubectl get pod -o wide -n test
案例2:通过 node Selector 调度到带有node=worker02标签的节点
# worker02节点打标签
kubectl label node worker02 node=worker02
# 查看节点标签
kubectl get node worker02 --show-labels | grep worker02
创建Pod并通过 NodeSelector 进行调度:
# cat deploy-nginx.yml
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy-nginx
namespace: test
spec:
replicas: 1
selector:
matchLabels:
app: deploy-nginx
template:
metadata:
labels:
app: deploy-nginx
spec:
nodeSelector: #定义nodeSelector
node: worker02 #指定节点标签
containers:
- name: nginx
image: nginx:1.20.0
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
protocol: TCP
# 更新pod配置
kubectl apply -f deploy-nginx.yml
# 查看pod信息
kubectl get pod -o wide -n test
2. 污点和容忍
污点(Taint) 通过在节点上添加污点属性,来避免 Pod 被分配到不合适的节点上。 容忍(Toleration) 通过在 Pod 上添加容忍属性,允许Pod被调度到带有污点的节点上。
污点属性说明:
PreferNoSchedule//尽量避免调度(软限制),除非没有其他节点可调度。NoSchedule//拒绝调度(硬限制),但不会影响当前节点已经存在的pod。NoExecute//拒绝调度,同时驱逐已经存在的pod。
污点案例1:设置污点 PreferNoSchedule
参考地址:kubernetes.io/zh-cn/docs/… 命令查询方法:kubectl taint --help
设置污点格式:kubectl taint node 节点名称 key=value:污点属性 更新污点格式:kubectl taint node 节点名称 key=value:新污点属性 删除污点格式:kubectl taint node 节点名称 key=value:污点-
# 设置污点PreferNoSchedule
kubectl taint node worker01 node=worker01:PreferNoSchedule
# 通过Pod详细查看污点
kubectl describe node worker01 | grep -i taint
...
Taints: node=worker01:PreferNoSchedule
为了演示污点效果,将worker02节点关机:
# kubectl get nodes
...
worker02 NotReady
将前边案例创建的Pod先删除掉:
kubectl delete -f deploy-nginx.yml
把配置文件中定向调度属性删除,再进行创建:
# cat deploy-nginx.yml
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy-nginx
namespace: test
spec:
replicas: 1
selector:
matchLabels:
app: deploy-nginx
template:
metadata:
labels:
app: deploy-nginx
spec:
nodeSelector: #删除(或者注释掉)
node: worker02 #删除(或者注释掉)
containers:
- name: nginx
image: nginx:1.20.0
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
protocol: TCP
# 创建pod
kubectl apply -f deploy-nginx.yml
# 查看pod信息
kubectl get pod -o wide -n test
# 验证Pod如果已经被调度到worker01节点后,删除Pod
kubectl delete -f deploy-nginx.yml
污点案例2:设置污点 NoScheduler
# 更新node=worker01污点为NoSchedule
kubectl taint node worker01 node=worker01:NoSchedule
# 查看污点信息
kubectl describe node worker01 | grep -i taint
...
Taints: node=worker01:NoSchedule
# 创建Pod
kubectl create -f deploy-nginx.yml
# 查看Pod信息
kubectl get pod -o wide -n test
# 验证Pod如果无法被调度到worker01节点后,删除Pod
kubectl delete -f deploy-nginx.yml
提示:使用kubeadm搭建的集群,默认就会给 Master 节点添加一个污点NodeSchedule,默认的Pod不会被调度到Master节点。
kubectl describe node master01 | grep -i taint
kubectl describe node master02 | grep -i taint
kubectl describe node master03 | grep -i taint
容忍案例:添加容忍调度到worker01节点
资源文档查询方法:kubectl explain pod.spec.tolerations
# cat vim deploy-nginx.yml
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy-nginx
namespace: test
spec:
replicas: 1
selector:
matchLabels:
app: deploy-nginx
template:
metadata:
labels:
app: deploy-nginx
spec:
tolerations: #添加容忍
- key: "node" #污点的key(必须引起来)
value: "worker01" #key的值
effect: NoSchedule #容器的污点
containers:
- name: nginx
image: nginx:1.17.0
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
protocol: TCP
# 创建pod
kubectl create -f deploy-nginx.yml
# 查看pod信息
kubectl get pod -o wide -n test
# 验证Pod如果已经被调度到worker01节点后,删除Pod
kubectl delete -f deploy-nginx.yml
# 删除污点
kubectl taint node worker01 worker01:NoSchedule-
十三、Pod 容器探测
容器探测类似于对容器进行健康检查,用来探测容器中的程序是否可以正常工作,如果探测到容器出现故障,k8s会尝试重启容器,如果重启失败,k8s不会将流量分配给该容器,不承担业务流量。
k8s提供了两种探针来实现对容器的探测,可通 kubectl explain pod.spec.containers 查看:
liveness Probe//存活探针,检测容器是否为正常运行状态,如果不是,容器将会被重启。readiness Probe//就绪探针,检测容器当前是否能接收请求,如果不能,k8s不会分配流量,也不会被重启。
以上两种探针目前均支持多种探测方式:
exec//通过在容器内执行命令,并根据返回的状态码来判断容器是否存活。tcpSocket//通过检查容器的特定端口是否可以成功连接来判断容器是否存活。httpGet//通过向容器发送HTTP请求,根据返回的状态码,判断容器是否存活。initialDelaySeconds//容器启动后等待多少秒执行第一次探测,默认为立即开始执行。timeoutSeconds//探测超时时间,默认1秒,最小可设置1秒。failureThreshold//连续探测失败多少次才被认定失败,默认3次为失败,最小可设置1。periodSeconds//执行探测频率,默认是10秒,最小可设置1秒。successThreshold//连续探测成功多少次才被认定为成功,默认1次。
案例1:liveness Probe + exec 探测
参考地址:kubernetes.io/zh-cn/docs/…
# cat deploy-nginx.yml
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy-nginx
namespace: test
spec:
replicas: 1
selector:
matchLabels:
app: deploy-nginx
template:
metadata:
labels:
app: deploy-nginx
spec:
containers:
- name: nginx
image: nginx:1.18.0
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
protocol: TCP
livenessProbe: #定义探针
exec: #定义探测方式
command: [/bin/ls,/etc/hello.txt] #探测一个不存在的文件
# 创建Pod
kubectl create -f deploy-nginx.yml
# 查看Pod信息
kubectl get pod -n test
# 查看Pod详细信息
kubectl describe pod -n test
# 删除Pod
kubectl delete -f deploy-nginx.yml
探测存在的文件:
# cat deploy-nginx.yml
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy-nginx
namespace: test
spec:
replicas: 1
selector:
matchLabels:
app: deploy-nginx
template:
metadata:
labels:
app: deploy-nginx
spec:
containers:
- name: nginx
image: nginx:1.18.0
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
protocol: TCP
livenessProbe:
exec:
command: [/bin/ls,/etc/passwd] #探测一个存在的文件
# 创建Pod
kubectl create -f deploy-nginx.yml
# 查看Pod信息
kubectl get pod -n test
# 查看Pod详细信息
kubectl describe pod -n test
# 删除Pod
kubectl delete -f deploy-nginx.yml
案例2:readiness Probe + tcpSocket 探测
# cat deploy-nginx.yml
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy-nginx
namespace: test
spec:
replicas: 1
selector:
matchLabels:
app: deploy-nginx
template:
metadata:
labels:
app: deploy-nginx
spec:
containers:
- name: nginx
image: nginx:1.18.0
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
protocol: TCP
readinessProbe: #定义探针
tcpSocket: #定义探测方式
port: 8080 #探测一个不存在的端口
initialDelaySeconds: 3 #容器启动后等待3秒执行探测
periodSeconds: 3 #执行探测频率为3秒
# 创建pod
kubectl create -f deploy-nginx.yml
# 查看Pod信息
kubectl get pod -n test
# 查看Pod详细信息
kubectl describe pod -n test
# 删除Pod
kubectl delete -f deploy-nginx.yml
探测存在的端口:
# cat deploy-nginx.yml
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy-nginx
namespace: test
spec:
replicas: 1
selector:
matchLabels:
app: deploy-nginx
template:
metadata:
labels:
app: deploy-nginx
spec:
containers:
- name: nginx
image: nginx:1.18.0
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
protocol: TCP
livenessProbe:
tcpSocket:
port: 80 #探测一个存在的端口
initialDelaySeconds: 3 #容器启动后等待3秒执行探测
periodSeconds: 3 #执行探测频率为3秒
# 创建pod
kubectl create -f deploy-nginx.yml
# 查看Pod信息
kubectl get pod -n test
# 查看Pod详细信息
kubectl describe pod -n test
# 删除Pod
kubectl delete -f deploy-nginx.yml
案例3:readiness Probe + httpGet 探测
# cat deploy-nginx.yml
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy-nginx
namespace: test
spec:
# replicas: 3
selector:
matchLabels:
app: deploy-nginx
template:
metadata:
labels:
app: deploy-nginx
spec:
containers:
- name: nginx
image: nginx:1.20.2
ports:
- name: http-nginx
containerPort: 80
protocol: TCP
imagePullPolicy: IfNotPresent
resources:
limits:
cpu: "1"
memory: "200M"
requests:
cpu: "0.5"
memory: "128M"
readinessProbe: #就绪探针
httpGet: #发送HTTP请求
path: /index.html #请求的页面
port: 80 #端口
initialDelaySeconds: 3 #容器启动后等待3秒执行探测
periodSeconds: 3 #执行探测频率为3秒
十四、Pod 重启策略
参考地址:kubernetes.io/zh-cn/docs/…
当Pod中的容器一旦出现了问题,K8s就会对容器所在的Pod进行重启,重启操作是由Pod的重启策略决定,Pod的重启策略有三种,可通过 kubectl explain pod.spec.restartPolicy 查看:
- Always //容器异常时,自动重启该容器,默认策略
- OnFailure //容器终止运行,且退出码不为0时重启(异常终止)
- Never //无论容器状态如何,都不重启该容器
重启操作延时:首次立即重启,随后为 10s、20s、40s、80s、160s、300s,最长延时为 300s,以后重启延时均为 300s,直至重启成功。
十五、Pod 更新策略
Deployment 控制器支持两种 Pod 更新的策略,通过 strategy 属性进行配置,可通过 kubectl explain deploy.spec.strategy 查看:
Recreate(重建更新) //首先停止所有旧的Pod副本,然后再创建新的Pod副本,直到新的Pod副本完全就绪。RollingUpdat(滚动更新) //逐步替换旧的Pod副本,以确保在更新过程中服务的持续可用性,也是默认策略。
案例1:Recreate 重建更新
# cat deploy-nginx.yml
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy-nginx
namespace: test
spec:
strategy: #更新策略
type: Recreate #策略类型
replicas: 3 #创建Pod数量
selector:
matchLabels:
app: deploy-nginx
template:
metadata:
labels:
app: deploy-nginx
spec:
containers:
- name: nginx
image: nginx:1.18.0
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
protocol: TCP
# 创建pod
kubectl create -f deploy-nginx.yml
# 另外开一个终端查看pod的信息,-w(Watch)选项可以持续监视资源的变化
kubectl get pod -w -n test
更新镜像版本:
# 更新镜像版本
kubectl edit deploy deploy-nginx -n test
...
spec:
containers:
- image: nginx:1.20.0 #指定新版本
观察pod的重建过程:
- 第一步:将Running的pod先终止(Terminating)
- 第二步:接下来创建新Pod,新Pod刚开始处于等待状态(Pending)
- 第三步:创建容器(ContainerCreating)
- 第四步:新的容器被创建且以成功运行(Running )
# 查看Pod信息
kubectl get pod -n test
# 查看deploy信息
kubectl get deploy -o wide -n test
# 删除Pod
kubectl delete -f deploy-nginx.yml
案例2:RollingUpdate 滚动更新
可以通过以下属性控制Pod的更新数量:
maxUnavailable//用来指定在升级过程中最多可停止的pod数量,默认为25%maxSurge//用来指定在升级过程中最多可新建的pod数量,默认为25%
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 1
maxSurge: 1
完整配置:
# cat deploy-nginx.yml
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy-nginx
namespace: test
spec:
strategy:
rollingUpdate: #滚动更新
maxUnavailable: 1 #最多停止的Pod数量为1个
maxSurge: 1 #最多新建的Pod数量为1个
replicas: 3
selector:
matchLabels:
app: deploy-nginx
template:
metadata:
labels:
app: deploy-nginx
spec:
containers:
- name: nginx
image: nginx:1.18.0
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
protocol: TCP
# 创建pod
kubectl create -f deploy-nginx.yml
# 另外一个终端动态查看pod信息
kubectl get pod -w -n test
更新镜像版本:
# 更新镜像版本
kubectl edit deploy deploy-nginx -n test
spec:
containers:
- image: nginx:1.20.0
# 查看Pod信息
kubectl get pod -n test
# 查看deploy信息
kubectl get deploy -o wide -n test
# 查看RS信息,当pod滚动更新后,rs也会随之跟着更新,原有rs中的pod会被删除,但是原有的rs并不会删除,用于做版本回退
kubectl get rs -o wide -n test
十六、Pod 版本回退
Deploy支持滚动升级过程中的暂停、继续、回退等功能,具体功能如下:
命令格式:kubectl rollout <command> [选项]
status//显示当前升级状态history//显示升级历史记录pause//暂停升级过程resume//继续升级过程restart//重启升级过程undo//版本回退(可以通过--to-revision切换到指定版本)
案例:多次更新镜像版本并回退
# 升级镜像版本
kubectl edit deploy deploy-nginx -n test
spec:
containers:
- image: nginx:1.20.1
# 升级镜像版本
kubectl edit deploy deploy-nginx -n test
spec:
containers:
- image: nginx:1.21.0
# 通过 kubectl rollout status 显示当前升级的状态
kubectl rollout status deploy deploy-nginx -n test
# 查看deploy当前使用的版本
kubectl get deploy -o wide -n test
# 查看当前所有版本(通过rs可以查看)
kubectl get rs -o wide -n test
# 通过 kubectl rollout history 查看升级历史记录
kubectl rollout history deploy deploy-nginx -n test
# 通过 kubectl rollout history --revision=版本编号,查看具体版本详细信息
kubectl rollout history --revision=2 deploy deploy-nginx -n test
# 通过 kubectl rollout undo --to-revision=版本编号,可直接回退到1版本,如果省略这个选项,就是回退到上个版本
kubectl rollout undo --to-revision=1 deploy deploy-nginx -n test
# 查看当前使用的版本
kubectl get deploy -o wide -n test
# 查看升级历史记录
kubectl rollout history deploy deploy-nginx -n test
十七、DaemonSet 控制器
DaemonSet(DS)控制器在功能方面与Deployment控制器几乎一样,支持滚动更新、版本回退等, 但DaemonSet适合部署系统级别的服务,如日志收集、节点监控、节点代理、网络插件等,以下是DaemonSet的特点及应用场景:
提示:DaemonSet不通过控制RS管理Pod。
- 每个节点只有一个副本:DaemonSet确保每个节点上都运行一个Pod副本(如:日志收集、节点监控、节点代理等),当新的节点加入集群时,DaemonSet会自动创建并调度Pod到这个新节点上。相反,如果节点从集群中被移除,这个节点上的Pod将被垃圾回收。
- 支持Pod的故障自动恢复:如果DaemonSet控制的Pod发生故障,它会自动重启Pod,如果Pod被删除,他会在节点重建新的Pod,以保证服务的可用性。
- 滚动更新:DaemonSet支持滚动更新,这使得你可以对运行在所有节点上的Pod进行版本更新操作,而不会影响到整个服务的可用性。
- 特定节点运行:也可以通过在DaemonSet的Pod模板中设置nodeSelector来让DaemonSet仅在满足某种条件的节点上运行。
案例1:创建Nginx Pod保证每个节点运行
参考地址:kubernetes.io/zh-cn/docs/… 资源文档查询方法:kubectl explain ds
# cat ds-nginx.yml
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: ds-nginx
namespace: test
spec:
selector:
matchLabels:
name: ds-nginx
template:
metadata:
labels:
name: ds-nginx
spec:
# tolerations: #如果节点有污点且需要调度,需要通过添加容忍来调度
# - key: #污点key
# value: #污点的值
# effect: NoSchedule #污点类型
containers:
- name: nginx
image: nginx:1.18.0
ports:
- containerPort: 80
# 创建Pod
kubectl create -f ds-nginx.yml
# 查看Pod信息
kubectl get pod -n test -o wide
# 查看ds信息
kubectl get ds -n test
# 删除Pod
kubectl delete -f ds-nginx.yml
案例2:指定仅在master01、master02节点运行
为master01、master02节点打标签:
# master01、master02节点打标签
kubectl label node master01 master02 k8s=master
# 查看节点标签
kubectl get node master01 master02 --show-labels | grep master
检查节点是否存在污点:
kubectl describe node master01 master02 | grep -i taint
Taints: master:NoSchedule
Taints: master:NoSchedule
创建Pod:
# cat ds-nginx.yml
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: ds-nginx
namespace: test
spec:
selector:
matchLabels:
name: ds-nginx
template:
metadata:
labels:
name: ds-nginx
spec:
nodeSelector: #定义nodeSelector
k8s: master #指定节点标签
tolerations: #如果节点有污点,需要通过添加容忍来调度
- key: master #污点key
value: #污点的值
effect: NoSchedule #污点类型
containers:
- name: nginx
image: nginx:1.18.0
ports:
- containerPort: 80
# 创建Pod
kubectl create -f ds-nginx.yml
# 查看Pod信息
kubectl get pod -n test -o wide
# 查看ds信息
kubectl get ds -n test
# 删除Pod
kubectl delete -f ds-nginx.yml
十八、HPA 控制器
HPA(Horizontal Pod Autoscaler)控制器, 可帮助Deployment 或者StatefulSet 根据CPU利用率自动调整Pod副本数量,它获取每个Pod的CPU指标,然后和HPA中定义的CPU指标进行对比,同时计算出需要增加或者删除的具体数量,最后实现pod的数量的自动(非手动)调整。以下是HPA控制器的主要特点:
- 自动扩缩容:HPA可以根据实际的工作负载自动调整Pod的副本数,以实现Pod的水平扩缩。这对于那些工作负载波动较大的应用非常有用。
- CPU利用率:HPA可以基于CPU利用率来自动调整Pod的副本数。当Pod的平均CPU利用率超过预定的目标时,HPA会增加Pod的副本数;反之,则减少副本数。
- 稳定性:HPA会根据规定的最小和最大副本数进行扩缩,不会导致副本数无休止的增加或者减少,这有助于保持系统的稳定性。
- 与Metrics Server协同工作:HPA依赖于Metrics Server(资源监控组件),通过Metrics Server获取到实时的监控数据,来决定是否需要增加或减少Pod的副本数。
1. metrics-server 资源监控
Metrics Server是Kubernetes的一个核心监控组件,它用于收集和存储每个节点和Pod的资源使用情况,如CPU和内存等。以下是Metrics Server的主要作用:
- 提供资源使用情况的数据:Metrics Server会周期性地从每个节点和Pod收集CPU和内存使用情况,并存储在内存中。
- 支持自动扩缩:Metrics Server的数据是HPA做自动扩缩容决策的重要依据。HPA根据Metrics Server提供的数据来决定是否需要增加或减少Pod的副本数。
- 支持kubectl top命令:kubectl top命令用于显示Node或Pod的CPU和内存使用情况。这个命令需要Metrics Server的支持才能工作。
请注意,Metrics Server并不提供长期的指标存储和数据可视化,只提供实时的资源使用情况。如果需要长期存储和数据可视化,或者需要收集更多种类的指标(如网络流量、磁盘使用等),需要使用其他的监控系统,如Prometheus等。
部署Metrics Server
# 下载Metrics Server资源文件
wget https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml
在文件中添加 --kubelet-insecure-tls 参数,忽略证书检测:
# vim components.yaml
...
- args:
- --kubelet-insecure-tls #忽略证书检测
生成Metrics Server证书签名请求文件:
cat > metrics-csr.json <<EOF
{
"CN": "aggregator",
"hosts": [],
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"ST": "BeiJing",
"L": "BeiJing",
"O": "system:masters",
"OU": "System"
}
]
}
EOF
使用现有的CA证书及其私钥签署:
cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=kubernetes metrics-csr.json | cfssljson -bare metrics
分发证书到其他master节点:
# 本机
cp metrics*.pem /etc/kubernetes/ssl/
# 其他master节点
for master in k8s-master02 k8s-master03
do
scp metrics*.pem $master:/etc/kubernetes/ssl
done
将Metrics Server证书注册到 API Server 中,三台master节点修改kube-apiserver.conf文件:
--runtime-config=api/all=true \
--requestheader-allowed-names=aggregator \
--requestheader-group-headers=X-Remote-Group \
--requestheader-username-headers=X-Remote-User \
--requestheader-extra-headers-prefix=X-Remote-Extra- \
--requestheader-client-ca-file=/etc/kubernetes/ssl/ca.pem \
--proxy-client-cert-file=/etc/kubernetes/ssl/metrics.pem \
--proxy-client-key-file=/etc/kubernetes/ssl/metrics-key.pem"
# 参数说明:
runtime-config=api/all=true //启用所有API版本和资源,这样可以使用所有API功能。
requestheader-allowed-names //允许"aggregator"用户发送请求,该用户在证书中已定义。
requestheader-group-headers //用户所在的组信息将通过X-Remote-Group请求头告诉API。
requestheader-username-headers //用户名将通过X-Remote-User这个请求头告诉API。
requestheader-extra-headers-prefix=X-Remote-Extra- //请求头中需要检查的前缀名。
三台节点重启API server服务:
systemctl daemon-reload
systemctl restart kube-apiserver
# 创建Metrics Server
kubectl create -f components.yaml
# 查看Metrics Server信息
kubectl get pod -n kube-system
# 通过kubectl top命令查看监控数据
kubectl top node
kubectl top pod -n kube-system
2. 案例:HPA自动扩缩容
参考地址:kubernetes.io/zh-cn/docs/… 资源文档查询方法:kubectl explain hpa
# cat hpa-nginx.yml
apiVersion: autoscaling/v1 #自动扩缩容版本
kind: HorizontalPodAutoscaler
metadata:
name: hpa-nginx
namespace: test
spec:
minReplicas: 1 #最小的pod数量
maxReplicas: 10 #最大的pod数量
targetCPUUtilizationPercentage: 10 #cpu使用指标,表示10%(生产环境建议定义在60-80)
scaleTargetRef: #指定要控制的deploy信息
apiVersion: apps/v1 #deploy版本
kind: Deployment #deploy类型
name: deploy-nginx #deploy名称
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy-nginx
namespace: test
spec:
selector:
matchLabels:
app: deploy-nginx
template:
metadata:
labels:
app: deploy-nginx
spec:
containers:
- name: nginx
image: nginx:1.18.0
resources: #资源限额
limits: #资源上限
cpu: 100m #cpu 1核心的10%的资源(生产环境建议600m-800m)
# 创建Pod
kubectl create -f hpa-nginx.yml
# 查看Pod信息
kubectl get pod test
# 查看deploy,hpa信息
kubectl get deploy,hpa -n test
测试HPA扩缩容
# 另开终端动态查看pod信息
kubectl get po -n test -w
# 通过压力测试工具访问Pod地址进行压力测试
yum -y install httpd-tools
ab -n 300000 -c 100 http://10.244.30.104/index.html
# 选项介绍
-n 请求的总数量
-c 并发数量
备注:autoscaling/v2版本配置
在HPA的autoscaling/v2版本中,废弃targetCPUUtilizationPercentage属性,通过下边方式定义CPU利用率:
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: hpa-nginx
namespace: test
spec:
scaleTargetRef: #指定要控制的deploy信息
apiVersion: apps/v1 #deploy版本
kind: Deployment #deploy类型
name: deploy-nginx #deploy名称
minReplicas: 1 #最小的pod数量
maxReplicas: 10 #最大的pod数量
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 10