Presumo che tu abbia un po' di familiarità con Docker e conosca nozioni di base come l'esecuzione di contenitori docker ecc.
In articoli precedenti abbiamo discusso dell'aggiornamento del contenitore Docker e della scrittura di file Docker.
Che cos'è esattamente la modifica di un'immagine della finestra mobile?
Un'immagine contenitore è costruita in livelli (o è una raccolta di livelli), ogni istruzione Dockerfile crea un livello dell'immagine. Ad esempio, considera il seguente Dockerfile:
FROM alpine:latest
RUN apk add --no-cache python3
ENTRYPOINT ["python3", "-c", "print('Hello World')"]
Poiché ci sono un totale di tre comandi Dockerfile, l'immagine creata da questo Dockerfile conterrà un totale di tre livelli.
Puoi confermarlo costruendo l'immagine:
docker image built -t dummy:0.1 .
E poi usando il comando docker image history
sull'immagine creata.
articles/Modify a Docker Image on modify-docker-images [?] took 12s
❯ docker image history dummy:0.1
IMAGE CREATED CREATED BY SIZE COMMENT
b997f897c2db 10 seconds ago /bin/sh -c #(nop) ENTRYPOINT ["python3" "-c… 0B
ee217b9fe4f7 10 seconds ago /bin/sh -c apk add --no-cache python3 43.6MB
28f6e2705743 35 hours ago /bin/sh -c #(nop) CMD ["/bin/sh"] 0B
<missing> 35 hours ago /bin/sh -c #(nop) ADD file:80bf8bd014071345b… 5.61MB
Ignora l'ultimo livello "
Ciascuno di questi livelli è di sola lettura. Ciò è vantaggioso perché poiché questi livelli sono di sola lettura, nessun processo associato a un'istanza in esecuzione di questa immagine sarà in grado di modificare il contenuto di questa immagine, pertanto questi livelli possono essere condivisi da molti contenitori senza dover mantenere un copia per ogni istanza. Ma affinché i processi dei contenitori siano in grado di eseguire r/w, un altro livello viene aggiunto sopra i livelli RO esistenti durante la creazione dei contenitori, questo è scrivibile e non condiviso da altri contenitori.
Lo svantaggio di questo livello r/w è che le modifiche apportate a questo livello non sono persistenti, sebbene sia possibile utilizzare i volumi per rendere persistenti alcuni dati, a volte potrebbe essere necessario/volere aggiungere un livello prima di un livello esistente o eliminare un livello da un immagine o semplicemente sostituire un livello. Questi sono i motivi per cui si potrebbe voler modificare una docker
esistente immagine.
In questo articolo tratterò tutti i casi che ho menzionato sopra, utilizzando metodi diversi.
Metodi per modificare un'immagine della finestra mobile
Esistono due modi per modificare un'immagine della finestra mobile.
- Tramite Dockerfiles.
- Utilizzando il comando
docker container commit
.
Spiegherò entrambi i metodi e, alla fine, aggiungerò anche quale caso d'uso sarebbe migliore per il metodo nel contesto.
Metodo 1:modifica dell'immagine della finestra mobile tramite Dockerfile
Modificare un'immagine mobile significa essenzialmente modificare i livelli di un'immagine. Ora, poiché ogni comando Dockerfile rappresenta un livello dell'immagine, la modifica di ogni riga di un Dockerfile cambierà anche la rispettiva immagine.
Quindi, se dovessi aggiungere un livello all'immagine, puoi semplicemente aggiungere un'altra istruzione Dockerfile, per rimuoverne uno rimuoveresti una linea e per cambiare un livello, cambieresti la linea di conseguenza.
Esistono due modi per utilizzare un Dockerfile per modificare un'immagine.
- Utilizzare l'immagine che desideri modificare come immagine di base e creare un'immagine figlio.
- Modifica del Dockerfile effettivo dell'immagine che desideri modificare.
Lascia che ti spieghi quale metodo dovrebbe essere usato quando e come.
1. Utilizzo di un'immagine come immagine di base
Questo è quando prendi l'immagine che desideri modificare e aggiungi livelli ad essa per creare una nuova immagine figlio. A meno che un'immagine non sia creata da zero, ogni immagine è una modifica alla stessa immagine di base principale.
Considera il precedente Dockerfile. Supponiamo che la build dell'immagine da quell'immagine sia denominata dummy:0.1
. Ora, se dovessi pensare che ora ho bisogno di usare Perl invece di Python3 per stampare "Hello World", ma non voglio nemmeno rimuovere Python3, potrei semplicemente usare dummy:0.1
image come immagine di base (poiché Python3 è già presente) e costruisci da quella come segue
FROM dummy:0.1
RUN apk add --no-cache perl
ENTRYPOINT ["perl", "-e", "print \"Hello World\n\""]
Qui sto costruendo sopra dummy:0.1
, aggiungendo più livelli come ritengo opportuno.
Questo metodo non sarà molto utile se la tua intenzione è quella di modificare o eliminare un livello esistente. Per questo, devi seguire il metodo successivo.
2. Modifica del Dockerfile dell'immagine
Poiché i livelli esistenti di un'immagine sono di sola lettura, non è possibile modificarli direttamente tramite un nuovo Dockerfile. Con il FROM
comando in un Dockerfile, prendi un'immagine come base e costruisci su su o aggiungi livelli ad esso.
Alcune attività potrebbero richiederci di modificare un livello esistente, anche se puoi farlo usando il metodo precedente con un mucchio di contraddittori RUN
istruzioni (come eliminare file, rimuovere/sostituire i pacchetti aggiunti in qualche livello precedente), non è una soluzione ideale o quella che consiglierei. Perché aggiunge livelli aggiuntivi e aumenta notevolmente le dimensioni dell'immagine.
Un metodo migliore sarebbe non utilizzare l'immagine come immagine di base, ma modificare l'effettivo Dockerfile di quell'immagine. Considera ancora il precedente Dockerfile, e se non dovessi mantenere Python3 in quell'immagine e sostituire il pacchetto Python3 e il comando con quelli Perl?
Se seguendo il metodo precedente avrei dovuto creare un nuovo Dockerfile in questo modo -
FROM dummy:0.1
RUN apk del python3 && apk add --no-cache perl
ENTRYPOINT ["perl", "-e", "print \"Hello World\n\""]
Se creato, ci saranno un totale di cinque livelli in questa immagine.
articles/Modify a Docker Image on modify-docker-images [?] took 3s
❯ docker image history dummy:0.2
IMAGE CREATED CREATED BY SIZE COMMENT
2792036ddc91 10 seconds ago /bin/sh -c #(nop) ENTRYPOINT ["perl" "-e" "… 0B
b1b2ec1cf869 11 seconds ago /bin/sh -c apk del python3 && apk add --no-c… 34.6MB
ecb8694b5294 3 hours ago /bin/sh -c #(nop) ENTRYPOINT ["python3" "-c… 0B
8017025d71f9 3 hours ago /bin/sh -c apk add --no-cache python3 && … 43.6MB
28f6e2705743 38 hours ago /bin/sh -c #(nop) CMD ["/bin/sh"] 0B
<missing> 38 hours ago /bin/sh -c #(nop) ADD file:80bf8bd014071345b… 5.61MB
Inoltre, la dimensione dell'immagine è 83,8 MB.
articles/Modify a Docker Image on modify-docker-images [?]
❯ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
dummy 0.2 2792036ddc91 19 seconds ago 83.8MB
Ora invece di farlo, prendi il Dockerfile iniziale e cambia quelli di Python3 in Perl in questo modo
FROM alpine:latest
RUN apk add --no-cache perl
ENTRYPOINT ["perl", "-e", "print \"Hello World\n\""]
Il numero di livelli è stato ridotto a 3 e la dimensione ora è 40,2 MB.
articles/Modify a Docker Image on modify-docker-images [?] took 3s
❯ docker image history dummy:0.3
IMAGE CREATED CREATED BY SIZE COMMENT
f35cd94c92bd 9 seconds ago /bin/sh -c #(nop) ENTRYPOINT ["perl" "-e" "… 0B
053a6a6ba221 9 seconds ago /bin/sh -c apk add --no-cache perl 34.6MB
28f6e2705743 38 hours ago /bin/sh -c #(nop) CMD ["/bin/sh"] 0B
<missing> 38 hours ago /bin/sh -c #(nop) ADD file:80bf8bd014071345b… 5.61MB
articles/Modify a Docker Image on modify-docker-images [?]
❯ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
dummy 0.3 f35cd94c92bd 29 seconds ago 40.2MB
Immagine modificata correttamente.
Il metodo precedente è più utile quando vuoi semplicemente aggiungere livelli sopra quelli esistenti, ma non è molto utile quando provi a modificare i livelli esistenti come eliminarne uno, sostituirne uno, riordinare quelli esistenti e presto. È qui che brilla questo metodo.
Metodo 2:modifica dell'immagine tramite docker commit
C'è un altro metodo in cui puoi scattare un'istantanea di un container in esecuzione e trasformarlo in un'immagine a sé stante.
Costruiamo un dummy:0.1
immagine identica, ma questa volta senza utilizzare un Dockerfile. Dato che ho usato alpine:latest
come dummy:0.1
's base, fai girare un contenitore di quell'immagine.
docker run --rm --name alpine -ti alpine ash
Ora all'interno del contenitore, aggiungi il pacchetto Python3, apk add --no-cache python3
. Una volta terminato, apri una nuova finestra di terminale ed esegui il seguente comando (o qualcosa di simile)
docker container commit --change='ENTRYPOINT ["python3", "-c", "print(\"Hello World\")"]' alpine dummy:0.4
Con il --change
flag Sto aggiungendo un'istruzione Dockerfile al nuovo dummy:04
immagine (in questo caso, il ENTRYPOINT
istruzioni).
Con il docker container commit
comando, fondamentalmente converti il livello r/w più esterno in un livello r/o, lo aggiungi ai livelli dell'immagine esistente e crei una nuova immagine. Questo metodo è più intuitivo/interattivo, quindi potresti voler usarlo al posto di Dockerfiles, ma capisci che non è molto riproducibile. Inoltre, le stesse regole si applicano alla rimozione o alla modifica di qualsiasi livello esistente, aggiungere un livello solo per rimuovere qualcosa o modificare qualcosa fatto in un livello precedente non è l'idea migliore, almeno nella maggior parte dei casi.
Questo conclude questo articolo. Spero che questo ti sia stato utile, se hai qualche domanda, commenta qui sotto.