GitLab_CI/CD_自动化部署完全指南

🚀 GitLab + CI/CD 自动化部署完全指南

适用场景:Win11 电脑 + VMware 虚拟机 + Ubuntu Server 24.04,从零搭建 GitLab 并实现 Java + Vue 全栈项目的自动化 CI/CD 部署。

阅读提示:本文档为"傻瓜式"教程,请严格按照顺序执行,遇到报错先看"排错大全"。如果看不懂,不是你的问题,是我写得还不够傻瓜!😄


📑 导航目录


🎯 写在前面:为什么要折腾这个?

想象一下这个场景:

你写了一段代码,提交到 Git,然后——

  • 手动打开服务器
  • 手动拉代码
  • 手动编译 Java
  • 手动构建 Vue
  • 手动复制到 Nginx 目录
  • 手动重启服务
  • 发现报错了,回滚,再来一遍…

累不累? 😫

而有了 CI/CD(持续集成/持续部署),流程变成:

你写了一段代码,git push → 自动编译 → 自动测试 → 自动部署 → 浏览器刷新,新功能上线了!🎉

这就是本文档要带你实现的目标。 跟着做,保证你能搭起来。如果搭不起来……来,先看看是不是哪一步偷偷跳过了!👀


📦 环境准备

硬件要求

资源最低要求推荐配置备注
CPU2 核4 核GitLab 很能吃
内存4 GB8 GB低于 4G 启动极慢
磁盘40 GB80 GBGitLab 初始化就要几十 G
网络能上网能上网需要拉镜像

⚠️ 血泪教训:磁盘一定要给够!GitLab 首次初始化就像个饕餮,空间不够直接罢工给你看。

软件清单

软件版本作用
Win11任意你的主力开发机
VMware Workstation最新版跑 Ubuntu 虚拟机
Ubuntu Server24.04 LTS服务器系统
GitLab CElatest代码仓库 + CI/CD 平台
Dockerdocker.io容器化部署
Nginx最新版反向代理 + 静态文件服务

网络架构

┌─────────────────────────────────────────────────────────────┐
│                        Win11 开发机                          │
│  ┌──────────────┐    git push    ┌──────────────────────┐   │
│  │  VS Code     │ ─────────────→ │  GitLab Web (8080)   │   │
│  │  Git Bash    │                │  查看流水线状态       │   │
│  └──────────────┘                └──────────────────────┘   │
└─────────────────────────────────────────────────────────────┘
                              │
                              │ 桥接模式(同局域网)
                              ▼
┌─────────────────────────────────────────────────────────────┐
│              Ubuntu Server 24.04 (VMware 虚拟机)             │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────────────┐ │
│  │  GitLab CE  │  │   Nginx     │  │  GitLab Runner      │ │
│  │  (Docker)   │  │   (80端口)   │  │  (Docker + Shell)   │ │
│  │  8080:80    │  │             │  │                     │ │
│  └─────────────┘  └─────────────┘  └─────────────────────┘ │
│  ┌─────────────┐  ┌─────────────┐                         │
│  │ Java 后端    │  │  Vue 前端    │                         │
│  │ 8081端口     │  │ /var/www    │                         │
│  └─────────────┘  └─────────────┘                         │
└─────────────────────────────────────────────────────────────┘

🖥️ 第一步:Ubuntu 虚拟机初始化

1.1 查看 IP 地址

开机后,在虚拟机控制台登录,执行:

ip addr show

找到你的网卡(通常是 ens33eth0)下面的 inet,例如:

inet 172.19.90.78/20

📝 拿出小本本,记下这个 IP!后面全部用它代替。

1.2 用 SSH 连接(强烈推荐!)

在 Win11 的 CMD / PowerShell 中执行:

ssh 你的用户名@你的IP
# 例如:ssh duke@172.19.90.78

第一次连接会提示:

Are you sure you want to continue connecting (yes/no/[fingerprint])?

⚠️ 注意!这里必须输入完整的 yes,按回车。

输入 Y?不行!
输入 y?也不行!
输入 yes?对了!SSH 就是这么傲娇。😤

然后输入密码登录。

💡 为什么强烈建议用 SSH?

  • VMware 控制台里复制粘贴不生效(Ubuntu Server 没有图形界面)
  • SSH 窗口可以正常复制粘贴,命令直接贴,爽歪歪
  • 字体可以调大,保护视力

1.3 更新系统

sudo apt update && sudo apt upgrade -y

这就像给系统打补丁,虽然无聊,但必须做。

1.4 安装常用工具

sudo apt install -y curl wget git vim net-tools ca-certificates gnupg

1.5 设置主机名(可选,但推荐)

sudo hostnamectl set-hostname gitlab-server

给服务器起个名字,以后登录提示符显示 gitlab-server,比一串数字亲切多了。


🐳 第二步:安装 Docker

2.1 安装 docker.io(Ubuntu 官方源,最稳)

不要折腾 Docker 官方仓库,Ubuntu 自带的 docker.io 完全够用。那些配置 GPG 密钥、添加源列表的教程,看着就头大,咱不整那些虚的:

# 更新包索引
sudo apt update

# 安装 Docker(就一行,简单粗暴)
sudo apt install -y docker.io

# 启动 Docker 服务
sudo systemctl start docker
sudo systemctl enable docker

# 将当前用户加入 docker 组(以后不用 sudo 也能跑 docker)
sudo usermod -aG docker $USER
newgrp docker

# 验证安装
docker --version

⚠️ 执行 newgrp docker 后,如果还是提示 docker: permission denied,请重新 SSH 连接一次。别问为什么,问就是 Linux 的权限缓存机制在搞事情。

2.2 安装 Docker Compose

Ubuntu 24.04 安装的是 docker-compose-v2,命令格式是 docker compose(中间空格,不是横杠):

sudo apt install -y docker-compose

验证:

docker compose version

如果你习惯敲 docker-compose,系统会温柔地告诉你:unknown command。记住:空格,空格,空格!

2.3 配置国内镜像加速器(如果拉取镜像慢)

国内网络你懂的,Docker Hub 有时候像蜗牛爬。配置加速器,让镜像飞起来:

sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json << 'EOF'
{
  "registry-mirrors": [
    "https://docker.1panel.live",
    "https://hub.rat.dev",
    "https://docker.m.daocloud.io"
  ]
}
EOF

sudo systemctl daemon-reload
sudo systemctl restart docker

这些镜像站是"公益节点",可能会变动。如果某天失效了,网上搜"Docker 国内镜像"换一批就行。


🦊 第三步:部署 GitLab

3.1 创建数据目录

GitLab 是个"数据大户",需要三个目录分别存配置、日志和数据:

sudo mkdir -p /srv/gitlab/{config,logs,data}
sudo mkdir -p /srv/gitlab-runner/config
sudo chmod 777 /srv/gitlab/{config,logs,data}
sudo chmod 777 /srv/gitlab-runner/config

chmod 777 意思是"所有人都能读写执行"。生产环境不建议这么奔放,但咱们是本地测试,先让权限不成为拦路虎。

3.2 创建 docker-compose.yml

不要用 vim!不要用 vim!不要用 vim!

新手用 vim 容易进去出不来(按 Esc 然后 :q! 可以强制退出,但何必呢)。用 tee 命令直接写入,优雅又安全:

sudo tee /srv/gitlab/docker-compose.yml << 'EOF'
version: '3.8'

services:
  gitlab:
    image: 'gitlab/gitlab-ce:latest'
    container_name: gitlab
    restart: always
    hostname: 'gitlab-server'
    environment:
      GITLAB_OMNIBUS_CONFIG: |
        external_url 'http://172.19.90.78:8080'
        gitlab_rails['gitlab_shell_ssh_port'] = 2222
        nginx['listen_https'] = false
        nginx['redirect_http_to_https'] = false
        nginx['listen_port'] = 80
    ports:
      - '8080:80'
      - '8443:443'
      - '2222:22'
    volumes:
      - '/srv/gitlab/config:/etc/gitlab'
      - '/srv/gitlab/logs:/var/log/gitlab'
      - '/srv/gitlab/data:/var/opt/gitlab'
    shm_size: '256m'

  gitlab-runner:
    image: 'gitlab/gitlab-runner:latest'
    container_name: gitlab-runner
    restart: always
    volumes:
      - '/srv/gitlab-runner/config:/etc/gitlab-runner'
      - '/var/run/docker.sock:/var/run/docker.sock'
    depends_on:
      - gitlab
EOF

⚠️ 超级重点nginx['listen_port'] = 80 必须写

如果不写,GitLab 内部的 Nginx 会误以为要监听 8080,但 Puma(Rails 内置服务器)默认也监听 8080。两个程序抢一个端口,结果就是——同归于尽,容器状态显示 unhealthy

⚠️ IP 地址:把 172.19.90.78 换成你虚拟机的实际 IP

3.3 启动 GitLab

cd /srv/gitlab
docker compose up -d

首次启动会拉取镜像并初始化数据库,需要 5~15 分钟。这段时间你可以:

  • 泡杯咖啡 ☕
  • 刷会儿手机 📱
  • 盯着终端看日志(推荐,有种看着孩子出生的感觉)
docker logs -f gitlab

当看到日志不再频繁滚动,或出现 gitlab Reconfigured!,按 Ctrl+C 退出日志查看。

3.4 获取 root 初始密码

docker exec -it gitlab grep 'Password:' /etc/gitlab/initial_root_password

输出示例:

Password: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx

⚠️ 这个文件会在 24 小时后自动删除!拿到密码后立刻登录修改,否则 24 小时后你就得重置密码了(虽然也能重置,但麻烦啊)。

3.5 浏览器登录

在 Win11 浏览器访问:

http://你的IP:8080
# 例如:http://172.19.90.78:8080
  • 用户名root
  • 密码:上一步获取的初始密码

登录后,点击右上角 root 头像 → Edit profile → Password,设置一个你能记住的新密码。

3.6 验证 GitLab 服务

# 检查容器状态
docker ps

# 本地测试端口
curl -I http://localhost:8080

预期返回 HTTP/1.1 302 Found200 OK


🏃 第四步:注册 GitLab Runner

Runner 是 CI/CD 的"打工仔",负责执行 .gitlab-ci.yml 里的任务。我们需要两种 Runner:

Runner 类型作用执行环境
Docker Runner编译代码(Maven、npm)Docker 容器内
Shell Runner部署到宿主机(复制文件、重启服务)直接在 Ubuntu 上

为什么需要两个?因为 Docker Runner 运行在容器里,默认看不到宿主机的 /var/www/opt/backend。让 Docker Runner 去部署,就像让鱼缸里的鱼去浇花——有心无力。

4.1 注册 Docker Runner

获取 Token

在 GitLab 网页:

  1. 点击左上角 Menu → Admin
  2. 左侧 CI/CD → Runners
  3. 点击右上角 New instance runner → Create runner
  4. 复制 Token(格式如 glrt-xxxxxxxxxx
执行注册
docker exec -it gitlab-runner gitlab-runner register

按提示输入:

提示输入
GitLab instance URLhttp://你的IP:8080
Registration token粘贴你复制的 Token
Descriptionmy-docker-runner
Tagsdocker
Maintenance note直接回车
Executordocker
Default Docker imageubuntu:24.04
验证
docker exec -it gitlab-runner gitlab-runner verify

在 GitLab 网页 Admin → Runners 中,应该看到绿色的 Online 状态。🟢

4.2 安装并注册 Shell Runner

Shell Runner 需要直接安装在宿主机上(不是 Docker 里):

# 添加 GitLab Runner 官方仓库
curl -L "https://packages.gitlab.com/install/repositories/runner/gitlab-runner/script.deb.sh" | sudo bash

# 安装 Runner
sudo apt install -y gitlab-runner

# 启动并设置开机自启
sudo systemctl enable gitlab-runner
sudo systemctl start gitlab-runner
获取项目级 Token

这次要从项目级别获取 Token(不是 Admin 级别):

  1. 在 GitLab 网页进入你的项目(如 hello-cicd
  2. Settings → CI/CD → Runners → New project runner
  3. 复制 Token

💡 为什么用 Project Runner 而不是 Instance Runner?
Instance Runner 是全局的,所有项目都能用,但默认项目看不到它。Project Runner 是项目专属的,注册后立刻出现在项目里,省心!

执行注册
sudo gitlab-runner register

按提示输入:

提示输入
URLhttp://你的IP:8080
Token粘贴项目级 Token
Descriptiondeploy-shell
Tagsshell
Executorshell
验证
sudo gitlab-runner list
sudo gitlab-runner verify

在 GitLab 网页 项目 → Settings → CI/CD → Runners 中,应该能看到 deploy-shell 显示为绿色 Online。


🌐 第五步:安装并配置 Nginx

5.1 安装 Nginx

sudo apt update
sudo apt install -y nginx
sudo systemctl enable nginx
sudo systemctl start nginx

5.2 创建前端部署目录

sudo mkdir -p /var/www/frontend
sudo chown -R www-data:www-data /var/www/frontend
sudo chmod 775 /var/www/frontend

5.3 配置 Nginx 站点

单页应用(Vue/React)专用配置,包含后端 API 反向代理:

# 禁用默认站点,避免冲突(默认站点的欢迎页会抢戏)
sudo rm -f /etc/nginx/sites-enabled/default

# 创建新站点配置
sudo tee /etc/nginx/sites-available/fullstack << 'EOF'
server {
    listen 80;
    server_name _;

    # Vue 前端(所有请求先找静态文件,找不到回退到 index.html)
    location / {
        root /var/www/frontend;
        index index.html;
        try_files $uri $uri/ /index.html;
    }

    # Java 后端 API 代理(解决跨域问题)
    location /api/ {
        proxy_pass http://127.0.0.1:8081/;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}
EOF

# 启用站点
sudo ln -sf /etc/nginx/sites-available/fullstack /etc/nginx/sites-enabled/

# 测试配置并重启
sudo nginx -t
sudo systemctl reload nginx

💡 try_files $uri $uri/ /index.html; 是 Vue 单页应用的救命稻草

Vue 是前端路由(URL 变化但不请求新页面),直接刷新 /about 时,Nginx 会去找 /about/index.html,当然找不到,返回 404。try_files 的意思是:“找不到文件?别慌,回退到 index.html,让 Vue 自己处理路由。”


☕ 第六步:配置 Java 后端服务

6.1 创建后端部署目录

sudo mkdir -p /opt/backend
sudo chown -R gitlab-runner:gitlab-runner /opt/backend

6.2 创建 systemd 服务文件

systemd 是 Ubuntu 的"服务管家",让 Java 程序像 Nginx 一样开机自启、崩溃自动重启:

sudo tee /etc/systemd/system/backend.service << 'EOF'
[Unit]
Description=Java Backend
After=network.target

[Service]
Type=simple
User=gitlab-runner
WorkingDirectory=/opt/backend
ExecStart=/usr/bin/java -jar /opt/backend/app.jar --server.port=8081
Restart=always
RestartSec=10

[Install]
WantedBy=multi-user.target
EOF

sudo systemctl daemon-reload

6.3 给 Shell Runner sudo 权限

Shell Runner 默认用户是 gitlab-runner,执行 systemctl 需要 sudo。但咱们不能给它全部权限(安全第一),只给必要的命令:

sudo tee /etc/sudoers.d/gitlab-runner << 'EOF'
gitlab-runner ALL=(ALL) NOPASSWD: /bin/rm, /bin/cp, /bin/mkdir, /bin/systemctl stop backend, /bin/systemctl start backend, /bin/systemctl status backend, /bin/systemctl daemon-reload, /bin/systemctl restart backend
EOF

sudo chmod 440 /etc/sudoers.d/gitlab-runner
sudo visudo -c

⚠️ 只给必要的命令权限,不要给 ALLgitlab-runner 要是能 sudo rm -rf /,那画面太美不敢看。


📝 第七步:.gitlab-ci.yml 配置完全指南

7.1 这是什么?

.gitlab-ci.yml 是 CI/CD 的"剧本",告诉 GitLab:

“代码推送后,先干嘛,再干嘛,最后干嘛。”

必须放在 Git 仓库的根目录,文件名必须.gitlab-ci.yml(注意前面有个点)。

my-project/                    ← 项目根目录
├── .gitlab-ci.yml             ← 放这里!
├── backend/
├── frontend/
└── README.md

⚠️ 文件名写错(如 gitlab-ci.yml 少了点)、放错位置(如放在 backend/ 里),流水线都不会触发。

7.2 基础结构速览

stages:           # ← 定义阶段顺序
  - build
  - test
  - deploy

build_job:        # ← Job 名字,随便取
  stage: build    # ← 属于哪个阶段
  tags:           # ← 用哪个 Runner 执行
    - docker
  image: node:20  # ← 用什么 Docker 镜像
  script:         # ← 真正执行的命令
    - echo "开始构建"
    - npm install
    - npm run build

执行顺序

build 阶段的所有 Job(并行)
    ↓
test 阶段的所有 Job(并行)
    ↓
deploy 阶段的所有 Job(并行)

7.3 核心字段详解

stages — 定义流水线阶段
stages:
  - build-backend
  - build-frontend
  - test
  - deploy

同一阶段的 Job 并行执行,不同阶段 串行执行

💡 技巧:把耗时的操作放在前面并行执行,比如前后端同时构建,省时间。

tags — 指定 Runner(关键!)
build_job:
  tags:
    - docker        # ← 只有标签含 docker 的 Runner 会执行
场景tags 设置
Maven 编译 Javatags: [docker]
npm 构建 Vuetags: [docker]
复制文件到 Nginx 目录tags: [shell]
执行 systemctl 重启服务tags: [shell]

⚠️ 如果 tags 不匹配,Job 会永远 pending(橙色),不会执行。 就像你叫了个外卖但地址写错了,骑手永远找不到你。

image — Docker 镜像
build_job:
  image: maven:3.9-eclipse-temurin-21-alpine
技术栈推荐镜像
Java + Mavenmaven:3.9-eclipse-temurin-21-alpine
Java + Gradlegradle:8.5-jdk21-alpine
Vue/Reactnode:20-alpine
Pythonpython:3.11-alpine
Gogolang:1.22-alpine

💡 带 alpine 的版本体积小(约 5MB 基础),拉取快,省时间。

script — 执行命令列表
script:
  - echo "开始构建"
  - cd backend
  - mvn clean package -DskipTests
  - ls -la target/

每行是一个独立的 shell 命令,按顺序执行。如果某一行报错,后面的命令不会执行。

多行脚本写法(更整洁):

script:
  - |
    echo "======== 开始构建 ========"
    cd backend
    mvn clean package -DskipTests
    echo "======== 构建完成 ========"
artifacts — 产物传递(跨 Job 共享文件)
build_job:
  script:
    - mvn package
  artifacts:
    paths:
      - backend/target/*.jar     # ← 把 jar 包保存下来
    expire_in: 1 week             # ← 1 周后自动删除

为什么需要 artifacts?

build_job 在 Docker 容器里编译出 jar 包,容器一销毁文件就没了。deploy_job 需要这个 jar 包才能部署。

artifacts 的作用:把文件"暂存"起来,让后面的 Job 能下载使用。

cache — 缓存加速
build_job:
  cache:
    paths:
      - backend/.m2/repository    # ← Maven 依赖缓存
      - frontend/node_modules/   # ← npm 依赖缓存
    key: "$CI_COMMIT_REF_SLUG"    # ← 按分支隔离缓存

artifacts vs cache 区别

  • artifacts:同一条流水线的不同 Job 之间传递文件(如 build → deploy)
  • cache:跨流水线复用文件(如下次构建直接用上次下载的依赖)
dependencies — 指定依赖哪个 Job 的产物
deploy_job:
  dependencies:
    - build-backend    # ← 只拿 build-backend 的 artifacts
rules / only — 触发条件

旧写法(不推荐新项目用):

deploy_job:
  only:
    - main          # ← 只有推送到 main 分支才触发

新写法(功能更强,推荐):

deploy_job:
  rules:
    - if: '$CI_COMMIT_BRANCH == "main"'       # main 分支才部署
      when: always
    - if: '$CI_COMMIT_BRANCH == "develop"'     # develop 分支只构建不部署
      when: never
    - when: manual                               # 其他分支手动触发
when含义
on_success前面阶段成功才执行(默认)
on_failure前面阶段失败才执行(用于报错通知)
always无论成败都执行(用于清理)
manual手动触发(用于部署到生产环境)

生产环境手动审批示例

deploy-prod:
  stage: deploy
  rules:
    - if: '$CI_COMMIT_BRANCH == "main"'
      when: manual          # ← 必须人工点击"执行"按钮
  script:
    - echo "✅ 生产环境已确认上线!"
needs — 跳过阶段,直接依赖(DAG 流水线)

默认流水线是阶段顺序执行,用 needs 可以让前后端并行部署

deploy-backend:
  stage: deploy
  needs: [build-backend]      # ← 只要 build-backend 完成就开始
  dependencies: [build-backend]

deploy-frontend:
  stage: deploy
  needs: [build-frontend]     # ← 只要 build-frontend 完成就开始
  dependencies: [build-frontend]
environment — 环境配置(部署追踪)
deploy_job:
  environment:
    name: production
    url: http://172.19.90.78

效果:GitLab 网页会显示 “Deployed to production” 按钮,点击直接跳转到部署地址。

7.4 实战配置模板(Java + Vue 全栈)

stages:
  - build-backend
  - build-frontend
  - deploy

variables:
  MAVEN_OPTS: "-Dmaven.repo.local=.m2/repository"

# ========== 构建 Java 后端 ==========
build-backend:
  stage: build-backend
  tags: [docker]
  image: maven:3.9-eclipse-temurin-21-alpine
  cache:
    paths: [backend/.m2/repository]
    key: "mvn-$CI_COMMIT_REF_SLUG"
  script:
    - cd backend
    - mvn -s settings.xml clean package -DskipTests
    - ls -la target/
  artifacts:
    paths: [backend/target/*.jar]
    expire_in: 1 day

# ========== 构建 Vue 前端 ==========
build-frontend:
  stage: build-frontend
  tags: [docker]
  image: node:20-alpine
  cache:
    paths: [frontend/node_modules/]
    key: "npm-$CI_COMMIT_REF_SLUG"
  script:
    - cd frontend
    - npm config set registry https://registry.npmmirror.com
    - npm install
    - npm run build
    - ls -la dist/
  artifacts:
    paths: [frontend/dist/]
    expire_in: 1 day

# ========== 部署后端 ==========
deploy-backend:
  stage: deploy
  tags: [shell]
  needs: [build-backend]
  dependencies: [build-backend]
  script:
    - sudo systemctl stop backend || true
    - cp backend/target/*.jar /opt/backend/app.jar
    - sudo systemctl start backend
    - sleep 5
    - sudo systemctl status backend

# ========== 部署前端 ==========
deploy-frontend:
  stage: deploy
  tags: [shell]
  needs: [build-frontend]
  dependencies: [build-frontend]
  script:
    - rm -rf /var/www/frontend/*
    - cp -r frontend/dist/* /var/www/frontend/
    - ls -la /var/www/frontend/

7.5 多环境部署模板(测试自动 + 生产手动)

stages:
  - build
  - deploy-staging
  - deploy-prod

build:
  stage: build
  tags: [docker]
  image: maven:3.9-eclipse-temurin-21-alpine
  script:
    - mvn clean package -DskipTests
  artifacts:
    paths: [target/*.jar]

# 测试环境:自动部署
deploy-staging:
  stage: deploy-staging
  tags: [shell]
  dependencies: [build]
  environment:
    name: staging
    url: http://172.19.90.78:8082
  rules:
    - if: '$CI_COMMIT_BRANCH == "develop"'
  script:
    - cp target/*.jar /opt/backend-staging/app.jar
    - sudo systemctl restart backend-staging

# 生产环境:手动审批
deploy-prod:
  stage: deploy-prod
  tags: [shell]
  dependencies: [build]
  environment:
    name: production
    url: http://172.19.90.78
  rules:
    - if: '$CI_COMMIT_BRANCH == "main"'
      when: manual          # ← 必须人工点击"执行"
  script:
    - cp target/*.jar /opt/backend/app.jar
    - sudo systemctl restart backend

7.6 常用内置变量

变量示例值说明
$CI_COMMIT_BRANCHmain当前分支名
$CI_COMMIT_SHAa1b2c3d...当前 commit 完整哈希
$CI_COMMIT_SHORT_SHAa1b2c3d当前 commit 短哈希
$CI_PROJECT_NAMEmy-project项目名
$CI_JOB_NAMEbuild_job当前 Job 名
$CI_REGISTRY172.19.90.78:8080GitLab 镜像仓库地址

💻 第八步:Win11 客户端配置

8.1 安装 Git

访问 https://git-scm.com/download/win 下载安装,一路默认即可。

验证:

git --version

8.2 配置 Git 身份

git config --global user.email "duke@example.com"
git config --global user.name "Duke"

不配置的话,Git 会傲娇地报错:fatal: unable to auto-detect email address

8.3 配置 SSH 密钥

ssh-keygen -t ed25519 -C "duke@gitlab"

一路回车。然后复制公钥:

type %USERPROFILE%\.ssh\id_ed25519.pub

复制输出的内容,在 GitLab 网页:

  1. 点击右上角 root 头像 → Preferences → SSH Keys
  2. 粘贴公钥,Title 填 Win11-PC
  3. 点击 Add key

如果 git push 提示 Permission denied (publickey),99% 是这步没做,或者公钥复制错了。


🎉 第九步:实战部署(完整示例)

9.1 在 GitLab 创建项目

  1. 点击 Create new project → Create blank project
  2. Project namehello-cicd
  3. VisibilityPublic
  4. 点击 Create project

9.2 克隆项目到本地

cd D:\demo\gitlab
git clone ssh://git@你的IP:2222/root/hello-cicd.git
cd hello-cicd

9.3 创建示例文件

创建 index.html

<!DOCTYPE html>
<html>
<head>
    <title>Hello GitLab CI/CD</title>
</head>
<body>
    <h1>🎉 部署成功!</h1>
    <p>Build Time: BUILD_TIME_PLACEHOLDER</p>
</body>
</html>

创建 .gitlab-ci.yml

stages:
  - build
  - deploy

build_job:
  stage: build
  tags:
    - docker
  image: node:20-alpine
  script:
    - echo "开始构建..."
    - mkdir -p dist
    - cp index.html dist/index.html
    - sed -i "s/BUILD_TIME_PLACEHOLDER/$(date)/g" dist/index.html
    - echo "构建完成!"
  artifacts:
    paths:
      - dist/

deploy_job:
  stage: deploy
  tags:
    - shell        # 关键:指定 Shell Runner
  script:
    - echo "清理旧文件..."
    - rm -rf /var/www/frontend/*
    - echo "复制新文件到 Nginx..."
    - cp -r dist/* /var/www/frontend/
    - echo "✅ 部署完成!"
    - ls -la /var/www/frontend/
  dependencies:
    - build_job
  only:
    - main
    - master

9.4 推送代码触发流水线

git add .
git commit -m "init: add CI/CD pipeline"
git push origin main

推送后,在 GitLab 网页进入项目 → CI/CD → Pipelines,可以看到流水线正在运行。

等两个 Job 都变绿 ✅ 后,在 Win11 浏览器访问:

http://你的IP
# 例如:http://172.19.90.78

你应该能看到 “🎉 部署成功!” 的页面,而且 Build Time 是刚才构建的时间。

以后每次改代码 → git push → 自动构建 → 自动部署到 Nginx! 🚀


☁️ 第十步:部署到云端(阿里云 / 腾讯云 / AWS)

前置要求:你已经跟着前面的步骤,在本地 VMware 上成功跑通了 GitLab + CI/CD。

现在你想把这套玩意儿搬到云上,让全世界(或者至少你的团队)都能访问。恭喜你,从"单机版玩家"进阶为"联网版玩家"了!🌐

10.1 本地 vs 云端:有啥不一样?

对比项本地 VMware云端服务器
网络模式NAT / 桥接,折腾死人公网 IP,开箱即用
访问方式只有局域网能访问全球任何地方都能访问
防火墙ufw 命令搞定安全组(云端特有,坑很多)
域名直接用 IP推荐绑定域名 + SSL
备案不需要国内服务器必须备案(否则 80/443 被封)
磁盘扩容关虚拟机 → 改设置 → 扩分区云控制台点几下,重启即可
数据备份自己搞云快照 / 云盘备份,一键恢复
成本电费 + 电脑折旧按月付费,约 50~200 元/月

💡 一句话总结:云端部署的核心流程和本地几乎一样,差异主要在网络安全和域名备案


10.2 云服务器选型推荐

GitLab 是个"资源饕餮",云服务器配置不能抠门:

用途CPU内存磁盘带宽月租参考
个人学习 / 小团队2 核4 GB80 GB SSD3 Mbps~50 元
推荐配置4 核8 GB100 GB SSD5 Mbps~100 元
团队正式使用4 核16 GB200 GB SSD10 Mbps~200 元

平台选择

  • 阿里云:生态完善,文档齐全,学生有优惠
  • 腾讯云:性价比高,新用户折扣大
  • 华为云:政企首选,稳定性好
  • AWS / Azure:国际业务首选,国内访问略慢

⚠️ 避坑指南

  • 不要买"突发性能实例"(T5/T6),CPU 性能被限制,GitLab 启动慢到怀疑人生
  • 一定要选 SSD 云盘,机械硬盘跑 GitLab 就是灾难
  • 带宽建议 3Mbps 起步,低于 1Mbps 拉镜像能急死人

10.3 购买和初始化云服务器

步骤 1:购买服务器

以阿里云为例:

  1. 登录 阿里云控制台
  2. 点击 创建实例
  3. 地域:选离你近的(如华东 1 杭州)
  4. 镜像:选择 Ubuntu 24.04 LTS 64位
  5. 实例规格:至少 2 核 4G(推荐 4 核 8G)
  6. 存储:系统盘 80GB+,建议加一块数据盘 100GB(放 GitLab 数据)
  7. 带宽:按固定带宽 3~5 Mbps
  8. 安全组:先选默认的,后面再改
  9. 登录凭证:设置 root 密码 或上传 SSH 公钥
  10. 确认订单,付款,等待 1~2 分钟创建完成
步骤 2:获取公网 IP

创建完成后,在 ECS 控制台找到你的实例,记录:

  • 公网 IP:如 47.102.123.45
  • 私有 IP:如 172.17.0.1(后面配置用不到,但知道一下)

📝 拿出小本本,记下公网 IP!后面全部用它代替。

步骤 3:SSH 连接云服务器

在 Win11 CMD / PowerShell 中:

ssh root@你的公网IP
# 例如:ssh root@47.102.123.45

第一次连接同样要输入 yes(完整的,不是 Y)。


10.4 配置安全组(云端特有,重点!)

安全组是云端的"数字防火墙",默认只开放 22 端口(SSH)。如果不配置,你访问 GitLab 会被无情拒绝。

阿里云安全组配置
  1. 进入 ECS 控制台 → 网络与安全 → 安全组
  2. 找到你的实例关联的安全组,点击 配置规则
  3. 点击 入方向 → 手动添加,添加以下规则:
类型端口范围授权对象说明
SSH22/220.0.0.0/0远程连接
HTTP80/800.0.0.0/0Nginx 前端
自定义 TCP8080/80800.0.0.0/0GitLab Web
自定义 TCP8081/80810.0.0.0/0Java 后端
自定义 TCP2222/22220.0.0.0/0GitLab SSH
HTTPS443/4430.0.0.0/0SSL(后面配)

⚠️ 0.0.0.0/0 表示允许任何 IP 访问。学习阶段可以这么设,生产环境建议限制为公司 IP 段。

腾讯云安全组配置

类似,进入 CVM 控制台 → 安全组 → 入站规则,添加上述端口。

验证端口是否通
# 在云服务器上启动一个临时服务测试
python3 -m http.server 8080 &

然后在 Win11 浏览器访问 http://你的公网IP:8080,如果能看到目录列表,说明安全组配置成功。

# 测试完关掉临时服务
kill %1

10.5 数据盘挂载(推荐)

如果你购买时加了一块数据盘(如 100GB),需要挂载到 /srv/gitlab 目录,这样即使系统盘出问题,GitLab 数据还在。

# 查看磁盘
lsblk

# 假设数据盘是 /dev/vdb(阿里云通常是 vdb,腾讯云是 vdc)
# 格式化(首次使用,会清空数据!)
sudo mkfs.ext4 /dev/vdb

# 创建挂载点
sudo mkdir -p /srv/gitlab

# 挂载
sudo mount /dev/vdb /srv/gitlab

# 设置开机自动挂载
sudo tee -a /etc/fstab << 'EOF'
/dev/vdb /srv/gitlab ext4 defaults 0 0
EOF

# 验证
df -h | grep /srv/gitlab

💡 把 GitLab 数据放在独立云盘上,就像把鸡蛋放在不同篮子里,系统盘崩了数据还在。


10.6 部署 GitLab(云端版)

与本地部署的差异点

云端部署的核心流程和本地 几乎一样,只有几个地方需要改:

  1. IP 地址:换成公网 IP
  2. external_url:建议用域名(后面讲)
  3. 安全组:已经配好了(见 10.4)
  4. 防火墙:云服务器通常没开 ufw,不用管
创建 docker-compose.yml(云端版)
sudo mkdir -p /srv/gitlab/{config,logs,data}
sudo mkdir -p /srv/gitlab-runner/config
sudo chmod 777 /srv/gitlab/{config,logs,data}
sudo chmod 777 /srv/gitlab-runner/config

sudo tee /srv/gitlab/docker-compose.yml << 'EOF'
version: '3.8'

services:
  gitlab:
    image: 'gitlab/gitlab-ce:latest'
    container_name: gitlab
    restart: always
    hostname: 'gitlab-server'
    environment:
      GITLAB_OMNIBUS_CONFIG: |
        external_url 'http://47.102.123.45:8080'
        gitlab_rails['gitlab_shell_ssh_port'] = 2222
        nginx['listen_https'] = false
        nginx['redirect_http_to_https'] = false
        nginx['listen_port'] = 80
    ports:
      - '8080:80'
      - '8443:443'
      - '2222:22'
    volumes:
      - '/srv/gitlab/config:/etc/gitlab'
      - '/srv/gitlab/logs:/var/log/gitlab'
      - '/srv/gitlab/data:/var/opt/gitlab'
    shm_size: '256m'

  gitlab-runner:
    image: 'gitlab/gitlab-runner:latest'
    container_name: gitlab-runner
    restart: always
    volumes:
      - '/srv/gitlab-runner/config:/etc/gitlab-runner'
      - '/var/run/docker.sock:/var/run/docker.sock'
    depends_on:
      - gitlab
EOF

⚠️ 47.102.123.45 换成你的真实公网 IP!

启动 GitLab
cd /srv/gitlab
docker compose up -d

同样等待 5~15 分钟初始化。期间可以:

docker logs -f gitlab
获取 root 密码
docker exec -it gitlab grep 'Password:' /etc/gitlab/initial_root_password
浏览器访问
http://你的公网IP:8080
# 例如:http://47.102.123.45:8080

如果能看到 GitLab 登录页,恭喜你,云端 GitLab 部署成功!🎉


10.7 域名绑定 + 备案(国内服务器必须)

为什么要域名?
  • IP 地址难记,域名好记(如 git.yourcompany.com
  • 配置 SSL 证书需要域名
  • 看起来更专业(毕竟 47.102.123.45:8080 像黑客攻击目标)
国内备案流程

如果你用的是国内云服务器(阿里云、腾讯云等),必须备案才能使用 80/443 端口:

  1. 购买域名(阿里云万网、腾讯云 DNSPod,约 30~70 元/年)
  2. 实名认证(域名持有者身份证照片)
  3. ICP 备案(在云平台提交备案申请)
    • 填写网站信息、负责人信息
    • 上传身份证、手持身份证照片
    • 阿里云/腾讯云初审(1~2 天)
    • 管局审核(7~20 天,不同省份速度不同)
  4. 备案通过后,80/443 端口才能正常访问

⚠️ 备案期间,网站不能访问,或者只能显示"网站建设中"。建议备案完成后再正式使用。

域名解析配置

备案通过后:

  1. 进入域名管理控制台(如阿里云 DNS 解析)
  2. 添加 A 记录
    • 主机记录:git(表示 git.yourdomain.com
    • 记录值:你的公网 IP(如 47.102.123.45
  3. 等待 5~10 分钟生效(DNS 传播)
修改 GitLab 使用域名
sudo tee /srv/gitlab/docker-compose.yml << 'EOF'
version: '3.8'

services:
  gitlab:
    image: 'gitlab/gitlab-ce:latest'
    container_name: gitlab
    restart: always
    hostname: 'git.yourdomain.com'
    environment:
      GITLAB_OMNIBUS_CONFIG: |
        external_url 'http://git.yourdomain.com:8080'
        gitlab_rails['gitlab_shell_ssh_port'] = 2222
        nginx['listen_https'] = false
        nginx['redirect_http_to_https'] = false
        nginx['listen_port'] = 80
    ports:
      - '8080:80'
      - '8443:443'
      - '2222:22'
    volumes:
      - '/srv/gitlab/config:/etc/gitlab'
      - '/srv/gitlab/logs:/var/log/gitlab'
      - '/srv/gitlab/data:/var/opt/gitlab'
    shm_size: '256m'

  gitlab-runner:
    image: 'gitlab/gitlab-runner:latest'
    container_name: gitlab-runner
    restart: always
    volumes:
      - '/srv/gitlab-runner/config:/etc/gitlab-runner'
      - '/var/run/docker.sock:/var/run/docker.sock'
    depends_on:
      - gitlab
EOF

cd /srv/gitlab
docker compose down
docker compose up -d

⚠️ git.yourdomain.com 换成你的真实域名!


10.8 配置 HTTPS(SSL 证书)

为什么要 HTTPS?
  • 数据加密传输,防止中间人攻击
  • GitLab 某些功能(如 Container Registry)强制要求 HTTPS
  • 浏览器不再显示"不安全"的警告,用户体验好
使用 Let’s Encrypt 免费证书

Let’s Encrypt 提供免费的 SSL 证书,有效期 90 天,可以自动续期。

前置条件

  • 域名已备案(国内)
  • 域名已解析到服务器 IP
  • 80 端口可访问(Let’s Encrypt 验证需要)

步骤

# 安装 certbot
sudo apt update
sudo apt install -y certbot

# 获取证书(替换为你的域名)
sudo certbot certonly --standalone -d git.yourdomain.com

# 按提示输入邮箱,同意协议
# 证书会生成在 /etc/letsencrypt/live/git.yourdomain.com/

修改 docker-compose.yml 启用 HTTPS

sudo tee /srv/gitlab/docker-compose.yml << 'EOF'
version: '3.8'

services:
  gitlab:
    image: 'gitlab/gitlab-ce:latest'
    container_name: gitlab
    restart: always
    hostname: 'git.yourdomain.com'
    environment:
      GITLAB_OMNIBUS_CONFIG: |
        external_url 'https://git.yourdomain.com'
        gitlab_rails['gitlab_shell_ssh_port'] = 2222
        nginx['listen_https'] = true
        nginx['redirect_http_to_https'] = true
        nginx['ssl_certificate'] = "/etc/gitlab/ssl/fullchain.pem"
        nginx['ssl_certificate_key'] = "/etc/gitlab/ssl/privkey.pem"
    ports:
      - '80:80'
      - '443:443'
      - '2222:22'
    volumes:
      - '/srv/gitlab/config:/etc/gitlab'
      - '/srv/gitlab/logs:/var/log/gitlab'
      - '/srv/gitlab/data:/var/opt/gitlab'
      - '/etc/letsencrypt/live/git.yourdomain.com/fullchain.pem:/etc/gitlab/ssl/fullchain.pem'
      - '/etc/letsencrypt/live/git.yourdomain.com/privkey.pem:/etc/gitlab/ssl/privkey.pem'
    shm_size: '256m'

  gitlab-runner:
    image: 'gitlab/gitlab-runner:latest'
    container_name: gitlab-runner
    restart: always
    volumes:
      - '/srv/gitlab-runner/config:/etc/gitlab-runner'
      - '/var/run/docker.sock:/var/run/docker.sock'
    depends_on:
      - gitlab
EOF

⚠️ git.yourdomain.com 换成你的真实域名!

重启 GitLab

cd /srv/gitlab
docker compose down
docker compose up -d

设置自动续期

Let’s Encrypt 证书 90 天过期,需要自动续期:

# 创建续期脚本
sudo tee /usr/local/bin/renew-ssl.sh << 'EOF'
#!/bin/bash
certbot renew --quiet
cd /srv/gitlab
docker compose restart gitlab
EOF

sudo chmod +x /usr/local/bin/renew-ssl.sh

# 添加到 crontab,每月 1 号凌晨 3 点执行
(crontab -l 2>/dev/null; echo "0 3 1 * * /usr/local/bin/renew-ssl.sh >> /var/log/renew-ssl.log 2>&1") | crontab -
验证 HTTPS

在浏览器访问:

https://git.yourdomain.com

应该能看到绿色的小锁 🔒,表示 HTTPS 配置成功!


10.9 云端 Runner 注册

云端 Runner 注册和本地完全一样,只是 URL 换成公网 IP 或域名:

Docker Runner

docker exec -it gitlab-runner gitlab-runner register
提示输入
URLhttp://你的公网IP:8080https://你的域名
Token从 GitLab Admin → Runners 获取
Tagsdocker
Executordocker
Default imageubuntu:24.04

Shell Runner

sudo gitlab-runner register
提示输入
URLhttp://你的公网IP:8080https://你的域名
Token从项目 Settings → CI/CD → Runners 获取
Tagsshell
Executorshell

10.10 Nginx + Java 后端(云端版)

和本地部署完全一样,直接复制粘贴:

# 安装 Nginx
sudo apt update
sudo apt install -y nginx
sudo systemctl enable nginx
sudo systemctl start nginx

# 创建前端目录
sudo mkdir -p /var/www/frontend
sudo chown -R www-data:www-data /var/www/frontend
sudo chmod 775 /var/www/frontend

# 配置 Nginx(和本地一样)
sudo rm -f /etc/nginx/sites-enabled/default
sudo tee /etc/nginx/sites-available/fullstack << 'EOF'
server {
    listen 80;
    server_name _;

    location / {
        root /var/www/frontend;
        index index.html;
        try_files $uri $uri/ /index.html;
    }

    location /api/ {
        proxy_pass http://127.0.0.1:8081/;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}
EOF

sudo ln -sf /etc/nginx/sites-available/fullstack /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx

# Java 后端服务(和本地一样)
sudo mkdir -p /opt/backend
sudo chown -R gitlab-runner:gitlab-runner /opt/backend

sudo tee /etc/systemd/system/backend.service << 'EOF'
[Unit]
Description=Java Backend
After=network.target

[Service]
Type=simple
User=gitlab-runner
WorkingDirectory=/opt/backend
ExecStart=/usr/bin/java -jar /opt/backend/app.jar --server.port=8081
Restart=always
RestartSec=10

[Install]
WantedBy=multi-user.target
EOF

sudo systemctl daemon-reload

# sudo 权限(和本地一样)
sudo tee /etc/sudoers.d/gitlab-runner << 'EOF'
gitlab-runner ALL=(ALL) NOPASSWD: /bin/rm, /bin/cp, /bin/mkdir, /bin/systemctl stop backend, /bin/systemctl start backend, /bin/systemctl status backend, /bin/systemctl daemon-reload, /bin/systemctl restart backend
EOF

sudo chmod 440 /etc/sudoers.d/gitlab-runner

10.11 数据备份策略(云端优势)

云端最大的好处之一就是备份方便,一定要利用起来!

方案 A:云快照(最简单)
  • 阿里云:ECS 控制台 → 实例详情 → 本实例快照 → 创建快照
  • 腾讯云:CVM 控制台 → 实例详情 → 快照 → 创建快照

建议

  • 每周自动快照一次
  • 重大升级前手动快照一次
  • 快照保留 2~4 个版本
方案 B:GitLab 内置备份
# 创建备份(包含仓库、数据库、配置)
docker exec -it gitlab gitlab-backup create

# 备份文件在 /srv/gitlab/data/backups/
ls -la /srv/gitlab/data/backups/

# 下载到本地(Win11 用 scp)
scp root@你的公网IP:/srv/gitlab/data/backups/xxx_gitlab_backup.tar .
方案 C:云盘备份到 OSS / COS
# 安装 ossutil(阿里云)
wget http://gosspublic.alicdn.com/ossutil/1.7.15/ossutil64
chmod +x ossutil64
sudo mv ossutil64 /usr/local/bin/

# 配置(按提示输入 AccessKey)
ossutil64 config

# 每天自动备份到 OSS
(crontab -l 2>/dev/null; echo "0 2 * * * cd /srv/gitlab/data/backups && ossutil64 cp *.tar oss://your-bucket/gitlab-backups/ >> /var/log/oss-backup.log 2>&1") | crontab -

💡 备份三原则:3-2-1 法则——至少 3 份备份,2 种不同介质,1 份异地存储。


10.12 云端特有排错

❌ 37. 安全组端口没开放,访问超时

现象:浏览器访问 http://公网IP:8080 一直转圈,最后超时。

原因:安全组没有开放 8080 端口。

解决:去云平台控制台 → 安全组 → 添加入方向规则,开放 8080 端口。


❌ 38. 备案未完成,80/443 端口被阻断

现象:访问 http://你的域名 显示"未备案"或无法访问,但 http://公网IP:8080 可以。

原因:国内服务器未备案,运营商封了 80/443 端口。

解决

  • 临时方案:用非标准端口(如 8080、8443)
  • 根本方案:完成 ICP 备案

❌ 39. Let’s Encrypt 证书申请失败

现象certbot 报错 Connection refusedTimeout

原因

  • 80 端口被占用(GitLab 容器占用了 80:80)
  • 安全组没开放 80 端口
  • 域名解析还没生效

解决

# 1. 临时停止 GitLab,释放 80 端口
cd /srv/gitlab
docker compose down

# 2. 申请证书
sudo certbot certonly --standalone -d git.yourdomain.com

# 3. 启动 GitLab
docker compose up -d

❌ 40. 公网 IP 暴露,被扫描攻击

现象:服务器 CPU 突然飙升,日志里大量陌生 IP 的登录尝试。

原因:GitLab 暴露在公网,被黑客扫描。

解决

# 1. 修改 SSH 默认端口(可选)
sudo sed -i 's/#Port 22/Port 22222/' /etc/ssh/sshd_config
sudo systemctl restart sshd

# 2. 安装 fail2ban 自动封禁暴力破解
sudo apt install -y fail2ban
sudo systemctl enable fail2ban
sudo systemctl start fail2ban

# 3. GitLab 设置强密码 + 关闭注册
# GitLab 网页 → Admin → Settings → Sign-up restrictions → 取消勾选 Sign-up enabled

❌ 41. 云服务器被限速,GitLab 极慢

现象:GitLab 页面加载慢,Runner 构建超时。

原因:云服务器带宽太小(如 1Mbps),或遇到网络高峰限速。

解决

  • 升级带宽到 5Mbps+
  • 配置国内镜像加速(Docker、Maven、npm)
  • 非工作时间执行大构建任务

❌ 42. 数据盘没挂载,GitLab 又满了

现象df -h 显示根分区满了,但明明买了 100GB 数据盘。

原因:数据盘买了但没挂载,GitLab 数据还是写在系统盘。

解决:见 10.5 节,挂载数据盘到 /srv/gitlab


10.13 成本优化建议

策略说明节省
按量付费转包年包月长期用选包年包月,便宜 30~50%~50 元/月
使用抢占式实例阿里云/腾讯云的竞价实例,价格低 70%~70 元/月
关闭时释放公网 IP不用的时候解绑公网 IP,省带宽费~20 元/月
使用轻量应用服务器阿里云/腾讯云轻量服务器,性价比更高~30 元/月
对象存储存备份备份放 OSS/COS,比云盘便宜~10 元/月

10.14 云端部署 checklist

部署完成后,逐项检查:

  • 云服务器已购买,配置满足最低要求
  • 安全组已开放 22、80、443、8080、8081、2222 端口
  • 数据盘已挂载到 /srv/gitlab
  • Docker 和 Docker Compose 已安装
  • GitLab 容器已启动,浏览器可访问
  • Docker Runner 已注册,状态 Online
  • Shell Runner 已注册,状态 Online
  • Nginx 已安装并配置
  • Java 后端 systemd 服务已配置
  • 域名已解析(可选)
  • SSL 证书已配置(可选)
  • 自动备份已配置(云快照或 ossutil)
  • fail2ban 已安装(安全)
  • GitLab 注册已关闭(安全)
  • root 密码已修改为强密码(安全)

🐛 第十一步:排错大全(30+ 常见问题)

恭喜你来到本文档最实用的章节!这里汇集了部署过程中可能遇到的所有坑,以及填坑方法。建议收藏,遇事不慌。

🔴 环境准备阶段

❌ 1. SSH 连接时输入 Y 无效

现象

Are you sure you want to continue connecting (yes/no/[fingerprint])? Y
Please type 'yes', 'no' or the fingerprint:

原因:SSH 要求输入完整的 yes,不能简写为 Yy

解决:输入完整的 yes,按回车。SSH 就是这么严格,不接受缩写。


❌ 2. VMware NAT 模式导致 Win11 无法访问虚拟机

现象:浏览器访问虚拟机 IP 显示 “拒绝连接”。

原因:NAT 模式下虚拟机 IP 只在 VMware 内部网络有效,宿主机无法直接访问。

解决

  1. 关闭虚拟机
  2. VMware → 虚拟机 → 设置 → 网络适配器
  3. 改为 桥接模式,勾选 “复制物理网络连接状态”
  4. 重新开机,获取新 IP

❌ 3. 虚拟机重启后 IP 变化

现象:桥接模式下 IP 随网络环境变化。

解决:使用 netplan 固定静态 IP(见第一步)。


❌ 4. 虚拟机控制台复制粘贴不生效

现象:在 VMware 黑框控制台里无法复制粘贴命令。

原因:Ubuntu Server 无图形界面,VMware 控制台不支持剪贴板。

解决:用 Win11 的 CMD/PowerShell 通过 SSH 连接虚拟机。SSH 窗口复制粘贴丝般顺滑。


🔴 Docker 安装阶段

❌ 5. Docker 官方仓库配置失败

现象

Package docker-ce-cli is not available...
Package 'docker-ce' has no installation candidate

原因:Docker 官方 APT 仓库配置失败,系统找不到 docker-ce 包。

解决:直接用 Ubuntu 官方源安装:

sudo apt update
sudo apt install -y docker.io

❌ 6. docker compose 命令不存在

现象

docker: unknown command: docker compose

原因:Ubuntu 24.04 安装的是 docker-compose-v2,命令格式是 docker compose(空格),不是 docker-compose(横杠)。

解决

sudo apt install -y docker-compose
# 装完后用 docker compose(空格)

❌ 7. 拉取镜像失败 connection refused

现象

failed to resolve reference ... dial tcp ... connect: connection refused

原因:无法访问 Docker Hub(国际网络问题)。

解决:配置国内镜像加速器(见第二步 2.3)。


🔴 GitLab 部署阶段

❌ 8. 磁盘空间不足

现象

ERROR: could not extend file ... No space left on device

原因:GitLab 首次初始化需要大量空间(建议 50GB+),虚拟机磁盘不足。

解决

  1. VMware 中关闭虚拟机 → 设置 → 硬盘 → 扩展(至少 80GB)
  2. Ubuntu 中扩展 LVM 分区:
sudo apt install -y cloud-guest-utils
sudo growpart /dev/sda 3
sudo pvresize /dev/sda3
sudo lvextend -l +100%FREE /dev/ubuntu-vg/ubuntu-lv
sudo resize2fs /dev/ubuntu-vg/ubuntu-lv

❌ 9. GitLab 初始化被中断导致配置损坏

现象

  • curl -I http://localhost:8080 返回 Empty reply from server
  • 容器状态 unhealthy
  • 删除 /srv/gitlab/config/* 后容器内找不到配置文件

原因:在容器运行时删除了 config 目录,导致内部进程崩溃。

解决

# 1. 彻底停止容器
cd /srv/gitlab
docker compose down

# 2. 清空所有数据(壮士断腕)
sudo rm -rf /srv/gitlab/config/*
sudo rm -rf /srv/gitlab/data/*
sudo rm -rf /srv/gitlab/logs/*

# 3. 重新启动(会重新初始化)
docker compose up -d

⚠️ 警告:这步会清空所有 GitLab 数据!如果是生产环境,请先备份!


❌ 10. Nginx 和 Puma 端口冲突

现象

Address already in use - bind(2) for "127.0.0.1" port 8080

原因external_url 'http://172.19.90.78:8080' 让 Nginx 误以为要监听 8080,但 Puma(Rails Web 服务器)默认也监听 8080。

解决:在 docker-compose.ymlGITLAB_OMNIBUS_CONFIG 中强制指定:

nginx['listen_port'] = 80

❌ 11. Win11 浏览器访问不了 GitLab

原因

  • GitLab 还在初始化(首次启动需要 5~15 分钟)
  • 防火墙拦截
  • 虚拟机网络模式不对(NAT 而不是桥接)

解决

# 开放端口
sudo ufw allow 8080
sudo ufw allow 80
sudo ufw allow 2222

# 检查容器状态
docker ps
curl -I http://localhost:8080

🔴 GitLab Runner 阶段

❌ 12. Docker Runner 容器停止运行

现象

Error response from daemon: container ... is not running

解决

cd /srv/gitlab
docker compose up -d gitlab-runner

❌ 13. Runner 标签不匹配导致 Job 无法执行

现象

This job has not started yet
No project runners found

原因

  • .gitlab-ci.yml 里写了 tags: - docker,但项目只有 Shell Runner
  • 或者 Runner 是 Instance Runner,但项目没有启用

解决

  • 方案 A:在项目中创建 Project Runner(推荐)
  • 方案 B:修改 .gitlab-ci.yml 的 tags 匹配实际 Runner 标签
  • 方案 C:给 Runner 勾选 “Run untagged jobs”

❌ 14. Shell Runner 项目里看不到

现象my-project → Settings → CI/CD → Runners 里看不到 deploy-shell

原因:Runner 注册成了 Instance Runner,但项目没有启用它。

解决:在项目里直接创建 New project runner,用项目级别的 Token 注册。


❌ 15. Docker Runner 无法访问宿主机目录

现象:deploy 阶段用 Docker Runner 执行 cp/var/www/frontend/ 失败。

原因:Docker Runner 运行在容器里,默认无法访问宿主机的文件系统。

解决

  • 推荐:deploy 阶段改用 Shell Runner(在宿主机上执行)
  • 或者给 Docker Runner 配置 volume 映射 /var/www/frontend

🔴 CI/CD 配置阶段

❌ 16. .gitlab-ci.yml 格式错误

现象

jobs:deploy_job:script config should be a string or a nested array of strings up to 10 levels deep

原因

  • Windows 记事本保存的 UTF-8 文件带 BOM 头(隐藏字符)
  • 使用了 Tab 键缩进,YAML 要求用空格
  • 缩进层级不对

解决

  • 不要用记事本,用 VS Code 或 GitLab 网页编辑器
  • 确保右下角显示 “Spaces: 2”“UTF-8”
  • 在 GitLab 网页直接编辑 .gitlab-ci.yml

❌ 17. 分支不匹配

现象:流水线只有 build_job,没有 deploy_job。

原因.gitlab-ci.yml 写了 only: - main,但 Git 分支是 master

解决

only:
  - main
  - master    # 加上这行,两个分支都能触发

❌ 18. Git 身份未配置

现象

fatal: unable to auto-detect email address

解决

git config user.email "duke@example.com"
git config user.name "Duke"

❌ 19. SSH 公钥认证失败

现象

git@172.19.90.78: Permission denied (publickey).

解决

ssh-keygen -t ed25519 -C "duke@gitlab"
type %USERPROFILE%\.ssh\id_ed25519.pub

复制输出到 GitLab Preferences → SSH Keys 中添加。


❌ 20. Maven 依赖下载慢/超时

现象:build-backend 运行 30+ 分钟后失败,显示 Connection reset

原因:从 Maven 中央仓库下载依赖,国际网络不稳定。

解决:在 backend/ 目录创建 settings.xml,配置阿里云镜像:

<?xml version="1.0" encoding="UTF-8"?>
<settings>
  <mirrors>
    <mirror>
      <id>aliyun</id>
      <name>Aliyun Maven</name>
      <url>https://maven.aliyun.com/repository/public</url>
      <mirrorOf>central</mirrorOf>
    </mirror>
  </mirrors>
</settings>

然后在 .gitlab-ci.yml 中使用:

script:
  - mvn -s settings.xml clean package -DskipTests

❌ 21. npm 下载慢

现象:build-frontend 中 npm install 卡住或极慢。

原因:默认从 npmjs.org(国外源)下载。

解决:在构建脚本中切换淘宝镜像:

script:
  - npm config set registry https://registry.npmmirror.com
  - npm install
  - npm run build

🔴 Nginx 部署阶段

❌ 22. 403 Forbidden(Nginx 目录为空)

现象:访问 http://你的IP/ 显示 403 Forbidden

原因

  • /var/www/frontend/ 目录为空(deploy 没把文件复制过来)
  • Nginx 配置错误

解决

# 检查目录
ls -la /var/www/frontend/

# 修复权限
sudo chown -R www-data:www-data /var/www/frontend
sudo chmod 755 /var/www/frontend

# 重启 Nginx
sudo systemctl reload nginx

❌ 23. Shell Runner 权限不足

现象

cp: cannot create regular file '/var/www/frontend/': Permission denied
sudo: I'm sorry gitlab-runner. I'm afraid I can't do that

原因gitlab-runner 用户没有 sudo 权限执行 rmcpsystemctl 等命令。

解决

sudo tee /etc/sudoers.d/gitlab-runner << 'EOF'
gitlab-runner ALL=(ALL) NOPASSWD: /bin/rm, /bin/cp, /bin/mkdir, /bin/systemctl stop backend, /bin/systemctl start backend, /bin/systemctl status backend, /bin/systemctl daemon-reload
EOF
sudo chmod 440 /etc/sudoers.d/gitlab-runner
sudo visudo -c

❌ 24. Nginx 默认站点冲突

现象:访问 IP 显示的是 Nginx 默认欢迎页,而不是自己的项目。

解决

# 禁用默认站点
sudo rm -f /etc/nginx/sites-enabled/default

# 启用自己的站点
sudo ln -sf /etc/nginx/sites-available/fullstack /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx

🔴 Java + Vue 全栈部署阶段

❌ 25. 8081 端口被旧项目占用

现象:后端启动成功,但访问 http://你的IP:8081/hello 返回的是旧项目的页面或 404。

原因:之前部署的 java-demo 项目还在运行,占用了 8081 端口。

解决

# 查看所有 Java 进程
ps aux | grep java

# 查看所有 Java 相关的 systemd 服务
sudo systemctl list-units --type=service | grep -i java

# 停止并禁用旧服务
sudo systemctl stop java-demo
sudo systemctl disable java-demo

# 杀掉所有残留进程
sudo pkill -9 java

# 只启动新服务
sudo systemctl start backend

❌ 26. 后端接口 404

现象curl http://localhost:8081/hello 返回 404,但 curl http://localhost:8081/ 能返回内容。

原因:Controller 代码里映射的是根路径 /,不是 /hello

解决:修改 HelloController.java

@RestController
@RequestMapping("/hello")  // 加上这行
public class HelloController {
    @GetMapping
    public String hello() {
        return "Hello from Java Backend! 🎉";
    }
}

❌ 27. 前端调用后端跨域

现象:前端点击按钮调用后端接口,浏览器控制台报跨域错误。

原因:前端和后端在不同端口,浏览器安全策略限制。

解决

  • 生产环境:通过 Nginx 反向代理,前端和后端走同域(http://你的IP/api/ → 后端)
  • 开发环境vue.config.js 配置 proxy:
devServer: {
  proxy: {
    '/api': {
      target: 'http://你的IP:8081',
      changeOrigin: true
    }
  }
}

❌ 28. Vue 刷新页面 404

现象:点击前端路由正常,但直接刷新页面显示 Nginx 404。

原因:Vue 是单页应用(SPA),路由由前端处理,Nginx 找不到对应的物理文件。

解决:Nginx 配置 try_files

location / {
    root /var/www/frontend;
    index index.html;
    try_files $uri $uri/ /index.html;  # 关键:找不到文件回退到 index.html
}

🔴 其他问题

❌ 29. 路径嵌套问题

现象:解压 zip 后路径变成 D:\demo\gitlab\my-project\my-project\

解决

cd D:\demo\gitlab
rmdir /S /Q my-project
# 重新解压,确保路径是 D:\demo\gitlab\my-project\.gitlab-ci.yml

❌ 30. vim 卡死

现象:粘贴内容后 vim 无法退出。

解决

  • Esc 键,然后输入 :q! 回车,强制退出不保存
  • 推荐:用 tee 命令直接写文件,不用 vim

❌ 31. docker compose up -d 报错 no configuration file provided

原因:当前目录没有 docker-compose.yml

解决

cd /srv/gitlab
docker compose up -d

❌ 32. curl -I http://localhost:8080 返回 Connection reset by peer

原因:Nginx 和 Puma 端口冲突。

解决:在 docker-compose.ymlGITLAB_OMNIBUS_CONFIG 中加上:

nginx['listen_port'] = 80

然后重启容器。


❌ 33. sudo systemctl start backend 报错 Failed to start backend.service

原因:jar 包不存在,或服务文件配置错误。

解决

# 检查 jar 包是否存在
ls -la /opt/backend/app.jar

# 检查服务文件语法
sudo systemctl daemon-reload

# 手动测试启动
sudo java -jar /opt/backend/app.jar --server.port=8081

❌ 34. cp target/*.jar /opt/backend/app.jar 报错 Permission denied

原因gitlab-runner 用户没有写入权限。

解决

sudo chown -R gitlab-runner:gitlab-runner /opt/backend
sudo chmod 755 /opt/backend

❌ 35. 虚拟机重启后 GitLab 没自动启动

原因:容器没有设置开机自启,或 Docker 服务没启动。

解决

# 启动 Docker
sudo systemctl start docker

# 启动 GitLab
cd /srv/gitlab
docker compose up -d

💡 如果 Docker 已设置 restart: always,容器会自动启动,但需要 Docker 服务先起来。


❌ 36. nginx['listen_port'] has been deprecated

原因:GitLab 新版语法变了,但不影响使用。

解决:可以忽略,或改成新语法:

gitlab_rails['nginx']['listen_port'] = 80

📋 附录一:运维命令速查表

GitLab 容器

场景命令
启动 GitLabcd /srv/gitlab && docker compose up -d
停止 GitLabcd /srv/gitlab && docker compose down
查看 GitLab 日志docker logs -f gitlab
查看容器状态docker ps
查看 GitLab 内部服务docker exec -it gitlab gitlab-ctl status
重启 GitLab 配置docker exec -it gitlab gitlab-ctl reconfigure
获取 root 密码docker exec -it gitlab grep 'Password:' /etc/gitlab/initial_root_password

Nginx

场景命令
测试配置sudo nginx -t
重载配置sudo systemctl reload nginx
重启 Nginxsudo systemctl restart nginx
查看 Nginx 状态sudo systemctl status nginx

Java 后端

场景命令
启动服务sudo systemctl start backend
停止服务sudo systemctl stop backend
重启服务sudo systemctl restart backend
查看状态sudo systemctl status backend
查看端口监听sudo ss -tlnp | grep 8081
查看 Java 进程ps aux | grep java

GitLab Runner

场景命令
查看 Runner 列表sudo gitlab-runner list
验证 Runnersudo gitlab-runner verify
重启 Runnersudo systemctl restart gitlab-runner
Docker Runner 验证docker exec -it gitlab-runner gitlab-runner verify

系统

场景命令
查看磁盘df -h
查看内存free -h
查看 CPUnproc
查看 IPip addr show
查看进程ps aux | grep java
查看端口占用sudo ss -tlnp

📋 附录二:最佳实践总结

场景建议
编辑配置文件用 VS Code 或 GitLab 网页编辑器,不要用记事本
SSH 连接用 Win11 Terminal SSH,不要用 VMware 控制台
Docker 安装直接用 sudo apt install docker.io,不要折腾官方仓库
GitLab 初始化不要中途删除 config 目录,等容器完全启动
磁盘空间虚拟机至少分配 80GB,GitLab 非常吃空间
Runner 注册在项目里创建 Project Runner,不要用 Instance Runner
CI/CD 调试deploy 脚本里加 echo $(pwd)ls -la 查看实际路径
Nginx 部署确保 /var/www/ 目录权限正确,www-data 用户可读写
多项目部署旧项目停用时务必 systemctl disablepkill 清理残留进程
网络加速Maven 用阿里云镜像,npm 用淘宝镜像,Docker 用国内加速器
分支管理.gitlab-ci.yml 同时写 mainmaster,避免分支名不匹配
权限最小化sudoers 只给必要命令,不要给 ALL

🎉 恭喜你!

如果你跟着本文档一步一步做到了这里,那么你已经:

  • ✅ 在 VMware 上跑起了 Ubuntu Server 24.04
  • ✅ 安装了 Docker 和 Docker Compose
  • ✅ 部署了 GitLab CE 私有化代码仓库
  • ✅ 注册了 Docker Runner + Shell Runner
  • ✅ 配置了 Nginx 反向代理
  • ✅ 搭建了 Java + Vue 全栈自动化 CI/CD 流水线
  • ✅ 掌握了 30+ 个常见问题的排查方法

以后你的开发流程变成:

写代码 → git add → git commit → git push → 自动构建 → 自动部署 → 刷新浏览器看效果

再也不用手动登录服务器、手动编译、手动复制文件了。把时间省下来,喝杯咖啡,摸摸鱼,不香吗?☕😎

🖥️ 环境:Win11 + VMware / 阿里云 / 腾讯云 + Ubuntu Server 24.04 + GitLab CE 19.2
📝 共收录 42 个常见问题 及解决方案
🚀 祝你部署顺利,流水线永远绿灯!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值