Any help from any source is appreciated.
Server has a Docker container with alpine, nginx, php. This container is able to write in bind mounted host directory, only when I set "chown -R nobody directory" to the host directory (nobody is a user in container).
I am using VSCode’s extension "Remote – SSH" to connect to server as user ubuntu. VSCode is able to edit files in that same host directory (being used for bind mount), only when I set "chown -R ubuntu directory".
Problem: if I set "ubuntu" as owner, container can’t write (using php to write), if I set "nobody" as owner, VSCode SSH can’t write. I am finding a way to allow both to write without changing directory owner user again and again, or similar ease.
Image used: https://hub.docker.com/r/trafex/php-nginx
What I tried:
In Container, I added user "nobody" to group "ubuntu". On host, directory (used as mount) was set "sudo chown -R ubuntu:ubuntu directory", user "ubuntu" was already added to group "ubuntu".
VSCode did edit, container was unable to edit. (Edit: IT WORKED, I changed the directory permission for the group to allow write)
Edit: the container already created without Dockerfile also ran and maybe edited with important changes, so maybe I can’t use Dockerfile or entrypoint.sh way to solve problem. Can It be achieved through running commands inside container or without creating container again? This container can be stopped.
Edit: I am wondering, in Triet Doan’s answer, an option is to modify UID and GID of already created user in the container, will doing this for the user and group "nobody" can cause any problems inside container, I am wondering because probably many commands for settings already executed inside container, files are already edited by php on mounted directory & container is running for days
Edit: I found that alpine has no usermod & groupmod.
2
Answers
This article wrote about this problem very nicely. I would just summarize the main ideas here.
The easiest way to tackle with this permission problem is to modify UID and GID in the container to the same UID and GID that are used in the host machine.
In your case, we try to get the UID and GID of user
ubuntu
and use them in the container.The author suggests 3 ways:
1. Create a new user with the same UID and GID of the host machine in
entrypoint.sh
.Here’s the Dockerfile version for Ubuntu base image.
The
entrypoint.sh
was created as follows:Simply build the container with the
docker build
command.The
LOCAL_UID
andLOCAL_GID
can be passed to the container in thedocker run
command.We can see that the UID and GID in the container are the same as those in the host.
2. Mount the host machine’s
/etc/passwd
and/etc/group
to a containerThis is also a fine approach and simpler at a glance. One drawback of this approach is that a new user created in a container can’t access the bind-mounted file and directories because UID and GID are different from the host machine’s ones.
One must be careful to have
/etc/passwd
and/etc/group
with read-only access, otherwise the container might access and overwrite the host machine’s/etc/passwd
and/etc/group
. Therefore, the author doesn’t recommend this way.3. Modify UID and GID with the same UID and GID of the host machine
This is mostly the same approach as No.1, but just modify the UID and GID in case a new user has been created in the container already. Assume you have a new user created in the Dockerfile, then just call these commands in either Dockerfile or
entrypoint.sh
.If your username and group name were "test", then you can use
usermod
andgroupmod
commands to modify UID and GID in the container. The taken UID and GID as environment variables from the host machine will be used for this "test" user.First, I’d recommend the container image should create a new username for the files inside the container, rather than reusing
nobody
since that user may also be used for other OS tasks that shouldn’t have any special access.Next, as Triet suggests, an entrypoint that adjusts the container’s user/group to match the volume is preferred. My own version of these scripts can be found in this base image that includes a
fix-perms
script that makes the user id and group id of the container user match the id’s of a mounted volume. In particular, the following lines of that script where$opt_u
is the container username,$opt_g
is the container group name, and$1
is the volume mount location:Then I start the container as root, and the container runs the fix-perms script from the entrypoint, followed by a command similar to:
This replaces the entrypoint that’s running as root with the application running as the specified user. I’ve got more examples of this in:
I’d avoid this and create a new user. Nobody is designed to be as unprivileged as possible, so there could be unintended consequences with giving it more access.
This is a pretty big code smell in containers. They should be designed to be ephemeral. If you can’t easily replace them, you’re missing the ability to upgrade to a newer image, and creating a lot of state drift that you’ll eventually need to cleanup. Your changes that should be preserved need to be in a volume. If there are other changes that would be lost when the container is deleted, they will be visible in
docker diff
and I’d recommend fixing this now rather than increasing the size of the technical debt.I would build a newer image that doesn’t depend on this username. Within the container, if there’s data you need to preserve, it should be in a volume.
I use the following in the entrypoint script to install it on the fly, but the shadow package should be included in the image you build rather than doing this on the fly for every new container: