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

BuildKit builds (via Docker) are broken if /etc/hosts or /etc/resolv.conf is replaced #1267

Open
rassie opened this issue Nov 19, 2019 · 21 comments
Labels
area/feature-parity Feature parity with classic builder

Comments

@rassie
Copy link

rassie commented Nov 19, 2019

My Dockerfile:

from archlinux:20191105
run pacman -Sy --noconfirm filesystem

The filesystem package contains most of the base system files, as can be seen at https://www.archlinux.org/packages/core/x86_64/filesystem/. If it's upgraded, it tries to write /etc/hosts and /etc/resolv.conf, which leads to errors with BuildKit ("classical" Docker build is fine):

$ DOCKER_BUILDKIT=0 docker build .
Sending build context to Docker daemon  159.8MB
Step 1/2 : from archlinux:20191105
20191105: Pulling from library/archlinux
Digest: sha256:3fcb6f0c3a1266b579f7d5a89cbb66db1530e8dd533794b9c9588b630255b754
Status: Downloaded newer image for archlinux:20191105
 ---> 5ee688d008f4
Step 2/2 : run pacman -Sy --noconfirm filesystem
 ---> Running in f092dfd264b8
:: Synchronizing package databases...
downloading core.db...
downloading extra.db...
downloading community.db...
resolving dependencies...
looking for conflicting packages...

Packages (1) filesystem-2019.10-2

Total Download Size:   0.03 MiB
Total Installed Size:  0.04 MiB
Net Upgrade Size:      0.00 MiB

:: Proceed with installation? [Y/n] 
:: Retrieving packages...
downloading filesystem-2019.10-2-x86_64.pkg.tar.xz...
checking keyring...
checking package integrity...
loading package files...
checking for file conflicts...
checking available disk space...
:: Processing package changes...
upgrading filesystem...
warning: directory permissions differ on /srv/ftp/
filesystem: 755  package: 555
:: Running post-transaction hooks...
(1/4) Creating system user accounts...
(2/4) Applying kernel sysctl settings...
  Skipped: Current root is not booted.
(3/4) Creating temporary files...
[/usr/lib/tmpfiles.d/journal-nocow.conf:26] Failed to resolve specifier: uninitialized /etc detected, skipping
All rules containing unresolvable specifiers will be skipped.
(4/4) Arming ConditionNeedsUpdate...
Removing intermediate container f092dfd264b8
 ---> a7fa3f88205d
Successfully built a7fa3f88205d
docker build .
[+] Building 16.4s (5/5) FINISHED                                                                                                    
 => [internal] load build definition from Dockerfile                                                                            0.1s
 => => transferring dockerfile: 105B                                                                                            0.0s
 => [internal] load .dockerignore                                                                                               0.1s
 => => transferring context: 2B                                                                                                 0.0s
 => [internal] load metadata for docker.io/library/archlinux:20191105                                                           0.5s
 => CACHED [1/2] FROM docker.io/library/archlinux:20191105@sha256:3fcb6f0c3a1266b579f7d5a89cbb66db1530e8dd533794b9c9588b630255  0.0s
 => ERROR [2/2] RUN pacman -Sy --noconfirm filesystem                                                                          15.7s
------                                                                                                                               
 > [2/2] RUN pacman -Sy --noconfirm filesystem:                                                                                      
#5 0.578 :: Synchronizing package databases...                                                                                       
#5 1.578 downloading core.db...                                                                                                      
#5 3.764 downloading extra.db...                                                                                                     
#5 7.726 downloading community.db...                                                                                                 
#5 14.71 resolving dependencies...
#5 14.72 looking for conflicting packages...
#5 14.72 
#5 14.72 Packages (1) filesystem-2019.10-2
#5 14.72 
#5 14.72 Total Download Size:   0.03 MiB
#5 14.72 Total Installed Size:  0.04 MiB
#5 14.72 Net Upgrade Size:      0.00 MiB
#5 14.72 
#5 14.72 :: Proceed with installation? [Y/n] 
#5 14.72 :: Retrieving packages...
#5 15.30 downloading filesystem-2019.10-2-x86_64.pkg.tar.xz...
#5 15.51 checking keyring...
#5 15.56 checking package integrity...
#5 15.59 loading package files...
#5 15.59 checking for file conflicts...
#5 15.59 checking available disk space...
#5 15.59 error: Partition /etc/resolv.conf is mounted read only
#5 15.59 error: Partition /etc/hosts is mounted read only
#5 15.59 error: not enough free disk space
#5 15.59 error: failed to commit transaction (not enough free disk space)
#5 15.60 Errors occurred, no packages were upgraded.
------
@tonistiigi
Copy link
Member

What version of docker is this?

@rassie
Copy link
Author

rassie commented Nov 19, 2019

I can give you an exact version when I'm at the console again, but it's whatever the current version for Ubuntu is (Docker's repositories, not Ubuntu's). I've also reproduced the problem with a current -dind Docker container.

@rassie
Copy link
Author

rassie commented Nov 20, 2019

@tonistiigi my version is

Client:
 Debug Mode: false

Server:
 Containers: 7
  Running: 0
  Paused: 0
  Stopped: 7
 Images: 106
 Server Version: 19.03.5
 Storage Driver: overlay2
  Backing Filesystem: extfs
  Supports d_type: true
  Native Overlay Diff: true
 Logging Driver: json-file
 Cgroup Driver: cgroupfs
 Plugins:
  Volume: local
  Network: bridge host ipvlan macvlan null overlay
  Log: awslogs fluentd gcplogs gelf journald json-file local logentries splunk syslog
 Swarm: inactive
 Runtimes: runc
 Default Runtime: runc
 Init Binary: docker-init
 containerd version: b34a5c8af56e510852c35414db4c1f4fa6172339
 runc version: 3e425f80a8c931f88e6d94a8c831b9d5aa481657
 init version: fec3683
 Security Options:
  apparmor
  seccomp
   Profile: default
 Kernel Version: 5.3.0-21-generic
 Operating System: Ubuntu 18.04.3 LTS
 OSType: linux
 Architecture: x86_64
 CPUs: 8
 Total Memory: 31.22GiB
[snip]
 Docker Root Dir: /var/lib/docker
 Debug Mode: false
 Registry: https://index.docker.io/v1/
 Labels:
 Experimental: false
 Insecure Registries:
  127.0.0.0/8
 Live Restore Enabled: false

WARNING: No swap limit support

@tonistiigi
Copy link
Member

Yes, this is somewhat expected by the current implementation. These files are configured by the container runtime. Even with the old implementation, these files do not really persist, you can write into them but the next command will not see the data you wrote, leading to a different error case. BuildKit will not allow writes instead of silently ignoring them. We could try to keep compatibility but it does have a bit of a performance overhead that would apply to all the containers, not just the ones the try to write to these files.

@ShemTovYosef
Copy link

I edited them to fake the docker hostname for applications that rely on these files and it helped and needed just during build stage due the limit to change the host.
For running containers we can specify the exactly hostname and edit /etc/hosts without any limits so this feature is missing in buildx

@qualiaa
Copy link

qualiaa commented Apr 17, 2020

I was having this issue, under the impression that --add-host was a runtime only flag -- it turns out I was wrong, and the solution for me was to use docker build --add-host=hostname:ip ... and remove modification of /etc/hosts from my Dockerfile. Not sure this will work for every use-case, though.

@ShemTovYosef
Copy link

Hi,

If you want to set specific hostname for during build time, now it implemented under this pull request:
#1339
You can vote for it to be merged asap.

@jamshid
Copy link

jamshid commented May 26, 2020

Also running into this... Is there any way to allow DOCKER_BUILDKIT=1 docker build . with below Dockerfile to succeed, so a legacy package installation does not have to be rewritten?

It's okay if the /etc/hosts changes are thrown away (pre-DOCKER_BUILDKIT behavior), the package installer just can't get the Read-only file system error.

I tried RUN --mount=type=tmpfs ... but that needs to replace the entire /etc directory and I don't want to lose other changes made by the legacy package installation.

FROM centos:6.10 as intermediate

# A legacy package installation tries something like this, which fails with DOCKER_BUILDKIT=1
#     /bin/sh: /etc/hosts: Read-only file system
#
RUN echo 127.0.0.1 foo >> /etc/hosts

PS: this older issue is not really related: moby/moby#11950

@tommyjcarpenter
Copy link

tommyjcarpenter commented Jan 27, 2021

I am also running into this, just trying to build a simple archlinux container. Turning off buildkit solves this problem. It would appear recently (sometime, in 2020 maybe, between June and December?) Docker for Mac made a signfigant shift to build kit? This same Dockerfile that used to work now does not.

I posted this question before finding this thread, for full details: https://unix.stackexchange.com/questions/631177/arch-linux-in-docker-on-a-free-system-is-running-out-of-space/631178#631178

@tonistiigi
Copy link
Member

I don't think there are plans to "fix" this. As I explained before these files are not modifiable in containers and managed by the runtime. Changing them leads to confusing behavior and broken images. --add-host works as intended also in BuildKit.

@tommyjcarpenter
Copy link

tommyjcarpenter commented Jan 27, 2021

I understand. But I think what will happen is that people are going to hit this and it will be "obscure" to them because it's indirect. I'm not directly doing anything with resolve or hosts. I'm merely building the same docker image that I've built for years, in the same way, and now suddenly it doesn't work. The error that gets posted out, as I wrote in that stackexchange post highlights the error here, albeit with a minor red herring about space, but again to the user it's Indirect unless they are doing things (purposefully) with the hosts or resolve file. People running say just an OS like Arch or Ubuntu, this could be a "hidden" landmine in their typical work flow; especially since they may not be aware that common docker tools have recently switched to buildkit "under the covers" (docker for mac for example)

@thaJeztah
Copy link
Member

I don't think there are plans to "fix" this. As I explained before these files are not modifiable in containers and managed by the runtime. Changing them leads to confusing behavior and broken images. --add-host works as intended also in BuildKit.

It's a tricky one; I agree that for users that want to customise during build, --add-host should be the recommendation; I guess (reading the discussion above) the problem, is that some packages (for whatever reason) appear to want to have these files writable. While it's worth looking why they want to do so, generally this would be out of control for the user that performs the build.

I saw moby/moby#11950 was linked above; probably relevant here are moby/moby#2267, and moby/moby#5129, which (although not "persisting"), makes both of these writable by mounting the files.

I do share the concerns about performance though, so not sure what's best.

@binhex
Copy link

binhex commented Jan 27, 2021

@thaJeztah sorry to labour the issue, but am i right in saying that there is still no workaround for the original issue, where installing arch linux package 'filesystem' causes a read only error due to bind mounts to the host?, i have gone through the links above but cannot see a way around this issue that relate to installation of a package that needs write access to /etc/hosts and /etc/resolv.conf please correct me if i'm wrong here.

@thaJeztah
Copy link
Member

thaJeztah commented Jan 28, 2021

@binhex correct; BuildKit currently mounts these read-only;

With BuildKit:

DOCKER_BUILDKIT=1 docker build --no-cache --progress=plain -<<EOF
FROM busybox
RUN mount | grep /etc
RUN cat /etc/hosts
EOF
#5 [2/2] RUN mount | grep /etc
#5 sha256:30dbb0d55d6b8a70aaf13d4655662c2ee23283d7fcbccceb70ff0a011adef4f1
#5 0.277 /dev/vda1 on /etc/resolv.conf type ext4 (ro,nosuid,nodev,noexec,relatime)
#5 0.277 /dev/vda1 on /etc/hosts type ext4 (ro,nosuid,nodev,noexec,relatime)
#5 DONE 0.4s

Without BuildKit:

DOCKER_BUILDKIT=0 docker build --no-cache --progress=plain -<<EOF
FROM busybox
RUN mount | grep /etc
EOF
Step 2/2 : RUN mount | grep /etc
 ---> Running in fbe072913354
/dev/vda1 on /etc/resolv.conf type ext4 (rw,relatime)
/dev/vda1 on /etc/hostname type ext4 (rw,relatime)
/dev/vda1 on /etc/hosts type ext4 (rw,relatime)

If your intent is to install the filesystem package to build a custom/more recent "base image" for arch linux, please refer to https://docs.docker.com/develop/develop-images/baseimages/

@binhex
Copy link

binhex commented Jan 29, 2021

Just for anybody who finds this useful, i stumbled across the OP issue when using GitHub Actions and attempting to build a Arch Linux Docker image 'from scratch' using the buildx step:-

        uses: docker/setup-buildx-action@v1

if i then used the following 'uses' action then it blew up with the same read only issue for /etc/hostsand /etc/resolv.conf as OP.

        uses: docker/build-push-action@v2

the solution for me is simply to ignore the filesystem package during upgrade by doing the following:-

sed -i -e 's~#IgnorePkg.*~IgnorePkg = filesystem~g' '/etc/pacman.conf'

pacman then happily ignores the upgrade of filesystem and completes, this is obviously not ideal but it works and im happy enough to share this as a workaround for now until when/if the filesystem package stops attempting to modify the two files mentioned above.

Wynndow added a commit to alphagov/verify-infrastructure that referenced this issue Jun 2, 2021
Since we started building the nginx-tls image in the pipeline with the
vito/oci-build-task image, the `build-nginx-tls` Concourse job has been
failing.

The build attempts to change the owner of the `/etc/hosts` directory to
`nginx`. This fails with the error message:

        `chown: /etc/hosts: Read-only file system`

The oci-build-task uses BuildKit directly under the hood, rather than
with Docker. I believe this is causing the issue.

It seems that `/etc/hosts` is treated specially by the build runtime,
and BuildKit does not allow writes to the dir. There is some discussion
of it in [this issue.](moby/buildkit#1267).

It seems that [you need to manually turn BuildKit on in Docker](https://docs.docker.com/develop/develop-images/build_enhancements/), which
would explain why this has only just broken.

To get around this issue, we can change the owner of `/etc/hosts` after
the build, in the entrypoint script. To do this we need to be the root
user, which is why the `USER nginx` instruction has been removed from the
Dockerfile.

Once the owner of `/etc/hosts` has been changed we can switch to the
`nginx` user. To do this from the entrypoint script the nginx users
needs to have a login shell set. That's what the `sed` command is doing.

I'm not 100% sure that this is the right approach for this. I'm not sure
why the `/etc/hosts` dir needs to be owned by nginx in the first place,
but it's probably been done for a good reason. But the simplest fix
would be to not change the ownership at all.
@ian-h-chamberlain
Copy link

A lot of posts here mention --add-host as the proper way to change /etc/hosts, but what about /etc/resolv.conf? My organization uses different nameservers on the host than we do during build, so what we'd probably use ideally is the --dns option that docker run has. However there appears to be no such option for docker build, so for now using BuildKit doesn't seem to be an option for us.

Is there any way to explicitly set nameservers for a single docker build command?

ian-h-chamberlain added a commit to ian-h-chamberlain/holo-docker that referenced this issue Sep 21, 2023
Runners use Docker v24 now, which uses BuildKit by default. This broke
the build when reinstalling `filesystem` due to
moby/buildkit#1267

Also expand out the package list in the Dockerfile for easier diffs when
adding/removing packages.
@TingxinLi
Copy link

I don't think there are plans to "fix" this. As I explained before these files are not modifiable in containers and managed by the runtime. Changing them leads to confusing behavior and broken images. --add-host works as intended also in BuildKit.

I understand the situation to use --add-host for docker build, but how to use it for buildctl? I couldn't find any way to use --add-host in buildctl build

@tonistiigi
Copy link
Member

@TingxinLi --opt add-hosts=name=ip,name2=ip2

@TingxinLi
Copy link

@TingxinLi --opt add-hosts=name=ip,name2=ip2

Thanks, I figured it out after reading the source code.

@mzihlmann
Copy link

mzihlmann commented Jan 23, 2024

how can i add-host to a bakefile?

edit:
this does the trick for me, i can pass network=host when creating the builder (note: there's security implications for that)

docker buildx create --driver-opt network=host

@thaJeztah thaJeztah added the area/feature-parity Feature parity with classic builder label Mar 6, 2024
@Miroka96
Copy link

I have to add to this issue as well... I either need /etc/hosts to be writable or need the hostname to not resolve to a loopback address.
Preferably, the hostname in /etc/hosts should resolve to the primary IPv4 address of the container like it does in non-buildkit mode.

Reasoning: I have to prebuild an Oracle database during a container build, sigh... (With their current free database version 23.5, they don't accept loopback addresses as IPs for the given hostname and this hostname is taken from /etc/hostname, which is also read-only and correlates with the 127.0.0.1 entry in /etc/hosts. Adding the hostname with a different IP again using --add-host is ignored because it gets appended to the end of /etc/hosts. For now, I have to stick to the non-buildkit Docker build mode because it seems easier than getting a fix from Oracle...)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area/feature-parity Feature parity with classic builder
Projects
None yet
Development

No branches or pull requests