From 499d8a9e4c932fcab3ddd584f6717a27b8e02da0 Mon Sep 17 00:00:00 2001 From: mellyssamnds Date: Sun, 9 Aug 2026 21:15:02 -0300 Subject: [PATCH 1/8] Adiciona manifest Kubernetes e pipeline Deploy --- .github/workflows/deploy.yml | 111 +++++++++++++++++++++++++++++++++++ k8s/app.yaml | 45 ++++++++++++++ 2 files changed, 156 insertions(+) create mode 100644 .github/workflows/deploy.yml create mode 100644 k8s/app.yaml diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml new file mode 100644 index 0000000..d6670dd --- /dev/null +++ b/.github/workflows/deploy.yml @@ -0,0 +1,111 @@ + +name: Deploy + + + +on: + +  workflow_dispatch: + + + +env: + +  REGISTRY: container-registry.br-se1.magalu.cloud + +  IMAGE_NAME: cloud-application + + + +jobs: + +  test: + +    runs-on: ubuntu-latest + +    steps: + +    - uses: actions/checkout@v4 + + + +    - uses: actions/setup-python@v5 + +      with: + +        python-version: '3.11' + + + +    - name: Instalar dependências + +      run: | + +        pip install poetry + +        poetry install --no-root + + + +    - name: Executar testes + +      run: poetry run pytest + + + +  build-and-deploy: + +    needs: test + +    runs-on: ubuntu-latest + +    steps: + +    - uses: actions/checkout@v4 + + + +    - name: Login no Container Registry + +      run: | + +        docker login https://${{ env.REGISTRY }} \ + +          -u ${{ secrets.MGC_REGISTRY_USER }} \ + +          -p ${{ secrets.MGC_REGISTRY_PASSWORD }} + + + +    - name: Build e push da imagem + +      run: | + +        IMAGE=${{ env.REGISTRY }}/${{ secrets.MGC_REGISTRY_NAME }}/${{ env.IMAGE_NAME }}:latest + +        docker build -t $IMAGE . + +        docker push $IMAGE + + + +    - name: Configurar kubectl + +      run: | + +        echo "${{ secrets.MGC_KUBECONFIG }}" > kubeconfig.yaml + + + +    - name: Deploy no Kubernetes + +      run: | + +        export KUBECONFIG=kubeconfig.yaml + +        export MGC_REGISTRY_NAME=${{ secrets.MGC_REGISTRY_NAME }} + +        envsubst < k8s/app.yaml | kubectl apply -f - + +        kubectl rollout status deployment/cloud-application + diff --git a/k8s/app.yaml b/k8s/app.yaml new file mode 100644 index 0000000..95d942b --- /dev/null +++ b/k8s/app.yaml @@ -0,0 +1,45 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: cloud-application + labels: + app: cloud-application +spec: + replicas: 2 + selector: + matchLabels: + app: cloud-application + template: + metadata: + labels: + app: cloud-application + spec: + containers: + - name: cloud-application + image: container-registry.br-se1.magalu.cloud/${MGC_REGISTRY_NAME}/cloud-application:latest + ports: + - containerPort: 8000 + livenessProbe: + httpGet: + path: /health + port: 8000 + initialDelaySeconds: 10 + periodSeconds: 30 + readinessProbe: + httpGet: + path: /health + port: 8000 + initialDelaySeconds: 5 + periodSeconds: 10 +--- +apiVersion: v1 +kind: Service +metadata: + name: cloud-application +spec: + type: LoadBalancer + selector: + app: cloud-application + ports: + - port: 80 + targetPort: 8000 From 53524dfec9cc10cd6ab61f7e14e9c19be50811bc Mon Sep 17 00:00:00 2001 From: mellyssamnds Date: Sun, 9 Aug 2026 21:27:47 -0300 Subject: [PATCH 2/8] =?UTF-8?q?Corrige=20espa=C3=A7amento=20do=20deploy.ym?= =?UTF-8?q?l?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/deploy.yml | 67 ------------------------------------ 1 file changed, 67 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index d6670dd..38768d9 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -1,111 +1,44 @@ - name: Deploy - - - on: -   workflow_dispatch: - - - env: -   REGISTRY: container-registry.br-se1.magalu.cloud -   IMAGE_NAME: cloud-application - - - jobs: -   test: -     runs-on: ubuntu-latest -     steps: -     - uses: actions/checkout@v4 - - -     - uses: actions/setup-python@v5 -       with: -         python-version: '3.11' - - -     - name: Instalar dependências -       run: | -         pip install poetry -         poetry install --no-root - - -     - name: Executar testes -       run: poetry run pytest - - -   build-and-deploy: -     needs: test -     runs-on: ubuntu-latest -     steps: -     - uses: actions/checkout@v4 - - -     - name: Login no Container Registry -       run: | -         docker login https://${{ env.REGISTRY }} \ -           -u ${{ secrets.MGC_REGISTRY_USER }} \ -           -p ${{ secrets.MGC_REGISTRY_PASSWORD }} - - -     - name: Build e push da imagem -       run: | -         IMAGE=${{ env.REGISTRY }}/${{ secrets.MGC_REGISTRY_NAME }}/${{ env.IMAGE_NAME }}:latest -         docker build -t $IMAGE . -         docker push $IMAGE - - -     - name: Configurar kubectl -       run: | -         echo "${{ secrets.MGC_KUBECONFIG }}" > kubeconfig.yaml - - -     - name: Deploy no Kubernetes -       run: | -         export KUBECONFIG=kubeconfig.yaml -         export MGC_REGISTRY_NAME=${{ secrets.MGC_REGISTRY_NAME }} -         envsubst < k8s/app.yaml | kubectl apply -f - -         kubectl rollout status deployment/cloud-application - From af4422e21ade54c386591d125385e3172c8dff86 Mon Sep 17 00:00:00 2001 From: mellyssamnds Date: Sun, 9 Aug 2026 21:34:36 -0300 Subject: [PATCH 3/8] =?UTF-8?q?Corrige=20espa=C3=A7os=20n=C3=A3o-quebr?= =?UTF-8?q?=C3=A1veis=20(NBSP)=20no=20YAML?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/deploy.yml | 80 ++++++++++++++++++------------------ 1 file changed, 40 insertions(+), 40 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 38768d9..9c89994 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -1,44 +1,44 @@ name: Deploy on: -  workflow_dispatch: + workflow_dispatch: env: -  REGISTRY: container-registry.br-se1.magalu.cloud -  IMAGE_NAME: cloud-application + REGISTRY: container-registry.br-se1.magalu.cloud + IMAGE_NAME: cloud-application jobs: -  test: -    runs-on: ubuntu-latest -    steps: -    - uses: actions/checkout@v4 -    - uses: actions/setup-python@v5 -      with: -        python-version: '3.11' -    - name: Instalar dependências -      run: | -        pip install poetry -        poetry install --no-root -    - name: Executar testes -      run: poetry run pytest -  build-and-deploy: -    needs: test -    runs-on: ubuntu-latest -    steps: -    - uses: actions/checkout@v4 -    - name: Login no Container Registry -      run: | -        docker login https://${{ env.REGISTRY }} \ -          -u ${{ secrets.MGC_REGISTRY_USER }} \ -          -p ${{ secrets.MGC_REGISTRY_PASSWORD }} -    - name: Build e push da imagem -      run: | -        IMAGE=${{ env.REGISTRY }}/${{ secrets.MGC_REGISTRY_NAME }}/${{ env.IMAGE_NAME }}:latest -        docker build -t $IMAGE . -        docker push $IMAGE -    - name: Configurar kubectl -      run: | -        echo "${{ secrets.MGC_KUBECONFIG }}" > kubeconfig.yaml -    - name: Deploy no Kubernetes -      run: | -        export KUBECONFIG=kubeconfig.yaml -        export MGC_REGISTRY_NAME=${{ secrets.MGC_REGISTRY_NAME }} -        envsubst < k8s/app.yaml | kubectl apply -f - -        kubectl rollout status deployment/cloud-application + test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + python-version: '3.11' + - name: Instalar dependências + run: | + pip install poetry + poetry install --no-root + - name: Executar testes + run: poetry run pytest + build-and-deploy: + needs: test + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Login no Container Registry + run: | + docker login https://${{ env.REGISTRY }} \ + -u ${{ secrets.MGC_REGISTRY_USER }} \ + -p ${{ secrets.MGC_REGISTRY_PASSWORD }} + - name: Build e push da imagem + run: | + IMAGE=${{ env.REGISTRY }}/${{ secrets.MGC_REGISTRY_NAME }}/${{ env.IMAGE_NAME }}:latest + docker build -t $IMAGE . + docker push $IMAGE + - name: Configurar kubectl + run: | + echo "${{ secrets.MGC_KUBECONFIG }}" > kubeconfig.yaml + - name: Deploy no Kubernetes + run: | + export KUBECONFIG=kubeconfig.yaml + export MGC_REGISTRY_NAME=${{ secrets.MGC_REGISTRY_NAME }} + envsubst < k8s/app.yaml | kubectl apply -f - + kubectl rollout status deployment/cloud-application From 3dc22a476633d691b64a081677f364dea626c52d Mon Sep 17 00:00:00 2001 From: mellyssamnds Date: Sun, 9 Aug 2026 21:49:26 -0300 Subject: [PATCH 4/8] =?UTF-8?q?Adiciona=20documenta=C3=A7=C3=A3o=20da=20mo?= =?UTF-8?q?delagem=20de=20dados?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/data-model.md | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 docs/data-model.md diff --git a/docs/data-model.md b/docs/data-model.md new file mode 100644 index 0000000..f8fdb51 --- /dev/null +++ b/docs/data-model.md @@ -0,0 +1,26 @@ +# Modelagem de Dados + +## Entidades + +### Pedido (orders) + +| Coluna | Tipo | Descrição | +|--------------|--------------------------------|----------------------------------------------------------------------------| +| id | String (UUID) | Chave primária. Gerado automaticamente (`uuid4`) na criação do pedido | +| customer | String | Nome do cliente que fez o pedido. Obrigatório | +| status | String | Status do pedido. Padrão: `"open"` | +| created_at | DateTime (com timezone, UTC) | Data/hora de criação do pedido. Preenchido automaticamente (`now(UTC)`) | + +### Item (items) + +| Coluna | Tipo | Descrição | +|--------------|-----------|-----------------------------------------------------------------------------| +| id | String (UUID) | Chave primária. Gerado automaticamente (`uuid4`) na criação do item | +| order_id | String | Chave estrangeira para `orders.id`. Obrigatório | +| sku | String | Código (SKU) do produto. Obrigatório | +| description | String | Descrição do item. Obrigatório | +| quantity | Integer | Quantidade do item no pedido. Obrigatório | + +## Relacionamento + +Relacionamento **1:N** entre `orders` e `items`: um pedido (`Order`) pode ter vários itens (`Item`), e cada item pertence a exatamente um pedido, via a chave estrangeira `items.order_id → orders.id`. From 937784ca96533f71c4e6c5fd395ec0ae8b34e05a Mon Sep 17 00:00:00 2001 From: mellyssamnds Date: Sun, 9 Aug 2026 22:09:29 -0300 Subject: [PATCH 5/8] =?UTF-8?q?Adiciona=20integra=C3=A7=C3=A3o=20com=20Pos?= =?UTF-8?q?tgreSQL=20via=20db-secret?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/deploy.yml | 6 ++++++ k8s/app.yaml | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 9c89994..483e196 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -36,6 +36,12 @@ jobs: - name: Configurar kubectl run: | echo "${{ secrets.MGC_KUBECONFIG }}" > kubeconfig.yaml + - name: Criar Secret do banco + run: | + export KUBECONFIG=kubeconfig.yaml + kubectl create secret generic db-secret \ + --from-literal=url=${{ secrets.DATABASE_URL }} \ + --dry-run=client -o yaml | kubectl apply -f - - name: Deploy no Kubernetes run: | export KUBECONFIG=kubeconfig.yaml diff --git a/k8s/app.yaml b/k8s/app.yaml index 95d942b..ef77ab6 100644 --- a/k8s/app.yaml +++ b/k8s/app.yaml @@ -19,6 +19,12 @@ spec: image: container-registry.br-se1.magalu.cloud/${MGC_REGISTRY_NAME}/cloud-application:latest ports: - containerPort: 8000 + env: + - name: DATABASE_URL + valueFrom: + secretKeyRef: + name: db-secret + key: url livenessProbe: httpGet: path: /health From 89297ac75770054f7b5c89ce0662ea9c0c3567ce Mon Sep 17 00:00:00 2001 From: mellyssamnds Date: Sun, 9 Aug 2026 23:05:25 -0300 Subject: [PATCH 6/8] Nomeia a porta do Service como http para o ServiceMonitor --- k8s/app.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/k8s/app.yaml b/k8s/app.yaml index ef77ab6..d20798d 100644 --- a/k8s/app.yaml +++ b/k8s/app.yaml @@ -47,5 +47,6 @@ spec: selector: app: cloud-application ports: - - port: 80 + - name: http + port: 80 targetPort: 8000 From af5df8ecf8280557524fc9be000e5a5cddb8b03c Mon Sep 17 00:00:00 2001 From: mellyssamnds Date: Sun, 9 Aug 2026 23:20:26 -0300 Subject: [PATCH 7/8] =?UTF-8?q?Adiciona=20label=20ao=20Service=20para=20o?= =?UTF-8?q?=20ServiceMonitor=20encontr=C3=A1-lo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- k8s/app.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/k8s/app.yaml b/k8s/app.yaml index d20798d..9001a99 100644 --- a/k8s/app.yaml +++ b/k8s/app.yaml @@ -42,6 +42,8 @@ apiVersion: v1 kind: Service metadata: name: cloud-application + labels: + app: cloud-application spec: type: LoadBalancer selector: From b250edfa9d40f7c84c025d74d5c3f949e12ac1f7 Mon Sep 17 00:00:00 2001 From: mellyssamnds Date: Sun, 9 Aug 2026 23:37:55 -0300 Subject: [PATCH 8/8] =?UTF-8?q?Adiciona=20documenta=C3=A7=C3=A3o=20de=20ar?= =?UTF-8?q?quitetura=20e=20ADRs=20(Compet=C3=AAncia=206)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/docs/adr/001-kubernetes-deploy.md | 35 ++++++++++ docs/docs/adr/002-dbaas-postgresql.md | 30 ++++++++ docs/docs/architecture.md | 97 ++++++++++++++++++++++++++ 3 files changed, 162 insertions(+) create mode 100644 docs/docs/adr/001-kubernetes-deploy.md create mode 100644 docs/docs/adr/002-dbaas-postgresql.md create mode 100644 docs/docs/architecture.md diff --git a/docs/docs/adr/001-kubernetes-deploy.md b/docs/docs/adr/001-kubernetes-deploy.md new file mode 100644 index 0000000..5f2a90d --- /dev/null +++ b/docs/docs/adr/001-kubernetes-deploy.md @@ -0,0 +1,35 @@ +# ADR 001 — Usar K3s para deploy da aplicação + +**Status:** Aceito +**Data:** 2026-08-04 + +## Contexto + +A aplicação precisa ser implantada na Magalu Cloud de forma acessível publicamente, resiliente a falhas e com capacidade de escalar. + +## Alternativas consideradas + +- **K3s em VM** — Kubernetes leve; cobra só a VM; provisionamento < 2 min; sem HA nativa. +- **MKS (Kubernetes Gerenciado)** — control plane e HA gerenciados; custo maior; provisionamento 5-10 min. +- **VM com Docker Compose** — mais simples de subir; sem orquestração, self-healing nem escala declarativa. + +## Decisão + +Usar K3s em uma VM BV2-2-40 (Ubuntu 24.04) com Klipper ServiceLB para expor a aplicação na porta 80 do IP público da VM. + +O script `k3s-mgc` automatiza todo o provisionamento. Critério: menor custo e provisionamento mais rápido, com manifests idênticos a qualquer Kubernetes. + +## Consequências + +**Positivas:** +- Custo menor que o MKS (cobra apenas pela VM e não pelo control plane) +- Provisionamento em menos de 2 minutos +- Manifests YAML idênticos a qualquer Kubernetes padrão (sem lock-in) +- Restart automático em caso de falha (liveness probe) +- Escalabilidade horizontal simples (basta aumentar o número de réplicas) + +**Negativas:** +- Single point of failure: sem alta disponibilidade nativa (tudo em uma VM) +- Armazenamento efêmero: volumes locais desaparecem se a VM for recriada +- Sem auto-scaling de nós: capacidade fixa (2 vCPU, 2 GB) +- IP público muda se a VM for substituída diff --git a/docs/docs/adr/002-dbaas-postgresql.md b/docs/docs/adr/002-dbaas-postgresql.md new file mode 100644 index 0000000..4dde7db --- /dev/null +++ b/docs/docs/adr/002-dbaas-postgresql.md @@ -0,0 +1,30 @@ +# ADR 002 — Usar DBaaS PostgreSQL da Magalu Cloud + +**Status:** Aceito +**Data:** 2026-08-04 + +## Contexto + +A aplicação precisa de persistência de dados. O banco precisa sobreviver a reinicializações de containers e estar disponível para múltiplas réplicas da API simultaneamente. + +## Alternativas consideradas + +- **DBaaS PostgreSQL gerenciado (externo)** — backup, patch e HA pelo provedor; custo maior; menos controle fino. +- **PostgreSQL em pod com PVC** — custo baixo, tudo em um lugar; volume, backup e recuperação por nossa conta; o dado morre junto com o cluster. + +## Decisão + +Usar o serviço DBaaS PostgreSQL da Magalu Cloud — banco gerenciado, sem necessidade de operar o servidor de banco de dados. Critério: disponibilidade e custo de operação (estado é caro de operar manualmente). + +## Consequências + +**Positivas:** +- Backup automático gerenciado pelo provedor +- Sem custo operacional de administração do banco +- Conexões simultâneas de múltiplos pods sem conflito +- Alta disponibilidade incluída no serviço + +**Negativas:** +- Custo por hora de uso, mesmo com pouco tráfego +- Menor controle sobre configurações avançadas do PostgreSQL +- Dependência do provedor para upgrades de versão diff --git a/docs/docs/architecture.md b/docs/docs/architecture.md new file mode 100644 index 0000000..3afb538 --- /dev/null +++ b/docs/docs/architecture.md @@ -0,0 +1,97 @@ +# Arquitetura da Solução + +## Diagrama de arquitetura (C4 — Nível de Container) + +```mermaid +graph LR + User["Usuário / Cliente HTTP"] + + subgraph GH["GitHub"] + GA["GitHub Actions
(CI/CD)"] + end + + subgraph MGC["Magalu Cloud"] + CR[("Container Registry")] + + subgraph VM["VM BV2-2-40 · K3s"] + LB["Klipper ServiceLB
IP público · porta 80"] + API1["Pod API
réplica 1 · :8000"] + API2["Pod API
réplica 2 · :8000"] + end + + DB[("DBaaS PostgreSQL
IP privado · :5432")] + end + + User -->|"HTTP :80"| LB + LB -->|"HTTP :8000"| API1 + LB -->|"HTTP :8000"| API2 + API1 -->|"SQL/TCP :5432 (rede privada)"| DB + API2 -->|"SQL/TCP :5432 (rede privada)"| DB + GA -->|"docker push (HTTPS)"| CR + GA -->|"kubectl apply (via kubeconfig)"| VM + VM -->|"docker pull (HTTPS)"| CR +``` + +## Componentes da arquitetura + +| Componente | Serviço MGC | Função | +|---|---|---| +| API | K3s (VM single node) — 2 réplicas | Processa as requisições HTTP | +| Banco de dados | DBaaS PostgreSQL | Persiste pedidos e itens | +| Imagens | Container Registry | Armazena versões da aplicação | +| Tráfego externo | Klipper ServiceLB (IP da VM, porta 80) | Distribui entre as réplicas e fornece acesso externo | +| CI/CD | GitHub Actions | Automatiza testes, build e deploy | + +## Requisitos não-funcionais + +| Requisito | Como medir | Alvo | +|---|---|---| +| Disponibilidade | Erros 5xx e uptime das probes no Grafana | 99,5% mensal | +| Latência | `histogram_quantile(0.95, ...)` do `/metrics` | P95 < 500 ms | +| Escalabilidade | Teste de carga (k6) + `rate(http_requests_total)` | 300 req/s sem degradar | +| Custo | VM + DBaaS + IP na calculadora MGC | Teto definido em ADR | + +## Estilo arquitetural + +A solução segue um **monolito em camadas** (apresentação → serviço → dados), implantado como container único com duas réplicas atrás de um LoadBalancer. Não há separação de bounded contexts nem comunicação assíncrona entre serviços — toda a lógica de pedidos e itens vive num único processo FastAPI. + +Estilo-alvo, caso o domínio de notificações cresça: extrair um segundo serviço (ex.: um serviço de notificações desacoplado, comunicando-se via fila ou evento), evoluindo de monolito para um conjunto pequeno de serviços. + +## Trade-offs + +| Aspecto | Decisão tomada | Alternativa não escolhida | Motivo da escolha | +|---|---|---|---| +| Deploy | K3s em VM | MKS (Kubernetes Gerenciado) | Custo menor, provisionamento < 2 min, manifests idênticos | +| Banco | DBaaS gerenciado | PostgreSQL em container | Backup automático, sem administração | +| CI/CD | GitHub Actions | Deploy manual | Consistência e rastreabilidade | +| Réplicas | 2 pods | 1 pod | Disponibilidade mínima sem custo excessivo | +| API | FastAPI (Python) | Node.js, Go, Java | Curva de aprendizado baixa, alta produtividade | + +## Pontos de melhoria + +### Escalabilidade + +A aplicação é stateless, então escala na horizontal — mais réplicas atrás do balanceador. Hoje são 2 réplicas fixas; o próximo passo natural é o HPA (Horizontal Pod Autoscaler), que ajusta esse número automaticamente pela utilização de CPU (ex.: mínimo 2, máximo 6, alvo de 70%). Vale registrar também que mais réplicas não resolvem um gargalo de banco — o PostgreSQL escala na vertical e costuma saturar primeiro. + +### Próximos passos naturais + +| Melhoria | Por quê | +|---|---| +| HTTPS / TLS | Toda API em produção deve ser acessada por HTTPS | +| Autoscaler (HPA) | Escala automaticamente conforme a carga | +| Versionamento de API | `/v1/orders` permite evoluir sem quebrar clientes | +| Rate limiting | Evita abuso e protege o banco de sobrecargas | +| Cache (Redis) | Reduz consultas repetidas ao banco | +| Migrações de schema (Alembic) | Controle de versão das mudanças no banco | +| Testes de carga | Valida o comportamento sob alto tráfego | +| Migrar para MKS | Quando precisar de HA real: basta trocar o kubeconfig — os manifests YAML são idênticos | + +### Custo estimado na Magalu Cloud + +| Recurso | Especificação | Observação | +|---|---|---| +| VM K3s | BV2-2-40 (2 vCPU, 2 GB) | Cobrada por hora de uso | +| DBaaS PostgreSQL | Instância pequena | Cobrado por hora de uso | +| Container Registry | Por armazenamento | Baixo para imagens < 500 MB | + +Consulte os preços atualizados em: https://magalu.cloud/precos/