Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dockerfile: Remove /etc/nsswitch.conf workaround #3685

Open
3 tasks done
polarathene opened this issue Dec 28, 2023 · 1 comment
Open
3 tasks done

Dockerfile: Remove /etc/nsswitch.conf workaround #3685

polarathene opened this issue Dec 28, 2023 · 1 comment
Labels
feat New feature or request.

Comments

@polarathene
Copy link

polarathene commented Dec 28, 2023

Preflight checklist

  • I could not find a solution in the existing issues, docs, nor discussions.
  • I agree to follow this project's Code of Conduct.
  • I have read and am following this repository's Contribution Guidelines.

Describe your problem

Some of the Dockerfile files in this repo (and likely other Ory projects) carry an old workaround (introduced in April 2020):

# set up nsswitch.conf for Go's "netgo" implementation
# - https://github.com/golang/go/blob/go1.9.1/src/net/conf.go#L194-L275
RUN echo 'hosts: files dns' > /etc/nsswitch.conf

# set up nsswitch.conf for Go's "netgo" implementation
# - https://github.com/golang/go/blob/go1.9.1/src/net/conf.go#L194-L275
RUN [ ! -e /etc/nsswitch.conf ] && echo 'hosts: files dns' > /etc/nsswitch.conf

This is no longer relevant since Alpine 3.16.3 which now includes /etc/nsswitch.conf, additionally since Go 1.16 the referenced logic has been changed to not prefer dns files, but instead files dns (preferring /etc/hosts before querying DNS).

Describe your ideal solution

Remove the relevant lines from the Dockerfile files across Ory projects.

Workarounds or alternatives

No issue, just communicating that the content is redundant to maintainers.

Version

2.1.2

@polarathene polarathene added the feat New feature or request. label Dec 28, 2023
@polarathene
Copy link
Author

Context

When /etc/nsswitch.conf does not exist, previously Go static builds (CGO_ENABLED=0) on Linux would perform a host lookup by first querying DNS with /etc/hosts as a fallback.

Thus the workaround of adding a /etc/nsswitch.conf file is no longer necessary to carry, so long as you build with Go 1.16 or newer.

Verification

The original golang bug report has a simple reproduction with building a basic Go program.

However to easily reproduce the bug and that demonstrate the fix, I've provided an alternative reproduction that compares past Caddy image releases.

Additional info - References & Timeline (click to expand)

Reproduction Config

Using Docker Compose, all we need is a single compose.yaml:

# compose.yaml

services:
  example:
    image: go-dns-bug
    container_name: nsswitch-example
    # Inline Dockerfile build
    # Purpose: Remove `/etc/nsswitch.conf` from the image
    build:
      # CADDY_VERSION below is not a Dockerfile build ARG,
      # Within a compose config, it is interpolated from ENV:
      # https://docs.docker.com/compose/environment-variables/env-file/#interpolation
      dockerfile_inline: |
        FROM caddy:${CADDY_VERSION:-2.3.0}-alpine AS base

        FROM base AS remove-conf
        RUN rm /etc/nsswitch.conf
      # Using an ENV, can change the build target to toggle removing /etc/nsswitch.conf
      target: ${BUILD_TARGET:-remove-conf}
      # Assists with prune filter for cleanup afterwards, as base images are years old:
      labels:
        - "prune-marker=go-dns-bug"
    # Appends to the run-time generated `/etc/hosts`:
    extra_hosts:
      - "example.com:127.0.0.1"
    ports:
      - "80:80"
    configs:
      - source: caddyfile
        target: /etc/caddy/Caddyfile

# Inline config file content requires Docker Compose v2.23.1 (Nov 2023).
# For earlier releases, create a file with the content and
# volume mount it to: /etc/caddy/Caddyfile
configs:
  caddyfile:
    content: |
      {
        admin example.com:1337
      }

      # Optional, can test connection with `curl localhost`
      :80 {
        log
        respond "hello!"
      }

Reproduction Commands

The above compose.yaml file bundles the Caddyfile config and Dockerfile via Docker Compose features (inline content + Dockerfile).

This makes it simple to run a few commands to test the following variants with ENV vars.

# The default will fail (Caddy 2.3.0 with `/etc/nsswitch.conf` removed):
$ docker compose up --force-recreate --build

nsswitch-example  | run: loading initial config: loading new config: starting caddy administration endpoint: listen tcp 93.184.216.34:1337: bind: cannot assign requested address
nsswitch-example exited with code 1

# Caddy 2.3.0 with `/etc/nsswitch.conf` provided from image works (`/etc/hosts` takes priority over DNS lookup):
$ BUILD_TARGET=base docker compose up --force-recreate --build

# Caddy 2.4.0 is consistent with or without `/etc/nsswitch.conf`,
# due to the release being built with Go 1.16 that fixes the logic:
$ CADDY_VERSION=2.4.0 BUILD_TARGET=base docker compose up --force-recreate --build
$ CADDY_VERSION=2.4.0 docker compose up --force-recreate --build
Context for above commands (collapsed for brevity)
  • --force-recreate is optional is appended to avoid any confusion that container re-use can cause.
  • --build is required to trigger building variants with ENV provided to commands below.
  • The default build target removes /etc/nsswitch.conf, BUILD_TARGET ENV is used to test the original image (both images bundle the /etc/nsswitch.conf workaround, they use Alpine before 3.16).
  • The default image is Caddy 2.3.0 (built with Go 1.15), thus it is reliant upon /etc/nsswitch.conf.
  • The final commands demonstrate that /etc/nsswitch.conf is not relevant for Caddy 2.4.0 (built with Go 1.16).

Optionally test the connection is working:

# `-w "\n"` is only to avoid affecting the terminal prompt position
$ curl -w "\n" localhost

hello!

For proper reproduction, it's worth noting that the Caddyfile configured admin address needs to resolve to an IP that's invalid to bind to within the container.

  • If the FQDN uses a reserved TLD like .test, typically the DNS query will fail and /etc/hosts will provide the fallback if one is available.
  • Changing example.com to example.test will demonstrate that even the failing case can work then, provided it can be resolved by a /etc/hosts entry (eg: added via compose config extra_hosts).

Reproduction Cleanup

$ docker compose down

# Target the images created for pruning via a label filter,
# since the base images (now untagged) are from years ago:
$ docker image prune --all --filter 'label=prune-marker=go-dns-bug'

Additional Info

Related to the topic, but not relevant.

In Nov 2022, Go 1.20 (released Feb 2023) changes DNS for macOS to always defer to the system DNS resolver, regardless of CGO_ENABLED=0. This addresses similar DNS issues for that platform.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feat New feature or request.
Projects
None yet
Development

No branches or pull requests

1 participant