Come aggiornare il contenitore della finestra mobile dopo aver modificato la sua immagine


518

Diciamo che ho estratto l' immagine mysql ufficiale : 5.6.21 .

Ho distribuito questa immagine creando diversi contenitori docker.

Questi contenitori sono in esecuzione da un po 'di tempo fino al rilascio di MySQL 5.6.22. L'immagine ufficiale di mysql: 5.6 viene aggiornata con la nuova versione, ma i miei contenitori eseguono ancora 5.6.21.

Come faccio a propagare le modifiche nell'immagine (ad esempio aggiornare la distro MySQL) a tutti i miei contenitori esistenti? Qual è il modo Docker corretto per farlo?

Risposte:


579

Dopo aver valutato le risposte e studiato l'argomento, vorrei riassumere.

Il modo Docker per aggiornare i contenitori sembra essere il seguente:

I contenitori dell'applicazione non devono archiviare i dati dell'applicazione . In questo modo puoi sostituire il contenitore dell'app con la sua versione più recente in qualsiasi momento eseguendo qualcosa del genere:

docker pull mysql
docker stop my-mysql-container
docker rm my-mysql-container
docker run --name=my-mysql-container --restart=always \
  -e MYSQL_ROOT_PASSWORD=mypwd -v /my/data/dir:/var/lib/mysql -d mysql

È possibile archiviare i dati sull'host (nella directory montata come volume) o in contenitori speciali per soli dati . Leggi di più al riguardo

L'aggiornamento delle applicazioni (ad es. Con yum / apt-get upgrade) all'interno dei container è considerato un anti-pattern . I contenitori dell'applicazione devono essere immutabili , il che garantisce un comportamento riproducibile. Alcune immagini ufficiali dell'applicazione (mysql: 5.6 in particolare) non sono nemmeno progettate per l'auto-aggiornamento (l'aggiornamento apt-get non funzionerà).

Vorrei ringraziare tutti coloro che hanno dato le loro risposte, in modo da poter vedere tutti i diversi approcci.


31
Cosa succede se è necessaria la migrazione dei dati? Il nuovo server non può montare i dati perché è in un vecchio formato, deve sapere che sta avvenendo una migrazione e cambiare la rappresentazione dei dati.
Dor Rotman,

12
Penso che i progettisti di immagini dovrebbero tenerne conto e consentire l'avvio di comandi personalizzati (ad es. Migrazione dei dati) durante la prima esecuzione del contenitore.
Yaroslav Stavnichiy,


4
@static_rtti Che ne dici di docker rename my-mysql-container trash-containercreare un nuovo?
Franklin Yu,

4
Ci sarebbe un comando all-in-one per aggiornare il contenitore senza doverlo arrestare manualmente, rimuoverlo e crearlo di nuovo (in base alla nuova immagine che è stata estratta)?
Michaël Perrin,

83

Non mi piace montare i volumi come collegamento a una directory host, quindi ho ideato un modello per l'aggiornamento dei container docker con container gestiti interamente. La creazione di un nuovo contenitore finestra mobile con --volumes-from <container>darà al nuovo contenitore la proprietà condivisa delle immagini aggiornate dei volumi gestiti dalla finestra mobile.

docker pull mysql
docker create --volumes-from my_mysql_container [...] --name my_mysql_container_tmp mysql

Non rimuovendo immediatamente l'originale my_mysql_container, è possibile tornare al contenitore di lavoro noto se il contenitore aggiornato non ha i dati corretti o non supera un test di integrità.

A questo punto, di solito eseguirò qualsiasi script di backup che ho per il container per darmi una rete di sicurezza nel caso qualcosa vada storto

docker stop my_mysql_container
docker start my_mysql_container_tmp

Ora hai l'opportunità di assicurarti che i dati che ti aspetti siano nel nuovo contenitore siano presenti ed eseguire un controllo di integrità.

docker rm my_mysql_container
docker rename my_mysql_container_tmp my_mysql_container

I volumi della finestra mobile rimarranno attivi fino a quando qualsiasi contenitore li sta utilizzando, in modo da poter eliminare il contenitore originale in modo sicuro. Una volta rimosso il contenitore originale, il nuovo contenitore può assumere l'omonimo dell'originale per rendere tutto bello com'era all'inizio.

Esistono due vantaggi principali nell'utilizzo di questo modello per l'aggiornamento dei contenitori della finestra mobile. Innanzitutto, elimina la necessità di montare i volumi nelle directory host consentendo il trasferimento diretto dei volumi in contenitori aggiornati. In secondo luogo, non ci si trova mai in una posizione in cui non esiste un contenitore docker funzionante; quindi se l'aggiornamento non riesce, puoi facilmente tornare a come funzionava prima ruotando di nuovo il contenitore docker originale.


3
Perché non ti piace montare i volumi host all'interno di un contenitore Docker? (Sto facendo esattamente questo, quindi sono interessato agli argomenti contrari a farlo: -) Ho montato ad esempio: ./postgres-data/:/var/lib/postgres/data- cioè montato la ./postgres-data/
directory

4
@KajMagnus Uso molto gli sciami docker e mi piace scrivere i miei contenitori per lavorare bene in uno sciame. Quando giro un container in uno sciame non ho idea di quale nodo sciame vivrà il contenitore, quindi non posso fare affidamento sul percorso host contenente i dati che desidero. Dal momento che Docker 1.9 (penso) i volumi possono essere condivisi tra host, il che rende l'aggiornamento e la migrazione dei container un gioco da ragazzi usando il metodo che ho descritto. Un'alternativa sarebbe quella di assicurarsi che un volume di rete sia montato su tutti i nodi dello sciame, ma suona come un grande dolore da mantenere.
kMaiSmith,

Grazie! Ok, montare i volumi host sembra qualcosa che anch'io voglio evitare, ora. Almeno un po 'più tardi se la mia app diventa popolare e deve scalare su più di un server
KajMagnus

32

Solo per fornire una risposta più generale (non specifica per mysql) ...

  1. In breve

Sincronizzazione con il registro delle immagini di servizio ( https://docs.docker.com/compose/compose-file/#image ):

docker-compose pull 

Ricrea contenitore se il file o l'immagine di composizione docker sono stati modificati:

docker-compose up -d
  1. sfondo

La gestione delle immagini dei container è uno dei motivi per l'utilizzo di docker-compose (consultare https://docs.docker.com/compose/reference/up/ )

Se esistono contenitori esistenti per un servizio e la configurazione o l'immagine del servizio è stata modificata dopo la creazione del contenitore, la finestra mobile componi raccoglie le modifiche arrestando e ricreando i contenitori (preservando i volumi montati). Per impedire a Compose di rilevare le modifiche, utilizzare il flag --no-ricreate.

Anche l'aspetto della gestione dei dati è coperto dalla composizione docker attraverso "volumi" esterni montati (Vedi https://docs.docker.com/compose/compose-file/#volumes ) o contenitore di dati.

Ciò lascia intatti i potenziali problemi di retrocompatibilità e migrazione dei dati, ma si tratta di problemi "applicativi", non specifici di Docker, che devono essere verificati rispetto alle note di rilascio e ai test ...


Come si fa con il versioning? ad esempio la nuova immagine è foo / image: 2 e docker-compose.yml ha image: foo / image: 1?
Dman,

GRAZIE. Migliore risposta!
Mick,

Mentre questo è sicuramente il modo di procedere, si dovrebbe essere consapevoli del fatto che eventuali modifiche apportate al contenitore andranno comunque perse una volta ricreato il contenitore. Pertanto, è ancora necessario mantenere le modifiche ai container all'interno dei volumi montati.
Petr Bodnár

23

Vorrei aggiungere che se si desidera eseguire automaticamente questo processo (download, arresto e riavvio di un nuovo contenitore con le stesse impostazioni descritte da @Yaroslav) è possibile utilizzare WatchTower. Un programma che aggiorna automaticamente i tuoi contenitori quando vengono cambiati https://github.com/v2tec/watchtower


20

Considera per questa risposta:

  • Il nome del database è app_schema
  • Il nome del contenitore è app_db
  • La password di root è root123

Come aggiornare MySQL durante la memorizzazione dei dati dell'applicazione all'interno del contenitore

Questa è considerata una cattiva pratica , perché se perdi il contenitore, perderai i dati. Sebbene sia una cattiva pratica, ecco un modo possibile per farlo:

1) Eseguire un dump del database come SQL:

docker exec app_db sh -c 'exec mysqldump app_schema -uroot -proot123' > database_dump.sql

2) Aggiorna l'immagine:

docker pull mysql:5.6

3) Aggiorna il contenitore:

docker rm -f app_db
docker run --name app_db --restart unless-stopped \
-e MYSQL_ROOT_PASSWORD=root123 \
-d mysql:5.6

4) Ripristina il dump del database:

docker exec app_db sh -c 'exec mysql -uroot -proot123' < database_dump.sql

Come aggiornare il contenitore MySQL usando un volume esterno

L'uso di un volume esterno è un modo migliore di gestire i dati e semplifica l'aggiornamento di MySQL. Perdere il contenitore non perderà alcun dato. È possibile utilizzare docker-compose per facilitare la gestione delle applicazioni Docker multi-container in un singolo host:

1) Crea il docker-compose.ymlfile per gestire le tue applicazioni:

version: '2'
services:
  app_db:
    image: mysql:5.6
    restart: unless-stopped
    volumes_from: app_db_data
  app_db_data:
    volumes: /my/data/dir:/var/lib/mysql

2) Aggiorna MySQL (dalla stessa cartella del docker-compose.ymlfile):

docker-compose pull
docker-compose up -d

Nota: l'ultimo comando sopra aggiornerà l'immagine MySQL, ricrea e avvia il contenitore con la nuova immagine.


Diciamo che ho un enorme database (diversi GB), i miei dati saranno inaccessibili fino a quando l'intero database non viene importato? Potrebbe essere un grande "tempo morto"
hellimac il

Da quando hai menzionato docker-compose, funzionerà? stackoverflow.com/a/31485685/65313
sivabudh

1
volumes_fromla chiave è ora obsoleta (anche rimossa nella versione 3 del file di composizione) a favore della nuova volumeschiave.
Franklin Yu,

docker pull image_uri:tag && docker restart container_running_that_imageha funzionato per me. Non c'è bisogno di docker-compose pull && docker-compose up -d.
Yuriy Pozniak,

16

Risposta simile a sopra

docker images | awk '{print $1}' | grep -v 'none' | grep -iv 'repo' | xargs -n1 docker pull

1
Brillante! Abbastanza sorpreso non ha ottenuto più voti. Ora l'unica cosa mancante sarebbe innescare un riavvio di tutti i contenitori che sono stati aggiornati.
sorin,

7
Purtroppo questo non aggiorna il contenitore esistente. Questo aggiornerà semplicemente l'immagine estratta, ma il contenitore esistente è immutabile e utilizza ancora l'immagine originale utilizzata per crearlo. Funziona solo se si crea un nuovo contenitore dall'immagine, ma qualsiasi contenitore esistente si basa ancora sull'immagine originale.
Eric B.

Sorprendente. Se è necessario estrarre la versione specifica del contenitore, farlo in questo modo: docker images | awk '{print $ 1 ":" $ 2}' | grep -v 'none' | grep -iv 'repo' | xargs -n1 docker pull
rogervila

11

Ecco come appare docker-composequando si costruisce un'abitudine Dockerfile.

  1. Crea prima il tuo Dockerfile personalizzato, aggiungendo un numero di versione successivo per differenziarlo. Ex:docker build -t imagename:version . questo memorizzerà la tua nuova versione localmente.
  2. Correre docker-compose down
  3. Modifica il tuo docker-compose.ymlfile per riflettere il nome della nuova immagine che hai impostato al passaggio 1.
  4. Corri docker-compose up -d. Cercherà localmente l'immagine e utilizzerà quella aggiornata.

-MODIFICARE-

I miei passaggi sopra sono più dettagliati di quanto debbano essere. Ho ottimizzato il mio flusso di lavoro includendo il build: .parametro nel mio file comporre docker. I passaggi ora sembrano:

  1. Verifica che il mio Dockerfile sia quello che voglio che assomigli.
  2. Imposta il numero di versione del mio nome immagine nel mio file comporre docker.
  3. Se la mia immagine non è ancora stata creata: corri docker-compose build
  4. Correre docker-compose up -d

Non me ne rendevo conto in quel momento, ma docker-compose è abbastanza intelligente da aggiornare semplicemente il mio contenitore alla nuova immagine con un solo comando, invece di doverlo prima buttare giù.


In una situazione reale non puoi usare le tue mani e fare quei cambiamenti. La tua soluzione non supporta i modi automatici per risolvere il problema.
Carlos Vázquez Losada,

7
quindi stai dicendo che, poiché la mia soluzione non è automatizzata, non è valida? È un requisito dell'OP? E le altre risposte implicano l'automazione? Davvero confuso. E penso che i downvotes stiano facendo un cattivo servizio agli altri che vengono qui. La mia risposta è valida al 100% per la domanda posta.
gdbj,

grazie per questa risposta, inoltre, non mi rendevo conto che potevi semplicemente correre docker-compose up -dsenza dover prima fermare tutto.
radicand,

4

Se non si desidera utilizzare Docker Compose, posso consigliare Portainer . Ha una funzione di ricrea che ti consente di ricreare un contenitore mentre si estrae l'immagine più recente.


2

È necessario ricostruire tutte le immagini e riavviare tutti i contenitori oppure in qualche modo aggiornare il software e riavviare il database. Non esiste un percorso di aggiornamento, ma che tu stesso abbia progettato.


Cosa intendi esattamente riavviando i contenitori? C'è un docker restartcomando, ma non sono sicuro che rileverà i cambiamenti dell'immagine. E cosa succede ai miei dati all'interno dei container?
Yaroslav Stavnichiy,

1
Spiacenti, non intendevo il riavvio della finestra mobile. Intendo docker rm -f CONTANER; finestra mobile eseguita NEW_IMAGE. I dati nel contenitore sql scompariranno. Questo è il motivo per cui le persone generalmente usano i volumi per archiviare i dati.
sabato

Se hai tutti i tuoi dati montati in volumi in contenitori separati o macchina host, il nas @seanmcl ha detto semplicemente di creare nuovi contenitori con nuovo mysql collegato agli stessi dati. Se non lo hai fatto (dovresti) ma puoi usare il comando docker exec disponibile in docker 1.3 per aggiornare mysql e riavviarlo all'interno del contenitore.
Usman Ismail

2

Prendendo da http://blog.stefanxo.com/2014/08/update-all-docker-images-at-once/

Puoi aggiornare tutte le tue immagini esistenti usando la seguente pipeline di comandi:

docker images | awk '/^REPOSITORY|\<none\>/ {next} {print $1}' | xargs -n 1 docker pull

6
Ciò aggiornerà le immagini, ma non il contenitore. Il contenitore è immutabile e l'immagine di base non può essere modificata senza creare un nuovo contenitore da un'immagine aggiornata.
Eric B.

2

Assicurarsi di utilizzare i volumi per tutti i dati persistenti (configurazione, registri o dati dell'applicazione) archiviati nei contenitori relativi allo stato dei processi all'interno di quel contenitore. Aggiorna il file Docker e ricostruisci l'immagine con le modifiche desiderate e riavvia i contenitori con i volumi montati nella posizione appropriata.


1

Questo è qualcosa con cui ho anche lottato per le mie immagini. Ho un ambiente server dal quale creo un'immagine Docker. Quando aggiorno il server, vorrei che tutti gli utenti che eseguono container basati sulla mia immagine Docker siano in grado di eseguire l'aggiornamento al server più recente.

Idealmente, preferirei generare una nuova versione dell'immagine Docker e avere tutti i contenitori basati su una versione precedente di quell'immagine che si aggiorna automaticamente alla nuova immagine "in atto". Ma questo meccanismo non sembra esistere.

Quindi il prossimo miglior progetto che sono stato in grado di inventare finora è quello di fornire un modo per aggiornare automaticamente il contenitore, in modo simile a come un'applicazione desktop controlla gli aggiornamenti e quindi si aggiorna da sola. Nel mio caso, questo probabilmente significherà creare uno script che coinvolge i pull di Git da un tag ben noto.

L'immagine / contenitore in realtà non cambia, ma cambiano gli "interni" di quel contenitore. Potresti immaginare di fare lo stesso con apt-get, yum o qualunque cosa sia appropriata per il tuo ambiente. Insieme a questo, aggiornerei il myserver: l'ultima immagine nel registro in modo che tutti i nuovi contenitori si basassero sull'immagine più recente.

Sarei interessato a sapere se esiste qualche tecnica nota che affronti questo scenario.


7
Va contro il concetto di infrastruttura immutabile e alcuni dei suoi benefici. Puoi testare la tua applicazione / ambiente per vedere che funziona e non è garantito se aggiorni i componenti all'interno. Dividere il codice contenitore dai dati dalla configurazione ti consente di aggiornare, testare che attualmente stiamo lavorando e distribuire in produzione, sapendo che non esiste una riga di codice diversa dall'immagine testata a quella di produzione. Ad ogni modo, il sistema ti consente di gestirlo come dici anche tu, è una tua scelta.
gmuslera,

Ottimo punto gmuslera. Concordato che si tratta di un anti-pattern per aggiornare gli "interni" di un contenitore docker esistente.
Bjlevine,

Quindi qual è la soluzione migliore per aggiornare automaticamente il contenitore della finestra mobile in base agli aggiornamenti dell'immagine della finestra mobile per fornire gli aggiornamenti a tutti i contenitori senza sforzo?
Tarek Salem

1

Aggiornare

Questo è principalmente quello di interrogare il contenitore per non aggiornarlo poiché la costruzione di immagini è il modo da fare

Ho avuto lo stesso problema, quindi ho creato la finestra mobile , uno strumento da riga di comando molto semplice che viene eseguito all'interno di un contenitore finestra mobile per aggiornare i pacchetti in altri contenitori in esecuzione.

Usa docker-py per comunicare con i contenitori docker in esecuzione e aggiornare i pacchetti o eseguire qualsiasi singolo comando arbitrario

Esempi:

docker run --rm -v /var/run/docker.sock:/tmp/docker.sock itech/docker-run exec

per impostazione predefinita, questo eseguirà il datecomando in tutti i contenitori in esecuzione e restituirà risultati, ma è possibile emettere qualsiasi comando, ad esdocker-run exec "uname -a"

Per aggiornare i pacchetti (attualmente usando solo apt-get):

docker run --rm -v /var/run/docker.sock:/tmp/docker.sock itech/docker-run update

È possibile creare e alias e utilizzarlo come una normale riga di comando, ad es

alias docker-run='docker run --rm -v /var/run/docker.sock:/tmp/docker.sock itech/docker-run'


E 'questa una buona idea? (Se lo fai apt update; apt upgrade, l'immagine crescerà.)
ctrl-alt-delor

L'immagine di @yaroslav è una soluzione migliore a questo problema. Quanto sopra non è proprio il modo Docker di fare le cose.
Joost van der Laan,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.