GIS项目依赖环境复杂?用Docker Compose一键部署PostGIS+GeoServer(含:编排模板)

编程与开发
Dr.GIS
wowwwai GIS研习社 · 工具流程与项目排障

GIS项目依赖环境复杂?用Docker Compose一键部署PostGIS+GeoServer(含:编排模板)这类问题,在WebGIS项目交付、课程实验环境搭建、团队协作开发中非常常见。PostGIS需要数据库扩展、GeoServer需要Java运行环境和数据目录,手工安装经常出现端口冲突、版本不一致、插件缺失、数据丢失等问题。本文用一个可复制的Docker Compose模板,把PostGIS和GeoServer放到同一个GIS服务栈里,适合快速搭建开发、测试和教学环境。

Docker Compose部署PostGIS和GeoServer一键部署GIS环境
Docker Compose将PostGIS数据库、GeoServer地图服务和数据卷统一编排,适合GIS项目快速搭建开发环境。

引言:为什么GIS项目适合用Docker Compose部署PostGIS+GeoServer

很多GIS项目不是一个单独软件能跑起来的,而是一组依赖共同工作:空间数据库负责存储矢量数据,地图服务负责发布WMS、WFS,前端WebGIS再去请求服务。只要其中一个环节版本或配置不一致,就可能导致整个项目无法复现。

用Docker Compose部署PostGIS+GeoServer的核心价值,是把环境描述成一个文本文件。新成员拿到项目后,不需要逐个安装PostgreSQL、PostGIS、Java、GeoServer,只要执行一条命令,就能得到基本一致的GIS运行环境。

本文面向GIS学生、入门GIS工程师、WebGIS开发者和需要本地测试地图服务的空间数据分析人员。目标不是讲Docker全部原理,而是给你一套能落地的PostGIS GeoServer Docker Compose编排模板,并说明每个关键配置为什么这样写。

背景:手工安装PostGIS和GeoServer容易遇到哪些问题

在传统安装方式下,一个GIS项目常见的环境问题包括:

  • PostGIS扩展未启用:PostgreSQL装好了,但数据库里没有执行CREATE EXTENSION postgis;,导致空间字段和空间函数不可用。
  • GeoServer版本不一致:本机、测试机、服务器使用了不同版本,样式、插件或REST接口行为不完全一致。
  • 端口冲突:本地已有PostgreSQL占用5432端口,GeoServer或Tomcat占用8080端口。
  • 数据目录混乱:GeoServer的数据目录如果没有持久化,容器重建后工作区、图层、样式可能丢失。
  • 团队协作困难:每个人都说“我这里能跑”,但数据库版本、坐标系定义、服务配置并不一致。

Docker Compose适合解决这种“多组件、多端口、多数据卷”的环境问题。它不会替代你理解PostGIS和GeoServer,但可以把重复安装、重复配置的成本降下来。

原理:Docker Compose如何编排PostGIS和GeoServer

Docker Compose是Docker提供的多容器编排工具。你可以在一个docker-compose.yml文件里声明多个服务,例如一个PostGIS容器、一个GeoServer容器,以及它们共用的网络和数据卷。

在本文的GIS环境里,整体关系可以理解为:

  • PostGIS容器:提供PostgreSQL数据库和PostGIS空间扩展,用来存储点、线、面、栅格索引等空间数据。
  • GeoServer容器:连接PostGIS数据库,把表发布为WMS、WFS等OGC服务。
  • Docker网络:让GeoServer可以通过服务名访问PostGIS,例如主机名写postgis,而不是写本机IP。
  • 数据卷:保存数据库文件和GeoServer数据目录,避免容器删除后配置和数据一起丢失。

需要注意的是,Docker Compose部署PostGIS+GeoServer并不等于生产环境已经完备。生产环境还需要备份、权限、日志、安全、反向代理、HTTPS、资源限制和监控。本文模板更适合开发、测试、教学和小型内网演示。

步骤:准备Docker Compose一键部署PostGIS+GeoServer

1. 准备项目目录

建议为GIS环境单独建一个目录,便于管理编排文件、初始化SQL和备份文件。例如:

gis-stack/
  docker-compose.yml
  initdb/
    01-init-postgis.sql
  backup/

docker-compose.yml负责声明服务,initdb目录用于首次启动数据库时自动执行初始化SQL,backup目录可以放数据库导入导出文件。

2. 编写PostGIS初始化SQL

initdb/01-init-postgis.sql中写入以下内容,用于创建PostGIS扩展和一个示例schema:

CREATE EXTENSION IF NOT EXISTS postgis;
CREATE EXTENSION IF NOT EXISTS postgis_topology;

CREATE SCHEMA IF NOT EXISTS gis;

CREATE TABLE IF NOT EXISTS gis.demo_points (
    id SERIAL PRIMARY KEY,
    name TEXT,
    geom geometry(Point, 4326)
);

INSERT INTO gis.demo_points (name, geom)
VALUES
('sample_point_1', ST_SetSRID(ST_MakePoint(116.391, 39.907), 4326)),
('sample_point_2', ST_SetSRID(ST_MakePoint(121.473, 31.230), 4326))
ON CONFLICT DO NOTHING;

CREATE INDEX IF NOT EXISTS demo_points_geom_idx
ON gis.demo_points
USING GIST (geom);

这里使用EPSG:4326作为示例坐标系,也就是常见的经纬度坐标。实际项目中,如果你使用CGCS2000、高斯投影、Web Mercator或地方坐标系,要在建表时明确SRID,并确保GeoServer发布图层时识别正确。

3. 编写docker-compose.yml编排模板

下面是一份适合开发测试使用的Docker Compose部署PostGIS和GeoServer模板:

services:
  postgis:
    image: postgis/postgis:16-3.4
    container_name: gis_postgis
    restart: unless-stopped
    environment:
      POSTGRES_DB: gisdb
      POSTGRES_USER: gisuser
      POSTGRES_PASSWORD: gispassword
      TZ: Asia/Shanghai
    ports:
      - "5432:5432"
    volumes:
      - postgis_data:/var/lib/postgresql/data
      - ./initdb:/docker-entrypoint-initdb.d
    networks:
      - gis_net
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U gisuser -d gisdb"]
      interval: 10s
      timeout: 5s
      retries: 5

  geoserver:
    image: kartoza/geoserver:2.25.2
    container_name: gis_geoserver
    restart: unless-stopped
    environment:
      GEOSERVER_ADMIN_USER: admin
      GEOSERVER_ADMIN_PASSWORD: geoserver
      GEOSERVER_DATA_DIR: /opt/geoserver/data_dir
      TZ: Asia/Shanghai
    ports:
      - "8080:8080"
    volumes:
      - geoserver_data:/opt/geoserver/data_dir
    depends_on:
      postgis:
        condition: service_healthy
    networks:
      - gis_net

volumes:
  postgis_data:
  geoserver_data:

networks:
  gis_net:
    driver: bridge

如果你本机已经有PostgreSQL占用5432端口,可以把左侧端口改成其他端口,例如:

ports:
  - "15432:5432"

这表示主机用15432访问容器内的5432。GeoServer连接PostGIS时,仍然应该使用Docker网络内的服务名postgis和端口5432,而不是localhost

4. 启动GIS服务栈

gis-stack目录下执行:

docker compose up -d

查看容器状态:

docker compose ps

查看日志:

docker compose logs -f postgis
docker compose logs -f geoserver

正常情况下,你应该能看到PostGIS数据库启动成功,GeoServer也完成初始化。第一次启动GeoServer可能需要较长时间,尤其是镜像首次拉取和数据目录首次生成时。

5. 验证PostGIS是否可用

进入PostGIS容器:

docker exec -it gis_postgis psql -U gisuser -d gisdb

执行以下SQL检查PostGIS扩展:

SELECT postgis_full_version();

SELECT id, name, ST_AsText(geom)
FROM gis.demo_points;

如果能够返回PostGIS版本信息和两个示例点,说明数据库、扩展、初始化SQL都正常。

6. 登录GeoServer并连接PostGIS

在浏览器访问:

http://localhost:8080/geoserver

使用模板中的账号登录:

  • 用户名:admin
  • 密码:geoserver

然后按以下思路创建PostGIS数据存储:

  1. 进入GeoServer管理界面。
  2. 创建工作区,例如gis
  3. 新建数据存储,选择PostGIS。
  4. 数据库连接参数填写:主机postgis,端口5432,数据库gisdb,用户gisuser,密码gispassword
  5. 保存后,发布gis.demo_points图层。
  6. 在图层预览中查看WMS或WFS输出。

这里最容易写错的是主机名。GeoServer在容器内部运行,它访问的localhost是GeoServer容器自己,不是PostGIS容器,也不是你的宿主机。因此,在Docker Compose网络内应使用服务名postgis

7. 用QGIS验证WMS和PostGIS连接

建议用QGIS做两类验证:

  • 验证PostGIS直连:在QGIS中新建PostgreSQL连接,主机填localhost,端口填宿主机映射端口,例如543215432
  • 验证GeoServer服务:在QGIS中新建WMS/WMTS连接,URL填写http://localhost:8080/geoserver/wms

如果QGIS能直接加载PostGIS表,也能通过GeoServer加载WMS图层,说明数据库、服务发布和客户端访问链路都已经打通。

常见坑:Docker Compose部署PostGIS GeoServer失败怎么排查

1. GeoServer连接PostGIS时不要写localhost

这是最常见的问题。GeoServer容器里的localhost指向GeoServer自身,不会指向PostGIS。正确写法是使用Compose服务名:

host: postgis
port: 5432

只有从宿主机上的QGIS、DBeaver、pgAdmin访问PostGIS时,才使用localhost加映射端口。

2. 初始化SQL只在数据库数据卷首次创建时执行

/docker-entrypoint-initdb.d中的SQL脚本只会在PostgreSQL数据目录第一次初始化时执行。如果你已经启动过容器,后来修改了01-init-postgis.sql,它不会自动再次执行。

开发环境可以删除数据卷后重新初始化:

docker compose down -v
docker compose up -d

但这会删除数据库数据。真实项目中请先备份,不要直接在生产环境执行。

3. GeoServer数据目录必须持久化

如果没有给GeoServer配置数据卷,容器删除后,工作区、图层、样式、数据存储等配置可能丢失。模板中使用:

volumes:
  - geoserver_data:/opt/geoserver/data_dir

这能让GeoServer配置随数据卷保存,而不是只保存在容器临时文件系统中。

4. 端口占用导致服务启动失败

如果本机已有数据库或其他服务占用5432、8080,Docker会提示端口绑定失败。解决方法是修改宿主机映射端口,例如:

ports:
  - "18080:8080"

修改后GeoServer访问地址变为:

http://localhost:18080/geoserver

5. 坐标系和SRID不一致会导致图层位置错误

PostGIS表的几何字段有SRID,GeoServer发布图层时也会读取坐标参考系统。如果表中SRID为空、错误或混用,WebGIS前端可能出现图层偏移、范围异常、无法缩放到图层等问题。

排查SQL可以使用:

SELECT ST_SRID(geom), COUNT(*)
FROM gis.demo_points
GROUP BY ST_SRID(geom);

如果结果中出现多个SRID,说明数据需要统一坐标系后再发布。

方法比较:手工安装、Docker单容器和Docker Compose怎么选

方式 适用场景 优点 限制
手工安装PostGIS和GeoServer 单机长期使用、需要深度定制环境 可控性强,便于学习底层配置 迁移困难,团队环境容易不一致
Docker单容器启动 只测试一个组件,例如单独测试PostGIS 命令简单,启动快 多服务关系不清晰,网络和数据卷容易散乱
Docker Compose编排 PostGIS+GeoServer+WebGIS联调、课程实验、团队开发 配置集中,可复制,可版本管理 仍需理解端口、网络、数据卷和安全配置
Kubernetes部署 生产集群、多服务伸缩、平台化运维 适合大规模和高可用场景 学习成本高,小型项目可能过度复杂

对大多数GIS开发和教学项目来说,Docker Compose是比较合适的中间方案:比手工安装更可复现,比Kubernetes更轻量。等项目进入生产阶段,再考虑反向代理、权限加固、备份策略和容器编排平台。

检查清单:部署前后建议逐项确认

  • 版本是否固定:不要长期使用不明确的latest标签,建议固定PostGIS和GeoServer镜像版本。
  • 密码是否修改:模板中的gispasswordgeoserver只适合本地测试,正式环境必须修改。
  • 端口是否冲突:确认5432和8080是否已被本机服务占用。
  • 数据卷是否配置:PostGIS数据目录和GeoServer数据目录都应持久化。
  • 初始化SQL是否执行:SELECT postgis_full_version();确认PostGIS扩展已启用。
  • GeoServer连接主机是否正确:容器内访问PostGIS应填写postgis,不是localhost
  • SRID是否一致:发布图层前检查空间表SRID,避免地图偏移。
  • 是否能用QGIS验证:分别测试PostGIS直连和GeoServer WMS服务。
  • 是否有备份策略:不要把Docker数据卷当成唯一备份。

FAQ:Docker Compose部署PostGIS+GeoServer常见问题

Q1:Docker Compose部署PostGIS+GeoServer适合生产环境吗?

可以作为生产环境的基础,但不能直接把本文开发模板原样用于生产。生产环境至少要补充强密码、网络隔离、定期备份、反向代理、HTTPS、资源限制、日志管理和访问权限控制。本文模板更适合开发测试和教学演示。

Q2:GeoServer连接PostGIS时主机名为什么填postgis?

因为postgisdocker-compose.yml里的服务名。Docker Compose会为同一网络下的服务提供名称解析。GeoServer容器可以通过postgis:5432访问PostGIS容器。

Q3:为什么修改初始化SQL后没有生效?

PostgreSQL官方镜像的初始化脚本只在数据目录为空时执行。如果数据卷已经存在,脚本不会再次运行。你可以手动进入数据库执行SQL,或者在确认不需要保留数据后使用docker compose down -v删除数据卷重新初始化。

Q4:PostGIS端口改成15432后,GeoServer也要改吗?

通常不需要。15432:5432表示宿主机通过15432访问容器内5432。GeoServer和PostGIS在同一个Docker网络中通信,仍然访问postgis:5432。只有QGIS、DBeaver等宿主机软件访问数据库时,才使用localhost:15432

Q5:GeoServer数据目录应该放在命名卷还是本地目录?

开发测试可以使用命名卷,简单稳定。如果你需要把GeoServer配置纳入备份、迁移或版本化管理,可以改成本地目录挂载。但要注意文件权限,尤其是在Linux服务器上运行容器时。

Q6:如何备份Docker里的PostGIS数据库?

可以使用pg_dump从容器中导出:

docker exec -t gis_postgis pg_dump -U gisuser -d gisdb -Fc > backup/gisdb.dump

恢复时可以使用pg_restore。正式项目建议制定定期备份策略,并把备份文件存放到容器和宿主机之外的可靠位置。

结论:用编排模板降低GIS环境复现成本

PostGIS和GeoServer是很多WebGIS项目的基础组合,但它们的安装、版本、端口、数据目录和连接配置容易让初学者反复踩坑。用Docker Compose部署PostGIS+GeoServer,可以把这些依赖集中到一个可复制的编排文件中,让开发、测试和教学环境更容易复现。

实际使用时,建议先用本文模板跑通PostGIS扩展、GeoServer连接和QGIS验证,再逐步加入自己的空间数据、样式、工作区和WebGIS前端。记住三个关键点:GeoServer连PostGIS用服务名postgis,数据库和GeoServer都要配置数据卷,正式环境必须单独处理安全和备份。