Docker infrastructure for managing multiple Magento 2 projects via nginx-proxy with simultaneous access to all instances. Useful for Magento 2 developers.
Magento 2 Docker infrastructure have the following structure:
nginx-proxy & shared infrastructure
βββ project1 infrastructure
βββ project2 infrastructure
βββ ...
βββ projectN infrastructure
βββ ...
Inspired by meanbee/docker-magento2
For Max OS X useful: https://www.meanbee.com/developers/magento2-development-procedure.html
-
Install & Configure docker-magento2-shared-infra
-
Prepare all config files:
- Run
make copy-configs- it will create config files from samples (will create./envs/composer.env,./envs/global.env,config.json).
make copy-configs
-
Fill COMPOSER_MAGENTO_USERNAME, COMPOSER_MAGENTO_PASSWORD, POSTFIX_SASL_PASSWD with you're data in
./envs/composer.env,./envs/global.env. Example of required field for./envs/composer.envfile:COMPOSER_MAGENTO_USERNAME={{repo.magento.com_username}} COMPOSER_MAGENTO_PASSWORD={{repo.magento.com_password}}
P.S. For existing project
{{repo.magento.com_username}}&{{repo.magento.com_password}}forcomposer.envcan be found inside{{magento_root}}/auth.json -
In
config.jsonupdate sections with you're data (read 'Single-store', 'Multi-store', 'Grunt' sections first), also check magento 2 system requirements:Option name Description M2_PROJECT Project name ( {{project_name}}) used to fill container hostname, etc. Example: magento2.dockerM2_VIRTUAL_HOSTS Comma separated list of all site domains ( {{all_site_domain}}). SeeSingle-storeorMulti-storesection.mkcertwill automatically create ssl certs.M2_DB_NAME Database name ( {{database_name}}) with pattern:{{client}}_{{project-name}}_{{dump-date}}. Example: someclient_someproject_20190710PHP_VERSION PHP version, available: 7.0, 7.1, 7.2, 7.3, 7.4, 8.0, 8.1, 8.2, 8.3, 8.4 M2_EDITION Magento edition. Options: community, enterprise, cloud, mage-os M2_VERSION Magento 2 version M2_SOURCE_VOLUME Magento root folder {{magento_root}}. Default: "./magento", example: "./source/src"M2_INSTALL: magento-installerconfig sectionβββ BASE_URL Main domain "http:// {{main_domain}}/" or "https". SeeSingle-storeorMulti-storesectionβββ SECURE_BASE_URL Main domain "https:// {{main_domain}}/". SeeSingle-storeorMulti-storesectionβββ INSTALL_DB Should magento-installerinstall database.βββ USE_SAMPLE_DATA Should magento-installerinstall magento sample data. Available: true, false, veniaβββ ADMIN_EMAIL Recommended use real email because starting from 2.4.0+ magento used 2FA by default βββ CRYPT_KEY if not empty magento-installerwill us this key else will generate randomM2_SETTINGS: Magento additional services settings βββ SEARCH_ENGINE_SETTINGS Search engine settings (Required unique index-prefix). If search_engine==false orsearch_engine/enabled==false will be ignore.βββ AMQ_SETTINGS AMQ settings. If rabbitmq==false will be ignoreβββ REDIS_SETTINGS Redis settings. If redis==false orredis/enabled==false will be ignore.βββ VARNISH_SETTINGS Varnish setting. If varnish==false will be ignoreDOCKER_SERVICES: βββ database: β βββ TYPE: Service type. Options: mariadb, mysql, percona β βββ VERSION: Service version. β βββ IMAGE: Optional. Service docker image. If not set, image will be defined based on TYPE. β βββ TAG: Optional. Service docker image tag. If not set, tag will be defined based on VERSION. β βββ VOLUME: Folder under mysql_volumes` that will be mounted to db container βββ search_engine: Use search engine service? Options: false, {} β βββ enabled: Is Service enabled? Options: true, false β βββ CONNECT_TYPE: Options: external (use shared search engine), internal (create separate container for project) β βββ TYPE: Service type. Options: elasticsearch, opensearch β βββ VERSION: Service version. If CONNECT_TYPE!=internal will be ignoreβ βββ IMAGE: Optional. Service docker image. If not set, image will be defined based on TYPE. β βββ TAG: Optional. Service docker image tag. If not set, tag will be defined based on VERSION. βββ varnish Use varnish service? Options: false, true βββ cron Use cron service? Options: false, true βββ redis Use redis service? Options: false, {} β βββ enabled: Is Service enabled? Options: true, false β βββ TYPE: Service type. Options: redis, valkey β βββ VERSION: Service version. β βββ IMAGE: Optional. Service docker image. If not set, image will be defined based on TYPE. β βββ TAG: Optional. Service docker image tag. If not set, tag will be defined based on VERSION. βββ rabbitmq Use rabbitmq service? Options: false, true βββ magento-coding-standard Create separate MCS container (need if project not contain latest MCS version: typical cloud and CE/EE before ver.2.4.4). Available options: false, true βββ venia Install veniaPWA and use magento as backend? Available options: false, true [Currently just install venia sample data]Section
php-containerscontain configuration for php-fpm, cli, msc container for each php version. Now"composerVersion": "latest"will set version 2.X for Magento 2.3.7 & 2.4.2+, in another case will set 1.10.17
- Run
-
Build magento 2 docker infrastructure:
make build
-
Make directory
{{magento_root}}inside project root directory{{root_directory}}. -
Up containers (first time up better don't add key
-dfor check if all okay,--remove-orphans- required, because latest compose doesn't always properly remove containers):docker compose up -d --remove-orphans
-
Clone existing repo with magento into
{{magento_root}}folder or run next command for install magento from scratch:docker compose run --rm cli magento-installer
-
Now you can enter to cli (you should run all magento commands under cli). P.S. Instead of
php bin/magentousesudo -uwww-data php bin/magento: Example :docker compose run --rm cli bash
-
If you clone existing repo import database:
- Copy database dump into
{{magento_root}}. - Go to cli-container & import database dump:
Import dump:
docker compose run --rm cli bash
Or using source:mysql -hdb -umagento2 -p {{youre_database_name}} < {{youre_database_dump}}Copy into right places undermysql -hdb -umagento2 -p use {{youre_database_name}}; source {{youre_database_dump}}{{magento_root}}all magento required secure sensitive file likeapp/etc/env.phpfile.
Inenv.phpfile used next config for a database:Maybe after you want to create admin user:'host' => 'db', 'dbname' => `{{database_name}}`, 'username' => 'magento2', 'password' => 'magento2',
sudo -uwww-data php bin/magento admin:user:create --admin-user="admin" --admin-password="admin123" --admin-email="[email protected]" --admin-firstname="AdminFirstName" --admin-lastname="AdminLastName"
- Update env.php with service configs (also need to do after updating additional docker services)
magento-service-updater
- Copy database dump into
config.jsonparams:{{all_site_domain}}same as{{main_domain}}(example: someproject.site)
- Add all you're site domain to
/etc/hostsfile:Example:# single-store sites (docker): ... 127.0.0.1 {{main_domain}} ... # end single-store sites (docker)
# single-store sites (docker): 127.0.0.1 some_anotherproject1.site 127.0.0.1 some_anotherproject2.site 127.0.0.1 someproject.site 127.0.0.1 some_anotherproject3.site # end single-store sites (docker)
Example: we have 3 store/website: someproject.site, someproject-vip.site, someproject-retail.site
config.jsonparams:{{all_site_domain}}- comma separated all site domains (example:someproject.site,someproject-vip.site,someproject-retail.site){{main_domain}}- So you should choose one domain main (example: we choosesomeproject.sitelike a{{main_domain}})
- In folder
{{root_directory}}/nginx/etc/multi_vhost/create one or ultiple own config file(s) for multi-store. Use fileexample_vhost.confas example. - Add space separated all you're site domain to
/etc/hostsfile:Example:# multi-store {{unique project name or main_domain or unique number}} (docker): 127.0.0.1 {{main_domain}} {{additional_domain_1}} ... {{additional_domain_N}} # end multi-store {{unique project name or number}} (docker)
# multi-store 9 (docker) 127.0.0.1 someproject.site someproject-vip.site someproject-retail.site 127.0.0.1 some_anotherproject2.site some_anotherproject2-vip.site some_anotherproject2-retail.site # end multi-store 9 (docker)
For use grunt need prepared magento grunt config file & init npm inside {{magento_root}} using cli-container.
Rename (create renamed copy) the following files in your Magento {{magento_root}}:
-
package.json.sample to package.json
-
Gruntfile.js.sample to Gruntfile.js Rename (create renamed copy) the following file:
-
{{magento_root}}/dev/tools/grunt/configs/themes.jsto{{magento_root}}/dev/tools/grunt/configs/local-themes.js -
Update local-themes.js by include your local site theme
-
Inside
{{root_directory}}:docker compose run --rm cli bash npm install npm update
Then in bash of cli-container got to magento root directory and use standard grunt command:
sudo -uwww-data grunt clean # Removes the theme related static files in the pub/static and var directories. sudo -uwww-data grunt exec # Republishes symlinks to the source files to the pub/static/frontend/ directory. sudo -uwww-data grunt less # Compiles .css files using the symlinks published in the pub/static/frontend/ directory. sudo -uwww-data grunt watch # Tracks the changes in the source files, recompiles .css files, and reloads the page in the browser.
Example of run grunt watch:
docker compose run --rm cli bash sudo -uwww-data grunt exec:all && sudo -uwww-data grunt less sudo -uwww-data grunt watch
P.S. LiveReloads the page in the browser not working.
Also Warning: Error compiling lib/web/css/docs/source/docs.less Use --force to continue. - it's magento native bug.
-
- Install & Enable the official Magento plugin for PphStorm.
- Enabled plugin for the project in Settings->PHP->Frameworks->Magento
- Config Project PHP CLI Interpreter:
Settings->Directories->Excluded files: *Test* P.S. not work with vendor/*Settings->PHP PHP Language level: `PHP_VERSION` CLI Interpreter: click '...' -> click '+' -> choose 'From Docker,...' Config Remote PHP Interpreter: choose 'Docker Compose' Name: 'cli' Service: 'cli' Path mapping: map `{{magento_root}}` in left column to path `/var/www/magento` inside container. -
- Enabled Xdebug in
./envs/global.envfile (PHP_XDEBUG_MODE=develop,debug,coverage- can be single mode or multimode). Add ConfigurationorEdit Configuration- Add
PHP remote debugName: Configuration IDE key(s): PHPSTORM Server: Name: Configuration host: localhost port: 80 Debuger: Xdebug Use path mapping: Yes map `{{magento_root}}` in left column to path `/var/www/magento` inside container - Apply this config
For cli debug:
sudo su -l www-data -s /bin/bash cd /var/www/magento/ && export XDEBUG_CONFIG="remote_host=host.docker.internal" php bin/magento setup:up # command for debug example exit
sudo su -l www-data -s /bin/bash cd /var/www/magento/ && export XDEBUG_CONFIG="client_host=host.docker.internal" php bin/magento setup:up # command for debug example exit
- Enabled Xdebug in
-
Currently, CE/EE ver.2.4.4+ contain one of the latest 'MCS' package version, so not need use separate 'MCS' container for it.
- If used separate 'MCS' container: on "Prepare all config files" step in
config.jsonsetmagento-coding-standardunderDOCKER_SERVICEStotrue. - Currently, PhpStorm don't have docker connection for eslint, so you need install npm on host machine.
- If used separate 'MCS' container: install Magento Coding Standard project
docker compose run --rm mcs magento-coding-standard-installer cd `{{root_directory}}/magento-coding-standard` npm init
- Config PhpStorm (after magento, magento-coding-standard projects (optional) was setup):
- If used separate 'MCS' container need create 'MCS' CLI Interpreter
Settings->Languages & Frameworks->PHP->Quality tools PHP_CodeSniffer: Configuration: click '...'-> PHP_CodeSniffer: click '+' -> PHP_CodeSniffer By Interpreter: click '...'-> CLI Interpreters: click '+' -> choose 'From Docker,...' Config Remote PHP Interpreter: choose 'Docker Compose' Name: 'mcs' Service: 'mcs' Path mapping: map <Project root>/magento-coding-standard->/var/www/magento-coding-standard. PHP_CodeSniffer path: `/var/www/magento-coding-standard/vendor/bin/phpcs` Path to phpcbf: `/var/www/magento-coding-standard/vendor/bin/phpcbf` Check files with extensions: 'php,js,css,inc,phtml' Show sniff name: Yes Coding Standard: Magento2 (if not see press reload & scroll up list) Enabled PHP_CodeSniffer by put swith to 'Yes' Settings->Editor->Inspection PHP->Quality tools ->PHP_CodeSniffer validation: Activate- If used 'MCS' package from magento project just use 'cli' container (see 'PphStorm Magento plugin' section):
Settings->Languages & Frameworks->PHP->Quality tools PHP_CodeSniffer: Configuration: choose 'cli' & click '...'-> PHP_CodeSniffer: click '+' -> PHP_CodeSniffer By Interpreter: choose 'cli' Path mapping: already filled. PHP_CodeSniffer path: `/var/www/magento/vendor/bin/phpcs` Path to phpcbf: `/var/www/magento/vendor/bin/phpcbf` Check files with extensions: 'php,js,css,inc,phtml' Show sniff name: Yes Coding Standard: Magento2 (if not see press reload & scroll up list) Enabled PHP_CodeSniffer by put swith to 'Yes' Settings->Editor->Inspection PHP->Quality tools ->PHP_CodeSniffer validation: Activate- Configure Mess Detector:
Settings->Languages & Frameworks->PHP->Quality tools Mess Detector: Configuration: choose 'cli' & click '...'-> Mess Detector: click '+' -> Mess Detector By Interpreter: choose 'cli' Path mapping: already filled. PHP Mess Detector path: already filled. Choose all 'Options' Add custom ruleset: path: {{absolute_path}}/magento/dev/tests/static/testsuite/Magento/Test/Php/_files/phpmd/ruleset.xml' Enabled PHP_CodeSniffer by put swith to 'Yes' Settings->Editor->Inspection PHP->Quality tools ->PHP Mess Detector validation: Activate- Configure ESlint:
Settings->Languages & Frameworks JavaScript->Code Quality Tools->ESLint: Manual ESLint configuration: ESLint package: {{absolute_path}}/magento-coding-standard/node_modules/eslint Configuration file: {{absolute_path}}/magento-coding-standard/eslint/.eslintrc Additional rules directory: {{absolute_path}}/magento-coding-standard/eslint/rules
For upgrade magento coding standard enter inside mcs container:
docker compose run --rm mcs bash <!-- upgrade comands --> ...
- If used separate 'MCS' container: on "Prepare all config files" step in
-
Install ngrok. Copy
ngrokto/usr/local/binfor run ngrok from any folder by command 'ngrok'. -
Download & install magento ngrok extension to app/code/Shkoliar/Ngrok folder.
-
Run to cli container and set
sudo -uwww-data php bin/magento config:set --lock-env web/url/redirect_to_base 0. -
Redeploy project: set:up, s:d:c, etc.
-
Run ngrok with additional param host-header. Example
ngrok http https://magento248.site --host-header=magento248.site: P.S.{{BASE_URL}}===http://{{main_domain}}/orhttps://{{main_domain}}/ngrok http {{BASE_URL}} --host-header={{main_domain}} # tested with http/https as `{{BASE_URL}}`How it works: internet->ngrok->reverse-proxy->project-entrypoint(nginx/varnish->nginx->varnish)->reverse-proxy->ngrok->internet
P.S. It for local development - do not commit Shkoliar_Ngrok into project git. Alternative:
ngrok http --host-header={{local_site_domain}} 80 # work for http only ngrok http {{BASE_URL}}:80 --host-header={{main_domain}} # additional specified port ngrok http {{BASE_URL}}:443 --host-header={{main_domain}} # additional specified port
-
For debug inside 'ubuntu' container (docker exec -it {{container}} bash):
sudo apt-get install nano sudo apt-get install rsyslog sudo apt-get install telnet sudo apt-get install dnsutils sudo apt-get install iputils-ping
-
For debug inside 'alpine' container (docker exec -it {{container}} sh):
yum install iputils
-
In Mysql:
mysql -hdb -umagento2 -p
show databases;
create database {{youre_database_name}};GRANT ALL PRIVILEGES ON {{youre_database_name}}.* TO 'magento2'@'%'; - add user `magento2` grant for {{youre_database_name}}
use {{youre_database_name}};source {{youre_database_dump}}Change password:
UPDATE mysql.user SET Password=PASSWORD('root') WHERE User='root'; FLUSH PRIVILEGES;
-
PphStorm & Database Get real db host & port (this info can be find using next command):
docker ps -a
Next use it when connected to db by PphStorm
If you can't edit the magento files in PhpStorm, try it:
sudo usermod -aG www-data ${USER}
sudo chmod -R g+w magentoFix problem with owner:
sudo chown -R www-data:www-data var/cacheExample of fix permission problem inside cli-container:
sudo chown -R www-data:www-data $MAGENTO_ROOT && sudo chmod -R g+w $MAGENTO_ROOT && rm -rf var/cache && rm -rf var/page_cache && rm -rf var/generation && rm -rf var/session- Implement https functional.
- Implement Venia Sample Data.
- Implement configuration for Magento PWA.
Because Venia required worked connection to magento 2 think at least as next step is create separate docker-compose.yml in
{{root_directory}}/magento_veniadirectory. PWA project should be initiated in{{root_directory}}/magento_venia/source. In VeniaDEV_SERVER_HOST=={{main_domain}},DEV_SERVER_PORT==443. Also need to create custom makeHostAndCert.js that respectNGINX_PROXY_PATHvenia docker-compose.yml example for connect to magento 2 as backend (need check if exists better way):
version: '2'
services:
pwa:
...
external_links:
- "web.{{project_name}}:{{main_domain}}" #need implement auto genatation via `php builder.php`
- "web.{{project_name}}:{{second_domain}}"
...
- "web.{{project_name}}:{{last_domain}}"
networks:
- default
- nginx-proxy
# used external proxy for use local magento 2 as backend
networks:
nginx-proxy:
external: trueversion: '3.9'
services:
pwa:
...
[WIP]??? Need test configuration
networks:
- default
- nginx-proxy
# used external proxy for use local magento 2 as backend
networks:
nginx-proxy:
external: true- Add additional service configuration (redis, rabbitmq)
- Implement https functional for single store.
- Implement https functional for multi-stores.
- Implement configuration for Magento PWA.
- Implement configuration for Magento Coding Standard.
- Implement internal elasticsearch/opensearch service.
-
Implement bash scripts for auto-generate ssl certificate - Implement auto-generate ssl certificate (
mkcertfrom docker-magento2-shared-infra) - Implement bash scripts for set/update default services configs to env.php
- Implement LiveReload
- Implement dynamic varnish configs during build docker infrastructure (like it was done for php containers)
- Implement dynamic internal elasticsearch/opensearch configs during build docker infrastructure (like it was done for php containers)
- Implement dynamic redis configs during build docker infrastructure (like it was done for php containers)
- Implement ngrok support via magento ngrok extension
- Replace the custom template engine via Twig templae engine
- Implement SPX - A simple profiler for PHP