虚拟化技术Docker程序员

Docker下的网络模式

2017-06-30  本文已影响1073人  anyesu

前言


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

四种网络模式的选择


bridge

这是 docker 默认使用的模式, Docker Daemon 启动时默认会创建 docker0 这个网桥, 网段为 172.17.0.0/16 , 宿主机ip为 172.17.0.1, 作为这个虚拟子网的网关。

当然, 也可以新建一个名为 anyesu_net 网段为 172.18.0.0 的网桥(docker默认创建的网段为 172.17.0.0

docker network create --subnet=172.18.0.0/16 anyesu_net

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

docker network 命令相关资料:Docker命令行参考(29) – docker network create创建一个网络

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

简单的方法是在项目配置文件中使用环境变量或hostname ZkServer 作为注册中心地址, 相应地对容器进行环境变量和 hosts 的配置即可。不过,作为一个懒人, 项目中已经写好了使用 localhost 但不想改成 ZkServer , 方法也简单, 就是使用上面的方法替换 localhost 的ip为172.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() 来获取本机可用ip。InetAddress.getLocalHost 这个方法在Windows下应该是取所有网卡中第一个可用的ip, 在Linux下应该是取主机名对应的ip(先去 /etc/hosts 中找, 找不到再去 dns 服务器找, 需要注意这有可能会得到一个错误的ip), 因此, 在Linux下针对上面的问题只需修改 hosts 文件, 指定主机名对应的ip为宿主机的局域网ip。另外测试了下, 设置的 host 在Linux下只用于提供给服务注册中心而不用于端口绑定, 即可设置任意ip; 而在Windows下设置了非本机ip会无法绑定端口。

hosts文件改完还有一个问题:tomcat 默认 shutdown 命令绑定的端口是 localhost:8005, 由于 localhost 已经不再是容器的IP, 因此端口绑定会失败。简单处理就是修改 tomcat/conf/server.xmlServer 节点的属性, 添加属性 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 , 监听端口与注册端口不一致会导致找不到对应服务

配置优先级:
系统环境变量 -> java命令参数-D -> 配置文件host属性 -> /etc/hosts中hostname-ip映射关系 -> 默认联通注册中心地址的网卡地址 -> 第一个可用的网卡地址

参考文章


系列文章


Docker 学习总结

Docker 常用指令详解

使用Dockerfile构建镜像

使用Docker-compose构建容器

Docker Daemon连接方式详解


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

上一篇下一篇

猜你喜欢

热点阅读