Terraform for AWS EKS and Datadog Observability with PagerDuty Incident Management

Orchestrating Cloud-Native: Terraform for AWS EKS, Datadog Observability, and PagerDuty Incident Management

In the fast-paced world of modern cloud infrastructure, managing complex systems requires robust automation, comprehensive observability, and efficient incident response. This guide provides a detailed, technical walkthrough on leveraging Terraform for provisioning and managing AWS EKS (Elastic Kubernetes Service) clusters, integrating Datadog for end-to-end observability, and seamlessly connecting with PagerDuty for streamlined incident management. This trifecta ensures high availability, performance, and operational excellence for your Kubernetes workloads.

Architecture Pro-Tip:

Always design your cloud infrastructure with modularity and reusability in mind. For EKS, separate core networking (VPC, subnets) from the EKS cluster definition, and further abstract Kubernetes add-ons (like Datadog Agent) into dedicated modules. This approach simplifies maintenance, promotes collaboration, and enhances the security posture of your IaC deployments.

Why This Stack? The Power of Integration

The combination of Terraform, AWS EKS, Datadog, and PagerDuty represents a gold standard for operating cloud-native applications:

  • Terraform: Provides Infrastructure as Code (IaC) capabilities, allowing you to define, provision, and manage your entire cloud infrastructure (EKS, networking, security groups, IAM roles) in a declarative manner. This reduces manual errors, increases repeatability, and facilitates version control.
  • AWS EKS: A fully managed Kubernetes service that simplifies the deployment, management, and scaling of containerized applications. It eliminates the need to install, operate, and maintain your own Kubernetes control plane.
  • Datadog: A leading monitoring and analytics platform that brings together metrics, logs, traces, and user experience data across your entire stack. For EKS, it provides deep visibility into cluster health, node performance, pod metrics, application traces, and container logs.
  • PagerDuty: An incident management platform that automates alert routing, on-call scheduling, and escalation policies. Integrating Datadog with PagerDuty ensures critical alerts are never missed and are escalated to the right teams promptly, minimizing downtime.

Prerequisites

Before you begin, ensure you have the following:

  • AWS Account: With necessary IAM permissions to create EKS clusters, VPCs, IAM roles, etc.
  • Terraform CLI: Installed and configured (version 1.0+ recommended).
  • AWS CLI: Installed and configured.
  • Kubectl: Installed for interacting with the EKS cluster.
  • Datadog Account: With API and Application keys generated.
  • PagerDuty Account: With an API key and a service created for EKS alerts.
  • Helm CLI: (Optional, but recommended for deploying Datadog Agent).

Step-by-Step Implementation Guide

1. Core AWS Infrastructure with Terraform

First, define your AWS provider and necessary networking components. We'll assume a basic VPC, subnets, and security groups are in place or will be created by a separate module. For EKS, you'll need private and public subnets, and an IAM role for the EKS cluster.

Create a main.tf:

provider "aws" { region = "us-east-1" } resource "aws_vpc" "eks_vpc" { cidr_block = "10.0.0.0/16" enable_dns_hostnames = true enable_dns_support = true tags = { Name = "eks-vpc" } } resource "aws_subnet" "public" { count = 2 vpc_id = aws_vpc.eks_vpc.id cidr_block = cidrsubnet(aws_vpc.eks_vpc.cidr_block, 8, count.index) availability_zone = data.aws_availability_zones.available.names[count.index] map_public_ip_on_launch = true tags = { Name = "eks-public-subnet-${count.index}" } } resource "aws_subnet" "private" { count = 2 vpc_id = aws_vpc.eks_vpc.id cidr_block = cidrsubnet(aws_vpc.eks_vpc.cidr_block, 8, count.index + 2) availability_zone = data.aws_availability_zones.available.names[count.index] tags = { Name = "eks-private-subnet-${count.index}" } } resource "aws_iam_role" "eks_cluster_role" { name = "eks-cluster-role" assume_role_policy = jsonencode({ Version = "2012-10-17" Statement = [ { Effect = "Allow" Principal = { Service = "eks.amazonaws.com" } Action = "sts:AssumeRole" }, ] }) } resource "aws_iam_role_policy_attachment" "eks_cluster_policy" { policy_arn = "arn:aws:iam::aws:policy/AmazonEKSClusterPolicy" role = aws_iam_role.eks_cluster_role.name } resource "aws_iam_role_policy_attachment" "eks_service_policy" { policy_arn = "arn:aws:iam::aws:policy/AmazonEKSServicePolicy" role = aws_iam_role.eks_cluster_role.name } data "aws_availability_zones" "available" {}

2. Provisioning AWS EKS Cluster with Terraform

Next, define the EKS cluster and its node groups. We'll use the official AWS EKS module for simplicity and best practices.

Add to your Terraform configuration:

module "eks_cluster" { source = "terraform-aws-modules/eks/aws" version = "~> 19.0" cluster_name = "my-observability-eks" cluster_version = "1.28" vpc_id = aws_vpc.eks_vpc.id subnet_ids = concat(aws_subnet.private[*].id, aws_subnet.public[*].id) eks_cluster_role_arn = aws_iam_role.eks_cluster_role.arn # EKS Managed Node Group eks_managed_node_groups = { example = { instance_types = ["t3.medium"] min_size = 2 max_size = 5 desired_size = 3 disk_size = 20 ami_type = "AL2_x86_64" # Amazon Linux 2 tags = { "Name" = "eks-worker-nodes" } } } tags = { Environment = "Dev" Project = "ObservabilityGuide" } } output "kubeconfig" { description = "Kubectl configuration to connect to the EKS cluster." value = module.eks_cluster.kubeconfig sensitive = true } output "cluster_endpoint" { description = "Endpoint for the EKS cluster." value = module.eks_cluster.cluster_endpoint }

3. Integrating Datadog for Observability

To deploy the Datadog Agent, we'll use the Terraform helm_release resource, which allows you to manage Helm charts directly. This assumes you have the Kubernetes provider configured to connect to your newly created EKS cluster.

First, ensure your Kubernetes provider is configured:

provider "kubernetes" { host = module.eks_cluster.cluster_endpoint cluster_ca_certificate = base64decode(module.eks_cluster.cluster_certificate_authority_data) token = data.aws_eks_cluster_auth.this.token } data "aws_eks_cluster_auth" "this" { name = module.eks_cluster.cluster_name }

Now, add the Datadog Agent Helm release:

resource "helm_release" "datadog_agent" { name = "datadog" repository = "https://helm.datadoghq.com" chart = "datadog" namespace = "default" # Or create a dedicated namespace version = "2.33.0" # Use a recent stable version set { name = "datadog.apiKey" value = var.datadog_api_key } set { name = "datadog.appKey" value = var.datadog_app_key } set { name = "datadog.site" value = "datadoghq.com" # Or your specific Datadog site (e.g., eu.datadoghq.com) } set { name = "clusterAgent.enabled" value = true } set { name = "clusterAgent.metricsProvider.enabled" value = true } set { name = "datadog.hostLabels.eks_cluster_name" value = module.eks_cluster.cluster_name } # Enable APM for distributed tracing set { name = "agents.apm.enabled" value = true } # Enable logging set { name = "agents.log.enabled" value = true } set { name = "agents.log.logsCollectionEnabled" value = true } } variable "datadog_api_key" { description = "Your Datadog API Key" type = string sensitive = true } variable "datadog_app_key" { description = "Your Datadog Application Key" type = string sensitive = true }

4. PagerDuty Incident Management Integration

Leverage the Datadog Terraform provider to configure the PagerDuty integration and define a sample monitor that will trigger an alert in PagerDuty.

First, set up the Datadog provider and PagerDuty integration:

provider "datadog" { api_key = var.datadog_api_key app_key = var.datadog_app_key } # Integrate Datadog with PagerDuty resource "datadog_integration_pagerduty" "eks_pagerduty" { # This assumes you have created a PagerDuty service manually or via the PagerDuty Terraform provider # Replace with your actual PagerDuty service key (integration key for Datadog) # For detailed integration, consider using the pagerduty provider to manage services and integrations # Here we are just ensuring Datadog knows about PagerDuty } variable "pagerduty_service_key" { description = "PagerDuty Integration Key for the Datadog service" type = string sensitive = true }

Now, create a sample Datadog monitor for EKS node CPU utilization that alerts PagerDuty:

resource "datadog_monitor" "eks_high_cpu" { name = "EKS Node CPU Utilization High on ${module.eks_cluster.cluster_name}" type = "metric alert" query = "avg(last_5m):avg:system.cpu.idle{kube_cluster_name:${module.eks_cluster.cluster_name}} by {host} < 20" message = <

Ready-to-Use Configuration Summary

Below is a condensed version of the Terraform configuration showcasing the integration. Remember to replace placeholder variables with your actual values and secure sensitive data appropriately (e.g., using Terraform Cloud variables, AWS Secrets Manager, or environment variables).

# main.tf # Configure AWS Provider provider "aws" { region = "us-east-1" } # Configure Kubernetes Provider for EKS cluster access provider "kubernetes" { host = module.eks_cluster.cluster_endpoint cluster_ca_certificate = base64decode(module.eks_cluster.cluster_certificate_authority_data) token = data.aws_eks_cluster_auth.this.token } data "aws_eks_cluster_auth" "this" { name = module.eks_cluster.cluster_name } # Configure Datadog Provider provider "datadog" { api_key = var.datadog_api_key app_key = var.datadog_app_key } # EKS Cluster Module (simplified, assumes VPC setup exists) module "eks_cluster" { source = "terraform-aws-modules/eks/aws" version = "~> 19.0" cluster_name = "my-observability-eks" cluster_version = "1.28" vpc_id = "vpc-xxxxxxxxxxxxxxxxx" # Replace with your VPC ID subnet_ids = ["subnet-xxxxxxxxxxxxxxxxx", "subnet-yyyyyyyyyyyyyyyyy"] # Replace with your private subnet IDs eks_cluster_role_arn = "arn:aws:iam::123456789012:role/eks-cluster-role" # Replace with your EKS Cluster IAM Role ARN eks_managed_node_groups = { example = { instance_types = ["t3.medium"] min_size = 2 max_size = 5 desired_size = 3 } } } # Deploy Datadog Agent via Helm resource "helm_release" "datadog_agent" { name = "datadog" repository = "https://helm.datadoghq.com" chart = "datadog" namespace = "default" version = "2.33.0" set { name = "datadog.apiKey"; value = var.datadog_api_key } set { name = "datadog.appKey"; value = var.datadog_app_key } set { name = "datadog.site"; value = "datadoghq.com" } set { name = "clusterAgent.enabled"; value = true } set { name = "clusterAgent.metricsProvider.enabled"; value = true } set { name = "datadog.hostLabels.eks_cluster_name"; value = module.eks_cluster.cluster_name } set { name = "agents.apm.enabled"; value = true } set { name = "agents.log.enabled"; value = true } set { name = "agents.log.logsCollectionEnabled"; value = true } } # Datadog PagerDuty Integration (ensure PagerDuty service is pre-configured) # datadog_integration_pagerduty resource does not directly accept service_key for integration # The integration is configured via Datadog UI or directly when setting up monitors like below: # resource "datadog_integration_pagerduty" "eks_pagerduty_integration" {} # This resource manages the overall integration status # Create a Datadog Monitor with PagerDuty notification resource "datadog_monitor" "eks_node_cpu_critical" { name = "EKS Node CPU Critical - ${module.eks_cluster.cluster_name}" type = "metric alert" query = "avg(last_5m):avg:system.cpu.idle{kube_cluster_name:${module.eks_cluster.cluster_name}} by {host} < 10" # Alert if idle < 10% message = "EKS node {{host.name}} in cluster ${module.eks_cluster.cluster_name} is experiencing critical CPU load! @pagerduty-${var.pagerduty_integration_key}" tags = ["env:prod", "team:devops", "severity:critical"] monitor_thresholds { critical = 10 } } # variables.tf variable "datadog_api_key" { description = "Your Datadog API Key" type = string sensitive = true } variable "datadog_app_key" { description = "Your Datadog Application Key" type = string sensitive = true } variable "pagerduty_integration_key" { description = "The PagerDuty integration key for the service receiving alerts from Datadog. This is typically found in the PagerDuty service's integration settings." type = string sensitive = true }

To deploy, navigate to your Terraform directory and run:

terraform init terraform plan terraform apply

Best Practices for Production Environments

  • State Management: Always use a remote backend for Terraform state (e.g., AWS S3 with DynamoDB locking) to enable collaboration and prevent state corruption.
  • Modularity: Break down your Terraform configuration into reusable modules (e.g., vpc-module, eks-cluster-module, datadog-observability-module) for better organization and scalability.
  • Security:
    • Limit IAM permissions to the principle of least privilege.
    • Use private EKS endpoints for enhanced security.
    • Rotate API keys and other credentials regularly.
    • Never hardcode sensitive information; use environment variables, AWS Secrets Manager, or Terraform Cloud/Enterprise variables.
  • Observability Structure:
    • Create dedicated Datadog dashboards for EKS cluster health, application performance, and specific services.
    • Implement comprehensive logging with proper tagging and parsing for easier troubleshooting.
    • Define clear SLOs/SLIs and corresponding Datadog monitors.
  • Incident Response:
    • Ensure PagerDuty escalation policies are well-defined and regularly tested.
    • Integrate Runbooks with PagerDuty services to provide immediate context and remediation steps for on-call teams.
    • Conduct regular incident response drills.
  • Cost Management: Monitor EKS node utilization and right-size your instances to optimize costs. Datadog can provide insights into resource consumption.

Troubleshooting / FAQ

Q: EKS cluster creation fails with IAM role errors.

A: Double-check the IAM role policies (AmazonEKSClusterPolicy and AmazonEKSServicePolicy) attached to the EKS cluster role. Ensure the trust policy allows eks.amazonaws.com to assume the role. Also verify the IAM user/role running Terraform has permissions to create/manage these roles.

Q: Datadog Agent pods are not coming up or reporting data.

A:

  • Verify datadog.apiKey and datadog.appKey are correct and have appropriate permissions in Datadog.
  • Check pod logs: kubectl logs <datadog-agent-pod-name> for errors.
  • Ensure the Kubernetes provider in Terraform is correctly configured to connect to your EKS cluster.
  • Check network connectivity from EKS nodes to Datadog endpoints (g.datadoghq.com, agent.datadoghq.com).

Q: PagerDuty alerts are not triggering from Datadog monitors.

A:

  • Confirm the @pagerduty-<YOUR_INTEGRATION_KEY> syntax in the Datadog monitor message is correct and uses the integration key (not the PagerDuty service ID).
  • Verify the PagerDuty integration is enabled in your Datadog account (Integrations -> PagerDuty).
  • Test the monitor with a low threshold to ensure it triggers in Datadog.

Conclusion

By strategically combining Terraform for IaC, AWS EKS for scalable container orchestration, Datadog for comprehensive observability, and PagerDuty for proactive incident management, organizations can establish a robust, resilient, and highly automated cloud-native operational framework. This guide provides the foundation for building such an environment, enabling your teams to focus on innovation rather than operational overhead.

Continual iteration, security consciousness, and performance optimization are key to maintaining a healthy and efficient EKS ecosystem. Embrace these tools to elevate your DevOps practices and ensure your applications run smoothly in production.

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

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