Ravindra BagaleCourses & study guides मराठी

Chapter 65: Kubernetes Domain Names and HTTPS: Ingress, DNS, ExternalDNS, cert-manager and Gateway API

65.2 Host and path routing with DNS records: A, CNAME, alias and TTL

Why: the problem

An Ingress rule only works when the request arrives with the right host name, and that name only reaches your cluster when DNS points it there. Zomato serves zomato.com, www.zomato.com, api.zomato.com and a blog, and every one of those names is a DNS record somewhere pointing at a load balancer. If the DNS record points at an old load balancer, the best Ingress rules in the world never see a single request. DNS has a few record types you must know. An A record maps a name to an IPv4 address, and AAAA to IPv6. A CNAME maps a name to another name, so www.shop.example.com can point at shop.example.com. A CNAME cannot sit at the zone apex (example.com itself), which is a problem because AWS load balancers give you a host name, not a fixed IP. Route 53 solves it with an alias record, an A record that follows an AWS resource such as an NLB or ALB and costs nothing to query. TTL (time to live) tells resolvers how many seconds to cache the answer; a TTL of 300 means a change can take up to five minutes to reach everyone, so teams lower TTL a day before a migration. On the Ingress side, host rules decide which set of paths applies. You can list many hosts in one Ingress or split them across Ingress objects owned by different teams; the controller merges them. A wildcard host such as *.shop.example.com matches one label (a.shop.example.com but not a.b.shop.example.com). Paths then pick the Service, and some controllers can rewrite the path, so /api/orders reaches the api pod as /orders. In this lesson we route three hosts on the kind cluster from 65.1, test them with curl --resolve so no real DNS is needed, add a wildcard rule and a rewrite, and then read real DNS records with dig to see A, CNAME, alias and TTL in action.

What: every term in plain English

  • Host rule — An Ingress rule that applies only to one host name.
  • Wildcard host — *.example.com, matching exactly one extra label.
  • A record — DNS name to IPv4 address.
  • AAAA record — DNS name to IPv6 address.
  • CNAME — DNS name to another name; not allowed at the zone apex.
  • Alias record — Route 53 record that points an A or AAAA name at an AWS resource such as an ALB or NLB.
  • Zone apex — The bare domain, such as example.com, without a sub-name.
  • TTL — Seconds a resolver may cache a DNS answer.
  • curl --resolve — Forces curl to use a given IP for a host name, skipping DNS, while sending the real Host header and SNI.
  • Rewrite — Changing the request path before it reaches the backend.
Reuse the ch65 cluster and controller. Deploy web, api and admin apps. Write host rules for three names. Test with curl --resolve. Add a wildcard host. Add a path rewrite. Read real DNS with dig.
Host and path routing with DNS

How: step by step

  1. Reuse the ch65 cluster and controller. Controller ready.
  2. Deploy web, api and admin apps. Three Services.
  3. Write host rules for three names. One Ingress per team.
  4. Test with curl --resolve. Each host reaches its app.
  5. Add a wildcard host. Tenant sub-names work.
  6. Add a path rewrite. Backend sees a clean path.
  7. Read real DNS with dig. A, CNAME and TTL visible.
  8. Plan a TTL change for migration. Low TTL before cutover.

Before you write any rule, draw the request path on paper: the browser asks a resolver for shop.example.com, the resolver asks the root, then the .com servers, then the name servers listed in NS records for example.com, and gets back an alias or A record pointing at the load balancer. The browser then opens a TCP connection to that address, sends TLS with the server name (SNI) and finally sends the HTTP Host header. The load balancer forwards to the Ingress controller, which matches host and path and proxies to a pod IP. Every one of these hops can fail separately, which is why the lab tests them separately: dig for DNS, curl --resolve for the controller, kubectl get endpointslices for the pods. When Nykaa or Myntra gets a report that the site is down for some users only, the cause is very often a stale DNS cache or a record pointing at an old load balancer, not the cluster at all. Keep a habit of checking the answer from more than one resolver, for example dig @1.1.1.1 and dig @8.8.8.8, and compare the TTLs you see.

Example 1: Three host names, three teams, one controller

Goal. Three host names, three teams, one controller.

apps.sh

for a in web api admin; do
  kubectl create deployment $a -n shop --image=hashicorp/http-echo:1.0 -- /http-echo -listen=:8080 -text="$a says hi" --dry-run=client -o yaml | kubectl apply -f -
  kubectl expose deployment $a -n shop --port=80 --target-port=8080 --dry-run=client -o yaml | kubectl apply -f -
done

hosts.yaml

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: storefront
  namespace: shop
spec:
  ingressClassName: nginx
  rules:
    - host: shop.example.com
      http:
        paths:
          - {path: /, pathType: Prefix, backend: {service: {name: web, port: {number: 80}}}}
    - host: www.shop.example.com
      http:
        paths:
          - {path: /, pathType: Prefix, backend: {service: {name: web, port: {number: 80}}}}
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: api
  namespace: shop
spec:
  ingressClassName: nginx
  rules:
    - host: api.shop.example.com
      http:
        paths:
          - {path: /, pathType: Prefix, backend: {service: {name: api, port: {number: 80}}}}
    - host: admin.shop.example.com
      http:
        paths:
          - {path: /, pathType: Prefix, backend: {service: {name: admin, port: {number: 80}}}}

What each line does

  • Two Ingress objects — The storefront team and the API team own separate files; the controller merges them.
  • www and apex — Both hosts point at web; in DNS www is usually a CNAME to the apex.
  • Flow-style YAML — {path: /, ...} is the same YAML, only shorter.
  • --dry-run piped to apply — Makes the script safe to run again.
  • No DNS yet — We test with curl --resolve, which sends the real Host header.

Green output

$ bash apps.sh && kubectl apply -f hosts.yaml
ingress.networking.k8s.io/storefront created
ingress.networking.k8s.io/api created
$ for h in shop www.shop api.shop admin.shop; do curl -s --resolve $h.example.com:80:127.0.0.1 http://$h.example.com/; done
web says hi
web says hi
api says hi
admin says hi
$ kubectl get ingress -n shop
NAME         CLASS   HOSTS                                         ADDRESS
storefront   nginx   shop.example.com,www.shop.example.com         localhost
api          nginx   api.shop.example.com,admin.shop.example.com   localhost

Expected result. Four names reach three apps through one controller. curl --resolve let us test real host names with no DNS change at all, which is exactly how you test before a cutover.

Example 2: Wildcard tenants and a path rewrite

Goal. Wildcard tenants and a path rewrite.

tenants.yaml

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: tenants
  namespace: shop
spec:
  ingressClassName: nginx
  rules:
    - host: "*.stores.example.com"
      http:
        paths:
          - {path: /, pathType: Prefix, backend: {service: {name: web, port: {number: 80}}}}

rewrite.yaml

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: api-rewrite
  namespace: shop
  annotations:
    nginx.ingress.kubernetes.io/use-regex: "true"
    nginx.ingress.kubernetes.io/rewrite-target: /$2
spec:
  ingressClassName: nginx
  rules:
    - host: shop.example.com
      http:
        paths:
          - path: /api(/|$)(.*)
            pathType: ImplementationSpecific
            backend: {service: {name: api, port: {number: 80}}}

What each line does

  • *.stores.example.com — Each seller gets a sub-name such as rajesh.stores.example.com with one rule.
  • Quoted wildcard — YAML treats a leading * as an alias, so the host must be quoted.
  • One label only — a.b.stores.example.com does not match the wildcard.
  • rewrite-target /$2 — The second regex group becomes the new path, so /api/orders reaches the pod as /orders.
  • ImplementationSpecific — Required because the path is a regex, which is controller-specific.

Green output

$ kubectl apply -f tenants.yaml -f rewrite.yaml
$ curl -s --resolve rajesh.stores.example.com:80:127.0.0.1 http://rajesh.stores.example.com/
web says hi
$ curl -s -o /dev/null -w "%{http_code}\n" --resolve a.b.stores.example.com:80:127.0.0.1 http://a.b.stores.example.com/
404
$ curl -s --resolve shop.example.com:80:127.0.0.1 http://shop.example.com/api/orders
api says hi
$ kubectl logs -n ingress-nginx deploy/ingress-nginx-controller --tail=1
"GET /api/orders HTTP/1.1" 200 ... [shop-api-80] ... 10.244.1.7:8080

Expected result. The wildcard served any seller name with a single rule and refused two-level names. The rewrite let the API team keep clean routes inside the pod while the public URL keeps the /api prefix.

Example 3: Read real DNS records and plan a TTL change

Goal. Read real DNS records and plan a TTL change.

dns.sh

dig +noall +answer example.com A
dig +noall +answer www.example.com
dig +noall +answer example.com NS
dig +short TXT example.com

migration-plan.txt

Day -1  Lower TTL on shop.example.com from 3600 to 60
Day 0   Check new cluster with curl --resolve shop.example.com:443:NEW_IP
Day 0   Change the alias record to the new load balancer
Day 0   Watch old controller logs drain to zero over 1 to 2 minutes
Day +1  Raise TTL back to 300

What each line does

  • +noall +answer — Prints only the answer lines: name, TTL, class, type, value.
  • TTL column — The second field; it counts down in resolver caches.
  • NS records — Which name servers own the zone, for example Route 53 servers.
  • Lower TTL first — Caches still hold the old long TTL, so lower it a full old-TTL before the change.
  • Drain check — Old controller logs show when users have moved.

Green output

$ bash dns.sh
example.com.        2735   IN  A      93.184.215.14
www.example.com.    2735   IN  CNAME  example.com.
example.com.        2735   IN  A      93.184.215.14
example.com.        86400  IN  NS     a.iana-servers.net.
example.com.        86400  IN  NS     b.iana-servers.net.
"v=spf1 -all"

Expected result. dig shows the record type, the target and how long caches may keep it. Lowering TTL a day before a load balancer change is what lets Flipkart or Zomato move traffic in minutes instead of hours.

Every command, step by step (kind lab with kubectl)

  1. Apps

    bash apps.sh
    

    What it does: Three Services.

    service/admin created
    
  2. Hosts

    kubectl apply -f hosts.yaml
    

    What it does: Two Ingresses.

    ingress.networking.k8s.io/api created
    
  3. Test apex

    curl -s --resolve shop.example.com:80:127.0.0.1 http://shop.example.com/
    

    What it does: web.

    web says hi
    
  4. Test API

    curl -s --resolve api.shop.example.com:80:127.0.0.1 http://api.shop.example.com/
    

    What it does: api.

    api says hi
    
  5. Wildcard

    kubectl apply -f tenants.yaml
    

    What it does: Tenants.

    ingress.networking.k8s.io/tenants created
    
  6. Tenant

    curl -s --resolve rajesh.stores.example.com:80:127.0.0.1 http://rajesh.stores.example.com/
    

    What it does: Matches.

    web says hi
    
  7. Rewrite

    kubectl apply -f rewrite.yaml
    

    What it does: Regex path.

    ingress.networking.k8s.io/api-rewrite created
    
  8. Rewritten

    curl -s --resolve shop.example.com:80:127.0.0.1 http://shop.example.com/api/orders
    

    What it does: Clean path.

    api says hi
    
  9. A record

    dig +noall +answer example.com A
    

    What it does: Name to IP.

    example.com.  2735  IN  A  93.184.215.14
    
  10. CNAME

    dig +noall +answer www.example.com
    

    What it does: Name to name.

    www.example.com.  2735  IN  CNAME  example.com.
    

When it is red 1

404 for a host that is in the Ingress

Cause. Typo in host, or a wildcard used for two labels.

Fix, step by step

  1. kubectl get ingress -A -o wide.
  2. Wildcards match one label only.

When it is red 2

error converting YAML: did not find expected alphabetic or numeric character

Cause. Unquoted wildcard host.

Fix, step by step

  1. Write host: "*.stores.example.com".

When it is red 3

Rewrite sends /api/orders to the pod as /api/orders

Cause. use-regex missing or path not a regex.

Fix, step by step

  1. Add use-regex true and the capture groups.

When it is red 4

DNS change done but users still hit the old cluster

Cause. Resolvers cache the old answer until the old TTL expires.

Fix, step by step

  1. Lower TTL a day earlier.
  2. Keep the old cluster serving until logs drain.

When it is red 5

CNAME at apex rejected by DNS provider

Cause. CNAME is not allowed at the zone apex.

Fix, step by step

  1. Use a Route 53 alias record for AWS load balancers.

Practice tasks

Easy Task 1: Hosts

Why: Route.

What to do: Apply hosts.yaml.

How:
  1. Two Ingresses.
Solution
kubectl get ingress -n shop

Easy Task 2: Resolve

Why: Test.

What to do: Curl every host with --resolve.

How:
  1. 127.0.0.1.
Solution
curl -s --resolve api.shop.example.com:80:127.0.0.1 http://api.shop.example.com/

Easy Task 3: dig

Why: Read.

What to do: Read A and CNAME records for a public site.

How:
  1. +noall +answer.
Solution
dig +noall +answer www.example.com

Medium Task 4: Wildcard

Why: Tenants.

What to do: Apply tenants.yaml and test one and two labels.

How:
  1. Quote the host.
Solution
curl -s --resolve a.stores.example.com:80:127.0.0.1 http://a.stores.example.com/

Medium Task 5: Rewrite

Why: Clean.

What to do: Apply rewrite.yaml and read controller logs.

How:
  1. $2.
Solution
kubectl logs -n ingress-nginx deploy/ingress-nginx-controller --tail=5

Medium Task 6: TTL

Why: Plan.

What to do: Write a cutover plan with TTL steps.

How:
  1. Lower a day early.
Solution
cat migration-plan.txt

Hard Task 7: Split

Why: Teams.

What to do: Move admin to its own Ingress in a new namespace.

How:
  1. Service in same namespace as Ingress.
Solution
kubectl get ingress -A

Hard Task 8: Zomato

Why: Main task.

What to do: Two hosts, wildcard, rewrite and TTL plan.

How:
  1. curl --resolve proof.
Solution
kubectl get ingress -A -o wide

Homework: try at home

Zomato is moving restaurant.zomato-lab.example.com and api.zomato-lab.example.com to a new cluster: write host rules for both plus a wildcard for city sub-names, add a rewrite for /api, test every name with curl --resolve, and write a TTL plan for the DNS cutover.

Recap

  • Host rules choose the rule set and paths choose the Service.
  • Many Ingress objects can share one controller and are merged.
  • A, AAAA and CNAME records point names; Route 53 alias records point at AWS load balancers, even at the apex.
  • TTL sets cache time; lower it before a migration.
  • curl --resolve tests real host names before DNS changes.

FAQ

Q. Should each team have its own Ingress?

Usually yes. Separate objects per team or namespace keep ownership clear; the controller merges them into one config.

Q. Can an Ingress point to a Service in another namespace?

No. The backend Service must be in the same namespace as the Ingress. Gateway API allows cross-namespace routes with a ReferenceGrant.

Q. Is a rewrite always a good idea?

Use it sparingly. It hides real paths from the app, which can break redirects and links. Many teams prefer apps that understand their prefix.

Q. What TTL should I use normally?

300 seconds is a common balance. Alias records in Route 53 use the target resource's TTL.

Interview questions

  1. Explain A, CNAME and alias records.

    Model answer: A maps to an IP, CNAME maps to another name and is not allowed at the apex, alias is Route 53's apex-safe pointer to AWS resources.

  2. How would you migrate a domain to a new cluster with no downtime?

    Model answer: Lower TTL early, test the new cluster with curl --resolve, switch the record, keep the old cluster until traffic drains.

  3. How does the controller pick a backend?

    Model answer: Host header first, then the longest matching path.

  4. What does a wildcard host match?

    Model answer: Exactly one extra label.

Quick quiz

Q1. Which record maps a name to another name?

CNAME.

Q2. Can a CNAME sit at example.com?

No; use an alias record on Route 53.

Q3. What does TTL control?

How long resolvers cache the answer.

Q4. How do you test a host with no DNS?

curl --resolve.

Q5. Does *.a.com match x.y.a.com?

No, one label only.

Samajla ka?