I use a simple Linux machine in Docker. Using it with Linux, I clone my dev repository and mount the repo as a volume in Docker. Then, when I enter into the Docker container, the files in the volume belong to user 1000 in group 1000 (all is fine because Docker keeps correctly all file owners). Now I'm trying to do the same in macOS, but in my macOS machine, my uid is 501 and my gid is 20. But when I go to the container, I realize that files inside it have gid and uid 0, the same as root. What can I do to keep file ownership in Docker?
问题:
回答1:
TL;DR
The osxfs driver pretends that the files are owned by the USER
that the container runs as. If you are seeing mounted files as being owned by root, your container probably is set to run as root.
The longer version
The osxfs driver on macOS tells a bit of a lie about ownership. Here is the relevant section of the documentation (emphasis mine):
Ownership
Initially, any containerized process that requests ownership metadata of an object is told that its
uid
andgid
own the object. When any containerized process changes the ownership of a shared file system object, e.g. withchown
, the new ownership information is persisted in thecom.docker.owner
extended attribute of the object. Subsequent requests for ownership metadata will return the previously set values. Ownership-based permissions are only enforced at the OS X file system level with all accessing processes behaving as the user running Docker. If the user does not have permission to read extended attributes on an object (such as when that object’s permissions are0000
),osxfs
will attempt to add an access control list (ACL) entry that allows the user to read and write extended attributes. If this attempt fails, the object will appear to be owned by the process accessing it until the extended attribute is readable again.
In other words,
Inside the container, the osxfs driver pretends that whatever uid/gid is running in the container is also the uid/gid that owns the mounted files.
If you chown files (in the container) to something else, no chown is performed on the real files; this owner information is stored in an extended file attribute instead, and that value is used by the container (and ignored by macOS).
The real files are owned by whoever owns them in macOS, outside the container. Access control is determined using those real file ownerships, and the uid/gid of the user running the Docker applications (which is probably your login user on the Mac).
I'll use a container on my Mac as an example. I built this container, and here is part of its Dockerfile:
FROM ubuntu:16.04
RUN useradd -d /planner -m planner
WORKDIR /planner
USER planner
As you can see, this container runs as the user "planner". As is typical in Ubuntu, being the first user added to this new system, it has a uid of 1000 and a gid of 1000.
Outside, on my Mac, my uid and gid are also typical (501, 20), but not the same as the "planner" user in my container.
I run this container with an external directory mounted, which contains my code. That's so I can reload the application during development without rebuilding the container (a common use case).
version: '2'
services:
uwsgi:
image: planner:latest
build: ./uwsgi
volumes:
- ./uwsgi/planner:/planner
If I look at the source directory (./uwsgi/planner
) on my Mac, the files are owned by me (uid 501, gid 20).
-rw-r--r-- 1 dan staff 3103 Oct 24 23:28 README.md
drwxr-xr-x 4 dan staff 136 Sep 14 2016 doc
-rwxr-xr-x 1 dan staff 260 Sep 14 2016 manage.py
drwxr-xr-x 7 dan staff 238 Jan 11 00:00 site_planner
drwxr-xr-x 4 dan staff 136 Jan 10 19:07 node_modules
drwxr-xr-x 12 dan staff 408 Mar 30 12:30 planner
-rw-r--r-- 1 dan staff 112 Oct 5 10:28 requirements.txt
But looking at the mounted directory inside the container, you can see that while the paths, dates, and sizes are the same, osxfs has masked the owner and told the container OS that these files are actually owned by "planner". The actual name and uid of the user are not important here. The osxfs driver is just using whatever the current user is. If you have a user with uid 1005 named "joe", then that is what you'll see instead.
-rw-r--r-- 1 planner planner 3103 Oct 25 03:28 README.md
drwxr-xr-x 4 planner planner 136 Sep 14 2016 doc
-rwxr-xr-x 1 planner planner 260 Sep 14 2016 manage.py
drwxr-xr-x 7 planner planner 238 Jan 11 05:00 site_planner
drwxr-xr-x 4 planner planner 136 Jan 11 00:07 node_modules
drwxr-xr-x 12 planner planner 408 Mar 30 16:30 planner
-rw-r--r-- 1 planner planner 112 Oct 5 14:28 requirements.txt
Now, this is just the osxfs driver on Mac. And it is done in the name of simplicity - on a Mac you are probably doing development work, and the nuances of file permissions are just a pain you have to work around. Also, notice that you are not able to execute this kind of chown on your Mac without using sudo or another tool to elevate your privileges.
$ chown 1000 manage.py
chown: manage.py: Operation not permitted
This matters, because aside from vmnetd, all of the Docker processes running on your Mac run as you, not as root. (That includes the osxfs process, as you can see in this screenshot.)
On a Linux server, it works more like you expect it to work. For example, as part of the same service I used in my example, I have a postgres container, and it uses an external directory for its data store. On my Mac, that directory is full of files owned by me (but the container thinks they are owned by user "postgres"). But, on the server, the real uids are preserved on the external filesystem.
$ ls -ln pgdata
total 120
drwx------. 6 999 999 4096 Oct 31 21:06 base
drwx------. 2 999 999 4096 Mar 8 19:22 global
drwx------. 2 999 999 4096 Oct 31 21:06 pg_clog
drwx------. 2 999 999 4096 Oct 31 21:06 pg_commit_ts
drwx------. 2 999 999 4096 Oct 31 21:06 pg_dynshmem
drwx------. 4 999 999 4096 Oct 31 21:06 pg_logical
drwx------. 4 999 999 4096 Oct 31 21:06 pg_multixact
drwx------. 2 999 999 4096 Mar 8 19:22 pg_notify
drwx------. 2 999 999 4096 Oct 31 21:06 pg_replslot
drwx------. 2 999 999 4096 Oct 31 21:06 pg_serial
drwx------. 2 999 999 4096 Oct 31 21:06 pg_snapshots
drwx------. 2 999 999 4096 Mar 8 19:22 pg_stat
drwx------. 2 999 999 4096 Apr 4 17:08 pg_stat_tmp
drwx------. 2 999 999 4096 Mar 20 15:36 pg_subtrans
drwx------. 2 999 999 4096 Oct 31 21:06 pg_tblspc
drwx------. 2 999 999 4096 Oct 31 21:06 pg_twophase
drwx------. 3 999 999 4096 Mar 17 18:30 pg_xlog
-rw-------. 1 999 999 4 Oct 31 21:06 PG_VERSION
-rw-------. 1 999 999 4496 Oct 31 21:06 pg_hba.conf
-rw-------. 1 999 999 1636 Oct 31 21:06 pg_ident.conf
-rw-------. 1 999 999 88 Oct 31 21:06 postgresql.auto.conf
-rw-------. 1 999 999 22233 Oct 31 21:06 postgresql.conf
-rw-------. 1 999 999 37 Mar 8 19:22 postmaster.opts
-rw-------. 1 999 999 68 Mar 8 19:22 postmaster.pid
Here the files are owned by uid 999, gid 999. That is not my uid (which is 5046 on this particular server).
999 is the uid of postgres inside the container, and that is exposed externally in the file permissions here.
In other words, the issue you are having is Mac-specific, and you should not have the same issue using Linux in production.
回答2:
What can I do to keep file ownership in docker?
why do you need to do this?
if you're using a host-mounted volume (via docker run
, with -v $PWD:/my/app
args for example) in your container, then it doesn't matter what the permissions are in the image itself.
you can edit the files on your mac and the changes will be immediately reflected in the container.
this is all i ever do from my mac, and i never have issues editing files in my volume or having those changes reflected in the container