
Introduction
In modern DevOps workflows, Infrastructure as Code (IaC) and CI/CD pipelines play a crucial role in ensuring scalable, repeatable, and automated deployments. AWS EKS (Elastic Kubernetes Service) allows teams to run Kubernetes clusters without managing the control plane, while Terraform helps with automated infrastructure provisioning.
In this guide, we’ll build an end-to-end DevOps pipeline to:
✅ Provision an EKS cluster with Terraform✅ Containerize a sample application using Docker✅ Push the image to Amazon ECR (Elastic Container Registry)✅ Deploy the app to Kubernetes using Helm✅ Automate everything with a GitHub Actions CI/CD pipeline
🚀 Architecture Overview
The workflow consists of the following steps:
1️⃣ Terraform provisions AWS infrastructure (VPC, EKS, IAM roles, security groups)2️⃣ Docker builds & pushes a containerized app to AWS ECR3️⃣ Kubernetes manifests (or Helm) deploy the app to the EKS cluster4️⃣ GitHub Actions automates CI/CD pipeline execution
1️⃣ Provisioning AWS EKS with Terraform
Step 1: Install Prerequisites
Ensure you have the following installed:
- Terraform (>=1.5.0)
- AWS CLI (
aws configure) - Kubectl (
eksctl install) - Helm (
helm install)
Step 2: Create Terraform Configuration for EKS
main.tf - Define the EKS cluster:
provider "aws" {
region = "us-east-1"
}
resource "aws_iam_role" "eks_cluster_role" {
name = "eks-cluster-role"
assume_role_policy = jsonencode({
Statement = [{
Action = "sts:AssumeRole"
Effect = "Allow"
Principal = { Service = "eks.amazonaws.com" }
}]
})
}
resource "aws_eks_cluster" "my_eks" {
name = "my-cluster"
role_arn = aws_iam_role.eks_cluster_role.arn
vpc_config {
subnet_ids = [aws_subnet.public_1.id, aws_subnet.public_2.id]
}
}
resource "aws_eks_node_group" "node_group" {
cluster_name = aws_eks_cluster.my_eks.name
node_role_arn = aws_iam_role.eks_cluster_role.arn
subnet_ids = [aws_subnet.public_1.id, aws_subnet.public_2.id]
instance_types = ["t3.medium"]
desired_size = 2
}
Step 3: Apply Terraform Configuration
terraform init
terraform apply -auto-approve
Verify the cluster:
aws eks --region us-east-1 update-kubeconfig --name my-cluster
kubectl get nodes
2️⃣ Build and Push Docker Image to Amazon ECR
Step 1: Create an ECR Repository
aws ecr create-repository --repository-name my-app
Step 2: Build and Push Docker Image
Dockerfile - Define containerized application:
FROM node:18
WORKDIR /app
COPY . .
RUN npm install
CMD ["node", "server.js"]
EXPOSE 3000
Authenticate and push to ECR:
aws ecr get-login-password --region us-east-1 | docker login --username AWS --password-stdin <account_id>.dkr.ecr.us-east-1.amazonaws.com
docker build -t my-app .
docker tag my-app:latest <account_id>.dkr.ecr.us-east-1.amazonaws.com/my-app:latest
docker push <account_id>.dkr.ecr.us-east-1.amazonaws.com/my-app:latest
3️⃣ Deploying to Kubernetes (EKS) using Helm
Step 1: Create Kubernetes Deployment Manifest
deployment.yaml - Define Kubernetes deployment:
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
spec:
replicas: 2
selector:
matchLabels:
app: my-app
template:
metadata:
labels:
app: my-app
spec:
containers:
- name: my-app
image: <account_id>.dkr.ecr.us-east-1.amazonaws.com/my-app:latest
ports:
- containerPort: 3000
Apply the deployment:
kubectl apply -f deployment.yaml
kubectl get pods
Step 2: Expose the Application
service.yaml - Define Kubernetes service:
apiVersion: v1
kind: Service
metadata:
name: my-app-service
spec:
selector:
app: my-app
ports:
- protocol: TCP
port: 80
targetPort: 3000
type: LoadBalancer
Apply the service:
kubectl apply -f service.yaml
kubectl get svc
4️⃣ Automating Everything with GitHub Actions
.github/workflows/deploy.yaml - Define CI/CD pipeline:
name: CI/CD Pipeline
on:
push:
branches:
- main
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/checkout@v2
- name: Login to AWS ECR
run: aws ecr get-login-password --region us-east-1 | docker login --username AWS --password-stdin <account_id>.dkr.ecr.us-east-1.amazonaws.com
- name: Build and Push Docker Image
run: |
docker build -t my-app .
docker tag my-app:latest <account_id>.dkr.ecr.us-east-1.amazonaws.com/my-app:latest
docker push <account_id>.dkr.ecr.us-east-1.amazonaws.com/my-app:latest
- name: Deploy to Kubernetes
run: |
kubectl apply -f deployment.yaml
kubectl apply -f service.yaml
🚀 Best Practices
✅ Use Terraform remote state with S3 + DynamoDB✅ Implement secrets management with AWS Secrets Manager✅ Use Helm charts for better Kubernetes deployments✅ Integrate AWS CloudWatch for monitoring
❓ FAQs
1️⃣ How do I update my app after changes?
- Push changes to main branch, and GitHub Actions will rebuild and deploy automatically.
2️⃣ How do I rollback a deployment?
kubectl rollout undo deployment my-app
3️⃣ Can I integrate AWS ALB with EKS?
- Yes! Use the AWS ALB Ingress Controller to expose services via ALB.
4️⃣ How do I monitor the application?
- Use AWS CloudWatch and
kubectl logs -f <pod-name>for debugging.
Share your thoughts below! 👇
📢 Have questions or feedback? Drop a comment below or connect with me on Twitter/X@spysood!
Originally published on Medium.