user containerN user imageN ...... user contaner1 user image1 Pause gcr.io/google_containers/pause-amd64
每个Pod中都可以包含一个或者多个容器,这些容器可以分为两类:
- 用户程序所在的容器,数量可多可少
- Pause容器,这是每个Pod都会有一个根容器,它的作用有两个 : 1.可以以它为依据,评估整个Pod的健康状态。2.可以在根容器上设置IP地址,其他容器共享此IP,实现pod内部的网络通信
这里是Pod的内部通信,Pod之间的通信采用虚拟二层网络技术来实现,当前环境使用的是flanne
Pod的定义
以下是Pod的资源清单,也就是yml配置
apiVersion: v1 #必选,版本号 kind: Pod #必选,资源类型,例如Pod,service,deployment metadata: #必选,元数据 name: string #必选,Pod名称 namespace: string #Pod所在的名称空间,默认为“default” labels: #自定义标签 - name: string spec: #必选,Pod中容器的详细定义 containers: #必选,Pod中容器列表 - name: string #必选,容器名称 image: #必选,容器镜像名称 imagePillPolicy: [Always|Never|IfNotPresent] #获取镜像策略 command: [string] #启动容器的命令参数列表,如不指定,使用打包时使用的启动命令 args: [string] #容器启动的参数列表 workingDir: string #容器的工作目录 volumeMounts: #挂载到容器内部的存储卷配置 - name: string #引用pod定义的共享存储卷民初,需要使用volumes[]部分定义的卷名 mountPath: string #存储卷在容器mount的绝对路径 readOnly: boolean #是否为只读模式 ports: #需要暴露的端口库号列表 - name: string #端口的名称 containerPort: int #容器需要监听的端口号 hostPort: int #容器所在主机需要监听的端口号,默认于Container相同 protocol: string #端口协议默认TCP env: # 容器运行前设置环境变量列表 - name: staring # 环境变量名称 value: 环境变量值 resources: #资源现在和请求的设置 limits: #资源限制的设置 cpu: string #cpu限制,单位为core数,将用于docker run --cpu-share参数 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: int host: string scheme: string HttpHeaders: - name: string value: string tcpSocket: #对Pod容器健康检查方式这种问tcpSocket方式 port: number initialDelaySecondes: 0 #容器启动完成后首次探测的时间,单位为秒 timeoutSeconds: 0 #对容器健康检查探测等待响应的超时时间,单位秒,默认1秒 periodSeconds: 0 #对容器监控检查的定期探测时间设置,单位秒,默认10秒一次 successThreshold:0 failuerThreshold:0 securityContext: privileged: false restarPolicy: [Always|Never|OnFailure] #Pod的重启策略 nodeName: <string> #设置NodeName表示将该Pod调度到指定名称的node节点上 nodeSeletor: obeject #设置NodeSeletor表示将该Pod调度到包含这个label的node上 imagePullSecrets:#Pull镜像时使用的Secret名称,以Key:secretkey格式指定 - name: string hostNetwork: false #是否使用主机网络模式,默认false voulmes: #在该Pod上定义共享存储卷列表 - name: string #共享存储卷名称(volumes类型有很多种) emptyDir: {} #类型为emtDir的存储卷,与Pod同生命周期的一个临时目录。为空值 hostPath: string #类型为HostPath的存储卷,表示挂载Pod所在的宿主机的目录 path: string #pod所在的宿主机的目录,将被用于同期种mount的目录 secret: #类型为secret的存储卷,挂载集群与定义的secret对象到容器内部 secretname: string itmes: - key: string path: string configMap: #类型为configMap的存储卷,挂载预定义的configMap对象到容器 name:string items: - key: string path: string
可以使用以下命令查询每种资源的配置方式
# kubectl explain 资源类型 # kubectl explain 资源类型.属性
Pod配置
创建一个pod-base.yml文件,内容如下
apiVersion: v1 kind: Pod metadata: name: pod-base namespace: dev labels: version: test spec: containers: - name: nginx image: nginx:1.17.2 - name: busybox image: busybox:1.30
上面定义了一个比较简单的Pod的配置,里面有两个容器:
- nginx: 用1.17.2版本的nginx镜像创建
- busybox: 用1.30版本的busybox镜像创建
#创建Pod kubectl apply -f pod-bose.yml #查看Pod状态 kubectl get pod -n dev NAME READY STATUS RESTARTS AGE nginx-64777cd554-7p7xt 1/1 Running 2 31h nginx-64777cd554-cqbjd 1/1 Running 1 25h nginx-64777cd554-tv5g2 1/1 Running 2 31h pod-base 1/2 CrashLoopBackOff 5 5m9s #可以通过describe查看内部的详情 #此时已经运行了一个基本的pod,虽然出现了一些问题 [root@master ~]# kubectl describe pod pod-base -n dev ............ Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Scheduled 4m34s default-scheduler Successfully assigned dev/pod-base to node1 Normal Pulling 4m31s kubelet, node1 Pulling image "nginx:1.17.2" Normal Pulled 3m42s kubelet, node1 Successfully pulled image "nginx:1.17.2" Normal Created 3m41s kubelet, node1 Created container nginx Normal Started 3m40s kubelet, node1 Started container nginx Normal Pulling 3m40s kubelet, node1 Pulling image "busybox:1.30" Normal Pulled 3m22s kubelet, node1 Successfully pulled image "busybox:1.30" Normal Created 2m39s (x4 over 3m22s) kubelet, node1 Created container busybox Normal Pulled 2m39s (x3 over 3m20s) kubelet, node1 Container image "busybox:1.30" already present on machine Normal Started 2m38s (x4 over 3m22s) kubelet, node1 Started container busybox Warning BackOff 2m8s (x8 over 3m19s) kubelet, node1 Back-off restarting failed container
镜像拉取
创建pod-imagePullPolicy.yml文件,内容如下
apiVersion: v1 kind: Pod metadata: name: pod-imagepullpolicy namespace: dev spec: containers: - name: nginx image: nginx:1.17.3 imagePullPolicy: Always - name: busybox image: busybox:1.30
imagePullPolicy,用于设置镜像拉取策略,kubernetes中支持配置的三种拉取策略
- Always:总是从远程仓库拉取镜像
- IfNotPresent: 本地有镜像则使用本地,没有则远程拉取
- Never: 只能使用本地镜像,从不去远程拉取
默认值说明:
如果镜像tag为具体版本号,默认策略就是IfNotPersent
如果镜像tag为latest,默认策略时always
#创建Pod kubectl apply -f pod-imagePullPolicy.yml # 查看pod kubectl get pod -n dev # 查看详细信息 kubectl get pod pod-imagepullpolicy -n dev
启动命令
上面的容器案例中,有一个问题没有解决,就是busybox运行一直没有成功,因为busybox并不是一个程序,而是一个类似工具类的集合,kubernetes集群启动管理后,它会自动关闭,解决办法就是让其一直运行,就需要使用到command配置,
vim pod-command.yml apiVersion: v1 kind: Pod metadata: name: pod-command namespace: dev spec: containers: - name: nginx image: nginx:1.17.2 imagePullPolicy: IfNotPresent - 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"] # 创建pod kubectl apply -f pod-command.yml #查看状态,可以看到两个Pod都正常运行了 [root@master ~]# kubectl get pod pod-command -n dev NAME READY STATUS RESTARTS AGE pod-command 2/2 Running 0 85s #进入pod中的busybox容器,查看文件内容 kubectl exec pod-command -n dev --it -c busybox /bin/sh
说明:
通过上面方向command已经可用完成启动命令和传递参数的功能,为什么这里还要通过args选项,用于传递参数?
这其实和docker有点关系,kubernetes中的comand,arges两项其实是实现覆盖DockerfileHon中的ENTRYPOINT的功能。
- 如果command和args均没有写,那么就用Dockerfile的配置。
- 如果command写了,arges没有写,那么Dockerfile默认的配置会被忽略,执行输入的command
- 如果command没写,但args写了,那么Dockerfile中配置的ENTRYPOINT的命令会被执行,使用当前args的参数
- 如果command和args都写了,那么Dockerfile的配置被忽略,执行command并追加上args参数
环境变量
vim pod-env.yml apiVersion: v1 kind: Pod metadata: name: pod-env namespace: dev spec: containers: - name: nginx image: nginx:1.17.2 imagePullPolicy: IfNotPresent - 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"] env: - name: "username" value: "admin" - name: "password" value: "123456"
env,环境变量,用于Pod中容器设置环境变量
# 创建Pod kubectl create -f pod-env.yml #进入容器查看环境变量 [root@master ~]# kubectl exec pod-env -n dev -it -c busybox /bin/sh / # echo $username admin / # echo $password 123456
不推荐使用这种方式,推荐这些配置在单独存储的配置文件中
端口设置
vim pod-ports.yml apiVersion: v1 kind: Pod metadata: name: pod-ports namespace: dev spec: containers: - name: nginx image: nginx:1.17.2 imagePullPolicy: IfNotPresent ports: - name: nginx-port containerPort: 80 protocol: TCP #启动pod kubectl create -f pod-ports.yml # 查看 kubectl get pod pod-ports -n dev
资源配额
容器中的程序要运行坑,而程序的运行肯定要占用一定的资源,如果不对某一个容器限定资源,可能会在某一瞬间吃掉大量的资源,导致其他容器无法运行。针对这种情况,kuberneters提供了对内存和cpu资源进行配额的机制,这个机制主要是在resources选项实现,其有两个子选线。
- limits: 用于限制运行时容器的最大占用资源,当容器超过limits时会被终止,并进行重启
- requests:用于设置容器需要的最小资源,如果环境资源不够,容器将无法启动
可用通过以上两个选项色泽资源的上下限
vim pod-resources.yml apiVersion: v1 kind: Pod metadata: name: pod-resuorces namespace: dev spec: containers: - name: nginx image: nginx:1.17.2 imagePullPolicy: IfNotPresent resources: limits: cpu: "1" memory: "1Gi" requests: cpu: "0.2" memory: "10Mi" # 运行pod kubectl create -f pod-resources.yml # 查看pod kubectl get pod pod-resuorces -n dev
Pod生命周期
我们一般将pod对象从创建至终的这断时间范围称为pod的生命周期,它主要包含下面的过程:
-
Pod创建过程
-
运行初始化容器过程
-
运行主容器过程
容器启动后钩子,容器终止前钩子
容器的存活性探测,就绪性探测
-
pod终止过程
在整个生命周期种Pod会出现5种状态(相位),分别如下;
-
挂起(Pending):apiserver已经创建了Pod资源对象,但它尚未被调度完成或者仍处于镜像下载状态
-
运行中(running):pod已经被调到至某节点,并且所有容器都已经被kubelet创建完成
-
成功(Succeded): pod中的所有容器都已经成功并且不会被重启
-
失败(Failed): 所有容器都已经终止,但至少有一个容器终止失败,即容器返回非0值的退出状态
-
未知(Unkown): apiserver无法正常获取到pod对象的状态信息,通常由网络通信失败导致
初始化容器
初始化容器是在pod的主容器启动前需要运行的容器,主要是做一些主容器的前置工作,它具有两大特征:
1.初始化容器必选运行完成至结束,若某一个初始化容器运行失败,那么kubernetes需要重启直到完成为止。
2.初始化容器必选按照定义的顺序执行,当且仅当前一个成功之后,后面一个才能运行
初始化容器由很多的应用场景,下面列出的是最常见的几个;
-
提供主容器镜像中不具被的工具程序或自定义代码
-
初始化容器要选育应用容器串行启动并运行完成,因此可用于延后应用容器的启动直至其依赖的条件得到满足
示例:
假设要以主容器来运行nginx,但是需要在运行nginx之前先要能够连接上MySQL和redis所在的服务器,为了简化测试,事先规定号MySQL(192.168.248.4)和redis(192.168.248.24)服务器的地址。
创建pod-initcontainer.yml
apiVersion: v1 kind: Pod metadata: name: pod-initcontainer namespace: dev spec: containers: - name: main-container image: nginx:1.17.2 ports: - name: nginx-port containerPort: 80 initContainers: - name: test-mysql image: busybox:1.30 command: ['sh','-c','until ping 192.168.248.4 -c 1;do echo waiting for mysql ... ;sleep 2;done'] - name: test-redis image: busybox:1.30 command: ['sh','-c','until ping 192.168.248.24 -c 1;do echo waiting for redis ... ;sleep 2;done'] # 启动pod kubectl create -f pod-initcontainer.yml #查看状态 [root@master ~]# kubectl get pod pod-initcontainer -n dev NAME READY STATUS RESTARTS AGE pod-initcontainer 0/1 Init:0/2 0 18s #动态查看状态 [root@master ~]# kubectl get pod pod-initcontainer -n dev -w NAME READY STATUS RESTARTS AGE pod-initcontainer 0/1 Init:0/2 0 52s #新开一个窗口,为当前服务器增加两个IP ifconfig ens33:1 192.168.248.4 netmask 255.255.255.0 up ifconfig ens33:1 192.168.248.24 netmask 255.255.255.0 up [root@master ~]# kubectl get pod pod-initcontainer -n dev -w NAME READY STATUS RESTARTS AGE pod-initcontainer 0/1 Init:0/2 0 52s pod-initcontainer 0/1 Init:1/2 0 2m37s pod-initcontainer 0/1 Init:1/2 0 2m38s pod-initcontainer 0/1 PodInitializing 0 2m51s pod-initcontainer 1/1 Running 0 2m52s
钩子函数
钩子函数能够感知自身生命周期中的事件,并在相应的时候到来之运行用户指定的程序代码。
kubeernetes在主容器启动之后和停止之前提供了两个钩子函数:
- post start: 容器创建之后执行,如果失败了会重启容器
- pre stop: 容器终止之前执行,执行完后后容器将成功终止,在其完成之前会删除阻塞容器的操作
钩子处理器支持使用下面三种方式定义动作:
Exec命令: 在容器内执行一次命令
...... lifecycle: postStart: exec: command: - cat - /tmp/healthy ......
TCPSocket: 在放弃容器尝试访问指定的socket
..... lifecycle: postStart: tcpoSocket: port: 8080 .....
HTTPGet:在当前容器中向某个url发起http请求
..... lifecycle: postStart: httpGet: path: / #url地址 post: 80 #端口号 host: 192.168.248.11 #主机地址 scheme: HTTP #支持协议,http或者https ......
下面以exec方式为例,演示钩子函数的使用,创建pod-hook-exec.yml文件
apiVersion: v1 kind: Pod metadata: name: pod-hook-exec namespace: dev spec: containers: - name: main-container image: nginx:1.17.2 ports: - name: nginx-pod containerPort: 80 lifecycle: postStart: exec: command: ["/bin/sh","-c","echo postStart... > /usr/share/nginx/html/index.html"] preStop: exec: command: ["/usr/sbin/nginx","-s","quit"] # 创建pod kubectl create -f pod-hook-exec.yml # 查看pod [root@master ~]# kubectl get pod pod-hook-exec -n dev -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES pod-hook-exec 1/1 Running 0 57s 10.244.1.43 node1 <none> <none> # 访问测试 [root@master ~]# curl 10.244.1.43 postStart...
容器探测
容器探测用于检测容器中的应用示例是否正常工作,是保证业务可用性的一种传统机制。如果经过探测,示例的状态不符合预期,那块kubernetes就会把该问题实例"摘除",不承担业务流量。kubernetes提供了两种探针来实现容器探测,分别是:
-
liveness probes:存活性探针,用于检测应用实例当前是否处于正常运行状态,如果不是,ks会重启容器
-
rediness probes: 就绪性探针,用于检测应用实例当前是否可用接受到请求,如果不能,k8s不会转发流量
上面两种探针目前均支持三种探测方式:
Exec命令:在容器内执行一次命令,如果命令执行的退出吗为0,则程序认为正常,否则不正常
livenessProbe: exec: command: - cat - /tmp/healthy
TCPSocket:将会尝试访问一个用户容器的端口,如果能建立连接,则认为正常,否则不正常
livenessProbe: tcpSocket: port: 8080
HTTPGet:调用web应用url,如果返回在200-399,则认为程序正常,否则不正常
lifecycle: postStart: httpGet: path: / #url地址 post: 80 #端口号 host: 192.168.248.11 #主机地址 scheme: HTTP #支持协议,http或者https
下面以liveness probes为例,做几个演示:
创建文件pod-liveness.yml
apiVersion: v1 kind: Pod metadata: name: pod-liveness namespace: dev spec: containers: - name: nginx image: nginx:1.17.2 ports: - name: nginx-port containerPort: 80 livenessProbe: exec: command: ["/bin/cat","/tmp/hello.txt"] #创建pod [root@master ~]# kubectl create -f pod-liveness.yml pod/pod-liveness created #查看pod详情 [root@master ~]# kubectl describe pod pod-liveness -n dev .................... Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Scheduled <unknown> default-scheduler Successfully assigned dev/pod-liveness to node2 Normal Pulled 28s (x2 over 50s) kubelet, node2 Container image "nginx:1.17.2" already present on machine Normal Created 28s (x2 over 50s) kubelet, node2 Created container nginx Normal Started 28s (x2 over 50s) kubelet, node2 Started container nginx Normal Killing 28s kubelet, node2 Container nginx failed liveness probe, will be restarted Warning Unhealthy 8s (x5 over 48s) kubelet, node2 Liveness probe failed: /bin/cat: /tmp/hello.txt: No such file or directory Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Scheduled <unknown> default-scheduler Successfully assigned dev/pod-liveness to node2 Normal Pulled 28s (x2 over 50s) kubelet, node2 Container image "nginx:1.17.2" already present on machine Normal Created 28s (x2 over 50s) kubelet, node2 Created container nginx Normal Started 28s (x2 over 50s) kubelet, node2 Started container nginx Normal Killing 28s kubelet, node2 Container nginx failed liveness probe, will be restarted Warning Unhealthy 8s (x5 over 48s) kubelet, node2 Liveness probe failed: /bin/cat: /tmp/hello.txt: No such file or directory #因为没有hello.txt文件,存活性探针会一直重启这个Pod [root@master ~]# kubectl get pod pod-liveness -n dev NAME READY STATUS RESTARTS AGE pod-liveness 1/1 Running 4 2m21s #正确示例 [root@master ~]# kubectl delete -f pod-liveness.yml pod "pod-liveness" deleted [root@master ~]# vim pod-liveness.yml apiVersion: v1 kind: Pod metadata: name: pod-liveness namespace: dev spec: containers: - name: nginx image: nginx:1.17.2 ports: - name: nginx-port containerPort: 80 livenessProbe: exec: command: ["/bin/ls","/tmp"] # 创建pod [root@master ~]# kubectl create -f pod-liveness.yml pod/pod-liveness created #创建成功并没有重启 [root@master ~]# kubectl get pod pod-liveness -n dev NAME READY STATUS RESTARTS AGE pod-liveness 1/1 Running 0 11s
TCPSocket
创建pod-liveness-tcpsocket.yml
apiVersion: v1 kind: Pod metadata: name: pod-tcpsocket namespace: dev spec: containers: - name: nginx image: nginx:1.17.1 ports: - name: nginx-port containerPort: 80 livenessProbe: tcpSocket: port: 8080 #尝试访问8080端口 # 创建Pod [root@master ~]# kubectl create -f pod-liveness-tcpsocket.yml pod/pod-tcpsocket created #查看信息 [root@master ~]# kubectl describe pod pod-tcpsocket -n dev ........... Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Scheduled <unknown> default-scheduler Successfully assigned dev/pod-tcpsocket to node1 Normal Pulled 15s kubelet, node1 Container image "nginx:1.17.2" already present on machine Normal Created 15s kubelet, node1 Created container nginx Normal Started 15s kubelet, node1 Started container nginx Warning Unhealthy 9s kubelet, node1 Liveness probe failed: dial tcp 10.244.1.46:8080: connect: connection refused
HTTPGet
创建文件pod-liveness-httpget.yml
apiVersion: v1 kind: Pod metadata: name: pod-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: / # 创建pod [root@master ~]# kubectl create -f pod-liveness-httpget.yml pod/pod-httpget created #查看pod详情 [root@master ~]# kubectl describe pod pod-httpget -n dev ............. Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Scheduled <unknown> default-scheduler Successfully assigned dev/pod-httpget to node2 Normal Pulled 29s kubelet, node2 Container image "nginx:1.17.1" already present on machine Normal Created 29s kubelet, node2 Created container nginx Normal Started 29s kubelet, node2 Started container nginx [root@master ~]# vim pod-liveness-httpget.yml
重启策略
一旦容器探测出现了问题,kubernetes就会对容器所在的Pod进行重启,其实这是由pod重启策略决定的,pod的重启策略有3种,分别是:
-
Always: 容器失效时,自动重启该容器,这也是默认从值
-
OnFailure: 容器终止运行且退出码不为0时重启
-
Never: 不论状态为何,都不重启该容器
重启策略适用于pod对象中的所有容器,首次需要重启的容器,将在其需要时立即进行重启,随后在次需要重启的操作将由kubelet延迟一段时间后进行,并且反复的重启操作的延迟时长为10s,20s,40s,80s,160s和300s,300s是最大延迟时长。
创建pod-restarpolicy.yml
apiVersion: v1 kind: Pod metadata: name: pod-restartpolicy namespace: dev spec: containers: - name: nginx image: nginx:1.17.2 ports: - name: nginx-port containerPort: 80 livenessProbe: httpGet: scheme: HTTP port: 80 path: /hello restartPolicy: Never # 创建Pod [root@master ~]# kubectl create -f pod-restartpolicy.yml pod/pod-restartpolicy created # 查看Pod详情发现nginx容器重启失败 [root@master ~]# kubectl describe pod pod-restartpolicy -n dev ....... Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Scheduled <unknown> default-scheduler Successfully assigned dev/pod-restartpolicy to node1 Normal Pulled 2m20s kubelet, node1 Container image "nginx:1.17.2" already present on machine Normal Created 2m20s kubelet, node1 Created container nginx Normal Started 2m19s kubelet, node1 Started container nginx Warning Unhealthy 114s (x3 over 2m14s) kubelet, node1 Liveness probe failed: HTTP probe failed with statuscode: 404 Normal Killing 114s kubelet, node1 Stopping container nginx # 由于策略定义的是Never所以容器不会重启 [root@master ~]# kubectl get pod pod-restartpolicy -n dev NAME READY STATUS RESTARTS AGE pod-restartpolicy 0/1 Completed 0 3m41
Pod调度
在默认情况下,一个Pod在那个Node节点上与性能,是由Scheduler组件采用相应的算法计算出来的,这个过程是不受人工控制的,但是在实际使用中,这并不能满足需求,因为在很多情况下,我们想控制某些Pod到达某些节点上,应该怎么做呢?这就需要了解Kubernetes对Pod的调度规则,kubernetes提供了四大类的调度。
-
自动调度: 运行在那个节点上完全由Scheduler经过一系列是算法得出
-
定性调度: NodeName,NodeSelector
-
亲和性调度: NodeAffinity,PodAffinity,PodAntiAffinity
-
污点(容忍)调度: Taints,Toleration
定向调度
定向调度,指的是利用在Pod上声明的NodeName或者NodeSelector,以此将Pod调度到期望的node节点上。注意,这里的调 是强制的,这就意味着即使要调度的目标Node不存在,也会向上面进行调度,只不过是Pod运行失败而已。
NodeName
NodeName用于强制约束将Pod调度到指定的node上,着种方式直接跳过了Scheduler的调度逻辑,直接写入PodList列表中
测试一些,创建一个pod-nodename.yml
apiVersion: v1 kind: Pod metadata: name: pod-nodename namespace: dev spec: containers: - name: nginx image: nginx:1.17.2 nodeName: node1 # 创建pod [root@master ~]# kubectl create -f pod-nodename.yml pod/pod-nodename created # 查看pod调度到Node属性,确实调度到了node1节点上 [root@master ~]# kubectl get pod pod-nodename -n dev -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES pod-nodename 1/1 Running 0 69s 10.244.1.56 node1 <none> <none>
NodeSeletor
NodeSeletor用于将Pod调度到添加了指定标签的node节点上,它通过kubernetes的label-selector机制实现,也就是说,在Pod创建之前,会有scheduler使MatchNodeSelector调度策略进行label匹配,找出目标node,然后将Pod调度到目标节点,该匹配规则是强制约束。
示例:
# 首先分别给node节点加上标签 [root@master ~]# kubectl label nodes node1 nodeenv=pro node/node1 labeled [root@master ~]# kubectl label nodes node2 nodeenv=dev node/node2 labeled # 创建一个pod-nodeselector.yml文件,并使用它创建pod vim pod-nodeselector.yml apiVersion: v1 kind: Pod metadata: name: pod-nodeselector namespace: dev spec: containers: - name: nginx image: nginx:1.17.2 nodeSelector: nodeenv: dev #创建Pod [root@master ~]# kubectl create -f pod-nodeselector.yml pod/pod-nodeselector created #查看pod调度到NODE属性,确实调度到了node2节点上 [root@master ~]# kubectl get pod pod-nodeselector -n dev -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES pod-nodeselector 1/1 Running 0 22s 10.244.2.74 node2 <none> <none> # 删除Pod,修改nodeSelector的值为一个不存在的标签 [root@master ~]# kubectl delete -f pod-nodeselector.yml pod "pod-nodeselector" deleted [root@master ~]# vim pod-nodeselector.yml [root@master ~]# kubectl create -f pod-nodeselector.yml pod/pod-nodeselector created # 再次查看发现Pod我i发正常运行,Node的值问none [root@master ~]# kubectl get pod pod-nodeselector -n dev -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES pod-nodeselector 0/1 Pending 0 56s <none> <none> <none> <none> # 查看详情发现node selector匹配失败的提示 [root@master ~]# kubectl describe pod 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 <unknown> default-scheduler 0/3 nodes are available: 3 node(s) didn't match node selector.
亲和性调度
定向调度使用起来非常方便,但是也有一定的问题,那就是如果没有满足条件的Node,那么Pod将不会运行,即使在集群中还有可以的Node列表也不行,这就限制了它的使用场景。
基于上面的问题,kubeneter还提供了一种亲和性调度(Affinity)。它在NodeSelector的基础上进行了扩展,可以通过匹配的形式,实现优先选择满足条件的Node进行调度,如果没有,也可以调度到不满足的节点上,使调度更加灵活。
Affinity主要分为三类:
-
nodeAffinity(node亲和性):以node为目标,解决pod可以调度到那些node的问题
-
podAffinity(pod亲和性): 以pod为目标,解决Pod可以和那些已存在的Pod部署在同一个拓扑域中的问题
-
podAntiAffinity(pod反亲和性): 以pod为目标,解决pod不能和那些已存在pod部署在同一个拓扑域中的问题
关于亲和性(反亲和性)使用场景说明: 亲和性: 如果两个应用频繁交互,那就有必要利用亲和性让两个应用尽可能的靠近,这样可以减少网络通信而带来的性能损耗。 反亲和性:当应用采用多副本部署使,有必要采用反亲和性让各个应用实例打散分布在各个node上,这样可以提高服务的高可用性。
NodeAffinity
首先来看一下NodeAffinity的可配置文件
od.spec.affinity.nodeAffinity requiredDuringSchedulingIgnoredDuringExecution 必须满足指定的规则才可以调度,相当于应限制 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"
演示一下requireDuringSchedulingIgnoredDuringExecution
创建pod-nodeaffinity-required.yml
apiVersion: v1 kind: Pod metadata: name: pod-nodeaffinity-required namespace: dev spec: containers: - name: nginx image: nginx:1.17.2 affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: nodeenv operator: In values: ["xxx","yyy"] # 创建pod [root@master ~]# kubectl create -f pod-nodeaffinity-required.yml pod/pod-nodeaffinity-required created # 查看pod状态发现运行失败 [root@master ~]# kubectl get pod pod-nodeaffinity-required -n dev NAME READY STATUS RESTARTS AGE pod-nodeaffinity-required 0/1 Pending 0 3m19s # 查看pod发现调度失败,提示node选择失败 [root@master ~]# kubectl describe pod pod-nodeaffinity-required -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 <unknown> default-scheduler 0/3 nodes are available: 3 node(s) didn't match node selector. # 接下来停止pod [root@master ~]# kubectl delete -f pod-nodeaffinity-required.yml pod "pod-nodeaffinity-required" deleted # 修改文件,将values: ["xxx","yyy" ]------->["dev","yyy"]后在次启动 [root@master ~]# kubectl create -f pod-nodeaffinity-required.yml pod/pod-nodeaffinity-required created #此时查看,发现已经调度成功,已经将pod调度到了node1上 [root@master ~]# kubectl get pod pod-nodeaffinity-required -n dev -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES pod-nodeaffinity-required 1/1 Running 0 42s 10.244.1.73 node1 <none> <none>
下面在演示preferredDuringSchedulingIgnoredDuringExecution
创建pod-nodeaffinity-preferred
apiVersion: v1 kind: Pod metadata: name: pod-nodeaffinity-preferred namespace: dev spec: containers: - name: nginx image: nginx:1.17.2 affinity: nodeAffinity: preferredDuringSchedulingIgnoredDuringExecution: - weight: 1 preference: matchExpressions: - key: nodeenv operator: In values: ["xxx","yyy"] # 创建pod [root@master ~]# kubectl create -f pod-nodeaffinity-prefereed.yml pod/pod-nodeaffinity-preferred created # 查看pod状态(运行成功) [root@master ~]# kubectl get pod pod-nodeaffinity-preferred -n dev -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES pod-nodeaffinity-preferred 1/1 Running 0 44s 10.244.2.83 node2 <none> <none> NodeAffinity规则设置的注意事项: 1.如果同时定义了nodeSelector和nodeAffinity,那么必须两个条件都得到满足,Pod才能运行在指定的node上 2.如果nodeAffinity指定了多个nodeSelectorTerms,那么只需要其中一个能够匹配成功即可 3.如果一个nodeSelectorTerms中有多个matchExperssions,则一个节点必须满足所有的才能匹配成功 4.如果一个pod所在的Node在Pod运行期间其标签发生了改变,不再符合该Pod的节点亲和性需求,则系统将忽略此变化
podAffinity配置
PodAffinty主要实现以运行的Pod为参照,实现让新创建的Pod跟参照pod在一个区域的功能。
PodAffinity的可配置项:
pod.spec.affinity.podAffinity requiredDuringSchedulingIgnoredDuringExecution: 硬限制 namespaces 指定参照pod的namespace topologKet 指定调度作用域 labelSelector 标签选择器 matcheExpressions 按节点标签列出的节点选择器要求列表(推荐) key values operator 关系符 matchLabels 值多个matchExperssions映射的内容 preferredDuringSchedulingIgnoredDuringExecution: 软限制 podAffinityTerm 选项 namespace topologyKey labelSelector matchExpressions key values operator matchLabels weight: 权重倾向,1-100 topologyKey用于指定调度时作用域,例如: 如果指定为kubernetes.io/hostname,那么就是以Node节点为区分范围 如果指定为beta.kubernetes.io/os,则是以Node节点的操作系统类型来区分范围
下面演示一下requiredDuringSchedulingIgnoredDuringExecution
创建一个pod-podaffinity-target.yml文件
apiVersion: v1 kind: Pod metadata: name: pod_podaffinity-target namespace: dev labels: version: v1 spec: containers: - name: nginx image: nginx:1.17.2 nodeName: node1 # 创建pod [root@master ~]# kubectl create -f pod-podaffinity-target.yml pod/pod-podaffinity-target created # 查看pod状态 [root@master ~]# kubectl get pod pod-podaffinity-target -n dev -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES pod-podaffinity-target 1/1 Running 0 39s 10.244.1.83 node1 <none> <none> # 创建pod-podaffinity-required.yml apiVersion: v1 kind: Pod metadata: name: pod-podaffinity-required namespace: dev spec: containers: - name: nginx image: nginx:1.17.2 affinity: podAffinity: requiredDuringSchedulingIgnoredDuringExecution: - labelSelector: matchExpressions: - key: version operator: In values: ["v1","yyy"] topologyKey: kubernetes.io/hostname 上面配置表达的意思: 新的Pod必须要与拥有标签version=v1或者version=yyy的pod在一个node上 # 创建Pod [root@master ~]# kubectl create -f pod-podaffinity-required.yml pod/pod-podaffinity-required created # 查看pod [root@master ~]# kubectl get pod pod-podaffinity-required -n dev -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES pod-podaffinity-required 1/1 Running 0 89s 10.244.1.84 node1 <none> <none>
PodAntiAffinity
PodAntiAffinity主要实现以运行的Pod为参照,让新创建的Pod跟参照的pod不在同一个区域中的功能,其配置方式和PodAffinity是一样的。
继续使用上一个例子中目标pod
创建pod-podantiaffinity-required.yml
apiVersion: v1 kind: Pod metadata: name: pod-podantiaffinity-required namespace: dev spec: containers: - name: nginx image: nginx:1.17.2 affinity: podAntiAffinity: requiredDuringSchedulingIgnoredDuringExecution: - labelSelector: matchExpressions: - key: version operator: In values: ["v1","yyy"] topologyKey: kubernetes.io/hostname #创建pod [root@master ~]# kubectl create -f pod-podantiaffinity-required.yml pod/pod-podantiaffinity-required created # 查看pod信息,可以看到调度到了node2上 [root@master ~]# kubectl get pod pod-podantiaffinity-required -n dev -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES pod-podantiaffinity-required 1/1 Running 0 47s 10.244.2.93 node2 <none> <none>
污点和容忍
污点(Taints)
前面的调度方式都是站在Pod的角度上,通过在Pod上添加属性,来确定Pod是否调度到指定的Node上,可以通过在Node上添加污点,来决定是否允许Pod调度。
Node被设置上污点一会就和Pod之间存在一种相斥的关系,从而拒绝Pod的调度,甚至可以将Pod驱逐出去
污点格式为: key=value:effect, key和value是污点的标签,effect描叙污点的作用,支持如下3个选项:
- PreferNoSchedule: kubernetes将尽量避免把Pod调度都具有该污点的Node上,除非没有其他可调度的节点
- NoSchedlue: kubernetes将不会把Pod调度到具有该污点的Node上,但不会影响当前Node上存在的Pod
- NoExecute: kubernetes将不会把Pod调度到具有该污点的Node上,同是将Node上已存在的Pod驱逐
使用kubectl设置和去除污点的命令如下:
#设置污点 kubectl taint nodes node1 key=values:effect #去除污点 kubectl taint nodes node1 key:effect- #去除所有污点 kubectl taint nodes node1 key-
下面演示污点效果:
- 准备节点node1(为了演示效果,暂时停止node2)
- 为node1节点设置一个污点: tag=test:PreferNoSchedule,然后创建pod1
- 修改为node1节点设置一个污点: tag=test:NoSchedule,然后创建pod2
- 修改为node1节点设置一个污点: tag=test:NoExectue,然后创建pod2
[root@master ~]# kubectl cordon node2 #为node1设置污点PreferNoSchedule [root@master ~]# kubectl taint nodes node1 tag=test:PreferNoSchedule node/node1 tainted # 创建pod1 [root@master ~]# kubectl run tainit1 --image=nginx:1.17.2 -n dev [root@master ~]# kubectl get pods -n dev -o wide tainit1-68d6b64b66-6bx5k 1/1 Running 0 2m7s 10.244.1.85 node1 <none> <none> #将node1污点修改为NoSchedule [root@master ~]# kubectl taint nodes node1 tag=test:PreferNoSchedule- node/node1 untainted [root@master ~]# kubectl taint nodes node1 tag=test:NoSchedule node/node1 tainted #创建pod2 [root@master ~]# kubectl run tainit2 --image=nginx:1.17.2 -n dev [root@master ~]# kubectl get pods -n dev -o wide tainit2-7f6d6975b-2bc9k 0/1 Pending 0 5s <none> <none> <none> <none> #将node1污点修改为NoExecute [root@master ~]# kubectl taint nodes node1 tag- node/node1 untainted #创建pod3 [root@master ~]# kubectl run tainit3 --image=nginx:1.17.2 -n dev [root@master ~]# kubectl get pods -n dev -o wide tainit1-68d6b64b66-9ps7p 0/1 Pending 0 62s <none> <none> <none> <none> tainit2-7f6d6975b-drvk4 0/1 Pending 0 62s <none> <none> <none> <none> tainit3-6f647d4d94-lj5bn 0/1 Pending 0 36s <none> <none> <none> <none>
容忍(Toleration) 上面介绍了污点的作用,我们可以在Node上添加污点用于拒绝pod调度上了,但是如果就是想将一个pod调度到一个有污点的Node上去,这个时候就可以使用容忍
污点就是拒绝,容忍就是忽略,Node通过污点拒绝pod调度上去,Pod通过容忍忽略拒绝
上面已经在node1上打上了NoExecute的污点,此时pod是调度不上去的,可以通过个pod添加容忍,然后将其调度上去
创建pod-toleration.yml
apiVersion: v1 kind: Pod metadata: name: pod-tolertion namespace: dev spec: containers: - name: nginx image: nginx:1.17.2 tolerations: # 添加容忍 - key: "tag" # 要容忍的污点的key operator: "Equal" # 操作符 value: "test" # 容忍的污点的value effect: "NoExecute" # 容忍规则,必须和标记污点相同 # 创建pod [root@master ~]# kubectl create -f pod-toleration.yml pod/pod-tolertion created [root@master ~]# kubectl get pods pod-tolertion -n dev -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES pod-tolertion 1/1 Running 0 19s 10.244.1.93 node1 <none> <none>
Pod控制器详解
在Kubernetes中,按照Pod的创建方式可以将其分为两类:
- 自主式pod: kubernetes直接创建出来的pod,这种pod删除后就没有了,也不会重建
- 控制器创建的pod: 通过控制器创建的Pod,这种pod删除了之后还会重建
Pod控制器式管理pod的中间层,使用了pod控制器后,我们只需要告诉pod创建,想要多少个什么样的pod就可以了,他就会创建满足条件的pod并确保每一个pod处于用户期望的状态,如果pod在运行种出现故障,控制器会基于指定策略重启或者重建pod。
在kubernetes种,有很多类型的pod控制器,每种都有自己的合适场景,常见的有下面几种:
-
ReplicationController: 比较原始的pod控制器,已经被废弃,由ReplicaSet替代
-
ReplicaSet: 保证指定数量的pod运行,并支持pod数量变更,镜像版本变更
-
Deployment: 通过控制ReplicaSet来控制pod,并支持滚动升级,版本回退
-
Horizontal Pod Autoscaler: 可以根据集群负载自动调整pod的数量,实现削峰填谷
-
DaemonSet:在集群中的指定Node上都运行一个副本,一般用于手好进程类的任务
-
Job: 它创建出来的pod只要完成任务后立即退出,用于执行一次性任务
-
Cronjob: 它创建的pod会周期性的执行,用于执行周期性任务
-
StatefulSet: 管理有状态的应用
ReplicaSet
ReplicaSet的主要作用式保证一定数量的Pod能够正常运行,它会持续监听这些pod的运行状态,一旦pod发生故障,就会重启或重建。同时它还支持对pod数量的扩容和版本镜像的升级。
ReplicaSet的资源清单文件:
apiVersion: apps/V1 #版本号 kind: ReplicaSet #类型 metadata: #元数据 name: #rs名称 namespace: #所属名称空间 labels: #标签 controller: rs spec: #详情描述 replicas: 3 #副本数量 selector: #选择器,通过它自动该控制器管理那些pod matchLabels: #label匹配规则 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:1.17.2 ports: - containerPort: 80
在这里需要新了解的配置项就是spec下面几个选项:
- replicas: 指定副本数量,其实就是当前rs创建出来的pod数量,默认为1
- selector: 选择器,它的作用是建立pod控制器和pod之间的关联关系,采用了Label Selector机制,在pod模板上定义label,在控制器上定义选择器,就可以表明当前控制器能管理那些pod了
- template: 模板,就是当前控制器创建pod所使用的模板
创建ReplicaSet
创建pc-replicaset.yml
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.17.2 # 创建rs [root@master ~]# kubectl create -f pc-replicaset.yml replicaset.apps/pc-replicaset created # 查看ReplicaSet信息 [root@master ~]# kubectl get rs pc-replicaset -n dev -o wide NAME DESIRED CURRENT READY AGE CONTAINERS IMAGES SELECTOR pc-replicaset 3 3 3 9m22s nginx nginx:1.17.2 app=nginx-pod
扩容缩容
# 编辑rs副本数量,修改spec:replicas:数量即可 [root@master ~]# kubectl edit rs pc-replicaset -n dev replicaset.apps/pc-replicaset edited #查看pod ][root@master ~]# kubectl get pod -n dev -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES pc-replicaset-4s6rz 0/1 ContainerCreating 0 28s <none> node2 <none> <none> pc-replicaset-5cdzq 1/1 Running 0 62m 10.244.1.98 node1 <none> <none> pc-replicaset-s2wlt 0/1 ContainerCreating 0 28s <none> node2 <none> <none> pc-replicaset-xt7cf 1/1 Running 0 65m 10.244.1.95 node1 <none> <none> pc-replicaset-zhf2z 1/1 Running 0 65m 10.244.1.96 node1 <none> <none> #也可以使用命令直接实现,使用scale命令实现扩缩容,后面--replicas=n直接指定目标数量即可 [root@master ~]# kubectl scale rs pc-replicaset --replicas=2 -n dev replicaset.apps/pc-replicaset scaled #命令运行完毕,查看pod,发现有3个退出 [root@master ~]# kubectl get pod -n dev -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES pc-replicaset-xt7cf 1/1 Running 0 68m 10.244.1.95 node1 <none> <none> pc-replicaset-zhf2z 1/1 Running 0 68m 10.244.1.96 node1 <none> <none>
镜像升级
#编辑rs的 容器镜像 - image: nginx:1.17.3 [root@master ~]# kubectl edit rs pc-replicaset -n dev replicaset.apps/pc-replicaset edite #再次查看,发现镜像版本已经变更 [root@master ~]# kubectl get rs -n dev -o wide NAME DESIRED CURRENT READY AGE CONTAINERS IMAGES SELECTOR pc-replicaset 2 2 2 72m nginx nginx:1.17.3 app=nginx-pod #也可以使用命令完成,kubectl set image rs rs名称 容器=镜像版本 -n namespace [root@master ~]# kubectl set image rs pc-replicaset nginx=nginx=1.17.1 -n dev replicaset.apps/pc-replicaset image updated #再次查看,可以看到镜像版本已经更新 [root@master ~]# kubectl get rs -n dev -o wide NAME DESIRED CURRENT READY AGE CONTAINERS IMAGES SELECTOR pc-replicaset 2 2 2 74m nginx nginx=1.17.1 app=nginx-pod
删除ReplicaSet
#使用kubectl delete命令会三次此RS以及它管理的pod #在kubernetes删除RS前,会将RS的replicasclear调整为0,等待所有的Pod删除后,在执行RS对象删除 [root@master ~]# kubectl delete rs pc-replicaset -n dev replicaset.apps "pc-replicaset" deleted #如果希望仅仅删除RS对象(保留pod),可以使用kubectl delete命令是添加--cascade=false选项(不推荐) [root@master ~]# kubectl delete rs pc-replicaset -n dev --cascade=false replicaset.apps "pc-replicaset" deleted [root@master ~]# kubectl get pod -n dev NAME READY STATUS RESTARTS AGE pc-replicaset-9556m 0/1 ContainerCreating 0 57s pc-replicaset-qvznw 1/1 Running 0 57s #也可以使用哦那个yml直接删除 [root@master ~]# kubectl delete -f pc-replicaset.yml
Deployment(Deploy)
为了更好的解决服务编排的问题,kubernetes在v1.2版本开始,引入Deployment控制器。值得一提的是,这种控制器并不直接管理pod,而是通过ReplicaSet来间接管理Pod,即:Deployment管理ReplicaSet,ReplicaSet管理Pod。所以Deployment比ReplicaSet功能更加强大。
Deployment主要功能有下面几个:
- 支持ReplicaSet的所用功能
- 支持发布的停止,继续
- 支持版本滚动升级和版本回退
Deploymenr的资源清单文件:
apiVersion: apps/v1 kind: Deployment metadata: name: #rs名称 namespace: #所属的名称空间 spec: replicas: 3 #副本数量 revisionHistoryLimit: 3 #保留历史版本,默认10 paused: false #暂停部署,默认false progressDeadlineSeconds: 600 #部署超时时间,默认600s strategy: #策略 type: RollingUpdate #滚动更新策略 rolliingUpdate: #滚动更新 maxSurge: 30% #最大额外可以存在的副本数,可以为百分比可以为整数 maxUnavailable: 30% #最大不可以状态的pod,可以为百分比可以为整数 selector: # 选择器,通过它指定该控制器管理那些pod matchLabels: #Label匹配规则 app: nginx-pod matchExpressions: # Expressions匹配规则 - {key:app, operator: IN , values:[nginx-pod]} template: #模板 metadata: labels: app: nginx-pod spec: containers: - name: nginx image: nginx:1.17.2 ports: containerPorts: 80
创建Deployment
创建文件pc-deployment.yml
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.17.2 # 创建deployment # --record=true 记录每次的版本变化 [root@master ~]# kubectl create -f pc-deployment.yml --record=true deployment.apps/pc-deployment created #查看deployment,UP-TO-DATE最新版本的pod的数量,AVAILABLE 当前可用pod的数量 [root@master ~]# kubectl get deploy -n dev -o wide NAME READY UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES SELECTOR pc-deployment 1/3 3 1 40s nginx nginx:1.17.2 app=nginx-pod #查看rs,发现rs的名称是在原来deployment的名字后面添加了一个随机10位数的随机串 [root@master ~]# kubectl get rs -n dev NAME DESIRED CURRENT READY AGE pc-deployment-675d469f8b 3 3 1 3m37 #查看pod [root@master ~]# kubectl get pod -n dev NAME READY STATUS RESTARTS AGE pc-deployment-675d469f8b-2jqkd 1/1 Running 1 9m55s pc-deployment-675d469f8b-n8vmx 1/1 Running 1 9m55s pc-deployment-675d469f8b-stswc 1/1 Running 0 9m55s
扩缩容
#变更副本数量为5个 [root@master ~]# kubectl scale deploy pc-deployment -n dev --replicas=5 deployment.apps/pc-deployment scaled #查看deployment [root@master ~]# kubectl get deploy -n dev NAME READY UP-TO-DATE AVAILABLE AGE pc-deployment 5/5 5 5 11m #查看pod [root@master ~]# kubectl get pod -n dev NAME READY STATUS RESTARTS AGE pc-deployment-675d469f8b-2jqkd 1/1 Running 1 12m pc-deployment-675d469f8b-fqfld 1/1 Running 0 48s pc-deployment-675d469f8b-khwr2 1/1 Running 0 48s pc-deployment-675d469f8b-n8vmx 1/1 Running 1 12m pc-deployment-675d469f8b-stswc 1/1 Running 0 12m # 编译deployment的副本数量,修改spec:replicas: 3 [root@master ~]# kubectl edit deploy pc-deployment -n dev deployment.apps/pc-deployment edited # 查看pod [root@master ~]# kubectl get pod -n dev NAME READY STATUS RESTARTS AGE pc-deployment-675d469f8b-2jqkd 1/1 Running 1 13m pc-deployment-675d469f8b-fqfld 1/1 Running 0 2m33s pc-deployment-675d469f8b-stswc 1/1 Running 0 13m
镜像更新
Deployment支持两种镜像更新的策略: 重建镜像和滚动跟新(默认),可用通过strategy选项进行配置
strategy: 指定新的Pod替换旧的Pod的策略,支持两个属性 type: 指定策略类型,支持两种策略 Recreate: 在创建出新的Pod之前会先杀掉所有已存在的pod RollingUpdate: 滚动跟新,就是杀死部分,就启动一部分,在更新的过程中存在两个版本的Pod rollingUpdate: 当type为RollingUpdate是生效,用于为RollingUpdate设置参数,支持两个属性: maxUnavailabe: 用来指定在升级过程中不可以pod的最大数量,默认25% maxSurge: 用来指定在升级过程中可用超过期望的Pod的最大数量,默认25%
重建更新:
#1.编辑pc-deployment.yml,在spec节点下添加更新策略 spec: strategy: type: Recrate # 应用策略 [root@master ~]# kubectl apply -f pc-deployment.yml # 2.创建deploy进行验证 #变更镜像 [root@master ~]# kubectl set image deployment pc-deployment nginx=nginx:1.17.4 -n dev deployment.apps/pc-deployment image updated root@master ~]# kubectl get pod -n dev -w NAME READY STATUS RESTARTS AGE pc-deployment-675d469f8b-2jqkd 1/1 Running 1 94m pc-deployment-675d469f8b-fqfld 1/1 Running 0 82m pc-deployment-675d469f8b-stswc 1/1 Running 0 94m pc-deployment-675d469f8b-stswc 1/1 Terminating 0 94m pc-deployment-675d469f8b-2jqkd 1/1 Terminating 1 94m pc-deployment-675d469f8b-fqfld 1/1 Terminating 0 83m pc-deployment-675d469f8b-2jqkd 0/1 Terminating 1 94m pc-deployment-675d469f8b-stswc 0/1 Terminating 0 94m pc-deployment-675d469f8b-fqfld 0/1 Terminating 0 83m pc-deployment-675d469f8b-2jqkd 0/1 Terminating 1 94m pc-deployment-675d469f8b-2jqkd 0/1 Terminating 1 94m pc-deployment-675d469f8b-fqfld 0/1 Terminating 0 83m pc-deployment-675d469f8b-fqfld 0/1 Terminating 0 83m pc-deployment-675d469f8b-stswc 0/1 Terminating 0 94m pc-deployment-675d469f8b-stswc 0/1 Terminating 0 94m pc-deployment-6c9f56fcfb-wrdtj 0/1 Pending 0 0s pc-deployment-6c9f56fcfb-zpmv7 0/1 Pending 0 0s pc-deployment-6c9f56fcfb-v2vl6 0/1 Pending 0 0s pc-deployment-6c9f56fcfb-wrdtj 0/1 Pending 0 0s pc-deployment-6c9f56fcfb-zpmv7 0/1 Pending 0 0s pc-deployment-6c9f56fcfb-v2vl6 0/1 Pending 0 0s pc-deployment-6c9f56fcfb-zpmv7 0/1 ContainerCreating 0 0s pc-deployment-6c9f56fcfb-wrdtj 0/1 ContainerCreating 0 0s pc-deployment-6c9f56fcfb-v2vl6 0/1 ContainerCreating 0 0s pc-deployment-6c9f56fcfb-zpmv7 1/1 Running 0 16s pc-deployment-6c9f56fcfb-v2vl6 1/1 Running 0 32s pc-deployment-6c9f56fcfb-wrdtj 1/1 Running 0 47s
滚动更新
1.编辑pc-deployment.yml,在spec节点下添加跟新策略 spec: strategy: type: RollingUpdate rollingUpdate: maxUnavailable: 25% maxSurge: 25% #应用 [root@master ~]# kubectl apply -f pc-deployment.yml deployment.apps/pc-deployment configured #变更镜像 [root@master ~]# kubectl set image deployment pc-deployment nginx=nginx:1.17.1 -n dev deployment.apps/pc-deployment image updated [root@master ~]# kubectl get pod -n dev -w NAME READY STATUS RESTARTS AGE pc-deployment-6c9f56fcfb-v2vl6 1/1 Running 0 3m1s pc-deployment-6c9f56fcfb-wrdtj 1/1 Running 0 3m1s pc-deployment-6c9f56fcfb-zpmv7 1/1 Running 0 3m1s pc-deployment-675d469f8b-gsvgm 0/1 Pending 0 0s pc-deployment-675d469f8b-gsvgm 0/1 Pending 0 0s pc-deployment-675d469f8b-gsvgm 0/1 ContainerCreating 0 0s pc-deployment-675d469f8b-gsvgm 1/1 Running 0 3s pc-deployment-6c9f56fcfb-wrdtj 1/1 Terminating 0 6m5s pc-deployment-675d469f8b-vtgbs 0/1 Pending 0 0s pc-deployment-675d469f8b-vtgbs 0/1 Pending 0 0s pc-deployment-675d469f8b-vtgbs 0/1 ContainerCreating 0 0s pc-deployment-6c9f56fcfb-wrdtj 0/1 Terminating 0 6m6s pc-deployment-6c9f56fcfb-wrdtj 0/1 Terminating 0 6m7s pc-deployment-675d469f8b-vtgbs 1/1 Running 0 2s pc-deployment-6c9f56fcfb-v2vl6 1/1 Terminating 0 6m7s pc-deployment-675d469f8b-4l4zz 0/1 Pending 0 0s pc-deployment-675d469f8b-4l4zz 0/1 Pending 0 0s pc-deployment-675d469f8b-4l4zz 0/1 ContainerCreating 0 0s pc-deployment-6c9f56fcfb-v2vl6 0/1 Terminating 0 6m8s pc-deployment-675d469f8b-4l4zz 1/1 Running 0 2s pc-deployment-6c9f56fcfb-zpmv7 1/1 Terminating 0 6m9s pc-deployment-6c9f56fcfb-wrdtj 0/1 Terminating 0 6m10s pc-deployment-6c9f56fcfb-wrdtj 0/1 Terminating 0 6m10s pc-deployment-6c9f56fcfb-zpmv7 0/1 Terminating 0 6m10s pc-deployment-6c9f56fcfb-zpmv7 0/1 Terminating 0 6m11s pc-deployment-6c9f56fcfb-zpmv7 0/1 Terminating 0 6m11s pc-deployment-6c9f56fcfb-v2vl6 0/1 Terminating 0 6m20s pc-deployment-6c9f56fcfb-v2vl6 0/1 Terminating 0 6m20s pc-deployment-5d89bdfbf9-xt428 0/1 Pending 0 0s pc-deployment-5d89bdfbf9-xt428 0/1 Pending 0 0s pc-deployment-5d89bdfbf9-xt428 0/1 ContainerCreating 0 0s pc-deployment-5d89bdfbf9-xt428 1/1 Running 0 2s pc-deployment-675d469f8b-4l4zz 1/1 Terminating 0 42s pc-deployment-5d89bdfbf9-cjpp2 0/1 Pending 0 0s pc-deployment-5d89bdfbf9-cjpp2 0/1 Pending 0 0s pc-deployment-5d89bdfbf9-cjpp2 0/1 ContainerCreating 0 0s pc-deployment-675d469f8b-4l4zz 0/1 Terminating 0 43s pc-deployment-5d89bdfbf9-cjpp2 1/1 Running 0 1s pc-deployment-675d469f8b-vtgbs 1/1 Terminating 0 45s
镜像更新中rs的变化:
#查看rs,发现原来的rs依旧存在,只是pod变为了0,然后新产生一个rs,pod数量为3 [root@master ~]# kubectl get rs -n dev NAME DESIRED CURRENT READY AGE pc-deployment-5d89bdfbf9 3 3 3 2m pc-deployment-675d469f8b 0 0 0 103m pc-deployment-6c9f56fcfb 0 0 0 8m47s
版本回退
deployment支持版本升级过程中暂停,继续功能以及版本回退等诸多功能。
kubectl rollout: 版本升级相关功能,支持下面的选项:
- status 显示当前升级状态
- history 显示升级历史记录
- pause 暂停版本升级过程
- resume 继续以及暂停的版本升级过程
- restart 重启版本升级过程
- undo 回滚到上一个版本(可用使用--to-revision回滚到指定版本)
# 查看当前升级的版本状态 [root@master ~]# kubectl rollout status deployment pc-deployment -n dev deployment "pc-deployment" successfully rolled out # [root@master ~]# kubectl rollout history deployment pc-deployment -n dev deployment.apps/pc-deployment REVISION CHANGE-CAUSE 2 kubectl create --filename=pc-deployment.yml --record=true 3 kubectl create --filename=pc-deployment.yml --record=true 4 kubectl create --filename=pc-deployment.yml --record=true # 版本回滚 # 这里直接使用--to-revision=2回滚到2版本,如果省略这个选项就是回退到上一个版本 [root@master ~]# kubectl rollout undo deployment pc-deployment --to-revision=2 -n dev deployment.apps/pc-deployment rolled back #查看发现,通过nginx进行版本可用发现到了1.17.4版本 [root@master ~]# kubectl get rs -n dev -o wide NAME DESIRED CURRENT READY AGE CONTAINERS IMAGES SELECTOR pc-deployment-5d89bdfbf9 0 0 0 16m nginx nginx:1.17.1 app=nginx-pod,pod-template-hash=5d89bdfbf9 pc-deployment-675d469f8b 0 0 0 117m nginx nginx:1.17.2 app=nginx-pod,pod-template-hash=675d469f8b pc-deployment-6c9f56fcfb 3 3 3 23m nginx nginx:1.17.4 app=nginx-pod,pod-template-hash=6c9f56fcfb
金丝雀发布 deployment支持更新过程中的控制,如“暂停(pause)”或“继续(resume)”更新操作
比如有一批新的pod资源创建完成后立即暂停更新过程,此时,仅存在一部分新版本应用,主体部分还是旧版本。然后,在筛选一小部分的用户请求路由到新版本的pod应用,继续概观察能否稳定的按期望的方式运行,确定没问题后在举行完成余下的pod资源滚动更新,否则立即回滚更新操作。
# 更新deployment的版本,并配置暂停deployment [root@master ~]# kubectl set image deploy pc-deployment nginx=nginx:1.17.3 -n dev && kubectl rollout pause deployment pc-deployment -n dev deployment.apps/pc-deployment image updated deployment.apps/pc-deployment paused #观察更新状态 [root@master ~]# kubectl rollout status deploy pc-deployment -n dev Waiting for deployment "pc-deployment" rollout to finish: 1 out of 3 new replicas have been updated... # 监控更新过程,可用看到已经新增了一个资源,但是并未按照预期的状态删除一个旧的资源,就是因为使用了pause暂停命令 [root@master ~]# kubectl get rs -n dev -o wide NAME DESIRED CURRENT READY AGE CONTAINERS IMAGES SELECTOR pc-deployment-5d89bdfbf9 0 0 0 25m nginx nginx:1.17.1 app=nginx-pod,pod-template-hash=5d89bdfbf9 pc-deployment-675d469f8b 0 0 0 126m nginx nginx:1.17.2 app=nginx-pod,pod-template-hash=675d469f8b pc-deployment-6c9f56fcfb 3 3 3 31m nginx nginx:1.17.4 app=nginx-pod,pod-template-hash=6c9f56fcfb pc-deployment-6dfdf96cc5 1 1 0 119s nginx ngnix:1.17.3 app=nginx-pod,pod-template-hash=6dfdf96cc5 # 继续更新 [root@master ~]# kubectl rollout resume deployment pc-deployment -n dev deployment.apps/pc-deployment resumed #查看deploy [root@master ~]# kubectl get rs -n dev NAME DESIRED CURRENT READY AGE pc-deployment-5d89bdfbf9 0 0 0 35m pc-deployment-675d469f8b 0 0 0 136m pc-deployment-6c9f56fcfb 0 0 0 41m pc-deployment-6dfdf96cc5 0 0 0 11m pc-deployment-7865c58bdf 3 3 3 63s
Horizonta Pod Autoscaler(HPA)
可用通过手工执行kubectl scale命令实现Pod扩容,但是这显然不符合kubernetes的定位目标--自动化、智能化。Kubernetes期望可用通过监测Pod的使用情况,实现pod数量的自动调整,于是就产生了HPA这种控制器。
HPA可以获取每个pod利用率,然后和PHPA中定义的指标进行对比,同时计算出需要伸缩的具体值,最后实现pod的数量的调整。其实HPA与之前的Deployment一样,也属于一种Kubernetes资源对象,它通过追踪分析目标pod的负载变化情况,来确定是否需要针对性的调整目标Pod的数量
1.安装metrice-server
metrucs-server可以用来收集集群中的资源使用情况
#安装git [root@master ~]# yum -y install git #获取metrics-server,注意使用版本 [root@master ~]# git clone -b v0.3.6 https://github.com/kubernetes-incubator/metrics-server #修改deployment,注意修改的是镜像和初始化参数 [root@master ~]# cd metrics-server/deploy/1.8+/ [root@master 1.8+]# vim metrics-server-deployment.yaml [root@master 1.8+]# vim metrics-server-deployment.yaml --- apiVersion: v1 kind: ServiceAccount metadata: name: metrics-server namespace: kube-system --- apiVersion: apps/v1 kind: Deployment metadata: name: metrics-server namespace: kube-system labels: k8s-app: metrics-server spec: selector: matchLabels: k8s-app: metrics-server template: metadata: name: metrics-server labels: k8s-app: metrics-server spec: hostNetwork: true serviceAccountName: metrics-server volumes: # mount in tmp so we can safely use from-scratch images and/or read-only containers - name: tmp-dir emptyDir: {} containers: - name: metrics-server image: registry.cn-hangzhou.aliyuncs.com/google_containers/metrics-server-amd64:v0.3.6 imagePullPolicy: Always args: - --kubelet-insecure-tls - --kubelet-preferred-address-types=InternalIP,Hostname,InternalDNS,ExternalDNS,ExternalIP volumeMounts: - name: tmp-dir mountPath: /tmp #查看pod运行状态 [root@master 1.8+]# kubectl get pod -n kube-system metrics-server-6b976979db-2hqm6 1/1 Running 0 2m21s #使用kubectl top node 查看资源使用状态 [root@master 1.8+]# kubectl top node NAME CPU(cores) CPU% MEMORY(bytes) MEMORY% master 111m 5% 970Mi 56% node1 28m 1% 388Mi 44% node2 34m 1% 426Mi 48% [root@master 1.8+]# kubectl top pod -n kube-system NAME CPU(cores) MEMORY(bytes) coredns-6955765f44-sch82 4m 15Mi coredns-6955765f44-thfs7 4m 15Mi etcd-master 15m 86Mi kube-apiserver-master 33m 294Mi kube-controller-manager-master 15m 63Mi .......................... #至此,metrics-server安装完成
2.准备deployment和service
# 创建deployment vim nginx.yml apiVersion: apps/v1 # 版本号 kind: Deployment # 类型 metadata: # 元数据 name: nginx # deployment的名称 namespace: dev # 命名类型 spec: # 详细描述 selector: # 选择器,通过它指定该控制器可以管理哪些Pod matchLabels: # Labels匹配规则 app: nginx-pod template: # 模块 当副本数据不足的时候,会根据下面的模板创建Pod副本 metadata: labels: app: nginx-pod spec: containers: - name: nginx # 容器名称 image: nginx:1.17.1 # 容器需要的镜像地址 ports: - containerPort: 80 # 容器所监听的端口 resources: # 资源限制 requests: cpu: "100m" # 100m表示100millicpu,即0.1个CPU #创建Deployment [root@master 1.8+]# kubectl create -f nginx.yml deployment.apps/nginx created #查看Deployment和Pod [root@master 1.8+]# kubectl get pod,deploy -n dev NAME READY STATUS RESTARTS AGE pod/nginx-7b766dbb7-8qrdv 1/1 Running 0 31s NAME READY UP-TO-DATE AVAILABLE AGE deployment.apps/nginx 1/1 1 1 31s #创建Service [root@master 1.8+]# kubectl expose deployment nginx --name=nginx --type=NodePort --port=80 --target-port=80 -n dev service/nginx exposed #查看Service [root@master 1.8+]# kubectl get svc -n dev NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE nginx NodePort 10.105.180.5 <none> 80:31628/TCP 35s
3.部署HPA
创建pc-hpa.yaml文件
apiVersion: autoscaling/v1 # 版本号 kind: HorizontalPodAutoscaler # 类型 metadata: # 元数据 name: pc-hpa # deployment的名称 namespace: dev # 命名类型 spec: minReplicas: 1 # 最小Pod数量 maxReplicas: 10 # 最大Pod数量 targetCPUUtilizationPercentage: 3 # CPU使用率指标 scaleTargetRef: # 指定要控制的Nginx的信息 apiVersion: apps/v1 kind: Deployment name: nginx #创建hpa [root@master 1.8+]# kubectl create -f pc-hpa.yaml horizontalpodautoscaler.autoscaling/pc-hpa created #查看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 42s
4.测试
● 使用压测工具如Jmeter对service的地址http://192.168.248.11:31628进行压测,然后通过控制台查看hpa和pod的变化
hpa的变化 [root@master ~]# kubectl get hpa -n dev -w NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE pc-hpa Deployment/nginx 0%/3% 1 10 1 3m28s pc-hpa Deployment/nginx 0%/3% 1 10 1 5m18s pc-hpa Deployment/nginx 1%/3% 1 10 1 9m6s pc-hpa Deployment/nginx 0%/3% 1 10 1 10m pc-hpa Deployment/nginx 1%/3% 1 10 1 12m pc-hpa Deployment/nginx 0%/3% 1 10 1 13m pc-hpa Deployment/nginx 0%/3% 1 10 1 18m pc-hpa Deployment/nginx 20%/3% 1 10 1 20m pc-hpa Deployment/nginx 20%/3% 1 10 4 21m pc-hpa Deployment/nginx 20%/3% 1 10 7 21m pc-hpa Deployment/nginx 4%/3% 1 10 7 21m pc-hpa Deployment/nginx 1%/3% 1 10 7 23m
DaemonSet(DS)
DaemonSet类型的控制器可以保证集群中的每一台(或指定)节点上都运行一个副本,一般适用于日志收集、节点监控等场景。也就是说,如果一个Pod提供的功能是节点级别的(每个节点都需要且只需要一个),那么这类Pod就适合使用DaemonSet类型的控制器创建。
DaemonSet控制器的特点:
- 每向集群中添加一个节点的时候,指定的Pod副本也将添加到该节点上。
- 当节点从集群中移除的时候,Pod也会被垃圾回收。
DaemonSet的资源清单:
apiVersion: apps/v1 # 版本号 kind: DaemonSet # 类型 metadata: # 元数据 name: # 名称 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:1.17.1 ports: - containerPort: 80
创建DaemonSet
创建pc-daemonset.yml文件
apiVersion: apps/v1 # 版本号 kind: DaemonSet # 类型 metadata: # 元数据 name: pc-damonset # 名称 namespace: dev #命名空间 spec: # 详情描述 selector: # 选择器,通过它指定该控制器管理那些Pod matchLabels: # Labels匹配规则 app: nginx-pod template: # 模板,当副本数量不足时,会根据下面的模板创建Pod模板 metadata: labels: app: nginx-pod spec: containers: - name: nginx image: nginx:1.17.1 ports: - containerPort: 80 #创建DaemonSet [root@master ~]# kubectl create -f pc-daemonset.yml daemonset.apps/pc-damonset created #查看DaemonSet [root@master ~]# kubectl get ds -n dev -o wide NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE CONTAINERS IMAGES SELECTOR pc-damonset 2 2 2 2 2 <none> 25s nginx nginx:1.17.1 app=nginx-pod #删除DaemonSet [root@master ~]# kubectl delete ds pc-damonset -n dev daemonset.apps "pc-damonset" deleted
job
Job主要用于负责批量处理短暂的一次性任务。
Job的特点:
- 当Job创建的Pod执行成功结束时,Job将记录成功结束的Pod数量。
- 当成功结束的Pod达到指定的数量时,Job将完成执行
job资源清单
apiVersion: batch/v1 # 版本号 kind: Job # 类型 metadata: # 元数据 name: # 名称 namespace: #命名空间 labels: # 标签 controller: job spec: # 详情描述 completions: 1 # 指定Job需要成功运行Pod的总次数,默认为1 parallelism: 1 # 指定Job在任一时刻应该并发运行Pod的数量,默认为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 20;done"] 关于模板中的重启策略的说明: # 如果设置为OnFailure,则Job会在Pod出现故障的时候重启容器,而不是创建Pod,failed次数不变。 # 如果设置为Never,则Job会在Pod出现故障的时候创建新的Pod,并且故障Pod不会消失,也不会重启,failed次数+1。 #如果指定为Always的话,就意味着一直重启,意味着Pod任务会重复执行,这和Job的定义冲突,所以不能设置为Always。
创建pc-job.yml文件
apiVersion: batch/v1 # 版本号 kind: Job # 类型 metadata: # 元数据 name: pc-job # 名称 namespace: dev #命名空间 spec: # 详情描述 manualSelector: true # 是否可以使用selector选择器选择Pod,默认为false selector: # 选择器,通过它指定该控制器管理那些Pod matchLabels: # Labels匹配规则 app: 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 3;done" ] # 创建job [root@master ~]# kubectl create -f pc-job.yml job.batch/pc-job created # 查看job [root@master ~]# kubectl get job -n dev -o wide -w NAME COMPLETIONS DURATION AGE CONTAINERS IMAGES SELECTOR pc-job 0/1 2s 2s counter busybox:1.30 app=counter-pod pc-job 1/1 28s 28s counter busybox:1.30 app=counter-pod #查看pod [root@master ~]# kubectl get pod -n dev -w NAME READY STATUS RESTARTS AGE pc-job-5s9ck 0/1 Pending 0 0s pc-job-5s9ck 0/1 Pending 0 0s pc-job-5s9ck 0/1 ContainerCreating 0 0s pc-job-5s9ck 1/1 Running 0 1s pc-job-5s9ck 0/1 Completed 0 28s #删除job [root@master ~]# kubectl delete -f pc-job.yml job.batch "pc-job" deleted
CronJob(CJ)
CronJob控制器以Job控制器为其管控对象,并借助它管理Pod资源对象,Job控制器定义的作业任务在其控制器资源创建之后便会立即执行,但CronJob可以以类似Linux操作系统的周期性任务作业计划的方式控制器运行时间点及重复运行的方式,换言之,CronJob可以在特定的时间点反复去执行Job任务
CronJob的资源清单
apiVersion: batch/v1beta1 # 版本号 kind: CronJob # 类型 metadata: # 元数据 name: # 名称 namespace: #命名空间 labels: controller: cronjob spec: # 详情描述 schedule: # cron格式的作业调度运行时间点,用于控制任务任务时间执行 concurrencyPolicy: # 并发执行策略 failedJobsHistoryLimit: # 为失败的任务执行保留的历史记录数,默认为1 successfulJobsHistoryLimit: # 为成功的任务执行保留的历史记录数,默认为3 jobTemplate: # job控制器模板,用于为cronjob控制器生成job对象,下面其实就是job的定义 metadata: {} spec: completions: 1 # 指定Job需要成功运行Pod的总次数,默认为1 parallelism: 1 # 指定Job在任一时刻应该并发运行Pod的数量,默认为1 activeDeadlineSeconds: 30 # 指定Job可以运行的时间期限,超过时间还没结束,系统将会尝试进行终止 backoffLimit: 6 # 指定Job失败后进行重试的次数,默认为6 template: # 模板,当副本数量不足时,会根据下面的模板创建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 20;done" ] schedule:cron表达式,用于指定任务的执行时间。 ● */1 * * * *:表示分钟 小时 日 月份 星期。 ● 分钟的值从0到59。 ● 小时的值从0到23。 ● 日的值从1到31。 ● 月的值从1到12。 ● 星期的值从0到6,0表示星期日。 ● 多个时间可以用逗号隔开,范围可以用连字符给出:* 可以作为通配符,/表示每... concurrencyPolicy:并发执行策略 ● Allow:运行Job并发运行(默认)。 ● Forbid:禁止并发运行,如果上一次运行尚未完成,则跳过下一次运行。 ● Replace:替换,取消当前正在运行的作业并使用新作业替换它。
创建pc-cronjob.yml文件
apiVersion: batch/v1beta1 # 版本号 kind: CronJob # 类型 metadata: # 元数据 name: pc-cronjob # 名称 namespace: dev #命名空间 spec: # 详情描述 schedule: "*/1 * * * * " # cron格式的作业调度运行时间点,用于控制任务任务时间执行 jobTemplate: # job控制器模板,用于为cronjob控制器生成job对象,下面其实就是job的定义 metadata: {} spec: template: # 模板,当副本数量不足时,会根据下面的模板创建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" ] #创建CronJob [root@master ~]# kubectl create -f pc-cronjob.yml cronjob.batch/pc-cronjob created #查看cronjob [root@master ~]# kubectl get cronjob -n dev -w NAME SCHEDULE SUSPEND ACTIVE LAST SCHEDULE AGE pc-cronjob */1 * * * * False 0 <none> 0s pc-cronjob */1 * * * * False 1 8s 23s pc-cronjob */1 * * * * False 0 28s 43s pc-cronjob */1 * * * * False 1 8s 83s pc-cronjob */1 * * * * False 0 28s 103s #删除CronJob [root@master ~]# kubectl delete -f pc-cronjob.yml cronjob.batch "pc-cronjob" deleted