Watch
0
0
Fork
You've already forked hyperhive
0
hyperhive/nix/container-modules/swarm-container-resolver.nix

61 lines
2.9 KiB
Nix

# The resolver file a swarm service container writes for itself.
#
# Every swarm service container shares the host netns (`privateNetwork =
# false`) and force-disables `resolvconf`, so that the `/etc/resolv.conf`
# `nixos-containers` copies in at start is not regenerated empty. That copy
# is a `cp --remove-destination` in the host-side preStart, run ONCE per
# container start — so the container's resolver is a snapshot of the host's
# file at its boot instant, and stays that snapshot for its whole life.
#
# A snapshot is not a resolver. Anything that makes the host's file wrong at
# that one instant — a resolvconf regeneration mid-deploy, a host that has
# not yet pointed itself at the bridge — leaves the container with a resolver
# it can never recover from, and the symptom surfaces arbitrarily far from
# the cause: a queue refusing every client because the auth-callout responder
# cannot look up its IdP.
#
# So the container writes the file itself, on every boot, from the one
# address that is correct on both sides of a netns boundary (the bridge IP —
# see `hive-gateway/default.nix`, which forces the host to the same value).
{
bridgeIp,
# Units in this container that resolve a name. The caller names them
# because this module cannot know them, and an unordered resolver write
# is a race that only shows up on a cold boot.
dnsConsumers ? [ ],
}:
{ lib, pkgs, ... }:
{
# ⚠️ `networking.nameservers` CANNOT replace this unit. `resolvconf` is its
# only consumer, and these containers disable it — so setting it renders no
# file and changes no behaviour, while still evaluating and deploying
# perfectly cleanly. It reads like a fix and is a no-op.
#
# ⚠️ Nor can a static `environment.etc."resolv.conf"`: that has to survive
# `etc` activation landing on top of the regular file the host already
# copied there, which is a runtime property no eval can demonstrate. This
# oneshot shape is the one every agent container already uses
# (`nix/agent-modules/network.nix`), so it has runtime evidence behind it.
systemd.services.swarm-bridge-dns = {
description = "point resolv.conf at the hive bridge resolver";
wantedBy = [ "multi-user.target" ];
after = [ "local-fs.target" ];
before = [ "network-online.target" ] ++ dnsConsumers;
serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
# Pin the journal identity; without it systemd derives one from the
# generated script's store path (an opaque `<hash>-…-start`).
SyslogIdentifier = "swarm-bridge-dns";
};
path = [ pkgs.coreutils ];
script = ''
set -eu
# `rm` first: this is a regular file the host copied in, not something
# to write through, and a leftover symlink would redirect the write.
rm -f /etc/resolv.conf
printf 'nameserver %s\n' ${lib.escapeShellArg bridgeIp} > /etc/resolv.conf
echo "swarm-bridge-dns: resolv.conf -> nameserver ${bridgeIp}"
'';
};
}