Docker的网络,是课程第四章的内容

1.本章概述和实验环境介绍

实验环境使用vagrant创建虚拟机,Vargantfile可以去docker-labs里面查看

2.网络基础回顾

一些基本的网络知识,略

3.Linux网络命名空间

3.1Linux网络命名空间

相关命令:

  • ip netns list,列出现在有多少network namespace(netns)
  • ip netns add test1,添加一个netns,name是test1
  • ip netns delete test1,删除一个netns
  • ip netns exec test1 ip a,在test1这个netns下,执行ip a命令
  • ip a显示现在的网络设置
  • ip link,类似ip a,但是信息略少
  • ip netns exec test1 ip link set dev lo up,设置设备lo的状态为up,但是会变成unknown,因为要变成up需要满足两端是连起来的这个条件

3.2Network namespace连通

netns 要在两个之间加上veth,veth就是一对pair,要把一个放到eth0里面,另一个放到eth1里面。这样eth0和eth1就会连通了。

3.3创建veth

  1. netns add test1,创建名为test1的network namespace(netns)
  2. netns add test2,创建test2
  3. ip link add veth-test1 type veth peer name veth-test2,创建veth,一端是veth-test1,一端是veth-test2
  4. ip link,查看创建的veth
  5. ip link set veth-test1 netns test1,把veth-test1添加到test1这个netns里面,运行完成之后test1里面会多一个veth,但是本机里面的veth就会没有了。相当于移动到test1里面
  6. ip netns exec test1 ip addr add 192.168.1.1/24 dev veth-test1,给veth-test1这个设备添加ip地址
  7. ip netns exec test1 ip link set dev veth-test1 up,设置veth-test1这个设备的状态为up
  8. ip link set veth-test2 netns test2
    ip netns exec test2 ip addr add 192.168.1.2/24 dev veth-test2
    ip netns exec test2 ip link set dev veth-test2 up,对test2进行相同操作
  9. ip netns exec test1 ping 192.168.1.2,在test1下ping test2的ip,要是设置正确的话,因为已经有了veth,所以两边是会通的

4.Docker bridge0详解

4.1Docker Network的相关命令

  1. docker network ls,查看docker的网络情况
  2. docker network inspect network_id,可以查看有哪个容器是在这个network里面的

4.2查看bridge的情况

可以使用brctl这个工具来查看bridge的情况
安装:yum install -y bridge-utils
使用:brctl show

4.3Bridge Network的情况

BridgeNetwork

  • 我们创建了一个docker容器之后,使用ip a,会看到多了一个网络设备,这个设备就是veth的一端,另一端是在创建的容器里面的。这样容器就可以和我们本机连通了
  • 在本机这一边的所有veth又是都连接到docker0的,是通过bridge的方式。我们可以通过brctl show这个命令来查看。那么所有的docker容器之间就可以互相访问了
  • docker0又使用NAT的方式和eth0连接,这样docker容器就可以访问互联网了

NOTICE

有的时候我们需要测试网络情况等等,会需要启动一个docker容器,但是不需要什么功能,只要是个容器就行了,那我们肯定希望这个容器越简单越好,我们可以使用busybox来创建 sudo docker run -d --name test busybox /bin/sh -c "while true; do sleep 3600; done"

5.容器之间的link

docker容器启动的时候带上link参数:

1
2
3
4
5
6
7
8
9
# 创建test1容器
docker run -d --name test1 busybox /bin/sh -c "while true; do sleep 3600; done"
# 创建test2容器,link到test1
docker run -d --name test2 --link test1 busybox /bin/sh -c "while true; do sleep 3600; done"
# test1,test2互相ping对方的ip,是可以ping通的
docker exec test1 ping 172.17.0.3
docker exec test2 ping 172.17.0.2
# 在test2里ping test1
docker run exec test2 ping test1

启动test2容器,link了test1。因为test1和test2都是连接到docker0上的,所以test1和test2之间是互通的,我们只要ping双方的ip就可以了。但是现在test2已经link到test1了,那么我们在test2里面ping test1(注意是ping test1,不用ping test1的ip),也是可以的。但是要注意,test1里面用ping test2是不可以的,因为link有一个方向的概念。

5.2docker network相关命令

  • docker network ls,可以查看现在的network
  • docker network create -d bridge my-bridge,创建一个名为my-bridge的network,-d指定类型为bridge
  • docker run -d --name test3 --network my-bridge busybox /bin/sh -c "while true; do sleep 3600; done",在创建容器的时候指定–network,那么容器就会连接到这个network上,可以使用brctl show来查看
  • docker network inspect my-bridge,也是可以查看连接到network的容器
  • docker network connect my-bridge test2,指定已经存在的容器连接到my-bridge这个network,但是容器还是会连接原本连接的那个network

NOTICE

我们用docker network connect my-bridge test2这个命令之后,那么原本就在my-bridge这个network里面的容器,可以直接ping test2(注意这里是直接ping test2就可以了,不用ping test2的ip也是可以的),也是会成功的。这是因为所有连接在自己创建的bridge上面的容器,相互之间都是可以默认用name来ping的。test2一旦加入my-bridge,也是可以直接ping这个网络内的其他容器的,比如ping test3

6.容器的端口映射

  1. docker run --name web -d -p 80:80 nginx,这样在docker容器启动起来之后,我们在本机curl 127.0.0.1,访问的就是docker容器里面的nginx
  2. docker run --name web -d -p 81:80 nginx,注意,这里是本机的81端口和docker容器的80端口,也就是说这时候在本机要访问 curl http://127.0.0.1:81 ,这样才会访问到docker容器里面

7.容器网络之host和none

7.1none网络

  1. docker run -d --name test1 --network none busybox /bin/sh -c "while true; do sleep 3600; done",使用–network指定连接到none这个network
  2. docker network inspect none,可以查看none的网络情况

none网络里面的容器,只有一个回环地址,没有其他的网络设备,也就是除了docker exec -it这种方式进入内部,外部是根本没有办法访问到这个容器的。我们可能会问用了none网络的容器有什么用?可能这个容器是一种工具,比如生成密码的,需要安全性,所以就用none网络,限制外部访问。

7.2host网络

  1. docker run -d --name test1 --network host busybox /bin/sh -c "while true; do sleep 3600; done",指定连接到host网络
  2. docker network inspect host,可以查看host的网络情况

host网络里面的容器,我们使用docker exec -it进入内部之后,可以看到ip a的结果和我们本机的ip a的结果是一样的。也就是容器和本机是用相同的网络的。这样的方式可能出现的问题是端口的占用,比如本机已经有其他软件使用了80端口,那么容器就没有办法使用80端口了

8.多容器复杂应用的部署演示

8.1部署演示

  1. 先启动redis容器
    docker run -d –name redis redis,不用使用-p参数把端口绑定到本机,因为这个redis只是给之后的flask-redis容器使用的,不是给本机使用的。
  2. 启动我们的flask程序
    docker run -d –link redis –name flask-redis -p 5000:5000 -e REDIS_HOST=redis liguoqinjim/flask-redis,首先是使用–link连接到redis容器,那么flask-redis这个容器里面ping redis得到的就是redis容器的ip,-p把5000端口映射到本机,-e给这个容器设置环境变量REDIS_HOST。那么我们程序里面会去取这个环境变量,得到的就是redis,那因为已经link过了,所以redis就相当于redis容器的ip了。

8.2docker env

  1. docker run -d --name test1 -e ENV_TEST=123 busybox /bin/sh -c "while true; do sleep 3600; done",-e设置容器的环境变量。
  2. docker exec test1 env,查看test1容器的环境变量,可以看到ENV_TEST这个变量

9.Overlay和Underlay的通俗解释

不同机器上的docker容器之间的通信,是靠VXLAN来实现的。VXLAN又需要overlay和underlay来完成整个过程。

overlay

VXLAN的大致实现的思路是:本来我们两个机器之前ping,最简单包里面的数据就是有一个src有一个dst,分别是自己的地址和目的地址。那么现在不同机器里面的容器,要去向别的机器的容器。我们把这个数据包整个加载到之前的机器的ping数据包里面。在机器间数据包到达目标机器的时候,解包之后再去向目标容器

10.Docker Overlay网络和etcd实现多机容器通信

在多个机器上的容器要相互通信,要有一个大前提,也就是每个容器的ip不能一样,不同机器的不同容器的ip都是不能一样的。因为要是一样,那数据包肯定是无法到达目标机器的。
所以我们为了保证每个容器的ip是不一样的,我们要使用一个第三方的分布式工具来保证ip不一样。这个实验里面我们使用etcd这个分布式工具

10.1多机容器通信

  1. 首先要在不同机器之间创建一个etcd的集群
  2. 要重启docker,参数里面要带上集群的参数
  3. 创建overlay的docker网络,我们在一台机器上创建一个overlay网络就可以了,因为有了etcd,每个机器上的docker都已经自动同步了,其他机器上也会有一个overlay网络。比如我们在机器1上面创建一个name为test1的容器,这个时候我们在机器2上面创建一个name为test1的容器时,docker是会报错的。因为docker不允许有两个name一样的容器。机器2的docker会知道已经有test1就是因为etcd的关系
  4. 运行容器,注意要使用–network命令,把容器连接到overlay的network里面。当两个容器都在overlay网络里面的时候,我们就可以相互ping了
  5. 这个时候我们使用docker network ls,我们会发现多了一个network,类型为bridge,name应该是docker_gwbridge。这个network是干什么的呢?这个network给容器访问外网的。具体可以查看下面的图片。

docker_gwbridge

10.2启动参数

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
## 启动命令
### 下载etcd
wget https://github.com/coreos/etcd/releases/download/v3.3.9/etcd-v3.3.9-linux-amd64.tar.gz

### docker-node1启动etcd
nohup ./etcd --name docker-node1 --initial-advertise-peer-urls http://192.168.205.10:2380 \
--listen-peer-urls http://192.168.205.10:2380 \
--listen-client-urls http://192.168.205.10:2379,http://127.0.0.1:2379 \
--advertise-client-urls http://192.168.205.10:2379 \
--initial-cluster-token etcd-cluster \
--initial-cluster docker-node1=http://192.168.205.10:2380,docker-node2=http://192.168.205.11:2380 \
--initial-cluster-state new&

### docker-node2启动etcd
nohup ./etcd --name docker-node2 --initial-advertise-peer-urls http://192.168.205.11:2380 \
--listen-peer-urls http://192.168.205.11:2380 \
--listen-client-urls http://192.168.205.11:2379,http://127.0.0.1:2379 \
--advertise-client-urls http://192.168.205.11:2379 \
--initial-cluster-token etcd-cluster \
--initial-cluster docker-node1=http://192.168.205.10:2380,docker-node2=http://192.168.205.11:2380 \
--initial-cluster-state new&

### 检查etcd启动是否正确
./etcdctl cluster-health

### 重新启动docker-node1
sudo service docker stop
sudo /usr/bin/dockerd -H tcp://0.0.0.0:2375 -H unix:///var/run/docker.sock --cluster-store=etcd://192.168.205.10:2379 --cluster-advertise=192.168.205.10:2375&

### 重新启动docker-node2
sudo service docker stop
sudo /usr/bin/dockerd -H tcp://0.0.0.0:2375 -H unix:///var/run/docker.sock --cluster-store=etcd://192.168.205.11:2379 --cluster-advertise=192.168.205.11:2375&

### 在docker-node1机器上创建overlay网络
docker network create -d overlay demo
docker network ls

### 在docker-node1里面 查看etcd里面的数据
./etcdctl ls /docker/network/v1.0/network

### test1容器ping test2
docker network inspect demo,用来查看overlay网络里面容器的ip
docker exec test1 ping ...