Creating, sharing and running a Docker image to decode AIS messages
(Posted 2018-09-24)
Recently, I showed how to use AISMessages to quickly build a Spring Boot based HTTP/JSON-service capable of converting NMEA-armoured AIS messages into JSON-based parsed AIS messages (what are AIS messages?. Now we want to make it even easier to get this AIS decoder service running, by building and sharing a Docker image of the service, which can easily be downloaded and spun up by anyone using Docker.
Getting ready
To get going we first want to make sure, that Docker is installed. For our purposes, we will use Docker for Mac. So go and grab that if you don’t already have it. If you are preferring a certain package manager or are using a different operating system, you will have to get Docker for that – take a look at “Get Started with Docker”.
With Docker properly installed, you should be able to run:
and get a sensible output.
Second we clone the source code of our AISdecoder into a folder on the local harddrive:
For the sake of getting the repository in the right starting state, we will rewind it a bit to the following commit:
And finally we compile the project in order to produce the binary artifact that we will run using Docker:
Now we are ready – and this is the file that we want to run in a Docker container:
Adding the Dockerfile
With all prerequisites in place, the first thing we want to do is to add a Dockerfile
to the project. The Dockerfile
describes how Docker should build the Docker image. It could look like this:
The FROM
keyword specifies the Docker base image. The rest of the Dockerfile can roughly be considered to be changes or additions to this base image. Base images can be self-built or they can be searched or browsed on e.g. Docker Hub, where contributors upload and share images. We choose to use the openjdk:11-jre-slim
image from Docker Hub, which is a Linux-based image with the OpenJDK version of Java 11 pre-installed. For a Spring Boot-based Java SE application this is a good start.
The MAINTAINER
keyword mainly adds meta information to the image and is not very important here.
COPY
on the other hand is quite important here. It copies the compiled .war-file from your local developer machine into the generated Docker image – and places it in folder /app as aisdecoder.war.
ENTRYPOINT
defines the executable command, that will be fired by default when running a container based on this image using docker run … later on. As you can probably see, this is equivalent to java -jar /app/aisdecoder.war – i.e. a command line based launch of our Java SE application.
Finally, EXPOSE 8080/tcp
tells Docker, that a container launched from this image listens on the specified network port at runtime. In this case in listens for TCP-based network traffic on port 8080 – which is exactly where the embedded Tomcat in our Java SE application listens. So any traffic going to port 8080 of this container will go to our own embedded Tomcat.
To learn more Dockerfile keywords – and details of those used here – it is a good idea to familiarize yourself with the reference documentation for Dockerfiles.
Building the Docker image
With the Dockerfile in place it is time to actually create the Docker image. This can be done like this:
This means, that Docker has now successfully built an image identified by 9f37cd551132
.
Running the Docker image as a container
To spawn a container based on this image, we can issue the following command line:
This instructs Docker to launch a new container based on image 9f37cd551132
. Thanks to the -p option docker will bind to port 8080 on the local host and forward traffic on this port to port 8080 inside the Docker container. In effect, this causes traffic on port 8080 on the host machine to be forwarded to the embedded Tomcat inside our Java SE application running in the Docker container.
Using the container
So, with our Docker container running, we can now reach its functionality by sending HTTP traffic to port 8080 on our host machine. Like this:
… which (as we have seen previously) will result in this output:
Building a Docker image with a tag
You may have experienced that 9f37cd551132
is not a terribly easy “name” to remember. Actually it is a hash value – and it changes dramatically with every little change to our image. To ease this, Docker supports associating descriptive – easier-to-remember – names with these hashes. So Docker images can be built with a name like this:
Here tbsalling/aisdecoder
is the repository name, and latest is the actual tag name. So now tbsalling/aisdecoder:latest
points to the image with hash value 9f37cd551132
.
Read more about Docker’s valid tags.
Running a Docker container using a tag
With a tag name in place, a Docker container can be spun up like this:
Uploading an image to Docker hub
With all this work done – wouldn’t it be nice if we could share the result? This would allow anyone to run aisdecoder locally by just downloading our Docker image and run it in a Docker container? Luckily this is possible by uploading our image to Docker Hub.
To do that first make sure, that you have a valid account on https://hub.docker.com. Then, from the command line login like this:
With the image already built (see above) we can now push (upload) it to Docker Hub using the repository and tag names like this:
Now the image is uploaded to Docker Hub. You can see that for yourself by visiting https://hub.docker.com/r/tbsalling/aisdecoder/.
Now let us logout of Docker Hub so that we could be anyone in the public:
Any random person (with Docker installed…) can now pull (download) and run this image as simple as:
Conclusion
In this post I have shown how to create a Docker image containing an HTTP/JSON-based decoder for NMEA messages with AIS-contents. I showed how to upload and share this image via Docker Hub – and demonstrated how anyone can pull this image and run the AIS decoder from scratch with just 2 command line instructions (provided Docker is already installed).
Have fun 🙂