Aiuto ripristino - sistema bloccato a mezzanotte

Va bene, era inevitabile che accadesse; le cose erano andate troppo bene per troppo tempo. Anni di funzionamento in modalità “cruise control”, con il sistema che si aggiornava automaticamente e io aggiornavo Discourse ogni poche settimane. A mezzanotte ieri, Amazon ha segnalato che il sistema non rispondeva: Discourse era offline e la CPU era al 100% fino a esaurimento delle risorse CPU di AWS. Non sono riuscito ad accedere al sistema; l’unica volta che, dopo diversi riavvii, sono riuscito ad accedere per un istante, ho visto questo in htop che consumava molta CPU:

snap lxd activate

Se qualcuno ha mai visto qualcosa del genere e può chiarire perché ciò possa essere accaduto da solo, sarebbe molto apprezzato per future referenze.

Venendo al problema urgente di fronte, ho proceduto a ricostruire un nuovo server su AWS utilizzando Ubuntu 20 LTS. La configurazione di Discourse è stata estremamente semplice. Avevo una copia del file app.yml che ho utilizzato per ricreare il forum Discourse. Il vecchio server utilizzava S3 sia per i backup che per i contenuti (immagini, ecc.).

Dopo aver creato il server, ho scaricato l’ultimo file di backup di Discourse da S3, lo ho caricato manualmente sul server Discourse e ho premuto il pulsante Restore. Dopo alcuni minuti ho ottenuto questo errore:

[2022-06-09 09:01:56] ALTER TABLE
[2022-06-09 09:01:56] ALTER TABLE
[2022-06-09 09:01:56] Migrating the database...
[2022-06-09 09:02:11] == 20220308201942 CreateUploadReferences: migrating ===========================
-- create_table(:upload_references, {})
   -> 0.0486s
-- add_index(:upload_references, [:upload_id, :target_type, :target_id], {:unique=>true, :name=>"index_upload_references_on_upload_and_target"})
   -> 0.0030s
== 20220308201942 CreateUploadReferences: migrated (0.0580s) ==================

== 20220309132719 CopyPostUploadsToUploadReferences: migrating ================
-- execute("INSERT INTO upload_references(upload_id, target_type, target_id, created_at, updated_at)\nSELECT post_uploads.upload_id, 'Post', post_uploads.post_id, uploads.created_at, uploads.updated_at\nFROM post_uploads\nJOIN uploads ON uploads.id = post_uploads.upload_id\nON CONFLICT DO NOTHING\n")
   -> 0.0595s
== 20220309132719 CopyPostUploadsToUploadReferences: migrated (0.0602s) =======

== 20220309132720 CopyPostUploadsToUploadReferencesForSync: migrating =========
-- execute("INSERT INTO upload_references(upload_id, target_type, target_id, created_at, updated_at)\nSELECT upload_id, 'Post', post_id, NOW(), NOW()\nFROM post_uploads\nON CONFLICT DO NOTHING\n")
   -> 0.0076s
== 20220309132720 CopyPostUploadsToUploadReferencesForSync: migrated (0.0080s) 

== 20220330160747 CopySiteSettingsUploadsToUploadReferences: migrating ========
-- execute("WITH site_settings_uploads AS (\n  SELECT id, unnest(string_to_array(value, '|'))::integer upload_id\n  FROM site_settings\n  WHERE data_type = 17\n  UNION\n  SELECT id, value::integer\n  FROM site_settings\n  WHERE data_type = 18 AND value != ''\n)\nINSERT INTO upload_references(upload_id, target_type, target_id, created_at, updated_at)\nSELECT site_settings_uploads.upload_id, 'SiteSetting', site_settings_uploads.id, uploads.created_at, uploads.updated_at\nFROM site_settings_uploads\nJOIN uploads ON uploads.id = site_settings_uploads.upload_id\nON CONFLICT DO NOTHING\n")
   -> 0.0034s
== 20220330160747 CopySiteSettingsUploadsToUploadReferences: migrated (0.0038s) 

== 20220330160751 CopyBadgesUploadsToUploadReferences: migrating ==============
-- execute("INSERT INTO upload_references(upload_id, target_type, target_id, created_at, updated_at)\nSELECT badges.image_upload_id, 'Badge', badges.id, uploads.created_at, uploads.updated_at\nFROM badges\nJOIN uploads ON uploads.id = badges.image_upload_id\nWHERE badges.image_upload_id IS NOT NULL\nON CONFLICT DO NOTHING\n")
   -> 0.0006s
== 20220330160751 CopyBadgesUploadsToUploadReferences: migrated (0.0010s) =====

== 20220330160754 CopyGroupsUploadsToUploadReferences: migrating ==============
-- execute("INSERT INTO upload_references(upload_id, target_type, target_id, created_at, updated_at)\nSELECT groups.flair_upload_id, 'Group', groups.id, uploads.created_at, uploads.updated_at\nFROM groups\nJOIN uploads ON uploads.id = groups.flair_upload_id\nWHERE groups.flair_upload_id IS NOT NULL\nON CONFLICT DO NOTHING\n")
   -> 0.0050s
== 20220330160754 CopyGroupsUploadsToUploadReferences: migrated (0.0055s) =====

== 20220330160757 CopyUserExportsUploadsToUploadReferences: migrating =========
-- execute("INSERT INTO upload_references(upload_id, target_type, target_id, created_at, updated_at)\nSELECT user_exports.upload_id, 'UserExport', user_exports.id, uploads.created_at, uploads.updated_at\nFROM user_exports\nJOIN uploads ON uploads.id = user_exports.upload_id\nON CONFLICT DO NOTHING\n")
   -> 0.0013s
== 20220330160757 CopyUserExportsUploadsToUploadReferences: migrated (0.0041s) 

== 20220330164740 CopyThemeFieldsUploadsToUploadReferences: migrating =========
-- execute("INSERT INTO upload_references(upload_id, target_type, target_id, created_at, updated_at)\nSELECT theme_fields.upload_id, 'ThemeField', theme_fields.id, uploads.created_at, uploads.updated_at\nFROM theme_fields\nJOIN uploads ON uploads.id = theme_fields.upload_id\nWHERE type_id = 2\nON CONFLICT DO NOTHING\n")
   -> 0.0006s
== 20220330164740 CopyThemeFieldsUploadsToUploadReferences: migrated (0.0010s) 

== 20220404195635 CopyCategoriesUploadsToUploadReferences: migrating ==========
-- execute("INSERT INTO upload_references(upload_id, target_type, target_id, created_at, updated_at)\nSELECT categories.uploaded_logo_id, 'Category', categories.id, uploads.created_at, uploads.updated_at\nFROM categories\nJOIN uploads ON uploads.id = categories.uploaded_logo_id\nWHERE categories.uploaded_logo_id IS NOT NULL\nON CONFLICT DO NOTHING\n")
   -> 0.0095s
-- execute("INSERT INTO upload_references(upload_id, target_type, target_id, created_at, updated_at)\nSELECT categories.uploaded_background_id, 'Category', categories.id, uploads.created_at, uploads.updated_at\nFROM categories\nJOIN uploads ON uploads.id = categories.uploaded_background_id\nWHERE categories.uploaded_background_id IS NOT NULL\nON CONFLICT DO NOTHING\n")
   -> 0.0004s
== 20220404195635 CopyCategoriesUploadsToUploadReferences: migrated (0.0103s) =

== 20220404201949 CopyCustomEmojisUploadsToUploadReferences: migrating ========
-- execute("INSERT INTO upload_references(upload_id, target_type, target_id, created_at, updated_at)\nSELECT custom_emojis.upload_id, 'CustomEmoji', custom_emojis.id, uploads.created_at, uploads.updated_at\nFROM custom_emojis\nJOIN uploads ON uploads.id = custom_emojis.upload_id\nWHERE custom_emojis.upload_id IS NOT NULL\nON CONFLICT DO NOTHING\n")
   -> 0.0032s
== 20220404201949 CopyCustomEmojisUploadsToUploadReferences: migrated (0.0036s) 

== 20220404203356 CopyUserProfilesUploadsToUploadReferences: migrating ========
-- execute("INSERT INTO upload_references(upload_id, target_type, target_id, created_at, updated_at)\nSELECT user_profiles.profile_background_upload_id, 'UserProfile', user_profiles.user_id, uploads.created_at, uploads.updated_at\nFROM user_profiles\nJOIN uploads ON uploads.id = user_profiles.profile_background_upload_id\nWHERE user_profiles.profile_background_upload_id IS NOT NULL\nON CONFLICT DO NOTHING\n")
   -> 0.0017s
-- execute("INSERT INTO upload_references(upload_id, target_type, target_id, created_at, updated_at)\nSELECT user_profiles.card_background_upload_id, 'UserProfile', user_profiles.user_id, uploads.created_at, uploads.updated_at\nFROM user_profiles\nJOIN uploads ON uploads.id = user_profiles.card_background_upload_id\nWHERE user_profiles.card_background_upload_id IS NOT NULL\nON CONFLICT DO NOTHING\n")
   -> 0.0011s
== 20220404203356 CopyUserProfilesUploadsToUploadReferences: migrated (0.0033s) 

== 20220404204439 CopyUserAvatarsUploadsToUploadReferences: migrating =========
-- execute("INSERT INTO upload_references(upload_id, target_type, target_id, created_at, updated_at)\nSELECT user_avatars.custom_upload_id, 'UserAvatar', user_avatars.id, uploads.created_at, uploads.updated_at\nFROM user_avatars\nJOIN uploads ON uploads.id = user_avatars.custom_upload_id\nWHERE user_avatars.custom_upload_id IS NOT NULL\nON CONFLICT DO NOTHING\n")
   -> 0.0200s
-- execute("INSERT INTO upload_references(upload_id, target_type, target_id, created_at, updated_at)\nSELECT user_avatars.gravatar_upload_id, 'UserAvatar', user_avatars.id, uploads.created_at, uploads.updated_at\nFROM user_avatars\nJOIN uploads ON uploads.id = user_avatars.gravatar_upload_id\nWHERE user_avatars.gravatar_upload_id IS NOT NULL\nON CONFLICT DO NOTHING\n")
   -> 0.0069s
== 20220404204439 CopyUserAvatarsUploadsToUploadReferences: migrated (0.0276s) 

== 20220404212716 CopyThemeSettingsUploadsToUploadReferences: migrating =======
-- execute("INSERT INTO upload_references(upload_id, target_type, target_id, created_at, updated_at)\nSELECT theme_settings.value::int, 'ThemeSetting', theme_settings.id, uploads.created_at, uploads.updated_at\nFROM theme_settings\nJOIN uploads ON uploads.id = theme_settings.value::int\nWHERE data_type = 6 AND theme_settings.value IS NOT NULL AND theme_settings.value != ''\nON CONFLICT DO NOTHING\n")
   -> 0.0025s
== 20220404212716 CopyThemeSettingsUploadsToUploadReferences: migrated (0.0030s) 

== 20220526203356 CopyUserUploadsToUploadReferences: migrating ================
-- execute("INSERT INTO upload_references(upload_id, target_type, target_id, created_at, updated_at)\nSELECT users.uploaded_avatar_id, 'User', users.id, uploads.created_at, uploads.updated_at\nFROM users\nJOIN uploads ON uploads.id = users.uploaded_avatar_id\nWHERE users.uploaded_avatar_id IS NOT NULL\nON CONFLICT DO NOTHING\n")
   -> 0.0227s
== 20220526203356 CopyUserUploadsToUploadReferences: migrated (0.0234s) =======


[2022-06-09 09:02:11] Reconnecting to the database...
[2022-06-09 09:02:12] Reloading site settings...
[2022-06-09 09:02:12] Disabling outgoing emails for non-staff users...
[2022-06-09 09:02:14] Disabling readonly mode...
[2022-06-09 09:02:14] Clearing category cache...
[2022-06-09 09:02:14] Reloading translations...
[2022-06-09 09:02:14] Remapping uploads...
[2022-06-09 09:02:14] Restoring uploads, this may take a while...
[2022-06-09 09:03:05] EXCEPTION: 509 of 1823 uploads are not migrated to S3. S3 migration failed for db 'default'.
[2022-06-09 09:03:05] /var/www/discourse/lib/file_store/to_s3_migration.rb:132:in `raise_or_log'
/var/www/discourse/lib/file_store/to_s3_migration.rb:79:in `migration_successful?'
/var/www/discourse/lib/file_store/to_s3_migration.rb:373:in `migrate_to_s3'
/var/www/discourse/lib/file_store/to_s3_migration.rb:66:in `migrate'
/var/www/discourse/lib/file_store/s3_store.rb:328:in `copy_from'
/var/www/discourse/lib/backup_restore/uploads_restorer.rb:62:in `restore_uploads'
/var/www/discourse/lib/backup_restore/uploads_restorer.rb:44:in `restore'
/var/www/discourse/lib/backup_restore/restorer.rb:61:in `run'
/var/www/discourse/script/spawn_backup_restore.rb:23:in `restore'
/var/www/discourse/script/spawn_backup_restore.rb:36:in `block in <main>'
/var/www/discourse/script/spawn_backup_restore.rb:4:in `fork'
/var/www/discourse/script/spawn_backup_restore.rb:4:in `<main>'

Qualcuno può consigliarmi qual è il problema e come posso ripristinare il server dai backup del server Amazon S3?

Ciao,
dopo aver ricreato il nuovo server da app.yml, hai avuto accesso ai backup nella sezione https://your.domain/admin/backups?

No, dopo aver ricreato da app.yml mi ha solo fornito una nuova configurazione pulita senza nulla. Ho scaricato l’ultimo backup da S3 e l’ho caricato manualmente su Discourse localmente e ho premuto ripristina.

Inizia a ripristinarlo, vedo tutte le impostazioni (incluse S3, le credenziali, tutto dalla pagina Impostazioni) tornare, vedo tutte le categorie apparire e i post apparire e tutto. Poi improvvisamente dopo pochi minuti ricevo un messaggio di logout e tutte le categorie, gli argomenti scompaiono e i log mostrano quell’errore (Sembra che torni indietro).

:thinking: quindi la configurazione s3 non è in app.yml (come descritto qui Configure an S3 compatible object storage provider for uploads )? Ma configurata come in Set up file and image uploads to S3

No, non vedo questo in app.yml

Tutte le impostazioni S3 sono state definite nelle pagine Admin → Impostazioni e ha funzionato bene per un anno finché non ho dovuto ripristinarlo quando il server è andato in crash la scorsa notte.

Corretto, questo è ciò che ho usato per configurare i backup e i caricamenti S3.

Penso che proverei a modificare app.yml con le tue impostazioni e da lì credo (spero?) che dovresti vedere i tuoi backup nella sezione admin e ripristinare da lì, senza l’importazione manuale e i caricamenti, che non dovresti dover ripristinare, ma sembrano essere inclusi nei backup. Non so perché stia fallendo però…

Credo che ciò possa essere dovuto al fatto che il tuo backup contenga un mix di caricamenti S3 e locali. Temo che non sia nel mio campo di competenza, ma c’è una discussione e una soluzione in questo argomento che ti permette di aggirare il problema. Tuttavia, era per un numero molto inferiore di errori, quindi potresti voler tenere conto di ciò:

Grazie, purtroppo il mio sito è andato in crash, quindi mi rimangono solo i caricamenti e i backup su S3. Presumo che non ci sia modo per me di migrare eventuali file locali rimanenti su S3 ora.

Quindi mi chiedo quali siano le mie opzioni al momento? C’è un modo per ripristinare dai backup S3 e ignorare i file locali? Ho trovato un modo per ignorare il caricamento su S3, ma poi quasi tutti i post hanno collegamenti/immagini interrotti (il 90%+ è probabilmente su S3 perché ho impostato il caricamento su S3 molti, molti anni fa).

Quindi un aggiornamento per coloro che potrebbero avere lo stesso problema (in pratica non riesco a ripristinare da un backup e il server è andato in crash a causa di un aggiornamento di sistema difettoso).

Per quanto ne so, la causa principale del problema è che ci sono caricamenti locali E caricamenti S3, quindi quando lo strumento di ripristino sta cercando di ripristinare, si blocca perché non sa come gestire contemporaneamente ripristini locali e S3 (forse è ora che Discourse riveda backup/ripristini).

Grazie a @RGJ per questo suggerimento, ha suggerito di forzare Discourse a ignorare il caricamento S3 durante il ripristino:

  1. Aggiungi una riga al tuo app.yml DISCOURSE_ENABLE_S3_UPLOADS=false
  2. Ricostruisci Discourse ./launcher rebuild app
  3. Tenta un ripristino (dalla pagina Backup della GUI o utilizzando la CLI)
  4. Quindi, dopo il ripristino, rimuovi quella riga da app.yml e ricostruisci ancora una volta

Sebbene questo abbia funzionato, è importante notare che il forum era gravemente danneggiato, le categorie, le impostazioni e i post sono stati ripristinati, tuttavia tutte le immagini, i collegamenti, i documenti incorporati, ecc. erano danneggiati e hanno generato errori.

La soluzione disperata:
Sono riuscito a recuperare il vecchio server ed estratto la directory /var/discourse (tar/gz) e l’ho copiata sul nuovo server ed eseguito ./launcher rebuild app. Questo ha completamente ripristinato il funzionamento del forum, tuttavia il problema fondamentale rimane: i backup NON funzioneranno perché hanno un mix di caricamenti locali e S3.

Quindi ho davvero bisogno di consigli sul modo migliore per risolvere questo problema una volta per tutte. È meglio/più facile spostare tutti i caricamenti da locale a S3 o da S3 a locale e come si fa? L’intero scopo di un backup è aiutare in situazioni come questa, ma mi ha deluso, quindi ho bisogno che tu lo risolva.

Se si configura come descritto in Utilizzo dello storage di oggetti per i caricamenti (S3 e cloni) si dovrebbe essere in grado di

 rake uploads:migrate_to_s3

Se si desidera smettere di usare s3, allora si può entrare nella console rails e impostare

  SiteSetting.include_s3_uploads_in_backups=true

Quindi eseguire un backup, assicurarsi di non avere s3 configurato nel proprio file app.yml e ripristinare il backup. Penso che questo ripristinerà i backup in locale.

Ma in entrambi i casi, consiglierei comunque di impostare le chiavi e il bucket di backup nelle variabili ENV nel proprio file app.yml e quindi verificare che sia possibile ripristinarlo in un nuovo sito.

Ok, penso di essermi un po’ confuso qui.

Penso che la cosa ideale da fare sarebbe avere tutti gli upload locali e salvare i backup (zip) su S3. In questo modo il backup è disponibile su S3 qualora succedesse qualcosa al server, ma il backup stesso è autonomo, senza dipendenze, quindi dovrebbe essere facile ripristinarlo su un nuovo server.

Quindi, se ho capito bene, dovrei seguire queste istruzioni:

If you want to stop using s3, then you can enter the rails console and set

  SiteSetting.include_s3_uploads_in_backups=true
Then take a backup, make sure that you do not have s3 configured in your app.yml and restore the backup. I think that this will restore backups to local.

e poi

  1. disabilitare l’opzione enable upload to S3 in Admin → Settings → Files
  2. abilitare l’opzione di backup su S3 nella pagina Admin → Settings → Backups

È corretto?

Questa è la parte che mi ha confuso, perché dovrei voler mettere la configurazione S3 nel file app.yml?

In modo da avere accesso ai tuoi backup tramite un ripristino da riga di comando prima di ripristinare il tuo backup. Altrimenti, devi configurare un account amministratore e quindi configurare S3 e quindi ripristinare. Allo stesso modo, tutte le impostazioni che inserisci nel tuo database vengono sovrascritte quando ripristini il database.

Penso che la best practice sia configurare S3 solo tramite variabili ENV nel file app.yml. Probabilmente avrebbe senso renderle impostazioni nascoste, se non per le centinaia di persone che sarebbero sorprese dalla loro scomparsa.

Perché altrimenti avrai problemi a ripristinare.

Come si ripristina un backup da S3 utilizzando la riga di comando? Secondo le istruzioni qui: Restore a backup from the command line
Dice che puoi inserire il file di backup nella cartella /var/discourse/shared/standalone/backups/default e quindi avviare un ripristino dalla CLI. Questo è ciò che avevo fatto con il tuo suggerimento in precedenza (che alla fine ha portato a collegamenti interrotti, sfortunatamente), ma funziona.

Come si ripristina direttamente da S3 utilizzando la CLI?

cd /var/discourse
./launcher enter app
discourse restore

Stamperà i backup disponibili che potrai quindi copiare/incollare quello che desideri ripristinare.

Grazie, quindi leggerà i backup S3 e li elencherà come opzione.

Jay, per dare seguito a un tuo suggerimento di spostare gli asset in locale:

Penso che tu possa impostare un’impostazione nascosta include_s3_uploads_in_backups su true e poi fare un backup e ripristinarlo quando S3 è disattivato per smettere di usare S3.

Avere backup S3 con essi configurati in app.yml significa che puoi fare un ripristino da riga di comando con solo il file app.yml (dopo aver clonato discourse e installato docker).

Per il primo passaggio dovrei eseguire il backup dei bucket S3 o si tratta di un’operazione sicura per i bucket?

Beh, almeno ho capito perché il mio server è andato in crash la scorsa notte (e di nuovo oggi dopo una ricostruzione completa :frowning: , vedi questo argomento per i dettagli: Ubuntu 20.04 kernel update with docker causing a crash on EC2 and Lightsail

Per farlo funzionare da un backup, ho dovuto:

  1. disabilitare Impostazioni → Fileabilita caricamenti s3
  2. Impostazioni → Backupposizione di backupS3
  3. abilitare Impostazioni → Backupbackup con caricamenti

Poi ho eseguito un backup e sono stato in grado di ripristinarlo con successo. Tuttavia, una cosa si è rotta: tutti gli allegati (file) ora hanno collegamenti non validi. Le immagini vanno tutte bene, ma i collegamenti degli allegati come https://domain.com/uploads/short-url/phu1HOLvkE8LWpkKYfnMPSWsvHh.zip ora mi danno un errore

Oops! That page doesn’t exist or is private.

C’è un modo per correggere questi collegamenti short-url?

Potresti provare a eseguire una ricostruzione HTML (o rebake) su uno di quegli argomenti per vedere se risolve il problema.

Grazie. Esiste una guida su come emettere il comando per eseguire il bake di argomenti specifici?