GithubHelp home page GithubHelp logo

osmtilemaker's Introduction

osmtilemaker

About

Generate your OSM tiles (one shot, no updates).

Follow the procedure below to:

  • adapt configuration to suit your needs
  • set up your local file system and download OSM raw data
  • build and run a docker with all needed stuff
  • import OSM data with osm2pgsql
  • generate tiles with scripts/gen-tile.py (using openstreetmap-carto and Mapnik)

This procedure is inspired by osmtilegen and scripts/gen-tile.py is adapted from generate_tiles.py using argparse python module.

Some commands are runned inside the docker container (through an interactive bash session) for convenience. If you want to package below procedure in one main script and avoid interactive bash session, there is not a long way.

Requirements

Hardware

For a full planet import, you can check

Maybe the main constraint is your disk space as you have to host (size given for a full planet import in january 2020 with default config and a ZFS filesystem with compression=lz4 and recordsize=8k for database):

  • [49 GB] - planet.osm.pbf file
  • [460 GB] - PostgreSQL/PostGIS OSM database peak usage (imported with osm2pgsql). End size: 185 GB.
  • [53 GB] - osm2pgsql nodes cache
  • tiles directory: Geofabrik - Tile Calculator helps to estimate tiles size considering your bbox and zoom levels

.conf/config file allows you to host these resources under different base directories (for example if you want to mount multiple hard disks). Check these variables: $HOSTPATH_OSM_FILE_DIR, $HOSTPATH_PG_DATA_DIR, $HOSTPATH_OSM2PGSQL_FLATNODE_DIR, $HOSTPATH_TILES_DIR. Having an SSD disk especially for the database will fast up the process.

It seems that a good start is having 32GB RAM with 6 to 8 cores CPU.

Software

  • GNU/Linux Debian based system (tested with Debian 9 and Ubuntu 18.04 and 20.04).
  • docker-ce version >=19 (tested with docker-ce 19.03.5 and 20.10.8), official install doc

Get source code and adapt configuration

  • clone this repo (it will be mounted later as a source docker volume)
  • go to root directory
cd osmtilemaker/

Config files are available under ./conf/ directory:

  • ./conf/config: main config file (examples: choose your .osm.pbf file, custom your area of interest, working directories location, database name ...)
  • ./conf/postgres-settings.sh: bash script to update postgresql.conf file with desired values

Because some osm2pgsql or PostgreSQL config variables impact performance: check About performance section below to custom them to suit your needs.

  • read config
. ./conf/config

Be aware that you must read config files before immersing in following chapters.

Check requirements

  • run this script until there is no error. It will check if all requirements are fullfilled and tell you what to do if necessary (as creating some directories or download an .osm.pbf file)
bash ./scripts/check_requirements.sh

Build and run docker

sudo docker build \
--tag $DOCKER_BUILD_TAG \
--build-arg INSTALLWORKDIR=$DOCKER_BUILD_ARG_INSTALLWORKDIR \
docker

Before running next command, be aware of issue #2 about the --shm-size parameter

sudo docker run -d \
  --env POSTGRES_PASSWORD=$DBPG_USER_POSTGRES_PWD \
  --env DBPG_USER_OSMTILEMAKER_USERNAME=$DBPG_USER_OSMTILEMAKER_USERNAME \
  --env DBPG_DATABASE_NAME=$DBPG_DATABASE_NAME \
  --volume $(pwd):$DOCKERPATH_SOURCE_DIR \
  --volume $HOSTPATH_WORKING_DIR:$DOCKERPATH_WORKING_DIR \
  --volume $HOSTPATH_OSM_FILE_DIR:$DOCKERPATH_OSM_FILE_DIR \
  --volume $HOSTPATH_PG_DATA_DIR:/var/lib/postgresql/data \
  --volume $HOSTPATH_OSM2PGSQL_FLATNODE_DIR:$DOCKERPATH_OSM2PGSQL_FLATNODE_DIR \
  --volume $HOSTPATH_TILES_DIR:$DOCKERPATH_TILES_DIR \
  --publish $DOCKER_HOST_PORT_TO_PUBLISH:5432 \
  --shm-size="256MB" \
  --name $DOCKER_NAME \
  $DOCKER_BUILD_TAG

You could check docker logs to be sure that everythings is ok

sudo docker logs $DOCKER_NAME

Set postgres settings

sudo docker exec $DOCKER_NAME bash $DOCKERPATH_SOURCE_DIR/conf/postgres-settings.sh
# you must restart your container to restart postgres service (needed for parameters which require a restart to update, as `shared_buffers`)
sudo docker restart $DOCKER_NAME
# you can check that your postgresql.conf file has been correctly edited
sudo docker exec $DOCKER_NAME bash -c 'cat ${PGDATA}/postgresql.conf'

Generate tiles

Let's start an interactive bash session inside $SOURCE_DIR.

sudo docker exec -it --workdir=$DOCKERPATH_SOURCE_DIR $DOCKER_NAME /bin/bash

Next commands must be run inside the docker container

Read configuration inside your docker

. ./conf/config

Create postgres user and database

sudo -u postgres bash $DOCKERPATH_SOURCE_DIR/scripts/init-db.sh

Compile openstreetmap-carto Carto MML file to Mapnik XML

mv $DOCKER_BUILD_ARG_INSTALLWORKDIR/openstreetmap-carto $DOCKERPATH_WORKING_DIR/openstreetmap-carto
# update 'dbname: "gis"' in project.mml to match your $DBPG_DATABASE_NAME
sed -i -e"s/dbname: \"gis\".*$/dbname: \"$DBPG_DATABASE_NAME\"/" $DOCKERPATH_WORKING_DIR/openstreetmap-carto/project.mml
cd $DOCKERPATH_WORKING_DIR/openstreetmap-carto/ &&  carto --quiet project.mml >osm.xml

Osm2pgsql import

Before running next command, be aware that osm2pgsql --flat-nodes option is not used by default in ./conf/config file (see $OSM2PGSQL_OPTS variable to activate it).

# prepare command
OSM2PGSQL_CMD="osm2pgsql $OSM2PGSQL_OPTS $DOCKERPATH_OSM_FILE_DIR/$OSM_LATEST_FILE_NAME"
# check it
echo $OSM2PGSQL_CMD
# run
nohup $OSM2PGSQL_CMD >> $DOCKERPATH_WORKING_DIR/osm2pgsql.log 2>&1 &
# check log file
tail -f -n 200 $DOCKERPATH_WORKING_DIR/osm2pgsql.log

Generate the tiles

Get shapefiles (processed coastline data as shapefile derived from OSM data is also needed for rendering usable map, more information at Wiki OSM - Coastline error checker)

$DOCKERPATH_WORKING_DIR/openstreetmap-carto/scripts/get-external-data.py -d $DBPG_DATABASE_NAME -U $DBPG_USER_OSMTILEMAKER_USERNAME

User postgres must be owner of your $TILES_DIR

chown postgres:postgres $DOCKERPATH_TILES_DIR

Running next command, you may notice some warnings like "warning: unable to find face-name 'Noto Sans ...". You can ignore this warnings, more information about this issue: Missing fonts after following INSTALL.md #3655.

nohup sudo -u postgres \
python3 $DOCKERPATH_SOURCE_DIR/scripts/gen-tile.py \
--bbox $BBOX \
--bbox_name $BBOX_NAME \
--mapfile $DOCKERPATH_WORKING_DIR/openstreetmap-carto/osm.xml \
--tile_dir $DOCKERPATH_TILES_DIR \
--minZoom $MINZOOM \
--maxZoom $MAXZOOM \
--num_threads $RENDERING_THREADS \
>> $DOCKERPATH_WORKING_DIR/gen-tile.log 2>&1 &
# check log file
tail -f -n 200 $DOCKERPATH_WORKING_DIR/gen-tile.log

Reinitialization

Just in case you need to restart from a fresh docker instance

sudo docker stop $DOCKER_NAME
sudo docker rm $DOCKER_NAME
# You must remove $HOST_VOLUMES_BASE_DIR by yourself (don't use variables in commands to avoid errors)

Preview with OpenLayers

These commands must be run outside docker

Requirements: you must have firefox and a web server running on localhost.

Move your tiles to your local webserver and then open ol-example.html (you could also use a symlink to avoid moving your tiles).

sudo mv $HOSTPATH_TILES_DIR /var/www/html/local-tiles
firefox ol-example.html

About performance

Useful links

It's useful to know how many nodes OSM database contains: Wiki OSM - Database statistics.

Suggestions

Below are some suggestions to customize configuration variables which impact osm2pgsql/PostgreSQL/gen-tile.py performances. It could be hard to know which values to choose as all provided advices throug links above are sometimes conflicting. If you think it could be improved, don't hesitate to contribute.

In ./conf/config file

  • OSM2PGSQL_OPTS
    • --slim: if you have enough RAM to store all nodes, you can consider to drop --slim option to speed up the import, according to Volkerschatz -osm2pgsql usage, each cached node requires 8 bytes of cache, plus about 10% to 30% overhead, so for ~5,7 billion nodes we need about 60GB RAM
    • --drop: to use with --slim because we do not need updates
    • --flat-nodes: "a binary file is used as a database of node locations". Useful to reduce database size and specify a file location (you can host it on a different hard disk). Warning: "This should only be used on full planet imports or very large extracts (e.g. Europe)" because "the file takes approximately 8 bytes * maximum node ID, or more than 50 GiB, regardless of the size of the extract." from osm2pgsql usage docs)
    • --cache: "The rule of thumb in slim mode is as follows: use the size of the PBF file you are trying to import or about 75% of RAM, whatever is smaller. Make sure there is enough RAM left for PostgreSQL. It needs at least the amount of shared_buffers given in its configuration."(from osm2pgsql usage docs). Unit is MB.
    • --number-processes: osm2pgsql usage docs offical doc says "This should typically be set to the number of CPU threads, but gains in speed are minimal past 8 threads.". So we use as many threads as CPU cores we have (or more if your processor is hyperthreaded, lscpu command could be useful to know more about your processor)
    • --disable-parallel-indexing: not used in default config file, but could be useful ("disables the clustering and indexing of all tables in parallel. This reduces disk and RAM requirements during the import, but causes the last stages to take significantly longer.")
  • RENDERING_THREADS: "rendering threads to spawn in gen-tile.py, should be roughly equal to number of threads available" says original generate_tiles.py tiles rendering script

In ./conf/postgres-settings.sh file: maybe use Paul’s Blog - New Server PostgreSQL Tuning recommendations.

About filesystem settings: using a ZFS filesystem for the hard disk hosting PostgreSQL database could speed up the import and reduce disk space usage (see Paul’s Blog - ZFS Settings for Osm2pgsql). Recommended parameters are recordsize of 8K (run zfs set recordsize=8k $your_pool) and lz4 compression (run zfs set compression=lz4 $your_pool)

Benchmarks

Note: feel free to add your own benchmark below, even with few details!

Full planet

Hardware and software configuration + osm2pgsql benchmarks

Available at OSM Wiki - Osm2pgsql/benchmarks - Desktop Debian 9, 4 cores i5-6500 CPU @ 3.20GHz/32GB RAM, 1TB+500GB SSD (hstore slim drop flat-nodes and ZFS filesystem)

Tiles production from level 1 to 12

Total: 415 hours ; 17,3 days ; ~ 13 957 698 tiles ; average speed : 9,34 tiles/sec ; 24,8 GB

Details:

  • from level 1 to 10 : 40 hours ; 1,7 days ; ~ 850 000 tiles ; vitesse moyenne : 5,9 tiles/sec ; 870 MB
  • level 11 : 81 hours ; 3,4 days ; ~ 2 623 488 tiles ; average speed : 9 tiles/sec ; 1,9 GB
  • level 12 : 294 hours ; 12,3 days ; ~ 10 484 210 tiles ; average speed : 9,9 tiles/sec ; 22 GB
Speed by longitude from level 11 to 13

tiles-production-speed-by-longitude.png

osmtilemaker's People

Contributors

apflkuacha avatar audour avatar centic9 avatar jimmyjones2 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

osmtilemaker's Issues

SHM size inadequate for planet

The docker container is started with 256MB SHM, but I needed about 3GB to render the planet. Maybe add a note to the docs?

I had to add printing of exception details to gen-tile.py to figure this out!

RAM runs out

Hi,
I am currently trying to generate tiles for lower Bavaria, Germany.
Zoom-Levels 1-15 work fine but every time trying level >=16 it crashes after a few hours because RAM is full.
While its running, the RAM-usage slowly goes up. From what I can tell it's Postgres that hogs all of it.

I'm currently running this on a machine with an EPYC 7502P and 128GB of RAM which should be more than enough.

This is my config-file, the postgres-config is unchanged:

#!/bin/bash

VERSION=1.1

# OSM DATA SOURCE
#################
OSM_LATEST_FILE_NAME=bayern-latest.osm.pbf
OSM_LATEST_FILE_DOWNLOAD_URL=https://download.geofabrik.de/europe/germany/bayern-latest.osm.pbf

# DOCKER CONFIG
###############
DOCKER_BUILD_TAG=osmtilemaker:$VERSION
DOCKER_BUILD_ARG_INSTALLWORKDIR=/var/install
DOCKER_NAME_SUFFIX=_v${VERSION}
DOCKER_NAME=osmtilemaker${DOCKER_NAME_SUFFIX}
DOCKER_HOST_PORT_TO_PUBLISH=5435

# HOST/DOCKER SHARED VOLUMES 
############################

# SOME SHARED VOLUMES NAMES
WORKING_DIR_NAME=working_dir
OSM_FILE_DIR_NAME=osm_data
OSM2PGSQL_FLATNODE_DIR_NAME=osm_nodes
TILES_DIR_NAME=tiles
LOG_DIR_NAME=log
# HOST_VOLUMES_PATH
HOST_VOLUMES_BASE_DIR=${HOME}/docker_mounted_volumes/$DOCKER_NAME-docker-volumes # default base directory on your host machine where shared docker volumes must be localized
HOSTPATH_WORKING_DIR=$HOST_VOLUMES_BASE_DIR/$WORKING_DIR_NAME
HOSTPATH_OSM_FILE_DIR=$HOST_VOLUMES_BASE_DIR/$OSM_FILE_DIR_NAME
HOSTPATH_PG_DATA_DIR=$HOST_VOLUMES_BASE_DIR/pg_data
HOSTPATH_OSM2PGSQL_FLATNODE_DIR=$HOST_VOLUMES_BASE_DIR/$OSM2PGSQL_FLATNODE_DIR_NAME
HOSTPATH_TILES_DIR=$HOST_VOLUMES_BASE_DIR/$TILES_DIR_NAME
# DOCKER_VOLUMES_PATH
DOCKER_VOLUMES_BASE_DIR=/docker_mounted_volumes # base directory inside your docker container where shared docker volumes must be localized
DOCKERPATH_WORKING_DIR=$DOCKER_VOLUMES_BASE_DIR/$WORKING_DIR_NAME
DOCKERPATH_SOURCE_DIR=$DOCKER_VOLUMES_BASE_DIR/sources
DOCKERPATH_OSM_FILE_DIR=$DOCKER_VOLUMES_BASE_DIR/$OSM_FILE_DIR_NAME
DOCKERPATH_OSM2PGSQL_FLATNODE_DIR=$DOCKER_VOLUMES_BASE_DIR/$OSM2PGSQL_FLATNODE_DIR_NAME
DOCKERPATH_TILES_DIR=$DOCKER_VOLUMES_BASE_DIR/$TILES_DIR_NAME

# POSTGRESQL CONFIG
###################

export PGCLIENTENCODING=UTF8
## PASSWORD
DBPG_USER_POSTGRES_PWD_DEFAULT=6myXVKF22vgJUv5fx
DBPG_USER_POSTGRES_PWD=$DBPG_USER_POSTGRES_PWD_DEFAULT
## USERS
DBPG_USER_OSMTILEMAKER_USERNAME=osmtilemaker
## DBPG INSTANCE
DBPG_HOST=localhost
DBPG_DATABASE_NAME=osmtilemaker

# OSM2PGSQL CONFIG
##################

OSM2PGSQL_OPTS="\
--username $DBPG_USER_OSMTILEMAKER_USERNAME --database $DBPG_DATABASE_NAME \
--hstore  \
--style $DOCKERPATH_WORKING_DIR/openstreetmap-carto/openstreetmap-carto.style \
--tag-transform-script $DOCKERPATH_WORKING_DIR/openstreetmap-carto/openstreetmap-carto.lua \
--slim --drop \
--cache 655 \
--number-processes 8 \
--multi-geometry "
# uncomment next line if you want to use --flat-nodes (only for huge extracts like planet or europe, see README.md)
# OSM2PGSQL_OPTS="$OSM2PGSQL_OPTS --flat-nodes $DOCKERPATH_OSM2PGSQL_FLATNODE_DIR/nodes.cache"

# RENDERING CONFIG
###############

RENDERING_THREADS=64

## ZOOMS (FROM 1 TO 18)
MINZOOM=16
MAXZOOM=17

## BBOX 
# - you can get your bbox limits graphically from http://tools.geofabrik.de/calc/ or http://harrywood.co.uk/maps/uixapi/xapi.html
# - you can estimate number and size of generated tiles thanks to http://tools.geofabrik.de/calc/

## Hamburg
BBOX_NAME='Niederbayern'
MIN_LONG=11.59
MIN_LAT=48.2
MAX_LONG=13.84
MAX_LAT=49.18

## World extent
#BBOX_NAME='World'
#MIN_LONG=-180.0
#MIN_LAT=-90.0
#MAX_LONG=180.0
#MAX_LAT=90.0
BBOX="$MIN_LONG $MIN_LAT $MAX_LONG $MAX_LAT"

ShapeFile no longer accessible

Hello,
this shapefile http://www.naturalearthdata.com/http//www.naturalearthdata.com/download/110m/cultural/ne_110m_admin_0_boundary_lines_land.zip is no longer accessible, which is needed by this script - https://github.com/gravitystorm/openstreetmap-carto/blob/v5.1.0/scripts/get-shapefiles.py
At this point of your docs https://github.com/Magellium/osmtilemaker#generate-the-tiles running this scripts returns timeout errors, and doesn't continue with downloading other shapefiles(just first of them).
I overcame it by copying those missing shapefiles from other of my projects to destination folder.
I've also found this https://github.com/nvkelso/natural-earth-vector/tree/master/110m_cultural, but it contains a lot more than those basic ne_110m_admin_0_boundary_lines_land.

Problem with docker image

Hello,
i'm not able to start the just created docker image.

docker run fails and docker logs reports just:

/usr/local/bin/docker-entrypoint.sh: line 82: initdb: command not found
does someone had a similar problem?

Error when rendering tiles: RuntimeError: Postgis Plugin: Null connection

When following the steps in the README with default configuration (only pbf-file and boundin-box are set differently), I get the following strange error at the step where tiles are actually rendered.

ERROR:root:message
Traceback (most recent call last):
  File "/docker_mounted_volumes/sources/scripts/gen-tile.py", line 136, in loop
    self.render_tile(tile_uri, x, y, z)
  File "/docker_mounted_volumes/sources/scripts/gen-tile.py", line 116, in render_tile
    mapnik.render(self.m, im)
RuntimeError: Postgis Plugin: Null connection
genTile LOG> 2022-03-25 09:58:10: line 139: ERROR: Exception generating tile: /docker_mounted_volumes/tiles/9/269/165.png, 9, 269, 165
ERROR:root:message
Traceback (most recent call last):
  File "/docker_mounted_volumes/sources/scripts/gen-tile.py", line 136, in loop
    self.render_tile(tile_uri, x, y, z)
  File "/docker_mounted_volumes/sources/scripts/gen-tile.py", line 116, in render_tile
    mapnik.render(self.m, im)
RuntimeError: Postgis Plugin: Null connection
ERROR:genTile:Exception generating tile: /docker_mounted_volumes/tiles/9/269/165.png, 9, 269, 165
genTile LOG> 2022-03-25 09:58:10: line 139: ERROR: Exception generating tile: /docker_mounted_volumes/tiles/7/67/41.png, 7, 67, 41
ERROR:genTile:Exception generating tile: /docker_mounted_volumes/tiles/7/67/41.png, 7, 67, 41
genTile LOG> 2022-03-25 09:59:32: line 149: INFO: Trentino: 1, 1, 0,
INFO:genTile:Trentino: 1, 1, 0,

Mapnik is at 3.1.0, Python-mapnik at 3.0.23:

$ pip3 list | grep map
mapnik             3.0.23
$ dpkg --list | grep map
ii  libmapnik3.1                           3.1.0+ds-1                     amd64        C++ toolkit for developing GIS applications (libraries)
ii  mapnik-utils                           3.1.0+ds-1                     amd64        C++ toolkit for developing GIS applications (utilities)
ii  python3-mapnik                         1:0.0~20200224-7da019cf9-3     amd64        Python 3 interface to the mapnik library

I could not find any error-log from postgres

I found mapnik/mapnik-support#60 (comment) which mentions that such an error-message might be a postgres-error that is not reported well, but it seems mapnik 3.1.0 is in place already here and thus low-level errors should not be hidden here.

Anything else that I can try to make tile-generation work here?

Zoom 19+ Tiles

First, thanks for putting together a great tool! It was easy to get started following your instructions, and I've been able to generate tiles for my region. I can tell you put a lot of time and energy into this.

Now to the question: Is there a way to generate tiles for higher zoom levels, 19 and above? Does that even make sense? My understanding is that sometimes tile servers will construct those tiles on the fly based on lower-resolution images, but I'm just dumping the images in a folder and letting nginx handle the rest, and things look somewhat blurry at higher zooms with just the 18 zoom tiles.

I considered modifying your script, but thought I would ask first, since I don't understand the limits of the underlying tools. Setting the MAX_TILE variable to 19 has no effect, and the tool will instead stop after confirming all lower-resolution tiles have been created.

High-res tiles

A question, not an issue …

Have you tried generating high-res tiles with osmtilemaker and can share how you did it by any chance?

Thanks for the great project!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.