09/2016

Jonathan VUILLEMIN

Docker (practical basics)

Text

What is Docker ?

Wikipedia Definition

Docker is an open-source project that automates the deployment of applications inside software containers, by providing an additional layer of abstraction and automation of operating-system-level virtualization on Linux.

... nice, thanks, and ?

Linux Containers

Docker is based on LXC (Linux Containers) which allows

it to isolate containers from each other.

 

LXC use mainly two Linux Kernel features to acheave it :

 

  • Namespaces (Isolation of resources)
  • Cgroups (Isolation of resource usage, as CPU/RAM)

Docker World

Docker can be split in multiple different parts :

 

  • Docker Engine
  • Docker Hub
  • Docker Company

How to use Docker ?

Docker can be used natively on Linux (and only Linux, boom) by the simple bash command (here, ubuntu):

$ sudo apt-get install docker-engine

Docker installation requires at least 3.13 Linux Kernel.

How to use Docker ?

Docker uses boot2docker to create a VM with a Tiny Core Linux version including Docker.

How to use Docker ?

Docker now offers Docker Toolbox which contains

Docker-machine.

 

It also allows to create multiple docker machines.

Container VS VM

Container VS Image

Image

An image is an inert snapshot of a container.

 

When runned (with a docker run command) it becomes a container.

 

As images can be quite heavy they are designed to be composed of layers of other images which allows to minimize an image weight, and those layers can be reused between images.

 

Images are stored (mainly) on Docker Hub.

Container VS Image

Image

An image is built from a Dockerfile. A file describing how the image is supposed to behave, what it extends from, ...

 

docker images command lists all local images :

➜  image2 git:(master) ✗ docker images
REPOSITORY                    TAG                 IMAGE ID            CREATED             SIZE
ekkinox/image2                latest              99575a3e62ce        19 minutes ago      126.6 MB
ekkinox/image1                latest              e4d90038788c        32 minutes ago      126.6 MB
doclersfbasicworkshop_nginx   latest              e40e5460d6cb        18 hours ago        183.2 MB
doclersfbasicworkshop_php     latest              29c570fb5d03        18 hours ago        392.3 MB
tianon/true                   latest              2cf9735a9162        19 hours ago        125 B
nazarpc/phpmyadmin            latest              5e14ef86056e        44 hours ago        433.5 MB
php                           5.6-fpm             c90bf43470d1        46 hours ago        362.7 MB
phpmyadmin/phpmyadmin         latest              de9568a72415        2 days ago          116.2 MB
mysql                         5.6                 72bb9d97fb75        11 days ago         328.9 MB
nginx                         stable              5c9792e3619e        2 weeks ago         182.8 MB
ubuntu                        16.04               bd3d4369aebc        3 weeks ago         126.6 MB
ubuntu                        14.04               4a725d3b3b1c        3 weeks ago         188 MB

Container VS Image

Container

Programmatically speaking, if an image is a class, then a container would be an instance of this class.

 

So, you can launch multiple containers for the same image (multiple instances).

docker ps command lists all running containers :

➜  image2 git:(master) ✗ docker ps
CONTAINER ID        IMAGE                         COMMAND                  CREATED             STATUS              PORTS                         NAMES
396fa752515e        ekkinox/image2                "/bin/bash"              20 minutes ago      Up 20 minutes                                     high_panini
aa60196275a3        ekkinox/image1                "/bin/bash"              29 minutes ago      Up 29 minutes                                     reverent_fermi
c7f259822acb        ubuntu:16.04                  "/bin/bash"              36 minutes ago      Up 36 minutes                                     awesome_elion
70ef83fa7097        ubuntu:14.04                  "/bin/bash"              37 minutes ago      Up 37 minutes                                     silly_mclean
698cd8bd50fe        nazarpc/phpmyadmin            "/home/entrypoint.sh"    17 hours ago        Up 17 hours         0.0.0.0:1234->80/tcp          doclersfbasicworkshop_phpmyadmin_1
4c5dd41b5a55        doclersfbasicworkshop_nginx   "nginx -g 'daemon off"   18 hours ago        Up 18 hours         0.0.0.0:80->80/tcp, 443/tcp   doclersfbasicworkshop_nginx_1
e58a4384d27a        mysql:5.6                     "docker-entrypoint.sh"   18 hours ago        Up 18 hours         0.0.0.0:3306->3306/tcp        doclersfbasicworkshop_db_1
faf8aba5cd3c        doclersfbasicworkshop_php     "php-fpm"                18 hours ago        Up 18 hours         9000/tcp                      doclersfbasicworkshop_php_1

Build our first container

$ docker run -itd ubuntu:16.04

To create a container from the official ubuntu image :

To enter into a container with your terminal (logged as root):

$ docker exec -it CONTAINERID bash

To check your running containers and their ids :

$ docker ps

Turn our container in an image

As said before : 

 An image is a snapshot of a container

Let's take a snapshot of our container :

$ docker commit -m "First commit" CONTAINERID ekkinox/image1

Build a container

You can now create as many container from this image as you want :

$ docker run -dit ekkinox/image1

-d : Daemonized

-it : Allocate TTY

Image name

Dockerfile

This approach is nice but as developers

we highly prefer working in files than terminals, right ?

 

That's why Docker uses Dockerfiles.

Dockerfile

A Dockerfile is a translation of what the image will be :

FROM ubuntu:16.04

MAINTAINER Jonathan VUILLEMIN <ekkinox@gmail.com>

RUN mkdir -p /home/ekkinox

To build an image from this Dockerfile :

$ docker build -t ekkinox/image2 .

Container

To create a container from our new image :

$ docker run -dit ekkinox/image2

-d : Daemonized

-it : Allocate TTY

Image name

More serious things:

Nginx , Php-fpm & MySQL

Nginx 

Dockerfile

FROM debian:jessie

MAINTAINER NGINX Docker Maintainers "docker-maint@nginx.com"

ENV NGINX_VERSION 1.11.4-1~jessie

RUN apt-key adv --keyserver hkp://pgp.mit.edu:80 --recv-keys 573BFD6B3D8FBC641079A6ABABF5BD827BD9BF62 \
	&& echo "deb http://nginx.org/packages/mainline/debian/ jessie nginx" >> /etc/apt/sources.list \
	&& apt-get update \
	&& apt-get install --no-install-recommends --no-install-suggests -y \
						ca-certificates \
						nginx=${NGINX_VERSION} \
						nginx-module-xslt \
						nginx-module-geoip \
						nginx-module-image-filter \
						nginx-module-perl \
						nginx-module-njs \
						gettext-base \
	&& rm -rf /var/lib/apt/lists/*

# forward request and error logs to docker log collector
RUN ln -sf /dev/stdout /var/log/nginx/access.log \
	&& ln -sf /dev/stderr /var/log/nginx/error.log

EXPOSE 80 443

CMD ["nginx", "-g", "daemon off;"]

Run a nginx container

$ docker run -dit nginx

-d : Daemonized

-it : Allocate TTY

Image name

Let's check it...

To know the IP of Docker Host :

D.M. Name

D.M. IP

Or, use 

$ docker inspect CONTAINERID

Browse our container

Manage ports

To open a port on the Container :

$ docker run -dit -p 8080:80 CONTAINERID

For our nginx container, ports already exposed due to:

EXPOSE 80 443

Php-fpm

 

#
# NOTE: THIS DOCKERFILE IS GENERATED VIA "update.sh"
#
# PLEASE DO NOT EDIT IT DIRECTLY.
#

FROM debian:jessie

# persistent / runtime deps
ENV PHPIZE_DEPS \
		autoconf \
		file \
		g++ \
		gcc \
		libc-dev \
		make \
		pkg-config \
		re2c
RUN apt-get update && apt-get install -y \
		$PHPIZE_DEPS \
		ca-certificates \
		curl \
		libedit2 \
		libsqlite3-0 \
		libxml2 \
		xz-utils \
	--no-install-recommends && rm -r /var/lib/apt/lists/*

ENV PHP_INI_DIR /usr/local/etc/php
RUN mkdir -p $PHP_INI_DIR/conf.d

##<autogenerated>##
ENV PHP_EXTRA_CONFIGURE_ARGS --enable-fpm --with-fpm-user=www-data --with-fpm-group=www-data
##</autogenerated>##

ENV GPG_KEYS 0BD78B5F97500D450838F95DFE857D9A90D90EC1 6E4F6AB321FDC07F2C332E3AC2BF0BC433CFC8B3

ENV PHP_VERSION 5.6.26
ENV PHP_FILENAME php-5.6.26.tar.xz
ENV PHP_SHA256 203a854f0f243cb2810d1c832bc871ff133eccdf1ff69d32846f93bc1bef58a8

RUN set -xe \
	&& cd /usr/src \
	&& curl -fSL "https://secure.php.net/get/$PHP_FILENAME/from/this/mirror" -o php.tar.xz \
	&& echo "$PHP_SHA256 *php.tar.xz" | sha256sum -c - \
	&& curl -fSL "https://secure.php.net/get/$PHP_FILENAME.asc/from/this/mirror" -o php.tar.xz.asc \
	&& export GNUPGHOME="$(mktemp -d)" \
	&& for key in $GPG_KEYS; do \
		gpg --keyserver ha.pool.sks-keyservers.net --recv-keys "$key"; \
	done \
	&& gpg --batch --verify php.tar.xz.asc php.tar.xz \
	&& rm -r "$GNUPGHOME"

COPY docker-php-source /usr/local/bin/

RUN set -xe \
	&& buildDeps=" \
		$PHP_EXTRA_BUILD_DEPS \
		libcurl4-openssl-dev \
		libedit-dev \
		libsqlite3-dev \
		libssl-dev \
		libxml2-dev \
	" \
	&& apt-get update && apt-get install -y $buildDeps --no-install-recommends && rm -rf /var/lib/apt/lists/* \
	\
	&& docker-php-source extract \
	&& cd /usr/src/php \
	&& ./configure \
		--with-config-file-path="$PHP_INI_DIR" \
		--with-config-file-scan-dir="$PHP_INI_DIR/conf.d" \
		\
		--disable-cgi \
		\
# --enable-ftp is included here because ftp_ssl_connect() needs ftp to be compiled statically (see https://github.com/docker-library/php/issues/236)
		--enable-ftp \
# --enable-mbstring is included here because otherwise there's no way to get pecl to use it properly (see https://github.com/docker-library/php/issues/195)
		--enable-mbstring \
# --enable-mysqlnd is included here because it's harder to compile after the fact than extensions are (since it's a plugin for several extensions, not an extension in itself)
		--enable-mysqlnd \
		\
		--with-curl \
		--with-libedit \
		--with-openssl \
		--with-zlib \
		\
		$PHP_EXTRA_CONFIGURE_ARGS \
	&& make -j"$(nproc)" \
	&& make install \
	&& { find /usr/local/bin /usr/local/sbin -type f -executable -exec strip --strip-all '{}' + || true; } \
	&& make clean \
	&& docker-php-source delete \
	\
	&& apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false $buildDeps

COPY docker-php-ext-* /usr/local/bin/

##<autogenerated>##
WORKDIR /var/www/html

RUN set -ex \
	&& cd /usr/local/etc \
	&& if [ -d php-fpm.d ]; then \
		# for some reason, upstream's php-fpm.conf.default has "include=NONE/etc/php-fpm.d/*.conf"
		sed 's!=NONE/!=!g' php-fpm.conf.default | tee php-fpm.conf > /dev/null; \
		cp php-fpm.d/www.conf.default php-fpm.d/www.conf; \
	else \
		# PHP 5.x don't use "include=" by default, so we'll create our own simple config that mimics PHP 7+ for consistency
		mkdir php-fpm.d; \
		cp php-fpm.conf.default php-fpm.d/www.conf; \
		{ \
			echo '[global]'; \
			echo 'include=etc/php-fpm.d/*.conf'; \
		} | tee php-fpm.conf; \
	fi \
	&& { \
		echo '[global]'; \
		echo 'error_log = /proc/self/fd/2'; \
		echo; \
		echo '[www]'; \
		echo '; if we send this to /proc/self/fd/1, it never appears'; \
		echo 'access.log = /proc/self/fd/2'; \
		echo; \
		echo 'clear_env = no'; \
		echo; \
		echo '; Ensure worker stdout and stderr are sent to the main error log.'; \
		echo 'catch_workers_output = yes'; \
	} | tee php-fpm.d/docker.conf \
	&& { \
		echo '[global]'; \
		echo 'daemonize = no'; \
		echo; \
		echo '[www]'; \
		echo 'listen = [::]:9000'; \
	} | tee php-fpm.d/zz-docker.conf

EXPOSE 9000
CMD ["php-fpm"]
##</autogenerated>##

Dockerfile

How to run PHP code ?

Run container, configured to run script.php as CMD

$ cd sandbox/script
$ docker build -t my-php-script .
$ docker run --rm --name my-running-script my-php-script

Dockerfile:

FROM php:5.6.26-fpm

COPY . /usr/src/myscript

WORKDIR /usr/src/myscript

CMD [ "php", "./script.php" ]

Code changes impacts

Now, try to change script.php behavior and re run the container... Still the same ! But why ?

 

As my-php-script is an inert image, a modification in my script.php files CAN'T affect this image.

As our my-running-script container is a living my-php-script,

a modification in my local files CAN'T affect this container.

 

A solution would be to update files directly in the container but it would only update the ​current container, not all containers related to my-php-script

...you already guess it is not the best solution.

Code changes impacts

A better solution ? using volumes

(The best is data volume containers, we will see that later)

First, remove the COPY directive from our Dockerfile:

FROM php:5.6.26-fpm

WORKDIR /usr/src/myscript

CMD [ "php", "./script.php" ]

And build & run the container with a volume (-v)

$ cd sandbox/script
$ docker build -t my-php-script2 .
$ docker run -v /home/nox/Dev/docker_workshop/php-fpm/script:/usr/src/myscript my-php-script2

And now we can see the changed script.php behavior !

MySQL

Dockerfile

FROM debian:jessie

# add our user and group first to make sure their IDs get assigned consistently, regardless of whatever dependencies get added
RUN groupadd -r mysql && useradd -r -g mysql mysql

# add gosu for easy step-down from root
ENV GOSU_VERSION 1.7
RUN set -x \
	&& apt-get update && apt-get install -y --no-install-recommends ca-certificates wget && rm -rf /var/lib/apt/lists/* \
	&& wget -O /usr/local/bin/gosu "https://github.com/tianon/gosu/releases/download/$GOSU_VERSION/gosu-$(dpkg --print-architecture)" \
	&& wget -O /usr/local/bin/gosu.asc "https://github.com/tianon/gosu/releases/download/$GOSU_VERSION/gosu-$(dpkg --print-architecture).asc" \
	&& export GNUPGHOME="$(mktemp -d)" \
	&& gpg --keyserver ha.pool.sks-keyservers.net --recv-keys B42F6819007F00F88E364FD4036A9C25BF357DD4 \
	&& gpg --batch --verify /usr/local/bin/gosu.asc /usr/local/bin/gosu \
	&& rm -r "$GNUPGHOME" /usr/local/bin/gosu.asc \
	&& chmod +x /usr/local/bin/gosu \
	&& gosu nobody true \
	&& apt-get purge -y --auto-remove ca-certificates wget

RUN mkdir /docker-entrypoint-initdb.d

# FATAL ERROR: please install the following Perl modules before executing /usr/local/mysql/scripts/mysql_install_db:
# File::Basename
# File::Copy
# Sys::Hostname
# Data::Dumper
RUN apt-get update && apt-get install -y perl pwgen --no-install-recommends && rm -rf /var/lib/apt/lists/*

# gpg: key 5072E1F5: public key "MySQL Release Engineering <mysql-build@oss.oracle.com>" imported
RUN apt-key adv --keyserver ha.pool.sks-keyservers.net --recv-keys A4A9406876FCBD3C456770C88C718D3B5072E1F5

ENV MYSQL_MAJOR 5.7
ENV MYSQL_VERSION 5.7.15-1debian8

RUN echo "deb http://repo.mysql.com/apt/debian/ jessie mysql-${MYSQL_MAJOR}" > /etc/apt/sources.list.d/mysql.list

# the "/var/lib/mysql" stuff here is because the mysql-server postinst doesn't have an explicit way to disable the mysql_install_db codepath besides having a database already "configured" (ie, stuff in /var/lib/mysql/mysql)
# also, we set debconf keys to make APT a little quieter
RUN { \
		echo mysql-community-server mysql-community-server/data-dir select ''; \
		echo mysql-community-server mysql-community-server/root-pass password ''; \
		echo mysql-community-server mysql-community-server/re-root-pass password ''; \
		echo mysql-community-server mysql-community-server/remove-test-db select false; \
	} | debconf-set-selections \
	&& apt-get update && apt-get install -y mysql-server="${MYSQL_VERSION}" && rm -rf /var/lib/apt/lists/* \
	&& rm -rf /var/lib/mysql && mkdir -p /var/lib/mysql /var/run/mysqld \
	&& chown -R mysql:mysql /var/lib/mysql /var/run/mysqld \
# ensure that /var/run/mysqld (used for socket and lock files) is writable regardless of the UID our mysqld instance ends up having at runtime
	&& chmod 777 /var/run/mysqld

# comment out a few problematic configuration values
# don't reverse lookup hostnames, they are usually another container
RUN sed -Ei 's/^(bind-address|log)/#&/' /etc/mysql/mysql.conf.d/mysqld.cnf \
	&& echo 'skip-host-cache\nskip-name-resolve' | awk '{ print } $1 == "[mysqld]" && c == 0 { c = 1; system("cat") }' /etc/mysql/mysql.conf.d/mysqld.cnf > /tmp/mysqld.cnf \
	&& mv /tmp/mysqld.cnf /etc/mysql/mysql.conf.d/mysqld.cnf

VOLUME /var/lib/mysql

COPY docker-entrypoint.sh /usr/local/bin/
RUN ln -s usr/local/bin/docker-entrypoint.sh /entrypoint.sh # backwards compat
ENTRYPOINT ["docker-entrypoint.sh"]

EXPOSE 3306
CMD ["mysqld"]

Pull it !

Let's use the official mysql repository

$ docker pull mysql

MySQL Container

To run a Container with MySQL :

$ docker run \
--name mysql \
-e MYSQL_ROOT_PASSWORD=root \
-e MYSQL_DATABASE=ekkinox \
-d \
mysql
$ docker exec -it CONTAINERID bash

root@0b1425f8cf45:/# mysql -u root -proot                                                                                                                                                                                              
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 2
Server version: 5.7.15 MySQL Community Server (GPL)

Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| ekkinox            |
| mysql              |
| performance_schema |
| sys                |
+--------------------+
5 rows in set (0.00 sec)

PHP linked to MySQL?

Build and run an php-fpm container, named mysqlphp, with Dockerfile:

FROM php:5.6.26-fpm

RUN apt-get update && apt-get install -y \
        libfreetype6-dev \
        libmcrypt-dev \
        libxml2-dev \
        curl \
        zlib1g-dev \
        libncurses5-dev \
        libcurl4-openssl-dev \
    && docker-php-ext-install -j$(nproc) mcrypt  pdo_mysql mbstring

COPY . /usr/src/myscript

WORKDIR /usr/src/myscript

CMD [ "php", "./connect.php" ]

We extend here php_fpm image to install some needed PHP extensions.

$ cd sandbox/mysql
$ docker build -t mysqlphp .

PHP linked to MySQL?

If we run:

But if we link (--link) to mysql container:

$ docker run mysqlphp

Warning: PDO::__construct(): php_network_getaddresses: getaddrinfo failed: Name or service not known in /usr/src/myscript/connect.php on line 5
Erreur !: SQLSTATE[HY000] [2002] php_network_getaddresses: getaddrinfo failed: Name or service not known<br/>%
$ docker run --link mysql:mysql mysqlphp
OK, connected !

Let's write a connect.php script:

<?php

try {

    $dbh = new PDO('mysql:host=mysql;dbname=ekkinox', 'root', 'root');
    echo 'OK, connected !';

} catch (PDOException $e) {
    echo "Erreur !: " . $e->getMessage() . "<br/>";
    die();
}

PHP linked to Nginx?

Run an php-fpm container, named php:

$ docker run --name php -p 9000:9000 -d php:5.6.26-fpm

Then run a nginx container, linked to php (using --link)

$ docker run -it --link php:php nginx /bin/bash

Once inside nginx container, check php-fpm ENV vars:

root@0e16019721b6:/# env | grep PHP
PHP_ENV_PHP_EXTRA_CONFIGURE_ARGS=--enable-fpm --with-fpm-user=www-data --with-fpm-group=www-data
PHP_ENV_PHP_VERSION=5.6.26
PHP_ENV_GPG_KEYS=0BD78B5F97500D450838F95DFE857D9A90D90EC1 6E4F6AB321FDC07F2C332E3AC2BF0BC433CFC8B3
PHP_PORT=tcp://172.17.0.6:9000
PHP_ENV_PHP_SHA256=203a854f0f243cb2810d1c832bc871ff133eccdf1ff69d32846f93bc1bef58a8
PHP_PORT_9000_TCP_PROTO=tcp
PHP_ENV_PHP_FILENAME=php-5.6.26.tar.xz
PHP_ENV_PHPIZE_DEPS=autoconf 		file 		g++ 		gcc 		libc-dev 		make 		pkg-config 		re2c
PHP_PORT_9000_TCP_PORT=9000
PHP_ENV_PHP_INI_DIR=/usr/local/etc/php
PHP_PORT_9000_TCP=tcp://172.17.0.6:9000
PHP_NAME=/modest_elion/php
PHP_PORT_9000_TCP_ADDR=172.17.0.6

Docker Hub

Docker Hub contains a lot of images for various purposes.

 

Docker Hub provides a free storage facility for your public images and a paying storage facility for your private images (GitHub style).

Push on Docker Hub

$ docker push ekkinox/mydockerizedproject

Pull from Docker Hub

$ docker pull ekkinox/mydockerizedproject

Automated Builds

Docker Hub allows you to link a GitHub repository to a Docker Hub repository.

 

Your GitHub repository should contain a Dockerfile on the root directory.

 

Each time you push on GitHub, Docker Hub (through webhooks) will pull your repository and build an image into your Docker Hub repository.

Orchestration

So, running all containers by hand can

be really messy and complicated... saw it.

 

"Damned, i'll never use this Docker stuff..."

Orchestration

For the moment our simple application requires us to do those kind of commands :

$ docker run \
--name mysql \
-e MYSQL_ROOT_PASSWORD=root \
-e MYSQL_DATABASE=ekkinox \
-d \
mysql

$ docker run \
-v /home/nox/Dev/docker_workshop/php-fpm/script:/usr/src/myscript \
my-php-script2

$ ... and more and more pain 0_x !

(and we did not even seen it running on nginx yet, right ?)

Orchestration

Solutions ?

 

  • Put those commands into a README ?
  • Put those commands into a bash script ?

 

No. Bad idea.

 

The solution is Docker compose

Orchestration

Docker compose works by putting a single yaml file in your project.

 

 

Let's build our project step by step ...

 

 

... yes we can.

Orchestration

First, we need nginx:

services:
    nginx:
        build: ./nginx
        ports:
            - "80:80"
        volumes:
            - ./logs/nginx/:/var/log/nginx

check with docker ps

$ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                         NAMES
01c2a83efc66        application_nginx   "nginx -g 'daemon off"   44 seconds ago      Up 43 seconds       0.0.0.0:80->80/tcp, 443/tcp  application_nginx_1

run docker compose up -d

$ docker-compose up -d
Creating network "application_default" with the default driver
Creating application_nginx_1

Orchestration

Then, add some code to nginx using volumes

services:
    nginx:
        build: ./nginx
        ports:
            - "80:80"
        volumes:
            - ./logs/nginx/:/var/log/nginx
            - ./src/:/var/www/application

rebuild and restart (only build needed, but shows all commands)

$ docker-compose down
$ docker-compose build
$ docker-compose up -d

Orchestration

Then, we need php-fpm

services:
    php:
        build: ./php-fpm

rebuild and restart

$ docker-compose down
$ docker-compose build
$ docker-compose up -d

check with docker ps

$ docker ps           
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                         NAMES
56f6a05b08c9        application_nginx   "nginx -g 'daemon off"   4 seconds ago       Up 2 seconds        0.0.0.0:80->80/tcp, 443/tcp   application_nginx_1
dab7a7298c36        application_php     "php-fpm"                4 seconds ago       Up 2 seconds        9000/tcp                      application_php_1

Orchestration

FIle not found !

normal, php-fpm does not know where to find php script:

$ docker-compose down
$ docker-compose build
$ docker-compose up -d

rebuild and restart:

php:
    build: ./php-fpm
    volumes:
        - ./src/:/var/www/application

Orchestration

Then, we need a mysql :

$ docker-compose up -d

and restart (no build needed here):

mysql:
    image: mysql:5.6
    expose:
        - 3306
    ports:
        - "3306:3306"
    environment:
        - MYSQL_ROOT_PASSWORD=root
        - MYSQL_DATABASE=ekkinox

 Now, http://192.168.99.100/index.php=> OK, connected !

Orchestration

As we are lazy, could be nice to have a PhpMyAdmin, right ?

$ docker-compose up -d

and restart (no build needed here):

phpmyadmin:
   image: nazarpc/phpmyadmin
   ports:
        - "1234:80"
   links:
        - mysql:mysql

check with docker ps

$ docker ps
CONTAINER ID        IMAGE                COMMAND                  CREATED             STATUS              PORTS                         NAMES
1b6487cedee9        nazarpc/phpmyadmin   "/home/entrypoint.sh"    43 seconds ago      Up 42 seconds       0.0.0.0:1234->80/tcp          application_phpmyadmin_1
b3a4ea177aed        mysql:5.6            "docker-entrypoint.sh"   44 seconds ago      Up 43 seconds       0.0.0.0:3306->3306/tcp        application_mysql_1
972ea0cf9df9        application_php      "php-fpm"                45 seconds ago      Up 43 seconds       9000/tcp                      application_php_1
783be0ad9874        application_nginx    "nginx -g 'daemon off"   45 seconds ago      Up 44 seconds       0.0.0.0:80->80/tcp, 443/tcp   application_nginx_1

Orchestration

Keeping mysql data could be nice, even if containers are killed.

Data volumes to the rescue:

and restart (no build needed here):

mysql:
    image: mysql:5.6
    expose:
        - 3306
    ports:
        - "3306:3306"
    environment:
        - MYSQL_ROOT_PASSWORD=root
        - MYSQL_DATABASE=ekkinox
    volumes_from:
        - mysql_data

mysql_data:
   image: tianon/true
   volumes:
        - ./mysql/data:/var/lib/mysql

rebuild and restart

 Now, http://192.168.99.100/users.php=> OK, persistent !

Orchestration

So, in short (more easy than docker commands, right ?) :

version: '2'

services:
    nginx:
        build: ./nginx
        ports:
            - "80:80"
        volumes:
            - ./logs/nginx/:/var/log/nginx
            - ./src/:/var/www/application

    php:
        build: ./php-fpm
        volumes:
            - ./src/:/var/www/application

    phpmyadmin:
       image: nazarpc/phpmyadmin
       ports:
            - "1234:80"
       links:
            - mysql:mysql

    mysql:
        image: mysql:5.6
        expose:
            - 3306
        ports:
            - "3306:3306"
        environment:
            - MYSQL_ROOT_PASSWORD=root
            - MYSQL_DATABASE=ekkinox
        volumes_from:
            - mysql_data

    mysql_data:
       image: tianon/true
       volumes:
            - ./mysql/data:/var/lib/mysql

Orchestration

Some docker useful commands:

# Stops all containers
$ docker stop $(docker ps -a -q)


# Delete all containers
$ docker rm $(docker ps -a -q)


# Delete all images
$ docker rmi $(docker images -q)

Orchestration

Some docker-compose useful commands:

$ docker-compose up -d
$ docker-compose down
$ docker-compose build
$ docker-compose logs -f
$ docker-compose restart

Scalability

Docker compose allows you to multiply a container by using the scale command :

$ docker-compose scale nginx=5

To allow links to properly function you have to stop and remove your nginx container and relaunch it :

$ docker-compose stop nginx
$ docker-compose rm nginx
$ docker-compose run -d nginx

Thank you ...

and use docker !

...questions ? no ? cool.

About Docker

By Michael PAMBO OGNANA

About Docker

Docker basics

  • 627