BOOTC-DNS(7)
π NAME π
bootc-dns β DNS and /etc/resolv.conf, and literally everything you need to know about them in the BOOTC-DNS(7) page. buckle up bestie π
πΈ DESCRIPTION πΈ
okay so the biggest thing first, and I need you to hear me on this: bootc does not configure networking or select a DNS resolver. not its job, never has been. the operating system inside the container image has to provide a coherent networking and DNS policy all on its own β same way it has to provide a kernel and an init system. that policy is usually owned by the distribution or the base image. periodt.
so the move β the recommended move β is to configure DNS through the network management and resolver services that the base image picked. do not treat /etc/resolv.conf as some file you should copy from the container build environment into the booted system. that's not it. π«
β¨ Build-time and boot-time resolver configuration β¨
when an image gets built, the container runtime normally hands you temporary /etc/hostname, /etc/hosts, and /etc/resolv.conf files so your RUN instructions have working networking. cute, right? except those files describe the build environment. they are not the DNS configuration of the machine that will actually boot the image. two completely different girlies. π
and here's the vibe shift: when the image is installed and booted, there is no outer Podman or other container runtime around anymore to recreate those files. the network stack baked into the image is the one responsible for generating the booted host's resolver configuration. for more on this whole distinction, see Container runtime vs bootc runtime (see bootc-container-runtime(7)).
in particular:
- Do not copy the build host's
/etc/resolv.confinto an image. - Do not rely on the
/etc/resolv.confvisible in a networkedRUNinstruction. it may be a bind mount owned by Podman or Buildah. sneaky like that fr. - Do not use an empty regular
/etc/resolv.confas a placeholder. bootc removes it when importing the image (more on that below π). - Do not add files below
/runto an image./runis runtime state and gets recreated on every single boot.
the one thing bootc does with these files: when importing an image (with the ostree backend today), it removes /etc/resolv.conf and /etc/hostname if they are zero-length regular files β because that is exactly what a container runtime leaves behind after bind-mounting its own copies during the build (see buildah#4242 <https://github.com/containers/buildah/issues/4242>, bootc #1096 <https://github.com/bootc-dev/bootc/pull/1096> and #1167 <https://github.com/bootc-dev/bootc/pull/1167>). apart from that, bootc never reads or writes /etc/resolv.conf. never ever. π
if aContainerfilestep must intentionally replace/etc/resolv.conf, run that step with networking disabled β for example withRUN --network=none. this avoids modifying a container-runtime bind mount. and honestly it should only be necessary when you're deliberately changing the resolver policy inherited from the base image. iykyk.
π¦ Follow the base image's resolver policy π¦
a derived image should normally just retain its base image's DNS implementation. like, inherit the vibe. configure DNS servers, search domains, and per-interface behavior through that implementation rather than replacing /etc/resolv.conf.
common policies include:
- NetworkManager supplies per-link DNS configuration to systemd-resolved, and
/etc/resolv.confpoints to the local resolver stub. - NetworkManager writes a regular
/etc/resolv.confdirectly. - Another network manager or resolver owns the file under a distribution-specific policy.
β οΈ important distinction, don't get it twisted: NetworkManager and systemd-resolved are not alternatives with the same role. NetworkManager configures network interfaces and may use systemd-resolved as its DNS backend. the base image has to make sure that its selected services, the type and target of /etc/resolv.conf, and its service enablement all agree with each other. for anything beyond that, follow your distribution's networking documentation and the references in Further reading. π
environment-specific DNS configuration should generally be supplied when a machine is provisioned. but if DNS configuration is intentionally lifecycle-bound to an image, then include NetworkManager connection profiles or resolver drop-ins in the image rather than including a generated /etc/resolv.conf. this keeps the configuration declarative and makes its owner clear. slay.
π Base images using systemd-resolved π
a base image using systemd-resolved should ensure that:
- systemd-resolved is installed and enabled.
- NetworkManager or the selected network manager is configured to supply DNS information to it.
/etc/resolv.confis a symlink to a resolver file generated below/run/systemd/resolve, normally../run/systemd/resolve/stub-resolv.conf.
the upstream systemd-resolved package supplies a tmpfiles.d rule (<https://www.freedesktop.org/software/systemd/man/latest/tmpfiles.d.html>) that creates the symlink at boot, so it genuinely does not need to exist in the image:
L! /etc/resolv.conf - - - - ../run/systemd/resolve/stub-resolv.conf
it does not contain DNS server addresses β systemd-resolved creates the target under /run from runtime network configuration. base image authors should normally use the rule provided by the systemd-resolved package. a custom distribution integration can ship an equivalent vendor rule in /usr/lib/tmpfiles.d.
do not disable systemd-resolved while retaining this rule and symlink. that leaves /etc/resolv.conf pointing to a runtime file that no enabled service creates. it's giving broken. π
π Fedora CoreOS example π
Fedora CoreOS uses NetworkManager with systemd-resolved. it retains the resolver stub symlink and configures DNS through NetworkManager connection profiles. for example, its Butane configuration examples write NetworkManager keyfiles under /etc/NetworkManager/system-connections/ and set the dns and dns-search properties there. iconic behavior honestly.
see the Fedora CoreOS documentation for host network configuration <https://docs.fedoraproject.org/en-US/fedora-coreos/sysconfig-network-configuration/> and Fedora's description of its systemd-resolved change <https://fedoraproject.org/wiki/Changes/systemd-resolved>. Fedora CoreOS also has an integration test for its resolver policy <https://github.com/coreos/fedora-coreos-config/blob/testing-devel/tests/kola/networking/resolv/systemd-resolved>.
and to be clear: this is an example of a complete base-image policy, not a requirement that all bootc images use systemd-resolved. it's one way, not the only way. π
π Base images using a regular /etc/resolv.conf π
a base image may instead have NetworkManager or another service write a regular /etc/resolv.conf at runtime, on the booted host β nothing in the container build produces that file. in that case it should ensure that:
- systemd-resolved is not enabled.
- No tmpfiles rule recreates the systemd-resolved symlink.
/etc/resolv.confis absent, or is a regular file that the selected service is configured to manage.
for Fedora-derived images, removing the systemd-resolved package is generally clearer than only disabling its service: the package also owns the tmpfiles rule that creates the symlink. do the removal in a RUN --network=none step β because with networking enabled, /etc/resolv.conf is the container runtime's bind mount, and the package's uninstall scriptlet fails when it tries to handle it (package removal needs no network anyway). the inherited stub symlink is left behind by the removal, so remove it in the same step:
RUN --network=none dnf -y remove systemd-resolved && rm -f /etc/resolv.conf
if the package must remain installed, mask its tmpfiles rule with a symlink to /dev/null at /etc/tmpfiles.d/systemd-resolve.conf and disable the service.
anyContainerfileoperation that removes the inherited resolver symlink should useRUN --network=none, because a networked build step sees a bind mount at/etc/resolv.confinstead of the image's file. ask me how I know π
π§ /etc/resolv.conf is a symlink, managed by tmpfiles.d π§
content that the image provides for /etc/resolv.conf should reach it through a symlink created by a systemd-tmpfiles rule, not as a regular file sitting in the image. why? because /etc is three-way merged across upgrades, and once a regular file there has been modified locally, a later image default no longer takes effect (see Filesystem: /etc (see bootc-filesystem(7))). the merge ate your config, bestie. π«
the target depends on the policy:
- a file under
/runwhen the resolver is dynamic β this is what the systemd-resolved rule above does; - a file under
/usrwhen the configuration is truly static (below).
a regular file that a service such as NetworkManager generates at runtime is a whole different matter: the service owns it and rewrites it on every boot, so it does not carry image content and the merge behavior does not apply to it. no notes.
β Static resolver configuration β
static DNS is configured through the network stack, like any other DNS setting, and that is the preferred mechanism even when the values never change:
- NetworkManager: set
ipv4.dns/ipv6.dnson the connection profile (withipv4.ignore-auto-dns yesif DHCP must not add servers), typically together with a static address. - systemd-resolved: drop-ins in
/etc/systemd/resolved.conf.d/.
baking DNS server addresses into the image as a resolv.conf file is discouraged: those are machine or environment configuration, and the file bypasses whatever the network stack would otherwise manage. if an image must ship one anyway, put the content under /usr β for example /usr/lib/resolv.conf β and point the symlink at it with a rule mirroring the systemd-resolved one:
L /etc/resolv.conf - - - - ../usr/lib/resolv.conf
then mask the vendor systemd-resolved rule for the same path (a symlink to /dev/null at /etc/tmpfiles.d/systemd-resolve.conf; two rules for one path are an error in tmpfiles.d), configure the network stack not to manage the file (dns=none in the [main] section of NetworkManager.conf; do not enable systemd-resolved), and use RUN --network=none for the build step that removes an inherited symlink. that's the whole combo, no skips. π₯
π Further reading π
behavior such as ndots, timeouts, retries, caching, and split DNS is defined by the resolver the base image selected β not by bootc. see the systemd-resolved docs <https://www.freedesktop.org/software/systemd/man/latest/systemd-resolved.html> and NetworkManager's documentation for NetworkManager.conf <https://networkmanager.pages.freedesktop.org/NetworkManager/NetworkManager/NetworkManager.conf.html> and connection settings <https://networkmanager.dev/docs/api/latest/ref-settings.html>.
π Application containers π
application containers and bootc hosts have different runtime behavior, and this trips people up constantly. by default, Podman creates /etc/hosts, /etc/hostname, and /etc/resolv.conf for each application container. runtime options such as podman run --dns control that generated file, and --dns=none requests use of the image's file.
the DNS options to podman build apply to networked RUN instructions β they do not define the DNS policy of a host booted from the completed image. very important, don't mix those two up. see the Podman documentation for podman-run(1) <https://docs.podman.io/en/latest/markdown/podman-run.1.html> and podman-build(1) <https://docs.podman.io/en/latest/markdown/podman-build.1.html>. π
π« SEE ALSO π«
bootc(8), bootc-container-runtime(7), bootc-docs(7), bootc-filesystem(7)
and that's part 1, bestie β there's more coming, so don't go anywhere β¨π¦
β¨ VERSION β¨
v1.17.1 π
That's the whole vibe. That's the version of bootc-dns(7) you're reading right now, bestie β short section, iconic energy, no cap. β¨π
and that's a wrap on BOOTC-DNS(7) π This was the bootc-dns(7) manual page, straight from bootc version v1.17.1 π¦ go forth and resolve your DNS with main character energy, you absolute legend π«Άπ
π¦ where this page comes from
- fedora 43: bootc 1.17.1-1.fc43 Β· Apache-2.0 AND BSD-3-Clause AND MIT AND (Apache-2.0 OR BSL-1.0) AND (Apache-2.0 OR MIT) AND (Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT) AND (Unlicense OR MIT)
- fedora 44: bootc 1.17.1-1.fc44 Β· Apache-2.0 AND BSD-3-Clause AND MIT AND (Apache-2.0 OR BSL-1.0) AND (Apache-2.0 OR MIT) AND (Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT) AND (Unlicense OR MIT)
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms