Usando un servicio para exponer la aplicación

Objetivos

Introduccion a los Services Kubernetes

Los Pods Kubernetes son efímeros. Los Pods tienen un ciclo de vida. Cuando un nodo worker muere, los Pods que se ejecutan en el Nodo también se pierden. Un ReplicaSet podría entonces llevar dinámicamente el clúster de vuelta al estado deseado a través de la creación de nuevos Pods para mantener la aplicación en funcionamiento. Como otro ejemplo, considere un backend de procesamiento de imágenes con 3 réplicas. Esas réplicas son intercambiables; el sistema de front-end no debe preocuparse por las réplicas de backend o incluso si se pierde y se recrea un Pod. Dicho esto, cada Pod en un clúster Kubernetes tiene una dirección IP única, incluso los Pods en el mismo Nodo, por lo que debe haber una forma de reconciliar automáticamente los cambios entre los Pods para que sus aplicaciones continúen funcionando.

Un Service en Kubernetes es una abstracción que define un conjunto lógico de Pods y una política para acceder a ellos. Los Services permiten un bajo acoplamiento entre Pods dependientes. Un Service se define usando YAML o JSON, como todos los manifiestos de objetos Kubernetes. El conjunto de Pods dirigidos por un Service generalmente se determina mediante un selector de etiquetas (consulte a continuación por qué podría desear un Service sin incluir un selector en la especificación).

Although each Pod has a unique IP address, those IPs are not exposed outside the cluster without a Service. Services allow your applications to receive traffic. Services can be exposed in different ways by specifying a type in the spec of the Service:

A pesar de que cada Pod tiene una dirección IP única, esas direcciones IP no se exponen fuera del clúster sin un Service. Los Services permiten que sus aplicaciones reciban tráfico. Los Services pueden exponerse de diferentes maneras especificando un tipo en la especificación del Service:

Se puede leer más acerca de los diferentes tipos de servico en el tutorial Usando IP de origen. También ver Conectando aplicaciones con Services.

Además debemos tener en cuenta que hay algunos casos de uso con Services que no implican definir un selector en la especificación. Un Service creado sin selector tampoco creará el objeto Endpoints correspondiente. Esto permite a los usuarios asignar manualmente un Service a endpoints específicos. Otra posibilidad por la que puede no haber un selector es que esté utilizando solamente type: ExternalName.

Services y Labels

Un Service enruta el tráfico a través de un conjunto de Pods. Los Services son la abstracción que permite que los pods mueran y se repliquen en Kubernetes sin afectar su aplicación. El descubrimiento y el enrutamiento entre Pods dependientes (como los componentes frontend y backend en una aplicación) son manejados por los Services de Kubernetes.

Services match a set of Pods using labels and selectors, a grouping primitive that allows logical operation on objects in Kubernetes. Labels are key/value pairs attached to objects and can be used in any number of ways: Los Services se asocian a un conjunto de Pods usando Labels y Selectors, una primitiva de agrupación que permite operaciones lógicas en objetos en Kubernetes. Las Labels son pares clave/valor asociados a objetos y se pueden usar de cualquier manera:

Las Labels se pueden asociar a objetos en el momento de la creación o más tarde. Se pueden modificar en cualquier momento.

Ahorra expongamos nuestra aplicación usando un Service y apliquemos algunas Labels.

Crear un nuevo Service

Verifiquemos que la aplicación se está ejecutando. Usaremos el comnado kubectl get y buscaremos Pods en ejecución:

kubectl get pods

Si ningún Pod está en ejecución, espere unos segundos y vuelva a listar los Pods. Puede continuar una vez que vea que se está ejecutando un Pod.

A continuación, listemos los Services actuales de nuestro clúster:

kubectl get services

Tenemos un Service llamado kubernetes que se crea de forma predeterminada cuando kind inicia el clúster. Para crear un nuevo Service y exponerlo al tráfico externo, usaremos el comando expose con NodePort como parámetro.

kubectl expose deployment/kubernetes-bootcamp --type="NodePort" --port 8080

Ejecutemos nuevamente el subcomando get services:

kubectl get services

We have now a running Service called kubernetes-bootcamp. Here we see that the Service received a unique cluster-IP, an internal port and an external-IP (the IP of the Node). Ahora tenemos un Service en ejecución llamado kubernetes-bootcamp. Aquí vemos que el Service recibió una IP de clúster única, un puerto interno y una IP externa (la IP del Nodo).

Para averiguar qué puerto se abrió externamente (para el tipo: NodePort Service) ejecutaremos el subcomando describe service:

kubectl describe services/kubernetes-bootcamp

Crearemos dos variables de entorno, NODE_PORT con el valor del puerto asignado y NODE_IP con la IP del primer Nodo del cluster:

export NODE_PORT="$(kubectl get services/kubernetes-bootcamp -o jsonpath='{.spec.ports[].nodePort}')"

echo "NODE_PORT=$NODE_PORT"

export NODE_IP="$(kubectl get nodes -o jsonpath='{.items[0].status.addresses[0].address}')"

echo "NODE_IP=$NODE_IP"

Ahora podemos probar que la aplicación se expone fuera del clúster usando curl, usando la dirección IP del Nodo y el puerto expuesto externamente:

curl "http://$NODE_IP:$NODE_PORT"

Obtenemos una respuesta del servidor. El Service está expuesto. Podemos repetir la prueba con cualquier otro nodo del clúster.

Usando Labels

El Deployment creó automáticamente una etiqueta para nuestro Pod. Con el subcomando describe deployment puede ver el nombre (la clave) de esa etiqueta:

kubectl describe deployment

Usemos esta Label para consultar nuestra lista de Pods. Usaremos el comando kubectl get pods con -l como parámetro, seguido de los valores de la Label:

kubectl get pods -l app=kubernetes-bootcamp

Se puede hacer lo mismo para listar los Services existentes:

kubectl get services -l app=kubernetes-bootcamp

Obtenemos el nombre del Pod y lo guardamos en la variable de entorno POD_NAME:

export POD_NAME="$(kubectl get pods -o go-template --template '{{range .items}}{{.metadata.name}}{{"\n"}}{{end}}')"

echo "Nombre del Pod: $POD_NAME"

Para aplicar una nueva Label usamos el subcomando label seguido del tipo de objeto, el nombre del objeto y la nueva Label:

kubectl label pods "$POD_NAME" version=v1

Esto aplicará una nueva Label a nuestro Pod (anclamos la versión de la aplicación al Pod), y podemos verificarlo con el comando:

kubectl describe pods "$POD_NAME"

Podemos ver aquí que la Label ahora está asociada a nuestro Pod. Y ahora podemos consultar la lista de pods usando la nueva Label:

kubectl get pods -l version=v1

Y podemos ver nuestro Pod.

Borrando un Service

Para eliminar Services puede usar el subcomando delete service. Las Labels también se pueden usar aquí:

kubectl delete service -l app=kubernetes-bootcamp

Confirmemos que el Service se ha eliminado:

kubectl get services

Esto nos confirma que nuestro Service se eliminó. Para confirmar que la ruta ya no está expuesta, puede usar curl con la IP y el puerto expuestos anteriormente:

curl "http://$NODE_IP:$NODE_PORT"

Esto demuestra que la aplicación ya no es accesible desde fuera del clúster. Puede confirmar que la aplicación sigue funcionando con un curl desde dentro del pod:

kubectl exec -ti $POD_NAME -- curl http://localhost:8080

Podemos ver aquí que la aplicación está activa. Esto se debe a que el Deployment está administrando la aplicación. Para apagar la aplicación, debería eliminar el Deployment también.

Volvemos a exponer la aplicación con el comando expose:

kubectl expose deployment/kubernetes-bootcamp --type="NodePort" --port 8080

Una vez que esté listo, continúe con Ejecutar varias instancias de su aplicación.