头图

项目经理:我们有个 Java 的新项目要开始了,需要你帮忙设置调试一下 CI/CD Pipeline
DevOps 工程师:好的,没问题

ONE WEEK LATER...

项目经理:新项目的 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 的复用。这种做法有以下好处:

  • 减少代码冗余。通过复用减少相同代码的复制使用,能有效减少代码冗余。
  • 减小变更范围。如果有配置需要修改时,只要在 include 的文件中(upstream)进行修改,就可以将变更传递到使用此文件(downstream)的地方。一个变更,多处生效。
  • 提高可维护性。将一个配置文件拆分成多个配置文件,避免形成“巨型”配置文件,修改时候无从下手,维护起来耗时耗力。

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

local

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

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

file

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

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

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

remote

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

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

template

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

上图所示,引入了容器镜像扫描的功能。下面的 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 构建,可以查看构建结果:

再进一步,加一个镜像扫描。极狐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"
其他三个重复,不再赘述。

可以查看构建结果:

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

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

极狐GitLab CI/CD include 语法能够很好的解决 CI/CD Pipeline 代码的封装和复用,可以将共性的流程抽象出来封装成 template,存储在极狐GitLab 上。

当有新项目需要设置 CI/CD Pipeline,只需要用 include 语法引入,再根据新项目的实际情况做一些变动,即可完成新项目的 CI/CD Pipeline 设置,能够节省大量时间,而且便于维护。


极狐GitLab
64 声望36 粉丝

极狐(GitLab) 以“核心开放”为原则,面向中国市场,提供开箱即用的开放式一体化安全DevOps平台——极狐GitLab。通过业界领先的优先级管理、安全、风险和合规性功能,实现产品、开发、QA、安全和运维团队间的高效协同...