drawing

NFV Hands-on Tutorial

with Docker

I am Juan Cabrera

In [2]:
print ('Name: ', Juan['name'])
print ('Email: ', Juan['email'])
print ('Work: ', Juan['work'])
Name:  Juan A. Cabrera
Email:  juan.cabrera@tu-dresden.de
Work:  Deutsche Telekom Chair of Communication Networks

Slides: https://comnets.bitbucket.io/wcnc-tutorial/hands-on/
Press esc for a menu of the slides

Slides inspired and adapted from:
Docker by Example, by:
Ganesh & Hari {ganesh|hari}(at)codeops.tech

Docker version

In [3]:
%%bash
docker -v
Docker version 18.09.4-ce, build d14af54266

Docker info

In [4]:
%%bash
docker info
Containers: 50
 Running: 0
 Paused: 0
 Stopped: 50
Images: 46
Server Version: 18.09.4-ce
Storage Driver: overlay2
 Backing Filesystem: extfs
 Supports d_type: true
 Native Overlay Diff: true
Logging Driver: json-file
Cgroup Driver: cgroupfs
Plugins:
 Volume: local
 Network: bridge host macvlan null overlay
 Log: awslogs fluentd gcplogs gelf journald json-file local logentries splunk syslog
Swarm: inactive
Runtimes: runc
Default Runtime: runc
Init Binary: docker-init
containerd version: bb71b10fd8f58240ca47fbb579b9d1028eea7c84.m
runc version: 69ae5da6afdcaaf38285a10b36f362e41cb298d6
init version: fec3683
Security Options:
 seccomp
  Profile: default
Kernel Version: 4.9.166-1-MANJARO
Operating System: Manjaro Linux
OSType: linux
Architecture: x86_64
CPUs: 4
Total Memory: 7.513GiB
Name: theshire
ID: E633:V5GR:2JQJ:6LP4:5LEV:P4D3:PSJK:3VTS:AOQQ:6ETU:LA47:2MNF
Docker Root Dir: /var/lib/docker
Debug Mode (client): false
Debug Mode (server): false
Registry: https://index.docker.io/v1/
Labels:
Experimental: false
Insecure Registries:
 127.0.0.0/8
Live Restore Enabled: false

Running a Container

Hello World

In [5]:
%%bash
docker run docker/whalesay cowsay Hello World
 _____________ 
< Hello World >
 ------------- 
    \
     \
      \     
                    ##        .            
              ## ## ##       ==            
           ## ## ## ##      ===            
       /""""""""""""""""___/ ===        
  ~~~ {~~ ~~~~ ~~~ ~~~~ ~~ ~ /  ===- ~~~   
       \______ o          __/            
        \    \        __/             
          \____\______/   

Hello World 2

What is going on?

In [6]:
%%bash
docker run hello-world
Hello from Docker!
This message shows that your installation appears to be working correctly.

To generate this message, Docker took the following steps:
 1. The Docker client contacted the Docker daemon.
 2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
 3. The Docker daemon created a new container from that image which runs the
    executable that produces the output you are currently reading.
 4. The Docker daemon streamed that output to the Docker client, which sent it
    to your terminal.

To try something more ambitious, you can run an Ubuntu container with:
 $ docker run -it ubuntu bash

Share images, automate workflows, and more with a free Docker ID:
 https://cloud.docker.com/

For more examples and ideas, visit:
 https://docs.docker.com/engine/userguide/

Getting help

In [7]:
%%bash
docker -h
Flag shorthand -h has been deprecated, please use --help

Usage:	docker [OPTIONS] COMMAND

A self-sufficient runtime for containers

Options:
      --config string      Location of client config files (default
                           "/home/juarch/.docker")
  -D, --debug              Enable debug mode
  -H, --host list          Daemon socket(s) to connect to
  -l, --log-level string   Set the logging level
                           ("debug"|"info"|"warn"|"error"|"fatal")
                           (default "info")
      --tls                Use TLS; implied by --tlsverify
      --tlscacert string   Trust certs signed only by this CA (default
                           "/home/juarch/.docker/ca.pem")
      --tlscert string     Path to TLS certificate file (default
                           "/home/juarch/.docker/cert.pem")
      --tlskey string      Path to TLS key file (default
                           "/home/juarch/.docker/key.pem")
      --tlsverify          Use TLS and verify the remote
  -v, --version            Print version information and quit

Management Commands:
  builder     Manage builds
  config      Manage Docker configs
  container   Manage containers
  engine      Manage the docker engine
  image       Manage images
  network     Manage networks
  node        Manage Swarm nodes
  plugin      Manage plugins
  secret      Manage Docker secrets
  service     Manage services
  stack       Manage Docker stacks
  swarm       Manage Swarm
  system      Manage Docker
  trust       Manage trust on Docker images
  volume      Manage volumes

Commands:
  attach      Attach local standard input, output, and error streams to a running container
  build       Build an image from a Dockerfile
  commit      Create a new image from a container's changes
  cp          Copy files/folders between a container and the local filesystem
  create      Create a new container
  diff        Inspect changes to files or directories on a container's filesystem
  events      Get real time events from the server
  exec        Run a command in a running container
  export      Export a container's filesystem as a tar archive
  history     Show the history of an image
  images      List images
  import      Import the contents from a tarball to create a filesystem image
  info        Display system-wide information
  inspect     Return low-level information on Docker objects
  kill        Kill one or more running containers
  load        Load an image from a tar archive or STDIN
  login       Log in to a Docker registry
  logout      Log out from a Docker registry
  logs        Fetch the logs of a container
  pause       Pause all processes within one or more containers
  port        List port mappings or a specific mapping for the container
  ps          List containers
  pull        Pull an image or a repository from a registry
  push        Push an image or a repository to a registry
  rename      Rename a container
  restart     Restart one or more containers
  rm          Remove one or more containers
  rmi         Remove one or more images
  run         Run a command in a new container
  save        Save one or more images to a tar archive (streamed to STDOUT by default)
  search      Search the Docker Hub for images
  start       Start one or more stopped containers
  stats       Display a live stream of container(s) resource usage statistics
  stop        Stop one or more running containers
  tag         Create a tag TARGET_IMAGE that refers to SOURCE_IMAGE
  top         Display the running processes of a container
  unpause     Unpause all processes within one or more containers
  update      Update configuration of one or more containers
  version     Show the Docker version information
  wait        Block until one or more containers stop, then print their exit codes

Run 'docker COMMAND --help' for more information on a command.

What images do you have?

In [11]:
%%bash
docker images
REPOSITORY                         TAG                 IMAGE ID            CREATED             SIZE
juancabre/verona                   latest              68b867c8e91b        4 months ago        170MB
juancabre/test-pre-verona          pingVim             947e9f61365b        4 months ago        226MB
my-bench                           latest              196c732622cd        16 months ago       166MB
my_server                          latest              187253ea98a9        16 months ago       108MB
juancabre/ubu_lecture_dockerfile   vim_config          08a2460bcd29        16 months ago       219MB
juancabre/ubu_lecture              latest              e5dbcde14e04        16 months ago       224MB
juancabre/ubu_lecture              ping                0c285dd24f81        16 months ago       167MB
nginx                              latest              40960efd7b8f        17 months ago       108MB
haproxy                            latest              f8177ad6f329        17 months ago       136MB
mysql                              5.7                 5709795eeffa        17 months ago       408MB
ubuntu                             <none>              dd6f76d9cc90        17 months ago       122MB
debian                             wheezy              f47fe1c60a2f        17 months ago       85.1MB
debian                             latest              6d83de432e98        17 months ago       100MB
hello-world                        latest              725dcfab7d63        17 months ago       1.84kB
alpine                             latest              053cde6e8953        17 months ago       3.97MB
gcc                                4.9                 1b3de68a7ff8        19 months ago       1.37GB
google/cadvisor                    latest              f9ba08bafdea        2 years ago         57.3MB
docker/whalesay                    latest              6b362a9f73eb        3 years ago         247MB

How to search for an image?

In [12]:
%%bash
docker search ubuntu
NAME                                                   DESCRIPTION                                     STARS               OFFICIAL            AUTOMATED
ubuntu                                                 Ubuntu is a Debian-based Linux operating sys…   9380                [OK]                
dorowu/ubuntu-desktop-lxde-vnc                         Docker image to provide HTML5 VNC interface …   288                                     [OK]
rastasheep/ubuntu-sshd                                 Dockerized SSH service, built on top of offi…   211                                     [OK]
consol/ubuntu-xfce-vnc                                 Ubuntu container with "headless" VNC session…   169                                     [OK]
ubuntu-upstart                                         Upstart is an event-based replacement for th…   97                  [OK]                
ansible/ubuntu14.04-ansible                            Ubuntu 14.04 LTS with ansible                   96                                      [OK]
neurodebian                                            NeuroDebian provides neuroscience research s…   56                  [OK]                
1and1internet/ubuntu-16-nginx-php-phpmyadmin-mysql-5   ubuntu-16-nginx-php-phpmyadmin-mysql-5          50                                      [OK]
ubuntu-debootstrap                                     debootstrap --variant=minbase --components=m…   40                  [OK]                
nuagebec/ubuntu                                        Simple always updated Ubuntu docker images w…   23                                      [OK]
tutum/ubuntu                                           Simple Ubuntu docker images with SSH access     20                                      
i386/ubuntu                                            Ubuntu is a Debian-based Linux operating sys…   17                                      
1and1internet/ubuntu-16-apache-php-7.0                 ubuntu-16-apache-php-7.0                        13                                      [OK]
ppc64le/ubuntu                                         Ubuntu is a Debian-based Linux operating sys…   12                                      
eclipse/ubuntu_jdk8                                    Ubuntu, JDK8, Maven 3, git, curl, nmap, mc, …   8                                       [OK]
codenvy/ubuntu_jdk8                                    Ubuntu, JDK8, Maven 3, git, curl, nmap, mc, …   5                                       [OK]
darksheer/ubuntu                                       Base Ubuntu Image -- Updated hourly             5                                       [OK]
pivotaldata/ubuntu                                     A quick freshening-up of the base Ubuntu doc…   2                                       
smartentry/ubuntu                                      ubuntu with smartentry                          1                                       [OK]
1and1internet/ubuntu-16-sshd                           ubuntu-16-sshd                                  1                                       [OK]
paasmule/bosh-tools-ubuntu                             Ubuntu based bosh-cli                           1                                       [OK]
pivotaldata/ubuntu-gpdb-dev                            Ubuntu images for GPDB development              0                                       
ossobv/ubuntu                                          Custom ubuntu image from scratch (based on o…   0                                       
1and1internet/ubuntu-16-healthcheck                    ubuntu-16-healthcheck                           0                                       [OK]
1and1internet/ubuntu-16-rspec                          ubuntu-16-rspec                                 0                                       [OK]

Let us get a new image - Ubuntu

In [13]:
%%bash
docker pull ubuntu
Using default tag: latest
latest: Pulling from library/ubuntu
898c46f3b1a1: Pulling fs layer
63366dfa0a50: Pulling fs layer
041d4cd74a92: Pulling fs layer
6e1bee0f8701: Pulling fs layer
6e1bee0f8701: Waiting
041d4cd74a92: Download complete
63366dfa0a50: Verifying Checksum
63366dfa0a50: Download complete
898c46f3b1a1: Verifying Checksum
898c46f3b1a1: Download complete
6e1bee0f8701: Verifying Checksum
6e1bee0f8701: Download complete
898c46f3b1a1: Pull complete
63366dfa0a50: Pull complete
041d4cd74a92: Pull complete
6e1bee0f8701: Pull complete
Digest: sha256:017eef0b616011647b269b5c65826e2e2ebddbe5d1f8c1e56b3599fb14fabec8
Status: Downloaded newer image for ubuntu:latest

Let us get a new image - Alpine

In [14]:
%%bash
docker pull alpine
Using default tag: latest
latest: Pulling from library/alpine
8e402f1a9c57: Pulling fs layer
8e402f1a9c57: Verifying Checksum
8e402f1a9c57: Download complete
8e402f1a9c57: Pull complete
Digest: sha256:644fcb1a676b5165371437feaa922943aaf7afcfa8bfee4472f6860aad1ef2a0
Status: Downloaded newer image for alpine:latest

Where are these images located?

In [11]:
from IPython.core.display import HTML
HTML('<a href="https://hub.docker.com/">Docker Hub</a>')
Out[11]:

Prefer Smaller Images

Alpine linux might be enough compared to Ubuntu image

In [12]:
%%bash
docker images
REPOSITORY                TAG                 IMAGE ID            CREATED             SIZE
dock0/arch                latest              9fd5c23f509f        About an hour ago   575.5 MB
nginx                     latest              e43d811ce2f4        39 hours ago        181.4 MB
dock0/arch                <none>              9b9558aeec5c        4 days ago          573.6 MB
alpine                    latest              baa5d63471ea        4 days ago          4.799 MB
nginx                     <none>              a5311a310510        10 days ago         181.4 MB
datadog/docker-dd-agent   latest              f385e05e1883        6 weeks ago         301.8 MB
node                      5-slim              c7a1798865e7        7 weeks ago         207.5 MB
ubuntu                    latest              bd3d4369aebc        8 weeks ago         126.6 MB
hello-world               latest              c54a2cc56cbb        3 months ago        1.848 kB
gophernet/mz              latest              71fa98ad2324        6 months ago        126.3 MB
networkstatic/iperf3      latest              6ea158fee1a7        7 months ago        125.5 MB
docker/whalesay           latest              6b362a9f73eb        17 months ago       247 MB

Getting details of an image

In [15]:
%%bash
docker inspect alpine
[
    {
        "Id": "sha256:5cb3aa00f89934411ffba5c063a9bc98ace875d8f92e77d0029543d9f2ef4ad0",
        "RepoTags": [
            "alpine:latest"
        ],
        "RepoDigests": [
            "alpine@sha256:644fcb1a676b5165371437feaa922943aaf7afcfa8bfee4472f6860aad1ef2a0"
        ],
        "Parent": "",
        "Comment": "",
        "Created": "2019-03-07T22:19:40.247110971Z",
        "Container": "277610461b47d66cbee3947628daa460aa62836414a2762aee57da387724e33e",
        "ContainerConfig": {
            "Hostname": "277610461b47",
            "Domainname": "",
            "User": "",
            "AttachStdin": false,
            "AttachStdout": false,
            "AttachStderr": false,
            "Tty": false,
            "OpenStdin": false,
            "StdinOnce": false,
            "Env": [
                "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
            ],
            "Cmd": [
                "/bin/sh",
                "-c",
                "#(nop) ",
                "CMD [\"/bin/sh\"]"
            ],
            "ArgsEscaped": true,
            "Image": "sha256:0b7fc56164419dfc0ce9fd320acfc2032a72c3b7f276c5f04cb733f9a4f45c7f",
            "Volumes": null,
            "WorkingDir": "",
            "Entrypoint": null,
            "OnBuild": null,
            "Labels": {}
        },
        "DockerVersion": "18.06.1-ce",
        "Author": "",
        "Config": {
            "Hostname": "",
            "Domainname": "",
            "User": "",
            "AttachStdin": false,
            "AttachStdout": false,
            "AttachStderr": false,
            "Tty": false,
            "OpenStdin": false,
            "StdinOnce": false,
            "Env": [
                "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
            ],
            "Cmd": [
                "/bin/sh"
            ],
            "ArgsEscaped": true,
            "Image": "sha256:0b7fc56164419dfc0ce9fd320acfc2032a72c3b7f276c5f04cb733f9a4f45c7f",
            "Volumes": null,
            "WorkingDir": "",
            "Entrypoint": null,
            "OnBuild": null,
            "Labels": null
        },
        "Architecture": "amd64",
        "Os": "linux",
        "Size": 5529047,
        "VirtualSize": 5529047,
        "GraphDriver": {
            "Data": {
                "MergedDir": "/var/lib/docker/overlay2/1171039d01d98be6610528a4f999c2d7c3e0ab8e963913159372eb0acd042b2c/merged",
                "UpperDir": "/var/lib/docker/overlay2/1171039d01d98be6610528a4f999c2d7c3e0ab8e963913159372eb0acd042b2c/diff",
                "WorkDir": "/var/lib/docker/overlay2/1171039d01d98be6610528a4f999c2d7c3e0ab8e963913159372eb0acd042b2c/work"
            },
            "Name": "overlay2"
        },
        "RootFS": {
            "Type": "layers",
            "Layers": [
                "sha256:bcf2f368fe234217249e00ad9d762d8f1a3156d60c442ed92079fa5b120634a1"
            ]
        },
        "Metadata": {
            "LastTagTime": "0001-01-01T00:00:00Z"
        }
    }
]

Inspect the "inside" of an image

In [16]:
%%bash
docker history ubuntu
IMAGE               CREATED             CREATED BY                                      SIZE                COMMENT
94e814e2efa8        3 weeks ago         /bin/sh -c #(nop)  CMD ["/bin/bash"]            0B                  
<missing>           3 weeks ago         /bin/sh -c mkdir -p /run/systemd && echo 'do…   7B                  
<missing>           3 weeks ago         /bin/sh -c rm -rf /var/lib/apt/lists/*          0B                  
<missing>           3 weeks ago         /bin/sh -c set -xe   && echo '#!/bin/sh' > /…   745B                
<missing>           3 weeks ago         /bin/sh -c #(nop) ADD file:1d7cb45c4e196a6a8…   88.9MB              

Deleting an image

docker rmi <image-tag>

Docker containers

We create a container using docker run
specifically:

docker run OPTIONS <<image-tag>> CMD ARGS

Let us ping a server

docker run alpine ping "8.8.8.8"

How do we run a container interactively?

docker run -t -i ubuntu /bin/bash

-t Attach a pseudo-tty console
-i Stands for Interactive

Docker containers are isolated

Have you ever wanted to try this command on a Linux system?

rm -rf / --no-preserve-root

Well, in docker you can with no consequences!

PLEASE BE VERY CAREFUL

If you are running this in your own system, make sure to be in a container

Running a container in the background

docker run -d ubuntu /bin/sh -c "while true; do $(echo date); sleep 2 ; done"

-d stands for detach

How do we see the logs of a container?

docker logs <Container-Tag>

Now that we know the basics...

Let us easily set up an HTTP server?

We can do it with one command, without pre-installs

Lets choose HTTP server

We choose Nginx

In [1]:
from IPython.display import IFrame
IFrame('https://en.wikipedia.org/wiki/Comparison_of_web_server_software#Overview', width=700, height=350)
Out[1]:

Is it in docker hub?

In [18]:
%%bash
docker search nginx
NAME                                                   DESCRIPTION                                     STARS               OFFICIAL            AUTOMATED
nginx                                                  Official build of Nginx.                        11193               [OK]                
jwilder/nginx-proxy                                    Automated Nginx reverse proxy for docker con…   1577                                    [OK]
richarvey/nginx-php-fpm                                Container running Nginx + PHP-FPM capable of…   702                                     [OK]
jrcs/letsencrypt-nginx-proxy-companion                 LetsEncrypt container to use with nginx as p…   500                                     [OK]
webdevops/php-nginx                                    Nginx with PHP-FPM                              123                                     [OK]
zabbix/zabbix-web-nginx-mysql                          Zabbix frontend based on Nginx web-server wi…   94                                      [OK]
bitnami/nginx                                          Bitnami nginx Docker Image                      65                                      [OK]
linuxserver/nginx                                      An Nginx container, brought to you by LinuxS…   58                                      
1and1internet/ubuntu-16-nginx-php-phpmyadmin-mysql-5   ubuntu-16-nginx-php-phpmyadmin-mysql-5          50                                      [OK]
zabbix/zabbix-web-nginx-pgsql                          Zabbix frontend based on Nginx with PostgreS…   30                                      [OK]
tobi312/rpi-nginx                                      NGINX on Raspberry Pi / ARM                     25                                      [OK]
nginx/nginx-ingress                                    NGINX Ingress Controller for Kubernetes         17                                      
nginxdemos/hello                                       NGINX webserver that serves a simple page co…   13                                      [OK]
schmunk42/nginx-redirect                               A very simple container to redirect HTTP tra…   13                                      [OK]
blacklabelops/nginx                                    Dockerized Nginx Reverse Proxy Server.          12                                      [OK]
wodby/drupal-nginx                                     Nginx for Drupal container image                12                                      [OK]
centos/nginx-18-centos7                                Platform for running nginx 1.8 or building n…   10                                      
centos/nginx-112-centos7                               Platform for running nginx 1.12 or building …   7                                       
1science/nginx                                         Nginx Docker images that include Consul Temp…   4                                       [OK]
nginxinc/nginx-unprivileged                            Unprivileged NGINX Dockerfiles                  4                                       
mailu/nginx                                            Mailu nginx frontend                            3                                       [OK]
travix/nginx                                           NGinx reverse proxy                             2                                       [OK]
toccoag/openshift-nginx                                Nginx reverse proxy for Nice running on same…   1                                       [OK]
wodby/nginx                                            Generic nginx                                   0                                       [OK]
ansibleplaybookbundle/nginx-apb                        An APB to deploy NGINX                          0                                       [OK]

Of course it is!

Let us run it!

docker run -d -p 80:80 nginx

-d stands for detach
-p stands for port. We basically say: "Redirect every incomming TCP packet at port 80 of the host, to the port 80 of the container"

Try it!

Open your browser at localhost:80

In [2]:
from IPython.display import IFrame
IFrame('http://localhost:80', width=700, height=350)
Out[2]:

What is going on there?

The container is an HTTP server listening to port 80

How do we forward the traffic from the host to the container?

When we use the flag -p we "publish a port, or range of ports to the host".

Format: hostPort:containerPort

For UDP ports: hostPort:containerPort/udp

Let us map a different port in the host

Let us stop the server

First we need to find the container

docker ps

Then, we stop it

docker stop CONTAINER_ID

Let us also delete it

docker rm CONTAINER_ID

Check that the container is not there anymore. Go to localhost:80 in your browser. You should see an error

Note: Use incognito mode. Otherwise, the browser will display the cached site.

Let us make the new server

docker run -d -p 45700:80 nginx

Now, if go in your browser to localhost:4570

Docker Container State Transition

title

Editing Nginx

index.html

Lets crreate the html file that we will serve from our containerized http server

index.html
=================================

<h1> Welcome to PBL </h1>

<h2> Have Fun! </h2>

Editing Nginx

Dockerfile

Dockerfiles are like a recipe. It is a set of instructions used to create a custom image

Dockerfile
=================================

# Base image
FROM nginx:latest
# The maintainer
MAINTAINER Juan

# The actual recipe
# ADD Will add the created file in the step above
ADD ./index.html /usr/share/nginx/html/index.html
EXPOSE 80
docker build -t my_server .
docker run -p 80:80 -d my_server

Docker Volumes

They can be used to make data persistent

# Make a folder to store the data
mkdir ~/testing_data

# Run a container
docker run -v ~/testing_data:/container_volumes ubuntu /bin/sh -c "echo peristent data > /container_volumes/data.txt"

# Check that your data is there
cat ~/testing_data/data.txt

Make an image to compile and run our C code with a specific gcc version

Dockerfile
=======================
FROM gcc:4.9
COPY . /usr/src/myapp
WORKDIR /usr/src/myapp
RUN gcc -o myapp main.c
CMD ["./myapp"]
main.c
=======================
#include <stdio.h>

main()
{
    printf("Hello container world\n");
}

Running the image

# Build the image
docker build . -t my-gcc-app

# Run a container
docker run -rm my-gcc-app

Monitoring your containers

First, Lets build a benchmarking image

Let us use sysbench

The cpu is one of the most simple benchmarks in SysBench. In this mode each request consists in calculation of prime numbers up to a value specified by the −−cpu−max−primes option. All calculations are performed using 64−bit integers.

Each thread executes the requests concurrently until either the total number of requests or the total execution time exceed the limits specified with the common command line options.

Monitoring your containers

First, Lets build a benchmarking image

Dockerfile
=======================
FROM ubuntu:latest
MAINTAINER Juan

RUN apt-get update \
    && apt-get install -y sysbench

CMD sysbench --test=cpu --cpu-max-prime=35000 --num-threads=4 run

build it and run it to test it

Monitoring your containers

Let us run the monitoring tool

There are several options out there.

Let us use Google's cAdvisor https://github.com/google/cadvisor

docker run \
  --volume=/:/rootfs:ro \
  --volume=/var/run:/var/run:rw \
  --volume=/sys:/sys:ro \
  --volume=/var/lib/docker/:/var/lib/docker:ro \
  --publish=8080:8080 \
  --detach=true \
  --name=cadvisor \
  google/cadvisor:latest

Run the benchmarking container, and check the browser

Monitoring your containers

Limit the number of cores

docker run --cpuset-cpus="0,1" my-benchmark

Making changes to an image

Go to https://hub.docker.com/ and create an account

Run the image you want to modify

The ubuntu image does not have the "ping" functionality installed. Lets add it.

docker run -it ubuntu
  • Make the modifications
    apt update
    apt install inetutils-ping
    exit
  • Take notes of the container ID
    docker commit -a '[COMMIT AUTHOR]' -m 'ping function' [CONTAINER ID]  [USERNAME]/ubu_lecture:ping

Lets push the image

  • Log in. You need sudo for this.
    sudo docker login
  • Push the image (use sudo docker push (USERNAME)/(NAME:[TAG])
    sudo docker push juancabre/ubu_lecture:ping
  • Go to https://hub.docker.com/ and see your new image there

Repeat all the steps with a new function and a new tag

I will do it for vim

Lets pull the images

  • First lets remove the images
    sudo rmi juancabre/ubu_lecture:ping
  • And now we pull it
    docker pull juancabre/ubu_lecture:ping

Lets use :ping as a base image to create a new image with both functionalities

  • Run your image (juancabre/ubu_lecture:ping)
  • Install the new functionalities
  • Exit
  • Commit the changes WITHOUT A TAG
    docker commit -a 'Juan' -m 'ping function' a122a23fd3bb  juancabre/ubu_lecture
  • Push the changes WITHOUT A TAG
    sudo docker push juancabre/ubu_lecture
  • What does this do? The default tag is called :latest

Now I have 3 images with the same base image

  • ubu_lecture:ping (it can ping)
  • ubu_lecture:vim (it can edit text)
  • ubu_lecture:latest (it can ping and edit text)

Doing the same with a Dockerfile

Dockerfile
=============================================
# Base image
FROM ubuntu
# The maintainer
MAINTAINER Juan Cabrera
# The actual recipee
RUN apt update;\
    apt install -y vim
# Adding files
ADD https://gist.githubusercontent.com/anonymous/c966c0757f62b451bffa/raw/a15e10aa38d146bf50ee6c9d7fd851ce5bb91aee/gistfile1.txt /root/.vimrc
# The default command to run
CMD /bin/bash

Build it

docker build -t juancabre/dockerfile:vim_config .

Run it

docker run -it juancabre/dockerfile:vim_config

Managing Multiple Containers and Containers Dependencies

Setting Up a Wordpress

To set a word press, we need a data base and a wordpress server

We can use docker compose to have one file to rule them all

yml
version: '2'

services:
   db:
     image: mysql:5.7
     volumes:
       - ./db_volume:/var/lib/mysql
     restart: always
     environment:
       MYSQL_ROOT_PASSWORD: wordpress
       MYSQL_DATABASE: wordpress
       MYSQL_USER: wordpress
       MYSQL_PASSWORD: wordpress

   wordpress:
     depends_on:
       - db
     image: wordpress:latest
     ports:
       - "8000:80"
     restart: always
     environment:
       WORDPRESS_DB_HOST: db:3306
       WORDPRESS_DB_PASSWORD: wordpress

Setting Up a Wordpress

What do we have in that file?

  • Services:
    • db: Database
      • Volumes
      • restart policy
      • environment variables
    • wordpress
      • Dependencies
      • ports
  • Volumes

Let us run it!

docker-compose up -d

Try it in your browser

Docker Compose: A Load Balancer

Excercise inspired from: http://blog.hypriot.com/

Lets create a webserver that performs a "computationally intensive" task

Let us create a Hello-World Node.js web application based on Express.js

Make two new folders: load-balancing/ and load-balancing/src/

We need 2 files inside load-balancing/src/. Namely index.js and package.json

load-balancing/src/index.js

var express = require('express');
var os = require("os");

var app = express();
var hostname = os.hostname();

app.get('/', function (req, res) {
    // A CPU Intensive task:
    for (var i = 0; i < 1000000 ; i++) {
        Math.pow(i,i);
    }
    // Respond the request:
    res.send('<html><body>Hello from Node.js container '
        + hostname + '</body></html>');
});

app.listen(80);
console.log('Running on http://localhost');

Docker Compose: A Load Balancer

load-balancing/src/package.json

{
  "name": "node-hello-world",
  "private": true,
  "version": "0.0.1",
  "description": "Node.js Hello world app on docker",
  "author": "hypriot.com",
  "dependencies": {
    "express": "4.12.0"
  }
}

Docker Compose: A Load Balancer

Now let us make the Dockerfile of our application

load-balancing/Dockerfile

FROM node

ADD src/ /src
WORKDIR /src

RUN npm install

EXPOSE 80

CMD ["node", "index.js"]

Build and run a container

docker build . -t node-hello
docker run -p 45700:80 --name web -d node-hello

Docker Compose: A Load Balancer

Try it in your browser

Lets benchmark it:

  • See the CPU utilization with htop
  • Install apache2-utils (in your pc or in an Ubuntu container)
  • run: ab -n 10000 -c 100 http://localhost:45700/
  • How many requests-per-second can you support?

Docker Compose: A Load Balancer

load-balancing/docker-compose.yml

yml
weba:
    build: .
    expose:
        - 80
webb:
    build: .
    expose:
        - 80
webc:
    build: .
    expose:
        - 80
haproxy:
    image: haproxy
    volumes:
        - ./haproxy/haproxy.cfg:/usr/local/etc/haproxy/haproxy.cfg:ro
    links:
        - weba
        - webb
        - webc
    ports:
        - "80:80"
        - "70:70"
    expose:
        - "80"
        - "70"

Docker Compose: A Load Balancer

Haproxy config file

load-balancing/haproxy/haproxy.cfg

global
  log 127.0.0.1 local0
  log 127.0.0.1 local1 notice

defaults
  log global
  mode http
  option httplog
  option dontlognull
  timeout connect 5000
  timeout client 10000
  timeout server 10000

listen stats
  bind :70
  stats enable
  stats uri /

frontend balancer
  bind 0.0.0.0:80
  mode http
  default_backend aj_backends

backend aj_backends
  mode http
  option forwardfor
  # http-request set-header X-Forwarded-Port %[dst_port]
  balance roundrobin
  server weba weba:80 check
  server webb webb:80 check
  server webc webc:80 check
  # option httpchk OPTIONS * HTTP/1.1\r\nHost:\ localhost
  option httpchk GET /
  http-check expect status 200

Docker Compose: A Load Balancer

Let us run it!

docker-compose up -d

Try it in your browser!

Let us benchmark this one! :D