Search code examples
dockernpmdocker-composenpm-installfpm

Cannot execute npm update when using a specific docker user


I have created a php fpm containers which is associated to the host user, in this way I doesn't have any issues with the file generated within the docker container (eg: when using php artisan make:controller).

So I have this docker-compose.yml:

    version: '3.9'
    
    services:
    
      laravel-fpm:
        user: 1000
        container_name: laravel_app
        restart: always
        build:
          context: .
          dockerfile: ./docker/php-fpm/Dockerfile
        volumes:
          - ./src:/var/www/html

and this is the Dockerfile:

    FROM php:8.0.2-fpm-alpine
    WORKDIR /var/www/html
    
    RUN docker-php-ext-install pdo_mysql
    RUN docker-php-ext-install mysqli
    RUN apk add icu-dev
    
    # Installa nodejs per l'utilizzo delle dipendenze npm
    RUN apk add --update npm
    RUN npm install gulp-cli -g
    RUN npm install
    
    CMD ["php-fpm"]
    
    EXPOSE 9000

When I access within the container docker-exec -it laravel_app sh, and then I run npm install I get:

Your cache folder contains root-owned files, due to a bug in
npm ERR! previous versions of npm which has since been addressed.
npm ERR! 
npm ERR! To permanently fix this problem, please run:
npm ERR!   sudo chown -R 1000:0 "/.npm"
npm ERR! code EACCES
npm ERR! syscall mkdir
npm ERR! path /.npm
npm ERR! errno -13

This problem is related to the USER directive which I have specified on the container, is there a way to fix that?


Solution

  • The Problem

    When you're running the Docker container as uid 1000, that user doesn't exist in the container, so default paths, such as for the npm cache that would normally be in the HOME directory of the running user don't have anywhere to live, so defaults to /. During the build, you are acting as root since there is no USER directive. Additionally, the npm install inside the build is possibly creating the cache directory, but without the package.json has nothing to install.

    The Solution(s)

    1. Create the user in your Dockerfile.
    2. Change where npm is writing the cache.
    3. Pre-create the directory

    Create a User

    If you create the user, that assumes that it will always be the same user, but since you're setting the user in the Docker Compose this possibly isn't the best solution (what if you use a different user?). If you can reason which user you will be, then this might be the best option, using a USER directive in the Dockerfile.

    Change the npm cache location

    You can use a .npmrc file, and set cache=/some_dir, or on the command line npm install --cache=/some_dir to change this. I'd suggest you create somewhere sensible in the root fs, something like /npm, then cache=/npm/.npm.

    In your Dockerfile, it would look like this:

    # Set the NPM cache location
    RUN mkdir /npm && chmod a+rwx /npm
    

    Pre-create the directory

    The simplest option is probably to just pre-create the cache directory with open permissions. The Dockerfile excerpt would be something like this:

    ...
    RUN apk add --update npm
    RUN npm install gulp-cli -g
    # You don't need this if you haven't got the
    #  application code in the build.
    # RUN npm install
    RUN mkdir /.npm && chmod a+rwx /.npm
    ...
    

    If you want to persist this across containers, you could create a volume or bind mount a local folder into the container in the docker compose file.