GitLab搭建私有Docker仓库及自动构建镜像(CI/CD)

搭建GitLab环境并启用Container Registry

使用docker部署

通过环境变量注入GitLab的URL和Container Registry的URL

docker run -d --name gitlab --restart always \ 
  -e GITLAB_OMNIBUS_CONFIG="external_url 'https://example.com:8991'; gitlab_rails['gitlab_shell_ssh_port'] = 9992; registry_external_url 'https://example.com:8993';" \
  -p 8991:8991 -p 8992:22 -p 8993:8993  \
  -v /config/gitlab/config:/etc/gitlab \
  -v /config/gitlab/logs:/var/log/gitlab \
  -v /config/gitlab/data:/var/opt/gitlab \
  --shm-size 256m \ 
  gitlab/gitlab-ce

为已经存在GitLab服务开启Container Registry

默认GitLab是没有启用Container Registry,我们可以为手动启用

修改/etc/gitlab/gitlab.rb

registry_external_url 'https://example.com:8993'

重启GitLab

然后我们就可以在项目中看到 Packages & Registries -> Container Registry 菜单了。

https配置

替换/etc/gitlab/ssl目录下的.crt和.key文件,或者修改/etc/gitlab/gitlab.rb如下配置

nginx['ssl_certificate'] = "/etc/gitlab/ssl/example.com.crt"
nginx['ssl_certificate_key'] = "/etc/gitlab/ssl/example.com.key"

重启GitLab

GitLab和Container Registry一般需要https,而且要正确的证书,否则在客户端操作的会报错。

测试Container Registry

# 登陆Container Registry
docker login example.com:8993
# 向Container Registry推送镜像
docker push example.com:8993/test-project/test-app:1.0
# 从Container Registry拉取镜像
docker pull example.com:8993/test-project/test-app:1.1
# 登出Container Registry
docker logout example.com:8993

部署gitlab-runner

使用docker启动

docker run -d --name gitlab-runner --restart always \
  -v /var/run/docker.sock:/var/run/docker.sock \
  -v gitlab-runner-config:/etc/gitlab-runner \
  gitlab/gitlab-runner:latest

注册runners,根据提示输入要注册的GitLab的URL和注册Token等完成注册

docker run --rm -it -v gitlab-runner-config:/etc/gitlab-runner gitlab/gitlab-runner:latest register

使用管理员登陆,在Admin Area -> Overview -> Runners找到用于注册Shared Runner的Registration token

gitlab-ci执行时报错解决

Post http://docker:2375/v2/auth: dial tcp: lookup docker on 169.254.169.254:53: no such host

解决方法:设置privileged = true

参考链接;https://forum.gitlab.com/t/error-during-connect-post-http-docker-2375-v1-40-auth-dial-tcp-lookup-docker-on-169-254-169-254-no-such-host/28678/3

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

解决方法:添加docker.sock的映射,volumes = ["/var/run/docker.sock:/var/run/docker.sock", "/cache"]

参考链接:https://gitlab.com/gitlab-org/gitlab-runner/-/issues/27300

配置文件 config.toml完整示例

concurrent = 1
check_interval = 0

[session_server]
  session_timeout = 1800

[[runners]]
  name = "xxxxxxxxxxxx"
  url = "https://example.com:8991/"
  token = "xxxxxxxxxxxxxxxxxxxxxxxx"
  executor = "docker"
  [runners.custom_build_dir]
  [runners.cache]
    [runners.cache.s3]
    [runners.cache.gcs]
    [runners.cache.azure]
  [runners.docker]
    tls_verify = false
    image = "docker:stable"
    privileged = true
    disable_entrypoint_overwrite = false
    oom_kill_disable = false
    disable_cache = false
    volumes = ["/var/run/docker.sock:/var/run/docker.sock", "/cache"]
    shm_size = 0

GitLab CI/CD示例(自动构建docker镜像并推送到Container Registry)

新建一个项目(test-app),目录结构如下

test-app
├── .gitlab-ci.yml
├── Dockerfile
├── README.md
└── app.py

app.py

print('hello world')

Dockerfile

FROM python:3.11-slim-bullseye

WORKDIR /usr/src/app

COPY . /usr/src/app
CMD ["python", "app.py"]

.gitlab-ci.yml

docker-build:
  image: docker:latest
  stage: build
  services:
    - docker:dind
  before_script:
    - docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY
    # - echo $CI_REGISTRY_USER
    # - echo $CI_REGISTRY_PASSWORD
    # - echo $CI_REGISTRY
  script:
    # - echo $CI_COMMIT_BRANCH
    - |
      if [[ "$CI_COMMIT_BRANCH" == "$CI_DEFAULT_BRANCH" ]]; then
        tag=""
        echo "Running on default branch '$CI_DEFAULT_BRANCH': tag = 'latest'"
      else
        tag=":$CI_COMMIT_REF_SLUG"
        echo "Running on branch '$CI_COMMIT_BRANCH': tag = $tag"
      fi
    - docker build --pull -t "$CI_REGISTRY_IMAGE${tag}" .
    - docker push "$CI_REGISTRY_IMAGE${tag}"
  rules:
    - if: $CI_COMMIT_BRANCH
      exists:
        - Dockerfile
    - if: '$CI_COMMIT_REF_NAME == "main"'
      when: never
    # - if: '$CI_PIPELINE_SOURCE == "tag"'
    #   when: on_success
    #   tags:
    #     - v*

rules可以控制任务是否执行,比如可以添加一条只用添加特定标签才运行(最后注释的内容)。.gitlab-ci.yml配置还有很多,可以实现整个workflow,具体查看官方文档,这里只试验了只有单个Job的Pipeline。

.gitlab-ci.yml的内容可以看出,这个CI的逻辑是:当提交在main分支并且存在Dockerfile文件则开始运行,构建镜像并添加标签(latest或者git的tag)并推送到该GitLab的容器仓库。 该过程完全自动化完成,通过一些内置的环境变量自动完成判断以及验证等,方便也安全。

当CI任务执行完,我们查看 Packages & Registries -> Package Registry 可以发现已经有构件好的镜像,可以pull下来测试一下

# 拉取自动打包的镜像
[root@centos ~]# docker pull example.com:8993/bds/test-app:latest
latest: Pulling from bds/test-app
Digest: sha256:8835de3b55e288188c0368b6b0994642528a01b635841f7e9681928c79dde789
Status: Image is up to date for example.com:8993/bds/test-app:latest
example.com:8993/bds/test-app:latest
# 运行查看输出
[root@centos ~]# docker run --rm -it example.com:8993/bds/test-app:latest
hello world

参考链接

  • https://docs.gitlab.com/ee/install/docker.html
  • https://docs.gitlab.com/ee/user/packages/container_registry/
  • https://docs.gitlab.com/runner/install/