k8s timeoutSeconds无效且没有按照periodSeconds的间隔时间来执行健康检查
健康检查日志没有严格按照periodSeconds间隔时间来打印。
核心代码如下:
pkg/kubelet/prober/worker.go
pkg/kubelet/prober/prober.go
runProbe方法(kubelet健康检查有3种方式)
httpGet
发送HTTP 请求,返回码介于 200~400 之间(前闭后开)时检查成功。
exec
容器中执行命令,当命令执行成功(返回码为 0)时检查成功。
tcpSocket
当 TCP 连接容器中的指定 TCP 端口成功时,检查成功。
doProbe函数的调用过程是串行的,一旦执行了健康检查,必须等到结果才能执行下一次健康检查。如果健康检查执行时间比较长,那么上一次健康检查执行完,很快就会触发下一次健康检查。
模拟的无状态应用yaml文件:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deploy
namespace: default
labels:
app: nginx
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.7.9
args:
- /bin/sh
- -c
- touch /root/wjq.log; touch /root/wjq.sh; chmod -R 777 /root/*; echo "echo 'begin' >> /root/wjq.log; date '+%Y-%m-%d %H:%M:%S' >> /root/wjq.log; sleep 300; date '+%Y-%m-%d %H:%M:%S' >> /root/wjq.log; echo 'end' >> /root/wjq.log" >> /root/wjq.sh; sleep 3000
livenessProbe:
exec:
command:
- bash
- /root/wjq.sh
initialDelaySeconds: 10
periodSeconds: 5
timeoutSeconds: 2
failureThreshold: 3
ports:
- containerPort: 80
securityContext:
runAsUser: 0
k8s v1.19.0版本日志输出
情况1:健康检查脚本耗时300s
脚本间隔122s执行,只考虑开始执行时间,忽略end
打印开始执行时间
情况2:健康检查脚本耗时30s
sleep 300改成sleep 30,结果和k8s 1.15.0版本保持一致
k8s v1.15.0版本日志输出(脚本执行时间达到30s,包含了多个5s的periodSeconds,紧挨着执行)
begin
2023-07-30 07:51:46
2023-07-30 07:52:16
end
begin
2023-07-30 07:52:16
2023-07-30 07:52:46
end
begin
2023-07-30 07:52:47
2023-07-30 07:53:17
end
begin
2023-07-30 07:53:17
2023-07-30 07:53:47
end
逻辑改变
pkg/probe/exec/exec.go
Probe方法
直接Run一直等命令结束(v1.15.0)->先start再wait超时后强制命令结束(v1.19.0)
pkg/kubelet/cri/remote/remote_runtime.go
ExecSync方法
超时时间是2分钟+自定义的超时时间即122s,使得看上去不是挨着执行
改成不加2分钟
脚本耗时30s,按照配置2秒就中断
类似于CommandContext方法
package main
import (
"context"
"fmt"
"os/exec"
"time"
)
func main() {
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()
cmd := exec.CommandContext(ctx, "/bin/sleep", "10")
out, err := cmd.CombinedOutput()
fmt.Printf("ctx.Err : [%v]\n", ctx.Err())
fmt.Printf("error : [%v]\n", err)
fmt.Printf("out : [%s]\n", string(out))
}