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É
Docker
- 2,997