Skip to main content

Creating a Containerized Application on Z: A Step-by-Step Guide

In this edition of 'The IBM Z Experience,' Joe Gulla extends a banking application consisting of CICS transactions and data in Db2 databases

TechChannel Application Development

Did you ever wonder what it looks like to develop and deploy a containerized application? I did. That’s why I wrote this article.

It took some research on my part, but what follows is a step-by-step list of activities that a programmer carries out to create a containerized application in an IBM Z environment running z/OS and Enterprise Linux from Red Hat.

About the Application

The new application in this exercise will utilize the existing function of a banking application and extend it. The old banking application in question is running on Linux on the IBM Z and consisting of CICS transactions and data in IBM Db2 databases. Extending it will make the data available on a cellphone or tablet in a new and interesting way without duplicating the function of the z/OS application as it currently operates.

To carry out this exercise I will explain a modern containerized application, built with Linux on IBM Z, that securely calls the CICS application via APIs, then presents the results to a mobile app. Below are the steps that a programmer typically follows to build a containerized application on IBM Z involving both z/OS and Red Hat Enterprise Linux.

It Starts With Design Work

The programmer starts by examining the existing banking application. Let’s call this the discovery step. The programmer (or application designer) identifies the CICS transactions that contain the needed banking logic, identifies the Db2 tables involved and determines what functions should be “exposed.” Exposed is the language used when APIs are making information available like “get balance” or “display recent activity.” In this way, the developer is reusing the functions and data already part of the application running on z/OS.

Next, the designer or developer designs the API Contract. This means laying out the REST APIs that represent business capabilities—for example, get the balance of an account for a given ID. Figuring this out means defining input/output JSON formats, identifying security requirements and planning for error handling.

Development Is Next

The next step is to expose z/OS functions as APIs. The tools commonly used on IBM Z to do this are z/OS Connect Enterprise Edition and CICS Web Services/REST APIs. At this step, the developer maps CICS transactions to REST APIs. To do this, they use z/OS Connect to transform JSON into COBOL data structures and route requests to CICS. In this way, they connect to Db2 indirectly through existing programs. At this stage, CICS transactions are now callable via secure REST endpoints.

Creating the Code Running on Linux

The next step is to build the Linux application code. This new application code functions as a business extension layer. In this example, the extension runs on Red Hat Enterprise Linux on IBM Z. The developer must choose a language from those supported by the bank. This might be Java Spring Boot, Node.js or Python (just examples) and the developer must write the application logic. The code will call z/OS APIs, combining or enhancing the data and formats responses for mobile use. It is significant that the innovative mobile device use is happening without changing the existing core systems.

Next, the developer needs to add mobile-device features. They typically transform raw banking data into user-friendly formats like charts, alerts or notifications. Another example might be a display that converts transaction history into categorized spending summaries.

Create the Dockerfile

The next step is to write the statements supporting an application using the following Dockerfile statements. Below is an example for an application written in Java. The Dockerfile is read by the Docker command and contains specific directives used to build the image:

     FROM registry.access.redhat.com/ubi8/openjdk-17
     COPY target/app.jar /app.jar
     ENTRYPOINT ["java", "-jar", "/app.jar"]

These instructions tell Docker to start with Red Hat’s pre-made Linux environment that already has Java 17 ready to go and then drop the application code into it. Complete details of the statements are found in Table 1.

Table 1. Items in the Dockerfile file for Our Banking Application

ItemTypeExplanation
FROMDockerfile instructionSpecifies the base image your container will build on. Every Dockerfile must start with (or include) a FROM.
registry.access.redhat.comContainer registryThis is the image registry (like Docker Hub, but for Red Hat images). It tells Docker where to pull the base image from.
ubi8Base OS image familyStands for Universal Base Image 8, a Red Hat Enterprise Linux 8–based image. It’s a secure, minimal RHEL-compatible OS layer.
openjdk-17Runtime layerIndicates this image includes Java OpenJDK 17 preinstalled, so you can run Java applications without installing Java yourself.
COPYDockerfile instructionCopies files from your local machine, the build context, into the container image.
target/app.jarSource pathThe compiled Java application (JAR file), typically produced by Maven or Gradle in the target/ directory.
/app.jarDestination pathThe location inside the container where the JAR file is stored.
ENTRYPOINTDockerfile instructionDefines the main command that runs when the container starts. This is usually your application.
“java”ExecutableThe Java runtime used to launch your application. Included because of the base image.
“-jar”Java optionTells Java to run a JAR file as an application.
“/app.jar”Application pathThe JAR file that will be executed inside the container.

Create the Container Image

Next is the Docker command. The standard syntax for the Docker command follows a structured, object-based pattern using the Bash shell: 

docker [GLOBAL_OPTIONS] COMMAND SUBCOMMAND [ARGUMENTS...]

The next step is to build the container:

docker build -t bank-mobile-api .

After the build, the container will contain the application plus the runtime dependencies. The main difference between a Dockerfile and the Docker command is that a Dockerfile is a blueprint file used to build a Docker image, while a Docker command is a command line interface (CLI) instruction used to manage and run Docker resources. Additional details about the command are in the table below.

Table 2. Items in the Docker Command

PartTypeExplanation
dockerCommand-line toolThe main program used to interact with Docker.
buildSubcommandTells Docker to create an image from a Dockerfile.
-tOption (flag)Stands for tag—used to assign a name to the image.
bank-mobile-apiImage name (tag)The name you are giving your built image so you can reference it later.
.Build contextMeans “current directory”, where Docker looks, for the Dockerfile and files to include.

It’s Time to Test

The next step is to run the container using the CLI:

     Docker run -p 8080:8080 bank-mobile-api

The API being tested issues calls to the z/OS backend to ensure correct responses. The test is used to validate security, performance and data accuracy. Since the end-to-end security has not yet been provisioned (a later step in this flow), the test will have to be performed over again to assess that specific area. The same is true for the monitor-and-optimize step (another step later in this flow). The component breakdown is shown in Table 3.

Table 3. Elements of the Previous Docker Command

TypeExplanation
docker runThis tells Docker to create and start a new container from a specific image.
-pThis is short for “publish” and maps a networking port on your computer to a port inside the container.
8080:8080This links Host Port:Container Port. The first 8080 is the port on your actual computer. The second 8080 is the port the application is listening to inside the isolated container.
bank-mobile-apiThis is the name of the Docker image (the blueprint) that Docker uses to build and run the container.

Complete the Other Lifecycle Activities

After the testing is completed, the job is not yet completed. What is left to do?

Store Image in Container Registry

Use the Docker command to push the application to the enterprise registry to make the container available for deployment.

docker tag bank-mobile-api registry.company.com/banking/mobile
docker push registry.company.com/banking/mobile

Deploy to Kubernetes Using OpenShift on IBM Z

Use Red Hat OpenShift (Kubernetes) to create Deployment YAML statements defining Pods, Servicesand Scaling policies. Kubernetes functionality in OpenShift manages scaling, resilience and availability. Below are statements to deploy the application using OpenShift. The statements are a YAML Kubernetes Manifest for deployment, which means run and manage this containerized application.

apiVersion: apps/v1
kind: Deployment
metadata:
name: mobile-api
spec:
   replicas:   3
   template:
     spec:
        containers:
– name api
image: registry/company/mobile

Table 4. Elements of the YAML Kubernetes Manifest

YAML ElementValueExplanation
apiVersionapps/v1Specifies the Kubernetes API version being used and apps/v1 is the stable API for Deployments.
kindDeploymentDefines the type of resource. A Deployment manages a set of identical Pods and ensures they are running as desired.
metadataContains identifying information about the object.
metadata.namemobile-apiThe name of the Deployment. This is how the resource is identified within the cluster.
specDefines the desired state of the Deployment.
spec.replicas3Specifies that three instances (Pods) of the application should be running at all times.
spec.templateDescribes the Pod that will be created by the Deployment.
spec.template.specDefines the specification of the Pods themselves.
spec.template.spec.containersLists the containers that will run inside each Pod.
containers.nameapiThe name of the container inside the Pod.
containers.imageregistry/company/mobileThe container image to run. This is pulled from a container registry.

Secure the End-to-End Flow

There are a number of components on different systems that need to work together in a secure manner. The flow is mobile device —-> API gateway —-> Linux container, accessing z/OS by way of an API exposing CICS/Db2 transactions and data.

Enabling TLS (HTTPS) involves configuring X.509 certificates and trust stores across all tiers, ensuring encrypted communication between the mobile client, API gateway (DataPower), containerized services and z/OS APIs. DataPower acts as the security gateway, terminating external TLS connections, validating OAuth/JWT tokens, enforcing API security policies defined in API Connect and securely forwarding requests to back-end services. Identity is propagated downstream and mapped to RACF credentials on z/OS, enabling fine-grained authorization for CICS transactions and Db2 data.

The table below shows the element of the application and the security procedure used to secure the transaction flow.

Table 5. Elements of a Secure Transaction

Element of ApplicationSecurity Procedure Used
Mobile App 
 Uses HTTPS
 Sends OAuth token
DataPower Gateway 
 Terminates TLS
 Validates OAuth/JWT
 Applies policies
 Re-encrypts traffic
Linux Container 
 Receives trusted request
 May validate token or rely on gateway
 Calls z/OS APIs via HTTPS
z/OS Connect 
 Accepts secured request
 Maps identity to RACF
 Invokes backend services
CICS / Db2 
 Protected by RACF rules
 Executes transaction securely

Integrate With Mobile Application

An important step is integration with the mobile system software. You do this through the API endpoints provided to mobile developers. It is necessary to ensure that latency is acceptable and data format matches the user needs. It is useful to utilize mobile features including push notifications and session handling conventions.

Monitor and Optimize

It is important to optimize what has been created for the application so it performs well. Ways to improve performance involve API caching, connection pooling and query performance. To do this, monitoring tools like Prometheus or Grafana examine Linux performance and IBM Omegamon and SMF for z/OS-side application performance. It is important to track response times, transaction volume and errors that arise.

Maintain Continuous Delivery (DevOps)

To maintain continuous delivery, the main activities that update the application updates need to be automated. This includes builds, tests and deployments. There are different tools that help make this happen using CI/CD pipelines. However, Red Hat OpenShift directly facilitates CI/CD pipelines through its own built-in, native features. While you can still use traditional external tools like Jenkins, OpenShift has evolved to provide modern, Kubernetes-native alternatives that reduce the need for third-party automation servers.

Lifecycle Recap

The flow of activities to build the application can be summarized in the figure below:

We take trusted banking functions running in CICS on z/OS, expose them as APIs and build a containerized app on Linux that calls those APIs and transforms the data into a mobile-friendly experience. The container is deployed on Kubernetes, so it scales easily, while the core banking logic safely remains unchanged.

Next Article in the Series

The next article of “The IBM Z Experience” is focused on z/OS modernization strategies—APIs, microservices and integration with cloud-native applications.


Key Enterprises LLC is committed to ensuring digital accessibility for techchannel.com for people with disabilities. We are continually improving the user experience for everyone, and applying the relevant accessibility standards.