Skip to main content
Redhat Developers  Logo
  • Products

    Featured

    • Red Hat Enterprise Linux
      Red Hat Enterprise Linux Icon
    • Red Hat OpenShift AI
      Red Hat OpenShift AI
    • Red Hat Enterprise Linux AI
      Linux icon inside of a brain
    • Image mode for Red Hat Enterprise Linux
      RHEL image mode
    • Red Hat OpenShift
      Openshift icon
    • Red Hat Ansible Automation Platform
      Ansible icon
    • Red Hat Developer Hub
      Developer Hub
    • View All Red Hat Products
    • Linux

      • Red Hat Enterprise Linux
      • Image mode for Red Hat Enterprise Linux
      • Red Hat Universal Base Images (UBI)
    • Java runtimes & frameworks

      • JBoss Enterprise Application Platform
      • Red Hat build of OpenJDK
    • Kubernetes

      • Red Hat OpenShift
      • Microsoft Azure Red Hat OpenShift
      • Red Hat OpenShift Virtualization
      • Red Hat OpenShift Lightspeed
    • Integration & App Connectivity

      • Red Hat Build of Apache Camel
      • Red Hat Service Interconnect
      • Red Hat Connectivity Link
    • AI/ML

      • Red Hat OpenShift AI
      • Red Hat Enterprise Linux AI
    • Automation

      • Red Hat Ansible Automation Platform
      • Red Hat Ansible Lightspeed
    • Developer tools

      • Red Hat Trusted Software Supply Chain
      • Podman Desktop
      • Red Hat OpenShift Dev Spaces
    • Developer Sandbox

      Developer Sandbox
      Try Red Hat products and technologies without setup or configuration fees for 30 days with this shared Openshift and Kubernetes cluster.
    • Try at no cost
  • Technologies

    Featured

    • AI/ML
      AI/ML Icon
    • Linux
      Linux Icon
    • Kubernetes
      Cloud icon
    • Automation
      Automation Icon showing arrows moving in a circle around a gear
    • View All Technologies
    • Programming Languages & Frameworks

      • Java
      • Python
      • JavaScript
    • System Design & Architecture

      • Red Hat architecture and design patterns
      • Microservices
      • Event-Driven Architecture
      • Databases
    • Developer Productivity

      • Developer productivity
      • Developer Tools
      • GitOps
    • Secure Development & Architectures

      • Security
      • Secure coding
    • Platform Engineering

      • DevOps
      • DevSecOps
      • Ansible automation for applications and services
    • Automated Data Processing

      • AI/ML
      • Data Science
      • Apache Kafka on Kubernetes
      • View All Technologies
    • Start exploring in the Developer Sandbox for free

      sandbox graphic
      Try Red Hat's products and technologies without setup or configuration.
    • Try at no cost
  • Learn

    Featured

    • Kubernetes & Cloud Native
      Openshift icon
    • Linux
      Rhel icon
    • Automation
      Ansible cloud icon
    • Java
      Java icon
    • AI/ML
      AI/ML Icon
    • View All Learning Resources

    E-Books

    • GitOps Cookbook
    • Podman in Action
    • Kubernetes Operators
    • The Path to GitOps
    • View All E-books

    Cheat Sheets

    • Linux Commands
    • Bash Commands
    • Git
    • systemd Commands
    • View All Cheat Sheets

    Documentation

    • API Catalog
    • Product Documentation
    • Legacy Documentation
    • Red Hat Learning

      Learning image
      Boost your technical skills to expert-level with the help of interactive lessons offered by various Red Hat Learning programs.
    • Explore Red Hat Learning
  • Developer Sandbox

    Developer Sandbox

    • Access Red Hat’s products and technologies without setup or configuration, and start developing quicker than ever before with our new, no-cost sandbox environments.
    • Explore Developer Sandbox

    Featured Developer Sandbox activities

    • Get started with your Developer Sandbox
    • OpenShift virtualization and application modernization using the Developer Sandbox
    • Explore all Developer Sandbox activities

    Ready to start developing apps?

    • Try at no cost
  • Blog
  • Events
  • Videos

Achieve more with less using Red Hat Developer Hub's self-service features

March 12, 2024
Josephine Pfeiffer
Related topics:
Automation and managementDeveloper ToolsGitOpsKubernetes
Related products:
Red Hat Developer HubRed Hat OpenShift

Share:

    A client company’s Red Hat OpenShift team was facing a common issue: engineering teams had to allocate time to handle repetitive and manual tasks, such as addressing a high volume of service desk tickets. Many of these tickets stemmed from misconfigurations and unclear documentation, which not only consume valuable time and effort from the engineering team but also hinder the productivity and satisfaction of end-users.

    The client wanted to improve the developer experience by introducing more self-service and automation. To achieve this, the client tested out Red Hat Developer Hub as a unified access point to tools and resources.

    Background

    Toil, as defined by Google’s site reliability engineering (SRE) framework, is work that doesn’t drive long-term value. In this case, answering recurring manual support tickets instead of working on adding features to the OpenShift platform is considered toil. This directly affects the pace at which the organization can innovate and respond to emerging needs.

    Moreover, the reliance on manual processes for addressing these tickets introduces the risk of errors and inconsistencies, further compromising the reliability and stability of the IT infrastructure. By automating these processes and enabling self-service capabilities, the team can significantly reduce the incidence of such issues, leading to a more stable and reliable platform.

    This shift not only improves the developer experience but also frees up the engineering team to focus on strategic initiatives that add long-term value to the OpenShift platform.

    Project goals

    The main objective of this proof of concept project was to pick one low hanging fruit use case to demonstrate how the developer experience can be improved while simultaneously reducing toil—turning a lose-lose into a win-win.

    To identify this low hanging fruit, a data-driven approach was chosen to group and map common service desk requests. The chosen use case was troubleshooting issues around deploying GitLab runners to OpenShift clusters. This use case was the most common request by number of Jira tickets over time that could be automated.

    Before this pilot the process involved the developers copy-pasting an ill-formatted YAML manifest from Confluence, then editing, and deploying it. This manual process was highly prone to human error, given YAML's sensitivity to formatting. 

    The project aimed to remove as many unnecessary roadblocks as possible from this process and avoid inconsistencies across deployments. Additionally, the integration of other tools the client was already using—such as Jira, GitLab, Argo CD, OpenShift—was meant to showcase the value of having a central hub for everything developers need for an end-to-end Secure Software Development Lifecycle.

    Implementation

    Step 1: Turn the resources into skeleton

    After installing Developer Hub and getting it up and running, the resource templates developers were previously copy-pasting were turned into a skeleton which the scaffolding template will later populate. Conceptually, this is similar to a helm template in the sense that values get substituted and a manifest is rendered out.

    apiVersion: v1
    kind: Secret
    metadata:
      name:  gitlab-runner-secret-${{ values.runnerName }}
      namespace: ${{ values.namespace }}
    type: Opaque
    stringData:
      runner-registration-token: ${{ values.runnerToken }}
    ---
    apiVersion: apps.gitlab.com/v1beta2
    kind: Runner
    metadata:
      name: ${{ values.runnerName }}
      namespace: ${{ values.namespace }}
    spec:
      imagePullPolicy: Always
      gitlabUrl: ${{ values.gitlabUrl }}
      token: ${{ values.runnerToken }}
      tags: ${{ values.runnerTags }}

    Step 2: Write scaffolding template

    The values are filled in by the user through a form. This is made possible by a template that allows us to define what inputs we want to collect from users, the input validation, and the actions to process the scaffolded resource.

    apiVersion: scaffolder.backstage.io/v1beta3
    kind: Template
    metadata:
      name: gitlab-runner-deployment
      title: GitLab runner deployment on Kubernetes
      description: Deploys an instance of a GitLab runner custom resource to a target cluster in a user-specified namespace.
      tags:
        - gitlab
        - kubernetes
    spec:
      owner: pfeifferj
      system: gitlab
      type: service
      parameters:
        - title: GitLab Runner Configuration
          required:
            - authToken
            - cluster
            - gitlabUrl
            - namespace
            - runnerName
            - runnerToken
          properties:
            authToken:
              type: string
              title: Kubernetes auth token
              description: Personal or ServiceAccount Token used to apply resources.
              ui:backstage:
                review:
                  mask: '[MASKED]'
            cluster:
              type: string
              title: Kubernetes Cluster
              enum:
                - https://api.ocp4-dev.josie.cloud:6443 # CHANGE ME
                - https://api.ocp4-tst.josie.cloud:6443 # CHANGE ME
                - https://api.ocp4-prd.josie.cloud:6443 # CHANGE ME
              enumNames:
                - dev cluster
                - test cluster
                - prod cluster
            gitlabUrl:
              type: string
              title: GitLab instance
              description: URL for your GitLab instance.
              default: https://gitlab.com
            namespace:
              type: string
              title: Target Kubernetes Namespace
              description: The Kubernetes Namespace the runner will be deployed to.        
            runnerName:
              type: string
              title: Runner Name
              description: Name used by the runner.
            runnerTags:
              type: string
              title: Runner tags
              description: Runner tags to control which jobs a runner can pick up.
            runnerToken:
              type: string
              title: Runner Registration Token
              description: Token used to register the runner with GitLab.
              ui:backstage:
                review:
                  mask: '[MASKED]'
      steps:
        - id: generate-manifests
          name: Create Resource from Template
          action: fetch:template
          input: 
            url: ./skeleton
            values:
              gitlabUrl: ${{ parameters.gitlabUrl }}
              namespace: ${{ parameters.namespace }}
              runnerName: ${{ parameters.runnerName }}
              runnerTags: ${{ parameters.runnerTags }}
              runnerToken: ${{ parameters.runnerToken }}
        - id: read-manifest
          name: Read manifest
          action: read:file
          input:
            filename: gitlab-runner.yaml
        - id: deploy-runner
          name: Deploy GitLab Runner
          action: deploy:kubernetes
          input:
            authToken: ${{ parameters.authToken }}
            clusterUrl: ${{ parameters.cluster }}
            manifest: ${{ steps['read-manifest'].output.content }}
      output:
        links:
          - url: '${{ parameters.gitlabUrl }}/admin/runners'
            title: GitLab Runner Settings

    The template uses masking for sensitive information like the Kubernetes auth tokens and the runner registration token. This ensures that these values are obscured in any review interfaces, enhancing security.

    Enum values for the Kubernetes cluster URLs are defined with friendly names (dev, test, prod), making it easier for users to select the correct environment without needing to remember complex URLs.

    Users are prompted to provide specific configuration details such as the GitLab URL, runner name, and tags. This flexibility allows for tailored deployments based on the user's specific needs.

    Upon completion, the template provides a direct link to the GitLab Runner settings page for the newly deployed runner. This facilitates immediate access to configure or review the runner settings in the GitLab instance.

    Next, we want to import the template into Developer Hub. To do this, we click Create… -> Register an existing component -> paste the GitHub link to the template.yaml and click analyze (see Figure 1).

    Templates imported this way are stored in the database and thus survive pod restarts. It is also possible to include templates as code by creating an app config referencing the relevant catalog source.

    Registering an existing component in developer hub
    Figure 1: Importing the template into Developer Hub
    Figure 1: Importing the template into Developer Hub.

    The template has been imported and now shows up in the catalog if the user clicks Create… again, as shown in Figure 2.

    imported template in the developer hub catalog
    Figure 2: The template in the catalog
    Figure 2: The template in the catalog.

    We can test the template by clicking Choose, which takes us to the form. This is shown in Figure 3.

    developer hub template form
    Figure 3: This is what the form for the template we just wrote looks like
    Figure 3: This is what the form for the template we just wrote looks like.

    Step 3: Write actions

    The preferred way to deploy Kubernetes resources is with Helm charts, using GitOps principles. However, in this case this wasn’t a feasible solution because most of the client’s end users had not yet adopted GitOps. Therefore, another action was required to mimic the behavior of oc apply -f manifest.yaml to apply the generated manifest.

    The Backstage CLI helps developers get started with plug-in creation.

    npx @backstage/cli@latest new --scope @pfeifferj will bootstrap the required project structure.

    The action used the Kubernetes client node library under the hood:

    import { createTemplateAction } from '@backstage/plugin-scaffolder-backend';
    import { KubeConfig, KubernetesObjectApi } from '@kubernetes/client-node';
    import * as yaml from 'js-yaml';

    The authentication to the cluster is delegated, i.e. the users use their personal token and the action thus inherits their permissions.

    In the future, this could be streamlined using Red Hat's single-sign on technology and having the scaffolding template read from the user context similarly how it can already read logged in users’ username or email, for example, ${{ user.entity.spec.profile.email }}.

    The user inputs clusterUrl and authToken are used to generate a kubeConfig.

    clusterUrl: {
        title: 'Cluster URL',
        description: 'URL of the Kubernetes API',
        type: 'string',
    },
    authToken: {
        title: 'Token',
        description: 'Bearer token to authenticate with the Kubernetes API',
        type: 'string',
    }
    
    

    Which is then used to create an API client, which then applies the manifest:

    const api = kubeConfig.makeApiClient(KubernetesObjectApi);
    const resources = yaml.loadAll(manifest) as KubernetesResource[];
    
    ...
    for (const resource of resources) {
    try {
            const result = await api.create(resource);
    ...
    

    See the complete code on GitHub.

    To load the plug-ins dynamically, we need to edit the developer-hub-dynamic-plugins ConfigMap:

    
    oc edit cm developer-hub-dynamic-plugins -n backstage
    
    ...
    plugins:
      - package: '@pfeifferj/backstage-scaffolder-backend-module-kubernetes-deploy-dynamic'
        integrity: 'sha512-AwysOmmabZ4mtqk8Z4lb7OHO0j8xtsjOYL+DGnIscIw2RdM6zIjsanbM2EWrLw+Q4N3cEht0gRJAjxW7SWEoFQ==' # get using npm info <package>
        disabled: false

    Next, we can verify the plugins are loaded correctly by checking the logs of the install-dynamic-plugins container in the backstage-developer-hub pod.

    
    oc logs -l app.kubernetes.io/component-backstage -c install-dynamic-plugins
    
    ...
    ======= Installing dynamic plugin @pfeifferj/plugin-scaffolder-backend-module-read-file
    ==> Grabbing package archive through `npm pack`
    ==> Verifying package integrity
    ==> Removing previous plugin directory /dynamic-plugins-root/pfeifferj-plugin-scaffolder-backend-module-read-file-0.0.8
    ==> Extracting package archive /dynamic-plugins-root/pfeifferj-plugin-scaffolder-backend-module-read-file-0.0.8.tgz
    Skipping directory entry package
    Skipping directory entry package/dist
    Skipping directory entry package/src
    ==> Removing package archive /dynamic-plugins-root/pfeifferj-plugin-scaffolder-backend-module-read-file-0.0.8.tgz
    ==> Successfully installed dynamic plugin @pfeifferj/plugin-scaffolder-backend-module-read-file
    ======= Installing dynamic plugin @pfeifferj/plugin-scaffolder-backend-module-kubernetes-deploy
    ==> Grabbing package archive through `npm pack`
    ==> Verifying package integrity
    ==> Removing previous plugin directory /dynamic-plugins-root/pfeifferj-plugin-scaffolder-backend-module-kubernetes-deploy-0.0.25
    ==> Extracting package archive /dynamic-plugins-root/pfeifferj-plugin-scaffolder-backend-module-kubernetes-deploy-0.0.25.tgz
    Skipping directory entry package
    Skipping directory entry package/dist
    Skipping directory entry package/src
    ==> Removing package archive /dynamic-plugins-root/pfeifferj-plugin-scaffolder-backend-module-kubernetes-deploy-0.0.25.tgz
    ==> Successfully installed dynamic plugin @pfeifferj/plugin-scaffolder-backend-module-kubernetes-deploy

    Step 4: Putting it all together

    With the template imported and the plug-ins installed, the users can now complete the process end-to-end: They fill out the form, the fetch:template action renders the manifest based on the inputs, the manifest is passed to the deploy:kubernetes action to be applied.

    Figure 4 shows a high-level abstraction of the scaffolding process as a diagram.

    developer-hub-scaffolding-process
    Figure 4: Process overview diagram
    Figure 4: Process overview diagram.

    This new process leaves little room for human errors, thanks to the guardrails of the form and input validation which provides the users with instant feedback. An example of this is shown in Figure 5.

    developer hub form input validation on the front end
    Figure 5: Input validation on the front-end
    Figure 5: Input validation on the front-end.

    The instant validation can be improved even further in the future using custom field extensions.

    Additionally, developers benefit from having all the tools and information they need to be productive at their fingertips in a single platform.

    Watch a demo video

    Check out the following video to see how you can use scaffolding templates and actions in Red Hat Developer Hub to create and deploy custom resources to OpenShift.

    Conclusion

    Embracing automation and self-service through the adoption of a golden path approach for standardized development workflows represents an important shift towards optimizing operational efficiency and developer productivity. 

    By systematically increasing capacity and minimizing unnecessary manual work, teams are empowered to allocate more time and resources to projects that drive significant business value. This strategy not only clears roadblocks for developers by smoothing out the development process but also sets the stage for a broader transformation within the organization. 

    With Red Hat Developer Hub at its core, the client is poised to harness the full potential of this platform, leveraging its capabilities to streamline workflows, enhance self-service options, and ultimately foster an environment where innovation has more space to flourish. 

    Next steps

    The customer was impressed with the pilot and has plans to leverage more self-service and automation capabilities for different manual processes.

    If you too are interested to get started on your self-service and automation journey, our Red Hat Developer Hub product page offers further guides, documentation, and support resources to help you navigate and test out the platform: 

    For practical implementation, explore the GitHub repositories containing the templates and plug-ins referenced in this post. The templates and plug-ins provided are examples and meant to serve as a starting point.

    • Scaffolding template: https://github.com/pfeifferj/backstage-template-scaffolder-gitlab-runner
    • Dynamic scaffolding action: https://github.com/pfeifferj/backstage-scaffolder-backend-module-kubernetes-deploy-dynamic
    • Underlying scaffolding actions:
      • https://github.com/pfeifferj/backstage-plugin-scaffolder-kubernetes-deploy
      • https://github.com/pfeifferj/backstage-plugin-scaffolder-read-file
    • Creating dynamic plug-ins: https://github.com/janus-idp/backstage-showcase/blob/main/showcase-docs/dynamic-plugins.md#backend-plugins
    OSZAR »

    Related Posts

    • A developer’s guide to Red Hat Developer Hub and Janus

    • What is Podman Desktop? A developer's introduction

    • How Red Hat enhances the developer experience

    • Podman Desktop 1.0: Local container development made easy

    • Why the developer experience is so important

    • Red Hat Developer Hub: Your gateway to seamless development

    Recent Posts

    • LLM Compressor: Optimize LLMs for low-latency deployments

    • How to set up NVIDIA NIM on Red Hat OpenShift AI

    • Leveraging Ansible Event-Driven Automation for Automatic CPU Scaling in OpenShift Virtualization

    • Python packaging for RHEL 9 & 10 using pyproject RPM macros

    • Kafka Monthly Digest: April 2025

    What’s up next?

    Development teams today face a huge amount of cognitive overload due to the many frameworks, new technologies, and new approaches that make writing software a lot harder than it used to be. In this learning path, learn how to install the Red Hat Developer Hub internal developer platform and learn the concepts and skills you need to install your IDP, configure simple GitHub authorization, and explore templating basics.

    Start the activity
    Red Hat Developers logo LinkedIn YouTube Twitter Facebook

    Products

    • Red Hat Enterprise Linux
    • Red Hat OpenShift
    • Red Hat Ansible Automation Platform

    Build

    • Developer Sandbox
    • Developer Tools
    • Interactive Tutorials
    • API Catalog

    Quicklinks

    • Learning Resources
    • E-books
    • Cheat Sheets
    • Blog
    • Events
    • Newsletter

    Communicate

    • About us
    • Contact sales
    • Find a partner
    • Report a website issue
    • Site Status Dashboard
    • Report a security problem

    RED HAT DEVELOPER

    Build here. Go anywhere.

    We serve the builders. The problem solvers who create careers with code.

    Join us if you’re a developer, software engineer, web designer, front-end designer, UX designer, computer scientist, architect, tester, product manager, project manager or team lead.

    Sign me up

    Red Hat legal and privacy links

    • About Red Hat
    • Jobs
    • Events
    • Locations
    • Contact Red Hat
    • Red Hat Blog
    • Inclusion at Red Hat
    • Cool Stuff Store
    • Red Hat Summit

    Red Hat legal and privacy links

    • Privacy statement
    • Terms of use
    • All policies and guidelines
    • Digital accessibility

    Report a website issue

    OSZAR »