
An image is basically an object that can be used to deploy an operating system to an OpenShift container, such as a Linux Red Hat operating system. These are typically small, lightweight operating systems that just contain the core features needed to run the operating system in an OpenShift container. Often, images come precompiled with certain features. For example, a Python image would contain the requirements needed to run a Python application in the container. A Node.js image would contain the requirements needed to run a Node.js application in the container.
A deployment includes a certain image and the deployment creates a replica set (which is the number of pods that should be created) and then the replica set should spawn pods, and each pod should include a container. The container runs the operating system.
There are various ways to deploy an app on OpenShift.
- From GitHub (https://github.com)
- From Docker Hub (https://hub.docker.com)
- From an image
- From a build
- From a template
- From a JSON or YAML file (templates)
Let's create a Python file named app.py that contains the following. This is a very simple Python script that returns "Hello World" once every 5 seconds. The reason a never ending while loop is used here is to keep the container Running. Without a while loop, the container would exit after printing Hello World. The while loop keeps the container running.
Python logger is used here so that the stdout is included in the pod logs.
import logging
import sys
import time
logger = logging.getLogger()
logger.setLevel(logging.INFO)
format = logging.Formatter(fmt="[%(asctime)s %(levelname)s] %(message)s", datefmt="%Y-%m-%d %H:%M:%S")
consoleHandler = logging.StreamHandler(sys.stdout)
consoleHandler.setFormatter(format)
logger.addHandler(consoleHandler)
int = 0
while int == 0:
logging.info("hello world")
time.sleep(5)
And then let's create a config map that contains app.py
oc create configmap my-config-map --from-file app.py --namespace my-project
Let's use the oc get images command to get the list of Red Hat Python images that can be used. Let's say we want to create our Python app using the registry.redhat.io/ubi9/python-39@sha256:0c2f708b4977469d090719d939778eb95b42c02c1da6476aa95f2e875920652b image, which will create the container using Python version 3.9.
~]$ oc get images | grep -i python
sha256:0c2f708b4977469d090719d939778eb95b42c02c1da6476aa95f2e875920652b registry.redhat.io/ubi9/python-39@sha256:0c2f708b4977469d090719d939778eb95b42c02c1da6476aa95f2e875920652b
sha256:190ea81f2f64ccf7f7c8cb9dc4612eda59eb9e3d2e17f71727a270f078f5114a registry.redhat.io/ubi8/python-27@sha256:190ea81f2f64ccf7f7c8cb9dc4612eda59eb9e3d2e17f71727a270f078f5114a
sha256:4a1d451e1d513115ff54c6e80299e761f60454b5f2f091f3c9ddb9fc1d61f5c4 registry.redhat.io/ubi8/python-38@sha256:4a1d451e1d513115ff54c6e80299e761f60454b5f2f091f3c9ddb9fc1d61f5c4
sha256:971dcd27c3d53f58eb59c946f123223b95662841c1214a394a445380beb75f59 registry.redhat.io/ubi8/python-36@sha256:971dcd27c3d53f58eb59c946f123223b95662841c1214a394a445380beb75f59
sha256:d4e20aa826660f635fad77837b9c6aab8248f0560cd8c3c2283c12704359e9bb registry.redhat.io/rhscl/python-38-rhel7@sha256:d4e20aa826660f635fad77837b9c6aab8248f0560cd8c3c2283c12704359e9bb
sha256:e2a461928e82d7da8991f4fdf5496219f013a6e70c4ef30cf5fb93a4cc450eac registry.redhat.io/ubi8/python-39@sha256:e2a461928e82d7da8991f4fdf5496219f013a6e70c4ef30cf5fb93a4cc450eac
Let's create a YAML file named deployment.yaml with the following, using "registry.redhat.io/ubi9/python-39@sha256:0c2f708b4977469d090719d939778eb95b42c02c1da6476aa95f2e875920652b" as the image to run app.py using Python version 3.9.
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
namespace: my-project
spec:
replicas: 1
selector:
matchLabels:
app: my-app
template:
metadata:
labels:
app: my-app
spec:
containers:
- command:
- /bin/sh
- -c
- python /opt/app-root/src/app.py
image: registry.redhat.io/ubi9/python-39@sha256:0c2f708b4977469d090719d939778eb95b42c02c1da6476aa95f2e875920652b
name: my-container
ports:
- containerPort: 8080
protocol: TCP
volumeMounts:
- mountPath: /opt/app-root/src/app.py
name: my-config-map
subPath: app.py
volumes:
- configMap:
defaultMode: 420
name: my-config-map
name: my-config-map
And then use the oc apply command to create the deployment. If you are not familiar with the oc command, check out my article OpenShift - Getting Started with the oc command
oc apply --filename deployment.py
At this point the oc get all command should return the following, where there is a deployment, a replica set, and a Running pod.
~]$ oc get all --namespace my-project
NAME READY STATUS RESTARTS AGE
pod/my-app-56c98b85f4-fqtc7 1/1 Running 0 6m28s
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/my-app 1/1 1 1 6m28s
NAME DESIRED CURRENT READY AGE
replicaset.apps/my-app-56c98b85f4 1 1 1 6m28s
The pod logs should now have Hello World once every 5 seconds. It works!
[c065234@DLOCPLJ-1-0001 oadp]$ oc logs my-app-56c98b85f4-fqtc7 --namespace my-project
[2025-05-14 01:47:47 INFO] hello world
[2025-05-14 01:47:52 INFO] hello world
[2025-05-14 01:47:57 INFO] hello world
[2025-05-14 01:48:02 INFO] hello world
[2025-05-14 01:48:07 INFO] hello world
Did you find this article helpful?
If so, consider buying me a coffee over at