我有一个简单的node.js docker app .
我能够成功运行它,但是尽管按照docker-compose docs中的描述安装了卷,但是在容器内重新加载的代码仍无法正常工作 .
目录布局:
my-test-app
| docker-compose.yml
| Dockerfile
| index.js
| package.json
Dockerfile:
FROM mhart/alpine-node:8
WORKDIR /app
COPY . .
EXPOSE 5000
CMD ["node", "index.js"]
泊坞窗,compose.yml:
version: '3'
services:
node-app:
build: .
ports:
- "5000:5000"
volumes:
- .:/app
redis:
image: "redis:alpine"
index.js:
const http = require('http');
const server = http.createServer((req, res) => {
res.end("hello world");
});
server.listen(5000);
的package.json:
{
"name": "my-test-app",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
},
"author": "",
"license": "MIT"
}
我也尝试了以下相同的结果(应用程序运行,无法重新加载代码)
-
使用官方节点图像,而不是
alpine-node
. -
将
./app
文件夹下的应用程序代码放在my-test-app
中,并相应地更新Dockerfile
内的COPY
和volumes
内的COPY
.
2 回答
我看过用于两种不同类型重新加载的短语“live reload”:
在代码更改时杀死并重新启动应用程序,并且
在代码更改时自动在客户端浏览器上重新加载HTML和资产 .
根据你的问题,我认为你指的是第一种类型,所以后面的答案解决了这个问题 .
这里的问题是 context 之一 .
请记住,docker容器与主机隔离 - 具体而言,容器中运行的进程与主机上运行的进程不同(并且通常无法与之交互) . 在您的情况下,您已选择在容器中安装主机目录,但这只是文件系统,而不是进程 .
想一想在实例化新容器时Docker镜像的作用:它在
WORKDIR
中运行node index.js
. 代码在哪里停止并在代码更改时重新启动它?据推测它正在 host 的一个过程中运行 . 这意味着它无法触及在 container 中运行的节点进程(因为它是隔离的) .现在,您还没有提到您使用什么方法来处理实时重新加载,但这不应该产生太大的差别 . 它们基本上都以相同的方式工作:在更改应用程序代码时,终止现有流程并启动新流程 .
要解决此问题,您有两种选择:
在容器内运行"live reloading"代码,或
在容器外运行开发代码
首先,您可以按照@ MarkS的建议使用nodemon . 这应该像更换一样简单
在您的Dockerfile中
当然,您已经在图像中正确安装了
nodemon
.我所做的另一种选择是在开发期间在Docker环境之外的主机上运行代码,然后在部署时将其打包在映像中 . 这解决了两个问题:
您遇到的孤立节点进程的问题,以及
权限问题 .
请记住,在Docker中运行的应用程序运行为
root
. 这意味着如果您的应用创建文件,它们将归root
所有 . 我尝试在Docker环境中进行开发,但对问题感到沮丧,例如,我想删除应用程序创建的文件,并且必须sudo
(以root
登录)才能清理内容 .我拥有的和你拥有的唯一区别是我的Dockerfile中没有COPY指令 . 尝试删除它,看看它是否有效 .
我还使用nodemon在代码更改时自动重启节点服务器: