本文介绍了如何从专线或VPN内网通过ECR Endpoint向ECR上传镜像。
一、背景
在数据安全和合规的场景中,用户可能希望全程通过内网完成Docker Image的上传,而不通过Internet。此时,可借助专线/VPN,通过ECR Endpoint,实现通过内网上传。整个体系架构图如下。
在以上架构中,左侧是AWS云上Region,在其中有ECR容器镜像仓库和S3存储桶(本实验中不需要配置S3 Endpoint即可工作)。为了让ECR能够从VPC内网访问,需要创建ECR所属的2个VPC Endpoint。在右侧是客户自己的IDC,与AWS云上Region通过专线或者VPN互通。
为了实现让开发者推送镜像的流量通过内网而不是Internet互联网来发送,需要在IDC内网配置私有DNS解析,让开发者的笔记本访问ECR域名时候,指向内网VPC Endpoint的别名。这样即可确保流量全都在内网上。
本文探讨了一个最小化配置,云端只配置最少的VPC Endpoint域名,IDC只配置最少的解析记录。
二、配置ECR Endpoint
本文假设使用者已经具备基本的AWS技能,不在详细描述专线/VPN、VPC、安全组等创建过程。
1、创建VPC Endpoint使用的安全规则组
首先在ECR所在Region创建一个VPC Endpoint专用的安全规则组。这个安全规则组内容需要包括:
- 允许本VPC的CIDR作为来源地址来访问
- 允许IDC的CIDR作为来源地址来访问
配置好的安全组如下截图。
2、创建ECR API Endpoint
进入VPC服务界面,从左侧菜单找到Endpoint终端节点,从右侧点击新建。如下截图。
在名称位置,输入ecr-api
,在服务类别位置选择AWS services
。如下截图。
在搜索框中,输入关键字ecr
,然后从过滤结果中,选择com.amazonaws.ap-southeast-1.ecr.api
。在下方VPC中,选择云上VPC。如下截图。
在VPC的子网清单中,选择了一个私有子网。如果只是开发者向云端ECR上传镜像,那么这里只选择一个子网创建Endpoint即可节省成本。如果是生产环境,且云端还有多种服务也从VPC内网调用ECR,那么这里就需要选择多可用区。如下截图。
从安全组列表中,选择上一步创建的VPC Endpoint专用的安全规则组。如下截图。
在Policy位置选择Full access
。如下截图。
在Tag标签位置保持默认值不需要修改。点击右下角创建按钮。如下截图。
创建成功。
3、创建ECR DKG Endpoint
在名称位置,输入ecr-dkr
,在服务类别位置选择AWS services
。如下截图。
在搜索框中,输入关键字ecr
,然后从过滤结果中,选择com.amazonaws.ap-southeast-1.ecr.dkr
。在下方VPC中,选择云上VPC。如下截图。
其他后续步骤,与上一步创建ECR API的Endpoint选项和流程相同。这里不再赘述。
创建ECR所需要的Endpoint完毕。
三、在IDC私有DNS中添加解析(客户真实环境需要的配置)
1、ECR API的VPC Enpoint需要的解析
在创建ECR所需要的Endpoint完毕之后,可以通过VPC Endpoint页面,获取Endpoint地址,以及要在本地IDC增加的解析记录。如下截图。
在以上截图中,可以看到多条域名记录,这里解释如下:
- 以
vpce-xxxx
开头的,是VPC Endpoint的别名,如果有多个可用,这个别名会自动解析到多个可用区轮训。如果只有一个可用区,那么这一条只会解析到唯一的可用区的Endpoint。 - 以
vpce-xxxx
开头的、但是其中包含ap-southeast-1a
这种形式的,是单个AZ对应的Endpoint的名字,在日常用,不需要使用这个名字。 - 最后一条是要增加解析的ECR服务完整域名。
根据以上解释说明,现在可以确认下来要增加的解析记录了。ECR API接口要增加的解析记录如下。
- 要增加的域名记录(上一张截图的最后一个域名):api.ecr.ap-southeast-1.amazonaws.com
- 解析类型:CNAME
- 值(上一张截图的第一个域名):vpce-0a771b3bbcbe107f4-6mennhxj.api.ecr.ap-southeast-1.vpce.amazonaws.com
请在IDC一侧对以上的域名配置解析。
2、ECR DKR的VPC Enpoint需要的解析
在创建ECR所需要的Endpoint完毕之后,可以通过VPC Endpoint页面,获取Endpoint地址,以及要在本地IDC增加的解析记录。如下截图。
在以上截图中,可以看到多条域名记录,这里解释如下:
- 以
vpce-xxxx
开头的,是VPC Endpoint的别名,如果有多个可用,这个别名会自动解析到多个可用区轮训。如果只有一个可用区,那么这一条只会解析到唯一的可用区的Endpoint。 - 以
vpce-xxxx
开头的、但是其中包含ap-southeast-1a
这种形式的,是单个AZ对应的Endpoint的名字,在日常用,不需要使用这个名字。 - 以
dkr.ecr.region-name
开头的,是dkr服务域名 - 以
*.dkr.ecr.region-name
开头的,是要添加解析的域名,星号开头代表通配符,也叫泛域名,几乎所有的DNS解析系统都支持这种格式的记录,表示所有子域名都需要解析
根据以上解释说明,现在可以确认下来要增加的解析记录了。ECR API接口要增加的解析记录如下。
- 要增加的域名记录(上一张截图的最后一个域名):*.dkr.ecr.ap-southeast-1.amazonaws.com
- 解析类型:CNAME
- 值(上一张截图的第一个域名):vpce-0424acc787dd05730-ypo3xc68.dkr.ecr.ap-southeast-1.vpce.amazonaws.com
这样就完成了DNS解析的配置。
3、添加解析的注意事项:
- 不要将整个
amazonaws.com
或者ap-southeast-1.amazonaws.com
解析过去,这样会影响ECR之外的其他服务。只需要将api.ecr这个记录解析过去,即可满足从内网通过VPC Endpoint上传镜像需要 - DKR服务是需要
*
开头的泛域名解析,技术所有DNS服务都支持这种格式的记录,请咨询DNS管理员进行配置 - VPC Endpoint是禁止ping的,ping只会解析出来IP,不会有ICMP的Response。如果配置正确,VPC Endpoint的443接口是可以通的
- 以上两个解析,请都使用CNAME解析,不要把域名解析为VPC Endpoint对应的内网IP。因为后续
docker push
命令会检查调用接口的HTTPS证书,如果使用VPC Endpoint域名,则一切正常,如果把域名解析到IP,则docker push
命令会报告证书不匹配无法操作 - 改开发者本机
/etc/hostname
是不行的,因为改hostname这种方式,只能完成域名->IP
的解析,不能支持域名->CNAME别名
形式的解析,因此请修改内网DNS实现以上所有配置
四、通过VPC Endpoint向ECR推送Image
1、查看本地现有镜像
配置完成后,即可按照正常流程来操作。进入ECR服务,找到容器镜像仓库。点击右上角View push commands
按钮,即可获得向ECR推送Image的命令。如下截图。
将其中几条命令复制下来。如下截图。
我们假设本地已经build好了image,我们将执行查看本地image名称、ECR身份认证、打tag、和上传一共4个步骤。
执行docker image ls
命令查看现有本地image名称。返回结果如下:
REPOSITORY TAG IMAGE ID CREATED SIZE
ecrtest latest 4fc6d86c1feb 21 hours ago 618MB
public.ecr.aws/amazonlinux/amazonlinux 2 6100d0d8c4fb 2 weeks ago 165MB
从以上结果,可看到本地构建好的容器是ecrtest
,其Tag标签是latest
。接下来进行ECR身份认证。
2、ECR身份认证
前边步骤配置正确的话,本命令流量会自动通过DNS解析指向的VPC Endpoint发送。执行如下命令完成ECR身份认证:
aws ecr get-login-password --region ap-southeast-1 | docker login --username AWS --password-stdin 123456789012.dkr.ecr.ap-southeast-1.amazonaws.com
注意以上命令中有个|
竖线表示管道,是两个命令组合在一起执行。以上命令可以从刚才提到的ECR服务界面,按下View push commands
按钮即可获得命令完整写法。如果您是从本文复制命令出来,那么要替换对应region、AWS账户ID才可以。认证成功,返回结果如下:
WARNING! Your password will be stored unencrypted in /root/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store
Login Succeeded
3、打标签
现在打标签。执行如下命令:
docker tag ecrtest:latest 123456789012.dkr.ecr.ap-southeast-1.amazonaws.com/amzn2023:3
以上命令也可以从ECR服务界面按下View push commands
按钮的提示信息中获得。如果您是从文档直接复制,那么请替换其中的ecrtest:latest
为开发者本地的镜像名字,替换后边的123456789012.dkr.ecr.ap-southeast-1.amazonaws.com/amzn2023:3
为ECR容器镜像仓库的名字。
执行这一步成功的话,直接返回提示符,不会有其他输出信息。
4、上传镜像
最后执行推包命令:
docker push 123456789012.dkr.ecr.ap-southeast-1.amazonaws.com/amzn2023:3
可看到推包成功。
The push refers to repository [133129065110.dkr.ecr.ap-southeast-1.amazonaws.com/amzn2023]
d8336505b4ab: Layer already exists
aa1a744e7ead: Layer already exists
a5169e087ca9: Layer already exists
76ccdf564f6c: Layer already exists
83d19604dff6: Layer already exists
a3e868634a80: Layer already exists
e36244d7b01c: Layer already exists
b21c32065eaf: Layer already exists
3: digest: sha256:b2b575080024b07891e5a369dd4fdf58853b4f7c9167d8f9a307c0d5fde604bc size: 1987
以上就是通过VPC Endpoint从内网向ECR容器镜像仓库推送image的过程。
五、在AWS云上另一个Region模拟IDC的交互行为(针对没有专线对接到IDC用户测试场景)
上述流程已经完整讲述了VPC Endpoint配置、DNS解析配置、推包等过程。针对AWS开发者和学习者,在没有专线对接到IDC用户测试场景中,要进行完整流程测试相对困难。那么此时可以使用同一个AWS账户的两个不同Region,各自创建一个VPC进行测试。
1、模拟IDC环境的关键步骤
准备如下:
- 1个VPC账号,2个Region有效
- 两个Region的VPC的CIDR即IP网段不重叠
- 两个VPC之间跨Region做好VPC Peering
- 两个VPC各自配置好路由表,允许互相流量通过VPC Peering互通
- 选择Region A模拟云端环境,配置ECR容器镜像仓库,配置ECR的Endpoint
- 选择Region B模拟IDC,在其中创建一个EC2作为开发者环境运行docker build命令
- 在模拟IDC环境的EC2上,build好一个docker image
- 为了确保网络环境模拟IDC受限,手工的删除Region B的EC2所在的子网路由表中
0.0.0.0/0
这一条的条目,这意味着本EC2就不能走互联网去访问ECR了,所有流量必须从ECR的VPC Endpoint发布过。当然,您可能会说这样就断网了,那么模拟环境可以用Workspaces跳板机进行登陆,也可以参考这篇文章使用EC2 Instance Connect功能登陆内网
以上环境完全模拟了IDC。现在来配置DNS解析。
2、在Route53上配置ECR API Endpoint所需要的子域名并解析到CNAME
前提到,一共需要ECR API和ECR DKR两个解析,一个是子域名,一个是泛域名。现在进行配置。
前文介绍过,我们要给api.ecr.ap-southeast-1.amazonaws.com
的VPC Endpoint配置CNAME解析。但是,如果在AWS云上的另一个Region来模拟IDC环境发起内网访问,此时配置Route53时候会遇到问题,因为Route53不支持给域名的根记录添加CNAME记录。这是Route53的功能局限导致的。也就是说,当创建了名为api.ecr.ap-southeast-1.amazonaws.com
的Route53 Private Zone后,只能添加xxx.api.ecr.ap-southeast-1.amazonaws.com
这种子域名解析,反而不能添加类型为CNAME的根记录。这个Route53局限性,使得我们在创建Private Zone时候要稍微修改下创建方式。
根据以上原因现在我们改为创建ecr.ap-southeast-1.amazonaws.com
的Private Zone,然后在其中添加一条名为api
的子域名解析,记录类型是CNAME,然后指向Endpoint即可。
进入Route53界面,点击左侧的Hosted zones
菜单,点击右上角的Create hosted zone
创建托管解析。如下截图。
在创建托管解析的界面上,输入名称是ecr.ap-southeast-1.amazonaws.com
,在备注位置可任意输入,选择类型是Private hosted zone
,也就是只对本VPC有效的解析。如下截图。
在Region位置选择模拟IDC环境的EC2所在的Region和对应的VPC。然后点击创建按钮。如下截图。
创建Zone完毕,点击右上角的Create record
按钮创建解析。如下截图。
在解析名称位置,输入api
,在解析类型位置,从下拉框选择为CNAME
类型。在Value
值位置,输入要解析到的VPC Endpoint地址(前文步骤中从VPC Endpoint界面复制出来),在TTL位置点击+1m
,即可自动设置TTL生存期为60秒。最后点击右下角创建记录按钮。如下截图。
创建完毕。如下截图。
创建完毕。等待1分钟左右生效。然后在模拟IDC环境中Docker构建环境的EC2上,使用ping命令探测下解析是否生效。
ping api.ecr.ap-southeast-1.amazonaws.com
返回结果如下:
PING vpce-0a771b3bbcbe107f4-6mennhxj.api.ecr.ap-southeast-1.vpce.amazonaws.com (172.31.60.215) 56(84) bytes of data.
^C
--- vpce-0a771b3bbcbe107f4-6mennhxj.api.ecr.ap-southeast-1.vpce.amazonaws.com ping statistics ---
4 packets transmitted, 0 received, 100% packet loss, time 3066ms
根据前文介绍,VPC Endpoint是不会返回ICMP Response的,也就是俗称是ping不通的,但是确实可以看到解析成功。此外使用CURL命令访问443端口也是活跃的。这里用ping探测的主要目的是看到域名解析如预期一样返回了CNAME,并且CNAME也正确的解析到了VPC内网IP。配置成功。
注意:前文已经介绍,添加解析时候请使用CNAME记录,不要使用A记录解析到IP地址,否则后续ECR身份认证会报错提示SSL证书错误。
3、在Route53上配置ECR DKR Endpoint所需要的泛域名解析
退出当前编辑Zone内Record的界面,返回Route53控制台,再次点击Create zone
按钮,创建一个DKR服务所使用的新的zone。
在创建界面中,输入完整的DKR域名,即dkr.ecr.ap-southeast-1.amazonaws.com
。如下截图。
继续完成Region和VPC设置,创建Zone完成。(与上一步相同,不再截图描述)。
进入刚创建好的DKR的zone。点击Create record
按钮添加泛域名解析。如下截图。
在解析名称位置,输入通配符*
,在解析类型位置,从下拉框选择为CNAME
类型。在Value
值位置,输入要解析到的VPC Endpoint地址vpce-0424acc787dd05730-ypo3xc68.dkr.ecr.ap-southeast-1.vpce.amazonaws.com
(可前文步骤中从VPC Endpoint界面复制出来),在TTL位置点击+1m
,即可自动设置TTL生存期为60秒。最后点击右下角创建记录按钮。如下截图。
创建完毕。等待1分钟左右生效。然后在模拟IDC环境中Docker构建环境的EC2上,使用ping命令探测下解析是否生效。
ping abc123.dkr.ecr.ap-southeast-1.amazonaws.com
返回结果如下:
PING vpce-0424acc787dd05730-ypo3xc68.dkr.ecr.ap-southeast-1.vpce.amazonaws.com (172.31.51.137) 56(84) bytes of data.
^C
--- vpce-0424acc787dd05730-ypo3xc68.dkr.ecr.ap-southeast-1.vpce.amazonaws.com ping statistics ---
2 packets transmitted, 0 received, 100% packet loss, time 1025ms
根据前文介绍,VPC Endpoint是不会返回ICMP Response的,也就是俗称是ping不通的,但是确实可以看到泛域名解析成功,将随意输入的abc123的子域名解析到Endpoint。此外使用CURL命令访问443端口也是活跃的。这里用ping探测的主要目的是看到域名解析如预期一样返回了CNAME,并且CNAME也正确的解析到了VPC内网IP。配置成功。
注意:前文已经介绍,添加解析时候请使用CNAME记录,不要使用A记录解析到IP地址,否则后续ECR身份认证会报错提示SSL证书错误。
4、从另一个Region的EC2上走VPC Endpoint内网推包测试
按与IDC相同的操作步骤,完成ECR身份验证,打tag,执行docker push
命令推包,可看到走VPC Endpoint通过内网推包成功。
六、参考文档
Create the VPC endpoints for Amazon ECR
https://docs.aws.amazon.com/AmazonECR/latest/userguide/vpc-endpoints.html#ecr-setting-up-vpc-create