Jenkins is an open-source automation server that helps automate parts of the software development process, including building, testing, and deploying applications. It is widely used for implementing Continuous Integration (CI) and Continuous Delivery (CD) workflows, often referred to as CI/CD pipelines.
Jenkins makes it easier for developers to integrate code changes frequently and automatically test them, reducing integration problems and allowing for faster delivery of high-quality software.
Jenkins requires Java (OpenJDK 11 or 17 recommended). The installation process varies slightly depending on your operating system. Below are common methods:
This is often the quickest and cleanest way to get Jenkins running for development or testing.
# Pull the Jenkins LTS image
docker pull jenkins/jenkins:lts
# Create a Docker volume to persist Jenkins data
docker volume create jenkins_home
# Run Jenkins container on port 8080 (web UI) and 50000 (agent communication)
docker run -d -p 8080:8080 -p 50000:50000 \
--name jenkins-server \
--restart=on-failure \
-v jenkins_home:/var/jenkins_home \
jenkins/jenkins:lts
After a few minutes, Jenkins will be accessible in your browser at `http://localhost:8080`.
Install Java first, then add the Jenkins repository and install.
# 1. Install Java Development Kit (JDK)
sudo apt update
sudo apt install -y openjdk-17-jdk
# 2. Add Jenkins repository key
sudo wget -O /usr/share/keyrings/jenkins-keyring.asc \
https://pkg.jenkins.io/debian-stable/jenkins-keyring.asc
# 3. Add Jenkins repository to your sources list
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
# 4. Update apt cache and install Jenkins
sudo apt update
sudo apt install -y jenkins
# 5. Check Jenkins service status (should be running)
sudo systemctl status jenkins
# Output: active (running)
# 6. Adjust firewall (if UFW is active)
sudo ufw allow 8080 # Allow HTTP access to Jenkins
sudo ufw enable
sudo ufw status
# 1. Install Java Development Kit (JDK)
sudo dnf install -y java-17-openjdk-devel
# 2. Add Jenkins repository
sudo wget -O /etc/yum.repos.d/jenkins.repo \
https://pkg.jenkins.io/redhat-stable/jenkins.repo
sudo rpm --import https://pkg.jenkins.io/redhat-stable/jenkins.io-2023.key
# 3. Install Jenkins
sudo dnf install -y jenkins
# 4. Start and enable Jenkins service
sudo systemctl start jenkins
sudo systemctl enable jenkins
# 5. Adjust firewall (if Firewalld is active)
sudo firewall-cmd --permanent --zone=public --add-port=8080/tcp
sudo firewall-cmd --reload
When you first access Jenkins, you'll go through a setup wizard.
The first screen requires an administrator password. Retrieve it from your server's initial admin password file.
# For Docker:
docker logs jenkins-server # Look for the password in the logs
# For Linux installations:
sudo cat /var/lib/jenkins/secrets/initialAdminPassword
Paste the password and click **Continue**.
Choose "Install suggested plugins." This will install common plugins for SCM (Git), Pipelines, build tools, etc.
Create your Jenkins administrator account. Remember these credentials!
After setup, you'll land on the Jenkins dashboard. Key elements:
Freestyle projects are the simplest job type in Jenkins, configured entirely through the graphical user interface. They are great for straightforward tasks like compiling code, running simple scripts, or executing basic tests.
You'll be directed to the project configuration page.
# For Linux/macOS
echo "Hello from Jenkins Freestyle Job!"
echo "Current directory: $(pwd)"
ls -lh
# For Windows
echo Hello from Jenkins Freestyle Job!
echo Current directory: %CD%
dir
From the project dashboard, click **Build Now** in the left menu.
Jenkins Pipelines are a suite of plugins that support implementing and integrating continuous delivery pipelines into Jenkins. "Pipeline as Code" allows you to define your entire CI/CD process in a `Jenkinsfile` (a Groovy script) stored in your source code repository.
This provides version control for your pipeline, making it auditable, reproducible, and easily shared.
A more recent and structured syntax, easier to learn and read. It's defined within a `pipeline { ... }` block using predefined sections like `agent`, `stages`, `steps`, `post`, `options`, `parameters`, `environment`, `buildTriggers`.
The original Pipeline syntax, based entirely on Groovy. Offers greater flexibility and control for complex or dynamic workflows, but requires more Groovy programming knowledge.
Create a file named `Jenkinsfile` at the root of your Git repository.
// Jenkinsfile (Declarative Pipeline)
pipeline {
// Defines where the entire pipeline will run. 'any' means on any available agent.
agent any
// Define environment variables accessible throughout the pipeline
environment {
// Build Number (built-in Jenkins variable)
BUILD_ID = "${env.BUILD_NUMBER}"
// Custom variable
APP_NAME = "MyWebApp"
}
// Define parameters that can be passed to the pipeline
parameters {
string(name: 'BRANCH_NAME', defaultValue: 'main', description: 'Git branch to build')
booleanParam(name: 'RUN_TESTS', defaultValue: true, description: 'Whether to run tests')
}
// Options for the pipeline
options {
// Discard old builds: keep a max of 5 builds and 3 days of artifacts
buildDiscarder(logRotator(numToKeepStr: '5', artifactNumToKeepStr: '3'))
timestamps() // Add timestamps to console output
}
stages {
stage('Checkout Code') { // First stage: Get code from SCM
steps {
echo "Checking out code for ${params.BRANCH_NAME}..."
// Use a Git SCM checkout, assuming 'github.com/your-org/your-repo.git'
// You'll need to configure Git credentials in Jenkins if your repo is private
git branch: "${params.BRANCH_NAME}", url: 'https://github.com/your-org/your-repo.git'
}
}
stage('Build') { // Second stage: Build the application (e.g., a Maven project)
steps {
echo "Building ${APP_NAME} build ${BUILD_ID}..."
// This assumes Maven is configured in Jenkins under "Manage Jenkins > Tools"
// and a pom.xml exists in your repo
sh 'mvn clean install -DskipTests'
}
// Post-build actions specific to this stage (e.g., if build fails)
post {
always {
archiveArtifacts artifacts: 'target/*.jar', fingerprint: true // Archive JAR file
}
failure {
echo 'Build failed! Check console output.'
}
}
}
stage('Test') { // Third stage: Run tests (conditional execution)
when {
expression { params.RUN_TESTS == true } // Only run if RUN_TESTS parameter is true
}
steps {
echo "Running tests..."
sh 'mvn test' // Run Maven tests
// Publish JUnit test results (requires JUnit plugin)
junit '**/target/surefire-reports/*.xml'
}
post {
unstable {
echo 'Tests had failures or skipped tests!'
}
failure {
echo 'Tests failed!'
}
}
}
stage('Deploy Staging') { // Fourth stage: Deploy to a staging environment
steps {
echo "Deploying to staging environment..."
// Example: Copy artifact to a remote server via SSH (requires SSH Agent plugin and credentials)
// sshagent(['your-ssh-credential-id']) {
// sh "scp target/*.jar user@staging-server:/var/www/html/app.jar"
// }
sh 'echo "Deployment to staging simulated."'
}
}
stage('Approval for Production') { // Optional stage for manual approval
input {
message "Proceed to production deployment?"
ok "Deploy to Production"
submitter "admin,devops" // Specific users or groups who can approve
}
steps {
echo "Approval received. Proceeding to production."
}
}
stage('Deploy Production') { // Final stage: Deploy to production (conditional on approval)
when {
expression { previousStageStatus('Approval for Production') == 'SUCCESS' } // Only if approval stage passed
}
steps {
echo "Deploying to production environment..."
sh 'echo "Deployment to production simulated."'
}
post {
success {
echo 'Deployment to Production successful!'
// Send email notification (requires Email Extension Plugin)
mail to: 'devops-team@example.com', \
subject: "Jenkins Pipeline: ${APP_NAME} Build ${BUILD_ID} - Production Deployment SUCCESS", \
body: "Build ${BUILD_ID} of ${APP_NAME} successfully deployed to production."
}
failure {
echo 'Deployment to Production FAILED!'
mail to: 'devops-team@example.com', \
subject: "Jenkins Pipeline: ${APP_NAME} Build ${BUILD_ID} - Production Deployment FAILED", \
body: "Build ${BUILD_ID} of ${APP_NAME} FAILED deployment to production. Check: ${env.BUILD_URL}"
}
}
}
}
// Post-build actions for the entire pipeline
post {
always {
echo 'Pipeline finished!'
}
cleanedUp {
echo 'Cleaning up workspace...'
// Clean workspace (requires Workspace Cleanup Plugin)
deleteDir()
}
}
}
From the project dashboard, click **Build Now**. You'll see the stages execute in the "Stage View" or "Blue Ocean" interface (if installed).
A Multibranch Pipeline project automatically discovers, manages, and executes Pipelines for branches containing a `Jenkinsfile` within a repository. It's ideal for projects with multiple development branches (feature branches, hotfix branches, etc.).
Plugins are the backbone of Jenkins' extensibility, allowing it to integrate with almost any build tool, SCM, cloud provider, or reporting system.
# Example: Installing a plugin from the CLI (if allowed by Jenkins security)
java -jar jenkins-cli.jar -s http://localhost:8080/ -webcli install-plugin blueocean
Jenkins allows you to offload build workloads from the main Jenkins controller to separate machines called "agents" (formerly "slaves"). This is crucial for scalability, isolating build environments, and performing builds on different operating systems.
ssh-keygen -t rsa -b 4096 -C "jenkins-agent-key" -f ~/.ssh/jenkins-agent-key -q -N ""
Copy the public key (`~/.ssh/jenkins-agent-key.pub`) to the agent machine's `~/.ssh/authorized_keys` file for the `jenkins_agent` user.
pipeline {
agent { label 'linux' } // Run the entire pipeline on 'linux' labeled agents
// ... or for a specific stage:
stages {
stage('Run on Linux Agent') {
agent { label 'linux' }
steps {
sh 'echo "Running on Linux agent: $NODE_NAME"'
}
}
}
}
Jenkins securely stores various types of credentials (usernames/passwords, SSH keys, secret text, Kubernetes secrets) to prevent them from being hardcoded in jobs or scripts.
The `withCredentials` step is used to access credentials securely within a Pipeline.
pipeline {
agent any
stages {
stage('Login to Docker Registry') {
steps {
// Assuming you have a "Username with password" credential with ID 'docker-hub-creds'
withCredentials([usernamePassword(credentialsId: 'docker-hub-creds', passwordVariable: 'DOCKER_PASSWORD', usernameVariable: 'DOCKER_USERNAME')]) {
sh "docker login -u ${DOCKER_USERNAME} -p ${DOCKER_PASSWORD} registry.hub.docker.com"
}
}
}
stage('Deploy via SSH') {
steps {
// Assuming you have an "SSH Username with private key" credential with ID 'deploy-ssh-key'
sshagent(['deploy-ssh-key']) {
sh "scp -o StrictHostKeyChecking=no target/my-app.jar user@remoteserver:/var/www/html/"
}
}
}
stage('Use a Secret Text') {
steps {
// Assuming you have a "Secret text" credential with ID 'my-api-key'
withCredentials([string(credentialsId: 'my-api-key', variable: 'API_KEY')]) {
sh "curl -H \"Authorization: Bearer ${API_KEY}\" https://api.example.com/data"
}
}
}
}
}
Environment variables allow you to pass dynamic values and configurations to your Jenkins jobs and pipelines.
Jenkins provides many predefined variables automatically (e.g., `BUILD_NUMBER`, `JOB_NAME`, `WORKSPACE`, `BUILD_URL`).
pipeline {
agent any
stages {
stage('Show Env Vars') {
steps {
echo "Build Number: ${env.BUILD_NUMBER}"
echo "Job Name: ${env.JOB_NAME}"
echo "Workspace: ${env.WORKSPACE}"
echo "Build URL: ${env.BUILD_URL}"
sh 'printenv' // Prints all environment variables in shell
}
}
}
}
Accessible across all jobs and pipelines within a Jenkins instance.
Defined within an `environment` block in a Declarative Pipeline, scoped to that pipeline or stage.
pipeline {
agent any
// Pipeline-level environment variable
environment {
APP_VERSION = "1.0.0"
}
stages {
stage('Stage 1') {
steps {
echo "App Version (from pipeline env): ${env.APP_VERSION}"
}
}
stage('Stage 2') {
// Stage-level environment variable (overrides pipeline-level if name is same)
environment {
BUILD_TYPE = "Production"
}
steps {
echo "App Version: ${env.APP_VERSION}"
echo "Build Type: ${env.BUILD_TYPE}"
}
}
}
}
Shared Libraries allow you to define reusable pieces of Pipeline code (e.g., common functions, steps, or utility scripts) in an external Git repository. This promotes code reuse and maintains a clean `Jenkinsfile`.
/my-jenkins-shared-lib
├── vars/
│ └── myCustomStep.groovy
│ └── commonUtils.groovy
├── src/
│ └── com/
│ └── example/
│ └── MyHelper.groovy
├── resources/
│ └── config.json
└── Jenkinsfile (optional, for testing the library itself)
// vars/myCustomStep.groovy
def call(String message = 'Default message') {
echo "--- Custom Step Started ---"
echo "Message: ${message}"
// Perform some common actions, e.g., deploy an artifact, run security scan
echo "--- Custom Step Finished ---"
}
@Library('my-shared-lib') _ // Load the shared library (the '_' is conventional)
pipeline {
agent any
stages {
stage('Example Stage') {
steps {
myCustomStep 'Hello from the pipeline!' // Call the global function
myCustomStep() // Call with default message
script {
// Access a class from src/
// def helper = new com.example.MyHelper()
// helper.doSomething()
}
}
}
}
}
Jenkins plays a central role in automating CI/CD workflows by integrating with various tools.
# Example GitHub Webhook Payload URL:
http://your_jenkins_url:8080/github-webhook/
# Ensure your Jenkins URL is accessible from GitHub.
stage('Build Node.js App') {
steps {
sh 'npm install'
sh 'npm run build'
}
}
stage('Build Java Maven App') {
tools {
// Define Maven tool name as configured in Manage Jenkins > Tools
maven 'Maven 3.8.6'
}
steps {
sh 'mvn clean package -DskipTests'
}
}
stage('Run Unit Tests') {
steps {
sh 'npm test' // Or 'mvn test'
junit '**/test-results/*.xml' // Publish JUnit results
}
}
stage('Run UI Tests (Selenium)') {
agent { label 'chrome-agent' } // Run on a specific agent with Chrome/Selenium setup
steps {
sh 'python3 -m pytest ui_tests/'
// ... possibly capture screenshots or video on failure
}
}
pipeline {
agent { docker { image 'maven:3.8.6-openjdk-17' } } // Use Maven container for build
stages {
stage('Build Docker Image') {
steps {
script {
docker.build("my-app:${env.BUILD_NUMBER}")
docker.withRegistry('https://registry.hub.docker.com', 'docker-hub-creds') {
docker.image("my-app:${env.BUILD_NUMBER}").push()
}
}
}
}
}
}
stage('Deploy to Kubernetes') {
steps {
// Assumes kubectl is configured on the agent
sh "kubectl apply -f k8s/deployment.yaml"
sh "kubectl set image deployment/my-app my-app=my-registry/my-app:${env.BUILD_NUMBER}"
}
}
Securing your Jenkins instance is paramount, as it can have access to sensitive credentials and infrastructure.
# For Linux installation:
sudo cat /var/log/jenkins/jenkins.log
# For Docker:
docker logs jenkins-server
Jenkins is a powerful tool at the heart of modern DevOps practices. By understanding its core functionalities, mastering Pipeline as Code, and leveraging its vast plugin ecosystem, you can build robust, automated CI/CD pipelines that streamline your software delivery process and enhance your team's productivity. Continuous learning and active participation in the Jenkins community will further deepen your expertise.