Docker isn't the only container technology out there, but it is certainly the
most popular. And while we often think of containers as "mini-VMs," they
aren't. They run as programs on the host without the walls and separation that
VMs give us. If a program is running as root
on a Docker container, it is
running as root
on the host. They share the OS with the host which makes them
smaller and faster to start up than their larger VM cousins.
An image is a software bundle that will run on a Docker host. A container is an instance of that image, running or stopped. Images are the cookie cutters; containers are the cookies.
An image is made up of multiple layers of software (each an image itself) along with the metadata about how it should be assembled. Containers are read-only copies of those images with a thin read-write layer on top for the ephemeral instance data. We'll see more about this later.
Because of this, containers can be used as immutable infrastructure. The images can be cloned and spun up and restarted and destroyed as needed, knowing that a new copy can be instantiated as needed. Don't get too attached to any particular instance. They are cattle, not pets.
Instantiate your first Docker container with the docker run command.
$ docker run hello-world
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
0e03bdcc26d7: Pull complete
Digest: sha256:e7c70bb24b462baa86c102610182e3efcb12a04854e8c582838d92970a09f323
Status: Downloaded newer image for hello-world:latest
Hello from Docker!
This message shows that your installation appears to be working correctly.
To generate this message, Docker took the following steps:
1. The Docker client contacted the Docker daemon.
2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
(amd64)
3. The Docker daemon created a new container from that image which runs the
executable that produces the output you are currently reading.
4. The Docker daemon streamed that output to the Docker client, which sent it
to your terminal.
To try something more ambitious, you can run an Ubuntu container with:
$ docker run -it ubuntu bash
Share images, automate workflows, and more with a free Docker ID:
https://hub.docker.com/
For more examples and ideas, visit:
https://docs.docker.com/get-started/
docker run
does a lot behind the scenes:
- looks in the image cache for the image
- downloads the image from Docker Hub (if needed)
- starts a container with the image
- allocates a filesystem
- adds the read-write layer
- sets up the network interface
- gets an IP address
- executes the process
- captures the output
- exits the container
Run another container interactively.
$ docker run -it ubuntu /bin/bash
Unable to find image 'ubuntu:latest' locally
latest: Pulling from library/ubuntu
6a5697faee43: Pull complete
ba13d3bc422b: Pull complete
a254829d9e55: Pull complete
Digest: sha256:fff16eea1a8ae92867721d90c59a75652ea66d29c05294e6e2f898704bdb8cf1
Status: Downloaded newer image for ubuntu:latest
root@b000cd0e03d5:/#
You are left in a shell (/bin/bash
) as root
on the container, and the
container is still running.
-i
keeps STDIN open (short for--interactive
)-t
allocates a terminal (short for--tty
)ubuntu
is the image to use/bin/bash
specifies the command to run, rather than the default
At the root prompt, exit and then start another container with the same command. Then update Ubuntu's software index and install some packages.
root@b000cd0e03d5:/# exit
exit
$ docker run -it ubuntu /bin/bash
root@0e41b62958cc:/# apt-get update
...
Reading package lists... Done
root@0e41b62958cc:/# apt-get install -y wget cowsay recode jshon
...
done.
root@0e41b62958cc:/#
Leave this container running at the root prompt.
This time, Docker didn't have to download the ubuntu
image again since it
already had it cached.
In a second window (leaving the container running in the other), list the running containers with the docker ps command.
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
0e41b62958cc ubuntu "/bin/bash" 3 minutes ago Up 3 minutes clever_wright
docker ps
shows our running container. You could also run with -a
(short for
--all
) to show all containers, running and stopped.
$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
0e41b62958cc ubuntu "/bin/bash" 3 minutes ago Up 3 minutes clever_wright
b000cd0e03d5 ubuntu "/bin/bash" 5 minutes ago Exited (0) 3 minutes ago gracious_curie
f0dbe294ef5a hello-world "/hello" 5 minutes ago Exited (0) 5 minutes ago musing_chaum
You can see our current container (0e41b62958cc
), the first Ubuntu container we
exited (b000cd0e03d5
), and Hello World (f0dbe294ef5a
), although your IDs
will be different.
Each container has a Container ID
and a Name
. If you don't assign a name
(we didn't) Docker assigns a random name. You can refer to a container by the at
least the first 5 digits of the Container ID
or by the Name
.
Let's make an image of the read-write layer on the running image (the one with the software installed) by using the docker commit command. Then stop the first container (from the same, second window) using the docker stop command.
$ docker commit 0e41b62958cc ggotimer/chuck-norris-1
sha256:1821b7de33f04fb70bc6fc60ce69921f31542ac538b5b1333f9c3c511081ecc5
$ docker stop clever_wright
clever_wright
You could have used the Container ID
(0e41b62958cc
) or the Name
(clever_wright
) in either command. I just showed an example of using each.
Images are named with a single word (e.g., hello-world
, ubuntu
) if they are
official Docker images. Otherwise they are named with your Docker Hub username
(if you have one, mine is ggotimer
), slash, an identifier (chuck-norris-1
in
this case), colon, and then a tag (latest
if you don't specify). Unless you
plan to push to Docker Hub it doesn't matter, but get in the habit of naming
them with the correct convention.
Notice that the container in the first window has stopped
(we didn't type exit
ourselves).
root@0e41b62958cc:/# exit
Check out the logs for the first container with the docker log command. You'll see a replay of all the input and output from that container, even after the container is stopped.
$ docker logs clever_wright
root@0e41b62958cc:/# apt-get update
...
Reading package lists... Done
root@0e41b62958cc:/# apt-get install -y wget cowsay recode jshon
...
done.
root@0e41b62958cc:/# exit
Let's look at the results of your interactive labor by starting your new image.
$ docker run ggotimer/chuck-norris-1 wget 'http://api.icndb.com/jokes/random?exclude=[explicit]' -qO-
{ "type": "success", "value": { "id": 549, "joke": "Chuck Norris killed two stones with one bird.", "categories": [] } }
Or you can try an even more unwieldy command.
$ docker run ggotimer/chuck-norris-1 /bin/bash -c "wget 'http://api.icndb.com/jokes/random?exclude=[explicit]' -qO- | jshon -e value -e joke -u | recode html | /usr/games/cowsay"
_____________________________________
/ Chuck Norris always knows the EXACT \
\ location of Carmen SanDiego. /
-------------------------------------
\ ^__^
\ (oo)\_______
(__)\ )\/\
||----w |
|| ||
We will make it easier to run, and to create, in Lesson 2- Build an Image with Code.