容器网络概述

本文涉及的产品
容器服务 Serverless 版 ACK Serverless,317元额度 多规格
容器服务 Serverless 版 ACK Serverless,952元额度 多规格
容器镜像服务 ACR,镜像仓库100个 不限时长
简介: 本文讲的是容器网络概述【编者的话】本文介绍容器网络,对容器网络的实践。
本文讲的是容器网络概述【编者的话】本文介绍容器网络,对容器网络的实践。

我在博客中经常讨论关于容器的事情,是因为我在工作中一直在关注着它们。

对于这些新奇容器的东西,最难理解的实际是关于容器的网络问题。

虽然有很多不同的方式来解决容器网络互连问题,并且介绍这方面的文档也很多,但是有些用起来很糟糕。我对这些非常的困惑,因此我试图在这篇博客当中用非专业术语的方式来理清这个问题。
(我不喜欢夸夸其谈,但是我对于容器网络文档当前状态真的很沮丧。)

到底容器网络是什么呢?

当我们在容器中运行程序时,你将有两个主要的操作:
  • 在主机网络命名空间上运行该程序。这是正常的容器网络方式——如果你在8282端口上运行的程序,那么他将在本地计算机的8282端口上运行。这很正常。
  • 在容器自身的网络命名空间上运行该程序。

如果你将程序运行在其自身所在容器网络命名空间上(假如是在 9382 端口),那么在其他计算机上的其它程序将要通过网络连接来与此程序通信。

起初我想:“这能复杂到哪去,将两个程序连接在一起很简单,不是吗?”就像说这个问题只有一种解决方式吗?而事实上对于容器中的程序网络互联问题有着成百上千的解决办法。接下来让我们去看看都有哪些方式。

每个容器都有个IP

如果你经常关注容器,你应该听说过 Kubernetes  。Kubernetes 是一个可以使得你的容器可以自行决定其应该在哪一台机器上运行的系统(当然还有其它功能)。

Kubernetes 的核心需求之一(当你刚刚开始用它的时候)就是每个容器要分配IP地址,于是在集群当中的其它应用程序可以通过容器对应的IP地址与之通信。这也就意味着在一台计算机上,你可能会拥有成百上千的容器以及对应的成百上千个IP地址(而不是一个IP地址和一堆端口)。

当我第一次听到“每个容器都有一个IP地址”的概念,我很困惑和担心。这个怎么可能行得通?!我的计算机也仅仅只有一个IP地址!这个听起来像是难以理解的魔法一样。事实证明,幸运的是,与大多数计算机的东西类似,这是完全可以理解的。

“每一个容器具有一个IP地址“这个问题正是我写这篇博客想要说清楚的问题。虽然有很多解决容器网络的方法,但是从现在开始这里只解释上述的这一种方式。

而且我讲的是针对AWS来解决容器网络问题。如果你有自己的物理数据中心,那么将有更多的选择。

我们的目标

你有一台计算机(AWS instance),这个计算机有一个IP地址(比如172.9.9.9)。

你想要你的容器也有一个IP地址(比如10.4.4.4)。

我们将要学习在172.9.9.9这台计算机上如果将一个数据包发送给10.4.4.4。

在AWS上是非常容易实现的—AWS上具有这项功能叫做 “VPC Route Tables”,你可以直接的告诉它“请为10.4.4.*发送数据包到172.9.9.9”,这样AWS将为你完成这件事。但是这个规则的限制是最多只能有50个,如果你想要的容器集群数目超过50个实例,那么你需要回到对容器网络困惑的原点。

一些网络基础:IP地址、MAC地址、本地网络

为了更好的理解怎样在一台物理机上拥有成百个IP地址,我们需要懂得一些计算机网络的基本概念。

我将说一些你理所应当懂得的东西:
  • 在计算机网络当中,程序是通过发送数据包来进行互相交互通信的
  • 每一个数据包(大部分的)都有一个IP地址包含在内
  • 在Linux中,内核来完成大部分的网络协议工作
  • 一点有关子网概念:子网10.4.4.0/24指的是“从10.4.4.0到10.4.4.255的每一个IP”。我有的时候会写成10.4.4.*来代替。

接下来我会尽全力去解释。

网络数据包的组成

一个网络数据包有很多个部分组成(经常被称为“layers”)。网络数据包的种类也有很多种,但是让我们只谈最常见的HTTP请求(像 GET / )。组成部分有:
  1. 数据包将被发送到的MAC地址(“Layer 2”)
  2. 源IP地址和目标IP地址(“Layer 3”)
  3. 端口和其它的TCP/UDP信息(“Layer 4”)
  4. HTTP数据包的具体数据内容像GET / (“Layer 7”)

本地网络 VS 远端网络

当你直接将一个数据包发给一台计算机(在同一个本地网络当中),过程如下。

数据包被MAC地址标记,我的MAC地址是 3c:97:ae:44:b3:7f ;我通过运行 ifconfig 命令:
bork@kiwi~> ifconfig
enp0s25   Link encap:Ethernet  HWaddr 3c:97:ae:44:b3:7f 


如果发送一个数据包给我,任意的一台本地计算机都可以将  3c:97:ae:44:b3:7f 写在数据包上,然后将它发送到我这里。在AWS上,“本地网络”意味着“可用区域”。如果两个实例在同一个AWS的可用区域中,它们只需写上目标的MAC地址,然后数据包会被传送到止指定的目标计算机,无所谓数据包上写的哪个IP地址。

OK,那么如果我的计算机和目标计算机不在同一个本地网络/可用区域中呢?然后呢?然后中间路由器就会查看数据包上的IP地址,然后将它送达指定的地址。

路由器的工作原理还有很多内容,但是现在我们没有时间去探讨。幸运的是,在AWS上你通常没有办法去配置路由信息,因此也就无所谓它是如何工作的!发送一个数据包到可用区域外的实例,你需要将该实例所在的物理机的IP地址写在数据包上。否则数据包无法找到目标实例。

如果你管理自己的数据中心,你可以很轻松的去设置自己的路由信息。
因此,针对AWS我们可以学到的如下:
  • 如果你和目标主机在同一个可用区域里,你仅仅发送数据包携带随便任何IP地址都可以,只要MAC地址是正确的就可以。
  • 如果你和目标主机不不同的AZ里,那么发送数据包到那台计算机,你就必须要将目标实例所在的IP地址写在数据包上。

路由表

你可能想问:“Julia,但是我如何控制要发送到的MAC地址的数据包呢。我从来没有做过这个,这非常令人困惑”。

当你发送一个数据包到本地网络的一台计算机,地址为 172.23.2.1 ,你的操作系统(我们希望你的操作系统是Linux)通过它维护的一个表来查看该IP所对应的MAC地址(这个表叫做ARP table)。将这个MAC地址放在数据包上,然后发送出去。

那么,如果我有一个地址为 10.4.4.4 的容器的数据包,但是我想将它发送到 172.23.2.1 ?这个其实也是非常简单的。你仅仅是在另外一个表上插入一个条目而已。这些都是表能做的事情。

这是推荐你可以手动执行的命令:
sudo ip route add 10.4.4.0/24 via 172.23.1.1 dev eth0


ip route add 是你所在的计算机(IP:172.23.1.1)的路由表当中加一个条目。这个路由表表示:“Linux,当你看到从 10.4.4.* 来的数据包,就将它发送到MAC地址为 172.23.2.1 的目标主机,可以吗?”

我可以赋予容器IP地址

是时候来庆祝我们的第一波胜利!我们现在知道所有的基本工具以及一种主要的方式来路由容器IP地址。

步骤如下:
  1. 为你的每一个计算机选择一个不同的子网(比如10.4.4.0/24,也表示为10.4.4.*)。这个子网将会让你可以在一台机器上有256个容器。
  2. 在每一台计算机上,增加路由到其它的每一台计算机。于是你可以为10.4.1.0/2410.4.2.0/2410.4.3.0/24等等增加一个路由。
  3. 你已经完成了,数据包10.4.4.4现在将会路由到正确的计算机。这里还存在一个问题就是如果数据包到达目标计算机,它们将会做些什么呢,稍后我会介绍一下。

于是我们用来处理容器网络的第一个工具就是路由表。

如果两台计算机不在同一个可用区域呢?

我们早些时候说过路由表这个方式仅仅作用在计算机直连网络中。那么如果两台计算机在远端网络(在不同的本地网络)我们就需要做一些更加复杂的事情了。

我们想要发送数据包到一个容器,该容器IP地址为 10.4.4.4 ,该容器所在的计算机地址为 172.9.9.9 。因为目标计算机是远端网络,那么我们不得不将IP地址 172.9.9.9 写入该数据包。那么现在问题来了,我们应该在哪里放 10.4.4.4 这个地址呢?

封装

所有的数据包都不会丢失,我们可以做一个叫“封装”的东西。这就是你拿到一个网络数据包,然后将它放在另外一个网络数据包里面。

因此代替原有的数据包:
IP: 10.4.4.4
TCP stuff
HTTP stuff

我们将会发送如下数据包:
IP: 172.9.9.9
(extra wrapper stuff)
IP: 10.4.4.4
TCP stuff
HTTP stuff

这里至少有两种不同的方式来做封装:分别为“ ip-in-ip ”封装和 “ vxlan ”封装。

Vxlan  封装是将你的整个数据包(包含MAC地址) 外包已成 UDP 数据。就像这样:
MAC address: 11:11:11:11:11:11
IP: 172.9.9.9
UDP port 8472 (the "vxlan port")
MAC address: ab:cd:ef:12:34:56
IP: 10.4.4.4
TCP port 80
HTTP stuff

ip-in-ip  封装仅仅是在就的IP头上打上一个额外的IP头。这就意味着,你不需要将目标MAC地址保持在你想发给的数据包上,但是我不确定你是否会关心这一点。
MAC:  11:11:11:11:11:11
IP: 172.9.9.9
IP: 10.4.4.4
TCP stuff
HTTP stuff


如何设置封装

像之前那样,你可以会想“我如何通过我的内核去对我的数据包做这样一个奇怪的封装“?这个证实确实并没有那么困难。基本上你所需要做的就是设置一个新的 网络接口 来配置封装。

在我自己的电脑上,我可以这样做: 参考这里
sudo ip tunnel add mytun mode ipip remote 172.9.9.9 local 10.4.4.4 ttl 255
sudo ifconfig mytun 10.42.1.1


紧接着你要设置一个路由表,但是你要告诉Linux将你的数据包路由到你所配置的封装网络接口上。这里我们可以像这样做:
sudo route add -net 10.42.2.0/24 dev mytun
sudo route list 


我给你这些命令是因为我认为你可以使用 create / inspect 这些 tunnels( ip route list ip tunnel ifconfig )——我已经遇到过一些错误,但是这是关于它是如何工作的。

路由是如何分布的?

我们已经谈论了将路由添加到路由表的过程( 10.4.4.4 被添加到 172.9.9.9 ),但是我没有解释路由器具体如何从路由表当中获取信息的。理论上我们是希望他们能自动去识别。

每一个容器网络的东西都是通过在每一个box里面运行一个守护进程来负责添加路由信息到路由表。

这里有两种主要方式:
  1. 这些路由器在一个etcd集群当中,每一个程序通过etcd集群来确认配置哪一个路由
  2. 通过BGP路由协议来互相的通信,然后在每一个box里面用一个守护进程(BIRD)来监听BGP消息

当数据包到达的你的box时会发生什么?

在正在运行Docker中,一个数据包从IP地址为 10.4.4.4 的容器过来,那么这个数据包最终到达你的程序是终态是什么样的呢?

我现在来解释 桥接网络 。这个地方我有一点模糊,所以可能会出现错误。

我现在的理解是这样的:
  • 在你的计算机上的每一个数据包都是通过一个实际的接口传送出去的(比如eth0
  • Docker会为每一个单一的容器创建(虚拟)网络接口,这些接口具有IP地址类似10.4.4.4
  • 这些虚拟网络接口都被桥接到你的真实的物理网络接口上。这就是说这些数据包被复制(?)到这些网络接口所对应真实网卡上,然后在网络上被传送出去

这看起来非常重要,但是我还没有完全理解。

最终:这些容器的网络如何工作的

现在我们有已经介绍了容器网络的基本概念。

Flannel

Flannel支持几种不同方式的网络:
  • vxlan(封装所有的数据包)
  • host-gw(仅仅是设置路由表,没有封装)

这个守护进程通过etcd集群来设置路由信息。

Calico

Calico支持两种不同的网络方式:
  • ip-in-ip:封装
  • “普通“模式(仅仅是设置路由表,没有封装)

这里守护进程是通过使用使用其它主机的 BGP 信息来设置路由表。Calico具有etcd集群但它并不用于分发路由。

Calico最令人兴奋的是可以不使用封装。如果你观察的够仔细你会发现Flannel也有一个选择是不需要使用封装。如果你是在AWS上,这两种你看不出哪个更好,它们有共同的限制:他们都是工作在具有相同的可用区域的实例之间。

这些关于容器网络的问题大部分都是设置路由以及tunnels等等一些事情,但是我觉得弄明白这些场景中到底做了什么是非常重要的,这样你才可以在出问题的时候调试和解决问题。

这是软件定义网络吗?

我不知道什么是软件定义网络。这有助于你做与众不同的网络,而且它都是软件,也许这就是所谓的软件定义网络吧?

总结

我已经陈述完了。希望这些能对您有一定作用,这个证明了容器网络并不是很烂,而且我们花费了一些时间在 ip 命令。 ifconfig tcpdump ,这些可以帮助我们理解基本的Kubernetes部署。你不需要成为一个专家级的网络工程师。我的同事Doug帮助我理解了很多问题。

原文链接: A container networking overview(翻译:edge_dawn 审校: 田浩浩)

原文发布时间为:2017-02-12

本文作者:田浩浩

本文来自云栖社区合作伙伴Dockerone.io,了解相关信息可以关注Dockerone.io。

原文标题:容器网络概述

相关实践学习
通过Ingress进行灰度发布
本场景您将运行一个简单的应用,部署一个新的应用用于新的发布,并通过Ingress能力实现灰度发布。
容器应用与集群管理
欢迎来到《容器应用与集群管理》课程,本课程是“云原生容器Clouder认证“系列中的第二阶段。课程将向您介绍与容器集群相关的概念和技术,这些概念和技术可以帮助您了解阿里云容器服务ACK/ACK Serverless的使用。同时,本课程也会向您介绍可以采取的工具、方法和可操作步骤,以帮助您了解如何基于容器服务ACK Serverless构建和管理企业级应用。 学习完本课程后,您将能够: 掌握容器集群、容器编排的基本概念 掌握Kubernetes的基础概念及核心思想 掌握阿里云容器服务ACK/ACK Serverless概念及使用方法 基于容器服务ACK Serverless搭建和管理企业级网站应用
相关文章
|
26天前
|
负载均衡 网络协议 开发者
掌握 Docker 网络:构建复杂的容器通信
在 Docker 容器化环境中,容器间的通信至关重要。本文详细介绍了 Docker 网络的基本概念和类型,包括桥接网络、宿主网络、覆盖网络和 Macvlan 网络等,并提供了创建、管理和配置自定义网络的实用命令。通过掌握这些知识,开发者可以构建更健壮和灵活的容器化应用,提高应用的可扩展性和安全性。
|
2天前
|
监控 Kubernetes 测试技术
掌握Docker网络模式:构建高效容器通信
【10月更文挑战第3天】本文深入探讨了Docker的网络模式,包括它们的工作原理、使用场景以及如何配置和优化容器间的通信。希望能够帮助开发者在项目中有效地应用Docker网络模式,构建高效的容器化应用。
|
1月前
|
NoSQL 应用服务中间件 Redis
Docker跨宿主机容器通信-通过网络跨宿主机互联
这篇文章介绍了Docker容器跨宿主机通信的实现方法,包括Docker的四种网络模式(host、none、container、bridge)以及如何通过修改网络配置和添加路由规则来实现不同宿主机上的容器之间的互联。
114 0
Docker跨宿主机容器通信-通过网络跨宿主机互联
|
4天前
|
机器学习/深度学习 存储 自然语言处理
深度学习入门:循环神经网络------RNN概述,词嵌入层,循环网络层及案例实践!(万字详解!)
深度学习入门:循环神经网络------RNN概述,词嵌入层,循环网络层及案例实践!(万字详解!)
|
5天前
|
机器学习/深度学习 PyTorch API
深度学习入门:卷积神经网络 | CNN概述,图像基础知识,卷积层,池化层(超详解!!!)
深度学习入门:卷积神经网络 | CNN概述,图像基础知识,卷积层,池化层(超详解!!!)
|
15天前
|
网络协议 安全 开发者
掌握 Docker 网络:构建复杂的容器通信
在 Docker 容器化环境中,容器间的通信至关重要。本文详细介绍了 Docker 网络的基础知识,包括网络驱动、端口映射和命名等核心概念,并深入探讨了 Bridge、Host、Overlay 和 Macvlan 四种网络类型的特点及应用场景。此外,还提供了创建、连接、查看和删除自定义网络的命令示例,以及高级网络配置方法,如网络命名空间、DNS 解析和安全通信配置,帮助开发者构建更健壮的容器化应用。
|
1月前
|
Linux 调度 Docker
容器网络概述
【9月更文挑战第9天】容器技术利用如命名空间(namespace)和控制组(cgroup)等技术创建隔离环境,实现资源限制与独立运行。命名空间避免命名冲突,cgroup则能对CPU、内存等资源进行限制。容器状态可通过镜像保存并标准化,确保在任何环境中都能复现相同状态。
|
2月前
|
存储 运维 监控
|
2月前
|
Kubernetes Cloud Native 网络安全
云原生入门指南:Kubernetes和容器化技术云计算与网络安全:技术融合的新篇章
【8月更文挑战第30天】在云计算的浪潮中,云原生技术如Kubernetes已成为现代软件部署的核心。本文将引导读者理解云原生的基本概念,探索Kubernetes如何管理容器化应用,并展示如何通过实践加深理解。
|
3天前
|
消息中间件 NoSQL Kafka
Flink-10 Flink Java 3分钟上手 Docker容器化部署 JobManager TaskManager Kafka Redis Dockerfile docker-compose
Flink-10 Flink Java 3分钟上手 Docker容器化部署 JobManager TaskManager Kafka Redis Dockerfile docker-compose
16 4