MapLibre/Martin 地图服务器docker化安装部署

Martin 是一款由 MapLibre 社区维护的超快速且轻量级的地理空间地图瓦片服务器。它主要使用 Rust 语言编写,旨在提供极高性能的实时瓦片渲染和分发服务,是当前开源 GIS 领域中 Windshaft 的主要现代替代方案之一。

核心功能与特性:

多源支持: 能够实时从 PostGIS 数据库(表、视图、自定义函数)生成矢量瓦片,并支持直接读取本地或远程(通过 HTTP/S3)的 PMTiles 和 MBTiles 文件。

极致性能: 相比于基于 Node.js 的 Windshaft 或基于 Go 的同类工具,Martin 凭借 Rust 的非阻塞异步架构(基于 Actix-web)展现出极高的吞吐量和极低的延迟。

动态函数渲染: 它是极少数能直接利用 PostGIS 自定义函数生成瓦片的服务器,允许开发者在 URL 中传递参数,实现服务器端的动态过滤和数据聚合。

生态集成: 完整支持 MapLibre 生态系统,能够动态生成字体(Fonts)、雪碧图(Sprites)和地图样式(Styles)。

多源合并: 允许将多个不同的数据源(例如一部分来自 PostGIS,一部分来自 PMTiles)组合成单一的瓦片源输出

github地址
https://github.com/maplibre/martin

文档
https://maplibre.org/martin/introduction.html

一、使用 Docker Compose 安装部署Martin

1.1 安装

为了方便管理环境变量和持久化配置,使用 docker-compose.yml。创建一个目录并进入,新建docker-compose.yml文件。

我这里已经安装了postgres,所以直连了,如果没有安装,可以配置postgres,统一安装管理。

复制代码
version: '3.3'

services:
  martin:
    # 镜像地址
    image: swr.cn-north-4.myhuaweicloud.com/ddn-k8s/ghcr.io/maplibre/martin:latest
    container_name: martin-server
    network_mode: "host"
    environment:
      # 数据库连接字符串,格式:postgres://用户名:密码@数据库IP:5432/数据库名
      - DATABASE_URL=postgres://postgres:123456@127.0.0.1:5432/postgres
      # 开启监听所有 IP
      - WATCH_MODE=true
      - MARTIN_LISTEN_ADDRESSES=0.0.0.0:3000
    volumes:
      - ./tiles:/data
    # command 显式开启 Web UI,并指定扫描 /data 目录
    command: --webui enable-for-all /data
    restart: always

执行:

复制代码
docker-compose up -d

查看日志,看是否正常运行(若未安装成功,可以执行此命令,定位原因)

复制代码
docker logs -f martin-server

或者直接

docker 复制代码
docker run -d --name martin-server -p 3000:3000 -e DATABASE_URL=postgres://用户名:密码@数据库IP:5432/数据库名 swr.cn-north-4.myhuaweicloud.com/ddn-k8s/ghcr.io/maplibre/martin:latest

1.2 验证

查看状态和源列表

http://localhost:3000/catalog

看到类似如下json文件,就说明成功了,

JSON 复制代码
{
    "tiles": {
        "subway_station": {
            "content_type": "application/x-protobuf",
            "description": "public.subway_station.geom"
        },
        "state": {
            "content_type": "application/x-protobuf",
            "description": "tiger.state.the_geom"
        },
        "aoi": {
            "content_type": "application/x-protobuf",
            "description": "public.aoi.geom"
        },
        "subway_station_in_ex_port": {
            "content_type": "application/x-protobuf",
            "description": "public.subway_station_in_ex_port.geom"
        },
        "faces": {
            "content_type": "application/x-protobuf",
            "description": "tiger.faces.the_geom"
        }
    },
    "sprites": {},
    "fonts": {},
    "styles": {}
}

获取某个图层的元数

http://localhost:3000/subway_station

JSON 复制代码
{
    "tilejson": "3.0.0",
    "tiles": [
        "http://localhost:3000/subway_station/{z}/{x}/{y}"
    ],
    "vector_layers": [
        {
            "id": "subway_station",
            "fields": {
                "Address": "varchar",
                "BELType": "int4",
                "Category": "varchar",
                "City": "varchar",
                "Code": "varchar",
                "District": "varchar",
                "Lat": "float8",
                "Lon": "float8",
                "MidType": "varchar",
                "Name_CHN": "varchar",
                "OBJECTID": "int4",
                "Province": "varchar",
                "SubType": "varchar",
                "TopType": "varchar",
                "id": "int4"
            }
        }
    ],
    "bounds": [
        87.449117,
        22.136547,
        126.742498,
        45.873099
    ],
    "description": "public.subway_station.geom",
    "name": "subway_station"
}

二、在地图中加载

Martin (矢量动态)将原始几何数据实时封装进矢量瓦片(MVT),由前端浏览器 (使用 MapLibre/Mapbox GL) 根据样式文件实时渲染出图像。

Martin(基于 Rust 的高性能切片服务器)通常生成的切片格式是 MVT (Mapbox Vector Tiles, .pbf),即矢量切片。由于 Leaflet 原生只支持栅格切片(图片),加载 Martin 的矢量切片需要借助插件。

2.1 Leaflet.VectorGrid(最常用)

Leaflet.VectorGrid 是加载 Martin 矢量切片(PBF格式)的标准方式。

html 复制代码
<!DOCTYPE html>
<html>

<head>
    <title>map</title>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.9.4/leaflet.css" />
    <script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.9.4/leaflet-src.min.js"></script>
	<script src="https://unpkg.com/leaflet.vectorgrid@1.3.0/dist/Leaflet.VectorGrid.bundled.js"></script>
    <style>
        html,
        body {
            height: 100%;
            width: 100%;
            overflow: hidden;
        }

        #map {
            height: 100%;
            width: 100%;
        }
    </style>
</head>

<body>
    <div id="map">
    </div>
</body>
<script>
    var map = L.map('map', {
        center: [33.72577076, 118.6680564],
        zoom: 13
    });
    L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { attribution: '&copy;' }).addTo(map);
	
	
	const martinUrl = 'http://loacalhost:3000/subway_station/{z}/{x}/{y}'
	
	var vectorTileOptions = {
        rendererFactory: L.canvas.tile, // 使用 Canvas 渲染
        vectorTileLayerStyles: {
            // 注意:这里的 key 必须是 Martin 提供的图层名(通常是数据库表名)
            subway_station: {
                color: '#ff0000',
                fill: true,
                fillColor: '#ff0000',
                fillOpacity: 0.5,
                radius: 5
            }
        },
        interactive: true, // 允许点击等交互
        getFeatureId: function(f) {
            return f.properties.id; // 用于高效更新样式
        }
    };
	
	var pbfLayer = L.vectorGrid.protobuf(martinUrl, vectorTileOptions).addTo(map);

    // 交互示例:点击显示属性
    pbfLayer.on('click', function(e) {
        var properties = e.layer.properties;
        L.popup()
            .setLatLng(e.latlng)
            .setContent("站名: " + (properties.name || "未知"))
            .openOn(map);
    });
</script>
</html>

实际效果图

2.1 使用 MapLibre-Leaflet (性能最佳)

适用矢量数据非常庞大、复杂的样式(Mapbox Style JSON),使用 WebGL 渲染方案。

html 复制代码
<!DOCTYPE html>
<html>
<head>
    <title>map</title>
	<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" />
    <link href="https://unpkg.com/maplibre-gl@3.x/dist/maplibre-gl.css" rel="stylesheet" />
	<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
    <script src="https://unpkg.com/maplibre-gl@3.x/dist/maplibre-gl.js"></script>
    <script src="https://unpkg.com/@maplibre/maplibre-gl-leaflet/leaflet-maplibre-gl.js"></script>
    <style>
        html,
        body {
            height: 100%;		
            width: 100%;
            overflow: hidden;
        }

        #map {
            height: 100%;
            width: 100%;
        }
    </style>
</head>

<body>
    <div id="map">
    </div>
</body>
<script>
var map = L.map('map').setView([39.9, 116.4], 10);
L.maplibreGL({
        style: {
            "version": 8,
            "sources": {
                "martin-source": {
                    "type": "vector",
                    "tiles": ["http://localhost:3000/subway_station/{z}/{x}/{y}"]
                }
            },
            "layers": [
                {
                    "id": "subway-layer",
                    "type": "circle",
                    "source": "martin-source",
                    "source-layer": "subway_station",
                    "filter": ["==", "Province", "河南省"],
                    "paint": {
                        "circle-color": "#ff0000",
                        "circle-radius": 5,
                        "circle-stroke-width": 2,
                        "circle-stroke-color": "#ffffff"
                    }
                }
            ]
        }
    }).addTo(map);
</script>
</html>

效果图

相关推荐
用户03284722207033 分钟前
如何搭建本地yum源(上)
运维
武子康2 小时前
调查研究-183 Apple container:Mac 上用轻量 VM 跑 Linux 容器,Swift 会改写本地容器体验吗?
docker·容器·apple
大树883 天前
金刚石散热越强,管路越先见顶
大数据·运维·服务器·人工智能·ai
摇滚侠3 天前
Linux CentOS7 rpm 安装 MySQL 5.7
linux·运维·mysql
霸道流氓气质3 天前
领域驱动设计(DDD)在 Spring Boot 微服务中的实践指南
运维·spring boot·微服务
小宇宙Zz3 天前
Maven依赖冲突
java·服务器·maven
Inhand陈工3 天前
基于台达PLC与映翰通IG502的智慧水产养殖精准投喂与远程运维解决方案
运维·人工智能·物联网·阿里云·信息与通信
Alsn863 天前
等待学习-学习目录:Docker 容器安全攻防
学习·安全·docker
酣大智3 天前
ARP代理--工作原理
运维·网络·arp·arp代理
shushangyun_3 天前
2026年快消品B2B系统推荐:支持终端门店订货、促销政策自动化的工具?
java·运维·网络·数据库·人工智能·spring·自动化