Есть такой ресурс под название OpenStreetMap. Смысл его в том, что его может наполнять любой пользователь интернета. А еще его могут использовать для разных задач, например для поиска какого-то адреса, для путешествий, использование в качестве «подложки» для картографов и т.д. и т.п.
И вот мне понадобилось его добавить в свой рабочий проект. Для этого есть 2 пути: использовать официальный сервис либо поднять свой сервер. Второй вариант может быть использован по ряду своих причин и какие были причины у меня останутся при мне.
Подготовка
Для начала нужно определиться на чем это все разворачивать. В моем распоряжении есть сервер с мелкомягкими на 192ГБ ОЗУ и 8 ядрами процессора (16 потоков). Теперь подумаем как это все расположить.
Так как это сервер уже с какими-то ГИСами, то плодить еще кучу виртуалок не хочется. Попробуем все это уместить в более скромный набор «всего» и «вся».
На сервер уже есть PostgreSQL 14, хоть и не настроенный, а просто установленный (он нужен и для других ГИС-систем).
Судя по просмотру материала тайловый сервер все равно придется делать на Linux. Тогда понадобится виртуальная машина. Тут снова 2 вариант: создать виртуалку на сервере виртуализации (у нас в основной массе используется ProxMox) либо создать виртуалку на Hyper-V. Второй вариант тоже предпочтительней, так как весь абор будет находиться на одной железке. Создаем виртуалку и выделяем ей 8ГБ ОЗУ и 4 ядра ЦПУ. В качестве ОС накатываем Линух (у меня Debian 11). После установки не забываем настроить адреса и SSH.
Вальс в троем
Первым делом нужно установить PostGIS (без него вообще никак) на Windows-сервер. Это специально расширение для PostgreSQL. Загружаем, устанавливаем. После открываем pgAdmin4 (он должен входить в стандартную поставку с PostgreSQL for Windows) и создаем пользователя для БД (в моем случае «osm», задаем пароль и выставляем для него права «Can login». Далее создаем БД для работы (в моем случае опять же «osm») и в качестве владельца указываем ранее созданного пользователя. После для БД выполняем запросы со страницы https://postgis.net/install/, чтобы расширение PostGIS установилось для базы и еще одну команду:
CREATE EXTENSION hstore;
Расширение hstore нужно для хранения тэгов карты.
Сюда же нужно загрузить утилиту osm2pgsql.
Теперь переходим на виртуалку иустанавливаем целый ворох программ:
apt install mapnik lipapache2-mod-tile python-psycopg2 python2-yaml python3-yaml git npm nodejs fonts-noto-hinted fonts-noto-unhinted ttf-unifont fonts-noto-cjk fonts-hanazono libmapnik-dev mapnik-utils python3-mapnik
Далее понадобится пакет для генерации стиля тайлов карты:
npm -g i carto
После загружаем непосредственно стили:
git clone https://github.com/gravitystorm/openstreetmap-carto.git
cd openstreetmap-carto
Теперь открываем на редактирование файл project.mm, изменяем параметры подключения к БД в разделе osm2pgsql. В частности такие параметры как «dbname«,» host», «user» и «password». После выполняем команду:
carto project.mm > mapnik.xml
После подготовки необходимо скопировать файлы openstreet-carto.lua и openstreet-carto.style на Windows-сервер и положить их рядом с osm2pgsql.
Далее идем на сайт download.geofabrik.de, выбираем нужную карту и загружаем «.osm.pbf».
Пока выполняется загрузка карты можно сделать настройку PostgreSQL (если до этого еще не было настроено). Для этого берем PGTune (ищем в интернете), указываем необходимые параметры, вбиваем в утилиту и получаем параметры настрокий. Загоняем их в postgresql.conf. Эту операцию нужно делать только в случае ПЕРВОНАЧАЛЬНОЙ УСТАНОВКИ PostgreSQL. Вообще, по хорошему, есть специальные рекомендации настрокий. Все это прекрасно гуглится и яндексится.
После загрузки карты и не долго думая импортируем карту в БД:
osm2pgsql.exe -c -m -G --slim --hstore --tag-transform-script c:\maps\openstreet-carto.lua -d <имя БД> -H localhost -U <логин> -W -S c:\maps\openstreet-carto.style c:\maps\russia-latest.osm.pbf
Карта может импортироваться достаточно долго (в зависимости какая была выбрана). Возвращаемся на виртуалку и продолжаем настройку.
Здесь открываем /etc/renderd.conf и приводим примерно к следующему виду:
[renderd]
stats_file=/run/renderd/renderd.stats
socketname=/run/renderd/renderd.sock
num_threads=4
tile_dir=/var/cache/renderd/tiles
;tile_dir=/var/lib/mod_tile
[mapnik]
plugins_dir=/usr/lib/mapnik/3.1/input
font_dir=/usr/share/fonts/truetype
font_dir_recurse=true
[default]
XML=/root/openstreetmap-carto/mapnik.xml
URI=/tile/
TILESIZE=256
HOST=localhost
TILEDIR=/var/lib/mod_tile
По факту добавляем/правим раздел [default]. Так же при необходимости нужно поправить параметр num_threads. Директории /var/lib/mod_tile нету, по этому нужно создать и выдать соответствующие права доступа:
mkdir /var/lib/mod_tile
chown -R _renderd:_renderd
После в файле /etc/apache2/ports.conf правим порт с 80 на 8080 (ну или требуемый по вкусу). В заключении в /etc/apache2/sites-available создаем файл tileserver_site.conf:
ServerAdmin admin@osm.net
#ServerName osm.net
DocumentRoot /var/www/osm
LogLevel info
ModTileTileDir /var/lib/mod_tile
LoadTileConfigFile /etc/renderd.conf
ModTileRequestTimeout 30
ModTileMissingRequestTimeout 60
ModTileMaxLoadOld 2
ModTileMaxLoadMissing 25
ModTileRenderdSocketName /var/run/renderd/renderd.sock
ModTileCacheDurationMax 604800
ModTileCacheDurationDirty 900
ModTileCacheDurationMinimum 10800
ModTileCacheDurationMediumZoom 13 86400
ModTileCacheDurationLowZoom 9 518400
ModTileCacheLastModifiedFactor 0.20
ModTileEnableTileThrottling Off
ModTileEnableTileThrottlingXForward 0
ModTileThrottlingTiles 10000 1
ModTileThrottlingRenders 128 0.2
Options FollowSymLinks
AllowOverride None
Options -Indexes -FollowSymLinks -MultiViews
AllowOverride None
Order Allow,Deny
Allow From All
Включаем конфиг:
/usr/sbin/a2ensite tileserver_site
systemctl restart apache2
После окончания импорта карты на том же web-сервере нужно выполнить некоторые скрипты. Для этого возвращаемся в директорию openstreetmap-carto и запускаем скрипт:
scripts/get-external-data.py -d <имя БД> -U <логин> -w <пароль> -H <адрес сервера БД>
Добавляем карты
Допустим, загрузили мы только один регион. Но а если хочется добавить еще один? Не проблема! Все тот же osm2pgsql с этим прекрасно справляется. Озадачиваем его следующим образом:
osm2pgsql.exe -a -m -G --slim --hstore --tag-transform-script c:\maps\openstreet-carto.lua -d <имя БД> -H localhost -U <логин> -W -S c:\maps\openstreet-carto.style f:\belarus-latest.osm.pbf
Ну и , собственно, ждем пока загрузится новый файл.
Хочу видеть результат
В общем то все готово, но хочется все это увидеть.
Для начала остановим renderd и запустим его в интеррактивном режиме (для отладки):
systemctl stop renderd
renderd -f -c /etc/renderd.conf
После можно открыть в браузере http://<ваш адрес>:8080/tile/0/0/0.png. В результате должен открыться тайл карты. Если нет, то смотрим консоль и логи web-сервера.
Но ведь хочется больше интеррактивности…
По пути /var/www/osm добавляем файл index.html со следующим содержимым:
<html lang="en">
<head>
<meta charset="utf-8">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io@master/en/v6.14.1/css/ol.css" type="text/css">
<style>
.map {
height: 400px;
width: 100%;
}
</style>
<script src="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io@master/en/v6.14.1/build/ol.js"></script>
<title>OpenLayers example</title>
</head>
<body>
<h2>My Map</h2>
<div id="map" class="map"></div>
<script type="text/javascript">
var map = new ol.Map({
target: 'map',
layers: [
new ol.layer.Tile({
source: new ol.source.XYZ({url: 'http://<ваш сервер>:8080/tile/{z}/{x}/{y}.png'})
})
],
view: new ol.View({
center: ol.proj.fromLonLat([37.41, 8.82]),
zoom: 4
})
});
</script>
</body>
</html>
И открываем http://<Ваш сервер>:8080. Должна появиться карта. Если нет, то проверяем ошибки.
Подводный камень
В моем случае была крайне низкая скорость. Причина этому были настройки сети в Hyper-V. Не известно по каким причинам, но виртуальный сетевой адаптер работал через мост и СУБД крайне медленно передавала данные. Коллега подсказал, что нужно избавиться от моста, после чего сеть начала работать так как нужно.
Немного оптимизации
В статье OSM User:Species/PostGIS Tuning описаны дополнительные индексы, которые могут помочь оптимизировать производительность базы. Здесь я их приводить не буду, так как в ней все очень хорошо расписано и в комментариях не нуждается.