首页 文章

如何处理Docker中的持久存储(例如数据库)

提问于
浏览
872

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

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

docker run --volumes-from c0dbc34fd631 -d app_name/postgres

恕我直言,有缺点,我不能(偶然)删除容器“c0dbc34fd631” .

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

注意:您也可以使用 --volumes-from my-data-container 代替 --volumes-from 'cryptic_id' ,其中 my-data-container 是您分配给仅数据容器的名称,例如 docker run --name my-data-container ... (见接受的答案)

14 回答

  • 3

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

    Data-only containers obsolete with docker 1.9.0? #17798 .

    我认为Docker维护者意识到仅数据容器模式有点像设计气味,并决定使卷成为一个独立的实体,可以在没有相关容器的情况下存在 .

  • 909

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

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

  • 62

    使用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:
    
  • 26

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

    Creating a MySQL Docker Container

    它的要点是使用主机上的目录来实现数据持久性 .

  • 16

    Docker 1.9.0及以上版本

    使用volume API

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

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

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

    如果你用_137887创建一个容器,Docker会自动为你创建一个命名卷,它可以:

    • 通过 docker volume ls 列出

    • 通过 docker volume inspect volume_name 确定

    • 备份为普通目录

    • 通过 --volumes-from 连接像以前一样备份

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

    docker volume ls -f dangling=true
    

    然后通过其名称删除它:

    docker volume rm <volume name>
    

    正如@mpugach在评论中强调的那样,你可以用一个漂亮的单行代码摆脱所有悬空卷:

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

    Docker 1.8.x及以下版本

    似乎最适合 生产环境 的方法是使用 data only container .

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

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

    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及更低版本的备份/恢复过程 .

    BACKUP:

    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:bind将当前目录挂载到容器中;写tar文件到

    • busybox:一个简单的小图像 - 适合快速维护

    • tar cvf /backup/backup.tar / data:创建/ data目录中所有文件的未压缩tar文件

    RESTORE:

    # 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解释为什么对容器和数据容器使用相同的图像是好的 .

  • 13

    我的解决方案是使用新的 docker cp ,它现在能够从容器中复制数据,无论它是否正在运行,并将主机卷共享到数据库应用程序在其中创建数据库文件的完全相同的位置 . 容器 . 这个双解决方案直接从原始数据库容器中运行,没有仅数据容器 .

    所以我的systemd init脚本正在将数据库备份到主机上的存档中 . 我在文件名中放置了一个时间戳,以便永远不会重写文件 .

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

    它在我的VM上工作得很好(我为自己构建了一个LEMP堆栈):https://github.com/DJviolin/LEMP

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

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

    Getting Started with Docker>“对于数据库,我们有一个卷,所以我们可以确保,当数据库上下移动时,我们不会在数据库容器停止时丢失数据 . ”

  • 10

    使用来自Kubernetes的持久卷声明(PVC),这是一个Docker容器管理和调度工具:

    Persistent Volumes

    为此目的使用Kubernetes的优点是:

    • 您可以使用任何存储,如NFS或其他存储,即使节点关闭,也无需存储 .

    • 此外,即使在容器本身被销毁之后,也可以将这些卷中的数据配置为保留 - 以便在必要时由另一个容器回收它 .

  • 9

    @ tommasop的答案很好,并解释了使用仅数据容器的一些机制 . 但是,有人最初认为数据容器是愚蠢的,当一个人可以将卷装入主机(如其他几个答案所示),但现在意识到实际上只有数据的容器非常整洁,我可以建议我自己关于此主题的博客文章:Why Docker Data Containers (Volumes!) are Good

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

    解决OP的一个原始问题:不得删除数据容器 . 即使删除了数据容器,只要任何容器具有对该卷的引用,即通过 --volumes-from 装入卷的任何容器,数据本身都不会丢失 . 因此,除非停止并删除所有相关容器(可以认为这相当于意外 rm -fr / ),否则数据是安全的 . 您始终可以通过执行 --volumes-from 任何具有该卷引用的容器来重新创建数据容器 .

    一如既往,尽管做备份!

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

  • 8

    从Docker Compose 1.6开始,Docker 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).
    

    Notes:

    • 您还可以在 volumes 块中指定各种驱动程序 . 例如,您可以为db_data指定Flocker驱动程序:
    volumes:
      db-data:
        driver: flocker
    
    • 由于他们改进了Docker Swarm和Docker Compose之间的集成(并且可能开始将Flocker集成到Docker生态系统中(我听说Docker已经购买了Flocker的传闻),我认为这种方法应该变得越来越强大 .

    Disclaimer: 这种方法很有前景,我在开发环境中成功使用它 . 我还是很担心在 生产环境 中使用它!

  • 6

    Docker release v1.0 中,可以通过给定命令在主机上绑定文件或目录的安装:

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

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

  • 5

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

    来自README:

    Flocker是一个数据卷管理器和多主机Docker集群管理工具 . 有了它,您可以使用与无状态应用程序相同的工具来控制数据,方法是利用Linux上ZFS的强大功能 . 这意味着您可以在Docker中运行数据库,队列和键值存储,并像应用程序的其余部分一样轻松移动它们 .

  • 1

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

    Repo: https://github.com/LevInteractive/docker-nodejs-example
    Article: http://lev-interactive.com/2015/03/30/docker-load-balanced-mongodb-persistence/

  • 0

    管理持久性数据有多个级别,具体取决于您的需求:

    • Store it on your host

    • 使用标志 -v host-path:container-path 将容器目录数据保存到主机目录 .

    • 通过运行安装到同一目录的备份/恢复容器(例如tutumcloud / dockup)来进行备份/恢复 .

    • Create a data container and mount its volumes to your application container

    • 创建导出数据卷的容器,使用 --volumes-from 将该数据装入应用程序容器 .

    • 备份/恢复与上述解决方案相同 .

    • Use a Docker volume plugin that backs an external/third-party service

    • Docker卷插件允许您的数据源来自任何地方 - NFS,AWS(S3,EFS和EBS)

    • 根据插件/服务,您可以将单个或多个容器附加到单个卷 .

    • 根据服务的不同,备份/恢复可能会自动完成 .

    • 虽然手动操作很麻烦,但是一些编排解决方案 - 例如Rancher - 将其烘焙并且易于使用 .

    • Convoy是手动执行此操作的最简单方法 .

  • 0

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

相关问题