When developing software it makes sense to be able to work on local files, while the source code should be served from a controlled environment (a container) to prevent pollution of the developer workstation.
In this article I will describe the evolution of a development workflow for deploying applications on OpenShift. The ultimate goal is to make it possible to maximize dev/prod parity, while minimizing the idle time in the change/test cycle.
OpenShift Source-To-Image makes it really easy to publish source code through container technology. Testing the resulting containers in OpenShift is easily done by using either oc cluster up or Minishift, but with the release of OpenShift 4 the first method becomes obsolete. This means that Minishift now is the go-to method for providing a local OpenShift environment for developers.
Note that I will use Python as the language of choice in this article, but a similar strategy can be followed when using other interpreted languages (Ruby, PHP, Perl). When using (byte) compiled languages (Java, GoLang), the build requirement for those makes using this strategy much harder to use.
Traditional local development
When using Python as the language, local development is typically done using
virtualenv and the Python modules being
used are then defined in
requirements.txt. This happens to be the file used by
the Python autodetection for OpenShift s2i, so the example repository makes it
easy to activate a local environment with the correct Python requirements.
The following commands provide you with a local clone of the example code and a Python virtualenv using the default Python version from your workstation:
We can now start a local (debug) webserver:
Run the following in a separate terminal to check the code using the
command (or use your preferred webbrowser):
Using this setup, changes to the application (
wsgi.py) are directly visible.
A new version of the application can be deployed to an OpenShift environment – without actually committing code – using:
This method is easy to setup and maintain, but it has a few obvious disadvantages:
- The Python binary and the installed modules are not guaranteed to be identical as the ones being used in the containerized environments,
- The time-to-build for deployment to OpenShift is bound to become an annoying delay in the development cycle.
Adding Minishift into the mix
Minishift allows you to test your code easily against a locally running OpenShift, saving you for an (extra) external dependency. To install Minishift, follow the guidelines provided within the OKD documentation.
Now start your local Minishift installation:
Make sure you are logged in as developer and deploy and expose the sample application:
Local changes can now be deployed by rebuilding the image from you working directory:
This takes care of the aforementioned disadvantage of not having code parity, but the build-cycle is introducing a delay which introduces an idle-cycle on the part of the developer, and there is a limit on how often one can go for a cup of coffee.
Gunicorn and dynamic code changes
The following section is specific for Python code being served through
gunicorn, but similar practices hold true for other languages (and their
respective HTTP engines).
gunicorn to reread changed code from the filesystem, we need to
gunicorn with a configuration file, containing the following:
Save this snippet in a file called
config.py, put it into a ConfigMap and
make it available to the DeploymentConfig for your application. Then enable
gunicorn to use this configuration by adding an environment variable to the
We now are running
gunicorn with debugging and reloading enabled. Open up a
terminal to be able to keep an eye on the logs:
Copying code changes into a running container
oc binary includes a
rsync verb which can copy (changes in) files from
your working directory to a running container. It can even watch for changes!
Note that there is no need to synchronize permissions between the source and the
target. There is also no need to copy the
Open up terminal and start the
In your original terminal execute the following:
The first line makes a change to the source file using
sed, which is then
copied into the running container by the
rsync process. The change will then
become visible in the output of the
You can of course use your favorite editor and webbrowser to perform those tasks.
If you do this really quick, you might not see the change immediately as there
is a delay in the change being picked up by both the
rsync and the
Make sure you terminate the
rsync process by pressing
^C in the terminal
where it is running, before proceeding with the following section. You now can
close this terminal.
Using a hostfolder for local source code
rsync method described above is quite convenient, there is a way
that is even more convenient, but a little bit more demanding to configure:
When using this method you do not have to worry about having the
running on your workstation. Once configured it is enough to have your Minishift
VM up and running! This method is for all practical purposes identical to the
way Vagrant makes local source code available using
a shared mount.
To setup the
hostfolder do the following from your terminal:
For a container running under OpenShift to be able to read from this mountpoint
we need to enable the
virt_sandbox_use_fusefs SElinux boolean:
By default a container running in OpenShift is not allowed any access to the host it is running on. This can be fixed by changing the SecurityContextConstraints for the ServiceAccount running the container:
Now the DeploymentConfig can be changed to use the mountpoint within the VM as the source for the code used by the application:
Now make another change and test to see if this change propogates:
Note that there still is a delay before the change is picked up by the
The above gives three alternative ways for testing your local changes before committing and pushing them:
- Internal debug webserver for your environment,
rsyncverb from the
This allows for a more lenient code-build-test cycle and thereby preventing commit-log pollution, as well as having a more efficient workflow while working on new features, or fixing the incidental bug, for your application.