Python Virtual Environment Setup in Jenkins

Python's Virtual Environments Feature presents a unique opportunity with CI/CD tooling - where users congregate to publish and execute code of their own devising. Developers might use different versions of the same package (creating dependency conflicts), or they might simply need a newer version of a package than is on the system by default.

Or, with security-centric implementations, developers don't get root access, which prevents package installation outside of userspace.

The Virtual Environments feature allows users to set up a container of sorts (albeit very limited) that permits installing of ephemeral packages (and specific package versions) to prevent dependency conflicts.

Prerequisites

Set Jenkins Global Parameters

Under Jenkins -> Manage Jenkins -> System, configure the Shell executable to /bin/bash. It's blank by default (Bourne Shell):

Jenkins Set Default Shell

Install Packages (example from Debian 12)

1apt install python3-venv python3-virtualenv

Consuming Virtual Environments in a Jenkins Job

Consuming a virtual env (venv) in Jenkins is now relatively straightforward. Here's an example from my Certificate Checker

1python3 -m venv checkcerts_env
2source checkcerts_env/bin/activate
3python3 -m pip install requests ruamel.YAML pyOpenSSL fqdn
4python3 check-certificates.py -f certs_list.json

With this example, I create a virtual environment (fresh every time) named checkcerts_env. It's not as necessary to create a venv with a unique name inside the Jenkins workspace if it's cleaned on run, but I prefer the extra safety.

The source command changes python3's environment to checkcerts_env. You can verify immediately after with:

1(checkcerts_env) jenkins@localhost:~/workspace/certificate-tracker$ which python
2/var/lib/jenkins/workspace/certificate-tracker/checkcerts_env/bin/python

From there, pip can install packages unique to this ephemeral workspace. Keep in mind this will slow execution down quite a bit, which is a fair trade for reliable outcomes.