Tutti i post

WordPress + MySQL su k3s: dalla VM al cluster

Come ho deployato WordPress e MySQL su un cluster k3s casalingo con due VM Proxmox da 2 GB RAM, PersistentVolume locale, Traefik ingress e ottimizzazioni anti-OOM.

Avevo due VM su Proxmox — 2 GB RAM e 1 vCPU ciascuna — e volevo capire fino a dove potevo spingere k3s in un ambiente casalingo. La risposta breve: funziona, ma serve attenzione alla memoria.

Il contesto hardware

Il cluster è composto da un nodo master e un nodo worker, entrambi Ubuntu 22.04 su Proxmox. Le risorse sono volutamente limitate per simulare un edge environment reale:

# Nodo master
RAM: 2 GB  |  vCPU: 1  |  Disco: 20 GB

# Nodo worker (target del deploy)
RAM: 2 GB  |  vCPU: 1  |  Disco: 20 GB
💡 k3s è progettato per ambienti con risorse limitate e consuma molto meno di k8s vanilla. L’agent sul worker a riposo occupa circa 120 MB RSS.

Perché MariaDB invece di MySQL

L’immagine mysql:8 ufficiale porta innodb_buffer_pool_size a ~128 MB ma il processo reale si assesta facilmente sui 400 MB. Con MariaDB e un tuning minimale si scende a ~220 MB — su 2 GB quella differenza si sente.

Struttura del deploy

Ho usato il local-path-provisioner già incluso in k3s per i PersistentVolume, evitando dipendenze esterne. Tutto vive nel namespace wordpress:

namespace: wordpress
├── PersistentVolumeClaim  mysql-pvc   (5 Gi)
├── PersistentVolumeClaim  wp-pvc      (3 Gi)
├── Deployment             mariadb
│     resources:
│       requests: { memory: 256Mi }
│       limits:   { memory: 512Mi }
├── Deployment             wordpress
│     resources:
│       requests: { memory: 128Mi }
│       limits:   { memory: 300Mi }
├── Service                mariadb     (ClusterIP)
├── Service                wordpress   (ClusterIP)
└── Ingress                            (Traefik, host: blog.local)

Il Deployment di MariaDB

Il punto critico è la ConfigMap con il tuning di InnoDB:

apiVersion: v1
kind: ConfigMap
metadata:
  name: mariadb-config
  namespace: wordpress
data:
  my.cnf: |
    [mysqld]
    innodb_buffer_pool_size = 128M
    max_connections         = 50
    query_cache_size        = 0

L’Ingress con Traefik

k3s include Traefik v2 già configurato come ingress controller di default. Non serve nessun Helm chart aggiuntivo:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: wordpress-ingress
  namespace: wordpress
  annotations:
    traefik.ingress.kubernetes.io/router.entrypoints: web
spec:
  rules:
  - host: blog.local
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: wordpress
            port:
              number: 80

Il tuning che fa la differenza

Senza resources.limits espliciti, k3s non applica nessun throttling e i pod possono consumare tutta la RAM disponibile fino all’OOM killer. Ho imparato questa lezione nel modo più classico: il worker è andato in swap storm al primo accesso alla dashboard di WordPress.

⚠️ Definire sempre resources.limits nei Deployment. Senza limiti, un solo pod può saturare il nodo e far crashare tutto il resto.

Consumo reale a riposo

Dopo una settimana di utilizzo, il worker si assesta su questi valori:

ComponenteRSSLimite
MariaDB~230 MB512Mi
WordPress~180 MB300Mi
k3s agent~120 MB
OS (Ubuntu)~350 MB
Totale~880 MB/ 2048 MB ✓

Rimane circa 1.1 GB di headroom, sufficiente per gestire picchi di traffico leggero.

Il setup funziona bene per un blog personale o sito portfolio. Per WooCommerce o carichi più seri, consiglio di salire almeno a 4 GB sul worker.

Prossimi passi

  • Aggiungere un CronJob per il backup automatico del PVC MySQL su storage esterno
  • Configurare cert-manager + Let’s Encrypt per HTTPS automatico
  • Integrare Prometheus + Grafana per monitorare il consumo RAM del namespace