Files
xian_algorithm_new/QGIS_DOCKER_README.md
T
2026-06-21 22:30:04 +08:00

271 lines
8.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# QGIS Docker 部署指南
QGIS 专题图产出通过 Docker 容器执行,主进程(Python 3.10)通过 `docker exec` 调用容器内的 QGIS 环境。
## 1. 环境要求
- DockerWindows: Docker DesktopLinux: 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
→ 实时写入进度表
```