Skip to content

Instantly share code, notes, and snippets.

@blues-man
Last active September 15, 2026 15:14
Show Gist options
  • Select an option

  • Save blues-man/2570c98ac24e18adf5fd3246b353e63c to your computer and use it in GitHub Desktop.

Select an option

Save blues-man/2570c98ac24e18adf5fd3246b353e63c to your computer and use it in GitHub Desktop.
Script to deploy the whole Getting Started with OpenShift for Developers workshop, for any of the four backend languages (tested on OpenShift 4.21)
#!/usr/bin/env bash
#
# Deploy the whole "Getting Started with OpenShift for Developers" workshop in one shot.
# https://redhat-scholars.github.io/openshift-starter-guides/
#
# Covers every module up to and including "Application Healthchecks":
# Projects -> Parksmap App -> Routes -> Permissions ->
# Nationalparks Backend App -> Connecting to a Database -> Application Healthchecks
#
# Tested end-to-end on OpenShift 4.21 (oc 4.18 client) in September 2026,
# for all four backend languages.
#
# Usage:
# ./workshop_deploy.sh # java backend, "workshop" project
# ./workshop_deploy.sh my-project # java backend, existing project
# ./workshop_deploy.sh my-project nodejs # nodejs backend
# ./workshop_deploy.sh my-project dotnet
# ./workshop_deploy.sh my-project python
# BACKEND=python ./workshop_deploy.sh my-project
#
# The backend matches the language tabs in the "Nationalparks Backend App" module.
# Accepted names: java (default) | dotnet | nodejs | python, plus the obvious
# aliases (quarkus, .net, csharp, js, javascript, node, py).
#
# "java" is the Quarkus backend: openshift-roadshow/nationalparks-quarkus.
#
# What changed vs. the OpenShift 4.10 version of this script:
# * MongoDB: quay.io/centos7/mongodb-36-centos7 is gone (CentOS 7 is EOL).
# We now use MongoDB's own Community Server image from Quay, as the guide
# does, with MONGO_INITDB_ROOT_* bootstrap credentials and an application
# user created via mongosh. It replaced docker.io/mongo:6.0.4: that tag was
# three years stale, Docker Hub rate-limits anonymous pulls, and clusters
# mirroring docker.io through a proxy fail the pull outright.
# * The Java backend is Quarkus 3 on Java 17, from its own repository
# openshift-roadshow/nationalparks-quarkus (default branch "main"). That is
# why the Java builder tag is openjdk-17-ubi8 and not openjdk-11-ubi8 --
# Quarkus 3 needs Java 17+. openshift-roadshow/nationalparks stays on
# Spring Boot for the workshops that still build it.
# * DeploymentConfig is deprecated - everything here is a plain Deployment.
# * All four backends work again. The .NET and Javascript ones had to be fixed
# upstream first: openshift-roadshow/nationalparks-dotnet#4 (runs on .NET 8,
# honours the MONGODB_* variables, data loader fixed) and
# openshift-roadshow/nationalparks-js#12 (Express 4 + the official mongodb
# driver, Node >= 18 instead of restify on Node 0.10).
# * The backends do NOT all read the same environment variables. Python is the
# odd one out: DB_HOST instead of MONGODB_SERVER_HOST, and MONGODB_USERNAME
# instead of MONGODB_USER. That is why the secret below is built per backend.
set -euo pipefail
PROJECT="${1:-workshop}"
BACKEND="${2:-${BACKEND:-java}}"
PARKSMAP_IMAGE="${PARKSMAP_IMAGE:-quay.io/openshiftroadshow/parksmap:latest}"
MONGODB_IMAGE="${MONGODB_IMAGE:-quay.io/mongodb/mongodb-community-server:8.0.32-ubi9-slim}"
# ---------------------------------------------------------------------------
# Backend selection
# Repo, S2I builder and runtime icon per language, matching the "Builder Image
# version" the guide tells you to pick in the web console.
# ---------------------------------------------------------------------------
case "${BACKEND,,}" in
java|quarkus)
NP_REPO="https://github.com/openshift-roadshow/nationalparks-quarkus.git"
NP_BUILDER="openshift/java:openjdk-17-ubi8"
NP_RUNTIME="java"
;;
dotnet|.net|net|csharp|c#)
NP_REPO="https://github.com/openshift-roadshow/nationalparks-dotnet.git"
NP_BUILDER="openshift/dotnet:8.0-ubi8"
NP_RUNTIME="dotnet"
;;
nodejs|node|js|javascript)
NP_REPO="https://github.com/openshift-roadshow/nationalparks-js.git"
NP_BUILDER="openshift/nodejs:20-ubi9"
NP_RUNTIME="nodejs"
;;
python|py)
NP_REPO="https://github.com/openshift-roadshow/nationalparks-py.git"
NP_BUILDER="openshift/python:3.9-ubi9"
NP_RUNTIME="python"
;;
*)
echo "Unknown backend '${BACKEND}'. Use one of: java, dotnet, nodejs, python." >&2
exit 1
;;
esac
# Env var names the application expects. Java, .NET and Javascript agree;
# Python reads the host from DB_HOST and the user from MONGODB_USERNAME.
if [ "${NP_RUNTIME}" = "python" ]; then
DB_HOST_VAR="DB_HOST"
DB_USER_VAR="MONGODB_USERNAME"
else
DB_HOST_VAR="MONGODB_SERVER_HOST"
DB_USER_VAR="MONGODB_USER"
fi
# Overridable, as before
NATIONALPARKS_REPO="${NATIONALPARKS_REPO:-$NP_REPO}"
NATIONALPARKS_BUILDER="${NATIONALPARKS_BUILDER:-$NP_BUILDER}"
# Database bootstrap values, same as the guide
MONGODB_ADMIN_USER="admin"
MONGODB_ADMIN_PASSWORD="secret"
MONGODB_APP_USER="parksapp"
MONGODB_APP_PASSWORD="keepsafe"
MONGODB_APP_DATABASE="parksapp"
oc="oc -n ${PROJECT}"
echo "### Deploying the ${NP_RUNTIME} backend (${NATIONALPARKS_REPO}) into project ${PROJECT}"
# ---------------------------------------------------------------------------
# Projects
# ---------------------------------------------------------------------------
oc new-project "${PROJECT}" 2>/dev/null || oc project "${PROJECT}"
# ---------------------------------------------------------------------------
# Permissions
# The parksmap frontend queries the OpenShift API to discover backends, so its
# ServiceAccount needs the "view" role in the project.
# ---------------------------------------------------------------------------
${oc} policy add-role-to-user view -z default
# ---------------------------------------------------------------------------
# Parksmap App + Routes
# ---------------------------------------------------------------------------
${oc} new-app "${PARKSMAP_IMAGE}" --name=parksmap \
-l 'app=workshop,component=parksmap,role=frontend,app.kubernetes.io/part-of=workshop,app.kubernetes.io/name=java'
${oc} create route edge parksmap --service=parksmap
# ---------------------------------------------------------------------------
# Connecting to a Database: MongoDB
# ---------------------------------------------------------------------------
${oc} create secret generic mongodb-credentials \
--from-literal=MONGO_INITDB_ROOT_USERNAME="${MONGODB_ADMIN_USER}" \
--from-literal=MONGO_INITDB_ROOT_PASSWORD="${MONGODB_ADMIN_PASSWORD}"
${oc} create secret generic nationalparks-mongodb-parameters \
--from-literal="${DB_HOST_VAR}"=mongodb \
--from-literal=MONGODB_DATABASE="${MONGODB_APP_DATABASE}" \
--from-literal="${DB_USER_VAR}"="${MONGODB_APP_USER}" \
--from-literal=MONGODB_PASSWORD="${MONGODB_APP_PASSWORD}"
${oc} new-app "${MONGODB_IMAGE}" --name=mongodb \
-l 'app=workshop,component=nationalparks,role=database,app.kubernetes.io/part-of=workshop,app.kubernetes.io/name=mongodb'
${oc} set env deploy/mongodb --from=secret/mongodb-credentials
${oc} rollout status deploy/mongodb
# The container is Ready as soon as it starts, but mongod bootstraps the root
# user on a temporary local-only instance first, so wait until it really listens
echo "Waiting for MongoDB to accept connections..."
for _ in $(seq 1 60); do
${oc} exec deploy/mongodb -- mongosh --quiet --eval 'db.runCommand({ping: 1})' >/dev/null 2>&1 && break
sleep 5
done
# Create the application user the nationalparks backend authenticates with
${oc} exec deploy/mongodb -- mongosh \
-u "${MONGODB_ADMIN_USER}" -p "${MONGODB_ADMIN_PASSWORD}" --authenticationDatabase admin --quiet \
--eval "use ${MONGODB_APP_DATABASE}" \
--eval "db.createUser({user: \"${MONGODB_APP_USER}\", pwd: \"${MONGODB_APP_PASSWORD}\", roles: [{role: \"dbAdmin\", db: \"${MONGODB_APP_DATABASE}\"},{role: \"readWrite\", db: \"${MONGODB_APP_DATABASE}\"}]})"
# ---------------------------------------------------------------------------
# Nationalparks Backend App (Source-to-Image)
# ---------------------------------------------------------------------------
${oc} new-app "${NATIONALPARKS_BUILDER}~${NATIONALPARKS_REPO}" --name=nationalparks \
-l "app=workshop,component=nationalparks,role=backend,app.kubernetes.io/part-of=workshop,app.kubernetes.io/name=${NP_RUNTIME}"
${oc} set env deploy/nationalparks --from=secret/nationalparks-mongodb-parameters
${oc} create route edge nationalparks --service=nationalparks
# Parksmap only picks up backends whose Route carries this label
${oc} label route nationalparks type=parksmap-backend
# ---------------------------------------------------------------------------
# Application Healthchecks
# ---------------------------------------------------------------------------
${oc} set probe deploy/nationalparks --readiness --liveness \
--get-url=http://:8080/ws/healthz/ \
--initial-delay-seconds=30 --period-seconds=10 --timeout-seconds=1 --failure-threshold=3
# ---------------------------------------------------------------------------
# Wait for everything to be up
# ---------------------------------------------------------------------------
${oc} logs -f bc/nationalparks
${oc} rollout status deploy/parksmap
${oc} rollout status deploy/nationalparks
# ---------------------------------------------------------------------------
# Load the National Parks dataset and verify
# Done over the Route rather than with "oc exec", because not every builder
# image ships curl. /ws/info is requested without a trailing slash and followed
# with -L: the Python backend registers it as /ws/info/ and redirects.
# ---------------------------------------------------------------------------
NP_HOST="$(${oc} get route nationalparks -o jsonpath='{.spec.host}')"
echo "Loading the National Parks dataset..."
curl -sk --max-time 300 "https://${NP_HOST}/ws/data/load"
echo
curl -skL --max-time 60 "https://${NP_HOST}/ws/info"
echo
echo
echo "Parksmap: https://$(${oc} get route parksmap -o jsonpath='{.spec.host}')"
echo "Nationalparks: https://${NP_HOST}/ws/data/all"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment