Docker From the Ground Up: Working With Containers, Part 2

This is part two of a two-part series about working with Docker containers. In part one, we focused on the many ways and options to run an image and how the host can interact with a Docker container.

Docker From the Ground Up: Working With Containers, Part 2

In this part, we’ll cover listing, starting, stopping and restarting containers as well as executing commands on running containers. In particular, you’ll learn the difference between running and stopped (exited) containers, and how to control precisely the information and display when you list your containers by filtering and formatting.

Then, you’ll get hands-on experience stopping, starting, restarting and attaching to your containers. Finally, you’ll run one-off commands as well as gain interactive shell access to a running container.

Before we start, make sure that Docker is installed properly in your environment. Depending on how it installed and your user, you may need to run it as sudo. I’ll skip the sudo.

Listing Containers

When working with containers, you often want to list, view and filter your containers. The docker ps command is the key, and it has several interesting options.

Running Containers

The most basic command is plain docker ps with no arguments, which shows all the currently running containers.

$ docker ps
CONTAINER ID        IMAGE               COMMAND                  
CREATED             STATUS              PORTS                           
NAMES
2f542e1cb88b        nginx               "nginx -g 'daemon ..."   
12 hours ago        Up 12 hours         443/tcp, 0.0.0.0:9000->80/tcp   
nginx

You get a lot of information on each container, including the container id, the image, the command, when it was created, its current status, its ports, and its names. It’s a little difficult to parse due to the wrapping. We’ll see later how to filter and format the output. Note that the command is truncated (as well as the container id). To show the full command, add --no-trunc:

$ docker ps --no-trunc

IMAGE   COMMAND
nginx   "nginx -g 'daemon off;'"

Now, the full command is visible: nginx -g 'daemon off;'

All Containers

As you recall, Docker keeps stopped containers around (unless you ran them with --rm). Adding -a shows all containers:

$ docker ps -a
CONTAINER ID        IMAGE               STATUS      NAMES
cc797c61dc21        busybox             Exited      busybox
67f3cb5a9647        busybox             Exited      ecstatic_jones
898fb562e535        hello-world         Exited      hopeful_spence
6dd210fda2d8        hello-world         Created     infallible_curie
2f542e1cb88b        nginx               Up 12 hours nginx

Formatting

The output of docker ps can be too verbose and often shows a lot of fields that are not interesting. You can use Go-template formatting to display just the fields you’re interested in. Here is showing just the name and the command:

$ docker ps --no-trunc --format '{{.Names}}t{{.Command}}'
nginx   "nginx -g 'daemon off;'"

That works, but to present it with the field names, add “table” to the beginning of the format string:

$ docker ps -a --no-trunc --format 'table {{.Names}}t{{.Command}}'
NAMES               COMMAND
busybox             "cat /data/1.txt"
ecstatic_jones      "cat /data/1.txt"
hopeful_spence      "/hello"
infallible_curie    "ls -la"
nginx               "nginx -g 'daemon off;'"

The format name for the container id (not selected here) is {{.ID}} (all caps).

Filtering

The docker ps command supports many filters. They are pretty straightforward to use. The syntax is -f "<filter>=<value>". Supported filters are id, label, name, exited, status, ancestor, before, since, isolation, network, and health.

Here is filtering by container name and showing only the busybox container:

$ docker ps -a -f "name=busybox" 
               --format 'table {{.ID}}t{{.Status}}t{{.Names}}'
CONTAINER ID        STATUS                      NAMES
cc797c61dc21        Exited (0) 11 minutes ago   busybox

The -q Flag

If all you want is the container id, use the -q flag (quiet flag). It’s simpler than --format 'table {{.ID}}'. This is often needed when you want to perform operations on multiple containers (you’ll see an example later).

$ docker ps -aq
cc797c61dc21
67f3cb5a9647
898fb562e535
6dd210fda2d8
2f542e1cb88b

Stopping, Starting, and Restarting Containers

You can stop running containers and start a stopped container. There are several differences between starting a stopped container and running a new instance of the same image:

  • You use the same environment variables, volumes, ports and other arguments of the original run command.
  • You don’t have to create yet another container.
  • If the stopped instance modified its file system, the started container will use the same.

Let’s stop the nginx container and then start it. When you refer to a container, you can use its name or an unambiguous prefix of its id. I usually name my long-running containers so I have a meaningful handle and don’t have to deal with Docker’s auto-generated names or containers’ id prefixes.

$ docker stop nginx
nginx

$ docker ps -a -f "name=nginx" --format 'table {{.Names}}t{{.Status}}'
NAMES               STATUS
nginx               Exited (0) 2 minutes ago

OK. Nginx is stopped (status is “Exited”). Let’s start it:

$ docker start nginx
nginx

$ docker ps -a -f "name=nginx" --format 'table {{.Names}}t{{.Status}}'
NAMES               STATUS
nginx               Up 33 seconds

Restarting a running container is another option, which is equivalent to docker stop followed by docker start.

$ docker restart nginx

nginx
$ docker ps -a -f "name=nginx" --format 'table {{.Names}}t{{.Status}}'
NAMES               STATUS
nginx               Up 2 seconds

Attaching to a Running Container

When you start a stopped container, or if you ran your container in detached mode (-d command-line argument), you can’t see the output. But you can attach to it.

$ docker attach nginx
172.17.0.1 - - [19/Mar/2017:08:40:03 +0000] "HEAD / HTTP/1.1" 200 0 "-"
"HTTPie/0.8.0" "-"

Removing Containers

You can remove stopped containers with the command:  docker rm <container id or name>

$ docker rm ecstatic_jones
ecstatic_jones

If you want to remove a running container, you can either stop it first or use the -f (force) command-line argument:

$ docker rm -nginx
Error response from daemon: You cannot remove a running container
3dbffa955f906e427298fbeb3eadfd229d64365dd880c9771a31b0aedb879d6d. 
Stop the container before attempting removal or use -f

$ docker rm -f -nginx
nginx

If you want to remove all containers, here is a nice snippet:

docker rm -f $(docker ps -aq)

If you want to remove just the stopped container, remove the -f (force) flag.

Executing a Command Inside a Running Container

Docker runs a single process inside a container, but you can execute additional commands against a running container. It is very similar to providing a custom command to the docker run command, except that in this case it is running side by side with the run command.

Simple Commands

Running a simple command is done via docker exec. You provide a running container id or name and the command you wish to execute. Let’s check out the nginx.conf file inside the nginx container and see how many worker processes are configured.

$ docker exec nginx cat /etc/nginx/nginx.conf | grep worker_processes
worker_processes  1;

Interactive Shell

One of the best troubleshooting techniques with Docker containers is to connect to an interactive shell and just explore the internal file system. In order to attach stdin and have a tty, you need to provide the -i -t command-line arguments (can be grouped as -it) and then the name of a shell executable (usually bash).

You end up with shell access to your container. Here is an example of checking the worker processes interactively from “inside” the container.

$ docker exec -it nginx bash
[email protected]:/# cat /etc/nginx/nginx.conf | grep worker_processes
worker_processes  1;
[email protected]:/#

Conclusion

Docker is a powerful platform, and since the container is its unit of work, it provides a lot of tools to manage and work with containers. I described most of the important aspects of working with containers, but there are many more advanced features, options and nuances to the commands I covered, as well some additional commands.

If you work closely with Docker containers, take the time to dive in and learn all about them. It will pay off handsomely.