Docker-node: node user permissions not persisted in running container

Created on 2 Aug 2018  Β·  13Comments  Β·  Source: nodejs/docker-node

Hello all,

I have a web app that uploads a file and need the uploaded file to be persisted in a volume.

I have a Dockerfile with the following - following best practises πŸ‘

RUN mkdir /uploaded-files && \
    chown -R node:node /uploaded-files && \
USER node

In the image the ownership / access is correct

image

But when the container is running the directory is owned by 'root'.

image

But the container is running using the 'node' user.

image

The directory is mounted to a volume of the same name on the host machine. If I run an image without USER node so it's running as 'root' it all works fine.

Anyone know why the ownership of this directory is changing when the container runs?

edit----->

Even the /home/node directory is owned by root and not node πŸ˜•

Most helpful comment

@LaurentGoderre No worries, I think I've worked it out now using the below.

https://stackoverflow.com/questions/50325494/how-can-i-change-permission-of-mounted-volumes-in-docker-compose-yml-from-the-do

So I've added :rw to the end of the volume so now it looks like this.

volumes:
      - /uploaded-files:/uploaded-files:rw

And the directory in the container kept the node user ownership and it's writing files on the volume fine now.

Yay! πŸŽ‰

All 13 comments

Looks like there is a syntax error. There shouldn't be a && \ after the chown because USER is a docker directive.

Hi @LaurentGoderre

Apologise, I've typed that incorrectly.

I've tried doing the following.

RUN mkdir /uploaded-files && \
    chown -R node:node /uploaded-files
USER node
RUN mkdir /uploaded-files && \
    chown -R node:node /uploaded-files && \
    chmod -R 777 /uploaded-files
USER node

I'm not sure if it's to do with the volume on the host being owned by root?

As when I run the container without it being bound to a volume the directory in the container has node being the owner.

The docker-compose.yml is like this

version: '3'

services:
  app:
    image: app:1.0.0
    environment:
      *variables in here*
    ports:
      - "3210:3000"
    volumes:
      - /uploaded-files:/uploaded-files

volumes:
  uploaded-files:

If I stop the container, remove the volume and restart the container then it creates a volume called root_uploaded-files

If I stat the directory it is as follows

[root@ahv-docker1-dev /]# stat uploaded-files/
  File: β€˜uploaded-files/’
  Size: 4096            Blocks: 8          IO Block: 4096   directory
Device: fd02h/64770d    Inode: 96          Links: 2
Access: (0755/drwxr-xr-x)  Uid: (    0/    root)   Gid: (    0/    root)
Context: system_u:object_r:unlabeled_t:s0
Access: 2018-08-02 09:53:04.532768235 +0100
Modify: 2018-08-02 09:52:58.664793452 +0100
Change: 2018-08-02 09:52:58.664793452 +0100

The volume looks like this inspected...

[
    {
        "Driver": "local",
        "Labels": {
            "com.docker.compose.project": "root",
            "com.docker.compose.volume": "uploaded-files"
        },
        "Mountpoint": "/var/lib/docker/volumes/root_uploaded-files/_data",
        "Name": "root_uploaded-files",
        "Options": {},
        "Scope": "local"
    }
]

Does the container need to be started as a node user on the host?! I've used volumes with Solr for storing data on a volume and that has it's own user and not had this issue before.

I believe that the m,ounting in your docker compose replaces the permissions you set in the docker file with the ones from the volume. I am not too familiar with volumes, hopefully someone else faced something similar

@LaurentGoderre No worries, I think I've worked it out now using the below.

https://stackoverflow.com/questions/50325494/how-can-i-change-permission-of-mounted-volumes-in-docker-compose-yml-from-the-do

So I've added :rw to the end of the volume so now it looks like this.

volumes:
      - /uploaded-files:/uploaded-files:rw

And the directory in the container kept the node user ownership and it's writing files on the volume fine now.

Yay! πŸŽ‰

Good to know!!! Thanks for sharing!

Actually that doesn't seem to have worked.

So before doing the above I actually chown -R node:node /uploaded-files from within a running container and gave it to node user. I tested that and it worked.

I then seen the above so took down the containers in the usual manor, removed the volume.

Then just brought it up with the :rw added and just assumed that had worked.

But!!!! Then I tried it on another server and it didn't work... πŸ˜• So I've done the following:

Server B:

  • chown -R node:node /uploaded-files (as originally on Server A)
  • go into the docker exec -it app sh
  • ls -la
  • directory uploaded-files is owned by node
  • tested an upload within the app and it worked (just as Server A)
  • docker-compose down
  • edited the docker-compose and changed the service name e.g. from app to app-test
  • docker-compose up - so the container is now running under a different name
  • docker exec -it app sh
  • ls -la
  • directory uploaded-files is owned by node

πŸ˜• ❓

How is it still owned by node when this is a new container with a different service name?

So back to the original server I go...

Server A:

  • create new Dockerfile with a different mkdir. RUN mkdir /file-store && \ chown -R node:node /file-store
  • update docker-compose.yml with new volume names volumes: <ul> <li>/file-store:/file-<a href="store:rw">store:rw</a><code>md5-bd5929635d28d11cb5d157cbb688e7b1</code>volumes:<br /> file-store

  • start the app
  • go into the container docker exec -it app sh
  • ls -la
  • and πŸŽ‰ it's owned by root still
  • So that means the :rw on the volume didn't work. Okay but how did the directory in the different container on Server B still have the correct permissions after I stopped it?

    So I then pointed the container dir to the original volume / host dir...

    Server A:

    • update docker-compose volume for the service to be volumes: <ul> <li>/uploaded-files:/file-<a href="store:rw">store:rw</a><code>md5-bd5929635d28d11cb5d157cbb688e7b1</code>volumes:<br /> uploaded-files

  • So by my understanding that means file-store in the container is now mounted to uploaded-files on host
  • Do the enter container dance again
  • docker exec -it app sh
  • ls -la
  • and .... wait for it .... the directory file-store inside the running container is now owned by user node
  • So that's new container, new service, new image ... but pointing to the original directory and some how it's go that chown -R node:node /uploaded-files which I did in a different container...

    Now I admit I'm not a linux expert ... but what the?! My head hurts!

    Are the different node users using different UUIDs? id node

    @ntwrkguru Do you mean on the host? Should the host need to have a node user to actually execute docker-compose up? With the same uid & gid?

    It doesn't need to be node but your own user should have user id 1000

    The permissions of the host directory should match that of the user in the container. If it's UUID 1000, then on the host, chown 1000:1000 /some/host/dir

    Ahhhh right okay.

    So on the server there is already a user with an uid 1000.

    uid=1000(linux_bkup) gid=1001(linux_bkup) groups=1001(linux_bkup),1000(beoper) - which I believe is from Backup Exec.

    If I stat uploaded-files directory I get back

    Access: (0755/drwxr-xr-x) Uid: ( 1000/linux_bkup) Gid: ( 1000/ beoper)

    So after I chown -R node:node /uploaded-files earlier it's then given that host directory the same uid? Presume it's looking at the uid rather than the actual username then?

    I've just tried to change the uid/gid of node user as per - https://github.com/nodejs/docker-node/blob/master/docs/BestPractices.md#non-root-user

    But get this error in Travis...

    RUN mkdir /uploaded-files && \
        chown -R node:node /uploaded-files && \
        groupmod -g 500 node && \
        usermod -u 500 -g 500 node
    

    image

    From your linked page:

    If you need to change the uid/gid of the user you can use:

    RUN groupmod -g 999 node && usermod -u 999 -g 999 node

    In your Dockerfile, instead of RUN chown, simply declare a user and then create the dirs.

    ...
    USER node
    RUN groupmod -g 500 node && usermod -u 500 node
    RUN mkdir /uploaded-files
    ...
    

    Closing as answered

    Was this page helpful?
    0 / 5 - 0 ratings

    Related issues

    dionysiusmarquis picture dionysiusmarquis  Β·  3Comments

    polys picture polys  Β·  3Comments

    eyaylagul picture eyaylagul  Β·  3Comments

    actualben picture actualben  Β·  3Comments

    danbev picture danbev  Β·  3Comments