在 Kubernetes 清单中使用容器映像摘要

Last reviewed 2021-01-08 UTC

本教程介绍了如何使用将容器部署到 Kubernetes 的开发者和运营商使用容器映像摘要来识别容器映像。容器映像摘要是唯一且不可改变地标识容器映像。

与使用映像标记相比,使用映像摘要部署容器映像有诸多好处。如需详细了解映像摘要,请参阅使用容器映像摘要的随附文档,然后再继续本教程。

Kubernetes pod 规范中的容器的 image 参数接受包含摘要的映像。此参数适用于所有使用 pod 规范的位置,例如 Deployment、StatefulSet、DaemonSet、ReplicaSet 和 Job 资源的 template 部分。

如需使用摘要部署映像,请使用映像名称,后跟 @sha256: 和摘要值。以下是使用包含摘要的映像的 Deployment 资源示例:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: echo-deployment
spec:
  selector:
    matchLabels:
      app: echo
  template:
    metadata:
      labels:
        app: echo
    spec:
      containers:
      - name: echoserver
        image: gcr.io/google-containers/echoserver@sha256:cb5c1bddd1b5665e1867a7fa1b5fa843a47ee433bbb75d4293888b71def53229
        ports:
        - containerPort: 8080

使用映像摘要的一个缺点是,在将映像发布到注册表之前,您不知道摘要值。构建新映像时,摘要值会发生变化,您需要在每次部署时更新 Kubernetes 清单。

本教程介绍了如何使用 SkaffoldkptdigesterKustomizegke-deploykoBazel 在清单中使用映像摘要。

建议

本文档介绍了几种在 Kubernetes 部署中使用映像摘要的方法。本文档中介绍的工具互为补充。例如,您可以结合使用 kpt 函数的输出和 kustomize 来为不同环境创建变体。Skaffold 可以使用 Bazel 构建映像,并使用 kpt 或 kustomize 将映像部署到 Kubernetes 集群。

这些工具互为补充的原因是它们根据 Kubernetes 资源模型 (KRM) 执行结构化修改。此模型使工具成为可插入工具,您可以改进这些工具的用途,创建可帮助您部署应用和服务的流程和流水线。

首先,我们建议您使用最适合您的现有工具和流程的方法:

  • 通过使用 digester 工具作为 Kubernetes 集群中的可变准入网络钩子,您可以向所有部署添加摘要,同时将对构建和部署容器映像的当前流程的影响降至最低。Digester 网络钩子也简化了 Binary Authorization 的采用,因为它只需要将标签添加到命名空间。

  • 如果您需要灵活的工具来处理 Kubernetes 清单,kpt 不失为一种很不错的选择。Digester 工具可以在 kpt 流水线中用作客户端 KRM 函数。

  • Skaffold 可用于向映像参考添加摘要。您只需进行细微的配置更改即可启用此功能。采用 Skaffold 具有额外优势,例如总结不同的工具构建和部署容器映像的方式。

  • 如果您已使用 kustomize 跨环境管理 Kubernetes 清单,我们建议您利用其映像转换器以摘要的形式部署映像。

  • ko 是构建和发布 Go 应用映像的好方法,它可用于 KnativeTektonsigstore 等开源项目。

  • 如果您已使用 Bazel 构建应用,我们建议您添加 rules_docker 规则集以构建映像,并添加 rules_k8s 规则集填充 Kubernetes 清单中的映像摘要。

如果您没有使用本文档中所述的任何工具,我们建议您从 Skaffold 和 digester 网络钩子开始。Skaffold 是开发者和发布团队使用的常用工具,与本教程中所述的其他工具集成。随着需求的变化,您可以利用这些集成选项。Digester Kubernetes 网络钩子通过为整个组织启用基于摘要的部署来补充 Skaffold。

目标

  • 使用 Skaffold 构建和推送映像,并在 Kubernetes 清单中插入映像名称和摘要。
  • 使用 kpt setter 将 Kubernetes 清单中的映像标记替换为映像摘要。
  • 使用 digester 客户端函数和可变准入网络钩子,将摘要添加到 Kubernetes Pod 和 Pod 模板中的映像。
  • 使用 kustomize 生成带有映像摘要的 Kubernetes 清单。
  • 使用 gke-deploy 将映像标记解析为 Kubernetes 清单中的摘要。
  • 使用 ko 构建和推送映像,并在 Kubernetes 清单中插入映像名称和摘要。
  • 使用 Bazel 构建和推送映像,并在 Kubernetes 清单中插入映像名称和摘要。

费用

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

您可使用价格计算器根据您的预计使用情况来估算费用。 Google Cloud 新用户可能有资格申请免费试用

完成本文档中描述的任务后,您可以通过删除所创建的资源来避免继续计费。如需了解详情,请参阅清理

准备工作

  1. 在 Google Cloud Console 中的项目选择器页面上,选择或创建一个 Google Cloud 项目

    转到“项目选择器”

  2. 确保您的 Google Cloud 项目已启用结算功能

  3. 启用 Container Registry API。

    启用 API

  4. 在 Google Cloud 控制台中,激活 Cloud Shell。

    激活 Cloud Shell

使用 Skaffold

Skaffold 是一种命令行工具,用于持续开发应用并将应用持续部署到 Kubernetes 集群。

使用 Skaffold 构建映像,将映像推送到 Container Registry,然后将 Kubernetes 清单模板中的 image 占位值替换为推送映像的名称、标记和摘要:

  1. 在 Cloud Shell 中,创建并转到用于存储您在本部分创建的文件的目录:

    mkdir -p ~/container-image-digests-tutorial/skaffold
    cd ~/container-image-digests-tutorial/skaffold
    
  2. 克隆 Skaffold Git 代码库:

    git clone https://github.com/GoogleContainerTools/skaffold.git
    
  3. 转到 getting-started 示例的目录:

    cd skaffold/examples/getting-started
    
  4. 查看与您的 Skaffold 版本匹配的 Git 标记:

    git checkout $(skaffold version)
    
  5. 查看 skaffold.yaml 配置文件:

    cat skaffold.yaml
    

    该文件类似于以下内容:

    apiVersion: skaffold/v2beta26
    kind: Config
    build:
      artifacts:
      - image: skaffold-example
    deploy:
      kubectl:
        manifests:
          - k8s-*
    

    build.artifacts 部分包含映像上下文,在本例中为占位符名称。Skaffold 会在输入清单文件中查找此占位符。在本部分中,您还需要定义 Skaffold 用于构建映像的上下文目录。默认情况下,Skaffold 使用当前目录作为构建上下文。

    deploy 部分指示 Skaffold 读取当前目录中名称与 k8s-* 模式匹配的输入清单,并使用 kubectl apply 部署渲染的清单。

    如需大致了解所有可用选项,请参阅 skaffold.yaml 参考文档

  6. 查看 Kubernetes 清单模板:

    cat k8s-pod.yaml
    

    该文件如下所示:

    apiVersion: v1
    kind: Pod
    metadata:
      name: getting-started
    spec:
      containers:
      - name: getting-started
        image: skaffold-example
    

    image 字段中的 skaffold-example 占位值与 skaffold.yaml 文件中的 image 字段的值匹配。Skaffold 会在渲染的输出中将此占位值替换为完整的映像名称和摘要。

  7. 构建映像并将其推送到 Container Registry:

    skaffold build \
        --default-repo=gcr.io/$(gcloud config get-value core/project) \
        --file-output=artifacts.json \
        --interactive=false \
        --push=true \
        --update-check=false
    

    此命令使用以下标志:

    • --file-output 标志指定 Skaffold 用于保存有关构建映像的信息(包括摘要值)的文件。
    • --push 标志指示 Skaffold 将构建的映像推送到由 --default-repo 标志指定的容器映像注册表。
    • --interactive--update-check 标志均设置为 false。在非交互式环境(如构建流水线)中,将这些标志设置为 false;对于本地开发,请将这些标志保留为默认值(两个标志均为 true)。

    如果您使用 Google Cloud Deploy 部署到 GKE,请在创建版本时使用 --file-output 标志中的文件作为 --build-artifacts 标志的值。

  8. 使用上一步中的容器映像的名称、标记和摘要渲染展开的 Kubernetes 清单:

    skaffold render \
        --build-artifacts=artifacts.json \
        --digest-source=none \
        --interactive=false \
        --offline=true \
        --output=rendered.yaml \
        --update-check=false
    

    此命令使用以下标志:

    • --build-artifacts 标志引用上一步中 skaffold build 命令的输出文件。
    • --digest-source=none 标志表示 Skaffold 使用 --build-artifacts 标志提供的文件中的摘要值,而不是解析容器注册表中的摘要。
    • --offline=true 标志表示您可以在无需访问 Kubernetes 集群的情况下运行该命令。
    • --output 标志指定渲染的清单的输出文件。
  9. 查看呈现的清单:

    cat rendered.yaml
    

    输出类似以下内容:

    apiVersion: v1
    kind: Pod
    metadata:
      name: getting-started
    spec:
      containers:
      - image: gcr.io/YOUR_PROJECT_ID/skaffold-example:TAG@sha256:DIGEST
        name: getting-started
    

    在此输出中,您会看到以下值:

    • YOUR_PROJECT_ID:您的 Cloud 项目 ID
    • TAG:Skaffold 分配给映像的标记。
    • DIGEST:映像摘要值

使用 kpt setter

kpt 是一个命令行工具,用于管理、操作、自定义和应用 Kubernetes 资源清单。

您可以在构建新映像时使用 kpt Functions 目录中的 create-settersapply-setters KRM 函数更新 Kubernetes 清单中的映像摘要。

  1. 在 Cloud Shell 中,创建并转到用于存储您在本部分创建的文件的目录:

    mkdir -p ~/container-image-digests-tutorial/kpt
    cd ~/container-image-digests-tutorial/kpt
    
  2. 下载 kpt:

    mkdir -p ${HOME}/bin
    curl -L https://github.com/GoogleContainerTools/kpt/releases/download/v1.0.0-beta.1/kpt_linux_amd64 --output ${HOME}/bin/kpt
    chmod +x ${HOME}/bin/kpt
    export PATH=${HOME}/bin:${PATH}
    
  3. 在当前目录中创建 kpt 软件包:

    kpt pkg init --description "Container image digest tutorial"
    
  4. 使用标记 1.10 创建引用映像 gcr.io/google-containers/echoserver 的 Kubernetes Pod 清单:

    cat << EOF > pod.yaml
    apiVersion: v1
    kind: Pod
    metadata:
      name: echo
    spec:
      containers:
      - name: echoserver
        image: gcr.io/google-containers/echoserver:1.10
        ports:
        - containerPort: 8080
    EOF
    
  5. 使用 kpt 为清单字段创建一个名为 echoimage 的 setter,现有值为 gcr.io/google-containers/echoserver:1.10

    kpt fn eval . \
        --image gcr.io/kpt-fn/create-setters:v0.1@sha256:0220cc87f29ff9abfa3a3b5643aa50f18d355d5e9dc9e1f518119633ddc4895c \
        -- "echoimage=gcr.io/google-containers/echoserver:1.10"
    
  6. 查看清单:

    cat pod.yaml
    

    该文件如下所示:

    apiVersion: v1
    kind: Pod
    metadata:
      name: echo
    spec:
      containers:
      - name: echoserver
        image: gcr.io/google-containers/echoserver:1.10 # kpt-set: ${echoimage}
        ports:
        - containerPort: 8080
    
  7. 获取容器映像的摘要值:

    DIGEST=$(gcloud container images describe \
        gcr.io/google-containers/echoserver:1.10 \
        --format='value(image_summary.digest)')
    
  8. 设置新字段值:

    kpt fn eval . \
        --image gcr.io/kpt-fn/apply-setters:v0.2@sha256:4d4295727183396f0c3c6a75d2560254c2f9041a39e95dc1e5beffeb49cc1a12 \
        -- "echoimage=gcr.io/google-containers/echoserver:1.10@$DIGEST"
    

    运行此命令时,kpt 将就地替换清单中的 image 字段值。

  9. 查看更新后的清单:

    cat pod.yaml
    

    该文件如下所示:

    apiVersion: v1
    kind: Pod
    metadata:
      name: echo
    spec:
      containers:
      - name: echoserver
        image: gcr.io/google-containers/echoserver:1.10@sha256:cb5c1bddd1b5665e1867a7fa1b5fa843a47ee433bbb75d4293888b71def53229 # kpt-set: ${echoimage}
        ports:
        - containerPort: 8080
    

使用 digester

Digester 向 Kubernetes Pod 和 Pod 模板规范中的容器和 init 容器映像添加摘要。Digester 会替换使用标记的容器映像引用:

spec:
  containers:
  - image: gcr.io/google-containers/echoserver:1.10

对于使用映像摘要的引用,请注意以下事项:

spec:
  containers:
  - image: gcr.io/google-containers/echoserver:1.10@sha256:cb5c1bddd1b5665e1867a7fa1b5fa843a47ee433bbb75d4293888b71def53229

Digester 可在 Kubernetes 集群中作为可变准入网络钩子运行,也可使用 kpt 或 kustomize 命令行工具作为客户端 KRM 函数运行。

使用 digester KRM 函数

  1. 在 Cloud Shell 中,创建并转到用于存储您在本部分创建的文件的目录:

    mkdir -p ~/container-image-digests-tutorial/digester-fn
    cd ~/container-image-digests-tutorial/digester-fn
    
  2. 下载 digester 二进制文件:

    DIGESTER_VERSION=v0.1.7
    mkdir -p ${HOME}/bin
    curl -L "https://github.com/google/k8s-digester/releases/download/${DIGESTER_VERSION}/digester_$(uname -s)_$(uname -m)" --output ${HOME}/bin/digester
    chmod +x ${HOME}/bin/digester
    export PATH=${HOME}/bin:${PATH}
    
  3. 使用标记 1.10 创建引用映像 gcr.io/google-containers/echoserver 的 Kubernetes Pod 清单:

    cat << EOF > pod.yaml
    apiVersion: v1
    kind: Pod
    metadata:
      name: echo
    spec:
      containers:
      - name: echoserver
        image: gcr.io/google-containers/echoserver:1.10
        ports:
        - containerPort: 8080
    EOF
    
  4. 使用 kpt 和当前目录 (.) 中的清单运行摘要 KRM 函数:

    kpt fn eval . --exec digester
    

    运行此命令时,kpt 会对当前目录中的清单执行就地更新。如果您希望 kpt 在控制台中显示更新后的清单,并保持清单文件不变,请添加 --output unwrap 标志。

  5. 查看更新后的清单:

    cat pod.yaml
    

    该文件如下所示:

    apiVersion: v1
    kind: Pod
    metadata:
      name: echo
    spec:
      containers:
        - name: echoserver
          image: gcr.io/google-containers/echoserver:1.10@sha256:cb5c1bddd1b5665e1867a7fa1b5fa843a47ee433bbb75d4293888b71def53229
          ports:
            - containerPort: 8080
    

使用 digester 准入网络钩子

  1. 在 Cloud Shell 中,创建并转到用于存储您在本部分创建的文件的目录:

    mkdir -p ~/container-image-digests-tutorial/digester-webhook
    cd ~/container-image-digests-tutorial/digester-webhook
    
  2. 下载 kind

    KIND_VERSION=v0.11.1
    mkdir -p ${HOME}/bin
    curl -L "https://github.com/kubernetes-sigs/kind/releases/download/${KIND_VERSION}/kind-linux-amd64" --output ${HOME}/bin/kind
    chmod +x ${HOME}/bin/kind
    export PATH=${HOME}/bin:${PATH}
    

    Kind 是一个命令行工具,用于使用 Docker 运行本地 Kubernetes 集群。

  3. 创建本地 Kubernetes 集群:

    kind create cluster
    
  4. 下载 digester 网络钩子 kpt 软件包并将其存储在名为 manifests 的目录中:

    DIGESTER_VERSION=v0.1.7
    kpt pkg get https://github.com/google/k8s-digester.git/manifests@${DIGESTER_VERSION} manifests
    
  5. 部署 digester 网络钩子:

    kpt live init manifests
    kpt live apply manifests --reconcile-timeout=3m --output=table
    
  6. 在种类集群中创建一个名为 digester-demo 的 Kubernetes 命名空间:

    kubectl create namespace digester-demo
    
  7. digest-resolution: enabled 标签添加到 digester-demo 命名空间:

    kubectl label namespace digester-demo digest-resolution=enabled
    

    Digester 网络钩子会将摘要添加到带有此标签的命名空间中的 pod。

  8. 使用标记 1.10 创建引用映像 gcr.io/google-containers/echoserver 的 Kubernetes Deployment 清单:

    cat << EOF > deployment.yaml
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: echo-deployment
    spec:
      selector:
        matchLabels:
          app: echo
      template:
        metadata:
          labels:
            app: echo
        spec:
          containers:
          - name: echoserver
            image: gcr.io/google-containers/echoserver:1.10
            ports:
            - containerPort: 8080
    EOF
    
  9. digester-demo 命名空间中应用清单:

    kubectl apply --filename deployment.yaml --namespace digester-demo \
        --output jsonpath='{.spec.template.spec.containers[].image}{"\n"}'
    

    --output 标志指示 kubectl 将映像名称输出到控制台,后跟换行符。输出如下所示:

    gcr.io/google-containers/echoserver:1.10@sha256:cb5c1bddd1b5665e1867a7fa1b5fa843a47ee433bbb75d4293888b71def53229
    

    此输出表明 digester 网络钩子将映像摘要添加到了 Deployment 资源中的 Pod 模板规范。

  10. 删除种类集群以释放 Cloud Shell 会话中的资源:

    kind delete cluster
    

使用 kustomize 映像转换器

kustomize 是一个命令行工具,可让您使用叠加层、补丁程序和转换器自定义 Kubernetes 清单。

您可以使用 kustomize 映像转换器来更新现有清单中的映像名称、标记和摘要。

以下 kustomization.yaml 代码段介绍如何将映像转换器配置为将转换器 digest 值用于映像,这些映像中的 Pod 规范 image 值与转换器 name 值匹配:

images:
- name: gcr.io/google-containers/echoserver
  digest: sha256:cb5c1bddd1b5665e1867a7fa1b5fa843a47ee433bbb75d4293888b71def53229

如需使用含有映像摘要的映像转换器,请执行以下操作:

  1. 在 Cloud Shell 中,创建并转到用于存储您在本部分创建的文件的目录:

    mkdir -p ~/container-image-digests-tutorial/kustomize
    cd ~/container-image-digests-tutorial/kustomize
    
  2. 创建 kustomization.yaml 文件:

    kustomize init
    
  3. 通过使用标记 1.10 引用映像 gcr.io/google-containers/echoserver 的 Pod 规范创建一个 Kubernetes 清单:

    cat << EOF > pod.yaml
    apiVersion: v1
    kind: Pod
    metadata:
      name: echo
    spec:
      containers:
      - name: echoserver
        image: gcr.io/google-containers/echoserver:1.10
        ports:
        - containerPort: 8080
    EOF
    
  4. 将清单作为资源添加到 kustomization.yaml 文件中:

    kustomize edit add resource pod.yaml
    
  5. 使用映像转换器更新映像的摘要:

    kustomize edit set image \
        gcr.io/google-containers/echoserver@sha256:cb5c1bddd1b5665e1867a7fa1b5fa843a47ee433bbb75d4293888b71def53229
    
  6. kustomization.yaml 文件中查看映像转换器:

    cat kustomization.yaml
    

    该文件如下所示:

    apiVersion: kustomize.config.k8s.io/v1beta1
    kind: Kustomization
    resources:
    - pod.yaml
    images:
    - digest: sha256:cb5c1bddd1b5665e1867a7fa1b5fa843a47ee433bbb75d4293888b71def53229
      name: gcr.io/google-containers/echoserver
    
  7. 查看生成的清单:

    kustomize build .
    

    输出如下所示:

    apiVersion: v1
    kind: Pod
    metadata:
      name: echo
    spec:
      containers:
      - image: gcr.io/google-containers/echoserver@sha256:cb5c1bddd1b5665e1867a7fa1b5fa843a47ee433bbb75d4293888b71def53229
        name: echoserver
        ports:
        - containerPort: 8080
    
  8. 如需将生成的清单应用到 Kubernetes 集群,您可以将 kubectl apply--kustomize 标志结合使用:

    kubectl apply --kustomize .
    

    如果要在稍后应用输出,可以将 kustomize build 命令的输出重定向到一个文件。Kustomize 具有本文档未介绍的其他功能。如需了解详情,请参阅 kustomize 文档。Kustomize 还可以作为 Cloud Build 社区构建器映像提供。

使用 gke-deploy

gke-deploy 是一个与 Google Kubernetes Engine (GKE) 搭配使用的命令行工具。gke-deploy 封装了 kubectl 命令行工具,并且可以修改您按照 Google 推荐的做法创建的资源。

如果您使用 gke-deploy 子命令 preparerungke-deploy 会默认将您的映像标记解析为摘要并使用映像摘要将展开后的清单保存到文件 output/expanded/aggregated-resources.yaml

您可以使用 gke-deploy run 将映像标记替换为摘要,并将展开的清单应用于 GKE 集群。虽然此命令使用方便,但存在一个缺点:映像标记会在部署时被替换。与标记关联的映像可能会在您决定部署与部署之间发生更改,导致部署异常映像。对于生产部署,我们建议将生成和应用清单步骤分开执行。

如需使用映像摘要替换 Kubernetes 部署清单中的映像标记,请执行以下操作:

  1. 在 Cloud Shell 中,创建并转到用于存储您在本部分创建的文件的目录:

    mkdir -p ~/container-image-digests-tutorial/gke-deploy
    cd ~/container-image-digests-tutorial/gke-deploy
    
  2. 安装 gke-deploy

    go install github.com/GoogleCloudPlatform/cloud-builders/gke-deploy@latest
    
  3. 使用标记 1.10 创建引用映像 gcr.io/google-containers/echoserver 的 Kubernetes Deployment 清单:

    cat << EOF > deployment.yaml
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: echo-deployment
    spec:
      selector:
        matchLabels:
          app: echo
      template:
        metadata:
          labels:
            app: echo
        spec:
          containers:
          - name: echoserver
            image: gcr.io/google-containers/echoserver:1.10
            ports:
            - containerPort: 8080
    EOF
    
  4. 根据 deployment.yaml 清单生成展开的清单:

    gke-deploy prepare \
        --filename deployment.yaml \
        --image gcr.io/google-containers/echoserver:1.10 \
        --version 1.10
    
  5. 查看展开的清单:

    cat output/expanded/aggregated-resources.yaml
    

    输出如下所示:

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      labels:
        app.kubernetes.io/managed-by: gcp-cloud-build-deploy
        app.kubernetes.io/version: "1.10"
      name: echo-deployment
      namespace: default
    spec:
      selector:
        matchLabels:
          app: echo
      template:
        metadata:
          labels:
            app: echo
            app.kubernetes.io/managed-by: gcp-cloud-build-deploy
            app.kubernetes.io/version: "1.10"
        spec:
          containers:
          - image: gcr.io/google-containers/echoserver@sha256:cb5c1bddd1b5665e1867a7fa1b5fa843a47ee433bbb75d4293888b71def53229
            name: echoserver
            ports:
            - containerPort: 8080
    

    在展开的清单中,映像标记会被替换为摘要。

    gke-deploy 命令一起使用的 --version 参数会在部署中设置建议的 app.kubernetes.io/version 标签的值,以及设置扩展清单的 Pod 模板元数据。

    gke-deploy 工具还可以作为适用于 Cloud Build 的预构建映像提供。如需了解如何将 gke-deploy 与 Cloud Build 配合使用,请参阅适用于 gke-deploy 的 Cloud Build 文档

使用 ko

ko 是一个命令行工具,用于构建 Go 容器映像并将其部署到 Kubernetes 集群。ko 可以在不使用 Docker 守护程序的情况下构建映像,以便您可以在无法安装 Docker 的环境中使用映像。

ko 子命令 publish 构建映像并将其发布到 Container Registry 或将它们加载到本地 Docker 守护程序。

ko 子命令 resolve 会执行以下操作:

  • 通过在 Kubernetes 清单的 image 字段中查找您使用 --filename 参数提供的占位符来找到要构建的映像。
  • 构建和发布映像。
  • image 值占位符替换为所构建映像的名称和摘要。
  • 输出展开的清单。

ko 子命令 applycreaterun 会执行与 resolve 相同的步骤,然后使用展开的清单执行 kubectl applycreaterun

如需通过 Go 源代码构建映像,并将映像摘要添加到 Kubernetes 部署清单,请执行以下操作:

  1. 在 Cloud Shell 中,创建并转到用于存储您在本部分创建的文件的目录:

    mkdir -p ~/container-image-digests-tutorial/ko
    cd ~/container-image-digests-tutorial/ko
    
  2. 下载 ko 并将其添加到您的 PATH

    mkdir -p ${HOME}/bin
    curl -L https://github.com/google/ko/releases/download/v0.9.3/ko_0.9.3_$(uname -s)_$(uname -m).tar.gz | tar -zxC ${HOME}/bin ko
    export PATH=${HOME}/bin:${PATH}
    
  3. 在名为 app 的新目录中创建模块名称为 example.com/hello-world 的 Go 应用:

    mkdir -p app/cmd/ko-example
    
    cd app
    
    go mod init example.com/hello-world
    
    cat << EOF > cmd/ko-example/main.go
    package main
    
    import "fmt"
    
    func main() {
        fmt.Println("hello world")
    }
    EOF
    
  4. 定义 ko 用于发布映像的映像代码库:

    export KO_DOCKER_REPO=gcr.io/$(gcloud config get-value core/project)
    

    本示例使用 Container Registry,但您可以使用其他注册表。

  5. 如需为您的应用构建和发布映像,请执行以下步骤之一:

    • 通过提供 Go 主软件包的路径,为应用构建并发布映像:

      ko publish --base-import-paths ./cmd/ko-example
      

      可选参数 --base-import-paths 表示 ko 使用主软件包目录的短名称作为映像名称。

      ko 采用以下格式将映像名称和摘要输出到 stdout

      gcr.io/YOUR_PROJECT_ID/ko-example@sha256:DIGEST_VALUE
      

      在此输出中:

      • YOUR_PROJECT_ID:您的 Cloud 项目 ID
      • DIGEST_VALUE:映像摘要值
    • 使用 ko 将清单占位符替换为其构建并发布的映像的名称和摘要:

      1. 创建 Kubernetes pod 清单。清单使用占位符 ko://IMPORT_PATH_OF_YOUR_MAIN_PACKAGE 作为 image 字段的值:

        cat << EOF > ko-pod.yaml
        apiVersion: v1
        kind: Pod
        metadata:
          name: ko-example
        spec:
          containers:
          - name: hello-world
            image: ko://example.com/hello-world/cmd/ko-example
        EOF
        
      2. 使用 ko resolve 为应用构建并发布映像,并将清单占位符替换为映像名称和摘要:

        ko resolve --base-import-paths --filename ko-pod.yaml
        

        ko 会将包含映像名称和清单的摘要输出到 stdout

        apiVersion: v1
        kind: Pod
        metadata:
          name: ko-example
        spec:
          containers:
          - name: hello-world
            image: gcr.io/YOUR_PROJECT_ID/ko-example@sha256:DIGEST
        

        在此输出中:

        • YOUR_PROJECT_ID:您的 Cloud 项目 ID
        • DIGEST:映像摘要值

使用 Bazel

Bazel 是一个开源多语言构建工具,基于 Google 的内部 Blaze 构建系统。

rules_docker 是一个用于构建和推送容器映像的 Bazel 规则集。这些规则可以在不使用 Docker 守护程序的情况下构建可重现的映像,并且 Bazel 的缓存可以加快构建映像并将映像推送到注册表的速度。

rules_k8s 是一个用于处理 Kubernetes 清单和集群的 Bazel 规则集。

如需构建并推送映像以使用映像摘要填充 Kubernetes 清单,请执行以下操作:

  1. 在 Cloud Shell 中,创建并转到用于存储您在本部分创建的文件的目录:

    mkdir -p ~/container-image-digests-tutorial/bazel
    cd ~/container-image-digests-tutorial/bazel
    
  2. 克隆 rules_k8s Git 代码库

    git clone https://github.com/bazelbuild/rules_k8s.git
    
  3. 转到 Git 代码库目录:

    cd rules_k8s
    
  4. 查看 Git 标记:

    git checkout v0.6
    
  5. WORKSPACE 文件中,替换 Bazel 将映像推送到基础映像的代码库名称,由您使用该映像来推送映像的代码库:

    sed -i~ "s/image_chroot.*/image_chroot = \"gcr.io\/$(gcloud config get-value core\/project)\",/" WORKSPACE
    

    本示例使用 Container Registry,但您可以使用其他注册表。

  6. 安装用于构建的 Bazel 版本:

    sudo apt-get install -y bazel-$(cat .bazelversion)
    
  7. 修复示例 Kubernetes 部署清单模板中的 apiVersion 字段:

    sed -i~ 's/v1beta1/v1/' examples/hellohttp/deployment.yaml
    
  8. 查看 Kubernetes 部署清单模板:

    cat examples/hellohttp/deployment.yaml
    

    该文件如下所示:

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: hello-http-staging
    spec:
      replicas: 1
      template:
        metadata:
          labels:
            app: hello-http-staging
        spec:
          containers:
          - name: hello-http
            image: hello-http-image:latest
            imagePullPolicy: Always
            ports:
            - containerPort: 8080
    
  9. hellohttp 示例构建 Java 映像,将其推送到 Container Registry,然后将 Kubernetes 部署清单模板中的 image 值替换为已推送的映像名称和摘要。重定向 stdout 输出以捕获名为 deployment.yaml.out 的新文件中展开的清单:

    bazel --output_user_root=/tmp/bazel \
        run //examples/hellohttp/java:staging > deployment.yaml.out
    

    第一次运行此命令时需要几分钟时间,因为它会下载规则集、编译器和依赖项。

    --output_user_root 参数指示 Bazel 将主目录之外的临时目录用于其基于磁盘的缓存。此临时目录是 Cloud Shell 中所必需的,以避免填满您的主目录卷。

  10. 查看展开的清单:

    cat deployment.yaml.out
    

    该文件类似于以下内容:

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: hello-http-staging
    spec:
      replicas: 1
      template:
        metadata:
          labels:
            app: hello-http-staging
        spec:
          containers:
          - image: gcr.io/YOUR_PROJECT_ID/hello-http-image@sha256:b9d0a4643e9f11efe7cd300dd219ad691077ddfaccc118144cd83b7c472a8e86
            imagePullPolicy: Always
            name: hello-http
            ports:
            - containerPort: 8080
    
  11. 检查 Bazel 推送到 Container Registry 的映像:

    gcloud container images describe \
        gcr.io/$(gcloud config get-value core/project)/hello-http-image
    

清除数据

为了避免产生费用,最简单的方法是删除您为本教程创建的项目。或者,您也可以删除各个资源。

删除项目

  1. 在 Google Cloud 控制台中,进入管理资源页面。

    转到“管理资源”

  2. 在项目列表中,选择要删除的项目,然后点击删除
  3. 在对话框中输入项目 ID,然后点击关闭以删除项目。

删除资源

若要保留本教程中使用的 Google Cloud 项目,请删除各个资源:

  1. 删除 Container Registry 中的映像:

    for IMG in hello-http-image ko-example skaffold-example ; do \
        gcloud container images list-tags \
            gcr.io/$(gcloud config get-value core/project)/$IMG \
            --format 'value(digest)' | xargs -I {} gcloud container images \
            delete --force-delete-tags --quiet \
            gcr.io/$(gcloud config get-value core/project)/$IMG@sha256:{}
    done
    
  2. 删除您在本教程中创建的文件:

    cd
    rm -rf ~/container-image-digests-tutorial
    

后续步骤