#!/usr/bin/env bash ############################################################################### # AgentMeshOS 文档站 Docker 菜单部署脚本 # 用途:部署、更新、检查、备份和清理 AgentMeshOS 文档站容器 ############################################################################### SCRIPT_NAME="agentmeshos-docs-docker-deploy.sh" SCRIPT_PROJECT="docs-site" SCRIPT_VERSION="v0.1.2" SCRIPT_UPDATED="2026-07-04" RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' CYAN='\033[0;36m' NC='\033[0m' IMAGE_NAME="ghcr.io/michaellab7284/agentmeshos-docs:latest" CONTAINER_NAME="agentmeshos-docs" HOST_ADDR="127.0.0.1" HOST_PORT="39130" CONTAINER_PORT="39130" BACKUP_DIR="/backup/agentmeshos/docs-site" 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"; } log_highlight() { echo -e "${CYAN}$1${NC}"; } require_tty() { if [ ! -r /dev/tty ]; then log_error "未检测到可交互终端。请在 SSH/终端中执行本脚本,不要在无交互环境中运行。" exit 1 fi } read_tty() { local __var_name="$1" IFS= read -r "${__var_name}" /dev/null 2>&1; then log_error "未检测到 Docker,请先安装 Docker。" exit 1 fi if ! docker info >/dev/null 2>&1; then log_error "Docker 服务未运行或当前用户无权限访问 Docker。" exit 1 fi } print_config() { echo "" echo "当前配置:" echo " 脚本:${SCRIPT_NAME} ${SCRIPT_VERSION}(${SCRIPT_UPDATED})" echo " 项目:${SCRIPT_PROJECT}" echo " 镜像:${IMAGE_NAME}" echo " 容器:${CONTAINER_NAME}" echo " 端口:${HOST_ADDR}:${HOST_PORT}:${CONTAINER_PORT}" echo " 公网入口:https://docs.yohan.fun" echo " 回源地址:http://127.0.0.1:${HOST_PORT}" echo "" } pull_image() { log_info "拉取镜像:${IMAGE_NAME}" docker pull "${IMAGE_NAME}" } remove_container_if_exists() { if docker ps -a --format '{{.Names}}' | grep -qx "${CONTAINER_NAME}"; then log_info "停止旧容器:${CONTAINER_NAME}" docker stop "${CONTAINER_NAME}" >/dev/null 2>&1 || true log_info "删除旧容器:${CONTAINER_NAME}" docker rm "${CONTAINER_NAME}" >/dev/null 2>&1 || true fi } start_container() { log_info "启动容器:${CONTAINER_NAME}" docker run -d \ --name "${CONTAINER_NAME}" \ --restart unless-stopped \ -p "${HOST_ADDR}:${HOST_PORT}:${CONTAINER_PORT}" \ --health-cmd="wget -q --spider http://127.0.0.1:${CONTAINER_PORT}/healthz || exit 1" \ --health-interval=30s \ --health-timeout=5s \ --health-retries=3 \ --health-start-period=10s \ "${IMAGE_NAME}" } health_check() { log_info "等待文档站启动..." local retries=20 local count=0 while [ "${count}" -lt "${retries}" ]; do if curl -fsS "http://127.0.0.1:${HOST_PORT}/healthz" >/dev/null 2>&1 \ && curl -fsS "http://127.0.0.1:${HOST_PORT}/" >/dev/null 2>&1 \ && curl -fsS "http://127.0.0.1:${HOST_PORT}/scripts/tailscale-headscale-linux.sh" >/dev/null 2>&1; then log_success "健康检查通过。" return 0 fi count=$((count + 1)) log_info "健康检查中... ${count}/${retries}" sleep 3 done log_error "健康检查失败,请执行菜单中的日志查看。" return 1 } deploy_or_update() { check_docker print_config pull_image || return 1 remove_container_if_exists start_container || return 1 health_check || return 1 show_summary } show_summary() { echo "" echo "==========================================" log_success "AgentMeshOS 文档站部署完成" echo "==========================================" log_highlight "公网地址:https://docs.yohan.fun" log_highlight "本机回源:http://127.0.0.1:${HOST_PORT}" log_highlight "客户端脚本:https://docs.yohan.fun/scripts/tailscale-headscale-linux.sh" echo "" echo "请确认宝塔 Nginx 已将 docs.yohan.fun 反代到:" echo " http://127.0.0.1:${HOST_PORT}" echo "==========================================" echo "" } show_status() { check_docker print_config docker ps -a --filter "name=${CONTAINER_NAME}" --format "table {{.Names}}\t{{.Image}}\t{{.Status}}\t{{.Ports}}" } show_logs() { check_docker docker logs --tail=200 -f "${CONTAINER_NAME}" } restart_container() { check_docker docker restart "${CONTAINER_NAME}" health_check } stop_container() { check_docker docker stop "${CONTAINER_NAME}" log_success "容器已停止。" } backup_container_info() { check_docker mkdir -p "${BACKUP_DIR}" local backup_file="${BACKUP_DIR}/agentmeshos-docs-container-$(date +%Y%m%d_%H%M%S).txt" { echo "IMAGE_NAME=${IMAGE_NAME}" echo "CONTAINER_NAME=${CONTAINER_NAME}" echo "HOST_ADDR=${HOST_ADDR}" echo "HOST_PORT=${HOST_PORT}" echo "CONTAINER_PORT=${CONTAINER_PORT}" echo "" docker inspect "${CONTAINER_NAME}" 2>/dev/null || true } > "${backup_file}" log_success "容器信息已备份:${backup_file}" } remove_container() { prompt_tty "确认删除文档站容器?请输入 YES:" answer if [ "${answer}" != "YES" ]; then log_info "已取消。" return 0 fi check_docker remove_container_if_exists log_success "容器已删除,镜像未删除。" } remove_image() { prompt_tty "确认删除本地镜像 ${IMAGE_NAME}?请输入 YES:" answer if [ "${answer}" != "YES" ]; then log_info "已取消。" return 0 fi check_docker docker rmi "${IMAGE_NAME}" || true } show_commands() { cat <