Capítulo 1. Introducción Introducción

Este trabajo se ha traducido utilizando IA. Agradecemos tus opiniones y comentarios: translation-feedback@oreilly.com

En este capítulo introductorio, preparamos el terreno para el resto del libro explicando algunos de los conceptos básicos de Kubernetes utilizados para diseñar e implementar aplicaciones nativas de la nube. Comprender estas nuevas abstracciones, y los principios y patrones relacionados de este libro, es clave para construir aplicaciones distribuidas que puedan ser automatizadas por Kubernetes.

Este capítulo no es un requisito previo para comprender los patrones que se describen más adelante. Los lectores familiarizados con los conceptos de Kubernetes pueden saltárselo y pasar directamente a la categoría de patrones que les interese.

El camino hacia la nube nativa

Microservicios es uno de los estilos arquitectónicos más populares para crear aplicaciones nativas de la nube. Abordan la complejidad del software mediante la modularización de las capacidades empresariales y el intercambio de complejidad de desarrollo por complejidad operativa. Por eso, un requisito previo clave para tener éxito con los microservicios es crear aplicaciones que puedan funcionar a escala mediante Kubernetes.

Como parte del movimiento de microservicios, existe una enorme cantidad de teoría, técnicas y herramientas complementarias para crear microservicios desde cero o para dividir monolitos en microservicios. La mayoría de estas prácticas se basan en el Domain-Driven Design de Eric Evans (Addison-Wesley) y en los conceptos de contextos delimitados y agregados. Los contextos delimitados se ocupan de grandes modelos dividiéndolos en distintos componentes, y los agregados ayudan a agrupar aún más los contextos delimitados en módulos con límites de transacción definidos. Sin embargo, además de estas consideraciones de dominio empresarial, para cada sistema distribuido -basado o no en microservicios- existen también preocupaciones técnicas en torno a su estructura externa y al acoplamiento en tiempo de ejecución. Los contenedores y los orquestadores de contenedores, como Kubernetes, aportan nuevas primitivas y abstracciones para abordar las preocupaciones de las aplicaciones distribuidas, y aquí analizamos las distintas opciones a tener en cuenta al introducir un sistema distribuido en Kubernetes.

A lo largo de este libro, examinamos las interacciones entre los contenedores y la plataforma tratando a los contenedores como cajas negras. Sin embargo, hemos creado esta sección para destacar la importancia de lo que se pone en los contenedores. Los contenedores y las plataformas nativas de la nube aportan enormes beneficios a tus aplicaciones distribuidas, pero si todo lo que pones en los contenedores es basura, obtendrás basura distribuida a escala. La Figura 1-1 muestra la mezcla de habilidades necesarias para crear buenas aplicaciones nativas de la nube y dónde encajan los patrones de Kubernetes.

The path to cloud native
Figura 1-1. El camino hacia la nube nativa

A alto nivel, crear buenas aplicaciones nativas en la nube requiere familiarizarse con múltiples técnicas de diseño:

  • En el nivel de código más bajo, cada variable que defines, cada método que creas y cada clase que decides instanciar desempeñan un papel en el mantenimiento a largo plazo de la aplicación. Independientemente de la tecnología de contenedores y la plataforma de orquestación que utilices, el equipo de desarrollo y los artefactos que creen tendrán el mayor impacto. Es importante cultivar desarrolladores que se esfuercen por escribir código limpio, tengan el número adecuado de pruebas automatizadas, refactoricen constantemente para mejorar la calidad del código y se guíen en el fondo por los principios de Software Craftsmanship.

  • Eldiseño orientado al dominio es abordar el diseño de software desde una perspectiva empresarial con la intención de mantener la arquitectura lo más cerca posible del mundo real. Este enfoque funciona mejor con lenguajes de programación orientados a objetos, pero también hay otras buenas formas de modelar y diseñar software para problemas del mundo real. Un modelo con los límites empresariales y de transacción adecuados, interfaces fáciles de consumir y API ricas es la base para el éxito posterior de la contenedorización y la automatización.

  • La arquitectura hexagonal y sus variaciones, como las arquitecturas Onion y Clean, mejoran la flexibilidad y mantenibilidad de las aplicaciones al desacoplar los componentes de la aplicación y proporcionar interfaces estandarizadas para interactuar con ellos. Al desacoplar la lógica empresarial central de un sistema de la infraestructura circundante, la arquitectura hexagonal facilita la portabilidad del sistema a distintos entornos o plataformas. Estas arquitecturas complementan el diseño orientado al dominio y ayudan a organizar el código de la aplicación con límites distintos y dependencias de infraestructura externalizadas.

  • El estilo arquitectónico de microservicios y la metodología de aplicación de doce factores evolucionaron muy rápidamente hasta convertirse en la norma para crear aplicaciones distribuidas, y proporcionan valiosos principios y prácticas para diseñar aplicaciones distribuidas cambiantes. Aplicar estos principios te permite crear implementaciones optimizadas para la escala, la resiliencia y el ritmo de cambio, que son requisitos comunes para cualquier software moderno hoy en día.

  • Los contenedores fueron adoptados muy rápidamente como la forma estándar de empaquetar y ejecutar aplicaciones distribuidas, ya sean microservicios o funciones. Crear contenedores modulares y reutilizables que sean buenos ciudadanos nativos de la nube es otro requisito previo fundamental. Nube nativa es un término utilizado para describir principios, patrones y herramientas para automatizar aplicaciones en contenedores a escala. Usamos nativo de la nube indistintamente con Kubernetes, que es la plataforma nativa de la nube de código abierto más popular disponible en la actualidad.

En este libro no tratamos el código limpio, el diseño dirigido por dominios, la arquitectura hexagonal ni los microservicios. Nos centramos únicamente en los patrones y prácticas que abordan las preocupaciones de la orquestación de contenedores. Pero para que estos patrones sean eficaces, tu aplicación tiene que estar bien diseñada desde dentro utilizando prácticas de código limpio, diseño dirigido por dominios, aislamiento de dependencias externas similar a la arquitectura hexagonal, principios de microservicios y otras técnicas de diseño relevantes.

Primitivas distribuidas

Para explicar en lo que entendemos por nuevas abstracciones y primitivas, aquí las comparamos con la conocida programación orientada a objetos (POO), y en concreto con Java. En el universo de la POO, tenemos conceptos como clase, objeto, paquete, herencia, encapsulación y polimorfismo. Luego, el tiempo de ejecución de Java proporciona características y garantías específicas sobre cómo gestiona el ciclo de vida de nuestros objetos y de la aplicación en su conjunto.

El lenguaje Java y la máquina virtual Java (JVM) proporcionan bloques de construcción locales, dentro del proceso, para crear aplicaciones. Kubernetes añade una dimensión totalmente nueva a esta conocida mentalidad al ofrecer un nuevo conjunto de primitivas distribuidas y un tiempo de ejecución para crear sistemas distribuidos que se extienden por múltiples nodos y procesos. Con Kubernetes a mano, no dependemos sólo de las primitivas locales para implementar todo el comportamiento de la aplicación.

Seguimos necesitando utilizar los bloques de construcción orientados a objetos para crear los componentes de la aplicación distribuida, pero también podemos utilizar las primitivas de Kubernetes para algunos de los comportamientos de la aplicación. La Tabla 1-1 muestra cómo varios conceptos de desarrollo se realizan de forma diferente con primitivas locales y distribuidas en la JVM y en Kubernetes, respectivamente.

Tabla 1-1. Primitivas locales y distribuidas
Concepto Primitivo local Primitiva distribuida

Encapsulación del comportamiento

Clase

Imagen del contenedor

Ejemplo de comportamiento

Objeto

Contenedor

Unidad de reutilización

.jar

Imagen del contenedor

Composición

La Clase A contiene la Clase B

Patrón Sidecar

Herencia

La clase A amplía la clase B

La imagen padre de un contenedor FROM

Unidad de Implementación

.jar/.war/.ear

Pod

Aislamiento Buildtime/Runtime

Módulo, paquete, clase

Espacio de nombres, Pod, contenedor

Condiciones previas de inicialización

Constructor

Contenedor init

Activador de postinicialización

Método init

postStart

Disparador de Predestrucción

Método de destrucción

preStop

Procedimiento de limpieza

finalize()gancho de cierre

-

Ejecución asíncrona y paralela

ThreadPoolExecutor,ForkJoinPool

Trabajo

Tarea periódica

Timer, ScheduledExecutorService

CronJob

Tarea de fondo

Hilo demonio

DaemonSet

Gestión de la configuración

System.getenv(), Properties

ConfigMap, Secreto

Las primitivas en proceso y las primitivas distribuidas tienen puntos en común, pero no son directamente comparables ni sustituibles. Funcionan a distintos niveles de abstracción y tienen distintas condiciones previas y garantías. Algunas primitivas deben utilizarse juntas. Por ejemplo, seguimos teniendo que utilizar clases para crear objetos y colocarlos en imágenes contenedoras. Sin embargo, algunas otras primitivas, como CronJob en Kubernetes, pueden sustituir completamente al comportamiento ExecutorService en Java.

A continuación, veamos algunas abstracciones y primitivas distribuidas de Kubernetes que son especialmente interesantes para los desarrolladores de aplicaciones.

Contenedores

Los contenedores son los bloques de construcción de las aplicaciones nativas de la nube basadas en Kubernetes. Si hacemos una comparación con la programación orientada a objetos y Java, las imágenes de contenedor son como clases, y los contenedores son como objetos. Del mismo modo que podemos extender clases para reutilizar y alterar el comportamiento, podemos tener imágenes contenedoras que extiendan otras imágenes contenedoras para reutilizar y alterar el comportamiento. Del mismo modo que podemos hacer composiciones de objetos y utilizar funcionalidades, podemos hacer composiciones de contenedores poniendo contenedores en un Pod y utilizando contenedores colaboradores.

Si seguimos con la comparación, Kubernetes sería como la JVM pero repartida en varios hosts, y se encargaría de ejecutar y gestionar los contenedores. Los contenedores Init serían algo parecido a los constructores de objetos; los DaemonSets serían similares a los hilos daemon que se ejecutan en segundo plano (como el Recolector de Basura de Java, por ejemplo). Un Pod sería algo similar a un contexto de Inversión de Control (IoC) (Spring Framework, por ejemplo), donde varios objetos en ejecución comparten un ciclo de vida gestionado y pueden acceder unos a otros directamente.

El paralelismo no va mucho más allá, pero la cuestión es que los contenedores desempeñan un papel fundamental en Kubernetes, y crear imágenes de contenedor modularizadas, reutilizables y de propósito único es fundamental para el éxito a largo plazo de cualquier proyecto e incluso del ecosistema de contenedores en su conjunto. Aparte de las características técnicas de una imagen de contenedor que proporcionan empaquetamiento y aislamiento, ¿qué representa un contenedor y cuál es su propósito en el contexto de una aplicación distribuida? He aquí algunas sugerencias sobre cómo ver los contenedores:

  • Una imagen de contenedor es la unidad de funcionalidad que responde a una única preocupación.

  • Una imagen de contenedor es propiedad de un equipo y tiene su propio ciclo de publicación.

  • Una imagen de contenedor es autocontenida y define y transporta sus dependencias en tiempo de ejecución.

  • Una imagen de contenedor es inmutable, y una vez construida, no cambia; está configurada.

  • Una imagen de contenedor define sus requisitos de recursos y dependencias externas.

  • Una imagen de contenedor tiene API bien definidas para exponer su funcionalidad.

  • Un contenedor suele ejecutarse como un único proceso Unix.

  • Un contenedor es desechable y seguro para ampliarlo o reducirlo en cualquier momento.

Además de todas estas características, una imagen contenedor adecuada es modular. Está parametrizada y creada para ser reutilizada en los distintos entornos en los que se va a ejecutar. Tener imágenes contenedoras pequeñas, modulares y reutilizables conduce a la creación de imágenes contenedoras más especializadas y estables a largo plazo, de forma similar a una gran biblioteca reutilizable en el mundo de los lenguajes de programación.

Vainas

Si miramos en las características de los contenedores, vemos que encajan perfectamente en la aplicación de los principios de los microservicios. Una imagen de contenedor proporciona una única unidad de funcionalidad, pertenece a un único equipo, tiene un ciclo de lanzamiento independiente y proporciona aislamiento de implementación y tiempo de ejecución. La mayoría de las veces, un microservicio corresponde a una imagen de contenedor.

Sin embargo, la mayoría de las plataformas nativas de la nube ofrecen otra primitiva para gestionar el ciclo de vida de un grupo de contenedores: en Kubernetes, se denomina Pod. Un Pod es una unidad atómica de programación, implementación y aislamiento en tiempo de ejecución para un grupo de contenedores. Todos los contenedores de un Pod se programan siempre en el mismo host, se despliegan y escalan juntos, y también pueden compartir el sistema de archivos, la red y los espacios de nombres de los procesos. Este ciclo de vida conjunto permite que los contenedores de un Pod interactúen entre sí a través del sistema de archivos o de la red mediante mecanismos de comunicación entre procesos del host local o del host, si se desea (por razones de rendimiento, por ejemplo). Un Pod también representa un límite de seguridad para una aplicación. Aunque es posible tener contenedores con distintos parámetros de seguridad en el mismo Pod, normalmente todos los contenedores tendrían el mismo nivel de acceso, segmentación de red e identidad.

Como puedes ver en la Figura 1-2, en tiempo de desarrollo y construcción, un microservicio corresponde a una imagen de contenedor que un equipo desarrolla y libera. Pero en tiempo de ejecución, un microservicio está representado por un Pod, que es la unidad de implementación, colocación y escalado. La única forma de ejecutar un contenedor -ya sea para escalado o migración- es a través de la abstracción Pod. A veces un Pod contiene más de un contenedor. En un ejemplo de este tipo, un microservicio en contenedores utiliza un contenedor de ayuda en tiempo de ejecución, como demuestra Capítulo 16, "Sidecar".

Pod as the deployment and management unit
Figura 1-2. Un Pod como unidad de implementación y gestión

Los contenedores, los Pods y sus características únicas ofrecen un nuevo conjunto de patrones y principios para diseñar aplicaciones basadas en microservicios. Ya vimos algunas de las características de los contenedores bien diseñados; ahora veamos algunas características de un Pod:

  • Un Pod es la unidad atómica de la programación. Eso significa que el programador intenta encontrar un host que satisfaga los requisitos de todos los contenedores que pertenecen al Pod (cubrimos algunos detalles específicos sobre los contenedores init de en el Capítulo 15, "Contenedor init"). Si creas un Pod con muchos contenedores, el programador necesita encontrar un host que tenga suficientes recursos para satisfacer todas las demandas de los contenedores combinadas. Este proceso de programación se describe en el Capítulo 6, "Colocación automatizada".

  • Un Pod garantiza la colocación de los contenedores. Gracias a la colocación, los contenedores de un mismo Pod disponen de medios adicionales para interactuar entre sí. Las formas más comunes de comunicación incluyen el uso de un sistema de archivos local compartido para intercambiar datos, el uso de la interfaz de red localhost, o el uso de algún mecanismo de comunicación entre procesos (IPC) del host para interacciones de alto rendimiento.

  • Un Pod tiene una dirección IP, un nombre y un rango de puertos que comparten todos los contenedores que pertenecen a él. Esto significa que los contenedores de un mismo Pod deben configurarse cuidadosamente para evitar choques de puertos, del mismo modo que los procesos Unix que se ejecutan en paralelo deben tener cuidado al compartir el espacio de red de un host.

Un Pod es el átomo de Kubernetes donde vive tu aplicación, pero no accedes a los Pods directamente, ahí es donde entran en escena los Servicios.

Servicios

Pods son efímeros. Aparecen y desaparecen en cualquier momento por todo tipo de razones (por ejemplo, al aumentar o disminuir la escala, al fallar las comprobaciones de estado de los contenedores o al migrar de nodo). La dirección IP de un Pod sólo se conoce después de programarlo e iniciarlo en un nodo. Un Pod puede reprogramarse en un nodo diferente si el nodo en el que se está ejecutando ya no está en buen estado. Esto significa que la dirección de red del Pod puede cambiar a lo largo de la vida de una aplicación, y se necesita otra primitiva para el descubrimiento y el equilibrio de carga.

Ahí es donde entran en juego los Servicios de Kubernetes. El Servicio es otra abstracción sencilla pero potente de Kubernetes que vincula el nombre del Servicio a una dirección IP y un número de puerto de forma permanente. Así, un Servicio representa un punto de entrada con nombre para acceder a una aplicación. En el escenario más común, el Servicio sirve como punto de entrada para un conjunto de Pods, pero no siempre es así. El Servicio es una primitiva genérica, y también puede apuntar a una funcionalidad proporcionada fuera del clúster Kubernetes. Como tal, la primitiva Servicio puede utilizarse para el descubrimiento de Servicios y el equilibrio de carga de, y permite alterar las implementaciones y el escalado sin afectar a los consumidores de Servicios. Explicamos los Servicios en detalle en el Capítulo 13, "Descubrimiento de Servicios".

Etiquetas

En hemos visto que un microservicio es una imagen de contenedor en tiempo de compilación, pero está representado por un Pod en tiempo de ejecución. Entonces, ¿qué es una aplicación que consta de varios microservicios? En este caso, Kubernetes ofrece otras dos primitivas que pueden ayudarte a definir el concepto de una aplicación: las etiquetas y los espacios de nombres.

Antes de los microservicios, una aplicación correspondía a una única unidad de implementación con un único esquema de versiones y ciclo de publicación. Había un único archivo para una aplicación en formato .war, .ear o cualquier otro formato de empaquetado. Pero entonces, las aplicaciones se dividieron en microservicios, que se desarrollan, liberan, ejecutan, reinician o escalan de forma independiente. Con los microservicios, la noción de aplicación disminuye, y no hay artefactos o actividades clave que tengamos que realizar a nivel de aplicación. Pero si sigues necesitando una forma de indicar que algunos servicios independientes pertenecen a una aplicación, se pueden utilizar etiquetas. Imaginemos que hemos dividido una aplicación monolítica en tres microservicios y otra en dos microservicios.

Ahora tenemos cinco definiciones de Pod (y quizá muchas más instancias de Pod) que son independientes de los puntos de vista del desarrollo y del tiempo de ejecución. Sin embargo, puede que aún necesitemos indicar que los tres primeros Pods representan una aplicación y los otros dos Pods representan otra aplicación. Incluso los Pods pueden ser independientes, para proporcionar un valor empresarial, pero pueden depender unos de otros. Por ejemplo, un Pod puede contener los contenedores responsables del frontend, y los otros dos Pods son responsables de proporcionar la funcionalidad del backend. Si alguno de estos Pods no funciona, la aplicación es inútil desde el punto de vista empresarial. Utilizar los selectores de etiquetas de nos da la posibilidad de consultar e identificar un conjunto de Pods y gestionarlo como una unidad lógica. La Figura 1-3 muestra cómo puedes utilizar etiquetas para agrupar las partes de una aplicación distribuida en subsistemas específicos.

Labels used as an application identity for Pods
Figura 1-3. Etiquetas utilizadas como identidad de aplicación para Pods

He aquí algunos ejemplos en los que las etiquetas pueden ser útiles:

  • Etiquetas son utilizadas por los ReplicaSets para mantener en funcionamiento algunas instancias de un Pod específico. Esto significa que cada definición de Pod debe tener una combinación única de etiquetas utilizadas para la programación.

  • Las etiquetas también son muy utilizadas por el programador. El programador utiliza las etiquetas para colocar o distribuir los Pods en los nodos que satisfacen los requisitos de los Pods.

  • Una etiqueta puede indicar una agrupación lógica de un conjunto de Pods y darles una identidad de aplicación.

  • Además de los casos de uso típicos anteriores, las etiquetas pueden utilizarse para almacenar metadatos. Puede ser difícil predecir para qué podría utilizarse una etiqueta, pero lo mejor es tener suficientes etiquetas para describir todos los aspectos importantes de los Pods. Por ejemplo, tener etiquetas para indicar el grupo lógico de una aplicación, las características empresariales y la criticidad, las dependencias específicas de la plataforma de ejecución, como la arquitectura de hardware, o las preferencias de ubicación, son todas ellas útiles.

Más adelante, el programador puede utilizar estas etiquetas para una programación más precisa, o bien se pueden utilizar las mismas etiquetas desde la línea de comandos para gestionar los Pods coincidentes a escala. Sin embargo, no debes excederte y añadir demasiadas etiquetas por adelantado. Siempre puedes añadirlas más tarde si es necesario. Eliminar etiquetas es mucho más arriesgado, ya que no hay una forma directa de averiguar para qué se utiliza una etiqueta y qué efecto no deseado puede causar tal acción.

Espacios de nombres

Otra primitiva de que también puede ayudar a gestionar un grupo de recursos es el espacio de nombres de Kubernetes. Como hemos descrito, un espacio de nombres puede parecer similar a una etiqueta, pero en realidad es una primitiva muy distinta, con características y propósitos diferentes.

Los espacios de nombres de Kubernetes te permiten dividir un clúster de Kubernetes (que suele estar repartido entre varios hosts) en un conjunto lógico de recursos. Los espacios de nombres proporcionan ámbitos para los recursos de Kubernetes y un mecanismo para aplicar autorizaciones y otras políticas a una subsección del clúster. El caso de uso más común de los espacios de nombres es representar diferentes entornos de software, como desarrollo, pruebas, pruebas de integración o producción. Los espacios de nombres también pueden utilizarse para conseguir multitenencia y proporcionar aislamiento para espacios de trabajo en equipo, proyectos e incluso aplicaciones específicas. Pero, en última instancia, para un mayor aislamiento de determinados entornos, los espacios de nombres no son suficientes, y lo habitual es tener clusters separados. Normalmente, hay un clúster Kubernetes de no producción utilizado para algunos entornos (desarrollo, pruebas y pruebas de integración) y otro clúster Kubernetes de producción para representar las pruebas de rendimiento y los entornos de producción.

Veamos algunas de las características de los espacios de nombres y cómo pueden ayudarnos en distintos escenarios:

  • Un espacio de nombres se gestiona como un recurso de Kubernetes.

  • Un espacio de nombres proporciona ámbito para recursos como contenedores, Pods, Servicios o ReplicaSets. Los nombres de los recursos deben ser únicos dentro de un espacio de nombres, pero no entre ellos.

  • Por defecto, los espacios de nombres proporcionan alcance a los recursos, pero nada aísla esos recursos ni impide el acceso de un recurso a otro. Por ejemplo, un Pod de un espacio de nombres de desarrollo puede acceder a otro Pod de un espacio de nombres de producción siempre que se conozca la dirección IP del Pod. "El aislamiento de red entre espacios de nombres para crear una solución ligera de multiarrendamiento se describe en el Capítulo 24, "Segmentación de red".

  • Algunos otros recursos, como los espacios de nombres, los nodos y los PersistentVolumes, no pertenecen a espacios de nombres y deben tener nombres únicos para todo el clúster.

  • Cada Servicio Kubernetes pertenece a un espacio de nombres y obtiene un registro correspondiente del Servicio de Nombres de Dominio (DNS) que tiene el espacio de nombres en forma de <service-name>.<namespace-name>.svc.cluster.local. Así que el nombre del espacio de nombres está en la URL de cada Servicio que pertenece al espacio de nombres dado. Ésa es una de las razones por las que es vital nombrar los espacios de nombres sabiamente.

  • Las ResourceQuotas proporcionan restricciones que limitan el consumo agregado de recursos por espacio de nombres. Con ResourceQuotas, un administrador de cluster puede controlar el número de objetos por tipo que se permiten en un espacio de nombres. Por ejemplo, un espacio de nombres de desarrollador puede permitir sólo cinco ConfigMap, cinco Secrets, cinco Services, cinco ReplicaSets, cinco PersistentVolumeClaims y diez Pods.

  • ResourceQuotas también puede limitar la suma total de recursos informáticos que podemos solicitar en un espacio de nombres determinado. Por ejemplo, en un clúster con una capacidad de 32 GB de RAM y 16 núcleos, es posible asignar 16 GB de RAM y 8 núcleos para el espacio de nombres de producción, 8 GB de RAM y 4 núcleos para el entorno de ensayo, 4 GB de RAM y 2 núcleos para el desarrollo, y la misma cantidad para los espacios de nombres de prueba. La capacidad de imponer restricciones de recursos desvinculadas de la forma y los límites de la infraestructura subyacente tiene un valor incalculable.

Debate

Sólo hemos tratado brevemente algunos de los principales conceptos de Kubernetes que utilizamos en este libro. Sin embargo, hay más primitivas que los desarrolladores utilizan en su día a día. Por ejemplo, si creas un servicio en contenedores, hay un montón de abstracciones de Kubernetes que puedes utilizar para aprovechar todas las ventajas de Kubernetes. Ten en cuenta que éstos son sólo algunos de los objetos que utilizan los desarrolladores de aplicaciones para integrar un servicio en contenedor en Kubernetes. Hay muchos otros conceptos utilizados principalmente por los administradores de clústeres para gestionar Kubernetes. La Figura 1-4 ofrece una visión general de los principales recursos de Kubernetes que son útiles para los desarrolladores.

Kubernetes concepts for developers
Figura 1-4. Conceptos de Kubernetes para desarrolladores

Con el tiempo, estas nuevas primitivas dan lugar a nuevas formas de resolver los problemas, y algunas de estas soluciones repetitivas se convierten en patrones. A lo largo de este libro, en lugar de describir detalladamente cada recurso de Kubernetes, nos centraremos en conceptos que se han demostrado como patrones.

Get Patrones Kubernetes, 2ª Edición now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.