Ajout architecture multi-arch

This commit is contained in:
Serge NOEL
2025-12-04 11:08:55 +01:00
parent 2080559f46
commit d04d1748d3
10 changed files with 785 additions and 4 deletions

201
web-gateway/BUILD-ARM64.md Normal file
View File

@@ -0,0 +1,201 @@
# Building for Raspberry Pi 4 (ARM64)
## Quick Start
The web-gateway is **fully compatible** with Raspberry Pi 4 running K3s! 🎉
### Option 1: Build Multi-Arch Image (Recommended)
Build once, run on both x86_64 and ARM64:
```bash
chmod +x build-multiarch.sh
# Build and push to Docker Hub
IMAGE_NAME=yourusername/web-gateway IMAGE_TAG=1.0.0 ./build-multiarch.sh
# Or use default (easylinux/web-gateway:latest)
./build-multiarch.sh
```
### Option 2: Build ARM64 Only
Faster if you only need ARM64:
```bash
chmod +x build-arm64.sh
# Build for ARM64
IMAGE_NAME=yourusername/web-gateway IMAGE_TAG=1.0.0 ./build-arm64.sh
# Push to registry
docker push yourusername/web-gateway:1.0.0
```
### Option 3: Build Natively on Raspberry Pi
Build directly on your RPi 4 (slower but simpler):
```bash
# On your Raspberry Pi 4
docker build -t yourusername/web-gateway:1.0.0 .
docker push yourusername/web-gateway:1.0.0
```
## Deploy to K3s on Raspberry Pi
```bash
# Update values.yaml or use --set
helm install rdp-web-gateway ./chart/rdp-web-gateway \
--namespace rdpbroker \
--create-namespace \
--set image.repository=yourusername/web-gateway \
--set image.tag=1.0.0 \
--set service.type=ClusterIP \
--set traefik.enabled=true \
--set traefik.host=rdp.yourdomain.com \
--set traefik.tls.enabled=true \
--set traefik.tls.certResolver=letsencrypt
```
## Resource Recommendations for Raspberry Pi 4
The default values.yaml may be too high for RPi 4. Use this configuration:
```yaml
# values-rpi4.yaml
resources:
limits:
cpu: 500m # Down from 1000m
memory: 512Mi # Down from 1Gi
requests:
cpu: 100m # Down from 200m
memory: 128Mi # Down from 256Mi
autoscaling:
enabled: true
minReplicas: 1 # Down from 2 (save memory)
maxReplicas: 3 # Down from 10
targetCPUUtilizationPercentage: 70
targetMemoryUtilizationPercentage: 80
replicaCount: 1 # Start with 1 replica
```
Deploy with adjusted resources:
```bash
helm install rdp-web-gateway ./chart/rdp-web-gateway \
--namespace rdpbroker \
-f chart/rdp-web-gateway/examples/traefik-letsencrypt.yaml \
-f values-rpi4.yaml
```
## Performance Notes
- **Node.js Alpine** images are very lightweight (~50MB compressed)
- **Memory footprint**: ~100-200MB per pod under normal load
- **CPU usage**: Very low when idle, spikes during RDP streaming
- **Network**: WebSocket is efficient, ~1-5Mbps per active session
- **Recommended**: 2-4GB RAM Raspberry Pi 4 can handle 3-5 concurrent sessions
## Verify Architecture
After building, verify the image supports ARM64:
```bash
docker buildx imagetools inspect yourusername/web-gateway:1.0.0
```
Expected output:
```
MediaType: application/vnd.docker.distribution.manifest.list.v2+json
Digest: sha256:...
Manifests:
Name: linux/amd64
Digest: sha256:...
Platform: linux/amd64
Name: linux/arm64
Digest: sha256:...
Platform: linux/arm64
```
## Troubleshooting
### Image pull fails on ARM64
```bash
# Check current architecture
uname -m # Should show: aarch64
# Verify image manifest
docker manifest inspect yourusername/web-gateway:1.0.0 | grep architecture
```
### OOMKilled (Out of Memory)
Reduce memory limits or number of replicas:
```yaml
resources:
limits:
memory: 256Mi # Lower if needed
autoscaling:
minReplicas: 1
```
### Build too slow
- Use `build-arm64.sh` instead of `build-multiarch.sh`
- Build on Raspberry Pi 4 itself (native build)
- Use GitHub Actions or CI/CD to build multi-arch images
## GitHub Actions Example
Add `.github/workflows/build.yml`:
```yaml
name: Build Multi-Arch
on:
push:
tags:
- 'v*'
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up QEMU
uses: docker/setup-qemu-action@v2
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Login to DockerHub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v4
with:
context: ./web-gateway
platforms: linux/amd64,linux/arm64
push: true
tags: |
yourusername/web-gateway:latest
yourusername/web-gateway:${{ github.ref_name }}
```
## Additional Notes
- **K3s on RPi 4**: Works perfectly! K3s is optimized for ARM
- **Storage**: Use SSD instead of SD card for better I/O performance
- **Network**: Gigabit Ethernet recommended for RDP streaming
- **Cooling**: Consider a fan/heatsink for sustained load

View File

@@ -295,12 +295,98 @@ The protocol follows a two-phase approach:
## Deployment
See the Helm chart in `chart/rdp-web-gateway/` for Kubernetes deployment.
### Kubernetes with Helm
#### Option 1: LoadBalancer (Default)
```bash
helm install rdp-web-gateway ./chart/rdp-web-gateway -n rdpbroker
# Deploy with LoadBalancer service
helm install rdp-web-gateway ./chart/rdp-web-gateway \
--namespace rdpbroker \
--create-namespace \
--set service.type=LoadBalancer
```
#### Option 2: Traefik IngressRoute with Let's Encrypt
**Recommended for production with automatic HTTPS**
1. **Apply Traefik middlewares** (one time):
```bash
kubectl apply -f chart/rdp-web-gateway/examples/traefik-middlewares.yaml -n rdpbroker
```
2. **Deploy with Traefik IngressRoute**:
```bash
# Edit the host in examples/traefik-letsencrypt.yaml
# Then deploy:
helm install rdp-web-gateway ./chart/rdp-web-gateway \
--namespace rdpbroker \
--create-namespace \
-f chart/rdp-web-gateway/examples/traefik-letsencrypt.yaml
```
Or directly with values:
```bash
helm install rdp-web-gateway ./chart/rdp-web-gateway \
--namespace rdpbroker \
--create-namespace \
--set service.type=ClusterIP \
--set traefik.enabled=true \
--set traefik.host=rdp.yourdomain.com \
--set traefik.tls.enabled=true \
--set traefik.tls.certResolver=letsencrypt
```
3. **Verify deployment**:
```bash
# Check IngressRoute
kubectl get ingressroute -n rdpbroker
# Check certificate (after a few seconds)
kubectl get certificate -n rdpbroker
# Access your gateway
https://rdp.yourdomain.com
```
#### Option 3: Standard Ingress (nginx, etc.)
```bash
helm install rdp-web-gateway ./chart/rdp-web-gateway \
--namespace rdpbroker \
--create-namespace \
--set service.type=ClusterIP \
--set ingress.enabled=true \
--set ingress.className=nginx \
--set ingress.hosts[0].host=rdp.example.com \
--set ingress.hosts[0].paths[0].path=/ \
--set ingress.hosts[0].paths[0].pathType=Prefix
```
### Important Notes for Traefik
**WebSocket Support**: Traefik automatically handles WebSocket upgrades, no special configuration needed!
**Let's Encrypt Certificate Resolver**: Ensure your Traefik has a certResolver named `letsencrypt` configured. Example:
```yaml
# Traefik values.yaml or static config
certificatesResolvers:
letsencrypt:
acme:
email: admin@yourdomain.com
storage: /data/acme.json
httpChallenge:
entryPoint: web
```
**Middlewares**: Apply the recommended middlewares for security:
- `redirect-to-https` - Force HTTPS
- `security-headers` - Security headers including WebSocket support
- `rate-limit` - Prevent abuse
- `compression` - Reduce bandwidth
## Browser Support
- Chrome/Edge 90+
@@ -341,9 +427,11 @@ nc -zv rdpbroker 3389
### WebSocket connection fails
Ensure WebSocket upgrade is allowed through any proxies/load balancers.
Ensure WebSocket upgrade is allowed through proxies/load balancers.
For nginx:
**For Traefik**: Already handled automatically! ✅
**For nginx**:
```nginx
location /ws/ {
proxy_pass http://backend;
@@ -352,6 +440,13 @@ location /ws/ {
proxy_set_header Connection "upgrade";
}
```
**For Traefik middlewares**: Ensure security-headers middleware includes:
```yaml
customResponseHeaders:
Connection: "upgrade"
Upgrade: "$http_upgrade"
```
### High memory usage
Adjust resource limits in Kubernetes values.yaml

49
web-gateway/build-arm64.sh Executable file
View File

@@ -0,0 +1,49 @@
#!/bin/bash
# Build ARM64-only image for Raspberry Pi 4
# Faster build when you only need ARM64
set -e
IMAGE_NAME="${IMAGE_NAME:-easylinux/web-gateway}"
IMAGE_TAG="${IMAGE_TAG:-latest}"
echo "============================================"
echo "Building ARM64 Image for Raspberry Pi 4"
echo "============================================"
echo "Image: ${IMAGE_NAME}:${IMAGE_TAG}"
echo "Platform: linux/arm64"
echo "============================================"
# Check if buildx is available
if ! docker buildx version >/dev/null 2>&1; then
echo "Error: docker buildx not found. Please install Docker Buildx."
exit 1
fi
# Create builder if needed
if ! docker buildx ls | grep -q arm64-builder; then
echo "Creating arm64-builder..."
docker buildx create --name arm64-builder --use --bootstrap
else
echo "Using existing arm64-builder..."
docker buildx use arm64-builder
fi
# Build ARM64 image
echo "Building for ARM64..."
docker buildx build \
--platform linux/arm64 \
--tag "${IMAGE_NAME}:${IMAGE_TAG}" \
--load \
.
echo "============================================"
echo "✅ ARM64 image built successfully!"
echo "============================================"
echo "Image: ${IMAGE_NAME}:${IMAGE_TAG}"
echo ""
echo "Push to registry:"
echo " docker push ${IMAGE_NAME}:${IMAGE_TAG}"
echo ""
echo "Or save as tar:"
echo " docker save ${IMAGE_NAME}:${IMAGE_TAG} | gzip > web-gateway-arm64.tar.gz"

53
web-gateway/build-multiarch.sh Executable file
View File

@@ -0,0 +1,53 @@
#!/bin/bash
# Build multi-architecture Docker image for web-gateway
# Supports: amd64 (x86_64) and arm64 (Raspberry Pi 4, Apple Silicon)
set -e
# Configuration
IMAGE_NAME="${IMAGE_NAME:-easylinux/web-gateway}"
IMAGE_TAG="${IMAGE_TAG:-latest}"
PLATFORMS="${PLATFORMS:-linux/amd64,linux/arm64}"
echo "============================================"
echo "Building Multi-Arch Docker Image"
echo "============================================"
echo "Image: ${IMAGE_NAME}:${IMAGE_TAG}"
echo "Platforms: ${PLATFORMS}"
echo "============================================"
# Check if buildx is available
if ! docker buildx version >/dev/null 2>&1; then
echo "Error: docker buildx not found. Please install Docker Buildx."
echo "See: https://docs.docker.com/buildx/working-with-buildx/"
exit 1
fi
# Create builder instance if it doesn't exist
if ! docker buildx ls | grep -q multiarch-builder; then
echo "Creating multiarch-builder..."
docker buildx create --name multiarch-builder --use --bootstrap
else
echo "Using existing multiarch-builder..."
docker buildx use multiarch-builder
fi
# Build and push multi-arch image
echo "Building for platforms: ${PLATFORMS}..."
docker buildx build \
--platform "${PLATFORMS}" \
--tag "${IMAGE_NAME}:${IMAGE_TAG}" \
--push \
.
echo "============================================"
echo "✅ Multi-arch image built successfully!"
echo "============================================"
echo "Image: ${IMAGE_NAME}:${IMAGE_TAG}"
echo ""
echo "Test on different platforms:"
echo " amd64 (x86_64): docker run --rm ${IMAGE_NAME}:${IMAGE_TAG} node --version"
echo " arm64 (RPi 4): docker run --rm ${IMAGE_NAME}:${IMAGE_TAG} node --version"
echo ""
echo "Verify architectures:"
echo " docker buildx imagetools inspect ${IMAGE_NAME}:${IMAGE_TAG}"

View File

@@ -0,0 +1,108 @@
# Raspberry Pi 4 optimized values for K3s cluster
# Deploy with: helm install rdp-web-gateway ./chart/rdp-web-gateway -f examples/rpi4-k3s.yaml
# Use ClusterIP with Traefik (common on K3s)
service:
type: ClusterIP
port: 80
targetPort: 8080
# Traefik IngressRoute (K3s includes Traefik by default)
traefik:
enabled: true
host: rdp.yourdomain.com
entryPoints:
- websecure
tls:
enabled: true
certResolver: letsencrypt
# Reduced resources for Raspberry Pi 4
resources:
limits:
cpu: 500m # 0.5 CPU core
memory: 512Mi # 512MB RAM
requests:
cpu: 100m # 0.1 CPU core minimum
memory: 128Mi # 128MB RAM minimum
# Conservative autoscaling for RPi cluster
autoscaling:
enabled: true
minReplicas: 1 # Start with 1 pod
maxReplicas: 3 # Max 3 pods (adjust based on cluster size)
targetCPUUtilizationPercentage: 70
targetMemoryUtilizationPercentage: 80
# Start with single replica
replicaCount: 1
# RDP Broker connection (internal ClusterIP)
config:
rdpBroker:
host: "rdpbroker"
port: 3389
server:
port: 8080
# Spread pods across nodes if you have multiple RPi
affinity:
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchExpressions:
- key: app.kubernetes.io/name
operator: In
values:
- rdp-web-gateway
topologyKey: kubernetes.io/hostname
# Optimize for ARM64
podAnnotations:
cluster.autoscaler.kubernetes.io/safe-to-evict: "true"
# Security context
securityContext:
capabilities:
drop:
- ALL
readOnlyRootFilesystem: false
runAsNonRoot: true
runAsUser: 1001
allowPrivilegeEscalation: false
podSecurityContext:
fsGroup: 1001
runAsNonRoot: true
runAsUser: 1001
# Health checks with longer delays for slower RPi startup
livenessProbe:
httpGet:
path: /health
port: http
initialDelaySeconds: 45 # Increased from 30
periodSeconds: 15 # Increased from 10
timeoutSeconds: 5
failureThreshold: 3
readinessProbe:
httpGet:
path: /health
port: http
initialDelaySeconds: 15 # Increased from 10
periodSeconds: 10 # Increased from 5
timeoutSeconds: 3
failureThreshold: 3
# Optional: Node selector for ARM64 nodes only
# nodeSelector:
# kubernetes.io/arch: arm64
# Optional: Tolerate RPi-specific taints
# tolerations:
# - key: "node.kubernetes.io/arm64"
# operator: "Exists"
# effect: "NoSchedule"

View File

@@ -0,0 +1,71 @@
# Example: Traefik with multiple middlewares and custom cert
# Deploy with: helm install rdp-web-gateway ./chart/rdp-web-gateway -f examples/traefik-advanced.yaml
service:
type: ClusterIP
port: 80
targetPort: 8080
traefik:
enabled: true
host: rdp.yourdomain.com
annotations:
# Optional annotations
kubernetes.io/ingress.class: traefik
entryPoints:
- web # HTTP (will redirect to HTTPS)
- websecure # HTTPS
middlewares:
# Redirect HTTP to HTTPS
- name: redirect-to-https
# Add security headers
- name: security-headers
# Rate limiting
- name: rate-limit
tls:
enabled: true
certResolver: letsencrypt
# Specify multiple domains/SANs
domains:
- main: rdp.yourdomain.com
sans:
- www.rdp.yourdomain.com
- rdp-gateway.yourdomain.com
config:
rdpBroker:
host: "rdpbroker"
port: 3389
server:
port: 8080
# Production resource limits
resources:
limits:
cpu: 2000m
memory: 2Gi
requests:
cpu: 500m
memory: 512Mi
# Autoscaling for production
autoscaling:
enabled: true
minReplicas: 3
maxReplicas: 20
targetCPUUtilizationPercentage: 60
targetMemoryUtilizationPercentage: 70
# Pod anti-affinity for high availability
affinity:
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchExpressions:
- key: app.kubernetes.io/name
operator: In
values:
- rdp-web-gateway
topologyKey: kubernetes.io/hostname

View File

@@ -0,0 +1,63 @@
# Example: Traefik with Let's Encrypt
# Deploy with: helm install rdp-web-gateway ./chart/rdp-web-gateway -f examples/traefik-letsencrypt.yaml
# Disable LoadBalancer, use IngressRoute instead
service:
type: ClusterIP
port: 80
targetPort: 8080
# Enable Traefik IngressRoute
traefik:
enabled: true
host: rdp.yourdomain.com
entryPoints:
- websecure # HTTPS entry point
tls:
enabled: true
certResolver: letsencrypt # Must match your Traefik certResolver name
# Optional: Add middlewares
# middlewares:
# - name: redirect-to-https
# - name: rate-limit
# RDP Broker connection (internal ClusterIP)
config:
rdpBroker:
host: "rdpbroker" # Kubernetes service name
port: 3389
server:
port: 8080
# Recommended: Enable network policies for security
networkPolicy:
enabled: true
policyTypes:
- Ingress
- Egress
ingress:
# Allow traffic from Traefik
- from:
- namespaceSelector:
matchLabels:
name: traefik # Adjust to your Traefik namespace
ports:
- protocol: TCP
port: 8080
egress:
# Allow traffic to RdpBroker
- to:
- podSelector:
matchLabels:
app: rdpbroker
ports:
- protocol: TCP
port: 3389
# Allow DNS resolution
- to:
- namespaceSelector:
matchLabels:
name: kube-system
ports:
- protocol: UDP
port: 53

View File

@@ -0,0 +1,71 @@
# Recommended Traefik Middlewares for RDP Web Gateway
# Apply these in your Traefik namespace or the same namespace as web-gateway
---
# Redirect HTTP to HTTPS
apiVersion: traefik.containo.us/v1alpha1
kind: Middleware
metadata:
name: redirect-to-https
spec:
redirectScheme:
scheme: https
permanent: true
---
# Security Headers
apiVersion: traefik.containo.us/v1alpha1
kind: Middleware
metadata:
name: security-headers
spec:
headers:
browserXssFilter: true
contentTypeNosniff: true
forceSTSHeader: true
frameDeny: true
stsIncludeSubdomains: true
stsPreload: true
stsSeconds: 31536000
customFrameOptionsValue: "SAMEORIGIN"
customResponseHeaders:
X-Forwarded-Proto: "https"
# Allow WebSocket upgrade
Connection: "upgrade"
Upgrade: "$http_upgrade"
---
# Rate Limiting (adjust as needed)
apiVersion: traefik.containo.us/v1alpha1
kind: Middleware
metadata:
name: rate-limit
spec:
rateLimit:
average: 100
burst: 50
period: 1s
---
# IP Whitelist (optional - restrict to specific IPs/ranges)
apiVersion: traefik.containo.us/v1alpha1
kind: Middleware
metadata:
name: ip-whitelist
spec:
ipWhiteList:
sourceRange:
- 192.168.1.0/24
- 10.0.0.0/8
# For use behind a proxy/load balancer
ipStrategy:
depth: 1
---
# Compression
apiVersion: traefik.containo.us/v1alpha1
kind: Middleware
metadata:
name: compression
spec:
compress: {}

View File

@@ -0,0 +1,44 @@
{{- if .Values.traefik.enabled -}}
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
name: {{ include "rdp-web-gateway.fullname" . }}
labels:
{{- include "rdp-web-gateway.labels" . | nindent 4 }}
{{- with .Values.traefik.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
entryPoints:
{{- toYaml .Values.traefik.entryPoints | nindent 4 }}
routes:
- match: Host(`{{ .Values.traefik.host }}`)
kind: Rule
services:
- name: {{ include "rdp-web-gateway.fullname" . }}
port: {{ .Values.service.port }}
{{- if .Values.traefik.middlewares }}
middlewares:
{{- toYaml .Values.traefik.middlewares | nindent 6 }}
{{- end }}
{{- if .Values.traefik.tls.enabled }}
tls:
{{- if .Values.traefik.tls.certResolver }}
certResolver: {{ .Values.traefik.tls.certResolver }}
{{- end }}
{{- if .Values.traefik.tls.secretName }}
secretName: {{ .Values.traefik.tls.secretName }}
{{- end }}
{{- if .Values.traefik.tls.domains }}
domains:
{{- range .Values.traefik.tls.domains }}
- main: {{ .main }}
{{- if .sans }}
sans:
{{- toYaml .sans | nindent 10 }}
{{- end }}
{{- end }}
{{- end }}
{{- end }}
{{- end }}

View File

@@ -51,6 +51,32 @@ ingress:
# hosts:
# - rdp.example.com
# Traefik IngressRoute configuration (alternative to standard Ingress)
traefik:
enabled: false
annotations: {}
# Host for the IngressRoute
host: rdp.example.com
# Traefik entryPoints
entryPoints:
- websecure
# Optional middlewares
middlewares: []
# - name: redirect-to-https
# - name: rate-limit
# TLS configuration
tls:
enabled: true
# Use Let's Encrypt cert resolver
certResolver: letsencrypt
# Or use existing secret
secretName: ""
# Optional: Specify domains
domains: []
# - main: rdp.example.com
# sans:
# - www.rdp.example.com
resources:
limits:
cpu: 1000m