Jak radzić sobie z trwałym magazynowaniem (np. Bazami danych) w Docker


992

Jak ludzie radzą sobie z trwałym przechowywaniem kontenerów Docker?

Obecnie używam tego podejścia: zbuduj obraz, np. Dla PostgreSQL, a następnie uruchom kontener za pomocą

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

IMHO, który ma tę wadę, że nie wolno mi (przypadkowo) usuwać kontenera „c0dbc34fd631”.

Innym pomysłem byłoby zamontowanie woluminów hosta „-v” w kontenerze, jednak identyfikator użytkownika w kontenerze niekoniecznie odpowiada identyfikatorowi użytkownika z hosta, a następnie uprawnienia mogą zostać pomieszane.

Uwaga: Zamiast --volumes-from 'cryptic_id'ciebie możesz również użyć --volumes-from my-data-containergdzie my-data-containerjest nazwa przypisana do kontenera tylko danych, np. docker run --name my-data-container ...(Patrz zaakceptowana odpowiedź)


Przepraszam, źle to sformułowałem, chciałem powiedzieć: wszystkie moje przyszłe wystąpienia z tego obrazu zależą od tego kontenera. Jeśli przypadkowo usunę ten kontener, mam kłopoty.
juwalter 17.09.13

@AntonStrogonoff - tak, błąd frazowania - chciałem powiedzieć: muszę się upewnić, że nigdy nie usunę tego (prawdopodobnie) starego kontenera, ponieważ wtedy zniknie odniesienie do pamięci „trwałej”
juwalter

tak powinno być --name. masz-name
Shammel Lee,

Odpowiedzi:


986

Docker 1.9.0 i nowsze wersje

Użyj interfejsu API woluminu

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

Oznacza to, że wzorzec kontenera zawierającego tylko dane musi zostać porzucony na rzecz nowych woluminów.

W rzeczywistości interfejs API woluminu jest tylko lepszym sposobem na osiągnięcie wzorca kontenera danych.

Jeśli utworzysz kontener za pomocą -v volume_name:/container/fs/pathDockera, automatycznie utworzy się nazwany wolumin, który może:

  1. Bądź na liście poprzez docker volume ls
  2. Być zidentyfikowanym poprzez docker volume inspect volume_name
  3. Utworzono kopię zapasową jako normalny katalog
  4. Utworzono kopię zapasową jak poprzednio przez --volumes-frompołączenie

Nowy interfejs API woluminu dodaje przydatne polecenie, które pozwala zidentyfikować wiszące woluminy:

docker volume ls -f dangling=true

A następnie usuń go poprzez jego nazwę:

docker volume rm <volume name>

Jak podkreśla @mpugach w komentarzach, możesz pozbyć się wszystkich wiszących woluminów za pomocą ładnego jednowierszowego:

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

Docker 1.8.xi niższe

Podejście, które wydaje się działać najlepiej w przypadku produkcji, polega na użyciu kontenera zawierającego tylko dane .

Kontener tylko danych jest uruchamiany na obrazie barebone i właściwie nie robi nic poza ujawnieniem woluminu danych.

Następnie możesz uruchomić dowolny inny kontener, aby uzyskać dostęp do woluminów kontenera danych:

docker run --volumes-from data-container some-other-container command-to-execute
  • Tutaj możesz uzyskać dobry obraz rozmieszczenia różnych pojemników.
  • Tutaj jest dobry wgląd w działanie woluminów.

W tym poście na blogu znajduje się dobry opis tak zwanego kontenera jako wzorca objętości, który wyjaśnia główny punkt posiadania kontenerów zawierających wyłącznie dane .

Dokumentacja dokera ma teraz DEFINICJALNY opis kontenera jako wzorzec wolumenu / s .

Poniżej znajduje się procedura tworzenia kopii zapasowych / przywracania dla Docker 1.8.xi niższych.

UTWORZYĆ KOPIĘ ZAPASOWĄ:

sudo docker run --rm --volumes-from DATA -v $(pwd):/backup busybox tar cvf /backup/backup.tar /data
  • --rm: wyjmij pojemnik po wyjściu
  • --volumes-from DATA: dołącz do woluminów udostępnianych przez kontener DATA
  • -v $ (pwd): / backup: bind podłącz bieżący katalog do kontenera; zapisać plik tar do
  • busybox: mały, prostszy obraz - dobry do szybkiej konserwacji
  • tar cvf /backup/backup.tar / data: tworzy nieskompresowany plik tar wszystkich plików w katalogu / data

PRZYWRACAĆ:

# 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

Oto fajny artykuł doskonałego Briana Goffa wyjaśniający, dlaczego warto używać tego samego obrazu dla kontenera i kontenera danych.


8
To różne narzędzie do różnych potrzeb. --volumes-frompozwala współdzielić miejsce na dysku, --linkumożliwia udostępnianie usług
tommasop

3
Jest inny projekt w pracach specjalnie przeznaczony do tego rodzaju rzeczy, może dodać go do tej odpowiedzi jako odniesienie do obejrzenia? github.com/ClusterHQ/flocker
Andre

9
Kontenery danych nie mają żadnego znaczenia i są naprawdę złym pomysłem! Kontener oznacza tylko coś, gdy proces w nim działa, w przeciwnym razie jest to tylko część systemu plików hosta. Możesz po prostu zamontować wolumin z opcją -v, która jest jedyną i najlepszą opcją. Masz kontrolę nad systemem plików i używanym dyskiem fizycznym.
Boynux,

11
Tak, od Docker 1.9, tworzenie nazwanych woluminów za pomocą API Volumes API ( docker volume create --name mydata) jest preferowane w stosunku do kontenera woluminów danych. Ludzie w Docker sami sugerują, że kontenery woluminów danych „ nie są już uważane za zalecany wzorzec ”, „ nazwane woluminy powinny być w stanie zastąpić woluminy zawierające tylko dane w większości (jeśli nie wszystkich) przypadkach ” i „ bez powodu, dla którego mogę użyć kontenery tylko z danymi ”.
Quinn Comendant

8
@ kodowanie, przykro mi, że jesteś smutny, częściowo dlatego, że oceniasz odpowiedzi z 3-letnim opóźnieniem, a częściowo dlatego, że odpowiedź jest zasadniczo poprawna w całej jej historii. Jeśli masz jakąś radę, skomentuj to, żebym mógł zintegrować odpowiedź i pomóc
innym

75

W Docker wersja 1.0 powiązanie podłączenia pliku lub katalogu na maszynie hosta można wykonać za pomocą podanego polecenia:

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

Powyższy wolumin może być używany jako trwały magazyn na hoście z uruchomionym Dockerem.


3
To powinna być zalecana odpowiedź, ponieważ jest o wiele mniej skomplikowana niż podejście oparte na pojemniku objętościowym, które ma obecnie więcej głosów
insitusec

2
Chciałbym, aby istniała flaga określająca mapowanie identyfikatora hosta: identyfikator-kontenera i identyfikator-hosta: identyfikator-kontenera podczas korzystania z polecenia podłączenia woluminu.
rampion

35

Od Docker Compose 1.6 poprawiono obsługę woluminów danych w Docker Compose. Poniższy plik tworzenia utworzy obraz danych, który będzie trwał między ponownymi uruchomieniami (a nawet usunięciem) kontenerów nadrzędnych:

Oto ogłoszenie na blogu: Compose 1.6: Nowy plik Compose do definiowania sieci i woluminów

Oto przykładowy plik tworzenia:

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:

O ile rozumiem: utworzy to kontener woluminu danych ( db_data), który będzie trwał między restartami.

Jeśli uruchomisz: docker volume lspowinieneś zobaczyć swój wolumin na liście:

local               mypthonapp_db-data
...

Możesz uzyskać więcej szczegółowych informacji na temat objętości danych:

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

Niektóre testy:

# 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).

Uwagi:

  • W volumesbloku można również określić różne sterowniki . Na przykład można określić sterownik Flocker dla danych db_data:

    volumes:
      db-data:
        driver: flocker
    
  • Ponieważ poprawiają integrację między Docker Swarm i Docker Compose (i być może zaczynają integrować Flocker z ekosystemem Docker (słyszałem plotki, że Docker kupił Flocker), myślę, że to podejście powinno stać się coraz silniejsze.

Oświadczenie: To podejście jest obiecujące i używam go z powodzeniem w środowisku programistycznym. Obawiałbym się wykorzystać to jeszcze w produkcji!


Flocker został wyłączony i na repozytorium github
Krishna

17

W przypadku, gdy nie jest jasne z aktualizacji 5 wybranej odpowiedzi, począwszy od Docker 1.9, można tworzyć woluminy, które mogą istnieć bez powiązania z konkretnym kontenerem, dzięki czemu wzorzec „kontenera tylko danych” staje się nieaktualny.

Zobacz Kontenery tylko z danymi przestarzałe w programie dokującym 1.9.0? # 17798 .

Wydaje mi się, że opiekunowie Dockera zdali sobie sprawę, że wzorzec kontenera obejmujący tylko dane był nieco zapachowym zapachem projektu i postanowili uczynić woluminy osobnym bytem, ​​który może istnieć bez powiązanego kontenera.


13

Chociaż jest to nadal część Dockera, która wymaga trochę pracy , powinieneś umieścić wolumin w Dockerfile z instrukcją VOLUME , abyś nie musiał kopiować woluminów z innego kontenera.

To sprawi, że twoje pojemniki będą mniej zależne od siebie i nie będziesz musiał się martwić, że usunięcie jednego pojemnika wpłynie na inny.


Drugim argumentem jest to, że kontenery „tylko dane” są ostatecznym odniesieniem do woluminu danych (Docker niszczy woluminy danych, gdy ostatni kontener odwołujący się do tego woluminu zostanie usunięty docker rm)
WineSoaked

2
Ten oficjalny przewodnik od Dockera sugeruje inaczej: docs.docker.com/userguide/dockervolumes/... " Woluminy danych są zaprojektowane do przechowywania danych, niezależnie od cyklu życia kontenera. Docker nigdy nie usuwa automatycznie woluminów po usunięciu kontenera, ani nie będzie Woluminy „odśmiecanie”, do których nie odwołuje się już kontener. ”
Alex

12

Korzystając z Docker Compose , po prostu dołącz nazwany wolumin, na przykład:

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

9

Odpowiedź @ tommasop jest dobra i wyjaśnia niektóre mechanizmy korzystania z kontenerów zawierających tylko dane. Ale ponieważ ktoś, kto początkowo myślał, że pojemniki z danymi są głupie, gdy można po prostu powiązać, zamontuje wolumin na hoście (jak sugeruje kilka innych odpowiedzi), ale teraz zdaje sobie sprawę, że w rzeczywistości pojemniki tylko z danymi są całkiem fajne, mogę zasugerować własny post na blogu na ten temat: Dlaczego pojemniki danych Docker (woluminy!) są dobre

Zobacz także: moja odpowiedź na pytanie „ Jaki jest (najlepszy) sposób zarządzania uprawnieniami do udostępnionych woluminów Docker? ”, Na przykład, jak używać kontenerów danych, aby uniknąć problemów takich jak uprawnienia i mapowanie UID / GID z hostem.

Aby rozwiązać jedną z pierwotnych obaw PO: nie można usunąć kontenera danych. Nawet jeśli kontener danych zostanie usunięty, same dane nie zostaną utracone, dopóki jakikolwiek kontener będzie miał odniesienie do tego woluminu, tj. Do dowolnego kontenera, przez który zamontowano wolumin --volumes-from. Tak więc, chyba że wszystkie powiązane kontenery zostaną zatrzymane i usunięte (można uznać to za ekwiwalent przypadku rm -fr /) dane są bezpieczne. Zawsze możesz odtworzyć kontener danych, wykonując --volumes-fromdowolny kontener, który ma odniesienie do tego woluminu.

Jak zawsze rób jednak kopie zapasowe!

AKTUALIZACJA: Docker ma teraz woluminy, którymi można zarządzać niezależnie od kontenerów, co dodatkowo ułatwia zarządzanie.


9

Istnieje kilka poziomów zarządzania trwałymi danymi, w zależności od potrzeb:

  • Zapisz go na swoim hoście
    • Użyj flagi, -v host-path:container-pathaby utrwalić dane katalogu kontenera w katalogu hosta.
    • Tworzenie kopii zapasowych / przywracanie odbywa się przez uruchomienie kontenera kopii zapasowych / przywracania (takiego jak tutumcloud / dockup) podłączonego do tego samego katalogu.
  • Utwórz kontener danych i podłącz jego woluminy do kontenera aplikacji
    • Utwórz kontener, który eksportuje wolumin danych, użyj --volumes-fromdo zamontowania tych danych w kontenerze aplikacji.
    • Wykonaj kopię zapasową / przywróć tak samo jak powyższe rozwiązanie.
  • Użyj wtyczki woluminu Docker, która wspiera usługę zewnętrzną / zewnętrzną
    • Wtyczki woluminów Docker umożliwiają dostęp do źródła danych z dowolnego miejsca - NFS, AWS (S3, EFS i EBS)
    • W zależności od wtyczki / usługi możesz dołączyć jeden lub wiele kontenerów do jednego woluminu.
    • W zależności od usługi kopie zapasowe / przywracania mogą być dla Ciebie zautomatyzowane.
    • Chociaż może to być kłopotliwe, aby to zrobić ręcznie, niektóre rozwiązania w zakresie aranżacji - takie jak Rancher - sprawiają, że jest on upieczony i prosty w użyciu.
    • Konwój jest najłatwiejszym rozwiązaniem do wykonania tego ręcznie.

8

Jeśli chcesz przenosić woluminy, powinieneś również spojrzeć na Flockera .

Z README:

Flocker to menedżer woluminów danych i narzędzie do zarządzania klastrami Docker dla wielu hostów. Dzięki niemu możesz kontrolować swoje dane za pomocą tych samych narzędzi, których używasz w bezpaństwowych aplikacjach, wykorzystując moc ZFS w systemie Linux.

Oznacza to, że możesz uruchamiać swoje bazy danych, kolejki i sklepy z kluczowymi wartościami w Docker i przenosić je tak łatwo, jak resztę aplikacji.


1
Dzięki Johann. Pracuję w ClusterHQ i chciałem tylko zauważyć, że wykroczyliśmy poza pamięć opartą na ZFS. Możesz teraz korzystać z Flockera z pamięcią taką jak Amazon EBS lub Google Persistent Disk. Oto pełna lista opcji przechowywania: docs.clusterhq.com/en/latest/supported/…
ferrantim

1
Flokery zostały zakończone i nie należy ich używać portworx.com/…
jesugmz

5

To zależy od twojego scenariusza (nie jest to tak naprawdę odpowiednie dla środowiska produkcyjnego), ale jest jeden sposób:

Tworzenie kontenera dokującego MySQL

Jego istotą jest użycie katalogu na hoście w celu utrwalenia danych.


6
Dzięki Ben, jeden z problemów, które widzę przy takim podejściu: zasób systemu plików (katalog, pliki) byłby własnością UID z kontenera docker / lxc (gość) - taki, który może kolidować z UID na hoście ...
juwalter

1
myślę, że jesteś całkiem bezpieczny, ponieważ jest uruchamiany przez root, ale zgadzam się, że jest to hack - odpowiedni w najlepszym przypadku do testowania lokalnej / efemerycznej integracji. To zdecydowanie obszar, w którym chciałbym zobaczyć więcej wzorów / myślenia. Powinieneś sprawdzić / opublikować to pytanie w docker-dev google group
ben schwartz

Ben, dzięki za to rozwiązanie! Nie nazwałbym tego jednak hackem, wydaje się znacznie bardziej niezawodny niż kontener jako wolumin . Czy widzisz jakieś wady w przypadku, gdy dane są wykorzystywane wyłącznie z kontenera? (UID nie ma znaczenia w tym przypadku)
johndodo



0

Moim rozwiązaniem jest skorzystanie z nowego docker cp, który jest teraz w stanie kopiować dane z kontenerów, bez względu na to, czy jest uruchomiony, czy nie i udostępniać wolumin hosta dokładnie w tej samej lokalizacji, w której aplikacja bazy danych tworzy swoje pliki bazy danych w kontenerze . To podwójne rozwiązanie działa bez kontenera tylko danych, prosto z oryginalnego kontenera bazy danych.

Tak więc mój systemowy skrypt startowy wykonuje kopię zapasową bazy danych w archiwum na hoście. W nazwie pliku umieściłem znacznik czasu, aby nigdy nie przepisywać pliku.

Robi to na 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'

I robi to samo na 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'

Dodatkowo odsłoniłem folder z hosta jako wolumin dokładnie w tej samej lokalizacji, w której przechowywana jest baza danych:

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

Działa świetnie na mojej maszynie wirtualnej (buduję stos LEMP dla siebie): https://github.com/DJviolin/LEMP

Ale po prostu nie wiem, czy jest to „kuloodporne” rozwiązanie, gdy twoje życie zależy od niego (na przykład sklep internetowy z transakcjami w każdej możliwej milisekundie)?

Po 20 min. 20 sek. Od tego oficjalnego filmu przewodniego Dockera prezenter robi to samo z bazą danych:

Rozpoczęcie pracy z Dockerem

„W przypadku bazy danych mamy wolumin, dzięki czemu możemy się upewnić, że gdy baza danych będzie rosła i spadała, nie tracimy danych, gdy kontener bazy danych zatrzyma się”.


Co rozumiesz przez „... skorzystaj z ...” ? I „... transakcje w możliwych milisekundach” ?
Peter Mortensen

0

Użyj trwałej deklaracji wolumenu (PVC) z Kubernetes, która jest narzędziem do zarządzania i planowania kontenerów Docker:

Trwałe objętości

Zalety korzystania z Kubernetes w tym celu:

  • Możesz użyć dowolnego magazynu, takiego jak NFS lub inny, i nawet gdy węzeł nie działa, nie musi to być.
  • Ponadto dane w takich woluminach można skonfigurować tak, aby były przechowywane nawet po zniszczeniu samego kontenera - aby w razie potrzeby można je było odzyskać z innego kontenera.
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.