WordPress with Portworx on Kubernetes


This reference architecture document shows how you can deploy WordPress, an open-source content management system, with Portworx on Kubernetes. This architecture provides the following benefits:

  • Portworx enables reliable and persistent storage to ensure WordPress runs with HA
  • Portworx enables shared volumes for file uploads
  • Kubernetes automatically replicates your MySQL data
  • You can horizontally scale the WordPress container using multi-writer semantics for the file-uploads directory
  • The cluster automatically repairs itself in the event of a node failure

Prerequisites

  • You must have a Kubernetes cluster with a minimum of three worker nodes.
  • Portworx is installed on your Kubernetes cluster. For details about how you can install Portworx on Kubernetes, see the Portworx on Kubernetes page.
  • You must have Stork installed on your Kubernetes cluster. For details about how you can install Stork, see the Stork page.

Dynamically provision a volume for MySQL

  1. Create a file called mysql-sc.yaml, specifying the following fields and values:

    • apiVersion: as storage.k8s.io/v1
    • kind: as StorageClass
    • metadata.name: with the name of your StorageClass object (this example uses mysql-sc)
    • provisioner: as kubernetes.io/portworx-volume. For details about the Portworx-specific parameters, refer to the Portworx Volume section of the Kubernetes website.
    • parameters.repl: with the number of replicas Portworx should create (this example creates two replicas)
    • parameters.priority_io: with the type of the storage pool (this example uses a high-priority storage pool)
    apiVersion: storage.k8s.io/v1
    kind: StorageClass
    metadata:
      name: mysql-sc
    provisioner: kubernetes.io/portworx-volume
    parameters:
      repl: "3"
      priority_io: "high"

    For more details about how you can configure a storage class, see the Using Dynamic Provisioning section of the Portworx documentation.

  2. Apply the spec:

    kubectl apply -f mysql-sc.yaml.yaml
  3. Create a file called mysql-pvc.yaml with the following content:

    apiVersion: v1
    kind: PersistentVolumeClaim
    metadata:
      name: mysql-pvc
      annotations:
        volume.beta.kubernetes.io/storage-class: mysql-sc
    spec:
      accessModes:
        - ReadWriteOnce
      resources:
        requests:
          storage: 2Gi
    NOTE: This PVC references the mysql-sc storage class. As a result, Kubernetes will automatically create a new PVC for each replica.
  4. Apply the spec:

    kubectl apply -f mysql-pvc.yaml

Dynamically provision a volume for WordPress

  1. Create a file called wordpress-sc.yaml with the following content:

    apiVersion: storage.k8s.io/v1
    kind: StorageClass
    metadata:
      name: wordpress-sc
    provisioner: kubernetes.io/portworx-volume
    parameters:
      repl: "3"
      priority_io: "high"
      shared: "true"
    NOTE: The shared: "true" flag creates a globally shared namespace volume which can be used by multiple Pods.
  2. Apply the spec:

    kubectl apply -f wordpress-sc.yaml
  3. Create a file called wordpress-pvc.yaml with the following content:

    apiVersion: v1
    kind: PersistentVolumeClaim
    metadata:
      name: wp-pvc
      labels:
        app: wordpress
      annotations:
        volume.beta.kubernetes.io/storage-class: wordpress-sc
    spec:
      accessModes:
        - ReadWriteMany
      resources:
        requests:
          storage: 1Gi
    NOTE: This PVC references the wordpress-sc storage class. As a result, Kubernetes will automatically create a new PVC for each replica.
  4. Apply the spec:

    kubectl apply -f wordpress-pvc.yaml

Create a Kubernetes secret for storing your MySQL password

A secret is an object that contains sensitive data. To create a secret, you can use the kubectl create secret command. Note that, to protect your sensitive data, the kubectl get and kubectl describe commands do not display the content of a secret.

  1. Use the echo command to save your MySQL password to a file called ./password.txt, replacing <YOUR-PASSWORD> with your actual password:

    echo -n '<YOUR-PASSWORD' > ./password.txt
  2. To create a new secret, enter the kubectl create secret command, specifying:

    • The generic parameter. This instructs Kubernetes to create a secret based on a file, directory, or specified literal value.
    • The name of your secret (this example uses mysql-pass)
    • The --from-file flag with the name of the file in which you stored your password
    kubectl create secret generic mysql-pass --from-file=./password.txt
  3. Use the kubectl get secrets command to verify that Kubernetes created the secret:

    kubectl get secrets

Deploy MySQL

  1. Create a file named mysql-service.yaml with the following content:

    apiVersion: v1
    kind: Service
    metadata:
      name: wordpress-mysql
      labels:
        app: wordpress
    spec:
      ports:
        - port: 3306
      selector:
        app: wordpress
        tier: mysql
      clusterIP: None
  2. Apply the spec:

    kubectl apply -f mysql-service.yaml
  3. Create a file named mysql-deployment.yaml with the following content:

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: wordpress-mysql
      labels:
        app: wordpress
    spec:
      selector:
        matchLabels:
          app: wordpress
      strategy:
        type: Recreate
      template:
        metadata:
          labels:
            app: wordpress
            tier: mysql
        spec:
          # Use the Stork scheduler to enable more efficient placement of the pods
          schedulerName: stork
          containers:
          - image: mysql:5.6
            imagePullPolicy:
            name: mysql
            env:
              # $ kubectl create secret generic mysql-pass --from-file=password.txt
              # make sure password.txt does not have a trailing newline
            - name: MYSQL_ROOT_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: mysql-pass
                  key: password.txt
            ports:
            - containerPort: 3306
              name: mysql
            volumeMounts:
            - name: mysql-persistent-storage
              mountPath: /var/lib/mysql
          volumes:
          - name: mysql-persistent-storage
            persistentVolumeClaim:
              claimName: mysql-pvc

    Note the following about this Deployment:

    • Kubernetes creates a single-instance MySQL database
    • Kubernetes creates an environment variable called MYSQL_ROOT_PASSWORD that contains your MySQL password
    • Portworx mounts the Portworx persistent volume in the /var/lib/mysql directory
    • The Stork scheduler will place your Pods closer to where their data is located
  4. Apply the spec:

    kubectl apply -f mysql-deployment.yaml

Deploy WordPress

  1. Create a file called wordpress-service.yaml with the following content:

    apiVersion: v1
    kind: Service
    metadata:
      name: wordpress
      labels:
        app: wordpress
    spec:
      ports:
        - port: 80
          nodePort: 30303
      selector:
        app: wordpress
        tier: frontend
      type: NodePort

    Note that the spec.type field is set to NodePort. Kubernetes exposes the service on each node and makes it accessible from outside the cluster. For more details, see the Type NodePort section of the Kubernetes documentation.

  2. Apply the spec:

    kubectl apply -f wordpress-service.yaml
  3. Create a file called wordpress-deployment.yaml with the following content:

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: wordpress
      labels:
        app: wordpress
    spec:
      selector:
        matchLabels:
          app: wordpress
      replicas: 3
      strategy:
        type: Recreate
      template:
        metadata:
          labels:
            app: wordpress
            tier: frontend
        spec:
          # Use the Stork scheduler to enable more efficient placement of the pods
          schedulerName: stork
          containers:
          - image: wordpress:4.8-apache
            name: wordpress
            imagePullPolicy:
            env:
            - name: WORDPRESS_DB_HOST
              value: wordpress-mysql
            - name: WORDPRESS_DB_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: mysql-pass
                  key: password.txt
            ports:
            - containerPort: 80
              name: wordpress
            volumeMounts:
            - name: wordpress-persistent-storage
              mountPath: /var/www/html
          volumes:
          - name: wordpress-persistent-storage
            persistentVolumeClaim:
              claimName: wp-pvc

    Note the following about this Deployment

    • Portworx will create three replicas of each volume
    • The Stork scheduler will place your Pods closer to where their data is located
    • Kubernetes will create an environment variable called WORDPRESS_DB_PASSWORD that contains your MySQL password
  4. Apply the spec:

    kubectl apply -f wordpress-deployment.yaml

Validate the cluster functionality

  1. List your Pods:

    kubectl get pods
  2. Display your services:

    kubectl get services

Clean up

  1. Enter the following command to delete the Kubernetes secret:

    kubectl delete secret mysql-pass
  2. Use the kubectl delete to delete your WordPress deployment and PVC:

    kubectl delete -f wordpress-deployment.yaml
    kubectl delete -f wordpress-pvc.yaml
  3. Use the kubectl delete to delete your MySQL deployment and PVC:

    kubectl delete -f mysql-deployment.yaml
    kubectl delete -f mysql-pvc.yaml

Discussion Forum

If you have more questions about this application, please head over to our discussion forum and feel free to ask more questions.


Last edited: Thursday, Aug 6, 2020