Kubernetes Deployment
This guide covers deploying AASPortal in Kubernetes environments, including support for ingress sub-path deployment.
Table of Contents
Prerequisites
Kubernetes cluster (v1.20+)
kubectl configured to access your cluster
Container registry access (DockerHub or private registry)
Ingress controller (nginx-ingress recommended)
Basic Deployment
Simple Root Path Deployment
Deploy AASPortal at the root path (/):
apiVersion: apps/v1
kind: Deployment
metadata:
name: aas-portal
namespace: aasportal
labels:
app: aas-portal
spec:
replicas: 1
selector:
matchLabels:
app: aas-portal
template:
metadata:
labels:
app: aas-portal
spec:
containers:
- name: aas-portal
image: fraunhoferiosb/aasportal:latest
env:
- name: JWT_SECRET
value: "change-this-secret-in-production" # REQUIRED for authentication
- name: ENDPOINTS
value: '["file:///endpoints/samples?name=Samples"]' # Optional: sample data
ports:
- containerPort: 80
name: http
resources:
requests:
memory: "512Mi"
cpu: "250m"
limits:
memory: "1Gi"
cpu: "500m"
livenessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 5
periodSeconds: 5
---
apiVersion: v1
kind: Service
metadata:
name: aas-portal-service
namespace: aasportal
spec:
selector:
app: aas-portal
ports:
- protocol: TCP
port: 80
targetPort: 80
type: ClusterIP
Apply the deployment:
kubectl create namespace aasportal
kubectl apply -f deployment.yaml
Important:
JWT_SECRETis required for user authentication (login/register) to workAlways use a strong, unique secret in production environments
Consider using Kubernetes Secrets instead of plain environment variables (see Environment Variables section)
Ingress Configuration
Root Path Ingress
Simple ingress for root path deployment:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: aas-portal-ingress
namespace: aasportal
annotations:
kubernetes.io/ingress.class: nginx
spec:
rules:
- host: aasportal.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: aas-portal-service
port:
number: 80
Sub-Path Deployment with BASE_HREF
New in v2.0: AASPortal supports deployment under any sub-path using the BASE_HREF environment variable.
Step 1: Configure Deployment with BASE_HREF
apiVersion: apps/v1
kind: Deployment
metadata:
name: aas-portal
namespace: aasportal
spec:
template:
spec:
containers:
- name: aas-portal
image: fraunhoferiosb/aasportal:latest
env:
- name: BASE_HREF
value: "/aasportal/" # Must end with /
ports:
- containerPort: 80
Step 2: Configure Ingress with Path Rewriting
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: aas-portal-ingress
namespace: aasportal
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/rewrite-target: /$2
spec:
rules:
- host: services.example.com
http:
paths:
- path: /aasportal(/|$)(.*)
pathType: ImplementationSpecific
backend:
service:
name: aas-portal-service
port:
number: 80
Important Notes:
BASE_HREFvalue must match the ingress path (e.g.,/aasportal/)Both values must end with a trailing slash (
/)The ingress annotation
nginx.ingress.kubernetes.io/rewrite-target: /$2is required for proper routing
Example: Multiple Applications Under Different Paths
You can deploy multiple instances of AASPortal or other applications under different paths:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: multi-service-ingress
namespace: aasportal
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/rewrite-target: /$2
spec:
rules:
- host: services.example.com
http:
paths:
# AASPortal for production
- path: /aasportal(/|$)(.*)
pathType: ImplementationSpecific
backend:
service:
name: aas-portal-prod-service
port:
number: 80
# AASPortal for development
- path: /aasportal-dev(/|$)(.*)
pathType: ImplementationSpecific
backend:
service:
name: aas-portal-dev-service
port:
number: 80
Remember to set the corresponding BASE_HREF in each deployment:
Production:
BASE_HREF=/aasportal/Development:
BASE_HREF=/aasportal-dev/
TLS/HTTPS Configuration
Enable HTTPS with cert-manager:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: aas-portal-ingress
namespace: aasportal
annotations:
kubernetes.io/ingress.class: nginx
cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
tls:
- hosts:
- aasportal.example.com
secretName: aas-portal-tls
rules:
- host: aasportal.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: aas-portal-service
port:
number: 80
Environment Variables
AASPortal supports the following Kubernetes-specific environment variables:
Frontend Configuration
Variable |
Description |
Default |
Required |
|---|---|---|---|
|
Base path for the application (e.g., |
|
No |
Example:
env:
- name: BASE_HREF
value: "/aasportal/"
Backend Configuration
Variable |
Description |
Default |
Required |
|---|---|---|---|
|
Port where AASNode listens |
|
No |
|
MongoDB connection string for user management |
|
No |
|
Initial AAS container endpoints (JSON array) |
|
No |
|
Secret for JWT token signing |
- |
Yes |
|
Allowed CORS origins |
|
No |
|
Number of background workers |
|
No |
Example with ConfigMap:
apiVersion: v1
kind: ConfigMap
metadata:
name: aas-portal-config
namespace: aasportal
data:
BASE_HREF: "/aasportal/"
AAS_NODE_PORT: "80"
ENDPOINTS: '["https://aas-server.example.com"]'
---
apiVersion: apps/v1
kind: Deployment
spec:
template:
spec:
containers:
- name: aas-portal
envFrom:
- configMapRef:
name: aas-portal-config
Example with Secrets:
apiVersion: v1
kind: Secret
metadata:
name: aas-portal-secrets
namespace: aasportal
type: Opaque
stringData:
JWT_SECRET: "your-super-secret-jwt-key-change-in-production"
USER_STORAGE: "mongodb://username:password@mongodb:27017/aasportal-users"
---
apiVersion: apps/v1
kind: Deployment
spec:
template:
spec:
containers:
- name: aas-portal
envFrom:
- secretRef:
name: aas-portal-secrets
High Availability Setup
Horizontal Pod Autoscaling
Enable automatic scaling based on CPU usage:
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: aas-portal-hpa
namespace: aasportal
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: aas-portal
minReplicas: 2
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 80
Pod Disruption Budget
Ensure availability during cluster maintenance:
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: aas-portal-pdb
namespace: aasportal
spec:
minAvailable: 1
selector:
matchLabels:
app: aas-portal
Multi-Zone Deployment
Distribute pods across availability zones:
apiVersion: apps/v1
kind: Deployment
metadata:
name: aas-portal
namespace: aasportal
spec:
replicas: 3
template:
spec:
affinity:
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchLabels:
app: aas-portal
topologyKey: topology.kubernetes.io/zone
Monitoring and Logging
Prometheus Monitoring
Add Prometheus annotations for metrics collection:
apiVersion: apps/v1
kind: Deployment
spec:
template:
metadata:
annotations:
prometheus.io/scrape: "true"
prometheus.io/port: "80"
prometheus.io/path: "/metrics"
Centralized Logging
Configure log collection with Fluent Bit:
apiVersion: apps/v1
kind: Deployment
spec:
template:
metadata:
annotations:
fluentbit.io/parser: json
spec:
containers:
- name: aas-portal
env:
- name: LOG_FORMAT
value: "json"
- name: LOG_LEVEL
value: "info"
Troubleshooting
Common Issues
1. Assets Not Loading Under Sub-Path
Symptom: CSS, JavaScript, or images return 404 when deployed under a sub-path.
Solution: Ensure BASE_HREF is set correctly:
# Check pod environment
kubectl exec -it <pod-name> -n aasportal -- env | grep BASE_HREF
# Check container logs for BASE_HREF setting
kubectl logs <pod-name> -n aasportal | grep "Setting BASE_HREF"
Expected output:
Setting BASE_HREF to: /aasportal/
2. Ingress Path Not Working
Symptom: Application returns 404 or shows wrong content.
Solution: Verify ingress configuration:
# Check ingress status
kubectl get ingress -n aasportal
kubectl describe ingress aas-portal-ingress -n aasportal
# Check ingress controller logs
kubectl logs -n ingress-nginx <ingress-controller-pod>
Ensure:
Path regex matches:
/aasportal(/|$)(.*)Rewrite target is set:
nginx.ingress.kubernetes.io/rewrite-target: /$2BASE_HREFmatches ingress path
3. Pod Crashes or Restarts
Symptom: Pods are in CrashLoopBackOff state.
Solution: Check pod logs and events:
# View recent logs
kubectl logs <pod-name> -n aasportal --tail=100
# View events
kubectl describe pod <pod-name> -n aasportal
# Check resource usage
kubectl top pod <pod-name> -n aasportal
4. CORS Issues
Symptom: Browser console shows CORS errors.
Solution: Configure CORS_ORIGIN environment variable:
env:
- name: CORS_ORIGIN
value: "https://aasportal.example.com"
Debugging Commands
# Get all resources
kubectl get all -n aasportal
# Check pod status
kubectl get pods -n aasportal -o wide
# View detailed pod information
kubectl describe pod <pod-name> -n aasportal
# Execute commands in pod
kubectl exec -it <pod-name> -n aasportal -- /bin/sh
# Port forward for local testing
kubectl port-forward -n aasportal service/aas-portal-service 8080:80
# View config.js content (verify BASE_HREF injection)
kubectl exec <pod-name> -n aasportal -- cat /usr/share/nginx/html/config.js
Health Checks
Verify deployment health:
# Check deployment status
kubectl rollout status deployment/aas-portal -n aasportal
# Test service connectivity
kubectl run -it --rm debug --image=busybox --restart=Never -n aasportal -- \
wget -O- http://aas-portal-service/
# Test from outside cluster (if using LoadBalancer)
curl -I http://<external-ip>/
Migration from Docker Compose
If you’re migrating from Docker Compose to Kubernetes:
Environment Variables: Convert
.envfiles to ConfigMaps and SecretsVolumes: Replace Docker volumes with PersistentVolumeClaims
Networking: Replace Docker networks with Kubernetes Services
Health Checks: Convert Docker healthchecks to Kubernetes probes
Example PersistentVolumeClaim for data persistence:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: aas-portal-data
namespace: aasportal
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
storageClassName: standard