Gideon
Posted on November 28, 2024
Jenkins is an open-source automation server that enables developers to build, test, and deploy their software reliably. It plays a pivotal role in the DevOps lifecycle by automating tasks, facilitating continuous integration and continuous delivery (CI/CD), and improving collaboration among development teams.
Installing Jenkins on your local Windows machine allows you to:
- Experiment with Jenkins features without affecting a production environment.
- Develop and test CI/CD pipelines locally.
- Gain hands-on experience with DevOps practices.
This guide will walk you through two methods to install Jenkins on Windows:
- Using Docker (Recommended)
- Using Windows Subsystem for Linux (WSL)
We'll compare both methods and explain why using Docker is the better choice.
Method 1: Installing Jenkins Using Docker
Placeholder for Docker and Jenkins Logos
Prerequisites
- Windows 10 or later
- Docker Desktop installed on your machine
Steps to Install Jenkins with Docker
Step 1: Install Docker Desktop
If you haven't installed Docker Desktop:
- Download Docker Desktop from the official website.
- Check the architecture of your Windows machine (x86_64 or Arm). Here's a medium article that helps.
- After a successful download, run the installer and follow the on-screen instructions.
- After installation, launch Docker Desktop and ensure it's running.
Step 2: Pull the Jenkins Docker Image
Open Command Prompt or PowerShell and run:
docker pull jenkins/jenkins:lts
This command downloads the latest stable (LTS) Jenkins image.
Step 3: Run Jenkins Container
docker run \
-p 8080:8080 \
-p 50000:50000 \
-d \
-v jenkins_home:/var/jenkins_home \
-v /var/run/docker.sock:/var/run/docker.sock \
-v $(which docker):/usr/bin/docker \
jenkins/jenkins:lts
docker run
: This is the Docker command used to create and run a new container from a specified image.-
-p 8080:8080
:- Purpose: Maps port 8080 of the host machine to port 8080 of the container.
-
Explanation: Jenkins uses port 8080 as its default web interface port. This mapping allows you to access the Jenkins web UI via
http://localhost:8080
.
-
-p 50000:50000
:- Purpose: Maps port 50000 of the host to port 50000 of the container.
- Explanation: Port 50000 is used by Jenkins for communication with build agents (JNLP agents). This mapping enables distributed builds and agent connections.
-
-d
:- Purpose: Runs the container in detached mode.
- Explanation: The container runs in the background, allowing you to continue using the terminal for other commands.
-
-v jenkins_home:/var/jenkins_home
:-
Purpose: Mounts the Docker volume
jenkins_home
to the container's/var/jenkins_home
directory. -
Explanation:
-
Data Persistence: Jenkins stores its configuration, plugins, and job data in
/var/jenkins_home
. Mounting a volume ensures that this data persists across container restarts or recreations. -
Named Volume: Using
jenkins_home
as a named volume allows Docker to manage the volume, and it can be reused or backed up easily.
-
Data Persistence: Jenkins stores its configuration, plugins, and job data in
-
Purpose: Mounts the Docker volume
-
-v /var/run/docker.sock:/var/run/docker.sock
:- Purpose: Mounts the Docker daemon socket from the host into the container.
-
Explanation:
- Docker Control: By mounting the Docker socket, Jenkins running inside the container can communicate with the Docker daemon on the host.
- Use Case: This is essential if you want Jenkins to build Docker images or manage Docker containers as part of your CI/CD pipelines.
-
-v $(which docker):/usr/bin/docker
:-
Purpose: Mounts the Docker executable from the host into the container at
/usr/bin/docker
. -
Explanation:
-
Docker CLI Access: This makes the Docker command-line tool (
docker
) available inside the Jenkins container. - Version Consistency: Ensures that the Docker CLI inside the container matches the version installed on the host, avoiding compatibility issues.
-
Docker CLI Access: This makes the Docker command-line tool (
-
Purpose: Mounts the Docker executable from the host into the container at
Note: $(which docker)
is a command substitution that returns the path of the Docker executable on the host system.
-
jenkins/jenkins:lts
:- Purpose: Specifies the Docker image to use, in this case, the Jenkins Long-Term Support (LTS) version.
-
Explanation:
- Stable Version: Using the LTS version ensures you are running a stable and well-supported release of Jenkins.
-
Image Source: The image
jenkins/jenkins:lts
is maintained by the Jenkins project on Docker Hub.
Summary of the Command's Purpose
This Docker command sets up a Jenkins server in a container with the capability to:
- Persist data through the
jenkins_home
volume. - Be accessible via the web interface on
localhost:8080
. - Communicate with build agents through port 50000.
- Interact with Docker on the host machine to build images and manage containers from within Jenkins jobs.
Why Mount Docker Socket and Executable?
By mounting both the Docker socket and executable:
-
Docker Socket (
/var/run/docker.sock
):- Grants the container access to the Docker daemon running on the host.
- Allows Jenkins to execute Docker commands that affect the host's Docker environment.
-
Docker Executable (
/usr/bin/docker
):- Provides the
docker
CLI inside the container. - Ensures Jenkins can run Docker commands as if it were on the host.
- Provides the
This setup is commonly used when you need Jenkins to perform Docker-related tasks, such as:
- Building Docker images.
- Running Docker containers.
- Managing Docker registries.
Security Considerations
- Privileges: Mounting the Docker socket and executable gives the Jenkins container elevated permissions over the host's Docker daemon.
- Risk: If the Jenkins server or any of its jobs are compromised, malicious commands could be executed on the host.
-
Mitigation:
- Limit access to the Jenkins server.
- Use proper authentication and authorization within Jenkins.
- Consider using Docker-in-Docker or Docker agents with limited permissions for additional isolation.
Alternative Approaches
-
Docker-in-Docker (
dind
):- Run a separate Docker daemon inside the container.
- Adds complexity and potential performance overhead.
- Provides better isolation from the host's Docker daemon.
-
Docker Agents:
- Use separate Docker containers as build agents.
- Avoids giving the main Jenkins container direct access to the host's Docker daemon.
Example Usage in a Jenkins Pipeline
With this setup, you can create Jenkins pipelines that include steps like:
pipeline {
agent any
stages {
stage('Build Docker Image') {
steps {
sh 'sudo docker build -t my-image .'
}
}
stage('Run Docker Container') {
steps {
sh 'sudo docker run -d --name my-container my-image'
}
}
}
}
This pipeline builds a Docker image and runs a container using the Docker commands available inside the Jenkins container.
Step 4: Access Jenkins Web Interface
- Open a web browser and navigate to
http://localhost:8080
.
- You'll see the "Unlock Jenkins" screen. Retrieve the initial admin password by checking the Docker container logs or reading the
initialAdminPassword
file:
docker exec -it <container_id> cat /var/jenkins_home/secrets/initialAdminPassword
Placeholder for Screenshot of Command to Retrieve Password
Copy the password, paste it into the web interface, and proceed with the setup.
Install suggested plugins or customize as needed.
Create your first admin user, and you're ready to use Jenkins!
Advantages of Using Docker
- Portability: Docker containers can run on any machine with Docker installed.
- Isolation: Each container is isolated, preventing conflicts with other applications.
- Ease of Setup: Simplifies the installation process with minimal configuration.
- Consistency: Ensures the environment is consistent across different setups.
- Easy Cleanup: Containers can be stopped and removed without leaving residual files.
To allow the Jenkins user inside the Docker container to run Docker commands without needing to prefix them with sudo
. This involves adding the Jenkins user to the Docker group inside the container.
Here's how you can do it:
Allowing Jenkins to Run Docker Commands Without sudo
By default, Docker commands require root privileges. To enable the Jenkins user inside the container to execute Docker commands without sudo
, you need to add the Jenkins user to the Docker group. Here's how to do it:
Step 1: Access the Running Jenkins Container as Root
First, you'll need to access the running Jenkins container with root privileges. You can do this using the docker exec
command:
docker exec -u 0 -it <container-name> bash
-
docker exec
: Runs a command in a running container. -
-u 0
: Specifies the user ID to execute the command as.0
is the user ID forroot
. -
-it
: Allocates a pseudo-TTY and keeps STDIN open, allowing you to interact with the container's shell. -
<container-name>
: Replace this with the actual name or ID of your Jenkins container. -
bash
: The command to run, in this case, starting a Bash shell.
Example:
docker exec -u 0 -it jenkins-container bash
Note: Replace jenkins-container
with your container's actual name or ID.
Step 2: Add Jenkins User to the Docker Group
Once inside the container as the root user, execute the following commands:
Check if the Docker Group Exists
First, verify whether the docker
group exists inside the container:
grep -i docker /etc/group
- If it doesn't exist, create it:
groupadd docker
Add Jenkins User to the Docker Group
Now, add the jenkins
user to the docker
group:
usermod -aG docker jenkins
-
usermod
: A command to modify a user's settings. -
-aG docker
: Appends the user to thedocker
group.
Verify the User's Group Membership
You can verify that the jenkins
user is now part of the docker
group:
groups jenkins
You should see docker
listed among the groups.
Step 3: Exit and Restart the Container
For the group membership changes to take effect, you need to restart the Jenkins container:
- Exit the container shell:
exit
- Restart the container:
docker restart <container-name>
Example:
docker restart jenkins-container
Step 4: Test Docker Commands in Jenkins
Now, inside your Jenkins jobs or pipelines, you should be able to run Docker commands without needing sudo
.
Example Pipeline Step:
pipeline {
agent any
stages {
stage('Test Docker Command') {
steps {
sh 'docker ps'
}
}
}
}
This pipeline stage will list running Docker containers, and it should execute without permission errors.
Why These Steps Are Necessary
Understanding User Permissions
-
Docker Daemon Access: The Docker daemon (
dockerd
) listens on a Unix socket (/var/run/docker.sock
) by default. Access to this socket is controlled by Unix file permissions. -
Docker Group: Users who are members of the
docker
group can interact with the Docker daemon withoutsudo
, as the socket is owned by thedocker
group.
Security Considerations
- Root Privileges: Granting access to the Docker daemon is equivalent to giving root access, as Docker commands can affect the host system.
- Caution Advised: Ensure that only trusted users and processes have this access.
Important Notes
1. Security Implications
- Risk of Privilege Escalation: Users with access to the Docker daemon can gain root-level access to the host.
-
Best Practices:
- Limit access to the Jenkins interface.
- Secure your Jenkins jobs to prevent arbitrary code execution.
- Regularly update Jenkins and its plugins to patch security vulnerabilities.
2. Alternatives to Adding Jenkins User to Docker Group
If security is a major concern, consider the following alternatives:
-
Docker-in-Docker (DinD):
- Run a separate Docker daemon inside the Jenkins container.
- Isolate Docker operations from the host.
- Cons: More complex setup, potential performance overhead.
-
Use Docker Agents:
- Instead of running Docker commands on the Jenkins master, use agents (nodes) that have Docker installed and configured.
- Assign jobs that require Docker to these agents.
- Pros: Better isolation, easier to manage permissions.
-
Use Pipeline Plugins:
- Utilize plugins like the Docker Pipeline plugin, which provides DSL for building and running containers.
- Pros: Abstracts Docker operations, can improve security.
3. Ensure Consistent Docker Versions
- Since you're mounting the Docker executable and socket from the host, make sure that the versions are compatible with the Jenkins environment inside the container.
- Incompatibilities can lead to unexpected behavior or errors.
Method 2: Installing Jenkins on Windows Subsystem for Linux (WSL)
Placeholder for WSL and Jenkins Logos
Prerequisites
- Windows 10 Version 2004 or higher
- Windows Subsystem for Linux (WSL) enabled
- A Linux distribution installed (e.g., Ubuntu from Microsoft Store)
Steps to Install Jenkins on WSL
Step 1: Enable WSL
- Open PowerShell as Administrator.
- Run:
wsl --install
Placeholder for Screenshot of WSL Installation Command
- Restart your computer if prompted.
Step 2: Install a Linux Distribution
- Open the Microsoft Store.
- Search for Ubuntu and install it.
Placeholder for Screenshot of Ubuntu in Microsoft Store
- Launch Ubuntu from the Start menu.
Step 3: Update Linux Packages
In the Ubuntu terminal, run:
sudo apt update
sudo apt upgrade -y
Placeholder for Screenshot of Package Update Commands
Step 4: Install Java
Jenkins requires Java. Install it using:
sudo apt install openjdk-21-jre -y
Placeholder for Screenshot of Java Installation Command
Step 5: Add Jenkins Repository and Key
- Add the Jenkins Debian repository key:
wget -q -O - https://pkg.jenkins.io/debian-stable/jenkins.io.key | sudo apt-key add -
- Add the repository to the sources list:
sudo sh -c 'echo deb https://pkg.jenkins.io/debian-stable binary/ > /etc/apt/sources.list.d/jenkins.list'
Placeholder for Screenshot of Adding Jenkins Repository
Step 6: Install Jenkins
Update packages and install Jenkins:
sudo apt update
sudo apt install jenkins -y
Placeholder for Screenshot of Jenkins Installation Command
Step 7: Start Jenkins Service
sudo service jenkins start
Verify Jenkins is running:
sudo service jenkins status
Placeholder for Screenshot of Jenkins Service Status
Step 8: Access Jenkins Web Interface
- Open a web browser and navigate to
http://localhost:8080
.
Placeholder for Screenshot of Jenkins Unlock Screen via WSL
- Retrieve the initial admin password:
cat /var/lib/jenkins/secrets/initialAdminPassword
- Continue with the setup as described in the Docker method.
Advantages of Using WSL
- Linux Environment: Provides a genuine Linux environment on Windows.
- Direct Access: Ability to use Linux commands and tools directly.
- Integration: Seamless integration between Windows and Linux file systems.
Why Docker is the Better Method
While both methods allow you to run Jenkins locally, using Docker has several advantages over WSL:
- Simplified Setup: Docker requires fewer steps and configurations.
- Resource Efficiency: Docker containers are lightweight compared to running a full Linux distribution in WSL.
- Isolation: Docker provides better isolation, reducing potential conflicts.
- Consistency Across Environments: Docker ensures that the Jenkins instance behaves the same across different systems.
- Easier Maintenance: Updating or removing Jenkins is straightforward with Docker commands.
- Portability: Docker images can be easily shared and deployed on other machines or servers.
In contrast, WSL may present challenges such as networking configurations, potential performance overhead, and a more complex setup process.
Conclusion
Installing Jenkins locally on your Windows machine empowers you to develop and test CI/CD pipelines in a controlled environment. While both Docker and WSL methods are viable, Docker offers a more streamlined, efficient, and beginner-friendly approach.
By leveraging Jenkins in your DevOps cycle, you can:
- Automate repetitive tasks.
- Enhance collaboration between development and operations teams.
- Accelerate software delivery.
- Improve code quality through continuous integration and testing.
Happy Building with Jenkins!
Posted on November 28, 2024
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.