ACK 跨 CEN 拉取 ACR VPC 镜像 ImagePullBackOff: dockerauth-ee-vpc 超时排查
以下命令里的地域、VPC、TR、路由表、域名和 IP 都做了占位处理。为了让链路方向更容易读,本文用“杭州侧”表示 ACR 所在地域,用“泰国侧”表示 ACK 集群所在地域。落地时把
<REGION_A>、<REGION_B>、<CEN_ID>、<TR_*>、<VPC_*>、<ROUTE_TABLE_*>、<ACR_AUTH_IP>、<ACR_OSS_INTERNAL_CIDR>等替换成自己的真实值即可。
一次 ACK 发布失败时,业务 Pod 卡在 ImagePullBackOff。表面看是镜像拉不下来,但真正的断点不在镜像仓库域名,而在 ACR VPC 鉴权域名:
failed to fetch oauth token:
Post "https://dockerauth-ee-vpc.<REGION_A>.aliyuncs.com/auth":
dial tcp <ACR_AUTH_IP>:443: i/o timeout
这类问题容易误判成“镜像太大”“节点拉镜像慢”“公网链路抖动”。实际排查时要把镜像拉取拆成三条链路:
registry-vpc.<REGION_A>.cr.aliyuncs.com:443 镜像仓库
dockerauth-ee-vpc.<REGION_A>.aliyuncs.com:443 ACR OAuth 鉴权
<acr-instance>-registry.oss-<REGION_A>-internal.aliyuncs.com:443 blob layer 下载
只要鉴权域名不通,镜像再小也拉不下来;鉴权通了以后,真正下载 layer 时还可能卡在 OSS internal 地址。

环境和现象
环境抽象如下:
| 项目 | 示例 |
|---|---|
| ACK 集群所在地域 | 泰国侧,命令中写作 <REGION_B>,RegionId 示例 ap-southeast-7 |
| ACR 企业版实例所在地域 | 杭州侧,命令中写作 <REGION_A>,RegionId 示例 cn-hangzhou |
| ACK 节点示例 IP | 192.168.1.1 |
| ACR VPC Registry | <acr-name>-registry-vpc.<REGION_A>.cr.aliyuncs.com |
| ACR VPC Auth | dockerauth-ee-vpc.<REGION_A>.aliyuncs.com |
| ACR Auth 私网 IP | <ACR_AUTH_IP> |
| ACR OSS Internal | <acr-instance>-registry.oss-<REGION_A>-internal.aliyuncs.com |
| ACR OSS Internal 网段 | <ACR_OSS_INTERNAL_CIDR> |
| 打通方式 | CEN / 企业版转发路由器 TR |
先用一个很小的 busybox 镜像测试,不要一开始就拿几百 MB 或几十 GB 的业务镜像测。测试 Pod 固定到问题节点上:
apiVersion: v1
kind: Pod
metadata:
name: acr-vpc-pull-test
namespace: test
spec:
nodeName: <ACK_NODE_NAME>
restartPolicy: Never
containers:
- name: busybox
image: <acr-name>-registry-vpc.<REGION_A>.cr.aliyuncs.com/devops/busybox:latest
imagePullPolicy: Always
command: ["sh", "-c", "sleep 3600"]
Pod 事件里看到的错误:
kubectl -n test get pod acr-vpc-pull-test -o wide
kubectl -n test get pod acr-vpc-pull-test \
-o jsonpath='phase={.status.phase}{"\n"}{range .status.containerStatuses[*]}name={.name} ready={.ready} imageID={.imageID} state={.state}{"\n"}{end}'
kubectl -n test get events \
--field-selector involvedObject.name=acr-vpc-pull-test \
--sort-by=.lastTimestamp
关键输出类似:
STATUS: ImagePullBackOff
failed to pull and unpack image ".../devops/busybox:latest":
failed to authorize:
failed to fetch oauth token:
Post "https://dockerauth-ee-vpc.<REGION_A>.aliyuncs.com/auth":
dial tcp <ACR_AUTH_IP>:443: i/o timeout
这里已经能确认:失败发生在 ACR 鉴权阶段,而不是业务容器启动、readiness、镜像命令或应用本身。
一、先在 ACK 节点上拆开测 registry 和 auth
登录到实际承载 Pod 的 ACK 节点,只测 TCP 443:
getent hosts <acr-name>-registry-vpc.<REGION_A>.cr.aliyuncs.com
getent hosts dockerauth-ee-vpc.<REGION_A>.aliyuncs.com
ip route get <ACR_AUTH_IP>
timeout 8 bash -lc '</dev/tcp/<acr-name>-registry-vpc.<REGION_A>.cr.aliyuncs.com/443' \
&& echo REGISTRY_VPC_443_OK || echo REGISTRY_VPC_443_FAIL
timeout 8 bash -lc '</dev/tcp/dockerauth-ee-vpc.<REGION_A>.aliyuncs.com/443' \
&& echo DOCKERAUTH_VPC_443_OK || echo DOCKERAUTH_VPC_443_FAIL
这次现场的关键结果是:
<acr-name>-registry-vpc.<REGION_A>.cr.aliyuncs.com:443 OK
dockerauth-ee-vpc.<REGION_A>.aliyuncs.com:443 FAIL
所以不能再说“VPC ACR 都不通”。它只是不通鉴权服务。
为了排除 ACR 自身故障,再找一台 ACR 所在地域 VPC 内的 ECS 做同样测试:
getent hosts <acr-name>-registry-vpc.<REGION_A>.cr.aliyuncs.com
getent hosts dockerauth-ee-vpc.<REGION_A>.aliyuncs.com
timeout 8 bash -lc '</dev/tcp/<acr-name>-registry-vpc.<REGION_A>.cr.aliyuncs.com/443' \
&& echo REGISTRY_VPC_443_OK || echo REGISTRY_VPC_443_FAIL
timeout 8 bash -lc '</dev/tcp/dockerauth-ee-vpc.<REGION_A>.aliyuncs.com/443' \
&& echo DOCKERAUTH_VPC_443_OK || echo DOCKERAUTH_VPC_443_FAIL
如果同地域 VPC 内结果是两个都 OK,而跨地域 ACK 节点只有 auth FAIL,问题边界就收敛到 CEN/TR 路由。
二、确认 ACK 节点属于哪个 VPC 和安全组
先拿到节点对应 ECS 实例的 VPC、交换机、安全组:
aliyun ecs DescribeInstances \
--RegionId <REGION_B> \
--InstanceIds '["<ACK_NODE_INSTANCE_ID>"]' \
| jq -r '.Instances.Instance[] | {
InstanceId,
InstanceName,
ZoneId,
VpcId:.VpcAttributes.VpcId,
VSwitchId:.VpcAttributes.VSwitchId,
PrivateIp:.VpcAttributes.PrivateIpAddress.IpAddress[0],
SecurityGroups:.SecurityGroupIds.SecurityGroupId
}'
再查安全组出方向,避免被 egress 限制误导:
aliyun ecs DescribeSecurityGroupAttribute \
--RegionId <REGION_B> \
--SecurityGroupId <ACK_NODE_SECURITY_GROUP_ID> \
--Direction egress \
| jq -r '.Permissions.Permission[]? |
[.Direction,.IpProtocol,.PortRange,.DestCidrIp,.Policy,.Priority,.Description] | @tsv'
如果出方向已经放行 0.0.0.0/0 或至少放行 <ACR_AUTH_IP>:443,就继续看路由。
三、VPC 控制台:确认泰国侧 ACK VPC 路由表是否把杭州侧 ACR Auth IP 指向 TR
这一节配置的是 泰国侧 ACK 节点所在 VPC 的路由表。入口在 VPC 控制台,不在 CEN 控制台。
配置入口:
阿里云控制台
-> 专有网络 VPC
-> 切到泰国侧 ACK 集群所在地域 <REGION_B>
-> 专有网络
-> 进入泰国侧 ACK 节点所在 VPC <VPC_ACK>
-> 路由表
-> 选择 ACK 节点交换机绑定的路由表 <ACK_VPC_ROUTE_TABLE_ID>
查询 ACK VPC 的路由表:
aliyun vpc DescribeRouteTableList \
--RegionId <REGION_B> \
--VpcId <VPC_ACK> \
| jq -r '.RouterTableList.RouterTableListType[]? |
[.RouteTableId,.RouteTableName,.RouteTableType,.VpcId,(.VSwitchIds.VSwitchId|tostring)] | @tsv'
查询路由条目:
aliyun vpc DescribeRouteEntryList \
--RegionId <REGION_B> \
--RouteTableId <ACK_VPC_ROUTE_TABLE_ID> \
--MaxResult 100 \
| jq -r '.RouteEntrys.RouteEntry[]? |
[.DestinationCidrBlock,.NextHopType,(.NextHops.NextHop[0].NextHopId // .NextHopId // ""),.Status,.RouteEntryType,.ServiceType,.RouteEntryName] | @tsv' \
| sort
这里要重点找:
<ACR_AUTH_IP>/32 -> <SG_TR_VPC_ATTACHMENT>
阿里云会提示:
100.64.0.0/10 及其子集是云服务网段,在配置跨地域访问云服务时建议配置服务所在地域的精细 IP,
避免 IP 配置范围过大导致本地域云服务不通。
所以不要粗暴把 100.64.0.0/10 全部扔进 CEN。这里应该只配 dockerauth-ee-vpc 解析出来的精细 IP,例如 <ACR_AUTH_IP>/32。
如果 ACK VPC 路由表缺这条,就在 ACK 节点交换机绑定的路由表里补。节点池如果跨多个交换机,要确认这些交换机是不是绑定同一张路由表;如果不是,就逐张补同一条路由。
新增路由条目的控制台入口:
VPC 控制台
-> 路由表 <ACK_VPC_ROUTE_TABLE_ID>
-> 路由条目列表
-> 添加路由条目
表单这样填:
| 字段 | 值 |
|---|---|
| 名称 | acr-dockerauth-vpc-to-tr |
| 资源组 | 可不选 |
| 目标网段 | <ACR_AUTH_IP>/32 |
| 下一跳类型 | 转发路由器 |
| 转发路由器 | <VPC_ATTACHMENT_REGION_B>,也就是泰国侧 ACK VPC 连接到泰国侧 TR 的 VPC Attachment |
| 描述 | Route ACR VPC dockerauth traffic to TR |
CLI 模板:
aliyun vpc CreateRouteEntry \
--RegionId <REGION_B> \
--RouteTableId <ACK_VPC_ROUTE_TABLE_ID> \
--DestinationCidrBlock <ACR_AUTH_IP>/32 \
--NextHopType Attachment \
--NextHopId <VPC_ATTACHMENT_REGION_B> \
--RouteEntryName acr-dockerauth-vpc-to-tr \
--Description 'Route ACR VPC dockerauth traffic to TR'
如果 ACK VPC 路由表已经有 <ACR_AUTH_IP>/32 -> TR Attachment,但节点仍然超时,说明问题不在 VPC 路由表本身,而是在 TR 路由表里。
四、CEN 控制台:确认泰国侧 / 杭州侧 VPC Attachment 和跨地域 Peer
这一节配置的是 CEN / 企业版转发路由器 TR 的连接关系。入口在 CEN 控制台,不在 VPC 路由表里。
配置入口:
阿里云控制台
-> 云企业网 CEN
-> 转发路由器
-> 选择对应地域的 TR,例如泰国侧 <TR_REGION_B> 或杭州侧 <TR_REGION_A>
-> 网络实例连接 / 跨地域连接
列出 CEN:
aliyun cbn DescribeCens --PageSize 50 \
| jq -r '.Cens.Cen[]? | [.CenId,.Name,.Status,.CreationTime] | @tsv'
确认两个地域的 VPC 都已挂载:
aliyun cbn DescribeCenAttachedChildInstances \
--CenId <CEN_ID> \
--ChildInstanceType VPC \
--ChildInstanceRegionId <REGION_A> \
--PageNumber 1 \
--PageSize 50 \
| jq -r '.ChildInstances.ChildInstance[]? |
[.ChildInstanceId,.ChildInstanceRegionId,.ChildInstanceType,.Status,.ChildInstanceOwnerId] | @tsv'
aliyun cbn DescribeCenAttachedChildInstances \
--CenId <CEN_ID> \
--ChildInstanceType VPC \
--ChildInstanceRegionId <REGION_B> \
--PageNumber 1 \
--PageSize 50 \
| jq -r '.ChildInstances.ChildInstance[]? |
[.ChildInstanceId,.ChildInstanceRegionId,.ChildInstanceType,.Status,.ChildInstanceOwnerId] | @tsv'
企业版转发路由器场景下,再查两个地域的 TR:
aliyun cbn ListTransitRouters \
--CenId <CEN_ID> \
| jq -r '.TransitRouters[]? | [.TransitRouterId,.TransitRouterName,.RegionId,.Status,.Type] | @tsv'
查 ACK 所在地域的 VPC attachment:
aliyun cbn ListTransitRouterVpcAttachments \
--CenId <CEN_ID> \
--RegionId <REGION_B> \
--MaxResults 100 \
| jq -r '.TransitRouterAttachments[]? |
[.TransitRouterAttachmentId,.TransitRouterId,.RegionId,.VpcId,.VpcOwnerId,.Status,.TransitRouterAttachmentName] | @tsv'
查 ACR 所在地域的 VPC attachment:
aliyun cbn ListTransitRouterVpcAttachments \
--CenId <CEN_ID> \
--RegionId <REGION_A> \
--MaxResults 100 \
| jq -r '.TransitRouterAttachments[]? |
[.TransitRouterAttachmentId,.TransitRouterId,.RegionId,.VpcId,.VpcOwnerId,.Status,.TransitRouterAttachmentName] | @tsv'
如果某个 VPC 没挂到对应地域的 TR,需要先创建 VPC Attachment。控制台入口:
阿里云控制台
-> 云企业网 CEN
-> 转发路由器
-> 选择对应地域的 TR <TR_REGION_X>
-> 网络实例连接
-> 创建网络实例连接
-> 网络实例类型选择 VPC
泰国侧 ACK 所在地域 VPC Attachment 的表单重点:
| 字段 | 值 |
|---|---|
| 地域 | 泰国侧 <REGION_B> |
| 转发路由器 | 泰国侧 <TR_REGION_B> |
| 网络实例类型 | VPC |
| 专有网络 | <VPC_ACK> |
| 交换机 | 选择 ACK VPC 内用于连接 TR 的可用区和交换机 |
| 名称 | cen-vpc-ack |
| 自动发布路由 | 按现网策略选择;不确定时先关闭,后续用静态路由精细控制 |
杭州侧也按同样方式把 ACR 所在 VPC 挂到杭州侧 <TR_REGION_A>。
CLI 预检模板:
aliyun cbn CreateTransitRouterVpcAttachment \
--DryRun true \
--CenId <CEN_ID> \
--RegionId <REGION_B> \
--TransitRouterId <TR_REGION_B> \
--VpcId <VPC_ACK> \
--ZoneMappings.1.ZoneId <ZONE_ID_1> \
--ZoneMappings.1.VSwitchId <VSWITCH_ID_1> \
--TransitRouterAttachmentName cen-vpc-ack \
--TransitRouterAttachmentDescription 'Attach ACK VPC to TR'
查两个地域之间的 peer attachment:
aliyun cbn ListTransitRouterPeerAttachments \
--CenId <CEN_ID> \
--RegionId <REGION_B> \
--MaxResults 100 \
| jq -r '.TransitRouterAttachments[]? |
[.TransitRouterAttachmentId,.TransitRouterId,.PeerTransitRouterRegionId,.PeerTransitRouterId,.Status,.TransitRouterAttachmentName] | @tsv'
aliyun cbn ListTransitRouterPeerAttachments \
--CenId <CEN_ID> \
--RegionId <REGION_A> \
--MaxResults 100 \
| jq -r '.TransitRouterAttachments[]? |
[.TransitRouterAttachmentId,.TransitRouterId,.PeerTransitRouterRegionId,.PeerTransitRouterId,.Status,.TransitRouterAttachmentName] | @tsv'
需要看到跨地域 peer attachment 是 Attached。
如果两个地域 TR 之间没有 peer attachment,需要创建跨地域连接。控制台入口:
阿里云控制台
-> 云企业网 CEN
-> 转发路由器
-> 选择泰国侧本端地域 TR <TR_REGION_B>
-> 跨地域连接
-> 创建跨地域连接
表单重点:
| 字段 | 值 |
|---|---|
| 本端地域 | 泰国侧 <REGION_B> |
| 本端转发路由器 | 泰国侧 <TR_REGION_B> |
| 对端地域 | 杭州侧 <REGION_A> |
| 对端转发路由器 | 杭州侧 <TR_REGION_A> |
| 带宽分配方式 | 按现网计费和带宽规划选择 |
| 名称 | cen-peer-region-b-region-a |
| 自动发布路由 | 按现网策略选择;排障时建议先用静态路由精细控制 |
CLI 预检模板:
aliyun cbn CreateTransitRouterPeerAttachment \
--DryRun true \
--CenId <CEN_ID> \
--RegionId <REGION_B> \
--TransitRouterId <TR_REGION_B> \
--PeerTransitRouterRegionId <REGION_A> \
--PeerTransitRouterId <TR_REGION_A> \
--BandwidthType DataTransfer \
--TransitRouterAttachmentName cen-peer-region-b-region-a \
--TransitRouterAttachmentDescription 'Peer TR between ACK region and ACR region'
五、CEN 控制台:查泰国侧 / 杭州侧 TR 路由表有没有 ACR Auth IP
这一节配置的是 转发路由器 TR 的路由表。入口仍然在 CEN 控制台,但它和第四节不同:第四节看连接是否存在,第五节看路由条目是否存在。
配置入口:
阿里云控制台
-> 云企业网 CEN
-> 转发路由器
-> 选择泰国侧 <TR_REGION_B> 或杭州侧 <TR_REGION_A>
-> 路由表
-> 选择路由表 <TR_RT_REGION_B 或 TR_RT_REGION_A>
-> 路由条目
列出泰国侧 ACK 所在地域 TR 的路由表:
aliyun cbn ListTransitRouterRouteTables \
--TransitRouterId <TR_REGION_B> \
--MaxResults 100 \
| jq -r '.TransitRouterRouteTables[]? |
[.TransitRouterRouteTableId,.TransitRouterRouteTableName,.TransitRouterRouteTableType,.TransitRouterRouteTableStatus] | @tsv'
列出杭州侧 ACR 所在地域 TR 的路由表:
aliyun cbn ListTransitRouterRouteTables \
--TransitRouterId <TR_REGION_A> \
--MaxResults 100 \
| jq -r '.TransitRouterRouteTables[]? |
[.TransitRouterRouteTableId,.TransitRouterRouteTableName,.TransitRouterRouteTableType,.TransitRouterRouteTableStatus] | @tsv'
然后查泰国侧 ACK 所在地域 TR 是否有杭州侧 ACR Auth IP <ACR_AUTH_IP>/32:
aliyun cbn ListTransitRouterRouteEntries \
--TransitRouterRouteTableId <TR_RT_REGION_B> \
--TransitRouterRouteEntryDestinationCidrBlock <ACR_AUTH_IP>/32 \
--TransitRouterRouteEntryStatus All \
--MaxResults 100
再查杭州侧 ACR 所在地域 TR 是否有 <ACR_AUTH_IP>/32:
aliyun cbn ListTransitRouterRouteEntries \
--TransitRouterRouteTableId <TR_RT_REGION_A> \
--TransitRouterRouteEntryDestinationCidrBlock <ACR_AUTH_IP>/32 \
--TransitRouterRouteEntryStatus All \
--MaxResults 100
这次现场就是两边 TR 路由表都没有 <ACR_AUTH_IP>/32。ACK VPC 路由表虽然把流量送进了 TR,但 TR 自己没有下一跳,最终表现为节点访问 dockerauth-ee-vpc 超时。
同时可以查回程路由作为旁证:
aliyun cbn ListTransitRouterRouteEntries \
--TransitRouterRouteTableId <TR_RT_REGION_A> \
--TransitRouterRouteEntryDestinationCidrBlock <ACK_NODE_CIDR> \
--TransitRouterRouteEntryStatus All \
--MaxResults 100
例如 <ACK_NODE_CIDR> 是 ACK 节点所在交换机或 VPC 网段。回程路由存在时,问题通常集中在去程的云服务 IP 路由。

如果缺失,就在第五步直接补两边 TR 静态路由。
1. 泰国侧 ACK 所在地域 TR:把 Auth IP 指向跨地域 Peer
控制台添加入口:
CEN 控制台
-> 转发路由器
-> 泰国侧 <TR_REGION_B>
-> 路由表
-> <TR_RT_REGION_B>
-> 路由条目
-> 添加路由条目
控制台字段:
| 字段 | 值 |
|---|---|
| 路由表 | <TR_RT_REGION_B> |
| 所属转发路由器 | 泰国侧 <TR_REGION_B> |
| 路由条目名称 | acr-dockerauth-vpc-to-region-a |
| 目的地址 CIDR | <ACR_AUTH_IP>/32 |
| 是否为黑洞路由 | 否 |
| 下一跳连接 | <PEER_ATTACHMENT_REGION_B_TO_A> |
| 描述 | Route ACR VPC dockerauth to region A via CEN |
CLI 模板:
aliyun cbn CreateTransitRouterRouteEntry \
--TransitRouterRouteTableId <TR_RT_REGION_B> \
--TransitRouterRouteEntryDestinationCidrBlock <ACR_AUTH_IP>/32 \
--TransitRouterRouteEntryNextHopType Attachment \
--TransitRouterRouteEntryNextHopId <PEER_ATTACHMENT_REGION_B_TO_A> \
--TransitRouterRouteEntryName acr-dockerauth-vpc-to-region-a \
--TransitRouterRouteEntryDescription 'Route ACR VPC dockerauth to region A via CEN'
2. 杭州侧 ACR 所在地域 TR:把 Auth IP 指向 ACR 所在 VPC Attachment
控制台添加入口:
CEN 控制台
-> 转发路由器
-> 杭州侧 <TR_REGION_A>
-> 路由表
-> <TR_RT_REGION_A>
-> 路由条目
-> 添加路由条目
控制台字段:
| 字段 | 值 |
|---|---|
| 路由表 | <TR_RT_REGION_A> |
| 所属转发路由器 | 杭州侧 <TR_REGION_A> |
| 路由条目名称 | acr-dockerauth-vpc |
| 目的地址 CIDR | <ACR_AUTH_IP>/32 |
| 是否为黑洞路由 | 否 |
| 下一跳连接 | <VPC_ATTACHMENT_REGION_A> |
| 描述 | Route ACR VPC dockerauth to ACR VPC |
CLI 模板:
aliyun cbn CreateTransitRouterRouteEntry \
--TransitRouterRouteTableId <TR_RT_REGION_A> \
--TransitRouterRouteEntryDestinationCidrBlock <ACR_AUTH_IP>/32 \
--TransitRouterRouteEntryNextHopType Attachment \
--TransitRouterRouteEntryNextHopId <VPC_ATTACHMENT_REGION_A> \
--TransitRouterRouteEntryName acr-dockerauth-vpc \
--TransitRouterRouteEntryDescription 'Route ACR VPC dockerauth to ACR VPC'
如果担心误操作,先加 --DryRun true 做预检。
六、验证:先测节点,再看 Pod
先查两条路由都已经 Active:
aliyun cbn ListTransitRouterRouteEntries \
--TransitRouterRouteTableId <TR_RT_REGION_B> \
--TransitRouterRouteEntryDestinationCidrBlock <ACR_AUTH_IP>/32 \
--TransitRouterRouteEntryStatus All \
--MaxResults 100
aliyun cbn ListTransitRouterRouteEntries \
--TransitRouterRouteTableId <TR_RT_REGION_A> \
--TransitRouterRouteEntryDestinationCidrBlock <ACR_AUTH_IP>/32 \
--TransitRouterRouteEntryStatus All \
--MaxResults 100
期望看到:
TransitRouterRouteEntryStatus: Active
TransitRouterRouteEntryType: Static
TransitRouterRouteEntryNextHopType: Attachment
再回到 ACK 节点测:
getent hosts dockerauth-ee-vpc.<REGION_A>.aliyuncs.com
ip route get <ACR_AUTH_IP>
timeout 8 bash -lc '</dev/tcp/dockerauth-ee-vpc.<REGION_A>.aliyuncs.com/443' \
&& echo DOCKERAUTH_VPC_443_OK || echo DOCKERAUTH_VPC_443_FAIL
timeout 8 bash -lc '</dev/tcp/<acr-name>-registry-vpc.<REGION_A>.cr.aliyuncs.com/443' \
&& echo REGISTRY_VPC_443_OK || echo REGISTRY_VPC_443_FAIL
修复后应该是:
DOCKERAUTH_VPC_443_OK
REGISTRY_VPC_443_OK
最后看测试 Pod:
kubectl -n test get pod acr-vpc-pull-test -o wide
kubectl -n test get pod acr-vpc-pull-test \
-o jsonpath='phase={.status.phase}{"\n"}{range .status.containerStatuses[*]}name={.name} ready={.ready} restart={.restartCount} imageID={.imageID} state={.state}{"\n"}{end}'
kubectl -n test get events \
--field-selector involvedObject.name=acr-vpc-pull-test \
--sort-by=.lastTimestamp \
| tail -30
期望状态:
STATUS: Running
READY: 1/1
imageID: <acr-name>-registry-vpc.<REGION_A>.cr.aliyuncs.com/devops/busybox@sha256:...
这时才说明 ACR VPC 拉取链路真的打通了。
七、auth 通了以后,还要检查 OSS internal blob 下载
有一种容易漏的情况:registry-vpc 和 dockerauth-ee-vpc 都通了,小镜像也可能拉通,但业务镜像仍然失败。Pod 事件里会出现类似错误:
failed to copy:
httpReadSeeker: failed open:
failed to do request:
Get "https://<acr-instance>-registry.oss-<REGION_A>-internal.aliyuncs.com/docker/registry/v2/blobs/.../data?...":
dial tcp <ACR_OSS_INTERNAL_IP>:443: i/o timeout
这说明已经越过 OAuth 鉴权,卡在下载镜像 layer 的 OSS internal 地址上。先在 ACK 节点上拆开测:
OSS_HOST=<acr-instance>-registry.oss-<REGION_A>-internal.aliyuncs.com
getent hosts "$OSS_HOST"
for ip in <ACR_OSS_INTERNAL_IP_1> <ACR_OSS_INTERNAL_IP_2> <ACR_OSS_INTERNAL_IP_3> <ACR_OSS_INTERNAL_IP_4>; do
echo "ip route get $ip"
ip route get "$ip" 2>&1 || true
done
timeout 8 bash -lc "</dev/tcp/$OSS_HOST/443" \
&& echo OSS_INTERNAL_HOST_443_OK || echo OSS_INTERNAL_HOST_443_FAIL
for ip in <ACR_OSS_INTERNAL_IP_1> <ACR_OSS_INTERNAL_IP_2> <ACR_OSS_INTERNAL_IP_3> <ACR_OSS_INTERNAL_IP_4>; do
timeout 8 bash -lc "</dev/tcp/$ip/443" && echo "$ip OK" || echo "$ip FAIL"
done
如果 DNS 返回多个 IP,不要只给失败日志里出现的那个 IP 加 /32。更稳妥的是确认这些 IP 落在哪个精细网段,例如:
<ACR_OSS_INTERNAL_CIDR> -> 例如某个 /24
然后分别核对三层路由。
ACK VPC 路由表:
aliyun vpc DescribeRouteEntryList \
--RegionId <REGION_B> \
--RouteTableId <ACK_VPC_ROUTE_TABLE_ID> \
--DestinationCidrBlock <ACR_OSS_INTERNAL_CIDR> \
--MaxResult 100
ACK 所在地域 TR 路由表:
aliyun cbn ListTransitRouterRouteEntries \
--TransitRouterRouteTableId <TR_RT_REGION_B> \
--TransitRouterRouteEntryDestinationCidrBlock <ACR_OSS_INTERNAL_CIDR> \
--TransitRouterRouteEntryStatus All \
--MaxResults 100
ACR 所在地域 TR 路由表:
aliyun cbn ListTransitRouterRouteEntries \
--TransitRouterRouteTableId <TR_RT_REGION_A> \
--TransitRouterRouteEntryDestinationCidrBlock <ACR_OSS_INTERNAL_CIDR> \
--TransitRouterRouteEntryStatus All \
--MaxResults 100
如果两边 TR 已经有 <ACR_OSS_INTERNAL_CIDR>,但泰国侧 ACK VPC 路由表没有,就在泰国侧 ACK VPC 路由表补一条到本地域 TR attachment。注意这一步不是去 CEN/TR 路由表里加,而是去泰国侧 ACK 节点所在地域的 VPC 路由表里加。
先确认要改哪张 VPC 路由表。ACK 节点本质上是 ECS,路由表是跟节点所在交换机绑定的:
# 1. 从 Pod 反查它落在哪个 ACK 节点
kubectl -n <NAMESPACE> get pod <POD_NAME> -o wide
# 2. 看节点的 providerID,里面通常能看到 ECS 实例 ID
kubectl get node <ACK_NODE_NAME> -o jsonpath='{.spec.providerID}{"\n"}'
# 3. 查这个 ECS 实例属于哪个 VPC / VSwitch
aliyun ecs DescribeInstances \
--RegionId <REGION_B> \
--InstanceIds '["<ECS_INSTANCE_ID>"]'
# 4. 查这个 VSwitch 绑定的路由表
aliyun vpc DescribeVSwitchAttributes \
--RegionId <REGION_B> \
--VSwitchId <ACK_NODE_VSWITCH_ID>
如果 ACK 节点池跨了多个交换机,就把每个节点交换机对应的路由表都查出来。生产里常见的是多个交换机共用同一张系统路由表;如果有自定义路由表,就要按实际绑定关系逐张补。
控制台操作路径:
阿里云控制台
-> 专有网络 VPC
-> 切到泰国侧 ACK 集群所在地域 <REGION_B>
-> 专有网络
-> 进入泰国侧 ACK 节点所在 VPC <VPC_ACK>
-> 路由表
-> 选择 ACK 节点交换机绑定的路由表 <ACK_VPC_ROUTE_TABLE_ID>
如果节点跨多个交换机,逐个确认这些交换机绑定的路由表
-> 路由条目列表
-> 添加路由条目
表单这样填:
| 字段 | 值 |
|---|---|
| 名称 | acr-oss-vpc |
| 资源组 | 可不选 |
| 目标网段 | <ACR_OSS_INTERNAL_CIDR> |
| 下一跳类型 | 转发路由器 |
| 转发路由器 | <VPC_ATTACHMENT_REGION_B>,也就是泰国侧 ACK VPC 连接到泰国侧 TR 的 VPC Attachment |
| 描述 | Route ACR OSS internal blob traffic via CEN |
用这次这种场景举例,表单含义是:
目标网段: 杭州侧 ACR 后端 OSS internal 域名解析出的精细网段
下一跳类型: 转发路由器
转发路由器: 泰国侧 ACK VPC 挂到泰国侧 TR 的 VPC attachment
提交后,泰国侧 ACK 节点访问这个杭州侧 OSS internal 网段的流量才会从 VPC 路由表进入 CEN/TR。否则即使两边 TR 路由已经存在,ACK 节点本地也不会把流量送进去。
CLI 模板:
aliyun vpc CreateRouteEntry \
--RegionId <REGION_B> \
--RouteTableId <ACK_VPC_ROUTE_TABLE_ID> \
--DestinationCidrBlock <ACR_OSS_INTERNAL_CIDR> \
--NextHopType Attachment \
--NextHopId <VPC_ATTACHMENT_REGION_B> \
--RouteEntryName acr-oss-vpc \
--Description 'Route ACR OSS internal blob traffic via CEN'
这里的风险和前面的 auth IP 一样:不要为了省事把 100.64.0.0/10 整段加进去。优先使用 OSS internal 域名当前解析结果所在的精细网段;如果追求最小影响,可以先加多个 /32 做验证,但后续 DNS 漂移到同网段其它 IP 时可能再次失败。
补完后再测:
timeout 8 bash -lc "</dev/tcp/$OSS_HOST/443" \
&& echo OSS_INTERNAL_HOST_443_OK || echo OSS_INTERNAL_HOST_443_FAIL
最后用业务镜像而不是 busybox 再测一次:
kubectl -n test run acr-vpc-business-pull-test \
--image=<acr-name>-registry-vpc.<REGION_A>.cr.aliyuncs.com/prod/public:<business-tag> \
--restart=Never \
--overrides='{
"apiVersion":"v1",
"spec":{
"nodeName":"<ACK_NODE_NAME>",
"containers":[{
"name":"acr-vpc-business-pull-test",
"image":"<acr-name>-registry-vpc.<REGION_A>.cr.aliyuncs.com/prod/public:<business-tag>",
"imagePullPolicy":"Always",
"command":["/bin/sh","-c","sleep 3600"]
}]
}
}'
kubectl -n test get events \
--field-selector involvedObject.name=acr-vpc-business-pull-test \
--sort-by=.lastTimestamp
看到业务镜像 Successfully pulled image 后,才算完整验证了 registry、auth、OSS blob 下载三段链路。
八、最后再改 Jenkins 或发布系统
不要在 busybox 没测通前直接把发布系统切到 VPC 地址。推荐顺序是:
1. 小镜像 busybox 走 VPC 地址拉取成功
2. ACK 节点能连通 auth 和 OSS internal blob 地址
3. 业务镜像指定 tag 走 VPC 地址拉取成功
4. 再改 Jenkins / 发布系统里的 IMAGE_REPOSITORY
5. 发一次真实发布,观察 rollout 和 Pod 事件
仓库地址切换通常只是 registry 域名不同:
非 VPC:
<acr-name>-registry.<REGION_A>.cr.aliyuncs.com/prod/public
VPC:
<acr-name>-registry-vpc.<REGION_A>.cr.aliyuncs.com/prod/public
但鉴权域名也会跟着变成 VPC 侧:
dockerauth-ee-vpc.<REGION_A>.aliyuncs.com
而 blob 下载会访问 ACR 后端的 OSS internal 域名:
<acr-instance>-registry.oss-<REGION_A>-internal.aliyuncs.com
所以只测 registry 域名不够,必须一起测 auth 域名和 OSS internal 域名。
快速参考
节点侧最小验证:
getent hosts <acr-name>-registry-vpc.<REGION_A>.cr.aliyuncs.com
getent hosts dockerauth-ee-vpc.<REGION_A>.aliyuncs.com
getent hosts <acr-instance>-registry.oss-<REGION_A>-internal.aliyuncs.com
ip route get <ACR_AUTH_IP>
ip route get <ACR_OSS_INTERNAL_IP>
timeout 8 bash -lc '</dev/tcp/<acr-name>-registry-vpc.<REGION_A>.cr.aliyuncs.com/443' \
&& echo REGISTRY_VPC_443_OK || echo REGISTRY_VPC_443_FAIL
timeout 8 bash -lc '</dev/tcp/dockerauth-ee-vpc.<REGION_A>.aliyuncs.com/443' \
&& echo DOCKERAUTH_VPC_443_OK || echo DOCKERAUTH_VPC_443_FAIL
timeout 8 bash -lc '</dev/tcp/<acr-instance>-registry.oss-<REGION_A>-internal.aliyuncs.com/443' \
&& echo OSS_INTERNAL_443_OK || echo OSS_INTERNAL_443_FAIL
ACK Pod 事件:
kubectl -n test get pod <POD> -o wide
kubectl -n test get events --field-selector involvedObject.name=<POD> --sort-by=.lastTimestamp
CEN/TR 路由查询:
aliyun cbn ListTransitRouterRouteEntries \
--TransitRouterRouteTableId <TR_ROUTE_TABLE_ID> \
--TransitRouterRouteEntryDestinationCidrBlock <ACR_AUTH_IP>/32 \
--TransitRouterRouteEntryStatus All \
--MaxResults 100
ACK VPC 路由查询:
aliyun vpc DescribeRouteEntryList \
--RegionId <REGION_B> \
--RouteTableId <ACK_VPC_ROUTE_TABLE_ID> \
--DestinationCidrBlock <ACR_OSS_INTERNAL_CIDR> \
--MaxResult 100
新增 TR 静态路由:
aliyun cbn CreateTransitRouterRouteEntry \
--TransitRouterRouteTableId <TR_ROUTE_TABLE_ID> \
--TransitRouterRouteEntryDestinationCidrBlock <ACR_AUTH_IP>/32 \
--TransitRouterRouteEntryNextHopType Attachment \
--TransitRouterRouteEntryNextHopId <NEXT_HOP_ATTACHMENT_ID> \
--TransitRouterRouteEntryName acr-dockerauth-vpc \
--TransitRouterRouteEntryDescription 'Route ACR VPC dockerauth via CEN'
新增 ACK VPC 到 TR 的 Auth 路由:
aliyun vpc CreateRouteEntry \
--RegionId <REGION_B> \
--RouteTableId <ACK_VPC_ROUTE_TABLE_ID> \
--DestinationCidrBlock <ACR_AUTH_IP>/32 \
--NextHopType Attachment \
--NextHopId <VPC_ATTACHMENT_REGION_B> \
--RouteEntryName acr-dockerauth-vpc-to-tr \
--Description 'Route ACR VPC dockerauth traffic to TR'
新增 ACK VPC 到 TR 的 OSS internal 路由:
aliyun vpc CreateRouteEntry \
--RegionId <REGION_B> \
--RouteTableId <ACK_VPC_ROUTE_TABLE_ID> \
--DestinationCidrBlock <ACR_OSS_INTERNAL_CIDR> \
--NextHopType Attachment \
--NextHopId <VPC_ATTACHMENT_REGION_B> \
--RouteEntryName acr-oss-vpc \
--Description 'Route ACR OSS internal blob traffic via CEN'
几条经验:
ImagePullBackOff里如果出现failed to fetch oauth token,优先查dockerauth,不要只查 registry。registry-vpc:443 OK不代表 ACR VPC 拉取链路完整。dockerauth通了也不代表完整,业务镜像下载大 layer 时还可能卡在 OSS internal。100.64.0.0/10是云服务网段,跨地域访问云服务时尽量用精细 IP,例如<ACR_AUTH_IP>/32。- VPC 路由表有下一跳到 TR,不代表 TR 路由表也有下一跳。
- 发布系统切 VPC 地址前,先用小镜像和业务镜像各测一次真实拉取。

浙公网安备 33010602011771号