Beats:使用 Autodiscover 监控 Docker 容器

Posted Elastic 中国社区官方博客

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Beats:使用 Autodiscover 监控 Docker 容器相关的知识,希望对你有一定的参考价值。

当你在容器上运行应用程序时,它们会成为监控系统的移动目标。在实际的容器部署中,我们通常并不知道到底部署多少个容器以及运行的接口是什么样的。这在实际的监控中是非常麻烦的。 Autodiscover 允许你跟踪它们并在发生变化时调整设置。 通过定义配置模板,自动发现子系统可以在服务开始运行时对其进行监控。

在今天的展示中,我将使用 Heartbeat 来进行展示。如果你想了解更多关于 Heartbeat 的配置,你可以阅读我之前的文章:

你可以在 heartbeat.yml 配置文件的 heartbeat.autodiscover 部分定义自动发现设置。 要启用自动发现,请指定提供程序列表。

在今天的展示中,我们将使用如下的架构来进行展示:

我在 Mac OS 的电脑上安装好 Elasticsearch 及 Kibana,而在另外一台 Ubuntu OS 的机器上安装 Docker,并在 Docker 里运行 Hearbeat 及一个 Web service 应用 hello-app。我们把 Heartbeat 及 Hello-app 置于 docker 里运行是为了能够使得它们互相能够通信。

安装

我们需要按照 Elasticsearch 及 Kibana。请按照我之前的教程分别进行安装:

因为我们需要使得我们的 Elasticsearch 及 Kibana 被另外一个机器所访问,所以在默认的配置中,我们需要对 config/elasticsearch.yml 做如下的修改:

config/elasticsearch.yml

network.host: 0.0.0.0
discovery.type: single-node

我们需要对 config/kibana.yml 文件做如下的修改:

config/kibana.yml

server.host: "0.0.0.0"

修改完上面的配置后,需要重新启动 Elasticsearch 及 Kibana。

下载测试服务

在今天的练习中,我们将使用一个非常简单的 hello-app 应用来进行展示。我们把这个应用安装到 Ubuntu 机器中。我们可以在如下的地址下载这个应用:

docker pull phozzy/hello-app

它的源码位于:https://github.com/phozzy/hello-app

这个应用是一个 go 语言编译的应用。它非常之简单:

main.go

package main

import (
	"fmt"
	"log"
	"net/http"
	"os"
)

func main() {
	// use PORT environment variable, or default to 8080
	port := "8080"
	if fromEnv := os.Getenv("PORT"); fromEnv != "" {
		port = fromEnv
	}

	// register hello function to handle all requests
	server := http.NewServeMux()
	server.HandleFunc("/", hello)

	// start the web server on port and accept requests
	log.Printf("Server listening on port %s", port)
	err := http.ListenAndServe(":"+port, server)
	log.Fatal(err)
}

// hello responds to the request with a plain-text "Hello, world" message.
func hello(w http.ResponseWriter, r *http.Request) {
	log.Printf("Serving request: %s", r.URL.Path)
	host, _ := os.Hostname()
	fmt.Fprintf(w, "Hello, GKE!\\n")
	fmt.Fprintf(w, "Version: %s\\n", os.Getenv("VERSION"))
	fmt.Fprintf(w, "Hostname: %s\\n", host)
}

在默认的情况下,这个应用运行于 8080 口上。从上面的应用中,我们可以看出来它有一个接口 "/",运行后输出一些文字。

我们通过如下的命令来查看已经下载的 docker image:

$ docker images | grep hello-app
phozzy/hello-app                      latest          ccc079c68c8d   16 months ago   11.5MB

我们使用如下的命令来进行运行:

docker run --name hello-app-1 -p 8888:8080 -d phozzy/hello-app:latest
$ docker run --name hello-app-1 -p 8888:8080 -d phozzy/hello-app:latest
952f433dad61a9991c2f4b5e5bf2da4fe15121990e0f69c1f2509ebe0376ba36

我们可以使用如下的命令来查看 container:

$ docker ps
CONTAINER ID   IMAGE                     COMMAND         CREATED              STATUS              PORTS                                       NAMES
952f433dad61   phozzy/hello-app:latest   "./hello-app"   About a minute ago   Up About a minute   0.0.0.0:8888->8080/tcp, :::8888->8080/tcp   hello-app-1

我们看到一个 container 已经运行起来了。我们在浏览器中打入如下的地址 http://localhost:8888/hello

我们可以看到如上的输出。

我们知道如果我们使用 HTTP 协议来监控这个服务时,我们必须很清楚地在 heartbeat.yml 文件中定义出来,比如:

heartbeat.yml

heartbeat.monitors:
- type: http
  enabled: true
  id: my-monitor
  name: My Monitor
  urls: ["http://localhost:8888/hello"]
  schedule: '@every 10s'

output.elasticsearch:
  hosts: ["192.168.0.3:9200"]

从上面我们可以看出来,我们需要非常明确地告诉 Heartbeat 我们需要对哪个服务的接口进行监控。但是如果是使用 container 的话,那么这个 url 可能是变化的,比如我们可以使用如下的方式来启动这个服务:

docker run --name hello-app-1 -p 1234:8080 -d phozzy/hello-app:latest

在上面,我们把端口地址修改为 1234,那么是不是我们需要重新修正刚才的 heartbeat.yml 文件呢?另外一种情况是,我们假如不使用之前的端口地址 8888,而改为新的端口地址,那么我们是不是也要重新来修改 heartbeat.yml 文件呢?

如果是,那么我们需要不断地修改这个 heartbeat.yml 文件。这样会显得非常之麻烦。如果你使用 Kubernetes 时,通常这些容器都是动态生成的。我们需要一种动态的方法来跟踪这些变化并自动做适当的调整。

使用 Autodiscover 来动态跟踪动态部署

 我们首先来创建一个崭新的文件 heartbeat.docker.yml 文件。它的内容如下:

heartbeat.docker.yml 

heartbeat.config.monitors:
  # Directory + glob pattern to search for configuration files
  path: ${path.config}/monitors.d/*.yml
  # If enabled, heartbeat will periodically check the config.monitors path for changes
  reload.enabled: false
  # How often to check for changes
  reload.period: 5s

# Configure monitors inline
heartbeat.monitors:
- type: http
  # Set enabled to true (or delete the following line) to enable this example monitor
  enabled: false
  # ID used to uniquely identify this monitor in elasticsearch even if the config changes
  id: my-monitor
  # Human readable display name for this service in Uptime UI and elsewhere
  name: My Monitor
  # List or urls to query
  urls: ["http://192.168.0.3:9200"]
  # Configure task schedule
  schedule: '@every 10s'

setup.template.settings:
  index.number_of_shards: 1
  index.codec: best_compression

setup.kibana:
  host: "192.168.0.3:5601"

# ---------------------------- Elasticsearch Output ----------------------------
output.elasticsearch:
  # Array of hosts to connect to.
  hosts: ["192.168.0.3:9200"]

processors:
  - add_observer_metadata:

# This allows to enable 6.7 migration aliases
#migration.6_to_7.enabled: true
heartbeat.autodiscover:
  providers:
    - type: docker
      templates:
        - condition:
            contains:
              docker.container.image: phozzy/hello-app:latest
          config:
            - type: http
              name: "Hello instance ${data.docker.container.name}"
              hosts: ["${data.host}:${data.port}/hello"]
              check.request:
                method: GET
              check.response:
                body: "Hello, GKE!"
              schedule: "@every 5s"

在上面,我们创建了一个 type 为 docker 的 provider。根据 Elastic 官方文档,这个 type 也可以是 kubernetes 或 AWS。在今天的练习中,我将使用 docker。我们为 docker 创建了一个 template。一个 template 由 condition 及 config 组成。只要满足条件的,就会使用相应定义的 config。针对我们的情况,我们希望 docker image 里含有 phozzy/hello-app:latest。如果这个条件满足,它就会自动地使用在 config 中定义的参数。在上面的 name 及 hosts 中,我们动态地从 docker 中获取一些数据,并配置。在上面的最后,我们把数据传入到 Elasticsearch 中。

我们来创建一个叫做 my_network 的 network:

docker network create --driver bridge my_network

这个 my_network 将被用作 Heartbeat 和 Hello-app 的通信。我们可以通过如下的命令来查看所有的 network:

docker network ls
$ docker network ls
NETWORK ID     NAME                    DRIVER    SCOPE
9c37dcff81fb   bridge                  bridge    local
b53ad76ab5ec   data-pipeline_default   bridge    local
da545fd42864   host                    host      local
2f8db3d8dca8   my_network              bridge    local
091528d93dcb   none                    null      local

在上面,我们可以看到 my_network 已经被成功地创建。我们可以使用如下的命令来检查这个 network:

docker network inspect my_network
$ docker network inspect my_network
[
    {
        "Name": "my_network",
        "Id": "2f8db3d8dca8ec28c2fc3af6729830797a8cc86ff34d5f9a44948b8abdbe253e",
        "Created": "2021-07-15T12:20:33.200347731+08:00",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": {},
            "Config": [
                {
                    "Subnet": "172.19.0.0/16",
                    "Gateway": "172.19.0.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {
            "c0807f8e0118a6eb5fc96217aad4a7bc2ae0493977cb5fb8b61ab7e01169c3a7": {
                "Name": "hello-app-1",
                "EndpointID": "3a511f2edf891b70278cc96f9d0a7863f1b7208ea89bb6fa7bd69eeb2177513a",
                "MacAddress": "02:42:ac:13:00:03",
                "IPv4Address": "172.19.0.3/16",
                "IPv6Address": ""
            },
            "f96004623acb404ca882e8f2f3b666960016f90fdf0b800849c5fa7eb7aa3066": {
                "Name": "heartbeat",
                "EndpointID": "6235d2ab9256a7ed36c56cc03ae81a3b1338d7f3a8fd1ed25a9dcd0384723d34",
                "MacAddress": "02:42:ac:13:00:02",
                "IPv4Address": "172.19.0.2/16",
                "IPv6Address": ""
            }
        },
        "Options": {},
        "Labels": {}
    }
]

接下来,我们添加 Ubuntu OS 当前的用户到 docker group。这个是因为我们需要用到 /var/run/docker.sock 这个文件。

ls -l /var/run/docker.sock
~$ ls -l /var/run/docker.sock
srw-rw---- 1 root docker 0 7月  15 10:56 /var/run/docker.sock

我们使用如下的命令:

sudo usermod -a -G docker $USER

由于一些原因,在我的配置中,我需要把 /var/run/docker.sock 的 owner 修改为我的账号 liuxg,否则有权限问题。

sudo chown $USER /var/run/docker.sock

我们进入上面 heartbeat.docker.yml 文件所处的目录,并使用如下的命令来启动 Heartbeat:

docker run -d \\
  --name=heartbeat \\
  --user=heartbeat \\
  --net=my_network \\
  --mount type=bind,source=/var/run/docker.sock,target=/var/run/docker.sock \\
  --volume="$(pwd)/heartbeat.docker.yml:/usr/share/heartbeat/heartbeat.yml:ro" \\
  docker.elastic.co/beats/heartbeat:7.13.0 \\
  --strict.perms=false -e

我们可以通过如下的命令来查看 heartbeat 容器是否已经成功运行:

docker ps | grep heartbeat
$ docker ps | grep heartbeat
f96004623acb   docker.elastic.co/beats/heartbeat:7.13.0   "/usr/bin/tini -- /u…"   2 hours ago   Up 35 minutes                            heartbeat

上面显示我们的 Heartbeat 已经被成功地部署了。

我们接下来启动 hello-app 应用。我们使用如下的命令来启动:

docker run --name hello-app-1 --net my_network -p 8888:8080 -d phozzy/hello-app:latest

 等上面的 hello-app 应用成功启动后,我们打开 Kibana 的界面:

我们可以看到 hello-app-1 的状态是 Up 的。它表明我们的 Heartbeat 能够成功地监控有 docker 生成的服务。

我们接下来启动另外一个 hello-app 的服务实例。在另外一个 terminal 中打入如下的命令:

docker run --name hello-app-2 --net my_network -p 9999:8080 -d phozzy/hello-app:latest
$ docker run --name hello-app-2 --net my_network -p 9999:8080 -d phozzy/hello-app:latest
cee77bd60d95cf25d7605c9c6b48a24b632dc61db9599c3e6b09afb089d36999

我们再次回到 Kibana 的界面,我们会看到如下的画面:

 从上面,我们可以清楚地看出来 hello-app-2 的状态也是 Up 的。

 参考:

【1】https://runnable.com/docker/basic-docker-networking

以上是关于Beats:使用 Autodiscover 监控 Docker 容器的主要内容,如果未能解决你的问题,请参考以下文章

Beats:为 Heartbeat 监控添加 geo 信息

Beats:为 Heartbeat 监控添加 geo 信息

基于ELK+Beats进行系统监控

Beats:在 Docker 中同时部署 Metricbeat 和 Elasticsearch

Beats数据采集

Beats:使用 Heartbeat 来检查 TLS 证书是否将要过期