僕の地球を作って！そろそろOpenStreetMapタイルサーバは数秒で構築できるようにしようよ。

今まで何度かOpenStreetMapのタイルサーバーを作っているのですが、時間をかけて同じ作業を何回もしてきました。色々忘れちゃうし、データベースへの展開にも時間がかかるし、一日仕事的な感じですよね。

ということで、今回は「なるべく時間をかけずに」「簡単に」自分の地図サーバを作れることを目標に、Dockerコンテナを作成しましたので、皆さんに共有したいと思います。

あと、各地域の地図を使いたい場合は、地図データを外部のPostgreSQLに入れたほうが良いので、Azure Database for PostgreSQLも使いつつ、より大きな地図データを使う方法も紹介したいと思います。

# 1. Dockerコンテナ単体で動かすOpenStreetMapのタイルサーバー
まずは、Dockerコンテナ単体で動かすOpenStreetMapのタイルサーバーです。このタイルサーバーは、各地域の形と南極大陸のデータで作成しています。
## 1.2. 構築と起動方法
Dockerを使ってビルドします。Dockerのインストール方法は[こちら](https://docs.docker.com/get-docker/ "Get Docker")をご参照ください。

```sh
git clone https://github.com/KentaroAOKI/openstreetmap-docker.git
cd openstreetmap-docker
docker build -t openstreetmaptile .
```

これだけで終わりです。ビルドにはそこそこ時間がかかるのでビルド済みイメージを使いたい人は以下のコマンドを実行してください。

```sh
docker pull kekekekenta/openstreetmaptile
docker rename kekekekenta/openstreetmaptile openstreetmaptile
```


以下のコマンドで起動してみます。（起動時はRenderdのデータベース設定の初期化処理が動きますので、Webサービスが立ち上がるまで少し待ちます）

```sh
docker run -d -p 8080:80 openstreetmaptile
```

ローカルの環境で動かした場合は、以下のURLにアクセスしてみてください。日本地域のデータは入っていないので形だけですが、動くことを確認できたと思います。（Azureなどのクラウドで起動した場合は、ホスト名の変更とポートのセキュリティ設定の確認が必要です）

http://localhost:8080/sample_leaflet.html#6/39.215/135.637

私は、Winsows 10 (WSL2 Backend) で動かしましたが、以下のような感じで表示されたと思います。（Azureなどのクラウドで起動した場合は、ホスト名の確認と、ポートのセキュリティ設定を確認してください）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/32580/da97b5cf-3b09-b687-8944-d89023bb8f2f.png)

# 2. Dockerコンテナと外部のPostgreSQLを使用して、各地域のOpenStreetMapデータを使う
Dockerコンテナ内に各地域のOpenStreetMapデータを入れるのは現実的じゃないので、外部のPostgreSQLを使う方法も紹介します。

## 2.1. PostgreSQLを構築

まずは、PostgreSQLを作ります。ここは皆さんがお持ちの環境もあると思いますので、不要な方は読み飛ばしてください。今回は、簡単に作ることを目標にしていますので、Azure Database for PostgreSQL を使いたいと思います。

まずは、Azureポータルから新規のAzure Database for PostgreSQLを選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/32580/70cd4767-0a7e-2e3c-7ef8-e230eab24e04.png)

Azure Database for PostgreSQL は特徴のある4つの構成から選ぶことができます。今回は「単一サーバー」を選択していますが、プレビューでも問題ない方は、フレキシブルサーバを使ったほうが良いと思います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/32580/f67aa0bf-51e9-4639-0034-48c61948290e.png)

バージョンは12でもかまいませんが今回は10を選択します。ストレージサイズによりIOPSの上限が変わります。できるだけ速く処理させたい場合は大きなサイズを選んでください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/32580/21f14c54-3781-468b-d489-47252a011940.png)

最後に、Dockerコンテナからのアクセスを許可するように、接続のセキュリティ設定も忘れないようにしてください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/32580/f8dc409c-81f5-93c1-68d8-baac6b15358e.png)

## 2.2. PostgreSQLのデータベースを初期化する
PostgreSQLの準備が整ったらOpenStreetMapのタイルサーバー向けにデーターベースを初期化します。

Dockerコンテナでは、以下の環境変数を用意しています。PostgreSQLの接続情報を環境変数に設定することにより外部のPostgreSQLを使うことができます。
- PSQL_HOST : PostgreSQLのホスト名を設定します。 (デフォルト設定は "localhost" です)
- PSQL_PORT :  PostgreSQLのポート番号を設定します。(デフォルト設定は  "5432" です)
- PSQL_USERNAME :  PostgreSQLの管理者を設定します。(デフォルト設定は  "postgres" です)
- PSQL_PASSWORD :  PostgreSQLの管理者パスワードを設定します。(デフォルト設定は  "postgrespassword" です)
- PSQL_DBNAME : 作成するデータベース名を設定します。 (デフォルト設定は  "gis" です)

データベースの作成は以下のようにDockerコンテナを実行します。

```sh
docker run -ti -e PSQL_HOST=xxxx.postgres.database.azure.com -e PSQL_USERNAME=xxx@xxx -e PSQL_PASSWORD=xxxx openstreetmaptile scripts/01_initialize_database.sh
```

次に、地図データをデーターベースに書き込みます。（ここでは南極大陸のデータを書き込みます）

```sh
docker run -ti -e PSQL_HOST=xxxx.postgres.database.azure.com -e PSQL_USERNAME=xxx@xxx -e PSQL_PASSWORD=xxxx openstreetmaptile scripts/02_write_osm.sh
```

最後に、各地域の形などExternalのデータを書き込みます。

```sh
docker run -ti -e PSQL_HOST=xxxx.postgres.database.azure.com -e PSQL_USERNAME=xxx@xxx -e PSQL_PASSWORD=xxxx openstreetmaptile scripts/03_write_external.sh
```

## 2.3. 外部のPostgreSQLに地図データを追加する
地図を追加する場合は、[Geofabrik GmbH の OpenStreetMap Data Extracts](https://download.geofabrik.de/)から取得します。

https://download.geofabrik.de/

例えば、日本の地図の場合は以下のように"asia/japan-latest.osm.pbf"をコマンドに渡します。

```sh
docker run -ti -e PSQL_HOST=xxxx.postgres.database.azure.com -e PSQL_USERNAME=xxx@xxx -e PSQL_PASSWORD=xxxx openstreetmaptile scripts/append_osm.sh asia/japan-latest.osm.pbf
```

## 2.4. 外部のPostgreSQLを使って動かす
外部のPostgreSQLを使用してOpenStreetMapのタイルサーバーを動かす時も、環境変数にPostgreSQLの接続情報を指定してください。

```sh
docker run -d -p 8080:80 -e PSQL_HOST=xxxx.postgres.database.azure.com -e PSQL_USERNAME=xxx@xxx -e PSQL_PASSWORD=xxxx openstreetmaptile
```

日本の地図が入りましたね。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/32580/a8966cf6-d3c9-6e77-055e-7221ac8b77b0.png)

# 3. 作成されたタイル画像を再利用する
Webページに表示される地図の画像は、Dockerコンテナ内でキャッシュされています。そのためコンテナを起動しなおすと、もう一度地図の画像を作り直すため表示に時間がかかってしまいます。そのため、以下のようにストレージをマウントして起動してもいいかもしれません。

```
docker run -d -p 80:80 -e PSQL_HOST=xxxx.postgres.database.azure.com -v /home/user/mod_tile:/var/lib/mod_tile openstreetmaptile
```

さらに、マウントした先のファイルシステムをfuseでAzuer Storage Blobにマウントすると更に再利用が進みますね。

[blobfuse を使用して Blob Storage をファイル システムとしてマウントする方法](https://docs.microsoft.com/ja-jp/azure/storage/blobs/storage-how-to-mount-container-linux)

# 4. さいごに
いままで何度も休日を潰していましたが、これからは更に進めた実験に時間が使えそうです。
ではー。