每个Pod中都可以包含一个或者多个容器,这些容器可以分为两类:
每个Pod中都可以包含一个或者多个容器,这些容器可以分为两类:
主容器 pause
业务容器 user container1 user container2
这里是Pod内部的通讯,Pod的之间的通讯采用虚拟二层网络技术来实现,我们当前环境用的是
Flannel
。
1、k8s集群中部署的最小单元
2、Pod最主要的功能管理是将一个业务或者一个调用链的所有服务(容器)
3、包含多个容器(一组容器的集合)
4、一个Pod中容器共享网络命名空间,Pod是短暂的
Pod是在`集群中运行部署应用或服务的最小单元`,他是可以支持很多容器的。Pod的设计理念是支持多个容器在一个Pod中共享网络地址和文件系统,可以通过进程间通信和文件共享这种简单高效的方式组合完成服务。
比如:你运行一个操作系统发行版的软件仓库,一个nginx容器用来发布软件,另一个容器专门用来从源仓库做同步,这两个容器的镜像不太可能是一个团队开发的,但是他们一块工作才能提供一个微服务,这种情况下,不同的团队各自开发构建自己的容器镜像,在部署的时候组合成一个微服务对外提供服务。这就是k8s中的Pod。
目前k8s中业务主要可以分为`长期伺服型(long-running)、批处理型(batch)、节点后台支撑型(node-daemon)和有状态应用型(stateful application);分别对应的小机器人控制器为Deployment、Job、DaemonSet 和 StatefulSet。`
`Pod是k8s中最小部署单元,用来管理一个调用链的容器`,它之中的主容器(pause)为整个调用链的容器提供基础网络,共享存储,监控业务容器的运行状态
1、必须小写
2、必须以字母开头
3、名称当中只能够包含字母、数字和中划线(-)
apiVersion: v1 #必选,版本号,例如v1
kind: Pod #必选,资源类型,例如 Pod
metadata: #必选,元数据
name: string #必选,Pod名称
annotations: #选做,描述信息
nginx: nginx
namespace: string #Pod所属的命名空间,默认为"default"
labels: #自定义标签列表
- name: string
spec: #必选,Pod中容器的详细定义
containers: #必选,Pod中容器列表
- name: string #必选,容器名称
image: string #必选,容器的镜像名称
imagePullPolicy: [ Always|Never|IfNotPresent ] #获取镜像的策略
command: [string] #容器的启动命令列表,如不指定,使用打包时使用的启动命令
args: [string] #容器的启动命令参数列表
workingDir: string #容器的工作目录
volumeMounts: #挂载到容器内部的存储卷配置
- name: string #引用pod定义的共享存储卷的名称,需用volumes[]部分定义的的卷名
mountPath: string #存储卷在容器内mount的绝对路径,应少于512字符
readOnly: boolean #是否为只读模式
ports: #需要暴露的端口库号列表
- name: string #端口的名称
containerPort: 80 #容器需要监听的端口号
hostPort: int #容器所在主机需要监听的端口号,默认与Container相同
protocol: string #端口协议,支持TCP和UDP,默认TCP
env: #容器运行前需设置的环境变量列表
- name: string #环境变量名称
value: string #环境变量的值
resources: #资源限制和请求的设置
limits: #资源限制的设置
cpu: string #Cpu的限制,单位为core数,将用于docker run --cpu-shares参数
memory: string #内存限制,单位可以为Mib/Gib,将用于docker run --memory参数
requests: #资源请求的设置
cpu: string #Cpu请求,容器启动的初始可用数量
memory: string #内存请求,容器启动的初始可用数量
lifecycle: #生命周期钩子
postStart: #容器启动后立即执行此钩子,如果执行失败,会根据重启策略进行重启
preStop: #容器终止前执行此钩子,无论结果如何,容器都会终止
livenessProbe: #对Pod内各容器健康检查的设置,当探测无响应几次后将自动重启该容器
exec: #对Pod容器内检查方式设置为exec方式
command: [string] #exec方式需要制定的命令或脚本
httpGet: #对Pod内个容器健康检查方法设置为HttpGet,需要制定Path、port
path: string
port: number
host: string
scheme: string
HttpHeaders:
- name: string
value: string
tcpSocket: #对Pod内个容器健康检查方式设置为tcpSocket方式
port: number
initialDelaySeconds: 0 #容器启动完成后首次探测的时间,单位为秒
timeoutSeconds: 0 #对容器健康检查探测等待响应的超时时间,单位秒,默认1秒
periodSeconds: 0 #对容器监控检查的定期探测时间设置,单位秒,默认10秒一次
successThreshold: 0
failureThreshold: 0
securityContext:
privileged: false
restartPolicy: [Always | Never | OnFailure] #Pod的重启策略
nodeName: <string> #设置NodeName表示将该Pod调度到指定到名称的node节点上
nodeSelector: obeject #设置NodeSelector表示将该Pod调度到包含这个label的node上
imagePullSecrets: #Pull镜像时使用的secret名称,以key:secretkey格式指定
- name: string
hostNetwork: false #是否使用主机网络模式,默认为false,如果设置为true,表示使用宿主机网络
volumes: #在该pod上定义共享存储卷列表
- name: string #共享存储卷名称 (volumes类型有很多种)
emptyDir: {} #类型为emtyDir的存储卷,与Pod同生命周期的一个临时目录。为空值
hostPath: string #类型为hostPath的存储卷,表示挂载Pod所在宿主机的目录
path: string #Pod所在宿主机的目录,将被用于同期中mount的目录
secret: #类型为secret的存储卷,挂载集群与定义的secret对象到容器内部
scretname: string
items:
- key: string
path: string
configMap: #类型为configMap的存储卷,挂载预定义的configMap对象到容器内部
name: string
items:
- key: string
path: string
# 在这里,可通过一个命令来查看每种资源的可配置项
# kubectl explain 资源类型 查看某种资源可以配置的一级属性
# kubectl explain 资源类型.属性 查看属性的子属性
[root@k8s-m-01 ~]# kubectl explain pod
KIND: Pod
VERSION: v1
FIELDS:
apiVersion <string>
kind <string>
metadata <Object>
spec <Object>
status <Object>
[root@k8s-m-01 ~]# kubectl explain pod.metadata
KIND: Pod
VERSION: v1
RESOURCE: metadata <Object>
FIELDS:
annotations <map[string]string>
clusterName <string>
creationTimestamp <string>
deletionGracePeriodSeconds <integer>
deletionTimestamp <string>
finalizers <[]string>
generateName <string>
generation <integer>
labels <map[string]string>
managedFields <[]Object>
name <string>
namespace <string>
ownerReferences <[]Object>
resourceVersion <string>
selfLink <string>
uid <string>
# kubectl explain Pod #查apiVersion版本号 v1
[root@k8s-m-01 ~]# vim pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: test-pod
spec:
containers:
- name: nginx
image: nginx
- name: tomcat
image: tomcat
# 1、nginx PHP MySQL
# 2、 制作镜像
# 3、创建nginx配置文件,然后构建镜像
# 4、编写配置清单,部署
[root@k8s-m-01 ~]# vim wordpress.yaml
apiVersion: v1
kind: Pod
metadata:
name: wordpress
spec:
containers:
- name: nginx
image: nginx
- name: php
image: alvinos/php:v2-fpm-mysql
- name: mysql
image: mysql:5.7
env:
- name: MYSQL_ROOT_PASSWORD
value: "123"
# k8s部署一个yaml的应用:kubectl apply -f [配置清单]
[root@k8s-m-01 ~]# kubectl apply -f pod.yaml
pod/test-pod create
ImgPullErr : # 镜像拉取失败
ContainerCreating : # 容器创建中
# 扩展 1、进入不是默认空间的容器
[root@k8s-m-01 ~]# kubectl get pod -n dev
NAME READY STATUS RESTARTS AGE
pc-deployment-5c767764f5-fq47c 1/1 Running 2 78m
[root@k8s-m-01 ~]# kubectl exec -it pc-deployment-5c767764f5-fq47c -n dev -c nginx -- bash
root@pc-deployment-5c767764f5-fq47c:/# curl localhost
<h1>Welcome to nginx!</h1>
# 2、权限问题
[root@k8s-m-01 ~]# ll -a
drwxr-xr-x 3 root root 33 Jul 30 14:43 .kube
# 必须要有这个文件,否则无法创建删除pod
apiVersion
版本,由kubernetes内部定义,版本号必须可以用 kubectl api-versions 查询到kind
类型,由kubernetes内部定义,版本号必须可以用 kubectl api-resources 查询到metadata
元数据,主要是资源标识和说明,常用的有name、namespace、labels等spec
描述,这是配置中最重要的一部分,里面是对各种资源配置的详细描述status
状态信息,里面的内容不需要定义,由kubernetes自动生成containers
<[]Object> 容器列表,用于定义容器的详细信息nodeName
根据nodeName的值将pod调度到指定的Node节点上nodeSelector
volumes
<[]Object> 存储卷,用于定义Pod上面挂在的存储信息restartPolicy
重启策略,表示Pod在遇到故障的时候的处理策略# 命令格式: kubectl run (pod控制器名称) [参数]
# --image 指定Pod的镜像
# --port 指定端口
# --namespace 指定namespace
[root@k8s-m-01 ~]# kubectl run nginx --image=nginx:latest --port=80 --namespace dev
deployment.apps/nginx created
# 1、查看Pod基本信息
[root@k8s-m-01 ~]# kubectl get pods -n dev
NAME READY STATUS RESTARTS AGE
nginx 1/1 Running 0 43s
# 2、查看Pod的详细信息
[root@k8s-m-01 ~]# kubectl describe pod nginx -n dev
Name: nginx
Namespace: dev
Priority: 0
Node: node1/192.168.5.4
Start Time: Wed, 08 May 2021 09:29:24 +0800
Labels: pod-template-hash=5ff7956ff6
run=nginx
Annotations: <none>
Status: Running
IP: 10.244.1.23
IPs:
IP: 10.244.1.23
Controlled By: ReplicaSet/nginx
Containers:
nginx:
Container ID: docker://4c62b8c0648d2512380f4ffa5da2c99d16e05634979973449c98e9b829f6253c
Image: nginx:latest
Image ID: docker-pullable://nginx@sha256:485b610fefec7ff6c463ced9623314a04ed67e3945b9c08d7e53a47f6d108dc7
Port: 80/TCP
Host Port: 0/TCP
State: Running
Started: Wed, 08 May 2021 09:30:01 +0800
Ready: True
Restart Count: 0
Environment: <none>
Mounts:
/var/run/secrets/kubernetes.io/serviceaccount from default-token-hwvvw (ro)
Conditions:
Type Status
Initialized True
Ready True
ContainersReady True
PodScheduled True
Volumes:
default-token-hwvvw:
Type: Secret (a volume populated by a Secret)
SecretName: default-token-hwvvw
Optional: false
QoS Class: BestEffort
Node-Selectors: <none>
Tolerations: node.kubernetes.io/not-ready:NoExecute for 300s
node.kubernetes.io/unreachable:NoExecute for 300s
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled <unknown> default-scheduler Successfully assigned dev/nginx-5ff7956ff6-fg2db to node1
Normal Pulling 4m11s kubelet, node1 Pulling image "nginx:latest"
Normal Pulled 3m36s kubelet, node1 Successfully pulled image "nginx:latest"
Normal Created 3m36s kubelet, node1 Created container nginx
Normal Started 3m36s kubelet, node1 Started container nginx
# 1、获取pod IP
[root@k8s-m-01 ~]# kubectl get pods -n dev -o wide
NAME READY STATUS RESTARTS AGE IP NODE ...
nginx 1/1 Running 0 190s 10.244.1.23 node1 ...
# 2、访问POD
[root@k8s-m-01 ~]# curl http://10.244.1.23:80
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
</head>
<body>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
# 1、删除指定Pod
[root@k8s-m-01 ~]# kubectl delete pod nginx -n dev
pod "nginx" deleted
# 2、此时,显示删除Pod成功,但是再查询,发现又新产生了一个
[root@k8s-m-01 ~]# kubectl get pods -n dev
NAME READY STATUS RESTARTS AGE
nginx 1/1 Running 0 21s
# 这是因为当前Pod是由Pod控制器创建的,控制器会监控Pod状况,一旦发现Pod死亡,会立即重建
# 此时要想删除Pod,必须删除Pod控制器
# 3、先来查询一下当前namespace下的Pod控制器
[root@k8s-m-01 ~]# kubectl get deploy -n dev
NAME READY UP-TO-DATE AVAILABLE AGE
nginx 1/1 1 1 9m7s
# 4、接下来,删除此PodPod控制器
[root@k8s-m-01 ~]# kubectl delete deploy nginx -n dev
deployment.apps "nginx" deleted
# 5、稍等片刻,再查询Pod,发现Pod被删除了
[root@k8s-m-01 ~]# kubectl get pods -n dev
No resources found in dev namespace.
创建一个pod-nginx.yaml,内容如下:
apiVersion: v1
kind: Pod
metadata:
name: nginx
namespace: dev
spec:
containers:
- image: nginx:latest
name: pod
ports:
- name: nginx-port
containerPort: 80
protocol: TCP
然后就可以执行对应的创建和删除命令了:
# 创建:kubectl create -f pod-nginx.yaml
# 删除:kubectl delete -f pod-nginx.yaml
# 1、创建容器使用docker,一个docker对应一个容器,一个容器有进程,一个容器运行一个应用程序
# 2、pod是多进程,运行多个应用程序
# 3、一个Pod有多个容器,每个容器里面运行一个应用程序
# 4、Pod存在未来亲密性应用
1、两个应用之间进行交互
2、网络之间调用
3、两个应用需要频繁调用
1、共享网络 === 》 容器本身之间相互隔离的
2、共享存储
# 1、共享网络
通过Pause容器,把其他业务容器加入Pause容器里面,让所有业务中在同一个名称空间中,可以实现网络共享
# 2、共享存储
引入数据卷概念volumes,用数据卷进行持久化数据存储
主要来研究pod.spec.containers属性,这也是pod配置中最为关键的一项配置。
[root@k8s-m-01 ~]# kubectl explain pod.spec.containers
KIND: Pod
VERSION: v1
RESOURCE: containers <[]Object> # 数组,代表可以有多个容器
FIELDS:
name <string> # 容器名称
image <string> # 容器需要的镜像地址
imagePullPolicy <string> # 镜像拉取策略
command <[]string> # 容器的启动命令列表,如不指定,使用打包时使用的启动命令
args <[]string> # 容器的启动命令需要的参数列表
env <[]Object> # 容器环境变量的配置
ports <[]Object> # 容器需要暴露的端口号列表
resources <Object> # 资源限制和资源请求的设置
创建pod-base.yaml文件,内容如下:
apiVersion: v1
kind: Pod
metadata:
name: pod-base
namespace: dev
labels:
user: heima
spec:
containers:
- name: nginx
image: nginx
- name: busybox
image: busybox:1.30
上面定义了一个比较简单Pod的配置,里面有两个容器:
# 1、创建Pod
[root@master pod]# kubectl apply -f pod-base.yaml
pod/pod-base created
# 2、查看Pod状况
# READY 1/2 : 表示当前Pod中有2个容器,其中1个准备就绪,1个未就绪
# RESTARTS : 重启次数,因为有1个容器故障了,Pod一直在重启试图恢复它
[root@master pod]# kubectl get pod -n dev
NAME READY STATUS RESTARTS AGE
pod-base 1/2 Running 4 95s
# 3、可以通过describe查看内部的详情
# 此时已经运行起来了一个基本的Pod,虽然它暂时有问题
[root@master pod]# kubectl describe pod pod-base -n dev
创建pod-imagepullpolicy.yaml文件,内容如下:
apiVersion: v1
kind: Pod
metadata:
name: pod-imagepullpolicy
namespace: dev
spec:
containers:
- name: nginx
image: nginx
imagePullPolicy: Always # 用于设置镜像拉取策略
- name: busybox
image: busybox:1.30
imagePullPolicy
,用于设置镜像拉取策略,kubernetes支持配置三种拉取策略:
# 1、IfNotPresent:(默认值)
本地有则使用本地镜像,本地没有则从远程仓库拉取镜像(本地有就本地,本地没远程下载)
# 2. Always:
创建Pod都会重新从远程仓库拉取一次镜像(一直远程下载)
# 3. Never:
只使用本地镜像,从不去远程仓库拉取,本地没有就报错 (一直使用本地)
# 1、20版本后默认的是Onfailure :当容器终止且退出码部位0,则kubetle则重新启动容器
默认值说明:
如果镜像tag为具体版本号, 默认策略是:IfNotPresent
如果镜像tag为:latest(最终版本) ,默认策略是always
# 1、创建Pod
[root@master pod]# kubectl create -f pod-imagepullpolicy.yaml
pod/pod-imagepullpolicy created
# 2、查看Pod详情
# 此时明显可以看到nginx镜像有一步Pulling image "nginx"的过程
[root@master pod]# kubectl describe pod pod-imagepullpolicy -n dev
......
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled <unknown> default-scheduler Successfully assigned dev/pod-imagePullPolicy to k8s-n-01
Normal Pulling 32s kubelet, k8s-n-01 Pulling image "nginx"
Normal Pulled 26s kubelet, k8s-n-01 Successfully pulled image "nginx"
Normal Created 26s kubelet, k8s-n-01 Created container nginx
Normal Started 25s kubelet, k8s-n-01 Started container nginx
Normal Pulled 7s (x3 over 25s) kubelet, k8s-n-01 Container image "busybox:1.30" already present on machine
Normal Created 7s (x3 over 25s) kubelet, k8s-n-01 Created container busybox
Normal Started 7s (x3 over 25s) kubelet, k8s-n-01 Started container busybox
# 在前面的案例中,一直有一个问题没有解决,就是的busybox容器一直没有成功运行,那么到底是什么原因导致这个容器的故障呢?
原来busybox并不是一个程序,而是类似于一个工具类的集合,kubernetes集群启动管理后,它会自动关闭。
# 解决方法就是让其一直在运行,这就用到了command配置。
apiVersion: v1
kind: Pod
metadata:
name: pod-command
namespace: dev
spec:
containers:
- name: nginx
image: nginx
- name: busybox
image: busybox:1.30
command: ["/bin/sh","-c","touch /tmp/hello.txt;while true;do /bin/echo $(date +%T) >> /tmp/hello.txt; sleep 3; done;"]
# 注:
"/bin/sh","-c", 使用sh执行命令
touch /tmp/hello.txt; 创建一个/tmp/hello.txt 文件
while true;do /bin/echo $(date +%T) >> /tmp/hello.txt; sleep 3; done; 每隔3秒向文件中写入当前时间
# 1、创建Pod
[root@master pod]# kubectl create -f pod-command.yaml
pod/pod-command created
# 2、查看Pod状态
# 此时发现两个pod都正常运行了
[root@master pod]# kubectl get pods pod-command -n dev
NAME READY STATUS RESTARTS AGE
pod-command 2/2 Runing 0 2s
# 3、进入pod中的busybox容器,查看文件内容
# 补充一个命令: kubectl exec pod名称 -n 命名空间 -it -c 容器名称 /bin/sh 在容器内部执行命令
# 使用这个命令就可以进入某个容器的内部,然后进行相关操作了
# 可以查看txt文件的内容
[root@master pod]# kubectl exec pod-command -n dev -it -c busybox /bin/sh
/ # tail -f /tmp/hello.txt
13:35:35
13:35:38
13:35:41
通过上面发现command已经可以完成启动命令和传递参数的功能,为什么这里还要提供一个args选项,用于传递参数呢?这其实跟docker有点关系,kubernetes中的command、args两项其实是实现覆盖Dockerfile中ENTRYPOINT的功能。
# 1 如果command和args均没有写,那么用Dockerfile的配置。
# 2 如果command写了,但args没有写,那么Dockerfile默认的配置会被忽略,执行输入的command
# 3 如果command没写,但args写了,那么Dockerfile中配置的ENTRYPOINT的命令会被执行,使用当前args的参数
# 4 如果command和args都写了,那么Dockerfile的配置被忽略,执行command并追加上args参数
apiVersion: v1
kind: Pod
metadata:
name: pod-env
namespace: dev
spec:
containers:
- name: busybox
image: busybox:1.30
command: ["/bin/sh","-c","while true;do /bin/echo $(date +%T);sleep 60; done;"]
env: # 设置环境变量列表
- name: "username"
value: "admin"
- name: "password"
value: "123456"
# 1、创建Pod
[root@k8s-m-01 ~]# kubectl create -f pod-env.yaml
pod/pod-env created
# 2、进入容器,输出环境变量
[root@k8s-m-01 ~]# kubectl exec pod-env -n dev -c busybox -it /bin/sh
/ # echo $username
admin
/ # echo $password
123456
这种方式不是很推荐,推荐将这些配置单独存储在配置文件中,这种方式将在后面介绍。
端口设置就是containers的ports选项
[root@k8s-m-01 ~]# kubectl explain pod.spec.containers.ports
KIND: Pod
VERSION: v1
RESOURCE: ports <[]Object>
FIELDS:
name <string> # 端口名称,如果指定,必须保证name在pod中是唯一的
containerPort<integer> # 容器要监听的端口(0
hostPort <integer> # 容器要在主机上公开的端口,如果设置,主机上只能运行容器的一个副本(一般省略)
hostIP <string> # 要将外部端口绑定到的主机IP(一般省略)
protocol <string> # 端口协议。必须是UDP、TCP或SCTP。默认为“TCP”。
apiVersion: v1
kind: Pod
metadata:
name: pod-ports
namespace: dev
spec:
containers:
- name: nginx
image: nginx
ports: # 设置容器暴露的端口列表
- name: nginx-port
containerPort: 80
protocol: TCP
# 1、创建Pod
[root@k8s-m-01 ~]# kubectl create -f pod-ports.yaml
pod/pod-ports created
# 2、查看pod
# 在下面可以明显看到配置信息
[root@k8s-m-01 ~]# kubectl get pod pod-ports -n dev -o yaml
......
spec:
containers:
- image: nginx
imagePullPolicy: IfNotPresent
name: nginx
ports:
- containerPort: 80
name: nginx-port
protocol: TCP
......
访问容器中的程序需要使用的是podIp:containerPort
容器中的程序要运行,肯定是要占用一定资源的,比如cpu和内存等,如果不对某个容器的资源做限制,那么它就可能吃掉大量资源,导致其它容器无法运行。
针对这种情况,kubernetes提供了对内存和cpu的资源进行配额的机制,这种机制主要通过resources选项实现,他有两个子选项:
limits
:用于限制运行时容器的最大占用资源,当容器占用资源超过limits时会被终止,并进行重启requests
:用于设置容器需要的最小资源,如果环境资源不够,容器将无法启动可以通过上面两个选项设置资源的上下限。
apiVersion: v1
kind: Pod
metadata:
name: pod-resources
namespace: dev
spec:
containers:
- name: nginx
image: nginx
resources: # 资源配额
limits: # 限制资源(上限)
cpu: "2" # CPU限制,单位是core数
memory: "10Gi" # 内存限制
requests: # 请求资源(下限)
cpu: "1" # CPU限制,单位是core数
memory: "10Mi" # 内存限制
cpu:core数,可以为整数或小数
memory: 内存大小,可以使用Gi、Mi、G、M等形式
# 1、运行Pod
[root@k8s-m-01 ~]# kubectl create -f pod-resources.yaml
pod/pod-resources created
# 2、查看发现pod运行正常
[root@k8s-m-01 ~]# kubectl get pod pod-resources -n dev
NAME READY STATUS RESTARTS AGE
pod-resources 1/1 Running 0 39s
# 3、停止(删除)Pod
[root@k8s-m-01 ~]# kubectl delete -f pod-resources.yaml
pod "pod-resources" deleted
# 4、编辑pod,修改resources.requests.memory的值为10Gi
[root@k8s-m-01 ~]# vim pod-resources.yaml
# 5、再次启动pod
[root@k8s-m-01 ~]# kubectl create -f pod-resources.yaml
pod/pod-resources created
# 6、查看Pod状态,发现Pod启动失败
[root@k8s-m-01 ~]# kubectl get pod pod-resources -n dev -o wide
NAME READY STATUS RESTARTS AGE
pod-resources 0/2 Pending 0 20s
# 7、查看pod详情会发现,如下提示
[root@k8s-m-01 ~]# kubectl describe pod pod-resources -n dev
......
Warning FailedScheduling <unknown> default-scheduler 0/2 nodes are available: 2 Insufficient memory.(内存不足)
我们一般将pod对象从创建至终的这段时间范围称为pod的生命周期,它主要包含下面的过程:
1、创建pod,并调度到合适的节点上
2、创建pause基础主容器,提供共享名称空间 # (info容器) == 根容器 == 主容器
3、从上到下依次创建业务容器
4、启动业务容器,启动那一刻会同时运行主容器上定义的Poststart钩子事件
5、持续存活状态监测、就绪状态监测
6、结束时,执行prestop钩子事件
7、终止业务容器,在终止主容器
8、销毁Pod
# 1、挂起(Pending):
API Server 创建了 pod 资源对象已存入 etcd 中,但它尚未被调度完成,或者仍处于从仓库下载镜像的过程中。
# 2、运行中(Running):
Pod 已经被调度至某节点,并且所有容器都已经被 kubelet 创建完成
# 3、成功(Succeeded):
Pod 中的所有容器都已经成功终止并且不会被重启。
# 4、失败(Failed):
Pod 中的所有容器都已终止了,并且至少有一个容器是因为失败终止。即容器以非 0 状态退出或者被系统禁止。
# 5、未知(Unknown):
Api Server 无法正常获取到 Pod 对象的状态信息,通常是由于无法与所在工作节点的kubelet 通信所致。
===================================================================================================
# 6、ImgPullErr : (不常用)
镜像拉取失败
# 7、ContainerCreating : (不常用)
容器创建中
kubernetes在集群启动之后,集群中的各个组件也都是以Pod方式运行的。可以通过下面命令查看:
[root@k8s-m-01 ~]# kubectl get pod -n kube-system
NAMESPACE NAME READY STATUS RESTARTS AGE
kube-system coredns-6955765f44-68g6v 1/1 Running 0 2d1h
kube-system coredns-6955765f44-cs5r8 1/1 Running 0 2d1h
kube-system etcd-master 1/1 Running 0 2d1h
kube-system kube-apiserver-master 1/1 Running 0 2d1h
kube-system kube-controller-manager-master 1/1 Running 0 2d1h
kube-system kube-flannel-ds-amd64-47r25 1/1 Running 0 2d1h
kube-system kube-flannel-ds-amd64-ls5lh 1/1 Running 0 2d1h
kube-system kube-proxy-685tk 1/1 Running 0 2d1h
kube-system kube-proxy-87spt 1/1 Running 0 2d1h
kube-system kube-scheduler-master 1/1 Running 0 2d1h
1. 用户通过kubectl或其他api客户端提交需要创建的Pod信息给apiServer
2. apiServer开始生成Pod对象的信息,并将信息存入etcd,然后返回确认信息至客户端
3. apiServer开始反映etcd中的Pod对象的变化,其它组件使用watch机制来跟踪检查apiServer上的变动
4. scheduler发现有新的Pod对象要创建,开始为Pod分配主机并将结果信息更新至apiServer
5. node节点上的kubelet发现有pod调度过来,尝试调用docker启动容器,并将结果回送至apiServer
6. apiServer将接收到的pod状态信息存入etcd中
1. 用户向apiServer发送删除pod对象的命令
2. apiServcer中的pod对象信息会随着时间的推移而更新,在宽限期内(默认30s),pod被视为dead
3. 将pod标记为terminating状态(正在删除状态)
4. kubelet在监控到pod对象转为terminating状态的同时启动pod关闭过程
5. 端点控制器监控到pod对象的关闭行为时将其从所有匹配到此端点的service资源的端点列表中移除
6. 如果当前pod对象定义了preStop钩子处理器,则在其标记为terminating后即会以同步的方式启动执行
7. pod对象中的容器进程收到停止信号
8. 宽限期结束后,若pod中还存在仍在运行的进程,那么pod对象会收到立即终止的信号
9. kubelet请求apiServer将此pod资源的宽限期设置为0从而完成删除操作,此时pod对于用户已不可见
初始化容器是在pod的主容器启动之前要运行的容器,主要是做一些主容器的前置工作,它具有两大特征:
1. 初始化容器必须运行完成直至结束,若某初始化容器运行失败,那么kubernetes需要重启它直到成功完成
2. 初始化容器必须按照定义的顺序执行,当且仅当前一个成功之后,后面的一个才能运行
案例,模拟下面这个需求:
假设要以主容器来运行nginx,但是要求在运行nginx之前先要能够连接上mysql和redis所在服务器
为了简化测试,事先规定好mysql(192.168.15.201)和redis(192.168.15.202)服务器的地址
1、创建pod-initcontainer.yaml,内容如下:
apiVersion: v1
kind: Pod
metadata:
name: pod-initcontainer
namespace: dev
spec:
containers:
- name: main-container
image: nginx:1.17.1
ports:
- name: nginx-port
containerPort: 80
initContainers:
- name: test-mysql
image: busybox:1.30
command: ['sh', '-c', 'until ping 192.168.15.201 -c 1 ; do echo waiting for mysql...; sleep 2; done;']
- name: test-redis
image: busybox:1.30
command: ['sh', '-c', 'until ping 192.168.15.202 -c 1 ; do echo waiting for reids...; sleep 2; done;']
# 1、创建pod
[root@k8s-m-01 ~]# kubectl create -f pod-initcontainer.yaml
pod/pod-initcontainer created
# 2、查看pod状态
# 发现pod卡在启动第一个初始化容器过程中,后面的容器不会运行
root@master ~]# kubectl describe pod pod-initcontainer -n dev
........
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 49s default-scheduler Successfully assigned dev/pod-initcontainer to k8s-n-01
Normal Pulled 48s kubelet, k8s-n-01 Container image "busybox:1.30" already present on machine
Normal Created 48s kubelet, k8s-n-01 Created container test-mysql
Normal Started 48s kubelet, k8s-n-01 Started container test-mysql
# 3、动态查看pod
[root@k8s-m-01 ~]# kubectl get pods pod-initcontainer -n dev -w
NAME READY STATUS RESTARTS AGE
pod-initcontainer 0/1 Init:0/2 0 15s
pod-initcontainer 0/1 Init:1/2 0 52s
pod-initcontainer 0/1 Init:1/2 0 53s
pod-initcontainer 0/1 PodInitializing 0 89s
pod-initcontainer 1/1 Running 0 90s
# 4、接下来新开一个shell,为当前服务器新增两个ip,观察pod的变化
[root@k8s-m-01 ~]# ifconfig eth0:1 192.168.15.201 netmask 255.255.255.0 up
[root@k8s-m-01 ~]# ifconfig eth0:2 192.168.15.202 netmask 255.255.255.0 up
钩子函数
能够感知自身生命周期中的事件,并在相应的时刻到来时运行用户指定的程序代码。
kubernetes在主容器的启动之后和停止之前提供了两个钩子函数:
1、post start: # 容器创建之后执行,如果失败了会重启容器
2、pre stop : # 容器终止之前执行,执行完成之后容器将成功终止,在其完成之前会阻塞删除容器的操作
钩子处理器支持使用下面三种方式定义动作:
……
lifecycle:
postStart:
exec:
command:
- cat
- /tmp/healthy
……
……
lifecycle:
postStart:
tcpSocket:
port: 8080
……
……
lifecycle:
postStart:
httpGet:
path: / #URI地址
port: 80 #端口号
host: 192.168.15.100 #主机地址
scheme: HTTP #支持的协议,http或者https
……
接下来,以exec方式为例,演示下钩子函数的使用,创建pod-hook-exec.yaml文件,内容如下:
apiVersion: v1
kind: Pod
metadata:
name: pod-hook-exec
namespace: dev
spec:
containers:
- name: main-container
image: nginx:1.17.1
ports:
- name: nginx-port
containerPort: 80
lifecycle:
postStart:
exec: # 在容器启动的时候执行一个命令,修改掉nginx的默认首页内容
command: ["/bin/sh", "-c", "echo postStart... > /usr/share/nginx/html/index.html"]
preStop:
exec: # 在容器停止之前停止nginx服务
command: ["/usr/sbin/nginx","-s","quit"]
# 1、创建pod
[root@k8s-m-01 ~]# kubectl create -f pod-hook-exec.yaml
pod/pod-hook-exec created
# 2、查看pod
[root@k8s-m-01 ~]# kubectl get pods pod-hook-exec -n dev -o wide
NAME READY STATUS RESTARTS AGE IP NODE
pod-hook-exec 1/1 Running 0 29s 10.244.2.48 k8s-n-02
# 3、访问pod
[root@k8s-m-01 ~]# curl 10.244.2.48
postStart...
`容器探测`用于检测容器中的应用实例是否正常工作,是保障业务可用性的一种传统机制。如果经过探测,实例的状态不符合预期,那么kubernetes就会把该问题实例" 摘除 ",不承担业务流量。kubernetes提供了两种探针来实现容器探测,分别是:
# 1、存活性检查 :
容器是否正常启动,探测失败,立即删除容器
# 2、就绪性检查 :
容器是否能够正常提供服务,探测失败,立即移除负载均衡
liveness probes
: 存活性探针,用于检测应用实例当前是否处于正常运行状态,如果不是,k8s会重启容器readiness probes
:就绪性探针,用于检测应用实例当前是否可以接收请求,如果不能,k8s不会转发流量
livenessProbe 决定是否重启容器,readinessProbe 决定是否将请求转发给容器
上面两种探针目前均支持三种探测方式:
……
livenessProbe:
exec:
command:
- cat
- /tmp/healthy
……
……
livenessProbe:
tcpSocket:
port: 8080
……
……
livenessProbe:
httpGet:
path: / #URI地址
port: 80 #端口号
host: 127.0.0.1 #主机地址
scheme: HTTP #支持的协议,http或者https
……
下面以liveness probes为例,做几个演示:
apiVersion: v1
kind: Pod
metadata:
name: pod-liveness-exec
namespace: dev
spec:
containers:
- name: nginx
image: nginx:1.17.1
ports:
- name: nginx-port
containerPort: 80
livenessProbe:
exec:
command: ["/bin/cat","/tmp/hello.txt"] # 执行一个查看文件的命令
# 1、创建Pod
[root@k8s-m-01 ~]# kubectl create -f pod-liveness-exec.yaml
pod/pod-liveness-exec created
# 2、查看Pod详情
[root@k8s-m-01 ~]# kubectl describe pods pod-liveness-exec -n dev
......
Normal Created 20s (x2 over 50s) kubelet, k8s-n-01 Created container nginx
Normal Started 20s (x2 over 50s) kubelet, k8s-n-01 Started container nginx
Normal Killing 20s kubelet, k8s-n-01 Container nginx failed liveness probe, will be restarted
Warning Unhealthy 0s (x5 over 40s) kubelet, k8s-n-01 Liveness probe failed: cat: can't open '/tmp/hello11.txt': No such file or directory
# 观察上面的信息就会发现nginx容器启动之后就进行了健康检查
# 检查失败之后,容器被kill掉,然后尝试进行重启(这是重启策略的作用,后面讲解)
# 稍等一会之后,再观察pod信息,就可以看到RESTARTS不再是0,而是一直增长
[root@k8s-m-01 ~]# kubectl get pods pod-liveness-exec -n dev
NAME READY STATUS RESTARTS AGE
pod-liveness-exec 0/1 CrashLoopBackOff 2 3m19s
# 当然接下来,可以修改成一个存在的文件,比如/tmp/hello.txt,再试,结果就正常了......
# command: ["/bin/ls","/tmp/"] #正确配置(查看文件的命令)
apiVersion: v1
kind: Pod
metadata:
name: pod-liveness-tcpsocket
namespace: dev
spec:
containers:
- name: nginx
image: nginx:1.17.1
ports:
- name: nginx-port
containerPort: 80
livenessProbe:
tcpSocket:
port: 8080 # 尝试访问8080端口
# 1、创建Pod
[root@k8s-m-01 ~]# kubectl create -f pod-liveness-tcpsocket.yaml
pod/pod-liveness-tcpsocket created
# 2、查看Pod详情
[root@k8s-m-01 ~]# kubectl describe pods pod-liveness-tcpsocket -n dev
......
Normal Scheduled 31s default-scheduler Successfully assigned dev/pod-liveness-tcpsocket to k8s-n-02
Normal Pulled <invalid> kubelet, k8s-n-02 Container image "nginx:1.17.1" already present on machine
Normal Created <invalid> kubelet, k8s-n-02 Created container nginx
Normal Started <invalid> kubelet, k8s-n-02 Started container nginx
Warning Unhealthy <invalid> (x2 over <invalid>) kubelet, k8s-n-02 Liveness probe failed: dial tcp 10.244.2.44:8080: connect: connection refused
# 观察上面的信息,发现尝试访问8080端口,但是失败了
# 稍等一会之后,再观察pod信息,就可以看到RESTARTS不再是0,而是一直增长
[root@k8s-m-01 ~]# kubectl get pods pod-liveness-tcpsocket -n dev
NAME READY STATUS RESTARTS AGE
pod-liveness-tcpsocket 0/1 CrashLoopBackOff 2 3m19s
# 当然接下来,可以修改成一个可以访问的端口,比如80,再试,结果就正常了......
# port: 80 (正确配置)
apiVersion: v1
kind: Pod
metadata:
name: pod-liveness-httpget
namespace: dev
spec:
containers:
- name: nginx
image: nginx:1.17.1
ports:
- name: nginx-port
containerPort: 80
livenessProbe:
httpGet: # 其实就是访问http://127.0.0.1:80/hello
scheme: HTTP #支持的协议,http或者https
port: 80 #端口号
path: /hello #URI地址
# 1、创建Pod
[root@k8s-m-01 ~]# kubectl create -f pod-liveness-httpget.yaml
pod/pod-liveness-httpget created
# 2、查看Pod详情
[root@k8s-m-01 ~]# kubectl describe pod pod-liveness-httpget -n dev
.......
Normal Pulled 6s (x3 over 64s) kubelet, k8s-n-01 Container image "nginx:1.17.1" already present on machine
Normal Created 6s (x3 over 64s) kubelet, k8s-n-01 Created container nginx
Normal Started 6s (x3 over 63s) kubelet, k8s-n-01 Started container nginx
Warning Unhealthy 6s (x6 over 56s) kubelet, k8s-n-01 Liveness probe failed: HTTP probe failed with statuscode: 404
Normal Killing 6s (x2 over 36s) kubelet, k8s-n-01 Container nginx failed liveness probe, will be restarted
# 3、观察上面信息,尝试访问路径,但是未找到,出现404错误
# 稍等一会之后,再观察pod信息,就可以看到RESTARTS不再是0,而是一直增长
[root@k8s-m-01 ~]# kubectl get pod pod-liveness-httpget -n dev
NAME READY STATUS RESTARTS AGE
pod-liveness-httpget 1/1 Running 5 3m17s
# 当然接下来,可以修改成一个可以访问的路径path,比如/,再试,结果就正常了......
# path: / (正确配置)
至此,已经使用liveness Probe
演示了三种探测方式,但是查看livenessProbe
的子属性,会发现除了这三种方式,还有一些其他的配置,在这里一并解释下:
[root@k8s-m-01 ~]# kubectl explain pod.spec.containers.livenessProbe
FIELDS:
exec <Object>
tcpSocket <Object>
httpGet <Object>
initialDelaySeconds <integer> # 容器启动后等待多少秒执行第一次探测
timeoutSeconds <integer> # 探测超时时间。默认1秒,最小1秒
periodSeconds <integer> # 执行探测的频率。默认是10秒,最小1秒
failureThreshold <integer> # 连续探测失败多少次才被认定为失败。默认是3。最小值是1
successThreshold <integer> # 连续探测成功多少次才被认定为成功。默认是1
下面稍微配置两个,演示下效果即可:
[root@k8s-m-01 ~]# more pod-liveness-httpget.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-liveness-httpget
namespace: dev
spec:
containers:
- name: nginx
image: nginx:1.17.1
ports:
- name: nginx-port
containerPort: 80
livenessProbe:
httpGet:
scheme: HTTP
port: 80
path: /
initialDelaySeconds: 30 # 容器启动后30s开始探测
timeoutSeconds: 5 # 探测超时时间为5s
# 1. Always: (默认)
当容器失效时,由 kubelet 自动重启该容器。
# 2. OnFailure:
当容器终止运行且退出码不为 0 时,由 kubelet 自动重启该容器
# 3. Never:
不论容器运行状态如何,kubelet 都不会重启该容器。
kubelet 重启失效容器的时间间隔以 sync-frequency 乘以 2n 来计算;例如 1、2、4、8 倍等,最长延时5min ,并且在成功重启后的 10 min 后重置该时间。
Pod 的重启策略与控制方式息息相关,当前可用于管理 Pod 的控制器包括 ReplicationController、Job、DaemonSet 及直接通过 kubelet 管理(静态 Pod)。每种控制器对 Pod 的重启策略要求如下:
# 1.RC 和 DaemonSet:必须设置为 Always,需要保证该容器持续运行。
# 2.Job 和 CronJob:OnFailure 或 Never,确保容器执行完成后不再重启。
# 3.kubelet:在 Pod 失效时自动重启它,不论将 RestartPolicy 设置为什么值,也不会对 Pod 进行健康检查。
`重启策略`适用于pod对象中的所有容器,首次需要重启的容器,将在其需要时立即进行重启,随后再次需要重启的操作将由kubelet延迟一段时间后进行,且反复的重启操作的延迟时长以此为10s、20s、40s、80s、160s和300s,300s是最大延迟时长。
`Pod 重启策略( RestartPolicy )应用于 Pod 内的所有容器`,井且仅在 Pod 所处的 Node 上由 kubelet 进行判断和重启操作。
当某个容器异常退出或者健康检查失败时, kubelet 将根据 `RestartPolicy `设置来进行相应的操作。`Pod 的重启策略包括:Always、OnFailure 和 Never,默认值为 Always
`
apiVersion: v1
kind: Pod
metadata:
name: pod-restartpolicy
namespace: dev
spec:
containers:
- name: nginx
image: nginx:1.17.1
ports:
- name: nginx-port
containerPort: 80
livenessProbe:
httpGet:
scheme: HTTP
port: 80
path: /hello
restartPolicy: Never # 设置重启策略为Never (默认Always)
# 1、创建Pod
[root@k8s-m-01 ~]# kubectl create -f pod-restartpolicy.yaml
pod/pod-restartpolicy created
# 2、查看Pod详情,发现nginx容器失败
[root@k8s-m-01 ~]# kubectl describe pods pod-restartpolicy -n dev
......
Warning Unhealthy 15s (x3 over 35s) kubelet, k8s-n-01 Liveness probe failed: HTTP probe failed with statuscode: 404
Normal Killing 15s kubelet, k8s-n-01 Container nginx failed liveness probe
# 3、多等一会,再观察pod的重启次数,发现一直是0,并未重启
[root@k8s-m-01 ~]# kubectl get pods pod-restartpolicy -n dev
NAME READY STATUS RESTARTS AGE
pod-restartpolicy 0/1 Running 0 5min42s
`Pod`中可以同时运行多个进程(作为容器运行)协同工作。
同一个 Pod 中的容器会自动的分配到同一个 node上。同一个 Pod 中的容器共享资源、网络环境和依赖,所以它们总是被同时调度。在一个 Pod 中同时运行多个容器是一种比较高级的用法。只有当你的容器需要紧密配合协作的时候才考虑用这种模式。
Pod 在设计⽀持就不是作为持久化实体的。在调度失败、节点故障、缺少资源或者节点维护的状态下都会死
掉会被驱逐。通常,我们是需要借助类似于 Docker 存储卷这样的资源来做 Pod 的数据持久
在默认情况下,一个Pod在哪个Node节点上运行,是由Scheduler组件采用相应的算法计算出来的,这个过程是不受人工控制的。但是在实际使用中,这并不满足的需求,因为很多情况下,我们想控制某些Pod到达某些节点上,那么应该怎么做呢?这就要求了解kubernetes对Pod的调度规则,kubernetes提供了四大类调度方式:
NodeName、NodeSelector
NodeAffinity、PodAffinity、PodAntiAffinity
Taints、Toleration
定向调度,指的是利用在pod上声明nodeName或者nodeSelector,以此将Pod调度到期望的node节点上。注意,这里的调度是强制的,这就意味着即使要调度的目标Node不存在,也会向上面进行调度,只不过pod运行失败而已。
NodeName
用于强制约束将Pod调度到指定的Name的Node节点上。这种方式,其实是直接跳过Scheduler的调度逻辑,直接将Pod调度到指定名称的节点。
创建一个pod-nodename.yaml文件
[root@k8s-m-01 ~]# kubectl get nodes
NAME STATUS ROLES AGE VERSION
k8s-m-01 Ready control-plane,master 4d18h v1.21.3
k8s-n-01 Ready <none> 4d18h v1.21.3
k8s-n-02 Ready <none> 4d18h v1.21.3
apiVersion: v1
kind: Pod
metadata:
name: pod-nodename
namespace: dev
spec:
containers:
- name: nginx
image: nginx:1.17.1
nodeName: k8s-n-01 # 指定调度到k8s-n-01节点上(node的主机名称)
# 1、创建Pod
[root@k8s-m-01 ~]# kubectl create -f pod-nodename.yaml
pod/pod-nodename created
# 2、查看Pod调度到NODE属性,确实是调度到了k8s-n-01节点上
[root@k8s-m-01 ~]# kubectl get pods pod-nodename -n dev -o wide
NAME READY STATUS RESTARTS AGE IP NODE ......
pod-nodename 1/1 Running 0 56s 10.244.1.87 k8s-n-01 ......
# 3、接下来,删除pod,修改nodeName的值为node3(并没有node3节点)
[root@k8s-m-01 ~]# kubectl delete -f pod-nodename.yaml
pod "pod-nodename" deleted
[root@k8s-m-01 ~]# vim pod-nodename.yaml
[root@k8s-m-01 ~]# kubectl create -f pod-nodename.yaml
pod/pod-nodename created
# 4、再次查看,发现已经向Node3节点调度,但是由于不存在node3节点,所以pod无法正常运行
[root@k8s-m-01 ~]# kubectl get pods pod-nodename -n dev -o wide
NAME READY STATUS RESTARTS AGE IP NODE ......
pod-nodename 0/1 Pending 0 6s <none> node3 ......
`NodeSelector用`于将pod调度到添加了指定标签的node节点上。它是通过kubernetes的`label-selector机制`实现的,也就是说,在pod创建之前,会由`scheduler使用MatchNodeSelector`调度策略进行`label`匹配,找出目标node,然后将pod调度到目标节点,该匹配规则是强制约束。
[root@k8s-m-01 ~]# kubectl label nodes k8s-n-01 nodeenv=pro
node/k8s-n-02 labeled
[root@k8s-m-01 ~]# kubectl label nodes k8s-n-02 nodeenv=test
node/k8s-n-02 labeled
apiVersion: v1
kind: Pod
metadata:
name: pod-nodeselector
namespace: dev
spec:
containers:
- name: nginx
image: nginx:1.17.1
nodeSelector:
nodeenv: pro # 指定调度到具有nodeenv=pro标签的节点上
# 1、创建Pod
[root@k8s-m-01 ~]# kubectl create -f pod-nodeselector.yaml
pod/pod-nodeselector created
# 2、查看Pod调度到NODE属性,确实是调度到了k8s-n-01节点上
[root@k8s-m-01 ~]# kubectl get pods pod-nodeselector -n dev -o wide
NAME READY STATUS RESTARTS AGE IP NODE ......
pod-nodeselector 1/1 Running 0 47s 10.244.1.87 k8s-n-01 ......
# 3、接下来,删除pod,修改nodeSelector的值为nodeenv: xxxx(不存在打有此标签的节点)
[root@k8s-m-01 ~]# kubectl delete -f pod-nodeselector.yaml
pod "pod-nodeselector" deleted
[root@k8s-m-01 ~]# vim pod-nodeselector.yaml
[root@k8s-m-01 ~]# kubectl create -f pod-nodeselector.yaml
pod/pod-nodeselector created
# 4、再次查看,发现pod无法正常运行,Node的值为none
[root@k8s-m-01 ~]# kubectl get pods -n dev -o wide
NAME READY STATUS RESTARTS AGE IP NODE
pod-nodeselector 0/1 Pending 0 2m20s <none> <none>
# 5、查看详情,发现node selector匹配失败的提示
[root@k8s-m-01 ~]# kubectl describe pods pod-nodeselector -n dev
.......
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Warning FailedScheduling <unknown> default-scheduler 0/3 nodes are available: 3 node(s) didn't match node selector.
Warning FailedScheduling default-scheduler 0/3 nodes are available: 3 node(s) didn' t match node selector.
上一节,介绍了两种定向调度的方式,使用起来非常方便,但是也有一定的问题,那就是如果没有满足条件的Node,那么Pod将不会被运行,即使在集群中还有可用Node列表也不行,这就限制了它的使用场景。
基于上面的问题,kubernetes还提供了一种亲和性调度`(Affinity)`。它在`NodeSelector`的基础之上的进行了扩展,可以通过配置的形式,实现优先选择满足条件的Node进行调度,如果没有,也可以调度到不满足条件的节点上,使调度更加灵活。
Affinity主要分为三类:
nodeAffinity(node亲和性
): 以node为目标,解决pod可以调度到哪些node的问题podAffinity(pod亲和性)
: 以pod为目标,解决pod可以和哪些已存在的pod部署在同一个拓扑域中的问题podAntiAffinity(pod反亲和性)
: 以pod为目标,解决pod不能和哪些已存在pod部署在同一个拓扑域中的问题关于亲和性(反亲和性)使用场景的说明:
亲和性
:如果两个应用频繁交互,那就有必要利用亲和性让两个应用的尽可能的靠近,这样可以减少因网络通信而带来的性能损耗。
反亲和性
:当应用的采用多副本部署时,有必要采用反亲和性让各个应用实例打散分布在各个node上,这样可以提高服务的高可用性
首先来看一下NodeAffinity的可配置项:
pod.spec.affinity.nodeAffinity
requiredDuringSchedulingIgnoredDuringExecution Node节点必须满足指定的所有规则才可以,相当于硬限制
nodeSelectorTerms 节点选择列表
matchFields 按节点字段列出的节点选择器要求列表
matchExpressions 按节点标签列出的节点选择器要求列表(推荐)
key 键
values 值
operator 关系符 支持Exists, DoesNotExist, In, NotIn, Gt, Lt
preferredDuringSchedulingIgnoredDuringExecution 优先调度到满足指定的规则的Node,相当于软限制 (倾向)
preference 一个节点选择器项,与相应的权重相关联
matchFields 按节点字段列出的节点选择器要求列表
matchExpressions 按节点标签列出的节点选择器要求列表(推荐)
key 键
values 值
operator 关系符 支持In, NotIn, Exists, DoesNotExist, Gt, Lt
weight 倾向权重,在范围1-100。
关系符的使用说明:
- matchExpressions:
- key: nodeenv # 匹配存在标签的key为nodeenv的节点
operator: Exists
- key: nodeenv # 匹配标签的key为nodeenv,且value是"xxx"或"yyy"的节点
operator: In
values: ["xxx","yyy"]
- key: nodeenv # 匹配标签的key为nodeenv,且value大于"xxx"的节点
operator: Gt
values: "xxx"
一下requiredDuringSchedulingIgnoredDuringExecution
,创建pod-nodeaffinity-required.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-nodeaffinity-required
namespace: dev
spec:
containers:
- name: nginx
image: nginx:1.17.1
affinity: #亲和性设置
nodeAffinity: #设置node亲和性
requiredDuringSchedulingIgnoredDuringExecution: # 硬限制
nodeSelectorTerms:
- matchExpressions: # 匹配env的值在["xxx","yyy"]中的标签
- key: nodeenv
operator: In
values: ["xxx","yyy"]
# 1、创建pod
[root@k8s-m-01 ~]# kubectl create -f pod-nodeaffinity-required.yaml
pod/pod-nodeaffinity-required created
# 2、查看pod状态 (运行失败)
[root@k8s-m-01 ~]# kubectl get pods pod-nodeaffinity-required -n dev -o wide
NAME READY STATUS RESTARTS AGE IP NODE ......
pod-nodeaffinity-required 0/1 Pending 0 16s <none> <none> ......
# 3、查看Pod的详情
# 发现调度失败,提示node选择失败
[root@k8s-m-01 ~]# kubectl describe pod pod-nodeaffinity-required -n dev
......
Warning FailedScheduling <unknown> default-scheduler 0/3 nodes are available: 3 node(s) didn't match node selector.
Warning FailedScheduling default-scheduler 0/3 nodes are available: 3 node(s) didn' t match node selector.
# 4、接下来,停止pod
[root@k8s-m-01 ~]# kubectl delete -f pod-nodeaffinity-required.yaml
pod "pod-nodeaffinity-required" deleted
# 5、修改文件,将values: ["xxx","yyy"]------> ["pro","yyy"]
[root@k8s-m-01 ~]# vim pod-nodeaffinity-required.yaml
# 6、再次启动
[root@k8s-m-01 ~]# kubectl create -f pod-nodeaffinity-required.yaml
pod/pod-nodeaffinity-required created
# 7、此时查看,发现调度成功,已经将pod调度到了k8s-n-01上
[root@k8s-m-01 ~]# kubectl get pods pod-nodeaffinity-required -n dev -o wide
NAME READY STATUS RESTARTS AGE IP NODE ......
pod-nodeaffinity-required 1/1 Running 0 11s 10.244.1.89 k8s-n-01 ......
一下requiredDuringSchedulingIgnoredDuringExecution
创建pod-nodeaffinity-preferred.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-nodeaffinity-preferred
namespace: dev
spec:
containers:
- name: nginx
image: nginx:1.17.1
affinity: #亲和性设置
nodeAffinity: #设置node亲和性
preferredDuringSchedulingIgnoredDuringExecution: # 软限制
- weight: 1
preference:
matchExpressions: # 匹配env的值在["xxx","yyy"]中的标签(当前环境没有)
- key: nodeenv
operator: In
values: ["xxx","yyy"]
# 1、创建pod
[root@k8s-m-01 ~]# kubectl create -f pod-nodeaffinity-preferred.yaml
pod/pod-nodeaffinity-preferred created
# 2、查看pod状态 (运行成功)
[root@k8s-m-01 ~]# kubectl get pod pod-nodeaffinity-preferred -n dev
NAME READY STATUS RESTARTS AGE
pod-nodeaffinity-preferred 1/1 Running 0 40s
NodeAffinity规则设置的注意事项:
# 1 、如果同时定义了,那么必须两个条件都得到满足,Pod才能运行在指定的Node上
# 2 、如果nodeAffinity指定了多个nodeSelectorTerms,那么只需要其中一个能够匹配成功即可
# 3 、如果一个nodeSelectorTerms中有多个matchExpressions ,则一个节点必须满足所有的才能匹配成功
# 4 、如果一个pod所在的Node在Pod运行期间其标签发生了改变,不再符合该Pod的节点亲和性需求,则系统将忽略此变化
PodAffinity主要实现以运行的Pod为参照,实现让新创建的Pod跟参照pod在一个区域的功能。
1、首先来看一下PodAffinity
的可配置项
pod.spec.affinity.podAffinity
requiredDuringSchedulingIgnoredDuringExecution 硬限制
namespaces 指定参照pod的namespace
topologyKey 指定调度作用域
labelSelector 标签选择器
matchExpressions 按节点标签列出的节点选择器要求列表(推荐)
key 键
values 值
operator 关系符 支持In, NotIn, Exists, DoesNotExist.
matchLabels 指多个matchExpressions映射的内容
preferredDuringSchedulingIgnoredDuringExecution 软限制
podAffinityTerm 选项
namespaces
topologyKey
labelSelector
matchExpressions
key 键
values 值
operator
matchLabels
weight 倾向权重,在范围1-100
`topologyKey`用于指定调度时作用域,例如:
如果指定为`kubernetes.io/hostname`,那就是以Node节点为区分范围
如果指定为`beta.kubernetes.io/os,`则以Node节点的操作系统类型来区分
requiredDuringSchedulingIgnoredDuringExecution
,1、首先创建一个参照Pod,pod-podaffinity-target.yaml:
apiVersion: v1
kind: Pod
metadata:
name: pod-podaffinity-target
namespace: dev
labels:
podenv: pro #设置标签
spec:
containers:
- name: nginx
image: nginx:1.17.1
nodeName: k8s-n-01 # 将目标pod名确指定到k8s-n-01上
# 启动目标pod
[root@k8s-m-01 ~]# kubectl create -f pod-podaffinity-target.yaml
pod/pod-podaffinity-target created
# 查看pod状况
[root@k8s-m-01 ~]# kubectl get pods pod-podaffinity-target -n dev
NAME READY STATUS RESTARTS AGE
pod-podaffinity-target 1/1 Running 0 4s
apiVersion: v1
kind: Pod
metadata:
name: pod-podaffinity-required
namespace: dev
spec:
containers:
- name: nginx
image: nginx:1.17.1
affinity: #亲和性设置
podAffinity: #设置pod亲和性
requiredDuringSchedulingIgnoredDuringExecution: # 硬限制
- labelSelector:
matchExpressions: # 匹配env的值在["xxx","yyy"]中的标签
- key: podenv
operator: In
values: ["xxx","yyy"]
topologyKey: kubernetes.io/hostname
上面配置表达的意思是:新Pod必须要与拥有标签nodeenv=xxx或者nodeenv=yyy的pod在同一Node上,显然现在没有这样pod,接下来,运行测试一下。
# 1、启动pod
[root@k8s-m-01 ~]# kubectl create -f pod-podaffinity-required.yaml
pod/pod-podaffinity-required created
# 2、查看pod状态,发现未运行
[root@k8s-m-01 ~]# kubectl get pods pod-podaffinity-required -n dev
NAME READY STATUS RESTARTS AGE
pod-podaffinity-required 0/1 Pending 0 9s
# 3、查看详细信息
[root@k8s-m-01 ~]# kubectl describe pods pod-podaffinity-required -n dev
......
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Warning FailedScheduling <unknown> default-scheduler 0/3 nodes are available: 2 node(s) didn't match pod affinity rules, 1 node(s) had taints that the pod didn't tolerate.
# 4、接下来修改 values: ["xxx","yyy"]----->values:["pro","yyy"]
# 意思是:新Pod必须要与拥有标签nodeenv=xxx或者nodeenv=yyy的pod在同一Node上
[root@k8s-m-01 ~]# vim pod-podaffinity-required.yaml
# 5、然后重新创建pod,查看效果
[root@k8s-m-01 ~]# kubectl delete -f pod-podaffinity-required.yaml
pod "pod-podaffinity-required" deleted
[root@k8s-m-01 ~]# kubectl create -f pod-podaffinity-required.yaml
pod/pod-podaffinity-required created
# 6、发现此时Pod运行正常
[root@k8s-m-01 ~]# kubectl get pods pod-podaffinity-required -n dev
NAME READY STATUS RESTARTS AGE LABELS
pod-podaffinity-required 1/1 Running 0 6s <none>
PodAntiAffinity
主要实现以运行的Pod为参照,让新创建的Pod跟参照pod不在一个区域中的功能。
它的配置方式和选项跟PodAffinty
是一样的,这里不再做详细解释,直接做一个测试案例。
[root@k8s-m-01 ~]# kubectl get pods -n dev -o wide --show-labels
NAME READY STATUS RESTARTS AGE IP NODE LABELS
pod-podaffinity-required 1/1 Running 0 3m29s 10.244.1.38 k8s-n-01 <none>
pod-podaffinity-target 1/1 Running 0 9m25s 10.244.1.37 k8s-n-01 podenv=pro
apiVersion: v1
kind: Pod
metadata:
name: pod-podantiaffinity-required
namespace: dev
spec:
containers:
- name: nginx
image: nginx:1.17.1
affinity: #亲和性设置
podAntiAffinity: #设置pod亲和性
requiredDuringSchedulingIgnoredDuringExecution: # 硬限制
- labelSelector:
matchExpressions: # 匹配podenv的值在["pro"]中的标签
- key: podenv
operator: In
values: ["pro"]
topologyKey: kubernetes.io/hostname
上面配置表达的意思是:新Pod必须要与拥有标签nodeenv=pro的pod不在同一Node上,运行测试一下。
# 创建pod
[root@k8s-m-01 ~]# kubectl create -f pod-podantiaffinity-required.yaml
pod/pod-podantiaffinity-required created
# 查看pod
# 发现调度到了k8s-n-02上
[root@k8s-m-01 ~]# kubectl get pods pod-podantiaffinity-required -n dev -o wide
NAME READY STATUS RESTARTS AGE IP NODE ..
pod-podantiaffinity-required 1/1 Running 0 30s 10.244.1.96 k8s-n-02 ..
前面的调度方式都是站在Pod的角度上,通过在Pod上添加属性,来确定Pod是否要调度到指定的Node上,其实我们也可以站在Node的角度上,通过在Node上添加`污点属性`,来决定是否允许Pod调度过来。
Node被设置上污点之后就和Pod之间存在了一种相斥的关系,进而拒 NoExecute绝Pod调度进来,甚至可以将已经存在的Pod驱逐出去。
污点的格式为:key=value:effect,
key和value是污点的标签,effect描述污点的作用,支持如下三个选项:
PreferNoSchedule
:kubernetes将尽量避免把Pod调度到具有该污点的Node上,除非没有其他节点可调度NoSchedule
:kubernetes将不会把Pod调度到具有该污点的Node上,但不会影响当前Node上已存在的PodNoExecute
:kubernetes将不会把Pod调度到具有该污点的Node上,同时也会将Node上已存在的Pod驱离# 1、设置污点
kubectl taint nodes k8s-n-01 key=value:effect
# 2、去除污点
kubectl taint nodes k8s-n-01 key:effect-
# 3、去除所有污点
kubectl taint nodes k8s-n-01 key-
接下来,演示下污点的效果:
1.准备节点k8s-n-01(为了演示效果更加明显,暂时停止k8s-n-02节点)
2.为k8s-n-01节点设置一个污点: tag=heima:PreferNoSchedule
;然后创建pod1( pod1 可以 )
3.修改为k8s-n-01节点设置一个污点: tag=heima:NoSchedule
;然后创建pod2( pod1 正常 pod2 失败 )
4.修改为k8s-n-01节点设置一个污点:tag=heima:NoExecute
;然后创建pod3 ( 3个pod都失败 )
# 1、为k8s-n-01设置污点(PreferNoSchedule)
[root@k8s-m-01 ~]# kubectl taint nodes k8s-n-01 tag=heima:PreferNoSchedule
# 2、创建pod1
[root@k8s-m-01 ~]# kubectl run taint1 --image=nginx:1.17.1 -n dev
[root@k8s-m-01 ~]# kubectl get pods -n dev -o wide
NAME READY STATUS RESTARTS AGE IP NODE
taint1-7665f7fd85-574h4 1/1 Running 0 2m24s 10.244.1.59 k8s-n-01
# 3、为k8s-n-01设置污点(取消PreferNoSchedule,设置NoSchedule)
[root@k8s-m-01 ~]# kubectl taint nodes k8s-n-01 tag:PreferNoSchedule-
[root@k8s-m-01 ~]# kubectl taint nodes k8s-n-01 tag=heima:NoSchedule
# 4、创建pod2
[root@k8s-m-01 ~]# kubectl run taint2 --image=nginx:1.17.1 -n dev
[root@k8s-m-01 ~]# kubectl get pods taint2 -n dev -o wide
NAME READY STATUS RESTARTS AGE IP NODE
taint1-7665f7fd85-574h4 1/1 Running 0 2m24s 10.244.1.59 k8s-n-01
taint2-544694789-6zmlf 0/1 Pending 0 21s <none> <none>
# 5、为k8s-n-01设置污点(取消NoSchedule,设置NoExecute)
[root@k8s-m-01 ~]# kubectl taint nodes k8s-n-01 tag:NoSchedule-
[root@k8s-m-01 ~]# kubectl taint nodes k8s-n-01 tag=heima:NoExecute
# 6、创建pod3
[root@k8s-m-01 ~]# kubectl run taint3 --image=nginx:1.17.1 -n dev
[root@k8s-m-01 ~]# kubectl get pods -n dev -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED
taint1-7665f7fd85-htkmp 0/1 Pending 0 35s <none> <none> <none>
taint2-544694789-bn7wb 0/1 Pending 0 35s <none> <none> <none>
taint3-6d78dbd749-tktkq 0/1 Pending 0 6s <none> <none> <none>
总结:
使用`kubeadm搭建的集群,默认就会给master节点添加一个污点标记,所以pod就不会调度到master节点上.`
上面介绍了污点
的作用,我们可以在node上添加污点用于拒绝pod调度上来,但是如果就是想将一个pod调度到一个有污点的node上去,这时候应该怎么做呢?这就要使用到容忍。
污点就是拒绝,容忍就是忽略,Node通过污点拒绝pod调度上去,Pod通过容忍忽略拒绝
下面先通过一个案例看下效果:
1.上一小节,已经在k8s-n-01节点上打上了NoExecute的污点,此时pod是调度不上去的
2.本小节,可以通过给pod添加容忍,然后将其调度上去
1、创建pod-toleration.yaml,内容如下
apiVersion: v1
kind: Pod
metadata:
name: pod-toleration
namespace: dev
spec:
containers:
- name: nginx
image: nginx:1.17.1
tolerations: # 添加容忍
- key: "tag" # 要容忍的污点的key
operator: "Equal" # 操作符
value: "heima" # 容忍的污点的value
effect: "NoExecute" # 添加容忍的规则,这里必须和标记的污点规则相同
# 添加容忍之前的pod
[root@k8s-m-01 ~]# kubectl get pods -n dev -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED
pod-toleration 0/1 Pending 0 3s <none> <none> <none>
# 添加容忍之后的pod
[root@k8s-m-01 ~]# kubectl get pods -n dev -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED
pod-toleration 1/1 Running 0 3s 10.244.1.62 k8s-n-01 <none>
[root@k8s-m-01 ~]# kubectl explain pod.spec.tolerations
......
FIELDS:
key # 对应着要容忍的污点的键,空意味着匹配所有的键
value # 对应着要容忍的污点的值
operator # key-value的运算符,支持Equal和Exists(默认)
effect # 对应污点的effect,空意味着匹配所有影响
tolerationSeconds # 容忍时间, 当effect为NoExecute时生效,表示pod在Node上的停留时间
Pod是kubernetes的最小管理单元,在kubernetes中,按照pod的创建方式可以将其分为两类:
# 自主式pod:
kubernetes`直接创建出来的Pod,这种pod删除后就没有了,也不会重建`
# 控制器创建的pod:
kubernetes通过控制器创建的pod,这种pod`删除了之后还会自动重建`
什么是Pod控制器
`Pod控制器是管理pod的中间层`,使用Pod控制器之后,只需要告诉Pod控制器,想要多少个什么样的Pod就可以了,它会创建出满足条件的Pod并确保每一个Pod资源处于用户期望的目标状态。如果Pod资源在运行中出现故障,它会基于指定策略重新编排Pod。
在kubernetes中,有很多类型的pod控制器,每种都有自己的适合的场景,常见的有下面这些:
# 1、ReplicationController:
比较原始的pod控制器,已经被废弃,由`ReplicaSet`替代
# 2、ReplicaSet:
保证副本数量一直维持在期望值,`并支持pod数量扩缩容,镜像版本升级`
# 3、Deployment:
通过控制ReplicaSet来控制Pod,`并支持滚动升级、回退版本`
# 4、Horizontal Pod Autoscaler:
可以根据集群`负载自动水平调整Pod的数量,实现削峰填谷`
# 5、DaemonSet:
在集群中的指定`Node上运行且仅运行一个副本`,一般用于守护进程类的任务
# 6、Job:
它创建出来的pod只要完成任务就立即退出,`不需要重启或重建,用于执行一次性任务`
# 7、Cronjob:
它创建的Pod负责周期性任务控制,`不需要持续后台运行`
# 8、StatefulSet:
>`管理有状态应用
`
ReplicaSet
的主要作用是保证一定数量的pod
正常运行,它会持续监听这些Pod的运行状态,一旦Pod发生故障,就会重启或重建。同时它还支持对pod数量的扩缩容和镜像版本的升降级。
apiVersion: apps/v1 # 版本号
kind: ReplicaSet # 类型
metadata: # 元数据
name: # rs名称
namespace: # 所属命名空间
labels: #标签
controller: rs
spec: # 详情描述
replicas: 3 # 副本数量
selector: # 选择器,通过它指定该控制器管理哪些pod
matchLabels: # Labels匹配规则
app: nginx-pod
matchExpressions: # Expressions匹配规则
- {key: app, operator: In, values: [nginx-pod]}
template: # 模板,当副本数量不足时,会根据下面的模板创建pod副本
metadata:
labels:
app: nginx-pod
spec:
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
在这里面,需要新了解的配置项就是spec下面几个选项:
replicas
:指定副本数量,其实就是当前rs创建出来的pod的数量,默认为1selector
:选择器,它的作用是建立pod控制器和pod之间的关联关系,采用的Label Selector机制label
,在控制器上定义选择器,就可以表明当前控制器能管理哪些podtemplate
:模板,就是当前控制器创建pod所使用的模板板,里面其实就是前一章学过的pod的定义1、创建ReplicaSet
创建pc-replicaset.yaml文件,内容如下:
apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: pc-replicaset
namespace: dev
spec:
replicas: 3
selector:
matchLabels:
app: nginx-pod
template:
metadata:
labels:
app: nginx-pod
spec:
containers:
- name: nginx
image: nginx
# 1、创建rs
[root@k8s-m-01 ~]# kubectl create -f pc-replicaset.yaml
replicaset.apps/pc-replicaset created
# 2、查看rs
# DESIRED:期望副本数量
# CURRENT:当前副本数量
# READY:已经准备好提供服务的副本数量
[root@k8s-m-01 ~]# kubectl get rs pc-replicaset -n dev -o wide
NAME DESIRED CURRENT READY AGE CONTAINERS IMAGES SELECTOR
pc-replicaset 3 3 3 22s nginx nginx app=nginx-pod
# 查看当前控制器创建出来的pod
# 这里发现控制器创建出来的pod的名称是在控制器名称后面拼接了-xxxxx随机码
[root@k8s-m-01 ~]# kubectl get pod -n dev
NAME READY STATUS RESTARTS AGE
pc-replicaset-6vmvt 1/1 Running 0 54s
pc-replicaset-fmb8f 1/1 Running 0 54s
pc-replicaset-snrk2 1/1 Running 0 54s
# 1、编辑rs的副本数量,修改spec:replicas: 6即可
[root@k8s-m-01 ~]# kubectl edit rs pc-replicaset -n dev
replicaset.apps/pc-replicaset edited
# 2、查看pod
[root@k8s-m-01 ~]# kubectl get pods -n dev
NAME READY STATUS RESTARTS AGE
pc-replicaset-6vmvt 1/1 Running 0 114m
pc-replicaset-cftnp 1/1 Running 0 10s
pc-replicaset-fjlm6 1/1 Running 0 10s
pc-replicaset-fmb8f 1/1 Running 0 114m
pc-replicaset-s2whj 1/1 Running 0 10s
pc-replicaset-snrk2 1/1 Running 0 114m
# 当然也可以直接使用命令实现
# 3、使用scale命令实现扩缩容, 后面--replicas=n直接指定目标数量即可
[root@k8s-m-01 ~]# kubectl scale rs pc-replicaset --replicas=2 -n dev
replicaset.apps/pc-replicaset scaled
# 命令运行完毕,立即查看,发现已经有4个开始准备退出了
[root@k8s-m-01 ~]# kubectl get pods -n dev
NAME READY STATUS RESTARTS AGE
pc-replicaset-6vmvt 0/1 Terminating 0 118m
pc-replicaset-cftnp 0/1 Terminating 0 4m17s
pc-replicaset-fjlm6 0/1 Terminating 0 4m17s
pc-replicaset-fmb8f 1/1 Running 0 118m
pc-replicaset-s2whj 0/1 Terminating 0 4m17s
pc-replicaset-snrk2 1/1 Running 0 118m
# 4、稍等片刻,就只剩下2个了
[root@k8s-m-01 ~]# kubectl get pods -n dev
NAME READY STATUS RESTARTS AGE
pc-replicaset-fmb8f 1/1 Running 0 119m
pc-replicaset-snrk2 1/1 Running 0 119m
# 1、编辑rs的容器镜像 - image: nginx:1.17.2
[root@k8s-m-01 ~]# kubectl edit rs pc-replicaset -n dev
replicaset.apps/pc-replicaset edited
# 2、再次查看,发现镜像版本已经变更了
[root@k8s-m-01 ~]# kubectl get rs -n dev -o wide
NAME DESIRED CURRENT READY AGE CONTAINERS IMAGES ...
pc-replicaset 2 2 2 140m nginx nginx:1.17.2 ...
# 同样的道理,也可以使用命令完成这个工作
# kubectl set image rs rs名称 容器=镜像版本 -n namespace
[root@k8s-m-01 ~]# kubectl set image rs pc-replicaset nginx=nginx -n dev
replicaset.apps/pc-replicaset image updated
# 3、再次查看,发现镜像版本已经变更了
[root@k8s-m-01 ~]# kubectl get rs -n dev -o wide
NAME DESIRED CURRENT READY AGE CONTAINERS IMAGES ...
pc-replicaset 2 2 2 145m nginx nginx ...
# 1、使用kubectl delete命令会删除此RS以及它管理的Pod
# 在kubernetes删除RS前,会将RS的replicasclear调整为0,等待所有的Pod被删除后,在执行RS对象的删除
[root@k8s-m-01 ~]# kubectl delete rs pc-replicaset -n dev
replicaset.apps "pc-replicaset" deleted
[root@k8s-m-01 ~]# kubectl get pod -n dev -o wide
No resources found in dev namespace.
# 2、如果希望仅仅删除RS对象(保留Pod),可以使用kubectl delete命令时添加--cascade=false选项(不推荐)。
[root@k8s-m-01 ~]# kubectl delete rs pc-replicaset -n dev --cascade=false
replicaset.apps "pc-replicaset" deleted
[root@k8s-m-01 ~]# kubectl get pods -n dev
NAME READY STATUS RESTARTS AGE
pc-replicaset-cl82j 1/1 Running 0 75s
pc-replicaset-dslhb 1/1 Running 0 75s
# 3、也可以使用yaml直接删除(推荐)
[root@k8s-m-01 ~]# kubectl delete -f pc-replicaset.yaml
replicaset.apps "pc-replicaset" deleted
1、
deployment是通过标签去管理pod的
2、deployment控制器会无限接近理想状态
# 1、Deployment:一般用来部署长期运行的、无状态的应用
特点:集群之中,随机部署(每一次请求都不依赖历史数据,也无数据持久化需求)
精确匹配: # matchLabels
模糊匹配: # matchExpressions
为了更好的解决服务编排的问题,kubernetes在V1.2版本开始,引入了Deployment控制器
。值得一提的是,这种控制器并不直接管理pod
,而是通过管理ReplicaSet来简介管理Pod
,即:Deployment管理ReplicaSet,ReplicaSet管理Pod
。所以Deployment比ReplicaSet功能更加强大。
Deployment主要功能有下面几个:
Deployment的资源清单文件:
apiVersion: apps/v1 # 版本号
kind: Deployment # 类型
metadata: # 元数据
name: # rs名称
namespace: # 所属命名空间
labels: #标签
controller: deploy
spec: # 详情描述
replicas: 3 # 副本数量
revisionHistoryLimit: 3 # 保留历史版本
paused: false # 暂停部署,默认是false
progressDeadlineSeconds: 600 # 部署超时时间(s),默认是600
strategy: # 策略
type: RollingUpdate # 滚动更新策略
rollingUpdate: # 滚动更新
maxSurge: 30% # 最大额外可以存在的副本数,可以为百分比,也可以为整数
maxUnavailable: 30% # 最大不可用状态的 Pod 的最大值,可以为百分比,也可以为整数
selector: # 选择器,通过它指定该控制器管理哪些pod
matchLabels: # Labels匹配规则
app: nginx-pod
matchExpressions: # Expressions匹配规则
- {key: app, operator: In, values: [nginx-pod]}
template: # 模板,当副本数量不足时,会根据下面的模板创建pod副本
metadata:
labels:
app: nginx-pod
spec:
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
创建pc-deployment.yaml,内容如下:
apiVersion: apps/v1
kind: Deployment
metadata:
name: pc-deployment
namespace: dev
spec:
replicas: 3
selector:
matchLabels:
app: nginx-pod
template:
metadata:
labels:
app: nginx-pod
spec:
containers:
- name: nginx
image: nginx
# 1、创建deployment
[root@k8s-m-01 ~]# kubectl create -f pc-deployment.yaml --record=true
deployment.apps/pc-deployment created
# 2、查看deployment
# UP-TO-DATE 最新版本的pod的数量
# AVAILABLE 当前可用的pod的数量
[root@k8s-m-01 ~]# kubectl get deploy pc-deployment -n dev
NAME READY UP-TO-DATE AVAILABLE AGE
pc-deployment 3/3 3 3 15s
# 3、查看rs
# 发现rs的名称是在原来deployment的名字后面添加了一个10位数的随机串
[root@k8s-m-01 ~]# kubectl get rs -n dev
NAME DESIRED CURRENT READY AGE
pc-deployment-6696798b78 3 3 3 23s
# 4、查看pod
[root@k8s-m-01 ~]# kubectl get pods -n dev
NAME READY STATUS RESTARTS AGE
pc-deployment-6696798b78-d2c8n 1/1 Running 0 107s
pc-deployment-6696798b78-smpvp 1/1 Running 0 107s
pc-deployment-6696798b78-wvjd8 1/1 Running 0 107s
# 1、变更副本数量为5个
[root@k8s-m-01 ~]# kubectl scale deploy pc-deployment --replicas=5 -n dev
deployment.apps/pc-deployment scaled
# 2、查看deployment
[root@k8s-m-01 ~]# kubectl get deploy pc-deployment -n dev
NAME READY UP-TO-DATE AVAILABLE AGE
pc-deployment 5/5 5 5 2m
# 3、查看pod
[root@k8s-m-01 ~]# kubectl get pods -n dev
NAME READY STATUS RESTARTS AGE
pc-deployment-6696798b78-d2c8n 1/1 Running 0 4m19s
pc-deployment-6696798b78-jxmdq 1/1 Running 0 94s
pc-deployment-6696798b78-mktqv 1/1 Running 0 93s
pc-deployment-6696798b78-smpvp 1/1 Running 0 4m19s
pc-deployment-6696798b78-wvjd8 1/1 Running 0 4m19s
# 4、编辑deployment的副本数量,修改spec:replicas: 4即可
[root@k8s-m-01 ~]# kubectl edit deploy pc-deployment -n dev
deployment.apps/pc-deployment edited
# 5、查看pod
[root@k8s-m-01 ~]# kubectl get pods -n dev
NAME READY STATUS RESTARTS AGE
pc-deployment-6696798b78-d2c8n 1/1 Running 0 5m23s
pc-deployment-6696798b78-jxmdq 1/1 Running 0 2m38s
pc-deployment-6696798b78-smpvp 1/1 Running 0 5m23s
pc-deployment-6696798b78-wvjd8 1/1 Running 0 5m23s
deployment支持两种更新策略:重建更新和滚动更新,
可以通过strategy
指定策略类型,支持两个属性:
`strategy`:指定新的Pod替换旧的Pod的策略, 支持两个属性:
` type`:指定策略类型,支持两种策略
` Recreate`:在创建出新的Pod之前会先杀掉所有已存在的Pod
`RollingUpdate`:滚动更新,就是杀死一部分,就启动一部分,在更新过程中,存在两个版本Pod
` rollingUpdate`:当type为RollingUpdate时生效,用于为RollingUpdate设置参数,支持两个属性:
` maxUnavailable`:用来指定在升级过程中不可用Pod的最大数量,默认为25%。
` maxSurge`: 用来指定在升级过程中可以超过期望的Pod的最大数量,默认为25%。
编辑pc-deployment.yaml,在spec节点下添加更新策略
spec:
strategy: # 策略
type: Recreate # 重建更新
# 1、变更镜像
[root@k8s-m-01 ~]# kubectl set image deployment pc-deployment nginx=nginx:1.17.2 -n dev
deployment.apps/pc-deployment image updated
# 2、观察升级过程
[root@k8s-m-01 ~]# kubectl get pods -n dev -w
NAME READY STATUS RESTARTS AGE
pc-deployment-5d89bdfbf9-65qcw 1/1 Running 0 31s
pc-deployment-5d89bdfbf9-w5nzv 1/1 Running 0 31s
pc-deployment-5d89bdfbf9-xpt7w 1/1 Running 0 31s
pc-deployment-5d89bdfbf9-xpt7w 1/1 Terminating 0 41s
pc-deployment-5d89bdfbf9-65qcw 1/1 Terminating 0 41s
pc-deployment-5d89bdfbf9-w5nzv 1/1 Terminating 0 41s
pc-deployment-675d469f8b-grn8z 0/1 Pending 0 0s
pc-deployment-675d469f8b-hbl4v 0/1 Pending 0 0s
pc-deployment-675d469f8b-67nz2 0/1 Pending 0 0s
编辑pc-deployment.yaml,在spec节点下添加更新策略
spec:
strategy: # 策略
type: RollingUpdate # 滚动更新策略
rollingUpdate:
maxSurge: 25%
maxUnavailable: 25%
# 1、变更镜像
[root@k8s-m-01 ~]# kubectl set image deployment pc-deployment nginx=nginx:1.17.3 -n dev
deployment.apps/pc-deployment image updated
# 2、观察升级过程
[root@k8s-m-01 ~]# kubectl get pods -n dev -w
NAME READY STATUS RESTARTS AGE
pc-deployment-c848d767-8rbzt 1/1 Running 0 31m
pc-deployment-c848d767-h4p68 1/1 Running 0 31m
pc-deployment-c848d767-hlmz4 1/1 Running 0 31m
pc-deployment-c848d767-rrqcn 1/1 Running 0 31m
# 至此,新版本的pod创建完毕,就版本的pod销毁完毕
# 中间过程是滚动进行的,也就是边销毁边创建
# 查看rs,发现原来的rs的依旧存在,只是pod数量变为了0,而后又新产生了一个rs,pod数量为4
# 其实这就是deployment能够进行版本回退的奥妙所在,后面会详细解释
[root@k8s-m-01 ~]# kubectl get rs -n dev
NAME DESIRED CURRENT READY AGE
pc-deployment-6696798b78 0 0 0 7m37s
pc-deployment-6696798b11 0 0 0 5m37s
pc-deployment-c848d76789 4 4 4 72s
deployment
支持版本升级过程中的暂停、继续功能以及版本回退等诸多功能,下面具体来看.
kubectl rollout
: 版本升级相关功能,支持下面的选项:
status
显示当前升级状态
history
显示 升级历史记录
pause
暂停版本升级过程
resume
继续已经暂停的版本升级过程
restart
重启版本升级过程
undo
回滚到上一级版本(可以使用–to-revision回滚到指定版本)
# 1、查看当前升级版本的状态
[root@k8s-m-01 ~]# kubectl rollout status deploy pc-deployment -n dev
deployment "pc-deployment" successfully rolled out
# 2、查看升级历史记录
[root@k8s-m-01 ~]# kubectl rollout history deploy pc-deployment -n dev
deployment.apps/pc-deployment
REVISION CHANGE-CAUSE
1 kubectl create --filename=pc-deployment.yaml --record=true
2 kubectl create --filename=pc-deployment.yaml --record=true
3 kubectl create --filename=pc-deployment.yaml --record=true
# 可以发现有三次版本记录,说明完成过两次升级
# 3、版本回滚
# 这里直接使用--to-revision=1回滚到了1版本, 如果省略这个选项,就是回退到上个版本,就是2版本
[root@k8s-m-01 ~]# kubectl rollout undo deployment pc-deployment --to-revision=1 -n dev
deployment.apps/pc-deployment rolled back
# 4、查看发现,通过nginx镜像版本可以发现到了第一版
[root@k8s-m-01 ~]# kubectl get deploy -n dev -o wide
NAME READY UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES
pc-deployment 4/4 4 4 74m nginx nginx
# 查看rs,发现第一个rs中有4个pod运行,后面两个版本的rs中pod为运行
# 其实deployment之所以可是实现版本的回滚,就是通过记录下历史rs来实现的,
# 一旦想回滚到哪个版本,只需要将当前版本pod数量降为0,然后将回滚版本的pod提升为目标数量就可以了
[root@k8s-m-01 ~]# kubectl get rs -n dev
NAME DESIRED CURRENT READY AGE
pc-deployment-6696798b78 4 4 4 78m
pc-deployment-966bf7f44 0 0 0 37m
pc-deployment-c848d767 0 0 0 71m
Deployment控制器支持控制更新过程中的控制,如“暂停(pause)”或“继续(resume)”更新操作。
比如有一批新的Pod资源创建完成后立即暂停更新过程,此时,仅存在一部分新版本的应用,主体部分还是旧的版本。然后,再筛选一小部分的用户请求路由到新版本的Pod应用,继续观察能否稳定地按期望的方式运行。确定没问题之后再继续完成余下的Pod资源滚动更新,否则立即回滚更新操作。这就是所谓的金丝雀发布。
# 1、更新deployment的版本,并配置暂停deployment
[root@k8s-m-01 ~]# kubectl set image deploy pc-deployment nginx=nginx:1.17.4 -n dev && kubectl rollout pause deployment pc-deployment -n dev
deployment.apps/pc-deployment image updated
deployment.apps/pc-deployment paused
# 2、观察更新状态
[root@k8s-m-01 ~]# kubectl rollout status deploy pc-deployment -n dev
Waiting for deployment "pc-deployment" rollout to finish: 2 out of 4 new replicas have been updated...
# 监控更新的过程,可以看到已经新增了一个资源,但是并未按照预期的状态去删除一个旧的资源,就是因为使用了pause暂停命令
[root@k8s-m-01 ~]# kubectl get rs -n dev -o wide
NAME DESIRED CURRENT READY AGE CONTAINERS IMAGES
pc-deployment-5d89bdfbf9 3 3 3 19m nginx nginx
pc-deployment-675d469f8b 0 0 0 14m nginx nginx:1.17.2
pc-deployment-6c9f56fcfb 2 2 2 3m16s nginx nginx:1.17.4
[root@k8s-m-01 ~]# kubectl get pods -n dev
NAME READY STATUS RESTARTS AGE
pc-deployment-5d89bdfbf9-rj8sq 1/1 Running 0 7m33s
pc-deployment-5d89bdfbf9-ttwgg 1/1 Running 0 7m35s
pc-deployment-5d89bdfbf9-v4wvc 1/1 Running 0 7m34s
pc-deployment-6c9f56fcfb-996rt 1/1 Running 0 3m31s
pc-deployment-6c9f56fcfb-j2gtj 1/1 Running 0 3m31s
# 3、确保更新的pod没问题了,继续更新
[root@k8s-m-01 ~]# kubectl rollout resume deploy pc-deployment -n dev
deployment.apps/pc-deployment resumed
# 4、查看最后的更新情况
[root@k8s-m-01 ~]# kubectl get rs -n dev -o wide
NAME DESIRED CURRENT READY AGE CONTAINERS IMAGES
pc-deployment-5d89bdfbf9 0 0 0 21m nginx nginx
pc-deployment-675d469f8b 0 0 0 16m nginx nginx:1.17.2
pc-deployment-6c9f56fcfb 4 4 4 5m11s nginx nginx:1.17.4
[root@k8s-m-01 ~]# kubectl get pods -n dev
NAME READY STATUS RESTARTS AGE
pc-deployment-6c9f56fcfb-7bfwh 1/1 Running 0 37s
pc-deployment-6c9f56fcfb-996rt 1/1 Running 0 5m27s
pc-deployment-6c9f56fcfb-j2gtj 1/1 Running 0 5m27s
pc-deployment-6c9f56fcfb-rf84v 1/1 Running 0 37s
# 删除deployment,其下的rs和pod也将被删除
[root@k8s-m-01 ~]# kubectl delete -f pc-deployment.yaml
deployment.apps "pc-deployment" deleted
在前面的课程中,我们已经可以实现通过手工执行`kubectl scale`命令实现Pod扩容或缩容,但是这显然不符合Kubernetes的定位目标--自动化、智能化。 Kubernetes期望可以实现通过监测Pod的使用情况,实现pod数量的自动调整,于是就产生了Horizontal Pod Autoscaler(HPA)这种控制器。
HPA可以获取每个Pod利用率,然后和HPA中定义的指标进行对比,同时计算出需要伸缩的具体值,最后实现Pod的数量的调整。其实HPA与之前的Deployment一样,也属于一种Kubernetes资源对象,它通过追踪分析RC控制的所有目标Pod的负载变化情况,来确定是否需要针对性地调整目标Pod的副本数,这是HPA的实现原理。
metrics-server可以用来收集集群中的资源使用情况
# 1、安装git
[root@k8s-m-01 ~]# yum install git -y
# 2、获取metrics-server, 注意使用的版本
[root@k8s-m-01 ~]# git clone -b v0.3.6 https://github.com/kubernetes-incubator/metrics-server
# 修改deployment, 注意修改的是镜像和初始化参数
[root@k8s-m-01 ~]# cd /root/metrics-server/deploy/1.8+/
[root@master 1.8+]# vim metrics-server-deployment.yaml
按图中添加下面选项
hostNetwork: true
image: registry.cn-hangzhou.aliyuncs.com/google_containers/metrics-server-amd64:v0.3.6
args:
- --kubelet-insecure-tls
- --kubelet-preferred-address-types=InternalIP,Hostname,InternalDNS,ExternalDNS,ExternalIP
# 1、安装metrics-server
[root@master 1.8+]# kubectl apply -f ./
# 2、查看pod运行情况
[root@master 1.8+]# kubectl get pod -n kube-system
metrics-server-6b976979db-2xwbj 1/1 Running 0 90s
# 3、使用kubectl top node 查看资源使用情况
[root@master 1.8+]# kubectl top node
NAME CPU(cores) CPU% MEMORY(bytes) MEMORY%
master 98m 4% 1067Mi 62%
k8s-n-01 27m 1% 727Mi 42%
k8s-n-02 34m 1% 800Mi 46%
[root@master 1.8+]# kubectl top pod -n kube-system
NAME CPU(cores) MEMORY(bytes)
coredns-6955765f44-7ptsb 3m 9Mi
coredns-6955765f44-vcwr5 3m 8Mi
etcd-master 14m 145Mi
...
# 至此,metrics-server安装完成
为了操作简单,直接使用命令
# 1、创建deployment
[root@master 1.8+]# kubectl run nginx --image=nginx:latest --requests=cpu=100m -n dev
# 2、创建service
[root@master 1.8+]# kubectl expose deployment nginx --type=NodePort --port=80 -n dev
# 3、查看
[root@master 1.8+]# kubectl get deployment,pod,svc -n dev
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/nginx 1/1 1 1 47s
NAME READY STATUS RESTARTS AGE
pod/nginx-7df9756ccc-bh8dr 1/1 Running 0 47s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/nginx NodePort 10.109.57.248 <none> 80:31136/TCP 35s
创建pc-hpa.yaml
apiVersion: autoscaling/v1
kind: HorizontalPodAutoscaler
metadata:
name: pc-hpa
namespace: dev
spec:
minReplicas: 1 #最小pod数量
maxReplicas: 10 #最大pod数量
targetCPUUtilizationPercentage: 3 # CPU使用率指标
scaleTargetRef: # 指定要控制的nginx信息
apiVersion: apps/v1
kind: Deployment
name: nginx
# 1、创建hpa
[root@master 1.8+]# kubectl create -f pc-hpa.yaml
horizontalpodautoscaler.autoscaling/pc-hpa created
# 2、查看hpa
[root@master 1.8+]# kubectl get hpa -n dev
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
pc-hpa Deployment/nginx 0%/3% 1 10 1 62s
使用压测工具对service地址192.168.109.100:31136
进行压测,然后通过控制台查看hpa和pod的变化
hpa变化
[root@k8s-m-01 ~]# kubectl get hpa -n dev -w
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
pc-hpa Deployment/nginx 0%/3% 1 10 1 4m11s
pc-hpa Deployment/nginx 0%/3% 1 10 1 5m19s
pc-hpa Deployment/nginx 22%/3% 1 10 1 6m50s
pc-hpa Deployment/nginx 22%/3% 1 10 4 7m5s
pc-hpa Deployment/nginx 22%/3% 1 10 8 7m21s
pc-hpa Deployment/nginx 6%/3% 1 10 8 7m51s
pc-hpa Deployment/nginx 0%/3% 1 10 8 9m6s
pc-hpa Deployment/nginx 0%/3% 1 10 8 13m
pc-hpa Deployment/nginx 0%/3% 1 10 1 14m
deployment变化
[root@k8s-m-01 ~]# kubectl get deployment -n dev -w
NAME READY UP-TO-DATE AVAILABLE AGE
nginx 1/1 1 1 11m
nginx 1/4 1 1 13m
nginx 1/4 1 1 13m
nginx 1/4 1 1 13m
nginx 1/4 4 1 13m
nginx 1/8 4 1 14m
nginx 1/8 4 1 14m
nginx 1/8 4 1 14m
nginx 1/8 8 1 14m
nginx 2/8 8 2 14m
nginx 3/8 8 3 14m
nginx 4/8 8 4 14m
nginx 5/8 8 5 14m
nginx 6/8 8 6 14m
nginx 7/8 8 7 14m
nginx 8/8 8 8 15m
nginx 8/1 8 8 20m
nginx 8/1 8 8 20m
nginx 1/1 1 1 20m
pod变化
[root@k8s-m-01 ~]# kubectl get pods -n dev -w
NAME READY STATUS RESTARTS AGE
nginx-7df9756ccc-bh8dr 1/1 Running 0 11m
nginx-7df9756ccc-cpgrv 0/1 Pending 0 0s
nginx-7df9756ccc-8zhwk 0/1 Pending 0 0s
nginx-7df9756ccc-rr9bn 0/1 Pending 0 0s
nginx-7df9756ccc-cpgrv 0/1 ContainerCreating 0 0s
nginx-7df9756ccc-8zhwk 0/1 ContainerCreating 0 0s
nginx-7df9756ccc-rr9bn 0/1 ContainerCreating 0 0s
nginx-7df9756ccc-m9gsj 0/1 Pending 0 0s
nginx-7df9756ccc-g56qb 0/1 Pending 0 0s
nginx-7df9756ccc-sl9c6 0/1 Pending 0 0s
nginx-7df9756ccc-fgst7 0/1 Pending 0 0s
nginx-7df9756ccc-g56qb 0/1 ContainerCreating 0 0s
nginx-7df9756ccc-m9gsj 0/1 ContainerCreating 0 0s
nginx-7df9756ccc-sl9c6 0/1 ContainerCreating 0 0s
nginx-7df9756ccc-fgst7 0/1 ContainerCreating 0 0s
nginx-7df9756ccc-8zhwk 1/1 Running 0 19s
nginx-7df9756ccc-rr9bn 1/1 Running 0 30s
nginx-7df9756ccc-m9gsj 1/1 Running 0 21s
nginx-7df9756ccc-cpgrv 1/1 Running 0 47s
nginx-7df9756ccc-sl9c6 1/1 Running 0 33s
nginx-7df9756ccc-g56qb 1/1 Running 0 48s
nginx-7df9756ccc-fgst7 1/1 Running 0 66s
nginx-7df9756ccc-fgst7 1/1 Terminating 0 6m50s
nginx-7df9756ccc-8zhwk 1/1 Terminating 0 7m5s
nginx-7df9756ccc-cpgrv 1/1 Terminating 0 7m5s
nginx-7df9756ccc-g56qb 1/1 Terminating 0 6m50s
nginx-7df9756ccc-rr9bn 1/1 Terminating 0 7m5s
nginx-7df9756ccc-m9gsj 1/1 Terminating 0 6m50s
nginx-7df9756ccc-sl9c6 1/1 Terminating 0 6m50s
# DaemonSet:每一个节点上部署一个Pod,删除节点自动删除对应的POD(zabbix-agent)
特点:每一台上有且只有一台
DaemonSet类型的控制器可以保证在集群中的每一台(或指定)节点上都运行一个副本。一般适用于日志收集、节点监控等场景。也就是说,如果一个Pod提供的功能是节点级别的(每个节点都需要且只需要一个),那么这类Pod就适合使用DaemonSet类型的控制器创建。
下面先来看下DaemonSet的资源清单文件
apiVersion: apps/v1 # 版本号
kind: DaemonSet # 类型
metadata: # 元数据
name: # rs名称
namespace: # 所属命名空间
labels: #标签
controller: daemonset
spec: # 详情描述
revisionHistoryLimit: 3 # 保留历史版本
updateStrategy: # 更新策略
type: RollingUpdate # 滚动更新策略
rollingUpdate: # 滚动更新
maxUnavailable: 1 # 最大不可用状态的 Pod 的最大值,可以为百分比,也可以为整数
selector: # 选择器,通过它指定该控制器管理哪些pod
matchLabels: # Labels匹配规则
app: nginx-pod
matchExpressions: # Expressions匹配规则
- {key: app, operator: In, values: [nginx-pod]}
template: # 模板,当副本数量不足时,会根据下面的模板创建pod副本
metadata:
labels:
app: nginx-pod
spec:
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
创建pc-daemonset.yaml,内容如下:
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: pc-daemonset
namespace: dev
spec:
selector:
matchLabels:
app: nginx-pod
template:
metadata:
labels:
app: nginx-pod
spec:
containers:
- name: nginx
image: nginx
# 1、创建daemonset
[root@k8s-m-01 ~]# kubectl create -f pc-daemonset.yaml
daemonset.apps/pc-daemonset created
# 2、查看daemonset
[root@k8s-m-01 ~]# kubectl get ds -n dev -o wide
NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES
pc-daemonset 2 2 2 2 2 24s nginx nginx
# 3、查看pod,发现在每个Node上都运行一个pod
[root@k8s-m-01 ~]# kubectl get pods -n dev -o wide
NAME READY STATUS RESTARTS AGE IP NODE
pc-daemonset-9bck8 1/1 Running 0 37s 10.244.1.43 k8s-n-01
pc-daemonset-k224w 1/1 Running 0 37s 10.244.2.74 k8s-n-02
# 4、删除daemonset
[root@k8s-m-01 ~]# kubectl delete -f pc-daemonset.yaml
daemonset.apps "pc-daemonset" deleted
# 5、更新
[root@k8s-m-01 k8s]# kubectl edit daemonsets zabbix-agent
- image: zabbix/zabbix-agent:5.2.4-centos
zabbix版本是5.2.4
# 6、回滚
[root@k8s-m-01 k8s]# kubectl rollout undo daemonset zabbix-agent
daemonset.apps/zabbix-agent rolled back
# 回滚到指定版本
[root@k8s-m-01 k8s]# kubectl rollout history daemonset zabbix-agent
daemonset.apps/zabbix-agent
REVISION CHANGE-CAUSE
1 <none>
2 <none>
[root@k8s-m-01 k8s]# kubectl rollout undo daemonset zabbix-agent --to-revision=1
# 7、扩展 (删除集群,重新添加)
[root@k8s-m-01 k8s]# kubectl delete nodes k8s-n-01 # 主节点删除n2从节点
[root@k8s-n-01 ~]# kubeadm reset
[root@k8s-n-01 ~]# rm -rf /etc/kubernetes/*
[root@k8s-m-01 ~]# kubeadm token create --print-join-command # 主节点
从节点拿着token直接执行一下,就加入集群了
# 不支持弹性扩容,但是支持资源更新
1、创建一个POD ---> 去执行指定的命令
2、如果运行成功,则状态变成:Completed
3、如果运行失败,则状态变成:Error
job,主要用于负责**批量处理(一次要处理指定数量任务)短暂的一次性(每个任务仅运行一次就结束)**任务。Job特点如下:
apiVersion: batch/v1 # 版本号
kind: Job # 类型
metadata: # 元数据
name: # rs名称
namespace: # 所属命名空间
labels: #标签
controller: job
spec: # 详情描述
completions: 1 # 指定job需要成功运行Pods的次数。默认值: 1
parallelism: 1 # 指定job在任一时刻应该并发运行Pods的数量。默认值: 1
activeDeadlineSeconds: 30 # 指定job可运行的时间期限,超过时间还未结束,系统将会尝试进行终止。
backoffLimit: 6 # 指定job失败后进行重试的次数。默认是6
manualSelector: true # 是否可以使用selector选择器选择pod,默认是false
selector: # 选择器,通过它指定该控制器管理哪些pod
matchLabels: # Labels匹配规则
app: counter-pod
matchExpressions: # Expressions匹配规则
- {key: app, operator: In, values: [counter-pod]}
template: # 模板,当副本数量不足时,会根据下面的模板创建pod副本
metadata:
labels:
app: counter-pod
spec:
restartPolicy: Never # 重启策略只能设置为Never或者OnFailure
containers:
- name: counter
image: busybox:1.30
command: ["bin/sh","-c","for i in 9 8 7 6 5 4 3 2 1; do echo $i;sleep 2;done"]
关于重启策略设置的说明:
如果指定为OnFailure,则job会在pod出现故障时重启容器,而不是创建pod,failed次数不变
如果指定为Never,则job会在pod出现故障时创建新的pod,并且故障pod不会消失,也不会重启,failed次数加1
如果指定为Always的话,就意味着一直重启,意味着job任务会重复去执行了,当然不对,所以不能设置为Always
创建pc-job.yaml,内容如下:
apiVersion: batch/v1
kind: Job
metadata:
name: pc-job
namespace: dev
spec:
manualSelector: true
selector:
matchLabels:
app: counter-pod
template:
metadata:
labels:
app: counter-pod
spec:
restartPolicy: Never
containers:
- name: counter
image: busybox:1.30
command: ["bin/sh","-c","for i in 9 8 7 6 5 4 3 2 1; do echo $i;sleep 3;done"]
# 1、创建job
[root@k8s-m-01 ~]# kubectl create -f pc-job.yaml
job.batch/pc-job created
# 2、查看job
[root@k8s-m-01 ~]# kubectl get job -n dev -o wide -w
NAME COMPLETIONS DURATION AGE CONTAINERS IMAGES SELECTOR
pc-job 0/1 21s 21s counter busybox:1.30 app=counter-pod
pc-job 1/1 31s 79s counter busybox:1.30 app=counter-pod
# 3、通过观察pod状态可以看到,pod在运行完毕任务后,就会变成Completed状态
[root@k8s-m-01 ~]# kubectl get pods -n dev -w
NAME READY STATUS RESTARTS AGE
pc-job-rxg96 1/1 Running 0 29s
pc-job-rxg96 0/1 Completed 0 33s
# 接下来,调整下pod运行的总数量和并行数量 即:在spec下设置下面两个选项
# completions: 6 # 指定job需要成功运行Pods的次数为6
# parallelism: 3 # 指定job并发运行Pods的数量为3
# 然后重新运行job,观察效果,此时会发现,job会每次运行3个pod,总共执行了6个pod
[root@k8s-m-01 ~]# kubectl get pods -n dev -w
NAME READY STATUS RESTARTS AGE
pc-job-684ft 1/1 Running 0 5s
pc-job-jhj49 1/1 Running 0 5s
pc-job-pfcvh 1/1 Running 0 5s
pc-job-684ft 0/1 Completed 0 11s
pc-job-v7rhr 0/1 Pending 0 0s
pc-job-v7rhr 0/1 Pending 0 0s
pc-job-v7rhr 0/1 ContainerCreating 0 0s
pc-job-jhj49 0/1 Completed 0 11s
pc-job-5vg2j 0/1 Completed 0 12s
# 删除job
[root@k8s-m-01 ~]# kubectl delete -f pc-job.yaml
job.batch "pc-job" deleted
CronJob控制器以Job控制器资源为其管控对象,并借助它管理pod资源对象,Job控制器定义的作业任务在其控制器资源创建之后便会立即执行,但CronJob可以以类似于Linux操作系统的周期性任务作业计划的方式控制其运行时间点及重复运行的方式。也就是说,CronJob可以在特定的时间点(反复的)去运行job任务。
apiVersion: batch/v1beta1 # 版本号
kind: CronJob # 类型
metadata: # 元数据
name: # rs名称
namespace: # 所属命名空间
labels: #标签
controller: cronjob
spec: # 详情描述
schedule: # cron格式的作业调度运行时间点,用于控制任务在什么时间执行
concurrencyPolicy: # 并发执行策略,用于定义前一次作业运行尚未完成时是否以及如何运行后一次的作业
failedJobHistoryLimit: # 为失败的任务执行保留的历史记录数,默认为1
successfulJobHistoryLimit: # 为成功的任务执行保留的历史记录数,默认为3
startingDeadlineSeconds: # 启动作业错误的超时时长
jobTemplate: # job控制器模板,用于为cronjob控制器生成job对象;下面其实就是job的定义
metadata:
spec:
completions: 1
parallelism: 1
activeDeadlineSeconds: 30
backoffLimit: 6
manualSelector: true
selector:
matchLabels:
app: counter-pod
matchExpressions: 规则
- {key: app, operator: In, values: [counter-pod]}
template:
metadata:
labels:
app: counter-pod
spec:
restartPolicy: Never
containers:
- name: counter
image: busybox:1.30
command: ["bin/sh","-c","for i in 9 8 7 6 5 4 3 2 1; do echo $i;sleep 20;done"]
# schedule: cron表达式,用于指定任务的执行时间
*/1 * * * *
<分钟> <小时> <日> <月份> <星期>
分钟 值从 0 到 59.
小时 值从 0 到 23.
日 值从 1 到 31.
月 值从 1 到 12.
星期 值从 0 到 6, 0 代表星期日
多个时间可以用逗号隔开; 范围可以用连字符给出;*可以作为通配符; /表示每...
# concurrencyPolicy:
Allow: 允许Jobs并发运行(默认)
Forbid: 禁止并发运行,如果上一次运行尚未完成,则跳过下一次运行
Replace: 替换,取消当前正在运行的作业并用新作业替换它
apiVersion: batch/v1beta1
kind: CronJob
metadata:
name: pc-cronjob
namespace: dev
labels:
controller: cronjob
spec:
schedule: "*/1 * * * *"
jobTemplate:
metadata:
spec:
template:
spec:
restartPolicy: Never
containers:
- name: counter
image: busybox:1.30
command: ["bin/sh","-c","for i in 9 8 7 6 5 4 3 2 1; do echo $i;sleep 3;done"]
# 1、创建cronjob
[root@k8s-m-01 ~]# kubectl create -f pc-cronjob.yaml
cronjob.batch/pc-cronjob created
# 2、查看cronjob
[root@k8s-m-01 ~]# kubectl get cronjobs -n dev
NAME SCHEDULE SUSPEND ACTIVE LAST SCHEDULE AGE
pc-cronjob */1 * * * * False 0 <none> 6s
# 3、查看job
[root@k8s-m-01 ~]# kubectl get jobs -n dev
NAME COMPLETIONS DURATION AGE
pc-cronjob-1592587800 1/1 28s 3m26s
pc-cronjob-1592587860 1/1 28s 2m26s
pc-cronjob-1592587920 1/1 28s 86s
# 4、查看pod
[root@k8s-m-01 ~]# kubectl get pods -n dev
pc-cronjob-1592587800-x4tsm 0/1 Completed 0 2m24s
pc-cronjob-1592587860-r5gv4 0/1 Completed 0 84s
pc-cronjob-1592587920-9dxxq 1/1 Running 0 24s
# 5、删除cronjob
[root@k8s-m-01 ~]# kubectl delete -f pc-cronjob.yaml
cronjob.batch "pc-cronjob" deleted
job管理的Pod的重启策略只能够有OnFailure(错误情况下重启),Never(无论什么情况下都不重启),不能够有Always(无论什么情况下都重启)
job管理的Pod的重启策略只能够有OnFailure(错误情况下重启),Never(无论什么情况下都不重启),不能够有Always(无论什么情况下都重启)