When we work as a team, it's insanely difficult for all of us to have the same environment. Some devs may be working on Linux machines whereas others working on Mac/Windows machines. Some dependencies may work on some machines, while others may not even support them. Then we also have this problem of "that works on my machine (but not in production)". How do we deal with all these kind of issues?

Earlier we were using Vagrant, an awesome tool to create, manage and share virtual environments across all platforms. It was a great idea that everyone in a team can have the same environment, regardless of the platform we use. It also helped us to try out new things without messing up our local environment. But Vagrant has a downside. Vagrant images are virtual machines running on Virtual Box/VMWare, with huge memory and CPU overhead.

Enter The Docker

Docker is a great technology which solves the same problem in a different way. Instead of using hardware virtualization, Docker provides light weight containers where we can run our applications with minimal overhead. We can bring up a Docker container in a matter of seconds.

In this article, I will try to explain the base Docker setup I use, with php7-fpm, Nginx, and MariaDB. This is a bare minimum setup, keeping Laravel in mind. But feel free to modify as per your requirements.

Requirements

Docker v > 1.12

Installation

Clone or download the project from Github.

git clone https://github.com/shameerc/docker-php7.git 

Usage

cd docker-php7
docker-compose up

This will build and start all the containers after downloading images from Docker hub (if not available locally) and installing the necessary packages. The docker-composer will be running in the foreground, printing logs from all containers into the console. If we want, we can run it in the background by providing -d as an option.

docker-compose up -d

Once the containers are ready and started, open http://localhost:8080/ in the browser. If everything went well, we will see the output of the phpinfo().

In order to run Laravel, install the project inside app folder and update the following database credentials in .env file.

DB_HOST=db
DB_PORT=3306
DB_DATABASE=laravel
DB_USERNAME=root
DB_PASSWORD=root

How it works

Inside docker-php7 we have a directory structure like this.

├── app/
├── database/
├── fpm
│   ├── Dockerfile
│   └── supervisord.conf
├── nginx
│   ├── Dockerfile
│   └── default.conf
├── docker-compose.yml
└── readme.md
  • app - Our application will be kept in this directory.
  • database is where MariaDB will store all the database files.
  • fpm folder contains the Dockerfile for php7-fpm container and the Supervisord config
  • nginx folder contains the Dockerfile for nginx and the default nginx config which will be copied to the container.
  • docker-compose.yml - Our docker-compose configuration. In this file, we define the containers and services that we want to start, along with associated volumes, ports, etc. When we run docker-compose up, it reads this file and builds the images.

docker-compose.yml

version: "2"
services:
  nginx:
      build:
          context: ./nginx
      ports:
          - "8080:80"
      volumes:
          - ./app:/var/app
      links:
          - fpm
  fpm:
      build:
          context: ./fpm
      volumes:
          - ./app:/var/app
      expose:
          - "9000"
      links:
          - db
      environment:
          - "DB_HOST=db"
          - "DB_DATABASE=laravel"
  db:
      image: mariadb
      environment:
          - MYSQL_ROOT_PASSWORD=root
          - MYSQL_DATABASE=laravel
      volumes:
          - ./database:/var/lib/mysql

version key specifies the docker compose syntax version that we are using. All the services should go under the services key. Here we are running three containers, nginx, fpm, and db. Let's look at the options for each container.

    build:
      context: ./nginx

This will build the Nginx container using the Dockerfile in nginx directory, which is specified using context key. We can also specify the image name directly, as we can see in the definition of db service.

      image: mariadb

This will start the container directly from mariadb image. Docker will pull the image from docker hub if it's not existing locally.

    ports:
          - "8080:80"

Here we tell Docker to map the port 80 of the container to port 8080 of the host machine. Then we can access the application running in a container using http://localhost:8080.

    expose:
      - "9000"

expose on the other hand maps the container port 9000 to the port 9000 of the host machine.

    volumes:
          - ./app:/var/app

This will map the ./app directory of the host machine to /var/app directory in the container. So whatever we put inside this directory will be available inside /var/app directory of the container.

    links:
          - fpm

links are used to link one container with other. Here we tell Docker that we want to link fpm container with nginx container so that we can access that service inside nginx. When a link is specified, docker will start the linked container before it starts the current one. In our case, nginx depends on fpm which links db. So, docker will first start the db container and then fpm and finally nginx.

Note: It's not necessary to specify the links as containers are implicitly linked when using docker compose version 2.

environment key specifies the environment variables that need to be set when the container is started.

    environment:
          - MYSQL_ROOT_PASSWORD=root
          - MYSQL_DATABASE=laravel

In this case, we want to set root as MYSQL_ROOT_PASSWORD environment variable and MYSQL_DATABASE to laravel, both of which are required by mariadb image.

    volumes:
          - ./database:/var/lib/mysql

This will map ./database directory of the host machine to /var/lib/mysql directory of Mariadb instance. It is really useful since we can keep the mysql data files on the host machine and make available in a new container when created.

Summary

In this article, we have discussed some of the basics of Docker and docker compose and gone through a basic docker-compose setup for PHP7 based applications. Please also have a look at the Dockerfiles for nginx and fpm. I really hope this will help you to get started with docker and docker-compose and use it in your day to day life. If you have any questions, don't hesitate to ask them in the comments below.

blog comments powered by Disqus