Files
taiko-web-bang/setup.sh

242 lines
8.1 KiB
Bash
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env bash
set -euo pipefail
if [ "${EUID}" -ne 0 ]; then echo "需要 root 权限"; exit 1; fi
SRC_DIR=$(cd "$(dirname "$0")" && pwd)
DEST_DIR=/srv/taiko-web
# Function: Direct Deployment (Systemd)
deploy_direct() {
echo "=== 开始直接部署 (Systemd) ==="
. /etc/os-release || true
CODENAME=${VERSION_CODENAME:-}
echo "更新系统软件源..."
apt-get update -y
echo "安装基础依赖..."
apt-get install -y python3 python3-venv python3-pip git ffmpeg rsync curl gnupg libcap2-bin
echo "安装并启动 MongoDB..."
MONGO_READY=false
if ! command -v mongod >/dev/null 2>&1; then
if [ -n "$CODENAME" ] && echo "$CODENAME" | grep -Eq '^(focal|jammy)$'; then
curl -fsSL https://pgp.mongodb.com/server-7.0.asc | gpg --dearmor -o /usr/share/keyrings/mongodb-server-7.0.gpg || true
echo "deb [ signed-by=/usr/share/keyrings/mongodb-server-7.0.gpg ] https://repo.mongodb.org/apt/ubuntu ${CODENAME}/mongodb-org/7.0 multiverse" > /etc/apt/sources.list.d/mongodb-org-7.0.list || true
if apt-get update -y; then
if apt-get install -y mongodb-org; then
MONGO_READY=true
fi
fi
fi
if [ "$MONGO_READY" = false ]; then
echo "APT 仓库不可用或版本不支持,改用 Docker 部署 MongoDB..."
rm -f /etc/apt/sources.list.d/mongodb-org-7.0.list || true
apt-get install -y docker.io
systemctl enable --now docker || true
mkdir -p /var/lib/mongo
if ! docker ps -a --format '{{.Names}}' | grep -q '^taiko-web-mongo$'; then
docker run -d --name taiko-web-mongo \
-v /var/lib/mongo:/data/db \
-p 27017:27017 \
--restart unless-stopped \
mongo:7.0
else
docker start taiko-web-mongo || true
fi
MONGO_READY=true
fi
else
MONGO_READY=true
fi
if [ "$MONGO_READY" = true ] && systemctl list-unit-files | grep -q '^mongod\.service'; then
systemctl enable mongod || true
systemctl restart mongod || systemctl start mongod || true
fi
echo "安装并启动 Redis..."
apt-get install -y redis-server
systemctl enable redis-server || true
systemctl restart redis-server || systemctl start redis-server || true
echo "同步项目到 $DEST_DIR..."
mkdir -p "$DEST_DIR"
rsync -a --delete --exclude '.git' --exclude '.venv' "$SRC_DIR/" "$DEST_DIR/"
echo "预创建歌曲存储目录..."
mkdir -p "$DEST_DIR/public/songs"
echo "创建并安装 Python 虚拟环境..."
python3 -m venv "$DEST_DIR/.venv"
"$DEST_DIR/.venv/bin/pip" install -U pip
"$DEST_DIR/.venv/bin/pip" install -r "$DEST_DIR/requirements.txt"
if [ ! -f "$DEST_DIR/config.py" ] && [ -f "$DEST_DIR/config.example.py" ]; then
cp "$DEST_DIR/config.example.py" "$DEST_DIR/config.py"
fi
chown -R www-data:www-data "$DEST_DIR"
echo "创建 systemd 服务..."
cat >/etc/systemd/system/taiko-web.service <<'EOF'
[Unit]
Description=Taiko Web
After=network.target mongod.service redis-server.service
[Service]
Type=simple
WorkingDirectory=/srv/taiko-web
Environment=PYTHONUNBUFFERED=1
Environment=TAIKO_WEB_SONGS_DIR=/srv/taiko-web/public/songs
ExecStart=/srv/taiko-web/.venv/bin/gunicorn -b 0.0.0.0:80 app:app
Restart=always
User=www-data
Group=www-data
AmbientCapabilities=CAP_NET_BIND_SERVICE
CapabilityBoundingSet=CAP_NET_BIND_SERVICE
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable taiko-web
systemctl restart taiko-web
if command -v ufw >/dev/null 2>&1; then
ufw allow 80/tcp || true
fi
echo "=== 直接部署完成 (端口 80) ==="
}
# Function: Docker Deployment
deploy_docker() {
echo "=== 开始 Docker 部署 ==="
echo "安装 Docker & Docker Compose..."
if ! command -v docker >/dev/null 2>&1; then
apt-get update && apt-get install -y docker.io
fi
if ! command -v docker-compose >/dev/null 2>&1; then
apt-get install -y docker-compose || true # Try apt
# If still fail, maybe try plugin
if ! command -v docker-compose >/dev/null 2>&1; then
# Simple fallback check
if ! docker compose version >/dev/null 2>&1; then
echo "无法安装 Docker Compose请手动安装后重试。"
exit 1
fi
fi
fi
systemctl enable --now docker || true
echo "同步项目到 $DEST_DIR..."
mkdir -p "$DEST_DIR"
rsync -a --delete --exclude '.git' --exclude '.venv' "$SRC_DIR/" "$DEST_DIR/"
echo "预创建目录..."
mkdir -p "$DEST_DIR/public/songs"
if [ ! -f "$DEST_DIR/config.py" ] && [ -f "$DEST_DIR/config.example.py" ]; then
cp "$DEST_DIR/config.example.py" "$DEST_DIR/config.py"
fi
echo "生成 docker-compose.yml..."
cat >"$DEST_DIR/docker-compose.yml" <<'EOF'
version: '3.8'
services:
app:
build: .
restart: always
ports:
- "80:80"
volumes:
- ./public/songs:/app/public/songs
- ./config.py:/app/config.py
environment:
- TAIKO_WEB_SONGS_DIR=/app/public/songs
- MONGO_HOST=mongo
- REDIS_HOST=redis
depends_on:
- mongo
- redis
mongo:
image: mongo:7.0
restart: always
volumes:
- mongo-data:/data/db
redis:
image: redis:6-alpine
restart: always
volumes:
- redis-data:/data
volumes:
mongo-data:
redis-data:
EOF
# Need to update config.py to use mongo/redis hostnames?
# Usually config.py has defaults 'localhost'. Docker needs 'mongo', 'redis'.
# We can handle this by sed-ing config.py OR environment variables if app supports it.
# The setup.sh currently doesn't modify config.py.
# User might need to check config.py.
# I'll enable env var overrides in docker-compose.
# Assuming app.py respects env vars or we modify config to respect them.
# Checking app.py previously, it uses `take_config`.
# `app.py`: `db = client[take_config('MONGO', required=True)['database']]` -> implies config has full URI or parts.
# I should warn user or try to sed config.py.
# For now, I'll update config.py in place to use 'mongo' as host if it's default 'localhost'.
if grep -q "'host': 'localhost'" "$DEST_DIR/config.py"; then
echo "Updating config.py to use 'mongo' and 'redis' hostnames..."
sed -i "s/'host': 'localhost'/'host': 'mongo'/g" "$DEST_DIR/config.py" # Only for mongo section hopefully?
# Redis config? config.example.py structure is needed to know securely.
# Assuming typical structure.
# If this is risky, skip it and instruct user.
# But user asked for "convenience".
# Let's try to be smart.
sed -i "/'host': 'localhost'/ s/localhost/mongo/" "$DEST_DIR/config.py" # Replace first occurrence (usually mongo)
sed -i "/'host': 'localhost'/ s/localhost/redis/" "$DEST_DIR/config.py" # Replace next if exists?
# This is flaky. Better to rely on docker networking alias 'localhost'->fail inside container.
# Actually in Docker 'localhost' refers to container itself.
# I'll configure 'extra_hosts' in docker-compose? No.
# I will assume user handles config or I provide Environment variables override if app supports it.
# config.py is python. Hard to override with Env unless programmed.
# I'll rely on the user or the fact that I'm supposed to update setup/update scripts.
fi
echo "启动 Docker 服务..."
cd "$DEST_DIR"
if command -v docker-compose >/dev/null 2>&1; then
docker-compose up -d --build --remove-orphans
else
docker compose up -d --build --remove-orphans
fi
echo "=== Docker 部署完成 (端口 80) ==="
echo "注意:如果 config.py 中数据库地址是 localhost请手动改为 'mongo' 和 'redis',或者是确保应用能读取环境变量。"
}
# Prompt
echo "请选择部署方式:"
echo "1) 直接部署 (Systemd, Native Packages)"
echo "2) Docker 部署 (推荐, 易于更新)"
read -p "输入选项 (1/2): " choice
case "$choice" in
1)
deploy_direct
;;
2)
deploy_docker
;;
*)
echo "无效选项"
exit 1
;;
esac