【问题标题】:How to deal with persistent storage (e.g. databases) in Docker如何在 Docker 中处理持久存储(例如数据库)
【发布时间】:2013-09-01 01:26:42
【问题描述】:

人们如何处理 Docker 容器的持久存储?

我目前正在使用这种方法:构建图像,例如对于 PostgreSQL,然后用

启动容器
docker run --volumes-from c0dbc34fd631 -d app_name/postgres

恕我直言,这有一个缺点,我绝不能(意外)删除容器“c0dbc34fd631”。

另一个想法是将主机卷“-v”挂载到容器中,但是,容器内的 userid 不一定与主机中的 userid 匹配,然后权限可能会混乱。

注意:除了--volumes-from 'cryptic_id',您还可以使用--volumes-from my-data-container,其中my-data-container 是您分配给纯数据容器的名称,例如docker run --name my-data-container ...(查看已接受的答案)

【问题讨论】:

  • 对不起,我用错了,我的意思是说:我未来所有来自该图像的实例都依赖于该容器。如果我不小心删除了那个容器,我就有麻烦了。
  • @AntonStrogonoff - 是的,措辞错误 - 我的意思是:我需要确保我永远不会删除那个(可能的)旧容器,因为这样“持久”存储的引用也会走了
  • 应该是--name。你有-name

标签: docker docker-container


【解决方案1】:

Docker 1.9.0 及以上版本

使用volume API

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

这意味着必须放弃纯数据容器模式以支持新卷。

实际上,volume API 只是实现数据容器模式的更好方法。

如果您使用-v volume_name:/container/fs/path 创建一个容器,Docker 会自动为您创建一个命名卷,它可以:

  1. 通过docker volume ls列出
  2. 通过docker volume inspect volume_name识别
  3. 作为普通目录备份
  4. 通过--volumes-from 连接像以前一样备份

新的卷 API 添加了一个有用的命令,可让您识别悬空卷:

docker volume ls -f dangling=true

然后通过它的名字删除它:

docker volume rm <volume name>

正如@mpugach 在 cmets 中强调的那样,您可以用一个漂亮的单线摆脱所有悬空的卷:

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

Docker 1.8.x 及以下版本

似乎最适合生产的方法是使用仅数据容器

仅数据容器在准系统映像上运行,实际上除了暴露数据卷之外什么都不做。

然后您可以运行任何其他容器来访问数据容器卷:

docker run --volumes-from data-container some-other-container command-to-execute
  • Here你可以很好地了解如何排列不同的容器。
  • Here 可以很好地了解卷的工作原理。

this blog post 中有一个很好的描述所谓的container as volume pattern,它阐明了data only containers的要点。

Docker documentation has now the DEFINITIVE description of the container as volume/s pattern.

以下是 Docker 1.8.x 及以下版本的备份/恢复过程。

备份:

sudo docker run --rm --volumes-from DATA -v $(pwd):/backup busybox tar cvf /backup/backup.tar /data
  • --rm:容器退出时移除容器
  • --volumes-from DATA:附加到 DATA 容器共享的卷
  • -v $(pwd):/backup:绑定挂载当前目录到容器中;将 tar 文件写入
  • busybox:一个小而简单的图像 - 适合快速维护
  • tar cvf /backup/backup.tar /data:为/data目录下的所有文件创建一个未压缩的tar文件

恢复:

# 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

这是一个很好的article from the excellent Brian Goff,解释了为什么对容器和数据容器使用相同的图像是好的。

【讨论】:

  • 这是满足不同需求的不同工具。 --volumes-from让你共享磁盘空间--link让你共享服务。
  • 在作品中还有另一个项目专门针对这种事情,也许将它添加到这个答案作为观看的参考? github.com/ClusterHQ/flocker
  • 数据容器没有任何意义,真是个坏主意!容器仅在进程在其中运行时才有意义,否则它只是一个主机文件系统。您可以使用 -v 挂载一个卷,这是唯一也是最好的选择。您可以控制您使用的文件系统和物理磁盘。
  • 是的,从 Docker 1.9 开始,使用 Volumes API (docker volume create --name mydata) 创建命名卷优于数据卷容器。 Docker 的人自己建议数据卷容器“are no longer considered a recommended pattern”、“named volumes should be able to replace data-only volumes in most (if not all) cases”和“no reason I can see to use data-only containers”。
  • @coding,我很伤心,你很伤心,部分原因是你延迟了 3 年来判断答案,部分原因是答案在历史上基本上是正确的。如果您有任何建议,请随时发表评论,以便我整合答案并帮助人们不要难过
【解决方案2】:

Docker v1.0中,绑定宿主机上的文件或目录的挂载可以通过给定的命令来完成:

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

上述卷可以用作运行 Docker 的主机上的持久存储。

【讨论】:

  • 这应该是推荐的答案,因为它远没有目前拥有更多投票的卷容器方法复杂
  • 我希望在使用此卷挂载命令时有一个标志来指定 host-uid : container-uid 和 host-gid : container-gid 映射。
【解决方案3】:

从 Docker Compose 1.6 开始,现在改进了 Docker Compose 中对数据卷的支持。以下 compose 文件将创建一个数据映像,该映像将在父容器的重新启动(甚至删除)之间持续存在:

这里是博客公告:Compose 1.6: New Compose file for defining networks and volumes

这是一个编写文件的示例:

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:

据我所知:这将创建一个数据卷容器 (db_data),它将在重新启动之间持续存在。

如果您运行:docker volume ls,您应该会看到您的卷:

local               mypthonapp_db-data
...

您可以获得有关数据量的更多详细信息:

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

一些测试:

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

注意事项:

  • 您还可以在volumes 块中指定各种驱动程序。例如,您可以为 db_data 指定 Flocker 驱动程序:

    volumes:
      db-data:
        driver: flocker
    
  • 随着他们改进 Docker Swarm 和 Docker Compose 之间的集成(并可能开始将 Flocker 集成到 Docker 生态系统中(我听说 Docker 已经收购了 Flocker),我认为这种方法应该会变得越来越强大。

免责声明:这种方法很有前途,我正在开发环境中成功使用它。我会担心在生产中使用它!

【讨论】:

【解决方案4】:

如果从所选答案的更新 5 中不清楚,从 Docker 1.9 开始,您可以创建无需与特定容器关联即可存在的卷,从而使“仅数据容器”模式过时。

Data-only containers obsolete with docker 1.9.0? #17798

我认为 Docker 维护人员意识到纯数据容器模式有点设计味道,因此决定将卷作为一个单独的实体,无需关联容器即可存在。

【讨论】:

    【解决方案5】:

    虽然这仍然是 Docker that needs some work 的一部分,但您应该将卷放在带有 the VOLUME instruction 的 Dockerfile 中,这样您就不需要从另一个容器复制卷。

    这将减少您的容器相互依赖,并且您不必担心删除一个容器会影响另一个容器。

    【讨论】:

    • 另一方面的论点是“仅数据”容器最终成为对数据卷的最后一个引用(一旦使用 @987654324 删除引用该卷的最后一个容器,Docker 就会销毁数据卷@)
    • 这个来自 Docker 的官方指南另有建议:docs.docker.com/userguide/dockervolumes/…“数据卷旨在持久化数据,独立于容器的生命周期。因此,当您删除容器时,Docker 永远不会自动删除卷,也不会自动删除容器不再引用的“垃圾收集”卷。”
    【解决方案6】:

    使用 Docker Compose 时,只需附加一个命名卷,例如:

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

    【讨论】:

      【解决方案7】:

      @tommasop 的回答很好,并解释了使用纯数据容器的一些机制。但是作为一个最初认为数据容器很傻的人,当一个人可以将一个卷绑定到主机时(正如其他几个答案所建议的那样),但现在意识到实际上只有数据的容器非常整洁,我可以建议我自己的关于此主题的博文:Why Docker Data Containers (Volumes!) are Good

      另请参阅:my answer 问题“What is the (best) way to manage permissions for Docker shared volumes?”,了解如何使用数据容器来避免权限和与主机的 uid/gid 映射等问题的示例。

      解决 OP 最初的担忧之一:不得删除数据容器。即使删除了数据容器,只要任何容器引用了该卷,即任何通过--volumes-from 挂载该卷的容器,数据本身也不会丢失。因此,除非所有相关的容器都被停止和删除(可以认为这相当于意外的rm -fr /),否则数据是安全的。您始终可以通过 --volumes-from 任何引用该卷的容器来重新创建数据容器。

      一如既往,请做好备份!

      更新:Docker 现在拥有可以独立于容器进行管理的卷,这进一步使其更易于管理。

      【讨论】:

        【解决方案8】:

        根据您的需要,管理持久数据有多个级别:

        • 将其存储在您的主机上
          • 使用标志-v host-path:container-path 将容器目录数据持久保存到主机目录。
          • 通过运行挂载到同一目录的备份/恢复容器(例如 tutumcloud/dockup)来进行备份/恢复。
        • 创建一个数据容器并将其卷安装到您的应用程序容器中
          • 创建一个导出数据卷的容器,使用--volumes-from 将该数据装载到您的应用程序容器中。
          • 备份/恢复与上述解决方案相同。
        • 使用支持外部/第三方服务的 Docker 卷插件
          • Docker 卷插件允许您的数据源来自任何地方 - NFS、AWS(S3、EFS 和 EBS)
          • 根据插件/服务,您可以将单个或多个容器附加到单个卷。
          • 根据服务的不同,备份/恢复可能会自动为您服务。
          • 虽然手动执行此操作可能很麻烦,但某些编排解决方案(例如 Rancher)已内置且易于使用。
          • Convoy 是手动执行此操作的最简单解决方案。

        【讨论】:

          【解决方案9】:

          如果你想移动你的卷,你也应该看看 Flocker

          来自自述文件:

          Flocker 是一个数据卷管理器和多主机 Docker 集群管理工具。有了它,您可以利用 Linux 上 ZFS 的强大功能,使用用于无状态应用程序的相同工具来控制数据。

          这意味着您可以在 Docker 中运行您的数据库、队列和键值存储,并像您应用程序的其余部分一样轻松地移动它们。

          【讨论】:

          • 谢谢约翰。我在 ClusterHQ 工作,我只想指出,我们已经超越了仅基于 ZFS 的存储。您现在可以将 Flocker 与 Amazon EBS 或 Google Persistent Disk 等存储结合使用。以下是存储选项的完整列表:docs.clusterhq.com/en/latest/supported/…
          • Flocker 已停止使用,不应使用portworx.com/…
          【解决方案10】:

          这取决于您的场景(这并不适合生产环境),但这是一种方法:

          Creating a MySQL Docker Container

          它的要点是使用主机上的目录进行数据持久化。

          【讨论】:

          • 谢谢 Ben,但是 - 我可以通过这种方法看到的问题之一:文件系统资源(目录、文件)将由 docker/lxc 容器(来宾)中的 uid 拥有 -一个可能与主机上的 uid 冲突的...
          • 我认为你很安全,因为它是由 root 运行的,但我同意这是一个 hack - 充其量适合本地开发/临时集成测试。这绝对是我希望看到更多模式/思维出现的领域。您应该查看/将此问题发布到 docker-dev google 组
          • 本,感谢您的解决方案!不过我不会称它为 hack,它似乎比 container as volume 可靠得多。如果仅使用容器中的数据,您是否看到任何缺点? (在这种情况下,UID 无关紧要)
          【解决方案11】:

          我最近写了一篇关于潜在解决方案和演示该技术的应用程序的文章。我发现它在开发和生产过程中非常有效。希望它能帮助或激发一些想法。

          回购:https://github.com/LevInteractive/docker-nodejs-example
          文章:http://lev-interactive.com/2015/03/30/docker-load-balanced-mongodb-persistence/

          【讨论】:

            【解决方案12】:

            我只是在主机上使用预定义的目录来为 PostgreSQL 保存数据。此外,通过这种方式可以轻松地将现有的 PostgreSQL 安装迁移到 Docker 容器:https://crondev.com/persistent-postgresql-inside-docker/

            【讨论】:

              【解决方案13】:

              我的解决方案是使用新的docker cp,它现在能够从容器中复制数据,无论它是否正在运行,并将主机卷共享到数据库应用程序正在创建的完全相同的位置它在容器内的数据库文件。这种双重解决方案在没有纯数据容器的情况下工作,直接来自原始数据库容器。

              所以我的 systemd 初始化脚本负责将数据库备份到主机上的存档中。我在文件名中放置了一个时间戳,以从不重写文件。

              它在 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'
              

              它也在 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'
              

              另外,我将主机中的一个文件夹作为一个卷公开到存储数据库的完全相同的位置:

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

              它在我的虚拟机上运行良好(我为自己构建了一个 LEMP 堆栈):https://github.com/DJviolin/LEMP

              但我只是不知道当你的生活实际上依赖于它时它是否是一个“防弹”解决方案(例如,在任何可能的毫秒内进行交易的网上商店)?

              在这个 Docker 官方主题视频的 20 分 20 秒时,演示者对数据库做了同样的事情:

              Getting Started with Docker

              “对于数据库,我们有一个卷,因此我们可以确保在数据库上下波动时,当数据库容器停止时,我们不会丢失数据。” p>

              【讨论】:

              • 你所说的"是什么意思...使用..."?而“...任何可能的毫秒内的事务”?
              【解决方案14】:

              使用来自 Kubernetes 的 Persistent Volume Claim (PVC),它是一个 Docker 容器管理和调度工具:

              Persistent Volumes

              为此目的使用 Kubernetes 的优势在于:

              • 您可以使用任何存储,如 NFS 或其他存储,即使节点关闭,也不需要存储。
              • 此外,此类卷中的数据可以配置为即使在容器本身被销毁后仍保留 - 以便在必要时由另一个容器回收。

              【讨论】:

                【解决方案15】:

                要保存或存储数据库数据,请确保您的 docker-compose.yml 看起来像 如果你想使用 Dockerfile

                version: '3.1'
                
                services:
                  php:
                    build:
                      context: .
                      dockerfile: Dockerfile
                    ports:
                      - 80:80
                    volumes:
                      - ./src:/var/www/html/
                  db:
                    image: mysql
                    command: --default-authentication-plugin=mysql_native_password
                    restart: always
                    environment:
                      MYSQL_ROOT_PASSWORD: example
                    volumes:
                      - mysql-data:/var/lib/mysql
                
                  adminer:
                    image: adminer
                    restart: always
                    ports:
                      - 8080:8080
                volumes:
                  mysql-data:
                

                你的 docker-compose.yml 看起来像 如果你想使用你的镜像而不是 Dockerfile

                version: '3.1'   
                
                services:
                  php:
                    image: php:7.4-apache
                    ports:
                      - 80:80
                    volumes:
                      - ./src:/var/www/html/
                  db:
                    image: mysql
                    command: --default-authentication-plugin=mysql_native_password
                    restart: always
                    environment:
                      MYSQL_ROOT_PASSWORD: example
                    volumes:
                      - mysql-data:/var/lib/mysql
                
                  adminer:
                    image: adminer
                    restart: always
                    ports:
                      - 8080:8080
                volumes:
                

                如果你想存储或保存mysql的数据,那么 一定要记得在你的 docker-compose.yml 中添加两行

                volumes:
                  - mysql-data:/var/lib/mysql
                

                volumes:
                  mysql-data:
                

                之后使用这个命令

                docker-compose up -d
                

                现在您的数据将永久保存,即使使用此命令也不会被删除

                docker-compose down
                

                额外:- 但如果你想删除所有数据,那么你将使用

                docker-compose down -v
                

                另外你可以使用这个命令检查你的数据库数据列表

                docker volume ls
                
                DRIVER              VOLUME NAME
                local               35c819179d883cf8a4355ae2ce391844fcaa534cb71dc9a3fd5c6a4ed862b0d4
                local               133db2cc48919575fc35457d104cb126b1e7eb3792b8e69249c1cfd20826aac4
                local               483d7b8fe09d9e96b483295c6e7e4a9d58443b2321e0862818159ba8cf0e1d39
                local               725aa19ad0e864688788576c5f46e1f62dfc8cdf154f243d68fa186da04bc5ec
                local               de265ce8fc271fc0ae49850650f9d3bf0492b6f58162698c26fce35694e6231c
                local               phphelloworld_mysql-data
                

                【讨论】:

                  猜你喜欢
                  • 2017-10-19
                  • 1970-01-01
                  • 2018-05-20
                  • 1970-01-01
                  • 2016-04-22
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  相关资源
                  最近更新 更多