Validated Patterns

Using subdomain in your OpenShift route definitions

by Lester Claudio
September 2, 2022
validated-pattern openshift route

What Is a route in OpenShift?

When creating Community or Validated Patterns using the Validated Patterns framework we often include application workloads, such as a UI, that will need to be accessed externally. A route allows developers to expose services through an HTTP(S) aware load balancing and proxy layer via a public DNS entry.

How is the kind: Route used in OpenShift?

If your application is meant to be used externally then you will need to define a route so that users can access the service using the URL you specify in the route definition.

Here’s a simple example of a route definition for a hello-openshift application:

apiVersion: route.openshift.io/v1
kind: Route
metadata:
  name: hello-openshift
spec:
  host: hello-openshift-hello-openshift.<Ingress_Domain>
  port:
    targetPort: 8080
  to:
    kind: Service
    name: hello-openshift

As you can see the spec describes the a host: or path to the route, the target port (8080), and the target, or to: that resolves into endpoints.

If we focus on the host: value you see that we need to provide the Ingress_Domain to the host. You might ask yourself: why is this a problem?

If you manage just one cluster, and your application just runs on that cluster, you can just hard code the ingress domain and be on your merry way. But what happens when you are deploying this application to multiple clusters and their domains are different? Whoever is doing the Ops to deploy your application will have to change the Ingress_Domain to match the the cluster domain manually before deploying the application.

Let’s go a step further and say you are using GitOps, and this definition lives in a git repository, what happens then? In our humble opinion it becomes a bit more complicated to make sure the ingress domain is set correctly.

The kind: Route spec to the rescue

The route specification for openshift can be found here. If you look at the .spec section you can see the properties that can be used. The one that we will focus in the subdomain property. From our docs here’s the definition of the subdomain property:

subdomain is a DNS subdomain that is requested within the ingress controller’s domain (as a subdomain). If host is set this field is ignored. An ingress controller may choose to ignore this suggested name, in which case the controller will report the assigned name in the status.ingress array or refuse to admit the route. If this value is set and the server does not support this field host will be populated automatically. Otherwise host is left empty. The field may have multiple parts separated by a dot, but not all ingress controllers may honor the request. This field may not be changed after creation except by a user with the update routes/custom-host permission.

Example: subdomain frontend automatically receives the router subdomain apps.mycluster.com to have a full hostname frontend.apps.mycluster.com.

If you have access to an OpenShift cluster you can test the above route manifest to see the results. Let’s create a quick route-example.yaml file and use the subdomain property. From the command line type the following:

$ cat <<EOF > /tmp/route-example.yaml
apiVersion: route.openshift.io/v1
kind: Route
metadata:
  name: hello-openshift
  namespace: hello-openshift
spec:
  subdomain: hello-openshift-hello-openshift
  port:
    targetPort: 8080
  to:
    kind: Service
    name: hello-openshift
EOF

Now let’s create a namespace where we will test create our Route.

$ oc create ns hello-openshift
namespace/hello-openshift created

Now let’s change our context to that namespace.

$ oc project hello-openshift
Now using project "hello-openshift" on server "https://api.magic-mirror-2.blueprints.rhecoeng.com:6443".

Last but not least now let’s apply that example route definition we just created.

$ oc create -f /tmp/route-example.yaml
route.route.openshift.io/hello-openshift created

If we inspect what was applied to the OpenShift cluster you should be able to see the following:

$ oc get route/hello-openshift -o yaml
apiVersion: route.openshift.io/v1
kind: Route
metadata:
  annotations:
    openshift.io/host.generated: "true"
  creationTimestamp: "2022-09-02T21:55:58Z"
  name: hello-openshift
  namespace: hello-openshift
  resourceVersion: "1349531"
  uid: c0cddbb2-271e-48fb-b7fd-bcd8c5075cdf
spec:
  host: hello-openshift-hello-openshift.apps.magic-mirror-2.blueprints.rhecoeng.com
  port:
    targetPort: 8080
  subdomain: hello-openshift-hello-openshift
  to:
    kind: Service
    name: hello-openshift
    weight: 100
  wildcardPolicy: None
status:
  ingress:
  - conditions:
    - lastTransitionTime: "2022-09-02T21:55:58Z"
      status: "True"
      type: Admitted
    host: hello-openshift-hello-openshift.apps.magic-mirror-2.blueprints.rhecoeng.com
    routerCanonicalHostname: router-default.apps.magic-mirror-2.blueprints.rhecoeng.com
    routerName: default
    wildcardPolicy: None

As you can see the subdomain property was replaced with the host property but it includes the ingress domain for the cluster. Why is this important? I can now apply this to any OpenShift cluster without worrying it’s ingress domain since it will get appended automatically.

There is currently a known issue when using the subdomain property in which the name given is not published with the correct template, instead of that they are published with the default ‘${name}-${namespace}.subdomain.local’. This has been fixed and it’s available in OpenShift 4.11.

Conclusion

Using the subdomain property when defining route is super useful if you are deploying your application to different clusters and it will allow you to not have to hard code the ingress domain for every cluster.

If you have any questions or want to see what we are working on please feel free to visit our Validated Patterns site. If you are excited or intrigued by what you see here we’d love to hear your thoughts and ideas! Try the patterns contained in our Validated Patterns Repo. We will review your pull requests to our pattern repositories.