feat: add feature branch deployments with per-branch isolation
Enable deploying feature branches into isolated environments on the same k3s cluster. Each branch gets its own namespace (cam-<slug>), PostgreSQL schema, and OpenSearch index prefix for data isolation while sharing the underlying infrastructure. - Make OpenSearch index prefix and DB schema configurable via env vars (defaults preserve existing behavior) - Restructure deploy/ into Kustomize base + overlays (main/feature) - Extend CI to build Docker images for all branches, not just main - Add deploy-feature job with namespace creation, secret copying, Traefik Ingress routing (<slug>-api/ui.cameleer.siegeln.net) - Add cleanup-branch job to remove namespace, PG schema, OS indices on branch deletion - Install required tools (git, jq, curl) in CI deploy containers Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
5
deploy/base/kustomization.yaml
Normal file
5
deploy/base/kustomization.yaml
Normal file
@@ -0,0 +1,5 @@
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
resources:
|
||||
- server.yaml
|
||||
- ui.yaml
|
||||
124
deploy/base/server.yaml
Normal file
124
deploy/base/server.yaml
Normal file
@@ -0,0 +1,124 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: cameleer3-server
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: cameleer3-server
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: cameleer3-server
|
||||
spec:
|
||||
imagePullSecrets:
|
||||
- name: gitea-registry
|
||||
containers:
|
||||
- name: server
|
||||
image: gitea.siegeln.net/cameleer/cameleer3-server:latest
|
||||
ports:
|
||||
- containerPort: 8081
|
||||
env:
|
||||
- name: SPRING_DATASOURCE_URL
|
||||
value: "jdbc:postgresql://postgres.cameleer.svc.cluster.local:5432/cameleer3?currentSchema=$(CAMELEER_DB_SCHEMA)"
|
||||
- name: CAMELEER_DB_SCHEMA
|
||||
value: "public"
|
||||
- name: SPRING_DATASOURCE_USERNAME
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: postgres-credentials
|
||||
key: POSTGRES_USER
|
||||
- name: SPRING_DATASOURCE_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: postgres-credentials
|
||||
key: POSTGRES_PASSWORD
|
||||
- name: OPENSEARCH_URL
|
||||
value: "http://opensearch.cameleer.svc.cluster.local:9200"
|
||||
- name: CAMELEER_OPENSEARCH_INDEX_PREFIX
|
||||
value: "executions-"
|
||||
- name: CAMELEER_AUTH_TOKEN
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: cameleer-auth
|
||||
key: CAMELEER_AUTH_TOKEN
|
||||
- name: CAMELEER_UI_USER
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: cameleer-auth
|
||||
key: CAMELEER_UI_USER
|
||||
optional: true
|
||||
- name: CAMELEER_UI_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: cameleer-auth
|
||||
key: CAMELEER_UI_PASSWORD
|
||||
optional: true
|
||||
- name: CAMELEER_UI_ORIGIN
|
||||
value: "http://localhost:5173"
|
||||
- name: CAMELEER_JWT_SECRET
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: cameleer-auth
|
||||
key: CAMELEER_JWT_SECRET
|
||||
optional: true
|
||||
- name: CAMELEER_OIDC_ENABLED
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: cameleer-oidc
|
||||
key: CAMELEER_OIDC_ENABLED
|
||||
optional: true
|
||||
- name: CAMELEER_OIDC_ISSUER
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: cameleer-oidc
|
||||
key: CAMELEER_OIDC_ISSUER
|
||||
optional: true
|
||||
- name: CAMELEER_OIDC_CLIENT_ID
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: cameleer-oidc
|
||||
key: CAMELEER_OIDC_CLIENT_ID
|
||||
optional: true
|
||||
- name: CAMELEER_OIDC_CLIENT_SECRET
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: cameleer-oidc
|
||||
key: CAMELEER_OIDC_CLIENT_SECRET
|
||||
optional: true
|
||||
resources:
|
||||
requests:
|
||||
memory: "256Mi"
|
||||
cpu: "100m"
|
||||
limits:
|
||||
memory: "512Mi"
|
||||
cpu: "500m"
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /api/v1/health
|
||||
port: 8081
|
||||
initialDelaySeconds: 30
|
||||
periodSeconds: 10
|
||||
timeoutSeconds: 3
|
||||
failureThreshold: 3
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /api/v1/health
|
||||
port: 8081
|
||||
initialDelaySeconds: 10
|
||||
periodSeconds: 5
|
||||
timeoutSeconds: 3
|
||||
failureThreshold: 3
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: cameleer3-server
|
||||
spec:
|
||||
type: ClusterIP
|
||||
selector:
|
||||
app: cameleer3-server
|
||||
ports:
|
||||
- port: 8081
|
||||
targetPort: 8081
|
||||
71
deploy/base/ui.yaml
Normal file
71
deploy/base/ui.yaml
Normal file
@@ -0,0 +1,71 @@
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: cameleer3-ui-config
|
||||
data:
|
||||
config.js: |
|
||||
window.__CAMELEER_CONFIG__ = {
|
||||
apiBaseUrl: 'http://localhost:8081/api/v1',
|
||||
};
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: cameleer3-ui
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: cameleer3-ui
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: cameleer3-ui
|
||||
spec:
|
||||
imagePullSecrets:
|
||||
- name: gitea-registry
|
||||
containers:
|
||||
- name: ui
|
||||
image: gitea.siegeln.net/cameleer/cameleer3-server-ui:latest
|
||||
ports:
|
||||
- containerPort: 80
|
||||
env:
|
||||
- name: CAMELEER_API_URL
|
||||
value: "http://cameleer3-server:8081"
|
||||
volumeMounts:
|
||||
- name: config
|
||||
mountPath: /usr/share/nginx/html/config.js
|
||||
subPath: config.js
|
||||
resources:
|
||||
requests:
|
||||
memory: "32Mi"
|
||||
cpu: "10m"
|
||||
limits:
|
||||
memory: "64Mi"
|
||||
cpu: "100m"
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /healthz
|
||||
port: 80
|
||||
periodSeconds: 10
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /healthz
|
||||
port: 80
|
||||
periodSeconds: 5
|
||||
volumes:
|
||||
- name: config
|
||||
configMap:
|
||||
name: cameleer3-ui-config
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: cameleer3-ui
|
||||
spec:
|
||||
type: ClusterIP
|
||||
selector:
|
||||
app: cameleer3-ui
|
||||
ports:
|
||||
- port: 80
|
||||
targetPort: 80
|
||||
26
deploy/overlays/feature/ingress.yaml
Normal file
26
deploy/overlays/feature/ingress.yaml
Normal file
@@ -0,0 +1,26 @@
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: cameleer-branch-ingress
|
||||
spec:
|
||||
rules:
|
||||
- host: BRANCH_SLUG-api.cameleer.siegeln.net
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: cameleer3-server
|
||||
port:
|
||||
number: 8081
|
||||
- host: BRANCH_SLUG.cameleer.siegeln.net
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: cameleer3-ui
|
||||
port:
|
||||
number: 80
|
||||
30
deploy/overlays/feature/init-job.yaml
Normal file
30
deploy/overlays/feature/init-job.yaml
Normal file
@@ -0,0 +1,30 @@
|
||||
apiVersion: batch/v1
|
||||
kind: Job
|
||||
metadata:
|
||||
name: init-schema
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
restartPolicy: Never
|
||||
containers:
|
||||
- name: init
|
||||
image: postgres:16
|
||||
command: ["sh", "-c"]
|
||||
args:
|
||||
- |
|
||||
PGPASSWORD=$POSTGRES_PASSWORD psql \
|
||||
-h postgres.cameleer.svc.cluster.local \
|
||||
-U $POSTGRES_USER -d cameleer3 \
|
||||
-c "CREATE SCHEMA IF NOT EXISTS BRANCH_SCHEMA"
|
||||
env:
|
||||
- name: POSTGRES_USER
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: postgres-credentials
|
||||
key: POSTGRES_USER
|
||||
- name: POSTGRES_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: postgres-credentials
|
||||
key: POSTGRES_PASSWORD
|
||||
backoffLimit: 3
|
||||
44
deploy/overlays/feature/kustomization.yaml
Normal file
44
deploy/overlays/feature/kustomization.yaml
Normal file
@@ -0,0 +1,44 @@
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
namespace: BRANCH_NAMESPACE
|
||||
resources:
|
||||
- ../../base
|
||||
- ingress.yaml
|
||||
- init-job.yaml
|
||||
images:
|
||||
- name: gitea.siegeln.net/cameleer/cameleer3-server
|
||||
newTag: BRANCH_SHA
|
||||
- name: gitea.siegeln.net/cameleer/cameleer3-server-ui
|
||||
newTag: BRANCH_SHA
|
||||
patches:
|
||||
# Server Deployment: branch-specific schema, index prefix, UI origin, OIDC disabled
|
||||
- patch: |
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: cameleer3-server
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- name: server
|
||||
env:
|
||||
- name: CAMELEER_DB_SCHEMA
|
||||
value: "BRANCH_SCHEMA"
|
||||
- name: CAMELEER_OPENSEARCH_INDEX_PREFIX
|
||||
value: "cam-BRANCH_SLUG-executions-"
|
||||
- name: CAMELEER_UI_ORIGIN
|
||||
value: "http://BRANCH_SLUG.cameleer.siegeln.net"
|
||||
- name: CAMELEER_OIDC_ENABLED
|
||||
value: "false"
|
||||
# UI ConfigMap: branch-specific API URL
|
||||
- target:
|
||||
kind: ConfigMap
|
||||
name: cameleer3-ui-config
|
||||
patch: |
|
||||
- op: replace
|
||||
path: /data/config.js
|
||||
value: |
|
||||
window.__CAMELEER_CONFIG__ = {
|
||||
apiBaseUrl: 'http://BRANCH_SLUG-api.cameleer.siegeln.net/api/v1',
|
||||
};
|
||||
57
deploy/overlays/main/kustomization.yaml
Normal file
57
deploy/overlays/main/kustomization.yaml
Normal file
@@ -0,0 +1,57 @@
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
namespace: cameleer
|
||||
resources:
|
||||
- ../../base
|
||||
patches:
|
||||
# Server Service: NodePort 30081
|
||||
- target:
|
||||
kind: Service
|
||||
name: cameleer3-server
|
||||
patch: |
|
||||
- op: replace
|
||||
path: /spec/type
|
||||
value: NodePort
|
||||
- op: add
|
||||
path: /spec/ports/0/nodePort
|
||||
value: 30081
|
||||
# UI Service: NodePort 30090
|
||||
- target:
|
||||
kind: Service
|
||||
name: cameleer3-ui
|
||||
patch: |
|
||||
- op: replace
|
||||
path: /spec/type
|
||||
value: NodePort
|
||||
- op: add
|
||||
path: /spec/ports/0/nodePort
|
||||
value: 30090
|
||||
# Server Deployment: same-namespace DNS + production UI origin
|
||||
- patch: |
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: cameleer3-server
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- name: server
|
||||
env:
|
||||
- name: SPRING_DATASOURCE_URL
|
||||
value: "jdbc:postgresql://postgres:5432/cameleer3?currentSchema=public"
|
||||
- name: OPENSEARCH_URL
|
||||
value: "http://opensearch:9200"
|
||||
- name: CAMELEER_UI_ORIGIN
|
||||
value: "http://192.168.50.86:30090"
|
||||
# UI ConfigMap: production API URL
|
||||
- target:
|
||||
kind: ConfigMap
|
||||
name: cameleer3-ui-config
|
||||
patch: |
|
||||
- op: replace
|
||||
path: /data/config.js
|
||||
value: |
|
||||
window.__CAMELEER_CONFIG__ = {
|
||||
apiBaseUrl: 'http://192.168.50.86:30081/api/v1',
|
||||
};
|
||||
Reference in New Issue
Block a user