容器间通信以及容器与外部世界连接

容器间通信

容器之间可以通过IP Docker DNS Server 或joined容器三种方式通信
【1】.ip通信
从前面的例子可以得出一个结论:两个容器要能通信,必须有属于同一个网络的网卡 具体做法就是在容器创建的时候通过 --network 指定相应的网络 或者通过docker network connect 将现有的容器加入到指定的网络

参考之前的rhel7-up和busybox的例子

##host模式指定是容器与主机享受相同的network nameserver,
在这种情况下,我们访问主机端口就能访问我们的容器的端口
举例:运行busybox容器,
–network=host在这样指定的模式下,我们访问本机的8080端口,就能访问到busybox的8080端口容器

docker network ls
docker run -it --network=none busybox ##只有本地回环接口
docker run -it --network=host busybox ##主机网络
/ # ifconfig ##即访问的就是本机的ifconfig

再打开一个shell连接server1,进行查看
ifconfig ##和容器中的ifconfig是一样的

两个容器之间的通信
下面两个容器是我用文件做的镜像运行成的容器,文件内容如下
(因为要用到yum安装软件)
cat /mnt/docker/dockerfile
FROM rhel7:latest
COPY westos.repo /etc/yum.repos.d/
RUN rpmdb --rebuilddb && yum clean all

容器1:rhel7-up:v1
容器2:rhel7-up:v2
cd /mnt/docker/

容器1:
docker build -t rhel7-up:v1 .
docker run -it rhel7-up:v1 /bin/bash
yum whatprovides */ifconfig ##安装ifconfig
yum install net-tools-2.0-0.22.20131004git.el7.x86_64 -y
ifconfig ##查看此容器的ip,172.17.0.2
yum whatprovides */ping ##安装ping命令
yum install iputils-20160308-10.el7.x86_64 -y
ping 172.17.0.2 ##截图第104

容器2:
docker build -t rhel7-up:v2 .
docker run -it rhel7-up:v2 /bin/bash
yum install net-tools -y
ifconfig ##查看此容器的ip,172.17.0.3
yum whatprovides */ping ##安装ping命令
yum install iputils-20160308-10.el7.x86_64 -y
ping 172.17.0.2 ##ping容器1的ip

容器1:
ping 172.17.0.3 ##ping容器2的ip

证明两个容器可以通信

【2】.Docker DNS Server
通过IP访问容器虽然满足了通信的需求,但是还是不够灵活,因为在部署应用之前可能无法确定IP 部署之后再指定要访问的IP会比较麻烦 对于这个问题 可以通过docker 自带的DNS服务解决
从docker1.10版本开始,docker daemon实现了一个内嵌的DNS server,使容器可以直接通过“容器名”通信,方法很简单,只要在启动时用 --name为容器命名就可以了

docker network create --driver bridge my_net
docker network inspect my_net

docker network create --driver bridge --subnet 172.22.16.0/24 --gateway 172.22.16.1 my_net2
docker network inspect my_net2
docker run -it --network=my_net2 --ip 172.22.16.8 busybox
ifconfig
ping 172.22.16.1

bbox1:
docker run -it --network=my_net2 --name=bbox1 busybox

再打开一个shell连接server1,运行容器bbox2
bbox2:
docker run -it --network=my_net2 --name=bbox2 busybox
/ # ping bbox1

在bbox1 ping bbox2:
/ # ping bbox2

使用docker DNS有个限制:只能在user-defined网络中使用 也就是说默认的bridge网络是无法使用DNS的
docker run -it --name=bbox3 busybox
再打开一个shell连接server1,运行容器bbox4
docker run -it --name=bbox4 busybox
/ # ping bbox3
ping: bad address ‘bbox3’

【3】.joined容器
是另一种实现容器间通信的方式
joined容器非常特别,它可以使两个或多个容器共享一个网络栈 共享网卡和配置信息,joined容器之间可以通过127.0.0.1 直接通信

先创建一个rhel7-up容器 名字为server1
docker run -it --name=server1 rhel7 /bin/bash
bash-4.2# ip a

然后创建busybox容器并通过 --network=container:server1 指定joined容器为server1
docker run -it --network=container:server1 busybox
/ # ip a

#busybox和web1的网卡mac地址与IP完全一样,它们共享了相同的网络栈 busybox可以直接用127.0.0.1访问server1

“”"
joined容器非常适合以下场景
1.不同容器中的程序希望通过loopback高效地通信 比如web server 与 App Server
2.希望监控其他容器的网络流量 比如运行在独立容器中的网络监控
“”"

容器与外部世界连接
前面我们已经解决了容器之间通信的问题,接下来讨论容器如何与外部世界通信,这里涉及两个方向
1.容器访问外部世界
2.外部世界访问容器

1.容器访问外部世界
在我们当前的实验环境下 docker host是可以访问外网的
ping www.baidu.com
我们看一下容器是否也能访问外网呢?
docker run -it busybox
/ # ping www.baidu.com

可以看到的是,容器默认就能访问外网

外网:指的是容器网络以外的网络环境,并非特指Internet

iptables -t nat -S

busybox位于docker0这个私有bridge网络中(172.17.0.0/16)

busybox从容器向外ping时,数据包是怎样到达baidu.com的呢

这里的关键就是NAT 我们查看以下docker host 上的iptables规则

“”"
-A POSTROUTING -s 172.17.0.0/16 ! -o docker0 -j MASQUERADE
其含义是:如果网桥docker0收到来自172.17.0.0/16网段的外出包,把它交给MASQUERADE处理,而MASQUERADE的处理方式是将包的源地址替换成host的地址发送出去,即做了一次网络地址转换(NAT)
“”"

下面我们通过tcpdump查看地址是如何转换的 先查看docker host路由表
ip r
default via 172.25.0.250 dev eth0

默认路由通过eth0发出去的,所以我们要同时监控eth0 和docker0上的icpm(ping)数据包

当busybox ping baidu.com 时

docker run -it busybox
/ # ping www.baidu.com

yum whatprovides */tcpdump
yum install 14:tcpdump-4.9.2-3.el7.x86_64 -y

tcpdump输出如下

tcpdump -i docker0 -n icmp
tcpdump -i eth0 -n icmp
docker0收到busybox的ping包 源地址为容器IP 172.17.0.2 交给MASQUERADE 处理 在eth0上面我们看到了变化
ping包的源地址变成了eth0的IP 172.25.0.7
这就是iptable NAT规则的处理结果 从而保证数据包能够到达外网

图片说明:
1.busybox发送ping包:172.17.0.2 >www.baidu.com
2.docker0收到包,发现是发送到外网站的,交给NAT处理
3.NAT将源地址转换成eth0的IP地址:172.25.0.7 >www.baidu.com
4.ping包从eth0发送出去,到达www.baidu.com

通过NAT,docker实现了容器对外网的访问
“”"
外部世界访问容器
外网如何访问到容器? 端口映射
docker可将容器对外提供服务的端口映射到host的某个端口,外网通过该端口访问容器,容器启动时通过-p参数映射端口
[root@server7 ~]# docker run -d -p 80 httpd
59605d55848ce748f56abf3079ae3901525000602cdeaf146a778f3d558e3c4f
[root@server7 ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
59605d55848c httpd “httpd-foreground” 4 seconds ago Up 4 seconds 0.0.0.0:32768->80/tcp jolly_galileo
[root@server7 ~]# docker port 59605d55848c
80/tcp -> 0.0.0.0:32768

容器启动后,可通过docker ps或者docker port查看到host映射的端口,在上面的例子中,httpd容器80端口被映射到host32773上,这样就可以通过:<32773>访问容器的WEB服务了

[root@server7 ~]# curl 172.25.0.7:32768

It works!

除了映射动态端口,也可以在-p中指定映射到host某个特定端口,例如可以将80端口映射到host的8080端口
[root@server7 ~]# docker run -d -p 8080:80 httpd
b59175d1bc6f7f2aa81cd854f87aef4c786a0fa801599125caed4721deb15f62
[root@server7 ~]# curl 172.25.0.7:8080

It works!

每一个映射的端口,host都会启动一个docker-proxy进程来处理访问容器的流量

ps -ef|grep docker-proxy

以0.0.0.0:32773->80/tcp 为例分析整个过程
1.docker-proxy 监听host的32773端口
2.当curl访问 172.25.0.7:32773时,docker-proxy转发给容器ip:80
3.httpd容器响应请求并返回结果

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值