1. Code
  2. Cloud & Hosting
  3. Hosting

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

Scroll to top
This post is part of a series called Docker from the Ground Up: Working with Containers.
Docker From the Ground Up: Working With Containers, Part 1

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. 

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.

1
$ docker ps
2
CONTAINER ID        IMAGE               COMMAND                  
3
CREATED             STATUS              PORTS                           
4
NAMES
5
2f542e1cb88b        nginx               "nginx -g 'daemon ..."   
6
12 hours ago        Up 12 hours         443/tcp, 0.0.0.0:9000->80/tcp   
7
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:

1
$ docker ps --no-trunc
2
3
IMAGE   COMMAND
4
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:

1
$ docker ps -a
2
CONTAINER ID        IMAGE               STATUS      NAMES
3
cc797c61dc21        busybox             Exited      busybox
4
67f3cb5a9647        busybox             Exited      ecstatic_jones
5
898fb562e535        hello-world         Exited      hopeful_spence
6
6dd210fda2d8        hello-world         Created     infallible_curie
7
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:

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

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

1
$ docker ps -a --no-trunc --format 'table {{.Names}}\t{{.Command}}'
2
NAMES               COMMAND
3
busybox             "cat /data/1.txt"
4
ecstatic_jones      "cat /data/1.txt"
5
hopeful_spence      "/hello"
6
infallible_curie    "ls -la"
7
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:

1
$ docker ps -a -f "name=busybox" \
2
               --format 'table {{.ID}}\t{{.Status}}\t{{.Names}}'
3
CONTAINER ID        STATUS                      NAMES
4
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).

1
$ docker ps -aq
2
cc797c61dc21
3
67f3cb5a9647
4
898fb562e535
5
6dd210fda2d8
6
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.

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

OK. Nginx is stopped (status is "Exited"). Let's start it:

1
$ docker start nginx
2
nginx
3
4
$ docker ps -a -f "name=nginx" --format 'table {{.Names}}\t{{.Status}}'
5
NAMES               STATUS
6
nginx               Up 33 seconds

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

$ docker restart nginx

1
nginx
2
$ docker ps -a -f "name=nginx" --format 'table {{.Names}}\t{{.Status}}'
3
NAMES               STATUS
4
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.

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

Removing Containers

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

1
$ docker rm ecstatic_jones
2
ecstatic_jones

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

1
$ docker rm -nginx
2
Error response from daemon: You cannot remove a running container
3
3dbffa955f906e427298fbeb3eadfd229d64365dd880c9771a31b0aedb879d6d. 
4
Stop the container before attempting removal or use -f
5
6
$ docker rm -f -nginx
7
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.

1
$ docker exec nginx cat /etc/nginx/nginx.conf | grep worker_processes
2
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.

1
$ docker exec -it nginx bash
2
root@b010e854bb98:/# cat /etc/nginx/nginx.conf | grep worker_processes
3
worker_processes  1;
4
root@b010e854bb98:/#

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.

Did you find this post useful?
Want a weekly email summary?
Subscribe below and we’ll send you a weekly email summary of all new Code tutorials. Never miss out on learning about the next big thing.
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.