基于 GitLab 的自动化镜像构建

一、部署并注册 GitLab Runner

1. 启动 GitLab Runner 容器

bash 复制代码
[root@host1 ~]# docker pull gitlab/gitlab-runner
Using default tag: latest
latest: Pulling from gitlab/gitlab-runner
de66fc90c55d: Pull complete 
41d67aeda2be: Pull complete 
4d48ea5044a3: Pull complete 
d4dc7e0c6f85: Pull complete 
91a2731001cc: Pull complete 
Digest: sha256:4411906ada6b40b2ca259a72549a0c83883649d7b1e4c634d4d0dadf41b00785
Status: Downloaded newer image for gitlab/gitlab-runner:latest
docker.io/gitlab/gitlab-runner:latest
bash 复制代码
[root@host1 ~]# docker run -d --name gitlab-runner --restart always -v /etc/hosts:/etc/hosts -v /srv/gitlab-runner/config:/etc/gitlab-runner -v /var/run/docker.sock:/var/run/docker.sock gitlab/gitlab-runner:latest
981d3076234d516848eb65832ffc645b1f4b130f5a8273a5d01bdcadce931fc0

验证容器是否正常启动

bash 复制代码
[root@host1 ~]# docker ps | grep gitlab-runner
981d3076234d   gitlab/gitlab-runner:latest    "/usr/bin/dumb-init ..."   57 seconds ago   Up 56 seconds                                                                                                     
                                gitlab-runner

2. 从 GitLab 获取注册令牌

  • 登录 GitLab Web 界面(http://gitlab.abc.com);

  • 点击顶部「Menu」→「Admin」→ 左侧「Overview」→「Runners」;

  • 点击「Register an instance runner」,复制弹出的注册令牌(后续步骤用)。

3. 容器内注册 Runner

交互输入(需根据实际环境调整):

  • GitLab instance URL: http://gitlab.abc.com

  • Registration token: (粘贴步骤 2 获取的令牌)

  • Description: Alltest(Runner 描述,自定义)

  • Tags: CItest(Runner 标签,需与流水线配置匹配)

  • Executor: docker(执行器选择 Docker,用于容器内构建镜像)

  • Default Docker image: docker(默认基础镜像)

bash 复制代码
[root@host1 ~]# docker exec -it gitlab-runner gitlab-runner register
Runtime platform                                    arch=amd64 os=linux pid=20 revision=139a0ac0 version=18.4.0
Running in system-mode.                            
                                                   
Enter the GitLab instance URL (for example, https://gitlab.com/):
http://gitlab.abc.com
Enter the registration token:
xtrus1yYddZf5RjYYuxF
Enter a description for the runner:
[981d3076234d]: Alltest
Enter tags for the runner (comma-separated):
CItest
Enter optional maintenance note for the runner:
docker
WARNING: Support for registration tokens and runner parameters in the 'register' command has been deprecated in GitLab Runner 15.6 and will be replaced with support for authentication tokens. For more information, see https://docs.gitlab.com/ci/runners/new_creation_workflow/ 
Registering runner... succeeded                     correlation_id=01K62VQD3GJ8TS35JBG1917T8H runner=xtrus1yYd
Enter an executor: docker-windows, docker+machine, docker-autoscaler, instance, custom, virtualbox, docker, kubernetes, shell, ssh, parallels:
docker
Enter the default Docker image (for example, ruby:3.3):
docker
Runner registered successfully. Feel free to start it, but if it's running already the config should be automatically reloaded!
 
Configuration (with the authentication token) was saved in "/etc/gitlab-runner/config.toml" 

二、配置 Runner 访问 GitLab 域名

Runner 容器内默认无法解析 gitlab.abc.com,需修改配置文件:

bash 复制代码
[root@host1 ~]# vi /srv/gitlab-runner/config/config.toml
[root@host1 ~]# cat /srv/gitlab-runner/config/config.toml
concurrent = 1
check_interval = 0
shutdown_timeout = 0

[session_server]
  session_timeout = 1800

[[runners]]
  name = "Alltest"
  url = "http://gitlab.abc.com"
  id = 1
  token = "uSq9g8YdfxBnDvmj8zyx"
  token_obtained_at = 2025-09-26T11:14:55Z
  token_expires_at = 0001-01-01T00:00:00Z
  executor = "docker"
  [runners.cache]
    MaxUploadedArchiveSize = 0
    [runners.cache.s3]
    [runners.cache.gcs]
    [runners.cache.azure]
  [runners.docker]
    tls_verify = false
    image = "docker"
    privileged = false
    disable_entrypoint_overwrite = false
    oom_kill_disable = false
    disable_cache = false
    volumes = ["/var/run/docker.sock:/var/run/docker.sock", "/cache"]
    shm_size = 0
    network_mtu = 0
    extra_hosts = ["gitlab.abc.com:192.168.197.9"]

保存后,重启 Runner 使配置生效:

bash 复制代码
[root@host1 ~]# docker restart gitlab-runner
gitlab-runner

三、编写 CI/CD 流水线配置

进入之前创建的 nginx-demo 项目目录,创建 / 修改 .gitlab-ci.yml

bash 复制代码
stages:
  - build  # 定义流水线阶段为"构建"

build_job:
  tags:
    - CItest  # 匹配 Runner 的标签,确保任务被该 Runner 执行
  stage: build
  script:
    - echo "开始构建 Docker 镜像..."
    - docker build -t registry.abc.com:5000/nginx:v1 .  # 构建镜像并打标签
    - docker push registry.abc.com:5000/nginx:v1        # 推送到私有镜像仓库
    - docker rmi -f registry.abc.com:5000/nginx:v1      # 清理本地镜像(可选)

四、提交代码触发流水线

所有代码过程:

bash 复制代码
Activate the web console with: systemctl enable --now cockpit.socket

Last login: Thu Sep 25 22:38:29 2025 from 192.168.197.1
[root@host1 ~]# docker run -d \
  --name gitlab-runner \
  --restart always \
  -v /etc/hosts:/etc/hosts \                             
  -v /srv/gitlab-runner/config:/etc/gitlab-runner \                     
  -v /var/run/docker.sock:/var/run/docker.sock \                            
  gitlab/gitlab-runner:14.6.0
Unable to find image 'gitlab/gitlab-runner:14.6.0' locally
docker: Error response from daemon: Get "https://registry-1.docker.io/v2/": context deadline exceeded

Run 'docker run --help' for more information
[root@host1 ~]# ping registry-1.docker.io
PING registry-1.docker.io (199.16.158.9) 56(84) 比特的数据。
^Z
[1]+  已停止               ping registry-1.docker.io
[root@host1 ~]# vi /etc/docker/daemon.json
[root@host1 ~]# cat /etc/docker/daemon.json
{
  "registry-mirrors": [
    "https://9fbd5949cbc94e4a9581e33b9077c811.mirror.swr.myhuaweicloud.com",
    "https://jnh8ca4k.mirror.aliyuncs.com"
  ],
  "insecure-registries": [
    "192.168.197.9:5000"
  ],
  "live-restore": true
}
[root@host1 ~]# systemctl daemon-reload
[root@host1 ~]# systemctl restart docker
[root@host1 ~]# docker pull gitlab/gitlab-runner:14.6.0
Error response from daemon: Get "https://registry-1.docker.io/v2/": dial tcp 103.246.246.144:443: connect: connection refused
[root@host1 ~]# cat /etc/resolv.conf
# Generated by NetworkManager
nameserver 8.8.8.8
nameserver 114.114.114.114
[root@host1 ~]# ping registry-1.docker.io
PING registry-1.docker.io (98.159.108.57) 56(84) 比特的数据。
^Z
[2]+  已停止               ping registry-1.docker.io
[root@host1 ~]# systemctl stop firewalld
[root@host1 ~]# setenforce 0
[root@host1 ~]# vi /etc/docker/daemon.json
[root@host1 ~]# cat /etc/docker/daemon.json
{
  "registry-mirrors": [
    "https://9fbd5949cbc94e4a9581e33b9077c811.mirror.swr.myhuaweicloud.com",
    "https://jnh8ca4k.mirror.aliyuncs.com",
    "https://docker.mirrors.ustc.edu.cn"
  ],
  "insecure-registries": [
    "192.168.197.9:5000"
  ],
  "live-restore": true
}
[root@host1 ~]# systemctl daemon-reload
[root@host1 ~]# systemctl restart docker
[root@host1 ~]# docker pull gitlab/gitlab-runner:14.6.0
Error response from daemon: Get "https://registry-1.docker.io/v2/": context deadline exceeded
[root@host1 ~]# curl -v https://registry-1.docker.io/v2/
*   Trying 98.159.108.58:443...
*   Trying 2001::a2dc:ce2:443...
* Immediate connect fail for 2001::a2dc:ce2: 网络不可达
^Z
[3]+  已停止               curl -v https://registry-1.docker.io/v2/
[root@host1 ~]# vi /etc/docker/daemon.json
[root@host1 ~]# cat /etc/docker/daemon.json
{
  "registry-mirrors": [
    "https://9fbd5949cbc94e4a9581e33b9077c811.mirror.swr.myhuaweicloud.com",
    "https://jnh8ca4k.mirror.aliyuncs.com",
    "https://docker.mirrors.ustc.edu.cn",
    "https://docker.mirror.aliyuncs.com",
    "https://reg-mirror.qiniu.com",
    "https://f1361db2.m.daocloud.io"
  ],
  "insecure-registries": [
    "192.168.197.9:5000"
  ],
  "live-restore": true
}
[root@host1 ~]# systemctl daemon-reload
[root@host1 ~]# systemctl restart docker
[root@host1 ~]# docker pull gitlab/gitlab-runner:14.6.0
Error response from daemon: Get "https://registry-1.docker.io/v2/": net/http: request canceled while waiting for connection (Client.Timeout exceeded while awaiting headers)
[root@host1 ~]#  docker run -d \
  --name gitlab-runner \
  --restart always \
  -v /etc/hosts:/etc/hosts \                             
  -v /srv/gitlab-runner/config:/etc/gitlab-runner \                     
  -v /var/run/docker.sock:/var/run/docker.sock \                            
  gitlab/gitlab-runner:14.6.0
docker: invalid reference format

Run 'docker run --help' for more information
bash: -v: 未找到命令...
bash: -v: 未找到命令...
-bash: gitlab/gitlab-runner:14.6.0: 没有那个文件或目录
[root@host1 ~]# docker pull gitlab/gitlab-runner:14.6.0
Error response from daemon: Get "https://registry-1.docker.io/v2/": context deadline exceeded
[root@host1 ~]# docker images | grep gitlab-runner
[root@host1 ~]# docker pull gitlab/gitlab-runner
Using default tag: latest
latest: Pulling from gitlab/gitlab-runner
de66fc90c55d: Pull complete 
41d67aeda2be: Pull complete 
4d48ea5044a3: Pull complete 
d4dc7e0c6f85: Pull complete 
91a2731001cc: Pull complete 
Digest: sha256:4411906ada6b40b2ca259a72549a0c83883649d7b1e4c634d4d0dadf41b00785
Status: Downloaded newer image for gitlab/gitlab-runner:latest
docker.io/gitlab/gitlab-runner:latest
[root@host1 ~]# docker run -d --name gitlab-runner --restart always -v /etc/hosts:/etc/hosts -v /srv/gitlab-runner/config:/etc/gitlab-runner -v /var/run/docker.sock:/var/run/docker.sock gitlab/gitlab-runner:latest
981d3076234d516848eb65832ffc645b1f4b130f5a8273a5d01bdcadce931fc0
[root@host1 ~]# docker ps | grep gitlab-runner
981d3076234d   gitlab/gitlab-runner:latest    "/usr/bin/dumb-init ..."   57 seconds ago   Up 56 seconds                                                                                                     
                                gitlab-runner
[root@host1 ~]# docker exec -it gitlab-runner gitlab-runner register
Runtime platform                                    arch=amd64 os=linux pid=20 revision=139a0ac0 version=18.4.0
Running in system-mode.                            
                                                   
Enter the GitLab instance URL (for example, https://gitlab.com/):
http://gitlab.abc.com
Enter the registration token:
xtrus1yYddZf5RjYYuxF
Enter a description for the runner:
[981d3076234d]: Alltest
Enter tags for the runner (comma-separated):
CItest
Enter optional maintenance note for the runner:
docker
WARNING: Support for registration tokens and runner parameters in the 'register' command has been deprecated in GitLab Runner 15.6 and will be replaced with support for authentication tokens. For more information, see https://docs.gitlab.com/ci/runners/new_creation_workflow/ 
Registering runner... succeeded                     correlation_id=01K62VQD3GJ8TS35JBG1917T8H runner=xtrus1yYd
Enter an executor: docker-windows, docker+machine, docker-autoscaler, instance, custom, virtualbox, docker, kubernetes, shell, ssh, parallels:
docker
Enter the default Docker image (for example, ruby:3.3):
docker
Runner registered successfully. Feel free to start it, but if it's running already the config should be automatically reloaded!
 
Configuration (with the authentication token) was saved in "/etc/gitlab-runner/config.toml" 
[root@host1 ~]# vi /srv/gitlab-runner/config/config.toml
[root@host1 ~]# cat /srv/gitlab-runner/config/config.toml
concurrent = 1
check_interval = 0
shutdown_timeout = 0

[session_server]
  session_timeout = 1800

[[runners]]
  name = "Alltest"
  url = "http://gitlab.abc.com"
  id = 1
  token = "uSq9g8YdfxBnDvmj8zyx"
  token_obtained_at = 2025-09-26T11:14:55Z
  token_expires_at = 0001-01-01T00:00:00Z
  executor = "docker"
  [runners.cache]
    MaxUploadedArchiveSize = 0
    [runners.cache.s3]
    [runners.cache.gcs]
    [runners.cache.azure]
  [runners.docker]
    tls_verify = false
    image = "docker"
    privileged = false
    disable_entrypoint_overwrite = false
    oom_kill_disable = false
    disable_cache = false
    volumes = ["/cache"]
    shm_size = 0
    network_mtu = 0
    extra_hosts = ["gitlab.abc.com:192.168.197.9"]
    volumes = ["/var/run/docker.sock:/var/run/docker.sock", "/cache"]
[root@host1 ~]# vi /srv/gitlab-runner/config/config.toml
[root@host1 ~]# cat /srv/gitlab-runner/config/config.toml
concurrent = 1
check_interval = 0
shutdown_timeout = 0

[session_server]
  session_timeout = 1800

[[runners]]
  name = "Alltest"
  url = "http://gitlab.abc.com"
  id = 1
  token = "uSq9g8YdfxBnDvmj8zyx"
  token_obtained_at = 2025-09-26T11:14:55Z
  token_expires_at = 0001-01-01T00:00:00Z
  executor = "docker"
  [runners.cache]
    MaxUploadedArchiveSize = 0
    [runners.cache.s3]
    [runners.cache.gcs]
    [runners.cache.azure]
  [runners.docker]
    tls_verify = false
    image = "docker"
    privileged = false
    disable_entrypoint_overwrite = false
    oom_kill_disable = false
    disable_cache = false
    volumes = ["/var/run/docker.sock:/var/run/docker.sock", "/cache"]
    shm_size = 0
    network_mtu = 0
    extra_hosts = ["gitlab.abc.com:192.168.197.9"]
[root@host1 ~]# docker restart gitlab-runner
gitlab-runner
[root@host1 ~]# cd nginx-demo
-bash: cd: nginx-demo: 没有那个文件或目录
[root@host1 ~]# docker exec -it gitlab-runner gitlab-runner list
Runtime platform                                    arch=amd64 os=linux pid=20 revision=139a0ac0 version=18.4.0
Listing configured runners                          ConfigFile=/etc/gitlab-runner/config.toml
Alltest                                             Executor=docker Token=uSq9g8YdfxBnDvmj8zyx URL=http://gitlab.abc.com
[root@host1 ~]# docker exec -it gitlab-runner ping -c 2 gitlab.abc.com
OCI runtime exec failed: exec failed: unable to start container process: exec: "ping": executable file not found in $PATH: unknown
[root@host1 ~]# docker exec -it gitlab-runner docker --version
OCI runtime exec failed: exec failed: unable to start container process: exec: "docker": executable file not found in $PATH: unknown
[root@host1 ~]# ls -l /root
总用量 3456092
-rw-r--r--. 1 root root   15727668  9月  3 15:43 aliyun-cli-linux-latest-amd64.tgz
-rw-r--r--. 1 root root   15727668  9月  3 15:43 aliyun-cli-linux-latest-amd64.tgz.1
-rw-------. 1 root root        989  9月  4 23:55 anaconda-ks.cfg
-rw-r--r--. 1 root root 3500064525  9月 10 22:50 centos-local-rootfs.tar.gz
drwxr-xr-x. 3 root root         24  9月  8 14:16 ch02
drwxr-xr-x. 3 root root         24  9月 25 23:22 ch07
-rw-r--r--. 1 root root        752  9月 17 12:47 compose.yaml
-rw-r--r--. 1 root root    7506199  9月 15 23:25 data
drwxr-xr-x. 7 root root         91  9月 24 17:06 django-nginx-uwsgi-mysql
drwxr-xr-x. 3 root root        102  9月 17 14:08 django-pg
drwxr-xr-x. 3 root root         42  9月 10 23:12 dockerfile-test
drwxr-xr-x. 3 root root        110  9月 24 13:48 flask-postgres
drwxr-xr-x. 2 root root         24  9月 19 23:18 fx-vnc
drwxr-xr-x. 3 root root         24  9月 21 23:11 java-projects
drwxr-xr-x. 3 root root         32  9月 21 22:58 maven-mirror-test
drwxr-xr-x. 2 root root         39  9月 20 23:30 multi-build
drwxr-xr-x. 3 root root        128  9月 17 23:01 multi-test
drwxr-xr-x. 2 root root         26  9月 17 12:09 mywordpress
drwxr-xr-x. 5 root root        138  9月 21 01:02 nodejs-mongo
drwxr-xr-x. 5 root root        102  9月 15 10:43 php-nginx-supervisord
drwxr-xr-x. 3 root root         26  9月 22 09:58 projects
drwxr-xr-x. 3 root root        101  9月 17 22:17 python-web
drwxr-xr-x. 2 root root         52  9月 18 19:23 scratch-img
drwxr-xr-x. 3 root root         20  9月 12 14:41 source
drwxr-xr-x. 4 root root         50  9月 22 13:33 spring-boot
[root@host1 ~]# mkdir -p /root/nginx-demo
[root@host1 ~]# cd /root/nginx-demo
[root@host1 nginx-demo]# vi .gitlab-ci.yml
[root@host1 nginx-demo]# cat .gitlab-ci.yml
stages:
  - build  # 定义流水线阶段为"构建"

build_job:
  tags:
    - CItest  # 匹配 Runner 的标签,确保任务被该 Runner 执行
  stage: build
  script:
    - echo "开始构建 Docker 镜像..."
    - docker build -t registry.abc.com:5000/nginx:v1 .  # 构建镜像并打标签
    - docker push registry.abc.com:5000/nginx:v1        # 推送到私有镜像仓库
    - docker rmi -f registry.abc.com:5000/nginx:v1      # 清理本地镜像(可选)
[root@host1 nginx-demo]# git add .gitlab-ci.yml
致命错误:不是 git 仓库(或者任何父目录):.git
[root@host1 nginx-demo]# cd /root/nginx-demo
[root@host1 nginx-demo]# git init
提示: 使用 'master' 作为初始分支的名称。这个默认分支名称可能会更改。要在新仓库中
提示: 配置使用初始分支名,并消除这条警告,请执行:
提示:
提示: git config --global init.defaultBranch <名称>
提示:
提示: 除了 'master' 之外,通常选定的名字有 'main'、'trunk' 和 'development'。
提示: 可以通过以下命令重命名刚创建的分支:
提示:
提示: git branch -m <name>
已初始化空的 Git 仓库于 /root/nginx-demo/.git/
[root@host1 nginx-demo]# vi Dockerfile
[root@host1 nginx-demo]# cat Dockerfile
FROM nginx:latest

RUN echo "<h1>Hello from GitLab CI/CD!</h1>" > /usr/share/nginx/html/index.html
[root@host1 nginx-demo]# git add .gitlab-ci.yml
[root@host1 nginx-demo]# git commit -m "添加 CI/CD 流水线配置"
[master(根提交) e86411f] 添加 CI/CD 流水线配置
 1 file changed, 12 insertions(+)
 create mode 100644 .gitlab-ci.yml
[root@host1 nginx-demo]# git push origin main
错误:源引用规格 main 没有匹配
错误:无法推送一些引用到 'origin'
[root@host1 nginx-demo]# git remote add origin http://gitlab.abc.com/root/nginx-demo.git
[root@host1 nginx-demo]# git push -u origin master:main
Username for 'http://gitlab.abc.com': root
Password for 'http://root@gitlab.abc.com': 
To http://gitlab.abc.com/root/nginx-demo.git
 ! [rejected]        master -> main (fetch first)
错误:无法推送一些引用到 'http://gitlab.abc.com/root/nginx-demo.git'
提示: 更新被拒绝,因为远程仓库包含您本地尚不存在的提交。这通常是因为另外
提示: 一个仓库已向该引用进行了推送。如果您希望先与远程变更合并,请在推送
提示: 前执行 'git pull'。
提示: 详见 'git push --help' 中的 'Note about fast-forwards' 小节。

1、解决 Git 推送冲突(远程仓库与本地仓库历史不相关)

由于 GitLab 上的 nginx-demo 项目可能包含初始化提交(如 README),本地新仓库需先拉取远程内容并合并:

bash 复制代码
[root@host1 nginx-demo]# git pull origin main --allow-unrelated-histories
Username for 'http://gitlab.abc.com': root
Password for 'http://root@gitlab.abc.com': 
remote: Enumerating objects: 6, done.
remote: Counting objects: 100% (6/6), done.
remote: Compressing objects: 100% (4/4), done.
remote: Total 6 (delta 0), reused 0 (delta 0), pack-reused 0
展开对象中: 100% (6/6), 520 字节 | 130.00 KiB/s, 完成.
来自 http://gitlab.abc.com/root/nginx-demo
 * branch            main       -> FETCH_HEAD
 * [新分支]          main       -> origin/main
提示: 您有偏离的分支,需要指定如何调和它们。您可以在执行下一次
提示: pull 操作之前执行下面一条命令来抑制本消息:
提示:
提示:   git config pull.rebase false  # 合并
提示:   git config pull.rebase true   # 变基
提示:   git config pull.ff only       # 仅快进
提示:
提示: 您可以将 "git config" 替换为 "git config --global" 以便为所有仓库设置
提示: 缺省的配置项。您也可以在每次执行 pull 命令时添加 --rebase、--no-rebase,
提示: 或者 --ff-only 参数覆盖缺省设置。
致命错误:需要指定如何调和偏离的分支。
[root@host1 nginx-demo]# git pull origin main --allow-unrelated-histories --no-rebase
Username for 'http://gitlab.abc.com': root
Password for 'http://root@gitlab.abc.com': 
来自 http://gitlab.abc.com/root/nginx-demo
 * branch            main       -> FETCH_HEAD
错误:工作区中下列未跟踪的文件将会因为合并操作而被覆盖:
Dockerfile
请在合并前移动或删除。
正在终止
使用策略 ort 合并失败。
[root@host1 nginx-demo]# git stash push -u -m "临时保存本地创建的 Dockerfile"
保存工作目录和索引状态 On master: 临时保存本地创建的 Dockerfile
[root@host1 nginx-demo]# git pull origin main --no-rebase
Username for 'http://gitlab.abc.com': root
Password for 'http://root@gitlab.abc.com': 
来自 http://gitlab.abc.com/root/nginx-demo
 * branch            main       -> FETCH_HEAD
致命错误:拒绝合并无关的历史
[root@host1 nginx-demo]# git pull origin main --no-rebase --allow-unrelated-histories
Username for 'http://gitlab.abc.com': root
Password for 'http://root@gitlab.abc.com': 
来自 http://gitlab.abc.com/root/nginx-demo
 * branch            main       -> FETCH_HEAD
Merge made by the 'ort' strategy.
 Dockerfile | 2 ++
 README.md  | 2 ++
 2 files changed, 4 insertions(+)
 create mode 100644 Dockerfile
 create mode 100644 README.md
[root@host1 nginx-demo]# git stash pop
已经是最新的。
Dockerfile already exists, no checkout
错误:无法从贮藏条目中恢复未跟踪文件
位于分支 master
无文件要提交,干净的工作区
贮藏条目被保留以备您再次需要。
[root@host1 nginx-demo]# git status
位于分支 master
无文件要提交,干净的工作区
[root@host1 nginx-demo]# git show stash@{0}:Dockerfile
致命错误:路径 'Dockerfile' 在磁盘上,但是不在 'stash@{0}' 中
[root@host1 nginx-demo]# mv Dockerfile Dockerfile.remote
[root@host1 nginx-demo]# git stash pop
已经是最新的。
位于分支 master
尚未暂存以备提交的变更:
  (使用 "git add <文件>..." 更新要提交的内容)
  (使用 "git restore <文件>..." 丢弃工作区的改动)
修改:     Dockerfile

未跟踪的文件:
  (使用 "git add <文件>..." 以包含要提交的内容)
Dockerfile.remote

修改尚未加入提交(使用 "git add" 和/或 "git commit -a")
丢弃了 refs/stash@{0}(5686d6ff25a8c8b79cacbb128241199205e4d312)
[root@host1 nginx-demo]# git push -u origin master:main
Username for 'http://gitlab.abc.com': ^Z
[4]+  已停止               git push -u origin master:main
[root@host1 nginx-demo]# git add .
[root@host1 nginx-demo]# git commit -m "Restore local Dockerfile and add backup of remote version"
[master d3b0b2a] Restore local Dockerfile and add backup of remote version
 2 files changed, 5 insertions(+), 2 deletions(-)
 create mode 100644 Dockerfile.remote
[root@host1 nginx-demo]# git push -u origin master:main
Username for 'http://gitlab.abc.com': root
Password for 'http://root@gitlab.abc.com': 
枚举对象中: 10, 完成.
对象计数中: 100% (10/10), 完成.
使用 8 个线程进行压缩
压缩对象中: 100% (7/7), 完成.
写入对象中: 100% (8/8), 1.19 KiB | 1.19 MiB/s, 完成.
总共 8(差异 1),复用 0(差异 0),包复用 0(来自  0 个包)
To http://gitlab.abc.com/root/nginx-demo.git
   a45c14a..d3b0b2a  master -> main
分支 'master' 设置为跟踪 'origin/main'。

这次推送一定会成功!推送完成后:

  1. 登录 GitLab,进入 nginx-demo 项目,你会看到 DockerfileDockerfile.remote 都已更新。

  2. GitLab CI/CD 流水线会被自动触发。

  3. 你可以在「CI/CD」→「流水线」页面查看你的 build_job 任务是否由 GitLab Runner 成功执行。

2、启动私有 Docker 镜像仓库(确保 docker push 有目标地址)

若还未启动私有仓库 registry.abc.com:5000,需先运行 Docker Registry 容器:

bash 复制代码
[root@host1 nginx-demo]# docker run -d -p 5000:5000 --restart always --name registry registry:2
Unable to find image 'registry:2' locally
2: Pulling from library/registry
44cf07d57ee4: Pull complete 
bbbdd6c6894b: Pull complete 
8e82f80af0de: Pull complete 
3493bf46cdec: Pull complete 
6d464ea18732: Pull complete 
Digest: sha256:a3d8aaa63ed8681a604f1dea0aa03f100d5895b6a58ace528858a7b332415373
Status: Downloaded newer image for registry:2
591ba633d6dd2dffddc6c763384d85245e36ef5bd8628a89852da1d57a7cb2fa
docker: Error response from daemon: failed to set up container networking: driver failed programming external connectivity on endpoint registry (87acd823aad49fa3f211f9ba60969b6ae43fe0da5c6b08f22ee572dc2b2f1c64): Bind for 0.0.0.0:5000 failed: port is already allocated

Run 'docker run --help' for more information
[root@host1 nginx-demo]# netstat -tulnp | grep :5000
tcp        0      0 0.0.0.0:5000            0.0.0.0:*               LISTEN      139593/docker-proxy 
tcp6       0      0 :::5000                 :::*                    LISTEN      139602/docker-proxy 
[root@host1 nginx-demo]# docker rm -f registry
registry
[root@host1 nginx-demo]# docker run -d -p 5001:5000 --restart always --name registry registry:2
9da64ff242bf253db9911eb48b374ba826a7dc05f400d40fb4d174aa67019529
[root@host1 nginx-demo]# vi /etc/docker/daemon.json
[root@host1 nginx-demo]# cat /etc/docker/daemon.json
{
  "registry-mirrors": [
    "https://9fbd5949cbc94e4a9581e33b9077c811.mirror.swr.myhuaweicloud.com",
    "https://jnh8ca4k.mirror.aliyuncs.com",
    "https://docker.mirrors.ustc.edu.cn",
    "https://docker.mirror.aliyuncs.com",
    "https://reg-mirror.qiniu.com",
    "https://f1361db2.m.daocloud.io"
  ],
  "insecure-registries": [
    "192.168.197.9:5001"
  ],
  "live-restore": true
}
[root@host1 nginx-demo]# systemctl daemon-reload
[root@host1 nginx-demo]# systemctl restart docker
[root@host1 nginx-demo]# curl http://192.168.197.9:5001/v2/_catalog
{"repositories":[]}
[root@host1 nginx-demo]# vi /root/nginx-demo/.gitlab-ci.yml
[root@host1 nginx-demo]# cat /root/nginx-demo/.gitlab-ci.yml
stages:
  - build  # 定义流水线阶段为"构建"

build_job:
  tags:
    - CItest  # 匹配 Runner 的标签,确保任务被该 Runner 执行
  stage: build
  script:
    - echo "开始构建 Docker 镜像..."
    - docker build -t registry.abc.com:5001/nginx:v1 .  # 构建镜像并打标签
    - docker push registry.abc.com:5001/nginx:v1        # 推送到私有镜像仓库
    - docker rmi -f registry.abc.com:5001/nginx:v1      # 清理本地镜像(可选)
[root@host1 nginx-demo]# git add .gitlab-ci.yml
[root@host1 nginx-demo]# git commit -m "update private registry port to 5001 in CI/CD"
[master 2b8ae36] update private registry port to 5001 in CI/CD
 1 file changed, 3 insertions(+), 3 deletions(-)
[root@host1 nginx-demo]# git push origin master:main
Username for 'http://gitlab.abc.com': root
Password for 'http://root@gitlab.abc.com': 
枚举对象中: 5, 完成.
对象计数中: 100% (5/5), 完成.
使用 8 个线程进行压缩
压缩对象中: 100% (3/3), 完成.
写入对象中: 100% (3/3), 317 字节 | 317.00 KiB/s, 完成.
总共 3(差异 2),复用 0(差异 0),包复用 0(来自  0 个包)
To http://gitlab.abc.com/root/nginx-demo.git
   d3b0b2a..2b8ae36  master -> main

!!!纠错:出现 "port is already allocated" 错误,核心原因是 服务器的 5000 端口已被其他进程占用。需先找到占用端口的进程,再通过 "停止占用进程" 或 "修改私有仓库端口" 两种方案解决(本文选择第二种)

3、验证 CI/CD 流水线执行

查看 GitLab 流水线状态

登录 GitLab(http://gitlab.abc.com)→ 进入 nginx-demo 项目 → 左侧「CI/CD」→「流水线」,确认流水线状态为「Running」或「Passed」。

检查私有仓库镜像

若流水线执行成功,可查看私有仓库中是否有推送的镜像:

bash 复制代码
# 查看仓库中所有镜像仓库
[root@host1 nginx-demo]# curl http://192.168.197.9:5000/v2/_catalog
{"repositories":["hello-world"]}
# 查看 nginx 镜像的标签列表
[root@host1 nginx-demo]# curl http://192.168.197.9:5000/v2/nginx/tags/list
{"errors":[{"code":"NAME_UNKNOWN","message":"repository name not known to registry","detail":{"name":"nginx"}}]}

4、(可选)修复 GitLab Runner 执行命令报错(ping/docker 命令不存在)

若需在 Runner 容器内执行 pingdocker 命令调试,需进入容器时指定包含工具的镜像 (如 ubuntu):

bash 复制代码
[root@host1 nginx-demo]# docker exec -it --rm -w /etc/gitlab-runner gitlab-runner /bin/bash
unknown flag: --rm

Usage:  docker exec [OPTIONS] CONTAINER COMMAND [ARG...]

Run 'docker exec --help' for more information
[root@host1 nginx-demo]# docker exec -it -w /etc/gitlab-runner gitlab-runner /bin/bash
root@981d3076234d:/etc/gitlab-runner# ping gitlab.abc.com
bash: ping: command not found
root@981d3076234d:/etc/gitlab-runner# apk update
bash: apk: command not found
root@981d3076234d:/etc/gitlab-runner# apt update
Get:1 http://archive.ubuntu.com/ubuntu noble InRelease [256 kB]                                     
Get:2 http://security.ubuntu.com/ubuntu noble-security InRelease [126 kB]                           
Get:3 http://archive.ubuntu.com/ubuntu noble-updates InRelease [126 kB]
Get:4 http://security.ubuntu.com/ubuntu noble-security/restricted amd64 Packages [2376 kB]
Get:5 http://archive.ubuntu.com/ubuntu noble-backports InRelease [126 kB]
Get:6 http://archive.ubuntu.com/ubuntu noble/universe amd64 Packages [19.3 MB]
Get:7 http://archive.ubuntu.com/ubuntu noble/multiverse amd64 Packages [331 kB]                     
Get:8 http://archive.ubuntu.com/ubuntu noble/main amd64 Packages [1808 kB]                          
Get:9 http://archive.ubuntu.com/ubuntu noble/restricted amd64 Packages [117 kB]                     
Get:10 http://archive.ubuntu.com/ubuntu noble-updates/universe amd64 Packages [1923 kB]             
Get:11 http://archive.ubuntu.com/ubuntu noble-updates/multiverse amd64 Packages [38.9 kB]           
Get:12 http://archive.ubuntu.com/ubuntu noble-updates/restricted amd64 Packages [2483 kB]           
Get:13 http://security.ubuntu.com/ubuntu noble-security/main amd64 Packages [1474 kB]               
Get:14 http://archive.ubuntu.com/ubuntu noble-updates/main amd64 Packages [1828 kB]                 
Get:15 http://archive.ubuntu.com/ubuntu noble-backports/universe amd64 Packages [35.6 kB]           
Get:16 http://archive.ubuntu.com/ubuntu noble-backports/main amd64 Packages [48.8 kB]               
Get:17 http://security.ubuntu.com/ubuntu noble-security/multiverse amd64 Packages [34.6 kB]         
Get:18 http://security.ubuntu.com/ubuntu noble-security/universe amd64 Packages [1136 kB]           
Fetched 33.6 MB in 13s (2509 kB/s)                                                                  
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
8 packages can be upgraded. Run 'apt list --upgradable' to see them.
root@981d3076234d:/etc/gitlab-runner# apt install -y iputils-ping
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
The following additional packages will be installed:
  libcap2-bin libpam-cap
The following NEW packages will be installed:
  iputils-ping libcap2-bin libpam-cap
0 upgraded, 3 newly installed, 0 to remove and 8 not upgraded.
Need to get 91.2 kB of archives.
After this operation, 322 kB of additional disk space will be used.
Get:1 http://archive.ubuntu.com/ubuntu noble-updates/main amd64 libcap2-bin amd64 1:2.66-5ubuntu2.2 [34.2 kB]
Get:2 http://archive.ubuntu.com/ubuntu noble-updates/main amd64 iputils-ping amd64 3:20240117-1ubuntu0.1 [44.6 kB]
Get:3 http://archive.ubuntu.com/ubuntu noble-updates/main amd64 libpam-cap amd64 1:2.66-5ubuntu2.2 [12.5 kB]
Fetched 91.2 kB in 2s (39.7 kB/s)    
debconf: delaying package configuration, since apt-utils is not installed
Selecting previously unselected package libcap2-bin.
(Reading database ... 8798 files and directories currently installed.)
Preparing to unpack .../libcap2-bin_1%3a2.66-5ubuntu2.2_amd64.deb ...
Unpacking libcap2-bin (1:2.66-5ubuntu2.2) ...
Selecting previously unselected package iputils-ping.
Preparing to unpack .../iputils-ping_3%3a20240117-1ubuntu0.1_amd64.deb ...
Unpacking iputils-ping (3:20240117-1ubuntu0.1) ...
Selecting previously unselected package libpam-cap:amd64.
Preparing to unpack .../libpam-cap_1%3a2.66-5ubuntu2.2_amd64.deb ...
Unpacking libpam-cap:amd64 (1:2.66-5ubuntu2.2) ...
Setting up libcap2-bin (1:2.66-5ubuntu2.2) ...
Setting up libpam-cap:amd64 (1:2.66-5ubuntu2.2) ...
debconf: unable to initialize frontend: Dialog
debconf: (No usable dialog-like program is installed, so the dialog based frontend cannot be used. at /usr/share/perl5/Debconf/FrontEnd/Dialog.pm line 79.)
debconf: falling back to frontend: Readline
Setting up iputils-ping (3:20240117-1ubuntu0.1) ...
root@981d3076234d:/etc/gitlab-runner# ping -c 2 gitlab.abc.com
PING gitlab.abc.com (192.168.197.9) 56(84) bytes of data.
64 bytes from gitlab.abc.com (192.168.197.9): icmp_seq=1 ttl=64 time=0.083 ms
64 bytes from gitlab.abc.com (192.168.197.9): icmp_seq=2 ttl=64 time=0.066 ms

--- gitlab.abc.com ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1002ms
rtt min/avg/max/mdev = 0.066/0.074/0.083/0.008 ms
root@981d3076234d:/etc/gitlab-runner# docker --version
bash: docker: command not found
root@981d3076234d:/etc/gitlab-runner# exit
exit
[root@host1 nginx-demo]# vi .gitlab-ci.yml
[root@host1 nginx-demo]# cat .gitlab-ci.yml
stages:
  - build

build_job:
  tags:
    - CItest
  stage: build
  
  # 关键配置:指定执行此任务的容器镜像
  image: docker:latest
  
  # 关键配置:如果需要在构建脚本中使用 docker 命令,通常需要 dind 服务
  services:
    - docker:dind

  script:
    - echo "开始构建 Docker 镜像..."
    - docker --version  # 现在这行命令会在 docker:latest 容器中成功执行
    - docker build -t registry.abc.com:5001/nginx:v1 .
    - docker push registry.abc.com:5001/nginx:v1
    - docker rmi -f registry.abc.com:5001/nginx:v1
[root@host1 nginx-demo]# docker --version
Docker version 28.4.0, build d8eb465

!!!核心逻辑总结

  1. Git 冲突解决 :通过 --allow-unrelated-histories 拉取合并远程仓库,确保本地提交能推送到远程;

  2. 私有仓库依赖 :必须先启动 Docker Registry,否则 docker push 步骤会失败;

  3. Runner 调试 :若需容器内执行系统命令,需进入时指定带工具的基础镜像(如 ubuntu

五、总结过程!!!:

bash 复制代码
以下是整个过程的详细总结和可执行的代码操作。

### 核心目标

在一台 Linux 服务器上,通过 Docker 部署 GitLab Runner,并配置它来自动构建、测试和推送一个简单的 Nginx Web 应用的 Docker 镜像到私有仓库。

### 环境准备与前提条件

1.  **服务器**: 一台安装了 Docker 和 Docker Compose 的 Linux 服务器。
2.  **GitLab**: 一个可用的 GitLab 实例(在本案例中为 `http://gitlab.abc.com`)。
3.  **网络**: 服务器可以访问互联网(用于拉取 Docker 镜像),并且 GitLab 实例和服务器之间网络互通。

---

### 第一阶段:配置 Docker 环境与 GitLab Runner

这一阶段的目标是让服务器能够顺畅地拉取镜像,并成功启动一个 GitLab Runner 容器。

#### 步骤 1:配置 Docker 镜像加速和不安全仓库

解决国内网络拉取镜像慢的问题,并允许 Docker 向本地私有仓库推送镜像。

```bash
# 1. 创建或编辑 Docker 配置文件
vi /etc/docker/daemon.json
```

将以下内容粘贴到文件中。**请将 `192.168.197.9` 替换为你的服务器 IP**。

```json
{
  "registry-mirrors": [
    "https://9fbd5949cbc94e4a9581e33b9077c811.mirror.swr.myhuaweicloud.com",
    "https://jnh8ca4k.mirror.aliyuncs.com",
    "https://docker.mirrors.ustc.edu.cn"
  ],
  "insecure-registries": [
    "192.168.197.9:5001"  // 假设私有仓库端口为 5001
  ],
  "live-restore": true
}
```

```bash
# 2. 重新加载配置并重启 Docker 服务
systemctl daemon-reload
systemctl restart docker
```

#### 步骤 2:启动 GitLab Runner 容器

使用 Docker 运行 GitLab Runner,并挂载必要的目录,特别是 Docker 套接字,以便 Runner 能够操作宿主机的 Docker。

```bash
# 拉取最新的 GitLab Runner 镜像
docker pull gitlab/gitlab-runner:latest

# 启动 GitLab Runner 容器
docker run -d \
  --name gitlab-runner \
  --restart always \
  -v /srv/gitlab-runner/config:/etc/gitlab-runner \
  -v /var/run/docker.sock:/var/run/docker.sock \
  gitlab/gitlab-runner:latest
```

#### 步骤 3:注册 GitLab Runner

将启动的 Runner 容器注册到你的 GitLab 实例上。

```bash
# 进入 Runner 容器内部执行注册命令
docker exec -it gitlab-runner gitlab-runner register
```

根据提示依次输入以下信息:
1.  **GitLab 实例 URL**: `http://gitlab.abc.com`
2.  **Registration token**: 从 GitLab 项目的 `Settings > CI/CD > Runners` 页面获取。
3.  **Runner description**: `Alltest` (自定义)
4.  **Runner tags**: `CItest` (自定义,非常重要,用于匹配任务)
5.  **Executor**: `docker`
6.  **Default Docker image**: `docker:latest` (推荐,因为它包含 `docker` 命令)

#### 步骤 4:修正 Runner 配置

注册后,需要手动编辑配置文件,添加域名解析和确保 Docker 套接字挂载正确。

```bash
# 编辑宿主机上的 Runner 配置文件
vi /srv/gitlab-runner/config/config.toml
```

找到 `[[runners]]` 下的 `[runners.docker]` 部分,确保它包含以下关键配置:

```toml
[[runners]]
  # ... 其他配置 ...
  executor = "docker"
  [runners.docker]
    tls_verify = false
    image = "docker:latest"
    privileged = false
    disable_entrypoint_overwrite = false
    oom_kill_disable = false
    disable_cache = false
    volumes = ["/var/run/docker.sock:/var/run/docker.sock", "/cache"] # 确保这一行正确
    shm_size = 0
    extra_hosts = ["gitlab.abc.com:192.168.197.9"] # 添加这一行,解决域名解析问题
```

```bash
# 重启 Runner 容器使配置生效
docker restart gitlab-runner
```

---

### 第二阶段:创建项目与配置流水线

这一阶段的目标是在 GitLab 上创建一个项目,并定义 CI/CD 流水线。

#### 步骤 1:在 GitLab 上创建项目

1.  登录 GitLab。
2.  创建一个名为 `nginx-demo` 的新项目。

#### 步骤 2:在本地初始化项目并关联远程仓库

```bash
# 1. 创建项目目录并进入
mkdir -p /root/nginx-demo
cd /root/nginx-demo

# 2. 初始化 Git 仓库
git init

# 3. 创建 Dockerfile
cat > Dockerfile << 'EOF'
FROM nginx:latest
RUN echo "<h1>Hello from GitLab CI/CD!</h1>" > /usr/share/nginx/html/index.html
EOF

# 4. 创建 .gitlab-ci.yml 流水线配置文件
cat > .gitlab-ci.yml << 'EOF'
stages:
  - build

build_job:
  tags:
    - CItest
  stage: build
  image: docker:latest
  services:
    - docker:dind
  script:
    - echo "开始构建 Docker 镜像..."
    - docker build -t 192.168.197.9:5001/nginx-demo:${CI_COMMIT_SHORT_SHA} .
    - docker push 192.168.197.9:5001/nginx-demo:${CI_COMMIT_SHORT_SHA}
    - echo "镜像推送成功: 192.168.197.9:5001/nginx-demo:${CI_COMMIT_SHORT_SHA}"
EOF

# 5. 添加所有文件并提交
git add .
git commit -m "Initial commit: add Dockerfile and .gitlab-ci.yml"

# 6. 关联远程 GitLab 仓库 (请替换为你的项目地址)
git remote add origin http://gitlab.abc.com/root/nginx-demo.git

# 7. 推送代码 (首次推送可能需要解决分支名和历史问题)
git push -u origin master:main
```
> **注意**: 上述 `git push` 命令如果遇到 "拒绝合并无关的历史" 或 "分支名不匹配" 的错误,请参考前面的对话,使用 `git pull --allow-unrelated-histories` 等命令解决。

---

### 第三阶段:启动私有镜像仓库并测试流水线

这一阶段的目标是提供一个镜像仓库,并最终看到流水线成功运行。

#### 步骤 1:启动 Docker Registry 私有仓库

```bash
# 检查 5000 端口是否被占用,如果被占用则使用其他端口如 5001
ss -tulnp | grep :5000

# 启动 Registry 容器,映射端口 5001
docker run -d -p 5001:5000 --restart always --name registry registry:2
```

#### 步骤 2:验证流水线执行

1.  **推送代码**: 完成上述所有步骤后,最后一次 `git push` 会自动触发 GitLab CI/CD 流水线。
2.  **查看结果**: 登录 GitLab,进入 `nginx-demo` 项目,导航到 `CI/CD > Pipelines`。你应该能看到一条流水线正在运行 (`Running`),稍等片刻,它会变为成功 (`Passed`)。
3.  **检查日志**: 点击流水线中的 `build_job`,查看详细的作业日志,确认每一步(`docker build`, `docker push`)都成功执行。
4.  **验证镜像**: 在服务器上执行以下命令,确认镜像已被成功推送到私有仓库。
    ```bash
    curl http://192.168.197.9:5001/v2/nginx-demo/tags/list
    ```
    如果成功,会返回类似 `{"name":"nginx-demo","tags":["<commit-sha>"]}` 的 JSON 响应。

### 总结

至此,你已经成功搭建了一个完整的 GitLab CI/CD 环境。每当你向 `nginx-demo` 项目的 `main` 分支推送代码时,GitLab Runner 都会自动执行以下操作:
1.  拉取最新的代码。
2.  启动一个包含 `docker` 命令的临时容器。
3.  在该容器内,基于 `Dockerfile` 构建一个新的 Nginx 镜像。
4.  将构建好的镜像推送到你本地的私有仓库 `192.168.197.9:5001`。

这个流程可以轻松扩展,加入测试(`test`)、代码质量检查(`lint`)、部署(`deploy`)等更多阶段,实现完整的 DevOps 自动化。
相关推荐
伐尘2 小时前
[群晖NAS] 群晖Docker安装gitlab + ipv6 远程访问
docker·gitlab·群晖·nas
hkhkhkhkh1232 小时前
Git push 失败(remote unpack failed: Missing tree)解决方案
linux·git
Eloudy2 小时前
制作 Bash Shell 方式的软件发布安装包的原理和方法
linux·bash
霖.242 小时前
K8s实践中的重点知识
linux·云原生·kubernetes
truesnow2 小时前
速通 awk:一篇文章带你理解 awk 原理,大量实战案例让你马上成为 awk 专家
linux
运维栈记3 小时前
自动化运维利器:MCP Server + 阿里云
运维·自动化
Rinleren3 小时前
DevOps 工具链:CI/CD 概念解析 + Git 版本控制 + GitLab 仓库 + Jenkins 自动化全教程
自动化·gitlab·jenkins
Lyre丶3 小时前
Ubuntu 24.04 LTS 安装GAMIT
linux·经验分享·学习·ubuntu·gamit
namekong83 小时前
ubuntu 通过下面几种方式查看系统 重启时间/开机时间:
linux·运维·ubuntu