Guía práctica de Kubernetes. Brendan Burns
Чтение книги онлайн.
Читать онлайн книгу Guía práctica de Kubernetes - Brendan Burns страница 9
Creación de una aplicación replicada
Nuestra aplicación de frontend es apátrida. Para su estado depende totalmente del backend de Redis. Como consecuencia, podemos replicarla arbitrariamente sin afectar al tráfico. Aunque es poco probable que la aplicación soporte un uso a gran escala, es una buena idea que se ejecute en al menos dos réplicas para poder resolver una caída inesperada o poner en marcha una nueva versión de la aplicación sin paradas.
Aunque en Kubernetes ReplicaSet es el recurso que gestiona la replicación de una aplicación contenida en un contenedor, no es una buena práctica utilizarlo directamente. En su lugar, se utiliza el recurso Deployment (implementación). Deployment combina las capacidades de replicación de ReplicaSet con el versionado y la capacidad de realizar un despliegue por etapas. Mediante el uso de Deployment podemos utilizar las herramientas incorporadas en Kubernetes para pasar de una versión de la aplicación a la siguiente.
El recurso Deployment para nuestra aplicación tiene el siguiente aspecto:
apiVersion: extensions/v1beta1 kind: Deployment metadata: labels: app: frontend name: frontend namespace: default spec: replicas: 2 selector: matchLabels: app: frontend template: metadata: labels: app: frontend spec: containers: - image: my-repo/journal-server:v1-abcde imagePullPolicy: IfNotPresent name: frontend resources: request: cpu: "1.0" memory: "1G" limits: cpu: "1.0" memory: "1G"
Hay varias cosas a tener en cuenta en este Deployment. La primera es que utilizamos Labels (etiquetas) para identificar el Deployment, así como los ReplicaSets y las pods (cápsulas) que crea Deployment. Hemos añadido la etiqueta layer: frontend a todos estos recursos para que podamos examinar todos los recursos de una capa en particular en una sola petición. Esto lo veremos a medida que añadamos otros recursos, donde seguiremos el mismo procedimiento.
Además, hemos añadido comentarios en varias partes de YAML, aunque estos comentarios no se convierten en un recurso de Kubernetes almacenado en el servidor. Como ocurre con los comentarios en el código, sirven de ayuda para orientar a los desarrolladores que analizan la configuración por primera vez.
También debemos tener en cuenta que para los contenedores en Deployment hemos especificado tanto las peticiones de recursos de Request (solicitud) como las de Limit (límite), y hemos establecido que Request es igual a Limit. Cuando se ejecuta una aplicación, Request es la reserva de recursos que se garantiza en la máquina host (anfitriona) en la que se ejecuta. Limit indica la cantidad máxima de recursos que se le permitirá usar al contenedor. Cuando empezamos, al establecer Request igual a Limit (solicitud igual a límite) se consigue el comportamiento más previsible de la aplicación. Esta previsibilidad se produce a expensas de la utilización de recursos. Dado que la configuración en la que Request es igual a Limit evita que las aplicaciones se sobreprogramen o consuman recursos inútiles, no podremos impulsar la utilización óptima a menos que ajustemos Request y Limit muy cuidadosamente. A medida que avancemos en la comprensión del modelo de recursos de Kubernetes, podremos considerar modificar Request y Limit en la aplicación de forma independiente. Pero, en general, la mayor parte de los usuarios cree que merece la pena la estabilidad de la previsibilidad frente a lo que se reduce su utilización.
Ahora que tenemos definido el recurso Deployment, lo comprobaremos en el control de versiones y lo desplegaremos en Kubernetes:
git add frontend/deployment.yaml git commit -m "Added deployment" frontend/deployment.yaml kubectl apply -f frontend/deployment.yaml
También es una buena práctica comprobar que el contenido del clúster coincide exactamente con el contenido del control del código fuente. La mejor forma de comprobarlo es adoptar una aproximación GitOps y hacer el despliegue en producción solo desde una rama específica del control del código fuente, utilizando la automatización de Continuous Integration (integración continua) (CI)/Continuous Delivery (entrega continua) (CD). De esta manera, se garantiza que los contenidos del control del código fuente y producción coinciden. Aunque una pipeline (canalización) CI/CD completa puede parecer excesiva para una aplicación sencilla, la automatización en sí misma —independientemente de la fiabilidad que proporciona— normalmente merece la pena, a pesar del tiempo que conlleva montarla. Y CI/CD es extremadamente difícil de reequipar en una aplicación existente e implementada con un enfoque imperativo.
Hay algunas partes de esta descripción de la aplicación YAML (por ejemplo, ConfigMap y los volúmenes secret), así como la Quality of Service (calidad de servicio) de las cápsulas, que examinamos en secciones posteriores.
Configuración de Ingress externa para tráfico HTTP
Los contenedores de nuestra aplicación ya están implementados, pero en este momento no es posible acceder a la aplicación. Por defecto, los recursos del clúster solo están disponibles dentro del mismo clúster. Para presentar nuestra aplicación al mundo, necesitamos crear un Service (servicio) y un balanceador de carga para proporcionar una dirección IP externa y traer tráfico a nuestros contenedores. Para la presentación externa vamos a usar dos recursos de Kubernetes. El primero es un Service que equilibra la carga de tráfico de Transmission Control Protocol (protocolo de control de transmisión) (TCP) o de User Datagram Protocol (protocolo de datagrama de usuario) (UDP). En nuestro caso, usamos el protocolo TCP. Y el segundo es un recurso Ingress (acceso), que proporciona balanceo de carga HTTP(S) con enrutamiento inteligente de peticiones basado en rutas y hosts HTTP. Con una aplicación tan sencilla como esta, te preguntarás por qué elegimos usar la Ingress más compleja. Pero, como verás en secciones posteriores, incluso esta sencilla aplicación servirá peticiones HTTP desde dos servicios diferentes. Además, al disponer de Ingress tenemos la ventaja de contar con cierta flexibilidad en caso de una futura expansión de nuestro servicio.
Antes de que se pueda definir el recurso Ingress, es necesario que exista un Service de Kubernetes al que Ingress apunte. Usaremos Labels (etiquetas) para dirigir el Service a las cápsulas que hemos creado en la sección anterior. Service es considerablemente más sencillo de definir que Deployment, y se ve de la siguiente manera:
apiVersion: v1 kind: Service metadata: labels: app: frontend name: frontend namespace: default spec: ports: - port: 8080 protocol: TCP targetPort: 8080 selector: app: frontend type: ClusterIP
Después de haber definido Service, podemos definir el recurso Ingress. A diferencia de los recursos de Service, Ingress necesita que un contenedor del controlador Ingress se ejecute en el clúster. Hay una serie de aplicaciones diferentes entre las que podemos elegir, ya sea las que proporciona el proveedor de la nube o las que se implementan utilizando servidores de código abierto. Si decidimos instalar un proveedor de Ingress de código abierto, es una buena idea utilizar el administrador de paquetes Helm (https://helm.sh) para su instalación y mantenimiento. Los proveedores de Ingress nginx o haproxy son las opciones más habituales:
apiVersion: extensions/v1beta1 kind: Ingress metadata: name: frontend-ingress spec: rules: - http: paths: - path: /api backend: serviceName: frontend servicePort: 8080
Configuración de la aplicación con ConfigMaps
Cada aplicación necesita un cierto grado