Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 47 additions & 39 deletions main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -149,50 +149,51 @@ module "fluent-bit" {
module "grafana_alloy_cluster" {
count = var.grafana_alloy.cluster.enabled ? 1 : 0

source = "cookielab/grafana-alloy/kubernetes//modules/cluster"
version = "v0.0.6"
kubernetes_cluster_name = var.cluster_name
chart_version = "0.12.5"
kubernetes_namespace = local.namespace
source = "./modules/grafana-alloy/modules/cluster"
cluster_name = var.cluster_name
chart_version = var.grafana_alloy.chart_version
namespace = local.namespace

replicas = var.grafana_alloy.cluster.replicas
metrics = {
endpoint = var.grafana_alloy.metrics.endpoint
tenant = var.grafana_alloy.metrics.tenant
ssl_enabled = var.grafana_alloy.metrics.ssl_enabled
endpoint = var.grafana_alloy.metrics.endpoint
tenant = var.grafana_alloy.metrics.tenant
ssl_enabled = var.grafana_alloy.metrics.ssl_enabled
backend_type = var.grafana_alloy.metrics.backend_type
}
image = {
repository = var.grafana_alloy.image.repository
registry = var.grafana_alloy.image.registry
}

tolerations = var.grafana_alloy.cluster.tolerations != null ? var.grafana_alloy.cluster.tolerations : var.tolerations
node_selector = var.grafana_alloy.cluster.node_selector != null ? var.grafana_alloy.cluster.node_selector : var.node_selector

agent_resources = {
requests = {
cpu = var.grafana_alloy.cluster.requests.cpu
memory = var.grafana_alloy.cluster.requests.memory
cpu = var.grafana_alloy.cluster.resources.requests.cpu
memory = var.grafana_alloy.cluster.resources.requests.memory
}
limits = {
cpu = var.grafana_alloy.cluster.limits.cpu
memory = var.grafana_alloy.cluster.limits.memory
cpu = var.grafana_alloy.cluster.resources.limits.cpu
memory = var.grafana_alloy.cluster.resources.limits.memory
}

}
}

module "grafana_alloy_loki" {
count = var.grafana_alloy.loki.enabled ? 1 : 0

source = "cookielab/grafana-alloy/kubernetes//modules/loki-logs"
version = "v0.0.6"
kubernetes_cluster_name = var.cluster_name
chart_version = "0.12.5"
kubernetes_namespace = local.namespace
source = "./modules/grafana-alloy/modules/loki-logs"
cluster_name = var.cluster_name
chart_version = var.grafana_alloy.chart_version
namespace = local.namespace

replicas = var.grafana_alloy.loki.replicas
metrics = {
endpoint = var.grafana_alloy.metrics.endpoint
tenant = var.grafana_alloy.metrics.tenant
ssl_enabled = var.grafana_alloy.metrics.ssl_enabled
endpoint = var.grafana_alloy.metrics.endpoint
tenant = var.grafana_alloy.metrics.tenant
backend_type = var.grafana_alloy.metrics.backend_type
}

loki = {
Expand All @@ -207,51 +208,58 @@ module "grafana_alloy_loki" {
clustering_enabled = var.grafana_alloy.loki.clustering_enabled
image = {
repository = var.grafana_alloy.image.repository
registry = var.grafana_alloy.image.registry
}

aws = var.grafana_alloy.aws

tolerations = var.grafana_alloy.loki.tolerations != null ? var.grafana_alloy.loki.tolerations : var.tolerations
node_selector = var.grafana_alloy.loki.node_selector != null ? var.grafana_alloy.loki.node_selector : var.node_selector

agent_resources = {
requests = {
cpu = var.grafana_alloy.cluster.requests.cpu
memory = var.grafana_alloy.cluster.requests.memory
cpu = var.grafana_alloy.loki.resources.requests.cpu
memory = var.grafana_alloy.loki.resources.requests.memory
}
limits = {
cpu = var.grafana_alloy.cluster.limits.cpu
memory = var.grafana_alloy.cluster.limits.memory
cpu = var.grafana_alloy.loki.resources.limits.cpu
memory = var.grafana_alloy.loki.resources.limits.memory
}

}
}

module "grafana_alloy_node" {
count = var.grafana_alloy.node.enabled ? 1 : 0

source = "cookielab/grafana-alloy/kubernetes//modules/node"
version = "v0.0.6"
kubernetes_cluster_name = var.cluster_name
chart_version = "0.12.5"
kubernetes_namespace = local.namespace
source = "./modules/grafana-alloy/modules/node"
cluster_name = var.cluster_name
chart_version = var.grafana_alloy.chart_version
namespace = local.namespace

metrics = {
endpoint = var.grafana_alloy.metrics.endpoint
tenant = var.grafana_alloy.metrics.tenant
ssl_enabled = var.grafana_alloy.metrics.ssl_enabled
endpoint = var.grafana_alloy.metrics.endpoint
tenant = var.grafana_alloy.metrics.tenant
ssl_enabled = var.grafana_alloy.metrics.ssl_enabled
backend_type = var.grafana_alloy.metrics.backend_type
}
image = {
repository = var.grafana_alloy.image.repository
registry = var.grafana_alloy.image.registry
}

tolerations = var.grafana_alloy.node.tolerations != null ? var.grafana_alloy.node.tolerations : var.tolerations
node_selector = var.grafana_alloy.node.node_selector != null ? var.grafana_alloy.node.node_selector : var.node_selector

agent_resources = {
requests = {
cpu = var.grafana_alloy.node.requests.cpu
memory = var.grafana_alloy.node.requests.memory
cpu = var.grafana_alloy.node.resources.requests.cpu
memory = var.grafana_alloy.node.resources.requests.memory
}
limits = {
cpu = var.grafana_alloy.node.limits.cpu
memory = var.grafana_alloy.node.limits.memory
cpu = var.grafana_alloy.node.resources.limits.cpu
memory = var.grafana_alloy.node.resources.limits.memory
}
}

}

module "cert_manager" {
Expand Down
50 changes: 50 additions & 0 deletions modules/grafana-alloy/config_map.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
resource "kubernetes_config_map_v1" "grafana_alloy" {
metadata {
name = format("%s-config", local.agent_name)
namespace = var.namespace
}

data = {
(local.agent_config_key) = join("\n", concat(
flatten(var.default_config_enabled ? [
[
var.integrations.k8s_cadvisor ? file("${path.module}/templates/k8s_cadvisor.river.tmpl") : "",
var.integrations.k8s_kubelet ? file("${path.module}/templates/k8s_kubelet.river.tmpl") : "",
var.integrations.k8s_mimir_rules ? file("${path.module}/templates/k8s_mimir_rules.river.tmpl") : "",
var.integrations.k8s_pods ? templatefile("${path.module}/templates/k8s_pods.river.tmpl", {
scrape_pods_global = var.k8s_pods.scrape_pods_global
scrape_pods_annotation = var.k8s_pods.scrape_pods_annotation
}) : "",
var.integrations.k8s_services ? file("${path.module}/templates/k8s_services.river.tmpl") : "",
var.integrations.node_exporter ? file("${path.module}/templates/node_exporter.river.tmpl") : "",
var.integrations.aws_alb ? file("${path.module}/templates/aws_alb.river.tmpl") : "",
var.integrations.aws_rds ? file("${path.module}/templates/aws_rds.river.tmpl") : "",
var.integrations.aws_sqs ? file("${path.module}/templates/aws_sqs.river.tmpl") : "",
var.integrations.aws_mq ? file("${path.module}/templates/aws_mq.river.tmpl") : "",
var.integrations.aws_opensearch ? file("${path.module}/templates/aws_opensearch.river.tmpl") : "",
var.integrations.remote_write_metrics ? templatefile("${path.module}/templates/remote_write_metrics.river.tmpl", {
grafana_alloy_metrics_tenant = var.metrics.tenant
}) : "",
var.integrations.kafka_jmx_metrics ? templatefile("${path.module}/templates/kafka_jmx_metrics.river.tmpl", {
addresses = var.kafka_jmx_metrics.kafka_broker_list
metrics_endpoint_path = var.kafka_jmx_metrics.metrics_endpoint_path
}) : "",
var.integrations.otel_collector ? templatefile("${path.module}/templates/otel_collector.river.tmpl", {
otel_http_port = var.otel.http_port
otel_grpc_port = var.otel.grpc_port
otel_service_graphs_dimensions = var.otel.service_graphs_dimensions
}) : "",
var.integrations.loki_logs ? templatefile("${path.module}/templates/loki_pod_logs.river.tmpl", {
scrape_pods_global = var.loki.scrape_pods_global
scrape_pods_annotation = var.loki.scrape_pods_annotation
loki_auth_enabled = var.loki.auth_enabled
loki_tenant_id = var.loki.tenant_id
clustering_enabled = var.clustering_enabled
scrape_logs_method = var.loki.scrape_logs_method
}) : "",
],
] : []),
flatten(var.config),
))
}
}
81 changes: 81 additions & 0 deletions modules/grafana-alloy/helm.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
resource "helm_release" "grafana_alloy" {
repository = "https://grafana.github.io/helm-charts"
chart = "alloy"
version = var.chart_version
name = local.agent_name
namespace = var.namespace
timeout = 600

values = [yamlencode({
image = var.image
controller = {
type = var.kubernetes_kind
resources = var.controller_resources
replicas = var.replicas
podDisruptionBudget = {
enabled = var.pod_disruption_budget.enabled
minAvailable = var.pod_disruption_budget.min_available
maxUnavailable = var.pod_disruption_budget.max_unavailable
}
volumes = {
extra = [for volume in var.host_volumes : {
name = volume.name
hostPath = {
path = volume.host_path
}
}]
}
tolerations = var.tolerations
nodeSelector = var.node_selector
}
alloy = merge(var.integrations.otel_collector ? { extraPorts = [
{
name = "http-otel"
targetPort = var.otel.http_port
port = var.otel.http_port
protocol = "TCP"
},
{
name = "grpc-otel"
targetPort = var.otel.grpc_port
port = var.otel.grpc_port
protocol = "TCP"
}]
} : {}, {
mode = "flow"
liveDebug = {
enabled = var.live_debug
}
securityContext = var.kubernetes_security_context
clustering = {
enabled = var.clustering_enabled
}
stabilityLevel = var.stability_level
configMap = {
create = false
name = kubernetes_config_map_v1.grafana_alloy.metadata[0].name
key = local.agent_config_key
}
resources = local.agent_resources
envFrom = [{
secretRef = {
name = kubernetes_secret_v1.grafana_alloy.metadata[0].name
}
}]
mounts = {
extra = [for mount in var.host_volumes : {
name = mount.name
mountPath = mount.mount_path
}]
}
})
}),
var.iam_role_arn != "" ? yamlencode({
serviceAccount = {
annotations = {
"eks.amazonaws.com/role-arn" = var.iam_role_arn
}
}
}) : yamlencode({})
]
}
17 changes: 17 additions & 0 deletions modules/grafana-alloy/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
locals {
agent_name = format("grafana-alloy-%s", var.agent_name)
agent_config_key = "config.river"
url_metrics_write = var.metrics.backend_type == "mimir" ? format("%s://%s/api/v1/push", var.metrics.ssl_enabled ? "https" : "http", trimsuffix(var.metrics.endpoint, "/")) : format("%s://%s/api/v1/write", var.metrics.ssl_enabled ? "https" : "http", trimsuffix(var.metrics.endpoint, "/"))
url_mimir_rules = trimsuffix(var.metrics.endpoint, "/")

agent_resources = {
requests = {
cpu = var.agent_resources.requests.cpu
memory = var.agent_resources.requests.memory
}
limits = {
cpu = var.agent_resources.limits.cpu == null ? var.agent_resources.requests.cpu : var.agent_resources.limits.cpu
memory = var.agent_resources.limits.memory == null ? var.agent_resources.requests.memory : var.agent_resources.limits.memory
}
}
}
67 changes: 67 additions & 0 deletions modules/grafana-alloy/modules/aws/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# Grafana Alloy AWS Module

This module deploys Grafana Alloy to collect metrics from AWS services via CloudWatch.

## Overview

The module is designed to collect various metrics from AWS services including:

- Amazon RDS metrics
- Amazon OpenSearch metrics
- Amazon SQS metrics
- Other CloudWatch metrics

The agent runs as a deployment and collects metrics from:

- AWS CloudWatch API to gather service metrics
- Supports collecting metrics from multiple AWS regions
- Allows filtering and aggregation of metrics before sending

The module supports scaling to multiple replicas for high availability and load distribution when collecting metrics.

<!-- BEGIN_TF_DOCS -->
## Requirements

| Name | Version |
|------|---------|
| <a name="requirement_terraform"></a> [terraform](#requirement\_terraform) | >= 1.4.0, < 2.0.0 |

## Providers

No providers.

## Modules

| Name | Source | Version |
|------|--------|---------|
| <a name="module_grafana_alloy"></a> [grafana\_alloy](#module\_grafana\_alloy) | ../../ | n/a |

## Resources

No resources.

## Inputs

| Name | Description | Type | Default | Required |
|------|-------------|------|---------|:--------:|
| <a name="input_agent_resources"></a> [agent\_resources](#input\_agent\_resources) | Resources for the Grafana OTel agent | <pre>object({<br/> requests = optional(object({<br/> cpu = optional(string, "500m")<br/> memory = optional(string, "512Mi")<br/> }), {})<br/> limits = optional(object({<br/> cpu = optional(string, null)<br/> memory = optional(string, null)<br/> }), {})<br/> })</pre> | `{}` | no |
| <a name="input_aws_alb"></a> [aws\_alb](#input\_aws\_alb) | Grafana Alloy scrape aws ALB metrics | <pre>object({<br/> scrape_interval = optional(string, "1m")<br/> scrape_timeout = optional(string, "30s")<br/> scrape_period = optional(string, "1m")<br/> region = optional(string, "eu-west-1")<br/> search_tags = optional(map(string), {})<br/> })</pre> | `{}` | no |
| <a name="input_aws_mq"></a> [aws\_mq](#input\_aws\_mq) | Grafana Alloy scrape aws MQ metrics | <pre>object({<br/> scrape_interval = optional(string, "1m")<br/> scrape_timeout = optional(string, "30s")<br/> scrape_period = optional(string, "1m")<br/> region = optional(string, "eu-west-1")<br/> search_tags = optional(map(string), {})<br/> })</pre> | `{}` | no |
| <a name="input_aws_opensearch"></a> [aws\_opensearch](#input\_aws\_opensearch) | Grafana Alloy scrape aws opensearch cloudwatch metrics | <pre>object({<br/> scrape_interval = optional(string, "1m")<br/> scrape_timeout = optional(string, "30s")<br/> scrape_period = optional(string, "1m")<br/> region = optional(string, "eu-west-1")<br/> })</pre> | `{}` | no |
| <a name="input_aws_rds"></a> [aws\_rds](#input\_aws\_rds) | Grafana Alloy scrape aws RDS metrics | <pre>object({<br/> scrape_interval = optional(string, "1m")<br/> scrape_timeout = optional(string, "30s")<br/> scrape_period = optional(string, "1m")<br/> region = optional(string, "eu-west-1")<br/> search_tags = optional(map(string), {})<br/> })</pre> | `{}` | no |
| <a name="input_aws_sqs"></a> [aws\_sqs](#input\_aws\_sqs) | Grafana Alloy scrape aws SQS metrics | <pre>object({<br/> scrape_interval = optional(string, "1m")<br/> scrape_timeout = optional(string, "30s")<br/> scrape_period = optional(string, "1m")<br/> region = optional(string, "eu-west-1")<br/> search_tags = optional(map(string), {})<br/> })</pre> | `{}` | no |
| <a name="input_chart_version"></a> [chart\_version](#input\_chart\_version) | Helm chart version of Grafana Alloy | `string` | `"1.0.2"` | no |
| <a name="input_config"></a> [config](#input\_config) | Grafana Alloy River config snippets | `list(string)` | `[]` | no |
| <a name="input_controller_resources"></a> [controller\_resources](#input\_controller\_resources) | Resources for the Grafana Alloy controller | <pre>object({<br/> requests = optional(object({<br/> cpu = optional(string, "1m")<br/> memory = optional(string, "5Mi")<br/> }), {})<br/> limits = optional(object({<br/> cpu = optional(string, "100m")<br/> memory = optional(string, "50Mi")<br/> }), {})<br/> })</pre> | `{}` | no |
| <a name="input_global_tolerations"></a> [global\_tolerations](#input\_global\_tolerations) | Global tolerations for the Grafana Alloy | <pre>list(object({<br/> key = string<br/> operator = string<br/> effect = string<br/> }))</pre> | `[]` | no |
| <a name="input_iam_role_arn"></a> [iam\_role\_arn](#input\_iam\_role\_arn) | This role is for assuming by cloudwatch exporter | `string` | `""` | no |
| <a name="input_image"></a> [image](#input\_image) | Image registry for Grafana Alloy | <pre>object({<br/> registry = optional(string, "docker.io")<br/> repository = optional(string, "grafana/alloy")<br/> })</pre> | `{}` | no |
| <a name="input_kubernetes_cluster_name"></a> [kubernetes\_cluster\_name](#input\_kubernetes\_cluster\_name) | Kubernetes cluster name | `string` | n/a | yes |
| <a name="input_kubernetes_namespace"></a> [kubernetes\_namespace](#input\_kubernetes\_namespace) | Kubernetes namespace | `string` | n/a | yes |
| <a name="input_metrics"></a> [metrics](#input\_metrics) | Grafana Alloy metrics endpoint of Prometheus-compatible receiver. NOTE: You must provide the base URL of the API. Mimir and Promethes backends are supported. | <pre>object({<br/> endpoint = optional(string, "http://mimir:9090")<br/> tenant = optional(string, "default")<br/> backend_type = optional(string, "mimir")<br/> ssl_enabled = optional(bool, true)<br/> })</pre> | `{}` | no |
| <a name="input_pod_disruption_budget"></a> [pod\_disruption\_budget](#input\_pod\_disruption\_budget) | Grafana Alloy pod disruption budget configuration | <pre>object({<br/> enabled = optional(bool)<br/> min_available = optional(number)<br/> max_unavailable = optional(number)<br/> })</pre> | <pre>{<br/> "enabled": true,<br/> "max_unavailable": null,<br/> "min_available": 1<br/>}</pre> | no |

## Outputs

No outputs.
<!-- END_TF_DOCS -->
Loading