Introducción al Balanceo de Carga de Capa 7
Los servicios de Kubernetes, tanto ClusterIP como NodePort, operan exculsivamente en la capa de transporte (L4). Para lograr balanceo de carga basado en HTTP/HTTPS y routing avanzado, es necesario implementar un controlador de Ingress que funcione en la capa 7 del modelo OSI. Existen múltiples implementaciones disponibles: NGINX, Contour, HAProxy, Traefik y Istio, cada una con características distintivas.
Componentes Principales de Ingress-NGINX
- controlador-ingress: Procesa las reglas definidas en objetos Ingress y actualiza dinámicamente la configuración del servidor web mediante scripts automatizados
- Objeto Ingress: Representa abstracción para mapear tráfico externo a servicios internos según dominio y ruta URL
- Controlador: Componente responsable de escuchar sockets y enrutar solicitudes siguiendo políticas definidas en recursos Ingress
Las ventajas clave incluyen consolidación de puertos expuestos (un solo punto de entrada), gestión centralizada mediante nombres de dominio y simplificación en el escalado de nuevas aplicaciones sin modificaciones adicionales de infraestructura.
Estructura de Infraestructura
| Servidor | Función | Dirección IP | Rol |
|---|---|---|---|
| node-primary.cluster.local | Ingress Controller + Traefik | 192.168.10.21 | Nodo Worker |
| node-secondary.cluster.local | Ingress Controller + Traefik | 192.168.10.22 | Nodo Worker |
| loadbalancer-dns.cluster.local | Balanceador L7 + DNS | 192.168.10.11 | Máquina Proxy |
| loadbalancer-cluster.cluster.local | Balanceador L7 | 192.168.10.12 | Máquina Proxy |
| admin-host.cluster.local | Despliegue de Manifiestos | 192.168.10.200 | Servidor Operaciones |
Preparación del Contenedro Traefik
# En servidor admin-host.cluster.local
docker pull traefik:v1.7-alpine
docker tag a8b4c9d0e1f2 registry.corp.internal/k8s/traefik:v1.7-enterprise
docker push registry.corp.internal/k8s/traefik:v1.7-enterprise
Catálogo de Recursos
mkdir -p /k8s-manifests/traefik-proxy && cd /k8s-manifests/traefik-proxy
Configuración RBAC
cat > /k8s-manifests/traefik-proxy/rbac-config.yaml <<'EOF'
apiVersion: v1
kind: ServiceAccount
metadata:
name: traefik-service-account
namespace: kube-system
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRole
metadata:
name: traefik-role-access
rules:
- apiGroups: [""]
resources: ["services", "endpoints", "secrets"]
verbs: ["get", "list", "watch"]
- apiGroups: ["extensions"]
resources: ["ingresses"]
verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
name: traefik-binding
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: traefik-role-access
subjects:
- kind: ServiceAccount
name: traefik-service-account
namespace: kube-system
EOF
Manifiesto DaemonSet
cat > /k8s-manifests/traefik-proxy/deployment-traefik.yaml <<'EOF'
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: traefik-proxy-controller
namespace: kube-system
labels:
app-label: traefik-lb
spec:
selector:
matchLabels:
app-label: traefik-lb
template:
metadata:
labels:
app-label: traefik-lb
pod-name: traefik-lb
spec:
serviceAccountName: traefik-service-account
terminationGracePeriodSeconds: 60
containers:
- image: registry.corp.internal/k8s/traefik:v1.7-enterprise
name: traefik-lb-container
ports:
- name: ingress-http
containerPort: 80
hostPort: 8080
- name: dashboard-port
containerPort: 8080
hostPort: 9090
securityContext:
capabilities:
drop:
- ALL
add:
- NET_BIND_SERVICE
args:
- --api
- --kubernetes
- --logLevel=INFO
- --insecureskipverify=true
- --kubernetes.endpoint=https://192.168.10.10:7443
- --accesslog
- --accesslog.filepath=/var/log/traefik-access.log
- --traefiklog
- --traefiklog.filepath=/var/log/traefik-server.log
- --metrics.prometheus
imagePullSecrets:
- name: registry-auth
EOF
El puerto 8080 en hostPort permite exposición directa del servicio de Ingress desde los nodos workers.
Instalación del Controlador
kubectl apply -f http://k8s-manifests.registry.internal/traefik-proxy/rbac-config.yaml
kubectl apply -f http://k8s-manifests.registry.internal/traefik-proxy/deployment-traefik.yaml
Manifiesto de Servicio de Prueba
cat > /k8s-manifests/nginx-demo/svc-definition.yaml <<'EOF'
apiVersion: v1
kind: Service
metadata:
annotations:
k8s-app: web-test-service
name: web-test-svc
namespace: default
spec:
ports:
- port: 80
protocol: TCP
targetPort: 80
selector:
application: web-test-app
sessionAffinity: None
EOF
Definición de Ingress
cat > /k8s-manifests/nginx-demo/route-ingress.yaml <<'EOF'
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: web-application-route
namespace: default
annotations:
ingress-class: traefik
spec:
rules:
- host: webapp.demo.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: web-test-svc
port:
number: 80
EOF
Despliegue de Aplicación Backend
cat > /k8s-manifests/nginx-demo/app-deployment.yaml <<'EOF'
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-test-app
labels:
application: web-test-app
spec:
replicas: 3
selector:
matchLabels:
application: web-test-app
template:
metadata:
labels:
application: web-test-app
spec:
containers:
- name: nginx-server
image: registry.corp.internal/public/nginx:v1.19-alpine
ports:
- name: http-port
containerPort: 80
EOF
Configuración DNS
# En loadbalancer-dns.cluster.local
echo "webapp A 192.168.10.10" >> /etc/bind/zones/demo.com.zone
sed -i 's/serial [0-9]*/serial '$(date +%Y%m%d%H%M)'/' /etc/bind/zones/demo.com.zone
systemctl restart bind9
Balanceador de Carga Externo NGINX
# En ambos servidores proxy
cat > /etc/nginx/conf.d/webapp-backend.conf <<'EOF'
upstream traefik_backend_pool {
server 192.168.10.21:8080 weight=1 max_fails=3 fail_timeout=10s;
server 192.168.10.22:8080 weight=1 max_fails=3 fail_timeout=10s;
}
server {
listen 80;
server_name webapp.demo.com;
location / {
proxy_pass http://traefik_backend_pool;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
EOF
nginx -s reload
Aplicación de Recursos
kubectl apply -f http://k8s-manifests.registry.internal/nginx-demo/app-deployment.yaml
kubectl apply -f http://k8s-manifests.registry.internal/nginx-demo/svc-definition.yaml
kubectl apply -f http://k8s-manifests.registry.internal/nginx-demo/route-ingress.yaml
Verificación de Estado
kubectl get ing -n default
NAME CLASS HOSTS ADDRESS PORTS AGE
web-application-route webapp.demo.com 80 2h
kubectl get pods -n kube-system -o wide | grep traefik
traefik-proxy-controller-pod-abc 1/1 Running 0 1d 10.244.10.5 node-primary.cluster.local <none>
traefik-proxy-controller-pod-def 1/1 Running 0 1d 10.244.10.6 node-secondary.cluster.local <none>
Personalización Contenido Web
kubectl exec -it $(kubectl get pods -l application=web-test-app -o jsonpath='{.items[0].metadata.name}') -- sh -c "echo <h1>Servidor 1</h1> > /usr/share/nginx/html/index.html"
kubectl exec -it $(kubectl get pods -l application=web-test-app -o jsonpath='{.items[1].metadata.name}') -- sh -c "echo <h1>Servidor 2</h1> > /usr/share/nginx/html/index.html"