news 2026/9/26 16:42:08

K8S集群监控镜像清单与离线打包:一次备齐所有镜像

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
K8S集群监控镜像清单与离线打包:一次备齐所有镜像

简介:这份资源面向Kubernetes运维工程师、SRE及云原生监控学习者,聚焦集群监控体系的镜像与配置落地,解决监控组件离线部署、镜像拉取困难及配置模板缺失等问题。压缩包共124个文件,约650.88MB,以57个yaml清单、16个gz镜像包、14个txt说明、8个json配置为主,另含yml、tmpl模板、log日志、silences静默规则及license、notice等辅助文件,覆盖Prometheus、Grafana、Alertmanager、amtool、prometheus-webhook-dingtalk等核心组件的镜像与配套配置。目录中镜像包与清单文件相互对应,便于按组件快速定位所需资源,适合搭建或迁移K8S监控环境时直接取用。目前已有382人学习下载,可作为集群监控部署、告警配置与镜像离线分发的实用参考合集。

1. K8S集群监控资源镜像清单:从“拉不到镜像”到“一次备齐”

做 K8S 集群监控最让人血压升高的瞬间,不是 Prometheus 规则写错,而是 Pod 卡在ImagePullBackOff,kubectl describe pod一看——镜像仓库连不上,或者某个 exporter 镜像 tag 根本不存在。尤其是内网环境、离线机房、信创服务器上部署 kube-prometheus-stack 时,几十个镜像要一个个docker pull、docker save、docker load,漏一个就前功尽弃。这份 K8S 集群监控资源镜像清单及镜像合集,解决的就是这件事:把一套完整监控栈所需的全部容器镜像提前梳理清楚、批量拉取、统一打包,让集群搭建和监控部署不再被镜像问题卡住。适合正在做 k8s 集群搭建、k8s 部署 prometheus、以及需要离线交付的运维和平台工程师。下面从镜像清单怎么定、怎么拉、怎么导、怎么验,一步步拆开讲。

2. 监控栈镜像清单怎么定:先搞清楚要跑哪些组件

2.1 一套标准监控栈到底包含哪些镜像

很多人以为监控就是 Prometheus 加 Grafana 两个镜像,实际上一套能用的 kube-prometheus-stack 至少涉及四类组件:指标采集、指标存储与查询、告警、可视化。每一类下面又有若干镜像,而且版本之间互相咬合,不能随便混搭。

以社区最常用的 kube-prometheus-stack 为例,核心镜像大致分这么几组:

组件类别代表镜像作用
指标采集prometheus-node-exporter采集节点 CPU/内存/磁盘/网络
指标采集kube-state-metrics把 K8S 对象状态转成指标
指标采集prometheus-operator管理 Prometheus 实例和配置
指标存储prometheus时序数据库与查询引擎
告警alertmanager告警分组、去重、路由
可视化grafana仪表盘展示
附加采集blackbox-exporter黑盒探测 HTTP/TCP/ICMP
附加采集pushgateway接收短生命周期任务指标

这张表不是让你照抄,而是让你意识到:镜像清单的粒度要细到每个 Deployment/StatefulSet/DaemonSet 实际引用的 image 字段。少一个 node-exporter,节点指标就是空的;少一个 kube-state-metrics,Pod 重启次数、Deployment 副本数这些关键指标全都没有。

我一般会先把 Helm chart 的 values 拉下来,用helm template渲染成纯 YAML,再从里面把所有image:字段抽出来。这样得到的清单才是真正会被 K8S 调度的镜像,而不是凭记忆列出来的。

2.2 用 helm template 抽取真实镜像清单

直接helm install再去看 Pod 用了什么镜像,属于事后补救。更稳的做法是渲染阶段就把镜像清单拿到手。下面这段命令把 chart 渲染成 YAML,再用 grep 和 sort 去重,得到一份干净的镜像列表。

# 添加 prometheus-community 仓库 helm repo add prometheus-community https://prometheus-community.github.io/helm-charts helm repo update # 渲染 kube-prometheus-stack 模板到本地文件 helm template monitoring prometheus-community/kube-prometheus-stack \ --namespace monitoring \ --set grafana.enabled=true \ --set prometheus.prometheusSpec.replicas=1 \ > monitoring-rendered.yaml # 抽取所有 image 字段并去重排序 grep -E '^\s+image:' monitoring-rendered.yaml \ | sed 's/.*image:\s*//' \ | tr -d '"' \ | sort -u \ > image-list.txt # 查看结果 cat image-list.txt

这段逻辑的关键点:helm template不会真正连集群,只做本地渲染,所以可以在任何有 helm 的机器上跑。grep -E '^\s+image:'匹配的是 YAML 里缩进后的 image 字段,sed去掉前缀,tr -d '"'去掉可能存在的引号,最后sort -u去重。得到的image-list.txt就是这份 chart 在当前 values 下真正需要的全部镜像。

参数说明:--namespace monitoring只影响渲染出的 namespace 字段,不影响镜像地址;--set后面的开关按你实际要启用的组件来,比如不需要 grafana 就设grafana.enabled=false,清单里自然少一个镜像。注意有些 chart 的镜像地址带{{ }}模板变量,渲染后会被替换成实际值,所以一定要用渲染后的结果,不要直接看 values.yaml。

2.3 镜像 tag 与 digest:为什么不能只记 tag

镜像清单里最容易翻车的地方是 tag。prometheus:v2.45.0这种 tag 看起来明确,但它是可变的——同一个 tag 可以被重新推送,内容就变了。生产环境更稳的做法是记录 digest,形如prometheus@sha256:abc123...。

不过 digest 可读性差,人工核对困难。我的习惯是清单里同时保留 tag 和 digest 两列:tag 用于人看和拉取,digest 用于校验。拉取时用 tag,打包前用docker inspect或skopeo inspect把 digest 记下来,导入后比对 digest 是否一致。

# 用 skopeo 查看镜像 digest,不需要本地 docker daemon skopeo inspect docker://prometheus/prometheus:v2.45.0 \ | grep -E 'Digest|RepoTags'

skopeo inspect的好处是不用先把镜像拉到本地,直接查远程仓库元数据,适合在清单整理阶段快速核对。如果返回的 Digest 和你记录的一致,说明镜像没被重新推送过。这一步在离线交付前做一遍,能避免“明明拉的是同一个 tag,行为却不一样”的玄学问题。

3. 批量拉取与离线打包:把镜像合集做成一个 tar

3.1 批量拉取脚本与并发控制

清单有了,接下来是拉取。一个个docker pull太慢,写个循环是最基本的。但循环里要注意两点:一是失败要记录,不能拉一半断了不知道缺哪个;二是并发别开太大,否则把本地磁盘 IO 和网络打满,反而更慢。

#!/bin/bash # pull-images.sh - 按清单批量拉取镜像 IMAGE_LIST="image-list.txt" FAILED_LOG="pull-failed.log" MAX_PARALLEL=4 > "$FAILED_LOG" pull_one() { local img="$1" if docker pull "$img" >/dev/null 2>&1; then echo "[OK] $img" else echo "[FAIL] $img" echo "$img" >> "$FAILED_LOG" fi } export -f pull_one export FAILED_LOG # 用 xargs 控制并发数 cat "$IMAGE_LIST" | xargs -P "$MAX_PARALLEL" -I {} bash -c 'pull_one "$@"' _ {} echo "拉取完成,失败列表见 $FAILED_LOG"

逻辑说明:xargs -P 4表示最多 4 个并发进程,-I {}把每一行作为参数传给后面的 bash。pull_one函数里把成功和失败分开输出,失败的同时追加到pull-failed.log。这样即使中途有镜像拉不到,也不会中断整体流程,最后看日志补拉即可。

参数说明:MAX_PARALLEL根据你的网络带宽和磁盘调整,内网 registry 可以开到 8,公网拉取建议 4 以内。docker pull的输出被重定向到/dev/null,避免并发时日志交错看不清,需要详细输出可以去掉重定向。

3.2 docker save 打包与分层压缩

镜像全部拉到本地后,用docker save打包成一个 tar。这里有个坑:如果直接docker save img1 img2 ... > all.tar,镜像多了之后 tar 会非常大,而且没有压缩。更好的做法是先 save 再 gzip,或者用docker save输出到管道直接压缩。

# 把清单里所有镜像打包并压缩 docker save $(cat image-list.txt | tr '\n' ' ') \ | gzip -1 > monitoring-images.tar.gz # 查看包大小 ls -lh monitoring-images.tar.gz

gzip -1表示最低压缩级别,速度最快,压缩率也够用。镜像层本身很多已经是压缩过的,再用高压缩级别收益不大,反而耗时。如果镜像特别多,可以分批 save,比如每 10 个一个包,避免单个 tar 过大导致传输中断后要重来。

注意docker save后面跟的是镜像名列表,如果清单里有重复或空行,先清理一下。另外docker save保留的是镜像的 tag 和层数据,导入后 tag 不变,但 digest 可能因为重新打包而变化,所以校验要以导入后的实际 digest 为准。

3.3 导入端 docker load 与 containerd 的差异

离线包拿到目标机器后,导入方式取决于容器运行时。用 Docker 的集群直接docker load,用 containerd 的集群(现在大多数 K8S 发行版默认 containerd)就不能用 docker load 了,得用ctr或nerdctl。

# Docker 运行时 docker load < monitoring-images.tar.gz # containerd 运行时,用 ctr 导入到 k8s.io 命名空间 ctr -n k8s.io images import monitoring-images.tar.gz # 如果装了 nerdctl,更接近 docker 体验 nerdctl -n k8s.io load < monitoring-images.tar.gz

关键差异:containerd 有命名空间概念,K8S 用的是k8s.io这个 namespace,导入时必须加-n k8s.io,否则ctr images ls看不到,K8S 也拉不到。这是离线部署里最常见的翻车点之一——镜像明明导入了,Pod 还是 ImagePullBackOff,就是因为导错了 namespace。

导入后验证:

# Docker docker images | grep -E 'prometheus|grafana|alertmanager' # containerd ctr -n k8s.io images ls | grep -E 'prometheus|grafana|alertmanager'

如果清单里的镜像地址带私有 registry 前缀,比如registry.internal:5000/prometheus/prometheus,导入后 tag 会保留这个前缀,K8S 的 image 字段也要对应改,否则还是会去公网拉。

4. 镜像清单落地时的避坑与排查

4.1 现象:Pod 一直 ImagePullBackOff,但镜像明明导入了

原因:containerd 命名空间不对,或者镜像 tag 与 YAML 里写的不完全一致。K8S 默认从k8s.io命名空间找镜像,如果导入时没加-n k8s.io,镜像在 default 命名空间,K8S 看不到。

解决:用ctr -n k8s.io images ls确认镜像在正确命名空间;再核对 YAML 里的 image 字段是否和导入的 tag 完全一致,包括 registry 前缀和 tag 后缀。差一个字符都会导致重新去远程拉。

4.2 现象:helm template 渲染出的镜像清单比实际运行的少

原因:有些镜像是在 chart 的 hook 或子 chart 里定义的,helm template默认不渲染 hook,或者子 chart 的 values 被覆盖后镜像变了。

解决:加--no-hooks的反面是默认不渲染 hook,需要显式加--include-crds和检查子 chart。更稳的做法是部署到测试集群后,用kubectl get pods -n monitoring -o jsonpath把所有实际镜像再抽一遍,和渲染清单做差集。

kubectl get pods -n monitoring -o jsonpath='{range .items[*]}{.spec.containers[*].image}{"\n"}{end}' | sort -u

4.3 现象:docker save 打包后文件巨大,传输经常断

原因:一次性 save 所有镜像,单个 tar 几十 GB,网络传输不稳定时容易断,断了又要从头来。

解决:分批打包,每批 5 到 10 个镜像,或者用skopeo copy直接同步到目标 registry,避免落地 tar 文件。如果必须用 tar,配合split分卷,传输后cat合并。

4.4 现象:导入后镜像 digest 和清单记录不一致

原因:docker save再docker load的过程中,镜像配置可能被重新计算,digest 变化。或者中间经过了私有 registry 的重新打包。

解决:如果对 digest 有严格要求,用skopeo copy保持 digest 不变,或者直接在目标环境从同一个 registry 拉取,不走 save/load。校验时以导入后docker inspect --format='{{.Id}}'或ctr images ls的 digest 为准,和源端比对。

4.5 现象:私有 registry 前缀导致 K8S 拉取失败

原因:清单里的镜像地址是prometheus/prometheus,但集群配置了私有 registry mirror,实际拉取时被重写成registry.internal/prometheus/prometheus,而私有 registry 里没有这个镜像。

解决:统一镜像地址。要么在清单阶段就把所有镜像 retag 成私有 registry 前缀,要么在 K8S 的 image 字段里写全地址。用docker tag或skopeo copy批量加前缀,再重新打包。

5. 用 skopeo 做镜像合集的增量同步与校验

最后一章讲一个我实际交付时最常用的技巧:用skopeo替代docker pull/save/load三件套,直接做 registry 到 registry 的同步,同时生成可校验的清单。这样既省掉本地磁盘中转,又能保留 digest,特别适合多集群批量交付。

skopeo copy的基本用法是从一个 registry 复制到另一个,或者从 registry 复制到本地目录(dir 格式)再打包。下面这个脚本把清单里的镜像同步到本地 dir,并生成一个带 digest 的清单文件。

#!/bin/bash # sync-with-skopeo.sh - 用 skopeo 同步镜像并记录 digest IMAGE_LIST="image-list.txt" DEST_DIR="./images-dir" MANIFEST="image-manifest.csv" mkdir -p "$DEST_DIR" echo "image,digest" > "$MANIFEST" while read -r img; do [ -z "$img" ] && continue # 把镜像名里的 / 和 : 替换成 _ 作为目录名 safe_name=$(echo "$img" | tr '/:' '__') dest="$DEST_DIR/$safe_name" if skopeo copy --all "docker://$img" "dir:$dest" >/dev/null 2>&1; then digest=$(skopeo inspect "dir:$dest" | grep -oP '"Digest":\s*"\K[^"]+') echo "$img,$digest" >> "$MANIFEST" echo "[OK] $img -> $digest" else echo "[FAIL] $img" fi done < "$IMAGE_LIST"

逻辑说明:skopeo copy --all会复制镜像的所有架构和 tag 信息到本地 dir 格式。skopeo inspect从本地 dir 读取 digest,写入 CSV。这样得到的image-manifest.csv就是一份可追溯的镜像合集清单,交付时连同images-dir一起打包,目标端用skopeo copy dir:... docker://...推送到私有 registry,digest 保持不变。

参数说明:--all表示复制所有架构,如果只需要 amd64 可以去掉,减小体积。dir:格式是 skopeo 的本地目录格式,不是 tar,但可以直接用tar czf打包整个目录。目标端推送时用skopeo copy --all dir:./images-dir/xxx docker://registry.internal/xxx,注意目标 registry 要允许推送。

校验环节,我习惯在目标端推送完成后,用skopeo inspect docker://registry.internal/xxx再取一次 digest,和 CSV 里的比对。全部一致才算交付完成。这个习惯帮我挡过好几次“镜像推上去了但层不完整”的问题——skopeo 的 digest 校验比docker pull成功更可靠,因为它校验的是 manifest 和层的完整性。

说个我自己的教训:早期做离线交付,图省事只用docker save打包,结果有一次目标机器磁盘空间不够,docker load到一半失败,镜像处于半导入状态,docker images能看到但跑起来就报层缺失。后来改成 skopeo 的 dir 格式加 digest 校验,每个镜像独立目录,坏一个不影响其他,重传也只需要传单个目录。这个习惯一直保留到现在,虽然多花几分钟做校验,但省掉了现场排查的几小时。希望帮到你。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/26 16:40:19

Go商城源码实战:gin+gorm+redis+mysql读写分离与分布式中间件串联

简介&#xff1a;这是一套基于 Gin、GORM、Redis 与 MySQL 读写分离架构的电子商城后端项目源码&#xff0c;面向计算机专业毕业设计、课程设计及 Go 语言后端进阶学习者&#xff0c;帮助解决高并发场景下的数据读写分离与鉴权加密等实际问题。压缩包共 131 个文件&#xff0c;…

作者头像 李华
网站建设 2026/9/26 16:40:19

TaoToken 统一 Key 接入 AI 工具集:settings.json 与 config.toml 配置骨架

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/26 16:39:17

逻辑回归实战:信用卡欺诈检测中的类别不平衡与阈值调优

简介&#xff1a;一份使用逻辑回归算法完成信用卡欺诈检测的机器学习项目&#xff0c;面向人工智能初学者和相关专业的高校学生&#xff0c;尤其适合正在准备课程设计、期末大作业的人群。项目压缩包共收录3个文件&#xff1a;Python源码、CSV信用卡交易数据集和Markdown说明文…

作者头像 李华
网站建设 2026/9/26 16:38:36

JSP+MySQL个人记事系统源码部署实战:从JDBC配置到Tomcat war包发布

简介&#xff1a;基于JSP与MySQL实现的个人记事备忘系统完整源码包&#xff0c;面向正在学习Java Web开发的初学者、毕业设计学生以及需要快速搭建轻量级记事本应用的开发者。项目采用JSPServletJDBC经典技术栈&#xff0c;涵盖用户笔记增删改查、分类管理、登录验证等核心功能…

作者头像 李华
网站建设 2026/9/26 16:36:55

Claude CLI工具链:基于MCP协议的工程化AI编程实践

1. 项目概述&#xff1a;这不是一个“模板库”&#xff0c;而是一套面向 Claude 生态的 CLI 工具链设计范式 “claude-code-templates”这个标题乍看像一个 GitHub 上常见的静态代码片段合集——比如几十个 .js 或 .py 文件&#xff0c;按语言或场景分类&#xff0c;供人复…

作者头像 李华