AWS EKS Infrastructure Setup Guide
CLI Setup
Prerequisites
- AWS CLI v2.0+
eksctl
v0.138.0+kubectl
v1.25+
Network Setup
- Create VPC:
bash
aws cloudformation deploy \
--template-file eks-vpc.yaml \
--stack-name prime-edm-vpc \
--parameters \
EnvironmentName=production \
VpcBlock=10.0.0.0/16 \
PublicSubnet1Block=10.0.1.0/24 \
PublicSubnet2Block=10.0.2.0/24 \
PrivateSubnet1Block=10.0.3.0/24 \
PrivateSubnet2Block=10.0.4.0/24
- Create Security Groups:
bash
aws ec2 create-security-group \
--group-name prime-edm-cluster-sg \
--description "EKS cluster security group" \
--vpc-id vpc-xxxxxxxx
aws ec2 authorize-security-group-ingress \
--group-id sg-xxxxxxxx \
--protocol tcp \
--port 443 \
--cidr 0.0.0.0/0
EKS Cluster Setup
- Create EKS cluster:
bash
eksctl create cluster \
--name prime-edm-cluster \
--region us-west-2 \
--version 1.25 \
--vpc-private-subnets subnet-xxxxx,subnet-yyyyy \
--vpc-public-subnets subnet-aaaaa,subnet-bbbbb \
--nodegroup-name standard-workers \
--node-type t3.medium \
--nodes 3 \
--nodes-min 1 \
--nodes-max 5 \
--managed
- Configure kubectl:
bash
aws eks update-kubeconfig \
--name prime-edm-cluster \
--region us-west-2
Node Group Management
- Add node group:
bash
eksctl create nodegroup \
--cluster prime-edm-cluster \
--region us-west-2 \
--name prod-workers \
--node-type t3.large \
--nodes 3 \
--nodes-min 3 \
--nodes-max 6 \
--managed
- Enable cluster autoscaler:
bash
kubectl apply -f https://raw.githubusercontent.com/kubernetes/autoscaler/master/cluster-autoscaler/cloudprovider/aws/examples/cluster-autoscaler-autodiscover.yaml
Terraform Setup
Prerequisites
- Terraform v1.0+
- AWS CLI configured
Directory Structure
terraform/
├── main.tf
├── variables.tf
├── outputs.tf
├── providers.tf
└── modules/
├── vpc/
├── eks/
└── node_groups/
Provider Configuration (providers.tf)
hcl
terraform {
required_version = ">= 1.0"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 4.0"
}
kubernetes = {
source = "hashicorp/kubernetes"
version = "~> 2.0"
}
}
}
provider "aws" {
region = var.region
}
Variables (variables.tf)
hcl
variable "region" {
description = "AWS region"
type = string
default = "us-west-2"
}
variable "cluster_name" {
description = "EKS cluster name"
type = string
default = "prime-edm-cluster"
}
variable "vpc_cidr" {
description = "VPC CIDR block"
type = string
default = "10.0.0.0/16"
}
variable "node_groups" {
description = "EKS node groups configuration"
type = map(object({
instance_types = list(string)
min_size = number
max_size = number
desired_size = number
}))
default = {
standard = {
instance_types = ["t3.medium"]
min_size = 1
max_size = 5
desired_size = 3
}
}
}
Main Configuration (main.tf)
hcl
module "vpc" {
source = "./modules/vpc"
vpc_cidr = var.vpc_cidr
cluster_name = var.cluster_name
}
module "eks" {
source = "./modules/eks"
cluster_name = var.cluster_name
vpc_id = module.vpc.vpc_id
subnet_ids = module.vpc.private_subnet_ids
node_groups = var.node_groups
}
module "node_groups" {
source = "./modules/node_groups"
cluster_name = var.cluster_name
node_groups = var.node_groups
subnet_ids = module.vpc.private_subnet_ids
}
VPC Module (modules/vpc/main.tf)
hcl
resource "aws_vpc" "main" {
cidr_block = var.vpc_cidr
enable_dns_hostnames = true
enable_dns_support = true
tags = {
Name = "${var.cluster_name}-vpc"
}
}
resource "aws_subnet" "private" {
count = 2
vpc_id = aws_vpc.main.id
cidr_block = cidrsubnet(var.vpc_cidr, 8, count.index)
availability_zone = data.aws_availability_zones.available.names[count.index]
tags = {
Name = "${var.cluster_name}-private-${count.index + 1}"
"kubernetes.io/role/internal-elb" = "1"
}
}
resource "aws_subnet" "public" {
count = 2
vpc_id = aws_vpc.main.id
cidr_block = cidrsubnet(var.vpc_cidr, 8, count.index + 2)
availability_zone = data.aws_availability_zones.available.names[count.index]
tags = {
Name = "${var.cluster_name}-public-${count.index + 1}"
"kubernetes.io/role/elb" = "1"
}
}
resource "aws_nat_gateway" "main" {
count = 2
allocation_id = aws_eip.nat[count.index].id
subnet_id = aws_subnet.public[count.index].id
tags = {
Name = "${var.cluster_name}-nat-${count.index + 1}"
}
}
EKS Module (modules/eks/main.tf)
hcl
resource "aws_eks_cluster" "main" {
name = var.cluster_name
role_arn = aws_iam_role.cluster.arn
version = "1.25"
vpc_config {
subnet_ids = var.subnet_ids
}
depends_on = [
aws_iam_role_policy_attachment.cluster_AmazonEKSClusterPolicy,
aws_iam_role_policy_attachment.cluster_AmazonEKSVPCResourceController,
]
}
resource "aws_iam_role" "cluster" {
name = "${var.cluster_name}-cluster-role"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Action = "sts:AssumeRole"
Effect = "Allow"
Principal = {
Service = "eks.amazonaws.com"
}
}
]
})
}
resource "aws_iam_role_policy_attachment" "cluster_AmazonEKSClusterPolicy" {
policy_arn = "arn:aws:iam::aws:policy/AmazonEKSClusterPolicy"
role = aws_iam_role.cluster.name
}
resource "aws_iam_role_policy_attachment" "cluster_AmazonEKSVPCResourceController" {
policy_arn = "arn:aws:iam::aws:policy/AmazonEKSVPCResourceController"
role = aws_iam_role.cluster.name
}
Node Groups Module (modules/node_groups/main.tf)
hcl
resource "aws_eks_node_group" "main" {
for_each = var.node_groups
cluster_name = var.cluster_name
node_group_name = each.key
node_role_arn = aws_iam_role.node.arn
subnet_ids = var.subnet_ids
scaling_config {
desired_size = each.value.desired_size
max_size = each.value.max_size
min_size = each.value.min_size
}
instance_types = each.value.instance_types
depends_on = [
aws_iam_role_policy_attachment.node_AmazonEKSWorkerNodePolicy,
aws_iam_role_policy_attachment.node_AmazonEKS_CNI_Policy,
aws_iam_role_policy_attachment.node_AmazonEC2ContainerRegistryReadOnly,
]
}
resource "aws_iam_role" "node" {
name = "${var.cluster_name}-node-role"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Action = "sts:AssumeRole"
Effect = "Allow"
Principal = {
Service = "ec2.amazonaws.com"
}
}
]
})
}
resource "aws_iam_role_policy_attachment" "node_AmazonEKSWorkerNodePolicy" {
policy_arn = "arn:aws:iam::aws:policy/AmazonEKSWorkerNodePolicy"
role = aws_iam_role.node.name
}
resource "aws_iam_role_policy_attachment" "node_AmazonEKS_CNI_Policy" {
policy_arn = "arn:aws:iam::aws:policy/AmazonEKS_CNI_Policy"
role = aws_iam_role.node.name
}
resource "aws_iam_role_policy_attachment" "node_AmazonEC2ContainerRegistryReadOnly" {
policy_arn = "arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly"
role = aws_iam_role.node.name
}