LEMP Stack on Kubernetes
This setup is for practice only and suitable for production environments
The LEMP stack—Linux, Nginx (pronounced "Engine-X"), MySQL (or MariaDB), and PHP—has been a popular and powerful choice for building and deploying web applications due to its open-source nature, performance, and scalability. However, as applications become more complex and traffic increases, managing the infrastructure can be challenging. Kubernetes, the leading container orchestration platform, addresses this by allowing us to containerize the LEMP stack components and deploy them on Kubernetes, providing agility, scalability, and resilience. This setup streamlines deployments, automates management tasks, and ensures high availability for web applications. This article will guide you through deploying a LEMP stack on Kubernetes, exploring best practices and demonstrating how to use Kubernetes features to enhance the performance and reliability of your web applications.
The Components I used in Kubernetes are:
Secrets - to store MYSQL related secrets like MYSQL_ROOT_PASSWORD, MYSQL_DATABASE, MYSQL_USER, MYSQL_PASSWORD and MYSQL_HOST
Config maps - to store the php.ini file
Deployment - the Hero of kubernetes (as i call it :-P ) to deploy our containers in pods
Services - to expose our application for accessing
Here’s the code base:
secrets.yaml
Copy
apiVersion: v1
kind: Secret
metadata:
name: mysql-root-pass
type: Opaque
stringData:
password: R00t
---
apiVersion: v1
kind: Secret
metadata:
name: mysql-user-pass
type: Opaque
stringData:
username: username
password: password
---
apiVersion: v1
kind: Secret
metadata:
name: mysql-db-url
type: Opaque
stringData:
database: database_db1
---
apiVersion: v1
kind: Secret
metadata:
name: mysql-host
type: Opaque
stringData:
host: mysql-service
Here, i have implemented all the secrets in a single file and i have used opaque type of secret and stringData. We can also use data block but using it expects us to keep the data in base64 encoded format. So, make sure you are opting stringData or data based on your requirement and preference.
configmap.yaml
Copy
apiVersion: v1
kind: ConfigMap
metadata:
name: php-config
data:
php.ini: |
variables_order = "EGPCS"
variables_order = "EGPCS"
sets the precedence order for how PHP handles incoming variables from different sources. It defines which source "wins" if there are name collisions (i.e., the same variable name is submitted via multiple methods).
In the EGPCS order:
E (Environment): Variables set in the server's environment have the highest precedence.
G (GET): Variables passed via the URL (query string) have the next highest precedence.
P (POST): Variables submitted via the HTTP POST method.
C (Cookie): Variables stored in cookies.
S (Server): Server variables (like those in
$_SERVER
) have the lowest precedence.
deployment.yml
Copy
apiVersion: apps/v1
kind: Deployment
metadata:
name: lemp-wp
labels:
app: lemp
spec:
replicas: 1
selector:
matchLabels:
app: lemp
template:
metadata:
labels:
app: lemp
spec:
containers:
- name: nginx-php-container
image: webdevops/php-nginx:alpine-3-php7
ports:
- containerPort: 80
volumeMounts:
- name: php-config-vol
mountPath: /opt/docker/etc/php/php.ini
subPath: php.ini
env:
- name: MYSQL_ROOT_PASSWORD
valueFrom:
secretKeyRef:
name: mysql-root-pass
key: password
- name: MYSQL_DATABASE
valueFrom:
secretKeyRef:
name: mysql-db-url
key: database
- name: MYSQL_USER
valueFrom:
secretKeyRef:
name: mysql-user-pass
key: username
- name: MYSQL_PASSWORD
valueFrom:
secretKeyRef:
name: mysql-user-pass
key: password
- name: MYSQL_HOST
valueFrom:
secretKeyRef:
name: mysql-host
key: host
- name: mysql-container
image: mysql:5.6
ports:
- containerPort: 3306
env:
- name: MYSQL_ROOT_PASSWORD
valueFrom:
secretKeyRef:
name: mysql-root-pass
key: password
- name: MYSQL_DATABASE
valueFrom:
secretKeyRef:
name: mysql-db-url
key: database
- name: MYSQL_USER
valueFrom:
secretKeyRef:
name: mysql-user-pass
key: username
- name: MYSQL_PASSWORD
valueFrom:
secretKeyRef:
name: mysql-user-pass
key: password
- name: MYSQL_HOST
valueFrom:
secretKeyRef:
name: mysql-host
key: host
volumes:
- name: php-config-vol
configMap:
name: php-config
Services.yaml
Copy
apiVersion: v1
kind: Service
metadata:
name: lemp-service
labels:
app: lemp
spec:
type: NodePort
selector:
app: lemp
ports:
- port: 80
targetPort: 80
nodePort: 30008
---
apiVersion: v1
kind: Service
metadata:
name: mysql-service
spec:
selector:
app: lemp
ports:
- protocol: TCP
port: 3306
targetPort: 3306
The LEMP based application is exposed using nodePort mode and mysql-service is used a default clusterIP Service. A better approach would be using a stateful set for Database.