Skip to content

Exposing apps

Earlier, we learned how to run software in Kubernetes as Deployments and how to access it within the cluster.

When the software users are in the cluster, they can directly contact it through the Service resource.

A lot of times the software user is outside the cluster (e.g. a person with a web browser) so we need a way to make our app available outside the cluster.

For exposing our application, we can use Ingress.

Ingress allows mapping HTTP/HTTPS traffic to Kubernetes hosted applications based on rules provided to Kubernetes.

In this section, we'll learn how to expose our application to users outside the Kubernetes cluster.

Load balancing for our app

Now that we have a working multi-pod deployment for our app, we'd naturally like to have a way to balance load between all of the Pods.

Let's create a YAML manifest named demo-service.yaml with the following contents:

apiVersion: v1
kind: Service
metadata:
  name: demo
  labels:
    app: demo
spec:
  selector:
    app: demo-pod
  ports:
  - port: 80
    targetPort: 8080
    protocol: TCP

In this YAML:

  • We use the spec.selector to find Pod targets for our Service. The traffic sent to the service will be forwarded to the Pods have the matching labels.
  • We use the ports section to define which ports in the Service should be forwarded to which ports in the Pods.

Let's create the Service and see what information it gives us.

$ kubectl apply -f demo-service.yaml
service/demo created

$ kubectl get svc
NAME   TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)   AGE
demo   ClusterIP   172.20.255.79    <none>        80/TCP    10s

Our service has the IP address 172.20.255.79.

The IP assigned to your Service in your cluster might be different, remember to replace the curl command with it.

We can try the one-off pod to communicate with it:

$ kubectl run --rm -it --restart=Never --image=curlimages/curl call-demo -- http://100.66.240.247
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
...

Kubernetes also creates two DNS names for our service in pattern:

  • One using the name of the Service: demo
  • One using the name of the Service and the namespace: demo.tutorial.svc.cluster.local.

Both of these names can be used from the namespace where we created our Service in, and the second one can be used everywhere in the cluster. Let's try using them!

$ kubectl run --rm -it --restart=Never --image=curlimages/curl call-demo -- demo
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
...

$ kubectl run --rm -it --restart=Never --image=curlimages/curl call-demo -- demo.tutorial.svc.cluster.local
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
...

Perfect! We can also check which Pods the service uses as targets by looking into the endpoints.

$ kubectl get endpoints
NAME   ENDPOINTS                        AGE
demo   10.0.2.105:8080,10.0.2.46:8080   8m59s

The IP addresses listed above are the IP addresses of the Pods.

Preparation

Before we can make an app available outside the cluster, we need to have it running.

Note

If you've followed the earlier sections and haven't reset your Kubernetes environment or deleted the resources, you should have a demo app already running.

In case you don't have the app running, make sure you have the following contents in the following files.

File: demo-content.yaml:

apiVersion: v1
kind: ConfigMap
metadata:
  name: demo-content
data:
  hello.txt: Hello world!
  filler.txt: |
    Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
    tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim
    veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea
    commodo consequat. Duis aute irure dolor in reprehenderit in voluptate
    velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat
    cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id
    est laborum.

File demo-deployment.yaml:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: demo
  labels:
    app: demo
spec:
  replicas: 3
  progressDeadlineSeconds: 20
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 0
  selector:
    matchLabels:
      app: demo-pod
  template:
    metadata:
      labels:
        app: demo-pod
    spec:
      containers:
      - image: nginxinc/nginx-unprivileged
        name: nginx
        ports:
        - containerPort: 8080
        readinessProbe:
          periodSeconds: 5
          successThreshold: 1
          httpGet:
            path: /
            port: 8080
        volumeMounts:
        - name: content
          mountPath: /usr/share/nginx/html/content
      volumes:
      - name: content
        configMap:
          name: demo-content

File demo-service.yaml:

apiVersion: v1
kind: Service
metadata:
  name: demo
  labels:
    app: demo
spec:
  selector:
    app: demo-pod
  ports:
  - port: 80
    targetPort: 8080
    protocol: TCP

Let's make sure these are deployed to the training cluster:

$ kubectl apply -f demo-content.yaml -f demo-deployment.yaml -f demo-service.yaml

To ensure that the demo application is working, run the following command:

$ kubectl run --restart=Never --rm -it --image=curlimages/curl call-demo -- http://demo/content/hello.txt
Hello world!

We're now ready to play with Ingress!

Ingress resource

Like everything else in Kubernetes, Ingress is also configured using Kubernetes resources.

Let's create a new YAML manifest named demo-ingress.yaml with the following contents.

Note

If you're participating in one of Polar Squad's workshops, the instructors will provide you a host value to use below.

Otherwise, you can leave it as null like below.

Note

Depending on the cluster setup, you may need to set the Ingress class either with an annotation, or a specific field in the spec.

The instructors will help you with this.

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: demo-ingress
  labels:
    app: demo
spec:
  rules:
  - host: <namespace>.k8s.polarsquad.training
    http:
      paths:
      - path: /content
        pathType: Prefix
        backend:
          service:
            name: demo
            port:
              number: 80

In this YAML file, the apiVersion is now networking.k8s.io/v1. This is distinct to Ingress kind.

We can specify one or more routing rules in the spec.rules section. Here we specify a single routing rule from all incoming HTTP/HTTPS traffic to path /content to be routed to the demo service port 80. The destination should match the Service details we created earlier.

The host value can be used for routing HTTP/HTTPS traffic based on domain names. For example, if we used host foobar.example.org, then only requests send to that host would be forwarded to the the demo application. In the Polar Squad workshops, the cluster is pre-configured with domain names that you can use, which is k8s.polarsquad.training.

Let's create the resource using kubectl.

$ kubectl apply -f demo-ingress.yaml
ingress.networking.k8s.io/demo-ingress created

Accessing our application

If we monitor the resource, we should eventually see that it gets an IP address.

$ kubectl get ingress -w
NAME           CLASS    HOSTS                         ADDRESS         PORTS   AGE
demo-ingress   <none>   foo.k8s.polarsquad.training   172.20.86.239   80      2m19s

The address there is the public IP address of a Load Balancer that points to the Kubernetes training cluster. Note that the address is different for your training cluster.

Open the IP address / hostname in your web browser (or using curl) in the /content/hello.txt path (e.g. http://foo.k8s.polarsquad.training/content/hello.txt).

Note

If you're participating in one of Polar Squad's training sessions, you should use the address you specified in the host: field.

Open the address in your web browser (or using curl) in the /content/hello.txt path.

You should get Hello world! as the response.

If we attempt to navigate to the root path of the Ingress, we should get a 404 Not Found response.

This is because we only specified /content path to be routed to the demo app.

We can also create other routing rules to other apps in the cluster using the same Ingress resource or a new one.

As mentioned earlier, we can route the requests based on paths and domain names.

Freestyle: Another application

Based on the manifests shown above, create another application deployment next to the demo application created earlier and make it available outside the training cluster in another HTTP path using Ingress.

Make sure you use different resource names and labels in your YAML.

Next

In the next section, we'll learn how to debug our applications in Kubernetes.