Docker e Kubernetes: container, non codice
"Funziona sulla mia macchina" non è una scusa accettabile. In che modo la containerizzazione garantisce la coerenza dallo sviluppo alla produzione.
La sindrome “Funziona sulla mia macchina”.
Sviluppatore A: “L’accesso funziona sul mio Mac.” Sviluppatore B: “Non funziona sul mio PC Windows.” Server: “Si blocca su Linux perché la versione di Node.js non corrisponde.” Questa è la deriva ambientale. Si sprecano migliaia di ore. Docker risolve questo problema. Non spediamo “Codice”. Spediamo un “Contenitore”. Un contenitore è una macchina virtuale leggera che contiene il sistema operativo (Alpine Linux), il runtime (nodo 18), le dipendenze (node_modules) e il codice. Se il contenitore si avvia sul tuo laptop, si avvierà sul server. Garantito. È l’unità standard di distribuzione.
Perché Maison Code ne parla
Noi di Maison Code diamo valore alla riproducibilità. Se un nuovo sviluppatore si unisce al team, non dovrebbe impiegare 3 giorni per installare Redis, Postgres e ImageMagick. Dovrebbero eseguire “docker-compose up” e codificare in 10 minuti. Utilizziamo Kubernetes (K8s) per i nostri clienti aziendali che necessitano di capacità di scalabilità massiccia e di autoriparazione. Ne parliamo perché DevOps non è un ripensamento; è il fondamento della velocità di sviluppo.
Il Dockerfile: la ricetta
Il Dockerfile definisce come costruire il contenitore.
“dockerfile N. 1. Immagine di base (piccola e sicura) DAL nodo: costruttore AS 18-alpine
2. Imposta la directory
DIR LAVORO /app
3. Installa le dipendenze (livello cache)
COPIA pacchetto*.json ./ ESEGUI npm ci
4. Copia il codice
COPIA. .
5. Costruisci
ESEGUI npm esegui build
--- Creazione in più fasi (ottimizzazione) ---
Scartiamo la fase di “costruttore” e conserviamo solo gli artefatti di produzione
DAL nodo:18-corridore AS alpino DIR LAVORO /app COPIA —from=builder /app/.next ./.next COPY —from=builder /app/public ./public COPY —from=builder /app/node_modules ./node_modules COPIA —from=builder /app/package.json ./package.json
6. Inizio
CMD [“npm”, “inizio”]
**Suggerimento per l'ottimizzazione**: **Build in più fasi**.
Nell'esempio sopra, utilizziamo una fase `builder` per compilare il codice. Quindi copiamo *solo* il risultato nella fase `runner`.
Lasciamo indietro il "Codice sorgente", il "Compilatore TypeScript" e le "DevDependencies".
Risultato: utilizza un'immagine da 100 MB anziché un'immagine da 1 GB. Distribuzione più rapida, runtime più sicuro.
## Docker Compose: orchestrazione locale
Raramente esegui un solo contenitore. Esegui un'app Web, un database e una cache.
`docker-compose.yml` li orchestra.
```yaml
versione: '3'
servizi:
web:
costruire: .
porte: ["3000:3000"]
ambiente:
DATABASE_URL: postgres://utente:pass@db:5432/miaapp
db:
immagine: postgres:15
ambiente:
POSTGRES_PASSWORD: superato
ridis:
immagine: redis:alpine
Ora, docker-compose up fa girare l’intero stack. Il contenitore “web” può comunicare con “db” semplicemente utilizzando il nome host “db”. DNS magico.
Kubernetes (K8s): Il Capitano
Docker esegue i contenitori. Kubernetes li gestisce. Se hai 1 server, usa Docker. Se disponi di 100 server, utilizza Kubernetes. Maniglie K8:
- Autoriparazione: “Il contenitore A si è bloccato. Riavviarlo.”
- Scalatura automatica: “L’utilizzo della CPU è elevato. Aggiungi altri 5 contenitori.”
- Aggiornamenti in sequenza: “Aggiorna la versione da 1 a 2. Fallo uno per uno. Se gli errori aumentano, esegui il rollback automaticamente.”
L’avvertimento “Eccessivo”.
Kubernetes è complesso. Ha una curva di apprendimento ripida (pod, distribuzioni, servizi, Ingress, grafici Helm). Per il 90% delle startup, K8 è eccessivo. Utilizza un PaaS (Platform as a Service) come Vercel, Railway o AWS App Runner. Eseguono contenitori per te senza il mal di testa di gestire il piano di controllo del cluster. Passa a K8 solo quando ti serve:
- Conformità (hosting in sede).
- Ottimizzazione dei costi su larga scala.
- Maglie di rete complesse.
7. Timone: il gestore dei pacchetti per K8
I file YAML di K8 sono dettagliati. “deployment.yaml” (50 righe). “service.yaml” (20 righe). “ingress.yaml” (30 righe). Moltiplicare per 3 ambienti (Dev, Staging, Prod). È ingestibile. Soluzione: timone. I grafici Helm sono modelli. “helm install my-app ./charts/my-app —set image.tag=v2”. Sostituisce le variabili nel modello e distribuisce i manifest. È “NPM per Kubernetes”.
8. GitOps (ArgoCD): La verità è in Git
Non eseguire mai kubectl apply -f file.yaml dal tuo laptop.
Questo crea “Deriva della configurazione”.
Soluzione: GitOps.
- Archivia tutti gli YAML in un Git Repo (“infra-repo”).
- Installare ArgoCD nel cluster.
- ArgoCD controlla il Git Repo.
- Se invii una modifica a Git, ArgoCD la applica automaticamente al cluster.
- Se qualcuno hackera manualmente il cluster, ArgoCD rileva la differenza e la ripristina (configurazione di autoriparazione). Lo stato del cluster corrisponde sempre a Git.
10. Immagini senza distro: la sicurezza attraverso il minimalismo
Alpine Linux è piccolo (5 MB). Ma ha una shell (/bin/sh).
Se un hacker entra, può eseguire comandi.
Soluzione: Immagini “Distroless” di Google.
Contengono solo la tua app e le sue dipendenze. Nessuna conchiglia. Nessun gestore di pacchetti. No “ls”.
Se un hacker sfrutta una vulnerabilità, verifica “Sono dentro!”… e poi non può fare nulla. Utilizza gcr.io/distroless/nodejs.
11. Budget per l’interruzione dei pod (PDB)
Hai 3 repliche della tua API.
Kubernetes vuole aggiornare il nodo (patch del sistema operativo).
Drena il nodo. Uccide tutte e 3 le repliche contemporaneamente.
Il sito non funziona più.
Correzione: definire un PDB. minDisponibile: 2.
K8 è costretto a ucciderne uno, attendere l’inizio di quello nuovo, quindi uccidere il successivo.
Ciò garantisce Distribuzioni Zero Downtime anche durante la manutenzione dell’infrastruttura.
12. Il punto di vista dello scettico
“Docker è lento su Mac.”
Contropunto:
Vero. Funziona in una macchina virtuale.
Ma il debug di “Perché bcrypt fallisce su Linux” richiede più tempo rispetto al calo di prestazioni del 5%.
Coerenza > Velocità pura.
Domande frequenti
D: Docker o macchina virtuale (VM)? R: Una VM cattura l’hardware (pesante). Un contenitore cattura lo spazio utente del sistema operativo (Light). Puoi eseguire 100 contenitori su un server che può contenere solo 5 VM.
D: Docker è sicuro?
R: Per impostazione predefinita, sì (isolamento).
Ma se esegui come “root” all’interno del contenitore e c’è un exploit del kernel, l’aggressore può scappare.
Best Practice: crea un utente generico (RUN adduser app) e passa ad esso (USER app) nel Dockerfile.
Conclusione
I contenitori sono i contenitori di spedizione del codice. Prima dei container standard, caricare una nave era un caos (barili, sacchi, scatole). Ora tutto sta in una scatola standard. Alla gru non importa cosa c’è dentro. Docker rende il tuo codice una casella standard. AWS è la gru. Imballalo bene e potrai spedirlo ovunque.
Incubi di distribuzione?
Se le tue distribuzioni sono situazioni instabili del tipo “ha funzionato sulla mia macchina”, Maison Code può Dockerizzare il tuo stack. Implementiamo pipeline CI/CD che costruiscono, testano e spediscono automaticamente i container.
Problemi di distribuzione?
Containerizziamo le applicazioni utilizzando Docker e le orchestriamo con Kubernetes per implementazioni a prova di proiettile. Assumi i nostri architetti.