Crater Docker Compose 部署:从拉代码到开出一张发票
Crater 是一个用 Laravel + Vue 构建的开源发票系统,覆盖发票、报价单、费用和收款的完整流程。本文解决的是单机自托管场景下的 Docker Compose 部署:从一台只装了 Docker 的机器开始,用一条命令拉起 4 个容器,走完网页安装向导,最后用一张真实发票验证结果——得到一套能对外开账的发票系统。
先搞清楚 4 个容器各干什么
仓库根目录的 docker-compose.yml 一次拉起 4 个服务,全部挂在名为 crater 的 bridge 网络里:
| 服务 | 镜像 / 构建 | 职责 |
|---|---|---|
| app | Dockerfile 现场构建(php:8.1-fpm) | 跑 Laravel,镜像里已装好 Composer 和全部 PHP 扩展 |
| db | mariadb 官方镜像 | 存全部业务数据,固定用户密码 crater |
| nginx | nginx:1.17-alpine | 反向代理,把 .php 请求转发到 app:9000 |
| cron | cron.dockerfile | 每分钟执行一次 php artisan schedule:run |
这套容器化部署里有两个细节值得知道:代码目录被同时挂进 app 和 nginx 容器的 /var/www,所以改完代码立即生效;PHP 侧的上传限制由 docker-compose/php/uploads.ini 注入(64M),docker-compose/nginx/nginx.conf 里配了对应的 client_max_body_size 64M,两层是一致的,不用额外担心上传被某一层拦下。
准备好 .env 再拉起容器
安装向导改 .env 的方式是"替换已有行":EnvironmentManager 用 str_replace 把 .env 里现有的 DB_CONNECTION、APP_URL、SANCTUM_STATEFUL_DOMAINS 这些行逐个换掉。所以 .env 必须先存在,否则向导保存数据库配置时会静默失败。第一件事就是复制模板:
git clone https://gitcode.com/gh_mirrors/cr/crater
cd crater
cp .env.example .env
.env.example 里需要留意的关键字段:
DB_CONNECTION=mysql
DB_HOST=db
DB_DATABASE=crater
DB_USERNAME=crater
DB_PASSWORD="crater"
APP_URL=http://your-domain
DB_HOST=db 不是笔误——db 是 compose 里的服务名,在容器内部网络中等价于主机名,千万别改成 127.0.0.1,否则 app 容器永远连不到数据库。APP_URL 和 SANCTUM_STATEFUL_DOMAINS 改成你的对外访问域名,否则 cookie 会写错域,登录后页面会跳来跳去。
然后拉起容器并初始化依赖:
docker-compose up -d --build
docker-compose exec app composer install --optimize-autoloader
docker-compose exec app php artisan storage:link
docker-compose exec app php artisan key:generate
第一行会现场构建 app 镜像(Dockerfile 里一次性装好 pdo_mysql、imagick 等扩展),后三行与直接执行 docker-compose/setup.sh 做的事完全相同:装依赖、建 /storage 软链、生成 APP_KEY。
在浏览器里完成安装向导
打开 http://localhost(或你的域名),InstallationMiddleware 会把请求重定向到 /installation,按四步走:
- 环境检查:PHP 版本与扩展、
storage/等目录的读写权限(由 FilePermissionChecker 执行); - 数据库配置:填连接信息,向导先真实 ping 一次连接、再改写
.env的 DB 段落。目标库必须为空——只要已存在users表就直接拒绝; - 存储位置:选本地磁盘,或 S3、Dropbox 等对象存储;
- 公司与管理员账户:填公司信息,创建第一个用户。
最后一步完成时会生成 storage/app/database_created 标记文件,它就是"是否已安装"的判断依据,刷新页面即可进入后台。
📄 验证部署:开一张真实的发票
先确认容器状态和日志里没有暗坑:
docker-compose ps
docker-compose logs -f app
四个服务都 Up 还不算完。进后台建一个项目(item)和一张发票,下载发票 PDF——系统默认生成的发票长这样:
发票 PDF 由后台任务异步生成,外发时走带哈希的路由链接(/invoices/pdf/{unique_hash}),这一步同时能顺带验证文件存储和邮件配置是否可用。
数据库存哪里:两种持久化取舍
db 的数据有两个去处,在 docker-compose.yml 的 db 服务 volumes 段切换:
| 方式 | 行为 | 适合 |
|---|---|---|
| 命名卷(默认) | 数据在 Docker 管理的 db 卷里,用 mysqldump 导出备份 | 默认单机部署 |
绑定挂载到 ./docker-compose/db/data(已注释的行) | 数据直接落在宿主机目录,方便 rsync 备份或迁移 | 要求数据必须留在宿主机磁盘 |
注意一个隐含行为:MariaDB 的 root 密码只在数据卷首次初始化时写入。如果你复用旧数据目录又改了密码,会立刻遇到对不上的凭据,只能重建卷。
🔧 修掉最常见的五个坑
- 页面 500,日志报缺 APP_KEY → 没执行
cp .env.example .env,Laravel 读不到任何配置,复制 env 后重启容器。 - 向导数据库那步保存不了 → 容器内以 uid 1000(crater-user)运行,宿主机代码目录不可写,对仓库目录执行
chown -R 1000:1000再试。 - 80 端口被占用起不来 → nginx 占用了宿主机 80,把 compose 里的映射改成
8080:80,用 8080 访问。 - 改了数据库密码还是报旧错误 → 数据卷已初始化过,env 只在首次启动生效,删旧卷或沿用旧密码。
- 向导提示数据库非空 → 目标库里已有
users表,换一个空库重装。
部署完成之后往哪走
四台容器起来、向导通过、发票能开出来,单机部署就算闭环了。接下来值得做的两件事:把 APP_ENV 切到 production、关掉 APP_DEBUG,并在向导的邮件步骤接好 SMTP,让发票邮件真正发得出去;如果有扩容需求,把这四个服务编排成 K8s 的 Deployment 也不难——核心只有两点:代码目录的共享卷,和数据库的持久化卷。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考




