271 lines
8.3 KiB
Markdown
271 lines
8.3 KiB
Markdown
|
|
# 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
|
|||
|
|
→ 实时写入进度表
|
|||
|
|
```
|