147 lines
5.0 KiB
YAML
147 lines
5.0 KiB
YAML
name: 构建并部署 Spring Boot 应用
|
||
|
||
on:
|
||
push:
|
||
branches: [main, develop]
|
||
pull_request:
|
||
branches: [main]
|
||
|
||
jobs:
|
||
build-and-deploy:
|
||
runs-on: ubuntu-24.04 # 使用自托管 Runner
|
||
|
||
steps:
|
||
- name: 检出代码
|
||
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 依赖
|
||
uses: actions/cache@v3
|
||
with:
|
||
path: ~/.m2/repository
|
||
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
|
||
restore-keys: |
|
||
${{ runner.os }}-maven-
|
||
|
||
- name: 运行测试
|
||
run: mvn test
|
||
|
||
- name: 使用 Jib 构建到本地 Docker
|
||
run: |
|
||
# 使用 Jib 直接构建到本地 Docker 守护进程
|
||
# 这会利用 Jib 的分层缓存机制,后续构建会更快
|
||
mvn compile jib:dockerBuild -DskipTests \
|
||
-Djib.to.image=light-delivery-app:latest \
|
||
-Djib.container.ports=8080,8443 \
|
||
-Djib.container.environment.SPRING_PROFILES_ACTIVE=prod \
|
||
-Djib.container.jvmFlags=-Xmx512m,-Xms256m
|
||
|
||
- name: 验证镜像构建
|
||
run: |
|
||
echo "构建的 Docker 镜像:"
|
||
docker images | grep light-delivery-app
|
||
echo "镜像详情:"
|
||
docker inspect light-delivery-app:latest --format='Size: {{.Size}} bytes, Created: {{.Created}}'
|
||
|
||
- name: 停止旧容器
|
||
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}}')" |