如何通过 Google Cloud Build 中的步骤设置环境或替换变量?

How do I set an environment or substitution variable via a step in Google Cloud Build?

基本上,在使用 Google Cloud Build 时,如何在后续步骤中读取在较早构建步骤中写入的值?

具体来说,我想创建一个基于时间戳和 $SHORT_SHA 组合的自定义图像标签。像下面这样的东西。虽然,它不起作用,因为 docker 抱怨 "export",而且,即使它起作用,它也可能是一个不同的环境:

  # Setting tag in a variable:
  - name: 'ubuntu'
    args: ['export', '_BUILD_TAG=`date', '-u', '+%Y%m%dT%H%M%S_$SHORT_SHA`']

然后,在后面的步骤中:

  # Using tag from the variable:
  - name: gcr.io/cloud-builders/docker
    args: ['build', '-t', 'gcr.io/$PROJECT_ID/$_BUILD_TAG', '.']

那么,如何在另一步骤中使用一个步骤的输出?我可以将 date 的内容写入文件,然后读取它,但我不知道如何从我读取的文件中设置变量(或以其他方式插入其结果以形成 docker 构建)。

- name: gcr.io/cloud-builders/docker
  entrypoint: sh
  args
    - '-c'
    - 'docker build -t gcr.io/$PROJECT_ID/$(date -u +%Y%m%dT%H%M%S_$SHORT_SHA) .'

我从来没有找到一种在一个构建步骤中设置可以在其他步骤中读取的环境变量的方法,但我最终通过以下方式构建康斯坦丁的答案来实现相同的效果:

在早期步骤中,我生成了基于日期的标签并将其写入文件。文件系统 (/workspace) 在步骤之间保留,并用作我的环境变量的存储。然后,在我需要引用该值的每个步骤中,我将该文件放在适当的位置。诀窍是使用 sh 或 bash 作为每个容器中的入口点,以便从文件读取的子 shell 可以执行。

这是一个例子:

## Set build tag and write to file _TAG
- name: 'ubuntu'
  args: ['bash', '-c', 'date -u +%Y%m%dT%H%M_$SHORT_SHA > _TAG']

...

# Using the _TAG during Docker build:
- name: gcr.io/cloud-builders/docker
entrypoint: sh
args: ['-c', 'docker build -t gcr.io/$PROJECT_ID/image_name:$(cat _TAG) .']

需要注意的一点是,如果您在 JSON 对象或需要双引号的对象中以这种方式进行 bash 插值,则需要 subshell 调用在容器中执行时永远不会被单引号括起来,只有双引号,这可能需要转义内部双引号以构建 JSON 对象。这是一个示例,我使用 _TAG 文件值修补 kubernetes 配置以部署新构建的映像:

- name: gcr.io/cloud-builders/kubectl
entrypoint: bash
args: ['-c', 'gcloud container clusters get-credentials --zone $$CLOUDSDK_COMPUTE_ZONE $$CLOUDSDK_CONTAINER_CLUSTER ; kubectl patch deployment deployment_name -n mynamespace -p "{\"spec\":{\"template\":{\"spec\":{\"containers\":[{\"name\":\"image_name\",\"image\":\"gcr.io/$PROJECT_ID/image_name:$(cat _TAG)\"}]}}}}}"']
env:
- 'CLOUDSDK_COMPUTE_ZONE=us-central1-b'
- 'CLOUDSDK_CONTAINER_CLUSTER=my-google-proj-cluster-name'

虽然这不能解决您的问题,但我确实想要 post 这个答案,因为您问题的第一句话是,“基本上,当使用 Google 云时构建,如何在后续步骤中读取在较早构建步骤中写入的值?”。这就是你的做法。

来自the official documentation

A Volume is a Docker container that is mounted into build steps to persist files across build steps. When Cloud Build runs a build step, it automatically mounts a workspace volume into /workspace. You can specify additional volumes to be mounted into your build steps' containers using the volumes field for your steps.

这是一个由某人 who asked this question in a github issue 实现的示例,但是将日期放入卷中以供以后通过另一个步骤阅读:

steps:
- name: 'ubuntu'
  volumes:
  - name: 'vol1'
    path: '/persistent_volume'
  entrypoint: 'bash'
  args:
  - '-c'
  - |
        date -u +%Y%m%dT%H%M_$SHORT_SHA > /persistent_volume/file
- name: 'gcr.io/cloud-builders/docker'
  volumes:
  - name: 'vol1'
    path: '/persistent_volume'
  args: ['run', '-v', 'vol1:/data', 'alpine', 'cat', 'data/file']

但是,对于您的特定情况,我会像完成一样用子 shell 命令标记它 :

$(date -u +%Y%m%dT%H%M%S_$SHORT_SHA)

在您的案例中,您不需要导出或装载卷。

steps:
- name: 'ubuntu'
  entrypoint: 'bash'
  args:
  - '-c'
  - |
        printenv

- name: gcr.io/cloud-builders/docker
  entrypoint: 'bash'
  args:
  - '-c'
  - |
        printenv

会输出

BUILD
Starting Step #0
Step #0: Pulling image: ubuntu
Step #0: Using default tag: latest
Step #0: latest: Pulling from library/ubuntu
Step #0: Digest: sha256:eb70667a801686f914408558660da753cde27192cd036148e58258819b927395
Step #0: Status: Downloaded newer image for ubuntu:latest
Step #0: HOSTNAME=XXXXXXXXXXX
Step #0: BUILDER_OUTPUT=/builder/outputs
Step #0: PWD=/workspace
Step #0: HOME=/builder/home
Step #0: SHLVL=1
Step #0: PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
Step #0: _=/usr/bin/printenv
Finished Step #0
Starting Step #1
Step #1: Already have image (with digest): gcr.io/cloud-builders/docker
Step #1: HOSTNAME=XXXXXXXXXXX
Step #1: PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
Step #1: PWD=/workspace
Step #1: SHLVL=1
Step #1: HOME=/builder/home
Step #1: DEBIAN_FRONTEND=noninteractive
Step #1: BUILDER_OUTPUT=/builder/outputs
Step #1: _=/usr/bin/printenv
Finished Step #1

所以你可以使用 /workspace/builder/home,但由于我们不能在 yaml 文件中使用 defined substitution 以外的变量,因此将它们作为脚本放在 repo 中,如下所示:

steps:
- name: 'ubuntu'
  entrypoint: 'bash'
  args:
  - '-c'
  - |
        bash test.bash

- name: gcr.io/cloud-builders/docker
  entrypoint: 'bash'
  args:
  - '-c'
  - |
        bash result.bash

test.bash

#!/bin/bash
SHORT_SHA=myvar
date -u +%Y%m%dT%H%M_$SHORT_SHA > /workspace/myfile.txt

result.bash

#!/bin/bash
_BUILD_TAG=`cat /workspace/myfile.txt`
echo "the transferred value is: $_BUILD_TAG"

输出:

BUILD
Starting Step #0
Step #0: Pulling image: ubuntu
Step #0: Using default tag: latest
Step #0: latest: Pulling from library/ubuntu
Step #0: Digest: sha256:eb70667a801686f914408558660da753cde27192cd036148e58258819b927395
Step #0: Status: Downloaded newer image for ubuntu:latest
Finished Step #0
Starting Step #1
Step #1: Already have image (with digest): gcr.io/cloud-builders/docker
Step #1: the transferred value is: 20190708T1706_myvar
Finished Step #1
PUSH
DONE

这是我自己刚刚在另一个中重用 GitVersion 输出的示例。它建立在@chetabahana 发布的答案之上。

steps:
- id: 'Gitversion: Unshallow repo'
  name: gcr.io/cloud-builders/git
  args: [fetch, --unshallow]

- id: 'Gitversion: Parse'
  name: gittools/gitversion:latest-linux
  entrypoint: /bin/bash
  args:
    - -c 
    - |
      dotnet /app/GitVersion.dll > /workspace/gitversion.json

- id: 'Gitversion: Env file'
  name: stedolan/jq
  entrypoint: /bin/bash
  args:
    - -c
    - |
      for s in $(cat /workspace/gitversion.json | jq -r "to_entries|map(\"\(.key)=\(.value|tostring)\")|.[]" ); do
        echo "export $s" >> /workspace/gitversion.env
      done

- id: 'Build and push API image'
  name: gcr.io/cloud-builders/docker
  entrypoint: /bin/bash
  args:
    - -c
    - |
      source /workspace/gitversion.env
      docker build -t gcr.io/xxxx/example:$${SemVer}-$${BuildMetaData} example-app
      docker push gcr.io/xxxx/example:$${SemVer}-$${BuildMetaData}

神奇的成分是 $$ 来逃避替换变量,这样构建作业就不会尝试替换,而是留给 bash 来替换。

太糟糕了,Google(目前)还不支持它。但是,我经常使用以下简单方法并且效果很好。请记住,该文件默认保存到 /workspace,在容器之间共享。如果您需要在其他目录中使用它,请将其保存或复制到其他位置。

# Save variable to file
- name: 'gcr.io/cloud-builders/gcloud'
  entrypoint: 'bash'
  args:
  - '-c'
  - |
    _id=$(openssl rand -hex 16,,)
    echo "$${_id}" > id.txt

# Set variable from file
- name: 'gcr.io/cloud-builders/gcloud'
  entrypoint: 'bash'
  args:
  - '-c'
  - |
    _id=$(cat id.txt)
    echo "$${_id}"