从 Artifact Registry 同步 OCI 工件

本页面介绍了如何使用 craneoras 创建映像并将其发布到 Artifact Registry 中的仓库。

您可以使用 Artifact Registry 将 Config Sync 配置为从 OCI 映像同步。如需使用此功能,您必须启用 RootSync API 和 RepoSync API

关于 Artifact Registry

Artifact Registry 是一项全托管式服务,同时支持容器映像和非容器制品。我们建议您使用 Artifact Registry 来存储和管理 Google Cloud上的容器映像。您可以通过多种工具将制品推送到 Artifact Registry。例如,您可以推送 Docker 映像,或使用 go-containerregistry 库来处理容器注册表。请选择最适合您的工具。

准备工作

  1. Sign in to your Google Cloud account. If you're new to Google Cloud, create an account to evaluate how our products perform in real-world scenarios. New customers also get $300 in free credits to run, test, and deploy workloads.
  2. Install the Google Cloud CLI.

  3. 如果您使用的是外部身份提供方 (IdP),则必须先使用联合身份登录 gcloud CLI

  4. 如需初始化 gcloud CLI,请运行以下命令:

    gcloud init
  5. Create or select a Google Cloud project.

    Roles required to select or create a project

    • Select a project: Selecting a project doesn't require a specific IAM role—you can select any project that you've been granted a role on.
    • Create a project: To create a project, you need the Project Creator (roles/resourcemanager.projectCreator), which contains the resourcemanager.projects.create permission. Learn how to grant roles.
    • Create a Google Cloud project:

      gcloud projects create PROJECT_ID

      Replace PROJECT_ID with a name for the Google Cloud project you are creating.

    • Select the Google Cloud project that you created:

      gcloud config set project PROJECT_ID

      Replace PROJECT_ID with your Google Cloud project name.

  6. Verify that billing is enabled for your Google Cloud project.

  7. Enable the GKE, Config Sync, Artifact Registry APIs:

    Roles required to enable APIs

    To enable APIs, you need the Service Usage Admin IAM role (roles/serviceusage.serviceUsageAdmin), which contains the serviceusage.services.enable permission. Learn how to grant roles.

    gcloud services enable container.googleapis.com  anthosconfigmanagement.googleapis.com  artifactregistry.googleapis.com
  8. Install the Google Cloud CLI.

  9. 如果您使用的是外部身份提供方 (IdP),则必须先使用联合身份登录 gcloud CLI

  10. 如需初始化 gcloud CLI,请运行以下命令:

    gcloud init
  11. Create or select a Google Cloud project.

    Roles required to select or create a project

    • Select a project: Selecting a project doesn't require a specific IAM role—you can select any project that you've been granted a role on.
    • Create a project: To create a project, you need the Project Creator (roles/resourcemanager.projectCreator), which contains the resourcemanager.projects.create permission. Learn how to grant roles.
    • Create a Google Cloud project:

      gcloud projects create PROJECT_ID

      Replace PROJECT_ID with a name for the Google Cloud project you are creating.

    • Select the Google Cloud project that you created:

      gcloud config set project PROJECT_ID

      Replace PROJECT_ID with your Google Cloud project name.

  12. Verify that billing is enabled for your Google Cloud project.

  13. Enable the GKE, Config Sync, Artifact Registry APIs:

    Roles required to enable APIs

    To enable APIs, you need the Service Usage Admin IAM role (roles/serviceusage.serviceUsageAdmin), which contains the serviceusage.services.enable permission. Learn how to grant roles.

    gcloud services enable container.googleapis.com  anthosconfigmanagement.googleapis.com  artifactregistry.googleapis.com
  14. 创建或有权访问满足 Config Sync 要求且使用最新版本的 Config Sync 的集群。
  15. 安装 nomos CLI 或将其升级到最新版本。
  16. (可选)如果您要使用 Cosign 验证 OCI 映像签名,请安装以下各项:
    • Cosign,用于为 OCI 映像签名。
    • OpenSSL,用于为网络钩子服务器生成凭证。
    • Docker,用于构建和推送准入 Webhook 服务器映像。

    费用

    在本文档中,您将使用 Google Cloud的以下收费组件:

    如需根据您的预计使用量来估算费用,请使用价格计算器

    新 Google Cloud 用户可能有资格申请免费试用

    创建 Artifact Registry 仓库

    在本部分中,您将创建一个 Artifact Registry 代码库。如需详细了解如何创建 Artifact Registry 代码库,请参阅创建代码库

    1. 创建 Artifact Registry 代码库:

      gcloud artifacts repositories create AR_REPO_NAME \
         --repository-format=docker \
         --location=AR_REGION \
         --description="Config Sync repo" \
         --project=PROJECT_ID
      

    请替换以下内容:

    • PROJECT_ID:组织的项目 ID。
    • AR_REPO_NAME:制品库的 ID。
    • AR_REGION:制品库的单区域级或多区域级位置。

    以下部分中使用的变量:

    • FLEET_HOST_PROJECT_ID:如果您使用的是 GKE Workload Identity Federation for GKE,则此 ID 与 PROJECT_ID 相同。如果您使用的是舰队 Workload Identity Federation for GKE,则这是集群注册到的舰队的项目 ID。
    • GSA_NAME:您要用于连接到 Artifact Registry 的自定义 Google 服务账号的名称。
    • KSA_NAME:协调器的 Kubernetes 服务账号。
      • 对于根代码库,如果 RootSync 名称为 root-sync,请添加 root-reconciler。否则,请添加 root-reconciler-ROOT_SYNC_NAME
      • 对于命名空间代码库,如果 RepoSync 名称为 repo-sync,请添加 ns-reconciler-NAMESPACE。否则,请添加 ns-reconciler-NAMESPACE-REPO_SYNC_NAME-REPO_SYNC_NAME_LENGTH,其中 REPO_SYNC_NAME_LENGTHREPO_SYNC_NAME 中的字符数。

    授予读取者权限

    完成以下步骤,使用 Kubernetes 服务账号向 Artifact Registry 进行身份验证:

    向使用 Workload Identity Federation for GKE 池的 Kubernetes 服务账号授予 Artifact Registry Reader (roles/artifactregistry.reader) IAM 角色:

    gcloud artifacts repositories add-iam-policy-binding AR_REPO_NAME \
       --location=AR_REGION \
       --member="serviceAccount:FLEET_HOST_PROJECT_ID.svc.id.goog[config-management-system/KSA_NAME]" \
       --role=roles/artifactregistry.reader \
       --project=PROJECT_ID
    

    将映像推送到 Artifact Registry 代码库

    在本部分中,您将创建一个 OCI 映像并将其推送到 Artifact Registry。

    1. 创建 Namespace 清单文件:

      cat <<EOF> test-namespace.yaml
      apiVersion: v1
      kind: Namespace
      metadata:
        name: test
      EOF
      
    2. 登录 Artifact Registry:

      gcloud auth configure-docker AR_REGION-docker.pkg.dev
      
    3. 打包映像并将其推送到 Artifact Registry:

      crane

      本部分中的命令使用 crane 与远程映像和注册表进行交互。

      1. 封装文件:

        tar -cf test-namespace.tar test-namespace.yaml
        
      2. 安装 crane 工具。

      3. 将该映像推送到 Artifact Registry。

        crane append -f test-namespace.tar -t AR_REGION-docker.pkg.dev/PROJECT_ID/AR_REPO_NAME/test-namespace:v1
        

      oras

      本部分中的命令使用 oras 与远程映像和注册表进行交互。

      1. 封装文件:

        tar -czf test-namespace.tar.gz test-namespace.yaml
        
      2. 安装 oras 工具。

      3. 将该映像推送到 Artifact Registry。

        oras push AR_REGION-docker.pkg.dev/PROJECT_ID/AR_REPO_NAME/test-namespace:v1 test-namespace.tar.gz
        

    将 Config Sync 配置为从映像同步

    在本部分中,您将创建一个 RootSync 对象,并将 Config Sync 配置为从 OCI 映像同步。

    1. 创建一个具有唯一名称的 RootSync 对象:

      cat <<EOF>> ROOT_SYNC_NAME.yaml
      apiVersion: configsync.gke.io/v1beta1
      kind: RootSync
      metadata:
        name: ROOT_SYNC_NAME
        namespace: config-management-system
      spec:
        sourceFormat: unstructured
        sourceType: oci
        oci:
          image: AR_REGION-docker.pkg.dev/PROJECT_ID/AR_REPO_NAME/test-namespace:v1
          dir: .
          auth: k8sserviceaccount
      EOF
      

      ROOT_SYNC_NAME 替换为您的 RootSync 名称。 该名称在集群中必须是唯一的,并且不能超过 26 个字符。 如需查看配置 RootSync 对象时的完整选项列表,请参阅 RootSyncRepoSync 字段

    2. 应用 RootSync 对象:

      kubectl apply -f ROOT_SYNC_NAME.yaml
      
    3. 验证 Config Sync 是否正在从映像同步:

      nomos status --contexts=$(kubectl config current-context)
      

      您应该会看到类似于以下示例的输出:

      Connecting to clusters...
      
      *publish-config-registry
         --------------------
         <root>:root-sync-test   AR_REGION-docker.pkg.dev/PROJECT_ID/AR_REPO_NAME/test-namespace:v1   
         SYNCED                  05e6a6b77de7a62286387cfea833d45290105fe84383224938d7b3ab151a55a1
         Managed resources:
            NAMESPACE   NAME             STATUS    SOURCEHASH
                        namespace/test   Current   05e6a6b
      

      您现在已成功将映像同步到您的集群。

    (可选)验证 OCI 来源签名

    从 Config Sync 1.20.0 版开始,Config Sync 支持在将配置应用于集群之前验证 OCI 来源映像的真实性。此方法使用 ValidatingWebhookConfiguration 对象和验证 webhook 服务器来拦截针对 RootSyncRepoSync 对象的更新请求。Config Sync 在成功提取新的图片摘要后,会更新 RootSyncRepoSync 对象的 configsync.gke.io/image-to-sync 注解。验证 webhook 服务器会比较旧注解和新注解之间的值,并在检测到更改时使用 Cosign 等验证工具运行验证。

    设置签名验证服务器

    为了确保 OCI 来源的真实性,您需要使用 HTTP 服务器来验证签名。您可以使用 Config Sync 示例仓库中的示例,也可以使用自己的 Docker 映像。

    1. 如果您要使用提供的示例,请完成以下步骤:

      1. 克隆示例代码库:

        git clone https://github.com/GoogleCloudPlatform/anthos-config-management-samples/
        
      2. 切换到包含签名验证服务器示例的目录:

        cd anthos-config-management-samples/tree/main/pre-sync/oci-image-verification
        
    2. 如需为签名验证服务器创建 Docker 映像并将其推送到映像注册表,请运行以下命令:

      docker build -t SIGNATURE_VERIFICATION_SERVER_IMAGE_URL:latest . && docker push SIGNATURE_VERIFICATION_SERVER_IMAGE_URL:latest
      

      SIGNATURE_VERIFICATION_SERVER_IMAGE_URL 替换为签名验证服务器映像的网址。

    向服务进行身份验证

    如需设置签名验证服务器,您必须向 Artifact Registry、Cosign 客户端和网络钩子服务器进行身份验证。

    1. 创建命名空间:

      kubectl create ns signature-verification
      
    2. 如需使用 Kubernetes ServiceAccount 向 Artifact Registry 进行身份验证,请完成以下步骤:

      1. 在您创建的命名空间中创建 Kubernetes 服务账号:

        kubectl create sa signature-verification-sa -n signature-verification
        
      2. 为 Artifact Registry Reader 角色 (roles/artifactregistry.reader) 添加 IAM 政策绑定:

        gcloud artifacts repositories add-iam-policy-binding REPOSITORY_NAME \
           --location=REPOSITORY_LOCATION \
           --member="serviceAccount:PROJECT_ID.svc.id.goog[signature-verification/signature-verification-sa]" \
           --role=roles/artifactregistry.reader \
           --project=PROJECT_ID
        

        替换以下内容:

        • REPOSITORY_NAME:用于存储 OCI 映像的 Artifact Registry 仓库的名称。
        • REPOSITORY_LOCATION:Artifact Registry 仓库的位置。
    3. 如需向 Cosign 客户端进行身份验证,请完成以下步骤:

      1. 生成一对 Cosign 密钥。此命令会生成一个公钥和一个私钥:

        cosign generate-key-pair
        
      2. 将公钥存储在您创建的命名空间的 Kubernetes Secret 中:

        kubectl create secret generic cosign-key --from-file=cosign.pub -n signature-verification
        
    4. 如需对签名验证服务器进行身份验证,请完成以下步骤:

      1. 如需加密签名验证服务器内的通信,请使用 OpenSSL 生成 TLS 证书和私钥:

        openssl req -nodes -x509 -sha256 -newkey rsa:4096 \
        -keyout tls.key \
        -out tls.crt \
        -days 356 \
        -subj "/CN=signature-verification-service.signature-verification.svc"  \
        -addext "subjectAltName = DNS:signature-verification-service,DNS:signature-verification-service.signature-verification.svc,DNS:signature-verification-service.signature-verification"
        
      2. 将您生成的凭证存储在 Kubernetes Secret 中:

        kubectl create secret tls webhook-tls --cert=tls.crt --key=tls.key -n signature-verification
        
      3. 获取 tls.cert 的 base64 编码内容。这是在下一部分中创建的验证网络钩子配置所必需的:

        cat tls.crt | base64 -w 0.
        

    部署准入网络钩子

    您可以使用以下示例为签名验证服务器和验证 webhook 配置创建部署。

    1. 通过保存以下文件为签名验证服务器创建部署:

      apiVersion: apps/v1
      kind: Deployment
      metadata:
        name: signature-verification-server
      spec:
        replicas: 1
        selector:
          matchLabels:
            app: signature-verification-server
        template:
          metadata:
            labels:
              app: signature-verification-server
          spec:
            serviceAccountName: signature-verification-sa
            containers:
            - name: signature-verification-server
              command:
              - /signature-verification-server
              image: SIGNATURE_VERIFICATION_SERVER_IMAGE_URL
              imagePullPolicy: Always
              ports:
              - containerPort: 10250
              volumeMounts:
              - name: tls-certs
                mountPath: "/tls"
              - name: cosign-key
                mountPath: "/cosign-key"
            volumes:
            - name: cosign-key
              secret:
                secretName: cosign-key
            - name: tls-certs
              secret:
                secretName: webhook-tls
      ---
      apiVersion: v1
      kind: Service
      metadata:
        name: signature-verification-service
      spec:
        ports:
        - port: 10250
          targetPort: 10250
        selector:
          app: signature-verification-server

      SIGNATURE_VERIFICATION_SERVER_IMAGE_URL 替换为签名验证服务器映像的完整网址。

    2. 将部署应用于集群:

      kubectl apply -f signature-verification-deployment.yaml -n signature-verification
      
    3. 通过保存以下文件创建验证 webhook 配置:

      apiVersion: admissionregistration.k8s.io/v1
      kind: ValidatingWebhookConfiguration
      metadata:
        name: image-verification-webhook
      webhooks:
      - name: imageverification.webhook.com
        clientConfig:
          service:
            name: signature-verification-service
            namespace: signature-verification
            path: "/validate"
            port: 10250
          caBundle: CA_BUNDLE
        rules:
        - apiGroups:
          - configsync.gke.io
          apiVersions:
          - v1beta1
          - v1alpha1
          operations:
          - UPDATE
          resources:
          - 'rootsyncs'
          - 'reposyncs'
          scope: '*'
        admissionReviewVersions: ["v1", "v1beta1"]
        sideEffects: None

      CA_BUNDLE 替换为 tls.cert 中的 base64 编码内容。

    4. 将验证 webhook 配置应用于集群:

      kubectl apply -f signature-verification-validatingwebhookconfiguration.yaml
      

    检查日志中是否存在映像验证错误

    设置映像验证服务器后,任何尝试从未签名的 OCI 映像进行同步的操作都应该会失败。

    如需检查签名验证错误,请运行以下命令,查看签名验证服务器的日志:

    1. 检查 kubectl 日志:

      kubectl logs deployment  signature-verification-server -n  signature-verification
      

      与签名验证相关的 kubectl 错误类似于以下内容:

      main.go:69: error during command execution: no signatures found
      
    2. 检查 Config Sync 日志:

      nomos status
      

      与签名验证相关的 Config Sync 错误类似于以下内容:

      Error:   KNV2002: admission webhook "imageverification.webhook.com" denied the request: Image validation failed: cosign verification failed: exit status 10, output: Error: no signatures found
      

    如果您未收到任何错误,则可以通过检查 RootSyncRepoSync 配置来确认已签名的映像是否是正在同步的对象:

    RootSync

     kubectl get rootsync ROOTSYNC_NAME -n config-management-system -oyaml
    

    ROOTSYNC_NAME 替换为 RootSync 的名称。

    RepoSync

     kubectl get reposync REPOSYNC_NAME -n REPOSYNC_NAMESPACE -oyaml
    

    替换以下内容:

    • REPOSYNC_NAMERepoSync 的名称。
    • REPOSYNC_NAMESPACE:与 RepoSync 关联的命名空间的名称。

    您应该会看到注解 configsync.gke.io/image-to-sync 已添加到 RootSyncRepoSync 对象。该注解包含来源 OCI 映像的网址和 Config Sync 提取的最新摘要。

    后续步骤