Search
left arrowBack
Pavel Rykov

Pavel Rykov

July 31, 2023 ・ Code

Migrate PHP (lamp) app to Kubernetes

Introduction

Migrating your PHP (LAMP) applications to Kubernetes is an important process for any web application. The majority of web sites and applications today are built on the LAMP stack, which involves using the Linux operating system, the Apache web server, MySQL for database, and PHP for scripting. In this guide, we will look at the process for migrating a traditional LAMP stack application to Kubernetes.

The first step in the process is to set up the Kubernetes environment. This involves using the Kubernetes command-line utility, kubectl, to create the necessary containers, specify their parameters, and define the set of services the application will use. Once the environment is set up, you can configure and deploy the application. This includes installing the necessary database within the containers, setting up runtime parameters, and configuring the services the application will use.

Finally, you need to configure the deploy scripts which will continually monitor your application’s health and availability. Depending on your application, you may need to use deployment tools such as GitHub Actions or Helm, or automated deployment and monitoring tools such as Puppet or Ansible. This step is necessary to ensure any changes made to your application are immediately reflected in the Kubernetes environment.

Migration Basics

The first step in the migration process is to identify the application’s components and how they will interact. A typical LAMP application will consist of Apache, MySQL, and PHP and all of these components need to be correctly containerized and run in Kubernetes. This means that all components must be packaged in Docker images and deployed as Kubernetes pods.

The next step is to optimize Docker images and Kubernetes configurations. Docker allows us to optimize the images by removing unnecessary libraries and packages, while Kubernetes configuration can be optimized to ensure that the deployment is running in the most efficient way. This includes selecting the right number of replicas and selecting the right resource limits for each pod. Additionally, we can use Kubernetes services like Service Mesh to ensure scalability and reliability of the application.

Once the optimization is complete, we need to establish networking between the application components. By using Kubernetes NetworkPolicies, Traefik IngressController and Open Service Broker API we can ensure secure, reliable and scalable communication between the separate application components.

Finally, we need to establish monitoring and logging for the application. This can be done using Prometheus, Grafana and Fluentd. Fluentd allows us to collect and store log data from application containers running in Kubernetes and Prometheus and Grafana can be used to monitor the application performance and resource usage.

By following the steps outlined in this article, you can migrate your PHP (LAMP) application to Kubernetes in a secure and efficient way. By leveraging the power of cloud native, containerized technologies, you can ensure that your application is running at its best and is secure and reliable.

Pre-migration Steps

Migrating PHP (LAMP) applications to Kubernetes can be intimidating, especially if you are unfamiliar with the technology. However, with the right preparation and planning, it can be a straightforward process. Below are some pre-migration steps you should take before attempting to move your LAMP applications to Kubernetes.

First and foremost, you must ensure your application is ready for a containerized environment. This means ensuring that all dependencies are properly resolved and that all configuration files are moved to the /etc directory. Additionally, you should make sure that all components of your application are configured properly including webservers, databases, and databases users.

Application

The code of the web application might look something like this.

Example index.php

<?php
$host = "192.168.1.120";
$username = "dbuser";
$password = "password";
$dbname = "mydb";

// Create connection
$conn = new mysqli($host, $username, $password, $dbname);

// Check connection
if ($conn->connect_error) {
    die("Connection failed: " . $conn->connect_error);
}

$sql = "SELECT * FROM users";
$result = $conn->query($sql);

if ($result->num_rows > 0) {
    // Output data of each row
    while($row = $result->fetch_assoc()) {
        echo "ID: " . $row["id"]. " - Name: " . $row["name"]. " - Email:  " . $row["email"]. "<br>";
    }
} else {
    echo "0 results";
}
$conn->close();

Dockerfile

Once your application is ready, you need to create a Dockerfile that describes how to build a Docker image containing all the components of your application. This Dockerfile should be as simple and concise as possible. Consider the following example Dockerfile to build a Docker image containing the codebase of a simple PHP web application, as well as all its dependencies.

Example Dockerfile

FROM php:8.2-apache

# Copy web application codebase
COPY index.php /var/www/html

# Install any needed dependencies
RUN apt-get update && apt-get install -y mysql-client

# Install the application-specific PHP extensions
RUN docker-php-ext-install pdo_mysql

Finally, once your Dockerfile is ready, you can start creating Kubernetes objects that will be responsible for deploying the image to the desired environment. These objects must be declared in the YAML-format configuration files. This is the main way to communicate with Kubernetes.

Before finally deploying to Kubernetes, it is important to test your configuration locally. This can be done with tools like Minikube and Docker Compose, which can help in validating that all components of your application work properly together before they are put into production.

Namespace

Kubernetes Namespaces are virtual clusters of nodes, networking and storage that allow users to segregate resources within a cluster. They provide the richness of an isolated environment for the resources associated with them. As the base for user-level isolation and security in Kubernetes, a Namespace can specify different access levels, resource quotas, and role-based access control to its resources.

Kubernetes supports per-namespace resource limits, and also allows users to configure different access policies for objects in different namespaces. Each namespace isolates network traffic between its services. Resources, such as ClusterIP services or LoadBalancer services, created within a namespace are also reachable only from within the same namespace and do not affect or reach services outside of it.

Example namespace.yml

---
apiVersion: v1
kind: Namespace
metadata:
  name: php-app

Deployment

Kubernetes Deployment is a powerful tool that allows Developers to manage and deploy applications to a Kubernetes cluster. Deployments are one of the most important resources used to create and manage workloads running on Kubernetes. The deployment abstraction helps to manage the most complex of applications. It allows for declarative management and execution of application updates, as well as providing rollback and rollover capabilities.

A Kubernetes deployment is defined in a deployment.yml file. This .yml file is written in YAML (Yet Another Markup Language) and it defines a DeploymentSpec object that contains the configuration for a related set of ReplicaSets. The deployment.yml is used to specify the number of replicas desired (called “replicas” in the .yml) and other settings of the DeploymentSpec. The .yml also defines the desired behavior when updating a DeploymentSpec.

For example, the following deployment.yml file defines a DeploymentSpec that creates three replicas of a website that runs on a web server. The PodTemplateSpec includes the necessary labels and annotations to identify the pod containers:

Example deployment.yml

---
apiVersion: apps/v1beta1
kind: Deployment
metadata:
  name: php-app-deployment
  namespace: php-app
  labels:
    app.kubernetes.io/name: php-app
spec:
  replicas: 3
  template:
    metadata:
      labels:
        app.kubernetes.io/name: php-app
    annotations:
      app.kubernetes.io/name: php-app
    spec:
      containers:
      - name: php-app-with-web-server
        image: registry.example.com/lamp-demo/php-app:1.0.0
        ports:
        - containerPort: 80
        env: 
        - name: ENV_VAR
          value: "value-of-env-var"
        resources:
          requests:
            memory: "64Mi"
            cpu: "200m"
          limits:
            memory: "128Mi"
            cpu: "400m"

Once the DeploymentSpec is created, the Kubernetes API server will create and manage the corresponding ReplicaSets, which will in turn launch the necessary containers to run the application. The DeploymentSpec will monitor the app’s status and respond accordingly when changes such as scaling up or down are implemented.

Service

Kubernetes Service is a resource used to connect to and manage applications running in the Kubernetes cluster. Services provide a set of functions for managing the lifecycle of the application in the cluster, including deployment, scaling, health checks, and more. It is one of the core features of Kubernetes and is designed to make it easier to deploy and manage applications.

Service is an abstraction for the underlying application that can be accessed through a set of defined ports. These services can be connected to other applications within the cluster by defining a connection between them using labels. The service also includes a configuration file which defines the ports, health checks, and other settings associated with the service

Example service.yml

---
apiVersion: v1
kind: Service
metadata:
  name: php-app-service
  namespace: php-app
  labels:
    app.kubernetes.io/name: php-app
spec:
 type: ClusterIP
 ports:
   - port: 80
     targetPort: 8080
     protocol: TCP
     name: http
 selector:
  app.kubernetes.io/name: php-app

This example creates a service called php-app-service which is associated with an app called php-app. The service will listen for traffic on port 80 and will forward it to the target port 8080.

Ingress

Kubernetes Ingress is a traffic-routing system used within Kubernetes clusters. It is based on the principles of the Layer 7 network routing, and it allows you to direct traffic from multiple services within your Kubernetes cluster to the same external IP address. This can be useful if you want to host multiple web services on a single server or want to simplify access to applications within your cluster. Ingress can help to improve the scalability and reliability of your applications by using intelligent routing policies.

An Ingress resource is typically defined as a YAML file, and is then called an ingress.yml. This file defines the rules for routing traffic from a specific service to an external IP address. The ingress.yml file consists of a set of rules, where each rule specifies a list of conditions and an action. For example, below is a sample ingress.yml used to connect a service ‘php-app-service’ with external IP address:

---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
 name: php-app-ingress
 namespace: php-app
 labels:
   app.kubernetes.io/name: php-app
spec:
 rules:
 - host: php-app.example.com
   http:
     paths:
       - path: /
         pathType: Prefix
         backend:
           service:
             name: php-app-service
             port:
               number: 80

The above ingress.yml tells Kubernetes to route all HTTP traffic received at example.com to the service ‘php-app-service’. It also specifies the port number (80) for the service.

Once the Ingress resource is defined and deployed, Kubernetes is responsible for automatically routing all incoming traffic based on the provided rules. This can make setting up services in Kubernetes easier, as it eliminates the need to manually configure the routing rules between services.

Demo project structure

Let's assemble the project by creating the following structure:

  • a "k8s" directory containing namespaces.yml, deployment.yml, service.yml and ingress.yml;

  • a "php-app" directory with Dockerfile and index.php.

| php-app-demo \
--| k8s \
----| namespace.yml
----| deployment.yml
----| service.yml
----| ingress.yml
--| php-app \
----| Dockerfile
----| index.php

All further work will be done within the php-app-demo directory context.

Build and Push to a Container Registry

It is assumed that the Docker Registry is already configured and available at registry.example.com. However, if not, the following link provides a detailed guide. To build a Docker container, the following command is executed:

docker build -t registry.example.com/lamp-demo/php-app:1.0.0 ./php-app

Then, the built image is pushed to Docker Registry:

docker push registry.example.com/lamp-demo/php-app:1.0.0

Now we can deploy the Application to a Kubernetes Cluster.

Deploy the Application

To complete the deployment of our application, we will run the following command:

kubectl apply -f ./k8s

This command is used to configure Kubernetes to run our application. It will take care of the deployment process and make sure it operates optimally. Our application will be running in no time.

Summary and Conclusion

This article provides an overview of the process of migrating an existing PHP (LAMP) application to Kubernetes. We started by discussing the basics of the migration process, including the steps necessary to migrate an application to a container environment. We then followed with a simple LAMP example and provided the steps necessary to properly deploy the app on a container platform. We continued to discuss more advanced topics, such as scaling and expanding the application once it is successfully running on Kubernetes. Finally, we looked at the advantages of using Kubernetes for application deployment, as well as provided some references for further reading.

Migrating to Kubernetes can be a challenging process, but it can provide your business with considerable savings of time and money, as well as delivering a secure platform for applications. However, this transition can be greatly simplified when using the correct resources. The Ivinco team have all the expertise and experience in Kubernetes necessary to make sure your PHP LAMP applications are safely and securely deployed on Kubernetes, and are running efficiently and reliably.

  • Code