Terraform for Production AWS EKS Observability with Datadog, Prometheus, and PagerDuty Integration

Terraform for Production AWS EKS Observability with Datadog, Prometheus, and PagerDuty Integration

In the dynamic world of cloud-native applications, maintaining peak performance and rapid incident response for AWS Elastic Kubernetes Service (EKS) is paramount. Observability, often misunderstood as mere monitoring, extends to understanding the internal state of a system from its external outputs. This guide provides a comprehensive, technical walkthrough on leveraging Terraform to provision and manage a robust observability stack for your production EKS clusters, integrating the power of Datadog for holistic monitoring, Prometheus for deep Kubernetes-native metrics, and PagerDuty for automated incident management.

Architecture Pro-Tip: For a truly resilient and scalable production observability strategy on AWS EKS, aim for a layered approach. Use Datadog as your primary pane of glass for aggregated metrics, logs, and traces, leveraging its native integrations and AI-driven insights. Complement this by having Datadog's agent scrape Prometheus-formatted metrics from critical Kubernetes components (like kube-state-metrics and node-exporter). Finally, ensure a clear, automated path from critical Datadog alerts directly to PagerDuty to streamline incident response, reducing Mean Time To Resolution (MTTR). Infrastructure as Code (IaC) with Terraform is the bedrock for ensuring consistency and repeatability across environments.

Why Terraform for EKS Observability?

Terraform, as an Infrastructure as Code (IaC) tool, enables you to define and provision your infrastructure using a declarative configuration language. For production EKS observability, Terraform offers several critical advantages:

  • Consistency: Ensure identical observability configurations across development, staging, and production environments.
  • Version Control: Manage your observability stack like application code, enabling rollbacks, audits, and collaborative development.
  • Automation: Automate the deployment and management of agents, monitors, dashboards, and incident response configurations, reducing manual errors.
  • Scalability: Easily scale your monitoring infrastructure as your EKS clusters grow or new services are introduced.

Key Observability Components for AWS EKS

Datadog: The Unified Monitoring Platform

Datadog provides comprehensive monitoring for cloud-scale applications, integrating metrics, logs, traces, and UX monitoring into a single platform. For EKS, Datadog offers:

  • EKS Integration: Deep visibility into Kubernetes components (pods, nodes, deployments) and underlying AWS infrastructure.
  • APM & Distributed Tracing: End-to-end visibility into application performance.
  • Log Management: Centralized log collection, processing, and analysis.
  • Custom Metrics & Dashboards: Flexibility to monitor anything and visualize it effectively.
  • Alerting: Sophisticated anomaly detection and threshold-based alerts.

Prometheus: Kubernetes-Native Metrics Powerhouse

While Datadog provides a comprehensive solution, Prometheus remains a standard for Kubernetes-native metric collection. Its robust data model and powerful PromQL query language are invaluable for deep-diving into specific Kubernetes performance indicators. The best practice often involves using Datadog to ingest metrics from Prometheus exporters like kube-state-metrics and node-exporter, consolidating all metrics in one place.

PagerDuty: Streamlined Incident Response

PagerDuty is an industry leader in incident management, on-call scheduling, and automated incident response. Integrating PagerDuty with Datadog ensures that critical alerts from your EKS environment are routed to the right teams immediately, facilitating rapid diagnosis and resolution.

  • Automated On-Call: Ensure 24/7 coverage with intelligent scheduling.
  • Incident Aggregation: Consolidate alerts from multiple monitoring tools.
  • Escalation Policies: Define rules for escalating incidents if not acknowledged.
  • Post-Incident Analysis: Tools for root cause analysis and continuous improvement.

Prerequisites for Implementation

Before you begin, ensure you have the following:

  • An active AWS Account with necessary IAM permissions for EKS, EC2, and other AWS services.
  • Terraform CLI (v1.0+) installed.
  • AWS CLI configured with appropriate credentials.
  • An active Datadog Account with an API Key and Application Key.
  • An active PagerDuty Account with an API Key.
  • An existing AWS EKS Cluster. This guide assumes your EKS cluster is already provisioned.
  • kubectl and helm CLIs installed (though Terraform will use Helm provider).

Terraform Implementation: Bringing It All Together

We will use the Terraform kubernetes, helm, datadog, and pagerduty providers to manage our observability stack.

1. Configure Terraform Providers

Set up your Terraform providers in a versions.tf or providers.tf file:

terraform { required_providers { aws = { source = "hashicorp/aws" version = "~> 5.0" } kubernetes = { source = "hashicorp/kubernetes" version = "~> 2.23" } helm = { source = "hashicorp/helm" version = "~> 2.11" } datadog = { source = "DataDog/datadog" version = "~> 3.0" } pagerduty = { source = "PagerDuty/pagerduty" version = "~> 1.14" } } } provider "aws" { region = var.aws_region } # Configure Kubernetes provider to connect to EKS data "aws_eks_cluster" "eks_cluster" { name = var.eks_cluster_name } data "aws_eks_cluster_auth" "eks_cluster_auth" { name = var.eks_cluster_name } provider "kubernetes" { host = data.aws_eks_cluster.eks_cluster.endpoint cluster_ca_certificate = base64decode(data.aws_eks_cluster.eks_cluster.certificate_authority.0.data) token = data.aws_eks_cluster_auth.eks_cluster_auth.token } provider "helm" { kubernetes { host = data.aws_eks_cluster.eks_cluster.endpoint cluster_ca_certificate = base64decode(data.aws_eks_cluster.eks_cluster.certificate_authority.0.data) token = data.aws_eks_cluster_auth.eks_cluster_auth.token } } provider "datadog" { api_key = var.datadog_api_key app_key = var.datadog_app_key } provider "pagerduty" { token = var.pagerduty_api_token }

2. Deploying Datadog Agent to EKS

The Datadog Agent is deployed as a Helm chart on your EKS cluster. This agent collects metrics, logs, and traces from your Kubernetes environment and sends them to Datadog.

resource "helm_release" "datadog_agent" { name = "datadog" repository = "https://helm.datadoghq.com" chart = "datadog" namespace = "datadog" version = "2.33.0" # Use a stable, recent version create_namespace = true set { name = "datadog.apiKey" value = var.datadog_api_key sensitive = true } set { name = "datadog.appKey" value = var.datadog_app_key sensitive = true } set { name = "clusterAgent.enabled" value = "true" } set { name = "agents.enabled" value = "true" } set { name = "kubeStateMetricsCore.enabled" value = "true" # Enables Datadog to collect kube-state-metrics } set { name = "prometheusScrape.enabled" value = "true" # Enables Datadog Agent to scrape Prometheus endpoints } set { name = "logs.enabled" value = "true" } set { name = "logs.containerCollectAll" value = "true" } set { name = "apm.enabled" value = "true" } set { name = "processAgent.enabled" value = "true" } set { name = "tags" value = "env:${var.environment},cluster:${var.eks_cluster_name}" } }

3. Integrating Prometheus Metrics via Datadog

Instead of running a separate Prometheus server for basic EKS metrics, the Datadog Agent can be configured to scrape Prometheus endpoints directly. The Helm chart configuration above for kubeStateMetricsCore.enabled and prometheusScrape.enabled handles this. For services exposing Prometheus metrics, you typically annotate their Kubernetes pods/deployments.

Example Pod Annotations for Prometheus Scraping by Datadog Agent:

metadata:

annotations:

prometheus.io/scrape: "true"

prometheus.io/port: "8080" # Or whatever port your service exposes metrics

ad.datadoghq.com/<container_name>.check_names: '["prometheus"]'

ad.datadoghq.com/<container_name>.init_configs: '[{}]'

ad.datadoghq.com/<container_name>.instances: |

[

{

"prometheus_url": "http://%%host%%:8080/metrics",

"namespace": "my-app"

}

]

4. Automating Incident Response with PagerDuty

Define PagerDuty services, escalation policies, and then link Datadog monitors to these services.

4.1. Define PagerDuty Escalation Policy and Service

First, create an escalation policy and a service in PagerDuty using the Terraform PagerDuty provider.

resource "pagerduty_user" "example_user" { name = "DevOps Engineer" email = "devops@example.com" role = "user" } resource "pagerduty_escalation_policy" "example_policy" { name = "EKS Production Escalation Policy" num_loops = 2 rule { delay_after_engaging = 30 # minutes target { type = "user" id = pagerduty_user.example_user.id } } } resource "pagerduty_service" "eks_critical_service" { name = "EKS Critical Services" auto_resolve_timeout = 60 # minutes acknowledgement_timeout = 30 # minutes escalation_policy = pagerduty_escalation_policy.example_policy.id } resource "pagerduty_service_integration" "datadog_integration" { name = "Datadog Integration" type = "datadog_api_inbound_integration" service = pagerduty_service.eks_critical_service.id }

4.2. Create Datadog Monitors Linked to PagerDuty

Now, create a Datadog monitor and configure it to send alerts to the PagerDuty service integration. The message field will trigger the PagerDuty incident.

resource "datadog_monitor" "eks_cpu_utilization" { name = "[EKS] High CPU Utilization on Cluster: ${var.eks_cluster_name}" type = "metric alert" query = "avg(last_5m):avg:kubernetes.cpu.usage.total{cluster_name:${var.eks_cluster_name}} by {host} > 85" message = "EKS cluster ${var.eks_cluster_name} host CPU utilization is above 85% for 5 minutes. @pagerduty-EKS Critical Services @slack-devops-alerts" tags = ["environment:${var.environment}", "service:eks", "severity:critical"] renotify_interval = 60 notify_no_data = false no_data_timeframe = 20 include_tags = true escalation_message = "CPU utilization remains high. Escalating to the next level of on-call." critical_threshold = 85 warning_threshold = 75 }

Practical Terraform Configuration Examples

Here's a consolidated example of what your Terraform setup might look like for critical components:

// variables.tf

variable "aws_region" { type = string }

variable "eks_cluster_name" { type = string }

variable "datadog_api_key" { type = string; sensitive = true }

variable "datadog_app_key" { type = string; sensitive = true }

variable "pagerduty_api_token" { type = string; sensitive = true }

variable "environment" { type = string; default = "production" }

variable "devops_engineer_email" { type = string; default = "devops@example.com" }

variable "devops_engineer_name" { type = string; default = "DevOps Engineer" }


// main.tf


terraform {

required_providers {

aws = { source = "hashicorp/aws" ; version = "~> 5.0" }

kubernetes = { source = "hashicorp/kubernetes" ; version = "~> 2.23" }

helm = { source = "hashicorp/helm" ; version = "~> 2.11" }

datadog = { source = "DataDog/datadog" ; version = "~> 3.0" }

pagerduty = { source = "PagerDuty/pagerduty" ; version = "~> 1.14" }

}

}


provider "aws" { region = var.aws_region }

data "aws_eks_cluster" "eks_cluster" { name = var.eks_cluster_name }

data "aws_eks_cluster_auth" "eks_cluster_auth" { name = var.eks_cluster_name }


provider "kubernetes" {

host = data.aws_eks_cluster.eks_cluster.endpoint

cluster_ca_certificate = base64decode(data.aws_eks_cluster.eks_cluster.certificate_authority.0.data)

token = data.aws_eks_cluster_auth.eks_cluster_auth.token

}


provider "helm" {

kubernetes {

host = data.aws_eks_cluster.eks_cluster.endpoint

cluster_ca_certificate = base64decode(data.aws_eks_cluster.eks_cluster.certificate_authority.0.data)

token = data.aws_eks_cluster_auth.eks_cluster_auth.token

}

}


provider "datadog" {

api_key = var.datadog_api_key

app_key = var.datadog_app_key

}


provider "pagerduty" {

token = var.pagerduty_api_token

}


// Deploy Datadog Agent via Helm

resource "kubernetes_namespace" "datadog_ns" {

metadata {

name = "datadog"

}

}


resource "helm_release" "datadog_agent" {

name = "datadog"

repository = "https://helm.datadoghq.com"

chart = "datadog"

namespace = kubernetes_namespace.datadog_ns.metadata.0.name

version = "2.33.0" # Specify version for consistency


set { name = "datadog.apiKey"; value = var.datadog_api_key; sensitive = true }

set { name = "datadog.appKey"; value = var.datadog_app_key; sensitive = true }

set { name = "clusterAgent.enabled"; value = "true" }

set { name = "agents.enabled"; value = "true" }

set { name = "kubeStateMetricsCore.enabled"; value = "true" }

set { name = "prometheusScrape.enabled"; value = "true" }

set { name = "logs.enabled"; value = "true" }

set { name = "logs.containerCollectAll"; value = "true" }

set { name = "apm.enabled"; value = "true" }

set { name = "processAgent.enabled"; value = "true" }

set { name = "tags"; value = "env:${var.environment},cluster:${var.eks_cluster_name}" }

}


// PagerDuty Configuration

resource "pagerduty_user" "devops_oncall" {

name = var.devops_engineer_name

email = var.devops_engineer_email

role = "user"

}


resource "pagerduty_escalation_policy" "eks_prod_policy" {

name = "${var.eks_cluster_name} Production Escalation Policy"

num_loops = 2

rule {

delay_after_engaging = 15

target { type = "user"; id = pagerduty_user.devops_oncall.id }

}

}


resource "pagerduty_service" "eks_critical_alerts" {

name = "${var.eks_cluster_name} Critical Alerts"

auto_resolve_timeout = 60

acknowledgement_timeout = 30

escalation_policy = pagerduty_escalation_policy.eks_prod_policy.id

}


resource "pagerduty_service_integration" "datadog_prod_integration" {

name = "Datadog via API"

type = "datadog_api_inbound_integration"

service = pagerduty_service.eks_critical_alerts.id

}


// Datadog Monitor for EKS Node CPU

resource "datadog_monitor" "eks_node_cpu_critical" {

name = "[Critical] EKS Node CPU High (${var.eks_cluster_name})"

type = "metric alert"

query = "avg(last_5m):avg:kubernetes.cpu.usage.total{cluster_name:${var.eks_cluster_name}} by {host} > 80"

message = <<EOT

@pagerduty-EKS Critical Alerts

EKS cluster ${var.eks_cluster_name} node {{host.name}} CPU utilization is above 80% for 5 minutes.

Investigate potential overloaded nodes or runaway processes.

EOT

tags = ["environment:${var.environment}", "service:eks", "severity:critical", "source:terraform"]

renotify_interval = 30

notify_no_data = false

no_data_timeframe = 20

include_tags = true

escalation_message = "CPU utilization on EKS node {{host.name}} remains critical. Further investigation required."


critical_threshold = 80

warning_threshold = 70

}

To apply this configuration:

  1. Save the code in .tf files (e.g., variables.tf, main.tf).
  2. Run terraform init to initialize the providers.
  3. Run terraform plan to review the changes.
  4. Run terraform apply to provision your observability stack.

Best Practices for Production EKS Observability

  • Granular Tagging: Use consistent tags (environment, service, owner, team) on all resources and Kubernetes objects. This allows for powerful filtering, cost allocation, and organization in Datadog.
  • SLOs & SLIs: Define Service Level Objectives (SLOs) and Service Level Indicators (SLIs) for your critical services. Configure Datadog monitors to alert on SLI breaches, driving PagerDuty incidents based on business impact.
  • Cost Optimization: Monitor Datadog ingestion volumes, especially for logs and custom metrics. Optimize log sampling or filtering to manage costs while retaining critical information.
  • Security Considerations: Ensure API keys and tokens for Datadog and PagerDuty are securely managed (e.g., AWS Secrets Manager, Vault) and never hardcoded. Grant the least privilege necessary for the Datadog Agent's IAM role.
  • Drift Detection: Regularly run terraform plan as part of your CI/CD pipeline to detect and remediate any manual changes or configuration drift in your observability stack.
  • Synthetic Monitoring: Implement Datadog Synthetics to proactively test critical application endpoints and user journeys, triggering alerts before users are impacted.

Troubleshooting Common Observability Issues

  • Datadog Agent Not Reporting:
    • Check Datadog Agent pod logs (kubectl logs -n datadog <datadog-agent-pod>).
    • Verify DATADOG_API_KEY and DATADOG_APP_KEY are correctly passed and valid.
    • Ensure network connectivity from EKS nodes to Datadog endpoints.
  • Missing Prometheus Metrics:
    • Confirm prometheusScrape.enabled is set to true in the Helm chart.
    • Verify Kubernetes service/pod annotations for Prometheus scraping are correct.
    • Check Datadog Agent status page for configured checks and errors (kubectl exec -it -n datadog <datadog-agent-pod> agent status).
  • PagerDuty Incidents Not Triggering:
    • Ensure the Datadog monitor's message contains the correct PagerDuty integration tag (e.g., @pagerduty-EKS Critical Services).
    • Verify the PagerDuty API token used by Terraform is valid.
    • Check Datadog event stream for monitor state changes and associated notifications.

Conclusion: Empowering Your EKS Operations with IaC Observability

Implementing a robust observability strategy for production AWS EKS is not just a best practice; it's a necessity for maintaining reliability and user satisfaction. By leveraging Terraform, you can declaratively provision and manage your entire observability stack, integrating Datadog for comprehensive monitoring, Prometheus for deep metric insights, and PagerDuty for efficient incident response. This IaC-driven approach ensures consistency, reduces manual errors, and empowers your DevOps teams to operate your EKS clusters with confidence and agility.

Embrace Infrastructure as Code for your observability stack, and transform potential outages into manageable, quickly resolved incidents.

Comments

Popular posts from this blog

Terraform Configuration for Datadog-PagerDuty Incident Management on AWS EKS

Terraform-Managed AWS EKS Observability and Incident Response with Datadog and PagerDuty