Skip to content

Commit bba02bf

Browse files
alexghraztec-bot
authored andcommitted
fix(ci3): cache DNS on build instances to dodge link-local PPS throttling (#24105)
## Problem CI DNS failures (`curl: (6) Could not resolve host …`, e.g. the `chonk_inputs.sh` S3 download) are consistent with AWS's **link-local PPS limit**: traffic to the Amazon resolver (the VPC `.2` address / `169.254.169.253`) is capped at **~1024 packets/sec per ENI**, and over that, packets are silently dropped (`linklocal_allowance_exceeded` in `ethtool -S`). We confirmed the build's DNS path makes this likely: the devbox container **and** nested docker-in-docker both get `nameserver 172.31.0.2` and query the VPC resolver directly — no caching. The host's `systemd-resolved` *is* caching (~48% hit on host-only traffic) but listens on loopback only (`127.0.0.53`), so containers can't use it. With the build's parallelism (and the larger spot instances), the aggregate DNS rate blows past 1024 pps. ## Fix Route container DNS through the host's caching `systemd-resolved`: - Expose its stub on the instance's **primary private IP** (derived from `ip route get`, no IMDS dependency) via `DNSStubListenerExtra` — that's the one address reachable from the devbox container *and* nested dind (unlike the docker0 gateway). - Point containers at it with `docker run --dns <priv_ip>`. Non-loopback nameservers propagate through the nested dockerd, so dind inherits it. Repeat lookups become cache hits and never reach the throttled resolver. ## Safety This can only help, never break resolution: if the IP can't be derived, `systemd-resolved` isn't active, or the stub doesn't come up on the IP (5×0.5s health check via `ss`), `priv_ip` is cleared and `--dns` is omitted — leaving DNS exactly as today. No counter instrumentation included — we're treating link-local throttling as the known cause. (PR #379's `linklocal_allowance_exceeded` logging can confirm before/after if desired.) ## Validation - `bash -n` on `ci3/bootstrap_ec2`; rendered+`bash -n` the injected host-script block; verified the `ip route get` parse and the `${priv_ip:+--dns …}` expansion locally. - Full validation is the PR's own CI run: a build instance that resolves through the cache and (ideally) flat `linklocal_allowance_exceeded`.
1 parent 63337ed commit bba02bf

1 file changed

Lines changed: 31 additions & 1 deletion

File tree

ci3/bootstrap_ec2

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,36 @@ sudo systemctl mask --now apt-daily.timer apt-daily-upgrade.timer apt-daily.serv
252252
sudo sysctl fs.inotify.max_user_watches=1048576 &>/dev/null
253253
sudo sysctl fs.inotify.max_user_instances=1048576 &>/dev/null
254254
255+
# DNS caching. CI's massively parallel jobs resolve the same handful of hosts (S3,
256+
# Docker Hub, npm, cargo, github) thousands of times. By default every lookup — from
257+
# the devbox container and nested docker-in-docker alike — goes straight to the VPC
258+
# resolver, which AWS caps at ~1024 pps per ENI for link-local services; over that,
259+
# packets are silently dropped and surface as "could not resolve host".
260+
# Route container lookups through the host's (caching) systemd-resolved instead, by
261+
# exposing its stub on the instance's primary private IP — the one address reachable
262+
# from both the devbox container and nested dind — and pointing containers at it via
263+
# --dns on docker run below. priv_ip is cleared (and --dns omitted, leaving DNS
264+
# unchanged) if any step fails, so this can only help, never break resolution.
265+
priv_ip=\$(ip -4 route get 169.254.169.253 2>/dev/null | awk '{for(i=1;i<=NF;i++) if(\$i=="src"){print \$(i+1); exit}}' || true)
266+
if [ -n "\$priv_ip" ] && systemctl is-active --quiet systemd-resolved \
267+
&& echo "DNSStubListenerExtra=\$priv_ip" | sudo tee -a /etc/systemd/resolved.conf >/dev/null \
268+
&& sudo systemctl restart systemd-resolved; then
269+
# Only route containers to the cache once it's actually listening on priv_ip.
270+
for _ in 1 2 3 4 5; do
271+
sudo ss -lnu "sport = :53" 2>/dev/null | grep -qF "\$priv_ip:53" && { dns_ready=1; break; }
272+
sleep 0.5
273+
done
274+
if [ "\${dns_ready:-0}" = 1 ]; then
275+
echo "HOST: DNS cache active on \$priv_ip (systemd-resolved)."
276+
else
277+
echo "HOST: DNS cache failed to bind \$priv_ip; using default resolver."
278+
priv_ip=
279+
fi
280+
else
281+
echo "HOST: DNS cache not configured; using default resolver."
282+
priv_ip=
283+
fi
284+
255285
# Pin host processes to top CPU cores to keep benchmark cores clean.
256286
# CPU layout: physical cores 0..N/2-1, hyperthreads N/2..N-1.
257287
# OS gets top 8 physical cores + their hyperthread siblings.
@@ -302,7 +332,7 @@ start_build() {
302332
local_uid=\$(id -u)
303333
local_gid=\$(id -g)
304334
305-
docker run --privileged --rm \${docker_args:-} \
335+
docker run --privileged --rm \${docker_args:-} \${priv_ip:+--dns \$priv_ip} \
306336
--name aztec_build \
307337
--hostname $docker_hostname \
308338
-v bootstrap_ci_local_docker:/var/lib/docker \

0 commit comments

Comments
 (0)