使用 Docker 运行 TICK Stack 的技巧

导航至

Docker?Docker docker docker。

虽然 Docker 的热度有所消退,被 “Kubernetes” 和 “Serverless” 等新词所取代,但不可否认的是,Docker 是开发者开始使用 Linux 容器的默认工具链,因为它非常普及,并与各种平台紧密集成。

Linux 容器是从几个底层 Linux 功能(如 命名空间cgroups)构建的抽象概念,它们共同提供了一种操作系统级别的虚拟化;对于您的应用程序来说,它们似乎都各自运行在自己的操作系统副本上。因此,与直接在主机上运行软件相比,Docker 提供了多种优势;它可以将您的应用程序与系统的其余部分以及彼此隔离,并使跨各种操作系统部署应用程序变得更加容易。总的来说,它使一切保持干净、整洁和良好分区。

如果您有兴趣了解更多关于容器的信息,我强烈推荐 Julia Evans 的文章 “What even is a container”。

就我个人而言,我在桌面上运行 Docker,并在那里部署尽可能多的应用程序;它不仅使我的主机保持整洁——我经常需要启动堆栈的新副本以测试特定问题、开发新功能或展示演示,而 Docker 使这一切变得异常容易。

我还在 Raspberry Pi 上 24/7 全天候运行一个 TICK Stack 实例,从我公寓周围的各种传感器收集数据。Docker 使我的系统保持清洁,并部署和升级软件变得容易。

Linux 容器和 Docker 都是很棒的工具,应该成为每个开发者武器库的一部分。那么我们如何使用它们来运行 TICK Stack 呢?

组件

您需要在本地机器上安装 Docker 和 Docker Compose。Docker 网站提供了 macOSWindows 上的安装文档,两者都包含 Docker Compose 作为安装的一部分。Docker CE 安装文档中还提供了针对多种 Linux 发行版的说明。在 Linux 上,Docker Compose 是一个单独的安装

由于 Docker 是 Linux 容器的实现,因此需要 Linux 操作系统才能运行。当您为 Windows 或 macOS 安装 Docker 时,它将设置和管理一个带有 Linux 内核的虚拟机,该虚拟机将运行您的所有容器。在 macOS 上,虚拟机通过使用 HyperKit 设置,而在 Windows 上,虚拟化由 Hyper-V 提供。不幸的是,Hyper-V 仅在 Windows 10 企业版、专业版和教育版上受支持;运行 Windows 家庭版的用户需要使用旧版 Docker Toolbox

您可以在 Docker Hub 上找到完整 TICK Stack 的官方镜像:TelegrafInfluxDBChronografKapacitor。与我们将其作为软件包发布到下载页面上的速度相比,镜像有时需要更长的时间才能在那里显示,因此如果时间紧迫,您可能需要维护自己的 Docker 镜像构建管道,但这超出了本文的范围。

运行容器

有几种与 Docker 交互和管理容器的方法。第一种是使用 docker 可执行文件来发出命令,如 docker rundocker stop。第二种,我们将在本文后面介绍,是使用 Docker Compose。

如果您按照 Docker 的安装说明一直到最后,您应该已经使用以下命令启动了 hello-world 容器

$ docker run hello-world

当运行更复杂的软件时,我们通常必须为 docker run 命令提供额外的参数,以便配置容器环境。这可能包括将容器中的端口暴露给 Docker 主机,或挂载卷以进行持久存储。

Docker 网络

首先,我们要设置一个新的 Docker 网络。Docker 自带一个内置网络,默认情况下所有容器都连接到该网络,但为我们的 TICK 部署创建一个新网络将使它们保持隔离,同时允许它们相互通信。隔离对于很多事情都有好处,但对于启动堆栈的多个实例进行测试或开发尤其有帮助。您可以在 文档 中阅读更多关于默认网络和用户定义网络之间差异的信息。

我们将使用以下命令创建一个新网络

$ docker network create --driver bridge tick-net

这将使用 bridge 驱动程序创建一个新网络,并将其命名为 tick-net

当我们执行 `docker run` 命令来启动容器时,我们将添加以下参数以将其连接到我们新创建的网络

--network tick-net

我们还需要将容器中的一些端口暴露给 Docker 主机,这样我们就可以从外部世界与容器中的应用程序进行通信。我们将以 InfluxDB 为例。数据库通过六个不同的端口进行通信,其中两个端口默认启用(标有 *)

端口 用途
8086* HTTP 服务
8088* RPC 备份/恢复
2003 Graphite 服务
4242 OpenTSDB 服务
8089 UDP 服务
25826 Collectd 服务

我们不会运行任何禁用的服务,这些服务提供了写入 InfluxDB 的其他方法,但我们希望使其他两个服务可用。我们将使用 publish 标志 --publish 或 -p,并将以下两行添加到我们的 docker run 命令中

-p 8086:8086
-p 8088:8088

持久存储

接下来,我们需要决定将配置文件放在哪里,以及将需要容器数据的容器的数据存储在哪里。

继续构建我们的 InfluxDB 运行命令,数据库期望它可以访问 Linux 上的两个文件位置, /var/lib/influxdb,它在其中存储数据,以及 /etc/influxdb,它在其中查找其配置。可以自定义这些位置,但对我们来说,默认值就足够了。

我们将通过将 volumes 标志 --volume 或 -v 添加到 docker run 中,将本地文件夹挂载到容器中的这些位置。如果您愿意,您可以让 Docker 为您管理 ,但在本地机器上绑定文件夹可确保我们能够从主机操作系统访问数据。

Docker 主机上的绑定点将根据您运行的机器而有所不同。为了举例说明,我们假设我们在 fprefect 用户的主目录中有一个名为 influxdb 的文件夹,以及该文件夹中的两个子文件夹,分别名为 data 和 config。我们将提供以下参数以将这两个文件夹挂载到容器内部

-v /Users/fprefect/influxdb/data/:/var/lib/influxdb
-v /Users/fprefect/influxdb/config:/etc/influxdb

整合在一起

我们几乎准备好启动我们的第一个容器了。我们只需要在我们的 docker run 命令中添加一些东西。我们将使用 -d 标志以 “detached” 模式启动容器,这将在后台运行它,并且我们将使用 --name 参数为其命名。最后,我们将运行最新版本的 influxdb 容器,标记为 1.5.4

这就是它全部组合在一起的样子

$ docker run -d \
    --network tick-net \
    -p 8086:8086 \
    -p 8082:8082 \
    -p 8089:8089 \
    -v /Users/fprefect/influxdb/data/:/var/lib/influxdb \
    -v /Users/fprefect/influxdb/config:/etc/influxdb \
    --name influxdb \
    influxdb:1.5.4

继续并在命令行上运行它。如果成功,它应该返回一个唯一的哈希值,用于标识正在运行的容器。

操作容器

现在我们有了一个正在运行的容器,让我们来谈谈一些额外的操作细节。我们通常需要检查的第一件事是我们的容器是否正在运行。为此,我们可以使用 docker ps 命令

$ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                                            NAMES
d20b788291ea        influxdb:1.5.4      "/entrypoint.sh infl…"   3 seconds ago       Up 1 second         0.0.0.0:8086->8086/tcp, 0.0.0.0:8088->8088/tcp   influxdb

太棒了!我们的容器已启动并正在运行。但是也许它的行为不如我们预期的那样?我们可能需要深入研究并查看日志。我们可以使用 docker logs 命令并提供容器的名称来获取这些日志。我们还将添加一个 --tail=5 参数,以将输出限制为最后 5 行。如果没有这个参数,我们将获得程序启动以来输出的所有日志,这可能会很多!

docker logs influxdb --tail=5
ts=2018-06-28T21:43:26.862912Z lvl=info msg="Compacted file" log_id=08z5Suul000 engine=tsm1 tsm1_strategy=full tsm1_optimize=false trace_id=08z5T3NG000 op_name=tsm1_compact_group tsm1_index=0 tsm1_file=/var/lib/influxdb/data/_internal/monitor/4/000000005-000000002.tsm.tmp
ts=2018-06-28T21:43:26.863008Z lvl=info msg="Finished compacting files" log_id=08z5Suul000 engine=tsm1 tsm1_strategy=full tsm1_optimize=false trace_id=08z5T3NG000 op_name=tsm1_compact_group groups=2 files=1 duration=49.357ms
ts=2018-06-28T21:43:26.863071Z lvl=info msg="TSM compaction (end)" log_id=08z5Suul000 engine=tsm1 tsm1_strategy=full tsm1_optimize=false trace_id=08z5T3NG000 op_name=tsm1_compact_group op_event=end op_elapsed=49.407ms
ts=2018-06-28T21:43:40.037174Z lvl=info msg="Post http://a7a2fee5bc09:80/write?consistency=&db=_internal&precision=ns&rp=monitor: dial tcp: lookup a7a2fee5bc09 on 127.0.0.11:53: no such host" log_id=08z5Suul000 service=subscriber
ts=2018-06-28T21:43:50.024014Z lvl=info msg="Post http://a7a2fee5bc09:80/write?consistency=&db=_internal&precision=ns&rp=monitor: dial tcp: lookup a7a2fee5bc09 on 127.0.0.11:53: no such host" log_id=08z5Suul000 service=subscriber

InfluxDB 容器看起来一切正常,所以让我们看看是否可以使用 Influx CLI 连接到数据库。我们可以使用本地主机上的 CLI 副本进行连接,但是如果我们想在容器本身内启动 CLI 呢?

Docker 也为此提供了一个命令: docker exec。为了运行交互式会话,我们还需要提供 -io 和 -t 参数,它们分别创建一个交互式会话并分配一个伪 TTY。

所以让我们在我们的 influxdb 容器中执行 influx CLI

$ docker exec -it influxdb influx
Connected to http://localhost:8086 version 1.5.4
InfluxDB shell version: 1.5.4
>

但是,您可能会注意到,箭头键在 CLI 中无法按预期工作。例如,当按下向上箭头时,屏幕上会打印 ^]]A。这是 influx CLI 检测和与终端环境交互的方式存在问题。但是,如果您先执行 bash shell,然后再运行 influx CLI,则箭头键应该可以按预期工作

$ docker exec -it influxdb /bin/bash
root@f7f7292006d0:/# influx
Connected to http://localhost:8086 version 1.5.4
InfluxDB shell version: 1.5.4
>

在继续下一节之前,让我们停止并删除我们的容器。您可以使用 docker stop 和 docker rm 命令,以及标识容器的唯一哈希值或容器名称,如下所示

$ docker stop influxdb
influxdb

$ docker rm influxdb
influxdb

$ docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES

Docker Compose

Docker Compose 是 “一个用于定义多容器 Docker 应用程序的工具”。它使我们能够启动多个容器并将它们自动连接在一起,我们可以使用它来帮助我们更轻松地部署和管理完整的 TICK Stack。我们将首先在 docker-compose.yml 文件中定义作为 TICK Stack 一部分的各种服务,然后使用 Compose 命令行工具部署这些服务。

下面是一个 docker-compose.yml 示例(使用 Compose 文件格式版本 3),它定义了两个服务, influxdb 和 chronograf

version: '3'
services:
  influxdb:
    image: influxdb:latest
    volumes:
      # Mount for influxdb data directory
      - ./influxdb/data:/var/lib/influxdb
      # Mount for influxdb configuration
      - ./influxdb/config/:/etc/influxdb/
    ports:
      # The API for InfluxDB is served on port 8086
      - "8086:8086"
      - "8082:8082"

  chronograf:
    image: chronograf:latest
    volumes:
      # Mount for chronograf database
      - ./chronograf/data/:/var/lib/chronograf/
    ports:
      # The WebUI for Chronograf is served on port 8888
      - "8888:8888"
    depends_on:
      - influxdb

该文件还定义了我们要发布到 Docker 主机的挂载点和端口。 chronograf 服务还有另一个有用的部分: depends_on。这将确保在启动 chronograf 容器之前, influxdb 容器已启动并正在运行。

要部署这些服务,请运行 docker-compose up -d(类似于 docker run,`-d` 参数以无头 “detached” 模式启动容器)。 docker-compose 使用执行它的目录来命名它管理的各种组件,因此将您的 docker-compose.yml 文件放在一个命名良好的目录中是一个好主意。对于此示例,我们将把我们的 docker-compose.yml 文件放在一个名为 tick 的目录中。

运行 docker-compose up -d 将执行多项操作:首先,它将创建一个名为 tick_network 的新 Docker 网络,然后它将为我们定义的每个服务启动一个容器,分别命名为 tick_influxdb_1 和 tick_chronograf_1

$ docker-compose up -d
Creating network "tick_default" with the default driver
Creating tick_influxdb_1 ... done
Creating tick_chronograf_1 ... done

$ docker ps -a
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                                            NAMES
88b0263b7e74        chronograf:latest   "/entrypoint.sh chro…"   11 seconds ago      Up 9 seconds        0.0.0.0:8888->8888/tcp                           tick_chronograf_1
dcfa7a03eccb        influxdb:latest     "/entrypoint.sh infl…"   11 seconds ago      Up 9 seconds        0.0.0.0:8082->8082/tcp, 0.0.0.0:8086->8086/tcp   tick_influxdb_1

您应该可以通过访问 http://localhost:8888 导航到 Chronograf GUI,并使用地址 http://influxdb:8086 将其连接到 InfluxDB,该地址使用 Docker Compose 的内置 DNS 解析来连接到 influxdb 容器。

获取日志的功能与不使用 Compose 的 Docker 非常相似。您可以使用 docker-compose logs servicename 命令从单个服务访问日志,并将您的服务名称替换为 servicename。您可以使用 --tail=5 限制日志数量,如下所示

$ docker-compose logs --tail=5 influxdb
Attaching to tick_influxdb_1
influxdb_1    | ts=2018-06-28T22:30:01.069954Z lvl=info msg="Listening on HTTP" log_id=08z87b10000 service=httpd addr=[::]:8086 https=false
influxdb_1    | ts=2018-06-28T22:30:01.070023Z lvl=info msg="Starting retention policy enforcement service" log_id=08z87b10000 service=retention check_interval=30m
influxdb_1    | ts=2018-06-28T22:30:01.070057Z lvl=info msg="Storing statistics" log_id=08z87b10000 service=monitor db_instance=_internal db_rp=monitor interval=10s
influxdb_1    | ts=2018-06-28T22:30:01.070263Z lvl=info msg="Listening for signals" log_id=08z87b10000
influxdb_1    | ts=2018-06-28T22:30:01.070313Z lvl=info msg="Sending usage statistics to usage.influxdata.com" log_id=08z87b10000

您也可以通过在命令末尾省略容器名称来获取所有服务的日志

$ docker-compose logs --tail=2
Attaching to tick_chronograf_1, tick_influxdb_1
chronograf_1  | time="2018-06-28T22:30:01Z" level=info msg="Serving chronograf at http://[::]:8888" component=server 
chronograf_1  | time="2018-06-28T22:30:01Z" level=info msg="Reporting usage stats" component=usage freq=24h reporting_addr="https://usage.influxdata.com" stats="os,arch,version,cluster_id,uptime" 
influxdb_1    | ts=2018-06-28T22:30:01.070263Z lvl=info msg="Listening for signals" log_id=08z87b10000
influxdb_1    | ts=2018-06-28T22:30:01.070313Z lvl=info msg="Sending usage statistics to usage.influxdata.com" log_id=08z87b10000

使用 Docker Compose 执行命令稍微容易一些,因为它会自动分配一个伪 TTY 并为您提供一个交互式会话,但其他方面看起来与标准 Docker 命令非常相似

$ docker-compose exec influxdb /bin/bash
root@dcfa7a03eccb:/#

要拆除一切,我们只需要从相应的目录执行 docker-compose down

TICK 沙箱

InfluxData 提供了 TICK stack 的 “发行版”,我们称之为 Sandbox。它提供了一个 docker-compose.yml 文件,其中包含所有最新的组件,包括仍在开发中的组件,如 Flux。它还提供了一对辅助脚本,以帮助那些不熟悉 Docker Compose 的人快速启动并运行。并且由于它使用 Docker Compose,它将拥有自己的网络和容器,并且不会与您恰好在 Docker 中运行的其他 TICK Stack 实例冲突。

总结

不要忘记清理您在学习这篇博文时创建的任何容器!使用 Docker 时需要注意的另一件事是容器镜像本身;镜像不会自动删除,因此随着时间的推移,当您升级正在使用的软件版本时,旧容器可能会累积并开始占用磁盘空间。有一些脚本可以为您管理此问题,但在大多数情况下,只需意识到潜在问题并偶尔手动清理就足够了。

与往常一样,如果您有任何问题或意见,请随时在 Twitter @noahcrowley 上与我联系,或在我们的社区网站 community.influxdata.com 上发布您的评论。如果您使用 Influx 构建了一些很棒的东西,请不要犹豫 告诉我们,可能会有连帽衫送给您!