Servicios
Como conectarnos a los recursos
Nos sirven para conectarse entre los pods como asi tambien para conectarse con el mundo exterior y asi poder ser accedidos.

Tipos de servicios
ClusterIP
Descripción: Este es el tipo de servicio predeterminado en Kubernetes. Se utiliza para exponer un servicio internamente dentro del clúster. No es accesible desde fuera del clúster. Acceso: Solo se puede acceder desde dentro del clúster, ya sea por otros pods o componentes del clúster. Uso: Ideal para servicios internos que no necesitan ser accesibles desde fuera, como microservicios o bases de datos internas.
apiVersion: v1
kind: Service
metadata:
name: mi-servicio
spec:
selector:
app: mi-app
ports:
- protocol: TCP
port: 80
targetPort: 8080
type: ClusterIP
NodePort
Descripción: Expone el servicio a través de un puerto específico en todos los nodos del clúster. Permite acceder a la aplicación desde fuera del clúster a través de la IP de cualquier nodo y el puerto asignado. Acceso: Externo, accesible desde fuera del clúster usando la dirección IP del nodo y el puerto que se asigna (generalmente en el rango de 30000-32767). Uso: Se usa cuando necesitas exponer temporalmente un servicio para pruebas o cuando no tienes un balanceador de carga disponible.
apiVersion: v1
kind: Service
metadata:
name: mi-servicio
spec:
selector:
app: mi-app
ports:
- protocol: TCP
port: 80
targetPort: 8080
nodePort: 30007 # Opcional, si no se especifica, se asigna automáticamente
type: NodePort
LoadBalancer
Descripción: Este tipo de servicio crea un balanceador de carga externo para exponer el servicio a través de una IP pública. Funciona en plataformas que soportan balanceadores de carga nativos, como GCP, AWS o Azure. Acceso: Externo, el servicio será accesible desde fuera del clúster a través de la IP asignada por el balanceador de carga. Uso: Ideal para aplicaciones que necesitan ser expuestas a Internet o a una red pública.
apiVersion: v1
kind: Service
metadata:
name: mi-servicio
spec:
selector:
app: mi-app
ports:
- protocol: TCP
port: 80
targetPort: 8080
type: LoadBalancer

Como sabe un servicio que pods le corresponden?
El servicio tomara como referencia el label de los pods.

apiVersion: v1
kind: Service
metadata:
name: mi-servicio
spec:
selector:
app: mi-app
ports:
- protocol: TCP
port: 80
targetPort: 8080
type: LoadBalancer
apiVersion: apps/v1
kind: Deployment
metadata:
name: mi-app-deployment
spec:
replicas: 3
selector:
matchLabels:
app: mi-app
template:
metadata:
labels:
app: mi-app # este es el label que toma encuenta el service
spec:
containers:
- name: mi-app-container
image: mi-imagen:latest
ports:
- containerPort: 8080
Crear un servicio nodePort
kubectl create deployment apache --image=httpd
kubectl expose deploy apache --port=80 --type=NodePort
Hacemos kubectl get svc
NAME | TYPE | CLUSTER-IP | EXTERNAL-IP | PORT(S) | AGE |
---|---|---|---|---|---|
apache | NodePort | 10.106.109.82 | none | 80:30612/TCP | 64s |
- External IP esta en none porque no estamos en entorno cloud.
- Vemos port que es 30612
- Chekeamos con
kubectl ip
la ip a usar con el puerto - En el navegador hacemos ip:port Tendriamos que ver la web de apache.
Podemos ver los servicios de minikube con minikube service list
NAMESPACE | NAME | TARGET PORT | URL |
---|---|---|---|
default | apache | 80 | http://192.168.49.2:30612 |
default | kubernetes | No node port | |
kube-system | kube-dns | No node port | |
------------- | ------------ | -------------- | --------------------------- |
Como sabe el servicio a que pods apuntar?
Si hacemos:
kubectl describe svc apache
Veremos :
Name: apache
Namespace: default
Labels: app=apache
Annotations: none
Selector: app=apache
Type: NodePort
IP Family Policy: SingleStack
IP Families: IPv4
IP: 10.106.109.82
IPs: 10.106.109.82
Port: unset 80/TCP
TargetPort: 80/TCP
NodePort: unset 30612/TCP
Endpoints: 10.244.2.2:80
Session Affinity: None
External Traffic Policy: Cluster
Internal Traffic Policy: Cluster
Events: none
Si prestamos atencion a
Endpoints: 10.244.2.2:80
Veremos que es la ip del pod. Revisemoslo.
kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE
apache-7d8d5c5d5-7g2bz 1/1 Running 1 (3m4s ago) 19h 10.244.2.2 mastercluster-m02
Que pasa con los Endpoints del servicio si escalamos?
kubectl scale deploy apache --replicas=3
Veremos que automáticamente actualiza la lista de ips.
Name: apache
Namespace: default
Labels: app=apache
Annotations: none
Selector: app=apache
Type: NodePort
IP Family Policy: SingleStack
IP Families: IPv4
IP: 10.106.109.82
IPs: 10.106.109.82
Port: unset 80/TCP
TargetPort: 80/TCP
NodePort: unset 30612/TCP
Endpoints: 10.244.2.2:80,10.244.0.3:80,10.244.3.2:80
Session Affinity: None
External Traffic Policy: Cluster
Internal Traffic Policy: Cluster
Events: none
Comunicacion entre servicios de tipo ClusterIP
El ClusterIP se utiliza solo para la Comunicacion interna entre los objetos de un cluster.
A continuacion crearemos dos deploy y probaremos la comunicacion entre ellos.
kubectl create deployment redis-master --image=redis
kubectl create deployment redis-slave --image=redis
kubectl get deployment
kubectl expose deployment redis-master --port=6379
(no ponemos el type porque por default es ClusterIP)kubectl get services
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
redis-master ClusterIP 10.105.11.137 <none> 6379/TCP 7s
El NAME lo podemos usar como DNS desde otros pods.
kubectl get pods
- Copiamos el NAME del pod de redis-slave
kubectl exec redis-slave-77464dc784-nlwbt -it -- sh
redis-cli -h redis-master
redis-cli
es la app de redis , no nuestro pod. este comando
nos permite conectarnos a otras db redis. -h
es host
y podemos el DNS del servicio, en este caso redis-master.
Practica, correr nuestr app con deployment + service.
El ejercicio se hara con nextjs14+ para eso tenemos que tener nuestra app de nextjs.
npx create-next-app@latest
- Creamos
Dockerfile
con lo siguiente.
# Etapa 1: Construcción
# Usa la imagen oficial de Node.js como base
FROM node:18-alpine AS builder
# Establece el directorio de trabajo dentro del contenedor
WORKDIR /app
# Copia los archivos package.json y package-lock.json o yarn.lock
COPY package*.json ./
# Si usas Yarn, reemplaza el comando anterior por: COPY yarn.lock ./
# Instala las dependencias de producción
RUN npm install --frozen-lockfile
# Copia el resto de los archivos de la aplicación
COPY . .
# Establece la variable de entorno para la producción
ENV NODE_ENV=production
# Construye la aplicación Next.js en modo standalone
RUN npm run build
# Elimina las dependencias de desarrollo
RUN npm prune --production
# Etapa 2: Ejecución
# Usa una imagen base mínima para ejecutar el contenedor
FROM node:18-alpine
# Establece el directorio de trabajo dentro del contenedor
WORKDIR /app
# Copia los archivos generados de la fase de construcción
COPY --from=builder /app ./
# Expone el puerto por defecto en el que Next.js se ejecuta (3000)
EXPOSE 3000
# Comando por defecto para iniciar la aplicación
CMD ["npm", "start"]
- Generamos la imagen:
docker build -t k8s-next .
- Creamos el yml:
#############
# DEPLOYMENT
#############
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-d
spec:
selector: #permite seleccionar un conjunto de objetos que cumplan las condicione
matchLabels:
app: k8s-next
replicas: 2 # indica al controlador que ejecute 2 pods
template: # Plantilla que define los containers
metadata:
labels:
app: k8s-next # Con esto el servicio sabe a que pod apuntar!
spec:
containers:
- name: k8s-next
image: k8s-next:latest
imagePullPolicy: Never # Como nuestra imagen es local tenemos que setear esto.
ports:
- containerPort: 3000 # IP por delfault por el que escucha nuestra app
---
#############
# SERVICIO
#############
apiVersion: v1
kind: Service
metadata:
name: web-svc
labels:
app: k8s-next
spec:
type: NodePort
ports:
- port: 3000
nodePort: 30002
protocol: TCP
selector:
app: k8s-next # este es el que apunta a los pods del __deployment__ es importante!
- Cargamos la imagen en minikube
minikube image load k8s-next:latest
- Ejecutamos
kubectl apply -f completo.yml
- Vamos al navegador ponemos IP:3002 donde la ip la obtenemos de
minikube ip
Obtener informacion adicional de Endpoits:
kubectl get endpoints web-svc -o yaml
kubectl describe endpoint web-svc
kubectl get endpoints
Ejercicio recomendado
El siguiente ejercicio muestra como tener un servidor con redis donde tendremos 1-master(redis) y 2-slave(redis).
Tene en cuenta que lo que determina que redis es maestro y esclavo se determina al momento de crear la imagen de redis.En este caso ya te las da el ejemplo. En la vida real tenes que setear vos hacia donde apuntan los slave.