Docker 服务发现与网络解决方案全解析
在容器化技术的应用中,服务发现和网络连接是至关重要的环节。本文将详细介绍多种服务发现解决方案,以及 Docker 网络的不同模式、新型网络特性和一些常见的跨主机网络解决方案。
1. 服务发现解决方案
除了基本的 TTL 检查外,更复杂深入的检查通常需要额外的服务。客户端可以自由实现逻辑,根据 API 版本和容量等属性在不同服务之间进行选择。以下是一些常见的服务发现解决方案:
| 解决方案 | 特点 | 适用场景 |
| — | — | — |
| ZooKeeper | 集中式、可靠且易于使用的存储,用于协调服务。用 Java 编写,通过 Java API 访问,有多种语言绑定。客户端需维护与服务器的活动连接并执行保活操作。 | 已有使用 ZooKeeper 的基础设施,且使用 Java 开发的场景。 |
| SmartStack | Airbnb 的服务发现解决方案,由 Nerve(健康检查和注册)和 Synapse(发现)两个组件组成。Synapse 使用 HAProxy 进行路由,并在发生变化时自动更新和重启。 | 适用于需要灵活服务发现和路由的场景。 |
| Eureka | Netflix 用于 AWS 负载均衡和故障转移的解决方案,设计为处理 AWS 节点的临时性。 | 在 AWS 基础设施上运行大型服务的场景。 |
| WeaveDNS | Weave 网络解决方案的服务发现组件,容器启动时自动注册,提供简单的负载均衡。 | 需要自动化服务发现和负载均衡的场景。 |
| docker - discover | 本质上是 SmartStack 的 Docker 原生实现,使用 etcd 作为后端,由 docker - register 和 docker - discover 两个组件组成,使用 HAProxy 处理路由。 | 对 Docker 原生服务发现有需求的场景。 |
此外,新的 Docker 网络特性(“New Docker Networking”)也通过服务对象提供了有限形式的服务发现,依赖于 Docker Overlay 网络驱动或其他兼容插件,如 Calico。
2. Docker 网络模式
在探讨跨主机网络解决方案之前,了解 Docker 的默认网络工作模式很有必要。Docker 有四种基本网络模式:
2.1 桥接模式(Bridge)
默认的桥接网络在开发环境中非常方便,能让容器轻松通信。但在生产环境中,其背后的底层配置开销较大。当容器启动时,Docker 会创建一个 veth 对,将容器的 eth0 连接到名为 docker0 的桥接器(通常运行在 172.17.42.1)。外部连接通过 IP 转发和 iptables 规则实现 IP 伪装(一种网络地址转换,NAT)。默认情况下,所有容器都可以相互通信,可通过在启动 Docker 守护进程时传递
--icc=false
标志来关闭容器间通信,通过设置
--icc=false
和
--iptables=true
可只允许链接的容器通信。
graph LR
classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px;
A(容器1):::process -->|veth对| B(docker0桥接器):::process
C(容器2):::process -->|veth对| B
B -->|IP转发和iptables规则| D(外部网络):::process
2.2 主机模式(Host)
使用
--net=host
运行的容器共享主机的网络命名空间,完全暴露在公共网络中。这意味着容器与主机共享 IP 地址,省去了桥接网络的底层配置,速度与正常主机网络相同。但需要注意的是,容器间通信需通过主机端口进行协调,可能需要对应用进行修改。同时,存在安全风险,可通过防火墙层进行管理。可考虑采用混合网络模型,让面向外部和网络密集型的容器(如代理和缓存)使用主机网络,其余容器使用内部桥接网络。容器在桥接网络中可通过 docker0 桥接器的 IP 地址与主机网络中的容器通信。
2.3 容器模式(Container)
使用另一个容器的网络命名空间,可用于创建和重用针对特定场景或数据中心架构优化的高效网络栈。但所有共享网络栈的容器需使用相同的 IP 地址等。在某些场景下效果很好,如 Kubernetes 就会使用这种模式。
2.4 无网络模式(None)
完全关闭容器的网络功能,适用于不需要网络的容器,如将输出写入卷的编译器容器。当需要从头开始设置自己的网络时,也可使用此模式,可借助 pipework 等工具处理 cgroups 和命名空间内的网络。
3. 新 Docker 网络特性
目前,Docker 网络栈和接口正在进行重大更新。主要变化是 docker 新增了两个顶级“对象”:网络(network)和服务(service),允许独立于容器创建和管理“网络”。容器启动时可分配到指定网络,只能与同一网络中的其他容器直接连接。容器可发布服务,通过名称进行通信,减少了对链接的依赖。
3.1 网络管理示例
- 列出当前网络及其 ID:
$ docker network ls
NETWORK ID NAME TYPE
d57af6043446 none null
8fcc0afef384 host host
30fa18d442b5 bridge bridge
- 创建服务:
$ docker run -d --name redis1 --publish-service db.bridge redis
9567dd9eb4fbd9f588a846819ec1ea9b71dc7b6cbd73ac7e90dc0d75a00b6f65
- 列出现有服务:
$ docker service ls
SERVICE ID NAME NETWORK CONTAINER
f87430d2f240 db bridge 9567dd9eb4fb
- 创建新容器并通过服务名称与其他容器通信:
$ docker run -it redis redis-cli -h db ping
PONG
3.2 服务重新分配示例
$ docker run redis redis-cli -h db set foo bar
OK
$ docker run redis redis-cli -h redis2 set foo baz
OK
$ docker run redis redis-cli -h db get foo
bar
$ docker service detach redis1 db
$ docker service attach redis2 db
$ docker run redis redis-cli -h db get foo
baz
新的网络模型在连接容器和维护系统时提供了更多的灵活性和可控性,同时仍支持以前的网络范式。
4. 网络类型和插件
网络有不同的类型,包括经典的主机、无网络和桥接类型,还有 overlay 类型,并且可以通过网络插件添加新类型。默认网络可在 Docker 守护进程上设置,若未设置则使用桥接网络。
4.1 插件安装
Docker 插件(包括网络驱动)可通过将其安装在
/usr/share/docker/plugins
目录下来添加,通常通过运行挂载该目录的容器来实现。插件可以用任何语言编写,只要能与 Docker 的 JSON - RPC API 接口。
以下是一些常见的跨主机网络解决方案:
4.2 Overlay
Overlay 是 Docker 用于跨主机网络的“内置”解决方案,使用 VXLAN 隧道连接具有自己 IP 空间的主机,使用 NAT 进行外部连接,使用 serf 库进行对等通信。连接容器到网络的方式与标准桥接网络类似,为 Overlay 网络设置 Linux 桥接器,并使用 veth 对连接容器。
4.2.1 示例步骤
- 登录到主机 overlay - 2:
$ docker-machine ssh overlay-2
- 创建名为“ovn”的 overlay 网络:
docker@overlay-2:~$ docker network create -d overlay ovn
5d2709e8fd689cb4dee6acf7a1346fb563924909b4568831892dcc67e9359de6
- 查看网络信息:
docker@overlay-2:~$ docker network info ovn
Network Id: 5d2709e8fd689cb4dee6acf7a1346fb563924909b4568831892dcc67e9359de6
Name: ovn
Type: overlay
- 启动 Redis 容器并将其作为服务暴露:
docker@overlay-2:~$ docker run -d --name redis-ov2 \
--publish-service redis.ovn redis:3
- 登录到主机 overlay - 1 并查看网络:
docker@overlay-2:~$ exit
$ docker-machine ssh overlay-1
docker@overlay-1:~$ docker network ls
NETWORK ID NAME TYPE
7f9a4f144131 none null
528f9267a171 host host
dfec33441302 bridge bridge
5d2709e8fd68 ovn overlay
- 启动 dnmonster 和 identidock 容器并连接到 ovn 网络:
docker@overlay-1:~$ docker run -d --name dnmonster-ov1 \
--publish-service dnmonster.ovn amouat/dnmonster:1.0
docker@overlay-1:~$ docker run -d --name identidock-ov1 \
--publish-service identidock.ovn amouat/identidock:1.0
- 检查是否正常工作:
docker@overlay-1:~$ docker exec identidock-ov1 curl -s localhost:9090
<html><head><title>Hello...
4.3 Weave
Weave 是一种开发者友好的网络解决方案,适用于各种环境,具有 WeaveDNS 用于服务发现和负载均衡、内置 IP 地址管理(IPAM)以及支持加密通信等功能。
4.3.1 示例步骤
- 创建 weave - redis 主机:
$ docker-machine create -d virtualbox weave-redis
- 登录并安装 Weave:
$ docker-machine ssh weave-redis
docker@weave-redis:~$ sudo curl -sL git.io/weave -o /usr/local/bin/weave
docker@weave-redis:~$ sudo chmod a+x /usr/local/bin/weave
docker@weave-redis:~$ weave launch
- 指向 Weave 代理并启动 Redis 容器:
docker@weave-redis:~$ eval $(weave env)
docker@weave-redis:~$ docker run --name redis -d redis:3
- 创建 weave - identidock 主机并安装 Weave:
$ docker-machine create -d virtualbox weave-identidock
$ docker-machine ssh weave-identidock \
"sudo curl -sL https://git.io/weave -o /usr/local/bin/weave && \
sudo chmod a+x /usr/local/bin/weave"
- 启动 Weave 并传入 weave - redis 主机的 IP:
$ docker-machine ssh weave-identidock \
"weave launch $(docker-machine ip weave-redis)"
- 检查网络连接:
$ docker-machine ssh weave-identidock
docker@weave-identidock:~$ eval $(weave env)
docker@weave-identidock:~$ docker run redis:3 redis-cli -h redis ping
PONG
- 启动 dnmonster 和 identidock 容器并检查应用是否正常工作:
docker@weave-identidock:~$ docker run --name dnmonster -d amouat/dnmonster:1.0
docker@weave-identidock:~$ docker run --name identidock -d -p 80:9090 \
amouat/identidock:1.0
docker@weave-identidock:~$ exit
$ curl $(docker-machine ip weave-identidock)
<html><head>...
$ curl -s $(docker-machine ip weave-identidock)/monster/gordon | head -c 4
PNG
Weave 通过两个容器管理其基础设施:
| 容器名称 | 功能 |
| — | — |
| weave | 包含 Weave 路由器,负责处理网络路由,与其他主机通信,学习网络拓扑,处理 DNS。 |
| weaveproxy | 拦截 docker run 请求,设置网络并修改请求,使容器使用 Weave 网络栈。 |
Weave 创建了一个 weave 桥接器,每个容器(包括路由器)通过 veth 对连接到该桥接器。它还支持将容器放置在不同子网中,实现应用隔离,并支持加密通信。
4.4 Flannel
Flannel 是 CoreOS 提供的跨主机网络解决方案,它为容器集群提供了一个扁平化的网络环境,使得不同主机上的容器可以像在同一个网络中一样进行通信。Flannel 的核心是在每个主机上运行一个 flanneld 守护进程,该进程负责分配子网并维护网络配置。
4.4.1 工作原理
- 子网分配 :Flannel 使用 etcd 作为分布式键值存储,在集群启动时,每个主机上的 flanneld 会从 etcd 中获取一个唯一的子网。
- 封装通信 :Flannel 通过网络封装技术(如 UDP、VXLAN 等)将容器之间的数据包进行封装,然后通过主机的网络接口进行传输。
4.4.2 安装和配置步骤
- 安装 etcd :在集群中的一台主机上安装并启动 etcd 服务。
# 下载 etcd
wget https://github.com/etcd-io/etcd/releases/download/v3.5.0/etcd-v3.5.0-linux-amd64.tar.gz
# 解压
tar xzvf etcd-v3.5.0-linux-amd64.tar.gz
# 启动 etcd
./etcd-v3.5.0-linux-amd64/etcd
- 在每个主机上安装 flanneld :
# 下载 flannel
wget https://github.com/coreos/flannel/releases/download/v0.14.0/flannel-v0.14.0-linux-amd64.tar.gz
# 解压
tar xzvf flannel-v0.14.0-linux-amd64.tar.gz
# 配置 flanneld 连接 etcd
./flanneld --etcd-endpoints=http://<etcd-server-ip>:2379
- 配置 Docker 使用 Flannel 网络 :在每个主机上修改 Docker 启动参数,使其使用 Flannel 分配的子网。
# 修改 Docker 服务配置文件
vi /etc/systemd/system/docker.service
# 在 ExecStart 行添加 --bip 参数
ExecStart=/usr/bin/dockerd --bip=$(cat /run/flannel/subnet.env | cut -d= -f2)
# 重新加载配置并重启 Docker
systemctl daemon-reload
systemctl restart docker
4.5 Project Calico
Project Calico 是 Metaswitch 开发的基于第 3 层(网络层)的网络解决方案,它为容器和虚拟机提供了高性能、安全的网络连接。Calico 不使用传统的网络封装技术,而是直接使用 IP 路由来实现容器之间的通信,因此具有较低的网络开销。
4.5.1 工作原理
- IP 路由 :Calico 在每个主机上配置路由表,使得容器之间的数据包可以直接通过 IP 路由进行转发。
- 网络策略 :Calico 提供了强大的网络策略功能,可以对容器之间的通信进行细粒度的控制。
4.5.2 安装和配置步骤
- 安装 Calico 组件 :可以使用 Kubernetes 或 Docker Compose 来安装 Calico。以下是使用 Kubernetes 的示例:
# 下载 Calico 配置文件
kubectl apply -f https://docs.projectcalico.org/v3.20/manifests/calico.yaml
- 配置网络策略 :可以使用 YAML 文件定义 Calico 网络策略,例如:
apiVersion: projectcalico.org/v3
kind: NetworkPolicy
metadata:
name: allow-nginx-to-redis
namespace: default
spec:
selector: app == 'nginx'
ingress:
- action: Allow
protocol: TCP
source:
selector: app == 'redis'
destination:
ports: [6379]
- 应用网络策略 :
kubectl apply -f network-policy.yaml
5. 总结与建议
5.1 服务发现总结
不同的服务发现解决方案适用于不同的场景:
- ZooKeeper 适用于已有 Java 基础设施且需要稳定可靠服务协调的场景。
- SmartStack 和 docker - discover 提供了灵活的服务发现和路由功能,适合对 Docker 原生支持有需求的场景。
- Eureka 是 AWS 环境下负载均衡和故障转移的理想选择。
- WeaveDNS 提供了自动化的服务发现和负载均衡,适合需要简化配置的场景。
5.2 网络解决方案总结
- 桥接模式 :适合开发环境,在生产环境中由于开销较大需谨慎使用。
- 主机模式 :适用于对网络性能要求较高的容器,如代理和缓存。
- 容器模式 :可用于创建和重用高效的网络栈,在特定场景下效果良好。
- 无网络模式 :适用于不需要网络的容器或需要自定义网络配置的场景。
- Overlay :是 Docker 内置的跨主机网络解决方案,使用方便,但目前处于实验阶段。
- Weave :功能丰富,提供服务发现、负载均衡和加密通信,适合开发者友好的场景。
- Flannel :为容器集群提供扁平化网络环境,配置相对简单。
- Project Calico :基于第 3 层网络,性能高且支持强大的网络策略。
5.3 建议
在选择服务发现和网络解决方案时,需要考虑以下因素:
-
应用场景
:根据应用的特点和需求选择合适的解决方案。
-
性能要求
:对于对网络性能要求较高的应用,可选择主机模式或 Project Calico 等高性能解决方案。
-
安全性
:对于对安全性要求较高的应用,可使用 Project Calico 的网络策略功能。
-
易用性
:对于开发者友好的场景,可选择 Weave 等易于使用的解决方案。
graph LR
classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px;
A(选择服务发现方案):::process -->|根据应用场景| B(ZooKeeper):::process
A -->|根据应用场景| C(SmartStack):::process
A -->|根据应用场景| D(Eureka):::process
A -->|根据应用场景| E(WeaveDNS):::process
F(选择网络解决方案):::process -->|根据性能要求| G(主机模式):::process
F -->|根据性能要求| H(Project Calico):::process
F -->|根据易用性| I(Weave):::process
F -->|根据应用场景| J(Overlay):::process
F -->|根据应用场景| K(Flannel):::process
F -->|根据应用场景| L(桥接模式):::process
F -->|根据应用场景| M(容器模式):::process
F -->|根据应用场景| N(无网络模式):::process
综上所述,Docker 的服务发现和网络解决方案提供了丰富的选择,开发者可以根据具体需求进行灵活配置,以实现高效、安全的容器化应用部署。在实际应用中,建议根据应用的特点和需求进行充分的测试和评估,选择最适合的解决方案。
超级会员免费看
5万+

被折叠的 条评论
为什么被折叠?



