En esta página, se describen los Services de Kubernetes y su uso en Google Kubernetes Engine (GKE). Existen diferentes tipos de objetos Service que puedes usar para agrupar un conjunto de extremos de Pod en un solo recurso. Para obtener información sobre cómo crear un Service, consulta Cómo exponer aplicaciones con Services.
¿Qué es un Service de Kubernetes?
La idea de un Service es agrupar un conjunto de extremos de Pod en un solo recurso. Puedes configurar varias formas para acceder a la agrupación. De forma predeterminada, obtienes una dirección IP de clúster estable que los clientes dentro del clúster pueden usar para comunicarse con los pods en el servicio. Un cliente envía una solicitud a una dirección IP estable, y la solicitud se enruta a uno de los pods en el servicio.
Un servicio identifica sus pods miembros con un selector. Para que un pod sea miembro del servicio, este debe tener todas las etiquetas especificadas en el selector. Una etiqueta es un par clave-valor arbitrario adjunto a un objeto.
El siguiente manifiesto de servicio tiene un selector que especifica dos etiquetas. El campo selector
indica que cualquier pod que tenga las etiquetas app: metrics
y department:engineering
es un miembro de este servicio.
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
selector:
app: metrics
department: engineering
ports:
...
¿Por qué usar un Service de Kubernetes?
En un clúster de Kubernetes, cada pod tiene una dirección IP interna. Sin embargo, los pods van y vienen en una implementación, y sus direcciones IP cambian. Por este motivo, no tiene sentido usar direcciones IP de pod directamente. Con un servicio, obtienes una dirección IP estable que dura toda la vida del servicio, incluso cuando las direcciones IP de los pods miembros cambian.
Además, un servicio proporciona el balanceo de cargas. Los clientes llaman a una única dirección IP estable, y sus solicitudes se balancean en los pods que son miembros del servicio.
Tipos de Services de Kubernetes
Existen 5 tipos de Servicios:
ClusterIP (predeterminado): Los clientes internos envían solicitudes a una dirección IP interna y estable.
NodePort: los clientes envían solicitudes a la dirección IP de un nodo en uno o más valores
nodePort
que el servicio especifica.LoadBalancer: los clientes envían solicitudes a la dirección IP de un balanceador de cargas de red.
ExternalName: los clientes internos usan el nombre de DNS de un servicio como un alias para un nombre de DNS externo.
Sin interfaz gráfica: Puedes usar un servicio sin interfaz gráfica cuando quieras una grupo de Pods, pero no necesites contar con una dirección IP estable.
El tipo NodePort
es una extensión del tipo ClusterIP
. Entonces, un servicio de tipo NodePort
tiene una dirección IP de clúster.
El tipo LoadBalancer
es una extensión del tipo NodePort
. Entonces, un servicio de tipo LoadBalancer
tiene una dirección IP de clúster y uno o más valores nodePort
.
Servicios de tipo ClusterIP
Cuando creas un servicio de tipo ClusterIP
, Kubernetes crea una dirección IP estable a la que se puede acceder desde los nodos del clúster.
A continuación, se muestra un manifiesto de un servicio de tipo ClusterIP:
apiVersion: v1
kind: Service
metadata:
name: my-cip-service
spec:
selector:
app: metrics
department: sales
type: ClusterIP
ports:
- protocol: TCP
port: 80
targetPort: 8080
Puedes crear el servicio mediante kubectl apply -f [MANIFEST_FILE]
. Después de crear el servicio, puedes usar kubectl get service
para ver la dirección IP estable:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S)
my-cip-service ClusterIP 10.11.247.213 none 80/TCP
Los clientes en el clúster llaman al servicio mediante la dirección IP del clúster y el puerto TCP especificado en el campo port
del manifiesto del servicio. La solicitud se reenvía a uno de los pods miembros en el puerto TCP especificado en el campo targetPort
. En el ejemplo anterior, un cliente llama al servicio a 10.11.247.213
en el puerto TCP 80. La solicitud se reenvía a uno de los pods miembros en el puerto TCP 8080. El Pod miembro debe tener un contenedor que escuche en el puerto TCP 8080. Si no hay un contenedor escuchando en el puerto 8080, los clientes verán un mensaje como “No se pudo establecer la conexión” o “No se puede acceder al sitio”.
Servicios de tipo NodePort
Cuando creas un servicio del tipo NodePort
, Kubernetes proporciona un valor nodePort
. Luego, se puede acceder al servicio mediante la dirección IP de cualquier nodo junto con el valor nodePort
.
Aquí hay un manifiesto para un servicio de tipo NodePort
:
apiVersion: v1
kind: Service
metadata:
name: my-np-service
spec:
selector:
app: products
department: sales
type: NodePort
ports:
- protocol: TCP
port: 80
targetPort: 8080
Después de crear el servicio, puedes usar kubectl get service -o yaml
para ver su especificación y ver el valor nodePort
.
spec:
clusterIP: 10.11.254.114
externalTrafficPolicy: Cluster
ports:
- nodePort: 32675
port: 80
protocol: TCP
targetPort: 8080
Los clientes externos llaman al servicio mediante la dirección IP externa de un nodo junto con el puerto TCP que especifica nodePort
. La solicitud se reenvía a uno de los pods miembros en el puerto TCP especificado en el campo targetPort
.
Por ejemplo, asumamos que la dirección IP externa de uno de los nodos del clúster es 203.0.113.2
. En el ejemplo anterior, el cliente externo llama al servicio a 203.0.113.2
en el puerto TCP 32675. La solicitud se reenvía a uno de los pods miembros en el puerto TCP 8080. El pod miembro debe tener un contenedor que esté escuchando en el puerto TCP 8080.
El tipo de servicio NodePort
es una extensión del tipo de servicio ClusterIP
. Entonces, los clientes internos tienen dos maneras de llamar al objeto Service:
- Usa
clusterIP
yport
. - Pueden usar la dirección IP interna de un nodo y
nodePort
.
Para algunas configuraciones de clúster, el balanceador de cargas de aplicaciones externo usa un Service de tipo NodePort
.
Un balanceador de cargas de aplicaciones externo es un servidor proxy y es muy diferente al balanceador de cargas de red de transferencia externo que se describe en este tema en Service de tipo LoadBalancer.
Servicios de tipo LoadBalancer
Para obtener más información sobre los Service de tipo LoadBalancer, consulta los conceptos del Service LoadBalancer.
Servicio de tipo ExternalName
Un servicio de tipo ExternalName
proporciona un alias interno para un nombre de DNS externo. Los clientes internos hacen solicitudes con el nombre de DNS interno, y las solicitudes se redireccionan a un nombre externo.
Aquí hay un manifiesto para un servicio de tipo ExternalName
:
apiVersion: v1
kind: Service
metadata:
name: my-xn-service
spec:
type: ExternalName
externalName: example.com
Cuando creas un servicio, Kubernetes crea un nombre de DNS que los clientes internos pueden usar para llamar al servicio. En el ejemplo anterior, el nombre de DNS es my-xnservice.default.svc.cluster.local. Cuando un cliente interno hace una solicitud a my-xn-service.default.svc.cluster.local, esta se redirecciona a example.com.
El tipo de servicio ExternalName
es muy diferente a los demás tipos de servicios. De hecho, el servicio de tipo ExternalName
no coincide con la definición de servicio detallada al comienzo de este tema. Un servicio de tipo ExternalName
no está asociado con un conjunto de pods y no tiene una dirección IP estable. En cambio, un servicio de tipo ExternalName
es una asignación de un nombre de DNS interno a un nombre de DNS externo.
Servicio sin interfaz gráfica
Un Service sin interfaz gráfica es un tipo de Service de Kubernetes que no asigna una dirección IP del clúster. En cambio, un Service sin interfaz gráfica usa un DNS para exponer las direcciones IP de los Pods asociados con el Service. Esto te permite conectarte directamente a los Pods, en lugar de pasar por un proxy.
Los Service sin interfaz gráfica son útiles en varias situaciones, que incluyen las siguientes:
Balanceo de cargas entre Pods: puedes usar los Service sin interfaz gráfica para balancear cargas entre Pods. Para implementar esto, cree un Service con un selector que coincida con los Pods con los que desea balancear cargas. Luego, el Service distribuirá el tráfico de manera uniforme entre todos los Pods que coincidan con el selector.
Descubrimiento de servicios: puedes usar un Service sin interfaz gráfica para implementar el descubrimiento de servicios. Para implementar esto, crea un Service con un nombre y un selector. El registro DNS del Service sin interfaz gráfica contiene todas las direcciones IP de los Pods detrás del Service que coinciden con el selector. Los clientes pueden usar estos registros DNS para encontrar las direcciones IP de los Pods asociados con el Service.
Acceso directo al Pod: los clientes pueden conectarse directamente a los Pods asociados con un Service sin interfaz gráfica, lo que puede ser útil para los Service que requieren acceso directo a los Pods subyacentes, como los balanceadores de cargas y los servidores DNS.
Flexibilidad: los Service sin interfaz gráfica se pueden usar para crear una variedad de topologías diferentes, como balanceadores de cargas, servidores DNS y bases de datos distribuidas.
Si tienes requisitos de red especiales para tus cargas de trabajo que no se pueden resolver con objetos Service sin interfaz gráfica con selectores, también existe la posibilidad de usar objetos Service sin interfaz gráfica sin selectores. Los Service sin interfaz gráfica son una herramienta útil para acceder a los Service que no se encuentran dentro del clúster de Kubernetes, ya que el plano de control no crea objetos EndpointSlice. Puedes obtener más información sobre este tema en Service sin selectores.
El siguiente ejemplo es un manifiesto para un Service sin interfaz gráfica:
apiVersion: v1
kind: Service
metadata:
name: nginx
spec:
clusterIP: None
selector:
app: nginx
ports:
- name: http
port: 80
targetPort: 80
Una vez que haya creado el Service sin interfaz gráfica, puede buscar las direcciones IP de los Pods asociados con el Service por medio de una consulta al DNS. Por ejemplo, el siguiente comando enumera las direcciones IP de los Pods asociados con el Service de nginx:
dig +short nginx.default.svc.cluster.local
Otro ejemplo en el que se usa la búsqueda expandida de Kubernetes:
dig +short +search nginx
Puedes crear un Service sin interfaz gráfica con un solo comando, y los objetos Service sin interfaz gráfica son fáciles de actualizar y escalar.
kubectl create service clusterip my-svc --clusterip="None" --dry-run=client -o yaml > [file.yaml]
Abstracción del servicio
Un servicio es una abstracción en el sentido de que no es un proceso que escucha en alguna interfaz de red. Parte de esta abstracción se implementa en las reglas iptables de los nodos del clúster. Según el tipo de Service, una parte de la abstracción se implementa mediante un balanceador de cargas de red de transferencia externo o un balanceador de cargas de aplicaciones externo.
Puertos de servicio arbitrarios
El valor del campo port
en un manifiesto de servicio es arbitrario. Sin embargo, el valor de targetPort
no es arbitrario. Cada pod miembro debe tener un contenedor que escuche en targetPort
.
A continuación, se muestra un servicio de tipo LoadBalancer
, que tiene un valor port
de 50000:
apiVersion: v1
kind: Service
metadata:
name: my-ap-service
spec:
clusterIP: 10.11.241.93
externalTrafficPolicy: Cluster
ports:
- nodePort: 30641
port: 50000
protocol: TCP
targetPort: 8080
selector:
app: parts
department: engineering
sessionAffinity: None
type: LoadBalancer
status:
loadBalancer:
ingress:
- ip: 203.0.113.200
El cliente llama al servicio a 203.0.113.200
en el puerto TCP 50000. La solicitud se reenvía a uno de los pods miembros en el puerto TCP 8080.
Varios puertos
El campo ports
de un Service es un array de objetos ServicePort. El objeto ServicePort tiene estos campos:
name
protocol
port
targetPort
nodePort
Si tienes más de un objeto ServicePort, cada uno debe tener un nombre exclusivo.
A continuación, se muestra un servicio del tipo LoadBalancer
que tiene dos objetos ServicePort
:
apiVersion: v1
kind: Service
metadata:
name: my-tp-service
spec:
clusterIP: 10.11.242.196
externalTrafficPolicy: Cluster
ports:
- name: my-first-service-port
nodePort: 31233
port: 60000
protocol: TCP
targetPort: 50000
- name: my-second-service-port
nodePort: 31081
port: 60001
protocol: TCP
targetPort: 8080
selector:
app: tests
department: engineering
sessionAffinity: None
type: LoadBalancer
status:
loadBalancer:
ingress:
- ip: 203.0.113.201
En el ejemplo anterior, si un cliente llama al servicio a 203.0.113.201
en el puerto TCP 60000, la solicitud se reenvía a uno de los pods miembros en el puerto TCP 50000. Sin embargo, si un cliente llama al servicio a 203.0.113.201
en el puerto TCP 60001, la solicitud se reenvía a uno Pod miembro en el puerto TCP 8080.
Cada pod miembro debe tener un contenedor que esté escuchando en el puerto TCP 50000 y otro escuchando en el puerto TCP 8080. Este puede ser un contenedor con dos subprocesos, o dos contenedores que se ejecutan en el mismo pod.
Extremos del servicio
Cuando creas un Service, Kubernetes crea un objeto de extremos con el mismo nombre que tu Service. Kubernetes utiliza objetos de extremos para hacer el seguimiento de los pods que son miembros del servicio.
Servicios de pila única y pila doble
Puedes crear un objeto Service IPv6 de tipo ClusterIP
o NodePort
.
GKE admite Services de pila doble del tipo LoadBalancer
durante la vista previa, que no proporciona ANS ni asistencia técnica.
Para cada uno de estos tipos de Services, puedes definir los campos ipFamilies
y ipFamilyPolicy
como IPv4, IPv6 o un objeto Service de pila doble.
¿Qué sigue?
- Más información sobre los Services de Kubernetes
- Expón aplicaciones con Services
- Más información sobre StatefulSets
- Más información sobre Ingress