很多情况下单个容器不足以维持整个服务,这就需要多个容器同时运转,因此必须保证容器之间的网络通信。
docker中的网络从覆盖范围可分为单个宿主机上的容器网络和跨多个宿主机的容器网络
安装docker时会自动在宿主机上创建三个网络
docker network ls
NETWORK ID NAME DRIVER SCOPE
94005da5d612 bridge bridge local
8aa390d1b8b4 host host local
9a75beb05504 none null local
docker有四种网络类型,none网络、host网络、bridge网络和用户自定义网络。
none网络
在none网络中,只有一个lo网卡,也就是说配置none网络的容器不能联网。因此很多对安全性要求较高且不需要联网的服务都会部署在none网络的容器中。
创建一个none网络的容器
docker run -itd --network=none centos:latest /bin/bash
进入容器查看ip
ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
host网络
连接到host网络的容器共享宿主机的网络栈,容器的网络配置与宿主机几乎一样,在容器中可以看到宿主机的所有网卡。
当容器对网络传输效率有较高要求时,就可以选择host网络。但是host网络不够灵活,比如要考虑端口冲突问题。另外,有些跨宿主机的网络会用到host网络
创建一个host网络的容器
docker run -itd --network=host centos:latest /bin/bash
查看ip
ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
4: eth0@if5: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
valid_lft forever preferred_lft forever
bridge网络
docker安装时会自动创建一个名为docker0的Linux bridge,如果不指定network,创建的容器都会挂在docker0上。我们可以来看看这个网桥。
先下载一个网桥管理工具
yum -y install bridge-utils
查看网桥
brctl show
bridge name bridge id STP enabled interfaces
docker0 8000.0242c86febe9 no
我们创建一个容器,观察docker0有什么变化
创建一个容器
docker run -itd centos:latest /bin/bash
再次查看网桥
brctl show
bridge name bridge id STP enabled interfaces
docker0 8000.0242c86febe9 no vetha2a2353
一个新的网络接口vetha2a2353被挂在了docker0上,vetha2a2353就是新创建容器的虚拟网卡。现在进入刚才的容器
ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
6: eth0@if7: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
valid_lft forever preferred_lft forever
容器有一个网卡eth0@if7,
事实上eth0@if7和vetha2a2353是一对veth pair。veth pair是一种成对出现的特殊网络设备,就像由一根网线连接起来的一对网卡,网线的一头(eth0@if7)在容器中,另一头(vetha2a2353)挂在网桥docker0上,这样eth0@if7就与docker0连接了起来。
我们还发现eth0@if7的ip是172.17.0.2,这是由什么决定的
docker network inspect bridge
[
{
"Name": "bridge",
"Id": "7eb41ec5fe8362e4a5f8c27c87512c126f00fbf9b9d726b4d72e90c14c6bc777",
"Created": "2019-10-22T19:25:49.616892457+08:00",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": null,
"Config": [
{
"Subnet": "172.17.0.0/16",
"Gateway": "172.17.0.1"
}
]
},
容器是以进程的形式存在于系统中的,也就是说最多不超过65535个,16位的掩码足够docker使用
user-defined网络
如果不喜欢用docker自带的bridge,还可以自己创建一个类似bridge的网络。
创建用户自定义网络
创建一个自定义网络
docker network create --driver bridge my_net1
查看网桥变化
docker network ls
NETWORK ID NAME DRIVER SCOPE
7eb41ec5fe83 bridge bridge local
a0757ad947a3 host host local
3e4cc21b0387 my_net1 bridge local
d5b646785c1f none null local
多了一个新的网络
还可以指定网桥的子网和容器的ip
指定自定义网桥的子网
docker network create --driver bridge --subnet=172.20.1.0/24 --gateway=172.20.1.1 my_net2
开启一个容器并使用新建的自定义网络
docker run -itd --network=my_net2 centos:latest /bin/bash
指定ip(只有使用--subnet创建的网络才能指定静态ip)
docker run -itd --network=my_net2 --ip=172.20.1.100 centos:latest /bin/bash
让连接其他网络的容器连接到my_net2
docker run -itd --network=my_net1 centos:latest /bin/bash
docker network contect my_net2 cranky_haibt
如果使用user-defined网络并使用--name指定容器的名字后,docker会自带DNS通信
docker run -itd --network=my_net2 --name=node1 centos:latest /bin/bash
docker run -itd --network=my_net2 --name=node2 centos:latest /bin/bash
接下来在两台容器内可以直接ping通对方的名字
容器之间的网络互联
创建一个db容器以模拟数据库服务
docker run -itd --network=my_net2 --name db centos:latest /bin/bash
创建一个web容器以模拟nginx服务并连接到db容器
docker run -itd --network=my_net2 --name web --link db:dblink centos:latest /bin/bash
--link db:dblink是这个连接的对端名字和连接名字,也就是说web容器和db容器建立了一个名为dblink的连接
查看连接情况
docker ps -a
使用ping来确定连接情况。我们会发现web容器能访问到db容器,而db容器不能访问web容器
容器端口映射
启动容器时如果不指定参数,从容器外部无法通过网络访问容器内部的服务
因此我们需要指定端口映射来将容器内部的端口映射到宿主机
-P 随机映射一个49000~49900的端口到容器内部开放的服务端口
-p 宿主机端口:容器端口,指定要映射的端口
既然如此我们可以尝试将nginx容器的服务映射到宿主机上
docker run -itd -p 10000:80 --name nginx_server nginx
查看映射
docker port eb1b8027922d
80/tcp -> 0.0.0.0:10000
从浏览器上访问宿主机的10000端口,web服务正在运行