[PT-BR] Subindo um Docker Compose na nuvem Render
Tags: java, springboot, dio, render
Published: 2024-03-20 18:27:24

## Repositório que estará sendo utilizado como exemplo
 
{% embed https://github.com/digitalinnovationone/santander-dev-week-2023-api %}
 
## Diferença entre nuvens

O ***Railway*** tem um interpretador para aplicações Spring Boot, então pelo repositório fornecido ele identifica o arquivo .jar necessário para aplicação.

O ***Render*** não, o que ele nos permite é gerar um serviço web, como um API, por exemplo, mas precisamos instruí-lo a montar o ambiente necessário para que a aplicação seja executada, faremos isso através de um arquivo parecido ao Docker Compose, mas não se assuste, é bem simples.

O Render não oferece suporte para arquivos `docker-compose.yml` ainda, mas podemos convertê-lo para o arquivo `render.yaml` para alcançarmos o mesmo resultado.

- Render Blueprints (IaC)

Blueprint é um modelo de infraestrutura-como-código para definir, implantar e gerenciar vários recursos com um único arquivo YAML, como: serviços e banco de dados.

![IaC](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/s2tbzznqkirhvm9ut11z.png)
 
## Passo a passo

- Alterar o `ddl-auto` no perfil de produção:

```
📂santander-dev-week-2023-api
 ┣ 📂.gradle
 ┣ 📂.idea
 ┣ 📂gradle
 ┣ 📂src
 ┃ ┗ 📂main
 ┃    ┗ 📂java
 ┃    ┗ 📂resources
 ┃       ┗ 📛application-dev.yml
 ┃       ┗ 📛application-prd.yml ←
 ┣ 🚫.gitignore
 ┣ 🐘build.gradle
 ┣ » gradlew
 ┣ » gradlew.bat
 ┣ 🐘settings.gradle
```

```yml
spring:
  datasource:
    url: jdbc:postgresql://${PGHOST}:${PGPORT}/${PGDATABASE}
    username: ${PGUSER}
    password: ${PGPASSWORD}
  jpa:
    open-in-view: false
    hibernate:
      ddl-auto: update ←
```
 
- Descobrindo o nome do arquivo .jar

> Execute:

![bootJar](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xnb91wkbp7dqqef87sdl.png)

ou se preferir também é possível pelo terminal:

```
.\gradlew bootJar
```

> Guarde o nome do arquivo .jar gerado dentro de build/libs:

```
📂santander-dev-week-2023-api
 ┣ 📂.gradle
 ┣ 📂.idea
 ┣ 📂build
 ┃ ┗ 📂libs
 ┃    ┗ ⚙santander-dev-week-2023-api-0.0.1-SNAPSHOT.jar ←
 ┣ 📂gradle
 ┣ 📂src
 ┣ 🚫.gitignore
 ┣ 🐘build.gradle
 ┣ » gradlew
 ┣ » gradlew.bat
 ┣ 🐘settings.gradle
```

> Feito isto você pode excluir a pasta build ou executar o comando no terminal `.\gradlew clean`, pois não terá mais utilidade

 
- Criando o `Dockerfile` na raiz do projeto e preenchendo-o: 

###### É um arquivo simples sem extensão.

```
📂santander-dev-week-2023-api
 ┣ 📂.gradle
 ┣ 📂.idea
 ┣ 📂gradle
 ┣ 📂src
 ┣ 🚫.gitignore
 ┣ 🐘build.gradle
 ┣ 🐋Dockerfile ←
 ┣ » gradlew
 ┣ » gradlew.bat
 ┣ 🐘settings.gradle
```

```docker
# Define a imagem base para a etapa de construção, que será uma versão do Debian
FROM debian:latest AS BUILD

# Atualiza os repositórios de pacotes e instala o JDK 17
RUN apt-get update && apt-get install -y openjdk-17-jdk

# Copia todo o conteúdo do diretório atual para o contexto de construção do Docker
COPY . .

# Concede permissão de execução ao script gradlew e executa os comandos clean e bootJar com ele
RUN chmod +x gradlew && ./gradlew clean bootJar

# Define a imagem base para a execução, que será uma versão mais leve do JDK 17
FROM openjdk:17-jdk-slim

# Copia o arquivo .jar da etapa de construção para o diretório atual do contêiner e o renomeia para app.jar
# Se atente ao nome do arquivo .jar gerado no passo anterior
COPY --from=build ./build/libs/santander-dev-week-2023-api-0.0.1-SNAPSHOT.jar app.jar

# Define o ponto de entrada do contêiner como a execução do arquivo .jar com a ativação do perfil "prd"
ENTRYPOINT ["java", "-jar", "-Dspring.profiles.active=prd", "app.jar"]
```
 
- Criando o arquivo `render.yaml` na raiz do projeto para o deploy:
```
📂santander-dev-week-2023-api
 ┣ 📂.gradle
 ┣ 📂.idea
 ┣ 📂gradle
 ┣ 📂src
 ┣ 🚫.gitignore
 ┣ 🐘build.gradle
 ┣ 🐋Dockerfile
 ┣ » gradlew
 ┣ » gradlew.bat
 ┣ 📛render.yaml ←
 ┣ 🐘settings.gradle
```
```yaml
databases:
  - name: postgres
    plan: free

services:
  - name: springboot-app
    type: web
    plan: free
    runtime: docker
    envVars: #Se atente às variáveis setadas no perfil de produção
      - key: PGHOST
        fromDatabase:
          name: postgres
          property: host
      - key: PGPORT
        fromDatabase:
          name: postgres
          property: port
      - key: PGDATABASE
        fromDatabase:
          name: postgres
          property: database
      - key: PGUSER
        fromDatabase:
          name: postgres
          property: user
      - key: PGPASSWORD
        fromDatabase:
          name: postgres
          property: password
```
 
- Finalizado, faça um ***push*** das modificações para seu repositório Github.

> Caso esteja seguindo por um clone do repositório de exemplo, execute o seguinte comando e suba para um novo repositório Github:

```bash
~/Desktop/santander-dev-week-2023-api
rm -rf .git ←

~/Desktop/santander-dev-week-2023-api
git init ←
```
 
- Criar uma [conta](https://dashboard.render.com/register) no Render vinculada ao <u>Github ou Google</u>.

> *É importante ser vinculada à alguma conta para liberar o plano grátis*

 
- Criar um novo [Blueprint](https://dashboard.render.com/select-repo?type=blueprint)

> Passar a URL do repositório Github criado e prosseguir:

![Repo URL](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mxlpz0olfuanlca9xzp0.png)

> Preencher o campo ***name***, ***aplicar*** e aguardar a construção dos serviços.


![Successful](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5gavlur0s479f983pd6z.png)

 
> Você pode acessar sua aplicação clicando no nome ou pelo [Dashboard](https://dashboard.render.com)

 
- Copiar o endereço da documentação do Swagger

> `url do seu web-service` + `/swagger-ui.html`

###### No meu caso seria `https://springboot-app-z98f.onrender.com` + `/swagger-ui.html` como pode-se averiguar:

![Service URL](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gyc4jxzl51pz7r7vygj8.png)
 
- Mantendo o serviço ativo

Como fora abordado, o Render tem uma política de hibernar todo serviço grátis que não interagir dentro de um intervalo de 15 minutos.

Mas podemos utilizar o monitorador de serviços online [UptimeRobot](https://uptimerobot.com) para enviar requisições a cada 5 minutos mantendo nosso serviço sempre interagindo.

Basta:

1. Se [registrar](https://uptimerobot.com) no ***UptimeRobot***;
2. Tornando-se um usuário você pode criar um serviço de monitoramento acessando este [link](https://dashboard.uptimerobot.com/monitors/new/http);
3. O tipo de monitoramento `Monitor Type` deve ser `HTTP`;
4. E em `URL to monitor:` basta colocar a URL do Swagger: `url do seu web-service` + `/swagger-ui.html`;
5. Caso não queira ser atualizado sobre o status do seu serviço basta desmarcar a caixa `Email`;
6. Pronto, basta criar seu monitor através do botão `Create Monitor`.

 

### 🎉 Parabéns! Agora você tem uma aplicação Spring Boot documentada pelo Swagger em produção!

 

Como eu havia dito, o `render.yaml` serve como um conversor de um `docker-compose.yml`, para fim de contexto este seria um compose equivalente ao que foi montado:

```yml
version: '3.9'

services:

  db:
    image: postgres:latest  # Define a imagem do serviço do banco de dados como a última versão do PostgreSQL.
    environment:
      POSTGRES_DB: api  # Define o nome do banco de dados como 'api'.
      POSTGRES_USER: apiuser  # Define o nome de usuário do PostgreSQL como 'apiuser'.
      POSTGRES_PASSWORD: apipassword  # Define a senha do usuário 'apiuser' como 'apipassword'.
    ports:
      - 5432:5432  # Mapeia a porta 5432 do host para a porta 5432 do contêiner PostgreSQL.

  app:
    build: # Define a construção do serviço de aplicativo a partir de um Dockerfile.
      context: .  # Define o contexto de construção como o diretório atual.
      dockerfile: Dockerfile  # Define o Dockerfile a ser utilizado para construir o serviço de aplicativo.
    ports:
      - "8080:8080"  # Mapeia a porta 8080 do host para a porta 8080 do contêiner da aplicação.
    environment:
      - PGHOST=db  # Define o host do banco de dados como 'db', correspondente ao nome do serviço no Docker Compose.
      - PGDATABASE=api  # Define o nome do banco de dados como 'api'.
      - PGPORT=5432  # Define a porta do banco de dados como 5432, a mesma porta mapeada para o serviço do banco de dados.
      - PGUSER=apiuser  # Define o nome de usuário do PostgreSQL como 'apiuser'.
      - PGPASSWORD=apipassword  # Define a senha do usuário 'apiuser' como 'apipassword'.
    depends_on:
      - db  # Define a dependência do serviço de aplicativo no serviço de banco de dados para garantir que o banco de dados esteja disponível antes de iniciar o aplicativo.
```