{"id":81600,"date":"2020-05-15T01:42:41","date_gmt":"2020-05-14T23:42:41","guid":{"rendered":"https:\/\/prohoster.info\/blog\/administrirovanie\/neskolko-sovetov-o-tom-kak-uskorit-sborku-docker-obrazov-naprimer-do-30-sekund"},"modified":"2020-05-15T01:42:41","modified_gmt":"2020-05-14T23:42:41","slug":"neskolko-sovetov-o-tom-kak-uskorit-sborku-docker-obrazov-naprimer-do-30-sekund","status":"publish","type":"post","link":"https:\/\/prohoster.info\/es\/blog\/administrirovanie\/neskolko-sovetov-o-tom-kak-uskorit-sborku-docker-obrazov-naprimer-do-30-sekund","title":{"rendered":"Consejos sobre c\u00f3mo acelerar la construcci\u00f3n de im\u00e1genes de Docker. Por ejemplo, hasta 30 segundos.","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p>Antes de que una caracter\u00edstica llegue a producci\u00f3n, en nuestra era de complejos orquestadores y CI\/CD, hay un largo camino que recorrer desde el commit hasta las pruebas y la entrega. Antes, pod\u00edas simplemente subir nuevos archivos por FTP (aunque ahora ya nadie hace eso, \u00bfverdad?), y el proceso de 'despliegue' tomaba segundos. Ahora, debes crear una solicitud de fusi\u00f3n y esperar un buen tiempo hasta que la caracter\u00edstica llegue a los usuarios.<\/p>\n<p><\/p>\n<p>Parte de este camino es la construcci\u00f3n de la imagen de Docker. A veces, la construcci\u00f3n tarda minutos, en ocasiones, decenas de minutos, lo que es dif\u00edcil de llamar normal. En este art\u00edculo, tomaremos una aplicaci\u00f3n sencilla, la empaquetaremos en una imagen, aplicaremos varios m\u00e9todos para acelerar la construcci\u00f3n y examinaremos los matices del funcionamiento de esos m\u00e9todos.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Consejos sobre c\u00f3mo acelerar la construcci\u00f3n de im\u00e1genes de Docker. Por ejemplo, hasta 30 segundos.\" src=\"\/wp-content\/uploads\/2020\/05\/7d4775ca1ac64735dfcaba205416da50.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<p>Tenemos una buena experiencia en la creaci\u00f3n y mantenimiento de sitios web de medios: <noindex><a rel=\"nofollow\" href=\"https:\/\/tass.ru\/\">TASS<\/a><\/noindex>, <noindex><a rel=\"nofollow\" href=\"https:\/\/thebell.io\/\">The Bell<\/a><\/noindex>, <noindex><a rel=\"nofollow\" href=\"https:\/\/novayagazeta.ru\/\">\"Nueva Gazeta\"<\/a><\/noindex>, <noindex><a rel=\"nofollow\" href=\"https:\/\/republic.ru\/\">Republic<\/a><\/noindex>\u2026 Recientemente ampliamos nuestro portafolio al lanzar un sitio en producci\u00f3n. <noindex><a rel=\"nofollow\" href=\"https:\/\/reminder.media\">Reminder<\/a><\/noindex>. Y mientras r\u00e1pidamente implement\u00e1bamos nuevas funciones y correg\u00edamos errores antiguos, el despliegue lento se convirti\u00f3 en un gran problema.<\/p>\n<p><\/p>\n<p>El despliegue lo hacemos en GitLab. Construimos im\u00e1genes, las subimos al GitLab Registry y desplegamos en producci\u00f3n. Lo que m\u00e1s tiempo toma en esta lista es la construcci\u00f3n de im\u00e1genes. Por ejemplo: sin optimizaci\u00f3n, cada construcci\u00f3n del backend tomaba 14 minutos.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Consejos sobre c\u00f3mo acelerar la construcci\u00f3n de im\u00e1genes de Docker. Por ejemplo, hasta 30 segundos.\" src=\"\/wp-content\/uploads\/2020\/05\/043bc8ad67c34e1c7bd705433c5e4e77.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Al final, se hizo evidente que no se pod\u00eda seguir as\u00ed, y nos sentamos a investigar por qu\u00e9 las im\u00e1genes tardaban tanto en construirse. \u00a1Finalmente logramos reducir el tiempo de construcci\u00f3n a 30 segundos!<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Consejos sobre c\u00f3mo acelerar la construcci\u00f3n de im\u00e1genes de Docker. Por ejemplo, hasta 30 segundos.\" src=\"\/wp-content\/uploads\/2020\/05\/d035eb1c7b95e0345a110ee59f472693.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Para este art\u00edculo, para no depender del entorno de Reminder, examinemos un ejemplo de creaci\u00f3n de una aplicaci\u00f3n vac\u00eda en Angular. Entonces, creamos nuestra aplicaci\u00f3n:<\/p>\n<p><\/p>\n<pre><code class=\"bash\">ng n app<\/code><\/pre>\n<p><\/p>\n<p>Le a\u00f1adimos PWA (somos progresistas):<\/p>\n<p><\/p>\n<pre><code class=\"bash\">ng add @angular\/pwa --project app<\/code><\/pre>\n<p><\/p>\n<p>Mientras se descargan millones de paquetes npm, vamos a ver c\u00f3mo est\u00e1 estructurada la imagen de docker. Docker permite empaquetar aplicaciones y ejecutarlas en un entorno aislado llamado contenedor. Gracias a esta aislamiento, es posible ejecutar m\u00faltiples contenedores en un solo servidor. Los contenedores son significativamente m\u00e1s ligeros que las m\u00e1quinas virtuales, ya que se ejecutan directamente en el n\u00facleo del sistema. Para iniciar un contenedor con nuestra aplicaci\u00f3n, primero necesitamos crear una imagen que empaquete todo lo necesario para que funcione nuestra aplicaci\u00f3n. En esencia, una imagen es una instant\u00e1nea del sistema de archivos. Por ejemplo, tomemos el Dockerfile:<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">FROM node:12.16.2\nWORKDIR \/app\nCOPY . .\nRUN npm ci\nRUN npm run build --prod<\/code><\/pre>\n<p><\/p>\n<p>El Dockerfile es un conjunto de instrucciones; al ejecutar cada una de ellas, Docker guardar\u00e1 los cambios en el sistema de archivos y los aplicar\u00e1 a los anteriores. Cada comando crea su propia capa. La imagen resultante es la combinaci\u00f3n de estas capas.<\/p>\n<p><\/p>\n<p>Lo importante a tener en cuenta: cada capa puede ser cacheada. Si no hay cambios desde la \u00faltima construcci\u00f3n, Docker tomar\u00e1 la capa ya existente en lugar de ejecutar el comando. Dado que la principal mejora en la velocidad de construcci\u00f3n proviene del uso de la cach\u00e9, nos enfocaremos en medir la velocidad espec\u00edficamente al construir la imagen con la cach\u00e9 preparada. As\u00ed que, paso a paso:<\/p>\n<p><\/p>\n<ol>\n<li>Eliminamos las im\u00e1genes localmente para que las ejecuciones anteriores no afecten la prueba.<br \/>\n<code>docker rmi $(docker images -q)<\/code><\/li>\n<li>Ejecutamos la construcci\u00f3n por primera vez.<br \/>\n<code>time docker build -t app .<\/code><\/li>\n<li>Modificamos el archivo src\/index.html \u2014 simulamos el trabajo de un programador.<\/li>\n<li>Ejecutamos la construcci\u00f3n por segunda vez.<br \/>\n<code>time docker build -t app .<\/code><\/li>\n<\/ol>\n<p><\/p>\n<p>Si se configura correctamente el entorno para construir las im\u00e1genes (de esto hablaremos un poco m\u00e1s adelante), Docker ya tendr\u00e1 un mont\u00f3n de cach\u00e9s cuando se inicie la construcci\u00f3n. Nuestra tarea es aprender a utilizar la cach\u00e9 para que la construcci\u00f3n sea lo m\u00e1s r\u00e1pida posible. Dado que asumimos que la construcci\u00f3n sin cach\u00e9 ocurre solo una vez \u2014la primera\u2014, podemos ignorar cu\u00e1n lenta fue esa primera vez. En las pruebas, lo que nos importa es la segunda ejecuci\u00f3n de la construcci\u00f3n, cuando las cach\u00e9s ya est\u00e1n listas y estamos listos para hornear nuestro pastel. Sin embargo, algunos consejos tambi\u00e9n afectar\u00e1n la primera construcci\u00f3n.<\/p>\n<p><\/p>\n<p>Colocamos el Dockerfile, descrito anteriormente, en la carpeta del proyecto y comenzamos la construcci\u00f3n. Todos los listados presentados han sido abreviados para facilitar la lectura.<\/p>\n<p><\/p>\n<pre><code class=\"bash\">$ time docker build -t app .\nEnviando el contexto de construcci\u00f3n al demonio de Docker 409MB\nPaso 1\/5 : FROM node:12.16.2\nEstado: Imagen m\u00e1s reciente descargada para node:12.16.2\nPaso 2\/5 : WORKDIR \/app\nPaso 3\/5 : COPY . .\nPaso 4\/5 : RUN npm ci\nse a\u00f1adieron 1357 paquetes en 22.47s\nPaso 5\/5 : RUN npm run build --prod\nFecha: 2020-04-16T19:20:09.664Z - Hash: fffa0fddaa3425c55dd3 - Tiempo: 37581ms\nConstruido con \u00e9xito c8c279335f46\nEtiquetado exitosamente app:latest\n\nreal 5m4.541s\nuser 0m0.000s\nsys 0m0.000s<\/code><\/pre>\n<p><\/p>\n<p>Modificamos el contenido de src\/index.html y ejecutamos por segunda vez.<\/p>\n<p><\/p>\n<pre><code class=\"bash\">$ time docker build -t app .\nEnviando el contexto de construcci\u00f3n al demonio de Docker 409MB\nPaso 1\/5 : FROM node:12.16.2\nPaso 2\/5 : WORKDIR \/app\n ---&gt; Usando cach\u00e9\nPaso 3\/5 : COPY . .\nPaso 4\/5 : RUN npm ci\nse a\u00f1adieron 1357 paquetes en 22.47s\nPaso 5\/5 : RUN npm run build --prod\nFecha: 2020-04-16T19:26:26.587Z - Hash: fffa0fddaa3425c55dd3 - Tiempo: 37902ms\nConstruido con \u00e9xito 79f335df92d3\nEtiquetado exitosamente app:latest\n\nreal 3m33.262s\nuser 0m0.000s\nsys 0m0.000s<\/code><\/pre>\n<p><\/p>\n<p>Para ver si hemos obtenido la imagen, ejecutamos el comando <code>docker images<\/code>:<\/p>\n<p><\/p>\n<pre><code class=\"bash\">REPOSITORY   TAG      IMAGE ID       CREATED              SIZE\napp          latest   79f335df92d3   Hace aproximadamente un minuto     1.74GB<\/code><\/pre>\n<p><\/p>\n<p>Antes de construir, Docker toma todos los archivos del contexto actual y se los env\u00eda a su demonio <code>Enviando el contexto de construcci\u00f3n al demonio de Docker 409MB<\/code>. El contexto de construcci\u00f3n se especifica como el \u00faltimo argumento del comando build. En nuestro caso, es el directorio actual \u2014 \".\", \u2014 y Docker arrastra todo lo que tenemos en esta carpeta. 409 megabytes es mucho: pensemos en c\u00f3mo solucionarlo.<\/p>\n<p><\/p>\n<h2 id=\"umenshaem-kontekst\">Reduciendo el contexto<\/h2>\n<p><\/p>\n<p>Para reducir el contexto, hay dos opciones. O colocar todos los archivos necesarios para la construcci\u00f3n en una carpeta separada y especificar el contexto a Docker justo para esa carpeta. Esto puede no ser siempre conveniente, por lo que hay una opci\u00f3n para especificar excepciones: qu\u00e9 no debe arrastrarse al contexto. Para ello, colocaremos en el proyecto un archivo .dockerignore y especificaremos lo que no se necesita para la construcci\u00f3n:<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">.git\n\/node_modules<\/code><\/pre>\n<p><\/p>\n<p>y volveremos a iniciar la construcci\u00f3n:<\/p>\n<p><\/p>\n<pre><code class=\"bash\">$ time docker build -t app .\nEnviando el contexto de construcci\u00f3n al demonio de Docker 607.2kB\nPaso 1\/5 : FROM node:12.16.2\nPaso 2\/5 : WORKDIR \/app\n ---&gt; Usando cach\u00e9\nPaso 3\/5 : COPY . .\nPaso 4\/5 : RUN npm ci\nse a\u00f1adieron 1357 paquetes en 22.47s\nPaso 5\/5 : RUN npm run build --prod\nFecha: 2020-04-16T19:33:54.338Z - Hash: fffa0fddaa3425c55dd3 - Tiempo: 37313ms\nConstruido con \u00e9xito 4942f010792a\nEtiquetado con \u00e9xito app:latest\n\nreal 1m47.763s\nuser 0m0.000s\nsys 0m0.000s<\/code><\/pre>\n<p><\/p>\n<p>607.2 kB \u2014 mucho mejor que 409 MB. Adem\u00e1s, hemos reducido el tama\u00f1o de la imagen de 1.74 a 1.38 GB:<\/p>\n<p><\/p>\n<pre><code class=\"bash\">REPOSITORIO   ETIQUETA   ID DE IMAGEN       CREADO         TAMA\u00d1O\napp          latest   4942f010792a   hace 3 minutos   1.38GB<\/code><\/pre>\n<p><\/p>\n<p>Intentemos reducir a\u00fan m\u00e1s el tama\u00f1o de la imagen.<\/p>\n<p><\/p>\n<h2 id=\"ispolzuem-alpine\">Usando Alpine<\/h2>\n<p><\/p>\n<p>Otra forma de ahorrar en el tama\u00f1o de la imagen es utilizar una imagen base m\u00e1s peque\u00f1a. La imagen base es aquella de la cual se prepara nuestra imagen. La capa inferior se especifica con el comando <code>FROM<\/code> en el Dockerfile. En nuestro caso, estamos utilizando una imagen basada en Ubuntu, en la que ya est\u00e1 instalado Node.js. Y su tama\u00f1o es \u2026<\/p>\n<p><\/p>\n<pre><code class=\"bash\">$ docker images -a | grep node\nnode 12.16.2 406aa3abbc6c hace 17 minutos 916MB<\/code><\/pre>\n<p><\/p>\n<p>\u2026 casi un gigabyte. Se puede reducir considerablemente usando una imagen basada en Alpine Linux. Alpine es un Linux muy peque\u00f1o. La imagen de Docker para Node.js basada en Alpine pesa solo 88.5 MB. Por lo tanto, reemplacemos nuestra pesada imagen:<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">FROM node:12.16.2-alpine3.11\nRUN apk --no-cache --update --virtual build-dependencies add \n\tpython \n\tmake \n\tg++\nWORKDIR \/app\nCOPY . .\nRUN npm ci\nRUN npm run build --prod<\/code><\/pre>\n<p><\/p>\n<p>Tuvimos que instalar algunas cosas necesarias para construir la aplicaci\u00f3n. S\u00ed, Angular no se construye sin Python \u00af(\u00b0_o)\\\/\u00af<\/p>\n<p><\/p>\n<p>Pero el tama\u00f1o de la imagen se redujo en 150 MB:<\/p>\n<p><\/p>\n<pre><code class=\"bash\">REPOSITORIO   ETIQUETA   ID DE IMAGEN       CREADO          TAMA\u00d1O\napp          latest   aa031edc315a   hace 22 minutos   761MB<\/code><\/pre>\n<p><\/p>\n<p>Vamos a\u00fan m\u00e1s lejos.<\/p>\n<p><\/p>\n<h2 id=\"multisteydzh-sborka\">Construcci\u00f3n de m\u00faltiples etapas<\/h2>\n<p><\/p>\n<p>No todo lo que est\u00e1 en la imagen lo necesitamos en producci\u00f3n.<\/p>\n<p><\/p>\n<pre><code class=\"bash\">$ docker run app ls -lah\ntotal 576K\ndrwxr-xr-x 1 root root 4.0K Apr 16 19:54 .\ndrwxr-xr-x 1 root root 4.0K Apr 16 20:00 ..\n-rwxr-xr-x 1 root root 19 Apr 17 2020 .dockerignore\n-rwxr-xr-x 1 root root 246 Apr 17 2020 .editorconfig\n-rwxr-xr-x 1 root root 631 Apr 17 2020 .gitignore\n-rwxr-xr-x 1 root root 181 Apr 17 2020 Dockerfile\n-rwxr-xr-x 1 root root 1020 Apr 17 2020 README.md\n-rwxr-xr-x 1 root root 3.6K Apr 17 2020 angular.json\n-rwxr-xr-x 1 root root 429 Apr 17 2020 browserslist\ndrwxr-xr-x 3 root root 4.0K Apr 16 19:54 dist\ndrwxr-xr-x 3 root root 4.0K Apr 17 2020 e2e\n-rwxr-xr-x 1 root root 1015 Apr 17 2020 karma.conf.js\n-rwxr-xr-x 1 root root 620 Apr 17 2020 ngsw-config.json\ndrwxr-xr-x 1 root root 4.0K Apr 16 19:54 node_modules\n-rwxr-xr-x 1 root root 494.9K Apr 17 2020 package-lock.json\n-rwxr-xr-x 1 root root 1.3K Apr 17 2020 package.json\ndrwxr-xr-x 5 root root 4.0K Apr 17 2020 src\n-rwxr-xr-x 1 root root 210 Apr 17 2020 tsconfig.app.json\n-rwxr-xr-x 1 root root 489 Apr 17 2020 tsconfig.json\n-rwxr-xr-x 1 root root 270 Apr 17 2020 tsconfig.spec.json\n-rwxr-xr-x 1 root root 1.9K Apr 17 2020 tslint.json<\/code><\/pre>\n<p><\/p>\n<p>Con <code>docker run app ls -lah<\/code> hemos lanzado un contenedor basado en nuestra imagen <code>app<\/code> y hemos ejecutado en \u00e9l el comando <code>ls -lah<\/code>, despu\u00e9s de lo cual el contenedor termin\u00f3 su trabajo.<\/p>\n<p><\/p>\n<p>En producci\u00f3n solo necesitamos la carpeta <code>dist<\/code>. Sin embargo, debemos exponer los archivos de alguna manera. Podemos iniciar alg\u00fan servidor HTTP en nodejs. Pero haremos algo m\u00e1s sencillo. Adivina la palabra rusa que tiene cuatro letras \u00ab\u044b\u00bb. \u00a1Correcto! \u042b\u043d\u0436\u044b\u043d\u044b\u043a\u0441\u044b. Tomaremos una imagen con nginx, colocaremos en ella la carpeta <code>dist<\/code> y una peque\u00f1a configuraci\u00f3n:<\/p>\n<p><\/p>\n<pre><code class=\"nginx\">server {\n    listen 80 default_server;\n    server_name localhost;\n    charset utf-8;\n    root \/app\/dist;\n\n    location \/ {\n        try_files $uri $uri\/ \/index.html;\n    }\n}<\/code><\/pre>\n<p><\/p>\n<p>Todo esto lo lograremos con una construcci\u00f3n de m\u00faltiples etapas. Cambiaremos nuestro Dockerfile:<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">FROM node:12.16.2-alpine3.11 as builder\nRUN apk --no-cache --update --virtual build-dependencies add \n    python \n    make \n    g++\nWORKDIR \/app\nCOPY . .\nRUN npm ci\nRUN npm run build --prod\n\nFROM nginx:1.17.10-alpine\nRUN rm \/etc\/nginx\/conf.d\/default.conf\nCOPY nginx\/static.conf \/etc\/nginx\/conf.d\nCOPY --from=builder \/app\/dist\/app .<\/code><\/pre>\n<p><\/p>\n<p>Ahora tenemos dos instrucciones <code>FROM<\/code> en el Dockerfile, cada una de ellas ejecuta su propia etapa de construcci\u00f3n. La primera la llamamos <code>en Raspberry Pi 3 con n\u00facleos un-def, lts, mp al usar pulseaudio es necesario desconectar una de las tarjetas de audio (auriculares o HDMI), de lo contrario, puede haber un apagado prolongado del equipo y se puede perder el sonido debido a pulseaudio atascado.<\/code>, y a partir del \u00faltimo FROM se preparar\u00e1 nuestra imagen final. El \u00faltimo paso es copiar el artefacto de nuestra construcci\u00f3n de la etapa anterior a la imagen final con nginx. El tama\u00f1o de la imagen se ha reducido considerablemente:<\/p>\n<p><\/p>\n<pre><code class=\"bash\">REPOSITORY   TAG      IMAGE ID       CREATED          SIZE\napp          latest   2c6c5da07802   hace 29 minutos   36MB<\/code><\/pre>\n<p><\/p>\n<p>Vamos a iniciar un contenedor con nuestra imagen y asegur\u00e9monos de que todo funciona:<\/p>\n<p><\/p>\n<pre><code class=\"bash\">docker run -p8080:80 app<\/code><\/pre>\n<p><\/p>\n<p>Con la opci\u00f3n -p8080:80 hemos redirigido el puerto 8080 en nuestra m\u00e1quina host al puerto 80 dentro del contenedor, donde se ejecuta nginx. Abrimos en el navegador <noindex><a rel=\"nofollow\" href=\"http:\/\/localhost:8080\/\">http:\/\/localhost:8080\/<\/a><\/noindex> y vemos nuestra aplicaci\u00f3n. \u00a1Todo funciona!<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Consejos sobre c\u00f3mo acelerar la construcci\u00f3n de im\u00e1genes de Docker. Por ejemplo, hasta 30 segundos.\" src=\"\/wp-content\/uploads\/2020\/05\/ab37d9576a84954f4e4860dd49a75f3d.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>La reducci\u00f3n del tama\u00f1o de la imagen de 1.74 GB a 36 MB reduce significativamente el tiempo de entrega de su aplicaci\u00f3n en producci\u00f3n. Pero regresemos al tiempo de construcci\u00f3n.<\/p>\n<p><\/p>\n<pre><code class=\"bash\">$ time docker build -t app .\nSending build context to Docker daemon 608.8kB\nStep 1\/11 : FROM node:12.16.2-alpine3.11 as builder\nStep 2\/11 : RUN apk --no-cache --update --virtual build-dependencies add python make g++\n ---&gt; Using cache\nStep 3\/11 : WORKDIR \/app\n ---&gt; Using cache\nStep 4\/11 : COPY . .\nStep 5\/11 : RUN npm ci\nadded 1357 packages in 47.338s\nStep 6\/11 : RUN npm run build --prod\nDate: 2020-04-16T21:16:03.899Z - Hash: fffa0fddaa3425c55dd3 - Time: 39948ms\n ---&gt; 27f1479221e4\nStep 7\/11 : FROM nginx:stable-alpine\nStep 8\/11 : WORKDIR \/app\n ---&gt; Using cache\nStep 9\/11 : RUN rm \/etc\/nginx\/conf.d\/default.conf\n ---&gt; Using cache\nStep 10\/11 : COPY nginx\/static.conf \/etc\/nginx\/conf.d\n ---&gt; Using cache\nStep 11\/11 : COPY --from=builder \/app\/dist\/app .\nSuccessfully built d201471c91ad\nSuccessfully tagged app:latest\n\nreal 2m17.700s\nuser 0m0.000s\nsys 0m0.000s<\/code><\/pre>\n<p><\/p>\n<h2 id=\"menyaem-poryadok-sloyov\">Cambiamos el orden de las capas<\/h2>\n<p><\/p>\n<p>Los primeros tres pasos han sido cacheados (sugerencia <code>Using cache<\/code>). En el cuarto paso se copian todos los archivos del proyecto y en el quinto se instalan las dependencias <code>RUN npm ci<\/code> \u2014 un total de 47.338s. \u00bfPor qu\u00e9 volver a instalar las dependencias si cambian muy raramente? Vamos a entender por qu\u00e9 no se almacenaron en cach\u00e9. La cuesti\u00f3n es que Docker revisa capa por capa si el comando y los archivos asociados han cambiado. En el cuarto paso copiamos todos los archivos de nuestro proyecto, y entre ellos, por supuesto, hay cambios, por lo que Docker no solo no toma esa capa de la cach\u00e9, sino que tampoco toma las siguientes. Hagamos un peque\u00f1o cambio en el Dockerfile.<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">FROM node:12.16.2-alpine3.11 as builder\nRUN apk --no-cache --update --virtual build-dependencies add \n    python \n    make \n    g++\nWORKDIR \/app\nCOPY package*.json .\/\nRUN npm ci\nCOPY . .\nRUN npm run build --prod\n\nFROM nginx:1.17.10-alpine\nRUN rm \/etc\/nginx\/conf.d\/default.conf\nCOPY nginx\/static.conf \/etc\/nginx\/conf.d\nCOPY --from=builder \/app\/dist\/app .<\/code><\/pre>\n<p><\/p>\n<p>Primero se copian package.json y package-lock.json, luego se instalan las dependencias, y solo despu\u00e9s se copia todo el proyecto. Como resultado:<\/p>\n<p><\/p>\n<pre><code class=\"bash\">$ time docker build -t app .\nSending build context to Docker daemon 608.8kB\nStep 1\/12 : FROM node:12.16.2-alpine3.11 as builder\nStep 2\/12 : RUN apk --no-cache --update --virtual build-dependencies add python make g++\n ---&gt; Using cache\nStep 3\/12 : WORKDIR \/app\n ---&gt; Using cache\nStep 4\/12 : COPY package*.json .\/\n ---&gt; Using cache\nStep 5\/12 : RUN npm ci\n ---&gt; Using cache\nStep 6\/12 : COPY . .\nStep 7\/12 : RUN npm run build --prod\nDate: 2020-04-16T21:29:44.770Z - Hash: fffa0fddaa3425c55dd3 - Time: 38287ms\n ---&gt; 1b9448c73558\nStep 8\/12 : FROM nginx:stable-alpine\nStep 9\/12 : WORKDIR \/app\n ---&gt; Using cache\nStep 10\/12 : RUN rm \/etc\/nginx\/conf.d\/default.conf\n ---&gt; Using cache\nStep 11\/12 : COPY nginx\/static.conf \/etc\/nginx\/conf.d\n ---&gt; Using cache\nStep 12\/12 : COPY --from=builder \/app\/dist\/app .\nSuccessfully built a44dd7c217c3\nSuccessfully tagged app:latest\n\nreal 0m46.497s\nuser 0m0.000s\nsys 0m0.000s<\/code><\/pre>\n<p><\/p>\n<p>46 segundos en lugar de 3 minutos \u2014 \u00a1mucho mejor! Es importante el orden correcto de las capas: primero copiamos lo que no cambia, luego lo que cambia raramente, y al final \u2014 lo que cambia con frecuencia.<\/p>\n<p><\/p>\n<p>A continuaci\u00f3n, algunas palabras sobre la construcci\u00f3n de im\u00e1genes en sistemas CI\/CD.<\/p>\n<p><\/p>\n<h2 id=\"ispolzovanie-predyduschih-obrazov-dlya-kesha\">Uso de im\u00e1genes anteriores para la cach\u00e9<\/h2>\n<p><\/p>\n<p>Si utilizamos alguna soluci\u00f3n SaaS para la construcci\u00f3n, la cach\u00e9 local de Docker puede estar limpia y fresca. Para que Docker tenga de d\u00f3nde obtener las capas cocidas, proporci\u00f3nale la imagen compilada anterior.<\/p>\n<p><\/p>\n<p>Tomemos como ejemplo la construcci\u00f3n de nuestra aplicaci\u00f3n en GitHub Actions. Usamos esta configuraci\u00f3n<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">on:\n  push:\n    branches:\n      - master\n\nname: Prueba de construcci\u00f3n de docker\n\njobs:\n  deploy:\n    name: Construcci\u00f3n\n    runs-on: ubuntu-latest\n    env:\n      IMAGE_NAME: docker.pkg.github.com\/${{ github.repository }}\/app\n      IMAGE_TAG: ${{ github.sha }}\n\n    steps:\n    - name: Checkout\n      uses: actions\/checkout@v2\n\n    - name: Iniciar sesi\u00f3n en GitHub Packages\n      env:\n        TOKEN: ${{ secrets.GITHUB_TOKEN }}\n      run: |\n        docker login docker.pkg.github.com -u $GITHUB_ACTOR -p $TOKEN\n\n    - name: Construcci\u00f3n\n      run: |\n        docker build \n          -t $IMAGE_NAME:$IMAGE_TAG \n          -t $IMAGE_NAME:latest \n          .\n\n    - name: Subir imagen a GitHub Packages\n      run: |\n        docker push $IMAGE_NAME:latest\n        docker push $IMAGE_NAME:$IMAGE_TAG\n\n    - name: Cerrar sesi\u00f3n\n      run: |\n        docker logout docker.pkg.github.com<\/code><\/pre>\n<p><\/p>\n<p>La imagen se construye y se sube a GitHub Packages en dos minutos y 20 segundos:<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Consejos sobre c\u00f3mo acelerar la construcci\u00f3n de im\u00e1genes de Docker. Por ejemplo, hasta 30 segundos.\" src=\"\/wp-content\/uploads\/2020\/05\/76b81216922f7ef2c4e777b60238acd5.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Ahora vamos a modificar la construcci\u00f3n para utilizar la cach\u00e9 basada en las im\u00e1genes construidas previamente:<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">on:\n  push:\n    branches:\n      - master\n\nname: Prueba de construcci\u00f3n de docker\n\njobs:\n  deploy:\n    name: Construcci\u00f3n\n    runs-on: ubuntu-latest\n    env:\n      IMAGE_NAME: docker.pkg.github.com\/${{ github.repository }}\/app\n      IMAGE_TAG: ${{ github.sha }}\n\n    steps:\n    - name: Checkout\n      uses: actions\/checkout@v2\n\n    - name: Iniciar sesi\u00f3n en GitHub Packages\n      env:\n        TOKEN: ${{ secrets.GITHUB_TOKEN }}\n      run: |\n        docker login docker.pkg.github.com -u $GITHUB_ACTOR -p $TOKEN\n\n    - name: Descargar im\u00e1genes m\u00e1s recientes\n      run: |\n        docker pull $IMAGE_NAME:latest || true\n        docker pull $IMAGE_NAME-builder-stage:latest || true\n\n    - name: Lista de im\u00e1genes\n      run: |\n        docker images\n\n    - name: Construcci\u00f3n\n      run: |\n        docker build \n          --target builder \n          --cache-from $IMAGE_NAME-builder-stage:latest \n          -t $IMAGE_NAME-builder-stage \n          .\n        docker build \n          --cache-from $IMAGE_NAME-builder-stage:latest \n          --cache-from $IMAGE_NAME:latest \n          -t $IMAGE_NAME:$IMAGE_TAG \n          -t $IMAGE_NAME:latest \n          .\n\n    - name: Subir imagen a GitHub Packages\n      run: |\n        docker push $IMAGE_NAME-builder-stage:latest\n        docker push $IMAGE_NAME:latest\n        docker push $IMAGE_NAME:$IMAGE_TAG\n\n    - name: Cerrar sesi\u00f3n\n      run: |\n        docker logout docker.pkg.github.com<\/code><\/pre>\n<p><\/p>\n<p>Para comenzar, es necesario explicar por qu\u00e9 se ejecutan dos comandos. <code>build<\/code>La raz\u00f3n es que, en una construcci\u00f3n de m\u00faltiples etapas, el resultado ser\u00e1 un conjunto de capas de la \u00faltima etapa. Sin embargo, las capas de etapas anteriores no se incorporar\u00e1n a la imagen. Por lo tanto, al utilizar la imagen final de una construcci\u00f3n anterior, Docker no podr\u00e1 encontrar las capas necesarias para construir la imagen con nodejs (etapa builder). Para resolver este problema, se crea una imagen intermedia. <code>$IMAGE_NAME-builder-stage<\/code> y se env\u00eda a GitHub Packages, para poder ser utilizada en construcciones posteriores como fuente de cach\u00e9.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Consejos sobre c\u00f3mo acelerar la construcci\u00f3n de im\u00e1genes de Docker. Por ejemplo, hasta 30 segundos.\" src=\"\/wp-content\/uploads\/2020\/05\/acaa70ae528589f4be2258650d8eb5de.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>El tiempo total de construcci\u00f3n se ha reducido a un minuto y medio. Se requieren 30 segundos para recuperar las im\u00e1genes anteriores.<\/p>\n<p><\/p>\n<h2 id=\"predvaritelnoe-sozdanie-obrazov\">Creaci\u00f3n preliminar de im\u00e1genes<\/h2>\n<p><\/p>\n<p>Otra forma de abordar el problema de la cach\u00e9 limpia de Docker es trasladar algunas capas a otro Dockerfile, compilarlo por separado, subirlo al Container Registry y usarlo como base.<\/p>\n<p><\/p>\n<p>Creamos nuestra imagen de nodejs para compilar la aplicaci\u00f3n Angular. Creamos en el proyecto Dockerfile.node<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">FROM node:12.16.2-alpine3.11\nRUN apk --no-cache --update --virtual build-dependencies add \n    python \n    make \n    g++<\/code><\/pre>\n<p><\/p>\n<p>Construimos y publicamos la imagen p\u00fablica en Docker Hub:<\/p>\n<p><\/p>\n<pre><code class=\"bash\">docker build -t exsmund\/node-for-angular -f Dockerfile.node .\ndocker push exsmund\/node-for-angular:latest<\/code><\/pre>\n<p><\/p>\n<p>Ahora en nuestro Dockerfile principal usamos la imagen ya preparada:<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">FROM exsmund\/node-for-angular:latest as builder\n...<\/code><\/pre>\n<p><\/p>\n<p>En nuestro ejemplo, el tiempo de construcci\u00f3n no se redujo, pero las im\u00e1genes previamente creadas pueden ser \u00fatiles si tienes muchos proyectos y en cada uno de ellos tienes que instalar dependencias id\u00e9nticas.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Consejos sobre c\u00f3mo acelerar la construcci\u00f3n de im\u00e1genes de Docker. Por ejemplo, hasta 30 segundos.\" src=\"\/wp-content\/uploads\/2020\/05\/5b4e4bd1d4b96a3f07305d2dd0f6d680.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Hemos revisado varios m\u00e9todos para acelerar la construcci\u00f3n de im\u00e1genes de Docker. Si deseas que el despliegue sea r\u00e1pido, intenta aplicar en tu proyecto:<\/p>\n<p><\/p>\n<ul>\n<li>reducci\u00f3n del contexto;<\/li>\n<li>uso de im\u00e1genes base peque\u00f1as;<\/li>\n<li>construcci\u00f3n de m\u00faltiples etapas;<\/li>\n<li>cambio en el orden de las instrucciones en el Dockerfile para utilizar el cach\u00e9 de manera efectiva;<\/li>\n<li>configuraci\u00f3n de la cach\u00e9 en sistemas CI\/CD;<\/li>\n<li>creaci\u00f3n previa de im\u00e1genes.<\/li>\n<\/ul>\n<p><\/p>\n<p>Espero que con este ejemplo quede m\u00e1s claro c\u00f3mo funciona Docker, y podr\u00e1s ajustar \u00f3ptimamente tu despliegue. Para experimentar con los ejemplos del art\u00edculo, se ha creado un repositorio <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/devopsprodigy\/test-docker-build\">https:\/\/github.com\/devopsprodigy\/test-docker-build<\/a><\/noindex>.<\/p>\n<p>Fuente: <a content=\"nofollow\" rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/itsumma\/blog\/501680\/\">habr.com<\/a> <\/p>","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"excerpt":{"rendered":"<p>\u041f\u0440\u0435\u0436\u0434\u0435 \u0447\u0435\u043c \u0444\u0438\u0447\u0430 \u043f\u043e\u043f\u0430\u0434\u0435\u0442 \u043d\u0430 \u043f\u0440\u043e\u0434, \u0432 \u043d\u0430\u0448\u0435 \u0432\u0440\u0435\u043c\u044f \u0441\u043b\u043e\u0436\u043d\u044b\u0445 \u043e\u0440\u043a\u0435\u0441\u0442\u0440\u0430\u0442\u043e\u0440\u043e\u0432 \u0438 CI\/CD \u043f\u0440\u0435\u0434\u0441\u0442\u043e\u0438\u0442 \u043f\u0440\u043e\u0439\u0442\u0438 \u0434\u043e\u043b\u0433\u0438\u0439 \u043f\u0443\u0442\u044c \u043e\u0442 \u043a\u043e\u043c\u043c\u0438\u0442\u0430 \u0434\u043e \u0442\u0435\u0441\u0442\u043e\u0432 \u0438 \u0434\u043e\u0441\u0442\u0430\u0432\u043a\u0438. \u0420\u0430\u043d\u044c\u0448\u0435 \u043c\u043e\u0436\u043d\u043e \u0431\u044b\u043b\u043e \u043a\u0438\u043d\u0443\u0442\u044c \u043d\u043e\u0432\u044b\u0435 \u0444\u0430\u0439\u043b\u044b \u043f\u043e FTP (\u0442\u0430\u043a \u0431\u043e\u043b\u044c\u0448\u0435 \u0442\u0430\u043a \u043d\u0438\u043a\u0442\u043e \u043d\u0435 \u0434\u0435\u043b\u0430\u0435\u0442, \u0432\u0435\u0440\u043d\u043e?), \u0438 \u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u00ab\u0434\u0435\u043f\u043b\u043e\u044f\u00bb \u0437\u0430\u043d\u0438\u043c\u0430\u043b \u0441\u0435\u043a\u0443\u043d\u0434\u044b. \u0422\u0435\u043f\u0435\u0440\u044c \u0436\u0435 \u043d\u0430\u0434\u043e \u0441\u043e\u0437\u0434\u0430\u0442\u044c merge request \u0438 \u0436\u0434\u0430\u0442\u044c \u043d\u0435\u043c\u0430\u043b\u043e\u0435 \u0432\u0440\u0435\u043c\u044f, \u043f\u043e\u043a\u0430 \u0444\u0438\u0447\u0430 [&hellip;]<\/p>\n","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"author":1,"featured_media":81601,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[688],"tags":[],"class_list":["post-81600","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-administrirovanie"],"aioseo_notices":[],"aioseo_head":"\n\t\t<!-- All in One SEO 5.0.2 - aioseo.com -->\n\t<meta name=\"description\" content=\"\u041f\u0440\u0435\u0436\u0434\u0435 \u0447\u0435\u043c \u0444\u0438\u0447\u0430 \u043f\u043e\u043f\u0430\u0434\u0435\u0442 \u043d\u0430 \u043f\u0440\u043e\u0434, \u0432 \u043d\u0430\u0448\u0435 \u0432\u0440\u0435\u043c\u044f \u0441\u043b\u043e\u0436\u043d\u044b\u0445 \u043e\u0440\u043a\u0435\u0441\u0442\u0440\u0430\u0442\u043e\u0440\u043e\u0432 \u0438 CI\/CD \u043f\u0440\u0435\u0434\u0441\u0442\u043e\u0438\u0442 \u043f\u0440\u043e\u0439\u0442\u0438 \u0434\u043e\u043b\u0433\u0438\u0439 \u043f\u0443\u0442\u044c \u043e\u0442 \u043a\u043e\u043c\u043c\u0438\u0442\u0430 \u0434\u043e \u0442\u0435\u0441\u0442\u043e\u0432 \u0438 \u0434\u043e\u0441\u0442\u0430\u0432\u043a\u0438.\" \/>\n\t<meta name=\"robots\" content=\"max-image-preview:large\" \/>\n\t<meta name=\"author\" content=\"Yuri Gagarin\"\/>\n\t<link rel=\"canonical\" href=\"https:\/\/prohoster.info\/es\/blog\/administrirovanie\/neskolko-sovetov-o-tom-kak-uskorit-sborku-docker-obrazov-naprimer-do-30-sekund\" \/>\n\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.2\" \/>\n\t\t<meta property=\"og:locale\" content=\"es_ES\" \/>\n\t\t<meta property=\"og:site_name\" content=\"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b\" \/>\n\t\t<meta property=\"og:type\" content=\"article\" \/>\n\t\t<meta property=\"og:title\" content=\"\ud83e\udd47\u041d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0441\u043e\u0432\u0435\u0442\u043e\u0432 \u043e \u0442\u043e\u043c, \u043a\u0430\u043a \u0443\u0441\u043a\u043e\u0440\u0438\u0442\u044c \u0441\u0431\u043e\u0440\u043a\u0443 Docker-\u043e\u0431\u0440\u0430\u0437\u043e\u0432. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0434\u043e 30 \u0441\u0435\u043a\u0443\u043d\u0434 | ProHoster\" \/>\n\t\t<meta property=\"og:description\" content=\"\u041f\u0440\u0435\u0436\u0434\u0435 \u0447\u0435\u043c \u0444\u0438\u0447\u0430 \u043f\u043e\u043f\u0430\u0434\u0435\u0442 \u043d\u0430 \u043f\u0440\u043e\u0434, \u0432 \u043d\u0430\u0448\u0435 \u0432\u0440\u0435\u043c\u044f \u0441\u043b\u043e\u0436\u043d\u044b\u0445 \u043e\u0440\u043a\u0435\u0441\u0442\u0440\u0430\u0442\u043e\u0440\u043e\u0432 \u0438 CI\/CD \u043f\u0440\u0435\u0434\u0441\u0442\u043e\u0438\u0442 \u043f\u0440\u043e\u0439\u0442\u0438 \u0434\u043e\u043b\u0433\u0438\u0439 \u043f\u0443\u0442\u044c \u043e\u0442 \u043a\u043e\u043c\u043c\u0438\u0442\u0430 \u0434\u043e \u0442\u0435\u0441\u0442\u043e\u0432 \u0438 \u0434\u043e\u0441\u0442\u0430\u0432\u043a\u0438.\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/prohoster.info\/es\/blog\/administrirovanie\/neskolko-sovetov-o-tom-kak-uskorit-sborku-docker-obrazov-naprimer-do-30-sekund\" \/>\n\t\t<meta property=\"og:image\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:secure_url\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:width\" content=\"350\" \/>\n\t\t<meta property=\"og:image:height\" content=\"350\" \/>\n\t\t<meta property=\"article:published_time\" content=\"2020-05-14T23:42:41+00:00\" \/>\n\t\t<meta property=\"article:modified_time\" content=\"2020-05-14T23:42:41+00:00\" \/>\n\t\t<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<meta property=\"article:author\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<!-- All in One SEO -->\n\n","aioseo_head_json":{"title":"\ud83e\udd47Algunos consejos sobre c\u00f3mo acelerar la construcci\u00f3n de im\u00e1genes Docker. Por ejemplo, hasta 30 segundos | ProHoster","description":"Antes de que la funci\u00f3n llegue a producci\u00f3n, en nuestra \u00e9poca de complejos orquestadores y CI\/CD, debe recorrer un largo camino desde el commit hasta las pruebas y la entrega.","canonical_url":"https:\/\/prohoster.info\/es\/blog\/administrirovanie\/neskolko-sovetov-o-tom-kak-uskorit-sborku-docker-obrazov-naprimer-do-30-sekund","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"es_ES","og:site_name":"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b","og:type":"article","og:title":"\ud83e\udd47\u041d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0441\u043e\u0432\u0435\u0442\u043e\u0432 \u043e \u0442\u043e\u043c, \u043a\u0430\u043a \u0443\u0441\u043a\u043e\u0440\u0438\u0442\u044c \u0441\u0431\u043e\u0440\u043a\u0443 Docker-\u043e\u0431\u0440\u0430\u0437\u043e\u0432. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0434\u043e 30 \u0441\u0435\u043a\u0443\u043d\u0434 | ProHoster","og:description":"\u041f\u0440\u0435\u0436\u0434\u0435 \u0447\u0435\u043c \u0444\u0438\u0447\u0430 \u043f\u043e\u043f\u0430\u0434\u0435\u0442 \u043d\u0430 \u043f\u0440\u043e\u0434, \u0432 \u043d\u0430\u0448\u0435 \u0432\u0440\u0435\u043c\u044f \u0441\u043b\u043e\u0436\u043d\u044b\u0445 \u043e\u0440\u043a\u0435\u0441\u0442\u0440\u0430\u0442\u043e\u0440\u043e\u0432 \u0438 CI\/CD \u043f\u0440\u0435\u0434\u0441\u0442\u043e\u0438\u0442 \u043f\u0440\u043e\u0439\u0442\u0438 \u0434\u043e\u043b\u0433\u0438\u0439 \u043f\u0443\u0442\u044c \u043e\u0442 \u043a\u043e\u043c\u043c\u0438\u0442\u0430 \u0434\u043e \u0442\u0435\u0441\u0442\u043e\u0432 \u0438 \u0434\u043e\u0441\u0442\u0430\u0432\u043a\u0438.","og:url":"https:\/\/prohoster.info\/es\/blog\/administrirovanie\/neskolko-sovetov-o-tom-kak-uskorit-sborku-docker-obrazov-naprimer-do-30-sekund","og:image":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:secure_url":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:width":350,"og:image:height":350,"article:published_time":"2020-05-14T23:42:41+00:00","article:modified_time":"2020-05-14T23:42:41+00:00","article:publisher":"https:\/\/www.facebook.com\/prohoster","article:author":"https:\/\/www.facebook.com\/prohoster"},"aioseo_meta_data":{"post_id":"81600","title":null,"description":null,"keywords":null,"keyphrases":null,"primary_term":null,"canonical_url":null,"og_title":null,"og_description":null,"og_object_type":"default","og_image_type":"default","og_image_url":null,"og_image_width":null,"og_image_height":null,"og_image_custom_url":null,"og_image_custom_fields":null,"og_video":null,"og_custom_url":null,"og_article_section":null,"og_article_tags":null,"twitter_use_og":false,"twitter_card":"default","twitter_image_type":"default","twitter_image_url":null,"twitter_image_custom_url":null,"twitter_image_custom_fields":null,"twitter_title":null,"twitter_description":null,"schema":{"blockGraphs":[],"customGraphs":[],"default":{"data":{"Article":[],"Course":[],"Dataset":[],"FAQPage":[],"Movie":[],"Person":[],"Product":[],"ProductReview":[],"Car":[],"Recipe":[],"Service":[],"SoftwareApplication":[],"WebPage":[]},"graphName":"","isEnabled":true},"graphs":[]},"schema_type":null,"schema_type_options":null,"pillar_content":false,"robots_default":true,"robots_noindex":false,"robots_noarchive":false,"robots_nosnippet":false,"robots_nofollow":false,"robots_noimageindex":false,"robots_noodp":false,"robots_notranslate":false,"robots_max_snippet":null,"robots_max_videopreview":null,"robots_max_imagepreview":"large","priority":null,"frequency":null,"local_seo":null,"seo_analyzer_scan_date":null,"breadcrumb_settings":null,"limit_modified_date":false,"reviewed_by":null,"ai":null,"created":"2021-02-28 15:55:42","updated":"2022-09-29 02:10:06","focus_keyword":null,"additional_keywords":null,"truseo_locale":null},"gt_translate_keys":[{"key":"link","format":"url"}],"_links":{"self":[{"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/posts\/81600","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/comments?post=81600"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/posts\/81600\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/media\/81601"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/media?parent=81600"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/categories?post=81600"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/tags?post=81600"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}