chore: initial commit of Go API gateway
CI / Test (push) Canceled after 0s
CI / Vet (push) Canceled after 0s
CI / Build (push) Canceled after 0s
CI / Security (govulncheck) (push) Canceled after 0s

Baseline for the Kong replacement on api.riotpiao.com. Brings the working
tree under version control for the first time: gateway source, the task
board that drives the agent runs, test fixtures, and K8s manifests.

Anchor the gateway ignore rule to the repo root. Unanchored, "gateway"
also matched the cmd/gateway/ source directory, so the program entrypoint
was excluded from every commit.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
This commit is contained in:
Story Crater Bot
2026-08-19 20:54:34 -07:00
co-authored by Claude Opus 5
commit 058f11cf2b
109 changed files with 8992 additions and 0 deletions
+38
View File
@@ -0,0 +1,38 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: api-gateway-config
namespace: api
labels:
app: api-gateway
data:
config.yaml: |
# Gateway configuration - loaded at startup, never compiled in
# See REQUIREMENTS.md for full specification
# Routes: standard HTTP proxy routes (not LLM-specific)
# These are for non-LLM services (agent-pod/console, etc.)
routes: []
# Models: LLM model registry for body-based dispatch
# POST /v1/chat/completions routes based on the "model" field in request JSON
models:
- name: "reasoning"
address: "reasoning-predictor.llm-serving:80"
path: "/v1/chat/completions"
- name: "ornith:35b"
address: "ornith-predictor.llm-serving:80"
path: "/v1/chat/completions"
- name: "qwen2.5:3b-instruct"
address: "ornith-predictor.llm-serving:80"
path: "/v1/chat/completions"
- name: "nomic-ai/nomic-embed-text-v2-moe"
address: "embeddings-predictor.llm-serving:80"
path: "/v1/embeddings"
- name: "BAAI/bge-reranker-base"
address: "reranker-predictor.llm-serving:80"
path: "/v1/rerank"
+104
View File
@@ -0,0 +1,104 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: api-gateway
namespace: api
labels:
app: api-gateway
component: gateway
spec:
replicas: 3
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
selector:
matchLabels:
app: api-gateway
template:
metadata:
labels:
app: api-gateway
component: gateway
annotations:
prometheus.io/scrape: "true"
prometheus.io/port: "8080"
prometheus.io/path: "/metrics"
spec:
serviceAccountName: api-gateway
securityContext:
runAsNonRoot: true
runAsUser: 1000
fsGroup: 1000
containers:
- name: gateway
image: ghcr.io/riotpiaole/api-gateway:latest
imagePullPolicy: Always
ports:
- name: http
containerPort: 8080
protocol: TCP
env:
- name: LISTEN_ADDR
value: "0.0.0.0:8080"
- name: CONFIG_PATH
value: "/etc/gateway/config.yaml"
- name: SHUTDOWN_TIMEOUT
value: "5m"
- name: LOG_LEVEL
value: "info"
volumeMounts:
- name: config
mountPath: /etc/gateway
readOnly: true
livenessProbe:
httpGet:
path: /healthz
port: http
scheme: HTTP
initialDelaySeconds: 5
periodSeconds: 10
timeoutSeconds: 2
failureThreshold: 3
readinessProbe:
httpGet:
path: /readyz
port: http
scheme: HTTP
initialDelaySeconds: 5
periodSeconds: 5
timeoutSeconds: 2
failureThreshold: 2
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 500m
memory: 512Mi
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
runAsNonRoot: true
runAsUser: 1000
capabilities:
drop:
- ALL
volumes:
- name: config
configMap:
name: api-gateway-config
affinity:
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchExpressions:
- key: app
operator: In
values:
- api-gateway
topologyKey: kubernetes.io/hostname
terminationGracePeriodSeconds: 300
+20
View File
@@ -0,0 +1,20 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: api
resources:
- rbac.yaml
- service.yaml
- deployment.yaml
- network-policy.yaml
- configmap.yaml
commonLabels:
app: api-gateway
managed-by: argocd
commonAnnotations:
argocd.argoproj.io/sync-wave: "2"
# Wave 2 ensures the gateway is ready before anything that depends on it
# Kong remains on wave 7 unchanged
+68
View File
@@ -0,0 +1,68 @@
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: api-gateway
namespace: api
labels:
app: api-gateway
spec:
podSelector:
matchLabels:
app: api-gateway
policyTypes:
- Ingress
- Egress
ingress:
# Allow from ingress-nginx controller (from ingress-nginx namespace)
- from:
- namespaceSelector:
matchLabels:
name: ingress-nginx
ports:
- protocol: TCP
port: 8080
# Allow from Prometheus scraping (if in monitoring namespace)
- from:
- namespaceSelector:
matchLabels:
name: monitoring
ports:
- protocol: TCP
port: 8080
egress:
# Allow DNS
- to:
- namespaceSelector:
matchLabels:
name: kube-system
ports:
- protocol: UDP
port: 53
# Allow to upstreams (LLM services in llm-serving namespace)
- to:
- namespaceSelector:
matchLabels:
name: llm-serving
ports:
- protocol: TCP
port: 80
- protocol: TCP
port: 8000
- protocol: TCP
port: 8001
# Allow to other upstreams if needed (embeddings, reranker, etc.)
- to:
- namespaceSelector:
matchLabels:
name: llm-serving
ports:
- protocol: TCP
port: 8080
# Allow to atlas (riotpiao-backend) for /cluster/* routes
- to:
- namespaceSelector:
matchLabels:
name: atlas
ports:
- protocol: TCP
port: 8080
+10
View File
@@ -0,0 +1,10 @@
apiVersion: v1
kind: ServiceAccount
metadata:
name: api-gateway
namespace: api
labels:
app: api-gateway
---
# No ClusterRole needed - the gateway has no k8s API access
# G2: The gateway holds no Kubernetes credentials
+18
View File
@@ -0,0 +1,18 @@
apiVersion: v1
kind: Service
metadata:
name: api-gateway
namespace: api
labels:
app: api-gateway
component: gateway
spec:
type: ClusterIP
selector:
app: api-gateway
ports:
- name: http
port: 8080
targetPort: http
protocol: TCP
sessionAffinity: None