如何在 Docker 容器之间迁移 MongoDB 数据库?

Ben*_*ell 4 mongodb docker

在 MongoDB 中迁移数据库是一个很好理解的问题域,并且有一系列工具可以在主机级别执行此操作。一切从mongodumpmongoexportrsync数据文件。如果您非常喜欢,可以使用SSHFSNFS等网络安装来缓解磁盘空间和 IOPS 约束问题。

迁移主机上的数据库

# Using a temporary archive
mongodump    --db my_db --gzip --archive /tmp/my_db.dump --port 27017
mongorestore --db my_db --gzip --archive /tmp/my_db.dump --port 27018
rm /tmp/my_db.dump

# Or you can stream it...
mongodump      --db my_db --port 27017 --archive \
| mongorestore --db my_db --port 27018 --archive
Run Code Online (Sandbox Code Playgroud)

然而,在容器化环境中执行相同的迁移可能会稍微复杂一些,而且容器的轻量级、特定用途的性质意味着您通常没有可用的相同工具集。

作为管理容器化基础设施的工程师,我对可以使用哪些方法将数据库从一个容器/集群迁移到另一个容器/集群感兴趣,无论是出于备份、集群迁移还是开发(数据采样)目的。

出于这个问题的目的,让我们假设数据库不是分布在多个主机上的多 TB 集群,并且每秒看到数千 (++) 次写入(即您可以进行备份并拥有“足够”的数据)有价值而无需担心复制 oplog 等)。

Ben*_*ell 5

我以前使用过几种方法来解决这个问题。具体方法取决于我在做什么以及我需要满足哪些要求。

1. 处理容器内的文件

# Dump the old container's DB to an archive file within the container
docker exec $OLD_CONTAINER \
     bash -c 'mongodump --db my_db --gzip --archive /tmp/my_db.dump'

# Copy the archive from the old container to the new one
docker cp $OLD_CONTAINER:/tmp/my_db.dump $NEW_CONTAINER:/tmp/my_db.dump

# Restore the archive in the new container
docker exec $NEW_CONTAINER \
     bash -c 'mongorestore --db my_db --gzip --archive /tmp/my_db.dump'
Run Code Online (Sandbox Code Playgroud)

这种方法非常有效并且避免了在通过管道传输数据时遇到的许多编码问题stdout,但是在迁移到不同主机上的容器时它也不是特别好(您需要到docker cp本地文件,然后重复该过程以复制该本地文件到新主机)以及从 Docker 迁移到 Kubernetes 时。

迁移到不同的 Docker 集群

# Dump the old container's DB to an archive file within the container
docker -H old_cluster exec $OLD_CONTAINER \
     bash -c 'mongodump --db my_db --gzip --archive /tmp/my_db.dump'
docker -H old_cluster exec $OLD_CONTAINER rm /tmp/my_db.dump

# Copy the archive from the old container to the new one (via your machine)
docker -H old_cluster cp $OLD_CONTAINER:/tmp/my_db.dump /tmp/my_db.dump
docker -H new_cluster cp /tmp/my_db.dump $NEW_CONTAINER:/tmp/my_db.dump
rm /tmp/my_db.dump

# Restore the archive in the new container
docker -H new_cluster exec $NEW_CONTAINER \
     bash -c 'mongorestore --db my_db --gzip --archive /tmp/my_db.dump'
docker -H new_cluster exec $NEW_CONTAINER rm /tmp/my_db.dump
Run Code Online (Sandbox Code Playgroud)

缺点

这种方法的最大缺点是需要在任何地方存储临时转储文件。在基本情况下,旧容器中有一个转储文件,新容器中有另一个;在最坏的情况下,你有你的本地计算机上的第3(或可能在多台机器,如果你需要scp/rsync它周围)。这些临时文件很可能会被遗忘,浪费不必要的空间并使容器的文件系统变得混乱。

2. 复制标准输出

# Copy the database over stdout (base64 encoded)
docker exec $OLD_CONTAINER \
     bash -c 'mongodump --db my_db --gzip --archive 2>/dev/null | base64' \
| docker exec $NEW_CONTAINER \
     bash -c 'base64 --decode | mongorestore --db my_db --gzip --archive'
Run Code Online (Sandbox Code Playgroud)

复制存档stdout并将其传递stdin到新容器允许您删除复制步骤并将命令连接到一个漂亮的小衬里(对于美丽的某些定义)。它还允许您潜在地混合和匹配主机甚至容器调度程序......

在不同的 Docker 集群之间迁移

# Copy the database over stdout (base64 encoded)
docker -H old_cluster exec $(docker -H old_cluster ps -q -f 'name=mongo') \
    bash -c 'mongodump --db my_db --gzip --archive 2>/dev/null | base64' \
| docker -H new_cluster exec $(docker -H new_cluster ps -q -f 'name=mongo') \
    bash -c 'base64 --decode | mongorestore --db my_db --gzip --archive'
Run Code Online (Sandbox Code Playgroud)

从 Docker 迁移到 Kubernetes

# Copy the database over stdout (base64 encoded)
docker exec $(docker ps -q -f 'name=mongo') \
    bash -c 'mongodump --db my_db --gzip --archive 2>/dev/null | base64' \
| kubectl exec mongodb-0 \
    bash -c 'base64 --decode | mongorestore --db my_db --gzip --archive'
Run Code Online (Sandbox Code Playgroud)

缺点

这种方法在“成功”的情况下效果很好,但在它无法正确转储数据库的情况下,需要抑制stderr流(使用2>/dev/null)可能会导致调试原因的严重头痛。

它的网络效率也比文件案例低 33%,因为它需要base64对数据进行编码以进行传输(对于大型数据库来说可能是一个大问题)。与所有流模式一样,也无法检查事后发送的数据,如果您需要追踪问题,这可能是一个问题。