Bagaimana menangani penyimpanan persisten (mis. Database) di Docker


993

Bagaimana orang berurusan dengan penyimpanan persisten untuk wadah Docker Anda?

Saat ini saya menggunakan pendekatan ini: membangun gambar, misalnya untuk PostgreSQL, dan kemudian mulai wadah dengan

docker run --volumes-from c0dbc34fd631 -d app_name/postgres

IMHO, yang memiliki kelemahan, bahwa saya tidak boleh (secara tidak sengaja) menghapus wadah "c0dbc34fd631".

Gagasan lain adalah memasang volume host "-v" ke dalam wadah, namun, userid di dalam wadah tidak selalu cocok dengan userid dari host, dan kemudian izin mungkin akan kacau.

Catatan: Alih-alih --volumes-from 'cryptic_id'Anda juga dapat menggunakan di --volumes-from my-data-containermana my-data-containernama yang Anda tetapkan untuk wadah hanya data, mis. docker run --name my-data-container ...(Lihat jawaban yang diterima)


Maaf, saya salah mengartikannya, saya bermaksud mengatakan: semua contoh masa depan saya dari gambar itu tergantung pada wadah itu. Jika saya menghapus wadah itu secara tidak sengaja, saya dalam masalah.
juwalter

@AntonStrogonoff - yep, kesalahan penyusunan kata - maksud saya mengatakan: Saya harus memastikan bahwa saya tidak akan pernah menghapus wadah lama (mungkin) itu, karena kemudian referensi penyimpanan "persisten" juga akan hilang
juwalter

seharusnya begitu --name. Anda punya-name
Shammel Lee

Jawaban:


986

Docker 1.9.0 dan lebih tinggi

Gunakan API volume

docker volume create --name hello
docker run -d -v hello:/container/path/for/volume container_image my_command

Ini berarti bahwa pola wadah hanya-data harus ditinggalkan demi volume baru.

Sebenarnya volume API hanyalah cara yang lebih baik untuk mencapai apa yang menjadi pola data-container.

Jika Anda membuat wadah dengan -v volume_name:/container/fs/pathDocker secara otomatis akan membuat volume bernama untuk Anda yang dapat:

  1. Daftarkan diri Anda melalui docker volume ls
  2. Diidentifikasi melalui docker volume inspect volume_name
  3. Dicadangkan sebagai direktori normal
  4. Dicadangkan seperti sebelumnya melalui --volumes-fromkoneksi

API volume baru menambahkan perintah yang berguna yang memungkinkan Anda mengidentifikasi volume yang menggantung:

docker volume ls -f dangling=true

Dan kemudian hapus melalui namanya:

docker volume rm <volume name>

Sebagai @mpugach menggarisbawahi dalam komentar, Anda dapat menyingkirkan semua volume yang menggantung dengan one-liner yang bagus:

docker volume rm $(docker volume ls -f dangling=true -q)
# Or using 1.13.x
docker volume prune

Docker 1.8.x dan di bawah

Pendekatan yang tampaknya bekerja paling baik untuk produksi adalah dengan menggunakan wadah data saja .

Wadah data saja dijalankan pada gambar barebones dan sebenarnya tidak melakukan apa-apa selain mengekspos volume data.

Kemudian Anda bisa menjalankan wadah lain untuk memiliki akses ke volume wadah data:

docker run --volumes-from data-container some-other-container command-to-execute
  • Di sini Anda bisa mendapatkan gambaran yang baik tentang bagaimana mengatur wadah yang berbeda.
  • Di sini ada wawasan yang bagus tentang cara kerja volume.

Dalam posting blog ini ada deskripsi yang baik tentang wadah yang disebut sebagai pola volume yang menjelaskan titik utama memiliki data wadah saja .

Dokumentasi Docker sekarang memiliki deskripsi DEFINITIF dari wadah sebagai pola volume .

Berikut ini adalah prosedur pencadangan / pemulihan untuk Docker 1.8.x dan di bawah ini.

CADANGAN:

sudo docker run --rm --volumes-from DATA -v $(pwd):/backup busybox tar cvf /backup/backup.tar /data
  • --rm: lepaskan wadah saat keluar
  • --volumes-from DATA: lampirkan volume yang dibagikan oleh wadah DATA
  • -v $ (pwd): / backup: bind mount direktori saat ini ke dalam wadah; untuk menulis file tar
  • busybox: gambar kecil yang lebih sederhana - bagus untuk perawatan cepat
  • tar cvf /backup/backup.tar / data: membuat file tar terkompresi dari semua file di direktori / data

MENGEMBALIKAN:

# Create a new data container
$ sudo docker run -v /data -name DATA2 busybox true
# untar the backup files into the new container᾿s data volume
$ sudo docker run --rm --volumes-from DATA2 -v $(pwd):/backup busybox tar xvf /backup/backup.tar
data/
data/sven.txt
# Compare to the original container
$ sudo docker run --rm --volumes-from DATA -v `pwd`:/backup busybox ls /data
sven.txt

Berikut ini adalah artikel bagus dari Brian Goff yang luar biasa yang menjelaskan mengapa sebaiknya menggunakan gambar yang sama untuk wadah dan wadah data.


8
Ini adalah alat yang berbeda untuk kebutuhan yang berbeda. --volumes-frommemungkinkan Anda berbagi ruang disk --linkmemungkinkan Anda berbagi layanan.
tommasop

3
Ada proyek lain dalam karya yang secara khusus dimaksudkan untuk hal semacam ini, mungkin menambahkannya ke jawaban ini sebagai referensi untuk menonton? github.com/ClusterHQ/flocker
Andre

9
Wadah data tidak memiliki arti apa pun dan merupakan ide yang sangat buruk! Kontainer hanya berarti sesuatu ketika suatu proses sedang berjalan di dalamnya, selain itu hanya sepotong sistem file host. Anda bisa memasang volume dengan -v itu satu-satunya dan pilihan terbaik. Anda memiliki kontrol atas sistem file dan disk fisik yang Anda gunakan.
Boynux

11
Yap, pada Docker 1.9, membuat Volume Bernama dengan Volumes API ( docker volume create --name mydata) lebih disukai daripada Kontainer Volume Data. Orang-orang di Docker sendiri menyarankan bahwa Wadah Volume Data " tidak lagi dianggap sebagai pola yang disarankan ," " volume yang dinamai harus dapat menggantikan volume hanya data di sebagian besar (jika tidak semua) kasus ," dan " tidak ada alasan saya bisa melihat untuk menggunakan wadah khusus data . "
Quinn Comendant

8
@ coding, saya sedih Anda sedih, sebagian karena Anda menilai jawaban dengan penundaan 3 tahun dan sebagian karena jawabannya secara substansial benar dalam semua riwayatnya. Jika Anda memiliki saran, jangan ragu untuk berkomentar sehingga saya dapat mengintegrasikan jawabannya dan membantu orang tidak sedih
tommasop

75

Dalam Docker release v1.0 , mengikat mount file atau direktori pada mesin host dapat dilakukan dengan perintah yang diberikan:

$ docker run -v /host:/container ...

Volume di atas dapat digunakan sebagai penyimpanan persisten pada host yang menjalankan Docker.


3
Ini harus menjadi jawaban yang disarankan karena jauh lebih kompleks daripada pendekatan volume-kontainer yang memiliki lebih banyak suara saat ini
insitusec

2
Saya berharap ada flag untuk menentukan host-uid: container-uid dan host-gid: container-gid mapping saat menggunakan perintah mount volume ini.
rampion

35

Pada Docker Compose 1.6, sekarang ada peningkatan dukungan untuk volume data di Docker Compose. File penulisan berikut akan membuat gambar data yang akan bertahan di antara restart (atau bahkan menghapus) wadah induk:

Berikut adalah pengumuman blog: Compose 1.6: New Compose file untuk mendefinisikan jaringan dan volume

Berikut ini contoh file penulisan:

version: "2"

services:
  db:
    restart: on-failure:10
    image: postgres:9.4
    volumes:
      - "db-data:/var/lib/postgresql/data"
  web:
    restart: on-failure:10
    build: .
    command: gunicorn mypythonapp.wsgi:application -b :8000 --reload
    volumes:
      - .:/code
    ports:
      - "8000:8000"
    links:
      - db

volumes:
  db-data:

Sejauh yang saya mengerti: Ini akan membuat wadah volume data (db_data ) yang akan bertahan di antara restart.

Jika Anda menjalankan: docker volume lsAnda akan melihat volume Anda terdaftar:

local               mypthonapp_db-data
...

Anda bisa mendapatkan detail lebih lanjut tentang volume data:

docker volume inspect mypthonapp_db-data
[
  {
    "Name": "mypthonapp_db-data",
    "Driver": "local",
    "Mountpoint": "/mnt/sda1/var/lib/docker/volumes/mypthonapp_db-data/_data"
  }
]

Beberapa pengujian:

# Start the containers
docker-compose up -d

# .. input some data into the database
docker-compose run --rm web python manage.py migrate
docker-compose run --rm web python manage.py createsuperuser
...

# Stop and remove the containers:
docker-compose stop
docker-compose rm -f

# Start it back up again
docker-compose up -d

# Verify the data is still there
...
(it is)

# Stop and remove with the -v (volumes) tag:

docker-compose stop
docker=compose rm -f -v

# Up again ..
docker-compose up -d

# Check the data is still there:
...
(it is).

Catatan:

  • Anda juga dapat menentukan berbagai driver di volumesblok. Misalnya, Anda bisa menentukan driver Flocker untuk db_data:

    volumes:
      db-data:
        driver: flocker
    
  • Ketika mereka meningkatkan integrasi antara Docker Swarm dan Docker Compose (dan mungkin mulai mengintegrasikan Flocker ke dalam sistem ekosistem Docker (saya mendengar desas-desus bahwa Docker telah membeli Flocker), saya pikir pendekatan ini harus menjadi semakin kuat.

Penafian: Pendekatan ini menjanjikan, dan saya menggunakannya dengan sukses di lingkungan pengembangan. Saya akan khawatir untuk menggunakan ini dalam produksi dulu!


Flocker telah ditutup dan tidak ada banyak aktivitas di repo github
Krishna

17

Dalam hal tidak jelas dari pembaruan 5 dari jawaban yang dipilih, pada Docker 1.9, Anda dapat membuat volume yang dapat ada tanpa dikaitkan dengan wadah tertentu, sehingga membuat pola "wadah hanya-data" usang.

Lihat Wadah khusus data yang usang dengan docker 1.9.0? # 17.798 .

Saya pikir pemilik Docker menyadari bahwa pola wadah data-satunya adalah sedikit bau desain dan memutuskan untuk membuat volume sebagai entitas terpisah yang dapat ada tanpa wadah terkait.


13

Meskipun ini masih merupakan bagian dari Docker yang memerlukan beberapa pekerjaan , Anda harus meletakkan volume di Dockerfile dengan instruksi VOLUME sehingga Anda tidak perlu menyalin volume dari wadah lain.

Itu akan membuat wadah Anda kurang saling bergantung dan Anda tidak perlu khawatir tentang penghapusan satu wadah yang memengaruhi wadah lainnya.


Argumen sisi lain adalah bahwa wadah "hanya data" akhirnya menjadi rujukan terakhir untuk volume data (Docker menghancurkan volume data setelah wadah terakhir yang merujuk pada volume yang dihapus dengan docker rm)
WineSoaked

2
Panduan resmi dari Docker ini menyarankan sebaliknya: docs.docker.com/userguide/dockervolumes/… "Volume data dirancang untuk mempertahankan data, terlepas dari siklus hidup wadah. Oleh karena itu Docker tidak pernah secara otomatis menghapus volume ketika Anda melepaskan wadah, juga tidak akan Volume "pengumpulan sampah" yang tidak lagi dirujuk oleh sebuah wadah. "
Alex

12

Saat menggunakan Docker Compose , cukup lampirkan volume bernama, misalnya:

version: '2'
services:
  db:
    image: mysql:5.6
    volumes:
      - db_data:/var/lib/mysql:rw
    environment:
      MYSQL_ROOT_PASSWORD: root
volumes:
  db_data:

9

@tommasop jawaban baik, dan menjelaskan beberapa mekanisme menggunakan wadah data saja. Tetapi sebagai seseorang yang awalnya berpikir bahwa kontainer data konyol ketika seseorang hanya dapat mengikat volume ke host (seperti yang disarankan oleh beberapa jawaban lain), tetapi sekarang menyadari bahwa sebenarnya hanya wadah data yang cukup rapi, saya dapat menyarankan saya sendiri posting blog tentang topik ini: Mengapa Wadah Data Docker (Volume!) Bagus

Lihat juga: jawaban saya untuk pertanyaan " Apa cara (terbaik) untuk mengelola izin untuk volume bersama Docker? " Untuk contoh tentang bagaimana menggunakan wadah data untuk menghindari masalah seperti izin dan pemetaan uid / gid dengan tuan rumah.

Untuk mengatasi salah satu masalah awal OP: wadah data tidak boleh dihapus. Bahkan jika kontainer data dihapus, data itu sendiri tidak akan hilang selama setiap kontainer memiliki referensi ke volume itu yaitu setiap kontainer yang memasang volume melalui --volumes-from. Jadi kecuali semua kontainer terkait dihentikan dan dihapus (orang bisa menganggap ini setara dengan kecelakaan rm -fr /) datanya aman. Anda selalu dapat membuat ulang wadah data dengan melakukan--volumes-from wadah apa pun yang memiliki referensi ke volume itu.

Seperti biasa, buat cadangan!

PEMBARUAN: Docker sekarang memiliki volume yang dapat dikelola secara terpisah dari wadah, yang selanjutnya membuatnya lebih mudah untuk dikelola.


9

Ada beberapa tingkat mengelola data persisten, tergantung pada kebutuhan Anda:

  • Simpan di host Anda
    • Gunakan bendera -v host-path:container-pathuntuk bertahan data direktori kontainer ke direktori host.
    • Pencadangan / pemulihan terjadi dengan menjalankan wadah pencadangan / pengembalian (seperti tutumcloud / dockup) yang dipasang pada direktori yang sama.
  • Buat wadah data dan pasang volumenya ke wadah aplikasi Anda
    • Buat wadah yang mengekspor volume data, gunakan --volumes-from untuk memasang data itu ke wadah aplikasi Anda.
    • Cadangkan / kembalikan sama dengan solusi di atas.
  • Gunakan plugin volume Docker yang mendukung layanan eksternal / pihak ketiga
    • Plugin volume Docker memungkinkan sumber data Anda berasal dari mana saja - NFS, AWS (S3, EFS, dan EBS)
    • Bergantung pada plugin / layanan, Anda dapat melampirkan wadah tunggal atau ganda ke volume tunggal.
    • Bergantung pada layanan, cadangan / pengembalian mungkin otomatis untuk Anda.
    • Meskipun hal ini bisa rumit untuk dilakukan secara manual, beberapa solusi orkestrasi - seperti Rancher - membuatnya dipanggang dan mudah digunakan.
    • Konvoi adalah solusi termudah untuk melakukan ini secara manual.

8

Jika Anda ingin memindahkan volume Anda, Anda juga harus melihat Flocker .

Dari README:

Flocker adalah pengelola volume data dan alat manajemen multi-host Docker. Dengannya Anda dapat mengontrol data Anda menggunakan alat yang sama yang Anda gunakan untuk aplikasi stateless Anda dengan memanfaatkan kekuatan ZFS di Linux.

Ini berarti Anda dapat menjalankan basis data, antrian, dan penyimpanan nilai kunci di Docker dan memindahkannya semudah aplikasi lainnya.


1
Terima kasih, Johann. Saya bekerja di ClusterHQ dan saya hanya ingin mencatat bahwa kami telah pindah melampaui hanya penyimpanan berbasis ZFS. Anda sekarang dapat menggunakan Flocker dengan penyimpanan seperti Amazon EBS atau Google Persistent Disk. Berikut adalah daftar lengkap opsi penyimpanan: docs.clusterhq.com/en/latest/supported/…
ferrantim

1
Flocker dihentikan dan tidak boleh digunakan portworx.com/...
jesugmz

5

Itu tergantung pada skenario Anda (ini tidak benar-benar cocok untuk lingkungan produksi), tetapi di sini ada satu cara:

Membuat Kontainer Docker MySQL

Inti dari ini adalah menggunakan direktori pada host Anda untuk kegigihan data.


6
Terima kasih Ben, namun - salah satu masalah yang dapat saya lihat dengan pendekatan ini: sumber daya sistem file (direktori, file) akan dimiliki oleh uid dari dalam wadah buruh pelabuhan / lxc (tamu) - yang mungkin bertabrakan dengan uid pada tuan rumah ...
juwalter

1
Saya pikir Anda cukup aman karena dijalankan oleh root, tapi saya setuju itu adalah hack - cocok untuk pengujian integrasi dev / ephemeral lokal di terbaik. Ini jelas merupakan area yang saya ingin melihat lebih banyak pola / pemikiran muncul. Anda harus memeriksa / memposting pertanyaan ini ke grup google docker-dev
ben schwartz

Ben, terima kasih atas solusi ini! Saya tidak akan menyebutnya hack, tampaknya jauh lebih dapat diandalkan daripada wadah sebagai volume . Apakah Anda melihat ada kekurangan jika data hanya digunakan dari wadah? (UID tidak masalah dalam kasus ini)
johndodo



0

Solusi saya adalah menggunakan yang baru docker cp , yang sekarang dapat menyalin data dari wadah, tidak masalah apakah itu berjalan atau tidak dan berbagi volume host ke lokasi yang sama persis di mana aplikasi database membuat file database di dalam wadah . Solusi ganda ini berfungsi tanpa wadah khusus data, langsung dari wadah basis data asli.

Jadi skrip init systemd saya mengambil pekerjaan mencadangkan database ke dalam arsip di host. Saya menempatkan cap waktu di nama file untuk tidak pernah menulis ulang file.

Itu melakukannya di ExecStartPre:

ExecStartPre=-/usr/bin/docker cp lanti-debian-mariadb:/var/lib/mysql /home/core/sql
ExecStartPre=-/bin/bash -c '/usr/bin/tar -zcvf /home/core/sql/sqlbackup_$$(date +%%Y-%%m-%%d_%%H-%%M-%%S)_ExecStartPre.tar.gz /home/core/sql/mysql --remove-files'

Dan itu juga melakukan hal yang sama di ExecStopPost:

ExecStopPost=-/usr/bin/docker cp lanti-debian-mariadb:/var/lib/mysql /home/core/sql
ExecStopPost=-/bin/bash -c 'tar -zcvf /home/core/sql/sqlbackup_$$(date +%%Y-%%m-%%d_%%H-%%M-%%S)_ExecStopPost.tar.gz /home/core/sql/mysql --remove-files'

Plus, saya mengekspos folder dari host sebagai volume ke lokasi yang sama persis di mana database disimpan:

mariadb:
  build: ./mariadb
  volumes:
    - $HOME/server/mysql/:/var/lib/mysql/:rw

Ini bekerja sangat baik pada VM saya (saya membangun sendiri tumpukan LEMP): https://github.com/DJviolin/LEMP

Tapi saya tidak tahu apakah itu solusi "antipeluru" ketika hidup Anda benar-benar bergantung padanya (misalnya, toko web dengan transaksi dalam milidetik yang memungkinkan)?

Pada 20 menit 20 detik dari video utama Docker ini, presenter melakukan hal yang sama dengan database:

Memulai dengan Docker

"Untuk basis data kami memiliki volume, sehingga kami dapat memastikan bahwa, ketika basis data naik dan turun, kami tidak kehilangan data, ketika wadah basis data berhenti."


Apa yang Anda maksud dengan "... gunakan ..." ? Dan "... transaksi dalam milidetik yang memungkinkan" ?
Peter Mortensen

0

Gunakan Persistent Volume Claim (PVC) dari Kubernetes, yang merupakan alat manajemen jadwal dan penjadwalan Docker:

Volume Persisten

Keuntungan menggunakan Kubernetes untuk tujuan ini adalah:

  • Anda dapat menggunakan penyimpanan apa pun seperti NFS atau penyimpanan lain dan bahkan ketika node sedang down, penyimpanan tidak perlu.
  • Selain itu, data dalam volume tersebut dapat dikonfigurasi untuk disimpan bahkan setelah wadahnya sendiri dihancurkan - sehingga dapat diambil kembali, jika perlu, oleh wadah lain.
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.