Servicio

En esta página se describen los servicios de Kubernetes y su uso en Google Kubernetes Engine. Para obtener información sobre cómo crear un servicio, consulta Cómo exponer aplicaciones con servicios.

¿Qué es un servicio?

El concepto de servicio es agrupar un conjunto de extremos de pod en un solo recurso. Puedes configurar varias formas para acceder a la agrupación. De manera 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 servicio?

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 sean miembros del servicio.

Tipos de servicios

Existen cinco tipos de servicios:

  • ClusterIP (predeterminado): los clientes internos envían solicitudes a una dirección IP interna 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.

  • Headless: puedes usar un servicio headless cuando quieras una agrupación de pods, pero no necesites 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 puedes acceder desde los nodos en el 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 con kubectl apply -f [MANIFEST_FILE]. Después de crearlo, 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. Esta 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 la dirección IP 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. Ten en cuenta que el pod miembro debe tener un contenedor que esté escuchando 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 de tipo NodePort, Kubernetes otorga el valor nodePort. Luego, se puede acceder al servicio mediante la dirección IP de cualquier nodo junto con el valor nodePort.

A continuación, se muestra un manifiesto de 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 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 nodePort especifica. La solicitud se reenvía a uno de los pods miembros en el puerto TCP que el campo targetPort especifica.

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 la dirección IP 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 servicio.

  • Mediante clusterIP y port
  • Mediante el uso de una dirección IP interna de un nodo y nodePort

Para algunas configuraciones de clúster, el balanceador de cargas de HTTP(S) de Google Cloud utiliza un servicio de tipo NodePort. Para obtener más información, consulta Cómo configurar el balanceo de cargas de HTTP con Ingress.

Ten en cuenta que el balanceador de cargas de HTTP(S) es un servidor proxy, y es completamente diferente al balanceador de cargas de red descrito en este tema en Servicio de tipo LoadBalancer.

Servicios de tipo LoadBalancer

Cuando creas un servicio de tipo LoadBalancer, un controlador de Google Cloud se activa y configura un balanceador de cargas de red en tu proyecto. El balanceador de cargas tiene una dirección IP estable a la que puedes acceder desde fuera del proyecto.

Ten en cuenta que el balanceador de cargas de red no es un servidor proxy. Reenvía paquetes sin cambios a la fuente y las direcciones IP de destino.

A continuación, se muestra un manifiesto de un servicio de tipo LoadBalancer:

apiVersion: v1
kind: Service
metadata:
  name: my-nlb-service
spec:
  selector:
    app: metrics
    department: engineering
  type: LoadBalancer
  ports:
  - port: 80
    targetPort: 8080

Después de crear el servicio, puedes usar kubectl get service -o yaml para ver su especificación y la dirección IP externa estable.

spec:
  clusterIP: 10.11.242.115
  externalTrafficPolicy: Cluster
  ports:
  - nodePort: 32676
    port: 80
    protocol: TCP
    targetPort: 8080
  selector:
    app: metrics
    department: engineering
  sessionAffinity: None
  type: LoadBalancer
  status:
    loadBalancer:
      ingress:
      - ip: 203.0.113.100

En el resultado, la dirección IP del balanceador de cargas de red aparece en loadBalancer:ingress:. Los clientes externos llaman al servicio mediante la dirección IP del balanceador de cargas y el puerto TCP que port especifica. La solicitud se reenvía a uno de los pods miembros en el puerto TCP que targetPort especifica. En el ejemplo anterior, el cliente llama al servicio a la dirección IP 203.0.113.100 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 esté escuchando en el puerto TCP 8080.

El tipo de servicio LoadBalancer es una extensión del tipo NodePort, que es una extensión del tipo ClusterIP.

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, y las solicitudes se redireccionan a un nombre externo.

A continuación, se muestra un manifiesto de 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, la solicitud se redirecciona a example.com.

El tipo de servicio ExternalName es completamente diferente a los demás tipos de servicio. 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á relacionado con el conjunto de pods y no tiene una dirección IP estable. En cambio, un servicio de tipo ExternalName es una asignación desde un nombre de DNS interno hacia uno externo.

Abstracción del servicio

Un servicio es una abstracción en el sentido que no es un proceso que escucha en la 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 servicio, el balanceo de cargas de red o el balanceo de cargas de HTTP(S) implementa otras partes de la abstracción.

Puertos de servicio arbitrarios

El valor del campo port en el manifiesto del servicio es arbitrario. Sin embargo, el valor de targetPort no es arbitrario. Cada pod miembro debe tener un contenedor que esté escuchando 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 la dirección IP 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 servicio es un arreglo de objetos ServicePort. El objeto ServicePort tiene estos campos:

  • name
  • protocol
  • port
  • targetPort
  • nodePort

Si tienes más de un 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 la dirección IP 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 la dirección IP 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 servicio, Kubernetes crea un objeto de extremos con el mismo nombre que tu servicio. Kubernetes utiliza objetos de extremos para hacer el seguimiento de los pods que son miembros del servicio.

Qué sigue

¿Te ha resultado útil esta página? Enviar comentarios:

Enviar comentarios sobre...