Usando un servicio para exponer la aplicación
Objetivos
- Aprender acerca de los Service Kubernetes
- Entender cómo las etiquetas y los selectores se relacionan con un Service
- Exponer una aplicación fuera del clúster Kubernetes usando un Service
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:
- ClusterIP (predeterminado) - Expone el Service en una IP interna en el clúster. Este tipo hace que el Service solo sea accesible desde dentro del clúster.
- NodePort - Expone el Service en el mismo puerto de cada Nodo seleccionado en el clúster usando NAT. Hace que un Service
sea accesible desde fuera del clúster usando
: . Es un superset de ClusterIP. - LoadBalancer - Crea un balanceador de carga externo en la nube actual (si es compatible) y asigna una IP externa fija al Service. Es un superset de NodePort.
- ExternalName - Asocia el Service con el contenido del campo externalName (por ejemplo, foo.bar.example.com), devolviendo un registro CNAME con su valor. No se configura ningún tipo de proxy. Este tipo requiere v1.7 o superior de kube-dns, o CoreDNS versión 0.0.8 o superior.
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:
- Designar objetos para desarrollo, prueba y producción
- Incrustar etiquetas de versión
- Clasificar un objeto usando etiquetas
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.