Complete documentation for future sessions
- CLAUDE.md for AI agents to understand the codebase - GITEA-GUIDE.md centralizes all Gitea operations (API, Registry, Auth) - DEVELOPMENT-WORKFLOW.md explains complete dev process - ROADMAP.md, NEXT-SESSION.md for planning - QUICK-REFERENCE.md, TROUBLESHOOTING.md for daily use - 40+ detailed docs in /docs folder - Backend as submodule from Gitea Everything documented for autonomous operation. Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
456
docs/04-kubernetes/gitea-deployment.md
Normal file
456
docs/04-kubernetes/gitea-deployment.md
Normal file
@@ -0,0 +1,456 @@
|
||||
# Gitea Deployment en Kubernetes
|
||||
|
||||
## Gitea StatefulSet
|
||||
|
||||
```yaml
|
||||
# k8s/gitea/gitea-statefulset.yaml
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: gitea-data
|
||||
namespace: gitea
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
resources:
|
||||
requests:
|
||||
storage: 50Gi
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
name: gitea
|
||||
namespace: gitea
|
||||
spec:
|
||||
serviceName: gitea
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: gitea
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: gitea
|
||||
spec:
|
||||
containers:
|
||||
- name: gitea
|
||||
image: gitea/gitea:1.22
|
||||
ports:
|
||||
- name: http
|
||||
containerPort: 3000
|
||||
- name: ssh
|
||||
containerPort: 22
|
||||
env:
|
||||
- name: USER_UID
|
||||
value: "1000"
|
||||
- name: USER_GID
|
||||
value: "1000"
|
||||
- name: GITEA__database__DB_TYPE
|
||||
value: "mysql"
|
||||
- name: GITEA__database__HOST
|
||||
value: "mysql.control-plane.svc.cluster.local:3306"
|
||||
- name: GITEA__database__NAME
|
||||
value: "gitea"
|
||||
- name: GITEA__database__USER
|
||||
value: "root"
|
||||
- name: GITEA__database__PASSWD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: aiworker-secrets
|
||||
key: db-password
|
||||
- name: GITEA__server__DOMAIN
|
||||
value: "git.aiworker.dev"
|
||||
- name: GITEA__server__SSH_DOMAIN
|
||||
value: "git.aiworker.dev"
|
||||
- name: GITEA__server__ROOT_URL
|
||||
value: "https://git.aiworker.dev"
|
||||
- name: GITEA__server__HTTP_PORT
|
||||
value: "3000"
|
||||
- name: GITEA__server__SSH_PORT
|
||||
value: "2222"
|
||||
- name: GITEA__security__INSTALL_LOCK
|
||||
value: "true"
|
||||
- name: GITEA__webhook__ALLOWED_HOST_LIST
|
||||
value: "*.svc.cluster.local"
|
||||
volumeMounts:
|
||||
- name: data
|
||||
mountPath: /data
|
||||
resources:
|
||||
requests:
|
||||
cpu: "500m"
|
||||
memory: "1Gi"
|
||||
limits:
|
||||
cpu: "2"
|
||||
memory: "4Gi"
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /api/healthz
|
||||
port: 3000
|
||||
initialDelaySeconds: 60
|
||||
periodSeconds: 10
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /api/healthz
|
||||
port: 3000
|
||||
initialDelaySeconds: 30
|
||||
periodSeconds: 5
|
||||
volumes:
|
||||
- name: data
|
||||
persistentVolumeClaim:
|
||||
claimName: gitea-data
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: gitea
|
||||
namespace: gitea
|
||||
spec:
|
||||
selector:
|
||||
app: gitea
|
||||
ports:
|
||||
- name: http
|
||||
port: 3000
|
||||
targetPort: 3000
|
||||
- name: ssh
|
||||
port: 2222
|
||||
targetPort: 22
|
||||
type: ClusterIP
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: gitea-ssh
|
||||
namespace: gitea
|
||||
annotations:
|
||||
service.beta.kubernetes.io/external-traffic: OnlyLocal
|
||||
spec:
|
||||
selector:
|
||||
app: gitea
|
||||
ports:
|
||||
- name: ssh
|
||||
port: 2222
|
||||
targetPort: 22
|
||||
protocol: TCP
|
||||
type: LoadBalancer
|
||||
---
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: gitea
|
||||
namespace: gitea
|
||||
annotations:
|
||||
cert-manager.io/cluster-issuer: "letsencrypt-prod"
|
||||
nginx.ingress.kubernetes.io/proxy-body-size: "512m"
|
||||
spec:
|
||||
ingressClassName: nginx
|
||||
tls:
|
||||
- hosts:
|
||||
- git.aiworker.dev
|
||||
secretName: gitea-tls
|
||||
rules:
|
||||
- host: git.aiworker.dev
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: gitea
|
||||
port:
|
||||
number: 3000
|
||||
```
|
||||
|
||||
## Gitea Configuration
|
||||
|
||||
```yaml
|
||||
# k8s/gitea/gitea-config.yaml
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: gitea-config
|
||||
namespace: gitea
|
||||
data:
|
||||
app.ini: |
|
||||
[server]
|
||||
PROTOCOL = http
|
||||
DOMAIN = git.aiworker.dev
|
||||
ROOT_URL = https://git.aiworker.dev
|
||||
HTTP_PORT = 3000
|
||||
SSH_PORT = 2222
|
||||
DISABLE_SSH = false
|
||||
START_SSH_SERVER = true
|
||||
SSH_LISTEN_HOST = 0.0.0.0
|
||||
SSH_LISTEN_PORT = 22
|
||||
LFS_START_SERVER = true
|
||||
OFFLINE_MODE = false
|
||||
|
||||
[database]
|
||||
DB_TYPE = mysql
|
||||
HOST = mysql.control-plane.svc.cluster.local:3306
|
||||
NAME = gitea
|
||||
USER = root
|
||||
SSL_MODE = disable
|
||||
|
||||
[security]
|
||||
INSTALL_LOCK = true
|
||||
SECRET_KEY = your-secret-key-here
|
||||
INTERNAL_TOKEN = your-internal-token-here
|
||||
|
||||
[service]
|
||||
DISABLE_REGISTRATION = false
|
||||
REQUIRE_SIGNIN_VIEW = false
|
||||
ENABLE_NOTIFY_MAIL = false
|
||||
|
||||
[webhook]
|
||||
ALLOWED_HOST_LIST = *.svc.cluster.local,*.aiworker.dev
|
||||
|
||||
[api]
|
||||
ENABLE_SWAGGER = true
|
||||
|
||||
[actions]
|
||||
ENABLED = true
|
||||
|
||||
[repository]
|
||||
DEFAULT_BRANCH = main
|
||||
FORCE_PRIVATE = false
|
||||
|
||||
[ui]
|
||||
DEFAULT_THEME = arc-green
|
||||
```
|
||||
|
||||
## Inicialización de Gitea
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# scripts/init-gitea.sh
|
||||
|
||||
set -e
|
||||
|
||||
echo "🚀 Initializing Gitea..."
|
||||
|
||||
# Wait for Gitea to be ready
|
||||
echo "⏳ Waiting for Gitea pod..."
|
||||
kubectl wait --for=condition=ready pod -l app=gitea -n gitea --timeout=300s
|
||||
|
||||
# Port-forward temporalmente
|
||||
echo "🔌 Port-forwarding Gitea..."
|
||||
kubectl port-forward -n gitea svc/gitea 3001:3000 &
|
||||
PF_PID=$!
|
||||
sleep 5
|
||||
|
||||
# Create admin user
|
||||
echo "👤 Creating admin user..."
|
||||
kubectl exec -n gitea gitea-0 -- gitea admin user create \
|
||||
--username aiworker \
|
||||
--password admin123 \
|
||||
--email admin@aiworker.dev \
|
||||
--admin \
|
||||
--must-change-password=false
|
||||
|
||||
# Create organization
|
||||
echo "🏢 Creating organization..."
|
||||
kubectl exec -n gitea gitea-0 -- gitea admin user create \
|
||||
--username aiworker-bot \
|
||||
--password bot123 \
|
||||
--email bot@aiworker.dev
|
||||
|
||||
# Generate access token
|
||||
echo "🔑 Generating access token..."
|
||||
TOKEN=$(kubectl exec -n gitea gitea-0 -- gitea admin user generate-access-token \
|
||||
--username aiworker-bot \
|
||||
--scopes write:repository,write:issue,write:user \
|
||||
--raw)
|
||||
|
||||
echo "✅ Gitea initialized!"
|
||||
echo "📍 URL: https://git.aiworker.dev"
|
||||
echo "👤 User: aiworker / admin123"
|
||||
echo "🔑 Bot Token: $TOKEN"
|
||||
echo ""
|
||||
echo "⚠️ Save this token and update the secret:"
|
||||
echo "kubectl create secret generic aiworker-secrets -n control-plane \\"
|
||||
echo " --from-literal=gitea-token='$TOKEN' --dry-run=client -o yaml | kubectl apply -f -"
|
||||
|
||||
# Stop port-forward
|
||||
kill $PF_PID
|
||||
```
|
||||
|
||||
## Gitea Webhook Configuration
|
||||
|
||||
```typescript
|
||||
// services/gitea/setup.ts
|
||||
import { giteaClient } from './client'
|
||||
import { logger } from '../../utils/logger'
|
||||
|
||||
export async function setupGiteaWebhooks(owner: string, repo: string) {
|
||||
const backendUrl = process.env.BACKEND_URL || 'https://api.aiworker.dev'
|
||||
|
||||
try {
|
||||
// Create webhook for push events
|
||||
await giteaClient.createWebhook(owner, repo, {
|
||||
url: `${backendUrl}/api/webhooks/gitea`,
|
||||
contentType: 'json',
|
||||
secret: process.env.GITEA_WEBHOOK_SECRET || '',
|
||||
events: ['push', 'pull_request', 'pull_request_closed'],
|
||||
})
|
||||
|
||||
logger.info(`Webhooks configured for ${owner}/${repo}`)
|
||||
} catch (error) {
|
||||
logger.error('Failed to setup webhooks:', error)
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
export async function initializeGiteaForProject(projectName: string) {
|
||||
const owner = process.env.GITEA_OWNER || 'aiworker'
|
||||
|
||||
// Create repository
|
||||
const repo = await giteaClient.createRepo(projectName, {
|
||||
description: `AiWorker project: ${projectName}`,
|
||||
private: true,
|
||||
autoInit: true,
|
||||
defaultBranch: 'main',
|
||||
})
|
||||
|
||||
// Setup webhooks
|
||||
await setupGiteaWebhooks(owner, projectName)
|
||||
|
||||
// Create initial branches
|
||||
await giteaClient.createBranch(owner, projectName, 'develop', 'main')
|
||||
await giteaClient.createBranch(owner, projectName, 'staging', 'main')
|
||||
|
||||
logger.info(`Gitea initialized for project: ${projectName}`)
|
||||
|
||||
return {
|
||||
repoUrl: repo.html_url,
|
||||
cloneUrl: repo.clone_url,
|
||||
sshUrl: repo.ssh_url,
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Backup de Gitea
|
||||
|
||||
```yaml
|
||||
# k8s/gitea/gitea-backup-cronjob.yaml
|
||||
apiVersion: batch/v1
|
||||
kind: CronJob
|
||||
metadata:
|
||||
name: gitea-backup
|
||||
namespace: gitea
|
||||
spec:
|
||||
schedule: "0 2 * * *" # Daily at 2 AM
|
||||
jobTemplate:
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- name: backup
|
||||
image: gitea/gitea:1.22
|
||||
command:
|
||||
- /bin/sh
|
||||
- -c
|
||||
- |
|
||||
echo "Starting backup..."
|
||||
gitea dump -c /data/gitea/conf/app.ini -f /backups/gitea-backup-$(date +%Y%m%d).zip
|
||||
echo "Backup complete!"
|
||||
# Upload to S3 or other storage
|
||||
volumeMounts:
|
||||
- name: data
|
||||
mountPath: /data
|
||||
- name: backups
|
||||
mountPath: /backups
|
||||
volumes:
|
||||
- name: data
|
||||
persistentVolumeClaim:
|
||||
claimName: gitea-data
|
||||
- name: backups
|
||||
persistentVolumeClaim:
|
||||
claimName: gitea-backups
|
||||
restartPolicy: OnFailure
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: gitea-backups
|
||||
namespace: gitea
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
resources:
|
||||
requests:
|
||||
storage: 100Gi
|
||||
```
|
||||
|
||||
## Monitoreo de Gitea
|
||||
|
||||
```yaml
|
||||
# k8s/gitea/gitea-servicemonitor.yaml
|
||||
apiVersion: monitoring.coreos.com/v1
|
||||
kind: ServiceMonitor
|
||||
metadata:
|
||||
name: gitea
|
||||
namespace: gitea
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
app: gitea
|
||||
endpoints:
|
||||
- port: http
|
||||
path: /metrics
|
||||
interval: 30s
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
```bash
|
||||
# Ver logs
|
||||
kubectl logs -n gitea gitea-0 --tail=100 -f
|
||||
|
||||
# Entrar al pod
|
||||
kubectl exec -it -n gitea gitea-0 -- /bin/sh
|
||||
|
||||
# Verificar config
|
||||
kubectl exec -n gitea gitea-0 -- cat /data/gitea/conf/app.ini
|
||||
|
||||
# Regenerar admin user
|
||||
kubectl exec -n gitea gitea-0 -- gitea admin user change-password \
|
||||
--username aiworker --password newpassword
|
||||
|
||||
# Limpiar cache
|
||||
kubectl exec -n gitea gitea-0 -- rm -rf /data/gitea/queues/*
|
||||
```
|
||||
|
||||
## SSH Keys Setup
|
||||
|
||||
```bash
|
||||
# Generar SSH key para agentes
|
||||
ssh-keygen -t ed25519 -C "aiworker-agent" -f agent-key -N ""
|
||||
|
||||
# Crear secret
|
||||
kubectl create secret generic git-ssh-keys -n agents \
|
||||
--from-file=private-key=agent-key \
|
||||
--from-file=public-key=agent-key.pub
|
||||
|
||||
# Añadir public key a Gitea
|
||||
# (via API o manualmente en UI)
|
||||
```
|
||||
|
||||
## Git Config para Agentes
|
||||
|
||||
```yaml
|
||||
# k8s/agents/git-config.yaml
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: git-config
|
||||
namespace: agents
|
||||
data:
|
||||
.gitconfig: |
|
||||
[user]
|
||||
name = AiWorker Agent
|
||||
email = agent@aiworker.dev
|
||||
[core]
|
||||
sshCommand = ssh -i /root/.ssh/id_ed25519 -o StrictHostKeyChecking=no
|
||||
[credential]
|
||||
helper = store
|
||||
```
|
||||
Reference in New Issue
Block a user