Elastic Stack 和 Docker Compose 入门:第 2 部分

blog-thumb-virtual-stack.png

欢迎阅读“Elastic® Stack 和 Docker Compose 入门”第二部分。在第一部分博文中,我们介绍了 Docker Compose 的基础知识,以及如何建立一个单节点集群作为本地的实际演练,其中包括 Elasticsearch®、Kibana®、Logstash®、Metricbeat 和 Filebeat。如果您还没有读过第一篇博文,请直接跳转过去阅读一下,然后再继续了解以下内容。

在本篇博文中,我们将在先前集群的基础上构建并实现更多功能,例如 Fleet、Agent、APM 和一个演示应用程序,以满足您进行 POC 的需求!请记住,即使集群规模较大,也不建议将 Docker Compose 用于生产环境。

当然,如果您已经很熟悉,只是想编写代码,请随时跳过阅读部分,直接从 GitHub 存储库下载文件

让我们开始吧!

Agent、Fleet、APM,天哪!

如果您不熟悉这些术语和产品,请不要担心!我们下面会先花几分钟的时间具体介绍这些功能,并说明为什么它们可能对您有用。 

在这个集群的原始架构中,我们侧重于介绍一些监测和文件采集方面的基础知识。以下您就可以看到这方面的介绍。

Elastic Agent:简要概述

下面我们先来介绍 Elastic Agent 以及与之相关的一些附加术语。

Elastic Agent 提供了一种一体化的方式,可让主机监测日志、指标和其他各种类型的数据。此外,它还提供了安全威胁防护、操作系统数据查询、远程服务或硬件数据转发等功能。Agent 可精简并加速整个基础架构的监测部署。每个代理都与策略相关联,更新这些策略,即可将新数据源、安全措施和附加功能等多个集成整合进来。

Elastic 集成旨在让您能够快速、轻松地从外部源收集数据,从而获得深入见解。这些集成通常会使用预构建的设置、仪表板、可视化和管道,以便协助理解指标、日志和事件。您可以在本地 Kibana 实例中找到集成页面,从而轻松浏览、安装和配置与 Elastic Agent 及其策略相关的集成。此外,您还可以在 Elastic 网站上查看可用集成的列表。

策略是定义 Elastic Agent 运行方式的设置和集成的集合。您可以将多个集成分配给一个 Agent 策略,从而让代理能够灵活地确定可采集的数据。通过为多个代理分配一个 Elastic Agent 策略,可让您使用 Fleet 以更大的规模管理和配置许多代理。

Fleet 是 Kibana 中的用户界面,用于集中管理 Elastic Agent 和相关联的策略。在这个用户界面中,您可以查看每个 Agent 的运行状况、安装的版本、上次签入或活动时间,以及策略信息。通过 Fleet Server 的协助,Fleet 能够高效地与每一个 Elastic Agent 进行通信。这样就可以在签入时远程推送新的策略更新,以及升级 Agent 二进制文件或集成。

Fleet Server 是 Elastic Agent 的一个实例,作为 Fleet 与所有已部署的 Elastic Agent 之间的通信协调器运行。

*呼!*

请查看 Elastic 文档,阅读与 Agent 和 Fleet 相关的所有这些主题的更多信息

我们将集成 Elastic Agent 和 Fleet,以演示如何在管理策略的同时收集日志和指标。让我们将其添加到架构图中,看看会是什么样子。

Elastic APM 和定制 Web 应用

Elastic APM 是在 Elastic Stack 基础上构建而成的应用程序性能监测系统。使用 Elastic APM 代理对代码进行检测,可以通过收集指标、痕迹、日志、错误和异常,并将这些信息发送到 Elasticsearch 中以在 APM 用户界面中查看,从而帮助简化故障排查和加速解决性能问题。

Elastic APM 可在云中部署,也可在本地自行管理。在管理 APM 本地实例时,您可以选择管理独立的 APM Server 二进制文件,也可以通过 Elastic Agent 将 APM 作为一项集成来使用。

对于本地 POC,我们将实施由 Elastic Agent 和 Fleet 服务管理的 Elastic APM。

如果您没有要监测的应用程序,那么监测应用程序性能的功能就没有多大用处。理想情况下,您已经有了一些代码,希望使用我们的 APM 代理之一对其进行检测。如果没有,GitHub 存储库中有一个小型 Python 应用程序,我们可以安装它来进行一些基本测试。

新架构

让我们再来看一下架构图,看看各个组件是如何配合到位的。

在架构图中,您可以看到我们有了新的 Fleet-Server 容器,它正在运行 Elastic Agent,用作所有代理与 Elastic 集群通信的中央通信点。Elastic Agent 正在运行 Elastic APM 集成,以便从我们的定制 Web 应用程序和 Kibana 收集遥测信息。

通信和访问

一般来说,开始使用 Docker 时遇到的许多常见挑战是了解通信的工作原理。有了前面提到的所有容器、端口、证书和 URL,让我们后退一步,看看当不同组件需要相互通信时,这个新架构会是什么样子的。

docker-compose.yml 文件内,您已经看到了我们用来为不同容器生成证书的代码。类似代码如下所示:

echo "Creating certs";
echo -ne \
"instances:\n"\
"  - name: es01\n"\
"    dns:\n"\
"       - es01\n"\
"       - localhost\n"\
"    ip:\n"\
"      - 127.0.0.1\n"\
"  - name: kibana\n"\
"    dns:\n"\
"      - kibana\n"\
"      - localhost\n"\
"    ip:\n"\
"      - 127.0.0.1\n"\
"  - name: fleet-server\n"\
"    dns:\n"\
"      - fleet-server\n"\
"      - localhost\n"\
"    ip:\n"\
"      - 127.0.0.1\n"\
> config/certs/instances.yml;

这个代码块正在创建一个名为 instances.yml 的文件,这个文件驻留在“setup”容器中,是一个包含所有容器名称及其 DNS 条目的列表,因为它们在 Docker 引擎中相互关联。我们将这个文件与 elasticsearch-certutil 实用工具结合使用,为每个容器创建一个证书,以便在容器通信时以及您与容器通信时确保容器之间的通信安全。
 

我们所有的容器都使用我们在 docker-compose.yml 中设置的默认网络相互通信,如下所示:

networks:
  default:
    name: elastic

这个网络位于 Docker 引擎内部,允许所有容器相互通信并解析其他容器的名称。为了让浏览器的流量能够到达容器,我们在每个服务中都公开了必要的端口。例如:

es01:
  depends_on:
    setup:
      condition: service_healthy
  image: docker.elastic.co/elasticsearch/elasticsearch:${STACK_VERSION}
  labels:
    co.elastic.logs/module: elasticsearch
  volumes:
    - certs:/usr/share/elasticsearch/config/certs
    - esdata01:/usr/share/elasticsearch/data
  ports:
    - ${ES_PORT}:9200
  environment:
    - node.name=es01
    - cluster.name=${CLUSTER_NAME}
    - discovery.type=single-node
  ...

具体来说,我们要查看“ports:”部分。这是告诉 Docker Compose 映射以“host:container”格式指定的端口。在这个示例中,`${ES_PORT}` 将替换为我们的 .env 文件中的 9200,并且该端口将在您的计算机(主机)上打开。第二个 9200 表示我们将主机映射到的容器上的端口。通过这种方式,当您通过浏览器访问 https://localhost:9200 时,您的流量将被发送到 es01 容器。

默认情况下,Elasticsearch 也会打开 9300 端口用于节点间通信。虽然 Docker 引擎中的其他容器能够在必要时访问这个端口,但您无法从主机访问这个端口,因为我们尚未公开这个端口。

如果我们尝试使用新架构来直观地理解这些概念,它可能看起来如下图所示:

在这张图中,容器“metricbeat01”能够解析我们为“es01”和“logstash01”指定的名称,甚至能够访问“logstash01”上未公开的监测端口 9600,因为它们驻留在同一 Docker 网络中。

但是,我们可以看到,为了让您访问 9200 上的 Elasticsearch 和 5601 上的 Kibana,您需要访问“localhost”,以便您的计算机可以将流量路由到 Docker 网络和正确的容器。

最后,在引用其中一个服务时决定使用哪个地址可能会很棘手。要记住的关键是,当您的一个容器正在访问另一个已配置 Elastic 网络的容器时,请使用正确的服务/容器名称。但是,如果来自主机的流量正在访问其中一个容器,那么您将需要验证 docker-compose.yml 中是否公开了正确的端口,并通过 localhost 访问该端口。

另请注意,虽然这些配置是开始本地开发的方法,但不建议在生产环境中使用。

实施

那么,我们该如何实现这一切呢?

首先,我们将快速回顾一下基础堆栈,并从文件结构、.env 文件和 docker-compose.yml 开始,重点介绍一些更改

文件结构

在文件结构中,我们添加了“app”文件夹,用于存放定制 Web 应用的所有代码和配置,同时还添加了一个新的 kibana.yml,因为我们将添加与 Elastic Agent 和 APM 相关的更多特定设置。

.env

我们的 .env 文件(GitHub 链接)基本保持不变,但 Fleet、APM Server 的新端口和 APM 密钥令牌除外,如下文所示。

稍后将在我们的实施中使用密钥令牌来授权对 APM Server 的请求。有关更多详细说明,请参阅文档

# Port to expose Fleet to the host
FLEET_PORT=8220


# Port to expose APM to the host
APMSERVER_PORT=8200


# APM Secret Token for POC environments only
ELASTIC_APM_SECRET_TOKEN=supersecrettoken

请记住,本篇博文中列出的任何密码或密钥仅供演示之用,应立即在您的环境中进行更改。

docker-compose.yml

对于 docker-compose.yml 文件,我们在基础堆栈中添加了一些内容,即“Fleet Server”和“webapp”的容器,包括添加额外的卷,以及将 fleet-server 添加到我们的服务器列表中,以生成前面提到的证书。

您可以在 GitHub 上找到整个文件,我们这里将只介绍其中的几处编辑。

关于环境变量的说明

现有服务中有许多环境变量都已指定证书,并将其传递到容器或其相应的配置文件。

与我们的 .env 文件非常类似,docker-compose.yml 中的环境变量允许我们将变量传递到容器中。通过这种方式,我们在容器上一次性将变量“CA_CERT”设置为等于证书路径,然后我们就可以在 metricbeat.yml 文件中根据需要使用这个变量了。例如,如果我们需要更新 CA_CERT,只需在 docker-compose.yml 中更新一次路径,然后重新部署 Metricbeat 容器。

metricbeat01 容器和 metricbeat.yml 文件就是传递“CA_CERT”环境变量并在 yml 文件中多次使用的很好示例。

阅读有关设置和使用环境变量的更多信息

docker-compose.yml(“fleet-server”容器)

将“fleet-server”容器添加到 docker-compose.yml 文件(GitHub 链接)中,会产生一个额外的容器,用于拉取 Elastic Agent 映像。代理映像既用于边缘数据收集,也用于配置 Fleet 管理服务器的基础映像。

请记住,我们使用了一些额外的标志来降低证书检查的严格程度,因为这是一个本地 POC。在生产环境中,您需要正确签发和验证所有证书。

如上前面所提到的,我们将公开两个端口用于通信。

ports:
  - ${FLEET_PORT}:8220
  - ${APMSERVER_PORT}:8200
  • “8220”处理所有发往 Agent/Fleet 通信的流量。
  • “8200”处理 APM 服务器将要使用的所有流量,因为我们的 Agent 包含 APM 集成。

下表是几个关键的环境配置:

注意:如果您还想配置和运行合成测试,则需要改为使用 Docker 映像“docker.elastic.co/beats/elastic-agent-complete:${STACK_VERSION}”。我们不会讨论这一部分,但您可以在我们的文档中阅读更多相关信息。

docker-compose.yml(“kibana”容器)

“kibana”容器需要进行两处更改(GitHub 链接)。第一处是“volumes”部分中 docker-compose.ymlkibana.yml 文件之间非常重要的连接。这行告诉 Docker 将本地 kibana.yml 文件“绑定挂载”到容器中以供使用。

- ./kibana.yml:/usr/share/kibana/config/kibana.yml:ro

接下来,我们在环境变量的底部添加了一个简单的更改,这样就可以传递我们最初在 .env 文件中设置的 APM 密钥令牌。

- ELASTIC_APM_SECRET_TOKEN=${ELASTIC_APM_SECRET_TOKEN}

kibana.yml

我们添加了一个新的 yml 文件来配置 Kibana,以便整合 Fleet 和 Agent(GitHub 链接)。

值得注意的是,xpack.fleet.packages 允许我们指定包自动拉入其资产:

xpack.fleet.packages:
  - name: fleet_server
    version: latest
  - name: system
...

xpack.fleet.agentPolicies 允许定义用于初始 Fleet 和 Agent 的基本策略:

xpack.fleet.agentPolicies:
  - name: Fleet-Server-Policy
    id: fleet-server-policy
    namespace: default
    monitoring_enabled: 
      - logs
      - metrics
...

您可以在我们的文档中阅读更多有关在没有 UI 的情况下配置策略的信息。

此外,我们还添加了一项支持 Elastic APM 以及相关 APM 包资产的策略:

- name: apm-1
        package:
          name: apm
        inputs:
        - type: apm
          enabled: true
          vars:
          - name: host
            value: 0.0.0.0:8200
          - name: secret_token
            value: ${ELASTIC_APM_SECRET_TOKEN}

我们设置服务器 URL 和 secret_token,以确保应用程序能正常通信。

其中一个额外功能是 telemetry.enabled: "true",它允许我们针对自己的 Kibana 实例运行 Elastic APM,以了解 APM 工作原理的其他用法。

docker-compose.yml(“webapp”容器)

 webapp:
    build:
      context: app
    volumes:
      - "/var/lib/docker/containers:/var/lib/docker/containers:ro"
      - "/var/run/docker.sock:/var/run/docker.sock:ro"
      - "/sys/fs/cgroup:/hostfs/sys/fs/cgroup:ro"
      - "/proc:/hostfs/proc:ro"
      - "/:/hostfs:ro"
    ports:
      - 8000:8000

对于我们的示例网络应用,我们使用 dockerfile 来帮助我们构建应用程序并部署到 Docker 中。

这种容器配置在很大程度上依赖于“context: app”构建命令。Docker 假设“app”是一个文件夹,该文件夹内就是我们的 Dockerfile。这些属性可以更加具体,但就我们的目的而言,默认假设完全没问题。

当 Docker Compose 构建这个容器时,它会读取“app”文件夹并抓取 dockerfile,以获取如何构建要在容器中使用的映像的说明。

此外,我们还指定要公开端口 8000,并传递一些类似 Metribeat 可用的“volumes”,以便监测资源。

app/dockerfile

# syntax=docker/dockerfile:1


FROM python:3.9-slim-buster


WORKDIR /app


COPY requirements.txt requirements.txt


RUN pip3 install -r requirements.txt


COPY main.py main.py


CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000", "--log-level", "info", "--workers", "1"]

现在,我们的 dockerfile 将使用“python:3.9-slim-buster”映像作为拉取的基础。在这里,它会创建 /app 文件夹,从我们的位置复制 requirements.txt 文件,然后通过 pip3 安装各个包。

之后,它会复制我们的 main.py 应用程序,然后尝试运行在 main.py 中构建的 Uvicorn 应用程序。

注意:出于缓存的目的,操作顺序在 dockerfile 中很重要。如果您更改了 docker 文件中调用的任何文件,则缓存将被丢弃,并会重新拉取该文件。通常情况下,请将变化最频繁的文件放在 dockerfile 的较后位置,以便在构建过程中缓存较慢或不变的文件。

app/main.py

main.py 应用程序 (GitHub) 是一个非常简单的应用程序,它结合了 FastAPINiceGUI。主应用程序已配置了 Starlette Elastic APM Agent,通过几个按钮就可以进行调用,从而有目的地向 APM 环境发送错误和消息。

Python:

from elasticapm.contrib.starlette import ElasticAPM, make_apm_client

apm = make_apm_client({
      'SERVICE_NAME': 'my_python_service',
      'SECRET_TOKEN': 'supersecrettoken',
      'SERVER_URL': 'http://fleet-server:8200',
      'ENVIRONMENT': 'development'
  })

app = FastAPI()
app.add_middleware(ElasticAPM, client=apm)

apm.capture_message(f"Custom Message: {message}")

@app.get("/error")
async def throw_error():
    try:
        1 / 0
    except Exception as e:
        apm.capture_exception()
    return {"message": "Failed Successfully :)"}

以上是代码片段,可以看到我们正在导入 APM 库、创建 APM 客户端并将中间件添加到 FastAPI 应用程序中。

这个应用程序仅作为示例,说明如何与 Elastic APM 进行交互。

启动 Docker Compose

至此我们已经配置好了一切,让我们启动集群吧!

运行 docker compose up 命令将启动所有容器,并可让您通过 https://localhost:5601 登录 Kibana。请记住,由于我们现在已经为 Kibana 安装了证书,我们必须使用 HTTPS,因此您可能需要点击浏览器给出的任何证书警告。
登录后,您可以通过汉堡菜单 -> Management(管理)-> Fleet 导航到 Fleet。

到达该位置后,您会在“Agents”菜单下看到一个“Host”(主机)。您可以在这个 Fleet 页面上查看已注册到集群中的所有代理。此外,您还可以创建或更改策略、注册新代理,以及更新任何全局 Fleet 配置。

不过,您可能会注意到 CPU 和“Memory”(内存利用率)字段没有更新。同样,如果点击“Host”链接,日志看起来也没有填充。经过进一步调查,我们在 fleet-server 容器日志中看到类似于以下内容的错误:

{"log.level":"info","message":"Attempting to reconnect to backoff(elasticsearch(http://localhost:9200)) with 17 reconnect attempt(s)","component":{"binary":"metricbeat","dataset":"elastic_agent.metricbeat","id":"http/metrics-monitoring","type":"http/metrics"},"log":{"source":"http/metrics-monitoring"},"log.origin":{"file.line":139,"file.name":"pipeline/client_worker.go"},"service.name":"metricbeat","ecs.version":"1.6.0","log.logger":"publisher_pipeline_output","ecs.version":"1.6.0"}
{"log.level":"error","message":"Error dialing dial tcp 127.0.0.1:9200: connect: connection refused","component":{"binary":"metricbeat","dataset":"elastic_agent.metricbeat","id":"http/metrics-monitoring","type":"http/metrics"},"log":{"source":"http/metrics-monitoring"},"service.name":"metricbeat","ecs.version":"1.6.0","log.logger":"esclientleg","log.origin":{"file.line":38,"file.name":"transport/logging.go"},"network":"tcp","address":"localhost:9200","ecs.version":"1.6.0"}

这是因为,默认情况下,我们的 Elastic Agent 会尝试将数据记录到本地 Elasticsearch 实例,这对于我们的 Docker 环境来说是不正确的。

我们需要在“Fleet”->“Settings UI”(设置 UI)中进行一些更新才能解决这个问题。

下面我们一起来看看如何操作。

重新配置输出,添加证书

导航到“Fleet”->“Settings”(设置)后,我们要查看“Outputs”(输出)部分,然后单击“Actions”(操作)标题下的Edit”(编辑)按钮:

这将为我们提供一个从界面右侧滑出的窗口,以便修改默认输出。

我们需要更改“Hosts”(主机)字段和“Elasticsearch CA trusted fingerprint”(Elasticsearch CA 可信指纹)字段,以及更改“Advanced YAML configuratio”(高级 YAML 配置)部分。

但是,我们还没有获取所有这些信息。因此,让我们跳转到一个终端,并获取它的信息。

首先,我们需要从集群中拉取 CA 证书。这将与我们在第一部分中使用的命令相同:

docker cp es-cluster-es01-1:/usr/share/elasticsearch/config/certs/ca/ca.crt /tmp/.

注意:这个命令将根据运行 docker-compose.yml 文件的目录或 .env 文件中指定的 COMPOSE_PROJECT_NAME 变量而有所不同。

接下来,我们需要获取证书的指纹。为此,我们可以使用 OpenSSL 命令:

openssl x509 -fingerprint -sha256 -noout -in /tmp/ca.crt | awk -F"=" {' print $2 '} | sed s/://g

这将产生类似于以下内容的值:

5A7464CEABC54FA60CAD3BDF16395E69243B827898F5CCC93E5A38B8F78D5E72

最后,我们需要将整个证书转换为 yml 格式。我们可以使用“cat”命令或在文本编辑器中打开证书来完成此操作:

cat /tmp/ca.crt

获得证书文本后,我们会将其添加到 yml 格式,并将所有这些信息输入到之前的“Fleet Settings”(Fleet 设置)屏幕中。

对于“Hosts”(主机),我们将需要使用“https://es01:9200”。这是因为托管 Fleet 服务器的容器了解如何与 es01 容器通信来发送数据。

输入为字段“Elasticsearch CA trusted fingerprint”(Elasticsearch CA 可信指纹)生成的指纹。

最后,将证书文本添加到“Advanced YAML configuration”(高级 YAML 配置)中。 由于这是一个 yml 配置,如果间隔不正确,它将会引发错误。

从以下位置开始:

ssl:
certificate_authorities:
- |

然后粘贴证书文本,确保缩进正确。

示例:

不要忘记单击“Save and Apply Settings”(保存并应用设置)->“Save and Deploy”(保存并部署)。

查看 Elastic Agent 数据

保存和部署完成后,返回到“Agent”选项卡,单击您的代理名称,您应该会看到正确显示的 CPU 和内存利用率,以及填充的日志。

从这里,您还可以单击View more agent metrics”(查看更多代理指标),前往 Agent 仪表板并查看其他数据

查看文档以了解有关监测代理的其他信息

查看 Elastic APM 数据

导航到汉堡菜单 ->“Observability”(可观测性)->“Overview”(概述),您将能够开始看到一些流入的 Elastic APM 指标。

具体来说,导航到“APM”->“Services”(服务),您将能够看到 Kibana 和我们的演示应用程序。

这可让您深入了解各种服务,并熟悉 Elastic APM 正在捕获的信息类型。

借助 Elastic Stack 进行故障排除并实现无缝扩展

我们的 Elastic Stack 和 Docker Compose 入门系列的第二部分重点介绍了 Elastic Agent、Fleet 和 Elastic APM 等其他安全性和功能。通过 Dockerfile 添加定制应用程序也有助于说明 Elastic APM 的实现。

这为开发和测试功能提供了一个绝佳的本地学习平台。

通过为您的应用程序配置 Elastic APM 代理来监测应用程序,将极大提高您增强应用程序并对其进行故障排除的能力。利用 Elastic Agent 和 Fleet 服务,可让您轻松扩展测量工具。

请记住,虽然我们演示的是 Elastic Agent 和 APM,但这种设置也可以测试 OTel 配置

当您准备好迁移到更适合生产的集群时,请查看 Elastic Cloud,了解如何将您在本地所学的知识无缝过渡到具有许多集成的适合生产的环境中。

这里讨论的所有文件都可以在 GitHub 上找到。欢迎提出问题和请求!

本博文所描述的任何特性或功能的发布及上市时间均由 Elastic 自行决定。当前尚未发布的任何特性或功能可能无法按时提供或根本不会提供。