The first time I successfully fired up a container I was pretty excited with the potential this tool had to make a lot of everyday tasks much easier. For example when I had a colleague ask for package xyz from EPEL/PPA made available from our internal mirrors, I could just fire up a clean centos/ubuntu/debian container and download the packages much faster. This seemed much better than having a centos7 virtual machine that I needed to fire up or browsing epel manually.

Then I realized it solved the issues of putting together a script you want to use locally but you need to install something from pip/npm/CPAN. I dislike having to add these things to my desktop, or having to setup parallel environments. Now one can put all this in a container and not have to worry about dirtying up your desktop install.

One of my first use cases was ipython3 (python 2.7 was the system default). Docker made this so much easier.

Create Local Docker Images

In order to create an image locally on your workstation you will need to make a “Dockerfile”. This file contains instructions telling docker how to assemble the image.

  • Dockerfile for ipython3 - literally called “Dockerfile”
FROM alpine:latest

RUN set -ex \
    && apk update \
    && apk add python3 libxml2 libxslt \
    && apk add --no-cache --virtual .build-deps \
        gcc python3-dev musl-dev linux-headers libxml2-dev libxslt-dev \
    && pip3 install --upgrade pip \
    && pip3 install ipython requests ftfy zeep pytz docker-py mysql-connector==2.1.6 \
    && apk del .build-deps

CMD ["/usr/bin/ipython"]
  • FROM - Is the base image and version. In this case I am using the lastest base image for alpine Linux.

    • You can specify a specific tag if you need to. To see valid alpine tags for example you would need to look at the project. In this case its at https://hub.docker.com/_/alpine/

    • apk is the package manager in Alpine.

  • RUN - Run these commands in order. Adds the goodies you want to have in your image.

  • CMD - in this case when ipython starts it will run in the foreground. Any process you fire off in the container should always be in the foreground. If not the container will just exit when the command completes. See https://docs.docker.com/engine/reference/builder/#parser-directives for all the goodies.

Thats about all there is to it for this one. Now I can build the image locally.

Building the Image.

Your Dockerfile should be in its own directory

$ ls
Dockerfile  README.md

Run docker build -t “image_name” .

  • in this case I am going with local/ipython3
$ sudo docker build -t local/ipython3 .

After it builds successfully you should see the image available on your workstation.

$ sudo docker images
REPOSITORY                    TAG                 IMAGE ID            CREATED             SIZE
local/ipython3                latest              c2cdc435736b        50 seconds ago      115MB

Running your container.

There is quite a few command line options you can use when starting a container locally with the docker command. The ones I personally use most often are –rm, -v, -i, and -t

  • –rm - This will remove the changes done to your local image while the container was running.
  • -v will expose a local file-system in the container
  • -i interactive.
  • -t tty.
  • -p expose port on docker host. -p 80:80 would expose tcp 80 on the docker host to the container on the same port. -p 80:80/udp would expose udp. You can expose multiple ports in the same command.
  • -d daemon mode, no examples of this in this article but worth knowing about.
$ sudo docker run --rm -i -t -v $HOME/scripts:/scripts local/ipython
Python 3.6.1 (default, May  2 2017, 15:16:41)
Type 'copyright', 'credits' or 'license' for more information
IPython 6.1.0 -- An enhanced Interactive Python. Type '?' for help.

In [1]:

And my exposed filesystem on the host is available

In [1]: !ls /scripts/
mypythonscript.py

Make an alias:

alias ipython='sudo docker run --rm -i -t -v $HOME/scripts:/scripts local/ipython'

Ansible is another good example:

FROM alpine:latest

RUN apk update \
    && apk add alpine-sdk bash gcc git libffi-dev musl-dev perl python3 python3-dev sshpass openssh libressl-dev \
    && pip3 install --upgrade pip \
    && pip3 install ansible

Build the image.

With this setup one can choose to run either ansible or ansible-playbook with an alias

alias ansible-playbook='sudo docker run --rm -i -t -v $HOME/projects/myansibleproject:/etc/ansible/ -v /home/$USER/.ssh:/root/.ssh local/ansible ansible-playbook'

alias ansible='sudo docker run --rm -i -t -v $HOME/projects/myansibleproject:/etc/ansible/ -v /home/$USER/.ssh:/root/.ssh local/ansible ansible'

I am exposing the local filesystem where my ansible repo is located and my ssh key.

$ ansible-playbook --version
[sudo] password for $USER:
ansible-playbook 2.4.1.0
  config file = /etc/ansible/ansible.cfg
  configured module search path = ['/root/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/lib/python3.6/site-packages/ansible
  executable location = /usr/bin/ansible-playbook
  python version = 3.6.1 (default, Oct  2 2017, 20:46:59) [GCC 6.3.0]
$ ansible --version
ansible 2.4.1.0
  config file = /etc/ansible/ansible.cfg
  configured module search path = ['/root/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/lib/python3.6/site-packages/ansible
  executable location = /usr/bin/ansible
  python version = 3.6.1 (default, Oct  2 2017, 20:46:59) [GCC 6.3.0]

In this case I’m building latest but you can edit the docker file to run exactly. what. you. want. And its easily reproduced EXACTLY as you want anywhere docker is running. 3 versions of ansible is no problem. Each run is off a clean image. The container starts, runs the command and exits.

If you put all your dockerfiles in your own private repo on github its simple to get your tools back if your machines dies, or you need them in 2 places, share with with your buddies. Nifty