KB-04 — End-to-End DNS & Traffic Flow¶
This page explains how DNS resolution and traffic routing works across every layer of the platform — from a pod making a DNS query to the response arriving at the correct backend service.
Components Involved¶
| Component | Role | Location |
|---|---|---|
| BIND | Authoritative DNS for the cluster zones | 100.115.1.21 (primary), 100.115.1.22 (secondary) |
| CoreDNS | In-cluster DNS resolver (ClusterIP 172.31.0.10) |
Pods on k8s-worker1–7 (7 replicas) |
| Nginx Ingress Controller | HTTP/HTTPS routing by hostname | DaemonSet on all 17 nodes |
| HAProxy | TLS termination for Ceph RGW S3 only | VIP 100.115.1.130 on Ceph MON nodes |
| Harbor | Container registry — direct IP, no Ingress | 100.115.1.101 (dedicated IP in BIND) |
Harbor does not use Nginx Ingress
Harbor has a dedicated IP (100.115.1.101) registered directly in BIND.
kubectl get ingress -A | grep harbor returns nothing — Harbor exposes itself
directly via its own service, not through the cluster Ingress Controller.
Both harbor.cl1.sq4.aegis.internal and harbor.mod.auh1.dev.dir point to 100.115.1.101.
Architecture Diagram¶
┌─────────────────────────────────────────────────────────┐
│ BIND DNS Servers │
│ Primary: 100.115.1.21 Secondary: 100.115.1.22 │
│ Zones: cl1.sq4.aegis.internal, mod.auh1.dev.dir │
└──────────────────────┬──────────────────────────────────┘
│ authoritative answers
│
┌──────────────────────▼──────────────────────────────────┐
│ CoreDNS (172.31.0.10:53) │
│ ClusterIP service — 7 pods on k8s-worker1–7 │
│ │
│ Resolution order: │
│ 1. kubernetes plugin → cluster.local names │
│ 2. hosts block → static overrides (interim) │
│ 3. forward to BIND → everything else │
└──────────────────────┬──────────────────────────────────┘
│ resolved IP
│
┌─────────────────────────────────┴──────────────────────────────────┐
│ │
▼ Ingress hostnames (gitlab, argocd, vault…) ▼ S3 endpoint
┌────────────────────────────────────────┐ ┌────────────────────────┐
│ Nginx Ingress Controller │ │ HAProxy VIP │
│ DaemonSet — all 17 nodes │ │ 100.115.1.130 │
│ Listens: 80/443 on every node │ │ TLS termination only │
│ Routes by Host: header │ │ → Ceph RGW backends │
└──────────────┬─────────────────────────┘ └────────────────────────┘
│
┌───────────┼───────────┐
▼ ▼ ▼
gitlab argocd vault
service service service
Scenario 1 — Pod on a Worker Node resolves gitlab.cl1.sq4.aegis.internal¶
Pod (k8s-worker3)
│
│ 1. DNS query → /etc/resolv.conf → nameserver 172.31.0.10
│
▼
CoreDNS pod (k8s-worker3 — LOCAL, no extra hop)
│
│ 2. Check kubernetes plugin → not a cluster.local name → skip
│ 3. Check hosts block → match: 100.115.1.51 → RETURN
│ (temporary — until BIND has the record)
│ OR
│ 3. forward to BIND 100.115.1.21 → A record → 100.115.1.51/52/53 → RETURN
│
▼
Pod receives: 100.115.1.51 (k8s-master1)
│
│ 4. TCP connect to 100.115.1.51:443
│
▼
Nginx Ingress Controller (running on k8s-master1 as DaemonSet)
│
│ 5. Reads Host: gitlab.cl1.sq4.aegis.internal header
│ 6. Matches Ingress rule → routes to gitlab-webservice Service
│
▼
GitLab pod (wherever it's scheduled)
Characteristics:
- DNS query stays on the same node — CoreDNS pod is co-located on every worker
- Zero extra network hops for DNS
- Ingress hit is determined by which master IP DNS returned (round-robin across .51/.52/.53)
Scenario 2 — Pod on a GPU Node resolves gitlab.cl1.sq4.aegis.internal¶
Pod (gpu3 — 100.115.1.x)
│
│ 1. DNS query → /etc/resolv.conf → nameserver 172.31.0.10
│
▼
CoreDNS ClusterIP 172.31.0.10
│
│ ⚠️ kube-proxy load-balances to one of the 7 CoreDNS pods
│ CoreDNS pods are on worker1–7, NOT on GPU nodes
│ → EXTRA network hop: gpu3 → k8s-workerX
│
▼
CoreDNS pod (k8s-workerX — REMOTE hop)
│
│ 2. Same resolution logic as Scenario 1
│
▼
Pod receives: 100.115.1.51 (or .52 or .53)
│
│ 3. TCP connect to 100.115.1.51:443
│
▼
Nginx Ingress Controller (on that master node)
│
│ 4. Routes to correct backend service
│
▼
Target pod
Characteristics: - DNS query crosses a node boundary — ~0.1–1ms additional latency per lookup - For AI/ML workloads doing frequent S3 calls or service discovery, this adds up - Mitigation: Add CoreDNS toleration for GPU nodes (or use NodeLocal DNSCache)
Scenario 3 — Pod resolves s3.cl1.sq4.aegis.internal (Ceph RGW / S3)¶
Pod (any node)
│
│ 1. DNS query → CoreDNS → BIND → 100.115.1.130
│
▼
HAProxy VIP: 100.115.1.130
│
│ 2. HAProxy terminates TLS (presents wildcard cert)
│ 3. Load-balances across 3 Ceph RGW backends
│
▼
Ceph RGW (ceph1/ceph2/ceph3 — 100.115.1.11–13)
│
│ 4. S3 API response
│
▼
Pod receives S3 response
Why HAProxy here and not Ingress?
Ceph RGW is not a Kubernetes service — it runs on bare-metal Ceph nodes outside the cluster. Nginx Ingress only routes to Kubernetes Services. HAProxy bridges the gap and also provides TLS termination so the RGW backends can stay on plain HTTP internally.
Scenario 4 — External User (VPN/Bastion) accesses argocd.cl1.sq4.aegis.internal¶
User laptop / Bastion
│
│ 1. DNS query → corporate resolver → BIND 100.115.1.21
│ 2. BIND returns A records: 100.115.1.51, 100.115.1.52, 100.115.1.53
│ OS picks one (round-robin)
│
▼
100.115.1.51 (k8s-master1) port 443
│
│ 3. Nginx Ingress terminates TLS (presents wildcard cert from cert-manager)
│ 4. Routes to argocd-server Service → ArgoCD pod
│
▼
ArgoCD UI in browser
Note: External users rely on BIND — CoreDNS is only for in-cluster pod DNS.
Until BIND has the records, external users must use /etc/hosts overrides.
DNS Resolution Order — CoreDNS¶
Query arrives at CoreDNS
│
▼
┌─────────────────────────────────┐
│ 1. kubernetes plugin │ ← *.cluster.local, *.svc.cluster.local
│ (pod/service names) │ e.g. gitlab-webservice.gitlab.svc.cluster.local
└──────────────┬──────────────────┘
│ no match
▼
┌─────────────────────────────────┐
│ 2. hosts block (interim) │ ← static overrides while BIND is being updated
│ gitlab → 100.115.1.51 │ REMOVE once BIND records are in place
│ argocd → 100.115.1.51 │
│ vault → 100.115.1.51 │
└──────────────┬──────────────────┘
│ no match (fallthrough)
▼
┌─────────────────────────────────┐
│ 3. forward . /etc/resolv.conf │ ← forwards to BIND 100.115.1.21/22
│ (BIND authoritative) │ harbor → 100.115.1.101
│ │ s3 → 100.115.1.130
└─────────────────────────────────┘
Why CoreDNS Does NOT Run on GPU or Master Nodes¶
| Node type | Schedulable for CoreDNS? | Reason |
|---|---|---|
| k8s-worker1–7 | ✅ Yes | No blocking taints |
| k8s-master1–3 | ❌ No (currently) | Taint node-role.kubernetes.io/master not tolerated |
| gpu1–7 | ❌ No | Taint nvidia.com/gpu:NoSchedule not tolerated |
CoreDNS tolerates node-role.kubernetes.io/control-plane but not node-role.kubernetes.io/master
(RKE2 sets both taints on master nodes).
Production fix — add master toleration so CoreDNS runs on 10 nodes (7 workers + 3 masters):
kubectl patch deployment rke2-coredns-rke2-coredns -n kube-system --type=json -p='[
{"op":"add","path":"/spec/template/spec/tolerations/-","value":
{"key":"node-role.kubernetes.io/master","operator":"Exists","effect":"NoSchedule"}}
]'
kubectl scale deployment rke2-coredns-rke2-coredns -n kube-system --replicas=10
Summary Table¶
| Query source | CoreDNS hop | DNS backend | Traffic lands on |
|---|---|---|---|
| Worker node pod → gitlab/argocd/vault/ask | Local (same node) | hosts block → BIND | Nginx Ingress (master node .51/.52/.53) |
| GPU node pod → gitlab/argocd/vault/ask | Remote (worker node) | hosts block → BIND | Nginx Ingress (master node .51/.52/.53) |
| Master node pod → gitlab/argocd/vault/ask | Remote (worker node) | hosts block → BIND | Nginx Ingress (master node .51/.52/.53) |
| Any pod → harbor | Local or Remote | BIND | Harbor direct (100.115.1.101) — no Ingress |
| Any pod → s3 | Local or Remote | BIND | HAProxy VIP (100.115.1.130) → Ceph RGW |
| External user/VPN | N/A (no CoreDNS) | BIND directly | Same as above |
DNS Records Reference¶
Zone: cl1.sq4.aegis.internal¶
| Hostname | IP | Via |
|---|---|---|
gitlab |
100.115.1.51/52/53 |
Nginx Ingress |
registry |
100.115.1.51/52/53 |
Nginx Ingress |
kas |
100.115.1.51/52/53 |
Nginx Ingress |
argocd |
100.115.1.51/52/53 |
Nginx Ingress |
vault |
100.115.1.51/52/53 |
Nginx Ingress |
harbor |
100.115.1.101 |
Direct (no Ingress) |
s3 |
100.115.1.130 |
HAProxy → Ceph RGW |
Zone: mod.auh1.dev.dir¶
| Hostname | IP | Via |
|---|---|---|
ask |
100.115.1.51/52/53 |
Nginx Ingress |
api |
100.115.1.51/52/53 |
Nginx Ingress |
argocd |
100.115.1.51/52/53 |
Nginx Ingress |
gitlab |
100.115.1.51/52/53 |
Nginx Ingress |
vault |
100.115.1.51/52/53 |
Nginx Ingress |
harbor |
100.115.1.101 |
Direct (no Ingress) |
s3 |
100.115.1.130 |
HAProxy → Ceph RGW |