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-11gapt-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_imageCommands
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_wozniakDocker 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 \
    logstashBuild 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_imagebuild 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.jsSkyDns
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É
Docker
- 3,134