Using subdomain in your OpenShift route definitions
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.