Walkthrough - Docker
The following walkthrough is a good way to get a glimpse of what Docker can do. It is mostly inspired by Coffee with Mich - Docker commands.
Express
What is Docker?
Eliminates “works on my machine”
Docker provides containers (vs VM)
Images have a name and a tag, latest is a “magical” tag, the others should “never” be overwritten.
Cheat sheet
- Images commands
Show the list of local images:
docker images
Pull an image from a registry:
docker pull {image[:tag]}
Delete an image locally:
docker rmi {image[:tag]}
Tag an image:
docker tag {source_image[:tag]} {target_image[:tag]}
- Container commands
Show the list of running containers:
docker ps
Show the list of all containers:
docker ps -a
Launch a container, give it a name and autoclean it when it’s done running:
docker run --name {name} --rm {imagename}
Get a bash shell into a running container:
docker -ti exec {container id} bash
Launch a container, map a directory and a port:
docker run --rm -v $HOME:/host_home -p 0.0.0.0:8080:80 {imagename}
Remove a stopped container:
docker rm {container id}
Detailed
What is Docker?
Docker is a software technology providing containers, promoted by the company Docker, Inc. Docker provides an additional layer of abstraction and automation of operating-system-level virtualization on Windows and Linux. Docker uses the resource isolation features of the Linux kernel such as cgroups and kernel namespaces, and a union-capable file system such as OverlayFS and others to allow independent “containers” to run within a single Linux instance, avoiding the overhead of starting and maintaining virtual machines (VMs). [1]
By providing well-defined environments, Docker is good at eliminating the famous “but it works on my machine!” statement.
Key concepts
Containers
You can think of a Docker container as a physical shipping container. It’s a box where you store and run an application and all of its dependencies. Just as cranes, trucks, trains, and ships can easily work with shipping container, so can Docker run, copy, and distribute containers with ease. Docker completes the traditional container metaphor by including a way to package and distribute software. The component that fills the shipping container role is called an image. [DIA02]
Images
A Docker image is a bundled snapshot of all the files that should be available to a program running inside a container. You can create as many containers from an image as you want. But when you do, containers that were started from the same image don’t share changes to their file system. When you distribute software with Docker, you distribute these images, and the receiving computers create containers from them. Images are the shippable units in the Docker ecosystem. [DIA02]
A docker image is composed of layers of intermediate images.
Repository
A repository is a named bucket of images. The name is similar to a URL. [DIA03]
Image Commands
To list the available images on the current machine:
This command returns 5 columns. While tag
, image id
, created
and size
are self-explanatory, repository
represents the repository and name of the
image. As an example, an image with the value mongo
in the repository field
is a local image named mongo
. An image with the value
quay.io/datacratic/baseimage
is an image named baseimage
from the
repository quay.io/datacratic
.
The -a
flag, if used, will also display all intermediate images.
The easiest way to share built images is through registries. The official docker public registry contains a ton of images.
To download an image from a registry, use the docker pull
command. So, say
we want to download the nginx:1.13.6 image, we would run:
Hint
You don’t need to run docker pull prior to using an image because if you try to launch a container based on an image that you don’t have locally, docker will pull it automatically.
Here, we didn’t put anything in front of nginx. This is because when there is no repository name found before the image name, docker assumes it points to the official registry.
Container commands
To see all running containers
This command returns 7 columns.
container id
: A unique auto-generated id representing the container.image
: The image repository, name and tag used to launch the container.names
: The unique name representing the container.command
: The command that the container runs.created
: How long ago the container was created.status
: The container status and its associated duration.ports
: Containers can expose some of their ports. Whenever they do, they are listed here.
Launch the ubuntu
image with the following command.
Nothing seems to happen? This is normal. You just launched what is called an “operating system container”. That is a container that accomplishes nothing on its own.
Let’s relaunch it and “log” into it.
Notice that your prompt (likely) changed and that you are now root. You have successfully launched a container and logged into it. By default, you are always root in docker.
Container Lifecycles
Run
exit
to exit the container.Run
docker ps
. You shouldn’t see your container.Run
docker ps -a
. You should see your container this time, along with the one that seemed to do nothing a couple of steps ago. The thing is thatdocker ps
doesn’t show stopped containers. That’s why you see them with the-a
flag. To restart a stopped container, run
Since we’re still working with our “operating system” container, it still doesn’t seem to do a thing, but you get the idea.
Now let’s introduce the exec
command. First, relaunch a container and log
into it.
From a different shell window, run docker ps
to find out the container id
of the container you just launched, and then run
Et voilà. You have a bash shell into a running container. To demonstrate it, from one of
your terminal window run touch tralala
and from the other run ls
. You
should see the file named tralala
.
Let’s introduce the kill
command. To demonstrate it, exit docker from one
of your terminals from the container and run
Your other terminal should now have exited the container because you just killed it.
Let’s now demonstrate how we clean up stopped containers.
Hint
To have your container auto-cleaned when it is stopped, launch it with
the --rm
flag.
Mapping entities to containers
Volumes
To map a volume/directory to docker, use the -v
flag when you launch it.
To map multiple directories, you can have multiple -v
flags. To add a layer of
security, you can also map directories as read only. To do so, add :ro
at
the end of the directive. So to reuse the previous example, it would become
$HOME:/host_home:ro
. If you restart the container with that command and
try to run touch cant_touch_this
you will get an error.
Caution
With the default settings, docker runs as root so any file you create while inside a container will be owned by root.
The source path of the volume mapping must be an absolute path.
a/b/c
won’t work, but/home/alone/a/b/c
will.If the source volume does not exist, it will be created and owned by root. (This is especially nasty and a source of errors.)
You can use the
-v
flag to mount single files.
Ports
To map a port to a container, use the -p
flag. Let’s demonstrate it with
nginx.
This launches an nginx (v1.13.6) container and map host port 8080 to container port 80. Now, run from a host terminal
You should get html content returned by nginx and you should see a log line in the terminal that runs the container. You can now exit it.
Exposing a port this way only makes it available from the host. If you want to
expose it to the network, prefix it with 0.0.0.0:
. So the previous example
would become -p 0.0.0.0:8080:80
.