# QGIS Docker 部署指南 QGIS 专题图产出通过 Docker 容器执行,主进程(Python 3.10)通过 `docker exec` 调用容器内的 QGIS 环境。 ## 1. 环境要求 - Docker(Windows: Docker Desktop;Linux: docker-ce) - 项目代码已部署到服务器 - 输出文件目录已创建 ## 2. 拉取 QGIS 镜像 ```bash # 官方 QGIS 镜像(含 QGIS 3.x + Python + Qt5) docker pull qgis/qgis:3.44.11 # 验证 docker run --rm qgis/qgis:3.44.11 qgis --version ``` ### 无外网环境(离线导入) ```bash # 在有网的机器上导出 docker save qgis/qgis:3.44.11 -o qgis-34411.tar # 传输到目标服务器后导入 docker load -i qgis-34411.tar ``` ## 3. 启动 QGIS 容器 ```bash # ---- Linux / macOS ---- PROJECT_ROOT=/home/xian/xian_algorithm_new FILE_STORE=/data docker run -d \ --name qgis-server \ --restart unless-stopped \ -v "${PROJECT_ROOT}:/app:ro" \ -v "${FILE_STORE}:${FILE_STORE}" \ qgis/qgis:3.44.11 \ sleep infinity # ---- Windows (cmd.exe) ---- # 注意:Windows 路径必须用正斜杠 /,不能用反斜杠 \ # 挂载目标必须是 Linux 路径(容器是 Linux) docker run -d ^ --name qgis-server ^ --restart unless-stopped ^ -v "F:/project/xian/xian_algorithm_new:/app:ro" ^ -v "G:/files:/files" ^ qgis/qgis:3.44.11 ^ sleep infinity ``` ### 参数说明 | 参数 | 说明 | |------|------| | `--name qgis-server` | 容器名称,需与 `settings.toml` 中 `QGIS_DOCKER_CONTAINER` 一致 | | `-v 项目代码:/app:ro` | 项目代码只读挂载,容器内路径由 `QGIS_DOCKER_PROJECT_DIR` 配置 | | `-v 输出目录:输出目录` | 文件输出目录读写挂载,保持主机与容器路径一致 | | `sleep infinity` | 保持容器运行,等待 `docker exec` 调用 | ## 4. 安装中文字体(手动) QGIS 模板使用了 SimHei(黑体)、SimSun(宋体)、Microsoft YaHei(微软雅黑)等 Windows 中文字体, Docker 镜像默认不包含这些字体,会导致中文全部乱码。**字体需手动安装,代码不会自动安装。** ### 步骤 ```bash # 1. 创建字体目录 docker exec qgis-server mkdir -p /usr/share/fonts/truetype/winfonts # 2. 从主机复制 Windows 中文字体 # Windows 路径(根据实际字体文件位置调整): docker cp "C:\Windows\Fonts\simhei.ttf" qgis-server:/usr/share/fonts/truetype/winfonts/ docker cp "C:\Windows\Fonts\simsun.ttc" qgis-server:/usr/share/fonts/truetype/winfonts/ docker cp "C:\Windows\Fonts\msyh.ttc" qgis-server:/usr/share/fonts/truetype/winfonts/ docker cp "C:\Windows\Fonts\msyhbd.ttc" qgis-server:/usr/share/fonts/truetype/winfonts/ # Linux 字体路径示例: # docker cp /usr/share/fonts/truetype/droid/DroidSansFallbackFull.ttf qgis-server:/usr/share/fonts/truetype/winfonts/ # 3. 刷新字体缓存 docker exec qgis-server fc-cache -fv # 4. 验证字体已识别 docker exec qgis-server python3 -c " from PyQt5.QtGui import QFontDatabase db = QFontDatabase() zh = [f for f in db.families() if 'SimHei' in f or 'YaHei' in f or 'SimSun' in f] print('中文字体:', zh) " ``` ### 持久化方案 容器重建后字体丢失。可选方案: **方案 A:挂载单个字体文件** ```bash docker run -d ... \ -v "C:\Windows\Fonts\simhei.ttf:/usr/share/fonts/truetype/winfonts/simhei.ttf" \ -v "C:\Windows\Fonts\simsun.ttc:/usr/share/fonts/truetype/winfonts/simsun.ttc" \ ... ``` **方案 B:挂载整个字体目录(推荐)** ```bash # 先在主机创建字体目录,放入所需字体文件 mkdir -p /opt/qgis-fonts cp /usr/share/fonts/truetype/droid/DroidSansFallbackFull.ttf /opt/qgis-fonts/ docker run -d ... \ -v "/opt/qgis-fonts:/usr/share/fonts/truetype/winfonts:ro" \ ... ``` ## 5. 验证容器 ```bash # 检查容器状态 docker ps # 测试 QGIS 可用性 docker exec qgis-server python3 -c "from qgis.core import QgsApplication; print('OK')" # 查看容器内项目代码 docker exec qgis-server ls /app/app/services/qgis/ ``` ## 6. 配置文件 所有 Docker 相关配置集中在 `settings.toml` 的 `[default]` 段: ```toml [default] # ---- Docker QGIS 配置 ---- QGIS_DOCKER_CONTAINER = "qgis-server" # 容器名称(需与 docker run --name 一致) QGIS_DOCKER_PROJECT_DIR = "/app" # 容器内项目代码挂载路径 QGIS_DOCKER_PYTHON = "/usr/bin/python3" # 容器内 Python 解释器路径 QGIS_DOCKER_IMAGE = "qgis/qgis:3.44.11" # Docker 镜像名称 QGIS_DOCKER_PREFIX_PATH = "/usr" # QGIS prefixPath(安装根目录) QGIS_DOCKER_PYTHONPATH = [ # QGIS Python 包路径列表 "/usr/lib/python3/dist-packages", "/usr/lib/python3.10/dist-packages", "/usr/lib/python3.11/dist-packages", "/usr/lib/python3.12/dist-packages", ] QGIS_DOCKER_QT_PLATFORM = "offscreen" # Qt 无头模式 QGIS_DOCKER_KEEP_ALIVE = "sleep infinity" # 容器保活命令 # ---- 专题图参数 ---- QGIS_GPKG_DIR = "app/data/gpkg" # GPKG 目录(相对于项目根) QGIS_EXPORT_DPI = 200 # 导出 DPI QGIS_PARALLEL_WORKERS = 4 # 并行 docker exec 子进程数 QGIS_MAX_CONCURRENT = 2 # 最大并发请求数 # ---- 文件路径 ---- FILE_STORE_DIR = "G:/files" # 主机端文件输出目录 ``` ### 环境变量覆盖 ```bash export QGIS_DOCKER_CONTAINER="qgis-server" export QGIS_DOCKER_PROJECT_DIR="/app" export QGIS_DOCKER_PYTHON="/usr/bin/python3" ``` ### 跨机器适配 不同机器只需修改 `settings.toml` 中的路径配置: | 配置项 | 开发机 (Windows) | 生产机 (Linux) | |--------|-----------------|---------------| | `FILE_STORE_DIR` | `"G:/files"` | `"/data"` | | `DB_HOST` | `"47.92.216.173"` | `"10.22.245.138"` | | `DB_PORT` | `7654` | `54321` | ## 7. 目录结构 ``` 项目根目录/ ├── app/ │ ├── data/ │ │ ├── gpkg/ # 静态底图 GeoPackage 文件 │ │ └── template/ # 专题图模板 (.qgz) │ ├── services/qgis/ │ │ ├── qgis_env.py # Docker 环境配置(路径映射、命令构建) │ │ ├── qgis_runner.py # 容器内子进程入口 │ │ ├── map_service.py # 地图生成主流程 │ │ ├── template_modifier.py # 模板 XML 修改 │ │ └── map_exporter.py # 图片导出 │ └── api/ │ └── qgis_map_export.py # FastAPI 专题图导出接口 ├── config.py # Dynaconf 配置入口 ├── settings.toml # 全部配置 ├── requirements.txt # Python 依赖 ├── QGIS_DOCKER_README.md # 本文档 └── tmp/ # 临时文件目录(容器内映射为 /app/tmp/) ``` ## 8. 临时文件 - 主机端临时 JSON(批量产图配置):写入 `{项目根}/tmp/`,容器内可通过 `/app/tmp/` 访问 - 容器端临时 .qgz(修改后的模板):写入容器内 `/tmp/`,由 runner 自动清理 ## 9. 故障排查 ```bash # 容器未运行 docker ps -a | grep qgis-server # 查看容器日志 docker logs qgis-server # 手动测试 runner docker exec qgis-server python3 /app/app/services/qgis/qgis_runner.py --help # 检查 QGIS 依赖 docker exec qgis-server python3 -c " from qgis.core import QgsApplication QgsApplication.setPrefixPath('/usr', True) app = QgsApplication([], False) app.initQgis() print('QGIS', QgsApplication.version()) app.exitQgis() " # 检查中文字体 docker exec qgis-server python3 -c " from PyQt5.QtGui import QFontDatabase db = QFontDatabase() zh = [f for f in db.families() if any(k in f for k in ['SimHei','YaHei','SimSun','WenQuanYi'])] print('中文字体:', zh if zh else '未安装!') " # 检查 GPKG 文件 docker exec qgis-server ls /app/app/data/gpkg/ # 检查临时文件目录 docker exec qgis-server ls /app/tmp/ ``` ## 10. 工作流程 ``` 用户请求 POST /qgis/export/map → docker inspect 检查容器是否运行 → 查询推理结果 → 扫描模板文件夹 → 构建配置(路径映射到容器内路径) → 并行启动 docker exec 子进程 → 容器内 qgis_runner.py → 加载 QGIS Python 包 → 初始化 QgsApplication → 逐模板处理: → TemplateModifier 修改模板 XML(替换连接参数、静态层→GPKG) → project.read() 加载模板 → 图层过滤、缩放、文本更新 → 导出 JPG → 实时写入进度表 ```