go语言-k8s宿主信息采集运维脚本

news2024/11/19 20:31:38

背景

由于工作需要,需要采集k8s集群中的宿主相关信息,包括cpu,memory,lvm,标签等信息。通常作为SRE会主选shell或python脚本来实现。但最近我们团队主流开发语言已经切换到golang.所以本次尝试用go语言来写写运维脚本。

实现流程图

代码实现

package main

import (
	"errors"
	"fmt"
	"github.com/gocarina/gocsv"
	"log"
	"os"
	"os/exec"
	"strings"
	"time"
)

// K8SNode 描述宿主节点
type K8SNode struct {
	IP           string `csv:"ip"`
	CPUSize      string `csv:"cpu_size"`
	MemorySize   string `csv:"memory_size"`
	LVMSize      string `csv:"lvm_size"`
	VMINum       int    `csv:"vmi_num"` // 虚拟机个数
	ProjectLabel string `csv:"project_label"`
}

// NodeDescribeOutput 执行kubectl describe node 指定ip后面的输出内容
func NodeDescribeOutput(ip string) (string, error) {
	cmd := "kubectl  describe node " + ip
	log.Printf("execut command: %s\n", cmd)
	output, err := ExecCmd(cmd)
	if err != nil {
		log.Println("err:", err)
		return "", err
	}
	return output, nil
}

// CpuSize 获取节点cpu
func CPUSize(describeInfo string) (string, error) {

	describeInfoList := strings.Split(describeInfo, "\n")
	for _, line := range describeInfoList {
		if strings.Contains(line, "cpu:") {
			cpusizelist := strings.Split(line, ":")
			//log.Printf("cpusize: %s", cpusizelist[1])
			size := strings.Replace(cpusizelist[1], " ", "", -1)
			return size, nil
		}
	}
	return "", errors.New("not found cpu size.")
}

// MemorySize 获取节点内存大小
func MemorySize(describeInfo string) (string, error) {

	describeInfoList := strings.Split(describeInfo, "\n")
	for _, line := range describeInfoList {
		if strings.Contains(line, "memory:") {
			memorysizelist := strings.Split(line, ":")
			size := strings.Replace(memorysizelist[1], " ", "", -1)
			return size, nil
		}
	}
	return "", errors.New("not found memory size.")
}

// LVMSize 获取节点本地磁盘大小
func LVMSize(describeInfo string) (string, error) {

	describeInfoList := strings.Split(describeInfo, "\n")
	for _, line := range describeInfoList {
		if strings.Contains(line, "lvm:") {
			sizelist := strings.Split(line, ":")
			size := strings.Replace(sizelist[1], " ", "", -1)
			return size, nil
		}
	}
	return "", errors.New("not found memory size.")
}

// VMINum 统计节点已经允许vmi的数量(vmi表示在k8s+kubevirt中KVM对应的对象)
func VMINum(describeInfo string) (int, error) {

	describeInfoList := strings.Split(describeInfo, "\n")
	var count int
	for _, line := range describeInfoList {
		if strings.Contains(line, "irt-launcher-") {
			count++
		}
	}
	return count, nil
}

// ProjectLabel 获取节点项目标签[我们业务定义project表示宿主用于哪一个项目]
func ProjectLabel(describeInfo string) (string, error) {

	describeInfoList := strings.Split(describeInfo, "\n")
	for _, line := range describeInfoList {
		if strings.Contains(line, "project=") {
			//log.Printf("cpusize: %s", cpusizelist[1])
			label := strings.Replace(line, " ", "", -1)
			label = strings.Replace(label, "project=", "", -1)
			label = strings.Replace(label, "\n", "", -1)
			return label, nil
		}
	}
	return "", errors.New("not found project label.")
}

// ExecCmd 对exec.Command()的封装
func ExecCmd(cmdstr string) (string, error) {

	cmd := exec.Command("bash", "-c", cmdstr)
	res, err := cmd.Output()
	if err != nil {
		return "", err
	}
	return string(res), nil

}

// GetIPList 获取集群中节点对应的IP列表
func GetIPList() []string {

	cmd := "kubectl get  node |grep -E \"[0-9]\" |awk '{print $1}'"
	log.Printf("execut command: %s\n", cmd)
	output, err := ExecCmd(cmd)
	if err != nil {
		log.Println("err:", err)
		var nilIPList []string
		return nilIPList
	}
	return strings.Split(string(output), "\n")
}

// 将结构体切片转换为csv文件
func WriteToCsv(filename string, nodes []*K8SNode) {
	// 创建csv文件
	os.Chdir("/tmp")
	nodesFile, err := os.OpenFile(filename, os.O_RDWR|os.O_CREATE, os.ModePerm)
	if err != nil {
		panic(err)
	}
	defer nodesFile.Close()

	// 将结构体切片转换为csv文件
	if err := gocsv.Marshal(&nodes, nodesFile); err != nil { // Load clients from file
		panic(err)
	}
}

// uploadToFilesever 将文件通过scp命令传到文件服务器
func uploadToFilesever(filename string) error {
	cmd := "scp " + filename + " 172.17.123.89:/home/segops/app/nginx/data/tmp/"
	log.Printf("execut command: %s\n", cmd)
	_, err := ExecCmd(cmd)
	if err != nil {
		log.Println("err:", err)
		return err
	}
	return nil
}

func main() {

	// Nodes 保存节点的切片
	var Nodes = []*K8SNode{}
	// count 用于统计节点数量
	var count int

	ipList := GetIPList()
	// 依次处理每一个宿主节点IP
	for _, ip := range ipList {
		//fmt.Println(ip)
		if ip == "" {
			continue
		}
		count++
		var oneNode = &K8SNode{}
		oneNode.IP = ip

		describeNodeOutput, err := NodeDescribeOutput(ip)
		if err != nil {
			log.Printf("%s NodeDescribeOutput error.\n", ip)
		}

		cpusize, err := CPUSize(describeNodeOutput)
		if err == nil {
			oneNode.CPUSize = cpusize
		} else {
			oneNode.CPUSize = ""
		}

		memsize, err := MemorySize(describeNodeOutput)
		if err == nil {
			oneNode.MemorySize = memsize
		} else {
			oneNode.MemorySize = ""
		}

		lvmsize, err := LVMSize(describeNodeOutput)
		if err == nil {
			oneNode.LVMSize = lvmsize
		} else {
			oneNode.LVMSize = ""
		}

		vminum, err := VMINum(describeNodeOutput)
		if err == nil {
			oneNode.VMINum = vminum
		} else {
			oneNode.VMINum = -1
		}

		projectlabel, err := ProjectLabel(describeNodeOutput)
		if err == nil {
			oneNode.ProjectLabel = projectlabel
		} else {
			oneNode.ProjectLabel = ""
		}
		fmt.Printf("%v\n", oneNode)
		//log.Println(ProjectLabel(describeNodeOutput))

		// 将一个K8SNode对象加入切片
		Nodes = append(Nodes, oneNode)
	}
	//fmt.Println("nodemap=%v", nodeMap)
	fmt.Printf("===========================================================================================\n")
	fmt.Printf("=========================================统计结果===========================================\n")
	fmt.Printf("===========================================================================================\n")
	fmt.Printf("ip\t\tcpu\t\tmemory\t\tlvmsize\t\tvminum\t\tprojectlabel\n")
	for _, node := range Nodes {
		fmt.Printf("%s\t%s\t\t%s\t%s\t\t%d\t\t%s\n", node.IP, node.CPUSize, node.MemorySize, node.LVMSize, node.VMINum, node.ProjectLabel)
	}
	fmt.Println()
	fmt.Printf("node num is %d\n", count)

	fmt.Println()
	fmt.Println("write to csv file:")
	currentTime := time.Now().Format("20060102150405")
	hostname, _ := os.Hostname()
	csvfilename := hostname + "_" + "nodesinfo" + "_" + currentTime + ".csv"

	// 写入csv文件
	WriteToCsv(csvfilename, Nodes)

	// 上传到文件服务器
	err := uploadToFilesever(csvfilename)
	if err != nil {
		fmt.Println("upload csv file error.")
		return
	}

	// 定义下载文件的路径
	downloadPath := "http://172.17.123.89:8080/tmp/" + csvfilename

	fmt.Println()
	fmt.Println("csv file can download from: ", downloadPath)
	fmt.Println()
}

实现结果

​
17:35:14  ===========================================================================================
17:35:14  =========================================统计结果===========================================
17:35:14  ===========================================================================================
17:35:14  ip		cpu		memory		lvmsize		vminum		projectlabel
17:35:14  172.24.52.11	96		394687572Ki	4862Gi		7		personal-dev
17:35:14  172.24.52.12	96		394687572Ki	4862Gi		8		personal-dev
17:35:14  172.24.52.13	96		394682812Ki	4862Gi		2		personal-dev
17:35:14  172.24.52.14	96		394687572Ki	4862Gi		5		personal-dev
17:35:14  172.24.52.141	96		394687572Ki	4862Gi		1		tools
17:35:14  172.24.52.142	96		394687572Ki	4862Gi		0		personal-dev-unuse
17:35:14  172.24.52.143	96		394687572Ki	4862Gi		0		personal-dev-unuse
17:35:14  172.24.53.79	80		394679084Ki	3225Gi		0		unuse
17:35:14  172.24.53.93	72		131267356Ki	11431Gi		0		unuse
17:35:14  172.24.53.94	72		131267356Ki	11431Gi		0		unuse
17:35:14  
17:35:14  node num is 122
17:35:14  
17:35:14  write to csv file:
17:35:14  2024/03/07 17:35:14 execut command: scp hyd01-seg-admin01_nodesinfo_20240307173514.csv 172.17.123.89:/home/segops/app/nginx/data/tmp/
17:35:15  
17:35:15  csv file can download from:  http://172.17.123.89:8080/tmp/hyd01-seg-admin01_nodesinfo_20240307173514.csv

​

 

总结

用go脚本写了约300行,并不简洁。所以在工作实际中,如果写一些逻辑简单的脚本建议首选用shell或python。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1500682.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

移掉 K 位数字(LeetCode 402)

文章目录 1.问题描述2.难度等级3.热门指数4.解题思路4.1 暴力法4.2 贪心 单调栈 参考文献 1.问题描述 给你一个以字符串表示的非负整数 num 和一个整数 k,移除这个数中的 k 位数字,使得剩下的整数最小。请你以字符串形式返回这个最小的整数。 示例 1 …

【产品测试】Bug报告的四个元素,你知道吗?

前言 由于任何由人编写的程序都不可避免的存在着不符合测试需求的错误,也就是bug。因此需要一个方法来跟踪、分析和展示那些测试活动,避免偏离最小。这种方法称之为错误跟踪系统。它主要是有效的管理缺陷,实现以下作用: 1)减少由…

YOLOX论文解读

paper:YOLOX: Exceeding YOLO Series in 2021 official implementation:https://github.com/Megvii-BaseDetection/YOLOX 本文的创新点 本文在YOLOv3的基础上进行了一些改进:包括将检测头进行解耦的decoupled head、从anchor-based转为anc…

经典定时任务结构设计:时间轮(Timing Wheel)案例和实现原理

1、直接上案例 import io.netty.util.HashedWheelTimer; import io.netty.util.Timeout; import io.netty.util.TimerTask; import lombok.extern.log4j.Log4j2;import java.util.concurrent.TimeUnit;/*** ClassName Test* Author will* Date 2024/3/8 16:31* Version 1.0.1*…

【PCIe】TLP结构与配置空间

🔥博客主页:PannLZ 文章目录 PCIe TLP结构PCIe配置空间和地址空间 PCIe TLP结构 TLP 主要由3个部分组成: Header 、 数据(可选,取决于具体的TLP 类 型 ) 和 ECRC (End to End CRC, 可选)。TLP 都始于发送端的事务层,终…

网络仿真(二)

时延和丢包率 网络中的节点之间时延(延迟)和丢包率是衡量网络性能的两个关键指标。 时延(延迟):时延是指数据在网络中从一个节点传输到另一个节点所需的时间。这包括处理时延(数据在节点处理的时间&#x…

ENVI必须会教程—Sentinel-2数据的读取与波段组合加载

实验2:读取Sentinel-2影像 目的:了解Sentinel-2影像读取方法,熟悉各波段及组合 过程: ①读取数据:在标题栏选择“文件”选项,点击“打开为”,选择“光学传感器”,由于哨兵2号数据…

Java后端八股笔记

Java后端八股笔记 Redis八股 上两种都有可能导致脏数据 所以使用两次删除缓存的技术,延时是因为数据库有主从问题需要更新,无法达到完全的强一致性,只能达到控制一致性。 一般放入缓存中的数据都是读多写少的数据 业务逻辑代码&#x1f44…

#stm32外设总结电容触摸按键

BS8116A-3 IRQ 外部中断请求 NMOS输出内部上拉 SCL SDA IIC通信接口 VDD 供电电压2.2-5.5V Ct电容: 0~25 pF 电容越大灵敏度越低 1、 软件使用流程 初始化 将IIC的两个引脚初始化为复用开漏模式 按键引脚设置上拉输入 下降沿触发外部中断 void KEY_Init(void) {//uint8_t …

音视频学习笔记——实现PCM和H264合成MP4功能

本文主要记录实现PCM和H264合成MP4功能的整个框架&#xff0c;各个模块中FFmpeg的api使用流程&#xff0c;便于后续学习和复盘。 本专栏知识点是通过<零声教育>的音视频流媒体高级开发课程进行系统学习&#xff0c;梳理总结后写下文章&#xff0c;对音视频相关内容感兴趣…

2024最新算法:冠豪猪优化算法(Crested Porcupine Optimizer,CPO)求解23个基准函数(提供MATLAB代码)

一、冠豪猪优化算法 冠豪猪优化算法(Crested Porcupine Optimizer&#xff0c;CPO)由Mohamed Abdel-Basset等人于2024年提出&#xff0c;该算法模拟冠豪猪的四种不同保护机制&#xff1a;视觉、听觉、气味和物理攻击。第一和第二防御技术&#xff08;视觉和听觉&#xff09;反…

安装nexus + 部署私有maven仓库

安装nexus 部署私有maven仓库 文章目录 安装nexus 部署私有maven仓库1.下载2.解压3.修改配置文件4.启动5.访问6.查看默认密码7.创建私库8.修改代码配置文件9.在maven 的setting.xml中配置私库的账号密码10.运行manve 【deploy】命令测试11.maven项目引用私库12. 重新加载mave…

C/C++内存管理【C++】

目录 一、 C/C内存分布1. C内存管理方式(1) new和delete操作内置类型(2) new和delete操作自定义类型 二、 operator new与operator delete函数三、 malloc/free和new/delete的区别四、内存泄漏 一、 C/C内存分布 C/C程序的内存布局会因编译器和操作系统而有所不同&#xff0c;但…

红帆ioffice-udfGetDocStep.asmx存在SQL注入漏洞

产品简介 红帆iOffice.net从最早满足医院行政办公需求&#xff08;传统OA&#xff09;&#xff0c;到目前融合了卫生主管部门的管理规范和众多行业特色应用&#xff0c;是目前唯一定位于解决医院综合业务管理的软件&#xff0c;是最符合医院行业特点的医院综合业务管理平台&am…

上门服务小程序|上门服务系统成品功能包含哪些?

随着移动互联网的快速发展&#xff0c;上门服务小程序成为了一种创新的家政服务模式。它不仅为用户带来了极大的便利&#xff0c;还能在提高服务效率和质量方面发挥作用。通过上门服务小程序&#xff0c;用户可以轻松预约按摩或理疗服务&#xff0c;无需繁琐操作&#xff0c;只…

9、JavaWeb-文件上传-配置文件

P146 案例-文件上传-简介 文件上传&#xff0c;将本地图片、视频等文件上传到服务器&#xff0c;供其他用户浏览下载的过程。 文件上传前端页面三要素&#xff1a; 如果前端表单的编码格式选择的默认编码方式x-www.form-urlencoded&#xff0c;则提交的文件仅仅是文件名&…

【Linux进阶之路】网络 —— “?“ (下)

文章目录 前言一、概念铺垫1.TCP2.全双工 二、网络版本计算器1. 原理简要2. 实现框架&&代码2.1 封装socket2.2 客户端与服务端2.3 封装与解包2.4 请求与响应2.5 对数据进行处理2.6 主程序逻辑 3.Json的简单使用 总结尾序 前言 在上文我们学习使用套接字的相关接口进行了…

Python实现广义泊松模型(GeneralizedPoisson算法)项目实战

说明&#xff1a;这是一个机器学习实战项目&#xff08;附带数据代码文档视频讲解&#xff09;&#xff0c;如需数据代码文档视频讲解可以直接到文章最后获取。 1.项目背景 广义泊松模型&#xff08;Generalized Poisson Model&#xff09;是一种统计学中用于处理数据的分析方…

MATLAB环境下滚动轴承复合故障仿真信号及时频谱

滚动轴承是一种广泛应用于各类旋转机械的通用基础部件&#xff0c;其运行状态的正常与否往往会对于整台机器的寿命、可靠性和精度等性能产生直接的影响。据统计&#xff0c;旋转机械中30%的故障和大型异步电机中44%的故障是由故障轴承引起的&#xff0c;而位于轴承内圈和外圈的…

浏览器的缓存导致的问题

同一个网站 频繁回退进入&#xff0c;音频播放器失效等问题问题 1.打开浏览器-更多工具-任务管理器 2.可以看到缓存页面进程 3.频繁回退进入 就会出现问题 解决方法&#xff1a; try {var bfWorker new Worker(window.URL.createObjectURL(new Blob([1])));window.addEvent…