在 Gitlab 的两步 Dockerfile 中传递 --build-arg 或使用环境变量

man*_*mat 5 continuous-integration environment-variables gitlab docker next.js

我的最小测试项目布局如下所示。

\n\n
\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 deployment\n\xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 build.sh\n\xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 nginx\n\xe2\x94\x82\xc2\xa0\xc2\xa0     \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 nginx.conf\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 Dockerfile\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 next.config.js\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 package.json\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 package-lock.json\n\xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 pages\n    \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 _app.js\n    \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 index.js\n
Run Code Online (Sandbox Code Playgroud)\n\n

Dockerfile 的内容:

\n\n
FROM node as build-stage\n\nARG K8S_SECRET_PUB\nENV K8S_SECRET_PUB ${K8S_SECRET_PUB}\n\nARG SRV\nENV SRV ${SRV}\n\nWORKDIR /app\nCOPY package*json /app/\nRUN npm install --production\nCOPY ./ /app/\nRUN npm run export\n\n\nFROM nginx:1.15-alpine\n\nRUN rm /etc/nginx/nginx.conf\nCOPY --from=build-stage /app/out /www\nCOPY deployment/nginx/nginx.conf /etc/nginx/\nEXPOSE 5000\n
Run Code Online (Sandbox Code Playgroud)\n\n

目标是将环境变量 K8S_SECRET_PUB 和 SRV 传递给构建过程。npm run export执行next build && next export以获取 nginx 服务器应提供服务的静态文件。

\n\n

next.config.js 的内容:

\n\n
require(\'dotenv\').config();\n\nmodule.exports = {\n  serverRuntimeConfig: {\n    srv: process.env.SRV\n  },\n  publicRuntimeConfig: {\n    pub: process.env.K8S_SECRET_PUB\n  }\n};\n
Run Code Online (Sandbox Code Playgroud)\n\n

pages/_app.js 的内容:

\n\n
import App from \'next/app\';\nimport getConfig from \'next/config\';\n\nconst { serverRuntimeConfig, publicRuntimeConfig } = getConfig();\n\nclass MyApp extends App {\n  render() {\n    return (\n      <div>\n        <h1>\n          {serverRuntimeConfig.srv || \'SRV not accessible from client :p\'}\n        </h1>\n        <h1>{publicRuntimeConfig.pub || \'PUB not set\'}</h1>\n      </div>\n    );\n  }\n}\n\nexport default MyApp;\n
Run Code Online (Sandbox Code Playgroud)\n\n

当通过本地构建docker镜像时docker build --build-arg K8S_SECRET_PUB=puppy --build-arg SRV=serverval -t my_image .,我可以通过启动容器docker run -p 5000:5000 my_image

\n\n

访问正在运行的容器有预期的结果。检查文件系统进一步表明,传递的构建参数已被拾取,并且文件已相应写入。

\n\n

在本地测试 docker 镜像

\n\n

然而,当我将这段代码推送到Gitlab时,部署的nginx看起来像这样:

\n\n

在 Gitlab 上运行

\n\n

我想要完成的是通过 Gitlab UI 在“设置”->“CI/CD”下定义的环境变量,并在 Dockerfile 中定义的构建阶段中使用它们。由于我们对 Auto Dev 很满意,因此我们尚未创建并签入 .gitlab-ci.yml 文件。

\n\n
\n\n

更新#1

\n\n

经过一番修改后,我现在可以访问环境变量了,但失去了 Auto DevOps 的便利性。

\n\n

我添加了一个deployment/build.sh包含以下内容的内容:

\n\n
#!/bin/sh\ndocker build --build-arg K8S_SECRET_PUB="${K8S_SECRET_PUB}" --build-arg SRV="${SRV}" -t my_image .\n
Run Code Online (Sandbox Code Playgroud)\n\n

我也开始了其中.gitlab-ci.yml包含这个:

\n\n
stages:\n    - build\n    - review\n    - deploy\n    - clean\n\nimage: docker:latest\n\nservices:\n    - docker:dind\n\nbuild:\n    stage: build\n    script:\n        - sh ./deployment/build.sh\n        - mkdir image\n        - docker save my_image > image/my_image.tar\n    artifacts:\n        paths:\n            - image\n
Run Code Online (Sandbox Code Playgroud)\n\n

将存储库推送到 Gitlab 后,管道成功,我可以下载工件、解压缩它、通过加载它docker load -i image/my_image.tar并运行它。果然,页面加载了 Gitlab CI/CD UI 中定义的变量。\n但是,现在我已经丢失了部署过程的所有其他步骤(这是我不想这样做的主要原因)首先编写 .gitlab-ci.yml )。

\n\n
\n\n

更新#2

\n\n

使用 Auto DevOps 模板,我在https://gitlab.com/gitlab-org/gitlab-ce/blob/master/lib/gitlab/ci/templates/Auto-DevOps.gitlab-ci.yml找到了我制作的模板这些变化:

\n\n
    \n
  • 注释掉该行- template: Jobs/Build.gitlab-ci.yml
  • \n
  • 将 alpine 替换为 docker 镜像
  • \n
  • 添加CODE_QUALITY_DISABLED: "true"到变量部分,因为代码质量检查花费的时间太长
  • \n
  • 添加服务并构建上述我之前尝试的部分
  • \n
\n\n

现在,我陷入了审核阶段。

\n\n
Application should be accessible at: http://*my_image_url*\nWaiting for deployment "review-branchname-abcxyz" rollout to finish: 0 of 1 updated replicas are available...\n
Run Code Online (Sandbox Code Playgroud)\n

man*_*mat 2

在更新 #2 之后,我做了以下更改以使其正常工作。

重写.gitlab-ci.yml:

image: docker:latest

variables:
  CI_APPLICATION_TAG: $CI_COMMIT_SHA
  CI_APPLICATION_REPOSITORY: $CI_REGISTRY_IMAGE/$CI_COMMIT_REF_SLUG
  CODE_QUALITY_DISABLED: "true"

  KUBERNETES_VERSION: 1.11.9
  HELM_VERSION: 2.13.1

  DOCKER_DRIVER: overlay2

  ROLLOUT_RESOURCE_TYPE: deployment

stages:
  - build
  - test
  - deploy # dummy stage to follow the template guidelines
  - review
  - dast
  - staging
  - canary
  - production
  - incremental rollout 10%
  - incremental rollout 25%
  - incremental rollout 50%
  - incremental rollout 100%
  - performance
  - cleanup

include:
#  - template: Jobs/Build.gitlab-ci.yml
  - template: Jobs/Test.gitlab-ci.yml
  - template: Jobs/Code-Quality.gitlab-ci.yml
  - template: Jobs/Deploy.gitlab-ci.yml
  - template: Jobs/Browser-Performance-Testing.gitlab-ci.yml
  - template: Security/DAST.gitlab-ci.yml
  - template: Security/Container-Scanning.gitlab-ci.yml
  - template: Security/Dependency-Scanning.gitlab-ci.yml
  - template: Security/License-Management.gitlab-ci.yml
  - template: Security/SAST.gitlab-ci.yml

# Override DAST job to exclude master branch
dast:
  except:
    refs:
      - master

services:
    - docker:dind

build:
    stage: build
    script:
        - sh ./deployment/build.sh
Run Code Online (Sandbox Code Playgroud)

使用了我找到的模板中的更多内容并重写了deployment/build.sh:

if ! docker info &>/dev/null; then
  if [ -z "$DOCKER_HOST" -a "$KUBERNETES_PORT" ]; then
    export DOCKER_HOST='tcp://localhost:2375'
  fi
fi

if [[ -n "$CI_REGISTRY_USER" ]]; then
  echo "Logging to GitLab Container Registry with CI credentials..."
  docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" "$CI_REGISTRY"
fi

if [[ -f Dockerfile ]]; then
  echo "Building Dockerfile-based application..."
else
  echo "Building Heroku-based application using gliderlabs/herokuish docker image..."
  cp /build/Dockerfile Dockerfile
fi

docker build --build-arg K8S_SECRET_PUB="${K8S_SECRET_PUB}" --build-arg SRV="${SRV}" --tag "$CI_APPLICATION_REPOSITORY:$CI_APPLICATION_TAG" .

docker push "$CI_APPLICATION_REPOSITORY:$CI_APPLICATION_TAG"
Run Code Online (Sandbox Code Playgroud)