如何从 gitlab CI 管道中推送到仓库?

Posted

技术标签:

【中文标题】如何从 gitlab CI 管道中推送到仓库?【英文标题】:How do I push to a repo from within a gitlab CI pipeline? 【发布时间】:2019-01-13 21:50:32 【问题描述】:

在我的 CI 管道中,我正在生成一个工件 public/graph.png,它可以可视化我的代码的某些方面。在后面的步骤中,我想从 CI 管道中将其提交给 repo。这是.gitlab-ci.yml的相关部分:

commit-graph:
  stage: pages
  script:
    - git config user.email "cipipeline@example.com"
    - git config user.name "CI Pipeline"
    - cd /group/project
    - mv public/graph.png .
    - git add graph.png
    - git commit -m "committing graph.png [ci skip]"
    - echo $CI_COMMIT_REF_NAME
    - git push origin HEAD:$CI_COMMIT_REF_NAME

当管道在 gitlab 中运行时失败:

$ git config user.email "cipipeline@dhgitlab.dunnhumby.co.uk" $ git config user.name "CI 管道" $ cd /组/项目 $ mv public/graph.png . $ git add graph.png $ git commit -m "提交 graph.png [ci 跳过]" [分离 HEAD 22a50d1] 提交 graph.png [ci 跳过] 1 个文件已更改,0 个插入 (+),0 个删除 (-) 创建模式 100644 graph.png $ 回声 $CI_COMMIT_REF_NAME jamiet/我的分公司 $ git push origin HEAD:$CI_COMMIT_REF_NAME 致命:无法访问“https://gitlab-ci-token:xxxxxxxxxxxxxxxxxxxx@example.com/group/project/project.git/”:服务器证书验证失败。 CAfile:/etc/ssl/certs/ca-certificates.crt CRLfile:无

不确定我做错了什么,并且对 SSL 了解不足,无法理解该错误。谁能给点建议?

顺便说一句,我们自己托管 gitlab。

【问题讨论】:

【参考方案1】:

我发现这个GitLab forum 链接很有帮助 根据用户的建议,您需要生成 SSH 密钥,将其与专用于该作业的新 GitLab 用户相关联,并将密钥添加到运行器。小缺点是您需要在 gitlab 中使用交换源作为原始 ssh 源(而不是在作业中使用的沙盒源),这导致提交者被更改为提到的新帐户,而不是触发管道的人。 来源链接:

# for your information
whoami
printenv

# we need to extract the ssh/git URL as the runner uses a tokenized URL
export CI_PUSH_REPO=`echo $CI_REPOSITORY_URL | perl -pe 's#.*@(.+?(\:\d+)?)/#git@\1:#'`

# runner runs on a detached HEAD, create a temporary local branch for editing
git checkout -b ci_processing
git config --global user.name "My Runner"
git config --global user.email "runner@gitlab.example.org"
git remote set-url --push origin "$CI_PUSH_REPO"

# make your changes
touch test.txt

# push changes
# always return true so that the build does not fail if there are no changes
git push origin ci_processing:$CI_COMMIT_REF_NAME || true

仅使用当前版本的 GitLab,您需要更改源变量名称,如下所示:

export CI_PUSH_REPO=`echo $CI_REPOSITORY_URL | perl -pe 's#.*@(.+?(\:\d+)?)/#git@\1:#'`

【讨论】:

【参考方案2】:

您可以将CI_SERVER_CLS_CA_FILE 添加到sslCAInfo git config。

checkout alchemy:
    stage: prepare
    script:
        - git config --global "http.$CI_SERVER_URL.sslCAInfo" "$CI_SERVER_TLS_CA_FILE"
        - git clone https://gitlab-ci-token:$CI_JOB_TOKEN@$CI_SERVER_HOST/sparklemuffin/alchemy.git

从管道克隆不同的存储库时,我遇到了同样的问题。它因服务器证书验证失败而失败。我不明白为什么会发生这种情况,Gitlab 本身克隆了存储库而没有任何问题。所以我设置CI_DEBUG_TRACE: "true" 并发现,Gitlab 创建这个文件配置 git 使用它来初始克隆存储库。由于某种原因,此配置稍后不再可用。 CI_SERVER_TLS_CA_FILE 仍然存在。

【讨论】:

我使用了类似的解决方案:我将export GIT_SSL_CAINFO="$CI_SERVER_TLS_CA_FILE" 放在脚本的顶部。它doesn't work if you put it under variables.【参考方案3】:

解决了。在推送之前发出git config --global http.sslverify "false" 解决了该特定问题(它暴露了另一个问题,但这是另一个线程:))

【讨论】:

好问题,但这个答案是-1,因为它鼓励避免问题而不是解决问题。现在有很多获得免费 SSL 证书的好方法,没有理由不解决 SSL 问题而不是完全禁用它。【参考方案4】:

我可以根据 tsr 的回答 https://***.com/a/57800614/5269825 与选定用户一起从 Gitlab-CI 提交,只需稍作更改:

# set remote URL to https://oauth2:<AccessToken>@server.com/project.git
CI_PUSH_REPO=`echo "$CI_REPOSITORY_URL $ACCESS_TOKEN_PARAM" | sed 's/^.*\(@.*\)\s\(.*\)/https:\/\/oauth2:\2\1/g'`
git config http.sslverify false
git remote set-url --push origin "$CI_PUSH_REPO"
git config user.name "Token Owner"
git config user.email "tokenowner@email.com"

# runner runs on a detached HEAD, create a temporary local branch for editing
git checkout -b ci_processing
# make your changes

# push changes
# always return true so that the build does not fail if there are no changes
git push origin ci_processing:$CI_BUILD_REF_NAME || true

ACCESS_TOKEN_PARAM 必须在项目的 CI/CD 变量配置中进行配置。

使用 Oauth2 和 Access Token 的想法来自 https://***.com/a/52074198/5269825 和 https://***.com/a/52154378/5269825。

此外,推送更改可能会触发新管道!

【讨论】:

【参考方案5】:

仍然需要一些手指俯卧撑,但我在日常工作中使用了一种从其自己的 CI 推送到存储库的不那么脆弱的方法。它直接从一个分离的头部推送到 master:

    生成 RSA 密钥并将其添加为具有写入权限的 Project Deploy Key(公共部分)。 将私有部分作为SSH_PUSH_KEY 从您的项目设置内部放入您的 CI/CD 变量中。确保将其设置为受保护。 添加一个 CI_KNOWN_HOSTS 变量,其中包含您的 GitLab 实例的 SSH 指纹(还记得 ssh 在您第一次尝试连接到主机时询问您吗?那个。)。

使用ssh-keyscan &lt;gitlab-host&gt; 获取它。它看起来类似于:

my.gitlab.instance.com ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEArlUMUmNj59PpoLyy4EsKbwhPUfXxuAzFN7dMKDXVvKMmN8344HqQV1tRx6fcmH+0BXK1JAP4f10V0VnYti3e1c5f9dhpl8pIqKLMJgdGDq3MLqjihL3bp5xm8nDsPTm5FoEPPYK1I3M2wr18pBB19evz64NHrK5R/HO5LyTrybVasFumt8cZoH6crnCFgfQWV1mHAG3j41Q0z4yxu6g8zBWESZcVVn90HxQH7+LDHx11122233344491MQGl5fZcKqVWsWQVEssaK87iBsWUxvsuoeVUrj4YRcmbi6F4+ZZZZZZZwwww3ZboWsSWxTk5ESR6WWHccBm8GQflXyY3ZQ==
    .gitlab-ci.yml 中设置您的工作,如下所示。适当地设置 stageresource_group 选项 - 如果没有后者,您可能会遇到竞争条件。另外,请确保正确设置only,否则您的 CI 可能会自行触发:
"This CI job pushes to its own repo":
    stage: my_push_stage
    resource_group: this_option_comes_handy_when_pushing
    only:
        - triggers
    before_script:
        - mkdir ~/.ssh/
        - echo "$CI_KNOWN_HOSTS" > ~/.ssh/known_hosts
        - echo "$SSH_PUSH_KEY" > ~/.ssh/id_rsa
        - chmod 600 ~/.ssh/id_rsa
        - git config user.email "ci@example.com"
        - git config user.name "CI"
        - git remote remove ssh_origin || true  # Local repo state may be cached
        - git remote add ssh_origin "git@$CI_SERVER_HOST:$CI_PROJECT_PATH.git"
    script:
        - touch "xyz"  # Make an edit
        - git add "xyz"
        - git commit -m "My CI commit"
        - git push ssh_origin HEAD:master  # ❗ this pushes to master, 
                                           # use $CI_BUILD_REF_NAME if you want to push to current branch
        - git tag MyCiTag  # If you need to add a tag you can do that too
        - git push --tags ssh_origin

【讨论】:

【参考方案6】:

您可以尝试实时获取,而不是声明 CI_KNOWN_HOST:

- 'which ssh-agent || ( apt-get update -y && apt-get install openssh-client -y )'
- ssh-keyscan -t rsa $CI_SERVER_HOST >> ~/.ssh/known_hosts

【讨论】:

【参考方案7】:

在我的情况下,deploy keys 选项是 Gitlab Shell Runner 的最佳选择(与个人令牌或 CI 令牌相比 - 仅支持基本身份验证)。如果有人正在努力从 Gitlab CI 推送,这可以通过与 Gitlab 服务器共享运行器的公钥来完成

【讨论】:

【参考方案8】:

这是一个截至今天的工作示例 环境:k8s gitlab:13.x gitlab 运行器:13.x 这个名为 convert 的工作的目标:- 将 excel 文件转换为 json 文件并提交和更新 repo 的分支。

convert:
  variables:
    REPO: "gitlab.com/group/myproject.git" # example
    BRANCH: "BRANCHNAME" # example
    # recommended to store the following as project variables to hide secrets away from the gitlab ci file.
    GITLAB_USER_ID: "gitlab_user" # example
    CI_USERNAME: "gitlab_user" # example
    CI_PUSH_TOKEN: "<api token from gitlab" # example
    GITLAB_USER_EMAIL: "gitlab_user@company.com" # example
  stage: convert
  image:
    name: python:3.7-buster
    entrypoint: ["/bin/ash"]
  before_script:
    - pip3 install openpyxl
    - ls -altr
  script:
    - echo 'converting excel to json'
    - python excel2json.py
    - git remote set-url origin https://$CI_USERNAME:$CI_PUSH_TOKEN@$REPO
    - git config --global user.email '$GITLAB_USER_EMAIL'
    - git config --global user.name '$GITLAB_USER_ID'
    - git add -A && git commit -m 'added/updated json files'
    - git push origin HEAD:$BRANCH

注意:CI_USERNAME == GITLAB_USER_ID。就我而言,两者都是一样的。

【讨论】:

【参考方案9】:

另一种方式:

    创建专用 Gitlab 帐户 将包含密码的 CI/CD 变量 GIT_CICDUSER_PASSWORD 添加到运行管道的主帐户内的项目中

然后一个工作可能看起来像:

task_requiring_a_push:
  stage: some-stage
  variables:
    GIT_STRATEGY: none
  script:
    - git config --global user.email "user@mail.com"
    - git config --global user.name "CI/CD User"
    - git clone https://<dedicated_gitlab_user_username>:$GIT_CICDUSER_PASSWORD@gitlab.com/$CI_PROJECT_PATH .
    - git checkout $CI_COMMIT_REF_NAME
    - # do something
    - git add *
    - git commit -m "message"
    - git push --push-option=ci.skip origin $CI_COMMIT_REF_NAME
only:
    - release-*

【讨论】:

以上是关于如何从 gitlab CI 管道中推送到仓库?的主要内容,如果未能解决你的问题,请参考以下文章

如何从 GitLab CI 管道的工作发送电子邮件?

剪切新版本时如何触发 GitLab CI/CD 管道?

如何在 GitLab CI 的管道中将变量的值从一个作业传递到下一个作业?

已经是最新的 gitlab 管道 ***

gitlab CI 管道检查代码格式

如何让 Gitlab CI 管道始终运行一些作业,而其他作业仅在合并请求上运行?