
In this blog post, we’ll cover OpenShift Builds and BuildConfig essentials, providing you with the fundamental knowledge and practical steps to create and manage builds within OpenShift. In today’s fast-paced software development landscape, Continuous Integration and Continuous Deployment (CI/CD) are essential for delivering high-quality applications at scale. Red Hat OpenShift, a leading Kubernetes-based platform, simplifies CI/CD with its powerful BuildConfig and Build capabilities. Whether you’re a DevOps engineer or a developer, you’ll learn how to leverage OpenShift to streamline your workflows.
Table of Contents
OpenShift Builds and BuildConfig Essentials
What Is a BuildConfig in OpenShift?
A BuildConfig is an OpenShift object that defines how to build a container image from source code. Think of it as a blueprint for building your app’s container image. It specifies the source code location, the build method or strategy and the output destination for the built image. BuildConfigs also support triggers, which automatically start new builds when changes occur such as code updates, image changes, or manual requests, making your CI/CD pipeline more responsive and efficient.
By managing these parameters declaratively, BuildConfigs allow you to standardize and automate the image build process without relying on manual scripts ensuring repeatability and integration with your CI/CD workflows.
Key Components of a BuildConfig
Understanding a BuildConfig means understanding the sections that define how a build should run. As stated in the section above, below are the essential parts of a BuildConfig object:
Location of the Source Code
A BuildConfig specifies the location of the source code in the spec.source
section of the manifest. This is where you define what code should be built and how OpenShift should access it.
The most common source types include:
- Git repository (which can either be a public or a private repository)
- Binary (allows you to upload local source code or artifacts (e.g., compiled JARs, WARs, static files) directly to OpenShift to trigger a build)
- Dockerfile (you can specify local inline location or the Dockerfile could be in the Git repository)
Git Source
Sample Git source definition;
...
spec:
...
# Where your source code lives
source:
type: Git
git:
uri: https://github.com/your-username/your-repo.git
ref: main
# Only rebuild if these paths change (optional but good to specify)
contextDir: "/"
...
So, what does this mean?
source:
This section defines how and where OpenShift will fetch the application source code for the build.type: Git
: Indicates that the source will come from a Git repository. Other types are discussed above.git:
A nested block that provides the Git-specific configuration.uri:
The URL of the Git repository that contains your application source code. This can point to public or private repos (credentials needed for private access).ref:
The branch, tag, or commit hash to check out. In this case, it’s using themain
branch. If omitted, it defaults to the repository’s default branch.
contextDir:
This tells OpenShift which subdirectory within the repository to use as the build context. / means the root directory of the repo. You can change this to something likesrc/
orapp/
if your application code is nested.
If you require proxy to connect to the Git repository, you can defined the proxy server address (http/https) or even specify domains that do not need to proxy to access under the spec.source section:
...
spec:
...
# Where your source code lives
source:
...
httpProxy: http://proxy.example.com
httpsProxy: https://proxy.example.com
noProxy: example.net, example.other.com
Read more on:
oc explain bc.spec.source.git
If the repository is private, be sure to define the rights credentials to access and clone the repo.
Binary Source
As stated above, Binary source allows you to upload local source code or artifacts (e.g., compiled JARs, WARs, static files) directly to OpenShift to trigger a build.
Some of the key features of a binary source is that:
- It is not triggerable automatically (e.g., via image or config changes).
- You have to manually trigger the build using the
oc start-build
CLI command. - Not supported in the web console, builds must be started via CLI.
When started from the CLI via oc start-build command, you can use various options to specify the location of your artefacts:
--from-file
: Sends a single file or URL to the file location as binary stream to the builder.--from-dir
: Sends the contents of a directory to the builder. Contents are archived and extracted in the build context. URLs to archives are also supported.--from-repo
: Similar to--from-dir
but assumes it’s a Git repo layout (for S2I builds).--from-archive
: Sends a local archive file to be extracted in the builder’s context.
oc explain bc.spec.source.binary
Choosing a Build Strategy
OpenShift supports several strategies for building container images. The build strategy is defined in the spec.strategy
section of a BuildConfig manifest and it determines how the source code is transformed into a runnable container image.
OpenShift supports three primary build strategies:
- Docker Build
- Source-to-Image (S2I) Build
- Custom Build
By default, Docker and S2I builds are supported. The output of Docker and S2I builds is a runnable container image, while Custom builds produce whatever the builder image is configured to create.
Additionally, a Pipeline Build Strategy (based on Jenkins or Tekton) can be used to support CI/CD workflows such as continuous integration and deployment.
Each strategy is suited for different use cases and levels of control s explained below:
Source-to-Image (S2I) Build Strategy
S2I is a build strategy that is ideal for building applications images where you don’t need to manage or create your own Dockerfile. It takes your source code and injects it into a base image (like Node.js, Python, or Java, etc), then builds a new runnable image.
S2I strategy is customizable with build environment variables.
Here is a sample definition on the manifest:
...
spec:
...
# How to build the image
strategy:
type: Source
sourceStrategy:
from:
kind: ImageStreamTag
name: nodejs:16-ubi8
namespace: openshift
# Environment variables for the build process
env:
- name: NPM_MIRROR
value: "https://registry.npmjs.org"
Where:
strategy:
This section defines how OpenShift should build the image.type: Source
: Indicates the use of S2I, where OpenShift injects your source code into a builder image (like Node.js) and produces a new runnable image.sourceStrategy:
sourceStrategy holds the parameters to the Source build strategy.from
: Specifies the builder image to use. In this example:kind: ImageStreamTag
tells OpenShift to use an image from an internal image stream.name: nodejs:16-ubi8
refers to the tag of the builder image (Node.js 16 on Red Hat UBI 8).namespace: openshift
means it’s pulling from the sharedopenshift
namespace, where standard builder images are usually available.
env
: Allows you to set environment variables used during the build process (not in the final container). Here, it setsNPM_MIRROR
to a specific registry, which is helpful for controlling or speeding up package installs.- forcePull: describes if the builder should pull the images from registry prior to building.
Read more from:
oc explain bc.spec.strategy.sourceStrategy
Docker Build Strategy
The Docker build strategy uses a Dockerfile to build an image. It behaves much like the standard docker build
command you’d use locally, but is executed within the OpenShift build infrastructure. OpenShift will use the Dockerfile found in your source repository (or defined inline) to perform the build.
This strategy gives you full control over image layers and build process.
Sample definition of Docker build strategy:
...
spec:
...
strategy:
type: Docker
dockerStrategy:
# Optional: specify Dockerfile path
dockerfilePath: "Dockerfile"
# Build arguments
buildArgs:
- name: NODE_ENV
value: "production"
# Force pull base images
forcePull: true
- strategy:
type: Docker
: Specifies that the build will use the Docker build strategy. OpenShift will look for a Dockerfile and execute a Docker-style build similar todocker build
.dockerStrategy:
This section contains specific configurations for the Docker build process.dockerfilePath: "Dockerfile"
: Specifies the path to the Dockerfile relative to the root of the source repository. Default is"Dockerfile"
at the root; this can be changed to any subpath like"docker/Dockerfile"
.buildArgs:
- A list of key-value pairs passed to the Docker build as
--build-arg
options. - These are build-time variables, not available in the final image at runtime.
- Example:
name: NODE_ENV
,value: "production"
passes--build-arg NODE_ENV=production
to the build.
- A list of key-value pairs passed to the Docker build as
forcePull: true
:- Instructs OpenShift to always pull the base image defined in the Dockerfile, even if a cached version is available.
- Ensures the build uses the latest image from the remote registry.
- Recommended in CI/CD pipelines to avoid outdated base images and ensure security updates are included.
Read more from:
oc explain bc.spec.strategy.dockerStrategy
Custom Build Strategy
The Custom build strategy gives developers full control over the build process by allowing them to define a custom builder image. The image could contain all the tools and logic required to perform the build, making it suitable for highly specialized use cases such as crafting minimal base images, or integrating non-standard build pipelines.
A custom builder image is just a standard container image, but one that includes everything needed to perform your specific build logic when executed by OpenShift.
Because custom builds bypass many of the built-in safety controls, they require elevated privileges to run. For this reason, they are disabled by default and should only be enabled for trusted users with cluster-admin level permissions. Granting access to custom builds without proper controls can introduce significant security risks.
To read more on the parameters you can pass to the Custom Strategy:
oc explain bc.spec.strategy.customStrategy
Pipeline Build Strategy
The Pipeline build strategy gave developers the ability to define Jenkins-based CI/CD workflows directly within OpenShift’s build system. This strategy allowed teams to create sophisticated automation pipelines using Jenkinsfile syntax, making it suitable for complex scenarios such as multi-stage deployments, automated testing workflows, or integration with existing Jenkins-based toolchains.
A pipeline build was defined using a Jenkinsfile, which could be either embedded directly in the OpenShift build configuration or stored in a Git repository and referenced by the build configuration. When triggered, OpenShift would execute the Jenkins pipeline while providing native platform integration for monitoring and management.
However, the Jenkins Pipeline build strategy is deprecated in OpenShift Container Platform 4 and should no longer be used for new projects. This deprecation occurred because OpenShift now provides superior functionality through OpenShift Pipelines (based on Tekton), which offers cloud-native CI/CD capabilities with better performance and Kubernetes integration. Organizations should migrate existing pipeline builds to OpenShift Pipelines or manage Jenkins independently using standard Jenkins practices rather than relying on OpenShift’s deprecated pipeline build integration.
Setting the Build Output Destination
The output section in a BuildConfig
defines where OpenShift should push the image to after the build process completes.
This destination is typically:
- An internal ImageStreamTag (used within OpenShift, recommended for most cases), or
- An external Docker image registry (like Docker Hub or Quay.io).
Internal: ImageStreamTag
Example:
...
spec:
...
output:
to:
kind: ImageStreamTag
name: nodejs-demo:latest
This configuration instructs the build process to push the resulting container image to an OpenShift ImageStream called nodejs-demo with the tag latest. The latest tag typically represents the most recent build of the image.
An ImageStream is an OpenShift resource that provides a consistent, trackable reference to container images. Instead of hardcoding image digests or registry URLs in workloads, you can refer to an ImageStreamTag
. OpenShift will resolve this reference to the actual image in the internal registry.
External: DockerImage
When the output kind
is DockerImage
, OpenShift pushes the image directly to an external registry (e.g., Docker Hub, Quay, Harbor, or a private registry).
...
spec:
...
output:
to:
kind: DockerImage
name: quay.io/myorg/myapp:v1.0.0
If the registry is not specified in the name, OpenShift defaults to Docker Hub. Authentication credentials must be pre-configured using a Secret
and referenced via the output.pushSecret
field.
Use this option if the image is intended for use outside of OpenShift, or when integrating with external CI/CD pipelines and runtime platforms.
Read more on;
oc explain bc.spec.output
oc explain bc.spec.output.to
Defining Build Triggers
In OpenShift, Build Triggers are mechanisms that automate the initiation of builds in response to certain events. Triggers are defined in a BuildConfig and allow OpenShift to automatically start a build process when specific conditions are met, such as changes in the source code or when new images are available. This automation reduces the need for manual intervention and ensures that applications are built and deployed continuously as part of a CI/CD pipeline.
In short, triggers are what make BuildConfigs reactive. They allow new builds to automatically start when:
- Code changes (Git webhook trigger: GitHub, GitLab, Bitbucket, or Generic webhook)
- Base images change (ImageChange trigger: when a new version of a dependent image is pushed)
- Configuration updates (ConfigChange trigger: when the BuildConfig is created or modified)
Check the explanation of the trigger types here:
oc explain bc.spec.triggers.type
Let’s see some of the example setup of various triggers below.
GitHub Triggers
A GitHub trigger fires up a build when code changes hit your GitHub repo, like new commits or pull requests.
- It uses a webhook to ping OpenShift about updates.
- You can set it to only watch specific branches, like main/master.
- For private repos, you’ll need a secret to keep things secure.
Example config:
...
spec:
...
triggers:
- type: GitHub
github:
secret: my-secret
To see configuration parameters for the Github trigger type;
oc explain bc.spec.triggers.github
GitLab Trigger
A GitLab trigger launches a build when your GitLab repo sees changes, like commits or merge requests.
- It relies on a webhook to notify OpenShift.
- You can make it trigger on merge requests too.
- For private repos, a secret ensures only legit updates trigger builds.
Example config;
...
spec:
...
triggers:
- type: GitLab
gitlab:
secret: my-secret
To see configuration parameters for the Github trigger type;
oc explain bc.spec.triggers.gitlab
ImageChange Trigger
An ImageChange trigger rebuilds your app when the base image, like nodejs, gets updated.
- It keeps an eye on an ImageStream for new image versions.
- Your build automatically uses the fresh image.
Example:
...
spec:
...
triggers:
- type: ImageChange
imageChange:
from:
kind: ImageStreamTag
name: nodejs:16
If the nodejs:16 image in the ImageStream updates, OpenShift starts a new build.
To check on more parameters you can define:
oc explain bc.spec.triggers.imageChange
ConfigChange Trigger
A ConfigChange trigger runs a build when you tweak your BuildConfig.
- It picks up changes to things like your source repo or environment variables.
- No need for external tools or services.
Example:
...
spec:
...
triggers:
- type: ConfigChange
Manual Trigger
A manual trigger lets you start a build whenever you want, using the CLI or OpenShift’s web console.
- You’re in charge of when the build happens.
- Perfect for testing or one-time builds.
Example:
oc start-build my-buildconfig
Run this command on the CLI or hit “Start Build” in the console, and the build begins.
Mixing Triggers
You can combine triggers in one BuildConfig. Each trigger does its own thing, starting a build when its event happens.
Example:
...
spec:
...
triggers:
- type: ConfigChange
- type: ImageChange
imageChange:
from:
kind: ImageStreamTag
name: nodejs:16
- type: GitHub
github:
secret: my-secret
This setup triggers builds for BuildConfig edits, nodejs:16 image updates, or GitHub code pushes. If multiple events happen at once, you might get multiple builds queued.
Some of the key things to consider in regards to the BuildConfig are:
- Don’t go wild with triggers, or you’ll end up with too many builds clogging things up.
- For GitHub or GitLab, set up webhooks in your repo to talk to OpenShift (check the BuildConfig for the webhook URL).
- Make sure your ImageStream images, like nodejs:16, are set up for ImageChange triggers.
- Always use secrets for GitHub or GitLab to block unauthorized triggers.
- If you want to pause a trigger, you can just remove it from the BuildConfig.
Controlling Build Resource Usage
Build processes can be resource intensive and if not executed with control, they might:
- Hog Cluster Resources: Consume excessive CPU/memory, slowing down other builds, deployments, or apps.
- Cause Cluster Instability: Overload nodes, leading to pod evictions or crashes.
- Exceed Budgets: Rack up costs in cloud environments with usage-based billing.
- Impact Multi-Tenant Clusters: In shared clusters, one user’s build could starve others.
As such, to ensure that this is controlled, OpenShift provides several mechanisms to limit build resource consumption within a BuildConfig or at the namespace/cluster level. Below are the key approaches:
1. Resource Limits in BuildConfig
You can specify CPU and memory limits directly in the BuildConfig to cap resources for build pods. This is done in the spec.resources section.
Example:
apiVersion: build.openshift.io/v1
kind: BuildConfig
metadata:
name: my-nodejs-app
namespace: my-namespace
spec:
...
resources:
limits:
cpu: "1" # Max 1 CPU core
memory: "1Gi" # Max 1 GiB memory
requests:
cpu: "500m" # Request 0.5 CPU core
memory: "512Mi" # Request 512 MiB memory
triggers:
...
Prevents the build from consuming more than 1 CPU core or 1 GiB of memory, protecting other workloads.
2. Namespace Resource Quotas
You can apply a ResourceQuota to a namespace to limit the total resources all builds (and other pods) can consume. This is useful in multi-tenant clusters.
apiVersion: v1
kind: ResourceQuota
metadata:
name: build-quota
namespace: my-namespace
spec:
hard:
limits.cpu: "4" # Total CPU limit for all pods
limits.memory: "8Gi" # Total memory limit for all pods
requests.cpu: "2" # Total CPU requests
requests.memory: "4Gi" # Total memory requests
pods: "10" # Max number of pods
3. LimitRange for Default Limits
A LimitRange sets default and maximum resource limits for pods (including build pods) in a namespace if no limits are specified in the BuildConfig.
Example:
apiVersion: v1
kind: LimitRange
metadata:
name: build-limits
namespace: my-namespace
spec:
limits:
- type: Container
max:
cpu: "1"
memory: "1Gi"
default: # default Limits
cpu: "500m"
memory: "512Mi"
defaultRequest:
cpu: "200m"
memory: "256Mi"
4. Cluster-Wide Build Defaults
Cluster admins can set default build resource limits using the buildDefaults configuration in the OpenShift API. This applies to all builds cluster-wide unless overridden.
apiVersion: config.openshift.io/v1
kind: Build
metadata:
name: cluster
spec:
buildDefaults:
resources:
limits:
cpu: "1"
memory: "1Gi"
requests:
cpu: "500m"
memory: "512Mi"
This enforces default CPU/memory limits for all builds unless a BuildConfig specifies otherwise.
Sample BuildConfig
Here is a sample BuildConfig for a Node.js app:
apiVersion: build.openshift.io/v1
kind: BuildConfig
metadata:
name: my-first-app-build
labels:
app: my-first-app
spec:
# What triggers a new build?
triggers:
- type: ConfigChange # Build when this BuildConfig changes
- type: ImageChange # Build when the base image updates
imageChange:
from:
kind: ImageStreamTag
name: nodejs:16-ubi8
# Where is your source code?
source:
type: Git
git:
uri: https://github.com/YOUR-USERNAME/YOUR-REPO.git
ref: main # Which branch to build
# How should OpenShift build your app?
strategy:
type: Source # Use Source-to-Image (S2I)
sourceStrategy:
from:
kind: ImageStreamTag
name: nodejs:16-ubi8
namespace: openshift # This is where OpenShift keeps base images
env:
- name: NODE_ENV
value: "production"
# Where should the built image go?
output:
to:
kind: ImageStreamTag
name: my-first-app:latest
# Prevent builds from using too many resources
resources:
limits:
cpu: "1"
memory: "1Gi"
requests:
cpu: "100m"
memory: "256Mi"
This BuildConfig defines the process for building a Node.js application in OpenShift. It triggers builds when the BuildConfig is modified or when the base image (nodejs:16-ubi8
) is updated. The source code is pulled from a Git repository, and the build uses the Source-to-Image (S2I) strategy with a production
environment setting. The built image is pushed to an ImageStreamTag called my-first-app:latest
. Resource limits and requests ensure that the build won’t exceed specified CPU and memory usage, with a maximum of 1 CPU and 1Gi of memory.
What Is a Build in OpenShift?
A Build in OpenShift is the process that takes your app’s source code and turns it into a runnable container image, following the configuration rules defined in the BuildConfig. Consider this analogy, if the BuildConfig is like a recipe for your app, the build is the cooking process; mixing ingredients, baking, and serving the dish.
When a trigger (like a code push or config change) or a manual command starts a build, OpenShift creates a Build object, runs it as a pod in your cluster, and pushes the finished image to the destination you chose.
Step-by-Step: What Happens During a Build
Let’s walk through what happens, step by step, using a sample BuildConfig given above, and cover how resources are used, how to monitor, and how to check the output.
Considering the sample config given above, when a trigger (e.g., you push your code updates to the main branch or edit the BuildConfig) or a manual command (e.g., oc start-build my-first-app-build) starts a build, here’s what goes down:
1. Create the BuildConfig:
- Before any build can run, you need to apply the BuildConfig to your OpenShift cluster. Save the YAML above to a file (e.g., my-first-app-build.yaml) and run:
oc apply -f my-first-app-build.yaml
- You can also create the BuildConfig directly from the OpenShift web interface as either admin or developer. Therefore, from OpenShift web, select the project/namespace you have access to and navigate to Builds > BuildConfig > Create BuildConfig for an admin view or Build > Create BuildConfig for a developer view.
- OpenShift now has the blueprint of how to build your app (source, strategy, output, etc.). You can view available BuildConfigs from UI or from CLI:
oc get bc -n namespace
You can also create a BC via CLI, oc new-build.
oc new-build --help
2. Trigger or Start the Build:
- Based on the sample bc given, a build starts when:
- ConfigChange: Editing the BuildConfig (e.g., changing NODE_ENV) triggers a build.
- ImageChange: An update to the nodejs:16-ubi8 image in the openshift namespace triggers a build.
- Alternatively, you can manually start a build:
oc start-build my-first-app-build -n my-namespace
- OpenShift will then create a Build object, named something like my-first-app-build-1 (the number increments for each build). This object tracks the build’s progress.
- You can see it with:
oc get builds -n my-namespace
- Or you can check from the UI.
3. Build Pod Creation
- A temporary pod (e.g., my-first-app-build-1-build) launches to run the build.
- It uses defined resource settings: reserves 100m CPU and 256 MiB memory (requests) and caps at 1 CPU core and 1 GiB memory (limits).
- The pod pulls the nodejs:16-ubi8 image from ImageStream and clones your Git repo’s main branch.
- See the pod:
oc get pods -n my-namespace | grep build
4. Source-to-Image (S2I) Build Process:
- OpenShift uses the S2I strategy to inject your application code into the
nodejs:16-ubi8
base image. - The
NODE_ENV
is set toproduction
, and commands likenpm install
andnpm build
(from yourpackage.json
) are executed. - Resource limits are enforced: the build stays within 1 CPU and 1 GiB memory. If the build exceeds these limits (e.g., a resource-heavy
npm install
), it will be throttled or fail to protect the cluster. - To monitor the build, you can follow the logs:
oc logs build/my-first-app-build-1 [-n namespace]
5. Image Creation and Push:
- On success, the pod packages your app into a new image and pushes it to my-first-app:latest in the ImageStream.
- If it fails (e.g., registry unreachable), the build status shows Failed.
6. Build Completion:
- The pod shuts down, and the Build object updates to Complete, Failed, or Cancelled (if you run oc cancel-build my-first-app-build-1).
- Check status:
oc get builds -n my-namespace.
Build Process Statuses in OpenShift
Builds have their own lifecycle states like New, Pending, Running, Complete, or Failed. They provide key information about the state of a build. You can view and debug them using the OpenShift CLI or web console.
oc get builds - namespace
oc describe build my-first-app-build-1 -n namespace
The statuses;
- New: The build has been created but is waiting to start.
- Pending: The pod is setting up (e.g., pulling the
nodejs:16-ubi8
image, cloning the repository). - Running: The S2I build process is actively running (e.g., executing
npm install
or other build steps). - Complete: The build has finished successfully, and the image is now available in
my-first-app:latest
. - Failed: The build encountered an issue (e.g., code errors, out of memory).
- Cancelled: The build was manually stopped.
How to Monitor Builds
Check Status:
oc get builds -n my-namespace
This shows stages (Running, Complete). Use -w for live updates.
View Logs:
oc logs build/my-first-app-build-1
Monitor Resources:
oc adm top pod -n my-namespace | grep build
checks CPU/memory. If the build hits 1 GiB memory, tweak the BuildConfig limits or optimize code.
Debug:
oc describe build my-first-app-build-1
This gives details like duration or failure reasons (e.g., “out of memory”).
How to Check Output
Verify the build’s image is ready:
Check ImageStream:
oc get imagestream my-first-app -n my-namespace
Use oc describe imagestream my-first-app for image details.
Verify Image:
oc describe istag my-first-app:latest
This shows creation time and build match.
Test It:
Run oc new-app my-first-app:latest for a test deployment, or use a DeploymentConfig with ImageChange for auto-deployment.
If there is no image, check oc logs build/my-first-app-build-1 for registry errors.
And that is all on OpenShift Build and BC essentials. In our next guide, we will dive deeper into BuildConfigs and the build process with a practical walkthrough, demonstrating how to create and manage builds in OpenShift step-by-step.
Conclusion
In this guide, we’ve explored the essentials of OpenShift builds and BuildConfigs, covering key aspects like source code location, build strategies, output destinations, and build triggers. We’ve also highlighted how to monitor build statuses and manage resources to ensure efficient builds. Understanding these concepts allows you to automate and optimize your application’s build and deployment pipeline in OpenShift, making your development workflow smoother and more effective.
Other OpenShift Tutorials
How to Upgrade OpenShift Cluster: Seamless Steps for Success
Automate Tasks in OpenShift with Kubernetes Jobs and Cron Jobs: A Practical Guide