8
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

MIERUNEAdvent Calendar 2024

Day 1

DockerでMapServerを動かしてみる

Last updated at Posted at 2024-12-01

これは MIERUNE AdventCalendar 2024 1日目の記事です!

MapServerとは?

MapServer.jpg

提供元:University of Minnesota、MIT、Wikimedia Commons(https://commons.wikimedia.org/w/index.php?curid=10007423)

MapServerは、オープンソースの地図配信ソフトウェアで、地理空間データを処理・可視化するために使用されます。1990年代後半に、アメリカのミネソタ大学ツインシティー校によって開発され、GIS(地理情報システム)の分野で広く利用されてきました。

MapServerの主な特徴の一つは、さまざまなフォーマットの地理空間データを動的に処理し、ラスタータイルとして動的に配信できる能力です。この配信能力は、OGC(Open Geospatial Consortium)が定めた国際標準規格であるWMS(Web Map Service)に対応している点で特に注目されてました。

WMSは、地理空間データをインターネット上で共有するための標準規格であり、リクエストに応じて地図画像や地理情報データを提供する仕組みを提供します。MapServerは、このWMS規格に準拠して動作することで、さまざまなクライアントソフトウェアやシステムと連携し、地理空間データの効率的な配信を実現します。

背景の変化とMapServerの現状

近年はブラウザの処理能力の向上により、地図データの描画や処理をクライアント側で行うことが可能になり、地図配信のアーキテクチャが大きく変化してきました。特に、WebGLを活用したライブラリや、ベクトルタイル形式の普及により、サーバーはデータ配信に特化し、地図のスタイリングや描画はクライアント側で行うケースが増えています。

また、MapServerのようにサーバー側でラスタータイルを動的に生成して配信するモデルの利用は減少傾向にあります。現在では、ラスタータイルは動的に生成されるのではなく、事前に生成された静的なタイルとしてキャッシュやCDNを通じて配信される傾向が強まっています。このアプローチは、パフォーマンスやスケーラビリティの観点で優れているためです。

しかし、古いWebGISシステムやレガシーな環境では、依然としてMapServerが利用されているケースが多く見られます。ちなみに、現在でもMapServerは継続的にアップデートされています。

MapServerを動かしてみる

PCを汚したくないので、今回はドッカーでMapServerを動かしてみます。ディレクトリ構成は以下になります。docker-compose.ymlとMapfile(sample.map)を用意します。

.
├── mapfile # マップファイルを格納するディレクトリ
│   ├── data
│   │   ├──(ここにデータを入れる)
│   └── sample.map
└── docker-compose.yml

ドッカーイメージはこちらになります。

しかし、私のM1 Mac 環境だと動かず、代わりにこちらのイメージを使用しました。

docker-compose.ymlに書き込みます。

services:
  mapserver:
    # M1 Macの場合を想定してるので、もし動かない場合は`mapserver/mapserver`のimageを試してください
    image: camptocamp/mapserver:8.0-gdal3.7-arm64
    container_name: mapserver
    ports:
      - "8080:80"
    volumes:
      - ./mapfile:/etc/mapserver
    environment:
      - MS_MAPFILE=/etc/mapserver/sample.map
      - MS_DEBUGLEVEL=5
      - MS_MAP_NO_PATH=true

使用するデータ

データ名 データタイプ  データ形式
Airports ポイント Shape
Roads ライン Shape
Urban Areas ポリゴン Shape
Ocean Bottom ラスター GeoTiff

先ほどのディレクトリに以下のようにデータを格納します。

.
└── mapfile
    ├── data
    │   ├── ne_10m_admin_0_countries
    │   │   ├── ne_10m_admin_0_countries.cpg
    │   │   ├── ne_10m_admin_0_countries.dbf
    │   │   ├── ne_10m_admin_0_countries.prj
    │   │   ├── ne_10m_admin_0_countries.shp
    │   │   └── ne_10m_admin_0_countries.shx
    │   ├── ne_10m_airports
    │   │   ├── ne_10m_airports.cpg
    │   │   ├── ne_10m_airports.dbf
    │   │   ├── ne_10m_airports.prj
    │   │   ├── ne_10m_airports.shp
    │   │   └── ne_10m_airports.shx
    │   ├── ne_10m_roads
    │   │   ├── ne_10m_roads.cpg
    │   │   ├── ne_10m_roads.dbf
    │   │   ├── ne_10m_roads.prj
    │   │   ├── ne_10m_roads.shp
    │   │   └── ne_10m_roads.shx
    │   ├── OB_LR
    │   │   ├── OB_LR.prj
    │   │   ├── OB_LR.tfw
    │   │   └── OB_LR.tif
    └── sample.map

Mapfileを書いてみる

MapServerはMapfile(.map)を使用して、各レイヤーの描画スタイル(色、ラベル、シンボルなど)を細かく設定できます。

また、VSCodeの場合、以下の拡張機能を使うとMapfileのテキストが見やすくなります

sample.map
MAP
    NAME "TestMapServer"
    UNITS DD
    EXTENT -180 -90 180 90 
    PROJECTION
        "init=EPSG:4326"
    END

    WEB
        METADATA
            "wms_title" "Test WMS Server"
            "wms_onlineresource" "http://localhost:8080/cgi-bin?/mapserv?map=/map/m1.map"
            "wms_srs" "EPSG:3857 EPSG:4326"
            "wms_enable_request" "*"
        END
    END

    OUTPUTFORMAT
        NAME "png"
        DRIVER AGG/PNG
        MIMETYPE "image/png"
        IMAGEMODE RGBA
        EXTENSION "png"
        TRANSPARENT ON
    END

    # シンボルの形状の定義
    SYMBOL
        NAME "circle"
        TYPE ELLIPSE
        POINTS 1 1 END
        FILLED TRUE
    END


    # Point Layer
    LAYER
        NAME "ne_10m_airports"
        TYPE POINT
        STATUS ON
        DATA "data/ne_10m_airports/ne_10m_airports.shp"
        METADATA
            "wms_title" "ne_10m_airports"
        END
        CLASS
            NAME "ne_10m_airports"
            STYLE
                COLOR 255 0 0
                SYMBOL "circle" # シンボルの形状を指定(デフォルト設定が必要)
                SIZE 12
            END
        END
    END

    # LineLayer
    LAYER
        NAME "ne_10m_roads"
        TYPE LINE
        STATUS ON
        DATA "data/ne_10m_roads/ne_10m_roads.shp"
        METADATA
            "wms_title" "ne_10m_roads"
        END
        CLASS
            NAME "ne_10m_roads"
            STYLE
                OUTLINECOLOR 0 255 0
                WIDTH 2
            END
        END
    END

    # Polygon Layer
    LAYER
        NAME "ne_10m_admin_0_countries"
        TYPE POLYGON
        STATUS ON
        DATA "data/ne_10m_admin_0_countries/ne_10m_admin_0_countries.shp"
        METADATA
            "wms_title" "ne_10m_admin_0_countries"
        END
        CLASS
            NAME "ne_10m_admin_0_countries"
            STYLE
                COLOR 255 175 0
                OUTLINECOLOR 0 0 0
            END
        END
    END

    # GeoTIFF Layer
    LAYER
        NAME "OB_LR"
        TYPE RASTER
        STATUS ON
        DATA "data/OB_LR/OB_LR.tif"  # GeoTIFFファイルのパス
        METADATA
            "wms_title" "OB_LR"
        END
        PROJECTION
            "init=EPSG:4326"  # GeoTIFFが使用する座標系を指定
        END
        CLASS
            NAME "OB_LR"
        END
    END

END

Mapfileを書いたところでドッカーを起動します。

docker compose up -d

起動後、以下のURLにブラウザでリクエストしてみます。

http://localhost:8080/cgi-bin?/mapserv?map=/map/sample.map&SERVICE=WMS&VERSION=1.3.0&REQUEST=GetCapabilities

するとMapServerがWMS(Web Map Service)のGetCapabilitiesリクエストを処理し、サービスの詳細情報を返します。この情報には、提供される地図データのレイヤー構成やサポートされる投影法、リクエスト可能な形式などが含まれます。

返されるXML形式のレスポンスは、クライアントソフトウェアによって解釈され、地図データの利用が可能になります。

image.png

クライアントで描画してみる

QGIS

ブラウザパネルの「WMS/WMTS」の項目を右クリックして「新規接続」を選択します。

image.png

名称は任意の文字列を入れ、URLに以下のリクエストURLを記入して「OK」を選択します

http://localhost:8080/cgi-bin?/mapserv?map=/map/sample.map

image.png

ブラウザパネルの「WMS/WMTS」のトグルを展開すると先ほど登録したものが表示されるので、さらにトグルを展開すると、Mapfileに記入したレイヤー群が表示されるので、ダブルクリックすることでレイヤーパネルに追加できます。

image.png

地図に描画された様子です。

image.png

MapLibre GL JS

公式のこちらのexamplesを参考にして描画してみます。

&LAYERS=の部分にMapfileで定義したレイヤー名をカンマ区切りで指定することとで、タイル画像として描画されます。ちなみに、後に書いたレイヤーの方が上に重なるようになっています。

import maplibregl from 'maplibre-gl';
import 'maplibre-gl/dist/maplibre-gl.css';

// 地図の表示
const map = new maplibregl.Map({
    container: 'map',
    style: {
        version: 8,
        glyphs: 'https://demotiles.maplibre.org/font/{fontstack}/{range}.pbf',
        sources: {
            'wms-source': {
                type: 'raster',
                tiles: [
                    'http://localhost:8080/cgi-bin?/mapserv?map=/map/sample.map&SERVICE=WMS&VERSION=1.3.0&REQUEST=GetMap&LAYERS=OB_LR,ne_10m_admin_0_countries,ne_10m_roads,ne_10m_airports&STYLES=&CRS=EPSG:3857&BBOX={bbox-epsg-3857}&WIDTH=256&HEIGHT=256&FORMAT=image/png',
                ],
                tileSize: 256,
            },
        },
        layers: [
            {
                id: 'wms-layer',
                type: 'raster',
                source: 'wms-source',
                paint: {
                    'raster-opacity': 1.0,
                },
            },
        ],
    },
    center: [135.41533470153811, 34.736675273476976],
    zoom: 4,
});

// NavigationControl
map.addControl(new maplibregl.NavigationControl(), 'top-right');

MapLibreで描画した様子です。

image.png

Chromeのコンソール画面でタイルリクエストを確認すると、複数のレイヤーが一枚のタイル画像として返してくれてるのが確認できます。

image.png

おわりに

今回MapServerを触るにあたり、ネット上に公開されている情報が少なく、環境を整えるのに苦戦しました。冒頭でも書きましたが、サーバーサイドで動的にラスタータイルを生成するMapServerのアプローチが時代のニーズに合わなくなってきているためであると考えられます。

明日は@nbayashiさんによる記事です!お楽しみに!!

8
2
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
8
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?