java_demo/deploy.sh

286 lines
6.6 KiB
Bash
Raw Normal View History

#!/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