【问题标题】:I lose my data when the container exits容器退出时我丢失了数据
【发布时间】:2013-10-25 08:36:30
【问题描述】:

尽管有 Docker 的 Interactive tutorialfaq 我在容器退出时丢失了我的数据。

我已经安装了 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 和其他人所说,实际上这不是 容器退出。每次它只是创建一个新容器。

【问题讨论】:

  • 这不能称为“容器退出”,你只是在创建一个新容器,使用退出词会混淆很多(我也因此感到困惑)。
  • @MohammedNoureldin,你是对的,退出是不正确的,但这正是你,我和其他人的想法。所以这是一个更好的词,您的编辑使问题成为答案!新的搜索者不会在这里找到!
  • 在我刚开始使用 Docker 时,我认为实际上由于您的问题,我发现该地址完全是错误的。新标题已经审核通过,我不明白为什么有人坚持错误的标题,这是你的问题,你的决定。
  • 我同意@MohammedNoureldin。具体标题、示例和接受的答案的组合并不能帮助未来的读者,尤其是初学者理解Docker。我建议保留标题和原始问题,因为初学者肯定会搜索这样的内容。但是,你为什么不在你写这篇文章的时候添加一些描述你的误解的东西。这将有助于使事情变得清晰。这就是我们在 SO 的文化……不是吗? :-)
  • 我遇到了这个问题......每次你退出你都必须启动你的容器而不是运行它......运行一个图像 agane 创建一个新容器这将有助于 docker start docker attach

标签: docker


【解决方案1】:

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

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

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

【讨论】:

  • docker ps 显示您只运行 docker 容器。 docker ps -a 还向您显示已经退出的那些——并且您可以继续运行。如果您想在此处制作快照以供将来使用,则仅在每次运行后才需要提交,否则容器本身将保留供您继续使用。
  • 请提问,所以如果我下载了一个jenkins 服务器 docker 并在我的 ci 主机上运行它,它运行了我的一些作业,结果 jenkins 服务器将一些日志写入磁盘。现在,如果我的服务器(托管我的 docker)重新启动并且我再次启动我的 jenkins docker,这是否意味着我丢失了所有日志文件?如果是这样,我怎么可能使用jenkins docker 来简化我在 CI 上的 jenkins 安装?
  • @Jas 如果您坚持使用同一个容器而不创建新容器,则没有问题。 Docker 现在有重启策略,所以你可以配置它在机器重启时重启同一个容器。我还建议您将 jenkins home 放入一个卷中,以便能够从外部访问它(备份等)。
  • 退出容器后,这是一种将文件复制出容器的便捷方法:docker cp $(docker ps -alq):/path/to/file .
  • 您也可以通过容器名称启动和附加容器。 (例如docker run -it --name my_debian debiandocker start my_debian && docker attach my_debian之后)
【解决方案2】:

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

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

这应该可行。

【讨论】:

  • 所以我应该在每次 run 之后使用 commit 来保存数据。
  • 仅当您在容器中进行更改(如安装新工具或数据)时才应使用提交,以便保存这些更改,并且下次从该映像运行新容器时,它将从上次保存或提交的点开始,保留您的数据。
  • @Unferth 如果我想继续提交更改怎么办?到目前为止,它使用&lt;none&gt; 创建了更多图像。如何继续将提交附加到现有图像之上?
  • 增量提交更改不是“docker 方式”。使用 DOCKERFILE。
  • 如何从容器中提交?考虑以下场景:1)我正在像这样运行容器: docker run -i -t myimage /bin/bash 2)我做了一些更改 3)我无法从容器内提交,所以当我退出容器时,我将丢失我的所有数据,而没有机会提交我以前的更改
【解决方案3】:

对于所提出的问题,上面确实有很好的答案。可能不需要其他答案,但我仍然想用最简单的语言表达我对这个话题的个人看法。

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

  • 泊坞窗图像可以是
    1. 从给定容器创建
    2. 已删除
    3. 用于创建任意数量的容器
  • 一个 docker 容器可以是
    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 命令的区别,不要对它们感到困惑。

【讨论】:

    【解决方案4】:

    持久化容器数据有以下几种方式:

    1. Docker 卷

    2. Docker 提交

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

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

      b) 在终端内安装 curl

         # 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之前吗?谢谢。
    • @AbhishekAnand 是的,因为使用 docker run 命令,您在容器中运行 bash,并且由于 -i-t 选项(与 TTY 交互)而留在容器中。但是,Docker 在容器外部的机器上运行,因此在从内部对容器进行必要的更改后,要返回系统的 shell,您必须 exit(或 Ctrl+D)容器的 shell。还要注意答案中的#$,它们表示命令写入的不同shell。
    • 快速提问:如果我不提交,我就会丢失数据。很明显。但是当我更改 nginx 配置时,为什么它仍然更新? (无需提交)@Erik
    • @grep 如果您有一个清晰且可重复的 MWE,请询问有关它的新问题,如果还没有关于此特定用例的问题。
    • 3. docker stop 后跟 docker start
    【解决方案5】:

    除了Unferth's answer,建议创建Dockerfile

    在一个空目录中,创建一个名为“Dockerfile”的文件,其内容如下。

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

    使用 Dockerfile 创建映像。让我们使用一个标签,这样我们就不需要记住十六进制的图像编号了。

    $ docker build -t iman/ping .
    

    然后在容器中运行映像

    $ docker run iman/ping stackoverflow.com
    

    【讨论】:

    • 永远不必多次手动操作,这正是 docker 的重点。创建一个 dockerfile,提交并上传生成的图像。向前拉所述图像。
    【解决方案6】:

    我对你的问题有一个更简单的答案,运行以下两个命令

    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 我使用

    获得的

    docker ps -a

    【讨论】:

    • 对于 Ubuntu 18.04 上的 Docker 18.09.2,它不能按原样工作。如果我将--name 和选项放在图像名称之前,它会起作用,如下所示:docker run --name mycontainername -t -d ubuntu /bin/bash
    【解决方案7】:

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

    文档非常简单易懂,比docker的文档好。

    Docker-Compose Docs

    最好的

    【讨论】:

      【解决方案8】:

      来自用户 kgs 的精彩回答 How to continue a docker which is exited

      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 上。并且在容器启动后执行。

      【讨论】:

        【解决方案9】:

        类似的问题(单靠 Dockerfile 无法解决)把我带到了这个页面。

        第 0 阶段: 总之,希望 Dockerfile 可以修复它:直到 --dns 和 --dns-search 出现在 Dockerfile 支持中 - 没有办法将基于 Intranet 的资源集成到其中。

        第 1 阶段: 在使用 Dockerfile 构建映像之后(顺便说一下,这是一个严重的故障 Dockerfile 必须位于 current 文件夹中),通过运行 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 以及目标映像名称(可能与 build/run 过程中的相同,但附加带有本地安装目的标签。例如:docker commit containerID pack/bsp:toolchained。 请参阅此链接了解如何获得正确的containerID

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

        stage5:在本地安装的容器需要运行的任何时候,使用之前保存的图像启动它。 例如:docker run -d -t pack/bsp:toolchained

        【讨论】:

          【解决方案10】:

          如果您想将数据持久保存在容器中,您可能需要查看 docker 卷。访问https://docs.docker.com/engine/tutorials/dockervolumes/。 docker 文档是一个很好的起点

          【讨论】:

            【解决方案11】:

            没有一个答案能解决这个设计选择的要点。我认为 docker 以这种方式工作是为了防止这两个错误:

            • 反复重启
            • 部分错误

            【讨论】:

              猜你喜欢
              • 2022-11-30
              • 1970-01-01
              • 2011-12-20
              • 2014-10-03
              • 2011-07-15
              • 2022-01-25
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多