Explore Docker - 2. Managing Containers

Explore Docker - 2. Managing Containers

·

17 min read

In my previous blog, I gave a brief introduction to Docker. In this part, we will dig deep into Docker containers.

We know that a container is the runtime instance of an image. You can start multiple containers from a single image.

image.png Keeping aside the theory, let's play around with containers.

Understanding Docker containers commands

Let's try something exciting – download and run an NGINX container by running the following two commands:

$ docker image pull nginx # Pulling nginx image

$ docker container run -d --name nginx-test -p 8080:80 nginx # Running container

# Pulling Image
deep@Latitude-5590:~/explore-docker$ docker image pull nginx
Using default tag: latest
latest: Pulling from library/nginx
6ec7b7d162b2: Pull complete 
cb420a90068e: Pull complete 
2766c0bf2b07: Pull complete 
e05167b6a99d: Pull complete 
70ac9d795e79: Pull complete 
Digest: sha256:4cf620a5c81390ee209398ecc18e5fb9dd0f5155cd82adcbae532fec94006fb9
Status: Downloaded newer image for nginx:latest
docker.io/library/nginx:latest

# Running Container
deep@Latitude-5590:~/explore-docker$ docker container run -d --name nginx-test -p 8080:80 nginx
ace004cb4246b59eef353dab9ab53b3e2bb352e8eab88b98f8fdac2ba2b911ca
deep@Latitude-5590:~/explore-docker$ docker container ls
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                  NAMES
ace004cb4246        nginx               "/docker-entrypoint.…"   4 minutes ago       Up 4 minutes        0.0.0.0:8080->80/tcp   nginx-test

As you can see from our docker container run command we have three flags.

  • -d stands for --detach
  • --name flag assign's name to containers
  • -p flag maps port

If we hadn't added -d flag, then our container would have executed in the foreground, which means that our Terminal would have been frozen until we pressed Ctrl + C. To understand this, try running the above command without -d flag and see the output of running the container in the foreground.

Once you run the command, open a browser http://localhost:9090/ . As you load the page, you will notice that your page visit is printed to the screen. Hitting refresh in your browser will display more hits, until you press Ctrl + C back in the Terminal:

# without -d flag
deep@Latitude-5590:~/explore-docker$ docker container run --name nginx-foreground -p 9090:80 nginx
172.17.0.1 - - [02/Jan/2021:12:03:48 +0000] "GET / HTTP/1.1" 200 612 "-" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:84.0) Gecko/20100101 Firefox/84.0" "-"
2021/01/02 12:03:49 [error] 30#30: *1 open() "/usr/share/nginx/html/favicon.ico" failed (2: No such file or directory), client: 172.17.0.1, server: localhost, request: "GET /favicon.ico HTTP/1.1", host: "localhost:9090", referrer: "http://localhost:9090/"
172.17.0.1 - - [02/Jan/2021:12:03:49 +0000] "GET /favicon.ico HTTP/1.1" 404 153 "http://localhost:9090/" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:84.0) Gecko/20100101 Firefox/84.0" "-"

Running docker container ls -a or docker ps -a shows that you have two containers, one of which has exited:

deep@Latitude-5590:~/explore-docker$ docker container ls -a
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS                     PORTS                  NAMES
61c6de3ae9e0        nginx               "/docker-entrypoint.…"   10 minutes ago      Exited (0) 3 seconds ago                          nginx-foreground
ace004cb4246        nginx               "/docker-entrypoint.…"   38 minutes ago      Up 38 minutes              0.0.0.0:8080->80/tcp   nginx-test

So, what happened when we ran the command with and without -d flag? When we removed the detach flag, Docker connected us to the NGINX process directly within the container. When we used Ctrl + C, we sent an instruction to the NGINX process to terminate it.

The --name flag , We gave a name to container nginx-foreground using the --name flag, as we cannot have two containers with the same name. That's why the name generator functions assign a random name to containers you do not wish to name yourself.

The - p port flag, We asked Docker to map port 9090 to port 80 on the container. This was because we cannot assign more than one process to a port on a host machine, so if we attempted to launch our second container with the same port as the first, we would have received an error message as shown below.

deep@Latitude-5590:~/explore-docker$ docker container run --name nginx-foreground -p 8080:80 nginx
docker: Error response from daemon: Conflict. The container name "/nginx-foreground" is already in use by container "61c6de3ae9e025567554b4aeaa697790518f5f4b7ad392b77b2a50d3a654e741". You have to remove (or rename) that container to be able to reuse that name.
See 'docker run --help'.

Interacting with containers

  • EXEC

    The exec command initiates a second process within the container that you can interact with. For example, to see your system hosts, we can run the following command:

    deep@Latitude-5590:~/explore-docker$ docker container exec nginx-test cat /etc/hosts
    127.0.0.1    localhost
    ::1    localhost ip6-localhost ip6-loopback
    fe00::0    ip6-localnet
    ff00::0    ip6-mcastprefix
    ff02::1    ip6-allnodes
    ff02::2    ip6-allrouters
    

    The above command will initiate a second process, the cat command, in this case, prints the contents of /etc/hosts to stdout. The second process will then terminate, leaving the container as it is. Another practical example, which is used a lot by developers, is initiating a bash process.

    deep@Latitude-5590:~/explore-docker$ docker container exec -i -t nginx-test /bin/bash
    root@ace004cb4246:/# ls
    bin   dev           docker-entrypoint.sh  home  lib64  mnt  proc  run   srv  tmp  var
    boot  docker-entrypoint.d  etc             lib   media  opt  root  sbin  sys  usr
    

    The above command initiates a bash process, flag -i and -t flags to keep open console access to our container. The -i stands for --interactive, which instructs Docker to keep stdin open so that we can send commands to the process. The -t flag is short for --tty and allocates a pseudo-TTY to the session.

    NOTE

    • TTY is an acronym used to describe text-only consoles in modern computing.
    • stdin Standard input (stdin) is the handle that our process reads to get information from the end-user. Standard output (stdout) is where the process writes normal information
  • ATTACH

    Use docker attach to attach your terminal’s standard input, output, and error (or any combination of the three) to a running container using the container’s ID or name. We still have our nginx-test container running, so let's connect to that by running this command:

    $ docker container attach nginx-test

    # Attach
    deep@Latitude-5590:~/explore-docker$ docker container attach nginx-test
    172.17.0.1 - - [02/Jan/2021:16:39:25 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:84.0) Gecko/20100101 Firefox/84.0" "-"
    172.17.0.1 - - [02/Jan/2021:16:39:25 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:84.0) Gecko/20100101 Firefox/84.0" "-"
    # After Ctrl + C
    deep@Latitude-5590:~/explore-docker$ docker container ls
    CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
    

    Opening your browser and going to localhost:8080 will print the NGINX access logs to the screen. Pressing Ctrl + C will terminate the process and return your Terminal to normal and you will see there are no running containers.

    Start the container again using command $ docker container start nginx-test. This will start the container back up in the initial launched state. Let's reattach to our process, but this time with an additional option - $ docker container attach --sig-proxy=false nginx-test

    # Restarting Container
    deep@Latitude-5590:~/explore-docker$ docker container start nginx-test
    nginx-test
    # Reattaching with --sig-proxy=false
    deep@Latitude-5590:~/explore-docker$ docker container attach --sig-proxy=false nginx-test
    172.17.0.1 - - [02/Jan/2021:16:51:13 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:84.0) Gecko/20100101 Firefox/84.0" "-"
    172.17.0.1 - - [02/Jan/2021:16:51:13 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:84.0) Gecko/20100101 Firefox/84.0" "-"
    # After Ctrl + C
    deep@Latitude-5590:~/explore-docker$ docker container ls
    CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                  NAMES
    ace004cb4246        nginx               "/docker-entrypoint.…"   5 hours ago         Up 30 seconds       0.0.0.0:8080->80/tcp   nginx-test
    

    Hitting the container's URL a few times and then pressing Ctrl + C will detach us from the NGINX process, but this time, rather than terminating the NGINX process, it will just return us to our Terminal.

  • LOGS

    The logs command is pretty self-explanatory. For example, to view the last entries written to stdout for our nginx-test container, you can use the following command:

    $ docker container logs --tail 5 nginx-test

    deep@Latitude-5590:~/explore-docker$ docker container logs --tail 5 nginx-test
    10-listen-on-ipv6-by-default.sh: info: Enabled listen on IPv6 in /etc/nginx/conf.d/default.conf
    /docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh
    /docker-entrypoint.sh: Configuration complete; ready for start up
    172.17.0.1 - - [04/Jan/2021:11:41:55 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:84.0) Gecko/20100101 Firefox/84.0" "-"
    172.17.0.1 - - [04/Jan/2021:11:41:55 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:84.0) Gecko/20100101 Firefox/84.0"
    

    To see the logs in real-time you can simply run the following command:

    $ docker container logs -f nginx-test, Here -f flag stands for --follow.

    To check logs for a particular DateTime you can use:

    $ docker container logs --since 2020-12-31T15:52:00 -t nginx-test

  • TOP

    The top command, lists the process running inside the container, and can be used as follows:

    deep@Latitude-5590:~/explore-docker$ docker container top nginx-test
    UID                 PID                 PPID                C                   STIME               TTY                 TIME                CMD
    root                9157                9138                0                   17:10               ?                   00:00:00            nginx: master process nginx -g daemon off;
    systemd+            9238                9157                0                   17:10               ?                   00:00:00            nginx: worker process
    
  • STATS

    The stats command provides real-time information.

    deep@Latitude-5590:~/explore-docker$ docker container stats nginx-test
    CONTAINER ID        NAME                CPU %               MEM USAGE / LIMIT    MEM %               NET I/O             BLOCK I/O           PIDS
    108b1eb32312        nginx-test          0.00%               4.762MiB / 15.5GiB   0.03%               12.3kB / 956B       9.5MB / 8.19kB      2
    

Containers states and miscellaneous commands

Let's launch a few containers first, run the following command:

$ for i in {1..4}; do docker container run -d --name nginx$(printf "$i") nginx; done

This will launch 4 containers as shown below, Let's proceed further:

deep@Latitude-5590:~/explore-docker$ for i in {1..4}; do docker container run -d --name nginx$(printf "$i") nginx; done
b1083d403ff3ea43840dfdf26888dca296c7bcda68d8a65197bd02380eb43150
85cf7861d52b0fe197ac08165a5b4525be89e0b28b9216b49fa85846278041c6
05be13ad42b7de676c0b971088c211adfe9ea85fc151d0e5dc4f8e912c339513
e8453941a4b5b79ab9a29f91e3412668645d92bdb472e4cfdb49cbd9775fb3ff

deep@Latitude-5590:~/explore-docker$ docker container ls -a
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                  NAMES
e8453941a4b5        nginx               "/docker-entrypoint.…"   2 minutes ago       Up 2 minutes        80/tcp                 nginx4
05be13ad42b7        nginx               "/docker-entrypoint.…"   2 minutes ago       Up 2 minutes        80/tcp                 nginx3
85cf7861d52b        nginx               "/docker-entrypoint.…"   2 minutes ago       Up 2 minutes        80/tcp                 nginx2
b1083d403ff3        nginx               "/docker-entrypoint.…"   2 minutes ago       Up 2 minutes        80/tcp                 nginx1
108b1eb32312        nginx               "/docker-entrypoint.…"   About an hour ago   Up About an hour    0.0.0.0:8080->80/tcp   nginx-test
  • PAUSE AND UNPAUSE

    Let's see how pause works. To do this, simply run the following:

    $ docker container pause nginx2

    deep@Latitude-5590:~/explore-docker$ docker container pause nginx2
    nginx2
    deep@Latitude-5590:~/explore-docker$ docker container ls
    CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS                   PORTS                  NAMES
    52d8b8e0c0f8        nginx               "/docker-entrypoint.…"   10 minutes ago      Up 10 minutes            80/tcp                 nginx5
    e8453941a4b5        nginx               "/docker-entrypoint.…"   10 minutes ago      Up 10 minutes            80/tcp                 nginx4
    05be13ad42b7        nginx               "/docker-entrypoint.…"   10 minutes ago      Up 10 minutes            80/tcp                 nginx3
    85cf7861d52b        nginx               "/docker-entrypoint.…"   10 minutes ago      Up 10 minutes (Paused)   80/tcp                 nginx2
    b1083d403ff3        nginx               "/docker-entrypoint.…"   10 minutes ago      Up 10 minutes            80/tcp                 nginx1
    108b1eb32312        nginx               "/docker-entrypoint.…"   About an hour ago   Up About an hour         0.0.0.0:8080->80/tcp   nginx-test
    

    You can see above, container nginx2 has been suspended or paused by cgroups freezer. Similarly to resume a paused container use:

    $ docker container unpause nginx2

  • STOP, START, RESTART, and KILL

    We are already familiar with start command. The stop command is similar to Ctrl + C.

    $ docker container stop nginx2

    On running this command, a request called SIGTERM is sent to terminate the process. If the process has not terminated itself within a grace period i.e 60 sec (default). This will immediately terminate the process, not giving any time to finish the running task. This can create a problem, You can override the grace period by using -t flag (--time). For example, wait up to 60 sec before killing the process.

    $ docker container stop -t 60 nginx3

    deep@Latitude-5590:~/explore-docker$ docker container stop -t 60 nginx3
    nginx3
    deep@Latitude-5590:~/explore-docker$ docker container ls
    CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                  NAMES
    52d8b8e0c0f8        nginx               "/docker-entrypoint.…"   33 minutes ago      Up 33 minutes       80/tcp                 nginx5
    e8453941a4b5        nginx               "/docker-entrypoint.…"   33 minutes ago      Up 33 minutes       80/tcp                 nginx4
    85cf7861d52b        nginx               "/docker-entrypoint.…"   33 minutes ago      Up 33 minutes       80/tcp                 nginx2
    b1083d403ff3        nginx               "/docker-entrypoint.…"   33 minutes ago      Up 33 minutes       80/tcp                 nginx1
    108b1eb32312        nginx               "/docker-entrypoint.…"   2 hours ago         Up 2 hours          0.0.0.0:8080->80/tcp   nginx-test
    deep@Latitude-5590:~/explore-docker$ docker container start nginx3
    nginx3
    

    The restart command stops and starts the container. Also, as with stop, you can pass the -t flag.

    $ docker container restart -t 60 nginx4

    The kill command kills the container immediately sending SIGKILL signal.

    $ docker container kill nginx5

  • REMOVING CONTAINERS

    The command docker container ls -a will show the status of all containers including the Exited once. To remove the exited containers, you can use prune command:

    $ docker container prune

    deep@Latitude-5590:~/explore-docker$ docker container ls -a
    CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS                     PORTS                  NAMES
    52d8b8e0c0f8        nginx               "/docker-entrypoint.…"   51 minutes ago      Up 51 minutes              80/tcp                 nginx5
    e8453941a4b5        nginx               "/docker-entrypoint.…"   51 minutes ago      Exited (0) 2 seconds ago
    # prune
    deep@Latitude-5590:~/explore-docker$ docker container prune
    WARNING! This will remove all stopped containers.
    Are you sure you want to continue? [y/N] y
    Deleted Containers:
    e8453941a4b5b79ab9a29f91e3412668645d92bdb472e4cfdb49cbd9775fb3ff
    Total reclaimed space: 1.114kB
    

    Sometimes, removing a container will not work as it is still running. If we want to force a removal, no matter what the condition of the container currently is, we can use the command-line parameter -f or --force.

    $ docker container rm -f /container name or ID/ ==> Avoid this, As it doesn’t bother asking nicely with a SIGTERM, it goes straight to the SIGKILL. You’re literally giving the container, and the app it’s running, no chance to complete any operation and gracefully exit.

Thank you for your time.

Did you find this article valuable?

Support Pradeep by becoming a sponsor. Any amount is appreciated!