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

时间:2013-08-28 19:45:44

标签: docker docker-container

人们如何处理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 ...(参见接受的答案)

15 个答案:

答案 0 :(得分:952)

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只是实现数据容器模式的更好方法。

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

  1. 通过docker volume ls
  2. 列出
  3. 通过docker volume inspect volume_name
  4. 进行识别
  5. 备份为普通目录
  6. 通过--volumes-from连接
  7. 进行备份

    新的卷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及以下

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

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

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

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

    this blog post中,可以很好地描述所谓的容器作为卷模式,它阐明了仅数据容器的要点。

    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:退出时取出容器
    • - 来自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解释为什么对容器和数据容器使用相同的图像是好的。

答案 1 :(得分:69)

Docker发行版v1.0 中,可以通过给定的命令在主机上绑定文件或目录的挂载:

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

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

答案 2 :(得分:30)

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

备注:

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

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

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

答案 3 :(得分:17)

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

请参阅 Data-only containers obsolete with docker 1.9.0? #17798

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

答案 4 :(得分:13)

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

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

答案 5 :(得分:11)

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

答案 6 :(得分:9)

@ 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现在拥有可以独立于容器进行管理的卷,这使得这更容易管理。

答案 7 :(得分:8)

如果您想移动卷,还应该查看 Flocker

来自自述文件:

  

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

     

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

答案 8 :(得分:8)

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

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

答案 9 :(得分:5)

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

Creating a MySQL Docker Container

它的主旨是使用主机上的目录来保持数据持久性。

答案 10 :(得分:3)

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

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

答案 11 :(得分:1)

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

答案 12 :(得分:0)

我的解决方案是使用新的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

  

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

答案 13 :(得分:0)

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

Persistent Volumes

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

  • 您可以使用任何存储,如NFS或其他存储,即使节点关闭,也无需存储。
  • 此外,即使在容器本身被销毁之后,也可以将这些卷中的数据配置为保留 - 这样,如果需要,可以通过另一个容器回收它。

答案 14 :(得分:0)

要保存或存储数据库数据,请确保您的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