从专线或VPN内网通过ECR Endpoint向ECR上传镜像

本文介绍了如何从专线或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