Error running grunt in docker: Fatal error: Unable to find local grunt

Error running grunt in docker: Fatal error: Unable to find local grunt

我正在尝试 运行 我的项目,所有依赖项都在 docker 中,但由于某种原因,我被 g运行t 依赖项困住了 g运行 t 失败并显示找不到本地 g运行t.

的错误

我创建了一个如何重现这个的例子:

.
├── code
│   ├── bower.json
│   ├── Gruntfile.js
│   └── package.json
├── docker-compose.yml
└── frontend.dockerfile

docker-compose.yml:

version: "2"
services:
  frontend:
    build:
      context: .
      dockerfile: frontend.dockerfile
    ports:
      - "8585:8000"
    volumes:
      - ./code:/srv/frontend
    command: grunt

frontend.dockerfile:

FROM node:wheezy

ADD code /srv/frontend
WORKDIR /srv/frontend
RUN npm install -g grunt-cli bower
RUN npm install

RUN groupadd -r usergroup && useradd -m -r -g usergroup user
RUN chown -R user:usergroup /srv/frontend
USER user

RUN bower install

bower.json:

{
  "name": "code",
  "description": "",
  "main": "index.js",
  "authors": [
    "Mr. No One"
  ],
  "license": "ISC",
  "homepage": "",
  "ignore": [
    "**/.*",
    "node_modules",
    "bower_components",
    "test",
    "tests"
  ],
  "dependencies": {
    "angular": "^1.5.8"
  }
}

Gruntfile.json:

module.exports = function(grunt) {
    grunt.initConfig({});

    // tasks
    grunt.registerTask('default', []);
};

package.json:

{
  "name": "code",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "grunt": "^1.0.1"
  }
}

$ docker-compose up ... installing all dependencies ... 安装后,尝试 运行 我在 docker-compose.yml 文件中指定的 grunt 命令时失败,并出现此错误:

frontend_1  | grunt-cli: The grunt command line interface (v1.2.0)
frontend_1  | 
frontend_1  | Fatal error: Unable to find local grunt.
frontend_1  | 
frontend_1  | If you're seeing this message, grunt hasn't been installed locally to
frontend_1  | your project. For more information about installing and configuring grunt,
frontend_1  | please see the Getting Started guide:
frontend_1  | 
frontend_1  | http://gruntjs.com/getting-started

package.json 实际上确实包含 grunt 作为依赖项,因此它应该在 RUN npm install.

之后安装

执行 docker exec -it <nameofyourcontainer> bash 并查看 node_modules 是否本地安装了 grunt。

你有没有在某处将 NODE_ENV 设置为 production? 这导致 npm 无法安装 devDepedencies

我想我找到了 node_modulesbower_components 没有创建的原因 in the docs

Note: If any build steps change the data within the volume after it has been declared, those changes will be discarded.

虽然我的 docker 文件中没有声明 VOLUME,但我的 docker-compose.yml 中确实有 volumes,所以我怀疑这条注释影响了我,因为npm installbower install 构建步骤都触及卷内的数据。

我从 docker 文件中删除了这些构建步骤,并在构建完成后手动执行它们:

$ docker-compose build
$ docker-compose run --rm frontend npm install
$ docker-compose run --rm frontend bower install

但是,当 运行 执行上述命令时,我遇到了权限问题,因为我新创建的用户没有写入主机的权限,而且我不想 运行 作为 root在容器内(例如,如果没有 --allow-root,bower 将不会喜欢它)

解决方法是创建与主机具有相同UID和GID的用户。

我发现 docker 允许 variable substitution and build arguments,这意味着您不必在 docker-compose.yml 中硬编码 UID 和 GID,相反,它们可以像这样从主机环境变量中获取并且可以在构建期间访问。

$ export HOST_UID=$(id -u)
$ export HOST_GID=$(id -g)

frontend.dockerfile:

FROM node:wheezy

ARG hostuid
ARG hostgid

ADD code /srv/frontend
WORKDIR /srv/frontend
RUN npm install -g grunt-cli bower

RUN groupadd -g "$hostgid" devgroup && useradd -m -u "$hostuid" -g devgroup developer
RUN chown -R developer:devgroup /srv/frontend
USER developer

docker-compose.yml:

version: "2"
services:
  frontend:
    build:
      context: .
      dockerfile: frontend.dockerfile
      args:
        - hostuid=${HOST_UID}
        - hostgid=${HOST_GID}
    ports:
      - "8585:8000"
    volumes:
      - ./code:/srv/frontend
    command: grunt