> ## Documentation Index
> Fetch the complete documentation index at: https://notes.kodekloud.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Demo Create Custom Catalog

> Guide to package the Example Voting App into an OpenShift Template and add it to the cluster catalog for reusable, parameterized deployments

Welcome — this guide shows how to package the Example Voting Application into a reusable OpenShift Template and add it to the cluster catalog. After following these steps, other developers can deploy the full voting stack (builds, images, deployments, services, and routes) through the catalog UI in just a few clicks.

What you'll accomplish

* Identify and collect all Kubernetes/OpenShift objects required by the app (Secrets, ImageStreams, BuildConfigs, DeploymentConfigs, Services, Routes).
* Consolidate and clean each object's YAML into a single Template file.
* Create the Template in your project (CLI or console).
* Deploy and test the Template from the catalog.

Plan

* Inspect resources in the project and copy their YAML definitions.
* Remove runtime fields (status, creationTimestamp, resourceVersion, selfLink, uid, labels that are not required).
* Replace base64-encoded secrets with `stringData` for readability (you can parameterize later).
* Add `parameters` to the Template for reusability (Git repo, tags, passwords, namespace).
* Create the Template and verify via Builds/Pods/Routes.

Create the template file
Create a file named `example-voting-app-template.yml`.

<Frame>
  <img src="https://mintcdn.com/kodekloud-c4ac6d9a/EeHAFJo7ohYv6ASi/images/OpenShift-3-for-the-Absolute-Beginners/Storage-Templates-and-Catalog/Demo-Create-Custom-Catalog/new-file-dialog-example-voting-app.jpg?fit=max&auto=format&n=EeHAFJo7ohYv6ASi&q=85&s=5b9888939c151e14187d0048609955e1" alt="A dark IDE screen showing a &#x22;New File&#x22; dialog box with an input field containing &#x22;example-voting-app-templa&#x22; and OK/Cancel buttons. The background also displays the prompt &#x22;Search Everywhere Double Shift.&#x22;" width="1920" height="1080" data-path="images/OpenShift-3-for-the-Absolute-Beginners/Storage-Templates-and-Catalog/Demo-Create-Custom-Catalog/new-file-dialog-example-voting-app.jpg" />
</Frame>

Start the file with the Template header and an `objects` array that will contain all resources:

```yaml theme={null}
apiVersion: v1
kind: Template
metadata:
  name: example-voting-app-template
objects:
# objects go here, each item prefixed with '-'
```

Important: a Template must include every resource required to deploy the application — BuildConfigs, DeploymentConfigs, Services, Routes, ImageStreams, Secrets, etc.

Key resources and a quick reference

| Resource Type | Purpose | Example / Notes |
| - | - | - |
| Secret | Store credentials/config for DB, Redis | Use `stringData` for clear-text values in templates |
| ImageStream | Local image name in OpenShift | Minimal `spec.lookupPolicy` is sufficient |
| BuildConfig | Source-to-image build definitions | Keep `spec.source`, `contextDir`, `strategy`, and `output` |
| DeploymentConfig | Pod template, env, probes, replicas | Keep `spec.template.spec.containers` with `env` from secrets |
| Service | Internal network access to pods | ClusterIP for internal communication |
| Route | External access to services | Configure `tls` and `targetPort` where needed |

Secrets
Start the Template with Secrets so other objects can reference them. In the OpenShift Console go to Resources → Secrets, select the DB and Redis secrets and choose "Edit YAML" to copy. Remove fields like `creationTimestamp`, `resourceVersion`, `selfLink`, `uid`, and unnecessary labels. Use `stringData` to provide readable values; OpenShift converts them to base64 when creating the Secret.

Example cleaned DB Secret:

```yaml theme={null}
- apiVersion: v1
  kind: Secret
  metadata:
    name: db
  stringData:
    database-name: postgres
    database-user: postgres_user
    database-password: postgres_password
  type: Opaque
```

Example cleaned Redis Secret:

```yaml theme={null}
- apiVersion: v1
  kind: Secret
  metadata:
    name: redis
  stringData:
    redis-password: redis_password
  type: Opaque
```

Note: these values should be parameterized later so catalog users can provide secure values via the catalog wizard.

BuildConfigs
Collect and clean each BuildConfig in the project. Keep `spec.source` (git URI and `contextDir`), `spec.strategy`, `spec.output`, and `spec.triggers`. Remove the `status` section and other runtime metadata. You can initially hard-code the repository URL and later move it to Template `parameters`.

Example BuildConfig for `result`:

```yaml theme={null}
- apiVersion: build.openshift.io/v1
  kind: BuildConfig
  metadata:
    name: result
  spec:
    runPolicy: Serial
    source:
      type: Git
      git:
        uri: "https://github.com/mmumshad/example-voting-app.git"
        ref: master
      contextDir: /result
    strategy:
      type: Source
      sourceStrategy:
        from:
          kind: ImageStreamTag
          name: "nodejs:8"
          namespace: openshift
        env:
          - name: PORT
            value: "8080"
    output:
      to:
        kind: ImageStreamTag
        name: "result:latest"
    triggers:
      - type: Generic
        generic:
          secret: "5a7ae0b1e2c90cbc"
      - type: GitHub
        github:
          secret: "7832f312c9c2e7f1"
      - type: ImageChange
```

Repeat the same cleanup for the `vote` and `worker` BuildConfigs.

ImageStreams
Add minimal ImageStream objects (one per application image). Keep only essential `metadata.name` and `spec.lookupPolicy`:

```yaml theme={null}
- apiVersion: image.openshift.io/v1
  kind: ImageStream
  metadata:
    name: result
  spec:
    lookupPolicy:
      local: false

- apiVersion: image.openshift.io/v1
  kind: ImageStream
  metadata:
    name: vote
  spec:
    lookupPolicy:
      local: false

- apiVersion: image.openshift.io/v1
  kind: ImageStream
  metadata:
    name: worker
  spec:
    lookupPolicy:
      local: false
```

If you build or push images manually into the internal registry, example docker commands:

```bash theme={null}
$ sudo docker tag myimage registry/voting-application/worker:tag
$ sudo docker push registry/voting-application/worker:tag
```

DeploymentConfigs
Copy your DeploymentConfig YAML, then remove `status` and ephemeral metadata. Keep `spec.replicas`, `spec.selector`, and the `spec.template.spec.containers` definition (image, env, ports, probes). Reference secrets with `valueFrom.secretKeyRef` so the deployed pods pick up credentials from the Secrets added above.

Example DeploymentConfig for PostgreSQL (db):

```yaml theme={null}
- apiVersion: apps.openshift.io/v1
  kind: DeploymentConfig
  metadata:
    name: db
  spec:
    replicas: 1
    selector:
      deploymentconfig: db
    template:
      metadata:
        labels:
          deploymentconfig: db
      spec:
        containers:
          - name: postgresql
            image: "docker.io/centos/postgresql-96-centos7:latest"
            imagePullPolicy: IfNotPresent
            ports:
              - containerPort: 5432
            env:
              - name: POSTGRESQL_USER
                valueFrom:
                  secretKeyRef:
                    name: db
                    key: database-user
              - name: POSTGRESQL_PASSWORD
                valueFrom:
                  secretKeyRef:
                    name: db
                    key: database-password
              - name: POSTGRESQL_DATABASE
                valueFrom:
                  secretKeyRef:
                    name: db
                    key: database-name
            livenessProbe:
              exec:
                command:
                  - /bin/sh
                  - -c
                  - pg_isready -h 127.0.0.1 -p 5432
              initialDelaySeconds: 30
              periodSeconds: 10
```

Repeat similar cleanup for the application DeploymentConfigs (result, vote, worker, redis). Keep liveness/readiness probes, env vars, and ports. Remove `status` from copied YAML.

Services and Routes
Add Service objects for components that must be addressable inside the cluster. The worker may not need a Service unless another component connects to it — but including Services in the Template preserves expected topology.

Example Service for `worker`:

```yaml theme={null}
- apiVersion: v1
  kind: Service
  metadata:
    name: worker
  spec:
    ports:
      - name: http
        port: 8080
        protocol: TCP
        targetPort: 8080
      - name: https
        port: 8443
        protocol: TCP
        targetPort: 8443
    selector:
      deploymentconfig: worker
    type: ClusterIP
```

Add Services for `result`, `vote`, `db`, and `redis` as required by your app.

Create minimal Route objects for externally exposed services (one per app you want publicly accessible). Example Route for `vote`:

```yaml theme={null}
- apiVersion: route.openshift.io/v1
  kind: Route
  metadata:
    name: vote
  spec:
    to:
      kind: Service
      name: vote
    port:
      targetPort: 8080
    tls:
      termination: edge
```

Parameterize the Template
To make the Template reusable and friendly in the Catalog wizard, move configurable items into `parameters`. Typical parameters:

* Git repository URL and ref
* Image tags (e.g. `result:latest`)
* Secret values (`database-password`, `redis-password`)
* Target namespace/project (or avoid hard-coding namespace and let users deploy into current project)
* Resource sizes or replica counts

Example parameter snippet to add near the top of your Template:

```yaml theme={null}
parameters:
  - name: GIT_REPO
    description: "Git repository URL for the voting app"
    value: "https://github.com/mmumshad/example-voting-app.git"
  - name: GIT_REF
    description: "Git reference (branch or tag) to build"
    value: "master"
  - name: DB_PASSWORD
    description: "Database password"
    generate: expression
    from: "[a-zA-Z0-9]{16}"
```

Then reference parameters in object fields using `${PARAM_NAME}` substitution.

Creating the Template with oc (CLI)
After finalizing `example-voting-app-template.yml`, create the Template with `oc`. The example below demonstrates configuring `oc` via Minishift on Windows, logging in, and creating the Template in a project.

Add `oc` to PATH (example Minishift output):

```bash theme={null}
c:\minishift-1.16.1-windows-amd64>minishift.exe oc-env
SET PATH=C:\Users\mmums\.minishift\cache\oc\v3.9.0\windows;%PATH%
REM Run this command to configure your shell:
REM    @FOR /f "tokens=*" %i IN ('minishift oc-env') DO @call %i
```

Apply the environment change (Windows example):

```powershell theme={null}
C:\minishift-1.16.1-windows-amd64>SET PATH=C:\Users\mmums\.minishift\cache\oc\v3.9.0\windows;%PATH%
```

Important: if you try to create a Template in `default` without the right permissions, you'll see a forbidden error. Create the Template in a project where you have rights or specify `-n <project>`.

Example (insufficient privileges):

```text theme={null}
d:\...>oc create -f example-voting-app-template.yml
Error from server (Forbidden): error when creating "example-voting-app-template.yml": templates is forbidden: User "app-developer-2" cannot create templates in the namespace "default": User "app-developer-2" cannot create templates in project "default"
```

Create the Template in the target project (example: `voting-application-3`):

```bash theme={null}
d:\...>oc create -f example-voting-app-template.yml -n voting-application-3
template "example-voting-app-template" created
```

Using the template from the catalog
Refresh the OpenShift Console Catalog view. You should see a new catalog item called `example voting app template` (or the display name set in your Template's metadata/annotations). Click it and follow the wizard to deploy the application stack. During the wizard you can supply the parameter values you defined.

<Frame>
  <img src="https://mintcdn.com/kodekloud-c4ac6d9a/EeHAFJo7ohYv6ASi/images/OpenShift-3-for-the-Absolute-Beginners/Storage-Templates-and-Catalog/Demo-Create-Custom-Catalog/openshift-origin-voting-app-db-secret.jpg?fit=max&auto=format&n=EeHAFJo7ohYv6ASi&q=85&s=11ac03c72089dd97f8701197c96252d5" alt="A screenshot of the OpenShift Origin web console for the &#x22;Example Voting Application&#x22; showing a secret named &#x22;db&#x22; with database-name, database-password, and database-user values masked. The left navigation (Overview, Applications, Builds, Resources, etc.) is visible and there are &#x22;Add to Application&#x22; and &#x22;Actions&#x22; buttons on the page." width="1920" height="1080" data-path="images/OpenShift-3-for-the-Absolute-Beginners/Storage-Templates-and-Catalog/Demo-Create-Custom-Catalog/openshift-origin-voting-app-db-secret.jpg" />
</Frame>

Open the Monitoring / Overview page to watch pod creation and build progress. The Overview shows pods, builds, and overall application health so you can follow progress in real time.

<Frame>
  <img src="https://mintcdn.com/kodekloud-c4ac6d9a/EeHAFJo7ohYv6ASi/images/OpenShift-3-for-the-Absolute-Beginners/Storage-Templates-and-Catalog/Demo-Create-Custom-Catalog/openshift-origin-monitoring-voting-pods.jpg?fit=max&auto=format&n=EeHAFJo7ohYv6ASi&q=85&s=ae30e8f307c52997a1dc71b5b86cd20a" alt="A screenshot of the OpenShift Origin web console showing the Monitoring page for an &#x22;Example Voting Application,&#x22; listing pods and their statuses. The pod list includes entries like result-1, vote-1, db-1 and redis with statuses such as Running or Container Creating." width="1920" height="1080" data-path="images/OpenShift-3-for-the-Absolute-Beginners/Storage-Templates-and-Catalog/Demo-Create-Custom-Catalog/openshift-origin-monitoring-voting-pods.jpg" />
</Frame>

When builds complete and pods are Running, open Links → Routes to access the voting UI and the results page.

<Frame>
  <img src="https://mintcdn.com/kodekloud-c4ac6d9a/EeHAFJo7ohYv6ASi/images/OpenShift-3-for-the-Absolute-Beginners/Storage-Templates-and-Catalog/Demo-Create-Custom-Catalog/openshift-console-example-voting-services.jpg?fit=max&auto=format&n=EeHAFJo7ohYv6ASi&q=85&s=02763f33457fb3e9edc23da08d02e080" alt="A screenshot of the OpenShift Origin web console showing the &#x22;Services&#x22; page for an &#x22;Example Voting Application.&#x22; It lists services (worker, result, db, vote, redis) with their Cluster IPs, ports, selectors, and ages." width="1920" height="1080" data-path="images/OpenShift-3-for-the-Absolute-Beginners/Storage-Templates-and-Catalog/Demo-Create-Custom-Catalog/openshift-console-example-voting-services.jpg" />
</Frame>

Improve and maintain your Template

* Parameterize values (Git URLs, secrets, image tags, replica counts, namespace) and provide defaults and descriptions for a good catalog experience.
* Reuse parameter names and patterns from builtin OpenShift templates for consistency.
* Test the Template by creating from the catalog and by `oc create -f` locally.
* Keep sensitive defaults empty; require users to input credentials or generate them securely.

<Callout icon="lightbulb" color="#1CB2FE">
  Tip: Review existing OpenShift templates in the cluster (`oc get templates -n openshift`) to learn common parameter names and patterns you can reuse.
</Callout>

Links and references

* OpenShift Templates: [https://docs.openshift.com/](https://docs.openshift.com/)
* Kubernetes Concepts: [https://kubernetes.io/docs/concepts/overview/what-is-kubernetes/](https://kubernetes.io/docs/concepts/overview/what-is-kubernetes/)
* Example voting app repository: [https://github.com/mmumshad/example-voting-app](https://github.com/mmumshad/example-voting-app)

Thanks for following this demo — you now have the steps needed to package an application into a reusable OpenShift Template and publish it to your cluster catalog.

<CardGroup>
  <Card title="Watch Video" icon="video" cta="Learn more" href="https://learn.kodekloud.com/user/courses/openshift-3-for-the-absolute-beginners/module/b01015b4-ff27-4531-8507-ffb64893375d/lesson/51c588c2-56c8-40ab-9a53-d202bc99bfb4" />
</CardGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.