背景
GTS统一工作台研发运维管理部分(研运中心)支持通过流水线发布应用到客户的K8S集群。平台部署在售卖区张家口地域有用户的K8S集群在阿里云深圳和杭州地域,部署时需要要流水线中把镜像推送到用户深圳及杭州的镜像仓库,正常情况大概四五分钟可以推完但在网络比较差的时候可能长至十几分支甚至半小时还未推完。
咨询了阿里云容器镜像仓库团队得知跨地域镜像推送是走公网流量网络稳定性不可控,而且如果容器镜像仓库不是企业版公网带宽是共享会在使用高峰期变慢。
方案调研
访问镜像仓库走公网稳定性不可控首先想到的是专线就可以保证稳定性,阿里云上有CEN(Cloud Enterprise Network)可以跨地域VPC专线打通,在深圳和杭州分别创建两个VPC与张家口打通让推镜像的流量走CEN即可。
一开始以为CEN添加好后配路由就可以解决,实际CEN上不支持公网路由由转发。然后尝试了在流水线VPC创建ECS A在深圳VPC创建ECS B通过内网地址OVS+VxLAN创建隧道,ECS A隧道网络IP 172.18.1.1,ECS B隧道网络中的IP为172.18.2.1。在ECS A中开启IP Forward并添加静态路由将registry.cn-shenzhen.aliyuncs.com对应IP的网关设为172.18.1.2。ECS B中开启IP Forward并用iptables对流水线VPC的网段设置SNAT。
通过ping测试registry.cn-shenzhen.aliyuncs.com的IP并用tcpdump抓包验证可以让流量通过ECS B转发到公网。但这需要流水线K8S集群Worker中的镜像仓库流量先转到ECS A在VPC上添加路由规则后不生效也提工单咨询到VPC不支持设置公网IP的路由,遂放弃了此方案。
而后又想到在深圳和杭州的VPC上分别创建镜像仓库的反向代理,在流水线K8S节点主机上把杭州及深圳的镜像仓库域名的IP通过Host配成反向代理服务的内网地址,由于镜像仓库默认是HTTPS协议如果反向代理使用HTTPS协议需要自己生成自签名证书,自签名证书在流水线主机上默认会认为不安全需要添加信任配置这样比较麻烦,然后又找到了另一个开源代理服务器软件goproxy,此软件既支持正向代理也支持反向代理,与nginx纯七层反向代理不同goproxy可以根据请求中的host自动转发到host域名对应的目标服务器,对于HTTPS流量只会解析TLS握手HELLO包拿到目标Host后面的流量四层转发(类似nginx四层代理中的preread功能),这样就不需要自己生成证书客户端看到的就是目标镜像仓库本身的证书。
方案实施
网络架构
CEN配置
创建CEN
流水线所在集群VPC是在宙斯上申请的,CEN也是在宙斯上创建文档可参考https://yuque.antfin-inc.com/aliyunops/zeus-doc/cen。
创建代理VPC
为了网络隔离和安全在杭州和深圳分别创建新的VPC未重用已有的VPC。
添加VPC实例
创建好CEN后把张家口、深圳及杭州的VPC添加到CEN中。
带宽分配
跨地域VPC默认带宽只提供连通性测试需要根据实际用量分配,经评估张家口到深圳及张家口到杭州各分配了200M带宽。
Proxy安装
资源创建
在深圳及杭州VPC分别创建内网SLB及安装代理的ECS,在SLB上创建TCP 443端口监听转发到ECS 443端口。
Proxy工具下载
将代理工具下载到/root/proxy-linux并解压
mkdir /root/proxy-linux
wget -O proxy-linux-amd64.tar.gz https://github.com/snail007/goproxy/releases/download/v11.0/proxy-linux-amd64.tar.gz
tar -xvf proxy-linux-amd64.tar.gz
Supervisor配置
在此选用了Supervisor作为守护来运行goproxy,主机重启或进程退出后会自动启动代理软件。
安装好supervisor后配置Unit文件路径是/etc/supervisor/conf.d/acr-proxy.conf内容如下。
command这一行启动代理的监听指定了ECS的内网IP原因是ECS启用了IPV6不指定或指定0.0.0.0时会监听到:::0导致跨主机通过IPV4地址访问不通。
[program:acr-proxy]
directory=/root/proxy-linux
command=/root/proxy-linux/proxy http -t tcp -p 10.20.x.x:443
priority=1
numprocs=1
autostart=true
autorestart=true
startretries=10
exitcodes=0
stopsignal=KILL
stopwaitsecs=10
redirect_stderr=true
logfile=/root/proxy-linux/proxy.log
logfile_maxbytes=50MB
logfile_backups=10
loglevel=info
AI 代码解读
设置好配置后通过supervisorctl update加载最新配置并启动代理,通过supervisorctl status可以查看进程状态
流水线主机配置
代理运行后在流水线K8S所有节点的主机/etc/hosts中添加,这里的IP是深圳及杭州SLB的IP
10.20.x.x registry.cn-shenzhen.aliyuncs.com
10.30.x.x registry.cn-hangzhou.aliyuncs.com
结果
自测
登录到K8S集群任意一台Worker节点
使用docker login登录到深圳镜像仓库
创建Dockerfile
FROM alpine:3.12
COPY data.bin /data.bin
构建镜像并推送
dd if=/dev/urandom of=data.bin bs=100M count=1 sudo docker rmi registry.cn-shenzhen.aliyuncs.com/namespace/random-speed-test:1.0 sudo docker build -t registry.cn-shenzhen.aliyuncs.com/namespace/random-speed-test:1.0 . date sudo docker push registry.cn-shenzhen.aliyuncs.com/namespace/random-speed-test:1.0 date
AI 代码解读
这里先使用dd命令生成了一个内容随机的data.bin文件大小100MB,因为Docker镜像push时如果层内容在服务器上已存在不会再推送,使用随机文件保证每轮测试都会推送。
通过控制hosts中的条目可以控制推送走CEN或公网流量。
测试结果:
序号 | CEN+代理 | 公网 |
---|---|---|
1 | 34s | 35s |
2 | 32s | 96s |
3 | 34s | 48s |
从测试结果中可以看出通过CEN+代理推送时长稳定较短,走公网时长不固定变化还比较大。测试较大的镜像得到结果也类似。
生产环境
使用代理前下午16~17点左右偶发性出现推送镜像耗时很长使用代理后未再出现。