= Kubernetes Cluster Logging using Elasticsearch, Fluentd, and Kibana
:toc:
:icons:
:linkcss:
:imagesdir: ../../resources/images
There are many options for aggregating and streaming kubernetes logs. In this part of the workshop, we are going to focus on an AWS based deployment which consists of the following:
. https://www.fluentd.org/[Fluentd] is an open source data collector providing a unified logging layer, supported by 500+ plugins connecting to many types of systems.
. https://www.elastic.co/products/elasticsearch[Elasticsearch] is a distributed, RESTful search and analytics engine.
. https://www.elastic.co/products/kibana[Kibana] lets you visualize your Elasticsearch data.
Together, Fluentd, Elasticsearch and Kibana is also known as "`EFK stack`".
In terms of architecture, Fluentd is deployed as a DaemonSet with the CloudWatch Logs plugin. The default configuration will stream system logs, Kubernetes container logs and Kubernetes API server audit logs to a CloudWatch log group. An AWS Lambda function, which is provided for you, will stream the Log Group into an Amazon Elasticsearch cluster. The logs can then be viewed using a Kibana dashboard.
== Prerequisites
In order to perform exercises in this chapter, you’ll need to deploy configurations to a Kubernetes cluster. To create an EKS-based Kubernetes cluster, use the link:../../01-path-basics/102-your-first-cluster#create-a-kubernetes-cluster-with-eks[AWS CLI] (recommended). If you wish to create a Kubernetes cluster without EKS, you can instead use link:../../01-path-basics/102-your-first-cluster#alternative-create-a-kubernetes-cluster-with-kops[kops].
All configuration files for this chapter are in the `02-path-working-with-clusters/204-cluster-logging-with-EFK` directory. Make sure you change to that directory before giving any commands in this chapter.
== Provision an Amazon Elasticsearch cluster
This example creates a two instance Amazon Elasticsearch cluster named `kubernetes-logs`. This cluster is created in the same region as the Kubernetes cluster and CloudWatch log group. Note that this cluster has an open access policy which will need to be locked down in production environments:
aws es create-elasticsearch-domain \
--domain-name kubernetes-logs \
--elasticsearch-version 5.5 \
--elasticsearch-cluster-config \
InstanceType=m4.large.elasticsearch,InstanceCount=2 \
--ebs-options EBSEnabled=true,VolumeType=standard,VolumeSize=100 \
--access-policies '{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Principal":{"AWS":["*"]},"Action":["es:*"],"Resource":"*"}]}'
It takes a little while for the cluster to be created and arrive at an `active` state. The https://console.aws.amazon.com/es/home[AWS Console] should show the following status when the cluster is ready:
image::logging-cloudwatch-es-cluster.png[]
Look for the word `Active` in the right column.
You could also check this via AWS CLI:
$ aws es describe-elasticsearch-domain --domain-name kubernetes-logs --query 'DomainStatus.Processing'
false
If the output value is `false` that means the domain has been processed and is now available to use.
== CloudWatch Log Group
A CloudWatch log group combines log streams that share the same retention, monitoring, and access control settings.
Create a CloudWatch log group:
aws logs create-log-group --log-group-name kubernetes-logs
== Deploy Fluentd
=== Log group name and log stream name
Fluentd log group name and stream name are configured in the file `templates/fluentd-configmap.yaml`. An excerpt from the file is shown:
output.conf: |
# Plugin specific settings
type cloudwatch_logs
log_group_name kubernetes-logs
log_stream_name fluentd-cloudwatch
auto_create_stream true
# Buffer settings
buffer_chunk_limit 2M
buffer_queue_limit 32
flush_interval 10s
max_retry_wait 30
disable_retry_limit
num_threads 8
It uses the default log group name of `kubernetes-logs` and the log stream name of `fluentd-cloudwatch`.
If you've followed the instructions in this chapter as is, then no change is required in this configuration file. However if a different log group name is used in the previous command or a different log stream name is needed, then that needs to be configured in this configuration file.
=== IAM configuration
You will need to create an IAM user and set the `AWS_ACCESS_KEY`, `AWS_SECRET_KEY` and `AWS_REGION` in the `templates/fluentd-ds.yaml` file. Other options to accomplish this (in a production environment) are to use either kubernetes secrets or EC2 IAM roles.
env:
- name: FLUENTD_CONFIG
value: fluentd-standalone.conf
- name: AWS_REGION
value: $REGION
- name: AWS_ACCESS_KEY
value: $ACCESS_KEY
- name: AWS_SECRET_KEY
value: $SECRET_KEY
If creating an IAM user, the associated policy needs the following permissions
```
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"logs:DescribeLogGroups"
],
"Resource": [
"arn:aws:logs:us-east-1::log-group::log-stream:*"
]
},
{
"Effect": "Allow",
"Action": [
"logs:DescribeLogStreams"
],
"Resource": [
"arn:aws:logs:us-east-1::log-group:kubernetes-logs:log-stream:*"
]
},
{
"Effect": "Allow",
"Action": [
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Resource": [
"arn:aws:logs:us-east-1::log-group:kubernetes-logs:log-stream:fluentd-cloudwatch"
]
}
]
}
```
=== Create Kubernetes resources
First create the logging namespace
$ kubectl create ns logging
namespace "logging" created
Create all of the necessary service accounts and roles:
$ kubectl create -f ./templates/fluentd-service-account.yaml
serviceaccount "fluentd" created
$ kubectl create -f ./templates/fluentd-role.yaml
clusterrole "fluentd-read" created
$ kubectl create -f ./templates/fluentd-role-binding.yaml
clusterrolebinding "fluentd-read" created
Then deploy Fluentd:
$ kubectl create -f ./templates/fluentd-configmap.yaml
configmap "fluentd-config" created
$ kubectl create -f ./templates/fluentd-svc.yaml
service "fluentd" created
$ kubectl create -f ./templates/fluentd-ds.yaml
daemonset "fluentd" created
Watch for all of the pods to change to running status:
$ kubectl get pods -w --namespace=logging
NAME READY STATUS RESTARTS AGE
fluentd-00zxr 1/1 Running 0 58s
fluentd-05hc0 1/1 Running 0 58s
fluentd-089s4 1/1 Running 0 58s
fluentd-v4vjp 1/1 Running 0 58s
fluentd-zv6bv 1/1 Running 0 58s
Remember, Fluentd is deployed as a DaemonSet, i.e. one pod per worker node, so your output will vary depending on the size of your cluster. In our case, a 5 node cluster is used and so 5 pods are shown in the output.
We can now login to the AWS console -> Management Tools -> CloudWatch -> Logs -> kubernetes-logs -> fluentd-cloudwatch
We should start to see logs arrive into the service and can use the search feature to looks for specific logs. It looks like as shown:
image::logging-cloudwatch-fluentd-stream.png[]
== Subscribe a CloudWatch Log Group to Amazon Elastisearch
CloudWatch Logs can be delivered to other services such as Amazon Elasticsearch for custom processing. This can be achieved by subscribing to a real-time feed of log events. A subscription filter defines the filter pattern to use for filtering which log events gets delivered to Elasticsearch, as well as information about where to send matching log events to.
In this section, we'll subscribe to the CloudWatch log events from the `fluent-cloudwatch` stream from the `kubernetes-logs` log group. This feed will be streamed to the Elasticsearch cluster.
Original instructions for this are available at:
http://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/CWL_ES_Stream.html
The instructions below show how this can be achieved for our setup:
. Open the CloudWatch console at https://console.aws.amazon.com/cloudwatch/.
. In the navigation pane, choose `Logs`.
. Select the log group to subscribe.
. Choose `Actions`, `Stream to Amazon Elasticsearch Service`.
+
image::logging-cloudwatch-es-subscribe.png[]
+
. Select the IAM role
+
image::logging-cloudwatch-es-subscribe-iam.png[]
+
. Click on `Next`.
. Select a Log Format:
+
image::logging-cloudwatch-es-subscribe-log-format.png[]
+
The fields that are sent to the Elasticsearch cluster can be selected. Optionally, you can select a log stream and then click on `Test Pattern` to verify that your search filter is returning the results you expect.
. Click on `Next`
. Review all the information:
+
image::logging-cloudwatch-es-subscribe-confirmation.png[]
+
. Click on `Next` and then `Start streaming`:
+
image::logging-cloudwatch-es-subscribe-start-streaming.png[]
+
. Cloudwatch page is refreshed to show that the filter was successfully created:
+
image::logging-cloudwatch-es-subscribe-filter-created.png[]
== Kibana dashboard
In https://console.aws.amazon.com/es/home?#kubernetes-logs:dashboard[Amazon Elasticsearch console], select the Elasticsearch cluster.
image::logging-cloudwatch-es-overview.png[]
Open the Kibana dashboard from the link:
image::logging-cloudwatch-kibana-default.png[]
Begin using the capabilites to search and visuzalize your Kubernetes cluster metrics.
== Delete resources
Delete the resources created during this chapter:
```
kubectl delete ns logging
aws es delete-elasticsearch-domain --domain-name kubernetes-logs
aws logs delete-log-group --log-group-name kubernetes-logs
```
You are now ready to continue on with the workshop!
:frame: none
:grid: none
:valign: top
[align="center", cols="1", grid="none", frame="none"]
|=====
|image:button-continue-operations.png[link=../../02-path-working-with-clusters/204-cluster-logging-with-EFK]
|link:../../operations-path.adoc[Go to Operations Index]
|=====