Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Docker 下的网络模式 #14

Open
anyesu opened this issue Apr 27, 2019 · 0 comments
Open

Docker 下的网络模式 #14

anyesu opened this issue Apr 27, 2019 · 0 comments

Comments

@anyesu
Copy link
Owner

anyesu commented Apr 27, 2019

前言


Docker 常用指令详解 一文中介绍了 Docker 的常用指令, 在构建容器的时候使用了 --net anyesu_net 这个选项, 意思是让容器使用自定义的网络 anyesu_net , 本文就 Docker 下的网络模式做一个简单介绍。

四种网络模式的选择


  • bridge

这是 Docker 默认使用的模式, Docker Daemon 启动时默认会创建 Docker0 这个网桥, 网段为 172.17.0.0/16 , 宿主机 IP172.17.0.1 , 作为这个虚拟子网的 网关

当然, 也可以新建一个名为 anyesu_net 网段为 172.18.0.0/16 的网桥:

docker network create --subnet=172.18.0.0/16 anyesu_net

启动 容器 时指定 --net anyesu_net 即可。

docker network 命令相关资料

  • host

容器 共享 宿主机 的网络 ( IP端口 ) 。使用 Docker 有相当一部分目的是为了隔离 宿主机容器 , 使用 host 模式就违背了这一点, 不是很好。另外有很多 镜像tomcat 默认监听 8080 端口的, 使用 host 模式后开多个 容器 就会造成端口冲突, 而不得不修改 tomcat 的监听端口。

  • none

这种模式下, 创建的 容器 拥有自己的 Network Namespace, 但是没有任何网络配置, 所以默认是没有网络的, 可以自己对 容器网卡IP 进行配置, 适合用来配置比默认设置更加复杂的网络环境。

  • container

类似于 host 模式, 不过这种模式是共享已存在的 容器 使用的网络。

给容器分配固定 IP


默认应该是按 容器 创建或启动顺序依次分配的, 所以 容器 重启后 IP 就可能会变化, 这对于一些需要定向访问 容器 的功能来说就比较麻烦了。一种解决办法是使用 link 来链接 容器, 原理就是动态配置 hosts , 不过这种方式启动顺序有依赖关系, 因此本人不习惯使用。还有一种方法, 是启动 容器 的时候使用自定义网络, 如 anyesu_net , 并指定 --ip 选项来固定 IP

当然, 网上还有很多教程借助 pipeworknsenter 等工具实现固定 IP 的功能, 甚至可以分配到 宿主机 所在物理网段上的 IP 。不过, 步骤都比较复杂, 有兴趣的小伙伴可以参考下面的几篇文章自己尝试哦。

关于容器中 hosts 文件的修改


启动 容器 的时候指定 --link--add-host 选项修改 hosts 文件内容, 但都是追加内容而无法覆盖已有内容, 比如我要重设 localhost 使其指向 宿主机IP 172.17.0.1 而不是默认的 127.0.0.1 ( 可能也就我吃饱了撑着要这么做吧 ) 就不能用这种方法了。

了解到 容器hosts 文件是 容器 启动时先在 宿主机 上动态创建后再挂载到 容器 上的 ( 源文件位于 宿主机/var/lib/docker/containers/[容器id] 目录下 ) , 因此, 容器 重启之后还会重新创建, 即之前所做的修改都没了。于是想到在容器的 启动命令 中动态修改, 但是 hosts 文件是不允许直接修改的, 于是采用下面的办法:

# 拷贝hosts内容
cp /etc/hosts /etc/hosts.tmp
# 替换字符串
sed -i 's$127.0.0.1$172.17.0.1$' /etc/hosts.tmp
# 覆盖hosts
cat /etc/hosts.tmp > /etc/hosts

# CMD参数中 使用 sh -c "... && ... && ..." 的方式来运行多个指令

个人觉得这也不是一种好办法, 就换了一种更简单粗暴的方法: -v /etc/hosts:/etc/hosts , 使用 宿主机 文件映射 容器hosts 文件 ( 或者新建一个 hosts 文件专门给 容器 用而不影响 宿主机hosts ) 达到覆盖的目的, 再配合 容器 固定 IP 配置, 多个 容器 共用一套 hosts 文件, 将所有 容器 的主机名和 IP 配置进去, 容器 之间也可以通过主机名或子网 IP 直接访问。

相关文章:

Docker 下使用 dubbo


公司项目中使用了 dubbo 来搭建分布式系统, 本地开发环境统一使用 localhost 来连接 ZooKeeper , 绑定不同端口实现 伪分布式 。后来就在测试环境上使用 Jenkins + Svn + Maven + Docker 的方式完成 一键构建 , 将每个服务部署在单独的容器之中, 使用默认的 bridge 网络模式。

遇到的问题

1. 访问宿主机上的 ZooKeeper

简单的方法是在项目配置文件中使用环境变量或主机名 ZkServer 作为注册中心地址, 相应的对 容器 进行环境变量和 hosts 的配置即可。不过,作为一个懒人, 项目中已经写好了使用 localhost 就不想改成 ZkServer 了, 方法也简单, 就是使用上面的方法替换 localhostIP172.17.0.1 , 即 宿主机的 IP

在Docker中运行Dubbo应用

2. 服务提供者注册 IP 问题

容器 内的服务默认注册到 zookeeper 上的地址是一个 IP ( 如 172.17.0.2 ) , 是一个内网地址, 对于 宿主机运行在其上的所有容器 之外的其他机器来说是不可访问的。如果要使服务对其他机器可用的话就要另辟蹊径了, 主要方法有:

  1. 容器使用 host 网络模式或设置为宿主机物理网段上的 IP
  2. 对宿主机和服务消费者之间的网络设置路由规则, 使消费者可访问容器内网 IP
  3. 修改 dubbo 源码来指定服务注册 IP

上面的方法实践起来有点复杂, 也不是很可靠, 还得另寻方法。

查了下 dubbo 的源码, 在 com.alibaba.dubbo.config.ServiceConfig 类的 doExportUrlsFor1Protocol 方法中, 如果配置中没有指定 host 属性或者使用了回环地址则调用 InetAddress.getLocalHost().getHostAddress() 来获取本机可用 IPInetAddress.getLocalHost 这个方法在 Windows 下应该是取所有网卡中第一个可用的 IP, 在 Linux 下应该是取主机名对应的 IP ( 先去 /etc/hosts 中找, 找不到再去 dns 服务器找, 需要注意这有可能会得到一个错误的 IP) , 因此, 在 Linux 下针对上面的问题只需修改 hosts 文件, 指定主机名对应的 IP宿主机 的局域网 IP 。另外测试了下, 设置的 hostLinux 下只用于提供给服务注册中心而不用于端口绑定, 也就是说可以设置任意 IP ; 而在 Windows 下设置了非本机 IP 会无法绑定端口。

hosts 文件改完还有一个问题:tomcat 默认 shutdown 命令绑定的端口是 localhost:8005, 由于 localhost 已经不再是容器的 IP , 因此端口绑定会失败。简单处理就是修改 tomcat/conf/server.xml 文件中 Server 节点的属性, 添加属性 address="127.0.0.1" , 如下所示:

<Server address="127.0.0.1" port="8005" shutdown="SHUTDOWN">
总结下最终的方案步骤:
  1. 创建自定义网络 ( 172.18.0.0/16 网段 )
  2. 容器 指定 hostname 、自定义网络、固定 IP
  3. 宿主机 ( 局域网 IP : 192.168.1.100)新建文件 /etc/hosts2 挂载到容器的 /etc/hosts 上 ( -v /etc/hosts2:/etc/hosts ) , 内容如下, 所有容器共用此 hosts 文件
172.18.0.1 localhost
192.168.1.100 docker_host1
192.168.1.100 docker_host2
...

  1. 宿主机容器 的端口映射 -p 20880:20880
最终结构图如下所示:

dubbo容器结构

2017-12-25 追加


目前 dubbo 自身已提供环境变量的方式注册 IP 和端口,详见 官方示例

  • 当前 2.5.9 版本有 bug , 监听端口与注册端口不一致会导致找不到对应服务

2.5.x 分支中配置优先级:
系统环境变量 > java 命令参数 ( -Dxxx=yyy ) > 配置文件 host 属性 > /etc/hostshostname-ip 映射关系 > 默认连通注册中心地址的网卡地址 > 第一个可用的网卡地址

参考文章


系列文章


Docker 学习总结

Docker 常用指令详解

使用 Dockerfile 构建镜像

使用 Docker Compose 构建容器

Docker Daemon 连接方式详解


转载请注明出处:http://www.jianshu.com/p/f510aaa470cc

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant