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 theDockerfile
for php7-fpm container and the Supervisord confignginx
folder contains theDockerfile
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 rundocker-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 Dockerfile
s 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.