当前位置:   article > 正文

docker---网络_docker desktop docker build 如何将端口映射

docker desktop docker build 如何将端口映射

docker网络

使用–publish或-p标志使端口可用于 Docker 外部的服务。这会在主机中创建一条防火墙规则,将容器端口映射到 Docker 主机上通往外界的端口。

  • -p 8080:80:将容器中的TCP端口80映射到Docker主机上的端口8080。

  • -p 192.168.1.100:8080:80:将容器中的TCP端口80映射到Docker主机上的端口8080,以便与主机IP地址为192.168.1.100的主机进行连接。

  • -p 8080:80/udp:将容器中的UDP端口80映射到Docker主机上的端口8080。

  • -p 8080:80/tcp -p 8080:80/udp:将容器中的TCP端口80映射到Docker主机上的TCP端口8080,同时将容器中的UDP端口80映射到Docker主机上的UDP端口8080。

当容器创建时,它会被分配一个主机特定网络上的 IP 地址,并可以使用该地址与其他容器或宿主机进行通信。这使得容器之间可以相互联系,共享数据或建立服务之间的通信渠道。

相关命令

  1. 查看容器IP
docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' container_name_or_id
  • 1

桥接网络(Bridge Network)

桥接网络(Bridge Network)是Docker中一种默认的网络模式,它允许多个Docker容器连接到同一个虚拟网络中,并且它们可以通过IP地址直接相互通信。

在桥接网络中,Docker会创建一个虚拟的网络桥接接口(bridge interface),用于连接同一网络中的多个容器。每个容器在连接到桥接网络时,会被分配一个唯一的IP地址,这使得它们可以通过IP地址进行直接的通信。

桥接网络提供了一种隔离和安全的容器通信方式,每个容器都可以具有独立的IP地址,就像在一个本地网络中一样。这样,你可以轻松地将多个容器组合成一个应用程序或服务的不同部分,并实现它们之间的相互通信。

此外,桥接网络还允许容器与Docker主机之间以及宿主机之间进行通信,使得容器内的服务可以通过桥接网络与外部进行交互。

总而言之,桥接网络是一种简单而有效的Docker网络模式,它为容器之间提供了可靠的通信机制,与外部网络进行隔离,并使容器能够方便地与宿主机和其他容器进行通信。

默认情况下,容器在连接到每个Docker网络时都会获得一个IP地址。容器会从网络的IP子网中分配一个IP地址。Docker守护程序会为容器执行动态子网划分和IP地址分配。每个网络还有一个默认的子网掩码和网关。

IP 和 主机名

当你使用docker network connect命令将现有容器连接到不同的网络时,你可以在该命令上使用--ip--ip6标志来指定容器在附加网络上的IP地址

当容器启动时,它只能连接到一个网络,使用--network标志指定。你可以使用docker network connect命令将运行中的容器连接到多个网络。当你使用--network标志启动容器时,你可以使用--ip--ip6标志来指定容器在该网络上的IP地址。

同样地,容器的主机名默认为容器在Docker中的ID。你可以使用--hostname覆盖主机名。当使用docker network connect命令连接到现有网络时,你可以使用--alias标志为容器在该网络上指定额外的网络别名。

DNS

是的,Docker容器在默认情况下会继承主机的DNS设置,并将其配置文件/etc/resolv.conf复制到容器中。这意味着连接到默认的桥接网络的容器会拥有与主机相同的DNS配置。

然而,连接到自定义网络的容器使用的是Docker内置的DNS服务器。这个内置的DNS服务器会将外部DNS查询转发到主机上配置的DNS服务器。

通过使用docker rundocker create命令的相应标志,你可以在每个容器的基础上配置DNS解析。下表列出了与DNS配置相关的可用标志:

标志说明
--dns设置容器使用的自定义DNS服务器。你可以通过指定IP地址或域名来设置DNS服务器。可以在容器启动时指定多个--dns标志来配置多个DNS服务器。
--dns-search设置容器的DNS搜索域。容器在解析没有指定域名的主机时,会尝试将其追加到由--dns-search指定的域名列表中。可以在容器启动时指定多个--dns-search标志来配置多个搜索域。
--dns-option设置容器的DNS选项。你可以通过指定--dns-option标志和选项值来配置DNS选项。可以在容器启动时指定多个--dns-option标志来配置多个DNS选项。
--dns-search-option设置容器的DNS搜索选项。你可以通过指定--dns-search-option标志和选项值来配置DNS搜索选项。可以在容器启动时指定多个--dns-search-option标志来配置多个DNS搜索选项。

通过使用这些标志,你可以为每个容器单独配置DNS解析,以满足你的特定需求。

使用主机的DNS和内置的DNS服务器有以下区别:

  1. DNS解析方式:使用主机的DNS意味着容器的DNS解析将直接使用主机上配置的DNS服务器。容器将通过主机网络访问DNS服务器,并依赖主机的DNS配置来解析域名。而使用内置的DNS服务器意味着容器的DNS解析将通过Docker内部的DNS服务器进行处理,内置的DNS服务器可以对容器进行更灵活的管理和控制。

  2. 网络隔离性:使用主机的DNS时,容器将直接使用主机的网络资源进行DNS查询。这意味着容器的网络流量可能会通过主机网络进行传输,使容器与主机之间的网络关系更加耦合。而使用内置的DNS服务器时,容器的网络流量将在Docker网络层级中进行处理,与主机的网络相对隔离,更加独立。

  3. DNS配置管理:使用主机的DNS需要在主机上进行DNS配置,包括配置DNS服务器和域名搜索路径等。这使得主机上的DNS配置对所有使用该主机的容器生效,容器无法独立配置DNS解析。而使用内置的DNS服务器,容器可以独立配置和管理DNS解析,通过Docker命令和标志来设置容器的DNS选项,更加灵活和可定制。

总之,使用主机的DNS和内置的DNS服务器主要区别在于DNS解析方式、网络隔离性和DNS配置管理。选择使用哪种方式取决于你的需求和对网络隔离性和配置管理的要求。

ipv6 地址

在主机系统的/etc/resolv.conf文件中如果包含一个或多个具有IPv6地址的nameserver条目时,这些nameserver条目会被复制到你运行的容器的/etc/resolv.conf文件中。

然而,对于使用musl libc的容器(例如Alpine Linux),这可能会导致主机名查找出现竞争条件。这意味着如果外部IPv6 DNS服务器在竞争条件中击败了内置的DNS服务器,主机名解析可能会时而失败。

通常情况下,外部DNS服务器很少比内置的DNS服务器更快。但是,例如垃圾回收或大量并发的DNS请求等情况下,有时候与外部服务器的往返时间比本地解析更快。

这段文字旨在解释在特定情况下,如果主机的/etc/resolv.conf文件包含IPv6地址的nameserver条目,可能会导致容器中的主机名解析失败。这是由于竞争条件导致的,并且在实际应用中发生的可能性较低。

musl libc是一个轻量级的C标准库,被设计用作Linux系统的替代品。与其他常见的C标准库(如glibc)相比,musl libc具有更小的内存占用和二进制大小,同时提供良好的兼容性和可移植性。

在Docker环境中,可以使用基于musl libc构建的特定Linux发行版,如Alpine Linux,作为容器的基础映像。因此,所谓的"musl libc的容器"指的是使用Alpine Linux或其他使用musl libc作为C标准库的发行版作为基础映像构建的容器。

Alpine Linux是一个轻量级的Linux发行版,非常适合用于构建容器化应用。它的核心是musl libc和BusyBox,内存占用和存储空间需求都非常小。使用Alpine作为容器基础映像可以减小容器的大小,并且运行与glibc基础映像相比通常更加高效。

因此,当讨论"musl libc的容器"时,通常指的是基于Alpine Linux或其他使用musl
libc作为C标准库的发行版构建的容器。

自定义的主机

默认情况下,主机上/etc/hosts文件中定义的自定义主机不会被容器继承。每个容器都有自己独立的网络命名空间,其中包括自己的/etc/hosts文件。

如果你想将额外的主机添加到容器中,可以在创建容器时修改容器的/etc/hosts文件。这可以通过在运行docker run命令时使用--add-host标志来实现。--add-host标志允许你在容器的/etc/hosts文件中指定额外的条目。

例如:

docker run --add-host myhost:192.168.1.100 mycontainer
  • 1

以上命令将在运行mycontainer容器时,在容器的/etc/hosts文件中添加了一条记录,将myhost映射到192.168.1.100的IP地址。

这样,容器内的应用程序就能够解析并访问myhost这个自定义主机。

网络驱动

Docker的网络子系统是可插拔的,使用驱动程序来实现。默认情况下,Docker提供了几种核心网络功能的驱动程序:

  • bridge:默认的网络驱动程序。如果没有指定驱动程序,创建的网络类型就是桥接网络。桥接网络通常在容器中运行的应用程序需要与同一主机上的其他容器通信时使用。详见桥接网络驱动程序。

  • host:移除容器与Docker主机之间的网络隔离,直接使用主机的网络。详见主机网络驱动程序。

  • overlay:覆盖网络连接多个Docker守护程序,使Swarm服务和容器能够在节点之间进行通信。这种策略消除了操作系统级别的路由需求。详见覆盖网络驱动程序。

  • ipvlan:IPvlan网络使用户完全控制IPv4和IPv6寻址。VLAN驱动程序在此基础上进行构建,为感兴趣的用户提供了完全控制第2层VLAN标记甚至IPvlan L3路由的支持,以实现基础网络集成。详见IPvlan网络驱动程序。

  • macvlan:Macvlan网络允许将MAC地址分配给容器,使其在网络上表现为物理设备。Docker守护进程根据容器的MAC地址路由流量。在处理期望直接连接到物理网络而不是通过Docker主机网络栈路由的传统应用程序时,使用macvlan驱动程序有时是最好的选择。详见Macvlan网络驱动程序。

  • none:完全隔离容器与主机及其他容器。none不适用于Swarm服务。详见None网络驱动程序。

  • 网络插件:你可以安装和使用第三方网络插件来扩展Docker的网络功能。

这些驱动程序提供了不同的网络配置和功能,使得Docker在不同的使用场景下能够更灵活地进行网络设置和管理。

网络驱动程序总结:

  • 默认的桥接网络适用于不需要特殊网络功能的容器。
  • 用户定义的桥接网络允许同一Docker主机上的容器相互通信。用户定义的网络通常为属于同一项目或组件的多个容器定义了一个隔离的网络。
  • 主机网络与容器共享主机的网络。使用此驱动程序时,容器的网络与主机不隔离。
  • 覆盖网络在需要运行在不同Docker主机上的容器相互通信或多个应用程序使用Swarm服务协同工作时最为适用。
  • Macvlan网络适用于从虚拟机设置迁移或需要使容器看起来像物理主机,在网络中具有唯一MAC地址。
  • IPvlan类似于Macvlan,但不会为容器分配唯一的MAC地址。当对网络接口或端口分配的MAC地址数量有限制时,考虑使用IPvlan。
  • 第三方网络插件允许你将Docker与专用网络堆栈集成。

桥接网络驱动程序

就网络而言,桥接网络是一种在网段之间转发流量的链路层设备桥接器可以是硬件设备,也可以是在主机内核中运行的软件设备

就 Docker 而言,桥接网络使用软件桥接,允许连接到同一桥接网络的容器进行通信,同时提供与未连接到该桥接网络的容器的隔离。Docker 桥接驱动程序会自动在主机中安装规则,以便不同桥接网络上的容器无法直接相互通信。

桥接网络适用于在同一Docker 守护进程主机上运行的容器。对于在不同 Docker 守护进程主机上运行的容器之间的通信,您可以在操作系统级别管理路由,也可以使用 覆盖网络。

当您启动 Docker 时,会自动创建一个默认桥接网络(也称为),并且新启动的容器会连接到该网络,除非另有说明。bridge您还可以创建用户定义的自定义桥接网络。用户定义的桥接网络优于默认bridge 网络。

用户自定义网络桥接和默认桥接网络的区别,以下是两个场景的示例:

使用默认桥接网络:

在这个例子中,假设你有一个包含后端服务和数据库服务。使用默认的桥接网络,你需要手动创建连接并使用 IP 地址或者容器名进行通信。

使用容器名通信
  1. 先使用docker运行一个postgres的服务
docker run --name my-postgres-bridge-test -e POSTGRES_PASSWORD=123456 -d postgres
  • 1
  1. 准备后端服务
package main

import (
	"fmt"

	"gorm.io/driver/postgres"
	"gorm.io/gorm"
)

func main() {
	initDB()
	select {}
}

func initDB() {
	var err error
	// 成功连接
	dsn := "host=my-postgres-bridge-test user=postgres password=123456 dbname=data_test port=5432 sslmode=prefer TimeZone=Asia/Shanghai"
	_, err = gorm.Open(postgres.Open(dsn))
	// DB.LogMode(true)
	if err != nil {
		panic(err)
	} else {
		fmt.Println("数据库连接成功")
	}
}
  • 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

dokcerfile 【这个dockerfile下面打包都是用这个】

FROM golang:1.20 AS builder

WORKDIR /app
ADD ./ ./



ENV GO111MODULE=on
ENV GOPROXY=https://goproxy.cn,direct
ENV CGO_ENABLED=0
RUN go build -o main


FROM alpine:3.12

WORKDIR /app
COPY --from=builder /app/main ./
EXPOSE 8080

ENTRYPOINT ./main
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  1. 打包程序
docker run --name link-postgres-server -d link-postgres-server:0.1
  • 1
  1. 运行容器
docker run --name link-postgres-server --link my-postgres-bridge-test -d link-postgres-server:0.1
  • 1

在这里插入图片描述

结论:以程序里host的配置方式(使用的是数据库容器的名字),如果不使用 --link去运行该服务就无法连接到数据库

使用IP通信
  1. 先使用docker运行一个postgres的服务
docker run --name my-postgres-bridge-test -e POSTGRES_PASSWORD=123456 -d postgres
  • 1
  1. 打包一个golang服务,连接该数据库
package main

import (
	"fmt"

	"gorm.io/driver/postgres"
	"gorm.io/gorm"
)

func main() {
	initDB()
	select {}
}

func initDB() {
	var err error

	dsn := "host=172.17.0.3 user= postgres password=123456 dbname=data_test port=5432 sslmode=prefer TimeZone=Asia/Shanghai"
	//这里的host使用的是my-postgres-bridge-test容器【运行postgres数据的容器】的Ip
	_, err = gorm.Open(postgres.Open(dsn))
	if err != nil {
		panic(err)
	} else {
		fmt.Println("数据库连接成功")
	}
}
  • 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
  1. 运行容器
docker run --name link-postgres-server link-test-server:0.1
  • 1

在这里插入图片描述
结论:使用IP通信就可以不用--link

使用用户自定义网络桥接:

在这个例子中,我们将使用用户自定义网络桥接,容器可以通过名称或别名进行解析。

  1. 首先,创建一个自定义网络:
docker network create postgres-net
  • 1
  1. 然后,启动数据库容器并将其连接到自定义网络:
docker run --name my-defined-postgres-bridge-test --network postgres-net -e POSTGRES_PASSWORD=123456 -d postgres
  • 1
  1. 后端服务
package main

import (
	"fmt"

	"gorm.io/driver/postgres"
	"gorm.io/gorm"
)

func main() {
	initDB()
	select {}
}

func initDB() {
	var err error
	dsn := "host=my-defined-postgres-bridge-test user=postgres password=123456 dbname=data_test port=5432 sslmode=prefer TimeZone=Asia/Shanghai"
	_, err = gorm.Open(postgres.Open(dsn))
	// DB.LogMode(true)
	if err != nil {
		panic(err)
	} else {
		fmt.Println("数据库连接成功")
	}
}

  • 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
  1. 打包镜像
docker build -t link-postgres-server:0.1 .
  • 1
  1. 接下来,启动后端容器并将其连接到相同的自定义网络:
docker run --name link-postgres-server --network=postgres-net -d link-postgres-server:0.1
  • 1

在这里插入图片描述

在这种情况下,你可以在后端容器中使用数据库容器的名称(my-defined-postgres-bridge-test)作为主机名或别名来进行数据库连接,而不需要使用 IP 地址。

通过使用用户自定义网络桥接,容器可以方便地通过名称进行通信,而无需手动创建连接或修改/etc/hosts文件。

请注意,这只是简化的示例,实际情况可能需要根据具体的应用程序和需求进行适当的修改。

使用用户自定义的网络(user-defined network)可以提供更好的隔离性。

默认情况下,所有没有指定–network参数的容器都会被附加到默认的桥接网络(default bridge network)。这可能存在风险,因为不相关的堆栈/服务/容器可以相互通信。

而使用用户自定义网络,则创建了一个封闭的网络环境,只有附加到该网络的容器之间才能相互通信。这样可以更好地隔离不同容器之间的通信,提高安全性。

随时将容器连接或断开连接到用户自定义网络上

在容器的生命周期中,可以随时将其连接或断开连接到用户自定义网络上。要将容器从默认的桥接网络中移除,需要停止容器并使用不同的网络选项重新创建它。这意味着可以根据需要灵活地调整容器与用户自定义网络的连接状态。

要随时连接和断开容器与用户自定义网络,可以使用Docker命令行界面或Docker API等工具进行操作。以下是使用Docker命令行界面示例:

  1. 连接容器到用户自定义网络:

    docker network connect <network_name> <container_name>
    
    • 1

    其中,<network_name>是要连接的用户自定义网络的名称,<container_name>是要连接的容器的名称或容器ID。

  2. 断开容器与用户自定义网络的连接:

    docker network disconnect <network_name> <container_name>
    
    • 1

    其中,<network_name>是要断开连接的用户自定义网络的名称,<container_name>是要断开连接的容器的名称或容器ID。

通过这些命令,你可以随时将容器连接到或断开连接从用户自定义网络,无需停止容器,并且可以根据需要自由调整容器的网络关联。请确保在执行这些命令时使用正确的网络名称和容器名称或ID。

实例

  1. 启动数据库容器
docker run --name my-defined-postgres-bridge-test -e POSTGRES_PASSWORD=123456 -d postgres
  • 1
  1. 编写程序
package main

import (
	"fmt"
	"time"

	"gorm.io/driver/postgres"
	"gorm.io/gorm"
)

func main() {
	initDB()
	select {}
}

func initDB() {
	var err error
	dsn := "host=my-defined-postgres-bridge-test user=postgres password=123456 dbname=data_test port=5432 sslmode=prefer TimeZone=Asia/Shanghai"
	for {
		_, err = gorm.Open(postgres.Open(dsn))
		// DB.LogMode(true)
		if err != nil {
			fmt.Println(err)
		} else {
			break
		}
		time.Sleep(5 * time.Second)
	}

	fmt.Println("数据库连接成功")
}
  • 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
  1. 打包程序
docker run --name link-postgres-server  -d docker-link-test:0.1
  • 1

在这里插入图片描述
容器运行之后会先持续打印图片中标识的1和2,也就是连接不上数据库的容器;因为这个时候postgres和golang后端程序都使用的默认的桥接网络,使用默认的桥接网络以现在的代码和运行方式它们两个容器是无法通信的。这个可以看前面的实例。
之后图片的第3,4步就是给posgres和golang程序连接到我自己定义的网络上,在执行完第4步之后,就可以看见日志,也就是第5步,数据库连接成功。

共享环境变量和服务访问

共享环境变量

在默认的桥接网络上,连接的容器共享环境变量。

最初,共享环境变量的唯一方式是使用–link标志将容器链接在一起。这种类型的变量共享对于用户定义的网络是不可能的。然而,有更好的方法来共享环境变量。以下是一些想法:

  1. 多个容器可以挂载一个包含共享信息的文件或目录,使用Docker卷进行共享。
  2. 多个容器可以使用docker-compose一起启动,并且compose文件可以定义共享的变量。
  3. 你可以使用Swarm服务而不是独立容器,并利用共享的Secrets和Configs。

连接到同一个用户定义的桥接网络的容器之间可以相互访问所有端口。要使端口在容器之间可访问,容器必须在相应的端口上监听并运行服务。

服务访问

可以通过将容器映射到主机上的特定端口,从而使容器的服务可以通过主机的IP和端口进行访问。例如,可以使用-p--publish标志来指定要将容器的端口映射到主机的哪个端口。

使用IPv6

如果您需要为Docker容器启用IPv6支持,在创建任何IPv6网络或为容器分配IPv6地址之前,您需要在Docker守护进程上启用该选项并重新加载它的配置。

在创建网络时,您可以使用 --ipv6 标志启用IPv6。在默认的桥接网络上,您无法选择性地禁用IPv6支持。

要启用Docker守护进程的IPv6支持,请按照以下步骤操作:

  1. 编辑 Docker 配置文件(通常是 /etc/docker/daemon.json),添加以下内容:
{
  "ipv6": true,
  "fixed-cidr-v6": "2001:db8:1::/64"
}
  • 1
  • 2
  • 3
  • 4

这将启用IPv6支持,并指定IPv6地址块。

  1. 保存配置文件,并重新加载 Docker 守护进程的配置。

  2. 创建IPv6网络时,使用 --ipv6 标志:

docker network create --ipv6 --subnet=2001:db8:1::/80 my-net
  • 1

默认桥接网络是在安装Docker时创建的,用于在主机上运行的容器相互通信。然而,它具有一些限制和不足之处:

  1. 单播通信:默认桥接网络仅支持容器之间的单播通信,容器无法直接通过桥接网络进行多播或广播通信。

  2. 容器间隔离性有限:默认桥接网络上的所有容器都处于相同的子网中,容器可以直接通过IP地址进行通信,这可能会导致安全和隔离问题。

  3. 缺乏自动化管理和动态扩展:默认桥接网络的管理是一个手动操作,您需要手动为容器分配IP地址。此外,默认桥接网络缺乏动态扩展功能,无法适应大规模容器部署。

建议在生产环境中使用Docker的用户自定义网络。用户自定义网络允许更灵活地配置网络属性,并提供更好的容器隔离和可扩展性。

配置默认桥接网络

要配置默认桥接网络,您可以在 daemon.json 文件中指定选项。以下是一个示例 daemon.json 文件,其中指定了几个选项。请只指定您需要自定义的设置。

{
  "bip": "192.168.1.5/24",
  "fixed-cidr": "192.168.1.0/25",
  "fixed-cidr-v6": "2001:db8::/64",
  "mtu": 1400,
  "default-gateway": "",
  "default-gateway-v6": ""
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

在上述示例中,您可以根据需要指定以下选项:

  • "bip":指定默认桥接网络的IPv4地址块。默认值为 172.17.0.1/16
  • "fixed-cidr":指定默认桥接网络的IPv4子网。如果指定了 "bip",则默认为与之相匹配的值。
  • "fixed-cidr-v6":指定默认桥接网络的IPv6地址块。
  • "mtu":指定默认桥接网络的最大传输单元(MTU)。默认值为 1500
  • "default-gateway":指定默认桥接网络的IPv4默认网关。
  • "default-gateway-v6":指定默认桥接网络的IPv6默认网关。

只需要指定您想要自定义的选项,其他选项可以留空或省略。

配置完成后,请重新加载 Docker 守护进程的配置以使更改生效。

关于桥接网络的连接限制

根据Linux内核的限制,当1000个或更多容器连接到单个网络时,桥接网络会变得不稳定,容器之间的通信可能会中断

覆盖网络驱动

什么是主机特定网络

主机特定网络是指 Docker 守护程序主机上的默认网络环境。在默认情况下,每个 Docker 守护程序主机都有一个名为 bridge 的主机特定网络,用于连接容器和宿主机的通信。

通过主机特定网络,容器可以使用主机的网络和资源,并与同一主机上的其他容器进行通信。

主机特定网络通常在单个宿主机内部有效。也就是说,容器只能通过主机特定网络与同一宿主机上的其他容器进行通信。

覆盖网络(overlay network)驱动程序

覆盖网络驱动程序允许在多个 Docker 守护程序主机之间创建一个分布式网络。这个网络是基于主机特定网络之上的一种虚拟网络,称为覆盖网络。覆盖网络的作用是提供一种机制,使得连接到该网络的容器可以在不同的 Docker 守护程序主机之间进行安全通信。

启用加密时【启用加密是指在覆盖网络中对通信数据进行加密,以提高数据传输的安全性和隐私保护】,连接到该网络的容器(包括Swarm服务容器)可以安全地进行通信。Docker会透明地处理每个数据包的路由,从正确的Docker守护程序主机发送到正确的目标容器。

当您初始化一个Swarm或将Docker主机加入到现有的Swarm中时,会在该Docker主机上创建两个新网络:

  • 一个名为 ingress 的覆盖网络,用于处理与Swarm服务相关的控制和数据流量。当您创建一个Swarm服务并且未连接到用户定义的覆盖网络时,默认情况下它会连接到 ingress 网络。
  • 一个名为 docker_gwbridge 的桥接网络,用于将单个Docker守护程序连接到参与Swarm的其他守护程序。

您可以使用 docker network create 命令创建用户定义的覆盖网络,就像创建用户定义的桥接网络一样。服务或容器可以同时连接到多个网络。服务或容器只能在它们各自连接的网络之间进行通信。

尽管您可以将Swarm服务和独立容器都连接到覆盖网络,但默认行为和配置关注点是不同的。出于这个原因,本主题的其余部分被分为适用于所有覆盖网络的操作,适用于Swarm服务网络的操作,以及适用于独立容器使用的覆盖网络的操作。

通常情况下,每个 Docker 守护程序主机都有自己的网络,容器只能与同一主机上的其他容器进行通信。但是,使用覆盖网络时,容器可以通过虚拟网络连接到不同的守护程序主机上的容器,实现跨主机的通信。

覆盖网络在容器部署和容器编排中非常有用,特别是在使用 Docker Swarm 进行容器编排时。它允许轻松地将容器部署到不同的宿主机上,并使它们能够无缝地进行通信。覆盖网络还提供了安全通信的特性,如加密和身份验证。

总之,覆盖网络驱动程序创建了一个位于主机特定网络之上的虚拟网络,使得容器可以在多个 Docker 守护程序主机之间进行分布式通信。

创建覆盖网络

要创建一个覆盖网络,您需要满足以下先决条件:
  1. Docker守护程序使用覆盖网络的防火墙规则

为了使参与覆盖网络的每个Docker主机之间的流量正常通信,您需要打开以下端口:

  • TCP端口2377用于群集管理通信
  • TCP和UDP端口7946用于节点之间的通信
  • UDP端口4789用于覆盖网络流量

在创建覆盖网络之前,您需要将Docker守护程序初始化为Swarm管理器,使用命令 docker swarm init,或加入到现有的Swarm中,使用命令 docker swarm join。这两种方式都会创建名为 ingress 的默认覆盖网络,该网络默认用于Swarm服务。即使您不打算使用Swarm服务,也需要进行这些操作。之后,您可以创建额外的用户定义的覆盖网络。

  1. 要创建用户定义的覆盖网络
    例如,要创建一个名为 my-overlay-network 的覆盖网络,可以运行以下命令:
docker network create -d overlay my-overlay-network
  • 1
  1. 要创建一个可以被Swarm服务或独立容器使用的覆盖网络,用于与其他在不同Docker守护程序上运行的独立容器进行通信,可以添加 --attachable 参数:
docker network create -d overlay --attachable my-attachable-overlay
  • 1

通过添加 --attachable 参数,您可以创建一个可附加的覆盖网络,使它可以被独立容器连接和使用。这意味着独立容器可以加入到这个覆盖网络,并与其他容器进行通信,而不仅限于Swarm服务。

这一功能特别适用于在容器化环境中需要进行跨主机通信的应用程序。通过将独立容器连接到可附加的覆盖网络,您可以轻松地实现容器之间的安全通信和交互。

上面两者的区别

docker network create -d overlay my-overlay-networkdocker network create -d overlay --attachable my-attachable-overlay 创建的网络有以下区别:

  1. 连接方式:

    • my-overlay-network 是一个普通的覆盖网络,它主要用于Swarm服务之间的通信。独立容器可以加入到该网络中,但无法直接通过网络连接到其他独立容器。
    • my-attachable-overlay 是一个可附加的覆盖网络,可以被独立容器连接和使用。这意味着独立容器可以加入到这个网络,并与其他容器进行通信,而不仅限于Swarm服务。
  2. 用途:

    • my-overlay-network 适用于Swarm服务。它是Swarm的默认覆盖网络,用于连接Swarm服务,并在Swarm集群中进行内部通信。
    • my-attachable-overlay 适用于独立容器和Swarm服务。它可以用于独立容器之间以及独立容器与Swarm服务之间的通信。独立容器可以连接到该网络,并与其他独立容器或Swarm服务进行通信。

结论:可以根据您的具体需求选择适合您应用程序的网络类型。如果您只需要Swarm服务之间的通信,可以使用普通的覆盖网络。如果您需要独立容器之间或独立容器与Swarm服务之间的通信,可以选择可附加的覆盖网络。

在覆盖网络上加密流量

要在覆盖网络上加密流量,您可以采取以下步骤:

  1. 默认情况下,Swarm服务管理流量是使用AES算法在GCM模式下进行加密的。Swarm中的管理节点每12小时轮换用于加密Gossip数据的密钥,从而确保通信的安全性。

  2. 要对应用程序数据进行加密,创建覆盖网络时需要添加 --opt encrypted 参数。这将在VXLAN层级启用IPSEC加密。需要注意的是,此加密会导致一定的性能损失,因此在生产环境之前,请务必进行测试。

  3. 当您启用覆盖网络加密时,Docker会在连接到覆盖网络的所有节点之间创建IPSEC隧道。这些隧道也使用AES算法在GCM模式下进行加密,并且管理节点会自动每12小时旋转密钥。

通过上述步骤,可以确保通过覆盖网络传输的数据在传输过程中得到加密保护,增加通信的安全性

需要注意的是,在启用覆盖网络加密时,可能会引入一定的性能损耗。因此,在使用之前,请务必进行适当的测试和评估,以确保在生产环境中的性能可以满足要求。

在Windows上不支持将节点连接到加密的覆盖网络

具体地说,覆盖网络加密在Windows上不受支持。如果一个Windows节点尝试连接到一个加密的覆盖网络,不会检测到任何错误,但节点无法进行通信。

如果您确实需要在Windows节点上实现加密通信,可能需要考虑其他加密方法,例如使用TLS/SSL进行容器之间的安全通信。可以借助工具和库实现容器级的加密和认证。

同时在Swarm模式下使用覆盖网络功能,创建一个加密且可附加的多主机网络

还可以将非受管的独立容器连接到该网络中。

以下是创建一个加密且可附加的多主机网络的命令示例:

docker network create --opt encrypted --driver overlay --attachable my-attachable-multi-host-network
  • 1

这将创建一个名为 my-attachable-multi-host-network 的加密且可附加的覆盖网络。您可以通过 --attachable 参数将独立容器连接到该网络,并实现容器之间的通信。

结论:通过使用加密覆盖网络,Swarm服务和独立容器都可以实现安全的跨主机通信,保护数据的机密性。

自定义的ingress网络

应用场景

自动选择的子网与您网络中已经存在的子网冲突,或者您需要自定义其他底层网络设置,比如MTU

过程

自定义ingress网络的过程涉及删除和重新创建它。通常在创建Swarm中的任何服务之前会进行这个操作。如果您有已经发布端口的现有服务,您需要在删除ingress网络之前将这些服务删除

在ingress网络不存在的时候,未发布端口的现有服务将继续运行,但不会进行负载均衡。这会影响发布端口的服务,例如发布了80端口的WordPress服务。

简而言之,自定义默认的ingress网络需要执行以下步骤:

  1. 删除现有的ingress网络:使用以下命令删除ingress网络:

    docker network rm ingress
    
    • 1

    删除入口网络会导致已发布端口的服务无法正常工作,但未发布端口的服务将继续运行。

  2. 自定义ingress网络设置:根据您的需求创建新的自定义ingress网络。您可以使用 docker network create 命令自定义网络设置。例如:

    docker network create --driver overlay --subnet 10.0.9.0/24 --ingress my-custom-ingress
    
    • 1

    以上命令创建一个名为 my-custom-ingress 的自定义ingress网络,指定了自定义的子网地址。

  3. 创建新的Swarm服务:在重新创建ingress网络之后,您可以创建新的Swarm服务,并按需发布端口。

需要注意的是,自定义ingress网络会影响现有的服务,因此在执行前,请务必确保您知道自己在做什么,并且已经备份了必要的数据。

如何自定义默认的ingress网络具体步骤

以下是每个步骤的概述:

  1. 使用 docker network inspect ingress 命令检查ingress网络,并移除所有连接到该网络的服务。这些服务是发布了端口的服务,比如发布了80端口的WordPress服务。确保停止所有相关的服务,否则接下来的步骤将失败。

  2. 移除现有的ingress网络:

    docker network rm ingress
    
    • 1

    注意:在尝试移除ingress网络之前,请确保已停止并移除所有连接到该网络的服务。

  3. 使用 --ingress 标志和其他自定义选项创建新的覆盖网络。以下是一个示例命令,其中设置了MTU为1200,子网为10.11.0.0/16,网关为10.11.0.2。

    docker network create --driver overlay    --ingress    --subnet=10.11.0.0/16    --gateway=10.11.0.2     --opt com.docker.network.driver.mtu=1200    my-ingress
    
    • 1

    在这个示例中,新的ingress网络命名为 my-ingress,并设置了自定义选项,包括设置MTU、子网和网关。

    注意:您可以为自己的ingress网络选择一个不同的名称,但只能创建一个ingress网络。再次尝试创建第二个ingress网络将失败。

  4. 重新启动在第一步中停止的服务。

根据需求可以进行相应的修改和适应。

如何自定义docker_gwbridge接口

这些步骤是为了自定义 docker_gwbridge 接口的设置。
以下是每个步骤的概述:

  1. 停止 Docker。

  2. 删除现有的 docker_gwbridge 接口:

    sudo ip link set docker_gwbridge down
    sudo ip link del dev docker_gwbridge
    
    • 1
    • 2
  3. 启动 Docker。不要加入或初始化集群(swarm)。

  4. 手动创建或重新创建 docker_gwbridge 网桥,并使用自定义设置,使用 docker network create 命令。以下示例使用子网 10.11.0.0/16。有关可自定义选项的完整列表,请参见Bridge driver options。

    docker network create \
    --subnet 10.11.0.0/16 \
    --opt com.docker.network.bridge.name=docker_gwbridge \
    --opt com.docker.network.bridge.enable_icc=false \
    --opt com.docker.network.bridge.enable_ip_masquerade=true \
    docker_gwbridge
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
  5. 初始化或加入集群(swarm)。由于该网桥已经存在,Docker 不会使用自动设置重新创建它。

swarm服务的配置

公开覆盖网络(overlay network)上的端口

连接到同一个覆盖网络的Swarm服务会相互之间暴露所有端口。
要使端口在服务外可访问,必须在docker service createdocker service update命令中使用-p--publish标志进行发布。
支持使用传统的冒号分隔语法或新的逗号分隔值语法。较长的语法是首选,因为它在某种程度上是自说明的。

以下是标志值的描述:

  • -p 8080:80-p published=8080,target=80:将服务上的TCP端口80映射到路由网格上的端口8080。
  • -p 8080:80/udp-p published=8080,target=80,protocol=udp:将服务上的UDP端口80映射到路由网格上的端口8080。
  • -p 8080:80/tcp -p 8080:80/udp-p published=8080,target=80,protocol=tcp -p published=8080,target=80,protocol=udp:将服务上的TCP端口80映射到路由网格上的TCP端口8080,并将服务上的UDP端口80映射到路由网格上的UDP端口8080。

这些参数的含义是将服务的指定端口映射到路由网格上的指定端口,以便在服务外部可以访问该端口。

Routing mesh(路由网格)

Routing mesh(路由网格)是Docker Swarm中的一个功能,用于在一个Swarm集群中自动路由流量。它允许您将流量发送到集群中所有正在运行特定服务的节点上,而无需显式指定特定节点当您连接到集群中的一个节点上的某个服务的端口时,routing mesh会自动将您的请求路由到正在运行该服务的节点上

Routing mesh使用虚拟IP(VIP)模式,这意味着您可以通过在Swarm集群中的任何节点上连接到服务的VIP来访问服务。它隐藏了底层的节点细节和负载均衡机制,使得服务更易于访问和扩展。

通过使用routing mesh,您可以轻松地扩展和管理Swarm集群中的服务,而无需手动配置和管理负载均衡器。它提供了一个抽象层,使得在整个集群中分布式部署和访问服务变得更加简单和透明。

绕过routing mesh

默认情况下,Swarm服务使用routing mesh来发布端口。当您连接到任何一个Swarm节点上的一个发布的端口时(不管它是否正在运行给定的服务),您将被重定向到运行该服务的工作节点,这是透明的。实际上,Docker充当了您的Swarm服务的负载均衡器。使用routing mesh的服务以虚拟IP(VIP)模式运行。即使一个服务在每个节点上运行(通过–mode global标志),也会使用routing mesh。使用routing mesh时,不能保证Docker节点服务客户端请求的顺序。

要绕过routing mesh,您可以使用DNS Round Robin(DNSRR)模式启动一个服务,即将–endpoint-mode标志设置为dnsrr。您必须在服务前面运行自己的负载均衡器。在Docker主机上对服务名称进行DNS查询将返回运行该服务的节点的IP地址列表。配置负载均衡器以使用此列表并在节点之间平衡流量。

使用DNS Round Robin(DNSRR)模式启动服务并配置自己的负载均衡器是一种绕过 routing mesh 的方法,而不是绕过 Swarm 服务本身。

在某些情况下,您可能需要绕过 routing mesh。例如,如果您想要自定义负载均衡策略或与现有负载均衡设备集成,您可以选择使用 DNSRR 模式并运行自己的负载均衡器。这样,您可以直接管理流量路由,并根据需要进行定制。

将控制流量和数据流量分离

默认情况下,与Swarm管理有关的控制流量和与应用程序之间的流量在同一网络上运行,尽管Swarm控制流量是加密的。您可以配置Docker使用不同的网络接口来处理这两种不同类型的流量。当您初始化或加入Swarm时,需要分别指定–advertise-addr和–datapath-addr。您必须为加入Swarm的每个节点都这样做。

--advertise-addr参数用于指定节点的Swarm管理流量地址。这是用于集群中节点之间通信的地址,并用于选举Swarm管理角色。

--datapath-addr参数用于指定节点的应用程序数据流量地址。这是应用程序和服务之间传输数据的地址。

通过使用不同的地址,您可以将控制流量和数据流量分开,这样可以更好地控制和管理它们。这种配置可以使您更好地保护Swarm管理流量的安全性,并优化应用程序的性能,使其能够以更高的速度和效率处理数据流量。

容器发现

在大多数情况下,您应该连接到服务名称,该名称将由支持服务的所有容器(“任务”)进行负载平衡和处理。要获取支持服务的所有任务的列表,请进行任务名称解析(DNS lookup for tasks.<service-name>)。

连接限制的overlay网络

由于Linux内核的限制,当1000个容器位于同一主机上时,overlay网络会变得不稳定,并且容器之间的通信可能会中断。

主机网络模式(Host network driver)

使用主机网络模式时,容器的网络堆栈与Docker主机不隔离(容器共享主机的网络命名空间),并且容器不会分配独立的IP地址。例如,如果您运行一个绑定到端口80的容器,并且使用主机网络模式,那么容器的应用程序将在主机的IP地址上的端口80上可用。

简而言之,使用主机网络模式将使容器绕过Docker主机的网络隔离,并与主机共享相同的网络接口和IP地址。这意味着容器的应用程序可以直接通过主机的IP地址和指定端口进行访问

需要注意的是,使用主机网络模式可以提高网络性能,但也破坏了容器的隔离性,因为容器与主机共享相同的网络命名空间。因此,在使用主机网络模式时,请确保该容器所提供的服务不会与主机上的其他服务发生冲突,并且容器的网络安全性得到充分考虑。

在使用主机模式网络时,容器没有自己的IP地址,因此端口映射无效,-p, --publish, -P 和 --publish-all 选项会被忽略,并产生一个警告信息。

使用主机模式网络可以优化性能,特别是在容器需要处理大量端口的情况下。因为在主机模式下,不需要进行网络地址转换(NAT),也不会为每个端口创建“userland-proxy”。

主机网络驱动程序仅适用于Linux主机,不支持在Docker Desktop for Mac,Docker Desktop for Windows或Docker EE for Windows Server上使用。

您还可以通过在docker service create命令中传递--network host来将主机网络用于Swarm服务。在这种情况下,控制流量(与管理Swarm和服务相关的流量)仍会通过overlay网络发送,但各个Swarm服务容器使用Docker守护程序的主机网络和端口发送数据。这会产生一些额外的限制。例如,如果一个服务容器绑定到端口80,那么在给定的Swarm节点上只能运行一个服务容器。

简而言之,使用主机模式网络可以提高性能,并且适用于需要处理大量端口的容器。但需要注意主机模式的使用限制,并确保在使用容器时避免端口冲突和网络安全问题。

官方文档

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/从前慢现在也慢/article/detail/87724
推荐阅读
相关标签
  

闽ICP备14008679号