Fazendo deploy em produção com Rails, PostgreSQL e Dokku
Publish Date: Mar 24 '22
14 0
Introdução
Disponibilizar uma aplicação na internet para outras pessoas acessarem é uma tarefa razoavelmente simples caso utilizemos o Heroku como PaaS (Plataforma como Serviço), mas se torna uma tarefa um pouco mais complicada quando, querendo baixar custos, passamos a utilizar uma instância na DigitalOcean, Linode, Vultr e etc, e é necessário configurar tudo manualmente, principalmente pra mim, que assunto de infraestrutura eu sou quase um leigo. Mas ainda há esperança para desenvolvedores como eu, que da nomeclatura DevOps, tem só o Dev, e nada de Ops. Eu falo do Dokku, que une a facilitade do Heroku com os baixos custos de uma instância própria. Ele é uma ferramenta de código aberto e gratuita, que resumidamente é um "self-hosted Heroku", um PaaS que tu hospeda no teu próprio servidor, te proporcionando uma maior capacidade de customização e uma redução dos custos.
A seguir vou mostrar como instalar o Dokku numa instância da DigitalOcean (mas tu consegue reproduzir usando o serviço de tua preferência), e implantar uma aplicação real desenvolvida com Ruby on Rails e PostgreSQL. Caso tu não tenha uma aplicação pra seguir o tutorial, pode usar essa aplicação MVP que desenvolvi e que é uma mini-rede social para publicação de customizações do jogo Animal Crossing: New Horizons, jogo do Nintendo Switch lançado em março de 2020. O código está disponível nesse repositório. Use o branch tutorial pois ele já está com alguns ajustes pra facilitar a configuração:
Antes de tudo é necessário criar uma conta na DigitalOcean, e criar uma instância, termo usado pela DO para se referir às instâncias é droplets, então crie um droplet. Não vai ter imagens desse processo nesse artigo pois a qualquer momento a DigitalOcean pode mudar toda a página e o artigo ficar desatualizado, mas não tem segredo, é só um formulário simples onde tu escolhe as configurações e finaliza o criação da instância. Uma máquina de 2GB de RAM é mais do que suficiente, mas já consegui configurar até usando a de 1GB de RAM.
Após a instância criada, é necessário se conectar nela utilizando o usuário root:
ssh root@IP_DO_TEU_SERVIDOR
Esse IP_DO_TEU_SERVIDOR se refere ao IP que a DigitalOcean forneceu após a criação do droplet. Caso já tenha configurado um domínio para essa instância, tu pode usar o domínio ao invés do IP.
Agora instale o Dokku com o seguinte comando
# Para sistemas debian, instale o dokku via apt-get
wget https://raw.githubusercontent.com/dokku/dokku/v0.27.0/bootstrap.sh
sudo DOKKU_TAG=v0.27.0 bash bootstrap.sh
A versão 0.27.0 é a mais recente disponível enquanto eu escrevo esse artigo, então confira a documentação oficial no site para verificar se novas versões foram publicadas.
Quando a instalação terminar, visite IP da tua máquina pelo navegador, preencha a chave pública do teu SSH no campo "Public SSH", pois isso te permitirá executar os comandos remotamente que vamos precisar mais pra frente. A sessão de configuração de hostname pode ser ignorada, vamos configurar isso já já. Finalize a instalação e tu estará pronto para começar a configuração da aplicação.
Configurando a aplicação
Com o Dokku já instalado, é hora de criar a aplicação. Ainda conectado como root na tua instância, execute:
dokku apps:create meu_app
O meu_app é o identificador da tua aplicação, substitua pelo nome do teu projeto, é ele que tu irá se referenciar no restante da configuração.
Uma coisa legal do Dokku é que ele é compátivel com os buildpacks que são utilizados no Heroku, que são conjuntos de scripts que configuram automaticamente várias dependências da aplicação, sem precisar fazer esse processo de forma manual. Então adicione o buildpack do Ruby para seguirmos a configuração:
Também configure a variável RAILS_ENV para ser production:
dokku config:set meu_app RAILS_ENV=production
Com esse comando dokku config:set, tu pode definir outras variáveis de ambiente também, caso sejam necessárias.
Como o Heroku, o Dokku também permite que um projeto tenha um arquivo Procfile. Esse arquivo serve para definir os processos que serão executados na inicialização da aplicação. Dois deles são especiais, o web e o release. O web é o único processo que pode receber as requisições externas roteadas pelo Dokku, e o release é o comando executado antes de finalizar a implantação da aplicação.
Tu pode ter outros processos e nomeá-los como quiser, por exemplo: depois de configurar um sidekiq na tua aplicação e no Dokku, será necessário colocar um meus_workers: bundle exec sidekiq -C config/sidekiq.yml no Procfile.
Para o escopo do artigo, precisa apenas do web para subir o servidor com o Puma e do release para executar as migrações e criar os seeds, então crie um arquivo Procfile na raíz do teu projeto com o seguinte conteúdo:
A partir do Rails 6, por questão de segurança, é necessário informar os domínios permitidos no header das requisições, então no config/environments/production.rb informe o IP do teu servidor, teu domínio ou desabilite essa verificação. As opções são essas:
config.hosts<<"IP_DO_TEU_SERVIDOR"# ouconfig.hosts<<"meudominio.com"# ou caso queira desabilitar a verificaçãoconfig.hosts.clear
Envie as duas mudanças (do Procfile e do production.rb) para o teu repositório e vamos seguir para instalar o PostgreSQL.
Instalando o PostgreSQL
Para instalar o PostgreSQL da maneira mais fácil, pode usar os plugins do Dokku:
Após isso, crie o banco de dados que será usado na aplicação:
dokku postgres:create meu_app_db
Observação: A versão do postgres instalada pode não ser a que você deseja, então você pode passar uma flag com uma versão específica: dokku postgres:create meu_app_db -I 14.1.
Faça a conexão entre o banco de dados recém-criado e a aplicação com o seguinte comando:
dokku postgres:link meu_app_db meu_app
Esse comando configura uma variável de ambiente chamada DATABASE_URL e ela será usada pela aplicação Rails para se conectar com o banco de dados. Uma informação extra: caso por algum motivo tu necessite que o banco seja acessado externamente, esse comando irá expor uma porta aleatória:
dokku postgres:expose meu_app_db
Configurando o domínio
Esse passo é opcional, caso tu tenha um domínio configurado apontando pro teu servidor e queira que ele se integre com a aplicação, tu precisa adicioná-lo ao meu_app:
dokku domains:add meu_app meudominio.com
# Caso queira o subdomínio www configurado:
dokku domains:add meu_app www.meudominio.com
Lembre-se da configuração que expliquei antes, sobre o config.hosts, que é necessário adicionar o meudominio.com no config.hosts para conseguir navegar na aplicação utilizando o teu domínio.
Fazendo o deploy
Agora falta pouco para finalizar a implantação da aplicação. Na tua máquina local, na pasta do teu projeto, adicione o repositório remoto apontando para o Dokku do teu servidor com seguinte comando:
Para finalmente fazer o deploy agora ou toda vez que tu quiser mandar atualizações da aplicação, ainda na pasta do teu projeto execute:
git push dokku main # ou qualquer outro branch que desejar colocar no ar
Esse comando vai demorar um pouco, pois ele irá fazer todo o processo de instalar o Ruby de acordo com o buildpack adicionado lá no início do artigo, vai instalar as gems, instalar as dependências de front-end caso existam, precompilar os assets, rodar os comandos pré e pós deploy e por fim reiniciar o nginx.
Agora tu pode acessar o http://IP_DO_TEU_SERVIDOR ou http://meudominio.com pelo navegador e se nada inesperado ocorrer, tua aplicação estará no ar, pronta para uso. Mas o ideal é que tua aplicação tenha SSL para dar mais segurança aos teus usuários, principalmente se tiver funcionalidade de autenticação ou se tratar dados mais sensíveis. Na próxima seção explico como configurar o SSL.
Adicionando o SSL
Caso tu já tenha configurado um domínio pra tua aplicação (caso contrário leia como fazer em Configurando o domínio) e queira configurar o SSL, primeiro instale o plugin do Let's Encrypt:
Pra finalizar a configuração de fato o SSL, é só executar o comando letsencrypt e que ele fará todo o trabalho por baixo dos panos de gerar os certificados para cada um dos domínios adicionados:
dokku letsencrypt:enable meu_app
E para ativar a renovação automática de 3 em 3 meses é com o seguinte comando:
dokku letsencrypt:cron-job --add meu_app
Pronto, se tudo tiver dado certo, se tu acessar https://meudominio.com, o navegador deverá mostrar na barra de navegação um cadeado sem nenhum erro ou alerta.
Conclusão
É isso, pode parecer complicado, mas é bem mais fácil que configurar uma máquina "crua" na mão. Com esse conceito de apps, fica fácil adicionar mais aplicações em um mesmo servidor, configurando um subdomínio para cada uma, até mesmo com tecnologias diferentes, pois o Dokku não é apenas para Ruby. É possível usar um Dockerfile ou uma imagem Docker no lugar dos buildpacks para ter uma configuração de ambiente mais customizada. Ele é uma ótima opção para MVPs ou aplicações com um baixo número de usuários, ou até para usar como ambiente de homologação (sandbox, QA).
Caso tenha ficado interessado no Dokku, saiba que há outras alternativas de PaaS self-hosted para tu analisar os pontos fortes e fracos de cada um e escolher o que melhor se adequa para tuas necessidades. Numa pesquisa rápida consigo listar o Flynn, o CapRover, o Convox e o brasileiro Tsuru, mas com uma pesquisa mais aprofundada tu pode encontrar mais opções.
Se tu já tiver usado o Dokku ou qualquer outra opção parecida, deixa nos comentários como foi a experiência, os pontos positivos e negativos, e alguma dica de configuração, caso tenha. Até o próximo artigo.
TL;DR
# Entre na instânciasshroot@IP_DO_TEU_SERVIDOR# Instale o Dokku. Confira a última versão no site oficial.wgethttps://raw.githubusercontent.com/dokku/dokku/v0.27.0/bootstrap.shDOKKU_TAG=v0.23.4bashbootstrap.sh# Visite o IP_DO_TEU_SERVIDOR pelo navegador, adicione # tua chave SSH, ignore as confgurações de hostname # e finalize a instalação.# Ainda conectado via SSH no servidor, crie um app no Dokkudokkuapps:createmeu_app# Adicione o buildpack do Rubydokkubuildpacks:addmeu_app\https://github.com/heroku/heroku-buildpack-ruby.git# Configure a variável RAILS_ENV para productiondokkuconfig:setmeu_appRAILS_ENV=production# Caso use as credentials, informe a master.keydookuconfig:setmeu_appRAILS_MASTER_KEY=tua_senha# Instale o PostgreSQLdokkuplugin:install\https://github.com/dokku/dokku-postgres.git# Crie um banco de dadosdokkupostgres:createmeu_app_db# Conecte o banco de dados com tua aplicaçãodokkupostgres:linkmeu_app_dbmeu_app# Caso tenha um domínio configurado no servidor:dokkudomains:addmeu_appmeudominio.com# Caso queira o subdomínio www configurado:dokkudomains:addmeu_appwww.meudominio.com# No código do teu projeto, lembre-se de informar# o host que tua aplicação irá rodar.# No arquivo /config/environments/production.rbconfig.hosts<<"IP_DO_TEU_SERVIDOR"# Ouconfig.hosts<<"meudominio.com"# Ou caso queira desabilitar a verificaçãoconfig.hosts.clear# Na tua máquina local, aponte para o repositório# remoto do Dokku do teu servidor:gitremoteadddokkudokku@IP_DO_TEU_SERVIDOR:meu_app# Faça o deploygitpushdokkumain# Acesse http://IP_DO_TEU_SERVIDOR ou# http://meudominio.com e a aplicação estará no ar.# Caso queira adicionar SSL na aplicação, instale # o letsencryptdokkuplugin:install\https://github.com/dokku/dokku-letsencrypt.git# Configure o e-mail para receber alertas do# Let's Encrypt:dokkuconfig:set--no-restartmeu_app\DOKKU_LETSENCRYPT_EMAIL=teu_email# Crie os certificados para os domínios da aplicaçãodokkuletsencryptmeu_app# Configure a renovação automáticadokkuletsencrypt:cron-job--addmeu_app# Acesse https://IP_DO_TEU_SERVIDOR ou# https://meudominio.com e a aplicação estará no ar# com SSL