4. Exposing a service
In this lab, we are going to make the freshly deployed application from the last lab available online.
Task 4.1: Create a ClusterIP Service
The command oc apply -f deployment_example-web-go.yaml
from the last lab creates a Deployment but no Service. A OpenShift Service is an abstract way to expose an application running on a set of Pods as a network service. For some parts of your application (for example, frontends) you may want to expose a Service to an external IP address which is outside your cluster.
OpenShift ServiceTypes
allow you to specify what kind of Service you want. The default is ClusterIP
.
Type
values and their behaviors are:
ClusterIP
: Exposes the Service on a cluster-internal IP. Choosing this value only makes the Service reachable from within the cluster. This is the default ServiceType.NodePort
: Exposes the Service on each Node’s IP at a static port (the NodePort). A ClusterIP Service, to which the NodePort Service routes, is automatically created. You’ll be able to contact the NodePort Service from outside the cluster, by requesting <NodeIP>:<NodePort>.LoadBalancer
: Exposes the Service externally using a cloud provider’s load balancer. NodePort and ClusterIP Services, to which the external load balancer routes, are automatically created.ExternalName
: Maps the Service to the contents of the externalName field (e.g. foo.bar.example.com), by returning a CNAME record with its value. No proxying of any kind is set up.
You can also use Ingress to expose your Service. Ingress is not a Service type, but it acts as the entry point for your cluster. Ingress exposes HTTP and HTTPS routes from outside the cluster to services within the cluster. Traffic routing is controlled by rules defined on the Route resource. A Route may be configured to give Services externally reachable URLs, load balance traffic, terminate SSL / TLS, and offer name-based virtual hosting. An Ingress controller is responsible for fulfilling the route, usually with a load balancer, though it may also configure your edge router or additional frontends to help handle the traffic.
In order to create a Route, we first need to create a Service of type ClusterIP .
To create the Service add a new file svc-web-go.yaml
with the following content:
---
apiVersion: v1
kind: Service
metadata:
labels:
app: example-web-go
name: example-web-go
spec:
ports:
- port: 5000
protocol: TCP
targetPort: 5000
selector:
app: example-web-go
type: ClusterIP
And then apply the file with:
oc apply -f svc-web-go.yaml --namespace <namespace>
There is also am imperative command to create a service and expose your application which can be used instead of the yaml file with the oc apply ...
command
oc expose deployment example-web-go --type=ClusterIP --name=example-web-go --port=5000 --target-port=5000 --namespace <namespace>
You will get the error message reading Error from server (AlreadyExists): services "example-web-go" already exists
here. This is because the oc new-app
command you executed during lab 3 already created a service. This is the default behavior of oc new-app
while oc create deployment
doesn’t have this functionality.
As a consequence, the oc expose
command above doesn’t add anything new but it demonstrates how to easily create a service based on a deployment.
Let’s have a more detailed look at our Service:
oc get services --namespace <namespace>
Which gives you an output similar to this:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
example-web-go ClusterIP 10.43.91.62 <none> 5000/TCP
Note
Service IP (CLUSTER-IP) addresses stay the same for the duration of the Service’s lifespan.By executing the following command:
oc get service example-web-go -o yaml --namespace <namespace>
You get additional information:
apiVersion: v1
kind: Service
metadata:
...
labels:
app: example-web-go
managedFields:
...
name: example-web-go
namespace: <namespace>
...
spec:
clusterIP: 10.43.91.62
externalTrafficPolicy: Cluster
ports:
- port: 5000
protocol: TCP
targetPort: 5000
selector:
app: example-web-go
sessionAffinity: None
type: ClusterIP
status:
loadBalancer: {}
The Service’s selector
defines which Pods are being used as Endpoints. This happens based on labels. Look at the configuration of Service and Pod in order to find out what maps to what:
oc get service example-web-go -o yaml --namespace <namespace>
...
selector:
app: example-web-go
...
With the following command you get details from the Pod:
Note
First, get all Pod names from your namespace with (oc get pods --namespace <namespace>
) and then replace <pod> in the following command. If you have installed and configured the bash completion, you can also press the TAB key for autocompletion of the Pod’s name.oc get pod <pod> -o yaml --namespace <namespace>
Let’s have a look at the label section of the Pod and verify that the Service selector matches the Pod’s labels:
...
labels:
app: example-web-go
...
This link between Service and Pod can also be displayed in an easier fashion with the oc describe
command:
oc describe service example-web-go --namespace <namespace>
Name: example-web-go
Namespace: example-ns
Labels: app=example-web-go
Annotations: <none>
Selector: app=example-web-go
Type: ClusterIP
IP: 10.39.240.212
Port: <unset> 5000/TCP
TargetPort: 5000/TCP
Endpoints: 10.36.0.8:5000
Session Affinity: None
External Traffic Policy: Cluster
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
The Endpoints
show the IP addresses of all currently matched Pods.
Task 4.2: Expose the Service
With the ClusterIP Service ready, we can now create the Route resource.
oc create route edge example-web-go --service example-web-go --namespace <namespace>
The output should be:
route.route.openshift.io/example-web-go created
We are now able to access our app via the freshly created route at https://example-web-go-<namespace>.<appdomain>
Find your actual app URL by looking at your route (HOST/PORT):
oc get route --namespace <namespace>
Browse to the URL and check the output of your app.
Note
If the site doesn’t load, check if you are using the http:// , not the https:// protocol, which might be the default in your browser.
Note
The <appdomain>
is the default domain under which your applications will be accessible and is provided by your trainer. You can also use oc get route example-web-go
to see the exact value of the exposed route.
Task 4.4: For fast learners
Have a closer look at the resources created in your namespace <namespace>
with the following commands and try to understand them:
oc describe namespace <namespace>
oc get all --namespace <namespace>
oc describe <resource> <name> --namespace <namespace>
oc get <resource> <name> -o yaml --namespace <namespace>