用Kibana将简单网站托管中的CloudFront实时日志可视化
首先
通过使用由亚马逊网络服务(AWS)提供的服务,如Amazon CloudFront和Amazon S3的组合,可以以低成本构建由HTML、JavaScript、图像和视频构成的静态网站的分发基础设施。本文将通过使用能够自动进行资源设置的AWS CloudFormation来说明如何迅速且无误地构建这些分发基础设施的步骤。请注意,本次使用的CloudFormation模板已在以下的GitHub存储库中公开。
- AWSCloudFormationTemplates/static-website-hosting-with-ssl
太长不读。
通过执行以下的CloudFormation模板,您可以快速且轻松地建立一个静态网站托管基础设施。只需点击下方按钮,即可在您的AWS账户(亚太地区东京 – ap-northeast-1)上运行这个CloudFormation模板。

请查看以前的文章以获取关于创建的AWS资源整体架构的图表。在本文中,我们将重点介绍以下资源。

使用Kibana来可视化CloudFront的实时日志。
与以往需要数分钟才能使用的标准日志相比,CloudFront的实时日志现在可以在生成后的几秒钟内访问。通过使用这个功能,我们可以进行更详细和更快速的监控,并及时根据发生的事件进行资源配置的快速更改。这个实时日志可以
-
- 取得するログのサンプリング率
-
- 取得するログのフィールド
- どのCloudFront Behavior に適用するか
可以指定任何日志,并将其发送到Kinesis Data Streams。同时,通过Kinesis Data Firehose,可以将到达Kinesis流的日志存储到Elasticsearch Service中,并通过使用Kibana轻松可视化日志内容。

通过按照这里列出的步骤来创建资源,可以构建以下架构。这些步骤在亚马逊网络服务(Amazon Web Services)博客上以标题“使用Amazon CloudFront日志创建实时仪表板”进行了发布。

本文中,我們將使用CloudFormation模板以一鍵方式創建上述架構。同時,我們還將解釋為每個AWS服務分配多少資源來應對負載所需。
亚马逊金融数据流
首先,我们需要创建一个Kinesis流来接收来自CloudFront的实时日志。
Parameters:
KinesisShardCount:
Type: Number
Default: 1
MinValue: 1
Description: The shard count of Kinesis [required]
Resources:
Kinesis:
Type: 'AWS::Kinesis::Stream'
Properties:
Name: !Ref AWS::StackName
RetentionPeriodHours: 24
StreamEncryption:
EncryptionType: KMS
KeyId: alias/aws/kinesis
ShardCount: !Ref KinesisShardCount
重要的是确定在这里使用多少个分片来构建Kinesis流。关于如何计算这个值,官方文档中提供了计算Kinesis数据流分片数的估算方法的描述,并且还包括了输出所有字段的实时日志的情况下,
1,000 Byte x 秒間リクエスト数 / 1,000,000 x 1.25 = シャード数
可以通过计算得出。
如果有可能发生最多每秒5000个请求的访问,请提供一个例子。
5,000 x 1,000 / 1,000,000 x 1.25 = 7
这样一来,我们可以看出,需要大约7个分片,包括缓存。
然而,对于出现突发流量的网站,由于每秒钟的日志输出会集中在特定的一秒钟,可能会超过文档中所述的值所能接收的数据量,从而导致出现 ProvisionedThroughputExceededException 异常。因此,为了保证安全,建议提前配置一个比文档中所述值更大的缓冲区,例如可以配置能够处理预期数据量的两倍的分片数量的分片。
根据流量调整分片数量
根据时间和事件的存在与否,CloudFront的流量会有所变动。由于Kinesis Data Streams的计费是按照分片数(分片时间)计费,并且无法接收超出其容量的实时日志,因此根据流向CloudFront的流量量,需要调整Kinesis流的分片数。
然而,在更改分片数量时存在一些限制。首先,调用UpdteShardCount API来更改分片数量只能执行将当前分片数量倍增或减半的操作。因此,无法将3个分片的Kinesis流更改为7个分片。因此,建议将分片数量设置为2的幂次方(1、2、4、8、16、32、64、128…)。此外,每个区域的初始分片数量为北弗吉尼亚(us-east-1)区域为500个分片,其他区域为200个分片。除此之外,对于执行UpdteShardCount API的次数还有限制。如果希望超过这些限制,请提交申请以放宽配额限制。
为了确认在Kinesis Data Streams中设置的容量是否适应负载,请监控以下CloudWatch指标。您可以从此链接中启用基于这些指标的CloudWatch警报。
亚马逊云端流量加速
接下来,进行CloudFront实时日志输出的配置。
首先,为了使CloudFront能够向Kinesis Data Streams输出日志,我们将使用IAM角色来授予权限。给予CloudFront的权限包括写入Kinesis的权限和创建用于数据加密的KMS密钥的权限。
Resources:
IAMRoleForCloudFrontRealtimeLog:
Type: 'AWS::IAM::Role'
Properties:
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal:
Service: cloudfront.amazonaws.com
Action: 'sts:AssumeRole'
Policies:
- PolicyName: !Sub '${AWS::StackName}-KinesisPutPolicy-${AWS::Region}'
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- 'kinesis:DescribeStreamSummary'
- 'kinesis:DescribeStream'
- 'kinesis:PutRecord'
- 'kinesis:PutRecords'
Resource:
- !GetAtt Kinesis.Arn
- Effect: Allow
Action:
- 'kms:GenerateDataKey'
Resource:
- !GetAtt KMSKey.Arn
RoleName: !Sub '${aws::StackName}-CloudFrontRealtimeLog-${AWS::Region}'
接下来,您需要指定先前创建的Kinesis Data Streams和IAM角色的ARN,以进行实时日志的配置。在字段(Fields)部分,您可以选择要输出至日志的字段。但在本模板中,我们将选择输出以下所有字段的配置。
User-Agent
ヘッダーの値cs-refererリクエスト内の Referer
ヘッダーの値cs-cookieリクエスト内の Cookie ヘッダーcs-uri-queryリクエスト URL のクエリ文字列の部分x-edge-response-result-typeビューワーにレスポンスを返す直前にサーバーがレスポンスを分類した方法x-forwarded-forリクエスト元のビューワーの IP アドレスssl-protocolリクエストとレスポンスを送信するためにビューワーとサーバーがネゴシエートした SSL/TLS プロトコルssl-cipherリクエストとレスポンスを暗号化するためにビューワーとサーバーがネゴシエートした SSL/TLS 暗号x-edge-result-typeサーバーが、最後のバイトを渡した後で、レスポンスを分類した方法fle-encrypted-fieldsサーバーが暗号化してオリジンに転送したフィールドレベル暗号化フィールドの数fle-statusリクエストボディが正常に処理されたかどうかを示すコードsc-content-typeレスポンスの HTTP Content-Type ヘッダーの値sc-content-lenレスポンスの HTTP Content-Length ヘッダーの値sc-range-start範囲の開始値sc-range-end範囲の終了値c-port閲覧者からのリクエストのポート番号x-edge-detailed-result-typex-edge-result-type と同じ値c-countryビューワーの IP アドレスによって決定される、ビューワーの地理的位置を表す国コードcs-accept-encodingビューワーリクエスト内の Accept-Encoding ヘッダーの値cs-acceptビューワーリクエスト内の Accept ヘッダーの値cache-behavior-path-patternビューワーリクエストに一致したキャッシュ動作を識別するパスパターンcs-headersビューワーリクエスト内の HTTP ヘッダーcs-header-namesビューワーリクエスト内の HTTP ヘッダーの名前cs-headers-countビューワーリクエスト内の HTTP ヘッダーの数此外,您可以通过更改SamplingRate值,在1%到100%之间指定CloudFront向Kinesis数据流发送日志的采样率。
Parameters:
SamplingRate:
Type: Number
Default: 100
MinValue: 1
MaxValue: 100
Description: The sampling rate of logs sent by CloudFront [required]
Resources:
CloudFrontRealtimeLogConfig:
Type: 'AWS::CloudFront::RealtimeLogConfig'
Properties:
EndPoints:
- KinesisStreamConfig:
RoleArn: !GetAtt IAMRoleForCloudFrontRealtimeLog.Arn
StreamArn: !GetAtt Kinesis.Arn
StreamType: Kinesis
Fields:
- timestamp
- c-ip
- time-to-first-byte
- sc-status
- sc-bytes
- cs-method
- cs-protocol
- cs-host
- cs-uri-stem
- cs-bytes
- x-edge-location
- x-edge-request-id
- x-host-header
- time-taken
- cs-protocol-version
- c-ip-version
- cs-user-agent
- cs-referer
- cs-cookie
- cs-uri-query
- x-edge-response-result-type
- x-forwarded-for
- ssl-protocol
- ssl-cipher
- x-edge-result-type
- fle-encrypted-fields
- fle-status
- sc-content-type
- sc-content-len
- sc-range-start
- sc-range-end
- c-port
- x-edge-detailed-result-type
- c-country
- cs-accept-encoding
- cs-accept
- cache-behavior-path-pattern
- cs-headers
- cs-header-names
- cs-headers-count
Name: RealtimeLogConfig
SamplingRate: !Ref SamplingRate
如果超过了已经配置的Kinesis流的容量并且生成了实时日志,超出容量的部分实时日志将会丢失。然而,这不会导致CloudFront分发的行为异常。
此外,CloudFront是AWS提供的全球服务,但是所有边缘位置的访问日志都会输出到接收实时日志的Kinesis流中。可以在x-edge-location字段中查看请求是在哪个边缘位置处理的。
当将上述的实时日志设置附加到以前创建的CloudFront分发上时,刚刚设置的实时日志输出将在CloudFront上生效。
CloudFront:
Type: 'AWS::CloudFront::Distribution'
Properties:
DistributionConfig:
DefaultCacheBehavior:
RealtimeLogConfigArn: !GetAtt CloudFrontRealtimeLogConfig.Arn
亚马逊弹性搜索服务 (Amazon Elasticsearch Service)
Elasticsearch是一种分布式分析引擎,可以进行各种类型的搜索,如结构化、非结构化、地理信息和指标,并对大规模数据进行分析。Amazon Elasticsearch Service是一个简单且可扩展地部署、保护和运行Elasticsearch的托管服务。
通过使用这个Elasticsearch服务,您可以保存和分析应用程序和基础设施的日志,以便快速发现问题,并为应用程序添加搜索功能。因此,我们将使用Elasticsearch来分析CloudFront的实时日志,并使用被称为Kibana的Elasticsearch可视化工具将其可视化。
Parameters:
ElasticSearchVolumeSize:
Type: Number
Default: 10
MinValue: 10
Description: The volume size (GB) of ElasticSearch Service [required]
ElasticSearchDomainName:
Type: String
Default: cloudfront-realtime-logs
AllowedPattern: .+
Description: The domain name of ElasticSearch Service [required]
ElasticSearchInstanceType:
Type: String
Default: r5.large.elasticsearch
AllowedValues:
- t3.small.elasticsearch
- t3.medium.elasticsearch
- t2.micro.elasticsearch
- t2.small.elasticsearch
- t2.medium.elasticsearch
- m5.large.elasticsearch
- m5.xlarge.elasticsearch
- m5.2xlarge.elasticsearch
- m5.4xlarge.elasticsearch
- m5.12xlarge.elasticsearch
- m4.large.elasticsearch
- m4.xlarge.elasticsearch
- m4.2xlarge.elasticsearch
- m4.4xlarge.elasticsearch
- m4.10xlarge.elasticsearch
- c5.large.elasticsearch
- c5.xlarge.elasticsearch
- c5.2xlarge.elasticsearch
- c5.4xlarge.elasticsearch
- c5.9xlarge.elasticsearch
- c5.18xlarge.elasticsearch
- c4.large.elasticsearch
- c4.xlarge.elasticsearch
- c4.2xlarge.elasticsearch
- c4.4xlarge.elasticsearch
- c4.8xlarge.elasticsearch
- r5.large.elasticsearch
- r5.xlarge.elasticsearch
- r5.2xlarge.elasticsearch
- r5.4xlarge.elasticsearch
- r5.12xlarge.elasticsearch
- r4.large.elasticsearch
- r4.xlarge.elasticsearch
- r4.2xlarge.elasticsearch
- r4.4xlarge.elasticsearch
- r4.8xlarge.elasticsearch
- r4.16xlarge.elasticsearch
- r3.large.elasticsearch
- r3.xlarge.elasticsearch
- r3.2xlarge.elasticsearch
- r3.4xlarge.elasticsearch
- r3.8xlarge.elasticsearch
- i3.large.elasticsearch
- i3.xlarge.elasticsearch
- i3.2xlarge.elasticsearch
- i3.4xlarge.elasticsearch
- i3.8xlarge.elasticsearch
- i3.16xlarge.elasticsearch
Description: The instance type of ElasticSearch Service [required]
ElasticSearchMasterUserName:
Type: String
AllowedPattern: .+
Description: The user name of ElasticSearch Service [required]
ElasticSearchMasterUserPassword:
Type: String
AllowedPattern: .+
NoEcho: true
Description: The password of ElasticSearch Service [required]
Resources:
KMSKey:
Type: AWS::KMS::Key
Properties:
Description: Encrypt CloudTrail Logs
Enabled: true
EnableKeyRotation: true
KeyPolicy:
Version: 2012-10-17
Id: DefaultKeyPolicy
Statement:
- Sid: Enable IAM User Permissions
Effect: Allow
Principal:
AWS: !Sub arn:aws:iam::${AWS::AccountId}:root
Action: 'kms:*'
Resource: '*'
- Effect: Allow
Principal:
Service: cloudtrail.amazonaws.com
Action:
- 'kms:GenerateDataKey*'
Resource:
- '*'
Condition:
StringLike:
kms:EncryptionContext:aws:cloudtrail:arn:
- !Sub arn:aws:cloudtrail:*:${AWS::AccountId}:trail/*
- Effect: Allow
Principal:
Service: cloudtrail.amazonaws.com
Action:
- 'kms:DescribeKey'
Resource:
- '*'
KeyUsage: ENCRYPT_DECRYPT
PendingWindowInDays: 30
ElasticSearchDomain:
Type: 'AWS::Elasticsearch::Domain'
Properties:
AccessPolicies:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
AWS:
- '*'
Action:
- es:*
Resource: !Sub arn:aws:es:${AWS::Region}:${AWS::AccountId}:domain/${ElasticSearchDomainName}/*
AdvancedSecurityOptions:
Enabled: true
InternalUserDatabaseEnabled: true
MasterUserOptions:
MasterUserName: !Ref ElasticSearchMasterUserName
MasterUserPassword: !Ref ElasticSearchMasterUserPassword
DomainEndpointOptions:
EnforceHTTPS: true
DomainName: !Ref ElasticSearchDomainName
EBSOptions:
EBSEnabled: true
VolumeSize: !Ref ElasticSearchVolumeSize
VolumeType: gp2
ElasticsearchClusterConfig:
DedicatedMasterCount: 3
DedicatedMasterEnabled: true
DedicatedMasterType: c5.large.elasticsearch
InstanceCount: 3
InstanceType: !Ref ElasticSearchInstanceType
ZoneAwarenessConfig:
AvailabilityZoneCount: 3
ZoneAwarenessEnabled: true
ElasticsearchVersion: 7.8
EncryptionAtRestOptions:
Enabled: true
KmsKeyId: !GetAtt KMSKey.Arn
NodeToNodeEncryptionOptions:
Enabled: true
SnapshotOptions:
AutomatedSnapshotStartHour: 0
以下是本模板的结构和注意事项。
DomainName には、「アカウントおよびリージョンに固有」「先頭が小文字」「3~28文字」「小文字のアルファベット、数字、ハイフンのみ使用可能」という制約が課せられています。
EBSOptions にて、アタッチするEBSボリュームのタイプとサイズを指定しています。
ElasticsearchClusterConfig にて、本番稼働用として奨励されている、マルチAZ + 専用データノード構成を規定しており、 データノード3台 + マスターノード3台 の構成としています。 AvailabilityZoneCount を3に設定しているため、 インスタンスは3つのAZに分散配置 されます。
EncryptionAtRestOptions にて、 保管時のデータ暗号化 を指定しています。 これと同時に 暗号化の際に使用するAWS KMSのカスタマーマスターキー(CMK)も作成 しています。
NodeToNodeEncryptionOptions にて、 ノード間の暗号化 を指定しています。
AutomatedSnapshotStartHour にて、 UTC時刻の午前0時にスナップショットが作成 されます。
访问控制
这个模板已经启用了细粒度访问控制(FGAC),下面是相关设置。

-
- 允许公共访问。
-
- 通过DomainEndpointOptions,强制使用HTTPS进行访问。
-
- 通过InternalUserDatabaseEnabled启用内部用户数据库,并通过MasterUserOptions指定主用户的用户名和密码。
- 通过AccessPolicies,允许执行Elasticsearch服务的所有操作。
通过上述设置,可以使用事先设置的用户名和密码,从外部访问该域和Kibana。
域名的尺寸配置
使用 Elasticsearch Service 时应注意的是选择哪种实例类型,以及需要准备多大的 EBS 卷。关于这一点,在官方文档的 Amazon ES 域大小调整部分有详细说明。
假设我们谈论存储空间,
ソースデータ x (1+ レプリカの数) x 1.45 = 最小ストレージ要件
如果要保存24小时的实时日志,而这个日志源产生的流量是每秒5,000个请求的CloudFront分配,可以使用以下方程式。
5,000(件) x 3,600(秒)x 24(時間) x 1,000(byte) = 432(GB)
原始数据为432GB,应用上述公式后,
432(GB) x (1 + 1) x 1.45 = 1252 (GB)
需要1252GB的存储空间。
另外,在上述示例中,源数据每小时以18GB的比例增加,这对Elasticsearch服务来说会产生巨大的负担。官方文档中指出,如果存在高负载的聚合处理、频繁的文档更新或大量的查询处理,这些资源可能无法满足需求。如果集群被归类到这种类别中,建议为每100 GiB的存储需求配置vCPU x 2核心和接近8 GiB内存的配置。将此建议应用于上述示例,
1252(GB)/ 100(GB)x 2 = 25(コア)
1252(GB)/ 100(GB)x 8 = 100(GBメモリ)
可以考虑需要的情况下。如上所述,由于此模板中准备了3个数据节点,所以每个实例所需的核数和内存大小是。
25(コア)/ 3 (台) = 8.3(コア)
100(GBメモリ)/ 3 (台) = 33.3(GBメモリ)
相邻的每个实例所需的EBS卷为:
1252(GB) / 3(台) = 417(GB)
以下のようになります。これに適合する インスタンス タイプ は、
m5.2xlarge.elasticsearch 以上のインスタンスタイプ
c5.4xlarge.elasticsearch 以上のインスタンスタイプ
r5.2xlarge.elasticsearch 以上のインスタンスタイプ
i3.2xlarge.elasticsearch 以上のインスタンスタイプ
在经验上,数据节点经常会出现堆空间不足的情况。因此,在上述示例中,选择作为内存优化实例的R5实例可能是一个不错的选择。关于主节点,可以参考独立主节点部分的内容。
根据描述,这个模板构建的配置似乎适用于c5.large.elasticsearch。但值得注意的是,这些值仅仅是计算上的数值,所以在决定数据节点和主节点的实例类型时,需要先施加预期的负载来验证其行为。
创建域后,如果要更改这些设置,则会执行Blue/Green部署过程并创建新的环境。由于这种设置更改需要时间且对主节点造成较大负载,因此需要足够的资源来处理与此部署过程相关的额外负荷。如果在资源不足的情况下进行设置更改,可能会导致设置更改(进行中)需要数小时才能完成。
请监控以下CloudWatch指标以确认Elasticsearch Service设置的容量是否适用于负载。您可以从此链接中基于这些指标批量启用CloudWatch警报。
努力数据传递
最后进行 Kinesis Data Firehose 的设置。Firehose 是一个可以接收流式数据并进行转换,并将其发送到 Amazon S3、Amazon Redshift、Amazon Elasticsearch Service、通用的 HTTP 终端等服务的工具。本次的目标是将从 Kinesis Stream 传输的实时日志发送到 Elasticsearch Service 中。
此外,在Kinesis流中,存储记录时需要进行Base64编码,因此实时日志也以Base64编码的状态进行存储。因此,我们可以使用Firehose的数据转换功能来进行目标列的Base64解码。Firehose的数据转换功能是通过将AWS Lambda与转换过程相关联来实现的。
这个Lambda函数所附加的IAM角色如下所示。给予Lambda函数的权限是将日志写入CloudWatch Logs的权限。
Resources:
IAMRoleForLambda:
Type: 'AWS::IAM::Role'
Properties:
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal:
Service: lambda.amazonaws.com
Action: 'sts:AssumeRole'
Description: A role required for Lambda to execute.
Policies:
- PolicyName: !Sub '${AWS::StackName}-AWSLambdaCloudWatchLogsPolicy-${AWS::Region}'
PolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action:
- 'logs:CreateLogStream'
Resource: '*'
- Effect: Allow
Action:
- 'logs:PutLogEvents'
Resource: '*'
RoleName: !Sub '${AWS::StackName}-Lambda-${AWS::Region}'
而且,执行数据转换处理的Lambda函数如下所示。
Resources:
Lambda:
Type: 'AWS::Lambda::Function'
Properties:
Code:
ZipFile: |
import logging
import base64
import json
logger = logging.getLogger()
logger.setLevel(logging.INFO)
logger.info("Loading function")
def lambda_handler(event, context):
output = []
# Based on the fields chosen during the creation of the Real-time log configuration.
# The order is important and please adjust the function if you have removed certain default fields from the configuration.
realtimelog_fields_dict = {
"timestamp": "float",
"c-ip": "str",
"time-to-first-byte": "float",
"sc-status": "int",
"sc-bytes": "int",
"cs-method": "str",
"cs-protocol": "str",
"cs-host": "str",
"cs-uri-stem": "str",
"cs-bytes": "int",
"x-edge-location": "str",
"x-edge-request-id": "str",
"x-host-header": "str",
"time-taken": "float",
"cs-protocol-version": "str",
"c-ip-version": "str",
"cs-user-agent": "str",
"cs-referer": "str",
"cs-cookie": "str",
"cs-uri-query": "str",
"x-edge-response-result-type": "str",
"x-forwarded-for": "str",
"ssl-protocol": "str",
"ssl-cipher": "str",
"x-edge-result-type": "str",
"fle-encrypted-fields": "str",
"fle-status": "str",
"sc-content-type": "str",
"sc-content-len": "int",
"sc-range-start": "int",
"sc-range-end": "int",
"c-port": "int",
"x-edge-detailed-result-type": "str",
"c-country": "str",
"cs-accept-encoding": "str",
"cs-accept": "str",
"cache-behavior-path-pattern": "str",
"cs-headers": "str",
"cs-header-names": "str",
"cs-headers-count": "int",
}
for record in event["records"]:
# Extracting the record data in bytes and base64 decoding it
payload_in_bytes = base64.b64decode(record["data"])
# Converting the bytes payload to string
payload = "".join(map(chr, payload_in_bytes))
# dictionary where all the field and record value pairing will end up
payload_dict = {}
# counter to iterate over the record fields
counter = 0
# generate list from the tab-delimited log entry
payload_list = payload.strip().split("\t")
# perform the field, value pairing and any necessary type casting.
# possible types are: int, float and str (default)
for field, field_type in realtimelog_fields_dict.items():
# overwrite field_type if absent or '-'
if payload_list[counter].strip() == "-":
field_type = "str"
if field_type == "int":
payload_dict[field] = int(payload_list[counter].strip())
elif field_type == "float":
payload_dict[field] = float(payload_list[counter].strip())
else:
payload_dict[field] = payload_list[counter].strip()
counter = counter + 1
# JSON version of the dictionary type
payload_json = json.dumps(payload_dict)
# Preparing JSON payload to push back to Firehose
payload_json_ascii = payload_json.encode("ascii")
output_record = {
"recordId": record["recordId"],
"result": "Ok",
"data": base64.b64encode(payload_json_ascii).decode("utf-8"),
}
output.append(output_record)
logger.info("Successfully processed {} records.".format(len(event["records"])))
return {"records": output}
Description: CloudFrontログを変換します
FunctionName: realtimeLogsTransformer
Handler: index.lambda_handler
MemorySize: 512
Role: !GetAtt IAMRoleForLambda.Arn
Runtime: python3.8
Timeout: 60
TracingConfig:
Mode: Active
LambdaLogGroup:
Type: 'AWS::Logs::LogGroup'
Properties:
LogGroupName: !Sub /aws/lambda/${Lambda}
RetentionInDays: 60
接下来,如果从Firehose到Elasticsearch Service的传输失败,我们也会预先创建一个用于存储实时日志的S3存储桶作为替代方案。
Resources:
S3ForKinesisFirehose:
Type: 'AWS::S3::Bucket'
UpdateReplacePolicy: Retain
DeletionPolicy: Retain
Properties:
BucketEncryption:
ServerSideEncryptionConfiguration:
- ServerSideEncryptionByDefault:
SSEAlgorithm: AES256
BucketName: !Sub ${ElasticSearchDomainName}-${AWS::Region}-${AWS::AccountId}
LifecycleConfiguration:
Rules:
- Id: ExpirationInDays
ExpirationInDays: 60
Status: Enabled
PublicAccessBlockConfiguration:
BlockPublicAcls: true
BlockPublicPolicy: true
IgnorePublicAcls: true
RestrictPublicBuckets: true
此外,将在IAM角色中指定授予Firehose的权限。
IAMRoleForKinesisFirehose:
Type: 'AWS::IAM::Role'
Properties:
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal:
Service: firehose.amazonaws.com
Action: 'sts:AssumeRole'
Description: A role required for KinesisFirehose to access Glue, S3, Lambda, CloudWatch Logs, Kinesis and KMS.
Policies:
- PolicyName: !Sub '${AWS::StackName}-FirehoseDelivery-${AWS::Region}'
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- 's3:AbortMultipartUpload'
- 's3:GetBucketLocation'
- 's3:GetObject'
- 's3:ListBucket'
- 's3:ListBucketMultipartUploads'
- 's3:PutObject'
Resource:
- !Sub 'arn:aws:s3:::${S3ForKinesisFirehose}'
- !Sub 'arn:aws:s3:::${S3ForKinesisFirehose}/*'
- Effect: Allow
Action:
- 'kms:Decrypt'
- 'kms:GenerateDataKey'
Resource:
- !GetAtt KMSKey.Arn
Condition:
StringEquals:
'kms:ViaService': s3.region.amazonaws.com
StringLike:
'kms:EncryptionContext:aws:s3:arn': !Sub 'arn:aws:s3:::${S3ForKinesisFirehose}/*'
- Effect: Allow
Action:
- 'es:DescribeElasticsearchDomain'
- 'es:DescribeElasticsearchDomains'
- 'es:DescribeElasticsearchDomainConfig'
- 'es:ESHttpPost'
- 'es:ESHttpPut'
Resource:
- !Sub 'arn:aws:es:${AWS::Region}:${AWS::AccountId}:domain/${ElasticSearchDomainName}'
- !Sub 'arn:aws:es:${AWS::Region}:${AWS::AccountId}:domain/${ElasticSearchDomainName}/*'
- Effect: Allow
Action:
- 'es:ESHttpGet'
Resource:
- !Sub 'arn:aws:es:${AWS::Region}:${AWS::AccountId}:domain/${ElasticSearchDomainName}/_all/_settings'
- !Sub 'arn:aws:es:${AWS::Region}:${AWS::AccountId}:domain/${ElasticSearchDomainName}/_cluster/stats'
- !Sub 'arn:aws:es:${AWS::Region}:${AWS::AccountId}:domain/${ElasticSearchDomainName}/realtime*/_mapping/*'
- !Sub 'arn:aws:es:${AWS::Region}:${AWS::AccountId}:domain/${ElasticSearchDomainName}/_nodes'
- !Sub 'arn:aws:es:${AWS::Region}:${AWS::AccountId}:domain/${ElasticSearchDomainName}/_nodes/stats'
- !Sub 'arn:aws:es:${AWS::Region}:${AWS::AccountId}:domain/${ElasticSearchDomainName}/_nodes/*/stats'
- !Sub 'arn:aws:es:${AWS::Region}:${AWS::AccountId}:domain/${ElasticSearchDomainName}/_stats'
- !Sub 'arn:aws:es:${AWS::Region}:${AWS::AccountId}:domain/${ElasticSearchDomainName}/realtime*/_stats'
- Effect: Allow
Action:
- 'kinesis:DescribeStream'
- 'kinesis:GetShardIterator'
- 'kinesis:GetRecords'
- 'kinesis:ListShards'
Resource: !GetAtt Kinesis.Arn
- Effect: Allow
Action:
- 'logs:PutLogEvents'
Resource:
- !Sub 'arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:${CloudWatchLogsGroupForFirehose}:log-stream:${CloudWatchLogsStreamForFirehoseElasticSearch}'
- !Sub 'arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:${CloudWatchLogsGroupForFirehose}:log-stream:${CloudWatchLogsStreamForFirehoseS3}'
- Effect: Allow
Action:
- 'lambda:InvokeFunction'
- 'lambda:GetFunctionConfiguration'
Resource:
- !GetAtt Lambda.Arn
- Effect: Allow
Action:
- 'kms:Decrypt'
Resource:
- !GetAtt KMSKey.Arn
Condition:
StringEquals:
'kms:ViaService': kinesis.ap-northeast-1.amazonaws.com
StringLike:
'kms:EncryptionContext:aws:kinesis:arn': !GetAtt Kinesis.Arn
RoleName: !Sub '${AWS::StackName}-Firehose-${AWS::Region}'
最后,我们将创建一个Firehose,指定Elasticsearch Service和S3作为实时日志的传送目标,并提供Lambda函数来进行数据转换。为了尽可能减少向Elasticsearch Service传送数据时的延迟,我们将设置BufferingHints为可配置的最小值。此外,通过将S3BackupMode设置为FailedDocumentsOnly,仅在将日志传送到Elasticsearch Service失败时,将实时日志保存到S3中。AWS::KinesisFirehose::DeliveryStream的某些属性在更新时的行为为Replacement,也就是在更新时需要重新创建Firehose资源并生成新的物理ID。因此,如果要更新这些属性的值,请同时更新DeliveryStreamName的值。
Resources:
KinesisFirehose:
Type: 'AWS::KinesisFirehose::DeliveryStream'
Properties:
DeliveryStreamName: !Sub ${AWS::StackName}-${KinesisFirehoseStreamNameSuffix}
DeliveryStreamType: KinesisStreamAsSource
KinesisStreamSourceConfiguration:
KinesisStreamARN: !GetAtt Kinesis.Arn
RoleARN: !GetAtt IAMRoleForKinesisFirehose.Arn
ElasticsearchDestinationConfiguration:
BufferingHints:
IntervalInSeconds: 60
SizeInMBs: 1
CloudWatchLoggingOptions:
Enabled: true
LogGroupName: !Ref CloudWatchLogsGroupForFirehose
LogStreamName: !Ref CloudWatchLogsStreamForFirehoseS3
DomainARN: !GetAtt ElasticSearchDomain.DomainArn
IndexName: realtime
IndexRotationPeriod: NoRotation
ProcessingConfiguration:
Enabled: true
Processors:
- Parameters:
- ParameterName: LambdaArn
ParameterValue: !GetAtt Lambda.Arn
Type: Lambda
RetryOptions:
DurationInSeconds: 300
RoleARN: !GetAtt IAMRoleForKinesisFirehose.Arn
S3BackupMode: FailedDocumentsOnly
S3Configuration:
BucketARN: !GetAtt S3ForKinesisFirehose.Arn
CloudWatchLoggingOptions:
Enabled: true
LogGroupName: !Ref CloudWatchLogsGroupForFirehose
LogStreamName: !Ref CloudWatchLogsStreamForFirehoseElasticSearch
RoleARN: !GetAtt IAMRoleForKinesisFirehose.Arn
TypeName: ''
CloudWatchLogsGroupForFirehose:
Type: 'AWS::Logs::LogGroup'
Properties:
LogGroupName: !Sub '/aws/kinesisfirehose/${AWS:StackName}'
RetentionInDays: 60
CloudWatchLogsStreamForFirehoseS3:
Type: 'AWS::Logs::LogStream'
Properties:
LogGroupName: !Ref CloudWatchLogsGroupForFirehose
LogStreamName: S3
CloudWatchLogsStreamForFirehoseElasticSearch:
Type: 'AWS::Logs::LogStream'
Properties:
LogGroupName: !Ref CloudWatchLogsGroupForFirehose
LogStreamName: ElasticSearch
以上是完成了所有必需的资源设置,以可视化CloudFront的实时日志。通过执行此CloudFormation模板,每个资源将被部署。
另外,请监控以下CloudWatch指标以确认Firehose是否正常工作。您可以通过此链接,批量启用基于这些指标的CloudWatch警报。
Kibana的配置
一旦上述资源的部署完成后,将为Elasticsearch中导入的数据指定索引,并进行使用Kibana进行可视化的设置。关于此步骤的详细信息,请参见此处,并与本文一起阅读。通过执行以下操作,Firehose将能够向Elasticsearch投放数据,并自动创建必要的图表和仪表板以进行可视化。
Security の Roles を選択します。

+ アイコンをクリックして新しいロールを追加します。
作成したロールに firehose という名前をつけます。

Cluster Permissions タブの Cluster-wide permissions で cluster_composite_ops cluster_monitor グループを追加します。

Index Permissions タブの Add index permissions から Index Patterns を選んで realtime* を入力します。Permissions: Action Groups で crud create_index manage アクショングループを追加します。

Save Role Definition をクリックします。
Security の Role Mappings を選択します。

Add Backend Role をクリックします。
先ほど作成した firehoseを選択します。
Backend roles に Kinesis Data Firehose が Amazon ES および S3 に書き込むために使用する IAM ロールの ARN を入力します。

Submit をクリックします。
Dev Tools を選択します。
timestamp フィールドを date タイプと認識させるために、以下のコマンドを入力して実行します。
PUT _template/custom_template
{
"template": "realtime*",
"mappings": {
"properties": {
"timestamp": {
"type": "date",
"format": "epoch_second"
}
}
}
}

インデックス および visualizes と dashboard の設定ファイル をインポートします。
我們成功在AWS上搭建了一個使用Kibana來實時查看CloudFront日誌的環境。
实时仪表盘
当您完成上述设置后,您可以登录Kibana并实时查看下列数据的图表等信息。
仪表板
可以通过一屏幕查看所有已创建的图表。

展现形象
每个图形如下:
每秒请求数

国家

响应时间

内容类型

响应码

结果类型

通过提取实时日志的任意字段,我们可以可视化各种数据,并实时确认其变化。这将使得网站的运营监控体系更加灵活和细致,我认为可以建立起比以往更高效的运维监控体系。
相关链接
-
- 使用CloudFormation一键搭建分发基础设施-通过CloudFormation轻松实现网站托管
-
- 使用CloudFormation将WAF与CloudFront进行关联-通过CloudFormation轻松实现网站托管
-
- 使用CloudFormation定期监测特定URL-通过CloudFormation轻松实现网站托管
使用CloudFormation将CloudFront的实时日志在Kibana中进行可视化-通过CloudFormation轻松实现网站托管