🚀 Complete automation pipeline with SSL, testing, and deployment

 Features:
- Full SSL setup with Let's Encrypt for all environments
- Automated CI/CD pipeline with GitHub Actions
- Comprehensive smoke testing workflow
- Auto-deploy to dev on main branch push
- Manual staging/production deployments with confirmation
- Istio + nginx SSL termination architecture

🔧 Infrastructure:
- Migrated from Kourier to Istio for Knative ingress
- nginx handles SSL termination and public traffic
- Istio manages internal Knative service routing
- Scale-to-zero configuration for all environments

🧪 Testing:
- SSL certificate validation and expiry checks
- Domain accessibility and content validation
- Performance testing and redirect behavior validation
- Automated smoke tests on every deployment

🌐 Domains:
- Dev: https://2048-dev.wa.darknex.us
- Staging: https://2048-staging.wa.darknex.us
- Production: https://2048.wa.darknex.us

📦 Deployment:
- Uses latest GHCR images with imagePullPolicy: Always
- Automated secret management across namespaces
- Environment-specific Knative service configurations
- Clean manifest structure with proper labeling
This commit is contained in:
Greg
2025-06-30 22:57:36 -07:00
parent f42d04f06e
commit 3dbb1d51e8
22 changed files with 1094 additions and 460 deletions

View File

@@ -1,20 +0,0 @@
apiVersion: networking.internal.knative.dev/v1alpha1
kind: ClusterDomainClaim
metadata:
name: 2048-dev.wa.darknex.us
spec:
namespace: game-2048-dev
---
apiVersion: networking.internal.knative.dev/v1alpha1
kind: ClusterDomainClaim
metadata:
name: 2048-staging.wa.darknex.us
spec:
namespace: game-2048-staging
---
apiVersion: networking.internal.knative.dev/v1alpha1
kind: ClusterDomainClaim
metadata:
name: 2048.wa.darknex.us
spec:
namespace: game-2048-prod

View File

@@ -1,15 +0,0 @@
apiVersion: serving.knative.dev/v1beta1
kind: DomainMapping
metadata:
name: 2048-dev.wa.darknex.us
namespace: game-2048-dev
labels:
app: game-2048
environment: development
spec:
ref:
name: game-2048-dev
kind: Service
apiVersion: serving.knative.dev/v1
tls:
secretName: game-2048-dev-cert-secret

View File

@@ -9,45 +9,18 @@ metadata:
spec:
template:
metadata:
labels:
app: game-2048
environment: development
annotations:
# Scale to zero configuration
autoscaling.knative.dev/minScale: "0"
autoscaling.knative.dev/maxScale: "10"
autoscaling.knative.dev/scaleDownDelay: "30s"
autoscaling.knative.dev/target: "100"
spec:
containers:
- name: game-2048
image: ghcr.io/ghndrx/k8s-game-2048:latest
- image: ghcr.io/ghndrx/k8s-game-2048:latest
imagePullPolicy: Always
ports:
- containerPort: 8080
protocol: TCP
- containerPort: 80
env:
- name: ENVIRONMENT
value: "development"
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 500m
memory: 256Mi
readinessProbe:
httpGet:
path: /
port: 8080
initialDelaySeconds: 5
periodSeconds: 10
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 15
periodSeconds: 20
traffic:
- percent: 100
latestRevision: true
imagePullSecrets:
- name: ghcr-secret

View File

@@ -0,0 +1,20 @@
apiVersion: networking.istio.io/v1beta1
kind: Gateway
metadata:
name: knative-ingress-gateway
namespace: knative-serving
labels:
app.kubernetes.io/component: net-istio
app.kubernetes.io/name: knative-serving
app.kubernetes.io/version: 1.12.0
networking.knative.dev/ingress-provider: istio
spec:
selector:
istio: ingressgateway
servers:
- hosts:
- '*'
port:
name: http
number: 80
protocol: HTTP

View File

@@ -4,5 +4,13 @@ metadata:
name: config-domain
namespace: knative-serving
data:
wa.darknex.us: ""
dev.wa.darknex.us: |
selector:
environment: development
staging.wa.darknex.us: |
selector:
environment: staging
wa.darknex.us: |
selector:
environment: production
autocreate-cluster-domain-claims: "true"

View File

@@ -1,15 +0,0 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: config-kourier
namespace: knative-serving
data:
_example: |
################################
# #
# EXAMPLE CONFIGURATION #
# #
################################
enable-service-links: "false"
# Enable automatic HTTP to HTTPS redirect
ssl-redirect: "true"

View File

@@ -0,0 +1,40 @@
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: game-2048-dev-nginx-cert
namespace: default
spec:
secretName: game-2048-dev-nginx-tls
issuerRef:
name: letsencrypt-prod
kind: ClusterIssuer
dnsNames:
- "2048-dev.wa.darknex.us"
---
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: game-2048-staging-nginx-cert
namespace: default
spec:
secretName: game-2048-staging-nginx-tls
issuerRef:
name: letsencrypt-prod
kind: ClusterIssuer
dnsNames:
- "2048-staging.wa.darknex.us"
---
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: game-2048-prod-nginx-cert
namespace: default
spec:
secretName: game-2048-prod-nginx-tls
issuerRef:
name: letsencrypt-prod
kind: ClusterIssuer
dnsNames:
- "2048.wa.darknex.us"

View File

@@ -0,0 +1,119 @@
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: game-2048-dev-proxy
namespace: default
annotations:
nginx.ingress.kubernetes.io/ssl-redirect: "true"
nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
cert-manager.io/cluster-issuer: "letsencrypt-prod"
nginx.ingress.kubernetes.io/backend-protocol: "HTTP"
nginx.ingress.kubernetes.io/configuration-snippet: |
proxy_set_header Host game-2048-dev.game-2048-dev.dev.wa.darknex.us;
spec:
ingressClassName: nginx
tls:
- hosts:
- 2048-dev.wa.darknex.us
secretName: game-2048-dev-nginx-tls
rules:
- host: 2048-dev.wa.darknex.us
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: istio-nodeport-service
port:
number: 80
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: game-2048-staging-proxy
namespace: default
annotations:
nginx.ingress.kubernetes.io/ssl-redirect: "true"
nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
cert-manager.io/cluster-issuer: "letsencrypt-prod"
nginx.ingress.kubernetes.io/backend-protocol: "HTTP"
nginx.ingress.kubernetes.io/configuration-snippet: |
proxy_set_header Host game-2048-staging.game-2048-staging.staging.wa.darknex.us;
spec:
ingressClassName: nginx
tls:
- hosts:
- 2048-staging.wa.darknex.us
secretName: game-2048-staging-nginx-tls
rules:
- host: 2048-staging.wa.darknex.us
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: istio-nodeport-service
port:
number: 80
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: game-2048-prod-proxy
namespace: default
annotations:
nginx.ingress.kubernetes.io/ssl-redirect: "true"
nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
cert-manager.io/cluster-issuer: "letsencrypt-prod"
nginx.ingress.kubernetes.io/backend-protocol: "HTTP"
nginx.ingress.kubernetes.io/configuration-snippet: |
proxy_set_header Host game-2048-prod.game-2048-prod.wa.darknex.us;
spec:
ingressClassName: nginx
tls:
- hosts:
- 2048.wa.darknex.us
secretName: game-2048-prod-nginx-tls
rules:
- host: 2048.wa.darknex.us
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: istio-nodeport-service
port:
number: 80
---
apiVersion: v1
kind: Service
metadata:
name: istio-nodeport-service
namespace: default
spec:
ports:
- name: http
port: 80
targetPort: 32135
protocol: TCP
clusterIP: None
---
apiVersion: v1
kind: Endpoints
metadata:
name: istio-nodeport-service
namespace: default
subsets:
- addresses:
- ip: 192.168.4.134 # Your k3s node IP
ports:
- name: http
port: 32135

View File

@@ -1,15 +0,0 @@
apiVersion: serving.knative.dev/v1beta1
kind: DomainMapping
metadata:
name: 2048.wa.darknex.us
namespace: game-2048-prod
labels:
app: game-2048
environment: production
spec:
ref:
name: game-2048-prod
kind: Service
apiVersion: serving.knative.dev/v1
tls:
secretName: game-2048-prod-cert-secret

View File

@@ -9,45 +9,18 @@ metadata:
spec:
template:
metadata:
labels:
app: game-2048
environment: production
annotations:
# Scale to zero configuration
autoscaling.knative.dev/minScale: "0"
autoscaling.knative.dev/maxScale: "50"
autoscaling.knative.dev/scaleDownDelay: "300s"
autoscaling.knative.dev/maxScale: "10"
autoscaling.knative.dev/target: "100"
spec:
containers:
- name: game-2048
image: ghcr.io/ghndrx/k8s-game-2048:latest
- image: ghcr.io/ghndrx/k8s-game-2048:latest
imagePullPolicy: Always
ports:
- containerPort: 8080
protocol: TCP
- containerPort: 80
env:
- name: ENVIRONMENT
value: "production"
resources:
requests:
cpu: 500m
memory: 512Mi
limits:
cpu: 2000m
memory: 1Gi
readinessProbe:
httpGet:
path: /
port: 8080
initialDelaySeconds: 5
periodSeconds: 10
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 15
periodSeconds: 20
traffic:
- percent: 100
latestRevision: true
imagePullSecrets:
- name: ghcr-secret

View File

@@ -12,45 +12,3 @@ spec:
- http01:
ingress:
class: nginx
- http01:
ingress:
class: nginx
---
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: game-2048-dev-cert
namespace: knative-serving
spec:
secretName: game-2048-dev-cert-secret
issuerRef:
name: letsencrypt-prod
kind: ClusterIssuer
dnsNames:
- "2048-dev.wa.darknex.us"
---
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: game-2048-staging-cert
namespace: knative-serving
spec:
secretName: game-2048-staging-cert-secret
issuerRef:
name: letsencrypt-prod
kind: ClusterIssuer
dnsNames:
- "2048-staging.wa.darknex.us"
---
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: game-2048-prod-cert
namespace: knative-serving
spec:
secretName: game-2048-prod-cert-secret
issuerRef:
name: letsencrypt-prod
kind: ClusterIssuer
dnsNames:
- "2048.wa.darknex.us"

View File

@@ -1,15 +0,0 @@
apiVersion: serving.knative.dev/v1beta1
kind: DomainMapping
metadata:
name: 2048-staging.wa.darknex.us
namespace: game-2048-staging
labels:
app: game-2048
environment: staging
spec:
ref:
name: game-2048-staging
kind: Service
apiVersion: serving.knative.dev/v1
tls:
secretName: game-2048-staging-cert-secret

View File

@@ -9,45 +9,18 @@ metadata:
spec:
template:
metadata:
labels:
app: game-2048
environment: staging
annotations:
# Scale to zero configuration
autoscaling.knative.dev/minScale: "0"
autoscaling.knative.dev/maxScale: "20"
autoscaling.knative.dev/scaleDownDelay: "60s"
autoscaling.knative.dev/maxScale: "10"
autoscaling.knative.dev/target: "100"
spec:
containers:
- name: game-2048
image: ghcr.io/ghndrx/k8s-game-2048:latest
- image: ghcr.io/ghndrx/k8s-game-2048:latest
imagePullPolicy: Always
ports:
- containerPort: 8080
protocol: TCP
- containerPort: 80
env:
- name: ENVIRONMENT
value: "staging"
resources:
requests:
cpu: 200m
memory: 256Mi
limits:
cpu: 1000m
memory: 512Mi
readinessProbe:
httpGet:
path: /
port: 8080
initialDelaySeconds: 5
periodSeconds: 10
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 15
periodSeconds: 20
traffic:
- percent: 100
latestRevision: true
imagePullSecrets:
- name: ghcr-secret