平常我们在pipeline里面执行docker build的操作的时候,一般是下面的步骤,登录registry,根据dockerfile生成镜像,给镜像打标签,然后推送到registry里面。
docker login
docker build
docker tag
docker push
这种操作很常见。如果我们的CI工具本身是一个容器,我们会遇到docker in docker的问题。解决这种dind的一种做法是在挂载CI的容器的时候,挂载宿主机的docker daemon, 比如 /var/run/docker.sock。另外一种方式就是使用dind的镜像,在容器里面嵌套容器。这两种方式都有安全方面的问题,因为需要运行在特权模式下。
现在还有一种方式,就是kaniko。kaniko不依赖于docker daemon,每条docker命令都在用户空间执行。因此很适合k8s这样的环境。
官方文档
https://github.com/GoogleContainerTools/kaniko
下面是一个例子,我把一个.net core app的docker 镜像推送到Azure Container Registry里面。 我已经在CI Variable里面定义了三个变量用于验证登录。kaniko可以把build,tag和push等操作一条命令就实现了,而且无需考虑docker in docker的问题。
build-code-job-main-V2:
image:
name: gcr.io/kaniko-project/executor:debug
entrypoint: [""]
stage: build
variables:
IMAGE_NAME: "dotnet_demo"
CONTAINER_SERVER: "gitlabazuredemo.azurecr.io"
script:
- echo "kaniko test"
- echo "$(pwd)"
- >-
/kaniko/executor
--context "$(pwd)"
--dockerfile "$(pwd)/Dockerfile"
--destination "${CONTAINER_SERVER}/${IMAGE_NAME}:${tagName}"
--destination "${CONTAINER_SERVER}/${IMAGE_NAME}:latest"
--destination "${CONTAINER_SERVER}/${IMAGE_NAME}:${CI_COMMIT_SHORT_SHA}"
rules:
- if: $CI_COMMIT_TAG =~ /^\d+\.\d+\.\d+.*/
- if: $CI_COMMIT_REF_NAME == "main"
执行效果