有时候,应用因为无限循环或死锁而停止响应,为确保应用在这种情况下可以重新启动,需要有一种机制检查应用程序的运行状况,而不是依赖应用程序内部的检测。
K8s 主要提供了三种探针来针对这种机制:
- 存活探针:用于检查容器是否正在运行。如果存活探针失败,则 K8s 认为该容器已死亡,并且将尝试重新启动容器。
- 就绪探针:用于检查容器是否已准备好接收流量。如果容器没有准备好,K8s 将不会将流量路由到该容器。
- 启动探针:用于检查容器是否已启动。与存活探针不同,启动探针在容器启动时运行一次,而不是在容器运行时持续运行。
探针的检查方法
- exec:通过在容器内执行指定命令,来判断命令退出时返回的状态码,返回状态码是0表示正常。
- httpGet:通过对容器的 IP 地址、端口和 URL 路径来发送 GET 请求;如果响应的状态码在 200 ~ 399 间,表示正常。
- tcpSocket:通过对容器的 IP 地址和指定端口,进行 TCP 检查,如果端口打开,发起 TCP Socket 建立成功,表示正常。
配置项
- initialDelaySeconds:等待我们定义的时间 结束后便开始探针检查
- periodSeconds:探针的间隔时间
- timeoutSeconds:探针的超时时间,当超过我们定义的时间后,便会被视为失败
- successThreshold:探针的最小连续成功数量
- failureThreshold:探针的最小连续失败数量
启动探针
apiVersion: v1 # 必选 API的版本号
kind: Pod # 必选 类型Pod
metadata: # 必选 元数据
name: nginx # 必选 符合RFC 1035规范的Pod名称
#namespace: default # 可选 Pod所在的命名空间 不指定默认为default 可以使用-n指定namespace
labels: # 可选 标签选择器 一般用于过滤和区分Pod
app: nginx-ready
spec: # 必选 用于定义容器的详细信息
containers: # 必选 容器列表
- name: nginx # 必选 符合RFC 1035规范的容器名称
image: nginx:latest # 必选 容器所用的镜像的地址
imagePullPolicy: Always # 可选 镜像拉取策略 IfNotPresent:如果宿主机有这个镜像,就不用拉取了 Always:总是拉取 Never:不管存在不存在,都不拉取
ports: # 可选 容器需要暴露的端口号列表
- name: http # 端口名称
containerPort: 80 # 端口号
protocol: TCP # 端口协议 默认TCP
startupProbe: # 可选 检测容器内进程是否完成启动 注意三种检查方式同时只能使用一种
failureThreshold: 3 # 失败三次算探针失败
exec:
command: ['/bin/sh','-c','echo Hello World']
initialDelaySeconds: 3 # 容器启动完成后首次探测的时间,单位为秒
timeoutSeconds: 2 # 对容器健康检查探测等待响应的超时时间,单位秒,默认1秒
periodSeconds: 1 # 对容器监控检查的定期探测时间设置,单位秒,默认10秒一次
successThreshold: 1 # 成功1次算探针OK
failureThreshold: 3 # 失败三次算探针失败
restartPolicy: Always # 可选 默认Always 容器故障或者没有启动成功 自动重启该容器 Onfailure: 容器以不为0的状态码终止 自动重启该容器 Never:无论何种状态 都不会重启
# kubectl apply -f pod.yaml
pod/nginx created
# kubectl get pod
NAME READY STATUS RESTARTS AGE
nginx 0/1 ContainerCreating 0 4s
# kubectl describe pod nginx
就绪探针
# grep -v '^#' pod.yaml
apiVersion: v1 # 必选 API的版本号
kind: Pod # 必选 类型Pod
metadata: # 必选 元数据
name: nginx # 必选 符合RFC 1035规范的Pod名称
#namespace: default # 可选 Pod所在的命名空间 不指定默认为default 可以使用-n指定namespace
labels: # 可选 标签选择器 一般用于过滤和区分Pod
app: nginx-ready
spec: # 必选 用于定义容器的详细信息
containers: # 必选 容器列表
- name: nginx # 必选 符合RFC 1035规范的容器名称
image: nginx:latest # 必选 容器所用的镜像的地址
imagePullPolicy: Always # 可选 镜像拉取策略 IfNotPresent:如果宿主机有这个镜像,就不用拉取了 Always:总是拉取 Never:不管存在不存在,都不拉取
ports: # 可选 容器需要暴露的端口号列表
- name: http # 端口名称
containerPort: 80 # 端口号
protocol: TCP # 端口协议 默认TCP
readinessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 3 # 容器启动完成后首次探测的时间,单位为秒
timeoutSeconds: 2 # 对容器健康检查探测等待响应的超时时间,单位秒,默认1秒
periodSeconds: 1 # 对容器监控检查的定期探测时间设置,单位秒,默认10秒一次
successThreshold: 1 # 成功1次算探针OK
failureThreshold: 3 # 失败三次算探针失败
restartPolicy: Always # 可选 默认Always 容器故障或者没有启动成功 自动重启该容器 Onfailure: 容器以不为0的状态码终止 自动重启该容器 Never:无论何种状态 都不会重启
可以看到端口检测正常
添加 nodeport 类型进行流量访问验证
# grep -v '^#' pod.yaml
apiVersion: v1 # 必选 API的版本号
kind: Pod # 必选 类型Pod
metadata: # 必选 元数据
name: nginx # 必选 符合RFC 1035规范的Pod名称
#namespace: default # 可选 Pod所在的命名空间 不指定默认为default 可以使用-n指定namespace
labels: # 可选 标签选择器 一般用于过滤和区分Pod
app: nginx-ready
spec: # 必选 用于定义容器的详细信息
containers: # 必选 容器列表
- name: nginx # 必选 符合RFC 1035规范的容器名称
image: nginx:latest # 必选 容器所用的镜像的地址
imagePullPolicy: Always # 可选 镜像拉取策略 IfNotPresent:如果宿主机有这个镜像,就不用拉取了 Always:总是拉取 Never:不管存在不存在,都不拉取
ports: # 可选 容器需要暴露的端口号列表
- name: http # 端口名称
containerPort: 80 # 端口号
protocol: TCP # 端口协议 默认TCP
readinessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 3 # 容器启动完成后首次探测的时间,单位为秒
timeoutSeconds: 2 # 对容器健康检查探测等待响应的超时时间,单位秒,默认1秒
periodSeconds: 1 # 对容器监控检查的定期探测时间设置,单位秒,默认10秒一次
successThreshold: 1 # 成功1次算探针OK
failureThreshold: 3 # 失败三次算探针失败
restartPolicy: Always # 可选 默认Always 容器故障或者没有启动成功 自动重启该容器 Onfailure: 容器以不为0的状态码终止 自动重启该容器 Never:无论何种状态 都不会重启
---
apiVersion: v1
kind: Service
metadata:
name: ready-nodeport
labels:
name: ready-nodeport
spec:
type: NodePort
ports:
- port: 88
protocol: TCP
targetPort: 80
nodePort: 30880
selector:
app: nginx-ready
访问验证
# kubectl get pod
NAME READY STATUS RESTARTS AGE
nginx 1/1 Running 0 15s
[root@k8s-master01 ~]# kubectl get svc -owide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 72d <none>
ready-nodeport NodePort 10.96.93.159 <none> 88:30880/TCP 20s app=nginx-ready
[root@k8s-master01 ~]# curl http://192.168.10.10:30880
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
修改 httpGet 或 tcpSocket 端口为 81 模拟探针探测失败,探测失败流量会不会分配进入
# kubectl get pod
NAME READY STATUS RESTARTS AGE
nginx 0/1 Running 0 22s
# kubectl get svc -owide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 72d <none>
ready-nodeport NodePort 10.96.115.11 <none> 88:30880/TCP 25s app=nginx-ready
[root@k8s-master01 ~]# curl http://192.168.10.10:30880
curl: (7) Failed connect to 192.168.10.10:30880; 拒绝连接
describe nginx查看
显示81端口不通,ready状态为0,但pod是running的,请求结果为拒绝连接,流量打入失败。就绪探针失败,是不会给该pod打入流量的。
存活探针
# grep -v '^#' pod.yaml
apiVersion: v1 # 必选 API的版本号
kind: Pod # 必选 类型Pod
metadata: # 必选 元数据
name: nginx # 必选 符合RFC 1035规范的Pod名称
#namespace: default # 可选 Pod所在的命名空间 不指定默认为default 可以使用-n指定namespace
labels: # 可选 标签选择器 一般用于过滤和区分Pod
app: nginx-ready
spec: # 必选 用于定义容器的详细信息
containers: # 必选 容器列表
- name: nginx # 必选 符合RFC 1035规范的容器名称
image: nginx:latest # 必选 容器所用的镜像的地址
imagePullPolicy: Always # 可选 镜像拉取策略 IfNotPresent:如果宿主机有这个镜像,就不用拉取了 Always:总是拉取 Never:不管存在不存在,都不拉取
ports: # 可选 容器需要暴露的端口号列表
- name: http # 端口名称
containerPort: 80 # 端口号
protocol: TCP # 端口协议 默认TCP
livenessProbe:
httpGet:
path: /
port: 80
scheme: HTTP
initialDelaySeconds: 3 # 容器启动完成后首次探测的时间,单位为秒
timeoutSeconds: 2 # 对容器健康检查探测等待响应的超时时间,单位秒,默认1秒
periodSeconds: 1 # 对容器监控检查的定期探测时间设置,单位秒,默认10秒一次
successThreshold: 1 # 成功1次算探针OK
failureThreshold: 3 # 失败三次算探针失败
restartPolicy: Always # 可选 默认Always 容器故障或者没有启动成功 自动重启该容器 Onfailure: 容器以不为0的状态码终止 自动重启该容器 Never:无论何种状态 都不会重启
---
apiVersion: v1
kind: Service
metadata:
name: ready-nodeport
labels:
name: ready-nodeport
spec:
type: NodePort
ports:
- port: 88
protocol: TCP
targetPort: 80
nodePort: 30880
selector:
app: nginx-ready
创建 pod 与 service 并访问测试
# kubectl apply -f pod.yaml
pod/nginx created
service/ready-nodeport created
[root@k8s-master01 ~]# kubectl get pod
NAME READY STATUS RESTARTS AGE
nginx 1/1 Running 0 4s
# kubectl get svc -owide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 72d <none>
ready-nodeport NodePort 10.96.54.68 <none> 88:30880/TCP 12s app=nginx-ready
[root@k8s-master01 ~]# curl 192.168.10.10:30880
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
修改检测端口为81,模拟检测失败
探针检测失败会根据 restartPolicy
重启策略操作
默认 Always 容器故障或者没有启动成功 自动重启该容器
重新创建该 pod
# kubectl get pod
NAME READY STATUS RESTARTS AGE
nginx 1/1 Running 0 4s
# kubectl get svc -owide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 72d <none>
ready-nodeport NodePort 10.96.54.68 <none> 88:30880/TCP 7m28s app=nginx-ready
# curl http://192.168.10.10:30880
curl: (7) Failed connect to 192.168.10.10:30880; 拒绝连接
查看 pod是否进行重启,可以看到pod已经重启5次,状态也变为CrashLoopBackOff
后续
当然,除了探针,Kubernetes 还有以下几种机制来确保容器的可用性:
RC
或ReplicaSet
:用于确保在集群中运行指定数量的 Pod。如果 Pod 在节点上失败或被删除,则 RC 或 ReplicaSet 将启动新的 Pod 来代替它们。- Deployment:用于管理 Pod 和 ReplicaSet 的更新。Deployment 可以在进行滚动更新时确保应用程序的可用性,并提供回滚机制以恢复到以前的版本。
- Service:用于将流量路由到运行中的 Pod。Service 为应用程序提供了一个稳定的 IP 地址和 DNS 名称,并可以将流量根据需要负载均衡到多个 Pod 中。
- Namespace:用于隔离和组织集群中的资源。通过使用 Namespace,可以将不同的应用程序或团队隔离开来,并控制它们可以访问的资源。