Introduction:
Ever wondered how much time the average developer spends just setting up a reliable local development environment? The answer definitely varies from organization to organization, the stack in question, and the level of documentation available. I think most developers, no matter what industry or stack they work in, can relate to personally struggling to set up an environment or seeing a developer on their team struggle with the process, however.
When I first started my professional software development journey, I was hired as a Magento 2 intern and this is something I struggled with for a while. At that time, using docker to accomplish my local development goals seemed like a huge undertaking. This article is hopefully just one in a series of articles that will make using Docker less intimidating and help other developers get up and running quickly. The configurations shared are what we use at www.www.peoplelikesoftware.com but your specific requirements may differ, nonetheless, I think this article can help you get to where you want to be in less time. The ins and outs of Docker will be discussed in later articles since including all of that in this one article would probably be information overload.
Instructions:
1. Install docker
sudo apt-get update && sudo apt-get install docker-ce docker-ce-cli containerd.io
To install a specific version of docker or if you run into any issues, review the documentation at this link https://docs.docker.com/engine/install/ubuntu/
2. Create a new working directory
mkdir magento-local-env && cd magento-local-env
3. Add a new domain to your /etc/hosts file, this domain will be used to navigate to your local Magento 2 instance
sudo su
echo “127.0.0.1 local.magento.com” >> /etc/hosts
exit
4. Create a docker-compose.yaml file and paste the configurations below into it.
vi docker-compose.yamlornano docker-compose.yaml
Docker-compose.yaml’s contents should be as follows:
version: '2.1'
services:
db:
hostname: db.magento2.docker
image: 'mariadb:10.1'
environment:
- MYSQL_ROOT_PASSWORD=magento2
- MYSQL_DATABASE=magento2
- MYSQL_USER=magento2
- MYSQL_PASSWORD=magento2
ports:
- '3306'
volumes:
- 'mymagento-magento-sync:/app:delegated'
- 'mymagento-magento-db:/var/lib/mysql'
healthcheck:
test: 'mysqladmin ping -h localhost'
interval: 30s
timeout: 30s
retries: 3
networks:
magento:
aliases:
- db.magento2.docker
redis:
hostname: redis.magento2.docker
image: 'redis:5.0'
volumes:
- 'mymagento-magento-sync:/app:delegated'
ports:
- 6379
healthcheck:
test: 'redis-cli ping || exit 1'
interval: 30s
timeout: 30s
retries: 3
networks:
magento:
aliases:
- redis.magento2.docker
elasticsearch:
hostname: elasticsearch.magento2.docker
image: 'magento/magento-cloud-docker-elasticsearch:6.5-1.1'
networks:
magento:
aliases:
- elasticsearch.magento2.docker
fpm:
hostname: fpm.magento2.docker
#image: 'magento/magento-cloud-docker-php:7.3-fpm-1.1'
build: '.docker/PHP/'
extends: generic
volumes:
- 'mymagento-magento-sync:/app:delegated'
networks:
magento:
aliases:
- fpm.magento2.docker
depends_on:
db:
condition: service_healthy
web:
hostname: web.magento2.docker
image: 'magento/magento-cloud-docker-nginx:latest-1.1'
extends: generic
ports:
- '80:80'
volumes:
- 'mymagento-magento-sync:/app:delegated'
environment:
- VIRTUAL_HOST=magento2.docker
- VIRTUAL_PORT=80
- HTTPS_METHOD=noredirect
- WITH_XDEBUG=1
networks:
magento:
aliases:
- web.magento2.docker
depends_on:
fpm:
condition: service_started
varnish:
hostname: varnish.magento2.docker
image: 'magento/magento-cloud-docker-varnish:6.2'
networks:
magento:
aliases:
- magento2.docker
depends_on:
web:
condition: service_healthy
tls:
hostname: tls.magento2.docker
image: 'magento/magento-cloud-docker-tls:latest-1.1'
ports:
- '443:443'
environment:
HTTPS_UPSTREAM_SERVER_ADDRESS: varnish
networks:
magento:
aliases:
- tls.magento2.docker
depends_on:
varnish:
condition: service_started
generic:
hostname: generic.magento2.docker
image: 'alpine:latest'
env_file: ./.docker/config.env
environment:
- MAGENTO_RUN_MODE=developer
- 'PHP_EXTENSIONS=bcmath bz2 calendar exif gd gettext intl mysqli pcntl pdo_mysql soap sockets sysvmsg sysvsem sysvshm opcache zip sodium redis xsl blackfire'
build:
hostname: build.magento2.docker
image: 'magento/magento-cloud-docker-php:7.3-cli-1.1'
extends: generic
volumes:
- 'mymagento-magento-sync:/app:delegated'
networks:
magento-build:
aliases:
- build.magento2.docker
depends_on:
db:
condition: service_healthy
redis:
condition: service_healthy
elasticsearch:
condition: service_healthy
deploy:
hostname: deploy.magento2.docker
image: 'magento/magento-cloud-docker-php:7.3-cli-1.1'
extends: generic
volumes:
- 'mymagento-magento-sync:/app:delegated'
networks:
magento:
aliases:
- deploy.magento2.docker
depends_on:
db:
condition: service_healthy
redis:
condition: service_healthy
elasticsearch:
condition: service_healthy fpm_xdebug:
hostname: fpm_xdebug.magento2.docker
image: 'magento/magento-cloud-docker-php:7.3-fpm-1.1'
extends: generic
ports:
- '9001:9001'
volumes:
- 'mymagento-magento-sync:/app'
environment:
- 'PHP_EXTENSIONS=bcmath bz2 calendar exif gd gettext intl mysqli pcntl pdo_mysql soap sockets sysvmsg sysvsem sysvshm opcache zip redis xsl sodium xdebug'
- XDEBUG_CONFIG=remote_host=host.docker.internal remote_autostart=On remote_enable=On idekey=XDEBUG remote_log=/tmp/xdebug.log remote_port=9000
networks:
magento:
aliases:
- fpm_xdebug.magento2.docker
depends_on:
db:
condition: service_started
mailhog:
hostname: mailhog.magento2.docker
image: 'mailhog/mailhog:latest'
restart: always
ports:
- '1025:1025'
- '8025:8025'
networks:
magento:
aliases:
- mailhog.magento2.docker
volumes:
mymagento-magento-sync:
driver_opts:
type: none
device: '${PWD}/mymagento-magento-sync'
o: bind
mymagento-magento-db: { }
networks:
magento:
driver: bridge
magento-build:
driver: bridge
5. Create Dockerfile at the location .docker/PHP/Dockerfile using the commands below
mkdir -p .docker/PHP/ && touch .docker/PHP/Dockerfile
5b. Copy the below content.
FROM php:7.3-fpm
RUN apt-get update && apt-get install -y \
cron \
git \
libfreetype6-dev \
libicu-dev \
libjpeg62-turbo-dev \
libmagickwand-dev \
libmcrypt-dev \
libpng-dev \
libxslt1-dev \
default-mysql-client \
vim \
zip \
libzip-dev \
wget \
net-tools \
netcat
RUN docker-php-ext-configure \
gd --with-freetype-dir=/usr/include/ --with-jpeg-dir=/usr/include/
RUN docker-php-ext-install \
bcmath \
gd \
gettext \
intl \
mbstring \
opcache \
pdo_mysql \
soap \
xsl \
zip \
sockets
RUN pecl channel-update pecl.php.net \
&& pecl install xdebug \
&& docker-php-ext-enable xdebug \
&& sed -i -e 's/^zend_extension/\;zend_extension/g' /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini
RUN pecl install imagick-3.4.3 \
&& docker-php-ext-enable imagick
RUN curl -sS https://getcomposer.org/installer | \
php -- --install-dir=/usr/local/bin --filename=composer
RUN wget https://github.com/mailhog/mhsendmail/releases/download/v0.2.0/mhsendmail_linux_amd64 \
&& chmod +x mhsendmail_linux_amd64 \
&& mv mhsendmail_linux_amd64 /usr/local/bin/mhsendmail
COPY conf/php.ini /usr/local/etc/php/
WORKDIR /app
EXPOSE 9001
Paste it into .docker/PHP/Dockerfile
vi .docker/PHP/Dockerfile
or
nano .docker/PHP/Dockerfile
6. Create a new directory named conf; add a file named php.ini in that directory.
mkdir -p .docker/PHP/conf/
cd .docker/PHP/conf/
vi php.ini
The path should be magento-local-env/.docker/PHP/conf/php.ini
7. Paste the following content into magento-local-env/.docker/PHP/conf/php.ini
memory_limit = 2G
max_execution_time = 1800
zlib.output_compression = On
cgi.fix_pathinfo = 0
date.timezone = UTC
8. Move back into the root dir
cd ../../../
9. Compose the local environment
touch .docker/config.php
touch .docker/config.env
mkdir mymagento-magento-syncdocker-compose -f docker-compose.yaml up --build -d
docker ps -a
It’s ok if the build or deploy container has an error or is “unhealthy”.
10. Tail the db container’s logs until you see “ready for connections”
docker logs magento-local-env_db_1 -f
11. Access the fpm containers cli
docker exec -it magento-local-env_fpm_1 bash
12. Use composer to create and install Magento 2, move all of the contents of the Magento package into the /app dir
You will need to enter your Magento account credentials from https://marketplace.magento.com/customer/accessKeys/
The public key is the username, the private key is the password. If you don’t already have a Magento account/key pair just create one/them. It’s free 🙂
Reference: https://devdocs.magento.com/guides/v2.4/install-gde/prereq/connect-auth.html
composer create-project --repository-url=https://repo.magento.com/ magento/project-community-edition=2.3.5p2
mv project-community-edition/* .
rm -rf project-community-edition/
The public key is the username, the private key is the password. If you don’t already have a Magento account/key pair just create one/them. It’s free 🙂 Enter your Magento account credentials from https://marketplace.magento.com/customer/accessKeys/
13. Set file permissions
find var generated vendor pub/static pub/media app/etc -type f -exec chmod g+w {} +
find var generated vendor pub/static pub/media app/etc -type d -exec chmod g+ws {} +
chown -R :www-data . # Ubuntu
chmod u+x bin/magento
14. Create an env.php file
exit
cd mymagento-magento-sync/app/etcsudo
vi env.php
Write your own custom configurations or paste the content below into the file.
Fyi, the reason I did not opt to create the file inside the fpm container is that vi doesn’t work as expected when trying to paste something inside the container for some reason.
Sample env.php below :
<?php
return [
'MAGE_MODE' => 'developer',
'cache_types' => [
'compiled_config' => 1,
'config' => 1,
'layout' => 1,
'block_html' => 1,
'collections' => 1,
'reflection' => 1,
'db_ddl' => 1,
'eav' => 1,
'customer_notification' => 1,
'config_integration' => 1,
'config_integration_api' => 1,
'target_rule' => 1,
'full_page' => 1,
'translate' => 1,
'config_webservice' => 1,
'vertex' => 1
],
'backend' => [
'frontName' => 'admin'
],
'db' => [
'connection' => [
'default' => [
'username' => 'magento2',
'host' => 'magento-local-env_db_1',
'dbname' => 'magento2',
'password' => 'magento2'
],
'indexer' => [
'username' => 'magento2',
'host' => 'magento-local-env_db_1',
'dbname' => 'magento2',
'password' => 'magento2'
]
]
],
'crypt' => [
'key' => ''
],
'resource' => [
'default_setup' => [
'connection' => 'default'
]
],
'x-frame-options' => 'SAMEORIGIN',
'session' => [
'save' => 'redis',
'redis' => [
'host' => 'magento-local-env_redis_1',
'port' => 6379,
'database' => 0,
'disable_locking' => 1
]
],
'install' => [
'date' => 'Fri, 15 Jun 2018 10:17:40 +0000'
],
'static_content_on_demand_in_production' => 0,
'force_html_minification' => 1,
'cron_consumers_runner' => [
'cron_run' => false,
'max_messages' => 10000,
'consumers' => [
]
],
'cache' => [
'frontend' => [
'default' => [
'backend' => 'Cm_Cache_Backend_Redis',
'backend_options' => [
'server' => 'magento-local-env_redis_1',
'port' => 6379,
'database' => 1
]
],
'page_cache' => [
'backend' => 'Cm_Cache_Backend_Redis',
'backend_options' => [
'server' => 'magento-local-env_redis_1',
'port' => 6379,
'database' => 2
]
]
]
],
'directories' => [
'document_root_is_pub' => true
],
'cron' => [
],
'lock' => [
'provider' => 'db',
'config' => [
'prefix' => null
]
]
];
15. Go back to the root directory and access the fpm containers cli again
cd ../../../docker exec -it magento-local-env_fpm_1 bash
16. Run the Magento 2 install command inside the container
Reference: https://devdocs.magento.com/guides/v2.4/install-gde/composer.html
bin/magento setup:install \
--base-url=http://local.magento.com \
--db-host=magento-local-env_db_1 \
--db-name=magento2 \
--db-user=magento2 \
--db-password=magento2 \
--admin-firstname=admin \
--admin-lastname=admin \
[email protected] \
--admin-user=admin \
--admin-password=admin123 \
--language=en_US \
--currency=USD \
--timezone=America/Chicago \
--use-rewrites=1
** If you changed the base-url in the command above, remember to update your /etc/hosts file ***
17. (Optional) Install sample data
bin/magento sampledata:deploy
18. Navigate to local.magento.com or your custom domain and you’re done !!!
If you got this far. Please leave a comment or share. I’d love to hear what you think about the article whether you hated or loved it. Stay tuned for my next article in which I demonstrate how to create a docker-compose file with one command using Magento Cloud’s ece-tools package. Thanks.