×
Community Blog Docker Container-Centric Commands for Beginners: Part 2

Docker Container-Centric Commands for Beginners: Part 2

This tutorial provides a quick demonstration of the 25 Docker commands that can be applied against containers.

By Alwyn Botha, Alibaba Cloud Tech Share Author. Tech Share is Alibaba Cloud's incentive program to encourage the sharing of technical knowledge and best practices within the cloud community.

This tutorial provides a quick demonstration of the 25 Docker commands that can be applied against containers. The article is structured so that you get to use the following 25 commands at least once each. This will help provide a better understanding of containers from a high-level perspective, such as what containers are and what you can do with them.

Docker Container Inspect

From https://docs.docker.com/engine/reference/commandline/container_inspect/#description

docker container inspect : Display detailed information on one or more containers

Fortunately we can inspect stopped containers as well, so we can just run:

docker container inspect mycontain

You will see a long list of all the settings applied to this container.

Right at the top you will also see its current status : exited.

        "State": {
            "Status": "exited",
            "Running": false,
            "Paused": false,
            "Restarting": false,
            "OOMKilled": false,
            "Dead": false,

Note that dead = false. That would indicate a somehow seriously broken container. Exited containers can be restarted ( as we did above ) but if you someday get a dead container I doubt that can be restarted.

Docker Container Commit and Export

  • docker container commit - Create a new image from a container's changes
  • docker container export - Export a container's filesystem as a tar archive

These 2 commands have different uses:

  • commit: create a new image. You can then build a new container using this image as the base image. The new container is like a clone of original container. environment variables still exist.
  • export: save container content as a tar archive file. You can then untar and investigate the file content at any Linux shell. Original container totally gone. All we have is a file system: no environment variables and no concept of 'container running state'.

Summary Demo - Docker Container Commands

This part of the tutorial will use several docker container commands discussed in part 1 and this part 2.

You can use the same overall approach to make tiny changes - then observe results - to your containers while you are busy developing.

The plan

Phase 1: signals

  • write simple bash signal trapping script
  • write short Dockerfile to create mytraps:demo image
  • run mytraps:demo image
  • observe echo output via docker logs
  • send TERM signal via docker kill - observe result in logs
  • rerun mytraps:demo image
  • send INT signal via docker kill - observe result in logs
  • rerun mytraps:demo image
  • attach to container via docker attach
  • press ctrl-c - observe result in logs
  • rerun mytraps:demo image
  • send KILL signal via docker kill - observe result in logs

Phase 2: environment variables

  • run mytraps:demo image
  • observe echo output via docker logs
  • method 1: change our environment variable via docker exec - observe result in logs
  • method 2: change our environment variable via docker exec - observe result in logs
  • send KILL signal via docker kill - observe result in logs
  • write simple bash signal trapping script

nano traps

Please remove that remove-me text. Markdown must have headings start with hash, so script first lines are rendered as headings. Insane absurd but true.

remove-me#!/bin/bash
function SIGINT_trap() {
  echo . . . SIGINT signal caught
  echo . . . doing SIGINT cleanup
  exit
}

function SIGTERM_trap() {
  echo . . . SIGTERM signal caught
  echo . . . doing SIGTERM cleanup
  exit
}

trap SIGINT_trap SIGINT
trap SIGTERM_trap SIGTERM

for i in `seq 1 50`; do
    sleep 1
    echo -n " . "
    echo $i
done

exit 0

Line 14 and 15 will call the relevant function based on the signal received.

  • write short Dockerfile to create mytraps:demo image
nano Dockerfile 

Dockerfile content:

FROM alpine:3.8
ENV myvar original value
COPY traps /root/
RUN chmod +x /root/traps
CMD ["/bin/sh", "/root/traps"]
  • line 1: use Alpine 3.8 image
  • line 2: define myvar environment variable and supply a value
  • line 3: copy our bash traps script to /root/ directory in container
  • line 4: make our traps script executeable
  • line 5: define we want to run our traps script upon container startup.

Build that image:

docker build --tag mytraps:demo --file Dockerfile  .
  • prepare second shell console to observe container logs

Start a second shell. Run:

docker container logs mycontain -f

You will get error, that is OK - we have not started container yet.

This step is to get that command in the shell history so we can quickly get at it. You will see below.

  • run mytraps:demo image

First shell:

docker container run -d --name mycontain mytraps:demo
  • observe echo output via docker logs

Second shell:

Press up arrow key to get previous command and press ENTER. You will see the bash script output.

  • send TERM signal via docker kill

Run in first shell:

docker container kill --signal 15  mycontain
  • observe result in logs

Second shell:

Expected output :

...
 . 15
 . 16
 . 17
 . 18
 . 19
. . . SIGTERM signal caught
. . . doing SIGTERM cleanup

SIGTERM / 15 signal got caught - script is doing SIGTERM cleanup.

Note that log output now stops as well: the container exited successfully after processing the signal processing function.

Test 1 complete: signal TERM / 15 processed success.

  • rerun mytraps:demo image ... for signal interrupt test

Remove previous exited container:

Run in first shell:

docker container prune -f 

Start container again:

docker container run -d --name mycontain mytraps:demo
  • observe echo output via docker logs

Second shell:

Press up arrow key to get previous command and press ENTER. You will see the bash script output just like before.

  • send interrupt signal via docker kill

Run in first shell:

docker container kill --signal SIGINT  mycontain
  • observe result in logs

Second shell:

Expected output :

...
 . 16
 . 17
 . 18
 . 19
 . 20
. . . SIGINT signal caught
. . . doing SIGINT cleanup

SIGINT signal got caught - script is doing SIGINT cleanup.

Note that log output now stops as well: the container exited successfully after processing the signal processing function.

Test 2 complete: signal SIGINT / 2 processed success.

Test 3: KILL signal

  • rerun mytraps:demo image

Remove previous exited container:

Run in first shell:

docker container prune -f 

Start container again:

docker container run -d --name mycontain mytraps:demo
  • observe echo output via docker logs

Second shell:

Press up arrow key to get previous command and press ENTER. You will see the bash script output just like before.

  • send interrupt signal via docker kill

Run in first shell:

docker container kill --signal SIGKILL  mycontain
  • observe result in logs

Second shell:

Expected output :

...
 . 6
 . 7
 . 8
 . 9
 . 10
 . 11
 . 12

SIGKILL signal cannot be caught - script cannot do any cleanup routines.

Note that log output now stops as well: the container exited UNsuccessfully after being rudely KILLed immediately via KILL signal.

Test 3 complete: signal SIGKILL / 2 processed success.

Important summary: your processes running in your containers must have the proper cleanup routines. With Docker you will be shutting down and restart containers much more frequently than in the pre-Docker world. So its critical your containers can correctly handle all the different ways of being shut down.

Based on these exercises you see how easy it is to test handling just 2 signals.

If you enter trap -l at your shell you will see a list of 64 possible signals. Your processes must be able to handle all the possible values they can receive.

docker container kill is wrongly named.

It should have been: docker container signal - since you can send signals just to re-read configuration files. Not all signals kill.

You can use SIGUSR1 and SIGUSR2 for any purpose - send your applications those signals and let it mean anything - not just KILL.

Docker Container Wait

From https://docs.docker.com/engine/reference/commandline/container_wait/

Block until one or more containers stop, then print their exit codes

To investigate how this works, we are going to run 3 containers, let them sleep a few seconds and then exit with unique exit codes.

Cut and paste the following to your shell:

docker container run -d --name mycontain1 mytraps:demo sh -c 'sleep 10;exit 1'
docker container run -d --name mycontain2 mytraps:demo sh -c 'sleep 15;exit 2'
docker container run -d --name mycontain3 mytraps:demo sh -c 'sleep 25;exit 3'

Start a new shell console session and run:

docker container wait mycontain1 mycontain2 mycontain3

Note that as the containers sleep period runs down, they exit with the specified exit code.

There is no indication of which container exited with which exit code, which is frankly quite lame.

If you need to know which container exited with which exit code use:

docker ps -a

Expected output :

CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS                      PORTS               NAMES
6c7fe618e23b        mytraps:demo        "sh -c 'sleep 25;exi…"   40 seconds ago      Exited (3) 14 seconds ago                       mycontain3
d4e1bb11e55c        mytraps:demo        "sh -c 'sleep 15;exi…"   43 seconds ago      Exited (2) 27 seconds ago                       mycontain2
bee5cbf37052        mytraps:demo        "sh -c 'sleep 10;exi…"   44 seconds ago      Exited (1) 33 seconds ago                       mycontain1

This functionality is not very exiting but may have some use case: you have several batch containers that may run for maybe an hour or more. You expect all to complete successfully.

Instead of running docker ps -a every few minutes ( breaking your otherwise thinking workflows ), you can use this command in a new shell to watch those containers for you. When all your many containers finishes the command will show the prompt again: if you have a list of zeros shown then success ... all containers exited successfully.

(No output shown for commands below. Try them by yourself. )

You can use :

docker ps -a --filter "name=mycontain1"  --filter "name=mycontain2" --filter "name=mycontain3"

but this is really longwinded.

Note all containers use the same image: mytraps:demo

docker ps -a --filter "ancestor=mytraps:demo"

ancestor filter: Filters containers which share a given image as an ancestor.

Much shorter than before.

The shortest typing winner is

docker ps -a | grep mycontain

or even ( in this case )

docker ps -a | grep mytraps

If you define an alias mypsa:

alias mypsa='docker ps -a | grep '

then you can use :

mypsa traps
mypsa contain

docker container port

List port mappings or a specific mapping for the container

docker ps -a also shows port mappings. Therefore I am not going to investigate this command here.

Tutorial Cleanup

Prune stopped containers:

docker container prune -f 
 
docker image rm mytraps:demo 

We used alpine:3.8 image a lot. Since you will probably use it in future I suggest you do not delete it.

Conclusion

In these 2 tutorials you used nearly all 25 docker container commands. You now have a good understanding of what commands you can apply against your containers.

If you want to become a Docker expert in shortest time I suggest you do similar tiny and quick ( but very useful ) exercises with all the Docker functionalities.

0 0 0
Share on

Alibaba Clouder

2,605 posts | 747 followers

You may also like

Comments