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.
Docker v > 1.12
Clone or download the project from Github.
git clone https://github.com/shameerc/docker-php7.git
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
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
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.
databaseis where MariaDB will store all the database files.
fpmfolder contains the
Dockerfilefor php7-fpm container and the Supervisord config
nginxfolder contains the
Dockerfilefor 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.
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,
db. Let's look at the options for each container.
build: context: ./nginx
This will build the Nginx container using the
nginx directory, which is specified using
context key. We can also specify the image name directly, as we can see in the definition of
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
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
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
MYSQL_ROOT_PASSWORD environment variable and
laravel, both of which are required by
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.
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.