#!/bin/bash set -e SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" cd "$SCRIPT_DIR" # 颜色输出 RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' NC='\033[0m' log_info() { echo -e "${GREEN}[INFO]${NC} $1"; } log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; } log_error() { echo -e "${RED}[ERROR]${NC} $1"; } # 检查 .env 文件 if [ ! -f .env ]; then log_warn ".env 文件不存在,从 .env.example 创建..." cp .env.example .env log_warn "请编辑 .env 文件填入正确的配置值,然后重新运行此脚本。" exit 1 fi # 自动安装 Docker(支持全新系统,使用国内镜像加速) install_docker() { log_info "正在自动安装 Docker(使用国内镜像源)..." # 检测操作系统 if [ -f /etc/os-release ]; then . /etc/os-release OS=$ID else log_error "无法识别操作系统,请手动安装 Docker: https://docs.docker.com/engine/install/" exit 1 fi # 国内 Docker 安装源(阿里云镜像) DOCKER_MIRROR="https://mirrors.aliyun.com/docker-ce" case "$OS" in ubuntu|debian) log_info "检测到 $OS,使用 apt 安装(阿里云镜像源)..." apt-get update -qq apt-get install -y -qq ca-certificates curl gnupg install -m 0755 -d /etc/apt/keyrings curl -fsSL "${DOCKER_MIRROR}/linux/$OS/gpg" | gpg --dearmor -o /etc/apt/keyrings/docker.gpg chmod a+r /etc/apt/keyrings/docker.gpg echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] ${DOCKER_MIRROR}/linux/$OS $(. /etc/os-release && echo "$VERSION_CODENAME") stable" > /etc/apt/sources.list.d/docker.list apt-get update -qq apt-get install -y -qq docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin ;; centos|rhel|almalinux|rocky) log_info "检测到 $OS,使用 yum/dnf 安装(阿里云镜像源)..." yum install -y yum-utils 2>/dev/null || dnf install -y dnf-plugins-core 2>/dev/null # 添加阿里云 Docker 仓库 REPO_FILE="/etc/yum.repos.d/docker-ce.repo" yum-config-manager --add-repo "${DOCKER_MIRROR}/linux/centos/docker-ce.repo" 2>/dev/null || \ dnf config-manager --add-repo "${DOCKER_MIRROR}/linux/centos/docker-ce.repo" 2>/dev/null # 替换仓库 URL 为阿里云镜像(兜底确保) if [ -f "$REPO_FILE" ]; then sed -i "s|https://download.docker.com|${DOCKER_MIRROR}|g" "$REPO_FILE" fi yum install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin 2>/dev/null || \ dnf install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin 2>/dev/null ;; fedora) log_info "检测到 Fedora,使用 dnf 安装(阿里云镜像源)..." dnf install -y dnf-plugins-core dnf config-manager --add-repo "${DOCKER_MIRROR}/linux/fedora/docker-ce.repo" REPO_FILE="/etc/yum.repos.d/docker-ce.repo" if [ -f "$REPO_FILE" ]; then sed -i "s|https://download.docker.com|${DOCKER_MIRROR}|g" "$REPO_FILE" fi dnf install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin ;; *) log_warn "未适配的发行版: $OS,尝试使用官方一键脚本(阿里云镜像)..." curl -fsSL https://get.docker.com | sh -s -- --mirror Aliyun ;; esac # 启动 Docker 服务 systemctl enable docker systemctl start docker log_info "Docker 安装完成: $(docker --version)" # 配置 Docker Hub 镜像加速 configure_registry_mirrors } # 配置 Docker Hub 国内镜像加速 configure_registry_mirrors() { DAEMON_JSON="/etc/docker/daemon.json" # 如果已有配置且包含 registry-mirrors,跳过 if [ -f "$DAEMON_JSON" ] && grep -q "registry-mirrors" "$DAEMON_JSON"; then log_info "Docker 镜像加速已配置,跳过。" return fi log_info "配置 Docker Hub 国内镜像加速..." mkdir -p /etc/docker if [ -f "$DAEMON_JSON" ]; then # 已有 daemon.json 但没有 mirror 配置,备份后合并 cp "$DAEMON_JSON" "${DAEMON_JSON}.bak" # 简单处理:如果是空对象或简单 JSON,直接重写 log_warn "已有 $DAEMON_JSON,已备份为 ${DAEMON_JSON}.bak" fi cat > "$DAEMON_JSON" <<'EOF' { "registry-mirrors": [ "https://docker.1ms.run", "https://docker.xuanyuan.me", "https://docker.m.daocloud.io" ] } EOF # 重载 Docker 配置 systemctl daemon-reload systemctl restart docker log_info "Docker Hub 镜像加速配置完成。" } # 检查 Docker 环境 if ! command -v docker &> /dev/null; then log_warn "未找到 docker 命令。" # 检查 root 权限(安装需要) if [ "$(id -u)" -ne 0 ]; then log_error "安装 Docker 需要 root 权限,请使用 sudo 运行: sudo $0 $*" exit 1 fi install_docker fi if ! docker compose version &> /dev/null 2>&1 && ! command -v docker-compose &> /dev/null; then log_error "Docker Compose 未安装。如果刚安装了 Docker,请重新登录终端后重试。" exit 1 fi # 判断使用 docker-compose 还是 docker compose COMPOSE_CMD="docker compose" if ! docker compose version &> /dev/null 2>&1; then COMPOSE_CMD="docker-compose" fi ACTION=${1:-up} case $ACTION in up|start) log_info "构建并启动所有服务..." $COMPOSE_CMD up -d --build log_info "所有服务已启动。" echo "" $COMPOSE_CMD ps ;; down|stop) log_info "停止所有服务..." $COMPOSE_CMD down log_info "所有服务已停止。" ;; restart) log_info "重启所有服务..." $COMPOSE_CMD down $COMPOSE_CMD up -d --build log_info "所有服务已重启。" ;; logs) $COMPOSE_CMD logs -f ${2:-} ;; status) $COMPOSE_CMD ps ;; rebuild) SERVICE=${2:-} if [ -n "$SERVICE" ]; then log_info "重建服务: $SERVICE" $COMPOSE_CMD build --no-cache $SERVICE $COMPOSE_CMD up -d $SERVICE else log_info "重建所有服务..." $COMPOSE_CMD build --no-cache $COMPOSE_CMD up -d fi ;; ssl-init) log_info "初始化 SSL 证书..." EXTRA_ARGS="" if [ "${2:-}" = "--staging" ]; then EXTRA_ARGS="--staging" elif [ "${2:-}" = "--dry-run" ]; then EXTRA_ARGS="--dry-run" fi bash ./init-ssl.sh $EXTRA_ARGS ;; ssl-renew) log_info "手动续签 SSL 证书..." $COMPOSE_CMD run --rm certbot renew --webroot -w /var/www/certbot log_info "重新加载 Nginx..." docker exec youle-nginx nginx -s reload log_info "SSL 续签完成。" ;; ssl-status) log_info "查看 SSL 证书状态..." $COMPOSE_CMD run --rm certbot certificates ;; *) echo "用法: $0 {up|down|restart|logs|status|rebuild|ssl-init|ssl-renew|ssl-status} [service|option]" echo "" echo " up/start - 构建并启动所有服务" echo " down/stop - 停止所有服务" echo " restart - 重启所有服务" echo " logs - 查看日志 (可指定服务名)" echo " status - 查看服务状态" echo " rebuild - 无缓存重新构建 (可指定服务名)" echo " ssl-init - 首次申请 SSL 证书 (可加 --staging 或 --dry-run)" echo " ssl-renew - 手动续签 SSL 证书" echo " ssl-status - 查看证书状态和到期时间" exit 1 ;; esac