gitlab pipeline 构建容器镜像方法
随着 k8s 的流行,用容器的方式来交付软件产品也变得越来越普遍,那么在 gitlab ci/cd 流程中如何更快捷、更安全的方式来构建容器镜像呢?目前主要有两大的方式:
- docker 构建镜像
- Kaniko 构建镜像
1. docker 构建镜像
1.1 shell executor 方式
注册 runner,使用 shell executor
gitlab-runner register -n \
--url https://jihulab.com/ \
--registration-token REGISTRATION_TOKEN \
--executor shell \
--description "My Runner"
在 runner 主机上安装 docker:Install Docker Engine | Docker Documentation
添加 runner 到 docker 组
usermod -aG docker gitlab-runner
验证 gitlab-runner 用户是否能够访问 docker
sudo -u gitlab-runner -H docker info
在 pipeline 中使用 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
-
镜像仓库使用的时 gitlab 提供的 REGISTRY,也可以替换成自行搭建的仓库
-
使用了 --cache 加速镜像构建
1.2 挂载 docker.sock 文件方式
使用 docker
executor,runner 配置类似以下内容:
[[runners]]
url = "https://jihulab.com/"
token = RUNNER_TOKEN
executor = "docker"
[runners.docker]
tls_verify = false
image = "docker:19.03.12"
privileged = false
disable_cache = false
volumes = ["/var/run/docker.sock:/var/run/docker.sock", "/cache"]
[runners.cache]
Insecure = false
使用以下注册方法可以生成上面配置内容:
gitlab-runner register -n \
--url https://jihulab.com/ \
--registration-token REGISTRATION_TOKEN \
--executor docker \
--description "My Docker Runner" \
--docker-image "docker:19.03.12" \
--docker-volumes /var/run/docker.sock:/var/run/docker.sock
在 pipeline 中使用 docker 打包镜像并上传到镜像仓库:
image: docker:19.03.12
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
1.3 dind(docker-in-docker) 方式
这种方式不需要挂载宿主机的socket文件,但是需要以 --privileged 权限来以 dind 镜像创建一个容器
1.3.1 使用 docker executor
开启 TLS
docker 19.03.12 版本后,默认开启 TLS
runner 配置类似以下内容:
[[runners]]
url = "https://jihulab.com/"
token = TOKEN
executor = "docker"
[runners.docker]
tls_verify = false
image = "docker:19.03.12"
privileged = true
disable_cache = false
volumes = ["/certs/client", "/cache"]
[runners.cache]
Insecure = false
- privileged = true 必须
使用以下注册方法可以生成上面配置内容:
gitlab-runner register -n \
--url https://jihulab.com/ \
--registration-token REGISTRATION_TOKEN \
--executor docker \
--description "My Docker Runner" \
--docker-image "docker:19.03.12" \
--docker-privileged \
--docker-volumes "/certs/client"
在 pipeline 中使用 docker in docker 打包镜像并上传到镜像仓库:
image: docker:19.03.12
variables:
DOCKER_DRIVER: overlay2
DOCKER_HOST: tcp://docker:2376
DOCKER_TLS_CERTDIR: "/certs"
services:
- docker:19.03.12-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
关闭 TLS
runner 配置类似以下内容:
[[runners]]
url = "https://jihulab.com/"
token = TOKEN
executor = "docker"
[runners.docker]
tls_verify = false
image = "docker:19.03.12"
privileged = true
disable_cache = false
volumes = ["/cache"]
[runners.cache]
Insecure = false
在 pipeline 中使用 docker in docker 打包镜像并上传到镜像仓库:
image: docker:19.03.12
variables:
DOCKER_DRIVER: overlay2
DOCKER_HOST: tcp://docker:2375
DOCKER_TLS_CERTDIR: ""
services:
- docker:19.03.12-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
1.3.2 使用 kubernetes executor
开启 TLS
使用 Helm Chart 方式安装 runner,更新配置文件 values.yaml 加载证书目录
runners:
config: |
[[runners]]
[runners.kubernetes]
image = "ubuntu:20.04"
privileged = true
[[runners.kubernetes.volumes.empty_dir]]
name = "docker-certs"
mount_path = "/certs/client"
medium = "Memory"
在 pipeline 中使用 docker in docker 打包镜像并上传到镜像仓库:
image: docker:19.03.12
variables:
DOCKER_DRIVER: overlay2
DOCKER_HOST: tcp://docker:2376
DOCKER_TLS_CERTDIR: "/certs"
DOCKER_TLS_VERIFY: 1
DOCKER_CERT_PATH: "$DOCKER_TLS_CERTDIR/client"
services:
- docker:19.03.12-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
2. Kaniko 构建镜像
使用 docker in docker 方式构建镜像时有以下问题:
- 需要使用 privileged mode ,存在安全隐患
- 因为需要额外运行 Docker daemon 进程,性能和速度上不太理想
Kaniko 是谷歌开源的一款用来构建容器镜像的工具。与 docker 不同,Kaniko 并不依赖于 Docker daemon 进程,完全是在用户空间根据 Dockerfile 的内容逐行执行命令来构建镜像,这就使得在一些无法获取 docker daemon
进程的环境下也能够构建镜像,比如在标准的Kubernetes Cluster上。
使用 kaniko,runner 只能使用以下类型的 executor:
2.1 使用 Kaniko 打包镜像
如果想使用 Kaniko 打包镜像,需要以下条件:
- kaniko debug 镜像:gcr.io/kaniko-project/executor:debug,国内可能无法下载,可以使用 willdockerhub/kaniko-executor:debug 代替,也可以使用微软国内镜像源:gcr.azk8s.cn/kaniko-project/executor:debug(gcr.io 的镜像都可以使用这个方法下载)
entrypoint
必须重写 overridden,否则打包脚本无法运行- 需要配置
config.json
,其中包含远程仓库的登陆认证信息
示例:
build:
stage: build
image:
# name: gcr.io/kaniko-project/executor:debug
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"
--destination "${CI_REGISTRY_IMAGE}:${CI_COMMIT_TAG}"
rules:
- if: $CI_COMMIT_TAG
- 查看 Kaniko 帮助:
docker run --rm willdockerhub/kaniko-executor:debug
2.2 自签证书 registry
如果本地镜像仓库使用的自签证书,会遇到报错:
$ /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
解决方法如下:
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