Deploying Microservices on AWS EKS with Private VPC and Subnets Using Terraform

Tanvir Ahmed
4 min readJan 16, 2025

--

Infrastructure Architecture Diagram

Modern cloud-native applications often follow the microservices architecture, enabling scalable, modular, and maintainable systems. In this blog, we’ll walk through deploying three microservices — user-service, transaction-service, and notification-service—on Amazon Elastic Kubernetes Service (EKS) using Terraform. We'll leverage a private VPC and private subnets to ensure a secure deployment.

For the complete source code and configuration files, visit the GitHub repository: 3-tier-microservices-k8s-terraform.

Why Private VPC and Private Subnets?

Deploying microservices within a private VPC enhances security by limiting access to the services from the internet. With private subnets:

  1. Worker nodes and services are not directly exposed.
  2. Access to the internet for updates or external communication is achieved through a NAT Gateway.
  3. Services communicate internally via ClusterIP and private DNS names.

Prerequisites

Before proceeding, ensure the following:

  1. AWS CLI and kubectl are installed and configured.
  2. Terraform (v1.0+) is installed.
  3. A basic understanding of Kubernetes and Terraform.
  4. Permissions to create resources like VPCs, subnets, and EKS clusters in your AWS account.

Architecture Overview

Our infrastructure will consist of:

  1. A VPC with both private and public subnets.
  2. An EKS Cluster with worker nodes deployed in private subnets.
  3. Microservices (user-service, transaction-service, notification-service) deployed as Kubernetes workloads.
  4. Internal communication between services using Kubernetes ClusterIP and DNS names.
  5. Optionally, an Application Load Balancer (ALB) to expose services securely.

Step-by-Step Deployment

1. Terraform & Manifests File Structure

Here is the recommended file structure:

├── eks
│ ├── manifests
│ │ ├── transaction-service.yaml
│ │ ├── notification-service.yaml
│ │ └── user-service.yaml
│ └── terraform
│ ├── eks-cluster.tf
│ ├── main.tf
│ ├── outputs.tf
│ └── vpc.tf
├── frontend
├── notification-service
├── transaction-service
└── user-service

2. VPC Configuration (terraform/vpc.tf)

Create a VPC with private and public subnets and a NAT Gateway for internet access from private subnets.

module "vpc" {
source = "terraform-aws-modules/vpc/aws"
version = "~> 3.19"
name = "private-vpc"
cidr = "10.0.0.0/16"
azs = ["us-east-1a", "us-east-1b"]
private_subnets = ["10.0.1.0/24", "10.0.2.0/24"]
public_subnets = ["10.0.3.0/24", "10.0.4.0/24"]
enable_nat_gateway = true
single_nat_gateway = true
tags = {
Name = "private-vpc"
}
}

3. EKS Cluster Configuration (terraform/eks-cluster.tf)

Deploy an EKS cluster with worker nodes in private subnets.

module "eks" {
source = "terraform-aws-modules/eks/aws"
version = "~> 18.0"
cluster_name = "microservices-cluster"
cluster_version = "1.27"
subnets = module.vpc.private_subnets
vpc_id = module.vpc.vpc_id
node_groups = {
private-nodes = {
desired_capacity = 2
max_capacity = 3
min_capacity = 1
instance_types = ["t3.medium"]
subnets = module.vpc.private_subnets
}
}
tags = {
Name = "eks-cluster"
}
}

4. Kubernetes Services YAML Files

Deploy the microservices as Kubernetes deployments and services.

user-service.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
name: user-service
labels:
app: user-service
spec:
replicas: 2
selector:
matchLabels:
app: user-service
template:
metadata:
labels:
app: user-service
spec:
containers:
- name: user-service
image: gcr.io/devops-demo-440509/user-service:latest
ports:
- containerPort: 8000
env:
- name: ALLOWED_ORIGINS
value: "http://frontend"
---
apiVersion: v1
kind: Service
metadata:
name: user-service
spec:
type: ClusterIP
selector:
app: user-service
ports:
- protocol: TCP
port: 8000
targetPort: 8000

Repeat similar configurations for transaction-service and notification-service.

5. Terraform Main File (main.tf)

Integrate VPC, EKS, and Kubernetes resources.

provider "aws" {
region = "us-east-1"
}
module "vpc" {
source = "./eks/vpc.tf"
}
module "eks" {
source = "./eks/eks-cluster.tf"
}
resource "kubernetes_namespace" "default" {
metadata {
name = "default"
}
}
provider "kubernetes" {
host = module.eks.cluster_endpoint
cluster_ca_certificate = base64decode(module.eks.cluster_certificate_authority_data)
token = module.eks.token
}
resource "kubernetes_deployment" "user_service" {
metadata {
name = "user-service"
namespace = "default"
}
spec {
replicas = 2
selector {
match_labels = {
app = "user-service"
}
}
template {
metadata {
labels = {
app = "user-service"
}
}
spec {
container {
image = "gcr.io/devops-demo-440509/user-service:latest"
name = "user-service"
port {
container_port = 8000
}
}
}
}
}
}

6. Apply the Terraform Plan

# Initialize Terraform
terraform init
# Validate configuration
terraform validate
# Plan the deployment
terraform plan
# Deploy the infrastructure
terraform apply

7. Testing the Microservices

  • Use Kubernetes port-forward for testing private services locally.
kubectl port-forward service/user-service 8000:8000
curl http://ip:8000/api/users/
  • Alternatively, use a bastion host to test from within the private network.

8. Optional: Add an API Gateway

To expose your services securely, consider deploying an API Gateway (e.g., AWS ALB Ingress or NGINX Ingress) for routing requests.

Conclusion

By deploying microservices on AWS EKS with a private VPC and private subnets, you achieve:

  1. Enhanced security by isolating services from direct internet exposure.
  2. Scalable and modular architecture using Kubernetes.
  3. Improved management with Terraform for infrastructure-as-code.

For the complete source code and YAML files, visit the GitHub repository: 3-tier-microservices-k8s-terraform.

This setup ensures your microservices are production-ready, secure, and easy to maintain. Happy deploying!

--

--

Tanvir Ahmed
Tanvir Ahmed

Written by Tanvir Ahmed

Tanvir is a Cloud & DevOps Engineer, AWS Certified. He focuses on multi-cloud, MLOps, and Data & AI, teaches others, and is always learning while enjoying life.

No responses yet