cicd

Posted Daeeman

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了cicd相关的知识,希望对你有一定的参考价值。

使用docker从0到1搭建

安装gitlab

sudo docker run --detach \\
  --hostname gitlab.mczaiyun.top \\
  --publish 443:443 --publish 80:80 --publish 222:22 \\
  --name gitlab \\
  --restart always \\
  --volume /srv/gitlab/config:/etc/gitlab \\
  --volume /srv/gitlab/logs:/var/log/gitlab \\
  --volume /srv/gitlab/data:/var/opt/gitlab \\
  gitlab/gitlab-ce:latest

hostname 域名 或 ip

publish 端口映射

restart 重启方式

gitlab/gitlab-ce:latest 镜像名称

volume 目录挂载

安装gitlab runner

sudo docker run -d --name gitlab-runner --restart always \\
  -v /srv/gitlab-runner/config:/etc/gitlab-runner \\
  -v /var/run/docker.sock:/var/run/docker.sock \\
  gitlab/gitlab-runner:latest 
docker run --rm -v /srv/gitlab-runner/config:/etc/gitlab-runner gitlab/gitlab-runner register \\
  --non-interactive \\
  --executor "docker" \\
  --docker-image alpine:latest \\
  --url "http://gitlab.mczaiyun.top/" \\
  --registration-token "vtizNrFzQKFacsSMxsJX" \\
  --description "first-register-runner" \\
  --tag-list "test-cicd1,dockercicd1" \\
  --run-untagged="true" \\
  --locked="false" \\
  --access-level="not_protected" 

.gitlab-ci.yml关键词完整解析

使用GitLab自带的流水线,必须要定义流水线的内容,而定义内容的文件默认叫做.gitlab-ci.yml,使用yml的语法进行编写。

目前任务关键词有28个,全局的关键词有10个,两者重叠的有很多。

任务的28个关键词分别是

可用于工作的关键字是:

关键词 描述
after_script 覆盖作业后执行的一组命令。
allow_failure 允许作业失败。失败的作业不会导致管道失败。
artifacts 成功时附加到作业的文件和目录列表。
before_script 覆盖在作业之前执行的一组命令。
cache 应在后续运行之间缓存的文件列表。
coverage 给定作业的代码覆盖率设置。
dast_configuration 在作业级别使用来自 DAST 配置文件的配置。
dependencies 通过提供要从中获取工件的作业列表来限制将哪些工件传递给特定作业。
environment 作业部署到的环境的名称。
except 控制何时不创建作业。
extends 此作业继承自的配置条目。
image 使用 Docker 镜像。
include 包括外部 YAML 文件。
inherit 选择所有作业继承的全局默认值。
interruptible 定义当新的运行变得多余时是否可以取消作业。
needs 在阶段排序之前执行作业。
only 控制何时创建作业。
pages 上传作业的结果以与 GitLab 页面一起使用。
parallel 应该并行运行多少个作业实例。
release 指示跑步者生成一个释放对象。
resource_group 限制作业并发。
retry 在失败的情况下可以自动重试作业的时间和次数。
rules 用于评估和确定作业的选定属性以及它是否已创建的条件列表。
script 由运行程序执行的 Shell 脚本。
secrets CI/CD 隐藏作业所需的信息。
services 使用 Docker 服务镜像。
stage 定义作业阶段。
tags 用于选择跑步者的标签列表。
timeout 定义优先于项目范围设置的自定义作业级别超时。
trigger 定义下游管道触发器。
variables 在作业级别定义作业变量。
when 何时运行作业。

不可用的工作名称

您不能将这些关键字用作作业名称:

  • image
  • services
  • stages
  • types
  • before_script
  • after_script
  • variables
  • cache
  • include
script, after_script, allow_failure, artifacts, before_script, cache, coverage, dependencies, environment, except, extends, image, include, interruptible, only, pages, parallel, release, resource_group, retry, rules, services, stage, tags, timeout, trigger, variables, when

全局的关键词

image,services,before_script,after_script,tags,cache,artifacts,retry,timeout,interruptible

最常任务中最常用的是这七个

script,artifacts,stage, when,tags,image,cache,

下面我先来详细介绍一下这七个关键词,知道了这个七个关键词,一般的流水线随随便便拿下,

1. script

任务要执行的shell脚本内容,内容会被runner执行,在这里,你不需要使用git clone ....克隆当前的项目,来进行操作,因为在流水线中,每一个的job的执行都会将项目下载,恢复缓存这些流程,不需要你再使用脚本恢复。你只需要在这里写你的项目安装,编译执行,如
npm install 另外值得一提的是,脚本的工作目录就是当前项目的根目录,所有可以就像在本地开发一样。此外script可以是单行或者多行

单行脚本

job:
  script: npm install

多行脚本

job:
  script:
    - npm config set sass_binary_site https://npm.taobao.org/mirrors/node-sass/
    - npm install --registry=http://registry.npm.taobao.org

script是一个job的必填内容,不可或缺。一个job最少有二个属性,一个是job name任务名称, 一个就是script

stage(阶段)

stage 是阶段的意思,用于归档一部分的job,按照定义的stage顺序来执行。默认的stage有build,test,deploy, 此外还有两个特殊的.pre 和 .post, job执行的顺序不是按照编写的顺序,大体上是按照stage定义的顺序来执行的,注意是大体,也有例外的情况。

如果文件中stages没有定义.gitlab-ci.yml,那么默认的流水线阶段是:

stages项目的顺序定义了作业的执行顺序:

  • 同一阶段的作业并行运行。
  • 下一阶段的作业在上一阶段的作业成功完成后运行。

例如:

stages:
  - build
  - test
  - deploy
  1. 中的所有作业build并行执行。
  2. 如果所有作业都build成功,则test作业并行执行。
  3. 如果所有作业都test成功,则deploy作业并行执行。
  4. 如果所有作业都deploy成功,则管道标记为passed

如果任何作业失败,管道将被标记为failed并且后续阶段的作业不会启动。当前阶段的作业不会停止并继续运行。

如果作业未指定stage,则为该作业分配test阶段。

.pre =>`build=>test=>deploy=>.post

//最简单,如果不指定stages,默认为test阶段
job1:
	script:
		-echo \'my prejob\'
//stages划分阶段执行,先执行job1=>job2=>job3
stages:
	- stage1
	- stage2
	- stage3
job1:
	stage:stage1
	script:
		- echo \'my stage1\'
job2:
	stage:stage2
	script:
		- echo \'my stage2\'
job3:
	stage:stage3
	script:
		- echo \'my stage3\'
//=====================
stages:
	- linecode
  - install
  - build
  - deploy
	- clean




job1:
	stage:build
	script:
		- echo \'my buildjob\'

job1:
	stage:test
	script:
		- echo \'my testjob\'


由于build在test之前所有会指向job1这个任务,后指向job0任务

retry

test:
	script:rspec
	retry:2:  //运行失败之后,最多再尝试2次
  	max:2
		when:runner_system_failure //限定触发失败时机

image

指定一个基础Docker镜像作为基础运行环境,经常用到的镜像有node nginx docker

job:
  image: node:latest
  script: npm install

在上面这个任务中,如果不指定image: node:latest 执行下面的npm install时会报错,找不到npm的命令。image的作用就是给当前任务或者当前流水线设置一个基础环境,有可能是nodejs,也有可能是java, go, php,可以设置当前流水线的,也可以设置当前任务的。

artifacts

翻译出来这个单词就是制品,一个成品,作用是将流水线过程中的一些文件,文件夹,打包压缩,提供一个外链供人下载,另外还能在后续的job中缓存。
比如我们构建一个前端项目后将dist目录做成一个压缩包,

build:
  script:
    - npm run build
  artifacts:
    paths:
      - dist/

在这个任务后面运行的任务会自动恢复这个制品,意味着你不用再执行npm run build来获取编译后的dist文件了,在安卓,ios打包的时候,非常有用,因为流水线最终输出的就是一个可下载,可安装的应用。paths 是用来指定将那些文件,目录放入制品中,也可以使用exclude关键词,将那些目录,文件排除,支持正则表达式。

此外还有以下几个属性

  • paths 文件路径
  • exclude 排除的文件
  • name 制品名称
  • expose_as 在UI页面导出的名称
  • untracked 布尔类型,是否将git忽略的文件加到制品中
  • when on_success;on_failure;always 何时上传制品
  • expire_in 过期时间默认30天
  • reports 收集测试报告
- build:
    script:
   		- npm run build
    artifacts:
       paths:
     			- dist/
       exclude:
     			- binaries/**/*.o
       expose_as: \'artifact 1\'
       name: "$CI_COMMIT_REF_NAME"
       untracked: false
       expire_in: 2 hrs 20 min
       when: on_failure

tags

tags 关键词是用于指定Runner,tags的取值范围是在该项目可见的runner tags中,可以在Setting =>CI/CD => Runner 中查看的到。要知道,改属性可以设置全局,不设置则默认使用公有Runner去执行流水线。每个任务可以指定一个Runner,可以指定多个标签,但runner却只能一个。以一个为准。tags是在我们注册Runner是配置的,后续也可以更改。

install:
  tags:
   			- hello-vue
     		- docker
  script:
        - npm config set sass_binary_site https://npm.taobao.org/mirrors/node-sass/
        - npm install --registry=http://registry.npm.taobao.org

cache

缓存是将当前工作环境目录中的一些文件,一些文件夹存储起来,用于在各个任务初始化的时候恢复。避免多个下载同样的包,能够大大优化流水线效率。在前端项目中,我们经常把node_modules缓存起来,这样一条流水线都可以使用这些下载好的包。在java项目中经常把maven下载的包缓存起来。以备后用
cache下的参数有

  • paths 当前工作环境下的目录

  • key 存储的key,key不变不会重新生成缓存,

  • :key:\\​prefix 使用一些文件制作成文件hash值,当做key的一部分

  • untracked 是否缓存git忽略的文件

  • when 定义何时存储缓存 on_success;on_failure;always

  • policy 缓存是否要在job完成后重新上传

缓存可以设置流水线全局,也可以在job中设置

cache:
  key: hello-vue-cache
  paths:
   - node_modules
     
cache:
		key:
    	files:
     		- Gemfile.lock
     		- package.json
		paths:
    	- vendor/ruby
    	- node_modules

when

when关键字是实现在发生故障或尽管发生故障时仍能运行的作业。比如你要在任务失败后需要触发一个job,
或者你需要手动执行任务,或者当你一个任务执行成功后,执行另一个任务.

  • on_success 所有任务执行成功后
  • on_failure 当至少一个任务失败后
  • always 执行作业,而不考虑作业在早期阶段的状态。
  • manual 手动执行任务
  • delayed 延迟执行任务
  • never在rules中不排除执行的任务在workflow:rules不允许的流水线

only/except

only/except 是规定当前job的可见状态,一个项目有很多分支,tag,我们的流水线,为了对特定的分支,特定的tag执行不同的job,这里就要使用only和except
在任务上加上这一段代码,就表明当前任务只有在master分支可以运行

only:
		- master

也可以根据当前的代码变动是合并,还是推送,还是使用API来触发的。
如果一个任务没有only属性,那默认就是only: [\'branches\', \'tags\'] 操作分支或者tags都会触发流水线。

before_script

before_script 关键词是用于在每个任务之前执行的脚本,但是会在artifacts恢复之后执行。你可以这样定义一个全局的before_script,

default:
before_script:

- echo "Execute this script in all jobs that don\'t already have a before_script section."

也可以在一个任务中中单独定义

job:
  before_script:
    - echo "Execute this script instead of the global before_script."
  script:
    - echo "This script executes after the job\'s `before_script`"

任务中的before_script会覆盖全局的before_script

after_script

after_script与before_script类似,用于定义多行脚本,会在任务执行完成后执行,即使任务失败也会被执行。如果任务被取消或者超时,after_script就不会被执行了,目前官方正在计划这个特性。
可以定义全局的,也可以定义局部的

default:
  after_script:
    - echo "Execute this script in all jobs that don\'t already have an after_script section."

job1:
  script:
    - echo "This script executes first. When it completes, the global after_script executes."

job:
  script:
    - echo "This script executes first. When it completes, the job\'s `after_script` executes."
    after_script:
        - echo "Execute this script instead of the global after_script."

dependencies

dependencies关键词是定义特定的job运行规则。默认artifacts是从当前阶段产生,在后续的阶段都会被下载,但我们可以使用dependencies关键词来控制artifacts从哪里下载,
这里有一个例子,

build:osx:
  stage: build
  script: make build:osx
  artifacts:
    paths:
      - binaries/

build:linux:
  stage: build
  script: make build:linux
  artifacts:
    paths:
      - binaries/

test:osx:
  stage: test
  script: make test:osx
  dependencies:
    - build:osx

test:linux:
  stage: test
  script: make test:linux
  dependencies:
    - build:linux

deploy:
  stage: deploy
  script: make deploy

根据这个例子我们不难看出,
任务test:osx 依赖build:osx
任务test:linux 依赖 build:linux
这样配置以后 任务test:linux 就不用等任务build:osx 执行完成在执行了,只需要等待任务build:linux完成
很好地利用了依赖关系来优化流水线的速率,前四个任务都执行完成后,才会执行最后一个部署的任务。

environment

environment是用于定义环境变量,可以是用k-v的方式定义

deploy to production:
stage: deploy
script: git push production HEAD:master
environment:
name: production

需要注意的是这里定义的环境变量是不能在script值使用的。
这个关键词可以和review和merge搭配。

extends

这个关键词可以使一个任务继承另一个任务。
如下案例

.tests:
  script: rake test
  stage: test
  only:
    refs:
      - branches

rspec:
  extends: .tests
  script: rake rspec
  only:
    variables:
      - $RSPEC

任务rspec 继承了.tests任务,在流水线中.tests是一个隐藏的任务,在流水线中,以英文远点开头的任务名,都是隐藏的任务。不会被执行。 被rspec继承后,相同的key会以rspec为准,rspec没有的,而.tests有的,则合并到rspec中,
合并后的结果是

rspec:
  script: rake rspec
  stage: test
  only:
    refs:
      - branches
        variables:
            - $RSPEC

使用这一个手段,可以写一个模板,只要稍微改改就能后使用。非常适合大批量编写流水线。

include

使用include可以导入一个或多个额外的yaml文件到你的CICD配置里,这一你就可以将一个很长的流水线,分隔出来。使用include来引入。
也可以将几个流水线中相同的配置,提取出来,公用。引入的文件扩展名 必须是.yaml或者.yml两种,其他的不行。
include 关键词下,有四个可选性,
local, 引入一个当前项目的文件
file, 引入一个不同项目的文件
remote, 引入一个公网文件,
template, 引入一个由GitLab提供的模板

下面是几个例子

include:
  - local: \'/templates/.gitlab-ci-template.yml\'
include:
  - project: \'my-group/my-project\'
    file: \'/templates/.gitlab-ci-template.yml\'
include:
  - local: \'/templates/.gitlab-ci-template.yml\'
include:

  - project: \'my-group/my-project\'
    ref: master
    file: \'/templates/.gitlab-ci-template.yml\'

  - project: \'my-group/my-project\'
    ref: v1.0.0
    file: \'/templates/.gitlab-ci-template.yml\'

  - project: \'my-group/my-project\'
    ref: 787123b47f14b552955ca2786bc9542ae66fee5b  # Git SHA
    file: \'/templates/.gitlab-ci-template.yml\'
 include:
 		- remote: \'https://gitlab.com/awesome-project/raw/master/.gitlab-ci-template.yml\'

trigger

trigger 是应对那些更加复杂的CICD流程,如多流水线,父子流水线
使用它可以定义一个下游的流水线,配置了trigger的任务是不能跑脚本的,就是说不能定义script, before_script, 和 after_script.
项目这个是一个多项目流水线

rspec:
  stage: test
  script: bundle exec rspec

staging:
  stage: deploy
  trigger: my/deployment

流水线执行完test任务后就会去执行my/deployment项目的流水线

配置下游流水线式也可以执行分支

rspec:
  stage: test
  script: bundle exec rspec

staging:
  stage: deploy
  trigger:
    project: my/deployment
    branch: stablez

rules

rules是用于规定任务的执行规则,使用一个表达式,来规范那些任务执行,那些任务不执行.还可以在任务成功,或者失败后,触发另一个任务。
如下面这个例子

docker build:
  script: docker build -t my-image:$CI_COMMIT_REF_SLUG .
  rules:
    - if: \'$CI_COMMIT_BRANCH == "master"\'
      when: delayed
      start_in: \'3 hours\'
      allow_failure: true

如果当前的分支是master分支则任务执行就延迟3个小时,并且允许失败。
rules的下面有是哪个可选属性

if 使用if表达式 添加或移除一个任务, 类似 only:variables.
changes 根据某些个文件是否改变来追加或移除一些任务。类似 only:changes.
exists 根据是否存在特定文件来追加或移除一些任务
if中可以使用CICD的所有预设变量,分支,来源,合并请求,commit,push web,schedule等。可以针对不用的情景配置不用的规则。
在看下这个例子

job:
  script: echo "Hello, Rules!"
  rules:
    - if: \'$CI_MERGE_REQUEST_TARGET_BRANCH_NAME == "master"\'
      when: manual
      allow_failure: true



解释起来并不复杂,一个判断语句,二句赋值语句。即如果当前分支是master,在任务的执行方式改为手动,并且运行失败。

以上是关于cicd的主要内容,如果未能解决你的问题,请参考以下文章

Jenkins CICD代码构建发布流程

DevOps落地实践 BAT系列 CICD iPipe vs CCI

jenkinsk8s的CICD流程设计

Docker+Harbor+Jenkins+Gitlab自动化CICD构建

CICD相关概念

当使用CICD的Conducto时,我必须创建自己的dockerfile吗?