GNU/Linux >> Linux Esercitazione >  >> Panels >> Docker

Come ridurre le dimensioni dell'immagine Docker:6 metodi di ottimizzazione

Se desideri ridurre le dimensioni dell'immagine della finestra mobile , è necessario utilizzare le best practice standard per la creazione di un'immagine Docker.

Questo blog parla di diverse tecniche di ottimizzazione che puoi implementare rapidamente per creare l'immagine della finestra mobile più piccola e minima . Esamineremo anche alcuni dei migliori strumenti per l'ottimizzazione dell'immagine Docker .

Docker come motore di container rende facile prendere un pezzo di codice ed eseguirlo all'interno di un container. Consente agli ingegneri di raccogliere tutte le dipendenze del codice e i file in un'unica posizione che può essere eseguita ovunque, abbastanza rapidamente e facilmente.

L'intero concetto di immagini "esegui ovunque" parte da un semplice file di configurazione chiamato Dockerfile. Innanzitutto, aggiungiamo tutte le istruzioni di compilazione, come le dipendenze del codice, i comandi e i dettagli dell'immagine di base, in Dockerfile.

Necessità dell'ottimizzazione dell'immagine Docker

Anche se il processo di creazione di Docker è semplice, molte organizzazioni commettono l'errore di creare immagini Docker gonfie senza ottimizzare le immagini del contenitore.

Nello sviluppo software tipico, ogni servizio avrà più versioni/rilasci e ogni versione richiede più dipendenze, comandi e configurazioni. Ciò introduce una sfida nella creazione dell'immagine Docker, come ora:lo stesso codice richiede più tempo e risorse per essere creato prima di poter essere spedito come container.

Ho visto casi in cui l'immagine iniziale dell'applicazione iniziava con 350 MB e nel tempo è cresciuta fino a superare 1,5 GB.

Inoltre, installando librerie indesiderate, aumentiamo la possibilità di un potenziale rischio per la sicurezza aumentando la superficie di attacco.

Pertanto, gli ingegneri DevOps devono ottimizzare le immagini della finestra mobile per garantire che l'immagine della finestra mobile non si gonfi dopo le build dell'applicazione o le versioni future. Non solo per gli ambienti di produzione, in ogni fase del processo CI/CD dovresti ottimizzare le immagini della finestra mobile.

Inoltre, con strumenti di orchestrazione dei container come Kubernetes, è meglio avere immagini di piccole dimensioni per ridurre il trasferimento delle immagini e il tempo di implementazione .

Come ridurre le dimensioni dell'immagine Docker?

Se prendiamo un'immagine contenitore di un'applicazione tipica, questa contiene un'immagine di base, Dipendenze/File/Config , e cruft (software indesiderato).

Quindi tutto si riduce all'efficienza con cui possiamo gestire queste risorse all'interno dell'immagine del contenitore.

Diamo un'occhiata ai diversi metodi consolidati per ottimizzare le immagini Docker. Inoltre, abbiamo fornito esempi pratici per comprendere l'ottimizzazione dell'immagine Docker in tempo reale.

O utilizzi gli esempi forniti nell'articolo o provi le tecniche di ottimizzazione su Dockerfile esistenti.

Di seguito sono riportati i metodi con cui possiamo ottenere l'ottimizzazione dell'immagine Docker.

  1. Utilizzo di immagini di base senza distro/minime
  2. Build multistadio
  3. Ridurre al minimo il numero di livelli
  4. Informazioni sulla memorizzazione nella cache
  5. Utilizzo di Dockerignore
  6. Conservare i dati dell'applicazione altrove

File di esercizi Docker: Tutto il codice dell'applicazione, i Dockerfile e le configurazioni utilizzati in questo articolo sono ospitati in questo repository Github. Puoi clonarlo e seguire il tutorial.

Metodo 1:usa immagini di base minime

Il tuo primo obiettivo dovrebbe essere la scelta dell'immagine di base giusta con un footprint minimo del sistema operativo.

Uno di questi esempi sono le immagini di base alpine. Le immagini Alpine possono essere fino a 5,59 MB . Non è solo piccolo; è anche molto sicuro.

alpine       latest    c059bfaa849c     5.59MB

Nginx alpine l'immagine di base è di soli 22 MB.

Per impostazione predefinita, viene fornito con la shell sh che aiuta a eseguire il debug del contenitore allegandolo.

È possibile ridurre ulteriormente la dimensione dell'immagine di base utilizzando immagini distroless. È una versione ridotta del sistema operativo. Le immagini di base distroless sono disponibili per java, nodejs, python, Rust, ecc.

Le immagini distroless sono così minime da non nemmeno avere una shell al loro interno . Quindi, potresti chiedere, quindi come eseguiamo il debug delle applicazioni? Hanno la versione di debug della stessa immagine fornita con il busybox per il debug.

Inoltre, la maggior parte delle distribuzioni ora ha le sue immagini di base minime.

Nota: Non è possibile utilizzare direttamente le immagini di base disponibili pubblicamente negli ambienti di progetto. È necessario ottenere l'approvazione dal team di sicurezza aziendale per utilizzare l'immagine di base. In alcune organizzazioni, lo stesso team di sicurezza pubblica immagini di base ogni mese dopo il test e la scansione della sicurezza. Tali immagini sarebbero disponibili nel repository privato della finestra mobile dell'organizzazione comune.

Metodo 2:usa le build multistadio Docker

Il modello di costruzione multifase si è evoluto dal concetto di modello builder in cui utilizziamo diversi Dockerfile per creare e impacchettare il codice dell'applicazione. Anche se questo modello aiuta a ridurre le dimensioni dell'immagine, crea un sovraccarico minimo quando si tratta di costruire pipeline.

Nella build multistadio, otteniamo vantaggi simili a quelli del modello builder. Utilizziamo immagini intermedie (fasi di compilazione) per compilare codice, installare dipendenze e file di pacchetto in questo approccio. L'idea alla base è quella di eliminare i livelli indesiderati nell'immagine.

Successivamente, solo i file dell'app necessari per eseguire l'applicazione vengono copiati in un'altra immagine con solo le librerie richieste, ovvero più leggere per eseguire l'applicazione.

Vediamolo in azione, con l'aiuto di un esempio pratico in cui creiamo una semplice applicazione Nodejs e ottimizziamo il suo Dockerfile.

Per prima cosa, creiamo il codice. Avremo la seguente struttura di cartelle.

├── Dockerfile1
├── Dockerfile2
├── env
├── index.js
└── package.json

Salva quanto segue come index.js .

const dotenv=require('dotenv'); 
dotenv.config({ path: './env' });

dotenv.config();

const express=require("express");
const app=express();

app.get('/',(req,res)=>{
  res.send(`Learning to Optimize Docker Images with DevOpsCube!`);
});


app.listen(process.env.PORT,(err)=>{
    if(err){
        console.log(`Error: ${err.message}`);
    }else{
        console.log(`Listening on port ${process.env.PORT}`);
    }
  }
)

Salva quanto segue come package.json .

{
  "name": "nodejs",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "dotenv": "^10.0.0",
    "express": "^4.17.2"
  }
}

Salva la seguente variabile di porta in un file chiamato env .

PORT=8080

Un semplice Dockerfile per questa applicazione vorrebbe questo:salvalo come Dockerfile1 .

FROM node:16
COPY . .
RUN npm installEXPOSE 3000
CMD [ "node", "index.js" ]

Vediamo lo spazio di archiviazione che richiede costruendolo.

docker build -t devopscube/node-app:1.0 --no-cache -f Dockerfile1 .

Dopo che la build è stata completata. Controlliamo le sue dimensioni usando –

docker image ls

Questo è ciò che otteniamo.

devopscube/node-app   1.0       b15397d01cca   22 seconds ago   910MB

Quindi la dimensione è 910MBs .

Ora, utilizziamo questo metodo per creare una build multistadio.

Useremo node:16 come immagine di base, ovvero l'immagine per tutte le installazione di dipendenze e moduli, dopodiché, sposteremo i contenuti in un 'alpine minimale e leggero ' immagine basata. Il 'alpine ' l'immagine ha le utilità minime e quindi è molto leggera.

Ecco una rappresentazione grafica di una build multistadio Docker.

Inoltre, in un unico Dockerfile , puoi avere più fasi con diverse immagini di base. Ad esempio, puoi avere fasi diverse per la creazione, il test, l'analisi statica e il pacchetto con diverse immagini di base.

Vediamo come potrebbe essere il nuovo Dockerfile. Stiamo solo copiando i file necessari dall'immagine di base all'immagine principale.

Salva quanto segue come Dockerfile2 .

FROM node:16 as build

WORKDIR /app
COPY package.json index.js env ./
RUN npm install

FROM node:alpine as main

COPY --from=build /app /
EXPOSE 8080
CMD ["index.js"]

Vediamo lo spazio di archiviazione che richiede costruendolo.

docker build -t devopscube/node-app:2.0 --no-cache -f Dockerfile2 .

Dopo che la build è stata completata. Controlliamo le sue dimensioni utilizzando

docker image ls

Questo è ciò che otteniamo.

devopscube/node-app   2.0       fa6ae75da252   32 seconds ago   171MB

Quindi la nuova dimensione ridotta dell'immagine è di 171 MB rispetto all'immagine con tutte le dipendenze.

Si tratta di un'ottimizzazione di oltre l'80%!

Tuttavia, se avessimo utilizzato la stessa immagine di base che abbiamo utilizzato nella fase di costruzione, non vedremmo molte differenze.

Puoi ridurre ulteriormente le dimensioni dell'immagine utilizzando immagini distroless . Ecco lo stesso Dockerfile con un passaggio di compilazione multifase che utilizza l'immagine distroless di google nodeJS invece di alpine.

FROM node:16 as build

WORKDIR /app
COPY package.json index.js env ./
RUN npm install

FROM gcr.io/distroless/nodejs

COPY --from=build /app /
EXPOSE 3000
CMD ["index.js"]

Se crei il Dockerfile sopra, la tua immagine sarà 118 MB ,

devopscube/distroless-node   1.0       302990bc5e76     118MB

Metodo 3:riduci al minimo il numero di livelli

Le immagini Docker funzionano nel modo seguente:ogni RUN, COPY, FROM Le istruzioni Dockerfile aggiungono un nuovo livello e ogni livello aumenta il tempo di esecuzione della build e aumenta i requisiti di archiviazione dell'immagine.

Vediamolo in azione, con l'aiuto di un esempio pratico:creiamo un'immagine Ubuntu con librerie aggiornate e aggiornate, insieme ad alcuni pacchetti necessari installati come vim, net-tools, dnsutils.

Un Dockerfile per ottenere ciò sarebbe il seguente:salvalo come Dockerfile3 .

FROM ubuntu:latest
ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update -y
RUN apt-get upgrade -y
RUN apt-get install vim -y
RUN apt-get install net-tools -y
RUN apt-get install dnsutils -y

Desideriamo anche esaminare il tempo di costruzione di questa immagine.

Il demone Docker ha una capacità integrata per visualizzare il tempo di esecuzione totale impiegato da un Dockerfile.

Per abilitare questa funzione, procedi come segue –

  1. Crea un daemon.json file con i seguenti contenuti in /etc/docker/
{
  "experimental": true
}

2. Eseguire il comando seguente per abilitare la funzione.

export DOCKER_BUILDKIT=1

Creiamolo e vediamo lo spazio di archiviazione e il tempo di costruzione.

time docker build -t devopscube/optimize:3.0 --no-cache -f Dockerfile3 .

Mostrerebbe i tempi di esecuzione nel terminale.

time docker build -t devopscube/optimize:3.0 --no-cache -f Dockerfile3 .


[+] Building 117.1s (10/10) FINISHED                                                                   
 => [internal] load build definition from Dockerfile                                              
.
.
.
.                                                                       
 => => writing image sha256:9601bcac010062c656dacacbc7c554b8ba552c7174f32fdcbd24ff9c7482a805      0.0s 
 => => naming to docker.io/devopscube/optimize:3.0                                                0.0s 
                                                                                                       
real    1m57.219s                                                                                      
user	0m1.062s
sys	0m0.911s

Una volta completata la compilazione, il tempo di esecuzione arriva a 117,1 secondi .

Controlliamo le sue dimensioni utilizzando

docker image ls

Questo è ciò che otteniamo.

devopscube/optimize  3.0   9601bcac0100   About a minute ago   227MB

Quindi la dimensione è di 227 MB .

Combiniamo i comandi RUN in un unico livello e salviamolo come Dockerfile4.

FROM ubuntu:latest
ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update -y && apt-get upgrade -y && apt-get install --no-install-recommends vim net-tools dnsutils -y

Nel comando RUN sopra, abbiamo usato --no-install-recommends flag per disabilitare i pacchetti consigliati. È consigliato ogni volta che usi install nei tuoi Dockerfiles

Vediamo il tempo di archiviazione e costruzione richiesto per la sua creazione.

time docker build -t devopscube/optimize:4.0 --no-cache -f Dockerfile4 .

Mostrerebbe i tempi di esecuzione nel terminale.

time docker build -t devopscube/optimize:0.4 --no-cache -f Dockerfile4 .


[+] Building 91.7s (6/6) FINISHED                                                                      
 => [internal] load build definition from Dockerfile2                                             0.4s
.
.
.  
 => => naming to docker.io/devopscube/optimize:4.0                                                0.0s 
                                                                                                       
real    1m31.874s                                                                                      
user	0m0.884s
sys	0m0.679s

Al termine della compilazione, il tempo di esecuzione arriva a 91,7 secondi.

Controlliamo le sue dimensioni utilizzando

docker image ls

Questo è ciò che otteniamo.

devopscube/optimize  4.0   37d746b976e3   42 seconds ago      216MB

Quindi la dimensione è di 216 MB.

Utilizzando questa tecnica di ottimizzazione, il tempo di esecuzione è stato ridotto da 117,1 a 91,7 secondi e la dimensione di archiviazione è stata ridotta da 227 MB a 216 MB.

Metodo 4:Capire la memorizzazione nella cache

Spesso, la stessa immagine deve essere ricostruita ancora e ancora con lievi modifiche al codice.

Docker aiuta in questi casi archiviando la cache di ogni livello di una build, sperando che possa essere utile in futuro.

A causa di questo concetto, si consiglia di aggiungere le righe utilizzate per l'installazione di dipendenze e pacchetti in precedenza all'interno del Dockerfile, prima dei comandi COPY.

Il motivo è che la finestra mobile sarebbe in grado di memorizzare nella cache l'immagine con le dipendenze richieste e questa cache può quindi essere utilizzata nelle build seguenti quando il codice viene modificato.

Ad esempio, diamo un'occhiata ai seguenti due Dockerfile.

Dockerfile5

FROM ubuntu:latest
ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update -y
RUN apt-get upgrade -y
RUN apt-get install vim -y
RUN apt-get install net-tools -y
RUN apt-get install dnsutils -y
COPY . .

Dockerfile6

FROM ubuntu:latest
COPY . .
ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update -y
RUN apt-get upgrade -y
RUN apt-get install vim -y
RUN apt-get install net-tools -y
RUN apt-get install dnsutils -y

Docker sarebbe in grado di utilizzare meglio la funzionalità della cache con Dockerfile6 rispetto a Dockerfile5 grazie al miglior posizionamento del comando COPY.

Metodo 5:usa Dockerignore

Di norma, solo i file necessari devono essere copiati sull'immagine della finestra mobile.

Docker può ignorare i file presenti nella directory di lavoro se configurati in .dockerignore file.

Questa funzione dovrebbe essere tenuta presente durante l'ottimizzazione dell'immagine della finestra mobile.

Metodo 6:conserva i dati dell'applicazione altrove

La memorizzazione dei dati dell'applicazione nell'immagine aumenterà inutilmente le dimensioni delle immagini.

Si consiglia vivamente di utilizzare la funzione di volume dei runtime del contenitore per mantenere l'immagine separata dai dati.

Strumenti di ottimizzazione dell'immagine Docker

Di seguito sono riportati alcuni degli strumenti open source che ti aiuteranno a ottimizzare

  1. Immergiti :è uno strumento di esplorazione delle immagini che ti aiuta a scoprire i livelli nelle immagini dei contenitori Docker e OCI. Usando dive, puoi trovare modi per ottimizzare le tue immagini Docker. Dai un'occhiata al repository Dive Github per maggiori dettagli.
  2. Docker Slim: Ti aiuta a ottimizzare le tue immagini Docker per sicurezza e dimensioni. Dai un'occhiata al repository Docker Slim Github per maggiori dettagli.

Continuerò ad aggiungere strumenti a questo elenco.


Docker
  1. Come spostare le immagini Docker tra host

  2. Come utilizzare un Dockerfile per creare un'immagine Docker

  3. Come eseguire il commit delle modifiche a un'immagine Docker

  4. Come creare un'immagine Docker da un contenitore e un file Docker

  5. Come aggiornare/aggiungere un file nell'immagine Docker

Come creare un'immagine Docker da un contenitore in esecuzione

Come ridurre le dimensioni dell'immagine Docker nei contenitori Docker

Come aggiornare le immagini Docker all'ultima versione

Come utilizzare Docker Commit per modificare le immagini del contenitore

Come creare un'immagine Docker personalizzata con Dockerfile

Come elencare / cercare / estrarre le immagini della finestra mobile su Linux