• 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 PHP Systems on Modern Linode Infrastructure

Dockerizing and Orchestrating Legacy PHP Systems on Modern Linode Infrastructure

Assessing Legacy PHP Application Dependencies

Before embarking on containerization, a thorough audit of the legacy PHP application’s dependencies is paramount. This involves identifying not only PHP extensions but also system-level libraries, external services (databases, message queues, caches), and specific file system configurations. For a typical monolithic PHP application, this might include:

  • PHP version and required extensions (e.g., mysqli, gd, redis, openssl).
  • Web server configuration (e.g., Apache .htaccess directives, Nginx rewrite rules).
  • Database connection details and specific SQL features used.
  • File permissions and directory structures critical for application operation (e.g., upload directories, cache directories).
  • Environment variables or configuration files that dictate application behavior.
  • External API integrations and their network accessibility.

Tools like phpinfo(), static analysis tools (e.g., PHPStan, Psalm), and manual code review are essential. Documenting these dependencies forms the basis for constructing a robust Dockerfile.

Crafting the Dockerfile for a Legacy PHP Application

The Dockerfile is the blueprint for your container image. For legacy PHP, we often start with a stable base image and layer on the necessary components. A common approach is to use an official PHP image and then install additional packages and extensions.

Consider an application that requires PHP 7.4, the gd and redis extensions, and runs on Apache. The Dockerfile might look like this:

Example Dockerfile

# Use an official PHP runtime as a parent image
FROM php:7.4-apache

# Set the working directory in the container
WORKDIR /var/www/html

# Install system dependencies required for PHP extensions
RUN apt-get update && apt-get install -y \
    libzip-dev \
    libpng-dev \
    libjpeg-dev \
    libfreetype6-dev \
    libssl-dev \
    libwebp-dev \
    libonig-dev \
    unzip \
    git \
    vim \
    cron \
    && rm -rf /var/lib/apt/lists/*

# Install PHP extensions
RUN docker-php-ext-configure gd --with-freetype --with-jpeg --with-webp \
    && docker-php-ext-install gd \
    && docker-php-ext-install zip \
    && docker-php-ext-install pdo_mysql \
    && docker-php-ext-install redis

# Enable Apache rewrite module
RUN a2enmod rewrite

# Copy application code into the container
COPY . /var/www/html

# Ensure correct permissions for web server
RUN chown -R www-data:www-data /var/www/html && chmod -R 755 /var/www/html

# Copy custom Apache configuration if needed
# COPY apache/000-default.conf /etc/apache2/sites-available/000-default.conf

# Copy custom PHP configuration if needed
# COPY php/php.ini /usr/local/etc/php/conf.d/custom.ini

# Expose port 80
EXPOSE 80

# Start Apache in the foreground
CMD ["apache2-foreground"]

Explanation:

  • FROM php:7.4-apache: Leverages an official PHP image with Apache pre-configured.
  • apt-get install: Installs necessary build dependencies for PHP extensions and other utilities.
  • docker-php-ext-install: A helper script to compile and install PHP extensions.
  • a2enmod rewrite: Enables Apache’s rewrite module, crucial for many PHP frameworks.
  • COPY . /var/www/html: Copies your application code into the web server’s document root.
  • chown/chmod: Sets appropriate ownership and permissions for the web server user (www-data).
  • EXPOSE 80: Informs Docker that the container listens on port 80.
  • CMD ["apache2-foreground"]: The command to run when the container starts, keeping Apache in the foreground so the container doesn’t exit.

Building and Testing the Docker Image

Once the Dockerfile is in place, build the image. Navigate to the directory containing your Dockerfile and application code, then execute:

docker build -t my-legacy-php-app:latest .

This command builds the image and tags it as my-legacy-php-app:latest. After building, run a container to test:

docker run -d -p 8080:80 --name legacy-app-test my-legacy-php-app:latest

Access your application via http://localhost:8080. Check container logs for any errors:

docker logs legacy-app-test

If issues arise, inspect the container’s filesystem or run it interactively for debugging:

docker run -it --rm my-legacy-php-app:latest bash

Orchestrating with Docker Compose on Linode

For production deployments on Linode, Docker Compose simplifies managing multi-container applications. This is especially useful if your legacy PHP app depends on external services like a database or Redis cache.

Example docker-compose.yml

version: '3.8'

services:
  app:
    build:
      context: .
      dockerfile: Dockerfile
    container_name: legacy_php_app
    ports:
      - "80:80"
    volumes:
      - ./app_data:/var/www/html/uploads # Example persistent volume for uploads
    environment:
      - DB_HOST=db
      - DB_USER=legacyuser
      - DB_PASS=securepassword
      - DB_NAME=legacydb
      - REDIS_HOST=redis
    depends_on:
      - db
      - redis
    networks:
      - app-network

  db:
    image: mysql:5.7
    container_name: legacy_db
    volumes:
      - db_data:/var/lib/mysql
    environment:
      MYSQL_ROOT_PASSWORD: rootpassword
      MYSQL_DATABASE: legacydb
      MYSQL_USER: legacyuser
      MYSQL_PASSWORD: securepassword
    networks:
      - app-network

  redis:
    image: redis:6.2
    container_name: legacy_redis
    ports:
      - "6379:6379"
    networks:
      - app-network

volumes:
  db_data:

networks:
  app-network:
    driver: bridge

Explanation:

  • services: Defines the individual containers (app, db, redis).
  • app service: Builds the PHP application image from the current directory (.) using the specified Dockerfile. It maps host port 80 to container port 80, mounts a volume for uploads, sets environment variables for database and Redis connections, and depends on the db and redis services.
  • db service: Uses an official MySQL 5.7 image, persists data using a named volume db_data, and configures the database with user credentials.
  • redis service: Uses an official Redis 6.2 image.
  • volumes: Declares named volumes for persistent data storage.
  • networks: Defines a custom bridge network for inter-container communication.

Deploying to Linode Kubernetes Engine (LKE) or Linode Compute Instances

On Linode, you have two primary orchestration options:

Option 1: Docker Compose on Linode Compute Instances

For simpler deployments or migrating from a single server, you can run Docker Compose directly on a Linode Compute Instance. Provision a Linode instance, install Docker and Docker Compose, then deploy your application.

# On your Linode Compute Instance:
sudo apt-get update && sudo apt-get install -y docker.io docker-compose

# Clone your application repository
git clone <your-repo-url>
cd <your-app-directory>

# Start the application
docker-compose up -d

To manage traffic and expose your application to the internet, consider using Linode’s Load Balancers in front of multiple instances running your Docker Compose setup. For persistent storage, ensure your volumes are configured correctly on the Linode instance or use Linode Block Storage.

Option 2: Linode Kubernetes Engine (LKE)

For more robust, scalable, and resilient deployments, LKE is the recommended path. This involves converting your docker-compose.yml into Kubernetes manifests (Deployments, Services, PersistentVolumeClaims, etc.).

Kubernetes Manifests (Example Snippets)

Deployment for the PHP App:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: legacy-php-app-deployment
spec:
  replicas: 3 # Scale as needed
  selector:
    matchLabels:
      app: legacy-php-app
  template:
    metadata:
      labels:
        app: legacy-php-app
    spec:
      containers:
      - name: legacy-php-app
        image: <your-docker-registry>/my-legacy-php-app:latest # Replace with your image
        ports:
        - containerPort: 80
        env:
        - name: DB_HOST
          value: "legacy-db-service" # Kubernetes Service name for the DB
        - name: DB_USER
          valueFrom:
            secretKeyRef:
              name: db-credentials
              key: username
        - name: DB_PASS
          valueFrom:
            secretKeyRef:
              name: db-credentials
              key: password
        - name: DB_NAME
          value: "legacydb"
        - name: REDIS_HOST
          value: "legacy-redis-service" # Kubernetes Service name for Redis
        volumeMounts:
        - name: uploads-volume
          mountPath: /var/www/html/uploads
      volumes:
      - name: uploads-volume
        persistentVolumeClaim:
          claimName: legacy-app-uploads-pvc

Service for the PHP App:

apiVersion: v1
kind: Service
metadata:
  name: legacy-php-app-service
spec:
  selector:
    app: legacy-php-app
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80
  type: ClusterIP # Or LoadBalancer if directly exposing

You would similarly create Deployments and Services for MySQL and Redis, and PersistentVolumeClaims (PVCs) to manage storage. Linode Kubernetes Engine integrates with Linode Block Storage for persistent volumes.

The process involves:

  • Pushing your Docker image to a container registry (e.g., Docker Hub, Linode Container Registry).
  • Applying your Kubernetes manifests to your LKE cluster using kubectl apply -f <your-manifest-file.yaml>.
  • Configuring an LKE Ingress Controller or a Linode Load Balancer to route external traffic to your legacy-php-app-service.

Monitoring and Maintenance

Once deployed, robust monitoring is crucial. Utilize tools like Prometheus and Grafana (often deployed within Kubernetes) to track application performance, resource utilization, and error rates. For LKE, Linode’s managed Kubernetes service offers integrated monitoring capabilities. Regularly update base images, PHP versions (where feasible), and security patches. Implement a CI/CD pipeline to automate builds, tests, and deployments, ensuring a smooth transition for your legacy system onto modern 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