I've been banging my head against a wall trying to get Podman to work with Jenkins in an easy way. With RHEL moving to Podman over Docker, this opens up some unusual problems in the Jenkins space. There exists a Docker Pipeline plugin (docker-workflow-plugin
) that suits the bill perfectly, but alas, it requires Docker to run. Or does it? In this guide, we'll look at getting Podman working in lieu of Docker, with the Docker plugin still working fine on the controller. Please note that this was tested on CloudBees CI with a RHEL 8 static agent, but should still work the same on OSS Jenkins. There is no guarantee of this working in any sense, so please use at your own risk and test thoroughly!
Take this example Declarative Pipeline using the Docker plugin:
pipeline {
agent {
docker {
label 'podman'
image 'maven'
}
}
stages {
stage('checkout') {
steps {
checkout scmGit(branches: [[name: '*/master']], extensions: [], userRemoteConfigs: [[url: 'https://github.com/jenkins-docs/simple-java-maven-app.git']])
}
}
stage('run') {
steps {
sh "mvn clean package"
archiveArtifacts artifacts: 'target/*.jar', followSymlinks: false
}
}
}
}
This pipeline uses the docker { }
block to spin up a container on an agent with the label podman
and the image of maven
. It then executes commands against the container (in this case mvn clean package
) and then archives the built JAR. When running this against Podman with no modifications, obviously it won't work as it's kicking off docker
commands against the system. This should be fairly easily remedied when looking at the Podman article "Emulating Docker CLI with Podman". Since we're not utilizing the plugin as a Cloud (which would require the Docker API), it'll just execute the commands directly against the host OS of the Agent. Theoretically, this should work just fine.
First, create the /usr/local/bin/docker
script:
#!/usr/bin/sh
[ -e /etc/containers/nodocker ] || \
echo "Emulate Docker CLI using podman. Create /etc/containers/nodocker to quiet msg." >&2
exec podman "$@"
Next, we need to make the /etc/containers/nodocker
file to suppress the warning that it's running as Podman instead of Docker:
touch /etc/containers/nodocker
Next we need to make the docker
script executable:
chmod +x /usr/local/bin/docker
By default, the Docker Plugin is going to attempt to run a command similar to this on the backend:
docker run -t -d -u 1000:1000 -w /var/lib/jenkins/workspace/podman-example-customer -v /var/lib/jenkins/workspace/podman-example-customer:/var/lib/jenkins/workspace/podman-example-customer:rw,z -v /var/lib/jenkins/workspace/podman-example-customer@tmp:/var/lib/jenkins/workspace/podman-example-customer@tmp:rw,z -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** maven cat
This should work, but unfortunately, it hard-codes the user entry with -u 1000:1000
. This is going to cause problems running Podman rootless, as it doesn't like being told which user to run as. We need to trim that, or we'll see errors similar to below in ours logs:
sh: 1: cannot create /var/lib/jenkins/workspace/podman-example-customer@tmp/durable-d61eb9e3/jenkins-log.txt: Permission denied
This occurs because the user, in this case 1000:1000
, doesn't have rights to modify files on the filesystem that are mounted (in this case, the workspace and workspace tmp directories). So, how do we stop it from doing that? Since it seems it's hard-coded to use -u 1000:1000
, let's trim that from our parameters being passed into the docker
script. We'll have it check if it's the first instance of -u
or 1000:1000
and kill them off from the list of params, and then continue as normal.
Here's a finalized script that worked for me. Note that I changed to using bash
as the shell since most of this isn't POSIX compliant:
#!/usr/bin/bash
[ -e /etc/containers/nodocker ] || \
echo "Emulate Docker CLI using podman. Create /etc/containers/nodocker to quiet msg." >&2
declare -a finalopts
finalopts=()
USERCHECK=0
USERIDCHECK=0
for o in "$@"; do
if [[ "$o" = "-u" && $USERCHECK = 0 ]] ; then
USERCHECK=1
continue
elif [[ "$o" = "1000:1000" && $USERIDCHECK = 0 ]] ; then
USERIDCHECK=1
continue
fi
finalopts+=("$o")
done
exec podman "${finalopts[@]}"
And voila! Using Maven, our build output now looks as expected!

Since all of these changes take place by mucking with the Docker command on the backend, no changes should need to be made to Pipelines using the Docker plugin to continue using Podman!