Migrating Jenkins DinD to Podman: Setting Up a Custom Podman Builder

ยท

3 min read

Introduction

If you're running Jenkins agents as Kubernetes pods with JNLP and Docker-in-Docker (DinD) as containers, you may be considering a migration to Podman as your container engine. This transition helps improve security, eliminates the need for privileged containers, and ensures better compliance with modern containerization best practices.

In this guide, we'll walk through how to set up a custom Podman builder and connect it with a JNLP agent in a Jenkins pod environment using the Podman Builder project.Steps to Set Up a Custom Podman Builder in Jenkins

Build a Custom Podman Image

you can create a custom image using the Podman Builder project and push to any registries

This entrypoint.sh configures Podman to listen on a TCP socket , sets up storage options

#!/bin/sh
set -eu

# Set container runtime to use Podman
export CONTAINER_RUNTIME=podman

# Create or update registries.conf file with the mirror URLs
cat <<EOF > /etc/containers/registries.conf
[registries.search]
registries = ['docker.io', 'quay.io']

[registries.insecure]
registries = []
[registries.block]
registries = []
[registries.forward]
registries = []
EOF

cat <<EOF > /etc/containers/containers.conf
[socket]
listen = "tcp://0.0.0.0:2375"

[containers]
netns="host"
EOF

cat <<EOF > /etc/containers/storage.conf
[storage]
# Default Storage Driver, Must be set for proper operation.
driver = "overlay"

# Runtime directory for temporary container storage.
runroot = "/run/containers/storage"

# Root directory where all container storage data resides.
graphroot = "/build/containers/storage"

[storage.options]
# List of additional image stores.
additionalimagestores = []

# Pull options for images (must be on a single line).
pull_options = { enable_partial_images = "false", use_hard_links = "false", ostree_repos = "" }

[storage.options.overlay]
# Mount options for overlay storage.
mountopt = "nodev"

[storage.options.thinpool]
# Storage options for thinpool.
# 'basesize' defines the default size for new container storage.
basesize = "50G"
EOF

# Start Podman service in the background
podman system service --time=0 tcp://localhost:2375  &

# Keep the container running
tail -f /dev/null

Replace DinD with a Podman Container

Once the podman image is ready, We need to replace the dind container with a podman container inside the Jenkins agent pod.

Modify your Jenkins agent pod YAML definition:

apiVersion: v1
kind: Pod
spec:
  containers:
      image: podman:latest
      imagePullPolicy: Always
      name: dind
      resources: {}
      securityContext:
        privileged: true
        procMount: Default
      tty: true
      workingDir: /home/build
    - env:
        - name: DOCKER_HOST
          value: tcp://localhost:2375
        - name: HOME
          value: /home/build
      image: jenkins-jnlp-worker
      imagePullPolicy: Always
      name: jnlp
      resources:
        limits:
          cpu: "25"
          memory: 64G
        requests:
          cpu: "17500m"
          memory: 45G
      securityContext:
        privileged: false
        procMount: Default
      tty: true
      workingDir: /home/build
  dnsPolicy: ClusterFirst
  imagePullSecrets:
    - name: <add_your_secret>
  nodeSelector:
    beta.kubernetes.io/arch: amd64
    buildtype: default
  priority: 0
  restartPolicy: Never
  schedulerName: default-scheduler
  securityContext: {}
  serviceAccount: default
  serviceAccountName: default
  terminationGracePeriodSeconds: 30

Conclusion

Migrating from DinD to Podman enhances security, simplifies container management, and aligns with modern container best practices. By following this approach and leveraging the Podman Builder project, you can seamlessly integrate Podman into your Jenkins agent pod setup while maintaining a robust CI/CD pipeline.

Happy containerizing with Podman! ๐Ÿš€

ย