彻底搞懂Docker网络原理之单机通信

一、背景

学习docker除了镜像的创建、容器的运行还有网络的通信,docker支持多种网络模式,以适应不同场景的容器通信需要。
本文不讲原理,只讲实践,通过列举各种场景,说明在docker的场景下多个容器之间如何通信。

二、准备

准备一台安装有docker的机器,笔者使用的是一台名为myvm1的虚拟机,ip为192.168.99.100

三、单机环境

首先我们来看在单台服务器上,可能会出现的docker容器通信场景

单个容器独立对外提供服务

例:一个开着6379的redis实例,供开发同学连接使用
在这里插入图片描述
在myvm1上启动一个redis容器

docker@myvm1:~$ docker run -d --name redis -e ALLOW_EMPTY_PASSWORD=yes -p 6379:6379 bitnami/redis:5.0
-d 后台运行
--name redis 指定容器名称
-e ALLOW_EMPTY_PASSWORD=yes 设置环境变量,允许空密码
-p 6379:6379 映射容器的6379到myvm1的6379
bitnami/redis:5.0 镜像名称

测试一下连接

$ redis-cli -h 192.168.99.100 -p 6379
192.168.99.100:6379>

这是一种最简单也是常见的网络访问方式,通过映射主机与容器的端口,使用主机IP+端口,从而访问容器内的服务。

docker是如何映射端口的呢?
1.看一下docker的网络列表

docker@myvm1:~$ docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
4e695b8923b8        bridge              bridge              local
e0a70416f49a        host                host                local
beca949fce33        none                null                local

2.可以看到有3个网络,再看下bridge的详情信息

docker@myvm1:~$ docker network inspect bridge
...
"Containers": {
    "6bec72f8abe49b8d399bdd738fbe446882ed6941d0b15f20da7d113918fac4a7": {
        "Name": "redis",
        "EndpointID": "f056f583e6afa32fcc1887f2afbb22448fc69f3e5e8594e7602dd1dfd61fcfe7",
        "MacAddress": "02:42:ac:11:00:02",
        "IPv4Address": "172.17.0.2/16",
        "IPv6Address": ""
    }
}
...

输出比较长,只截取Containers这段,可以看到包含了刚创建的redis容器

3.再从主机的角度看下6379的端口

root@myvm1:~# netstat -tulp | grep 6379
tcp        0      0 :::6379       :::*       LISTEN   2941/docker-proxy

可以看到myvm1的6379是被docker-proxy监听的

4.另外查看iptables chain

root@myvm1:~# iptables -L DOCKER
Chain DOCKER (1 references)
target     prot opt source               destination
ACCEPT     tcp  --  anywhere             172.17.0.2           tcp dpt:6379

可以看到6379被转发到了172.17.0.2,而这个ip正式上述b中出现的redis容器的ip地址

root@myvm4:~# ifconfig
docker0   Link encap:Ethernet  HWaddr 02:42:F7:68:34:D6
          inet addr:172.17.0.1  Bcast:172.17.255.255  Mask:255.255.0.0

5.总结

  • 安装docker后会在宿主机(myvm1)上创建一个虚拟网卡docker0
  • 后续创建的容器所分配的ip将从该虚拟网卡分配
  • 根据容器创建时的-p参数在主机上建立端口路由规则,将对主机端口的服务转发到具体容器对应的端口

两个容器之间访问

例:一个user-service服务访问redis实例
在这里插入图片描述

使用IP访问

为了方便我们使用bitnami/redis:5.0镜像的redis-cli代替user-service对redis的访问,模拟两个容器的通信

root@myvm1:~# docker ps -a
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                    NAMES
6bec72f8abe4        bitnami/redis:5.0   "/entrypoint.sh /run…"   9 hours ago         Up 9 hours          0.0.0.0:6379->6379/tcp   redis

可以看到主机的6379是绑定到0.0.0.0的,即主机上的所有ip,那现在主机有多少个ip呢

root@myvm1:~# ifconfig
docker0   Link encap:Ethernet  HWaddr 02:42:F7:68:34:D6
          inet addr:172.17.0.1  Bcast:172.17.255.255  Mask:255.255.0.0
         
eth1      Link encap:Ethernet  HWaddr 08:00:27:19:F6:25
          inet addr:192.168.99.100  Bcast:192.168.99.255  Mask:255.255.255.0

说明在myvm1上通过192.169.99.100和172.17.0.2都是能访问到redis的,验证一下

root@myvm1:~# docker run -it --rm bitnami/redis:5.0 redis-cli -h 172.17.0.2
Welcome to the Bitnami redis container
172.17.0.2:6379>

root@myvm1:~# docker run -it --rm bitnami/redis:5.0 redis-cli -h 192.168.99.100
Welcome to the Bitnami redis container
192.168.99.100:6379>

所以方式一可以通过主机ip或者docker虚拟ip互相访问,但这有个问题,就是换了机器部署ip可能会变,需要改参数

使用link参数
root@myvm1:~# docker run -it --rm --link redis:redis-host  bitnami/redis:5.0 redis-cli -h redis-host
Welcome to the Bitnami redis container
redis-host:6379>

--link redis:redis-host #冒号左边的redis表示要连接的容器名称,冒号右边为host别名,在容器内访问这个host别名就能访问到link的目标容器

通过link的方式,能够做到相对固定的写法,但官方已经不推荐使用link了,不久的将来将移除link模式,详见Legacy container links

创建自定义网络推荐
root@myvm1:~# docker network create my-bridge
a14418fb65607760962dff76e7e9ff0141bfdec3df1ee78677957fae244161ab

重新创建redis容器,指定使用自定义的my-bridge网络

root@myvm1:~# docker run -d --name redis -e ALLOW_EMPTY_PASSWORD=yes -p 6379:6379 --network my-bridge  bitnami/redis:5.0

这次增加了--network my-bridge参数

使用redis-cli验证一下连接

root@myvm1:~# docker run -it --rm --network my-bridge bitnami/redis:5.0 redis-cli -h redis
redis:6379>

注意这里也指定了--network my-bridge,因为要加入同一个网络。访问redis容器直接使用容器名称,即redis

在这里插入图片描述
官方推荐使用自定义的bridge网络,创建容器之间的连接,是单台主机上多个容器之间网络通信的最佳实践,更多docker network create选项

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值