kubernetes不常用但是很有用的命令-常用必备
一、利用 PreStop 钩子实现 Pod 优雅关闭
在发布版本是,有没有遇到500错误问题?原因是部分流量被路由到了Terminating状态的pod上,但Pod里的应用已经不接受新的请求。
这不是代码问题,而是pod下线的时序问题。
删除pod时,同时会做两件事:
- 把pod ip从Endpoint里摘掉。
- kubec-proxy更新iptables规则和pod收到SIGTERM信号开始关闭进程
如果这两件事不同步,流量就可能会打到正在关闭的Pod上。
解决方法很简单:
加一个PreStop钩子,在下线前sleep一会儿,给网络规则更新流出时间窗口。
lifecycle:
preStop:
exec:
# 先优雅停nginx,在sleep30s等待网络规则同步
command: ["/bin/sh", "-c", "sleep 25 && nginx -s quit"]
二、使用临时容器快速调试异常Pod
很多业务镜像为了安全精简,连bash都没有。Pod起不来或者跑着跑着不对劲了。想进去排查,然后发现各种命令无法使用,如:ping,curl等等。
有一种做法事尝试安装调试工具或者重新制作调试镜像,进行部署。最后发现现场早就没有了。
在k8s 1.23之后新增了临时容器(Ephemeral Containers)。不用重启Pod,直接在运行的Pod里原地注入一个带调试工具的容器,共享一个进程命名空间和网络命名空间。
# kubectl debug mypod -it --image=busybox -n namespace
这个调试容器会跑在Pod里,你可以用busybox里的各种工具去排查问题。用完退出即可。调试容器会自动清理,不污染业务容器。
三、kubectl debug原生调试容器,镜像无需再预装工具
临时容器适合原地诊断,不重启Pod,直接往里塞个调试工具,用完就走。
有限场景它搞不定。比如怀疑环境变量配错或者启动命令不对导致pod无法启动柜,这种就要在Pod启动阶段敢于了。使用临时容器肯定不行:pod没有启动,出现无法注入问题。
这时候换kubectl debug的pod复制模式:
# 复制一个pod,把业务容器镜像换成调试镜像
# kubectl debug mypod -it --copy-to=my-debugger --set-image=*=busybox
这个命令会基于原pod的配置复制出一个新Pod,但把镜像换成你指定的调试镜像。你可以改变环境变量、调启动参数、换镜像版本,在新pod上随便折腾,不影响原Pod。
四、port-forward本地端口转发,直连集群内部服务
在某些场景,只想本地连下集群里的MySQL或者Redis看看数据,不想把他暴漏成NodePort或者LoadBalancer给全网访问。
kubectl pod-forward就是干这个的。
# 把本地3306端口转发到集群里mysql pod的3306端口
# kubectl port-forward pod/mysql-pod 3306:3306
# 转发到service
# kubectl port-forward service/mysql-svc 3306:3306
然后再本地使用mysql -h 127.0.0.1 -P 3306 -u root -p就能连上集群里的数据库。
五、--previous看CrashLoopBackOff前最后一眼
Podu已知在CrashLoopBackOff重启,kubectl logs看到的永远是当前容器的日志,刚启动就挂了,还没有输出什么内容。真正的错误日志还在上一个容器里。
这个时候使用--previous或者-p参数:
# kubectl logs mypod --previous
这个命令会显示上一个容器的标准输出和标准错误,里面往往会有应用启动失败的真实原因。
六、StartupProbe启动探针,避免慢启动应用被误杀重启
有些应用启动特别慢,如:java。如果用传统的livenessProbe和readinessProbe,启动过程中探针失败几次就会被k8s判定为不健康,然后重启pod;越重启越起不来的死循环。
startProbe就是救这个的。
startupProbe在Pod启动阶段生效,只有他通过了,livenessProbe和readinessProbe才开始工作。
startupProbe:
httpGet:
path: /healthz
port: 8080
failureThreshold: 30 #允许失败30次
periodSeconds: 5 #每5s探测一次
上面这个配置给了应用最多150s(30x5)的启动时间,完全够一个java应用慢慢起来。
七、CRD自定义资源扩展k8s集群能力
k8s的核心设计是声明式API,你告诉它“想要的最终状态”,控制器负责把实际状态往这个方向赶。
CRD(CustomResourceDefinition)就是让你自己定义“想要的最终状态”长什么样。
比如想要管理一台数据库集群,可以定义一个MySQLCluster资源;
apiVersuib: db.example.io/v1
kind: MySQLCluster
metadata:
name: my-cluster
spec:
replicas: 3
version: 8.0
storage: 100Gi
然后写一个控制器(用Operator SDK或Kubebuilder),监听这个CRD的增删改,自己去创建StatefulSet、service、PV等底层资源。
想扩展k8s能力,CRD是基本功。
更多推荐


所有评论(0)