Magento 2 & Docker Tutorial – Part 3

Magento 2 & Docker Tutorial – Part 3

thumbnail
Want to talk about your project?

Part 3 – How to run Magento 2 with Elasticsearch on the docker environment?

This tutorial is a part of the big one Magento & Docker tutorial. You can find the last part here. The complete code of the previous tutorial is on the GitHub.

Review current configuration

In the previous tutorial, we have made a complete configuration for running web applications. We have all needed services for the base run Magento 2

  • NGINX
  • PHP-FPM
  • MySql

The file structure looks like this:

  App
  - conf
    - app
      - etc
        - nginx
          - conf.d
            - default.conf
  - dockerfile
    - phpfpm
      - Dockerfile
  - sql
  - src
  - docker-compose.yml

We have made own PHP Docker image, but Magento needs more specific php extensions and libraries. We will add it on this tutorial part. We will try to configure Elasticsearch indexing also.

Let’s start.

Modify PHP-FPM image

Install needed PHP extensions

We can check what php extensions Magento needs in the official documentation

  • ext-bcmath
  • ext-ctype
  • ext-curl
  • ext-dom
  • ext-gd
  • ext-hash
  • ext-iconv
  • ext-intl
  • ext-mbstring
  • ext-openssl
  • ext-pdo_mysql
  • ext-simplexml
  • ext-soap
  • ext-xsl
  • ext-zip
  • lib-libxml

Let’s install missed extensions. Open dockerfiles/phpfpm/Dockerfile and add libraries and extensions installation RUN part.

RUN apt-get update && apt-get install -y \
  gzip \
  libbz2-dev \
  libfreetype6-dev \
  libicu-dev \
  libjpeg62-turbo-dev \
  libmcrypt-dev \
  libpng-dev \
  libsodium-dev \
  libssh2-1-dev \
  libxslt1-dev \
  libzip-dev \
  lsof \
  default-mysql-client \
  zip

RUN docker-php-ext-configure \
  gd --with-freetype-dir=/usr/include/ --with-jpeg-dir=/usr/include/

RUN docker-php-ext-install \
  bcmath \
  bz2 \
  calendar \
  exif \
  gd \
  gettext \
  intl \
  mbstring \
  mysqli \
  opcache \
  pcntl \
  pdo_mysql \
  soap \
  sockets \
  sodium \
  sysvmsg \
  sysvsem \
  sysvshm \
  xsl \
  zip

Whole PHP file looks like this:

FROM php:7.3-fpm

RUN apt-get update && apt-get install -y \
  gzip \
  libbz2-dev \
  libfreetype6-dev \
  libicu-dev \
  libjpeg62-turbo-dev \
  libmcrypt-dev \
  libpng-dev \
  libsodium-dev \
  libssh2-1-dev \
  libxslt1-dev \
  libzip-dev \
  lsof \
  default-mysql-client \
  zip

RUN docker-php-ext-configure \
  gd --with-freetype-dir=/usr/include/ --with-jpeg-dir=/usr/include/

RUN docker-php-ext-install \
  bcmath \
  bz2 \
  calendar \
  exif \
  gd \
  gettext \
  intl \
  mbstring \
  mysqli \
  opcache \
  pcntl \
  pdo_mysql \
  soap \
  sockets \
  sodium \
  sysvmsg \
  sysvsem \
  sysvshm \
  xsl \
  zip

RUN mv "$PHP_INI_DIR/php.ini-development" "$PHP_INI_DIR/php.ini"

Application user

The best practice is to create the user for web files. Add the part to creating the user and group  after the php.ini selection statement.

RUN groupadd -g 1000 app \
 && useradd -g 1000 -u 1000 -d /var/www -s /bin/bash app

Prepare application directory and set permissions

RUN mkdir -p /var/www/html \
   && chown -R app:app /var/www

Change user, set home directory as volume, and set the workdir to /var/www/html

USER app:app

VOLUME /var/www

WORKDIR /var/www/html

Get composer

For Magento installation, the composer will be useful. We can use the COPY statement from the docker. There is possible to COPY element from directly from another image. Let’s try to copy the composer binary from the composer image. Add this statement after FROM.

COPY --from=composer /usr/bin/composer /usr/bin/composer

After that, the composer will be available for use inside the container.

Complete Dockerfile

FROM php:7.3-fpm

COPY --from=composer /usr/bin/composer /usr/bin/composer

RUN apt-get update && apt-get install -y \
  gzip \
  libbz2-dev \
  libfreetype6-dev \
  libicu-dev \
  libjpeg62-turbo-dev \
  libmcrypt-dev \
  libpng-dev \
  libsodium-dev \
  libssh2-1-dev \
  libxslt1-dev \
  libzip-dev \
  lsof \
  default-mysql-client \
  zip

RUN docker-php-ext-configure \
  gd --with-freetype-dir=/usr/include/ --with-jpeg-dir=/usr/include/

RUN docker-php-ext-install \
  bcmath \
  bz2 \
  calendar \
  exif \
  gd \
  gettext \
  intl \
  mbstring \
  mysqli \
  opcache \
  pcntl \
  pdo_mysql \
  soap \
  sockets \
  sodium \
  sysvmsg \
  sysvsem \
  sysvshm \
  xsl \
  zip

RUN mv "$PHP_INI_DIR/php.ini-development" "$PHP_INI_DIR/php.ini"

RUN groupadd -g 1000 app \
 && useradd -g 1000 -u 1000 -d /var/www -s /bin/bash app
RUN mkdir -p /var/www/html \
   && chown -R app:app /var/www

USER app:app
VOLUME /var/www
WORKDIR /var/www/html

Build image

docker build -t <yournamespace>/php-fpm:7.3-magento2

Push a new image to the hub.

docker push <yournamespace>/php-fpm:7.3-magento2

Modify the docker-compose

Change image in phpfpm service to <yournamespace>/php-fpm:7.3-magento2 

Download Magento

You have to configure Magento credentials before installation:

https://devdocs.magento.com/guides/v2.3/install-gde/prereq/connect-auth.html

We have all the needed extensions, so we can try to install the Magento store.

Remove all files from ./src. and following the instructions from https://devdocs.magento.com/guides/v2.3/install-gde/composer.html use the composer

composer create-project --repository-url=https://repo.magento.com/ 
 magento/project-community-edition src/

Magento NGINX configuration

In Magento source files we can find the sample Nginx configuration file. Open ./src/nginx.conf.sample file. Magento developers tell us how to configure our NGINX server. Copy commented “upstream” and “server” part and paste it to /conf/app/etc/nginx/conf.d/default.conf. Set server to phpfpm:9000, $MAGE_ROOT to /var/www/html, server_name to _, and include to /var/www/html/nginx.conf.sample

Whole file:

upstream fastcgi_backend {
  server  phpfpm:9000;
}
  server {
    listen 80;
    server_name _;
    set $MAGE_ROOT /var/www/html;
    set $MAGE_DEBUG_SHOW_ARGS 1;
    include /var/www/html/nginx.conf.sample;
  }

After that go up services

docker-compose up -d

Magento set up

Base configuration

Now, we have to set up the Magento database. Go into the phpfpm container docker-compose exec phpfpm bash, and run commands for set config values, and install base data

$ bin/magento setup:config:set --backend-frontname=admin --db-host=mysql --db-name=mydatabase --db-user=myuser --db-password=test123

$ bin/magento setup:install

After that create admin user:

  $ bin/magento admin:user:create --admin-user='admin'
  --admin-password='test123' --admin-email='admin@admin.com'
  --admin-firstname='Admin' --admin-lastname='Admin'

Now, the sotre should be visible on  http://127.0.0.1/.

And you should be able to login to the admin panel on http://127.0.0.1/admin using admin user data from admin:user:create command.

Sample data

You can install Magento sample data for better effect. Use

$ bin/magento sampledata:deploy

The above command needs your Magento marketplace credentials. You can find it on you account settings https://marketplace.magento.com/customer/accessKeys/.

To complete sample data installation you have to run

  $ bin/magento setup:upgrade
  $ bin/magento cache:flush

Now our store looks much better.

Elasticsearch

Adobe recommends Elasticsearch as the best search engine for the Magento store. Let’s try to configure this in our docker environment.

First, we have to add a new service in docker-compose.yml.

  elasticsearch:
    image: elasticsearch:7.7.1
    ports:
      - "9300:9300"
      - "9200:9200"
    environment:
      discovery.type: single-node

Rebuild the environment:

$ docker-compose down
$ docker-compose up -d

Now, the search engine has to be changed in the admin panel. Go to http://127.0.0.1/admin. Select Stores -> Configuration -> Catalog -> Catalog -> Catalog Search. Select Elasticsearch 7+ in Search Engine field. Set Elasticsearch Server Hostname to elasticsearch. Now click “Test connection”. If the Elasticsearch service works, you should see

Now, Elasticsearch index needs to be fill. Go into the phpfpm container and run:

$ bin/magento indexer:reindex catalogsearch_fulltext
$ bin/magento cache:flush

Now, our store uses the elasticsearch indexes for search. You can verify the index data by simple curl request

$ curl -XGET 'localhost:9200/_search?size=1' -H 'Content-Type: 
  application/json' -d '{ "query": { "match_all": {} } }'

You can find sample product data in the response

{
  "took":1,
  "timed_out":false,
  "_shards":{
  "total":1,
  "successful":1,
  "skipped":0,
  "failed":0
},
  "hits":{
  "total":{
  "value":187,
  "relation":"eq"
},
  "max_score":1.0,
  "hits":[
{
  "_index":"magento2_product_1_v2",
  "_type":"document",
  "_id":"1",
  "_score":1.0,
  "_source":{
  "store_id":"1",
  "sku":"24-MB01",
  "status":"1",
  "status_value":"Enabled",
  "visibility":"4",
  "name":"Joust Duffle Bag",
  "url_key":"joust-duffle-bag",
  "description":"The sporty Joust Duffle Bag can't be beat - not in the gym, not on the luggage carousel, not anywhere. Big enough to haul a basketball or soccer ball and some sneakers with plenty of room to spare, it's ideal for athletes with places to go. Dual top handles. Adjustable shoulder strap. Full-length zipper. L 29\" x W 13\" x H 11\".",
  "category_ids":[
  2,
  3,
  4
  ],
  "position_category_2":"0",
  "name_category_2":"Default Category",
  "position_category_3":"0",
  "name_category_3":"Gear",
  "position_category_4":"0",
  "name_category_4":"Bags",
  "price_0_1":"34.000000",
  "price_1_1":"34.000000",
  "price_2_1":"34.000000",
  "price_3_1":"34.000000"
}
}
  ]
}
}

So, the Elasticsearch works!

Conclusions

During these tutorials, we set up full Magento 2 store in a docker environment. After reading entire articles you should be able to

  • install docker and docker-compose
  • create simple PHP, Mysql, NGINX environment in docker-compose
  • set up initial MySql data in docker
  • build own docker images
  • configure php-fpm and NGINX for Magento 2
  • run Elasticsearch in docker
  • configure Magento to use Elasticsearch

There are still many ways to improve Magento 2 development in docker, but everyone needs their own tutorial but I tried to convey the basics for further works.

You can find many complex solutions using the docker, I recommend to use it instead of reinventing the wheel. Knowledge from these articles will help you a better understand, and adept at another solution. 

I think, one of the best Magento 2 and Docker toolbox is: https://github.com/markshust/docker-magento

FIles from this part of the tutorial are there:

https://github.com/pandagrouppl/docker-magento-tutorial/tree/PART-3

Sources:

...