QGIS的docker管理
This commit is contained in:
+85
-9
@@ -66,7 +66,65 @@ docker run -d ^
|
|||||||
| `-v 输出目录:输出目录` | 文件输出目录读写挂载,保持主机与容器路径一致 |
|
| `-v 输出目录:输出目录` | 文件输出目录读写挂载,保持主机与容器路径一致 |
|
||||||
| `sleep infinity` | 保持容器运行,等待 `docker exec` 调用 |
|
| `sleep infinity` | 保持容器运行,等待 `docker exec` 调用 |
|
||||||
|
|
||||||
## 4. 安装中文字体(手动)
|
## 4. 预拷贝静态数据到容器本地 FS(必须,性能关键)
|
||||||
|
|
||||||
|
WSL2 9P 文件系统随机读取极慢(GPKG 62MB 耗时 6-10s/模板,模板 ZIP 也慢),拷贝到容器内 `/data/` 后读取仅需 ~0.5s。
|
||||||
|
|
||||||
|
### 方式一:Python 脚本(推荐)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python app/script/copy_data_to_container.py
|
||||||
|
```
|
||||||
|
|
||||||
|
输出示例:
|
||||||
|
```
|
||||||
|
=== 预拷贝静态数据到容器 qgis-server ===
|
||||||
|
|
||||||
|
[GPKG] 主机目录: F:\project\xian\xian_algorithm_new\app\data\gpkg
|
||||||
|
文件数: 23, 总大小: 62.3 MB
|
||||||
|
容器目标: qgis-server:/data/gpkg
|
||||||
|
拷贝完成: 3.2s, 容器内 23 个文件
|
||||||
|
|
||||||
|
[模板] 主机目录: F:\project\xian\xian_algorithm_new\app\data\template
|
||||||
|
文件数: 34, 总大小: 45.1 MB
|
||||||
|
容器目标: qgis-server:/data/template
|
||||||
|
拷贝完成: 2.1s, 容器内 34 个文件
|
||||||
|
|
||||||
|
=== 总耗时: 5.4s ===
|
||||||
|
```
|
||||||
|
|
||||||
|
其他用法:
|
||||||
|
```bash
|
||||||
|
python app/script/copy_data_to_container.py --dry-run # 仅查看信息
|
||||||
|
python app/script/copy_data_to_container.py --only gpkg # 只拷贝 GPKG
|
||||||
|
python app/script/copy_data_to_container.py --only template # 只拷贝模板
|
||||||
|
```
|
||||||
|
|
||||||
|
### 方式二:手动 docker cp
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 清理旧文件
|
||||||
|
docker exec qgis-server rm -rf /data/gpkg /data/template
|
||||||
|
|
||||||
|
# 拷贝 GPKG
|
||||||
|
docker cp F:\project\xian\xian_algorithm_new\app\data\gpkg qgis-server:/data/gpkg
|
||||||
|
|
||||||
|
# 拷贝模板
|
||||||
|
docker cp F:\project\xian\xian_algorithm_new\app\data\template qgis-server:/data/template
|
||||||
|
|
||||||
|
# 验证
|
||||||
|
docker exec qgis-server ls -la /data/gpkg
|
||||||
|
docker exec qgis-server ls -la /data/template/rainfall
|
||||||
|
docker exec qgis-server ls -la /data/template/earthquake
|
||||||
|
```
|
||||||
|
|
||||||
|
### 何时需要重新执行
|
||||||
|
|
||||||
|
- GPKG 或模板文件有更新时
|
||||||
|
- 容器重建后(`/data` 目录丢失)
|
||||||
|
- 首次部署时
|
||||||
|
|
||||||
|
## 5. 安装中文字体(手动)
|
||||||
|
|
||||||
QGIS 模板使用了 SimHei(黑体)、SimSun(宋体)、Microsoft YaHei(微软雅黑)等 Windows 中文字体,
|
QGIS 模板使用了 SimHei(黑体)、SimSun(宋体)、Microsoft YaHei(微软雅黑)等 Windows 中文字体,
|
||||||
Docker 镜像默认不包含这些字体,会导致中文全部乱码。**字体需手动安装,代码不会自动安装。**
|
Docker 镜像默认不包含这些字体,会导致中文全部乱码。**字体需手动安装,代码不会自动安装。**
|
||||||
@@ -122,7 +180,7 @@ docker run -d ... \
|
|||||||
...
|
...
|
||||||
```
|
```
|
||||||
|
|
||||||
## 5. 验证容器
|
## 6. 验证容器
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# 检查容器状态
|
# 检查容器状态
|
||||||
@@ -135,7 +193,7 @@ docker exec qgis-server python3 -c "from qgis.core import QgsApplication; print(
|
|||||||
docker exec qgis-server ls /app/app/services/qgis/
|
docker exec qgis-server ls /app/app/services/qgis/
|
||||||
```
|
```
|
||||||
|
|
||||||
## 6. 配置文件
|
## 7. 配置文件
|
||||||
|
|
||||||
所有 Docker 相关配置集中在 `settings.toml` 的 `[default]` 段:
|
所有 Docker 相关配置集中在 `settings.toml` 的 `[default]` 段:
|
||||||
|
|
||||||
@@ -158,6 +216,8 @@ QGIS_DOCKER_KEEP_ALIVE = "sleep infinity" # 容器保活命令
|
|||||||
|
|
||||||
# ---- 专题图参数 ----
|
# ---- 专题图参数 ----
|
||||||
QGIS_GPKG_DIR = "app/data/gpkg" # GPKG 目录(相对于项目根)
|
QGIS_GPKG_DIR = "app/data/gpkg" # GPKG 目录(相对于项目根)
|
||||||
|
QGIS_DOCKER_GPKG_DIR = "/data/gpkg" # 容器内 GPKG 本地路径(预拷贝后读取)
|
||||||
|
QGIS_DOCKER_TEMPLATE_DIR = "/data/template" # 容器内模板本地路径(预拷贝后读取)
|
||||||
QGIS_EXPORT_DPI = 200 # 导出 DPI
|
QGIS_EXPORT_DPI = 200 # 导出 DPI
|
||||||
QGIS_PARALLEL_WORKERS = 4 # 并行 docker exec 子进程数
|
QGIS_PARALLEL_WORKERS = 4 # 并行 docker exec 子进程数
|
||||||
QGIS_MAX_CONCURRENT = 2 # 最大并发请求数
|
QGIS_MAX_CONCURRENT = 2 # 最大并发请求数
|
||||||
@@ -184,7 +244,7 @@ export QGIS_DOCKER_PYTHON="/usr/bin/python3"
|
|||||||
| `DB_HOST` | `"47.92.216.173"` | `"10.22.245.138"` |
|
| `DB_HOST` | `"47.92.216.173"` | `"10.22.245.138"` |
|
||||||
| `DB_PORT` | `7654` | `54321` |
|
| `DB_PORT` | `7654` | `54321` |
|
||||||
|
|
||||||
## 7. 目录结构
|
## 8. 目录结构
|
||||||
|
|
||||||
```
|
```
|
||||||
项目根目录/
|
项目根目录/
|
||||||
@@ -200,6 +260,8 @@ export QGIS_DOCKER_PYTHON="/usr/bin/python3"
|
|||||||
│ │ └── map_exporter.py # 图片导出
|
│ │ └── map_exporter.py # 图片导出
|
||||||
│ └── api/
|
│ └── api/
|
||||||
│ └── qgis_map_export.py # FastAPI 专题图导出接口
|
│ └── qgis_map_export.py # FastAPI 专题图导出接口
|
||||||
|
├── script/
|
||||||
|
│ └── copy_data_to_container.py # GPKG + 模板预拷贝脚本
|
||||||
├── config.py # Dynaconf 配置入口
|
├── config.py # Dynaconf 配置入口
|
||||||
├── settings.toml # 全部配置
|
├── settings.toml # 全部配置
|
||||||
├── requirements.txt # Python 依赖
|
├── requirements.txt # Python 依赖
|
||||||
@@ -207,12 +269,12 @@ export QGIS_DOCKER_PYTHON="/usr/bin/python3"
|
|||||||
└── tmp/ # 临时文件目录(容器内映射为 /app/tmp/)
|
└── tmp/ # 临时文件目录(容器内映射为 /app/tmp/)
|
||||||
```
|
```
|
||||||
|
|
||||||
## 8. 临时文件
|
## 9. 临时文件
|
||||||
|
|
||||||
- 主机端临时 JSON(批量产图配置):写入 `{项目根}/tmp/`,容器内可通过 `/app/tmp/` 访问
|
- 主机端临时 JSON(批量产图配置):写入 `{项目根}/tmp/`,容器内可通过 `/app/tmp/` 访问
|
||||||
- 容器端临时 .qgz(修改后的模板):写入容器内 `/tmp/`,由 runner 自动清理
|
- 容器端临时 .qgz(修改后的模板):写入容器内 `/tmp/`,由 runner 自动清理
|
||||||
|
|
||||||
## 9. 故障排查
|
## 10. 故障排查
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# 容器未运行
|
# 容器未运行
|
||||||
@@ -242,14 +304,28 @@ zh = [f for f in db.families() if any(k in f for k in ['SimHei','YaHei','SimSun'
|
|||||||
print('中文字体:', zh if zh else '未安装!')
|
print('中文字体:', zh if zh else '未安装!')
|
||||||
"
|
"
|
||||||
|
|
||||||
# 检查 GPKG 文件
|
# 检查 GPKG 文件(容器本地路径,性能关键)
|
||||||
docker exec qgis-server ls /app/app/data/gpkg/
|
docker exec qgis-server ls /app/app/data/gpkg/ # 挂载路径(慢)
|
||||||
|
docker exec qgis-server ls /data/gpkg/ # 本地路径(快,需预拷贝)
|
||||||
|
|
||||||
|
# 检查模板文件(容器本地路径)
|
||||||
|
docker exec qgis-server ls /data/template/rainfall/ # 本地路径(快)
|
||||||
|
docker exec qgis-server ls /data/template/earthquake/
|
||||||
|
|
||||||
# 检查临时文件目录
|
# 检查临时文件目录
|
||||||
docker exec qgis-server ls /app/tmp/
|
docker exec qgis-server ls /app/tmp/
|
||||||
```
|
```
|
||||||
|
|
||||||
## 10. 工作流程
|
### 静态数据相关问题
|
||||||
|
|
||||||
|
| 问题 | 原因 | 解决 |
|
||||||
|
|------|------|------|
|
||||||
|
| 产图慢(>60s) | GPKG/模板从挂载目录读取(9P 慢) | 执行 `python app/script/copy_data_to_container.py` |
|
||||||
|
| 日志显示 `gpkg_dir=/app/...` | 未预拷贝或 `QGIS_DOCKER_GPKG_DIR` 为空 | 检查 settings.toml 配置 |
|
||||||
|
| 容器重建后变慢 | `/data` 目录丢失 | 重新执行拷贝脚本 |
|
||||||
|
| `docker cp` 权限错误 | 容器未运行 | `docker start qgis-server` |
|
||||||
|
|
||||||
|
## 11. 工作流程
|
||||||
|
|
||||||
```
|
```
|
||||||
用户请求 POST /qgis/export/map
|
用户请求 POST /qgis/export/map
|
||||||
|
|||||||
@@ -175,10 +175,15 @@ def _build_qgis_config(batch_folder: str) -> dict:
|
|||||||
is_docker = False
|
is_docker = False
|
||||||
|
|
||||||
if is_docker:
|
if is_docker:
|
||||||
# GPKG 目录:容器内路径 = 项目挂载目录 + GPKG 子目录
|
# GPKG 目录:优先使用容器内本地路径(预拷贝后绕过 WSL2 9P)
|
||||||
project_dir = get_docker_project_dir()
|
# 需先执行 python script/copy_gpkg_to_container.py
|
||||||
gpkg_subdir = getattr(settings, "QGIS_GPKG_DIR", "app/data/gpkg")
|
gpkg_dir = getattr(settings, "QGIS_DOCKER_GPKG_DIR", "") or ""
|
||||||
gpkg_dir = f"{project_dir}/{gpkg_subdir}"
|
if not gpkg_dir:
|
||||||
|
# fallback: 使用挂载路径(性能差)
|
||||||
|
project_dir = get_docker_project_dir()
|
||||||
|
gpkg_subdir = getattr(settings, "QGIS_GPKG_DIR", "app/data/gpkg")
|
||||||
|
gpkg_dir = f"{project_dir}/{gpkg_subdir}"
|
||||||
|
logger.warning(f"GPKG 将从挂载目录读取(慢),建议执行 copy_gpkg_to_container.py")
|
||||||
# batch_folder:主机路径 → 容器路径
|
# batch_folder:主机路径 → 容器路径
|
||||||
host_fs = get_host_file_store().rstrip("/")
|
host_fs = get_host_file_store().rstrip("/")
|
||||||
container_fs = get_container_file_store().rstrip("/")
|
container_fs = get_container_file_store().rstrip("/")
|
||||||
@@ -365,7 +370,7 @@ def _generate_batch_maps(models: list, config: dict, batch_key: str,
|
|||||||
import json, math, concurrent.futures, subprocess, tempfile, threading
|
import json, math, concurrent.futures, subprocess, tempfile, threading
|
||||||
from app.services.qgis.qgis_env import (
|
from app.services.qgis.qgis_env import (
|
||||||
get_docker_project_dir, get_container_python_path, build_docker_exec_cmd,
|
get_docker_project_dir, get_container_python_path, build_docker_exec_cmd,
|
||||||
map_host_to_container, map_container_to_host,
|
map_host_to_container, map_container_to_host, map_template_to_container,
|
||||||
)
|
)
|
||||||
|
|
||||||
max_workers = getattr(settings, "QGIS_PARALLEL_WORKERS", 4)
|
max_workers = getattr(settings, "QGIS_PARALLEL_WORKERS", 4)
|
||||||
@@ -397,9 +402,9 @@ def _generate_batch_maps(models: list, config: dict, batch_key: str,
|
|||||||
cm = dict(m)
|
cm = dict(m)
|
||||||
if "outFile" in cm:
|
if "outFile" in cm:
|
||||||
cm["outFile"] = map_host_to_container(cm["outFile"])
|
cm["outFile"] = map_host_to_container(cm["outFile"])
|
||||||
# 模板 path 也需要映射:Windows主机路径 → 容器内路径
|
# 模板 path 映射到容器本地路径(预拷贝后绕过 9P)
|
||||||
if "path" in cm:
|
if "path" in cm:
|
||||||
cm["path"] = map_host_to_container(cm["path"])
|
cm["path"] = map_template_to_container(cm["path"])
|
||||||
container_models.append(cm)
|
container_models.append(cm)
|
||||||
|
|
||||||
request = json.dumps({"config": config, "models": container_models}, ensure_ascii=False)
|
request = json.dumps({"config": config, "models": container_models}, ensure_ascii=False)
|
||||||
|
|||||||
@@ -0,0 +1,159 @@
|
|||||||
|
"""
|
||||||
|
将主机端 GPKG 和模板文件预拷贝到 Docker 容器本地文件系统。
|
||||||
|
|
||||||
|
WSL2 9P 文件系统随机读取极慢(GPKG 62MB 耗时 6-10s,模板 ZIP 也慢),
|
||||||
|
拷贝到容器内 /data/ 后读取仅需 ~0.5s。
|
||||||
|
|
||||||
|
用法:
|
||||||
|
python app/script/copy_data_to_container.py [--container qgis-server] [--dry-run] [--only gpkg|template]
|
||||||
|
|
||||||
|
前置条件:
|
||||||
|
Docker 容器已启动(docker start qgis-server)
|
||||||
|
"""
|
||||||
|
import argparse
|
||||||
|
import os
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
PROJECT_ROOT = Path(__file__).resolve().parent.parent.parent
|
||||||
|
|
||||||
|
|
||||||
|
def _load_config():
|
||||||
|
"""从 settings.toml 读取配置"""
|
||||||
|
try:
|
||||||
|
from config import settings
|
||||||
|
return {
|
||||||
|
"gpkg_subdir": getattr(settings, "QGIS_GPKG_DIR", "app/data/gpkg"),
|
||||||
|
"template_subdir": "app/data/template",
|
||||||
|
"container": getattr(settings, "QGIS_DOCKER_CONTAINER", "qgis-server"),
|
||||||
|
"container_gpkg": getattr(settings, "QGIS_DOCKER_GPKG_DIR", "/data/gpkg"),
|
||||||
|
"container_template": getattr(settings, "QGIS_DOCKER_TEMPLATE_DIR", "/data/template"),
|
||||||
|
}
|
||||||
|
except ImportError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# fallback: 解析 TOML
|
||||||
|
cfg = {
|
||||||
|
"gpkg_subdir": "app/data/gpkg",
|
||||||
|
"template_subdir": "app/data/template",
|
||||||
|
"container": "qgis-server",
|
||||||
|
"container_gpkg": "/data/gpkg",
|
||||||
|
"container_template": "/data/template",
|
||||||
|
}
|
||||||
|
toml_path = PROJECT_ROOT / "settings.toml"
|
||||||
|
if toml_path.exists():
|
||||||
|
for line in toml_path.read_text(encoding="utf-8").splitlines():
|
||||||
|
line = line.strip()
|
||||||
|
for key, prefix in [
|
||||||
|
("gpkg_subdir", "QGIS_GPKG_DIR"),
|
||||||
|
("container", "QGIS_DOCKER_CONTAINER"),
|
||||||
|
("container_gpkg", "QGIS_DOCKER_GPKG_DIR"),
|
||||||
|
("container_template", "QGIS_DOCKER_TEMPLATE_DIR"),
|
||||||
|
]:
|
||||||
|
if line.startswith(prefix) and "=" in line:
|
||||||
|
cfg[key] = line.split("=", 1)[1].strip().strip('"').strip("'")
|
||||||
|
return cfg
|
||||||
|
|
||||||
|
|
||||||
|
def _run(cmd, timeout=10, **kwargs):
|
||||||
|
"""subprocess.run 封装,统一 UTF-8 编码,避免 Windows GBK 报错"""
|
||||||
|
result = subprocess.run(
|
||||||
|
cmd, capture_output=True, timeout=timeout,
|
||||||
|
encoding="utf-8", errors="replace", **kwargs,
|
||||||
|
)
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def _check_container(container: str):
|
||||||
|
"""检查容器是否运行"""
|
||||||
|
result = _run(["docker", "inspect", "--format={{.State.Running}}", container], timeout=5)
|
||||||
|
if (result.stdout or "").strip() != "true":
|
||||||
|
raise RuntimeError(f"容器 {container} 未运行,请先 docker start {container}")
|
||||||
|
|
||||||
|
|
||||||
|
def _copy_dir_to_container(host_dir: Path, container: str, container_dest: str, label: str, dry_run: bool):
|
||||||
|
"""拷贝单个目录到容器"""
|
||||||
|
if not host_dir.is_dir():
|
||||||
|
print(f" [{label}] 目录不存在,跳过: {host_dir}")
|
||||||
|
return 0
|
||||||
|
|
||||||
|
files = list(host_dir.rglob("*"))
|
||||||
|
files = [f for f in files if f.is_file()]
|
||||||
|
if not files:
|
||||||
|
print(f" [{label}] 目录为空,跳过: {host_dir}")
|
||||||
|
return 0
|
||||||
|
|
||||||
|
total_size = sum(f.stat().st_size for f in files)
|
||||||
|
print(f" [{label}] 主机目录: {host_dir}")
|
||||||
|
print(f" 文件数: {len(files)}, 总大小: {total_size / 1024 / 1024:.1f} MB")
|
||||||
|
print(f" 容器目标: {container}:{container_dest}")
|
||||||
|
|
||||||
|
if dry_run:
|
||||||
|
print(f" [dry-run] 跳过")
|
||||||
|
return 0
|
||||||
|
|
||||||
|
# 确保目标目录存在
|
||||||
|
parent_dir = container_dest.rsplit("/", 1)[0]
|
||||||
|
_run(["docker", "exec", container, "mkdir", "-p", parent_dir])
|
||||||
|
|
||||||
|
# 清理旧目录
|
||||||
|
_run(["docker", "exec", container, "rm", "-rf", container_dest])
|
||||||
|
|
||||||
|
# docker cp
|
||||||
|
t0 = time.time()
|
||||||
|
result = _run(["docker", "cp", str(host_dir), f"{container}:{container_dest}"], timeout=120)
|
||||||
|
elapsed = time.time() - t0
|
||||||
|
|
||||||
|
if result.returncode != 0:
|
||||||
|
raise RuntimeError(f"[{label}] docker cp 失败: {result.stderr}")
|
||||||
|
|
||||||
|
# 验证
|
||||||
|
verify = _run(["docker", "exec", container, "find", container_dest, "-type", "f"])
|
||||||
|
stdout = (verify.stdout or "").strip()
|
||||||
|
count = len([l for l in stdout.splitlines() if l.strip()])
|
||||||
|
print(f" 拷贝完成: {elapsed:.1f}s, 容器内 {count} 个文件")
|
||||||
|
return elapsed
|
||||||
|
|
||||||
|
|
||||||
|
def copy_to_container(container: str = None, dry_run: bool = False, only: str = None):
|
||||||
|
"""将 GPKG 和模板拷贝到容器本地文件系统"""
|
||||||
|
cfg = _load_config()
|
||||||
|
if container is None:
|
||||||
|
container = cfg["container"]
|
||||||
|
|
||||||
|
_check_container(container)
|
||||||
|
|
||||||
|
t_total = time.time()
|
||||||
|
print(f"=== 预拷贝静态数据到容器 {container} ===\n")
|
||||||
|
|
||||||
|
if only != "template":
|
||||||
|
host_gpkg = PROJECT_ROOT / cfg["gpkg_subdir"]
|
||||||
|
_copy_dir_to_container(host_gpkg, container, cfg["container_gpkg"], "GPKG", dry_run)
|
||||||
|
print()
|
||||||
|
|
||||||
|
if only != "gpkg":
|
||||||
|
host_template = PROJECT_ROOT / cfg["template_subdir"]
|
||||||
|
_copy_dir_to_container(host_template, container, cfg["container_template"], "模板", dry_run)
|
||||||
|
|
||||||
|
elapsed = time.time() - t_total
|
||||||
|
print(f"\n=== 总耗时: {elapsed:.1f}s ===")
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
parser = argparse.ArgumentParser(description="将 GPKG 和模板预拷贝到 Docker 容器本地 FS")
|
||||||
|
parser.add_argument("--container", default=None, help="Docker 容器名称")
|
||||||
|
parser.add_argument("--dry-run", action="store_true", help="仅显示信息,不实际拷贝")
|
||||||
|
parser.add_argument("--only", choices=["gpkg", "template"], help="只拷贝指定类型")
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
try:
|
||||||
|
copy_to_container(container=args.container, dry_run=args.dry_run, only=args.only)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"错误: {e}", file=sys.stderr)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
@@ -167,6 +167,33 @@ def map_container_to_host(path: str) -> str:
|
|||||||
return path
|
return path
|
||||||
|
|
||||||
|
|
||||||
|
def map_template_to_container(host_path: str) -> str:
|
||||||
|
"""将主机端模板路径映射到容器内本地路径(预拷贝后绕过 9P)。
|
||||||
|
|
||||||
|
主机: F:/project/xian/xian_algorithm_new/app/data/template/rainfall/xxx.qgz
|
||||||
|
容器: /data/template/rainfall/xxx.qgz
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
from config import settings
|
||||||
|
container_tpl = getattr(settings, "QGIS_DOCKER_TEMPLATE_DIR", "") or ""
|
||||||
|
except Exception:
|
||||||
|
container_tpl = ""
|
||||||
|
|
||||||
|
if not container_tpl:
|
||||||
|
# fallback: 用通用映射(走 9P,慢)
|
||||||
|
return map_host_to_container(host_path)
|
||||||
|
|
||||||
|
normalized = host_path.replace("\\", "/").lower()
|
||||||
|
# 找 "app/data/template/" 后面的部分
|
||||||
|
marker = "app/data/template/"
|
||||||
|
idx = normalized.find(marker)
|
||||||
|
if idx >= 0:
|
||||||
|
relative = host_path.replace("\\", "/")[idx + len(marker):]
|
||||||
|
return f"{container_tpl.rstrip('/')}/{relative}"
|
||||||
|
|
||||||
|
return map_host_to_container(host_path)
|
||||||
|
|
||||||
|
|
||||||
def build_docker_volume_mounts() -> list:
|
def build_docker_volume_mounts() -> list:
|
||||||
"""
|
"""
|
||||||
构建 Docker 卷挂载参数列表(用于 docker run)。
|
构建 Docker 卷挂载参数列表(用于 docker run)。
|
||||||
|
|||||||
+7
-8
@@ -8,9 +8,13 @@ RAIN_STATION_GRID_DIR = "/xian/rainfall/grid/images/:id"
|
|||||||
REDIS_RAIN_STATION_GRID_KEY = "xian:rainfall:rain_station_grid"
|
REDIS_RAIN_STATION_GRID_KEY = "xian:rainfall:rain_station_grid"
|
||||||
REDIS_RAIN_STATION_IDENTIFIER_KEY = "xian:rainfall:rain_station_identifier"
|
REDIS_RAIN_STATION_IDENTIFIER_KEY = "xian:rainfall:rain_station_identifier"
|
||||||
PREDICT_PROBABILITY_THRESHOLD = 50
|
PREDICT_PROBABILITY_THRESHOLD = 50
|
||||||
# 静态底图 GeoPackage 目录(相对于项目根目录)
|
# 静态底图 GeoPackage 目录
|
||||||
QGIS_GPKG_DIR = "app/data/gpkg"
|
QGIS_GPKG_DIR = "app/data/gpkg"
|
||||||
# 专题图输出子目录(相对于 FILE_STORE_DIR)
|
# 容器内 GPKG 本地路径
|
||||||
|
QGIS_DOCKER_GPKG_DIR = "/data/gpkg"
|
||||||
|
# 容器内模板本地路径
|
||||||
|
QGIS_DOCKER_TEMPLATE_DIR = "/data/template"
|
||||||
|
# 专题图输出子目录
|
||||||
QGIS_OUTPUT_DIR = "xian/qgis/map/:eventType/:inferenceId"
|
QGIS_OUTPUT_DIR = "xian/qgis/map/:eventType/:inferenceId"
|
||||||
# 专题图默认参数
|
# 专题图默认参数
|
||||||
QGIS_DEFAULTS_MAP_LAYOUT = "A4"
|
QGIS_DEFAULTS_MAP_LAYOUT = "A4"
|
||||||
@@ -21,7 +25,7 @@ QGIS_DEFAULTS_MAP_UNIT = "制图单位:西安市应急管理局"
|
|||||||
QGIS_EXPORT_DPI = 200
|
QGIS_EXPORT_DPI = 200
|
||||||
# 并行 docker exec 子进程数
|
# 并行 docker exec 子进程数
|
||||||
QGIS_PARALLEL_WORKERS = 4
|
QGIS_PARALLEL_WORKERS = 4
|
||||||
# 最大并发请求数(防止多人同时触发资源耗尽)
|
# 最大并发请求数
|
||||||
QGIS_MAX_CONCURRENT = 2
|
QGIS_MAX_CONCURRENT = 2
|
||||||
# ============================================================
|
# ============================================================
|
||||||
# Docker QGIS 配置
|
# Docker QGIS 配置
|
||||||
@@ -91,11 +95,6 @@ REDIS_DB = 0
|
|||||||
# 文件路径配置
|
# 文件路径配置
|
||||||
# ============================================================
|
# ============================================================
|
||||||
FILE_STORE_DIR = "G:/files"
|
FILE_STORE_DIR = "G:/files"
|
||||||
# ============================================================
|
|
||||||
# 专题图输出子目录
|
|
||||||
# ============================================================
|
|
||||||
QGIS_OUTPUT_DIR = "xian/qgis/map/:eventType/:inferenceId"
|
|
||||||
QGIS_DEFAULTS_MAP_UNIT = "制图单位:西安市应急管理局"
|
|
||||||
|
|
||||||
# ============================================================
|
# ============================================================
|
||||||
# 生产环境
|
# 生产环境
|
||||||
|
|||||||
Reference in New Issue
Block a user