Olá a todos.
Tenho uma instância do Discourse bastante pequena em execução (na verdade, há anos, com praticamente zero problemas): https://discuss.cubeisland.de/.
Tenho usado o processo de implantação padrão baseado no launcher em uma VM dedicada (em meu próprio hardware em um data center). A única coisa que mudei ao longo dos anos foi migrar para um banco de dados PostgreSQL externo compartilhado.
Recentemente, comecei a migrar aplicativos de VMs dedicadas para um swarm Docker como passo preparatório para eventualmente migrar para um cluster Kubernetes, principalmente para economizar recursos e tornar partes da infraestrutura mais “elásticas”.
Hoje foi o dia em que olhei para essa pequena instância do Discourse, uma das poucas VMs de aplicativo dedicadas restantes. “Já está rodando no Docker, quão difícil pode ser implantá-la em um swarm”, pensei. E, pelo que li, realmente seria. Posso simplesmente pegar a imagem da instância em execução atualmente, enviá-la ao nosso registro interno e executá-la no swarm, e tudo funcionaria perfeitamente, o que é ótimo.
Analisei os arquivos do launcher, especialmente os templates e exemplos, e percebi que provavelmente seria uma boa ideia ter o Redis separado em tal implantação. Talvez eu pudesse configurar um job de CI para construir novas imagens quando adicionar plugins ou quiser atualizar. Então, verifiquei o discourse_docker localmente, copiei minha definição de container app.yml existente para a cópia e tentei executar ./launcher bootstrap app para construir uma imagem que eu pudesse então enviar ao meu registro, sem implantá-la imediatamente.
Para minha surpresa, o script tentou conectar ao servidor PostgreSQL de “produção” para migrar o banco de dados, o que, felizmente, ele não tinha acesso a partir da minha estação de trabalho local.
Procurei por aqui e aparentemente é assim que funciona, o que me faz questionar:
- Como construiria um container para uma nova instância, onde ainda não tenho um banco de dados? Preciso configurar o banco de dados de produção antes de poder construir a imagem?
- Suponho que essa seja a única vez que db:migrate é executado. Então, se eu tiver várias instâncias semelhantes (por exemplo, produção e teste), precisaria atualizar uma das instâncias para construir a nova imagem e, em seguida, não poderia usar a mesma imagem para a segunda instância, mesmo que a imagem fosse idêntica.
- Como proceder para construir imagens para instâncias onde o servidor de banco de dados não é acessível a partir do sistema que está construindo a imagem (o que não deve ser tão incomum).
Depois de ler alguns posts (obviamente incluindo este), estou perfeitamente ciente das razões para o processo de construção como ele está atualmente e vejo o valor dele para os mencionados 99% das pessoas que implantam o Discourse casualmente em suas VMs padrão completas. E estou muito acostumado com modelos de container “tudo em um” e não me oponho a isso. Afinal, o valor principal do Docker vem do fato de que o fornecedor do software pode pré-configurar configurações altamente otimizadas e agrupá-las em um ambiente de execução reproduzível, eliminando a necessidade de muito conhecimento específico do aplicativo no lado das operações. Então, estou totalmente alinhado com o uso das ferramentas fornecidas por vocês. Por que eu esperaria que alguém construísse containers melhores do que o próprio fornecedor do software? Por que eu gostaria de separar o nginx e o aplicativo Ruby, quando não há nenhum benefício a ser ganho, apenas para tornar a implantação mais “pura” (o que quer que isso signifique)?
No entanto, é estranho ver um container que está mutando o estado de execução enquanto está longe de estar em execução. Já executo vários aplicativos em containers e containerizei vários eu mesmo, alguns dos quais nunca foram destinados a rodar em containers.
O principal exemplo que me vem à mente, de um aplicativo que lida com requisitos/problemas semelhantes de maneira similar ao Discourse, é o GitLab. Embora eles agora forneçam um elegante Helm chart para uma implantação Kubernetes totalmente decomposta “como deveria ser”, estou supondo (sem olhar números) que uma porcentagem semelhante de 99% de suas implantações de pequeno a médio porte estão usando a imagem Docker omnibus do GitLab (ou o pacote do SO, que é praticamente a mesma coisa). Eles têm um processo de inicialização semelhante, mas baseado no chef dentro do container, que é executado a cada inicialização e faz as coisas usuais, como migrações de banco de dados e compilação de ativos.
Sim, a inicialização do GitLab pode levar vários minutos devido a isso, mas isso nunca foi um problema para as implantações que vi (algumas em empresas maiores). Especialmente com sistemas modernos de orquestração como Docker Swarm e Kubernetes e outros, que podem executar atualizações contínuas para você, onde a instância antiga é desligada apenas se a nova instância estiver em execução e passar com sucesso nos testes de saúde e prontidão, um processo de implantação demorado pode não ser realmente um problema. Mas mesmo sem atualizações contínuas sofisticadas, que podem ou não funcionar, você também pode lidar com bastante tempo de inatividade em muitas situações.
Então: É possível configurar o launcher para ignorar as operações dependentes do banco de dados durante a construção da imagem e, em vez disso, realizar essas operações durante a inicialização do container?
Estou definitivamente disposto a investir um pouco de tempo nisso eu mesmo, mas meu tempo à noite é limitado, então qualquer orientação seria muito bem-vinda.
Também estou aberto a processos completamente diferentes se vocês acharem que isso é estúpido ou nem mesmo possível, etc.
Obrigado por qualquer feedback!