Initial commit: Full Crawl API implementation
Some checks failed
CI / Test (push) Has been cancelled
Deploy / Deploy to Staging (push) Has been cancelled
CI / Build & Push (push) Has been cancelled
Deploy / Deploy to Production (push) Has been cancelled

This commit is contained in:
2026-04-29 07:03:48 +00:00
commit 62994d4f3d
92 changed files with 6176 additions and 0 deletions

97
k8s/api.yaml Normal file
View File

@@ -0,0 +1,97 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: api
namespace: crawlapi
spec:
replicas: 3
selector:
matchLabels:
app: api
template:
metadata:
labels:
app: api
spec:
containers:
- name: api
image: crawlapi/api:latest
ports:
- containerPort: 3000
env:
- name: DATABASE_URL
value: "postgres://$(POSTGRES_USER):$(POSTGRES_PASSWORD)@postgres:5432/crawlapi"
- name: REDIS_URL
value: "redis://redis:6379"
- name: S3_ENDPOINT
value: "http://minio:9000"
- name: S3_BUCKET
value: "crawlapi"
- name: PLAYWRIGHT_SCRIPT_PATH
value: "/app/playwright/pool.js"
envFrom:
- secretRef:
name: crawlapi-secrets
resources:
requests:
memory: "256Mi"
cpu: "250m"
limits:
memory: "512Mi"
cpu: "500m"
livenessProbe:
httpGet:
path: /metrics
port: 3000
initialDelaySeconds: 10
periodSeconds: 30
readinessProbe:
httpGet:
path: /metrics
port: 3000
initialDelaySeconds: 5
periodSeconds: 10
startupProbe:
httpGet:
path: /metrics
port: 3000
failureThreshold: 30
periodSeconds: 10
---
apiVersion: v1
kind: Service
metadata:
name: api
namespace: crawlapi
spec:
selector:
app: api
ports:
- port: 3000
targetPort: 3000
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: api
namespace: crawlapi
annotations:
nginx.ingress.kubernetes.io/ssl-redirect: "true"
cert-manager.io/cluster-issuer: letsencrypt
spec:
ingressClassName: nginx
tls:
- hosts:
- api.crawlapi.dev
secretName: api-tls
rules:
- host: api.crawlapi.dev
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: api
port:
number: 3000

30
k8s/cert-manager.yaml Normal file
View File

@@ -0,0 +1,30 @@
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt
spec:
acme:
server: https://acme-v02.api.letsencrypt.org/directory
email: admin@crawlapi.dev
privateKeySecretRef:
name: letsencrypt-private-key
solvers:
- http01:
ingress:
class: nginx
---
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: crawlapi-tls
namespace: crawlapi
spec:
secretName: crawlapi-tls-secret
issuerRef:
name: letsencrypt
kind: ClusterIssuer
dnsNames:
- crawlapi.dev
- www.crawlapi.dev
- api.crawlapi.dev
- status.crawlapi.dev

63
k8s/frontend.yaml Normal file
View File

@@ -0,0 +1,63 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: frontend
namespace: crawlapi
spec:
replicas: 2
selector:
matchLabels:
app: frontend
template:
metadata:
labels:
app: frontend
spec:
containers:
- name: frontend
image: crawlapi/frontend:latest
ports:
- containerPort: 3000
resources:
requests:
memory: "128Mi"
cpu: "100m"
---
apiVersion: v1
kind: Service
metadata:
name: frontend
namespace: crawlapi
spec:
selector:
app: frontend
ports:
- port: 3000
targetPort: 3000
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: frontend
namespace: crawlapi
annotations:
nginx.ingress.kubernetes.io/ssl-redirect: "true"
cert-manager.io/cluster-issuer: letsencrypt
spec:
ingressClassName: nginx
tls:
- hosts:
- crawlapi.dev
- www.crawlapi.dev
secretName: frontend-tls
rules:
- host: crawlapi.dev
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: frontend
port:
number: 3000

67
k8s/minio.yaml Normal file
View File

@@ -0,0 +1,67 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: minio
namespace: crawlapi
spec:
replicas: 1
selector:
matchLabels:
app: minio
template:
metadata:
labels:
app: minio
spec:
containers:
- name: minio
image: minio/minio:latest
command: ["server", "/data", "--console-address", ":9001"]
env:
- name: MINIO_ROOT_USER
valueFrom:
secretKeyRef:
name: crawlapi-secrets
key: minio-access-key
- name: MINIO_ROOT_PASSWORD
valueFrom:
secretKeyRef:
name: crawlapi-secrets
key: minio-secret-key
ports:
- containerPort: 9000
- containerPort: 9001
volumeMounts:
- name: minio-storage
mountPath: /data
volumes:
- name: minio-storage
persistentVolumeClaim:
claimName: minio-pvc
---
apiVersion: v1
kind: Service
metadata:
name: minio
namespace: crawlapi
spec:
selector:
app: minio
ports:
- name: api
port: 9000
targetPort: 9000
- name: console
port: 9001
targetPort: 9001
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: minio-pvc
namespace: crawlapi
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 50Gi

4
k8s/namespace.yaml Normal file
View File

@@ -0,0 +1,4 @@
apiVersion: v1
kind: Namespace
metadata:
name: crawlapi

57
k8s/postgres.yaml Normal file
View File

@@ -0,0 +1,57 @@
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: postgres
namespace: crawlapi
spec:
serviceName: postgres
replicas: 1
selector:
matchLabels:
app: postgres
template:
metadata:
labels:
app: postgres
spec:
containers:
- name: postgres
image: postgres:16-alpine
env:
- name: POSTGRES_USER
valueFrom:
secretKeyRef:
name: crawlapi-secrets
key: postgres-user
- name: POSTGRES_PASSWORD
valueFrom:
secretKeyRef:
name: crawlapi-secrets
key: postgres-password
- name: POSTGRES_DB
value: crawlapi
ports:
- containerPort: 5432
volumeMounts:
- name: postgres-storage
mountPath: /var/lib/postgresql/data
volumeClaimTemplates:
- metadata:
name: postgres-storage
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 10Gi
---
apiVersion: v1
kind: Service
metadata:
name: postgres
namespace: crawlapi
spec:
selector:
app: postgres
ports:
- port: 5432
targetPort: 5432

32
k8s/redis.yaml Normal file
View File

@@ -0,0 +1,32 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: redis
namespace: crawlapi
spec:
replicas: 1
selector:
matchLabels:
app: redis
template:
metadata:
labels:
app: redis
spec:
containers:
- name: redis
image: redis:7-alpine
ports:
- containerPort: 6379
---
apiVersion: v1
kind: Service
metadata:
name: redis
namespace: crawlapi
spec:
selector:
app: redis
ports:
- port: 6379
targetPort: 6379

18
k8s/secrets.yaml Normal file
View File

@@ -0,0 +1,18 @@
apiVersion: v1
kind: Secret
metadata:
name: crawlapi-secrets
namespace: crawlapi
type: Opaque
stringData:
postgres-user: "crawlapi"
postgres-password: "changeme"
jwt-secret: "super-secret-jwt-key"
minio-access-key: "minioadmin"
minio-secret-key: "minioadmin"
s3-access-key: "minioadmin"
s3-secret-key: "minioadmin"
stripe-secret-key: "sk_test_..."
stripe-webhook-secret: "whsec_..."
google-client-id: ""
google-client-secret: ""

69
k8s/worker.yaml Normal file
View File

@@ -0,0 +1,69 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: worker
namespace: crawlapi
spec:
replicas: 5
selector:
matchLabels:
app: worker
template:
metadata:
labels:
app: worker
spec:
containers:
- name: worker
image: crawlapi/worker:latest
env:
- name: DATABASE_URL
value: "postgres://$(POSTGRES_USER):$(POSTGRES_PASSWORD)@postgres:5432/crawlapi"
- name: REDIS_URL
value: "redis://redis:6379"
- name: S3_ENDPOINT
value: "http://minio:9000"
- name: S3_BUCKET
value: "crawlapi"
- name: PLAYWRIGHT_SCRIPT_PATH
value: "/app/playwright/pool.js"
- name: BROWSER_POOL_SIZE
value: "5"
- name: MAX_PAGES_PER_BROWSER
value: "10"
envFrom:
- secretRef:
name: crawlapi-secrets
resources:
requests:
memory: "512Mi"
cpu: "500m"
limits:
memory: "2Gi"
cpu: "2000m"
---
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: worker-hpa
namespace: crawlapi
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: worker
minReplicas: 3
maxReplicas: 20
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 80