What is Docker Compose

As seen in my previous article, we can configure docker based LAMP stack using Docker images. Another way to do it is to use Docker Compose.

This tool can be used to define and run multi-container applications easily. Indeed, through a YAML file (docker-compose.yml) we will store all the configurational information needed for services and through Dockerfiles we will store all commands required to assemble an image for our containers.

We will be able to configure application’s services and then with a single command, create and start all of them.

In this article we will configure a LAMP stack through 3 containers :

  • An Apache Container
  • A PHP Container
  • A Database Container

Docker-compose.yml

Let’s configure our services in our docker-compose.yml file.

Set a version

The first line of our file is the version, in our case “version 1” :

version : '1'

Build services

Then, we need to configure and build our services :

services:
  apache:
    build: './apache'
  php:
    build: './php'
  mysql:

    build: './mysql'

Instead of directly specifying the remote image to use, in the build section, we provide to Docker Compose the directory where the Dockerfile to build the image is found. It’s called the context, basically, configuration options that are applied at build time.

We have in the meantime created 3 diretories which will contain our DockerFiles described in the last part of this tutorial.

Mapping ports

We now need to map our containers ports. There are only ports to map for our apache container, because it’s the only one we need to be accessed from external.

services:
  apache:
    build: './apache'
    ports:
      - 8080:80

      - 443:443


This will link our containers ports to our local machine’s ports. So in my example, we link port 8080 and 443 of our container to port 80 and 443 of my laptop.

Mapping volumes

In order to have our code into the container, the best way is to map a local directory to a volume. Any files inside the directory will be accessible to both the host machine and the container.

apache:
    build: './apache'
    ports:
      - 8080:80
      - 443:443
    volumes:
      - ./var/www/html:/usr/local/apache2/htdocs

php:
    build: './php'
    volumes:
      - ./var/www/html:/usr/local/apache2/htdocs
mysql:
    build: './mysql'
    volumes:

      - ./mysql:/var/lib/mysql

  • In the apache and PHP service, we have link our local directory ./var/www/html with our static files to /usr/local/apache2/htdocs of our container.
  • In the mysql service, we link our local directory ./mysql to /var/lib/mysql on the container to be able to have persisting database.

Container networks

Last step, we must configure our network to let our containers communicate. In a LAMP stack, we only want PHP and MySQL to be able to communicate. Then, we want let the Apache container reach both PHP and MySQL. Finally we need to expose Apache to any.

It means that we need two networks :

  1. Frontend : Apache and external access
  2. Backend : PHP and MySQL

We can add them in our YAML file like so :

networks:
  backend:
  frontend:

You can configure your networks further if necessary.

Then, we add our networks to our services and we have our final YAML file :

version : '1'

apache:
    build: './apache'
    ports:
      - 8080:80
      - 443:443
    volumes:
      - ./var/www/html:/usr/local/apache2/htdocs
php:
    build: './php'
    volumes:
      - ./var/www/html:/usr/local/apache2/htdocs
mysql:
    build: './mysql'
    volumes:
      - ./mysql:/var/lib/mysql

networks:
  backend:
  frontend:

services:
  apache:
    build: './apache'
    restart: always
    ports:
      - 80:80
      - 443:443
    networks:
      - frontend
      - backend
    volumes:
      - ./public_html:/usr/local/apache2/htdocs
      - ./cert/:/usr/local/apache2/cert/
    depends_on:
      - php
      - mysql
  php:
    build: './php'
    restart: always
    networks:
      - backend
    volumes:
      - ./public_html:/usr/local/apache2/htdocs
      - ./tmp:/usr/local/tmp
  mysql:
    build: './mysql'
    restart: always
    networks:
      - backend
    volumes:
      - ./database:/var/lib/mysql

Here is a quick description for each line, it help you to understand everything :

  • build : Configuration options that are applied at build time.
  • restart : The container will always restart
  • networks : Networks to join, referencing entries under the top-level network key.
  • volumes : Mount host paths or named volumes, specified as sub-options to a service.
  • ports : Expose ports.
  • depends_on : Express dependency between services. It means that all dependencies will be included and apache service will be started after PHP and MySQL.

Dockerfiles

We have configure our YAML for Docker Compose, but now we need to create a Dockerfile for each container.

A DockerFile is basically a text file.

For our Apache Container, we use alpine image, update and upgrade it and copy our apache.conf file. Then we expose our ports.

FROM httpd:2.4.35-alpine
RUN apk update; \
    apk upgrade;
COPY ./apache.conf /usr/local/apache2/conf/httpd.conf
EXPOSE 8080
EXPOSE 443



For MySQL, we use an image, change MySQL root password and copy the configuration :

FROM mysql:8.0.13
ENV MYSQL_ROOT_PASSWORD <password>
COPY my.cnf /etc/mysql/

Finally, for our PHP container, we do the same thing, except that we install some php packages that will be used by our scripts :

FROM php:7.3-rc-fpm-alpine
RUN apk update; \
    apk upgrade;
RUN docker-php-ext-install mysqli
RUN apk add freetype libpng libjpeg-turbo freetype-dev libpng-dev libjpeg-turbo-dev
RUN docker-php-ext-install -j$(nproc) iconv
RUN docker-php-ext-configure gd --with-freetype-dir=/usr/include/ --with-jpeg-dir=/usr/include/
RUN docker-php-ext-install -j$(nproc) gd
COPY php.ini /usr/local/etc/php/php.ini

The RUN command lets you run a Linux command. Here, we need to install mysqli to allow PHP to interact with our MySQL server.

You just have to run the command “docker-compose up” to build the images and run the containers !

Images are now built, next time, it will run containers directly.

Sources :

  • https://doc.ubuntu-fr.org
  • https://docs.docker.com
  • https://linuxconfig.org
  • https://medium.com

Leave a Comment

Your email address will not be published. Required fields are marked *