LoginSignup
18
17

More than 5 years have passed since last update.

Open Street Map独自タイルサーバをAmazon Elastic Container Serviceで稼働させる

Posted at

はじめに

Google Maps API関連の契約が大きく変更され、Open Street Map(以下、OSM)を使うサイトが増えたかなと感じる今日この頃。
OSMは無料で使えるのだけど、少し日本人離れしているデザインなので、自前で環境構築した方がOSM本家に迷惑もかからないし、便利かなと思います。

この記事のサーバ環境は、Amazon Elastic Container Service(以下、ECS)を使っています。
オンプレミスのサーバやローカル環境でも、Dockerが使える環境であれば動かせます。

ベースとなるコンテナイメージは、海外の方が作られたものを、クローンさせて使わさせていただいております。
また、この記事で対象にしているOSMのリージョンは北海道です。

OSMタイルサーバをECSで動かしている記事が見当たらなかったので、思い切って記事にしました。

仕上がりイメージ

北海道大学付近です。めちゃくちゃ賑やかですね。
タイル画像は、ズームレベル20までレンダリングする設定になっていますので、拡大しても綺麗です。

スクリーンショット 2018-12-07 16.40.05.png

事前準備

ある程度の知識と技術、用意するものが必要です。
Dockerコンテナイメージは、私が用意してあるものをお使いいただけます。

必要な知識

  • Dockerに関する知識
  • AWSに関する知識

用意するもの

  • Dockerコンテナ実行環境
  • AWS環境 (VPCやIAM周りの設定が事前に必要なので、各自で用意してくださいね)

マシンスペックは、1コア、2GB程度のメモリが必要です。

サーバ準備

実行環境であるサーバを用意します。
コンソールからやるか、CloudFormation(CFn)でサクッと用意しちゃいましょう。
ECSのクラスタ名は、「osm-tile」にしました。

高スペックなマシーンは不要ですし、お安いスポットインスタンスを有効に使いましょう。
t2.smallくらいのスペックで十分かと思います。
ケチってt2.microにすると、osm2pgsqlでエラーになりました。
ECSは仮想メモリ割り当て設定がないので、ごにょごにょすれば行けそうな気もします。
インポート時のメモリ割り当てを変更するでも良いと思います。
最初のレンダリングには若干時間がかかりますが、キャッシュしてしまえばレスポンスも良いです。

ディスクは、12GBを割り当てています。
リージョンによってはもっと大きい容量が必要ですので、ご注意ください。
北海道は、インポート後5GBくらい、タイルのキャッシュに数GB必要になりますので、不要なタイル画像はクリーニングしましょう。
EBSは、オンラインで拡張することが出来ますので、あまり気にならないかもしれません。

ガチで運用するなら、リザーブドインスタンスにするとか、Blue/Green Deploymentとか、色々とやることはあるのですが、リバースプロキシのキャッシュ機能を使うことも出来るので、要件に応じて各自でいろいろとご検討ください。

osm-tile.yml
AWSTemplateFormatVersion: '2010-09-09'
Description: 'Open Street Map Tile Service ECS Template Spot Instance.'

Parameters:
  Ec2KeyName:
    Description: EC2 SSH KEY
    Type: AWS::EC2::KeyPair::KeyName
    Default: HOGEFUGA-KEY

  Ec2InstanceType:
    Description: EC2 Instance type
    Type: String
    Default: t2.small
    AllowedValues:
    - t2.nano
    - t2.micro
    - t2.small
    - t2.medium
    - t2.large
    ConstraintDescription: must be a valid EC2 instance type.

  Ec2ImageId:
    Description: amzn-ami-2018.03.h-amazon-ecs-optimized
    Type: String
    Default: ami-0edf19001c48838c7

Resources:
  Ec2InstanceLaunchConfig:
    Type: AWS::AutoScaling::LaunchConfiguration
    Properties:
      InstanceType: !Ref 'Ec2InstanceType'
      KeyName: !Ref 'Ec2KeyName'
      ImageId: !Ref 'Ec2ImageId'
      IamInstanceProfile: 'arn:aws:iam::************:instance-profile/ecsInstanceRole'
      BlockDeviceMappings:
        - DeviceName: '/dev/xvdcz'
          Ebs:
            VolumeSize: 22
            VolumeType: gp2
        - DeviceName: '/dev/xvda'
          Ebs:
            VolumeSize: 12
            VolumeType: gp2
      SecurityGroups:
        - sg-********
      AssociatePublicIpAddress: 'false'
      InstanceMonitoring: 'false'
      SpotPrice: "0.02"
      UserData:
        Fn::Base64: |
          #!/bin/bash

          # Specify the cluster that the container instance should register into
          cluster=osm-tile

          echo ECS_CLUSTER=$cluster >> /etc/ecs/ecs.config;echo ECS_BACKEND_HOST= >> /etc/ecs/ecs.config;
          # yum
          yum -y install jq wget aws-cli

  Ec2InstanceAutoScalingGroup2:
    Type: AWS::AutoScaling::AutoScalingGroup
    Properties:
      VPCZoneIdentifier:
        - 'subnet-********'
      LaunchConfigurationName: !Ref 'Ec2InstanceLaunchConfig'
      MinSize: 0
      MaxSize: 1
      DesiredCapacity: 1
      TerminationPolicies:
        - OldestInstance

  ECSClusterFront:
    Type: AWS::ECS::Cluster
    Properties:
      ClusterName: osm-tile

awscliでスタックを作成します。
コマンドがよく分からない方は、Webコンソール画面からでも利用できます。

$ aws cloudformation create-stack \
--stack-name osm-tile \
--template-body file:///Users/******/osm-tile.yml \
--tags Key=Name,Value=osm-tile \
  Key=Author,Value=hogefuga \
--parameters ParameterKey=Ec2KeyName,ParameterValue=HOGEFUGA-KEY \
  ParameterKey=Ec2InstanceType,ParameterValue=t2.small

{
    "StackId": "arn:aws:cloudformation:ap-northeast-1:************:stack/osm-tile/d04f2e50-f8fb-11e8-ac84-0e2c94******"
}

インスタンス起動まで待ちましょう。3分くらいかかります。
ダッシュボードの表示にインスタンスが増えればOKです。

スクリーンショット 2018-12-07 16.59.08.png

Dockerコンテナの定義

コンテナイメージは以下のものを使います。
あれ?北海道しかないじゃん!!
そうです。
北海道エリアだけインポートしているので、使用する地域に合わせてDockerfileを変更してください。

ECSを使うので、タスク定義を作成しましょう。
docker-compose.ymlから作成することも出来ます。

コマンド例

$ ecs-cli compose \
  -f docker-compose.yml \
  --project-name osm-tile-project \
  --cluster osm-tile \
  create

リポジトリに置いてありますので、参考にしてください。
https://github.com/akikinyan/melbourne-map/blob/develop/docker-compose.yml

ECSは、相対ディレクトリ指定運用が難しいので、最新のコンテナイメージは相対パス指定を不要にしています。
コンテナ内に、config.jsonファイルを追加しただけなんですけどね。
「./data」はデータボリュームでもOKです。
最近、ECSもデータボリュームが使えるようになりました。
「./renderer」は記述不要としました。

とりあえずそのまま載せておきます。

dockerfile
version: '2'
services:
  postgis:
    build: ./postgis
    image: akikinyan/osm-postgis:latest
    volumes:
      - ./data:/var/lib/postgresql/data
    environment:
      - POSTGRES_DB=gis
  renderer:
    build: ./renderer
    image: akikinyan/osm-renderer:latest
    volumes:
      - ./renderer/map_data:/map_data
      - ./renderer/scripts:/scripts
    volumes_from:
      - postgis:ro
    ports:
      - "8080:8080"
      - "9090:9090"
    depends_on:
      - postgis
  web:
    image: nginx:1.11-alpine
    volumes:
      - ./web:/usr/share/nginx/html
    ports:
      - "8888:80"

タスク定義

最終的なイメージを載せておきます。
Webコンテナは、別な環境からアクセスするため、作成しませんでした。
最近は、Blue-Green Deploymentの方がいいかなぁと思うので、レンダリング部分とデータベース部分を分離しておいた方が良いかもしれませんが、このOSMコンテナは一緒でも良いような気もします。

ちなみに、Application Load Balancer配下に環境を設置する場合は、ポート番号を適宜変更してください。
試した感じでは、レンダリングサーバが、コンテキストパスを良い感じで処理してくれるようなので、コンテキストパスは任意のもので良さそうです。
(時間の都合でどういう仕組みなのかは把握してないです)

スクリーンショット 2018-12-07 15.22.50.png

{
  "ipcMode": null,
  "executionRoleArn": null,
  "containerDefinitions": [
    {
      "dnsSearchDomains": [],
      "logConfiguration": {
        "logDriver": "none",
        "options": null
      },
      "entryPoint": [],
      "portMappings": [],
      "command": [],
      "linuxParameters": {
        "capabilities": {
          "add": null,
          "drop": null
        },
        "sharedMemorySize": null,
        "tmpfs": null,
        "devices": null,
        "initProcessEnabled": null
      },
      "cpu": 0,
      "environment": [
        {
          "name": "POSTGRES_DB",
          "value": "gis"
        }
      ],
      "ulimits": null,
      "dnsServers": [],
      "mountPoints": [
        {
          "readOnly": false,
          "containerPath": "/var/lib/postgresql/data",
          "sourceVolume": "volume-0"
        }
      ],
      "workingDirectory": null,
      "secrets": null,
      "dockerSecurityOptions": [],
      "memory": null,
      "memoryReservation": 256,
      "volumesFrom": [],
      "image": "akikinyan/osm-postgis:latest",
      "disableNetworking": null,
      "interactive": null,
      "healthCheck": null,
      "essential": true,
      "links": [],
      "hostname": null,
      "extraHosts": null,
      "pseudoTerminal": null,
      "user": null,
      "readonlyRootFilesystem": false,
      "dockerLabels": null,
      "systemControls": null,
      "privileged": false,
      "name": "postgis"
    },
    {
      "dnsSearchDomains": [],
      "logConfiguration": {
        "logDriver": "none",
        "options": null
      },
      "entryPoint": [],
      "portMappings": [
        {
          "hostPort": 8080,
          "protocol": "tcp",
          "containerPort": 8080
        }
      ],
      "command": [],
      "linuxParameters": {
        "capabilities": {
          "add": null,
          "drop": null
        },
        "sharedMemorySize": null,
        "tmpfs": null,
        "devices": null,
        "initProcessEnabled": null
      },
      "cpu": 0,
      "environment": [],
      "ulimits": null,
      "dnsServers": [],
      "mountPoints": [],
      "workingDirectory": null,
      "secrets": null,
      "dockerSecurityOptions": [],
      "memory": null,
      "memoryReservation": 256,
      "volumesFrom": [
        {
          "sourceContainer": "postgis",
          "readOnly": true
        }
      ],
      "image": "akikinyan/osm-renderer:latest",
      "disableNetworking": null,
      "interactive": null,
      "healthCheck": null,
      "essential": true,
      "links": [
        "postgis:postgis"
      ],
      "hostname": null,
      "extraHosts": null,
      "pseudoTerminal": null,
      "user": null,
      "readonlyRootFilesystem": false,
      "dockerLabels": null,
      "systemControls": null,
      "privileged": false,
      "name": "renderer"
    }
  ],
  "placementConstraints": [],
  "memory": null,
  "taskRoleArn": null,
  "compatibilities": [
    "EC2"
  ],
  "taskDefinitionArn": "arn:aws:ecs:ap-northeast-1:************:task-definition/osm-tile-service:1",
  "family": "osm-tile-service",
  "requiresAttributes": [
    {
      "targetId": null,
      "targetType": null,
      "value": null,
      "name": "com.amazonaws.ecs.capability.docker-remote-api.1.17"
    },
    {
      "targetId": null,
      "targetType": null,
      "value": null,
      "name": "com.amazonaws.ecs.capability.docker-remote-api.1.25"
    },
    {
      "targetId": null,
      "targetType": null,
      "value": null,
      "name": "com.amazonaws.ecs.capability.docker-remote-api.1.18"
    },
    {
      "targetId": null,
      "targetType": null,
      "value": null,
      "name": "ecs.capability.docker-plugin.local"
    },
    {
      "targetId": null,
      "targetType": null,
      "value": null,
      "name": "com.amazonaws.ecs.capability.docker-remote-api.1.21"
    }
  ],
  "pidMode": null,
  "requiresCompatibilities": [
    "EC2"
  ],
  "networkMode": null,
  "cpu": null,
  "revision": 1,
  "status": "ACTIVE",
  "volumes": [
    {
      "name": "volume-0",
      "host": null,
      "dockerVolumeConfiguration": {
        "autoprovision": true,
        "labels": null,
        "scope": "shared",
        "driver": "local",
        "driverOpts": null
      }
    }
  ]
}

タスク起動

Dockerコンテナを起動します。
うっかりECSのログ設定を忘れてしまったので、docker-compose upコマンドで起動したログを載せておきます。
t2.mediumインスタンスでテストした時のログですが、データロードまで少し時間がかかります。

[ec2-user@ip-10-1-*-*** melbourne-map]$ docker-compose up
Creating network "melbourne-map_default" with the default driver
Creating volume "melbourne-map_osm-data" with default driver
Pulling web (nginx:1.11-alpine)...
1.11-alpine: Pulling from library/nginx
709515475419: Pull complete
4b21d71b440a: Pull complete
c92260fe6357: Pull complete
ed383a1b82df: Pull complete
Creating melbourne-map_postgis_1_60c7123978a5 ... done
Creating melbourne-map_web_1_1fadfe7b920b      ... done
Creating melbourne-map_renderer_1_70ada7233ba7 ... done
Attaching to melbourne-map_postgis_1_6a59f2e4f643, melbourne-map_web_1_c83180b5cf64, melbourne-map_renderer_1_6702d8636309
postgis_1_6a59f2e4f643 | The files belonging to this database system will be owned by user "postgres".
postgis_1_6a59f2e4f643 | This user must also own the server process.
postgis_1_6a59f2e4f643 | 
postgis_1_6a59f2e4f643 | The database cluster will be initialized with locale "en_US.utf8".
postgis_1_6a59f2e4f643 | The default database encoding has accordingly been set to "UTF8".
postgis_1_6a59f2e4f643 | The default text search configuration will be set to "english".
postgis_1_6a59f2e4f643 | 
postgis_1_6a59f2e4f643 | Data page checksums are disabled.
postgis_1_6a59f2e4f643 | 
postgis_1_6a59f2e4f643 | fixing permissions on existing directory /var/lib/postgresql/data ... ok
postgis_1_6a59f2e4f643 | creating subdirectories ... ok
postgis_1_6a59f2e4f643 | selecting default max_connections ... 100
postgis_1_6a59f2e4f643 | selecting default shared_buffers ... 128MB
postgis_1_6a59f2e4f643 | selecting dynamic shared memory implementation ... posix
postgis_1_6a59f2e4f643 | creating configuration files ... ok
postgis_1_6a59f2e4f643 | creating template1 database in /var/lib/postgresql/data/base/1 ... ok
postgis_1_6a59f2e4f643 | initializing pg_authid ... ok
postgis_1_6a59f2e4f643 | setting password ... ok
postgis_1_6a59f2e4f643 | initializing dependencies ... ok
postgis_1_6a59f2e4f643 | creating system views ... ok
postgis_1_6a59f2e4f643 | loading system objects' descriptions ... ok
postgis_1_6a59f2e4f643 | creating collations ... ok
postgis_1_6a59f2e4f643 | creating conversions ... ok
postgis_1_6a59f2e4f643 | creating dictionaries ... ok
postgis_1_6a59f2e4f643 | setting privileges on built-in objects ... ok
postgis_1_6a59f2e4f643 | creating information schema ... ok
postgis_1_6a59f2e4f643 | loading PL/pgSQL server-side language ... ok
postgis_1_6a59f2e4f643 | vacuuming database template1 ... ok
postgis_1_6a59f2e4f643 | copying template1 to template0 ... ok
postgis_1_6a59f2e4f643 | copying template1 to postgres ... ok
postgis_1_6a59f2e4f643 | syncing data to disk ... 
postgis_1_6a59f2e4f643 | WARNING: enabling "trust" authentication for local connections
postgis_1_6a59f2e4f643 | You can change this by editing pg_hba.conf or using the option -A, or
postgis_1_6a59f2e4f643 | --auth-local and --auth-host, the next time you run initdb.
postgis_1_6a59f2e4f643 | ok
postgis_1_6a59f2e4f643 | 
postgis_1_6a59f2e4f643 | Success. You can now start the database server using:
postgis_1_6a59f2e4f643 | 
postgis_1_6a59f2e4f643 |     pg_ctl -D /var/lib/postgresql/data -l logfile start
postgis_1_6a59f2e4f643 | 
postgis_1_6a59f2e4f643 | ****************************************************
postgis_1_6a59f2e4f643 | WARNING: No password has been set for the database.
postgis_1_6a59f2e4f643 |          This will allow anyone with access to the
postgis_1_6a59f2e4f643 |          Postgres port to access your database. In
postgis_1_6a59f2e4f643 |          Docker's default configuration, this is
postgis_1_6a59f2e4f643 |          effectively any other container on the same
postgis_1_6a59f2e4f643 |          system.
postgis_1_6a59f2e4f643 | 
postgis_1_6a59f2e4f643 |          Use "-e POSTGRES_PASSWORD=password" to set
postgis_1_6a59f2e4f643 |          it in "docker run".
postgis_1_6a59f2e4f643 | ****************************************************
postgis_1_6a59f2e4f643 | waiting for server to start....LOG:  database system was shut down at 2018-12-06 03:29:20 UTC
postgis_1_6a59f2e4f643 | LOG:  MultiXact member wraparound protections are now enabled
postgis_1_6a59f2e4f643 | LOG:  database system is ready to accept connections
postgis_1_6a59f2e4f643 | LOG:  autovacuum launcher started
postgis_1_6a59f2e4f643 |  done
postgis_1_6a59f2e4f643 | server started
postgis_1_6a59f2e4f643 | CREATE DATABASE
postgis_1_6a59f2e4f643 | 
postgis_1_6a59f2e4f643 | 
postgis_1_6a59f2e4f643 | /usr/local/bin/docker-entrypoint.sh: sourcing /docker-entrypoint-initdb.d/postgis.sh
postgis_1_6a59f2e4f643 | CREATE DATABASE
postgis_1_6a59f2e4f643 | UPDATE 1
postgis_1_6a59f2e4f643 | Loading PostGIS extensions into template_postgis
postgis_1_6a59f2e4f643 | CREATE EXTENSION
postgis_1_6a59f2e4f643 | CREATE EXTENSION
postgis_1_6a59f2e4f643 | CREATE EXTENSION
postgis_1_6a59f2e4f643 | CREATE EXTENSION
postgis_1_6a59f2e4f643 | CREATE EXTENSION
postgis_1_6a59f2e4f643 | Loading PostGIS extensions into gis
postgis_1_6a59f2e4f643 | CREATE EXTENSION
postgis_1_6a59f2e4f643 | CREATE EXTENSION
postgis_1_6a59f2e4f643 | CREATE EXTENSION
postgis_1_6a59f2e4f643 | CREATE EXTENSION
postgis_1_6a59f2e4f643 | CREATE EXTENSION
postgis_1_6a59f2e4f643 | osm2pgsql version 0.92.0 (64 bit id space)
postgis_1_6a59f2e4f643 | 
postgis_1_6a59f2e4f643 | Using built-in tag processing pipeline
postgis_1_6a59f2e4f643 | Using projection SRS 3857 (Spherical Mercator)
postgis_1_6a59f2e4f643 | Setting up table: planet_osm_point
postgis_1_6a59f2e4f643 | Setting up table: planet_osm_line
postgis_1_6a59f2e4f643 | Setting up table: planet_osm_polygon
postgis_1_6a59f2e4f643 | Setting up table: planet_osm_roads
postgis_1_6a59f2e4f643 | Allocating memory for dense node cache
postgis_1_6a59f2e4f643 | Allocating dense node cache in one big chunk
postgis_1_6a59f2e4f643 | Allocating memory for sparse node cache
postgis_1_6a59f2e4f643 | Sharing dense sparse
postgis_1_6a59f2e4f643 | Node-cache: cache=800MB, maxblocks=12800*65536, allocation method=11
postgis_1_6a59f2e4f643 | Mid: pgsql, scale=100 cache=800
postgis_1_6a59f2e4f643 | Setting up table: planet_osm_nodes
postgis_1_6a59f2e4f643 | Setting up table: planet_osm_ways
postgis_1_6a59f2e4f643 | Setting up table: planet_osm_rels
postgis_1_6a59f2e4f643 | 
postgis_1_6a59f2e4f643 | Reading in file: /hokkaido-latest.osm.pbf
postgis_1_6a59f2e4f643 | Using PBF parser.
Processing: Node(5880k 294.0k/s) Way(0k 0.00k/s) Relation(0 0.00/s)LOG:  checkpoints are occurring too frequently (25 seconds apart)
postgis_1_6a59f2e4f643 | HINT:  Consider increasing the configuration parameter "max_wal_size".
Processing: Node(12180k 276.8k/s) Way(0k 0.00k/s) Relation(0 0.00/s)LOG:  checkpoints are occurring too frequently (23 seconds apart)
postgis_1_6a59f2e4f643 | HINT:  Consider increasing the configuration parameter "max_wal_size".
Processing: Node(18530k 276.6k/s) Way(0k 0.00k/s) Relation(0 0.00/s)LOG:  checkpoints are occurring too frequently (23 seconds apart)
postgis_1_6a59f2e4f643 | HINT:  Consider increasing the configuration parameter "max_wal_size".
Processing: Node(19702k 281.5k/s) Way(2357k 84.20k/s) Relation(9850 351.79/s)  parse time: 126s
postgis_1_6a59f2e4f643 | Node stats: total(19702672), max(6120021395) in 70s
postgis_1_6a59f2e4f643 | Way stats: total(2357510), max(652949469) in 28s
postgis_1_6a59f2e4f643 | Relation stats: total(9853), max(9077199) in 28s
postgis_1_6a59f2e4f643 | Committing transaction for planet_osm_point
postgis_1_6a59f2e4f643 | Committing transaction for planet_osm_line
postgis_1_6a59f2e4f643 | Committing transaction for planet_osm_polygon
postgis_1_6a59f2e4f643 | Committing transaction for planet_osm_roads
postgis_1_6a59f2e4f643 | Setting up table: planet_osm_nodes
postgis_1_6a59f2e4f643 | Setting up table: planet_osm_ways
postgis_1_6a59f2e4f643 | Setting up table: planet_osm_rels
postgis_1_6a59f2e4f643 | Using built-in tag processing pipeline
postgis_1_6a59f2e4f643 | Setting up table: planet_osm_nodes
postgis_1_6a59f2e4f643 | Setting up table: planet_osm_ways
postgis_1_6a59f2e4f643 | Setting up table: planet_osm_rels
postgis_1_6a59f2e4f643 | Using built-in tag processing pipeline
postgis_1_6a59f2e4f643 | 
postgis_1_6a59f2e4f643 | Going over pending ways...
postgis_1_6a59f2e4f643 |    1860907 ways are pending
postgis_1_6a59f2e4f643 | 
postgis_1_6a59f2e4f643 | Using 2 helper-processes

renderer_1_6702d8636309 | Waiting while database is initializing...
renderer_1_6702d8636309 | Waiting while database is initializing...
renderer_1_6702d8636309 | Waiting while database is initializing...
renderer_1_6702d8636309 | Starting renderer

動作確認

URLにアクセスして確認します。
HTML内のタイルの接続先を変更してから接続してみてください。
ローカルにHTMLファイルを作ってアクセスしても良いです。

index.html
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8"/>
    <link rel="stylesheet" href="http://cdn.leafletjs.com/leaflet-0.7.1/leaflet.css" />
    <script type="text/javascript" src="http://cdn.leafletjs.com/leaflet-0.7.1/leaflet.js"></script>
    <style type="text/css">
        html, body, #map {
            width: 100%;
            height: 100%;
            margin: 0 !important;
            overflow: hidden;
        }
    </style>
</head>

<body>
<div id="map"></div>
</body>

<script type="text/javascript">
    var map = L.map('map').setView([43.06, 141.34], 12);
    L.tileLayer('http://localhost:8080/{z}/{x}/{y}.png', {
        attribution: 'Map data &copy; <a href="http://openstreetmap.org">OpenStreetMap</a> contributors, <a href="http://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>, Imagery © <a href="http://cloudmade.com">CloudMade</a>',
        maxZoom: 18
    }).addTo(map);
</script>
</html>

リポジトリに上がっている緯度経度の設定が、なぜか南半球になっているので、北半球に移動してください(笑)

スクリーンショット 2018-12-07 15.35.05.png

カスタマイズ

タイルのカスタマイズについて記載しておきます。

リージョンの変更

ダウンロードするファイルは、Download OpenStreetMap data for this regionから検索可能です。
postgisのDockerfileを修正します。
Dockerイメージが大きくなるので、pbfをコンテナ内に入れなくてもと思っているのですが、元々作ってくれた方の意図をそのままにしています。

ちなみに、北海道と東北、関東と関西のようなリージョンが複数必要な場合、2つ指定してもうまく動きませんのでご注意ください。

FROM mdillon/postgis:9.5

WORKDIR /

RUN apt-get update && \
    apt-get install -y osm2pgsql git wget && \
    rm -rf /var/lib/apt/lists/*

RUN git clone https://github.com/akikinyan/openstreetmap-carto.git

RUN wget http://download.geofabrik.de/asia/japan/hokkaido-latest.osm.pbf


#Overriding init script to add hstore extension that osm2pgsql requires
COPY ./initdb-postgis.sh /docker-entrypoint-initdb.d/postgis.sh

タイルの細かい変更

Dockerfileファイルを見ると、コンパイルしてからレンダリングエンジンを起動しています。
いろいろ弄りたい方は、別のリポジトリからcloneしている方を弄りましょう。
https://github.com/akikinyan/openstreetmap-carto

Dockerファイルの中を書いておきます。

renderer/entrypoint.sh
sh /scripts/compile_style.sh

while [ ! -e /var/lib/postgresql/data/DB_INITED ]
do
sleep 5
echo "Waiting while database is initializing..."
done

#Have to wait because once DB created then osm2pgsql restarting postgres.
#TODO: Using pg_isready
echo "DB successfully created, waiting for restart"
sleep 10

echo "Starting renderer"
sh /scripts/run_render.sh
renderer/scripts/compile_style.sh
#!/usr/bin/env bash

# Compiling carto css style and generates OSM xml
# that can be passed to mapnik.

carto /openstreetmap-carto/project.mml > /map_data/stylesheet_.xml

DS='<Parameter name=\"dbname\"><![CDATA[gis]]><\/Parameter>\
    <Parameter name=\"host\"><![CDATA[postgis]]><\/Parameter>\
    <Parameter name=\"port\"><![CDATA[5432]]><\/Parameter>\
    <Parameter name=\"user\"><![CDATA[postgres]]><\/Parameter>\
    <Parameter name=\"password\"><![CDATA[postgres]]><\/Parameter>'
sed "s/<Parameter name=\"dbname\">.*<\/Parameter>/${DS}/" /map_data/stylesheet_.xml > /map_data/stylesheet.xml
rm /map_data/stylesheet_.xml

例えば、道路の設定はroads.mssです。
@moterway-fillとかの部分は、OSMのWikipediaで調べると何者か分かります。

openstreetmap-carto/roads.mss
/* For the main linear features, such as roads and railways. */

//road colors for major roads were generated with scripts/generate_road_colors.py
@motorway-fill: #e892a2; // Lch(70,35,10), error 0.5
@trunk-fill: #f9b29c; // Lch(79,33,42), error 0.7
@primary-fill: #fcd6a4; // Lch(88,31,74), error 1.7
@secondary-fill: #f7fabf; // Lch(97,29,106), error 1.7
@tertiary-fill: #ffffff;
@residential-fill: #ffffff;
@service-fill: @residential-fill;
@living-street-fill: #ededed;
@pedestrian-fill: #dddde8;
@raceway-fill: pink;
@road-fill: #ddd;
@footway-fill: salmon;
@steps-fill: @footway-fill;
@cycleway-fill: blue;
@bridleway-fill: green;
@track-fill: #996600;
@aeroway-fill: #bbc;
@runway-fill: @aeroway-fill;
@taxiway-fill: @aeroway-fill;
@helipad-fill: @aeroway-fill;

データの取得はproject.mmlで処理をしているので、ズームレベルに応じた描画以外にも、こちらのファイルの修正が必要となる場合があります。propertiesの部分がそれです。

openstreetmap-carto/project.mml
{
      "name": "roads-text-name",
      "srs-name": "900913",
      "geometry": "linestring",
      "class": "",
      "id": "roads-text-name",
      "srs": "+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0.0 +k=1.0 +units=m +nadgrids=@null +wktext +no_defs +over",
      "Datasource": {
        "extent": "-20037508,-20037508,20037508,20037508",
        "table": "(SELECT way,\n    CASE WHEN substr(highway, length(highway)-3, 4) = 'link' THEN substr(highway, 0, length(highway)-4) ELSE highway END,\n    CASE WHEN (tunnel = 'yes' OR tunnel = 'building_passage' OR covered = 'yes') THEN 'yes' ELSE 'no' END AS tunnel,\n    CASE WHEN construction IN ('service', 'footway', 'cycleway', 'bridleway', 'path', 'track') THEN 'yes' ELSE 'no' END AS int_construction_minor,\n    name\n  FROM planet_osm_line\n  WHERE highway IN ('motorway', 'motorway_link', 'trunk', 'trunk_link', 'primary', 'primary_link', 'secondary', 'secondary_link', 'tertiary', \n                    'tertiary_link', 'residential', 'unclassified', 'road', 'service', 'pedestrian', 'raceway', 'living_street', 'construction')\n    AND name IS NOT NULL\n) AS roads_text_name",
        "geometry_field": "way",
        "type": "postgis",
        "key_field": "",
        "dbname": "gis"
      },
      "extent": [
        -180,
        -85.05112877980659,
        180,
        85.05112877980659
      ],
      "properties": {
        "minzoom": 13
      },
      "advanced": {}
    },

反映させるため、プロセス(コンテナ)再起動が必要です。
ECS環境で反映する場合は、最新のコンテナイメージにデプロイし直します。

OSMでルート案内

ルート案内のroutinoを使ってみましたが、時間帯の通行禁止が反映されていないので、地域によっては交通違反になる可能性大です。ご注意ください。
ルート検索を試してみたい方は、私のDockerコンテナイメージをお使いいただけます。
https://hub.docker.com/r/akikinyan/routino-docker

さいごに

GoogleMapの商用利用が安かったら良かったのだけど、実際に見積もってみたら結構な金額になってしまいました。
OSMは、下図としてはそれなりに使えるのですが、検索やルート案内などの機能が弱いです。
それを補うためのインタフェースがあれば、地域によっては十分じゃないかなと言った印象です。

18
17
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
18
17