如何在CI场景下实现Docker 'latest'标签自动更新且无冗余下载
我给同事提供了可通过本地docker run运行的Docker容器,该容器通过Gitlab CI频繁构建,并以Semver 2.0版本标签推送到公司Nexus仓库。同事使用的启动脚本如下:
#!/bin/bash docker run -it -p 8080:80 nexus.company.net/goodservice:latest --dependency-overrides=local echo "find the good service under http://localhost:8080, have fun!"
注:
--dependency-overrides是我实现的简易方法,可让同事无需Redis即可运行服务,通过该方式替换DI容器中的实现。
现在遇到的问题是:当本地已经下载过某个版本(比如1.0.1-pre.5)后,再用latest标签执行docker run不会触发镜像更新。虽然添加--pull=always可以解决,但这个基于alpine的.NET镜像大小约100MB,同事用的是计量4G网络,流量成本很高。我想知道有没有办法让Docker只检查latest标签是否有更新,而不是直接拉取整个镜像?在官方文档里没找到相关内容(顺便提一句:如果Docker或CNCF的相关人员看到,希望能新增--pull=updated这类选项)。求可行的解决方案建议。
先对比镜像摘要再决定是否拉取
通过docker manifest inspect获取远程latest镜像的摘要,再和本地镜像的摘要对比,只有不一致时才拉取完整镜像:# 获取远程latest镜像的配置摘要 REMOTE_DIGEST=$(docker manifest inspect nexus.company.net/goodservice:latest | jq -r '.config.digest') # 获取本地latest镜像的配置摘要(不存在则返回空) LOCAL_DIGEST=$(docker inspect nexus.company.net/goodservice:latest --format='{{.Config.Digest}}' 2>/dev/null) if [ "$REMOTE_DIGEST" != "$LOCAL_DIGEST" ]; then echo "发现新版本,开始拉取..." docker pull nexus.company.net/goodservice:latest fi # 启动容器 docker run -it -p 8080:80 nexus.company.net/goodservice:latest --dependency-overrides=local这个方法仅拉取几KB的元数据做对比,能大幅节省流量,需要同事本地安装
jq工具来解析JSON输出。改用明确版本号替代latest标签
既然已经用Semver 2.0版本标签推送镜像,可以让同事的脚本使用具体版本号:比如你每次发布后把最新版本号同步到一个内部可访问的静态文件,同事的脚本先获取该版本号,再检查本地是否存在对应镜像:# 从内部地址获取最新版本号 LATEST_VERSION=$(curl -s http://internal.company.net/goodservice/latest-version) IMAGE="nexus.company.net/goodservice:$LATEST_VERSION" # 检查本地是否有该版本镜像 if ! docker image inspect $IMAGE &>/dev/null; then echo "本地无此版本,开始拉取..." docker pull $IMAGE fi docker run -it -p 8080:80 $IMAGE --dependency-overrides=local这种方式完全避免了
latest标签的歧义,同事也能明确知道运行的版本,只有本地无对应版本时才会拉取。优化镜像分层减少拉取流量
进一步拆分镜像分层,把.NET runtime、系统依赖这类不常变化的内容放在基础层,业务代码单独作为上层。这样即使更新业务代码,同事拉取时只需要下载变化的分层(可能远小于100MB),配合--pull=always也能降低实际流量消耗。
内容的提问来源于stack exchange,提问作者crimson_code

