90DaysOfDevOps 实战:为 Elastic Stack 启用 APM Server 扩展并接入 Agent
90DaysOfDevOps 实战:为 Elastic Stack 启用 APM Server 扩展并接入 Agent
导读
本篇文章围绕 90DaysOfDevOps 仓库中 Elastic Stack 的 apm-server 扩展目录 展开,完整讲解如何在该仓库的 Docker Compose 编排基础上叠加启动 APM Server、理解其接收 APM Agent 数据并写入 Elasticsearch 的链路,以及如何用 Python Flask 应用接入 APM Agent 并在 Kibana 中完成连通性检查与 APM 仪表盘导入。读完本文,你将掌握一条可复制的「APM Server 扩展 + Agent 接入 + Kibana 可视化」完整实操路径。
APM Server 在 Elastic Stack 中的角色
原扩展文档开门见山地给出了 APM Server 的定位:APM Server 接收来自 APM Agent 的数据,并将其转换为可在 Kibana 中可视化的 Elasticsearch 文档。
在整条链路中:
- 应用代码内嵌 APM Agent(如 Python、Java、Node.js 等语言的探针),负责采集事务(transaction)、跨度(span)、错误(error)等性能与稳定性数据;
- Agent 通过 HTTP 将数据上报给 APM Server;
- APM Server 完成数据校验、归一化与转换后写入 Elasticsearch;
- 用户在 Kibana 的 APM 应用中查看服务地图、事务瀑布图、错误分布等视图。
从仓库的 docker-compose.yaml 可以看到,主栈默认只编排了 setup、elasticsearch、logstash、kibana 四个服务,APM Server 并不在默认栈内,而是以「扩展(extension)」的形式提供,这也正体现了 extensions 目录「第三方扩展,启用 Elastic Stack 的额外集成」的设计意图。
使用 Docker Compose 叠加启动 APM Server
启动命令
原文档给出的核心启动方式是在 Elastic Stack 编排根目录执行:
$ docker-compose -f docker-compose.yml -f extensions/apm-server/apm-server-compose.yml up
该命令利用 Docker Compose 的**多文件叠加(merge)**机制:-f docker-compose.yml 先加载主栈定义,-f extensions/apm-server/apm-server-compose.yml 再叠加 apm-server 扩展服务,最终一次性把五个服务全部启动。在 90DaysOfDevOps 仓库中,该命令应在 2022/Days/Monitoring/Elastic Stack/ 目录下执行,因为主栈的 .env 与 docker-compose.yaml 均位于此处。
扩展 compose 文件逐项解读
仓库中的 apm-server-compose.yml 是扩展的核心定义,逐项拆解如下:
| 配置项 | 值 | 作用说明 |
|---|---|---|
services.apm-server.build.context |
extensions/apm-server/ |
指向扩展目录,使用其中的 Dockerfile 构建镜像 |
build.args.ELASTIC_VERSION |
${ELASTIC_VERSION} |
从 .env 注入版本号,仓库当前固定为 8.1.0 |
command |
--strict.perms=false |
关闭配置文件严格权限校验,避免挂载进来的 apm-server.yml 因属主/权限不符合镜像内默认要求而启动失败 |
volumes |
./extensions/apm-server/config/apm-server.yml:/usr/share/apm-server/apm-server.yml:ro,Z |
将仓库内的配置文件以只读方式挂载为容器内默认配置路径;:Z 适配 SELinux 环境 |
ports |
'8200:8200' |
APM Server 对外暴露 8200 端口,供 Agent 上报数据 |
environment.ELASTIC_PASSWORD |
${ELASTIC_PASSWORD:-} |
透传 Elasticsearch 超级用户密码,用于 APM Server 写索引时认证 |
networks |
elk |
加入主栈的 elk 桥接网络,通过服务名访问 Elasticsearch |
depends_on |
elasticsearch |
保证 Elasticsearch 先于 APM Server 启动 |
其中 Dockerfile 极其精简,仅一行基础镜像声明:
ARG ELASTIC_VERSION
FROM docker.elastic.co/apm/apm-server:${ELASTIC_VERSION}
也就是说,APM Server 直接使用官方 apm-server 镜像,版本完全由 .env 中的 ELASTIC_VERSION=8.1.0 控制,与主栈的 Elasticsearch、Kibana 保持同一大版本,避免兼容性问题。
apm-server.yml:APM Server 的运行时配置
扩展目录下的 config/apm-server.yml 是挂载进容器的实际配置文件,内容如下:
apm-server:
host: 0.0.0.0:8200
output:
elasticsearch:
hosts: ['http://elasticsearch:9200']
username: elastic
password: ${ELASTIC_PASSWORD}
三个核心段落分别承担:
apm-server.host:监听地址为0.0.0.0:8200,表示同时绑定容器内全部网卡;对外映射由 compose 文件的ports: '8200:8200'完成,宿主机上通过http://localhost:8200即可访问。Agent 侧的默认服务地址也正是http://localhost:8200(见下文 Agent 配置)。output.elasticsearch.hosts:写入目标为http://elasticsearch:9200。这里使用服务名elasticsearch而非 IP,依赖 compose 网络内的 DNS 解析,与主栈 docker-compose.yaml 中 Kibana 访问 Elasticsearch 的写法elasticsearch.hosts: ["http://elasticsearch:9200"]一致。output.elasticsearch.username / password:仓库主栈开启了 X-Pack 安全认证(见 elasticsearch/config/elasticsearch.yml 中的xpack.security.enabled: true),因此 APM Server 必须以elastic用户身份写入,密码取自环境变量ELASTIC_PASSWORD,最终由 .env 注入。这正是 compose 文件中environment: ELASTIC_PASSWORD: ${ELASTIC_PASSWORD:-}存在的意义。
将应用接入 APM Server:Python Flask 示例
原文档指出,连接 APM Server 最基础的配置只需指定 SERVICE_NAME(服务名)和 SERVER_URL(服务地址),并给出了一个完整的 Python Flask 配置:
import elasticapm
from elasticapm.contrib.flask import ElasticAPM
from flask import Flask
app = Flask(__name__)
app.config['ELASTIC_APM'] = {
# Set required service name. Allowed characters:
# a-z, A-Z, 0-9, -, _, and space
'SERVICE_NAME': 'PYTHON_FLASK_TEST_APP',
# Set custom APM Server URL (default: http://localhost:8200)
'SERVER_URL': 'http://apm-server:8200',
'DEBUG': True,
}
配置要点拆解:
SERVICE_NAME:必填项,用于在 Kibana 的 APM 界面中区分不同的服务;允许的字符为a-z、A-Z、0-9、-、_以及空格。示例中PYTHON_FLASK_TEST_APP会在仪表盘中呈现为一个独立服务。SERVER_URL:Agent 上报的 APM Server 地址。默认值为http://localhost:8200;示例中特意写成了http://apm-server:8200,表明该 Flask 应用同样运行在elk网络内、以服务名访问 APM Server 的典型场景(对应 apm-server-compose.yml 的ports: '8200:8200'与网络定义)。若应用运行在宿主机而非容器内,则应改回http://localhost:8200。DEBUG:开启后 Agent 会在本地输出更详细的调试日志,便于排查上报问题;生产环境建议关闭。
接入流程可归纳为三步:安装 elastic-apm Python 包 → 在 Flask 应用中通过 ElasticAPM(app) 初始化探针 → 在 app.config['ELASTIC_APM'] 中配置服务名与服务地址。各支持语言的 Agent 配置项可在 Elastic APM Agent 官方文档中查阅(原文档以 [APM Agents][apm-agents] 链接给出)。
在 Kibana 中检查连通性并导入 APM 仪表盘
APM Server 启动且 Agent 上报成功后,进入 Kibana(主栈默认映射 5601 端口)完成以下五个步骤:
- 在 Kibana 首页的 Observability 面板下点击 Add APM;
- 点击 Check APM Server status,确认 APM Server 已正常启动并注册到 Elasticsearch;
- 点击 Check agent status,验证 Agent 是否已成功连接并注册(此时应能看到上一步配置的服务名
PYTHON_FLASK_TEST_APP); - 点击 Load Kibana objects,为 APM 数据创建索引模式(index pattern),使 Kibana 能够正确检索和聚合 APM 文档;
- 点击 Launch APM,进入 APM 仪表盘查看服务概览、事务性能与错误分析。
需要说明的是,APM Server 在 Elasticsearch 中产出的索引数据,正是其在栈中的职责体现——「接收 Agent 数据 → 转换为 Elasticsearch 文档 → 供 Kibana 可视化」,而这五个点击步骤实质上是在完成索引模式的初始化与仪表盘的导入。
与主栈其他组件的协作与注意事项
从仓库整体编排看,APM Server 扩展与主栈存在以下几处强耦合,部署时需一并注意:
- 版本一致性:APM Server 镜像版本由
.env的ELASTIC_VERSION(当前8.1.0)统一驱动,与 Elasticsearch、Kibana 保持一致是数据兼容的基础。 - 网络与依赖:扩展服务必须加入
elk网络,并depends_on: elasticsearch,保证写索引前 ES 已就绪;写入目标使用服务名elasticsearch:9200,与 kibana.yml 中elasticsearch.hosts的寻址方式一致。 - 安全认证:主栈 elasticsearch.yml 启用了 X-Pack 安全,APM Server 必须携带
elastic用户凭据(密码在 .env 中配置),否则写入会因认证失败而报错。 - 端口规划:8200 端口需在宿主机保持空闲;若与已有服务冲突,可调整 compose 中
ports的左半部分映射值,但 Agent 侧SERVER_URL需同步修改。 - 配置文件权限:compose 中显式添加了
--strict.perms=false以规避挂载配置文件的权限校验问题,这是 Beats 系列组件在容器化挂载场景下的常见处理方式。
结语
通过本文的实操路径,你可以在 90DaysOfDevOps 仓库的 Elastic Stack 编排之上,以「叠加扩展」的轻量方式快速获得 APM Server 能力,并完成从 Flask 应用接入、连通性校验到 Kibana 可视化仪表盘的一整套 APM 观测闭环。仓库中同级的 curator、filebeat、metricbeat 等扩展采用了完全相同的「compose 叠加 + 配置挂载」模式,掌握 APM Server 的接入方式后,可以举一反三地扩展其他 Elastic Stack 集成能力。