简体   繁体   中英

In Docker with root, error `EACCES: permission denied, open '/root/.config/configstore/bower-github.json'` despite that file being accessible

Setup

I'm trying to dockerize a pretty old project that uses Node 12, npm 8 and bower.

Since there's no prebuilt image that bundles these three dependencies, I'm building my own image with this Dockerfile :

FROM node:12

RUN npm install -g npm@8
RUN npm install -g bower

RUN echo "node version: $(node --version)"
RUN echo "npm version: $(npm --version)"
RUN echo "bower version: $(bower --version)"

Here's the docker-compose.yml (fragment):

version: "3.9"

services:
  frontend:
    build: ./front-end
    working_dir: /home/node/app/
    volumes:
      - ./front-end:/home/node/app/
    entrypoint: [ "/bin/bash", "-c" ]
    command:
      - |
        npm i
        bower i --allow-root
        npm start

Problem

I run it like this:

docker compose build frontend --no-cache --progress=plain
docker compose up --force-recreate frontend

It crashes like this:

my-frontend-1  | npm ERR! path /home/node/app/node_modules/ember-cli-cookie
my-frontend-1  | npm ERR! command failed
my-frontend-1  | npm ERR! command sh -c -- bower install --allow-root
my-frontend-1  | npm ERR! /home/node/app/node_modules/bower/lib/node_modules/configstore/index.js:54
my-frontend-1  | npm ERR!                             throw err;
my-frontend-1  | npm ERR!                             ^
my-frontend-1  | npm ERR!
my-frontend-1  | npm ERR! Error: EACCES: permission denied, open '/root/.config/configstore/bower-github.json'
my-frontend-1  | npm ERR! You don't have access to this file.

Analysis

Here's my reconstruction of events:

  1. First of all, it's not the bower i step of docker-compose.yml that's crashing, it's npm i . If I comment out npm i , then the script proceeds further.
  2. npm installs the ember-cli-cookie@0.2.0 package.
  3. npm calls the postinstall script of ember-cli-cookie .
  4. The postinstall script calls bower install --allow-root .
  5. The actual command executed by npm is sh -c -- bower install --allow-root .
  6. It crashes with EACCES: permission denied, open '/root/.config/configstore/bower-github.json' .

Here are permissions for the inaccessible file:

root@7d24854cf1af:/home/node/app# ls -alhF /root/.config/configstore/
total 20K
drwx------ 1 root root 4.0K Aug 24 20:16 ./
drwx------ 1 root root 4.0K Aug 24 19:55 ../
-rw------- 1 root root    2 Aug 24 20:16 bower-github.json
-rw------- 1 root root   55 Aug 24 19:55 update-notifier-npm.json

whoami returns root .

I checked permissions and username by inserting commands into docker-compose.yml immediately before npm i .

I don't understand how this can be possible: root is unable to access a file with permissions of -rw------- 1 root root .

If I try accessing it manually like this (replicating the sh -c approach):

sh -c -- "nano /root/.config/configstore/bower-github.json"

...I'm able to view the file save changes to it just fine.

I even tried adding RUN chmod -R a+rwx /root/.config/ to the end of my Dockerfile, rebuilding the image and recreating the container — it made no difference!

Question

Why is this happening and how to fix it?

PS Homework

I've found these related questions but their answers did not help me:

The cause of the problem

npm is running from the user that's invoking it, but from the user who owns current directoy.

Since the project folder is volumes: -ed into the container, npm is running with uid and gid of the host OS user. Such user does not exist in the container, so it's kinda a ghost. This user has no access to /root/.config/ , thus the failure.

A related problem

When node_modules/ is on the host OS filesystem and npm is in a container, there's gonna be a discrepancy in file ownership, preventing you from eg deleing node_modules/ from the host OS.

The solution to both problems

The graceful solution to this problem is to create a user in the container with uid and gid identical to your user in the host OS. Here's how you do it.

Dockerfile :

FROM node:12

# https://jtreminio.com/blog/running-docker-containers-as-current-host-user/
ARG USER_ID
ARG GROUP_ID

RUN if [ ${USER_ID:-0} -ne 0 ] && [ ${GROUP_ID:-0} -ne 0 ]; then \
  userdel -f node &&\
  if getent group node ; then groupdel node; fi &&\
  groupadd -g ${GROUP_ID} node &&\
  useradd -l -u ${USER_ID} -g node node &&\
  install -d -m 0755 -o node -g node /home/node &&\
  chown --changes --silent --no-dereference --recursive \
  --from=33:33 ${USER_ID}:${GROUP_ID} \
  /home/node \
  ;fi

USER node

# https://stackoverflow.com/a/59151128/901944
RUN mkdir ~/.npm-global
RUN npm config set prefix '~/.npm-global'
ENV PATH=/home/node/.npm-global/bin:$PATH

RUN npm install -g npm@8

Build the container with docker :

USER_ID=$(id -u) GROUP_ID=$(id -g) \
    docker image build \
    --build-arg USER_ID=$(id -u ${USER}) \
    --build-arg GROUP_ID=$(id -g ${USER}) \
    -t frontend \
    .

docker-compose.yml (fragment):

services:
  php:
    build:
      context: .
      dockerfile: Dockerfile
      args:
        USER_ID: ${USER_ID:-0}
        GROUP_ID: ${GROUP_ID:-0}

Build the container with docker compose :

USER_ID=$(id -u) GROUP_ID=$(id -g) docker compose build --no-cache fronend

Source

This amazing article describes the problem in detail and explores potential solutions, starting with simpler ones and explaining why they are no good and why the elaborate solution is required.

https://jtreminio.com/blog/running-docker-containers-as-current-host-user/

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM