Migre rapidamente para contêineres separados de web e dados

:warning: Aviso: Se você não se sente confortável atuando como administrador de sistemas Linux e não tem experiência com contêineres Docker, migrar para uma implantação com múltiplos contêineres causará dificuldades. Nesse caso, tanto a equipe quanto os voluntários aqui pedirão apropriadamente que você retorne a uma implantação única e independente, totalmente gerenciada pelo script launcher.

Se você migrar para uma implantação com múltiplos contêineres e seu sistema quebrar como resultado, é provável que você tenha a oportunidade de manter ambas as partes quebradas. Se você ler as instruções abaixo e parecer mágica, em vez de esclarecer como as coisas realmente funcionam dentro dos contêineres, corra, não caminhe, até sua implantação independente padrão mais próxima; isso fará um favor a você.

O método recomendado para migrar de uma implantação de contêiner único para uma implantação com múltiplos contêineres é essencialmente:

  • Faça um backup do seu Discourse
  • Jogue tudo fora
  • Comece do zero com uma implantação com múltiplos contêineres
  • Restaure seu backup

Se, como eu, você tiver um site grande que leva horas para restaurar, talvez se pergunte se existe uma maneira mais rápida. Não se pergunte mais! Eu migrei de uma implantação independente para uma implantação com três contêineres (web, dados e Redis) em menos tempo do que normalmente leva para ./launcher rebuild app nesse site. (12 minutos de tempo total de inatividade, enquanto reconstruir o aplicativo às vezes leva mais de 30 minutos.) Com base na minha experiência, eu manteria o Redis junto com o Postgres em um único contêiner de dados no futuro.

Se você fizer isso, assume a responsabilidade de saber quando precisa reconstruir seus outros contêineres (dados e, se for tolo como eu e separar o Redis, o Redis também). Você não receberá mais atualizações gratuitas de tudo com ./launcher rebuild app — se não tiver recursos para gerenciar esse processo, use uma implantação independente ou adquira o Discourse hospedado.

Teste

Não use este processo para migrar para múltiplos contêineres a menos que, após lê-lo, você também entenda como ele indicaria como migrar rapidamente de múltiplos contêineres para um único contêiner. Se isso não for óbvio para você após a leitura, então este post é uma tecnologia suficientemente avançada (ou seja, indistinguível de mágica), e é possível que você também não reconheça se esse processo quebrar no meio do caminho. Nesse caso, você pode acabar com um Discourse quebrado que só reconhecerá muito mais tarde. Se isso acontecer, você terá que manter ambas as partes quebradas. Quebrou, comprou, como dizem!

Backup

Faça o backup primeiro e ative os backups de miniaturas primeiro, para que você não precise reconstruí-los todos na restauração. Se você cometer um erro aqui, facilmente entrará em uma situação em que a maneira mais fácil, segura e rápida de recuperar é mudar para o método normal. Esteja pronto para voltar ao método recomendado se algo der errado.

Baixe seu backup. Os comandos abaixo envolvem mover arquivos dentro dos dados do Discourse e, se você cometer um erro, talvez tenha excluído seu backup. Então, baixe-o. E, se seu backup não incluir uploads, faça backup deles também. Eles também estão localizados onde você estará movendo arquivos.

Sério, faça o backup.

Quando fiz isso, primeiro fiz um backup, depois fiz um backup remoto do sistema, antes de prosseguir.

Configurar nova configuração com múltiplos contêineres

Você precisará de pelo menos containers/web_only.yml e containers/data.yml e, se também quiser separar o Redis, também de containers/redis.yml. Comece copiando samples/data.yml (e opcionalmente samples/redis.yml) para o diretório containers/.

Se estiver implantando o Redis separadamente, remova o modelo do Redis do topo do arquivo containers/data.yml. (Mas não faça isso sem um bom motivo; é apenas trabalho extra.)

Você tem duas maneiras de criar o web_only.yml.

  1. Copie samples/web_only.yml para containers/; depois, compare ambos com containers/app.yml, preservando qualquer configuração do Postgres em params: no seu novo containers/data.yml
  • Copie qualquer params: para o Postgres de containers/app.yml para containers/data.yml
  • Crie uma senha única para substituir SOME_SECRET
  1. Alternativamente, copie containers/app.yml para containers/web_only.yml e compare-o com samples/web_only.yml,
  • Remova todas as referências aos modelos do Postgres e Redis
  • Remova a seção inteira params: que continha apenas configurações do Postgres
  • Adicione uma seção links:, literalmente de samples/web_only.yml ou modificada (veja abaixo) se estiver implantando o Redis em um contêiner separado
  • Adicione uma seção de banco de dados de samples/web_only.yml e crie uma senha única para substituir SOME_SECRET
  • Altere as definições de volume de standalone para web_only

Aqui está a seção links: para usar se estiver separando o Redis em seu próprio contêiner, em vez de usar a configuração razoável padrão de agrupá-lo com o Postgres no contêiner de dados:

# Use a chave 'links' para vincular contêineres, ou seja, use a flag Docker --link.
links:
  - link:
      name: data
      alias: data
  - link:
      name: redis
      alias: redis

O link redis não é necessário se estiver combinando os contêineres Redis e Postgres como um único contêiner de dados; isso serve apenas para mostrar o que você faria.

Aqui está uma cópia das configurações atuais do Postgres em env em samples/data.yml nas quais você precisará alterar SOME_SECRET:

  ## TODO: configurar conectividade com os bancos de dados
  DISCOURSE_DB_SOCKET: ''
  #DISCOURSE_DB_USERNAME: discourse
  DISCOURSE_DB_PASSWORD: SOME_SECRET
  DISCOURSE_DB_HOST: data
  ## Se usar um único contêiner de dados+redis, o seguinte será "data"
  DISCOURSE_REDIS_HOST: redis

Note que, para uma implantação normal (não multisite), você não precisará modificar nenhuma outra linha. DISCOURSE_DB_SOCKET é para um socket de domínio Unix para o Postgres; não é um número de porta.

Aqui está um exemplo da alteração na definição de volumes no final do web_only.yml que você precisará usar se o copiar de app.yml em vez de samples/web_only.yml:

@@ -75,10 +80,10 @@
 ## O contêiner Docker é sem estado; todos os dados são armazenados em /shared
 volumes:
   - volume:
-      host: /var/discourse/shared/standalone
+      host: /var/discourse/shared/web_only
       guest: /shared
   - volume:
-      host: /var/discourse/shared/standalone/log/var-log
+      host: /var/discourse/shared/web_only/log/var-log
       guest: /var/log

Agora, defina a mesma senha secreta usada em containers/web_only.yml em containers/data.yml no lugar de SOME_SECRET.

Agora você está pronto para a migração.

Agora é o momento de fazer e baixar seu backup final antes de tentar a migração rápida. Lembre-se: se algo der errado aqui, vá imediatamente para o método recomendado. Não posso enfatizar isso o suficiente.

Contêineres de dados (Postgres) e Redis separados:

cd /var/discourse

./launcher stop app
cd  shared
mkdir data
mkdir redis
mv standalone/postgres_* data/
mv standalone/redis_data/ redis/
mv standalone web_only
mkdir -p data/log/var-log
mkdir -p redis/log/var-log

cd ..

./launcher destroy app

./launcher bootstrap data
./launcher bootstrap redis
./launcher start redis
./launcher start data

./launcher bootstrap web_only
./launcher start web_only

Contêiner de dados combinado Postgres+Redis:

cd /var/discourse

./launcher stop app
cd  shared
mkdir data
mv standalone/postgres_* data/
mv standalone/redis_data/ data/
mv standalone web_only
mkdir -p data/log/var-log

cd ..

./launcher destroy app

./launcher bootstrap data
./launcher start data

./launcher bootstrap web_only
./launcher start web_only

Note também que, se você configurou anteriormente um nginx externo, precisará alterar o caminho proxy_pass para corresponder ao novo local do socket web_only; por exemplo, de http://unix:/var/discourse/shared/standalone/nginx.http.sock: para http://unix:/var/discourse/shared/web_only/nginx.http.sock:

Para mim, em uma VM de 2 núcleos com 4 GB de RAM e um site com backups de 600 MB sem downloads, esse processo resultou em 12 minutos de inatividade. Sua experiência pode variar.

Note que nada disso até agora atualiza o launcher. Você pode não estar atualizado. (Por exemplo, executei isso após a atualização do Postgres 12 estar disponível, mas antes de aplicá-la. Esse processo deixou-me com o Postgres 10. Em seguida, a próxima coisa que fiz foi reconstruir o aplicativo de dados, o que atualizou o launcher e me levou com sucesso pelo processo de atualização do Postgres 12.)

O que fazer em atualizações futuras

Após essa migração, se precisar atualizar o Redis ou os dados, primeiro deve parar o aplicativo web. Isso se pareceria mais ou menos com isso:

./launcher stop web_only
./launcher rebuild data # e/ou redis
./launcher rebuild web_only

Note que, se você reconstruir o contêiner data (ou postgres, ou redis) precisará criar um novo contêiner web para reconectá-lo ao novo contêiner de dados. Você pode fazer isso reconstruindo web_only ou, se achar que não precisa reconstruí-lo, um ./launcher destroy web_only; ./launcher start web_only fará o trabalho (e se receber um erro sobre “contêiner de dados ausente” ou similar, é isso que você precisa fazer).

No entanto, quando nem o Postgres nem o Redis precisam de atualização, é muito mais rápido não ter que reconstruir esses contêineres, e a maioria das reconstruções de aplicativo é apenas ./launcher rebuild web_only.

Alternativamente, para ainda menos tempo de inatividade (variando entre 15 segundos e 2 minutos, conforme relatado):

./launcher bootstrap web_only
./launcher destroy web_only && ./launcher start web_only

Novamente, ao migrar para uma implantação com múltiplos contêineres, acompanhar quando isso é apropriado agora é sua responsabilidade. Você receberá notificações no console de Administração sobre atualizações, mas elas se aplicarão apenas ao contêiner web_only. Nada dirá quando você precisa atualizar o Postgres ou o Redis. Se fizer isso, leia a categoria de Anúncios antes de cada atualização de versão que fizer e leia as notas de lançamento para cada nova versão para a qual você está atualizando ou passando. Ou seja, se pular uma atualização de versão, não pule a leitura das notas de lançamento da versão que pulou. (Considere configurar um monitoramento nas notas de lançamento ou inscrever seu leitor de feeds em https://meta.discourse.org/tag/release-notes.rss para se manter atualizado.)

Note que reconstruir o contêiner web_only exige que o banco de dados esteja em execução, então você não pode acelerar as coisas reconstruindo todos os dois ou três contêineres em paralelo. Se for reconstruí-los todos a cada vez, mantenha-se com a implantação independente padrão recomendada; será mais rápido do que gerenciar múltiplos contêineres.

Revisão do Backup

Se você fizer backup dos uploads separadamente do banco de dados, espero que tenha um regime de backup remoto baseado em arquivos para os uploads, para que estejam sendo salvos para restauração em caso de desastre.

Revise sua implementação de backup remoto para garantir que ela fará backup dos uploads em /var/discourse/shared/web_only em vez de /var/discourse/shared/standalone, para que mantenha seus backups atualizados em sua nova implementação com múltiplos contêineres.

22 curtidas

Olá, mcdanlj! Sou novo aqui. Descobri que o Discourse tem dois métodos de implantação, um é o modo autônomo de app.yml, o outro é o seu método, que é dividir o banco de dados e o cache redis no modo multicontainer apenas para web de web-only.yml, data.yml, redis.yml. Mas, ao mesmo tempo, também descobri que app.yml também pode ser conectado ao redis e ao banco de dados modificando os parâmetros DISCOURSE_DB_HOST e DISCOURSE_REDIS_HOST, então por que precisamos dividir o app.yml em web-only.yml, data.yml e redis.yml?

Se você já tem um banco de dados e Redis (por exemplo, RDS e ElastiCache, ou criados por você de outra forma), então você não precisa ter os seus próprios.

Observe que cada Discourse precisa do seu próprio Redis.

1 curtida

Obrigado Jay pela sua explicação gentil! Mas ainda fico confuso. Do Tutorial do Falco notei que é fácil usar o rds e o elasticache da aws sem a necessidade de configurar web-only.yml, data.yml e redis.yml. O Tutorial do Falco apenas edita os parâmetros em app.yml. Mas o Tutorial do mcdanlj é diferente. É porque o fórum dele é muito grande? Portanto, ele não pode usar o caminho simples que Falco fornece?

Usar rds e executar seu próprio servidor de banco de dados são coisas diferentes. Se você tem muito dinheiro e conhecimento, rds é ótimo. Se você não sabe nada, uma instalação em um único contêiner é incrível. Se você tem pouco dinheiro e quer diminuir o tempo de inatividade, a abordagem de dois contêineres é boa.

Na maioria das vezes, você deve usar o que fizer mais sentido para você.

1 curtida

Muito obrigado! Talvez um único contêiner seja a melhor maneira para mim :rofl: Eu não percebia a diferença entre rds e meu próprio servidor de banco de dados antes de você me dizer :joy:

1 curtida

@ShawnLi Se o sistema de dois contêineres parece complicado, é um bom sinal de que a opção padrão de um contêiner é uma boa escolha para você. A implantação de dois contêineres economiza alguns minutos de inatividade aproximadamente uma vez por mês durante as atualizações, mas requer mais compreensão e exige que você siga manualmente os detalhes nos anúncios a cada nova versão.

É por isso que comecei com:

:grinning:

2 curtidas

Obrigado mcdanlj! Seu tutorial é ótimo e eu realmente aprendi muito com ele. Decidi escolher a configuração padrão simples de um contêiner. Sim, eu rodo :rofl:

2 curtidas