{"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\/it\/blog\/administrirovanie\/neskolko-sovetov-o-tom-kak-uskorit-sborku-docker-obrazov-naprimer-do-30-sekund","title":{"rendered":"Alcuni consigli su come velocizzare la costruzione delle immagini Docker. Ad esempio, fino a 30 secondi","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p>Prima che una funzionalit\u00e0 arrivi in produzione, al giorno d'oggi, con orchestratori complessi e CI\/CD, c'\u00e8 un lungo percorso da affrontare, dal commit ai test e alla consegna. In passato era possibile trasferire nuovi file via FTP (ma nessuno lo fa pi\u00f9, giusto?), e il processo di \"deploy\" richiedeva secondi. Ora, invece, bisogna creare una merge request e attendere un bel po' di tempo prima che la funzionalit\u00e0 raggiunga gli utenti.<\/p>\n<p><\/p>\n<p>Parte di questo percorso \u00e8 la costruzione dell'immagine Docker. A volte la costruzione richiede minuti, altre volte decine di minuti, il che \u00e8 difficile da considerare normale. In questo articolo prenderemo come esempio un'applicazione semplice, la confezioneremo in un'immagine, applicheremo diversi metodi per accelerare la costruzione e esamineremo le sfide legate a questi metodi.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Alcuni consigli su come velocizzare la costruzione delle immagini Docker. Ad esempio, fino a 30 secondi\" 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>Abbiamo una buona esperienza nella creazione e nel supporto di siti per i media: <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\/\">&quot;Nuova Gazeta&quot;<\/a><\/noindex>, <noindex><a rel=\"nofollow\" href=\"https:\/\/republic.ru\/\">Republic<\/a><\/noindex>\u2026 Non molto tempo fa abbiamo ampliato il nostro portafoglio, lanciando un sito in produzione <noindex><a rel=\"nofollow\" href=\"https:\/\/reminder.media\">Reminder<\/a><\/noindex>. E mentre ci affrettavamo a completare nuove funzionalit\u00e0 e risolvere bug vecchi, il deploy lento \u00e8 diventato un grosso problema.<\/p>\n<p><\/p>\n<p>Effettuiamo il deploy su GitLab. Creiamo immagini, le carichiamo nel GitLab Registry e le distribuiamo in produzione. La parte pi\u00f9 lunga di questo processo \u00e8 la costruzione delle immagini. Ad esempio: senza ottimizzazione, ogni costruzione del backend richiedeva 14 minuti.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Alcuni consigli su come velocizzare la costruzione delle immagini Docker. Ad esempio, fino a 30 secondi\" src=\"\/wp-content\/uploads\/2020\/05\/043bc8ad67c34e1c7bd705433c5e4e77.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Alla fine ci siamo resi conto che non era possibile continuare in questo modo, e ci siamo messi a capire perch\u00e9 le immagini impiegassero cos\u00ec tanto tempo a essere costruite. Alla fine, siamo riusciti a ridurre il tempo di costruzione a 30 secondi!<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Alcuni consigli su come velocizzare la costruzione delle immagini Docker. Ad esempio, fino a 30 secondi\" src=\"\/wp-content\/uploads\/2020\/05\/d035eb1c7b95e0345a110ee59f472693.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Per questo articolo, per non legarci all'ambiente di Reminder, consideriamo un esempio di creazione di un'applicazione vuota su Angular. Quindi, creiamo la nostra applicazione:<\/p>\n<p><\/p>\n<pre><code class=\"bash\">ng n app<\/code><\/pre>\n<p><\/p>\n<p>Aggiungiamoci PWA (siamo pur sempre progressivi):<\/p>\n<p><\/p>\n<pre><code class=\"bash\">ng add @angular\/pwa --project app<\/code><\/pre>\n<p><\/p>\n<p>Mentre si scaricano milioni di pacchetti npm, diamo un'occhiata a come \u00e8 strutturata l'immagine Docker. Docker offre la possibilit\u00e0 di confezionare applicazioni e farle girare in un ambiente isolato, chiamato contenitore. Grazie all'isolamento, \u00e8 possibile eseguire molti contenitori contemporaneamente su un singolo server. I contenitori sono significativamente pi\u00f9 leggeri delle macchine virtuali, in quanto vengono eseguiti direttamente sul kernel del sistema. Per eseguire un contenitore con la nostra applicazione, dobbiamo prima creare un'immagine in cui confezioniamo tutto il necessario per il funzionamento della nostra applicazione. In sostanza, l'immagine \u00e8 un'istantanea del file system. Ad esempio, consideriamo il 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>Il Dockerfile \u00e8 un insieme di istruzioni; eseguendo ciascuna di esse, Docker salver\u00e0 le modifiche nel file system e le sovrapporr\u00e0 a quelle precedenti. Ogni comando crea il proprio strato. L'immagine finale \u00e8 l'insieme degli strati uniti.<\/p>\n<p><\/p>\n<p>Cosa \u00e8 importante sapere: ogni strato pu\u00f2 essere memorizzato nella cache da Docker. Se nulla \u00e8 cambiato dall'ultima build, Docker utilizzer\u00e0 lo strato gi\u00e0 pronto invece di eseguire il comando. Poich\u00e9 il principale guadagno in velocit\u00e0 di build deriverebbe dall'uso della cache, nelle misurazioni della velocit\u00e0 di build ci concentreremo sulla costruzione dell'immagine con la cache pronta. Quindi, per passi:<\/p>\n<p><\/p>\n<ol>\n<li>Rimuoviamo le immagini localmente, in modo che le esecuzioni precedenti non influenzino il test.<br \/>\n<code>docker rmi $(docker images -q)<\/code><\/li>\n<li>Eseguiamo la build per la prima volta.<br \/>\n<code>time docker build -t app .<\/code><\/li>\n<li>Modifichiamo il file src\/index.html per simulare il lavoro di uno sviluppatore.<\/li>\n<li>Eseguiamo la build per la seconda volta.<br \/>\n<code>time docker build -t app .<\/code><\/li>\n<\/ol>\n<p><\/p>\n<p>Se l'ambiente per la creazione delle immagini \u00e8 impostato correttamente (di cui parleremo brevemente dopo), Docker avr\u00e0 gi\u00e0 a bordo vari strati di cache quando avviamo la build. Il nostro obiettivo \u00e8 imparare a utilizzare la cache in modo che la build si svolga nel modo pi\u00f9 rapido possibile. Poich\u00e9 presumiamo che l'avvio della build senza cache avvenga solo una volta \u2014 la prima \u2014 possiamo ignorare la lentezza di questa prima esecuzione. \u00c8 il secondo avvio della build che ci interessa nei test, quando le cache sono gi\u00e0 attive e siamo pronti a infornare il nostro dolce. Tuttavia, alcuni suggerimenti influenzeranno anche la prima build.<\/p>\n<p><\/p>\n<p>Posizioniamo il Dockerfile descritto sopra nella cartella del progetto e avviamo la build. Tutti gli elenchi forniti sono abbreviati per facilitare la lettura.<\/p>\n<p><\/p>\n<pre><code class=\"bash\">$ time docker build -t app .\nInvio del contesto di build al demone Docker 409MB\nPasso 1\/5 : FROM node:12.16.2\nStato: Immagine pi\u00f9 recente scaricata per node:12.16.2\nPasso 2\/5 : WORKDIR \/app\nPasso 3\/5 : COPY . .\nPasso 4\/5 : RUN npm ci\naggiunti 1357 pacchetti in 22.47s\nPasso 5\/5 : RUN npm run build --prod\nData: 2020-04-16T19:20:09.664Z - Hash: fffa0fddaa3425c55dd3 - Tempo: 37581ms\nCostruzione avvenuta con successo c8c279335f46\nTagging avvenuto con successo app:latest\n\nreale 5m4.541s\nutente 0m0.000s\nsistema 0m0.000s<\/code><\/pre>\n<p><\/p>\n<p>Modifichiamo il contenuto di src\/index.html e avviamo per la seconda volta.<\/p>\n<p><\/p>\n<pre><code class=\"bash\">$ time docker build -t app .\nInvio del contesto di build al demone Docker 409MB\nPasso 1\/5 : FROM node:12.16.2\nPasso 2\/5 : WORKDIR \/app\n ---&gt; Utilizzo della cache\nPasso 3\/5 : COPY . .\nPasso 4\/5 : RUN npm ci\naggiunti 1357 pacchetti in 22.47s\nPasso 5\/5 : RUN npm run build --prod\nData: 2020-04-16T19:26:26.587Z - Hash: fffa0fddaa3425c55dd3 - Tempo: 37902ms\nCostruzione avvenuta con successo 79f335df92d3\nTagging avvenuto con successo app:latest\n\nreale 3m33.262s\nutente 0m0.000s\nsistema 0m0.000s<\/code><\/pre>\n<p><\/p>\n<p>Per vedere se siamo riusciti a creare l'immagine, eseguiamo il comando <code>docker images<\/code>:<\/p>\n<p><\/p>\n<pre><code class=\"bash\">REPOSITORY   TAG      IMAGE ID       CREATED              SIZE\napp          latest   79f335df92d3   Circa un minuto fa   1.74GB<\/code><\/pre>\n<p><\/p>\n<p>Prima di costruire, Docker prende tutti i file nel contesto corrente e li invia al suo demone <code>Invio del contesto di build al demone Docker 409MB<\/code>. Il contesto per la build viene specificato come ultimo argomento del comando build. Nel nostro caso, si tratta della directory corrente - \u00ab.\u00bb, - e Docker porta tutto ci\u00f2 che abbiamo in questa cartella. 409 MB sono molti: pensiamo a come risolvere questo problema.<\/p>\n<p><\/p>\n<h2 id=\"umenshaem-kontekst\">Riduciamo il contesto<\/h2>\n<p><\/p>\n<p>Per ridurre il contesto, ci sono due opzioni. O mettiamo tutti i file necessari per la costruzione in una cartella separata e indichiamo a Docker di utilizzare proprio quella cartella come contesto. Questo potrebbe non essere sempre comodo, quindi c'\u00e8 la possibilit\u00e0 di specificare delle eccezioni: cosa non deve essere portato nel contesto. Per farlo, mettiamo nel progetto un file .dockerignore e indichiamo cosa non serve per la build:<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">.git\n\/node_modules<\/code><\/pre>\n<p><\/p>\n<p>e avviamo nuovamente la costruzione:<\/p>\n<p><\/p>\n<pre><code class=\"bash\">$ time docker build -t app .\nInvio del contesto di build al demone Docker 607.2kB\nStep 1\/5 : FROM node:12.16.2\nStep 2\/5 : WORKDIR \/app\n ---&gt; Utilizzando la cache\nStep 3\/5 : COPY . .\nStep 4\/5 : RUN npm ci\naggiunti 1357 pacchetti in 22.47s\nStep 5\/5 : RUN npm run build --prod\nData: 2020-04-16T19:33:54.338Z - Hash: fffa0fddaa3425c55dd3 - Tempo: 37313ms\nCostruito con successo 4942f010792a\nContrassegnato con successo app:latest\n\nreale 1m47.763s\nutente 0m0.000s\nsys 0m0.000s<\/code><\/pre>\n<p><\/p>\n<p>607.2 Kbyte - molto meglio rispetto a 409 MB. Inoltre, abbiamo ridotto la dimensione dell'immagine da 1.74 a 1.38GB:<\/p>\n<p><\/p>\n<pre><code class=\"bash\">REPOSITORY   TAG      IMAGE ID       CREATED         SIZE\napp          latest   4942f010792a   3 minuti fa   1.38GB<\/code><\/pre>\n<p><\/p>\n<p>Proviamo a ridurre ulteriormente la dimensione dell'immagine.<\/p>\n<p><\/p>\n<h2 id=\"ispolzuem-alpine\">Utilizziamo Alpine<\/h2>\n<p><\/p>\n<p>Un altro modo per risparmiare sulla dimensione dell'immagine \u00e8 utilizzare una piccola immagine madre. L'immagine madre \u00e8 l'immagine sulla quale viene costruita la nostra immagine. Lo strato inferiore \u00e8 specificato nel comando <code>DA<\/code> nel Dockerfile. Nel nostro caso, utilizziamo un'immagine basata su Ubuntu, gi\u00e0 dotata di nodejs. E pesa ...<\/p>\n<p><\/p>\n<pre><code class=\"bash\">$ docker images -a | grep node\nnode 12.16.2 406aa3abbc6c 17 minuti fa 916MB<\/code><\/pre>\n<p><\/p>\n<p>... quasi un gigabyte. Possiamo ridurre notevolmente il volume utilizzando un'immagine basata su Alpine Linux. Alpine \u00e8 un sistema operativo Linux molto leggero. L'immagine Docker per nodejs basata su alpine pesa solo 88.5 MB. Quindi, sostituiamo la nostra immagine grossa con:<\/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++\nWORKDIR \/app\nCOPY . .\nRUN npm ci\nRUN npm run build --prod<\/code><\/pre>\n<p><\/p>\n<p>Abbiamo dovuto installare alcune cose necessarie per costruire l'applicazione. S\u00ec, Angular non si costruisce senza Python \u00af(\u00b0_o)\\\/\u00af<\/p>\n<p><\/p>\n<p>Ma la dimensione dell'immagine \u00e8 scesa di 150 MB:<\/p>\n<p><\/p>\n<pre><code class=\"bash\">REPOSITORY   TAG      IMAGE ID       CREATED          SIZE\napp          latest   aa031edc315a   22 minuti fa   761MB<\/code><\/pre>\n<p><\/p>\n<p>Andiamo oltre.<\/p>\n<p><\/p>\n<h2 id=\"multisteydzh-sborka\">Build multi-stage<\/h2>\n<p><\/p>\n<p>Non tutto ci\u00f2 che c'\u00e8 nell'immagine ci serve in produzione.<\/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>Utilizzando <code>docker run app ls -lah<\/code> abbiamo avviato un container basato sulla nostra immagine <code>app<\/code> e abbiamo eseguito al suo interno il comando <code>ls -lah<\/code>, dopo di che il container ha terminato il suo lavoro.<\/p>\n<p><\/p>\n<p>In produzione abbiamo bisogno solo della cartella <code>dist<\/code>. Dobbiamo comunque trasferire i file all'esterno. Possiamo avviare un server HTTP su nodejs. Ma faremo qualcosa di pi\u00f9 semplice. Indovinate la parola russa che ha quattro lettere \u00ab\u044b\u00bb. Giusto! \u042b\u043d\u0436\u044b\u043d\u044b\u043a\u0441\u044b. Prendiamo l'immagine con nginx, ci mettiamo dentro la cartella <code>dist<\/code> e una piccola configurazione:<\/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>Tutto questo ci aiuter\u00e0 a fare un multi-stage build. Modifichiamo il nostro 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>Ora abbiamo due istruzioni <code>DA<\/code> nel Dockerfile, ognuna delle quali avvia il proprio stadio di costruzione. Il primo lo abbiamo chiamato <code>builder<\/code>, mentre a partire dall'ultimo FROM verr\u00e0 preparata la nostra immagine finale. L'ultimo passo \u00e8 copiare l'artefatto della nostra build nella fase precedente nell'immagine finale con nginx. La dimensione dell'immagine \u00e8 diminuita significativamente:<\/p>\n<p><\/p>\n<pre><code class=\"bash\">REPOSITORY   TAG      IMAGE ID       CREATED          SIZE\napp          latest   2c6c5da07802   29 minuti fa   36MB<\/code><\/pre>\n<p><\/p>\n<p>Facciamo partire il container con la nostra immagine e assicuriamoci che tutto funzioni:<\/p>\n<p><\/p>\n<pre><code class=\"bash\">docker run -p8080:80 app<\/code><\/pre>\n<p><\/p>\n<p>Con l'opzione -p8080:80 abbiamo mappato la porta 8080 sulla nostra macchina host alla porta 80 all'interno del container, dove gira nginx. Apriamo nel browser <noindex><a rel=\"nofollow\" href=\"http:\/\/localhost:8080\/\">http:\/\/localhost:8080\/<\/a><\/noindex> e vediamo la nostra applicazione. Funziona tutto!<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Alcuni consigli su come velocizzare la costruzione delle immagini Docker. Ad esempio, fino a 30 secondi\" src=\"\/wp-content\/uploads\/2020\/05\/ab37d9576a84954f4e4860dd49a75f3d.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Ridurre la dimensione dell'immagine da 1.74 GB a 36 MB abbrevia significativamente il tempo di consegna della tua applicazione in produzione. Ma torniamo al tempo di costruzione.<\/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\">Cambiando l'ordine dei layer<\/h2>\n<p><\/p>\n<p>I primi tre passaggi sono stati memorizzati nella cache (suggerimento <code>Using cache<\/code>). Nel quarto passaggio vengono copiati tutti i file del progetto e nel quinto passaggio vengono installate le dipendenze <code>RUN npm ci<\/code> \u2014 un totale di 47.338 secondi. Perch\u00e9 ricominciare ogni volta a installare le dipendenze, se cambiano molto raramente? Vediamo perch\u00e9 non sono state memorizzate nella cache. Il fatto \u00e8 che Docker controlla strato per strato se il comando e i file ad esso correlati sono cambiati. Nel quarto passaggio copiamo tutti i file del nostro progetto e tra di essi ci sono naturalmente delle modifiche, quindi Docker non solo non prende dalla cache questo strato, ma nemmeno tutti i successivi! Apportiamo alcune piccole modifiche al 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>Prima si copiano package.json e package-lock.json, poi si installano le dipendenze e solo dopo si copia l'intero progetto. Come risultato:<\/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 secondi anzich\u00e9 3 minuti \u2014 decisamente meglio! \u00c8 importante il giusto ordine degli strati: prima copiamo quello che non cambia, poi quello che cambia raramente e infine quello che cambia spesso.<\/p>\n<p><\/p>\n<p>Passiamo ora a dire qualcosa sulla creazione di immagini nei sistemi CI\/CD.<\/p>\n<p><\/p>\n<h2 id=\"ispolzovanie-predyduschih-obrazov-dlya-kesha\">Utilizzo di immagini precedenti per la cache<\/h2>\n<p><\/p>\n<p>Se utilizziamo per la costruzione una soluzione SaaS, allora la cache locale di Docker potrebbe essere pulita e fresca. Per consentire a Docker di recuperare gli strati costruiti, fornitegli l'immagine precedentemente creata.<\/p>\n<p><\/p>\n<p>Prendiamo ad esempio la costruzione della nostra applicazione in GitHub Actions. Utilizziamo questa configurazione<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">on:\n  push:\n    branches:\n      - master\n\nname: Test docker build\n\njobs:\n  deploy:\n    name: Build\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: Login to 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: Build\n      run: |\n        docker build \n          -t $IMAGE_NAME:$IMAGE_TAG \n          -t $IMAGE_NAME:latest \n          .\n\n    - name: Push image to GitHub Packages\n      run: |\n        docker push $IMAGE_NAME:latest\n        docker push $IMAGE_NAME:$IMAGE_TAG\n\n    - name: Logout\n      run: |\n        docker logout docker.pkg.github.com<\/code><\/pre>\n<p><\/p>\n<p>L'immagine viene costruita e caricata in GitHub Packages in due minuti e 20 secondi:<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Alcuni consigli su come velocizzare la costruzione delle immagini Docker. Ad esempio, fino a 30 secondi\" src=\"\/wp-content\/uploads\/2020\/05\/76b81216922f7ef2c4e777b60238acd5.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Ora modifichiamo la build per utilizzare la cache basata sulle immagini precedentemente costruite:<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">on:\n  push:\n    branches:\n      - master\n\nname: Test docker build\n\njobs:\n  deploy:\n    name: Build\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: Login to 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: Pull latest images\n      run: |\n        docker pull $IMAGE_NAME:latest || true\n        docker pull $IMAGE_NAME-builder-stage:latest || true\n\n    - name: Images list\n      run: |\n        docker images\n\n    - name: Build\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: Push image to 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: Logout\n      run: |\n        docker logout docker.pkg.github.com<\/code><\/pre>\n<p><\/p>\n<p>Per iniziare, \u00e8 necessario spiegare perch\u00e9 vengono eseguite due comandi. <code>build<\/code>La questione \u00e8 che in una build multi-stadio, l'immagine risultante sar\u00e0 un insieme di livelli dell'ultimo stadio. In questo modo, i livelli degli stadi precedenti non verranno inclusi nell'immagine. Pertanto, utilizzando l'immagine finale proveniente da una build precedente, Docker non sar\u00e0 in grado di trovare i livelli gi\u00e0 pronti per costruire l'immagine con nodejs (stadio builder). Per risolvere questo problema, viene creato un'immagine intermedia. <code>$IMAGE_NAME-builder-stage<\/code> e viene caricata in GitHub Packages, affinch\u00e9 possa essere utilizzata in una build successiva come sorgente della cache.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Alcuni consigli su come velocizzare la costruzione delle immagini Docker. Ad esempio, fino a 30 secondi\" src=\"\/wp-content\/uploads\/2020\/05\/acaa70ae528589f4be2258650d8eb5de.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Il tempo totale di build \u00e8 stato ridotto a un minuto e mezzo. Mezzo minuto viene speso per recuperare le immagini precedenti.<\/p>\n<p><\/p>\n<h2 id=\"predvaritelnoe-sozdanie-obrazov\">Creazione preventiva delle immagini<\/h2>\n<p><\/p>\n<p>Un altro modo per risolvere il problema della cache pulita di Docker \u00e8 spostare parte degli strati in un altro Dockerfile, compilarlo separatamente, caricarlo nel Container Registry e usarlo come genitore.<\/p>\n<p><\/p>\n<p>Creiamo la nostra immagine Node.js per la compilazione dell'applicazione Angular. Creiamo nel progetto 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>Costruiamo e carichiamo un'immagine pubblica su 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>Ora nel nostro Dockerfile principale utilizziamo l'immagine pronta:<\/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>Nel nostro esempio, il tempo di costruzione non \u00e8 diminuito, ma le immagini create in precedenza possono essere utili se hai molti progetti e in ognuno di essi devi installare le stesse dipendenze.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Alcuni consigli su come velocizzare la costruzione delle immagini Docker. Ad esempio, fino a 30 secondi\" src=\"\/wp-content\/uploads\/2020\/05\/5b4e4bd1d4b96a3f07305d2dd0f6d680.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Abbiamo esaminato diversi metodi per accelerare la costruzione delle immagini Docker. Se desideri che il deploy avvenga rapidamente, prova a applicare nel tuo progetto:<\/p>\n<p><\/p>\n<ul>\n<li>riduzione del contesto;<\/li>\n<li>utilizzo di piccole immagini genitorial;<\/li>\n<li>build multi-stadio;<\/li>\n<li>modifica dell'ordine delle istruzioni nel Dockerfile per utilizzare efficacemente la cache;<\/li>\n<li>configurazione della cache nei sistemi CI\/CD;<\/li>\n<li>creazione preventiva delle immagini.<\/li>\n<\/ul>\n<p><\/p>\n<p>Spero che con questo esempio diventi pi\u00f9 chiaro come funziona Docker e che tu possa ottimizzare il tuo deploy. Per provare gli esempi dell'articolo, \u00e8 stato creato un repository <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/devopsprodigy\/test-docker-build\">https:\/\/github.com\/devopsprodigy\/test-docker-build<\/a><\/noindex>.<\/p>\n<p>Fonte: <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.1.1 - 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\/it\/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.1.1\" \/>\n\t\t<meta property=\"og:locale\" content=\"it_IT\" \/>\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\/it\/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\udd47Alcuni suggerimenti su come accelerare la costruzione delle immagini Docker. Ad esempio, fino a 30 secondi | ProHoster","description":"Prima che la funzionalit\u00e0 arrivi in produzione, al giorno d'oggi, con orchestratori complessi e CI\/CD, deve percorrere un lungo cammino dal commit ai test e alla consegna.","canonical_url":"https:\/\/prohoster.info\/it\/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":"it_IT","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\/it\/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\/it\/wp-json\/wp\/v2\/posts\/81600","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/comments?post=81600"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/posts\/81600\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/media\/81601"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/media?parent=81600"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/categories?post=81600"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/tags?post=81600"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}