È questo processo sicuro? Posso eseguire senza problemi una configurazione multicontenitore in un ambiente di sviluppo, ma se la utilizzo in produzione, mentre gli utenti accedono al vecchio contenitore e il nuovo viene avviato ed esegue la migrazione del database, le richieste al vecchio contenitore continueranno a utilizzare la logica backend precedente e a salvare i dati come definiti nella versione precedente, anche dopo il completamento della migrazione del database (ma prima che l’intero processo di avvio sia terminato).
Anche se so che questo non è un problema specifico di Discourse (un ambiente con più repliche potrebbe presentare lo stesso problema se una replica viene aggiornata prima delle altre, a meno che non si fermino tutte prima dell’aggiornamento, cosa che probabilmente non è fattibile se si desidera l’alta disponibilità), il processo che hai descritto è comunque sicuro in linea di principio?
Una cosa a cui posso pensare è assicurarsi di tenere sempre Discourse aggiornato per minimizzare le migrazioni del database tra i rebuild. Ma in ogni caso, questa non è ancora la soluzione ideale e potrebbero sorgere problemi anche in questo scenario.
La configurazione multicontenitore sembra essere uno degli approcci raccomandati (anche se non è quella standard con un solo contenitore), quindi penso che dovrebbe essere sicura e sto solo pensando troppo.
Sai se funziona senza problemi sui siti in produzione (eseguendo l’avvio in un contenitore mentre un altro è attivo)? Chiedo solo per avere riscontri da persone che lo hanno già fatto in produzione, per sapere se funziona bene anche dopo diversi rebuild, se ci sono insidie, ecc… Come ho detto, in un ambiente di sviluppo funziona senza problemi.
Se desideri un downtime pari a zero, ci sono alcuni passaggi aggiuntivi da seguire: disabilita “post-migrations” sui nuovi container, esegui il rollout completo del nuovo container, riabilita i post-migrations, quindi esegui nuovamente il rollout. In questo modo, si impedirà l’esecuzione di migrazioni che eliminano colonne fino a quando il vecchio codice non sarà completamente fermo.
Non esiste ancora una guida pratica per questo; è documentato solo qui:
Per la maggior parte, tuttavia, la maggior parte dei forum può tollerare un minuto o tre di downtime ogni mese.
Sì. Nella maggior parte dei casi non ci sono migrazioni che interrompono il contenitore in esecuzione.
Puoi anche configurarlo in modo da avere le migrazioni disabilitate nel file web_only.yml, quindi, dopo che il nuovo contenitore è in esecuzione, eseguire qualcosa del genere:
cd /var/www/discourse; SKIP_POST_DEPLOYMENT_MIGRATIONS=0 rake db:migrate
Poi selezioniamo il contenitore che vogliamo rendere attivo tramite un collegamento simbolico al socket effettivo, così:
Diciamo che vogliamo che il contenitore socket2 sia attivo:
ls -sf /var/discourse/shared/socket2/nginx.http.sock /var/run/nginx.http.sock
Diciamo che vogliamo apportare una modifica a socket1 e rendere socket1 attivo:
cd /var/discourse
./launcher rebuild socket1
ls -sf /var/discourse/shared/socket1/nginx.http.sock /var/run/nginx.http.sock
Notate che non c’è motivo di bootstrapare solo il contenitore socket1, perché il contenitore è esposto tramite un socket di dominio Unix nella sua directory condivisa / volume dedicata, quindi entrambi questi contenitori “web app” possono essere eseguiti contemporaneamente:
Non si verifica alcuna “collisione di binding delle porte” esposta come quando una porta del contenitore TCP/IP è esposta. Per questo motivo, in produzione espongo solo un socket di dominio Unix (non una porta TCP/IP).
Ovviamente, potete bootstrapare se lo desiderate:
cd /var/discourse
./launcher bootstrap socket1
./launcher start socket1
ls -sf /var/discourse/shared/socket1/nginx.http.sock /var/run/nginx.http.sock
Sta a voi, ma tenete presente che se eseguite entrambi i contenitori contemporaneamente, entrambi eseguiranno sidekiq ed eseguiranno lavori programmati, come è nostra esperienza; quindi sincronizziamo occasionalmente i nostri upload in entrambi i contenitori.
Questo funziona perfettamente per noi e possiamo ricostruire un contenitore web app e renderlo attivo con praticamente zero tempi di inattività. In produzione prendiamo molto sul serio i tempi di inattività e li evitiamo quando possibile.
Nota:
Questo metodo (sopra) è progettato per la parte dell’applicazione web della soluzione, non per il contenitore dati. Non ho creato una soluzione simile per i dati; ma chissà, forse un giorno passerò del tempo a costruire qualcosa di simile (ma diverso, ovviamente) per il contenitore dati (una sorta di “metodo con due contenitori dati, sincronizzazione dei DB”, totalmente da definire al momento nella mia mente).
Quindi, in realtà sto facendo l’opposto di questo:
Come ho detto, in ambiente di sviluppo funziona perfettamente.
In genere non configuro questo in sviluppo perché richiede più tempo per essere impostato e non è necessario in sviluppo perché un po’ di tempo di inattività è accettabile, dato che è solo “io e il codice” (non attivo con utenti e bot che colpiscono il sito) e inoltre non uso Docker in sviluppo** (sul desktop).
Spero che questo sia d’aiuto.
**Per “sviluppo”, intendo lo sviluppo software (ad esempio di plugin); non semplicemente mettere in “staging” un’installazione di Discourse, a cui mi riferisco come “staging” e non “sviluppo” (solo per essere molto chiaro).
Grazie, non lo sapevo. È un’ottima funzionalità e vedo come possa evitare problemi come quello che ho menzionato prima (anche se questo non dovrebbe evitare cambiamenti nella logica che utilizzano colonne già esistenti, ma questo dovrebbe essere un caso più raro).
Grazie per la risposta. SKIP_POST_DEPLOYMENT_MIGRATIONS sembra essere ciò che @riking ha menzionato e sembra essere ciò che cercavo, per evitare che le migrazioni interrompano le operazioni eseguite nel container in esecuzione.
Grazie per la spiegazione. Sembra un buon approccio per me, alternando due container (per poter avere un container in esecuzione mentre l’altro si avvia).
Quando ho detto “ambiente di sviluppo”, intendevo un ambiente di sviluppo remoto che ho utilizzato per testare la configurazione multicontainer (sia sulla stessa macchina sia con i container su macchine diverse).
Ho detto “dev” e non “staging” perché in un ambiente di staging utilizzerei i file yml con gli stessi plugin e un database di produzione di backup per i test. Ma è vero, se voglio semplicemente impostare un ambiente di sviluppo, nella maggior parte dei casi utilizzerei l’approccio con un solo container.
Per quanto ne so, questa guida è un mucchio di parole che girano attorno a:
eseguire un backup
creare una nuova istanza di Discourse completamente nuova, con più parole ma gli stessi risultati di eseguire semplicemente discourse_setup 2container
ripristinare
Perché non spostare o copiare /var/discourse/shared/standalone/{postgres,redis}* in /var/discourse/shared/data dopo uno spegnimento pulito e prima di avviare due nuovi container da file containers/*.yml separati? Un ciclo di backup/ripristino sembra un modo davvero pesante per spostare tutti quei dati, aggiungendo ore inutilmente al processo. Sto trascurando qualcosa di ovvio?
Ho appena testato questo processo sul mio Discourse di prova, e ho separato anche Redis, tanto per essere sicuro di coprire tutti gli aspetti. Modifica: ho spostato la descrizione in un nuovo argomento:
Il sito sembra funzionare correttamente senza un ciclo di backup/ripristino. C’è qualcosa di non ovvio che dovrei controllare?
Ho eseguito lo stesso processo per un Discourse relativamente grande e funziona perfettamente. Ho deciso che in produzione rinominerei il mio nuovo container web_only in app, così le mie dita continueranno a fare automaticamente la cosa giusta. Dopo aver scritto i nuovi file container/*.yml, il tempo di inattività per l’intera migrazione è stato di 12 minuti, molto più veloce di quanto sarebbe stato con un ciclo di backup/ripristino.
Immagino che in questo caso dovremo semplicemente accettare di non essere d’accordo. Penso che se qualcuno è in grado di gestire più container, possa anche eseguire alcuni comandi, e non credo che questi comandi siano più difficili da digitare rispetto al semplice usare bin/rails c e iniziare a scrivere comandi Ruby qui, né richiedano competenze significativamente diverse o maggiori rispetto a quelle necessarie per utilizzare più container. Tuttavia, sposterò il contenuto in un nuovo post separato, invece di lasciarlo sepolto in un commento qui.
…E, se commettono un errore, non c’è nulla che possa sostituire un backup prima di una migrazione! Spero di averlo chiarito nel mio articolo, ora collegato qui sopra!
Qui sta il difetto del tuo ragionamento. Aggiungere 2container a ./discourse-setup non include alcuna misura di competenza. Ci sono molte persone che eseguono due container semplicemente perché vedono argomenti come questo e presuppongono che esista una “ricetta segreta” o che sia “la cosa da fare”.
L’argomento su postgres 12 dovrebbe servire da monito riguardo alla complessità aggiuntiva. Utilizzare un backup come passaggio tra gli stati permette all’utente di tornare a un singolo container rinominando un singolo file; una volta che si inizia a spostare cartelle, questa semplicità viene meno.
@Stephen C’è un difetto nel tuo ragionamento: la descrizione dei container multipli è piena di avvertimenti secondo cui devi assumerti la responsabilità degli aggiornamenti e capire come funziona, e la lunga descrizione sopra è così oscurata che probabilmente chiunque la guardasse si arrenderebbe comunque. Vai a leggere il mio Migrate quickly to separate web and data containers e dimmi che non spaventerà le persone che avranno difficoltà a seguirlo, o che non mette in risalto la necessità di eseguire il backup e la possibilità di tornare a un backup se qualcosa va storto!
Ero profondamente infelice quando ho eseguito ./launcher rebuild app poco dopo aver migrato su un server più performante (per una correzione di sicurezza) e aver avuto il mio sito fuori servizio per un tempo eccessivamente lungo, gran parte del quale dedicato alla ricostruzione delle parti di postgres del container. È stato allora che ho trovato la documentazione a 2 container e questa documentazione e non volevo assolutamente subire un altro periodo di inattività di 4 ore per la migrazione, quindi ho continuato ad accettare lunghi tempi di inattività per ./launcher rebuild app per evitare le 4 ore di downtime che richiederebbe un ripristino. Come persona vagamente competente, sono stato molto infastidito per lungo tempo dal fatto che questa configurazione fosse di fatto nascosta.
L’argomento su postgres 12 è un ottimo riferimento, perché le persone finiscono per avere più tempo di inattività perché devono ricostruire l’intera applicazione più volte, quando potrebbero ricostruire solo il container postgres due volte. Non posso dire di aver letto l’intero thread a causa della cancellazione automatica dopo 6 giorni, ma non mi risulta affatto evidente che i deploy multi-container incompetenti siano il, o anche solo un, grosso problema lì.
(Scusa, a volte mi stanco un po’ dell’idea che “tutti gli utenti siano incompetenti” qui.)
Potrebbe non avere senso per te, ma per noi che siamo qui su meta da 6/7 anni offrendo assistenza alle persone in Support, avere una strategia di rollback avrà sempre senso.
I bug possono comunque finire nei test superati, occasionalmente i limiti di velocità di rubygems influenzano le ricostruzioni e persino GitHub ha avuto qualche problema. Per questo motivo, non vedo alcun valore nel cambiare lo stato in modo da rendere più difficile semplicemente rinominare un file ed eseguire ./launcher start app.
La tua propensione al rischio potrebbe essere diversa, nel qual caso puoi scegliere un percorso differente. Per coloro che aiutano regolarmente a rimediare ai danni, la guida attuale funziona bene.
Non ho la sensazione che tu abbia effettivamente letto il processo che ho scritto, dato che scrivi come se non avessi sottolineato la necessità di poter eseguire il ripristino. Ti prego di leggerlo e poi tornare indietro per valutare di modificare quanto hai scritto in modo che sia una dichiarazione veritiera riguardo alle mie istruzioni. Così com’è, ho la sensazione che tu mi stia “spiegando” senza aver avuto la cortesia di leggere ciò che ho scritto.
Tuttavia, ho aggiunto molti altri avvertimenti, incluso uno in alto, in aggiunta agli avvertimenti in questo post, che da cinque anni continua a essere la posizione canonica per le istruzioni su questo processo di migrazione.
Prima di tutto, grazie per aver cercato di sgombrare questa “giungla” per noi, avventurieri , probabilmente seguirò le tue orme tra qualche giorno…
Cosa c’è nel file multisite.yml?
Ho recentemente configurato un forum Discourse self-hosted su un VPS. I file caricati sono archiviati su Wasabi, così come i backup. Tutto è ospitato su Linode.
Ho utilizzato il modello standalone e ho trovato la procedura di configurazione un vero soffio di aria fresca rispetto ad altri software. È stato sublime! Una pura gioia. Vorrei che ogni progetto open source prestasse tanta attenzione all’installazione e alla configurazione quanto ha fatto Discourse.
Ecco il punto però. Ho un server PostgreSQL dedicato in esecuzione su un server separato, accessibile solo tramite un indirizzo RFC-1918 non raggiungibile da Internet, che vorrei utilizzare per Discourse. Non mi piace molto avere server di database in esecuzione sullo stesso server dell’applicazione o del web.
Quindi, esiste un modo per separare il database standalone e spostarlo sul mio cluster database dedicato?
Immagino che dovrò semplicemente eseguire un pgdump del database di Discourse, spostarlo sul mio database dedicato e ripristinarlo, seguito da un vacuum analyze su tutte le tabelle dopo il ripristino/importazione, e poi puntare semplicemente l’applicazione Discourse al nuovo database attraverso la rete.
Ma non riesco a trovare dove sono memorizzate le credenziali del database. Ho controllato in app.yml, ma non sembrano esserci voci relative al database, e quando ho guardato nella cartella ../templates/ nessuno dei file yml sembrava contenere le credenziali del database.
Se normalmente non ci sono credenziali per il database postgres integrato, è possibile eseguire un pgdump ed esportare il database dal container standalone?