使用 Skopeo Copy 提升 Artifact
功能概述
Artifact 提升可将已构建的 artifact 从一个受信任的位置移动到另一个位置,例如从开发镜像仓库移动到暂存或生产仓库。对于容器镜像,请使用 skopeo-copy Task 来复制镜像,而无需重新构建。
当提升需要人工审核时,请在 skopeo-copy 之前添加一个手动批准步骤。批准步骤会暂停 PipelineRun,直到所需批准人完成批准;只有在批准成功后,复制步骤才会开始。
使用场景
- 将镜像从开发、测试或暂存仓库提升到生产环境。
- 在一次可审计的提升运行中提升多个相关镜像。
- 要求发布经理或发布组批准生产提升。
- 将构建流水线与提升流水线分离,使生产 artifact 复制自不可变的构建输出,而不是重新构建。
前提条件
- 已安装
Tekton Pipelines。
skopeo-copy Task 已从已配置的 Hub catalog 中可用。
- 已部署
Manual Approval Gate,用于本指南中展示的批准工作流。
- 源和目标 registry 凭证已准备为 Kubernetes
Secret 对象,并位于 PipelineRun 运行所在的 namespace 中。
- 流水线作者可以创建或更新
Pipeline 资源,运行用户可以在目标 namespace 中创建 PipelineRun 资源。
- 你了解基本的
Pipeline、PipelineRun、Task 和 Workspace 概念。
提升流程
典型的镜像提升流水线包含两个阶段:
wait-for-approval:要求指定批准人批准提升。
promote-images:使用 skopeo-copy 复制一个或多个镜像。
将批准策略保留在 Pipeline 定义中。不要将 approvers、numberOfApprovalsRequired 或批准规则等批准策略参数作为 PipelineRun 参数暴露出来。如果这些值在运行时可被暴露,流水线执行者就可能覆盖默认批准规则,从而绕过预期的发布控制。
PipelineRun 只应提供每次运行时合法会变化的值,例如源镜像和目标镜像映射。
步骤
1. 准备 registry 凭证
为源 registry 创建一个 secret,为目标 registry 创建另一个 secret。以下示例使用 kubernetes.io/dockerconfigjson secrets:
kubectl create secret docker-registry src-registry-config \
-n <namespace> \
--docker-server=dev-registry.example.com \
--docker-username=<source-username> \
--docker-password=<source-password>
kubectl create secret docker-registry dst-registry-config \
-n <namespace> \
--docker-server=prod-registry.example.com \
--docker-username=<destination-username> \
--docker-password=<destination-password>
如果同一组凭证可访问两个 registry,则可以将同一个 secret 绑定到两个 workspace。
2. 创建提升流水线
以下流水线在 Pipeline 中固定批准策略,并且仅将 imageMappings、srcTLSVerify 和 dstTLSVerify 作为运行时输入暴露。请将 release-manager 和 group:release-approvers 替换为你的 Identity Provider 中的规范用户和组标识符。
apiVersion: tekton.dev/v1
kind: Pipeline
metadata:
name: promote-artifacts-with-approval
spec:
params:
- name: imageMappings
type: array
description: Source-to-destination image mappings for this promotion run.
- name: srcTLSVerify
type: string
default: "true"
description: Enable TLS verification for the source registry.
- name: dstTLSVerify
type: string
default: "true"
description: Enable TLS verification for the destination registry.
workspaces:
- name: src-registry-config
- name: dst-registry-config
tasks:
- name: wait-for-approval
taskRef:
apiVersion: openshift-pipelines.org/v1alpha1
kind: ApprovalTask
timeout: "24h"
params:
- name: approvers
value:
- release-manager
- group:release-approvers
- name: numberOfApprovalsRequired
value: "1"
- name: description
value: "Approve artifact promotion to the production registry."
- name: promote-images
runAfter:
- wait-for-approval
taskRef:
resolver: hub
params:
- name: type
value: artifact
- name: catalog
value: catalog
- name: kind
value: task
- name: name
value: skopeo-copy
- name: version
value: "0.1"
params:
- name: imageMappings
value:
- $(params.imageMappings[*])
- name: srcTLSVerify
value: $(params.srcTLSVerify)
- name: dstTLSVerify
value: $(params.dstTLSVerify)
workspaces:
- name: src-registry-config
workspace: src-registry-config
- name: dst-registry-config
workspace: dst-registry-config
imageMappings 参数接受每个数组项一个 SRC DST 映射。每个镜像引用都必须包含 skopeo transport 前缀,例如 docker://。当 imageMappings 不为空时,skopeo-copy 会使用它进行批量提升,并忽略 srcImage 和 dstImages。
3. 启动提升运行
创建一个 PipelineRun,并提供需要提升的镜像。对于多个镜像,请将每个源到目标的配对放入 imageMappings 中:
apiVersion: tekton.dev/v1
kind: PipelineRun
metadata:
name: promote-artifacts-prod-run
spec:
pipelineRef:
name: promote-artifacts-with-approval
timeouts:
pipeline: 72h
tasks: 72h
params:
- name: imageMappings
value:
- docker://dev-registry.example.com/team/app-api:1.2.3 docker://prod-registry.example.com/team/app-api:1.2.3
- docker://dev-registry.example.com/team/app-worker:1.2.3 docker://prod-registry.example.com/team/app-worker:1.2.3
- name: srcTLSVerify
value: "true"
- name: dstTLSVerify
value: "true"
workspaces:
- name: src-registry-config
secret:
secretName: src-registry-config
- name: dst-registry-config
secret:
secretName: dst-registry-config
将 timeouts.pipeline 和 timeouts.tasks 设置得足够长,以覆盖预期的批准窗口。批准任务的超时时间应短于 PipelineRun 的超时时间。在此示例中,批准任务最长可等待 24h,而整个 PipelineRun 最长可运行 72h。
另一种方式:将一个镜像提升到多个目标
如果你要将一个源镜像提升到一个或多个目标标签,也可以使用 srcImage 和 dstImages,而不是 imageMappings:
tasks:
- name: promote-image
taskRef:
resolver: hub
params:
- name: type
value: artifact
- name: catalog
value: catalog
- name: kind
value: task
- name: name
value: skopeo-copy
- name: version
value: "0.1"
params:
- name: srcTransport
value: registry
- name: srcImage
value: dev-registry.example.com/team/app-api:1.2.3
- name: dstTransport
value: registry
- name: dstImages
value:
- prod-registry.example.com/team/app-api:1.2.3
- prod-registry.example.com/team/app-api:stable
仅当一个源镜像需要一个或多个目标标签时,才使用这种形式。当一次提升运行包含多个源镜像时,请使用 imageMappings。
运行结果
PipelineRun 会在 wait-for-approval 处停止,直到所需批准人或组完成批准。
- 如果批准被拒绝,
PipelineRun 会失败,提升复制不会开始。
- 如果批准成功,
skopeo-copy 会将每个映射复制到目标 registry。
skopeo-copy 会为成功的 registry 目标输出基于 digest 的结果,包括 IMAGES、dst-IMAGE_URL、dst-IMAGE_DIGEST、dst-image-urls 和 dst-image-tag。
使用以下命令检查运行状态:
kubectl get pipelinerun promote-artifacts-prod-run -n <namespace>
kubectl get approvaltask promote-artifacts-prod-run-wait-for-approval \
-n <namespace> \
-o jsonpath='{.status.state}{"\n"}'
PROMOTE_TASKRUN="$(kubectl get taskrun \
-n <namespace> \
-l tekton.dev/pipelineRun=promote-artifacts-prod-run,tekton.dev/pipelineTask=promote-images \
-o jsonpath='{.items[0].metadata.name}')"
kubectl get taskrun "${PROMOTE_TASKRUN}" \
-n <namespace> \
-o jsonpath='{range .status.results[*]}{.name}: {.value}{"\n"}{end}'
PROMOTE_POD="$(kubectl get taskrun "${PROMOTE_TASKRUN}" \
-n <namespace> \
-o jsonpath='{.status.podName}')"
kubectl logs "${PROMOTE_POD}" -n <namespace> -c step-copy-images
如需查看批准审计详情,请检查生成的 ApprovalTask 上的 status.approversResponse。
故障排查
- 提升在未经过预期 gate 的情况下开始: 确认
skopeo-copy task 设置了 runAfter: [wait-for-approval],或者以其他方式依赖批准任务。
- 运行用户可以更改批准人: 从
PipelineRun 参数中移除批准策略值,并将其保留在受保护的 Pipeline 定义中。
- 批准任务始终不出现: 确认已安装并就绪
Manual Approval Gate,然后检查 CustomRun 和 ApprovalTask 资源。
- registry 身份验证失败: 验证源和目标 secret 是否包含
imageMappings 中所用 registry 的凭证。
- 内部 registry 的 TLS 验证失败: 优先挂载正确的 CA bundle。仅当受信任的内部 registry 有意使用不安全访问或自签名证书时,才将
srcTLSVerify 或 dstTLSVerify 设为 "false"。
- 只有部分映射被复制: 检查
promote-images TaskRun 日志。每个 imageMappings 项都必须恰好包含两个引用:SRC DST。
了解更多