Docker网络
1. 理解Docker0
- 清空所有环境
docker rm -f $(docker ps -aq)
docker rmi -f $(docker images -aq)
1.1 测试
-
三个网络
-
问题:docker 是如何处理容器网络访问的?
# 测试 进行一个tomcat docker run -d -P --name tomcat01 tomcat # 查看网络 docker exec -it tomcat01 ip addr
-
此时出现报错。这是版本不一致的缺失命令
OCI runtime exec failed: exec failed: unable to start container process: exec: "ip": executable file not found in $PATH: unknown
-
进入容器,更新所需的命令
shell docker exec -it tomcat01 /bin/bash apt update && apt install -y iproute2
-
更新完成之后退出容器,再次输入
docker exec -it tomcat01 ip addr
查看网络情况 -
发现容器启动的时候会得到一个
eth0@if7
的 ip 地址,这是 docke r分配的
-
思考:Linux 能不能 ping 通容器内部? --可以
-
容器内部可以 ping 通外界吗?–可以
# 进入容器之后需要执行以下命令 apt-get update apt install iputils-ping apt install net-tools
1.2 原理
-
我们没启动一个 docker 容器,docker 就会给 docker 容器分配一个 IP,我们只要安装了 docker,就会有一个网卡 docker0 桥接模式,使用的技术是
veth-pair
技术- 再次测试
ip addr
,发现多了一个ip
- 再次测试
-
在启动一个容器测试,发现又多了一对网卡
- 再次进入容器 tomcat2 内部更新命令资源,退出重新查看ip
- 可以发现和上面的是能对应上的,所以说是一对网卡!
- 我们发现这个容器带的网卡,都是一对对的
veth-pair
就是一对的虚拟设备接口,他们都是成对出现的,一端连着协议,一端彼此相连- 正因为有这个特性,利用
veth-pair
充当一个桥梁,连接各种虚拟网络设备的OpenStac
,Docker
容器之间的连接,OVS
的连接,都是使用veth-pair
技术
- 我们来测试一下 tomcat01 和 tomcat02 是否可以 ping 通
# 进入容器更新命令资源 docker exec -it tomcat02 /bin/bahs apt install iputils-ping # 更新完成后退出容器,输入ping命令 docker exec -it tomcat02 ping 172.17.0.2
结论:容器和容器之间是可以 ping 通的,并且是通过 docker0 而非直接连通
- 所有的容器不指定网络的情况下,都是 docker0 路由的,docker 会给我们的容器分配一个默认的可用 ip
1.3 小结
-
Docker 使用的是 Linux 的桥接,宿主机是一个 Docker 容器的网桥
docker0
-
Docker 中所有网络接口都是虚拟的(不需要考虑硬件因素),虚拟的转发效率高(内网传递文件)
-
只要容器删除,对应的一对网桥就没了
-
高可用!
思考一个场景:我们编写了一个微服务,database url=ip:项目不重启,但是数据ip换了,我们希望可以处理这个问题。故通过名字来进行访问容器。
2. -link
$ docker exec -it tomcat02 ping tomcat01
ping: tomcat01: Name or service not known
# 运行一个tomcat03 --link tomcat02
$ docker run -d -P --name tomcat03 --link tomcat02 tomcat
e63b5bd877a4ece0c56101064bb2f653c5e01f83baef067d9c7cd0db87e63208
# 运行一个tomcat03 --link tomcat02 可以ping通
$ docker exec -it tomcat03 ping tomcat02
# 用tomcat02 ping tomcat03 ping不通
# 如果报错OCI错误,是因为容器没有安装ping命令,依次执行以下命令
apt-get update
apt install iputils-ping
apt install net-tools
探究
-
查看网络详细信息。可以发现 link 链接的信息
docker inspect tomcat03
-
查看本地网桥
docker network inspect 网络id 网段
-
显示了三个容器的 ip 地址
-
查看 tomcat03 里面的
/etc/hosts
发现又 tomcat02 的配置
-
--link
本质就是在hosts
配置中添加映射 -
现在使用 Docker 已经不建议使用
--link
了 -
自定义网络,不适用
docker0
! -
docker0
问题:不支持容器名连接访问
3. 自定义网络
- 查看所有的 docker 网络
3.1 网络模式
- bridge:桥接 docker (默认,自己创建也是用 bridge 模式)
- none:不配置网络,一般不用
- host:和宿主机共享网络
- container:容器网络联通(用的少!局限很大)
3.2 测试
-
先清空所有的环境
docker rm -f $(docker ps -aq)
-
这时就恢复成只有五个网卡的状态
3.3 自定义网络
# 我们直接启动的命令 --net bridge, 而这个就是我们的docker0
# bridge 就是docker0
$ docker run -d -P --name tomcat01 tomcat
等价于 => docker run -d -P --name tomcat01 --net bridge tomcat
# docker0,特点:默认,域名不能访问。--link可以打通连接,但是很麻烦!
# 我们可以 自定义一个网络
$ docker network create --driver bridge --subnet 192.168.0.0/16 --gateway 192.168.0.1 mynet
$ docker network inspect mynet;
- 启动两个 tomcat ,再次查看网络情况
docker run -d -P --name tomcat01 --net mynet tomcat
docker run -d -P --name tomcat02 --net mynet tomcat
docker network inspect mynet
-
可以看到现在的两个容器,网卡是我们自定义的 ip 地址
-
在自定义的网络下,服务可以互相 ping 通,仅仅使用名字,无需
--link
-
我们自定的网络 docker 帮我们维护好了对应的关系,推荐我们平时这样使用网络!
好处
- redis 不同的集群使用不同的网络,保证集群是安全和健康的
- mysql 不同的集群使用不同的网络,保证集群是安全和健康的
4. 网络连通
-
docker0 和 mynet(自定义网络) 是无法直接连接的,并且也不能直接打通。若需要连通的话,要 connect 连接 docker0 的容器和 mynet 的网络
-
但是在实际的工作中,比如我们部署了mysql 使用了一个网段。部署了tomcat 使用了另一个网段,两个网段之间肯定是不能互相连通的,但是tomcat和mysql又需要相互连通,我们就要使用网络连通。原理图如下:
-
连通之后,发现 docker0 下的容器 tomcat1,直接被连到了 mynet 的网络下
-
这就是一个容器两个 ip 地址!
-
好比阿里云服务器,有一个公网 ip 和一个私网 ip
docker run -d -P --name tomcat-net-01 tomcat docker run -d -P --name tomcat-net-02 tomcat docker network connect mynet tomcat1 docker network inspect mynet
-
docker0 下的 tomcat-net-01 连通加入后,此时,它已经可以和 mynet 下的 tomat01 ping 通了
-
而 docker0 下的 tomcat-net-02 仍然是不通的
结论:假设要跨网络操作别人,就需要使用 docker net work connect
连通!
5. 实战:部署Redis集群
# 创建网卡
docker network create redis --subnet 172.38.0.0/16
# 通过脚本创建六个redis配置
for port in $(seq 1 6);\
do \
mkdir -p /mydata/redis/node-${port}/conf
touch /mydata/redis/node-${port}/conf/redis.conf
cat << EOF > /mydata/redis/node-${port}/conf/redis.conf
port 6379
bind 0.0.0.0
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
cluster-announce-ip 172.38.0.1${port}
cluster-announce-port 6379
cluster-announce-bus-port 16379
appendonly yes
EOF
done
# 通过脚本运行六个redis
for port in $(seq 1 6); \
do \
docker run -p 637${port}:6379 -p 1637${port}:16379 --name redis-${port} \
-v /mydata/redis/node-${port}/data:/data \
-v /mydata/redis/node-${port}/conf/redis.conf:/etc/redis/redis.conf \
-d --net redis --ip 172.38.0.1${port} redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf; \
done
# 进入其中一个容器
docker exec -it redis-1 /bin/sh
# 创建集群
redis-cli --cluster create 172.38.0.11:6379 172.38.0.12:6379 172.38.0.13:6379 172.38.0.14:6379 172.38.0.15:6379 172.38.0.16:6379 --cluster-replicas 1
-
docker 搭建 redis 集群完成!
-
在另一个会话中停止 redis-3 ,再次去查找数据。可以发现集群里面的主机宕机后,投票选举除了一个新的主机。
-
我们使用docker 之后,所有的技术都会慢慢变得简单起来!
6. 总结
-
veth pair
是成对出现的一种虚拟网络设备接口,一端连着网络协议栈,一端彼此相连。 -
docker中默认使用
docker0网络
。 -
docker0
相当于一个路由器的作用,任何一个容器启动默认都是docker0
网络。 -
docker0
是容器和虚拟机之间通信的桥梁。 -
推荐使用自定义网络,更好实现使用服务名的连通方式,避免ip改变的尴尬。
-
网络之间不能直接连通,网络连通是将一个容器和一个网络之间的连通,实现跨网络操作。