Docker 离线地图服务器搭建实战:Node.js + OpenLayers + MBTiles
摘要:本文记录了一次从零搭建离线地图服务器的完整过程。选用 Node.js + OpenLayers + MBTiles 技术栈,利用 Docker 将服务容器化并上传至 Docker Hub。文中详细说明了瓦片数据的获取方法(如水经注下载 MBTiles)、镜像的使用步骤以及前端集成示例,帮助有离线地图需求的项目快速落地。
一、项目背景
公司内部项目需要集成离线地图功能。此前我曾成功将百度地图离线化,但版本较老,且百度 API 封闭性强,很多功能难以深度定制。于是决定自研一套离线地图服务,最终确定了以下技术组合:
- OpenLayers:专为 Web GIS 客户端开发的 JavaScript 类库,支持标准格式的地图数据访问,灵活可扩展。
- MBTiles:基于 SQLite 的地图瓦片存储格式,单文件便于分发和挂载。
- Node.js:轻量服务端,提供瓦片读取和静态文件托管。
整套服务已打包为 Docker 镜像 914423503/linemap:latest,做到开箱即用。
二、准备工作
2.1 安装 Docker
请确保已安装 Docker 并配置镜像加速(如阿里云、网易等)。若未安装,可参考:
bash
# Ubuntu 示例
sudo apt update
sudo apt install docker.io
sudo systemctl start docker
sudo systemctl enable docker
2.2 获取 MBTiles 瓦片文件
MBTiles 是地图离线化的关键,这里推荐使用 水经注 软件进行下载。
下载步骤(以水经注为例):
bash
下载并安装"水经注万能地图下载器"(收费软件,也可申请试用)。
选择目标区域(如北京市),设置瓦片级别(建议 1-19 级)。
导出格式选择 MBTiles,并指定输出路径。
等待下载完成,得到一个 .mbtiles 文件,例如 beijing_e_19.mbtiles。
将文件移动至宿主机的 /App/map/ 目录下,命名为 beijing_e_19.mbtiles。

注意:也可通过其他工具生成 MBTiles(如 QGIS + QTiles 插件),但水经注图形化操作更为便捷,覆盖数据源丰富。
2.3 下载前端 GIS 配置文件
我已将必需的 gis.js 和 CntenLomap.js 上传至 GitHub:
bash
git clone https://github.com/914423503/linemap.git
将仓库中的 gis.js 和 CntenLomap.js 复制到宿主机的 /App/map/ 目录下。
修改 gis.js 中的 IP 地址为您的服务器 IP(例如 192.168.1.79):

javascript
// gis.js 中定位到地图服务地址
var mapServer = 'http://192.168.1.79:3000';
最终宿主机目录结构大致如下:
text
/App/map/
├── beijing_e_19.mbtiles
├── gis.js
└── CntenLomap.js
三、启动离线地图服务
3.1 拉取 Docker 镜像
bash
docker pull 914423503/linemap:latest

3.2 运行容器
将宿主机的 /App/map 目录挂载进容器,让服务读取 MBTiles 和 JS 文件:
bash
docker run -d -p 3000:3000 \
-v /App/map:/map \
-v /App/map/gis.js:/app/public/javascripts/gis.js \
914423503/linemap:latest
参数说明:
-p 3000:3000:映射容器 3000 端口到宿主机。
-v /App/map:/map:挂载宿主机瓦片和脚本目录。
-v ...gis.js:单独挂载前端配置文件,确保使用修改后的 IP。
3.3 访问地图页面
打开浏览器,输入 http://your-ip:3000/gis,即可看到北京市的离线地图。效果如下图

四、前端项目集成
在您的 Web 项目中,只需引入 OpenLayers 并指向该服务即可。以下是一个简单示例:
html
<!DOCTYPE html>
<html>
<head>
<title>离线地图集成</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io@master/en/v6.14.1/css/ol.css">
<script src="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io@master/en/v6.14.1/build/ol.js"></script>
</head>
<body>
<div id="map" style="width: 100%; height: 600px;"></div>
<script>
// 将 gis.js 中的配置动态引入,或直接使用以下方式
var map = new ol.Map({
target: 'map',
layers: [
new ol.layer.Tile({
source: new ol.source.XYZ({
url: 'http://your-ip:3000/tiles/{z}/{x}/{y}.png' // 根据实际服务路径调整
})
})
],
view: new ol.View({
center: ol.proj.fromLonLat([116.397428, 39.90923]),
zoom: 12
})
});
</script>
</body>
</html>
实际路径请参考 gis.js 中的瓦片地址定义,我的镜像内置了瓦片读取接口,URL 规范可参考仓库说明。
五、常见问题
Q:页面空白或无法加载瓦片?
检查挂载路径是否正确,/App/map/beijing_e_19.mbtiles 是否存在。
确认容器日志:docker logs 容器ID 查看 Node 报错。
确保 gis.js 中的 IP 地址与当前宿主机一致,且端口 3000 未被防火墙拦截。
Q:如何制作其他城市的 MBTiles?
使用水经注重新下载目标区域,或者将多个 .mbtiles 文件合并(需编写脚本)。建议一个区域一个容器实例,通过不同端口区分。
Q:能否使用免费瓦片源?
OpenStreetMap 导出工具也可生成 MBTiles,但国内访问速度较慢,水经注提供的高德、谷歌等源更符合实际项目需求。
结语
本文提供了一套轻量、可控的离线地图容器化方案,从瓦片获取到服务部署再到前端接入一应俱全。希望能帮助到同样受困于离线地图集成的朋友。如果有更好的改进思路,欢迎交流!