chore: 增加 Docker 单容器部署

生产用 Dockerfile + compose 嵌入前端二进制,run.sh docker 一键构建启动。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Logan.LiandCursor committed 2026-08-12 12:02:29 +08:00
1 parent 95405de119
commit cb1a9be2c4
7 files changed
+224 -4

No files matched your search

+26
View File
@@ -0,0 +1,26 @@
.git
.zcode
.claude
.env
.env.*
!.env.example
*.md
logs
*.pid
*.log
*.db
*.sqlite
*.sqlite3
opsx-licence
backend/backend
backend/server
backend/static/*
!backend/static/.gitkeep
frontend/node_modules
frontend/dist
frontend/logs
**/*_test.go
**/coverage.out
.DS_Store
.idea
.vscode
+11 -2
View File
@@ -1,5 +1,6 @@
# opsx-licence - 环境变量配置模板
# 复制此文件为 .env 并根据需要修改
# Docker: cp .env.example .env && ./run.sh docker up
# ============================================
# 后端配置 (backend)
@@ -8,8 +9,8 @@
# 服务器端口
PORT=9001
# 运行模式: debug / release
GIN_MODE=debug
# 运行模式: debug / release(生产 / Docker 请用 release)
GIN_MODE=release
# JWT 密钥(生产环境必须修改!)
JWT_SECRET=your-super-secret-key-change-this-in-production
@@ -17,6 +18,7 @@ JWT_SECRET=your-super-secret-key-change-this-in-production
# 数据库配置
# 可选: sqlite / mysql / postgres
DB_DRIVER=sqlite
# 本地开发可用相对路径;Docker Compose 会覆盖为 /data/db.sqlite3
DB_NAME=db.sqlite3
# MySQL 配置(使用 mysql 时填写)
@@ -55,6 +57,13 @@ SUCCESS_URL=opsxshell://pro/activated
# PEM 私钥仅保存在服务端,切勿下发到客户端或写入仓库
# WAFFO_PRIVATE_KEY_PEM=
# ============================================
# Docker Compose
# ============================================
# 宿主机映射端口(容器内固定 9001)
HOST_PORT=9001
VERSION=latest
# ============================================
# 前端配置 (frontend)
# ============================================
+66
View File
@@ -0,0 +1,66 @@
# opsx-licence — 前端嵌入 Go 单二进制,Docker 部署
# Stage 1: Node 构建 Vue
# Stage 2: Go(+CGO) 嵌入 static 并编译
# Stage 3: 精简运行时
# 署名 Logan.Li
# ==================== Stage 1: Frontend ====================
FROM node:20-bookworm-slim AS frontend-builder
WORKDIR /frontend
ENV NODE_OPTIONS="--max-old-space-size=2048"
RUN npm config set registry https://registry.npmmirror.com
COPY frontend/package.json frontend/package-lock.json ./
RUN npm ci
COPY frontend/ ./
RUN npm run build
# ==================== Stage 2: Backend ====================
FROM golang:1.24-bookworm AS backend-builder
WORKDIR /src
ENV GOPROXY=https://goproxy.cn,direct
ENV CGO_ENABLED=1
RUN apt-get update && apt-get install -y --no-install-recommends \
gcc libc6-dev \
&& rm -rf /var/lib/apt/lists/*
COPY backend/go.mod backend/go.sum ./
RUN go mod download
COPY backend/ ./
RUN rm -rf static && mkdir -p static
COPY --from=frontend-builder /frontend/dist/. ./static/
RUN go build -trimpath -ldflags="-s -w" -o /out/opsx-licence .
# ==================== Stage 3: Runtime ====================
FROM debian:bookworm-slim
RUN apt-get update && apt-get install -y --no-install-recommends \
ca-certificates tzdata curl \
&& rm -rf /var/lib/apt/lists/* \
&& useradd --system --uid 10001 --home-dir /app --shell /usr/sbin/nologin opsx
ENV TZ=Asia/Shanghai \
PORT=9001 \
GIN_MODE=release \
DB_DRIVER=sqlite \
DB_NAME=/data/db.sqlite3
WORKDIR /app
COPY --from=backend-builder /out/opsx-licence /app/opsx-licence
RUN mkdir -p /data && chown -R opsx:opsx /app /data
USER opsx
VOLUME ["/data"]
EXPOSE 9001
HEALTHCHECK --interval=15s --timeout=3s --start-period=10s --retries=5 \
CMD curl -fsS "http://127.0.0.1:${PORT}/health" || exit 1
ENTRYPOINT ["/app/opsx-licence"]
+10 -1
View File
@@ -1,7 +1,7 @@
# opsx-licence - Makefile
# 提供常用开发命令的快捷方式
.PHONY: help install dev build build-ui build-api build-binary clean status stop restart lint test
.PHONY: help install dev build build-ui build-api build-binary docker-up docker-down clean status stop restart lint test
# 默认显示帮助
help:
@@ -13,6 +13,8 @@ help:
@echo " make build-ui - 仅构建前端"
@echo " make build-api - 仅构建后端"
@echo " make build-binary - 构建前端嵌入式单二进制 opsx-licence"
@echo " make docker-up - Docker 构建并启动"
@echo " make docker-down - 停止 Docker 容器"
@echo " make test - 运行后端测试"
@echo " make lint - 运行代码检查"
@echo " make clean - 清理构建产物和日志"
@@ -50,6 +52,13 @@ build: build-ui build-api
build-binary:
./run.sh build
# Docker 部署 // Logan.Li
docker-up:
./run.sh docker up
docker-down:
./run.sh docker down
# 后端测试
test:
@echo "🧪 运行后端测试..."
+13
View File
@@ -43,6 +43,19 @@ cp .env.example .env
- 后端:http://localhost:9001
- 默认账号:`admin` / `admin`
### Docker 部署(生产推荐)
```bash
cp .env.example .env
# 修改 JWT_SECRET、Waffo 等
./run.sh docker up # 等价于 docker compose up -d --build
./run.sh docker logs
./run.sh docker down
```
- 访问:http://localhost:9001(管理后台 + `/api`)
- 数据卷:`licence_data` → 容器内 `/data/db.sqlite3`
### 构建单二进制
```bash
+36
View File
@@ -0,0 +1,36 @@
# opsx-licence Docker 部署(单容器:管理后台 + /api)
# 用法:
# cp .env.example .env # 填 JWT / Waffo
# docker compose up -d --build
# # 或旧版: docker-compose up -d --build
# 署名 Logan.Li
services:
opsx-licence:
image: opsx-licence:${VERSION:-latest}
build:
context: .
dockerfile: Dockerfile
container_name: opsx-licence
restart: unless-stopped
ports:
- "${HOST_PORT:-9001}:9001"
env_file:
- .env
environment:
TZ: Asia/Shanghai
PORT: "9001"
GIN_MODE: ${GIN_MODE:-release}
DB_DRIVER: sqlite
DB_NAME: /data/db.sqlite3
volumes:
- licence_data:/data
healthcheck:
test: ["CMD", "curl", "-fsS", "http://127.0.0.1:9001/health"]
interval: 15s
timeout: 3s
retries: 5
start_period: 15s
volumes:
licence_data:
+62 -1
View File
@@ -1,7 +1,7 @@
#!/bin/bash
# opsx-licence 启动脚本
# 一键启动前后端服务,支持日志轮转与单二进制部署
# 用法: ./run.sh [start|stop|restart|status|frontend|backend|build|binary|help]
# 用法: ./run.sh [start|stop|restart|status|frontend|backend|build|binary|docker|help]
set -e
@@ -282,6 +282,62 @@ binary_command() {
esac
}
# ============================================================
# Docker 部署(生产推荐)
# ============================================================
compose_cmd() {
if docker compose version >/dev/null 2>&1; then
echo "docker compose"
elif command -v docker-compose >/dev/null 2>&1; then
echo "docker-compose"
else
error "未找到 docker compose / docker-compose"
return 1
fi
}
docker_command() {
local sub=${1:-up}
local dc
dc=$(compose_cmd) || return 1
if [ ! -f "$SCRIPT_DIR/.env" ]; then
warning "缺少 .env,正在从 .env.example 复制"
cp "$SCRIPT_DIR/.env.example" "$SCRIPT_DIR/.env"
warning "请编辑 .env 修改 JWT_SECRET / Waffo 配置后再部署"
fi
case "$sub" in
up|start)
info "Docker 构建并启动..."
$dc -f "$SCRIPT_DIR/docker-compose.yml" up -d --build
success "容器已启动: http://localhost:${HOST_PORT:-9001}"
;;
down|stop)
info "停止 Docker 容器..."
$dc -f "$SCRIPT_DIR/docker-compose.yml" down
;;
restart)
$dc -f "$SCRIPT_DIR/docker-compose.yml" restart
;;
rebuild|upgrade)
info "重新构建并滚动升级..."
$dc -f "$SCRIPT_DIR/docker-compose.yml" up -d --build --force-recreate
;;
logs)
$dc -f "$SCRIPT_DIR/docker-compose.yml" logs -f --tail=200
;;
status|ps)
$dc -f "$SCRIPT_DIR/docker-compose.yml" ps
;;
*)
error "未知 docker 命令: $sub"
echo "用法: ./run.sh docker [up|down|restart|rebuild|logs|status]"
return 1
;;
esac
}
# ============================================================
# 命令
# ============================================================
@@ -320,6 +376,7 @@ show_help() {
echo " frontend 仅启动前端服务"
echo " build 构建嵌入前端的单二进制 $STANDALONE_BIN"
echo " binary 管理单二进制服务(start|stop|restart|status|upgrade)"
echo " docker Docker 部署(up|down|restart|rebuild|logs|status)"
echo " status 查看服务状态"
echo " help 显示帮助信息"
echo ""
@@ -330,6 +387,7 @@ show_help() {
echo " ./run.sh backend # 仅启动后端"
echo " ./run.sh build # 生成 ./opsx-licence"
echo " ./run.sh binary start # 启动单二进制服务"
echo " ./run.sh docker up # Docker 构建并启动(生产推荐)"
}
# ============================================================
@@ -389,6 +447,9 @@ main() {
binary)
binary_command "${2:-start}"
;;
docker)
docker_command "${2:-up}"
;;
status)
show_status
;;