diff --git a/README.md b/README.md index 5dc4e58..14d0f93 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,57 @@ A RESTful API that manages the full lifecycle of service orders, customers, vehi --- +## Fase 2 + +Fase 2 expands Fase 1 with **Clean Architecture**, **automated email notifications**, **Kubernetes on AWS EKS**, **Terraform IaC**, and a **GitHub Actions CI/CD pipeline** — turning the original monolith into a production-ready, scalable system. + +### Architecture + +``` +GitHub Actions (CI/CD) + │ + ├─ coverage.yml ──→ unit tests · 80% coverage gate · GitHub Pages report + │ + └─ deploy.yml ──→ docker build · push GHCR · EF migrations · kubectl apply + │ + ▼ + AWS EKS Cluster (Terraform-provisioned VPC + EKS) + ┌─────────────────────────────────────────────┐ + │ Namespace: mechanics-software │ + │ │ + │ ┌─────────────────────┐ │ + │ │ API Deployment │◄── HPA │ + │ │ ASP.NET Core 8 │ (auto-scale) │ + │ │ N replicas │ │ + │ └──────────┬──────────┘ │ + │ │ ClusterIP │ + │ ▼ │ + │ ┌─────────────────────┐ │ + │ │ PostgreSQL 16 │◄── PVC │ + │ └─────────────────────┘ (persistent) │ + │ │ + │ LoadBalancer ──────────────────► Internet │ + └─────────────────────────────────────────────┘ +``` + +### Deploy flow + +``` +git push → main + │ + ├── coverage.yml → dotnet test → enforce 80% line coverage → publish HTML report + │ + └── deploy.yml → docker build → push to GHCR + │ + └─→ kubectl apply (initContainer runs EF migrations first) +``` + +### Demo video + +[Watch on YouTube](https://youtu.be/vqERT_zrLpo) + +--- + ## Getting Started ### Prerequisites diff --git a/infra/README.md b/infra/README.md index 7d995b4..5a84bd0 100644 --- a/infra/README.md +++ b/infra/README.md @@ -1,94 +1,218 @@ -# Infra — Terraform +# Infra — Terraform (AWS EKS) -Infrastructure as Code para o **Mechanics Software**, provisionando um cluster Kubernetes local (Kind) e os recursos de banco de dados PostgreSQL. +Infrastructure as Code para o **Mechanics Software**, provisionando um cluster Kubernetes na AWS (EKS) com VPC dedicada. + +## O que é criado + +| Recurso | Descrição | +|---------|-----------| +| VPC `10.0.0.0/16` | 3 subnets públicas + 3 privadas, NAT Gateway, DNS habilitado | +| EKS Cluster `mechanics-software` | Kubernetes 1.30, endpoint público | +| Node Group `default` | `t3.small`, 1–3 nós, desired 2 | +| Add-ons | `coredns`, `kube-proxy`, `vpc-cni`, `aws-ebs-csi-driver` | + +--- ## Pré-requisitos | Ferramenta | Versão mínima | Instalação | -|---|---|---| +|------------|--------------|------------| | Terraform | >= 1.7 | https://developer.hashicorp.com/terraform/install | -| Kind | >= 0.23 | `brew install kind` | +| AWS CLI | >= 2.0 | https://docs.aws.amazon.com/cli/latest/userguide/install-cliv2.html | | kubectl | >= 1.29 | `brew install kubectl` | -| Docker | >= 24 | https://docs.docker.com/get-docker/ | -## Recursos criados +--- + +## Configurar em uma nova conta AWS + +Siga este passo a passo sempre que precisar usar uma conta AWS diferente. + +### 1. Criar credenciais na conta AWS + +No console AWS da nova conta: + +1. Acesse **IAM → Users → Create user** +2. Nome: `mechanics-software-deploy` (ou qualquer nome) +3. Em **Permissions**, selecione **Attach policies directly** e adicione `AdministratorAccess` +4. Após criar, acesse o usuário → **Security credentials → Create access key** +5. Selecione **CLI** como use case +6. Anote o **Access Key ID** e **Secret Access Key** — você só vê a Secret uma vez + +### 2. Configurar o AWS CLI localmente + +```bash +aws configure +``` + +Preencha quando solicitado: + +``` +AWS Access Key ID: +AWS Secret Access Key: +Default region name: us-east-1 +Default output format: json +``` + +Verifique se está funcionando: -| Módulo | Recurso | Descrição | -|---|---|---| -| `kubernetes` | Kind Cluster | 1 control-plane + 2 workers | -| `database` | Namespace `mechanics-software` | Namespace dedicado no cluster | -| `database` | PVC `postgres-pvc` | Volume persistente de 1Gi (ReadWriteOnce) | -| `database` | Secret `mechanics-secrets` | Credenciais do banco e JWT secret | +```bash +aws sts get-caller-identity +``` -## Passo a passo +Saída esperada (com os dados da nova conta): +```json +{ + "UserId": "AIDA...", + "Account": "123456789012", + "Arn": "arn:aws:iam::123456789012:user/mechanics-software-deploy" +} +``` -### 1. Inicializar os providers +### 3. Inicializar o Terraform ```bash cd infra terraform init ``` -### 2. Visualizar o plano de execução +> O `terraform.tfstate` é ignorado pelo `.gitignore` — cada ambiente começa do zero, sem conflito com estado anterior. + +### 4. Revisar o plano ```bash -terraform plan \ - -var="db_password=postgres" \ - -var="jwt_secret=dev-secret-change-in-production-32chars" +terraform plan ``` -### 3. Aplicar a infraestrutura +Revise os recursos que serão criados (VPC, subnets, EKS cluster, node group). Deve mostrar **~54 resources to add**. + +### 5. Aplicar a infraestrutura ```bash -terraform apply -auto-approve \ - -var="db_password=postgres" \ - -var="jwt_secret=dev-secret-change-in-production-32chars" +terraform apply ``` -### 4. Configurar o kubeconfig +Digite `yes` quando solicitado. O processo leva **10–15 minutos**. + +Ao final, os outputs mostram: + +``` +cluster_name = "mechanics-software" +cluster_region = "us-east-1" +kubeconfig_command = "aws eks update-kubeconfig --name mechanics-software --region us-east-1" +``` + +### 6. Configurar o kubeconfig + +```bash +aws eks update-kubeconfig --name mechanics-software --region us-east-1 +``` + +Verificar que o cluster está saudável: ```bash -export KUBECONFIG=$(terraform output -raw kubeconfig_path) kubectl get nodes ``` Saída esperada: +``` +NAME STATUS ROLES AGE VERSION +ip-10-0-x-x.us-east-1.compute.internal Ready 2m v1.30.x +ip-10-0-x-x.us-east-1.compute.internal Ready 2m v1.30.x +``` + +### 7. Fazer deploy da aplicação +```bash +kubectl apply -f ../k8s/ ``` -NAME STATUS ROLES AGE VERSION -mechanics-software-control-plane Ready control-plane ... v1.x.x -mechanics-software-worker Ready ... v1.x.x -mechanics-software-worker2 Ready ... v1.x.x + +Aguardar os pods ficarem prontos: + +```bash +kubectl get pods -n mechanics-software --watch ``` -### 5. Verificar os recursos do banco +Saída esperada: +``` +NAME READY STATUS RESTARTS AGE +mechanics-api-xxxxxxxxx-xxxxx 1/1 Running 0 2m +postgres-xxxxxxxxx-xxxxx 1/1 Running 0 2m +``` + +Pegar o endpoint externo da API: + +```bash +kubectl get svc mechanics-api-service -n mechanics-software +``` + +O `EXTERNAL-IP` é a URL pública da API. + +--- + +## Configurar o pipeline CI/CD (GitHub Actions) + +Para que o pipeline faça deploy automático na nova conta, atualize os secrets do repositório. + +Acesse: **GitHub → Settings → Secrets and variables → Actions** + +Atualize os seguintes secrets: + +| Secret | Valor | +|--------|-------| +| `AWS_ACCESS_KEY_ID` | Access Key ID criado no passo 1 | +| `AWS_SECRET_ACCESS_KEY` | Secret Access Key criado no passo 1 | +| `AWS_REGION` | `us-east-1` (ou a região escolhida) | +| `KUBE_CONFIG` | Conteúdo do kubeconfig — veja abaixo | + +Para obter o `KUBE_CONFIG`: ```bash -kubectl get namespace mechanics-software -kubectl get pvc -n mechanics-software -kubectl get secret mechanics-secrets -n mechanics-software +cat ~/.kube/config | base64 ``` +Cole o resultado base64 no secret `KUBE_CONFIG`. + +--- + ## Variáveis | Variável | Obrigatória | Default | Descrição | -|---|---|---|---| -| `db_password` | Sim | — | Senha do PostgreSQL | -| `jwt_secret` | Sim | — | Chave JWT (mínimo 32 caracteres) | -| `cluster_name` | Não | `mechanics-software` | Nome do cluster Kind | -| `db_name` | Não | `mechanics_software` | Nome do banco de dados | -| `db_user` | Não | `postgres` | Usuário do banco | -| `smtp_host` | Não | `""` | Host SMTP para notificações | -| `smtp_port` | Não | `587` | Porta SMTP | -| `smtp_user` | Não | `""` | Usuário SMTP | -| `smtp_pass` | Não | `""` | Senha SMTP | +|----------|-------------|---------|-----------| +| `cluster_name` | Não | `mechanics-software` | Nome do cluster EKS | +| `aws_region` | Não | `us-east-1` | Região AWS | + +Para sobrescrever: + +```bash +terraform apply -var="cluster_name=meu-cluster" -var="aws_region=sa-east-1" +``` + +--- ## Destruir o ambiente +**Importante:** destrua o cluster após gravar o vídeo para evitar cobranças na conta AWS. + ```bash -terraform destroy -auto-approve \ - -var="db_password=postgres" \ - -var="jwt_secret=dev-secret-change-in-production-32chars" +cd infra +terraform destroy ``` -Isso remove o cluster Kind e todos os recursos provisionados. +Digite `yes` quando solicitado. O processo leva **5–10 minutos**. + +Verifique no console AWS que todos os recursos foram removidos (VPC, EKS, EC2). + +--- + +## Estrutura dos arquivos + +``` +infra/ + main.tf # módulo kubernetes (chama modules/kubernetes) + variables.tf # cluster_name, aws_region + outputs.tf # cluster_name, cluster_region, kubeconfig_command + providers.tf # AWS provider + modules/ + kubernetes/ + main.tf # VPC + EKS cluster + node group +```