-
-
Notifications
You must be signed in to change notification settings - Fork 389
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
Add Support for Docker Desktop and Rootless Docker on Linux #1083
Comments
FWIW, Docker Desktop is the only option (AFAIK) for running Docker on macOS, and that's where I've done all my testing. Agreed that #1082 is probably the best short term option; I'm not sure I have any great ideas on a permanent fix. The only thought I've had is that the /app mount is entirely arbitrary; if there's somewhere "safe" that we can put content that is be owned by brutus (e.g., |
As detailed in #1095, both Docker Desktop and rootless Docker use Linux namespaces to isolate the container. So, while the default user inside the container is For our use-case, we're most interested in filesystem interaction (although, network access could be important as well). For bind mounts, the Removing the diff --git a/{{ cookiecutter.formal_name }}/Dockerfile b/{{ cookiecutter.formal_name }}/Dockerfile
index 512027c..8000d8d 100644
--- a/{{ cookiecutter.formal_name }}/Dockerfile
+++ b/{{ cookiecutter.formal_name }}/Dockerfile
@@ -27,28 +27,14 @@ RUN apt-get update -y && \
python${PY_VERSION}-dev \
python${PY_VERSION}-venv
-# Ensure Docker user UID:GID matches host user UID:GID (beeware/briefcase#403)
-# Use --non-unique to avoid problems when the UID:GID of the host user
-# collides with entries provided by the Docker container.
-ARG HOST_UID
-ARG HOST_GID
-RUN groupadd --non-unique --gid $HOST_GID briefcase && \
- useradd --non-unique --uid $HOST_UID --gid $HOST_GID brutus --home /home/brutus && \
- mkdir -p /home/brutus && chown brutus:briefcase /home/brutus
-
# Ensure pip is available; do this as the brutus user
# to ensure that the pip cache is created user-readable.
-USER brutus
RUN python${PY_VERSION} -m ensurepip
# As root, Install system packages required by app
-USER root
ARG SYSTEM_REQUIRES
RUN apt-get update -y && \
apt-get install --no-install-recommends -y ${SYSTEM_REQUIRES}
-# Use the brutus user for operations in the container
-USER brutus
-
# ========== START USER PROVIDED CONTENT ==========
{{ cookiecutter.dockerfile_extra_content }} |
If removing those sections is a potential fix, we could put those parts as "template optional" - i.e., add a In the meantime - do we need to add to the documentation to clarify exactly what type of Docker install is valid (especially on the BeeWare tutorial, which is the first point of contact people have with this problem?) |
After figuring out that Python The next problem is detecting when to build the image with and without brutus. This is especially true for rootless Docker on Linux....because it seems to be using the same Docker Engine....just without root. So, things are moved around a bit and user namespace mapping is doing a lot of heavy lifting...but everything else looks mostly the same as rootful Docker. I do see something called Given this, I'm also considering a different approach altogether. Basically, launch a container (like alpine or something small) with a bind-mount in to the project and touch a file inside the bind mount. If the file on the host system is owned by root, then we'd know we need to create the brutus user....however, if the file is owned by the current user, then we'd skip brutus. I suppose another approach altogether is actually understanding and taking advantage of the user namespace mapping functionality. My current understanding is a whole range of user IDs used inside the container are mapped to the host user ID running the container.....so, maybe this is just as easy as reading the |
The context for that part: On macOS, you can mount any external volume you want into your Docker container. However, when you create a new file inside the container, the GID and UID of the file is set to the GID and UID of the user inside the docker container. By default, the Docker user is UID/GID 0 which means you end up writing files on your user's filesystem that are owned by the macOS root user outside the container. The Brutus user is created with the same GID and UID as the user outside the container, so the files that are created are readable by the user. I don't recall if the same behavior happens on Linux. FWIW - this is 100% a hack, and it also seems like a delightful opportunity for a security hole on the part of Docker - but I'm not aware of any options we can pass to Docker that make it not do this weird UID/GID stuff. |
We tested this on latest Docker Desktop on macOS and anything the container root user writes to the bind mount ends up owned by the user running Docker Desktop. Maybe this changed with osxfs....or VirtioFS....I'm not sure:
Nonetheless, Docker Desktop does not behave like this on Linux. If root writes to a bind mount on Linux, the file is owned by root on the host. At any rate, I also posted about this on the Docker forums. I was told I could copy the files in to a volume mount each time if I wanted....but this doesn't seem ideal. Alternatively, the current conditional non-root user option was confirmed as an option. Another option was to |
Interesting situation....when a deb is installed and run in a Docker Desktop container, libgtk-3 seg faults when the app starts. The same deb does install and runs fine in a VM....so I'm not gonna go down this rabbit hole right now....but FYI in case this comes up in the future. [edit] |
I've looked through so much documentation and articles about this and there doesn't appear to be a reliable way to share a directory between a host and a container while supporting write permissions for either irrespective of how Docker is configured. Most of the recommended configurations require changes to the host environment; for example, Docker's own suggestion if you try to leverage the user ID mapping:
I'm mostly down to two options:
|
I'm not sure I see how this would even work in practice - how do you exfiltrate the build artefacts?
This approach seems completely acceptable to me.
I'd agree that using the "actual" image is preferable. The |
Yeah...that |
I haven't been following this discussion, so this might not be helpful, but there is a |
Right. This also brings up more generalized thoughts I've had about this problem....fwiw While we're delegating to Docker to provide the environment to install prerequisite packages, build stub binaries, and create redistributable artifacts, we are not letting Docker manage the intermediate (yet persistent) data that we're storing in the host file system. This creates the crux of our problem as Docker must cross a boundary from what it controls in to what it does not. volume mountInstead, we could allow Docker to manage this persistent (yet ultimately ephemeral in the larger sense) data via a volume mount. So, instead of bind mounting part of the In this way, Briefcase would then need to manually manage the boundary between Docker and the host; this would namely require managing the updating of the user's source in to the volume mount as well as extracting out those redistributable artifacts. I think that would be fairly straightforward....however, we would also need to make all the assumptions Briefcase makes about the build file system (i.e. the (this also may help with support for Docker on windows) dockerfile onlyAnother thought I had was to exclusively use the Dockerfile to run Docker commands. In practice, I think this would be a multi-target Dockerfile where each target would roughly represent a Briefcase command. So, a This would, however, have the effect of basically recreating Briefcase inside a Dockerfile. As such, this doesn't seem feasible at this point. But maybe if Briefcase was originally oriented around using Docker for everything, this type of approach might make more sense. conclusionWhile it's interesting to imagine a more "docker-native" implementation, these approaches don't seem particularly feasible at this point. Or even some intermediate state of them. For instance, using a volume mount in conjunction with the host file system Another intermediate state is perhaps always using So, continuing to use the bind mount like this is probably the best option....while just trying to accommodate Docker's varying behaviors... |
I guess I can see how this would work; but if I'm understanding you correctly, there's 2 notable costs:
That's an interesting (and not insignificant) point; that said, I think the existing issues with Windows support are resolvable, just fiddly because of the path interpolation that needs to happen (and, ironically, are mostly a problem because of testing, not because of the implementation).
To me, this is "rewrite Briefcase, but in dockerfiles". Yes, it's probably possible, but... ugh :-)
...
Agreed this is possible, but not especially attractive. It resolves issue (1) from above, but at the cost of making issue (2) worse.
I think I agree. While these bugs are annoying, we're not that far from having a working solution; and while I'm always down for a massive rework/refactoring if it turns out a core implementation is "wrong" in some way, in this case I think it's more a case of there being some unaccounted for edge cases, rather than anything fundamentally wrong. |
WSL 2 with Docker DesktopOut of curiosity, I tested running Briefcase in WSL 2 with Docker Desktop running with WSL 2 integration enabled for the WSL distro I was using. To my surprise, It turns out that Docker Desktop with WSL 2 integration does not support user namespace mapping....despite Docker using a Linux VM in WSL to run the containers. (This is apparently because Docker Desktop and the WSL distro are already isolated from each other....by running in their own user namespaces.) Therefore, the files created inside the container in the bind mount directory are owned by So....this further reinforces the strategy of "perform a bind mount write and see who owns the file" is the one to continue moving forward with....there are just too many configurations without reliable ways to probe the environment to determine what to do. At any rate....this does mean the Linux commands should already all be possible on Windows with WSL 2. [edit] This even includes |
Interesting... what does |
log file header:
I wouldn't expect anything about Windows to leak through. My understanding is WSL is effectively running as a VM in Windows' hyper visor; so, the Windows environment should be isolated. It even built and ran an AppImage. |
What is the problem or limitation you are having?
Using Briefcase to create AppImages does not support Docker Desktop or rootless Docker; see #1082 and #1095.
Describe the solution you'd like
Support for Docker Desktop and rootless Docker.
On Linux, Docker Desktop complicates bind mounts because it runs containers inside a VM. Therefore, a bind mount is first translated through the VM and then in to the container. This results in existing files and directories being owned by root; files and directories created or
chown
ed inside the container result in ownership by non-existing users/groups.Docker provides these recommendations for managing this.
I do not have a native macOS environment and cannot confirm if Docker Desktop on macOS suffers the same fate.Potential solution outlined below. tldr: don't create
brutus
user in image build sinceroot
is mapped to host user.Describe alternatives you've considered
Implementing #1082 at least prevents unsuspecting users from errors that do not suggest at all their Docker platform is unsupported. Given Docker Desktop support is far from trivial (or really possible?), that may be considered sufficient.
Additional context
No response
The text was updated successfully, but these errors were encountered: