Using Docker for distributing command line tools - Step by Step

There are some inherent benefits of using a command line tool using Docker. This article will show you step-by-step how to distribute a command line tool using Docker. In case you are new to Docker, get up to speed with Docker.

Before I get to the details, let me share a few reasons why you might want to do this:

  • It keeps your host clean
  • You don't have to install all the frameworks and dependencies your tool demands
  • You get better portability of your tool
  • Your tool is now more reusable
  • You don't get into messy version conflicts on the host
  • It saves you time that for reconfiguring the tool on different hosts

For this example, let's work with a tool like Graphviz. In short, if you give it a file (call it file.dot for now) like this...

digraph G {
 main -> parse -> execute;
 main -> init;
 main -> cleanup;
 execute -> make_string;
 execute -> printf
 init -> make_string;
 main -> printf;
 execute -> compare;
}

...you will get an output like this (file.png)!

Neat, huh?

Learn more about drawing graphs with Dot.

Step 1 - Create a Dockerfile

Here is how the Dockerfile looks like:

FROM alpine:3.7
  
RUN apk add --update graphviz ttf-ubuntu-font-family && \
    mkdir /dot

WORKDIR /dot

CMD dot -Tpng
  • The Alpine Linux is a ridiculously small image. It is a minimal Docker image based on Alpine Linux with a complete package index and only 5 MB in size!
  • Don't confuse APK (Alpine Linux Package Management) with the Android Application Package. It is quite like yum or apt-get.
  • The RUN command installs graphvis and ttf-ubuntu-font-family. I tried without the font but the output was garbled. I had to install a font explicitly to get an appropriate output.
  • The CMD command executes the dot command with certain parameters.

Step 2 - Build Docker image

$ docker build -t attosol/dot2png:1.0.0 .
Sending build context to Docker daemon  46.59kB
Step 1/4 : FROM alpine:3.7
 ---> 3fd9065eaf02
Step 2/4 : RUN apk add --update graphviz ttf-ubuntu-font-family &&     mkdir /dot
 ---> Running in 3ad3e58fcd69
fetch http://dl-cdn.alpinelinux.org/alpine/v3.7/main/x86_64/APKINDEX.tar.gz
fetch http://dl-cdn.alpinelinux.org/alpine/v3.7/community/x86_64/APKINDEX.tar.gz
(1/30) Installing libxau (1.0.8-r2)
(2/30) Installing libbsd (0.8.6-r1)
(3/30) Installing libxdmcp (1.1.2-r4)
(4/30) Installing libxcb (1.12-r1)
(5/30) Installing libx11 (1.6.5-r1)
(6/30) Installing libxext (1.3.3-r2)
(7/30) Installing libxrender (0.9.10-r2)
(8/30) Installing expat (2.2.5-r0)
(9/30) Installing libbz2 (1.0.6-r6)
(10/30) Installing libpng (1.6.34-r1)
(11/30) Installing freetype (2.8.1-r2)
(12/30) Installing fontconfig (2.12.6-r0)
(13/30) Installing pixman (0.34.0-r3)
(14/30) Installing cairo (1.14.10-r0)
(15/30) Installing libgcc (6.4.0-r5)
(16/30) Installing libffi (3.2.1-r4)
(17/30) Installing libintl (0.19.8.1-r1)
(18/30) Installing libuuid (2.31-r0)
(19/30) Installing libblkid (2.31-r0)
(20/30) Installing libmount (2.31-r0)
(21/30) Installing pcre (8.41-r1)
(22/30) Installing glib (2.54.2-r0)
(23/30) Installing libltdl (2.4.6-r4)
(24/30) Installing libxft (2.3.2-r2)
(25/30) Installing graphite2 (1.3.10-r0)
(26/30) Installing harfbuzz (1.6.3-r0)
(27/30) Installing pango (1.40.14-r0)
(28/30) Installing libstdc++ (6.4.0-r5)
(29/30) Installing graphviz (2.40.1-r0)
(30/30) Installing ttf-ubuntu-font-family (0.83-r0)
Executing busybox-1.27.2-r7.trigger
Executing fontconfig-2.12.6-r0.trigger
Executing glib-2.54.2-r0.trigger
Executing graphviz-2.40.1-r0.trigger
OK: 30 MiB in 41 packages
 ---> e6b79f54e7af
Removing intermediate container 3ad3e58fcd69
Step 3/4 : WORKDIR /dot
 ---> 1bade4d4c4ea
Removing intermediate container e88f70bb2b50
Step 4/4 : CMD dot -Tpng
 ---> Running in d7ee1981e6d2
 ---> 308223891ee3
Removing intermediate container d7ee1981e6d2
Successfully built 308223891ee3
Successfully tagged attosol/dot2png:1.0.0

You will be amazed that this fully functional image costed you just ==30.8MB==!

$ docker image ls
REPOSITORY          TAG                 IMAGE ID            CREATED              SIZE
attosol/dot2png     1.0.0               308223891ee3        About a minute ago   30.8MB

Step 3 - Convert file.dot to file.png

In order to use this image, you can now execute:

$ cat file.dot | docker run --rm -i attosol/dot2png:1.0.0 > file.png
  • --rm removes the container once it is done
  • --i instructs Docker to keep STDIN open even if not attached

Step 4 - Publish it to Dockerhub

Your tool is now working locally. Let's publish it to the Dockerhub. Ensure that you have registered and keep your username & password handy for the next steps.

Login

$ docker login
Username (your_user_id): 
Password: 
Login Succeeded

Tag (optional)

$ docker tag attosol/dot2png:1.0.0 attosol/dot2png:latest

Read more about TAG.

Publish

$ docker push attosol/dot2png
$ docker push attosol/dot2png:1.0.0

NOTE: attosol is our organization name at Dockerhub.

Yay! It is done. Now you can run the following on any other host and expect the command to convert the DOT file into a PNG.

$ cat file.dot | docker run --rm -i attosol/dot2png:1.0.0 > file.png

or

$ cat file.dot | docker run --rm -i attosol/dot2png > file.png

NOTE: The second command above automatically points to the :latest tag. If you don't have the latest tag pushed, you will be required to mention the :tag explicitly like in the the first command.

If you check Docker hub, you should be able to see this image.

Notice that Short summary & Full summary is empty. Wouldn't it be great if this is automatically filled up for us?

For this to happen, you need to have a Github/Bitbucket repository. Push your source code to Github with a README.md file. Post that, connect your account to Dockerhub.

...and create an Automated Build by clicking Create > Create Automated Build.

The Short summary field is supposed to be filled manually, while the Full summary is picked up automatically from the README.md file. Once you have created the build, go to Build settings and select the branch & tags appropriately and Save Changes. You can manually trigger a build from this screen as well.

After saving this... every time you push some changes to your repository, a new build will be triggered automatically and you can watch the build details as it happens (if you like).

Review the Repo again and you should see the Short & Full summary populated.

That would be all for now. I hope you found this article helpful! Happy Docking :-)

What next?

Well, stay tuned for upcoming articles. You may contact us at contact@attosol.com for your software and consultancy requirements.

© 2023, Attosol Private Ltd. All Rights Reserved.