深入理解 Docker 网络——多机通信及 Docker Swarm 实战

网络是云原生的灵魂,这篇文章将带你深入理解 Docker 在多机中是如何通信的

目录

引言

一、Docker overlay 网络实现原理

(一) Docker overlay 网络内部架构

(二) Docker overlay 网络传输过程

二、Docker Swarm 介绍

(一) 架构图

(二) 核心概念

Node

Service

扫描二维码关注公众号,回复: 15230472 查看本文章

Task

Node、Service 及 Task 关系图

三、Docker Swarm 实战

(一) 环境准备

(二) 搭建 Swarm 集群

(三) 实战案例

不使用 Docker Stack

使用 Docker Stack

参考文档


引言

上一篇介绍了 Docker 单机通信原理:链接

为了保证高可用,更常用的是将不同容器部署在多台机器上。这篇文章继续介绍 Docker 的多机通信原理,以及进行 Docker Swarm 实战

Docker 多机通信有多种实现方式,如直接路由方式、桥接方式、Overlay 隧道方式等。当前版本 Docker(20.10.21) 提供了多种解决方案,如 MacVlan 网络overlay 网络。overlay 网络实际上是目前最主流的容器跨节点数据传输和路由方案

1.12 版本开始,Docker 官方提供了 Docker Swarm 容器编排工具,并内置在 Docker Engine 中。Docker Swarm 底层使用了Docker overlay 网络,因此这篇文章主要介绍 overlay 网络的实现原理

一、Docker overlay 网络实现原理

Docker overlay 网络是基于 VXLAN 实现的分布式网络,可用于 Docker 的多机通信

VXLAN 是在底层物理网络(Underlay)之上使用隧道技术,借助 UDP 层构建的 Overlay 逻辑网络,它对原有的网络架构几乎没有影响,不需要对原网络做任何改动,就可以架设一层新的网络

Linux 内核在 3.7.0 版本时,就已经加入了对 VXLAN 的支持,Docker 正是利用了 Linux 内核中的原生 VXLAN 特性实现 overlay 网络的

(一) Docker overlay 网络内部架构

两台机器之间通过物理网络可以互相通信,如下图所示

在此基础上,使用 VXLAN 隧道技术创建虚拟二层覆盖网络,VXLAN 隧道两端都是 VXLAN 隧道终端(VXLAN Tunnel Endpoint, VTEP)。VTEP 的主要功能是 VXLAN 报文的封装和解封装

通常情况下,需要在宿主机中为 Overlay 网络创建一个默认的网桥,用于和物理网络通信。在 Docker Swarm 初始化后,引擎会自动创建 bridge 类型的 docker_gwbridge,且每台宿主机最多只能有一个 docker_gwbridge,如下图所示

创建 Overlay 网络时,Docker 引擎为每台主机创建所需的网络基础资源。每创建一个 Overlay,就会有一个 Linux 网桥关联到一个 VXLAN 接口上,VTEP 的位置和状态会被保存在分布式 Overlay 控制层中。但只有当容器被连接到 Overlay 网络时,Docker 引擎才会在主机上实例化 Overlay 网络,这可以预防连接一些不存的容器时,创建无效的网络实例

关联容器并实例化网络后,Docker overlay 驱动为集群内的每个容器分配唯一 IP 地址,如 eth1: 10.0.0.3 和 eth1: 10.0.0.6

通信过程中,Docker overlay 驱动将容器间通信所需的信息封装到 VXLAN Header 中,包括源容器 IP 及目标容器 IP

(二) Docker overlay 网络传输过程

如图所示,假设 2 台 CentOS 主机上的 2 个容器都已经连接到 ov-net 网络中,CentOS-A 上的 web-app 容器想要发送一条 Redis 命令到 CentOS-B 上的 redis-demo 中的 Redis 服务,查询网站当前的访问次数

传输过程如下

  • web-app 对 redis-demo 进行 DNS 解析。因为两个容器处于同一个 overlay 网络,CentOS-A 上的 Docker 引擎中的本地 DNS 服务可以解析 redis-demo 的 overlay IP 地址为 10.0.0.6
  • web-app 生成指向 redis-demo MAC 地址的 L2 报文
  • overlay 驱动负责将生成的报文封装到 VXLAN Header 中,此外,将当前主机及目标主机的物理 IP 地址封装到 Underlay IP Header 中
  • 报文封装完成后就发送出去,物理网络负责将它路由或桥接到正确的主机上
  • 数据包到达 CentOS-B 的 eth0 接口,Overlay 网络驱动解封装出原始 L2 报文并送至 redis-demo 的 eth0 接口,然后传输到容器内部的服务中

二、Docker Swarm 介绍

(一) 架构图

Docker Swarm 是 Docker 官方提供的容器编排工具,可以很方便地在多个服务器或主机上搭建集群服务。Docker Swarm 底层使用了上文提到的 Docker overlay 网络,集群管理和容器编排特性来自于 Docker 的另一个独立项目 swarmkit

一个 swarm 集群包含一个或多个管理节点(Manager),以及若干个工作节点(Worker),组成的集群架构图如下

(二) 核心概念

Node

Node 是 Swarm 集群中 Docker 引擎的实例,在一台物理机或云服务器上可以部署一个或多个 Node。Node 按角色可以分为管理节点和工作节点

管理节点的作用如下

  • 集群管理,维护 Swarm 状态,根据 Raft 协议选举一个 Leader 节点执行调度任务
  • 默认情况下,可以充当工作节点

工作节点上运行着一个代理,接收并执行管理节点分派的任务,并向管理节点报告任务执行情况

Service

Service 是对任务(Task)的定义,是 Swarm 系统的核心结构,创建服务时需要指定容器镜像,以及需要在容器中执行的命令

服务可以分为副本服务和全局服务。对于副本服务,管理节点根据设置的副本数调度对应的任务到工作节点;对于全局服务,每个节点有且只有一个任务

Task

Task 是 Swarm 的最小调度单元,包含一个容器,以及需要在容器中执行的命令

需要注意的是,一个 Task 的生命周期是单向的。比如,状态可以从 NEW 到 RUNNING,再到 COMPLETE,但不能反向。也就是说,一旦任务结束了,需要再次执行时,会创建新的任务并执行

Node、Service 及 Task 关系图

Service 相当于绘制一张施工蓝图,Swarm 则根据蓝图的细节,分配 Task 到不同的 Node 上干活

可以参考下图进行理解 

三、Docker Swarm 实战

基于以上的介绍,接下来进行 Docker Swarm 实战

(一) 环境准备

首先准备 3 台云服务器,IP 地址及计划节点角色如下,准备搭建 1 主 2 从的 Swarm 集群

121.37.169.103 # Manager节点,设置hostname为manager
1.116.156.102  # Worker节点,设置hostname为worker-01
139.196.219.92 # Worker节点,设置hostname为worker-02

设置 3 台云服务器的安全组,入方向规则添加 2377, 6379, 8080, 80 端口

(二) 搭建 Swarm 集群

在管理节点主机执行如下命令

# 语法 docker swarm init --advertise-addr <MANAGER-IP>
docker swarm init --advertise-addr 121.37.169.103

在工作节点对应的 2 台主机执行如下命令,这里的 Token 是在初始化管理节点时生成的,需要保持一致

docker swarm join --token SWMTKN-1-3w41cnhrqfu8tddsmfwzr05wgt7yupyfmwkavck6cdftfv47r9-19tgpf75tb3hqtaob5wz8dmtu 121.37.169.103:2377

# 打印的日志如下
This node joined a swarm as a worker.

进入管理节点,查看集群状态(该命令只能在管理节点执行)

docker node ls

输出信息如下

ID                            HOSTNAME    STATUS    AVAILABILITY   MANAGER STATUS   ENGINE VERSION
622h0w3knqdrvifyvb2thkkr6 *   manager     Ready     Active         Leader           20.10.21
gztfkjkrzrqljrhqtnpgq4b31     worker-01   Ready     Active                          20.10.21
k3r6xodo2cb5tdzks7h48zabm     worker-02   Ready     Active                          20.10.21

此时查看 Docker 网络,发现 3 台主机都有 docker_gwbridgeingress,其中 3 台主机的 ingress 网络 ID 均为 pupcl8y1k6kk,这也验证了 Docker Swarm 底层使用了 Docker overlay 网络进行多机通信

docker network ls

(三) 实战案例

如图所示,准备一个 SpringBoot 项目,使用 Redis 缓存应用的访问次数,计划为应用创建 3 个实例,并用 nginx 做负载均衡

SpringBoot 项目 docker-demo,对外提供了 2 个 Rest API,分别是

host:8080/hello - 增加访问次数

host:8080/visitCount - 返回当前总访问次数

项目地址:[email protected]:jason315/docker-demo.git

不使用 Docker Stack

Step 1 - 创建自定义 overlay 网络

进入管理节点,执行以下命令

docker network create -d overlay ov-net

Step 2 - 创建 Redis 服务

进入管理节点,执行以下命令

docker service create --network ov-net --name redis-demo -p 6379:6379 redis

# 上一条命令执行成功后,查看 Redis 运行在哪个节点上
docker service ps redis-demo

发现 Redis 运行在了 worker-02 节点上,对应的 IP 地址为 1.116.156.102

修改 docker-demo 项目的 application.yml 文件

server:
  port: 8080
spring:
  application:
    name: docker-demo
  redis:
    host: 139.196.219.92
    port: 6379

Step 3 - 将 docker-demo 项目打成镜像

# 进入 docker-demo 项目根目录
mvn clean package

target 目录下会生成 jar 包:docker-demo-0.0.1-SNAPSHOT.jar

将 jar 包上传到 3 台主机的一个目录下,假设为 /var/local/dockerdemo

分别进入 /var/local/dockerdemo 目录,创建 Dockerfile

FROM openjdk:8

MAINTAINER jason315
LABEL name="docker-demo" version="1.0" author="jason315"

COPY docker-demo-0.0.1-SNAPSHOT.jar docker-demo-image.jar
CMD ["java", "-jar", "docker-demo-image.jar"]

在 3 台主机上都将 jar 包构建成 Docker 镜像

docker build -t docker-demo:1.0 .

Step 4 - 创建 docker-demo 服务

docker service create --name docker-demo \
    --network ov-net \
    --replicas 3 \
    docker-demo:1.0

Step 5 - 创建 nginx 服务

在 3 台主机的 /var/local/dockerdemo 目录下都创建 nginx.conf 文件

user nginx;
worker_processes  1;
events {
    worker_connections  1024;
}
http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;
    sendfile      on;
    keepalive_timeout  65;
    server {
        listen 80;
        location / {
        proxy_pass http://balance;
      }
    }
    upstream balance {
        server docker-demo:8080;
    }
    include /etc/nginx/conf.d/*.conf;
}

这里 upstream 中的服务名设置的是 docker-demo,这是在第 5 步创建的,由于是在同一个 overlay 网络中,可以进行自动域名解析 

Step 6 - 创建 nginx 服务

docker service create --name nginx-demo \
    --mount type=bind,src=/var/local/dockerdemo/nginx.conf,dst=/etc/nginx/nginx.conf \
    --network ov-net \
    -p 80:80 \
    nginx

查看 nginx 服务在哪个节点上,发现是在管理节点上,对应的 IP 地址为 121.37.169.103

Step 7 - 测试

通过 /hello 接口访问一定次数后,调用 /visitCount 接口查看总访问次数,测试通过,然后可以停止服务了,Redis 服务先保留,后面还会再用到

# 在管理节点执行如下命令
docker service rm nginx-demo
docker service rm docker-demo

使用 Docker Stack

Docker 提供了类似于 Docker Compose 的机制,可以通过一个配置文件来描述集群需要创建哪些服务,这就需要用到 Docker Stack 了

同样地,在管理节点的 /var/local/dockerdemo 目录下创建 service.yml 文件

version: '3'

services:
  docker-demo:
    image: docker-demo:1.0
    networks:
      - ov-net2
    deploy:
      mode: replicated
      replicas: 3
      restart_policy:
        condition: on-failure
        delay: 5s
        max_attempts: 3
      update_config:
        parallelism: 1
        delay: 10s
  nginx-demo:
    image: nginx
    ports:
     - 80:80
    networks:
      - ov-net2
    volumes:
     - /var/local/dockerdemo/nginx.conf:/etc/nginx/nginx.conf
    deploy:
      mode: replicated
      replicas: 1

networks:
  ov-net2:
    driver: overlay

用 Stack 部署服务时,需要指定名称(假设为 stack-demo)

最终创建出来的服务会加上 Stack 名称作为前缀,如 stack-demo_docker-demo,因此需要适当修改 nginx.conf 的 upstram 部分

upstream balance {
    server stack-demo_docker-demo:8080;
}

接下来,根据 service.yml 创建服务

docker stack deploy -c service.yml stack-demo

创建完成后仍然可以用 docker service 相关命令查看

# 查看服务列表
docker service ls
ID             NAME                     MODE         REPLICAS   IMAGE             PORTS
rgk39ijvtvsq   redis-demo               replicated   1/1        redis:latest      *:6379->6379/tcp
lw737pf0uuv5   stack-demo_docker-demo   replicated   3/3        docker-demo:1.0
em7okvpd7e7a   stack-demo_nginx-demo    replicated   1/1        nginx:latest      *:80->80/tcp

# 查看 nginx 服务部署在哪里
docker service ps stack-demo_nginx-demo

当前 nginx 服务部署在管理节点上,访问结果如下

此时在管理节点上查看 overlay 网络,可以看到默认的 ingress, 以及自定义的 ov-net,还有 Stack 根据配置文件创建的 stack-demo_ov-net2

[root@manager dockerdemo]# docker network ls -f SCOPE=swarm
NETWORK ID     NAME                 DRIVER    SCOPE
pupcl8y1k6kk   ingress              overlay   swarm
lu3k1fu7yjw0   ov-net               overlay   swarm
wg81aqso2ovv   stack-demo_ov-net2   overlay   swarm

到这里 Docker 多机通信底层原理及实战就结束了,但 Docker Swarm 只是匆匆过客,最终还是要回到 Kubernetes 上

参考文档

Use overlay networks | Docker Documentation

Github 关于 overlay 网络的介绍

VXLAN 基础教程:VXLAN 协议原理介绍

猜你喜欢

转载自blog.csdn.net/u013481793/article/details/128253816