docker 101

Stefano Morandi | Cristian Pavan
2019-10-26

PNLUG, Linuxday 2019

Hello !

I’m Stefano and I’m DevOps @uomorando.

I’m Cristian and I’m Developer @tux_eithel.

We work at AKQA.

And we ❤️ GNU/Linux!

intro

problem

  • isolate process environment
  • abstract process/application from hardware
  • package all application needs

containers

long story

  • CP-40 [1968 circa]
  • chroot UNIX-like os [1982]
  • jail *BSD [2000]
  • LVS Linux [2001]
  • LXC Linux [2008]
  • docker [2013]

trust the tecnology not the product

docker

most common, but not the only one

docker

  • Docker Inc.
  • docker engine (CE, EE)

OCI

The Open Container Initiative is a lightweight, open governance structure for the express purpose of creating open industry standards around container formats and runtime.

newcomers

  • LXD (Linux)
  • Buildah / Podman / Skopeo (non root)
  • rkt (non root)

core technologies

namespace

isolate process

control groups

manage resource

reproducible dev setup/build

  • it works on my mac/pc
  • it NOT works on my server

DEV environment, not production

basic concepts

images

An image is a read-only template with instructions for creating a Docker container. Often, an image is based on another image, with some additional customization.

layers

001-docker-layers.png

containers

A container is a runnable instance of an image.

registries

A Docker registry stores Docker images.

docker hub

gitlab

live session

install docker linux

from docker.com

https://docs.docker.com/install/linux/docker-ce/ubuntu/

sudo apt-get remove docker docker-engine docker.io \
     containerd runc
sudo apt-get update
sudo apt-get install \
    apt-transport-https \
    ca-certificates \
    curl \
    gnupg-agent \
    software-properties-common

install docker linux

curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -

echo "deb [arch=amd64] https://download.docker.com/linux/ubuntu \
   $(lsb_release -cs) \
   stable" > /etc/apt/sources.list.d/docker.list
sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io
sudo usermod -aG docker <username>

install docker mac

from docker.com

https://hub.docker.com/editions/community/docker-ce-desktop-mac

via brew

brew cask install docker

install docker-compose

from https://docs.docker.com/compose/install/

sudo curl -L "https://github.com/docker/compose/releases/download/1.24.1/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose

basic docker commands

test

docker run hello-world

Hello from Docker!
This message shows that your installation appears to be working correctly.

...

docker pull

docker pull busybox
Using default tag: latest
latest: Pulling from library/busybox
7c9d20b9b6cd: Pulling fs layer
7c9d20b9b6cd: Download complete
7c9d20b9b6cd: Pull complete
Digest: sha256:fe301db49df08c384001ed752dff6d52b4305a73a7f608f21528048e8a08b51e
Status: Downloaded newer image for busybox:latest

docker pull

docker pull busybox
Using default tag: latest
latest: Pulling from library/busybox
Digest: sha256:fe301db49df08c384001ed752dff6d52b4305a73a7f608f21528048e8a08b51e
Status: Image is up to date for busybox:latest

no download

docker run

docker run busybox echo "ciao, mondo!"
ciao, mondo!

check docker status

  • docker info
    docker info | grep Version
    
    Server Version: 19.03.3
    Kernel Version: 4.15.0-65-generic
    
  • docker images
    docker image ls
    
    REPOSITORY                                    TAG                 IMAGE ID            CREATED             SIZE
    morandz/emacs-reveal                          latest              6e4b5827afc5        46 hours ago        759MB
    busybox                                       latest              19485c79a9bb        2 weeks ago         1.22MB
    registry.gitlab.com/oer/docker/emacs-reveal   3.3                 26559340ea1a        4 months ago        759MB
    

check docker status

  • docker container
    docker container ls
    
    CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
    
  • docker container
    docker container ls -a
    
    CONTAINER ID        IMAGE               COMMAND                 CREATED             STATUS                     PORTS               NAMES
    830947d3c078        busybox             "echo 'ciao, mondo!'"   3 minutes ago       Exited (0) 3 minutes ago                       jovial_mirzakhani
    

check docker status

  • docker container rm
    docker container rm jovial_mirzakhani
    
    jovial_mirzakhani
    
  • docker run
    docker run --rm busybox echo "ciao, mondo!"
    
    ciao, mondo!
    
    docker container ls -a
    
    CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
    

minimal webservice

run apache image

setup docker webserver for a static website

pull apache image

https://hub.docker.com/_/httpd

003-docker-hub-httpd.png

Official Images => DOCKER Official

pull apache image

docker pull httpd:2.4
2.4: Pulling from library/httpd
b8f262c62ec6: Pulling fs layer
...
60812fa1ab4c: Pull complete
Digest: sha256:39d7d9a3ab93c0ad68ee7ea237722ed1b0016ff6974d80581022a53ec1e58797
Status: Downloaded newer image for httpd:2.4

run it!

docker run --rm httpd:2.4

check

curl -I http://127.0.0.1
curl: (7) Failed to connect to 127.0.0.1 port 80: Connection refused

networking

docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
5f90a017d066        bridge              bridge              local
146c0e76bc9a        host                host                local
1acf502fece9        none                null                local

bridge

  • forward traffic between networks
  • containners connected to the same bridge can comunicate
  • provide automatic DNS resolution

host

  • no isolation from docker host
  • more performance

ports

docker run --rm -p80:80 httpd:2.4
curl -I http://127.0.0.1
HTTP/1.1 200 OK
Date: Thu, 19 Sep 2019 14:58:09 GMT
Server: Apache/2.4.41 (Unix)
Last-Modified: Mon, 11 Jun 2007 18:53:14 GMT
ETag: "2d-432a5e4a73a80"
Accept-Ranges: bytes
Content-Length: 45
Content-Type: text/html

storage system

publish local files

we need to know where the documentroot is

RTFM! :-D

httpd docs

https://hub.docker.com/_/httpd

/usr/local/apache2/htdocs/

bind mounts

mkdir -p docker-101/htdocs
cd docker-101
echo "Hello, World!" > htdocs/index.html
ls -l htdocs/
total 8
-rw-r--r--  1 stefano.morandi  wheel  14 Sep 19 17:21 index.html

bind mounts

docker run --rm -p80:80 -v `pwd`/htdocs:/usr/local/apache2/htdocs httpd:2.4
curl  http://localhost
Hello, World!

run as service

docker run -d --rm -p80:80 -v `pwd`/htdocs:/usr/local/apache2/htdocs httpd:2.4
docker container ls
CONTAINER ID        IMAGE               COMMAND              CREATED              STATUS              PORTS                NAMES
2692286141e0        httpd:2.4           "httpd-foreground"   About a minute ago   Up About a minute   0.0.0.0:80->80/tcp   practical_pascal

stop

docker container stop practical_pascal
practical_pascal
docker container ls -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES

logs

docker run -d --rm -p80:80 -v `pwd`/htdocs:/usr/local/apache2/htdocs httpd:2.4
docker container ls -a
CONTAINER ID        IMAGE               COMMAND              CREATED             STATUS              PORTS                NAMES
4e8c60f15f8c        httpd:2.4           "httpd-foreground"   59 seconds ago      Up 57 seconds       0.0.0.0:80->80/tcp   suspicious_banach
docker logs -f suspicious_banach

Dockerfile

build your own image

publish docker image with all html code

dockerfile

FROM: httpd:2.4
COPY ./htdocs/ /usr/local/apache2/htdocs/
docker build -t pnlug/apache:2.4 . -f Dockerfile
Sending build context to Docker daemon  10.24kB
Step 1/2 : FROM httpd:2.4
 ---> 66a97eeec7b8
Step 2/2 : COPY ./htdocs/ /usr/local/apache2/htdocs/
 ---> 9c7d1671e6b9
Successfully built 9c7d1671e6b9
Successfully tagged pnlug/apache:2.4

dockerfile

docker image ls
REPOSITORY                                    TAG                 IMAGE ID            CREATED             SIZE
pnlug/apache                                  2.4                 9c7d1671e6b9        13 seconds ago      154MB
morandz/emacs-reveal                          latest              5f712f35769b        2 minutes ago       1.03GB
httpd                                         2.4                 66a97eeec7b8        3 days ago          154MB
registry.gitlab.com/oer/docker/emacs-reveal   5.9.0               4dd7a8c319b3        5 days ago          1.03GB

dockerfile

docker run -d --rm -p80:80  pnlug/apache:2.4
2fa1a7bc7c64e75296b426029ba262154bde65c55541c6e5debf138cf1a28aea
curl http://localhost
ciao

nodejs

webserver with node

pull image

https://hub.docker.com/_/node/

docker pull node:10-alpine
10-alpine: Pulling from library/node
e7c96db7181b: Pulling fs layer
50958466d97a: Pulling fs layer
...
56174ae7ed1d: Pull complete
284842a36c0d: Pull complete
Digest: sha256:77c898d0da5e7bfb6e05c9a64de136ba4e03889a72f3c298e95df822a38f450d
Status: Downloaded newer image for node:10-alpine

hello.js

const http = require('http');

const hostname = '0.0.0.0';
const port = 3000;

const server = http.createServer((req, res) => {
  res.statusCode = 200;
  res.setHeader('Content-Type', 'text/plain');
  res.end('Hello World\n');
});

server.listen(port, hostname, () => {
  console.log(`Server running at http://${hostname}:${port}/`);
});

run it

docker run --rm -d -p 3000:3000 -v `pwd`:/app -w /app node:10-alpine hello.js
curl http://127.0.0.1:3000
Hello World

CMD vs Entrypoint

CMD

CMD instruction allows you to set a default command, which will be executed only when you run container without specifying a command.

Entrypoint

ENTRYPOINT command and parameters are not ignored when Docker container runs with command line parameters.

CMD vs Entrypoint

FROM alpine:3.9

CMD ["/bin/echo", "Hello, Linuxday"]
docker build -t pnlug/cmd-ent -f Dockerfile-cmd .
Sending build context to Docker daemon  10.75kB
Step 1/2 : FROM alpine:3.9
 ---> 055936d39205
Step 2/2 : CMD ["echo", "Hello, Linuxday"]
 ---> Running in 230fc0ce264f
Removing intermediate container 230fc0ce264f
 ---> 5086350c1695
Successfully built 5086350c1695
Successfully tagged pnlug/cmd-ent:latest

CMD vs Entrypoint

docker run --rm pnlug/cmd-ent
Hello, Linuxday
docker run --rm pnlug/cmd-ent echo "Ciao Mondo"
Ciao Mondo

CMD vs Entrypoint

FROM alpine:3.9

ENTRYPOINT ["echo", "Hello World!"]
docker build -t pnlug/cmd-ent -f Dockerfile-cmd .
Sending build context to Docker daemon  10.75kB
Step 1/2 : FROM alpine:3.9
 ---> 055936d39205
Step 2/2 : ENTRYPOINT ["/bin/echo", "Hello World!"]
 ---> Running in 151e663170bb
Removing intermediate container 151e663170bb
 ---> b189906342d6
Successfully built b189906342d6
Successfully tagged pnlug/cmd-ent:latest

CMD vs Entrypoint

docker run --rm pnlug/cmd-ent
Hello World!
docker run --rm pnlug/cmd-ent echo "Ciao Mondo"
Hello World! echo Ciao Mondo

CMD vs Entrypoint

FROM alpine:3.9

ENTRYPOINT ["echo", "Hello"]
CMD ["Linuxday"]
docker build -t pnlug/cmd-ent -f Dockerfile-cmd .
Sending build context to Docker daemon  10.75kB
Step 1/3 : FROM alpine:3.9
 ---> 055936d39205
Step 2/3 : ENTRYPOINT ["echo", "Hello"]
 ---> Running in 833e2c1a0dc9
Removing intermediate container 833e2c1a0dc9
 ---> 4b1114d48437
Step 3/3 : CMD ["Linuxday"]
 ---> Running in c38f57bb098a
Removing intermediate container c38f57bb098a
 ---> 1901b09dfad4
Successfully built 1901b09dfad4
Successfully tagged pnlug/cmd-ent:latest

CMD vs Entrypoint

docker run --rm pnlug/cmd-ent
Hello Linuxday
docker run --rm pnlug/cmd-ent "Mondo"
Hello Mondo

CMD vs Entrypoint

node:10-alpine dockerfile

ENTRYPOINT ["docker-entrypoint.sh"]

CMD [ "node" ]

CMD vs Entrypoint

docker run --rm -p 3000:3000 -v `pwd`:/app -w /app node:10-alpine --version
v10.16.3
docker run --rm -p 3000:3000 -v `pwd`:/app -w /app node:10-alpine npm --version
6.9.0

makefile

makefile rulez!

example

SHELL:=/bin/bash
LOCAL_DIR=$(shell pwd)

IMAGE_NODE=node:10-alpine

pull-image:
        @docker pull ${IMAGE_NODE}

run:
        @docker run --rm -d -p 3000:3000 -v ${LOCAL_DIR}:/app -w /app ${IMAGE_NODE} node hello.js

functions

in your .bashrc / .zshrc

node10(){
        docker run --rm -p 3000:3000 -v `pwd`:/app -w /app node:10-alpine $@
}

Exercise

Build a website with nodejs (version 12)

  • dockerfile
  • makefile

Orchestraton

problem

setup minimal a php page with mysql interaction

  • apache
  • php
  • mysql

needs

pull images

docker pull php:7.2-apache
docker pull mariadb:10.1
7.2-apache: Pulling from library/php
b8f262c62ec6: Already exists
a98660e7def6: Pulling fs layer
...
638370de0271: Pull complete
Digest: sha256:24299b59ee1f0bf81ed09fb295d206da52d2587ff8fd99945c4d798970b87e93
Status: Downloaded newer image for php:7.2-apache

10.1: Pulling from library/mariadb
5667fdb72017: Pulling fs layer
d83811f270d5: Pulling fs layer
...
3f8dcde4fb2b: Pull complete
336764d78786: Pull complete
8d4d93194de3: Pull complete
Digest: sha256:82889ab2b6a04d253a0c2285a39ae14afbf4f031b09e00250830c6f72e542d59
Status: Downloaded newer image for mariadb:10.1

mysql container

MySQL needs some variables:

MYSQL_ROOT_PASSWORD
MYSQL_DATABASE
MYSQL_USER
MYSQL_PASSWORD

docker volumes

Volumes are the preferred mechanism for persisting data generated by and used by Docker containers. While bind mounts are dependent on the directory structure of the host machine, volumes are completely managed by Docker

mysql volume

docker volume create mysql-test

start mysql container

export MYSQL_ROOT_PASSWORD=passwd
export MYSQL_DATABASE=db

docker run --name db --rm -d -v mysql-test:/var/lib/mysql \
    -eMYSQL_ROOT_PASSWORD=$MYSQL_ROOT_PASSWORD \
    -eMYSQL_DATABASE=$MYSQL_DATABASE mariadb:10.1
cba671f87cb880d0c3181021693c3d8e926d30f039cf146c97064c4a0685f35b

start apache container

docker run --name apache --rm -d -p80:80 -v `pwd`/htdocs:/var/www/html/ --link db php:7.2-apache
f2fb78a71c17abc2a5647b8e08951af9899f08f8b36ef73f22d29901015eabf3

exec

docker exec -it apache /bin/bash

apt update && apt install iputils-ping
ping -c1 db
exit

php script

// htdocs/index.php
<?php
$dbhost = "db";
$dbuser = "root";
$dbpass = "password";
$dbname = "test";

try {
    $conn = new PDO("mysql:host=$dbhost;dbname=$dbname", $dbuser, $dbpass);
    // set the PDO error mode to exception
    $conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    echo "Connected successfully";
    }
catch(PDOException $e) {
    echo "Connection failed: " . $e->getMessage();
}
?>

WTF

curl http://localhost/index.php
Connection failed: could not find driver

new dockerfile

Dockerfile-php

FROM php:7.2-apache

RUN apt-get update
RUN docker-php-ext-install -j "$(nproc)" \
    pdo pdo_mysql

build new image

docker stop apache
docker build . -f Dockerfile-php -t pnlug/php:7.2-apache
Sending build context to Docker daemon  119.8MB
Step 1/3 : FROM php:7.2-apache
 ---> 2aefc00193b5
Step 2/3 : RUN apt-get update
 ---> Running in b8507ac92ded
Get:1 http://security-cdn.debian.org/debian-security buster/updates InRelease [39.1 kB]
...
Step 3/3 : RUN docker-php-ext-install -j "$(nproc)"     pdo pdo_mysql
 ---> Running in ae875eb770cd
Configuring for:
PHP Api Version:         20170718
...

run new image

docker run --name apache --rm -d -p80:80 -v `pwd`/htdocs:/var/www/html/ --link db pnlug/php:7.2-apache
90c9694a039ee7ec7e3f2e60143a907a3a8108501d74b587847a23db0703014c

test new image

curl http://localhost/index.php
Connected successfully

cleanup

docker stop apache
docker stop db

docker container ls -a
apache
db
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES

cleanup

docker image rm pnlug/php:7.2-apache
docker image rm mariadb:10.1
Untagged: pnlug/php:7.2-apache
Deleted: sha256:601a713f0b2b75ca4198722eee6213c8536e871a892796eb0407fe2adbf0713a
...
Deleted: sha256:11b2e249c2e0c0be9a9dfd5545303c7d4384dd8f4ff1b936ed9391db03db46ba
Untagged: mariadb:10.1
Untagged: mariadb@sha256:92e3a5650ed15df2455fa3aa7e2a5370b7c1ba0fdaba33aa2eeb218e6a30d1d2
...
Deleted: sha256:b9997ded97a1c277d55be0d803cf76ee6e7b2e8235d610de0020a7c84c837b93
Deleted: sha256:a090697502b8d19fbc83afb24d8fb59b01e48bf87763a00ca55cfff42423ad36

docker-compose

docker-compose

version: '3.1'

services:
  apache:
    container_name: apache
    build:
      context: .
      dockerfile: Dockerfile-php
    image: pnlug/php:7.2-apache
    volumes:
      - ./htdocs/:/var/www/html/
    depends_on:
      - db
    ports:
      - 80:80

  db:
    container_name: db
    image: mariadb:10.1
    environment:
      MYSQL_DATABASE: test
      MYSQL_USER: test
      MYSQL_PASSWORD: test
      MYSQL_RANDOM_ROOT_PASSWORD: '1'
    volumes:
      - mysql-test:/var/lib/mysql
volumes:
  mysql-test

build

docker-compose build

up

docker-compose up

down

docker-compose down
Stopping apache ... done
Stopping db     ... done
Removing apache ... done
Removing db     ... done
Removing network examples_default

Exercise

Build a Wordpress project

  • docker images
  • docker compose
  • makefile

License Information

docker 101” © 2019 di Stefano Morandi | Cristian Pavan

pubblicato con licenza Creative Commons license CC BY-SA 4.0.