在k8s中,我们的应用会以pod的形式被调度到各个node节点上,在设计集群如何处理容器之间的网络时是一个不小的挑战,今天我们会从pod(应用)通信来展开关于k8s网络的讨论。

小作文包含如下内容:

  • k8s网络模型与实现方案
  • pod内容器通信
  • pod与pod通信
  • pod与service通信
  • 外网与service通信

k8s网络模型与实现方案

k8s集群中的每一个Pod(最小调度单位)都有自己的IP地址,即ip-per-pod模型

ip-per-pod模型中每一个pod在集群中保持唯一性,我们不需要显式地在每个 Pod 之间创建链接, 不需要处理容器端口到主机端口之间的映射。从端口分配、命名、服务发现、 负载均衡、应用配置和迁移的角度来看,Pod 可以被视作独立虚拟机或者物理主机。

如下图,从表面上来看两个容器在docker网络与k8s网络中与client通信形式。

k8s是一套庞大的分布式系统,为了保持核心功能的精简(模块化)以及适应不同业务用户的网络环境,k8s通过CNI(Container Network Interface)即容器网络接口集成各种网络方案。这些网络方案必须符合k8s网络模型要求:

  • 节点上的 Pod 可以不通过 NAT 和其他任何节点上的 Pod 通信
  • 节点上的代理(比如:系统守护进程、kubelet)可以和节点上的所有Pod通信

备注:仅针对那些支持 Pods 在主机网络中运行的平台(比如:Linux):

  • 那些运行在节点的主机网络里的 Pod 可以不通过 NAT 和所有节点上的 Pod 通信

如此操作,是不是有点像美团?将配送业务外包(CNI)给三方公司(实现方案),骑手是通过哪种飞机大炮(网络)送餐的我不管,只要符合准时、不撒漏(模型要求)等相关规矩这就是一次合格的配送。

CNI 做两件事,容器创建时的网络分配,和当容器被删除时释放网络资源。 常用的 CNI 实现方案有 Flannel、Calico、Weave以及各种云厂商根据自身网络推出的CNI插件如华为的 CNI-Genie、阿里云Terway。关于各实现方案的原理不是本次讨论重点,有机会单独写一篇。


pod内容器通信

Pod内容器非常简单,在同一个 Pod 内,所有容器共享存储、网络即使用同一个 IP 地址和端口空间,并且可以通过 localhost 发现对方。Pod 使用了一个中间容器 Infra,Infra 在 Pod 中首先被创建,而其他容器则通过 Join Network Namespace 的方式与 Infra 容器关联在一起。

我们有一个pod包含busybox、nginx这两个容器

kubectl get pod -n training
NAME READY STATUS RESTARTS AGE
pod-localhost-765b965cfc-8sh76 2/2 Running 0 2m56s

在busybox中使用telnet连接nginx容器的 80端口看看。

kubectl exec -it  pod-localhost-765b965cfc-8sh76 -c container-si1nrb -n training -- /bin/sh

# telnet localhost 80
Connected to localhost

一个pod有多个容器时可以通过-c指定进入的容器名(通过describe查看容器名称),显然通过localhost就可以轻松访问到同一个pod中的nginx容器80端口。这也是在许多关系密切的应用中通常会部署在同一个pod中。


pod与pod通信

  1. pod在同一主机

我们通过node选择器将两个pod调度到同一个node中

 ...
nodeSelector:
kubernetes.io/hostname: node2
...

两个容器分别获得一个IP地址,同样通过IP地址双方网络正常互通。

# kubectl get pod -o wide -n training
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES pod-to-pod-64444686ff-w7c4g 1/1 Running 0 6m53s 100.82.98.206 node2 <none> <none>
pod-to-pod-busybox-7b9db67bc6-tl27c 1/1 Running 0 5m3s 100.82.98.250 node2 <none> <none>
# kubectl exec -it pod-to-pod-busybox-7b9db67bc6-tl27c -n training -- /bin/sh
/# telnet 100.82.98.206 80
Connected to 100.82.98.206

同一主机网络的pod互通和我们之前学习的docker bridge相似,通过linux网桥添加虚拟设备对veth pair连接容器和主机主机命名空间。具体可查看文章《docker容器网络bridge》。

我们把之前的图拿过来,在k8s中只不过把灰色部分替换成CNI方案实现。

  1. pod在不同主机

此时我们的pod分布如下:

kubectl get pod -o wide -n training
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES pod-to-pod-64444686ff-w7c4g 1/1 Running 0 104m 100.82.98.206 node2 <none> pod-to-pod-busybox-node2-6476f7b7f9-mqcw9 1/1 Running 0 42s 100.91.48.208 node3 <none> # kubectl exec -it pod-to-pod-busybox-node2-6476f7b7f9-mqcw9 -n training -- /bin/sh
/ # telnet 100.82.98.206 80
Connected to 100.82.98.206

pod在不同主机的通信依赖于CNI插件,这里我们以Calico为例的做简单了解,从Calico架构图中可以看到每个node节点的自身依然采用容器网络模式,Calico在每个节点都利用Linux 内核实现了一个高效的虚拟路由器vRouter来负责数据转发。每个虚拟路由器将路由信息广播到网络中,并添加路由转发规则。同时基于iptables还提供了丰富的网络策略,实现k8s的Network Policy策略,提供容器间网络可达性限制的功能。

简单理解就是通过在主机上启动虚拟路由器(calico node),将每个主机作为路由器使用实现互联互通的网络拓扑。

Calico节点组网时可以直接利用数据中心的网络结构(L2或者L3),不需要额外的NAT、隧道或者Overlay Network,没有额外的封包解包,能够节约CPU运算,提高网络效率。


pod与service通信

我们知道在k8s中容器随时可能被摧毁,pod的IP显然不是持久的,会随着扩展或缩小应用规模、或者应用程序崩溃以及节点重启等而消失和出现。service 设计就是来处理这个问题。service可以管理一组 Pod 的状态,允许我们跟踪一组随时间动态变化的 Pod IP 地址。而客户端只需要知道service这个不变的虚拟IP就可以了。

我们先来看看典型的service与pod使用,我们创建了一个service,标签选择器为app:nginx,将会路由到app=nginx标签的Pod上。

# kubectl get service -n training
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
training-service ClusterIP 10.96.229.238 <none> 8881/TCP 10m

Service对外暴露的端口8881,这样在集群的中的pod即可通过8881访问到与service 绑定的label为app=nginx的pod

kubectl run -it --image nginx:alpine curl --rm /bin/sh
/ # curl 10.96.229.238:8881
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
...

其实大多数时候在自动化部署服务时并不知道service ip,所以另一种常见方式通过DNS进行域名解析后,可以使用“ServiceName:Port”访问Service,可以自己尝试一下。

service 是如何做到服务发现的?

Endpoints是k8s中的一种资源对象,k8s通过Endpoints监控到Pod的IP,service又关联Endpoints从而实现Pod的发现。大致如下图所示,service的发现机制我们会在后面文章中做深入了解。


外网与service通信

其实所谓外网通信也是service的表现形式。

service几种类型和不同用途。

  • ClusterIP:用于在集群内部互相访问的场景,通过ClusterIP访问Service,即我们上面所说的pod与service。
  • NodePort:用于从集群外部访问的场景,通过节点上的端口访问Service。
  • LoadBalancer:用于从集群外部访问的场景,其实是NodePort的扩展,通过一个特定的LoadBalancer访问Service,这个LoadBalancer将请求转发到节点的NodePort,而外部只需要访问LoadBalancer。
  • None:用于Pod间的互相发现,这种类型的Service又叫Headless Service。

我们先来看NodePort:

我们在service中指定type: NodePort创建出的service将会包含一个在所有node 开放的端口30678,这样我们访问任意节点IP:30678即可访问到我们的pod

# kubectl get service -n training
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
training-service NodePort 10.96.229.238 <none> 8881:30678/TCP 55m # curl 192.168.1.86:30678
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
....

LoadBalancer类型和它名字一样,为负载均衡而生。它的结构如下图所示,

LoadBalancer本身不是属于Kubernetes的组件,如果使用云厂商的容器服务。通常会提供一套他们的负载均衡服务比如阿里云ACK的SLB、华为云的ELB等等。Service是基于四层TCP和UDP协议转发的,而k8s 另外一种资源对象Ingress可以基于七层的HTTP和HTTPS协议转发,可通过域名和路径做到更细粒度的划分,这是后话。


希望小作文对你有些许帮助,如果内容有误请指正。

您可以随意转载、修改、发布本文,无需经过本人同意。 通过博客阅读:iqsing.github.io

k8s网络模型与集群通信的更多相关文章

  1. kubeadm实现k8s高可用集群环境部署与配置

    高可用架构 k8s集群的高可用实际是k8s各核心组件的高可用,这里使用主备模式,架构如下: 主备模式高可用架构说明: 核心组件 高可用模式 高可用实现方式 apiserver 主备 keepalive ...

  2. 【葵花宝典】lvs+keepalived部署kubernetes(k8s)高可用集群

    一.部署环境 1.1 主机列表 主机名 Centos版本 ip docker version flannel version Keepalived version 主机配置 备注 lvs-keepal ...

  3. 日志分析系统 - k8s部署ElasticSearch集群

    K8s部署ElasticSearch集群 1.前提准备工作 1.1 创建elastic的命名空间 namespace编排文件如下: elastic.namespace.yaml --- apiVers ...

  4. 集群通信组件Tribes之整体介绍

    接下来一系列文章会对集群通信框架tribes进行源码级别的分析,欢迎讨论. 把若干机器组合成一个集群,集群为了能协同工作,成员之间的通信是必不可少的,当然可以说这也是集群实现中重点需要解决的核心问题, ...

  5. 集群通信组件tribes之使用方法

    上面已经对tribes的内部实现机制及原理进行了深入的剖析,在理解它的设计原理后看看如何使用tribes,整个使用相当简单便捷,只需要四步: ① 定义一个消息对象,由于这个消息对象是要在网络之间传递的 ...

  6. 集群通信组件tribes之用法

    上面已经对tribes的内部实现机制及原理进行了深入的剖析.在理解它的设计原理后看看怎样使用tribes.整个使用相当简单便捷,仅仅须要四步: ① 定义一个消息对象,因为这个消息对象是要在网络之间传递 ...

  7. .Net Core2.1 秒杀项目一步步实现CI/CD(Centos7.2)系列一:k8s高可用集群搭建总结以及部署API到k8s

    前言:本系列博客又更新了,是博主研究很长时间,亲自动手实践过后的心得,k8s集群是购买了5台阿里云服务器部署的,这个集群差不多搞了一周时间,关于k8s的知识点,我也是刚入门,这方面的知识建议参考博客园 ...

  8. k8s 使本地集群支持 LoadBalancer 服务

    k8s 使本地集群支持 LoadBalancer 服务 为了使本地集群支持 LoadBalancer 服务,可以参考以下两种实现方案: keepalived-cloud-provider metalL ...

  9. Envoy 基础教程:使用 Unix Domain Socket(UDS) 与上游集群通信

    Envoy Proxy 在大多数情况下都是作为 Sidecar 与应用部署在同一网络环境中,每个应用只需要与 Envoy(localhost)交互,不需要知道其他服务的地址.然而这并不是 Envoy ...

随机推荐

  1. React-高阶函数_函数柯里化

    高阶函数_函数柯里化 高阶函数(定义) 如果一个函数符合下面两个规范,就是高阶函数: 如果A函数,接收的参数是一个函数,那么A就是一个高阶函数(比如数组方法arr.map()接收的就是一个处理item ...

  2. Angular 的性能优化

    目录 序言 变更检查机制 性能优化原理 性能优化方案 小结 参考 序言 本文将谈一谈 Angular 的性能优化,并且主要介绍与运行时相关的优化.在谈如何优化之前,首先我们需要明确什么样的页面是存在性 ...

  3. 数值计算:Legendre多项式

    Legendre多项式的概念以及正交特性在此不多作描述,可以参考数学物理方程相关教材,本文主要讨论在数值计算中对于Legendre多项式以及其导数的计算方法. Legendre多项式的计算 递推公式 ...

  4. css的公共属性及原因

    在我们写多个网页的时候,会发现总会遇到很多相同的css样式,若是每次都要在网页代码中写,会浪费时间,同时也会消耗浏览器和计算机的性能.因此,我个人将我敲代码过程中的经常用到的css样式总结了一下.再用 ...

  5. 基于python深度学习的apk风险预测脚本

    基于python深度学习的apk风险预测脚本 为了有效判断安卓apk有无恶意操作,利用python脚本,通过解包apk文件,对其中xml文件进行特征提取,通过机器学习构建模型,预测位置的apk包是否有 ...

  6. Winfrom窗体初始化和窗体Load方法前后

    运行结果为 [窗体初始化之前!]>[窗体初始化!]>[窗体Load!]

  7. [软工作业]-软件案例分析-CSDN

    [软工作业]-软件案例分析-CSDN(app) 项目 内容 这个作业属于哪个课程 2020春季计算机学院软件工程(罗杰 任健) 这个作业的要求在哪里 个人博客作业-软件案例分析 我在这个课程的目标是 ...

  8. [敏捷软工团队博客]The Agiles 团队介绍&团队采访

    项目 内容 课程:北航-2020-春-敏捷软工 博客园班级博客 作业要求 团队作业-团队介绍和采访 团队名称来源 The Agile is The Agile. 敏捷就是敏捷.我们只是敏捷的践行者罢了 ...

  9. git常用的一些简单命令

    1.如果一个文件被修改了,但是还没有使用 git add 命令,此时想取消这次修改,需要执行的命令如下: git checkout -- 文件名 2.如果一个文件执行了 git add ,此时想取消这 ...

  10. 热身训练2 The All-purpose Zero

    The All-purpose Zero 简要题意:  长度为n的数组,每个数字为S[i],$0$是一种很神奇的数字,你想要的,它都可以变! 问这个序列的最长上升子序列长度为多少? 分析: 我们将除了 ...