• Skip to secondary menu
  • Skip to main content
  • Skip to primary sidebar
  • Home
  • Projects
  • Products
  • Themes
  • Tools
  • Request for Quote

Vengala Vinay

Having 9+ Years of Experience in Software Development

  • Home
  • WordPress
  • PHP
    • Codeigniter
  • Django
  • Magento
  • Selenium
  • Server
Home » Dockerizing and Orchestrating Legacy Magento 2 Systems on Modern Linode Infrastructure

Dockerizing and Orchestrating Legacy Magento 2 Systems on Modern Linode Infrastructure

Assessing Legacy Magento 2 for Containerization

Before diving into Dockerfiles and orchestration, a thorough assessment of the existing Magento 2 installation is paramount. Legacy systems often carry technical debt that can complicate containerization. Key areas to scrutinize include:

  • PHP Version Compatibility: Determine the exact PHP version(s) used. Magento 2 has specific version requirements. Ensure your chosen Docker image supports this or plan for necessary upgrades.
  • Extensions: Identify all installed third-party extensions. Some extensions might have hardcoded paths, rely on specific system libraries not present in minimal Docker images, or have complex installation procedures that need to be adapted.
  • Customizations: Analyze any custom themes or module modifications. These need to be packaged correctly within the container build process.
  • Database Dependencies: Note the specific MySQL/MariaDB version and any custom configurations or stored procedures.
  • Caching Mechanisms: Understand the current caching setup (e.g., Varnish, Redis, Memcached). These will likely become separate services in your containerized environment.
  • File System Permissions: Magento 2 is notoriously sensitive to file permissions. Document the current setup and plan how to replicate it within the container’s user context.
  • Environment Variables: Identify configuration settings that are currently managed via environment variables or direct file edits. These should be externalized for containerized deployments.

Crafting the Dockerfile for Magento 2

A robust Dockerfile is the foundation of your containerized Magento 2 application. We’ll aim for a multi-stage build to keep the final image lean. This example assumes a common setup using Apache, PHP, and Composer.

First, the build stage to install dependencies and compile Magento:

# Stage 1: Build dependencies and compile Magento
FROM composer:2.7 as builder

WORKDIR /app

# Copy composer.json and composer.lock first to leverage Docker cache
COPY composer.json composer.lock ./
RUN composer install --no-dev --optimize-autoloader --prefer-dist

# Copy the rest of the Magento application code
COPY . .
RUN composer dump-autoload --optimize --no-dev

# Install Magento if it's not already present (e.g., for a fresh install or specific build)
# RUN bin/magento setup:di:compile \
#     && bin/magento setup:static-content:deploy -f en_US en_GB \
#     && bin/magento indexer:reindex \
#     && bin/magento cache:flush

# Stage 2: Production image
FROM php:8.2-apache

# Install necessary PHP extensions and system packages
RUN apt-get update && apt-get install -y \
    libzip-dev \
    unzip \
    git \
    libpng-dev \
    libjpeg-dev \
    libfreetype6-dev \
    libwebp-dev \
    libicu-dev \
    libxslt1-dev \
    acl \
    && rm -rf /var/lib/apt/lists/* \
    && docker-php-ext-configure gd --with-freetype --with-webp --with-jpeg \
    && docker-php-ext-install -j$(nproc) gd zip intl opcache bcmath sockets

# Configure Apache
COPY --from=builder /app/vendor/ /var/www/html/vendor/
COPY --from=builder /app/app/ /var/www/html/app/
COPY --from=builder /app/lib/ /var/www/html/lib/
COPY --from=builder /app/pub/ /var/www/html/pub/
COPY --from=builder /app/bin/ /var/www/html/bin/
COPY --from=builder /app/generated/ /var/www/html/generated/
COPY --from=builder /app/setup/ /var/www/html/setup/
COPY --from=builder /app/update/ /var/www/html/update/
COPY --from=builder /app/composer.json /var/www/html/composer.json
COPY --from=builder /app/composer.lock /var/www/html/composer.lock

# Copy Magento root files (excluding vendor, generated, etc.)
# This assumes your Magento root is the same as the builder's WORKDIR
COPY . /var/www/html/

# Ensure correct ownership for Magento files
RUN chown -R www-data:www-data /var/www/html \
    && chmod -R 0775 /var/www/html/var \
    && chmod -R 0775 /var/www/html/pub/static \
    && chmod -R 0775 /var/www/html/pub/media \
    && chmod -R 0775 /var/www/html/generated

# Configure Apache virtual host for Magento
COPY docker/apache/000-default.conf /etc/apache2/sites-available/000-default.conf
RUN a2enmod rewrite expires headers \
    && a2dissite 000-default.conf \
    && a2ensite 000-default.conf \
    && apache2ctl graceful

# Set environment variables for Magento configuration
ENV MAGENTO_ROOT=/var/www/html \
    MAGENTO_BASE_URL=http://localhost \
    APP_ENV=production

# Expose port 80
EXPOSE 80

# Default command to run Apache
CMD ["apache2-foreground"]

The `docker/apache/000-default.conf` would contain a standard Apache configuration for Magento:

# docker/apache/000-default.conf
<VirtualHost *:80>
    DocumentRoot /var/www/html/pub
    DirectoryIndex index.php

    <Directory /var/www/html/pub>
        Options Indexes FollowSymLinks
        AllowOverride All
        Require all granted
        RewriteEngine On
        RewriteCond %{REQUEST_FILENAME} !-f
        RewriteCond %{REQUEST_FILENAME} !-d
        RewriteRule ^(.*) index.php [L]
    </Directory>

    # Other Magento-specific Apache configurations can go here
    ErrorLog ${APACHE_LOG_DIR}/error.log
    CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>

Orchestrating with Docker Compose

Docker Compose is ideal for defining and running multi-container Docker applications. For Magento 2, we typically need services for the web server, PHP-FPM (if not using Apache directly in the image), database, Redis, and potentially Varnish.

Here’s a sample `docker-compose.yml` for a basic setup:

version: '3.8'

services:
  app:
    build:
      context: .
      dockerfile: Dockerfile
    container_name: magento2_app
    ports:
      - "8080:80"
    volumes:
      - ./app_code:/var/www/html/app/code # Mount custom modules
      - ./pub_static:/var/www/html/pub/static # Persist static content
      - ./media:/var/www/html/pub/media # Persist media files
      - ./var:/var/www/html/var # Persist var directory (logs, cache, etc.)
    environment:
      - MAGENTO_ROOT=/var/www/html
      - MAGENTO_BASE_URL=http://localhost:8080
      - APP_ENV=production
      - DB_HOST=db
      - DB_NAME=magento
      - DB_USER=magento
      - DB_PASSWORD=magento_password
      - REDIS_FRONTEND_HOST=redis
      - REDIS_DEFAULT_HOST=redis
    depends_on:
      - db
      - redis
    networks:
      - magento_network

  db:
    image: mysql:8.0
    container_name: magento2_db
    environment:
      MYSQL_ROOT_PASSWORD: root_password
      MYSQL_DATABASE: magento
      MYSQL_USER: magento
      MYSQL_PASSWORD: magento_password
    volumes:
      - db_data:/var/lib/mysql
    networks:
      - magento_network

  redis:
    image: redis:7.2
    container_name: magento2_redis
    networks:
      - magento_network

  # Optional: Varnish service
  # varnish:
  #   image: varnish:7.4
  #   container_name: magento2_varnish
  #   ports:
  #     - "80:80" # Varnish listens on port 80
  #   environment:
  #     - VCL_CONFIG=/etc/varnish/default.vcl
  #   volumes:
  #     - ./docker/varnish/default.vcl:/etc/varnish/default.vcl
  #   depends_on:
  #     - app
  #   networks:
  #     - magento_network

volumes:
  db_data:

networks:
  magento_network:
    driver: bridge

Key considerations for `docker-compose.yml`:

  • Volumes: Crucial for persisting database data, media files, generated code, and logs. Mounting `app_code` allows for live development of custom modules.
  • Environment Variables: Externalize database credentials, cache configurations, and base URLs. These should be managed securely, ideally via a `.env` file.
  • `depends_on`: Ensures services start in the correct order.
  • Networks: Creates a dedicated network for containers to communicate.
  • Static Content Deployment: The `pub/static` and `generated` directories are critical. In a production setup, you’d typically pre-compile static content during the Docker build or via a separate CI/CD step, rather than relying on runtime generation. The volumes here are for development convenience or to ensure persistence.

Database Migration and Initial Setup

Migrating an existing Magento 2 database into a Dockerized environment requires careful planning. The most straightforward approach for initial setup is to:

  • Dump the existing database: Use `mysqldump` on your current production or staging server.
  • Import into the Docker container: Start the `db` service, then use `docker exec` to import the dump.

Example import command:

# Assuming your dump file is named magento_dump.sql
docker exec -i magento2_db sh -c 'exec mysql -u"$MYSQL_USER" -p"$MYSQL_PASSWORD" "$MYSQL_DATABASE"' < magento_dump.sql

After the database is imported, you’ll need to configure Magento to use the new database credentials and potentially update the base URL. This can be done via environment variables passed to the `app` service or by running Magento CLI commands within the container.

To run Magento CLI commands:

docker-compose exec app bin/magento setup:store-config:set --base-url=http://localhost:8080/
docker-compose exec app bin/magento setup:upgrade
docker-compose exec app bin/magento cache:flush

Linode Kubernetes Engine (LKE) Deployment Strategy

For production deployments on Linode, migrating from Docker Compose to Kubernetes is the logical next step for scalability and resilience. Linode Kubernetes Engine (LKE) provides a managed Kubernetes control plane.

Your `docker-compose.yml` translates into Kubernetes manifests (Deployments, Services, PersistentVolumeClaims, etc.).

Key Kubernetes Resources:

  • Deployments: For the Magento application, Redis, and potentially Varnish. These manage replica sets and rolling updates.
  • StatefulSets: Typically used for the MySQL database to ensure stable network identifiers and persistent storage.
  • Services: To expose your application internally (e.g., `app-service` pointing to the `app` Deployment) and externally (e.g., an Ingress controller or LoadBalancer Service).
  • PersistentVolumeClaims (PVCs): To request storage for your database, media, and logs. Linode Block Storage can be provisioned dynamically or statically.
  • ConfigMaps/Secrets: To manage environment variables and sensitive data like database passwords.
  • Ingress Controller: To manage external access to your services, handle SSL termination, and route traffic (e.g., Nginx Ingress Controller, Traefik).

A simplified example of a Magento Deployment manifest:

# kubernetes/deployment-app.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: magento-app
  labels:
    app: magento
spec:
  replicas: 2 # Scale as needed
  selector:
    matchLabels:
      app: magento
  template:
    metadata:
      labels:
        app: magento
    spec:
      containers:
      - name: magento
        image: your-docker-registry/magento2:latest # Replace with your image
        ports:
        - containerPort: 80
        envFrom:
        - configMapRef:
            name: magento-config
        - secretRef:
            name: magento-secrets
        volumeMounts:
        - name: pub-static-volume
          mountPath: /var/www/html/pub/static
        - name: media-volume
          mountPath: /var/www/html/pub/media
        - name: var-volume
          mountPath: /var/www/html/var
      volumes:
      - name: pub-static-volume
        persistentVolumeClaim:
          claimName: magento-static-pvc
      - name: media-volume
        persistentVolumeClaim:
          claimName: magento-media-pvc
      - name: var-volume
        persistentVolumeClaim:
          claimName: magento-var-pvc

And a corresponding Service:

# kubernetes/service-app.yaml
apiVersion: v1
kind: Service
metadata:
  name: magento-app-service
spec:
  selector:
    app: magento
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80
  type: ClusterIP # Typically exposed via Ingress

You would create similar manifests for Redis, MySQL (using a StatefulSet), and potentially Varnish. The database service would likely be a managed database service provided by Linode or another cloud provider for better reliability and management.

Performance Tuning and Monitoring

Containerizing Magento 2 on Linode opens up opportunities for performance tuning. Key areas include:

  • PHP-FPM Configuration: Tune `pm.max_children`, `pm.start_servers`, `pm.min_spare_servers`, `pm.max_spare_servers`, and `pm.max_requests` within the PHP-FPM pool configuration (if using PHP-FPM).
  • OpCache: Ensure OpCache is enabled and properly configured in `php.ini` within your Docker image.
  • Redis Tuning: Optimize Redis configuration for caching and session storage.
  • Database Optimization: Indexing, query optimization, and proper MySQL configuration (`innodb_buffer_pool_size`, etc.).
  • Varnish Configuration: Fine-tune VCL for optimal caching and request handling.
  • Resource Allocation: Properly size your LKE nodes and container resource requests/limits in Kubernetes.
  • Monitoring: Implement robust monitoring using tools like Prometheus and Grafana, integrated with your LKE cluster, to track container resource usage, application performance metrics (APM), and error rates.

By systematically containerizing and orchestrating your legacy Magento 2 system on Linode, you can achieve greater scalability, improved deployment efficiency, and a more resilient infrastructure.

Primary Sidebar

A little about the Author

Having 9+ Years of Experience in Software Development.
Expertised in Php Development, WordPress Custom Theme Development (From scratch using underscores or Genesis Framework or using any blank theme or Premium Theme), Custom Plugin Development. Hands on Experience on 3rd Party Php Extension like Chilkat, nSoftware.

Recent Posts

  • Step-by-Step: Diagnosing indexing lock conflicts and high CPU during bulk stock updates on DigitalOcean Servers
  • How to Debug and Fix memory leaks and socket exhaustion in daemon processes in Modern C++ Applications
  • Infrastructure as Code: Provisioning Secure PHP Clusters on DigitalOcean Using Terraform
  • Fixing Slow Largest Contentful Paint (LCP) caused by unoptimized database queries in Legacy Laravel Codebases Without Breaking API Contracts
  • An Auditor’s Checklist for Securing Laravel Backends on Google Cloud

Copyright © 2026 · Vinay Vengala