Mejores prácticas de Kubernetes. Crea contenedores pequeños



El primer paso para implementar en Kubernetes es colocar su aplicación en un contenedor. En esta serie, veremos cómo puede crear una imagen de un contenedor pequeño y seguro.
Gracias a Docker, crear imágenes de contenedor nunca ha sido tan fácil. Especifique la imagen base, agregue sus cambios y cree un contenedor.



Aunque esta técnica es excelente para comenzar, el uso de imágenes básicas de forma predeterminada puede conducir a un trabajo inseguro con imágenes grandes llenas de vulnerabilidades.

Además, la mayoría de las imágenes en Docker usan Debian o Ubuntu como imagen base, y aunque esto proporciona una excelente compatibilidad y fácil adaptación (el archivo Docker solo toma dos líneas de código), las imágenes básicas pueden agregar cientos de megabytes de carga adicional a su contenedor. Por ejemplo, un simple archivo node.js de la aplicación Go hello-world toma alrededor de 700 megabytes, mientras que el tamaño de la aplicación en sí es de unos pocos megabytes.



Por lo tanto, toda esta carga adicional es un desperdicio de espacio digital y un excelente caché para vulnerabilidades y errores en el sistema de seguridad. Así que veamos dos formas de reducir el tamaño de una imagen de contenedor.

El primero es el uso de imágenes básicas de pequeño tamaño, el segundo es el uso del patrón de diseño Builder Pattern. El uso de imágenes base más pequeñas es probablemente la forma más fácil de reducir el tamaño de su contenedor. Lo más probable es que su idioma o la pila que está utilizando proporcione una imagen de aplicación original que es mucho más pequeña que la imagen predeterminada. Echemos un vistazo a nuestro contenedor node.js.



Por defecto, en Docker, el tamaño del nodo base: imagen 8 es 670 MB, y el tamaño del nodo: 8-alpine es solo 65 MB, es decir, 10 veces más pequeño. El uso de la imagen base más pequeña de Alpine reducirá significativamente el tamaño de su contenedor. Alpine es una distribución de Linux pequeña y ligera que es muy popular entre los usuarios de Docker porque es compatible con muchas aplicaciones, al tiempo que mantiene el tamaño pequeño de los contenedores. A diferencia de la imagen estándar de "nodo" de Docker, "nodo: alpino" elimina muchos archivos y programas de utilidades, dejando solo aquellos que son suficientes para ejecutar su aplicación.

Para cambiar a una imagen base más pequeña, simplemente actualice el archivo Docker para comenzar a trabajar con la nueva imagen base:



Ahora, a diferencia de la antigua imagen onbuild, debe copiar su código en el contenedor e instalar cualquier dependencia. En el nuevo archivo Docker, el contenedor comienza con el nodo: imagen alpina, luego crea un directorio para el código, instala dependencias usando el administrador de paquetes NPM y finalmente inicia server.js.



Con esta actualización, un contenedor es 10 veces más pequeño. Si su lenguaje de programación o pila no tiene la capacidad de reducir la imagen base, use Alpine Linux. También proporcionará la capacidad de administrar completamente el contenido del contenedor. El uso de imágenes básicas de pequeño tamaño es una excelente manera de crear rápidamente contenedores pequeños. Pero puede lograr una reducción aún mayor utilizando el Patrón de generador.



En los idiomas interpretados, el código fuente se pasa primero al intérprete y luego se ejecuta directamente. En los idiomas compilados, el código fuente se convierte primero en código compilado. Sin embargo, la compilación a menudo utiliza herramientas que realmente no son necesarias para ejecutar el código. Esto significa que puede eliminar por completo estas herramientas del contenedor final. Puede usar el Patrón de construcción para esto.



El código se crea en el primer contenedor y se compila. Luego, el código compilado se empaqueta en el contenedor final sin los compiladores y las herramientas necesarias para compilar este código. Omitamos la aplicación Go a través de este proceso. Primero, pasaremos de la imagen onbuild a Alpine Linux.



En el nuevo archivo Docker, el contenedor comienza con la imagen golang: alpine. Luego crea un directorio para el código, lo copia en el código fuente, crea este código fuente e inicia la aplicación. Este contenedor es mucho más pequeño que el contenedor onbuild, pero aún contiene el compilador y otras herramientas Go que realmente no necesitamos. Así que simplemente extraigamos el programa compilado y colóquelo en nuestro propio contenedor.



Puede notar algo extraño en este archivo Docker: contiene dos líneas FROM. La primera sección de 4 líneas se ve exactamente igual al archivo Docker anterior, excepto que usa la palabra clave AS para nombrar este paso. En la siguiente sección, hay una nueva línea FROM que le permite comenzar una nueva imagen, y en lugar de la imagen golang: alpine, usaremos Raw alpine como imagen base.

Raw Alpine Linux no tiene ningún certificado SSL instalado, lo que hará que la mayoría de las llamadas a la API HTTPS fallen, así que instalemos algunos certificados raíz de CA.

Y ahora lo más interesante: para copiar el código compilado del primer contenedor al segundo, simplemente puede usar el comando COPY ubicado en la quinta línea de la segunda sección. Copiará solo un archivo de aplicación y no afectará a las herramientas de utilidad Go. El nuevo archivo Docker de varios pasos contendrá una imagen de contenedor de solo 12 megabytes de tamaño, mientras que la imagen del contenedor original era de 700 megabytes, ¡y esa es una gran diferencia!
Por lo tanto, el uso de pequeñas imágenes básicas y patrones de construcción son excelentes maneras de crear contenedores mucho más pequeños sin mucho trabajo.
Es posible que, según la pila de aplicaciones, haya formas adicionales de reducir el tamaño de la imagen y el contenedor, pero ¿los contenedores pequeños realmente tienen una ventaja medible? Veamos dos aspectos donde los contenedores pequeños son extremadamente efectivos: rendimiento y seguridad.

Para evaluar el aumento del rendimiento, considere la duración del proceso de creación de un contenedor, insertándolo en el registro (push) y luego recuperándolo desde allí (pull). Puede ver que un contenedor más pequeño tiene una ventaja innegable sobre un contenedor más grande.



Docker almacenará en caché las capas, por lo que las compilaciones posteriores serán muy rápidas. Sin embargo, en muchos sistemas de CI que se utilizan para construir y probar contenedores, las capas no se almacenan en caché, por lo que se ahorra mucho tiempo. Como puede ver, el tiempo para construir un contenedor grande, dependiendo de la potencia de su máquina, es de 34 a 54 segundos, y cuando se utiliza un contenedor reducido con el Patrón de construcción, de 23 a 28 segundos. Para operaciones de este tipo, las ganancias de productividad serán del 40-50%. Tan solo piense cuántas veces crea y prueba su código.

Después de construir el contenedor, debe insertar su imagen (imagen del contenedor de inserción) en el registro del contenedor para usar Kubernetes en su clúster. Recomiendo usar el registro de contenedores de Google.



Al usar el Registro de contenedores de Google (GCR), solo paga por el almacenamiento sin procesar y la red, y no hay una tarifa adicional de administración de contenedores. Es confidencial, seguro y muy rápido. GCR utiliza muchos trucos para acelerar la operación de extracción. Como puede ver, insertar una imagen de contenedor de Docker Container Image usando go: onbuild, dependiendo del rendimiento de la computadora, tomará de 15 a 48 segundos, y la misma operación con un contenedor más pequeño tomará de 14 a 16 segundos, y para máquinas menos eficientes, la ventaja en la velocidad de operación aumenta en 3 veces. Para máquinas grandes, el tiempo es aproximadamente el mismo, ya que GCR utiliza el caché global para una base de datos común de imágenes, es decir, no es necesario descargarlas en absoluto. En una computadora de bajo consumo, la CPU es un cuello de botella,por lo tanto, la ventaja de usar contenedores pequeños aquí es mucho más tangible.

Si usa GCR, le recomiendo usar Google Container Builder (GCB) como parte de su sistema de compilación.



Como puede ver, usarlo le permite lograr resultados mucho mejores al reducir la duración de la operación Build + Push que incluso con una máquina productiva; en este caso, el proceso de construcción y envío de contenedores al host es casi 2 veces más rápido. Además, cada día obtienes 120 minutos de ensamblaje gratis, lo que en la mayoría de los casos satisface las necesidades de crear contenedores.

Luego viene la métrica de rendimiento más importante: la velocidad a la que recupera o descarga contenedores Pull. Y si realmente no le importa el tiempo dedicado a la operación de inserción, la duración del proceso de extracción afecta seriamente el rendimiento general del sistema. Supongamos que tiene un grupo de tres nodos y uno de ellos se bloquea. Si utiliza un sistema de gestión, como Google Kubernetes Engine, reemplazará automáticamente el nodo inactivo por uno nuevo. Sin embargo, este nuevo nodo estará completamente vacío y tendrá que arrastrar todos sus contenedores a él para que funcione. Si la operación de extracción es lo suficientemente larga, todo este tiempo su clúster funcionará con un rendimiento más bajo.

Hay muchos casos en los que esto puede suceder: agregar un nuevo nodo a un clúster, actualizar nodos o incluso cambiar a un nuevo contenedor para su implementación. Por lo tanto, minimizar el tiempo de extracción de extracción se convierte en un factor clave. Es indiscutible que un contenedor pequeño se descarga mucho más rápido que uno grande. Si usa varios contenedores en un clúster de Kubernetes, ahorrar tiempo puede ser muy significativo.



Eche un vistazo a la comparación: la operación de extracción cuando se trabaja con contenedores pequeños toma de 4 a 9 veces menos tiempo, dependiendo de la potencia de la máquina, que la misma operación que usa go: onbuild. El uso de imágenes básicas comunes de contenedores de contenedores pequeños acelera enormemente el tiempo y la velocidad con que los nuevos nodos de Kubernetes pueden desplegarse y conectarse.

Veamos el tema de la seguridad. Se cree que los contenedores más pequeños son mucho más seguros que los grandes porque tienen una superficie de ataque más pequeña. ¿Es realmente? Una de las características más útiles del Registro de contenedores de Google es la capacidad de escanear automáticamente sus contenedores en busca de vulnerabilidades. Hace unos meses, creé contenedores onbuild y multi-stage, así que veamos si hay alguna vulnerabilidad allí.



El resultado es sorprendente: solo se encontraron 3 vulnerabilidades medianas en un contenedor pequeño, y 16 vulnerabilidades críticas y otras 376 vulnerabilidades en uno grande. Si observa el contenido de un contenedor grande, puede ver que la mayoría de los problemas de seguridad no tienen nada que ver con nuestra aplicación, sino que están relacionados con programas que ni siquiera usamos. Entonces, cuando las personas hablan de una gran superficie para ataques, quieren decir exactamente eso.



La conclusión es obvia: cree contenedores pequeños porque proporcionan beneficios reales en el rendimiento y la seguridad de su sistema.

Mejores prácticas de Kubernetes. Organización de Kubernetes con espacio de nombres


Un poco de publicidad :)


Gracias por estar con nosotros. ¿Te gustan nuestros artículos? ¿Quieres ver más materiales interesantes? Apóyenos haciendo un pedido o recomendando a sus amigos, VPS en la nube para desarrolladores desde $ 4.99 , un análogo único de servidores de nivel básico que inventamos para usted: toda la verdad sobre VPS (KVM) E5-2697 v3 (6 núcleos) 10GB DDR4 480GB SSD 1Gbps desde $ 19 o cómo dividir el servidor? (las opciones están disponibles con RAID1 y RAID10, hasta 24 núcleos y hasta 40GB DDR4).

Dell R730xd 2 veces más barato en el centro de datos Equinix Tier IV en Amsterdam? ¡Solo tenemos 2 x Intel TetraDeca-Core Xeon 2x E5-2697v3 2.6GHz 14C 64GB DDR4 4x960GB SSD 1Gbps 100 TV desde $ 199 en los Países Bajos!Dell R420 - 2x E5-2430 2.2Ghz 6C 128GB DDR3 2x960GB SSD 1Gbps 100TB - ¡desde $ 99! Lea sobre Cómo construir un edificio de infraestructura. clase c con servidores Dell R730xd E5-2650 v4 que cuestan 9,000 euros por un centavo?

All Articles