Development environment for Magento 2 using Docker

Related Inchoo Services

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.

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/apache.conf:/etc/apache2/sites-available/000-default.conf
        - ./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

…and apache.conf

ServerAdmin webmaster@m2-sample.docker
    ServerName m2.docker
    Serveralias www.m2.docker
 
    DocumentRoot /var/www/html/pub
 
        Options FollowSymLinks
        AllowOverride None
 
        Options Indexes FollowSymLinks MultiViews
        AllowOverride All
        Require all granted
 
        SetHandler "proxy:unix:/run/php/php-fpm.sock|fcgi://localhost/"
 
    ErrorLog ${APACHE_LOG_DIR}/error.log
    CustomLog ${APACHE_LOG_DIR}/access.log combined

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.

It would be tricky to write an article about all that, but if you want to play with it, check:
https://github.com/tomasinchoo/m2-sample.docker/tree/master (make sure to check m2-sample.docker branch too).

There is also a repository for Magento 1 here: https://github.com/tomasinchoo/m1-sample.docker
It’s still not 100% done, but feel free to post issue directly on github page.

Thanks for reading.

You made it all the way down here so you must have enjoyed this post! You may also like:

GDPR compliant Magento 2 database dump Deni Pesic
, | 1

GDPR compliant Magento 2 database dump

Magento Coding Standards Damir Korpar
, | 4

Magento Coding Standards

Run methods that are specified in module’s xml file using XPath and Varien_Object Ivan Galambos
Ivan Galambos, | 0

Run methods that are specified in module’s xml file using XPath and Varien_Object

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <blockquote cite=""> <code> <del datetime=""> <em> <s> <strike> <strong>. You may use following syntax for source code: <pre><code>$current = "Inchoo";</code></pre>.