Skip to content
On this page

Build a docker container for my Magento store

Docker is a powerful tool that can help developers streamline their development process and improve consistency across different environments. In this tutorial, we will walk through the steps to containerize a Magento 2 project.

Step 1: Prepare your application

Before you begin, you will need a valid app/etc/config.php with a few specific settings. Specifically, the scopes and themes settings. These settings must be added to your config.php ahead of time in order for you to containerize Magento 2.

TIP

If are migrating to Mappia and you have a running store already, you can use bin/magento app:config:dump to generate these values. For our purposes, we really only need the scopes and themes key, however you can include whatever else you think is useful cross-environment.

Be aware that by moving the scopes and themes into app/etc/config.php, you will be preventing business users from adding new stores in the admin panel. Consider this carefully.

DANGER

Do not run bin/magento app:config:dump in production. You will lock the admin system configurations and someone will eventually be upset at you.

You should create a local version of your production application and run the command there.

Below is an example of what a sample config.php should look like.

php
<?php
return [
    'modules' => [
        'Magento_Store' => 1,
        ...
        'Magento_Wishlist' => 1,
        'Magento_WishlistAnalytics' => 1,
        'Magento_WishlistGraphQl' => 1,
        ...
    ],
    'scopes' => [
        'websites' => [
            'admin' => [
                'website_id' => '0',
                'code' => 'admin',
                'name' => 'Admin',
                'sort_order' => '0',
                'default_group_id' => '0',
                'is_default' => '0',
            ],
            'base' => [
                'website_id' => '1',
                'code' => 'base',
                'name' => 'default-website',
                'sort_order' => '0',
                'default_group_id' => '1',
                'is_default' => '1',
            ],
        ],
        'groups' => [
            0 => [
                'group_id' => '0',
                'website_id' => '0',
                'name' => 'Default',
                'root_category_id' => '0',
                'default_store_id' => '0',
                'code' => 'default',
            ],
            1 => [
                'group_id' => '1',
                'website_id' => '1',
                'name' => 'Default Store',
                'root_category_id' => '2',
                'default_store_id' => '1',
                'code' => 'main_website_store',
            ],
        ],
        'stores' => [
            'admin' => [
                'store_id' => '0',
                'code' => 'admin',
                'website_id' => '0',
                'group_id' => '0',
                'name' => 'Admin',
                'sort_order' => '0',
                'is_active' => '1',
            ],
            'default' => [
                'store_id' => '1',
                'code' => 'default',
                'website_id' => '1',
                'group_id' => '1',
                'name' => 'English',
                'sort_order' => '0',
                'is_active' => '1',
            ],
        ],
    ],
    'themes' => [
        'adminhtml/Magento/backend' => [
            'parent_id' => null,
            'theme_path' => 'Magento/backend',
            'theme_title' => 'Magento 2 backend',
            'is_featured' => '0',
            'area' => 'adminhtml',
            'type' => '0',
            'code' => 'Magento/backend',
        ],
    ]
];

Step 2: Setup

Next, install Docker on your machine if you haven't already done so. Once Docker is installed, we need to create a Dockerfile to define the image that we will use to run our Magento 2 application.

You can put this Dockerfile anywhere in your project, but for a sane default, the docker folder is a nice organizational folder for all docker related artifacts.

bash
mkdir -p docker
# We want to ignore the docker folder to allow faster rebuilds.
touch .dockerignore && echo "docker" >> .dockerignore
touch docker/Dockerfile

The Dockerfile should contain the following code:

docker
ARG BASE_IMAGE="graycore/magento-php:8.1-fpm-alpine-v6.0.0-alpha.4"

FROM ${BASE_IMAGE}

WORKDIR /var/www/html

COPY ./ .

## Install Composer Dependencies
## Make sure that the composer auth.json file isn't stored in a temporary layer
RUN --mount=type=secret,id=composer.auth,target=/root/.composer/auth.json,required \
      composer install --no-dev --no-ansi --no-interaction --no-progress --no-suggest

RUN php bin/magento setup:di:compile &&  \
    composer dump-autoload -o --classmap-authoritative \
    && php bin/magento setup:static-content:deploy -f --theme $YOUR_THEME_HERE --theme Magento\backend \
    && find var pub/media -type f -exec chmod g+w {} + \
    && find var pub/media -type d -exec chmod g+ws {} + \
    && chown -R :www-data var pub/media \ 
    && chmod u+x bin/magento

Let's break down what's going on:

Setting the stage

docker
ARG BASE_IMAGE="graycore/magento-php:8.1-fpm-alpine-v6.0.0-alpha.4"

FROM ${BASE_IMAGE}

This Dockerfile uses the official Graycore Magento 2 PHP images as a base, but it allows you to swap out the base image to whatever you would like. This will be useful when we decide to switch between the cli and fpm bases.

TIP

The prebuilt Graycore images are base images which should work for most Magento 2 stores. However, you can replace them with your own image if you have other requirements.

Putting the pieces in place

The next entries put your application into the /var/www/html container.

docker
WORKDIR /var/www/html

COPY ./ .

Installing dependencies

Next, we install dependencies, but importantly, we use an uncached env argument (composer.auth) for the composer authentication so that we don't accidentally store license keys in the final image.

docker
## Install Composer Dependencies
## Make sure that the composer auth.json file isn't stored in a temporary layer
RUN --mount=type=secret,id=composer.auth,target=/root/.composer/auth.json,required \
      composer install --no-dev --no-ansi --no-interaction --no-progress --no-suggest

Compilation

We compile the app.

RUN php bin/magento setup:di:compile &&  \    

Improving Composer Performance

docker
    composer dump-autoload -o --classmap-authoritative \

Static-content deploy

docker
    && php bin/magento setup:static-content:deploy -f --theme $YOUR_THEME_HERE \

File Permissions

Finally, we set file permissions for the application runtime.

docker
    && find var pub/media -type f -exec chmod g+w {} + \
    && find var pub/media -type d -exec chmod g+ws {} + \
    && chown -R :www-data var pub/media \ 
    && chmod u+x bin/magento

Step 3: Build the images

Mappia requires two images to operate effectively. Firstly, the cli image, which is a php image without fpm, and secondly fpm which is the image that contains php-fpm which will ultimately process requests.

You can build these images using the docker cli:

bash
docker build . -f docker/Dockerfile -t my-magento2-image:cli-v1.0.0 \
    --secret id=composer.auth,src=auth.json \
    --build-arg BASE_IMAGE=graycore/magento-php:8.1-alpine-v6.0.0

docker build . -f docker/Dockerfile -t my-magento2-image:fpm-v1.0.0 \
    --secret id=composer.auth,src=auth.json \
    --build-arg BASE_IMAGE=graycore/magento-php:8.1-fpm-alpine-v6.0.0

Step 4: Publish the images

Assuming that your images built successfully, you're now ready to publish these images to your registry of choice!

This process typically looks like:

bash
docker login $REGISTRY_NAME
docker push my-magento2-image:fpm-v1.0.0

Next Steps

You are now ready to deploy with Mappia! You can now proceed to: