First time with Docker

Posted by Nicolas B. on October 12, 2015

Maybe you already hear about Docker, this open source application to manage containers. But it’s not very easy to start working with it.
There is only few weeks that I start to understand how it works. So I decided to write an article to list some basics.

Prerequisites

There are multiple ways to install Docker listed in the documentation.

I am working on OSX, so I will be focus on the OSX environment. If you are on Linux just follow the Docker documentation.

You can use Docker Toolbox to install Docker via an installer. But I prefer to do the installation by using command lines as follows.

First we need VirtualBox installed.
We could install it from their website or with Homebrew Cask like this:

$ brew cask install virtualbox

Then install Docker.

$ brew install docker

If you are using MacPorts there are the same packets.
sudo port install docker do the same.

Docker Machine

On Linux we can use Docker directly after its installation. But on OSX we need to install boot2docker to be able to use Docker. It creates a very small Linux VM.

There is two ways to install it. You can follow installation instructions on boot2docker.io or install it via docker-machine.

I prefer to use docker-machine because it allows to install and manage multiple machines (locales and remotes).

So let’s install it.

$ brew install docker-machine

Then we need to create the Docker machine named dev (Docker Machine get started).

$ docker-machine create --driver virtualbox dev

If we list our machines we have the dev docker machine.

$ docker-machine ls
NAME   ACTIVE   DRIVER       STATE     URL                         SWARM
dev             virtualbox   Running   tcp://192.168.99.100:2376

But if we try listing the processes we have an error.

$ docker ps # list the processes
Get http:///var/run/docker.sock/v1.20/containers/json: dial unix /var/run/docker.sock: no such file or directory.
* Are you trying to connect to a TLS-enabled daemon without TLS?
* Is your docker daemon up and running?

docker command needs some informations about the host machine to communicate with it and do the jobs we need. We have to set the env variables with this command.

$ eval "$(docker-machine env dev)"
$ docker ps
CONTAINER ID        IMAGE                        COMMAND                CREATED              STATUS              PORTS               NAMES

We are now ready to create our first Docker container.

Docker with existing images

As first example we could use a simple and light image named busybox.

Busybox

Busybox is one of the smallest Docker images (less than 5MB). This image contains “common UNIX utilities into a single small executable”.

$ docker run -it busybox

By doing this command we will create a new container from the busybox image. If this is the first time we execute it, it will pull the image first.
And for this image it will open a shell inside. This come from its definition.

When we are into the container we could do what we want. It’s really close to a VM for this part.
But each time we use docker run command, it will create a new container and loose what we did. If we want to use the same container we have to name it with --name option and --detatch the container.

For example:

$ docker run -itd --name=my-busybox busybox
3c4eb1117ece13b72647459960f4438f9da1b9445afe56188b19d1492b8c1c61

# And play with 'my-busybox' container
$ docker exec -it my-busybox ls -la
$ docker exec -it my-busybox touch index.html
$ docker exec -it my-busybox ls -la
$ docker exec -it my-busybox echo hello world
$ docker exec -it my-busybox sh

About the docker run options:
-d, --detach=false: Run container in background and print container ID
--name=: Assign a name to the container
-i, --interactive=false: Keep STDIN open even if not attached.
-t, --tty=false: Allocate a pseudo-TTY.

Debian

To test something most common. We could do the same with the debian image.

$ docker run -it debian

For debian image it’s similar than the busybox one. But it will open a instance with bash and not sh (debian image definition).

Nginx

Now let’s use nginx image. This works a bit different.

$ docker run -p 8000:80 nginx

With this command we expose the port 80 of the container into the port 8000 of docker host.
Just execute one of this two lines in a new terminal to check it.

$ curl $(docker-machine ip dev):8000

# To open in browser (OSX)
$ open http://$(docker-machine ip dev):8000

Nice but could be better by including content!

$ docker run -p 8000:80 \
  -v /path/to/content:/usr/share/nginx/html:ro \
  nginx

If we refresh our brother we now have our folder accessible :)

About the options:
-p, --publish=[]: Publish a container’s port(s) to the host.
-v, --volume=[]: Bind mount a volume.

Explanation of /path/to/content:/usr/share/nginx/html:ro:
/path/to/content: is the local folder to share.
/usr/share/nginx/html: the remote folder.
ro: read-only mode (optional).

Remove old containers

Some commands to help us.

$ docker ps
CONTAINER ID        IMAGE                        COMMAND                CREATED              STATUS              PORTS               NAMES

We normally have nothing running. But it does not mean that there is 0 containers.

$ docker ps -a
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS                      PORTS               NAMES
60477ca46da0        debian              "/bin/bash"              4 minutes ago       Exited (0) 4 seconds ago                        boring_morse
4e584955af81        nginx               "nginx -g 'daemon off"   5 minutes ago       Exited (0) 35 seconds ago                       agitated_mahavira

There is container exited. The following command will remove containers that not running.

$ docker rm $(docker ps -a -q)

Dockerfile, Docker-composer

I will talk about Dockerfile file and docker-compose command in a next article.

Conclusion

Really interesting tool but it need a new an approach.
For a web application we don’t really have to use and configure a http server. It’s not the job of the application container. But we may have to use a proxy that could be instantiate into a container. And its the proxy server that will redirect the call into the good docker container port.