121 lines
3.9 KiB
Bash
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}"
|