技术专栏丨支撑多样化数据服务的K8s容器化部署实践

赌博导航网站

技术专栏K K8s集装箱部署实践,支持各种数据服务

需求背景

SDMK(智能数据市场)是TalkingData的数据智能市场。该平台提供各种数据服务,包括API服务,SaaS服务和人工智能算法模型服务,如Lookalike和预测引擎。目的是减少数据应用场景的难度。帮助更多公司发现数据的深层价值。

SDMK数据平台使用微服务架构设计和实现。有近20个APP模块,加上70多个适配器用于第三方数据服务和其他APP模块。 REST API几乎有数十万。一。微服务架构的应用使每个服务都能由专门的开发团队(或个人)开发。开发人员可以自由选择开发技术,每个微服务都可以独立开发,升级和扩展。因此,系统具有高稳定性和快速迭代,但也遇到负载均衡,故障重启,弹性扩展,资源隔离等问题。

因为微服务后面可能有多个副本实例,你如何进行自动负载平衡?当其中一个副本实例关闭时,您是否需要手动重启?当流量增加时,我如何轻松或自动添加节点以满足相应的SLA?面对这些问题和其他问题,Kubernetes(K8s)可以很好地解决,这使其成为企业微服务集装箱化的首选解决方案。

本文将简要介绍K8s的核心概念,重点介绍使用K8s的TalkingData SDMK的容器化部署实践。

e56c299c62b14ed3acbf614c5e7f1691.jpeg

K8s的核心理念

首先,Kubernetes(K8s)是一个用于自动化容器操作的开源平台,包括部署,调度和集群间扩展。如果您曾经使用Docker容器技术来部署容器,您可以将Docker视为Kubernetes内部使用的低级组件。 Kubernetes不仅支持Docker,还支持另一种容器技术Rocket。

使用Kubernetes:

自动化容器部署和复制

随时扩展或缩小容器尺寸

将容器组织成组并在容器之间提供负载平衡

轻松升级新版本的应用程序容器

提供容器灵活性,如果容器出现故障则更换容器.

86cfb42d60184c799445e72883130b12.jpeg

群集有一个K8s Master(上图中的紫色框)。 K8s Master提供了有关群集的独特视角,并具有一系列组件,例如K8s API服务器。 API Server提供可用于与群集交互的REST接口。主节点包括用于创建和复制Pod的复制控制器。

K8s API服务器提供HTTP 目。

K8s Controller Manager是群集中所有资源对象的操作命令中心。

K8s Scheduler是负责调度Pod资源的过程。

Etcd服务,它提供集群中所有资源对象配置的持久性。

节点

作为集群中的工作节点,Node运行实际应用程序。由节点上的K8s管理的最小运行单元是Pod。在节点上运行的K8s Kubelet和kube-proxy服务进程负责软件模式的Pod创建,启动,监视,重启,销毁和负载平衡。节点(上面的橙色框)是物理或虚拟机,作为K8s工作者,通常称为Minion。每个节点都运行以下K8s关键组件:

Kubelet:是主节点代理。

Kube-proxy:服务使用它来链接到Pods。

Docker或Rocket:K8用于创建容器的容器技术。

Pod是K8s最基本的操作单元,包含一个或多个密切相关的容器。可以通过容器化环境将Pod视为应用层的“逻辑主机”; Pod中的多个容器应用程序通常是紧密耦合,Pod在Node上创建,启动或销毁;每个Pod运行一个名为Pause的特殊容器,其他容器是业务容器。这些业务容器共享Pause容器的网络堆栈和卷。卷已加载,因此它们之间的通信和数据交换更有效。我们可以充分利用此功能将一组密切相关的服务流程放入同一个Pod中。

Pod的生命周期由复制控制器管理,由模板定义,然后分配给要运行的节点。在Pod中包含的容器运行之后,Pod结束。 K8s为Pod设计了一个独特的网络配置,包括:为每个Pod分配一个IP地址,使用Pod名称作为容器之间通信的主机名,等等。

RC(复制控制器)

RC是复制控制器,新一代RC称为RS(复制集)。其主要功能如下:

确保Pods:RC的数量用于管理Pod正常运行的数量。 RC可以由一个或多个Pod组成。创建RC后,系统将根据定义的份数创建Pod的数量。在运行过程中,如果Pods的数量小于定义的数量,它将重新启动停止或重新分配Pod,否则它将终止额外的。

确保Pod健康:当Pod不健康,运行不正常或无法提供服务时,RC还会杀死不健康的Pod并重新创建新的Pod。

弹性扩展:在业务高峰期或低峰期,可以通过RC动态调整Pod的数量,以提高资源利用率。同时,配置相应的监控功能(Hroizontal Pod Autoscaler),定期从监控平台自动获取RC相关Pod的整体资源使用情况,实现自动扩容。

滚动升级:滚动升级是一种平滑的升级方法。通过逐步更换策略,整个系统稳定。初始化升级时,可以及时发现并解决问题以避免问题。

标签

标签以键/值的形式附加到各种对象,例如Pod,Service,RC,Node等,以识别这些对象,管理关联等,例如Service和Pod之间的关系。通过此关联,选择器可用于过滤与该Pod关联的服务。

标签选择器

使用标签选择器,用户可以识别一些对象,这些对象是K8的核心分组基元。选择器有两种主要类型:

基于平等

基于集合的要求

部署

部署表示用户对K8群集的更新操作。部署是比RS应用程序模型更广泛的API对象,可以通过创建新服务,更新新服务或滚动服务来实现。卷起一个服务,实际创建一个新的RS,然后逐渐将新RS中的副本数增加到理想状态,将旧RS中的副本数减少到0个复合操作;这种具有RS的复合操作并没有得到很好的描述,因此使用更一般的部署来描述。随着K8s的发展方向,未来所有长期伺服型服务的管理将通过部署进行管理。

服务

RC,RS和Deployment仅保证支持该服务的Pod数量,但它不能解决如何访问这些服务的问题。 Pod只是正在运行的服务的一个实例。它可以随时在一个节点停止,在另一个节点上启动一个带有新IP的新Pod,因此无法提供具有特定IP和端口号的服务。需要服务发现和负载平衡功能来提供稳定的服务。服务发现完成是为客户端访问的服务查找相应的后端服务实例。在K8s集群中,客户端需要访问的服务是Service对象。每个服务对应于群集内的有效虚拟IP,并且通过群集内的虚拟IP访问服务。 K8s集群中的服务负载平衡由Kube-proxy实现。 Kube-proxy是K8s集群内的负载均衡器。它是一个分布式代理服务器,在K8的每个节点上都有一个;这种设计体现了其可扩展性优势。需要访问服务的节点越多,提供负载平衡功能的Kube代理就越多。高可用节点也会增加。

SDMK容器化部署实践

一个

服务曝光实践

上述服务通常仅在集群内有效。在K8s的世界中,服务需要暴露在集群之外。通常有几种方式:

1. Cluseter IP

群集中的私有IP,这是默认值。

2. NodePort服务

它主要通过在集群的每个节点上公开一个端口然后将该端口映射到特定服务来实现。虽然每个节点有很多端口,但由于安全性和易用性(更多服务),它很混乱,很容易产生端口冲突。实际用途并不多。

1e9f602f00fe4b019759454951cd3410.jpeg

3. LoadBalancer服务

它是K8s与云平台深度结合的一个组成部分。使用LoadBalancer服务公开服务时,它实际上通过底层平台创建了一个负载均衡器来公开服务。此方法主要用于云平台。

4.入口服务

Ingress用户可以使用开源反向代理负载平衡器(如nginx)实现外部曝光服务。它由三个组件组成:反向代理负载均衡器,Ingress控制器和Ingress。

反向负载均衡器,只需nginx,apache等,部署也比较自由,可以RC,Deployments,DaemonSet。

Ingress Controller:可以简单地理解为监视器,Ingress Crontroller通过与Kubernetes API的持续交互,后端服务的实时感知,pod变化,如增加或减少pod,增加或减少服务等,当此信息更改时,Ingress Controller将组合上下文,生成配置,然后更新到反向代理负载平衡器,并重新加载配置以实现服务发现。

Ingress:简单地说,这是一个规则定义;例如,哪个域对应于哪个服务,即请求转发哪个域名,以及转发到哪个服务。

7528297bfcfb4b91a1f1661ae055d62f.jpeg

SDMK部署是采用Ingress的方式。在K8s群集中,Ingress是一组规则,用于授权入站连接到达群集服务,提供七层负载平衡功能,通过Ingress配置提供外部可访问的URL,负载平衡,SSL,基于名称的虚拟主机等。

SDMK在部署时主要考虑以下两种部署方法:

分享Ingress

独家Ingress

01

分享Ingress

0f3308bcb0f34a9388b15088c997159a.jpeg

目。但问题是,一旦流量门户出现问题(例如性能问题和可用性问题),就会影响群集中的所有服务。可用性。

02

独家Ingress

2c32123a5e0442e88f93bf9c5b47fa8f.jpeg

例如,在上述部署架构图中,统一接入层由多个入口实例组成,以承载集群入口流量。每个微服务模块独占一个入口,也可以根据后端服务流量级别扩展和缩小入口节点。当然,如果前一个集群的规模不大,您还可以使用将Ingress服务与业务应用程序混合的方法,但建议限制资源和隔离。

e7780c2ad1c045c7a1399daa16adec88.jpeg

作为集群流量门户,Ingress的高可靠性尤为重要。出于这个原因,SDMK采用独有的Ingress并使用nCopy-ingress-controller来部署多个副本并将其与后端服务隔离。这将避免业务应用程序和Ingress服务之间的资源竞争,以及单点问题。

两个

灵活的拉伸练习

cf34aec9d49f4a8d9d8888b68060376d.jpeg

在K8s中,Pod是最基本的调度单元。多个Pod可以形成一个集合,为外部提供服务。目前,有两种情况需要注意:

1.集合中的Pod可能由于某种原因而失败,并且需要一些机制来创建新的Pod以确保正在运行足够数量的Pod。

2. Pod的数量由访问请求确定。也就是说,当当前实例的数量不足以满足访问请求时,需要增加实例的数量。相反,需要通过某种策略减少实例数量。

如果人肉实时监控实例的运行状态,手动启动新Pod以替换故障Pod,监控实例负载,手动创建或删除Pod,这项工作繁琐且工作量大,但是K8已经有了相应的机制。为了应对这种变化,这种机制是弹性扩张。

弹性扩展(Elastic scaling)一种基于资源使用自动扩展工作负载的方法。弹性缩放在K8中有两个维度:Cluster Autoscaler和Horizontal Pod Autoscaler,它们可以一起用于动态调整并行度的计算能力和水平可伸缩性,以满足系统的SLA。 Cluster Autaoscaler依赖于托管集群的云提供商的基础功能,HPA可以独立于Iaas/Paas提供商运营。

dd943bf66ea940c391c97d9d6ea81e5c.jpeg

简而言之,HPA实现了一个控制循环,它可以通过资源指示器API定期查询CPU,MEM和特定应用程序的其他信息。度量服务器负责收集每个应用程序Pod的指标信息,然后由控制器进行计算。从而实现弹性膨胀和收缩。目前的主要指标分为以下三类:

Pod的资源指标,例如cpu,mem等。

自定义:自定义指标信息,例如:入口QPS,在线活动应用程序数量等

外部:群集指标的监控指标,通常由云供应商提供

计算算法:

desiredReplicas=ceil [currentReplicas *(currentMetricValue/desiredMetricValue)]

例如:

currentMetricValue为200m,desiredMetricValue为100m。如果未超过您设置的最大值,则复印份数将加倍。如果超过,则将最大值作为当前目标副本号。如果计算的值为0.5,则它大于该数字的最小整数。

这里要说明的是要注意你使用的K8版本:

HPA功能最初是在K8s v1.1中引入的。第一个版本基于观察到的CPU利用率,后续版本继续发展,支持基于内存的使用。 K8s 1.6中引入了一个新的API Customization Indicator API,允许HPA访问任何指标。聚合层是在K8s1.7中引入的,允许第三方应用程序通过注册为API附加组件来扩展K8s API。自定义指标API和聚合层使Prometheus等监控系统能够向HPA控制器公开特定于应用程序的指标。

练习部分

bcb750643b4c4ab09861d49763bd3904.png

您需要在部署的yaml文件中定义每个APP使用的资源。对于资源限制,需要根据实际业务需求调整大小,并添加相应的探测策略。

Resoureces:用于限制容器的资源使用,主要是CPU和内存资源。

readnessProbe:确定容器和服务是否已准备好接受流量。仅当小方块将状态识别为准备好时才接受交通。这是为了控制哪些pod应该用作服务的后端。如果Pod处于非就绪状态,它们将从服务负载平衡器中删除。

livenessProbe:确定何时重启容器。例如,当应用程序正在运行但无法进一步处理时,活动探测器将捕获死锁,它将在此状态下重新启动容器,如果应用程序有错误,它可以继续运行。

Env:此选项用于设置一些环境变量。这里JAVA_OPTS用于启用CGroup资源感知。对于JDK8及更低版本,需要单独设置,否则应用程序无法感知容器资源限制,但JAVASE8u131和JDK9支持它。感知限制容器资源的能力。你可以参考这个博客:

1apiVersion: autoscaling/v2beta1

2kind: HorizontalPodAutoscaler

3metadata:

4name: dm-sdmk-kafka-service

5namespace: dm

6spec:

7scaleTargetRef:

8apiVersion: extensions/v1beta1

9kind:部署

10name: dm-sdmk-kafka-service

11minReplicas: 3

12maxReplicas: 5

13metrics:

14-型:资源

15resource:

16name: cpu

17targetAverageUtilization: 50

18-型:资源

19resource:

20名:内存

21targetAverageValue: 1536Mi

件,如CPU平均利用率50% 件达到相应的阈值时,Pod将被缩放。根据相应的业务模块类型设置特定设置。 件进行扩展,因为大多数APP应用程序在流量上升时会占用更多内存。

排水练习

1be9550866dd44fbb05464930ccc710d.png

当K8s环境中的SDMK已经在简单状态下部署和测试时,它现在可用。现在,您希望将特定用户的流量引入K8s环境中的SDMK,以便它可以承担特定的流量并到达物理机器环境。 SDMK将SDMK与K8s环境混合,如上图所示。

01

物理机器部署

3d23f433cc1d4b50a5ef632683a5b030.png

如上图所示,物理机上的部署是通过物理机上的nginx进行负载均衡。以下是多台物理计算机上的网关节点。网关是SDMK的网关,用于接收和处理服务呼叫请求。

01

并行部署

84fe5a9b6d5d4db98d91a861d5429176.png

并行部署如上图所示。 K8s环境的门户域名也安装在该位置的nginx方法下,并且流量在nginx处进行区分。哪些用户的流量达到K8s环境,以及哪些用户的流量受到影响。物理机器环境。通过向nginx添加lua脚本来实现SDMK,其部署如下图所示:

faaa575b12554eb19efde77c4f551d7a.png

实施步骤:

在Nginx上添加特定的lua脚本,并通过lua脚本连接redis

Lua脚本在nginx上的每个请求中获取userId

然后,将获得的userId与Redis中配置的用户userId匹配。如果是,则进入K8s环境;如果没有,则输入物理机器环境,从而将流量部分引入K8s环境

并行运行一段时间后,如果K8s环境没有问题,请逐步增加K8s环境的流量。

练习部分

Lua脚本实现脚本:

1local_M={}

2_M。 _VERSION='0.01'

3localfunctiontryExec(PROD,灰色)

4localredis=require'redis’

5localred=redis.connect('172.20.33.5',6379,0.2)

6token=ngx.req.get_headers()['userId']

7iftoken==nilthen

8returnprod

9end

10

11localtemp,userId=token: match('([^,] +) - ([^,] +)')

12localres=red: get(userId)

13ififres然后

14returnprod

15end

16

17ifres==ngx.null然后

18returnprod

19else

20returngray

21end

22end

23

24

25function_M.execByToken(PROD,灰色)

26localok,msg=pcall(tryExec,prod,grey)

27ifok然后

28ngx.exec(MSG)

29else

30ngx.exec(PROD)

31end

32end

33return_M

将配置添加到Nginx:

1location/data {

2套$目标 '';

3台$ $ header_host主机;

4access_by_lua'

5package.path='的/usr /本地/nginx的/CONF/LUA/? LUA'

6local sdmk=require'sdmk'

7ngx.var.target=sdmk.tryExec( 'dmkdataProd', 'dmkdataK8s')

8if ngx.var.target=='dmkdataK8s'然后

9ngx.var.header_host='nginx-dm-talkingdata-datamarket-gateway-k8s.dm.svc.sc.tendcloud.com'

10end

11' ;

12

13proxy_http_version1。 1;

14proxy_set_headerConnection'';

15proxy_set_headerHost $ header_host;

16proxy_set_headerX-Real-IP $ remote_addr;

17proxy_set_headerX-Forwarded-For $ proxy_add_x_forwarded_for;

18proxy_set_headerX-Forwarded-Server $ host;

19 target;

20}

需要注意的是需要将域名引入header_host中的K8s环境。

注意事项

1.优雅的容器封闭问题

容器是否可以正常关闭,接收SIGTERM信号而不是直接查杀,以便应用程序可以有效地处理数据,释放资源等,否则可能发生数据丢失。

2.数据库访问限制

生产环境的数据库具有相应的访问限制。当前的SDMK数据库访问限制是通过授权IP段表单来实现的。

3. Nginx-ingress-Controller的性能问题

无论是使用共享Ingress的方法还是采用独有的Ingress方法,都必须在生产环境之前进行压力测试,看它是否能满足系统的要求。

4.资源限制问题

如果设置了Pod的资源限制,则应用程序是否可以识别容器的资源限制,即是否启用了CGroup资源感知,JAVASE8u131和JDK9支持对容器资源限制的感知。

设置资源限制以满足应用程序的基本需求:如果不满意,它将出现,容器up,kill,kill和kill无限循环。

件。

两者,设置

自定义度量标准:例如,消息队列,等待消息的数量

6.特殊形象新要求

可以运行同事,只提供标准图像,如果有特殊需求,则需要在Dockerfile中进行一些处理。例如:

Springboot2需要Jetty9.4,JDK1.8或更高版本的图像

要生成文档应用程序,您需要安装一个特殊的中文字库

7.建议添加容器探针

活动探针:确定何时重启容器。例如,当应用程序正在运行但无法执行进一步操作时,活动探测器将捕获死锁,它将在此状态下重新启动容器,如果应用程序有错误,则可以继续运行。

准备探针:以确定容器和服务是否准备好接受流量。只有当小盒子的状态被kubelet识别为准备好时才接受流量。这是为了控制哪些pod应该用作服务的后端。如果pod尚未就绪,则将从服务负载均衡器中删除它们。

8. Nginx消耗对K8s环境域名的访问权限

需要将域名带入header_host

并添加DNS解析,因为K8s生成的域名,相应的IP是动态变化的

END

作者:TalkingData Yangshuang Liang Sohu返回看更多