#DaysOfArm (14 of X)

This is my 14th #DaysOfArm article that tracks some of the experiences that I’ve had so far. And just to recap from the first post (here) on June 12 2021.

It’s been just over 2 weeks since the launch of Ampere Arm deployed in Oracle Cloud Infrastructure (OCI). Check this article out to learn more (here). And it’s been about one week since I started looking into the new architecture and deployment, since I started provisioning the VM.Standard.A1.Flex Compute Shape on OCI and since I started migrating a specific application that has many different variations to it to test it all out.

This is my next learning where I’ve deployed successfully openrouteservice – an open-source routing / direction API all deployed on an 4 OCPU with 24 GB of RAM in an Always Free Tier tenancy.

Over the past couple of weeks, I’ve been working in the background with some open-source projects. I published a recent one where I deployed Pelias (here) a open-source geocoding platform.- Pelias (here). The purpose of the geocoding was to simplify the ability to create a set of directions. For this, I opted for openrouteservice (here).

Image from https://github.com/GIScience/openrouteservice

Similar to geocoding, there are numerous existing solutions and APIs out there for routes and directions but they have different terms and conditions that limit their use :- as either a trial; requires a paid account; or restricts the use of the geocode API with their other services including maps or routes.

I wanted to research and create something that aligned with the purpose of Oracle Cloud Always Free Tier.

Here is a high-level detail of how to get this going on OCI.

1. Provision Compute / Network

I provisioned a Virtual Cloud Network (VCN) using the VCN Wizard (noting that there is the service limit of 1 VCN in Always Free Tier).

Note: If you want this service available outside of the network, then add ingress rule for destination port of 8080/TCP in the network security list.

I provisioned a Compute instance with the following configuration.

  • VM.Standard.A1.Flex Compute Shape
  • 4 OCPUs with 24 GB of RAM (which is the Always Free Tier service limit)
  • ~150GB for the block storage for the book volume
  • Oracle Linux 8 (with the latest update)

If you want more assistance, there is a tutorial that you can follow (here).

2. Install Software Requirements

Once you have provisioned and connected to the instance using either ssh or putty, here is a brief list of commands to run as root. Assuming you just logged into the VM as opc.

sudo su -
dd iflag=direct if=/dev/sda of=/dev/null count=1
echo "1" | sudo tee /sys/class/block/sda/device/rescan
cd /usr/libexec
./oci-growfs
yum update -y && yum install -y git python3-devel
yum install -y automake autoconf
python3 -m pip install --upgrade pip
dnf config-manager --add-repo=https://download.docker.com/linux/centos/docker-ce.repo
yum install docker-ce
service docker start
systemctl enable docker
useradd giscience
usermod -a -G docker giscience
firewall-cmd --add-port 8080/tcp --permanent --zone=public
firewall-cmd --add-port 443/tcp --permanent --zone=public
firewall-cmd --add-port 80/tcp --permanent --zone=public
firewall-cmd --reload

In summary, this is what this does.

  • Expands the default boot volume size to the ~150 GB that has been provisioned.
  • Updates the packages and installs git and additional python3 packages.
  • Also install automake and autoconf (for building osmctools).
  • Upgrades pip (python installer).
  • Install docker (community edition) repository and then docker itself.
  • Configure docker as a service and start docker.
  • Create a user called giscience and add the docker group to that user.
  • Update the firewall for openrouteservice.

3. Download openrouteservice (from github)

Once this has been executed as root, then the following can be executed as giscience (the application user). This will install openrouteservice build the docker images and store them locally. Assuming you just logged into the VM as opc.

sudo su - giscience
mkdir repos
cd repos
git clone https://github.com/GIScience/openrouteservice && cd openrouteservice
cp openrouteservice/src/main/resources/app.config.sample openrouteservice/src/main/resources/app.config
docker build -t openrouteservice/openrouteservice:latest .

This is relatively easy part of the process to build the docker image to run.

4. Start Importing Datasets

There are a few setup tasks required.

4.1 Setup the environment

This is once-off setup to configure the environment to where the maps will be stored and referenced as well updating the Java memory configuration. Assuming you are still the giscience user.

# create maps directory for the maps to download and process
cd ~/repos/openrouteservice/docker
mkdir maps

# update the docker-compose file
sed -i 's/\#- .\/your_osm.pbf:\/ors-core\/data\/osm_file.pbf/- \/home\/giscience\/repos\/openrouteservice\/docker\/maps\/osm_file.pbf:\/ors-core\/data\/osm_file.pbf/g' docker-compose.yml
sed -i 's/-Xms1g -Xmx2g/-Xms2g -Xmx16g/g' docker-compose.yml
4.2 Download maps

OpenStreetMaps (here) data is used to create the graphs required. The source of this data that I used for this is Geofabrik (here). The specific type that I used was the OSM PBF format. In addition, I would suggest being as specific as possible with the maps that you want to use to ensure you have sufficient block volume storage for the graph data generated.

cd ~/repos/openrouteservice/docker/maps
wget https://download.geofabrik.de/australia-oceania-latest.osm.pbf
wget https://download.geofabrik.de/asia/malaysia-singapore-brunei-latest.osm.pbf

If you are only needing a single region, rename it to be osm_file.pbf aligned to the docker-compose file updates.

4.3 Merge maps (if required)

The service supports a single OSM PBF file. If you have multiple data files downloaded, you will need to merge the files into a single file. I found osmctools that enabled this process.

# clone the osmctools repository
cd ~/repos
git clone https://gitlab.com/osm-c-tools/osmctools

# build the osmctools
cd osmctools
autoreconf --install
./configure
make all

# copy these tools locally so they can be referred to
cd src/
cp osmconvert osmfilter osmupdate ~/.local/bin

There is a series of conversion steps to merge these files. Here is an example where I merged two datasets – one from Australia and one from Singapore.

cd ~/repos/openrouteservice/docker/maps
osmconvert australia-oceania-latest.osm.pbf -o=australia-oceania-latest.o5m
osmconvert malaysia-singapore-brunei-latest.osm.pbf -o=malaysia-singapore-brunei-latest.o5m
osmconvert `ls *.o5m` -o=osm_file.o5m
osmconvert osm_file.o5m -o=osm_file.pbf

You can remove the original and the o5m format files if you are requiring additional storage.

4.3 Start the service

The technology stack is relatively simple with a single docker container. The following command starts up the instance.

# cd into the docker directory
cd ~/repos/openrouteservice/docker
docker-compose up -d

The docker container ors-app creates a log file that can be accessed.

docker logs -f ors-app

There are additional directories generated by the container that are created and owned by the root user. The ownership of these files and directories can be changed to the application user.

The lifecycle of the ors-app has two distinct phases described below.

4.3.1 Startup with Maven

The service is deployed to Tomcat and uses Apache Maven for managing the dependencies. Upon the first startup, the container will initialise the Maven repository which may take minutes to complete. You will likely to see the following warning log entries. Through my observations, I have not seen any impact due to these warnings.

### Package openrouteservice and deploy to Tomcat ###
WARNING: An illegal reflective access operation has occurred
WARNING: Illegal reflective access by com.google.inject.internal.cglib.core.$ReflectUtils$1 (file:/usr/share/maven/lib/guice.jar) to method java.lang.ClassLoader.defineClass(java.lang.String,byte[],int,int,java.security.ProtectionDomain)
WARNING: Please consider reporting this to the maintainers of com.google.inject.internal.cglib.core.$ReflectUtils$1
WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations
WARNING: All illegal access operations will be denied in a future release
4.3.2 Graph Processing

The service processes the OSM data to create the graph data required. This can be a complex process and does take time to do. A couple of things that you can monitor.

Watch the disk utilisation growth

The graph data is processed and stored on disk in the elevation_cache and graph directories. I recommend monitoring the disk utilisation.

Watch the process utilisation

This process is multi-threaded and hence it is typically to see the Java process running at 100%+.

Process Recovery

This processing may fail (I’ve seen a couple of scenarios where the processing stopped). This is ok. You can fix the issue and restart the process.

cd ~/repos/openrouteservice/docker
docker-compose down
docker-compose up -d

I had issues with corrupt zip files (which I had to delete first). Also I had issues with OutOfMemory errors (which a restart helps). I have had times where I had restarted the process multiple times before it finished the processing.

Watch the log files

These log messages will indicate that the processing is complete and the service is ready.

10 Jul 00:38:56 INFO [routing.RoutingProfileManager] - ========================================================================
10 Jul 00:38:56 INFO [routing.RoutingProfileManager] - ====> Recycling garbage...
10 Jul 00:38:56 INFO [routing.RoutingProfileManager] - Before:  Total - 15.84 GB, Free - 8.34 GB, Max: 16 GB, Used - 7.50 GB
10 Jul 00:38:57 INFO [routing.RoutingProfileManager] - After:  Total - 15.84 GB, Free - 10.98 GB, Max: 16 GB, Used - 4.86 GB
10 Jul 00:38:57 INFO [routing.RoutingProfileManager] - ========================================================================
10 Jul 00:38:57 INFO [routing.RoutingProfileManager] - ====> Memory usage by profiles:
10 Jul 00:38:57 INFO [routing.RoutingProfileManager] - [1] 1.92 GB (39.4%)
10 Jul 00:38:57 INFO [routing.RoutingProfileManager] - [2] 1.17 GB (24.1%)
10 Jul 00:38:57 INFO [routing.RoutingProfileManager] - Total: 3.09 GB (63.5%)
10 Jul 00:38:57 INFO [routing.RoutingProfileManager] - ========================================================================
4.4 Service Status

There are two URLs that are available to help with the service status. These can also give you an indicator of the startup process.

This URL pattern shows the status or the service as well as some metadata.

http://<ipaddress>:8080/ors/status

This URL pattern shows the health of the service. This is useful for a health status URL for load-balancing.

http://<ipaddress>:8080/ors/health

5. Test the APIs

From here, we can test it out … The base URL of the service is:

http://<ipaddress>:8080/ors

and much of the documentation of the APIs (including the resource path) can be appended to this base URL including the version (which is v2). To interactively learn more about the APIs, you can try out the Open Route Service API Playgound (here).

It is now ready !!!


There are a couple of things that I’m continuing to work on.

  • Embedding this into other solutions like Oracle APEX.
  • Creating an Infrastructure as Code implementation for this stack.

This would not be possible for the countless people and organisations that contribute to these projects. Here is a list of them based upon the specific projects that I’ve forked or used. If I’ve missed someone, please let me know.

  • The team from openrouteservice (here).
  • The team from OpenStreetMap (here) where some of the data is sourced.
  • The team from Geofabrik (here) where some of the data is sourced.
  • The team from osmctools (here) which helps merging the OSM PBF files.

It is important to attribute everyone in this process.

If you want to try this out yourself or work on your own application, sign-up (here) for the free Oracle Cloud Trial. I’d be interested to hear your experiences and learn from others as well. Leave a comment or contact me at jason.lowe@oracle.com if you want to collaborate.

There’s plenty of work to make this more achievable for everyone. And hence sharing this knowledge is the reason why I’m writing this series – #XDaysOfArm. I’ll keep documenting as long as I keep learning.

Author: Jason Lowe

I am passionate about how organisations adopt IT quickly and sustainably to achieve a specific and measurable outcome. This thinking is supported through lean IT practices in operational support and project delivery, and adopting these practices with Oracle technologies by creating sustainable platforms. I'm also interested different perspectives and drivers - from enterprise to start-ups, academia to commercial to public sector, cost-sensitive (risk) to value-driven (reward) - all of which influences decisions that organisations make. I have a passion for community and have been called "a connector" - meeting new people that are trying to solve valuable and hard problems and connecting them with others that can validate and help realise their full potential. I've supported different organisations like TADHack and Hacking Health as a global organiser. I'm is a persistent blogger on medium.com and redthunder.blog and on LinkedIn - https://www.linkedin.com/in/lowe-jason #CommunityMatters #ItTakesAVillage

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s