Servicios


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 y port.
  • 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?