Find the Best Cosmetic Hospitals

Explore trusted cosmetic hospitals and make a confident choice for your transformation.

โ€œInvest in yourself โ€” your confidence is always worth it.โ€

Explore Cosmetic Hospitals

Start your journey today โ€” compare options in one place.

OpenShift Lab 9: Work with Databases in the OpenShift Web Console

Lab Goal

In this lab, you will deploy a PostgreSQL database on OpenShift Local using the OpenShift web console. You will create the database using modern OpenShift resources such as Deployment, Service, Secret, ConfigMap, and PersistentVolumeClaim.

This lab replaces the older MongoDB web-console lab that used an outdated MongoDB image, an ephemeral database template, hard-coded credentials, and DeploymentConfig. The new lab uses current OpenShift-friendly practices.

By the end of this lab, you will understand how an application or client pod connects to a database inside OpenShift using internal service discovery.


What You Will Learn

You will learn how to:

  1. Start OpenShift Local.
  2. Log in to the OpenShift web console.
  3. Create a new project.
  4. Create a PostgreSQL database using the web console.
  5. Store database credentials in a Secret.
  6. Store non-sensitive database configuration in a ConfigMap.
  7. Create persistent storage using a PersistentVolumeClaim.
  8. Expose the database internally using a Service.
  9. Deploy a database client pod.
  10. Connect to PostgreSQL from inside the OpenShift cluster.
  11. Create a table and insert test data.
  12. Verify that data survives a database pod restart.
  13. Validate everything using optional oc commands.
  14. Clean up the lab environment.

Lab Architecture

In this lab, you will create the following OpenShift resources:

ResourceNamePurpose
Projectlab9-db-web-consoleIsolated namespace for this lab
Secretpostgresql-secretStores database username, password, and database name
ConfigMappostgresql-configStores non-sensitive PostgreSQL settings
PersistentVolumeClaimpostgresql-dataProvides persistent database storage
DeploymentpostgresqlRuns the PostgreSQL database pod
ServicepostgresqlProvides stable internal DNS name for the database
Deploymentdb-clientRuns a client pod used to test database connectivity

Why This Lab Uses PostgreSQL Instead of the Old MongoDB Template

The older lab used an old MongoDB 3.6 template and an ephemeral database. That approach is not ideal for a current OpenShift student lab.

This replacement lab uses PostgreSQL because:

  1. PostgreSQL is commonly used in enterprise application environments.
  2. The database runs as a standard Kubernetes Deployment.
  3. Credentials are stored in a Secret.
  4. Non-sensitive settings are stored in a ConfigMap.
  5. Data is stored on a PersistentVolumeClaim.
  6. Students can clearly understand how applications connect to databases through internal Services.

Important Concept

A database should usually not be exposed publicly through an OpenShift Route.

In OpenShift:

ResourceUsed For
ServiceInternal communication inside the cluster
RouteExternal HTTP/HTTPS access to web applications

In this lab, PostgreSQL will only be available inside the OpenShift cluster through the internal service name:

postgresql

The database will not be exposed using a Route.


Part 1: Prerequisites

Required Tools

You need the following tools installed on your machine:

  1. OpenShift Local
  2. crc command
  3. oc command
  4. A browser
  5. At least 4 CPUs and enough memory available for OpenShift Local

Recommended OpenShift Local Configuration

OpenShift Local with the OpenShift preset requires a local single-node OpenShift cluster. For smooth lab work, use at least:

ResourceRecommended
CPU4 or more
Memory12 GB or more
Disk35 GB or more

Part 2: Start OpenShift Local

Open a terminal on your machine.

Check your OpenShift Local version:

crc version

Set the OpenShift preset:

crc config set preset openshift
Code language: JavaScript (javascript)

Run the setup command:

crc setup

Start OpenShift Local:

crc start

The start command may take several minutes.

When the cluster starts successfully, OpenShift Local prints login information for the web console and command line.

To view the credentials again, run:

crc console --credentials
Code language: JavaScript (javascript)

To open the web console, run:

crc console
Code language: JavaScript (javascript)

Part 3: Configure the oc CLI

OpenShift Local provides the oc CLI environment command.

Run:

crc oc-env

On Linux or macOS, apply the environment using:

eval $(crc oc-env)
Code language: JavaScript (javascript)

Now log in as the developer user.

Use the password shown by:

crc console --credentials
Code language: JavaScript (javascript)

Login command:

oc login -u developer https://api.crc.testing:6443
Code language: JavaScript (javascript)

Verify login:

oc whoami

Expected output:

developer

Check the cluster:

oc get nodes
Code language: JavaScript (javascript)

Expected result:

NAME                 STATUS   ROLES                         AGE   VERSION
crc-xxxxx-master-0   Ready    control-plane,master,worker    ...

The exact node name and version may be different.


Part 4: Create a New Project from the Web Console

  1. Open the OpenShift web console.
  2. Log in as:
Username: developer
Password: Use the password from crc console --credentials
Code language: JavaScript (javascript)
  1. Switch to the Developer perspective.
  2. Click Project dropdown.
  3. Click Create Project.
  4. Enter the following project name:
lab9-db-web-console
Code language: JavaScript (javascript)
  1. Click Create.

You now have a separate OpenShift project for this lab.


Part 5: Create Database Resources Using Import YAML

In the OpenShift web console:

  1. Make sure you are in the project:
lab9-db-web-console
Code language: JavaScript (javascript)
  1. Go to +Add.
  2. Choose Import YAML.
  3. Paste the full YAML below.
  4. Click Create.

YAML: PostgreSQL Database, Secret, ConfigMap, PVC, Service, and Client Pod

apiVersion: v1
kind: Secret
metadata:
  name: postgresql-secret
  labels:
    app.kubernetes.io/name: postgresql
    app.kubernetes.io/part-of: lab9-database-demo
type: Opaque
stringData:
  POSTGRESQL_USER: appuser
  POSTGRESQL_PASSWORD: ChangeMeLab9!
  POSTGRESQL_DATABASE: appdb
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: postgresql-config
  labels:
    app.kubernetes.io/name: postgresql
    app.kubernetes.io/part-of: lab9-database-demo
data:
  POSTGRESQL_MAX_CONNECTIONS: "50"
  POSTGRESQL_SHARED_BUFFERS: "64MB"
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: postgresql-data
  labels:
    app.kubernetes.io/name: postgresql
    app.kubernetes.io/part-of: lab9-database-demo
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: postgresql
  labels:
    app: postgresql
    app.kubernetes.io/name: postgresql
    app.kubernetes.io/part-of: lab9-database-demo
spec:
  replicas: 1
  selector:
    matchLabels:
      app: postgresql
  strategy:
    type: Recreate
  template:
    metadata:
      labels:
        app: postgresql
        app.kubernetes.io/name: postgresql
        app.kubernetes.io/part-of: lab9-database-demo
    spec:
      terminationGracePeriodSeconds: 30
      containers:
        - name: postgresql
          image: registry.redhat.io/rhel9/postgresql-15:latest
          imagePullPolicy: IfNotPresent
          ports:
            - name: postgresql
              containerPort: 5432
              protocol: TCP
          env:
            - name: POSTGRESQL_USER
              valueFrom:
                secretKeyRef:
                  name: postgresql-secret
                  key: POSTGRESQL_USER
            - name: POSTGRESQL_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: postgresql-secret
                  key: POSTGRESQL_PASSWORD
            - name: POSTGRESQL_DATABASE
              valueFrom:
                secretKeyRef:
                  name: postgresql-secret
                  key: POSTGRESQL_DATABASE
            - name: POSTGRESQL_MAX_CONNECTIONS
              valueFrom:
                configMapKeyRef:
                  name: postgresql-config
                  key: POSTGRESQL_MAX_CONNECTIONS
            - name: POSTGRESQL_SHARED_BUFFERS
              valueFrom:
                configMapKeyRef:
                  name: postgresql-config
                  key: POSTGRESQL_SHARED_BUFFERS
            - name: POSTGRESQL_LOG_DESTINATION
              value: /dev/stderr
          resources:
            requests:
              cpu: 100m
              memory: 256Mi
            limits:
              cpu: 500m
              memory: 768Mi
          readinessProbe:
            tcpSocket:
              port: 5432
            initialDelaySeconds: 10
            periodSeconds: 10
            timeoutSeconds: 2
          livenessProbe:
            tcpSocket:
              port: 5432
            initialDelaySeconds: 30
            periodSeconds: 20
            timeoutSeconds: 2
          securityContext:
            allowPrivilegeEscalation: false
            capabilities:
              drop:
                - ALL
          volumeMounts:
            - name: postgresql-data
              mountPath: /var/lib/pgsql/data
      volumes:
        - name: postgresql-data
          persistentVolumeClaim:
            claimName: postgresql-data
---
apiVersion: v1
kind: Service
metadata:
  name: postgresql
  labels:
    app: postgresql
    app.kubernetes.io/name: postgresql
    app.kubernetes.io/part-of: lab9-database-demo
spec:
  type: ClusterIP
  selector:
    app: postgresql
  ports:
    - name: postgresql
      protocol: TCP
      port: 5432
      targetPort: 5432
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: db-client
  labels:
    app: db-client
    app.kubernetes.io/name: db-client
    app.kubernetes.io/part-of: lab9-database-demo
spec:
  replicas: 1
  selector:
    matchLabels:
      app: db-client
  template:
    metadata:
      labels:
        app: db-client
        app.kubernetes.io/name: db-client
        app.kubernetes.io/part-of: lab9-database-demo
    spec:
      containers:
        - name: db-client
          image: registry.redhat.io/rhel9/postgresql-15:latest
          imagePullPolicy: IfNotPresent
          command:
            - /bin/bash
            - -c
          args:
            - echo "db-client is ready"; while true; do sleep 3600; done
          env:
            - name: PGHOST
              value: postgresql
            - name: PGPORT
              value: "5432"
            - name: PGDATABASE
              valueFrom:
                secretKeyRef:
                  name: postgresql-secret
                  key: POSTGRESQL_DATABASE
            - name: PGUSER
              valueFrom:
                secretKeyRef:
                  name: postgresql-secret
                  key: POSTGRESQL_USER
            - name: PGPASSWORD
              valueFrom:
                secretKeyRef:
                  name: postgresql-secret
                  key: POSTGRESQL_PASSWORD
          resources:
            requests:
              cpu: 50m
              memory: 128Mi
            limits:
              cpu: 250m
              memory: 256Mi
          securityContext:
            allowPrivilegeEscalation: false
            capabilities:
              drop:
                - ALL
Code language: JavaScript (javascript)

Part 6: Understand the YAML

1. Secret

kind: Secret
metadata:
  name: postgresql-secret

The Secret stores sensitive database values:

POSTGRESQL_USER
POSTGRESQL_PASSWORD
POSTGRESQL_DATABASE

The PostgreSQL pod uses these values when the database is initialized.

The client pod also uses these values to connect to the database.

In real projects, never hard-code production passwords in YAML files committed to Git.

For production, use a secret management approach such as:

  1. External Secrets Operator
  2. HashiCorp Vault
  3. AWS Secrets Manager
  4. Azure Key Vault
  5. Google Secret Manager
  6. Sealed Secrets
  7. GitOps secret encryption tools

For this beginner lab, the password is visible so students can understand the workflow.


2. ConfigMap

kind: ConfigMap
metadata:
  name: postgresql-config

The ConfigMap stores non-sensitive settings:

POSTGRESQL_MAX_CONNECTIONS
POSTGRESQL_SHARED_BUFFERS

Use ConfigMaps for application configuration that is not secret.

Examples:

APP_MODE=dev
LOG_LEVEL=debug
DATABASE_HOST=postgresql
DATABASE_PORT=5432

Do not store passwords, tokens, or private keys in ConfigMaps.


3. PersistentVolumeClaim

kind: PersistentVolumeClaim
metadata:
  name: postgresql-data

The PersistentVolumeClaim requests storage for the database.

The PostgreSQL database writes its data to:

/var/lib/pgsql/data
Code language: JavaScript (javascript)

That directory is backed by the PVC.

This means the data can survive a pod restart or pod recreation.


4. PostgreSQL Deployment

kind: Deployment
metadata:
  name: postgresql

The Deployment creates and manages the PostgreSQL pod.

The lab uses:

strategy:
  type: Recreate

This is useful for a single-instance database because the old pod is stopped before a new pod is started.


5. PostgreSQL Service

kind: Service
metadata:
  name: postgresql

The Service provides a stable internal name for the database.

Other pods in the same project can connect to PostgreSQL using:

postgresql:5432
Code language: CSS (css)

The client pod uses:

PGHOST=postgresql

This is OpenShift/Kubernetes service discovery.


6. DB Client Deployment

kind: Deployment
metadata:
  name: db-client

The db-client pod is a test pod. It is not the database. It is used to test database connectivity from inside the cluster.

The client pod has PostgreSQL client tools available, including:

psql

You will use this pod to connect to the PostgreSQL Service.


Part 7: Verify Resources in the Web Console

After clicking Create, go to:

Developer perspective > Topology

You should see two workloads:

postgresql
db-client

Click the postgresql workload.

Check:

  1. Pod status
  2. Deployment status
  3. Service
  4. Logs
  5. Events

The PostgreSQL pod should eventually show as running.

Click the db-client workload.

Check that its pod is also running.


Part 8: Verify Resources Using CLI

Run:

oc project lab9-db-web-console
Code language: JavaScript (javascript)

List all major resources:

oc get deploy,po,svc,pvc,secret,cm
Code language: JavaScript (javascript)

Expected resources:

deployment.apps/postgresql
deployment.apps/db-client

pod/postgresql-xxxxx
pod/db-client-xxxxx

service/postgresql

persistentvolumeclaim/postgresql-data

secret/postgresql-secret

configmap/postgresql-config

Check rollout status:

oc rollout status deployment/postgresql

Expected output:

deployment "postgresql" successfully rolled out
Code language: JavaScript (javascript)

Check client rollout:

oc rollout status deployment/db-client

Expected output:

deployment "db-client" successfully rolled out
Code language: JavaScript (javascript)

Check the PVC:

oc get pvc postgresql-data
Code language: JavaScript (javascript)

Expected output:

NAME              STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS
postgresql-data   Bound    pvc-xxxxxx                                  1Gi        RWO            ...

The STATUS should be:

Bound

Part 9: Check PostgreSQL Logs

From the web console:

  1. Go to Developer perspective.
  2. Open Topology.
  3. Click postgresql.
  4. Click the pod.
  5. Open the Logs tab.

Or use CLI:

oc logs deployment/postgresql

You should see PostgreSQL initialization and startup messages.

The exact log output may vary, but it should indicate that PostgreSQL started successfully.


Part 10: Connect to PostgreSQL from the Web Console Terminal

Now connect to the database from inside the OpenShift cluster.

In the web console:

  1. Go to Developer perspective.
  2. Open Topology.
  3. Click db-client.
  4. Open the running pod.
  5. Click the Terminal tab.

Inside the terminal, run:

psql -h "$PGHOST" -U "$PGUSER" -d "$PGDATABASE" -c "SELECT version();"
Code language: JavaScript (javascript)

Expected output should include PostgreSQL version information.

Example:

PostgreSQL 15.x
Code language: CSS (css)

Now check the current database and current user:

psql -h "$PGHOST" -U "$PGUSER" -d "$PGDATABASE" -c "SELECT current_database(), current_user;"
Code language: JavaScript (javascript)

Expected output:

 current_database | current_user
------------------+--------------
 appdb            | appuser

This confirms that the client pod can connect to the PostgreSQL database using the internal service name.


Part 11: Create a Table and Insert Data

From the db-client pod terminal, run:

psql -h "$PGHOST" -U "$PGUSER" -d "$PGDATABASE"
Code language: JavaScript (javascript)

You should now be inside the PostgreSQL shell.

You will see a prompt similar to:

appdb=>
Code language: PHP (php)

Create a table:

CREATE TABLE IF NOT EXISTS lab9_messages (
  id SERIAL PRIMARY KEY,
  student_name TEXT NOT NULL,
  message TEXT NOT NULL,
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
Code language: PHP (php)

Insert a row:

INSERT INTO lab9_messages(student_name, message)
VALUES ('student01', 'Hello from OpenShift Local Lab 9');
Code language: JavaScript (javascript)

Query the table:

SELECT id, student_name, message, created_at
FROM lab9_messages
ORDER BY id DESC
LIMIT 5;

Expected output:

 id | student_name |              message               |         created_at
----+--------------+------------------------------------+----------------------------
  1 | student01    | Hello from OpenShift Local Lab 9   | ...
Code language: JavaScript (javascript)

Exit PostgreSQL:

\q

Part 12: One-Line SQL Test Alternative

If copy-paste into the PostgreSQL shell is difficult, run the following one-line commands from the db-client pod terminal.

Create the table:

psql -h "$PGHOST" -U "$PGUSER" -d "$PGDATABASE" -c "CREATE TABLE IF NOT EXISTS lab9_messages (id SERIAL PRIMARY KEY, student_name TEXT NOT NULL, message TEXT NOT NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP);"
Code language: JavaScript (javascript)

Insert a row:

psql -h "$PGHOST" -U "$PGUSER" -d "$PGDATABASE" -c "INSERT INTO lab9_messages(student_name, message) VALUES ('student01', 'Hello from OpenShift Local Lab 9');"
Code language: JavaScript (javascript)

Query rows:

psql -h "$PGHOST" -U "$PGUSER" -d "$PGDATABASE" -c "SELECT id, student_name, message, created_at FROM lab9_messages ORDER BY id DESC LIMIT 5;"
Code language: JavaScript (javascript)

Part 13: Verify Database Connectivity Using CLI

You can also run the SQL test from your local terminal using oc exec.

First, find the db-client pod:

oc get pods -l app=db-client
Code language: JavaScript (javascript)

Store the pod name in a variable:

DB_CLIENT_POD=$(oc get pod -l app=db-client -o jsonpath='{.items[0].metadata.name}')
Code language: PHP (php)

Run a database query:

oc exec "$DB_CLIENT_POD" -- bash -lc 'psql -h "$PGHOST" -U "$PGUSER" -d "$PGDATABASE" -c "SELECT current_database(), current_user;"'
Code language: JavaScript (javascript)

Expected output:

 current_database | current_user
------------------+--------------
 appdb            | appuser

Create the table:

oc exec "$DB_CLIENT_POD" -- bash -lc 'psql -h "$PGHOST" -U "$PGUSER" -d "$PGDATABASE" -c "CREATE TABLE IF NOT EXISTS lab9_messages (id SERIAL PRIMARY KEY, student_name TEXT NOT NULL, message TEXT NOT NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP);"'
Code language: JavaScript (javascript)

Insert a row:

oc exec "$DB_CLIENT_POD" -- bash -lc 'psql -h "$PGHOST" -U "$PGUSER" -d "$PGDATABASE" -c "INSERT INTO lab9_messages(student_name, message) VALUES ('cli-user', 'Inserted using oc exec from local terminal');"'
Code language: JavaScript (javascript)

Query the table:

oc exec "$DB_CLIENT_POD" -- bash -lc 'psql -h "$PGHOST" -U "$PGUSER" -d "$PGDATABASE" -c "SELECT id, student_name, message, created_at FROM lab9_messages ORDER BY id DESC LIMIT 5;"'
Code language: JavaScript (javascript)

Part 14: Prove That the Service Name Works

The database client connects to:

postgresql

This name comes from the OpenShift Service:

kind: Service
metadata:
  name: postgresql

Inside the same OpenShift project, pods can reach the database using:

postgresql:5432
Code language: CSS (css)

To inspect the service, run:

oc describe service postgresql

You should see:

Name:              postgresql
Type:              ClusterIP
Port:              postgresql  5432/TCP
Endpoints:         ...
Code language: HTTP (http)

The Endpoints field should point to the PostgreSQL pod IP and port.


Part 15: Prove That Data Persists After Pod Restart

A database should not lose data just because the pod restarts.

In this lab, data is stored on the PersistentVolumeClaim named:

postgresql-data

Option A: Restart from Web Console

  1. Go to Developer perspective.
  2. Open Topology.
  3. Click the postgresql workload.
  4. Open the Deployment.
  5. Scale the Deployment to 0.
  6. Wait until the PostgreSQL pod disappears.
  7. Scale the Deployment back to 1.
  8. Wait until the new pod is running.

Now go back to the db-client pod terminal and run:

psql -h "$PGHOST" -U "$PGUSER" -d "$PGDATABASE" -c "SELECT id, student_name, message, created_at FROM lab9_messages ORDER BY id DESC LIMIT 5;"
Code language: JavaScript (javascript)

Your previously inserted row should still exist.


Option B: Restart from CLI

Scale PostgreSQL down:

oc scale deployment/postgresql --replicas=0

Wait:

oc get pods -l app=postgresql
Code language: JavaScript (javascript)

Scale PostgreSQL back up:

oc scale deployment/postgresql --replicas=1

Wait for rollout:

oc rollout status deployment/postgresql

Query the data again:

oc exec "$DB_CLIENT_POD" -- bash -lc 'psql -h "$PGHOST" -U "$PGUSER" -d "$PGDATABASE" -c "SELECT id, student_name, message, created_at FROM lab9_messages ORDER BY id DESC LIMIT 5;"'
Code language: JavaScript (javascript)

If the data is still visible, persistence is working.


Part 16: Check That No Route Was Created

A PostgreSQL database should usually remain internal to the cluster.

Check routes:

oc get route
Code language: JavaScript (javascript)

Expected output:

No resources found in lab9-db-web-console namespace.
Code language: JavaScript (javascript)

This is correct.

The database is reachable inside OpenShift using the Service:

postgresql:5432
Code language: CSS (css)

It is not exposed outside the cluster.


Part 17: Student Checkpoint

At this point, students should be able to answer:

QuestionExpected Answer
What stores the database password?Secret
What stores non-sensitive database settings?ConfigMap
What gives the database a stable internal name?Service
What stores database files?PersistentVolumeClaim
What runs the PostgreSQL container?Deployment
What is the internal database hostname?postgresql
What is the PostgreSQL port?5432
Should the database have an external Route?No

Part 18: Full CLI Validation Script

Run the following commands from your local terminal after logging in with oc.

oc project lab9-db-web-console

echo "Checking deployments..."
oc get deployment

echo "Checking pods..."
oc get pods -o wide

echo "Checking service..."
oc get svc postgresql

echo "Checking PVC..."
oc get pvc postgresql-data

echo "Checking Secret and ConfigMap..."
oc get secret postgresql-secret
oc get configmap postgresql-config

echo "Checking PostgreSQL rollout..."
oc rollout status deployment/postgresql

echo "Checking db-client rollout..."
oc rollout status deployment/db-client

echo "Finding db-client pod..."
DB_CLIENT_POD=$(oc get pod -l app=db-client -o jsonpath='{.items[0].metadata.name}')
echo "DB client pod: $DB_CLIENT_POD"

echo "Running PostgreSQL connectivity test..."
oc exec "$DB_CLIENT_POD" -- bash -lc 'psql -h "$PGHOST" -U "$PGUSER" -d "$PGDATABASE" -c "SELECT current_database(), current_user;"'

echo "Checking existing lab table..."
oc exec "$DB_CLIENT_POD" -- bash -lc 'psql -h "$PGHOST" -U "$PGUSER" -d "$PGDATABASE" -c "SELECT COUNT(*) FROM lab9_messages;"'
Code language: PHP (php)

Expected result:

  1. Both Deployments should be available.
  2. Both pods should be running.
  3. The Service should exist.
  4. The PVC should be Bound.
  5. The PostgreSQL query should return appdb and appuser.

Part 19: Troubleshooting

Problem 1: PostgreSQL Pod Shows ImagePullBackOff

Check the pod:

oc get pods
Code language: JavaScript (javascript)

Describe the pod:

oc describe pod -l app=postgresql

Check events:

oc get events --sort-by=.lastTimestamp
Code language: JavaScript (javascript)

Possible causes:

  1. Red Hat registry pull secret issue.
  2. Network issue.
  3. Image name or tag not available in your environment.

Possible fix for a classroom lab:

Edit the Deployment image from:

registry.redhat.io/rhel9/postgresql-15:latest

to:

registry.access.redhat.com/rhel9/postgresql-15:latest

Then save and wait for the pod to restart.


Problem 2: PVC Is Pending

Check the PVC:

oc get pvc
Code language: JavaScript (javascript)

Describe the PVC:

oc describe pvc postgresql-data

Check storage classes:

oc get storageclass
Code language: JavaScript (javascript)

Possible causes:

  1. No default StorageClass.
  2. OpenShift Local storage is not ready.
  3. Cluster is still starting.

In OpenShift Local, wait a few minutes and check again.

If there is no default StorageClass, ask the instructor to verify the OpenShift Local setup.


Problem 3: PostgreSQL Pod Is CrashLoopBackOff

Check logs:

oc logs deployment/postgresql

Check previous logs:

oc logs deployment/postgresql --previous

Common causes:

  1. Wrong environment variable names.
  2. Invalid database initialization.
  3. PVC already contains old incompatible data.
  4. Password changed after the database was already initialized.

For a lab reset, delete and recreate the project:

oc delete project lab9-db-web-console
Code language: JavaScript (javascript)

Then create the project again and reapply the YAML.


Problem 4: Password Authentication Failed

If you changed the Secret after PostgreSQL was already initialized, the database password inside the persistent data directory may not change automatically.

For this beginner lab, the simplest reset is:

oc delete project lab9-db-web-console
Code language: JavaScript (javascript)

Then recreate the project and apply the YAML again.

In production, password rotation requires a planned database credential rotation process.


Problem 5: psql Command Not Found

Make sure you are running the command inside the db-client pod, not your laptop terminal.

From CLI:

DB_CLIENT_POD=$(oc get pod -l app=db-client -o jsonpath='{.items[0].metadata.name}')
oc exec -it "$DB_CLIENT_POD" -- bash
Code language: PHP (php)

Then run:

psql --version

Problem 6: No Route Found

This is expected.

Run:

oc get route
Code language: JavaScript (javascript)

Expected output:

No resources found

PostgreSQL is not an HTTP web application. It should normally be accessed internally through a Service, not exposed externally through a Route.


Part 20: Cleanup

To delete all resources created in this lab, delete the project.

From the web console:

  1. Switch to Administrator perspective.
  2. Go to Home > Projects.
  3. Find:
lab9-db-web-console
Code language: JavaScript (javascript)
  1. Delete the project.

Or use CLI:

oc delete project lab9-db-web-console
Code language: JavaScript (javascript)

Verify:

oc get project lab9-db-web-console
Code language: JavaScript (javascript)

The project should no longer exist.


Part 21: Lab Summary

In this lab, you created a database-backed OpenShift environment using the web console.

You created:

ResourcePurpose
SecretStored database credentials
ConfigMapStored non-sensitive database configuration
PersistentVolumeClaimStored database data persistently
DeploymentRan the PostgreSQL database
ServiceProvided internal DNS name for PostgreSQL
Client DeploymentTested database connectivity

You verified that:

  1. PostgreSQL runs inside OpenShift.
  2. The database is reachable by service name.
  3. Credentials can be injected from a Secret.
  4. Non-sensitive settings can be injected from a ConfigMap.
  5. Database data persists after pod restart.
  6. The database does not need an external Route.

Part 22: Lab Review Questions

Question 1

What is the purpose of a Secret in this lab?

Answer

A Secret stores sensitive data such as the database username, password, and database name.


Question 2

What is the purpose of a ConfigMap in this lab?

Answer

A ConfigMap stores non-sensitive configuration such as database tuning values or application settings.


Question 3

Why do we use a PersistentVolumeClaim?

Answer

A PersistentVolumeClaim provides persistent storage so database data is not lost when the pod restarts.


Question 4

Why does PostgreSQL use a Service?

Answer

The Service provides a stable internal DNS name and port for other pods to connect to PostgreSQL.


Question 5

Why did we not create a Route for PostgreSQL?

Answer

A Route is mainly used to expose HTTP or HTTPS applications outside the cluster. PostgreSQL is a database service and should normally remain internal to the cluster.


Question 6

What hostname does the client pod use to connect to PostgreSQL?

Answer

postgresql

Question 7

What port does PostgreSQL listen on?

Answer

5432

Question 8

Which resource runs the PostgreSQL container?

Answer

Deployment.


Question 9

Which resource stores the PostgreSQL data files?

Answer

PersistentVolumeClaim.


Question 10

What command can you use to verify the PostgreSQL pod logs?

Answer

oc logs deployment/postgresql

Part 23: Instructor Notes

This lab is designed as a replacement for older OpenShift database labs that used deprecated or outdated patterns.

The lab intentionally avoids:

  1. MongoDB 3.6
  2. DeploymentConfig
  3. Ephemeral-only database storage
  4. Hard-coded database URLs in application configuration
  5. Exposing a database using a Route
  6. Old OpenShift template-based database provisioning

The lab teaches current OpenShift concepts:

  1. Deployment
  2. Service
  3. Secret
  4. ConfigMap
  5. PersistentVolumeClaim
  6. Internal service discovery
  7. Pod terminal access
  8. CLI validation with oc exec

For production environments, students should also learn:

  1. StatefulSet for production-grade stateful workloads
  2. Database Operators
  3. Automated backup and restore
  4. Monitoring and alerting
  5. Secret rotation
  6. TLS for database connections
  7. NetworkPolicy
  8. Resource sizing
  9. High availability
  10. Disaster recovery

This lab is intentionally simple because it is focused on beginner-level OpenShift database fundamentals using the web console.


Part 24: Instructor Validation Checklist

Before giving this lab to students, the instructor should run:

crc version
crc status
oc version
oc whoami
oc get nodes
oc get storageclass
Code language: JavaScript (javascript)

Then apply the lab and validate:

oc project lab9-db-web-console
oc get deploy,po,svc,pvc,secret,cm
oc rollout status deployment/postgresql
oc rollout status deployment/db-client
oc logs deployment/postgresql
Code language: JavaScript (javascript)

Then run:

DB_CLIENT_POD=$(oc get pod -l app=db-client -o jsonpath='{.items[0].metadata.name}')

oc exec "$DB_CLIENT_POD" -- bash -lc 'psql -h "$PGHOST" -U "$PGUSER" -d "$PGDATABASE" -c "SELECT version();"'

oc exec "$DB_CLIENT_POD" -- bash -lc 'psql -h "$PGHOST" -U "$PGUSER" -d "$PGDATABASE" -c "SELECT current_database(), current_user;"'
Code language: PHP (php)

If these commands pass, the lab is ready for students.


Final Outcome

You have successfully completed the updated OpenShift Lab 9.

You deployed a PostgreSQL database using the OpenShift web console, configured it using Secret and ConfigMap, stored its data on a PersistentVolumeClaim, exposed it internally using a Service, and tested database connectivity from another pod inside the cluster.

Find Trusted Cardiac Hospitals

Compare heart hospitals by city and services โ€” all in one place.

Explore Hospitals
Iโ€™m a DevOps/SRE/DevSecOps/Cloud Expert passionate about sharing knowledge and experiences. I have worked at <a href="https://www.cotocus.com/">Cotocus</a>. I share tech blog at <a href="https://www.devopsschool.com/">DevOps School</a>, travel stories at <a href="https://www.holidaylandmark.com/">Holiday Landmark</a>, stock market tips at <a href="https://www.stocksmantra.in/">Stocks Mantra</a>, health and fitness guidance at <a href="https://www.mymedicplus.com/">My Medic Plus</a>, product reviews at <a href="https://www.truereviewnow.com/">TrueReviewNow</a> , and SEO strategies at <a href="https://www.wizbrand.com/">Wizbrand.</a> Do you want to learn <a href="https://www.quantumuting.com/">Quantum Computing</a>? <strong>Please find my social handles as below;</strong> <a href="https://www.rajeshkumar.xyz/">Rajesh Kumar Personal Website</a> <a href="https://www.youtube.com/TheDevOpsSchool">Rajesh Kumar at YOUTUBE</a> <a href="https://www.instagram.com/rajeshkumarin">Rajesh Kumar at INSTAGRAM</a> <a href="https://x.com/RajeshKumarIn">Rajesh Kumar at X</a> <a href="https://www.facebook.com/RajeshKumarLog">Rajesh Kumar at FACEBOOK</a> <a href="https://www.linkedin.com/in/rajeshkumarin/">Rajesh Kumar at LINKEDIN</a> <a href="https://www.wizbrand.com/rajeshkumar">Rajesh Kumar at WIZBRAND</a> <a href="https://www.rajeshkumar.xyz/dailylogs">Rajesh Kumar DailyLogs</a>

Related Posts

OpenShift Tutorial โ€“ Deploy and Access Your First Applications using OpenShift Local

How to install oc? OpenShift: How to Install OpenShift CLI oc How to login? Login to the Openshift using Web Console and CLI using oc Copy the admin…

Read More

OpenShift Lab 14: Setting Up and Using OpenShift Serverless Functions on OpenShift Local

Lab Objective In this lab, you will install and use OpenShift Serverless Functions on OpenShift Local. You will create a simple Node.js serverless function, deploy it to…

Read More

OpenShift Lab 13: Deploy a Java Spring Boot Application with MySQL Using the OpenShift Web Console

Lab Objective In this lab, you will deploy a Java Spring Boot application on OpenShift using the OpenShift web console. You will deploy two components: The Java…

Read More

OpenShift Lab 12: Deploy an Application from an Existing Container Image Using the OpenShift Web Console

Lab Objective In this lab, you will deploy an application on OpenShift from an existing container image. This lab is different from building an application from source…

Read More

OpenShift: How to Install OpenShift CLIย oc

Option – 1 – REDHAT Websites URL – https://access.redhat.com/downloads/content/290/ver=4.18/rhel—9/4.18.11/x86_64/product-software Option – 2 – OKD Websites The OKD (Origin Community Distribution of Kubernetes for OpenShift) is the open-source…

Read More

OpenShift Lab 11: Build and Deploy an Application from Source Code Using the OpenShift Web Console

Lab Objective In this lab, you will build and deploy a web application from source code stored in a Git repository using the OpenShift web console. You…

Read More
Subscribe
Notify of
guest
1 Comment
Newest
Oldest Most Voted
Skylar Bennett
Skylar Bennett
8 days ago

The lab demonstrates how to work with databases through the OpenShift web console, but it could also address operational concerns that become important beyond a learning environment. Topics such as persistent storage selection, backup and recovery strategies, secret rotation, and database upgrades are critical for running stateful workloads reliably. It would also be helpful to discuss monitoring database health, tracking resource consumption, and planning for high availability to ensure applications remain resilient as usage grows.

1
0
Would love your thoughts, please comment.x
()
x