Docker Basics

Introduction

Docker has loads of commands, im not aiming to cover all of them instead to provide a narrative that makes it easier to get up to speed with docker.

  • There are images and containers.
  • Images are pretty much like a virtual computer image.
  • Containers are running images.

Images

You can download prebuilt images from Docker Hub that contains some OS and some programs installed onto it.

First you have to download an image.
You can do this with the pull command.

1
2
3
docker pull <dockerhub user>/<image>
# Example
docker pull crossbario/crossbar

This downloads the crossbar latest image onto your computer.
The location of the images is in /var/lib/docker but there is some magic involved.

The images are stored in /var/lib/docker/graph//layer.

Note that images are just diffs from the parent image. The parent ID is stored with the image’s metadata /var/lib/docker/graph//json.When you docker run an image. AUFS will ‘merge’ all layers into one usable file system.

You can check all your downloaded images:

1
docker images

You can remove an image:

1
docker rmi <id>

If you delete it gets deleted from your computer.
You cant delete an image if you have a running container that uses it.

Dockerfiles

A dockerfile is a file that describes an Image.
A docker file can be built on top of an existing image.
In this way you can tweak and add additional functionality to an existing Image.

You can create an image from a Dockerfile with the build command:

1
docker build -t <image-name> <path-to-dockerfile>

If you specify a name its easier to reference during the container creation.
If you dont set a name you can reference an image by id or the auto generated name.

Dockerfiles has their own syntax but its mostly bash commands with some directive commands.The most important command is the ENTRYPOINT which gets run each time when the container starts.

Containers

Containers are instantiated images.

Containers are either running or stopped.

You can list you running containers:

1
docker ps

You can list all your containers, this shows stopped containers too:

1
docker ps –a

You can stop a container:

1
docker stop <name>

You can start or restart a container:

1
2
docker start <name> 
docker restart <name>

You can check the output of the docker container:

1
2
3
4
# snapshot
docker logs <name>
# follow or -f
docker logs <name> --follow

Containers from Images - docker run

Docker run is basically a combination of two commands.
Docker create and docker start.

So if you call run on an image it first creates a container from that image then starts that container.

You can run a container from an image:

1
docker run <dockerhub username>/<image>

This downloads the image if its not present on the computer then start up a virtual machine based on the image.

If you already have the image stored on your computer you can reference it by its name or id:

1
docker run <image>

To see the output of the running container you have to specify the -i -t flags:

1
docker run -it <image>

To detach from a running container use the -d flag.

1
docker run -d <image>

To see the output of an already stopped or crashed container:

1
docker logs <container name>

To delete the container after we stop it (Useful when creating and debugging images) use the –rm flag:

1
2
3
4
5
6
7
8
docker run -it --rm <image> 
```

You can set a restart policy for the container with --restart:

```sh
# Dont let the container to stop
docker run --restart=always <image>

Settings with docker run

These can be set either from the Dockerfile or from directly the docker run command.

To open a port on container use the –expose or -e flag:

1
2
# Expose the port 1337 on the container
docker run -it -e 1337 <image>

If a port is exposed it does not mean its mapped to the host.

You can map an exposed port on the container to a host port with the -p flag.

1
2
3
docker run -e <container port> -p <host port>:<container port> <image>
# The host 4444 port is mapped to the containers 1337 port.
docker run -it -e 1337 -p 4444:1337 <image>

You can map folders on the host into the container with –volume or -v:

1
docker run --volume <path to host folder>:<path to container folder> <image>

Processes with docker run

Most of the images define some sort of main process as the default command.

By default a container is stopped when the main process is finished.
The main process can be defined in the Dockerfile as an Entrypoint or CMD but you can overwrite it trough docker run.

1
docker run –it –rm ubuntu bash –c "sleep 5; echo all done"

Here the container waits 5 seconds then prints a message and exits.

We can extend the lifetime of the container if we detach it with the -d flag.
In this form the container will keep running in the background even after the main process is finished.

1
docker run –it –d ubuntu bash

To enter a container running in the background you can use the attach command.

1
docker attach <container name>

Stepping into a Container - docker exec

You can do multiple things with exec. You can run commands and create new processes from the host in the container. The coolest example of that is where you enter the containers shell.

You can “step into” the container shell by specifying the shell in the container.

Note that all containers should have sh but some of them has /bin/bash as well. This depends on the image you are using. What happens is you create a new process in the container and attach to it.

1
2
3
docker exec <container name> sh
# Or
docker exec <container name> /bin/bash

Images from containers - docker commit

Lets say we have a container that we stepped into with exec and did some changes.
In order to save those changes we can save the container to an image.
This can be alternative to creating a Dockerfile, you run your base image do some changes interactively then commit the container into an image.

1
2
3
docker commit <container name> -t <image name> 
# You can add a tag after you created the image with
docker tag <image name> <image id>

Multiple Containers - docker compose

If you have multiple images and containers you want to manage together you can use docker compose to do that.

In a docker-compose.yml file you specify the path to each containers Dockerfile and the settings you want to start with.

Then you start or stop all containers with a single command:

1
2
docker compose up
docker compose down

Remote hosts - docker machine

With docker machine you can mount a remote computer and manage the containers running remotely just like you would on your local computer. With the combination of docker compose and docker machine you can control microservices on a remote host like AWS from your local terminal.

Multiple Hosts - docker swarm

It turns a pool of Docker hosts into a single, virtual host using an API proxy system. It has load balancing capabilities as well.

Workflow - Using an existing image

  • Download the image
  • Run the image

Workflow - Dockerizing your app

  • First you create your app
  • Find a docker image that has what you need
  • Create a Dockerfile that builds on that image
  • Test your container (ideally with docker run –rm)
  • Create a Dockerfile for each of your services.
  • Create a docker compose file
  • Mount your remote machine with docker machine
  • Start / Stop your services with docker compose