znlgis 博客

GIS开发与技术分享

第四章:目录与配置管理

4.1 引言

GeoServer 的核心是其目录(Catalog)系统,它管理着所有的配置信息,包括工作区、数据存储、图层、样式等。在传统的单体 GeoServer 中,这些配置通常存储在”数据目录”(Data Directory)的 XML 文件中。然而,在 GeoServer Cloud 的分布式环境中,需要所有服务实例能够共享和同步配置信息,这就需要更加健壮的目录后端解决方案。

本章将深入介绍 GeoServer Cloud 支持的各种目录后端,重点讲解推荐的 PGConfig(PostgreSQL)后端的配置和使用,同时也会介绍外部化配置的各种方法和最佳实践。

4.2 GeoServer Catalog 概念

4.2.1 Catalog 的作用

Catalog 是 GeoServer 的核心配置存储系统,包含以下主要内容:

Catalog
├── 工作区(Workspaces)
│   └── 命名空间(Namespaces)
├── 数据存储(Stores)
│   ├── 数据存储(DataStores) - 矢量数据
│   ├── 覆盖存储(CoverageStores) - 栅格数据
│   └── WMS/WMTS 存储 - 级联服务
├── 资源(Resources)
│   ├── 要素类型(FeatureTypes)
│   └── 覆盖(Coverages)
├── 图层(Layers)
├── 图层组(LayerGroups)
├── 样式(Styles)
├── 服务配置(Service Configurations)
│   ├── WMS 配置
│   ├── WFS 配置
│   └── ...
└── 安全配置(Security)
    ├── 用户(Users)
    ├── 角色(Roles)
    └── 访问规则(Access Rules)

4.2.2 配置对象关系

理解 Catalog 中各对象的关系对于正确配置 GeoServer 至关重要:

Workspace(工作区)
    │
    ├── Namespace(命名空间)1:1 关系
    │
    ├── DataStore(数据存储)
    │       │
    │       └── FeatureType(要素类型)
    │               │
    │               └── Layer(图层)
    │
    └── CoverageStore(覆盖存储)
            │
            └── Coverage(覆盖)
                    │
                    └── Layer(图层)

Style(样式)──────────┘
        可被多个图层引用

4.2.3 传统数据目录结构

传统 GeoServer 的数据目录结构如下:

GEOSERVER_DATA_DIR/
├── global.xml                    # 全局配置
├── logging.xml                   # 日志配置
├── workspaces/                   # 工作区目录
│   └── myworkspace/
│       ├── namespace.xml
│       ├── workspace.xml
│       └── mystore/
│           ├── datastore.xml
│           └── mylayer/
│               ├── featuretype.xml
│               └── layer.xml
├── styles/                       # 样式目录
│   ├── default_point.sld
│   └── mystyle.sld
├── layergroups/                  # 图层组
├── gwc/                          # GeoWebCache 配置
├── security/                     # 安全配置
│   ├── config.xml
│   ├── layers.properties
│   ├── services.properties
│   └── usergroup/
│       └── users.xml
└── www/                          # Web 资源

4.3 目录后端选择

4.3.1 后端对比

GeoServer Cloud 支持三种目录后端,各有特点:

特性 PGConfig DataDir JDBCConfig
推荐度 ★★★★★ ★★★☆☆ ★☆☆☆☆
可扩展性 优秀 一般 一般
一致性 强一致 最终一致 最终一致
性能
维护状态 活跃开发 维护 已弃用
适用场景 生产环境 开发测试 遗留兼容

4.3.2 选择建议

PGConfig(推荐)

适用于:

优势:

DataDir(共享数据目录)

适用于:

限制:

JDBCConfig(已弃用)

4.4 PGConfig PostgreSQL 后端

4.4.1 概述

PGConfig 是 GeoServer Cloud 推荐的目录后端,它将所有配置存储在 PostgreSQL 数据库中。主要特点:

4.4.2 数据库要求

4.4.3 配置 PGConfig

1. 准备数据库

-- 创建用户
CREATE USER geoserver WITH PASSWORD 'your_password';

-- 创建数据库
CREATE DATABASE geoserver_config OWNER geoserver;

-- 连接到数据库并创建扩展(可选)
\c geoserver_config
CREATE EXTENSION IF NOT EXISTS postgis;

2. 配置服务

在 compose.yml 或环境变量中配置:

services:
  wms:
    image: geoservercloud/geoserver-cloud-wms:${TAG}
    environment:
      - SPRING_PROFILES_ACTIVE=pgconfig
      # 数据库连接
      - PGCONFIG_HOST=database
      - PGCONFIG_PORT=5432
      - PGCONFIG_DATABASE=geoserver_config
      - PGCONFIG_SCHEMA=public
      - PGCONFIG_USERNAME=geoserver
      - PGCONFIG_PASSWORD=your_password
      # 连接池配置
      - PGCONFIG_HIKARI_MINIMUM_IDLE=2
      - PGCONFIG_HIKARI_MAXIMUM_POOL_SIZE=10

3. 完整的 Spring 配置示例

spring:
  profiles:
    active: pgconfig

geoserver:
  backend:
    pgconfig:
      enabled: true
      # 数据库连接
      host: ${PGCONFIG_HOST:localhost}
      port: ${PGCONFIG_PORT:5432}
      database: ${PGCONFIG_DATABASE:geoserver}
      schema: ${PGCONFIG_SCHEMA:public}
      username: ${PGCONFIG_USERNAME:geoserver}
      password: ${PGCONFIG_PASSWORD:geoserver}
      # HikariCP 连接池
      hikari:
        minimum-idle: ${PGCONFIG_HIKARI_MINIMUM_IDLE:2}
        maximum-pool-size: ${PGCONFIG_HIKARI_MAXIMUM_POOL_SIZE:10}
        idle-timeout: ${PGCONFIG_HIKARI_IDLE_TIMEOUT:30000}
        max-lifetime: ${PGCONFIG_HIKARI_MAX_LIFETIME:60000}
        connection-timeout: ${PGCONFIG_HIKARI_CONNECTION_TIMEOUT:10000}
      # 初始化配置
      initialize: ${PGCONFIG_INITIALIZE:true}
      create-schema: ${PGCONFIG_CREATE_SCHEMA:true}

4.4.4 数据库架构

PGConfig 会自动创建以下表结构:

-- 工作区表
CREATE TABLE workspaces (
    id VARCHAR(36) PRIMARY KEY,
    name VARCHAR(255) NOT NULL UNIQUE,
    isolated BOOLEAN DEFAULT FALSE,
    date_created TIMESTAMP,
    date_modified TIMESTAMP
);

-- 数据存储表
CREATE TABLE datastores (
    id VARCHAR(36) PRIMARY KEY,
    workspace_id VARCHAR(36) REFERENCES workspaces(id),
    name VARCHAR(255) NOT NULL,
    description TEXT,
    type VARCHAR(255),
    enabled BOOLEAN DEFAULT TRUE,
    connection_params JSONB
);

-- 要素类型表
CREATE TABLE featuretypes (
    id VARCHAR(36) PRIMARY KEY,
    store_id VARCHAR(36) REFERENCES datastores(id),
    name VARCHAR(255) NOT NULL,
    native_name VARCHAR(255),
    title VARCHAR(255),
    description TEXT,
    srs VARCHAR(255),
    native_bounds GEOMETRY,
    lat_lon_bounds GEOMETRY,
    metadata JSONB
);

-- 样式表
CREATE TABLE styles (
    id VARCHAR(36) PRIMARY KEY,
    workspace_id VARCHAR(36) REFERENCES workspaces(id),
    name VARCHAR(255) NOT NULL,
    format VARCHAR(50),
    language_version VARCHAR(50),
    filename VARCHAR(255),
    style_body TEXT
);

-- ... 更多表

4.4.5 数据库维护

备份

# 完整备份
pg_dump -U geoserver -h localhost geoserver_config > backup.sql

# 仅备份数据
pg_dump -U geoserver -h localhost --data-only geoserver_config > data_backup.sql

恢复

# 恢复到新数据库
createdb geoserver_config_restore
psql -U geoserver -h localhost geoserver_config_restore < backup.sql

性能监控

-- 查看活动连接
SELECT * FROM pg_stat_activity WHERE datname = 'geoserver_config';

-- 查看表大小
SELECT 
    relname AS table_name,
    pg_size_pretty(pg_total_relation_size(relid)) AS total_size
FROM pg_catalog.pg_statio_user_tables
ORDER BY pg_total_relation_size(relid) DESC;

-- 查看慢查询
SELECT * FROM pg_stat_statements 
WHERE dbid = (SELECT oid FROM pg_database WHERE datname = 'geoserver_config')
ORDER BY total_time DESC LIMIT 10;

4.4.6 PGBouncer 连接池

在大规模部署中,建议使用 PGBouncer 作为连接池代理:

# compose.yml
services:
  pgbouncer:
    image: bitnami/pgbouncer:latest
    environment:
      - POSTGRESQL_HOST=database
      - POSTGRESQL_PORT=5432
      - POSTGRESQL_USERNAME=geoserver
      - POSTGRESQL_PASSWORD=${PGCONFIG_PASSWORD}
      - POSTGRESQL_DATABASE=geoserver_config
      - PGBOUNCER_POOL_MODE=transaction
      - PGBOUNCER_MAX_CLIENT_CONN=1000
      - PGBOUNCER_DEFAULT_POOL_SIZE=20
    ports:
      - "6432:6432"

  wms:
    environment:
      - PGCONFIG_HOST=pgbouncer
      - PGCONFIG_PORT=6432

PGBouncer 配置说明:

参数 说明 推荐值
POOL_MODE 连接池模式 transaction
MAX_CLIENT_CONN 最大客户端连接 根据服务数调整
DEFAULT_POOL_SIZE 默认池大小 20-50

4.5 DataDir 数据目录后端

4.5.1 概述

DataDir 后端使用传统的文件系统数据目录存储配置。在 GeoServer Cloud 中,需要所有服务实例共享同一个数据目录。

4.5.2 配置方式

1. 使用 Docker 卷

services:
  wms:
    image: geoservercloud/geoserver-cloud-wms:${TAG}
    environment:
      - SPRING_PROFILES_ACTIVE=datadir
      - GEOSERVER_DATA_DIR=/opt/app/data_directory
    volumes:
      - geoserver-data:/opt/app/data_directory:rw

  wfs:
    image: geoservercloud/geoserver-cloud-wfs:${TAG}
    environment:
      - SPRING_PROFILES_ACTIVE=datadir
      - GEOSERVER_DATA_DIR=/opt/app/data_directory
    volumes:
      - geoserver-data:/opt/app/data_directory:rw

volumes:
  geoserver-data:

2. 使用 NFS 共享存储

volumes:
  geoserver-data:
    driver: local
    driver_opts:
      type: nfs
      o: addr=nfs-server.example.com,nolock,soft,rw
      device: ":/exports/geoserver-data"

4.5.3 初始化数据目录

GeoServer Cloud 可以从空数据目录启动,也可以使用预配置的数据目录:

使用示例数据目录

# 下载示例数据
wget https://github.com/geoserver/geoserver-cloud/raw/main/compose/catalog-datadir.tgz

# 解压到数据目录
tar -xzf catalog-datadir.tgz -C /path/to/data_directory

从现有 GeoServer 迁移

# 复制现有数据目录
cp -r /var/geoserver/data/* /new/data_directory/

# 确保权限正确
chown -R 1000:1000 /new/data_directory

4.5.4 配置同步机制

DataDir 后端依赖事件总线进行配置同步:

1. 管理员通过 WebUI 修改配置
2. WebUI 服务写入文件系统
3. WebUI 发送配置变更事件到 RabbitMQ
4. 所有服务实例接收事件
5. 各实例重新加载受影响的配置

配置事件总线:

spring:
  rabbitmq:
    host: ${RABBITMQ_HOST:rabbitmq}
    port: ${RABBITMQ_PORT:5672}
    username: ${RABBITMQ_USERNAME:guest}
    password: ${RABBITMQ_PASSWORD:guest}
  cloud:
    bus:
      enabled: true

4.5.5 注意事项

使用 DataDir 后端时需要注意:

  1. 文件锁定:并发写入可能导致问题
  2. 网络存储性能:NFS 等网络存储可能影响性能
  3. 同步延迟:配置变更需要时间传播
  4. 一致性:不保证强一致性

4.6 外部化配置详解

4.6.1 配置来源优先级

GeoServer Cloud 支持多种配置来源,按以下优先级(从高到低)加载:

1. 命令行参数       --server.port=8080
2. 系统属性         -Dserver.port=8080
3. 环境变量         SERVER_PORT=8080
4. Config Server    从配置服务器获取
5. 本地 application.yml
6. 默认值           框架内置默认值

4.6.2 环境变量配置

环境变量是最常用的配置方式,命名规则:

配置属性:geoserver.backend.pgconfig.host
环境变量:GEOSERVER_BACKEND_PGCONFIG_HOST

规则:
- 将点(.)替换为下划线(_)
- 将连字符(-)替换为下划线(_)
- 转换为大写

常用环境变量示例:

# 基本配置
GEOSERVER_BASE_PATH=/geoserver/cloud
GEOSERVER_ADMIN_USERNAME=admin
GEOSERVER_ADMIN_PASSWORD=secure_password

# 数据库配置
PGCONFIG_HOST=localhost
PGCONFIG_PORT=5432
PGCONFIG_DATABASE=geoserver
PGCONFIG_USERNAME=geoserver
PGCONFIG_PASSWORD=password

# JVM 配置
JAVA_OPTS=-Xms512m -Xmx2g -XX:+UseG1GC

# 日志配置
LOGGING_LEVEL_ORG_GEOSERVER=INFO
LOGGING_LEVEL_ORG_GEOTOOLS=WARN

4.6.3 JNDI 数据源配置

GeoServer Cloud 提供了简化的 JNDI 支持,用于配置数据源:

jndi:
  datasources:
    # PostGIS 数据源
    postgis:
      enabled: true
      wait-for-it: true        # 等待数据库可用
      wait-timeout: 60         # 等待超时(秒)
      url: jdbc:postgresql://localhost:5432/geodata
      username: geoserver
      password: ${POSTGIS_PASSWORD}
      # HikariCP 配置
      connection-timeout: 5000
      idle-timeout: 60000
      max-lifetime: 120000
      minimum-idle: 2
      maximum-pool-size: 10
      
    # Oracle 数据源
    oracle:
      enabled: ${ORACLE_ENABLED:false}
      url: jdbc:oracle:thin:@//oracle-host:1521/ORCL
      username: geoserver
      password: ${ORACLE_PASSWORD}
      driver-class-name: oracle.jdbc.OracleDriver

在 GeoServer 中使用 JNDI 数据源:

JNDI 名称:java:comp/env/jdbc/postgis

4.6.4 HTTP 代理配置

配置级联 WMS/WMTS/WFS 服务的 HTTP 代理:

geotools:
  httpclient:
    proxy:
      enabled: true
      http:
        host: proxy.example.com
        port: 8080
        user: proxyuser
        password: proxypassword
        nonProxyHosts: localhost,*.internal.com
      https:
        host: ${geotools.httpclient.proxy.http.host}
        port: ${geotools.httpclient.proxy.http.port}

环境变量方式:

HTTP_PROXYHOST=proxy.example.com
HTTP_PROXYPORT=8080
HTTP_PROXYUSER=proxyuser
HTTP_PROXYPASSWORD=proxypassword
HTTP_NONPROXYHOSTS=localhost,*.internal.com

4.6.5 数据格式过滤

可以控制启用哪些数据格式:

geotools:
  data:
    filtering:
      enabled: true
      # 矢量格式
      vector-formats:
        "[PostGIS]": true
        "[Shapefile]": true
        "[GeoPackage]": true
        "[Oracle NG]": ${ORACLE_ENABLED:false}
        "[Microsoft SQL Server]": false
      # 栅格格式
      raster-formats:
        "[GeoTIFF]": true
        "[ImageMosaic]": true
        "[WorldImage]": true
        "[ArcGrid]": false

4.6.6 服务路径配置

修改默认的服务访问路径:

# 默认路径:/geoserver/cloud
# 修改为:/gis

geoserver:
  base-path: /gis
  
# 或通过环境变量
GEOSERVER_BASE_PATH=/gis

4.7 配置版本管理

4.7.1 Git 管理配置

推荐使用 Git 管理 GeoServer Cloud 配置:

# 初始化配置仓库
mkdir geoserver-cloud-config
cd geoserver-cloud-config
git init

# 目录结构
geoserver-cloud-config/
├── application.yml           # 共享配置
├── wms-service.yml          # WMS 配置
├── wfs-service.yml          # WFS 配置
├── gateway-service.yml      # 网关配置
├── application-docker.yml   # Docker 环境
├── application-k8s.yml      # Kubernetes 环境
└── application-prod.yml     # 生产环境

4.7.2 Config Server 使用 Git

# config-service 配置
spring:
  cloud:
    config:
      server:
        git:
          uri: https://github.com/your-org/geoserver-cloud-config
          default-label: main
          search-paths: '{application}'
          clone-on-start: true
          force-pull: true
          # 私有仓库认证
          username: ${GIT_USERNAME}
          password: ${GIT_PASSWORD}

4.7.3 配置版本追踪

利用 Git 追踪配置变更:

# 查看配置历史
git log --oneline application.yml

# 查看特定版本的配置
git show abc123:application.yml

# 比较配置差异
git diff HEAD~1 application.yml

# 回滚配置
git checkout abc123 -- application.yml
git commit -m "Rollback to previous config"
git push

然后刷新服务配置:

curl -X POST http://config-server:8888/actuator/bus-refresh

4.8 配置最佳实践

4.8.1 安全配置

敏感信息处理

# 不要这样做
geoserver:
  admin:
    password: admin123

# 应该这样做
geoserver:
  admin:
    password: ${GEOSERVER_ADMIN_PASSWORD}

使用 Kubernetes Secrets

apiVersion: v1
kind: Secret
metadata:
  name: geoserver-secrets
type: Opaque
stringData:
  admin-password: "secure-password-here"
  db-password: "db-password-here"

引用 Secret:

env:
  - name: GEOSERVER_ADMIN_PASSWORD
    valueFrom:
      secretKeyRef:
        name: geoserver-secrets
        key: admin-password

4.8.2 环境分离

为不同环境创建独立的配置:

# application-dev.yml
geoserver:
  backend:
    pgconfig:
      host: localhost
      hikari:
        maximum-pool-size: 5

---
# application-prod.yml
geoserver:
  backend:
    pgconfig:
      host: postgres-cluster.internal
      hikari:
        maximum-pool-size: 30

激活特定环境:

SPRING_PROFILES_ACTIVE=pgconfig,prod

4.8.3 配置验证

启动时验证配置的有效性:

spring:
  cloud:
    config:
      fail-fast: true  # 配置加载失败时快速失败
      retry:
        initial-interval: 1000
        max-interval: 5000
        max-attempts: 10

4.8.4 配置文档化

为配置添加注释:

# ============================================
# GeoServer Cloud - WMS Service Configuration
# ============================================
# 
# Environment: Production
# Last Updated: 2024-01-15
# Maintainer: ops@example.com
#
geoserver:
  wms:
    # 渲染线程池大小
    # 建议设置为 CPU 核心数的 1-2 倍
    rendering:
      pool-size: ${WMS_RENDERING_POOL_SIZE:4}
    
    # 最大请求内存(字节)
    # 限制单个请求可使用的最大内存
    max-request-memory: ${WMS_MAX_REQUEST_MEMORY:67108864}  # 64MB

4.8.5 监控配置变更

设置配置变更通知:

management:
  endpoints:
    web:
      exposure:
        include: health,info,refresh,bus-refresh,env

# 启用审计日志
logging:
  level:
    org.springframework.cloud.bus: DEBUG
    org.springframework.cloud.config: INFO

4.9 故障排除

4.9.1 常见配置问题

问题:数据库连接失败

# 检查数据库连接
docker compose exec wms nc -zv database 5432

# 检查数据库用户权限
docker compose exec database psql -U geoserver -c "\du"

# 查看服务日志
docker compose logs wms | grep -i "database\|connection\|postgres"

问题:配置不生效

# 检查当前配置
curl http://localhost:9102/actuator/env | jq '.propertySources'

# 刷新配置
curl -X POST http://localhost:9102/actuator/refresh

# 检查 Config Server 是否可达
curl http://config:8888/wms-service/default

问题:事件同步失败

# 检查 RabbitMQ 连接
docker compose exec wms nc -zv rabbitmq 5672

# 查看 RabbitMQ 队列状态
docker compose exec rabbitmq rabbitmqctl list_queues

# 检查 Bus 事件
docker compose logs wms | grep -i "bus\|event\|rabbit"

4.9.2 配置调试技巧

启用配置调试日志

logging:
  level:
    org.springframework.boot.context.config: DEBUG
    org.springframework.cloud.config: DEBUG

查看实际加载的配置

# 所有配置属性
curl http://localhost:9102/actuator/configprops | jq

# 环境变量
curl http://localhost:9102/actuator/env | jq '.propertySources[] | select(.name | contains("systemEnvironment"))'

4.9.3 数据库诊断

-- 检查配置数据
SELECT * FROM workspaces;
SELECT * FROM datastores WHERE workspace_id IS NOT NULL;
SELECT * FROM styles LIMIT 10;

-- 检查最近修改
SELECT * FROM workspaces ORDER BY date_modified DESC LIMIT 5;

-- 检查数据一致性
SELECT w.name AS workspace, COUNT(d.id) AS stores
FROM workspaces w
LEFT JOIN datastores d ON w.id = d.workspace_id
GROUP BY w.name;

4.10 本章小结

本章深入介绍了 GeoServer Cloud 的目录和配置管理:

  1. Catalog 概念:理解了 GeoServer 目录系统的核心对象和它们之间的关系。

  2. 后端选择:比较了 PGConfig、DataDir 和 JDBCConfig 三种后端的特点和适用场景。

  3. PGConfig 配置:详细学习了 PostgreSQL 后端的配置、维护和优化方法。

  4. DataDir 配置:了解了数据目录后端在 GeoServer Cloud 中的使用方法和限制。

  5. 外部化配置:掌握了环境变量、JNDI 数据源、HTTP 代理等配置方法。

  6. 配置管理:学习了使用 Git 进行配置版本管理的最佳实践。

  7. 故障排除:了解了常见配置问题的诊断和解决方法。

在下一章中,我们将深入探讨 GeoServer Cloud 的安全配置和认证机制。

4.11 思考题

  1. PGConfig 相比 DataDir 后端有哪些优势?在什么情况下仍然应该选择 DataDir?

  2. 如何设计一个支持配置回滚的 GeoServer Cloud 部署方案?

  3. 在多租户环境中,如何使用工作区隔离实现配置隔离?

  4. PGBouncer 在大规模部署中的作用是什么?应该如何配置?

  5. 如何确保敏感配置(如数据库密码)在分布式环境中的安全性?