亚马逊AWS官方博客

基于ECS的容器日志解决方案

摘要

ECS是AWS发布的容器集群管理和调度服务。通过ECS容器集群管理服务,用户可以很方便地管理成百上千个容器组成的业务系统,而无需运维容器集群管理、调度及状态存储等相关管理组件。相比于虚拟机,容器技术拥有诸多优势,使得近年来越来越多的用户选择拥抱容器技术。

容器技术的优势:

·         更有效的资源利用

·         更快的启动和销毁速度

·         捆绑应用代码和运行依赖

·         版本化管理容器镜像

·         非常适合微服务的场景

尽管容器技术优势很多,但却无法解决应用程序的故障,传统虚机场景下的监控、日志搜集等应用在容器场景下同样需要。本文主要针对于运行在AWS ECS容器集群管理服务上的容器应用,来为大家详解相关的日志解决方案,具体包括:日志搜集、搜索和分析等,并为大家解答在使用AWS相关日志搜集服务时候的一些常见问题,例如:

·         如何更方便地搜集容器日志

·         如何将多行显示的日志汇聚成一条搜集

·         如何从互联网访问VPC 内部的Elasticsearch和Kibana服务

·         如何为Kibana应用添加用户登入认证功能

·         如何设置index的默认primary shard以更好地适配日志量

·         如何定期删除Elasticsearch中的老旧日志

 

下图是本文使用的整体架构图:

流程介绍

我们先简单介绍一下这个架构中各个组件的功能以及日志从生成到处理的流程:

·         ECS是AWS的容器管理及调度平台,用于管理我们的应用容器

·         应用容器通过awslogs driver将日志输出到CloudWatch logs中

·         输出到CloudWatch logs中的日志可以实时地导入到AWS Elasticsearch集群中

·         用户可以通过CloudWatch logs界面可以对日志进行关键字匹配方式的简单搜索

·         用户也可以通过nginx代理调用Elasticsearch API或者登入Kibana对日志进行更为丰富地搜索和分析

·         Nginx代理服务器为internet上的用户提供代理及登入认证功能,Route 53服务为internet访问提供DNS解析服务,同时对nginx server进行健康检查并在必要的时候进行故障切换

·         CloudWatch logs中的日志也可以定期批量导入到S3中通过Athena,Redshift,EMR等大数据分析工具分析,并通过QuickSight做展示 (这部分内容不作为本文介绍的重点)

·         用户可以通过Cloud 9 IDE开发lambda程序,该lambda由CloudWatch Events每天触发用于根据自定义策略清理Elasticsearch中的老旧日志,全量日志保存在CloudWatch logs及S3中

 

ECS支持多种docker logs driver将容器中的日志输出,比如:awslogs、fluentd、json-file等。其中,awslogs相比于其他driver有如下优势:

·         天然集成CloudWatch logs对日志进行搜索、查看,并能根据需要产生metrics,进而基于日志产生事件告警

·         默认启用,无需通过user data修改ECS实例的配置

·         默认安装,无需通过user data或者自定义AMI安装

·         输出到CloudWatch logs中的日志以task id而非container id进行分类,便于追溯

·         配置简单

 

通过awslogs driver,我们可以很方便地将ECS运行的容器内日志集中传输到CloudWatch logs中进行收集查看,具体的配置非常简单,在创建task definition的时候,为container选择awslogs driver,并且设置输出的awslogs-group,awslogs-region和awslogs-stream-prefix即可,之后就可以在CloudWatch logs中对应的log group下看到以task id标识的log stream。

ES默认的shard配置:

 

需要注意的是,有些应用得一条日志内容可能会被分成多行输出,最典型的场景就是tomcat的错误日志,如下图所示,默认该条日志在CloudWatch logs中也会分成多个日志条目,这将不便于我们进行日志搜索和故障分析。

 

所以,对于这种类型的应用,我们需要做额外的设置:设置awslogs-datetime-format来匹配多行日志中的开头日期,这样以该格式日期开始的多行日志就会被记录成CloudWatch logs中的一条日志而非多条。

我们可以看到日志在CloudWatch logs中已经以时间为标志,显示为一行了:

CloudWatch logs的界面提供了一个过滤栏,我们可以通过简单的关键字匹配的方式过滤出符合条件的日志,美中不足的是目前CloudWatch logs主要支持关键字匹配的过滤条件,还不支持诸如通配符等高级的过滤方式,有该需求或者希望能够对日志进行分析统计展示的用户可以很方便地将CloudWatch logs中的日志实时地导入Elasticsearch中并结合Kibana进行更为细致地搜索和分析,同时,CloudWatch logs界面也支持将日志导出到S3中,结合EMR,Athena,Redshift等大数据分析服务进行分析,这一部分内容不作为本文的重点,有兴趣的读者可以通过AWS官网了解相关的大数据处理服务,下面我们主要介绍如何将CloudWatch logs中的日志导入到Elasticsearch中。

 

将CloudWatch logs中的日志导入Elasticsearch

首先我们来创建Elasticsearch集群

点击创建一个新的domain,我们可以注意到目前AWS托管的Elasticsearch集群支持两种Endpoint:VPC和Internet。我们将会在下文具体的配置页面中做相应的介绍。

为集群起一个名字并选择相应的版本:

在之后的配置集群页面中,我们需要设置集群节点的机型、数量以及是否需要专门的master节点。大家可以参考AWS Elasticsearch的官方文档来查看这些选项的最佳实践。通常对于master节点我们推荐采用计算优化型实例,而对于计算节点我们推荐采用IO优化型实例。同时,我们也建议开启zone awareness功能(要求计算节点为偶数),这将使节点分布在两个可用区中,实现可用区级别的冗余。

 

另外可以根据需要启用数据加密并且设定自动做快照的时间:

之后我们需要选择使用VPC还是Internet的接入方式,如果选择Internet接入方式,那么ES的节点会被分配至公网IP,在策略允许的情况下可以通过公网访问ES及Kibana;如果选择VPC接入方式,那么ES的节点会被分配私有IP,在策略允许的情况下可以有如下几种访问方式:

1.      如果将ES作为搜索引擎使用,那么VPC内部的应用服务器可以通过私网直接对ES进行API的调用访问

2.      如果本地站点和AWS的VPC建有VPN或者DX连接,那么本地设备可以通过VPN或者DX使用私网IP访问ES及Kibana

3.      如果需要通过公网访问ES及Kibana,可以通过在EC2上部署反向代理实现

 

本次案例我们使用的是VPC的接入方式,并且通过部署反向代理实现公网访问ES及Kibana。这样做有一个额外的好处:由于Kibana本身并没有集成账号登入的功能,默认我们可以通过安全组对IP进行控制,通过反向代理我们可以额外地增加用户名密码的登入认证功能,增加一层安全防护。

由于我们使用VPC的接入方式,访问策略可以选择通过安全组做相关的控制。

创建完集群后,我们可以在控制台中看到ES和Kibana的endpoint信息。

 

配置nginx代理服务器

下面我们来配置nginx代理服务器,这边略去创建EC2的过程,需要注意将该EC2放到公有子网中并且建议分配弹性IP。

首先通过yum工具安装nginx,然后创建如下配置文件,注意将ELASTIC-IP修改成EC2的EIP,并且修改ES的endpoint以及server_name:

/etc/nginx/conf.d/elasticsearch.conf

/etc/nginx/conf.d/kibana.conf

接下来为HTTP基本认证生成用户账号,首先利用yum工具安装httpd,然后生成账号并启动nginx:

为了更简便地给大家进行介绍,本文中为Kibana的访问只启用了HTTP的基本认证,可以用相同的方法为ES的API访问启用基本认证。

为了能够从公网访问到ES和Kibana,我们需要为nginx配置文件中的server_name设置DNS解析,可以使用route 53来将server_name解析到EC2的EIP,用户也可以通过跨AZ部署多台EC2 nginx代理结合route 53的health check功能,就能够很方便地实现代理服务器的高可用设计。

接下来我们可以在浏览器中输入kibana.ivanyu.tech来测试下基本认证:

我们需要输入用户名密码后,才能访问到Kibana的页面:

并且我们能够通过ES的API来访问ES集群:

以上我们就完成了ES集群的创建,以及通过nginx代理实现公网访问ES及Kibana,并且为Kibana的访问增添了基本的用户认证功能。

 

在将日志传入ES之前,我们需要调整其设置,对于AWS托管的ES集群,默认每个index会有5个shard,而每个shard会有1个replica,CloudWatch logs中的日志会以天为单位在ES中创建名字如cwl-2018.01.23的index。官方推荐将一个shard的数据量控制在50GB以下,对于PB级别的index建议一个shard的数据量至少为100GB以上,由于一个index的primary shard数量在index创建后不能简单地在线修改,我们需要通过创建template模板,为CloudWatch logs日志生成的index设置默认的primary shard和replica,我们通过如下API为CloudWatch logs日志对应的index设置10个primary shard和1个replica。

 

 

将CloudWatch logs中的日志streaming到ES集群

下面我们介绍如何将CloudWatch logs中的日志streaming到ES集群中,首先在CloudWatch logs界面选择应用日志打入的log group,选择Stream to Amazon Elasticsearch Service。

选择之前创建的ES集群,由于我们会通过lambda实现日志从CloudWatch logs到ES集群的导入,需要为lambda函数分配IAM role,可以选择创建一个新的role或者选择一个已有的role,该role需要满足如下条件和策略:

点击下一步,由于tomcat生成的日志以空格分隔,所以我们选择Space Delimited的日志格式,设置Filter Pattern为日志设置schema,点击Test Pattern查看匹配效果。

我们可以看到日志被正确地匹配并生成了相应的schema,方便之后在Kibana中基于字段做搜索。

点击下一步后可以开始Streaming,我们可以登入Kibana界面,创建相应的index来进行日志的搜索,Kibana能够支持比CloudWatch logs界面更丰富的搜索功能,比如支持通配符方式的搜索。

通过ES API我们也能够对index的信息做查看:

在通过日志搜索来排查问题的应用场景中,我们经常只会对近几天的日志感兴趣,在不宕机的情况下AWS ES可以很方便地添加新的节点,最多能够支持到1.5PB,100个节点的规模,但是考虑到成本及具体场景,我们可以通过curator cli或者API实现ES中老旧的日志index的定期清理。在使用curator cli的情况下,我们需要通过一台EC2运行cron定时任务,这里我们选择使用curator python API,通过CloudWatch event结合lambda构建无服务器的定时任务。

本文中,我们通过AWS Cloud9云端IDE来编写代码,Cloud9能方便地创建并部署lambda,我们首先创建一个Cloud9环境,Cloud9环境的创建非常简单,只需要选取机型及VPC、subnet即可

创建完环境后,会自动跳转到代码编写界面,点击创建lambda:

配置lambda函数名字:

选择python2.7并任意选择一个模板:

我们暂时不设置触发器,先简单地为lambda分配admin权限:

修改lambda代码如下,并在CLI界面使用pip工具安装elasticsearch-curator package,本例用于匹配并删除以“cwl-”开头创建于1天之前的index,可以根据需要修改相应参数。

通过Cloud9我们可以简单测试一下代码的功能:

调试完成后,我们可以通过Cloud9一键部署lambda:

接下来我们利用CloudWatch event配置定时任务,定时运行lambda函数对ES中的日志进行清理。在这里,我们进入CloudWatch event界面,创建一个规则:

设置每天运行一次lambda函数:

通过CloudWatch查看lambda触发事件及相关日志:

以上即为针对AWS ECS容器集群管理服务的容器日志的解决方案,并包括日志产生后,整个生命周期中的搜集、汇聚、展示、搜索、清理、分析等实现。希望这些内容可以帮助大家更好的使用ECS 集群管理服务,更好的应用容器技术。

 

参考资料:

调整AWS ES默认的shard配置: http://www.havingatinker.uk/aws-elasticsearch-service-woes.html

Cloudwatch logging driver参数: https://docs.docker.com/engine/admin/logging/awslogs/

设置Kibana代理服务器及基本认证: http://blog.ruanbekker.com/blog/2017/09/16/nginx-reverse-proxy-for-elasticsearch-and-kibana-5-on-aws/

Curator Python API: https://curator.readthedocs.io/en/latest/