commit 94fb5e68c66accceda16f83d27b2a96bb60ee143 Author: hoshikawa2 Date: Thu May 7 13:02:13 2026 -0300 first commit diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..7bc07ec --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,10 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Environment-dependent path to Maven home directory +/mavenHomeManager.xml +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/deploy_langfuse_oci.iml b/.idea/deploy_langfuse_oci.iml new file mode 100644 index 0000000..d6ebd48 --- /dev/null +++ b/.idea/deploy_langfuse_oci.iml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..89ee753 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..a7e2e9f --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..35eb1dd --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.oca/custom_code_review_guidelines.txt b/.oca/custom_code_review_guidelines.txt new file mode 100644 index 0000000..a0a3b63 --- /dev/null +++ b/.oca/custom_code_review_guidelines.txt @@ -0,0 +1,24 @@ +# Sample guideline, please follow similar structure for guideline with code samples +# 1. Suggest using streams instead of simple loops for better readability. +# +# *Comment: +# Category: Minor +# Issue: Use streams instead of a loop for better readability. +# Code Block: +# +# ```java +# // Calculate squares of numbers +# List squares = new ArrayList<>(); +# for (int number : numbers) { +# squares.add(number * number); +# } +# ``` +# Recommendation: +# +# ```java +# // Calculate squares of numbers +# List squares = Arrays.stream(numbers) +# .map(n -> n * n) // Map each number to its square +# .toList(); +# ``` +# diff --git a/README.md b/README.md new file mode 100644 index 0000000..f9285ea --- /dev/null +++ b/README.md @@ -0,0 +1,1382 @@ +# 🚀 Tutorial Completo — Deploy do Langfuse no Oracle Kubernetes Engine (OKE) + +## 📌 Introdução + +Este tutorial apresenta um processo completo para implantação do Langfuse no Oracle Cloud Infrastructure (OCI), utilizando: + +- Oracle Kubernetes Engine (OKE) +- OCI Container Registry (OCIR) +- OCI Vault +- OCI Object Storage +- PostgreSQL +- Redis +- ClickHouse + +Além do deployment em si, este tutorial cobre: +- arquitetura do Langfuse +- conceitos fundamentais +- purpose de cada componente +- gerenciamento de imagens Docker +- secrets centralizados no OCI Vault +- preparação de ambiente +- deployment automatizado via Kubernetes YAML + +## 🧠 O que é o Langfuse + +Langfuse é uma plataforma de observabilidade para aplicações de IA generativa. + +Ele permite: +- rastrear chamadas de LLM +- armazenar traces +- monitorar prompts +- analisar custos +- acompanhar latência +- versionar prompts +- inspecionar tool calls +- avaliar qualidade de respostas + +## 🏗️ Arquitetura Geral + +Componentes: +- PostgreSQL +- Redis +- ClickHouse +- Langfuse API +- Langfuse Worker +- OCI Vault +- OCI Object Storage +- OCIR +- OKE + +## 🔐 OCI Vault + +Os scripts create_secrets.sh e update_secret.sh criam e atualizam secrets no OCI Vault. + +Antes de iniciar esta etapa, crie um VAULT e UMA ENCRYPTION KEY. Busque pelos OCID destes 2 componentes para setar dentro de seu script create_secrets.sh e update_secret.sh + +A ENCRYPTION_KEY precisa possuir: +- 64 caracteres +- hexadecimal +- 256 bits + +Exemplo: + +```bash +ENCRYPTION_KEY=$(openssl rand -hex 32) +``` + +## 📦 OCI Registry (OCIR) + +O script mirror_images.sh copia imagens públicas para o registry privado OCI. + +Exemplo: + +```bash +docker pull langfuse/langfuse:3.1.0 + +docker tag langfuse/langfuse:3.1.0 iad.ocir.io/namespace/langfuse:3.1.0 + +docker push iad.ocir.io/namespace/langfuse:3.1.0 +``` + +O mesmo ocorre para: +- langfuse-worker +- redis +- postgres +- clickhouse + +## ☸️ Kubernetes Deployment + +O arquivo final.yaml contém: +- StorageClass +- PVCs +- Deployments +- StatefulSets +- Services +- HPA + +## PostgreSQL + +Responsável por: +- usuários +- traces +- prompts +- configurações + +Readiness probe: + +```yaml +pg_isready -U langfuse +``` + +## Redis + +Responsável por: +- filas +- cache +- jobs + +## ClickHouse + +Responsável por: +- analytics +- métricas +- observabilidade + +## Langfuse API + +Responsável por: +- UI +- API +- autenticação + +## Langfuse Worker + +Responsável por: +- filas +- processamento assíncrono +- exports + +## initContainers + +Utilizados para aguardar: +- PostgreSQL +- Redis +- ClickHouse + +antes da inicialização dos pods. + +Exemplo: + +```yaml +until nc -z langfuse-db 5432 +``` + +## 🌐 OCI Load Balancer + +Service utilizado: + +```yaml +kind: Service +type: LoadBalancer +``` + +Healthcheck: + +```yaml +oci.oraclecloud.com/healthcheck-path: "/api/public/health" +``` + +## ☁️ OCI Object Storage + +Utilizado para: +- eventos +- batches +- exports + +Auth utilizada: + +```yaml +LANGFUSE_OCI_AUTH_TYPE=instance_principal +``` + +## ⚙️ Principais Variáveis + +| Variável | Função | +|---|---| +| DATABASE_URL | PostgreSQL | +| REDIS_AUTH | Redis | +| CLICKHOUSE_PASSWORD | ClickHouse | +| NEXTAUTH_SECRET | Auth | +| ENCRYPTION_KEY | Criptografia | +| SALT | Salt | +| NEXTAUTH_URL | URL pública | + +# 📦 Fluxo Completo — Imagens, OCI Vault e Deployment Final + +## 🎯 Objetivo + +Antes do deployment do Langfuse no Oracle Kubernetes Engine (OKE), existem algumas etapas preparatórias fundamentais. + +Essas etapas possuem dois objetivos principais: + +1. Centralizar imagens Docker em um registry privado OCI (OCIR) +2. Centralizar secrets no OCI Vault para que o deployment Kubernetes possa consumir valores seguros dinamicamente + +O fluxo completo funciona assim: + +```text +Docker Hub + ↓ +Mirror para OCI Registry (OCIR) + ↓ +Criação de Secrets no OCI Vault + ↓ +Captura dos OCIDs dos Secrets + ↓ +Leitura dinâmica via OCI CLI + ↓ +envsubst + ↓ +Geração do final.yaml + ↓ +kubectl apply +``` + +>**Nota:** Antes de iniciar o processo de deployment, certifque-se de que exista um dynamic group e as policies estejam de acordo na OCI. + +Dynamic Group oke-langfuse: +ALL {instance.compartment.id = 'ocid1.compartment.oc1..aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'} +- Todos os recursos deste compartment estarão habilitados para as policies abaixo + + +Algumas policies importantes: +- Allow dynamic-group oke-langfuse to manage objects in compartment kubernetes +- Allow dynamic-group oke-langfuse to read buckets in compartment kubernetes +- Allow dynamic-group oke-langfuse to manage volume-family in compartment kubernetes + +--- + +# 🟢 Etapa 1 — Publicar Imagens no OCI Registry (OCIR) + +## 📌 Objetivo + +O Kubernetes do OKE precisa baixar imagens Docker. + +Embora seja possível utilizar imagens públicas diretamente do Docker Hub, em ambientes corporativos normalmente utilizamos um registry privado OCI por motivos de: + +* segurança +* governança +* performance +* disponibilidade +* controle de versões +* evitar rate limit do Docker Hub + +--- + +# 📦 Imagens utilizadas + +O deployment utiliza: + +| Imagem | Função | +| ---------------------------- | --------- | +| langfuse/langfuse | API/UI | +| langfuse/langfuse-worker | Worker | +| postgres | Banco | +| redis | Cache | +| clickhouse/clickhouse-server | Analytics | + +--- + +# 🔄 Processo de Mirror + +O script: + +```text +mirror_images.sh +``` + +executa: + +1. Pull da imagem pública +2. Tag para o OCIR +3. Push para o registry OCI + +--- + +# Exemplo + +## Pull + +```bash +docker pull langfuse/langfuse:3.1.0 +``` + +## Tag + +```bash +docker tag langfuse/langfuse:3.1.0 iad.ocir.io/namespace/langfuse:3.1.0 +``` + +## Push + +```bash +docker push iad.ocir.io/namespace/langfuse:3.1.0 +``` + +--- + +# 📌 Resultado Final + +Após isso, o Kubernetes utilizará: + +```text +iad.ocir.io/SEU_NAMESPACE/langfuse:3.1.0 +``` + +em vez da imagem pública. + +--- + +# 🔐 Etapa 2 — Criar Secrets no OCI Vault + +## 📌 Objetivo + +O deployment possui: + +* senhas +* tokens +* chaves de criptografia + +Esses valores NÃO devem ficar hardcoded no YAML. + +Por isso usamos: + +* OCI Vault +* OCI KMS + +--- + +# 🧠 Secrets utilizados + +| Secret | Finalidade | +| ------------------- | -------------------- | +| DB_PASSWORD | PostgreSQL | +| REDIS_AUTH | Redis | +| CLICKHOUSE_PASSWORD | ClickHouse | +| NEXTAUTH_SECRET | Auth Langfuse | +| ENCRYPTION_KEY | Criptografia interna | +| SALT | Salt interno | + +--- + +# 🔧 Script utilizado + +Arquivo: + +```text +create_secrets.sh +``` + +--- + +# 📌 Como funciona + +O script: + +1. Gera senhas +2. Gera ENCRYPTION_KEY +3. Codifica em Base64 +4. Cria os secrets no OCI Vault + +--- + +# 🔐 ENCRYPTION_KEY + +A variável: + +```bash +ENCRYPTION_KEY=$(openssl rand -hex 32) +``` + +gera: + +* 32 bytes +* 64 chars hex +* 256 bits + +Formato obrigatório do Langfuse. + +--- + +# 📤 Resultado do Script + +Ao final, o OCI Vault retorna: + +```bash +export OCI_SECRET_DB=ocid1.vaultsecret... +``` + +Esses valores são os: + +* OCIDs dos secrets + +--- + +# 🧠 O que é o OCID do Secret? + +Cada secret criado no OCI Vault recebe um identificador único: + +```text +ocid1.vaultsecret.oc1.... +``` + +Esse OCID é utilizado depois para: + +* localizar +* ler +* atualizar + +o conteúdo do secret. + +--- + +# 🔥 Etapa 3 — Capturar os OCIDs + +## 📌 Objetivo + +Os scripts seguintes precisam saber: + +* qual secret acessar +* onde buscar a senha + +Por isso os OCIDs precisam ser armazenados. + +--- + +# 📌 Exemplo + +```bash +export OCI_SECRET_DB="ocid1.vaultsecret.oc1..." +``` + +--- + +# 📌 Utilização + +Esses OCIDs serão utilizados no: + +```text +set_var.sh +``` + +--- + +# ⚙️ Etapa 4 — Carregar Secrets Dinamicamente + +## 📌 Objetivo + +Antes de gerar o YAML final: + +* precisamos buscar os valores reais no OCI Vault + +--- + +# 🔧 Função utilizada + +```bash +get_secret() { + + oci secrets secret-bundle get \ + --secret-id "$secret_ocid" \ + --query 'data."secret-bundle-content".content' \ + --raw-output | base64 --decode +} +``` + +--- + +# 📌 O que ocorre aqui + +O script: + +1. Chama OCI CLI +2. Busca o secret +3. Recebe Base64 +4. Decodifica +5. Exporta para variável de ambiente + +--- + +# 📌 Exemplo + +```bash +export DB_PASSWORD=$(get_secret "$OCI_SECRET_DB") +``` + +--- + +# 📌 Resultado + +Agora temos: + +```bash +export DB_PASSWORD="senha_real" +``` + +em memória no shell. + +--- + +# 🧩 Etapa 5 — Construção do final.yaml + +## 📌 Objetivo + +O arquivo: + +```text +langfuse_dest.yaml +``` + +possui placeholders: + +```yaml +${DB_PASSWORD} +``` +--- + +# ⚙️ Variáveis de Ambiente — Langfuse no OKE + +## 📌 Introdução + +O deployment do Langfuse depende de diversas variáveis de ambiente responsáveis por configurar: + +* banco de dados +* cache +* analytics +* autenticação +* object storage +* OCI +* imagens +* Kubernetes +* URLs +* segurança + +Essas variáveis são carregadas principalmente pelo: + +```text id="vars1" +set_var.sh +``` + +e posteriormente injetadas no: + +```text id="vars2" +final.yaml +``` + +através do: + +```bash id="vars3" +envsubst +``` + +--- + +# 🧩 Variáveis de Configuração OCI + +--- + +## OCI_PROFILE + +```bash id="vars4" +export OCI_PROFILE=DEFAULT +``` + +### Objetivo + +Define qual profile do OCI CLI será utilizado. + +### Origem + +Arquivo: + +```text id="vars5" +~/.oci/config +``` + +### Exemplo + +```ini id="vars6" +[DEFAULT] +user=... +fingerprint=... +tenancy=... +region=... +``` + +--- + +## OCI_REGION + +```bash id="vars7" +export OCI_REGION=us-ashburn-1 +``` + +### Objetivo + +Define a região OCI utilizada por: + +* Vault +* Object Storage +* Registry +* APIs OCI + +### Exemplos + +| Região | Valor | +| --------- | ------------- | +| Ashburn | us-ashburn-1 | +| São Paulo | sa-saopaulo-1 | + +--- + +## OCI_NAMESPACE + +```bash id="vars8" +export OCI_NAMESPACE="idavixsf5sbx" +``` + +### Objetivo + +Namespace do OCI Object Storage e OCIR. + +Utilizado em: + +* Registry +* Bucket endpoints + +--- + +# 📦 Variáveis do OCI Registry (OCIR) + +--- + +## REGION + +```bash id="vars9" +export REGION="iad" +``` + +### Objetivo + +Região curta utilizada pelo OCIR. + +### Exemplos + +| Região OCI | Short Name | +| ------------- | ---------- | +| us-ashburn-1 | iad | +| sa-saopaulo-1 | gru | + +--- + +## TENANCY_NAMESPACE + +```bash id="vars10" +export TENANCY_NAMESPACE=${OCI_NAMESPACE} +``` + +### Objetivo + +Namespace do tenancy no OCIR. + +--- + +## REGISTRY + +```bash id="vars11" +export REGISTRY="${REGION}.ocir.io/${TENANCY_NAMESPACE}" +``` + +### Resultado + +```text id="vars12" +iad.ocir.io/idavixsf5sbx +``` + +### Objetivo + +Registry privado OCI utilizado pelo Kubernetes. + +--- + +# 🧠 Variáveis do Deployment + +--- + +## APP_NAME + +```bash id="vars13" +export APP_NAME="langfuse" +``` + +### Objetivo + +Prefixo dos recursos Kubernetes. + +### Exemplos + +Gera: + +* langfuse-db +* langfuse-redis +* langfuse-clickhouse + +--- + +## K8S_NAMESPACE + +```bash id="vars14" +export K8S_NAMESPACE="langfuse" +``` + +### Objetivo + +Namespace Kubernetes onde os recursos serão criados. + +--- + +## IMAGE_REPOSITORY + +```bash id="vars15" +export IMAGE_REPOSITORY="${REGISTRY}" +``` + +### Objetivo + +Define o registry utilizado pelas imagens. + +### Resultado + +```text id="vars16" +iad.ocir.io/idavixsf5sbx +``` + +--- + +## IMAGE_TAG + +```bash id="vars17" +export IMAGE_TAG="3.1.0" +``` + +### Objetivo + +Tag da imagem principal Langfuse. + +--- + +## CLICKHOUSE_TAG + +```bash id="vars18" +export CLICKHOUSE_TAG="23.8" +``` + +### Objetivo + +Versão do ClickHouse. + +--- + +## REDIS_TAG + +```bash id="vars19" +export REDIS_TAG="7.2" +``` + +### Objetivo + +Versão Redis. + +--- + +## POSTGRES_TAG + +```bash id="vars20" +export POSTGRES_TAG="15" +``` + +### Objetivo + +Versão PostgreSQL. + +--- + +# 🌐 Variáveis de URL + +--- + +## NEXTAUTH_URL + +```bash id="vars21" +export NEXTAUTH_URL="https://langfuse.seudominio.com" +``` + +### Objetivo + +URL pública utilizada pelo frontend do Langfuse. + +### Impacto + +Utilizada para: + +* login +* redirects +* cookies +* OAuth + +--- + +# 🔐 Variáveis de Secrets OCI Vault + +--- + +## OCI_SECRET_DB + +```bash id="vars22" +export OCI_SECRET_DB="ocid1.vaultsecret..." +``` + +### Objetivo + +OCID do secret contendo a senha PostgreSQL. + +--- + +## OCI_SECRET_REDIS + +```bash id="vars23" +export OCI_SECRET_REDIS="ocid1.vaultsecret..." +``` + +### Objetivo + +OCID do secret Redis. + +--- + +## OCI_SECRET_CLICKHOUSE + +```bash id="vars24" +export OCI_SECRET_CLICKHOUSE="ocid1.vaultsecret..." +``` + +### Objetivo + +OCID da senha ClickHouse. + +--- + +## OCI_SECRET_NEXTAUTH + +```bash id="vars25" +export OCI_SECRET_NEXTAUTH="ocid1.vaultsecret..." +``` + +### Objetivo + +Secret de autenticação do Langfuse. + +--- + +## OCI_SECRET_ENCRYPTION + +```bash id="vars26" +export OCI_SECRET_ENCRYPTION="ocid1.vaultsecret..." +``` + +### Objetivo + +Secret utilizado para criptografia interna. + +--- + +## OCI_SECRET_SALT + +```bash id="vars27" +export OCI_SECRET_SALT="ocid1.vaultsecret..." +``` + +### Objetivo + +Salt interno do Langfuse. + +--- + +# 🔥 Variáveis Carregadas Dinamicamente + +Estas variáveis são carregadas via: + +```bash id="vars28" +get_secret() +``` + +--- + +## DB_PASSWORD + +```bash id="vars29" +export DB_PASSWORD=$(get_secret "$OCI_SECRET_DB") +``` + +### Objetivo + +Senha PostgreSQL. + +--- + +## DATABASE_URL + +```bash id="vars30" +export DATABASE_URL="postgresql://langfuse:${DB_PASSWORD}@${APP_NAME}-db:5432/langfuse" +``` + +### Objetivo + +Connection string PostgreSQL. + +### Estrutura + +```text id="vars31" +postgresql://USUARIO:SENHA@HOST:PORTA/BANCO +``` + +--- + +## REDIS_AUTH + +```bash id="vars32" +export REDIS_AUTH=$(get_secret "$OCI_SECRET_REDIS") +``` + +### Objetivo + +Senha Redis. + +--- + +## CLICKHOUSE_PASSWORD + +```bash id="vars33" +export CLICKHOUSE_PASSWORD=$(get_secret "$OCI_SECRET_CLICKHOUSE") +``` + +### Objetivo + +Senha ClickHouse. + +--- + +## NEXTAUTH_SECRET + +```bash id="vars34" +export NEXTAUTH_SECRET=$(get_secret "$OCI_SECRET_NEXTAUTH") +``` + +### Objetivo + +Secret JWT/Auth do Langfuse. + +--- + +## ENCRYPTION_KEY + +```bash id="vars35" +export ENCRYPTION_KEY=$(get_secret "$OCI_SECRET_ENCRYPTION") +``` + +### Objetivo + +Criptografia interna. + +### Requisitos + +* 64 chars +* hexadecimal +* 256 bits + +### Validação + +```bash id="vars36" +openssl rand -hex 32 +``` + +--- + +## SALT + +```bash id="vars37" +export SALT=$(get_secret "$OCI_SECRET_SALT") +``` + +### Objetivo + +Salt interno utilizado pelo Langfuse. + +--- + +# ⚡ Redis + +--- + +## REDIS_HOST + +```bash id="vars38" +export REDIS_HOST="${APP_NAME}-redis" +``` + +### Objetivo + +Hostname Redis interno Kubernetes. + +--- + +## REDIS_PORT + +```bash id="vars39" +export REDIS_PORT="6379" +``` + +### Objetivo + +Porta Redis. + +--- + +# 📊 ClickHouse + +--- + +## CLICKHOUSE_URL + +```bash id="vars40" +export CLICKHOUSE_URL="http://${APP_NAME}-clickhouse:8123" +``` + +### Objetivo + +Endpoint HTTP ClickHouse. + +--- + +## CLICKHOUSE_USER + +```bash id="vars41" +export CLICKHOUSE_USER="default" +``` + +### Objetivo + +Usuário ClickHouse. + +--- + +## CLICKHOUSE_MIGRATION_URL + +```bash id="vars42" +export CLICKHOUSE_MIGRATION_URL="clickhouse://${APP_NAME}-clickhouse:9000" +``` + +### Objetivo + +Endpoint nativo ClickHouse utilizado pelas migrations. + +--- + +## CLICKHOUSE_CLUSTER_ENABLED + +```bash id="vars43" +export CLICKHOUSE_CLUSTER_ENABLED="false" +``` + +### Objetivo + +Define se ClickHouse opera em cluster distribuído. + +--- + +# ☁️ OCI Object Storage + +--- + +## LANGFUSE_S3_EVENT_UPLOAD_BUCKET + +```bash id="vars44" +export LANGFUSE_S3_EVENT_UPLOAD_BUCKET="langfuse-events" +``` + +### Objetivo + +Bucket de eventos. + +--- + +## LANGFUSE_S3_EVENT_UPLOAD_REGION + +```bash id="vars45" +export LANGFUSE_S3_EVENT_UPLOAD_REGION="${OCI_REGION}" +``` + +### Objetivo + +Região do bucket. + +--- + +## LANGFUSE_S3_EVENT_UPLOAD_ENDPOINT + +```bash id="vars46" +export LANGFUSE_S3_EVENT_UPLOAD_ENDPOINT="https://${OCI_NAMESPACE}.compat.objectstorage.${OCI_REGION}.oraclecloud.com" +``` + +### Objetivo + +Endpoint S3-compatible OCI. + +--- + +## LANGFUSE_USE_OCI_NATIVE_OBJECT_STORAGE + +```bash id="vars47" +export LANGFUSE_USE_OCI_NATIVE_OBJECT_STORAGE="true" +``` + +### Objetivo + +Ativa integração OCI nativa. + +--- + +## LANGFUSE_OCI_AUTH_TYPE + +```bash id="vars48" +export LANGFUSE_OCI_AUTH_TYPE="instance_principal" +``` + +### Objetivo + +Utiliza Instance Principal em vez de Access Key. + +### Benefício + +Não precisamos: + +* access key +* secret key + +--- + +# 📌 Resumo Geral + +## Principais categorias + +| Categoria | Variáveis | +| -------------- | ------------------------------- | +| OCI | OCI_REGION, OCI_PROFILE | +| Registry | REGISTRY, IMAGE_REPOSITORY | +| Kubernetes | APP_NAME, K8S_NAMESPACE | +| PostgreSQL | DATABASE_URL | +| Redis | REDIS_AUTH | +| ClickHouse | CLICKHOUSE_URL | +| Security | NEXTAUTH_SECRET, ENCRYPTION_KEY | +| OCI Vault | OCI_SECRET_* | +| Object Storage | LANGFUSE_S3_* | + +--- + +# 🚀 Fluxo Completo + +```text id="vars49" +OCI Vault + ↓ +get_secret() + ↓ +export VARIAVEIS + ↓ +envsubst + ↓ +final.yaml + ↓ +kubectl apply +``` + +--- + +# ✅ Resultado Final + +Ao final: + +* todas variáveis ficam centralizadas +* secrets permanecem seguros +* deployment torna-se parametrizável +* ambiente fica reproduzível +* stack torna-se adequada para CI/CD e produção + + +--- + +# 🔧 Substituição dinâmica + +O script utiliza: + +```bash +envsubst < langfuse_dest.yaml > final.yaml +``` + +--- + +# 📌 O que acontece + +O Linux substitui: + +```yaml +${DB_PASSWORD} +``` + +por: + +```yaml +langfuse123 +``` + +--- + +# 📌 Resultado + +É gerado: + +```text +final.yaml +``` + +com: + +* todas variáveis preenchidas +* senhas reais +* URLs reais +* tags reais +* namespace real + +--- + +# ☸️ Etapa 6 — Deployment Kubernetes + +## 📌 Objetivo + +Aplicar: + +* Deployments +* Services +* StatefulSets +* PVCs +* HPAs + +no OKE. + +>**Nota:** É importante frisar que em regime produtivo, as etapas de gerar imagens, setar variaveis e executar a atualização no YAML de deployment final não são etapas necessárias. Pressupõe-se que as variáveis e as imagens já estejam preparadas para a execução de uma esteira produtiva. Estas etapas anteriores apenas servem para este tutorial como ilustração de como os recursos de OCI se comportam. + +--- + +# 🔧 Comando + +```bash +kubectl apply -f final.yaml +``` + +>**Nota:** O arquivo de deployment final.yaml publica a solução em um endpoint com DNS: https://langfuse.seu. Lembre-se de alterar + +--- + +# 📌 Resultado + +O Kubernetes: + +* cria pods +* cria services +* cria volumes +* cria load balancer +* sobe Langfuse + +--- + +# 🔒 Benefícios dessa Arquitetura + +## Segurança + +Nenhuma senha: + +* hardcoded +* commitada +* salva no YAML final do template + +--- + +## Governança + +Secrets centralizados no OCI Vault. + +--- + +## Escalabilidade + +O mesmo template pode ser usado para: + +* DEV +* QA +* PROD + +mudando apenas: + +* variáveis +* secrets +* tags + +--- + +## Reutilização + +O deployment torna-se: + +* parametrizável +* automatizável +* CI/CD friendly + +--- + +# 🚀 Fluxo Final Consolidado + +```text +1. mirror_images.sh + ↓ +2. create_secrets.sh + ↓ +3. capturar OCIDs + ↓ +4. set_var.sh + ↓ +5. envsubst + ↓ +6. final.yaml + ↓ +7. kubectl apply +``` + +--- + +# Testando a Solução + +Abra o browser para validar a UI do Langfuse. O Load-Balancer foi criado para uma subnet privada, nada impede de se criar em uma subnet pública. +Para poder acessar talvez seja necessário executar o ssh em túnel como o exemplo: + + ssh -i /mnt/d/Dropbox/ORACLE/sshkeybundle/Privatekey.pem opc@129.158.211.144 -L 8087:10.0.20.44:80 + + +E depois acessar via browser com: + + http://localhost:8087 + +![img.png](img.png) + +--- + +# ✅ Resultado Final + +Ao final: + +* imagens privadas OCI +* secrets centralizados +* deployment automatizado +* stack observável +* Langfuse operacional no OKE +* arquitetura segura e escalável + diff --git a/create_secrets.sh b/create_secrets.sh new file mode 100644 index 0000000..1ca22f7 --- /dev/null +++ b/create_secrets.sh @@ -0,0 +1,103 @@ +#!/bin/bash +set -ex + +echo "🔐 Criando secrets no OCI Vault..." + +# ========================= +# ⚙️ CONFIG +# ========================= + +export COMPARTMENT_ID="ocid1.compartment.oc1..aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + +export VAULT_ID="ocid1.vault.oc1.iad.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + +export KEY_ID="ocid1.key.oc1.iad.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + +export PREFIX="langfuse" + +# ========================= +# 🔑 SENHAS +# ========================= + +# Senha comum simples +if [ -z "$COMMON_SECRET" ]; then + echo "🔑 Gerando COMMON_SECRET..." + COMMON_SECRET=$(openssl rand -base64 32 | tr -d '\n') +fi + +# ENCRYPTION_KEY precisa: +# - 64 chars +# - hexadecimal +# - 256 bits +if [ -z "$ENCRYPTION_KEY" ]; then + echo "🔐 Gerando ENCRYPTION_KEY..." + ENCRYPTION_KEY=$(openssl rand -hex 32) +fi + +echo "👉 COMMON_SECRET: $COMMON_SECRET" +echo "👉 ENCRYPTION_KEY: $ENCRYPTION_KEY" + +# ========================= +# 🔧 FUNÇÃO +# ========================= + +create_secret() { + + local name=$1 + local value=$2 + + echo "📦 Criando secret: $name" + + local base64_value + base64_value=$(printf "%s" "$value" | base64 | tr -d '\n') + + oci vault secret create-base64 \ + --compartment-id "$COMPARTMENT_ID" \ + --vault-id "$VAULT_ID" \ + --key-id "$KEY_ID" \ + --secret-name "$name" \ + --secret-content-content "$base64_value" \ + --query 'data.id' \ + --raw-output +} + +# ========================= +# 🔥 CRIAR SECRETS +# ========================= + +DB_SECRET=$(create_secret "${PREFIX}-db-password" "$COMMON_SECRET") + +REDIS_SECRET=$(create_secret "${PREFIX}-redis" "$COMMON_SECRET") + +CLICKHOUSE_SECRET=$(create_secret "${PREFIX}-clickhouse" "$COMMON_SECRET") + +NEXTAUTH_SECRET=$(create_secret "${PREFIX}-nextauth" "$COMMON_SECRET") + +# 👇 SOMENTE ESTA KEY TEM FORMATO ESPECIAL +ENCRYPTION_SECRET=$(create_secret "${PREFIX}-encryption" "$ENCRYPTION_KEY") + +SALT_SECRET=$(create_secret "${PREFIX}-salt" "$COMMON_SECRET") + +OCI_ACCESS_SECRET=$(create_secret "${PREFIX}-oci-access" "$COMMON_SECRET") + +OCI_SECRET_SECRET=$(create_secret "${PREFIX}-oci-secret" "$COMMON_SECRET") + +# ========================= +# 📤 OUTPUT +# ========================= + +echo "" +echo "✅ Secrets criados com sucesso!" +echo "" + +echo "export OCI_SECRET_DB=$DB_SECRET" +echo "export OCI_SECRET_REDIS=$REDIS_SECRET" +echo "export OCI_SECRET_CLICKHOUSE=$CLICKHOUSE_SECRET" +echo "export OCI_SECRET_NEXTAUTH=$NEXTAUTH_SECRET" +echo "export OCI_SECRET_ENCRYPTION=$ENCRYPTION_SECRET" +echo "export OCI_SECRET_SALT=$SALT_SECRET" +echo "export OCI_SECRET_OCI_ACCESS=$OCI_ACCESS_SECRET" +echo "export OCI_SECRET_OCI_SECRET=$OCI_SECRET_SECRET" + +echo "" +echo "💡 Salve isso no seu pipeline ou env.sh" \ No newline at end of file diff --git a/final.yaml b/final.yaml new file mode 100644 index 0000000..dbcb09d --- /dev/null +++ b/final.yaml @@ -0,0 +1,591 @@ +apiVersion: storage.k8s.io/v1 +kind: StorageClass +metadata: + name: oci-bv-high-performance +provisioner: blockvolume.csi.oraclecloud.com +parameters: + vpusPerGB: "20" + attachment-type: "paravirtualized" +volumeBindingMode: WaitForFirstConsumer +allowVolumeExpansion: true +reclaimPolicy: Delete +--- +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: langfuse-db-pvc + namespace: langfuse +spec: + accessModes: ["ReadWriteOnce"] + storageClassName: oci-bv-high-performance + resources: + requests: + storage: 50Gi +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: langfuse-db + namespace: langfuse +spec: + replicas: 1 + strategy: + type: Recreate + selector: + matchLabels: + app: langfuse-db + template: + metadata: + labels: + app: langfuse-db + spec: + imagePullSecrets: + - name: ocirsecret + containers: + - name: langfuse-db + image: iad.ocir.io/xxxxxxxxxx/postgres:15 + ports: + - containerPort: 5432 + env: + - name: POSTGRES_USER + value: "langfuse" + - name: POSTGRES_PASSWORD + value: "langfuse123" + - name: POSTGRES_DB + value: "langfuse" + - name: PGDATA + value: "/var/lib/postgresql/data/pgdata" + resources: + requests: + cpu: "50m" + memory: "2Gi" + limits: + cpu: "512m" + memory: "3Gi" + volumeMounts: + - name: db-data + mountPath: /var/lib/postgresql/data + volumes: + - name: db-data + persistentVolumeClaim: + claimName: langfuse-db-pvc +--- +apiVersion: v1 +kind: Service +metadata: + name: langfuse-db + namespace: langfuse +spec: + type: NodePort + selector: + app: langfuse-db + ports: + - protocol: TCP + port: 5432 + targetPort: 5432 + +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: langfuse-redis + namespace: langfuse +spec: + replicas: 1 + selector: + matchLabels: + app: langfuse-redis + template: + metadata: + labels: + app: langfuse-redis + spec: + imagePullSecrets: + - name: ocirsecret + containers: + - name: redis + image: iad.ocir.io/xxxxxxxxxxx/redis:7.2 + command: ["redis-server", "--requirepass", "redis123"] + ports: + - containerPort: 6379 + resources: + requests: + cpu: "50m" + memory: "2Gi" + limits: + cpu: "512m" + memory: "3Gi" +--- +apiVersion: v1 +kind: Service +metadata: + name: langfuse-redis + namespace: langfuse +spec: + type: NodePort + selector: + app: langfuse-redis + ports: + - protocol: TCP + port: 6379 + targetPort: 6379 +--- +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: langfuse-clickhouse + namespace: langfuse +spec: + serviceName: langfuse-clickhouse + replicas: 1 + selector: + matchLabels: + app: langfuse-clickhouse + template: + metadata: + labels: + app: langfuse-clickhouse + spec: + imagePullSecrets: + - name: ocirsecret + containers: + - name: clickhouse + image: iad.ocir.io/xxxxxxxxxxxx/clickhouse:23.8 + ports: + - containerPort: 8123 + - containerPort: 9000 + resources: + requests: + cpu: "2" + memory: "8Gi" + limits: + cpu: "4" + memory: "16Gi" + volumeMounts: + - name: data + mountPath: /var/lib/clickhouse + env: + - name: CLICKHOUSE_DB + value: "default" + + - name: CLICKHOUSE_USER + value: "default" + + - name: CLICKHOUSE_PASSWORD + value: "clickhouse123" + + - name: CLICKHOUSE_DEFAULT_ACCESS_MANAGEMENT + value: "1" + volumeClaimTemplates: + - metadata: + name: data + spec: + accessModes: ["ReadWriteOnce"] + storageClassName: oci-bv-high-performance + resources: + requests: + storage: 200Gi +--- +apiVersion: v1 +kind: Service +metadata: + name: langfuse-clickhouse + namespace: langfuse +spec: + selector: + app: langfuse-clickhouse + ports: + - name: http + port: 8123 + - name: native + port: 9000 +--- +# ===== LANGFUSE APPLICATION ===== + +apiVersion: apps/v1 +kind: Deployment +metadata: + name: langfuse + namespace: langfuse +spec: + replicas: 1 + selector: + matchLabels: + app: langfuse + template: + metadata: + labels: + app: langfuse + spec: + imagePullSecrets: + - name: ocirsecret + + initContainers: + + - name: wait-for-postgres + image: busybox + + command: + - sh + - -c + - | + until nc -z langfuse-db 5432; do + echo "⏳ Waiting for PostgreSQL..." + sleep 2 + done + + - name: wait-for-redis + image: busybox + + command: + - sh + - -c + - | + until nc -z langfuse-redis 6379; do + echo "⏳ Waiting for Redis..." + sleep 2 + done + + - name: wait-for-clickhouse + image: busybox + + command: + - sh + - -c + - | + until nc -z langfuse-clickhouse 9000; do + echo "⏳ Waiting for ClickHouse..." + sleep 2 + done + containers: + - name: langfuse + image: iad.ocir.io/xxxxxxxxxxxx/langfuse:3.1.0 + ports: + - containerPort: 3000 + env: + - name: DATABASE_URL + value: "postgresql://langfuse:langfuse123@langfuse-db:5432/langfuse" + - name: NEXTAUTH_SECRET + value: "nextauth-secret-123" + - name: SALT + value: "salt-secret-123" + - name: ENCRYPTION_KEY + value: "ea58fe36914e38ec5d52657c928d3e8350ff1513e1930e0fd306dce6422bf87d" + - name: NEXTAUTH_URL + value: https://langfuse.seudominio.com + - name: TELEMETRY_ENABLED + value: "false" + - name: CLICKHOUSE_URL + value: "http://langfuse-clickhouse:8123" + - name: CLICKHOUSE_USER + value: "default" + - name: CLICKHOUSE_PASSWORD + value: "clickhouse123" + - name: CLICKHOUSE_CLUSTER_ENABLED + value: "false" + - name: CLICKHOUSE_MIGRATION_URL + value: "clickhouse://langfuse-clickhouse:9000" + - name: REDIS_HOST + value: "langfuse-redis" + - name: REDIS_PORT + value: "6379" + - name: REDIS_AUTH + value: "redis123" + # ===== OCI OBJECT STORAGE (EVENTS) ===== + - name: LANGFUSE_USE_OCI_NATIVE_OBJECT_STORAGE + value: "true" + - name: LANGFUSE_OCI_AUTH_TYPE + value: "instance_principal" + - name: LANGFUSE_S3_EVENT_UPLOAD_BUCKET + value: "langfuse-events" + + - name: LANGFUSE_S3_EVENT_UPLOAD_REGION + value: "us-ashburn-1" + + - name: LANGFUSE_S3_EVENT_UPLOAD_ENDPOINT + value: "https://xxxxxxxxxxx.compat.objectstorage.us-ashburn-1.oraclecloud.com" + +# - name: LANGFUSE_S3_EVENT_UPLOAD_ACCESS_KEY_ID +# valueFrom: +# secretKeyRef: +# name: langfuse-secret +# key: oci-access-key +# +# - name: LANGFUSE_S3_EVENT_UPLOAD_SECRET_ACCESS_KEY +# valueFrom: +# secretKeyRef: +# name: langfuse-secret +# key: oci-secret-key + + - name: LANGFUSE_S3_EVENT_UPLOAD_FORCE_PATH_STYLE + value: "true" + + # ===== EXPORT ===== + - name: LANGFUSE_S3_BATCH_EXPORT_ENABLED + value: "true" + + - name: LANGFUSE_S3_BATCH_EXPORT_BUCKET + value: "langfuse-exports" + + - name: LANGFUSE_S3_BATCH_EXPORT_REGION + value: "us-ashburn-1" + + - name: LANGFUSE_S3_BATCH_EXPORT_ENDPOINT + value: "https://xxxxxxxxxxxx.compat.objectstorage.us-ashburn-1.oraclecloud.com" + +# - name: LANGFUSE_S3_BATCH_EXPORT_ACCESS_KEY_ID +# valueFrom: +# secretKeyRef: +# name: langfuse-secret +# key: oci-access-key +# +# - name: LANGFUSE_S3_BATCH_EXPORT_SECRET_ACCESS_KEY +# valueFrom: +# secretKeyRef: +# name: langfuse-secret +# key: oci-secret-key + + - name: LANGFUSE_S3_BATCH_EXPORT_FORCE_PATH_STYLE + value: "true" + resources: + requests: + cpu: "50m" + memory: "2Gi" + limits: + cpu: "512m" + memory: "3Gi" + livenessProbe: + httpGet: + path: /api/public/health + port: 3000 + initialDelaySeconds: 30 + periodSeconds: 15 + readinessProbe: + httpGet: + path: /api/public/health + port: 3000 + initialDelaySeconds: 15 + periodSeconds: 10 + +--- +# ===== LANGFUSE WORKER ===== + +apiVersion: apps/v1 +kind: Deployment +metadata: + name: langfuse-worker + namespace: langfuse +spec: + replicas: 1 + selector: + matchLabels: + app: langfuse-worker + template: + metadata: + labels: + app: langfuse-worker + spec: + imagePullSecrets: + - name: ocirsecret + + initContainers: + + - name: wait-for-postgres + image: busybox + + command: + - sh + - -c + - | + until nc -z langfuse-db 5432; do + echo "⏳ Waiting for PostgreSQL..." + sleep 2 + done + + - name: wait-for-redis + image: busybox + + command: + - sh + - -c + - | + until nc -z langfuse-redis 6379; do + echo "⏳ Waiting for Redis..." + sleep 2 + done + + - name: wait-for-clickhouse + image: busybox + + command: + - sh + - -c + - | + until nc -z langfuse-clickhouse 9000; do + echo "⏳ Waiting for ClickHouse..." + sleep 2 + done + containers: + - name: worker + image: iad.ocir.io/xxxxxxxxxxxx/langfuse-worker:3.1.0 + env: + - name: DATABASE_URL + value: "postgresql://langfuse:langfuse123@langfuse-db:5432/langfuse" + - name: ENCRYPTION_KEY + value: "ea58fe36914e38ec5d52657c928d3e8350ff1513e1930e0fd306dce6422bf87d" + - name: CLICKHOUSE_URL + value: "http://langfuse-clickhouse:8123" + - name: CLICKHOUSE_USER + value: "default" + - name: CLICKHOUSE_PASSWORD + value: "clickhouse123" + - name: CLICKHOUSE_CLUSTER_ENABLED + value: "false" + - name: CLICKHOUSE_MIGRATION_URL + value: "clickhouse://langfuse-clickhouse:9000" + - name: REDIS_HOST + value: "langfuse-redis" + - name: REDIS_PORT + value: "6379" + - name: REDIS_AUTH + value: "redis123" + # ===== OCI OBJECT STORAGE (EVENTS) ===== + - name: LANGFUSE_USE_OCI_NATIVE_OBJECT_STORAGE + value: "true" + - name: LANGFUSE_OCI_AUTH_TYPE + value: "instance_principal" + - name: LANGFUSE_S3_EVENT_UPLOAD_BUCKET + value: "langfuse-events" + + - name: LANGFUSE_S3_EVENT_UPLOAD_REGION + value: "us-ashburn-1" + + - name: LANGFUSE_S3_EVENT_UPLOAD_ENDPOINT + value: "https://xxxxxxxxx.compat.objectstorage.us-ashburn-1.oraclecloud.com" + +# - name: LANGFUSE_S3_EVENT_UPLOAD_ACCESS_KEY_ID +# valueFrom: +# secretKeyRef: +# name: langfuse-secret +# key: oci-access-key +# +# - name: LANGFUSE_S3_EVENT_UPLOAD_SECRET_ACCESS_KEY +# valueFrom: +# secretKeyRef: +# name: langfuse-secret +# key: oci-secret-key + + - name: LANGFUSE_S3_EVENT_UPLOAD_FORCE_PATH_STYLE + value: "true" + + # ===== EXPORT ===== + - name: LANGFUSE_S3_BATCH_EXPORT_ENABLED + value: "true" + + - name: LANGFUSE_S3_BATCH_EXPORT_BUCKET + value: "langfuse-exports" + + - name: LANGFUSE_S3_BATCH_EXPORT_REGION + value: "us-ashburn-1" + + - name: LANGFUSE_S3_BATCH_EXPORT_ENDPOINT + value: "https://xxxxxxxxxxx.compat.objectstorage.us-ashburn-1.oraclecloud.com" + +# - name: LANGFUSE_S3_BATCH_EXPORT_ACCESS_KEY_ID +# valueFrom: +# secretKeyRef: +# name: langfuse-secret +# key: oci-access-key +# +# - name: LANGFUSE_S3_BATCH_EXPORT_SECRET_ACCESS_KEY +# valueFrom: +# secretKeyRef: +# name: langfuse-secret +# key: oci-secret-key + + - name: LANGFUSE_S3_BATCH_EXPORT_FORCE_PATH_STYLE + value: "true" + resources: + requests: + cpu: "50m" + memory: "2Gi" + limits: + cpu: "512m" + memory: "3Gi" +--- +# ===== LANGFUSE SERVICE ===== + +apiVersion: v1 +kind: Service +metadata: + name: langfuse-web + namespace: langfuse + annotations: + service.beta.kubernetes.io/oci-load-balancer-internal: "true" + oci.oraclecloud.com/healthcheck-path: "/api/public/health" + oci.oraclecloud.com/healthcheck-port: "3000" +spec: + type: LoadBalancer + selector: + app: langfuse + ports: + - protocol: TCP + port: 80 + targetPort: 3000 +--- +# ===== LANGFUSE HPA - HORIZONTAL POD AUTOSCALER ===== + +apiVersion: autoscaling/v2 +kind: HorizontalPodAutoscaler +metadata: + name: langfuse-hpa +spec: + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: langfuse + minReplicas: 2 + maxReplicas: 10 + metrics: + - type: Resource + resource: + name: cpu + target: + type: Utilization + averageUtilization: 70 +--- +# ===== WORKER - AUTOSCALER ===== +apiVersion: autoscaling/v2 +kind: HorizontalPodAutoscaler +metadata: + name: langfuse-worker-hpa +spec: + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: langfuse-worker + minReplicas: 2 + maxReplicas: 10 + metrics: + - type: Resource + resource: + name: cpu + target: + type: Utilization + averageUtilization: 70 +--- +apiVersion: v1 +kind: Service +metadata: + name: langfuse-lb + namespace: langfuse + annotations: + service.beta.kubernetes.io/oci-load-balancer-shape: "flexible" + oci.oraclecloud.com/healthcheck-path: "/api/public/health" +spec: + type: LoadBalancer + selector: + app: langfuse + ports: + - port: 80 + targetPort: 3000 \ No newline at end of file diff --git a/img.png b/img.png new file mode 100644 index 0000000..6bb69d5 Binary files /dev/null and b/img.png differ diff --git a/langfuse_dest.yaml b/langfuse_dest.yaml new file mode 100644 index 0000000..540d3c4 --- /dev/null +++ b/langfuse_dest.yaml @@ -0,0 +1,591 @@ +apiVersion: storage.k8s.io/v1 +kind: StorageClass +metadata: + name: oci-bv-high-performance +provisioner: blockvolume.csi.oraclecloud.com +parameters: + vpusPerGB: "20" + attachment-type: "paravirtualized" +volumeBindingMode: WaitForFirstConsumer +allowVolumeExpansion: true +reclaimPolicy: Delete +--- +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: ${APP_NAME}-db-pvc + namespace: ${K8S_NAMESPACE} +spec: + accessModes: ["ReadWriteOnce"] + storageClassName: oci-bv-high-performance + resources: + requests: + storage: 50Gi +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: ${APP_NAME}-db + namespace: ${K8S_NAMESPACE} +spec: + replicas: 1 + strategy: + type: Recreate + selector: + matchLabels: + app: ${APP_NAME}-db + template: + metadata: + labels: + app: ${APP_NAME}-db + spec: + imagePullSecrets: + - name: ocirsecret + containers: + - name: ${APP_NAME}-db + image: ${IMAGE_REPOSITORY}/postgres:${POSTGRES_TAG} + ports: + - containerPort: 5432 + env: + - name: POSTGRES_USER + value: "langfuse" + - name: POSTGRES_PASSWORD + value: "${DB_PASSWORD}" + - name: POSTGRES_DB + value: "langfuse" + - name: PGDATA + value: "/var/lib/postgresql/data/pgdata" + resources: + requests: + cpu: "50m" + memory: "2Gi" + limits: + cpu: "512m" + memory: "3Gi" + volumeMounts: + - name: db-data + mountPath: /var/lib/postgresql/data + volumes: + - name: db-data + persistentVolumeClaim: + claimName: ${APP_NAME}-db-pvc +--- +apiVersion: v1 +kind: Service +metadata: + name: ${APP_NAME}-db + namespace: ${K8S_NAMESPACE} +spec: + type: NodePort + selector: + app: ${APP_NAME}-db + ports: + - protocol: TCP + port: 5432 + targetPort: 5432 + +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: ${APP_NAME}-redis + namespace: ${K8S_NAMESPACE} +spec: + replicas: 1 + selector: + matchLabels: + app: ${APP_NAME}-redis + template: + metadata: + labels: + app: ${APP_NAME}-redis + spec: + imagePullSecrets: + - name: ocirsecret + containers: + - name: redis + image: ${IMAGE_REPOSITORY}/redis:${REDIS_TAG} + command: ["redis-server", "--requirepass", "${REDIS_AUTH}"] + ports: + - containerPort: 6379 + resources: + requests: + cpu: "50m" + memory: "2Gi" + limits: + cpu: "512m" + memory: "3Gi" +--- +apiVersion: v1 +kind: Service +metadata: + name: ${APP_NAME}-redis + namespace: ${K8S_NAMESPACE} +spec: + type: NodePort + selector: + app: ${APP_NAME}-redis + ports: + - protocol: TCP + port: 6379 + targetPort: 6379 +--- +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: ${APP_NAME}-clickhouse + namespace: ${K8S_NAMESPACE} +spec: + serviceName: ${APP_NAME}-clickhouse + replicas: 1 + selector: + matchLabels: + app: ${APP_NAME}-clickhouse + template: + metadata: + labels: + app: ${APP_NAME}-clickhouse + spec: + imagePullSecrets: + - name: ocirsecret + containers: + - name: clickhouse + image: ${IMAGE_REPOSITORY}/clickhouse:${CLICKHOUSE_TAG} + ports: + - containerPort: 8123 + - containerPort: 9000 + resources: + requests: + cpu: "2" + memory: "8Gi" + limits: + cpu: "4" + memory: "16Gi" + volumeMounts: + - name: data + mountPath: /var/lib/clickhouse + env: + - name: CLICKHOUSE_DB + value: "default" + + - name: CLICKHOUSE_USER + value: "default" + + - name: CLICKHOUSE_PASSWORD + value: "${CLICKHOUSE_PASSWORD}" + + - name: CLICKHOUSE_DEFAULT_ACCESS_MANAGEMENT + value: "1" + volumeClaimTemplates: + - metadata: + name: data + spec: + accessModes: ["ReadWriteOnce"] + storageClassName: oci-bv-high-performance + resources: + requests: + storage: 200Gi +--- +apiVersion: v1 +kind: Service +metadata: + name: ${APP_NAME}-clickhouse + namespace: ${K8S_NAMESPACE} +spec: + selector: + app: ${APP_NAME}-clickhouse + ports: + - name: http + port: 8123 + - name: native + port: 9000 +--- +# ===== LANGFUSE APPLICATION ===== + +apiVersion: apps/v1 +kind: Deployment +metadata: + name: ${APP_NAME} + namespace: ${K8S_NAMESPACE} +spec: + replicas: 1 + selector: + matchLabels: + app: ${APP_NAME} + template: + metadata: + labels: + app: ${APP_NAME} + spec: + imagePullSecrets: + - name: ocirsecret + + initContainers: + + - name: wait-for-postgres + image: busybox + + command: + - sh + - -c + - | + until nc -z ${APP_NAME}-db 5432; do + echo "⏳ Waiting for PostgreSQL..." + sleep 2 + done + + - name: wait-for-redis + image: busybox + + command: + - sh + - -c + - | + until nc -z ${APP_NAME}-redis 6379; do + echo "⏳ Waiting for Redis..." + sleep 2 + done + + - name: wait-for-clickhouse + image: busybox + + command: + - sh + - -c + - | + until nc -z ${APP_NAME}-clickhouse 9000; do + echo "⏳ Waiting for ClickHouse..." + sleep 2 + done + containers: + - name: ${APP_NAME} + image: ${IMAGE_REPOSITORY}/langfuse:${IMAGE_TAG} + ports: + - containerPort: 3000 + env: + - name: DATABASE_URL + value: "${DATABASE_URL}" + - name: NEXTAUTH_SECRET + value: "${NEXTAUTH_SECRET}" + - name: SALT + value: "${SALT}" + - name: ENCRYPTION_KEY + value: "${ENCRYPTION_KEY}" + - name: NEXTAUTH_URL + value: ${NEXTAUTH_URL} + - name: TELEMETRY_ENABLED + value: "false" + - name: CLICKHOUSE_URL + value: "http://${APP_NAME}-clickhouse:8123" + - name: CLICKHOUSE_USER + value: "default" + - name: CLICKHOUSE_PASSWORD + value: "${CLICKHOUSE_PASSWORD}" + - name: CLICKHOUSE_CLUSTER_ENABLED + value: "false" + - name: CLICKHOUSE_MIGRATION_URL + value: "clickhouse://${APP_NAME}-clickhouse:9000" + - name: REDIS_HOST + value: "${APP_NAME}-redis" + - name: REDIS_PORT + value: "6379" + - name: REDIS_AUTH + value: "${REDIS_AUTH}" + # ===== OCI OBJECT STORAGE (EVENTS) ===== + - name: LANGFUSE_USE_OCI_NATIVE_OBJECT_STORAGE + value: "true" + - name: LANGFUSE_OCI_AUTH_TYPE + value: "instance_principal" + - name: LANGFUSE_S3_EVENT_UPLOAD_BUCKET + value: "langfuse-events" + + - name: LANGFUSE_S3_EVENT_UPLOAD_REGION + value: "${OCI_REGION}" + + - name: LANGFUSE_S3_EVENT_UPLOAD_ENDPOINT + value: "https://${OCI_NAMESPACE}.compat.objectstorage.${OCI_REGION}.oraclecloud.com" + +# - name: LANGFUSE_S3_EVENT_UPLOAD_ACCESS_KEY_ID +# valueFrom: +# secretKeyRef: +# name: langfuse-secret +# key: oci-access-key +# +# - name: LANGFUSE_S3_EVENT_UPLOAD_SECRET_ACCESS_KEY +# valueFrom: +# secretKeyRef: +# name: langfuse-secret +# key: oci-secret-key + + - name: LANGFUSE_S3_EVENT_UPLOAD_FORCE_PATH_STYLE + value: "true" + + # ===== EXPORT ===== + - name: LANGFUSE_S3_BATCH_EXPORT_ENABLED + value: "true" + + - name: LANGFUSE_S3_BATCH_EXPORT_BUCKET + value: "langfuse-exports" + + - name: LANGFUSE_S3_BATCH_EXPORT_REGION + value: "${OCI_REGION}" + + - name: LANGFUSE_S3_BATCH_EXPORT_ENDPOINT + value: "https://${OCI_NAMESPACE}.compat.objectstorage.${OCI_REGION}.oraclecloud.com" + +# - name: LANGFUSE_S3_BATCH_EXPORT_ACCESS_KEY_ID +# valueFrom: +# secretKeyRef: +# name: langfuse-secret +# key: oci-access-key +# +# - name: LANGFUSE_S3_BATCH_EXPORT_SECRET_ACCESS_KEY +# valueFrom: +# secretKeyRef: +# name: langfuse-secret +# key: oci-secret-key + + - name: LANGFUSE_S3_BATCH_EXPORT_FORCE_PATH_STYLE + value: "true" + resources: + requests: + cpu: "50m" + memory: "2Gi" + limits: + cpu: "512m" + memory: "3Gi" + livenessProbe: + httpGet: + path: /api/public/health + port: 3000 + initialDelaySeconds: 30 + periodSeconds: 15 + readinessProbe: + httpGet: + path: /api/public/health + port: 3000 + initialDelaySeconds: 15 + periodSeconds: 10 + +--- +# ===== LANGFUSE WORKER ===== + +apiVersion: apps/v1 +kind: Deployment +metadata: + name: ${APP_NAME}-worker + namespace: ${K8S_NAMESPACE} +spec: + replicas: 1 + selector: + matchLabels: + app: ${APP_NAME}-worker + template: + metadata: + labels: + app: ${APP_NAME}-worker + spec: + imagePullSecrets: + - name: ocirsecret + + initContainers: + + - name: wait-for-postgres + image: busybox + + command: + - sh + - -c + - | + until nc -z ${APP_NAME}-db 5432; do + echo "⏳ Waiting for PostgreSQL..." + sleep 2 + done + + - name: wait-for-redis + image: busybox + + command: + - sh + - -c + - | + until nc -z ${APP_NAME}-redis 6379; do + echo "⏳ Waiting for Redis..." + sleep 2 + done + + - name: wait-for-clickhouse + image: busybox + + command: + - sh + - -c + - | + until nc -z ${APP_NAME}-clickhouse 9000; do + echo "⏳ Waiting for ClickHouse..." + sleep 2 + done + containers: + - name: worker + image: ${IMAGE_REPOSITORY}/langfuse-worker:${IMAGE_TAG} + env: + - name: DATABASE_URL + value: "${DATABASE_URL}" + - name: ENCRYPTION_KEY + value: "${ENCRYPTION_KEY}" + - name: CLICKHOUSE_URL + value: "http://${APP_NAME}-clickhouse:8123" + - name: CLICKHOUSE_USER + value: "default" + - name: CLICKHOUSE_PASSWORD + value: "${CLICKHOUSE_PASSWORD}" + - name: CLICKHOUSE_CLUSTER_ENABLED + value: "false" + - name: CLICKHOUSE_MIGRATION_URL + value: "clickhouse://${APP_NAME}-clickhouse:9000" + - name: REDIS_HOST + value: "${APP_NAME}-redis" + - name: REDIS_PORT + value: "6379" + - name: REDIS_AUTH + value: "${REDIS_AUTH}" + # ===== OCI OBJECT STORAGE (EVENTS) ===== + - name: LANGFUSE_USE_OCI_NATIVE_OBJECT_STORAGE + value: "true" + - name: LANGFUSE_OCI_AUTH_TYPE + value: "instance_principal" + - name: LANGFUSE_S3_EVENT_UPLOAD_BUCKET + value: "langfuse-events" + + - name: LANGFUSE_S3_EVENT_UPLOAD_REGION + value: "${OCI_REGION}" + + - name: LANGFUSE_S3_EVENT_UPLOAD_ENDPOINT + value: "https://${OCI_NAMESPACE}.compat.objectstorage.${OCI_REGION}.oraclecloud.com" + +# - name: LANGFUSE_S3_EVENT_UPLOAD_ACCESS_KEY_ID +# valueFrom: +# secretKeyRef: +# name: langfuse-secret +# key: oci-access-key +# +# - name: LANGFUSE_S3_EVENT_UPLOAD_SECRET_ACCESS_KEY +# valueFrom: +# secretKeyRef: +# name: langfuse-secret +# key: oci-secret-key + + - name: LANGFUSE_S3_EVENT_UPLOAD_FORCE_PATH_STYLE + value: "true" + + # ===== EXPORT ===== + - name: LANGFUSE_S3_BATCH_EXPORT_ENABLED + value: "true" + + - name: LANGFUSE_S3_BATCH_EXPORT_BUCKET + value: "langfuse-exports" + + - name: LANGFUSE_S3_BATCH_EXPORT_REGION + value: "${OCI_REGION}" + + - name: LANGFUSE_S3_BATCH_EXPORT_ENDPOINT + value: "https://${OCI_NAMESPACE}.compat.objectstorage.${OCI_REGION}.oraclecloud.com" + +# - name: LANGFUSE_S3_BATCH_EXPORT_ACCESS_KEY_ID +# valueFrom: +# secretKeyRef: +# name: langfuse-secret +# key: oci-access-key +# +# - name: LANGFUSE_S3_BATCH_EXPORT_SECRET_ACCESS_KEY +# valueFrom: +# secretKeyRef: +# name: langfuse-secret +# key: oci-secret-key + + - name: LANGFUSE_S3_BATCH_EXPORT_FORCE_PATH_STYLE + value: "true" + resources: + requests: + cpu: "50m" + memory: "2Gi" + limits: + cpu: "512m" + memory: "3Gi" +--- +# ===== LANGFUSE SERVICE ===== + +apiVersion: v1 +kind: Service +metadata: + name: langfuse-web + namespace: ${K8S_NAMESPACE} + annotations: + service.beta.kubernetes.io/oci-load-balancer-internal: "true" + oci.oraclecloud.com/healthcheck-path: "/api/public/health" + oci.oraclecloud.com/healthcheck-port: "3000" +spec: + type: LoadBalancer + selector: + app: ${APP_NAME} + ports: + - protocol: TCP + port: 80 + targetPort: 3000 +--- +# ===== LANGFUSE HPA - HORIZONTAL POD AUTOSCALER ===== + +apiVersion: autoscaling/v2 +kind: HorizontalPodAutoscaler +metadata: + name: ${APP_NAME}-hpa +spec: + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: ${APP_NAME} + minReplicas: 2 + maxReplicas: 10 + metrics: + - type: Resource + resource: + name: cpu + target: + type: Utilization + averageUtilization: 70 +--- +# ===== WORKER - AUTOSCALER ===== +apiVersion: autoscaling/v2 +kind: HorizontalPodAutoscaler +metadata: + name: langfuse-worker-hpa +spec: + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: ${APP_NAME}-worker + minReplicas: 2 + maxReplicas: 10 + metrics: + - type: Resource + resource: + name: cpu + target: + type: Utilization + averageUtilization: 70 +--- +apiVersion: v1 +kind: Service +metadata: + name: ${APP_NAME}-lb + namespace: ${K8S_NAMESPACE} + annotations: + service.beta.kubernetes.io/oci-load-balancer-shape: "flexible" + oci.oraclecloud.com/healthcheck-path: "/api/public/health" +spec: + type: LoadBalancer + selector: + app: ${APP_NAME} + ports: + - port: 80 + targetPort: 3000 \ No newline at end of file diff --git a/mirror_images.sh b/mirror_images.sh new file mode 100644 index 0000000..9b9b4fd --- /dev/null +++ b/mirror_images.sh @@ -0,0 +1,81 @@ +#!/bin/bash +set -e + +# ========================= + +# ⚙️ CONFIG + +# ========================= + +export REGION="iad" +export TENANCY_NAMESPACE="aaaaaaaaa" +export REGISTRY="${REGION}.ocir.io/${TENANCY_NAMESPACE}" + +# Tags fixas (produção) + +export LANGFUSE_TAG="3.1.0" +export CLICKHOUSE_TAG="23.8" +export REDIS_TAG="7.2" +export POSTGRES_TAG="15" + +echo "🔐 Login no OCI Registry..." +docker login ${REGION}.ocir.io + +# ========================= + +# 🟢 LANGFUSE (API) + +# ========================= + +echo "📦 Langfuse..." +docker pull langfuse/langfuse:${LANGFUSE_TAG} +docker tag langfuse/langfuse:${LANGFUSE_TAG} ${REGISTRY}/langfuse:${LANGFUSE_TAG} +docker push ${REGISTRY}/langfuse:${LANGFUSE_TAG} + +# ========================= +# 🟢 LANGFUSE WORKER +# ========================= + +echo "📦 Langfuse Worker..." + +docker pull langfuse/langfuse-worker:${LANGFUSE_TAG} + +docker tag langfuse/langfuse-worker:${LANGFUSE_TAG} \ + ${REGISTRY}/langfuse-worker:${LANGFUSE_TAG} + +docker push ${REGISTRY}/langfuse-worker:${LANGFUSE_TAG} + +# ========================= + +# 🟣 CLICKHOUSE + +# ========================= + +echo "📦 ClickHouse..." +docker pull clickhouse/clickhouse-server:${CLICKHOUSE_TAG} +docker tag clickhouse/clickhouse-server:${CLICKHOUSE_TAG} ${REGISTRY}/clickhouse:${CLICKHOUSE_TAG} +docker push ${REGISTRY}/clickhouse:${CLICKHOUSE_TAG} + +# ========================= + +# 🔴 REDIS + +# ========================= + +echo "📦 Redis..." +docker pull redis:${REDIS_TAG} +docker tag redis:${REDIS_TAG} ${REGISTRY}/redis:${REDIS_TAG} +docker push ${REGISTRY}/redis:${REDIS_TAG} + +# ========================= + +# 🟡 POSTGRES (OPCIONAL) + +# ========================= + +echo "📦 Postgres..." +docker pull postgres:${POSTGRES_TAG} +docker tag postgres:${POSTGRES_TAG} ${REGISTRY}/postgres:${POSTGRES_TAG} +docker push ${REGISTRY}/postgres:${POSTGRES_TAG} + +echo "✅ Todas as imagens foram transferidas com sucesso!" diff --git a/set_var.sh b/set_var.sh new file mode 100644 index 0000000..a6872ae --- /dev/null +++ b/set_var.sh @@ -0,0 +1,236 @@ +#!/bin/bash +set -ex + +echo "========================================" +echo "🚀 INICIANDO DEPLOY LANGFUSE" +echo "========================================" + +# ========================= + +# 🔐 CONFIG SECRETS (OCIDs) + +# ========================= + +echo "" +echo "🔐 Etapa 1: Configurando OCIDs dos secrets..." + +export OCI_SECRET_OCI_SECRET="ocid1.vaultsecret.oc1.iad.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +export OCI_SECRET_OCI_ACCESS="ocid1.vaultsecret.oc1.iad.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + +export OCI_SECRET_SALT="ocid1.vaultsecret.oc1.iad.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +export OCI_SECRET_ENCRYPTION="ocid1.vaultsecret.oc1.iad.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +export OCI_SECRET_NEXTAUTH="ocid1.vaultsecret.oc1.iad.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + +export OCI_SECRET_CLICKHOUSE="ocid1.vaultsecret.oc1.iad.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +export OCI_SECRET_REDIS="ocid1.vaultsecret.oc1.iad.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +export OCI_SECRET_DB="ocid1.vaultsecret.oc1.iad.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + +export OCI_NAMESPACE="xxxxxxxxxxx" + +echo "✅ OCIDs carregados" + +# ========================= + +# ⚙️ CONFIG OCI + +# ========================= + +echo "" +echo "⚙️ Etapa 2: Configuração OCI..." + +export OCI_PROFILE=DEFAULT +export OCI_REGION=us-ashburn-1 + +echo "✔️ Profile: $OCI_PROFILE" +echo "✔️ Region: $OCI_REGION" + +# ========================= + +# 📦 REGISTRY + +# ========================= + +echo "" +echo "📦 Etapa 3: Configurando registry..." + +export REGION="iad" +export TENANCY_NAMESPACE=${OCI_NAMESPACE} +export REGISTRY="${REGION}.ocir.io/${TENANCY_NAMESPACE}" + +echo "✔️ Registry: $REGISTRY" + +# ========================= + +# 🧩 DEPLOY CONFIG + +# ========================= + +echo "" +echo "🧩 Etapa 4: Configuração do deploy..." + +export APP_NAME="langfuse" +export K8S_NAMESPACE="langfuse" + +export IMAGE_REPOSITORY="${REGISTRY}" +export IMAGE_TAG="3.1.0" + +export CLICKHOUSE_TAG="23.8" +export REDIS_TAG="7.2" +export POSTGRES_TAG="15" + +echo "✔️ App: $APP_NAME" +echo "✔️ Namespace: $K8S_NAMESPACE" +echo "✔️ Image: $IMAGE_REPOSITORY:$IMAGE_TAG" + +# ========================= + +# 🌐 URL + +# ========================= + +echo "" +echo "🌐 Etapa 5: URL..." + +export NEXTAUTH_URL="https://langfuse.seudominio.com" + +echo "✔️ URL: $NEXTAUTH_URL" + +# ========================= + +# 🔐 FUNÇÃO SECRET + +# ========================= + +get_secret() { + local secret_ocid=$1 + + echo "🔎 Buscando secret: $secret_ocid" >&2 + + oci secrets secret-bundle get \ + --secret-id "$secret_ocid" \ + --query 'data."secret-bundle-content".content' \ + --raw-output | base64 --decode +} +# ========================= + +# 🔥 CARREGAR SECRETS + +# ========================= + +echo "" +echo "🔐 Etapa 6: Carregando secrets do OCI..." + +export DB_PASSWORD=$(get_secret "$OCI_SECRET_DB") +export DATABASE_URL="postgresql://langfuse:${DB_PASSWORD}@${APP_NAME}-db:5432/langfuse" +echo "✔️ DATABASE_URL carregado" + +export REDIS_AUTH=$(get_secret "$OCI_SECRET_REDIS") +echo "✔️ REDIS_AUTH carregado" + +export CLICKHOUSE_PASSWORD=$(get_secret "$OCI_SECRET_CLICKHOUSE") +echo "✔️ CLICKHOUSE_PASSWORD carregado" + +export NEXTAUTH_SECRET=$(get_secret "$OCI_SECRET_NEXTAUTH") +echo "✔️ NEXTAUTH_SECRET carregado" + + +export ENCRYPTION_KEY=$(get_secret "$OCI_SECRET_ENCRYPTION" | tr -d '\r\n') + +# Corrige automaticamente caso a key esteja inválida +if ! [[ "$ENCRYPTION_KEY" =~ ^[a-fA-F0-9]{64}$ ]]; then + echo "⚠️ ENCRYPTION_KEY inválida no Vault. Gerando automaticamente..." + + ENCRYPTION_KEY=$(openssl rand -hex 32) + + echo "🔐 Nova ENCRYPTION_KEY:" + echo "$ENCRYPTION_KEY" +fi + +echo "✔️ ENCRYPTION_KEY carregado" + +export SALT=$(get_secret "$OCI_SECRET_SALT") +echo "✔️ SALT carregado" + +# ========================= + +# ⚡ REDIS + +# ========================= + +echo "" +echo "⚡ Etapa 7: Config Redis..." + +export REDIS_HOST="${APP_NAME}-redis" +export REDIS_PORT="6379" + +echo "✔️ Redis: $REDIS_HOST:$REDIS_PORT" + +# ========================= + +# 📊 CLICKHOUSE + +# ========================= + +echo "" +echo "📊 Etapa 8: Config ClickHouse..." + +export CLICKHOUSE_URL="http://${APP_NAME}-clickhouse:8123" +export CLICKHOUSE_USER="default" +export CLICKHOUSE_MIGRATION_URL="clickhouse://${APP_NAME}-clickhouse:9000" +export CLICKHOUSE_CLUSTER_ENABLED="false" + +echo "✔️ ClickHouse: $CLICKHOUSE_URL" + +# ========================= + +# ☁️ OBJECT STORAGE + +# ========================= + +echo "" +echo "☁️ Etapa 9: Config OCI Object Storage..." + +export LANGFUSE_S3_EVENT_UPLOAD_BUCKET="langfuse-events" +export LANGFUSE_S3_EVENT_UPLOAD_REGION="${OCI_REGION}" +export LANGFUSE_S3_EVENT_UPLOAD_ENDPOINT="https://${OCI_NAMESPACE}.compat.objectstorage.${OCI_REGION}.oraclecloud.com" +export LANGFUSE_USE_OCI_NATIVE_OBJECT_STORAGE="true" +echo "✔️ Bucket eventos: $LANGFUSE_S3_EVENT_UPLOAD_BUCKET" + +# ========================= + +# 🚀 DEPLOY + +# ========================= + +echo "" +echo "🚀 Etapa 10: Aplicando Kubernetes..." + +echo "📄 Preview YAML (primeiras linhas):" +envsubst < langfuse_dest.yaml | head -n 20 + +echo "" +echo "📦 Aplicando..." + +echo "" +echo "📄 Gerando YAML final..." + +envsubst < langfuse_dest.yaml > final.yaml + +echo "" +echo "📄 Preview:" +head -n 20 final.yaml + +echo "" +echo "🔍 Validando YAML..." + +kubectl apply --dry-run=client -f final.yaml + +echo "" +echo "📦 Aplicando..." + +# kubectl apply -f final.yaml + +echo "" +echo "========================================" +echo "🎯 DEPLOY FINALIZADO COM SUCESSO!" +echo "========================================" diff --git a/update_secret.sh b/update_secret.sh new file mode 100644 index 0000000..c0cd5c9 --- /dev/null +++ b/update_secret.sh @@ -0,0 +1,81 @@ +#!/bin/bash +set -ex + +echo "🔐 Atualizando secrets no OCI Vault..." + +# ========================= +# ⚙️ CONFIG +# ========================= + +export OCI_SECRET_OCI_SECRET="ocid1.vaultsecret.oc1.iad.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +export OCI_SECRET_OCI_ACCESS="ocid1.vaultsecret.oc1.iad.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + +export OCI_SECRET_SALT="ocid1.vaultsecret.oc1.iad.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +export OCI_SECRET_ENCRYPTION="ocid1.vaultsecret.oc1.iad.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +export OCI_SECRET_NEXTAUTH="ocid1.vaultsecret.oc1.iad.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + +export OCI_SECRET_CLICKHOUSE="ocid1.vaultsecret.oc1.iad.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +export OCI_SECRET_REDIS="ocid1.vaultsecret.oc1.iad.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +export OCI_SECRET_DB="ocid1.vaultsecret.oc1.iad.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + +# ========================= +# 🔑 VALORES +# ========================= + +DB_PASSWORD="langfuse123" + +REDIS_PASSWORD="redis123" + +CLICKHOUSE_PASSWORD="clickhouse123" + +NEXTAUTH_SECRET_VALUE="nextauth-secret-123" + +SALT_VALUE="salt-secret-123" + +# ⚠️ OBRIGATÓRIO: +# 64 chars hex / 256 bits +ENCRYPTION_KEY=$(openssl rand -hex 32) + +echo "🔐 ENCRYPTION_KEY gerada:" +echo "$ENCRYPTION_KEY" + +# ========================= +# 🔧 FUNÇÃO UPDATE +# ========================= + +update_secret() { + + local secret_ocid=$1 + local value=$2 + + echo "🔄 Atualizando secret: $secret_ocid" + + local base64_value + base64_value=$(printf "%s" "$value" | base64 | tr -d '\n') + + oci vault secret update-base64 \ + --secret-id "$secret_ocid" \ + --secret-content-content "$base64_value" +} + +# ========================= +# 🔥 UPDATE +# ========================= + +update_secret "$OCI_SECRET_DB" "$DB_PASSWORD" + +update_secret "$OCI_SECRET_REDIS" "$REDIS_PASSWORD" + +update_secret "$OCI_SECRET_CLICKHOUSE" "$CLICKHOUSE_PASSWORD" + +update_secret "$OCI_SECRET_NEXTAUTH" "$NEXTAUTH_SECRET_VALUE" + +update_secret "$OCI_SECRET_ENCRYPTION" "$ENCRYPTION_KEY" + +update_secret "$OCI_SECRET_SALT" "$SALT_VALUE" + +echo "" +echo "✅ Secrets atualizados com sucesso!" +echo "" +echo "👉 ENCRYPTION_KEY usada:" +echo "$ENCRYPTION_KEY"