refactor: 彻底移除 docker compose,改用纯 docker 构建+重启部署
This commit is contained in:
parent
e11814048c
commit
a5c5d24083
@ -3,27 +3,36 @@ name: Build and Deploy
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
pull_request:
|
||||
branches: [main]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Build Docker image
|
||||
run: |
|
||||
docker build -t awesome-index:latest .
|
||||
|
||||
deploy:
|
||||
needs: build
|
||||
if: github.ref == 'refs/heads/main'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Copy files to server
|
||||
- name: Copy scripts to server
|
||||
uses: appleboy/scp-action@master
|
||||
with:
|
||||
host: 114.134.187.170
|
||||
username: root
|
||||
password: ${{ secrets.SERVER_PASSWORD }}
|
||||
source: "package.json,package-lock.json,src,public,.env.example,start.sh"
|
||||
source: "start.sh,.env.example"
|
||||
target: "/app/awesome/"
|
||||
|
||||
- name: Deploy and start service
|
||||
- name: Restart container
|
||||
uses: appleboy/ssh-action@master
|
||||
with:
|
||||
host: 114.134.187.170
|
||||
@ -31,10 +40,5 @@ jobs:
|
||||
password: ${{ secrets.SERVER_PASSWORD }}
|
||||
script: |
|
||||
cd /app/awesome
|
||||
|
||||
# 如不存在 .env 则从 example 复制
|
||||
[ ! -f .env ] && cp .env.example .env
|
||||
|
||||
# 执行启动脚本
|
||||
chmod +x start.sh
|
||||
bash start.sh
|
||||
|
||||
30
Jenkinsfile
vendored
30
Jenkinsfile
vendored
@ -3,7 +3,6 @@ pipeline {
|
||||
|
||||
environment {
|
||||
IMAGE_NAME = 'awesome-index'
|
||||
CONTAINER_NAME = 'awesome'
|
||||
DEPLOY_PATH = '/app/awesome'
|
||||
SSH_HOST = '114.134.187.170'
|
||||
SSH_USER = 'root'
|
||||
@ -13,9 +12,8 @@ pipeline {
|
||||
stage('Build') {
|
||||
steps {
|
||||
script {
|
||||
echo "Building Docker image ${IMAGE_NAME}:${BUILD_NUMBER}"
|
||||
sh "docker build -t ${IMAGE_NAME}:${BUILD_NUMBER} ."
|
||||
sh "docker tag ${IMAGE_NAME}:${BUILD_NUMBER} ${IMAGE_NAME}:latest"
|
||||
echo "Building Docker image ${IMAGE_NAME}:latest"
|
||||
sh "docker build -t ${IMAGE_NAME}:latest ."
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -29,28 +27,12 @@ pipeline {
|
||||
// 创建部署目录
|
||||
sh "sshpass -p '${SSH_PASS}' ssh -o StrictHostKeyChecking=no ${remote} 'mkdir -p ${DEPLOY_PATH}/data ${DEPLOY_PATH}/logs'"
|
||||
|
||||
// 复制必要文件
|
||||
sh "sshpass -p '${SSH_PASS}' scp -o StrictHostKeyChecking=no docker-compose.yml ${remote}:${DEPLOY_PATH}/"
|
||||
sh "sshpass -p '${SSH_PASS}' scp -o StrictHostKeyChecking=no .env.example ${remote}:${DEPLOY_PATH}/.env"
|
||||
// 上传脚本(构建机 = 部署机,镜像已在服务器上,无需传输镜像)
|
||||
sh "sshpass -p '${SSH_PASS}' scp -o StrictHostKeyChecking=no .env.example ${remote}:${DEPLOY_PATH}/.env.example"
|
||||
sh "sshpass -p '${SSH_PASS}' scp -o StrictHostKeyChecking=no start.sh ${remote}:${DEPLOY_PATH}/"
|
||||
|
||||
// 导入镜像
|
||||
sh "docker save ${IMAGE_NAME}:latest | gzip > ${IMAGE_NAME}.tar.gz"
|
||||
sh "sshpass -p '${SSH_PASS}' scp -o StrictHostKeyChecking=no ${IMAGE_NAME}.tar.gz ${remote}:${DEPLOY_PATH}/"
|
||||
|
||||
// 在服务器上加载并重启
|
||||
sh """
|
||||
sshpass -p '${SSH_PASS}' ssh -o StrictHostKeyChecking=no ${remote} '
|
||||
cd ${DEPLOY_PATH} &&
|
||||
gunzip -c ${IMAGE_NAME}.tar.gz | docker load &&
|
||||
rm -f ${IMAGE_NAME}.tar.gz &&
|
||||
docker compose down --remove-orphans &&
|
||||
docker compose up -d
|
||||
'
|
||||
"""
|
||||
|
||||
// 清理本地
|
||||
sh "rm -f ${IMAGE_NAME}.tar.gz"
|
||||
// 在服务器上重启容器
|
||||
sh "sshpass -p '${SSH_PASS}' ssh -o StrictHostKeyChecking=no ${remote} 'cd ${DEPLOY_PATH} && chmod +x start.sh && bash start.sh'"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -21,11 +21,11 @@ npm test # node:test,10 个用例
|
||||
### Docker 部署
|
||||
|
||||
```bash
|
||||
cp .env.example .env # 修改 SESSION_SECRET / ADMIN_INIT_PASSWORD / AI_INGEST_KEY
|
||||
docker compose up -d --build
|
||||
docker build -t awesome-index:latest .
|
||||
bash start.sh # 用新镜像重启容器
|
||||
```
|
||||
|
||||
数据持久化在宿主机 `./data/awesome.duckdb`,升级镜像不丢数据。
|
||||
`start.sh` 会检查 `.env`(不存在则从 `.env.example` 复制),然后 `docker run` 启动容器。数据持久化在宿主机 `./data/awesome.duckdb`,重启不丢数据。
|
||||
|
||||
## 给人的入口
|
||||
|
||||
|
||||
19
deploy.sh
19
deploy.sh
@ -1,5 +1,5 @@
|
||||
#!/bin/bash
|
||||
# Awesome Index 部署脚本(直接部署,不使用 Docker)
|
||||
# Awesome Index 部署脚本(构建机 = 部署机:本地构建镜像,SSH 重启容器)
|
||||
# 服务器: 114.134.187.170
|
||||
|
||||
set -e
|
||||
@ -19,20 +19,15 @@ if ! command -v sshpass &> /dev/null; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "1. 创建部署目录..."
|
||||
sshpass -p "$REMOTE_PASS" ssh -o StrictHostKeyChecking=no "$REMOTE_USER@$REMOTE_HOST" \
|
||||
"mkdir -p $DEPLOY_PATH/data $DEPLOY_PATH/logs"
|
||||
echo "1. 构建 Docker 镜像..."
|
||||
docker build -t awesome-index:latest .
|
||||
|
||||
echo "2. 上传源码..."
|
||||
sshpass -p "$REMOTE_PASS" scp -o StrictHostKeyChecking=no -r \
|
||||
package.json package-lock.json src public .env.example start.sh \
|
||||
echo "2. 上传脚本到服务器..."
|
||||
sshpass -p "$REMOTE_PASS" scp -o StrictHostKeyChecking=no \
|
||||
start.sh .env.example \
|
||||
"$REMOTE_USER@$REMOTE_HOST:$DEPLOY_PATH/"
|
||||
|
||||
echo "3. 重命名 .env.example 为 .env(如不存在)..."
|
||||
sshpass -p "$REMOTE_PASS" ssh -o StrictHostKeyChecking=no "$REMOTE_USER@$REMOTE_HOST" \
|
||||
"cd $DEPLOY_PATH && [ ! -f .env ] && cp .env.example .env"
|
||||
|
||||
echo "4. 在服务器上执行启动脚本..."
|
||||
echo "3. 在服务器上重启容器..."
|
||||
sshpass -p "$REMOTE_PASS" ssh -o StrictHostKeyChecking=no "$REMOTE_USER@$REMOTE_HOST" \
|
||||
"cd $DEPLOY_PATH && chmod +x start.sh && bash start.sh"
|
||||
|
||||
|
||||
@ -1,16 +0,0 @@
|
||||
services:
|
||||
web:
|
||||
build: .
|
||||
container_name: awesome-index
|
||||
ports:
|
||||
- "3000:3000"
|
||||
volumes:
|
||||
- ./data:/app/data
|
||||
environment:
|
||||
PORT: "3000"
|
||||
DUCKDB_PATH: /app/data/awesome.duckdb
|
||||
SESSION_SECRET: ${SESSION_SECRET:-change-me-in-production}
|
||||
ADMIN_INIT_PASSWORD: ${ADMIN_INIT_PASSWORD:-admin}
|
||||
AI_INGEST_KEY: ${AI_INGEST_KEY:-}
|
||||
BASE_URL: ${BASE_URL:-http://localhost:3000}
|
||||
restart: unless-stopped
|
||||
@ -58,8 +58,8 @@
|
||||
```
|
||||
awesome/
|
||||
├── package.json # 依赖与 scripts(dev / start / test / migrate)
|
||||
├── Dockerfile # 多阶段构建(node:22-alpine)
|
||||
├── docker-compose.yml # 单服务编排 + data 卷 + healthcheck
|
||||
├── Dockerfile # 多阶段构建(node:22-bookworm-slim)
|
||||
├── start.sh # 用已构建镜像重启容器(docker run,无 compose)
|
||||
├── .env.example # 配置样例
|
||||
├── .gitignore # node_modules / data / .env
|
||||
│
|
||||
|
||||
37
start.sh
37
start.sh
@ -1,32 +1,38 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
# Awesome Index 启动脚本(直接部署,不使用 Docker)
|
||||
# Awesome Index 重启脚本(使用已构建的镜像,纯 docker run,无 compose)
|
||||
DEPLOY_PATH="$(cd "$(dirname "$0")" && pwd)"
|
||||
cd "$DEPLOY_PATH"
|
||||
|
||||
# 检查 .env 文件
|
||||
if [ ! -f .env ]; then
|
||||
echo "错误: 缺少 .env 文件,请从 .env.example 复制并修改"
|
||||
exit 1
|
||||
if [ -f .env.example ]; then
|
||||
cp .env.example .env
|
||||
echo "已从 .env.example 创建 .env(请检查 SESSION_SECRET / ADMIN_INIT_PASSWORD / AI_INGEST_KEY)"
|
||||
else
|
||||
echo "错误: 缺少 .env 文件"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# 安装依赖
|
||||
echo "安装依赖..."
|
||||
npm ci --omit=dev --no-audit --no-fund
|
||||
# 停止并删除旧容器
|
||||
echo "停止旧容器..."
|
||||
docker rm -f awesome-index 2>/dev/null || true
|
||||
|
||||
# 停止旧进程
|
||||
echo "停止旧进程..."
|
||||
pkill -f "node src/index.js" 2>/dev/null || true
|
||||
sleep 1
|
||||
|
||||
# 启动服务
|
||||
# 用新镜像启动容器
|
||||
echo "启动 Awesome Index..."
|
||||
nohup node src/index.js > logs/app.log 2>&1 &
|
||||
docker run -d \
|
||||
--name awesome-index \
|
||||
--restart unless-stopped \
|
||||
-p 3000:3000 \
|
||||
-v "$DEPLOY_PATH/data:/app/data" \
|
||||
--env-file .env \
|
||||
awesome-index:latest
|
||||
|
||||
# 健康检查
|
||||
echo "等待服务就绪..."
|
||||
sleep 2
|
||||
sleep 5
|
||||
|
||||
MAX_RETRIES=10
|
||||
RETRY_COUNT=0
|
||||
@ -35,12 +41,11 @@ while [ $RETRY_COUNT -lt $MAX_RETRIES ]; do
|
||||
echo "✓ 服务已启动: http://localhost:3000"
|
||||
echo ""
|
||||
echo "管理后台: http://localhost:3000/admin"
|
||||
echo "默认账号: admin / (见 .env 中的 ADMIN_INIT_PASSWORD)"
|
||||
exit 0
|
||||
fi
|
||||
RETRY_COUNT=$((RETRY_COUNT + 1))
|
||||
sleep 2
|
||||
done
|
||||
|
||||
echo "✗ 服务启动失败,请检查日志: tail -50 logs/app.log"
|
||||
echo "✗ 服务启动失败,请检查日志: docker logs awesome-index"
|
||||
exit 1
|
||||
|
||||
Loading…
Reference in New Issue
Block a user