标签归档:k8s

搜狗BizCloud基于Kubernetes的私有云实践

【编者的话】随着搜狗业务的快速增长,需要更有效地控制成本,提升研发效率,我们基于Docker和Kubernetes构建了一站式私有云管理平台——BizCloud,此平台涵盖服务管理、弹性伸缩、灰度发布、自动运维、持续集成等功能。本文将简要介绍BizCloud的设计思路、架构及服务发现、授权、灰度发布等核心功能的实现。

BizCloud简介

我们基础环境非常复杂,目前有多个版本操作系统共存,应用也常常存在着多个版本同时测试或部署,在多版本并行测试过程中,经常出现环境借用的情况,因操作系统和基础软件不一致的问题,会出现线下测试没问题,但上线后出问题;其次,线上的实体机在业务低峰时使用率较低,存在较大的提升空间;服务上下线也涉及到一系列机器的申请回收流程,需要手工执行,系统的弹性伸缩能力不足。这种种问题都是我们设计私有云的原因,也就是要做到保持环境一致、提升资源利用率,并提升弹性计算能力。

为了解决上述问题,我们使用目前非常流行的容器技术Docker和容器编排工具Kubernetes,研发了商业云平台BizCloud。但Docker和Kubernenets只提供了一个基础功能:容器运行和容器编排,如何能快速地学会使用,并为大家所接受才是关键。

在自研BizCloud过程中,一个重点就是要对接、打通现存的系统和流程,尽量保持用户操作习惯,服务在容器化的过程中,尽可能不需要调整,这样系统才易于推广落地;另一方面,我们要支持服务一键自动部署(QA特别需要这样的功能),服务出现故障后,如系统宕机或服务挂掉后,服务能自动迁移,而且我们需要支持灰度发布,尽量实现运维的自动化。

商业平台系统的整体架构如下图所示。共分为三层,IaaS层、PaaS层、SaaS层:在IaaS层,我们使用Docker+Kubernetes封装了部门的基础资源,提供容器化服务;PaaS层提供了很多基础服务和基础框架,并且也实现了一些自动化工具,包括刚才提到过的统一服务管理中心,统一配置中心,项目管理系统、SOA服务框架等,贯穿了应用开发、测试、运维整个生命周期的一体化平台,其中的红色部分,包括服务管理、编译中心、商业云平台都是为BizCloud而新开发的模块;第三层SaaS主要是一些商业平台业务系统。本文的分享也主要集中在PaaS层的研发实践上。

关键功能解析

对于一个服务而言,不管是部署还是故障迁移,都有很重要的两个功能:在服务启动之前,要申请服务所需资源的权限,如数据库权限,开通iptables等,也就是服务授权;而服务启动之后,要暴露服务给使用方,现在服务部署到某个机器上了,需要将请求发送到这台机器上,这个过程是服务发现。以往这两个工作主要是人工执行,在BizCloud中,这两个过程需要自动化执行。

自动化执行这个过程需要解决3个问题:1) when,什么时候执行;2)who,谁来执行;3)how,怎么执行。为实现服务版本的平滑过渡,BizCloud也提供了灰度发布功能,以降低上线风险;灰度发布不是一个独立的系统,但和系统的架构是紧密相连的。下面我们分别介绍服务发现,服务授权和灰度发布的实现要点。

服务发现

首先是when,即服务发现和服务授权的发起时间,我们知道在Kubernetes服务里,服务状态的变化和Pod的变化是紧密相连的,因此,我们引入了一个模块k8s-monitor,用来监控并判断发起动作。

k8s-monitor是BizCloud的监控器,其主要功能是监控Kubernetes集群中的Pods的状态事件:ADD、MODIFY、DELETE,监控到事件后,k8s-monitor计算是否需要进行服务发现或服务授权等相关处理,如果需要,则通知下游系统进行处理。除了常规的事件监控之外,k8s-monitor还会定期与服务管理模块同步数据,清理服务管理模块上可能存在的脏数据。

使用k8s-monitor这样一个单独的模块,好处是显而易见的:将相关权限集中管理起来,避免云平台入侵应用,如果没有这样一个模块,每个应用都需要增加自己的的服务授权和服务发现的功能,对模块入侵较大;其次,这个模块非常容易扩展,其他服务也可以订阅这个模块的数据,实现自己的处理逻辑。

通常一个典型的服务都有两层:一个用户接入层,通常是用Nginx接入用户流量,Nginx将流量分发到后面的Web服务器上;第二层SOA层,这里Web服务通过SOA调用后端服务,后端服务也可继续调用其他服务,最终将用户请求返回。在做服务发现时,需要完成这两种类型的服务发现。

首先,对于接入层,如图所示,如果Pod1因故障挂掉,Kubernetes重新调度了PodN之后,k8s-monitor监控到(至少)2个事件:Pod1 DEL,PodN ADD,k8s-monitor将事件通知到服务管理中心。Nginx会实时从服务管理中心获取服务对应关系,动态加载Nginx配置,将已经挂掉的Pod1从Nginx中摘除,新增加的PodN暴露给外部。

而SOA服务的角色分为两种,一种是consumer,一种是provider。consumer和provider之间的负载均衡、白名单控制是通过SOA的注册中心来统一管理。像图里展示的,如果Pod1因故障挂掉,Kubernetes重新调度了PodN之后,k8s-monitor将监控到的事件Pod1 DEL,PodN ADD通知到SOA注册中心,SOA注册中心会将对应的变化更新到ZK上,ZK会触发事件通知服务的consumer获取最新的服务provider。

授权

由于商业平台的特殊性,对权限控制非常严格,权限控制的重要性在于:1)防止测试流量打到线上; 2)防止恶意访问等。以前模式往往是人工检验进行授权,但在云平台上,这种方式不再适用,Kubernetes也没有直接提供授权的功能,而且授权是和系统架构紧密相关的。

为满足BizCloud的需求,对服务授权进行了改造,当时改造面临了一些挑战:首先服务依赖关系从何获取;其次,容器可能随时启动、销毁,服务IP会随容器变动;再次,我们需要同时支持DB授权、IP白名单授权、SOA等不同粒度的授权。

服务授权的发起仍然依赖于k8s-monitor,与服务发现类似,k8s-monitor将监控到的事件Pod1 DEL,PodN ADD,包括一些其他服务基本信息、IP等通知到授权模块,授权模块开始执行授权工作。

刚才说明了授权的时间,但具体给谁来授权呢?如下图所示,每一个服务都有自己的服务配置信息,这里展示一个服务,该服务依赖了很多资源,包Redis、数据库(1个主库、2个从库)等资源。将这些配置文件上传到配置中心后,配置中心会将这些配置解析,然后根据这些依赖关系计算出依赖图,如右图所示。新启动的服务可以从配置中心获取自己的资源依赖关系,要申请的资源。

对于不同类型的授权,我们有不同的处理方式,每种授权对应的粒度也不同:1)DB授权,授权信息包括ip+port+user,通过数据库执行机来执行,将授权信息写入数据库权限表;2)SOA授权,这里授权信息包括服务实例+ip+port,该类授权通过SOA注册中心执行,最终生成服务访问白名单;3)iptable授权,授权信息包括ip+port,这类授权通过salt-stack执行,最终会写入系统的iptables文件。

灰度发布

我们的灰度发布的周期一般比较长,为了保证灰度的一致性,我们会将上下游依赖的服务分组,一个正常组,一个灰度组。在具体执行时,我们会多建一个灰度的Deployment,这样每个服务有2组Deployment,一个正常Deployment、一个灰度Deployment,然后根据灰度比例动态调节正常Deployment和灰度Deployment的实例数,从而实现灰度发布。在流量接入方面,我们已经实现了基于用户ID的灰度,在BizCloud上,我们的灰度分流仍然基于用户ID。

灰度发布时的服务发现同样包括接入层和SOA层两部分:对于接入层,我们使用了OpenResty,并引入了ngx_dynamic_upstream模块,这样可以通过HTTP API方式动态调整服务的Upstream;在SOA层的灰度发布中,我们对consumer-provider划分为了可以动态更新的两个组:正常组和灰度组,k8s-monitor将变更发送到SOA注册中心后,SOA注册中心还是通过ZK通知Consumer取最新的provider分组,从而实现灰度分流。

配套工具

为了更方便地使用BizCloud,我们提供了多个配套工具。

WebShell

首先是WebShell。通过WebShell,我们可以从Web浏览器以类似SSH的方式登录并操作Docker容器,方便开发运维等查看、调试系统。

9.png

Webshell主要有3个组件:1)Web浏览器负责界面呈现;2)Docker Controller是Docker容器应用的控制中心,作为桥梁,负责消息的转发;3)Docker Daemon提供HTTP API接口给外部系统调用以访问容器内部。

Web浏览器运行JS脚本,通过Web Socket与Docker Controller建立通信链路。Docker Controller通过Docker HTTP API与Docker Daemon建立通信链路。这里使用到Docker HTTP API的接口,利用返回的数据流承载Docker Controller和Docker Daemon之间的交互数据。链路建立后,用户就可以在Web浏览器输入字符与Docker容器交互。

模板生成

我们还提供了模块自动生成的功能,这样开发只需要关注自己的服务即可,不需要重复编写发布等一系列Kubernetes部署文件。对于一个服务,服务部署模板是提供了一类模板的集合,包括Deployment、Namespace、ConfigMaps,这些模板都是可参数化的。在具体部署服务时,也就是实例化一个服务,我们先查找服务实例的部署环境具体的部署参数,然后将这些参数注入到模板中,生成具体的模板文件,然后发布。

相关系统

云平台其他模块在这里做了一个简单的展示,在左上角展示了一个应用正在运行的容器,并可以点击控制台登录到容器内部;右上角是统一配置中心,可以查看、操作引用对应的配置;左下角是统一服务管理平台,上面罗列了现在线上存在的一些服务信息;右下角是统一部署中心,在上面可以查看服务部署的情况,包括服务授权信息、服务发现信息等等。

小结

在本次分享中,我们对搜狗商业平台部的私有云BizCloud的来龙去脉做了一个简要介绍,然后介绍了在实现商业云平台中的关键机制,包括授权、服务发现、灰度发布的实现,也介绍了一些相关配套工具如WebShell等。使用BizCloud后, 对于dev而言流程基本不变,QA在搭建测试环境时,能一键部署相关服务,方便了很多,但对ops,在BizCloud上配置好应用的资源需求后,即可部署系统,一键实现服务扩缩容(包括横向扩展,增加或减少服务实例数,也可以横向扩展,增加服务的CPU和内存数),自动进行服务发现和授权,避免了大量重复性手工操作。

目前我们正在进行一些有状态服务的容器化工作,如Redis、MySQL的容器化。因为我们对数据的准确性和稳定性要求非常高,所以将数据库的容器化是非常谨慎的,我们希望随着容器技术不断发展,在未来也能顺利实现基础资源的容器化。更智能的调度:我们希望能实现一个资源负载可预测的调度算法,能结合应用的CPU、内存、磁盘、网络IO、DISKIO、DBIO等历史数据指标进行综合计算,给出多维度下的基于时间片、优先级的准确实时的负载预测,来执行更智能的调度。

以上内容根据2017年09月26日晚DockOne社区微信群分享内容整理。 分享人刘林,搜狗高级工程师,毕业于中国人民大学,有多年的后台服务开发经验,现供职于搜狗商业平台研发部,负责私有云的研发工作。DockOne每周都会组织定向的技术分享,欢迎感兴趣的同学加微信:liyingjiesa,进群参与,您有想听的话题或者想分享的话题都可以给我们留言。

 

来源: https://www.kubernetes.org.cn/2831.html

Kubernetes存储机制的实现

由于容器的使用寿命短,当迁移的应用程序从开发到生产环境时候,开发人员面临着巨大的挑战。当容器挂掉或崩溃时,任何与之相关的数据都会丢失。为了解决这个问题引发的数据丢失,我们需要将数据存储持久化磁盘(PD),也可以称为卷。数据可以通过容器中断事件被写入一个容器外的持久化磁盘。当与POD一起工作时,持久卷呈现出一个重要的优点——在一个通用应用程序堆栈和POD中存在的数据可以被多个容器共享。

在讨论实现持久化存储的不同方式之前,重要的是要了解持久卷的特性。第一个特征是持久化卷的容量。使用持久化卷时候要指定它的容量。截至发稿,容量是唯一一个可以被设置的属性,但是有规划使其他属性如IOPS和吞吐量可以被制定/设置。持久化卷的第二个特性是访问模式。不同类型的持久化存储解决方案有不同的访问方式。访问模式readwriteonce,readonlymany,和readwritemany。

在第一种访问模式中,仅支持单一节点对卷进行读写操作。在第二种访问模式中,支持多个节点读操作和单一节点写操作。在第三种访问模式中,支持多个节点同时进行读写操作。当使用命令行接口时,访问模式是相同的。然而,必须要注意的一个关键点就是:即使一个卷支持多种访问模式但是在同一时间只能使用其中一种。供应商提供的完整版放完模式列表可以从Kubernetes的如下地址获取:https://kubernetes.io/docs/user-guide/persistent-volumes/

Kubernetes对持久化卷的支持比原生的Docker更好。在Kubernetes,卷与PODS是绑定的,他们生命周期的起止也是一致的。PODS的优势在于支持多个不同类型的卷同时关联。在下面文章中,将讨论可以被关联到PODS的卷类型。

临时磁盘是一种非常简洁方法来实现在容器崩溃时候进行持久化操作。临时磁盘使用空目录的磁盘实现。在使用内存中运行node来实现以提高性能这种场景下,存储可以使用临时磁盘来实现。需要着重提醒的是,虽然临时磁盘提供了数据持久化功能,但是当PODs被移除时候仍然会发生数据丢失。还应该注意的是重启时候任何内存中的数据将会丢失。临时存储对于存储被发送其他容器临时进程数据的一个合理解决方案。实施临时磁盘是通过指定一个YAML文件完成。一个YAML文件举例如下。

apiVersion:  v1

kind:     Pod

metadata:

name:   test-gcespec:

containers:

-     image:  nginx:latest

ports:

-     containerPort:   80

name:   test-gce

volumeMounts:

-   mountPath: /usr/share/nginx/html

name:   gce-pd

volumes:

-     name:   gce-pd

gcePersistentDisk:

pdName:     mysite-volume-1

fsType:  ext4

指定一个YAML文件后,需要使用创建和执行命令去确保临时卷的创建。

在上一节中,我们讨论了临时磁盘如何用于临时进程数据。在下一节中,我们将讨论持久存储的解决方案。

云基础设施的使用已成为既定的商业惯例。Kubernetes 原生支持GCE持久化卷和AWS的弹性块存储,分别由谷歌和亚马逊提供的解决方案。我们将展示如何使用GCE持久卷然后移动到AWS的弹性块存储。

第一步是登录到您的GCE控制台。登录后,点击计算然后点击磁盘,然后创建一个磁盘。

20170321161832

然后将提示提供磁盘参数,如磁盘名称、磁盘说明、区域(请注意该区域应与群集节点所在的区域相同)、磁盘类型、大小、磁盘映像类型(这相当于您想要使用的操作系统)和加密。提供参数并点击创建。

20170321161846

GCE在持久化的优势在于可以挂载到多个节点,但它只能用于读模式。为了进一步展示GCE的使用,让我们创建一个POD。保存如下所示内容到一个YAML文件。

apiVersion:  v1

kind:     Pod

metadata:

name:   test-gcespec:

containers:

-     image:  nginx:latest

ports:

-     containerPort:   80

name:   test-gce

volumeMounts:

-   mountPath: /usr/share/nginx/html

name:   gce-pd

volumes:

-     name:   gce-pd

gcePersistentDisk:

pdName:     mysite-volume-1

fsType:  ext4

AWS的弹性块存储采用的是类似于GCE。然而,在某一个时期,弹性块存储一个卷只能挂载到一个实例。

其他两个持久性存储解决方案,可以用于网络文件共享(NFS)和gitrepo。

在本篇文章中,我们注意到开发人员使用持久存储的重要性,它可以避免在容器挂掉或者崩溃数据丢失。我们讨论了持久化卷的特点。我们还讨论了如何使用临时磁盘,GCE和弹性块存储的可用云解决方案。最后,我们谈到了NFS和gitrepo两等解决方案,可用于实现持久存储。

原文链接:https://www.eduonix.com/blog/software-development/learn-storage-implemented-kubernetes/

作者:Sabeer Shaikh

译者:张将

使用Kubernetes-Jenkins实现CI/CD

Author: Ramit Surana DevOps Zone
DevOps Zone让你成为Sonatype Nexus的合作伙伴,Nexus套件能帮助你扩展DevOps交付过程,持续的将组件智能的集成到开发工具中,包括:Eclipse, IntelliJ, Jenkins, Bamboo, SonarQube等等,请看演示

关于持续集成和持续发布,Martin Fowler给出了最好的定义:

“持续集成是一种软件开发实践,团队成员可以频繁的集成他们的工作,通常每个人一天至少一次集成甚至多次集成。每次集成都通过自动化构建和测试进行验证,以尽快检测集成错误。许多团队发现,这种方法可以显著减少集成的问题,并允许团队更加快速的开发。”

简介

本文将讨论和探索两个令人惊奇和相当有趣的技术。一个是Jenkins,一个流行的持续集成/发布的工具,另一个是Kubernetes,一个流行的容器编排引擎。另外一个惊喜,我们发现了Fabric8——一个酷炫的微服务平台。现在,让我们开始吧!

警告:在下文的几个步骤中,你的服务器可能会中途挂起几次,请选择配置高的PC。

方法论

有很多方法,可以让我们实现CI/CD,在本文中,我们重点介绍Kubneretes-Jenkins插件和Fabric8。

总体架构

在开始我们的工作之前,让我们花一点时间分析开始使用Jenkins使用Kubernetes容器所需的工作流。Kubernetes对于开发者来说是一个惊人的开源容器编排引擎。Kubernetes是由Google发起的,这使Kubernetes在使用多个开源容器项目方面有一个惊人的优势。默认情况下,Docker更受Kubernetes的使用者支持和青睐。使用Docker容器的工作流程如下图所示:

20170320212433

与使用rkt容器(rktnetes)类似,如下图:

20170320212443

目前,Jenkins还没有支持RKT容器的插件,但我认为工作流在其实现后也将保持不变。

Kubernetes-Jenkins插件

在你的主机上安装Kubernetes

在主机上安装Kubernetes是一个容易的任务。如果你想在本地机器上试用它,我建议你试试Minikube,这里有快速安装指南:

  1. 确认你的kubectl已经安装完成,参考文档
  2. 确认已经下载完依赖的组件,参考先决条件
  3. 下载、安装Minikube

Carlossg在使用Jenkins和Kubernetes的方面做了惊人的工作,他为Jenkins创建了一个特棒Kubernetes插件,使用这个插件,你可以很容易地直接使用Kubernetes。此外,还为用户提供了更容易的配置选项,他已经构建了一个包含Kubernetes插件的Jenkins镜像,镜像可以在Docker Hub上找到。在接下来的步骤中,我们将从Docker Hub上获取此镜像,并创建一个卷/var/jenkins/_home用于存储Jenkins的数据。

存在一个问题

虽然我们正在做我们计划做的一切,我们仍然会遇到一个问题。 你会注意到,每当你要关闭它后,重新启动你的Jenkins容器,所有的数据都会丢失。 无论你做了什么,例如创建作业,安装插件等等,都会丢失。 这是容器的常见问题之一。 让我们更深入地讨论它。

关于数据容器的一个词

当谈到容器时,数据是一个棘手的概念。在所有时间保证数据安全、可用性方面容器并不是一个很好的例子。过去发生了许多事件,其中已经看到容器会丢失数据。有很多种办法能解决这个问题,其中之一是使用Docker卷,我没有发现使用持久卷的好处。另一个办法是创建“数据容器”,并将其用作存储数据的源,而不是仅仅依赖一个镜像。
下图简单说明了我们使用“数据容器”来确保我们数据可用性的方法:

20170320212452

接下了的步骤是启动Jenkins Kubernetes容器:

// Running jenkins using another container containing data
 $ docker run --volumes-from jenkins-k8s -p 8080:8080 -p 50000:50000 \
 -v /var/jenkins_home csanchez/jenkins-kubernetes

// Created a container for containing jenkins data with
 // the image name csanchez/jenkins-kubernetes
 $ docker create --name jenkins-k8s csanchez/jenkins-kubernetes

打开浏览器输入http://localhost:8080,你会看到如下界面:

20170320212459

Jenkins的Kubernetes插件设置

现在,Jenkins已经预先配置好了Kubernetes插件,所以我们直接跳到下一步。使用Jenkins GUI,使用Manage Jenkins > Configure System > Cloud > Add a new Cloud > Kubernetes。界面如下图中的几个步骤:

20170320212509

接下来按照下图的设置进行配置:

20170320212516

如果你想使用Jenkins slave,可以在Docker hub上下载jnlp-slave镜像。它提供了简单安装Slave节点的模板。你可以通过创建模板来配置一个Slave节点,如下图所示:

20170320212524

为了让Jenkins slave能参与任务调度,当在Jenkins上创建一个任务的时候,向下图所示设置你的任务:

20170320212532

现在只需把Kubernetes Pod模板中的标签的名称放在restrict部分,保存并应用新的设置。当构建此Job时,会看到Slave上运行这个Job。
一切准备就绪了!你现在可以根据需要添加更多的插件。

Fabric8

Fabric8是一个基于Docker,Kubernetes和Jenkins的开源微服务平台。 它是由Red Hat创建的。 该项目的目的是通过持续交流水线轻松创建,构建,测试和部署微服务,然后使用持续改进和ChatOps运行和管理它们。
Fabric8会自动安装并配置一下内容:

  • Jenkins
  • Gogs
  • Fabric8 registry
  • Nexus
  • SonarQube

下图是Fabric8的架构图:

20170320212843

为了开始我们的演示,你需要使用命令行工具安装Fabric8(gofabric8)。下载gofabric8,解压之后运行命令:

$ sudo cp /usr/local/bin/ gofabric8

在终端上检查$ gofabric8命令是否安装成功:

$ gofabric8 deploy -y

运行命令后,终端上会显示:

20170320212850

创建秘钥:

$ gofabric8 secrets -y

终端返回:

20170320212900

使用kubectl查看pod运行状态:

20170320212907

你可以使用Kubernetes Dashboard提供的页面查看所有Pod的状态,打开浏览器,输入:http://192.168.99.100:30000:

20170320212915

相似的,可以打开Fabric8的页面:

20170320212922

我们来分析一下上面的命令的执行过程,可以通过一个工作流图展示:

20170320212929

实现CI/CD

说起来容易做起来难。从源头构建Jenkins并整合Kubernetes实现持续集成(CI)仅仅是故事的一部分,但是实现持续发布(CD)时另外一个非常不同而且更加复杂的故事了。
这里有一些关于使用Jenkins插件的技巧,他们能帮你更加容易地实现Jenkins的持续交付。

Pipeline Plugin

Pipeline是由Jenkins社区构建的核心插件。此插件确保任何编排引擎与你的环境集成,而且复杂性很低。目前,我相信这仅仅是个开始,因为不同的社区已经为这种引擎构建不同的插件,这些插件都围绕Jenkins UI展开。使用Pipeline插件,用户可以在Jenkinsfile中实现他们项目的整个构建/测试/部署的流水线,并将这个文件跟代码存储在一起,作为代码的一部分放进代码控制中。

GitHub Plugin

这些天,大多数工作都使用GitHub作为源代码管理(SCM)工具。我建议你使用GitHub插件,它可以帮助你的Jenkins从GitHub拉取代码,并分析和测试。为了实现鉴权访问,我建议你看看GitHub OAuth插件。

Docker Plugin

对于Docker来说,这是最适合的插件之一,帮助你做几乎一切与Docker有关的事情。 这个插件还能帮助你使用Docker容器作为Jenkins Slave节点。还有几个其他的Docker插件,根据时间和你的用法,可以在它们之间切换。

AWS Plugin

AWS人员推出了一个名为AWS Pipeline的超棒的服务。 此特定服务可帮助您使用AWS实现持续交付。 目前,这个插件正在大量开发,可能不适合生产环境。 另外,可以查看AWS CodeCommit关注进度。

OpenStack

对于OpenStack用户,OpenStack插件适合使用OpenStack的环境配置。

Google Cloud Platform

可以在Google Cloud Platform上提供了部署管理器,使用部署管理器,你可以创建灵活的声明性模板,这些模板可以部署各种云平台,例如Google Cloud Storage, Google Compute Engine和Google Cloud SQL。部署管理器还可以将资源的使用定义存储在发布模板中。这是一个非常新的插件,但是我认为他是一个值得尝试好工具,如果你希望实现自动化和Google的云服务。

 

来源: https://www.kubernetes.org.cn/1791.html

Kubernetes集群中的网络

本文从一个服务的不同访问方式入手,分析了Kubernetes集群中的网络组成,也给出了一个简单可行的网络性能评估方案。

本文适合对虚拟网桥、iptables以及Kubernetes的相关概念有了解的读者。

另外Service-Pod流量转发时提到”iptables转发”,严格说措辞不准确,因为iptables仅负责用数据库维护了Kernel中Netfilter的hook,这样表述是为了便于理解。

另外,本文也希望为以下几个问题找出明确的答案:

  • Service-Pod之间转发流量时,kube-proxy是否承担流量转发?kube-proxy的转发机制是怎么样的?
  • Service-Pod之间(Service对应多个Pod时)的负载均衡的实现原理是怎么样的?是用kube-proxy来做负载均衡吗?

Kubernetes网络组成分析

从不同访问方式的数据流上看,一个Kubernetes集群的网络可以划分为2部分:

  • Kubernetes网络模型实现:如Overlay Network(第三方实现中有Flannel,Contiv等)
  • 集群IP(Cluster IP),用以集群内服务发现,DNS解析等

本节中的试验集群使用Flannel搭建Overlay Network,其他的解决方案没有本质区别。

为了说明Kubernetes集群网络,下面来部署一个Nginx服务,同时部署了2个Pod:

$ kubectl create -f https://raw.githubusercontent.com/yangyuqian/k8s-the-hard-way/master/assets/nginx.yaml

deployment "nginx-deployment" created
service "nginx-service" created

可以直接在主机上用Pod的IP来访问对应的Pod:

$ kubectl get pod --selector="app=nginx" -o jsonpath='{ .items[*].status.podIP }'

172.30.40.3 172.30.98.4

$ curl 172.30.40.3:80
...

$ curl 172.30.98.4:80
...

注意:下面“在集群内”的命令都需要attach到一个Pod里面才可以执行。

也可以在集群内,使用Cluster IP来访问服务:

$ kubectl get services
NAME            CLUSTER-IP       EXTERNAL-IP   PORT(S)                               AGE
kubernetes      10.254.0.1       <none>        443/TCP                               1d
nginx-service   10.254.126.60    <none>        8000/TCP                              9m

$ kubectl run --rm -it curl --image="docker.io/appropriate/curl" sh

$ curl 10.254.126.60:8000
...

如果部署了DNS服务,那么还可以通过集群内的域名来访问对应的服务:

$ curl nginx-service:8000
...

图1 上面例子的网络图解(采用Flannel来搭建Overlay Network)

 

20170312111354

 

总结

Service到Pod的流量完全在本机网络中完成,简单而不失高效。

kube-proxy并不承担实际的流量转发工作,实际上,它会从kube-apiserver动态拉取最新的应用与服务状态信息,并更新本机上的iptable规则. 即使把kube-proxy停掉,已经生成的规则还是可用的。

Service对多个Pod进行流量转发时,采用iptable规则来进行负载均衡,上面的例子中,iptable会在两个Pod中进行分别50%概率的流量转发。

性能评估

集群拓扑结构:

测试集群采用Digital Ocean上2台VPS,用Flannel搭建Overlay Network,使用vxlan backend, 默认mtu配置。

这里旨在提供一种网络性能的评估方案,评估结果只能说明当前实验环境下的Flannel网络性能。

 

20170312111406

分别对下面3种网络访问方式,使用qperf做TCP和UDP的带宽和延迟测试:

  1. 节点之间
  2. Pod-Pod之间
  3. Pod-Service-Pod

实验 1 节点之间

Node 1上启动qperf server:

$ qperf

Node 2上测试直接访问性能:

$ qperf -v ${node1_ip} tcp_bw tcp_lat udp_bw udp_lat conf

tcp_bw:
bw              =   331 MB/sec
msg_rate        =  5.05 K/sec
send_cost       =   451 ms/GB
recv_cost       =  2.05 sec/GB
send_cpus_used  =    15 % cpus
recv_cpus_used  =    68 % cpus
tcp_lat:
latency        =   125 us
msg_rate       =  7.99 K/sec
loc_cpus_used  =    14 % cpus
rem_cpus_used  =    14 % cpus
udp_bw:
send_bw         =  2.43 GB/sec
recv_bw         =   132 MB/sec
msg_rate        =  4.03 K/sec
send_cost       =   302 ms/GB
recv_cost       =  4.05 sec/GB
send_cpus_used  =  73.5 % cpus
recv_cpus_used  =  53.5 % cpus
udp_lat:
latency        =   113 us
msg_rate       =  8.84 K/sec
loc_cpus_used  =    11 % cpus
rem_cpus_used  =     9 % cpus
conf:
loc_node   =  kube-minion-2
loc_cpu    =  Intel Xeon E5-2650L v3 @ 1.80GHz
loc_os     =  Linux 3.10.0-514.6.1.el7.x86_64
loc_qperf  =  0.4.9
rem_node   =  kube-minion-1
rem_cpu    =  Intel Xeon E5-2650L v3 @ 1.80GHz
rem_os     =  Linux 3.10.0-514.6.1.el7.x86_64
rem_qperf  =  0.4.9

实验 2 Pod-Pod之间

部署qperf-server:

$ kubectl create -f https://raw.githubusercontent.com/yangyuqian/k8s-the-hard-way/master/assets/qperf-server.yaml

测试Pod-Pod之间网络:

$ podip=`kubectl get pod --selector="k8s-app=qperf-server" -o jsonpath='{ .items[0].status.podIP }'`
$ kubectl run qperf-client -it --rm --image="arjanschaaf/centos-qperf" -- -v $podip -lp 4000 -ip 4001  tcp_bw tcp_lat udp_bw udp_lat conf

bw              =    170 MB/sec
    msg_rate        =   2.59 K/sec
    port            =  4,001
    send_cost       =   3.07 sec/GB
    recv_cost       =   3.27 sec/GB
    send_cpus_used  =     52 % cpus
    recv_cpus_used  =   55.5 % cpus
tcp_lat:
    latency        =    154 us
    msg_rate       =    6.5 K/sec
    port           =  4,001
    loc_cpus_used  =     16 % cpus
    rem_cpus_used  =     17 % cpus
udp_bw:
    send_bw         =   2.93 GB/sec
    recv_bw         =   42.9 MB/sec
    msg_rate        =   1.31 K/sec
    port            =  4,001
    send_cost       =    341 ms/GB
    recv_cost       =   17.1 sec/GB
    send_cpus_used  =    100 % cpus
    recv_cpus_used  =   73.5 % cpus
udp_lat:
    latency        =    170 us
    msg_rate       =   5.87 K/sec
    port           =  4,001
    loc_cpus_used  =     17 % cpus
    rem_cpus_used  =   22.5 % cpus
conf:
    loc_node   =  qperf-client-2392635233-sbwff
    loc_cpu    =  Intel Xeon E5-2650L v3 @ 1.80GHz
    loc_os     =  Linux 3.10.0-514.6.1.el7.x86_64
    loc_qperf  =  0.4.9
    rem_node   =  qperf-server-rmjd8
    rem_cpu    =  Intel Xeon E5-2650L v3 @ 1.80GHz
    rem_os     =  Linux 3.10.0-514.6.1.el7.x86_64
    rem_qperf  =  0.4.9

实验 3 Service-Pod之间

部署qperf-server:

$ kubectl create -f https://raw.githubusercontent.com/yangyuqian/k8s-the-hard-way/master/assets/qperf-server.yaml

测试Pod – Service – Pod网络:

$ kubectl run qperf-client -it --rm --image="arjanschaaf/centos-qperf" -- -v qperf-server -lp 4000 -ip 4001  tcp_bw tcp_lat udp_bw udp_lat conf

tcp_bw:
bw              =    217 MB/sec
msg_rate        =   3.31 K/sec
port            =  4,001
send_cost       =   1.38 sec/GB
recv_cost       =   3.11 sec/GB
send_cpus_used  =     30 % cpus
recv_cpus_used  =   67.5 % cpus
tcp_lat:
latency        =    157 us
msg_rate       =   6.38 K/sec
port           =  4,001
loc_cpus_used  =     15 % cpus
rem_cpus_used  =   14.5 % cpus
udp_bw:
send_bw         =   1.28 GB/sec
recv_bw         =   7.83 MB/sec
msg_rate        =    239 /sec
port            =  4,001
send_cost       =    693 ms/GB
recv_cost       =   69.6 sec/GB
send_cpus_used  =     89 % cpus
recv_cpus_used  =   54.5 % cpus
udp_lat:
latency        =    140 us
msg_rate       =   7.12 K/sec
port           =  4,001
loc_cpus_used  =   17.5 % cpus
rem_cpus_used  =     11 % cpus
conf:
loc_node   =  qperf-client-3660233240-w0nq9
loc_cpu    =  Intel Xeon E5-2650L v3 @ 1.80GHz
loc_os     =  Linux 3.10.0-514.6.1.el7.x86_64
loc_qperf  =  0.4.9
rem_node   =  qperf-server-rmjd8
rem_cpu    =  Intel Xeon E5-2650L v3 @ 1.80GHz
rem_os     =  Linux 3.10.0-514.6.1.el7.x86_64
rem_qperf  =  0.4.9

评估结论

使用Flannel vxlan backend前提下,采用默认mtu配置,Overlay Network的转发延迟在微妙量级,带宽有一定影响(减半)。

来源: https://www.kubernetes.org.cn/1712.html

swarm与kubernetes的对比

前言:docker swarm 与kubernetes都是集群管理工具,一个是docker原生自带,一个是谷歌项目下的容器编排工具,那么到底他们到底有什么有缺点呢?

kubernetes:

kubernetes,是Google多年大规模容器管理技术的开源版本,是众多厂商推崇的docker管理优秀之作,随着越来越多的厂商不停地贡献代码,kubernetes功能也愈发完善

swarm:

Swarm是Docker公司在2014年12月初发布的一套用来管理Docker集群的较为简单的工具,由于Swarm使用标准的Docker API接口作为其前端访问入口,所以各种形式的Docker Client(dockerclient in go, docker_py, docker等)都可以直接与Swarm通信。随着Swarm0.2发布,swarm增加了新的策略来调度集群中的容器方式,使得在可用的节点上传播它们,以及支持更多的Docker命令以及集群驱动。

swarm结构图

示例

那么到底是docker亲儿子swarm管理上更胜一筹还是Google的kubernetes管理更加受人们青睐,下面是本人总结的对比详情。

swarm与kubernetes

swarm优点:

1 架构简单,部署运维成本较低

docker swarm 集群模式由于原生态集成到docker-engine中,所以首先学习成本低,对于使用docker-engine 1.12版本及以上可以平滑过渡,service服务可以满足动态增减容器个数,同时具备自身的负载均衡,swarm管理者多台设定保证了机器在出错后有一个良好的容灾机制

2 启动速度快

swarm集群只会有两层交互,容器启动是毫秒级

swarm劣势:

1 无法提供更精细的管理

swarm API兼容docker API,所以使得swarm无法提供集群的更加精细的管理

2 网络问题

在网络方面,默认docker容器是通过桥接与NAT和主机外网络通信,这样就出现2个问题,一个是因为是NAT,外部主机无法主动访问到容器内(除了端口映射),另外默认桥接IP是一样的,这样会出现不同主机的容器有相同的IP的情况。这样两容器更加不能通信。同时网络性能方面,有人测试经过桥接的网络性能只有主机网络性能的70%。当然以上问题可以通过其他工具解决,比如用 Flannel 或者 OVS网桥

3 容器可靠性

在容器可靠性方面,相较于Kubernetes的Replication Controllers可以监控并维持容器的生命,swarm在启动时刻可以控制容器启动,在启动后,如果容器或者容器主机崩溃,swarm没有机制来保证容器的运行。

kubernetes优点:

1 管理更趋于完善稳定

kubernetes 集群管理更趋于完善稳定,同时pod功能上比swarm的service更加强大

2 健康机制完善

Replication Controllers可以监控并维持容器的生命

3 轻松应对复杂的网络环境

kubernetes默认使用Flannel作为overlay网络。

Flannel是CoreOS 团队针对 Kubernetes 设计的一个覆盖网络(OverlayNetwork)工具,其目的在于帮助每一个使用 Kuberentes 的CoreOS 主机拥有一个完整的子网。

kubernetes劣势:

1 配置、搭建稍显复杂,学习成本高

由于配置复杂,学习成本相对较高,对应运维的成本相对高点

2 启动速度稍逊

kubernetes会有五层交互,启动是秒级,启动速度慢于swarm

通过以上介绍,相信大家应该对docker容器集群管理工具的选择有了一个基本的认识,不管怎么选择,最终我们的目的都是为了减少人为干预,更智能的生产环境运维,所以应该根据实际情况斟酌选择。

 

-----------

下面这里有很多 相关 教程 可以参考 https://www.aliyun.com/jiaocheng/topic_24443.html

例如下面的一个例子

  • docker~swarm搭建docker高可用集群
  • 摘要:回到目录Swarm概念Swarm是Docker公司推出的用来管理docker集群,它将一群Docker宿主机变成一个单一的,虚拟的主机。Swarm使用标准的DockerAPI接口作为其前端访问入口,换言之,各种形式的DockerClient(dockerclientinGo,docker_py,docker等)均可以直接与Swarm通信。Swarm几乎全部用go语言来完成开发,Swarm0.2发布,相比0.1版本,0.2版本增加了一个新的策略来调度集群中的容器,使得在可用的节
  • 回到目录Swarm概念Swarm是Docker公司推出的用来管理docker集群,它将一群Docker宿主机变成一个单一的,虚拟的主机。Swarm使用标准的Docker API接口作为其前端访问入口,换言之,各种形式的Docker Client(docker client in Go, docker_py, docker等)均可以直接与Swarm通信。Swarm几乎全部用go语言来完成开发,Swarm0.2发布,相比0.1版本,0.2版本增加了一个新的策略来调度集群中的容器,使得在可用的节点上传播它们,以及支持更多的Docker命令以及集群驱动。
    Swarm deamon只是一个调度器(Scheduler)加路由器(router),Swarm自己不运行容器,它只是接受docker客户端发送过来的请求,调度适合的节点来运行容器,这意味着,即使Swarm由于某些原因挂掉了,集群中的节点也会照常运行,当Swarm重新恢复运行之后,它会收集重建集群信息.

    Swarm结构图docker~swarm搭建docker高可用集群

    Swarm的基本命令docker node 用来显示集群的节点,默认建立时只有一个节点,当然也就谈不上高可用了,可以使用docker node --help来查看所有node参数

    docker~swarm搭建docker高可用集群

    集群初始化 docker swarm init

    docker~swarm搭建docker高可用集群

    当已经被初始化后,就不能重新执行这个操作了,使用docker node ls 来查看刚建立的集群

    集群中的管理节点和工作节点功能图

    docker~swarm搭建docker高可用集群

    添加管理节点 docker swarm join

    Docker Swarm 命令中还需要添加一些选项:

    * join:表明一个新的节点将被添加进 Swarm

    * –manager:表明节点的性质(manager vs worker)

    * –listen-addr:让一个新添加的节点可以访问 Swarm 内的其他节点

    * 最后的参数就是第一管理节点的地址(即这一命令将被送到的那个节点)

    注意:由于 –auto-accept manager 选项会在 Swarm 初始化的过程中被提供,所以第二管理节点会被自动接受。如果没有这一选项,那么第二管理节点需要被第一管理节点手动接受。

    $ MANAGER2_IP=$(docker-machine ip manager2)docker-machine ssh manager2 docker swarm join --manager --listen-addr $MANAGER2_IP:2377 $MANAGER1_IP:2377

    Swarn部署时使用的脚本,来自网络

    下面是一小段用来创建 Docker 主机并部署 Swarm 的 Shell 脚本。当然了,管理/工作节点的数字都是可以随意改动的。
    注意:创建两个管理节点和两个工作节点,仅仅是用来作示范。在工业生产中,我们可能需要在集群里搭建 3 个管理节点和 5 个工作节点。

    # Define the number of managers/workersMANAGER=3WORKER=5# Create the Docker hostsfor i in $(seq 1 $MANAGER); do docker-machine create --driver virtualbox manager$i; donefor i in $(seq 1 $WORKER); do docker-machine create --driver virtualbox worker$i; done# Init the swarmdocker-machine ssh manager1 docker swarm init --auto-accept manager --auto-accept worker --listen-addr $(docker-machine ip manager1):2377# Add additional manager(s)for i in $(seq 2 $MANAGER); do docker-machine ssh manager$i docker swarm join --manager --listen-addr $(docker-machine ip manager$i):2377 $(docker-machine ip manager1):2377; done# Add workersfor i in $(seq 1 $WORKER); do docker-machine ssh worker$i docker swarm join --listen-addr $(docker-machine ip worker$i):2377 $(docker-machine ip manager1):2377; done对于上面文章中,只提到了集群,而没有谈到如何去使用,在建立集群后,服务的部署我们可以用

    docker stack deploy  -c test.yml test

    来建立一个服务,同时可以使用docker service来查看已经运行的服务!

    回到目录