1. yaml复杂语法
YAML最重要的两个东西,一定要掌握这两种数据和熟悉转换为json是怎么样的
- 对象:键值对的集合,又称为映射(mapping)/ 哈希(hashes) / 字典(dictionary,yaml整个文件本身就是一个对象。
下面写一个关于prometheus的resource.yaml文件
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
creationTimestamp: null
labels:
prometheus: k8s
role: alert-rules
name: prometheus-template-rules
namespace: monitoring
转换为json对象是:
{
"apiVersion": "monitoring.coreos.com/v1",
"kind": "PrometheusRule",
"metadata": {
"creationTimestamp": null,
"labels": {
"prometheus": "k8s",
"role": "alert-rules"
},
"name": "prometheus-template-rules",
"namespace": "monitoring"
}
}
值得注意的是像metadata这样的一个对象里面有多个key,value键值对的情况,一定要熟悉这种缩进代表什么。其实缩进多少空格没所谓,主要是同等位置的东西要对齐,就像creationTimestamp与labels,name,namespace都是matadata里面的键值对,一定要对齐。
- 数组:一组按次序排列的值,又称为序列(sequence) / 列表(list)
spec:
groups:
- name: kkdd
rule:
- alert: ingressAlert
for: 1s
expr: xioad
labels:
nodename: '{{.NodeName}}'
annotations:
containerID: label.name
podName: label.pod
- alert: egressAlert
for: 1s
expr: xxxxadad
转为json的结果,结果就是groups是一个list,里面包含了一个对象,而rule也是一个list,但是里面有2个对象。
{
"spec": {
"groups": [
{
"name": "kkdd",
"rule": [
{
"alert": "ingressAlert",
"for": "1s",
"expr": "xioad",
"labels": {
"nodename": "{{.NodeName}}"
},
"annotations": {
"containerID": "label.name",
"podName": "label.pod"
}
},
{
"alert": "egressAlert",
"for": "1s",
"expr": "xxxxadad"
}
]
}
]
}
}
2. 替换模板中的变量
主要是想将带有变量的template.yaml通过够替换变量,生成结果yaml。
方案:golang提供了text/template包,我们可以用它来渲染模板。
第一步:准备模板,我在本目录下创建了一个template.yaml
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
creationTimestamp: null
labels:
prometheus: k8s
role: alert-rules
name: prometheus-template-rules
namespace: monitoring
spec:
groups:
{{- range .Resources}} ###这里主要是for循环一个结构体
- name: {{.NodeName}}-resources-limit-{{.ResourceValue}}unit.rules
rules:
- alert: ingressAlert {{"{{.value}} "}} {{"$"}}
for: 1s # status from pending to firing for 1s
# expr for test
expr: max(kube_pod_labels{label_unit="{{.ResourceValue}}"}) by (pod, label_unit) * on(pod) group_right(label_unit) (sum(rate(container_network_receive_bytes_total{namespace="default",node="{{.NodeName}}"}[5m])) BY (instance, pod) / 128) > 200 * {{.ResourceValue}}
labels:
nodename: "{{.NodeName}}"
annotations:
containerID: "{{"{{ $labels.name }}"}}" # notifications sended with the messages
podName: "{{"{{ $labels.pod }}"}}"
- alert: egressAlert
for: 1s # status from pending to firing for 1s
# expr for test
expr: max(kube_pod_labels{label_unit="{{.ResourceValue}}"}) by (pod, label_unit) * on(pod) group_right(label_unit) (sum(rate(container_network_transmit_bytes_total{namespace="default",node="{{.NodeName}}"}[5m])) BY (instance, pod) / 128) > 200 * {{.ResourceValue}}
labels:
nodename: "{{.NodeName}}"
annotations:
containerID: "{{"{{ $labels.name }}"}}" # notifications sended with the messages
podName: "{{"{{ $labels.pod }} "}}"
{{- end }}
第二步:写go代码,来替换;Golang的代码
需要循环的部分用到语法{{- range .Resources}},{{- end}}。用它包裹起来的部分可以重复生成,而且是拼接在一份文件中。
Golang的代码:
package main
import (
"bufio"
"fmt"
"io"
"log"
"os"
"strings"
"text/template"
)
type DeployTemplDatas struct {
Resources []DeployTemplData
}
type DeployTemplData struct {
NodeName string
ResourceValue int
}
//主入口函数
func main() {
nodeNms := []string{"nodeName1","nodeName2"}
resourceVals := []int{111,2}
dd := generateObjects(nodeNms,resourceVals)
ParseFiles(nodeNms,resourceVals)
}
func ParseFiles(nodeNms []string,resourceVals []int ){
t := template.New("test")
t = template.Must(template.ParseFiles("./template.yaml"))
data := generateObjects(nodeNms,resourceVals)
userFile := "result.yaml"
fout, err := os.Create(userFile) //create the file in the directory which the present file belongs to
if err != nil {
fmt.Println(userFile, err)
return
}
// 传入一个DeployTemplData结构体切片
t.Execute(fout, data)
}
// @title generateObjects
// @description to generate the objects with the different nodeName and resourceValue
//生成len(nodeNames)*len(resourceVals)个对象
func generateObjects(nodeNames []string,resourceVals []int) DeployTemplDatas{
datas := make([]DeployTemplData,0,len(nodeNames)*len(resourceVals))
for i :=0;i<len(nodeNames);i++{
for j:=0;j<len(resourceVals);j++{
data := DeployTemplData{
NodeName: nodeNames[i],
ResourceValue: resourceVals[j],
}
datas = append(datas, data)
}
}
temldatas := DeployTemplDatas{
Resources: datas,
}
return temldatas
}
第三步得到结果:
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
creationTimestamp: null
labels:
prometheus: k8s
role: alert-rules
name: prometheus-template-rules
namespace: monitoring
spec:
groups:
- name: nodeName1-resources-limit-1unit.rules
rules:
- alert: ingressAlert {{.value}} $
for: 1s # status from pending to firing for 1s
# expr for test
expr: max(kube_pod_labels{label_unit="1"}) by (pod, label_unit) * on(pod) group_right(label_unit) (sum(rate(container_network_receive_bytes_total{namespace="default",node="nodeName1"}[5m])) BY (instance, pod) / 128) > 200 * 1
labels:
nodename: "nodeName1"
annotations:
containerID: "{{ $labels.name }}" # notifications sended with the messages
podName: "{{ $labels.pod }}"
- alert: egressAlert
for: 1s # status from pending to firing for 1s
# expr for test
expr: max(kube_pod_labels{label_unit="1"}) by (pod, label_unit) * on(pod) group_right(label_unit) (sum(rate(container_network_transmit_bytes_total{namespace="default",node="nodeName1"}[5m])) BY (instance, pod) / 128) > 200 * 1
labels:
nodename: "nodeName1"
annotations:
containerID: "{{ $labels.name }}" # notifications sended with the messages
podName: "{{ $labels.pod }} "
- name: nodeName1-resources-limit-2unit.rules
rules:
- alert: ingressAlert {{.value}} $
for: 1s # status from pending to firing for 1s
# expr for test
expr: max(kube_pod_labels{label_unit="2"}) by (pod, label_unit) * on(pod) group_right(label_unit) (sum(rate(container_network_receive_bytes_total{namespace="default",node="nodeName1"}[5m])) BY (instance, pod) / 128) > 200 * 2
labels:
nodename: "nodeName1"
annotations:
containerID: "{{ $labels.name }}" # notifications sended with the messages
podName: "{{ $labels.pod }}"
- alert: egressAlert
for: 1s # status from pending to firing for 1s
# expr for test
expr: max(kube_pod_labels{label_unit="2"}) by (pod, label_unit) * on(pod) group_right(label_unit) (sum(rate(container_network_transmit_bytes_total{namespace="default",node="nodeName1"}[5m])) BY (instance, pod) / 128) > 200 * 2
labels:
nodename: "nodeName1"
annotations:
containerID: "{{ $labels.name }}" # notifications sended with the messages
podName: "{{ $labels.pod }} "
- name: nodeName2-resources-limit-1unit.rules
rules:
- alert: ingressAlert {{.value}} $
for: 1s # status from pending to firing for 1s
# expr for test
expr: max(kube_pod_labels{label_unit="1"}) by (pod, label_unit) * on(pod) group_right(label_unit) (sum(rate(container_network_receive_bytes_total{namespace="default",node="nodeName2"}[5m])) BY (instance, pod) / 128) > 200 * 1
labels:
nodename: "nodeName2"
annotations:
containerID: "{{ $labels.name }}" # notifications sended with the messages
podName: "{{ $labels.pod }}"
- alert: egressAlert
for: 1s # status from pending to firing for 1s
# expr for test
expr: max(kube_pod_labels{label_unit="1"}) by (pod, label_unit) * on(pod) group_right(label_unit) (sum(rate(container_network_transmit_bytes_total{namespace="default",node="nodeName2"}[5m])) BY (instance, pod) / 128) > 200 * 1
labels:
nodename: "nodeName2"
annotations:
containerID: "{{ $labels.name }}" # notifications sended with the messages
podName: "{{ $labels.pod }} "
- name: nodeName2-resources-limit-2unit.rules
rules:
- alert: ingressAlert {{.value}} $
for: 1s # status from pending to firing for 1s
# expr for test
expr: max(kube_pod_labels{label_unit="2"}) by (pod, label_unit) * on(pod) group_right(label_unit) (sum(rate(container_network_receive_bytes_total{namespace="default",node="nodeName2"}[5m])) BY (instance, pod) / 128) > 200 * 2
labels:
nodename: "nodeName2"
annotations:
containerID: "{{ $labels.name }}" # notifications sended with the messages
podName: "{{ $labels.pod }}"
- alert: egressAlert
for: 1s # status from pending to firing for 1s
# expr for test
expr: max(kube_pod_labels{label_unit="2"}) by (pod, label_unit) * on(pod) group_right(label_unit) (sum(rate(container_network_transmit_bytes_total{namespace="default",node="nodeName2"}[5m])) BY (instance, pod) / 128) > 200 * 2
labels:
nodename: "nodeName2"
annotations:
containerID: "{{ $labels.name }}" # notifications sended with the messages
podName: "{{ $labels.pod }} "
解析:
- 我准备了包含四个对象的切片Resources,然后遍历替换,生成了包含四个na,
- {{-}}中的-有何作用?可以除去占用此行的空格,如果不加这个 -,那么range会占用一行,即结果会在range行这里空一行。
- Resources是一个数组或者是切片,在循环里面的点"."代表的是当前循环数组中的每一个对象,对象里面的字段就可以用.XXX来表示了。
- 如果是想要安全替换,我们并不想{{.value}}被替换,忽略跳过此替换,原样输出{{.value}},方法是:{{" {{.value}} "}};详细可以看上面的例子,美元符号,点都有涉及了。
3. 总结
- 完成功能关键在于知道Golang的template的循环是使用{{range .xxx}}{{end}}语法;原样输出在模板中怎么写。
- 拓展,template还可以有其他的表达式,条件判断等等功能,详细点击—>李文周的博客