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 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 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 son 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 sin interfaz gráfica cuando quieras tener una agrupación 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 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 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 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:

  • Usa clusterIP y port.
  • Usa la 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 usa un servicio de tipo NodePort. Para obtener más información, consulta la página sobre 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 muy diferente al balanceador de cargas de red descrito en este tema en Servicios 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 las direcciones IP de destino y origen.

Aquí hay un manifiesto para 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 ver 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 junto con el puerto TCP que especifica port. La solicitud se reenvía a uno de los pods miembros en el puerto TCP especificado en targetPort. 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 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.

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 servicio, el balanceo de cargas de red o el balanceo de cargas de HTTP(S) implementan otras partes de la abstracción.

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 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 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.

Pasos siguientes

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

Enviar comentarios sobre...

Documentación de Kubernetes Engine