Skip to content

Instantly share code, notes, and snippets.

@henrybravo
Last active September 18, 2023 14:52
Show Gist options
  • Save henrybravo/d54dbb97cec67b2b1efc87e2f821ec38 to your computer and use it in GitHub Desktop.
Save henrybravo/d54dbb97cec67b2b1efc87e2f821ec38 to your computer and use it in GitHub Desktop.
Getting started with docker containers to be used in Amazon ECS/EKS/Fargate.

Getting Started with Docker and Containers

Docker Architecture

Our First Containers

Background Containers

Restarting and attaching to containers

Understanding Docker Images

Building Images Interactively

Building Docker images with a Dockerfile

Publishing images

Container Networking Basics

Our First Containers

Hello World

$ docker run busybox echo hello world
hello world

We used one of the smallest, simplest images available: busybox. busybox is typically used in embedded systems (phones, routers...) We ran a single process and echo'ed hello world.

A more useful container

$ docker run -it amazonlinux
Unable to find image 'amazonlinux:latest' locally
Trying to pull repository docker.io/library/amazonlinux ... 
sha256:b852ce504670f604074bb0a0285849c95541453c39da4a6abe19c096695ccfca: Pulling from docker.io/library/amazonlinux
40280b975f14: Pull complete 
Digest: sha256:b852ce504670f604074bb0a0285849c95541453c39da4a6abe19c096695ccfca
Status: Downloaded newer image for docker.io/amazonlinux:latest
bash-4.2#
  • -it is shorthand for -i -t.
  • -i tells Docker to connect us to the container's stdin.
  • -t tells Docker that we want a pseudo-terminal.

Do something in our container

bash-4.2# figlet hello
bash: figlet: command not found

An observation

Let's check how many packages are installed here.

bash-4.2# rpm -qa | wc -l
102
  • rpm -qa lists the packages installed in our container
  • wc -l counts them

Install a package in our container

We want figlet, so let's install it:

bash-4.2# yum update -y && yum install figlet -y

One minute later, figlet is installed!

bash-4.2# figlet 'Hello Team'

Exiting our container

Just exit the shell, like you would usually do.

(E.g. with ^D or exit)

bash-4.2# exit
  • Our container is now in a stopped state.
  • It still exists on disk, but all compute resources have been freed up.

Starting another container

What if we start a new container, and try to run figlet again?

$ docker run -it amazonlinux
bash-4.2# figlet 'Hello Team'

Type exit to exit and proceed

exit
  • We started a brand new container.
  • The basic amazonlinux image was used, and figlet is not here.

Background Containers

Our first containers were interactive. Let's continue.

A non-interactive container

  • We will run a small custom container.
  • This container just displays the time every second.
$ docker run hbravo/quartz
...
^C

This container will run forever.

To stop it, press ^C.

  • Docker has automatically downloaded the image hbravo/quartz
  • This image is a user image, created by hbravo

Run a container in the background

Containers can be started in the background, with the -d flag (daemon mode):

$ docker run -d hbravo/quartz
47d677dcfba4277c6cc68fcaa51f932b544cab1a187c853b7d0caf4e8debe5ad

Docker gives us the ID of the container.

List running containers

With docker ps, just like the UNIX ps command, lists running processes.

$ docker ps
CONTAINER ID  IMAGE           ...  CREATED        STATUS        ...
47d677dcfba4  jpetazzo/clock  ...  2 minutes ago  Up 2 minutes  ...

Docker tells us:

  • The (truncated) ID of our container
  • The image used to start the container
  • That our container has been running (Up) for a couple of minutes

Starting more containers

Let's start two more containers.

$ docker run -d hbravo/quartz
57ad9bdfc06bb4407c47220cf59ce21585dce9a1298d7a67488359aeaea8ae2a
$ docker run -d hbravo/quartz
068cc994ffd0190bbe025ba74e4c0771a5d8f14734af772ddee8dc1aaf20567d

Check that docker ps correctly reports all 2 containers.

View the logs of a container

$ docker logs 068
Fri Feb 20 00:39:52 UTC 2015
Fri Feb 20 00:39:53 UTC 2015
...

We specified a prefix of the full container ID. You can, of course, specify the full ID.

Stopping our containers

Let's stop one of our containers:

$ docker stop 47d6
47d6
  • This will take 10 seconds:
  • Docker sends the TERM signal;
  • the container doesn't react to this signal (it's a simple Shell script with no special signal handling);
  • 10 seconds later, since the container is still running, Docker sends the KILL signal;
  • this terminates the container.

List stopped containers

$ docker ps -a
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS
bd8506a11b98        hbravo/quartz       "/bin/sh -c 'while..."   22 minutes ago      Exited (0) 22 minutes ago               6ace1563fd52        amazonlinux         "/bin/bash"              25 minutes ago      Exited (0) 22 minutes ago               0be0fcd6c807        amazonlinux         "/bin/bash"              25 minutes ago      Exited (127) 25 minutes ago             891d63c20cb3        amazonlinux         "/bin/bash"              26 minutes ago      Exited (0) 25 minutes ago               ff4d569e8e80        amazonlinux         "/bin/bash"              53 minutes ago      Exited (0) 26 minutes ago               

Restarting and attaching to containers

  • The distinction between foreground and background containers is arbitrary
  • From Docker's point of view, all containers are the same
  • All containers run the same way, whether there is a client attached to them or not
  • It is always possible to detach from a container, and to reattach to a container
  • Analogy: attaching to a container is like plugging a keyboard and screen to a physical server

Detaching from a container

If you have started an interactive container (with option -it), you can detach from it.

The "detach" sequence is ^P^Q.

Otherwise you can detach by killing the Docker client.

(But not by hitting ^C, as this would deliver SIGINT to the container.)

What does -it stand for?

-t means "allocate a terminal." -i means "connect stdin to the terminal."

Attaching to a container

You can attach to a container:

$ docker attach <containerID>
  • The container must be running
  • There can be multiple clients attached to the same container
  • If you don't specify --detach-keys when attaching, it defaults back to ^P^Q

Try it on our previous container:

$ docker attach $(docker ps -lq)

Check that ^X x doesn't work, but ^P ^Q does.

Understanding Docker Images

Showing current images

$ docker images
REPOSITORY                 TAG                 IMAGE ID            CREATED             SIZE
docker.io/node             latest              c888d933885c        35 hours ago        676 MB
docker.io/centos           latest              ff426288ea90        3 days ago          207 MB
docker.io/ubuntu           latest              00fd29ccc6f1        4 weeks ago         111 MB
docker.io/amazonlinux      latest              6133b2c7d7c2        2 months ago        165 MB
docker.io/hbravo/quartz    latest              9fa18fecadd7        4 days ago         6.03 MB

Searching for images

We cannot list all images on a remote registry, but we can search for a specific keyword:

$ docker search marathon
NAME                     DESCRIPTION                     STARS  OFFICIAL  AUTOMATED
mesosphere/marathon      A cluster-wide init and co...   105              [OK]
mesoscloud/marathon      Marathon                        31               [OK]
mesosphere/marathon-lb   Script to update haproxy b...   22               [OK]
tobilg/mongodb-marathon  A Docker image to start a ...   4                [OK]
  • "Stars" indicate the popularity of the image
  • "Official" images are those in the root namespace
  • "Automated" images are built automatically by the Docker Hub. (This means that their build recipe is always available.)

Downloading images

Explicitly, with

$ docker pull.

Implicitly, when executing $ docker run and the image is not found locally

docker pull node
Using default tag: latest
Trying to pull repository docker.io/library/node ... 
sha256:30f98963fd361b0241db107e68da88a1ebed0561e3ecc7bf221586901863e4b1: Pulling from docker.io/library/node
f49cf87b52c1: Pull complete 
7b491c575b06: Pull complete 
b313b08bab3b: Pull complete 
51d6678c3f0e: Pull complete 
da59faba155b: Pull complete 
7f84ea62c1fd: Pull complete 
c565d8353be2: Pull complete 
d5ff402a260a: Pull complete 
Digest: sha256:30f98963fd361b0241db107e68da88a1ebed0561e3ecc7bf221586901863e4b1
Status: Downloaded newer image for docker.io/node:latest

Building Images Interactively

Create a new container and make some changes

Start an Ubuntu container:

$ docker run -it ubuntu
root@<yourContainerId>:#/
  • Run the command apt-get update to refresh the list of packages available to install.
  • Then run the command apt-get install figlet to install the program we are interested in.
root@<yourContainerId>:#/ apt-get update && apt-get install figlet
.... OUTPUT OF APT-GET COMMANDS ....

Inspect the changes

Type exit at the container prompt to leave the interactive session.

Now let's run docker diff to see the difference between the base image and our container.

docker diff $(docker ps -l -q)
...
C /etc/alternatives
A /etc/alternatives/figlet
A /etc/alternatives/figlet.6.gz
C /root
A /root/.bash_history
C /run
D /run/secrets
C /tmp
C /usr/bin
A /usr/bin/chkfont
A /usr/bin/figlet
A /usr/bin/figlet-figlet
A /usr/bin/figlist
...

Commit and run your image

The docker commit command will create a new layer with those changes, and a new image using this new layer.

$ docker commit <yourContainerId>
<newImageId>
$ docker run -it <newImageId>
root@e2072fdfa86e:/# figlet 'It Works!'

Tagging images

Referring to an image by its ID is not convenient. Let's tag it instead.

We can use the tag command:

$ docker tag <newImageId> figlet

But we can also specify the tag as an extra argument to commit:

$ docker commit <containerId> figlet

And then run it using its tag:

$ docker run -it figlet

Building Docker images with a Dockerfile

  • A Dockerfile is a build recipe for a Docker image
  • It contains a series of instructions telling Docker how an image is constructed
  • The docker build command builds an image from a Dockerfile

Writing our first Dockerfile

Our Dockerfile must be in a new, empty directory.

Create a directory to hold our Dockerfile.

$ mkdir myimage

Create a Dockerfile inside this directory.

$ cd myimage
$ vim Dockerfile

*Of course, you can use any other editor of your choice.

Type this into our Dockerfile

FROM amazonlinux
RUN yum update -y
RUN yum install -y figlet
CMD ["/usr/bin/figlet","Hello World!"]
  • FROM indicates the base image for our build
  • Each RUN line will be executed by Docker during the build
  • Our RUN commands must be non-interactive (No input can be provided to Docker during the build)
  • In many cases, we will add the -y flag to yum commands
  • The CMD instruction can be used for executing a specific command when a container is instantiated using the image being built

Build it

Save our file, then execute:

$ docker build -t amzlinuxfiglet:dev .
  • -t indicates the tag to apply to the image.
  • . indicates the location of the build context.

Running the image

The resulting image is not different from the one produced manually.

$ docker run amzlinuxfiglet:dev

Using image and viewing history

The history command lists all the layers composing an image.

For each layer, it shows its creation time, size, and creation command.

When an image was built with a Dockerfile, each layer corresponds to a line of the Dockerfile.

$ docker history figlet
IMAGE               CREATED             CREATED BY                                      SIZE
fb3992dbaea0        12 minutes ago      /bin/bash                                       41 MB
00fd29ccc6f1        4 weeks ago         /bin/sh -c #(nop)  CMD ["/bin/bash"]            0 B
<missing>           4 weeks ago         /bin/sh -c mkdir -p /run/systemd && echo '...   7 B
<missing>           4 weeks ago         /bin/sh -c sed -i 's/^#\s*\(deb.*universe\...   2.76 kB
<missing>           4 weeks ago         /bin/sh -c rm -rf /var/lib/apt/lists/*          0 B
<missing>           4 weeks ago         /bin/sh -c set -xe   && echo '#!/bin/sh' >...   745 B
<missing>           4 weeks ago         /bin/sh -c #(nop) ADD file:f5a2d04c3f3cafa...   111 MB

Publishing images

In this example we are going to commit our new image to Amazon ECR - so we can e.g. use it in Amazon ECS or Amazon Fargate Tasks.

aws ecr create-repository --repository-name myamzlinuxfiglet
aws ecr get-login
docker login -u AWS *****
docker tag amzlinuxfiglet:dev *****.dkr.ecr.eu-west-1.amazonaws.com/amzlinuxfiglet:dev
docker push *****.dkr.ecr.eu-west-1.amazonaws.com/amzlinuxfiglet:dev

Container Networking Basics

Run the Docker Hub image nginx, which contains a basic web server

$ docker run -d -P nginx
66b1ce719198711292c8f34f84a7b68c3876cf9f67015e752b94e189d35a204e
Docker will download the image from the Docker Hub.
  • -d tells Docker to run the image in the background
  • -P tells Docker to make this service reachable from other computers. (-P is the short version of --publish-all.)

But, how do we connect to our web server now?

Finding our web server port

We will use docker ps:

$ docker ps
CONTAINER ID  IMAGE  ...  PORTS                                          ...
e40ffb406c9e  nginx  ...  0.0.0.0:32769->80/tcp, 0.0.0.0:32768->443/tcp  ...
  • The web server is running on ports 80 and 443 inside the container
  • Those ports are mapped to ports 32769 and 32768 on our Docker host

Manual allocation of port numbers

If you want to set port numbers yourself, no problem:

$ docker run -d -p 80:80 nginx
$ docker run -d -p 8000:80 nginx
$ docker run -d -p 8080:80 -p 8888:80 nginx
  • We are running 3 NGINX web servers.
  • The first one is exposed on port 80
  • The second one is exposed on port 8000
  • The third one is exposed on ports 8080 and 8888

Note: the convention is port-on-host:port-on-contain

Finding the container's IP address

We can use the docker inspect command to find the IP address of the container.

$ docker inspect --format '{{ .NetworkSettings.IPAddress }}' <yourContainerID>
172.17.0.3

Reference

This manual is based on the exellent material from http://container.training

Some useful links:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment