在 GitLab CI/CD 中使用内置的容器镜像库

配置 Docker-in-Docker

Docker-in-Docker (dind) means:

  • 你应该注册一个 Docker executorKubernetes executor
  • 执行器(executor)使用 docker 镜像运行你的 CI/CD jobs

参考 Docker-in-Docker with TLS disabled in the Docker executor

身份认证

shell 复制代码
docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY

CI_REGISTRY_USER CI_REGISTRY_PASSWORDCI_REGISTRY 都是 CI/CD 变量

参考:Authenticate with the Container Registry

Gitlab Runner 配置

[root@localhost test]# cat /etc/gitlab-runner/config.toml 
[[runners]]
  ....
  [runners.docker]
    tls_verify = false
    privileged = true
    image = "docker:20.10.16"
    disable_entrypoint_overwrite = false
    oom_kill_disable = false
    disable_cache = false
    volumes = ["/cache"]
    shm_size = 0
    extra_hosts = ["registry.gitlab.example.com:your-gitlab-instance-host"]

构建并推送镜像到镜像库

[root@localhost opt]# cat .gitlab-ci.yml 
stages:
  - build

build-image:
  stage: build
  image: docker:20.10.16
  services:
    - name: docker:20.10.16-dind
      command: ["--insecure-registry", "registry.gitlab.example.com"]
  variables:
    IMAGE_TAG: $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG
    DOCKER_HOST: tcp://docker:2375
    DOCKER_TLS_CERTDIR: ""
  before_script:
      - docker info
  script:
   - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
   - docker build --pull -t $IMAGE_TAG .
   - docker push $IMAGE_TAG

使用镜像库的镜像

[root@localhost opt]# cat .gitlab-ci.yml 
stages:
  - test

# before_script: docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY

format:
  stage: test
  image: registry.gitlab.example.com/group/project:tag
  variables:
   CGO_ENABLED: 1
  script:
    - go fmt $(go list ./... | grep -v /vendor/)
    - go vet $(go list ./... | grep -v /vendor/)
    - go test -race $(go list ./... | grep -v /vendor/)

Troubleshooting

docker: Cannot connect to the Docker daemon at tcp://docker:2375. Is the docker daemon running?

原因是 Docker daemon 启动失败,请检查 docker executor 是否配置正确,是否配置 CI/CD 变量 DOCKER_HOSTDOCKER_TLS_CERTDIR

参考 Docker-in-Docker with TLS disabled in the Docker executor

Error response from daemon: Get "https://registry.gitlab.example.com/v2/": dial tcp: lookup registry.gitlab.example.com on 192.168.40.190:53: no such host

原因是在 job 执行中使用了 docker-in-docker(dind)方式运行一个 Docker daemon,这个 docker daemon 没有使用宿主机的 /etc/hosts 文件,而是使用了默认的 DNS 服务器来解析所需的域名。因此,当尝试登陆registry.gitlab.example.com 时,DNS 无法解析这个名字,导致了错误

解决方法:为 Docker runner 添加额外的 hosts 映射

[[runners]]
  ....
  [runners.docker]
    ....
    extra_hosts = ["registry.gitlab.example.com:your-gitlab-instance-host"]
Error response from daemon: Get "https://registry.gitlab.example.com/v2/": x509: certificate is not valid for any names, but wanted to match registry.gitlab.example.com

原因是 Docker daemon 无法验证镜像仓库自签的 SSL 证书

解决方法:把这个镜像仓库添加到 dind serviceinsecure-registries 列表中

通过挂载配置文件的方式
[root@localhost opt]# cat /opt/daemon.json 
{
  "insecure-registries": ["registry.gitlab.example.com"]
}

[root@localhost opt]# cat /etc/gitlab-runner/config.toml
[[runners]]
  ....
  [runners.docker]
    ....
    volumes = ["/opt/daemon.json:/etc/docker/daemon.json:ro"]
通过 GitLab Runner 配置的方式
[[runners]]
  ...
  executor = "docker"
  [runners.docker]
    ...
    privileged = true
    [[runners.docker.services]]
      name = "docker:20.10.16-dind"
      command = ["--insecure-registry", "registry.gitlab.example.com"]
通过 CLI flag 的方式
[root@localhost opt]# cat .gitlab-ci.yml
build-image:
  stage: build
  image: docker:20.10.16
  services:
    - name: docker:20.10.16-dind
      command: ["--insecure-registry", "registry.gitlab.example.com"]

补充:在 CLI 中使用容器镜像库

shell 复制代码
# 登录
docker login registry.gitlab.example.com

# 构建镜像
docker build -t registry.gitlab.example.com/group/project .

# 推送镜像
docker push registry.gitlab.example.com/group/project

参考文档

Build and push container images to the Container Registry
Use Docker to build Docker images