Kubernetes 学习笔记之阿里云游戏业务实战

栏目: 编程工具 · 发布时间: 6年前

内容简介:我们游戏按照业务逻辑划分,服务器可分为三种类型,前端服务器(客户端直接进行连接的)、后端服务器(只负责处理各种游戏逻辑不提供连接)、任务服务器(各种 cron、job 任务),其中前端服务器按照功能划分为 http 短连接服务器和 socket 长连接服务器,后端服务器按照业务划分 例如 matching 匹配服务器。在部署这些服务器的同时,我需要使用 kubernetes 达到的目标有:

Kubernetes 学习笔记之阿里云游戏业务实战

作者介绍:段鹏举,边锋后端开发工程师。

本人一直做业务开发,不曾了解过运维知识,因为要对一个项目的技术部分负责,开发业务的同时还需要思考系统层面的事情,团队人数又少,不得不采用 k8s 这种能达到事半功倍效果的工具。本文是在阿里云 kubernetes 部署游戏业务的实战笔记,不涉及 k8s 原理等深层知识。我学习 k8s 的时间也比较短,如有理解错误的地方,还望海涵。

目标

我们游戏按照业务逻辑划分,服务器可分为三种类型,前端服务器(客户端直接进行连接的)、后端服务器(只负责处理各种游戏逻辑不提供连接)、任务服务器(各种 cron、job 任务),其中前端服务器按照功能划分为 http 短连接服务器和 socket 长连接服务器,后端服务器按照业务划分 例如 matching 匹配服务器。

在部署这些服务器的同时,我需要使用 kubernetes 达到的目标有:

  • 对于每种类型的服务器,需要同时存在若干个版本

  • 对于无状态服务器如 http、cron 可以比较方便的更新、回滚

  • 对于有状态服务器如 socket、matching 可以业务无间断的进行更新、回滚,用户不会掉线、无感知

  • 可以进行灰度发布

  • 当服务器的负载变化时,能够自动伸缩服务器数量

  • 当服务器异常宕机时,能够自我修复

准备 Docker 镜像

  1. 使用阿里云容器镜像服务准备好 docker 远程仓库

  2. 在应用(服务器代码)准备好之后,使用 Docker 构建镜像,并打上版本号,Push 到远程仓库(这一步骤可以通过 Jekins 自动完成,后续实践的时候会更新文档,目前就以手工进行)

部署应用

类似于 web 前端框架中的命令式(jquery)与声明式(react),我对 k8s 有一种理解与之类似:我们只需要通过配置文件“告诉”k8s 我们想要的最终结果就行,中间的过程无须再关心,k8s 会以各种机制保证这一结果

1.因为使用的 Docker 远程仓库是私有仓库,部署应用时就需要添加 imagePullSecrets,首先使用 kubectl 在 default 命名空间里创建 secret,如需指定命名空间添加 -n 参数,后面命令类似

2.根据服务器的特点创建部署 yaml 文件

  • http 无状态应用

创建对应的 service

创建对应的 ingress(路由)对外提供服务

此时已经可以通过域名进行访问了,这就是我们想要的“最终状态”,而具体实现细节以及如何维持这个状态不变,我们无需再关心

为何不直接使用 Service 对外提供服务?

其实我们只需要把 Service 的类型改成 LoadBlancer,阿里云(其他云服务商类似)会给 Service 添加一个监听的 nodePort,再自动创建一个负载均衡,通过 tcp 转发到 Service 的 nodePort 上(这地方阿里云有个 bug 每次更新 Service 它都会把转发类型改成 tcp),可想而知,当我们的 Service 越来越多时,nodePort 的管理成本也就越来越高, k8s 提供了另外一个资源解决这种问题,就是 Ingress

Ingress 工作机制

Ingress 其实就是从 kuberenets 集群外部访问集群的一个入口,将外部的请求根据配置的规则转发到集群内不同的 Service 上,其实就相当于 nginx、haproxy 等负载均衡代理服务器,我们直接使用 Nginx 也可以达到一样的目的,只是 nginx 这种方式当添加、移除 Service 时动态刷新会比较麻烦一点,Ingress 相当于都给你做好了,不需要再次实现一遍,Ingress 默认使用的 Controller 就是 nginx。

Ingress controller 可以理解为一个监听器,通过不断地与 kube-apiserver 打交道,实时的感知后端 service、pod 的变化,当得到这些变化信息后,Ingress controller 再结合 Ingress 的配置,更新反向代理负载均衡器,达到服务发现的作用。

配置 Ingress

可以通过 annotations 注解的方式告诉 Ingress 你的配置,例如:如果你使用的是 Nginx-Ingress-Controller,可以通过 nginx.ingress.kubernetes.io/cors-allow-origin:* 来配置 cors,和配置 Nginx 几乎是一样的,只是名称不一样而已。

所有的 Nginx-Ingress-Controller 的注解可以在这里查询 传送门

可以进入 nginx-Ingress-controller 的 pod 中,添加一些注解,更新,会看到 nginx 重新生成了配置,并“重新启动”,对比注解和 nginx.conf 很快就能理解 Ingress

Ingress 灰度发布

可以通过添加注解 nginx.ingress.kubernetes.io/service-match:'test-svc: header("Version", "1.0.0000")' ,来进行灰度发布,比如匹配 request headersVersion=1.0.0000 的流量转发到 test-svc,可以匹配 header、query、cookie,同时还可以配置权重等,例如修复问题时只把 10%的流量切进来,待问题验证得到解决后再设置 100。

我们每次游戏前端发布版本都会在 header 中添加一个 Version 参数,我设置灰度发布之后就可以把特定前端版本的流量自由的切到某个特定的服务中,比较灵活。

滚动更新

当不需要灰度发布时,仅仅需要对某个 Service 的 pod 进行更新,只需要更改上文 Deployment 中镜像版本即可,当 k8s 检测到 template 字段更改时,会根据设置的 rollingUpdate strategy 策略进行滚动更新,对于 http 这种无状态的服务,也能达到业务不间断更新

  • 长连接 有状态应用

无状态: 该服务运行的实例不会在本地存储需要持久化的数据,并且多个实例对于同一个请求响应的结果是完全一致的

有状态:和上面的概念是对立的了,该服务运行的实例需要在本地存储持久化数据,比如 socket 长连接

Service 和 Ingress 与无状态 http 应用基本一致,参照上文部署即可。全部部署完成后,观察 k8s 后台可以看到,有 name 分别为 connector-prod-v100000-0、connector-prod-v100000-1、connector-prod-v100000-2 的三个 pod 正在运行,后面的 -n 是由于资源类型设置为 StatefulSet k8s 自动加上的以作区分。

在容器中获取 pod 信息

一般来说对于 StatefulSet 我们可能会在容器内知道这个 pod 的 name,这时候就可以采用类似于上面的方法,通过 valueFrom fieldPath:metadata.name 把 pod name 信息注入到容器的环境变量中,这种特殊的语法是 Downward API,帮助我们获取许多 pod 的信息,可参照传送门进行学习

滚动更新

对于 StatefulSet 默认的滚动更新策略是 OnDelete, 也就是当这个 pod 被删除后,k8s 再次创建时会更新镜像。即使我们改变这个策略,那么可以直接对齐进行更新吗?对于大多数 StatefulSet 是不太合适的(比如 pod 上面有用户的长连接 如果直接更新用户会断线 影响体验),或者说对于 StatefulSet 的滚动更新一直都是个很复杂的话题,所以如果要更新,推荐使用 灰度发布

灰度发布的过程与上文 http 一致,对于我们的业务来说,用户的下一次连接会切到指定的版本上

  • matching 后端有状态应用

因为后端服务器不需要外界的访问,所以创建一个 StatefulSet 启动后端微服务就可以,启动后会监听消息队列进行处理并返回数据

RPC 设计

可以看到,我把许多 POD 信息注入到了容器中

  • 环境变量 SERVER_ID 是名称-环境-版本号-序号命名的可以选择某一个服务器;

  • 环境变量 SERVER_TYPE 可以选择某一类型的服务器;

  • 环境变量 VERSION 可以选择某一版本的服务器。

因此就可以通过类似于标签选择的方式发送和接受消息队列,例如:

在代码中获取环境变量

如果想匹配某一个服务器:

如果想匹配某一类型的所有服务器:

在其他应用内发送 rpc(如在 http 应用内调用 matching 应用),按照上面的标签格式发送消息即可:

长连接客户端发送 rpc

和前端同学约定,在 socket 请求中按照 event 字段分为 4 个类型:Push、Notify、Request、Response

Request-Response

客户端主动发起,要求有回应,类似于 http:

Notify-Push

客户端主动发起,不要求回应

在服务器需要回应的地方发送 PUSH 事件

对于处理消息会发送到哪个后端服务器,写一个路由函数发起 rpc 即可

"灰度发布"

同理,有状态后端服务器也不适用滚动更新,因为会丢失业务信息。因为后端服务器外界不可访问,也不能用 Ingress 路由灰度发布的方式来更新,怎么办呢?

其实按照上面的 rpc 设计已经解决了这个问题,例如现在匹配服是 1.0.0000 版本,如果想要发布 1.0.0001 版本,只需要部署一个 matching-v100001 的应用,客户端在配置文件里把 Version 改成 1.0.0001,那么下一次请求就会匹配到 matching-v100001 的应用上,这样可以根据客户端配置随时切换服务器版本号,达到了灰度发布的效果。

  • cron 定时任务

部署之后定时器就开始运行了,非常简单。通过 spec.successfulJobsHistoryLimitspec.failedJobsHistoryLimit ,表示历史限制,是可选的字段。它们指定了可以保留多少完成和失败的 Job,默认没有限制,所有成功和失败的 Job 都会被保留。然而,当运行一个 Cron Job 时,Job 可以很快就堆积很多,所以一般推荐设置这两个字段的值。如果设置限制的值为 0,那么相关类型的 Job 完成后将不会被保留。

更新

直接更改镜像版本号就可以了,下次运行的时候会以新的镜像版本运行

结束

至此,基本的游戏业务框架已经搭建完成,最初的目标都达成了。下一期更新 kubernetes 学习笔记 (四):自动化部署 k8s 实战

扫描下面的二维码(或微信搜索 k8s技术圈 )关注我们的微信公众帐号,在微信公众帐号中回复 加群 即可加入到我们的 kubernetes 讨论群里面共同学习。

Kubernetes 学习笔记之阿里云游戏业务实战


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

CSS

CSS

麦克法兰 / 江苏东南大学 / 2007-6 / 65.00元

《CSS(使用指南)(影印版)》主要内容:层叠样式表(CSS)能让你内心的设计思想迸发出来并得以实现。不过,将CSS与网站底层的HTML页面进行整合是一件非常困难的工作,有时甚至复杂得令人沮丧——这导致多数Web设计者不得不放弃一些奇思妙想。《CSS: The Missing Manual》可以消除Web设计工作的痛苦,并且带给你: HTML——重新入门。如果你是HTML新手,你会学到如何以......一起来看看 《CSS》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

随机密码生成器
随机密码生成器

多种字符组合密码

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具