Capitulo 6: Services
Capitulo 6: Services
< Volver al Indice del Tutorial
Por Que se Necesitan los Services
Los pods en Kubernetes son efimeros. Cuando un pod muere y se recrea, recibe una IP diferente. Si tienes 3 replicas de un backend, cada una tiene su propia IP y estas cambian constantemente.
Un Service resuelve este problema: proporciona una IP y un nombre DNS estable para acceder a un grupo de pods. Funciona como un balanceador de carga interno.
Cliente → Service (IP fija) → Pod 1
→ Pod 2
→ Pod 3
ClusterIP: Comunicacion Interna
Es el tipo por defecto. Crea una IP virtual accesible solo dentro del cluster.
apiVersion: v1
kind: Service
metadata:
name: backend-svc
spec:
type: ClusterIP
selector:
app: backend
ports:
- port: 80 # Puerto del Service
targetPort: 3000 # Puerto del contenedor
protocol: TCP
kubectl apply -f backend-svc.yaml
kubectl get svc backend-svc
DNS Automatico
Kubernetes asigna automaticamente un registro DNS a cada Service. El formato es:
nombre-servicio.namespace.svc.cluster.local
Por ejemplo, backend-svc en el namespace default se resuelve como:
backend-svc.default.svc.cluster.local
Desde cualquier pod dentro del mismo namespace, puedes usar simplemente el nombre:
curl http://backend-svc
Desde otro namespace:
curl http://backend-svc.default.svc.cluster.local
NodePort: Exponer en Puerto del Nodo
Expone el Service en un puerto estatico de cada nodo del cluster. Util para acceso externo sin un LoadBalancer.
apiVersion: v1
kind: Service
metadata:
name: webapp-nodeport
spec:
type: NodePort
selector:
app: webapp
ports:
- port: 80
targetPort: 80
nodePort: 30080 # Puerto en el nodo (30000-32767)
kubectl apply -f webapp-nodeport.yaml
Accede desde fuera del cluster:
curl http://IP-DEL-NODO:30080
El rango de puertos permitido es 30000-32767. Si no especificas nodePort, Kubernetes asigna uno aleatorio en ese rango.
Limitaciones de NodePort
- Rango restringido de puertos.
- Necesitas conocer la IP del nodo.
- No es ideal para produccion (usa LoadBalancer o Ingress).
LoadBalancer: ServiceLB de K3s
En K3s, el tipo LoadBalancer usa ServiceLB (anteriormente llamado Klipper). No necesitas un proveedor de nube; K3s crea un balanceador integrado.
apiVersion: v1
kind: Service
metadata:
name: webapp-lb
spec:
type: LoadBalancer
selector:
app: webapp
ports:
- port: 80
targetPort: 80
kubectl apply -f webapp-lb.yaml
kubectl get svc webapp-lb
La columna EXTERNAL-IP muestra la IP asignada. En K3s con un solo nodo, esta IP es la misma del nodo.
ServiceLB funciona desplegando un DaemonSet que escucha en el puerto del host y redirige trafico al Service. Es simple y funcional para entornos pequenos.
Verificar ServiceLB
# Ver los pods de ServiceLB
kubectl get pods -n kube-system -l svccontroller.k3s.cattle.io=true
Endpoints: Descubrimiento via Selectors
Un Service usa el campo selector para encontrar los pods que debe incluir. Kubernetes mantiene un objeto Endpoints que lista las IPs de los pods que coinciden.
# Ver los endpoints de un Service
kubectl get endpoints backend-svc
Salida ejemplo:
NAME ENDPOINTS AGE
backend-svc 10.42.0.15:3000,10.42.0.16:3000 5m
Si un pod no esta listo (falla el readiness probe), se elimina de los endpoints automaticamente. Esto evita enviar trafico a pods que no pueden responder.
Service sin selector
Puedes crear un Service sin selector para apuntar a un servicio externo:
apiVersion: v1
kind: Service
metadata:
name: db-externa
spec:
type: ClusterIP
ports:
- port: 5432
---
apiVersion: v1
kind: Endpoints
metadata:
name: db-externa
subsets:
- addresses:
- ip: 192.168.1.100
ports:
- port: 5432
Esto permite que los pods internos usen db-externa como nombre DNS aunque el servicio real este fuera del cluster.
DNS Interno de K3s: CoreDNS
K3s incluye CoreDNS como servidor DNS del cluster. Se despliega automaticamente y resuelve nombres de Services a sus IPs.
# Verificar que CoreDNS esta corriendo
kubectl get pods -n kube-system -l k8s-app=kube-dns
Probar resolucion DNS
Lanza un pod temporal para probar:
kubectl run dns-test --image=busybox --rm -it --restart=Never -- nslookup backend-svc
Salida esperada:
Server: 10.43.0.10
Address 1: 10.43.0.10 kube-dns.kube-system.svc.cluster.local
Name: backend-svc
Address 1: 10.43.X.X backend-svc.default.svc.cluster.local
Registros DNS que CoreDNS crea
| Tipo | Formato | Ejemplo |
|---|---|---|
| Service | svc.namespace.svc.cluster.local | backend-svc.default.svc.cluster.local |
| Pod | pod-ip.namespace.pod.cluster.local | 10-42-0-15.default.pod.cluster.local |
Ejemplo: Frontend Hablando con Backend
Despleguemos un frontend y un backend que se comunican via Services.
Backend
apiVersion: apps/v1
kind: Deployment
metadata:
name: backend
spec:
replicas: 2
selector:
matchLabels:
app: backend
template:
metadata:
labels:
app: backend
spec:
containers:
- name: backend
image: hashicorp/http-echo
args:
- "-text=Respuesta del backend"
- "-listen=:5000"
ports:
- containerPort: 5000
---
apiVersion: v1
kind: Service
metadata:
name: backend-svc
spec:
selector:
app: backend
ports:
- port: 5000
targetPort: 5000
Frontend
apiVersion: apps/v1
kind: Deployment
metadata:
name: frontend
spec:
replicas: 2
selector:
matchLabels:
app: frontend
template:
metadata:
labels:
app: frontend
spec:
containers:
- name: frontend
image: curlimages/curl
command: ["sh", "-c"]
args:
- |
while true; do
echo "Consultando backend..."
curl -s http://backend-svc:5000
sleep 5
done
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: frontend-svc
spec:
type: NodePort
selector:
app: frontend
ports:
- port: 80
targetPort: 80
nodePort: 30080
kubectl apply -f backend.yaml
kubectl apply -f frontend.yaml
Verifica la comunicacion:
# Ver logs del frontend llamando al backend
kubectl logs -l app=frontend --tail=10
Salida esperada:
Consultando backend...
Respuesta del backend
Consultando backend...
Respuesta del backend
El frontend usa backend-svc:5000 como URL. CoreDNS resuelve ese nombre a la IP del ClusterIP del Service, que balancea entre las 2 replicas del backend.
Siguiente: Capitulo 7: ConfigMaps y Secrets —>