使用自托管的方式
This commit is contained in:
@@ -1,50 +1,147 @@
|
|||||||
name: 构建并部署 Spring Boot 应用
|
name: 构建并部署 Spring Boot 应用
|
||||||
on: [push]
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [main, develop]
|
||||||
|
pull_request:
|
||||||
|
branches: [main]
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build-and-deploy:
|
build-and-deploy:
|
||||||
container:
|
runs-on: self-hosted # 使用自托管 Runner
|
||||||
image: maven:3.8.6-openjdk-17
|
|
||||||
options: --pull=always
|
|
||||||
|
|
||||||
runs-on: ubuntu-24.04 # 使用更稳定的标签
|
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: 检出代码
|
- name: 检出代码
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: 设置 JDK 17
|
||||||
|
uses: actions/setup-java@v4
|
||||||
|
with:
|
||||||
|
java-version: '17'
|
||||||
|
distribution: 'temurin'
|
||||||
|
cache: 'maven'
|
||||||
|
|
||||||
|
- name: 验证环境
|
||||||
|
run: |
|
||||||
|
echo "Runner 工作目录: $(pwd)"
|
||||||
|
echo "Docker 信息:"
|
||||||
|
docker --version
|
||||||
|
docker info
|
||||||
|
echo "Maven 信息:"
|
||||||
|
mvn --version
|
||||||
|
|
||||||
- name: 缓存 Maven 依赖
|
- name: 缓存 Maven 依赖
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v3
|
||||||
with:
|
with:
|
||||||
path: ~/.m2/repository
|
path: ~/.m2/repository
|
||||||
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
|
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
|
||||||
|
restore-keys: |
|
||||||
|
${{ runner.os }}-maven-
|
||||||
|
|
||||||
- name: 使用 Maven 打包
|
- name: 运行测试
|
||||||
run: mvn clean package -DskipTests
|
run: mvn test
|
||||||
|
|
||||||
- name: 验证构建结果
|
- name: 使用 Jib 构建到本地 Docker
|
||||||
run: ls -la target/*.jar
|
|
||||||
|
|
||||||
- name: 构建 Docker 镜像
|
|
||||||
run: docker build -t light-delivery-app:latest .
|
|
||||||
|
|
||||||
- name: 部署到服务器
|
|
||||||
env:
|
|
||||||
SSH_PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_KEY }}
|
|
||||||
SERVER_IP: ${{ secrets.SERVER_IP }}
|
|
||||||
run: |
|
run: |
|
||||||
mkdir -p ~/.ssh
|
# 使用 Jib 直接构建到本地 Docker 守护进程
|
||||||
echo "$SSH_PRIVATE_KEY" > ~/.ssh/deploy_key
|
# 这会利用 Jib 的分层缓存机制,后续构建会更快
|
||||||
chmod 600 ~/.ssh/deploy_key
|
mvn compile jib:dockerBuild -DskipTests \
|
||||||
ssh-keyscan $SERVER_IP >> ~/.ssh/known_hosts
|
-Djib.to.image=light-delivery-app:latest \
|
||||||
|
-Djib.container.ports=8080,8443 \
|
||||||
|
-Djib.container.environment.SPRING_PROFILES_ACTIVE=prod \
|
||||||
|
-Djib.container.jvmFlags=-Xmx512m,-Xms256m
|
||||||
|
|
||||||
ssh -i ~/.ssh/deploy_key root@$SERVER_IP '
|
- name: 验证镜像构建
|
||||||
docker stop light-delivery-container || true
|
run: |
|
||||||
docker rm light-delivery-container || true
|
echo "构建的 Docker 镜像:"
|
||||||
docker run -d \
|
docker images | grep light-delivery-app
|
||||||
--name light-delivery-container \
|
echo "镜像详情:"
|
||||||
-p 443:443 -p 80:80 \
|
docker inspect light-delivery-app:latest --format='Size: {{.Size}} bytes, Created: {{.Created}}'
|
||||||
-v /etc/ssl/certs:/etc/ssl/certs:ro \
|
|
||||||
-e KEY_STORE_PASSWORD="$(cat /etc/ssl/certs/keyStorePass.txt)" \
|
- name: 停止旧容器
|
||||||
light-delivery-app:latest
|
run: |
|
||||||
'
|
# 优雅停止旧容器
|
||||||
|
docker stop light-delivery-container 2>/dev/null || echo "没有运行中的容器"
|
||||||
|
docker rm light-delivery-container 2>/dev/null || echo "没有可删除的容器"
|
||||||
|
|
||||||
|
- name: 备份当前镜像(可选)
|
||||||
|
run: |
|
||||||
|
# 为当前运行中的镜像创建备份标签
|
||||||
|
if docker images light-delivery-app:latest --quiet | grep -q .; then
|
||||||
|
BACKUP_TAG="backup-$(date +%Y%m%d-%H%M%S)"
|
||||||
|
docker tag light-delivery-app:latest light-delivery-app:$BACKUP_TAG
|
||||||
|
echo "已创建备份: light-delivery-app:$BACKUP_TAG"
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: 运行新容器
|
||||||
|
run: |
|
||||||
|
# 创建必要的目录
|
||||||
|
sudo mkdir -p /app/logs
|
||||||
|
sudo mkdir -p /etc/ssl/certs
|
||||||
|
sudo chown $USER:$USER /app/logs 2>/dev/null || true
|
||||||
|
|
||||||
|
echo "启动新容器..."
|
||||||
|
docker run -d \
|
||||||
|
--name light-delivery-container \
|
||||||
|
--restart=unless-stopped \
|
||||||
|
--log-opt max-size=10m \
|
||||||
|
--log-opt max-file=3 \
|
||||||
|
-p 8080:8080 \
|
||||||
|
-p 8443:8443 \
|
||||||
|
-e SPRING_PROFILES_ACTIVE=prod \
|
||||||
|
-e JAVA_OPTS="-Xmx512m -Xms256m -Djava.security.egd=file:/dev/./urandom" \
|
||||||
|
-v /app/logs:/app/logs \
|
||||||
|
-v /etc/ssl/certs:/etc/ssl/certs:ro \
|
||||||
|
-e SERVER_SSL_KEY_STORE_PASSWORD="${{ secrets.KEY_STORE_PASSWORD }}" \
|
||||||
|
light-delivery-app:latest
|
||||||
|
|
||||||
|
- name: 等待应用启动并健康检查
|
||||||
|
run: |
|
||||||
|
echo "等待应用启动..."
|
||||||
|
# 最大重试次数
|
||||||
|
MAX_RETRIES=12
|
||||||
|
RETRY_COUNT=0
|
||||||
|
|
||||||
|
while [ $RETRY_COUNT -lt $MAX_RETRIES ]; do
|
||||||
|
if curl -f -s http://localhost:8080/actuator/health > /dev/null 2>&1; then
|
||||||
|
echo "✅ 应用健康检查通过"
|
||||||
|
|
||||||
|
# 获取详细的健康信息
|
||||||
|
HEALTH_INFO=$(curl -s http://localhost:8080/actuator/health)
|
||||||
|
echo "健康状态: $HEALTH_INFO"
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
|
||||||
|
RETRY_COUNT=$((RETRY_COUNT + 1))
|
||||||
|
echo "健康检查失败 ($RETRY_COUNT/$MAX_RETRIES),10秒后重试..."
|
||||||
|
sleep 10
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ $RETRY_COUNT -eq $MAX_RETRIES ]; then
|
||||||
|
echo "❌ 应用启动超时,查看日志:"
|
||||||
|
docker logs light-delivery-container --tail 50
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: 清理资源
|
||||||
|
run: |
|
||||||
|
# 清理旧的备份镜像(保留最近5个)
|
||||||
|
echo "清理旧的备份镜像..."
|
||||||
|
docker images light-delivery-app --filter "reference=light-delivery-app:backup-*" \
|
||||||
|
--format "{{.Tag}}\t{{.CreatedAt}}" | \
|
||||||
|
sort -k2 -r | \
|
||||||
|
tail -n +6 | \
|
||||||
|
awk '{print $1}' | \
|
||||||
|
xargs -r -I {} docker rmi light-delivery-app:{} || echo "无需清理"
|
||||||
|
|
||||||
|
# 清理无用镜像和容器
|
||||||
|
docker system prune -f
|
||||||
|
|
||||||
|
- name: 部署完成通知
|
||||||
|
run: |
|
||||||
|
echo "🎉 部署完成!"
|
||||||
|
echo "应用运行在: http://localhost:8080"
|
||||||
|
echo "容器状态: $(docker inspect light-delivery-container --format='{{.State.Status}}')"
|
||||||
|
echo "启动时间: $(docker inspect light-delivery-container --format='{{.State.StartedAt}}')"
|
Reference in New Issue
Block a user