前言:这一章主要是deploy与service的配置及其原理,以及一些细节上的补充,同时还会附上镜像拉取策略和容器健康检查的一些操作实例,内容比较多,建议根据目录查看。
1、镜像拉取策略
IfNotPresent:在镜像已经存在的情况下,kubelet将不再去拉取镜像,仅当本地缺失时才会从仓库中拉取,这是默认的镜像拉取策略。
Alaways:每次创建Pod都会重新拉取一次镜像,无论本地是否有镜像。
Never:Pod不会主动拉取这个镜像,即使无法创建pod,也仅使用本地镜像。
注意:对于标签为latest的镜像文件,其默认的镜像获取策略即为Always,而对于其他标签的镜像,其默认策略则为IfNotPresent。
下面演示一下这三种镜像拉取策略配置:
1)使用always策略下载镜像
[root@k8s-master1 imagePullPolicy]# pwd
/root/pod.yaml.d/imagePullPolicy
[root@k8s-master1 imagePullPolicy]# vim always-test.yaml
[root@k8s-master1 imagePullPolicy]# cat always-test.yaml
---
apiVersion: v1
kind: Pod
metadata:
name: always-pod
spec:
nodeName: k8s-node1
containers:
- name: nginx
image: registry.cn-chengdu.aliyuncs.com/liumuquan_app/nginx:latest
imagePullPolicy: Always
此时两个node上都有该镜像
创建pod,并查看创建详情
[root@k8s-master1 imagePullPolicy]# kubectl apply -f always-test.yaml
pod/always-pod created
[root@k8s-master1 imagePullPolicy]# kubectl get pod
NAME READY STATUS RESTARTS AGE
always-pod 1/1 Running 0 64s
[root@k8s-master1 imagePullPolicy]# kubectl describe pod always-pod
创建详情能看到重新拉取镜像的过程
2)使用IfNotPresent策略下载镜像
[root@k8s-master1 imagePullPolicy]# kubectl get pod
NAME READY STATUS RESTARTS AGE
always-pod 1/1 Running 0 6m14s
[root@k8s-master1 imagePullPolicy]# kubectl delete pod always-pod
pod "always-pod" deleted
[root@k8s-master1 imagePullPolicy]# cat always-test.yaml > ifnotpresent-test.yaml
[root@k8s-master1 imagePullPolicy]# vim ifnotpresent-test.yaml
[root@k8s-master1 imagePullPolicy]# cat ifnotpresent-test.yaml
---
apiVersion: v1
kind: Pod
metadata:
name: ifnotpresent-pod
spec:
nodeName: k8s-node1
containers:
- name: nginx
image: registry.cn-chengdu.aliyuncs.com/liumuquan_app/nginx:latest
imagePullPolicy: IfNotPresent
创建pod,并查看创建详情
[root@k8s-master1 imagePullPolicy]# kubectl apply -f ifnotpresent-test.yaml
pod/ifnotpresent-pod created
[root@k8s-master1 imagePullPolicy]# kubectl get pod
NAME READY STATUS RESTARTS AGE
ifnotpresent-pod 1/1 Running 0 2s
[root@k8s-master1 imagePullPolicy]# kubectl describe pod ifnotpresent-pod
创建详情,因为node上本身保存有该镜像,所以并没有拉取镜像过程
3)使用Never策略下载镜像
[root@k8s-master1 imagePullPolicy]# kubectl delete pod ifnotpresent-pod
pod "ifnotpresent-pod" deleted
[root@k8s-master1 imagePullPolicy]# cat always-test.yaml > never-test.yaml
[root@k8s-master1 imagePullPolicy]# vim never-test.yaml
[root@k8s-master1 imagePullPolicy]# cat never-test.yaml
---
apiVersion: v1
kind: Pod
metadata:
name: never-pod
spec:
nodeName: k8s-node1
containers:
- name: nginx
image: registry.cn-chengdu.aliyuncs.com/liumuquan_app/nginx:latest
imagePullPolicy: Never
此时创建pod,详情如下
删除创建的pod以及node节点保存的镜像文件,再次创建,情况如下,创建失败报错
2、Deployment
Deployment
是一种用于定义和管理多个副本应用的新一代对象,相比于 Replication Controller
,它提供了更完善的功能,使用起来更加简便。其主要功能包括:
- 保证一定数量的副本始终可用,以防某个
Pod
故障导致服务中断。 - 在
Pod
定义发生变化时进行滚动更新(Rolling Update),第一个更新成功方可更新第二个,否则自动终止更新。
Deployment
通过“控制器”模式(controller pattern)管理 Pod
。例如,当请求创建三个 Tomcat Pod
时,Deployment
记录这一请求并确保集群中始终保持三个副本。如果一个 Pod
被删除,Deployment
会自动创建一个新的 Pod
以维持副本数量,从而保证应用程序的高可用性。
Deployment
通过标签管理副本。例如:
Deployment 副本:3(标签选择器:app: tomcat)
Tomcat Pods:
tomcat-pod1(标签:app: tomcat)
tomcat-pod2(标签:app: tomcat)
tomcat-pod3(标签:app: tomcat)
Deployment
实际上管理这些带有特定标签的 Pod
,确保 Pod
数量与预期一致。
Deployment
的使用流程如下:
1、使用 YAML 文件创建 Deployment。
2、Deployment 的创建过程细分为以下步骤:
用户通过 kubectl 创建 Deployment。
Deployment 创建一个 ReplicaSet。
ReplicaSet 创建 Pod。
对象的命名方式是:子对象的名字 = 父对象名字 + 随机字符串或数字
2.1、deployment操作演示
[root@k8s-master1 ~]# mkdir deployment.yaml.d
[root@k8s-master1 ~]# cd deployment.yaml.d/
[root@k8s-master1 deployment.yaml.d]# vim deployment.yaml
[root@k8s-master1 deployment.yaml.d]# cat deployment.yaml
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
namespace: default
spec:
selector: #标签选择器
matchLabels:
app: nginx #标签
replicas: 2 #创建两个pod
template:
metadata:
labels:
app: nginx #标签
spec:
containers:
- name: nginx
image: registry.cn-chengdu.aliyuncs.com/liumuquan_app/nginx:1.20.1
ports:
- containerPort: 80
volumeMounts:
- name: nginx-vol
mountPath: "/usr/share/nginx/html"
volumes:
- name: nginx-vol
emptyDir: {} #这里挂一个空文件
创建deployment,并查看相关资源对象
[root@k8s-master1 deployment.yaml.d]# kubectl apply -f deployment.yaml
deployment.apps/nginx-deployment created
[root@k8s-master1 deployment.yaml.d]# kubectl get pod
NAME READY STATUS RESTARTS AGE
nginx-deployment-65f474ff44-84lqh 1/1 Running 0 18s
nginx-deployment-65f474ff44-gmhld 1/1 Running 0 18s
[root@k8s-master1 deployment.yaml.d]# kubectl get deployment
NAME READY UP-TO-DATE AVAILABLE AGE
nginx-deployment 2/2 2 2 49s
[root@k8s-master1 deployment.yaml.d]# kubectl get deploy
NAME READY UP-TO-DATE AVAILABLE AGE
nginx-deployment 2/2 2 2 56s
此时外部访问pod_ip结果为403(空目录覆盖了原有文件)
尝试删除一个pod,deployment会瞬间创建一个新的pod
[root@k8s-master1 deployment.yaml.d]# kubectl get pod
NAME READY STATUS RESTARTS AGE
nginx-deployment-65f474ff44-84lqh 1/1 Running 0 4m33s
nginx-deployment-65f474ff44-gmhld 1/1 Running 0 4m33s
[root@k8s-master1 deployment.yaml.d]# kubectl delete pod nginx-deployment-65f474ff44-84lqh
pod "nginx-deployment-65f474ff44-84lqh" deleted
[root@k8s-master1 deployment.yaml.d]# kubectl get pod
NAME READY STATUS RESTARTS AGE
nginx-deployment-65f474ff44-gmhld 1/1 Running 0 5m5s
nginx-deployment-65f474ff44-kgwnl 1/1 Running 0 15s
想要删除这两个pod只能删除控制器有两种方式:
- kubectl删除控制器yaml文件
- kubectl delete deployment nginx-deployment
2.2、deployment扩容
首先创建一个replicas: 1的deployment,并应用
[root@k8s-master1 deployment.yaml.d]# vim deployment.yaml
[root@k8s-master1 deployment.yaml.d]# cat deployment.yaml
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
namespace: default
spec:
selector:
matchLabels:
app: nginx
replicas: 1
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: registry.cn-chengdu.aliyuncs.com/liumuquan_app/nginx:1.20.1
ports:
- containerPort: 80
volumeMounts:
- name: nginx-vol
mountPath: "/usr/share/nginx/html"
volumes:
- name: nginx-vol
emptyDir: {}
[root@k8s-master1 deployment.yaml.d]# kubectl apply -f deployment.yaml
deployment.apps/nginx-deployment created
[root@k8s-master1 deployment.yaml.d]# kubectl get pod
NAME READY STATUS RESTARTS AGE
nginx-deployment-65f474ff44-454mt 1/1 Running 0 3s
[root@k8s-master1 deployment.yaml.d]# kubectl get deploy
NAME READY UP-TO-DATE AVAILABLE AGE
nginx-deployment 1/1 1 1 43
此时因为业务需要对整体进行扩容,只需将replicas改为2,重新应用,即可完成扩容,取消/增减卷挂载同样操作即可。
[root@k8s-master1 deployment.yaml.d]# vim deployment.yaml
[root@k8s-master1 deployment.yaml.d]# kubectl apply -f deployment.yaml
deployment.apps/nginx-deployment configured
[root@k8s-master1 deployment.yaml.d]# kubectl get deploy
NAME READY UP-TO-DATE AVAILABLE AGE
nginx-deployment 2/2 2 2 2m36s
[root@k8s-master1 deployment.yaml.d]# kubectl get pod
NAME READY STATUS RESTARTS AGE
nginx-deployment-65f474ff44-298fb 1/1 Running 0 7s
nginx-deployment-65f474ff44-454mt 1/1 Running 0 2m38s
虽然批量操作很方便,但这里会引出一个问题,新建/重建pod都会产生的IP地址变化,转发规则不能及时修改,这时就要引出另一种资源对象service。
2.3、Replication Controller(补充了解)
Replication Controller(简称rc)用来管理Pod的副本,保证集群中存在指定数量的Pod副本。集群中副本的数量大于指定数量,则会停止指定数量之外的多余容器数量,反之,则会启动少于指定数量个数的容器,保证数量不变。Replication Controller是实现弹性伸缩、动态扩容的核心。
RC 的主要功能点:
确保pod数量:指定某个服务在Kubernetes中有相应数量的Pod在运行;
确保pod健康:当pod不健康,运行出错或者无法提供服务时,会杀死不健康pod并重新创建,保持pod数量一致;
弹性伸缩:当业务高峰期的时候可以设置扩增pod数量,配合监控就可以做自动伸缩了;
实操演示:
[root@k8s-master1 deployment.yaml.d]# vim nginx-rc.yaml
[root@k8s-master1 deployment.yaml.d]# cat nginx-rc.yaml
---
apiVersion: v1
kind: ReplicationController
metadata:
name: my-nginx
spec:
replicas: 2
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: registry.cn-chengdu.aliyuncs.com/liumuquan_app/nginx:1.20.1
ports:
- containerPort: 80
rc无需声明标签选择器
创建rc
[root@k8s-master1 deployment.yaml.d]# kubectl apply -f nginx-rc.yaml
replicationcontroller/my-nginx created
[root@k8s-master1 deployment.yaml.d]# kubectl get rc
NAME DESIRED CURRENT READY AGE
my-nginx 2 2 2 18s
[root@k8s-master1 deployment.yaml.d]# kubectl get pod
NAME READY STATUS RESTARTS AGE
my-nginx-bl97r 1/1 Running 0 66s
my-nginx-c8g9t 1/1 Running 0 66s
注意:
Deployment
和 ReplicationController
(RC) 在 Kubernetes 中都用于管理 Pod 的副本,但有以下区别:
-
功能:
Deployment
提供了更高级的功能,如滚动更新、回滚、版本控制等。ReplicationController
主要负责确保一定数量的 Pod 副本在任何时候都在运行,但没有内置的更新策略。
-
更新策略:
Deployment
支持滚动更新和回滚,可以方便地管理应用版本的升级。ReplicationController
不支持滚动更新,更新应用需要手动替换或删除旧的 RC。
-
声明式管理:
Deployment
是声明式的,用户定义期望的状态,Kubernetes 自动处理变化以达到这个状态。ReplicationController
更倾向于命令式管理,需要手动进行管理和调整。
基于以上差距deployment几乎完全取代RC成为更好用的pod控制器。
3、Service
在解释Kubernetes Service之前,先了解其使用场景:
- 客户端访问K8S集群中的Pod时,需要知道Pod的IP和端口。如何在不知道Pod地址的情况下快速连接Pod?
- 若某节点上的Pod发生故障,K8S会感知并重启该Pod,但重启后的Pod IP会发生变化。客户端如何感知并保持对Pod的访问?
- 如果多个Pod组成Pod组,如何实现负载均衡?
为解决这些问题,K8S引入了Service的概念。Kubernetes Service是管理具有相同功能的一组Pod的资源对象,其具体作用如下:
- 通过Pod的Label Selector访问Pod组。
- Service的IP保持不变(Headless Service除外),确保访问接口的稳定性,并屏蔽Pod IP变化的影响,实现自动更新。建议使用ServiceName进行访问。
- Service通过kube-proxy利用iptables/ipvsadm提供负载均衡能力,实现反向代理,将请求转发到合适的Pod。
这里可选择程序有两个iptables,ipvsadm
iptables 与 IPVS 都是基于 Netfilter 实现的,但因为定位不同,二者有着本质的差别:iptables 是为防火墙而设计的;IPVS 则专门用于高性能负载均衡,并使用更高效的数据结构(Hash 表),允许几乎无 限的规模扩张。 与 iptables 相比,IPVS 拥有以下明显优势:
- 1. 为大型集群提供了更好的可扩展性和性能;
- 2. 支持比 iptables 更复杂的复制均衡算法(最小负载、最少连接、加权等);
- 3. 支持服务器健康检查和连接重试等功能;
- 4. 可以动态修改 ipset 的集合,即使 iptables 的规则正在使用这个集合。
Service工作流程(nodeport实操结束有简单版)
1.master上的kube-apiserver会处理service的创建,以及Service与通过label匹配与Pod绑定而产生的endpoints对象,并将这些元数据内容存储到etcd中。
2.node上的kube-proxy通过实时监听kube-apiserver上service以及endpoints的变化情况来感知相关事件并更新本地的service和endpoint的映射关系;同时node上的kubedns/coredns服务也会同时将service的域名信息与IP的对应关系存储起来供dns解析之用。
3.kube-proxy将从apiserver获取到的service和endpoint的映射关系保存在本地的iptables/ipvs中供后续查询使用
4.client发起对服务的访问,首先kubedns/coredns将服务名称解析成一个虚拟IP(ClusterIP)
5.然后使用这个IP去iptables/ipvs中去找service和endpoint的映射关系
6.找到映射关系后,通过iptables/ipvs的负载均衡算法(典型也是最简单的就是roundrobin算法)匹配到一个合适的Pod进行访问即可
注意:service提供针对pod的负载均衡的能力,但是只提供4层负载均衡的能力,而没有7层功能,只能到ip层面。
service的类型:
K8S中Service分为四类,分别是ClusterIP,NodePort,LoadBalancer以及ExternalName。
如下图所示:
其中绿色的代表从外向内的访问模式;蓝色的代表从内向外的访问模式,黄色代表集群内部的访问模式。
3.1、ClusterIP
- 默认类型,自动分配一个仅可在内部访问的虚拟IP。应用方式:内部服务访问(如被tomcat访问的mysql)
- 这是K8S默认的服务类型,只能在K8S中进行服务通信。在ClusterIP中,K8S会在Service创建完毕后提供一个内部IP作为ClusterIP,K8S内部服务可以通过ClusterIP或者ServiceName来访问该服务。
操作如下:
[root@k8s-master1 deployment.yaml.d]# vim nginx-dep.yaml
[root@k8s-master1 deployment.yaml.d]# cat nginx-dep.yaml
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-dep
spec:
selector:
matchLabels:
app: nginx
replicas: 2
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: registry.cn-chengdu.aliyuncs.com/liumuquan_app/nginx:1.20.1
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: nginx-svc-clusterip
spec:
type: ClusterIP
selector:
app: nginx
ports:
- protocol: TCP
port: 80
targetPort: 80
[root@k8s-master1 deployment.yaml.d]# kubectl apply -f nginx-dep.yaml
deployment.apps/nginx-dep created
service/nginx-svc-clusterip created
[root@k8s-master1 deployment.yaml.d]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 11d
nginx-svc-clusterip ClusterIP 10.100.124.42 <none> 80/TCP 15s
[root@k8s-master1 deployment.yaml.d]# kubectl get endpoints
NAME ENDPOINTS AGE
kubernetes 192.168.188.101:6443 11d
nginx-svc-clusterip 10.244.1.23:80,10.244.2.17:80 34s
[root@k8s-master1 deployment.yaml.d]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-dep-5c5f7b5898-8vtrt 1/1 Running 0 56s 10.244.1.23 k8s-node1 <none> <none>
nginx-dep-5c5f7b5898-bzdh2 1/1 Running 0 56s 10.244.2.17 k8s-node2 <none> <none>
此时这两个pod只能在集群内部(node,pod)完成访问
3.2、NodePort
在ClusterIP的基础之上,为集群内的每台物理机绑定一个端口,外网通过任意节点的物理机IP:端口来访问服务。应用方式:外服访问服务
操作如下:
1)暴露nginx端口
首先创建deployment
[root@k8s-master1 deployment.yaml.d]# vim deployment.yaml
[root@k8s-master1 deployment.yaml.d]# cat deployment.yaml
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
namespace: default
spec:
selector:
matchLabels:
app: nginx
replicas: 2
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: registry.cn-chengdu.aliyuncs.com/liumuquan_app/nginx:1.20.1
ports:
- containerPort: 80
[root@k8s-master1 deployment.yaml.d]# kubectl apply -f deployment.yaml
deployment.apps/nginx-deployment created
创建service文件并以nodeport的方式暴露端口
[root@k8s-master1 deployment.yaml.d]# vim nginx-svc.yaml
[root@k8s-master1 deployment.yaml.d]# cat nginx-svc.yaml
---
apiVersion: v1
kind: Service
metadata:
name: mysvc
spec:
type: NodePort #类型
ports:
- port: 8080 #ClusterIP的端口(可以理解为service产生的ip)
nodePort: 30001 #node节点暴露的端口
targetPort: 80 #pod的端口
selector: #选择器
app: nginx
创建svc(service)
[root@k8s-master1 deployment.yaml.d]# kubectl apply -f nginx-svc.yaml
service/mysvc created
[root@k8s-master1 deployment.yaml.d]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 11d
mysvc NodePort 10.104.115.196 <none> 8080:30001/TCP 13s
[root@k8s-master1 deployment.yaml.d]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-deployment-5c5f7b5898-25jxx 1/1 Running 0 11m 10.244.1.20 k8s-node1 <none> <none>
nginx-deployment-5c5f7b5898-r2dfb 1/1 Running 0 11m 10.244.2.14 k8s-node2 <none> <none>
[root@k8s-master1 deployment.yaml.d]# kubectl get endpoints
NAME ENDPOINTS AGE
kubernetes 192.168.188.101:6443 11d
mysvc 10.244.1.20:80,10.244.2.14:80 34m
service的工作原理:
如上文所示:
svc产生的CLUSTER-IP | 10.104.115.196 |
pod的ip | 10.244.1.20,10.244.2.14 |
node的ip | 192.168.188.102,192.168.188.103 |
根据文件配置node暴露出来的端口号为30001(可选范围30000-32767),pod此时提供nginx服务端口为默认的80,与其映射(对接)CLUSTER-IP端口为8080(可在正常范围内随意设置但不可重复)。
浏览器访问node的30001端口,请求会被转发到CLUSTER-IP的8080端口,然后被转发到名为endpoint的地址池内,地址池内包含标签为app:nginx的pod的ip+端口号,在地址池内pod的选择默认为轮询转发。
此时访问node的30001端口可以直接访问pod内nginx服务
2)暴露tomcat端口
[root@k8s-master1 deployment.yaml.d]# kubectl delete svc mysvc
service "mysvc" deleted
[root@k8s-master1 deployment.yaml.d]# kubectl delete deploy nginx-deployment
deployment.apps "nginx-deployment" deleted
[root@k8s-master1 deployment.yaml.d]# vim tomcat_deploy_svc.yaml
[root@k8s-master1 deployment.yaml.d]# cat tomcat_deploy_svc.yaml
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: tomcat-deployment
namespace: default
spec:
selector:
matchLabels:
app: tomcat
replicas: 2
template:
metadata:
labels:
app: tomcat
spec:
containers:
- name: tomcat
image: registry.cn-chengdu.aliyuncs.com/liumuquan_app/tomcat:8.5.100-jre8
ports:
- containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
name: tomcat-svc
spec:
type: NodePort
ports:
- port: 9527
nodePort: 30002
targetPort: 8080
selector:
app: tomcat
创建deploy和svc
[root@k8s-master1 deployment.yaml.d]# kubectl apply -f tomcat_deploy_svc.yaml
物理机浏览器访问node的30002端口(服务已经正常搭建,这个镜像为精简版所以显示404)
3.3、LoadBalancer
在NodePort基础之上,提供外部负载均衡器与外网统一IP,此IP可以将请求转发到对应服务上。这个是各个云厂商提供的服务。应用方式:公网访问服务。这个因为没有公网ip所以这里只给出配置方式
apiVersion: v1
kind: Service
metadata:
name: loadbalance-test
spec:
ports:
- name: loadbalance-port
#service对外提供的端口
port: 80
# 代理的容器的端口
targetPort: 80
# 在物理机上开辟的端口,从30000开始
nodePort: 32138
selector:
app: nginx
type: LoadBalancer
status:
loadBalancer:
ingress:
- ip: 云厂商LoadbalanceIP
外部访问时直接访问公网IP即可直达服务。
3.4、ExternalName
引入集群外部的服务,可以在集群内部通过别名方式访问
(通过serviceName.namespaceName.svc.cluster.local访问)
apiVersion: v1
kind: Service
metadata:
name: service-ext
spec:
type: ExternalName
# 引入外部服务
externalName: baidu.com
3.5、Headless Service
上面我们讲解了service的使用方法和实现逻辑,主要就是代理一组pod容器提供负载均衡以及反向代理服务。但是有时候我们不需要这种负载均衡,比如下面的两个场景:
- K8S部署某个kafka集群,此时就不需要service来负载均衡,客户端需要的是一组pod所有ip的列表。
- 客户端自己处理负载均衡的逻辑,比如K8S部署两个mysql,客户端自己处理负载请求,或者根本不处理这种负载,就要两套mysql然后手动控制读写请求。
基于上面的两个场景,K8S提供了headless serivce功能,字面意思是无头service,其实就是该service不显式的对外提供IP。
headless service一般结合StatefulSet控制器来部署有状态的应用,比如大数据组件或者nosql数据库等,这种分布式的系统需要headless service来获取所有节点ip的列表供业务场景使用。
4、容器监控检查及恢复机制
在 k8s 中,可以为 Pod 里的容器定义一个健康检查"探针"(Probe)。kubelet 就会根据这个 Probe 的返回值决定这个容器的状态,而不是直接以容器是否运行(来自 Docker 返回的信息)作为依据。这种机制,是生产环境中保证应用健康存活的重要手段。
[root@k8s-master1 deployment.yaml.d]# vim test-liveness-exec.yaml
[root@k8s-master1 deployment.yaml.d]# cat test-liveness-exec.yaml
---
apiVersion: v1
kind: Pod
metadata:
labels:
test: liveness
name: test-liveness-exec
spec:
containers:
- name: liveness
image: registry.cn-chengdu.aliyuncs.com/liumuquan_app/nginx
args: #传参执行下面命令
- /bin/sh
- -c
- touch /tmp/healthy; sleep 30; rm -rf /tmp/healthy; sleep 50
livenessProbe: #探针,健康检查
exec: #类型
command: #命令
- cat
- /tmp/healthy #结合下面的参数,每隔五秒查看文件是否存在,如果不在了pod异常
initialDelaySeconds: 5 #健康检查,在容器启动 5 s 后开始执行
periodSeconds: 5
创建并观察pod状态(注意看重启位置数字变化)
[root@k8s-master1 deployment.yaml.d]# kubectl apply -f test-liveness-exec.yaml
[root@k8s-master1 deployment.yaml.d]# kubectl get pod
刚创建
NAME READY STATUS RESTARTS AGE
test-liveness-exec 1/1 Running 0 18s
删除文件命令启动后
NAME READY STATUS RESTARTS AGE
test-liveness-exec 1/1 Running 1 75s
查看pod事件
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 4m7s default-scheduler Successfully assigned default/test-liveness-exec to k8s-node1
Normal Pulled 4m6s kubelet, k8s-node1 Successfully pulled image "registry.cn-chengdu.aliyuncs.com/liumuquan_app/nginx" in 634.594286ms
Normal Pulled 2m54s kubelet, k8s-node1 Successfully pulled image "registry.cn-chengdu.aliyuncs.com/liumuquan_app/nginx" in 588.01354ms
Normal Created 99s (x3 over 4m6s) kubelet, k8s-node1 Created container liveness
Normal Started 99s (x3 over 4m6s) kubelet, k8s-node1 Started container liveness
Normal Pulled 99s kubelet, k8s-node1 Successfully pulled image "registry.cn-chengdu.aliyuncs.com/liumuquan_app/nginx" in 604.298548ms
Warning Unhealthy 54s (x9 over 3m34s) kubelet, k8s-node1 Liveness probe failed: cat: /tmp/healthy: No such file or directory
Normal Killing 54s (x3 over 3m24s) kubelet, k8s-node1 Container liveness failed liveness probe, will be restarted
注意:
- Kubernetes 中并没有 Docker 的 Stop 语义。所以虽然显示 Restart(重启),但实际却是重新创建了容器。
- Pod 的恢复过程,永远都是发生在当前节点上,而不会跑到别的节点上去。事实上,一旦一个 Pod 与一个节点(Node)绑定,除非这个绑定发生了变化(pod.spec.node 字段被修改),否则它永远都不会离开这个节点。
http get方式探针
通过http访问主页面查看容器状态是否健康
配置如下
---
apiVersion: v1
kind: Pod
metadata:
name: liveness-httpget-pod
namespace: default
spec:
containers:
- name: liveness-exec-container
image: registry.cn-chengdu.aliyuncs.com/liumuquan_app/nginx
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
name: http #名称
livenessProbe: #探针,健康检查
httpGet:
port: http #与上方名称对应
path: /index.html #使用http访问的路径,作为检查标准
initialDelaySeconds: 1
periodSeconds: 3
创建pod查看详情
[root@k8s-master1 deployment.yaml.d]# kubectl describe pod liveness-httpget-pod
登陆容器将容器内的检测文件(nginx主页移除)
[root@k8s-master1 deployment.yaml.d]# kubectl exec -it liveness-httpget-pod /bin/bash
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
root@liveness-httpget-pod:/# mv /usr/share/nginx/html/index.html 111.txt
移除后自动退出,容器已经重建
root@liveness-httpget-pod:/# command terminated with exit code 137
[root@k8s-master1 deployment.yaml.d]#
再次查看pod详情
[root@k8s-master1 deployment.yaml.d]# kubectl get pod
NAME READY STATUS RESTARTS AGE
liveness-httpget-pod 1/1 Running 1 6m48s
此时再次登陆查看,发现文件又出现了,证明并非“RESTART”,而是重建
[root@k8s-master1 deployment.yaml.d]# kubectl exec -it liveness-httpget-pod /bin/bash
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
root@liveness-httpget-pod:/# ls /usr/share/nginx/html/
50x.html index.html