# 从零搭建gitlabci环境
# 搭建环境
将gitlab镜像拉到服务器上跑起来。
# 1】拉取镜像
- 使用docker拉取
gitlab/gitlab-ce
的镜像 - docker拉取
nginx
镜像
#查看本地镜像
docker images
#从远程仓库拉取gitlab/gitlab-ce的镜像
docker pull gitlab/gitlab-ce
#从远程仓库拉取nginx镜像
docker pull nginx
docker images
#REPOSITORY TAG IMAGE ID CREATED SIZE
#node latest 8f1b7f0dfc2f 5 days ago 907MB
#nginx latest 08b152afcfae 5 days ago 133MB
#gitlab/gitlab-ce latest 75d591b81fd7 6 days ago 2.23GB
# 2】运行镜像到容器
sudo docker run --detach --hostname gitlab.rayhomie.icu --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
# 3】查看当前运行的容器
docker container ls -a
#CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
#df62d4c44c25 gitlab/gitlab-ce:latest "/assets/wrapper" 3 minutes ago Created gitlab
# 4】查看容器名为gitlab的日志
#打印当前运行日志
docker logs gitlab
#实时打印日志
docker logs -f gitlab
# 5】成功运行gitlab
此时我们就成功地将gitlab镜像跑在了本地的docker容器中,并且可以通过地址来访问gitlab界面。
# GitLab CI/CD基础知识
简单理解:但我们把本地代码推到gitlab远程仓库时,会触发一个流程,这个流程会执行一系列的任务,这些任务组装起来就是一个pipeline(流水线)。
- pipeline(流水线)
- stage(阶段)
- job(任务)
如上图可以看出这几个概念之间的关系是:
- 一个流水线包含多个阶段;
- 一个阶段包含多个任务;
gitlab只是一个代码仓库(代码管理工具平台),它是不会去跑这些流水线上的任务。所以又要引出一个概念gitlab runner(一个安装在服务器上的软件),所有的我们定义的cicd的操作都是在gitlab runner上去跑。(gitlab runner就是给cicd提供一个环境)
- .gitlab-ci.yml文件:用来定义流水线、阶段、任务。
# docker安装GitLab Runner
# 1】拉取runner镜像
在docker远程仓库拉取gitlab/gitlab-runner镜像到本地:
#拉取镜像到本地
docker pull gitlab/gitlab-runner
# 2】运行镜像到容器
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
# 3】注册gitlab runner
要使gitlab runner和gitlab产生联系,需要找到我们gitlab的Token:
然后在gitlab runner运行的docker容器中用这个Token去注册一下,脚本具体如下:
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.xxxx.com/" --registration-token "vtizNrFzQKFacsSMxsJX" --description "first-register-runner" --tag-list "test-cicd,dockercicd" --run-untagged="true" --locked="false" --access-level="not_protected"
- url参数是我们gitlab的地址
- registration-token参数是上图gitlab的token
- tag-list参数是注册这个runner的标签(后面可用于指定具体哪个runner去执行流水线任务)
# .gitlab-ci.yml的编写
# 基本关键词使用
- script:让gitlab runner去执行shell脚本(所有的任务都需要有script关键字去执行)
- stages:全局自定义阶段
- stage:在每个job(任务)中定义该任务属于哪个stage阶段。stage 是阶段的意思,用于归档一部分的job,按照定义的stage顺序来执行。(默认的stage有
.pre
,build
,test
,deploy
,.post
)job执行的顺序不是按照编写的顺序,大体上是按照stage定义的顺序来执行的,注意是大体,也有例外的情况。 - retry:有可能这个任务会失败,需要有个重试的机制(
retry:2
指定如果失败重试2次,最多设置为重试2次,也就是最多运行3次) - image:指定一个基础Docker镜像作为基础运行环境,经常用到的镜像有node、java、python、docker
- tags:tags 关键词是用于指定Runner,tags的取值范围是在该项目可见的runner tags中
- only、except:限定当前任务执行的条件(限定分支等)
- when:when关键词是实现在发生故障或尽管发生故障时仍能运行的作业,比如你要在任务失败后需要出发一个job,或者你需要手动执行任务,或者当你一个任务执行成功后,执行另一个任务。
- on_success:所有任务执行成功后
- on_failure:当至少一个任务失败后
- always:执行作业,而不考虑作业在早期阶段的状态
- manual:手动执行任务
- delayed:延迟执行任务
- never:在
rules
中不排除执行的任务,在workflow:rules
不允许的流水线
- cache:把一些文件列表保存到缓存中,在各个任务之间互相传递。缓存是将当前工作环境目录中的一些文件,一些文件夹存储起来,用于在各个任务初始化的时候恢复
- artifacts:成功时附加到作业的文件和目录列表。
- variables:在.gitlab-ci.yml文件中定义全局变量或者局部变量。(在全局定义即全局变量,在任务中单独定义即局部变量)
- release:自动化发布包
- timeout:设置超时时间
- resource_group:确保一个分支同时只有一个流水线在工作
- after_script
- allow_failure
- before_script
- coverage
- dependencies
- environment
- extends
- include
- interruptible
- pages
- parallel
- rules
- services
- trigger
# stage
由于build
在test
之前所有会先指向job1
这个任务,后指向job0
任务:(下面👇:)
stages:
- build
- test
- deploy
job 0:
stage: test
script: echo 'tets'
job 1:
stage: build
script: echo 'build'
下面写了一个默认官方提供stage的案例,含5个jobs属于5个阶段:
官方默认的阶段stages顺序是.pre
,build
,test
,deploy
,.post
默认的gitlab runner在同一个阶段的任务是按顺序同步执行的(如果需要他每个阶段任务并发执行的话,需要对gitlab runner进行配置)
所以我们任务的执行顺序是:job1 -> job2 -> job4 -> job6 -> job3 -> job5
stages:
- .pre
- build
- test
- deploy
- .post
job 1:
stage: .pre
script:
- echo '.pre job'
job 2:
stage: build
script:
- echo 'build job'
job 3:
stage: deploy
script:
- echo 'deploy job'
job 4:
stage: test
script:
- echo 'test1 job'
job 5:
stage: .post
script:
- echo '.post job'
job 6:
stage: test
script:
- echo 'test2 job'
# cache
image: 'node:12.6.0'
stages:
- install
- build
- deploy
job_install:
stage:install
tags:
- public-runner001
script:
- npm install
job_build:
stage:build
tags:
- public-runner001
script:
- npm run build
job_deploy:
stage:deploy
tags:
- public-runner001
script:
- echo 'start deploy'
此时跑流水线的话,在build阶段会报错,因为在第一个阶段的任务结束时会将node_modules文件夹删除掉,此时我们就需要使用缓存将node_modules文件夹进行缓存,缓存的文件夹才可以在各个任务中一直被使用。
(yml文件中的 “-” 和 “:”之后一定要留下空格)
image: 'node:12.6.0'
stages:
- install
- build
- deploy
#缓存node_modules文件夹,并指定唯一标识key
cache:
key: hello-gitlab-ci
paths:
- node_modules
job_install:
stage: install
tags:
- public-runner001
script:
- npm install
job_build:
stage: build
tags:
- public-runner001
script:
- npm run build
job_deploy:
stage: deploy
tags:
- public-runner001
script:
- echo 'start deploy'
此时我们可以看到我们的pipeline流水线已经成功执行完成:
# job_install
# job_build
# job_deploy
# only、when
image: 'node:12.6.0'
stages:
- install
- build
- deploy
#缓存node_modules文件夹,并指定唯一标识key
cache:
key: hello-gitlab-ci
paths:
- node_modules
job_install:
stage: install
tags:
- public-runner001
script:
- npm install
job_build:
stage: build
tags:
- public-runner001
script:
- npm run build
only:
- release
#限定在release分支执行
job_deploy:
stage: deploy
tags:
- public-runner001
script:
- echo 'start deploy'
when: manual
#手动执行任务
# docker部署前端项目
# 任务列表:
- 安装node包
- 编译
- docker镜像部署
使用的关键词有:image,stages,stage,tag,script,cache,docker,build
# 编写Dockerfile:
FROM node:lastest as builder
WORKDIR /app
COPY package.json .
RUN npm install --registry=http://registry.npm.taobao.org
COPY . .
RUN npm run build
FROM ngins:lastest
COPY --from=builder /app/dist /usr/share/nginx/html
# 编写.gitlab-ci.yml:
#设置node为基础环境镜像
image: node:alpine
#声明阶段
stages:
- install
- lint-code
- build
- deploy
#设置缓存
cache:
key: xd-log-platform
paths:
- node_modules
#定义install任务(1.选定阶段、2.runner的tags、3.脚本)
job_install:
stage: install
tags:
- dev-runner-001
script:
- npm install
#定义build任务(artifacts是将dist目录存储起来,让其他任务中也能使用到。因为每个任务之间都是隔离的,任务开始时都会重置环境,因此就需要使用cache、artifacts等关键字)
job_build:
stage: build
tags:
- dev-runner-001
script:
- npm run build
artifacts:
paths:
- dist/
#定义deploy任务(1.使用docker基础镜像,2.通过dockerfile构建镜像,3.如果环境中有容器则删除该容器并起动运行一个容器,4.且设置为手动执行任务)
job_deploy:
image: docker
stage: deploy
tags:
- dev-runner-001
script:
- docker build -t xd_log_platform_images .
- if [ $(docker ps -aq --filter name=xd_log_platform_container) ];then docker rm -f xd_log_platform_container;
- docker run -d -p 8001:80 --name xd_log_platform_container xd_log_platform_images
- echo 'deploy docker image success. visit http://123.23.23.13:8001 '
when: manual
如果发现报错,可能是gitlab-runner的配置有问题:
#进入gitlab-runner的配置目录
cd /srv/gitlab-runner/config
#编辑配置文件
vim config.toml
打开编辑页面后你会发现有很多配置项:
#允许当前阶段几个任务并行执行
concurrent = 1
#代码提交后多久检测一次代码变更,执行gitlab-ci
check_interval = 0
#下面就是该机器上的所有gitlab-runner的配置
[[runners]]
name = "dev-runner-001"
url = "xxxxxx"
token = "xxxxxxxxxx"
executor = "docker"
[runners.custom_build_dir]
[runners.cache]
[runners.cache.s3]
[runners.cache.gcs]
[runners.cache.azure]
[runners.docker]
tls_verify = false
image = "alpine:latest"
privileged = false
disable_entrypoint_overwrite = false
oom_kill_disable = false
disable_cache = false
#映射
volumes = ["/cache"]
#如果docker执行有问题需要设置一下官方提供的目录映射
#volumes = ["/cache","/usr/bin/docker:/usr/bin/docker","/var/run/docker.sock:/var/run/docker.sock"]
shm_size = 0
# oss部署前端项目
# 任务列表:
- 开题oss
- 创建bucket
- 创建ack密钥
- 使用ossutil
- 隐秘信息变量存储
#...
job_deploy_oss:
stage: deploy
tags:
- dev-runner-001
script:
- wget http://gosspublic.alicdn.com/ossutil/1.6.18/ossutil64
- chomd 755 ossutil64
- ./ossutil64 config -e ${endPoint} -i ${accessKeyID} -k ${accessKeySecret} -L CH --loglevel debug -c ~/.ossutilconfig
- ./ossutil64 -c ~/.ossutilconfig cp -r -f dist oss://bucket_name/
when: manual
指定oss配置文件,递归强制上传dist文件夹下的文件到指定的oss的bucket上。
# ci环境变量的使用:
通过这样设置了的环境变量值,就可以在**.gitlab-ci.yml**文件中通过${variables}
的形式进行使用变量。
# 变量的注入与使用
但我们.gitlab.yml文件中有很多地方使用到了相同的值,我们就可以将这些值提取成变量来使用。
# 三种变量的使用:
- 在.gitlab-ci.yml中自己定义(variables关键字)
- pipeline中预定义的变量(提交的commit的哈希值,当前的分支,当前的任务名称等)
- 自己在项目中设置变量(在可视化页面中进行设置)
# 变量的类型:
- k-v变量
- 文件(签名证书,密钥等)
# 变量能在哪些关键字中使用:
environment:url
environment:name
resource_group
include
variables
image
services:[]
services:[]:name
cache:key
artifacts:name
script,before_script,after_script
only:variables:[],export:variables:[],rules:if
# 如何使用:
# variables关键字定义及使用
#是一个全局的变量,任何一个任务中都可以使用。
variables:
TEST_VAR: "All jobs can use this variable's value"
#在任务中执行打印变量(直接用$符号+变量名即可)
log_var:
script:
- echo $TEST_VAR
#这是我们刚才使用docker部署前端项目中的任务,我们想要把当前任务中的镜像名称和容器名称定义成局部变量:
job_deploy:
variables:
IMAGE_NAME: "xd_log_platform_images"
CONTAINER_NAME: "xd_log_platform_container"
image: docker
stage: deploy
tags:
- dev-runner-001
script:
- docker build -t $IMAGE_NAME .
- if [ $(docker ps -aq --filter name=$CONTAINER_NAME) ];then docker rm -f $CONTAINER_NAME;
- docker run -d -p 8001:80 --name $CONTAINER_NAME $IMAGE_NAME
- echo 'deploy docker image success. visit http://123.23.23.13:8001 '
when: manual
# 在可视化页面设置变量并使用
#打印我们上面👆设置的NAME变量
log_project_var:
script:
- echo $NAME
勾选mask variable时的打印效果如下:
# pipeline中预定义的变量
可在官网去查看预定义的变量名,但是我们怎么去查看到这些预定义变量呢?👇
#我们可以使用该任务去导出所有的变量(即打印出来)
get_all_var:
script:
- export
#当前任务就是使用预设变量的例子
test_variable:
stage: test
script:
- echo $CI_JOB_STAGE
# 流水线的类型以及流水线的触发方式
# 流水线类型:
- 基本流水线
- DAG流水线 (一个项目同时部署多个平台,多条流水线并行执行)
- 多项目流水线
- 父子流水线
- 合并请求流水线
# 流水线的触发:
- 推送代码
- 定时触发
- url触发
- 手动触发
# 定时触发
# url触发
# 流水线最佳实践及调试
使用关键词:
- interruptible:设置为true,标记该任务可被阻断。
- release
- timeout
- resource_group
涉及功能:
- 自动取消旧的流水线
- 创建一个release
- 设置超时时间
- 保证安全部署,一个分支只允许有一个部署任务
- 流水线的调试
- 设置部署冻结
- 流水线内置的调试
# 1】自动取消旧的流水线
在同一个分支,短时间内只对最新的提交进行ci,取消未执行完的流水线。
install_job:
stage: install
script:
- echo 'start install'
- sleep 60
- echo 'end install'
interruptible: true
build_job:
stage: build
script:
- echo 'start build'
- sleep 120
- echo 'end build'
interruptible: true
第一次提交:
紧接着提交第二次:(上一次的ci就被取消了)
# 2】创建一个release
自动创建一个release:(release就是包,流水线中使用release关键词)
- 使用gitlab提供的镜像进行打release
- only指定触发任务的方式,当打tag时就会创建release
create_release:
image: registry.gitlab.com/gitlab-org/release-cli:latest
stage: build
script: echo 'start create release'
release:
tag_name: $CI_COMMIT_TAG
description: 'my release'
only:
- tags
# 3】设置超时时间
官方默认的超时时间是一个小时(如果需要自定义的话需要使用timeout关键字)
build:
script: build.sh
timeout: 3 hours 30 minutes
test:
script: rspec
timeout: 3h 30m
# 4】限定并发任务
保证安全部署,一个分支只允许有一个部署任务(流水线)
deploy:
stage: deploy
environment:
name: staging
script:
- echo 'start deploy'
- sleep 120
resource_group: prod