gitlab gitrunner springboot 多环境多分支部署 (非容器方式,使用原生linux 环境)

一、环境架构设计

环境分支策略:

  • master分支 -> 生产环境(production)

  • develop分支 -> 测试环境(testing)

  • feature/*分支 -> 开发环境(development)

服务器结构:

text

复制代码
GitLab Server (可托管或自建)
    ↓
GitLab Runner (注册到GitLab)
    ↓
部署目标服务器:
- 192.168.1.10:8080 (开发环境)
- 192.168.1.20:8080 (测试环境)  
- 192.168.1.30:8080 (生产环境)

二、准备工作

1. Spring Boot项目配置

application.yml (多环境配置):

yaml

复制代码
spring:
  profiles:
    active: @activatedProperties@

---
spring:
  config:
    activate:
      on-profile: development
server:
  port: 8080
app:
  environment: development

---
spring:
  config:
    activate:
      on-profile: testing
server:
  port: 8080
app:
  environment: testing

---
spring:
  config:
    activate:
      on-profile: production
server:
  port: 8080
app:
  environment: production

pom.xml (配置profile):

xml

复制代码
<profiles>
    <profile>
        <id>development</id>
        <properties>
            <activatedProperties>development</activatedProperties>
        </properties>
    </profile>
    <profile>
        <id>testing</id>
        <properties>
            <activatedProperties>testing</activatedProperties>
        </properties>
    </profile>
    <profile>
        <id>production</id>
        <properties>
            <activatedProperties>production</activatedProperties>
        </properties>
    </profile>
</profiles>

2. GitLab Runner安装配置

bash

复制代码
# 在Runner服务器安装
curl -L "https://packages.gitlab.com/install/repositories/runner/gitlab-runner/script.deb.sh" | sudo bash
sudo apt-get install gitlab-runner

# 注册Runner
sudo gitlab-runner register
# 输入GitLab URL: https://gitlab.example.com
# 输入注册令牌(从GitLab Admin > Runners获取)
# 标签: shell-runner,linux,springboot
# 执行器: shell

三、GitLab CI/CD配置

.gitlab-ci.yml:

yaml

复制代码
stages:
  - build
  - test
  - deploy

variables:
  MAVEN_OPTS: "-Dmaven.repo.local=$CI_PROJECT_DIR/.m2/repository"
  APP_NAME: "my-springboot-app"
  DEPLOY_USER: "deploy"
  
# 缓存Maven依赖
cache:
  paths:
    - .m2/repository/
    - target/

# 1. 构建阶段
build-job:
  stage: build
  script:
    - echo "Building application..."
    - mvn clean package -DskipTests
  artifacts:
    paths:
      - target/*.jar
    expire_in: 1 hour
  only:
    - branches
  tags:
    - shell-runner

# 2. 测试阶段  
unit-test:
  stage: test
  script:
    - echo "Running unit tests..."
    - mvn test
  only:
    - develop
    - master
  tags:
    - shell-runner

# 3. 开发环境部署
deploy-development:
  stage: deploy
  variables:
    DEPLOY_SERVER: "192.168.1.10"
    DEPLOY_PATH: "/opt/apps/development"
    PROFILE: "development"
  script:
    - |
      echo "Deploying to development environment..."
      # 停止现有应用
      ssh $DEPLOY_USER@$DEPLOY_SERVER "cd $DEPLOY_PATH && ./stop.sh || true"
      
      # 传输文件
      scp target/*.jar $DEPLOY_USER@$DEPLOY_SERVER:$DEPLOY_PATH/
      scp deploy-scripts/start-development.sh $DEPLOY_USER@$DEPLOY_SERVER:$DEPLOY_PATH/start.sh
      scp deploy-scripts/stop.sh $DEPLOY_USER@$DEPLOY_SERVER:$DEPLOY_PATH/
      
      # 启动应用
      ssh $DEPLOY_USER@$DEPLOY_SERVER "cd $DEPLOY_PATH && chmod +x *.sh && ./start.sh"
  environment:
    name: development
    url: http://192.168.1.10:8080
  only:
    - /^feature\/.*$/
  tags:
    - shell-runner

# 4. 测试环境部署
deploy-testing:
  stage: deploy
  variables:
    DEPLOY_SERVER: "192.168.1.20"
    DEPLOY_PATH: "/opt/apps/testing"
    PROFILE: "testing"
  script:
    - |
      echo "Deploying to testing environment..."
      # 构建测试包
      mvn clean package -Ptesting -DskipTests
      
      # 传输文件
      scp target/*.jar $DEPLOY_USER@$DEPLOY_SERVER:$DEPLOY_PATH/
      scp deploy-scripts/start-testing.sh $DEPLOY_USER@$DEPLOY_SERVER:$DEPLOY_PATH/start.sh
      
      # 部署
      ssh $DEPLOY_USER@$DEPLOY_SERVER "cd $DEPLOY_PATH && ./stop.sh || true"
      ssh $DEPLOY_USER@$DEPLOY_SERVER "cd $DEPLOY_PATH && chmod +x *.sh && ./start.sh"
  environment:
    name: testing
    url: http://192.168.1.20:8080
  only:
    - develop
  tags:
    - shell-runner
  when: manual  # 测试环境需要手动触发

# 5. 生产环境部署
deploy-production:
  stage: deploy
  variables:
    DEPLOY_SERVER: "192.168.1.30"
    DEPLOY_PATH: "/opt/apps/production"
    PROFILE: "production"
  before_script:
    - echo "Starting production deployment..."
  script:
    - |
      # 构建生产包
      mvn clean package -Pproduction -DskipTests
      
      # 备份当前版本
      ssh $DEPLOY_USER@$DEPLOY_SERVER "cd $DEPLOY_PATH && cp $APP_NAME.jar $APP_NAME.jar.backup.$(date +%Y%m%d%H%M%S) || true"
      
      # 传输文件
      scp target/*.jar $DEPLOY_USER@$DEPLOY_SERVER:$DEPLOY_PATH/$APP_NAME.jar
      scp deploy-scripts/start-production.sh $DEPLOY_USER@$DEPLOY_SERVER:$DEPLOY_PATH/start.sh
      scp deploy-scripts/stop.sh $DEPLOY_USER@$DEPLOY_SERVER:$DEPLOY_PATH/
      scp deploy-scripts/health-check.sh $DEPLOY_USER@$DEPLOY_SERVER:$DEPLOY_PATH/
      
      # 滚动部署
      ssh $DEPLOY_USER@$DEPLOY_SERVER "cd $DEPLOY_PATH && ./stop.sh"
      sleep 10
      ssh $DEPLOY_USER@$DEPLOY_SERVER "cd $DEPLOY_PATH && chmod +x *.sh && ./start.sh"
      
      # 健康检查
      ssh $DEPLOY_USER@$DEPLOY_SERVER "cd $DEPLOY_PATH && ./health-check.sh"
  environment:
    name: production
    url: http://192.168.1.30:8080
  only:
    - master
  tags:
    - shell-runner
  when: manual  # 生产环境需要手动触发

四、部署脚本

deploy-scripts/start-development.sh:

bash

复制代码
#!/bin/bash
APP_NAME="my-springboot-app"
DEPLOY_PATH="/opt/apps/development"
LOG_PATH="/var/log/$APP_NAME"

# 创建日志目录
mkdir -p $LOG_PATH

# 启动应用(开发环境)
nohup java -jar \
  -Dspring.profiles.active=development \
  -Dserver.port=8080 \
  $DEPLOY_PATH/$APP_NAME.jar \
  > $LOG_PATH/app.log 2>&1 &

echo $! > $DEPLOY_PATH/app.pid
echo "Application started with PID: $(cat $DEPLOY_PATH/app.pid)"

deploy-scripts/start-testing.sh:

bash

复制代码
#!/bin/bash
APP_NAME="my-springboot-app"
DEPLOY_PATH="/opt/apps/testing"
LOG_PATH="/var/log/$APP_NAME"
JAVA_OPTS="-Xms512m -Xmx1024m -XX:+UseG1GC"

mkdir -p $LOG_PATH

nohup java $JAVA_OPTS -jar \
  -Dspring.profiles.active=testing \
  -Dserver.port=8080 \
  $DEPLOY_PATH/$APP_NAME.jar \
  > $LOG_PATH/app.log 2>&1 &

echo $! > $DEPLOY_PATH/app.pid

deploy-scripts/start-production.sh:

bash

复制代码
#!/bin/bash
APP_NAME="my-springboot-app"
DEPLOY_PATH="/opt/apps/production"
LOG_PATH="/var/log/$APP_NAME"
JAVA_OPTS="-Xms1g -Xmx2g -XX:+UseG1GC -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=$LOG_PATH"

mkdir -p $LOG_PATH

nohup java $JAVA_OPTS -jar \
  -Dspring.profiles.active=production \
  -Dserver.port=8080 \
  -Dlogging.file.path=$LOG_PATH \
  $DEPLOY_PATH/$APP_NAME.jar \
  > $LOG_PATH/console.log 2>&1 &

echo $! > $DEPLOY_PATH/app.pid
echo "Production application started with PID: $(cat $DEPLOY_PATH/app.pid)"

deploy-scripts/stop.sh:

bash

复制代码
#!/bin/bash
APP_NAME="my-springboot-app"
DEPLOY_PATH="/opt/apps"

# 根据当前目录确定环境
CURRENT_ENV=$(basename $(pwd))
PID_FILE="$DEPLOY_PATH/$CURRENT_ENV/app.pid"

if [ -f "$PID_FILE" ]; then
  PID=$(cat $PID_FILE)
  if ps -p $PID > /dev/null; then
    echo "Stopping application (PID: $PID)..."
    kill $PID
    sleep 10
    if ps -p $PID > /dev/null; then
      echo "Force stopping application..."
      kill -9 $PID
    fi
  fi
  rm -f $PID_FILE
fi

deploy-scripts/health-check.sh:

bash

复制代码
#!/bin/bash
APP_URL="http://localhost:8080/actuator/health"
MAX_RETRY=30
RETRY_INTERVAL=5

for i in $(seq 1 $MAX_RETRY); do
  response=$(curl -s -o /dev/null -w "%{http_code}" $APP_URL)
  if [ "$response" = "200" ]; then
    echo "Application is healthy!"
    exit 0
  fi
  echo "Health check attempt $i/$MAX_RETRY failed. Retrying in $RETRY_INTERVAL seconds..."
  sleep $RETRY_INTERVAL
done

echo "Health check failed after $MAX_RETRY attempts"
exit 1

五、服务器准备

1. 部署服务器配置(每台环境服务器):

bash

复制代码
# 创建部署用户
sudo useradd -m -s /bin/bash deploy
sudo passwd deploy

# 创建应用目录
sudo mkdir -p /opt/apps/{development,testing,production}
sudo chown -R deploy:deploy /opt/apps

# 安装Java
sudo apt update
sudo apt install -y openjdk-11-jdk

# 配置SSH密钥认证(用于GitLab Runner连接)
# 在GitLab Runner服务器生成密钥,并将公钥复制到部署服务器的~/.ssh/authorized_keys

2. 配置免密SSH登录:

bash

复制代码
# 在GitLab Runner服务器执行
sudo -u gitlab-runner ssh-keygen -t rsa
sudo -u gitlab-runner cat ~/.ssh/id_rsa.pub

# 将公钥添加到各环境服务器的deploy用户
# 在目标服务器执行:
mkdir -p /home/deploy/.ssh
echo "ssh-rsa [PUBLIC_KEY]" >> /home/deploy/.ssh/authorized_keys
chmod 600 /home/deploy/.ssh/authorized_keys
chown -R deploy:deploy /home/deploy/.ssh

六、高级配置

1. 环境变量管理

在GitLab项目的 Settings > CI/CD > Variables 中添加:

  • PRODUCTION_SERVER_PRIVATE_KEY (生产服务器私钥)

  • TESTING_SERVER_PRIVATE_KEY (测试服务器私钥)

  • DB_PRODUCTION_PASSWORD

  • DB_TESTING_PASSWORD

2. 回滚脚本

deploy-scripts/rollback.sh:

bash

复制代码
#!/bin/bash
ENV=${1:-production}
DEPLOY_PATH="/opt/apps/$ENV"
APP_NAME="my-springboot-app"

# 查找最新的备份文件
BACKUP_FILE=$(ls -t $DEPLOY_PATH/$APP_NAME.jar.backup.* 2>/dev/null | head -1)

if [ -z "$BACKUP_FILE" ]; then
  echo "No backup file found for rollback"
  exit 1
fi

echo "Rolling back to: $BACKUP_FILE"

# 停止当前应用
cd $DEPLOY_PATH && ./stop.sh

# 恢复备份
cp $BACKUP_FILE $DEPLOY_PATH/$APP_NAME.jar

# 启动应用
cd $DEPLOY_PATH && ./start.sh

七、监控与维护

1. 日志轮转配置

/etc/logrotate.d/my-springboot-app:

bash

复制代码
/var/log/my-springboot-app/*.log {
    daily
    rotate 30
    compress
    delaycompress
    missingok
    notifempty
    create 0644 deploy deploy
    postrotate
        # 重新打开日志文件
        /bin/kill -HUP $(cat /opt/apps/production/app.pid 2>/dev/null) 2>/dev/null || true
    endscript
}

2. 服务管理脚本

/etc/systemd/system/my-springboot-app.service (生产环境建议使用systemd):

ini

复制代码
[Unit]
Description=My Spring Boot Application
After=network.target

[Service]
Type=simple
User=deploy
WorkingDirectory=/opt/apps/production
ExecStart=/usr/bin/java -jar -Dspring.profiles.active=production my-springboot-app.jar
ExecStop=/bin/kill -15 $MAINPID
Restart=on-failure
RestartSec=10

[Install]
WantedBy=multi-user.target

八、使用流程

  1. 开发流程

    • 从develop创建feature分支

    • 开发完成后提交Merge Request到develop

    • CI会自动部署到开发环境验证

  2. 测试流程

    • develop分支合并后,手动触发测试环境部署

    • 测试通过后,创建release分支

  3. 生产发布

    • release分支合并到master

    • 手动触发生产环境部署

    • 监控应用健康状态

这个方案提供了完整的非容器化部署流程,具有以下特点:

  • ✅ 清晰的Git分支策略

  • ✅ 环境隔离配置

  • ✅ 自动化构建和部署

  • ✅ 手动审批控制(测试和生产)

  • ✅ 健康检查和监控

  • ✅ 支持回滚操作

  • ✅ 日志管理和轮转

相关推荐
LongQ30ZZ1 天前
Linux的常见指令
linux·服务器
走向IT1 天前
vdbench在Centos系统上联机测试环境搭建
linux·运维·centos
阳宗德1 天前
基于CentOS Linux release 7.1实现了Oracle Database 11g R2 企业版容器化运行
linux·数据库·docker·oracle·centos
liulilittle1 天前
libxdp: No bpffs found at /sys/fs/bpf
linux·运维·服务器·开发语言·c++
Byte Beat1 天前
ubuntu安装docker
linux·ubuntu·docker
HIT_Weston1 天前
88、【Ubuntu】【Hugo】搭建私人博客:侧边导航栏(二)
linux·运维·ubuntu
彩妙不是菜喵1 天前
操作系统中的Linux:进程详解--->(深入浅出)从入门到精通
linux·操作系统
enjoy编程1 天前
Spring boot 4 探究netty的关键知识点
spring boot·设计模式·reactor·netty·多线程
liulilittle1 天前
AF_XDP开发环境(Ubuntu24.04.3)
linux·运维·服务器·ubuntu