维护
自托管 rtCloud 实例的日常维护:升级、备份、恢复和常见问题故障排除。
常用命令
定期使用这些命令管理您的 rtCloud 容器。请在包含 docker-compose.production.yml 的目录中运行它们。
# 检查所有容器的状态和健康
docker compose -f docker-compose.production.yml ps
# 查看实时日志(所有服务)
docker compose -f docker-compose.production.yml logs -f
# 仅查看应用日志
docker compose -f docker-compose.production.yml logs -f rtcloud
# 重启单个容器
docker compose -f docker-compose.production.yml restart rtcloud
# 停止所有服务
docker compose -f docker-compose.production.yml down
# 启动所有服务
docker compose -f docker-compose.production.yml up -d
# 在应用容器内打开 shell
docker compose -f docker-compose.production.yml exec rtcloud bash
升级
rtCloud 更新以新的 Docker 镜像标签分发。升级会拉取最新镜像并重新创建应用容器。数据库迁移在启动时自动运行。
1. 拉取最新镜像:
docker compose -f docker-compose.production.yml pull
2. 重新创建应用容器:
docker compose -f docker-compose.production.yml up -d
Docker 仅替换镜像已更改的容器。MySQL 容器和所有命名卷不受影响。
固定版本
要升级到特定版本而不是 latest,请在 .env 中更新 RTCLOUD_IMAGE:
RTCLOUD_IMAGE=rtawebteam/rta-smartsurvey:1.2.3
然后按上述方式运行 docker compose pull 和 up -d。
降级
通常不建议降级,因为数据库迁移无法撤销。如果必须降级,请从升级前的数据库备份中恢复。
备份和恢复
备份数据库
运行此命令将应用数据库导出到 SQL 文件:
docker compose -f docker-compose.production.yml exec mysql \
mysqldump -u root -p"$(grep MYSQL_ROOT_PASSWORD .env | cut -d= -f2)" smartsurvey \
> backup-$(date +%Y%m%d-%H%M%S).sql
备份文件写入主机上的当前目录。
恢复数据库
docker compose -f docker-compose.production.yml exec -T mysql \
mysql -u root -p"$(grep MYSQL_ROOT_PASSWORD .env | cut -d= -f2)" smartsurvey \
< backup-20240101-120000.sql
备份上传的文件
调查提交通常包含存储在命名 Docker 卷中的上传文件(照片、音频、文档)。请单独备份,与数据库备份分开:
# 备份上传文件
docker run --rm \
-v rtcloud_uploads:/data \
-v "$(pwd):/backup" \
alpine tar czf /backup/uploads-$(date +%Y%m%d).tar.gz -C /data .
# 备份音频录音
docker run --rm \
-v rtcloud_audios:/data \
-v "$(pwd):/backup" \
alpine tar czf /backup/audios-$(date +%Y%m%d).tar.gz -C /data .
如果您更改了默认值,请将 rtcloud_uploads 和 rtcloud_audios 替换为实际卷名称(以 COMPOSE_PROJECT_NAME 为前缀)。
恢复上传的文件
docker run --rm \
-v rtcloud_uploads:/data \
-v "$(pwd):/backup" \
alpine tar xzf /backup/uploads-20240101.tar.gz -C /data
自动每日备份
在主机上添加 cron 任务以自动运行备份。使用 crontab -e 编辑 root crontab:
# 每天凌晨 2:00 进行数据库备份,保留 30 天历史
0 2 * * * cd /opt/rtcloud && docker compose -f docker-compose.production.yml exec -T mysql \
mysqldump -u root -p"$(grep MYSQL_ROOT_PASSWORD .env | cut -d= -f2)" smartsurvey \
> /backups/db-$(date +\%Y\%m\%d).sql && \
find /backups -name "db-*.sql" -mtime +30 -delete
故障排除
应用容器无法启动
检查容器日志中的错误消息:
docker compose -f docker-compose.production.yml logs rtcloud
常见原因:
.env中缺少或无效的环境变量- MySQL 尚未就绪(等待 60 秒后再次检查)
- 端口冲突——另一个进程已在使用
APP_PORT
MySQL 不健康
docker compose -f docker-compose.production.yml logs mysql
常见原因:
.env中未设置MYSQL_ROOT_PASSWORD- 数据卷损坏(罕见——使用
df -h检查磁盘空间)
MySQL 在首次启动时可能需要 30–60 秒才能初始化。在认定失败前请等待并再次检查。
端口已被占用
在 .env 中将 APP_PORT 或 SHINY_PORT 更改为空闲端口,然后重新创建容器:
docker compose -f docker-compose.production.yml up -d --force-recreate
查找主机上占用某端口的进程:
lsof -i :8080
400 CSRF 令牌无法验证
此错误出现在本地或反向代理环境中,请求来源与预期主机不匹配。仅在本地开发中禁用 CSRF 验证:
CSRF_VALIDATION_ENABLED=false
然后重启应用:
docker compose -f docker-compose.production.yml up -d --force-recreate rtcloud
不要在生产环境中禁用 CSRF 验证。如果此错误在生产中出现,请确保您的反向代理正确转发
Host和X-Forwarded-For头。
忘记管理员密码
直接在数据库中重置管理员密码。连接到 MySQL 容器并更新密码哈希:
第一步 — 生成新密码哈希。将 newpassword 替换为您期望的密码:
docker compose -f docker-compose.production.yml exec rtcloud php -r "
\$salt = trim(shell_exec(\"mysql -h mysql -u root -p\\\"\${MYSQL_ROOT_PASSWORD}\\\" \${MYSQL_DATABASE} -se \\\"SELECT salt FROM ss_user WHERE username='admin';\\\"\"));
echo md5(\$salt . 'newpassword') . PHP_EOL;
"
第二步 — 在数据库中更新哈希:
docker compose -f docker-compose.production.yml exec mysql \
mysql -u root -p"${MYSQL_ROOT_PASSWORD}" smartsurvey \
-e "UPDATE ss_user SET password='<hash_from_step_1>' WHERE username='admin';"
容器持续重启
检查健康检查是否失败:
docker compose -f docker-compose.production.yml ps
docker inspect rtcloud-app --format '{{json .State.Health}}'
应用健康检查调用 /health 端点。如果多次失败,请检查应用日志中的启动错误。
磁盘空间已满
找出占用空间的内容:
# 检查主机磁盘使用情况
df -h
# 检查 Docker 磁盘使用情况(镜像、容器、卷)
docker system df
# 删除未使用的镜像和已停止的容器(安全执行)
docker system prune
不要使用 docker system prune --volumes,这会删除应用数据。
健康检查
每个服务都有自动健康检查。容器状态反映结果:
| 容器 | 检查方法 | 启动周期 | 间隔 |
|---|---|---|---|
rtcloud-app | HTTP GET /health | 90 秒 | 30 秒 |
rtcloud-mysql | mysqladmin ping | 30 秒 | 10 秒 |
rtcloud-keycloak | HTTP GET :9000/health/live | 120 秒 | 30 秒 |
健康检查失败的容器根据 RESTART_POLICY 设置(默认:unless-stopped)自动重启。