Gitlab CI/CD 在管道之间传递工件/变量

mii*_*le7 30 pass-data gitlab gitlab-ci devops

太长了;博士

\n

如何$BUILD_VERSION在 Gitlab CI 中不同管道的作业之间传递数据(例如变量)?

\n

所以(就我而言):

\n
Pipeline 1 on push ect.            Pipeline 2 after merge\n\n    `building` job ...                `deploying` job\n          \xe2\x94\x82                                \xe2\x96\xb2\n          \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80 $BUILD_VERSION \xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x98\n
Run Code Online (Sandbox Code Playgroud)\n
\n

背景

\n

考虑以下示例(完整内容yml如下):

\n
Pipeline 1 on push ect.            Pipeline 2 after merge\n\n    `building` job ...                `deploying` job\n          \xe2\x94\x82                                \xe2\x96\xb2\n          \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80 $BUILD_VERSION \xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x98\n
Run Code Online (Sandbox Code Playgroud)\n

我有两个阶段,登台部署暂存阶段building的工作构建应用程序并创建一个“审查应用程序”(为了简单起见,没有单独的构建阶段)。然后,部署中的作业会上传新应用程序。deploying

\n

building每当打开合并请求时,包含作业的管道就会运行。这样,应用程序就构建完成了,开发人员可以单击合并请求中的“审核应用程序”图标。该deploying作业在合并请求合并后立即运行。这个想法如下:

\n
                      *staging* stage (pipeline 1)        *deploy* stage (pipeline 2)\n\n<open merge request> -> `building` job (and show)   ...   <merge> -> `deploying` job\n                             \xe2\x94\x82                                            \xe2\x96\xb2\n                             \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80 $BUILD_VERSION \xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x98\n
Run Code Online (Sandbox Code Playgroud)\n

对我来说问题是,登台/创建building一些数据,例如$BUILD_VERSION. 我想将其放在deploy /$BUILD_VERSION中,例如通过Gitlab API 创建新版本。deploying

\n

所以我的问题是:如何将$BUILD_VERSION(和其他数据)从staging /传递buildingdeploy / deploying

\n
\n

到目前为止我尝试过的

\n

artifacts.reports.dotenv

\n

所描述的情况在 gitlab 文档中将环境变量传递给另一个作业中处理得更少。另外,yml下面显示的文件深受此示例的启发。尽管如此,它仍然不起作用。

\n

build.env工件是在 中创建的building,但每当deploying执行作业时,该build.env文件就会被删除,如下面第 15 行所示:“删除 build.env”。我尝试添加build.env.gitignore但它仍然被删除。

\n

准备环境 - 通过 gitlab-runner 在 runner 上运行... - 从 Git 存储库获取源代码 - 获取 git 深度设置为 50 的更改... - 重新初始化现有的 Git 存储库 - 签出为暂存... - 删除构建。 env - 跳过 Git 子模块设置 - 执行作业脚本的“step_script”阶段 - 使用 docker 映像 - echo $BUILD_VERSION - 作业成功

\n

经过几个小时的搜索,我在这个 gitlab 问题评论这个 stackoverflow 帖子中发现不适artifacts.reports.dotenv用于dependenciesneeds关键字。

\n

删除dependencies不起作用。仅使用needs也不起作用。不允许同时使用两者。

\n

有谁知道如何让它发挥作用?我觉得这就是它应该发挥的作用。

\n

将工件作为文件获取

\n

stackoverflow 帖子Gitlab ci cd removes artifact for merge requests的答案建议将其用作build.env普通文件。我也尝试过这个。(相关)yml如下:

\n
building:\n    stage: staging\n    # only on merge requests\n    rules:\n        # execute when a merge request is open\n        - if: $CI_PIPELINE_SOURCE == "merge_request_event"\n          when: always\n        - when: never\n    script:\n        - echo "BUILD_VERSION=1.2.3" > build.env\n    artifacts:\n        reports:\n            dotenv: build.env\n\ndeploying:\n    stage: deploy\n    # after merge request is merged\n    rules:\n        # execute when a branch was merged to staging\n        - if: $CI_COMMIT_BRANCH == $STAGING_BRANCH\n          when: always\n        - when: never\n    dependencies: \n        - building\n    script:\n        - echo $BUILD_VERSION\n
Run Code Online (Sandbox Code Playgroud)\n

结果与上面相同。被build.env删除。然后source build.env命令失败,因为build.env不存在。(无论是否build.env在其中.gitignore,都进行了测试)

\n

从 API 获取工件

\n

我还找到了 stackoverflow 帖子Use artifacts from merge request job in GitLab CI的答案,它建议将 API 与$CI_JOB_TOKEN. 但由于我需要非合并请求管道中的工件,因此我无法使用建议的CI_MERGE_REQUEST_REF_PATH.

\n

我尝试使用$CI_COMMIT_REF_NAME. 那么(的重要部分)yml是:

\n
                      *staging* stage (pipeline 1)        *deploy* stage (pipeline 2)\n\n<open merge request> -> `building` job (and show)   ...   <merge> -> `deploying` job\n                             \xe2\x94\x82                                            \xe2\x96\xb2\n                             \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80 $BUILD_VERSION \xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x98\n
Run Code Online (Sandbox Code Playgroud)\n

但 API 请求被拒绝并显示“404 Not Found”。由于提交 SHA 不受支持$CI_COMMIT_BEFORE_SHA或者$CI_COMMIT_SHA也不起作用。

\n

使用needs

\n

更新:我在 gitlab 文档中找到了同一项目中管道之间的 Artifact downloads部分,这正是我想要的。但是:我无法让它工作。

\n

yml从文档中进行更少的复制后,看起来如下所示:

\n
building:\n    # ...\n    artifacts:\n        paths:\n            - build.env\n\ndeploying:\n    # ...\n    before_script:\n        - source build.env\n
Run Code Online (Sandbox Code Playgroud)\n

现在deploying作业立即失败,我收到以下错误横幅:

\n

此作业依赖于具有过期/删除工件的其他作业:\n请参阅 https://docs.gitlab.com/ee/ci/yaml/README.html#dependencies

\n

我尝试设置artifacts.expire_in = never(如图所示)但仍然遇到相同的错误。另外,在“设置” > “CI/CD” > “工件”中,选择“保留最近成功作业中的工件”。所以神器应该存在。我在这里错过了什么?根据文档这应该有效!

\n
\n

我希望有人能帮助我找到这份$BUILD_VERSION工作deploying。如果除了我尝试过的方法之外还有其他方法,我很高兴听到它们。提前致谢。

\n
\n

这个例子.gitlab-ci.yml

\n
deploying:\n    # ...\n    script:\n        - url=$CI_API_V4_URL/projects/jobs/artifacts/$CI_COMMIT_REF_NAME/download?job=building\n        - echo "Downloading $url"\n        - \'curl --header "JOB-TOKEN: ${CI_JOB_TOKEN}" --output $url\'\n        # ...\n
Run Code Online (Sandbox Code Playgroud)\n

Est*_*eis 9

根据 Gitlab 文档,应该可以通过 URL 下载任何作业的工件(如果它尚未过期)。

此外,您还可以使用 Gitlab API 从其他项目下载(未过期的)工件;您可以使用 Gitlab API 来标记作业的工件以保留无论过期策略,或删除工件。

但我自己还没有尝试过。

对于您的情况,假设“构建”和“部署”作业都在分支上运行main,您有望像这样传递工件。

如果您有其他方法可以在作业中找出deploying作业在哪个分支名称 Xbuilding上运行,那么您可以从分支 X 下载工件,而不是main像我下面那样总是从分支 X 下载工件。

# Assuming
# domain: example.com
# namespace: mygroup
# project: myproject

building:
    # on latest commit on `main`, because we need a predictable
    # branch name to save/retrieve the artifact.
    stage: staging
    script:
        - echo "BUILD_VERSION=1.2.3" > build.env
    artifacts:
        # 'paths', not 'reports'
        paths:
            - build.env

deploying:
    # after merge request is merged
    stage: deploy
    dependencies: 
        - building
    script:
        # could use ${CI_PROJECT_URL} to get https://example.com/mygroup/myproj
        - curl https://${CI_SERVER_HOST}/${CI_PROJECT_NAMESPACE}/${CI_PROJECT_NAME}/-/jobs/artifacts/main/raw/build.env?job=building > build.env
        - source build.env
        - echo $BUILD_VERSION  # should print '1.2.3'.

Run Code Online (Sandbox Code Playgroud)

文档的相关部分,包含链接和摘录:

通过 URL 访问分支或标签的最新作业工件

要浏览或下载分支的最新工件,请使用这两个 URL 之一。[我认为该/file/变体用于 Gitlab Pages 工件,但我不确定。——埃斯蒂斯]

  • 浏览文物:
    https://example.com/<namespace>/<project>/-/jobs/artifacts/<ref>/browse?job=<job_name>
  • 下载所有工件的 zip:
    https://example.com/<namespace>/<project>/-/jobs/artifacts/<ref>/download?job=<job_name>
  • 下载一个工件文件:
    https://example.com/<namespace>/<project>/-/jobs/artifacts/<ref>/raw/<path/to/file>?job=<job_name>
  • 下载一个工件文件(与 Gitlab Pages 相关?):
    https://example.com/<namespace>/<project>/-/jobs/artifacts/<ref>/file/<path>?job=<job_name>

例如,要下载包含domain gitlab.com、namespace gitlab-org、project gitlab、分支上的最新提交main、job coverage、文件路径的工件review/index.htmlhttps://gitlab.com/gitlab-org/gitlab/-/jobs/artifacts/main/raw/review/ index.html?job=覆盖率

配置设置:保留每个分支最近成功作业的工件

  • 该选项默认开启
  • AFAICT它保留了最新的工件
    • 每个活动分支或标签(又名“ref”);
    • 如果在该引用上运行多个管道,则最后一个管道的工件将覆盖较早管道生成的工件。
  • 所有其他文物仍然受制作它们的expire_in环境的控制。.gitlab-ci.yml

用于工作工件的 Gitlab API

使用 Gitlab API 的优点是,如果您可以获得正确的令牌,您还可以从其他项目下载工件。如果您的脚本在 Gitlab CI 中运行,您将需要数字项目 ID,即 $CI_PROJECT_ID。

要下载工件存档:

  • curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/${CI_PROJECT_ID}/jobs/artifacts/main/download?job=test"

要下载单个工件文件:

  • curl --location --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/${CI_PROJECT_ID}/jobs/artifacts/main/raw/some/release/file.pdf?job=pdf"

  • 谢谢您的回答。我前段时间确实尝试过这个,但没有成功。API 需要前一个作业的作业 ID,但我很难找到它。可能有一种方法可以获得给定分支的最后运行作业,但我不记得了。我已经通过标记提交解决了我的问题(标签可以被拉出,因此很容易获得) (3认同)
  • 是的,手动标记提交可能是实现此目的的最简单方法。这个答案的最终 API url 看起来像是自动解析为给定分支的最后运行作业,也许它们仍然可以工作?一旦我再次搞乱 Gitlab,我就会尝试一下。同上我下面的另一个答案:未经测试,但可能有效,而且到目前为止的研究可能会节省一些人的工作。如果我将来有时间进行测试,我会更新我的答案。 (2认同)

Pet*_*ter 6

您不能使用 CI/CD 在完全不相关的管道之间传递工件。事实上,“构建”是在定义合并请求的分支上运行,“部署”是在合并结果上运行,并不意味着“部署”只是下一个阶段。如果中间合并了另一个 MR 会怎样?如果出现合并冲突怎么办?

换句话说,你不能仅仅因为构建了开发分支就跳过了主分支上的“构建”。让“构建”始终发生,并将“部署”限制在主分支。在此设置中,您可以轻松地将工件从“构建”传递到“部署”。

或者,如果您希望合并事件实际更新主分支的版本状态,只需使用源代码控制的 VERSION 文件即可。这就是 git 的用途。当您合并时,main 将采用分支中的版本。如果不同的分支首先进入,您就必须解决冲突,正如您应该做的那样。