- 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>
457 lines
10 KiB
Markdown
457 lines
10 KiB
Markdown
# 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
|
|
```
|