北京时间 10 月 13 日 23:00 到 10 月 14 日 02:00,Istio 会把 gcr.io/istio-release、registry.istio.io/release 和 istio-release.storage.googleapis.com 再关一次,12 月这几个地址就正式退役。镜像改拉 docker.io/istio 或自建拉取缓存,Helm 仓库换成 https://blob.istio.io/istio-release/charts,OCI chart 换成 oci://ghcr.io/istio/release/charts。这周把地址换完,13 日深夜那三个小时正好拿来验收。
为什么要搬
Istio 官方博客 8 月 21 日发文(作者 Steven Jin 与 Keith Mattix),原话是今年要把全部基础设施从 Google Cloud Platform 迁到 Amazon Web Services,原因是 "changes in our funding model",也就是资金模式变了。
registry.istio.io 为什么也要一起下线,7 月 23 日那篇博客交代过。这个地址原本是 Cloudflare Worker,可以把请求代理到任意 OCI 仓库,背后一直指向 gcr.io/istio-release。项目 2027 年基础设施预算有限,打算改用免费的镜像托管平台,可所有流量经 Cloudflare 汇到少数几个出口 IP,会触发这些平台的限流,于是只能放弃。
GitHub 上的跟踪 issue #61467 里有人问为什么镜像不放 GHCR,维护者回复 GHCR 有未公开的限制,按 Istio 现在的拉取量很容易超。所以镜像的正式去处是 Docker Hub。
哪些地址要换
| 用途 | 旧地址(12 月退役) | 新地址 |
|---|---|---|
| 容器镜像 | gcr.io/istio-release、registry.istio.io/release |
docker.io/istio,或指向它的拉取缓存 |
| Helm 仓库 | https://istio-release.storage.googleapis.com/charts |
https://blob.istio.io/istio-release/charts |
| OCI Helm chart | gcr.io/istio-release/charts |
ghcr.io/istio/release/charts |
| RPM、DEB、源码、SPDX、istioctl、licenses | https://istio-release.storage.googleapis.com/releases |
https://blob.istio.io/istio-release/releases |
版本边界很清楚。1.30 是最后一个往旧地址发布镜像和 chart 的小版本,1.31 起只发新地址。官方说新地址已经放了所有历史版本,所以老版本集群也可以直接切,不用先升级。10 月 6 日我核对了一遍:旧 Helm 索引里最高只到 1.30.5,gcr.io/istio-release/pilot:1.31.1 不存在;blob.istio.io 和 ghcr.io 上 1.30.x、1.31.1 都能取到,Docker Hub 上 istio/pilot:1.30.5 与 1.31.1 也都在。
最容易中招的是 1.30。7 月的博客写明,1.30 默认就用 registry.istio.io/release 作为镜像仓库,其他版本默认是 docker.io/istio。翻 istiod chart 的默认值也能看到,1.30.0 的 global.hub 是 registry.istio.io/release,1.29.0 和 1.31.1 是 docker.io/istio。如果你用 1.30 且没改过 hub,大概率要动手。
1.31 本身还有不少功能变化,这篇不展开,它的升级说明里第一条就是 GCP 下线。
四次断服测试,换成北京时间
官方把这种演练叫 scream test,测试期间会临时关闭 gcr.io/istio-release、registry.istio.io/release 和整个 https://istio-release.storage.googleapis.com/。博客、1.31 升级说明和 issue #61467 三处给的时间一致:
| 次序 | 官方时间(UTC) | 北京时间(UTC+8) | 时长 |
|---|---|---|---|
| 第一次 | 9 月 15 日 15:00 至 16:00 | 9 月 15 日 23:00 至 9 月 16 日 00:00 | 1 小时,已结束 |
| 第二次 | 10 月 13 日 15:00 至 18:00 | 10 月 13 日 23:00 至 10 月 14 日 02:00 | 3 小时 |
| 第三次 | 11 月 17 日 15:00 至 21:00 | 11 月 17 日 23:00 至 11 月 18 日 05:00 | 6 小时 |
| 第四次 | 12 月 8 日 15:00 至 12 月 9 日 15:00 | 12 月 8 日 23:00 至 12 月 9 日 23:00 | 24 小时 |
窗口一次比一次长,第四次整整一天。官方只说旧地址 2026 年 12 月退役,没有给出具体哪一天,按最后一次测试之后随时可能关来准备更稳妥。
窗口里可能出什么问题
已经在节点上跑着的 Pod 不会因为仓库断开而停掉。带版本号的镜像默认拉取策略是 IfNotPresent,节点上有缓存就不会去拉。出问题的是那些需要真正去拉镜像的时刻:节点扩容、Pod 被调度到没缓存的新节点、新建 Pod 注入 sidecar、Istio 组件滚动升级。这时 Pod 会卡在 ErrImagePull 或 ImagePullBackOff。
Helm 这边,仍指向旧仓库的 helm repo update 取不到 index.yaml,helm upgrade 或 helm pull 旧 OCI 地址也会失败。CI 里如果有脚本直接从 istio-release.storage.googleapis.com/releases 下载 istioctl 或安装包,同样会断。
13 日深夜可以这样用这个窗口:挑一个不重要、已注入 sidecar 的 Deployment 做一次 rollout restart,最好让它落到新节点上;在 CI 里手动跑一遍会拉 Istio 镜像或 chart 的流水线;本地执行一次 helm repo update。窗口内或窗口后看一下事件里有没有旧地址:
kubectl get events -A --field-selector reason=Failed | grep -E 'gcr\.io/istio-release|registry\.istio\.io'
排查清单
下面的命令都只读不写,可以直接复制。正则同时匹配两个旧镜像仓库。
正在运行的 Pod,包括 initContainers
kubectl get pods -A -o jsonpath='{range .items[*]}{.metadata.namespace}{"/"}{.metadata.name}{"\t"}{range .spec.initContainers[*]}{.image}{" "}{end}{range .spec.containers[*]}{.image}{" "}{end}{"\n"}{end}' \
| grep -E 'gcr\.io/istio-release|registry\.istio\.io'
sidecar 模式下 istio-proxy 容器和 istio-init 初始化容器都会被列出来。只查 containers 会漏掉 init 容器,上面的命令两者都覆盖了。
Deployment、DaemonSet、StatefulSet 的模板
kubectl get deploy,ds,sts -A \
-o custom-columns='KIND:.kind,NAMESPACE:.metadata.namespace,NAME:.metadata.name,IMAGES:.spec.template.spec.containers[*].image,INIT:.spec.template.spec.initContainers[*].image' \
| grep -E 'gcr\.io/istio-release|registry\.istio\.io'
有些团队在 Pod 模板上用注解 sidecar.istio.io/proxyImage 固定了 sidecar 镜像,这个也要查:
kubectl get deploy,ds,sts -A \
-o jsonpath='{range .items[*]}{.metadata.namespace}{"/"}{.metadata.name}{"\t"}{.spec.template.metadata.annotations.sidecar\.istio\.io/proxyImage}{"\n"}{end}' \
| grep -E 'gcr\.io/istio-release|registry\.istio\.io'
sidecar 注入模板和 Istio 的 ConfigMap
注入用的 hub 存在 istio-sidecar-injector(多 revision 时带后缀)这类 ConfigMap 的 values 里。下面这条把所有内容里含旧地址的 ConfigMap 都找出来,需要装 jq:
kubectl get configmap -A -o json \
| jq -r '.items[] | select((.data // {}) | tostring | test("gcr\\.io/istio-release|registry\\.istio\\.io")) | "\(.metadata.namespace)/\(.metadata.name)"'
如果集群里还有 IstioOperator 资源,顺手看一眼 hub:
kubectl get istiooperators.install.istio.io -A -o yaml | grep -nE 'hub:'
Helm release
查 Helm 装的 release 时,建议看渲染后的清单。helm get values --all 会带上 chart 内置的 _internal_defaults_do_not_set 块,1.30 的 chart 在这里写着 registry.istio.io/release,即使你已经改了 global.hub 也会被误报。
helm list -A -o json | jq -r '.[] | "\(.name) \(.namespace) \(.chart)"' \
| while read -r name ns chart; do
helm get manifest "$name" -n "$ns" | grep -qE 'gcr\.io/istio-release|registry\.istio\.io' && echo "$ns/$name ($chart)"
done
想看自己显式设置过哪些值,用不带 --all 的 helm get values <release> -n <namespace>。
本地、CI 和代码仓库
先看 Helm 客户端里还有没有旧仓库:
helm repo list -o json | jq -r '.[] | select(.url | test("istio-release\\.storage\\.googleapis\\.com")) | "\(.name) \(.url)"'
有的话用同名覆盖,原来的 istio/istiod 这类引用不用改:
helm repo add istio https://blob.istio.io/istio-release/charts --force-update
helm repo update istio
用 OCI 方式的,把地址换成 GHCR:
helm install istiod oci://ghcr.io/istio/release/charts/istiod --version 1.31.1 -n istio-system
CI 镜像、Terraform、Argo CD 或 Flux 的 values、Kustomize 补丁里也可能写死了旧地址,在代码仓库根目录搜一遍:
rg -n 'gcr\.io/istio-release|registry\.istio\.io|istio-release\.storage\.googleapis\.com'
把 hub 改过来
用 istioctl 安装的,在 IstioOperator 里改 hub,或者命令行直接指定:
apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
spec:
hub: docker.io/istio # 或你的拉取缓存地址
istioctl install -f istiooperator.yaml
# 或者
istioctl install --set hub=docker.io/istio
用 Helm 安装的,官方建议在 values 里同时设置顶层 hub 和 global.hub:
hub: docker.io/istio # 或你的拉取缓存地址
global:
hub: docker.io/istio # 或你的拉取缓存地址
升级时把 --version 写成 helm list 里看到的当前版本,免得顺手把小版本也升了:
helm upgrade istiod istio/istiod -n istio-system --version <当前版本> -f my-values.yaml
base、cni、ztunnel、gateway 等其他 chart 也按同样方式处理。sidecar 镜像是在 Pod 创建时由注入模板写进去的,改完 hub 之后已有的 Pod 不会自动换,需要把相关命名空间的工作负载重启一遍,例如 kubectl rollout restart deployment -n <namespace>,然后再跑一次前面的排查命令确认清零。
拉取缓存与 Docker Hub 限流
镜像全部回到 Docker Hub 之后,要留意限流。按 Docker 官方文档,未登录用户每个 IPv4 地址(或 IPv6 /64 网段)每 6 小时 100 次拉取,Personal 账号登录后 200 次,Pro、Team、Business 不限。多架构镜像每个架构各算一次。大集群节点往往共用 NAT 出口,一次大规模扩容就可能撞线,超限时 Docker Hub 返回 429。官方 7 月的博客也建议,能配拉取缓存最好配上。
常见的三种做法:
Harbor 代理缓存项目。 在 Harbor 里建一个指向 Docker Hub 的 registry endpoint,再建 proxy cache 项目,hub 改成 harbor.example.com/<项目名>/istio。Harbor 文档提到 2.1.1 起检查缓存更新用 HEAD 请求,不计入 Docker Hub 限流,建议用这个版本以上。
containerd 镜像源。 在 containerd 配置里把 config_path 指向 /etc/containerd/certs.d,再给 docker.io 写一个 hosts.toml,hub 保持 docker.io/istio 不变,节点拉取时先走内部镜像:
# /etc/containerd/certs.d/docker.io/hosts.toml
server = "https://registry-1.docker.io"
[host."https://docker-mirror.internal"]
capabilities = ["pull", "resolve"]
这个办法只对引用 docker.io 的镜像生效,救不了仍然写着 gcr.io/istio-release 的配置,hub 还是得先改。托管 Kubernetes 的节点配置方式因云厂商而异,以厂商文档为准。
Amazon ECR pull through cache。 ECR 支持把 Docker Hub 作为上游,但 Docker Hub 属于需要认证的上游,凭据要先存进 AWS Secrets Manager,secret 名必须以 ecr-pullthroughcache/ 开头,并与规则在同一账号和区域:
aws ecr create-pull-through-cache-rule \
--ecr-repository-prefix docker-hub \
--upstream-registry-url registry-1.docker.io \
--credential-arn arn:aws:secretsmanager:<region>:<account-id>:secret:ecr-pullthroughcache/<name> \
--region <region>
之后 hub 写成 <account-id>.dkr.ecr.<region>.amazonaws.com/docker-hub/istio。ECR 对已缓存的标签大约每 24 小时回源检查一次,上游不可达时仍返回最后一次缓存的镜像。
验签的公钥要按版本选
如果你在流水线或准入控制里用 cosign 校验 Istio 镜像签名,这次迁移还换了签名密钥。官方博客和镜像签名文档给出的对应关系是:
| Istio 版本 | 公钥 |
|---|---|
| 1.18.x 至 1.30.x | https://istio.io/misc/istio-key.pub |
| 1.31.0 | https://istio.io/misc/istio-key.pub |
| 1.31.1 及以后 | https://istio.io/misc/istio-key-v2.pub |
旧公钥会长期保留。校验命令按官方文档写法:
cosign verify --key "https://istio.io/misc/istio-key-v2.pub" docker.io/istio/pilot:1.31.1
注意一个细节:10 月 6 日中午(北京时间)我实测,https://istio.io/misc/istio-key.pub 能正常下载,istio-key-v2.pub 会跳转到 /latest/misc/istio-key-v2.pub 并返回 404。打算切到 v2 公钥的团队,先确认地址能取到再改流水线,取不到时盯一下官方页面的更新。
参考来源
- Istio 博客:ACTION REQUIRED FOR GOOGLE CONTAINER REGISTRY USERS, scream tests, and our move to AWS(2026-08-21):https://istio.io/latest/blog/2026/retirement-of-gcp/
- Istio 博客:An Update on Our Container Registry Migration(2026-07-23):https://istio.io/latest/blog/2026/retirement-of-gcr.io-follow-up/
- GitHub issue #61467:https://github.com/istio/istio/issues/61467
- Istio 1.31 升级说明:https://istio.io/latest/news/releases/1.31.x/announcing-1.31/upgrade-notes/
- Istio 镜像签名与校验文档:https://istio.io/latest/docs/ops/best-practices/image-signing-validation/
- Istio Helm 安装文档:https://istio.io/latest/docs/setup/install/helm/
- Docker Hub 拉取限额:https://docs.docker.com/docker-hub/usage/pulls/
- Harbor 代理缓存:https://goharbor.io/docs/main/administration/configure-proxy-cache/
- containerd hosts.toml 配置:https://github.com/containerd/containerd/blob/main/docs/hosts.md
- Amazon ECR pull through cache:https://docs.aws.amazon.com/AmazonECR/latest/userguide/pull-through-cache.html
- InfoQ 旁证报道(2026-10-03):https://www.infoq.com/news/2026/10/istio-1-31-agentgateway/
一起交流
分享你的思考,让讨论更进一步。