内网镜像源管理
背景
很多企业为了安全性,线上除了业务网络外,是关闭了外网进出路线的。
但是我们在使用 docker 和 k8s 时, 又不可避免的会使用到很多 docker.io, ghcr.io, quay.io 等公网仓库的镜像。
该如何较好的拉取这些镜像呢?
内部镜像仓库
除非一次性项目,以后都不再管理了,否则都是有必要搭建一个内部的 镜像仓库的。
简单临时用一下这种情况, 推荐使用官方的 docker-registry 就可以。
一般情况下推荐还是搭建一个 Harbor, 在官方仓库的基础上增加了 https, 备份, 同步等一些功能。
如何把镜像上传到内部镜像仓库
方法一: 手动模式
- 本地 docker pull 镜像
- 本地导出镜像
- 上传镜像到服务器
- 服务器 load 镜像
- 服务器上 push 到镜像仓库
很麻烦是不?是真麻烦,稍微多更新几个镜像就受不了。
方法二: 脚本离线传输
弄个脚本将外部 Harbor 的镜像全导出来, 批量上传需要的镜像到内网, 内部再批量提交
方法三: 临时网络开关
推荐采用这种模式;
- 限制只允许 Harbor 出公网
- 需要更新和拉取外网镜像时开一下防火墙策略, 更新完成即把策略再关闭
- 开启网络策略后就可以立即手工做预热镜像, 不一定非得生产环境更新镜像时再拉取;
- 再严格一点可以部署2个 Harbor, 只临时开放一个测试环境的, 生产的从测试定时同步过来;
方法四: 推荐两套仓库的方案
- 部署一个 Harbor 作为内部镜像站,存放企业内部专有的镜像
- 部署一个 docker hub 的 registry-mirrors 只缓存外部的镜像
实践一: Harbor 自定义镜像站的镜像站
即允许 Harbor 访问外网的情况,配置一个镜像站。
一是减少了人员操作量,二是内部节点更新镜像时可以有份缓存,减少带宽消耗和时间。
创建步骤
-
Harbor 上创建一个 docker-hub 的仓库 位置在 系统管理-仓库管理, 只需要选择 提供者为 Docker Hub, 然后随便填个名字 就ok

-
创建一个自定义项目, 如 cproxy, 配置镜像代理,选择上一步创建的仓库即可

使用方法
假设内部私有仓库的域名为 registry.services.wait
拉取 Hub 根目录 library 下的镜像 docker pull registry.services.wait/cproxy/nginx:latest
拉取常规镜像 docker pull registry.services.wait/cproxy/project-name/nginx:latest
Harbor镜像站路径的问题
存在一个问题: 在 /etc/docker/daemon.json 文件中配置 registry-mirrors 时是不能使用路径的; 如 https://registry.services.wait/cproxy 是会报错的;
如果带上这个 cproxy 名字的话,那么所有外部的 yml 文件最后都得手动修改给加上; 还有很多隐藏的镜像(yml文件里面没有写的那种)就更麻烦了。
解决办法: 前置一个 nginx, 并且配置一个 vhost, 例如监听 mirrors-docker.services.wait
将这个域名反代到 registry.services.wait/cproxy 上面去
/etc/docker/daemon.json 文件的 registry-mirrors 就配置 https://mirrors-docker.services.wait 即可。
containerd 的 config.toml 里面是一样的镜像配置。
也就是内部的业务镜像配置的时候, 需要显式添加域名和项目地址,不走镜像站,如 image: registry.services.wait/group1/web1:v0.1
外部镜像可以不添加域名,从而走镜像站 image: nginx:latest
不过最后这一步我没有做成功,理论应该是可行的。遇到个小错误,nginx没有转发到 mirrors 去, 环境被铲了,下次有机会再部署排查一下。
实践二: 独立部署 docker-mirrors镜像站
推荐用这种模式 内部镜像写全路径,指向内部仓库域名和地址; 外部镜像走 registry-mirrors 的配置, 并内部 dns 指向到这台可以出公网的代理仓库节点上
/etc/docker/daemon.json
{
"insecure-registries": ["registry.services.wait"],
"registry-mirrors": ["https://mirrors-docker.services.wait"],
"exec-opts": ["native.cgroupdriver=systemd"]
}services:
registry-mirrors:
restart: unless-stopped
image: registry.services.wait/cwx/registry:2.8.1
ports:
- "5000:5000/tcp"
volumes:
- registry-mirrors:/var/lib/registry
environment:
- REGISTRY_PROXY_REMOTEURL="https://registry-1.docker.io"
# 主要是为了提供 https, 如果不用可以忽略
nginx:
image: registry.services.wait/cwx/nginx:1.23.4
restart: unless-stopped
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
- /data/Harbor-data/secret/cert:/etc/cert:z
ports:
- 443:443
volumes:
registry-mirrors:如果是临时网络策略也不让开,那就只能外部pull,然后内部push了。 如果不想去修改那些yml文件, 则还是部署一个 mirrors registry,但按照普通模式部署。 没有这样试过, 感觉理论可行。