云原生(三)、Docker网络

Docker网络

在 Docker 中,不同容器之间的网络访问原理取决于容器所使用的网络模式。下面是 Docker 中常见的两种网络模式下容器间网络访问的原理:

  1. 桥接模式(Bridge)

    • 在桥接模式下,Docker 使用 Linux 桥接技术创建一个虚拟的网络桥接设备,所有容器都连接到该桥接设备上。
    • 每个容器都被分配一个唯一的 IP 地址,并且它们可以通过这些 IP 地址相互通信。
    • Docker 主机上运行的容器可以使用 NAT(Network Address Translation)机制来实现与外部网络的通信。
    • 当容器之间需要通信时,数据包会在它们之间通过 Linux 桥接设备转发。
  2. 主机模式(Host)

    • 在主机模式下,容器与宿主机共享网络命名空间,它们直接使用宿主机的网络栈和接口。
    • 因此,在主机模式下,容器之间的网络访问就像是它们运行在同一台主机上的进程之间的通信,无需进行额外的网络转发或 NAT。
    • 容器可以直接使用宿主机上的 IP 地址和端口,因此在主机模式下,容器之间的通信速度可能会更快,但也可能会导致端口冲突和网络配置更改的困扰。

我们主要使用docker的桥接模式

bash 复制代码
#准备工作,清空当前的容器与镜像
docker rm -f $(dokcer ps -a -q)
docker rmi -f $(dokcer ps -aq)

使用ip addr 查看网络状态

bash 复制代码
[root@hcss-ecs-8f46 ~]# 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 mq state UP group default qlen 1000
    link/ether fa:16:3e:0f:69:6a brd ff:ff:ff:ff:ff:ff
    inet 192.168.2.3/20 brd 192.168.15.255 scope global dynamic noprefixroute eth0
       valid_lft 314842758sec preferred_lft 314842758sec
    inet6 fe80::f816:3eff:fe0f:696a/64 scope link 
       valid_lft forever preferred_lft forever
#docker 创建的网络
3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default 
    link/ether 02:42:87:87:66:38 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:87ff:fe87:6638/64 scope link 
       valid_lft forever preferred_lft forever

1、微服务这么多,会有无数的ip地址,所以可以通过容器的名称访问容器网络,docker每启动一个容器,就会创建一个ip。

bash 复制代码
[root@hcss-ecs-8f46 ~]#  docker run -itd --name web-01 centos
Unable to find image 'centos:latest' locally
latest: Pulling from library/centos
7a0437f04f83: Already exists 
Digest: sha256:dbbacecc49b088458781c16f3775f2a2ec7521079034a7ba499c8b0bb7f86875
Status: Downloaded newer image for centos:latest
3c3f2c1f573c6bf504dd91f6b2946e496644cd8e7a599a249beb71d8fc68a083
[root@hcss-ecs-8f46 ~]# docker exec -it web-01 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启动容器是产生的ip,它归docker0管
54: eth0@if55: <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

# 容器外部可以ping通容器内部的ip地址
[root@hcss-ecs-8f46 ~]# 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.041 ms
64 bytes from 172.17.0.2: icmp_seq=2 ttl=64 time=0.034 ms
1、分析容器外部ping容器内部的网络原理
bash 复制代码
[root@hcss-ecs-8f46 ~]# 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 mq state UP group default qlen 1000
    link/ether fa:16:3e:0f:69:6a brd ff:ff:ff:ff:ff:ff
    inet 192.168.2.3/20 brd 192.168.15.255 scope global dynamic noprefixroute eth0
       valid_lft 314841874sec preferred_lft 314841874sec
    inet6 fe80::f816:3eff:fe0f:696a/64 scope link 
       valid_lft forever preferred_lft forever
3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
    link/ether 02:42:87:87:66:38 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:87ff:fe87:6638/64 scope link 
       valid_lft forever preferred_lft forever
55: veth1da7586@if54: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default 
    link/ether d2:72:78:49:50:2b brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet6 fe80::d072:78ff:fe49:502b/64 scope link 
       valid_lft forever preferred_lft forever
[root@hcss-ecs-8f46 ~]# docker exec -it web-01 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
54: eth0@if55: <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
  • 启动容器后,会自动创建IP地址

  • 网路容器外与容器内的网络是配对的。例如我们新运行的centos,外部分配的网络是"55: veth1da7586@if54:",容器内部存在网络地址"54: eth0@if55: "

  • 总结

    • 只要启动一个容器,就会默认分配一对网卡
    • 这对网络是虚拟接口"veth-pair",它是一对虚拟设备接口,成对出现,一端连着协议栈,一端彼此相连
    • 就好比一个桥梁,连接容器内外
  • inet 172.17.0.2/16 brd 172.17.255.255 总共可以创建 255*255个容器,再多就没有网络地址了。

2、容器删除或重启后,IP变化,如何解决容器间的网络访问问题
  • 方案1、--link,但不方便,几乎不用。
bash 复制代码
# 通过参数 --link在容器启动时就链接到另一个容器网络中,就可以通过名称ping了
docker run -itd --name web-02 --link web-01  centos
docker exec -it web-02 ping web-01

# 但是反向仍ping不通
[root@hcss-ecs-8f46 ~]# docker exec -it web-01 ping web-02
ping: web-02: Name or service not known


# 底层原理:
# 与本机的域名解析过程类似,host 127.0.0.1 www.badu.com
# --links 相当于hosts 添加了一条记录。
  • 方案2、自定义网络。
bash 复制代码
[root@hcss-ecs-8f46 ~]# docker network --help

Usage:  docker network COMMAND

Manage networks

Commands:
  connect     Connect a container to a network
  create      Create a network
  disconnect  Disconnect a container from a network
  inspect     Display detailed information on one or more networks
  ls          List networks
  prune       Remove all unused networks
  rm          Remove one or more networks

Run 'docker network COMMAND --help' for more information on a command.

# docker0的特点
 1.它是默认的
 2.域名访问不通
 3.通过--link域名通了,但容器删了就又不行了
bash 复制代码
[root@hcss-ecs-8f46 ~]# docker network ls
NETWORK ID     NAME      DRIVER    SCOPE
3e1cb1f23c44   bridge    bridge    local
3783048b4c7a   host      host      local
eddad10b8bca   none      null      local
[root@hcss-ecs-8f46 ~]# docker network inspect 3e1cb1f23c44
[
    {
        "Name": "bridge",
        "Id": "3e1cb1f23c447860fa017d76195a53b025cb117a7e0ef4bea77ba41d9b378b39",
        "Created": "2024-03-13T10:46:36.060713723+08:00",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": null,
            "Config": [
                {
                #网络配置 网段 /16代表后俩位数字可以 故总网段数为255*255
                    "Subnet": "172.17.0.0/16",
                    "Gateway": "172.17.0.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        # 之前创建的容器,都在contain内中
        "Containers": {
            "3c3f2c1f573c6bf504dd91f6b2946e496644cd8e7a599a249beb71d8fc68a083": {
                "Name": "web-01",
                "EndpointID": "390419366b591b79b84e7f662a40f440d1fb439478f11756f049828d21b5c247",
                "MacAddress": "02:42:ac:11:00:02",
                "IPv4Address": "172.17.0.2/16",
                "IPv6Address": ""
            },
            "995d9af8e8c729ef1a5bf19a0ddd9c2a79d30d825a1b94a562d8e9e1585e3a50": {
                "Name": "web-02",
                "EndpointID": "b0d57efdd0cf62641c0e6ec8c0ea9eb52e0a6a688aeac7b67c3bd7dbfe6d26f9",
                "MacAddress": "02:42:ac:11:00:03",
                "IPv4Address": "172.17.0.3/16",
                "IPv6Address": ""
            }
        },
        "Options": {
            "com.docker.network.bridge.default_bridge": "true",
            "com.docker.network.bridge.enable_icc": "true",
            "com.docker.network.bridge.enable_ip_masquerade": "true",
            "com.docker.network.bridge.host_binding_ipv4": "0.0.0.0",
            "com.docker.network.bridge.name": "docker0",
            "com.docker.network.driver.mtu": "1500"
        },
        "Labels": {}
    }
]
创建自定义网络

create命令创建一个新的网络 myDockerStudy

bash 复制代码
docker network create --driver bridge --subnet 192.169.0.0/16 --gateway 192.169.0.1 myDockerStudyNet

[root@hcss-ecs-8f46 ~]# docker network inspect myDockerStudyNet
[
    {
        "Name": "myDockerStudyNet",
        "Id": "cb2029ad79edbe63a178253584d997e1b91586c1ccb6adebbf36123ea511452a",
        "Created": "2024-03-17T11:45:42.577493481+08:00",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": {},
            "Config": [
                {
                    "Subnet": "192.169.0.0/16",
                    "Gateway": "192.169.0.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {},
        "Options": {},
        "Labels": {}
    }
]

通过网络指定使用自己创建的网络.

bash 复制代码
docker run -itd --name  web-01-net --net  myDockerStudyNet centos
docker run -itd --name  web-02-net --net  myDockerStudyNet centos

[root@hcss-ecs-8f46 ~]# docker network inspect cb2
[
    {
        "Name": "myDockerStudyNet",
        "Id": "cb2029ad79edbe63a178253584d997e1b91586c1ccb6adebbf36123ea511452a",
        "Created": "2024-03-17T11:45:42.577493481+08:00",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": {},
            "Config": [
                {
                    "Subnet": "192.169.0.0/16",
                    "Gateway": "192.169.0.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {
            "f112d82ae67e66fab583c6986ccaf87b489a49a4e56652e6c83d4a2e6d126160": {
                "Name": "web-02-net",
                "EndpointID": "dfdae007633db3dd06e82a900857b3157a021a5277a5272eaabfb41d77cb927f",
                "MacAddress": "02:42:c0:a9:00:03",
                "IPv4Address": "192.169.0.3/16",
                "IPv6Address": ""
            },
            "fa6d1332e302d27350969c1f64f87e2c378adbc182971899e35d8ab1052b376e": {
                "Name": "web-01-net",
                "EndpointID": "5d35bd6354a686152d3a4e8ada3e33cf74628b105476dbd6239316aa0250cd5c",
                "MacAddress": "02:42:c0:a9:00:02",
                "IPv4Address": "192.169.0.2/16",
                "IPv6Address": ""
            }
        },
        "Options": {},
        "Labels": {}
    }
]

使用自身创建的网络,容器间可以互相ping的

bash 复制代码
##ip
[root@hcss-ecs-8f46 ~]# docker exec -it web-01-net ping 192.169.0.3
PING 192.169.0.3 (192.169.0.3) 56(84) bytes of data.
64 bytes from 192.169.0.3: icmp_seq=1 ttl=64 time=0.071 ms


##容器名称
[root@hcss-ecs-8f46 ~]# docker exec -it web-01-net ping web-02-net
PING web-02-net (192.169.0.3) 56(84) bytes of data.
64 bytes from web-02-net.myDockerStudyNet (192.169.0.3): icmp_seq=1 ttl=64 time=0.049 ms

##反ping

[root@hcss-ecs-8f46 ~]# docker exec -it web-02-net ping web-01-net
PING web-01-net (192.169.0.2) 56(84) bytes of data.
64 bytes from web-01-net.myDockerStudyNet (192.169.0.2): icmp_seq=1 ttl=64 time=0.048 ms

总结:使用自定义网络后。容器之间就可以通过容器名称互相访问了。ip无论发生怎样的变化,也不会产生错误。

3、容器与多网络联通

通过以上的操作,我们现在共有2个网络。分别是docker0与我们的自定义网络myDockerStudyNet。那么这两个网路能否互相ping通呢

bash 复制代码
# 无法ping通
[root@hcss-ecs-8f46 ~]# docker exec -it web-01 ping 192.169.0.3
PING 192.169.0.3 (192.169.0.3) 56(84) bytes of data.
^C
--- 192.169.0.3 ping statistics ---
6 packets transmitted, 0 received, 100% packet loss, time 145ms

所以自定义网络之间库存时互不相通的,我们使用自定义网络的好处就是网络隔离。

如果在同一个网络下,有些程序猿的恶意代码就不能防止了,所以在部署时。使用网络隔离,创建两个桥接网卡,比如订单业务(里面的数据库、redis、mq,都在order-net网络下),其他业务在其他网络。

那么关键问题出现了,如何成功让web-01-net ping web-01?

bash 复制代码
#使用docker network connect命令
[root@hcss-ecs-8f46 ~]# docker network connect --help

Usage:  docker network connect [OPTIONS] NETWORK CONTAINER

Connect a container to a network

Options:
      --alias strings           Add network-scoped alias for the container
      --driver-opt strings      driver options for the network
      --ip string               IPv4 address (e.g., "172.30.100.104")
      --ip6 string              IPv6 address (e.g., "2001:db8::33")
      --link list               Add link to another container
      --link-local-ip strings   Add a link-local address for the container
      
      
# 执行
[root@hcss-ecs-8f46 ~]# docker network connect myDockerStudyNet web-01
[root@hcss-ecs-8f46 ~]# docker network inspect myDockerStudyNet
[
    {
        "Name": "myDockerStudyNet",
        "Id": "cb2029ad79edbe63a178253584d997e1b91586c1ccb6adebbf36123ea511452a",
        "Created": "2024-03-17T11:45:42.577493481+08:00",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": {},
            "Config": [
                {
                    "Subnet": "192.169.0.0/16",
                    "Gateway": "192.169.0.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {
            "09479e1e460ff05ca7da8c810d9a36bde71f923952e5dbb27e8497482fc2e7a1": {
                "Name": "web-01",
                "EndpointID": "12d3797952ae9f5a34fb3dc5dee8d034529abda6da8e33f86a1061a4d38f6840",
                "MacAddress": "02:42:c0:a9:00:04",
                "IPv4Address": "192.169.0.4/16",
                "IPv6Address": ""
            },
            "f112d82ae67e66fab583c6986ccaf87b489a49a4e56652e6c83d4a2e6d126160": {
                "Name": "web-02-net",
                "EndpointID": "dfdae007633db3dd06e82a900857b3157a021a5277a5272eaabfb41d77cb927f",
                "MacAddress": "02:42:c0:a9:00:03",
                "IPv4Address": "192.169.0.3/16",
                "IPv6Address": ""
            },
            "fa6d1332e302d27350969c1f64f87e2c378adbc182971899e35d8ab1052b376e": {
                "Name": "web-01-net",
                "EndpointID": "5d35bd6354a686152d3a4e8ada3e33cf74628b105476dbd6239316aa0250cd5c",
                "MacAddress": "02:42:c0:a9:00:02",
                "IPv4Address": "192.169.0.2/16",
                "IPv6Address": ""
            }
        },
        "Options": {},
        "Labels": {}
    }
]

**会发现web-01同时存在于docker0,myDockerStudyNet两个网络中。且该容器拥有了两个ip地址。**myDockerStudyNet中的3个容器就可以互相访问了。

总结

如果要夸网络操作别的容器,使用docker network connect命令。最终即使是天一样多的网络,也可以清晰且任意的在各个网络中访问

相关推荐
King without kingdom1 小时前
面试题(三)
运维·服务器·网络
亿林安全2 小时前
等保测评中的常见误区及应对策略
网络·安全·web安全
亿林网络安全事业部2 小时前
等保测评:企业如何构建安全的网络架构
网络·安全·架构
求学者1.03 小时前
网络编程问题解答
网络
MAMA66813 小时前
一个简单的基于C语言的HTTP代理服务器的案例
c语言·网络·http
云兮Coder4 小时前
鸿蒙Harmony应用开发,数据驾驶舱网络请求(Axios) 封装
网络·华为·harmonyos
赵渝强老师4 小时前
【赵渝强老师】K8s的DaemonSets控制器
linux·docker·云原生·容器·kubernetes
江西昊仔4 小时前
Docker指令学习1
学习·docker·eureka
Proxy7115 小时前
SOCKS5代理为何比HTTP代理更快?
网络·网络协议·http
qq_316837755 小时前
https的连接过程
网络·网络协议·ssl