Skip to content

fix(podman): mount managed /etc/hosts for all custom services#1105

Open
erhanurgun wants to merge 1 commit into
lerd-env:mainfrom
erhanurgun:fix/custom-service-hosts-isolation
Open

fix(podman): mount managed /etc/hosts for all custom services#1105
erhanurgun wants to merge 1 commit into
lerd-env:mainfrom
erhanurgun:fix/custom-service-hosts-isolation

Conversation

@erhanurgun

Copy link
Copy Markdown
Contributor

Problem

Custom services created without ShareHosts (phpmyadmin, pgadmin, mongo-express) receive no /etc/hosts mount. Podman then synthesises the file from base_hosts_file, which defaults to the host's own /etc/hosts. Any 127.0.0.1 lerd-<svc> line there — a stale entry from an older lerd, or one written for a client shim / host-proxy app — shadows the container-DNS name.

The sidecar then resolves e.g. lerd-mysql to its own loopback and fails:

mysqli::real_connect(): (HY000/2002): Connection refused

phpMyAdmin, pgAdmin and Mongo Express all break this way. PHP-FPM containers are unaffected because they already bind-mount the managed hosts file, so the two paths were inconsistent.

Fix

Mount the managed container hosts file in the else branch of GenerateCustomQuadlet, so every custom service overrides host /etc/hosts inheritance. ShareHosts services keep the browser-hosts variant for .test resolution.

if svc.ShareHosts {
    fmt.Fprintf(&b, "Volume=%s:/etc/hosts:ro,z\n", config.BrowserHostsFile())
} else {
    fmt.Fprintf(&b, "Volume=%s:/etc/hosts:ro,z\n", config.ContainerHostsFile())
}

Test

  • Updated TestGenerateCustomQuadlet_NoShareHosts to assert the managed hosts mount is present (and the browser variant is not).
  • TestGenerateCustomQuadlet_ShareHosts unchanged and passing.
  • Verified on a live rootless-podman stack: with a 127.0.0.1 lerd-mysql line present on the host, a phpMyAdmin container regenerated with the mount resolves lerd-mysql via container DNS and connects (MySQL 8.4.10), where before it returned Connection refused.

Custom services without ShareHosts received no /etc/hosts mount, so podman
synthesised the file from base_hosts_file, which defaults to the host's own
/etc/hosts. Any "127.0.0.1 lerd-<svc>" line there (a stale entry from an
older lerd, or one written for a client shim / host-proxy app) then shadows
the container-DNS name: sidecar services such as phpmyadmin, pgadmin and
mongo-express resolve lerd-mysql to their own loopback and fail with
"mysqli::real_connect(): (HY000/2002): Connection refused".

Mount the managed container hosts file in the else branch so every custom
service overrides host inheritance. ShareHosts services keep the browser-hosts
variant for .test resolution. PHP-FPM containers already bind-mount this file;
this brings sidecar services in line.
@erhanurgun
erhanurgun requested a review from a team as a code owner July 23, 2026 08:56
@geodro

geodro commented Jul 24, 2026

Copy link
Copy Markdown
Member

thanks for the patch, can I ask what the mount is actually for? I can't work out what these sidecars read out of that file, it carries localhost, host.containers.internal and the .test domains, and phpMyAdmin, pgAdmin and Mongo Express want none of those, since lerd-phpmyadmin resolves lerd-mysql through aardvark either way. So it reads like it's there to shadow the inherited file rather than supply anything, and I want to be sure that's the intent in case I'm missing a case.

The inheritance is real, I checked and my sidecars are carrying my host /etc/hosts wholesale. What I can't place is the 127.0.0.1 lerd-mysql line, I grepped the repo including install.sh and nothing on our side writes it, and the client shim runs in a throwaway container on the lerd network so it resolves through container DNS without touching the host file. Any chance you remember what put it there? If lerd wrote it that's the bug to fix, and if not we're really deciding whether to isolate sidecars on principle, which is fair but a different change.

If it is just isolation we want, podman's --hosts-file none does that while keeping its own generated entries including the container's own name, though it was renamed across versions so it'd need a capability check like the StopTimeout one.

One heads up either way, WriteFPMQuadlet calls ensureFPMHostsFile first because podman creates a directory at a missing Volume source, and EnsureCustomServiceQuadlet doesn't materialise the hosts file, so this has every custom service depending on a path nothing guarantees exists.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants