terraform/eks/daemon/fluent/bit/main.tf (474 lines of code) (raw):
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: MIT
module "fluent_common" {
source = "../common"
ami_type = var.ami_type
instance_type = var.instance_type
}
resource "kubernetes_config_map" "cluster_info" {
depends_on = [
module.fluent_common
]
metadata {
name = "fluent-bit-cluster-info"
namespace = "amazon-cloudwatch"
}
data = {
"cluster.name" = module.fluent_common.cluster_name
"logs.region" = var.region
"http.server" = "On"
"http.port" = "2020"
"read.head" = "Off"
"read.tail" = "On"
}
}
resource "kubernetes_service_account" "fluentbit_service" {
metadata {
name = "fluent-bit"
namespace = "amazon-cloudwatch"
}
}
resource "kubernetes_cluster_role" "fluentbit_clusterrole" {
metadata {
name = "fluent-bit-role"
}
rule {
non_resource_urls = ["/metrics"]
verbs = ["get"]
}
rule {
verbs = ["get", "list", "watch"]
resources = ["namespaces", "pods", "pods/logs", "nodes", "nodes/proxy"]
api_groups = [""]
}
}
resource "kubernetes_cluster_role_binding" "fluentbit_rolebinding" {
depends_on = [
kubernetes_service_account.fluentbit_service,
kubernetes_cluster_role.fluentbit_clusterrole,
]
metadata {
name = "fluent-bit-role-binding"
}
role_ref {
api_group = "rbac.authorization.k8s.io"
kind = "ClusterRole"
name = "fluent-bit-role"
}
subject {
kind = "ServiceAccount"
name = "fluent-bit"
namespace = "amazon-cloudwatch"
}
}
# TODO could use template file
resource "kubernetes_config_map" "fluentbit_config" {
depends_on = [
module.fluent_common
]
metadata {
name = "fluent-bit-config"
namespace = "amazon-cloudwatch"
labels = {
k8s-app = "fluent-bit"
}
}
data = {
"fluent-bit.conf" = <<EOF
[SERVICE]
Flush 5
Grace 30
Log_Level info
Daemon off
Parsers_File parsers.conf
HTTP_Server $${HTTP_SERVER}
HTTP_Listen 0.0.0.0
HTTP_Port $${HTTP_PORT}
storage.path /var/fluent-bit/state/flb-storage/
storage.sync normal
storage.checksum off
storage.backlog.mem_limit 5M
@INCLUDE application-log.conf
@INCLUDE dataplane-log.conf
@INCLUDE host-log.conf
EOF
"application-log.conf" = <<EOF
[INPUT]
Name tail
Tag application.*
Exclude_Path /var/log/containers/cloudwatch-agent*, /var/log/containers/fluent-bit*, /var/log/containers/aws-node*, /var/log/containers/kube-proxy*
Path /var/log/containers/*.log
multiline.parser docker, cri
DB /var/fluent-bit/state/flb_container.db
Mem_Buf_Limit 50MB
Skip_Long_Lines On
Refresh_Interval 10
Rotate_Wait 30
storage.type filesystem
Read_from_Head $${READ_FROM_HEAD}
[INPUT]
Name tail
Tag application.*
Path /var/log/containers/fluent-bit*
multiline.parser docker, cri
DB /var/fluent-bit/state/flb_log.db
Mem_Buf_Limit 5MB
Skip_Long_Lines On
Refresh_Interval 10
Read_from_Head $${READ_FROM_HEAD}
[INPUT]
Name tail
Tag application.*
Path /var/log/containers/cloudwatch-agent*
multiline.parser docker, cri
DB /var/fluent-bit/state/flb_cwagent.db
Mem_Buf_Limit 5MB
Skip_Long_Lines On
Refresh_Interval 10
Read_from_Head $${READ_FROM_HEAD}
[FILTER]
Name kubernetes
Match application.*
Kube_URL https://kubernetes.default.svc:443
Kube_Tag_Prefix application.var.log.containers.
Merge_Log On
Merge_Log_Key log_processed
K8S-Logging.Parser On
K8S-Logging.Exclude Off
Labels Off
Annotations Off
Use_Kubelet On
Kubelet_Port 10250
Buffer_Size 0
[OUTPUT]
Name cloudwatch_logs
Match application.*
region ${var.region}
log_group_name /aws/containerinsights/${module.fluent_common.cluster_name}/application
log_stream_prefix $${HOST_NAME}-
auto_create_group true
extra_user_agent container-insights
EOF
"dataplane-log.conf" = <<EOF
[INPUT]
Name systemd
Tag dataplane.systemd.*
Systemd_Filter _SYSTEMD_UNIT=docker.service
Systemd_Filter _SYSTEMD_UNIT=containerd.service
Systemd_Filter _SYSTEMD_UNIT=kubelet.service
DB /var/fluent-bit/state/systemd.db
Path /var/log/journal
Read_From_Tail $${READ_FROM_TAIL}
[INPUT]
Name tail
Tag dataplane.tail.*
Path /var/log/containers/aws-node*, /var/log/containers/kube-proxy*
multiline.parser docker, cri
DB /var/fluent-bit/state/flb_dataplane_tail.db
Mem_Buf_Limit 50MB
Skip_Long_Lines On
Refresh_Interval 10
Rotate_Wait 30
storage.type filesystem
Read_from_Head $${READ_FROM_HEAD}
[FILTER]
Name modify
Match dataplane.systemd.*
Rename _HOSTNAME hostname
Rename _SYSTEMD_UNIT systemd_unit
Rename MESSAGE message
Remove_regex ^((?!hostname|systemd_unit|message).)*$
[FILTER]
Name aws
Match dataplane.*
imds_version v1
[OUTPUT]
Name cloudwatch_logs
Match dataplane.*
region ${var.region}
log_group_name /aws/containerinsights/${module.fluent_common.cluster_name}/dataplane
log_stream_prefix $${HOST_NAME}-
auto_create_group true
extra_user_agent container-insights
EOF
"host-log.conf" = <<EOF
[INPUT]
Name tail
Tag host.dmesg
Path /var/log/dmesg
Key message
DB /var/fluent-bit/state/flb_dmesg.db
Mem_Buf_Limit 5MB
Skip_Long_Lines On
Refresh_Interval 10
Read_from_Head $${READ_FROM_HEAD}
[INPUT]
Name tail
Tag host.messages
Path /var/log/messages
Parser syslog
DB /var/fluent-bit/state/flb_messages.db
Mem_Buf_Limit 5MB
Skip_Long_Lines On
Refresh_Interval 10
Read_from_Head $${READ_FROM_HEAD}
[INPUT]
Name tail
Tag host.secure
Path /var/log/secure
Parser syslog
DB /var/fluent-bit/state/flb_secure.db
Mem_Buf_Limit 5MB
Skip_Long_Lines On
Refresh_Interval 10
Read_from_Head $${READ_FROM_HEAD}
[FILTER]
Name aws
Match host.*
imds_version v1
[OUTPUT]
Name cloudwatch_logs
Match host.*
region ${var.region}
log_group_name /aws/containerinsights/${module.fluent_common.cluster_name}/host
log_stream_prefix $${HOST_NAME}.
auto_create_group true
extra_user_agent container-insights
EOF
"parsers.conf" = <<EOF
[PARSER]
Name syslog
Format regex
Regex ^(?<time>[^ ]* {1,2}[^ ]* [^ ]*) (?<host>[^ ]*) (?<ident>[a-zA-Z0-9_\/\.\-]*)(?:\[(?<pid>[0-9]+)\])?(?:[^\:]*\:)? *(?<message>.*)$
Time_Key time
Time_Format %b %d %H:%M:%S
[PARSER]
Name container_firstline
Format regex
Regex (?<log>(?<="log":")\S(?!\.).*?)(?<!\\)".*(?<stream>(?<="stream":").*?)".*(?<time>\d{4}-\d{1,2}-\d{1,2}T\d{2}:\d{2}:\d{2}\.\w*).*(?=})
Time_Key time
Time_Format %Y-%m-%dT%H:%M:%S.%LZ
[PARSER]
Name cwagent_firstline
Format regex
Regex (?<log>(?<="log":")\d{4}[\/-]\d{1,2}[\/-]\d{1,2}[ T]\d{2}:\d{2}:\d{2}(?!\.).*?)(?<!\\)".*(?<stream>(?<="stream":").*?)".*(?<time>\d{4}-\d{1,2}-\d{1,2}T\d{2}:\d{2}:\d{2}\.\w*).*(?=})
Time_Key time
Time_Format %Y-%m-%dT%H:%M:%S.%LZ
EOF
}
}
resource "kubernetes_daemonset" "fluentbit-daemon" {
depends_on = [
module.fluent_common,
kubernetes_cluster_role_binding.fluentbit_rolebinding,
kubernetes_config_map.fluentbit_config
]
metadata {
name = "fluent-bit"
namespace = "amazon-cloudwatch"
labels = {
k8s-app = "fluent-bit"
version = "v1"
"kubernetes.io/cluster-service" = "true"
}
}
spec {
selector {
match_labels = {
k8s-app = "fluent-bit"
}
}
template {
metadata {
labels = {
k8s-app = "fluent-bit"
version = "v1"
"kubernetes.io/cluster-service" = "true"
}
}
spec {
container {
name = "fluent-bit"
image = "public.ecr.aws/aws-observability/aws-for-fluent-bit:stable"
image_pull_policy = "Always"
env {
name = "AWS_REGION"
value_from {
config_map_key_ref {
name = "fluent-bit-cluster-info"
key = "logs.region"
}
}
}
env {
name = "CLUSTER_NAME"
value_from {
config_map_key_ref {
name = "fluent-bit-cluster-info"
key = "cluster.name"
}
}
}
env {
name = "HTTP_SERVER"
value_from {
config_map_key_ref {
name = "fluent-bit-cluster-info"
key = "http.server"
}
}
}
env {
name = "HTTP_PORT"
value_from {
config_map_key_ref {
name = "fluent-bit-cluster-info"
key = "http.port"
}
}
}
env {
name = "READ_FROM_HEAD"
value_from {
config_map_key_ref {
name = "fluent-bit-cluster-info"
key = "read.head"
}
}
}
env {
name = "READ_FROM_TAIL"
value_from {
config_map_key_ref {
name = "fluent-bit-cluster-info"
key = "read.tail"
}
}
}
env {
name = "HOST_NAME"
value_from {
field_ref {
field_path = "spec.nodeName"
}
}
}
env {
name = "HOSTNAME"
value_from {
field_ref {
field_path = "metadata.name"
}
}
}
env {
name = "CI_VERSION"
value = "k8s/1.3.15"
}
resources {
limits = {
"memory" = "200Mi"
}
requests = {
"cpu" = "500m",
"memory" = "100Mi"
}
}
volume_mount {
mount_path = "/var/fluent-bit/state"
name = "fluentbitstate"
}
volume_mount {
mount_path = "/var/log"
name = "varlog"
read_only = true
}
volume_mount {
mount_path = "/var/lib/docker/containers"
name = "varlibdockercontainers"
read_only = true
}
volume_mount {
mount_path = "/fluent-bit/etc/"
name = "fluent-bit-config"
}
volume_mount {
mount_path = "/run/log/journal"
name = "runlogjournal"
read_only = true
}
volume_mount {
mount_path = "/var/log/dmesg"
name = "dmesg"
read_only = true
}
}
termination_grace_period_seconds = 10
host_network = true
dns_policy = "ClusterFirstWithHostNet"
volume {
name = "fluentbitstate"
host_path {
path = "/var/fluent-bit/state"
}
}
volume {
name = "varlog"
host_path {
path = "/var/log"
}
}
volume {
name = "varlibdockercontainers"
host_path {
path = "/var/lib/docker/containers"
}
}
volume {
name = "fluent-bit-config"
config_map {
name = "fluent-bit-config"
}
}
volume {
name = "runlogjournal"
host_path {
path = "/run/log/journal"
}
}
volume {
name = "dmesg"
host_path {
path = "/var/log/dmesg"
}
}
service_account_name = "fluent-bit"
toleration {
key = "node-role.kubernetes.io/master"
operator = "Exists"
effect = "NoSchedule"
}
toleration {
operator = "Exists"
effect = "NoExecute"
}
toleration {
operator = "Exists"
effect = "NoSchedule"
}
}
}
}
}
resource "null_resource" "validator" {
depends_on = [
module.fluent_common,
kubernetes_daemonset.fluentbit-daemon,
]
provisioner "local-exec" {
command = <<-EOT
echo "Validating EKS fluentbit logs"
cd ../../../../..
go test ${var.test_dir} -eksClusterName=${module.fluent_common.cluster_name} -computeType=EKS -v -eksDeploymentStrategy=DAEMON
EOT
}
}