easy-serverless 功能分析

avatar
前端

总体介绍

easy-serverless 是一个应用部署平台,用于满足不少同事对于部署应用迫切的需求,部署小应用再也不需要:申请服务器、搭建环境、申请网络权限、申请域名等一系列操作,打开 easy-serverless 平台,即可通过几步操作将应用部署到公司内部的 Kubernetes 集群上。目前支持部署前端静态网站,Node 服务,Nginx 服务, Mongodb 及 Redis 数据库, MinIO 对象存储等。

juejin1.png

平台依赖于公司内部的 Kubernetes 集群,每种类型的容器化应用都由自定义的镜像创建,使用了 Kubernetes 的 Javascript 客户端库提供的 API 来执行容器操作。持久化存储采用分布式存储方案 Longhorn 来对存储卷进行管理。

用户分析

服务种类占比

根据文章发布时统计,总运行服务个数有 114 个

可以看出大部分的平台用户选择把个人博客,平台官网等静态前端网站部署在 easy-serverless平台上。

整体架构图

serverless-architecture.png

其中的 token 为集群中创建的 service accounttoken,并分配了访问权限,可通过 kubectl get secret 获取到相应的 token

图中的自定义 namespace 为以用户名称创建的命名空间,用户创建的服务都运行在自己的命名空间里。

背景知识

想要理解 easy-serverless 的工作原理,我们需要先了解一下 DockerKubernetesLonghorn 的知识, 有相关背景知识的同学可以跳过这个章节。

Docker

Docker 的作用和虚拟机相似,但是更加的轻量,不需要模拟硬件也不需要单独运行操作系统,只为每一个应用提供完全隔离的 container,不同的 container 之间相互不受影响。Docker 中比较重要的三个概念是:

  • dockerfile
  • image
  • container

dockerfile 定义镜像,可指定为 Linux 基础镜像,或者为 Docker Hub 上开源的镜像,然后可在基础镜像上自定义。镜像定义好之后,我们可以通过镜像去创建不同的容器(container),由此创建的容器环境都是一致的(比如操作系统,node 版本等)。创建多个容器化应用,相比起在多个不同的服务器上部署相同的应用,减少了部署上带来的麻烦,也避免了不同服务器环境不一致导致的应用表现不一致的问题。

architecture.svg

Kubernetes

Kubernetes 是一个开源的 Docker 容器编排系统,一个 Kubernetes 集群通常包含 2 台及以上的服务器,其中包含一个 master 节点和多个 node 节点, master 节点负责整个集群的管理和控制。它能很好的支撑分布式系统,内部已包含故障发现、服务滚动升级、在线扩容等能力。Kubernetes 中所有的资源对象都可以采用 yaml 文件来定义。

Kubernetes 中比较重要的几个概念是:

  • namespace(命名空间)
  • pod
  • service
  • kubectl

20129737F10FwgsSWh.png

  • namespace 用于实现资源隔离,在逻辑上区分不同资源。在 easy-serverless 中使用对应的用户名创建了命名空间, 这规定了 pod,存储卷等资源从属与哪个命名空间。还结合了 configMap 的配置,限定用户的 namespace 能占用的资源配额,比如服务数量,存储空间限制等。
  • pod 里会有一个或者是多个容器,就是我们的服务运行的地方。可以使用 yaml 文件基于特定镜像定义对应的 deployment,也可以直接定义资源类型 pod。
  • service 是独立于 pod 的生命周期的,可以把 pod 里面的服务,暴露到集群外部。Kubernetes 内部的 kube-proxy 是一个负载均衡器,负责把 service 的请求转发到后端的某个 pod 实例上, service 也会有自己独特的 Cluster IP。
  • kubectl 为客户端 cli 工具, 用户可以通过命令行的方式对集群进行操作, 包括查看 pod 运行状态,资源对象的创建,修改,运行等, 我们可以通过网站提供的 交互式教程 来学习相关的知识和 Kubernetes 的基本操作。

Longhorn

longhornKubernetes 的分布式持久化存储卷(PersistantVolume)管理系统, 社区目前开源的有 LonghornCeph 这两个方案。

Kubernetes 有自己的持久卷,longhorn 提供了一个比较完善的管理体系, 可运行 Longhorn UI 对存储卷进行管理操作。使用 longhorn 申请资源时也同样需要在 yaml 中定义持久化存储卷声明。对于有两个节点的集群,每个存储卷会对应一个 engine 和在不同节点上的 2 个副本,这保证了每个 node 都可以访问存储卷,存储卷副本的编排也依赖于 Kubernetes

how-longhorn-works.svg

功能点分析

了解完了涉及的基础知识,下面会对 easy-serverless 中的具体功能实现进行说明。

镜像的定制

easy-serverlesss 中支持创建的静态网站,node 服务,mongo,minio 等服务,这些都是基于上传到公司云的自定义的镜像创建的。以创建一个简单的 node 服务镜像为例,说明下如何制作自定义的镜像。

(1)在本地安装 Docker,定义自己的 dockerfile

FROM node:16-alpine3.11
     
MAINTAINER  username yourEmail@xxx.com

SHELL ["/bin/sh", "-c"]

RUN echo 'start build' && \
  sed -i 's/dl-cdn.alpinelinux.org/mirrors.yourmirror.com.cn/g' /etc/apk/repositories && \
  apk add git

dockerfile 自定义的镜像基于 DockerHub 中的镜像 node:16-alpine3.11,alpine 不同版本的 node 镜像,默认已经安装了 node, npm, yarn 等。考虑到直接访问官方镜像源的一些网络限制,在此基础上修改了镜像源地址为内部的镜像源地址,并且执行了一些自定义的操作。

(2)本地基于 dockerfile 构建你的镜像

 docker build -f ./dockerfile -t my-node:16-alpine3.11 .

(3) 构建成功之后可以在本地的鲸鱼应用 Docker Desktop 中运行一个容器,测试相关的功能

(4) 公司云平台上是需要把镜像打包之后上传, 我们使用 save 命令保存压缩包到本地,然后上传到公司云平台,就可以使用自己的镜像了

docker save -o ./node-16-alpine.tar.gz  my-node

服务和应用的创建

我们使用了 @kubernetes-client-node 客户端库来使用 Kubernetes 提供的能力,它提供了一系列的 API 便于去操作和管理我们的服务。除了 JavaScript 客户端,官方还提供了 Go,Java,Python,dotnet 等客户端库便于使用。

前面提到过 Kubernetes 中所有的资源对象都可以采用 yaml 文件来定义,资源对象的定义包含 Pod, Deployment, Service, Ingress, Replication Controller 等等,一个简单的 yaml 定义如下:

apiVersion: XXX
kind: XXX                     // 类型
metadata:                     // 基础信息
  name: XXX
  labels: 
    {{key: value}}
spec:                         // 详细定义可选内容
  container: 
  volumes:     

以平台创建的一个 node 服务为例, 我们来分析部署一个服务都需要声明哪些资源, 在 easy-serverless 的实现中一共定义了三种资源类型,ConfigMap(配置集),Deployment(部署,部署中包含容器),以及 Service(服务)。

  • ConfigMap: 一系列配置信息,环境变量的结合,这些信息都能通过 api 或者命令行 kubectl describe configmap app_name 查到。

  • Deployment: deployment 同样在包含了一些基础信息,在 spec 详细信息中创建了一个容器,并且执行拉取仓库代码,安装依赖,运行服务等操作,还定义了内部的端口。

  • Service: 判断了如果用户定义了外部端口,则外部可通过端口访问,没有则内部访问特有的 Cluster IP。

编写好这 3 部分的 yaml,我们就可以使用 API 根据这个 yaml 文件去创建服务了。

限额的配置

为了防止服务器资源的滥用, easy-serverless 中做了一些限额的配置。

每个用户注册时会分配一定额度的资源,比如允许创建的服务数,可使用的存储容量。在新创建资源的时候会去比对已经使用的配额和分配的额度 ,判断用户是否还有额度添加资源。

存储卷的管理

对于 mongodb, redis 这类应用,我们需要用到持久化的存储。

Longhorn 的特点是支持分布式, longhorn-ui 提供了一个可视化的界面可对存储卷进行操作。有对应的重启,备份,快照等功能。

想要访问 longhorn-ui,只需要找到 longhorn 的 service 对应的外部端口号,使用 master节点的IP:port 就可以了

image-20211206103708486.png

域名及ingress配置

域名我们申请了 XX.dev.XXX.net 这个地址,编辑域名的时候可以在界面中设置流量的转发,这里实际是创建了一个 ingress 类型。

ingressKubernetes 内部支持的功能,ingress 的作用和 nginx 相似,可以配置对应的规则做资源转发,但是只支持转发到集群内部服务, 根据用户配置的转发规则来添加 ingress 中的规则。

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: {{domainName}}
  labels:
    create-by: ezsvs
spec:
  rules:
  - host: {{domainName}}.dev.XXX.net
    http:
      paths:
      {{#each forwards}}
      - path: {{path}}
        # pathType: Prefix
        backend:
          serviceName: {{serviceName}}
          servicePort: {{servicePort}}
      {{/each}}

参考资料

书籍:
《Kubernetes权威指南》

官方文档:
dockerhub
kubernetes官方文档
longhorn官方文档