Skip main navigation
/user/kayd @ :~$ cat deploy-jenkins-eks-tutorial.md

Deploy Jenkins on Amazon EKS: Complete Tutorial for Pods and Deployments Deploy Jenkins on Amazon EKS: Complete Tutorial for Pods and Deployments

QR Code for Article
Karandeep Singh
Karandeep Singh
• 8 minutes

Summary

Step-by-step tutorial for deploying Jenkins on Amazon EKS. Learn pods vs deployments and why each matters for your CI/CD setup.

What We’re Building Today

Today I’ll show you how to run Jenkins on Amazon EKS. We’ll start simple with pods. Then I’ll explain why that’s not enough for production. Finally, we’ll build it properly with deployments.

By the end, you’ll understand the difference between pods and deployments. More importantly, you’ll know when to use each one.

What Actually Is a Pod?

Think of a pod as a wrapper around your container. It’s the smallest thing you can deploy in Kubernetes. A pod usually contains one container, but it can have more.

Here’s the thing though - pods are fragile. If something goes wrong, the pod just dies. Kubernetes won’t restart it automatically. That’s where deployments come in, but we’ll get to that.

Why Start with Pods?

Pods are great for learning and testing. They’re simple to understand. You create one, it runs, you delete it. No magic happening behind the scenes.

But here’s what happens when you use just pods in production. Your Jenkins dies at 3 AM. Nobody notices until morning. Your team can’t deploy anything. Everyone’s mad.

That’s why we need deployments. But let’s start with pods first so you understand the building blocks.

Setting Up Your First Jenkins Pod

Make sure your EKS cluster is running. I’m assuming you already have that part sorted. If not, that’s a different tutorial.

Create a file called jenkins-pod.yaml. Here’s what goes inside:

apiVersion: v1
kind: Pod
metadata:
  name: jenkins-pod
  labels:
    app: jenkins
spec:
  containers:
  - name: jenkins
    image: jenkins/jenkins:lts
    ports:
    - containerPort: 8080
    - containerPort: 50000

Let me break this down for you:

  • apiVersion: v1 - This tells Kubernetes what version of the pod spec we’re using
  • kind: Pod - We’re creating a pod (not a deployment, not a service)
  • metadata - Basic info about our pod like name and labels
  • spec - The actual configuration of what goes inside the pod

The container section is pretty straightforward. We’re using the official Jenkins LTS image. Port 8080 is for the web UI. Port 50000 is for build agents to connect.

Deploy this pod:

kubectl apply -f jenkins-pod.yaml

Check if it’s working:

kubectl get pods

You should see something like this:

NAME          READY   STATUS    RESTARTS   AGE
jenkins-pod   1/1     Running   0          30s

How to Access Your Jenkins Pod

Here’s the tricky part. Your Jenkins is running inside the cluster. You can’t just open a browser and go to it. You need to create a tunnel.

Use port-forward to access it:

kubectl port-forward jenkins-pod 8080:8080

Keep this command running. Open your browser and go to http://localhost:8080. You should see the Jenkins unlock screen.

Getting the Initial Jenkins Password

Jenkins creates a random password on first startup. You need to grab it from the logs:

kubectl logs jenkins-pod

Look for something like this in the output:

Jenkins initial setup is required. An admin user has been created and a password generated.
Please use the following password to proceed to installation:

f8d8c9b4a1e2c3d4e5f6g7h8i9j0k1l2

This may also be found at: /var/jenkins_home/secrets/initialAdminPassword

Copy that password and paste it into the Jenkins setup page.

The Problem with Just Using Pods

Now here’s where things get real. Let’s say your Jenkins pod crashes. Maybe it runs out of memory. Maybe the node dies. What happens?

Your pod is gone. That’s it. Game over.

Try this experiment. Delete your pod:

kubectl delete pod jenkins-pod

Now check what’s running:

kubectl get pods

Nothing. Your Jenkins is completely gone. All your job configurations, build history, everything.

This is why we don’t use naked pods in production. They’re too fragile.

Enter Deployments - The Solution

A deployment is like a smart wrapper around pods. It knows how many pods you want running. If one dies, it creates a new one automatically.

Think of it as a supervisor for your pods. The supervisor’s job is to make sure the right number of pods are always running.

Here’s how a deployment works:

  1. You say “I want 1 Jenkins pod running”
  2. Deployment creates 1 pod
  3. Pod dies for some reason
  4. Deployment notices and creates a new pod
  5. You’re back to 1 pod running

Let’s build this properly now.

Creating Your Jenkins Deployment

Create a new file called jenkins-deployment.yaml:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: jenkins-deployment
spec:
  replicas: 1
  selector:
    matchLabels:
      app: jenkins
  template:
    metadata:
      labels:
        app: jenkins
    spec:
      containers:
      - name: jenkins
        image: jenkins/jenkins:lts
        ports:
        - containerPort: 8080
        - containerPort: 50000

This looks similar to our pod, but there’s some new stuff:

  • kind: Deployment - We’re creating a deployment now
  • replicas: 1 - We want exactly 1 pod running
  • selector - How the deployment finds its pods
  • template - The pod specification that gets created

The template section is basically our original pod spec. But now it’s wrapped in a deployment that manages it.

Deploy this:

kubectl apply -f jenkins-deployment.yaml

Check what got created:

kubectl get deployments
kubectl get pods

You’ll see both a deployment and a pod. The deployment created the pod automatically.

Testing Deployment Self-Healing

Now for the cool part. Let’s kill the pod and watch what happens:

First, get the pod name:

kubectl get pods

You’ll see something like jenkins-deployment-abc123-xyz. Delete it:

kubectl delete pod jenkins-deployment-abc123-xyz

Immediately run this:

kubectl get pods

You’ll see the old pod terminating and a new one starting up. The deployment noticed the pod was gone and created a replacement automatically.

This is why deployments are essential for production workloads.

Accessing Your Deployment

Access your deployment the same way:

kubectl port-forward deployment/jenkins-deployment 8080:8080

Notice I’m using deployment/jenkins-deployment instead of the pod name. This automatically connects to one of the pods managed by the deployment.

0

Why Not Just Scale Pods?

You might be thinking “why not just create multiple pods manually?” Let me show you why that’s a bad idea.

If you create 3 separate Jenkins pods, you’ll have 3 different Jenkins instances. They won’t share data. They’ll fight over ports. It’ll be a mess.

Jenkins is special - you typically want exactly one master running. But the deployment still helps because it ensures that one pod is always available.

For other applications, you might want multiple replicas. Web servers, APIs, workers - these can all be scaled horizontally with deployments.

1

Adding Storage (Finally Some Persistence)

Right now, when your pod restarts, you lose all Jenkins data. That’s not useful for real work. Let’s add some storage.

Update your deployment to include a volume:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: jenkins-deployment
spec:
  replicas: 1
  selector:
    matchLabels:
      app: jenkins
  template:
    metadata:
      labels:
        app: jenkins
    spec:
      containers:
      - name: jenkins
        image: jenkins/jenkins:lts
        ports:
        - containerPort: 8080
        - containerPort: 50000
        volumeMounts:
        - name: jenkins-storage
          mountPath: /var/jenkins_home
      volumes:
      - name: jenkins-storage
        emptyDir: {}

The new parts:

  • volumeMounts - Where to mount the storage inside the container
  • volumes - What kind of storage to use

I’m using emptyDir here which is simple but temporary. The data survives pod restarts but not node failures. For production, you’d want persistent volumes, but that’s beyond our scope today.

Apply the changes:

2
kubectl apply -f jenkins-deployment.yaml

Building Jenkins Agents with Pods

Jenkins master doesn’t do the actual build work. That’s what agents are for. You can run agents as separate pods.

Create jenkins-agent-pod.yaml:

apiVersion: v1
kind: Pod
metadata:
  name: jenkins-agent-pod
  labels:
    app: jenkins-agent
spec:
  containers:
  - name: jenkins-agent
    image: jenkins/inbound-agent:latest

This creates a basic agent pod. In a real setup, you’d configure it to connect to your Jenkins master. But for learning purposes, this shows you the structure.

3

Scaling Agents with Deployments

If you need multiple agents, use a deployment instead of individual pods:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: jenkins-agent-deployment
spec:
  replicas: 3
  selector:
    matchLabels:
      app: jenkins-agent
  template:
    metadata:
      labels:
        app: jenkins-agent
    spec:
      containers:
      - name: jenkins-agent
        image: jenkins/inbound-agent:latest

This creates 3 agent pods. Unlike Jenkins master, agents can be scaled horizontally. More agents = more parallel builds.

Deploy it:

4
kubectl apply -f jenkins-agent-deployment.yaml

When to Use Pods vs Deployments

Here’s my rule of thumb:

Use pods for:

  • Quick testing
  • One-off jobs
  • Learning Kubernetes concepts

Use deployments for:

  • Anything that needs to stay running
  • Production workloads
  • Applications that might need scaling

In this Jenkins example, both the master and agents should probably be deployments in production. Even though Jenkins master is typically single-instance, the self-healing aspect of deployments is valuable.

5

Common Mistakes I See

Mistake 1: Running production workloads as naked pods Solution: Always use deployments for anything important

Mistake 2: Trying to scale Jenkins master to multiple replicas Solution: Keep Jenkins master at 1 replica, scale agents instead

Mistake 3: Not setting resource limits Solution: Always set CPU and memory limits on your containers

Here’s how to add resource limits:

6
containers:
- name: jenkins
  image: jenkins/jenkins:lts
  resources:
    limits:
      cpu: 2000m
      memory: 4Gi
    requests:
      cpu: 1000m
      memory: 2Gi

Troubleshooting Your Setup

When things go wrong (and they will), here’s how to debug:

Check pod status:

kubectl get pods
kubectl describe pod <pod-name>

Check logs:

kubectl logs <pod-name>
kubectl logs deployment/jenkins-deployment

Get a shell inside the pod:

kubectl exec -it <pod-name> -- /bin/bash

Check resource usage:

7
kubectl top pods

Cleaning Up Your Mess

When you’re done experimenting, clean everything up:

kubectl delete deployment jenkins-deployment
kubectl delete deployment jenkins-agent-deployment
kubectl delete pod jenkins-pod
kubectl delete pod jenkins-agent-pod

This removes everything and frees up cluster resources.

8

What We Learned Today

  • Pods are the basic building blocks but they’re fragile
  • Deployments manage pods and provide self-healing
  • Jenkins master should typically run as a single replica
  • Agent pods can be scaled horizontally for more build capacity
  • Always use deployments for production workloads

Next Steps

This tutorial covered the basics of running Jenkins on EKS with pods and deployments. In real production setups, you’d also want:

  • Persistent storage for Jenkins data
  • Proper networking and ingress
  • Security configurations
  • Monitoring and logging
  • Backup strategies

But now you understand the foundation. Pods and deployments are the building blocks that everything else sits on top of.

Start simple, learn the concepts, then add complexity as you need it. That’s the Kubernetes way.

Similar Articles

More from devops