运维实战 容器部分 Docker网络
Posted 洛冰音
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了运维实战 容器部分 Docker网络相关的知识,希望对你有一定的参考价值。
运维实战 容器部分 Docker网络
原生网络模式
Docker
安装后会自动创建3种网络: Bridge
. Host
, None
, Docker
安装时会创建一个名为docker0
的Linux bridge
, 新建的容器会自动桥接到这个接口.
docker0
作为所有容器的网关,默认IP为172.17.0.1
,新创建的容器分配的IP
默认单调递增,因此如果不加以设置每次开启容器时的IP都可能出现变化.
##安装用于查看信息的软件包
yum install bridge-utils.x86_64
##查看网桥初始状态
[root@Server1 ~]# brctl show
bridge name bridge id STP enabled interfaces
docker0 8000.02424bfd7ed8 no
##创建容器后可以观察到有接口接在了网桥上
[root@Server1 ~]# docker run -d --name nginx nginx:latest
c980d6466da5a6f21c247099abec01aa2f4b333f21b0714ada8838b99d9a994c
[root@Server1 ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
c980d6466da5 nginx:latest "/docker-entrypoint.…" 4 seconds ago Up 3 seconds 80/tcp Nginx
[root@Server1 ~]# brctl show
bridge name bridge id STP enabled interfaces
docker0 8000.02424bfd7ed8 no veth50c8b1c
##新的容器也会依次接入
[root@Server1 ~]# docker run -d --name Nginx2 nginx:latest
97c176c978040853067c5268897319c4f49fc30884499bc757084671bb79d689
[root@Server1 ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
97c176c97804 nginx:latest "/docker-entrypoint.…" 3 seconds ago Up 1 second 80/tcp Nginx2
c980d6466da5 nginx:latest "/docker-entrypoint.…" 49 seconds ago Up 48 seconds 80/tcp Nginx
[root@Server1 ~]# brctl show
bridge name bridge id STP enabled interfaces
docker0 8000.02424bfd7ed8 no veth50c8b1c
veth90063b4
关闭容器, 则桥接自动关闭
Bridge
模式下容器没有一个公有IP, 只有宿主机可以直接访问, 外部主机是不可见的. 容器通过宿主机的NAT规则后可以访问外网.
Host模式
Host
模式可以让容器共享宿主机网络栈, 这样的好处是外部主机与容器直接通信, 但是容器的网络缺少隔离性.
Host
网络模式需要在容器创建时指定--network
##可以看到采用Host模式创建的容器并没有直接挂接在docker0上
[root@Server1 ~]# docker run -d --name Nginx --network host nginx:latest
f60c42e66598f7a8557f11e42e2876c12cb957dc6bd4bcca92c693e7a28707e6
[root@Server1 ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
f60c42e66598 nginx:latest "/docker-entrypoint.…" 5 seconds ago Up 4 seconds Nginx
[root@Server1 ~]# brctl show
bridge name bridge id STP enabled interfaces
docker0 8000.02424bfd7ed8 no
[root@Server1 ~]# ip addr
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
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether 52:54:00:9b:66:f1 brd ff:ff:ff:ff:ff:ff
inet 172.25.5.1/24 brd 172.25.5.255 scope global eth0
valid_lft forever preferred_lft forever
inet6 fe80::5054:ff:fe9b:66f1/64 scope link
valid_lft forever preferred_lft forever
3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default
link/ether 02:42:4b:fd:7e:d8 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
valid_lft forever preferred_lft forever
inet6 fe80::42:4bff:fefd:7ed8/64 scope link
valid_lft forever preferred_lft forever
None模式
None
模式是指禁用网络功能, 只有lo接口,在容器创建时使用--network=none
进行指定
[root@Server1 ~]# docker run -d --name Nginx --network none nginx:latest
d13f5ba0fc1a10a3c325e6f000c0c8ab28ee150caec8ba26099ba53327be62a9
[root@Server1 ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
d13f5ba0fc1a nginx:latest "/docker-entrypoint.…" 4 seconds ago Up 3 seconds Nginx
[root@Server1 ~]# brctl show
bridge name bridge id STP enabled interfaces
docker0 8000.02424bfd7ed8 no
查看容器内部网络情况
##Host模式
[root@Server1 ~]# docker run -it --name Centos --network host centos:latest
[root@Server1 /]# ip addr
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
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether 52:54:00:9b:66:f1 brd ff:ff:ff:ff:ff:ff
inet 172.25.5.1/24 brd 172.25.5.255 scope global eth0
valid_lft forever preferred_lft forever
inet6 fe80::5054:ff:fe9b:66f1/64 scope link
valid_lft forever preferred_lft forever
3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default
link/ether 02:42:4b:fd:7e:d8 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
valid_lft forever preferred_lft forever
inet6 fe80::42:4bff:fefd:7ed8/64 scope link
valid_lft forever preferred_lft forever
[root@Server1 /]# hostname
Server1
##None模式
[root@Server1 ~]# docker run -it --name Centos --network none centos:latest
[root@80228b8f69f6 /]# ip addr
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
Docker自定义网络
自定义网络模式中, Docker
提供了三种自定义网络驱动: bridge
, overlay
和macvlan
bridge
驱动类似默认的bridge
网络模式, 但增加了一些新的功能;
overlay
和macvlan
是用于创建跨主机网络.
建议使用自定义的网络来控制哪些容器可以相互通信, 还可以自动DNS解析容器名称到IP地址.
创建自定义网桥
#没有指定,默认为桥接docker
[root@Server1 ~]# docker network create MyNet1
f7778a9243a9115df2232bce7f51b7f2e0cad255dde85f2e62aab3c7d353345a
[root@Server1 ~]# docker network ls
NETWORK ID NAME DRIVER
SCOPEf7778a9243a9 MyNet1 bridge
localaa1073e86d69 bridge bridge
local2c8ef7f4a10e host host
local48d010d8c011 none null local
- 指定容器运行在该网络中
docker run -it --name Node1 --network MyNet1 busybox
ip addr #可以看到ip呈单调递增趋势
ctrl+p+q #将运行的容器打入后台, 不要关闭, 如果关闭, 分配的ip会被回收
docker run -it --name Node2 --network MyNet1 busybox
ip addr
##可以ping通同一网络中的容器
ping Node1
##自带DNS解析功能
cat /etc/hosts
自定义网段及网关
- 删除之前测试用的容器, 创建新的网络源
MyNet2
[root@Server1 ~]# docker network create --subnet 172.20.0.0/24 --gateway 172.20.0.1 MyNet2
2c8c1dc7fcbc9e4848103248ce074af88ee9a3fc0f37ed507780288b699a99fd
[root@Server1 ~]# docker network ls
NETWORK ID NAME DRIVER
SCOPEf7778a9243a9 MyNet1 bridge
local2c8c1dc7fcbc MyNet2 bridge
localaa1073e86d69 bridge bridge
local2c8ef7f4a10e host host
local48d010d8c011 none null local
[root@Server1 ~]# docker network inspect MyNet2
[
{ "Name": "MyNet2",
"Id": "2c8c1dc7fcbc9e4848103248ce074af88ee9a3fc0f37ed507780288b699a99fd",
"Created": "2021-04-28T13:51:37.120782352+08:00",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": {},
"Config": [
{
"Subnet": "172.20.0.0/24",
"Gateway": "172.20.0.1"
}
]
},
"Internal": false,
"Attachable": false,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {},
"Options": {},
"Labels": {}
}]
- 运行容器并指定IP
docker run -it --name Node1 --network MyNet2 --ip 172.20.0.10 ubuntu
ip addr
ctrl+p+q将该容器进程打入后台,注意不能直接关闭
docker run -it --name Node2 --network MyNet2 --ip 172.20.0.11 ubuntu
使用--ip
参数可以指定容器IP地址, 但必须是在自定义网桥上, 默认的bridge模式不支持.
同一网桥上的容器是可以互通的.
- 不同网桥的容器通信
在MyNet1
中运行新容器, 由于MyNet1
没有使用自定义模式, 不需要指定IP
docker run -it --name Node3 --network MyNet1 ubuntu
docker run -it --name Node4 --network MyNet1 ubuntu
MyNet1
中的Node3
和Node4
属于同一网络, 互相可以联通.
但与Node1
和Node2
不在同一网络中, 互相不能联通.
- 不同网络
MyNet1
和MyNet2
实现通信
##为Node1添加一块MyNet1的网卡
docker network connect MyNet1 Node1
##进入容器
docker container attach vm1
ip addr
##可以连通Node3和Node4了
Docker容器通信
容器之间除了使用IP
通信外, 还可以使用容器名称通信, Docker 1.10
开始, 内嵌了一个DNS server
, dns
解析功能必须在自定义网络中使用, 启动容器时使用 --name 参数指定容器名称.
Joined容器方式通信
docker run -it --name Node1 --network MyNet1 ubuntu
docker run -it --name Node2 --network container:Node1 ubuntu
处于这个模式下的Docker
容器会共享一个网络栈, 这样两个容器之间可以使用localhost
高效快速通信.
Link链接方式通信
--link
可以用来链接2个容器
docker run -it --name Node1 ubuntu
docker run -it --name Node2 --link Node1:web ubuntu
##都可以ping通,上面设置了Node1的别名为web
ping vm1
ping web
##可以看到自动设置了解析
cat /etc/hosts
外网如何访问容器
- 外网访问容器用到了
docker-proxy
和iptables DNAT
- 宿主机访问本机容器使用的是
iptables DNAT
- 外部主机访问容器或容器之间的访问是
docker-proxy
实现
docker-proxy
和DNA
T实现了双冗余, 只要其中一个存在都可以实现从外网访问容器
跨主机容器网络
跨主机网络解决方案
Docker
原生的overlay
和macvlan
- 第三方的
flannel
,weave
,calico
众多网络方案是如何与Docker
集成在一起的
-
采用
libnetwork
这一Docker
容器网络库 -
CNM (Container Network Model)这个模型对容器网络进行了抽象
CNM分三类组件
- Sandbox: 容器网络栈,包含容器接口,
DNS
, 路由表 - Endpoint: 作用是将
Sandbox
接入Network
- Network: 包含一组
endpoint
,同一Network
的endpoint
可以通信
Macvlan网络方案实现
特点
- 是
Linux kernel
提供的一种网卡虚拟化技术. - 无需
Linux bridge
, 直接使用物理接口, 性能极好. - 无需
NAT
和端口映射 - 会独占主机网卡 但可以通过子接口进行设置
操作流程
- 首先在实验用虚拟机上增加新的一块网卡
- 打开网卡混杂模式
[root@Server2 docker]# ip link set eth1 promisc on
[root@Server2 docker]# ip addr show
[root@Server2 docker]# ip link set up eth1
[root@Server2 docker]# ip addr show
[root@Server2 docker]# docker network create -d macvlan --subnet 10.0.0.00/24 --gateway 10.0.0.1 -o parent=eth1 MacVlan
[root@Server2 docker]# docker network ls
NETWORK ID NAME DRIVER
SCOPE42c1b23d732f MacVlan1 macvlan
locala1fc6d2b4881 bridge bridge
locala8e736a43b65 host host
local1cea84391117 none null
local
[root@Server2 docker]# docker run -it --name Node1 --network MacVlan1 --ip 10.0.0.10 busybox:latest
/ #
##在Server1进行同样的操作后进行联通测试
/ # ping 10.0.0.10PING 10.0.0.10 (10.0.0.10):
56 data bytes64 bytes from 10.0.0.10: seq=0 ttl=64 time=0.611 ms
64 bytes from 10.0.0.10: seq=1 ttl=64 time=1.349 ms
64 bytes from 10.0.0.10: seq=2 ttl=64 time=1.278 ms
64 bytes from 10.0.0.10: seq=3 ttl=64 time=1.131 ms
--- 10.0.0.10 ping statistics ---4 packets transmitted, 4 packets received, 0% packet lossround-trip min/avg/max = 0.611/1.092/1.349 ms
可以看出, macvlan
方式确实做到了外部主机相互连接
macvlan
会独占主机网卡,但是可以使用vlan
子接口实现多macvlan
网络
vlan
可以将物理二层网络划分为4094个逻辑网络并彼此隔离.
因此vlan id
的取值为1
-4094
[root@Server1 docker]# docker network create -d macvlan --subnet 20.0.0.00/24 --gateway 20.0.0.1 -o parent=eth1.1 MacVlan
2831f365c16bf92878c1bd31caba449e230ae0149be66e7f9915e3b0dd854c7cd
[root@Server1 docker]# docker run -it --name Node2 --network MacVlan2 --ip 20.0.0.11 busybox:latest
Macvlan网络间的隔离和连通
macvlan
网络在二层上是隔离的,所以不同macvlan
网络的容器时不能相互通信的- 可以在三层上通过网关将
macvlan
连通起来 Docker
本身不做任何限制,像传统vlan
网络那样管理即可
以上是关于运维实战 容器部分 Docker网络的主要内容,如果未能解决你的问题,请参考以下文章