- 从 900 行减少到 176 行(-80%)
- 从 8 个公开方法减少到 2 个(-75%)
- 删除了 20+ 个未使用的私有方法
- 删除了硬编码的目录列表
// 启动前调用(只设置 MySQL 配置文件权限)
directory_permission_manager.ensure_mysql_config_safe()?;
// 失败时调用(可选的修复逻辑)
directory_permission_manager.fix_mysql_permissions_on_failure()?;// 目录创建由 DockerManager 自动处理(从 docker-compose.yml 读取)
docker_manager.ensure_host_volumes_exist().await?;| 组件 | 职责 | 实现方式 |
|---|---|---|
| DockerManager | 自动检测 docker-compose.yml 并创建挂载目录 | ensure_host_volumes_exist() |
| DirectoryPermissionManager | 设置 MySQL 配置文件权限(644) | ensure_mysql_config_safe() |
| Docker init 容器 | 修改数据目录所有权(chown 999:999) | mysql-permission-fix 容器 |
-
目录创建自动化
DockerManager解析 docker-compose.yml- 自动检测所有 bind mount 的宿主机路径
- 自动创建不存在的目录
- 不需要硬编码目录列表 ✅
-
chown 需要 root 权限
- Rust 代码以普通用户运行,无法 chown
- Docker init 容器以 root 运行,可靠地执行 chown
-
配置文件不需要 chown
- MySQL 只需读取配置文件
- 保持当前用户所有权即可
- 只需确保权限是 644(MySQL 安全要求)
-
chmod 失败通常不影响
- WSL2/网络文件系统可能不支持标准权限
- Docker 有自己的权限映射机制
- 只要所有权正确,容器就能运行
// ❌ 这些调用在代码中全部被注释掉了
progressive_permission_management()
post_container_start_maintenance()
check_and_fix_mysql_config_permissions()
post_mysql_start_permission_check()
basic_permission_fix()// ❌ 这些功能试图处理所有边缘情况,但实际不需要
is_safe_to_clean_mysql_dir()
is_likely_user_data()
is_mysql_init_file()
safe_cleanup_mysql_init_files()
is_safe_init_directory()
fix_existing_mysql_permissions()
set_wsl2_permission() // 从未被调用
is_wsl2_windows_mount() // 从未被使用// 从 docker-compose.yml 自动检测挂载目录
docker_manager.ensure_host_volumes_exist().await?;
// 解析示例:
// volumes:
// - ./data/mysql:/var/lib/mysql
// - ./logs/mysql:/var/log/mysql
// - ./config/mysql.cnf:/etc/mysql/conf.d/mysql.cnf:ro
//
// 自动创建:
// - data/mysql/
// - logs/mysql/
// - config/ (mysql.cnf 的父目录)// 关键:MySQL 会拒绝 group-writable 或 world-writable 的配置文件
// 必须设置为 644
chmod 644 config/mysql.cnf// 只在 MySQL 启动失败时调用
// 设置最宽松权限(777)尝试修复
chmod 777 data/mysql/
chmod 644 config/mysql.cnf // 配置文件仍然保持 644mysql-permission-fix:
image: busybox:1.36-uclibc
volumes:
- ./data/mysql:/var/lib/mysql
- ./logs/mysql:/var/log/mysql
# 注意:不挂载配置文件
command: |
chown -R 999:999 /var/lib/mysql /var/log/mysql
chmod -R 755 /var/lib/mysql /var/log/mysql
restart: "no"
mysql:
depends_on:
mysql-permission-fix:
condition: service_completed_successfully
volumes:
- ./config/mysql.cnf:/etc/mysql/conf.d/mysql.cnf:ro # 只读挂载cargo run -- docker-service start
# 应该成功启动所有服务# 设置错误权限
chmod 777 config/mysql.cnf
# 启动服务
cargo run -- docker-service start
# 验证权限已修复
ls -la config/mysql.cnf
# 应该显示:-rw-r--r-- (644)# 检查字符集配置
docker exec mysql mysql -uroot -p -e "SHOW VARIABLES LIKE 'character_set%';"
# 应该看到 utf8mb4(说明配置文件生效)- ✅
docs/docker-volume-permissions.md- 详细的权限机制说明 - ✅
docs/mysql-config-permissions-quick-ref.md- 快速参考 - ✅
docs/permission-refactoring-summary.md- 重构对比 - ✅
docs/REFACTORING_COMPLETE.md- 本文档
如果遇到权限问题:
-
首先检查 Docker init 容器
docker-compose logs mysql-permission-fix
-
检查配置文件权限
ls -la config/mysql.cnf # 应该是 644 -
检查 MySQL 日志
docker logs mysql 2>&1 | grep -i "ignored\|permission"
问自己三个问题:
- 这个功能是否可以在 Docker init 容器中实现?
- 这个功能是否真的需要?(还是"以防万一")
- 是否有更简单的方式?
记住:
- 简单 > 复杂
- 可靠 > 完美
- 实用 > 理论
这次重构的核心思想:
不要试图在 Rust 代码中解决所有权限问题
- Rust:创建目录 + 设置配置文件权限(644)
- Docker:处理数据目录所有权(chown 999:999)
- 简单、可靠、易维护
结果:
- ✅ 代码减少 75%
- ✅ 复杂度大幅降低
- ✅ 更易理解和维护
- ✅ 功能完全保留
- ✅ 测试更容易
教训:
- ❌ 过度设计是技术债务
- ❌ "以防万一"的代码通常不需要
- ❌ 被注释掉的代码应该删除
- ✅ 简单的设计更可靠
- ✅ 职责分离很重要