Files
2026-09-07 18:24:55 +08:00

121 lines
3.9 KiB
Bash

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