feat(val-blog): add 2026-04-30 dream journey post

This commit is contained in:
Chen Gu
2026-08-13 17:00:22 +08:00
committed by Chen Gu
parent 691f96e8a6
commit 81978704fc
941 changed files with 195468 additions and 755 deletions
+167
View File
@@ -0,0 +1,167 @@
#!/bin/bash
set -e
# 蓝绿部署脚本(Caddy 版本)
# 用法: ./deploy.sh [blue|green]
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
cd "$SCRIPT_DIR"
# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
# 日志函数
log_info() { echo -e "${GREEN}[INFO]${NC} $1"; }
log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
log_error() { echo -e "${RED}[ERROR]${NC} $1"; }
# 自动发现 Docker 网络名(兼容 docker compose 前缀)
detect_network() {
local net
net=$(docker network ls --format "{{.Name}}" | grep -E '^(gch3n-infra_)?gch3n-network$' | head -1 || true)
if [ -z "$net" ]; then
# 回退到默认 bridge,避免脚本直接失败
net="bridge"
log_warn "未发现 gch3n-network,回退使用 bridge 网络"
fi
echo "$net"
}
# 获取当前活跃的环境
get_active_color() {
local active=$(docker ps --filter "name=app-" --format "{{.Names}}" | grep -E "app-(blue|green)" | head -1)
if [ -z "$active" ]; then
echo "none"
else
echo "$active" | sed 's/app-//'
fi
}
# 健康检查(主机侧)
check_health() {
local color=$1
local port=$2
local max_attempts=30
local attempt=0
log_info "检查 $color 健康状态 (127.0.0.1:$port)..."
while [ $attempt -lt $max_attempts ]; do
if curl -fsS "http://127.0.0.1:$port/health" >/dev/null 2>&1; then
log_info "$color 健康检查通过 ✓"
return 0
fi
attempt=$((attempt + 1))
log_warn "健康检查尝试 $attempt/$max_attempts 失败,等待 2 秒..."
sleep 2
done
log_error "$color 健康检查失败 ✗"
return 1
}
# 部署到指定环境
deploy_to() {
local target_color=$1
local target_port=$2
local other_color=$3
local network_name=$4
log_info "开始部署到 $target_color 环境..."
# 1. 构建新镜像
log_info "构建 Docker 镜像..."
docker build -t "gch3n/app:$target_color" -t "gch3n/app:latest" ./app
# 2. 停止目标环境(如果存在)
if docker ps -q --filter "name=app-$target_color" | grep -q .; then
log_warn "停止现有的 $target_color 容器..."
docker stop "app-$target_color" || true
docker rm "app-$target_color" || true
fi
# 3. 启动新容器
log_info "启动 $target_color 容器(network=$network_name..."
docker run -d \
--name "app-$target_color" \
--network "$network_name" \
-p "127.0.0.1:$target_port:$target_port" \
-e "PORT=$target_port" \
-e "DEPLOY_COLOR=$target_color" \
--health-cmd="wget --quiet --tries=1 --spider http://localhost:$target_port/health || exit 1" \
--health-interval=10s \
--health-timeout=5s \
--health-retries=3 \
--health-start-period=10s \
--restart=unless-stopped \
"gch3n/app:$target_color"
# 4. 健康检查
if ! check_health "$target_color" "$target_port"; then
log_error "$target_color 部署失败,执行回滚..."
docker stop "app-$target_color" || true
docker rm "app-$target_color" || true
if [ "$other_color" != "none" ]; then
log_warn "保持 $other_color 环境运行"
fi
exit 1
fi
# 5. 停止旧环境(Caddy 会自动只转发健康后端)
if [ "$other_color" != "none" ] && [ "$other_color" != "$target_color" ]; then
log_info "停止旧环境 $other_color..."
docker stop "app-$other_color" || true
docker rm "app-$other_color" || true
fi
log_info "部署完成!当前活跃环境: $target_color"
log_info "Caddy 会自动反代到健康实例,访问: https://app.gch3n.online"
}
# 主逻辑
main() {
log_info "========================================"
log_info " gch3n.online 蓝绿部署脚本 (Caddy)"
log_info "========================================"
local network_name
network_name=$(detect_network)
# 获取当前活跃环境
local active=$(get_active_color)
log_info "当前活跃环境: $active"
# 确定目标环境
local target=$1
if [ -z "$target" ]; then
# 自动选择非活跃环境
if [ "$active" = "blue" ]; then
target="green"
else
target="blue"
fi
log_info "自动选择目标环境: $target"
fi
# 验证参数
if [ "$target" != "blue" ] && [ "$target" != "green" ]; then
log_error "无效的环境: $target,只能是 blue 或 green"
exit 1
fi
# 确定端口
local target_port=3001
[ "$target" = "green" ] && target_port=3002
# 执行部署
deploy_to "$target" "$target_port" "$active" "$network_name"
}
# 执行
main "$@"