从手动部署到自动化:GitLab Runner 实现 CI/CD 的实战笔记

📘 开发记录 · 2025-09-29 · 459 人浏览
从手动部署到自动化:GitLab Runner 实现 CI/CD 的实战笔记
🤖AI摘要

之前我们公司的项目都是靠手动部署:打包、拷贝、登录服务器、重启服务……一套流程下来经常要二三十分钟,而且每次发版都容易手忙脚乱。为了减少这种重复劳动,我决定在项目里接入 GitLab CI/CD,把部署自动化。

下面是我在折腾 GitLab Runner 的完整过程,包含安装、配置、免密登录,以及 .gitlab-ci.yml 的实际案例,还有一些踩坑记录。算是一次实战笔记,写下来给自己留个档,也希望能帮到有类似需求的人。


一、GitLab Runner 安装与配置

1. 在 Linux 服务器上安装 GitLab Runner

安装 Runner 其实很简单,官方提供了一键脚本:

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

# 安装最新版本的 GitLab Runner
sudo yum install gitlab-runner -y

# 如果是 Ubuntu/Debian,用 apt 安装
curl -L "https://packages.gitlab.com/install/repositories/runner/gitlab-runner/script.deb.sh" | sudo bash
sudo apt-get install gitlab-runner -y

我个人习惯直接用官方源,省事儿,不用再去找 rpm 或 deb 包。


2. 注册 GitLab Runner

装好 Runner 后,要让它和 GitLab 绑定。这里用 gitlab-runner register

sudo gitlab-runner register

一路输入配置信息:

  • GitLab instance URL: http://10.0.5.169/
  • Registration token: 在项目设置 -> CI/CD -> Runners 里获取
  • Description: 比如 Production Deployment Runner
  • Tags: 我用了 deploy,production,war
  • Executor: 我选了 shell,本地执行脚本最简单

第一次填的时候有点紧张,生怕输错 😂,不过输错了也没事,重新来一次就好。
~后面发现gitlab runner里面包含了指令 直接复制就好
image.png


2.1 创建部署用户(deploy)

为了安全起见,我没有直接用 root,而是单独创建了一个 deploy 用户:

sudo useradd -m -s /bin/bash deploy
sudo passwd deploy

给它加 sudo 权限:

# Ubuntu/Debian
sudo usermod -aG sudo deploy

# CentOS/RHEL
sudo usermod -aG wheel deploy

第一次忘了加 sudo,结果 Runner 脚本执行的时候各种权限错误,只能回头补上。


2.2 配置 sudo 免密码(可选)

有些命令(比如重启 Tomcat)如果每次都要输入密码,会很麻烦。于是我给 deploy 用户加了免密码配置:

sudo visudo

在文件末尾添加:

deploy ALL=(ALL) NOPASSWD: /opt/tomcat9/bin/*, \
/usr/bin/systemctl restart tomcat*, \
/usr/bin/systemctl stop tomcat*, \
/usr/bin/systemctl start tomcat*

这里千万不要图省事直接给 ALL,只开放必要命令就行。


3. 配置 SSH 免密登录

Runner 需要免密登录到部署服务器。先在 Runner 机器上切换到 gitlab-runner 用户并生成 SSH 密钥:

sudo -u gitlab-runner -H bash
ssh-keygen -t rsa -b 2048 -N "" -f ~/.ssh/id_rsa
cat ~/.ssh/id_rsa.pub
exit

然后把公钥加到部署服务器的 authorized_keys

ssh [email protected]
mkdir -p ~/.ssh && chmod 700 ~/.ssh
echo "粘贴上面的公钥" >> ~/.ssh/authorized_keys
chmod 600 ~/.ssh/authorized_keys

更省事的方式:

sudo -u gitlab-runner ssh-copy-id [email protected]

我第一次用 ssh-copy-id 的时候,因为防火墙没放 22 端口,折腾了半天才反应过来 😂。


4. 测试免密连接

最后一定要测试:

sudo -u gitlab-runner ssh [email protected] "echo 'SSH连接成功'"

能正常输出说明搞定。


二、编写 .gitlab-ci.yml

Runner 配好后,还需要在项目里写 .gitlab-ci.yml,告诉它每一步该怎么执行。下面是我的服务器配置,大家可以参考,主要操作就是先打war包,然后把war推送到目标部署服务器。服务器tomcat关闭,然后替换war,启动。当然之前的war包也进行了按日期备份:

stages:
  - build
  - deploy

variables:
  MAVEN_CLI_OPTS: "--batch-mode --errors --fail-at-end --show-version -Dmaven.repo.local=$CI_PROJECT_DIR/.m2/repository"
  # === 路径与部署参数(按需修改) ===
  POM_DIR: "code/service"               # ← pom.xml 所在目录
  APP_NAME: "tjzc-service"              # 部署到 webapps 后的名字:${APP_NAME}.war
  LINUX_SERVER: "10.0.5.166"
  LINUX_USER: "deploy"
  LINUX_TOMCAT: "/data/soft/tomcat"     # Tomcat 根目录(含 webapps/)
  TOMCAT_SERVICE: "tomcat"              # systemctl 的服务名,例如 tomcat/tomcat9
  BACKUP_BASE: "/backup/tomcat"         # 备份根路径
  BACKUP_RETENTION_DAYS: "30"           # 备份保留天数

# 1) 构建(Runner 自带 Maven/JDK)
build:
  stage: build
  tags: [deploy]
  script:
    - set -e
    - test -f "$POM_DIR/pom.xml" || (echo "找不到 $POM_DIR/pom.xml,请检查 POM_DIR" && exit 1)
    - cd "$POM_DIR"
    - mvn $MAVEN_CLI_OPTS clean package -DskipTests
  artifacts:
    paths:
      - $POM_DIR/target/*.war
    expire_in: 7 days

# 2) 部署(停服 → 备份(若有) → 上传 → 启动)
deploy-linux:
  stage: deploy
  tags: [deploy]
  needs: ["build"]
  script:
    - set -euo pipefail
    # 取构建产物(如有多包,取第一个;可按需改名匹配)
    - WAR_FILE=$(ls "$POM_DIR"/target/*.war | head -1)
    - REMOTE_WAR="${LINUX_TOMCAT}/webapps/${APP_NAME}.war"

    # 停止 Tomcat
    - ssh ${LINUX_USER}@${LINUX_SERVER} "${LINUX_TOMCAT}/bin/shutdown.sh || true"

    # 若存在旧 war/目录则备份至带时间戳目录,并清理超期备份
    - |
      ssh ${LINUX_USER}@${LINUX_SERVER} "
        set -e
        TIMESTAMP=\$(date +%F_%H%M%S)
        BACKUP_DIR='${BACKUP_BASE}/${APP_NAME}/'\"\$TIMESTAMP\"
        mkdir -p \"\$BACKUP_DIR\"

        # 备份 war(如果存在)
        if [ -f '${LINUX_TOMCAT}/webapps/${APP_NAME}.war' ]; then
          mv '${LINUX_TOMCAT}/webapps/${APP_NAME}.war' \"\$BACKUP_DIR/\"
        fi

        # 备份解压目录(如果存在)
        if [ -d '${LINUX_TOMCAT}/webapps/${APP_NAME}' ]; then
          tar -C '${LINUX_TOMCAT}/webapps' -czf \"\$BACKUP_DIR/${APP_NAME}.dir.tgz\" '${APP_NAME}'
          rm -rf '${LINUX_TOMCAT}/webapps/${APP_NAME}'
        fi

        # 清理超过 ${BACKUP_RETENTION_DAYS} 天的备份
        find '${BACKUP_BASE}/${APP_NAME}' -mindepth 1 -maxdepth 1 -type d -mtime +${BACKUP_RETENTION_DAYS} -exec rm -rf {} +
      "

    # 上传新 war(重命名为 ${APP_NAME}.war)
    - scp "$WAR_FILE" ${LINUX_USER}@${LINUX_SERVER}:"$REMOTE_WAR"

    # 启动 Tomcat (使用 startup.sh 脚本)
    - ssh ${LINUX_USER}@${LINUX_SERVER} "${LINUX_TOMCAT}/bin/startup.sh"
    - |
      ssh ${LINUX_USER}@${LINUX_SERVER} "
        for i in \$(seq 1 60); do
          pgrep -f 'org.apache.catalina.startup.Bootstrap' >/dev/null && exit 0
          sleep 1
        done
        echo 'Tomcat 进程未在 60 秒内启动' >&2; exit 1
      "
  environment:
    name: production

我这里分了两个阶段:

  • build:用 Maven 打包
  • deploy:传到服务器,重启 Tomcat

第一次跑的时候卡在 scp,因为免密配置没生效,还要输密码。修好后就顺畅多了。


三、一些小感受

整个流程跑通后,心里还是挺有成就感的。以前一套手动操作下来动不动 20 分钟,现在基本就是点一下,等 Runner 自己跑完,省时省力。

当然这只是一个入门级的 CI/CD 流程,真正的生产环境可能还需要加灰度发布、回滚机制之类的,但对目前场景来说已经够用了。


四、常见问题和踩坑记录

最后总结下我遇到的一些坑:

  1. SSH 免密失败

    • 常见原因:防火墙没放端口、.ssh 权限不对。
  2. 权限不足

    • deploy 用户没加 sudo 权限,Runner 执行 systemctl 时报错。
  3. Runner tag 没对上

    • .gitlab-ci.yml 写了 tags: deploy,但 Runner 注册时没加这个 tag,结果任务一直 pending。
  4. 环境变量缺失

    • Runner 机器没装 JDK、Maven,打包直接失败。要记得补充 JAVA_HOMEMAVEN_HOME
  5. 小提醒

    • 不要用 root 直接跑 Runner,风险太大。
    • .gitlab-ci.yml 多加点 echo,方便排查问题。

结语

这次把 GitLab CI/CD 跑通之后,算是把部署这件事自动化了,手工操作少了,心里更踏实。后面有机会的话,我还想继续探索下分环境部署、自动回滚这些更高级的玩法。


Under CC BY NC-SA License.
Powered by Typecho | Theme by Jasmine
您是第 71112 位访客