从 Docker 容器备份/恢复 InfluxDB

导航至

过去几年最令人兴奋的发展之一是容器的出现,它允许将软件部署在安全隔离的环境中,并打包了所有的依赖项和库。

Docker 已成为市场上领先的容器产品之一,我们看到它们被广泛使用。很多时候,InfluxDB 都在监控来自容器的指标,而 TICK Stack (Telegraf、InfluxDB、Chronograf 和 Kapacitor) 中的产品也经常在容器内运行。实际上,如果您想了解更多,之前有一篇博客文章介绍了如何设置 InfluxData Sandbox,它不仅在容器中运行,还收集关于您的本地系统、容器环境和 InfluxDB 数据库的指标。这是开始使用该产品的绝佳方式。

挑战

不可避免地,您可能会发现自己在 Docker 容器中运行 InfluxDB。人们喜欢容器的原因在于它们是运行程序的隔离环境。当您关闭正在运行的应用程序时,按照设计,您正在运行的容器也会关闭。在这些环境中,当您想要恢复在容器中运行的 InfluxDB 数据库时,可能会遇到挑战。问题在于,为了从备份恢复 InfluxDB 数据库,实例需要停止。而当您在容器中运行 InfluxDB 并停止数据库时,容器也会关闭。那么,您如何解决这个两难境地呢?这就是我将在本博客中介绍的内容。

设置

创建运行 InfluxDB 的 Docker 容器,并将一些测试数据加载到其中。

我将详细介绍我的整个设置,以便您可以在实验室中轻松重现这些步骤。GitHub 上有一个 InfluxDB 的 Dockerfile 示例,以帮助在 Docker 容器中设置 InfluxDB 实例。我将使用它来设置我的数据库。我还创建了一个示例数据集 stocks.txt,我将在本示例中使用它。

我修改了之前提到的 influxdata-docker 仓库中 influxdb 下的 Dockerfile,添加了一些额外的端口以暴露,并添加了一个 copy 语句,将位于本地服务器上的 stocks.txt 文件复制到 docker 容器中。这样我就有一些数据可以使用了。这是我的 Dockerfile 的样子

FROM buildpack-deps:jessie-curl

RUN set -ex && \
    for key in \
        05CE15085FC09D18E99EFB22684A14CF2582E0C5 ; \
    do \
        gpg --keyserver ha.pool.sks-keyservers.net --recv-keys "$key" || \
        gpg --keyserver pgp.mit.edu --recv-keys "$key" || \
        gpg --keyserver keyserver.pgp.com --recv-keys "$key" ; \
    done

ENV INFLUXDB_VERSION 1.3.5
RUN wget -q https://dl.influxdata.com/influxdb/releases/influxdb_${INFLUXDB_VERSION}_amd64.deb.asc && \
    wget -q https://dl.influxdata.com/influxdb/releases/influxdb_${INFLUXDB_VERSION}_amd64.deb && \
    gpg --batch --verify influxdb_${INFLUXDB_VERSION}_amd64.deb.asc influxdb_${INFLUXDB_VERSION}_amd64.deb && \
    dpkg -i influxdb_${INFLUXDB_VERSION}_amd64.deb && \
    rm -f influxdb_${INFLUXDB_VERSION}_amd64.deb*
COPY influxdb.conf /etc/influxdb/influxdb.conf

EXPOSE 8086 8125/udp 8092/udp 8094

VOLUME /var/lib/influxdb

COPY stocks.txt /stocks.txt
COPY entrypoint.sh /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]
CMD ["influxd"]

在 Dockerfile 所在的目录中,执行以下操作来构建 InfluxDB 容器。

$ docker build -t test_influxdb .

完成后,您可以列出 docker 镜像,您应该会看到 influxdb-container 列出。

$ docker images
REPOSITORY    TAG     IMAGE ID      CREATED      SIZE
test_influxdb latest  7b7def77ff12  5 mins ago   224MB

启动容器并打开一个 bash shell 进入其中。注意:位于您本地服务器上的两个目录被映射到容器内的目录。第一个是 InfluxDB 数据目录,第二个是我们备份数据的位置。

$ export INFLUXDIR="$HOME/influxdb-test"
$ export BACKUPDIR="$HOME/backup-test"

$ CONTAINER_ID=$(docker run --rm \
  --detach \
  -v $INFLUXDIR:/var/lib/influxdb \
  -v $BACKUPDIR:/backups \
  -p 8086 \
  test_influxdb:latest
  )

$ docker exec –it "$CONTAINER_ID" /bin/bash

这应该在运行 InfluxDB 的容器中启动一个终端会话。您应该看到在构建容器时复制到容器中的 stocks.txt 文件位于根目录中。

# ls –l stocks.txt
-rw-r--r-- 1 root root 3070 Jul 20 01:45 stocks.txt

现在让我们将其导入到 stocks 数据库中,然后我们将备份该数据库。

# influx -import -path=stocks.txt -precision s

2017/09/25 18:58:36 Processed 1 commands
2017/09/25 18:58:36 Processed 38 inserts
2017/09/25 18:58:36 Failed 0 inserts

# influx -execute "select count(*) from stocks.autogen.stock_price"
name: stock_price
time count_high count_low count_open count_volume
---- ---------- --------- ---------- ------------
0    38         38        38        38

过程

现在我们有了一个可以工作的环境,让我们首先备份我们的容器化 InfluxDB 实例。这将备份到我们在构建容器时映射的目录 $HOME/backup-test。以下是我们将遵循的步骤,首先备份我们的数据库,然后删除数据库,最后恢复已删除的数据库。

  1. 捕获容器 ID、镜像名称以及用于与容器中 InfluxDB 通信的端口。
  2. 将 InfluxDB 备份到 docker 容器启动时定义的备份目录。
  3. 从 InfluxDB 中删除数据库。
  4. 检查以确保数据库已删除。
  5. 停止 docker 容器,因为必须停止 InfluxDB 才能运行恢复操作。
  6. 在临时容器中运行恢复命令。
  7. 启动 InfluxDB 容器。
  8. 查询 InfluxDB 以显示数据库存在并且记录已恢复。

详细信息

  • 首先,捕获容器 ID 和容器的临时端口。
$ CONTAINER_ID=`docker ps | grep test_influxdb | cut –c 1-12`
$ PORT=$(docker port "$CONTAINER_ID" 8086 | cut -d: -f2)
  • 其次,备份 stocks 数据库。
$ docker exec "$CONTAINER_ID" influx backup –database stocks "/backup/stocks.backup"
  • 运行 SHOW DATABASES 查询,然后 DROP 数据库,然后再次运行 SHOW DATABASES 查询以显示它已被删除。
$ curl http://localhost:${PORT}/query?q=SHOW+DATABASES
{"results":[{"statement_id":0,"series":[{"name":"databases","columns":["name"],"values":[["_internal"],["stocks"]]}]}]}

$ curl –XPOST http://localhost:${PORT}/query?q=DROP+DATABASE+stocks
{"results":[{"statement_id":0}]}

$ curl "http://localhost:${PORT}/query?q=SHOW+DATABASES"
{"results":[{"statement_id":0,"series":[{"name":"databases","columns":["name"],"values":[["_internal"]]}]}]}
  • 停止 docker 容器,这将停止 InfluxDB 数据库。
$ docker stop "$CONTAINER_ID"
  • 在临时容器中运行恢复命令。以下 docker 命令会影响先前挂载到 /var/lib/influxdb 的卷。
$ docker run --rm \
  --entrypoint /bin/bash \
  -v $INFLUXDIR:/var/lib/influxdb \
  -v $BACKUPDIR:/backups \
  test_influxdb:latest \
  -c "influxd restore -metadir /var/lib/influxdb/meta -datadir /var/lib/influxdb/data -database stocks /backups/stocks.backup"

Using metastore snapshot: /backups/stocks.backup/meta.00
Restoring from backup /backups/stocks.backup/stocks.*
unpacking /var/lib/influxdb/data/stocks/autogen/3/000000001-000000001.tsm
unpacking /var/lib/influxdb/data/stocks/autogen/4/000000001-000000001.tsm
unpacking /var/lib/influxdb/data/stocks/autogen/5/000000001-000000001.tsm
unpacking /var/lib/influxdb/data/stocks/autogen/6/000000001-000000001.tsm
unpacking /var/lib/influxdb/data/stocks/autogen/7/000000001-000000001.tsm
unpacking /var/lib/influxdb/data/stocks/autogen/8/000000001-000000001.tsm
unpacking /var/lib/influxdb/data/stocks/autogen/9/000000001-000000001.tsm
unpacking /var/lib/influxdb/data/stocks/autogen/10/000000001-000000001.tsm
unpacking /var/lib/influxdb/data/stocks/autogen/11/000000001-000000001.tsm
  • 像之前一样在后台启动容器,并显示已恢复的数据库。
$ CONTAINER_ID=$(docker run --rm \
  --detach \
  -v $INFLUXDIR:/var/lib/influxdb \
  -v $BACKUPDIR:/backups \
  -p 8086 \
  test_influxdb:latest
  )
$ PORT=$(docker port "$CONTAINER_ID" 8086 | cut -d: -f2)
$ curl -G "http://localhost:${PORT}/query?pretty=true"  --data-urlencode "q=SHOW DATABASES"
{
    "results": [
        {
            "statement_id": 0,
            "series": [
                {
                    "name": "databases",
                    "columns": [
                        "name"
                    ],
                    "values": [
                        [
                            "_internal"
                        ],
                        [
                            "stocks"
                        ]
                    ]
                }
            ]
        }
    ]
}
  • 我们再做一个计数,以显示所有记录都已恢复。
$ curl -G "http://localhost:${PORT}/query?pretty=true" --data-urlencode "db=stocks" --data-urlencode "q=SELECT count(*) FROM \"stock_price\""

{
    "results": [
        {
            "statement_id": 0,
            "series": [
                {
                    "name": "stock_price",
                    "columns": [
                        "time",
                        "count_high",
                        "count_low",
                        "count_open",
                        "count_volume"
                    ],
                    "values": [
                        [
                            "1970-01-01T00:00:00Z",
                            38,
                            38,
                            38,
                            38
                        ]
                    ]
                }
            ]
        }
    ]
}

后续步骤

我希望这对您有所帮助。如果您是 Docker 容器中运行 InfluxDB 的新手,那么上面的设置部分有很多有用的链接。官方 InfluxDB docker 仓库位于此处。此外,如前所述,请查看 InfluxData Sandbox。它是快速入门整个 TICK Stack 的一种快捷方式,并且可以非常快速地开始收集和可视化来自您的本地系统、您的 InfluxDB 实例以及 TICK Stack 正在运行的 docker 环境的指标。

致谢

上述在容器中运行时恢复 InfluxDB 的技术由 InfluxData 工程团队的 Mark Rushakoff 开发。