Jenkins

The CI/CD incumbent for ~20 years. Master/agent architecture, Declarative vs Scripted Pipeline, Configuration-as-Code (JCasC), shared libraries, Kubernetes plugin for ephemeral agents, security hardening after CVE-2024-23897.

Overview

Jenkins, the incumbent

Jenkins is the CI/CD incumbent. JetBrains 2024 DevEcosystem puts it at ~28% share, second only to GitHub Actions (~33%) and ahead of GitLab CI (~21%).

Why Jenkins is still chosen in 2026

  • On-prem and air-gapped — Runs anywhere: your data center, VPC, air-gapped lab. Regulated industries (finance, defense, pharma) often forbid SaaS CI; self-managed Jenkins is the most mature on-prem option, with self-managed GitLab CI the alternative
  • Massive existing investment — 10+ years of Jenkinsfiles, shared libraries and integrated plugins; migrating off is years of work and rarely cost-justified
  • Maximum flexibility via Groovy — Read external systems, generate dynamic stages, integrate anything via plugins. YAML CI tools have a logic ceiling; Jenkins doesn't
  • ~1,800 plugins — A plugin for every CI/CD task ever attempted; unmatched breadth, but maintenance varies wildly and CVEs are frequent

Why teams migrate off

  • Operational overhead — Controllers need Java tuning, plugin upgrades, JCasC maintenance, security patching; a poorly maintained Jenkins is a constant source of incidents
  • Dated UX — 2010-era ergonomics in many places; Blue Ocean helps but isn't universal
  • Plugin security — CVE-2024-23897 (January 2024): anonymous arbitrary file read via the Jenkins CLI's expansion of @-prefixed args, CVSS 9.8, weeks of incident response across the industry
  • Cost of skill — Groovy expertise is rarer than YAML; Jenkinsfile maintenance becomes a specialist activity

Three load-bearing concepts

  • Configuration-as-Code (JCasC) is non-negotiable — Click-ops Jenkins is a dead end: drift, no audit, no disaster recovery. JCasC reads jenkins.yaml at startup, so the controller becomes ephemeral and reproducible
  • Ephemeral agents via the Kubernetes plugin — Static agents are the supply-chain footgun (compromised build, backdoored agent, next build inherits it); pod-per-build is the right pattern
  • Shared Libraries — Without them every Jenkinsfile reimplements deploy steps; with them one library defines deploy(env), runQualityGate(), buildContainer() for 80 service repos, versioned

Key concepts

Jenkinsfile (Declarative)
Lives at repository root. Declarative is the default flavor in 2026 — opinionated structure, easier to lint: Two flavors exist. Declarative (above) — opinionated, lintable. Scripted — node { … } with arbitrary Groovy; powerful but harder to constrain.
Configuration-as-Code (JCasC)
Single jenkins.yaml that seeds the controller at startup. Replaces click-ops with version-controlled config: Mounted into the controller pod via ConfigMap. Controller is now ephemeral — destroy and rebuild from scratch in minutes; config comes from git. Without JCasC, controller config is unreproducible click-ops drift.
Shared Libraries (@Library)
Versioned Groovy code shared across all Jenkinsfiles in an org. Lives in a separate repo with this layout: A var file looks like: Consumed in any Jenkinsfile by a one-liner: The @v3 pins the library version. Version bumps are explicit per-Jenkinsfile, just like dependency upgrades. Without shared libraries, every team copy-pastes deploy steps; with them, one well-tested library serves the whole org.
Kubernetes plugin (ephemeral agents)
Spawns one pod per build. Pod is destroyed at build end. Replaces static agent VMs. Pod template can be defined globally (in JCasC) or per-Jenkinsfile (inline yaml '''…'''). The inline form is more common in 2026 — pipeline declares its own runtime: Operational notes: - Use distinct ServiceAccounts per pod template — one for build pods (no cluster perms), one for deploy pods (k8s deploy perms in target namespaces). - Set securityContext.runAsNonRoot: true on every container; PSS/PSA enforces. - Cap concurrent pods via cloud's containerCap — runaway pipelines can otherwise overwhelm node capacity. - Pod-level resource requests/limits are essential; without them, K8s schedules with default 0/0 and pods get OOMkilled randomly.
Pipeline triggers
Common patterns: For SCM-driven triggers (the modern default), configure webhooks in GitHub/GitLab pointing at /github-webhook/ on the controller, then the Jenkinsfile uses: Multi-branch pipelines auto-discover branches and PRs from the SCM and create a Jenkinsfile build per branch. Combined with branch protection in the SCM, this is the canonical pattern for PR-driven CI on Jenkins.
Credentials and secrets
Jenkins's credential management is mature; the gotcha is the wrong way to use it. Right way — withCredentials block scopes secrets to a specific stage and never logs them: Wrong way — assigning credentials to global env or pipeline-level environment: Modern pattern: federated identity via Vault Agent / IAM Roles for ServiceAccounts (IRSA) when on AWS EKS. Pod assumes a role via OIDC; no secret ever lives in Jenkins credential store. Same pattern as GHA OIDC — short-lived tokens, rotation implicit, audit per-build. Secrets in build logs is the most common Jenkins security incident. The credentials binding plugin masks values in logs — but only the literal string, not derived values. echo "key is ${AWS_SECRET_ACCESS_KEY}" masks; echo "first 4: ${AWS_SECRET_ACCESS_KEY[0..3]}" does not. Train accordingly.
Recipe: Jenkinsfile for Java microservice on K8s
Production-grade pattern combining JCasC-mounted shared library, ephemeral K8s agent, parallel stages, post-block notifications: Notes: parallel test/quality stage cuts wall time by ~60% over serial. input block pauses for human approval before prod deploy — Jenkins's equivalent of GHA Environments + required reviewers. Cosign signing is keyless via OIDC (cosign container has the OIDC token from pod service account).
Recipe: hardening after CVE-2024-23897
CVE-2024-23897 (January 2024, CVSS 9.8) — anonymous arbitrary file read via Jenkins CLI's expansion of @-prefixed args. Patched in 2.442 / LTS 2.426.3. The aftermath drove a global Jenkins hardening exercise. Hardening checklist: Beyond the CVE-specific patch: - Disable anonymous read access. Default Jenkins lets anonymous users see job names and console logs — anyone with network access learns about your build infrastructure. - Run controller behind a reverse proxy (nginx / Caddy) with rate limiting; never expose port 8080 directly to the internet. - Enable CSRF crumb requirement (default in modern Jenkins; verify it's on). - Sandbox Groovy execution via Script Security plugin. Pipeline scripts run in a sandbox; @NonCPS escape requires admin approval. Without sandboxing, any Jenkinsfile can execute arbitrary Groovy on the controller. - Patch cadence — subscribe to jenkins-advisories@googlegroups.com. Patch within 1 week of advisory; LTS line is the supported channel. - Plugin hygiene — uninstall plugins you don't use. Each plugin is attack surface. Run jenkins-plugin-cli list-plugins quarterly to inventory. - Audit log to SIEM via Audit Trail plugin. Forward to Splunk/Datadog/ELK for retention beyond local rotation.
Recipe: dynamic parallel stages from a list
Common need: run the same stage across N services from a config file. Scripted Groovy makes this easy: parallel accepts a Map. collectEntries builds the map dynamically. The same pattern works for matrix builds (multiple JDK versions × multiple OS), per-region deploys, fan-out E2E test shards. Declarative Pipeline has a built-in matrix directive for the simple case: Use Declarative matrix for static cross-products; Scripted dynamic parallel for runtime-discovered lists.
Recipe: blue-green deploy with rollback
Jenkins's input step + parallel stages enables a true blue-green with manual gate: The input step pauses indefinitely until a human clicks. options { timeout(time: 1, unit: 'HOURS') } at pipeline level auto-rejects after the timeout, triggering the post failure block which rolls back. This is the Jenkins-native equivalent of GHA Environments + required reviewers + automated rollback. Pre-K8s ingress control planes, this was THE blue-green pattern.

When to use it

  • On-prem or air-gapped CI/CD requirements that rule out SaaS
  • Existing Jenkins investment that's working — migration cost rarely justified
  • Complex pipelines beyond YAML's reasonable reach (dynamic stage generation, plugin integrations)
  • Regulated industries (finance, defence, pharma) where SaaS CI is forbidden by policy
  • Multi-tenant CI hosting where you need fine-grained RBAC and tenant isolation

Interview questions

  • When does Jenkins still beat GitHub Actions / GitLab CI in 2026?
  • Walk through a production Jenkins setup on Kubernetes — controller, agents, storage, security.
  • Compare Declarative vs Scripted Pipeline — when do you use each?
  • How do you handle plugin security and CVE response in Jenkins?
  • How do you migrate from Jenkins to GitHub Actions or another modern CI?
  • Quick-fire interview answers — Jenkins essentials in one-liners.

Sign up free to read the full topic

More DevOps topics

Start free on Cariara · Coding problems · System design studio