• Docker基础入门:Docker网络与微服务项目发布



    💖The Begin💖点点关注,收藏不迷路💖

    在这里插入图片描述

    一、前言

    Docker是当今最流行的容器化平台之一,它提供了一个轻量级、可移植和可扩展的应用环境。

    而在Docker中,网络是构建容器化应用的关键组成部分之一。本文将深入探讨Docker网络,构建高效、可扩展的应用容器化网络架构。

    二、Docker0理解

    在 Docker 中,“docker0” 是一个虚拟以太网桥接口,用于连接主机与运行的容器之间的通信。

    当在主机上安装 Docker 时,它会自动创建 “docker0” 网络接口。它具有一个默认的 IP 地址(通常是 172.17.0.1)和一个子网掩码。Docker 容器启动时,会自动分配一个 IP 地址,并连接到 “docker0” 网桥。

    通过 “docker0” 网桥,容器可以相互之间进行通信,也可以与主机进行通信。还可以通过端口映射将容器内部的服务暴露给主机或外部网络。

    “docker0” 是 Docker 默认的网络配置,还可以使用其他网络驱动程序和网络模式来创建不同类型的网络,以满足不同的应用需求。

    2.1 ip a查看当前网络环境

    在这里插入图片描述

    问题:docker 是如何处理容器网络访问的???
    在这里插入图片描述

    2.2 实战–启动一个tomact01容器(查看网络环境)

    1、启动一个tomact容器
    docker run -d -P --name tomact01 tomcat
    
    • 1
    • 2
    2、查看容器的内部网络地址  ip addr
    [root@zyl-server ~]# docker exec -it tomcat01 ip a
    OCI runtime exec failed: exec failed: unable to start container process: exec: "ip": executable file not found in $PATH: unknown
    
    • 1
    • 2
    • 3

    报错:

    OCI runtime exec failed: exec failed: unable to start container process: exec: "ip": executable file not found in $PATH: unknown
    
    • 1

    因为该容器的镜像时精简版,内部缺少iproute2导致无法使用ip命令。

    报错解决:

    进入容器
    
    docker exec -it 容器名 /bin/bash
    
    进入后:
    
    ##更新apt
    
    apt-get update
    
    ##安装iproute2
    
    apt install -y iproute2
    
    ##安装完以后退出exit
    
    ##检查
    docker exec -it 容器名 ip addr
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    在这里插入图片描述
    在这里插入图片描述

    3、容器启动后会得到一个eth0@if7的地址(docker分配的地址)
    
    [root@zyl-server ~]# docker exec -it tomcat01 ip a
    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
    6: eth0@if7: <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
    [root@zyl-server ~]#
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    4、思考:在主机能不能ping通容器内部这个docker分配的地址???
    
    ping <容器IP地址>
    
    • 1
    • 2
    • 3

    在这里插入图片描述

    原理:

    当Docker容器启动时,它会被分配一个IP地址,并且默认情况下会与主机上的"docker0"网桥接口相连。通过主机上的网络栈,可以使用分配给容器的IP地址与容器进行通信。

    5、再次ip addr 查看,发现又多了一对网卡(vethbd9e5f4@if6 ,vethbd9e5f4@if8),和tomcat容器的网卡( eth0@if7)相似
    
    原因:veth-pair充当了一个桥梁,连接了各种虚拟网络设备。
    
    "veth" 接口工作在不同的网络命名空间中,其中一个端口连接到主机上的"docker0"网桥,而另一个端口连接到容器内部的网络栈(例如"eth0")。
    
    通过这样的网络配置,容器可以使用独立的IP地址和网络设置与其他容器或主机进行通信,同时保持网络隔离和安全性。
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    在这里插入图片描述

    2.3 实战–启动一个tomact02容器(查看网络环境)

    6、再次启动一个tomcat02,思考:tomcat02与tomcat01之间是否可以ping通???
    [root@zyl-server ~]# docker run -d -P --name tomcat02 tomcat
    
    
    [root@zyl-server ~]# docker ps
    CONTAINER ID   IMAGE     COMMAND             CREATED          STATUS          PORTS                                         NAMES
    60014b1a25c2   tomcat    "catalina.sh run"   38 minutes ago   Up 38 minutes   0.0.0.0:32769->8080/tcp, :::32769->8080/tcp   tomcat02
    732466647cdc   tomcat    "catalina.sh run"   39 minutes ago   Up 39 minutes   0.0.0.0:32768->8080/tcp, :::32768->8080/tcp   tomcat01
    [root@zyl-server ~]#
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    7、测试tomcat02与tomcat01之间的通信
    
    docker exec -it tomcat02 ping 172.17.0.2
    
    • 1
    • 2
    • 3

    报错:

    
    [root@zyl-server ~]# docker exec -it tomcat02 ping 172.17.0.2
    OCI runtime exec failed: exec failed: unable to start container process: exec: "ping": executable file not found in $PATH: unknown
    [root@zyl-server ~]#
    
    • 1
    • 2
    • 3
    • 4

    解决:

    // 进入容器内部
    [root@zyl-server ~]# docker exec -it tomcat01 /bin/bash
    [root@zyl-server ~]# docker exec -it tomcat02 /bin/bash
    
    // tomcat02与tomcat01安装iputils-ping
    
    apt install -y iputils-ping
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    8、再次测试(tomcat02 ping 172.17.0.2[root@zyl-server ~]# docker exec -it tomcat02 ping 172.17.0.2
    
    (tomcat01 ping 172.17.0.3[root@zyl-server ~]# docker exec -it tomcat01 ping 172.17.0.3
    
    • 1
    • 2
    • 3
    • 4
    • 5

    在这里插入图片描述

    2.4 容器与容器之间的通信

    结论:容器与容器之间是可以通信的!!!!

    如:tomcat01与tomcat02之间共用一个路由器(docker0)。

    在这里插入图片描述

    2.5 总结

    Docker 默认使用桥接(Bridge)网络模式

    在桥接网络模式下,Docker 会创建一个名为 “docker0” 的虚拟以太网桥接口,并为每个容器分配一个虚拟网络接口(veth pair)-----转发效率高。容器的网络流量会通过这个虚拟网络接口与主机上的 “docker0” 桥接口相连。

    通过桥接网络,不同的容器可以彼此通信,也可以与主机进行通信,同时它们共享主机的网络连接。默认情况下,Docker 容器会自动分配一个 IP 地址,并且可以通过主机或其他容器的 IP 地址进行访问。

    在这里插入图片描述
    只要容器删除,对应的网桥对就没了!!!

    2.6 容器间通过服务名通信

    前面tomcat01与tomcat02之间是通过IP通信的,怎么实现通过服务名通信???

    [root@zyl-server ~]# docker exec -it tomcat02 ping tomcat01
    ping: tomcat01: Name or service not known
    [root@zyl-server ~]#
    
    
    • 1
    • 2
    • 3
    • 4

    问题思考:假如一个微服务场景,database url=ip:xxx,项目不重启,数据库ip变了,如何解决这个问题,怎么实现通过服务名通信???

    解决:

    1、再启动一个tomcat03,使用--link
    
    ##--link tomcat02:将容器 "tomcat02" 与新创建的 "tomcat03" 容器进行链接(连接)
    
    [root@zyl-server ~]# docker run -d -P --name tomcat03 --link tomcat02 tomcat
    5dd7eba42a5c236b272dac6ef4624da6eed564325af8b8491b451d16418a884e
    [root@zyl-server ~]#
    
    2、测试(tomcat03 ping tomcat02),使用服务名通信
    [root@zyl-server ~]# docker exec -it tomcat03 ping tomcat02
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    在这里插入图片描述

    3、反向则不能ping通(tomcat02 ping tomcat03)
    
    [root@zyl-server ~]# docker exec -it tomcat02 ping tomcat03
    ping: tomcat03: Name or service not known
    [root@zyl-server ~]#
    
    • 1
    • 2
    • 3
    • 4
    • 5

    探究原因

    [root@zyl-server ~]# 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 60014b1a25c2
    172.17.0.4      5dd7eba42a5c
    [root@zyl-server ~]#
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    其实–link 就是在hosts配置中增加了一个

    172.17.0.3      tomcat02 60014b1a25c2
    
    • 1

    在这里插入图片描述

    –link 选项在容器中添加了一个条目到 /etc/hosts 文件中,以便容器可以通过服务名称进行相互访问。

    使用 --link 命令将两个容器连接在一起时,Docker 会自动修改容器的 /etc/hosts 文件,将被链接的容器的 IP 地址和服务名称映射为条目。

    这样,“tomcat03” 容器就可以通过使用服务名称 “tomcat02” 访问到 “tomcat02” 容器。

    不过需要注意的是,–link 选项已经过时,推荐使用 自定义网络(User-defined Network)来实现容器间的连接和通信。用户自定义网络提供更灵活和可持续的解决方案,更好地管理容器之间的关系和网络配置。

    三、自定义网络(User-defined Network)

    Docker 提供了用户自定义网络(User-defined Network)的功能,它允许您在 Docker 环境中创建自己的网络,并在这个网络上运行容器。使用用户自定义网络可以更好地管理容器之间的关系和网络配置。

    3.1 查看所有docker网络

    要列出 Docker 中的所有网络,可以使用 docker network ls 命令。该命令将显示当前 Docker 环境中的所有网络及其详细信息。

    列出 Docker 中的所有网络:

    [root@zyl-server ~]# docker network ls
    NETWORK ID     NAME      DRIVER    SCOPE
    8290ad5ab9f8   bridge    bridge    local
    fe8aa9233f89   host      host      local
    7ae86ca33507   none      null      local
    [root@zyl-server ~]#
    
    NETWORK ID:网络的唯一标识符。
    NAME:网络的名称。
    DRIVER:网络驱动程序类型。
    SCOPE:网络的范围(local 表示仅限本地)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    其中包含了几个常见的网络,如默认的 bridge 网络(桥接)、用户自定义的 mynetwork 网络,以及其他特殊网络如 host(和宿主机共享网络)和 none(不配置网络)。

    3.2 使用 Docker 创建自定义网络的步骤

    1、创建一个名为 "mynetwork" 的用户自定义网络:
    [root@zyl-server ~]# docker network create --driver bridge  --subnet 192.168.0.0/16 --gateway 192.168.0.1 mynetwork
    da1bb471897eeb1d7e3e867fe7124d29d806da6b06e05cd2c9fd86580ac55486
    [root@zyl-server ~]#
    
    驱动程序(Driver):通过 --driver bridge 参数指定了网络驱动程序为 bridge,这意味着创建的网络将采用桥接模式。桥接模式是 Docker 默认的网络模式,使得容器可以通过网络桥接与宿主机和其他容器相连。
    
    子网(Subnet):通过 --subnet 192.168.0.0/16 参数指定了网络的子网。这意味着创建的网络将包含在以 192.168.0.0 为起始地址、子网掩码为 /16(即 255.255.0.0)的子网中。这个子网范围内的 IP 地址将被分配给容器。
    
    网关(Gateway):通过 --gateway 192.168.0.1 参数指定了网络的网关地址。该地址将作为网络的出口地址,用于容器与外部网络之间的通信。
    
    [root@zyl-server ~]# docker network ls
    NETWORK ID     NAME        DRIVER    SCOPE
    8290ad5ab9f8   bridge      bridge    local
    fe8aa9233f89   host        host      local
    da1bb471897e   mynetwork   bridge    local
    7ae86ca33507   none        null      local
    [root@zyl-server ~]#
    
    [root@zyl-server ~]# docker network inspect mynetwork
    [
        {
            "Name": "mynetwork",
            "Id": "da1bb471897eeb1d7e3e867fe7124d29d806da6b06e05cd2c9fd86580ac55486",
            "Created": "2023-08-31T00:01:02.667263189+08:00",
            "Scope": "local",
            "Driver": "bridge",
            "EnableIPv6": false,
            "IPAM": {
                "Driver": "default",
                "Options": {},
                "Config": [
                    {
                        "Subnet": "192.168.0.0/16",
                        "Gateway": "192.168.0.1"
                    }
                ]
            },
            "Internal": false,
            "Attachable": false,
            "Ingress": false,
            "ConfigFrom": {
                "Network": ""
            },
            "ConfigOnly": false,
            "Containers": {},
            "Options": {},
            "Labels": {}
        }
    ]
    [root@zyl-server ~]#
    
    
    • 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
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52

    在这里插入图片描述

    2、运行容器并将其连接到用户自定义网络:
    docker run -d --name container1 --network mynetwork image1
    docker run -d --name container2 --network mynetwork image2
    
    
    如:还是启动两个tomcat:
    docker run -d -P --name tomcat-mynet-01 --network mynetwork tomcat
    docker run -d -P --name tomcat-mynet-02 --network mynetwork tomcat
    
    我们创建了两个tomcat容器,并将它们连接到 "mynetwork" 网络。这样,这两个容器就可以通过服务名称进行通信,而无需使用 IP 地址。
    
    请注意,--network 参数用于指定容器要连接到的网络(用户自定义网络 mynetwork )。
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    在这里插入图片描述

    3、进入容器
    
    docker exec -it 容器名 /bin/bash
    
    进入后:
    
    ##更新apt
    
    apt-get update
    
    ##安装iproute2
    
    apt install -y iproute2
    
    ##安装iputils-ping
    apt install -y iputils-ping
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    报错:
    在apt-get update的时候出现了如下异常。

    Err:1 http://deb.debian.org/debian bullseye InRelease   Temporary failure resolving 'deb.debian.org' 
    
    Err:2 http://security.debian.org/debian-security bullseye-security InRelease   Temporary failure resolving 'security.debian.org'
    
    • 1
    • 2
    • 3

    解决:

    原因在于DNS服务解析异常,解决的方法也很简单,只需要修改/etc/docker/daemon.json加入如下内容即可(如果没有这个文件则创建

     "dns": ["8.8.8.8", "114.114.114.114"]
    
    • 1

    在这里插入图片描述

    最后重启docker服务,系统即可正常解析镜像网站并运行

    systemctl restart docker
    
    • 1

    在这里插入图片描述

    删除tomcat-mynet-01、tomcat-mynet-02,再次执行步骤二、步骤三。启动两个tomcat。

    4、容器间通信:
    现在,使用容器名称进行容器间的通信。在容器内部,可以使用服务名称或容器名称作为主机名来访问其他容器。
    
    例如,在 tomcat-mynet-01 内部,可以通过服务名称 tomcat-mynet-01 访问 tomcat-mynet-01:
    
    ping tomcat-mynet-02
    
    同样,在 tomcat-mynet-02 内部,可以通过服务名称 tomcat-mynet-02 访问 tomcat-mynet-01:
    
    ping tomcat-mynet-01
    
    
    示例:
    
    [root@zyl-server ~]#  docker exec -it tomcat-mynet-02 /bin/bash
    root@7ff9f7a73f15:/usr/local/tomcat# ping tomcat-mynet-01
    PING tomcat-mynet-01 (192.168.0.2) 56(84) bytes of data.
    64 bytes from tomcat-mynet-01.mynetwork (192.168.0.2): icmp_seq=1 ttl=64 time=0.103 ms
    64 bytes from tomcat-mynet-01.mynetwork (192.168.0.2): icmp_seq=2 ttl=64 time=0.127 ms
    64 bytes from tomcat-mynet-01.mynetwork (192.168.0.2): icmp_seq=3 ttl=64 time=0.161 ms
    ^C
    --- tomcat-mynet-01 ping statistics ---
    3 packets transmitted, 3 received, 0% packet loss, time 2001ms
    rtt min/avg/max/mdev = 0.103/0.130/0.161/0.023 ms
    root@7ff9f7a73f15:/usr/local/tomcat#
    
    
    或者:
    
    [root@zyl-server ~]# docker exec -it tomcat-mynet-01 ping tomcat-mynet-02
    PING tomcat-mynet-02 (192.168.0.3) 56(84) bytes of data.
    64 bytes from tomcat-mynet-02.mynetwork (192.168.0.3): icmp_seq=1 ttl=64 time=0.134 ms
    64 bytes from tomcat-mynet-02.mynetwork (192.168.0.3): icmp_seq=2 ttl=64 time=0.137 ms
    64 bytes from tomcat-mynet-02.mynetwork (192.168.0.3): icmp_seq=3 ttl=64 time=0.131 ms
    64 bytes from tomcat-mynet-02.mynetwork (192.168.0.3): icmp_seq=4 ttl=64 time=0.148 ms
    ^C
    --- tomcat-mynet-02 ping statistics ---
    4 packets transmitted, 4 received, 0% packet loss, time 3007ms
    rtt min/avg/max/mdev = 0.131/0.137/0.148/0.006 ms
    [root@zyl-server ~]#
    
    • 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

    在这里插入图片描述

    在这里插入图片描述

    3.3 总结

    在这里插入图片描述

    1、启动一个tomcat04
    
    [root@zyl-server ~]# docker run -d -P --name tomcat04  tomcat
    
    2、测试,tomcat04 ping tomcat-mynet-02
    
    [root@zyl-server ~]# docker exec -it tomcat04 ping tomcat-mynet-02
    ping: tomcat-mynet-02: Name or service not known
    [root@zyl-server ~]#
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    使用用户自定义网络可以提供更好的容器间通信方式,而不仅仅依赖于 --link 命令。用户自定义网络还可以提供更多高级功能,如容器发现、DNS 名称解析、子网划分等。

    3.4 容器之间进行网络连通

    在3.3 基础上,引出了网络连通(思考:如果容器A ping 容器D能否ping通)。

    [root@zyl-server ~]# 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.
    [root@zyl-server ~]#
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    docker network子命令:
    
    docker network create <network-name>:创建一个自定义网络。
    docker network ls:列出所有网络。
    docker network inspect <network-name>:显示指定网络的详细信息。
    docker network connect <network-name> <container-name>:将指定容器连接到指定的网络。
    docker network disconnect <network-name> <container-name>:将指定容器从指定的网络中断开连接。
    docker network rm <network-name>:删除指定的网络。
    可以通过运行docker network <command> --help来获取特定命令的更详细的帮助信息,例如docker network connect --help[root@zyl-server ~]# 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@zyl-server ~]#
    
    选项和参数:
    
    NETWORK:要连接的网络的名称或ID。
    CONTAINER:要连接到网络的容器的名称或ID。
    可选选项:
    
    --alias:为容器添加一个网络范围的别名。可以指定多个别名,使用空格分隔。
    --driver-opt:指定网络驱动选项,用于配置网络驱动程序。
    --ip:指定容器的IPv4地址。
    --ipv6-address:指定容器的IPv6地址。
    --link-local-ip:为容器添加一个链路本地地址(IPv4)。可以指定多个地址,使用空格分隔。
    --link-local-ipv6-address:为容器添加一个链路本地IPv6地址。
    
    • 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

    测试,解决3.3 tomcat04 ping tomcat-mynet-02问题

    1、将名为tomcat04的容器连接到名为mynetwork的网络
    
    docker network connect mynetwork tomcat04
    
    2、docker inspect 检查mynetwork的网络详细信息
    
    docker inspect mynetwork
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    在这里插入图片描述

    结论:(一个容器两个IP,如:阿里云服务器:一个公网IP,一个私网IP)

    3、验证:tomcat04 ping tomcat-mynet-02
    
    [root@zyl-server ~]# docker exec -it tomcat04 ping tomcat-mynet-02
    
    • 1
    • 2
    • 3

    在这里插入图片描述

    四、 实战–部署redis集群(3主3从)

    清空docker环境(非测试环境慎用):

     docker stop $(docker ps -aq) 会停止所有正在运行的容器。
    
     docker rm $(docker ps -aq) 会删除所有容器。
    
    • 1
    • 2
    • 3
    [root@zyl-server ~]# docker stop $(docker ps -aq)
    [root@zyl-server ~]# docker rm $(docker ps -aq)
    
    • 1
    • 2

    Redis 集群是一种用于高可用性和扩展性的 Redis 解决方案。基于 Docker 容器化部署 Redis 集群可以简化整个过程,并提供更好的灵活性和可移植性。

    3 主 3 从的 Redis 集群:

    提供高可用性:当一个主节点发生故障时,通过自动故障转移机制,从节点可以自动晋升为新的主节点,从而保证 Redis 集群的可用性。

    提高读写性能:通过路由算法,对键值进行分片存储,使得 Redis 集群能够处理更大的数据集并提高读写性能。

    提供容错性:节点之间的数据复制和同步确保了数据的多重备份,从而增强了 Redis 集群的容错能力。

    方便管理和部署:采用 Docker 容器化部署 Redis 集群,可以更方便地管理和部署 Redis 环境,提高了生产环境中的运维效率。

    部署 Redis 集群可以为企业的业务提供更高的可用性和性能,并增强了应用的容错能力,也可以减少运维的工作量和风险。

    在这里插入图片描述
    Redis 集群搭建步骤:

    1、创建网络:
    [root@zyl-server ~]# docker network create redis-network --subnet 172.19.0.0/16
    e1aea82ce159a3e39aacee7a2c5f97b0673dd6d3062337f0878169d8418b1a77
    [root@zyl-server ~]#
    
    2# 通过脚本创建六个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.19.0.1${port}
    cluster-announce-port 6379
    cluster-announce-bus-port 16379
    appendonly yes
    EOF
    done
    
    3# 启动6个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-network --ip 172.19.0.1${port} redis redis-server /etc/redis/redis.conf
    done
    
    
    • 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

    在这里插入图片描述
    在这里插入图片描述

    4、获取名为 "redis" 的容器的 IP 地址
    [root@zyl-server ~]# docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' redis-1
    172.19.0.11
    [root@zyl-server ~]# docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' redis-2
    172.19.0.12
    [root@zyl-server ~]# docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' redis-3
    172.19.0.13
    [root@zyl-server ~]# docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' redis-4
    172.19.0.14
    [root@zyl-server ~]# docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' redis-5
    172.19.0.15
    [root@zyl-server ~]# docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' redis-6
    172.19.0.16
    [root@zyl-server ~]#
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    在这里插入图片描述

    5# 或者 单个启动
    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.19.0.11 redis redis-server /etc/redis/redis.conf
    
    # 进入redis-1(主节点)
    docker exec -it redis-1 sh
    
    # 创建一个包含主节点和从节点的 Redis 集群
    redis-cli --cluster create 172.19.0.11:6379 172.19.0.12:6379 172.19.0.13:6379 172.19.0.14:6379 172.19.0.15:6379 172.19.0.16:6379 --cluster-replicas 1
    
    
    --cluster-replicas 1 表示每个主节点都会有一个从节点。你可以根据实际需求调整从节点数量。
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    在这里插入图片描述

    6、检查集群状态:
    # 连接redis集群
    redis-cli -c
    
    # 集群信息
    cluster info
    
    # 当前连接节点所属集群的配置信息
    cluster nodes
    
    # 查看集群信息,节点的 IP 地址和端口号
    redis-cli --cluster check ip:port
    
    示例:
    #  redis-cli --cluster check 172.19.0.15:6379
    172.19.0.12:6379 (eeb57961...) -> 0 keys | 5462 slots | 1 slaves.
    172.19.0.11:6379 (f8f1ff36...) -> 0 keys | 5461 slots | 1 slaves.
    172.19.0.13:6379 (63dc2e88...) -> 0 keys | 5461 slots | 1 slaves.
    [OK] 0 keys in 3 masters.
    0.00 keys per slot on average.
    >>> Performing Cluster Check (using node 172.19.0.15:6379)
    S: 30b9739795dbe2b684422d5e26b3af9233abcc09 172.19.0.15:6379
       slots: (0 slots) slave
       replicates f8f1ff368512219bc1175f9437cf66bfc312b162
    S: b83a04599b536842ea1a4be7df2a295ffa2c12a2 172.19.0.16:6379
       slots: (0 slots) slave
       replicates eeb57961e87268137f766f85eb4b314d356e8e20
    S: d508d0102f96efd3c4849efa72c42d57ea097eda 172.19.0.14:6379
       slots: (0 slots) slave
       replicates 63dc2e880044e44994a3384828b3cc9d4651b383
    M: eeb57961e87268137f766f85eb4b314d356e8e20 172.19.0.12:6379
       slots:[5461-10922] (5462 slots) master
       1 additional replica(s)
    M: f8f1ff368512219bc1175f9437cf66bfc312b162 172.19.0.11:6379
       slots:[0-5460] (5461 slots) master
       1 additional replica(s)
    M: 63dc2e880044e44994a3384828b3cc9d4651b383 172.19.0.13:6379
       slots:[10923-16383] (5461 slots) master
       1 additional replica(s)
    [OK] All nodes agree about slots configuration.
    >>> Check for open slots...
    >>> Check slots coverage...
    [OK] All 16384 slots covered.
    #
    
    运行这个命令后,Redis 集群会自动执行状态检查并报告集群中的任何错误或不一致的情况。
    
    如果一切正常,它将显示类似于 "All 16384 slots covered" 的消息,表示所有槽已被正确分配。
    
    • 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
    • 44
    • 45
    • 46
    • 47
    • 48

    在这里插入图片描述

    7、测试:
    
    7.1 插入数据k1 v1
    
    # redis-cli -c
    127.0.0.1:6379> set k1 v1
    -> Redirected to slot [12706] located at 172.19.0.13:6379
    OK
    172.19.0.13:6379>
    
    Redis 返回了一条信息指示该命令已被重定向到槽位 [12706],该槽位位于 IP 地址为 172.19.0.13 的节点上的端口 6379 上。
    
    可以看到当前处理数据的是172.19.0.13(redis-3),接下来停止172.19.0.13(redis-3),172.19.0.14(redis-4)自动替代主节点,----》达到高可用。
    
    7.2  停止172.19.0.13(redis-3[root@zyl-server ~]# docker stop redis-3
    redis-3
    [root@zyl-server ~]#
    
    
    7.3  停止172.19.0.13(redis-3),get  刚才set的 k1 v1,可以看到172.19.0.14(redis-4)自动替代主节点(redis-3),----》达到高可用。
    
    # redis-cli -c
    127.0.0.1:6379> get k1
    -> Redirected to slot [12706] located at 172.19.0.14:6379
    "v1"
    172.19.0.14:6379>
    
    • 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

    在这里插入图片描述

    五、打包发布运行spring-boot微服务项目

    5.1 SpringBoot 项目创建

    在这里插入图片描述
    HelloController.java文件:

    package com.example.demo.controller;
    
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    @RestController
    public class HelloController {
    
    
        @RequestMapping("/hello")
        public String hello(){
    
          return "Hello 醉颜凉!!!!!!!!!!";
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    运行SpringBoot 项目:
    在这里插入图片描述
    打包SpringBoot 项目:
    在这里插入图片描述

    5.2 创建 Dockerfile

    FROM java:8
    
    COPY *.jar /app.jar
    
    LABEL authors="zyl"
    
    CMD ["--server.port=8080"]
    
    EXPOSE 8080
    
    ENTRYPOINT ["java", "-jar","/app.jar"]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
     Dockerfile 中使用了 java 作为基础镜像,并将构建的目录设置为 / 。
    
    然后,将构建产物(在这里是demo1-0.0.1-SNAPSHOT.jarr)复制到镜像中的 / 目录。
    
    最后,暴露容器的 8080 端口,并在容器启动时执行 java -jar 命令来启动 Spring Boot 应用。
    
    • 1
    • 2
    • 3
    • 4
    • 5

    5.3 上传文件

    上传文件jar包与 Dockerfile 文件至 /home/zyl/projects
    
    demo1-0.0.1-SNAPSHOT.jar
    Dockerfile
    
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    在这里插入图片描述

    5.4 构建 Docker 镜像

    进入到 Dockerfile 所在的目录,并运行以下命令来构建 Docker 镜像。

    docker build -t my-spring-boot-app .
    
    • 1

    在这里插入图片描述

    5.5 运行 Docker 容器

    使用以下命令来运行刚才构建的 Docker 镜像:
    docker run -d -P --name zyl-spring-boot-app2 my-spring-boot-app

    [root@zyl-server projects]# docker run -d -p 8080:8080 --name  zyl-spring-boot-app my-spring-boot-app
    e719e38bb18dbb6c1fe88522bd77c0523f2a9045d4f0dbfa89d3269382c11485
    [root@zyl-server projects]#
    
    • 1
    • 2
    • 3

    现在, Spring Boot 微服务项目已经使用 Docker 打包、发布并在容器中运行起来了。可以通过访问 http://localhost:端口来访问运行在 Docker 容器中的应用程序。

    5.6 测试访问

    用docker run指令启动容器返回了容器id,但是用docker ps指令却不显示刚才启动的容器。

    [root@zyl-server projects]# docker ps
    CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES
    [root@zyl-server projects]# docker ps -a
    CONTAINER ID   IMAGE                COMMAND                  CREATED         STATUS                     PORTS     NAMES
    ba6429acfdee   my-spring-boot-app   "java -jar /app.jar …"   4 minutes ago   Exited (1) 4 minutes ago             zyl-spring-boot-app2
    e719e38bb18d   my-spring-boot-app   "java -jar /app.jar …"   7 minutes ago   Exited (1) 7 minutes ago             zyl-spring-boot-app
    [root@zyl-server projects]#
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    解决:

    容器状态是Exited,用docker logs contenterid指令查看容器启动日志。

    
    [root@zyl-server projects]# docker logs -f e719e38bb18d
    Error: A JNI error has occurred, please check your installation and try again
    Exception in thread "main" java.lang.UnsupportedClassVersionError: org/springframework/boot/loader/JarLauncher has been compiled by a more recent version of the Java Runtime (class file version 61.0), this version of the Java Runtime only recognizes class file versions up to 52.0
            at java.lang.ClassLoader.defineClass1(Native Method)
            at java.lang.ClassLoader.defineClass(ClassLoader.java:763)
            at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
            at java.net.URLClassLoader.defineClass(URLClassLoader.java:467)
            at java.net.URLClassLoader.access$100(URLClassLoader.java:73)
            at java.net.URLClassLoader$1.run(URLClassLoader.java:368)
            at java.net.URLClassLoader$1.run(URLClassLoader.java:362)
            at java.security.AccessController.doPrivileged(Native Method)
            at java.net.URLClassLoader.findClass(URLClassLoader.java:361)
            at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
            at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331)
            at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
            at sun.launcher.LauncherHelper.checkAndLoadMain(LauncherHelper.java:495)
    [root@zyl-server projects]#
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    修改Dockerfile文件,重新build:

    官方Docker弃用了Java镜像。

    将java:8替换为openjdk:17,idea打包用的是17。

    FROM openjdk:17
    
    COPY *.jar /app.jar
    
    LABEL authors="zyl"
    
    CMD ["--server.port=8080"]
    
    EXPOSE 8080
    
    ENTRYPOINT ["java", "-jar","/app.jar"]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    在这里插入图片描述

    5.7 再次运行 Docker 容器

    [root@zyl-server projects]# docker run -d -P --name  zyl-spring-boot-app my-spring-boot-app
    2273c7aa7597fc6b5e841a1cbdf985c3b3591da47555460a0b0aa4a51322768a
    [root@zyl-server projects]# docker ps
    CONTAINER ID   IMAGE                COMMAND                  CREATED         STATUS         PORTS                                         NAMES
    2273c7aa7597   my-spring-boot-app   "java -jar /app.jar …"   5 seconds ago   Up 3 seconds   0.0.0.0:32773->8080/tcp, :::32773->8080/tcp   zyl-spring-boot-app
    [root@zyl-server projects]#
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    5.8 再次测试访问

    [root@zyl-server projects]# curl localhost:32773/hello
    Hello 醉颜凉!!!!!!!!!![root@zyl-server projects]#
    
    • 1
    • 2

    在这里插入图片描述


    💖The End💖点点关注,收藏不迷路💖
  • 相关阅读:
    详解JS——垃圾回收的原理
    OpenCV学习笔记
    澳大利亚博士后招聘|皇家墨尔本理工学院材料科学
    基于Socket编程下 实现Linux-Linux、Linux-Windows tcp通信
    微信小程序6 - 自定义组件
    linux下离线安装k8s集群1.19.4附带nfs存储
    【MySql】mysql之索引
    基于LLMs的多模态大模型(Visual ChatGPT,PICa,MM-REACT,MAGIC)
    一张图进阶 RocketMQ - 消息发送
    Sql Server 存储过程
  • 原文地址:https://blog.csdn.net/qq_41840843/article/details/132589714