1.9. Debug Containers

This lab contains an overview of many commands we already used in previous chapters, we have a closer look at stopping, starting, naming and debugging containers.

Feel free to skip this lab if you are short on time.

Listing containers

To see all running containers:

docker ps

To see only the last container that was started:

docker ps -l

To see only the ID of containers:

docker ps -q

To see only the ID of the last started container:

docker ps -ql

To see the size of the containers:

docker ps -s

To see the general docker storage usage:

docker system df

This is helpful for scripting or doing a lot of experimentation where you start and delete a container quite a lot of times. As an example docker rm -f $(docker ps -ql), which will delete the last started container.

Naming a container

We already did name the frontend container, let us do it here again for the hello-world example:

docker run hello-world

The hello-world container seems to have exited straight away after displaying the information message, let us display the last container that was started:

docker ps -l

this shows something like this

CONTAINER ID   IMAGE         COMMAND    CREATED          STATUS                      PORTS     NAMES
5e301a6a9888   hello-world   "/hello"   11 seconds ago   Exited (0) 10 seconds ago             romantic_johnson

Now the made up name romantic_johnson is not very handy, if we want to refer to an instance, let us name it hello-world

docker run --name hello-world hello-world

now running

docker ps -l

Shows us, that our container has been given the name hello-world indeed.

Start an image with a custom command

Until now, we started the images as they were. But we also have the ability to run our own commands in the image, overwriting the default CMD from the Dockerfile.

Let us start an alpine image directly with the sleep infinity command:

docker run --name sleepy alpine sleep infinity

We have successfully started the container, but are stuck in the sleep process now! Let us find out how to detach from it.

Detaching from a container

  • The detach key sequence is CTRL-p CTRL-q for interactive sessions. Unfortunately this does not work in our web client, so use the next option:
  • Detach by killing the Docker client: close the current terminal and open a new one

Attaching to a container

You could re-attach to the the hello-world container again with this command (do it in a new shell which you can kill again after this):

docker attach sleepy
  • The container must be running.
  • There can be multiple clients attached to the same container.
  • Warning: if the container was started without -it (see next chapter):
    • You won’t be able to detach with CTRL-p CTRL-q.
    • If you hit CTRL-c, the signal will be proxied to the container.

You can always detach by killing the Docker client (e.g. close the bash window/terminal).

Background and foreground

From Docker’s point of view, all containers are the same. All containers run the same way, whether there is a client (your docker client) attached to them or not.

It is always possible to detach from a container, and to re-attach to a container.

This short overview explains how those things work together:

Docker attach

Interactive containers

If you want to be inside a container after starting it, you can start it with the -it option.

What does -it stand for?

  • -t means “terminal” as in “allocate a terminal.”
  • -i means “interactive” as in “connect stdin to the terminal.”

Try it out:

docker run -it alpine sh

You are now inside the container:

hostname

gives you the id of this container, now you can exit it by typing

exit

Which will stop sh and the container.

Stop and start running container

Now that we know about detaching and attaching let us get back to our sleepy container, which should still be running.

With docker ps we can check our sleepy container and our custom command:

CONTAINER ID   IMAGE     COMMAND            CREATED          STATUS          PORTS     NAMES
72d3f936d2f7   alpine    "sleep infinity"   10 seconds ago   Up 10 seconds             sleepy

How to stop it? Simple:

docker stop sleepy

That took longer than expected, docker stop gracefully stops a container by sending a SIGTERM signal followed by a SIGKILL signal after a grace period. You can also directly send the SIGKILL with the docker kill command.

Let us start the container again:

docker run --name sleepy -d alpine sleep infinity

You get an error….this is because there is still stopped container around with that name.

We can restart the sleep command in our stopped container though:

docker start sleepy

Which put our container back into running state! This means it started a new sleep process in the container environment. Now let us kill it straight away:

docker kill sleepy

And you see the went a lot faster than before.

If you want to get rid of the stopped container you can remove it:

docker rm sleepy

Listing images

This is straightforward:

docker image list

Viewing logs of containers

docker logs <container>

This will show the whole log of that container, sometimes it’s enough to display just a few lines:

docker logs --tail 3 <container>

With the -follow option you can tell the docker logs command to follow the log file in real time:

docker logs --tail 3 --follow <container>

(Advanced) Start a container with a custom command

Please start a container which outputs your own name to the console and then exits.

Then start another container where you can see your name in the logs and not in the output. This time no instructions are given. After your done remove both containers.

Housekeeping

There are various housekeeping commands.

Dev environment

Stop all running containers and then delete them:

docker stop $(docker ps -a -q)
docker rm $(docker ps -a -q)

Delete all images:

docker rmi $(docker images -q)

Pruning

Remove unused data:

docker system prune

Remove all stopped containers:

docker container prune

Remove unused images:

docker image prune

Docker info

To receive general info about your docker environment use

docker system info
Client: Docker Engine - Community
 Version:    27.5.0
 Context:    default
 Debug Mode: false
 Plugins:
  buildx: Docker Buildx (Docker Inc.)
    Version:  v0.19.3
    Path:     /usr/libexec/docker/cli-plugins/docker-buildx
  compose: Docker Compose (Docker Inc.)
    Version:  v2.32.3
    Path:     /usr/libexec/docker/cli-plugins/docker-compose

Server:
 Containers: 2
  Running: 0
  Paused: 0
  Stopped: 2
 Images: 127
 Server Version: 27.5.0
 Storage Driver: overlay2
  Backing Filesystem: extfs
  Supports d_type: true
  Using metacopy: false
  Native Overlay Diff: true
  userxattr: false
 Logging Driver: json-file
 Cgroup Driver: systemd
 Cgroup Version: 2
 Plugins:
  Volume: local
  Network: bridge host ipvlan macvlan null overlay
  Log: awslogs fluentd gcplogs gelf journald json-file local splunk syslog
 Swarm: inactive
 Runtimes: io.containerd.runc.v2 runc
 Default Runtime: runc
 Init Binary: docker-init
 containerd version: bcc810d6b9066471b0b6fa75f557a15a1cbf31bb
 runc version: v1.2.4-0-g6c52b3f
 init version: de40ad0
 Security Options:
  apparmor
  seccomp
   Profile: builtin
  cgroupns
 Kernel Version: 6.8.0-52-generic
 Operating System: Ubuntu 22.04.5 LTS
 OSType: linux
 Architecture: x86_64
 CPUs: 8
 Total Memory: 15.33GiB
 Name: g-ThinkPad-X1-Yoga-Gen-6
 ID: MMSJ:NDHM:MVNC:N7V6:K5PT:KJDT:EJ4L:QPGM:I42U:YL57:UGPL:NCKC
 Docker Root Dir: /var/lib/docker
 Debug Mode: false
 Username: songlaa
 Experimental: false
 Insecure Registries:
  127.0.0.0/8
 Live Restore Enabled: false