☰
Taiga自建项目管理:Docker Compose部署、HTTPS与运维排障
2026/10/27 2:42:21 网站建设 项目流程

1. 为什么我选择自己部署一套 Taiga:场景判断与方案取舍

Taiga 部署这件事,我在过去两年里前前后后做过四五次:给一个十来人的小团队做过内网版,给自己折腾过带 HTTPS 的公网实例,也帮朋友在低配机器上做过精简版。Taiga 是一套开源的项目管理工具,核心能力覆盖 Scrum 与看板两种工作流,用户故事、任务、缺陷、迭代、燃尽图、Wiki 这些都在里面,界面干净、拖拽顺手,中文支持也过得去。说白了,它就是让你不用把项目进度散落在聊天记录、表格和便利贴里的那一类工具。

真正让我愿意反复动手部署的原因,是数据归属和定制自由度。SaaS 版按人头收费,人一多就是笔固定开销;而项目管理数据本身就带着组织架构、需求优先级、客户信息这类东西,放在别人服务器上总觉得不太踏实。自己部署一套,数据在自己手里,想改个字段、加个状态、接个内部 SSO 都随你。这篇文章面向的是有基本 Linux 操作经验、看得懂 docker 命令、能自己排查一点日志的读者,小白读完能照做,老手能直接跳到配置细节和踩坑章节。

需要先说清楚一件事:Taiga 不是一个单文件程序,它是一组服务拼起来的系统。后端是 Django 写的 API 服务,前端是单独编译的 SPA,实时通知靠一个 Node 服务,异步任务靠消息队列加 worker,数据落在 PostgreSQL,缓存和队列又用到 Redis 和 RabbitMQ,最后还得有个 Nginx 在前面挡着。理解了这套拓扑,后面所有的报错你都能自己对上号;不理解,就只能看到"页面 502"然后干瞪眼。

1.1 Taiga 到底解决了什么问题

从功能视角看,Taiga 把项目拆成"项目—史诗(可选)—用户故事—任务/缺陷"这几层,用户故事可以挂到迭代(Sprint)里,看板上拖动卡片就是改状态,燃尽图自动跟着变。团队里最常见的用法是:产品侧写用户故事、排优先级、估点;开发侧在迭代里认领任务、更新状态;测试侧提缺陷,缺陷也走同一套看板。这套流程本身不新鲜,Jira、Redmine 都能做,Taiga 的差异在于它把"轻"做得很彻底——没有几百个配置项等着你调,新建项目三分钟就能跑起来。

从运维视角看,它解决的是"信息孤岛"问题。我以前见过一个团队,需求写在文档里,任务写在表格里,讨论散在群聊里,每周开会花两个小时对齐进度。换成自建 Taiga 之后,所有东西收敛到一个链接里,谁在做什么、卡在哪、这周能不能交付,一眼能看到。这个价值跟工具本身贵不贵没关系,跟"信息有没有统一入口"关系很大。

还有一层容易被忽略:Taiga 支持私有项目、支持给外部协作方开受限账号,这意味着你可以把客户拉进来只看某一个项目,而不必把整个组织暴露出去。做外包或者对接甲方的团队,这一点特别实用。

1.2 三种部署路线的横向对比

动手之前先选路线,这一步选错,后面全是返工。我实际用过的三种方式,各自的适用面差别挺大。

部署方式上手难度升级成本定制能力适合谁
官方 Docker Compose 编排低低(换镜像 tag 重启)中等,改环境变量为主绝大多数自建场景,首选
源码手动部署高高(要重新编译、跑迁移)高,能直接改代码需要深度二开、改前端逻辑
容器编排平台(K8s 一类)很高中等高多实例、有专职运维的团队

我一般推荐先走 Docker Compose。原因很直接:Taiga 的组件太多,手动装一遍,光是 Python 依赖、Node 版本、PostgreSQL 扩展这几样就能耗掉半天,而且升级时容易漏掉某一步迁移。官方编排把这些都固化了,你只需要维护一份.env,出问题直接看容器日志,定位范围小很多。

源码部署不是不能做,我自己也做过一次,是因为要给前端加一个内部的水印组件。如果你的需求里没有"改代码"这一条,真的没必要受那个罪。至于 K8s,除非你们团队已经有现成的集群和 CI/CD 流水线,否则为了一个十几人用的项目管理工具上 K8s,运维成本远大于收益。

1.3 组件构成:一台机器上跑着什么

把编排文件拉下来之后,你会看到一串服务名,这里逐个交代清楚它们是干嘛的,后面排查问题全靠这张地图。

  • taiga-back:Django 后端,所有 REST API 都由它提供,端口 8000,对外不直接暴露,只给网关转发。
  • taiga-front:前端静态资源,本质是一个 Nginx 容器,里面装着编译好的 SPA,端口 80。
  • taiga-async:Celery worker,处理发邮件、生成导出文件、计算统计这类耗时任务,它不监听端口,只从队列里取活。
  • taiga-events:Node 写的 WebSocket 服务,负责"别人改了卡片,你这边实时刷新",端口 8888。
  • taiga-db:PostgreSQL,所有业务数据在这里。
  • taiga-rabbitmq:消息队列,给 Celery 传任务。
  • taiga-gateway:Nginx 反向代理,把/api、/events、/admin、静态资源按路径分发到对应容器,这是唯一对外的入口。

理解这套关系的关键在于:前端和后端是分开的两个容器,它们之间靠网关按 URL 前缀转发来通信。所以你在浏览器里看到的域名只有一个,但背后是四五个服务在接力。很多"登录成功但接口 404"的问题,根源都是网关的路径规则没对上。

2. 部署前的环境规划与资源预算

我见过太多人一上来就docker compose up,跑起来能用,过两个月磁盘满了、备份没有、升级卡住,最后推倒重来。部署这件事,前面花的规划时间会以十倍返还给你。这一章讲的是开跑之前必须定下来的几件事:机器多大、端口怎么分、数据放哪、域名怎么接。

2.1 机器规格与端口规划

先给数字。我的经验值是:3 到 15 人的团队,2 核 4G 内存、40G 系统盘足够跑起来;但如果团队活跃度高、附件传得多,内存建议直接上 8G,因为 PostgreSQL 加上几个 Python 进程和 Node 进程,4G 会经常在边缘试探,一到大附件上传或者生成报表就容易 OOM。磁盘方面,系统盘给 30G 装系统和镜像,另外挂一块数据盘专门放数据库和附件,这样将来扩容或者迁移会轻松很多。

操作系统我一般选主流的 Linux 发行版长期支持版本,内核 5.x 以上,Docker Engine 20.10 以上配合 Compose V2。检查版本这步别省:

docker --version docker compose version uname -r free -h df -h

端口规划上,原则是只暴露一个入口,其余全部走容器内部网络。下面这张表是我常用的分配:

端口用途是否对外
80 / 443网关入口,HTTP/HTTPS是
8000后端 API否,仅容器内
8888WebSocket 事件服务否,经网关转发
5432PostgreSQL否,强烈建议不映射到宿主机
5672RabbitMQ否
6379Redis(如果启用)否

数据库端口千万不要图省事映射到公网。Taiga 的数据库里存着全部业务数据,一旦被扫到弱口令,损失是灾难性的。需要连数据库调试的时候,用 SSH 隧道或者docker exec进去,别开公网口子。

还有一个容易忘的点:文件描述符限制。WebSocket 长连接和数据库连接都比较吃 fd,建议在宿主机把nofile调到 65535,否则并发一上来就会出现莫名其妙的连接被拒。

2.2 目录结构与数据持久化设计

容器是无状态的,所有有价值的东西都在卷里。我习惯在数据盘上建一个固定目录,把数据库、附件、配置分开放:

mkdir -p /data/taiga/{db,media,static,backup,conf} chown -R 1000:1000 /data/taiga/media

db放 PostgreSQL 数据目录,media放用户上传的附件和头像,static放收集起来的静态文件,backup放备份产物。目录建好之后,在编排文件里把这些宿主机路径挂进对应容器。

这里有个坑我踩过不止一次:media 目录的属主必须是容器内运行用户(通常是 uid 1000)。如果目录是 root 建的、权限 755,容器里的应用进程写不进去,表现就是"上传附件转圈然后失败",日志里一行PermissionError埋在几千行输出里。所以建目录的时候顺手chown,能省掉后面半小时的排查。

持久化清单我一般列成这样,部署完对一遍:

  • PostgreSQL 数据目录(最重要,丢了就是全部项目数据)
  • media 附件目录(丢了是全部上传文件)
  • .env配置文件(丢了要重新对一遍所有参数)
  • 网关的证书和自定义配置(丢了要重新申请证书)

静态文件其实可以不持久化,重新收集一次就行,但留着能加快重启速度,看个人习惯。

2.3 域名、证书与网络层的前置准备

如果只是内网用,直接 IP 加端口访问就行,省掉证书这一整套。但只要涉及公网访问,我强烈建议上域名加 HTTPS,原因有两个:一是 WebSocket 在 HTTPS 页面下必须用wss://,混合内容会被浏览器直接拦掉,实时通知就废了;二是登录用的会话 Cookie 在非 HTTPS 下传得不踏实。

准备工作很简单:把域名的 A 记录指到服务器 IP,等解析生效,然后确认 80 和 443 端口在防火墙上是放行的。如果服务器前面还有一层云厂商的负载均衡或者安全组,记得把这些端口也放开,别只改了系统防火墙。

证书我一般用 Let's Encrypt 的自动化工具签,续期脚本挂到定时任务里。这里提醒一句:签证书的时候 80 端口必须是通的,因为校验要走 HTTP-01。如果你打算一开始就把 80 关掉只留 443,那得用 DNS 方式校验,配置会麻烦一些。我的做法是先让 80 通着把证书签下来,签完再决定要不要重定向。

还有个小细节:Taiga 的站点地址配置(后面.env里的TAIGA_SITES_DOMAIN和TAIGA_SITES_SCHEME)会写进前端配置和邮件链接里。这个值一旦定下来就别随便改,改了之后已发出的邮件链接会全部指向旧地址,用户点开就是 404。上线前想清楚,是https://pm.example.com还是带端口的内部地址。

3. Docker Compose 方式落地实操

这一章是全文最"可抄"的部分。我会按真实操作顺序走一遍,中间穿插参数解释和当场遇到的问题。你照着做,正常情况下四十分钟内能拿到一个可登录的实例。

3.1 获取编排文件与目录初始化

先建工作目录,把官方编排仓库拉下来。我不建议直接在生产目录里改官方文件,习惯是复制一份出来做本地化修改:

mkdir -p /opt/taiga && cd /opt/taiga git clone https://github.com/kaleidos-ventures/taiga-docker.git cd taiga-docker cp .env.example .env

拉下来之后先别急着启动,把docker-compose.yml和.env通读一遍。这一步很多人跳过,结果后面出问题完全不知道某个变量是从哪来的。重点看三处:各服务的volumes映射(确保持久化目录对得上)、gateway的端口映射(默认可能是 9000,改成 80/443)、以及depends_on的启动顺序。

把前面规划好的数据目录挂进去,改完大概是这个样子(片段示意):

services: taiga-db: volumes: - /data/taiga/db:/var/lib/postgresql/data taiga-back: volumes: - /data/taiga/media:/taiga-back/media - /data/taiga/static:/taiga-back/static

改完记得检查目录权限,前面说过的chown 1000:1000别忘。

3.2 .env 配置文件逐项拆解

.env是整个部署的中枢,我按重要性逐项说。

必改项,不改就跑不起来或者不安全:

  • TAIGA_SECRET_KEY:Django 的签名密钥,绝对不能留默认值。生成方式是openssl rand -hex 32,生成一串扔进去。这个值泄露等于会话可以被伪造,务必当密码对待。
  • POSTGRES_PASSWORD和TAIGA_DB_PASSWORD:数据库密码,建议也用随机串,两者保持一致。
  • RABBITMQ_PASS:消息队列密码,同样随机化。
  • TAIGA_SITES_DOMAIN:你的访问域名,比如pm.example.com;带端口的话写pm.example.com:8080。
  • TAIGA_SITES_SCHEME:https或http,跟实际访问协议一致。

功能开关,按需调整:

  • PUBLIC_REGISTER_ENABLED:是否允许陌生人自助注册。公网实例我一般设成False,账号由管理员在后台建,避免被爬虫刷注册。
  • ENABLE_ALIASES:是否允许用用户名别名登录,小团队开着方便,大组织建议关掉以免重名混乱。
  • TAIGA_ENABLE_EMAIL:邮件通知总开关,配合下面的 SMTP 参数用。

邮件相关(不发邮件可以整段跳过):

TAIGA_ENABLE_EMAIL=True EMAIL_HOST=smtp.example.com EMAIL_PORT=587 EMAIL_HOST_USER=notify@example.com EMAIL_HOST_PASSWORD=你的授权码 EMAIL_USE_TLS=True EMAIL_DEFAULT_FROM=notify@example.com

注意:不少邮件服务商要求用"授权码"而不是登录密码,填错了表现是异步任务日志里反复出现认证失败,但前端界面毫无提示,很容易误判成"邮件功能坏了"。

配置完核对一遍,我习惯用grep -v '^#' .env | grep -v '^$'把有效行打出来,扫一眼有没有漏改的默认值。

3.3 启动、初始化管理员与首次访问验证

启动分两步走,先起数据库和队列,再起应用,比一把梭稳:

docker compose up -d taiga-db taiga-rabbitmq docker compose ps # 等 db 状态变成 healthy docker compose up -d

第一次启动会拉镜像、跑数据库迁移,时间取决于网络,五到十分钟正常。期间用docker compose logs -f taiga-back盯着,看到Starting gunicorn之类的字样就说明后端起来了。

接着初始化管理员账号:

docker compose run --rm taiga-back python manage.py createsuperuser

按提示输入用户名、邮箱、密码。这里有个细节:用户名不要用纯数字或者带特殊符号,历史版本对这类用户名的 URL 处理有过问题,用字母加下划线最稳。

然后验证。浏览器打开http://你的地址,能看到登录页就成功了。登录后依次检查四件事:新建一个项目、创建一个用户故事、拖到看板上、刷新页面看状态有没有保住。这四步过了,说明数据库读写、前端路由、API 通信都是通的。

再做一次反向验证:故意重启一次docker compose restart,重新登录看数据还在不在。这一步是验证持久化卷挂对了没有,很多人跳过,等到服务器重启才发现数据全没了。

3.4 反向代理与 HTTPS 的收尾工作

如果你用的是编排里自带的网关容器,它本身已经做了路径分发,只需要在前面再套一层宿主机的 Nginx 处理证书和域名,把请求转发到网关端口即可:

server { listen 443 ssl http2; server_name pm.example.com; ssl_certificate /etc/letsencrypt/live/pm.example.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/pm.example.com/privkey.pem; client_max_body_size 50m; location / { proxy_pass http://127.0.0.1:9000; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } location /events { proxy_pass http://127.0.0.1:9000; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_read_timeout 3600s; } }

两个参数值得单独解释。client_max_body_size默认只有 1M,超过就返回 413,表现是"附件传不上去但小文件可以"——这个坑我踩过,排查了半小时才发现是 Nginx 拦的。/events那个 location 里的Upgrade头是 WebSocket 必需的,漏了的话实时通知完全不工作,而且浏览器控制台只会给你一行不太明显的报错。

配置写完nginx -t验证语法,再 reload。然后回到浏览器,用 HTTPS 地址登录,打开两个窗口分别改同一张卡片,看另一个窗口会不会自动更新。会,就说明wss通了。

4. 源码部署方式:适合需要二次开发的场景

Docker 方案覆盖九成需求,但总有那么一成的场景绕不过去——比如要给前端加个内部标识、要把登录接到自建的身份系统、要改某个 API 的返回结构。这时候容器方案就得自己打镜像,反而不如直接源码跑来得痛快。这一章讲清楚源码路线的关键步骤,只讲跟容器方案不一样的地方。

4.1 后端环境与依赖安装

后端是 Python 项目,对版本有要求,太新的 Python 可能有依赖不兼容,我一般用 3.10 或 3.11。用虚拟环境隔离:

python3 -m venv /opt/taiga/venv source /opt/taiga/venv/bin/activate git clone https://github.com/kaleidos-ventures/taiga-back.git cd taiga-back pip install -U pip wheel pip install -r requirements.txt

依赖里有一个容易被忽略的:PDF 导出用的渲染引擎依赖一堆系统库(字体、图形库)。如果系统是最小化安装,pip install不会报错,但真正导出 PDF 的时候会抛异常。解决办法是提前把这些系统包装上,各发行版的包名不同,按官方文档列的那几个装就行。

数据库准备:

sudo -u postgres createuser taiga sudo -u postgres createdb taiga -O taiga

然后复制settings/local.py.example为settings/local.py,改数据库连接、密钥、站点地址。接着跑迁移和收集静态文件:

python manage.py migrate --noinput python manage.py collectstatic --noinput python manage.py createsuperuser

一个实操提醒:local.py里的SITES配置决定了邮件里生成的链接,跟容器方案里的TAIGA_SITES_DOMAIN是一个东西,务必跟实际访问地址一致。我第一次做源码部署时这里填了localhost:8000,结果所有通知邮件里的链接都指向本机,同事点开全是打不开的页面。

4.2 前端编译与 conf.json 的关键项

前端是 Angular 项目,需要 Node 环境(版本看仓库的.nvmrc或package.json里的 engines 字段,别硬用最新版)。流程是:

git clone https://github.com/kaleidos-ventures/taiga-front-dist.git cd taiga-front-dist # 把编译产物放进去,或者自己编译

自己编译的话进taiga-front仓库,装依赖、跑构建,产物会输出到dist。编译完最关键的一步是改dist/conf.json,这个文件是运行时配置,前端启动时读它决定去哪儿找后端:

{ "api": "https://pm.example.com/api/v1/", "eventsUrl": "wss://pm.example.com/events", "eventsSocketUrl": "wss://pm.example.com/events", "defaultLanguage": "zh", "theme": "taiga" }

四个字段的含义:api是后端地址,注意结尾带不带斜杠有讲究,跟你的网关规则对齐;eventsUrl和eventsSocketUrl是实时通知地址,必须是wss://才能在被 HTTPS 包裹的页面里工作;defaultLanguage设成zh可以让新用户默认中文界面。

提示:很多人改完conf.json发现没生效,是因为浏览器缓存了旧文件。前端静态资源一般带强缓存,改完配置要么清缓存,要么在文件名上加版本号,要么把 HTML 设成不缓存。我一般直接在网关层给conf.json单独加一条不缓存的规则。

4.3 进程管理与 systemd 托管

源码跑起来之后,得让它常驻。后端用 gunicorn,事件服务用 node,异步任务用 celery,三个进程都要托管。我习惯用 systemd,写三个 unit 文件,以其中一个为例:

[Unit] Description=Taiga Backend After=network.target postgresql.service rabbitmq-server.service [Service] User=taiga WorkingDirectory=/opt/taiga/taiga-back Environment="PATH=/opt/taiga/venv/bin" ExecStart=/opt/taiga/venv/bin/gunicorn -w 4 -b 127.0.0.1:8000 taiga.wsgi Restart=always RestartSec=5 [Install] WantedBy=multi-user.target

几个参数值得说:-w 4是 worker 数,经验公式是 CPU 核数乘 2 再加 1,但项目管理这种 IO 偏多的场景,4 个就够,开太多反而抢内存;Restart=always保证挂了自动拉起来;RestartSec=5防止疯狂重启刷日志。

事件服务和异步任务的 unit 大同小异,注意异步任务的启动命令要指定队列名,跟后端配置里的队列名对上,对不上就会出现"任务提交了但永远不执行"的诡异现象。

三个服务都systemctl enable --now之后,systemctl status逐个确认是 active (running),再看日志有没有报错。源码方案的好处在这里体现出来了:日志就在你手边,改一行代码重启一下服务就生效,不用重新打镜像。

5. 部署后高频问题排查实录

前面三章讲的是"怎么跑起来",这一章讲"跑起来之后为什么又出问题"。我把这两年遇到的、以及帮别人看过的问题整理了一遍,按现象归类,每个都给出定位路径和解决办法。这一章的价值可能比前面加起来都高,因为部署本身是一次性的,排查是长期的。

5.1 页面能打开但接口全部 502

这是最高频的一类。现象是登录页正常显示(说明前端容器活着),但一提交登录就转圈然后报错。定位顺序是固定的:

先看后端容器活没活:docker compose ps taiga-back,状态是restarting或者exited就说明它在崩溃循环。再看日志docker compose logs --tail=100 taiga-back,常见的三种错:

第一种是数据库连不上,日志里出现could not connect to server。原因通常是数据库还没初始化完,后端就急着重启了。解决办法是等数据库 healthy 再起后端,或者给后端加重试。我一般直接docker compose restart taiga-back,因为数据库这会儿已经好了,重启一次就接上。

第二种是数据库密码不匹配。日志里是password authentication failed。这种情况多半是.env里的TAIGA_DB_PASSWORD和POSTGRES_PASSWORD不一致,或者数据库卷是旧的、里面还是老密码。后者比较麻烦,要么改回旧密码,要么进数据库改密码,要么(数据可丢的情况下)清空数据卷重来。

第三种是迁移没跑。日志里是relation "xxx" does not exist。手动跑一次docker compose run --rm taiga-back python manage.py migrate --noinput就好。

如果后端日志一切正常但接口还是 502,问题就在网关。检查网关容器的 upstream 配置里写的主机名对不对——容器间通信用服务名,不是localhost。我见过有人把网关配置里的taiga-back:8000改成了127.0.0.1:8000,在容器里这个地址指向网关自己,当然连不上。

5.2 实时通知不刷新,非得手动刷新页面

现象是别人改了卡片,你这边毫无反应,F5 之后才看到最新状态。这个问题几乎 100% 出在 WebSocket 链路上,按下面的顺序查:

第一步,浏览器 F12 打开网络面板,筛 WS,看有没有一条到/events的连接。没有连接,说明前端配置里的eventsUrl错了,或者协议写成了ws://而页面是 HTTPS,被浏览器拦了。有连接但状态是 101 之外的(比如 502、404),说明网关没转发对。

第二步,检查网关对/events路径的转发配置。前面写过,必须有Upgrade和Connection两个头,缺一不可。有些教程只写了Upgrade漏了Connection,效果是一样的——不工作。

第三步,检查事件服务容器本身。docker compose logs taiga-events,如果里面有连 RabbitMQ 失败的日志,说明队列连接参数不对,事件服务起不来,自然没有推送。

还有一种隐蔽情况:事件服务正常,网关也正常,但公司网络出口的代理设备会掐掉长连接。这种只能通过换网络环境验证,或者退而求其次,把前端的轮询间隔调短一点当兜底。

5.3 附件上传失败,小文件可以大文件不行

分界线通常出现在 1M 或者 10M,这个数字就是线索。1M 是 Nginx 的client_max_body_size默认值,10M 可能是应用层或者云负载均衡的限制。逐层排查:

  • 宿主机 Nginx:改client_max_body_size 50m;并 reload。
  • 容器内网关:编排文件里如果有 nginx 配置,同样要改。
  • 云厂商负载均衡:控制台上找请求体大小限制,一般也能调。
  • 应用层:Taiga 后端有自己的上传大小限制,在local.py或环境变量里,按需调整。

如果大小没问题但还是失败,去查 media 目录的权限。前面强调过chown 1000:1000,容器里的进程以非 root 用户跑,写不进 root 属主的目录。表现是日志里一行Permission denied: '/taiga-back/media/...',前端只给你一个笼统的失败提示。

5.4 邮件通知发不出去,界面毫无提示

邮件是异步任务,所以失败不会在前端报错,只会静默丢进日志。定位入口是异步 worker 的日志:

docker compose logs --tail=200 taiga-async

看到SMTPAuthenticationError就是账号密码问题,多半是用了登录密码而不是授权码;看到ConnectionRefusedError是端口或地址不通,注意 25 端口在很多云环境是被封的,用 587 加 STARTTLS 更稳;看到Timeout就查网络策略,容器能不能出网。

还有一个非常容易忽略的点:发件人地址必须跟认证账号一致,不一致会被服务商拒掉。另外,邮件里的链接地址取的是站点配置,如果站点配置还是默认的localhost,收件人点开就是打不开的页面——这不算发送失败,但用户体验上等同于失败。

5.5 常见问题速查表

把上面这些和另外几个小问题汇总成表,出问题先扫一眼,能省不少时间。

现象最可能的原因快速验证处理方式
页面 502后端崩溃或未就绪docker compose ps看日志、重启后端
登录后立刻退出密钥变更导致会话失效检查 SECRET_KEY 是否改过改回或重新登录
附件上传 413网关请求体限制看 Nginx 错误日志调大 client_max_body_size
附件上传 500media 目录无写权限看后端日志 Permission deniedchown 到容器用户
实时通知不工作WebSocket 未转发F12 看 WS 连接补 Upgrade 头、改 wss
邮件不发送SMTP 认证或端口被封看 async 日志换授权码、换 587 端口
中文导出乱码容器内缺中文字体导出 PDF 看效果装字体后重启
时区显示错误容器默认 UTC看创建时间设置时区环境变量
磁盘持续增长日志未轮转、备份堆积du -sh逐目录看配日志轮转、清理旧备份

注意:改任何配置之后,记得docker compose up -d让变更生效,只改文件不重启是最常见的"改了没用"原因。有些变量是容器启动时读取的,热改不生效。

6. 备份、升级与长期维护

部署完成只是开始,真正决定这套东西能不能用两年的,是备份和升级这两件事做得好不好。我见过团队用得很顺,结果一次升级失败把所有项目数据锁死在里面,最后靠三天前的备份恢复,丢了一周的迭代记录。这一章讲的就是怎么避免这种事。

6.1 数据库与媒体文件的备份脚本

备份的核心原则:数据库和附件必须成对备份。只备数据库,恢复出来的项目里所有附件都是红叉;只备附件,数据库里没有对应的记录,文件就是一堆孤儿。

数据库用pg_dump,走容器执行,不用在宿主机装客户端:

#!/bin/bash set -e DATE=$(date +%Y%m%d_%H%M%S) BACKUP_DIR=/data/taiga/backup mkdir -p "$BACKUP_DIR" docker compose exec -T taiga-db \ pg_dump -U taiga -d taiga --no-owner --clean \ | gzip > "$BACKUP_DIR/taiga_db_$DATE.sql.gz" tar -czf "$BACKUP_DIR/taiga_media_$DATE.tar.gz" -C /data/taiga media find "$BACKUP_DIR" -name "taiga_*" -mtime +14 -delete

几个设计考虑:--clean让备份文件里带上 drop 语句,恢复时不用手动清库;-T关掉伪终端,不然在 cron 里跑会报错;find -mtime +14 -delete做保留策略,不然备份目录迟早撑爆磁盘。

挂到 crontab 里每天凌晨跑一次,并且定期做恢复演练。没演练过的备份等于没有备份,这话不好听但是真的。演练方式很简单:起一个临时容器,把备份灌进去,看能不能正常启动、数据对不对。

6.2 版本升级的正确姿势

升级前必做三件事:完整备份、看一眼新版本的变更说明(尤其是数据库迁移和配置项变动)、确认当前版本号。升级本身的流程不复杂:

cd /opt/taiga/taiga-docker git pull # 对比 .env.example 有没有新增变量,有就补进 .env docker compose pull docker compose up -d docker compose run --rm taiga-back python manage.py migrate --noinput

关键在于第四步和第五步的顺序不能乱,镜像换新之后一定要跑迁移。有些版本会引入新的必填配置项,如果.env里没有,容器会起不来,日志里会明确告诉你缺哪个变量,照着补就行。

升级失败的典型场景是跨了多个大版本直接升。数据库结构的迁移是有顺序的,跳版本可能触发不可逆的变更。我的做法是小版本跟紧,大版本先在一个克隆环境里试一遍,确认没问题再动生产。

提示:升级前把旧的镜像 tag 记下来。出问题时能快速回滚到旧镜像(docker compose里把 image 固定成旧 tag),虽然数据库不一定能回退,但至少能先把服务恢复起来,给人留出处理时间。

6.3 日常该盯的几个指标

系统跑起来之后,不需要天天看,但有几项值得每周扫一眼:

磁盘使用率是第一位。附件和数据库增长是线性的,加上日志和备份,很容易在某个时间点突然满。设个告警阈值,80% 就该清理了。

容器重启次数是第二位。docker compose ps里如果某个服务的状态频繁变化,说明它在崩溃循环,可能是内存不足被 OOM killer 干掉,也可能是某个外部依赖不稳。这个指标比 CPU 更能反映健康度。

异步任务的积压是第三位。如果队列里堆了几千个任务没消费,说明 worker 挂了或者卡住了,表现是"操作都成功但邮件延迟几小时才到"。查法是看 worker 日志,或者直接看队列管理界面里的消息数。

最后是证书到期时间。自动续期虽然省事,但续期失败是静默的,等到过期那天全站报证书错误就晚了。我在监控里加了一条证书剩余天数的检查,低于 15 天就提醒。

这套东西我自己用了两年多,中间经历过一次磁盘写满、一次升级踩坑、一次邮件服务商改策略导致通知全挂。回过头看,真正省事的不是部署时多顺利,而是备份能恢复、日志能定位、配置有记录。所以我现在养成了一个习惯:每次改完配置,把改动内容和原因写进一个CHANGELOG.md放在部署目录里。半年后你再回来看,会感谢当时那个多写两行的自己。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询