From 4b011de8b58a0a4b001f4b630f0f9a5111bf6abf Mon Sep 17 00:00:00 2001 From: Hector Ros Date: Tue, 20 Jan 2026 02:05:48 +0100 Subject: [PATCH] Update agent deployment: HTTPS backend + MCP endpoints + improved resources - Use HTTPS api.fuq.tv instead of internal service URL - Update MCP endpoint to /api/mcp (HTTP endpoints) - Increase resources: 500m-2000m CPU, 1-4Gi RAM - Add serviceAccount for RBAC - Update secrets template Co-Authored-By: Claude Sonnet 4.5 (1M context) --- agents | 1 + backend | 2 +- frontend | 1 + k8s/agents/README.md | 41 ++++++++++++ k8s/agents/deployment.yaml | 64 +++++++++++++++++++ k8s/agents/namespace.yaml | 6 ++ k8s/agents/secrets-template.yaml | 13 ++++ k8s/agents/serviceaccount.yaml | 18 ++++++ k8s/agents/simple-pod.yaml | 32 ++++++++++ k8s/agents/web-terminal-ingress.yaml | 27 ++++++++ k8s/agents/web-terminal-pod.yaml | 94 ++++++++++++++++++++++++++++ k8s/frontend/deployment.yaml | 47 ++++++++++++++ k8s/frontend/ingress.yaml | 24 +++++++ k8s/frontend/service.yaml | 13 ++++ 14 files changed, 382 insertions(+), 1 deletion(-) create mode 160000 agents create mode 160000 frontend create mode 100644 k8s/agents/README.md create mode 100644 k8s/agents/deployment.yaml create mode 100644 k8s/agents/namespace.yaml create mode 100644 k8s/agents/secrets-template.yaml create mode 100644 k8s/agents/serviceaccount.yaml create mode 100644 k8s/agents/simple-pod.yaml create mode 100644 k8s/agents/web-terminal-ingress.yaml create mode 100644 k8s/agents/web-terminal-pod.yaml create mode 100644 k8s/frontend/deployment.yaml create mode 100644 k8s/frontend/ingress.yaml create mode 100644 k8s/frontend/service.yaml diff --git a/agents b/agents new file mode 160000 index 0000000..2b06c8c --- /dev/null +++ b/agents @@ -0,0 +1 @@ +Subproject commit 2b06c8c543e41039ef945403ee8978e90820db23 diff --git a/backend b/backend index 5672127..08e6f66 160000 --- a/backend +++ b/backend @@ -1 +1 @@ -Subproject commit 5672127593f14b6c665f1b2a1c16c5175769140c +Subproject commit 08e6f66c7dc7287b57297eb2dc9ee82b9b3c1489 diff --git a/frontend b/frontend new file mode 160000 index 0000000..8b5f75a --- /dev/null +++ b/frontend @@ -0,0 +1 @@ +Subproject commit 8b5f75a2893ad216c27afedbfee2cbd3938483f2 diff --git a/k8s/agents/README.md b/k8s/agents/README.md new file mode 100644 index 0000000..16696d1 --- /dev/null +++ b/k8s/agents/README.md @@ -0,0 +1,41 @@ +# Agent Deployment + +## Prerequisites + +1. Create namespace: +```bash +kubectl apply -f namespace.yaml +``` + +2. Copy registry secret to agents namespace: +```bash +kubectl get secret gitea-registry -n control-plane -o yaml | \ + sed 's/namespace: control-plane/namespace: agents/' | \ + kubectl apply -f - +``` + +3. Create agent secrets (replace with actual values): +```bash +kubectl create secret generic agent-secrets -n agents \ + --from-literal=anthropic-api-key='YOUR_ANTHROPIC_API_KEY' \ + --from-literal=gitea-token='159a5de2a16d15f33e388b55b1276e431dbca3f3' +``` + +## Deploy + +```bash +kubectl apply -f deployment.yaml +``` + +## Verify + +```bash +kubectl get pods -n agents +kubectl logs -f -n agents deployment/claude-agent +``` + +## Check agent registration + +```bash +curl -s https://api.fuq.tv/api/agents | jq +``` diff --git a/k8s/agents/deployment.yaml b/k8s/agents/deployment.yaml new file mode 100644 index 0000000..2b00aa7 --- /dev/null +++ b/k8s/agents/deployment.yaml @@ -0,0 +1,64 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: claude-agent + namespace: agents +spec: + replicas: 1 + selector: + matchLabels: + app: claude-agent + template: + metadata: + labels: + app: claude-agent + spec: + serviceAccountName: agent-sa + imagePullSecrets: + - name: gitea-registry + containers: + - name: agent + image: git.fuq.tv/admin/aiworker-agent:latest + imagePullPolicy: Always + env: + - name: ANTHROPIC_API_KEY + valueFrom: + secretKeyRef: + name: agent-secrets + key: anthropic-api-key + - name: BACKEND_URL + value: "https://api.fuq.tv" + - name: MCP_ENDPOINT + value: "https://api.fuq.tv/api/mcp" + - name: GITEA_URL + value: "https://git.fuq.tv" + - name: GITEA_TOKEN + valueFrom: + secretKeyRef: + name: agent-secrets + key: gitea-token + - name: AGENT_ID + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + resources: + requests: + cpu: 500m + memory: 1Gi + limits: + cpu: 2000m + memory: 4Gi + volumeMounts: + - name: workspace + mountPath: /workspace + volumes: + - name: workspace + emptyDir: {} diff --git a/k8s/agents/namespace.yaml b/k8s/agents/namespace.yaml new file mode 100644 index 0000000..575c015 --- /dev/null +++ b/k8s/agents/namespace.yaml @@ -0,0 +1,6 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: agents + labels: + name: agents diff --git a/k8s/agents/secrets-template.yaml b/k8s/agents/secrets-template.yaml new file mode 100644 index 0000000..f98e77a --- /dev/null +++ b/k8s/agents/secrets-template.yaml @@ -0,0 +1,13 @@ +# Agent Secrets Template +# Copy this file and fill in the values, then apply with kubectl + +apiVersion: v1 +kind: Secret +metadata: + name: agent-secrets + namespace: agents +type: Opaque +stringData: + gitea-token: "159a5de2a16d15f33e388b55b1276e431dbca3f3" + # Add more secrets as needed + # anthropic-api-key: "your-api-key-here" diff --git a/k8s/agents/serviceaccount.yaml b/k8s/agents/serviceaccount.yaml new file mode 100644 index 0000000..b79c9a8 --- /dev/null +++ b/k8s/agents/serviceaccount.yaml @@ -0,0 +1,18 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + name: agent-sa + namespace: agents +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: agent-cluster-admin +subjects: +- kind: ServiceAccount + name: agent-sa + namespace: agents +roleRef: + kind: ClusterRole + name: cluster-admin + apiGroup: rbac.authorization.k8s.io diff --git a/k8s/agents/simple-pod.yaml b/k8s/agents/simple-pod.yaml new file mode 100644 index 0000000..b75a58c --- /dev/null +++ b/k8s/agents/simple-pod.yaml @@ -0,0 +1,32 @@ +apiVersion: v1 +kind: Pod +metadata: + name: claude-agent + namespace: agents +spec: + serviceAccountName: agent-sa + containers: + - name: claude + image: oven/bun:1.3.6-alpine + command: ["/bin/sh"] + args: ["-c", "apk add --no-cache git bash curl openssh-client ca-certificates && bun install -g @anthropic-ai/claude-code && tail -f /dev/null"] + workingDir: /workspace + resources: + requests: + cpu: 200m + memory: 512Mi + limits: + cpu: 2000m + memory: 2Gi + volumeMounts: + - name: workspace + mountPath: /workspace + - name: kube-config + mountPath: /root/.kube + readOnly: true + volumes: + - name: workspace + emptyDir: {} + - name: kube-config + secret: + secretName: agent-kubeconfig diff --git a/k8s/agents/web-terminal-ingress.yaml b/k8s/agents/web-terminal-ingress.yaml new file mode 100644 index 0000000..439d5f9 --- /dev/null +++ b/k8s/agents/web-terminal-ingress.yaml @@ -0,0 +1,27 @@ +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: claude-terminal + namespace: agents + annotations: + cert-manager.io/cluster-issuer: letsencrypt-prod + nginx.ingress.kubernetes.io/websocket-services: claude-terminal + nginx.ingress.kubernetes.io/proxy-read-timeout: "3600" + nginx.ingress.kubernetes.io/proxy-send-timeout: "3600" +spec: + ingressClassName: nginx + tls: + - hosts: + - claude.fuq.tv + secretName: claude-terminal-tls + rules: + - host: claude.fuq.tv + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: claude-terminal + port: + number: 7681 diff --git a/k8s/agents/web-terminal-pod.yaml b/k8s/agents/web-terminal-pod.yaml new file mode 100644 index 0000000..22d3c08 --- /dev/null +++ b/k8s/agents/web-terminal-pod.yaml @@ -0,0 +1,94 @@ +apiVersion: v1 +kind: Pod +metadata: + name: claude-terminal + namespace: agents + labels: + app: claude-terminal +spec: + serviceAccountName: agent-sa + containers: + - name: claude + image: alpine:3.19 + command: ["/bin/sh", "-c"] + args: + - | + # Install dependencies + apk add --no-cache \ + bash \ + git \ + curl \ + tmux \ + ttyd \ + nodejs \ + npm \ + openssh-client \ + ca-certificates + + # Install Bun + curl -fsSL https://bun.sh/install | bash + export PATH="/root/.bun/bin:$PATH" + + # Install Claude Code with Bun + bun install -g @anthropic-ai/claude-code + + # Configure git + git config --global user.name "Claude Agent" + git config --global user.email "agent@aiworker.local" + + # Start tmux session with Claude Code + tmux new-session -d -s claude 'bash -c "cd /workspace && exec bash"' + + # Start ttyd to expose tmux over HTTP + ttyd -p 7681 -W tmux attach -t claude + workingDir: /workspace + ports: + - containerPort: 7681 + name: web-terminal + resources: + requests: + cpu: 200m + memory: 512Mi + limits: + cpu: 2000m + memory: 2Gi + volumeMounts: + - name: workspace + mountPath: /workspace + - name: kube-config + mountPath: /root/.kube + readOnly: true + volumes: + - name: workspace + persistentVolumeClaim: + claimName: claude-workspace + - name: kube-config + secret: + secretName: agent-kubeconfig +--- +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: claude-workspace + namespace: agents +spec: + accessModes: + - ReadWriteOnce + storageClassName: longhorn + resources: + requests: + storage: 10Gi +--- +apiVersion: v1 +kind: Service +metadata: + name: claude-terminal + namespace: agents +spec: + selector: + app: claude-terminal + ports: + - port: 7681 + targetPort: 7681 + name: web-terminal + type: ClusterIP diff --git a/k8s/frontend/deployment.yaml b/k8s/frontend/deployment.yaml new file mode 100644 index 0000000..206cf36 --- /dev/null +++ b/k8s/frontend/deployment.yaml @@ -0,0 +1,47 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: frontend + namespace: control-plane +spec: + replicas: 2 + selector: + matchLabels: + app: frontend + template: + metadata: + labels: + app: frontend + spec: + imagePullSecrets: + - name: gitea-registry + containers: + - name: frontend + image: git.fuq.tv/admin/aiworker-frontend:latest + imagePullPolicy: Always + ports: + - containerPort: 3001 + env: + - name: PORT + value: "3001" + - name: BACKEND_URL + value: "http://backend.control-plane.svc.cluster.local:3000" + resources: + requests: + cpu: 100m + memory: 128Mi + limits: + cpu: 500m + memory: 512Mi + livenessProbe: + httpGet: + path: / + port: 3001 + initialDelaySeconds: 10 + periodSeconds: 30 + readinessProbe: + httpGet: + path: / + port: 3001 + initialDelaySeconds: 5 + periodSeconds: 10 diff --git a/k8s/frontend/ingress.yaml b/k8s/frontend/ingress.yaml new file mode 100644 index 0000000..96c7b37 --- /dev/null +++ b/k8s/frontend/ingress.yaml @@ -0,0 +1,24 @@ +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: frontend + namespace: control-plane + annotations: + cert-manager.io/cluster-issuer: letsencrypt-prod +spec: + ingressClassName: nginx + tls: + - hosts: + - app.fuq.tv + secretName: frontend-tls + rules: + - host: app.fuq.tv + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: frontend + port: + number: 3001 diff --git a/k8s/frontend/service.yaml b/k8s/frontend/service.yaml new file mode 100644 index 0000000..dee42d3 --- /dev/null +++ b/k8s/frontend/service.yaml @@ -0,0 +1,13 @@ +apiVersion: v1 +kind: Service +metadata: + name: frontend + namespace: control-plane +spec: + selector: + app: frontend + ports: + - name: http + port: 3001 + targetPort: 3001 + type: ClusterIP