Docker部署GIS服务总失败?新手入门环境配置与避坑指南(含:实战脚本)
《Docker部署GIS服务总失败?新手入门环境配置与避坑指南(含:实战脚本)》这篇文章,专门解决 GIS 初学者在用 Docker 部署 GeoServer、PostGIS、Nginx、WebGIS 前端服务时反复失败的问题。很多报错看起来像 Docker 问题,实际上常见原因是端口冲突、数据卷权限、容器网络、坐标数据路径、服务启动顺序没有处理好。

引言:Docker部署GIS服务为什么新手最容易卡住
Docker 的优势是“环境可复制”,但 GIS 服务并不只是启动一个容器那么简单。一个完整的 GIS 开发环境通常包含空间数据库、地图服务、切片或静态资源服务、前端 WebGIS 应用,有时还会挂载 Shapefile、GeoTIFF、MBTiles、样式文件和插件目录。
新手常见的失败现象包括:
- PostGIS 容器启动了,但 GeoServer 连不上数据库。
- GeoServer 页面能打开,但发布图层时报错。
- WebGIS 前端访问 WMS、WMTS 或矢量瓦片时跨域失败。
- 容器重启后数据丢失。
- Windows 或 Linux 上挂载目录后,GeoServer 没有权限读取数据。
- 端口已经被占用,导致服务看似启动,实际无法访问。
本文按一个最小可用的 GIS 服务环境来讲:PostGIS + GeoServer + Nginx。你可以在此基础上继续接入 Leaflet、OpenLayers、Cesium 或自己的 WebGIS 项目。
背景:一个 Docker GIS 入门环境应该包含什么
如果只是学习 Docker 命令,运行一个单独容器就够了。但如果目标是 Docker部署GIS服务,建议一开始就用多容器编排方式,也就是使用 docker compose。这样可以把数据库、地图服务、反向代理、数据目录、环境变量都写在一个配置文件中,后续迁移和排错会简单很多。
一个入门级 GIS 服务环境通常包括:
- PostGIS:存储空间表、行政区边界、道路、POI、分析结果等矢量数据。
- GeoServer:发布 WMS、WFS、WMTS 等 OGC 标准地图服务。
- Nginx:提供反向代理、静态页面访问、统一入口和跨域配置。
- 数据卷:保存数据库数据、GeoServer 工作空间、样式、上传的数据文件。
- 自定义网络:让容器之间使用服务名互相访问,而不是写死 IP。
很多新手直接运行多个 docker run 命令,短期能启动,长期很难维护。更推荐用一个 docker-compose.yml 文件来管理整个 GIS 环境。
原理:Docker部署GIS服务失败通常不是“镜像坏了”
排查 Docker部署GIS服务失败时,不要第一反应就换镜像。大多数问题来自以下四类原理。
1. 容器内外端口不是一回事
例如 GeoServer 容器内部可能监听 8080,你映射为宿主机 8081:8080。这时浏览器应该访问宿主机的 8081,而容器之间访问 GeoServer 时仍应使用容器内部端口 8080。
宿主机访问: http://localhost:8081/geoserver
容器间访问: http://geoserver:8080/geoserver
2. 容器之间不要用 localhost 互相访问
在 GeoServer 里配置 PostGIS 数据源时,如果数据库和 GeoServer 是两个容器,数据库主机不要填 localhost。因为对 GeoServer 容器来说,localhost 指的是 GeoServer 容器自己,不是 PostGIS 容器。
正确做法是使用 docker compose 里的服务名,例如:
PostGIS 主机:postgis
端口:5432
数据库:gis
用户名:gis
密码:gis_password
3. 数据卷决定数据是否会丢失
如果没有挂载数据卷,PostGIS 数据库文件和 GeoServer 配置很可能随着容器删除而丢失。GIS 服务的数据通常很重,数据库、样式、工作空间、栅格文件都必须明确挂载。
4. GIS 文件路径和权限经常导致发布失败
GeoServer 发布 Shapefile 或 GeoTIFF 时,如果文件挂载到容器内的路径不对,或者容器用户没有读取权限,就会出现“文件不存在”“无法读取数据源”“图层预览为空”等问题。
步骤:使用 docker compose 部署 PostGIS + GeoServer + Nginx
下面给出一个适合学习和本地开发的实战脚本。生产环境需要进一步处理 HTTPS、备份、安全密码、资源限制和访问控制。
步骤 1:准备项目目录
在你的电脑上创建一个目录,例如:
gis-docker-stack/
├── docker-compose.yml
├── nginx/
│ └── default.conf
├── geoserver_data/
├── postgis_data/
└── web/
└── index.html
Linux 或 macOS 可以执行:
mkdir -p gis-docker-stack/{nginx,geoserver_data,postgis_data,web}
cd gis-docker-stack
Windows 用户也可以手动创建同样的目录。建议路径不要包含中文、空格和特殊符号,避免挂载路径被 Docker Desktop 解析出错。
步骤 2:编写 docker-compose.yml
services:
postgis:
image: postgis/postgis:16-3.4
container_name: gisyxs_postgis
environment:
POSTGRES_DB: gis
POSTGRES_USER: gis
POSTGRES_PASSWORD: gis_password
ports:
- "5432:5432"
volumes:
- ./postgis_data:/var/lib/postgresql/data
networks:
- gisnet
restart: unless-stopped
geoserver:
image: docker.osgeo.org/geoserver:2.25.2
container_name: gisyxs_geoserver
environment:
GEOSERVER_ADMIN_USER: admin
GEOSERVER_ADMIN_PASSWORD: geoserver_password
ports:
- "8081:8080"
volumes:
- ./geoserver_data:/opt/geoserver_data
depends_on:
- postgis
networks:
- gisnet
restart: unless-stopped
nginx:
image: nginx:1.27-alpine
container_name: gisyxs_nginx
ports:
- "8080:80"
volumes:
- ./nginx/default.conf:/etc/nginx/conf.d/default.conf:ro
- ./web:/usr/share/nginx/html:ro
depends_on:
- geoserver
networks:
- gisnet
restart: unless-stopped
networks:
gisnet:
driver: bridge
这个配置里有几个关键点:
postgis、geoserver、nginx是服务名,容器之间可以直接使用这些名字访问。- 宿主机访问 GeoServer 使用
http://localhost:8081/geoserver。 - 宿主机访问 Nginx 使用
http://localhost:8080。 - PostGIS 数据挂载到
./postgis_data,GeoServer 配置挂载到./geoserver_data。
步骤 3:编写 Nginx 反向代理配置
创建 nginx/default.conf:
server {
listen 80;
server_name localhost;
location / {
root /usr/share/nginx/html;
index index.html;
}
location /geoserver/ {
proxy_pass http://geoserver:8080/geoserver/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Methods "GET, POST, OPTIONS";
add_header Access-Control-Allow-Headers "Origin, Content-Type, Accept, Authorization";
if ($request_method = OPTIONS) {
return 204;
}
}
}
这样前端可以通过 Nginx 访问 GeoServer:
http://localhost:8080/geoserver/
对 WebGIS 开发者来说,这种方式比在前端直接写 http://localhost:8081/geoserver 更接近真实部署结构,也更容易统一处理跨域。
步骤 4:准备一个简单前端页面
创建 web/index.html。如果严格只测试 Nginx 是否工作,可以写一个最简单的 HTML 文件:
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>GIS Docker Stack</title>
</head>
<body>
<h2>GIS Docker Stack is running</h2>
<p>GeoServer proxy: /geoserver/</p>
</body>
</html>
启动后访问 http://localhost:8080,如果能看到页面,说明 Nginx 静态服务正常。
步骤 5:启动服务
docker compose up -d
查看容器状态:
docker compose ps
查看日志:
docker compose logs -f postgis
docker compose logs -f geoserver
docker compose logs -f nginx
如果容器反复重启,先看日志,不要盲目删除目录。PostGIS 首次初始化、GeoServer 首次写入数据目录都可能需要一点时间。
步骤 6:验证 PostGIS 是否可用
进入 PostGIS 容器:
docker exec -it gisyxs_postgis psql -U gis -d gis
检查 PostGIS 扩展:
SELECT PostGIS_Version();
如果能返回版本信息,说明 PostGIS 已经可用。也可以创建一个测试表:
CREATE TABLE test_points (
id serial PRIMARY KEY,
name text,
geom geometry(Point, 4326)
);
INSERT INTO test_points (name, geom)
VALUES ('gisyxs_test', ST_SetSRID(ST_MakePoint(116.391, 39.907), 4326));
SELECT id, name, ST_AsText(geom) FROM test_points;
步骤 7:在 GeoServer 中连接 PostGIS
浏览器打开:
http://localhost:8081/geoserver
使用配置中的管理员账号登录:
用户名:admin
密码:geoserver_password
创建 PostGIS 数据源时,重点填写:
- host:
postgis - port:
5432 - database:
gis - user:
gis - passwd:
gis_password - schema:通常填写
public
注意:这里的 host 不是 localhost,也不是宿主机 IP,而是 docker compose 服务名 postgis。
步骤 8:发布测试图层并验证 WMS
在 GeoServer 中发布 test_points 表后,可以通过图层预览检查 WMS 是否正常。如果通过 Nginx 访问,URL 结构类似:
http://localhost:8080/geoserver/你的工作区/wms
如果地图不显示,先检查以下三点:
- 图层坐标系是否正确设置为 EPSG:4326。
- 图层边界是否计算成功。
- 前端请求的图层名是否包含工作区前缀,例如
workspace:test_points。
常见坑:Docker GIS 环境配置最容易忽略的错误
坑 1:端口冲突导致服务访问失败
如果你的电脑已经安装了 PostgreSQL,本机 5432 可能被占用。此时 Docker 会提示端口绑定失败。可以把宿主机端口改成 15432:
ports:
- "15432:5432"
注意,容器之间访问 PostGIS 仍然使用 postgis:5432,不要改成 15432。
坑 2:GeoServer 连接数据库时写 localhost
这是 Docker部署GIS服务中最典型的新手错误。容器内部的 localhost 只代表当前容器自己。GeoServer 连接 PostGIS 时必须写服务名 postgis。
坑 3:删除容器后发现数据没了
如果没有配置 volumes,删除容器可能会让数据随容器消失。PostGIS 和 GeoServer 都应该挂载数据目录。开发环境可以使用相对路径,生产环境建议使用明确的数据盘路径。
坑 4:Windows 路径和权限问题
Docker Desktop 在 Windows 上挂载目录时,路径权限、换行符、盘符共享都可能造成问题。建议:
- 项目目录放在英文路径下。
- 避免路径中出现空格和中文。
- 使用 WSL2 后端时,尽量把项目放在 Linux 文件系统内。
- 如果 GeoServer 读取挂载文件失败,先用
docker exec进入容器检查文件是否真的存在。
坑 5:depends_on 不等于服务完全可用
depends_on 只能保证容器启动顺序,不保证 PostGIS 已经完成初始化。GeoServer 启动后第一次连接数据库失败,不一定是配置错,也可能是数据库还没准备好。
可以等待 PostGIS 日志出现类似“database system is ready to accept connections”的信息后,再去 GeoServer 中配置数据源。
坑 6:WMS 能访问,前端却加载失败
这通常与跨域、代理路径、图层名、坐标系或请求参数有关。先用浏览器直接打开 GetCapabilities:
http://localhost:8080/geoserver/ows?service=WMS&version=1.3.0&request=GetCapabilities
如果能力文档能返回,说明服务本身大概率正常。再检查前端 OpenLayers 或 Leaflet 的图层 URL、参数和控制台报错。
方法比较:docker run、docker compose 与手动安装怎么选
| 方式 | 适合场景 | 优点 | 缺点 |
|---|---|---|---|
| docker run | 临时测试单个服务 | 命令直接,启动快 | 多容器管理困难,参数容易丢 |
| docker compose | 本地 GIS 开发环境、教学环境、小型项目演示 | 服务关系清晰,便于复现和迁移 | 需要理解网络、端口、数据卷 |
| 手动安装 | 需要深度定制的服务器环境 | 可控性强,便于与系统服务集成 | 环境差异大,迁移和恢复成本高 |
| Kubernetes | 多节点、高可用、生产集群 | 扩展能力强,适合平台化部署 | 学习成本高,不适合新手入门起步 |
对于 GIS 初学者和入门级 GIS 工程师,建议先用 docker compose。它能覆盖绝大多数 Docker GIS 入门环境配置问题,也能帮助你理解真实项目中的服务拆分方式。
检查清单:Docker部署GIS服务失败时按这个顺序排查
- 第一步:看容器是否启动,执行
docker compose ps,确认状态不是Exited或反复重启。 - 第二步:看日志,执行
docker compose logs -f 服务名,优先找端口、权限、数据库初始化、配置文件语法错误。 - 第三步:查端口映射,确认浏览器访问的是宿主机端口,例如
8081:8080应访问8081。 - 第四步:查容器网络,容器之间使用服务名访问,例如 GeoServer 连接 PostGIS 写
postgis。 - 第五步:查数据卷,确认数据库数据、GeoServer 数据目录是否正确挂载。
- 第六步:查文件权限,进入容器查看挂载文件是否存在、是否可读。
- 第七步:查坐标系,确认 PostGIS 表的 SRID、GeoServer 图层坐标系、前端地图坐标系是否匹配。
- 第八步:查服务接口,先测试 GetCapabilities,再测试前端代码。
如果你不确定问题在哪里,最稳妥的方式是从 PostGIS、GeoServer、Nginx 依次验证,而不是一上来就看 WebGIS 前端页面。
FAQ:Docker GIS 服务部署常见问题
Q1:Docker部署GIS服务需要先学 Linux 吗?
不需要先成为 Linux 高手,但至少要会看目录、端口、日志和权限。GIS 服务部署经常涉及数据目录挂载、配置文件修改和服务日志排查,这些基础操作比背 Docker 命令更重要。
Q2:GeoServer 容器能打开页面,但连不上 PostGIS,怎么办?
优先检查数据库主机名是否写成了 localhost。在 docker compose 网络中,GeoServer 连接 PostGIS 应填写服务名 postgis。然后检查用户名、密码、数据库名和 schema 是否一致。
Q3:为什么容器重启后 GeoServer 配置丢失?
通常是 GeoServer 数据目录没有正确挂载。需要把容器内的 GeoServer 数据目录挂载到宿主机目录,例如本文中的 ./geoserver_data:/opt/geoserver_data。不同镜像的数据目录位置可能不同,使用前要查看镜像说明。
Q4:Docker 部署 PostGIS 后,QGIS 怎么连接?
如果端口映射是 5432:5432,QGIS 中主机填写 localhost,端口填写 5432,数据库、用户名、密码与 compose 文件保持一致。如果宿主机端口改成 15432,QGIS 端口就填 15432。
Q5:WebGIS 前端访问 GeoServer 出现跨域错误怎么办?
入门阶段推荐通过 Nginx 统一代理 GeoServer,并在 Nginx 中添加跨域响应头。前端请求同一个入口,例如 http://localhost:8080/geoserver/,比直接请求 GeoServer 宿主机端口更容易管理。
Q6:Docker GIS 环境适合生产部署吗?
可以,但本文脚本主要面向学习和本地开发。生产环境还需要处理强密码、HTTPS、备份恢复、资源限制、日志轮转、访问控制、数据库性能优化、镜像版本固定和安全更新。
Q7:PostGIS 表在 GeoServer 中看不到,是什么原因?
常见原因包括表没有 geometry 字段、geometry 字段 SRID 不明确、数据库连接 schema 填错、表权限不足、GeoServer 没有刷新数据源。可以先在 PostGIS 中执行 SELECT Find_SRID('public','表名','geom'); 检查 SRID。
结论:先把网络、端口、数据卷和日志跑通
Docker部署GIS服务并不难,难点在于 GIS 服务链条比普通 Web 服务更长:PostGIS 管数据,GeoServer 发服务,Nginx 做入口,前端负责渲染。任何一个环节的端口、路径、权限或坐标系出错,都会表现为“部署失败”。
新手最推荐的学习路线是:先用 docker compose 跑通 PostGIS、GeoServer 和 Nginx;再发布一个最简单的点图层;最后接入 OpenLayers、Leaflet 或 Cesium。只要你按日志、端口、网络、数据卷、坐标系的顺序排查,大多数 Docker GIS 入门环境配置问题都能定位到具体原因。
记住一个原则:容器启动成功不等于 GIS 服务可用。真正可用的标准是数据库能连接、图层能发布、OGC 服务能访问、前端地图能正确显示。