Help us learn about your current experience with the documentation. Take the survey.

构建并推送容器镜像到容器注册表

  • Tier: Free, Premium, Ultimate
  • Offering: GitLab.com, GitLab Self-Managed, GitLab Dedicated

在构建和推送容器镜像之前,您必须先对容器注册表进行 认证

使用 Docker 命令

您可以使用 Docker 命令来构建和推送容器镜像到您的容器注册表:

  1. 认证到容器注册表。

  2. 运行 Docker 命令来构建或推送。例如:

    • 构建:

      docker build -t registry.example.com/group/project/image .
    • 推送:

      docker push registry.example.com/group/project/image

使用 GitLab CI/CD

使用 GitLab CI/CD 来构建、推送、测试和部署来自容器注册表的容器镜像。

配置您的 .gitlab-ci.yml 文件

您可以配置您的 .gitlab-ci.yml 文件来构建和推送容器镜像到容器注册表。

  • 如果多个作业需要认证,将认证命令放在 before_script 中。

  • 在构建前,使用 docker build --pull 来获取基础镜像的更改。这会稍微耗时,但能确保您的镜像是最新的。

  • 在每次 docker run 之前,执行显式的 docker pull 来获取刚刚构建的镜像。如果您使用多个运行器并在本地缓存镜像,这一步尤其重要。

    如果您在镜像标签中使用 Git SHA,每个作业都是唯一的,您永远不会遇到过时的镜像。但是,如果在依赖项更改后重新构建某个提交,仍然可能存在过时的镜像。

  • 不要直接构建到 latest 标签,因为可能有多个作业同时进行。

使用 Docker-in-Docker 容器镜像

您可以将自己的 Docker-in-Docker (DinD) 容器镜像与容器注册表或依赖代理一起使用。

使用 DinD 从您的 CI/CD 管道构建、测试和部署容器化应用程序。

先决条件:

当您想使用存储在 GitLab 容器注册表中的镜像时,使用此方法。

在您的 .gitlab-ci.yml 文件中:

  • 更新 imageservices 以指向您的注册表。
  • 添加服务 别名

您的 .gitlab-ci.yml 应该类似于这样:

build:
  image: $CI_REGISTRY/group/project/docker:24.0.5
  services:
    - name: $CI_REGISTRY/group/project/docker:24.0.5-dind
      alias: docker
  stage: build
  script:
    - docker build -t my-docker-image .
    - docker run my-docker-image /script/to/run/tests

使用此方法来缓存来自 Docker Hub 等外部注册表的镜像,以实现更快的构建速度并避免速率限制。

在您的 .gitlab-ci.yml 文件中:

  • 更新 imageservices 以使用依赖代理前缀。
  • 添加服务 别名

您的 .gitlab-ci.yml 应该类似于这样:

build:
  image: ${CI_DEPENDENCY_PROXY_GROUP_IMAGE_PREFIX}/docker:24.0.5
  services:
    - name: ${CI_DEPENDENCY_PROXY_GROUP_IMAGE_PREFIX}/docker:24.0.5-dind
      alias: docker
  stage: build
  script:
    - docker build -t my-docker-image .
    - docker run my-docker-image /script/to/run/tests

如果您忘记设置服务别名,容器镜像将找不到 dind 服务,并显示如下错误:

error during connect: Get http://docker:2376/v1.39/info: dial tcp: lookup docker on 192.168.0.1:53: no such host

使用 GitLab CI/CD 的容器注册表示例

如果您在运行器上使用 DinD,您的 .gitlab-ci.yml 文件应该类似于这样:

build:
  image: docker:24.0.5
  stage: build
  services:
    - docker:24.0.5-dind
  script:
    - echo "$CI_REGISTRY_PASSWORD" | docker login $CI_REGISTRY -u $CI_REGISTRY_USER --password-stdin
    - docker build -t $CI_REGISTRY/group/project/image:latest .
    - docker push $CI_REGISTRY/group/project/image:latest

您可以在您的 .gitlab-ci.yml 文件中使用 CI/CD 变量。例如:

build:
  image: docker:24.0.5
  stage: build
  services:
    - docker:24.0.5-dind
  variables:
    IMAGE_TAG: $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG
  script:
    - echo "$CI_REGISTRY_PASSWORD" | docker login $CI_REGISTRY -u $CI_REGISTRY_USER --password-stdin
    - docker build -t $IMAGE_TAG .
    - docker push $IMAGE_TAG

在上面的示例中:

  • $CI_REGISTRY_IMAGE 解析为与此项目关联的注册表地址。
  • $IMAGE_TAG 是一个自定义变量,它将注册表地址与 $CI_COMMIT_REF_SLUG(镜像标签)组合在一起。$CI_COMMIT_REF_NAME 预定义变量解析为分支或标签名称,可能包含正斜杠。镜像标签不能包含正斜杠,请使用 $CI_COMMIT_REF_SLUG

下面的示例将 CI/CD 任务分为四个流水线阶段,包括两个并行运行测试。

build 存储在容器注册表中,并由后续阶段在需要时下载容器镜像。当您向 main 分支推送更改时,流水线会将镜像标记为 latest,并使用应用程序特定的部署脚本进行部署:

default:
  image: docker:24.0.5
  services:
    - docker:24.0.5-dind
  before_script:
    - echo "$CI_REGISTRY_PASSWORD" | docker login $CI_REGISTRY -u $CI_REGISTRY_USER --password-stdin

stages:
  - build
  - test
  - release
  - deploy

variables:
  # 使用 TLS https://docs.gitlab.com/ee/ci/docker/using_docker_build.html#tls-enabled
  DOCKER_HOST: tcp://docker:2376
  DOCKER_TLS_CERTDIR: "/certs"
  CONTAINER_TEST_IMAGE: $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG
  CONTAINER_RELEASE_IMAGE: $CI_REGISTRY_IMAGE:latest

build:
  stage: build
  script:
    - docker build --pull -t $CONTAINER_TEST_IMAGE .
    - docker push $CONTAINER_TEST_IMAGE

test1:
  stage: test
  script:
    - docker pull $CONTAINER_TEST_IMAGE
    - docker run $CONTAINER_TEST_IMAGE /script/to/run/tests

test2:
  stage: test
  script:
    - docker pull $CONTAINER_TEST_IMAGE
    - docker run $CONTAINER_TEST_IMAGE /script/to/run/another/test

release-image:
  stage: release
  script:
    - docker pull $CONTAINER_TEST_IMAGE
    - docker tag $CONTAINER_TEST_IMAGE $CONTAINER_RELEASE_IMAGE
    - docker push $CONTAINER_RELEASE_IMAGE
  rules:
    - if: $CI_COMMIT_BRANCH == "main"

deploy:
  stage: deploy
  script:
    - ./deploy.sh
  rules:
    - if: $CI_COMMIT_BRANCH == "main"
  environment: production

上面的示例明确调用了 docker pull。如果您更喜欢使用 image: 隐式拉取容器镜像,并使用 DockerKubernetes 执行器,请确保将 pull_policy 设置为 always