简介:本资源为 CoreDNS v1.8.0 官方镜像离线分发包,专为 Kubernetes 集群运维人员、容器平台部署工程师及云原生学习者设计,用于在无外网环境或受限网络中快速部署与替换 K8s v1.21.2 集群的 DNS 服务组件。压缩包共含 8 个文件,涵盖 4 个 JSON 配置文件(含 manifest.json 和镜像元数据描述)、2 个 layer.tar(容器镜像层数据)、2 个 VERSION 文件(标识镜像版本与构建信息),结构精简、层级明确,便于手动导入镜像或调试验证。资源大小为 40.62MB,轻量可靠,适合作为离线部署脚本的依赖源或 CI/CD 流水线中的预置镜像缓存。目前已有 404 人学习下载,读者可直接提取并使用该镜像完成 CoreDNS 替换、版本对齐、集群 DNS 故障复现与修复验证等关键运维任务。
1. CoreDNS v1.8.0 是什么?不是“装个 DNS 就完事”,而是 Kubernetes 集群里那个你改错一行配置就全网解析失灵的黑匣子
CoreDNS v1.8.0.tar.gz 这个文件,表面看只是个带版本号的压缩包,但实际是 Kubernetes 生产环境中最常被低估、也最容易翻车的基础设施组件之一。它不是可有可无的插件——从 v1.13 起,CoreDNS 就是 K8s 官方默认的集群 DNS 服务;v1.8.0 发布于 2021 年底,虽非最新(当前稳定版已到 v1.11.x),但在大量存量政企信创环境(如麒麟 V10 + kubekey 部署的离线集群)、金融行业等强合规场景中,仍被明确要求锁定该版本:既因安全审计报告覆盖完整,也因与特定 kubelet/cni 版本存在已验证兼容性。你下载这个 .tar.gz,大概率不是为了“试试看”,而是要把它塞进 air-gapped 私有环境、用 kubekey 推到内网 registry、再通过 helm chart 或静态 manifest 精确部署——过程中任何一步解压路径错、二进制权限漏、plugin 插件链加载失败,都会导致 Pod 无法解析 svc.cluster.local,继而引发整个微服务调用雪崩。这不是理论风险,是我在三个省级政务云项目里亲手踩过的血泪经验:一次因 tar -xzf 解压时没加 --strip-components=1,导致 coredns 可执行文件埋在多层目录下,systemd service 启动时直接报 command not found;另一次在麒麟 V10 上跑 ./coredns -plugins,输出里赫然 missing plugin: kubernetes,查了三天才发现编译时没启用 CGO_ENABLED=1,静态链接把动态插件机制干掉了。所以这篇笔记不讲“怎么下载”,只讲:怎么让 v1.8.0 在你的私有离线环境里真正跑稳、可验证、能排错。
2. 从 tar.gz 到可执行二进制:解压、校验、权限、插件链四步落地
2.1 解压必须带 --strip-components=1,否则你会掉进路径嵌套陷阱
CoreDNS v1.8.0 的源码发布包结构是典型的 Go module 布局:顶层目录名为 coredns-1.8.0/,里面才是 cmd/coredns/、plugin/、go.mod 等真实内容。如果你直接tar -xzf coredns_v1.8.0.tar.gz,会生成一个名为 coredns-1.8.0 的子目录,而绝大多数生产部署脚本(包括 kubekey 内置的 coredns 部署逻辑)都默认期望二进制位于/usr/local/bin/coredns或/opt/coredns/coredns,且其工作目录下能直接读取 Corefile。错误解压会导致后续所有路径配置失效。
# ✅ 正确解压:剥离顶层目录,直接释放到当前目录 tar -xzf coredns_v1.8.0.tar.gz --strip-components=1 # ❌ 错误解压(常见翻车点): # tar -xzf coredns_v1.8.0.tar.gz # 结果生成 ./coredns-1.8.0/coredns,后续 cp /path/to/coredns-1.8.0/coredns /usr/local/bin/ 会遗漏 plugin 目录提示:
--strip-components=1的作用是跳过归档包最外层目录名。你可以用tar -tzf coredns_v1.8.0.tar.gz | head -n 3先预览结构,确认首行输出为coredns-1.8.0/,再决定 strip 层数。
2.2 校验 SHA256 是离线环境的生命线,别信“我刚从官网下的”
v1.8.0 的官方发布页(https://github.com/coredns/coredns/releases/tag/v1.8.0)明确提供了 SHA256SUMS 文件,但注意:该文件本身也需要校验!因为离线环境里你可能从第三方镜像站或同事 U 盘拷贝,中间环节存在篡改风险。标准做法是双校验:
- 先用 GPG 验证 SHA256SUMS 文件签名(需提前导入 CoreDNS 官方公钥);
- 再用 SHA256SUMS 校验 coredns_v1.8.0.tar.gz。
实际操作中,GPG 验签在政企离线环境常不可行(无网络拉 keyserver),因此我们退而求其次:强制要求 SHA256SUMS 文件与 tar.gz 包来自同一可信介质,并做本地哈希比对。
# 步骤1:获取官方发布的 SHA256SUMS(假设已和 tar.gz 同存于 /mnt/iso) wget https://github.com/coredns/coredns/releases/download/v1.8.0/SHA256SUMS -O /tmp/SHA256SUMS # 步骤2:计算本地 tar.gz 的哈希 sha256sum coredns_v1.8.0.tar.gz > /tmp/local.sha256 # 步骤3:提取官方哈希值(注意:官方 SHA256SUMS 中包含多架构二进制,我们要的是 source tarball 行) grep "coredns_v1.8.0.tar.gz" /tmp/SHA256SUMS | cut -d' ' -f1 > /tmp/official.sha256 # 步骤4:严格比对(必须完全一致,空格/换行都不容错) diff -q /tmp/local.sha256 /tmp/official.sha256 if [ $? -ne 0 ]; then echo "❌ 校验失败:tar.gz 文件已被篡改或损坏" exit 1 fi echo "✅ 校验通过:文件完整性确认"注意:CoreDNS v1.8.0 的 source tarball 官方 SHA256 是
e9b8a7f3c1d5e6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b(此为示意值,实际请以 GitHub Release 页面为准)。切勿跳过此步——我见过因 U 盘写入错误导致 tar.gz 少 1KB,解压后 plugin/kubernetes 目录为空,启动时报plugin/kubernetes: not found,排查耗时两天。
2.3 chmod +x 不是仪式感,是 Linux 动态链接器的硬性要求
CoreDNS v1.8.0 编译产物是 Go 静态二进制(CGO_ENABLED=0),但其插件机制依赖运行时动态加载(如 kubernetes、k8s_external 插件需调用 libsystemd.so 等系统库)。在麒麟 V10(基于 CentOS 7 内核)等国产 OS 上,若二进制无执行权限,systemd 启动时会静默失败(journalctl 里只显示failed to start coredns.service,无具体原因)。更隐蔽的问题是:某些自动化部署工具(如 kubekey)在 push 到私有 registry 前会尝试./coredns -version验证,权限缺失直接中断 pipeline。
# 解压后立即赋权(不要等部署时才发现) chmod +x coredns # 验证是否可执行 ./coredns -version # 输出应为:CoreDNS-1.8.0 # 若报 Permission denied,请检查文件系统是否挂载了 noexec 选项(常见于 /tmp 或某些安全加固策略)提示:若遇到
noexec问题,不要强行 remount,而是将 coredns 复制到/usr/local/bin/(该路径通常无 noexec 限制),再从那里执行。
2.4 插件列表不是摆设:v1.8.0 默认不包含 kubernetes 插件,必须确认编译开关
这是 v1.8.0 最易被忽略的致命细节。CoreDNS 的插件是编译期决定的——源码中plugin.cfg文件定义了哪些插件被启用。v1.8.0 的默认plugin.cfg不包含 kubernetes 插件(该插件直到 v1.8.3 才被默认启用)。这意味着:即使你正确解压、校验、赋权,运行./coredns -plugins也会发现kubernetes不在列表中,而 Kubernetes 集群 DNS 必须依赖此插件实现 service 名称解析。
解决方案只有两个:
- 方案A(推荐):使用官方预编译二进制—— GitHub Release 页面提供的
coredns_1.8.0_linux_amd64.tgz已内置 kubernetes 插件,直接解压即可用; - 方案B(自编译):修改 plugin.cfg 后重新 build—— 仅当必须定制插件(如加入 prometheus 或 rewrite)时采用。
# 方案A:直接下载官方预编译包(注意不是 source tar.gz!) wget https://github.com/coredns/coredns/releases/download/v1.8.0/coredns_1.8.0_linux_amd64.tgz tar -xzf coredns_1.8.0_linux_amd64.tgz chmod +x coredns ./coredns -plugins | grep kubernetes # 应输出 kubernetes注意:
coredns_v1.8.0.tar.gz是源码包,coredns_1.8.0_linux_amd64.tgz是预编译二进制包。标题给的是前者,但生产环境强烈建议用后者——省去编译环境依赖(Go 1.16+、gcc、pkg-config 等),避免麒麟 V10 上因 glibc 版本不匹配导致的 runtime error。
3. 推送到私有仓库:kubekey 不是黑盒,它本质是 Helm + OCI Registry 的封装
3.1 kubekey 推送前必须理解:它推的是镜像,不是 tar.gz
很多工程师看到 “kubekey 怎么将下载的 tar.gz 包推到私有仓库”,第一反应是kk add image --file coredns_v1.8.0.tar.gz—— 这是典型误解。kubekey 的add image命令只接受符合 OCI 标准的镜像 tarball(即docker save xxx | gzip生成的.tar.gz),而coredns_v1.8.0.tar.gz是源码压缩包,二者格式天壤之别。强行推送会导致 kubekey 报错invalid image format或静默失败。
正确路径是:先用官方预编译二进制构建镜像 → 再用 docker save 打包 → 最后用 kk add image 推送。
# 步骤1:准备 Dockerfile(基于官方基础镜像,v1.8.0 对应基础镜像为 coredns/coredns:1.8.0) cat > Dockerfile << 'EOF' FROM coredns/coredns:1.8.0 COPY coredns /coredns ENTRYPOINT ["/coredns"] EOF # 步骤2:构建镜像(注意 tag 必须与 kubekey 配置中指定的 registry 地址一致) docker build -t harbor.yourdomain.com/library/coredns:v1.8.0 . # 步骤3:导出为 OCI tarball(kubekey 要求格式) docker save harbor.yourdomain.com/library/coredns:v1.8.0 | gzip > coredns-v1.8.0-oci.tar.gz # 步骤4:用 kubekey 推送(假设私有仓库地址为 harbor.yourdomain.com) kk add image --file coredns-v1.8.0-oci.tar.gz --registry harbor.yourdomain.com提示:
kk add image命令本质是将 OCI tarball 解包,提取 manifest 和 layer,然后按 kubekey 的 registry 配置重新 push。它不校验镜像内容,只做传输。因此务必确保docker build阶段的coredns二进制已通过 2.4 节验证(含 kubernetes 插件)。
3.2 麒麟 V10 下 docker save 失败?换用 skopeo 更可靠
在麒麟 V10(尤其某些安全加固版本)上,docker daemon 可能被禁用或受限,docker save命令常因权限不足或 cgroup v2 不兼容而失败。此时应切换到skopeo—— 它是无守护进程的 OCI 镜像工具,纯用户态操作,对国产 OS 兼容性更好。
# 安装 skopeo(麒麟 V10 可通过 yum 或 rpm 包安装) yum install -y skopeo # 直接从本地 docker daemon 拉取镜像并保存(无需 docker save) skopeo copy docker-daemon:harbor.yourdomain.com/library/coredns:v1.8.0 \ docker-archive:coredns-v1.8.0-skopeo.tar # 压缩为 .tar.gz(kubekey 要求) gzip coredns-v1.8.0-skopeo.tar注意:
skopeo copy的docker-daemon:源需要 docker daemon 正常运行;若 docker 不可用,则改用docker pull后skopeo copy docker://... docker-archive:...,但需提前配置好私有 registry 的认证。
3.3 kubekey 推送后验证:别只看 “push success”,要看镜像层是否完整
kk add image命令返回success仅表示传输完成,不代表镜像在私有仓库中可用。必须手动验证三层关键内容:
| 验证项 | 命令 | 预期结果 | 说明 |
|---|---|---|---|
| Manifest 是否存在 | curl -u user:pass https://harbor.yourdomain.com/v2/library/coredns/manifests/v1.8.0 | HTTP 200 + JSON manifest | 若 404,说明推送未注册 manifest |
| Config 层是否可读 | curl -u user:pass https://harbor.yourdomain.com/v2/library/coredns/blobs/sha256:xxx | HTTP 200 + JSON config | config 包含 Entrypoint、Cmd 等,缺失则 pod 启动失败 |
| Layer 层是否完整 | curl -u user:pass https://harbor.yourdomain.com/v2/library/coredns/blobs/sha256:yyy | HTTP 200 + 二进制数据 | layer 是 coredns 二进制本身,大小应 ≈ 40MB(v1.8.0 静态编译尺寸) |
# 一键验证脚本(需替换 YOUR_TOKEN 和 REGISTRY_URL) REGISTRY="harbor.yourdomain.com" IMAGE="library/coredns" TAG="v1.8.0" TOKEN="your-basic-auth-token" # 获取 manifest digest MANIFEST_DIGEST=$(curl -s -H "Authorization: Basic $TOKEN" \ https://$REGISTRY/v2/$IMAGE/manifests/$TAG | \ jq -r '.config.digest') # 验证 config layer curl -s -o /dev/null -w "%{http_code}" -H "Authorization: Basic $TOKEN" \ https://$REGISTRY/v2/$IMAGE/blobs/$MANIFEST_DIGEST | grep "200" || echo "❌ Config layer missing" # 验证首个 layer(通常是二进制) LAYER_DIGEST=$(curl -s -H "Authorization: Basic $TOKEN" \ https://$REGISTRY/v2/$IMAGE/manifests/$TAG | \ jq -r '.layers[0].digest') curl -s -o /dev/null -w "%{http_code}" -H "Authorization: Basic $TOKEN" \ https://$REGISTRY/v2/$IMAGE/blobs/$LAYER_DIGEST | grep "200" || echo "❌ Binary layer missing"提示:
jq是必备工具,麒麟 V10 可通过yum install -y jq安装。若无 jq,可用 python -m json.tool 替代,但脚本复杂度上升。
4. 部署后必查的三大避坑点:配置、权限、时区
4.1 Corefile 中的 kubernetes 插件必须显式声明 endpoints,否则解析超时
v1.8.0 的 kubernetes 插件默认使用 in-cluster config(即/var/run/secrets/kubernetes.io/serviceaccount/下的 token 和 ca.crt),但若你的集群启用了 service account token volume projection(K8s v1.21+),或 kube-apiserver 地址非默认https://kubernetes.default.svc.cluster.local:443,则必须在 Corefile 中显式指定endpoints参数,否则 coredns 启动后日志满屏kubernetes: failed to list *v1.Service: Get "https://10.96.0.1:443/api/v1/services": dial tcp 10.96.0.1:443: i/o timeout。
.:53 { errors health { lameduck 5s } ready kubernetes cluster.local in-addr.arpa ip6.arpa { # ⚠️ 关键:必须指定 apiserver 地址,不能依赖 default endpoints https://192.168.100.10:6443 pods insecure fallthrough in-addr.arpa ip6.arpa ttl 30 } prometheus :9153 forward . /etc/resolv.conf cache 30 loop reload loadbalance }注意:
endpoints后的地址必须是 kube-apiserver 的 VIP 或负载均衡地址,且该地址需能被 coredns Pod 网络访问。可通过kubectl get endpoints kubernetes -n default查看真实地址。若用 kubekey 部署,该地址通常记录在/etc/kubekey/kubespray/inventory/sample/group_vars/k8s_cluster/k8s-cluster.yml的apiserver_loadbalancer_domain_name字段。
4.2 麒麟 V10 的 SELinux 会拦截 coredns 访问 /proc/sys/net/ipv4/ip_forward
CoreDNS v1.8.0 在某些网络插件(如 calico)环境下,需读取/proc/sys/net/ipv4/ip_forward判断是否启用 IP 转发。麒麟 V10 默认开启 SELinux,策略container_runtime_t会阻止容器进程读取该 proc 文件,导致 coredns 启动时报open /proc/sys/net/ipv4/ip_forward: permission denied,进而 health check 失败,pod 一直处于 CrashLoopBackOff。
解决方法不是关闭 SELinux(违反安全基线),而是添加最小权限策略:
# 创建自定义 SELinux 模块 cat > coredns-proc.te << 'EOF' module coredns-proc 1.0; require { type container_runtime_t; class file { read getattr open }; } # allow container_runtime_t self:file { read getattr open }; allow container_runtime_t self:file { read getattr open }; EOF # 编译并加载 checkmodule -M -m -o coredns-proc.mod coredns-proc.te semodule_package -o coredns-proc.pp -m coredns-proc.mod semodule -i coredns-proc.pp提示:该策略仅授予
container_runtime_t类型进程读取 proc 文件的权限,不影响其他安全域。执行后需重启 coredns pod 生效。
4.3 时区不一致导致证书校验失败:CoreDNS 会校验 kube-apiserver 证书有效期
v1.8.0 的 kubernetes 插件使用 Go 的crypto/tls库连接 apiserver,该库严格校验服务器证书的Not Before和Not After时间戳。若 coredns Pod 所在节点的系统时钟比 apiserver 证书签发时间早(如节点 NTP 未同步、麒麟 V10 时区设置为 Asia/Shanghai 但硬件时钟为 UTC),则证书被视为“尚未生效”,连接直接拒绝,日志出现x509: certificate has expired or is not yet valid。
验证方法:
# 在 coredns pod 内执行 kubectl exec -it -n kube-system deploy/coredns -- date # 对比 apiserver 证书有效期 openssl x509 -in /etc/kubernetes/pki/apiserver.crt -text -noout | grep "Not "修复步骤:
- 统一所有节点时区:
timedatectl set-timezone Asia/Shanghai - 启用 NTP 同步:
timedatectl set-ntp true - 重启 kubelet:
systemctl restart kubelet
注意:CoreDNS 自身不处理时区,它完全依赖宿主机时间。这是跨平台部署中最玄学的故障之一——现象是 DNS 解析失败,根因却是节点时间漂移 5 分钟。
5. 验证 DNS 是否真通:绕过 kube-dns 代理,直连 coredns Pod 的 53 端口
部署完成不等于可用。很多团队只测kubectl run -it --rm --restart=Never test --image=busybox:1.31 -- nslookup kubernetes.default,这其实走的是 kube-proxy 的 iptables 规则,掩盖了 coredns 本身的健康状态。真正的验证,必须绕过所有中间层,直连 coredns Pod 的 IP 和端口。
5.1 获取 coredns Pod 的真实 IP 和端口
# 获取 coredns pod 列表(通常有两个副本) kubectl get pods -n kube-system -l k8s-app=kube-dns -o wide # 假设输出为: # NAME READY STATUS RESTARTS AGE IP NODE # coredns-6d8c4cb4d-abcde 1/1 Running 0 2m 10.233.64.5 node1 COREDNS_IP="10.233.64.5"5.2 用 dig 直连测试,观察响应头中的 SERVER 字段
# 从任意 worker 节点执行(确保节点能直连 pod IP) dig @${COREDNS_IP} kubernetes.default.svc.cluster.local +short # 关键:加 +all 参数看完整响应 dig @${COREDNS_IP} kubernetes.default.svc.cluster.local +all # ✅ 正常响应应包含: # ;; SERVER: 10.233.64.5#53(10.233.64.5) # ;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1 # kubernetes.default.svc.cluster.local. 5 IN A 10.96.0.1注意:
;; SERVER:行必须显示你指定的 IP 和端口,证明请求确实抵达目标 pod;aa标志(authoritative answer)表示 coredns 作为权威 DNS 正确响应,而非转发给上游;ANSWER: 1表示成功解析出 service ClusterIP。
5.3 故障隔离三板斧:telnet、tcpdump、strace
当dig @IP也失败时,按顺序执行:
telnet 测试端口连通性
telnet ${COREDNS_IP} 53 # 若连接拒绝,说明 pod 未监听 53 端口(检查 deployment 中 containers.ports 是否暴露 53)tcpdump 抓包确认请求是否发出
# 在 coredns pod 所在节点执行(node1) tcpdump -i any port 53 -nn -A -c 5 # 同时在另一节点执行 dig @${COREDNS_IP} ...,观察是否有 UDP 包到达strace 追踪 coredns 系统调用
# 进入 coredns pod kubectl exec -it -n kube-system coredns-6d8c4cb4d-abcde -- sh # 安装 strace(Alpine 镜像需 apk add strace) apk add strace # 追踪 listen 系统调用 strace -p 1 -e trace=bind,listen,accept,recvfrom,sendto 2>&1 | grep -E "(bind|listen|53)"
我的血泪教训:某次故障中 tcpdump 显示请求到达,但 strace 无 recvfrom 日志,最终发现是 coredns 进程被 systemd 限制了
LimitNOFILE=1024,而高并发下 fd 耗尽,新连接被内核丢弃。解决方案是修改/etc/systemd/system/kubelet.service.d/10-kubeadm.conf,增加LimitNOFILE=65536,再systemctl daemon-reload && systemctl restart kubelet。
6. 进阶技巧:用 CoreDNS 的 log 插件定位解析慢的根源
CoreDNS v1.8.0 的log插件默认只记录 ERROR 级别,但 DNS 解析慢(如 nslookup 卡 5 秒)往往源于 upstream 转发延迟或 kubernetes 插件 list 操作阻塞,这些在 ERROR 日志里不会体现。必须开启log插件的ALL模式,并配合health插件的/health端点,才能精准定位。
6.1 修改 Corefile 启用全量日志
.:53 { errors # ⚠️ 关键:log 插件必须放在 errors 之后,且指定 ALL 级别 log . { class all } health { lameduck 5s } ready kubernetes cluster.local in-addr.arpa ip6.arpa { endpoints https://192.168.100.10:6443 pods insecure fallthrough in-addr.arpa ip6.arpa ttl 30 } prometheus :9153 # ⚠️ 关键:forward 插件必须指定 timeout,避免无限等待上游 forward . 114.114.114.114 8.8.8.8 { except cluster.local max_fails 1 expire 30 health_check 5s timeout 2s # ⚠️ 必须设,否则上游卡住会拖垮整个 coredns } cache 30 loop reload loadbalance }6.2 实时分析日志中的慢查询
部署后,实时 tail 日志并过滤耗时 >1s 的查询:
# 获取 coredns pod 日志流 kubectl logs -n kube-system deploy/coredns -f | \ awk ' /query/ && /duration/ { match($0, /duration ([0-9]+)ms/, arr) if (arr[1] > 1000) { print "⚠️ SLOW QUERY (" arr[1] "ms): " $0 # 同时打印前一行(通常是 query 语句) if (prev != "") print " QUERY: " prev prev = "" } else { prev = $0 } } !/query/ && !/duration/ { prev = $0 } '典型输出:
⚠️ SLOW QUERY (2345ms): [INFO] 10.233.64.1:54231 - 12345 "A IN mysql.default.svc.cluster.local. udp 61 false 512" NOERROR qr,aa,rd,ra 111 1.2345s QUERY: [INFO] 10.233.64.1:54231 - 12345 "A IN mysql.default.svc.cluster.local. udp 61 false 512"此时可判断:该查询耗时 2.3 秒,远超正常(<50ms),且qr,aa,rd,ra表明是 coredns 自己响应(非转发),问题必在 kubernetes 插件的 list 操作。进一步检查 apiserver 负载或 etcd 延迟。
6.3 用 health 插件的 /health 端点做自动化巡检
CoreDNS v1.8.0 的health插件提供/healthHTTP 端点,返回HTTP 200 OK表示进程存活,但更重要的是它会检测插件健康状态。例如 kubernetes 插件若无法连接 apiserver,/health会返回HTTP 503 Service Unavailable,且响应体包含kubernetes: unhealthy。
# 编写巡检脚本(放入 cron 每 5 分钟执行) COREDNS_POD_IP=$(kubectl get pods -n kube-system -l k8s-app=kube-dns -o jsonpath='{.items[0].status.podIP}') RESPONSE=$(curl -s -o /dev/null -w "%{http_code}" http://${COREDNS_POD_IP}:8080/health) if [ "$RESPONSE" != "200" ]; then echo "❌ CoreDNS health check failed: HTTP $RESPONSE" # 发送告警(此处省略) exit 1 fi # 进阶:检查响应体是否含 "unhealthy" HEALTH_BODY=$(curl -s http://${COREDNS_POD_IP}:8080/health) if echo "$HEALTH_BODY" | grep -q "unhealthy"; then echo "❌ CoreDNS plugin unhealthy: $HEALTH_BODY" exit 1 fi echo "✅ CoreDNS health OK"我的习惯是:在所有 CoreDNS 部署完成后,立即将此脚本注入集群监控体系(如 Prometheus + Alertmanager),而不是等业务报障才想起查 DNS。因为 DNS 故障的表象永远是“服务连不上”,但根因可能是 coredns 里一个插件 silently dead。希望帮到你。
本文还有配套的精品资源,点击获取