How to Use the Ingress Application Load Balancer to Expose an App Outside a Kubernetes Cluster

4 min read

In this article, we will explain how you can expose an application to the Internet with the Ingress application load balancer (ALB).

There are three options to expose an application if you are using a standard classic Kubernetes cluster (the NodePort is the only option if you are using a free Kubernetes cluster):

Ingress is a Kubernetes service that balances network traffic workloads in your cluster by forwarding public or private requests to your apps. You can use Ingress to expose multiple app services to the public or to a private network by using a unique public or private route:

There are three options to expose an application if you are using a standard classic Kubernetes cluster (the NodePort is the only option if you are using a free Kubernetes cluster):

Prerequisites

Deploying an application

Deploy a sample Hello World app into a Kubernetes pod in your project.

1. Create a new namespace for your project:

$ kubectl create namespace project-a

2. Set the namespace preference so that you don't need to specify the namespace for all subsequent kubectl commands in that context:

$ kubectl config set-context --current --namespace=project-a

3. Clone the source code for the sample Hello World app:

$ git clone https://github.com/IBM/container-service-getting-started-wt.git
$ cd "container-service-getting-started-wt/Lab 1"

4. Build a Docker image (Note: You need to have the Docker image running locally):

$ ibmcloud cr build -t us.icr.io/tn_namespace/hello-world:1 .

5. To pull images into a non-default Kubernetes namespace in IBM Cloud Kubernetes Service, you must add a new secret in your new namespace. You can copy the existing default secret into the new namespace. See more details here:

$ kubectl get secret default-us-icr-io -n default -o yaml | sed 's/default/project-a/g' | kubectl -n project-a create -f -
secret/project-a-us-icr-io created

6. Verify that the secret copied:

$ kubectl get secrets
NAME                  TYPE                                  DATA   AGE
project-a-us-icr-io   kubernetes.io/dockerconfigjson        1      10s

7. Create a deployment to deploy the app:

$ kubectl create deployment hello-world-deployment --image=us.icr.io/tn_namespace/hello-world:1
deployment.apps/hello-world-deployment created

8. Verify the deployment—hello-world-deployment—and the app are running on a pod:

$ kubectl get deployment hello-world-deployment
NAME                     READY   UP-TO-DATE   AVAILABLE   AGE
hello-world-deployment   1/1     1            1           1m5s
$ kubectl get pods
NAME                                     READY   STATUS    RESTARTS   AGE
hello-world-deployment-56999cc7cf-fk6ph   1/1     Running   0          1m50s

9. Scale up the number of replicas. Running three instances makes the app more highly available than just one instance:

$ kubectl scale deployment/hello-world-deployment --replicas=3
deployment.apps/hello-world-deployment scaled
$ kubectl get deployment hello-world-deployment
NAME                     READY   UP-TO-DATE   AVAILABLE   AGE
hello-world-deployment   3/3     3            3           2m40s

Creating an Ingress service

The following diagram shows how Ingress directs communication from the Internet to an app in a classic single-zone cluster.

The following diagram shows how Ingress directs communication from the Internet to an app in a classic single-zone cluster.

The ALB checks if a routing rule for the myapp path in the cluster exists. If a matching rule is found, the request is proxied according to the rules that you defined in the Ingress resource to the pod where the app is deployed. The source IP address of the package is changed to the IP address of the worker node where the app pod runs. If multiple app instances are deployed in the cluster, the ALB load balances the requests between the app pods.

See more details in the doc: How does a request get to my app in a classic cluster?

Use the following steps to create an Ingress application load balancer (ALB) service to expose your app.

1. Create a ClusterIP service

Create a Kubernetes ClusterIP service for the app deployment that you want to expose. Your app can be exposed by a Kubernetes service to be included in the Ingress load balancing:

$ kubectl expose deploy hello-world-deployment --name hello-world-svc --port 8080
service/my-app-svc exposed
$ kubectl get services
NAME              TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)    AGE
hello-world-svc   ClusterIP   172.21.82.31   <none>        8080/TCP   7s
$ kubectl describe service hello-world-svc
Name:              hello-world-svc
Namespace:         project-a
Labels:            app=hello-world-deployment
Annotations:       <none>
Selector:          app=hello-world-deployment
Type:              ClusterIP
IP:                172.21.82.31
Port:              <unset>  8080/TCP
TargetPort:        8080/TCP
Endpoints:         172.30.233.41:8080,172.30.233.42:8080,172.30.233.43:8080
Session Affinity:  None
Events:            <none>

Make sure to include a label to your deployment in the metadata section of your configuration file—such as app=hello-world-deployment. This label is needed to identify all pods where your app runs so that the pods can be included in the Ingress load balancing.

2. Select an app domain

You can choose the domain through which your apps will be accessible. You can use the IBM-provided domain, such as mycluster-<hash>-0000.us-south.containers.appdomain.cloud/myapp, to access your app:

$ ibmcloud ks cluster get --cluster tncluster  | grep Ingress
Ingress Subdomain:              tncluster-5be51ad3139a99d89cdf8f97c78ef71c-0000.us-south.containers.appdomain.cloud   
Ingress Secret:                 tncluster-5be51ad3139a99d89cdf8f97c78ef71c-0000   

3. Select TLS termination

You can choose whether to use TLS termination. The ALB load balances HTTP network traffic to the apps in your cluster. To also load balance incoming HTTPS connections, you can configure the ALB to decrypt the network traffic and forward the decrypted request to the apps that are exposed in your cluster. If you use the IBM-provided Ingress subdomain, you can use the IBM-provided TLS certificate, which is stored as a Kubernetes secret in the default namespace. 

4. Create the Ingress resource

Create an Ingress configuration file that is named—for example, myingress.yaml—to define the routing rules that the ALB uses to route traffic to your app service.

Ensure that the resource deploys into the same namespace as the app services that you specified in the resource. If your apps are exposed by services in different namespaces in one cluster, add a wildcard subdomain to the beginning of the domain, such as subdomain1.custom_domain.net or subdomain1.mycluster-<hash>-0000.us-south.containers.appdomain.cloud. Use a unique subdomain for each Ingress resource that you create in the cluster.

Example configuration for the Ingress resource:

$ cat myingress.yaml 
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: myingress
spec:
  rules:
  - host: subdomain1.tncluster-5be51ad3139a99d89cdf8f97c78ef71c-0000.us-south.containers.appdomain.cloud
    http:
      paths:
      - path: /
        backend:
          serviceName: hello-world-svc
          servicePort: 8080

Apply the Ingress configuration to create:

$ kubectl apply -f myingress.yaml
ingress.networking.k8s.io/myingress configured

Verify that the Ingress resource was created successfully. If messages in the events describe an error in your resource configuration, change the values in your resource file and reapply the file for the resource:

$ kubectl describe ingress myingress
...
Rules:
  Host                                                                                            Path  Backends
  ----                                                                                            ----  --------
  subdomain1.tncluster-5be51ad3139a99d89cdf8f97c78ef71c-0000.us-south.containers.appdomain.cloud  
                                                                                                  /   hello-world-svc:8080 (172.30.233.41:8080,172.30.233.42:8080,172.30.233.43:8080)
...
Events:
  Type    Reason   Age   From                                                 Message
  ----    ------   ----  ----                                                 -------
  Normal  Success  51s   public-crbsps9s2d08ovk65207gg-alb1-56c8bc6f8d-7bkpt  Successfully applied ingress resource.

Access your app with the Ingress subdomain and the path—https://<ingress_subdomain>/<app_path>:

$ curl subdomain1.tncluster-5be51ad3139a99d89cdf8f97c78ef71c-0000.us-south.containers.appdomain.cloud:80
Hello world from hello-world-deployment-56999cc7cf-vsr2q! Your app is up and running in a cluster!

5. Add Ingress annotations

You can add the Ingress annotations to add capabilities. For more details, see the documentation.                                       

  • rewrite-path can route incoming network traffic to a different path that your back-end app listens on
  • redirect-to-https can redirect insecure HTTP requests on your domain to HTTPS

You can change the ingress configuration like this:

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: myingress
  annotations:
    ingress.bluemix.net/rewrite-path: "serviceName=hello-world-svc rewrite=/"
    ingress.bluemix.net/redirect-to-https: "true"
spec:
  tls:
  - hosts:
    - subdomain1.tncluster-5be51ad3139a99d89cdf8f97c78ef71c-0000.us-south.containers.appdomain.cloud
    secretName: tncluster-5be51ad3139a99d89cdf8f97c78ef71c-0000
  rules:
  - host: subdomain1.tncluster-5be51ad3139a99d89cdf8f97c78ef71c-0000.us-south.containers.appdomain.cloud
    http:
      paths:
      - path: /hello
        backend:
          serviceName: hello-world-svc
          servicePort: 8080

Apply the new Ingress configuration:

$ kubectl apply -f myingress2.yaml
ingress.networking.k8s.io/myingressresource configured

Verify access to your app:

$ curl https://subdomain1.tncluster-5be51ad3139a99d89cdf8f97c78ef71c-0000.us-south.containers.appdomain.cloud/hello
Hello world from hello-world-deployment-56999cc7cf-vsr2q! Your app is up and running in a cluster!

6. Set up a custom domain

If you choose a custom domain, you can set it up through the following steps:

  • Register a custom domain by working with your Domain Name Service (DNS) provider or by using IBM Cloud DNS.
  • Define an alias for your custom domain by specifying the IBM-provided subdomain as a Canonical Name record (CNAME).
  • Change the host name with your custom domain in the Ingress configuration.

Example configuration for the Ingress resource:

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: myingress
spec:
   tls:
  - hosts:
    - <your custom domain>
    secretName: <secret for your customer domain>
  rules:
  - host: <your custom domain>

You can access with your customer domain:

$ curl https://<your custom domain>/<app_path>
Hello world from hello-world-deployment-56999cc7cf-vsr2q! Your app is up and running in a cluster!

Cleanup

1. Check all your resources that have the app=hello-world-deployment label:

$ kubectl get all -l app=hello-world-deployment -n project-a`

2. Then, you can delete all the resources with the label:

$ `kubectl delete all -l app=hello-world-deployment-n project-a`
  pod "hello-world-deployment-56999cc7cf-vsr2q" deleted
  service "hello-world-service" deleted
  deployment.apps "hello-world-deployment" deleted

3. Delete the Ingress resource and the namespace:

$ kubectl delete ingress myingress
ingress.extensions "myingress" deleted
$ kubectl delete namespace project-a
namespace "project-a" deleted

Summary

I hope that you now understand how you can expose an application to the outside of your Kubernetes cluster with the Ingress application load balancer (ALB) so that users can access the app from the Internet.

For more more information, you can see the following:

Be the first to hear about news, product updates, and innovation from IBM Cloud