Ciao a tutti.
Ho una piccola istanza di Discourse in esecuzione da anni (con praticamente zero problemi): https://discuss.cubeisland.de/.
Ho sempre utilizzato il processo di deployment standard basato sul launcher su una VM dedicata (sul mio hardware in un data center). L’unica modifica apportata nel corso degli anni è stata la migrazione a un database PostgreSQL esterno condiviso.
Recentemente ho iniziato a migrare le applicazioni dalle VM dedicate a un Docker Swarm come passo preparatorio per migrare eventualmente a un cluster Kubernetes, principalmente per risparmiare risorse e rendere alcune parti dell’infrastruttura più “elastiche”.
Oggi ho deciso di occuparmi di questa piccola istanza di Discourse, una delle poche VM dedicate rimaste. “È già in esecuzione su Docker, quanto potrà mai essere difficile deployarla su Swarm?” ho pensato. E da quello che ho letto, in realtà potrebbe esserlo. Potrei semplicemente prendere l’immagine dall’istanza attualmente in esecuzione, caricarla nel nostro registro interno ed eseguirla nel Swarm, e tutto funzionerebbe perfettamente, il che è ottimo.
Ho esaminato i file del launcher, in particolare i template e gli esempi, e ho capito che potrebbe essere una buona idea separare Redis in un tale deployment. Forse potrei anche impostare un job CI per costruire nuove immagini quando aggiungo plugin o quando voglio aggiornare. Quindi ho clonato discourse_docker in locale, copiato la mia definizione esistente del contenitore app.yml nel clone e ho provato a eseguire ./launcher bootstrap app per costruire un’immagine che avrei poi potuto caricare nel mio registro, senza deployarla immediatamente.
A mia sorpresa, lo script ha tentato di connettersi al server PostgreSQL “production” per eseguire la migrazione del database, il che, per fortuna, non è riuscito a fare dal mio workstation locale.
Ho dato un’occhiata qui e sembra che questo sia il modo in cui funziona, il che mi fa chiedersi:
- Come si costruisce un contenitore per una nuova istanza, dove non ho ancora un database? Dovrei impostare il database production prima di poter costruire l’immagine?
- Immagino che db:migrate venga eseguito solo questa volta, quindi se ho diverse istanze simili (ad esempio prod e test), dovrei aggiornare una delle istanze per costruire la nuova immagine e poi non potrei usare la stessa immagine per la seconda istanza, anche se l’immagine sarebbe identica.
- Come si potrebbero costruire immagini per istanze in cui il server database non è accessibile dal sistema che costruisce l’immagine (il che non dovrebbe essere così raro).
Dopo aver letto diversi post (ovviamente incluso questo), sono perfettamente consapevole delle ragioni del processo di build così com’è ora e ne vedo il valore per il 99% delle persone che deployano Discourse in modo casuale sulle loro VM standard complete. Sono anche molto abituato ai modelli di contenitore “all-in-one” e non mi oppongo a questo. Dopo tutto, il valore chiave di Docker deriva dal fatto che il fornitore del software può preconfigurare configurazioni altamente ottimizzate e raggrupparle in un ambiente di esecuzione riproducibile, eliminando la necessità di molte conoscenze specifiche dell’applicazione da parte del team operativo. Quindi sono completamente d’accordo nell’utilizzare gli strumenti forniti da voi; perché dovrei aspettarmi che qualcun altro costruisca contenitori migliori rispetto al fornitore del software stesso? Perché vorrei separare nginx dall’applicazione Ruby, quando non c’è alcun beneficio da guadagnare, solo per rendere il deployment più “puro” (qualunque cosa significhi…)?
Tuttavia, è strano vedere un contenitore che modifica lo stato di runtime mentre è ben lontano dall’esecuzione. Eseguito già diverse applicazioni in contenitori e ne ho containerizzate diverse io stesso, alcune delle quali non erano mai state pensate per essere eseguite in contenitori.
L’esempio principale che mi viene in mente, di un’applicazione che gestisce requisiti/problemi simili a Discourse in modo simile, è GitLab. Anche se ora forniscono un chart Helm elegante per un deployment Kubernetes completamente decomposto “come dovrebbe essere”, indovino (senza guardare numeri specifici) che un simile 99% delle sue distribuzioni di piccole e medie dimensioni utilizza l’immagine Docker omnibus di GitLab (o il pacchetto OS, che è praticamente lo stesso). Hanno un processo di bootstrap simile, ma basato su Chef all’interno del contenitore, che viene eseguito ad ogni avvio e fa le solite cose come le migrazioni del database e la compilazione degli asset.
Sì, l’avvio di GitLab può richiedere diversi minuti a causa di questo, ma non è mai stato un problema per le distribuzioni che ho visto (alcune in aziende più grandi). Soprattutto con moderni sistemi di orchestrazione come Docker Swarm e Kubernetes e altri, che possono eseguire aggiornamenti rolling per te, dove l’istanza vecchia viene spenta solo se la nuova istanza è in esecuzione e supera con successo i controlli di health e readiness, un processo di deployment lungo potrebbe non essere effettivamente un problema. Ma anche senza aggiornamenti rolling sofisticati, che potrebbero o meno funzionare, in molte situazioni si può comunque gestire un certo tempo di inattività.
Quindi: è possibile configurare il launcher per saltare le operazioni dipendenti dal database durante la build dell’immagine e invece eseguire queste operazioni durante l’avvio del contenitore?
Sono sicuramente disposto a investire un po’ di tempo io stesso, ma il mio tempo serale è limitato, quindi qualsiasi indicazione sarebbe molto gradita.
Sono anche aperto a processi completamente diversi se pensate che questa idea sia stupida o non fattibile.
Grazie per qualsiasi feedback!