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).
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%+.
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.92 GB (39.4%) 10 Jul 00:38:57 INFO [routing.RoutingProfileManager] -  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.
This URL pattern shows the health of the service. This is useful for a health status URL for load-balancing.
5. Test the APIs
From here, we can test it out … The base URL of the service is:
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 firstname.lastname@example.org 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.