Development environment for Magento 2 using Docker

When I first started with PHP a long time ago, I really had trouble setting up work environment.
I had no clue about what I was doing.

Don’t ask me how, but I ended up with Apache Tomcat running PHP.
Honestly, I don’t know if I could even set up such a blasphemy today.


EDIT NOTE:
Due the fact that udovicic/echo:apache-php7.1 is updated, you no longer need apache config, so I edited this post and removed apache configuration.

Over the years I went the whole path from xampp, manual LAMP setup, vagrant…
All those had at least 1 dealbreaker, especially when I started working with Magento.

Finally, Docker came and made development much easier.

At this point, it becomes a little bit tricky to explain what Docker is.
It performs operating system level virtualization (containerization) which refers to the operating system feature in which the kernel allows the existence of multiple isolated user-space instances.
If the sentence above doesn’t make any sense to you, then maybe it would be wise to visit http://www.docker.com and at some point come back here, otherwise, continue reading…

What I’m going to share now is not some Docker wisdom. It is more about setup capable of running Magento 2 via Docker, so this article assumes that you are somewhat familiar with Docker.

So, let’s begin…

Let’s run Magento 2 on let’s say http://m2.docker

First thing you should do is add this line somewhere in your /etc/hosts file:

127.0.0.1 m2.docker www.m2.docker

We will need some filesystem structure, so do the following:

tomas ~ $ mkdir m2.docker
tomas ~ $ cd m2.docker/
tomas ~/m2.docker $ mkdir docker
tomas ~/m2.docker $ mkdir html
tomas ~/m2.docker $ mkdir -p docker/db
tomas ~/m2.docker $ touch docker/xdebug.ini
tomas ~/m2.docker $ touch docker/apache.conf
tomas ~/m2.docker $ touch docker-compose.yml
tomas ~/m2.docker $ touch .env

Now, let’s go file by file:

.env

In this file you can write variables that will be used in docker-compose.yml
Mine looks like this:

CONTAINER_PREFIX=m2docker
SERVER_NAME=m2.docker
SERVER_ALIAS=www.m2.docker
DIRECTORY_NAME=m2.docker
WEB_USER=inchoo
WEB_ROOT = /var/www/html
MYSQL_DB_HOST = ${CONTAINER_PREFIX}_db_1
MYSQL_DATABASE=inchoo
MYSQL_ROOT_USERNAME=root
MYSQL_ROOT_PASSWORD=inchoo
MYSQL_USER=inchoo
MYSQL_PASSWORD=inchoo
DOCKER_EXEC=docker exec
DOCKER_EXEC_INTERACTIVE=docker exec -i
DOCKER_EXEC_TTY=${DOCKER_EXEC_INTERACTIVE} -t

For docker-compose.yml you will need code below.

I also added some comments with links to documentation.
Note that I’m using apache-php image created by my colleague Stjepan and I highly recommend it for development.

# https://docs.docker.com/compose/compose-file
version: "3.6"
 
# https://docs.docker.com/compose/compose-file/#service-configuration-reference
services:
 
#custom name
apache-php:
# https://docs.docker.com/compose/compose-file/#image
# https://githheizenberg ub.com/udovicic/echo => https://hub.docker.com/r/udovicic/echo/
image: udovicic/echo:apache-php7.1
 
# https://docs.docker.com/compose/compose-file/#ports
ports:
- "80:80"
 
# https://docs.docker.com/compose/compose-file/#expose
expose:
- "9000"
 
# https://docs.docker.com/compose/compose-file/#volumes
volumes:
- ./docker/xdebug.ini:/etc/php/7.1/mods-available/xdebug.ini
- ./html:/var/www/html
 
# https://docs.docker.com/compose/compose-file/#environment
environment:
- TERM=xterm-256color
- APACHE_RUN_USER=1000
 
# https://docs.docker.com/compose/compose-file/#network-configuration-reference
networks:
default:
aliases:
- ${SERVER_NAME}
- ${SERVER_ALIAS}
 
db:
 
# https://hub.docker.com/_/mysql/
image: mysql:5.7
 
volumes:
- ./docker/db/data:/var/lib/mysql
 
environment:
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
MYSQL_DATABASE: ${MYSQL_DATABASE}
MYSQL_USER: ${MYSQL_USER}
MYSQL_PASSWORD: ${MYSQL_PASSWORD}
 
redis:
 
# https://hub.docker.com/_/redis/
image: redis:latest
 
phpmyadmin:
 
# https://hub.docker.com/r/phpmyadmin/phpmyadmin/
image: phpmyadmin/phpmyadmin
 
ports:
- "8080:80"
 
environment:
MYSQL_USERNAME: ${MYSQL_ROOT_USERNAME}
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}

…and xdebug.ini

zend_extension=xdebug.so
xdebug.remote_autostart=0
xdebug.remote_enable=1
xdebug.remote_port=9000
xdebug.remote_connect_back=1

A this point we have working environment, so let’s try to run it:

tomas ~/m2.docker $ docker-compose up -d
Creating network "m2docker_default" with the default driver
Creating m2docker_apache-php_1 ... done
Creating m2docker_redis_1      ... done
Creating m2docker_phpmyadmin_1 ... done
Creating m2docker_db_1         ... done
tomas ~/m2.docker $ docker ps
CONTAINER ID        IMAGE                         COMMAND                  CREATED             STATUS              PORTS                            NAMES
e3384b0eff8c        mysql:5.7                     "docker-entrypoint.s…"   3 seconds ago       Up 2 seconds        3306/tcp                         m2docker_db_1
d283bf018330        phpmyadmin/phpmyadmin         "/run.sh phpmyadmin"     3 seconds ago       Up 2 seconds        9000/tcp, 0.0.0.0:8080->80/tcp   m2docker_phpmyadmin_1
ded8bce1d993        redis:latest                  "docker-entrypoint.s…"   3 seconds ago       Up 2 seconds        6379/tcp                         m2docker_redis_1
fe8a80763ac6        udovicic/echo:apache-php7.1   "/start.sh"              3 seconds ago       Up 2 seconds        0.0.0.0:80->80/tcp, 9000/tcp     m2docker_apache-php_1
tomas ~/m2.docker $

Now when it works…

Magento should be installed in “html” directory.
Note that you need to use “db” when referring to database address, and so on. Just check docker-compose.yml (service name).
Also, relevant credentials are in .env file.

PhpMyAdmin is available @ http://m2.docker:8080

This is a very basic setup. I usually create git repository which initially ends up with 2 branches like for example m2-docker and master and then I copy .git directory into html and checkout master branch while in the base directory I checkout m2-docker branch.

Thanks for reading.