Я втрачаю свої дані, коли контейнер виходить


394

Незважаючи на інтерактивний підручник Докера та файли, я втрачаю свої дані, коли контейнер виходить.

Я встановив Docker, як описано тут: http://docs.docker.io/en/latest/installation/ubuntulinux без проблем на ubuntu 13.04.

Але він втрачає всі дані при виході.

iman@test:~$ sudo docker version
Client version: 0.6.4 
Go version (client): go1.1.2 
Git commit (client): 2f74b1c 
Server version: 0.6.4 
Git commit (server): 2f74b1c 
Go version (server): go1.1.2 
Last stable version: 0.6.4 


iman@test:~$ sudo docker run ubuntu ping
2013/10/25 08:05:47 Unable to locate ping 
iman@test:~$ sudo docker run ubuntu apt-get install ping
Reading package lists... 
Building dependency tree... 
The following NEW packages will be installed: 
  iputils-ping 
0 upgraded, 1 newly installed, 0 to remove and 0 not upgraded. 
Need to get 56.1 kB of archives. 
After this operation, 143 kB of additional disk space will be used. 
Get:1 http://archive.ubuntu.com/ubuntu/ precise/main iputils-ping amd64 3:20101006-1ubuntu1 [56.1 kB] 
debconf: delaying package configuration, since apt-utils is not installed 
Fetched 56.1 kB in 0s (195 kB/s) 
Selecting previously unselected package iputils-ping. 
(Reading database ... 7545 files and directories currently installed.) 
Unpacking iputils-ping (from .../iputils-ping_3%3a20101006-1ubuntu1_amd64.deb) ... 
Setting up iputils-ping (3:20101006-1ubuntu1) ... 
iman@test:~$ sudo docker run ubuntu ping
2013/10/25 08:06:11 Unable to locate ping 
iman@test:~$ sudo docker run ubuntu touch /home/test
iman@test:~$ sudo docker run ubuntu ls /home/test
ls: cannot access /home/test: No such file or directory 

Я також перевірив це на інтерактивних сесіях з тим же результатом. Я щось забув?

РЕДАКТУВАННЯ: ВАЖЛИВО ДЛЯ НОВИХ ПОТРІБНИКІВ

Як сказали @ mohammed-noureldin та інші, насправді це НЕ є контейнер, що виходить . Кожен раз, коли він просто створює новий контейнер.


10
Це не можна назвати « контейнером, що виходить », ви просто створюєте новий контейнер, використовуючи слово, що виходить, може сильно заплутати (я через це теж заплутався).
Мухаммед Нурелдін

1
@MohammedNoureldin, ти маєш рацію, вихід невірний, але це саме те, що ви, я та інші думали. Тож краще слово, про яке йдеться, ваша редакція робить питання на відповідь! Нових шукачів тут не знайдуть!
іман

На моєму початковому етапі з Докером я подумав, що насправді через ТВОЕ запитання я вважаю, що ця адреса просто НЕПРАВИЛЬНА. нова назва була переглянута і прийнята, я не розумію, чому хтось повинен наполягати на неправильному заголовку, це ваше питання та ваше рішення.
Мухаммед Нурелдін

3
Я згоден з @MohammedNoureldin. Поєднання конкретної назви, прикладу та прийнятої відповіді не допомагає майбутнім читачам, а особливо новачкам зрозуміти Docker. Я б запропонував зберегти назву та оригінальне запитання, оскільки початківці обов'язково шукають щось подібне. Але чому б ви не додали щось, що описує ваші помилкові уявлення під час написання публікації. Це допоможе зрозуміти речі. Це наша культура тут, в SO… чи не так? :-)
tgogos

2
У мене була ця проблема ... кожен раз, коли ви повинні запустити ваш контейнер, не запускайте його ... запустіть зображення agane зробити новий контейнер, це допоможе докеру запустити <ідентифікатор контейнера> докер приєднати <ідентифікатор контейнера>
destmeh

Відповіді:


399

Вам потрібно здійснити внесені вами зміни в контейнер, а потім запустити його. Спробуйте це:

sudo docker pull ubuntu

sudo docker run ubuntu apt-get install -y ping

Потім отримайте ідентифікатор контейнера за допомогою цієї команди:

sudo docker ps -l

Внести зміни в контейнер:

sudo docker commit <container_id> iman/ping 

Потім запустіть контейнер:

sudo docker run iman/ping ping www.google.com

Це має спрацювати.


9
Таким чином , я повинен використовувати фіксації після кожного запуску , щоб зберегти дані.
iman

5
Коміт слід використовувати лише тоді, коли ви внесете ЗМІНИ в контейнер (наприклад, встановлення нових інструментів чи даних), щоб ці зміни були збережені, і наступного разу, коли ви запустите новий контейнер із цього зображення, він розпочнеться з точки останнього збереження або здійснювати, зберігаючи ваші дані.
Unferth

7
@Unferth що робити, якщо я хочу продовжувати вносити зміни? Поки це створює більше зображень із <none>. Як я можу додавати комітку поверх наявного зображення?
Марконі

62
Поступово внесення змін - це не "докерський шлях". Використовуйте DOCKERFILE.
user2105103

23
Як би ви зробили зсередини контейнера? Розглянемо наступний сценарій: 1) Я запускаю контейнер так: docker run -i -t myimage / bin / bash 2) я вношу деякі зміни 3) я не можу зробити зсередини контейнера, тому коли я виходжу з контейнера, я втратить усі мої дані, не маючи шансу здійснити попередні зміни
qgicup

374

Коли ви використовуєте docker runдля запуску контейнера, він фактично створює новий контейнер на основі вказаного вами зображення.

Окрім інших корисних відповідей тут, зауважте, що ви можете перезапустити існуючий контейнер після його виходу, і зміни все ще є.

docker start f357e2faab77 # restart it in the background
docker attach f357e2faab77 # reattach the terminal & stdin

88
docker psпоказує, що ви працюєте лише з контейнерами докера. docker ps -aпоказує вам і ті, що вийшли - і що ви можете продовжувати працювати. Фіксація необхідна лише після кожного запуску, якщо ви хочете зробити знімок там для подальшого використання, інакше сам контейнер буде триматися навколо вас, щоб продовжувати використовувати.
користувач1278519

2
Питання, будь ласка, тому якщо я завантажую jenkinsсерверний докер і я запускаю його на своєму хості ci, і він виконує деякі роботи, які у мене є, і в результаті сервер jenkins записує на диск деякі журнали. тепер якщо мій сервер (на якому розміщений мій докер) буде перезапущений, і я запускаю знову свій докер-jenkins, це означатиме, що я втратив усі файли журналу? якщо це так, як я можу, наприклад, використовувати jenkinsдокер для полегшення моєї установки dnkins на CI?
Жас

2
@Jas Якщо ви дотримуєтесь одного і того ж контейнера і не створюєте нових, проблем немає. На сьогодні Docker має політику перезавантаження, тож ви можете налаштувати його для перезавантаження того ж контейнера при перезавантаженні машини. Я також радив би розмістити ваші дженкіни додому в об'ємі, щоб мати доступ до нього ззовні (резервні копії тощо).
ZeissS

7
Ось зручний спосіб копіювання файлів із контейнера після виходу:docker cp $(docker ps -alq):/path/to/file .
Джош Хабдас

3
Ви також можете запустити та приєднати контейнер за його назвою. (наприклад, docker run -it --name my_debian debianі після docker start my_debian && docker attach my_debian)
Джонні Віллер

127

Існують такі способи збереження даних контейнера:

  1. Обсяги докерів

  2. Докер здійснюють

    а) створити контейнер з образу ubuntu і запустити bash-термінал.

       $ docker run -i -t ubuntu:14.04 /bin/bash
    

    b) Всередині терміналу встановити завиток

       # apt-get update
       # apt-get install curl
    

    в) Вийдіть з контейнерного терміналу

       # exit
    

    г) Візьміть на замітку свій ідентифікатор контейнера, виконавши таку команду:

       $ docker ps -a
    

    д) збережіть контейнер як нове зображення

       $ docker commit <container_id> new_image_name:tag_name(optional)
    

    f) переконайтеся, що ви можете бачити нове зображення зі встановленим завитком.

       $ docker images           
    
       $ docker run -it new_image_name:tag_name bash
          # which curl
            /usr/bin/curl
    

Чи потрібно exitраніше docker commit? Дякую.
Абхішек Ананд

2
@AbhishekAnand так, тому що за допомогою docker runкоманди ви запускаєте bash в контейнері, і ви залишаєтесь там, завдяки -iі -tпараметрам (інтерактивне з TTY). Однак Docker працює на вашій машині, поза контейнером, тому після внесення необхідних змін у контейнер зсередини, щоб повернутися до оболонки вашої системи, ви повинні exit(або Ctrl + D) оболонку контейнера. Також зверніть увагу на відповідь #та $у відповіді, де вказані різні оболонки, на які написані команди.
Ерік

Швидке запитання: Якщо я не беру на себе зобов'язання, я втратив дані. Ясно. Але коли я змінюю конфігурацію nginx, чому вона залишається оновленою? (не потрібно вчиняти) @Erik
grep

@grep, якщо у вас є чітке та відтворюване MWE, будь ласка, задайте нове запитання щодо нього, якщо вже немає жодного з цього конкретного випадку використання.
Ерік

3. docker stopслідом за ним docker start.
carillonator

59

Крім відповіді Унферта , рекомендується створити Dockerfile .

У порожньому каталозі створіть файл під назвою "Dockerfile" із наступним вмістом.

FROM ubuntu
RUN apt-get install ping
ENTRYPOINT ["ping"]

Створіть зображення за допомогою Dockerfile . Давайте скористаємося тегом, тому нам не потрібно запам’ятовувати шістнадцятковий номер зображення.

$ docker build -t iman/ping .

А потім запустіть зображення в контейнері.

$ docker run iman/ping stackoverflow.com

1
Ніколи не потрібно робити це вручну більше одного разу - це саме сенс докера. Створіть докер-файл, скопіюйте та завантажте отримане зображення. Витягніть зазначене зображення вперед.
Брендон Бертелсен

11

Я отримав набагато простішу відповідь на ваше запитання, виконайте наступні дві команди

sudo docker run -t -d ubuntu --name mycontainername /bin/bash
sudo docker ps -a

вищевказана команда ps -a повертає список усіх контейнерів. Візьміть назву контейнера, на який посилається ім'я зображення - "ubuntu". docker auto генерує імена контейнерів, наприклад, - 'lightlyxuyzx'це, якщо ви не використовуєте параметр --name.

Важливі параметри -t і -d, створений контейнер відокремлений і його можна приєднати, як зазначено нижче, за допомогою параметра -t.

З опцією --name, ви можете назвати контейнер у моєму випадку "mycontainername".

sudo docker exec -ti mycontainername bash

і ця команда вище допомагає вам увійти в контейнер з оболонкою bash. З цього моменту будь-які зміни, внесені в контейнер, докер автоматично зберігаються. Наприклад -apt-get install curl всередині контейнера Ви можете вийти з контейнера без проблем, докер автоматично зберігає зміни.

При наступному використанні все, що вам потрібно зробити, це запустити ці дві команди щоразу, коли ви хочете працювати з цим контейнером.

Ця команда нижче запустить зупинений контейнер:

sudo docker start mycontainername

sudo docker exec -ti mycontainername bash

Ще один приклад з портами та спільним простором, наведеним нижче:

docker run -t -d --name mycontainername -p 5000:5000 -v ~/PROJECTS/SPACE:/PROJECTSPACE 7efe2989e877 /bin/bash

У моєму випадку: 7efe2989e877 - це образ зображення попереднього запущеного контейнера, який я отримав за допомогою

докер пс -а


4
З Docker 18.09.2 на Ubuntu 18.04 він не працює так, як є. Це спрацьовує, якщо я поставити --nameта опцію перед назвою зображення, як це:docker run --name mycontainername -t -d ubuntu /bin/bash
Stéphane Gourichon


3

Моя пропозиція - керувати docker, з docker compose. Це простий спосіб керувати всіми контейнерами докера для вашого проекту, ви можете зіставити версії та зв’язати різні контейнери для спільної роботи.

Документи зрозуміти дуже просто, краще, ніж документи докера.

Док-композиційні документи

Найкраще


3

Вище є чудові відповіді на поставлене запитання. Можливо, не буде потреби в іншій відповіді, але все ж я хочу дати свою особисту думку з цієї теми найпростішими можливими словами.

Ось декілька пунктів про контейнери та зображення, які допоможуть нам зробити висновок:

  • Зображення докера може бути :
    1. створено-з-даного-контейнера
    2. видалено
    3. використовується для створення-будь-якої кількості контейнерів
  • Контейнер для докерів може бути :
    1. створений із зображення
    2. розпочато
    3. зупинився
    4. перезапущено
    5. видалено
    6. використовується для створення будь-якого числа зображень
  • Команда запуску докера робить це :
    1. Завантажує зображення або використовує кешоване зображення
    2. Створює з нього новий контейнер
    3. Запускає контейнер
  • Коли для створення зображення використовується Dockerfile :
    1. Вже відомо, що з часом зображення буде використано для запуску докерного контейнера.
    2. Після видачі команди збірки docker, docker за кадром створює запущений контейнер із базовою файловою системою та виконує кроки всередині Dockerfile для налаштування цього контейнера відповідно до необхідності розробників.
    3. Після того, як контейнер буде налаштований з специфікаціями Dockerfile, він буде зроблений як зображення.
    4. Зображення готується до рок-н-ролу!

Висновок :

Як ми бачимо, контейнер докера не залежить від зображення докера.

Контейнер можна перезапустити за умови унікального ідентифікатора цього контейнера [використовувати docker ps --allдля отримання ідентифікатора] .

Будь-яка операція, наприклад створення нового каталогу, створення файлів, встановлення інструментів тощо, може бути виконана всередині контейнера під час його запуску. Після того, як контейнер буде зупинений, він зберігає всі зміни. Зупинка та перезавантаження контейнера - це як перезавантаження комп'ютерної системи.

Уже створений контейнер завжди доступний для перезавантаження, але коли ми видаємо docker runкоманду, новий контейнер створюється із зображення, а значить, це як нова комп'ютерна система. Зміни, внесені всередині старого контейнера - як ми зараз можемо зрозуміти - недоступні в цьому новому контейнері.

Заключна примітка :

Я думаю, зараз очевидно, чому дані, здається, втрачаються, але вони завжди є .. але в іншому [старому] контейнері. Отже, візьміть хорошу ноту різниці в docker start& docker runкоманди і ніколи не заплутатися в них.


1

подібна проблема (і жоден спосіб Dockerfile не міг її виправити) привела мене до цієї сторінки.

етап 0: для всіх, сподіваючись, що Dockerfile зможе це виправити: поки --dns та --dns-search не з’являться у підтримці Dockerfile - немає можливості інтегрувати ресурси на базі інтрамережі.

етап 1: після складання зображення за допомогою Dockerfile (до речі, це серйозний глюк Dockerfile повинен бути в поточній папці), маючи зображення для розгортання, що базується на інтранет, запустивши скрипт запуску docker. приклад: docker run -d \ --dns=${DNSLOCAL} \ --dns=${DNSGLOBAL} \ --dns-search=intranet \ -t pack/bsp \ --name packbsp-cont \ bash -c " \ wget -r --no-parent http://intranet/intranet-content.tar.gz \ tar -xvf intranet-content.tar.gz \ sudo -u ${USERNAME} bash --norc"

етап 2: застосування сценарію запуску докера в демон-режимі, що забезпечує місцеві записи dns, щоб мати можливість завантажувати та розгортати локальні речі.

важливий момент: сценарій запуску повинен закінчуватися чимось на зразок, /usr/bin/sudo -u ${USERNAME} bash --norcщоб тримати контейнер працює навіть після завершення встановлення скриптів.

ні , неможливо запустити контейнер в інтерактивному режимі для повного питання автоматизації, оскільки він залишатиметься всередині внутрішнього командного рядка, поки не буде натиснуто CTRL-p CTRL-q .

ні , якщо взаємодія bash не буде виконана в кінці інсталяційного скрипту, контейнер припиняється негайно після завершення виконання сценарію, втрачаючи всі результати установки.

етап 3: контейнер все ще працює у фоновому режимі, але незрозуміло, завершив процедуру встановлення контейнер чи ні ще. використовуючи наступний блок для визначення процедури виконання: while ! docker container top ${CONTNAME} | grep "00[[:space:]]\{12\}bash \--norc" - do echo "." sleep 5 done сценарій буде продовжуватись лише після завершення встановлення. і це правильний момент для виклику: фіксувати , надаючи поточний ідентифікатор контейнера, а також ім'я зображення призначення (він може бути таким же, як у процедурі збирання / запуску, але додається до тегу місцевих цілей установки. Приклад:. docker commit containerID pack/bsp:toolchainedдив. це посилання на Як отримати належний контейнерID

етап 4: контейнер було оновлено з локальними встановленнями, а також було зроблено в новопризначене зображення (додано тег цілей). зараз безпечно припинити роботу контейнера. приклад:docker stop packbsp-cont

етап5: будь-який момент, коли контейнер з локальними встановленнями потребує запуску, запустіть його із збереженого раніше зображення. приклад:docker run -d -t pack/bsp:toolchained


1

тут блискуча відповідь. Як продовжити докер, який вийшов із кілограмів користувача

docker start $(docker ps -a -q --filter "status=exited")
(or in this case just docker start $(docker ps -ql) 'cos you don't want to start all of them)

docker exec -it <container-id> /bin/bash

Цей другий рядок є вирішальним. Отже, exec використовується замість запуску, і не на зображенні, а на контейнері. І ви це робите після запуску контейнера.


0

Жодна з відповідей не стосується питання цього вибору дизайну. Я думаю, що докер працює таким чином, щоб запобігти ці 2 помилки:

  • Повторний перезапуск
  • Часткова помилка
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.