完成迁移

迁移的第 6 阶段。Mesh v1 已经移除,网格运行在 Mesh v2 上。还剩下三件事:采用 default 修订版本标签,接管由 Mesh v1 负责续订的证书颁发机构,以及迁移可观测性堆栈。

采用默认修订版本标签

Mesh v1 存在期间,default 注入 webhook 归它所有,Mesh v2 无法声明该 webhook。现在,名为 default 的 IstioRevisionTag 允许命名空间使用 istio-injection=enabled,而不是特定于修订版本的标签,并确保该标签在未来的 Mesh v2 更新中持续有效。

cat <<EOF | kubectl apply -f -
apiVersion: sailoperator.io/v1
kind: IstioRevisionTag
metadata:
  name: default
spec:
  targetRef:
    kind: Istio
    name: default
EOF
kubectl get istiorevisiontags

如果资源报告 Helm 所有权错误,则 Mesh v1 遗留下来的 istio-reader-service-account 服务账户仍缺少 Helm 元数据,请参阅安装 Mesh v2 控制平面。

命名空间会继续使用已有的修订版本标签。要将命名空间改为使用该标签,请执行:

kubectl label ns "${MESH_NAMESPACE}" istio-injection=enabled istio.io/rev- --overwrite
NOTE

这会更改命名空间所跟随的控制平面,但不会更改其 Pod 是否注入。使用从 Mesh v1 继承的注入策略(autoInject: disabled)时,只有携带 sidecar.istio.io/inject: "true" 的 Pod 才会被注入。请参阅使用 IstioRevisionTag 进行 Sidecar 注入。

交接证书颁发机构

网格会保留一直使用的根证书颁发机构。发生变化的是 cacerts Secret 中的中间证书:Mesh v1 使用较短的有效期签发该证书并自动续订,而执行此操作的组件已经移除。将其替换为由同一根证书签发的长期证书,使每个工作负载证书保持有效,并且无需重启任何代理。

导出根证书颁发机构

umask 077
export CA_DIR=${CA_DIR:-$(mktemp -d "${HOME}/ca-handover-XXXXXX")}
mkdir -p "${CA_DIR}"
chmod 700 "${CA_DIR}"
kubectl --context "${GLOBAL_CONTEXT}" -n cpaas-system get secret asm-istio-rootca \
  -o jsonpath='{.data.tls\.crt}' | base64 -d > "${CA_DIR}/root-cert.pem"
kubectl --context "${GLOBAL_CONTEXT}" -n cpaas-system get secret asm-istio-rootca \
  -o jsonpath='{.data.tls\.key}' | base64 -d > "${CA_DIR}/root-key.pem"
openssl x509 -in "${CA_DIR}/root-cert.pem" -noout -subject -enddate

如果 global 集群中已不存在该 Secret,请从 ${BACKUP_DIR}/global-asm-istio-rootca.yaml 中获取这两个文件,其中保存着相同的两个密钥。

签发新的中间证书

export CA_DAYS=${CA_DAYS:-3650}
openssl genrsa -out "${CA_DIR}/ca-key.pem" 4096
openssl req -new -key "${CA_DIR}/ca-key.pem" -subj "/O=Istio/CN=Intermediate CA/L=${CLUSTER_NAME}" \
  -out "${CA_DIR}/ca.csr"
cat > "${CA_DIR}/ca-ext.cnf" <<EOF
[ v3_ca ]
basicConstraints = critical, CA:TRUE, pathlen:0
keyUsage = critical, digitalSignature, keyEncipherment, keyCertSign
subjectKeyIdentifier = hash
EOF
openssl x509 -req -in "${CA_DIR}/ca.csr" -CA "${CA_DIR}/root-cert.pem" -CAkey "${CA_DIR}/root-key.pem" \
  -CAcreateserial -days "${CA_DAYS}" -extensions v3_ca -extfile "${CA_DIR}/ca-ext.cnf" -out "${CA_DIR}/ca-cert.pem"
cat "${CA_DIR}/ca-cert.pem" "${CA_DIR}/root-cert.pem" > "${CA_DIR}/cert-chain.pem"
openssl x509 -in "${CA_DIR}/ca-cert.pem" -noout -subject -issuer -enddate

CA_DAYS 是中间证书的有效期(以天为单位);除非在运行此代码块之前设置该值,否则默认为 3650 天。请根据证书策略选择该值,将其保持在上一步打印的根证书有效期之内,并在证书过期前规划轮换。跨越多个集群的网格会为每个集群使用一个中间证书,所有证书均由同一个根证书签发。

替换 cacerts Secret

kubectl -n istio-system create secret generic cacerts \
  --from-file="${CA_DIR}/ca-cert.pem" --from-file="${CA_DIR}/ca-key.pem" \
  --from-file="${CA_DIR}/root-cert.pem" --from-file="${CA_DIR}/cert-chain.pem" \
  --dry-run=client -o yaml | kubectl replace -f -
替换 Secret,不要删除并重新创建

istiod 会监视此 Secret。如果先将其删除,控制平面会在短时间内处于未配置证书颁发机构的状态,并可能使用自签名证书颁发工作负载证书,而其他代理都不信任该自签名证书。上述命令会通过一次 API 调用交换内容。

从工作站中移除私钥

先将根密钥复制到存放私钥的位置——中间证书轮换时还需要使用它——然后删除工作目录。该目录中保存着根证书和新中间证书的私钥,而现在这两个私钥都已位于集群中。

shred -u "${CA_DIR}"/*key.pem 2>/dev/null || rm -f "${CA_DIR}"/*key.pem
rm -rf "${CA_DIR}"

验证交接

until kubectl -n istio-system logs "deploy/istiod-${V2_REVISION}" --since=10m \
  | grep -q "newly added intermediate CA"; do sleep 10; done
kubectl -n istio-system logs "deploy/istiod-${V2_REVISION}" --since=10m | grep -A2 "newly added intermediate CA"
kubectl -n "${MESH_NAMESPACE}" get pod -o jsonpath='{range .items[*]}{.metadata.name} {.status.startTime}{"\n"}{end}'
  • istiod 日志会报告新的中间证书并打印其主题。该 Secret 以文件形式挂载,因此替换 Secret 后最多需要等待一分钟;在验证其他内容之前,请先等待此日志出现。
  • 没有 Pod 被重启:启动时间保持不变。
  • 现有工作负载证书会继续工作。它们会在正常的 24 小时有效期内使用新的中间证书重新签发。

重启一个工作负载即可立即查看新的证书链:

kubectl -n "${MESH_NAMESPACE}" rollout restart "deploy/${WORKLOAD}"
kubectl -n "${MESH_NAMESPACE}" rollout status "deploy/${WORKLOAD}" --timeout=300s
POD=$(kubectl -n "${MESH_NAMESPACE}" get pod -l "app=${WORKLOAD}" -o jsonpath='{.items[0].metadata.name}')
istioctl proxy-config secret "${POD}" -n "${MESH_NAMESPACE}" -o json \
  | jq -r '.dynamicActiveSecrets[] | select(.name=="default") | .secret.tlsCertificate.certificateChain.inlineBytes' \
  | base64 -d | openssl x509 -noout -issuer

签发者是新的中间证书,而对仍持有旧中间证书签发的证书的工作负载的调用会继续正常工作,因为两者都由同一个根证书签发。

迁移可观测性堆栈

自移除 Mesh v1 后,Tracing 一直处于中断状态。请按照迁移可观测性堆栈安装 OpenTelemetry v2 和 Jaeger v2,保留现有追踪数据以供查询,并将 mesh 和 Kiali 重新指向新的管道。

恢复修订版本删除宽限期

阶段 2将 inactiveRevisionDeletionGracePeriodSeconds 延长至 30 天,以确保迁移期间不会删除修订版本。mesh 稳定运行一到两周后,将其恢复为默认值:

kubectl patch istio default --type=json \
  -p='[{"op":"remove","path":"/spec/updateStrategy/inactiveRevisionDeletionGracePeriodSeconds"}]'

将其保留为 30 天意味着未来每次控制平面更新都会让之前的 istiod 继续运行一个月。更改此字段不会重启任何内容。

最终验收

kubectl get istio,istiocni,istiorevision,istiorevisiontag
kubectl get pod -A -o json | jq -r '[.items[]
  | select(.metadata.annotations["sidecar.istio.io/status"] != null)
  | .metadata.annotations["sidecar.istio.io/status"] | fromjson | .revision] | unique'
kubectl get crd -o name | sed 's|.*/||' | grep -E '\.asm\.alauda\.io$' | while read -r crd; do
  printf '%s: ' "${crd}"; kubectl get "${crd}" -A --no-headers 2>/dev/null | wc -l
done
  • 每个 Mesh v2 资源都报告 Healthy。
  • 每个注入的 Pod 都运行 Mesh v2 修订版本。
  • 不再有任何 Mesh v1 资源。
  • Kiali 显示完整的流量图,并且——在迁移可观测性堆栈后——可以在 Jaeger v2 中查询追踪数据。
  • 自阶段 5以来,探针报告没有任何故障。

停止探针,归档包含证书材料的备份,并在轮换计划中记录新的中间证书。