Я теряю свои данные при выходе из контейнера


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 

Я также проверил это с интерактивными сессиями с тем же результатом. Я что-то забыл?

РЕДАКТИРОВАТЬ: ВАЖНО ДЛЯ НОВЫХ ПОЛЬЗОВАТЕЛЕЙ DOCKER

Как @ Магомет-Noureldin и другие говорили, на самом деле это НЕ контейнер выхода . Каждый раз он просто создает новый контейнер.


10
Это нельзя назвать « выходом из контейнера », вы просто создаете новый контейнер, и использование выходного слова может сильно запутать (из-за этого я тоже запутался).
Мохаммед Нурельдин

1
@MohammedNoureldin, вы правы, выходить не правильно, но это именно то, что вы, я и другие думали. Так что это лучшее слово в вопросе, ваша редакция делает вопрос ответом! Новые искатели не найдут здесь!
Иман

В самом начале своей работы с Docker я думал, что на самом деле из-за ВАШЕГО вопроса я нахожу этот адрес просто НЕПРАВИЛЬНЫМ. новый заголовок был рассмотрен и принят, я не понимаю, почему кто-то должен настаивать на неправильном названии, это ваш вопрос и ваше решение.
Мохаммед Нурельдин

3
Я согласен с @MohammedNoureldin. Сочетание конкретного названия, примера и принятого ответа не помогает будущим читателям и особенно новичкам понять Docker. Я бы предложил сохранить название и исходный вопрос, поскольку новички обязательно будут искать что-то подобное. Но почему бы вам не добавить что-то, описывающее ваши заблуждения во время написания поста? Это поможет прояснить ситуацию. Это наша культура здесь, в СО ... не так ли? :-)
tgogos

2
У меня была эта проблема ... каждый раз, когда вы выходите, вы должны запустить свой контейнер, а не запускать его ... запустите образ agane, создайте новый контейнер, это поможет запуску докера <идентификатор контейнера> прикрепление докера <идентификатор контейнера>
рок-н-ролл

Ответы:


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
Поэтому я должен использовать commit после каждого запуска для сохранения данных.
Имэн

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

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

62
Инкрементное внесение изменений - это не «путь докера». Используйте DOCKERFILE.
user2105103

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

375

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

Помимо других полезных ответов здесь, обратите внимание, что вы можете перезапустить существующий контейнер после его выхода, и ваши изменения все еще там.

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

89
docker psпоказывает только запущенные Docker-контейнеры. docker ps -aпоказывает вам также те, которые вышли - и что вы можете продолжать работать. Фиксация необходима только после каждого запуска, если вы хотите сделать снимок для будущего использования, в противном случае сам контейнер останется для вас, чтобы вы продолжали использовать.
user1278519

2
Вопрос, пожалуйста, поэтому, если я загружаю jenkinsдокер сервера и запускаю его на своем хосте ci, и он выполняет некоторые задания, которые у меня есть, и в результате сервер jenkins записывает на диск некоторые журналы. теперь, если мой сервер (на котором размещен мой докер) перезапущен, и я снова запускаю мой докер jenkins, значит ли это, что я потерял все файлы журнала? если это так, как я могу использовать jenkinsDocker, например, чтобы облегчить мою установку Jenkins на CI?
Jas

2
@Jas Если вы придерживаетесь того же контейнера и не создаете новые, проблем не возникает. В настоящее время Docker имеет политики перезапуска, поэтому вы можете настроить его для перезапуска того же контейнера при перезагрузке компьютера. Я бы также посоветовал вам поместить свой jenkins домой в том, чтобы иметь доступ к нему извне (резервные копии и т. Д.).
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)
Джонни Виллер

128

Существуют следующие способы сохранения данных контейнера:

  1. Объемы докеров

  2. Docker commit

    а) создать контейнер из образа Ubuntu и запустить терминал Bash.

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

    б) Внутри терминала установите скручиваемость

       # apt-get update
       # apt-get install curl
    

    в) Выход из контейнерного терминала

       # exit
    

    d) Запишите идентификатор вашего контейнера, выполнив следующую команду:

       $ docker ps -a
    

    д) сохранить контейнер как новое изображение

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

    е) убедитесь, что вы можете видеть свой новый образ с установленным curl.

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

Нужно ли exitраньше docker commit? Спасибо.
Абхишек Ананд

2
@AbhishekAnand да, потому что с docker runкомандой запуска Баш в контейнере и вы остаетесь там из - за -iи -tопций (интерактивные с TTY). Однако Docker запускается на вашей машине вне контейнера, поэтому после внесения необходимых изменений в контейнер изнутри, чтобы вернуться к оболочке вашей системы, вы должны exit(или Ctrl + D) оболочку контейнера. Также обратите внимание на #и $в ответе, которые указывают различные оболочки, в которые записаны команды.
Эрик

Быстрый вопрос: если я не сделаю коммит, я потерял данные. Ясно. Но когда я меняю конфигурацию nginx, почему она остается обновленной? (не нужно совершать) @Erik
grep

@grep, если у вас есть четкое и воспроизводимое MWE, пожалуйста, задайте новый вопрос о нем, если его еще нет в данном конкретном случае использования.
Эрик

3. с docker stopпоследующим docker start.
карильонатор

59

В дополнение к ответу Unferth рекомендуется создать Dockerfile .

В пустом каталоге создайте файл с именем «Dockerfile» со следующим содержимым.

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

Создайте изображение, используя Dockerfile . Давайте использовать тег, чтобы нам не нужно было запоминать шестнадцатеричный номер изображения.

$ docker build -t iman/ping .

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

$ docker run iman/ping stackoverflow.com

1
Никогда не нужно делать это вручную более одного раза, и это именно то, что нужно. Создайте dockerfile, зафиксируйте и загрузите полученное изображение. Потяните за изображение, идущее вперед.
Брэндон Бертельсен

11

У меня есть гораздо более простой ответ на ваш вопрос, выполните следующие две команды

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

Приведенная выше команда ps -a возвращает список всех контейнеров. Возьмите имя контейнера, который ссылается на имя изображения - 'Ubuntu'. Например 'lightlyxuyzx', docker auto генерирует имена для контейнеров - это если вы не используете опцию --name.

Опции -t и -d важны, созданный контейнер отсоединяется и может быть присоединен, как указано ниже, с опцией -t.

С опцией --name, вы можете назвать свой контейнер в моем случае «mycontainername».

sudo docker exec -ti mycontainername bash

и эта команда поможет вам войти в контейнер с помощью оболочки bash. С этого момента любые изменения, сделанные вами в контейнере, автоматически сохраняются Docker. Например - apt-get install curlвнутри контейнера Вы можете выйти из контейнера без проблем, Docker автоматически сохраняет изменения.

При следующем использовании все, что вам нужно сделать, это запускать эти две команды каждый раз, когда вы хотите работать с этим контейнером.

Эта команда ниже запустит остановленный контейнер:

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 - это imageid предыдущего запущенного контейнера, который я получил с помощью

докер ps -a


4
С Docker 18.09.2 на Ubuntu 18.04 он не работает как есть. Это работает, если я поставлю --nameопцию и перед именем изображения, например:docker run --name mycontainername -t -d ubuntu /bin/bash
Стефан Гурихон


3

Мое предложение состоит в том, чтобы управлять докером с помощью docker compose. Это простой способ управления всеми контейнерами докера для вашего проекта, вы можете отобразить версии и связать различные контейнеры для совместной работы.

Документы очень просты для понимания, лучше, чем документы докеров.

Докер-составить документы

Лучший


3

Выше приведены отличные ответы на заданный вопрос. Возможно, нет необходимости в другом ответе, но все же я хочу высказать свое личное мнение по этой теме в самых простых словах.

Вот несколько пунктов о контейнерах и изображениях, которые помогут нам сделать вывод:

  • Образ докера может быть :
    1. сотворены из-а-данного контейнера-
    2. Исключен
    3. используемый к создать-любое-число-контейнеров
  • Док-контейнер может быть :
    1. сотворено из-ан-изображений
    2. начал
    3. остановился
    4. перезапущен
    5. Исключен
    6. используемый к создать-любое-число-изображений
  • Команда Docker Run делает это :
    1. Загружает изображение или использует кэшированное изображение
    2. Создает новый контейнер из него
    3. Запускает контейнер
  • Когда Dockerfile используется для создания изображения :
    1. Уже хорошо известно, что образ в конечном итоге будет использоваться для запуска док-контейнера.
    2. После выдачи команды docker build закулисный docker создает работающий контейнер с базовой файловой системой и выполняет шаги внутри Dockerfile для настройки этого контейнера в соответствии с потребностями разработчиков.
    3. После того, как контейнер настроен со спецификациями Dockerfile, он будет зафиксирован как образ.
    4. Изображение готовится к рок-н-роллу!

Вывод :

Как мы видим, Docker-контейнер не зависит от Docker-образа.

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

Любая операция, например создание нового каталога, создание файлов, установка инструментов и т. Д., Может выполняться внутри контейнера, когда он работает. Как только контейнер остановлен, он сохраняет все изменения. Остановка и перезапуск контейнера - это как перезагрузка компьютерной системы.

Уже созданный контейнер всегда доступен для перезапуска, но когда мы выдаем docker runкоманду, из образа создается новый контейнер, и, следовательно, он похож на новую компьютерную систему. Изменения, сделанные в старом контейнере - как мы теперь можем понять - недоступны в этом новом контейнере.

Последнее замечание :

Полагаю, теперь очевидно, почему данные кажутся потерянными, но они всегда там, но в другом [старом] контейнере. Итак, обратите внимание на разницу в docker start& docker runcommand и никогда не запутайтесь в них.


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: применение сценария запуска Docker в режиме демона, обеспечивающем локальные записи 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 сценарий будет продолжен только после завершения установки. и это подходящий момент для вызова: commit , предоставляющий текущий идентификатор контейнера, а также имя целевого образа (оно может быть таким же, как в процедуре сборки / запуска , но дополнено тегом локальных целей установки. пример:. docker commit containerID pack/bsp:toolchainedсм. эту ссылку на как получить правильный containerID

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

stage5: в любой момент, когда требуется запустить контейнер с локальной установкой, запустите его с ранее сохраненным образом. пример:docker run -d -t pack/bsp:toolchained


1

блестящий ответ здесь Как продолжить докер который выходит из пользователя kgs

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 используется вместо run, и не на изображении, а на containerid. И вы делаете это после того, как контейнер был запущен.


0

Ни один из ответов не касается смысла этого выбора дизайна. Я думаю, что докер работает таким образом, чтобы предотвратить эти 2 ошибки:

  • Повторный перезапуск
  • Частичная ошибка
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.