Work in Progress: This page is under development. Use the feedback button on the bottom right to help us improve it.

AWS EKS Deployment

Deploy Laminar on Amazon EKS for production workloads.

Prerequisites

Quick Start

cd laminar-infra
 
# 1. Create AWS infrastructure
cd infrastructure/environments/dev
terragrunt run --all apply
 
# 2. Configure kubectl
aws eks update-kubeconfig --name laminar-dev-eks-cluster --region us-east-1

Architecture

Network Topology

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                          VPC: 10.0.0.0/16                                   β”‚
β”‚                          Region: us-east-1                                  β”‚
β”‚                                                                             β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
β”‚  β”‚                        Internet Gateway                               β”‚  β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
β”‚              β”‚                    β”‚                    β”‚                    β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”         β”‚
β”‚  β”‚   Public Subnet   β”‚ β”‚   Public Subnet   β”‚ β”‚   Public Subnet   β”‚         β”‚
β”‚  β”‚  10.0.192.0/20    β”‚ β”‚  10.0.208.0/20    β”‚ β”‚  10.0.224.0/20    β”‚         β”‚
β”‚  β”‚    us-east-1a     β”‚ β”‚    us-east-1b     β”‚ β”‚    us-east-1c     β”‚         β”‚
β”‚  β”‚                   β”‚ β”‚                   β”‚ β”‚                   β”‚         β”‚
β”‚  β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚ β”‚                   β”‚ β”‚                   β”‚         β”‚
β”‚  β”‚  β”‚     NLB     β”‚  β”‚ β”‚                   β”‚ β”‚                   β”‚         β”‚
β”‚  β”‚  β”‚  (ingress)  β”‚  β”‚ β”‚                   β”‚ β”‚                   β”‚         β”‚
β”‚  β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚ β”‚                   β”‚ β”‚                   β”‚         β”‚
β”‚  β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚ β”‚                   β”‚ β”‚                   β”‚         β”‚
β”‚  β”‚  β”‚ NAT Gateway β”‚  β”‚ β”‚                   β”‚ β”‚                   β”‚         β”‚
β”‚  β”‚  β”‚ (Elastic IP)β”‚  β”‚ β”‚                   β”‚ β”‚                   β”‚         β”‚
β”‚  β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚ β”‚                   β”‚ β”‚                   β”‚         β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜         β”‚
β”‚              β”‚                    β”‚                    β”‚                    β”‚
β”‚              β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                    β”‚
β”‚                                   β”‚                                         β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
β”‚  β”‚                    Private Subnets (EKS Worker Nodes)                 β”‚  β”‚
β”‚  β”‚                                                                       β”‚  β”‚
β”‚  β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚  β”‚
β”‚  β”‚  β”‚ tenant-{name} namespace                                         β”‚  β”‚  β”‚
β”‚  β”‚  β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚  β”‚  β”‚
β”‚  β”‚  β”‚  β”‚ Console  β”‚ β”‚ Controller β”‚ β”‚  Workers   β”‚ β”‚  PostgreSQL  β”‚   β”‚  β”‚  β”‚
β”‚  β”‚  β”‚  β”‚  :3000   β”‚ β”‚   :8000    β”‚ β”‚  (dynamic) β”‚ β”‚    :5432     β”‚   β”‚  β”‚  β”‚
β”‚  β”‚  β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚  β”‚  β”‚
β”‚  β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚  β”‚
β”‚  β”‚                                                                       β”‚  β”‚
β”‚  β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚  β”‚
β”‚  β”‚  β”‚ laminar-monitoring namespace                                    β”‚  β”‚  β”‚
β”‚  β”‚  β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                    β”‚  β”‚  β”‚
β”‚  β”‚  β”‚  β”‚ Grafana  β”‚ β”‚ GrepTimeDB β”‚ β”‚   Vector   β”‚                    β”‚  β”‚  β”‚
β”‚  β”‚  β”‚  β”‚  :3001   β”‚ β”‚   :4000    β”‚ β”‚            β”‚                    β”‚  β”‚  β”‚
β”‚  β”‚  β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                    β”‚  β”‚  β”‚
β”‚  β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚  β”‚
β”‚  β”‚                                                                       β”‚  β”‚
β”‚  β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚  β”‚
β”‚  β”‚  β”‚ laminar-connectors namespace                                    β”‚  β”‚  β”‚
β”‚  β”‚  β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                                   β”‚  β”‚  β”‚
β”‚  β”‚  β”‚  β”‚  MinIO   β”‚ β”‚  Redpanda  β”‚                                   β”‚  β”‚  β”‚
β”‚  β”‚  β”‚  β”‚  :9000   β”‚ β”‚   :9092    β”‚                                   β”‚  β”‚  β”‚
β”‚  β”‚  β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                                   β”‚  β”‚  β”‚
β”‚  β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚  β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
β”‚                                                                             β”‚
β”‚  Route Tables:                                                              β”‚
β”‚  β€’ Public:  0.0.0.0/0 β†’ Internet Gateway                                   β”‚
β”‚  β€’ Private: 0.0.0.0/0 β†’ NAT Gateway                                        β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Traffic Flow

Inbound (Internet β†’ Application):

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Internet │───▢│ Route53  │───▢│    NLB      │───▢│ingress-nginx│───▢│   Pod    β”‚
β”‚          β”‚    β”‚lmnr.cloudβ”‚    β”‚ :80/:443    β”‚    β”‚ ClusterIP   β”‚    β”‚  :3000   β”‚
β”‚          β”‚    β”‚          β”‚    β”‚ Public SN   β”‚    β”‚ Private SN  β”‚    β”‚ Private  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Outbound (Pod β†’ Internet):

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚   Pod    │───▢│ Private RT  │───▢│ NAT Gateway │───▢│ Internet β”‚
β”‚ Private  β”‚    β”‚ 0.0.0.0/0   β”‚    β”‚ Elastic IP  β”‚    β”‚          β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

VPC Configuration

SettingValue
CIDR10.0.0.0/16 (65,536 IPs)
DNS HostnamesEnabled
DNS SupportEnabled
Regionus-east-1

Subnets

TypeCIDRAZIPsPurposeK8s Tag
Public10.0.192.0/20us-east-1a4,096NLB, NATkubernetes.io/role/elb=1
Public10.0.208.0/20us-east-1b4,096NLBkubernetes.io/role/elb=1
Public10.0.224.0/20us-east-1c4,096NLBkubernetes.io/role/elb=1
Private10.0.0.0/18us-east-1a16,384EKS nodeskubernetes.io/role/internal-elb=1
Private10.0.64.0/18us-east-1b16,384EKS nodeskubernetes.io/role/internal-elb=1
Private10.0.128.0/18us-east-1c16,384EKS nodeskubernetes.io/role/internal-elb=1

EKS Cluster

SettingValue
Namelaminar-dev-eks-cluster
Kubernetes Version1.30
Endpoint AccessPublic + Private
AddonsEBS CSI Driver (IRSA)
OIDC ProviderEnabled (for IRSA)

Node Groups

GroupInstance TypeCountvCPUMemoryAMIDisk
large-nodesc8g.xlarge348 GiBAL2023_ARM_6430GB gp3
medium-nodesc8g.medium512 GiBAL2023_ARM_6430GB gp3

Total Capacity: 8 nodes, 17 vCPU, 34 GiB memory

Ingress (Network Load Balancer)

SettingValue
TypeNetwork Load Balancer (NLB)
Schemeinternet-facing
Target TypeIP (direct to pods)
Cross-Zone LBEnabled
Ports80 (HTTP), 443 (HTTPS)
Controlleringress-nginx

Storage

ClassProvisionerTypeIOPSEncryptedBinding
gp3 (default)ebs.csi.aws.comgp33,000YesWaitForFirstConsumer

IRSA (IAM Roles for Service Accounts)

RoleService AccountNamespacePermissions
argo-workflows-ecr-pushargo-workflowargoECR push to laminar/*
ebs-csi-controllerebs-csi-controller-sakube-systemEBS volume management

Security

LayerConfiguration
Node PlacementPrivate subnets only
Instance MetadataIMDSv2 enforced (token-based)
EBS VolumesEncrypted by default
IAMIRSA for fine-grained permissions
Load BalancerNLB in public subnets
API ServerPublic + Private access

DNS & TLS

ComponentConfiguration
DNS ProviderRoute53
Domain*.lmnr.cloud
Certificate Managercert-manager
ACME ServerLet's Encrypt (letsencrypt-prod)
ValidationHTTP-01 via ingress-nginx
ClusterIssuersletsencrypt-staging, letsencrypt-prod

Infrastructure Components

Terragrunt creates:

ResourceDescription
VPC10.0.0.0/16 with public/private subnets
EKSKubernetes 1.30 cluster
Node Group3x c8g.xlarge + 5x c8g.medium (ARM64)
NAT GatewayFor private subnet internet access
IRSAIAM roles for service accounts

Infrastructure Structure

infrastructure/
β”œβ”€β”€ root.hcl              # Terragrunt root config
β”œβ”€β”€ modules/              # Reusable Terraform modules
β”‚   └── aws/
β”‚       β”œβ”€β”€ vpc/
β”‚       β”œβ”€β”€ subnets/
β”‚       β”œβ”€β”€ eks/
β”‚       └── ...
└── environments/
    └── dev/
        β”œβ”€β”€ env.hcl       # Environment variables
        β”œβ”€β”€ vpc/
        β”œβ”€β”€ public_subnets/
        β”œβ”€β”€ private_subnets/
        β”œβ”€β”€ nat_gateway/
        β”œβ”€β”€ eks/
        └── ...

Commands

Infrastructure:

cd infrastructure/environments/dev
 
terragrunt run --all plan     # Preview changes
terragrunt run --all apply    # Apply all
terragrunt run --all destroy  # Destroy all

Configuration

Environment config - infrastructure/environments/dev/env.hcl:

locals {
  environment             = "dev"
  vpc_cidr                = "10.0.0.0/16"
  aws_region              = "us-east-1"
  kubernetes_cluster_name = "laminar-dev-eks-cluster"
}

Create new environment:

  1. Copy environments/dev to environments/prod
  2. Update env.hcl with new values
  3. Run terragrunt run --all apply