java_demo/deploy.sh

286 lines
6.6 KiB
Bash
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/bin/bash
# Jenkins Demo 部署脚本
# 用于生产环境部署
set -e
# 配置变量
APP_NAME="jenkins-demo"
APP_VERSION="1.0.0"
DOCKER_IMAGE="${APP_NAME}:${APP_VERSION}"
CONTAINER_NAME="${APP_NAME}-prod"
APP_PORT="80"
CONTAINER_PORT="8080"
# 颜色输出
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# 日志函数
log_info() {
echo -e "${BLUE}[INFO]${NC} $1"
}
log_success() {
echo -e "${GREEN}[SUCCESS]${NC} $1"
}
log_warning() {
echo -e "${YELLOW}[WARNING]${NC} $1"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
# 检查Docker是否安装
check_docker() {
if ! command -v docker &> /dev/null; then
log_error "Docker未安装请先安装Docker"
exit 1
fi
log_info "Docker检查通过"
}
# 停止并移除现有容器
stop_existing_container() {
if docker ps -a --format 'table {{.Names}}' | grep -q "^${CONTAINER_NAME}$"; then
log_info "停止现有容器: ${CONTAINER_NAME}"
docker stop ${CONTAINER_NAME} || true
docker rm ${CONTAINER_NAME} || true
log_success "现有容器已停止并移除"
else
log_info "未发现现有容器: ${CONTAINER_NAME}"
fi
}
# 备份现有镜像
backup_current_image() {
if docker images | grep -q "${APP_NAME}.*latest"; then
BACKUP_TAG="backup-$(date +%Y%m%d-%H%M%S)"
log_info "备份当前镜像为: ${APP_NAME}:${BACKUP_TAG}"
docker tag ${APP_NAME}:latest ${APP_NAME}:${BACKUP_TAG}
log_success "镜像备份完成"
fi
}
# 拉取最新镜像
pull_latest_image() {
log_info "拉取最新镜像: ${DOCKER_IMAGE}"
if docker pull ${DOCKER_IMAGE}; then
docker tag ${DOCKER_IMAGE} ${APP_NAME}:latest
log_success "镜像拉取完成"
else
log_error "镜像拉取失败"
exit 1
fi
}
# 启动新容器
start_new_container() {
log_info "启动新容器: ${CONTAINER_NAME}"
docker run -d \
--name ${CONTAINER_NAME} \
--restart unless-stopped \
-p ${APP_PORT}:${CONTAINER_PORT} \
-e SPRING_PROFILES_ACTIVE=prod \
-e JAVA_OPTS="-Xms512m -Xmx1024m" \
-v /var/log/${APP_NAME}:/app/logs \
--health-cmd="curl -f http://localhost:${CONTAINER_PORT}/api/health || exit 1" \
--health-interval=30s \
--health-timeout=10s \
--health-retries=3 \
--health-start-period=60s \
${APP_NAME}:latest
log_success "容器启动完成"
}
# 健康检查
health_check() {
log_info "执行健康检查..."
local max_attempts=30
local attempt=1
while [ $attempt -le $max_attempts ]; do
if curl -f -s http://localhost:${APP_PORT}/api/health > /dev/null; then
log_success "应用程序健康检查通过"
return 0
fi
log_info "健康检查失败,重试 (${attempt}/${max_attempts})"
sleep 10
((attempt++))
done
log_error "健康检查失败,应用程序可能未正常启动"
return 1
}
# 回滚函数
rollback() {
log_warning "开始回滚操作..."
# 停止失败的容器
docker stop ${CONTAINER_NAME} || true
docker rm ${CONTAINER_NAME} || true
# 查找最新的备份镜像
BACKUP_IMAGE=$(docker images --format "table {{.Repository}}:{{.Tag}}" | grep "${APP_NAME}:backup-" | head -1)
if [ -n "$BACKUP_IMAGE" ]; then
log_info "使用备份镜像回滚: ${BACKUP_IMAGE}"
docker tag ${BACKUP_IMAGE} ${APP_NAME}:latest
start_new_container
if health_check; then
log_success "回滚成功"
else
log_error "回滚后健康检查仍然失败"
exit 1
fi
else
log_error "未找到备份镜像,无法回滚"
exit 1
fi
}
# 清理旧镜像
cleanup_old_images() {
log_info "清理旧的Docker镜像..."
# 保留最近的5个备份镜像
OLD_BACKUPS=$(docker images --format "table {{.Repository}}:{{.Tag}}" | grep "${APP_NAME}:backup-" | tail -n +6)
if [ -n "$OLD_BACKUPS" ]; then
echo "$OLD_BACKUPS" | while read -r image; do
log_info "删除旧备份镜像: $image"
docker rmi "$image" || true
done
fi
# 清理悬挂镜像
docker image prune -f
log_success "镜像清理完成"
}
# 显示部署信息
show_deployment_info() {
echo
log_success "=== 部署信息 ==="
echo "应用名称: ${APP_NAME}"
echo "应用版本: ${APP_VERSION}"
echo "容器名称: ${CONTAINER_NAME}"
echo "访问地址: http://localhost:${APP_PORT}"
echo "健康检查: http://localhost:${APP_PORT}/api/health"
echo "API文档: http://localhost:${APP_PORT}/api/users"
echo
log_success "=== 部署完成 ==="
}
# 主函数
main() {
log_info "开始部署 ${APP_NAME} v${APP_VERSION}"
# 检查环境
check_docker
# 备份现有镜像
backup_current_image
# 停止现有容器
stop_existing_container
# 拉取新镜像
pull_latest_image
# 启动新容器
start_new_container
# 健康检查
if health_check; then
# 清理旧镜像
cleanup_old_images
# 显示部署信息
show_deployment_info
else
# 健康检查失败,执行回滚
rollback
fi
}
# 脚本使用说明
usage() {
echo "用法: $0 [选项]"
echo
echo "选项:"
echo " deploy 执行部署(默认)"
echo " rollback 回滚到上一个版本"
echo " status 查看应用状态"
echo " logs 查看应用日志"
echo " stop 停止应用"
echo " help 显示帮助信息"
echo
}
# 查看应用状态
status() {
echo "=== 容器状态 ==="
docker ps -a --filter name=${CONTAINER_NAME}
echo
echo "=== 镜像列表 ==="
docker images | grep ${APP_NAME}
}
# 查看应用日志
logs() {
if docker ps --filter name=${CONTAINER_NAME} --format '{{.Names}}' | grep -q ${CONTAINER_NAME}; then
docker logs -f ${CONTAINER_NAME}
else
log_error "容器 ${CONTAINER_NAME} 未运行"
fi
}
# 停止应用
stop() {
log_info "停止应用..."
docker stop ${CONTAINER_NAME} || true
docker rm ${CONTAINER_NAME} || true
log_success "应用已停止"
}
# 根据参数执行不同操作
case "${1:-deploy}" in
deploy)
main
;;
rollback)
rollback
;;
status)
status
;;
logs)
logs
;;
stop)
stop
;;
help)
usage
;;
*)
log_error "未知参数: $1"
usage
exit 1
;;
esac