EKS Container Logs Module
This Terraform Module installs and configures aws-for-fluent-bit on an EKS cluster, so that each node runs fluent-bit to collect the logs and ship to CloudWatch Logs, Kinesis Streams, or Kinesis Firehose.
This module uses the community helm chart, with a set of best practices inputs.
This module is for setting up log aggregation for EKS Pods on EC2 workers (self-managed or managed node groups). For Fargate pods, take a look at the eks-fargate-container-logs module.
How does this work?
This module solves the problem of unifying the log streams in your Kubernetes cluster to be shipped to an aggregation
service on AWS (CloudWatch Logs, Kinesis, or Firehose) so that you have a single interface to search and monitor your
logs. To achieve this, the module installs a service (fluent-bit
) that monitors the log files on the filesystem,
parses custom log formats into a unified format, and ships the result to a centralized log aggregation service
(CloudWatch).
fluent-bit
is installed as a Kubernetes
DaemonSet
, which ensures that there is one
fluent-bit
Pod
running per node. In this way, we are able to ensure that all workers in the cluster are running the
fluent-bit
service for shipping the logs into CloudWatch.
You can read more about fluent-bit
in their official home page. You can also learn more about
CloudWatch logging in the official AWS
docs.
What is the difference with fluentd?
fluent-bit is an optimized version of fluentd that focuses on
streaming and aggregating log files. fluentd
has a larger ecosystem of plugins that enable various processing
capabilities on top of the logs prior to aggregating in the data store.
For most EKS deployments, it is recommended to use this fluent-bit
module for container log aggregation. Unless you have a specific
need for a plugin only supported by fluentd
, the superior performance and memory footprint of fluent-bit
will
ensure resources are available on your EKS workers for your Pods.
Log format
This module leverages native plugins for Kubernetes built into fluent-bit
that extract additional
metadata for each Pod that is reporting. Each log is shipped to the respective outputs in the following structure:
{
"kubernetes": {
"namespace_name": "NAMESPACE_WHERE_POD_LOCATED",
"pod_name": "NAME_OF_POD_EMITTING_LOG",
"pod_id": "ID_IN_KUBERNETES_OF_POD",
"container_hash": "KUBERNETES_GENERATED_HASH_OF_CONTAINER_EMITTING_LOG",
"container_name": "NAME_OF_CONTAINER_IN_POD_EMITTING_LOG",
"docker_id": "ID_IN_DOCKER_OF_CONTAINER",
"host": "NODE_NAME_OF_HOST_EMITTING_LOG",
"labels": {
"KEY": "VALUE",
},
"annotations": {
"KEY": "VALUE"
}
},
"log": "CONTENTS_OF_LOG_MESSAGE",
"stream": "STDERR_OR_STDOUT",
"time": "TIMESTAMP_OF_LOG"
}
This allows you to filter and search the logs by the respective attributes. For example, the following CloudWatch
Insights Query can be used to search for all logs from Pods in the kube-system
Namespace:
fields @timestamp, @message
| filter kubernetes.namespace_name = "kube-system"
| sort @timestamp desc
| limit 20
Reference
- Inputs
- Outputs
Required
iam_role_for_service_accounts_config
object(…)Configuration for using the IAM role with Service Accounts feature to provide permissions to the helm charts. This expects a map with two properties: openid_connect_provider_arn
and openid_connect_provider_url
. The openid_connect_provider_arn
is the ARN of the OpenID Connect Provider for EKS to retrieve IAM credentials, while openid_connect_provider_url
is the URL. Set to null if you do not wish to use IAM role with Service Accounts.
object({
openid_connect_provider_arn = string
openid_connect_provider_url = string
})
Optional
additional_inputs
stringCan be used to add more inputs. This string should be formatted according to Fluent Bit docs, as it will be injected directly into the fluent-bit.conf file.
""
aws_elasticsearch_configuration
object(…)Configurations for forwarding logs to AWS managed Elasticsearch. Set to null if you do not wish to forward the logs to ES.
object({
# The AWS region where the Elasticsearch instance is deployed.
region = string
# Elasticsearch endpoint to ship logs to.
endpoint = object({
host = string
port = number
})
# Whether or not AWS based authentication and authorization is enabled on the Elasticsearch instance.
use_aws_auth = bool
# Whether or not TLS is enabled on the Elasticsearch endpoint.
use_tls = bool
# Match string for logs to send to Elasticsearch.
match = string
})
null
Details
Elasticsearch endpoint to ship logs to.
Details
Whether or not AWS based authentication and authorization is enabled on the Elasticsearch instance.
Details
Whether or not TLS is enabled on the Elasticsearch endpoint.
Details
Match string for logs to send to Elasticsearch.
The version of the aws-for-fluent-bit helm chart to deploy. Note that this is different from the app/container version (use aws_for_fluent_bit_version
to control the app/container version).
"0.1.15"
The Container repository to use for looking up the aws-for-fluent-bit Container image when deploying the pods. When null, uses the default repository set in the chart.
null
Which version of aws-for-fluent-bit to install. When null, uses the default version set in the chart.
null
aws_partition
stringThe AWS partition used for default AWS Resources.
"aws"
cloudwatch_configuration
object(…)Configurations for forwarding logs to CloudWatch Logs. Set to null if you do not wish to forward the logs to CloudWatch Logs.
object({
# The AWS region that holds the CloudWatch Log Group where the logs will be streamed to.
region = string
# The name of the AWS CloudWatch Log Group to use for all the logs shipped by the cluster. Set to null to use chart
# default (`/aws/eks/fluentbit-cloudwatch/logs`).
log_group_name = string
# Prefix to append to all CloudWatch Log Streams in the group shipped by fluentbit. Use "" if you do not with to
# attach a prefix, or null to use chart default (`fluentbit-`).
log_stream_prefix = string
})
null
Details
The name of the AWS CloudWatch Log Group to use for all the logs shipped by the cluster. Set to null to use chart
default (`/aws/eks/fluentbit-cloudwatch/logs`).
Details
Prefix to append to all CloudWatch Log Streams in the group shipped by fluentbit. Use "" if you do not with to
attach a prefix, or null to use chart default (`fluentbit-`).
dependencies
list(string)Create a dependency between the resources in this module to the interpolated values in this list (and thus the source resources). In other words, the resources in this module will now depend on the resources backing the values in this list such that those resources need to be created before the resources in this module, and the resources in this module need to be destroyed before the resources in the list.
[]
extra_filters
stringCan be used to provide custom filtering of the log output. This string should be formatted according to Fluent Bit docs, as it will be injected directly into the fluent-bit.conf file.
""
extra_outputs
stringCan be used to fan out the log output to multiple additional clients beyond the AWS ones. This string should be formatted according to Fluent Bit docs, as it will be injected directly into the fluent-bit.conf file.
""
firehose_configuration
object(…)Configurations for forwarding logs to Kinesis Firehose. Set to null if you do not wish to forward the logs to Firehose.
object({
# The AWS region that holds the Firehose delivery stream.
region = string
# The name of the delivery stream you want log records sent to. This must already exist.
delivery_stream_name = string
})
null
Details
The name of the delivery stream you want log records sent to. This must already exist.
iam_role_name_prefix
stringUsed to name IAM roles for the service account. Recommended when iam_role_for_service_accounts_config
is configured.
null
kinesis_configuration
object(…)Configurations for forwarding logs to Kinesis stream. Set to null if you do not wish to forward the logs to Kinesis.
object({
# The AWS region that holds the Kinesis stream.
region = string
# The name of the stream you want log records sent to. This must already exist.
stream_name = string
})
null
Details
The name of the stream you want log records sent to. This must already exist.
pod_node_affinity
list(object(…))Configure affinity rules for the Pod to control which nodes to schedule on. Each item in the list should be a map with the keys key
, values
, and operator
, corresponding to the 3 properties of matchExpressions. Note that all expressions must be satisfied to schedule on the node.
list(object({
key = string
values = list(string)
operator = string
}))
[]
Details
Each item in the list represents a matchExpression for requiredDuringSchedulingIgnoredDuringExecution.
https://kubernetes.io/docs/concepts/configuration/assign-pod-node/affinity-and-anti-affinity for the various
configuration option.
Example:
[
{
"key" = "node-label-key"
"values" = ["node-label-value", "another-node-label-value"]
"operator" = "In"
}
]
Translates to:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: node-label-key
operator: In
values:
- node-label-value
- another-node-label-value
Specify the resource limits and requests for the fluent-bit pods. Set to null (default) to use chart defaults.
Any types represent complex values of variable type. For details, please consult `variables.tf` in the source repo.
null
Details
This object is passed through to the resources section of a pod spec as described in
https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/
Example:
{
requests = {
cpu = "250m"
memory = "128Mi"
}
limits = {
cpu = "500m"
memory = "256Mi"
}
}
Configure tolerations rules to allow the Pod to schedule on nodes that have been tainted. Each item in the list specifies a toleration rule.
Any types represent complex values of variable type. For details, please consult `variables.tf` in the source repo.
[]
Details
Each item in the list represents a particular toleration. See
https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/ for the various rules you can specify.
Example:
[
{
key = "node.kubernetes.io/unreachable"
operator = "Exists"
effect = "NoExecute"
tolerationSeconds = 6000
}
]
Optionally use a cri parser instead of the default Docker parser. This should be used for EKS v1.24 and later.
true
When true, all IAM policies will be managed as dedicated policies rather than inline policies attached to the IAM roles. Dedicated managed policies are friendlier to automated policy checkers, which may scan a single resource for findings. As such, it is important to avoid inline policies when targeting compliance with various security standards.
true