Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Conexão com o banco & Migrations #61

Closed
huogerac opened this issue Jul 8, 2021 · 37 comments · Fixed by #73
Closed

Conexão com o banco & Migrations #61

huogerac opened this issue Jul 8, 2021 · 37 comments · Fixed by #73

Comments

@huogerac
Copy link

huogerac commented Jul 8, 2021

Olá pessoal,

Acredito que a fundação deste tema está dividido em 3 partes:

  • Conexão com o banco de dados
  • Migrações para criar/alterar as tabelas de forma programática
  • Consulta ao banco (que pode ou não utilizar um ORM)

Me parece que no Next.js tem o https://www.prisma.io/ e https://github.com/typeorm/typeorm.
Aparentemente resolvem os 3 pontos acima. Talvez uma desvantagens é ter que instalar typescript (já que o projeto inicialmente não vai usá-lo)

Uma alternativa que acredito interessante e não sei se no NodeJS/Javascript tem, é algo que já utilizei no Python, algo nesta linha aqui: https://nackjicholson.github.io/aiosql/

É bem minimalista, ou seja, temos que resolver a conexão e migrations com outras bibliotecas,
mas é muito mais simples, não tem um ORM (e definições de Models)

Obs: ORM é bem legal, tem diversas vantagens, mas a maior desvantagem pode ser que quando voce precisa fazer uma consulta um pouquinho mais complicada, coisa q no SQL puro é bem simples e direto, no ORM pode ser dificil

Tem isto em varias linguagens, onde temos o SQL puro, mas ainda separado e com uma abstração bem pequena

## No código:
queries.get_all_greetings(conn)

## Na camada do banco:
-- name: get_all_greetings
-- Get all the greetings in the database
select greeting_id, greeting from greetings;

Bom, o que voces já trabalharam para resolver isto no nodejs/next.js?

Abraço

@herculesgabriel
Copy link

Massa, @huogerac! Das opções que você trouxe eu já utilizei o TypeORM, sempre com TypeScript. Porém, é possível utilizá-lo com JavaScript também, tanto puro quanto utilizando Babel para utilizar recursos experimentais da linguagem.

Exemplos na documentação do TypeORM:
https://github.com/typeorm/javascript-example
https://github.com/typeorm/babel-example

O mesmo serve para o Prisma. Aqui na documentação tem o getting started com JS:
https://www.prisma.io/docs/getting-started/setup-prisma/start-from-scratch-node-postgres

Esse último eu nunca cheguei a utilizar. Mas dei uma olhada na documentação e me pareceu interessante. Gostei da forma como é feita a configuração, me parece mais simples de entender.

Além disso, tem também o famoso Sequelize, opção madura também.

Confesso que fiquei um pouco animado para testar o Prisma, mas não tenho experiência para dizer se é uma opção segura, sendo que acredito ser o mais novo dos aqui citados.
https://www.prisma.io/nextjs

Quem conhecer o funcionamento dessas bibliotecas especificamente com o Next.js, caso exista alguma diferença significativa, pode contestar haha

@rhandrade
Copy link
Contributor

A grande desvantagem que eu vejo em não usar um ORM é se precisar migrar o banco de dados. Já tive que fazer isso no passado e foi um trampo gigante, pois era tudo na mão e existiam comandos que não eram compatíveis entre os bancos.

Na minha opinião o ORM ajuda nisso, e caso precisar fazer alguma query mais complexa que o ORM complique ou não de suporte, essas sim seriam feitas em SQL puro.

Acredito que aqui também entraria aquela questão que o @filipedeschamps pontuou, no qual o MySQL está mais preparado para um ambiente serveless do que o Postgres, por exemplo. Se quisermos começar com um e depois mudar para outro poderíamos ter um grande retrabalho.

@cezarmezzalira
Copy link

cezarmezzalira commented Jul 13, 2021

Opa pessoal, tudo certo?
Já tive experiência com o Sequelize e com o TypeORM, que são ótimos ORM.
Como o foco do projeto por hora é de utilizar apenas JS, na minha opinião eu iria com o Sequelize.
Ele é muito massa para questão de migrations e não exige muita configuração e nem a utilização de notations para definição de tipos.
Quanto ao uso do banco de dados, só tenho experiencia em utilizar o postgres rodando em um container docker e a API rodando na mesma máquina no Digital Ocean.
Mas acredito que daria para usar uma solução de banco em AWS, conforme a documentação da própria Vercel : https://vercel.com/docs/solutions/databases

Um exemplo de aplicação que usa o que o projeto já tem especificado está nesse post:
https://javascript.plainenglish.io/next-js-with-sequelize-web-application-a-full-stack-web-development-a0051074e998

@rodrigoKulb
Copy link
Contributor

rodrigoKulb commented Jul 13, 2021

Pessoal ficou definido se vamos de MySQL 🎉️ ou PostgreSQL 🚀️ ?

@cezarmezzalira
Copy link

O @filipedeschamps tinha comentado sobre usar Postgres (PG), pois já era um banco que ele tinha usado na pagar.me com um ótimo desempenho. Ele também pontuou a questão de que gostaria de explorar o máximo do PG.
Na minha opinião, o PG é um banco de dados maduro, tem a possibilidade de gravar dados em colunas JSON muito semelhante ao MongoDB, bem como é open source 😄
Na AWS existe um plano gratuito de até 750h/mês no Amazon RDS, que poderia servir para começarmos.

@filipedeschamps
Copy link
Owner

filipedeschamps commented Jul 13, 2021

Vocês topam sofrer comigo? 😂

Vamos implementar na raça nossas entidades e escrever na unha o SQL? De ORM eu já usei o Sequelize e adoro ele, de fato fazer todo o CRUD sai de graça, e como apontado pelo @rhandrade na hora de mudar de banco de dados, um ORM facilita bastante. E sempre dá para fugir dele escrevendo as queries de forma raw.

Mas novamente eu pergunto, vocês topam sofrer comigo? Vamos para esse projeto fazer as coisas na mão, para realmente aprender um pouco mais sobre modelagem e principalmente SQL? Eu me sinto muito mais future proof ou a prova de balas dando um upgrade nas minhas habilidades sobre isso.

Claro que a gente não precisa tirar todas as abstrações ao ponto de implementar nosso próprio conector 😂 mas sugiro usar algo como o módulo pg. E eu vejo que independente do vai e volta de ORMs ou Query Builders, a base fica ali sólida, nesse caso o conector com o banco de dados, e dá pra ver no número de downloads desse módulo. E é super simples usar ele, olha só um trecho de código (simplificado, tinha mais coisas) que fiz em outro projeto:

// database.js

import { Pool } from "pg";
const pool = new Pool();

async function query(query) {
  const results = await pool.query(query);
  return results;
}

export default {
  query
};

Ele usa o Pool para reaproveitar as conexões. Nesse caso não tem lógica embutida para retry, mas dá para fazer também. E usar dentro do código é bem simple:

// qualquer-dado.js

import database from "database.js";

async function QualquerDado(request, response) {
  const query = {
    text: `
    select *
    from tabela
    where coluna = $1;
    `,
    values: ["turma"],
  };

  const result = await database.query(query);

  return response.json({
    count: result.rows.length,
    dados: result.rows,
  });
}

export default QualquerDado;

Quanto a Migration

Tem um módulo chamado node-pg-migrate que é muito simples de usar, e aceita o Client criado pelo pg, então reaproveita e mesma conexão.

Conclusão?

Como estamos em um ambiente novo, super serveless eu diria 😂 , me sinto muito mais seguro ter um pouco mais controle nessa camada. Não que isso vá nos dar menos problemas, iclusive deveríamos colocar nossa expectativa que inicialmente teremos mais problemas, mas também mais conhecimentos sobre o que está acontecendo, e pra mim isso tem valor infinito. Fora que, novamente, independente das novas abstrações que criarem, a nossa base vai continuar sólida. Topam?

@brunofamiliar
Copy link
Contributor

Sobre esse tema, já utilizei o Sequelize também, minha experiência com essa lib foi das melhores 😄. Acredito que SQL não é um assunto trivial, e utilizando um ORM, perdemos um pouco dessa essência de entender a fundo o comportamento de cada comando e o quanto isso pode refletir possitivamente / negativamente em nossa aplicação. @filipedeschamps , analisei sua sugestão, acredito que podemos ter uma grande evolução nesse quesito. A única coisa que ainda eu me perguntaria é: Será que devemos nos preocupar nesse momento com a possibilidade de mudar o banco de dados? Porque se esse for o caso, vamos ter que ficar cientes que futuramente teremos um "trabalho" maior ao realizar a migração ( coloquei em aspas porque tudo coopera para nosso crescimento ).

@filipedeschamps
Copy link
Owner

A única coisa que ainda eu me perguntaria é: Será que devemos nos preocupar nesse momento com a possibilidade de mudar o banco de dados? Porque se esse for o caso, vamos ter que ficar cientes que futuramente teremos um "trabalho" maior ao realizar a migração ( coloquei em aspas porque tudo coopera para nosso crescimento ).

Excelente pergunta @brunofamiliar pensando aqui, sempre existe essa possibilidade e se ela vier a se tornar realidade, o que prevejo de impacto tirando a parte de infraestrutura é o seguinte:

  1. Conector com o banco: precisaremos trocar e reimplementar, mas essa é a parte mais fácil.
  2. Queries simples: não vejo quase nenhum impacto nisso, e se tiver, vai ser simples consertar.
  3. Queries complexas: imagino que já estaríamos usando diretamente queries raw, fora do ORM.
  4. Migrations: apesar de ser algo simples, talvez nesse caso fosse mais fácil consolidar tudo numa única migration inicial e começar tudo do zero, dado que para a nova versão do código não interessa o que foi migrado no passado.

E como qualquer previsão em tecnologia, o que realmente vai acabar acontecendo é a soma dos problemas previstos vezes 10 😂 mas é o que é 👍

@brunofamiliar
Copy link
Contributor

Show! Eu topo encarar esse desafio 😄

@cezarmezzalira
Copy link

Vou contar uma coisa caras: sou viciado em escrever queries SQL 🤣🤣

CHALLENGE ACCEPTED😎

@rhandrade
Copy link
Contributor

Show @filipedeschamps seguindo essa linha de raciocínio faz sentido seguir com algo mais mão na massa. Topo encarar esse desafio. 😄

@boemekeld
Copy link

Super apoio a escolha de usar SQL! Inclusive, dando preferência para SQL Standard sempre que possível.

Uma coisa que pode ajudar na transição para outro banco de dados é documentar quais queries utilizam funções específicas do banco de dados atual.

Quanto ao futuro, que é serverless, vocêm sabem né? 😆 acredito que os serverless databases irão evoluir para suportar SQL direto no Edge (possivelmente a partir do SQLite, que até já é possível executá-lo em Lambda ou Worker). Então, usando SQL, estaremos sempre bem preparados 😉

@rodrigoKulb
Copy link
Contributor

rodrigoKulb commented Jul 14, 2021

SELECT * FROM membros-da-turma WHERE challenge LIKE "ACCEPTED"

Bora!!!

@filipedeschamps
Copy link
Owner

Sensacionaaaal turma 😍

Então sobre onde hospedar o banco de dados, lendo uma discussion lá no repo da Vercel, o Digital Ocean se demonstrou uma excelente solução para um banco Postgres, pois com um clique você consegue colocar na frente da instância o pg-bouncer e que vai ajudar muito em gerenciar o limite de conexões com o banco (e isso pode acabar sendo o maior inimigo num ambiente serverless).

Porém vocês aceitaram sofrer junto comigo 😂 e o que acham de subir uma instância primeiro sem o pg-bouncer para visualizarmos na prática nossa aplicação estourando por falta de conexão? Para realmente vivermos a elasticidade e limite desse tipo de situação, principalmente para lapidarmos nossa aplicação a se comportar da forma certa em cenários ruins (inclusive, quando tivermos conteúdos reais no site em forma estática, ver o que fica em pé de fato mesmo com o banco de dados fora).

E isso me fez entender que teremos que configurar um ótimo Log Drain e configurar algum tipo de alerta em algum lugar. Acham válido adicionarmos isso na próxima Milestone? Não temos nada sobre logs em nenhum lugar.

@cezarmezzalira
Copy link

cezarmezzalira commented Jul 14, 2021

Pessoal, uma das minhas principais preocupações sobre usar SQL diretamente é o SQL Injection, que é algo que foi levantado nessa thread aqui.
Dando uma olhada na documentação do pg, encontrei uma parte sobre Queries bem bacana, onde explica que em situações de tabelas dinâmicas, é recomendado usar o pg-format.
Para esses casos, o melhor cenário para queries de Inclusão, Alteração e Exclusão seria passando os parâmetros via parâmetro values, como no exemplo abaixo, retirado desse repo do Rodrigo Branas:

const database = require('../infra/database');

exports.getPosts = function () {
	return database.query('select * from blog.post');
};

exports.getPost = function (id) {
	return database.oneOrNone('select * from blog.post where id = $1', [id]);
};

exports.getPostByTitle = function (title) {
	return database.oneOrNone('select * from blog.post where title = $1', [title]);
};

exports.savePost = function (post) {
	return database.one('insert into blog.post (title, content) values ($1, $2) returning *', [post.title, post.content]);
};

exports.updatePost = function (id, post) {
	return database.none('update blog.post set title = $1, content = $2 where id = $3', [post.title, post.content, id]);
};

exports.deletePost = function (id) {
	return database.none('delete from blog.post where id = $1', [id]);
};

Talvez seja por ai que a gente deve começar :)

@boemekeld
Copy link

Sobre onde hospedar, a Amazon possui um banco de dados SQL voltado para serverless, é o Amazon Aurora Serverless. Na prática, é um MySQL otimizado para trabalhar com um número grande de conexões e com recursos auto escaláveis. Existe o V1 e o V2 (que em breve deve sair do Preview).

Uma vantagem que vejo, é o back-end estar mais próximo ao banco de dados (assumindo que a estrutura de back-end da Vercel esteja na AWS).

Outra vantagem é o custo, que deve ser menor quando o projeto ganhar proporções maiores (mas talvez não agora no início, onde um custo mínimo fica por volta de R$ 300 por mês).

Existe ainda um outro serviço, chamado AWS RDS Proxy, que serve justamente para intermediar as conexões entre o back-end serverless e o banco de dados.

@filipedeschamps
Copy link
Owner

Ahhh que massa @boemekeld eu lembro que tinha visto isso no passado, achei fantástico, mas acabei não me aprofundando por ser MySQL (e mais uma vez, MySQL na frente no mundo serverless, interessante né?) e também vi que não era possível expor ele para o mundo (pelo menos na época), a conexão tinha que ser por dentro de uma VPC, daí o backend da Vercel não vai conseguir entrar. Mas talvez daria para expor o Proxy? E usar a AWS facilitaria o billing aqui do meu lado, ficaria tudo num único lugar, porque já uso o Glacier para fazer backup dos vídeos. E sobre custo, me surpreendeu esses R$ 300 por mês mínimos, dado que eles batem bastante na tecla do custo 👍

Bom, de qualquer forma, sugiro continuar no caminho da gente presenciar o comportamento das conexões estourando 😂

@boemekeld
Copy link

@filipedeschamps sim, eles prometem compatibilidade com PostgreSQL, mas na prática o MySQL está na frente!

Sobre a conectividade com mundo externo, sim, você precisa usar uma VPC, porém, sua VPC pode ter conexão externa, para isso ela precisará de um Internet Gateway configurado (a desvantagem é que o VPC também terá um custo, #malditos).

No caso do RDS proxy, acredito que seja possível conectar de fora sem VPC.

De qualquer maneira, também apoio a ideia de testar o limite das conexões 😉

@rodrigoKulb
Copy link
Contributor

rodrigoKulb commented Jul 15, 2021

Tenho um servidor (host) na AWS, é possivel criar um banco de dados a partir de $15, Não utilizo o plano de banco de dados, pois tenho um host lá já com banco. Mas parece ser legal.

Captura de tela em 2021-07-15 14-57-56

@huogerac
Copy link
Author

Hey pessoal,

O que voces acham desta ideia aqui: Usar um droplet de $5 na Digital Ocean e instalar o Postgres. Eu fiz isto algumas vezes, teve projeto que decolou e migramos para a AWS com backup e tudo mais, o serviço RDS da AWS é fantástico. Sem palavras.

MAS, mas para início, e digo mais, da para aguentar muita coisa com este droplet de 5 doletas. E na linha do @filipedeschamps de ver os problemas acontecerem...

Enfim, se gostarem desta ideia, consigo fazer instalação automatizada via ansible (para facilitar replicação) e deixar um postgres rodando na D.O. de forma que fica fácil migrar, seja para outro droplet com mais memória ou outro servidor em outra cloud.

@cezarmezzalira
Copy link

@huogerac eu uso DO e acho muito barato para começar.
Acho muito legal a possibilidade de você ir migrando para droplets mais parrudos de forma transparente.
Por mim, dava pra mandar ver, só compartilhar conosco os dados para podermos acessar :)

@filipedeschamps
Copy link
Owner

@huogerac detona!!! Vai ser muito massa ter essa automação!

@brunofamiliar
Copy link
Contributor

Eu não entendo muito bem sobre parte de infra pessoal, mas está sendo muito massa aprender com vocês 😄. Sobre o DO droplets, até onde eu li, eles ainda não fornece CDN e o backup de banco é algo cobrado a parte. Mas acredito que nesse momento deve ser uma boa opção a ser adota pelo projeto visto que, conforme mencionado pelo @huogerac; a transição para outra base no futuro pode acontecer de forma fluída, e os recursos existentes vão comportar muito bem a aplicação.

@huogerac
Copy link
Author

Resumo:

Temos um postgres 11 rodando e aberto para o mundo (MEDO), instalei para validar em um servidorzinho que tenho na D.O. (chamei de ambiente dev).

image

Notas:

  • scripts ansibles geralmente tem dados sensíveis como o acesso ao banco, secrets de api, variaveis de ambiente. Logo é uma boa prática usar o ansible-vault para fazer o encrypt.
  • Voces vão precisar da chave para ver os dados de acesso, podem me enviar email: huogerac [arroba] gmail [ponto] com, ou definir um lugar onde posso colocar (ver Issue Onde armazenar dados sensíveis do projeto? #68 )
  • Este ambiente que criei é para testes (devops/ansible/hosts/development), a ideia é replicar oq fiz no servidor oficial que o @filipedeschamps deverá criar (vamos chamar de devops/ansible/hosts/production)
  • Geralmente eu deixo o servidor onde instalo o postgres fechado (porta 5432 não acessível via internet), apenas aberto para a rede interna. Mas para permitir que voces acessem, tive que abrir esta porta no firewall e no pg_hba.conf, ou seja, no mínimo vamos ter que estudar um pouco como proteger melhor um postgres aberto na internet...

Qual a ideia:

  • Podemos utilizar o ip 178.62.218.219 para testar, mas devemos ter um servidor de produção com o banco do tabnews.com.br
  • Criar um droplet na digital ocean com ubuntu 20 e seguir os passos abaixo para instalar o postgres usando ansible (para facilitar replicação)

Passo a Passo para instalação

  • Criar droplet usando ubuntu 20
  • Seguir os passos 1,2,3 e 4 deste post aqui onde instala o básico do básico no ubuntu para rodar oq precisamos
  • instalar o ansible localmente, como é python, quem usa linux ou mac, basicamente é fazer um pip install ansible. Eu recomendo fazer isto dentro de um virtualenv
  • Dai é basicamente 2 comandos (dentro da pasta devops/ansible)
  • Criar o arquivo devops/ansible/.vault_pass com a chave q preciso compartilhar
  • Rodar: ansible-playbook -i hosts/development --tags postgres playbook.yml --vault-password-file .vault_pass
  • No servidor podemos utilizar sudo service postgresql status para ver q o postgres está rodando
  • No servidor podemos utilizar netstat -nlt para ver as portas abertas e podemos ver :::5432 = aberta para o mundo (mas o firewall ainda não vai deixar)
  • por último, temos que liberar o firewall com sudo ufw allow 5432
  • done!

Como ver o arquivo de configuração?

  • Entrando na pasta devops/ansible
  • Digitando o comando ansible-vault decrypt --vault-password-file .vault_pass group_vars/development.yml
  • dai conseguimos ver user/pwd e nome do banco

Próximos passos

  • Criar droplet de produção na D.O
  • Criar o arquivo hosts/production com o IP do droplet (seguindo o development)
  • Criar o arquivo group_vars/production.yml (seguindo o development.yml):
---
environment: production

database_name: tabnews
database_user: tabnews
database_password: xXXXXXx

Pessoal, acho que é isto, espero que não tenha ficado complicado demais. Tem meu email ai no post, se tiver algo que não esteja muito claro.

Todos arquivos do ansible estão na branch:
https://github.com/filipedeschamps/tabnews.com.br/tree/Task61_instala_postgres (pasta devops)

Não abri PR ainda, para esperar avaliação de voces.

@filipedeschamps
Copy link
Owner

Show de bola @huogerac! Muito obrigado por colocar a mão na massa dessa forma!!!! Então ultra-resumão foi subir um droplet de Ubuntu, configurar ele, e daí instalar e configurar o Postgres. Como efeito colateral, é preciso gerenciar as chaves, segredos e manter o OS atualizado (e o banco).

Você já testou o Postgres gerenciado da DigitalOcean? Eu nunca testei, só usei o Postgres no RDS na AWS e era muito bom. Vou fazer um teste aqui para sentir se ele abstrair parte desse trabalho, e ver se talvez ele consegue nos entregar na mão a url de conexão e credenciais, porque daí é só questão de cadastrar isso nas variáveis de ambiente da Vercel e a aplicação em prod ou staging podem usar diretamente. Acredito que vai ser mais caro que um droplet, mas o tradeoff é que não iremos precisar nos preocupar com os patches de segurança da máquina.

Vou fazer uma conta aqui e assim que fizer retorno aqui com os resultados.

PS: Desculpa a demora para interagir com as issues, essa semana o Oliver pegou pesado aqui em casa 😂

@filipedeschamps
Copy link
Owner

Turma, esse foi o resultado

Depois de configurar o billing da nova conta que criei (acabei ganhando $100 dólares de crédito), escolhi a opção de criar um banco de dados gerenciado e essa tela abaixo é basicamente o que se precisa escolher pra criar o banco, e como vocês podem ver, a instância mínima é mais cara e custa $15 dólares.

image

Config

Depois ele ajuda você a fazer algumas configurações, onde o segundo passo é ele pedindo para você fechar o banco de dados para internet, e deixar disponível só pra rede interna.

image

Credenciais

Pulei essa etapa, pois precisamos expor ele pros servidores da Vercel, e ele já retorna url de acesso e credenciais (eu alterei antes do print):

image

Pool e Patches de Segurança

O legal é que ele já fornece uma opção para você configurar o pg-pool e também já habilitou patches de segurança (minors) por padrão:

image

Backups

Não encontrei onde ficam os backups, só encontrei isso (e to confuso):

image

Tela do Pool

O que achei legal é que ele mostra que nossa atual instância só suporta 22 conexões simultâneas, mas já oferece uma forma fácil de configurar o pool. Eu não vou fazer agora, para realmente enfrentarmos esse problema e deixar nossa aplicação mais robusta, mas achei bem legal a interface.

image

Conclusão

Achei bem interessante, foi um pouquinho mais caro que pensei que seria para a instância mínima, mas bastante conveniente, principalmente para não se preocupar com patches de segurança do OS (que é transparente) e minors do Postgres e imagino que fazer upgrade major do Postgres ou aumentar a instância imagino ser fácil também. Por outro lado, o que fiz não é Devops, porque foi tudo no braço 😂

Talvez o que podemos fazer é começar assim, e depois quando o projeto estiver parando em pé economicamente falando, fazer todo esse setup de novo na AWS e usando um Terraform da vida (porque eu acho que eventualmente a gente vai usar outros serviços de lá como S3).

E essa migração também vai gerar bastante conhecimento.

Qual a impressão de vocês?

@huogerac
Copy link
Author

Massa que $15 doletas da para ser uma opção já para este projeto! Tem varias vantagens sim!

  • Eu diria, que vi alguns projetos iniciando sem problema na abordagem da branch com ansible, mesmo sem ficar se preocupando com os updates (ou fazendo a cada 3 meses apenas). Em outras palavras, postgres é do cralhor! hehhe, mesmo usando a versão 11 ou 12
  • Outra coisa que vi indo para está direção, é que com instalação própria, conseguimos instalar 2 bases (dev e prod) na mesma instancia ($5), ou seja, da medo rodar as migrations das novas features diretamente em produção, sempre tenho no mínimo outro ambiente com a cópia de produção.
  • Acho que eu poderia ter simplificado um pouco mais, pelo menos removendo o ansible-vault e aquele setup inicial da instancia que fiz referencia para outro post (vou tentar melhorar isto em breve)

Enfim, se $15 conto não é problema! Massa! este serviço da D.O. é bom sim! e o backup/restore é tranquilo, tenho ansible pra isto, a gente faz em outra issue na hora q precisar

@filipedeschamps
Copy link
Owner

Show @huogerac bom ponto sobre os dois ambientes e de fato eles gerenciados ficarão bem mais caros que em 1 droplet. Mas dois cuidados que eu tomaria em unir esses dois ambientes é em disponibilidade (por exemplo o banco dev consumir todo recurso da máquina por um erro, afetando o banco de prod), e segurança, pois fica fácil escalar acesso de dev para prod 👍

Bom, eu to colocando a mão na massa aqui para fazer essas coisas rodarem em ambiente local com docker-compose, que vai servir para os testes também, e um pouco mais pra frente fazer duas instâncias do banco, uma para Preview e outra para Production 🤝 estamos avançando 🎉

@rodrigoKulb
Copy link
Contributor

Bem legal o banco de dados gerenciado, você consegue abstrair todos os possíveis problemas de OS, com uma diferença bem baixa no valor.

Acabou que ficou o mesmo preço do Banco gerenciado na AWS ambos são $ 15,00.

Digital Ocean
PostgreSQL 13
1GB Memoria
1vCPU
10 GB Disk
Transferência (Não achei no print)
Preço $ 15,00 (crédito de $100,00)

AWS
PostgreSQL 12.7
1GB Memoria
1vCPU
40 GB Disk
100 GB transferência
Preço $ 15,00 (primeiro mês grátis)

Sobre o bkp achei esse link informando que não existe um custo adicional para o mesmo, e o bkp é diário.
https://www.digitalocean.com/community/questions/what-is-the-recommended-way-to-backup-my-managed-postgresql-database

@huogerac
Copy link
Author

Pessoal,

Apenas para referencia e para complementar a branch que instala um Postgres na D.O usando Ansible.
Se algum dia alguem precisar!
https://huogerac.hashnode.dev/install-postgres-13-on-ubuntu-20-using-ansible-ckrcv6i520704a2s1ga5bedko

@huogerac
Copy link
Author

Hey @filipedeschamps
No vídeo#90 desta semana você disse que está usando Terraform. Legal fazer infra as code. Se ajudar, segue um script que usei para subir Postgres na AWS...Espero que ajude

https://github.com/huogerac/devops-tools/tree/main/devops/terraform/aws/rds

@filipedeschamps
Copy link
Owner

@huogerac show!! Como preciso deixar o banco público para a Vercel conseguir se conectar, tive que dar um balão maior, olha só:

terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 3.0"
    }
  }
}

provider "aws" {
  region  = "us-east-1"
  profile = "tabnews"
}

# Criar uma nova VPC que resolva DNS
# e consiga fazer acesso a internet.
# Esse recurso vai ser usado por:
# 1. Internet Gateway
resource "aws_vpc" "staging" {
  cidr_block           = "10.0.0.0/16"
  enable_dns_support   = true
  enable_dns_hostnames = true

  tags = {
    Name = "staging"
  }
}

# Criar um internet gateway que se
# conecta com a VPC ali de cima.
resource "aws_internet_gateway" "staging" {
  vpc_id = aws_vpc.staging.id

  tags = {
    Name = "staging"
  }
}

# Pega todas as Availability Zones que estão
# disponíveis na "region" declarado no provider "aws"
data "aws_availability_zones" "available" {
  state = "available"
}

# Faz um loop para criar um subnet por cada
# availability zone. O RDS tem um requisito
# de ter no mínimo 2 subnets. Que nesse caso,
# vai ser criado 2 subnets públicas.
resource "aws_subnet" "database_staging_public" {
  count                   = 2
  vpc_id                  = aws_vpc.staging.id
  cidr_block              = cidrsubnet(aws_vpc.staging.cidr_block, 8, count.index)
  availability_zone       = data.aws_availability_zones.available.names[count.index]
  map_public_ip_on_launch = true

  tags = {
    Name = "database_staging_public"
  }
}

# O RDS também tem um requisito de ter um
# subnet group, que nesse caso vai pegar dinamicamente
# todos os subnets criados acima.
resource "aws_db_subnet_group" "staging_public" {
  name       = "database_staging_public"
  subnet_ids = aws_subnet.database_staging_public.*.id

  tags = {
    Name = "database_staging_public"
  }
}

# Como vamos expor o banco de dados de forma pública
# eu precisei criar um Route Table que mapeia o caminho
# entre a VPC e o Internet Gateway e que vai ser
# usado por todas as subnets logo ali em baixo.
resource "aws_route_table" "staging_public" {
  vpc_id = aws_vpc.staging.id

  route {
    cidr_block = "0.0.0.0/0"
    gateway_id = aws_internet_gateway.staging.id
  }

  tags = {
    Name = "staging_public"
  }
}

# Nesse ponto a gente faz a associação entre o Route Table
# criado acima e todas as subnets públicas disponíveis.
# Assim elas conseguem acessar a internet.
resource "aws_route_table_association" "staging_public" {
  count          = length(aws_subnet.database_staging_public)
  subnet_id      = aws_subnet.database_staging_public[count.index].id
  route_table_id = aws_route_table.staging_public.id
}

# Pelo que lembro, esse não foi um ponto necessário para dar
# acesso público ao RDS, mas quando ele era criado sem definir
# um Security Group, ele usava um padrão disponível na conta
# e que liberava tudo. Preferi criar um específico para o
# tipo de acesso e porta do banco.
resource "aws_security_group" "postgres_staging" {
  name   = "postgres-staging"
  vpc_id = aws_vpc.staging.id

  ingress {
    from_port        = 3297
    to_port          = 3297
    protocol         = "tcp"
    cidr_blocks      = ["0.0.0.0/0"]
    ipv6_cidr_blocks = ["::/0"]
  }

  egress {
    from_port        = 0
    to_port          = 0
    protocol         = "-1"
    cidr_blocks      = ["0.0.0.0/0"]
    ipv6_cidr_blocks = ["::/0"]
  }
}

# Isso gera uma nova senha randômica, e que vai
# ser usada no banco de dados.
# ATENÇÃO: por enquanto não estou utilizando,
# mas é só para facilitar nos testes.
resource "random_password" "password" {
  length           = 32
  special          = true
  override_special = "!#$%&*()-_=+[]{}<>:?"
}

# Criar um RDS de PostgreSQL.
# Tem vários parâmetros comentados e hardcoded, porque
# estou estudando e testando tudo ainda. E a ideia é exportar
# vários desses valores para algo como um Secret Manager da AWS.
# Eu quero fazer o commit desse arquivo aqui no repositório
# do TabNews e não quero expor nada, nem a porta que foi utilizada.
resource "aws_db_instance" "postgres_staging" {
  identifier        = "postgres-staging"
  storage_type      = "gp2"
  allocated_storage = 20
  engine            = "postgres"
  engine_version    = "13.3"
  # engine_version    = "14.1"
  instance_class = "db.t4g.micro"
  name           = "test1234"
  username       = "test1234"
  password       = "test1234"
  # password                    = random_password.password.result
  port                        = 3297
  publicly_accessible         = true
  multi_az                    = false
  max_allocated_storage       = 20
  allow_major_version_upgrade = false
  auto_minor_version_upgrade  = true

  db_subnet_group_name   = aws_db_subnet_group.staging_public.name
  vpc_security_group_ids = [aws_security_group.postgres_staging.id]

  apply_immediately       = true
  backup_retention_period = 0

  skip_final_snapshot = true

  # final_snapshot_identifier = "test" # Não vou usar, pois faço skip_final_snapshot = true
  # timezone = "" # Preciso disso?
  # backup_window = "03:00-04:00" # Em qual timezone isso funciona?
  # delete_automated_backups = true # Pesquisar mais sobre isso.
  # maintenance_window = "wed:03:00-wed:04:00" # Em qual timezone isso funciona?
  # availability_zone # Preciso definir isso?
  # license_model = "license-included" # O que é isso?
  # monitoring_interval = "5" # O que isso faz?
  # performance_insights_enabled = true # O que isso faz?
  # replicas = 1 # Vamos precisar? Muito caro?

  tags = {
    Name = "postgres_staging"
  }
}


output "postgres_staging_username" {
  value = aws_db_instance.postgres_staging.username
}

output "postgres_staging_password" {
  value     = aws_db_instance.postgres_staging.password
  sensitive = true
}

output "postgres_staging_endpoint" {
  value = aws_db_instance.postgres_staging.endpoint
}

@huogerac
Copy link
Author

Que massa, vou olhar com calma mais tarde! massa que tem tudo comentado!

@boemekeld
Copy link

Oi @filipedeschamps, chegou a dar uma olhada no PlanetScale? é uma opção interessante, tenho escolhido ele ao invés do RDS. Fica tudo muito mais simples, sem a necessidade de configurar RDS e VPC. E tem uma funcionalidade de branch e pull request em alterações do banco de dados, delicinha! 😆
Quanto ao migrations / ORM, apoio o Prisma.io.
Abs.

@filipedeschamps
Copy link
Owner

@huogerac show! Fiz alguns ajustes legais (principalmente pra ficar tudo 100% na hora do destroy) e agora estou modularizando para conseguirmos ter a infra de staging e production "iguais", e por iguais eu digo que a topologia vai ser a mesma, mas é importante ter a flexibilidade de na de staging poder escolher um banco mais fraco, sem backup e em us-east-1 e em production ter um banco mais forte, etc. e em São Paulo se quisermos. E resolvi a parte das credenciais de um jeito interessante que ao criar o recurso, tudo é gerado de forma randômica (incluindo a porta), usando o máximo do length em usuário e senha. Ta bem massa 👍

@boemekeld show! Cheguei a avaliar o PlanetScale e é uma solução sensacional. A escolha de usar o Postgres foi literalmente para se ferrar. E eu não digo isso brincando não, era realmente pra conseguir se virar e aprender mais a respeito. Incluindo não usar ORM e fazer as queries na unha. Não está sendo nada produtivo no quesito velocidade de desenvolvimento, mas está sendo muito proveitoso no quesito conhecimento 🤝

@huogerac
Copy link
Author

Hey pessoal!
Sei que já está fechado este asssunto do DB, e que a solução com Terraform ficou linda!

Mas olha o que apareceu na minha timeline! achei legal compartilhar! me pareceu um negócio legal de fazer uma POC.

Abraço

https://github.com/nhost/nhost

@filipedeschamps
Copy link
Owner

Que massa essa solução @huogerac 😍 topa fazer um post lá no TabNews para turma conhecer?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

8 participants