Development environment for Magento 2 using Docker

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.

Related Inchoo Services

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

How to programmatically create customers in Magento 2.3.x Deni Pesic
Deni Pesic, | 2

How to programmatically create customers in Magento 2.3.x

Top challenges and best practices in ERP and eCommerce integration Aron Stanic
Aron Stanic, | 2

Top challenges and best practices in ERP and eCommerce integration

GDPR compliant Magento 2 database dump Deni Pesic
Deni Pesic, | 3

GDPR compliant Magento 2 database dump

14 comments

  1. @timm

    You should be able to see error in cat /var/log/apache2/error.log
    Of course, you need to SSH to container first. You can do that like this:
    docker exec -i -t -u inchoo m2docker_apache-php_1 /bin/bash -c ‘cd /var/www/html; /bin/bash’

    In any case, you probably have issues with memory_limit, max_execution time or max_input_time …

    I didn’t include any php.ini in docker-compose, but you can edit it in container directly (once logged in) and restart apache.

    You can also add any php config directive in xdebug.ini that is part of this post (it will be parsed).
    Add something like:
    max_execution_time = 1800
    max_input_time = 1800
    memory_limit = 2048M
    or whatever you like the best.

    After that, do docker-compose down and docker-compose up -d –force-recreate (two “-” before force-recreate …. I’m not sure what’s going on with formating)

    Sorry if this is not helpful but I’m kinda blind here 😉

  2. Hi,

    the last time I tried a lot to install magento2 properly.
    I even changed my OS to Ubuntu, to operate on linux, which seams to make the deal easier after I struggled with windows10 (wind10 update to pro, learning docker, trying about 10 tutorials which all exposed new errors).

    I thought with my new ubuntu the world gets easier. I really hoped it.
    After trying ur tutorial I could get to 59% percent while installation where magento stuck. Checked all error logs, installation logs, nothing which points to an error.

    Actually I think about to check php.ini file (no error related given but who knows)
    or trying a new apache_php docker image… what ever.. I am really impressed that so many tutorials are not working for me and its frustrating.

  3. @Avr Hill
    I got docker image from dockerhub (as you can see from links in comments) and as mentioned in the text it is created by my work colleague. I chose it because it is lightweight and compliant with latest M2 requirements.

    When it comes to “advising official”, I think that’s just not true. There are lots of official images that suck and also many that are not official and are great. Yes, I would usually use official images if they are good, but in this case, I’m not really sure what would I use instead, because official PHP images require additional build for all extensions you might need. Why apache+php on one image? Just easier for us do distribute between ourselves and teams.

    When it comes to data, you have html directory and it totally doesn’t care if docker container is running or not. Those are the same files you have on your host. No caching on anything involved. If you have any issues then, it could be anything, from Magento cache to browser cache, but there is no delay on anything you change in html directory.

    There is one catch though and I will update post right now:
    Apache config is no longer needed. It is built in the image.

  4. Hi Tomas.

    Once you have this running, how do you actually develop?
    Files inside volumes don’t seem to be updated within a running container when edited on the outside without running docker-compose up again, so I guess you edit inside the running container?

    And where did you find udovicic/echo:apache-php7.1, and why did you select that one?
    Everyone always advises using official images.

  5. Hey thanks for the wonderful blog post. Do you have another article that goes over how to setup magento2 in the html folder with docker? Sorry big noob here & having the hardest time to get my dev env going. Can’t seem to reach my magento files. I assume i might need to run the php install within the php container? have no clue how do to it =(!
    Thanks for the help!

  6. There appears to be missing information in the apache.conf above (missing VirtualHost line, missing Directory lines). This will not work (apache container will halt before fulling starting). Can you fix the guide?

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>.

Tell us about your project

Drop us a line. We'd love to know more about your project.