Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
295 changes: 295 additions & 0 deletions PASSO_A_PASSO.md

Large diffs are not rendered by default.

18 changes: 12 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ O fluxo separa duas responsabilidades:
1. o Terraform cria a rede, a instância EC2 e o acesso ao cluster;
2. o Argo CD acompanha a pasta [`apps/`](apps/) na branch `main` e reconcilia os workloads no namespace `acta-prod`.

Atualmente, o estado GitOps inclui `acta-pg-api`, `acta-mongo-api`, `acta-import-api` e o worker de importação. As imagens são obtidas do GitHub Container Registry com tags imutáveis baseadas no SHA de cada serviço.
O estado GitOps inclui AI, MCP, as APIs e o worker de importação. O deploy configura o AI para acessar o MCP em `https://mcp.<ip-com-hifens>.sslip.io/mcp`. As imagens e os segredos necessários devem estar disponíveis no GHCR e no Infisical.

## ✨ Capacidades

Expand Down Expand Up @@ -63,7 +63,7 @@ instance_type = "t3.medium"

O arquivo `terraform.tfvars`, estados, planos, credenciais AWS e chaves privadas são ignorados pelo Git. Nunca versione esses arquivos.

Os manifests `InfisicalSecret` contêm apenas referências. Os valores reais de banco, Firebase, Cloudinary, Redis e tokens devem permanecer no Infisical.
Os manifests `InfisicalSecret` contêm somente referências. Os valores reais de banco, Firebase, Cloudinary, Redis e tokens devem permanecer no Infisical. Antes de sincronizar AI e MCP, confirme que os caminhos planejados e os nomes referenciados existem no projeto Infisical autorizado. Não copie valores para o Git ou para a documentação.

## 🧪 Validação local

Expand All @@ -88,7 +88,7 @@ Esses comandos verificam formatação e configuração estática. Eles não conf
> [!CAUTION]
> O processo cria recursos cobráveis na AWS. Revise o `terraform plan`, a conta selecionada, a região e os custos antes de confirmar a aplicação.

Na raiz do repositório, execute:
O procedimento detalhado, incluindo pré-requisitos, verificações e diagnóstico, está em [`PASSO_A_PASSO.md`](PASSO_A_PASSO.md). Na raiz do repositório, execute:

```powershell
.\infra\aws\deploy.ps1
Expand All @@ -103,7 +103,7 @@ O script:
5. cria o Secret de autenticação do Infisical a partir de entradas interativas;
6. aplica [`argocd/prod.yaml`](argocd/prod.yaml) e ajusta os hosts `sslip.io` ao Elastic IP;
7. aguarda sincronização, workloads e certificados;
8. consulta os endpoints públicos e exibe o estado final.
8. consulta os endpoints públicos da PG API, Mongo API, Import API e a rota `/health` do MCP e exibe o endereço `/mcp` do MCP.

O kubeconfig obtido do servidor é salvo em `~/.kube/acta-aws.yaml`. A chave privada esperada pelo script fica em `.aws/labsuser.pem`; esse caminho é local e está ignorado pelo Git.

Expand Down Expand Up @@ -134,12 +134,14 @@ O Argo CD usa `prune` para remover recursos excluídos do estado desejado e `sel

| Componente | Porta | Verificação de disponibilidade |
| --- | ---: | --- |
| `acta-ai` | 8200 | `GET /health` (interno ao cluster; sem Ingress) |
| `acta-mcp` | 8000 | `GET /health` público; protocolo MCP em `/mcp` |
| `acta-pg-api` | 8080 | `GET /api/v1/health` |
| `acta-mongo-api` | 8081 | `GET /api/v1/health` |
| `acta-import-api` | 8000 | `GET /docs` |
| `acta-import-worker` | — | Processo RQ sem Service HTTP |

Cada workload usa imagem imutável do GHCR, requests e limits de CPU/memória. As APIs possuem probes de inicialização, prontidão e vida configuradas nos respectivos manifests.
Os manifests das APIs PG, Mongo e Import e do worker definem requests e limits de CPU/memória. AI e MCP têm Services internos e probes; as imagens e referências Infisical precisam estar disponíveis para os Deployments iniciarem corretamente. Durante a implantação, `infra/aws/deploy.ps1` deriva o host MCP do IP público do Terraform, configura `ACTA_MCP_URL` no Deployment do AI para `https://mcp.<ip-com-hifens>.sslip.io/mcp` e imprime a URL resultante. O cliente AI envia a chave Bearer configurada e o contexto de usuário/empresa esperado pelo MCP.

## 🔐 Segredos e acesso de rede

Expand Down Expand Up @@ -170,9 +172,12 @@ flowchart LR

K3S --> PG[acta-pg-api]
K3S --> MG[acta-mongo-api]
K3S --> AI[acta-ai]
AI --> |HTTPS /mcp| MCP[acta-mcp]
K3S --> IM[acta-import-api e worker]

NET[Internet] --> ING[Traefik e cert-manager]
ING --> MCP
ING --> PG
ING --> MG
ING --> IM
Expand All @@ -188,6 +193,7 @@ Terraform prepara a infraestrutura e o cluster. Ele não substitui o Argo CD: o
│ └── teste-infra.yml # CI de validação da infraestrutura
├── apps/
│ ├── config/ # referências de segredos no Infisical
│ ├── ai.yaml, mcp.yaml # Deployments e Services de AI/MCP
│ ├── *-api.yaml # Deployments e Services
│ ├── ingress.yaml # HTTPS, hosts e certificados
│ └── kustomization.yaml # agrega o estado de produção
Expand All @@ -207,4 +213,4 @@ Terraform prepara a infraestrutura e o cluster. Ele não substitui o Argo CD: o

- [Repositório](https://github.com/AppActa/acta-platform) · [Licença MIT](LICENSE) · `acta.institutojef@gmail.com`
- Contribuições: use *issues* e *pull requests*; há um [`PULL_REQUEST_TEMPLATE.md`](PULL_REQUEST_TEMPLATE.md).
- Autoria: Equipe ACTA.
- Autoria: Equipe ACTA.
90 changes: 90 additions & 0 deletions apps/ai.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
apiVersion: apps/v1
kind: Deployment

metadata:
name: acta-ai
annotations:
secrets.infisical.com/auto-reload: "true"
labels:
app.kubernetes.io/name: acta-ai
app.kubernetes.io/part-of: acta

spec:
replicas: 1
revisionHistoryLimit: 1

selector:
matchLabels:
app.kubernetes.io/name: acta-ai

template:
metadata:
labels:
app.kubernetes.io/name: acta-ai
app.kubernetes.io/part-of: acta

spec:
containers:
- name: acta-ai
image: ghcr.io/appacta/acta-ai:c308b670d003b36585f53eea084a4b228356aea5
imagePullPolicy: IfNotPresent

ports:
- name: http
containerPort: 8200
protocol: TCP

envFrom:
- secretRef:
name: acta-ai-env

env:
- name: PORT
value: "8200"

# deploy.ps1 substitui o template pela url do mcp
- name: ACTA_MCP_URL
value: https://mcp.0-0-0-0.sslip.io/mcp

startupProbe:
tcpSocket:
port: http
periodSeconds: 10
failureThreshold: 60

readinessProbe:
httpGet:
path: /health
port: http
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3

livenessProbe:
httpGet:
path: /health
port: http
periodSeconds: 20
timeoutSeconds: 5
failureThreshold: 3
---
apiVersion: v1
kind: Service

metadata:
name: acta-ai
labels:
app.kubernetes.io/name: acta-ai
app.kubernetes.io/part-of: acta

spec:
type: ClusterIP

selector:
app.kubernetes.io/name: acta-ai

ports:
- name: http
port: 8200
targetPort: http
protocol: TCP
36 changes: 36 additions & 0 deletions apps/config/ai-secrets.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
apiVersion: secrets.infisical.com/v1alpha1
kind: InfisicalSecret

metadata:
name: acta-ai-secrets

spec:
hostAPI: https://app.infisical.com/api
resyncInterval: 60

authentication:
universalAuth:
credentialsRef:
secretName: infisical-universal-auth
secretNamespace: acta-prod
secretsScope:
projectId: 051dcf5e-00ed-4d46-8b36-baad0a621f5d
envSlug: prod
secretsPath: /ai
recursive: false

managedKubeSecretReferences:
- secretName: acta-ai-env
secretNamespace: acta-prod
creationPolicy: Owner

template:
includeAllSecrets: false
data:
OPENAI_API_KEY: "{{ .OPENAI_API_KEY.Value }}"
JEV_API_KEY: "{{ .JEV_API_KEY.Value }}"
MONGODB_URI: "{{ .MONGODB_URI.Value }}"
GEMINI_API_KEY: "{{ .GEMINI_API_KEY.Value }}"
QDRANT_CLUSTER_ENDPOINT: "{{ .QDRANT_CLUSTER_ENDPOINT.Value }}"
QDRANT_API_KEY: "{{ .QDRANT_API_KEY.Value }}"
ACTA_MCP_API_KEY: "{{ .ACTA_MCP_API_KEY.Value }}"
1 change: 0 additions & 1 deletion apps/config/import-api-secrets.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ spec:
CLOUDINARY_API_KEY: "{{ .CLOUDINARY_API_KEY.Value }}"
CLOUDINARY_API_SECRET: "{{ .CLOUDINARY_API_SECRET.Value }}"
ACTA_PG_API_URL: "{{ .ACTA_PG_API_URL.Value }}"
ACTA_IA_TOKEN: "{{ .ACTA_IA_TOKEN.Value }}"
REDIS_HOST: "{{ .REDIS_HOST.Value }}"
REDIS_PORT: "{{ .REDIS_PORT.Value }}"
REDIS_DB: "{{ .REDIS_DB.Value }}"
Expand Down
38 changes: 38 additions & 0 deletions apps/config/mcp-secrets.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
apiVersion: secrets.infisical.com/v1alpha1
kind: InfisicalSecret

metadata:
name: acta-mcp-secrets

spec:
hostAPI: https://app.infisical.com/api
resyncInterval: 60

authentication:
universalAuth:
credentialsRef:
secretName: infisical-universal-auth
secretNamespace: acta-prod
secretsScope:
projectId: 051dcf5e-00ed-4d46-8b36-baad0a621f5d
envSlug: prod
secretsPath: /mcp
recursive: false

managedKubeSecretReferences:
- secretName: acta-mcp-env
secretNamespace: acta-prod
creationPolicy: Owner

template:
includeAllSecrets: false
data:
ACTA_MCP_API_KEY: "{{ .ACTA_MCP_API_KEY.Value }}"
DATABASE_URL: "{{ .DATABASE_URL.Value }}"
MONGODB_URI: "{{ .MONGODB_URI.Value }}"
GEMINI_API_KEY: "{{ .GEMINI_API_KEY.Value }}"
QDRANT_CLUSTER_ENDPOINT: "{{ .QDRANT_CLUSTER_ENDPOINT.Value }}"
QDRANT_API_KEY: "{{ .QDRANT_API_KEY.Value }}"
CLOUDINARY_CLOUD_NAME: "{{ .CLOUDINARY_CLOUD_NAME.Value }}"
CLOUDINARY_API_KEY: "{{ .CLOUDINARY_API_KEY.Value }}"
CLOUDINARY_API_SECRET: "{{ .CLOUDINARY_API_SECRET.Value }}"
4 changes: 3 additions & 1 deletion apps/config/pg-api-secrets.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ spec:
DB_PASSWORD: "{{ .DB_PASSWORD.Value }}"
FIREBASE_PROJECT_ID: "{{ .FIREBASE_PROJECT_ID.Value }}"
CORS_ALLOWED_ORIGINS: "{{ .CORS_ALLOWED_ORIGINS.Value }}"
BREVO_SENDER_EMAIL: "{{ .BREVO_SENDER_EMAIL.Value }}"
BREVO_API_KEY: "{{ .BREVO_API_KEY.Value }}"

- secretName: firebase-admin
secretNamespace: acta-prod
Expand All @@ -40,4 +42,4 @@ spec:
template:
includeAllSecrets: false
data:
service-account.json: "{{ .FIREBASE_SERVICE_ACCOUNT_JSON.Value }}"
service-account.json: "{{ .FIREBASE_SERVICE_ACCOUNT_JSON.Value }}"
26 changes: 25 additions & 1 deletion apps/ingress.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -82,4 +82,28 @@ spec:
tls:
- hosts:
- import-api.0-0-0-0.sslip.io
secretName: import-api-tls
secretName: import-api-tls
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: mcp
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
ingressClassName: traefik
rules:
- host: mcp.0-0-0-0.sslip.io
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: acta-mcp
port:
number: 8000
tls:
- hosts:
- mcp.0-0-0-0.sslip.io
secretName: mcp-tls
4 changes: 4 additions & 0 deletions apps/kustomization.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,14 @@ kind: Kustomization
namespace: acta-prod

resources:
- ai.yaml
- mcp.yaml
- pg-api.yaml
- mongo-api.yaml
- import-api.yaml
- ingress.yaml
- config/ai-secrets.yaml
- config/mcp-secrets.yaml
- config/pg-api-secrets.yaml
- config/mongo-api-secrets.yaml
- config/import-api-secrets.yaml
Loading
Loading