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
- Ingress & Gateway API
- Ingress and Load Balancer Errors — 502, 503, 504, 404, 413 and TLS
- Install and CLI Fundamentals
- Installation and Bootstrap
- Internal Developer Platforms
- Internal Developer Platforms (IDPs) & Backstage
- Jenkins Controller vs Agent Architecture
- Jenkinsfile — Pipeline as Code
- JFrog Artifactory — Production Administration, Errors and Mistakes
- JFrog Xray — Policies, Watches, Impact Analysis, Errors and Mistakes
- Karpenter — Node Autoscaling
- kubectl CLI Command Reference
Start free on Cariara · Coding problems · System design studio