Compare commits
No commits in common. "8de9b5c0cb21a9f787c6cc56cd0ab27cdad762b8" and "1d152c0dce28e2b77f20cbeb7593f6e568215792" have entirely different histories.
8de9b5c0cb
...
1d152c0dce
@ -1,17 +0,0 @@
|
|||||||
.git
|
|
||||||
.github
|
|
||||||
.gitea
|
|
||||||
.env
|
|
||||||
.env.local
|
|
||||||
venv
|
|
||||||
__pycache__
|
|
||||||
*.pyc
|
|
||||||
.vanna
|
|
||||||
vanna
|
|
||||||
chroma_db
|
|
||||||
data_storage
|
|
||||||
.DS_Store
|
|
||||||
*.md
|
|
||||||
docs
|
|
||||||
test_*.py
|
|
||||||
node_modules
|
|
||||||
20
.env.example
20
.env.example
@ -1,20 +0,0 @@
|
|||||||
# OpenAI
|
|
||||||
OPENAI_API_KEY=
|
|
||||||
OPENAI_MODEL=gpt-5
|
|
||||||
OPENAI_TEMPERATURE=1.0
|
|
||||||
|
|
||||||
# ClickHouse Cloud (database `gold`, usuário `wren_ia`)
|
|
||||||
CLICKHOUSE_HOST=
|
|
||||||
CLICKHOUSE_PORT=8443
|
|
||||||
CLICKHOUSE_DATABASE=gold
|
|
||||||
CLICKHOUSE_USER=wren_ia
|
|
||||||
CLICKHOUSE_PASSWORD=
|
|
||||||
CLICKHOUSE_SECURE=true
|
|
||||||
|
|
||||||
# CORS (separar por vírgula)
|
|
||||||
VANNA_CORS_ORIGINS=https://lab.clubpetro.com,https://homologation.clubpetro.com
|
|
||||||
|
|
||||||
# RLS defaults (apenas pra `python ask.py` na CLI; servidor web extrai de query string)
|
|
||||||
RLS_PROGRAM_ID=
|
|
||||||
RLS_STORE_ID=
|
|
||||||
RLS_USER_ID=
|
|
||||||
@ -1,60 +0,0 @@
|
|||||||
name: CD
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches: [master, main]
|
|
||||||
pull_request:
|
|
||||||
|
|
||||||
env:
|
|
||||||
IMAGE_BASE: ${{ secrets.AR_LOCATION }}-docker.pkg.dev/${{ secrets.GCP_PROJECT }}/${{ secrets.AR_REPO }}
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
if: ${{ hashFiles('Dockerfile') != '' }}
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Auth GCP
|
|
||||||
uses: google-github-actions/auth@v2
|
|
||||||
with:
|
|
||||||
credentials_json: ${{ secrets.GCP_SA_KEY }}
|
|
||||||
|
|
||||||
- name: Setup gcloud
|
|
||||||
uses: google-github-actions/setup-gcloud@v2
|
|
||||||
with:
|
|
||||||
project_id: ${{ secrets.GCP_PROJECT }}
|
|
||||||
|
|
||||||
- name: Configure Docker auth
|
|
||||||
run: gcloud auth configure-docker ${{ secrets.AR_LOCATION }}-docker.pkg.dev --quiet
|
|
||||||
|
|
||||||
- name: Build image
|
|
||||||
run: |
|
|
||||||
IMG="${IMAGE_BASE}/${{ gitea.event.repository.name }}:lab-${{ gitea.run_number }}"
|
|
||||||
docker build --platform=linux/amd64 -t "$IMG" .
|
|
||||||
echo "IMG=$IMG" >> $GITHUB_ENV
|
|
||||||
|
|
||||||
- name: Push image (apenas em push pra master/main)
|
|
||||||
if: github.event_name == 'push'
|
|
||||||
run: docker push "$IMG"
|
|
||||||
|
|
||||||
- name: Deploy hml2 (apenas em push pra master/main)
|
|
||||||
if: github.event_name == 'push'
|
|
||||||
run: |
|
|
||||||
gcloud container clusters get-credentials ${{ secrets.GKE_CLUSTER }} --region ${{ secrets.GKE_REGION }} --project ${{ secrets.GCP_PROJECT }}
|
|
||||||
NS=${{ secrets.K8S_NAMESPACE }}
|
|
||||||
|
|
||||||
# 1) Aplica manifests (idempotente — cria PVC/Service/Ingress/Deployment se faltarem)
|
|
||||||
if [ -d k8s ]; then
|
|
||||||
kubectl apply -n "$NS" -f k8s/
|
|
||||||
fi
|
|
||||||
|
|
||||||
# 2) Atualiza image
|
|
||||||
DEPLOYMENT="${{ gitea.event.repository.name }}-deployment"
|
|
||||||
if kubectl get deployment "$DEPLOYMENT" -n "$NS" >/dev/null 2>&1; then
|
|
||||||
CONTAINER=$(kubectl get deployment "$DEPLOYMENT" -n "$NS" -o jsonpath='{.spec.template.spec.containers[0].name}')
|
|
||||||
kubectl set image deployment/"$DEPLOYMENT" -n "$NS" "$CONTAINER=$IMG"
|
|
||||||
kubectl rollout status deployment/"$DEPLOYMENT" -n "$NS" --timeout=300s
|
|
||||||
else
|
|
||||||
echo "Deployment $DEPLOYMENT não existe no ns $NS — pulei set image (provavelmente é o 1º deploy e o kubectl apply acabou de criar)"
|
|
||||||
fi
|
|
||||||
@ -1,29 +0,0 @@
|
|||||||
# Histórico de mudanças com IA
|
|
||||||
|
|
||||||
Registro das alterações feitas neste repositório com apoio de IA (Claude), incluindo tempo aproximado. Ordem cronológica — **mais recente no topo**.
|
|
||||||
|
|
||||||
## Formato de entrada
|
|
||||||
|
|
||||||
```
|
|
||||||
### YYYY-MM-DD HH:MM — Título curto
|
|
||||||
|
|
||||||
- **Tempo:** ~X min
|
|
||||||
- **Prompt:** resumo do pedido
|
|
||||||
- **Mudanças:** o que foi feito
|
|
||||||
- **Artefatos:** branch, PR #, commit hash
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 2026-05-05 ~17:30 — Bootstrap de deploy no hml2
|
|
||||||
|
|
||||||
- **Tempo:** ~30 min
|
|
||||||
- **Prompt:** "fazer pull do repo vanna-clubpetro e fazer o deploy"
|
|
||||||
- **Mudanças:**
|
|
||||||
- Criado `Dockerfile` multi-stage: stage 1 (Node 18) clona vanna-ai/vanna upstream pinned em `365d061` e builda o webcomponent (~7.5MB); stage 2 (Python 3.11-slim) instala vanna editable + `requirements.txt` + código do app. CMD com `--workers 1` (constraint do ChromaDB SQLite).
|
|
||||||
- Criado `requirements.txt` (clickhouse-connect, chromadb, openai, fastapi, uvicorn, pandas, plotly, pydantic, python-dotenv).
|
|
||||||
- Criado `.env.example` baseado em `docs/deploy.md`.
|
|
||||||
- Criado `.dockerignore`.
|
|
||||||
- Criado `k8s/`: `deployment.yaml` (1 réplica, strategy Recreate, PVC montado em `/app/chroma_db`, `/app/data_storage` e `~/.cache/chroma`, probes TCP), `service.yaml` (ClusterIP 80→8765), `ingress.yaml` (`lab.clubpetro.com/api/vanna/*` com timeouts altos pra SSE/WebSocket), `pvc.yaml` (5Gi standard-rwo).
|
|
||||||
- Criado `.gitea/workflows/cd.yml` seguindo template do lab — PR só valida build, merge faz `kubectl apply -f k8s/` (idempotente) + `kubectl set image` na tag `lab-<run_number>`.
|
|
||||||
- **Artefatos:** branch `chore/initial-deploy`, PR a abrir em `clubpetro-lab/vanna-clubpetro`. Pendente: criar Secret K8s `vanna-clubpetro-secret` com `OPENAI_API_KEY` + `CLICKHOUSE_*` antes do pod subir.
|
|
||||||
60
Dockerfile
60
Dockerfile
@ -1,60 +0,0 @@
|
|||||||
# syntax=docker/dockerfile:1.6
|
|
||||||
# Multi-stage:
|
|
||||||
# 1) Clona vanna-ai/vanna upstream (commit pinned em 365d061) e builda o webcomponent (~7.5MB)
|
|
||||||
# 2) Imagem Python 3.11 com vanna editable + requirements + código do app
|
|
||||||
ARG VANNA_UPSTREAM_COMMIT=365d0617c1a4567ffee1b19b40c27feb4206bfcf
|
|
||||||
|
|
||||||
# ============================================================================
|
|
||||||
# Stage 1 — webcomponent (Node)
|
|
||||||
# ============================================================================
|
|
||||||
FROM node:18-bookworm-slim AS webcomponent
|
|
||||||
ARG VANNA_UPSTREAM_COMMIT
|
|
||||||
RUN apt-get update && apt-get install -y --no-install-recommends git ca-certificates \
|
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
|
||||||
WORKDIR /vanna
|
|
||||||
RUN git init -q \
|
|
||||||
&& git remote add origin https://github.com/vanna-ai/vanna.git \
|
|
||||||
&& git fetch --depth 50 origin "$VANNA_UPSTREAM_COMMIT" \
|
|
||||||
&& git checkout FETCH_HEAD
|
|
||||||
WORKDIR /vanna/frontends/webcomponent
|
|
||||||
RUN npm install --no-audit --no-fund --loglevel=error \
|
|
||||||
&& npm run build \
|
|
||||||
&& ls -lh dist/vanna-components.js
|
|
||||||
|
|
||||||
# ============================================================================
|
|
||||||
# Stage 2 — runtime Python
|
|
||||||
# ============================================================================
|
|
||||||
FROM python:3.11-slim-bookworm
|
|
||||||
ARG VANNA_UPSTREAM_COMMIT
|
|
||||||
|
|
||||||
ENV PYTHONDONTWRITEBYTECODE=1 \
|
|
||||||
PYTHONUNBUFFERED=1 \
|
|
||||||
PIP_NO_CACHE_DIR=1 \
|
|
||||||
PIP_DISABLE_PIP_VERSION_CHECK=1
|
|
||||||
|
|
||||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
|
||||||
git ca-certificates curl build-essential \
|
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
|
||||||
|
|
||||||
WORKDIR /app
|
|
||||||
|
|
||||||
# Copia o vanna upstream + bundle já buildado do stage 1
|
|
||||||
COPY --from=webcomponent /vanna /app/vanna
|
|
||||||
|
|
||||||
# Instala vanna editable
|
|
||||||
RUN pip install -e ./vanna
|
|
||||||
|
|
||||||
# Instala deps do app
|
|
||||||
COPY requirements.txt .
|
|
||||||
RUN pip install -r requirements.txt
|
|
||||||
|
|
||||||
# Código do app
|
|
||||||
COPY . .
|
|
||||||
|
|
||||||
# data dirs
|
|
||||||
RUN mkdir -p /app/chroma_db /app/data_storage
|
|
||||||
|
|
||||||
EXPOSE 8765
|
|
||||||
|
|
||||||
# `--workers 1` é OBRIGATÓRIO — múltiplos workers corrompem o SQLite do Chroma
|
|
||||||
CMD ["uvicorn", "server:app", "--host", "0.0.0.0", "--port", "8765", "--workers", "1"]
|
|
||||||
@ -1,65 +0,0 @@
|
|||||||
apiVersion: apps/v1
|
|
||||||
kind: Deployment
|
|
||||||
metadata:
|
|
||||||
name: vanna-clubpetro-deployment
|
|
||||||
labels:
|
|
||||||
app: vanna-clubpetro
|
|
||||||
spec:
|
|
||||||
replicas: 1 # ChromaDB SQLite-based — múltiplas réplicas corrompem o vector store
|
|
||||||
strategy:
|
|
||||||
type: Recreate # com PVC ReadWriteOnce não dá pra ter 2 pods montando ao mesmo tempo
|
|
||||||
selector:
|
|
||||||
matchLabels:
|
|
||||||
app: vanna-clubpetro
|
|
||||||
template:
|
|
||||||
metadata:
|
|
||||||
labels:
|
|
||||||
app: vanna-clubpetro
|
|
||||||
spec:
|
|
||||||
containers:
|
|
||||||
- name: vanna-clubpetro
|
|
||||||
image: us-central1-docker.pkg.dev/corepetro/clubpetro-lab/vanna-clubpetro:lab-latest
|
|
||||||
imagePullPolicy: IfNotPresent
|
|
||||||
ports:
|
|
||||||
- name: http
|
|
||||||
containerPort: 8765
|
|
||||||
env:
|
|
||||||
- name: VANNA_CORS_ORIGINS
|
|
||||||
value: "https://lab.clubpetro.com,https://homologation.clubpetro.com"
|
|
||||||
envFrom:
|
|
||||||
- secretRef:
|
|
||||||
name: vanna-clubpetro-secret
|
|
||||||
resources:
|
|
||||||
requests:
|
|
||||||
cpu: "200m"
|
|
||||||
memory: "1Gi"
|
|
||||||
limits:
|
|
||||||
cpu: "1"
|
|
||||||
memory: "2Gi"
|
|
||||||
readinessProbe:
|
|
||||||
tcpSocket:
|
|
||||||
port: 8765
|
|
||||||
initialDelaySeconds: 30
|
|
||||||
periodSeconds: 10
|
|
||||||
timeoutSeconds: 5
|
|
||||||
livenessProbe:
|
|
||||||
tcpSocket:
|
|
||||||
port: 8765
|
|
||||||
initialDelaySeconds: 60
|
|
||||||
periodSeconds: 30
|
|
||||||
timeoutSeconds: 5
|
|
||||||
failureThreshold: 3
|
|
||||||
volumeMounts:
|
|
||||||
- name: data
|
|
||||||
mountPath: /app/chroma_db
|
|
||||||
subPath: chroma_db
|
|
||||||
- name: data
|
|
||||||
mountPath: /app/data_storage
|
|
||||||
subPath: data_storage
|
|
||||||
- name: data
|
|
||||||
mountPath: /root/.cache/chroma
|
|
||||||
subPath: chroma-onnx-cache
|
|
||||||
volumes:
|
|
||||||
- name: data
|
|
||||||
persistentVolumeClaim:
|
|
||||||
claimName: vanna-clubpetro-data
|
|
||||||
@ -1,32 +0,0 @@
|
|||||||
apiVersion: networking.k8s.io/v1
|
|
||||||
kind: Ingress
|
|
||||||
metadata:
|
|
||||||
name: vanna-clubpetro
|
|
||||||
labels:
|
|
||||||
app: vanna-clubpetro
|
|
||||||
annotations:
|
|
||||||
kubernetes.io/ingress.class: nginx
|
|
||||||
nginx.ingress.kubernetes.io/use-regex: "true"
|
|
||||||
nginx.ingress.kubernetes.io/rewrite-target: /$2
|
|
||||||
# SSE/WebSocket precisam de timeout grande pra streaming não ser cortado
|
|
||||||
nginx.ingress.kubernetes.io/proxy-read-timeout: "3600"
|
|
||||||
nginx.ingress.kubernetes.io/proxy-send-timeout: "3600"
|
|
||||||
nginx.ingress.kubernetes.io/proxy-buffering: "off"
|
|
||||||
nginx.ingress.kubernetes.io/proxy-http-version: "1.1"
|
|
||||||
spec:
|
|
||||||
ingressClassName: nginx
|
|
||||||
rules:
|
|
||||||
- host: lab.clubpetro.com
|
|
||||||
http:
|
|
||||||
paths:
|
|
||||||
- path: /api/vanna(/|$)(.*)
|
|
||||||
pathType: Prefix
|
|
||||||
backend:
|
|
||||||
service:
|
|
||||||
name: vanna-clubpetro
|
|
||||||
port:
|
|
||||||
number: 80
|
|
||||||
tls:
|
|
||||||
- hosts:
|
|
||||||
- lab.clubpetro.com
|
|
||||||
secretName: lab-tls
|
|
||||||
13
k8s/pvc.yaml
13
k8s/pvc.yaml
@ -1,13 +0,0 @@
|
|||||||
apiVersion: v1
|
|
||||||
kind: PersistentVolumeClaim
|
|
||||||
metadata:
|
|
||||||
name: vanna-clubpetro-data
|
|
||||||
labels:
|
|
||||||
app: vanna-clubpetro
|
|
||||||
spec:
|
|
||||||
accessModes:
|
|
||||||
- ReadWriteOnce
|
|
||||||
resources:
|
|
||||||
requests:
|
|
||||||
storage: 5Gi
|
|
||||||
storageClassName: standard-rwo
|
|
||||||
@ -1,15 +0,0 @@
|
|||||||
apiVersion: v1
|
|
||||||
kind: Service
|
|
||||||
metadata:
|
|
||||||
name: vanna-clubpetro
|
|
||||||
labels:
|
|
||||||
app: vanna-clubpetro
|
|
||||||
spec:
|
|
||||||
type: ClusterIP
|
|
||||||
selector:
|
|
||||||
app: vanna-clubpetro
|
|
||||||
ports:
|
|
||||||
- name: http
|
|
||||||
port: 80
|
|
||||||
targetPort: 8765
|
|
||||||
protocol: TCP
|
|
||||||
@ -1,10 +0,0 @@
|
|||||||
# Runtime deps. O `vanna` editable é instalado via `pip install -e ./vanna` no Dockerfile.
|
|
||||||
clickhouse-connect>=0.7,<1.0
|
|
||||||
chromadb>=0.4,<1.0
|
|
||||||
openai>=1.0
|
|
||||||
python-dotenv>=1.0
|
|
||||||
fastapi>=0.110
|
|
||||||
uvicorn[standard]>=0.27
|
|
||||||
pandas>=2.0
|
|
||||||
plotly>=5.18
|
|
||||||
pydantic>=2.5
|
|
||||||
Loading…
Reference in New Issue
Block a user