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

2023年 10月 16日 43.5k 0

作者:Eddie Mitchell

欢迎阅读 Elastic® Stack 和 Docker Compose 入门的第二部分。 在第一部分博客中,我们了解了 Docker Compose 的基础知识以及如何将单节点集群建立为本地游乐场,其中包括 Elasticsearch®、Kibana®、Logstash®、Metricbeat 和 Filebeat。 如果你还没有阅读第一篇博客,你可能需要跳过去阅读它,然后再继续。

在本博客中,我们将在之前的集群之上进行构建,并实现额外的功能,例如舰队、代理、APM 和演示应用程序,让你享受 POC 乐趣! 请记住,即使集群规模较大,也不建议将 Docker Compose 用于生产。

当然,如果你已经熟悉并且只想编写代码,请随时到 GitHub 存储库获取这些文件。

让我们开始吧!

Agent、Fleet、APM,天哪!

如果你不熟悉这些术语和产品,请不要担心! 首先,我们花几分钟时间来介绍这些功能是什么以及为什么它们可能对你有用。

在这个集群的原始架构中,我们专注于一些监控和文件摄取的基础知识。 在这里你可以看到它的代表。

Elastic Agent:快速概述

让我们从 Elastic Agent 及其附带的一些附加术语开始。

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

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

Policies (策略) 是定义 Elastic Agent 如何运行的设置和集成的集合。 可以将多个集成分配给一个代理策略,从而允许代理能够灵活地捕获数据。 将 Elastic 代理策略分配给多个代理允许你使用 Fleet 更大规模地管理和配置许多代理。

Fleet 是 Kibana 中的用户界面,允许集中管理 Elastic Agent 和相关策略。 此用户界面使你能够查看每个代理的运行状况、安装的版本、上次签入或活动时间以及策略信息。 Fleet 通过 Fleet Server 促进与每个 Elastic 代理的通信。 这允许在签入时远程推送新的策略更新以及升级代理二进制文件或集成。

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 文件中,你已经看到了我们用来为不同容器生成证书的代码。 它看起来像这样:



1.  echo "Creating certs";
2.  echo -ne 
3.  "instances:n"
4.  "  - name: es01n"
5.  "    dns:n"
6.  "       - es01n"
7.  "       - localhostn"
8.  "    ip:n"
9.  "      - 127.0.0.1n"
10.  "  - name: kibanan"
11.  "    dns:n"
12.  "      - kibanan"
13.  "      - localhostn"
14.  "    ip:n"
15.  "      - 127.0.0.1n"
16.  "  - name: fleet-servern"
17.  "    dns:n"
18.  "      - fleet-servern"
19.  "      - localhostn"
20.  "    ip:n"
21.  "      - 127.0.0.1n"
22.  > config/certs/instances.yml;


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

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



1.  networks:
2.    default:
3.      name: elastic


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



1.  es01:
2.    depends_on:
3.      setup:
4.        condition: service_healthy
5.    image: docker.elastic.co/elasticsearch/elasticsearch:${STACK_VERSION}
6.    labels:
7.      co.elastic.logs/module: elasticsearch
8.    volumes:
9.      - certs:/usr/share/elasticsearch/config/certs
10.      - esdata01:/usr/share/elasticsearch/data
11.    ports:
12.      - ${ES_PORT}:9200
13.    environment:
14.      - node.name=es01
15.      - cluster.name=${CLUSTER_NAME}
16.      - discovery.type=single-node
17.    ...


具体来说,我们正在查看 “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 服务器和 APM 秘密令牌的新端口之外,如下所示。

稍后在我们的实施中将使用 secret token 来授权对 APM 服务器的请求。 你可以在文档中阅读有关它们的更多信息。



1.  # Port to expose Fleet to the host
2.  FLEET_PORT=8220

5.  # Port to expose APM to the host
6.  APMSERVER_PORT=8200

9.  # APM Secret Token for POC environments only
10.  ELASTIC_APM_SECRET_TOKEN=supersecrettoken


请记住,本博客中列出的任何密码或密钥均用于演示目的,应立即在你的环境中进行更改。

docker-compose.yml

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

你可以在 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。 在生产环境中,你需要正确颁发和验证所有证书。

如上所述,我们公开两个端口用于通信。



1.  ports:
2.    - ${FLEET_PORT}:8220
3.    - ${APMSERVER_PORT}:8200


  • “8220” 处理所有发往代理/舰队通信的流量。
  • “8200” 处理 APM 服务器将使用的所有流量,因为我们的代理包含 APM 集成。

这里有几个关键的环境配置:

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

docker-compose.yml(‘kibana’ 容器)

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

- ./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 允许我们指定包将自动提取其资产:



1.  xpack.fleet.packages:
2.    - name: fleet_server
3.      version: latest
4.    - name: system
5.  ...


而 xpack.fleet.agentPolicies 允许定义用于初始 fleet 和代理的基本策略:



1.  xpack.fleet.agentPolicies:
2.    - name: Fleet-Server-Policy
3.      id: fleet-server-policy
4.      namespace: default
5.      monitoring_enabled: 
6.        - logs
7.        - metrics
8.  ...


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

我们还添加了一项政策来支持 Elastic APM 以及相关的 APM 包资产:



1.  - name: apm-1
2.          package:
3.            name: apm
4.          inputs:
5.          - type: apm
6.            enabled: true
7.            vars:
8.            - name: host
9.              value: 0.0.0.0:8200
10.            - name: secret_token
11.              value: ${ELASTIC_APM_SECRET_TOKEN}


我们设置服务器 URL 和 Secret_token 以确保我们的应用程序可以正常通信。

一个好处是 telemetry.enabled: "true",它允许我们针对我们自己的 Kibana 实例运行 Elastic APM,以查看 APM 工作方式的其他用法。

docker-compose.yml(‘webapp’容器)

 1.   webapp:
2.      build:
3.        context: app
4.      volumes:
5.        - "/var/lib/docker/containers:/var/lib/docker/containers:ro"
6.        - "/var/run/docker.sock:/var/run/docker.sock:ro"
7.        - "/sys/fs/cgroup:/hostfs/sys/fs/cgroup:ro"
8.        - "/proc:/hostfs/proc:ro"
9.        - "/:/hostfs:ro"
10.      ports:
11.        - 8000:8000

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

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

当 Docker Compose 构建此容器时,它将读入 “app” 文件夹并获取 dockerfile 以获取有关如何构建要在容器中使用的映像的说明。

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

app/dockerfile



1.  # syntax=docker/dockerfile:1

4.  FROM python:3.9-slim-buster

7.  WORKDIR /app

10.  COPY requirements.txt requirements.txt

13.  RUN pip3 install -r requirements.txt

16.  COPY main.py main.py

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


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

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

注意:出于缓存目的,操作顺序在 dockerfile 中很重要。 如果更改 docker 文件中调用的任何文件,则缓存将被丢弃,并且将发生新的文件拉取。 通常,你希望将最频繁更改的文件稍后放置在 dockerfile 中,以便较慢或未更改的文件可以在构建过程中保留缓存。

app/main.py

main.py 应用程序 (GitHub) 是一个非常简单的应用程序,结合了 FastAPI 和 NiceGUI。 主应用程序已使用 Starlette Elastic APM 代理进行检测,并且有几个按钮允许进行调用,从而有目的地在我们的 APM 环境中抛出错误和消息。

Python:



1.  from elasticapm.contrib.starlette import ElasticAPM, make_apm_client

3.  apm = make_apm_client({
4.        'SERVICE_NAME': 'my_python_service',
5.        'SECRET_TOKEN': 'supersecrettoken',
6.        'SERVER_URL': 'http://fleet-server:8200',
7.        'ENVIRONMENT': 'development'
8.    })

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

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

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


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

此应用程序仅作为如何与 Elastic APM 交互的示例。

Docker Compose up

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

运行命令 docker compose up 将启动所有容器,并允许你通过 https://localhost:5601 登录 Kibana。 请记住,由于我们现在已经为 Kibana 准备了证书,因此我们必须使用 HTTPS,因此你可能必须单击浏览器向你提供的任何证书警告。登录后,你可以通过汉堡菜单 -> Management -> Fleet.。

到达那里后,你将在 “Agents” 菜单下看到一个主机。 你可以在此 “Fleet” 页面中查看已注册到集群中的所有代理。 你还可以创建或更改策略、注册新代理以及更新任何全局队列配置。

但是,你可能会注意到 CPU 和内存使用情况字段并未更新。 同样,如果你单击 “Host” 链接,日志看起来也没有被填充。 经过进一步调查,我们在 fleet 服务器容器日志中看到类似于以下内容的错误:



1.  {"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"}
2.  {"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 中执行一些更新才能解决此问题。

让我们来看看。

重新配置输出,添加证书

导航到 “fleet” -> “Settings”后,我们要查看 “Output”部分,然后单击 “Actions” 标题下的 “Edit” 按钮:

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

我们需要更改 “Hosts” 字段以及 “Elasticsearch CA trusted fingerprint” 字段,以及对 “Advanced YAML configuration” 部分的更改。

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

首先,我们需要从集群中提取 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” 命令或仅通过在文本编辑器中打开证书来完成此操作:

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

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

输入为 “Elasticsearch CA trusted fingerprint.” 字段生成的指纹。

最后,将证书文本添加到 “Advanced YAML configuration.”。 由于这是一个 yml 配置,如果间隔不正确,它将抛出错误。

从如下位置开始:



1.  ssl:
2.  certificate_authorities:
3.  - |


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

例子:

不要忘记单击 “Save and Apply Settings” -> “Save and Deploy.”。

查看 Elastic Agent 数据

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

从这里,你还可以单击 “View more agent metrics” 以前往代理仪表板并查看其他数据。

查看文档以获取有关监控代理的更多信息。

查看 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 Agents 和 APM,但此设置还允许测试 OTel 配置!

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

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

本文中描述的任何特性或功能的发布和时间安排均由 Elastic 自行决定。 当前不可用的任何特性或功能可能无法按时交付或根本无法交付。

相关文章

JavaScript2024新功能:Object.groupBy、正则表达式v标志
PHP trim 函数对多字节字符的使用和限制
新函数 json_validate() 、randomizer 类扩展…20 个PHP 8.3 新特性全面解析
使用HTMX为WordPress增效:如何在不使用复杂框架的情况下增强平台功能
为React 19做准备:WordPress 6.6用户指南
如何删除WordPress中的所有评论

发布评论