使用Docker运行一个Node项目
Posted GoldenaArcher
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用Docker运行一个Node项目相关的知识,希望对你有一定的参考价值。
使用Docker运行一个Node项目
流程如下:
step 0 - 基础文件
-
docker file:
# specify a base image FROM alpine # install dependencies RUN npm install # default command CMD [ "npm", "start" ]
⚠️ 这里使用的基础镜像是 alpine。
-
package.json:
"dependencies": "express": "*", "redis": "2.8.0" , "scripts": "start": "node index.js"
-
index.js:
const express = require('express'); const app = express(); app.get('/', (req, res) => res.send('Hi there') ); app.listen(9999, () => console.log('Listening on port 9999'); );
step 1 - 基础镜像错误
运行Docker,其运行结果如下:
➜ visits-starter docker build .
Sending build context to Docker daemon 19.46kB
Step 1/3 : FROM alpine
latest: Pulling from library/alpine
213ec9aee27d: Already exists
Digest: sha256:bc41182d7ef5ffc53a40b044e725193bc10142a1243f395ee852a8d9730fc2ad
Status: Downloaded newer image for alpine:latest
---> 9c6f07244728
Step 2/3 : RUN npm install
---> Running in facd3767fa67
/bin/sh: npm: not found
The command '/bin/sh -c npm install' returned a non-zero code: 127
报错的原因是因为 alpine 中并没有 node 相关的包,因此直接运行 npm install
会抛出 npm: not found
的错。这个时候比较简单的解决方案:
-
下载、配置并安装 node
-
使用别人已经打包好的基础镜像,这里使用的是
node:14-alpine
。我尝试使用 v16,不过似乎是有一些配置问题,直接运行会导致报错。目前 v14 的支持一直到 2023-04-30……不知道之后是不是会考虑直接升级到 v18 还是 v20.
修正后的部分:
# specify a base image
# FROM alpine - remove
# and replace with
FROM node:14-alpine
运行结果:
➜ visits-starter docker build .
Sending build context to Docker daemon 19.46kB
Step 1/3 : FROM node:14-alpine
---> 798752c1e2a0
Step 2/3 : RUN npm install
---> Running in f980f1bc6709
npm WARN saveError ENOENT: no such file or directory, open '/package.json'
npm notice created a lockfile as package-lock.json. You should commit this file.
npm WARN enoent ENOENT: no such file or directory, open '/package.json'
npm WARN !invalid#2 No description
npm WARN !invalid#2 No repository field.
npm WARN !invalid#2 No README data
npm WARN !invalid#2 No license field.
up to date in 0.436s
found 0 vulnerabilities
Removing intermediate container f980f1bc6709
---> 9575921d8a0b
Step 3/3 : CMD [ "npm", "start" ]
---> Running in 2eac9cfdffcd
Removing intermediate container 2eac9cfdffcd
---> a6c1af8bcdbd
Successfully built a6c1af8bcdbd
Use 'docker scan' to run Snyk tests against images to find vulnerabilities and learn how to fix them
step 2 - 文件找不到错误
虽然在运行Docker的时候没有报错,不过我尝试运行了一下 npm start
还是报错了,运行结果如下:
➜ visits-starter docker run -it a6c1af8bcdbd sh
/ # ls
bin etc lib mnt package-lock.json root sbin sys usr
dev home media opt proc run srv tmp var
/ # npm start
npm ERR! code ENOENT
npm ERR! syscall open
npm ERR! path /package.json
npm ERR! errno -2
npm ERR! enoent ENOENT: no such file or directory, open '/package.json'
npm ERR! enoent This is related to npm not being able to find a file.
npm ERR! enoent
npm ERR! A complete log of this run can be found in:
npm ERR! /root/.npm/_logs/2022-10-06T18_04_50_719Z-debug.log
/ #
应用并没有运行,并且爆出错误 package.json 找不到的错。
会出现这个错误的原因是因为每一个运行的镜像是当前系统的一个snapshot,而本地的文件——package.json, index.js——并没有复制到镜像中,因此在运行的时候,node会找不到package.json去运行。
这个时候就需要使用一个新的指令:COPY
去将本地文件复制到镜像中去:
# specify a base image
FROM node:14-alpine
# copy from locak system to docker temp container
COPY ./ ./
# install dependencies
RUN npm install
# default command
CMD [ "npm", "start" ]
运行结果:
➜ visits-starter docker build .
Sending build context to Docker daemon 19.46kB
Step 1/4 : FROM node:14-alpine
---> 798752c1e2a0
Step 2/4 : COPY ./ ./
---> 22d75ba79400
Step 3/4 : RUN npm install
---> Running in 5065b9da7657
npm notice created a lockfile as package-lock.json. You should commit this file.
npm WARN !invalid#2 No description
npm WARN !invalid#2 No repository field.
npm WARN !invalid#2 No license field.
added 61 packages from 46 contributors and audited 61 packages in 3.026s
7 packages are looking for funding
run `npm fund` for details
found 1 high severity vulnerability
run `npm audit fix` to fix them, or `npm audit` for details
Removing intermediate container 5065b9da7657
---> 05230fcb61cc
Step 4/4 : CMD [ "npm", "start" ]
---> Running in 372aba7de32a
Removing intermediate container 372aba7de32a
---> 147ae3af863d
Successfully built 147ae3af863d
Use 'docker scan' to run Snyk tests against images to find vulnerabilities and learn how to fix them
注意这里:added 61 packages from 46 contributors and audited 61 packages in 3.026s
,这是可以确认package.json中的所有文件被下载了。
随后运行这个docker镜像:
➜ visits-starter docker run 147ae3af863d
> @ start /
> node index.js
Listening on port 9999
目前程序已经可以运行,也在监听9999这个端口,但是当打开浏览器时,浏览器没法打开该网址。
这是因为镜像的路由并没有设置,本地无法访问镜像内部的端口。当然,docker默认禁止对内访问,对外访问是可以进行的——不然node的包也没办法下载成功。
step 3 - 配置路由
路由配置(port mapping) 只能在运行时进行操作,因此可以运行下面的指令:
我用了tag这样输入指令起来方便点
# outsite port does not have to be same as image port
➜ visits-starter docker run -p 9999:9999 ga/v
> @ start /
> node index.js
Listening on port 9999
运行成功后:
step 4 - 文件结构优化
继续访问镜像并且看一下目前的目录结构:
➜ visits-starter docker run -it ga/v sh
/ # ls
Dockerfile etc lib node_modules package.json root srv usr
bin home media opt pnpm-lock.yaml run sys var
dev index.js mnt package-lock.json proc sbin tmp
/ #
这个文件比较小还不要紧,但是文件比较大的时候就可能会出现重写系统默认文件的情况。Docker也提供了可以设置working directory的指令,这样可以让所有的文件复制到该working directory下。
Dockerfile更新如下:
# specify a base image
FROM node:14-alpine
# specify a working dir
WORKDIR /usr/app
# copy from locak system to docker temp container
COPY ./ ./
# install dependencies
RUN npm install
# default command
CMD [ "npm", "start" ]
之后运行指令查看目录结构:
➜ visits-starter docker run -it ga/v sh
/usr/app # ls
Dockerfile index.js node_modules package-lock.json package.json pnpm-lock.yaml
/usr/app # pwd
/usr/app
/usr/app #
step 5 - 优化安装
这一步是为了可以让修改源代码不影响node包的安装。Docker对比指令,一旦发现指令与先前的不同——如修改了源码,那么整个COPY ...
,RUN ...
, CMD ...
的步骤全都会重新运行,这也就代表着所有的依赖包都会被重新下载。
为了提升性能,可以将复制 package.json
与其他代码的操作分开,这样只要 package.json
不被修改,那么代码就不会重新下载 node 依赖包。
# specify a base image
FROM node:14-alpine
# specify a working dir
WORKDIR /usr/app
# copy from locak system to docker temp container
COPY ./package.json ./
# install dependencies
RUN npm install
COPY ./ ./
# default command
CMD [ "npm", "start" ]
以上是关于使用Docker运行一个Node项目的主要内容,如果未能解决你的问题,请参考以下文章