docker 容器化部署 Node 项目
应用场景
-
docker 部署 Node 项目
-
用 forever 守护进程工具管理 且将 logs 映射到主机目录 logs 文件夹(bind volume)
-
用于项目开发容器:本地没有 node 开发环境且懒得安装
-
主机项目文件更新,容器内 node 服务需
npx forever restartall
或者npm run restart
重启(restart = npx forever restartall)
部署过程
-
安装 docker
-
docker pull node:tag
拉取 node 镜像(版本取决于实际项目) -
启动容器
docker run -dp 8388:8388 \ --name node \ -w /app \ --mount type=bind,src=/node/server/,target=/app \ --mount type=bind,src=/node/logs,target=/logs \ node:21.2.0 \ /bin/bash -c "npm install && node /app/index.js && npm run dev"
-
--name
为该容器起一个别名,替代 <container ID> -
-w
指定工作目录,容器内所有命令都将在该目录下执行 -
--mount type=bind,src=...,target=/app
bind volume,将主机目录挂载到容器内,用于映射项目源文件、日志文件 -
-d
后台运行容器 -
-p
端口映射,将容器内 8388 端口映射到主机 8388 端口
-
在 npm run dev 的 dev 中,此脚本字段对应的命令为
npx dotenvx run --env-file=/app/.env.pack.dev -- forever start -c 'node --harmony' -l /logs/access.log -e /logs/err.log -a /app/index.js
-
在容器中, 使用 forever 启动 node 应用时需要在命令中添加
-c 'node --harmony'
-
执行非 node 命令,需要用 npx 执行(
npx dotenvx run
、npx forever list
) -
dotenvx run
为 dotenvx 库提供的命令行, 用于设置 env
1、启动容器时,执行了 npm install && node /app/index.js
两条命令,若不执行node /app/index.js
,则容器启动后会被迫停止 EXIT(0)
2、工具 forever、dotenvx 都预先存在于 package.json,npm install
后可直接使用, 也可手动在 node 容器中安装
docker(例如 node) 容器访问宿主机某端口服务
1、容器内的服务访问 localhost 和宿主机上非容器的服务访问 localhost 是不一样的, 比如都是访问 localhost:8288, 容器是在访问本身内部的 8288 端口服务,而不是访问宿主机的 8288 端口服务
2、请注意,本文只探讨容器访问宿主机,不涉及容器间的通信
3、那么如何从容器中访问到宿主机的网络?有以下两种解决办法,第一种亲测有效
使用 host 网络
-
Docker 容器运行的时候有
host、bridge、none
三种网络可供配置。默认是bridge
,即桥接网络,以桥接模式连接到宿主机;host
是宿主网络,即与宿主机共用网络;none
则表示无网络,容器将无法联网。 -
容器使用
host
网络,那么容器的 localhost 就是宿主机的 localhost。 -
在 docker 中使用
--network host
来为容器配置 host 网络(依照第二步部署过程中的 docker run, 给出示例命令):docker run -d \ --name node \ --network host \ -w /app \ --mount type=bind,src=/node/server/,target=/app \ --mount type=bind,src=/node/logs,target=/logs \ node:21.2.0 \ /bin/bash -c "npm install && node /app/index.js && npm run dev"
-
上面的命令中,没有必要像前面一样使用
-p 8388:8388
来映射端口,是因为本身与宿主机共用了网络,容器中暴露端口等同于宿主机暴露端口。 -
总结: host 网络下 docker 容器与宿主机共用了网络,通用性好。但是,由于 host 网络没有 bridge 网络的隔离性好,使用 host 网络安全性不如 bridge 高。
使用宿主机 IP
在 Linux 下安装 Docker 的时候,会在宿主机安装一个虚拟网卡 docker0,我们可以使用宿主机在 docker0 上的 IP 地址来代替 localhost。
-
ip addr show docker0
查询宿主机 IP 地址$ ip addr show docker0 3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default link/ether 02:42:d5:4c:f2:1e brd ff:ff:ff:ff:ff:ff inet 172.17.0.1/16 scope global docker0 valid_lft forever preferred_lft forever inet6 fe80::42:d5ff:fe4c:f21e/64 scope link valid_lft forever preferred_lft forever
-
可以发现宿主机的 IP 是
172.17.0.1
,那么将 node 容器内访问宿主机的 url 改为http(s)://172.17.0.1:8288
, 就可以访问到宿主机的 8288 端口,解决 502 Bad Gateway 错误。
但是,在 Windows 和 macOS 平台下并没有 docker0 虚拟网卡,这时候可以使用 host.docker.internal
这个特殊的 DNS 名称来解析宿主机 IP。
-
request_url:
http(s)://host.docker.internal:8288
-
由此发现,不同系统下宿主机的 IP 是不同的,所以使用宿主机 IP,不能跨环境通用。
文章参考: Docker 容器访问宿主机网络