GitLab 是一个全球知名的一体化 DevOps 平台,很多人都通过私有化部署 GitLab 来进行源代码托管。极狐GitLab :https://gitlab.cn/install?channel=content&utm_source=csdn 是 GitLab 在中国的发行版,专门为中国程序员服务。可以一键式部署极狐GitLab。
更多关于极狐GitLab :https://gitlab.cn 或者 DevOps 的最佳实践,可以关注文末的极狐GitLab 公众号。
学习极狐GitLab 的相关资料:
- 极狐GitLab 官网:https://gitlab.cn
- 极狐GitLab 官网文档:https://docs.gitlab.cn
- 极狐GitLab 论坛:https://forum.gitlab.cn/
- 极狐GitLab 安装配置:https://gitlab.cn/install
- 极狐GitLab 资源中心:https://resources.gitlab.cn
搜索【极狐GitLab】公众号,后台输入加群,备注gitlab,即可加入官方微信技术交流群。
极狐GitLab 公众号后台回复新手指南,免费领取极狐GitLab 新手指南一份,从零到一快速上手极狐GitLab。
使用极狐GitLab CI/CD 构建容器镜像是比较常用的 DevOps 流程,目前主要有以下两种方式:
- docker 构建镜像
- kaniko 构建镜像
本文演示使用极狐GitLab 自带的容器镜像仓库,开启方法也很简单,编辑配置文件 /etc/gitlab/gitlab.rb
,添加以下配置:
registry_external_url 'https://gitlab.leffss.cn:5050'
然后执行 gitlab-ctl reconfigure ; gitlab-ctl restart
就生效了。
1. docker 构建镜像
1.1 shell 执行器方式
原理:job 中直接调用宿主机的 docker 命令进行镜像的构建与上传
注册 runner,使用最基本的 shell 执行器:
gitlab-runner register -n \
--url https://gitlab.leffss.cn/ \
--registration-token oYJBJ-y3rCP6zs9e5y9J \
--executor shell \
--tag-list shell \
--description "My Shell Runner"
添加 gitlab-runner 用户到 docker 组
usermod -aG docker gitlab-runner
验证 gitlab-runner 用户是否能够使用 docker
sudo -u gitlab-runner -H docker info
创建 .gitlab-ci.yml,其中的 build job 直接调用宿主机 docker 命令
before_script:
- docker info
- echo $CI_REGISTRY_PASSWORD | docker login $CI_REGISTRY -u $CI_REGISTRY_USER --password-stdin
build:
stage: build
script:
- docker pull $CI_REGISTRY_IMAGE:latest || true
- docker build --cache-from $CI_REGISTRY_IMAGE:latest -t $CI_REGISTRY_IMAGE:$CI_COMMIT_TAG -t $CI_REGISTRY_IMAGE:latest .
- docker push $CI_REGISTRY_IMAGE:latest
- docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_TAG
rules:
- if: $CI_COMMIT_TAG
tags:
- shell
然后创建一个 tag 触发流水线。
1.2 挂载 docker.sock 文件方式
原理:job 中启动一个 docker 客户端,然后调用宿主机的 docker socket 文件进行镜像的构建与上传
注册 runner,使用 docker 执行器并挂载属主机 docker 的 socket 文件:
gitlab-runner register -n \
--url https://gitlab.leffss.cn/ \
--registration-token HqxWfyRQDosB4iBXWudg \
--executor docker \
--description "My Docker Runner" \
--docker-image "docker:20.10.24" \
--tag-list socket \
--docker-extra-hosts gitlab.leffss.cn:172.16.10.9 \
--docker-pull-policy if-not-present \
--docker-volumes /var/run/docker.sock:/var/run/docker.sock
创建 .gitlab-ci.yml,其中的 build job 就是一个 docker 客户端,它通过 /var/run/docker.sock 文件访问宿主机 docker 服务端
image: docker:20.10.24
before_script:
- docker info
- echo $CI_REGISTRY_PASSWORD | docker login $CI_REGISTRY -u $CI_REGISTRY_USER --password-stdin
build:
stage: build
script:
- docker pull $CI_REGISTRY_IMAGE:latest || true
- docker build --cache-from $CI_REGISTRY_IMAGE:latest -t $CI_REGISTRY_IMAGE:$CI_COMMIT_TAG -t $CI_REGISTRY_IMAGE:latest .
- docker push $CI_REGISTRY_IMAGE:latest
- docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_TAG
rules:
- if: $CI_COMMIT_TAG
tags:
- socket
然后创建一个 tag 触发流水线即可。
1.3 dind(docker-in-docker) 方式
原理:job 不直接调用宿主机 docker 命令,也不调用宿主机的 docker socket 文件,而是在 privileged(特权模式)下以 service 的方式启动一个 docker 服务器与客户端进行镜像的构建与上传
使用 dind,runner 一般使用以下类型的执行器:
1.3.1 使用 docker 执行器
注册 runner,使用 docker 执行器并设置开启特权模式:
gitlab-runner register -n \
--url https://gitlab.leffss.cn/ \
--registration-token oYJBJ-y3rCP6zs9e5y9J \
--executor docker \
--description "My Docker Runner" \
--docker-image "docker:20.10.24" \
--tag-list dind \
--docker-privileged \
--docker-extra-hosts gitlab.leffss.cn:172.16.10.15 \
--docker-pull-policy if-not-present \
--docker-volumes "/certs/client"
创建 .gitlab-ci.yml
,首先 service 启动了一个 docker 服务端,build job 是一个 docker 客户端,它通过变量 DOCKER_HOST 访问 service 启动的 docker 服务端
image: docker:20.10.24
variables:
DOCKER_DRIVER: overlay2
DOCKER_HOST: tcp://docker:2376
DOCKER_TLS_CERTDIR: "/certs"
services:
- docker:20.10.24-dind
before_script:
- docker info
- echo $CI_REGISTRY_PASSWORD | docker login $CI_REGISTRY -u $CI_REGISTRY_USER --password-stdin
build:
stage: build
script:
- docker pull $CI_REGISTRY_IMAGE:latest || true
- docker build --cache-from $CI_REGISTRY_IMAGE:latest -t $CI_REGISTRY_IMAGE:$CI_COMMIT_TAG -t $CI_REGISTRY_IMAGE:latest .
- docker push $CI_REGISTRY_IMAGE:latest
- docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_TAG
rules:
- if: $CI_COMMIT_TAG
tags:
- dind
- service 使用的是 docker link 功能
然后创建一个 tag 触发流水线即可。
如果您的镜像仓库未开启 https,可以按照以下设置解决:
services:
- name: docker:20.10.24-dind
entrypoint: ["dockerd-entrypoint.sh"]
command: ["--insecure-registry=registry.example.com"]
1.3.2 使用 kubernetes 执行器
k8s 执行器的原理和使用方法和上面的 docker 执行器是一样的,只是注册配置有点差别。因为没有准备 k8s 环境,就不做演示了。
Helm 方式安装 runner 配置文件 values.yaml :
runners:
config: |
[[runners]]
[runners.kubernetes]
image = "docker:20.10.24"
privileged = true
[[runners.kubernetes.volumes.empty_dir]]
name = "docker-certs"
mount_path = "/certs/client"
medium = "Memory"
2. kaniko 构建镜像
上面的几种方式构建镜像虽然都比较方便,但是会有以下问题:
直接访问主机 docker 进程,存在安全隐患
需要使用 privileged mode ,存在安全隐患
因为需要额外运行 docker server 进程,性能和速度上不太理想
kaniko 是谷歌开源的一款用来构建容器镜像的工具。与 docker 不同,kaniko 并不依赖于 docker server 进程,完全是根据 Dockerfile 的内容逐行执行命令来构建镜像,这就使得在一些无法获取 docker server
进程的环境下也能够构建镜像。
也就是说 kaniko 可以兼顾一定的速度,并且没有安全隐患。
使用 kaniko,runner 一般使用以下类型的执行器:
这里以 docker 执行器为例
2.1 注册 runner
gitlab-runner register -n \
--url https://gitlab.leffss.cn/ \
--registration-token HqxWfyRQDosB4iBXWudg \
--executor docker \
--description "My Docker Runner" \
--docker-image "docker:20.10.24" \
--tag-list kaniko \
--docker-extra-hosts gitlab.leffss.cn:172.16.10.9 \
--docker-pull-policy if-not-present
2.2 打包镜像
注意事项:
- kaniko 官方 debug 镜像:gcr.io/kaniko-project/executor:debug,国内可能无法下载,可以使用 willdockerhub/kaniko-executor:debug 代替
创建 .gitlab-ci.yml,build job 中 kaniko 直接解析 Dockerfile
build:
stage: build
image:
name: willdockerhub/kaniko-executor:debug
entrypoint: [""]
script:
- mkdir -p /kaniko/.docker
- echo "{\"auths\":{\"${CI_REGISTRY}\":{\"auth\":\"$(printf "%s:%s" "${CI_REGISTRY_USER}" "${CI_REGISTRY_PASSWORD}" | base64 | tr -d '\n')\"}}}" > /kaniko/.docker/config.json
- >-
/kaniko/executor
--context "${CI_PROJECT_DIR}"
--dockerfile "${CI_PROJECT_DIR}/Dockerfile"
--cache=true
--cache-repo "${CI_REGISTRY_IMAGE}:latest"
--destination "${CI_REGISTRY_IMAGE}:${CI_COMMIT_TAG}"
--destination "${CI_REGISTRY_IMAGE}:latest"
rules:
- if: $CI_COMMIT_TAG
tags:
- kaniko
- 如果 CI_REGISTRY 未开启 https,可以添加参数解决:
--insecure-registry "${CI_REGISTRY}"
然后创建一个 tag 触发流水线
如果不需要推送到远端,则可以这样:
build:
stage: build
image:
name: willdockerhub/kaniko-executor:debug
entrypoint: [""]
script:
- >-
/kaniko/executor
--context "${CI_PROJECT_DIR}"
--dockerfile "${CI_PROJECT_DIR}/Dockerfile"
--destination "${CI_REGISTRY_IMAGE}:${CI_COMMIT_TAG}"
--tarPath "${CI_PROJECT_DIR}/test.tar"
--no-push
rules:
- if: $CI_COMMIT_TAG
tags:
- kaniko
2.3 自签证书 registry
如果镜像仓库使用的自签证书,上传镜像会遇到 x509 报错:
$ /kaniko/executor --context $CI_PROJECT_DIR --dockerfile $CI_PROJECT_DIR/Dockerfile --no-push
INFO[0000] Downloading base image registry.gitlab.example.com/group/docker-image
error building image: getting stage builder for stage 0: Get https://registry.gitlab.example.com/v2/: x509: certificate signed by unknown authority
解决方法就是把自签 ca 根证书添加到 kaniko 相关 ssl 证书目录中即可:
before_script:
- mkdir -p /kaniko/.docker
- echo "{\"auths\":{\"${CI_REGISTRY}\":{\"auth\":\"$(printf "%s:%s" "${CI_REGISTRY_USER}" "${CI_REGISTRY_PASSWORD}" | base64 | tr -d '\n')\"}}}" > /kaniko/.docker/config.json
- |
echo "-----BEGIN CERTIFICATE-----
...
...
...
-----END CERTIFICATE-----" >> /kaniko/ssl/certs/additional-ca-cert-bundle.crt