How to Access your Web Application on Kubernetes Azure<!-- --> | <!-- -->Patrick Desjardins Blog
Patrick Desjardins Blog
Patrick Desjardins picture from a conference

How to Access your Web Application on Kubernetes Azure

Posted on: September 7, 2022

The article's goal is to expose your web application on the Internet. We already explained how to publish with Azure and Kubernetes our three Docker images. However, while having the deployment and service up and running, the load-balancer was still not accessible when performing an HTTP request.

Pre-Requisite

Reverse Proxy

Between the article where I explained how to publish with Azure and Kubernetes and now, I decided to perform a change: using a reverse proxy using a single container for the frontend to redirect API calls to a second docker container that has the backend API logics. It is not a required step but it allows us to have in Kubernetes only the frontend with a service exposed publicly. It also has many other advantages, but for our goal to deploy on Microsoft Azure Kubernetes, we want to simplify our infrastructure. The reverse proxy works for all the HTTP requests that the web application performs and for the WebSocket connections.

New Docker Images

The reverse proxy required many changes. For once, we are using NGINX to reverse proxy. So, there was a need to build and publish frontend images. The backend also changed with a different endpoint for the WebSocket that is now served under the path /ws/ to differentiate from the GET/POST of HTTP which are directly under the /. That is true for the backend. From the perspective of the frontend, GET/POST is performed toward the frontend server with the path /api/.

The new images are created automatically since we created an Github Action that builds and push to the Microsoft Azure Registry Container service.

The Service Load-Balancer

The backend and Redis services are of type NodePort, and the frontend service is of type LoadBalancer. That is one key point in allowing the frontend server to be accessible outside your controlled Kubernetes environment. In the Azure portal, you can see the IP if you go under your Kubernetes Service, and click Services and ingresses.

azure services external ip

It is also possible to get the same information with the kubectrl:

1kubectl get services -n realtimepixel-prod

Which should give something in this format:

1NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
2backend-service NodePort 10.0.232.135 <none> 80:30606/TCP 10d
3frontend-service LoadBalancer 10.0.208.65 20........ .6 80:30194/TCP 10d
4redis-service NodePort 10.0.172.49 <none> 6379:30408/TCP 10d

If your code is working well on all your pods under all these services, the IP will provide your web application. Same thing if you use the frontend to perform an API call using the /api; it will work. However, if one pod is in a bad state, it will not work but still provide you with an IP. I was stubborn, and though I had a Kubernetes issue while I had a code issue. In my case, environment variables were not properly passed. If the link (ip and port) is not providing your the expected result, it is important to not assume that the code is executing properly. Maybe the pod is not crashing but the actual code is not executing the server as expected.

Static IP for the frontend service

In this step, we will assign a static IP to the frontend. The IP is still not using an ingress but shows how to have permanent access to the frontend.

1az aks show \
2 --resource-group realtimepixel_resourcegroup \
3 --name realpixelask2 \
4 --query nodeResourceGroup \
5 -o tsv
6
7az network public-ip create \
8 --resource-group MC_realtimepixel_resourcegroup_realpixelask2_eastus \
9 --name realtimepixel_public_ip \
10 --sku Standard \
11 --allocation-method static \
12 --query publicIp.ipAddress \
13 -o tsv

The result was for me 20.121.6.121

On the Microsoft Azure Portal, we can see the new entry under the Public IP addresses service.

azure publicip

Update the frontend service Helm chart to receive a new annotation and the new IP.

1apiVersion: v1
2kind: Service
3metadata:
4 {{- with .Values.frontend.annotations }}
5 annotations:
6 {{- toYaml . | nindent 4 }}
7 {{- end }}
8 name: {{ .Values.frontendServiceName }}
9 namespace: {{ .Values.namespace }}
10 labels:
11 app: {{ .Values.frontendServiceName }}
12spec:
13 loadBalancerIP: {{ .Values.azureLoadBalancerIP }}
14 type: {{ .Values.frontendService.type }}
15 ports:
16 - port: {{ .Values.frontendService.port }}
17 targetPort: {{ .Values.frontendContainerPort }}
18 selector:
19 app: {{ .Values.frontendContainerName }}

and inside the value.yml file:

1frontend:
2 annotations: {
3 "service.beta.kubernetes.io/azure-load-balancer-resource-group": "MC_realtimepixel_resourcegroup_realpixelask2_eastus"
4 }
5azureLoadBalancerIP: "20.121.6.121"

The change will make the frontend service IP remain static regardless of any other new deployment that would have changed the service IP. Still, at this point, who still does not have a domain (DNS) attached to the service? Nor do we have an HTTPS certificate (TLS/SSL).

Set an Azure DNS address to the static IP

Let's find the unique id of the public IP created in the previous step.

1az network public-ip list \
2 --query "[?ipAddress!=null]|[?contains(ipAddress, '20.121.6.121')].[id]" \
3 --output tsv

The result:

1/subscriptions/972d99d7-1ce0-4e2a-881b-43969768a358/resourceGroups/mc_realtimepixel_resourcegroup_realpixelask2_eastus/providers/Microsoft.Network/publicIPAddresses/realtimepixel_public_ip_ingress

Apply the DNS realtimepixel for the ip:

1az network public-ip update \
2 --ids /subscriptions/972d99d7-1ce0-4e2a-881b-43969768a358/resourceGroups/mc_realtimepixel_resourcegroup_realpixelask2_eastus/providers/Microsoft.Network/publicIPAddresses/realtimepixel_public_ip_ingress \
3 --dns-name realtimepixel

At this point, the service has a public DNS name: realtimepixel.eastus.cloudapp.azure.com pointing to 20.121.6.121 that point to our frontend web server.