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)! dot output

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.

Published to Docker Hub

Notice that Short Description & Full Description 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.

connect github

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

automated build

The Short Description field is supposed to be filled manually, while the Full Description 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.

build settings

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).

build details

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

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

What next?

Well, stay tuned for upcoming articles. Say hi, share this article, leave a comment or Subscribe now to stay updated through our newsletter. Also, check out our services or contact us at contact@attosol.com for your software and consultancy requirements.

Ads:

Disclosure: Some links you will find on this web page are considered affiliate links. This means that if you press on the link and ultimately make a purchase, we might receive a commission from the advertiser. This does not affect you or your purchase price, only helps us dedicate resources to make this site more useful to you.

Rahul Soni

⌘⌘ Entrepreneur. Author. Geek. ⌘⌘

Kolkata, India

Subscribe to Attosol Technologies

Get the latest posts delivered right to your inbox.

or subscribe via RSS with Feedly!