Docker for Magento 2 Development

Docker for Magento 2 Illustrative Logo

Docker and Magento

In this first post, of which many will follow, we show you how to set up Docker for Magento 2 development. Way back when I first heard of Docker, I was still using WAMP, MAMP, Vagrant, VMWare and anything else I could get my hands on. While there are pros and cons to all of the different virtual machine platforms, there was really nothing that truly satisfied all of my needs. It always seemed as though I would get some of the features I needed at the expense of others. Try as I might, I could never quite find the balance I was looking for. When I first started to hear about Docker, I was intrigued yet skeptical, maybe even intimidated.

Crawl Before You Can Walk

I am not, nor have I ever been, a server or dev ops guy. I am a programmer. One day, when I had some free time, I decided to download and install Docker. Despite all that I had read online, I had quite a bit of trouble figuring out how Docker worked and what it’s capabilities were. I had read mountains of online documentation and followed countless tutorials. Quite literally, I spent several frustrating weeks, at least 8 hours per day, trying to figure out what I was doing and why it wasn’t working. Anyone less stubborn and hard-headed would have abandoned the idea completely. In fact, it’s probably the reason I’m going bald. Fortunately, a light bulb did finally pop on above my head and nowadays I am extremely happy with Docker.

Due to the massive frustration I experienced and the sanity that I lost, I just knew I had to make this the first tutorial that I write. My goal is to condense years of experience into a one-page tutorial so that you can get up and running with your Magento 2 projects and keep your hair!

Update: Spin Up Magento With a Single CLI Command

Setup Docker for Magento 2 Development

To follow this tutorial on YouTube, click here.

Install Docker

The first, and perhaps most obvious, step is to download Docker, install it, and start it up. Docker is available for all major operating systems including, but not limited to, Mac OS X, Windows, Ubuntu, Debian, CentOS, and more. The steps in this tut assume that you are on a Mac. However, the steps are the same or very similar no matter what operating system you are on.

Install Composer

Although there are other ways to install and manage Magento 2, Composer is the preferred way. Composer will allow you to manage and install packages as well as allow you to run additional scripts after each update. Additionally, you may have noticed “uninstall” scripts in some Magento extensions. These scripts only work when the extension or module is managed with Composer.

Download Magento 2

To download the Magento 2 Open Source metapackage, do the following:

  1. Log in or create an account on Magento marketplace. Once logged in, navigate to Access Keys and keep that window open as you will need the keys in step #3.
  2. Determine a location on your local machine where you would like the website files to live.
  3. Open up a command line terminal. Before copying and pasting the code below, replace the placeholder path with the absolute path of where you plan to download/install Magento.
    cd /path/to/where/you/will/download/magento && \
    composer create-project --repository-url=https://repo.magento.com/ magento/project-community-edition .
  4. The latest version of Magento 2 is now downloaded to your machine. From this point forward, we will refer to the directory where you installed Magento as /path/to/magento.
  5. Increase the PHP memory limit from the default value of 756M to 2048M.
    find . -name '.htaccess' -exec sed -i '' s/756M/2048M/g {} + && \
    find . -name '.htaccess' -exec sed -i '' s/768M/2048M/g {} + && \
    find . -name '.user.ini' -exec sed -i '' s/756M/2048M/g {} + && \
    find . -name '.user.ini' -exec sed -i '' s/768M/2048M/g {} +
  6. Choose a domain name you would like to use to access the site and add it to your hosts file.
    sudo -- sh -c "echo '127.0.0.1 local.domain.com' >> /etc/hosts"

Create a docker-compose.yml file

  1. Choose a place on your local machine where you will keep your Docker configuration files. We will refer to this location as /path/to/docker.
  2. cd /path/to/docker
  3. Open a new text document in the text editor of your choice.
  4. Copy and past the following code into the new file.
    version: '3'
    services:
        web:
            image: webdevops/php-apache-dev:ubuntu-16.04
            container_name: web
            restart: always
            user: application
            environment:
              - WEB_ALIAS_DOMAIN=local.domain.com
              - WEB_DOCUMENT_ROOT=/app/pub
              - PHP_DATE_TIMEZONE=EST
              - PHP_DISPLAY_ERRORS=1
              - PHP_MEMORY_LIMIT=2048M
              - PHP_MAX_EXECUTION_TIME=300
              - PHP_POST_MAX_SIZE=500M
              - PHP_UPLOAD_MAX_FILESIZE=1024M
            volumes:
              - /path/to/magento:/app:cached
            ports:
              - "80:80"
              - "443:443"
              - "32823:22"
            links:
              - mysql
        mysql:
            image: mariadb:10
            container_name: mysql
            restart: always
            ports:
              - "3306:3306"
            environment:
              - MYSQL_ROOT_PASSWORD=root
              - MYSQL_DATABASE=magento
            volumes:
              - db-data:/var/lib/mysql
        phpmyadmin:
            container_name: phpmyadmin
            restart: always
            image: phpmyadmin/phpmyadmin:latest
            environment:
              - MYSQL_ROOT_PASSWORD=root
              - PMA_USER=root
              - PMA_PASSWORD=root
            ports:
              - "8080:80"
            links:
              - mysql:db
            depends_on:
              - mysql
    
    volumes:
        db-data:
            external: false
    
  5. Replace the domain name on line 8 with the domain you created earlier in this tutorial.
  6. Replace /path/to/magento on line 17 with the absolute path to the Magento files you downloaded earlier. Leave everything after the colon just the way it is.
  7. Save the new file as /path/to/docker/docker-compose.yml

Now We’re Ready to Fire It Up

  1. At this point in time, your terminal should still be open to /path/to/docker.
  2. Fire up your virtual machine! The first time you spin up, Docker needs to download the images, this may take a few minutes. Future spin-ups will only take a few seconds, usually less than 10.
    docker-compose up -d --build
  3. Let’s make sure that it’s up and running as planned. In a web browser, go to 127.0.0.1:8080 and make sure that you can see phpMyAdmin. If you can, it was a success.

Finally, Let’s Install Magento 2!

  1. Access your Docker web container’s command line.
    docker exec -it web bash
  2. Navigate to the web document root.
    cd /app
  3. Optional but recommended: deploy sample data.
    php bin/magento sampledata:deploy
  4. Install Magento 2! Before copying and pasting the command shown below into the Docker terminal, you must replace the values on lines 2-6 with your own details. On lines 7-8, replace the placeholder domain with the domain name you created earlier.
    php bin/magento setup:install \
    --admin-firstname=John \
    --admin-lastname=Doe \
    --admin-email=johndoe@example.com \
    --admin-user=admin \
    --admin-password='SomePassword123' \
    --base-url=https://local.domain.com \
    --base-url-secure=https://local.domain.com \
    --backend-frontname=admin \
    --db-host=mysql \
    --db-name=magento \
    --db-user=root \
    --db-password=root \
    --use-rewrites=1 \
    --language=en_US \
    --currency=USD \
    --timezone=America/New_York \
    --use-secure-admin=1 \
    --admin-use-security-key=1 \
    --session-save=files \
    --use-sample-data
  5. In your web browser, visit your website at https://local.domain.com or whatever domain you chose. The first time you go to access the site, it might take a couple of minutes for the page to load. This is because nothing is cached yet and the Magento system is automatically generating files as the page loads. Subsequent page loads will be faster. Additionally, because the web container uses a self-signed SSL certificate, the browser will likely present you with a security alert the first time you visit the URL. Just follow any prompts to add an exception so that you can proceed to the local website.
  6. Congratulations! You are now running Magento 2 on Docker. Keep in mind, this process is easily repeatable for other projects. While you might have spent a bit of time reading through this tutorial, once you have repeated the process a few times, it should only take you 15 minutes or less to spin up a brand new Magento 2 project.

Helpful Docker Information & Commands

Now that you have your Magento 2 project up and running on a series of Docker containers, I would like to share some useful information and commands with you so that you can get the most out of it.

Docker Info

  • Your database is persistent due to a data volume contained in the docker-compose.yml file. This means that when you tear down the virtual machine and spin it back up at a later date or time, your database will still be intact and ready to go.
  • If you would like to use Sequel Pro or some other tool to connect to the database, it is accessible at 127.0.0.1:3306. The username is root and the password is root. The name of the database is magento.
  • The VM includes phpMyAdmin for your convenience. It can be accessed from a web browser at 127.0.0.1:8080.

Docker Commands

  • Spin Up
    docker-compose up -d --build
  • Tear Down
    docker-compose down
  • Connect to web container CLI
    docker exec -it web bash
  • Connect to database container CLI
    docker exec -it mysql bash

About the Docker Image

We want to be sure to give credit where credit is due. On line 4 of the docker-compose.yml file is a reference to the image we use for the web service. That image is: webdevops/php-apache-dev and the docs regarding the image are located here. While I could have assembled my own custom image through the use of a Dockerfile, WebDevOps has gone through the trouble of creating approximately 20 different Docker images that are absolutely perfect for most projects. So a big thank you to WebDevOps for making these images available to the public!

Also in the Magento 2 Development Environment Series

38 Replies to “Docker for Magento 2 Development”

  1. Seems like everyone and their pet dog is hitting this error:

    Your requirements could not be resolved to an installable set of packages.

    Problem 1
    – Installation request for magento/product-community-edition 2.2.0 -> satisfiable by magento/product-community-edition[2.2.0].
    – magento/product-community-edition 2.2.0 requires ext-mcrypt * -> the requested PHP extension mcrypt is missing from your system.
    Problem 2
    – magento/framework 101.0.6 requires ext-mcrypt * -> the requested PHP extension mcrypt is missing from your system.

    Any suggestions for iOS? can’t seem to install this with brew.

    1. Try adding the –ignore-platform-reqs flag to your composer install command. What’s happening when you go to install is that composer is checking to see that your computer meets the requirements of the platform. But since Magento will actually be running inside of Docker, the extensions of your host/local computer aren’t relevant. Another alternative is that you can probably just run the composer install command inside of the Docker container. You can connect to the Docker container with “docker exec -it web bash” and then “cd /app” and in the /app dir is where you can run composer install.

  2. Is there a way to tell docker which version of php to run? Looks like it’s running 7.0.32 by default, but needs at least 7.1 for doctrine.

    1. Yes. The Docker image I use comes in many variations which you can see here. However, you can do this easily by following these steps:

      docker-compose down
      In your docker-compose.yml file, update the image tag from webdevops/php-apache-dev:ubuntu-16.04 to webdevops/php-apache-dev:7.1
      docker-compose up -d –build

      After you do that, you should be running 7.1.

  3. root@7c2017b03029:/app# bin/magento deploy:mode:set developer

    The file “/app/pub/static/adminhtml/Magento/backend/en_US/fonts/admin-icons/admin-icons.woff2” cannot be deleted Warn
    ing!unlink(/app/pub/static/adminhtml/Magento/backend/en_US/fonts/admin-icons/admin-icons.woff2): No such file or dire
    ctory

    How can i sovle this?

  4. I keep getting this error when running the docker-compose up -d –build command:

    “ERROR: for web Cannot create container for service web: invalid volume specification: ‘/Users/adamdarby/m2-sandbox/app:cached:rw’: invalid mount config for type “bind”: invalid mount path: ‘cached’ mount path must be absolute”

    The line in my yml file is:

    volumes:
    – /Users/adamdarby/m2-sandbox/app:cached

    Any ideas?

  5. The volume doesn’t seem to have write permissions as I keep getting the below mentioned error every time I access Magento.

    Fatal error: Uncaught Magento\Framework\Exception\FileSystemException: Directory “/app/var/page_cache” cannot be created Warning!mkdir(): Permission denied in /app/vendor/magento/framework/Filesystem/Driver/File.php on line 225

    From what I’ve found, the problem seems to be that all the directories inside the volume are owned by root. A container app can only write to these volumes if the app inside the container is also running as root which is said to be not recommended. Please suggest what changes I need to make to fix the permissions issue.

    TIA

    1. Thanks for letting me know the issue you’re facing. Fortunately, it’s easy to fix. Connect to the web container with docker exec -it web bash and then cd /app && chown -R application:application ./

      As a permanent fix, I am updating the docker-compose.yml file on the blog. Right after line 6, you can add user:application. Then docker-compose down && docker-compose up -d –build

      I hope this helps!

  6. Thanks Shawn for the great tutorial. I followed your tutorial and have 3 docker images on my local. I finished working on a magento site and want to export both the code and database. How do I export this image to either github/hub.docker.com so anyone could download the image and spin it which will generate the 3 images, website and the Database??

  7. This is all well and good but the past 6 months of experience on Mac OS have shown that there are severe issues with docker. The docs here https://docs.docker.com/docker-for-mac/troubleshoot/ clearly state:

    “There are a number of issues with the performance of directories bind-mounted with osxfs. In particular, writes of small blocks, and traversals of large directories are currently slow. Additionally, containers that perform large numbers of directory operations, such as repeated scans of large directory trees, may suffer from poor performance. Applications that behave in this way include:

    rake
    ember build
    Symfony
    Magento
    Zend Framework
    PHP applications that use Composer to install dependencies in a vendor folder”

    People need to be aware this is the case and it would be very helpful if Adobe/Magento could engage with docker to get these issues sorted.

    1. Hi Andrew, this is something I am fully aware of and it’s not much of an issue in this case. On line 18 of my sample docker-compose.yml file, I used “:cached” which relieves that issue a bit.

  8. Hello Shawn, thanks for the tutorial.
    I have followed all the steps in your youtube video, however when I proceed to ‘install magento’, it stucks at Module ‘Magento_ConfigurableSampleData’.
    I tried to use ‘ bin/magento setup:upgrade’ to check which module causing problem,
    it stucks at the same place ‘Magento_ConfigurableSampleData’ and showing the error:
    Area code not set: Area code must be set before starting a session.
    I have been googling for nights and tried to edit
    vendor/magento/module-configurable-sample-data/Setup/RecurringData.php
    nothing seems helping to solve.

    Can you please advice?
    I am trying to install magento 2.3 -develop

    Thanks a lot!

  9. Hi, when trying to run any command once in the web container to do with bin/magento, I get the following error?

    Could not open input file: bin/magento

    However if I run it in the root magento directory, without going through dockers web container, it’ll work fine. I’m also getting the following error when trying to install sample data.

    SQLSTATE[HY000] [2002] php_network_getaddresses: getaddrinfo failed: nodename nor servname provided, or not known

    In InstallCommand.php line 264:

    Parameter validation failed

    1. Hi Elliot, if you’ve followed the steps exactly and you’re on a Mac this shouldn’t happen for you. Here’s a couple of hint’s since I don’t know what steps you’ve taken.

      • Run docker inspect web to and look for the mounts section. Make sure your Magento root directory is mounted to the /app directory in your web container
      • When you docker exec -it web bash, you need to cd /app. /app is where the root is. Then you can run php bin/magento all your want
      • When you go to install the sample data, you need to do it from inside of docker. That’s because the webhost is aliased as “mysql” inside of docker. It’s a container link. Your mac doesn’t know “mysql” is the name of your db host. Howerver, you can add the line 127.0.0.1 mysql into your /etc/hosts file on your Mac and it will then know what “mysql” is pointing at.

      I hope this helps. If that doesn’t fix your problem, please run through the steps again. I know they work because I’ve been following my own instructions for years now. You likely just went wrong somewhere along the way.

  10. Thanks for replying so quickly!

    The volumes path in docker-compose.yml is setup as the following /Users/elliothagerty/Documents/WebDevelopment/****/Sites/new-****:/app:cached

    And the mounts is:

    “Mounts”: [
    {
    “Type”: “bind”,
    “Source”: “/Users/elliothagerty/Documents/WebDevelopment/****/Sites/****”,
    “Destination”: “/app”,
    “Mode”: “cached”,
    “RW”: true,
    “Propagation”: “rprivate”
    }
    ],

  11. Hello and thank for your guide. It works great!

    The only issue I’m facing is the speed. Because we mount the entire project folder, docker in order to keep everything sync. Even with the cached flag the speed is kinda unacceptable especially when we try to do development .

    For example when i disable the caches to develop something each page refresh takes easily 30 secs or more. My machine is iMac 2017 i7 32 gigs of ram and I gave everything to docker and in the php.ini. So basically my machine is kinda of a beast

    I know it’s a docker for mac issue but is there something you recommend?

    1. Hi Sakis, no doubt you have a powerful machine. However, Docker has it’s own memory limits so it you should check to see what your settings are and adjust if needed. I go with 4 cpus, 6gb ram, and 1gb swap. It doesn’t fly but its not that bad either.

      Additionally, I make sure I am in developer mode with all caches enabled except for full_page and block_html. Additionally, if I am updating layout xml files I also disable the layout cache.

      Another thing I find helpful is Vinai’s cache clean utility. Its a pretty great dev tool you can find here: https://github.com/mage2tv/magento-cache-clean

      Also, check .htaccess, .user.ini, pub/.htaccess, and pub/.user.ini and ensure that the memory limit is 2048GB.

      If none of this helps, you’ll probably want to profile any custom code or third party extensions as there is likely to be a bottleneck.

      I hope this helps!

  12. hi shawn,
    would you please help me solving this issue on ubuntu, “Could not open input file: bin/magento”
    i have double checked my docker-compose.yml and docker inspect web file, they all are up to mark.

  13. Hi Shawn,

    i am new to Docker and Mac.
    As i understood, i need to add the self-signed certificate to the keychain to create an exception for Chrome. But i can’t figure out where the certificate is located after spinning up the container.
    I would appreciated you help, thanks.

    1. Hi Nic, thanks for checking out my article. You shouldn’t need to do anything with the certificate itself. Chrome and Firefox should both give you a warning but you should be able to click a link and “accept the risk” and then no further action should be required.

      1. Hi,
        thank you for your quick reply.
        I am not even sure anymore if it is really the certificate. While i am trying to get into the backend i always geht a redirection error. I’ll check the tutorial again and hopefully i can find my mistake.

        1. Hi Nic, if youre getting a redirection error in the admin panel, its likely unrelated to the vm itself, maybe something to do with cookies or something. Try to access the admin panel from a different browser and see what happens.

          1. Good afternoon I am loving this tutorial, I have attempted to follow others but this has been incredibly clear. I am running into a problem when attempting to run php bin/mangento sampledate:deply in that I get
            [Magento supports PHP 7.1.3 or later. Please read……]

            Is there any way to get around this as I did with the –ignore-platform-reqs command in composer?

            Please let me know and thanks for putting this out there.

          2. It sounds like you are running your php commands on your computer instead of inside the Docker container. You should connect to the container and run it inside.

  14. Hi Shawn,

    This article too amazing.
    Could you please update more for docker-compose.yml file with Nodejs and Yarn?
    I’m trying to play with PWA at new magento version but can’t made it run.
    Thanks.

Leave a Reply

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