博客/社区

在AWS Fargate上部署没有Kubernetes的Grafana Loki和Grafana Tempo的指南

2021年8月11日8分钟

Zach是公司的首席云平台工程师Seniorlink船帆座产品团队。他是一名美国陆军老兵,一个狂热的攀岩者,一个强迫性的系统建造者。

在Seniorlink,我们提供服务和技术,以支持家庭照顾他们在家的亲人。在过去的两年里,我们已经将我们的项目扩展到美国各地,因此我们对应用系统的观察需求也在增长。

我们见证了……的发展Grafana洛基而且Grafana节奏就在产品发布的时候;bob手机app官网我们计划与Loki的集成来取代昂贵且难以维护的Graylog (Elasticsearch)集群,并使用Tempo引入分布式跟踪来增加我们的服务可观察性。

Loki和Tempo都继承了Cortex的核心部分,并遵循类似的架构模式。数据通过分发器和摄取器流入存储后端,数据通过查询前端和查询工作者读取。系统的每个点都是独立可伸缩的。了解系统架构和写入和读取路径的流程将极大地帮助您实现AWS Fargate部署。

我们的应用程序仍然主要部署在EC2上。我们还没有达到Kubernetes很适合的规模或复杂性,但我们希望我们的Loki/Tempo部署尽可能短暂。我们为两个系统选择了纯AWS ECS Fargate部署。Fargate是AWS的无服务器容器编排解决方案,允许我们运行容器工作负载,而无需担心主机管理。

Grafbob电竞频道ana实验室团队主要是为Kubernetes部署而开发的,所以这篇文章将处理在将Loki或Tempo部署到AWS Fargate时需要克服的一些挑战。Fargate没有Helm或Jsonnet配置可从货架上拉出和部署;我们必须研究Grafana实验室团队的系bob电竞频道统,并从头开始将其整合到AWS基础设施中。

任务配置

部署到Fargate的第一个挑战是服务的配置。

Kubernetes提供了许多将数据填充到pod中的选项(ConfigMaps, Secrets, InitContainers等等),但在Fargate上,存储是短暂的,除非依赖于EFS (NFS挂载)。

Fargate任务定义接受环境变量和秘密,但其他所有内容都必须构建到映像中或在运行时提取。我们希望避免仅对几个配置文件使用EFS或安装AWS CLI从S3提取配置所带来的成本和麻烦。Loki/Tempo配置非常复杂,将所有内容都指定为CLI参数将非常繁琐且容易出错。我们选择使用Grafana docker映像作为基础层,并使用模板配置文件(使用Go模板语法)和Gomplate,一个可以使用各种数据源渲染Go模板的小实用程序。

然后将图像发布到我们的AWS图像存储库(AWS ECR)。Loki和Tempo本身不允许通过环境变量进行配置,但是Gomplate实用程序让我们可以绕过这个问题,这样Fargate任务就可以轻松地将数据从AWS填充到服务中。

只要通过命令行参数或环境变量指定了“目标”微服务,所有Loki和Tempo服务都可以共享相同的配置文件,所以你只需要做一个配置。

chunk_store_config: chunk_cache_config: redis: endpoint: "{{. env。REDIS_ENDPOINT}}:6379"过期:6h

在容器启动时,一个入口点脚本运行gomplate,用AWS ParameterStore中的值来呈现配置文件,然后启动Loki或Tempo作为主容器进程。我们添加tini将容器管理为PID1,并向应用程序捕获/转发SIGTERM和SIGKILL信号。我们的洛基和Tempo图像都使用了相同的模式。

# !/bin/sh /etc/loki/gomplate -f /etc/loki/loki.tmpl -o /etc/loki/loki-config.yml --chmod 640 loki -config.file /etc/loki/loki-config.yml

服务发现

当Loki和Tempo在分布式系统中运行时,它们必须协调服务对等点之间的数据和活动。底层的Cortex库允许使用几种方法来做到这一点,例如etcd或Consul或Gossip Memberlist。

会员列表最像是kubernetes提供的无头服务,但在Fargate上你需要引入一些额外的部件。AWS ECS Discovery(即AWS CloudMap)为Fargate部署提供了类似的机制。ECS Discovery将ECS服务与Route53 a或SRV记录相关联(如果您希望端口可发现),并在容器启动时自动(解除)注册目标。

首先创建用于服务发现的名称空间,然后为每个服务创建发现定义。最后,Fargate服务引用ECS Discovery名称空间。下面是这个配置的一个示例terrform片段。当完成时,Memberlist配置引用CloudMap DNS记录,该记录将包含注册Fargate任务的所有ipv4地址。

资源“aws_service_discovery_private_dns_namespace”“this”{name = ecs.yourdomain.com VPC = data.aws_vpc。Id}资源"aws_service_discovery_service" "ingester" {name = "ingester" dns_config {namespace_id = aws_service_discovery_private_dns_namespace.this. name = "ingester"。id routing_policy = "MULTIVALUE" dns_records {ttl = 5 type = "A"}} health_check_custom_config {failure_threshold = 5}}

需要注意的是,有几个Loki和Tempo服务查询容器网络设备以发现它们的IP地址并将其注册到成员列表中。这个查询是通过Cortex库完成的,默认情况下查找“eth0”作为设备。Fargate 1.4.0(现在在AWS中被选为默认的“最新”版本)使用eth0作为内部AWS设备,并将容器的外部网络接口移动到“eth1”。这表现为容器加入了成员列表,但彼此完全无法通信,因为注册的地址是内部容器IP而不是实际的网络IP。如果您看到成员列表条目与您的VPC子网cidr不匹配,您就遇到了这个问题!如果您使用Fargate 1.4.0,解决方案是在Loki/Tempo配置中设置首选网络设备。

Ingester: lifecycler: # faragate 1.4.0使用eth1;使用其他平台的默认值interface_names: ["eth1"]

API入口

一旦Loki或Tempo启动并运行,您将需要一种方法将流量路由到适用的服务,以便Grafana、Promtail或Grafana Agent可以到达微服务后端。这需要按路径分配流量,因此我们求助于AWS应用程序负载均衡器。基于每个服务的API, Loki和Tempo的配置略有不同。请参阅特定的Grafana文档以了解区别,但下面是允许Grafana从单个入口点使用分布式查询前端和查询器服务的路由配置。

资源“aws_alb_listener_rule”“query_frontend”{listener_arn = aws_alb_listener.https。Arn动作{type = "forward" target_group_arn = aws_alb_target_group.query_frontend。Arn}条件{path_pattern {values = ["/loki/api/v1/query", "/loki/api/v1/query_range", "/loki/api/v1/label*", "/loki/api/v1/series"]}}}资源"aws_alb_listener_rule" "querier_tail_websocket" {listener_arn = aws_alb_listener.https。Arn动作{type = "forward" target_group_arn = aws_alb_target_group.querier。Arn}条件{path_pattern {values = ["/loki/api/v1/tail"]}}}

启动和安全关机

如果您需要修改官方Loki或Tempo映像以运行初始化和配置脚本,您还需要确保处理了信号捕获。正如前面提到的,一个很好的轻量级选项是tini,但是如果更适合您的组织,您也可以在脚本中构建自己的sigterm捕获器。

# !/bin/sh pid=0 sigterm_handler() { if [ $pid -ne 0 ]; then kill -TERM "$pid" wait "$pid" fi exit 143; } trap 'kill ${!}; sigterm_handler' TERM # add your tasks here pid="$!" echo "PID=$pid" # wait forever while true do tail -f /dev/null & wait ${!} done

对于Loki和Tempo摄取器来说,优雅的关闭是特别值得关注的,它们可能有未填充的块,没有被刷新到后端。根据日志、跟踪和配置的数量,这些块可能会在摄取器上停留一个小时或更长时间。在没有持久存储的纯Fargate部署中,这是一个问题。

Kubernetes摄取器能够使用持久卷声明在摄取器重新启动或关闭之间恢复数据而不会丢失。捕获和转发来自Fargate的SIGTERM是确保摄取器有足够时间将块刷新到存储的第一步。第二是增加ECS容器定义中的“stop_timeout”参数。AWS允许的最大时间是120秒,之后Fargate将发出最终SIGKILL以终止任务。

Loki和Tempo服务api的最新更改还包括冲洗端点强制摄取器将块提交到备份存储(在我们的例子中是AWS S3),并关闭摄取器。我们强烈建议使用此端点作为初始化系统或自动化的一部分,以防止数据丢失。

结论

在Seniorlink,我们已经在AWS Fargate的生产环境中使用了Loki一年多了,大约四个月前开始部署Tempo,同时将OpenTelemetry跟踪集成到我们的应用程序中。我们的Loki服务目前每秒吸收大约1000行,Tempo平均每秒从当前的仪器应用程序中吸收250个跨度和50个轨迹。通过采用Grafana、Loki和Tempo,可以对应用程序行为进行单一的统一视图,并减少应用程序故障排除的分析时间。