This article is based on a post originally published by R. Moorman at Moor Interactive (moori.nl), describing their team’s hands-on evaluation of Jenkins Blue Ocean and Pipelines.
Why Jenkins Pipelines and Blue Ocean?
Mature engineering teams tend to iterate constantly on their CI/CD workflows. Jenkins has long been a staple of that process, but its classic UI and job-configuration model can become unwieldy as project count grows. Cloud-native alternatives like Travis CI and Drone gained popularity in part because they store build configuration alongside source code in Git — something Jenkins historically made difficult.
Two Jenkins features close that gap significantly:
- Jenkins Pipelines — lets you define your entire build, test, and deployment process as code in a
Jenkinsfilecommitted to your repository. - Blue Ocean — a plugin that rethinks the Jenkins user experience, surfacing pipeline status, stage results, and test data with minimal navigation.
“Blue Ocean is a project that rethinks the user experience of Jenkins, modelling and presenting the process of software delivery by surfacing information that’s important to development teams with as few clicks as possible.”
The sections below walk through spinning up Jenkins Blue Ocean with Docker Compose, writing a declarative Jenkinsfile, and using key Pipeline features such as Docker agents, conditional stages, and post actions.
Running Jenkins Blue Ocean with Docker Compose
Containerising Jenkins keeps your host clean and makes the setup reproducible. You need three files: a Dockerfile, a docker-compose.yaml, and a docker.conf that exposes the Docker socket so Jenkins can spin up agent containers.
Dockerfile
Start from the official Blue Ocean image and copy in the Docker daemon configuration:
FROM jenkinsci/blueocean:latest
MAINTAINER R. Moorman <rob@moori.nl>
USER root
COPY docker.conf /etc/init.d/dockerCode language: HTML, XML (xml)
docker-compose.yaml
Mount the Docker socket so Jenkins can create sibling containers on the host, and persist Jenkins home to a local directory:
version: '2'
services:
jenkins:
build: .
ports:
- 8080:8080
volumes:
- ./jenkins_home:/var/jenkins_home
- /var/run/docker.sock:/var/run/docker.sockCode language: JavaScript (javascript)
docker.conf
Expose the Docker daemon on TCP as well as the Unix socket so the Jenkins Docker plugin can reach it:
DOCKER_OPTS="-H tcp://0.0.0.0:4243 -H unix:///var/run/docker.sock --tls=false"Code language: JavaScript (javascript)
With all three files in the same directory, start the stack:
docker-compose up
Jenkins will be available at http://localhost:8080/. Complete the initial setup wizard, then navigate to the Blue Ocean view via the sidebar.

Writing Your First Declarative Jenkinsfile
After switching to the Blue Ocean view you can create a new Pipeline and point it at a source repository. Blue Ocean will look for a Jenkinsfile at the repository root. You can also use the built-in visual Pipeline editor for quick experiments, but writing the Jenkinsfile by hand gives you full version-control history and the most flexibility.
The following example is based on a Python project. It checks out source code, runs the flake8 linter, converts results to JUnit XML format, and publishes them so Blue Ocean can display them as test results. The full example repository is available at https://github.com/robmoorman/jenkins-blueocean.
pipeline {
agent {
docker 'python:3.6.1'
}
stages {
stage('Install dependencies') {
steps {
sh 'pip install -r requirements.txt'
}
}
stage('Test') {
steps {
sh 'flake8 src/ --exit-zero --output-file flake8-output.txt'
sh 'flake8_junit flake8-output.txt flake8-output.xml'
}
}
}
post {
always {
junit 'flake8-output.xml'
}
failure {
echo 'Failed!'
}
success {
echo 'Done!'
}
}
}Code language: PHP (php)

Key Pipeline Concepts Explained
Agents
The agent directive tells Jenkins where and how to run a pipeline or an individual stage. Specifying a Docker image as the agent is especially clean: Jenkins pulls the image, runs your steps inside the container, then discards it. This mirrors the approach used by Travis CI and Drone, so teams familiar with those platforms adapt quickly.
You can define different agents per stage, which makes it straightforward to compile in one environment and deploy from another — all within the same Jenkinsfile.
Stages and Steps
Splitting your build into named stages and steps serves two purposes:
- Visibility — Blue Ocean renders each stage as a column in its pipeline view, making it immediately obvious where a build failed.
- Control flow — when a step fails, the pipeline halts and subsequent steps are skipped. You can also attach
postblocks to individual stages (for example, always publishing coverage reports after the test stage, regardless of pass/fail).
Conditional Steps with when
The when directive lets you gate a stage on branch name, environment variable, or other conditions. This is particularly useful for deployment stages that should only run on specific branches:
stage('Deploy') {
when {
branch 'develop'
}
steps {
sh 'sh ./etc/deploy_test.sh'
}
}Code language: JavaScript (javascript)
Combining branch conditions with pull-request detection keeps a single Jenkinsfile as the authoritative source of truth for the entire delivery process — from feature branch lint checks through to production deployment.
Post Actions and Notifications
The post block supports conditional sections including always, success, failure, unstable, and changed. Common uses include:
- Publishing JUnit test results (
junitstep) - Sending Slack notifications on build failure
- Archiving build artefacts
- Triggering downstream pipelines
Note that at the time this was written (early 2017, around the first public Blue Ocean release), not all Jenkins plugins had been updated to render correctly within the Blue Ocean UI. The classic Jenkins view remained fully compatible, so plugin incompatibility was an inconvenience rather than a blocker. Plugin compatibility has continued to improve since then — check the Blue Ocean compatibility matrix for current status.

Conclusion
Jenkins Pipelines, with declarative Jenkinsfiles and Docker agents, offer a flexible and version-controlled approach to CI/CD that competes directly with cloud-native platforms. Storing pipeline logic in the repository itself — rather than in Jenkins job configuration — addresses one of the longest-standing pain points of traditional Jenkins setups.
Blue Ocean addresses the usability gap with a modern, stage-oriented interface that makes pipeline status easy to understand at a glance. Plugin ecosystem maturity was a real limitation at the time of Blue Ocean’s initial release, but it should not be treated as a dealbreaker given the pace of development in the Jenkins ecosystem.
If you are evaluating whether to migrate from a cloud CI platform back to self-hosted Jenkins, or simply looking to modernise an existing Jenkins setup, starting with a Dockerised Blue Ocean instance and declarative Pipelines is a low-risk way to assess the workflow before committing fully.
Next steps: Explore shared libraries to make pipeline steps reusable across repositories, and look at the parallel directive for running independent stages concurrently to cut build times.