Working With Containers
This lesson covers running Docker containers and working with different Docker images. Prior to starting, be sure you are familiar with Docker containers and have Docker installed.
You will run through a Docker hello-world demo using terminal. You will unpack the Docker command, and use the run command to start building Docker images.
We will discuss the Docker daemon, and how it uses the files and instructions in the image to start the hello-world container. You will learn how to list local images with Docker images, which is key for listing and debugging Docker state.
You will review the columns of the repository:
- Repository—lists where the image came from
- TAG—displays the image tag
- Image ID—every image has a unique ID that is calculated from its contents
- Created—displays how long ago the repository was created
- Size—displays the overall size of the repository
Then we will try some interactive practice using Docker run and several terminal options to demonstrate the predefined behavior of images.
And finally, we will use all that has been learned so far to check the weather using the curl tool plaintext weather service.
Hello and welcome back to the Introduction to Docker course from CloudAcademy. I'm Adam Hawkins and I'll be your instructor for this lesson.
This lesson is the first in a two part series on container fundamentals. This lesson is a short one and the next one is much longer. This lesson covers the basics before diving deeper in part two.
Here's our topics. We're covering running Docker containers and working with different Docker images. You should be able to run and interact with Docker containers by the end of this lesson. Here's a heads-up in case you missed it. I'm skipping the various installation tutorials because I know that you can handle that. Please install Docker ahead of time if you'd like to follow along. Also, I'm running examples in an Ubuntu Linux VM. It shouldn't make much of a difference, I'm just letting you know.
So, all set, let's head over to the terminal for the classic hello-world demo. Every technology has a hello-world demo. Docker is no different. Let's fire that up and see what happens. Let's unpack this command. The Docker command is everything related to building Docker images and running Docker containers. There are many subcommands, some of which we'll cover throughout the course. The run command takes a Docker image and starts it as a Docker container. More on that later. Hit enter and watch what happens.
First the Docker daemon checks if it has the hello-world image locally. If not then it's pulled from the Docker registry. The image is pulled because we've never used it before. Then the Docker daemon uses all the files and instructions in the image to start the hello-world container. The hello-world image is quite a handy teacher, also. You can catch an alternate explanation of this process from the container itself.
Now repeat the command. Notice how it did not pull the image this time? This is because it's already been stored locally. You can list local images with Docker images. This command is key for listing and debugging Docker state. You'll see right off the bat there are five columns. The repository column lists where the image came from. This may be the official registry or your own. repository also refers to the image name. See how it matches what we passed to Docker run? The TAG column displays the image tag. Tags usually indicate versions, say Ruby 2.1 or Ruby 2.2. Notice how Docker shows the 'latest' tag? Docker run uses this when no tag is specified. The third column is the image ID. Every image has a unique ID. The ID is sort of like a GCMD, in that it's calculated from its contents.
The size column is interesting. You can see the hello-world image is super tiny. You'll find that images may become very large, sometimes almost one gigabyte. The hello-world image is quite basic. It simply printed output and exited. That was enough for hello-world but not enough to grasp what's actually happening. The hello-world image prompted us to be a bit more ambitious.
Let's try something interactive. Here we're using Docker run with two new options and a second argument. The -i and -t options are mainly for interactive processes. -i keeps standard input attached to the container so we can type and send signals. The -t option allocates a teletype terminal. This is for escape sequences for things like colors. We also tell Docker to use a specific command for this container. This demonstrates images have a predefined behavior when no command is specified. Hit enter and you'll be attached to a fully isolated Docker container once the image pulls. You can see we're sitting in a terminal. It feels familiar. You can see we're root at this particular host. The hostname is a Docker container ID.
Let's play around by checking the weather. We can do this with a curl tool plaintext weather service. Hm, command not found. No problem. We're using Ubuntu so we can just install the app package. Right, but what about the permissions? Notice who the current user is. We're root, how did that happen? The Docker daemon runs as root so all containers are run as root by default. We have everything we need so now we can install curl. I'll type in the commands now an then fast forward through the installation process.
There's nothing out of the ordinary here. I used the standard app commands. First is app-get update. This is required because all the package references are baked into the image. Second, install the package with app-get install. The -y flag is short for yes, so skip asking for confirmation. Time to try again. Shout out here to one of my favorite cities in the whole wide world, Helsinki. Let me zoom out a bit so this fits better on the screen. Great, now we have the weather in Helsinki. This is enough for this container.
Let's run through the example again in a new container. Rerun the command to start the bash container. Next try the same curl as last time. Strange, the command fails. But we just installed curl, so what gives? Well, we're using the same image as last time, but not the same container. This illustrates a key concept. Containers are ephemeral. Making changes to one container does not affect the other containers. This is how isolation works. Let's clarify this by inspecting all of the Docker containers.
The docker ps command prints information on Docker containers. Running it now produces no output. This may seem strange, but it is correct. There are no containers actually running. They have either all stopped or we have exited them. Run docker ps -a to bring up information about all containers. Now we see all our handiwork. There is a container ID column. The Docker daemon gives each container a unique ID. This was the hostname in our shell prompt, if you remember. You can also see the image, command and status. Note that these containers are still around. Docker can stop, start and restart containers until they've been removed.
We'll cover this more in the next lesson. I promised you this would be a quick lesson. The next lesson goes much deeper. We'll cover running containers in the background and many more things you can do with Docker containers.
Adam is backend/service engineer turned deployment and infrastructure engineer. His passion is building rock solid services and equally powerful deployment pipelines. He has been working with Docker for years and leads the SRE team at Saltside. Outside of work he's a traveller, beach bum, and trance addict.