OpenStreetMap est la solution idéale quand on souhaite avoir un outil cartographique, mais qu'on ne veut pas utiliser Google. De plus, il est souhaitable pour plusieurs raisons d'avoir sa propre stack de système d'information géographique (SIG).
Quand on a besoin d'une carte (pour son site, pour le système d'information de son entreprise), soit on externalise (chez Google Maps pour le plus souvent, mais ça peut aussi consister à utiliser les serveurs d'openstreetmap.org), soit on ne veut pas dépendre d'un service extérieur (s'il a un problème, s'il y a une coupure réseau ou tout simplement s'il ne propose pas ce dont on a besoin ; ou tout simplement pour ne pas abuser des maigres ressources du projet OpenStreetMap).
Ce premier article d'une série a pour but de servir de guide à toute personne qui aurait besoin de mettre en place des services en interne pour être autonome.
Pour la majorité des gens (moi y compris avant que je ne me plonge dedans), OpenStreetMap est juste une carte à laquelle on peut accéder en allant sur le site openstreetmap.org. En réalité, OpenStreetMap, ce sont surtout des données. Ensuite il s'agit d'utiliser ces données, c'est le cas en faisant des cartes (comme par exemple celle du site openstreetmap.org), mais cela permet aussi de faire du géo-codage (obtenir les coordonnées GPS à partir d'une adresse, mais pas seulement) et du calcul d'itinéraires.
Ce sera donc non pas un, mais trois articles que je vous proposerai. Le premier (celui-ci donc) va traiter de l'installation d'un serveur de tuiles (c'est-à-dire, avoir notre propre serveur qui va fournir des tuiles). Des tuiles, ce sont des images qu'on pourra reconstituer pour faire une carte. Il y a principalement deux bibliothèques JavaScript pour faire cela :
- openlayers, qui est fournie avec l'installation ;
- eaflet, beaucoup plus élaborée et majoritairement utilisée (l'auteur a eu de très bons échos sur cette dernière).
Ces usages sont hors de portée de ces articles qui se focaliseront sur le « back-end », on utilisera juste openlayers pour vérifier que le serveur de tuiles fonctionne (mais la page.html est fournie avec l'installation des paquets sur Ubuntu donc il n'y aura rien à faire). Le second article parlera de la mise en place d'un service d'itinéraires (on donne deux adresses, le service nous retourne la route, ainsi qu'un temps de trajet estimé). Enfin, le troisième article indiquera comment mettre en place un service de géo-codage.
Enfin, ces trois articles se baseront sur l'utilisation du système d'exploitation Ubuntu 14.04. Je supposerai que vous avez de maigres connaissances sur ce système (comment lancer un service, le système des droits/permissions UNIX, etc.).
1. Qu'est-ce qu’un serveur de tuiles ?
D'un côté, le projet OpenStreetMap (ou OSM) fournit des données, de l'autre il y a les différentes cartes. Qu'y a-t-il entre les deux ? Le serveur de tuiles !
Ce que j'appelle le serveur de tuiles est en réalité plusieurs logiciels fonctionnant de concert afin de générer des images (des .png, aussi connues sous le nom de tuiles (tiens donc)) à partir des données présentes dans la base de données.
L'installation peut devenir assez rapidement non-fonctionnelle (testé et vérifié de multiples fois par l'auteur aussi bien en tant que responsable qu'en tant que témoin). Je vous invite donc à faire une première installation telle que je la décris afin d'avoir un setup fonctionnel et libre à vous d'aller ensuite vous amuser à casser des choses.
Un serveur de tuiles est composé de plusieurs briques principales :
- apache2 avec le mod_tile ;
- renderd ;
- postgresql.
2. Installation des logiciels
On va installer les différents logiciels nécessaires. On ajoute un PPA qui permet d'avoir les paquets (plus récents) sans avoir à les compiler :
$ sudo add-apt-repository ppa:kakrueger/openstreetmap
On installe le mod_tile qui va tirer avec lui toutes les dépendances dont il a besoin :
$ sudo apt-get update && sudo apt-get install libapache2-mod-tile
Lors de l'installation de mod_tile et de ses dépendances, il va nous proposer de configurer et de mettre en place un certain nombre de choses. Premièrement, il va demander si on veut installer les frontières ainsi que les limites du littoral mondial de la planète Terre tout entière. On accepte. Il va ensuite nous proposer gentiment de se charger de la mise en place d'une base de données postgis (ou plus exactement une base de données postgresql avec l'extension postgis) afin de pouvoir y stocker les données tout à l'heure. Comme on n'est pas là pour se prendre la tête, on va accepter docilement. On laisse le nom par défaut (gis), car c'est mieux (trustme, j'ai fait l'erreur de penser que si je donnais un autre nom ça serait plus cool, don't be a cool kid) et on laisse aussi www-data comme propriétaire. Une fois qu'on a déclaré allégeance à l'installeur, il se charge de faire son job, installer tout ça bien comme il faut pour qu'on n'ait « plus qu'à ».
3. Téléchargement des données
Maintenant, la première étape est de remplir la base de données avec les données d'OSM. Il faut donc commencer par les télécharger. Il y a plusieurs endroits où on peut les avoir. N'ayant jamais eu aucun de problème avec, je conseille d'utiliser les services de http://download.geofabrik.de. Cette entreprise allemande spécialisée dans les prestations liées à OSM fournit des lots de données pour les différentes régions du monde avec une granularité appréciable : dans le cas de la France, on peut télécharger les données jusqu'à la région.
Je vous laisse choisir ce que vous voulez prendre comme périmètre. Néanmoins, si c'est juste pour tester, je vous conseille de prendre une petite zone (une région française est très bien) ; sauf si le temps n'est pas un problème. Il faut télécharger les données sous format pbf.
Dans mon cas, j'ai fait le choix de la Basse-Normandie :
$ wget http://download.geofabrik.de/europe/france/basse-normandie-latest.osm.pbf
Plusieurs régions
Je donne l'astuce, car je pense que ça peut intéresser plus d'une personne : si on veut un serveur de tuiles pour plusieurs régions, il faut rassembler les différents pbf téléchargés en un seul. Cela se fait avec le logiciel osmosis :
$ sudo apt-get install osmosis
Pour avoir un pbf qui contient la Bretagne, la Basse-Normandie et la Haute-Normandie (le « Grand Ouest »), il faut procéder de la manière suivante :
$ osmosis --rb bretagne-latest.osm.pbf --rb basse-normandie-latest.osm.pbf --rb haute-normandie-latest.osm.pbf --merge --merge --wb grand-ouest.pbf
L'argument --rb veut dire qu'on lit (read) un pbf, l'argument --wb qu'on écrit (write) un pbf et enfin, il faut l'argument --merge le nombre de fois qu'un pbf est lu moins une fois. Ne me demandez pas pourquoi, je ne veux même pas savoir ; mais un élément de réponse est que ce logiciel est écrit en Java.
4. Import des données
Maintenant qu'on a notre pbf, soit le fichier qui contient les données qu'on souhaite mettre dans la base postgis, on utilise le logiciel osm2pgsql pour les charger dans la base.
Je vous conseille de tuner un peu votre base si l'import que vous souhaitez faire est conséquent [1].
La commande générique est :
$ sudo -u www-data osm2pgsql --slim -C <taille du cache> --number-processes <nombre de processus> <nom du fichier pbf>
Suivant les ressources que j'ai (la quantité de RAM dont la machine que j'utilise dispose), je mets une taille plus ou moins grande du cache. Pour le nombre de processus, en général, je mets le nombre de cœurs que le CPU a. C'est sans doute perfectible, mais ça me suffit.
Dans le cas de mon exemple, j'ai une VM avec deux cœurs et 2 Gi de mémoire vive, et la commande utilisée est :
$ sudo -u www-data osm2pgsql --slim -C 512 --number-processes 2 basse-normandie-latest.osm.pbf
À la fin, il vous indique combien de temps cela a pris. Dans mon cas : Osm2pgsql took 770s overall.
5. Lancement des services
On peut pendant ce temps configurer les autres logiciels. On édite le fichier /etc/apache2/sites-enabled tileserver_site.conf et on change le ServerName, on met à la place l'adresse IP ou le nom de domaine que la machine a. On recharge alors la configuration d'apache2 :
$ sudo service apache2 reload
Dans le fichier /etc/renderd.conf, on change la valeur de la variable HOST à nouveau par l'adresse IP ou le nom de domaine que la machine a.
Une fois que l'import est fini, il faut l'indiquer pour qu'il puisse le savoir. Cela se fait en créant un fichier :
$ sudo -u www-data touch /var/lib/mod_tile/planet-import-complete
On lance alors renderd. Soit vous avez confiance et vous le lancez via la commande service, soit vous le lancez en mode debug :
$ sudo -u www-data renderd -f -c /etc/renderd.conf
On peut faire pointer son navigateur sur http://adresseip/osm/slippymap.html et on doit voir la carte. Au début ça va être lent, car la machine va devoir générer les tuiles, mais plus vous allez utiliser le serveur de tuiles, plus il y a aura de tuiles générées, donc juste à chercher sur le disque, ainsi, ça devrait être plus rapide.
Vous pouvez forcer la génération des tuiles avec la commande render_list. Si vous ne voulez pas générer pour toute la planète (si vous n'avez importé qu'une partie par exemple), il vaut mieux indiquer l'emprise :
$ render_list -a -z 0 -Z <niveau_de_zoom> -x <coordonnées x min> -X <coordonnées x max> -y <coordonnées y min> -Y <coordonnées y max> -l <charge de la machine (load average)> -n <nombre de processus>
Pour obtenir les coordonnées des tuiles, le plus facile est d'aller sur http://tools.geofabrik.de/map/ puis d'activer l'overlays "Tile coordinates" et ainsi vous avez les coordonnées des tuiles pour chacune des tuiles.
6. Mettre à jour les données et les tuiles
6.1 D'abord les données
L'intérêt d'utiliser les données d'OSM est qu'elles sont constamment mises à jour par les contributeurs (aussi je vous invite à en devenir un !). Il est donc intéressant de mettre à jour la base de données. Pour cela, on utilise osmosis. Si vous ne l'avez pas encore installé (pour concaténer des pbf) :
$ sudo apt-get install osmosis
Osmosis fait des mises à jour incrémentales, c'est-à-dire qu'il va rajouter uniquement les différences et ne va pas recommencer depuis le début. Par contre, cela veut dire qu'il ne faut pas sauter de mise à jour. La granularité des mises à jour est la journée. C'est-à-dire qu'en mettant à jour, si dans la base, les données dataient du lundi, les nouvelles données seront celles du mardi. Par conséquent, en temps normal (c'est-à-dire dans le cas où on ne souhaite pas rattraper du retard), on mettra à jour une fois par jour.
On va créer un dossier pour osmosis dont on va donner la propriété à l'utilisateur www-data, car c'est lui qui va faire les mises à jour. On va le laisser le configurer pour son besoin :
$ mkdir osmosis && cd osmosis
$ sudo chown www-data:www-data osmosis
$ sudo -u www-data osmosis --rrii workingDirectory=.
Cela va créer deux fichiers : un fichier de lock (qu'osmosis utilise pour être sûr qu'il n'y a pas deux instances d'osmosis qui tournent en même temps) et un fichier de configuration, configuration.txt.
Comme nous avons commencé à utiliser download.geofabrik.de pour les données, nous allons continuer à utiliser ce site pour les mises à jour. Quand vous vous rendez sur la page de la région géographique que vous avez choisie, il y a une ligne ".osc.gz files that contain all changes in this region, suitable e.g. for Osmosis updates".
On met alors ce lien dans le fichier configuration.txt qu'osmosis a créé, dans la variable baseUrl, et on laisse le reste tel quel. Pour la Basse-Normandie, ça donne :
baseUrl=http://download.geofabrik.de/europe/france/basse-normandie-updates/
Maintenant qu'osmosis sait où récupérer les données, on peut presque lancer une mise à jour. C'est peut-être clair pour vous, mais j'ai mis du temps à le comprendre : quand on lance osmosis, il va importer les différences uniquement sur une journée. Supposons qu'on soit le 8 du mois, vous avez importé initialement les données du 3, si vous lancez osmosis, vous aurez alors en base les données du 4. Pour avoir les données du 8, il faudra donc lancer osmosis quatre autres fois.
Osmosis se repère temporellement grâce à un fichier qui s'appelle state.txt. Par la suite, il va le gérer lui-même, mais il faut l'initialiser. On va donc sur la page que vous avez mis dans la variable baseUrl : il y a un dossier qui se nomme 000 et un fichier state.txt. On va dans le dossier 000 et on va à nouveau dans le dossier 000. Dans mon cas, l'adresse à laquelle je suis est : http://download.geofabrik.de/europe/france/basse-normandie-updates/000/000/.
Dans cette page, il y a un ensemble de couples de fichiers state.txt et d'osc.gz, chaque paire étant préfixée d'un nombre. Il y a également la date d'édition des fichiers. On va donc télécharger le fichier state.txt qui date de la veille du jour où l'on a téléchargé le .pbf. On prend celui de la veille, car on veut être sûr qu'on ne rate pas de données : ce n'est pas grave de prendre des données plus vieilles, car il va juste réécrire dessus. Lorsqu'on l'a téléchargé, il est nécessaire de le renommer en state.txt.
Pour mettre à jour, cela se fait en trois étapes :
1. Dans la première partie, osmosis va créer un fichier contenant les différences : c'est rapide (moins d'une minute).
2. On va ensuite importer ces données dans la base avec osm2pgsql : c'est long (suivant la taille des données que vous importez). En important les données, osm2pgsql va générer un fichier avec la liste des tuiles impactées pour la mise à jour.
3. Enfin, la troisième étape est donc de traiter les tuiles qui sont expirées avec la commande render_expired.
On commence donc par créer le fichier de diff :
$ sudo -u www-data osmosis --read-replication-interval workingDirectory=. --simplify-change --write-xml-change changes.osc.gz
Vous devriez avoir un fichier nommé changes.osc.gz dans le dossier.
Ensuite, il faut l'importer dans la base postgis. En faisant ça, osm2pgsql va créer le fichier avec les tuiles obsolètes. La commande générique est :
$ sudo -u www-data osm2pgsql -a --slim -C <taille du cache> --number-processes <nombre de processus> changes.osc.gz -e11-17 -o expired-tiles.txt
Sur ma VM, j'ai utilisé :
$ sudo -u www-data osm2pgsql -a --slim -C 512 --number-processes 2 changes.osc.gz -e11-17 -o expired-tiles.txt
Vous pouvez jouer sur les paramètres -e pour dire entre quels zooms vous souhaitez indiquer que les tuiles sont obsolètes. J'ai pris de 11 à 17, libre à vous d'en prendre d'autres.
Une fois que l'import du diff a fini, il reste donc à expirer les tuiles.
6.2 Mises à jour des tuiles
render_expired a trois actions possibles face à une tuile ayant expiré :
- la marquer comme dirty ;
- la supprimer (rm) ;
- la régénérer.
Chaque étape prend plus de ressources. Marquer une tuile comme dirty implique que la prochaine fois que quelqu'un tentera d'y accéder, le système va la régénérer, cela représente un faible accès disque sur le coup et donc permet d'étaler la charge du serveur dans le temps. Supprimer la tuile du disque demande déjà un peu plus de ressources en I/O (à l'échelle d'une tuile c'est négligeable, mais il y a plein de tuiles donc ça s'additionne vite). Enfin, régénérer une tuile c'est ce qu'il y a de plus coûteux comme vous pouvez vous en douter.
La commande pour agir sur les tuiles est de la forme :
$ sudo -u www-data render_expired -n 2 -z 11 -Z 18 < expired-tiles.txt
Cette commande va lancer deux processus et va régénérer les tuiles entre les zooms 11 et 18. J'ai choisi de tout régénérer, car je suis sur une petite zone géographique avec peu de tuiles, mais si vous êtes sur une grande zone, il faudra utiliser aussi les paramètres -T (comme touch, soit marquer) et -d (comme delete) pour alléger la mise à jour.
Une fois que tout ça est fonctionnel, il ne reste plus qu'à créer un petit script tout bête qui consiste à lancer ces commandes (osmosis, puis osm2pgsql et enfin render_expired) puis mettre en place un cron qui va appeler quotidiennement le script et ainsi vous aurez un serveur de tuiles à jour \o/
7. Bonus
Comme je suppose que vous allez faire plusieurs imports, il faut à chaque fois remettre en place la base de données gis. Pour faire cela, il suffit de supprimer la base de données (il faut que renderd soit arrêté sinon postgresql va refuser, car il y est connecté) puis de la recréer. Pour plus de lisibilité, je laisse le prompt pour voir les changements (et vous pourrez admirer le nom de la machine).
danj@trelou:~$ sudo -u postgres psql
psql (9.3.9)
Type "help" for help.
postgres=# drop database gis;
DROP DATABASE
postgres=# create database gis;
CREATE DATABASE
postgres=# \q
Il faut alors transformer cette nouvelle base en base postgis, c'est-à-dire rajouter l'extension :
danj@trelou:~$ sudo -u postgres psql -d gis
psql (9.3.9)
Type "help" for help.
gis=# create extension postgis;
CREATE EXTENSION
postgres=# \q
Conclusion
Nous avons donc vu comment installer les différents logiciels pour avoir un serveur de tuiles, comment mettre des données dedans et comment les mettre à jour. Vous êtes maintenant paré à tout !
Référence
[1] Comment « tuner » sa base postgresql : https://wiki.postgresql.org/wiki/Tuning_Your_PostgreSQL_Server