Publié le 12/08/2020 par Michael BOUVY
May 2024 update: you should consider having a look at our new guide : https://clickandmortar.github.io/magento-kubernetes/
_______________________
Magento 2 currently does not have a fully cloud native approach, and documentation lacks on this topic. We'll see below how to deploy immutable Docker images of Magento 2 on Kubernetes, make it possible to build once (ie. a tag) and deploy many times (ie. staging, preproduction, production).
This post is not a detailed how-to guide, but rather a compilation of solutions to known difficulties you'll face trying to deploy Magento to Kubernetes.
At the end of this post, you'll also find a list of many security/observability/availability related recommendations.
Once the code copied and dependencies installed via Composer, Magento requires two major commands to be ran during build, which will not work out-of-the-box in this context (no access to database or external service):
See our clickandmortar/magento-kubernetes GitHub repository for a complete Dockerfile example.
When ran with an existing app/etc/env.php, this command will try to connect to the database and/or the cache. To get around this, move it to a temporary location:
RUN mv app/etc/env.php app/etc/env.php.orig \
&& bin/magento setup:di:compile
Keep your app/etc/config.php in place, it is required for Magento to know which modules are enabled.
This command needs to know the websites structure to work properly, you'll need to dump your database config to app/etc/config.php before building the image:
bin/magento app:config:dump
This file containing the whole Magento config may be reverted to it's simpler version containing only modules once static content is deployed, otherwise you wont be able to change any setting on your deployed environment (except using environment variables, which is recommended).
I'd recomment to keep both files:
Then within your Dockerfile:
RUN mv app/etc/config.php app/etc/config.php.orig \
&& mv app/etc/config.docker.php app/etc/config.php \
&& bin/magento setup:static-content:deploy \
--max-execution-time=3600 \
-t my/theme -t Magento/backend \
ja_JP de_DE es_ES ... \
&& mv app/etc/config.php.orig app/etc/config.php
For both commands above, you may need to increase the memory limit:
RUN php -d memory_limit=1024M bin/magento setup:...
Magento allows to override any system configuration using environment variables, following the following patterns, replacing the slash character of config paths with double underscores:
Note that these environment values take precedence over values in config.php and the database.
⚠️ Note that you need to use encrypted values for sensitive configuration (ie. payment gateway credentials) environment variables.
However, Magento does not offer a similar mechanism for values of env.php. Easy way to be able to define database connection info and such using environment variables, is taking advantage of PHP's getenv() function:
<?php
...
'db' => [
'table_prefix' => '',
'connection' => [
'default' => [
'host' => getenv('MAGENTO_DATABASE_HOST'),
'dbname' => getenv('MAGENTO_DATABASE_NAME'),
'username' => getenv('MAGENTO_DATABASE_USERNAME'),
'password' => getenv('MAGENTO_DATABASE_PASSWORD'),
'model' => 'mysql4',
'engine' => 'innodb',
'initStatements' => 'SET NAMES utf8;',
'active' => '1'
]
]
],
...
The schema below is an overview of the (simplified) target architecture of Magento running in Kubernetes:
Magento Kubernetes simplified architecture.
Usage of cloud managed services is recommended whenever possible.
And below is a detailed view of the Magento Deployment part:
As you can see, Magento requires volumes to be shared between running Pods:
To achieve this, you'll need a StorageClass allowing mounting a PersistentVolume with the ReadWriteMany access mode. You may use Kubernetes NFS provisioner or a managed service offering a RWX StorageClass (Google Cloud Filestore, Alicloud NAS, etc.).
Most practical way to deploy Magento to Kubernetes is using Helm. It offers advanced templating features, release management and hooks.
When deploying a new release, Magento requires the setup:upgrade command to be executed, before the application is effectively deployed.
For this purpose, usage of Helm chart hooks is quite handy, as shown using the annotations in this example:
# upgrade-job.yaml
apiVersion: batch/v1
kind: Job
metadata:
name: "{{ include "magento.fullname" . }}-pre-upgrade-job"
labels:
{{- include "magento.labels" . | nindent 4 }}
annotations:
"helm.sh/hook": pre-upgrade
"helm.sh/hook-weight": "1"
"helm.sh/hook-delete-policy": before-hook-creation
spec:
template:
metadata:
labels:
{{- include "magento.labels" . | nindent 8 }}
spec:
restartPolicy: Never
containers:
- name: php
image: {{ .Values.image.name }}:{{ .Values.image.tag }}
command: ["bin/magento", "setup:upgrade", "--keep-generated"]
envFrom:
- configMapRef:
name: magento-cm
- secretRef:
name: magento-secret
You may also need to define a post-install,post-upgrade hook to clear the cache once the release is fully deployed.
The rest of the Helm chart required to deployed Magento is quite straightforward, a good start is using Helm create command.
The deployment architecture described above is quite basic, and requires additional work on the following topics: