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 :
- Frontend : Apache and external access
- 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