• Articles about computing
• Articles about software development
Examining simple build and deployment operations on OpenShift 3
OpenShift 3 is designed to make simple application deployment more-or-less
automatic — you can go directly from source code in a repository, to
an application running in a container (pod) with no detailed understanding
of the internal operations involved. However, such an understanding is
necessary to set up more complicated build operations.
This article describes how to deploy a simple Java application, which is
provided as an executable JAR file, by creating a build configuration
and a deployment configuration. All OpenShift steps are carried out on
the command line using the
oc tool, and we will inspect
the OpenShift artefacts created by the infrastructure at each step.
To follow the steps in this example, you will need a Java 1.8 JDK,
and an installation of Maven (and probably some experience of
setting it up and using it).
I don't assume much knowledge of OpenShift 3, but you need to know
what a pod is, and have some understanding of containers.
Create a simple Apache Camel application from an archetype
For this demonstration I will be using an application based on Fuse
Integration Services (FIS) — this is a framework for building Apache Camel
applications based on Spring Boot. There is no particularly compelling
reason for this choice, other than that I need to deploy FIS applications
on OpenShift for other purposes. This demonstration would work with
any self-contained Java application that can be run from a JAR
Get the source
A sample FIS Camel application can be built from a Maven archetype,
$ mvn org.apache.maven.plugins:maven-archetype-plugin:2.4:generate \
Fill in the prompted values — the exact input is unimportant, but
fis-test for the artefact name, which also becomes
the name of the directory that Maven creates for the source.
The application includes a lot of infrastructure, including the whole of
the Apache Camel core, but all it does in its stock form is write messages
to standard out.
Build and test the JAR
cd to the newly-created directory, and then
$ mvn package
This creates a JAR file in the
It should be possible to run the application locally, to see the output
it produces. Of course, in a real development exercise you would probably
want to run unit tests, etc., as well.
$ java -jar target/fis-test-1.0-SNAPSHOT.jar
Create an OpenShift project
Log into OpenShift at the command line (
oc login...) and create a
new OpenShift project; the project name and description are unimportant
for our present purposes.
$ oc new-project test-project
Create an OpenShift build configuration
In OpenShift, a build configuration (BC) is a specification (in the form
of a Kubernetes object)
that describes how to build a deployable image (usually a Docker image)
from some kind of source. For our purposes it is important to note that
"source" is interpreted very broadly. Although we are using the
"source-to-image" process here, the source is an executable Java JAR
file. In fact, so far as OpenShift is concerned, "source" is anything
that isn't a Docker image — it might even be a configuration file.
If we have a Docker image, we can skip the
build step completely, and go directly to creating a deployment
configuration (see below).
Set up a new OpenShift build configuration, using the stock Java builder
image, and indicating that the build will take a binary as input
(a JAR, in this case).
$ oc new-build --binary=true --name=fis-test --image-stream=redhat-openjdk18-openshift:1.2
fis-test will be used for the created image, and
for a number of other purposes. To see the details of the build configuration:
$ oc describe bc/fis-test
This shows the following information, among other things. Note that the
build will produce an image called fis-test, and that there is no source
for the image yet: we will provide it when invoking the build from
the command line.
From Image: ImageStreamTag openshift/redhat-openjdk18-openshift:1.2
Output to: ImageStreamTag fis-test:latest
Binary: provided on build
You can also view, and perhaps edit, the Kubernetes object definition in
YAML format by running
$ oc edit bc/fis-test
Build the application image
Start the build defined by the
fis-test build configuration,
uploading the JAR built earlier by Maven:
$ oc start-build fis-test --from-file=target/fis-test-1.0-SNAPSHOT.jar --follow
--follow switch here indicates that the command should not
complete until the build does.
OpenShift creates a new pod to do the build, whose name is based on the
build configuration name — in this case,
takes as its image the builder image specified in the
To start the build, the file (or directory) specified on the command line
is packed into
a tar file, and then becomes the builder image's standard input. OpenShift
tar command in the builder's container, unpacking the
from stdin into a directory —
/tmp/src by default.
It then runs the
/usr/local/bin/s2i/assemble which, in this
simply copies the JAR files from
Java builder image can manage other kinds of Java souce or binary,
and actions will be different in those cases: in some cases, actual
Java compilation may be performed, although this is not necessary in
the present example.
assemble (and some other scripts that
in this case) the whole contents of the filesytem of the builder
are pushed to the docker registry as a new image. Consequently, we
end up with the a new image called
fis-test which is
almost exactly the same as
redhat-openjdk18-openshift, but with our JAR file in
/deployments. It is the presence of this JAR that will
trigger a JVM execution when the new image is deployed and executed.
The fact that the new image contains everything that was in the builder
image is a point of contention for some OpenShift users. A case can
certainly be made that a production container ought not to
tooling, both for reasons of resource management and for security. If
this is a problem, then a different build mechanism will need to be used,
or a second "chained" build step will be needed to sanitize the generated
We can list the builds in the current project like this, and we should
see one completed build:
$ oc get builds
NAME TYPE FROM STATUS STARTED DURATION
fis-test-1 Source Binary Complete 7 minutes ago 1m5s
We should also see one completed pod, that was used to do the build:
$ oc get pods
NAME READY STATUS RESTARTS AGE
fis-test-1-build 0/1 Completed 0 8m
This pod could now be deleted — it won't be used for anything else;
presumably it is retained so its logs can
be inspected if the build fails.
Deploy the image into an OpenShift pod
We now have one new image stream in the project's namespace:
$ oc get is
NAME DOCKER REPO TAGS UPDATED
fis-test 172.30.1.1:5000/test-project/fis-test latest 8 minutes ago
The image stream consists of one image — the one with the default
We need to tell OpenShift how to deploy and run this image in one or
more pods; this requires the creation of a deployment configuration.
$ oc new-app fis-test
Note that the name
'fis-test' is the name of the image stream — there are many other possible
new-app, including source code repositories.
new-app can create build configurations as well but, so far as I know, we need
oc new-build explicitly to provide an executable
Looking at the list of deployment configurations:
$ oc get dc
NAME REVISION DESIRED CURRENT TRIGGERED BY
fis-test 1 1 1 config,image(fis-test:latest)
we see that the deployment is (by default) triggered by a configuration
change, or a change to the image ``fis-test:latest``. In this case,
providing the configuration counts as a trigger, and the deployment and
provisioning steps will be triggered without further intervention.
So you should already see one pod running:
$ oc describe dc fis-test|grep Replicas
Replicas: 1 current / 1 desired
Since the build configuration was created using default values, the
desired replica count (number of pods) will be 1.
The single, new pod is created by a transient deployer pod. The name
of this pod, in this example, will be
Unlike the builder pod, however, this pod is not retained after
completion. You may see it briefly flash into life if you watch the
pod list whilst doing a deployment.
Since the image for the new pod was created by the source-to-image process
using the script /usr/local/s2i/assemble, the entry
point for execution will be
run script delegates (in this simple case) to
/opt/run-java/run-java.sh, which detects the JAR file
/deployments, and executes it using
java -jar.... The command line specifies the use of the
Jolokia Java agent, so that the user can have a graphical view
of the JVM operation.
After modifying the application, subsequent OpenShift builds are carried
out by repeating the
command, which will trigger a rebuild and redeployment in
OpenShift. The infrastructure will create new build pods and deployer
pod as necessary, numbering them sequentially.
Note that the default redeployment strategy is 'Rolling',
which will cause the a new pod to be started with the new code,
before the old one is shut down. Depending on the application, this
may be inappropriate, and it might be advisable to change the deployment
strategy to 'Recreate' (e.g., using
oc edit dc/fis-test).
In practice, I would expect that substantial OpenShift projects would
be built using some form of pipeline process, perhaps coordinated
by a build manager like Jenkins. The build manager would create new
OpenShift pods to carry out specific build and deployment operations.
Although OpenShift makes it possible to go directly from a source code
repository to a running container, the large number of default settings
involved in this operation make it less suitable for large-scale development
I've used the command-line for everything in this example, not just because
I think it makes the detailed steps clearer, but because I think that
the terminology it uses is more apposite. The OpenShift web console,
although powerful in its own right, uses terms like 'build' and 'deployment'
in non-specific ways. The web console uses the term 'deployment' to
mean both a deployment configuration, and the process of executing a
deployment. If you already understand the OpenShift build and deployment
philosophy that shouldn't be a problem, but the
doesn't mix up the different concepts.