Cara meng-upgrade kontainer buruh pelabuhan setelah gambarnya berubah

518

Katakanlah saya telah menarik gambar resmi mysql: 5.6.21 .

Saya telah menggunakan gambar ini dengan membuat beberapa wadah buruh pelabuhan.

Kontainer ini telah berjalan selama beberapa waktu hingga MySQL 5.6.22 dirilis. Gambar resmi mysql: 5.6 akan diperbarui dengan rilis baru, tetapi wadah saya masih berjalan 5.6.21.

Bagaimana cara menyebarkan perubahan pada gambar (yaitu meningkatkan distro MySQL) ke semua kontainer saya yang ada? Apa cara Docker yang tepat untuk melakukan ini?

Yaroslav Stavnichiy
sumber

Jawaban:

579

Setelah mengevaluasi jawaban dan mempelajari topik yang ingin saya rangkum.

Cara Docker untuk memutakhirkan kontainer tampaknya sebagai berikut:

Wadah aplikasi tidak boleh menyimpan data aplikasi . Dengan cara ini Anda dapat mengganti wadah aplikasi dengan versi yang lebih baru kapan saja dengan menjalankan sesuatu seperti ini:

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

Anda dapat menyimpan data di host (dalam direktori yang dipasang sebagai volume) atau dalam wadah khusus data saja . Baca lebih lanjut tentang itu

Meng-upgrade aplikasi (mis. Dengan peningkatan yum / apt-get) dalam wadah dianggap sebagai anti-pola . Wadah aplikasi seharusnya tidak berubah , yang akan menjamin perilaku yang dapat direproduksi. Beberapa gambar aplikasi resmi (khususnya mysql: 5.6) bahkan tidak dirancang untuk memperbarui sendiri (pemutakhiran apt-get tidak akan berfungsi).

Saya ingin mengucapkan terima kasih kepada semua orang yang memberikan jawaban mereka, sehingga kami dapat melihat semua pendekatan yang berbeda.

Yaroslav Stavnichiy
sumber
31
Bagaimana jika migrasi data diperlukan? Server baru tidak dapat me-mount data karena dalam format lama, perlu mengetahui migrasi yang terjadi dan mengubah representasi data.
Dor Rotman
12
Saya pikir, perancang gambar harus menjelaskan hal itu dan mengizinkan peluncuran perintah khusus (mis., Migrasi data) selama menjalankan pertama kontainer.
Yaroslav Stavnichiy
4
@static_rtti Bagaimana docker rename my-mysql-container trash-containersebelum membuat yang baru?
Franklin Yu
4
Apakah akan ada perintah all-in-one untuk memperbarui wadah tanpa harus menghentikannya secara manual, menghapusnya, dan membuatnya lagi (berdasarkan gambar baru yang telah ditarik)?
Michaël Perrin
83

Saya tidak suka memasang volume sebagai tautan ke direktori host, jadi saya membuat pola untuk memutakhirkan wadah buruh pelabuhan dengan wadah yang sepenuhnya dikelola buruh pelabuhan. Membuat wadah buruh pelabuhan baru dengan --volumes-from <container>akan memberikan wadah baru dengan gambar yang diperbarui milik bersama volume yang dikelola buruh pelabuhan.

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

Dengan tidak segera menghapus yang asli my_mysql_container, Anda memiliki kemampuan untuk kembali ke wadah yang dikenal jika wadah yang ditingkatkan tidak memiliki data yang tepat, atau gagal dalam tes kewarasan.

Pada titik ini, saya biasanya akan menjalankan skrip cadangan apa pun yang saya miliki untuk wadah untuk memberi saya jaring pengaman jika terjadi kesalahan

docker stop my_mysql_container
docker start my_mysql_container_tmp

Sekarang Anda memiliki kesempatan untuk memastikan data yang Anda harapkan ada di wadah baru dan menjalankan pemeriksaan kewarasan.

docker rm my_mysql_container
docker rename my_mysql_container_tmp my_mysql_container

Volume buruh pelabuhan akan bertahan selama wadah apa pun menggunakannya, sehingga Anda dapat menghapus wadah asli dengan aman. Setelah wadah asli dihapus, wadah baru dapat mengasumsikan senama dari aslinya untuk membuat semuanya seindah itu dimulai.

Ada dua keuntungan utama menggunakan pola ini untuk meningkatkan wadah buruh pelabuhan. Pertama, ini menghilangkan kebutuhan untuk me-mount volume ke direktori host dengan memungkinkan volume untuk langsung ditransfer ke kontainer yang ditingkatkan. Kedua, Anda tidak pernah dalam posisi di mana tidak ada wadah buruh pelabuhan yang berfungsi; jadi jika pemutakhiran gagal, Anda dapat dengan mudah kembali ke cara kerjanya sebelumnya dengan memutar wadah buruh pelabuhan yang asli lagi.

kaiSmith
sumber
3
Mengapa Anda tidak suka memasang volume host di dalam wadah Docker? (Saya melakukan hal itu jadi saya tertarik pada argumen yang menentang melakukan hal itu: -) Saya telah memasang mis: ./postgres-data/:/var/lib/postgres/data- yaitu memasang dir host ./postgres-data/, di dalam wadah PostgreSQL saya.)
KajMagnus
4
@ KajMagnus Saya banyak menggunakan gerombolan buruh pelabuhan, dan saya suka menulis wadah untuk bekerja dengan baik di gerombolan. Ketika saya memutar sebuah wadah di gerombolan, saya tidak tahu simpul mana gerombolan wadah akan hidup, jadi saya tidak bisa mengandalkan jalur host yang berisi data yang saya inginkan. Karena volume Docker 1.9 (saya pikir) dapat dibagikan di seluruh host yang membuat peningkatan dan migrasi kontainer menjadi mudah menggunakan metode yang saya jelaskan. Alternatifnya adalah memastikan beberapa volume jaringan dipasang pada semua node berkerumun, tapi itu terdengar seperti rasa sakit yang sangat besar untuk dipertahankan.
kMaiSmith
Terima kasih! Oke, memasang volume host sepertinya adalah sesuatu yang juga ingin saya hindari, sekarang. Setidaknya beberapa saat kemudian jika aplikasi saya menjadi populer dan perlu
ditingkatkan
32

Hanya untuk memberikan jawaban yang lebih umum (bukan spesifik mysql) ...

  1. Pendeknya

Sinkronisasi dengan registri gambar layanan ( https://docs.docker.com/compose/compose-file/#image ):

docker-compose pull 

Menciptakan wadah jika file atau gambar pembuat galangan telah berubah:

docker-compose up -d
  1. Latar Belakang

Pengelolaan gambar wadah adalah salah satu alasan untuk menggunakan komposisi buruh pelabuhan (lihat https://docs.docker.com/compose/reference/up/ )

Jika ada wadah yang ada untuk suatu layanan, dan konfigurasi atau gambar layanan diubah setelah pembuatan wadah, pembuat komposisi buruh pelabuhan mengambil perubahan dengan menghentikan dan menciptakan kembali wadah (menjaga volume yang terpasang). Agar Compose tidak menerima perubahan, gunakan flag --no-createate.

Aspek manajemen data juga dicakup oleh komposisi buruh pelabuhan melalui "volume" eksternal yang terpasang (Lihat https://docs.docker.com/compose/compose-file/#volumes ) atau wadah data.

Hal ini membuat potensi kompatibilitas mundur dan masalah migrasi data tidak tersentuh, tetapi ini adalah masalah "aplikatif", bukan spesifik Docker, yang harus diperiksa dengan catatan rilis dan pengujian ...

Ronan Fauglas
sumber
Bagaimana Anda melakukannya dengan versi? contoh gambar baru adalah foo / image: 2 dan docker-compose.yml memiliki gambar: foo / image: 1?
dman
TERIMA KASIH. Jawaban Terbaik!
Mick
Meskipun ini pasti cara yang harus ditempuh, orang harus menyadari bahwa setiap perubahan yang dibuat dalam wadah masih akan hilang begitu wadah dibuat kembali. Jadi menjaga perubahan kontainer hanya dalam volume yang terpasang masih diperlukan.
Petr Bodnár
23

Saya ingin menambahkan bahwa jika Anda ingin melakukan proses ini secara otomatis (unduh, hentikan, dan mulai ulang wadah baru dengan pengaturan yang sama seperti yang dijelaskan oleh @Yaroslav) Anda dapat menggunakan WatchTower. Sebuah program yang secara otomatis memperbarui wadah Anda ketika mereka diubah https://github.com/v2tec/watchtower

Ricardo Polo Jaramillo
sumber
20

Pertimbangkan untuk jawaban ini:

  • Nama basis data adalah app_schema
  • Nama wadahnya adalah app_db
  • Kata sandi root adalah root123

Cara memperbarui MySQL saat menyimpan data aplikasi di dalam wadah

Ini dianggap praktik yang buruk , karena jika Anda kehilangan wadah, Anda akan kehilangan datanya. Meskipun ini adalah praktik yang buruk, berikut adalah cara yang mungkin untuk melakukannya:

1) Lakukan dump database sebagai SQL:

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

2) Perbarui gambar:

docker pull mysql:5.6

3) Perbarui wadah:

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

4) Kembalikan dump database:

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

Cara memperbarui wadah MySQL menggunakan volume eksternal

Menggunakan volume eksternal adalah cara yang lebih baik untuk mengelola data, dan membuatnya lebih mudah untuk memperbarui MySQL. Kehilangan wadah tidak akan kehilangan data apa pun. Anda dapat menggunakan docker-compose untuk memfasilitasi mengelola aplikasi Docker multi-kontainer dalam satu host:

1) Buat docker-compose.ymlfile untuk mengelola aplikasi Anda:

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) Perbarui MySQL (dari folder yang sama dengan docker-compose.ymlfile):

docker-compose pull
docker-compose up -d

Catatan: perintah terakhir di atas akan memperbarui gambar MySQL, membuat ulang dan memulai wadah dengan gambar baru.

Alexandre V.
sumber
Katakanlah saya memiliki basis data yang sangat besar (beberapa GB), apakah data saya tidak dapat diakses hingga seluruh basis data diimpor? Itu bisa menjadi "downtime" besar
hellimac
Karena Anda menyebutkan docker-compose, akankah ini berhasil? stackoverflow.com/a/31485685/65313
sivabudh
1
volumes_fromkunci sekarang ditinggalkan (bahkan dihapus dalam versi 3 file penulisan) mendukung volumeskunci baru .
Franklin Yu
docker pull image_uri:tag && docker restart container_running_that_imagebekerja untukku. Tidak perlu docker-compose pull && docker-compose up -d.
Yuriy Pozniak
16

Jawaban yang mirip dengan di atas

docker images | awk '{print $1}' | grep -v 'none' | grep -iv 'repo' | xargs -n1 docker pull
Eddie Jaoude
sumber
1
Cemerlang! Cukup terkejut karena tidak mendapatkan lebih banyak suara. Sekarang satu-satunya hal yang hilang adalah memicu restart semua kontainer yang diperbarui.
sorin
7
Sayangnya ini tidak akan memperbarui wadah yang ada. Ini hanya akan memperbarui gambar yang ditarik, tetapi wadah yang ada tidak berubah dan masih menggunakan gambar asli yang digunakan untuk membuatnya. Ini hanya berfungsi jika Anda membuat wadah baru dari gambar, tetapi wadah yang ada masih didasarkan pada gambar asli.
Eric B.
Luar biasa. Jika Anda perlu menarik versi tertentu dari wadah, lakukan seperti ini: buruh pelabuhan gambar | awk '{print $ 1 ":" $ 2}' | grep -v 'tidak ada' | grep -iv 'repo' | xargs -n1 docker pull
rogervila
11

Inilah yang terlihat seperti menggunakan docker-composesaat membangun kebiasaan Dockerfile.

  1. Bangun Dockerfile khusus Anda terlebih dahulu, tambahkan nomor versi berikutnya untuk dibedakan. Mis: docker build -t imagename:version . Ini akan menyimpan versi baru Anda secara lokal.
  2. Lari docker-compose down
  3. Edit docker-compose.ymlfile Anda untuk mencerminkan nama gambar baru yang Anda atur pada langkah 1.
  4. Lari docker-compose up -d. Ini akan mencari gambar secara lokal dan menggunakan yang ditingkatkan.

-EDIT-

Langkah-langkah saya di atas lebih verbal daripada yang seharusnya. Saya telah mengoptimalkan alur kerja saya dengan memasukkan build: .parameter ke file komposisi buruh pelabuhan saya. Langkah-langkahnya terlihat sekarang:

  1. Verifikasi bahwa Dockerfile saya seperti apa yang saya inginkan.
  2. Tetapkan nomor versi nama gambar saya di file komposisi docker saya.
  3. Jika gambar saya belum dibangun: jalankan docker-compose build
  4. Lari docker-compose up -d

Saya tidak menyadarinya saat itu, tetapi komposisi buruh pelabuhan cukup pintar untuk hanya memperbarui wadah saya ke gambar baru dengan satu perintah, daripada harus menurunkannya terlebih dahulu.

gdbj
sumber
Dalam situasi nyata Anda tidak dapat menggunakan tangan Anda sendiri dan melakukan perubahan itu. Solusi Anda tidak mendukung cara otomatis untuk menyelesaikan masalah.
Carlos Vázquez Losada
7
jadi Anda mengatakan itu karena solusi saya tidak otomatis, itu tidak valid? Apakah itu persyaratan dari OP? Dan apakah jawaban lain menyiratkan otomatisasi? Sangat bingung. Dan, saya pikir downvotes merugikan orang lain yang datang ke sini. Jawaban saya 100% valid untuk pertanyaan yang diajukan.
gdbj
Terima kasih atas jawaban ini, saya juga tidak menyadari bahwa Anda bisa berlari docker-compose up -dtanpa harus menghentikan semuanya terlebih dahulu.
Radicand
4

Jika Anda tidak ingin menggunakan Docker Compose, saya dapat merekomendasikan portainer . Ini memiliki fungsi buat ulang yang memungkinkan Anda membuat ulang wadah sambil menarik gambar terbaru.

beruik
sumber
2

Anda harus membangun kembali semua gambar dan memulai kembali semua wadah, atau entah bagaimana memperbarui perangkat lunak dan memulai kembali database. Tidak ada jalur peningkatan tetapi Anda mendesain sendiri.

seanmcl
sumber
Apa yang sebenarnya Anda maksud dengan memulai kembali wadah? Ada docker restartperintah, tapi saya tidak yakin itu akan mengambil perubahan gambar. Dan apa yang terjadi pada data saya di dalam wadah?
Yaroslav Stavnichiy
1
Maaf, maksud saya bukan docker restart. Maksudku buruh pelabuhan r-CONTANER; buruh pelabuhan menjalankan NEW_IMAGE. Data dalam wadah sql Anda akan hilang. Itu sebabnya orang umumnya menggunakan volume untuk menyimpan data.
seanmcl
Jika Anda memiliki semua data Anda terpasang dalam volume dalam wadah yang terpisah atau mesin host nas @seanmcl mengatakan hanya membuat wadah baru dengan mysql baru terhubung ke data yang sama. Jika Anda tidak melakukan itu (Anda harus) tetapi Anda dapat menggunakan perintah exec buruh pelabuhan yang tersedia di buruh pelabuhan 1.3 untuk memperbarui mysql dan restart di dalam wadah.
Usman Ismail
2

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

Anda dapat memperbarui semua gambar Anda yang ada menggunakan pipa perintah berikut:

docker images | awk '/^REPOSITORY|\<none\>/ {next} {print $1}' | xargs -n 1 docker pull
gvlx
sumber
6
Ini akan memperbarui gambar, tetapi bukan wadahnya. Wadah tidak dapat diubah dan gambar dasarnya tidak dapat diubah tanpa membuat wadah baru dari gambar yang diperbarui.
Eric B.
2

Pastikan Anda menggunakan volume untuk semua data persisten (konfigurasi, log, atau data aplikasi) yang Anda simpan di wadah terkait dengan keadaan proses di dalam wadah itu. Perbarui Dockerfile Anda dan bangun kembali gambar dengan perubahan yang Anda inginkan, dan mulai kembali wadah dengan volume Anda terpasang di tempat yang sesuai.

Daniel Dinnyes
sumber
1

Ini adalah sesuatu yang juga saya perjuangkan untuk gambar saya sendiri. Saya memiliki lingkungan server tempat saya membuat gambar Docker. Ketika saya memperbarui server, saya ingin semua pengguna yang menjalankan kontainer berdasarkan gambar Docker saya untuk dapat meningkatkan ke server terbaru.

Idealnya, saya lebih suka membuat versi baru dari gambar Docker dan memiliki semua wadah berdasarkan versi sebelumnya dari gambar yang secara otomatis diperbarui ke gambar baru "di tempat." Tetapi mekanisme ini tampaknya tidak ada.

Jadi desain terbaik berikutnya yang dapat saya buat sejauh ini adalah menyediakan cara untuk memiliki pembaruan kontainer itu sendiri - mirip dengan bagaimana aplikasi desktop memeriksa pembaruan dan kemudian meningkatkannya sendiri. Dalam kasus saya, ini mungkin berarti membuat skrip yang melibatkan Git pull dari tag terkenal.

Gambar / wadah tidak benar-benar berubah, tetapi "internal" wadah itu berubah. Anda dapat membayangkan melakukan hal yang sama dengan apt-get, yum, atau apa pun yang sesuai untuk lingkungan Anda. Bersamaan dengan ini, saya akan memperbarui server saya: gambar terbaru dalam registri sehingga setiap wadah baru akan didasarkan pada gambar terbaru.

Saya akan tertarik mendengar apakah ada seni sebelumnya yang membahas skenario ini.

bjlevine
sumber
7
Ini bertentangan dengan konsep infrastruktur abadi dan beberapa manfaatnya. Anda dapat menguji aplikasi / lingkungan Anda untuk melihat apakah itu berfungsi dan tidak dijamin jika Anda memperbarui komponen di dalamnya. Memisahkan kode kontainer dari data dari konfigurasi memungkinkan Anda memperbarui, menguji bahwa kami saat ini bekerja dan menggunakan ke produksi, mengetahui bahwa tidak ada garis kode yang berbeda dari gambar yang diuji ke yang produksi. Bagaimanapun, sistem membiarkan Anda mengelolanya seperti yang Anda katakan juga, itu pilihan Anda.
gmuslera
Gmuslera titik yang sangat bagus. Setuju bahwa itu adalah anti-pola untuk memperbarui 'internal' dari wadah buruh pelabuhan yang ada.
bjlevine
Jadi apa solusi terbaik untuk memperbarui wadah buruh pelabuhan secara otomatis berdasarkan pembaruan gambar buruh pelabuhan untuk memberikan pembaruan ke semua wadah dengan mudah?
tarek salem
1

Memperbarui

Ini terutama untuk meminta wadah tidak memperbarui karena membangun gambar adalah cara yang harus dilakukan

Saya memiliki masalah yang sama sehingga saya membuat docker-run , alat baris perintah yang sangat sederhana yang berjalan di dalam container docker untuk memperbarui paket dalam kontainer yang sedang berjalan lainnya.

Ini menggunakan docker-py untuk berkomunikasi dengan menjalankan wadah buruh pelabuhan dan memperbarui paket atau menjalankan perintah tunggal sewenang-wenang

Contoh:

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

secara default ini akan menjalankan dateperintah di semua wadah yang berjalan dan mengembalikan hasil tetapi Anda dapat mengeluarkan perintah apa pun misalnyadocker-run exec "uname -a"

Untuk memperbarui paket (saat ini hanya menggunakan apt-get):

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

Anda dapat membuat dan alias dan menggunakannya sebagai baris perintah biasa misalnya

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

ITech
sumber
Apakah ini ide yang bagus? (Jika Anda melakukannya apt update; apt upgrade, gambar akan tumbuh.)
ctrl-alt-delor
Gambar @yaroslav adalah solusi yang lebih baik untuk masalah ini. Di atas sebenarnya bukan cara Docker melakukan sesuatu.
Joost van der Laan