2020년 2월 16일 일요일

OpenStreetMap 타일 서버 개발

이 글은 OSM(OpenStreetMap) 타일 서버 개발하는 예제를 간략히 다룬다. 

타일 서버 개발 결과

OSM이란
OSM은 전세계 지도를 커버하는 사용자가 작성하는 맵이다. OSM은 매분 업데이트되고, 무료이다. 그리고, 상세한 데이터를 제공한다. 참고로, 이 예제는 우분투 기반으로 실습한다.

HW 환경
영국 지도만 4G RAM, 60GB 디스크가 필요하다. 전체 planet map은 32G RAM, 1TB SSD가 필요하다.

소프트웨어 준비
sudo apt update; sudo apt upgrade

PostgreSQL Database Server와 PostGIS Extension 설치
다음과 같은 명령을 통해 PostgreSQL DB와 PostGIS 확장을 설치한다.
sudo apt install postgresql postgresql-contrib postgis postgresql-10-postgis-2.4
sudo -u postgres -i
createuser osm
createdb -E UTF8 -O osm gis

psql -c "CREATE EXTENSION postgis;" -d gis
psql -c "CREATE EXTENSION hstore;" -d gis
Set osm as the table owner.

psql -c "ALTER TABLE spatial_ref_sys OWNER TO osm;" -d gis
Exit from the postgres user.
exit

sudo adduser osm

맵 스타일시트와 맵 데이터 다운로드
맵 데이터를 다음 명령으로 다운로드 한다.
su - osm
wget https://github.com/gravitystorm/openstreetmap-carto/archive/v4.20.0.tar.gz
tar xvf v4.20.0.tar.gz

만약 planet data 다운로드하려면 아래와 같이 진행한다.
wget -c http://planet.openstreetmap.org/pbf/planet-latest.osm.pbf

다음은 영국지도이고 다운로드를 위해서는 985M 용량이 필요하다.
wget -c http://download.geofabrik.de/europe/great-britain-latest.osm.pbf
Exit from osm user.
exit

맵 데이터 임포트
맵 용량이 크므로 swap file을 조정한다.
sudo fallocate -l 2G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile

Output:
Setting up swapspace version 1, size = 2097148 KiB
no label, UUID=h32b3e10-0779-4865-9ea0-6e2af8f3kea9
Enable the swap file

sudo swapon /swapfile
sudo nano /etc/ssh/ssh_config
ServerAliveInterval 60

PostgreSQL에 맵 데이터 임포트 
맵 데이터 임포트를 위해, osm2pgsql을 사용해 OSM 데이터를 postGIS 지원용 PostgreSQL DB로 변환한다.
sudo apt install osm2pgsql
su - osm
osm2pgsql --slim -d gis --hstore --multi-geometry --number-processes 8 --tag-transform-script /home/osm/openstreetmap-carto-4.20.0/openstreetmap-carto.lua --style /home/osm/openstreetmap-carto-4.20.0/openstreetmap-carto.style -C 12000 /home/osm/great-britain-latest.osm.pbf
exit

mod_tile와 Renderd 설치
다음과 같이 mod-tile과 renderd를 설치한다.
sudo add-apt-repository ppa:osmadmins/ppa
sudo apt install libapache2-mod-tile renderd
systemctl status renderd

Mapnik Stylesheet 생성
다음과 같이 mapnik과 sytlesheet를 생성한다.
sudo apt install curl unzip gdal-bin mapnik-utils libmapnik-dev nodejs npm
sudo npm install -g carto
su - osm
cd /home/osm/openstreetmap-carto-4.20.0/
scripts/get-shapefiles.py
carto project.mml > style.xml
exit

Fonts 설치
맵에 사용될 폰트로 설치한다.
sudo apt install ttf-dejavu
sudo apt install fonts-noto-cjk fonts-noto-hinted fonts-noto-unhinted ttf-unifont

renderd 설정
renderd를 다음과 같이 설정한다.
sudo nano /etc/renderd.conf
num_threads=4
XML=/home/osm/openstreetmap-carto-4.20.0/style.xml
HOST=map.your-domain.com

plugins_dir=/usr/lib/mapnik/3.0/input/
mapnik-config --input-plugins

font_dir=/usr/share/fonts/truetype
font_dir_recurse=true

sudo nano /etc/init.d/renderd
RUNASUSER=osm

renderd를 실행한다.
sudo chown osm:osm /var/lib/mod_tile/ -R
sudo systemctl daemon-reload
sudo systemctl restart renderd
sudo journalctl -eu renderd

Apache 설정
아파치 웹 서버를 설정한다.
sudo nano /etc/apache2/sites-available/tileserver_site.conf
ServerName map.yourdomain.com
sudo systemctl restart apache2
map.your-domain.com/osm/0/0/0.png
osm-tile-for-world-map

Tiled Web Map 표시
openlayers를 다운로드해 설치한다.
cd /var/www/
sudo wget https://github.com/openlayers/openlayers/releases/download/v5.3.0/v5.3.0.zip
sudo unzip v5.3.0.zip

index.html file 생성
index파일을 아래와 같이 수정한다.
sudo nano /var/www/index.html

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Accessible Map</title>
<link rel="stylesheet" href="http://map.yourdomain.com/v5.3.0/css/ol.css" type="text/css">
<script src="http://map.yourdomain.com/v5.3.0/build/ol.js"></script>
<style>
  a.skiplink {
    position: absolute;
    clip: rect(1px, 1px, 1px, 1px);
    padding: 0;
    border: 0;
    height: 1px;
    width: 1px;
    overflow: hidden;
  }
  a.skiplink:focus {
    clip: auto;
    height: auto;
    width: auto;
    background-color: #fff;
    padding: 0.3em;
  }
  #map:focus {
    outline: #4A74A8 solid 0.15em;
  }
</style>
</head>
<body>
  <a class="skiplink" href="#map">Go to map</a>
  <div id="map" class="map" tabindex="0"></div>
  <button id="zoom-out">Zoom out</button>
  <button id="zoom-in">Zoom in</button>
  <script>
    var map = new ol.Map({
      layers: [
        new ol.layer.Tile({
          source: new ol.source.OSM({
             url: 'http://map.yourdomain.com/osm/{z}/{x}/{y}.png'
          })
       })
     ],
     target: 'map',
     controls: ol.control.defaults({
        attributionOptions: /** @type {olx.control.AttributionOptions} */ ({
          collapsible: false
        })
     }),
    view: new ol.View({
       center: [244780.24508882355, 7386452.183179816],
       zoom:5
    })
 });

  document.getElementById('zoom-out').onclick = function() {
    var view = map.getView();
    var zoom = view.getZoom();
    view.setZoom(zoom - 1);
  };

  document.getElementById('zoom-in').onclick = function() {
     var view = map.getView();
     var zoom = view.getZoom();
     view.setZoom(zoom + 1);
  };
</script>
</body>
</html>

다음과 같이 leaflet 패키지를 설치한다.
cd /var/www/
sudo wget http://cdn.leafletjs.com/leaflet/v1.4.0/leaflet.zip
sudo unzip leaflet.zip

index파일에 leaflet을 사용할 수 있도록 지정한다.
sudo nano /var/www/index.html

<html>
<head>
<meta charset="UTF-8">
<title>My first osm</title>
<link rel="stylesheet" type="text/css" href="leaflet.css"/>
<script type="text/javascript" src="leaflet.js"></script>
<style>
   #map{width:100%;height:100%}
</style>
</head>

<body>
  <div id="map"></div>
  <script>
    var map = L.map('map').setView([53.555,9.899],5);
    L.tileLayer('http://map.yourdomain.com/osm/{z}/{x}/{y}.png',{maxZoom:18}).addTo(map);
</script>
</body>
</html>

map.yourdomain.com/index.html

Pre-render Tiles
지도 타일을 렌더링한다.
render_list -m default -a -z 0 -Z 15 --num-threads=8
render_list -m default -a -z 0 -Z 15 --num-threads=8 --force
sudo add-apt-repository ppa:certbot/certbot
sudo apt install certbot
sudo apt install python3-certbot-apache
sudo certbot --apache --agree-tos --redirect --hsts --staple-ocsp --must-staple --email
osm tile server ubuntu 18.04 install

sudo a2enmod http2
sudo nano /etc/apache2/sites-enabled/tileserver_site-le-ssl.conf
Protocols h2 http/1.1
sudo systemctl restart apache2
nano /home/osm/openstreetmap-carto-4.20.0/project.mml

osm2pgsql: &osm2pgsql
  type: "postgis"
  dbname: "gis"
  key_field: ""
  geometry_field: "way"
  extent: "-20037508,-20037508,20037508,20037508"
Specify the IP address of PostgreSQL database server.

osm2pgsql: &osm2pgsql
  type: "postgis"
  host: "10.0.0.2"
  dbname: "gis"
  key_field: ""
  geometry_field: "way"
  extent: "-20037508,-20037508,20037508,20037508"

스타일을 설정하고, postgresql과 renderd를 재시작한다.
carto project.mml > style.xml
sudo nano /etc/postgresql/10/main/postgresql.conf
sudo nano /etc/postgresql/10/main/pg_hba.conf
host   gis   osm   10.0.0.1/32   trust
sudo systemctl restart postgresql
sudo systemctl restart renderd

sudo journalctl -eu renderd
sudo ufw allow in from 10.0.0.1 to any port 5432

레퍼런스

댓글 없음:

댓글 쓰기