容器 DevOps: Gitlab CI
当下 Gitlab 具备了 CI/CD 能力。 其 CI 流水线 主要定义在源代码根目录的 .gitlab-ci.yml 的文件里。这篇文章主要描述了如何编写 GitOps 方式的 gitlab-ci 文件。
示例描述
本文使用了 Gitlab SaaS 版本。SaaS 版本的 CI 每个月有 400min 的免费的额度。
本文的源代码在:https://gitlab.com/cloudbeer/gateway,这是一个 Spring Cloud gateway 应用。
ci 的过程包括:
- 编译 java 源码
- 打包 docker 镜像,并上传到镜像仓库(本文使用的是 AWS ECR 仓库)
- 修改部署目标脚本的镜像版本
完成这几个步骤之后,argocd 会接手 cd 的工作。
.gitlab-ci.yml 代码拆解
环境变量
环境变量的定义有三种方式:
- 全局定义:左侧菜单 Settings -> CI/CD, 页面上 Variables 部分,展开 Expand。
- 在 yaml 文件里直接定义:参见下面的代码。
- 手工指定:在每次手工启动流水线时,可以填写变量。
variables:
DOCKER_DRIVER: overlay
DOCKER_REGISTRY: 00000000.dkr.ecr.us-east-2.amazonaws.com
AWS_DEFAULT_REGION: us-east-2
DOCKER_HOST: tcp://docker:2375
stages 的定义
首先定义几个 大的步骤:
stages:
- build
- package
- deploy
然后在各个步骤详情里,可以把当前的步骤进行分类,就像这样:
do-something:
stage: build
image: alpine
script: "sleep 300"
源码编译
对于编译型语言,需要将源代码进行编译,本示例中就是需要将 java 源代码编译打包成 jar 包。
maven-build:
image: maven:latest
stage: build
script: "mvn package"
artifacts:
paths:
- target/*.jar
- 编译时使用 maven 这个镜像
- 运行的指令是
mvn package
- 编译的结果指定为 target 目录下的所有 jar 文件,gitlab 会将 artifacts 上传,供给后面的步骤使用。
Docker 镜像打包上传
docker-build:
image:
name: amazon/aws-cli
entrypoint: [""]
services:
- docker:dind
stage: package
before_script:
- amazon-linux-extras install docker
script:
- docker build -t $DOCKER_REGISTRY/$CI_PROJECT_NAME:$CI_COMMIT_SHORT_SHA .
- aws ecr get-login-password | docker login --username AWS --password-stdin $DOCKER_REGISTRY
- docker push $DOCKER_REGISTRY/$CI_PROJECT_NAME:$CI_COMMIT_SHORT_SHA
- 打包完成后需要上传到 ecr,而 ecr 依赖了 aws cli,所以使用了 aws_cli 的镜像包。在执行过程中,还需要将 AWS 的 AKSK 配置到环境变量。
- 在 before_script 里,在 aws_cli 镜像里安装 docker,此时使用了 dind (docker in docker) 模式。
- 在 docker build 的过程中,使用了 git 的 commiot sha 作为版本号。 CI_COMMIT_SHORT_SHA 是 gitlab 的内置环境变量。
gitlab 的 dind 可以参考这个:https://docs.gitlab.com/ee/ci/docker/using_docker_build.html
gitlab 内置环境变量参考:https://docs.gitlab.com/ee/ci/variables/predefined_variables.html
部署
在本示例中,采用了 gitops 的方式,将 CI 和 CD 完全解耦,CI 只需要做到构建完成,并更新部署代码仓库就可以了。剩下的工作交由 CD 来完成。
yaml-change:
stage: deploy
image: line/kubectl-kustomize
before_script:
- apk add git
- git clone https://cloudbeer:${GITHUB_PWD}@github.com/cloudbeer/cd-script.git "/${CI_COMMIT_SHA}"
- git config --global user.email "cloudbeer@gmail.com"
- git config --global user.name "gitlab-robot"
script:
- cd "/${CI_COMMIT_SHA}/gateway"
- kustomize edit set image $DOCKER_REGISTRY/$CI_PROJECT_NAME:$CI_COMMIT_SHORT_SHA
- cat kustomization.yaml
after_script:
- cd "/${CI_COMMIT_SHA}"
- git add .
- git commit -m "[skip ci]updating image $DOCKER_REGISTRY/$CI_COMMIT_SHORT_SHA"
- git push origin main
- 镜像上传到镜像仓库后,就可以去修改部署代码了。本示例将部署代码放到了 github,您可以将部署代码放到任意 git 仓库。但在 gitops 模式下,部署脚本不建议和业务源代码放到一起。
- 本示例使用了 kustomize 来更新部署,kustomize 也被 argocd 默认支持。
- 过程是:将部署代码从 git 仓库拉回本地,通过 kustomize 命令修改了 image 的地址,修改完成后推回 git 仓库。
GITHUB_PWD 需要配置一个 带有 scope 的 token,请到 https://github.com/settings/tokens 配置。
完整的代码如下:
variables:
DOCKER_REGISTRY: cloudbeer
DOCKER_DRIVER: overlay
DOCKER_HOST: tcp://docker:2375
stages:
- build
- package
- deploy
maven-build:
image: maven:latest
stage: build
script: "mvn package"
artifacts:
paths:
- target/*.jar
docker-build:
image: docker:20
stage: package
services:
- docker:dind
before_script:
- docker info
script:
- docker build -t $DOCKER_REGISTRY/$CI_PROJECT_NAME:$CI_COMMIT_SHORT_SHA .
- echo $DOCKER_PASS | docker login -u$DOCKER_USER --password-stdin
- docker push $DOCKER_REGISTRY/$CI_PROJECT_NAME:$CI_COMMIT_SHORT_SHA
yaml-change:
stage: deploy
image: line/kubectl-kustomize
before_script:
- apk add git
- git clone https://cloudbeer:${GITHUB_PWD}@github.com/cloudbeer/cd-script.git "/${CI_COMMIT_SHA}"
- git config --global user.email "cloudbeer@gmail.com"
- git config --global user.name "gitlab-robot"
script:
- cd "/${CI_COMMIT_SHA}/gateway"
- kustomize edit set image $DOCKER_REGISTRY/$CI_PROJECT_NAME:$CI_COMMIT_SHORT_SHA
- cat kustomization.yaml
after_script:
- cd "/${CI_COMMIT_SHA}"
- git add .
- git commit -m "[skip ci]updating image $DOCKER_REGISTRY/$CI_COMMIT_SHORT_SHA"
- git push origin main
完整代码与文章正文会稍有出入,改用了公开的 github 和 docker hub 来存储 部署文件 和 镜像。
本项目的运行和测试过程
克隆项目
git clone https://gitlab.com/cloudbeer/gateway.git
上传到您自己的 gitlab 仓库,并启动自动构建。
修改构建脚本,将 部署仓库,镜像仓库分别改成您自己的地址。并将相关账号配置到 Variables 里。
改动代码后,如果您不想让 gitlab 自动启动 pipeline,在 commit 信息里加上 [skip ci]xxxx
即可。
观察构建过程,成功后,可以看到镜像仓库中增加了 版本(tag), 部署仓库中的 gateway 目录里的 kustomization.yaml 被修改。
本文涉及的三个外部仓库,这三个仓库均为 public:
业务源代码:https://gitlab.com/cloudbeer/gateway