Criando servidor de backup no Google Cloud Platform
Tags: googlecloud, devops, linux, portugues
Published: 2020-08-16 23:41:21

Olá, me chamo André Pereira, e esse é o meu primeiro post aqui no dev.to. Geralmente atuo como fullstack nos projetos que desenvolvo e por conta da responsabilidade que isso me traz, acabo não tendo oportunidade de trabalhar com infraestrutura. 

Porém, recentemente eu resolvi fazer uma tarefa referente a infraestrutura de um projeto. A ideia era programar o Crontab da instância de produção para copiar os dados para uma instância de backup, ambas hospedadas no GCP. Aparentemente é uma tarefa simples, mas pode se tornar complicada para inexperientes em infraestrutura ou GCP. 

Sem mais delongas, vamos ao telão: 

## Sumário

##### (Caso você já tenha uma instância de produção pronta comece a partir do item 3)

<a name="item-1"></a>

[1. Criando a instância de produção](#item-1)
[2. Criando o banco de dados na instância de produção](#item-2)
[3. Criando a instância de backup](#item-3)
[4. Conectando as duas instâncias via SSH](#item-4)
[5. Criando os shell scripts de backup](#item-5)
[6. Entendendo e configurando o Crontab](#item-6)
[7. Adicionando o shell script de expurgo](#item-7)

## 1. Criando a instância de produção 

Como eu havia introduzido utilizaremos o Google Cloud Platform para hospedar nossos servidores. Lembre-se, **eu não irei ensinar a fazer deploy da sua aplicação, essa instância será apenas para simular um backup**. Caso você ainda não tenha uma conta, acesse [Google Cloud Platform](https://cloud.google.com/), clique "Comece a usar gratuitamente" e conclua o cadastro. Perceba que o cadastro irá requerer um cartão de crédito para confirmação, mas não se preocupe, nada será cobrado.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/pabehmlp0i5ryig4v2nf.png)

Após o cadastro você será levado para uma página de primeiros passos com algumas apresentações. Você pode configurar um projeto no menu superior se preferir. Por padrão o GCP te coloca no "My First Project", e por questões de agilidade utilizaremos esse projeto mesmo. 

<a name="vms"></a>

Para ir até o gerenciamento de instâncias clique no menu de navegação no canto superior esquerdo, procure a opção "Google Compute Engine", e selecione "Instâncias de VM"

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/wff2qfaaj5jgjqqm1zvy.png)

Agora iremos criar nossa instância de produção. Clique em "Criar" e nos deparamos com um formulário.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/les1r7l4nickk0puyxfx.png)

Escolha um nome para a instância, defina a região (Para um melhor tempo de resposta escolha southamerica-east1) e a zona de acordo com suas necessidades. Na parte de configuração da máquina podemos deixar a série "N1", e o tipo de máquina "n1-standard-1", mas caso você esteja configurando uma instância para a sua aplicação, você deve avaliar qual máquina satisfaz melhor as necessidades da hospedagem.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/dlwaquxwgwnvwm5ifgvx.png)

Um pouco mais abaixo encontraremos a seção de "Disco de inicialização" onde escolheremos o tamanho do disco da nossa instância, e qual OS será instalado na mesma. Por padrão o Google nos traz um disco de 10GB com Debian 9. Para este tutorial utilizaremos Ubuntu 18.04, então vamos mudar isso clicando no botão "Alterar". 

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/0v5ow4y2gntvkay93mwt.png)

<a name="disk"></a>

Na tela de configuração do disco de inicialização, selecionamos menu de "Imagens públicas", o sistema operacional "Ubuntu", e a versão "Ubuntu 18.04 LTS". Logo abaixo no Tipo de disco de inicialização, selecionamos "Disco permanente padrão", e o tamanho fica a critério do usuário. Neste tutorial usarei 20GB.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/2lu40nl2ddy0q00fq0hp.png)

Podemos confirmar a configuração do disco, e de volta no formulário de criação da instância clicaremos em "Criar". Estas são as configurações mínimas necessárias para simular o nosso banco de produção. 

Note que ao longo do formulário de criação um valor no canto superior direito simulava o gasto mensal que seria necessário para manter essa instância funcionando. Mas como você deve ter lido ao se cadastrar, o Google disponibiliza U$300 para novos usuários, o que convertido em reais na cotação atual nos dá cerca de R$1350, que é mais do que o necessário para estudos como esses. 

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/e4yh22vtpm8h3vkmijvx.png)

Agora ao acessar a aba de "Instâncias de VM", conseguimos ver nossa instância na listagem funcionando.

<a name="item-2"></a>

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/3el6cj6ltwxwyv8ww7v7.png)

## 2. Criando o banco de dados na instância de produção 

Agora que temos nossa instância pronta para uso. Vamos acessá-la usando a própria conexão SSH do GCP, e para isso basta clicar no botão SSH no final da tabela de instâncias.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/e0xu77qfjhplzqck6sgi.png)

Uma janela será aberta e após a conexão temos acesso direto à instância com o nosso usuário do GCP. Aqui instalaremos os pacotes necessários para criar o nosso banco de dados. Neste tutorial utilizaremos PostgreSQL em um container Docker para agilizar o processo.

Instalando o Docker via Snap:

```
$ sudo snap install docker
```

Criando container Docker com PostgreSQL:
```
$ sudo docker run --name prod_database -e POSTGRES_PASSWORD=docker -p 5432:5432 -d postgres
```

Após isso, basta rodar `sudo docker ps` para verificar se o container já está ativo. Caso o comando retorne uma tabela vazia significa que o container está inativo, portanto rode `sudo docker start prod_database`, e repita o processo de verificação para prosseguir.

Agora iremos acessar o container e popular o banco com alguns dados para o backup.

Acessando o container:

```
$ sudo docker exec -it prod_database bash
```

A aparência do terminal irá mudar pois estamos logados no container como usuário root (#).

Acessando o PostgreSQL:

```
# psql -U postgres
```

Iremos utilizar o banco "postgres" que vem por padrão no PostgreSQL, para uma melhor visualização disso, basta digitar `\l` e serão retornados os bancos existentes. Até o momento seu terminal estará parecido com isso: 

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/2tdy7p7fyggcgejljb95.png)

Conectando ao banco:

```
\c postgres
```

Criando tabela `users`: 

```SQL
CREATE TABLE users (
	id serial PRIMARY KEY,
	name VARCHAR (255) NOT NULL,
	email VARCHAR (255) UNIQUE NOT NULL
); 
```

Criando tabela `users` com alguns dados:

```SQL
INSERT INTO users(name, email) 
VALUES 
('Andre Pereira', 'contato.andrepsf@gmail.com'), 
('Maria Silva', 'mariasilva@email.com'),
('João Paulo', 'joaopaulo@email.com');
```

Verificando se os dados foram cadastrados corretamente:

```SQL
SELECT * FROM users;
```

O retorno deverá ser o seguinte: 

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/n1rf6whsni6cac4ail1i.png)

<a name="item-3"></a>

Feito. Agora temos uma servidor com dados armazenados e podemos prosseguir para o próximo passo.

## 3. Criando a instância de backup 

Aqui repetiremos um passo-a-passo muito semelhante ao da primeira parte deste tutorial. Já logado na sua conta do Google que administra o GCP vá até a listagem de instâncias de VM ([help](#vms)), e no menu superior clique em criar instância. 

Defina um nome para a instância, selecione a região, e defina as configurações da máquina. Minhas configurações ficaram da seguinte forma: 

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/fy466mzunakwbnhc8rru.png)

Logo abaixo na seção do disco de inicialização clique em alterar. também iremos manter a mesma configuração utilizada no início do tutorial ([help](#disk)), no entanto, podemos alocar bem mais espaço no disco. A depender do tamanho do seu banco, eu recomendaria pelo menos 500GB. Então, temos:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/42nzg8wgprwofzb11uma.png)

<a name="item-4"></a>

Por fim, podemos clicar em "Criar" no fim do formulário e prosseguir para a próxima parte.

## 4. Conectando as duas instâncias via SSH 

Agora que temos as duas instâncias prontas para uso, precisamos conectá-las via SSH para enviar dados para a instância de backup.

Caso você não saiba como o protocolo SSH funciona, sugiro que procure fontes confiáveis e leia sobre, pois trataremos esse assunto de forma bem rasa ao longo deste guia.

Para que a conexão seja feita, precisamos gerar um par de chaves SSH no servidor de produção e autorizá-la no servidor de backup. Para fazer isso, primeiro vá até a listagem instâncias de VM e clique no botão "SSH" da instância de produção.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/ydjsw6pmeiytqifzl5wm.png)

Uma janela será aberta e após a conexão temos acesso ao servidor de produção. Para gerar uma novo par de chaves SSH utilizaremos o comando:

```
$ ssh-keygen -t rsa -b 4096
```

Após isso será pedido que você selecione uma pasta destino para as chaves. Basta pressionar `enter` para que elas sejam criadas no diretório padrão `~/.ssh/`. Depois será pedido uma _passphrase_, basta deixar o campo em branco e confirmar com `enter` duas vezes.
Pronto, para confirmar se as chaves foram realmente criadas, basta rodar:

```
$ ls ~/.ssh/
```

E verificar se na pasta existem os arquivos `id_rsa` e `id_rsa.pub`. Caso contrário, repita o processo indicando que quer suas chaves no diretório `~/.ssh`.

Explicando esses dois arquivos rapidamente, temos `id_rsa` como chave privada e `id_rsa.pub` como chave pública. Essa última será compartilhada com o servidor de backup. Por questões de segurança recomendo que mude as permissões na chave privada para somente leitura do usuário dono com o comando:

```
$ chmod 400 ~/.ssh/id_rsa
```

Prosseguindo com o acesso ao servidor de backup, primeiro você deve obter o valor de sua chave pública:

```
$ cat ~/.ssh/id_rsa.pub
```

O comando `cat` retornará o valor da chave. Copie-o e cole em um editor de texto de sua preferência e feche a janela de acesso ao servidor de produção. A ideia aqui é eliminar as quebras de linha presentes na chave pública utilizando `backspace`, caso contrário ela será invalidada. Essas foram as quebras de linha presentes no meu arquivo:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/j1zr0i3qeqckoynf1t0e.png)

Após eliminar as quebras de linha, copie o conteúdo, e vá novamente até a listagem de instâncias de VM e clique na instância "backup". 

Agora, no menu de detalhamento da instância clique em editar no menu superior. 

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/dp2kskffb4ebx633agcn.png)

Desça até a seção "Chaves SSH", clique em "Mostrar e editar" e insira a chave pública no campo. Perceba que caso a chave tenha sido validada corretamente, o nome do seu usuário aparecerá à esquerda do campo.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/01osoimfcpm47bo0pzkg.png)

Desça até o final da página e clique em "Salvar", volte até a listagem de instâncias, e abra o acesso ao servidor de produção novamente.

Caso tudo tenha corrido bem até aqui, para acessar a instância de backup através da instância de produção basta rodar:

```
$ ssh <nome-da-instancia-de-backup>
```

No meu caso: 
```
$ ssh backup
```

<a name="item-5"></a>

Pronto! Agora as duas máquinas estão conectadas. Para voltar para a máquina de produção basta rodar o comando `exit`.

## 5. Criando os shell scripts de backup 

Para configurar os shells scripts você deve voltar a instância de produção, então caso ainda não o tenha feito, rode `exit`.

Iremos criar algumas pastas para armazenar backups temporários ainda nessa máquina antes de passá-los para a outra instância. As pastas serão criadas na raiz `/` com o seguinte comando:

```
$ sudo mkdir -p /backups_tmp/databases/postgres
```

Após isso iremos mudar usuário dono dessas pastas para o nosso ao invés do root.

```
$ sudo chown $USER:$USER -R /backups_tmp/
```

Navegaremos até a pasta `/backups_tmp`:

```
$ cd /backups_tmp
```

E iremos começar escrever o nosso shell script. Eu utilizarei o nano, mas sinta-se à vontade para utilizar outro editor como o Vim.

```
$ nano backup.sh
```
Cole o seguinte script dentro do arquivo. 

```shell
#!/bin/sh

# backup.sh

DATE=$(/bin/date +%Y%m%d%H%M%S)

POSTGRES_NAME="prod_database"

POSTGRES_USER="postgres"

POSTGRES_DATABASE="postgres"

sudo docker exec -t $POSTGRES_NAME pg_dumpall -c -U $POSTGRES_USER > /backups_tmp/databases/postgres/$POSTGRES_DATABASE-$DATE

rsync -avzhe ssh /backups_tmp/databases/ backup:~/backups/databases/
```

Aqui definimos quatro variáveis que são utilizadas ao longo do script. O primeiro comando roda o comando `pg_dumpall` gerando um backup no container onde está o nosso banco de dados. 

O retorno desse comando é inserido em um arquivo na pasta `databases/postgres/`, que é composto pelo nome do banco de dados seguido de um hífen e a data em que o backup foi gerado.

O segundo comando é onde acontece o envio do arquivo para o servidor de backup. Utilizamos `rsync` para sincronizar os dados do backup temporário com o servidor de backup. 

Após o parâmetro `ssh` é informado o diretório dos arquivos ou pastas a serem enviados: `/backups_tmp/databases`. Em seguida informamos o destino dos arquivos neste formato `<nome-ou-ip-do-servidor>:/diretorio/alvo`, que no meu caso ficou como: `backup:~/backups/databases`

Pressione `CTRL+O` para salvar e `CTRL+X` para fechar o nano, sempre confirmando com `enter`.

Agora basta dar permissão de execução para o arquivo:

```
$ chmod +x backup.sh
```

Antes de executar o arquivo e passarmos para a próxima parte do tutorial, execute `ssh backup` para ir até a instância de backup, e rode o comando para criar os diretórios.

```
$ mkdir -p ~/backups/databases/postgres/
```

Volte a instância de produção, e execute o shell script que criamos.

```
$ ./backup.sh
``` 

O backup será gerado, armazenado na pasta `postgres` e enviado para a pasta `postgres` do servidor de backup. O retorno deverá ser semelhante ao seguinte:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/3cbrnp94h7q32mwism0x.png)

<a name="item-6"></a>

Sugiro que você verifique os arquivos no servidor de backup antes de prosseguir para a próxima parte, caso algo não esteja como esperado, revise o seu script e repita os passos.

## 6. Entendendo e configurando o Crontab 

Agora iremos programar o Crontab para rodar o nosso script de backup e remover arquivos antigos periodicamente. Mas antes entenda como o Crontab funciona.

Para configurá-lo iremos fazer alterações no arquivo `/etc/crontab`, portanto:

```
$ sudo nano /etc/crontab
```

Ao abrir o arquivo você irá se deparar com o seguinte conteúdo:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/jl8cbpfhclu5u3t6v68w.png)

Para configurar novas tarefas iremos alterar somente a tabela ao fim do arquivo. Ela funciona da seguinte forma:

 * `m` -> minuto (0 - 59)

 * `h` -> hora do dia (0 - 23)

 * `dom` -> Dia do mês (1 - 31)

 * `mon` -> Mês (1 - 12)

 * `dow` -> Dia da semana começando pelo domingo (0 - 7) 

 * `user` -> Usuário que executará a tarefa

 * `command` -> O comando da tarefa

Então caso precisássemos criar o arquivo `example.txt` com o usuário `john` todo dia 15 do mês e aos domingos às 18:47h, adicionaríamos a seguinte linha ao Crontab:

```
47 21 15 * 0 john touch ~/example.txt
```

Se desejar fazer mais testes, sugiro que acesse o [Crontab Guru](https://crontab.guru/).

Perceba que adicionei +3 à hora, pois o Crontab segue o horário do sistema, que por padrão é UTC. Você pode verificar o horário com o comando `date`. 

Caso seja necessário que uma tarefa seja executada todo dia em determinado horário, basta preencher a hora exigida e as colunas de dias com `*`.

Agora que Sabemos como o Crontab funciona, vamos configurar nossas tarefas de backup. A primeira será a execução do arquivo de backup, a segunda será a limpeza total dos dados na máquina de produção a cada 7 dias na segunda-feira.

```
30 6 * * * contato_andrepsf /backups_tmp/backup.sh
15 6 * * 1 contato_andrepsf rm -rf /backups_tmp/databases/postgres/*
```
<a name="item-7"></a>

Dessa forma já temos nosso Crontab totalmente pronto. Caso você queira testar, basta definir um horário próximo e esperar que o Crontab execute as tarefas.

## 7. Adicionando o shell script de expurgo 

Por fim, iremos adicionar um script de expurgo na instância de backup. O script será executado todo dia pelo Crontab eliminando os dados com 7 dias desde a data de criação.

Para começar acesse a máquina de backup com `ssh backup`. Logo em seguida iremos criar o arquivo `backup_purge.sh`.

```
$ nano backup_purge.sh
```

Cole o seguinte script dentro do arquivo. 

```shell
#!/bin/sh

# backup_purge.sh

DATE=$(/bin/date -d "-7day" +%Y%m%d)

rm -rf ~/backups/databases/postgres/postgres-"$DATE"*
```

Salve o arquivo, feche o nano, e dê permissão de execução.

```
$ chmod +x backup_purge.sh
```

Abra o crontab.

```
$ sudo nano /etc/crontab
```

E adicione uma linha ao arquivo para a execução do script todo dia.

```
15 6 * * * contato_andrepsf ~/backup_purge.sh
```
Feito! Agora o nosso script diariamente irá expurgar os arquivos de backup diariamente.

## Conclusão

Com isso está pronta a nossa rotina de backup no GCP. Vale lembrar que a localização dos arquivos é totalmente personalizável e você pode organizar da forma que achar mais adequado. 

Obrigado por ler até aqui, fico aberto a qualquer sugestão ou dúvida. Espero ter ajudado :).

## Bibliografia

https://cloud.google.com/compute/docs/instances/
https://www.openssh.com/
https://hub.docker.com/_/postgres
http://www.bosontreinamentos.com.br/linux/10-exemplos-do-comando-rsync-para-backup-e-sincronismo-de-arquivos-no-linux/