A beginner-friendly walkthrough of provisioning a real Kubernetes cluster, Jenkins CI/CD pipeline, and security tooling on AWS — step by step.
🧭 What We're Building
By the end of this guide you'll have a fully working DevOps environment running on AWS EC2 that includes:
- A custom VPC with security groups
- A Kubernetes (v1.28) cluster with 1 master + 2 worker nodes
- A Jenkins CI/CD pipeline that takes code from commit all the way to production
- SonarQube for automated code quality analysis
- Kubeaudit for Kubernetes security scanning
- Nexus Repository Manager for artifact versioning
- Docker for containerizing and pushing images
This is the exact setup I built for a real project — so everything here is battle-tested.
🛠️ Prerequisites
Before we start, make sure you have:
- An AWS account (free tier works for learning)
- Basic familiarity with the Linux command line
- SSH client installed (Terminal on Mac/Linux, PuTTY or WSL on Windows)
That's it. You don't need to be a DevOps expert — that's what this guide is for.
Step 1 — Create Your VPC and Security Groups
The first thing we need is a Virtual Private Cloud (VPC) — think of it as your own private network inside AWS.
Create the VPC
- Go to AWS Console → VPC → Create VPC
- Set the IPv4 CIDR block to
10.0.0.0/16 - Give it a name like
devops-vpc - Click Create
Create a Subnet
- Go to Subnets → Create Subnet
- Select your new VPC
- Set CIDR to
10.0.1.0/24 - Choose an availability zone (e.g.
us-east-1a)
Set Up Security Groups
This is important — we need to open specific ports for our tools to communicate.
- Go to Security Groups → Create Security Group
- Add these Inbound Rules:
| Port | Protocol | Purpose |
|---|---|---|
| 22 | TCP | SSH access |
| 6443 | TCP | Kubernetes API server |
| 8080 | TCP | Jenkins web UI |
| 8081 | TCP | Nexus Repository Manager |
| 9000 | TCP | SonarQube |
| 30000-32767 | TCP | Kubernetes NodePort services |
💡 Tip: For learning purposes you can set the source to
0.0.0.0/0. For production, always restrict to your IP.
Step 2 — Launch Your EC2 Instances
We need 3 EC2 instances — one master node and two worker nodes for Kubernetes.
Launch Each Instance
- Go to EC2 → Launch Instance
- Choose Ubuntu 22.04 LTS as the AMI
- Select t2.medium (2 vCPU, 4GB RAM) — minimum for Kubernetes
- Select your VPC and subnet from Step 1
- Attach your security group
- Create or use an existing key pair (.pem file) for SSH
- Launch
Repeat this 3 times — name them:
k8s-masterk8s-worker-1k8s-worker-2
Connect via SSH
chmod 400 your-key.pem
ssh -i your-key.pem ubuntu@<YOUR_EC2_PUBLIC_IP>
Step 3 — Set Up Kubernetes with Kubeadm
Run these commands on all 3 nodes first.
Install Dependencies (all nodes)
# Update packages
sudo apt-get update && sudo apt-get upgrade -y
# Install Docker
sudo apt-get install -y docker.io
sudo systemctl enable docker
sudo systemctl start docker
# Install Kubernetes tools
sudo apt-get install -y apt-transport-https ca-certificates curl
curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.28/deb/Release.key | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg
echo 'deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.28/deb/ /' | sudo tee /etc/apt/sources.list.d/kubernetes.list
sudo apt-get update
sudo apt-get install -y kubelet kubeadm kubectl
sudo apt-mark hold kubelet kubeadm kubectl
# Disable swap (required by Kubernetes)
sudo swapoff -a
sudo sed -i '/ swap / s/^\(.*\)$/#\1/g' /etc/fstab
Initialize the Master Node
Run this only on the master node:
sudo kubeadm init --pod-network-cidr=10.244.0.0/16
# Set up kubectl for your user
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
# Install Flannel network plugin
kubectl apply -f https://raw.githubusercontent.com/flannel-io/flannel/master/Documentation/kube-flannel.yml
After kubeadm init completes, you'll see a kubeadm join command. Copy it — you'll need it for the worker nodes.
Join the Worker Nodes
Run the join command on each worker node:
sudo kubeadm join <MASTER_IP>:6443 --token <TOKEN> --discovery-token-ca-cert-hash sha256:<HASH>
Verify Your Cluster
Back on the master node:
kubectl get nodes
You should see all 3 nodes with status Ready. 🎉
Step 4 — Install Jenkins
Run this on your master node (or a dedicated EC2 instance):
# Install Java (required by Jenkins)
sudo apt-get install -y openjdk-21-jdk
# Add Jenkins repo
curl -fsSL https://pkg.jenkins.io/debian-stable/jenkins.io-2023.key | sudo tee /usr/share/keyrings/jenkins-keyring.asc > /dev/null
echo deb [signed-by=/usr/share/keyrings/jenkins-keyring.asc] https://pkg.jenkins.io/debian-stable binary/ | sudo tee /etc/apt/sources.list.d/jenkins.list > /dev/null
sudo apt-get update
sudo apt-get install -y jenkins
sudo systemctl enable jenkins
sudo systemctl start jenkins
Open Jenkins in your browser at http://<YOUR_EC2_IP>:8080
Get the initial admin password:
sudo cat /var/lib/jenkins/secrets/initialAdminPassword
Install Required Jenkins Plugins
Go to Manage Jenkins → Plugins and install:
- Docker Pipeline
- Kubernetes CLI
- Maven Integration
- SonarQube Scanner
Step 5 — Set Up SonarQube
# Run SonarQube via Docker (easiest way)
docker run -d --name sonarqube \
-p 9000:9000 \
sonarqube:community
Open http://<YOUR_EC2_IP>:9000 — default login is admin / admin.
Connect SonarQube to Jenkins
- In SonarQube go to Administration → Security → Generate Token
- Copy the token
- In Jenkins go to Manage Jenkins → Credentials → Add
- Add the token as a Secret Text credential named
sonar-token
Step 6 — Set Up Nexus Repository Manager
docker run -d --name nexus \
-p 8081:8081 \
sonatype/nexus3
Open http://<YOUR_EC2_IP>:8081
Get the admin password:
docker exec nexus cat /nexus-data/admin.password
Nexus will store your built artifacts (JAR files, Docker images) so every build is versioned and traceable.
Step 7 — Create Your Jenkins Pipeline
Create a file called Jenkinsfile in the root of your project repo:
pipeline {
agent any
tools {
jdk 'JDK21'
maven 'Maven3'
}
stages {
stage('Checkout') {
steps {
git branch: 'main', url: 'https://github.com/YOUR_USERNAME/YOUR_REPO.git'
}
}
stage('Build') {
steps {
sh 'mvn clean package -DskipTests'
}
}
stage('SonarQube Analysis') {
steps {
withSonarQubeEnv('SonarQube') {
sh 'mvn sonar:sonar'
}
}
}
stage('Build Docker Image') {
steps {
sh 'docker build -t your-app:${BUILD_NUMBER} .'
sh 'docker tag your-app:${BUILD_NUMBER} your-registry/your-app:${BUILD_NUMBER}'
}
}
stage('Push to Nexus') {
steps {
sh 'mvn deploy'
}
}
stage('Deploy to Kubernetes') {
steps {
sh 'kubectl apply -f k8s/deployment.yaml'
sh 'kubectl set image deployment/your-app your-app=your-registry/your-app:${BUILD_NUMBER}'
}
}
}
post {
success {
echo '✅ Pipeline completed successfully!'
}
failure {
echo '❌ Pipeline failed — check the logs above.'
}
}
}
Step 8 — Security Scanning with Kubeaudit
Kubeaudit scans your Kubernetes cluster for common security issues.
# Install Kubeaudit
wget https://github.com/Shopify/kubeaudit/releases/latest/download/kubeaudit_linux_amd64.tar.gz
tar -xzf kubeaudit_linux_amd64.tar.gz
sudo mv kubeaudit /usr/local/bin/
# Run a full audit
kubeaudit all
Common issues it will flag:
- Missing NetworkPolicies (controls traffic between pods)
- Missing AppArmor annotations
- Containers running as root
- Missing resource limits
Fix them one by one — each fix makes your cluster significantly more secure.
🎉 What You've Built
Congratulations! You now have a production-grade DevOps environment that:
- Automatically builds your code on every commit
- Scans for bugs with SonarQube before deploying
- Stores versioned artifacts in Nexus
- Deploys to Kubernetes with zero downtime
- Audits security with Kubeaudit
This is the kind of infrastructure that runs real production workloads at companies around the world.
💡 Key Lessons I Learned
- Security groups matter — always be intentional about which ports are open
- Swap must be disabled before Kubernetes will work — I learned this the hard way
- Kubeaudit catches things you'd never think of — run it early, not after you deploy
- Nexus + versioned artifacts means you can always roll back to any previous build
🔗 What's Next?
- Add Terraform to provision all of this infrastructure as code
- Set up Prometheus + Grafana for monitoring your cluster
- Configure automatic SSL with cert-manager
- Add Helm charts for cleaner Kubernetes deployments
Thanks for reading! If this helped you, drop a ❤️ and follow for more DevOps content. Feel free to ask questions in the comments — I'm happy to help.
Tags: devops kubernetes aws jenkins docker
Top comments (0)