#!/usr/bin/env bash set -Eeuo pipefail SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)" IMAGE="${NGINX_IMAGE:-nginx-oneclick:1.28}" NGINX_VERSION="${NGINX_VERSION:-1.28}" CONTAINER_NAME="${NGINX_CONTAINER_NAME:-nginx-1.28}" HOST_PORT="${NGINX_HOST_PORT:-80}" CONTAINER_PORT=80 FORCE_RECREATE="${FORCE_RECREATE:-0}" ARCHIVE="${NGINX_IMAGE_ARCHIVE:-${SCRIPT_DIR}/nginx-oneclick-1.28.tar.gz}" die() { echo "错误:$*" >&2 exit 1 } command -v docker >/dev/null 2>&1 || die "未找到 Docker,请先安装 Docker。" [[ "${HOST_PORT}" =~ ^[0-9]+$ ]] || die "NGINX_HOST_PORT 必须是数字。" (( HOST_PORT >= 1 && HOST_PORT <= 65535 )) || die "NGINX_HOST_PORT 必须在 1-65535 范围内。" echo "部署参数:" echo " 镜像:${IMAGE}" echo " 容器:${CONTAINER_NAME}" echo " 端口:${HOST_PORT}:${CONTAINER_PORT}" if ! docker image inspect "${IMAGE}" >/dev/null 2>&1 && [[ -f "${ARCHIVE}" ]]; then echo "[1/4] 从镜像包加载 ${ARCHIVE}" case "${ARCHIVE}" in *.tar.gz|*.tgz) gzip -cd -- "${ARCHIVE}" | docker load ;; *) docker load --input "${ARCHIVE}" ;; esac fi if ! docker image inspect "${IMAGE}" >/dev/null 2>&1; then echo "[1/4] 未找到本地镜像,自动构建 ${IMAGE}" docker build \ --pull \ --build-arg "NGINX_VERSION=${NGINX_VERSION}" \ --tag "${IMAGE}" \ "${SCRIPT_DIR}" else echo "[1/4] 已找到镜像 ${IMAGE}" fi existing_container=0 if docker container inspect "${CONTAINER_NAME}" >/dev/null 2>&1; then existing_container=1 current_image="$(docker inspect -f '{{.Config.Image}}' "${CONTAINER_NAME}")" current_host_port="$(docker inspect -f '{{with (index .HostConfig.PortBindings "80/tcp")}}{{(index . 0).HostPort}}{{end}}' "${CONTAINER_NAME}" 2>/dev/null || true)" if [[ "${current_image}" != "${IMAGE}" || "${current_host_port}" != "${HOST_PORT}" ]]; then if [[ "${FORCE_RECREATE}" != "1" ]]; then die "已存在同名容器但镜像或端口不匹配。确认后可设置 FORCE_RECREATE=1 再执行。" fi echo "[2/4] FORCE_RECREATE=1,重建已有容器 ${CONTAINER_NAME}" docker rm -f "${CONTAINER_NAME}" >/dev/null existing_container=0 fi fi if (( existing_container == 0 )); then echo "[2/4] 创建容器 ${CONTAINER_NAME}" docker run -d \ --name "${CONTAINER_NAME}" \ --restart unless-stopped \ --publish "${HOST_PORT}:${CONTAINER_PORT}" \ --log-opt max-size=10m \ --log-opt max-file=3 \ "${IMAGE}" >/dev/null else running="$(docker inspect -f '{{.State.Running}}' "${CONTAINER_NAME}")" if [[ "${running}" != "true" ]]; then echo "[2/4] 启动已存在的容器 ${CONTAINER_NAME}" docker start "${CONTAINER_NAME}" >/dev/null else echo "[2/4] 容器 ${CONTAINER_NAME} 已在运行" fi fi echo "[3/4] 等待容器就绪" for _ in {1..30}; do running="$(docker inspect -f '{{.State.Running}}' "${CONTAINER_NAME}" 2>/dev/null || true)" [[ "${running}" == "true" ]] && break sleep 1 done [[ "${running}" == "true" ]] || die "容器未能进入运行状态。" echo "[4/4] 验证 HTTP 服务" url="http://127.0.0.1:${HOST_PORT}/" http_ok=0 if command -v curl >/dev/null 2>&1; then for _ in {1..30}; do if curl --fail --silent --max-time 2 "${url}" >/dev/null; then http_ok=1 break fi sleep 1 done elif command -v wget >/dev/null 2>&1; then for _ in {1..30}; do if wget -q -O /dev/null --timeout=2 "${url}"; then http_ok=1 break fi sleep 1 done else echo "警告:系统没有 curl 或 wget,跳过 HTTP 验证。" >&2 http_ok=1 fi (( http_ok == 1 )) || die "HTTP 验证失败:${url}" nginx_version="$(docker exec "${CONTAINER_NAME}" nginx -v 2>&1 || true)" echo echo "部署成功。" echo " 容器:${CONTAINER_NAME}" echo " 端口:0.0.0.0:${HOST_PORT} -> ${CONTAINER_PORT}" echo " 版本:${nginx_version}" echo " 查看状态:docker ps --filter name=${CONTAINER_NAME}"