Join our Discord Server
Ajeet Raina Ajeet Singh Raina is a former Docker Captain, Community Leader and Distinguished Arm Ambassador. He is a founder of Collabnix blogging site and has authored more than 700+ blogs on Docker, Kubernetes and Cloud-Native Technology. He runs a community Slack of 9800+ members and discord server close to 2600+ members. You can follow him on Twitter(@ajeetsraina).

How to Build and Deploy Production-grade WordPress Application using Docker and Kubernetes

5 min read



WordPress is an open-source CMS that allows users to create a website or blog easily. Deploying a WordPress website to production is a challenging task, and it requires a lot of configuration and optimization. Docker and Kubernetes are two popular technologies that can help simplify the process of deploying WordPress to production.

In this blog post, we will show you how to deploy a production-grade WordPress website using Docker and Kubernetes. We will cover the following topics:

Prerequisites

  • Setting up a MySQL database
  • Setting up WordPress with Docker Compose
  • Creating a Docker image for WordPress
  • Deploying WordPress to Kubernetes

Prerequisites

Before we start, make sure you have the following:

  • Docker installed on your machine. 

You can use Docker Desktop for your initial level of testing and that can be downloaded free of cost from the Downloads page.

  • Kubernetes installed and configured.

You can either use Kubernetes under Docker Desktop for your initial testing or preferrably use any of Cloud providers like AKS, EKS and GKE. Choose as per your convenience.

  • A domain name for your WordPress website.
  • Basic knowledge of Docker and Kubernetes.

If you’re completely new to Docker and Kubernetes, refer to this and this link. 

Setting up a MySQL database

The first step in deploying a WordPress website is to set up a MySQL database. To set up a MySQL database in Kubernetes, we will create a Kubernetes deployment and service.

Create a file called mysql-deployment.yaml and add the following contents:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: mysql
spec:
  selector:
    matchLabels:
      app: mysql
  strategy:
    type: Recreate
  template:
    metadata:
      labels:
        app: mysql
    spec:
      containers:
      - image: mysql:5.7
        name: mysql
        env:
        - name: MYSQL_ROOT_PASSWORD
          value: yourpassword
        - name: MYSQL_DATABASE
          value: wordpress
        ports:
        - containerPort: 3306
          name: mysql
        volumeMounts:
        - name: mysql-persistent-storage
          mountPath: /var/lib/mysql
      volumes:
      - name: mysql-persistent-storage
        persistentVolumeClaim:
          claimName: mysql-pv-claim
---
apiVersion: v1
kind: Service
metadata:
  name: mysql
spec:
  ports:
  - name: mysql
    port: 3306
    targetPort: 3306
  selector:
    app: mysql

This YAML file creates a deployment and service for the MySQL database. It uses the official MySQL Docker image and sets the MySQL root password and database name using environment variables. It also creates a persistent volume claim to store the MySQL data.

To create the MySQL deployment and service, run the following command:

$ kubectl apply -f mysql-deployment.yaml

Setting up WordPress with Docker Compose

Now that we have a MySQL database running in Kubernetes, we can set up WordPress using Docker Compose. Docker Compose is a tool for defining and running multi-container Docker applications.

Create a file called docker-compose.yaml and add the following contents:

version: '3.7'

services:
  db:
    image: mysql:5.7
    volumes:
      - db_data:/var/lib/mysql
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: yourpassword
      MYSQL_DATABASE: wordpress

  wordpress:
    depends_on:
      - db
    image: wordpress:5.7.2-fpm-alpine
    ports:
      - "8000:80"
    restart: always
    environment:
      WORDPRESS_DB_HOST: db:3306
      WORDPRESS_DB_USER: root
      WORDPRESS_DB_PASSWORD: yourpassword
      WORDPRESS_DB_NAME: wordpress
    volumes:
      - ./wp-content:/var/www/html/wp-content

volumes:
  db_data:

This YAML file creates two services:

  • db: This service uses the official MySQL Docker image and sets the MySQL root password and database name using environment variables. It also creates a volume for storing the MySQL data.

  • wordpress: This service uses the official WordPress Docker image and sets the database hostname, username, password, and database name using environment variables. It also creates a volume for storing the WordPress content.

To start the WordPress and MySQL containers using Docker Compose, run the following command:

$ docker-compose up -d

Creating a Docker image for WordPress

Now that we have WordPress running with Docker Compose, we can create a Docker image for WordPress that includes all the required plugins, themes, and configuration.

Create a file called Dockerfile in the root directory of your WordPress installation and add the following contents:

FROM wordpress:5.7.2-fpm-alpine

# Install required PHP extensions
RUN apk add --no-cache \
    php7-mysqli \
    php7-curl \
    php7-gd \
    php7-intl \
    php7-mbstring \
    php7-soap \
    php7-xml \
    php7-xmlrpc \
    php7-zip \
    php7-opcache

# Copy custom configuration files
COPY php.ini /usr/local/etc/php/
COPY wp-config.php /var/www/html/
COPY custom-entrypoint.sh /usr/local/bin/

# Set permissions
RUN chmod +x /usr/local/bin/custom-entrypoint.sh

ENTRYPOINT ["custom-entrypoint.sh"]
CMD ["php-fpm"]

This Dockerfile installs the required PHP extensions and copies the custom configuration files. It also sets the entrypoint to a custom script that runs the required database migrations and configurations.

Create a file called custom-entrypoint.sh in the root directory of your WordPress installation and add the following contents:

#!/bin/sh

# Wait for the database to be ready
until wp db check --allow-root; do
  sleep 1
done

# Run the database migrations
wp db upgrade --allow-root

# Configure WordPress settings
wp option update siteurl "http://your-domain.com" --allow-root
wp option update home "http://your-domain.com" --allow-root
wp option update blogname "Your WordPress Site Title" --allow-root
wp option update blogdescription "Your WordPress Site Description" --allow-root
wp option update timezone_string "Your WordPress Timezone" --allow-root
wp option update permalink_structure "/%postname%/" --allow-root

# Activate plugins and themes
wp plugin activate your-plugin --allow-root
wp theme activate your-theme --allow-root

exec docker-entrypoint.sh "$@"

This script waits for the database to be ready, runs the required database migrations, and configures the WordPress settings. It also activates the required plugins and themes.

To build the Docker image, run the following command:

$ docker build -t your-registry/your-image:latest .

Replace your-registry and your-image with your Docker registry and image name.

Deploying WordPress to Kubernetes

Now that we have a Docker image for WordPress, we can deploy it to Kubernetes.

Create a file called wordpress-deployment.yaml and add the following contents:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: wordpress
spec:
  selector:
    matchLabels:
      app: wordpress
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxUnavailable: 1
      maxSurge: 1
  template:
    metadata:
      labels:
        app: wordpress
    spec:
      containers:
      - name
- name: wordpress
    image: your-registry/your-image:latest
    ports:
    - containerPort: 9000
    env:
    - name: WORDPRESS_DB_HOST
      value: "mysql"
    - name: WORDPRESS_DB_USER
      valueFrom:
        secretKeyRef:
          name: mysql
          key: username
    - name: WORDPRESS_DB_PASSWORD
      valueFrom:
        secretKeyRef:
          name: mysql
          key: password
    - name: WORDPRESS_DB_NAME
      valueFrom:
        configMapKeyRef:
          name: wordpress
          key: database_name
    volumeMounts:
    - name: wordpress-content
      mountPath: /var/www/html/wp-content
  volumes:
  - name: wordpress-content
    persistentVolumeClaim:
      claimName: wordpress-content
apiVersion: v1
kind: Service
metadata:
name: wordpress
spec:
selector:
app: wordpress
ports:

name: http
port: 80
targetPort: 9000
type: LoadBalancer

This YAML file defines a Deployment and a Service for WordPress. The Deployment specifies the container image and environment variables, and also mounts the wordpress-content volume. The Service exposes the WordPress container using a LoadBalancer.

Create a file called mysql-deployment.yaml and add the following contents:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: mysql
spec:
  selector:
    matchLabels:
      app: mysql
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxUnavailable: 1
      maxSurge: 1
  template:
    metadata:
      labels:
        app: mysql
    spec:
      containers:
      - name: mysql
        image: mysql:5.7
        env:
        - name: MYSQL_ROOT_PASSWORD
          valueFrom:
            secretKeyRef:
              name: mysql
              key: password
        - name: MYSQL_DATABASE
          valueFrom:
            configMapKeyRef:
              name: wordpress
              key: database_name
        ports:
        - containerPort: 3306
        volumeMounts:
        - name: mysql-data
          mountPath: /var/lib/mysql
      volumes:
      - name: mysql-data
        persistentVolumeClaim:
          claimName: mysql-data
---
apiVersion: v1
kind: Service
metadata:
  name: mysql
spec:
  selector:
    app: mysql
  ports:
  - name: mysql
    port: 3306
    targetPort: 3306

This YAML file defines a Deployment and a Service for MySQL. The Deployment specifies the container image and environment variables, and also mounts the mysql-data volume. The Service exposes the MySQL container using a ClusterIP.

Create a file called wordpress-content-pvc.yaml and add the following contents:

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: wordpress-content
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi

This YAML file defines a PersistentVolumeClaim for storing the WordPress content.

Create a file called mysql-data-pvc.yaml and add the following contents:

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mysql-data
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi

This YAML file defines a PersistentVolumeClaim for storing the MySQL data.

Finally, we need to apply the YAML files to our Kubernetes cluster. Run the following commands in your terminal:

$ kubectl apply -f wordpress-config.yaml
$ kubectl apply -f wordpress-deployment.yaml
$ kubectl apply -f mysql-deployment.yaml
$ kubectl apply -f wordpress-content-pvc.yaml
$ kubectl apply -f mysql-data-pvc.yaml

This will create the necessary Kubernetes objects for deploying WordPress using Docker.

Once the objects have been created, you can check their status by running the following commands:

$ kubectl get configmap wordpress
$ kubectl get secret mysql
$ kubectl get pvc
$ kubectl get deployment
$ kubectl get pod
$ kubectl get service

If everything is working correctly, you should see output that indicates the objects are running and available.

To access WordPress, you can use the external IP address of the WordPress service. You can get this address by running the following command:

$ kubectl get service wordpress

This will output the external IP address of the WordPress service. You can use this IP address to access WordPress in your web browser.

Conclusion

In this blog post, we have shown you how to deploy a production-grade WordPress instance using Docker and Kubernetes. We have walked you through the process of creating Docker images for WordPress and MySQL, as well as the necessary Kubernetes objects for deploying WordPress.

By following these steps, you can create a scalable and reliable WordPress deployment that is easy to manage and maintain. We hope that this blog post has been useful for you and has given you a good understanding of how to deploy WordPress using Docker and Kubernetes

Have Queries? Join https://launchpass.com/collabnix

Ajeet Raina Ajeet Singh Raina is a former Docker Captain, Community Leader and Distinguished Arm Ambassador. He is a founder of Collabnix blogging site and has authored more than 700+ blogs on Docker, Kubernetes and Cloud-Native Technology. He runs a community Slack of 9800+ members and discord server close to 2600+ members. You can follow him on Twitter(@ajeetsraina).

Platform Engineering vs DevOps vs SRE: A Cheatsheet

According to Gartner®, by 2026, 80% of large software engineering organizations will establish platform engineering teams—a significant leap from 45% in 2022. This shift...
Tanvir Kour
2 min read

How to Develop Event-Driven Applications with Kafka and Docker

Event-driven architectures have become increasingly popular with the rise of microservices. These architectures are built around the concept of reacting to events in real-time,...
Abraham Dahunsi
6 min read
Join our Discord Server
Index