前面一节我们介绍了使用go-template截取属性,go-template功能非常强大,可以定义变量,使用流程控制等,这是jsonpath所不具备的.然而,jsonpth使用的时候更为灵活.通过上一节我们发现,我们想要找到某个具体属性,必须从最外层一层层向内找到具体属性,这对于嵌套层次非常深的yaml对象来说操作是非常繁琐的.而使用jsonpath只需要知道顶层对象,然后可以省略中间的对象,递归查找直接找到我们想要的属性,这在很多时候对我们在不清楚对象的层次但是清楚知道某个属性名称的时候获取这个属性的值是非常有帮助的.并且jsonpath可以使用下标索引数组对象,这在实际工作中也是非常有帮助的(比如虽然pod里可以包含多个containers,但是很多时候一个pod里只有一个container,使用go-template我们为了找到这个对象需要写一个遍历表达式,而使用jsonpath可以直接取第0个对象,省去了写循环的麻烦),还有一点很重要的是jsonpath是一个标准,这对于熟悉jsonpath的开发者来说使用起来方便很多.

jsonpath模板使用一对花括号( {} )把jsonpath表达式包含在里面( go-template 是双花括号).除了标准jsonpath语法外,kubernetes jsonpath模板还额外支持以下语法:

用""双引号来引用JSONPath表达式中的文本

使用 range end 来遍历集合(这点和go-template类似)

使用负数来从尾部索引集合

$操作符是可选的因为表达式默认总是从根节点开始选择
对象通过它的 String() 函数打印输出出来

假如有以下JSON字符串

"kind": "List", "items":[ "kind":"None", "metadata":{"name":"127.0.0.1"}, "status":{ "capacity":{"cpu":"4"}, "addresses":[{"type": "LegacyHostIP", "address":"127.0.0.1"}] "kind":"None", "metadata":{"name":"127.0.0.2"}, "status":{ "capacity":{"cpu":"8"}, "addresses":[ {"type": "LegacyHostIP", "address":"127.0.0.2"}, {"type": "another", "address":"127.0.0.3"} "users":[ "name": "myself", "user": {} "name": "e2e", "user": {"username": "admin", "password": "secret"} iterate list {range .items[*]}[{.metadata.name}, {.status.capacity}] [127.0.0.1, map[cpu:4]] [127.0.0.2, map[cpu:8]] quote interpreted string {range .items[*]}{.metadata.name}{’\t’} 127.0.0.1 127.0.0.2

使用jsonpath示例

kubectl get pods -o json
kubectl get pods -o=jsonpath='{@}'
kubectl get pods -o=jsonpath='{.items[0]}'
kubectl get pods -o=jsonpath='{.items[0].metadata.name}'
kubectl get pods -o=jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.status.startTime}{"\n"}{end}'

如果对象是集合类型,需要使用range关键字开始,以end关键字结果,同前面一节go-template类似.

我们通过以下示例来看如何通过jsonpath简单地获取到容器所在节点名称

[centos@k8s-master ~]$ kubectl get po consul-0 -ojsonpath='{..nodeName}'
k8s-node1
[centos@k8s-master ~]$

当然以上也可以通过grep来获取到同样的信息,并且对于很多熟悉linux命令的童鞋来说更为方便,如果仅仅是查看.grep确实更为方便,但是通过jsonpath是准确地获取到了一个属性的值,而grep则是截取的包含这个关键字的一行,如果我们要把获取的值作为下一个命令的的输入值时,通过grep获取的结果往往是需要处理的.例如通过grep获取到的结果如下

"k8s-node1",[centos@k8s-master ~]$ kubectl get po consul-0 -ojson|grep nodeName
        "nodeName": "k8s-node1",

这里想要准备的获取结果,产生要截取第二列值,然后再去掉引号,操作起来不如jsonpath方便.尤其在不同环境如果输出的格式不一样的话,通过字符串截取得到的结果可能是错误的.