Skip to main content
Menu
Home WhoAmI Stack Insights Blog Contact
/user/KayD @ localhost :~$ cat create-custom-ami-of-jenkins-devops.md

Create Custom AMI of Jenkins | DevOps

Karandeep Singh
• 9 minutes read

Summary

A comprehensive guide to roll out your own custom Jenkins AMI, perfect for those who want a hassle-free, tailor-made Continuous Integration environment.

Introduction

If you’ve spent any amount of time in the DevOps world, you’ve probably found yourself setting up Jenkins servers more times than you’d like to admit. The process is repetitive, time-consuming, and frankly, a bit boring after the third or fourth time. That’s exactly why I started building custom Amazon Machine Images for Jenkins, and honestly, it’s been a game changer.

In this guide, I’ll walk you through how to create your own Jenkins AMI from scratch. We’ll cover everything from spinning up a fresh Ubuntu instance to baking that perfect image you can reuse whenever you need a new Jenkins server.

What’s An AMI Anyway?

For those who haven’t worked with AWS much, Amazon Machine Images are basically snapshots of a configured server. They contain the operating system, all the software you’ve installed, and any configurations you’ve made. When you need a new server with the same setup, you just launch an instance from that AMI and you’re good to go. No more spending an hour installing packages and tweaking config files.

And Jenkins? What’s the Big Deal?

Jenkins is an open-source automation server that handles continuous integration and continuous deployment. It’s been around for years and has a massive plugin ecosystem. Most teams I’ve worked with use it for building code, running tests, and deploying applications. It’s flexible, well-documented, and free. The downside is that setting it up properly takes time, especially when you want specific plugins and configurations.

Why Combine Jenkins and AMI?

Here’s where things get interesting. When you create a custom AMI with Jenkins pre-installed and configured, you’re essentially creating a template for your CI/CD infrastructure. Need to scale up your build capacity? Launch a few more instances from your AMI. Disaster recovery? Spin up a replacement in minutes instead of hours. It’s the kind of infrastructure automation that makes your life significantly easier.

Why Bother With a Custom AMI?

You might be wondering why you shouldn’t just use one of the pre-built Jenkins AMIs from the AWS Marketplace or install Jenkins manually each time. Fair question.

Plugins Are a Pain

If you’ve worked with Jenkins, you know plugins are essential. Git integration, Docker support, Slack notifications, whatever your team needs. But installing and configuring plugins manually every single time you set up a new Jenkins instance gets old fast. With a custom AMI, all your standard plugins are already there, configured the way you like them.

Version Consistency

Jenkins releases updates pretty frequently. That’s generally good for features and security, but it can cause problems when different environments run different versions. With a custom AMI, you lock in a specific Jenkins version. Every instance launched from that AMI runs the same version, which makes debugging and maintenance much simpler.

Your Configuration, Every Time

Maybe you run Jenkins on a non-standard port because 8080 is already taken by something else. Maybe you have specific JVM settings or security configurations. Whatever your setup looks like, a custom AMI preserves all of it.

Getting Started: Setting Up Your Base Instance

Alright, let’s get into the actual work. We’ll be using Ubuntu 24.04 LTS for this guide because it’s well-supported, stable, and most people are familiar with it.

Step 1: Launch an EC2 Instance

Log into your AWS console and launch a new EC2 instance. Select Ubuntu Server 24.04 LTS as your AMI. For the instance type, a t3.medium works well for building the AMI, though you might want something bigger for actual production use depending on your build workloads.

Make sure your security group allows inbound traffic on port 22 (SSH) and port 8080 (Jenkins web interface). You can lock this down further later, but you’ll need these ports open during setup.

Step 2: Connect to Your Instance

Once your instance is running, SSH into it:

ssh -i your-key.pem ubuntu@your-instance-ip

First thing, update your packages:

sudo apt update && sudo apt upgrade -y

This might take a few minutes depending on how many updates are available.

Step 3: Install Java

Jenkins runs on the JVM, so we need Java installed. For Jenkins LTS releases, Java 17 works well. If you’re running the latest weekly releases, you’ll want Java 21.

For most production setups, I recommend sticking with the LTS release and Java 17:

sudo apt install fontconfig openjdk-17-jre -y

If you need Java 21 for the weekly releases:

sudo apt install fontconfig openjdk-21-jre -y

Verify the installation:

java -version

You should see output showing the version you just installed.

A note on Java versions: Java 11 support is being phased out of Jenkins and will be completely removed in 2026. Don’t use Java 11 for new installations.

Step 4: Add the Jenkins Repository

Jenkins isn’t in the default Ubuntu repositories, so we need to add their official repo. First, import the GPG key:

sudo wget -O /usr/share/keyrings/jenkins-keyring.asc \
    https://pkg.jenkins.io/debian-stable/jenkins.io-2023.key

Then add the repository:

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

Update your package list to include the new repository:

sudo apt update

Installing and Configuring Jenkins

Now we’re ready to actually install Jenkins.

Step 5: Install Jenkins

This part is straightforward:

sudo apt install jenkins -y

The installation will take a minute or two. Once it’s done, Jenkins should start automatically.

Step 6: Start and Enable Jenkins

Make sure Jenkins is running and set to start on boot:

sudo systemctl enable jenkins
sudo systemctl start jenkins

Check the status:

sudo systemctl status jenkins

You should see “active (running)” in the output. If something went wrong, the status output will usually give you a hint about what failed.

Step 7: Get the Initial Admin Password

When you first access Jenkins through the web interface, it asks for an initial admin password. You can find it here:

sudo cat /var/lib/jenkins/secrets/initialAdminPassword

Copy that password somewhere, you’ll need it in a moment.

Step 8: Configure Jenkins Through the Web Interface

Open your browser and go to http://your-instance-ip:8080. Paste in that admin password you just copied.

Jenkins will ask if you want to install suggested plugins or select plugins manually. For a custom AMI, I usually go with “Select plugins to install” so I can pick exactly what I need. Common choices include:

  • Git
  • Pipeline
  • Docker Pipeline
  • Blue Ocean (if you like the newer UI)
  • Credentials Binding
  • SSH Agent

After the plugins install, create your admin user. Pick a username and password you’ll actually remember, or better yet, use something you can look up later from your password manager.

Set your Jenkins URL. This is important if you’re going to put Jenkins behind a load balancer or reverse proxy later.

The Docker Alternative

Before we get to creating the AMI, it’s worth mentioning that a lot of teams are running Jenkins in Docker these days. It’s not necessarily better than a traditional installation, but it does offer some advantages worth considering.

Why Docker?

Running Jenkins in a container makes it easy to version your entire Jenkins setup, not just the configuration files. You can test upgrades by running a new container alongside your existing one. Backups are simpler because everything lives in a mounted volume. And if you’re already running Kubernetes or ECS, containerized Jenkins fits naturally into that workflow.

Quick Docker Setup

If you want to go the Docker route, here’s how to get started on your Ubuntu instance:

sudo apt install docker.io -y
sudo systemctl enable docker
sudo systemctl start docker
sudo usermod -aG docker ubuntu

Log out and back in for the group change to take effect, then run Jenkins:

docker run -d \
    --name jenkins \
    --restart=on-failure \
    -p 8080:8080 \
    -p 50000:50000 \
    -v jenkins_home:/var/jenkins_home \
    jenkins/jenkins:lts-jdk17

Important: Use the jenkins/jenkins image from Docker Hub. The old jenkins image is deprecated and hasn’t been updated in years.

Building a Custom Jenkins Image

For more control, create a Dockerfile:

FROM jenkins/jenkins:lts-jdk17

ENV JAVA_OPTS="-Djenkins.install.runSetupWizard=false"

COPY plugins.txt /usr/share/jenkins/ref/plugins.txt
RUN jenkins-plugin-cli --plugin-file /usr/share/jenkins/ref/plugins.txt

USER jenkins

Create a plugins.txt with the plugins you need:

git
workflow-aggregator
docker-workflow
blueocean

Build and run:

docker build -t my-jenkins:latest .
docker run -d --name jenkins -p 8080:8080 -v jenkins_home:/var/jenkins_home my-jenkins:latest

When to Use What

AMIs work well when you’re running traditional EC2 instances and want fast startup times. Docker makes more sense when you’re using container orchestration like ECS or Kubernetes, or when you want to manage Jenkins configuration as code alongside your application repos.

Neither approach is wrong. Pick the one that fits how your team already works.

Creating Your Custom AMI

Once you’ve got Jenkins installed, configured, and tested, it’s time to create the AMI.

Step 9: Clean Up Before Creating the Image

Before you create the AMI, clean up any temporary files and sensitive data you don’t want baked into the image:

sudo apt clean
sudo rm -rf /var/lib/apt/lists/*
rm -rf ~/.bash_history
history -c

If you created any temporary credentials or test data in Jenkins, remove those too.

Step 10: Create the AMI

Go to the EC2 console in AWS. Find your instance, right-click on it (or use the Actions menu), and select Image and templates > Create image.

Give it a descriptive name like jenkins-ubuntu2404-java17-2025-01 so you can tell at a glance what’s in it and when it was created. Add a description if you want to note which plugins are installed or any special configuration.

Click Create Image. AWS will stop your instance briefly, create a snapshot, and then restart it. The whole process usually takes 10-15 minutes depending on how much data is on the disk.

Once the AMI shows “available” in the AMI section of the console, you’re done. You can now launch new Jenkins instances from this AMI whenever you need them.

A Few Things I’ve Learned

After building quite a few Jenkins AMIs over the years, here are some things that have bitten me:

Don’t bake secrets into AMIs. API keys, passwords, SSH keys, that kind of thing should come from environment variables, AWS Secrets Manager, or parameter store at runtime. If you bake them into the AMI, they’re there forever and anyone with access to the AMI can extract them.

Keep your AMIs updated. Build a new AMI every month or so with the latest security patches. Old AMIs with old packages are a security liability.

Document what’s in the AMI. Either in the AMI description or in a README somewhere, note what version of Jenkins, Java, and major plugins are installed. Future you will thank present you.

Test your AMI before relying on it. Launch an instance from the AMI and verify everything works. Run a test build. Check that all the plugins are there. It’s frustrating to discover your AMI is broken when you actually need it.

Wrapping Up

That’s pretty much it. You now have a custom Jenkins AMI you can use to quickly spin up new Jenkins instances. No more spending an hour installing packages and clicking through setup wizards. Just launch an instance and get to work.

If you run into issues or have questions, feel free to reach out. I’m always happy to talk shop about Jenkins and CI/CD infrastructure.


Contents