一种内外网Docker镜像同步的Harbor复制架构,适用于本地高性能编译+生产环境拿来主义
众所周知生产环境的服务器配置还是比较珍贵的,尤其是涉及到代码编译这种大任务,如果放在业务服务器中则业务服务器必然被吸血CPU算力和内存导致业务出问题,专门弄一台高配编译机又显得有些没必要,有的时候就是得让我们现在本地打包完毕后,再推送到远程生产端
然而现在都是容器时代,大家的服务早就全上Docker了,那种各自在自己机器上编译的不但容易出环境问题(大家编译环境不一样)还很难和Docker生态组织起来。
开发服务器放在本地机房,配置能拉多高就有多高,如果说我们走统一编译环境的路子,编译制品在那一套编译环境中生产,用脚本统一推送到Docker私服。这种情况下,有没有办法能做到优雅的在开发环境、测试环境、生产环境,共用一套本地编译服务器?
动动脑筋其实没问题。
只要有出口能访问外网,那搞一套内外网复制、推送编译制品的架构就OK。
首先是Harbor安装配置,这个地方没有什么需要注意的,首先要实现的目标是各自的内网均能够访问、登录。
本地测试/开发环境,与生产环境,都先做到正常运行。
安装:
cd /opt wget https://github.com/goharbor/harbor/releases/download/v2.9.4/harbor-offline-installer-v2.9.4.tgz tar -zxvf harbor-offline-installer-v2.9.4.tgz cd harbor
配置
cp harbor.yml.tmpl harbor.yml # 不启用 https, 全注释掉, hostname、port换成想要的 vi harbor.yml ./install.sh
可以通过Docker命令测试:
docker login 192.168.10.10:50080 -u 'admin' -p Harbor12345
上方的 192.168.10.10:50080 假设为你内网/本地的Harbor地址与端口,实际拉取镜像时,确定可以走这个内网IP拉取
接着,就到了关键时候。大框架下分为4步走
- 首先约定一个假域名给公网Harbor,所有服务不允许使用IP直连,而是用域名
- 把这个假域名配置到公网的生产服务器上,使其可以访问,做好安全配置
- 替换所有环境中的HOSTS指向,包括各容器内,内网的归内网,外网的归外网
- 采用Harbor Replication架构做镜像复制,模式用Push
假设你的假域名设置为:harbor.example.com
生产环境的IP地址为:88.88.88.88
我们首先更改 /etc/hosts 把域名 harbor.example.com 指向私网/公网,即可在内网(生产环境)、外网(测试环境)等多个不同的环境访问。
个人电脑直接修改hosts即可,修改 C:\Windows\System32\drivers\etc
比如,生产配置加上 88.88.88.88 harbor.example.com
而开发环境的相关服务器配置加上 192.168.10.10 harbor.example.com
生产环境反向代理如下,给假域名做代理,确保能被访问,为了安全性,直接在防火墙上只允许内网IP/公司出口服务器等安全IP访问,做对应白名单机制
server {
listen 80;
server_name harbor.example.com;
location / {
proxy_pass http://192.168.0.111:50080;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_redirect http:// $scheme://;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forarded-Scheme $scheme;
client_max_body_size 0;
}
}
我们这些操作的目的是为了实现:内外网都访问相同的域名,但是路由的目标不一样
注意,这个内外网的宿主立场在生产环境
生产环境的内网,肯定不能绕一圈,还是得用内网IP直接拉镜像,而生产环境的外网,就是我们开发环境/测试环境等,也需要有个入口能访问、复制推送。所以我们这里做出利用HOSTS区分的策略。
为什么不能直接各访问个的呢?
因为Harbor它底层逻辑不允许,标准配置模型只有一个规范入口(hostname),你用第二个IP必定出问题,Docker拉取镜像不是只访问一次,而是要走链接、获取Token、用Token获取镜像……等等步骤,这中间的地址都是Harbor Core返回的,外部无法介入,而Harbor只会返回一个地址,也就是那唯一一个规范入口
这里的解法就是一个域名,内外网分别解析
好,接着就是替换所有环境中的HOSTS指向,各个宿主机的/etc/hosts就不用说了,这里单独需要说的是容器内的。
比如说你的Docker调度服务,如果使用的是Portainer。生产环境在容器启动时就需要配置:
docker run -d -p 9000:9000 --name portainer --restart=always --add-host harbor.example.com:192.168.0.111 -v /var/run/docker.sock:/var/run/docker.sock -v portainer_data:/data portainer/portainer-ce:latest
其他需要在Docker容器内访问Harbor的服务同理。
比如你开发环境的Harbor自身,为了给公网的Harbor同步,自然要配齐对应的hosts。
由于Harbor的部署本身,就是它脚本自己会生成一个docker-compose文件作为编译物,所以我们这里直接修改Harbor自身的docker-compose.yml,在对应服务下增加指向生产的hosts配置。
涉及服务:registry、core、jobservice,这三个都需要新增
extra_hosts: - "harbor.example.com:88.88.88.88"
修改完毕后,直接重启更新
接下来一切就顺理成章了,生产环境该怎么用怎么用,因为他们的域名直接指向内网,所以拉取推送Docker镜像都是内网交互。
而开发环境由于和生产环境不是一个内网,所以开发环境也配置了对应的HOSTS,能解析到正确的公网IP上。
我们在【系统管理】-【仓库管理】菜单内,新增 http://harbor.example.com 作为一个仓库服务
然后再【系统管理】-【复制管理】菜单中,新一条复制规则,比如匹配所有的prod tag,采用Push-based模式,目标仓库选择刚刚创建的仓库即可
最终我们就实现了,将编译、构建这件高消耗流程从生产环境完全摘出
只需在开发环境编译机上操作,构建出来的镜像默认就是全部存在开发环境的Harbor上,然后如果tag中包含prod,则自动诱发复制流程,由开发环境Harbor主动push到生产环境Harbor,生产环境只需要在对应Docker调度中心点一点,或者配置监控自动更新即可。