Chapter 1. Installing the Developer Hub Operator with the OLM framework You can install the Developer Hub Operator on GKE using the Operator Lifecycle Manager (OLM) framework . Following that, you can proceed to deploy your Developer Hub instance in GKE. For information about the OLM, see Operator Lifecycle Manager(OLM) documentation. Prerequisites You have subscribed to registry.redhat.io . For more information, see Red Hat Container Registry Authentication . You have installed the Operator Lifecycle Manager (OLM). For more information about installation and troubleshooting, see How do I get Operator Lifecycle Manager? You have installed kubectl . For more information, see Install kubetl . You have installed the Google Cloud CLI. For more information, see Install the gcloud CLI . You have logged in to your Google account and created a GKE Autopilot or GKE Standard cluster. Procedure Connect to your GKE cluster using the following command: gcloud container clusters get-credentials <cluster-name> \ 1 --location=<cluster-location> 2 1 Enter your GKE cluster name. 2 Enter your GKE cluster location. This command configures your Kubernetes client to point to your GKE cluster. Run the following command in your terminal to create the rhdh-operator namespace where the Operator is installed: kubectl create namespace rhdh-operator Create a pull secret using the following command: kubectl -n rhdh-operator create secret docker-registry rhdh-pull-secret \ --docker-server=registry.redhat.io \ --docker-username=<user_name> \ 1 --docker-password=<password> \ 2 --docker-email=<email> 3 1 Enter your username in the command. 2 Enter your password in the command. 3 Enter your email address in the command. The created pull secret is used to pull the Developer Hub images from the Red Hat Ecosystem. Create a CatalogSource resource that contains the Operator from the Red Hat Ecosystem: Example CatalogSource resource cat <<EOF | kubectl -n rhdh-operator apply -f - apiVersion: operators.coreos.com/v1alpha1 kind: CatalogSource metadata: name: redhat-catalog spec: sourceType: grpc image: registry.redhat.io/redhat/redhat-operator-index:v4.17 secrets: - "rhdh-pull-secret" displayName: Red Hat Operators EOF Create an OperatorGroup resource as follows: Example OperatorGroup resource cat <<EOF | kubectl apply -n rhdh-operator -f - apiVersion: operators.coreos.com/v1 kind: OperatorGroup metadata: name: rhdh-operator-group EOF Create a Subscription resource using the following code: Example Subscription resource cat <<EOF | kubectl apply -n rhdh-operator -f - apiVersion: operators.coreos.com/v1alpha1 kind: Subscription metadata: name: rhdh namespace: rhdh-operator spec: channel: fast installPlanApproval: Automatic name: rhdh source: redhat-catalog sourceNamespace: rhdh-operator startingCSV: rhdh-operator.v1.4.2 EOF Run the following command to verify that the created Operator is running: kubectl -n rhdh-operator get pods -w If the Operator pod shows ImagePullBackOff status, you might need permission to pull the image directly within the Operator deployment's manifest. Tip You can include the required secret name in the deployment.spec.template.spec.imagePullSecrets list and verify the deployment name using kubectl get deployment -n rhdh-operator command. For example: kubectl -n rhdh-operator patch deployment \ rhdh.fast --patch '{"spec":{"template":{"spec":{"imagePullSecrets":[{"name":"rhdh-pull-secret"}]}}}}' \ --type=merge Update the default configuration of the Operator to ensure that Developer Hub resources can start correctly in GKE using the following steps: Edit the backstage-default-config ConfigMap in the rhdh-operator namespace using the following command: kubectl -n rhdh-operator edit configmap backstage-default-config Locate the db-statefulset.yaml string and add the fsGroup to its spec.template.spec.securityContext , as shown in the following example: db-statefulset.yaml fragment db-statefulset.yaml: | apiVersion: apps/v1 kind: StatefulSet --- TRUNCATED --- spec: --- TRUNCATED --- restartPolicy: Always securityContext: # You can assign any random value as fsGroup fsGroup: 2000 serviceAccount: default serviceAccountName: default --- TRUNCATED --- Locate the deployment.yaml string and add the fsGroup to its specification, as shown in the following example: deployment.yaml fragment deployment.yaml: | apiVersion: apps/v1 kind: Deployment --- TRUNCATED --- spec: securityContext: # You can assign any random value as fsGroup fsGroup: 3000 automountServiceAccountToken: false --- TRUNCATED --- Locate the service.yaml string and change the type to NodePort as follows: service.yaml fragment service.yaml: | apiVersion: v1 kind: Service spec: # NodePort is required for the ALB to route to the Service type: NodePort --- TRUNCATED --- Save and exit. Wait until the changes are automatically applied to the Operator pods. 1.1. Deploying the Developer Hub instance on GKE with the Operator You can deploy your Developer Hub instance in GKE using the Operator. Prerequisites A cluster administrator has installed the Red Hat Developer Hub Operator. You have subscribed to registry.redhat.io . For more information, see Red Hat Container Registry Authentication . You have installed kubectl . For more information, see Install kubetl . You have configured a domain name for your Developer Hub instance. You have reserved a static external Premium IPv4 Global IP address that is not attached to any virtual machine (VM). For more information see Reserve a new static external IP address You have configured the DNS records for your domain name to point to the IP address that has been reserved. Note You need to create an A record with the value equal to the IP address. This process can take up to one hour to propagate. Procedure Create a ConfigMap named app-config-rhdh containing the Developer Hub configuration using the following template: app-config-rhdh.yaml fragment apiVersion: v1 kind: ConfigMap metadata: name: app-config-rhdh data: "app-config-rhdh.yaml": | app: title: Red Hat Developer Hub baseUrl: https://<rhdh_domain_name> backend: auth: externalAccess: - type: legacy options: subject: legacy-default-config secret: "USD{BACKEND_SECRET}" baseUrl: https://<rhdh_domain_name> cors: origin: https://<rhdh_domain_name> Create a Secret named my-rhdh-secrets and add a key named BACKEND_SECRET with a Base64-encoded string as value: my-rhdh-secrets fragment apiVersion: v1 kind: Secret metadata: name: my-rhdh-secrets stringData: # TODO: See https://backstage.io/docs/auth/service-to-service-auth/#setup BACKEND_SECRET: "xxx" Important Ensure that you use a unique value of BACKEND_SECRET for each Developer Hub instance. You can use the following command to generate a key: node-p'require("crypto").randomBytes(24).toString("base64")' To enable pulling the PostgreSQL image from the Red Hat Ecosystem Catalog, add the image pull secret in the default service account within the namespace where the Developer Hub instance is being deployed: kubectl patch serviceaccount default \ -p '{"imagePullSecrets": [{"name": "rhdh-pull-secret"}]}' \ -n <your_namespace> Create your Backstage custom resource (CR) file using the following template: Custom resource fragment apiVersion: rhdh.redhat.com/v1alpha3 kind: Backstage metadata: # This is the name of your Developer Hub instance name: my-rhdh spec: application: imagePullSecrets: - "rhdh-pull-secret" route: enabled: false appConfig: configMaps: - name: "app-config-rhdh" extraEnvs: secrets: - name: "my-rhdh-secrets" Set up a Google-managed certificate by creating a ManagedCertificate object which you must attach to the Ingress. Example of a ManagedCertificate object apiVersion: networking.gke.io/v1 kind: ManagedCertificate metadata: name: <rhdh_certificate_name> spec: domains: - <rhdh_domain_name> For more information about setting up a Google-managed certificate, see Setting up a Google-managed certificate . Create a FrontendConfig object to set a policy for redirecting to HTTPS. You must attach this policy to the Ingress. Example of a FrontendConfig object apiVersion: networking.gke.io/v1beta1 kind: FrontendConfig metadata: name: <ingress_security_config> spec: sslPolicy: gke-ingress-ssl-policy-https redirectToHttps: enabled: true For more information about setting a policy to redirect to HTTPS, see HTTP to HTTPS redirects . Create an ingress resource using the following template, customizing the names as needed: Example of an ingress resource configuration apiVersion: networking.k8s.io/v1 kind: Ingress metadata: # TODO: this the name of your Developer Hub Ingress name: my-rhdh annotations: # If the class annotation is not specified it defaults to "gce". kubernetes.io/ingress.class: "gce" kubernetes.io/ingress.global-static-ip-name: <ADDRESS_NAME> networking.gke.io/managed-certificates: <rhdh_certificate_name> networking.gke.io/v1beta1.FrontendConfig: <ingress_security_config> spec: ingressClassName: gce rules: # TODO: Set your application domain name. - host: <rhdh_domain_name> http: paths: - path: / pathType: Prefix backend: service: # TODO: my-rhdh is the name of your `Backstage` custom resource. # Adjust if you changed it! name: backstage-my-rhdh port: name: http-backend Verification Wait for the ManagedCertificate to be provisioned. This process can take a couple of hours. Access RHDH with https://<rhdh_domain_name> Additional information For more information on setting up GKE using Ingress with TLS, see Secure GKE Ingress .

Commands:
gcloud container clusters get-credentials <cluster-name> \ 1 --location=<cluster-location> 2
create namespace rhdh-operator
-n rhdh-operator create secret docker-registry rhdh-pull-secret --docker-server=registry.redhat.io --docker-username=<user_name> \ 1 --docker-password=<password> \ 2 --docker-email=<email> 3
cat <<EOF | kubectl -n rhdh-operator apply -f - apiVersion: operators.coreos.com/v1alpha1 kind: CatalogSource metadata: name: redhat-catalog spec: sourceType: grpc image: registry.redhat.io/redhat/redhat-operator-index:v4.17 secrets: - "rhdh-pull-secret" displayName: Red Hat Operators EOF
cat <<EOF | kubectl apply -n rhdh-operator -f - apiVersion: operators.coreos.com/v1 kind: OperatorGroup metadata: name: rhdh-operator-group EOF
cat <<EOF | kubectl apply -n rhdh-operator -f - apiVersion: operators.coreos.com/v1alpha1 kind: Subscription metadata: name: rhdh namespace: rhdh-operator spec: channel: fast installPlanApproval: Automatic name: rhdh source: redhat-catalog sourceNamespace: rhdh-operator startingCSV: rhdh-operator.v1.4.2 EOF
-n rhdh-operator get pods -w
-n rhdh-operator patch deployment rhdh.fast --patch '{"spec":{"template":{"spec":{"imagePullSecrets":[{"name":"rhdh-pull-secret"}]}}}}' --type=merge
-n rhdh-operator edit configmap backstage-default-config
db-statefulset.yaml: | apiVersion: apps/v1 kind: StatefulSet --- TRUNCATED --- spec: --- TRUNCATED --- restartPolicy: Always securityContext: # You can assign any random value as fsGroup fsGroup: 2000 serviceAccount: default serviceAccountName: default --- TRUNCATED ---
deployment.yaml: | apiVersion: apps/v1 kind: Deployment --- TRUNCATED --- spec: securityContext: # You can assign any random value as fsGroup fsGroup: 3000 automountServiceAccountToken: false --- TRUNCATED ---
service.yaml: | apiVersion: v1 kind: Service spec: # NodePort is required for the ALB to route to the Service type: NodePort --- TRUNCATED ---
apiVersion: v1 kind: ConfigMap metadata: name: app-config-rhdh data: "app-config-rhdh.yaml": | app: title: Red Hat Developer Hub baseUrl: https://<rhdh_domain_name> backend: auth: externalAccess: - type: legacy options: subject: legacy-default-config secret: "USD{BACKEND_SECRET}" baseUrl: https://<rhdh_domain_name> cors: origin: https://<rhdh_domain_name>
apiVersion: v1 kind: Secret metadata: name: my-rhdh-secrets stringData: # TODO: See https://backstage.io/docs/auth/service-to-service-auth/#setup BACKEND_SECRET: "xxx"
node-p'require("crypto").randomBytes(24).toString("base64")'
patch serviceaccount default -p '{"imagePullSecrets": [{"name": "rhdh-pull-secret"}]}' -n <your_namespace>
apiVersion: rhdh.redhat.com/v1alpha3 kind: Backstage metadata: # This is the name of your Developer Hub instance name: my-rhdh spec: application: imagePullSecrets: - "rhdh-pull-secret" route: enabled: false appConfig: configMaps: - name: "app-config-rhdh" extraEnvs: secrets: - name: "my-rhdh-secrets"
apiVersion: networking.gke.io/v1 kind: ManagedCertificate metadata: name: <rhdh_certificate_name> spec: domains: - <rhdh_domain_name>
apiVersion: networking.gke.io/v1beta1 kind: FrontendConfig metadata: name: <ingress_security_config> spec: sslPolicy: gke-ingress-ssl-policy-https redirectToHttps: enabled: true
apiVersion: networking.k8s.io/v1 kind: Ingress metadata: # TODO: this the name of your Developer Hub Ingress name: my-rhdh annotations: # If the class annotation is not specified it defaults to "gce". kubernetes.io/ingress.class: "gce" kubernetes.io/ingress.global-static-ip-name: <ADDRESS_NAME> networking.gke.io/managed-certificates: <rhdh_certificate_name> networking.gke.io/v1beta1.FrontendConfig: <ingress_security_config> spec: ingressClassName: gce rules: # TODO: Set your application domain name. - host: <rhdh_domain_name> http: paths: - path: / pathType: Prefix backend: service: # TODO: my-rhdh is the name of your `Backstage` custom resource. # Adjust if you changed it! name: backstage-my-rhdh port: name: http-backend