Docker, LXC e Kubernetes: container nel homelab

2026-02-12T18:00:00.000Z

Container nel homelab: quale scegliere?

| Tecnologia | Isolamento | Overhead | Caso d'uso | |-----------|-----------|---------|-----------| | LXC (Proxmox) | Namespace Linux | Bassissimo | Servizi di sistema (DNS, proxy) | | Docker | Namespace + cgroups | Basso | App stateless, microservizi | | Kubernetes (k3s) | Pod + namespace | Medio | Ambienti multi-nodo, HA | | VM KVM | Hardware virtuale | Alto | Windows, kernel diverso |


LXC su Proxmox: servizi leggeri

LXC è ideale per servizi che richiedono poche risorse:

# Crea LXC Debian per Nginx reverse proxy
pct create 101 local:vztmpl/debian-12-standard_12.7-1_amd64.tar.zst \
  --hostname nginx-proxy \
  --cores 1 \
  --memory 512 \
  --rootfs local-lvm:8 \
  --net0 name=eth0,bridge=vmbr0,ip=192.168.10.50/24,gw=192.168.10.1 \
  --unprivileged 1

# Avvia e configura
pct start 101
pct exec 101 -- apt update && apt install -y nginx

LXC per servizi comuni

# DNS/DHCP con Pi-hole
pct create 102 ... --hostname pihole
pct exec 102 -- curl -sSL https://install.pi-hole.net | bash

# Reverse proxy con Nginx Proxy Manager  
pct create 103 ... --hostname nginx-pm
pct exec 103 -- docker-compose up -d  # (con Docker nel LXC)

# Monitoring con Uptime Kuma
pct create 104 ... --hostname uptime

Docker Compose: stack applicativi

Stack completo homelab

# docker-compose.yml - Stack homelab completo
version: '3.8'

services:
  # Nginx Proxy Manager - Reverse proxy con SSL automatico
  nginx-proxy:
    image: jc21/nginx-proxy-manager:latest
    restart: always
    ports:
      - "80:80"
      - "443:443"
      - "81:81"  # Admin UI
    volumes:
      - ./npm/data:/data
      - ./npm/letsencrypt:/etc/letsencrypt

  # Portainer - Gestione Docker via UI
  portainer:
    image: portainer/portainer-ce:latest
    restart: always
    ports:
      - "9443:9443"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - portainer_data:/data

  # Watchtower - Aggiornamento automatico container
  watchtower:
    image: containrrr/watchtower
    restart: always
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
    command: --schedule "0 4 * * *" --cleanup  # Update alle 4:00

  # Uptime Kuma - Monitoring servizi
  uptime-kuma:
    image: louislam/uptime-kuma:1
    restart: always
    ports:
      - "3001:3001"
    volumes:
      - uptime_data:/app/data

volumes:
  portainer_data:
  uptime_data:

Stack AI self-hosted

# AI stack
services:
  ollama:
    image: ollama/ollama:latest
    restart: always
    ports:
      - "11434:11434"
    volumes:
      - ollama_data:/root/.ollama
    deploy:
      resources:
        reservations:
          devices:
            - driver: nvidia
              count: 1
              capabilities: [gpu]

  open-webui:
    image: ghcr.io/open-webui/open-webui:main
    restart: always
    ports:
      - "3000:8080"
    environment:
      - OLLAMA_BASE_URL=http://ollama:11434
    depends_on:
      - ollama
    volumes:
      - webui_data:/app/backend/data

volumes:
  ollama_data:
  webui_data:

Dockerfile: build immagini custom

# Esempio: app Python con requirements
FROM python:3.11-slim

WORKDIR /app

# Installa dipendenze (cached layer)
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

# Copia codice
COPY . .

# Utente non-root (sicurezza)
RUN useradd -m appuser && chown -R appuser /app
USER appuser

EXPOSE 8000
CMD ["python", "app.py"]
# Build e push su registry privato
docker build -t mio-registry:5000/myapp:1.0 .
docker push mio-registry:5000/myapp:1.0

k3s: Kubernetes leggero per homelab

k3s è una distribuzione Kubernetes certificata CNCF, ottimizzata per edge e homelab:

# Installazione k3s (nodo master)
curl -sfL https://get.k3s.io | sh -

# Verifica
kubectl get nodes
kubectl get pods -A

# Token per aggiungere worker
cat /var/lib/rancher/k3s/server/node-token

# Installazione worker node
curl -sfL https://get.k3s.io | K3S_URL=https://master-ip:6443 \
  K3S_TOKEN=<TOKEN> sh -

Deploy applicazione su k3s

# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-homelab
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:alpine
        ports:
        - containerPort: 80
        resources:
          limits:
            memory: "128Mi"
            cpu: "100m"
---
apiVersion: v1
kind: Service
metadata:
  name: nginx-service
spec:
  selector:
    app: nginx
  ports:
  - port: 80
    targetPort: 80
  type: LoadBalancer
kubectl apply -f deployment.yaml
kubectl get pods
kubectl get svc

Registry Docker privato

# Registry locale con autenticazione
services:
  registry:
    image: registry:2
    restart: always
    ports:
      - "5000:5000"
    environment:
      REGISTRY_AUTH: htpasswd
      REGISTRY_AUTH_HTPASSWD_REALM: "Registry Realm"
      REGISTRY_AUTH_HTPASSWD_PATH: /auth/htpasswd
    volumes:
      - ./auth:/auth
      - registry_data:/var/lib/registry

  registry-ui:
    image: joxit/docker-registry-ui:latest
    ports:
      - "8080:80"
    environment:
      - REGISTRY_URL=http://registry:5000
    depends_on:
      - registry

Script di manutenzione

#!/bin/bash
# cleanup-docker.sh - Pulizia periodica Docker

echo "=== Docker Cleanup ==="

# Rimuovi container fermati
docker container prune -f

# Rimuovi immagini non usate
docker image prune -af --filter "until=720h"  # Più vecchie di 30 giorni

# Rimuovi volumi orfani
docker volume prune -f

# Rimuovi network non usate
docker network prune -f

# Report spazio liberato
docker system df

echo "=== Cleanup completato ==="

Monitoring container con Grafana

# Stack monitoring completo
services:
  prometheus:
    image: prom/prometheus:latest
    volumes:
      - ./prometheus.yml:/etc/prometheus/prometheus.yml
    ports:
      - "9090:9090"

  cadvisor:
    image: gcr.io/cadvisor/cadvisor:latest
    volumes:
      - /:/rootfs:ro
      - /var/run:/var/run:ro
      - /sys:/sys:ro
      - /var/lib/docker/:/var/lib/docker:ro
    ports:
      - "8081:8080"

  grafana:
    image: grafana/grafana:latest
    ports:
      - "3000:3000"
    volumes:
      - grafana_data:/var/lib/grafana
    environment:
      - GF_SECURITY_ADMIN_PASSWORD=admin

Best Practice

  • One process per container — un servizio per container
  • Utente non-root nei Dockerfile — USER appuser
  • Health checksHEALTHCHECK CMD curl -f http://localhost/ || exit 1
  • Limite risorse — sempre resources.limits in produzione
  • Backup volumi — script automatico per docker volume
  • Non montare /var/run/docker.sock in produzione se non necessario
  • Evitare tag latest in produzione — usa versioni esplicite

Risorse