Docker

Virtualisation

Why ?

  • Isolated applications
  • Reduce hardware vendor lock-in
  • Same versions from development to production
  • Faster server provisioning
  • Reduce the data center footprint

Act of creating a virtual (rather than actual) version of something, including but not limited to a virtual computer hardware platform, operating system (OS), storage device, or computer network resources.

Type 1

Type 2

cGroups

cGroups (Control groups)

  • Linux kernel feature
  • Implemented by Paul Menage and Rohit Seth (Google) 2006
  • Isolation
  • Resource limitation
  • Prioritization
  • Accounting
  • Control

Containers

Avantages

  • Fast boot (~ 300ms)
  • Lightweight footprint and minimal overhead 
  • Fast FileSystem IO (direct access to File)
  • Container ready to use

DrawBack

  • Immature technology
  • Supervision (backups, logs, etc...)
  • Network & dns
  • Shared files Permissions
  • Linux only

Containers are not virtual machines

  • Stateless
  • Only one process (best practices)
  • Random IP
  • No emulation (cpu, memory, disk)

Docker

Docker

  • Initial commit 2013-01-18
  • v1.0 => 2014-06-09
  • Server/Client
  • Image/Container
  • Features:
    • Portable deployment across machines
    • Application-centric
    • Automatic build
    • Versioning
    • Component re-use
    • Sharing
    • Tool ecosystem

AUFS

Another Union File System

root@host:/# ps fx
PID COMMAND
208 bash
154 /usr/bin/docker -d -p /var/run/docker.pid

root@host:/# doker run -ti ubuntu sh




root@host:/# ps fx
PID COMMAND
208 bash
154 /usr/bin/docker -d -p /var/run/docker.pid
263  \_ sh
256 docker run --rm -ti ubuntu sh




root@host:/# ps fx
PID COMMAND
208 bash
154 /usr/bin/docker -d -p /var/run/docker.pid
263  \_ sh
275      \_ sleep 10
256 docker run --rm -ti ubuntu sh







# ps fx
PID COMMAND
  1 sh






# sleep 10 & ps fx
PID COMMAND
  1 sh
 10 sleep 10

Host

Container

Metal

Container

$ docker run \
    -d --name oracle \
    wnameless/oracle-xe-11g
apt-get install gcc make binutils libmotif4 lesstif2 rpm libaio1 libdb4.6 libstdc++5

ln -s /usr/bin/awk /bin/awk
ln -s /usr/bin/rpm /bin/rpm
ln -s /usr/bin/basename /bin/basename
ln -s /etc /etc/rc.d

groupadd oinstall
groupadd dba
useradd -m -g oinstall -G dba -p passwd -s /bin/bash -d /home/$ oracle oracle
passwd oracle   <-- change password!

mkdir /home/u01
ln -s /home/u01 /
mkdir /u02/oradata   <-- assuming it's already mounted
chown -R oracle.oinstall /home/u01 /u02/
chmod -R 775 /home/u01 /u02/

chown -R oracle.oinstall /opt/database

vim /etc/sysctl.conf
    kernel.sem = 250 32000 100 128
    kernel.shmmax = 2147483648
    net.ipv4.ip_local_port_range = 9000 65000
    net.core.rmem_default = 262144
    net.core.rmem_max = 4194304
    net.core.wmem_default = 262144
    net.core.wmem_max = 1048576
    fs.aio-max-nr = 1048576
    fs.file-max = 6815744

vm/hugetlb_shm_group = dba_group_gid
sysctl -p

vim /etc/security/limits.conf
    *               soft    nproc   2047
    *               hard    nproc   16384
    *               soft    nofile  1024
    *               hard    nofile  65536

/etc/pam.d/su
/etc/pam.d/login
/etc/pam.d/sshd

vim /etc/profile
    if [ $USER = "oracle" ]; then
          if [ $SHELL = "/bin/ksh" ]; then
                ulimit -p 16384
                ulimit -n 65536
          else
                ulimit -u 16384 -n 65536
          fi
    fi

vim /home/oracle/.profile
    ORACLE_BASE=/u01/app/oracle
    ORACLE_SID=instancename
    export ORACLE_BASE ORACLE_SID
    unset ORACLE_HOME
    unset TNS_ADMIN

apt-get install xserver-xorg-video-dummy vnc4server x11-xserver-utils xterm wm2
x-terminal-emulator -geometry 80x24+10+10 -ls -title "$VNCDESKTOP Desktop" &
wm2 &

vim /home/oracle/.profile
    ORACLE_BASE=/u01/app/oracle
    ORACLE_SID=instancename
    ORATAB=/etc/oratab
    export PATH=$PATH:/u01/app/oracle/product/11.2.0/dbhome_1/bin/
    export ORACLE_BASE ORACLE_SID ORATAB
    export ORACLE_HOME=$ORACLE_BASE/product/11.2.0/dbhome_1
    unset TNS_ADMIN

vim /etc/init.d/oracle
    #!/bin/bash
    #
    # Run-level Startup script for the Oracle Instance and Listener
    #
    # chkconfig: 345 91 19
    # description: Startup/Shutdown Oracle listener and instance

    ### BEGIN INIT INFO
    # Provides:          oracle
    # Required-Start:    $remote_fs $syslog $all
    # Required-Stop:
    # Default-Start:     2 3 4 5
    # Default-Stop:      0 1 6
    # Short-Description: Oracle database server
    # Description:       Oracle database server
    ### END INIT INFO

    ORACLE_HOME="/u01/app/oracle/product/11.2.0/dbhome_1"
    ORACLE_OWNR="oracle"

    # if the executables do not exist -- display error

    if [ ! -f $ORACLE_HOME/bin/dbstart -o ! -d $ORACLE_HOME ]
    then
            echo "Oracle startup: cannot start"
            exit 1
    fi

    # depending on parameter -- startup, shutdown, restart
    # of the instance and listener or usage display

    case "$1" in
        start)
            # Oracle listener and instance startup
            echo -n "Starting Oracle: "
            su - $ORACLE_OWNR -c "$ORACLE_HOME/bin/lsnrctl start"
            su - $ORACLE_OWNR -c "$ORACLE_HOME/bin/dbstart $ORACLE_HOME"
            touch /var/lock/oracle
            echo "OK"
            ;;
        stop)
            # Oracle listener and instance shutdown
            echo -n "Shutdown Oracle: "
            su - $ORACLE_OWNR -c "$ORACLE_HOME/bin/lsnrctl stop"
            su - $ORACLE_OWNR -c "$ORACLE_HOME/bin/dbshut $ORACLE_HOME"
            rm -f /var/lock/oracle
            echo "OK"
            ;;
        reload|restart)
            $0 stop
            $0 start
            ;;
        *)  
            echo "Usage: $0 start|stop|restart|reload"
            exit 1
    esac
    exit 0

update-rc.d oracle defaults

find /usr/lib -name libpthread_nonshared.a
ln -s /usr/lib/x86_64-linux-gnu/libpthread_nonshared.a /usr/lib64/libpthread_nonshared.a
ln -s /usr/lib/x86_64-linux-gnu/libc_nonshared.a /usr/lib64/
ln -s /lib/x86_64-linux-gnu/libgcc_s.so.1 /lib64/
ln -s /usr/lib/x86_64-linux-gnu/libstdc++.so.6 /usr/lib64/

cd $ORACLE_HOME/sysman/lib
make -f ins_emagent.mk "agent"

Try an App

$ docker run \
    --name sentry-app \
    --link sentry-db:postgres \
    sentry


$ docker run -p 5000:5000 registry

$ docker run -d \
    -v /var/run/docker.sock:/var/run/docker.sock \
    tobegit3hub/seagull

$ docker run -t \
    -v /usr/local/bin/:/tmp/bin \
    php:5.6 php /tmp/bin/melody help

$ docker run --rm --name GITLAB \
    --link gitlab_db:mysql \
    --link gitlab_redis:redisio \
    -e "DB_USER=root" -e "DB_PASS=root" -e "DB_NAME=gitlab"
    centurylink/gitlab

Mac Os / windows

Problems

  • Permissions on FS (cache, logs)
    • use volume container
  • Performance
    • use NFS
  • DNS
    • port forwarding (1 project  = 1 port)
    • nameserver + routing

Repository

Repositories

$ docker run my_local_image

$ docker run php # (a official public image)

$ docker run my_user/my_image

$ docker run my_private_repository:8000/my_image

Commands

Docker run

Run a command in a new container

$ docker run ubuntu lsb_release -r
Release:	14.04

$ docker run -t -i --rm ubuntu bash
root@d0f33c53c59a:/# ps faux
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  0.5  0.0  18184  3292 ?        Ss   14:01   0:00 bash
root        16  0.0  0.0  15572  2180 ?        R+   14:01   0:00 ps faux

$ docker run php:5.4 php --version
PHP 5.4.36 (cli) (built: Jan 22 2015 01:43:04) 
Copyright (c) 1997-2014 The PHP Group
Zend Engine v2.4.0, Copyright (c) 1998-2014 Zend Technologies

$ docker run -d --name my_app php:5.4-apache
f4a472e2817a56b4e12a1432505f531c52c6b9a616270abd5a227d9d642a0f2e

$ docker run -e SYMFONY_ENV=prod ubuntu env
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOSTNAME=49db3488e635
SYMFONY_ENV=prod
HOME=/root

Docker ps

List containers

$ docker ps
CONTAINER ID IMAGE        COMMAND CREATED        STATUS        NAMES
4c01db0b339c ubuntu:12.04 bash    17 seconds ago Up 16 seconds webapp

$ docker ps -a
CONTAINER ID IMAGE         COMMAND CREATED        STATUS        NAMES
4c01db0b339c ubuntu:12.04  bash    17 seconds ago Up 16 seconds webapp
b715035816d7 ubuntu:12.04          4 minutes ago  Exited (0)    sharp_wozniak

Docker logs

Fetch the logs of a container

$ docker run -d --name test_logs php:5.4-apache
b3f0f20ad6bec53fbf6a841bf5dd6abd7d132e95de36b53b000e61361041d240

$ docker logs test_logs
AH00558: apache2: Could not reliably determine the server's fully qualified domain name, using 172.17.0.61. Set the 'ServerName' directive globally to suppress this message
AH00558: apache2: Could not reliably determine the server's fully qualified domain name, using 172.17.0.61. Set the 'ServerName' directive globally to suppress this message
[Fri Jan 23 14:26:59.138701 2015] [mpm_prefork:notice] [pid 1] AH00163: Apache/2.4.10 (Debian) PHP/5.4.36 configured -- resuming normal operations
[Fri Jan 23 14:26:59.138728 2015] [core:notice] [pid 1] AH00094: Command line: 'apache2 -D FOREGROUND'

Docker exec

Run a command in a running container

$ docker run -d --name test_exec php:5.6-apache
b3f0f20ad6bec53fbf6a841bf5dd6abd7d132e95de36b53b000e61361041d240

$ docker exec test_exec tail -f /var/log/apache2/error.log
[...]

$ docker exec -ti test_exec bash
root@5844da00d620:/var/www/html# tail -f /var/log/apache2/error.log
[...]

root@5844da00d620:/var/www/html# ps faux
USER       PID %CPU %MEM    VSZ   RSS STAT START   TIME COMMAND
root        28  0.0  0.0  20212  3004 S    14:29   0:00 bash
root        33  0.0  0.0  17488  2128 R+   14:30   0:00  \_ ps faux
root         1  0.0  0.2 161084 17548 Ss   14:29   0:00 apache2 -DFOREGROUND
www-data     7  0.0  0.0 161108  6624 S    14:29   0:00 apache2 -DFOREGROUND
www-data     8  0.0  0.0 161108  6624 S    14:29   0:00 apache2 -DFOREGROUND
www-data     9  0.0  0.0 161108  6624 S    14:29   0:00 apache2 -DFOREGROUND
www-data    10  0.0  0.0 161108  6624 S    14:29   0:00 apache2 -DFOREGROUND
www-data    11  0.0  0.0 161108  6624 S    14:29   0:00 apache2 -DFOREGROUND

Docker pull

Pull an image or a repository from the registry

$ docker pull php
Pulling repository php
1811729731ef: Download complete 
511136ea3c5a: Download complete 
bce696e097dc: Download complete 
58052b122b60: Download complete 
0e7f8f5c5b8d: Download complete 
04492ae680ed: Download complete 
6eaa8423e2ff: Download complete 
7328b592049c: Download complete 
3d67d10cb968: Download complete 
24ae7550fca5: Download complete 
d3e82086ee0b: Download complete 
711d800d93a0: Download complete 
Status: Image is up to date for php:latest

$ docker pull ubuntu:trusty
Pulling repository ubuntu
b39b81afc8ca: Download complete 
511136ea3c5a: Download complete 
53f858aaaf03: Download complete 
837339b91538: Download complete 
615c102e2290: Download complete 
Status: Downloaded newer image for ubuntu:trusty

Docker build

    Build a new image from the source code

$ docker build .
Uploading context 18.829 MB
Uploading context
Step 0 : FROM busybox
 ---> 769b9341d937
Step 1 : CMD echo Hello world
 ---> Using cache
 ---> 99cc1ad10469
Successfully built 99cc1ad10469

$ echo ".git" > .dockerignore
$ sudo docker build .
Uploading context  6.76 MB
Uploading context
Step 0 : FROM busybox
 ---> 769b9341d937
Step 1 : CMD echo Hello world
 ---> Using cache
 ---> 99cc1ad10469
Successfully built 99cc1ad10469

Docker commit

Create a new image from a container's changes

$ docker run --name build_test -ti ubuntu bash
root@521856f3e8b1:/# touch foo
root@521856f3e8b1:/# exit

$ docker commit build_test ubuntu_with_foo
8dd67ceb1967337c0de348a55ad5229918f10eba2fb1d3a72244909dcf85d8a7

$ docker run --rm ubuntu_with_foo ls -al foo
-rw-r--r-- 1 root root 0 Jan 23 13:57 foo

Advanced

Links

$ docker run -d --name db mysql

$ docker run -d --link db:mysql_host --name app php:5.6-apache

$ docker run --link db:mysql_host ubuntu env
MYSQL_HOST_PORT=tcp://172.17.0.77:3306
MYSQL_HOST_PORT_3306_TCP=tcp://172.17.0.77:3306
MYSQL_HOST_PORT_3306_TCP_ADDR=172.17.0.77
MYSQL_HOST_PORT_3306_TCP_PORT=3306
MYSQL_HOST_PORT_3306_TCP_PROTO=tcp

$ docker run \
    --link db:mysql_host \
    ubuntu ping mysql_host -c 1
PING mysql_host (172.17.0.77): 56 data bytes
64 bytes from 172.17.0.77: icmp_seq=0 ttl=64 time=0.076 ms
--- mysql_host ping statistics ---
1 packets transmitted, 1 packets received, 0% packet loss
round-trip min/avg/max/stddev = 0.076/0.076/0.076/0.000 ms

$ docker run \
    --link db:mysql_host \
    mysql mysqldump -u root -h mysql_host --all-database

Port

$ docker run -d \
    --port 8000:80 \
    php:5.6-apache

Volumes

$ docker run -d \
    -v /var/lib/mysql \
    --name dbdata \
    mysql echo Data-only container for mysql

$ docker run -d \
    --volumes-from dbdata \
    --name db \
    mysql

$ docker run \
    --volumes-from dbdata \
    -v $(pwd):/backup \
    ubuntu tar czf /backup/backup.tgz /var/lib/mysql


$ docker run -d \
    --volumes-from app_server \
    --name logstash \
    logstash

Build images

Dockerfile

# Nginx
#
# VERSION               0.0.1

FROM      ubuntu
MAINTAINER Victor Vieux <victor@docker.com>

RUN apt-get qq update && \
    apt-get install -y inotify-tools nginx apache2 openssh-server

# Firefox over VNC
#
# VERSION               0.3

FROM ubuntu

# Install vnc, xvfb in order to create a 'fake' display and firefox
RUN apt-get update && apt-get install -y x11vnc xvfb firefox
RUN mkdir ~/.vnc
# Setup a password
RUN x11vnc -storepasswd 1234 ~/.vnc/passwd
# Autostart firefox (might not be the best way, but it does the trick)
RUN bash -c 'echo "firefox" >> /.bashrc'

EXPOSE 5900
CMD    ["x11vnc", "-forever", "-usepw", "-create"]

Docker build

$ docker build -t my_image .
Sending build context to Docker daemon  2.56 kB
Sending build context to Docker daemon 
Step 0 : FROM ubuntu
 ---> b39b81afc8ca
Step 1 : MAINTAINER Victor Vieux <victor@docker.com>
 ---> Running in 701da73cbfdb
 ---> 3161b6d9ed0e
Removing intermediate container 701da73cbfdb
Step 2 : RUN apt-get update && apt-get install -y inotify-tools nginx apache2 openssh-server
 ---> Running in 3baade8e3aff
Ign http://archive.ubuntu.com trusty InRelease
Hit http://archive.ubuntu.com trusty Release.gpg
Get:1 http://archive.ubuntu.com trusty-updates Release.gpg [933 B]
[...]
Running hooks in /etc/ca-certificates/update.d....done.
Processing triggers for sgml-base (1.26+nmu4ubuntu1) ...
 ---> 22c7bd6f9efd
Removing intermediate container 3baade8e3aff
Successfully built 22c7bd6f9efd


$ docker tag my_image my_image:demoA

$ docker run my_image

build use cache

$ docker build -t my_image .
Sending build context to Docker daemon  2.56 kB
Sending build context to Docker daemon 
Step 0 : FROM ubuntu
 ---> b39b81afc8ca
Step 1 : MAINTAINER Victor Vieux <victor@docker.com>
 ---> Using cache
 ---> 3161b6d9ed0e
Step 2 : RUN apt-get update && apt-get install -y inotify-tools nginx apache2 openssh-server
 ---> Using cache
 ---> 22c7bd6f9efd
Successfully built 22c7bd6f9efd

each step is a layer

Mailcacher

FROM debian:latest
MAINTAINER Jérémy Derussé "jeremy@derusse.com"

# Install requirements
RUN \
  apt-get update -qq && \
  apt-get install --no-install-recommends -y ruby sqlite3 && \
  rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*

# Install build tools, then install mailcatcher, the remove build tools
RUN \
  apt-get update -qq && \
  apt-get install --no-install-recommends -y build-essential ruby-dev libsqlite3-dev  && \

  gem install mailcatcher --no-ri --no-rdoc && \

  apt-get remove --purge -y build-essential ruby-dev libsqlite3-dev && \
  apt-get autoclean && apt-get clean && \

  rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*


EXPOSE 80
EXPOSE 25

CMD ["--smtp-port", "25", "--http-port", "80", "--ip", "0.0.0.0", "-f"]
ENTRYPOINT ["mailcatcher"]

DNS

$ NAMESERVER=`nslookup -query=ns google.com | awk '/Server:/{split($0,A,":"); print A[2]}' | tr -d ' ' | tr -d '\t'`

$ docker run -d --name skydns  \
    -p 172.17.42.1:53:53/udp \
    crosbymichael/skydns -nameserver $NAMESERVER:53 -domain docker

$ docker run -d --name skydock \
    -v /var/run/docker.sock:/docker.sock 
    skydock \
        -ttl 3600 -environment dev -s /docker.sock -domain docker \
        -name skydns -plugins /plugins/containerEnv.js

SkyDns

FIG

docker-composer

composer up

fig.yml

web:
  image: php:5.6-apache
  links:
    - db:mysql
  volumes:
   - .:/var/www/html
  ports:
   - "80:80"

db:
  image: postgres
$ fig up -d
Creating project_db_1...
Creating project_web_1...

$ fig stop web
Stopping project_web_1...

$ fig start web
Starting project_web_1...

$ fig scale web=3
Starting project_web_2...
Starting project_web_3...

$ fig ps
        Name             Command              State     Ports 
-------------- ----------------------------------------------
project_web_1  /usr/local/bin/run              Up    80/tcp    
project_web_2  /usr/local/bin/run              Up    80/tcp    
project_web_3  /usr/local/bin/run              Up    80/tcp    
project_db_1   /usr/sbin/mysqld --skip-na ...  Up    3306/tcp  

$ logs web
Attaching to project_web_3, project_web_2, project_web_1
app_2 | RUN apache
app_1 | RUN apache
app_1 | RUN apache
app_3 | RUN apache

Docker

By Jérémy DERUSSÉ