K3s and Joomla

Running a Jooma CMS on K3s.

K3S v1.24.8+k3s1 on Ubuntu 20.04 (AMD64). Disabled servicelb and traefik. Installed metalLB and traefik after initial installation. Using local-path storage class.

This config cannot scale - replicas: above 1 will not work if you are using more than one node. A ReadWriteOnce volume can only be mounted to a single pod (unless the pods are running on the same node).  Get the files on GitHub (https://github.com/lars-c/K3s-Joomla)

Loadbalancer: metalLB is configured with an IP pool of 192.168.1.150-192.168.1.159. Pool is called 'first-pool'.

kubectl get ipaddresspool -n metallb-system
NAME         AUTO ASSIGN   AVOID BUGGY IPS   ADDRESSES
first-pool   true          false             ["192.168.1.150-192.168.1.159"]

Environment variables:
Joomla: JOOMLA_DB_HOST, JOOMLA_DB_NAME and JOOMLA_DB_PASSWORD.
MySQL: MYSQL_PASSWORD, MYSQL_DATABASE and TZ

JOOMLA_DB_HOST        configmap    joomla_db_host        joomla-mysql
JOOMLA_DB_NAME        configmap    mysql_database        joomla_12
JOOMLA_DB_PASSWORD    secret/mysql-secret                password    cGFzc3dvcmQ=

MYSQL_PASSWORD        secret/mysql-secret                password    cGFzc3dvcmQ=
MYSQL_DATABASE        configmap    mysql_database        configmap    joomla_12
TZ                    configmap    mysql_timezone        configmap    Europe/Copenhagen

Only MYSQL_PASSWORD/JOOMLA_DB_PASSWORD is mandatory.

Docker-compose.yaml file (edited) (https://hub.docker.com/_/joomla)

version: '3.1'
services:
  joomla:
    image: joomla
    restart: always
    links:
      - joomladb:mysql
    ports:
      - 8080:80
    environment:
      JOOMLA_DB_HOST: joomladb
      JOOMLA_DB_PASSWORD: example
  joomladb:
    image: mysql:5.6
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: example

As I use the same docker image, I will need to handle the following values:

Two services: Joomla and MySQL.

Joomla:
Image: joomla:php8.1-apache.
Links: Handle the service dependency with environment variables (and services).
Ports: Pod/container expect traffic on port 80.
Environment variables: handle with configmap or secrets.

Joomladb:
Image: mysql:5.7.
Environment variables: Passwords is best handled with a secrets.

Docker-compose example file do not include volumes. One way to handle volumes in a joomla docker-compose file:

version: '3.1'
services:
  joomla:
    image: joomla
    volumes:
      - joomla_data:/var/www/html
    restart: always
    links:
      - joomladb:mysql
    ports:
      - 8080:80
    environment:
      JOOMLA_DB_HOST: joomladb
      JOOMLA_DB_PASSWORD: example
  joomladb:
    image: mysql:5.6
    volumes:
      - mysql_data:/var/lib/mysql
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: example
volumes:
  joomal_data:
    driver: local
  mysql_data:
    driver: local

Need to handle permanent storage for '/var/www/html' inside the joomla container/pod. Likewise for MySQL for the '/var/lib/mysql' path.

MySQL
1. Namespace
2. Service
3. ConfigMap
4. Secret
5. Storage
6. Deployment

Joomla
1. Service
2. Storage
6. Deployment

1. Namespace (MySQL)

Just the 'joomla' namespace (same for both services)

---
apiVersion: v1
kind: Namespace
metadata:
  name: joomla
  labels:
    name: joomla


 2. Service (MySQL)
 
Default MySQL port. The name of this service (joomla-mysql) is what the Joomla service will use.

---
apiVersion: v1
kind: Service
metadata:
  name: joomla-mysql
  namespace: joomla
  labels:
    app: joomla
spec:
  ports:
  - port: 3306
  selector:
    app: joomla
    tier: mysql
  clusterIP: None

3. configMap (Both)

The Joomla service need to know the name of the MySQL service (joomla_db_host). Database name (mysql_database) and database time zone (mysql_timezone) is optional.

---
apiVersion: v1
kind: ConfigMap
metadata:
  name: joomla
  namespace: joomla
data:
  joomla_db_host: "joomla-mysql"
  mysql_database: "joomla_12"
  mysql_timezone: "Europe/Copenhagen"

4. Secret (Both)

Database password Password must be base64 encoded. From a Ubuntu/WSL terminal:

echo -n password | base64
---
apiVersion: v1
kind: Secret
metadata:
  name: mysql-secret
  namespace: joomla
type: Opaque
data:
  password: cGFzc3dvcmQ=


5. Storage (MySQL)

A persistent volume claim (PVC) for the MySQL deployment.

---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: joomla-mysql-pv-claim
  namespace: joomla
  labels:
    app: joomla
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi

 

6. Deployment (MySQL)

Image: mysql:5.7
MYSQL_DATABASE, MYSQL_ROOT_PASSWORD and TZ is described in more details above. Only MYSQL_ROOT_PASSWORD is mandatory.
Ports: Pod use default MySQL port 3306.
Volumes: Using the above PersistentVolumeClaim 'joomla-mysql-pv-claim' for adding permanent storage for "/var/lib/mysql" inside the MySQL container/pod.

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: joomla-mysql
  namespace: joomla
  labels:
    app: joomla
spec:
  selector:
    matchLabels:
      app: joomla
      tier: mysql
  strategy:
    type: Recreate
  template:
    metadata:
      labels:
        app: joomla
        tier: mysql
    spec:
      containers:
      - image: mysql:5.7
        name: mysql
        env:
        - name: MYSQL_DATABASE
          valueFrom:
            configMapKeyRef:
              name: joomla
              key: mysql_database
        - name: MYSQL_ROOT_PASSWORD
          valueFrom:
            secretKeyRef:
              name: mysql-secret
              key: password
        - name: TZ
          valueFrom:
            configMapKeyRef:
              name: joomla
              key: mysql_timezone
        ports:
        - containerPort: 3306
          name: mysql
        volumeMounts:
        - name: joomla-mysql-persistent-storage
          mountPath: /var/lib/mysql
      volumes: 
      - name: joomla-mysql-persistent-storage
        persistentVolumeClaim:
          claimName: joomla-mysql-pv-claim

1. Service (Joomla)

The Joomla pod expect trafic on port 80. Address-pool 'first-pool' defined. The choosen loadbalancer IP (192.168.1.152) is somewhere inside the defined 'first-pool' of IP adresses.

---
apiVersion: v1
kind: Service
metadata:
  name: joomla
  namespace: joomla
  labels:
    app: joomla
  annotations:
    metallb.universe.tf/address-pool: first-pool
spec:
  ports:
    - port: 80
  selector:
    app: joomla
  type: LoadBalancer
  loadBalancerIP: 192.168.1.152


2. Storage (Joomla)

Using storage class 'local-path' here.

---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: joomla-pv-claim
  namespace: joomla
  labels:
    app: joomla
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi

6. Deployment (Joomla)

Image: Using php8.1-apache (Joomla official image)
JOOMLA_DB_HOST, JOOMLA_DB_NAME and JOOMLA_DB_PASSWORD are described above.
Joomla container use port 80 (TCP).
volumeMounts: Added a volumeMounts for path "/var/www/html" and finially created a volume.

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: joomla
  namespace: joomla
  labels:
    app: joomla
spec:
  selector:
    matchLabels:
      app: joomla
      tier: frontend
  strategy:
    type: Recreate
  template:
    metadata:
      labels:
        app: joomla
        tier: frontend
    spec:
      containers:
      - image: joomla:php8.1-apache
        name: joomla
        env:
        - name: JOOMLA_DB_HOST
          valueFrom:
            configMapKeyRef:
              name: joomla
              key: joomla_db_host
        - name: JOOMLA_DB_NAME
          valueFrom:
            configMapKeyRef:
              name: joomla
              key: mysql_database
        - name: JOOMLA_DB_PASSWORD
          valueFrom:
            secretKeyRef:
              name: mysql-secret
              key: password
        ports:
        - containerPort: 80
          name: joomla
        volumeMounts:
        - name: joomla-persistent-storage
          mountPath: /var/www/html
      volumes:
      - name: joomla-persistent-storage
        persistentVolumeClaim:
          claimName: joomla-pv-claim

 

Tiny, flawed fragments,
Fingers weave them with delight,
Beauty blooms as one.