Skip to main content
Type: rvn-eks-cluster · Latest version: 0.2.0

Dependencies and consumers

Every dependency input can be specified manually to reference existing external infrastructure rather than a Ravion module.

Readme

Production-ready Amazon EKS cluster with default managed capacity, core add-ons, and optional Fargate compute. Extend with the EKS Add-ons module (Karpenter, load balancer controller, EBS CSI, Container Insights).

Overview

Amazon EKS (Elastic Kubernetes Service) runs managed Kubernetes control planes on AWS. This module creates an EKS cluster inside your selected VPC and provisions everything a working cluster needs, in the correct order:
  1. Cluster - control plane, secrets encryption, VPC CNI, kube-proxy, Pod Identity Agent, and the AWS Load Balancer Controller IAM role; optional OIDC provider for IRSA workloads
  2. Default capacity - a managed node group for cluster components, add-ons, and workloads without stricter placement
  3. CoreDNS - installed only after compute exists so it starts healthy
  4. Optional compute - additional managed node groups and Fargate profiles
This module talks only to the AWS API, so it provisions in a single apply. Optional extensions - Karpenter autoscaling, the AWS Load Balancer Controller, the EBS CSI driver, and Container Insights - are added by the separate EKS Add-ons module, so clusters only carry what they use. Terraform source: ravionhq/modules/compute/eks

Use cases

Compute

Default capacity

Every cluster gets a required managed node group that provides default compute for cluster components such as CoreDNS, add-ons, and workloads without stricter placement. It defaults to 2-4 On-demand t3.medium nodes. Its settings are collapsed by default so teams using Karpenter can keep the recommended baseline without extra configuration. The minimum node count is also used as the initial size; after creation, the running node count is managed by Kubernetes autoscalers, and Terraform only enforces the min/max bounds. Each workload module can use automatic placement or target EC2 On-demand, EC2 Spot, or a dedicated Fargate profile.

Additional node groups

Add managed node groups for application workloads through the Additional node groups form. Each group independently chooses On-demand or Spot capacity, instance types, size bounds, labels, and taints. The minimum node count is also the initial node count. Add one On-demand group and one Spot group when workloads should be able to use both. Multiple instance types are especially useful for Spot because AWS can choose from more available pools.

Karpenter

This module does not create any Karpenter resources. To add Karpenter autoscaling, deploy the EKS Add-ons module referencing this cluster - it provisions everything Karpenter needs (IAM roles, Pod Identity association, instance profile, interruption queue, EventBridge rules) and installs the controller and a default NodePool.

Fargate

Fargate profiles run pods from selected namespaces on serverless compute instead of EC2 nodes. Each profile matches one or more namespace selectors, optionally narrowed by pod labels. Profiles use the cluster’s private subnets and a generated pod execution role unless you override them.

Cluster access

By default the Kubernetes API server is reachable only from inside the VPC. Enable Public endpoint access to reach it from the internet, and restrict the allowed source ranges with Public access CIDRs. A Ravion Runner security group is created automatically and allowed to reach the API endpoint on port 443. Modules that talk to the Kubernetes API (such as EKS Add-ons with Karpenter enabled) pick it up from this cluster so their pipeline runs can reach a private endpoint, so there is nothing to configure. Its ID is available as the ravion_runner_security_group_id stack output. A Ravion Runner role is also created by default: a stable IAM role registered as an EKS access entry with cluster-admin, which Ravion Runner step executions assume when they need the Kubernetes API. This keeps per-run pipeline roles out of the cluster’s access configuration — the EKS Add-ons module assumes it automatically via aws eks get-token. Its ARN is available as the ravion_runner_role_arn stack output. The trust policy admits only this AWS account; tighten it further with the ravion_runner_role_trusted_principal_arns Terraform variable. EKS access entries control which IAM principals can access the cluster. The IAM principal that creates the cluster is granted admin access automatically. Grant additional principals access through the Access entries form: give each entry an IAM principal ARN, then attach EKS access policies scoped to the whole cluster or to selected namespaces, and optionally map the principal to Kubernetes RBAC groups. Automatic access for Ravion deploys will be wired here in a future release.

IAM compatibility when upgrading

Add-ons use EKS Pod Identity, so the IAM OIDC provider and its certificate lookup are now off by default. Existing workloads that use IRSA need oidc_provider_creation_enabled: true under Advanced Terraform variables before upgrading to retain their provider. The cluster’s issuer URL remains available even without an IAM provider. The cluster role no longer includes AmazonEKSVPCResourceController by default. Existing Windows networking or security groups for pods need vpc_resource_controller_policy_enabled: true under Advanced Terraform variables to retain it. Ordinary Linux pod networking and multi-AZ placement do not need it. Managed node roles replace ECR ReadOnly with PullOnly, matching Karpenter nodes. This updates IAM attachments without replacing nodes. Worker-node and CNI permissions remain in place.

Networking

Zone-local routing

A multi-AZ cluster spreads pods across availability zones for resilience, but by default Kubernetes also spreads every in-cluster request across those zones, and AWS bills cross-AZ data transfer in both directions. This module keeps that traffic local by default:
  • CoreDNS is spread across zones with a topology.kubernetes.io/zone topology spread constraint, so every zone has a resolver.
  • The EKS Add-ons module patches the kube-dns Service with trafficDistribution: PreferClose, so DNS lookups go to the resolver in the caller’s zone.
  • The EKS Web Service chart sets the same trafficDistribution on each workload Service, and both the Web Service and Worker charts spread their pods across zones, so service-to-service calls stay in-zone whenever the destination has a pod there.
When a zone has no pod for the destination, traffic falls back to every zone; nothing is ever dropped. The spread is a soft preference (ScheduleAnyway), so a two-node cluster or a Spot interruption never leaves pods pending. Zone-local routing needs Kubernetes 1.31 or later; on older versions the Service field is ignored and routing behaves as before. Turn it off for the cluster by setting topology_aware_routing_enabled: false under Advanced Terraform variables; the EKS Add-ons module reads the same flag from this cluster’s outputs. Individual workloads keep the chart defaults regardless of the cluster flag.

Observability

Control plane logs (API server, audit, and authenticator by default) are shipped to CloudWatch Logs and shown on the module’s Logs tab. Adjust the log types and retention in the Observability section. Container Insights (node, pod, and container metrics plus application/data plane logs) is installed through the EKS Add-ons module; once enabled there, its data populates this module’s Metrics and Logs tabs. Control plane health metrics (API server requests and errors, pending pods, etcd database size) are published by EKS automatically at no cost and appear on the Metrics tab regardless.

Configuration

Design decisions

This module follows AWS EKS production patterns:
  • Ordered provisioning: CoreDNS is installed only after the default capacity node group exists, avoiding the add-on deadlock that occurs on clusters without compute
  • Private by default: the API endpoint is private unless public access is explicitly enabled
  • Encrypted secrets: Kubernetes secrets are envelope-encrypted with KMS by default
  • Deletion protection on: the cluster cannot be deleted until protection is turned off, preventing accidental destroys
  • Autoscaler-friendly sizing: Terraform sets the initial node count but never fights an autoscaler over the running count
  • Pod Identity over IRSA: add-on IAM roles use EKS Pod Identity associations; creating an IAM OIDC provider for IRSA workloads is opt-in
  • Zone-local by default: CoreDNS is spread across availability zones and, together with the EKS Add-ons and workload modules, Service traffic prefers same-zone endpoints, so multi-AZ resilience does not come with cross-AZ data transfer charges on every request

Learn more

Amazon EKS Compute

Inputs reference

All inputs for rvn-eks-cluster version 0.2.0. Use the name shown for each field as the input key in module config.
$ref:rvn-aws-network
required
VPC network.
  • Immutable after creation

EKS cluster config

string
required
EKS cluster name. Name and prefix for related resources.
  • Default: <<project.given_id>>-<<environment.given_id>>
  • Immutable after creation
  • Pattern: ^[0-9A-Za-z][A-Za-z0-9-_]{0,99}$ — 1-100 letters, numbers, hyphens, and underscores. Start with a letter or number.
string
required
Kubernetes version. Kubernetes version for the EKS cluster.
  • Default: $values:first
boolean
Deletion protection. Prevent the cluster from being deleted via the AWS API. Must be turned off before this module can be destroyed.
  • Default: true
boolean
Secrets encryption. Envelope-encrypt Kubernetes secrets with a KMS key. A key is created automatically unless an existing key ARN is provided below.
  • Default: true
string
Secrets KMS key ARN. Existing KMS key for Kubernetes secrets encryption. Leave blank to create a dedicated key.
  • Shown when: {"secrets_encryption_enabled":true}

Default capacity

string
Capacity type. On-demand is stable default capacity; Spot is lower cost but nodes can be interrupted.
  • Default: ON_DEMAND
  • Allowed values: ON_DEMAND (On-demand), SPOT (Spot)
string_array
required
Instance types. EC2 instance types AWS may use for this node group. Multiple types improve Spot availability.
  • Default: ["t3.medium"]
number
Minimum nodes. Minimum nodes in the default managed node group. Set it high enough to run cluster components and leave spare capacity for workloads and rolling node updates.
  • Default: 2
  • Min: 1
number
Maximum nodes. Maximum nodes in the default managed node group. Set it high enough for peak workloads and replacement capacity during rolling node updates, otherwise pods can remain pending.
  • Default: 4
  • Min: 1
number
Disk size (GB). Root EBS volume size for default capacity nodes. Leave blank for the AMI default.
  • Min: 20
object_map
Additional node groups. Add independently sized On-demand or Spot managed node groups when workloads need more or separate capacity. Create one of each to make both capacity types available.
  • Default: {}

Fargate

object_map
Fargate profiles. Run pods from selected namespaces on AWS Fargate instead of EC2 nodes.
  • Default: {}

Cluster access

boolean
Private endpoint access. Allow access to the Kubernetes API server from inside the VPC.
  • Default: true
boolean
Public endpoint access. Allow access to the Kubernetes API server from the public internet.
  • Default: false
string_array
Public access CIDRs. IPv4 CIDR blocks allowed to reach the public API server endpoint. Terraform defaults to 0.0.0.0/0.
  • Shown when: {"endpoint_public_access_enabled":true}
boolean
Ravion Runner role. Create an IAM role that Ravion Runner step executions assume for Kubernetes API access, registered as an EKS access entry with cluster-admin. Used by the EKS Add-ons module to install Helm charts.
  • Default: true
object_map
Access entries. Additional IAM principals that need cluster access. The principal that creates the cluster receives admin access automatically.
  • Default: {}

Observability

string_array
Control plane log types. Control plane log types shipped to CloudWatch Logs. Remove all entries to disable control plane logging.
  • Default: ["api","audit","authenticator"]
  • Allowed values: api (API server), audit (Audit), authenticator (Authenticator), controllerManager (Controller manager), scheduler (Scheduler)
number
Log retention (days). Retention in days for the control plane CloudWatch log group.
  • Default: 30
  • Min: 1

Misc

keyvalue
Tags. A map of tags to assign to all resources. Default tags are Owner, ProjectGivenId, EnvironmentGivenId, ModuleGivenId, ModuleId

Terraform settings

string
OpenTofu version override. Override the environment’s default version for this module
string
Ravion Terraform workspace name. Override Terraform state backend workspace name. Defaults to project + environment + module given ids.
  • Immutable after creation
object
Advanced Terraform variables. Optional raw Terraform variable overrides for advanced module inputs or one-off overrides. Values here override the generated variables above.
  • Default: {}