Skip to content

Commit 7d87e32

Browse files
committed
k8s: added patching of CoreDNS
Signed-off-by: Oleksander Piskun <oleksandr2088@icloud.com>
1 parent c4dc8e4 commit 7d87e32

2 files changed

Lines changed: 132 additions & 12 deletions

File tree

development/docs/keda-autoscaler-setup.md

Lines changed: 37 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -211,25 +211,50 @@ kubectl get pods -n keda
211211

212212
## Step 2: DNS setup (kind only)
213213

214-
KEDA pods need to resolve `nextcloud.local`. Add it to CoreDNS:
214+
KEDA pods need to resolve `nextcloud.local`. **HaRP does this automatically now**
215+
when `HP_K8S_HOST_ALIASES` is set, HaRP patches the CoreDNS `ConfigMap` on
216+
startup and restarts CoreDNS so that every pod in the cluster (including KEDA)
217+
can resolve the configured hostnames.
218+
219+
If you need to do it manually (or verify), the commands are:
215220

216221
```bash
217222
# Get the nginx proxy IP
218223
PROXY_IP=$(docker inspect master-proxy-1 \
219224
--format '{{(index .NetworkSettings.Networks "master_default").IPAddress}}')
220225
echo "Proxy IP: $PROXY_IP"
221226

222-
# Patch CoreDNS to resolve nextcloud.local
223-
kubectl get configmap coredns -n kube-system -o json | python3 -c "
224-
import json, sys
225-
cm = json.load(sys.stdin)
226-
corefile = cm['data']['Corefile']
227-
cm['data']['Corefile'] = corefile.replace(
228-
'forward . /etc/resolv.conf',
229-
'hosts {\n ${PROXY_IP} nextcloud.local\n fallthrough\n }\n forward . /etc/resolv.conf'.replace('\${PROXY_IP}', '${PROXY_IP}')
230-
)
231-
json.dump(cm, sys.stdout)
232-
" | kubectl apply -f -
227+
# Write the Corefile with the correct IP
228+
cat > /tmp/Corefile << EOF
229+
.:53 {
230+
errors
231+
health {
232+
lameduck 5s
233+
}
234+
ready
235+
kubernetes cluster.local in-addr.arpa ip6.arpa {
236+
pods insecure
237+
fallthrough in-addr.arpa ip6.arpa
238+
ttl 30
239+
}
240+
prometheus :9153
241+
hosts {
242+
${PROXY_IP} nextcloud.local
243+
fallthrough
244+
}
245+
forward . /etc/resolv.conf {
246+
max_concurrent 1000
247+
}
248+
cache 30
249+
loop
250+
reload
251+
loadbalance
252+
}
253+
EOF
254+
255+
kubectl create configmap coredns -n kube-system \
256+
--from-file=Corefile=/tmp/Corefile \
257+
--dry-run=client -o yaml | kubectl apply -f -
233258

234259
kubectl rollout restart deployment coredns -n kube-system
235260
```

haproxy_agent.py

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2038,6 +2038,98 @@ def _k8s_parse_host_aliases() -> list[dict[str, Any]]:
20382038
return [{"ip": ip, "hostnames": hosts} for ip, hosts in ip_to_hosts.items()]
20392039

20402040

2041+
async def _k8s_ensure_coredns_host_aliases() -> None:
2042+
"""Patch CoreDNS to resolve hostnames from HP_K8S_HOST_ALIASES cluster-wide.
2043+
2044+
In local/development setups, ``nextcloud.local`` only exists in the host's
2045+
``/etc/hosts``. Pod-level ``hostAliases`` fix this for ExApp pods, but
2046+
other K8s-native components (KEDA, monitoring, etc.) still rely on
2047+
cluster DNS. This function patches the CoreDNS ``hosts`` plugin so that
2048+
**every** pod in the cluster can resolve those names.
2049+
2050+
Only runs when ``HP_K8S_HOST_ALIASES`` is set and ``HP_K8S_ENABLED`` is
2051+
true. Errors are logged but never fatal — pod hostAliases remain as
2052+
fallback.
2053+
"""
2054+
if not K8S_ENABLED or not K8S_HOST_ALIASES_RAW.strip():
2055+
return
2056+
2057+
host_aliases = _k8s_parse_host_aliases()
2058+
if not host_aliases:
2059+
return
2060+
2061+
LOGGER.info("Ensuring CoreDNS resolves host aliases: %s", K8S_HOST_ALIASES_RAW)
2062+
2063+
try:
2064+
# 1. Read current CoreDNS ConfigMap.
2065+
status, data, _text = await _k8s_request(
2066+
"GET", "/api/v1/namespaces/kube-system/configmaps/coredns",
2067+
)
2068+
if status != 200 or not data:
2069+
LOGGER.warning("Could not read CoreDNS ConfigMap (HTTP %d), skipping.", status)
2070+
return
2071+
2072+
corefile = data.get("data", {}).get("Corefile", "")
2073+
if not corefile:
2074+
LOGGER.warning("CoreDNS ConfigMap has no Corefile entry, skipping.")
2075+
return
2076+
2077+
# 2. Build the ``hosts { … }`` block from our aliases.
2078+
hosts_lines: list[str] = []
2079+
for alias in host_aliases:
2080+
for hostname in alias["hostnames"]:
2081+
hosts_lines.append(f" {alias['ip']} {hostname}")
2082+
hosts_block = "hosts {\n" + "\n".join(hosts_lines) + "\n fallthrough\n }"
2083+
2084+
# 3. Replace existing hosts block or insert before ``forward``.
2085+
hosts_re = re.compile(r"hosts\s*\{[^}]*\}")
2086+
if hosts_re.search(corefile):
2087+
new_corefile = hosts_re.sub(hosts_block, corefile, count=1)
2088+
elif "forward ." in corefile:
2089+
new_corefile = corefile.replace("forward .", f"{hosts_block}\n forward .", 1)
2090+
else:
2091+
LOGGER.warning(
2092+
"CoreDNS Corefile has no 'hosts' block and no 'forward' directive, cannot patch."
2093+
)
2094+
return
2095+
2096+
if new_corefile == corefile:
2097+
LOGGER.info("CoreDNS already has correct host aliases, no patch needed.")
2098+
return
2099+
2100+
# 4. Patch the ConfigMap.
2101+
status, _, _text = await _k8s_request(
2102+
"PATCH",
2103+
"/api/v1/namespaces/kube-system/configmaps/coredns",
2104+
json_body={"data": {"Corefile": new_corefile}},
2105+
content_type="application/strategic-merge-patch+json",
2106+
)
2107+
if status != 200:
2108+
LOGGER.warning("Failed to patch CoreDNS ConfigMap (HTTP %d): %s", status, _text[:200])
2109+
return
2110+
2111+
# 5. Trigger a CoreDNS rollout restart (annotation change).
2112+
restart_annotation = time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime())
2113+
status, _, _text = await _k8s_request(
2114+
"PATCH",
2115+
"/apis/apps/v1/namespaces/kube-system/deployments/coredns",
2116+
json_body={
2117+
"spec": {"template": {"metadata": {"annotations": {
2118+
"harp.nextcloud.com/restartedAt": restart_annotation,
2119+
}}}}
2120+
},
2121+
content_type="application/strategic-merge-patch+json",
2122+
)
2123+
if status != 200:
2124+
LOGGER.warning("Failed to restart CoreDNS Deployment (HTTP %d): %s", status, _text[:200])
2125+
return
2126+
2127+
LOGGER.info("CoreDNS patched and restarted with host aliases: %s", K8S_HOST_ALIASES_RAW)
2128+
2129+
except Exception as exc:
2130+
LOGGER.warning("Failed to configure CoreDNS host aliases (non-fatal): %s", exc)
2131+
2132+
20412133
def _k8s_build_deployment_manifest(payload: CreateExAppPayload, replicas: int) -> dict[str, Any]:
20422134
"""Build a Deployment manifest from CreateExAppPayload."""
20432135
deployment_name = payload.exapp_k8s_name
@@ -3003,6 +3095,9 @@ async def run_http_server(host="127.0.0.1", port=8200):
30033095

30043096

30053097
async def main():
3098+
# Ensure cluster-wide DNS for host aliases before starting servers.
3099+
await _k8s_ensure_coredns_host_aliases()
3100+
30063101
spoa_task = asyncio.create_task(SPOA_AGENT._run(host=SPOA_HOST, port=SPOA_PORT)) # noqa
30073102
http_task = asyncio.create_task(run_http_server(host="127.0.0.1", port=8200))
30083103

0 commit comments

Comments
 (0)