Skip to content

Exposing Your Application via HTTP Endpoint

To make your application accessible externally, you must expose it through an HTTP endpoint. This is typically achieved using the Kubernetes Gateway API, which provides a standardized way to manage ingress traffic.


Prerequisite: Gateway Controller

A Gateway Controller is required to implement the Gateway API resources. If you already have a GatewayAPI Controller installed, ensure the className matches the controller's configured class name:

spec:
  gatewayClassName: <YOUR_CONTROLLER_CLASSNAME>

Quick Setup: Gateway Controller

You can use either the NGINX Gateway Fabric or a cloud-native Gateway Controller (AWS, GCP, Azure):

NGINX Gateway Fabric

  1. Install GatewayAPI CRDs:
    kubectl kustomize "https://github.com/nginx/nginx-gateway-fabric/config/crd/gateway-api/standard?ref=v2.0.1" | kubectl apply -f -
    
  2. Deploy the NGINX GatewayAPI Controller:
    helm install ngf oci://ghcr.io/nginx/charts/nginx-gateway-fabric --create-namespace -n nginx-gateway --version 2.0.1
    
  3. Ensure all pods are running:
    kubectl get pods -n nginx-gateway
    

Cloud-Native Gateway Controllers

  • AWS: Use AWS Load Balancer Controller or Gateway API support in EKS.
  • GCP: Use GKE Gateway Controller.
  • Azure: Use Azure Application Gateway Ingress Controller.

Refer to your cloud provider's documentation for installation steps.

(Optional) TLS Configuration Using cert-manager

  1. Add the Helm cert-manager repository:

    helm repo add jetstack https://charts.jetstack.io --force-update
    

  2. Install cert-manager:

    helm upgrade --install cert-manager jetstack/cert-manager --namespace cert-manager --set config.enableGatewayAPI=true --set crds.enabled=true --create-namespace
    

  3. Ensure all cert-manager pods are running:

    kubectl get pods -n cert-manager
    

Create a cert issuer

cert-issuer.yaml
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt
spec:
  acme:
    server: https://acme-v02.api.letsencrypt.org/directory
    privateKeySecretRef:
      name: letsencrypt
    solvers:
      - http01:
          gatewayHTTPRoute:
            parentRefs:
              - name: qmig-gateway

Update the desired namespace ({{ Namespace }}) and ({{ GatewayName }}).

cert-issuer.yaml
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
  name: letsencrypt
  namespace: {{ Namespace }}
spec:
  acme:
    server: https://acme-v02.api.letsencrypt.org/directory
    privateKeySecretRef:
      name: letsencrypt
    solvers:
      - http01:
          gatewayHTTPRoute:
            parentRefs:
              - name: {{ GatewayName }}
kubectl apply -f cert-issuer.yaml

Create a Gateway

Update the desired namespace ({{ Namespace }}). Once updated, apply the configuration:

AWS NLB

If deploying on AWS and using a Network Load Balancer (NLB), ensure your Gateway specs include the following annotations for proper cross-zone load balancing and external access:

kind: Gateway
spec:
  infrastructure:
    annotations:
      service.beta.kubernetes.io/aws-load-balancer-attributes: |
        load_balancing.cross_zone.enabled=true
      service.beta.kubernetes.io/aws-load-balancer-nlb-target-type: instance
      service.beta.kubernetes.io/aws-load-balancer-scheme: internet-facing
      service.beta.kubernetes.io/aws-load-balancer-type: external

cert-issuer Annotations

Update the annotation for gateway as per cert-issuer create

  annotations:
    cert-manager.io/cluster-issuer: letsencrypt
  annotations:
    cert-manager.io/issuer: letsencrypt
gateway.yaml
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: qmig-gateway
  namespace: {{ Namespace }}
  labels:
    component: "app"
    app.kubernetes.io/name: qmig
spec:
  gatewayClassName: nginx
  listeners:
  - name: http
    protocol: HTTP
    port: 80
    allowedRoutes:
      namespaces:
        from: Same
gateway.yaml
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: qmig-gateway
  namespace: {{ Namespace }}
  labels:
    component: "app"
    app.kubernetes.io/name: qmig
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt # If cluster-issuer created
    # cert-manager.io/issuer: letsencrypt # If issuer created
spec:
  gatewayClassName: nginx
  listeners:
  - name: http
    protocol: HTTP
    port: 80
    allowedRoutes:
      namespaces:
        from: Same
  - name: https
    protocol: HTTPS
    port: 443
    allowedRoutes:
      namespaces:
        from: Same
    tls:
      mode: Terminate
      certificateRefs:
        - name: qmig-tls
kubectl apply -f gateway.yaml

(Optional) Map Domain to External IP

  • Retrieve the external IP (LoadBalancer) of the Gateway in your <namespace>:

    kubectl get gateway -n <namespace>
    

  • Update your domain's DNS settings with your domain provider to point to the external IP of the Gateway. Create an A record with the following details:

    • Type: A
    • Name: @ (or your desired subdomain, e.g., www)
    • Value: <EXTERNAL-IP> (replace with the external IP retrieved in the previous step)
    • TTL: Default or as per your provider's recommendation
  • Once updated, allow some time for DNS propagation before accessing your application using your domain.

Create HTTPRoute

Update the desired namespace ({{ Namespace }}) and replace your-domain.com. Once updated, apply the configuration:

Note

Verify the service names in your backendRefs match the services available in your namespace. For example:

backendRefs:
  - name: qmig-airflow-webserver

route.yaml
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
 name: qmig-route
 namespace: {{ Namespace }}
 labels:
   component: "app"
   app.kubernetes.io/name: qmig
spec:
 parentRefs:
 - name: qmig-gateway
   namespace: {{ Namespace }}
   sectionName: http
 hostnames:
 - "your-domain.com"
 rules:
 - matches:
   - path:
       type: PathPrefix
       value: /
   backendRefs:
   - name: qmig-app
     port: 4200
 - matches:
   - path:
       type: PathPrefix
       value: /api
   backendRefs:
   - name: qmig-eng
     port: 8080
 - matches:
   - path:
       type: PathPrefix
       value: /airflow
   backendRefs:
   - name: qmig-airflow-webserver
     port: 8080
route.yaml
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
 name: qmig-route
 namespace: {{ Namespace }}
 labels:
   component: "app"
   app.kubernetes.io/name: qmig
spec:
 parentRefs:
 - name: qmig-gateway
   namespace: {{ Namespace }}
   sectionName: http
 - name: qmig-gateway
   namespace: {{ Namespace }}
   sectionName: https
 hostnames:
 - "your-domain.com"
 rules:
 - matches:
   - path:
       type: PathPrefix
       value: /
   backendRefs:
   - name: qmig-app
     port: 4200
 - matches:
   - path:
       type: PathPrefix
       value: /api
   backendRefs:
   - name: qmig-eng
     port: 8080
 - matches:
   - path:
       type: PathPrefix
       value: /airflow
   backendRefs:
   - name: qmig-airflow-webserver
     port: 8080
kubectl apply -f route.yaml

Access Endpoint

  1. Retrieve the external IP (LoadBalancer)/Host of the HTTPRoute in your <namespace>:
    kubectl get httproute -n <namespace>
    
  2. Access the application in your browser or via curl:
    curl http://<EXTERNAL-IP>
    

If the domain is mapped, access your application using your-domain.com.

References

For detailed installation and configuration instructions, refer to the official documentation: