容器退出时我丢失了数据


394

尽管有Docker的Interactive教程常见问题解答,但当容器退出时,我仍然丢失了数据。

我已经按照以下说明安装了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用户的重要

正如@ mohammed-noureldin和其他人所说,实际上这不是退出容器。每次它只是创建一个新的容器。


10
那不能被称为“ 容器退出 ”,您只是在创建一个新的容器,使用退出词会造成很多混乱(因此我也感到困惑)。
Mohammed Noureldin

1
@MohammedNoureldin,您是对的,退出是不正确的,但这正是您,我和其他人的想法。因此,这是一个更好的疑问词,您的编辑使问题成为答案!新的搜索者在这里找不到!
iman

在我刚接触Docker的那一刻,我认为实际上是由于您的问题,我发现该地址简直是错误的。新标题已经过审核并被接受,我不明白为什么有人要坚持一个错误的标题,这是您的疑问和决定。
Mohammed Noureldin

3
我同意@MohammedNoureldin。特定标题,示例和可接受的答案的组合不会帮助将来的读者,尤其是初学者理解Docker。我建议保留标题和原始问题,因为初学者肯定会搜索类似的内容。但是,为什么不在撰写本文时添加一些描述您的误解的内容。这将有助于弄清楚事情。这就是我们这里的文化...不是吗?:-)
tgogos

2
我遇到了这个问题...每次退出时都必须启动容器而不运行它...运行图像gane新建一个容器,这将有助于docker启动<container id>
docker

Answers:


399

您需要提交对容器所做的更改,然后运行它。尝试这个:

sudo docker pull ubuntu

sudo docker run ubuntu apt-get install -y ping

然后使用以下命令获取容器ID:

sudo docker ps -l

提交对容器的更改:

sudo docker commit <container_id> iman/ping 

然后运行容器:

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

这应该工作。


9
所以我应该在每次运行后使用commit来保存数据。
iman 2013年

5
仅当您在容器中进行更改(例如安装新工具或数据)时才应使用Commit,以便保存这些更改,并且下次当您从该映像运行新容器时,它将从上次保存或重新保存开始提交,保留您的数据。
2013年

7
@Unferth如果我想继续提交更改怎么办?到目前为止,它使用创建了更多图像<none>。如何继续将提交追加到现有映像的顶部?
Marconi 2014年

62
逐步提交更改不是“ docker way”。使用DOCKERFILE。
user2105103 2015年

23
您将如何在容器内提交?考虑以下情形:1)我正在像这样运行容器:docker run -i -t myimage / bin / bash 2)我进行了一些更改3)我无法在容器内提交,因此当我退出容器时,我将失去我的所有数据,而没有机会进行我之前的更改
qgicup 2015年

374

当您docker run用来启动容器时,它实际上根据您指定的图像创建一个新的容器

除了此处的其他有用答案外,请注意,您可以在现有容器退出后重新启动,并且所做的更改仍然存在。

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

88
docker ps显示仅运行docker容器。 docker ps -a还向您显示已退出的-您可以继续运行。仅在每次运行后才需要提交提交(如果要在此处创建快照以供将来使用),否则容器本身会一直存在,以供您继续使用。
user1278519 2014年

2
请问问题,所以如果我下载jenkins服务器docker并在ci主机上运行它,并且它运行了我拥有的一些作业,结果jenkins服务器将一些日志写到磁盘上。现在,如果我的服务器(托管我的Docker的服务器)重新启动,然后再次启动我的jenkins docker,这是否意味着我丢失了所有日志文件?如果是这样的话,我怎么可能使用jenkinsdocker来简化我在CI上的jenkins安装?
2015年

2
@Jas如果坚持使用同一容器而不创建新容器,则没有问题。如今,Docker具有重启策略,因此您可以将其配置为在机器重启时重启同一容器。我还建议您将jenkins放在一个卷中,以便可以从外部(备份等)访问它。
ZeissS 2015年

7
这是一种方便的方法,可在您退出后从容器中复制文件:docker cp $(docker ps -alq):/path/to/file .
Josh Habdas 2015年

3
您还可以启动并附加其名称的容器。(例如 docker run -it --name my_debian debian及之后docker start my_debian && docker attach my_debian
Johnny Willer

127

有以下几种方法来保存容器数据:

  1. Docker卷

  2. Docker提交

    a)从ubuntu映像创建容器并运行bash终端。

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

    b)在终端内安装卷发

       # apt-get update
       # apt-get install curl
    

    c)退出集装箱码头

       # exit
    

    d)通过执行以下命令记录您的容器ID:

       $ docker ps -a
    

    e)将容器另存为新映像

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

    f)确认您可以看到安装了curl的新图像。

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

有必要exit之前docker commit吗?谢谢。
Abhishek Anand

2
@AbhishekAnand是的,因为使用docker run命令您在容器中运行bash,并且由于-i-t选项(与TTY交互)而停留在该容器中。但是,Docker在容器外部的机器上运行,因此,从内部对容器进行必要的更改后,要返回系统的外壳,您必须exit(或按Ctrl + D)容器的外壳。还要注意答案中的#$,它们指示要写入命令的不同shell。
Erik '18

快速提问:如果我不提交,则会丢失数据。很明显。但是,当我更改nginx配置时,为什么仍保持更新状态?(无需提交)@Erik
grep

@grep如果您有一个清晰且可复制的MWE,请针对此特定问题提出新的问题,如果尚无此问题。
Erik

3. docker stop其次docker start
carillonator

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'。docker auto为容器生成名称,例如-'lightlyxuyzx',也就是说,如果您不使用--name选项。

-t和-d选项很重要,已创建的容器已分离,可以使用-t选项重新附加,如下所示。

使用--name选项,可以在我的情况下为“ mycontainername”命名容器。

sudo docker exec -ti mycontainername bash

以上命令可以帮助您使用bash shell登录到容器。从这一点开始,您在容器中所做的任何更改都会被docker自动保存。例如 -apt-get install curl在容器内部您可以退出容器而没有任何问题,docker auto会保存更改。

在下一个用法中,您要做的就是,每次要使用此容器时都运行这两个命令。

以下命令将启动已停止的容器:

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
在Ubuntu 18.04上使用Docker 18.09.2时,它无法按原样工作。它的工作原理,如果我把--name和期权图像名称之前,像这样:docker run --name mycontainername -t -d ubuntu /bin/bash
斯特凡纳·古里科


3

我的建议是使用docker compose管理docker。这是管理项目的所有Docker容器的简便方法,您可以映射版本并链接不同的容器以一起工作。

这些文档很容易理解,比docker的文档更好。

Docker撰写的文档

最好


3

上面确实有很好的答案。可能不需要其他答案,但我仍然想以最简单的方式对这个话题发表个人看法。

以下是有关容器和图像的一些要点,它们将帮助我们得出结论:

  • 泊坞窗映像可以是
    1. 从给定的容器创建
    2. 已删除
    3. 用于创建任何数量的容器
  • 泊坞窗容器可以是
    1. 从图像创建
    2. 开始了
    3. 停了
    4. 重新开始
    5. 已删除
    6. 用于创建任意数量的图像
  • docker run命令执行以下操作
    1. 下载图像或使用缓存的图像
    2. 用它创建一个新的容器
    3. 启动容器
  • 当使用Dockerfile创建映像时
    1. 众所周知,该映像最终将用于运行docker容器。
    2. 发出docker build命令后,docker后台创建了一个具有基本文件系统的运行容器,并按照Dockerfile中的步骤按照开发人员的需要配置该容器。
    3. 在为容器配置了Dockerfile的规范后,它将被提交为映像。
    4. 图像准备好摇摆!

结论

如我们所见,Docker容器独立于Docker映像。

可以重新启动容器,前提是该容器的唯一ID [用于docker ps --all获取ID]

容器运行时,可以在容器内进行任何操作,例如创建新目录,创建文件,安装工具等。容器停止后,它将保留所有更改。容器停止和重新启动就像重新启动计算机系统一样。

已经创建的容器始终可用于重新启动,但是当我们发出 docker run命令时,将在映像之外创建一个新容器,因此它就像一个新的计算机系统。我们现在可以理解,在旧容器内进行的更改在此新容器中不可用。

最后的笔记

我想现在很明显为什么数据似乎丢失了,但它始终存在..但是在另一个[旧]容器中。因此,请充分注意docker startdocker run命令之间的差异,并且不要混淆它们。


1

类似的问题(而且Dockerfile不能单独解决)将我带到了此页面。

阶段0: 所有人都希望Dockerfile可以解决它:直到--dns和--dns-search出现在Dockerfile支持中-无法将基于Intranet的资源集成到其中。

阶段1: 使用Dockerfile构建映像之后(顺便说一句,严重的是Dockerfile必须位于当前文件夹中),并通过运行docker run脚本来部署基于Intranet的映像。例: 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 run脚本,以提供本地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,提供当前容器ID以及目标映像名称(它可能与构建/运行过程中的相同,但附加了本地安装目的标签。例如:docker commit containerID pack/bsp:toolchained。参见此链接如何获得正确的containerID

阶段4:容器已使用本地安装进行了更新,并且已提交到新分配的映像中(已添加了目的标签的映像)。现在可以安全地停止容器运行。例:docker stop packbsp-cont

stage5:需要运行带有本地安装的容器的任何时刻,请使用先前保存的映像启动它。例:docker run -d -t pack/bsp:toolchained


1

一个绝妙的回答: 如何继续 从用户kgs 退出的 docker

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

没有任何答案解决此设计选择的重点。我认为docker通过这种方式来防止这2个错误:

  • 反复重启
  • 部分错误
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.