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里面包含了指令 直接复制就好)
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 流程,真正的生产环境可能还需要加灰度发布、回滚机制之类的,但对目前场景来说已经够用了。
四、常见问题和踩坑记录
最后总结下我遇到的一些坑:
SSH 免密失败
- 常见原因:防火墙没放端口、
.ssh权限不对。
- 常见原因:防火墙没放端口、
权限不足
deploy用户没加 sudo 权限,Runner 执行 systemctl 时报错。
Runner tag 没对上
.gitlab-ci.yml写了tags: deploy,但 Runner 注册时没加这个 tag,结果任务一直 pending。
环境变量缺失
- Runner 机器没装 JDK、Maven,打包直接失败。要记得补充
JAVA_HOME和MAVEN_HOME。
- Runner 机器没装 JDK、Maven,打包直接失败。要记得补充
小提醒
- 不要用 root 直接跑 Runner,风险太大。
.gitlab-ci.yml多加点echo,方便排查问题。
结语
这次把 GitLab CI/CD 跑通之后,算是把部署这件事自动化了,手工操作少了,心里更踏实。后面有机会的话,我还想继续探索下分环境部署、自动回滚这些更高级的玩法。