Skip to main content

· One min read
cnfatal

为什么要自己设计模型仓库

最近需要寻找一种更友好的方式来存储我们的模型。 我们曾经在使用 ormb 时遇见了问题,由于我们的模型有的非常大(数十 GB),在使用 ormb 时将会面临:

  1. ormb push 时,harbor 报错。原因是 harbor 内存超出限制以及 harbor 接入的 s3 有单文件上传大小限制。
  2. 每当模型有变动时(即使变动很小),都会重新生成全量的镜像层,在部署时都需要重新拉取数十 GB 的文件。
  3. 其他相关问题。

此外,我们还正在开发新的KubeGems算法商店,需要一个能够和算法商店对接的模型仓库服务,以便于仓库中的模型能够在算法商店中更好的展示。

寻找替代

为此,需要寻找新的替代方案。需要能够满足:

  • 支持模型readme预览,能查看模型文件列表。
  • 可以版本化管理并支持增量。

使用 GIT LFS:

Huggingface 使用了 git + lfs 模型进行模型托管,将小文件以及代码使用 git 进行版本管理,将模型或其他大文件存放至 git lfs。

这种方式增加了一个 git 服务,对于大流量时,git 服务会成为瓶颈。 对于私有化部署,需要引入一个 git server 和对 git servre 的多租户配置,对于我们来说确实不够精简。 而且使用 git 方式,模型数据会在两个地方存放,增加维护成本。

使用对象存储:

一众云厂商的解决方案是将模型存储到了对象存储,华为 ModelArts ,百度 BML,阿里 PAI,腾讯 TI-ONE,Amazon SageMaker 等。 对于公有云来说,提供 ML 解决方案同时将数据都放在对象存储中是最好的方式。

但在私有云中,虽然也用对象存储,但我们没有 ML 的配套方案。若让用户将模型直接存储在对象存储中,将难以进行版本控制。 我们需要提供一套管理机制,放在用户和对象存储之间。

使用OCI registry:

借鉴 ormb 的方式,可以将模型存储在 OCI registry 中。为了解决之前遇到的问题,需要对现有 ormb 的打包流程进行优化,将 big layer 进行拆分,增加文件复用。 这又带来新问题,对于使用者来说,必须要使用修改后的 ormb 才能正常下载模型。

改都改了不如彻底一点,基于 OCI 编写一个新的程序来帮助我们解决这个问题。对,就这么干!

从零开始

以 OCI 作为服务端,OCI 服务端后端存储对接到 S3。OCI 仓库不使用 harbor,选择了更轻量的 docker registry v2。 将模型使用合适的方法分层然后 push 到 OCI 仓库,下载时再将模型拉下来合并还原。

非常好,我们的数据经过了 本地->OCI->S3 并存储起来了。但是,如果流量再大一点呢,OCI 或许是新的瓶颈。 那能不能 本地->S3 呢?这样岂不是又快又好了。

上面说到在直接使用对象存储时我们面临的问题为难以进行版本控制,且 s3 的 key 需要分发到客户端,更难以进行权限控制。

这里借鉴 git lfs 提供的思路,将文件直接从 git 直接上传到 git lfs server,而 git server 仅做了协调。

于是一个新的结构产生了:

这个协调者负责沟通用户和 S3,并包含了鉴权等,核心流程为:

  1. 用户本地将模型合理打包成多个文件,并计算文件的 hash 准备上传。
  2. 检查该 hash 的文件是否存在,若存在即结束,不做操作。
  3. 若不存在则 modelx 返回一个临时 url,客户端向该 url 上传。
  4. 上传完成后通告 modelx。

这和 git lfs 非常像, git lfs 也有基于 S3 的实现, 但是我们不需要引入一个完整的 git server(带来了额外的复杂度)。

好了,总体思路确定后,开始完善每个流程的细节,这个新的东西称为 modelx

modelx

数据存储

先解决如何存储数据,先看存储部分 server 端接口:

参考 OCI 我们 server 端仅包含三种核心对象:

namedescription
index全局索引,用于寻找所有 manifest
manifest版本描述文件,记录版本包含的 blob 文件
blob数据文件,实际存储数据的类型

所以一个 manifest 示例为:

schemaVersion:
mediaType:
config:
- name: modelx.yaml
digest: sha256:xxxxxxxx...
mediaType: "?"
size: 45
blobs:
- name: file-a.bin
digest: sha256:xxxxxxxx...
mediaType: ""
size: 18723
- name: file-b.bin
digest: sha256:xxxxxxxx...
mediaType: "?"
size: 10086
annotaitons:
description: "some description"

服务端接口:

methodpathdescription
GET/获取全局索引
GET/{repository}/{name}/index获取索引
GET/{repository}/{name}/manifests/{tag}获取特定版本描述文件
DELETE/{repository}/{name}/manifests/{tag}删除特定版本描述文件
HEAD/{repository}/{name}/blobs/{digest}判断数据文件是否存在
GET/{repository}/{name}/blobs/{digest}获取特定版本数据文件
PUT/{repository}/{name}/blobs/{digest}上传特定版本数据文件

似曾相识,对,这和 OCI registry 的接口非常像,但是更简单了。

上传流程:

  1. 客户端准备本地文件,对每个需要上传的 blob 文件,计算 sha256。生成 manifest。
  2. 客户端对每个 blob 文件执行:
    1. 检查服务端是否存在对应 hash 的 blob 文件,如果存在,则跳过。
    2. 否则开始上传,服务端存储 blob 文件。服务端可能存在重定向时遵循重定向。
  3. 在每个 blob 均上传完成后,客户端上传 manifest 文件
  4. 服务端解析 manifest 文件,更新 index。

这里有一个隐形约定:客户端在上传 manifest 之前,确保已经上传了所有 blob。 上传 manifest 意味着客户端承诺上传了 manifest 中所有的部分,以便于其他客户端可以发现并能够下载完整的数据。

下载流程:

  1. 客户端向服务端查询 index 文件,获取 manifest 文件的地址。
  2. 客户端向服务端获取 manifest 文件,并解析 manifest 文件,获取每个 blob 文件的地址。
  3. 客户端对每个 blob 文件执行:
    1. 检查本地文件是否存在,如果存在,判断 hash 是否相等,若相等则认为本地文件于远端相同无需更新。
    2. 若不存在或者 hash 不同,则下载该文件覆盖本地文件。

我们实现了一个简单的文件服务器,这对我们来说已经可以用了。

负载分离

这就是一个简单的文件服务器,数据还是流过了 modelx, 那如何实现直接本地直接上传到 S3 流程呢?

这里借助了 302 状态码,当客户端上传 blob 时,可能收到 302 响应, 此时 Location Header 会包含重定向的 URI,客户端需要重新将 blob 上传至该地址。下载时也使用相同逻辑。

在使用S3作为存储后端时,我们使用到了s3 presign urls,能够对特定object生成临时 url 来上传和下载,这非常关键。

为了支持非 http 协议存储,客户端需要在收到 302 响应后根据具体地址使用不同的方式处理上传。

  • 对于 http ,会收到以 http(s):// 开头的重定向地址,此时客户端继续使用 http 协议上传至该地址。
  • 对于 S3,可能收到以 s3:// 开头的 presign 的 S3 地址,则此时则需要客户端转为使用 s3 client 上传 blob 到该地址。
  • 此外,服务端还可以响应其他协议的地址,客户端可以自行实现并扩展到其他存储协议。

这基本上是一个简单高效的,可索引的,版本化的文件存储服务。不仅可以用于存储模型,甚至可以推广到存储镜像,charts 等。

为什么不用OCI?

我们在研究了OCI destribution 的协议后,发现OCI协议在上传接口上无法做到能够让客户端直接与存储服务器交互。 总是需要在最终的存储服务器前增加一个适应层。 详细的可以参看 OCI Distribution Specification

OCI 中无法获得模型文件列表,从而无法仅下载指定文件。

模型存储

在已有的服务端实现中,可以看到 modelx 服务端仅负责文件存储,对于 manifest 中实际包含哪些 blob,还是由客户端决定。

我们的最终目的是用于存储模型,面临的模型可能有超大单文件以及海量小文件的场景。 除了解决如何将模型存储起来,还需要解决如何管理多个模型版本,模型下载(增量下载)。

在上一节的 manifest 中,每一个 blob 都包含了 mediaType 字段,以表示该文件的类型。可以从这里进行扩展。

  • 对于单个大文件,可以不用特殊处理,客户端会在上传和下载时使用 s3 client 分块处理。
  • 对于海量小文件,选择在客户端将小文件打包压缩为单文件,设置特别的 mediaType 进行上传;在下载时,对特别的 mediaType 进行解包还原。
  • 对于增量,类似于OCI image,客户端会在本地计算更改的文件,客户端仅用上传改变的文件。在下载时,客户端也会仅下载与远程对比 hash 不同的文件。
  • 对于部署,部署时可能仅需要下载某一个文件,则可以借助 modelx.yaml,在其中指定仅需要在部署时下载的模型文件。 同时 modelx.yaml 还包含了 model-serving 时所需要的一些信息。

一个 modelx.yaml 示例(非最终版):

config:
inputs: {}
outputs: {}
description: Awesome text generator
framework: pytorch
maintainers:
- maintainer
tags:
- modelx
- demo
task: text-generation
modelFiles:
- torch.bin
- tf_output.h5

认证授权

有了上面的实现,认证可以插入到服务端几个接口中,对请求进行拦截。

目前modelx实现了基于 OIDC 的认证方案,modelx 仅需要填写一个外部 OIDC Identity Provider 地址即可使用。

总结

最终来说,我们实现了一个简单的、 高性能的、可扩展的模型存储服务。 结合了 OCI、git-lfs 和 对象存储的优势,并解决了我们在模型管理遇到的问题。 未来 modelx 依旧还有许多事情要做,欢迎大家参与到 modelx 以及 kubegems 社区中来。

如果你想快速体验一下 modelx 可以看看Setup.

· One min read
LinkMaq

Nacos 介绍

Nacos 是阿里云开源一款在微服务场景下用于处理应用配置发布管理和服务注册管理的服务平台。其主要提供了如下几个特性:

  • 服务发现和服务健康监测

基于 DNS 和 RPC 的服务发现。服务提供者使用 原生SDKOpenAPI、或一个独立的Agent TODO注册 Service 后,服务消费者可以使用DNS TODOHTTP&API查找和发现服务。

  • 动态配置服务

动态配置服务可以让您以中心化、外部化和动态化的方式管理所有环境的应用配置和服务配置。

  • 动态 DNS 服务

动态 DNS 服务支持权重路由,让您更容易地实现中间层负载均衡、更灵活的路由策略、流量控制以及数据中心内网的简单DNS解析服务。

  • 服务及其元数据管理

Nacos 从微服务平台建设的视角管理数据中心的所有服务及元数据,包括管理服务的描述、生命周期、服务的静态依赖分析、服务的健康状态、服务的流量管理、路由及安全策略、服务的 SLA 以及最首要的 metrics 统计数据。

KubeGems 中的 Nacos

KubeGems 自v1.21版本之后开启了对 Nacos 配置中心的支持,并利用了内置 Plugins CRD 实现了对 Nacos 的快速启动。

KubeGems 中的 Nacos 安装源来至官方社区提供https://github.com/nacos-group/nacos-k8s,并在 plugin crd 中来管理部署的版本。用过 Nacos 的同学可能知道,其内部的数据模型主要围绕dataidgroupnamespace这 3 个进行操作。由于 KubeGems 的设计是一个支持多租户的平台,所以在应用 nacos 数据模型时,按照了 tenant + project来区分内部的命名空间。

启用和配置插件

KubeGems 启用 Nacos 需要具备系统管理员的权限进行操作。管理员进入管理后台的“插件管理”,点击“启用“按钮“即可开启Nacos。

直到出现如下状态,代表插件运行正常

此时,我们就可以在租户的环境中开始使用 Nacos 服务

个性化配置

Nacos插件的配置以 CRD 的形式存放在 nacos命名空间中,我们可以通过命令kubectl edit plugin nacos -n nacos对插件进行个性化配置。

apiVersion: plugins.kubegems.io/v1beta1
kind: Plugin
metadata:
finalizers:
- plugins.kubegems.io/finalizer
generation: 1
name: nacos
namespace: nacos
spec:
kind: helm
path: helm
url: https://github.com/nacos-group/nacos-k8s.git
values:
namespace: nacos
global:
mode: cluster
nacos:
replicaCount: 1
image:
repository: registry.cn-beijing.aliyuncs.com/kubegems/nacos-server
tag: v2.1.1
plugin:
image:
repository: registry.cn-beijing.aliyuncs.com/kubegems/nacos-peer-finder-plugin
persistence:
data:
storageClassName: local-path
enabled: true
service:
type: ClusterIP
version: master

提示:KubeGems的插件 CRD 由 https://github.com/kubegems/bundle-controller提供支持,我们也可以直接使用 bundle-controller 在非 kubegems 集群中管理插件。

集群部署

Nacos集群由社区提供支持部署,kubegems 默认将 nacos 的全局运行模式设置为“cluster”,如果您需要扩展成多集群,只需修改replicaCount的副本数为 3 即可。

开放集群外访问

Nacos 插件默认运行在 Kubernetes 内部,如果需要在集群外访问 Nacos 需借助网关实现。管理员可以在后台创建一条基于默认网关的 ingress 来代理 nacos api。过程如下:

第一步: 进入路由功能页面,选择 nacos 命名空间

第二步:创建并提交一条路由规则,用于 nacos 的代理

第三步:获取访问地址

提示:Nacos2.0版本相比1.X新增了gRPC的通信方式,因此需要增加2个端口。新增端口是在配置的主端口(server.port)基础上,进行一定偏移量自动生成

使用配置中心

进入应用环境下的“应用配置”,可以点击右上角的“获取访问信息”查看当前环境下的 nacos sdk 所需的配置信息

配置管理

点击“创建配置项”就可以创建配置

配置历史与回滚

监听列表

运行测试

我们用 nacos-sdk-go/v1来做一个简单的认证

package main

import (
"fmt"
"time"

"github.com/nacos-group/nacos-sdk-go/clients"
"github.com/nacos-group/nacos-sdk-go/common/constant"
"github.com/nacos-group/nacos-sdk-go/vo"
)

func main() {
sc := []constant.ServerConfig{
{
IpAddr: "nacos.kubegems.io",
Port: 31956,
},
}

cc := constant.ClientConfig{
NamespaceId: "69f7325702bc396a8773f9a0a94eea310b21ec39", //namespace id
TimeoutMs: 5000,
NotLoadCacheAtStart: true,
LogDir: "/tmp/nacos/log",
CacheDir: "/tmp/nacos/cache",
LogLevel: "debug",
}
client, err := clients.NewConfigClient(
vo.NacosClientParam{
ClientConfig: &cc,
ServerConfigs: sc,
},
)

if err != nil {
panic(err)
}

content, err := client.GetConfig(vo.ConfigParam{
DataId: "test",
Group: "e3",
})
fmt.Println("GetConfig,config :" + content)

err = client.ListenConfig(vo.ConfigParam{
DataId: "test",
Group: "e3",
OnChange: func(namespace, group, dataId, data string) {
fmt.Println("config changed group:" + group + ", dataId:" + dataId + ", content:" + data)
},
})
time.Sleep(300 * time.Second)
}

以下是运行情况

总结

本文主要介绍了在 KubeGems 中启用并使用Nacos插件作为应用的配置中心的基本管理功能。Nacos 是一个非常棒的应用配置管理平台,KubeGems 团队将持续关注此项目,并为用户在 Kubernetes 集群提供更友好的支持。

· One min read
LinkMaq

Kind是Kubernetes In Docker的缩写,通过使用 Docker ,它能快速的拉起一套 Kubernetes 服务。因此它在Kubernetes功能测试和二开等领域被广泛使用。

KubeGems是一款以围绕 Kubernetes 通过自研和集成云原生项目而构建的通用性开源 PaaS 云管理平台。经过我们内部近一年的持续迭代,当前 KubeGems 的核心功能已经初步具备多云多租户场景下的统一管理。并通过插件化的方式,在用户界面中灵活控制包括 监控系统日志系统微服务治理 等众多插件的启用和关闭。

本文将指导用户使用 Kind 快速部署一个 KubeGems v1.21的版本用于本地测试。

安装 Kind

在 Linux 上

curl -Lo ./kind https://github.com/kubegems/kind/releases/download/v0.15.0-alpha-kubegems/kind-linux-amd64
chmod +x ./kind
sudo mv ./kind /usr/local/bin/kind

在 MacOS 上

# for Intel Macs
[ $(uname -m) = x86_64 ]&& curl -Lo ./kind https://github.com/kubegems/kind/releases/download/v0.15.0-alpha-kubegems/kind-darwin-amd64
# for M1 / ARM Macs
[ $(uname -m) = arm64 ] && curl -Lo ./kind https://github.com/kubegems/kind/releases/download/v0.15.0-alpha-kubegems/kind-darwin-arm64
chmod +x ./kind
mv ./kind /some-dir-in-your-PATH/kind

在 Windows 上

curl.exe -Lo kind-windows-amd64.exe ./kind https://github.com/kubegems/kind/releases/download/v0.15.0-alpha-kubegems/kind-windows-amd64
Move-Item .\kind-windows-amd64.exe c:\some-dir-in-your-PATH\kind.exe

创建服务

Single Cluster

和创建 Kubernetes 集群一样,使用命令kind create cluster就能快速拉起一个 Kubernetes 服务并部署 KubeGems image-20220805141017484.png

由于不需要定制kindest/node镜像,所以 KubeGems安装全程需要连接公网下载所需的镜像。在启动完成之前会有许多 Pod 的状态为 CrashLoopBackOff,这是由于其依赖的服务(mysql、redis、gitea、argocd 等)还在启动中,这是正常的,请耐心等待。

kubegems 所有服务部署并启动完成后会有如下 pod

image-20220805141327441.png

当容器状态全部Running后,使用 port-forward 将 KubeGems Dashboard 服务映射到本地

kubectl port-forward svc/kubegems-dashboard :80 -n kubegems                           

Forwarding from 127.0.0.1:52302 -> 8000
Forwarding from [::1]:52302 -> 8000

此时,我们打开浏览器访问 http://localhost:52302即可访问 KubeGems,默认用户admin 默认密码demo!@#admin

使用 Kind 生成的 KubeConfig文件导入集群是,注意修改集群 Server 地址为内部地址http://kubernetes.default:443

image-20220805144837887.png

Mutil Cluster

如果您需要使用 Kind 部署一个 Kubernetes 集群,那么可以按照如下配置

cat ./kind.yaml

kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
- role: control-plane
- role: control-plane
- role: worker
- role: worker
- role: worker

并通过命令 kind create cluster --config kind.yaml

image-20220805143833694.png

打开 KubeGems 后台并导入集群后,我们便可以在机器列表中查看集群内主机数量

image-20220805145229274.png

指定 Kubernetes版本创建 KubeGems

如果您要在指定的 Kubernetes 版本中创建 KubeGems,只需要kind 在创建过程中指定kindest/node镜像版本即可

kind create cluster  --image kindest/node:v1.23.6

启用插件

默认情况下 KubeGems 只做了最小化安装,如果您要启用更多功能,可在管理员后台的组件管理中启用相关插件

image-20220805145350662.png


· One min read
liutao

Apache Skywalking 专门为微服务架构和云原生架构系统而设计并且支持分布式链路追踪的APM系统。Apache Skywalking 通过加载探针的方式收集应用调用链路信息,并对采集的调用链路信息进行分析,生成应用间关系和服务间关系以及服务指标。Apache Skywalking 目前支持多种语言,其中包括 Java.Net CoreNode.jsGo 语言。本文将从以 KubeGems 应用商店出发,来快速搭建一套Skywalking,希望能够帮助到大家。

安装SkyWalking OAP

KubeGems应用商店(HelmChart)是一个描述Kubernetes相关资源的文件集合,单个应用可以用来部署某些复杂的HTTP服务器以及Web全栈应用、数据库、缓存等

  1. Elasticsearch安装

在KubeGems应用商店中找到Elasticsearch

选择部署7.13.2版本,填写必要的【项目】、【环境】等信息

img

为方便演示,Master、ES副本数都配置为1,可根据实际需要配置参数,还可以修改 Values 中的配置

SkyWalking 初始化 ElasticSearch index 的是默认规则是 1 副本 1 分片,实际在使用中ElasticSearch 的实例数最好大于 2 个

img

点击部署,ES服务搭建完成。

img

  1. SkyWalking安装

同样在应用商店找到skywalking应用,填写基本信息,进入详细配置页,将数据设置为ES应用名称与端口

img

点击部署,可以看到skywalking-oap、skywalking-ui服务已经部署完成

img

在KubeGems控制台,找到容器服务-->运行时-->路由,创建路由,将skywalking-ui服务地址进行域名映射。我这里直接采用随机域名,用户可以根据自己公司内的域名手动配置。

img

在浏览器中打开路由访问地址,已经能正常看skywalking-ui的页面了

img

img

skywalking服务搭建完成啦,是不是非常的快速方便,哈哈哈哈哈😄

SkyWalking Agent

所谓Agent是指SkyWalking从各个平台(Java Python等)收集监控数据的代理,此处我们以为Java应用为例,收集Java应用产生的各种监控数据

SkyWalking的数据采集主要是通过业务探针(Agent)来实现的,针对不同的编程语言SkyWalking提供了对应的Agent实现。Java微服务接入SkyWalking可以使用“SkyWalking Java Agent”来上报监控数据。

这就需要Java微服务在部署启动的过程中需要获取 SkyWalking Java Agent 探针包,并在启动参数中通过--javaagent:xxx进行参数指定。而具体的集成方式大致有以下四种:

  • 使用官方提供的基础镜像;

  • 将agent包构建到已存在的基础镜像中;

  • 将agent包放到共享volume中;

  • 通过sidecar 模式挂载agent;

其中前两种方式主要是通过在构建Docker镜像的过程中将Agent依赖打包集成到Java服务的Docker镜像中,而sidecar模式则是利用k8s的相关特性来实现在容器启动时挂载Agent相关依赖。

为什么选择sidecar

Sidecard主要原理是通过Kubernetes的初始化容器initContainers来实现的,initContainers是一种专用容器,它应用容器启动之前运行,可以用于完成应用启动前的必要初始化工作。如果微服务是直接部署在 Kubernetes 集群,那么采用 sidecar 模式来使用 SkyWalking Agent会更加方便,因为这种方式不需要修改原来的基础镜像,也不需要重新构建新的服务镜像,而是会以sidecar模式,通过共享的volume将agent所需的相关文件直接挂载到已经存在的服务镜像中。

初始化容器InitContainers

InitContainers 就是用来做初始化工作的容器,可以是一个或者多个,如果有多个的话,这些容器会按定义的顺序依次执行,只有所有的initContainers执行完后,主容器才会被启动。我们知道一个Pod里面的所有容器是共享数据卷和网络命名空间的,所以initContainers里面产生的数据可以被主容器使用到的

自定义SkyWalking Agent镜像

  • 下载SkyWalking官方发行包,并解压到指定目录
#下载skywalking-8.6.0 for es7版本的发布包,与部署的skywalking后端版本一致
$ wget https://archive.apache.org/dist/skywalking/8.6.0/apache-skywalking-apm-8.6.0.tar.gz

#将下载的发布包解压到当前目录
$ tar -zxvf apache-skywalking-apm-es7-8.6.0.tar.gz
  • 修改配置,编辑config/agent.config文件,以下只列出部分配置项
# The agent namespace
# agent.namespace=${SW_AGENT_NAMESPACE:default-namespace}
# 表示提供相同功能/逻辑的逻辑组的服务名称
agent.service_name=${SW_AGENT_NAME:Your_ApplicationName}

# OAP服务地址,修改默认地址为skywalking-oap服务名
collector.backend_service=${SW_AGENT_COLLECTOR_BACKEND_SERVICES:skywalking-oap:11800}
# 日志文件名
logging.file_name=${SW_LOGGING_FILE_NAME:skywalking-api.log}
# 日志级别:TRACE、DEBUG、INFO、WARN、ERROR、OFF。
logging.level=${SW_LOGGING_LEVEL:INFO}
# 最大历史日志文件。发生翻转时,如果日志文件超过此数量,则最旧的文件将被删除。默认情况下,负数或零表示关闭。
logging.max_history_files=${SW_LOGGING_MAX_HISTORY_FILES:10}
# 挂载插件的特定文件夹。安装文件夹中的插件可以工作。
plugin.mount=${SW_MOUNT_FOLDERS:plugins,activations,bootstrap-plugins}
# 排除插件目录中定义的一些插件
# plugin.exclude_plugins=${SW_EXCLUDE_PLUGINS:}
  • 构建skywalking-agent sidecar 镜像并push至hub私有镜像仓库

在前面步骤中解压的skywalking发行包,进入agent目录编写Dockerfile文件

FROM busybox:latest
RUN set -eux && mkdir -p /usr/skywalking/agent/
COPY . /usr/skywalking/agent/
WORKDIR /
  • 完成Docker文件编写后,执行镜像构建命令:
# 构建镜像,注意最后一个.
docker build -t <your-registry>/skywalking-agent-sidecar:8.6.0 .
# 镜像推送至私有Harbor仓库
docker push <your-registry>/skywalking-agent-sidecar:8.6.0

sidecar挂载

在KubeGems中找到 【工作负载】,编辑更新工作负载进入到容器镜像页面

设置SW环境变量,编辑工作容器

  • SW_AGENT_NAME=\<YourApplicationName>
  • JAVA_TOOL_OPTIONS=-javaagent:/usr/skywalking/agent/skywalking-agent.jar

添加容器镜像,选择初始化容器将skywalking-agent-sidecard镜像进行挂载,并添加启动命令

sh -c /usr/skywalking/agent/* /skywalking/agent

img

挂载emptyDir卷

img

点击确定保存工作负载信息,自动重启后进入应用容器,可以看到agent目标已经加载到容器中了

root@pod-7bc77468ff-7b4xt:/# cd /usr/skywalking/agent/
root@pod-7bc77468ff-7b4xt:/usr/skywalking/agent# ll

total 17716
drwxrwxrwx 9 root root 194 May 19 08:14 ./
drwxr-xr-x 3 root root 27 May 19 08:14 ../
-rw-r--r-- 1 root root 114 May 19 08:14 Dockerfile
drwxr-xr-x 2 root root 4096 May 19 08:14 activations/
drwxr-xr-x 2 root root 85 May 19 08:14 bootstrap-plugins/
drwxr-xr-x 2 root root 64 May 19 08:14 config/
drwxr-xr-x 2 root root 32 May 19 08:14 logs/
drwxr-xr-x 2 root root 4096 May 19 08:14 optional-plugins/
drwxr-xr-x 2 root root 45 May 19 08:14 optional-reporter-plugins/
drwxr-xr-x 2 root root 4096 May 19 08:14 plugins/
-rw-r--r-- 1 root root 18121582 May 19 08:14 skywalking-agent.jar

此时打开skywalking-ui,已经可以看到监控数据了

img

SkyWalking动态配置

SkyWalking配置主要是通过application.yml操作系统环境变量设置的,其中一些还支持来自上游管理系统的动态设置。上游服务支持包括Zookeeper、Etcd、Consul、Apollo、Nacos、K8s-configmap等。

目前SkyWalking支持以下动态配置

配置说明
agent-analyzer.default.slowDBAccessThresholdreceiver-trace/default/slowDBAccessThreshold慢数据库语句的阈值,覆盖application.yml.
agent-analyzer.default.uninstrumentedGateways未检测的网关覆盖gateways.yml.
alarm.default.alarm-settings警报设置将覆盖alarm-settings.yml
core.default.apdexThresholdapdex 阈值设置,将覆盖service-apdex-threshold.yml.
core.default.endpoint-name-grouping端点名称分组设置,将覆盖endpoint-name-grouping.yml.
agent-analyzer.default.sampleRate跟踪采样,覆盖receiver-trace/default/sampleRate.application.yml
agent-analyzer.default.slowTraceSegmentThreshold设置这个关于延迟的阈值将使慢跟踪段在花费更多时间时被采样,即使采样机制被激活。默认值为-1,这意味着不会对慢速跟踪进行采样。单位,毫秒。的覆盖receiver-trace/default/slowTraceSegmentThresholdapplication.yml
configuration-discovery.default.agentConfigurationsConfigurationDiscovery 设置

k8s-configmap

很多应用在其初始化或运行期间要依赖一些配置信息。大多数时候, 存在要调整配置参数所设置的数值的需求。 ConfigMap 是 Kubernetes 用来向应用 Pod 中注入配置数据的方法。

本文介绍如何通过KubGems平台动态配置SkyWalking参数

  • KubGems工作台 --> 配置中心 --> 配置 --> 创建配置
  • 添加参数及告警规则配置

img

  • 编辑yaml,添加修改app、compoent标签值
kind: ConfigMap
apiVersion: v1
metadata:
name: skywalking-dynamic-config
namespace: default
creationTimestamp: '2022-05-16T11:14:23Z'
labels:
component: oap
data:
agent-analyzer.default.sampleRate: '7000'
agent-analyzer.default.slowDBAccessThreshold: default:250,mongodb:100
alarm.default.alarm-settings: >-
rules:
# Rule unique name, must be ended with `_rule`.
service_resp_time_rule:
metrics-name: service_resp_time
op: ">"
threshold: 2000
period: 10
count: 3
silence-period: 5
message: 最近3分钟内服务 {name} 的平均响应时间超过2秒
  • 修改skywalking-oap环境变量信息,使用k8s-configmap配置
apiVersion: apps/v1
kind: Deployment
metadata:
name: skywalking-oap
labels:
app: skywalking
app.kubernetes.io/instance: skywalking
.........

env:

.....

- name: SW_CLUSTER_K8S_LABEL

value: app=skywalking,component=oap

- name: SW_CONFIGURATION

value: k8s-configmap

SW_CONFIGURATION= k8s-configmap,动态配置采用k8s-configmap SW_CLUSTER_K8S_LABEL= app=collector,release=skywalking,根据这个值自动选择合适的configmap

  • 重启skywalking-oap,配置生效

SkyWalking配置优化

OAP优化

skywalking写入ES的操作是使用了ES的批量写入接口,我们要做的是调整相关参数尽量降低ES索引的写入频率。 参数调整主要是针对skywalking的配置文件`application.yml,相关参数如下:

storage:
elasticsearch:
bulkActions: ${SW_STORAGE_ES_BULK_ACTIONS:4000} # Execute the bulk every 2000 requests
bulkSize: ${SW_STORAGE_ES_BULK_SIZE:40} # flush the bulk every 20mb
flushInterval: ${SW_STORAGE_ES_FLUSH_INTERVAL:30} # flush the bulk every 10 seconds whatever the number of requests
concurrentRequests: ${SW_STORAGE_ES_CONCURRENT_REQUESTS:4} # the number of concurrent requests
metadataQueryMaxSize: ${SW_STORAGE_ES_QUERY_MAX_SIZE:8000}

调整 bulkActions 默认2000次请求批量写入一次改到4000次;

  • bulkSize批量刷新从20M一次到40M一次;

  • flushInterval每10秒刷新一次堆改为每30秒刷新;

  • concurrentRequests查询的最大数量由5000改为8000。

过滤不需要监控的接口

  • 制作agent镜像时,将apm-trace-ignore-plugin-8.6.0.jar复制到\plugins下面

  • config目录下新建一个配置文件 apm-trace-ignore-plugin.config,文件内容为:

trace.ignore_path=${SW_AGENT_TRACE_IGNORE_PATH:/actuator,/actuator/**,/admin/**,/nacos/**}

设置采样率

在默认情况下,SkyWalking会采集所有追踪的数据。但是如果系统比较复杂,采集的端点比较多的时候,可能存储压力比较大,这个时候我们可以修改配置,只存储部分的调用链路信息。比如:50%。 设置采样率的时候并不会影响相关指标的计算。包括服务,服务实例,端点,拓扑图等相关指标的计算还是使用完整的数据计算的。

在k8s-configmap中,添加配置项,设置采样率为70%:

agent-analyzer.default.sampleRate: '7000'

总结

本文用于指导用于在 KubeGems 中快速部署并运行 SkyWalking服务,用户可在研发环境中快速启用此功能来验证 APM 相关功能。更多关于KubeGems 与 SkyWalking 的配置优化,我们会持续更新,敬请关注。

· One min read
LinkMaq

KubeGems Logging 服务主要面向平台内部以及平台内租户提供日志采集、解析、传输和存储等相关的能力。依靠 Logging Operator 对日志的配置和路由管理,实现平台的终端用户可以对应用运行期间的日志进行实时查询和分析。KubeGems 日志持久化采用 Grafana Loki 实现。

核心需求

多租户

KubeGems 是一个多租户平台,基于此场景。平台内部对于租户应用产生的日志应该具备独立的解析配置以及路由规则

系统鲁棒性

  • 高性能

    • 日志采集和转发性能至少需处理 10K line/sec
    • 支持采取日志限流策略
    • 日志延迟不得低于 5min
  • 可扩展

    • 架构支持灵活的水平扩展以提升整体日志吞吐量
    • 组件因满足无状态属性

可运维性

  • 可配置

    • 日志规则和路由的配置应 CRD 化,由 Operator 统一管理,并尽量做到配置简化。
    • 需支持常见的 json 解析字段增删改 等插件配置。
    • 应用日志应满足发送多种常见的数据管道或收集系统,诸如 kafka、elasticSearch、MongoDB 等。
  • 可视化

    • 日志规则应在 UI 中由用户组合装配置日志的解析与输出规则。
  • 监控与告警

    • 日志采集的状态统计,包含组件运行状态以及日志采集统计。
    • 需支持用户根据自定义日志片段进行设置告警规则。

需求边界

  • 对于应用日志没有输出到控制台(stdout)的场景,暂不纳入采集需求

可采取其他方式重定向内部日志到控制台,诸如s6-log

日志设计

Logging Operator

Logging Operator 是 BanzaiCloud 下开源的一个云原生场景下的日志采集方案。它在 2020 年 3 月的时候经过重构后的 v3 版本,底层凭借高效的 fluentbit 和插件丰富的 flunetd,Logging Operator几乎已经完美的适配了 kubernetes 模式下的日志采集场景。

在 KubeGems 1.20 的版本中,我们选择采用 Logging Operator 作为内部日志流传的核心框架。其主要原因如下:

  • 原生 Flow 和 Output 类资源作用域为 kubernetes 命名空间,这与 KubeGems 租户环境的资源独立性相谋和

  • 采用高性能的 fluentbit 作为日志采集客户端,fluentd 为日志聚合端。flunetd 在 logging 中通过 replicas 控制副本数,可根据吞吐量水平扩容

  • flunetd 支持的插件较为丰富,满足当前基本需求

Logging Operator 不足:

  • 核心资源 Flow 和 Output 交于用户配置较为困难,需要 KubeGems 将资源封装(也许兼容源对象)
  • 可观测性功能较弱
  • 日志 Match 部分功能较弱,无法通过直接匹配 workload 进行关联

KubeGems 日志整体架构

由 Logging Operator 负责日志组件的运行管理和配置管理,租户侧资源以 CR 的方式在所属的环境空间中管理。Operator 将 CR 渲染为 Fluentd 的配置文件,用于处理日志的过滤和转发规则。可观测部分,由 KubeGems Plugins 服务初始化 ServiceMonitor,抓取组件运行期间的状态。

KubeGems Logging

KubeGems 对 Logging Operator 的封装仅满足简单的两种模式的场景:

  • 精简模式

    开箱即用的日志采集模式,对于用户环境空间内的所有容器开启采集,并输出到 KubeGems 平台内置的 Loki 组件用于日志分析和告警等场景

  • 局部自定义模式

    面向希望通过配置局部容器采集,并需要对接外部日志分析系统的场景。则采用此方式,不过此时

除此之外,对于希望能够完全掌握平台内的日志路由的高端用户,KubeGems 只需兼容对 Logging Operator 的原始 CR 资源即可。

精简模式

对于通用场景下的容器控制台日志采集,KubeGems 采用精简模式配置规则,仅需在用户界面中支持 一键配置开启日志采集 功能。一键启用功能的实现主要分为两部分。

  1. KubeGems Installer 服务在对 kubernetes 集群启用 logging 插件时,将对 logging operator 以及关联的 clusteroutputs/containers-console资源进行初始化。

    默认的clusteroutput 资源定义了容器日志的输出路径是 Loki

  2. 用户创建默认的容器采集规则时,LabelSelector 为空,即匹配当前命名空间下的所有 Pod。

  3. Flow 中只启用 Prometheus 插件用于统计采集状态。

  4. Flow 中关联系统默认的 clusteroutputs/containers-console

即在精简模式下,KubeGems 只在租户空间的接口中传入如下参数:

POST  observe/log/<tenant_name>/flowlite?enabled=true&namespace=tenant
参数释意requiredType
enabled启用环境空间的日志采集功能TrueBoolean
namespace采集日志的目标命名空间TrueString

KubeGems 将 Flows 渲染为如下内容:

apiVersion: logging.banzaicloud.io/v1beta1
kind: Flow
metadata:
name: default
namespace: tenant
spec:
match:
- select: {}
filters:
- prometheus:
labels:
container: $.kubernetes.container_name
namespace: $.kubernetes.namespace_name
node: $.kubernetes.host
pod: $.kubernetes.pod_name
metrics:
- desc: Total number of log entries generated by either application containers
or system components
name: logging_entry_count
type: counter
globalOutputRefs:
- containers-console

局部自定义模式

用户如果需要按照应用日志需求,局部对环境空内应用进行日志的规则和路由时,KubeGems 需要对 Logging Operator 的 CR 资源进行优化,以方面在用户界面中实现跟友好的交互。其中首先需要处理平台 应用元数据 相关的事务。默认情况下 Flow 的规则采用 labelSelector 对命名空间内资源做匹配,如下:

apiVersion: logging.banzaicloud.io/v1beta1
kind: Flow
metadata:
name: default
namespace: tenant
spec:
localOutputRefs:
- defalt
match:
- select:
labels:
app: nginx

虽然通过 labelSelector可以灵活控制日志采集规则,但经过实际验证,这个逻辑仍然存在 反直觉的场景,用户大多需要的是在 Selector 阶段与应用资源直接关联 ,当然我们不能直接把label 与 workload 做等同映射。我们需要通过外部方式来对 Label 做通用性匹配。

KubeGems CommonLabels

KubeGems 通用标签 是根据用户上层操作而对 Kubernetes Workload 做自动注入的一组元数据。它是一组常量,被定义到common.go当中。 当用户在 Kubernetes 中做资源对象的操作时,它会以 mutatingwebhook的方式自动注入的被管理的资源对象当中。

CommonLabel 中的 kubegems.io/applications 或者 Kubernetes 中的 app.kubernetes.io/nameapp共同声明了该应用的 workerload 标签。基于此,用户在创建日志规则是,可以通过 LabelSelector 定位到环境下的唯一资源。对于用户提交的 Flow ,同一种日志解析、路由规则类型的资源可以集中管理配置,如下:

apiVersion: logging.banzaicloud.io/v1beta1
kind: Flow
metadata:
name: default
namespace: tenant
spec:
localOutputRefs:
- default
match:
- select:
labels:
kubegems.io/applications: nginx
- select:
labels:
kubegems.io/applications: mysql
- select:
labels:
app.kubernetes.io/name: tomcat

局部模式下的用户流程

局部自定义模式下,开放普通用户配置有限功能的 Flow 以及 Outputs 资源。KubeGems 仍然需要对 CR 做简单接口封装。它的调用流程如下:

  1. 创建日志规则时,请求KubeGems listWorkload 返回当前环境空间下具备采集条件( CommonLabel)的资源列表,由用户在前端选择加入。
  2. 用户界面内提供插件列表,有用户自定义插件是否启用
  3. 通过请求 KubeGems listOutput 返回当前环境下可用的日志路由。普通用户同时也具备列出 ClusterOutput 资源(它由KubeGems 平台管理员创建)。
  4. 日志规则关联 localOutputRefs或者 globalOutputRefs后提交给 KubeGems 后台渲染 Flow 文件。
  5. Flow/Output 资源由 Logging Operator 处理,并返回资源validate结果和状态。

即在 局部自定义模式 下,KubeGems 在租户空间的接口中传入如下参数:

POST  observe/log/<tenant_name>/flow?name=tenant&namespace=tenant&monitor=true&throttle=4000&geoip_keys=remote_addr&outputs=my-elasticsearch,my-kafka&clusteroutputs=loki
参数释意requiredType
name日志采集规则名称TrueString
namespace采集日志的目标命名空间TrueString
monitor启用日志采集状态监控,default: trueFalseBoolean
throttle启用容器级日志条目限速,Lines / 10sFalseInt16
geoip_keys启用 GEO IPFalseString
outputs普通日志输出通道,多个通道用 ,逗号分割At laeast oneString
clusteroutputs日志输出通道,多个通道用 ,逗号分割At laeast oneString

outputs 和 clusteroutputs 参数至少满足一个

KubeGems 将 Flow 渲染如下:

apiVersion: logging.banzaicloud.io/v1beta1
kind: Flow
metadata:
name: tenant
namespace: tenant
spec:
filters:
- geoip:
geoip_lookup_keys: remote_addr
records:
- city: ${city.names.en["remote_addr"]}
location_array: '''[${location.longitude["remote"]},${location.latitude["remote"]}]'''
country: ${country.iso_code["remote_addr"]}
country_name: ${country.names.en["remote_addr"]}
postal_code: ${postal.code["remote_addr"]}
- record_modifier:
records:
- throttle_group_key: ${record['kubernetes']['namespace_name']+record['kubernetes']['pod_name']}
- prometheus:
labels:
container: $.kubernetes.container_name
namespace: $.kubernetes.namespace_name
node: $.kubernetes.host
pod: $.kubernetes.pod_name
metrics:
- desc: Total number of log entries generated by either application containers
or system components
name: logging_entry_count
type: counter
- throttle:
group_bucket_limit: 4000
group_bucket_period_s: 10
group_key: throttle_group_key
localOutputRefs:
- my-elasticsearch
- my-kafka
globalOutputRefs:
- loki

原始模式

对于租户需要使用 Logging Operator 完整特性来做自定义日志解析场景,KubeGems 只需在页面中满足对 Flow 原始格式 的校验和提交即可。

POST  observe/log/<tenant_name>/flow?raw=true

Body:

apiVersion: logging.banzaicloud.io/v1beta1
kind: Flow
metadata:
name: kafka
spec:
filters:
- tag_normaliser: {}
- parser:
remove_key_name_field: true
reserve_data: true
parse:
type: multi_format
patterns:
- format: nginx
- format: regexp
expression: /foo/
- format: none
match:
- select:
labels:
app.kubernetes.io/name: log-generator
localOutputRefs:
- kafka-output

KubeGems Log Observability

KubeGems 的日志可观测性主要满足以下几点需求

  • 用户环境空间内的日志采集速率分析
  • 用户环境空间内的错误日志统计
  • 用户自定义的日志告警规则

默认情况下 KubeGems Logging 插件集成了 Loki 实例用于持久化平台内容器日志。借有 Loki Ruler,可实现日志告警和错误日志分析相关功能。

日志可观测性流程

  1. KubeGems Installer 在 Kubernetes 集群初始化阶段负责将 Logging 插件下的 Loki 和 Recording Rules 配置。
  2. 普通用户在用户界面中创建日志告警规则,由 KubeGems 将告警规则以 Loki API 方式提交。
  3. 当产生Loki 产生日志告警时,经由 AlertManager 将告警事件推送给用户,并在 KubeGems Webhook 记录。

在上述流程中,KubeGems 日志告警中仅需提供 logrules 接口,用于管理用户告警内容。

Log Alerting Template

Loki 的 Rules 的语法规则和 Prometheus 一样,区别只在expr中体现。当前 KubeGems 中的 Metrics 告警采用的是预制模板 的方式,以支持用户更快的创建规则。在日志告警规则也可参考此方式,预制常见的 LogQL 模板。

普通模板

普通模板即用户只需要设置日志关键字符以管道的方式过滤字符。KubeGems 在后端组装语句 expr 并请求 Loki API 完成规则提交 。查询语句如下:

sum by (pod,namespace,application) (count_over_time({pod="<pod>",namespace="<namespace>",applications="<applications>"}  |~ `<your_log_string>`  |~ `<your_log_string>`[1m]))

格式化模板(json/logfmt)

采用 LogQL 的格式化解析器提取日志,通过查找 key-values 的方式过滤结果。

  • json 解释器
sum by  (pod,namespace,application) (count_over_time({pod="<pod>",namespace="<namespace>",applications="<applications>"}  | json |  <your_key>=<your_string>  |   __error__=""[1m]))
  • logfmt
 sum by  (pod,namespace,application) (count_over_time({pod="<pod>",namespace="<namespace>",applications="<applications>"}  | logfmt |  <your_key>=<your_string>  |   __error__=""[1m]))

高级模式

采用 LogQL 原生语句直接提交 Rules。

上述 3 种 LogQL 预制模板,最终提交的格式化 alertrules 结构如下:

  - name: should_fire
rules:
- alert: <your_log_string>-alert
expr: sum by (pod,namespace,application) (count_over_time({pod="<pod>",namespace="<namespace>",applications="<applications>"} |~ `<$your_log_string>` |~ `<$your_log_string>`[1m])) >= <$your_thresholds>
for: 1m
labels:
severity: <$your_severity>
pod: {{$labels.pod}}
namespace: {{$labels.namespace}}
application: {{labels.applicastions}}
annotations:
summary: message <your_log_string> alerting ,now has {{$labels.value}}.

Log Recording Rules

Recording Rules 允许用户预先将需要进行大量计算的表达式的结果转化保存为一组新的时间序列,并将其通过 remote_write的方式写入 Prometheus。在 KubeGems 中,平台将接入 Logging Observability 的应用预制了通用性的 Error Log Rules。

与 Alerting Rules 一样,Recoring Rules 如要 Loki Ruler 的支持,这部分将在 KubeGems Installer 初始化中部署到您的集群。

关于 Loki Ruler 对 RemoteWrite 的配置,可查考loki/remote-write

Log Metrics

Log Metrics 在 KubeGems 中,由用户提交的日志采集器中声明,这部分采用 fluent-plugin-prometheus,核心部分即为每个进入管道的日志流创建一个 计数器(Counter)并记录其条目和元数据。

  - prrometheus:
labels:
container: $.kubernetes.container_name
namespace: $.kubernetes.namespace_name
node: $.kubernetes.host
pod: $.kubernetes.pod_name
metrics:
- desc: Total number of log entries generated by either application containers
or system components
name: logging_entry_count
type: counter

最终由 Prometheus 将指标logging_entry_count持久化到本地。

总结

KubeGems 中基于租户的日志采集方案整体设计采用 Logging Operator + Loki 架构,用户可根据企业自身组织结构对其进行管理和适配。对于在 Kubernetes 集群中操作原生的 CRD 资源复杂的场景下,KubeGems 尽量让用户在接入日志采集、监控和告警的三个方面做到开箱即用的功能,极大简化系统管理者或研发人员的是学习和接入成本。

· One min read
yud

主要数据模型

pic

数据模型的主要层级关系为 租户 -> 项目 -> 环境 -> 应用;

对应到集群中的以下资源

资源简写group/version是否是namespaced资源Crd
environmentstenvgems.kubegems.io/v1beta1falseEnvironment
tenantgatewaystgwgems.kubegems.io/v1beta1falseTenantGateway
tenantnetworkpoliciestnetpolgems.kubegems.io/v1beta1falseTenantNetworkPolicy
tenantresourcequotastquotagems.kubegems.io/v1beta1falseTenantResourceQuota
tenantstengems.kubegems.io/v1beta1falseTenant
  • 系统内顶级资源为租户和集群, 租户和集群都由系统管理员添加;租户与集群通过TenantResourceQuota关联,一个租户在一个集群下只能存在一个TenantResourceQuota; 租户映射到集群中的CRD为Tenant, 租户CRD下存在网络隔离策略(TenantNetworkPolicy)资源限制(TenantResourceQuota)以及租户网关(TenantGateway), 这些子资源都将在租户crd创建的时候默认创建;
  • 用户(Users)与租户,项目,环境都存在着关联关系,这些关联关系将为以后的用户权限提供数据支持;
  • 项目仅仅是平台侧的概念,它表示一组应用的集合
  • 环境与集群的namespace关联,实现环境隔离,资源限制,网络隔离等,环境则更多的是运维相关属性;
  • 应用表示真实的应用

用户权限

系统的用户权限主要通过角色实现, 角色又分为系统级角色,租户级角色,项目级角色环境级角色;

系统级角色

  • 系统管理员的职责是管理系统资源,集群,集群插件,租户等; 系统管理员拥有一切资源的操作权限和读权限
  • 普通用户代表 KubeGems 中的普通成员,用普通用户角色的账号仅能登陆系统,其他租户,项目等权限将根据租户和项目下的角色判断

租户级角色

  • 租户管理员的主要职责是负责租户的成员管理和项目管理,负责项目添加和删除,租户成员的添加和修改; 租户管理员拥有租户下的一切资源操作权限和读权限

  • 租户成员默认仅可以读租户下的项目信息; 在添加项目成员环境成员的时候,用户必须是租户成员才能作为项目成员和环境成员的备选项;

项目级角色

  • 项目管理员的职责是负责项目的成员管理,项目的环境管理和项目下的应用管理; 项目管理员拥有项目下的一切资源的操作权限和读权限;

  • 项目成员拥有三个角色,分别是开发 测试 运维

    • 项目开发成员可以读所有环境,只能操作开发类型的环境
    • 项目测试成员可以读所有环境,只能操作测试类型的环境
    • 项目运维成员可以读所有环境,可以操作开发 测试 生产类型的环境

环境级角色

  • 环境reader在默认情况下,项目成员是所有环境的reader,即只要是项目成员,就能读取所有的环境数据

  • 环境operator通常不需要配置这个角色,但是有特殊的情况,例如开发需要操作生产环境的资源,默认情况下开发人员只能操作开发环境,这时候授权开发人员在生产环境是operator的角色,就可以操作生产环境了;

登陆模块

需求

支持多源登陆(ldap, oauth2)

  • 本地认证,支持账号+密码登陆

  • 外部认证,支持ldap和oauth2的认证

登陆设计

插件式设计,允许不同类型的登陆源实现登陆插件即可,插件目前分为两类,分别是OAUTHLDAP

插件需要实现接口aaa.AuthenticateIface接口

type AuthenticateIface interface {
// 返回登陆插件的名字
GetName() string
// 返回登陆地址
LoginAddr() string
// , 获取用户信息
// 验证凭据,获取根据用户提供的凭据获取用户信息
GetUserInfo(ctx context.Context, cred *Credential) (*UserInfo, error)
}

登陆流程:

  1. LDAP类型和默认账号密码登陆,直接提供登陆的用户和密码以及登陆源即可,登陆后将获得token

  2. OAUTH类型,先获取登陆地址,重定向到登陆地址,通常这个登陆地址为第三方平台的认证授权界面,授权后第三方将会重定向到平台配置的一个地址,并且携带着第三方平台的一个授权code,平台通过这个code获取access_token,再带着这个access_token访问用户信息,通过第三方平台中的用户名作为kubegems中的用户,登陆成功后获得token

认证设计

插件式设计,目前仅实现了基于JWT的认证方式; 需要实现接口aaa.UserGetterIface

type UserGetterIface interface {
GetUser(req *http.Request) (u user.CommonUserIface, exist bool)
}

认证流程

不同的认证插件, 从请求头中获取需要的信息,例如通过Authorization头获取Bearer token,通过获取到的信息载入用户,如果没有找到用户,则表示未登陆