Featured project 10 · CI/CD · Jenkins + Kubernetes
Jenkins + Kubernetes Test Pipeline
A Jenkins pipeline, configured entirely as code, that builds a small API, deploys it to a kind Kubernetes cluster in a namespace per build and runs unit, smoke and regression tests against the deployment; GitHub Actions starts a real Jenkins on every push and requires the pipeline to pass.
Purpose
Shows the CI/CD side of test automation: getting tests to run reliably against a freshly deployed system, on every change, with results people can read. The service under test lives in the repository, so the pipeline depends on nothing outside it, and the Jenkinsfile itself is tested in CI like any other code.
Technology stack
| Area | Tools |
|---|---|
| CI server | Jenkins 2.580 LTS in Docker: Configuration as Code, Job DSL, Pipeline Graph View, JUnit, HTML Publisher, credentials binding |
| Kubernetes | kind 0.33 (Kubernetes in Docker), kubectl 1.37: Deployment with probes, Service, Job, a namespace per build |
| System under test | room-booking: Node.js 24 API, no dependencies, with node:test unit tests |
| Tests | pytest 9 + requests: smoke and regression suites, JUnit XML and pytest-html reports, Ruff |
| CI | GitHub Actions: checks, the Kubernetes path with the same scripts, and a real Jenkins that runs the Jenkinsfile |
Architecture overview
Jenkinsfile stages, parallelism, parameters, quality gate, reports
│ calls
scripts/*.sh kind-up, deploy, smoke-job, api-tests, teardown (also used by GitHub Actions)
│
kind cluster 'qa' namespace qa-<build>: Deployment (2 pods, probes) + Service + smoke Job
▲
Jenkins controller (Docker) JCasC + Job DSL, uses the host's Docker for images and the clusterKey engineering decisions
- Everything as code: plugins in the image, users, credentials and the job in JCasC and Job DSL, the pipeline in the Jenkinsfile
- Scripts do the work and the Jenkinsfile orchestrates, so GitHub Actions runs the same deployment and tests without Jenkins
- A namespace per build on a reused cluster: isolated runs, one-command cleanup, about 30 seconds per build
- Two deployment checks: a Kubernetes Job inside the cluster through the Service name, and API tests from outside through port-forward
- The deployment reports its build number, and a smoke test asserts it, so a stale pod or wrong image cannot pass
- The quality gate also fails when too few tests ran; each stage records its results once (an early version counted every test twice)
Implemented features
- Parallel unit tests and lint, then image build, kind cluster and image load, deploy with rollout wait, in-cluster smoke Job, parallel API smoke and regression
- Parameters for the test scope and keeping the deployment; timeouts, timestamps, no concurrent builds, log rotation
- JUnit results with trend, published HTML reports, archived artifacts, a masked credential in the notification step
- A deliberately broken rule failed the build at the first stage, before anything was built or deployed
- CI starts the Jenkins image, triggers the job through the REST API and fails unless the Jenkins build ends with SUCCESS
- Design notes and 76 interview questions on Jenkins, pipelines, Docker and Kubernetes, linked to the code (Markdown + PDF)
Setup and execution
docker compose -f jenkins/docker-compose.yml up -d --build --wait # Jenkins on http://localhost:8088
scripts/run-jenkins-build.sh # start the job, wait, print the resultSample test results


CI workflow
On every push and pull request: unit tests, lint and the API tests against the service on the runner; then, in parallel, the Kubernetes path without Jenkins (kind, deploy, smoke Job, API tests) and a job that builds and starts the Jenkins image and runs the pipeline in it.
Known limitations and future improvements
Limitations
- Builds run on the controller and it uses the host's Docker socket: fine for a local demo, not for a shared Jenkins
- Images are loaded into kind instead of pushed to a registry; plugins are not pinned yet
Next steps
- Kubernetes pod agents instead of controller executors
- A registry, pinned plugins and a shared library for common steps
