qpixel 0.13.0 Docker Compose 部署指南

qpixel v0.13.0 官方源码 compose 三服务栈部署实录:bullseye EOL 的 apt 修复、MySQL 数据目录初始化双坑排障、健康检查编排、双层环境变量体系与等价 docker run,HTTP/数据层验证回显。

qpixelqpixel问答社区RailsDockerMySQLRedis自托管2026/11/02

qpixel 0.13.0 Docker Compose 部署指南

目标:在 Linux 宿主机上用官方源码仓库自带的 docker-compose.yml,把 qpixel v0.13.0(Codidact 问答平台,Rails 8.1.3.1 + MySQL 8.4 + Redis)三服务栈完整拉起并通过 HTTP/数据层验证。本文全部命令与回显均为 2026-11-02 实测,含构建与数据库初始化两次真实故障的完整排障实录。

一、环境信息

  • 操作系统:Ubuntu 系 Linux(x86_64)
  • 容器运行时:Docker 29.9.2(storage driver overlayfs,runc)
  • 编排工具:Docker Compose v5.6.1(docker compose version 实测回显:Docker Compose version v5.6.1)
  • 软件版本:qpixel v0.13.0(官方最新稳定版,GitHub Release 2026-09-12 发布,2026-11-02 查询;认知与选型见《qpixel 介绍与选型指南》)
  • 应用栈技术组成(启动日志实测):Rails 8.1.3.1、Ruby 3.4.5、Puma 7.2.1、MySQL 8.4.2、Redis
  • 部署根目录:/opt/data/quzuo/tmp/qpixel/qpixel-0.13.0(v0.13.0 归档包解包目录,即 compose 文件所在的应用根)
  • compose 项目名:qpixel-0130-stack(compose 文件写 name: qpixel-0.13.0-stack,Docker 归一化去掉点号后落到资源名前缀)
  • 网络:qpixel-v0.13.0-net,自定义 bridge,显式子网 10.89.68.0/24
  • Web 映射:宿主 8131 → 应用 3000(8128–8152 段内取空闲端口,ss -ltn 预检)
  • 初始社区:Dev Community;演示账号 admin / q1w2e3r4(全局管理员,admin@example.com)
  • 运行环境:RAILS_ENV=development(官方 compose 路线即开发模式,见文末官方说明)

三服务一览(docker compose ps 实测回显):

NAME                        IMAGE                     COMMAND                  SERVICE   CREATED             STATUS                       PORTS
qpixel-0130-stack-db-1      qpixel-0130-stack-db      "/bin/bash /docker/e…"   db        About an hour ago   Up About an hour (healthy)   3306/tcp, 33060/tcp
qpixel-0130-stack-redis-1   redis:latest              "docker-entrypoint.s…"   redis     About an hour ago   Up About an hour (healthy)   6379/tcp
qpixel-0130-stack-uwsgi-1   qpixel-0130-stack-uwsgi   "/bin/bash /code/doc…"   uwsgi     About an hour ago   Up About an hour             80/tcp, 443/tcp, 0.0.0.0:8131->3000/tcp, [::]:8131->3000/tcp

二、镜像选型说明

qpixel 不发布官方运行时镜像,官方部署路线(仓库 docker/README.md)是拿源码包自带的 docker-compose.yml 本地构建两个镜像,Redis 直接用官方镜像:

服务镜像来源基础镜像实测占用
dbqpixel-0130-stack-db仓库 docker/Dockerfile.db 构建mysql:8.4.2800MB
redisredis:latestDocker Hub 官方镜像直接拉取——
uwsgiqpixel-0130-stack-uwsgi仓库 docker/Dockerfile 构建(CLIENT_DOCKERFILE 指定)ruby:3.4.5-bullseye + 从 node:12.18.3-slim 拷入 Node/Yarn2.23GB

(占用为 docker images 实测 SIZE 列。)

两个自建镜像的要点:

  • db:Dockerfile.db 全文只有 4 行——FROM mysql:8.4.2、COPY docker/mysql-init.sql /docker-entrypoint-initdb.d/、ENTRYPOINT ["/bin/bash"]、CMD ["/docker/entrypoint.sh"]。注意它把 ENTRYPOINT 改成了 bash,真正的启动命令是 compose 绑挂进来的 docker/db-entrypoint.sh(见第七章),这直接导致了后文「首次 up 数据库起不来」的坑。
  • uwsgi:服务名叫 uwsgi 是历史遗留,实际进程是 Puma(启动日志 => Booting Puma)。docker/Dockerfile 为多阶段构建:ruby:3.4.5-bullseye 装系统依赖和 gem(bundle install),再从 node:12.18.3-slim 挑文件拷入 node/npm/yarn(前端资产编译用)。
  • 构建配置二选一:CLIENT_DOCKERFILE 默认指 docker/Dockerfile(类生产配置,起服务);另有 docker/Dockerfile.dev(本地开发配置,内置 Firefox,但不自动起 Rails,需手动 rails server -b 0.0.0.0)。本文用默认值。
  • ⚠️ bullseye 已 EOL:ruby:3.4.5-bullseye 的 apt 源指向 deb.debian.org,Debian 11 归档后该源 404,官方 Dockerfile 原样构建必失败,必须先做第四章 4.5 节的源修复。

三、前置条件

docker compose version          # 要求 2.x+(本文 v5.6.1)
docker info >/dev/null && echo docker-ok   # docker daemon 在跑
ss -ltn | grep ':8131' || echo port-8131-free   # Web 端口空闲
  • 宿主机已装 Docker Engine 与 compose plugin(官方 README 提示 Debian 系可 sudo apt-get install docker-compose-plugin)。
  • 构建需要外网:拉 ruby:3.4.5-bullseye、node:12.18.3-slim、mysql:8.4.2、redis:latest 四个基础镜像,构建中访问 archive.debian.org(修复后)、RubyGems 与 npm 源。
  • 磁盘余量 ≥ 5GB(两个产物镜像实测合计约 3GB,加构建缓存与 MySQL 数据目录)。
  • 自定义网络显式指定子网(本文 10.89.68.0/24),避免与同宿主机其他栈冲突。

四、部署步骤

4.1 获取 v0.13.0 源码归档

qpixel 官方 compose 路线要求源码目录整体在场(compose 把源码目录 bind 进应用当运行目录),用 Git tag 对应的归档包:

cd /opt/data/quzuo/tmp/qpixel
curl -sSL -o qpixel-v0.13.0.tar.gz https://codeload.github.com/codidact/qpixel/tar.gz/refs/tags/v0.13.0
tar xzf qpixel-v0.13.0.tar.gz

实测:归档 4,205,661 字节,顶层目录 qpixel-0.13.0/;下载 URL 当日 HEAD 请求回显 HTTP/2 200。

4.2 一键初始化配置文件(local-setup.sh)

官方脚本把 5 个样例文件复制为正式配置:

cd qpixel-0.13.0
chmod +x docker/local-setup.sh
docker/local-setup.sh

脚本内容(实测 cat):

#!/bin/bash

cp ./docker/dummy.env ./docker/env
cp ./docker/compose-env .env
cp config/database.docker.yml config/database.yml
cp config/storage.docker.yml config/storage.yml
cp ./.sample.irbrc ./.irbrc

即:.env(compose 插值层)来自 docker/compose-env,docker/env(注入应用的密钥层)来自 docker/dummy.env,config/database.yml、config/storage.yml 来自对应 .docker.yml 模板。

4.3 调整 .env(compose 插值层)

实测修改后的 .env 全文:

COMPOSE_FILE=./docker-compose.yml
LOCAL_DEV_PORT=8131
COMMUNITY_NAME=Dev Community
MAILER_PROTOCOL=https
RAILS_ENV=development
CONFIRMABLE_ALLOWED_ACCESS_DAYS=2
ENV_FILE_LOCATION=./docker/env
CLIENT_DOCKERFILE=docker/Dockerfile

与默认 compose-env 的差异只有 LOCAL_DEV_PORT(默认 3000 → 8131)。官方 README 特别强调:编辑 .env 只影响 compose 文件里的插值变量,不会改变运行环境内的环境变量;后者要改 docker/env。

4.4 调整 docker/env(应用密钥层)

docker/dummy.env 只带 4 个 MySQL 变量,管理员三件套需补上。实测最终文件全文:

MYSQL_ROOT_PASSWORD=qpixel
MYSQL_DATABASE=qpixel
MYSQL_USER=qpixel
MYSQL_PASSWORD=qpixel
COMMUNITY_ADMIN_USERNAME=admin
COMMUNITY_ADMIN_PASSWORD=q1w2e3r4
COMMUNITY_ADMIN_EMAIL=admin@example.com

官方 README 要求 COMMUNITY_ADMIN_PASSWORD 至少 6 字符,否则初始管理员不会创建(见第十一章 Q4)。

4.5 修复 Dockerfile 的 EOL apt 源

直接 docker compose build 第一次失败,回显节选(build.log 实录):

18.72 E: Failed to fetch http://deb.debian.org/debian-security/pool/updates/main/libf/libfcgi/libfcgi0ldbl_2.4.2-2%2bdeb11u1_amd64.deb  404  Not Found [IP: 146.75.122.132 80]
18.73 E: Failed to fetch http://deb.debian.org/debian-security/pool/updates/main/libx/libxslt/libxslt1-dev_1.1.34-4%2bdeb11u3_amd64.deb  404  Not Found [IP: 146.75.122.132 80]
18.73 E: Unable to fetch some archives, maybe run apt-get update or try with --fix-missing?
------
Dockerfile:10
--------------------
  10 | >>> RUN apt-get update && \
  11 | >>>     apt-get install -y bison \
--------------------
target uwsgi: failed to solve: process "/bin/sh -c apt-get update && ..." did not complete successfully: exit code: 100
BUILD_EXIT=1

原因:bullseye(Debian 11)EOL,其包已从 deb.debian.org 移除。给 docker/Dockerfile 的 apt 安装步骤前插入两行修复(sed 换 archive 源 + 关闭有效期检查):

RUN sed -i 's|http://deb.debian.org/debian-security|http://archive.debian.org/debian-security|; s|http://deb.debian.org/debian|http://archive.debian.org/debian|g' /etc/apt/sources.list \
 && echo 'Acquire::Check-Valid-Until "false";' > /etc/apt/apt.conf.d/99no-check-valid-until \
 && apt-get update && \
    apt-get install -y bison \
    ...

4.6 构建

docker compose build

第二次构建成功(build2.log 回显节选):

#36 [uwsgi] exporting to image
#36 naming to docker.io/library/qpixel-0130-stack-uwsgi:latest done
#36 unpacking to docker.io/library/qpixel-0130-stack-uwsgi:latest 5.9s done
#37 [uwsgi] resolving provenance for metadata file
#37 DONE 0.0s
 Image qpixel-0130-stack-db Built
 Image qpixel-0130-stack-uwsgi Built
BUILD_EXIT=0

只重建单个服务可用 docker compose build uwsgi / docker compose build db。

4.7 启动(含一次数据库初始化故障实录)

docker compose up -d

首败:db 起不来,日志报:

mysqld: File './binlog.index' not found (OS errno 13 - Permission denied)

原因:compose 把宿主 bind 目录 docker/mysql 挂到 /var/lib/mysql,该目录属 root,而 MySQL 进程 uid=999。处理:

chown -R 999:999 docker/mysql

仍 unhealthy,新报错:

File ./ibdata1: 'open' returned OS error 71

原因(读 docker/db-entrypoint.sh 定位):qpixel 的 db 镜像把 ENTRYPOINT 换成了 bash,db-entrypoint.sh 直接裸跑 mysqld,完全绕开了官方 mysql 镜像的初始化流程——空数据目录里没有 ibdata1 可谈。官方镜像初始化必须借道完成一次:

rm -rf docker/mysql/*
docker run --rm -v "$(pwd)/docker/mysql:/var/lib/mysql" \
  -e MYSQL_ROOT_PASSWORD=qpixel -e MYSQL_DATABASE=qpixel \
  -e MYSQL_USER=qpixel -e MYSQL_PASSWORD=qpixel \
  mysql:8.4.2

回显节选:

[Note] [Entrypoint]: Initializing database files
[Warning] [MY-010453] root@localhost is created with an empty password ! ...
[Note] [Entrypoint]: Creating database qpixel
[Note] [Entrypoint]: Creating user qpixel
[Note] [Entrypoint]: MySQL init process done. Ready for start up.
/usr/sbin/mysqld: ready for connections. Version: '8.4.2' ... port: 3306

(该一次性进程跑完自动退出,数据文件已落在 bind 目录。)随后再次 docker compose up -d,三服务全部起来,db/redis 状态 healthy。

4.8 应用层初始化(自动)

uwsgi 的启动脚本 docker/entrypoint.sh 首次运行会串完整个建库流程(实测日志 uwsgi-init.log 节选):

Created database 'qpixel_dev'
Created database 'qpixel_test'
PostType: created 5
CloseReason: created 5
License: created 5
TagSet: created 2
PostHistoryType: created 16
User: created 1
Ability: created 7
CommunityUser: created 1
Filter: created 4
Category: created 2
PostFlagType: created 5
Post: created 23
ReactionType: created 3
SiteSetting: skipped 112
=> Booting Puma
=> Rails 8.1.3.1 application starting in development
Puma starting in single mode...
* Puma version: 7.2.1 ("On The Corner")
* Ruby version: ruby 3.4.5 (2025-07-16 revision 20cda200d3) +PRISM [x86_64-linux]
*  Min threads: 5
*  Max threads: 5
*  Environment: development
*          PID: 104
* Listening on http://0.0.0.0:3000

(SiteSetting: skipped 112 是 entrypoint 设计里第二次 rails db:seed 的输出——种子幂等跳过,属正常。)

4.9 验证

curl -sS -o /dev/null -w "HTTP %{http_code}\n" http://localhost:8131/

实测回显:

HTTP 200

页面标题实测:[DEV] Q&A - QPixel。数据层验证(rails runner,实测):

docker compose exec -T uwsgi rails runner 'puts Community.first.name'
# => Dev Community
docker compose exec -T uwsgi rails runner 'u = User.find_by(username: "admin"); puts "admin user: id=#{u.id} global_admin=#{u.is_global_admin} email=#{u.email}"'
# => admin user: id=1 global_admin=true email=admin@example.com

邮件预览入口实测:curl -sS -o /dev/null -w "HTTP %{http_code}" http://localhost:8131/letter_opener → HTTP 200。

浏览器打开 http://localhost:8131,Sign in 用 admin / q1w2e3r4 登录。

4.10 部署后必做的分类配置

官方 README 明确:发帖前必须给每个分类绑定 Tag Set,否则无法发帖。进 /categories/,对每个分类点 edit,在 "Tag Set" 字段选择(如 Meta 分类选 "Meta"、Q&A 分类选 "Main"),保存。然后即可建帖。

五、数据持久化说明

数据落点持久化方式
MySQL 全部库(qpixel_dev/qpixel_test 及 binlog、ibdata1)宿主 ./docker/mysqlbind mount → /var/lib/mysql,down/重建镜像均不丢
应用源码(即运行代码本体)宿主 ./(部署根)bind mount → /code,改代码重启即生效
静态资产./staticbind mount → /var/www/static
上传图片./imagesbind mount → /var/www/images
Redis无卷仅作缓存/队列,重启清空可接受
首次初始化标记 /db-created应用运行环境文件系统内不持久。镜像重建后 entrypoint 会重跑 db:create/db:schema:load/种子(种子实测幂等:Post: skipped 23、SiteSetting: skipped 112)

备份口径:停栈后直接 rsync ./docker/mysql 即可整库冷备;热备走 mysqldump 或仓库自带 scripts/database_backup.rb(默认注释停用,见《qpixel 0.13.0 常用 CLI 命令与工具详解》)。

六、环境变量表

6.1 .env(compose 插值层)

变量本文取值默认(compose-env)作用
COMPOSE_FILE./docker-compose.yml同左compose 入口文件,可换自定义编排
LOCAL_DEV_PORT81313000宿主映射端口("${LOCAL_DEV_PORT}:3000")
COMMUNITY_NAMEDev CommunityDev Community初始社区名(仅数据库初始化时消费)
MAILER_PROTOCOLhttpshttps邮件链接协议
RAILS_ENVdevelopmentdevelopmentRails 环境
CONFIRMABLE_ALLOWED_ACCESS_DAYS22未确认账号允许访问天数
ENV_FILE_LOCATION./docker/env同左密钥文件位置
CLIENT_DOCKERFILEdocker/Dockerfile同左uwsgi 构建用 Dockerfile(可换 docker/Dockerfile.dev)

6.2 docker/env(env_file 注入 db 与 uwsgi)

变量本文取值必需作用
MYSQL_ROOT_PASSWORDqpixel是root 口令(初始化用)
MYSQL_DATABASEqpixel是初始化库名
MYSQL_USER / MYSQL_PASSWORDqpixel / qpixel是应用连接账号(与 config/database.yml 一致)
COMMUNITY_ADMIN_USERNAMEadmin是*初始管理员用户名(仅建库时用)
COMMUNITY_ADMIN_PASSWORDq1w2e3r4是*初始管理员口令,≥6 字符
COMMUNITY_ADMIN_EMAILadmin@example.com是*初始管理员邮箱

(* 官方 README 标注 "Only required on database init"。)

6.3 应用内实测注入清单

uwsgi 运行环境 env 实测(节选):

COMMUNITY_ADMIN_EMAIL=admin@example.com
COMMUNITY_ADMIN_PASSWORD=q1w2e3r4
COMMUNITY_ADMIN_USERNAME=admin
COMMUNITY_NAME=Dev Community
CONFIRMABLE_ALLOWED_ACCESS_DAYS=2
LOCAL_DEV_PORT=8131
MAILER_PROTOCOL=https
RAILS_ENV=development

6.4 代码有默认值、本文未注入的可选变量

变量默认值出处(源码实测)
PORT3000config/puma.rb
RAILS_MAX_THREADS / RAILS_MIN_THREADS5config/puma.rb
PIDFILEtmp/pids/server.pidconfig/puma.rb
WEB_CONCURRENCY2(该行被注释,未启用)config/puma.rb
REDIS_URLredis://localhost:6379/1config/cable.yml
MAILER_DELIVERY_METHOD未设则 :letter_opener_webconfig/environments/development.rb
MAILER_HOSTmeta.codidact.comconfig/environments/development.rb
ALL_REQUESTS_LOCALtrueconfig/environments/development.rb
PERFORM_CACHING / LOG_LEVEL / RAISE_DELIVERY_ERRORS未设走代码默认config/environments/development.rb

参数语义与调优口径详见《qpixel 0.13.0 配置参数详解》。

七、配置参数说明(compose 编排层)

docker-compose.yml 全文实测要点:

name: qpixel-0.13.0-stack
services:
  db:
    restart: on-failure:3
    build: { context: ".", dockerfile: docker/Dockerfile.db }
    volumes:
      - ./docker/db-entrypoint.sh:/docker/entrypoint.sh
      - ./docker/mysql:/var/lib/mysql
    env_file: [ ${ENV_FILE_LOCATION} ]
    cap_add: [ SYS_NICE ]
    healthcheck:
      test: mysqladmin ping -h 127.0.0.1 -u $$MYSQL_USER --password=$$MYSQL_PASSWORD
      start_period: 5s
      interval: 5s
      timeout: 5s
      retries: 12
  uwsgi:
    restart: on-failure:3
    build: { context: ".", dockerfile: ${CLIENT_DOCKERFILE} }
    depends_on:
      db: { condition: service_healthy }
      redis: { condition: service_healthy }
    ports: [ "${LOCAL_DEV_PORT}:3000" ]
    volumes:
      - .:/code
      - ./static:/var/www/static
      - ./images:/var/www/images
    links: [ redis, db ]
  redis:
    restart: on-failure:3
    image: redis:latest
    healthcheck: { test: ["CMD", "redis-cli", "ping"] }
networks:
  default:
    name: qpixel-v0.13.0-net
    ipam: { config: [ { subnet: 10.89.68.0/24 } ] }
  • 启动顺序靠健康检查把关:depends_on ... condition: service_healthy,db 用 mysqladmin ping($$ 是 compose 转义,取容器内环境变量),12 次×5s 重试给足 MySQL 初始化时间。
  • cap_add: SYS_NICE:MySQL 8 调整调度优先级需要,缺省会刷告警。
  • db 启动命令(docker/db-entrypoint.sh 全文实测):
#!/bin/bash

mysqld --init-file=/docker-entrypoint-initdb.d/mysql-init.sql \
       --mysql-native-password=on \
       --skip-mysqlx

--mysql-native-password=on 兼容 mysql2 gem 老认证握手;--skip-mysqlx 关掉 X 协议(33060 端口仅监听不服务);--init-file 执行 docker/mysql-init.sql 授权(实测内容:对 qpixel_dev/qpixel_test/qpixel_dump/qpixel 四库 GRANT ALL ON ... TO qpixel)。

  • uwsgi 的 entrypoint(docker/entrypoint.sh):无 /db-created 标记时依次跑 rails db:create → rails db:schema:load → rails r db/scripts/create_tags_path_view.rb → rails db:migrate(两遍,第二遍显式 RAILS_ENV=development)→ rails r docker/create_admin_and_community.rb → UPDATE_POSTS=true rails db:seed,然后再跑一遍 rails db:seed(脚本注释:不重跑会在首页 500),最后 rails server -b 0.0.0.0。
  • 初始管理员创建逻辑(docker/create_admin_and_community.rb):四个必需 ENV 缺任一即打印缺失项并 exit 1;社区 host 写成 localhost:${LOCAL_DEV_PORT},用户直接以 is_global_admin: true, is_global_moderator: true, staff: true, confirmed_at: DateTime.now 落库(免邮箱确认)。

八、配置文件挂载

宿主文件挂载点生效方式
.env不挂载(compose 启动时读取做插值)改后需 docker compose up -d 重建才生效(插值发生在编排层)
docker/env不挂载(env_file 注入进程环境)改后 docker compose up -d --force-recreate 对应服务
docker/db-entrypoint.shdb:/docker/entrypoint.sh改后重启 db 服务
config/database.yml、config/storage.yml随源码目录整体挂载进 /code改后重启 uwsgi 服务(Rails 启动时读取)
static/、images//var/www/static、/var/www/images文件级即时生效

config/database.yml 实测全文(由 database.docker.yml 模板复制):

default: &default
  adapter: mysql2
  encoding: utf8mb4
  collation: utf8mb4_unicode_ci
  host: db
  port: 3306
  username: qpixel
  password: qpixel

development:
  <<: *default
  database: qpixel_dev

test:
  <<: *default
  database: qpixel_test

production:
  <<: *default
  database: qpixel

redis_default: &redis_default
  host: redis
  port: 6379

redis_development:
  <<: *redis_default

redis_test:
  <<: *redis_default

redis_production:
  <<: *redis_default

要点:host: db / host: redis 是 compose 服务名解析;username/password 必须与 docker/env 一致(官方 README 第 2 步专门提醒)。

九、等价 docker run

不使用 compose 时的等价三条原生命令(网络、卷、端口与编排一致;db 的健康门控需改为手工确认起后再拉 uwsgi):

docker network create --subnet 10.89.68.0/24 qpixel-v0.13.0-net

docker run -d --name qp-db \
  --network qpixel-v0.13.0-net \
  --cap-add SYS_NICE \
  --env-file ./docker/env \
  -v "$(pwd)/docker/db-entrypoint.sh:/docker/entrypoint.sh" \
  -v "$(pwd)/docker/mysql:/var/lib/mysql" \
  qpixel-0130-stack-db

docker run -d --name qp-redis \
  --network qpixel-v0.13.0-net \
  redis:latest

docker run -d --name qp-app \
  --network qpixel-v0.13.0-net \
  -p 8131:3000 \
  --env-file ./docker/env \
  -e COMMUNITY_NAME="Dev Community" \
  -e RAILS_ENV=development \
  -e MAILER_PROTOCOL=https \
  -e CONFIRMABLE_ALLOWED_ACCESS_DAYS=2 \
  -e LOCAL_DEV_PORT=8131 \
  -v "$(pwd):/code" \
  -v "$(pwd)/static:/var/www/static" \
  -v "$(pwd)/images:/var/www/images" \
  qpixel-0130-stack-uwsgi

注意 --env-file 只能注入 KEY=VALUE 平面变量,compose 里 ${LOCAL_DEV_PORT} 这类插值仍需 .env 在场(构建期);换端口时 LOCAL_DEV_PORT 与 -p 映射要保持一致(初始社区 host 由它拼出)。

十、常用运维命令

cd /opt/data/quzuo/tmp/qpixel/qpixel-0.13.0

docker compose ps                          # 三服务状态(本文第一章回显)
docker compose logs -f --tail 50 uwsgi     # 跟踪应用日志(Puma 访问/报错)
docker compose logs --tail 30 db           # 查看 MySQL 日志
docker compose restart uwsgi               # 改 config/*.yml、代码后重启应用
docker compose exec -T uwsgi rails runner '<Ruby 代码>'   # 数据层操作入口
docker compose exec -T db sh -c 'mysql -uqpixel -pqpixel qpixel_dev -e "SHOW TABLES"'  # 直查库
docker compose stop / start                # 停/起(数据保留)
docker compose down                        # 删容器与网络(bind 数据保留)
docker compose down -v                     # 本栈无命名卷,效果同 down;数据在 ./docker/mysql,删它才是清库

十一、常见问题

Q1:docker compose build 在 apt 步骤报一堆 404。 A:bullseye EOL,deb.debian.org 已移除其包。按 4.5 节换 archive.debian.org 并关闭 Check-Valid-Until。本文实测第一次 build 因此失败(exit code: 100),修复后 BUILD_EXIT=0。

Q2:首次 up 后 db 一直 unhealthy,日志 File './binlog.index' not found (OS errno 13 - Permission denied)。 A:bind 数据目录属 root 而 MySQL 进程 uid=999。chown -R 999:999 docker/mysql。

Q3:chown 后仍起不来,报 File ./ibdata1: 'open' returned OS error 71。 A:qpixel 的 db 镜像 ENTRYPOINT 被改成 bash 裸跑 mysqld,不会自动初始化空数据目录。按 4.7 节用官方 mysql:8.4.2 镜像带同样 bind 目录跑一次初始化(Initializing database files → MySQL init process done),再 up -d。

Q4:登录页用 admin 登不进去。 A:检查 COMMUNITY_ADMIN_PASSWORD 是否 ≥6 字符——官方 README 明说口令过短则用户根本不会创建;另外 entrypoint 里四个必需 ENV 缺任一,创建脚本会直接 exit 1(打印 XXX is required)。

Q5:首页 500,报 posts 相关错误。 A:entrypoint 源码注释写明:rails db:seed 不跑第二遍就会在首页 500。手工补一次:docker compose exec -T uwsgi rails db:seed。

Q6:注册/发帖按钮不可用。 A:先完成 4.10 节分类 Tag Set 配置;帖子正文/标题有字符要求且至少一个标签(官方 README 第 7 步)。

Q7:收不到确认邮件。 A:该编排默认不发真邮件,letter_opener_web 拦截,浏览器开 http://localhost:8131/letter_opener 查看(实测 HTTP 200)。

Q8:每次执行 rails/rake 命令都刷 fatal: not a git repository 和 To use retry middleware with Faraday v2.0+...。 A:正常噪音。前者因 config/initializers/zz_cache_setup.rb 调 git rev-parse 取版本信息而源码是 tar 包解出(无 .git);后者是 Faraday v2 的 gem 提示。读回显直接跳过。

Q9:改端口后页面跳转/邮件链接端口不对。 A:初始社区的 host 在建库时按 localhost:${LOCAL_DEV_PORT} 写死进 communities 表(docker/create_admin_and_community.rb),换端口需同步更新该记录(rails runner 改 Community.first.update(host: ...))。

十二、参考链接

qpixel 0.13.0 Docker Compose 部署指南 - Quzuo