Spug v4.1.1 Docker Compose 部署指南
在 Ubuntu 22.04 服务器上以官方 Docker Compose 编排完整部署 Spug v4.1.1:编排文件逐项注解、首启自动初始化实录、随机管理员密码、登录验证、升级备份与四个排障实录。
Spug v4.1.1 Docker Compose 部署指南
目标:在一台 Linux 服务器上,用官方主推的 Docker Compose 形态完成 Spug v4.1.1 的从零部署:下载编排、启动、等待自动初始化、取回首启随机密码、登录验证,并覆盖升级、备份与常见故障。本文全部命令与输出均在 2026-10-25 于 Ubuntu 22.04 + Docker Engine 29.8.1 环境实测取得(组件背景与选型见 《Spug v4.1.1 介绍与选型指南》)。
一、环境信息
系统环境
| 项目 | 实测值 |
|---|---|
| 操作系统 | Ubuntu 22.04(宿主机,Linux 内核 6.x) |
| Docker Engine | 29.8.1(含 compose 插件) |
| 部署目录 | /opt/spug |
| 服务访问端口 | 8128(官方默认 80,本文按需改用 8128) |
| Spug 版本 | v4.1.1(openspug/spug:4.1.1,ghcr.io 同步发布) |
| 数据库 | MariaDB 10.11(编排内独立服务) |
| 实测日期 | 2026-10-25 |
镜像内组件实测(来自运行中服务的版本查询,2026-10-25)
| 组件 | 实测版本 | 说明 |
|---|---|---|
| 基础系统 | Debian GNU/Linux 12 (bookworm) | 官方镜像底座 |
| Python | 3.11.17 | 后端运行时 |
| Redis | 7.0.15 | 缓存/队列/消息通道(服务内自带,监听 127.0.0.1) |
| nginx | 1.22.1 | 前端静态资源与反向代理 |
| 应用服务 | gunicorn(127.0.0.1:9001,2 worker × 8 线程) | HTTP API |
| WebSocket 服务 | daphne(127.0.0.1:9002) | 在线终端/控制台实时输出 |
二、软件介绍
Spug(openspug/spug)是面向中小企业的轻量级无 Agent 自动化运维平台,把主机管理、批量执行、在线终端、应用发布、任务计划、配置中心、监控报警收敛到一个 Web 界面;目标主机只需 SSH 可达,无需安装任何被控端。当前最新稳定版为 v4.1.1(2026-10-12 安全修复版),官方主推的部署形态即本文的 Docker Compose:一个 spug 服务 + 一个 db 服务,首次启动自动完成数据库结构创建与管理员账号生成。产品定位、架构与竞品对比详见 《Spug v4.1.1 介绍与选型指南》。
三、部署实践
3.1 前置条件
- 一台 2 核 4GB 以上的 Linux 服务器(官方无硬性下限,实测镜像压缩层 148 MB、解压 658 MB,外加 MariaDB 10.11 压缩层约 104 MB)。
- 已安装 Docker Engine 20.10.10 及以上(v4 容器启动脚本会检查内核线程数上限,过旧的 Engine 版本无法通过检查),并带 compose 插件:
$ docker --version
Docker version 29.8.1, build 8a1e6b8
$ docker compose version
Docker Compose version v29.8.1
- 服务器放行访问端口(本文为 8128,官方默认 80),并具备外网或镜像代理以拉取
openspug/spug:4.1.1与mariadb:10.11。
3.2 编排文件与参数说明
官方编排文件位于仓库 4.0 分支(https://raw.githubusercontent.com/openspug/spug/4.0/docker-compose.yml),头注释给出三步用法并注明:升级执行 docker compose pull && docker compose up -d,数据保留在两个命名卷。下面是本文实测使用的编排文件(基于官方文件,仅按实测环境调整了容器名与端口,并在两个服务上补了 TZ: Asia/Shanghai;官方文件默认 container_name: spug / spug-db、端口 80):
# /opt/spug/docker-compose.yml
# 基于官方 openspug/spug 4.0 分支 docker-compose.yml,容器名与端口按实测环境调整
services:
spug:
image: openspug/spug:4.1.1 # 也可 ghcr.io/openspug/spug:4.1.1
container_name: spug-4.1.1-app
restart: unless-stopped
ports:
- "8128:80" # 左侧为对外端口,80 冲突时改这里
environment:
TZ: Asia/Shanghai # 任务计划与时区的基准
MYSQL_HOST: db
MYSQL_PORT: 3306
MYSQL_DATABASE: spug
MYSQL_USER: spug
MYSQL_PASSWORD: ${SPUG_DB_PASSWORD:-spug.cc} # 与 db 服务保持一致
# SPUG_ADMIN_PASSWORD: q1w2e3r4 # 可选:预设首启管理员密码;不设则随机生成并打印在日志
volumes:
- spug-data:/data # 应用程序与运行数据全部落在此卷
# 以下三项用于「主机文件分发」「流水线数据传输」节点以 sshfs 挂载来源主机;
# 不用这两个功能可删除,官方注释明确说明
cap_add:
- SYS_ADMIN
devices:
- /dev/fuse
security_opt:
- apparmor:unconfined
depends_on:
db:
condition: service_healthy # 等待数据库健康检查通过后再启动
db:
image: mariadb:10.11
container_name: spug-4.1.1-db
restart: unless-stopped
command: --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
environment:
MARIADB_DATABASE: spug
MARIADB_USER: spug
MARIADB_PASSWORD: ${SPUG_DB_PASSWORD:-spug.cc} # 仅 Spug 服务可访问
MARIADB_RANDOM_ROOT_PASSWORD: "1" # root 密码随机化,不对外暴露
volumes:
- spug-db:/var/lib/mysql # 数据库数据卷
healthcheck:
test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"]
interval: 5s
timeout: 5s
retries: 30
start_period: 30s
volumes:
spug-data:
spug-db:
关键参数注解:
| 参数 | 说明 | 实测要点 |
|---|---|---|
SPUG_DB_PASSWORD | 编排级环境变量,compose 启动前注入;spug 与 db 两个服务必须一致 | 默认值 spug.cc;生产建议在启动前 export SPUG_DB_PASSWORD=强密码 或写入同目录 .env 文件 |
SPUG_ADMIN_PASSWORD | 可选,预设首个管理员密码 | 不设则首启随机生成并打印在日志(见 3.3) |
SPUG_ADMIN_USER | 可选,预设管理员用户名 | 不设为 admin |
TZ | 时区 | v4.1.0 起任务计划的执行时刻与时间戳都跟随该变量,国内环境设 Asia/Shanghai |
MYSQL_* | 数据库连接参数 | MYSQL_HOST: db 指向编排内的 db 服务;指向外部库时改成对应地址即可(另见 《Spug v4.1.1 配置参数详解》 的运行时回退规则) |
| 数据卷 | spug-data→应用(容器内 /data)、spug-db→数据库 | 升级/重建编排不影响数据 |
⚠️ 不要把官方 MariaDB 服务的库改为不存在的库名:
MARIADB_DATABASE: spug会随首启自动建库,与MYSQL_DATABASE: spug必须同名。
3.3 首次启动与自动初始化
第 1 步:准备目录与编排文件
$ mkdir -p /opt/spug && cd /opt/spug
$ curl -fsSLO https://raw.githubusercontent.com/openspug/spug/4.0/docker-compose.yml
按 3.2 说明调整端口/时区/数据库密码后执行启动。数据库密码建议显式指定:
$ export SPUG_DB_PASSWORD='Q1w2E3r4-Spug'
第 2 步:启动编排
$ docker compose up -d
输出要点(节选,2026-10-25 实测):两个命名卷 spug-data、spug-db 创建,db 容器完成健康检查(healthy)后 spug 容器启动:
✔ Volume "stack_spug-data" Created
✔ Volume "stack_spug-db" Created
✔ Container spug-4.1.1-db Healthy
✔ Container spug-4.1.1-app Started
第 3 步:观察自动初始化(仅首次启动执行)
首启时 spug 服务会依次完成:安装程序到数据卷 → 等待数据库就绪 → 建表迁移 → 生成管理员 → 拉起全部服务。实测日志(docker compose logs spug,逐行照抄,省略号处为各业务模块的迁移明细,account/alarm/app/config/credential/deploy/exec/home/host/monitor/notify/pipeline/repository/schedule/setting 全模块逐个建表):
spug-4.1.1-app | [spug] installing Spug v4.1.1 into /data/spug
spug-4.1.1-app | [spug] waiting for the database at db:3306
spug-4.1.1-app | /usr/local/lib/python3.11/site-packages/paramiko/pkey.py:100: CryptographyDeprecationWarning: TripleDES has been moved to cryptography.hazmat.decrepit.ciphers.algorithms.TripleDES and will be removed from cryptography.hazmat.primitives.ciphers.algorithms in 48.0.0.
spug-4.1.1-app | "cipher": algorithms.TripleDES,
spug-4.1.1-app | /usr/local/lib/python3.11/site-packages/paramiko/transport.py:259: CryptographyDeprecationWarning: TripleDES has been moved to cryptography.hazmat.decrepit.ciphers.algorithms.TripleDES and will be removed from cryptography.hazmat.primitives.ciphers.algorithms in 48.0.0.
spug-4.1.1-app | "class": algorithms.TripleDES,
spug-4.1.1-app | Migrations for 'account':
spug-4.1.1-app | apps/account/migrations/0001_initial.py
spug-4.1.1-app | - Create model History
spug-4.1.1-app | - Create model Role
spug-4.1.1-app | - Create model User
spug-4.1.1-app | Migrations for 'alarm':
spug-4.1.1-app | apps/alarm/migrations/0001_initial.py
spug-4.1.1-app | - Create model Alarm
spug-4.1.1-app | - Create model Group
spug-4.1.1-app | - Create model Contact
spug-4.1.1-app | Migrations for 'config':
spug-4.1.1-app | apps/config/migrations/0001_initial.py
spug-4.1.1-app | - Create model Service
spug-4.1.1-app | - Create model Environment
spug-4.1.1-app | - Create model ConfigHistory
spug-4.1.1-app | - Create model Config
……
spug-4.1.1-app | [spug] ============================================================
spug-4.1.1-app | [spug] created the admin account
spug-4.1.1-app | [spug] username: admin
spug-4.1.1-app | password: dmpcUXabJa_c7pGx
spug-4.1.1-app | (generated once; change it after logging in)
spug-4.1.1-app | [spug] ============================================================
spug-4.1.1-app | [spug] starting services
spug-4.1.1-app | 2026-10-25 09:25:15,082 CRIT Supervisor is running as root. Privileges were not dropped because no user is specified in the config file. If you intend to run as root, you can set user=root in the config file to avoid this message.
⚠️ 管理员密码只在首次启动打印一次。若在编排中预设了
SPUG_ADMIN_PASSWORD则不会随机生成;若错过了日志,登录后立即修改,或参考 《Spug v4.1.1 常用 CLI 命令详解》 用user reset重设。日志中的 paramikoCryptographyDeprecationWarning为上游依赖的弃用提示,不影响功能。
第 4 步:取回首启随机密码
$ docker compose logs spug | grep password
spug-4.1.1-app | password: dmpcUXabJa_c7pGx
第 5 步:确认服务就绪
$ docker compose ps
NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS
spug-4.1.1-app openspug/spug:4.1.1 "/entrypoint.sh" spug 12 minutes ago Up 8 minutes (healthy) 0.0.0.0:8128->80/tcp, [::]:8128->80/tcp
spug-4.1.1-db mariadb:10.11 "docker-entrypoint.s…" db 12 minutes ago Up 12 minutes (healthy) 3306/tcp
两个服务均为 healthy 即初始化完成。spug 服务的健康检查就绪约在首启后 1~2 分钟(迁移建表耗时占大头)。
3.4 登录验证
浏览器打开 http://<服务器地址>:8128/,以 admin + 第 4 步取到的密码登录。本文额外用接口做了双重验证(2026-10-25 实测):
$ curl -sI http://127.0.0.1:8128/ | head -n 3
HTTP/1.1 200 OK
Server: nginx
Date: Sun, 25 Oct 2026 01:38:02 GMT
$ curl -s -X POST -H 'Content-Type: application/json' \
-d '{"username":"admin","password":"dmpcUXabJa_c7pGx","type":"default"}' \
http://127.0.0.1:8128/api/account/login/
{"data": {"id": 1, "access_token": "82d20cdaccc44fe48ae3e6f85781e8d3", "nickname": "管理员", "is_supper": true, …}}
返回 32 位 access_token 即登录成功(有效期 8 小时,后续请求以 x-token 头携带)。接口调用必须带 type 参数,排障见第四章实录一。服务内部 7 个受管进程可用 supervisorctl status 观察(实测):
nginx RUNNING pid 25, uptime 0:09:49
redis RUNNING pid 26, uptime 0:09:49
spug-api RUNNING pid 27, uptime 0:09:49
spug-monitor RUNNING pid 32, uptime 0:09:49
spug-scheduler RUNNING pid 35, uptime 0:09:49
spug-worker RUNNING pid 40, uptime 0:09:49
spug-ws RUNNING pid 45, uptime 0:09:49
💡 首启登录后建议立即:①在「个人中心」改掉随机密码;②创建普通账号并关闭 admin 日常使用(示例账号体系 root/admin + q1w2e3r4 的改法见 CLI 篇)。
3.5 升级、数据备份与清理
升级(官方口径:数据保留在两个命名卷,升级后首启自动执行数据库结构更新):
$ docker compose pull && docker compose up -d
数据库结构变更随启动自动执行,也可手动幂等执行(实测:无可执行迁移时输出如下):
$ docker exec spug-4.1.1-app sh -c 'cd /data/spug/spug_api && python3 manage.py updatedb'
No changes detected in apps 'credential', 'notify', 'host', 'monitor', 'config', 'pipeline', 'deploy', 'home', 'schedule', 'exec', 'alarm', 'repository', 'account', 'app', 'setting'
Operations to perform:
Apply all migrations: account, alarm, app, config, credential, deploy, exec, home, host, monitor, notify, pipeline, repository, schedule, setting
Running migrations:
No migrations to apply.
初始化/更新成功
备份:核心数据在两个命名卷中——应用卷(容器内 /data,含程序、上传文件、发布仓库缓存)与数据库卷(容器内 /var/lib/mysql)。常规做法是备份数据库导出文件 + 应用卷打包,并保留到平台之外。
清理:停止并连同数据卷删除(谨慎,不可逆):
$ docker compose down -v
3.6 单容器试用形态(SQLite)
只想本地快速体验时,官方支持单容器形态(内置 SQLite,不含编排内的独立数据库服务):
$ docker run -d --name spug-4.1.1-try -p 8129:80 openspug/spug:4.1.1
官方定位为 quick look;正式使用仍建议按本文编排形态配 MariaDB/MySQL(SQLite 形态无独立数据库服务,并发能力与备份手段都受限)。
四、排障实录
实录一:登录接口报 (1048, "Column 'type' cannot be null")
现象:用 curl 按直觉只传用户名密码调登录接口:
$ curl -s -X POST -H 'Content-Type: application/json' \
-d '{"username":"admin","password":"dmpcUXabJa_c7pGx"}' \
http://127.0.0.1:8128/api/account/login/
{"code": 500, "message": "(1048, \"Column 'type' cannot be null\")"}
定位:查看服务日志确认报错来自登录视图落库「登录历史」记录时 type 字段为空——account_user 表的 type 列是「登录方式」标识(Web/开放 API 等),接口请求体不填就是 null。浏览器 UI 登录不受影响(前端会自动带上 type)。
解决:请求体补 "type":"default" 即可(见 3.4 成功示例)。要点:这不是部署故障,是 API 调用姿势问题;自研脚本对接登录接口时务必携带 type 字段。
实录二:首启长时间停在 waiting for the database
现象:docker compose logs spug 反复出现 [spug] waiting for the database at db:3306,始终不进入迁移阶段。
定位与解决(按概率排查):
db服务未 healthy:docker compose ps观察 STATUS,健康检查给足 30 秒 start_period + 30 次重试;若 db 起不来,看docker compose logs db(常见是数据卷残留旧密码或库名被改过——MYSQL_*与MARIADB_*两套变量必须一致)。- 数据库密码含特殊字符且只改了一侧:
SPUG_DB_PASSWORD是编排级变量,spug与db服务共用,只改一侧必然握手失败。 - 连接串指向外部库时网络不可达:
MYSQL_HOST需要能从 Spug 服务侧解析并连通 3306。
实测环境等待耗时参考:正常路径下 db healthy 后数秒内即进入迁移阶段,全程初始化 1~2 分钟。
实录三:端口 80 已被占用导致启动失败
现象:docker compose up -d 报端口绑定失败(宿主 80 被 nginx 等占用)。
解决:只改端口映射左侧,容器内固定 80:
ports:
- "8128:80"
本文实测即采用 8128,验证通过(3.4 节 curl 回显)。
实录四:从 3.x 升级后容器拒绝启动
现象:3.x 时代的旧数据卷直接套到 4.x 编排上,容器启动即退出。
定位:v4.1.0 官方 Release Notes 明确——4.x 检测到 3.x 遗留数据卷(镜像内 /data/mysql)时会拒绝启动且不改动卷内数据,属防误升级的保护设计。
解决:3.x → 4.x 是破坏性升级(运行时、镜像、数据卷均不兼容),按官方升级指南先完成 3.x 数据备份与迁移方案,再以全新数据卷部署 4.x;不要尝试原卷直升。
五、FAQ
Q1:默认账号密码是什么?
A:首启自动创建 admin(可用 SPUG_ADMIN_USER 改名),密码随机生成、只在首启日志打印一次(docker compose logs spug | grep password);生产环境用 SPUG_ADMIN_PASSWORD 预设强密码。
Q2:数据都存在哪里?
A:两个命名卷——spug-data(应用与运行数据,容器内 /data)与 spug-db(MariaDB 数据)。docker compose down 不删卷,down -v 才删。
Q3:能改管理员密码吗?忘了怎么办?
A:能。Web 个人中心改,或服务内 python3 manage.py user reset -u admin -p 新密码(实测见 CLI 篇)。
Q4:必须配 MySQL/MariaDB 吗?
A:编排形态标配 MariaDB 10.11;不设 MYSQL_HOST 时可退化为内置 SQLite(官方定位试用)。生产用 SQLite 无法满足备份与并发要求,不推荐。
Q5:支持 ARM 服务器吗?
A:支持。v4.1.0 起官方镜像 amd64 与 arm64 双架构发布(openspug/spug 与 ghcr.io/openspug/spug 同步)。
Q6:生产环境要不要保留 cap_add: SYS_ADMIN 等三项配置?
A:只有使用「主机文件分发」或流水线「数据传输」节点(sshfs 挂载来源主机)才需要;官方注释明确不用可删,按最小权限原则裁剪。
六、总结与参考链接
本文以官方 Compose 形态在 Ubuntu 22.04 上完成了 Spug v4.1.1 的 0→1 部署:一个编排文件、两个服务、首启自动建库建号,1~2 分钟即可登录使用;实测踩坑点集中在 API 登录参数、数据库等待与 3.x 数据卷兼容三处,均已给出定位路径。下一步:
- 运行时与数据库参数逐项解析 → 《Spug v4.1.1 配置参数详解》
- 服务内命令行运维(账号、升级、进程管理) → 《Spug v4.1.1 常用 CLI 命令详解》
参考链接:
- 官方编排文件(4.0 分支):https://raw.githubusercontent.com/openspug/spug/4.0/docker-compose.yml
- 官方安装文档:https://spug.cc/docs/install/docker/
- 更新日志(v4.1.0/v4.1.1 行为变更):https://spug.cc/docs/change-log/
- GitHub 仓库:https://github.com/openspug/spug