127.0.0.1 与 0.0.0.0 的区别

image

从何而起

最近偶尔有同学说项目运行出错了, 一排查往往是切换了 node 版本, 比如需要重新编译一下 node-sass (其实脚手架早换成了 dart-sass, 太低版本突然升级有些许风险), 以及少部分使用 windows 开发的同学因为删除 node_modules 清缓存时常出现“假删”的现象, 想着是否有必要本地开发使用 CI 构建的镜像来保证环境的一致性, 况且其他大厂的 云IDE 听说也是进行得比较火热, 我们只是落地本地 docker 开发或许会容易很多

目标

考虑到大部分同学对 docker 不是很了解, 本次的目标希望是能够一行命令让 docker 把项目运行起来

如何达成目标

docker 中运行 git 命令需要生成 ssh key 怎么办 ?

每次进入 docker 都需要重新配置下环境, 终究还是不妥当, 后面想了一会决定通过 docker 数据卷 volumes 去把本地的 .ssh 目录给映射到 docker, 让本机和 docker 共享一份配置

团队的 npm 还有权限控制怎么办 ?

其实和上面问题的解决办法是一致的, 再把 .npmrc 文件也通过 docker 数据卷 volumes 去映射一下

如何编写代码

image

如果大家是在 docker 中编写代码的话, 可能需要比较厚实的 vim 功底, 还是通过 vscode 的 VS Code Remote Development 去做了,感觉比较麻烦,况且现在都在本机,不如还是通过 docker 数据卷 volumes 把当前项目的目录给映射过去, 大家还是保持现在的 vscode 开发, 图示的内容我们都没有做 😅

好像问题都解决了

最后也是顺利运行起了 docker 命令, 但发现本地浏览器访问开发的地址始终是服务无响应, 问题出在哪了 ?

debug

image

主机到容器的端口映射的问题 ?

起一个简单的 http server 就能验证了, 最后发现下面的方式是能有响应的。

1
2
3
4
5
6
7
const http = require('http')

const server = http.createServer((req, res) => {
res.end('Hello World!');
});

server.listen(8000);

那就是 WebpackDevServer 的问题了

WebpackDevServer 启动的代码类似于下面, 和上面的简单的 http server 的区别在于 listen 参数 host 传了值

1
2
3
4
5
6
7
const devServer = new WebpackDevServer(compiler, devServerConfig)

devServer.listen(port, host, err => {
if (err) {
return console.log(err)
}
})

debug 一看这里的 host 值为 localhost, 而 localhost 只是一个本地通常使用的域名, 在 /etc/hosts 文件中进行了绑定, 它的背后其实是 127.0.0.1

1
127.0.0.1     localhost

即如果 docker 中监听 127.0.0.1 将会造成上面说的本机访问服务无响应的问题

没有传 host 参数的默认值是什么了

现在让我们回头再看简单的 http server 不传 host 参数默认值会是什么, 通过下面的代码也发现了默认会去绑定 :: 或者 0.0.0.0, 后面我们以 0.0.0.0 为例, 关于 ip 协议可以继续阅读 是时候说说到底什么是IPv4和IPv6了!

1
2
3
4
5
6
7
8
9
10
11
12
// lib/net.js

// Try binding to ipv6 first
err = handle.bind6(DEFAULT_IPV6_ADDR, port, flags);
if (err) {
handle.close();
// Fallback to ipv4
return createServerHandle(DEFAULT_IPV4_ADDR, port);
}

const DEFAULT_IPV4_ADDR = '0.0.0.0';
const DEFAULT_IPV6_ADDR = '::';

127.0.0.1 与 0.0.0.0

可以仔细阅读一下两者的官方解释, 简单概括就是

  • 127.0.0.1 通常用于本机中各个应用之间的网络交互, 与其他主机关联访问会存在障碍
  • 0.0.0.0 可以代表本机的所有 IPv4 地址, 适用性会更广, 当在 docker 监听时, 外部能够访问得到, 再比如监听 0.0.0.0 时, 可通过 ifconfig 命令用本机的 ip 地址去访问,而前者则不行

127.0.0.1

127.0.0.1是回送地址,指本地机,一般用来测试使用。回送地址(127.x.x.x)是本机回送地址(Loopback Address),即主机IP堆栈内部的IP地址,主要用于网络软件测试以及本地机进程间通信,无论什么程序,一旦使用回送地址发送数据,协议软件立即返回,不进行任何网络传输。

0.0.0.0

0.0.0.0,在这里意味着 “本地机器上的所有IP地址”(实际上可能是 “本地机器上的所有IPv4地址”)。因此,如果你的webserver机器有两个IP地址,192.168.1.1和10.1.2.1,而你允许像apache这样的webserver守护程序监听0.0.0.0,它在这两个IP地址上都可以到达。但是,只有能与这些IP地址和网络端口联系的才可以。

开始开发

image
到这里终于可以愉快的在 docker 中进行开发了, 最后记录下 docker 运行的命令

  • 把配置文件映射到 docker 中
  • 把当前项目目录映射到 docker 的 temp 目录中
  • 本机与 docker 端口进行一下映射
  • 运行某个镜像的 id
    1
    2
    3
    4
    5
    6
    7
    docker run -t -i \
    -v ~/.ssh:/root/.ssh \
    -v ~/.npmrc:/root/.npmrc \
    -v $(pwd):/temp \
    -p 3000:3000 \
    00eb8ccbb6d0 \
    /bin/bash

小结

docker 中构建时间会明显长一些, 编译大型项目有些许卡顿, 快速运行一个 puppeteer 镜像进行一些测试是个不错的选择~