【Docker】docker网络

【Docer篇整理】

=========================
篇一:docker核心概念与常用指令
篇二:镜像与docker数据卷
篇三:dockerfile
篇四:docker网络

文章目录

  • 1、Veth
  • 2、理解Docker0
  • 3、- -link
  • 4、自定义网络
  • 5、网络连通
  • 6、实战:部署Reids集群
  • 7、SpringBoot微服务打包成Docker镜像

1、Veth

Veth是Linux中一种虚拟出来的网络设备,veth设备总是成对出现,所以一般也叫veth-pair。veth模拟了在物理世界里的两块网卡,以及一条网线。通过它可以将两个虚拟的设备连接起来,让他们之间相互通信。

【Docker】docker网络_第1张图片
如:v-a和v-b是一对veth设备,v-a收到的数据会从v-b发出。相反,v-b收到的数据会从v-a发出。Veth就像一根网线。

【Docker】docker网络_第2张图片

Veth设备的特点:

  • veth和其它的网络设备都一样,一端连接的是内核协议栈
  • veth设备是成对出现的,另一端两个设备彼此相连
  • 一个设备收到协议栈的数据发送请求后,会将数据发送到另一个设备上去

【Docker】docker网络_第3张图片
关于网桥:【Docker】docker网络_第4张图片

2、理解Docker0

# 查询ip地址
ip addr

查询宿主机IP地址,可以看到这三个IP:

【Docker】docker网络_第5张图片

在宿主机启动一个容器:发现容器启动的时候得到一个eth0@if115 ip地址,这是docker分配的

[root@9527 ~] docker run -d -P --name tomcat01 tomcat
 
# 查看容器内部的网络地址 ip addr
# 不用进入容器执行,就一句,直接跟后面
[root@9527 ~] docker exec -it tomcat01 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
114: eth0@if115: <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
 

思考: linux 宿主机能不能ping通这个容器?

[root@9527 ~] ping 172.17.0.2
PING 172.17.0.2 (172.17.0.2) 56(84) bytes of data.
64 bytes from 172.17.0.2: icmp_seq=1 ttl=64 time=0.077 ms
...
 
==>linux 可以 ping 通docker容器内部!

原理:

  • 每启动一个docker容器, docker就会给docker容器分配一个ip
  • 只要安装了docker,就会有一个网卡 docker0桥接模式,使用的技术是veth-pair技术

上面容器启动后,ip addr 查看宿主机:发现多了一个网卡vethcf5ccc0,115和114刚好与容器中的114: eth0@if115相对应:

【Docker】docker网络_第6张图片
再启动一个容器测试, ip addr 查看宿主机发现又多了一对网卡:

docker run -d -P --name tomcat02 tomcat

【Docker】docker网络_第7张图片

这种容器带来的网卡,都是一对一对的,这就是evth-pair技术。

# 我们发现这个容器带来网卡,都是一对对的
# veth-pair 就是一对的虚拟设备接口,他们都是成对出现的,一端连着协议,一端彼此相连
# 正因为有这个特性,veth-pair充当一个桥梁, 连接各种虚拟网络设备
# OpenStac, Docker容器之间的链接,OVS的链接, 都是使用veth-pair技术

测试tomcat01和tomcat02之间是否可以ping通:

docker exec -it tomcat02 ping 172.17.0.2


发现容器和容器之间是可以ping通的,网络模型图如下:

【Docker】docker网络_第8张图片

结论:

  • tomcat01和tomcat02是共用的一个路由器,docker0

  • 所有容器不指定网络的情况下,都是docker0路由的,doucker会给我们的容器分配一个默认的可用IP

这个可用IP的数量:
以255.255.0.1/16为例
00000000.00000000.00000000.00000000 (二进制下)
转十进制则为255.255.255.255
16即二进制下的前16位,即255.255.下是一个网络
===>
可用IP有255 x 255 - 1 - 1 = 655355
第一个1即0.0
第二个1即255.255

---
255.255.0.1/24 即只有最后的一位,255个IP是在这个网络范围的

Docker使用的是Linux的桥接,宿主机中是一个Docker容器的网桥docker0
【Docker】docker网络_第9张图片
Docker中的所有的网络接口都是虚拟的,因为虚拟的转发效率高(参考内网传递文件!)

3、- -link

[root@9527 ~] docker exec -it tomcat02 ping tomcat01
ping: tomcat01: Name or service not known

ping IP可以通,ping 容器名却不通,想实现通过容器名来互相访问,可以使用- -link

[root@9527 ~] docker run -d -P  --name tomcat03 --link tomcat02 tomcat
3a2bcaba804c5980d94d168457c436fbd139820be2ee77246888f1744e6bb473

[root@9527 ~] docker exec -it tomcat03 ping tomcat02
PING tomcat02 (172.17.0.3) 56(84) bytes of data.
64 bytes from tomcat02 (172.17.0.3): icmp_seq=1 ttl=64 time=0.129 ms
64 bytes from tomcat02 (172.17.0.3): icmp_seq=2 ttl=64 time=0.100 ms
...
 

反向可以ping通吗?----不能

[root@iZ2zeg4ytp0whqtmxbsqiiZ ~] docker exec -it tomcat02 ping tomcat03
ping: tomcat03: Name or service not known

原因探究:

【Docker】docker网络_第10张图片

继续往下看inspect信息:看到docker为每个容器分配的IP地址

【Docker】docker网络_第11张图片
这个tomcat03能ping通tomcat02就是–link时在03本地hosts文件配置了tomcat02的IP和名字

[root@9527 ~] docker exec -it tomcat03 cat /etc/hosts
127.0.0.1   localhost
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
172.17.0.3  tomcat02 f22ed47ed1be  ## !!!
172.17.0.4  3a2bcaba804c

现在已经不建议使用–link了,往下看自定义网络

4、自定义网络

查看所有的docker网络

docker network ls

【Docker】docker网络_第12张图片

网络模式

  • bridge: 桥接模式,docker 默认的模式,自己创建的也是用brdge模式

  • none: 不配置网络

  • host: 主机模式,即和宿主机共享网络

  • container:容器网络连通(用的少,局限很大)

# 直接启动的命令默认有一个 --net bridge,而这个就是我们的docker0
docker run -d -P --name tomcat01 tomcat
# 等价于
docker run -d -P --name tomcat01 --net bridge tomcat

docker0特点,默认,容器名不能访问(加 --link可以打通连接,但不建议),基于这个情况,考虑使用自定义网络:

自定义网络

# --driver bridge
# --subnet 192.168.0.0/16 可以支持255*255个网络 192.168.0.2 ~ 192.168.255.254
# --gateway 192.168.0.1
[root@9527 ~] docker network create --driver bridge 
			--subnet 192.168.0.0/16 
			--gateway 192.168.0.1 mynet
26a5afdf4805d7ee0a660b82244929a4226470d99a179355558dca35a2b983ec
[root@9527 ~] docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
30d601788862        bridge              bridge              local
226019b14d91        host                host                local
26a5afdf4805        mynet               bridge              local
7496c014f74b        none                null                local

创建成功,查看这个自定义网络的信息:

docker network inspect mynet

【Docker】docker网络_第13张图片
在自己创建的网络里面启动两个容器:

[root@9527 ~] docker run -d -P --name tomcat-net-01 --net mynet tomcat

[root@9527 ~] docker run -d -P --name tomcat-net-02 --net mynet tomcat

# ping IP连接和bridge网络下一样
[root@9527~] docker exec -it tomcat-net-01 ping 192.168.0.3
PING 192.168.0.3 (192.168.0.3) 56(84) bytes of data.
....

# 现在不使用 --link,直接可以ping名字
[root@9527~] docker exec -it tomcat-net-01 ping tomcat-net-02
PING tomcat-net-02 (192.168.0.3) 56(84) bytes of data.
 ...

我们自定义的网络docker都已经帮我们维护好了对应的关系,推荐我们平时这样使用网络。

如此,不同的集群使用不同的网络,保证了集群是安全和健康的。如下图中的redis集群和mysql集群:

【Docker】docker网络_第14张图片

两个不同网络下的集群如何连通,看下面。

5、网络连通

【Docker】docker网络_第15张图片
基于这个指令,测试在docker0和我自定义网络下的两个容器之间的连通:

[root@9527 ~] docker network connect  mynet tomcat01

连通之后就是将tomcat01 放到了mynet网络下,简单讲就是一个容器两个ip地址 ,类比阿里云服务器,公网ip,私网ip

[root@9527 ~] docker network inspect mynet 
# 查看下mynet网络的变化
# 看到tomcat01直接加入了mynet网络,拥有第二个IP

【Docker】docker网络_第16张图片

# 连通ok
[root@9527 ~] docker exec -it tomcat01 ping tomcat-net-01
PING tomcat-net-01 (192.168.0.2) 56(84) bytes of data.
....

# 换tomcat02依旧无法连通,没有connect
[root@iZ2zeg4ytp0whqtmxbsqiiZ ~] docker exec -it tomcat02 ping tomcat-net-01
ping: tomcat-net-01: Name or service not known
 

结论:假设要跨网络 操作别的容器,就要使用docker network connect连通…!

6、实战:部署Reids集群

实验选定 三主三从 的结构,启动六个容器:

【Docker】docker网络_第17张图片
首先创建Redis集群的自定义网络:

docker network create redis --subnet 172.38.0.0/16

接下来使用脚本直接创建六个Redis的配置:

# 通过脚本创建六个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

[root@9527 ~] ls /mydata/redis/
node-1 node-2 node-3 node-4 node-5 node-6

启动容器:

# 创建结点1
docker run -p 6371:6379 -p 16371:16379 --name redis-1 \
-v /mydata/redis/node-1/data:/data \
-v /mydata/redis/node-1/conf/redis.conf:/etc/redis/redis.conf \
-d 
--net redis 
--ip 172.38.0.11 
redis:5.0.9-alpine3.11 
redis-server /etc/redis/redis.conf
 
#创建结点2
docker run -p 6372:6379 -p 16372:16379 --name redis-2 \
-v /mydata/redis/node-2/data:/data \
-v /mydata/redis/node-2/conf/redis.conf:/etc/redis/redis.conf \
-d 
--net redis 
--ip 172.38.0.12 
redis:5.0.9-alpine3.11 
redis-server /etc/redis/redis.conf

....
3、4、5、6的创建指令一样,改下端口和配置文件、映射目录就行

docker ps 可以看到六个容器启动成功(这里也感受到了容器的轻量级,起六个也没啥)

【Docker】docker网络_第18张图片

创建Redis集群:

[root@9527 ~] docker exec -it redis-1 /bin/sh
/data : ls
appendonly.aof  nodes.conf
/data : 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

>>> Performing hash slots allocation on 6 nodes...
Master[0] -> Slots 0 - 5460
Master[1] -> Slots 5461 - 10922
Master[2] -> Slots 10923 - 16383
.....

【Docker】docker网络_第19张图片
等待搭建成功后,连接集群:

[root@9527 ~] docker exec -it redis-1 /bin/sh
/data : redis-cli - c # 注意加-c,即cluster
127.0.0.1:6379> cluster info

127.0.0.1:6379> cluster nodes

【Docker】docker网络_第20张图片

set一个值存入Redis:

127.0.0.1:6379> set a b 
-> Redirected to slot located at 172.38.0.13:6379
OK

可以看到是13这台master处理了,此时停掉13,即redis-3容器

[root@9527 ~] docker stop redis-3

模拟主节点挂了以后,此时再get刚存入的值,观察是否从机生效(选举):

127.0.0.1:6379> get a  
-> Redirected to slot located at 172.38.0.14:6379
"b"

可以看到14做为13的从机,查数据仍然没问题!!

【Docker】docker网络_第21张图片

13failed,14成为master,集群部署成功!

7、SpringBoot微服务打包成Docker镜像

基本步骤是:

  • 敲代码,写Springboot项目
  • 打包应用
  • 编写Dockerfile
  • 构建镜像
  • 发布运行

创建一个测试demo工程:

【Docker】docker网络_第22张图片

并新建一个controller

@RestController
public class HelloController{
	
	@GetMapping("/hello")
	public String hello(){
		return "hello,9527";
	}
}

maven中的package打包:

【Docker】docker网络_第23张图片

本地测试jar包可正常启动,且能访问localhost:8080/hello

【Docker】docker网络_第24张图片
下载docker插件:
【Docker】docker网络_第25张图片
【Docker】docker网络_第26张图片

下载完成后可连接远程仓库:

【Docker】docker网络_第27张图片

编写Dockerfile文件

【Docker】docker网络_第28张图片

这里先不CI/CD,直接把jar包和Dockerfile文件放到Linux宿主机,执行docker build

[root@9527 ~] mkdir idea
[root@9527 ~] cd idea
[root@9527 idea] docker build -t code9527 .

镜像构建成功后,启动容器:

[root@9527 idea] docker -d -P --name springboot-web code9527

# 启动成功后,docker ps看到随机映射端口是32779
[root@9527 idea] curl localhost:32779/test
hello,9527
[root@9527 idea] 

成功!

以后,交付的时候,交付一个镜像即可。部署时docker pull ,运行容器即可!当然实际开发需要CI/CD和K8s对大量容器进行编排。

【Docker篇整理结束 2023/5/6 00:12】

【Docker】docker网络_第29张图片

你可能感兴趣的:(Docker笔记,docker,网络,linux)