2015-06-25 2 views
5

Uso la finestra mobile sia nello sviluppo che nella produzione e una cosa che mi infastidisce è la semplicità della cache della docker. Ho un'applicazione ruby ​​che richiede bundle install per installare le dipendenze, quindi inizio con il seguente file Docker: ADD Gemfile Gemfile ADD Gemfile.lock Gemfile.lock RUN bundle install --path /root/bundle Tutte le dipendenze sono memorizzate nella cache e funzionano perfettamente finché non aggiungo una nuova gemma. Anche se la gem che ho aggiunto è di soli 0,5 MB, occorrono ancora 10-15 minuti per installare da zero tutte le gemme dell'applicazione. E poi altri 10 minuti per la distribuzione a causa della dimensione della cartella delle dipendenze (circa 300 MB).Docker bundle installa problemi di cache durante l'aggiornamento delle gemme

Ho riscontrato esattamente lo stesso problema con node_modules e npm. Mi stavo chiedendo, qualcuno ha trovato una soluzione per questo problema?

I miei risultati della ricerca finora:

  • Source to image - cache file arbitrari attraverso incrementale costruisce. Sfortunatamente, a causa del suo funzionamento, è necessario spingere l'intero 300MB in un registro anche quando le gemme non vengono cambiate. Build più veloce -> implementazione più lenta anche quando le gemme non vengono aggiornate.

  • Gemfile.tip - dividere Gemfile in due file diversi e aggiungere solo gemme a uno di essi. Soluzione molto specifica per il bundler e non sono convinto che verrà scalata oltre l'aggiunta di 1-2 gemme.

  • Harpoon - sarebbe una buona misura se non il fatto che costringono l'ammaraggio di Dockerfile e passino al loro formato. Il che significa maggiore sofferenza per tutti i nuovi sviluppatori in una squadra poiché questo set di strumenti richiede tempo per imparare separatamente dalla finestra mobile.

  • Memorizza temporaneamente la cache. Questa è solo un'idea che non ero sicuro sia possibile. In qualche modo portare la cache del gestore pacchetti (non la cartella delle dipendenze) alla macchina prima di installare i pacchetti e quindi rimuoverla. Basato sul mio hack, velocizza in modo significativo l'installazione del pacchetto per bundler e npm senza sovraccaricare la macchina con file cache inutili.

+0

Dovrebbe essere possibile copiare la directory gem dall'immagine costruita in un file tar. Quindi puoi aggiungere un layer appena prima del tuo Gemfile Gemfile ADD che ripristina la directory gem nell'immagine. A quel punto, solo le modifiche dovrebbero essere ricostruite. Sto sperimentando con quella tecnica ora. Se riesco a farlo funzionare, invierò una risposta. –

+0

@ScottJacobsen ha avuto fortuna finora? – jQwierdy

+0

@jQwierdy - ha pubblicato la mia soluzione. –

risposta

2

Memorizzo le gem in un file tar nella directory tmp dell'applicazione.Quindi copio le gemme in un livello usando il comando ADD prima di installare il pacchetto. Dal mio Dockerfile.yml:

WORKDIR /home/app 

# restore the gem cache. This only runs when 
# gemcache.tar.bz2 changes, so usually it takes 
# no time 
ADD tmp/gemcache.tar.bz2 /var/lib/gems/ 

COPY Gemfile /home/app/Gemfile 
COPY Gemfile.lock /home/app/Gemfile.lock 
RUN gem update --system && \ 
gem update bundler && \ 
bundle install --jobs 4 --retry 5 

Assicurarsi che si sta inviando la cache gioiello alla vostra macchina finestra mobile. La mia gemcache è 118 MB, ma dal momento che sto costruendo localmente copia velocemente. La mia .dockerignore:

tmp 
!tmp/gemcache.tar.bz2 

è necessario memorizzare nella cache le gemme da un'immagine costruita, ma inizialmente non si può avere un'immagine. Creare una cache vuota in questo modo (ho questo in un task rake):

task :clear_cache do 
    sh "tar -jcf tmp/gemcache.tar.bz2 -T /dev/null" 
end 

Dopo che l'immagine è costruita copiare le gemme per la cache gemma. La mia immagine è taggata app. Creo un contenitore di finestra mobile dall'immagine, copia /var/lib/gems/2.2.0 nel mio gemcache utilizzando il comando docker cp, quindi elimina il contenitore. Ecco il mio compito rake:

task :cache_gems do 
    id = `docker create app`.strip 
    begin 
    sh "docker cp #{id}:/var/lib/gems/2.2.0/ - | bzip2 > tmp/gemcache.tar.bz2" 
    ensure 
    sh "docker rm -v #{id}" 
    end 
end 

Sull'immagine successiva costruire il gemcache viene copiato a un livello prima che il bundle install si chiama. Questo richiede un po 'di tempo, ma è più veloce di un bundle install da zero.

Le configurazioni successive sono ancora più veloci perché la finestra mobile ha memorizzato nella cache il livello ADD tmp/gemcache.tar.bz2 /var/lib/gems/. Se vengono apportate modifiche a Gemfile.lock, vengono apportate solo tali modifiche.

Non c'è alcun motivo per ricostruire la cache della gemma su ciascuna modifica di Gemfile.lock. Una volta che ci sono abbastanza differenze tra la cache e lo Gemfile.lock che un bundle install è lento, è possibile ricostruire la cache della gemma. Quando voglio ricostruire la cache della gemma, è un semplice comando rake cache_gems.

+0

Soluzione interessante. Anche se la mia preoccupazione sarebbe stata la fase manuale di eseguire le gemme della cache in un momento indefinito. – mfilimonov

+0

Potrebbe fare qualcosa di simile nel file docker "bundle check || (bundle install && rake cache_gems)" avrebbe il comportamento previsto? – jQwierdy

+0

Lo farebbe solo quando il pacchetto è stato modificato, verrà installato e ogni volta che verrà installato memorizzerà nella cache le gemme :-) – jQwierdy

3

ho trovato due possibili soluzioni che utilizzano volume di dati esterni per l'archiviazione gemma: one e two.

In breve,

  • si specifica un'immagine che viene utilizzata per memorizzare solo
  • gemme nei tuoi app immagini, in docker-compose.yml si specifica il punto di montaggio per BUNDLE_PATH via volumes_from.
  • all'avvio del contenitore dell'app, esegue bundle check || bundle install e le cose vanno bene.

Questa è una soluzione possibile, tuttavia a me sembra che vada leggermente contro il modo docker. In particolare, bundle install mi sembra dovrebbe essere parte del processo di generazione e non dovrebbe essere parte del runtime. Altre cose, che dipendono dallo bundle install come asset:precompile sono ora anche un'attività di runtime.

Questa è una soluzione affidabile, ma non vedo l'ora di qualcosa di un po 'più robusto.