Hi everyone! Welcome to the ALM Workshop 2025!
This workshop is designed to give you hands-on experience with:
- Learning new and unfamiliar technologies.
- Implementing Continuous Integration (CI) and Application Lifecycle Management (ALM) concepts.
- Applying the theory you’ve learned in a real-world setup.
To make things more interesting, we’ll be using technologies that you may not have worked with before:
- Golang – A modern programming language known for its efficiency and simplicity.
- Quay – A container registry for storing and managing container images.
- GitHub DevSpaces / DevContainers – A development environment that works in the cloud.
- GitHub Actions – A CI/CD pipeline tool for automating software workflows.
- RedHat OpenShift – A Kubernetes-based container platform for deploying applications.
The workshop is divided into several tasks, each serving as a checkpoint. If you get stuck or run out of time, you can always check out the corresponding solution branch to catch up.
Before starting, follow these steps:
-
Fork this repository to your own GitHub account.
-
Start a GitHub CodeSpace from the
mainbranch.- This may take 2+ minutes, so be patient.
- You may get pop-ups asking to install extensions—accept them.
-
Review the repository structure:
- .devcontainer/devcontainer.json – Configures our development environment.
- .github/workflows/ - Contains our yaml files for our CI/CD pipelines.
- infra/openshift.yaml – Contains our Kubernetes resources.
- workshop-service/ – Contains the source code.
- Dockerfile – A multi-stage build file for our Go application.
-
Test your Docker setup by building and running the image:
docker build -t test-workshop . --progress=plain docker run -p 3000:3000 test-workshop-
Your app should be accessible via the GitHub workspace URL or localhost.
- If you missed the popup you can click on the little transmission tower in the bottom left
-
Visit the
/workshopendpoint to check if it works.- You can also share your links that GitHub codespaces generate when you're running your application, but by default the connection is set to private!
- You can change the visibilty in the same ports tab as before as you can see in the image.
-
Now that we have a working development environment, let's move on!
Currently, we only have a local development setup. Our goal is to:
- Work with multiple developers while ensuring consistent, repeatable builds.
- Follow Software Development Lifecycle (SDLC) best practices.
- Deploy our application publicly in a reliable manner.
We'll set up a GitHub Actions pipeline to automate the build process.
-
A pre-configured GitHub Actions workflow file is already available in
.github/workflows/ci.yamlfor this task. -
Make sure you enable workflows on your GitHub Actions tab.
-
Modify the steps to build and push the container image to Quay.io.
-
Use a Robot Account to authenticate with Quay.io.
- HINTS:
- The image name should be as such
quay.io/<your-username>/alm-workshopto properly push - You might need to register the repository in quay first before you can push.
- How will you manage your quay Robot User password in the pipeline?
- Does the robot account have enough permissions on the repository in quay?
- The image name should be as such
- HINTS:
-
Validate the deployment by pulling the container image and running it locally:
docker run -p 3000:3000 quay.io/<your-username>/alm-workshop:<tag>
- You can find the tag in your
quay.iorepository
- You can find the tag in your
Currently, all builds result in an unversioned image, making it hard to track releases.
We'll implement Semantic Versioning (SemVer) to tag images correctly upon release.
This means that when you create a GitHub release with a certain SemVer, the pipeline should be ran again and the docker-image should be <quay-user>/alm-workshop:x.x.x
- Modify the CI pipeline to trigger on GitHub Releases.
- Create a GitHub release for version
1.0.0.
Right now, our application is only running locally. We need a publicly accessible deployment.
We'll deploy our container to RedHat OpenShift Sandbox.
-
Log in to OpenShift Sandbox.
-
You should be able to launch OpenShift
-
Click on the + button on the top right corner.
-
Deploy your Quay.io container image by using the image registry URL.
- Runtime icon = Golang
- Deploy resource type = deployment
- Rest should be OK by default
-
Verify deployment via Topology View and try to access the remote endpoint.
- Click the little arrow icon above your application to open the route.
Manually deploying an application for every change is time-consuming and error-prone.
We'll use Infrastructure as Code (IaC) to automate OpenShift deployments.
-
Delete the manual deployment from Topology View.
-
Create a new branch
devfrommain. -
Read the openshift.yaml to understand the Kubernetes resources and what they do.
-
Modify
openshift.yamlto use your Quay.io image. -
Login to the cluster from a CLI by copying the Login Command
-
You should now be able to do several commands using the OpenShift CLI:
oc get podsto see your pods that are runningoc get deploymentswill show you the deployment resource that OpenShift created for us in the previous stepoc get svcwill show the servicesoc get routeswill show the routes & the urls from which you can connectoc apply -f infra/openshift.yamlwill deploy your application
-
Automate this deployment process by modifying the
cd.yamlpipeline.- Move the file from
.github/to.github/workflows/so the pipeline will automatically be picked up by GitHub Actions. - Provide the correct secrets to login to the OpenShift cluster from your repository.
- Make sure that this pipeline only runs from the dev branch.
- The token that we used before is only valid for 24 hours, so we usually don't use this for automation but it's OK for this task.
- Move the file from
-
Make a change in the openshift.yaml (update the replicas) and let the pipeline apply the changes.
-
Validate the changes via the UI or via the CLI.
Our /workshop endpoint lacks customization and fun elements.
We'll update the application to:
- Add your name to the list of participants.
- Introduce a new field:
SweaterScorethat holds a numeric value of 1-10 on the presentators sweaters. - Provide validation on this range.
- Set the default SweaterScore via an environment variable.
- Modify the application code (
workshop.go). - Validate that it works locally.
- Release this update as version 1.1.0.
Right now, we only have a DEV environment. We need a TST (Test) environment.
We'll create a separate TST branch and adjust configurations accordingly.
- Create a new branch
tstfromdev. - Modify the
openshift.yamlto:- Use different names for Deployment, Service, and Route by using
tst-instead ofdev-.- Normally we would use "Namespaces" to avoid naming conflicts, but the OpenShift Sandbox does not allow us to create multiple namespaces due to security risks.
- Ensure it deploys only released versions (not latest dev builds).
- Use different names for Deployment, Service, and Route by using
- Update the pipeline to trigger on the TST branch.
- Deploy version 1.0.0, then later update to 1.1.0.
You now have a fully functional CI/CD pipeline, supporting automated builds, releases, and deployments!
The next step is to now improve upon this, so that you as a developer can focus solely on producing the code. Choose some of the extra tasks to do.
Try improving your setup with:
- Custom Docker tags
- Do custom tags for your docker builds, right now it takes the branch name but try something as followed:
- On
mainbranch, should be tagged as such<name>:latest. - On other branches, should be tagged as such
<name>:dev-<commitHash>with the hash being a substring of 8 characters.
- On
- Do custom tags for your docker builds, right now it takes the branch name but try something as followed:
- Automatic deployment triggers
- The
devOpenshift environment should always the use the:latestimage that is created when a developer pushes code to main and the build succeeds. - Create a trigger in your pipeline that automatically restarts the deployment on Openshift.
- The
- Lightweight container images
- Right now we're using the default Golang Docker image but we can speed up the build process by picking a smaller base image.
- Automated tests in Docker
- Write a Go test & add tests execution to the multi-stage Dockerfile.
- Adding a metrics endpoint
- Add a metrics endpoint to your application that will give you insights into the application performance.
- Implementing Helm Charts
- Helm charts are the most popular way of managing Kubernetes resources, because you can use advanced templating features.
- Helm charts will replace our current kubectl apply and deploy method.
- Configuring Horizontal Pod Autoscaling
- Add a Horizontal Pod Autoscaler that based on amount of load (requests) to the service will automatically spin up extra pods.
- Simulate a load with Postman or just a bash while loop with curl.
Happy coding! 🚀







