一个有意思的场景

项目经理:我们有个 Java 的新项目要开始了,需要你帮忙设置调试一下 CI/CD Pipeline。

DevOps 工程师:好的,没问题。

就这样,一周过去了。。

项目经理:新项目的 CI/CD Pipeline 咋样了啊,我看研发还是手动人肉编译部署呢,严重影响了效率。CI/CD Pipeline 遇到什么问题了吗?

DevOps 工程师:已经写了50% 了,正在写其他的,然后调试,再一周能好。

项目经理:WHT,一个 CI/CD Pipeline 为啥这么久?而且前面有类似的 Java 项目,有可用的 CI/CD Pipeline,直接抽象成 template,然后用 include 语法在新项目中引入,再根据新项目的特性做微调即可。分分钟能搞定的啊。

DevOps 工程师:什么 template?什么 include?还能这么玩?

项目经理:我乖。。。。。。

封装和复用是软件编程设计中常用的特性,能够在很大程度上提高代码整体的可读性、可维护性。对于 CI/CD Pipeline 来讲也可以用封装和复用来针对新项目快速构建起一套合适的 CI/CD Pipeline,节约时间的同时方便实现 Pipeline as Code,提升团队的端到端交付能力。

极狐GitLab include 语法

极狐GitLab CI/CD 是通过 YAML 语法来编写并存储到 YAML 文件中,可以将能够抽象出来的 CI/CD Pipeline(诸如单元测试、镜像构建、安全扫描等)代码存放到一个 YAML 文件,然后在其他项目的 .gitlab-ci.yml 中直接用 include 语法引入这个 YAML 文件即可。相当于用 include 一行代码实现了多行代码的功能,实现了 CI/CD Pipeline 的复用。这种做法有以下好处:

极狐GitLab include 的用法有以下四种,以引用不同来源的 YAML 文件:

引用同一项目中的流水线配置文件:

include:
  - local: '/templates/.include-template.yml'

引入同一极狐GitLab 实例中的流水线配置文件:

include
  - project: xiaomage/templates
  - ref: main
    file: docker-image-build-tamplates.yml

上述写法引入了 xiaomage/templates 项目下的 docker-image-build-tamplates.yml 配置文件。

引用位于其他远端仓库中的流水线配置文件:

include: 
  - remote: 'https://jihulab.com/xiaomage/teamplates/raw/main/docker-image-build-tamplates.yml'

极狐GitLab 内置了很多开箱即用的 template,可以直接引入使用。所有的模版存储在 lib/gitlab/ci/templates 下面。也可以在项目中添加 .gitlab-ci.yml 文件的时候选择:

include-template

上图所示,引入了容器镜像扫描的功能。下面的 Demo 中会演示扫描效果。可以用同样的方法引入极狐GitLab DevSecOps 中的其他安全测试手段。

极狐GitLab include 中的 Override

include 引入的流水线配置是“共性”的内容,在实际使用的过程中是“个性”的使用,这时候需要用 Override 的方式修改引入文件中的一些配置和参数。

比如,如果将镜像构建并推送至极狐GitLab 镜像仓库的流程定义为如下的流水线配置文件:

variables:
  IMAGE_TAG: 1.0.0
  
build:
  image: docker:latest
  stage: build
  script:
    - docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY
    - docker build -t $CI_REGISTRY_IMAGE:$IMAGE_TAG .
    - docker push $CI_REGISTRY_IMAGE:$IMAGE_TAG

项目的 .gitlab-ci.yml 文件内容如下:

variables:
  IMAGE_TAG: 2.0.0
  
include: 
  - remote: 'https://jihulab.com/xiaomage/teamplates/raw/main/docker-image-build-tamplates.yml'

则最终构建出来的镜像的 tag 是 2.0.0。是因为.gitlab-ci.ymlvariables::IMAGE_TAG 的值覆盖了引入的流水线配置中的 variables::IMAGE_TAG 。这种方式成为了“合并”(merging)。

极狐GitLab include 的嵌套使用

include 语法可以实现配置文件的嵌套使用,比如在项目的 .gitlab-ci.yml 内容如下:

include:
  - local: /.gitlab-ci/another-config.yml

/.gitlab-ci/another-config.yml 内部又使用了 include 引入了另外一个配置文件:

include:
  - local: /.gitlab-ci/config-defaults.yml

最终 /.gitlab-ci/config-defaults.yml 的内容为:

default:
  after_script:
    - echo "Job complete."

上面的写法实现了 include 的 2 级嵌套。

关于极狐GitLab include 的其他用法,可以参考极狐GitLab 官网文档

极狐GitLab include 实战

以 istio 中的 bookinfo为例来演示 include 的强大功能。 bookinfo 中有 6 个服务(details、productpage、ratings、reviews、mysql、mongodb),每个都包含一个 Dockerfile:

├── details
│   ├── Dockerfile
├── mongodb
│   ├── Dockerfile
├── mysql
│   ├── Dockerfile
├── productpage
│   ├── Dockerfile
├── ratings
│   ├── Dockerfile
└── reviews
    ├── reviews-wlpcfg
    │   ├── Dockerfile

如果完整构建这几个镜像,就需要执行 6 次镜像构建命令,在极狐GitLab CI/CD 中,构建镜像的 Job 如下:

build:
  image: docker:latest
  stage: build
  script:
    - docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY
    - docker build -t $CI_REGISTRY_IMAGE:1.0.0 .
    - docker push $CI_REGISTRY_IMAGE:1.0.0

因此,可以重复写 6 次来完成整个镜像的构建,比如:

stages:
  - build
  
ratings_image_build:
  image: docker:latest
  stage: build
  script:
    - docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY
    - docker build -t $CI_REGISTRY_IMAGE:1.0.0 .
    - docker push $CI_REGISTRY_IMAGE:1.0.0

productpage_image_build:
  image: docker:latest
  stage: build
  script:
    - docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY
    - docker build -t $CI_REGISTRY_IMAGE:1.0.0 .
    - docker push $CI_REGISTRY_IMAGE:1.0.0
    
details_image_build:
  image: docker:latest
  stage: build
  script:
    - docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY
    - docker build -t $CI_REGISTRY_IMAGE:1.0.0 .
    - docker push $CI_REGISTRY_IMAGE:1.0.0

其他三个重复,不再赘述。

上述写法除了冗余、重复并没有太多价值。可以将镜像构建的代码写入一个 YAML 文件,并且存储到极狐GitLab(比如 SaaS 上),存储路径为:https://jihulab.com/xiaomage/teamplates/raw/main/docker-image-build-tamplates.yml。然后在项目的 .gitlab-ci.yml 文件中使用 include 引入此文件即可:

variables:
  IMAGE_TAG: "1.0.0"

stages:
  - build

include: 
  - remote: 'https://jihulab.com/xiaomage/teamplates/raw/main/docker-image-build-tamplates.yml'

.image_build:
  image: docker:latest
  stage: build

ratings_image_build:
  extends: .image_build
  variables:
    BASIC_PATH: "samples/bookinfo/src/ratings"
    IMAGE_NAME: "ratings"

productpage_image_build:
  extends: .image_build
  variables:
    BASIC_PATH: "samples/bookinfo/src/productpage"
    IMAGE_NAME: "productpage"

details_image_build:
  extends: .image_build
  variables:
    BASIC_PATH: "samples/bookinfo/src/details"
    IMAGE_NAME: "details"
其他三个重复,不再赘述。

而且使用了 variables 来完成对于 include 引入的 template 文件中的 variables 进行了覆盖,这样只需要修改一次即可完成 6 个镜像的 tag 修改。触发 CI/CD Pipeline 构建,可以查看构建结果:

include-image-build

再进一步,加一个镜像扫描。极狐GitLab 本身支持对于容器镜像的扫描,详情可以查看过往文章云原生时代,保证容器镜像安全分几步?

只需以下两行代码即可开启容器镜像扫描:

include:
  - template: Security/Container-Scanning.gitlab-ci.yml

Security/Container-Scanning.gitlab-ci.yml 是极狐GitLab 提供的众多开箱即用的 template 中的一个。

因此将镜像构建与扫描都用 include 引入:

variables:
  CS_ANALYZER_IMAGE: registry.gitlab.cn/security-products/container-scanning/trivy:4
  SECURE_ANALYZERS_PREFIX: "registry.gitlab.cn/security-products"
  IMAGE_TAG: "1.0.0"

stages:
  - build
  - test

include: 
  - remote: 'https://jihulab.com/xiaomage/teamplates/raw/main/docker-image-build-tamplates.yml'
  - template: Container-Scanning.gitlab-ci.yml


.image_build:
  image: docker:latest
  stage: build

ratings_image_build:
  extends: .image_build
  variables:
    BASIC_PATH: "samples/bookinfo/src/ratings"
    IMAGE_NAME: "ratings"

productpage_image_build:
  extends: .image_build
  variables:
    BASIC_PATH: "samples/bookinfo/src/productpage"
    IMAGE_NAME: "productpage"

details_image_build:
  extends: .image_build
  variables:
    BASIC_PATH: "samples/bookinfo/src/details"
    IMAGE_NAME: "details"
...... 其他三个个重复,不再赘述......


container_scanning:
  image: "$CS_ANALYZER_IMAGE"
  stage: test
  variables:
    DOCKER_IMAGE: "$CI_REGISTRY_IMAGE/$IMAGE_NAME:$IMAGE_TAG"
    GIT_STRATEGY: fetch
    DOCKER_USER: "$CI_REGISTRY_USER"
    DOCKER_PASSWORD: "$CI_REGISTRY_PASSWORD"


container_scanning_ratings:
  extends: container_scanning
  variables:
    IMAGE_NAME: "ratings"


container_scanning_productpage:
  extends: container_scanning
  variables:
    IMAGE_NAME: "productpage"

container_scanning_details:
  extends: container_scanning
  variables:
    IMAGE_NAME: "details"
其他三个重复,不再赘述。

可以查看构建结果:

include-image-build-and-scan

在极狐GitLab 镜像仓库查看推送的镜像:

image-registry

在极狐GitLab 安全仪表盘查看镜像扫描结果:

security-dashboard

极狐GitLab CI/CD include 语法能够很好的解决 CI/CD Pipeline 代码的封装和复用,可以将共性的流程抽象出来封装成 template,存储在极狐GitLab 上,当有新项目需要设置 CI/CD Pipeline,只需要用 include 语法引入再根据新项目的实际情况做一些变动,即可完成新项目的 CI/CD Pipeline 设置,能够节省大量时间,而且便于维护。

60天免费试用极狐GitLab专业版

极狐GitLab不仅是源代码管理或CI/CD工具,它是一个覆盖完整软件开发生命周期和DevOps的开放式一体化平台。

企业版试用
售前咨询
联系电话
在线支持
预约演示