node.js - 为什么 NPM 在 Docker 容器中不可用

我对 docker 非常陌生,并且正在使用它。我正在尝试在 docker 容器中运行 nodejs 应用程序。我将 ubuntu:14.04 作为基础镜像并构建了我自己的 nodeJS 烘焙镜像。我的 Dockerfile 内容如下所示

FROM ubuntu:14.04

MAINTAINER nmrony

#install packages, nodejs and npm
RUN apt-get -y update && \
    apt-get -y install build-essential && \
    curl -sL https://deb.nodesource.com/setup | bash - && \
    apt-get install -y nodejs

#Copy the sources to Container
COPY ./src /src
CMD ["cd /src"]
CMD ["npm install"]

CMD ["nodejs", "/src/server.js"]

我使用以下命令运行容器

docker run -p 8080:8080 -d --name nodejs_expreriments nmrony/exp-nodejs

运行良好。但是当我尝试浏览 http:localhost:8080 时它不会运行。 当我运行 docker logs nodejs_expreriments 时,出现以下错误

Error: Cannot find module 'express'
    at Function.Module._resolveFilename (module.js:338:15)
    at Function.Module._load (module.js:280:25)
    at Module.require (module.js:364:17)
    at require (module.js:380:17)
    at Object.<anonymous> (/src/server.js:1:77)
    at Module._compile (module.js:456:26)
    at Object.Module._extensions..js (module.js:474:10)
    at Module.load (module.js:356:32)
    at Function.Module._load (module.js:312:12)
    at Function.Module.runMain (module.js:497:10)

我用交互式 shell 运行另一个容器,发现 npm 没有安装。有人可以帮我为什么 NPM 没有安装在容器上吗?我做错了吗?

最佳答案

您的根本问题是,您只能在 Docker 文件中准确地拥有 一个 CMD。每个 RUN/COPY 命令在 docker build 期间构建一个层,因此您可以拥有任意数量的层。但是,one CMD 会在 docker run 期间执行。由于您有三个 CMD 语句,因此实际上只有一个被执行(大概是最后一个)。

(IMO,如果 Dockerfile 团队会选择单词 BUILD 而不是 RUNRUN 而不是 CMD,因此 docker build 执行 BUILD 语句,而 docker run 执行 RUN 语句,这对新用户来说可能不会那么困惑。哦,好吧。)

您要么希望将前两个 CMD 转换为 RUN(如果您希望它们在 docker build 期间发生并且是烘焙到图像中)或者可能将所有三个 CMD 放在您运行的脚本中。以下是一些解决方案:

(1) 最简单的更改可能是使用 WORKDIR 而不是 cd 并使您的 npm install 成为 RUN命令。如果您希望能够在构建期间 npm install 以便您的服务器在运行时快速启动,您需要这样做:

#Copy the sources to Container
COPY ./src /src
WORKDIR /src
RUN npm install
CMD nodejs server.js

(2) 如果您正在进行主动开发,您可能需要考虑以下内容:

#Copy the sources to Container
WORKDIR /src
COPY ./src/package.json /src/package.json
RUN npm install
COPY /src /src
CMD nodejs server.js

因此,如果您的 package.json 发生更改,您只需执行 npm install。否则,每次图像中的任何东西发生变化时,你都会重建所有东西

(3) 如果您经常更改包文件并且不想一直为构建和运行而烦恼,另一个有用的选项是将源代码卷上的图像,以便您无需重建即可运行:

...
WORKDIR /src
VOLUME /src
CMD build_and_serve.sh

build_and_serve.sh的内容在哪里:

#!/bin/bash
npm install && nodejs server.js

然后你像这样运行它:

docker run -v /path/to/your/src:/src -p 8080:8080 -d --name nodejs_expreriments nmrony/exp-nodejs

当然,最后一个选项不会为您提供可移植的 docker 镜像,您可以将其与您的服务器一起提供给他人,因为您的代码在镜像之外在一个卷上。

很多选择!

https://stackoverflow.com/questions/28633438/

相关文章:

docker - 如何在 Docker 内的 Jenkins 中运行 Katalon 测试套件

docker - 如何用 nix 构建一个 docker 容器?

docker - 使用 pyodbc 将 docker python 连接到 SQL 服务器

docker - 如何在 Docker Hub 上查看 Docker 镜像层?

docker - 如何在 Docker 中将卷从容器挂载到主机?

macos - 无法从 docker 容器访问本地网络 IP

docker - 为什么 Kubernetes 源代码比其他容器编排器大一个数量级?

Docker - 关于使用 Redis、Postgres、ElasticSearch、NGINX、W

docker - 停止和启动容器时出现奇怪的 docker 错误

git - 何时从 Docker 存储库中提取,何时从 Git 存储库中提取然后构建?