Jenkins automates repetitive tasks like compiling code, running tests, and deploying to servers. You define a pipeline in a Jenkinsfile, Jenkins executes it on agents (machines), and you monitor results via the web dashboard.
✦ Definition~90s read
What is Introduction to Jenkins?
Jenkins is an open-source automation server that orchestrates building, testing, and deploying software. It runs as a Java application with a web UI and supports pipelines defined as code (Jenkinsfile).
★
Imagine you run a restaurant kitchen.
Plain-English First
Imagine you run a restaurant kitchen. Every time you get an order (code commit), you need to cook (build), taste-test (test), and plate (deploy). Jenkins is your head chef who watches the order board, assigns tasks to line cooks (agents), and yells when something burns. You don't do it manually—you write the recipe (pipeline) once, and Jenkins follows it every time.
You pushed code on Friday at 4:55 PM. Monday morning, the team discovers the build broke silently—no one ran tests over the weekend. Classic. Jenkins exists so you never have that conversation again. It's the workhorse that catches broken builds before they hit production, and it's been doing it for over a decade. By the end of this, you'll have a running Jenkins instance, a pipeline that builds and tests your code, and the knowledge to avoid the three mistakes that burn every new Jenkins admin.
What Problem Does Jenkins Solve?
Before Jenkins, teams built software by hand. A developer would pull the latest code, compile it on their machine, run tests locally, and if it passed, copy the artifact to a server. This worked until it didn't—the classic 'works on my machine' problem. The build environment differed between dev laptops, so builds that passed locally failed on the server. Jenkins enforces a consistent environment: every build runs in the same way, on the same type of agent, every time. It also catches integration issues early because it runs tests automatically on every commit. Without Jenkins, you're one manual step away from deploying a broken build to production.
first-pipeline.JenkinsfileDEVOPS
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// io.thecodeforge — DevOps tutorial
pipeline {
agent any // Run on any available agent
stages {
stage('Build') {
steps {
echo 'Compiling code...'
// In a real project, you'd run: sh 'mvn compile'
}
}
stage('Test') {
steps {
echo 'Running unit tests...'
// sh 'mvn test'
}
}
stage('Deploy') {
steps {
echo 'Deploying to staging...'
// sh 'scp target/app.jar user@staging:/opt/app/'
}
}
}
}
Output
Started by user anonymous
[Pipeline] Start of Pipeline
[Pipeline] node
[Pipeline] {
[Pipeline] stage
[Pipeline] { (Build)
[Pipeline] echo
Compiling code...
[Pipeline] }
[Pipeline] // stage
[Pipeline] stage
[Pipeline] { (Test)
[Pipeline] echo
Running unit tests...
[Pipeline] }
[Pipeline] // stage
[Pipeline] stage
[Pipeline] { (Deploy)
[Pipeline] echo
Deploying to staging...
[Pipeline] }
[Pipeline] // stage
[Pipeline] }
[Pipeline] // node
[Pipeline] End of Pipeline
Finished: SUCCESS
Senior Shortcut: Start with a Jenkinsfile
Don't configure jobs through the UI—that's not reproducible. Always define your pipeline as code in a Jenkinsfile committed to your repo. It's version-controlled, reviewable, and portable. The UI is for monitoring, not configuration.
Jenkins Architecture: Master, Agents, and Executors
Jenkins has two components: the master and agents. The master is the brain—it serves the web UI, stores job configurations, and schedules builds. Agents are the muscle—they execute the actual build steps. Each agent has a number of executors, which are like worker threads. An executor runs one build at a time. If you have 2 executors on an agent, it can run 2 builds concurrently. Why separate master and agents? Security and resource isolation. You don't want a malicious build script to compromise the master. Also, you can scale horizontally by adding more agents. The master should never run builds itself—that's a rookie mistake that leads to resource contention and crashes.
agent-setup.shDEVOPS
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// io.thecodeforge — DevOps tutorial
# On the agent machine, download and run the agent JAR
# Replace JENKINS_URL and SECRET with actual values
wget http://JENKINS_URL/jnlpJars/agent.jar
java -jar agent.jar -jnlpUrl http://JENKINS_URL/computer/agent-name/slave-agent.jnlp \
-secret YOUR_SECRET \
-workDir /home/jenkins/agent
# To run as a service, use systemd:
# /etc/systemd/system/jenkins-agent.service
[Unit]
Description=JenkinsAgentAfter=network.target
[Service]
User=jenkins
ExecStart=/usr/bin/java -Xmx2g -jar /home/jenkins/agent.jar -jnlpUrl http://JENKINS_URL/computer/agent-name/slave-agent.jnlp -secret YOUR_SECRET -workDir /home/jenkins/agent
Restart=always
RestartSec=10
[Install]
WantedBy=multi-user.target
Output
INFO: Connecting to JENKINS_URL via JNLP
INFO: Connected. Agent identity: agent-name
INFO: Protocol JNLP4-connect accepted. Ready.
Production Trap: Running Builds on the Master
Never set 'agent any' on the master node. If a build consumes all memory, it kills the master—no UI, no scheduling, no recovery. Always dedicate agents for builds. Mark the master as 'only build jobs with label expressions matching this node' and set its executors to 0.
Installing Jenkins: The 10-Minute Setup
You need a machine with Java 11 or 17. Don't use Java 8—it's end-of-life and has security issues. The easiest way is using the official Docker image. But if you're on bare metal, download the WAR file and run it. For production, install via the native package manager so Jenkins runs as a service. I'll show both. The Docker approach is great for local testing; the native install is for production servers. After installation, you'll unlock Jenkins using an initial admin password, install suggested plugins, and create your first admin user.
Jenkins initial setup is required. An admin user has been created and a password generated.
Please use the following password to proceed to installation:
0a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p
This may also be found at: /var/lib/jenkins/secrets/initialAdminPassword
Never Do This: Expose Jenkins on Default Port 8080
Change the port to something non-standard (e.g., 9090) to reduce automated attacks. Edit /etc/default/jenkins and set HTTP_PORT=9090. Also, put Jenkins behind a reverse proxy (nginx) with HTTPS. The default setup is not production-ready.
Your First Pipeline: Build, Test, Deploy a Real App
Let's create a pipeline for a Java Spring Boot app. The pipeline will: checkout code from Git, compile with Maven, run unit tests, package a JAR, and deploy to a staging server. We'll use a Jenkinsfile stored in the repo. This is the standard pattern—no UI configuration. The pipeline uses stages for each logical step, and post-build actions to archive artifacts and send notifications. I'll include error handling: if tests fail, the build stops and sends an email.
spring-boot-pipeline.JenkinsfileDEVOPS
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
// io.thecodeforge — DevOps tutorial
pipeline {
agent { label 'linux' } // Only run on Linux agents
tools {
maven 'Maven-3.8' // Use a pre-configured Maven installation
}
environment {
APP_NAME = 'checkout-service'
STAGING_SERVER = 'staging.example.com'
}
stages {
stage('Checkout') {
steps {
checkout scm // Checkout from Git (SCM configured in job)
}
}
stage('Build') {
steps {
sh 'mvn clean compile' // Compile source code
}
}
stage('Test') {
steps {
sh 'mvn test' // Run unit tests
}
post {
failure {
// If tests fail, send email and stop pipeline
emailext(
subject: "${env.JOB_NAME} - Build #${env.BUILD_NUMBER} - Test Failure",
body: "Tests failed. Check ${env.BUILD_URL}",
to: 'team@example.com'
)
}
}
}
stage('Package') {
steps {
sh 'mvn package -DskipTests' // PackageJAR (tests already run)
archiveArtifacts artifacts: 'target/*.jar', fingerprint: true
}
}
stage('Deploy to Staging') {
steps {
sh "scp target/${APP_NAME}-*.jar jenkins@${STAGING_SERVER}:/opt/app/"
sh "ssh jenkins@${STAGING_SERVER} 'sudo systemctl restart ${APP_NAME}'"
}
}
}
post {
always {
cleanWs() // Clean workspace after build
}
success {
emailext(
subject: "${env.JOB_NAME} - Build #${env.BUILD_NUMBER} - Success",
body: "Deployed successfully to staging.",
to: 'team@example.com'
)
}
failure {
emailext(
subject: "${env.JOB_NAME} - Build #${env.BUILD_NUMBER} - Failed",
body: "Build failed. Check ${env.BUILD_URL}",
to: 'team@example.com'
)
}
}
}
The Classic Bug: Hardcoded Credentials in Jenkinsfile
Plugins: The Good, The Bad, and The Bloated
Jenkins has over 1,800 plugins. You don't need most of them. The essential ones: Git, Pipeline, Blue Ocean (better UI), Credentials Binding, Email Extension, and Docker Pipeline. Avoid plugins that add UI widgets or reporting—they slow down the master. The worst offender is the 'Build Pipeline Plugin'—it's a memory hog. Use the native Pipeline view instead. Rule of thumb: if you can do it with a shell command, don't install a plugin. Plugins are the main reason Jenkins masters crash—each one adds classloader overhead.
plugin-list.txtDEVOPS
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// io.thecodeforge — DevOps tutorial
# Essentialplugins (install via UI or CLI):
- git
- workflow-aggregator (Pipeline)
- blueocean
- credentials-binding
- email-ext
- docker-workflow
- junit (for test reports)
# Plugins to avoid:
- build-pipeline-plugin (use BlueOcean instead)
- dashboard-view (bloated)
- any plugin that hasn't been updated in 2+ years
# CLI to install plugins:
java -jar jenkins-cli.jar -s http://localhost:8080/ install-plugin git workflow-aggregator blueocean credentials-binding email-ext docker-workflow junit -restart
Jenkins supports two pipeline syntaxes: Declarative and Scripted. Declarative is simpler—you define stages and steps in a structured block. Scripted is more flexible—it's Groovy code with full control flow. For 90% of use cases, use Declarative. It's easier to read, has built-in error handling, and is less error-prone. Scripted is for complex scenarios like dynamic parallel branches or custom logic. I've seen teams use Scripted because they wanted to 'be flexible' and ended up with unmaintainable spaghetti. Start with Declarative. Only switch to Scripted when you hit a wall.
declarative-vs-scripted.JenkinsfileDEVOPS
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// io.thecodeforge — DevOps tutorial
// Declarativepipeline (recommended)
pipeline {
agent any
stages {
stage('Build') {
steps {
echo 'Building...'
}
}
}
}
// Scriptedpipeline (use only when needed)
node {
stage('Build') {
echo 'Building...'
}
// Can use loops, conditionals, etc.
def branches = ['linux', 'windows']
for (branch in branches) {
stage("Build on ${branch}") {
echo "Building on ${branch}"
}
}
}
Output
// Declarative output:
Started by user admin
[Pipeline] Start of Pipeline
[Pipeline] node
[Pipeline] {
[Pipeline] stage
[Pipeline] { (Build)
[Pipeline] echo
Building...
[Pipeline] }
[Pipeline] // stage
[Pipeline] }
[Pipeline] // node
[Pipeline] End of Pipeline
Finished: SUCCESS
// Scripted output:
Started by user admin
[Pipeline] node
[Pipeline] {
[Pipeline] stage
[Pipeline] { (Build)
[Pipeline] echo
Building...
[Pipeline] }
[Pipeline] // stage
[Pipeline] stage
[Pipeline] { (Build on linux)
[Pipeline] echo
Building on linux
[Pipeline] }
[Pipeline] // stage
[Pipeline] stage
[Pipeline] { (Build on windows)
[Pipeline] echo
Building on windows
[Pipeline] }
[Pipeline] // stage
[Pipeline] }
[Pipeline] // node
[Pipeline] End of Pipeline
Finished: SUCCESS
Senior Shortcut: Use the Snippet Generator
Triggering Builds: Webhooks, Polling, and Scheduled
You don't want to click 'Build Now' manually. Set up triggers: push a webhook from GitHub/GitLab, poll the SCM every minute, or run on a cron schedule. Webhooks are best—they trigger immediately on push. Polling is a fallback if you can't expose Jenkins to the internet. Scheduled builds are for nightly integration tests. The classic mistake: polling every minute on 100 jobs—that's 100 HTTP requests per minute to your Git server. Use webhooks. If you must poll, set the interval to 5 minutes or more.
Never Do This: Expose Jenkins Webhook Without Authentication
Managing Secrets: Credentials Binding Done Right
Hardcoding passwords in Jenkinsfiles is a security breach waiting to happen. Use Jenkins' Credentials Binding plugin. Store secrets in Jenkins (Manage Credentials) and reference them in your pipeline. The plugin injects them as environment variables or files. For SSH keys, use sshUserPrivateKey. For API tokens, use string. Never echo secrets in build logs—Jenkins automatically masks them if you use the binding correctly. I've seen a team leak AWS keys because they used sh 'echo $AWS_SECRET' for debugging. Don't.
credentials.JenkinsfileDEVOPS
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
// io.thecodeforge — DevOps tutorial
pipeline {
agent any
environment {
// Reference a credential ID stored in Jenkins
// The value is masked in logs
DOCKER_PASSWORD = credentials('docker-hub-password')
}
stages {
stage('Login to Docker Hub') {
steps {
withCredentials([string(credentialsId: 'docker-hub-username', variable: 'DOCKER_USER')]) {
sh '''
echo $DOCKER_PASSWORD | docker login -u $DOCKER_USER --password-stdin
'''
}
}
}
stage('Deploy with SSH Key') {
steps {
withCredentials([sshUserPrivateKey(
credentialsId: 'staging-server-key',
keyFileVariable: 'SSH_KEY',
usernameVariable: 'SSH_USER'
)]) {
sh 'ssh -i $SSH_KEY -o StrictHostKeyChecking=no $SSH_USER@staging.example.com "sudo systemctl restart app"'
}
}
}
}
}
Output
Started by user admin
[Pipeline] Start of Pipeline
[Pipeline] node
[Pipeline] {
[Pipeline] stage
[Pipeline] { (Login to Docker Hub)
[Pipeline] withCredentials
[Pipeline] {
[Pipeline] sh
[Pipeline] }
[Pipeline] // withCredentials
[Pipeline] }
[Pipeline] // stage
[Pipeline] stage
[Pipeline] { (Deploy with SSH Key)
[Pipeline] withCredentials
[Pipeline] {
[Pipeline] sh
[Pipeline] }
[Pipeline] // withCredentials
[Pipeline] }
[Pipeline] // stage
[Pipeline] }
[Pipeline] // node
[Pipeline] End of Pipeline
Finished: SUCCESS
The Classic Bug: Credential ID Mismatch
Scaling Jenkins: Master-Agent with Docker
As your team grows, you need more build capacity. The simplest scale-out: run agents as Docker containers. Jenkins has a 'Docker Plugin' that spins up a container for each build, runs the pipeline inside, then destroys it. This ensures a clean environment every time. No more 'it worked on the agent but not on my machine'. You can also use Kubernetes plugin for dynamic pod allocation. But start with Docker—it's simpler. The gotcha: each container needs enough resources. Set memory limits in the Docker template, or you'll get OOM kills.
docker-agent.JenkinsfileDEVOPS
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// io.thecodeforge — DevOps tutorial
pipeline {
agent {
docker {
image 'maven:3.8-openjdk-11' // Use a Maven image
args '-v /tmp:/tmp' // Mount host temp directory
reuseNode true // Reuse the same workspace across stages
}
}
stages {
stage('Build') {
steps {
sh 'mvn clean compile'
}
}
stage('Test') {
steps {
sh 'mvn test'
}
}
}
}
Output
Started by user admin
[Pipeline] Start of Pipeline
[Pipeline] node
[Pipeline] {
[Pipeline] stage
[Pipeline] { (Build)
[Pipeline] sh
[Pipeline] }
[Pipeline] // stage
[Pipeline] stage
[Pipeline] { (Test)
[Pipeline] sh
[Pipeline] }
[Pipeline] // stage
[Pipeline] }
[Pipeline] // node
[Pipeline] End of Pipeline
Finished: SUCCESS
Production Trap: Docker Daemon Disk Space
Monitoring Jenkins: What to Watch
Jenkins can run for months without issues, then suddenly die. Monitor these: JVM heap usage (set a max via -Xmx), disk space for JENKINS_HOME (especially job logs—they grow fast), and queue length (if builds pile up, you need more agents). Use the 'Monitoring' plugin or JMX to expose metrics. Alert on: queue time > 5 minutes, disk usage > 80%, and build failure rate > 10%. I once saw a master crash because a single job generated 50GB of logs in one night. Set log rotation: in job config, 'Discard Old Builds' with a max of 30 days or 100 builds.
Build discarder set for job 'my-job': keep 100 builds or 30 days.
Senior Shortcut: Use the Jenkins Metrics Plugin
● Production incidentPOST-MORTEMseverity: high
The 4GB Container That Kept Dying
Symptom
Jenkins agent container crashed every 3 hours with OOMKilled. Builds failed randomly, no pattern.
Assumption
Memory leak in the build script. Team spent a week profiling Groovy code.
Root cause
Default JVM heap for the agent was 512MB. The agent was running inside a Docker container with 4GB memory limit, but the JVM never used more than 512MB because the -Xmx flag wasn't set. The container had plenty of memory, but the JVM starved itself.
Fix
Set -Xmx2g in the agent startup command: java -Xmx2g -jar agent.jar -jnlpUrl http://jenkins:8080/computer/agent/slave-agent.jnlp -secret @secret-file -workDir /home/jenkins
Key lesson
Always set JVM heap limits explicitly.
Defaults are designed for laptops, not production containers.
Production debug guideSystematic recovery paths for the failure modes engineers actually hit.3 entries
Symptom · 01
Build fails with 'java.io.IOException: No space left on device'
Pipeline stuck in 'pending—waiting for next available executor'
→
Fix
1. Check executor usage: Manage Jenkins > Manage Nodes. 2. Add more executors to existing agents. 3. Spin up additional agents. 4. Check if job label matches agent label exactly.
Feature / Aspect
Jenkins
GitLab CI/CD
Setup complexity
Requires separate server, plugins, and configuration
Built into GitLab, minimal setup
Pipeline as code
Jenkinsfile (Declarative or Scripted)
.gitlab-ci.yml (YAML)
Plugin ecosystem
1800+ plugins, but many are outdated
Limited but curated integrations
Scalability
Master-agent with Docker/Kubernetes
Auto-scaling runners
Learning curve
Steep—Groovy syntax, plugin management
Moderate—YAML-based
Best for
Complex pipelines, legacy systems, on-premise
GitLab-native workflows, cloud-native
Key takeaways
1
Jenkins automates the build-test-deploy cycle, catching integration issues early. Always define pipelines as code in a Jenkinsfile.
2
Never run builds on the master—use dedicated agents. Set master executors to 0.
3
Use Credentials Binding for secrets. Never hardcode passwords or keys in Jenkinsfiles.
4
Monitor JVM heap, disk space, and queue length. Set log rotation to prevent disk full errors.
INTERVIEW PREP · PRACTICE MODE
Interview Questions on This Topic
FAQ · 4 QUESTIONS
Frequently Asked Questions
01
What is Jenkins and why should I use it?
Jenkins is an automation server that runs your build, test, and deploy tasks automatically when you push code. Use it to catch broken builds early, enforce consistent build environments, and save your team from manual deployment errors.
Was this helpful?
02
What's the difference between Jenkins and GitHub Actions?
Jenkins is self-hosted and highly customizable via plugins, but requires maintenance. GitHub Actions is cloud-hosted and simpler to set up for GitHub repos. Choose Jenkins if you need on-premise control or complex pipelines; choose GitHub Actions for quick, cloud-native CI/CD.
Was this helpful?
03
How do I create a Jenkins pipeline for a Java project?
Add a Jenkinsfile to your repo root with stages: Checkout (git), Build (mvn compile), Test (mvn test), Package (mvn package), Deploy (scp or docker push). Use Declarative syntax. Configure the job to point to your repo and the Jenkinsfile.
Was this helpful?
04
Why does my Jenkins build fail with 'No space left on device'?
Jenkins stores build logs and artifacts in JENKINS_HOME. Over time, old builds fill the disk. Fix: configure 'Discard Old Builds' in each job to keep only the last 30 days or 100 builds. Also clean workspace periodically with cleanWs() in your pipeline.