boojum
boojum

Reputation: 741

docker-compose: create named volume as specific user

Here's a minimal docker-compose.yml:

version: "3.6"

services:
  foo:
    user: "${UID}:${GID}"
    image: node:latest
    container_name: foo
    working_dir: /var/www/foo
    volumes:
      - bar:/var/www/foo/bar

volumes:
  bar:

After running docker-compose up the named volume is created at /var/lib/docker/volumes/project_bar, and the project_bar directory is owned by root - this is fine. Although the _data directory inside it is also own by root - I would like it to be own by a specific, non-root user.

For example:

docker-compose run --rm foo sh -c "mkdir bar/foo"

will fail with mkdir: cannot create directory 'bar/foo': Permission denied.

I was under the impression that specifying user: "${UID}:${GID}" (note: uid/gid are available to docker, exported in shell they are) will solve this. Obviously, I was wrong.

Is there a way to have /var/lib/docker/volumes/project_bar/_data being own by specific user? Without chown'ing anything if possible. And without involving Dockerfile.

EDIT: To clarify, I would like /var/www/foo/bar in the container and its equivalent in /var/lib/docker/volumes to be owned by a specific, not root user.

Upvotes: 2

Views: 1902

Answers (1)

BMitch
BMitch

Reputation: 263637

You are either involving the Dockerfile, or you need to setup the volume with a separate process. The named volume will be initialized with the contents of the image, including files, directories, owners, and permissions. This happens when the volume is empty or non-existent.

So your options include:

  • update the image to include the desired ownership of that directory. Note if the image defines this as a volume, your change must preced that definition.
  • create a volume in advance with the desired ownership and mount that in the container
  • modify the entrypoint of the container to run as root, fix the permissions, and then switch to the desired user (using something like gosu)

Expanding on the second option, you can create a volume with the desired ownership and content by running a temporary container to do the task:

docker container run --rm -v bar-data:/data busybox /bin/sh -c \
  "touch /data/.initialized && chown -R ${UID}:${GID} /data"

Then in your compose file you can declare that volume as external:

version: "3.6"

services:
  foo:
    user: "${UID}:${GID}"
    image: node:latest
    container_name: foo
    working_dir: /var/www/foo
    volumes:
      - bar:/var/www/foo/bar

volumes:
  bar:
    # tell compose this volume is externally created with a different name
    external: true
    name: bar-data

That will create a volume with a single file, needed to prevent docker from reinitializing an empty volume from the image contents. This also means you need to load any data you want in the volume since it will be otherwise empty. A common method to copy data into a volume involves using tar:

tar -cC source_dir . | \
  docker run --rm -i -v foo-data:/target busybox tar -xC /target

Upvotes: 5

Related Questions