One of the fundamental principles of Continuous Delivery is Build Binaries Only Once. Subsequent deployments, testing and releases should be never attempt to build the binary artifacts again, instead reusing the already built binary. In many cases, the binary is built at each stage using the same source code, and is considered to be “the same”. But it is not necessarily the same because of different environmental configuration or other factors.

A Docker image is a “binary artifact” that includes all of the application stack and requirements. OpenShift creates a Docker image as part of each build. By treating the built Docker image as the deployable unit, OpenShift enables Build Once, Deploy Anywhere.


It is assumed that you have a general understanding of the basic usage of OpenShift 3 and access to an OpenShift 3 environment. If not, please take a look at the Amazon Web Services “Test Drive” for OpenShift, which can give you a free trial of OpenShift 3 running on top of AWS.

OpenShift Core Concepts in Build Once, Deploy Anywhere


A project is a Kubernetes namespace with additional annotations, and is the central vehicle by which access to resources for regular users is managed. A project allows a community of users to organize and manage their content in isolation from other communities. Users must be given access to projects by administrators, or if allowed to create projects, automatically have access to their own projects.

Image Stream

An image stream is similar to a Docker image repository in that it contains one or more Docker images identified by tags. An image stream presents a single virtual view of related images.
1. Its own image repository in OpenShift's integrated Docker Registry
2. Other image streams
3. Docker image repositories from external registries

Service Account

A Service Account enables the components inside OpenShift to make API calls independently. Service Accounts provide a flexible way to control API access without sharing a regular user's credentials. A Service Account is a kind of non-human user. Built-in service accounts are as follows:
- system:image-builder, which is used by build pods, which allows pushing images to any image stream in the project using the internal Docker registry.
- system:deployer, which is used by deployment pods, which allows viewing and modifying replication controllers and pods in the project.
- default, which is used to run all other pod unless the specify different service account.


A template describes a set of objects that can be parameterized and processed to produce a list of objects for creation by OpenShift. The objects to create can include anything that users have permission to create within a project, for example services, build configurations, and deployment configurations. A template may also define a set of labels to apply to every object defined in the template.


Build an Application

First, an application is built so that its “binary artifact” can later be deployed anywhere.

1.Create Project hello

oc new-project hello

2.Create Application php-hello-world

oc new-app

3.Expose the Application

oc expose service php-hello-world

You should see a response of “Hello World”. You would have to change your hostname depending on the configuration of your OpenShift environment.

Create Another Project

To simulate “deploy anywhere”, a new project should be created where the built image can be re-used. While possible previously with a few more steps, OpenShift v3.0.2.0 makes it even easier to deploy an application from an existing Docker image which was built in another project.

1.Create Project prod-hello

oc new-project prod-hello

2.Examine Project Policy of hello

oc describe policyBindings :default -n hello

-n hello, the -n flag tells the oc client which project to use

Role: system:image-puller
Groups: system:serviceaccounts:hello

At this moment, no ServiceAccounts are specified for the system:image-pullers role on the hello project. The prod-hello project needs access to pull the images from the hello project.

3.Add ServiceAccount Access to hello Project

oc policy add-role-to-user system:image-puller system:serviceaccount:prod-hello:default -n hello
  • system:image-puller, is the role to add a user to.
  • system:serviceaccount::, the “user account” to add to the role.

Running this command gives the system:image-puller role to the default Service Account from the prod-hello project to the hello project. In other words, you are granting read access to prod-hello in hello.

oc describe policyBindings :default -n hello
Role: system:image-puller
Groups: system:serviceaccounts:hello

Deploy with existing Image Stream

1.Create A Deployment Template

Since the purpose of “Build Once, Deploy Anywhere” is to only build once, it would be useful to create a quick way to deploy the existing built image from the original hello project. This can be done with a template. The existing resources in the hello project can be exported to form the base of this template. However, as prod-hello should not do another build, the buildConfig resource will be omitted from the final template.

oc export deploymentConfig,service,route -o yaml --as-template=php-hello-world > prod-php-hello-world.yaml

The name attribute of the ImageStreamTag and the host attribute of the Route should be changed. The updated snippets of the template should look like the following:

- apiVersion: v1
kind: DeploymentConfig
- type: ConfigChange
- imageChangeParams:
automatic: true
- php-hello-world
kind: ImageStreamTag
name: php-hello-world:prod-hello type: ImageChange


- apiVersion: v1
kind: Route
host: to:
kind: Service
name: php-hello-world

You can edit the template by hand or by using the scripts as follows. Be sure to use the appropriate hostnames/domains for your environment:

perl -i -pe 's/name: php-hello-world:latest/name: php-hello-world:prod-hello/g' prod-php-hello-world.yaml
perl -i -pe 's/' prod-php-hello-world.yaml

Because the hello-prod project will not perform a build, there is no ImageStream which is tagged with hello-prod. This would prevent OpenShift from automatically deploying when the template is instantiated.

2.Instantiate the Template

oc project prod-hello
oc new-app -f prod-php-hello-world.yaml

3.Examine the ImageStream

oc project hello
oc get imageStream
oc describe imageStream php-hello-world
Name: php-hello-world
Created: 28 minutes ago
Labels: app=php-hello-world
Docker Pull Spec:

Tag Spec Created PullSpec Image
latest 26 minutes ago

4.Tag the ImageStream

oc tag hello/php-hello-world@sha256:a94f7113d501dea557c952886d099b59825ad14e2a3f25aa545fe0311aef7b4c prod-hello/php-hello-world:prod-hello

Please substitute the proper SHA string for your environment.

5.Deploy the Image

oc deploy prod-php-helo-world --latest -n prod-hello


Click the image to see it full size.


Docker’s container packaging format enables combining the application, system environment and data together. Through the use of various core components in OpenShift, you can easily and practically enable Continuous Delivery. OpenShift enables you to Build Once, Deploy Anywhere!

Click the image to see it full size.


Kei Omizo
OpenShift Solution Architect,
Strategic Business Development APAC
Red Hat K.K.



OpenShift Container Platform, OpenShift Dedicated

< Back to the blog