Containerizing Magento with Docker Compose: Elasticsearch, MySQL and Magento
Magento is a complex piece of software, and as such, we need all the help we can get when it comes to developing customizations for it. A fully featured local development environment can do just that, but these can often times be very complex as well. It’d be nice to have some way to completely capture all the setup for such an environment and be able to get it all up and running quickly, repeatably… even with a single command. Well, Docker containers can help with that. And they can be easily provisioned with the Docker Compose tool.
In this post, we’re going to go in depth into how to fully containerize a Magento 2.4 installation for development, complete with its other dependencies Elasticsearch and MySQL. By the end of it, we’ll have a single command that sets up all the infrastructure needed to install and run Magento, and develop for it. Let’s get started.
Magento 2.4 application components
The first thing that we need to know is what the actual components of a Magento application are. Starting with 2.4, Magento requires access to an Elasticsearch service to power catalog searches. Other than that, we have the usual suspects for typical PHP applications. Here’s what we need:
- MySQL
- Elasticsearch
- A web server running the Magento application
In terms of infrastructure, this is pretty straightforward. It would cleanly translate into three separate machines talking to each other via the network, but in the Docker world, each of these machines become containers. Since we need multiple containers for our infrastructure, things like Docker Compose can come in handy to orchestrate the creation of all that. So let’s get to it.
Creating a shared network
Since we want to create three separate containers that can talk to each other, we need to ask the Docker engine to create a network for them. This can be done with this self-explanatory command:
docker network create magento-demo-network
magento-demo-network
is the name I’ve chosen for my network but you can choose whatever is most appropriate.
You can run the following command to check your newly created network:
docker network ls
Output usually looks like this:
$ docker network ls
NETWORK ID NAME DRIVER SCOPE
bd562b9cf5a4 bridge bridge local
adb9ec2365c5 host host local
2dba8d97410e magento-demo-network bridge local
c3473c60ed52 none null local
There’s our magento-demo-network
network among other networks that Docker creates by default.
Containerizing MySQL
Getting a MySQL instance up and running is super easy these days thanks to Docker. There’s already an official image for MySQL in Docker Hub so we will use that. We can set it up with this command:
docker run -d \
--name magento-demo-mysql \
--network magento-demo-network \
--network-alias mysql \
-p 3306:3306 \
-v magento-demo-mysql-data:/var/lib/mysql \
-e MYSQL_ROOT_PASSWORD=password \
-e MYSQL_USER=kevin \
-e MYSQL_PASSWORD=password \
-e MYSQL_DATABASE=magento_demo \
mysql:5.7
And just like that, we have a running MySQL instance. Running docker ps
can get you a list of currently running containers. The one we just created should show up there.
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b73739ad5d66 mysql:5.7 "docker-entrypoint.s…" 22 seconds ago Up 21 seconds 0.0.0.0:3306->3306/tcp, 33060/tcp magento-demo-mysql
Let’s go through each one of the options from that command now to understand it better.
docker run -d
: Runs the container in detached mode. This means that it’s run in the background as a daemon. Control is returned to the console immediately.--name magento-demo-mysql
: This is the name of our container. Normally, Docker will generate random names for containers. In this case, we want to give it a name to refer to it with other Docker commands.--network magento-demo-network
: Tells Docker to run the container as part of themagento-demo-network
network that we created earlier. This is the network that we will use for all of our containers.--network-alias mysql
: This is the name of this container within the network. This is how other containers in the network will be able to reference it. We’ll see that come to life a bit later.-p 3306:3306
: Sets up our new MySQL container to allow connections over port3306
. This is MySQL’s default port, which Magento will use to connect to it. This basically says “requests coming over the network to port3306
of this container are going to be handled by the service installed in this container that listens to port3306
”. That service happens to be MySQL.-v magento-demo-mysql-data:/var/lib/mysql
: Creates a Docker volume. Specifically, we’re setting this one up to store the data files from MySQL. We need to do this so that the data stored in our MySQL container is persisted across shutdowns.magento-demo-mysql-data
is the name of the volume and/var/lib/mysql
is the directory within the MySQL container where that volume is mounted. In other words, any files stored in that directory are going to be stored within the volume instead. The volume is stored by Docker in the host machine, outside the container./var/lib/mysql
is the default directory where MySQL stores databases.-e MYSQL_ROOT_PASSWORD=password
: Is the password for the root user for MySQL. This is passed into the containerized MySQL via environment variables. Hence the-e
option.-e MYSQL_USER=kevin
: Creates a new login in MySQL withkevin
as its username.-e MYSQL_PASSWORD=password
: Sets the wordpassword
as the password for thatkevin
user.-e MYSQL_DATABASE=magento_demo
: Creates a database namedmagento_demo
.mysql:5.7
: This is the image that we’re using for our container.5.7
specifies the version that we want to run. Themysql
image in Docker Hub contains a few more versions. Or “tags”, in Docker words.
Connecting to this container
docker ps
showed us that our container was running. We can also interact with it. Here are a couple of ways of doing it:
Connecting from within the container
The easiest way of connecting to the MySQL instance is by running mysql
CLI client from within the container itself. You can do that with:
docker exec -it magento-demo-mysql mysql -u kevin -p
Here’s how that command works:
docker exec -it
is used to run commands inside a container in interactive mode. Just what we need here in this case because we’re runningmysql
, which is an interactive CLI.magento-demo-mysql
is the name we gave our container in thedocker run
command from before via the--name magento-demo-mysql
option. This is why it’s useful to give names to containers: so we can use them in commands like this.mysql -u kevin -p
is the command that’s run within the container. This is just the usual way of connecting to a MySQL server instance using themysql
CLI client. We usekevin
because that’s what we setMYSQL_USER
to when we created our container before.
After running the previous command, the console will ask you for your password. We set that to password
via MYSQL_PASSWORD
so that’s what we need to type in. This will eventually result in the mysql
prompt showing up. Run show databases
to confirm that the magento_demo
database that we specified via MYSQL_DATABASE
got created.
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| magento_demo |
+--------------------+
2 rows in set (0.00 sec)
You can Ctrl + D
your way out of that when you’re done exploring the containerized MySQL instance.
Connecting directly from the host machine
We can also connect to the MySQL instance running in the container, directly from our host machine. We can use:
mysql -h localhost -P 3306 --protocol=tcp -u kevin -p
Note that it is required that the
mysql
CLI client is installed in the host machine for this to work.
Same as before, mysql
will ask you for the password and, once typed in, it will give you its prompt.
Containerizing Elasticsearch
Like MySQL, there’s an official Elasticsearch Docker image up in Docker Hub. As a result, getting a working Elasticsearch installation is a piece of cake. It’s done with a command like this:
docker run -d \
--name magento-demo-elasticsearch \
--network magento-demo-network \
--network-alias elasticsearch \
-p 9200:9200 \
-p 9300:9300 \
-e "discovery.type=single-node" \
elasticsearch:7.8.1
You can validate that the Elasticsearch is running with curl localhost:9200/_cat/health
. That should return something like this:
$ curl localhost:9200/_cat/health
1597622135 23:55:35 docker-cluster green 1 1 0 0 0 0 0 0 - 100.0%
Alright! That was easy enough. Again, thanks to Docker, we have an application that’s somewhat complex to set up, up and running in a matter of seconds.
Like before, let’s dissect that command that we used. Very similar to the MySQL one, only with some Elasticsearch specific settings:
docker run -d
: Same as with the MySQL container, runs it in detached mode.--name magento-demo-elasticsearch
: Gives the container a friendly name.--network magento-demo-network
: Puts the container in the same network as the rest of our infrastructure.--network-alias elasticsearch
: Is the name by which other containers in the network can refer to this contianer.-p 9200:9200
: Opens port9200
so that other containers within the network can talk to this one.-p 9300:9300
: Same thing but for a different port.-e "discovery.type=single-node"
: Sets up thediscovery.type
environment variable that the image uses to configure Elasticsearch with.elasticsearch:7.8.1
: Specifies that our container will be running version7.8.1
of Elasticsearch.
Containerizing Magento
Now this is the step where things get a little bit more involved. Nothing crazy however, so let’s get into it.
The Dockerfile
There’s no image of Magento 2 that would be able to get us up and running as quickly as with MySQL or Elasticsearch, at least not that I could find, so we’re going to have to create our own. We can create our own images with the help of Dockerfiles. A Dockerfile is a file that contains all the specifications needed for a container. The Docker engine uses it to create images which can then be used as basis for running containers.
Here’s a Dockerfile for Magento 2.4 that I came up with:
# /path/to/project/Dockerfile
# Our image is based on Ubuntu.
FROM ubuntu
# Here we define a few arguments to the Dockerfile. Specifically, the
# user, user id and group id for a new account that we will use to work
# as within our container.
ARG USER=docker
ARG UID=1000
ARG GID=1000
# Install PHP, composer and all extensions needed for Magento.
RUN apt-get update && apt-get install -y software-properties-common curl
RUN add-apt-repository ppa:ondrej/php
RUN apt-get update && apt-get install -y php
RUN apt-get update && apt-get install -y \
php-mysql php-xml php-intl php-curl \
php-bcmath php-gd php-mbstring php-soap php-zip \
composer
# Install Xdebug for a better developer experience.
RUN apt-get update && apt-get install -y php-xdebug
RUN echo "xdebug.remote_enable=on" >> /etc/php/7.4/mods-available/xdebug.ini
RUN echo "xdebug.remote_autostart=on" >> /etc/php/7.4/mods-available/xdebug.ini
# Install the mysql CLI client.
RUN apt-get update && apt-get install -y mysql-client
# Set up a non-root user with sudo access.
RUN groupadd --gid $GID $USER \
&& useradd -s /bin/bash --uid $UID --gid $GID -m $USER \
&& apt-get install -y sudo \
&& echo "$USER ALL=(root) NOPASSWD:ALL" > /etc/sudoers.d/$USER \
&& chmod 0440 /etc/sudoers.d/$USER
# Use the non-root user to log in as into the container.
USER ${UID}:${GID}
# Set this as the default directory when we connect to the container.
WORKDIR /workspaces/magento-demo
# This is a quick hack to make sure the container has something to run
# when it starts, preventing it from closing itself automatically when
# created. You could also remove this and run the container with `docker
# run -t -d` to get the same effect. More on `docker run` further below.
CMD ["sleep", "infinity"]
Feel free to go through the comments in the file above for more details, but essentially, this Dockerfile describes what a machine ready to run Magento should look like. It’s got PHP and all the necessary extensions, Xdebug, and Composer. It also includes the mysql
CLI client.
Importantly, it allows for creating a user account with sudo access. Later, we’ll use this capability to create a user account, inside the container that mimics the one we’re using in our host machine, effectively using the same user both inside and outside the container. The purpose of this is to make it possible to work on the Magento source code files from inside the container without having to deal with Linux permission issues when we try to do the same from outside the container (that is, directly via the host machine).
The image
Alright, now that we have our image defined in the form of our Dockerfile, let’s create it. To do that, we go into our project directory, create a new file named Dockerfile
:
cd /path/to/project
touch Dockerfile
Then use a text editor to save the contents from above into it, and finally run this command:
docker build \
--build-arg USER=kevin \
--build-arg UID=$(id -u) \
--build-arg GID=$(id -g) \
-t magento-demo-web .
Here’s what this all means:
docker build
: Is the command to build images from Dockerfiles.--build-arg USER=kevin
: Specifies the username for the account with sudo access that we will log into our container as. I’ve chosenkevin
here but you should use the one you’re logged in as on your machine.--build-arg UID=$(id -u)
: Uses theid -u
to pass in the Id of the currently logged in user.--build-arg GID=$(id -g)
: Uses theid -g
to pass in the Group Id of the currently logged in user.-t magento-demo-web .
: Specifies the name of the resulting image to bemagento-demo-web
. The.
is a reference to the current working directory from where we’re running the command, which is where our Dockerfile is located.
Run docker image ls
and you should see our new home grown magento-demo-web
image along with the other ones that we’ve downloaded from Docker Hub:
REPOSITORY TAG IMAGE ID CREATED SIZE
magento-demo-web latest 90d311df434f 22 minutes ago 452MB
mysql 5.7 718a6da099d8 12 days ago 448MB
ubuntu latest 1e4467b07108 3 weeks ago 73.9MB
elasticsearch 7.8.1 a529963ec236 3 weeks ago 811MB
The container
Ok, now that we have an image that’s capable of running Magento, let’s put it to work by creating a container based on it. We do that with:
docker run -d \
--name magento-demo-web \
--network magento-demo-network \
--network-alias web \
-p 5000:5000 \
-v ${PWD}:/workspaces/magento-demo \
magento-demo-web
Line by line, this is telling the Docker engine to:
docker run -d
: Run the container in detached mode. You could also add the-t
argument which makes sure the container stays up and running even if there’s no program or service running within it. We don’t need that in this case though, because we defined our Dockerfile with that niftysleep infinity
command.--name magento-demo-web
: Set the name of our container tomagento-demo-web
.--network magento-demo-network
: Make our container part of the same network as the MySQL and Elasticsearch ones.--network-alias web
: Set our container’s name within the network.-p 5000:5000
: Open port5000
to access our soon-to-be-running Magento app.-v ${PWD}:/workspaces/magento-demo
: Create a new volume that makes our current working directory the same as the/workspaces/magento-demo
directory within the container. This is where we’ll store all the Magento files. Binding these directories makes it possible to access and modify the Magento files both from the container and from the host machine. This just makes things easier and more convenient for development purposes.magento-demo-web
: Use this image.
Running docker container ls
will show a list of all running containers, including the one we just created:
docker container ls
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
4af35c42e0bb magento-demo-web "/bin/bash" 5 minutes ago Up 5 minutes 0.0.0.0:5000->5000/tcp magento-demo-web
6c5ea65a7bd6 elasticsearch:7.8.1 "/tini -- /usr/local…" 2 hours ago Up 2 hours 0.0.0.0:9200->9200/tcp, 0.0.0.0:9300->9300/tcp magento-demo-elasticsearch
b73739ad5d66 mysql:5.7 "docker-entrypoint.s…" 3 hours ago Up 3 hours 0.0.0.0:3306->3306/tcp, 33060/tcp magento-demo-mysql
Connecting to the container
With the container up and running, we can connect to it with:
docker exec -it magento-demo-web bash
You may remember this as the same command we used before to connect to the MySQL container. This time, however, we’re using it to connect to our magento-demo-web
container, referenced by the name we gave it, and running bash
on it in order to open a shell.
After that, a prompt like this should show up:
kevin@4af35c42e0bb:/workspaces/magento-demo$
We’re now inside our container. Notice how we’re automatically taken to /workspaces/magento-demo
. This is just like we specified in our Dockerfile with the WORKDIR
command. Feel free to run php -v
or composer -V
to validate that the setup from our Dockerfile got all the way into our container:
kevin@4af35c42e0bb:/workspaces/magento-demo$ php -v
PHP 7.4.9 (cli) (built: Aug 7 2020 14:30:01) ( NTS )
Copyright (c) The PHP Group
Zend Engine v3.4.0, Copyright (c) Zend Technologies
with Zend OPcache v7.4.9, Copyright (c), by Zend Technologies
with Xdebug v2.9.6, Copyright (c) 2002-2020, by Derick Rethans
kevin@4af35c42e0bb:/workspaces/magento-demo$ composer -V
Composer 1.10.1 2020-03-13 20:34:27
Talking to other containers in the network
We also need to validate that our containers are actually able to talk to each other via the network that we set up. If all went according to plan, still from within our magento-demo-web
container, this command should open a mysql
session:
mysql -h mysql -u kevin -p
Notice how this time we don’t use localhost
or 127.0.0.1
to connect to our MySQL instance. This time, we use mysql
. This is the network alias we gave out MySQL container, so this is how our magento-demo-web
sees it. To magento-demo-web
, the MySQL container is just another machine in the same network.
Same deal for the Elasticsearch container. We can do something like this to talk to it:
curl elasticsearch:9200/_cat/health
Again, from the perspective of magento-demo-web
, this is just another machine in the network which it can reach by using the elasticsearch
network alias that we gave it when creating it.
Installing Magento in our container
Now that we have our environment ready for Magento, let’s install it. First order of business is to create the Composer project:
composer create-project --repository-url=https://repo.magento.com/ magento/project-community-edition ./install
If you’re familiar with Composer, then this should look very familiar to you. This command will download all the Magento files as specified by the magento/project-community-edition
project from the https://repo.magento.com/
repository. There are a few gotchas though:
- First, Magento is not openly available to download just like that. As such, Composer will ask for authentication in order to do so. Follow this guide to obtain the authentication keys from the Magento Marketplace. When Composer asks for a username, type in the public key; when it asks for password, type in the private key.
- Second, you’ll notice that I specified
./install
at the end of that command. This is where all the files will be downloaded. I’ve chosen this (aninstall
directory inside our current one) becausecomposer create-project
will refuse to download the files in a directory that’s not empty. Ours isn’t, because we’ve got our Dockerfile in it. But that’s nothing to worry about, once Composer finishes downloading everything, we’ll just copy the files over to their rightful location at/workspaces/magento-demo
. You can do so with some Linux sorcery like this:
(shopt -s dotglob; mv -v ./install/* .)
This Composer operation will take a good while, but when it’s done, make sure to move all the contents of ./install
into /workspaces/magento-demo
. We now need to actually install Magento:
bin/magento setup:install \
--base-url=http://localhost:5000 \
--db-host=mysql \
--db-name=magento_demo \
--db-user=kevin \
--db-password=password \
--admin-firstname=admin \
--admin-lastname=admin \
--admin-email=admin@admin.com \
--admin-user=admin \
--admin-password=admin123 \
--language=en_US \
--currency=USD \
--timezone=America/New_York \
--use-rewrites=1 \
--elasticsearch-host=elasticsearch \
--elasticsearch-port=9200
Even if you have never installed Magento before, the command above should be pretty straightforward. An interesting thing to note is how we’ve set up our database and Elasticsearch settings here:
--db-host=mysql \
--db-name=magento_demo \
--db-user=kevin \
--db-password=password \
and
--elasticsearch-host=elasticsearch \
--elasticsearch-port=9200
--db-host
is the hostname of the machine where the MySQL server is running. We use our container’s network alias here. --db-name
is the name of the database we created when initializing our container via the MYSQL_DATABASE
environment variable. --db-user
and --db-password
are the credentials for the login that we created in the same manner. --elasticsearch-host
is the network alias of our Elasticsearch container, and finally --elasticsearch-port
is the port that we configured it to listen to.
As you can see, these are the same settings that we used to configure our MySQL and Elasticsearch containers. So make sure to do the same if you’ve been following along and decided to go with different values.
Once that command is done, we’re ready. We have a working Magento. Try it out by running this:
php -S 0.0.0.0:5000 -t ./pub/ ./phpserver/router.php
And navigating to localhost:5000
in your browser. You should see your empty Magento homepage.
Optional: Installing the sample data
If you’re planning some custom extension, or to just play with Magento to get to know it better, you may want to add some sample data. Luckily, the Magento devs have graciously provided such a thing in the form of a Composer package. If you want, you can install it with this recipe:
bin/magento sampledata:deploy
bin/magento setup:upgrade
bin/magento indexer:reindex
bin/magento cache:flush
bin/magento sampledata:deploy
will also ask you for your Magento Makerplace keys so have them ready.
So turn off the built-in PHP server, run these, wait a good while, and fire up the built in server once more. Your Magento app should now have a catalog and all sorts of other data loaded in.
Composing it all together
Now that was a lot. It was much easier than having to set everything up from scratch without Docker, but still, I promised a minimal setup overhead. A single command. With Docker Compose we can do just that.
For containers, the usual workflow is a three step process:
- Create the Dockerfile (sometimes omitted if we have a readily available image like it was the case with MySQL and Elasticsearch).
- Create or download an image.
- Run the container.
Docker Compose can help us by capturing all the settings needed to create containers in a single YAML file; which then can be taken by a CLI tool (i.e. docker-compose
) and it can set up the complete infrastructure. This single file is named docker-compose.yml
and this is what it may look like for our current setup:
version: "3.8"
# Listing our three containers. Or "services", as known by Docker Compose.
services:
# Defining our MySQL container.
# "mysql" will be the network alias for this container.
mysql:
image: mysql:5.7
container_name: magento-demo-mysql
networks:
- magento-demo-network
ports:
- "3306:3306"
volumes:
- magento-demo-mysql-data:/var/lib/mysql
environment:
MYSQL_ROOT_PASSWORD: password
MYSQL_USER: kevin
MYSQL_PASSWORD: password
MYSQL_DATABASE: magento_demo
# Defining our Elasticsearch container
# "elasticsearch" will be the network alias for this container.
elasticsearch:
image: elasticsearch:7.8.1
container_name: magento-demo-elasticsearch
networks:
- magento-demo-network
ports:
- "9200:9200"
- "9300:9300"
environment:
discovery.type: single-node
# Defining our custom Magento 2 container.
# "web" will be the network alias for this container.
web:
# The build section tells Docker Compose how to build the image.
# This essentially runs a "docker build" command.
build:
context: .
dockerfile: Dockerfile
args:
USER: kevin
UID: 1000
GID: 1000
container_name: magento-demo-web
networks:
- magento-demo-network
ports:
- "5000:5000"
volumes:
- .:/workspaces/magento-demo
# The volume that is used by the MySQL container
volumes:
magento-demo-mysql-data:
# The network where all the containers will live
networks:
magento-demo-network:
As you can see, most of docker-compose.yml
is more or less rewriting the docker run
commands in a YAML format. With the exception of the web
container/service which includes a build
section that reflects the docker build
command that was used to take the Dockerfile and turn it into an image.
If you want to try it out, make sure to remove all the infrastructure we’ve created, to avoid any conflicts. You can do so from your host machine with these commands:
docker container rm -f magento-demo-web magento-demo-elasticsearch magento-demo-mysql
docker image rm magento-demo-web
docker network rm magento-demo-network
docker volume rm magento-demo-mysql-data
Make sure you’re in the directory where the Dockerfile lives in the host machine. Then create a new docker-compose.yml
file and put all the content above into it. Finally, run:
docker-compose up -d
This will take a little while, but by the end of it, you’ll have a complete infrastructure with the three containers that we’ve created step by step throughout this article. With the docker-compose.yml
file, docker-compose up
essentially takes care of running all of our docker build
and docker run
commands.
The -d
option means that the the command will run in the background and give you back control of your console. You can also run it without it if you want the console to show the logs from the containers.
You can still see the logs even in detached mode with:
docker-compose logs
You can also inspect the running containers. For that, you can use:
docker-compose ps
Output will look something like this:
$ docker-compose ps
Name Command State Ports
--------------------------------------------------------------------------------------------------------------------
magento-demo-elasticsearch /tini -- /usr/local/bin/do ... Up 0.0.0.0:9200->9200/tcp, 0.0.0.0:9300->9300/tcp
magento-demo-mysql docker-entrypoint.sh mysqld Up 0.0.0.0:3306->3306/tcp, 33060/tcp
magento-demo-web sleep infinity Up 0.0.0.0:5000->5000/tcp
Notice how docker-compose ps
gives us our container names just as we specified them in the docker-compose.yml
file.
docker-compose
has many other utilities, check them out with docker-compose --help
.
Now, same as before, we still need to open a terminal into our Magento container to run some installation commands on it. To do so, we can run the following command:
docker-compose exec web bash
Notice how with docker-compose
we refer to the container via its service name. That is, the name we gave the container under the services
section of docker-compose.yml
.
Of course, we can still use the same command that we used before, when we created our container directly with docker
:
docker exec -it magento-demo-web bash
Now, once inside our container we need to install Magento again. Remember that we wiped out all the infrastructure we created manually, so these are fresh new containers; akin to new machines.
If you were running this from scratch you would just go ahead and do…
composer create-project --repository-url=https://repo.magento.com/ magento/project-community-edition ./install
and
(shopt -s dotglob; mv -v ./install/* .)
In this case, however, we already have all the Magento files in our directory, So we can save time and skip this step. We can reuse these files and just run bin/magento setup:install
.
But since this is a new Magento installation, we do need to remove the config file before setup:install
’ing. So go ahead and…
rm app/etc/env.php
…then:
bin/magento setup:install \
--base-url=http://localhost:5000 \
--db-host=mysql \
--db-name=magento_demo \
--db-user=kevin \
--db-password=password \
--admin-firstname=admin \
--admin-lastname=admin \
--admin-email=admin@admin.com \
--admin-user=admin \
--admin-password=admin123 \
--language=en_US \
--currency=USD \
--timezone=America/New_York \
--use-rewrites=1 \
--elasticsearch-host=elasticsearch \
--elasticsearch-port=9200
After a while, Magento will be fully installed in our new infrastructure created by Docker Compose and ready to be fired up via the PHP built in server:
php -S 0.0.0.0:5000 -t ./pub/ ./phpserver/router.php
Bonus: Interactive debugging with Visual Studio Code
So this is a fully functioning Magento installation with files that we can edit to our heart’s content. In terms of a “fully featured” development environment, however, we need to spruce it up a bit.
So install VS Code from https://code.visualstudio.com/ and install the Remote Development plugin.
Open a new VS Code window and open the command palette with Ctrl + Shift + P
. In there, type in Remote-Containers: Attach to Running Container...
and press Enter
. In the menu that shows up, select our magento-demo-web
container.
That will result in a new VS Code instance that is connected to the container. Open an integrated terminal in VS Code and you’ll see:
Now, install the PHP Debug extension so that we can take advantage of that Xdebug that we installed in our container via our Dockerfile.
Create a new launch configuration for interactive debugging with PHP by clicking on the “Run” button in the action bar to the left (Ctrl + Shift + D
also works). Click the “create a launch.json file” link in the pane that appears. Then, in the resulting menu at the top of the window, select the “PHP” option. Here’s a screen capture for guidance:
That will result in a new .vscode/launch.json
file created that contains the launch configuration for the PHP debugger.
Now let’s put a breakpoint anywhere, like in line 13 of the pub/index.php
file; press the “Start debugging” button in the “Run” pane, near the top left of the screen (making sure that the “Listen to XDebug” option is selected), and start up the PHP built in server from VS Code’s integrated terminal with php -S 0.0.0.0:5000 -t ./pub/ ./phpserver/router.php
. Now navigate to localhost:5000
in your browser and enjoy VS Code’s interactive debugging experience:
Summary
Whew! That was quite a bit. In this blog post, we’ve done a deep dive into how to set up all the pieces of a Magento application using Docker containers: MySQL, Elasticsearch, and Magento itself. Then, we captured all that knowledge into a single docker-compose.yml
file which can be run with a single docker-compose up
command to provision all the infrastructure in our local machine. As a cherry on top, we set up interactive debugging of our brand new Magento application with VS Code. Thanks to the safety net provided by these tools, I feel like I’m ready to really dig into Magento and start developing customizations, or debugging existing websites. If you’ve been following along this far, dear reader, I hope you do too.
magento mysql elasticsearch docker containers
Comments