Gateway Stack (Ingress)
Overview
The Gateway Stack provides the entry point for all external traffic into the Kubernetes cluster. It handles SSL/TLS termination, load balancing, routing, and provides a management interface.
Stack Architecture
Components
1. Traefik Ingress Controller
Purpose: Edge router and reverse proxy with automatic HTTPS
Features:
- Automatic SSL/TLS with Let's Encrypt
- HTTP/2 and HTTP/3 support
- WebSocket support
- Load balancing algorithms
- Rate limiting and circuit breakers
- Middleware chain processing
- Prometheus metrics export
Key Configuration:
yaml
# Static Configuration
entryPoints:
web:
address: ":80"
http:
redirections:
entryPoint:
to: websecure
scheme: https
websecure:
address: ":443"
http:
tls:
certResolver: letsencrypt
certificatesResolvers:
letsencrypt:
acme:
email: devops@healthflow.eg
storage: /certificates/acme.json
httpChallenge:
entryPoint: web
providers:
kubernetesIngress: {}
kubernetesCRD: {}
api:
dashboard: true
insecure: false
metrics:
prometheus:
addEntryPointsLabels: true
addServicesLabels: true2. Portainer
Purpose: Web-based Kubernetes management interface
Features:
- Visual stack deployment
- Resource monitoring
- Log viewing
- User/team management
- RBAC integration
- Helm chart management
3. Portainer Agent
Purpose: Collects data from each cluster node
Deployment: DaemonSet (runs on all nodes)
Kubernetes Manifests
Namespace
yaml
apiVersion: v1
kind: Namespace
metadata:
name: gateway-stack
labels:
name: gateway-stack
stack: infrastructureTraefik Deployment
yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: traefik
namespace: gateway-stack
labels:
app: traefik
spec:
replicas: 3
selector:
matchLabels:
app: traefik
template:
metadata:
labels:
app: traefik
spec:
serviceAccountName: traefik
containers:
- name: traefik
image: traefik:v3.2
args:
- --configFile=/config/traefik.yml
ports:
- name: web
containerPort: 80
protocol: TCP
- name: websecure
containerPort: 443
protocol: TCP
- name: metrics
containerPort: 8082
protocol: TCP
- name: dashboard
containerPort: 8080
protocol: TCP
resources:
limits:
cpu: "2"
memory: 2Gi
requests:
cpu: "500m"
memory: 512Mi
volumeMounts:
- name: config
mountPath: /config
- name: certificates
mountPath: /certificates
livenessProbe:
httpGet:
path: /ping
port: 8080
initialDelaySeconds: 10
periodSeconds: 10
readinessProbe:
httpGet:
path: /ping
port: 8080
initialDelaySeconds: 5
periodSeconds: 5
volumes:
- name: config
configMap:
name: traefik-config
- name: certificates
persistentVolumeClaim:
claimName: traefik-certificatesTraefik Service (LoadBalancer)
yaml
apiVersion: v1
kind: Service
metadata:
name: traefik
namespace: gateway-stack
annotations:
service.beta.kubernetes.io/aws-load-balancer-type: nlb
spec:
type: LoadBalancer
selector:
app: traefik
ports:
- name: web
port: 80
targetPort: 80
protocol: TCP
- name: websecure
port: 443
targetPort: 443
protocol: TCPTraefik Ingress (Dashboard)
yaml
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: traefik-dashboard
namespace: gateway-stack
spec:
entryPoints:
- websecure
routes:
- match: Host(`traefik.healthflow.eg`)
kind: Rule
services:
- name: api@internal
kind: TraefikService
middlewares:
- name: dashboard-auth
- name: security-headers
tls:
certResolver: letsencryptMiddleware Configurations
yaml
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
name: security-headers
namespace: gateway-stack
spec:
headers:
customResponseHeaders:
X-Content-Type-Options: "nosniff"
X-Frame-Options: "SAMEORIGIN"
X-XSS-Protection: "1; mode=block"
Referrer-Policy: "strict-origin-when-cross-origin"
stsSeconds: 31536000
stsIncludeSubdomains: true
stsPreload: true
---
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
name: rate-limit
namespace: gateway-stack
spec:
rateLimit:
average: 100
burst: 200
period: 1s
---
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
name: cors-all
namespace: gateway-stack
spec:
headers:
accessControlAllowMethods:
- GET
- POST
- PUT
- DELETE
- PATCH
- OPTIONS
accessControlAllowOriginList:
- https://healthflow.eg
- https://*.healthflow.eg
accessControlAllowHeaders:
- Authorization
- Content-Type
accessControlMaxAge: 3600Portainer Deployment
yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: portainer
namespace: gateway-stack
spec:
replicas: 1
selector:
matchLabels:
app: portainer
template:
metadata:
labels:
app: portainer
spec:
containers:
- name: portainer
image: portainer/portainer-ce:latest
args:
- --http-enabled
ports:
- containerPort: 9000
name: http
- containerPort: 8000
name: edge
volumeMounts:
- name: data
mountPath: /data
resources:
limits:
cpu: "1"
memory: 1Gi
requests:
cpu: "250m"
memory: 256Mi
volumes:
- name: data
persistentVolumeClaim:
claimName: portainer-dataService Dependencies
Environment Variables
Traefik
| Variable | Description | Default | Required |
|---|---|---|---|
TRAEFIK_LOG_LEVEL | Log verbosity | INFO | No |
TRAEFIK_ACCESS_LOG | Enable access logs | true | No |
TRAEFIK_METRICS_PROMETHEUS | Enable Prometheus metrics | true | No |
LETSENCRYPT_EMAIL | Email for SSL certificates | - | Yes |
Portainer
| Variable | Description | Default | Required |
|---|---|---|---|
PORTAINER_ADMIN_PASSWORD | Admin user password hash | - | Yes |
PORTAINER_SNAPSHOT_INTERVAL | Environment snapshot interval | 5m | No |
PORTAINER_SSL_CERT_PATH | Custom SSL certificate path | - | No |
Persistent Volumes
Traefik Certificates
yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: traefik-certificates
namespace: gateway-stack
spec:
accessModes:
- ReadWriteMany
storageClassName: nfs-client
resources:
requests:
storage: 1GiPortainer Data
yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: portainer-data
namespace: gateway-stack
spec:
accessModes:
- ReadWriteOnce
storageClassName: gp3
resources:
requests:
storage: 10GiDeployment Instructions
1. Create Namespace and Secrets
bash
# Create namespace
kubectl create namespace gateway-stack
# Create basic auth secret for Traefik dashboard
htpasswd -nb admin <password> | kubectl create secret generic traefik-auth \
--from-literal=users=$(cat -) \
--namespace gateway-stack
# Create Portainer admin password
kubectl create secret generic portainer-admin \
--from-literal=password='<strong-password>' \
--namespace gateway-stack2. Deploy Traefik
bash
kubectl apply -f traefik/rbac.yaml
kubectl apply -f traefik/config.yaml
kubectl apply -f traefik/pvc.yaml
kubectl apply -f traefik/deployment.yaml
kubectl apply -f traefik/service.yaml
kubectl apply -f traefik/middleware.yaml
kubectl apply -f traefik/ingress.yaml3. Deploy Portainer
bash
kubectl apply -f portainer/pvc.yaml
kubectl apply -f portainer/deployment.yaml
kubectl apply -f portainer/service.yaml
kubectl apply -f portainer/agent-daemonset.yaml
kubectl apply -f portainer/ingress.yaml4. Verify Deployment
bash
# Check pod status
kubectl get pods -n gateway-stack
# Check services
kubectl get svc -n gateway-stack
# Check ingress routes
kubectl get ingressroute -n gateway-stack
# View Traefik logs
kubectl logs -n gateway-stack -l app=traefik -fMonitoring & Health Checks
Traefik Health Endpoints
- Ping:
http://traefik:8080/ping - Dashboard:
https://traefik.healthflow.eg/dashboard/ - Metrics:
http://traefik:8082/metrics
Portainer Access
- UI:
https://portainer.healthflow.eg - API:
https://portainer.healthflow.eg/api
Troubleshooting
Traefik Not Getting Certificates
bash
# Check ACME storage
kubectl exec -n gateway-stack deployment/traefik -- cat /certificates/acme.json
# Verify DNS points to load balancer
nslookup traefik.healthflow.eg
# Check Let's Encrypt rate limits
# https://letsencrypt.org/docs/rate-limits/Portainer Can't Connect to Agent
bash
# Verify agent is running on all nodes
kubectl get pods -n gateway-stack -l app=portainer-agent -o wide
# Check agent logs
kubectl logs -n gateway-stack -l app=portainer-agentNext Steps
- Data Stack - Deploy databases
- Monitoring Stack - Setup observability
- Service Discovery Stack - Deploy Consul & Vault