如何用kubectl等待CRD创建?脚本前检查CRD存在的最优方案
嗨,我明白你在CI管道里遇到的麻烦了——第一个脚本部署的NATS operator会创建CRD,第二个脚本必须等这些CRD彻底就绪才能成功运行,而且CI还会多次跑第二个脚本对吧?之前用kubectl wait没找对条件,我来给你几个靠谱的解决方案:
方法一:精准等待单个CRD的就绪条件
CRD的就绪其实依赖两个核心状态:Established(API服务器已认可该CRD,能处理对应的自定义资源请求)和NamesAccepted(CRD的命名没有冲突,符合规范)。你只需要针对目标CRD,等待这两个条件都变为True就行。
假设NATS operator创建的CRD是natsclusters.nats.io(你可以先跑第一个YAML后用kubectl get crds确认实际名称),对应的命令是:
kubectl wait --for=condition=Established --for=condition=NamesAccepted crd/natsclusters.nats.io --timeout=5m
这个命令会一直阻塞,直到CRD满足两个就绪条件,或者到5分钟超时退出,刚好适配CI的场景——等CRD就绪后再执行第二个脚本的kubectl apply -f 2.nats-cluster.yaml。
方法二:批量等待多个CRD(适合不确定CRD名称的场景)
如果你的operator会创建多个CRD,或者不想硬编码CRD名称,可以写个简单的bash循环脚本,定期检查所有目标CRD的状态:
#!/bin/bash # 定义CRD的名称前缀(比如NATS的CRD通常带nats关键字) CRD_NAME_PREFIX="nats" # 设置超时时间(单位:秒) MAX_WAIT_TIME=300 START_TIMESTAMP=$(date +%s) while true; do # 获取所有匹配前缀的CRD数量 total_crds=$(kubectl get crds -o jsonpath='{range .items[?(@.metadata.name contains "'$CRD_NAME_PREFIX'")]}{.metadata.name}{"\n"}{end}' | wc -l) if [ $total_crds -eq 0 ]; then echo "还没检测到目标CRD,继续等待..." sleep 5 continue fi # 获取已经满足两个就绪条件的CRD数量 ready_crds=$(kubectl get crds -o jsonpath='{range .items[?(@.metadata.name contains "'$CRD_NAME_PREFIX'")]}{.metadata.name}{"\t"}{.status.conditions[?(@.type=="Established")].status}{"\t"}{.status.conditions[?(@.type=="NamesAccepted")].status}{"\n"}{end}' | grep -E "True\tTrue" | wc -l) if [ $ready_crds -eq $total_crds ]; then echo "所有目标CRD都已就绪!" exit 0 fi # 检查是否超时 current_timestamp=$(date +%s) elapsed_time=$((current_timestamp - START_TIMESTAMP)) if [ $elapsed_time -ge $MAX_WAIT_TIME ]; then echo "等待CRD就绪超时,已等待${MAX_WAIT_TIME}秒" exit 1 fi echo "已等待${elapsed_time}秒,还有$((total_crds - ready_crds))个CRD未就绪..." sleep 5 done
把这个脚本放在第一个kubectl apply之后、第二个脚本之前执行,就能确保CRD全部就绪后再继续。
为什么你之前的尝试不对?
你之前用的--for=condition=complete是针对Job、Pod这类资源的完成状态,CRD根本没有这个条件,所以才会失效。CRD的就绪判断必须用Established和NamesAccepted这两个专属条件哦。
内容的提问来源于stack exchange,提问作者NealR

