smellman's Broken Diary

クソみたいなもんです

OpenMapTiles/Tileserver-GL/MaputnikによるMapbox Vector TileのOSS実装環境のまとめ

本記事はOpenStreetMap Advent Calendar 2017の12月10日付けの記事となります。

昨年からosm2vectortilesを検証しだし、今年はOpenMapTilesによる検証及び実運用を進めていたので、とりあえずこの界隈をまとめようと思います。
ただ、主な内容はOpenStreetMapのMapbox Vector Tileを作ってみた その2 、あとスタイルの編集とかフォントとかからあまり変わっては居ません。

まず、今回取り扱うプログラムの簡単な説明をしたいと思います。

OpenMapTiles
OpenStreetMapのデータからMapbox Vector Tileを生成するためのプログラム群
Tileserver-GL
Mapbox Vector Tileの配信用サーバ兼レンダリングサーバ
Maputnik
Mapbox-GL Styleのエディタ

一般的なワークフローとしては、まずOpenMapTilesでMapbox Vector Tileを作成し、Tileserver-GLでMapbox Vector Tileを配信させ、MaputnikでMapbox-GL Styleを作成して、Tileserver-GLで作成したMapbox-GL Styleを配信させるという流れになります。

ここでややこしいのがTileserver-GLがタイルとスタイルを両方配信する役目を持っているということです。実際、タイルとスタイルがないとMapbox GL上で地図がレンダリングできないため、これがセットで配信できるという風に理解していただきたいです。

なお、Mapbox社は上記に該当するものを全てサービスとして提供をしていますが、使ったことがないのでわかりません(汗
なので、少なくとも本記事ではMapbox社のサービス自体と比較するというものではありません。

では、それぞれのプログラムの解説及び今年一年で変わった部分などを解説していきます。

OpenMapTiles

OpenMapTilesは前述通りOpenStreetMapのデータからMapbox Vector Tileを生成するプログラム群というものになります。
各処理をDockerコンテナで行うことで処理毎に開発、メンテナンスがされているという特長があります。

今年大きく変わったところは以下のものが挙げられます。

  • Multi Languageサポート(v3.6): デフォルトで35言語のインポートを可能にしていて、対応言語の変更も可能です。これはMapbox GL JSなどで動的に表示言語を変更するのに役に立ちます。
  • Wikidataのインポートをサポート(v3.7): これはOSMのデータよりもWikidataの方が多言語対応のデータを多く含んでいるということから、上記のMulti Languageサポートをより強力にするために取り込みをおこないます。
  • postserveの提供: 今年追加されたdockerコンテナで、ST_AsMVTを利用してPostgisのデータから直接Mapbox Vector Tileを出力するというものです。

他にもレイヤーの追加や、インポート対象のデータの更新や対象のズームレベルの変更など様々な変更が入っています。

また、この一年でインポートにかかる時間が増えました。
Thinkpad X220 (Core i5 4core, SSD 256GB, Memory 16GB)のマシンで計測したところZ14でたしか夜間ぐらいで終わっていたものが計測したところ16時間ぐらいかかるようになっています。
しかしながら、取り込みのスピードとしてはそこまで問題にならないかと思います。

また、postserveが提供されているため、OSMのデータをインポート後に直接postserveで運用するという手もあります。
実際のところpostserveの開発者はvarnishと組み合わせて配信をしているようです*1

では、とりあえずOpenMapTilesの作成手順を簡単にまとめましょう。

まず用意するのは docker-compose が動作する環境です。Ubuntu 17.10であれば、以下のようにします。

sudo apt-get install docker.io
sudo curl -L https://github.com/docker/compose/releases/download/1.17.0/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
sudo usermod -aG docker $USER
sudo reboot
docker run hello-world # 一般ユーザで動作確認
docker-compose -v

以上でセットアップが完了です。

あとはOpenMapTilesを取得して構築を行います。

git clone https://github.com/openmaptiles/openmaptiles.git
cd openmaptiles
git checkout -b origin/v3.7 v3.7
vim .env # QUICKSTART_MAX_ZOOM=14に変更
./quickstart.sh japan

最終的なアウトプットは data/tiles.mbtiles になります。
ここらへんは今年の初めあたりからはほぼ変わっていません。

では、続いてTileserver-GLの話をします。

Tileserver-GL

Tileserver-GLはMapbox Vector Tileの配信用サーバ兼レンダリングサーバとなります。
こちらもDockerによる運用が簡単なのがポイントです。
弊社でも現在二件ほどTileserver-GL+Dockerで運用を行っています。

大きな変更点は今年にかけてエントリーポイントのURLが変更になったことです。
詳しい情報はAvailable Endpointを参考にしてください。
このため、以前から運用中のものはURLなどの変更が必要になるのに注意が必要です。

動作方法はいろいろありますが、実運用として使うのであればdocker-composeとVarnish cacheによる運用をおすすめします。
実際にこの運用の構築手順を見ていきましょう。

まず最初に tileserver-gl を動作させるところまで持っていきます。
最初に運用をするサーバにmbtilesをコピーします。

scp data/tiles.mbtiles example.com:/tmp/japan.mbtiles

次にtileserver-glが起動をするかどうかを確認します。

mkdir ~/tiles
cp /tmp/japan.mbtiles ~/tiles
cd ~/tiles
docker pull klokantech/tileserver-gl
docker run -it -v $(pwd):/data -p 8080:80 klokantech/tileserver-gl
curl http://localhost:8080/data/v3.json

これでアクセスできたら成功です。

次に、config.jsonファイルを作成します。
現段階では最小限のファイルだけ作成します。

vim config.json
{
  "data": {
    "japan-vector": {
      "mbtiles": "japan.mbtiles"
    }
  }
}
docker run -it -v $(pwd):/data -p 8080:80 klokantech/tileserver-gl
curl http://localhost:8080/data/japan-vector.json

なお、この状態ではスタイルの配信を行っていない状態になります。

では、もう少し踏み込んでセットアップをしていきます。
今度はMapbox GL Styleが参照する font と sprite 、および style のディレクトリの用意をします。
今回は解説が面倒なのでフォントはgithubにアップロードしているものを取ってきます。

wget https://github.com/openmaptiles/fonts/releases/download/v1.1/v1.1.zip
mkdir fonts
cd fonts
unzip ../v1.1.zip
cd ..
mkdir sprites
mkdir styles

この段階で以下のような構成になっているはずです。

.
├── config.json
├── fonts
├── japan.mbtiles
├── sprites
└── styles

では、上記ディレクトリ構成をconfig.jsonに反映させます。

vim config.json
{
  "options": {
    "paths": {
      "root": "",
      "fonts": "fonts",
      "sprites": "sprites",
      "styles": "styles",
      "mbtiles": ""
    }
  },
  "styles": {
  },
  "data": {
    "japan-vector": {
      "mbtiles": "japan.mbtiles"
    }
  }
}

スタイルは後述するMaputnikで扱うので、次にこれをdocker-composeで動かせるようにしましょう。

vim docker-compose.yaml
version: '2'
services:
  varnish:
    image: eeacms/varnish
    ports:
    - "6081:6081"
    depends_on:
    - raster-tileserver
    environment:
      BACKENDS: "raster-tileserver"
      BACKENDS_PORT: "80"
      BACKENDS_PROBE_INTERVAL: "10s"
      BACKENDS_PROBE_TIMEOUT: "2s"
      DNS_ENABLED: "true"
    restart: always
  vector-tileserver:
    image: klokantech/tileserver-gl
    ports:
    - "8080:80"
    volumes:
    - .:/data
    restart: always
  raster-tileserver:
    image: klokantech/tileserver-gl
    volumes:
    - .:/data
    restart: always

上記のdocker-compose.yamlで行っているのは vector tile と raster tile の配信をわけ、raster tileの配信を Varnish Cache でまとめるというものです*2
なお、向き先の変更についてはnginxなどで行っています。
実運用の環境では以下のようにしています。

  location / {
    proxy_set_header X-Forwarded-Proto https;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $http_host;
    proxy_pass http://localhost:8080;
  }

  location ~ ^/.*\.png {
    proxy_set_header X-Forwarded-Proto https;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $http_host;
    proxy_pass http://localhost:6081;
  }

また、実運用時にはdocker-compose scaleを使って処理が重たい raster tile のサーバの台数を変更することで効率よくCPUを利用するようにしています。

docker-compose up -d
docker-compose scale raster-tileserver=3

では、最後にMaputnikについてお話します。

Maputnik

これも今年はじめの記事から対してあまり変わっていないというか、むしろ maputnik.com のドメイン更新を怠ったので大変なことになりました(汗

Maputnikは現在のMapbox社のエディタのクローンとして誕生したものです。
実装には React を使っていて、現在は github.io にホスティングされているものか、もしくはローカル環境で起動したものが利用できます。
今回は localhost 上で一度スタイルの設定をしたいので、 docker 環境を作ってしまいましょう*3

git clone git@github.com:maputnik/editor.git
cd editor
docker build -t maputnik:latest .
docker run -it -p 8888:8888 maputnik

あとは http://localhost:8888 にアクセスをして Open からベースとなるスタイルを選択して Export から Download を選択して JSON ファイルを保存します。

次にこのjsonファイルをtileserver-glのstylesにコピーをします。

scp ~/Downloads/ciwhogehoge.json example.com:~/tiles/styles/mydesign.json

次にサーバ上で mydesign.json を編集し、以下の場所を書き換えます。

sources.openmaptiles.url
"mbtiles:{japan-vector}"
glyphs
"{fontstack}/{range}.pbf"
sprite
"スプライト画像のpath"

なお、spriteは必要に応じて変更してください。
というのも、sprite画像自体は元々提供されているデザインと対になってデザインされているケースが多いので、その場合は必要に応じてwgetなどで取得してください。

cd sprites
wget https://raw.githubusercontent.com/lukasmartinelli/osm-liberty/gh-pages/sprites/osm-liberty.json
wget https://raw.githubusercontent.com/lukasmartinelli/osm-liberty/gh-pages/sprites/osm-liberty.png
wget https://raw.githubusercontent.com/lukasmartinelli/osm-liberty/gh-pages/sprites/osm-liberty%402x.json
wget https://raw.githubusercontent.com/lukasmartinelli/osm-liberty/gh-pages/sprites/osm-liberty%402x.png

このようにした場合は sprite の値は "osm-liberty" となります。

では、今回は osm-liberty をベースに処理をしてみます。

vim styles/mydesign.json #sources.openmaptiles.url, glyphs, spriteを編集
vim config.json
{
  "options": {
    "paths": {
      "root": "",
      "fonts": "fonts",
      "sprites": "sprites",
      "styles": "styles",
      "mbtiles": ""
    }
  },
  "styles": {
    "mydesign": {
      "style": "mydesign.json"
    }
  },
  "data": {
    "japan-vector": {
      "mbtiles": "japan.mbtiles"
    }
  }
}

これでdocker-composeを再起動するとデザインが追加され、Viewerからアクセスが可能になります。
あとはnginxなどをセットアップすれば完成です。

なお、この後デザインを変更する場合はGL Styleのリンクをダウンロードしてmaputnikで編集をすればOKです。
また、一旦httpsでアクセス可能になれば maputnik をローカルで立ち上げずに作業することができるので、デプロイは面倒ですが共同編集のようなことが可能になります。

OpenMapTiles Map Server

ここまで3つのOSSをベースに話をしてきましたが、OpenMapTiles自体に大きな動きがあり、OpenMapTilesを運営しているKlokanTechが簡単に OpenMapTiles のホスティングまでを可能にするサービスを開始しました。

それが、 OpenMapTile Map Server です。

OpenMapTiles Map Server

これは Docker のインスタンス1つでOpenMapTilesがホスティングしてるMapbox Vector Tileのダウンロードや展開を可能にする物で、 MacWindowsであれば Kitematic を使って簡単に動かすことが可能です。
詳しいことは以前雑にまとめたので適当にみてください。

speakerdeck.com

というわけでOpenMapTiles周りは商業まわりも頑張っているようです。

来年に向けてのトピック

さて、今年の分のおさらいをしたのですが、来年に向けて1つホットな話題があります。
それが、Mapbox Vector Tileを使ったNative Clientの台頭です。

まず、大きなポイントとしては Mapbox GL の React Native 対応が安定してきました。

github.com

先日、React Native Mapbox GL を使って簡単なクライアントを作成してみたのですが、期待通りの動きをしてくれました。
ただ、Mapbox GL の Native 版については起動制限などがあるのではないかという話があり、どのように回避していくのかが気になるところです。
今のところは "pk.NO_ACCESS_TOKEN" とかいうTokenを入れておくとザルなのと、そもそもTokenのチェックの仕方がandroidの方が厳しいというよくわからない実装になっているので、具体的なところはよくわかっていません。

また、Native対応という点では Mapzen の Tangram ES という OpenGL ES を使ったライブラリもあります。

github.com

これは Tangram *4という Leaflet JS 上で WebGL を使ったレンダリングをするためのライブラリの Native 版という存在です。
Mapbox GL Styleとは違い、シーンの表現に yaml を採用したものとなっていて、また対応しているベクトルタイルの種類が豊富という利点もあります。

これらのライブラリが台頭してくることにより、よりOpenMapTilesを使ったサービス展開などが望めるかもしれません。

資料など

今年はOpenMapTilesについていろいろと喋りましたので、その資料とか貼っておきます。

State of the Map 2017 発表資料(えせ英語)と動画(えせ英語)

speakerdeck.com


State of the Map 2017 - Friday Room 1 10:30 to 13:00

(やばい、State of the Mapの動画編集まだ終わってないorz)

FOSS4G Tokyo 2017 ハンズオンデイ資料

speakerdeck.com

FOSS4G Tokyo 2017 コアデイ資料

speakerdeck.com

(やばい、FOSS4G Tokyo 2017 コアデイの動画編集まだ終わってないorz)

*1:ただし、postserveは直接gzip圧縮したファイルを出力していないのに注意してください

*2:実際には png 画像だけ raster tile の方に振り分けています

*3:現在リリースされているバージョンは古いのですが、静的なWebアプリケーションなのでPythonやNodeでWebサーバを立てるだけでローカルでも動きます

*4:Tangram JSと言ったほうが良いのかもしれないが、正式にはTangramのはず