Please enable Javascript to view the contents

文档工具化 - Ops 工具

 ·  ☕ 6 分钟

1. 什么是文档工具化

文档工具化,工具产品化,是我之前博文中反复提过的一个口号。

好的文档,不如好用的工具。一个脚本、一条命令,比阅读文档更加直接,更能快速解决问题。同时,有很多文档会让读者对知识产生眩晕,在急于解决问题的窗口期无法补全知识体系的情况下,很容易出现错误的理解。

这种有领域壁垒的知识,需要融入一点设计对其进行转换,才能让用户更好的使用。这就是文档工具化的意义。

从文档到工具,从工具到产品,雕琢地痕迹会越来越明显,这是一个很有趣的过程,不断地去掉冗余,去掉不必要的东西,让用户更加专注于解决问题。

2. Ops 工具

有了上述想法之后,我一直希望能够将平时工作中的一些操作,通过工具的方式进行封装,让这些操作能够得到更好的复用。

半年多前,我新建了一个项目,叫做 ops,主要用来辅助我完成工作中的一些操作。

如上图,是这个项目的一个构想。设计理念在于,运维工具的核心在于文本分发和脚本执行,实现了这两种能力就能够满足运维的功能需求。

目前,我面向的运维对象是 Host 主机、Kubernetes 集群,很少直接面向容器。因此在 OpsObject 层实现了 Host 和 Cluster 对象,分别对应主机和 Kubernetes 集群。

而在此之上,分别实现了面向主机的文件分发、脚本执行,以及面向 Kubernetes 集群的文件分发、脚本执行,也就是 Core 核心能力层。

得益于 Core 层的能力,我已经可以实现一些简单的运维功能,比如:批量添加 hosts,批量安装、变更 Prometheus 等。

但这还不够,很多运维操作不是单步能够完成,因此需要一些流程控制,比如: 备份集群之前,需要先安装 Velero,安装 Velero 之前,需要先安装 Helm 等。因此引入了一个新的对象 Task,用于完成编排,这样其实就和 Ansible 很像了。

在 Tools 层,我提供了三个入口,:opscli、opsserver、opscontroller。目前主要完成了 opscli 和 opscontroller 两个部分。

3. opscli

opscli 是一个静态的二进制文件,支持 Linux 和 macOS 系统,可以通过 curl 命令直接下载使用。

3.1 安装

如果网络连接 GitHub 很好,可以使用下面的命令安装:

1
curl -sfL https://raw.githubusercontent.com/shaowenchen/ops/main/getcli.sh | VERSION=latest sh -

如果网络连接 GitHub 不好,可以使用下面的命令安装:

1
curl -sfL https://cf.ghproxy.cc/https://raw.githubusercontent.com/shaowenchen/ops/main/getcli.sh |VERSION=latest sh -

3.2 配置自动补全

  • 如果使用 bash
1
echo 'source <(opscli completion bash)' >>~/.bashrc
  • 如果使用 zsh
1
echo 'source <(opscli completion zsh)' >>~/.zshrc

3.3 使用

  • 查看帮助
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
opscli --help

Usage:
  opscli [command]

Available Commands:
  completion  Generate the autocompletion script for the specified shell
  create      command about Ops Resource
  file        transfer between local and remote file
  help        Help about any command
  shell       run shell on hosts
  task        command about task
  upgrade     upgrade to latest version
  version     get current version
  • 面向主机,远程执行命令
1
2
3
opscli shell -i 1.1.1.1 --port 2222 --username root --content "uname -a"

Linux node1 5.4.219-1.el7.elrepo.x86_64 #1 SMP Sun Oct 16 10:03:45 EDT 2022 x86_64 x86_64 x86_64 GNU/Linux

这里的 -i 可以指向一个 ip,也可以指向一个文件,文件中包含多个 ip,每行一个 ip。--content 指向要执行的命令,也可以是脚本文件。

  • 面向集群,远程执行命令
1
opscli shell -i ~/.kube/config --content "docker pull shaowenchen/ops-cli:latest" --sudo  --all

这里的 -i 指向一个 kubeconfig 文件,--all 表示对集群中的所有节点都执行命令,如果不加 --all,则只会在 master 节点执行命令,使用 --nodename 可以指定指向命令的节点。

另外有一个特殊的参数 --incluster 表示这条命令将会在集群的某一个 Pod 运行,这在集群内部检测问题时非常有用。

  • 面向主机,文件分发

文件的分发,是一个映射的过程,本地、远程两个目标 + 数据流方向。

1
opscli file --remotefile /etc/hosts --localfile ./file1 --direction download -i 1.1.1.1 --port 2222 --username root

这里的 --direction 表示数据流方向,download 表示从远程下载到本地,upload 表示从本地上传到远程。

  • 面向集群,文件分发
1
opscli file --remotefile /etc/hosts --localfile ./file1 --direction download -i ~/.kube/config --nodename node1

这里的 --nodename 表示目标节点。

实际上文件分发,还支持源文件来自镜像、S3,这里就不一一列举了。

  • task 使用
1
2
3
4
5
6
7
8
9
ls ~/.ops/tasks/

add-file2image.yaml          alert-http-status.yaml       app-openebs.yaml             get-kubeconfig.yaml          pull-file.yaml               upgrade-1.16m.yaml           upgrade-kernel3to5.yaml
add-imagepullsecret.yaml     alert-promql.yaml            app-prometheus.yaml          get-osstaus.yaml             push-file.yaml               upgrade-1.16n.yaml           velero-backup.yaml
add-localbinpath.yaml        app-descheduler.yaml         clear-docker.yaml            k8s-drain-node.yaml          renew-kube-cert.yaml         upgrade-1.17m.yaml           velero-install.yaml
add-opscli.yaml              app-grafana.yaml             clear-kube.yaml              k8s-hpa.yaml                 set-docker-liverestore.yaml  upgrade-1.17n.yaml           velero-restore.yaml
add-reqlimit.yaml            app-istio.yaml               clear-opstask.yaml           list-podimage.yaml           set-hosts.yaml               upgrade-1.19m.yaml           velero-status.yaml
add-sshkey.yaml              app-longhorn.yaml            get-diskio-byfio.yaml        list-reqlimit.yaml           set-hubimage.yaml            upgrade-1.19n.yaml           velero-uninstall.yaml
add-superuser.yaml           app-metricsserver.yaml       get-imagefile.yaml           list-svc.yaml                set-kernel.yaml              upgrade-base.yaml

~/.ops/tasks/ 目录下,有很多的 task yaml 文件,可以直接使用。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
opscli task -f ~/.ops/tasks/get-osstaus.yaml -i 1.1.1.1 --port 2222 --username root

> Run Task  /  on  1.1.1.1
(1/11) Kernel Version
5.4.219-1.el7.elrepo.x86_64
(2/11) CPU Usage Percent/Load/Total
10.11%/0.00/4
(3/11) Mem Usage Percent/Total
33.02%/7.8G
(4/11) Disk Usage Percent/Total
69%/52G /dev/mapper/centos-root
35%/1.1G /dev/sda1
4%/26G /dev/mapper/centos-home
(5/11) NF_Conntrack Usage/Total
1344/131072
(6/11) PID Usage
1.57%/65535
(7/11) ARP Router
0.02%/80000
(8/11) Open Files Number
1.29%/1048576
(9/11) User Instances
0.23%/8192
(10/11) User Watches
0.00%/524288
(11/11) User Processes
360/31711

如果是面向集群,只需要将 -i 指向一个 kubeconfig 文件,然后加上 --all 或者指定 --nodename 即可。

4 opsserver

这部分还在开发中,主要是为了提供一个 HTTP API,以供其他系统、脚本调用。

5 opscontroller

5.1 安装

  • 安装 Helm
1
curl https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 | bash
  • 添加 Helm 仓库
1
helm repo add ops https://www.chenshaowen.com/ops/charts
  • 安装 ops-controller
1
helm install myops ops/ops --version 1.0.0 --namespace ops-system --create-namespace
  • 查看安装结果
1
kubectl get pods -n ops-system

opscontroller 默认只会处理 ops-system 命名空间下的 CRD 资源对象。

如果需要变更,可以修改 Env 中 ACTIVE_NAMESPACE 的值,指定某一个命令空间,如果为空,则表示处理所有命名空间。

5.2 使用

  • 创建一个主机对象
1
opscli create host --name dev1 -i 1.1.1.1 --port 2222 --namespace ops-system
1
2
3
4
5
6
7
8
kubectl -n ops-system get hosts

NAME   HOSTNAME   ADDRESS       DISTRIBUTION   ARCH     CPU   MEM    DISK   HEARTTIME   HEARTSTATUS
dev1   node1      1.1.1.1       centos         x86_64   4     7.8G   52G    59s         successed
dev2   node2      1.1.1.1       centos         x86_64   4     7.8G   52G    60s         successed
dev3   node3      1.1.1.1       centos         x86_64   4     7.8G   52G    0s          successed
dev4   node4      1.1.1.1       centos         x86_64   4     7.8G   52G    2s          successed
dev5   node5      1.1.1.1       centos         x86_64   1     1.8G   95G    0s          successed

controller 会定时检测主机的状态,并将主机的状态更新到 host 对象中。

  • 创建一个集群对象
1
opscli create cluster --name dev1 -i ~/.kube/config --namespace ops-system
1
2
3
4
5
6
7
8
kubectl -n ops-system get cluster

NAME   SERVER                       VERSION   NODE   RUNNING   TOTALPOD   CERTDAYS   STATUS
dev1   https://1.1.1.1:6443         v1.21.0   1      14        14         193        successed
dev2   https://1.1.1.1:6443         v1.23.0   3      22        22         350        successed
intl   https://1.1.1.1:6443         v1.21.4   1      18        95         268        successed
prod   https://1.1.1.1:6443         v1.21.4   10     134       1098       183        successed
test   https://1.1.1.1:6443         v1.21.4   1      23        23         227        successed

controller 会定时检测集群的状态,并将集群的状态更新到 cluster 对象中。

  • task 任务也可以通过 opscli 创建,但我更希望的是用 yaml 直接创建

controller 主要是定时执行 task 对象中的任务。比如清理集群,提供告警等。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
kubectl -n ops-system get task

NAME                             CRONTAB       TYPEREF   NAMEREF   NODENAME   ALL    STARTTIME   RUNSTATUS
alert-http-status-dockermirror   */1 * * * *
alert-http-status-harbor        */1 * * * *
alert-http-status-git           */1 * * * *
alert-http-status-mirror-go      */1 * * * *
alert-http-status-mirror-maven   */1 * * * *
alert-http-status-mirror-npm     */1 * * * *
alert-http-status-mirror-pypi    */1 * * * *
alert-promql-node-cpu            */1 * * * *
alert-promql-node-disk           */1 * * * *
alert-promql-node-io             */1 * * * *
alert-promql-node-mem            */1 * * * *
alert-promql-pending             */1 * * * *
alert-promql-pending-pod         */1 * * * *
alert-promql-pvc                 */1 * * * *
alert-trigger-autotest           */5 * * * *
clear-docker                     15 * * * *    cluster   prod                 true
clear-opstask-dev1               10 * * * *    cluster   dev1
clear-opstask-dev2               10 * * * *    cluster   dev2
clear-opstask-prod               10 * * * *    cluster   prod
clear-opstask-test               10 * * * *    cluster   test

通过 TYPEREF 指向对象类型,NAMEREF 指向对象名称。上面是我生产环境的配置,下面是发出的告警通知。

alert 告警如上图,主要支持两种方式,一种是通过 promql 查询,另一种是通过 http 请求。

定时任务 clear-docker 会清理集群每个节点上的构建残留物,clear-opstask 会清理因执行集群 Ops 错误时产生的 Pod。

6. 总结

这个项目主要是为了方便我自己运维主机和管理集群,同时提供了周期任务能力,以及告警能力。目前还在开发中,后续会继续完善。

在工作中去抽取项目,不是一件容易的事,需要找到项目和工作之间的契合点。很多工作中的项目和业务紧密耦合,无法抽取;而如果脱离工作,没有实际的业务场景打磨,项目也很难有价值。

起初 opscli 有很多的子命令用于满足各种场景,但是后来我又通过 task 对象来重新实现。这样做的好处是,task 对象可以作为公司敏感数据单独存放和配置,而功能实现部分可以放开限制,不用担心敏感信息泄露。

当然,Ansible 也实现了类似的功能,程序员的快乐之一也是不断地重复造轮子。在造轮子的过程中,我也重新学习了一遍 CRD 开发,也学习了 Helm Chart 的开发,并将其发布到了 https://artifacthub.io/

7. 参考


微信公众号
作者
微信公众号