如何在 Docker 容器中运行 npm 命令?

21

我正在尝试在Docker容器内以开发模式运行Angular应用程序,但是当我使用docker-compose build运行它时,它可以正常工作,但是当我尝试启动该容器时,我会收到以下错误:



ERROR: for sypgod  Cannot start service sypgod: OCI runtime create failed: container_linux.go:346: starting container process caused "exec: \"npm\": executable file not found in $PATH

真正的问题是它无法识别npm serve命令,但为什么?

设置如下:

Docker容器(Nginx反向代理 -> 运行在端口4000上的Angular)

我知道有更好的部署方法,但此时此刻出于某些个人原因,我需要这个设置。

Dockerfile:


FROM node:10.9 


COPY package.json package-lock.json ./

RUN npm ci && mkdir /angular && mv ./node_modules ./angular

WORKDIR /angular

RUN npm install -g @angular/cli 

COPY . . 


FROM nginx:alpine
COPY toborFront.conf /etc/nginx/conf.d/
EXPOSE 8080
CMD ["nginx", "-g", "daemon off;"]
CMD ["npm", "serve", "--port 4000"]

Nginx服务器网站

server{
    listen 80;
    server_name sypgod;


    location / {
            proxy_read_timeout 5m;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_pass http://localhost:4000/;


    }

}


Docker Compose 文件(我遇到问题的重要部分)

 sypgod: # The name of the service
        container_name: sypgod  # Container name
        build: 
            context: ../angular
            dockerfile: Dockerfile # Location of our Dockerfile


5个回答

9

4
谢谢你提供这个解决方案。为什么需要在主机上安装npm?它可以在没有npm的情况下运行,难道不是整个想法都是从docker中运行npm吗? - DenisNovac
下面的命令对我有效:docker run -v "$PWD":/usr/src/app -w /usr/src/app node:16 sh -c 'npm install --only=prod && npm run build-prod' - Tobi G.

9
最终运行的图像是这个:
FROM nginx:alpine
COPY toborFront.conf /etc/nginx/conf.d/
EXPOSE 8080
CMD ["npm", "serve", "--port 4000"]

第一阶段没有任何效果(您可以从中拷贝COPY --from=...文件),如果有多个CMD,只有最后一个有效。由于您在纯nginx映像中运行此命令,所以没有npm命令,导致您看到的错误。
我建议您在主机上使用Node进行实时开发环境。当您构建和测试应用程序并准备部署时,如果适用,则使用Docker。在Dockerfile中,第一阶段运行ng build来将应用程序编译为静态文件,在第二阶段添加COPY --from=...以将构建应用程序放入Nginx映像中,并删除所有CMD行(nginx具有适当的默认CMD)。@VikramJakhar的答案显示了更完整的Dockerfile。
看起来您可能正在尝试在Docker中同时运行Nginx和Angular开发服务器。如果这是您的目标,则需要在两个单独的容器中运行它们。要做到这一点:
  • 将此Dockerfile分成两个文件。将CMD ["npm", "serve"]行放在第一个(仅Angular)Dockerfile的末尾。
  • docker-compose.yml文件中添加第二个块以运行第二个容器。后端npm serve容器不需要发布ports:
  • 将Nginx配置中的后端服务器主机名从localhost更改为其他容器的Docker Compose名称。

我已经将它分成两个不同的Docker文件,一个是带有Nginx的,另一个是Angular项目。 我已经退出了发布端口,但在Nginx配置中,我不确定容器的组合名称是什么,是:sypgod吗? 因此,文件应该像这样: - Ratchet
services: 下声明第二个容器的块的名称是什么?那是一个有效的主机名。 - David Maze
sypgod是吗,但我还应该添加端口吗? - Ratchet
是的,您需要端口(容器内服务正在侦听的端口;需要在0.0.0.0“所有接口”上侦听;ports:没有影响)。 - David Maze
它不能正常工作,我已将其放入nginx conf http://sypgod:4000/中,但它不起作用,sypgod是容器的名称。 - Ratchet
它起作用了,现在我明白了一切的工作原理。谢谢。 - Ratchet

2
您可以像以下这样做:
### STAGE 1: Build ###

# We label our stage as ‘builder’
FROM node:alpine as builder

RUN apk --no-cache --virtual build-dependencies add \
    git \
    python \
    make \
    g++

    RUN mkdir -p /ng-app/dist

    WORKDIR /ng-app

    COPY package.json package-lock.json ./

    ## Storing node modules on a separate layer will prevent unnecessary npm installs at each build
    RUN npm install

    COPY . .

    ## Build the angular app in production mode and store the artifacts in dist folder

    RUN npm run ng build -- --prod --output-path=dist


    ### STAGE 2: Setup ###

    FROM nginx:1.14.1-alpine

    ## Copy our default nginx config
    COPY toborFront.conf /etc/nginx/conf.d/

    ## Remove default nginx website
    RUN rm -rf "/usr/share/nginx/html/*"

    ## From ‘builder’ stage copy over the artifacts in dist folder to default nginx public folder
    COPY --from=builder /ng-app/dist /usr/share/nginx/html

    CMD ["nginx", "-g", "daemon off;"]

这个是有效的,因为我之前试过了,但问题是我想稍后在Angular服务器端渲染中部署,所以为此,我必须执行npm serve:ssr并将其放入Nginx内的反向代理。我是通过尝试OP中提供的示例来做到这一点的,因为它很容易,然后尝试服务器端渲染,所以你的答案是100%正确的,但不是我需要的。 - Ratchet

0
如果您已经安装了 Portainer.io 来管理您的 Docker 设置,那么您可以从浏览器中打开特定容器的控制台。
这对于运行参考命令非常有用,例如 "npm list" 以显示加载了哪些依赖项的版本。

portainer

这样你就可以像这样查看它:

console

我发现这个工具在诊断依赖更新导致的问题非常有用。在测试环境中一切正常,但是 Docker 版本安装了新的次要版本,导致应用程序出现故障。

0
我在这一步卡住了。
docker run -it --rm node /usr/local/bin/npm install

使用默认的最新标签从节点镜像实例化一个容器。在预定义的工作目录中,在容器内运行npm install。解决方案是简单地使用绑定挂载与设置工作目录相结合。
docker run -it --rm -v .:/tmp -w /tmp node /usr/local/bin/npm install

. 是要在其中运行 npm install 的项目,而 /tmp 只是容器内挂载项目的目录。使用 /tmp 是有道理的,因为容器将在命令执行后由于 --rm 标志而被删除。

P.S. 考虑使用 node:alpinenode:hydrogen-alpinehydrogen 是 lts 版本 18 的代号,但您可以使用更新的 lts 版本代号),并通过标记为 docker tag ecbe47697d08 nodedocker tag ecbe47697d08 node:alp 在本地为镜像设置别名。alpine 镜像占用的磁盘空间大约是非 alpine 镜像的十分之一,但提供了与非 alpine 镜像相同版本的 npm


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接