Is this process safe? I can run a multicontainer setup just fine in a dev environment, but if I start using it in a production environment, while people are accessing the old container and the new container bootstrap and runs the db migration step, the requests to the old container will still use the old backend logic and save data as defined in the previous version, even after the db migration step ends (but before the entire bootstrap process is done).
Although I know that this is not a problem related to discourse itself (an environment with several replicas could have this problem if one replica is updated before the other, unless you stop all of them before upgrading, but this probably won’t be the case if you want HA), the process you described is still safe, in a general way?
One thing that I can think about is making sure to always keep discourse up to date to have the minimal db migration between rebuilds. But in any case, this still is not ideal, and problems could arise even in this case.
The multicontainer setup seems like one of the recommended approaches (although not the standard one with just 1 container), so I think it should be safe, and I’m just overthinking.
Do you know if it works just fine in production sites (doing the bootstrap in one container even while another is running)? I’m just asking to know about people that have already done it in production sites, to have some feedback and know if it works fine, even after several rebuilds, if there are some gotchas, etc… Like I said, in a dev environment it works fine.
If you want zero downtime, there’s a couple extra steps that need to be done - disable “post-migrations” on the new containers, roll out the new container fully, enable post-migrations, then roll out again. This will stop any column-dropping migrations from executing until the old code is no longer running.
There’s no howto for this yet, it’s only documented here:
For the most part, though, most forums can live with a minute or three of downtime every month.
Then we select the container we want to be live by a symbolic link to the actually socket, like this:
Say we want the socket2 container to be live:
ls -sf /var/discourse/shared/socket2/nginx.http.sock /var/run/nginx.http.sock
Say we want to make a change on socket1 and make socket1 live:
cd /var/discourse
./launcher rebuild socket1
ls -sf /var/discourse/shared/socket1/nginx.http.sock /var/run/nginx.http.sock
Notice, there is no reason to bootstrap only the socket1 container, because the container is exposed via a unix domain socket in it’s own shared directory / volume, so both of these “web app” containers can run at the same time:
This is no exposed “port binding collision” like when a TCP/IP container port is exposed. For this reason, I only expose a unix domain socket in production (not a TCP/IP port)
Of course, you can bootstrap if you want:
cd /var/discourse
./launcher bootstrap socket1
./launcher start socket1
ls -sf /var/discourse/shared/socket1/nginx.http.sock /var/run/nginx.http.sock
It’s up to you, but keep in mind if you run both containers at the same time, both will run sidekiq and run scheduled jobs, so has been our experience; so we occasionally sync our uploads in both containers.
This works flawlessly for us and we can rebuild a web app container and make it live with basically zero downtime. We take downtime very seriously in production and avoid it whenever we can.
Note:
This method (above) is designed for the web app part of the solution, not for the data container. I have not created a similar solution for data; but who knows, maybe someday, I’ll spend some time and build something similar (but different, of course) for the data container (some kind of "two data container, sync the DBs, method, totally TBD at this point in my mind).
So, I am actually doing the opposite of this:
Like I said, in a dev environment it works fine.
I generally do not set this up in dev because it takes longer to set up and is not necessary in dev because a little down time is fine, since it’s just “me and the code” (not live with users and bots hitting the site) and plus I do not use docker in development** (on the desktop).
Hope this helps.
**By “development”, I mean software (for example plugin) development; not just simply “staging” a Discourse install, which I refer to as “staging” not “development” (just to be quite clear).
Thanks, I didn’t know about that. It’s a great feature and can see it avoiding problems like the one I mentioned before (although this shouldn’t avoid changed logic using already existing columns, but this should be a more rare case).
Thanks for the answer. The SKIP_POST_DEPLOYMENT_MIGRATIONS seems like it’s what @riking mentioned and seems like what I was after, to avoid migrations breaking stuff done in the running container.
Thanks for your explanation. That seems like a good approach to me, alternating between 2 containers (to be able to have 1 running container while the other bootstrap).
I said dev environment meaning to be that it was a remote development environment that I used to test the multicontainer setup (both in the same machine as well as having the containers in different machines).
I said dev and not staging because in a staging environment I would use the yml files with the same plugins and use a backup production database to test. But true, if I just want to setup a dev environment, in most cases, I would use the 1 container approach.
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?