监控与优化

从kube-prometheus定制k8s监控(三) 定制的原则

2020-08-30  本文已影响0人  SongRijie

上一篇介绍了如何借助kube-prometheus生成的通用配置文件,对k8s进行最基础的监控。 一般情况下这是不够的,我们仍旧需要配置告警的发送渠道、增加额外的告警条件、持久化历史数据、对系统应用(如mysql,kafka)的监控和指标收集,对自有应用的监控等等。 从这一篇开始,逐步分享笔者在定制过程中的经验。

定制的原则

kube-prometheus这个项目开发的其实是一个jsonnet的库,核心代码在jsonnet/kube-prometheus目录下, 其他文件大多是说明和例子。 通过jsonnet解释执行example.jsonnet这个入口,在manifests/目录下生成之前提到的配置文件。

这个项目用到了很多上游的jsonnet库,比如:

完整列表在jsonnet/kube-prometheus/jsonnetfile.json`。

由于项目本身处于很早期,变化大,问题也不少,所以我们要做好时不时更新上游库的准备。 笔者就遇到过几次莫须有的告警,其实是上游kubernetes-mixin的告警策略不合理造成的。 好在几次问题修复都比较快,看到PR被合并后,用命令更新上游库,重新编译配置文件,再应用到集群中解决问题。

所以,定制要利用jsonnet的mixin,不是简单地修改manifests/下生成的配置,也不能去修改库中的代码。 否则,每次更新库之后都需要重做修改。

关于jsonnet

定制绕不开要了解jsonnet

jsonnet是google开发的模板语言(data templating language),可以定义和生成json。 jsonnet支持变量、函数、条件、运算、包管理、错误处理等,用来更方便的维护配置文件。 创造一个新的语言来解决工程问题,算是西方工程师的文化。

jsonnet有c++和golang两个版本, jsonnet-builder是jsonnet的包管理工具。

jsonnet虽然资料很少,但语言本身不复杂。3-4个小时就能大致读完官网提供的Tutorial和Standard Library。不过笔者并非专业coder,对这个语言运用的理解足足花了一两周的时间。 我理解的几个要点:

编译环境

照着readme里Customizing Kube-Prometheus去做就行了。

安装golang运行环境

不细说了。

安装jsonnet-builder, jsonnet和gojsontoyaml

$ go get github.com/jsonnet-bundler/jsonnet-bundler/cmd/jb
$ brew install jsonnet
$ go get github.com/brancz/gojsontoyaml

克隆kube-prometheus库

$ mkdir kube-prometheus; cd kube-prometheus
$ jb init
$ jb install github.com/prometheus-operator/kube-prometheus/jsonnet/kube-prometheus@release-0.4

更新自身和依赖的库

$ jb update

所有库文件都保存在vender/文件夹下。

编译

example.jsonnet是定制的起点,我们先复制这个文件到你自己命名的项目文件,比如我们是wk-mixin.jsonnet,然后用jsonnet执行。

$ cp example.jsonnet wk-mixin.jsonnet
$ ./build.sh wk-mixin.jsonnet
+ set -o pipefail
++ pwd
+ PATH=/Users/Roger/Documents/Program/git/kube-prometheus/tmp/bin:/usr/local/opt/mysql-client/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/go/bin:/usr/local/opt/mysql-client/bin:/Users/Roger/Documents/Program/golib/bin:/usr/local/go/bin:/Users/Roger/Documents/Program/golib/bin
+ rm -rf manifests
+ mkdir -p manifests/setup
+ jsonnet -J vendor -m manifests wk-mixin.jsonnet
+ xargs '-I{}' sh -c 'cat {} | gojsontoyaml > {}.yaml; rm -f {}' -- '{}'

如果运行成功,manifests/目录下应该会生成很多yaml文件。 这代表你把基本编译环境跑通了。

如果你对这个定制项目使用版本管理,vendor/manifests/都是不需要提交的。

对示例的理解

在自己动手定制之前,我们先要理解当前的配置文件是如何生成出来的。

build.sh

我们先来看一下编译脚本build.sh。 关键部分只有一行:

jsonnet -J vendor -m manifests "${1-example.jsonnet}" | xargs -I{} sh -c 'cat {} | gojsontoyaml > {}.yaml' -- {}

example.jsonnet

再看example.jsonnet的内容(以release-04为例):

example.jsonnet.png

整个文件其实分两个部分:

  1. L1-14定义了变量kp, 你可以不断用+去添加和覆盖。
  2. L2(import xxx.libsonnet)就是简单地把libsonet的内容替换到这个位置。
  3. L10-14实际是一个替换操作。代码里约定俗成,所有用到namspace的地方,都会从$_config.namespace获取。 这里利用+和"late bound",等同于替换了所有引用namespace的地方。 另外,我们注意到L11中的_config+::用的是双引号,代表_config这个对象,不会出现在最后json的结果中。
  4. L16-28控制实际的输出。以L23为例,上面提到build.sh会用最顶层的键名作为文件名,这行输出的文件名是['node-exporter-' + name], 其中name是通过 std.objectFields()这个标准函数,循环读取某个键下元素名,这个例子里是kp.nodeExporter代表kp变量中nodeExporter下的元素。

有个要点,各个库习惯把可配置的变量写在{_config:: {<组件名>: { ... } } }, 定制的时候用+直接修改。那么如何知道哪些变量可以设置呢?一种方法是读项目里提供的例子,另一种就是读库的源码。 另外,对某些设置,可能库并没有提供_config下的变量, 一般来说,这是库作者不推荐修改的,但是你仍旧可以利用jsonnet的特性去做,通常更复杂些。

如何开始定制?

针对已有组件的配置修改

在动手之前,推荐先阅读所有的例子,如果恰巧有匹配的,就照例子修改,主要是对变量kp的修改。这些例子包括:

监控其他通用系统

如果是基于已有组件的配置修改,大部分在例子里都能找到。 但如果是要添加新的监控对象,比如kafka,则需要做这些工作:

监控自有应用

自有应用需要自己编写全部内容。

测试环境和生产环境

最后提一下环境的切换。 从测试的角度,配置修改都需要在测试环境运行通过后,再应用到生产环境中。 这两个环境不完全相同,比如域名,告警邮件地址,告警的钉钉群等等。 如何能方便的切换生成这两个环境的配置?分享一下我的经验:

{
    "domain": ".example.wukongbox.cn",
    "email": "example@wukongbox.com",
    "ding": "000000000000000000000000000000000000000000000000000000"
}
local kp =
  ...
  {
    _config+:: {
    ...
      wukongbox: 
      // read env type
      local env = std.extVar("env");

      // loading envs from external json
      if env == 'production' then 
        (import 'wk-env-production.json')
      else 
        (import 'wk-env-lab.json'),
      ...

后面的文章,对我们自己项目里曾经做过的定制,我会一个个来举例说明,希望对其他人有帮助。

上一篇 下一篇

猜你喜欢

热点阅读