0x00 前言
上一篇 已經介紹了jsonnet這個語法的一般用法, 學習之後就來體驗一下它的使用場景:
我們先寫好一些常用的部署配置模板, 比如Deployment, Service 等.
然後在需要臨時部署的時候 , 只需要寫最小化代碼, 完成配置文件的生成,驗證,部署.
0x01 相關工具
-
jsonnet
: 用於解析jsonnet源碼至json文檔, 安裝方式:brew install jsonnet
-
gojsontoyaml
: json格式向yaml格式轉換go install github.com/brancz/gojsontoyaml@latest
-
kubeval
: 驗證生成的yaml 是否是合法的k8s部署文件, 安裝:brew tap instrumenta/instrumenta && brew install kubeval
-
kubecfg
: 支持jsonnet文件的yaml展示, 以及與k8s集羣的交互, 詳見這裏 安裝:brew install kubecfg
-
開發環境
: 使用VSCode, 加上插件 Jsonnet NG就可以高亮, 格式化, 錯誤提示等.
0x02 模板文件編寫
先編寫兩個模板文件
deploy-base.jsonnet
{
name:: error 'name is required',
container:: error 'container is required',
apiVersion: 'apps/v1',
kind: 'Deployment',
metadata: {
name: $.name,
labels: { app: $.name },
},
spec: {
selector: { matchLabels: $.metadata.labels },
template: {
metadata: { labels: $.metadata.labels },
spec: {
containers: [
$.container { name: $.name },
],
},
},
},
}
service-base.jsonnet
{
name:: error 'name is required',
namespace:: error 'namespace is required',
# 定義默認值,外部可以覆蓋
port:: {
port: 8080,
targetPort: 8080,
},
apiVersion: 'v1',
kind: 'Service',
metadata: {
name: $.name,
namespace: $.namespace,
},
spec: {
selector: { app: $.name },
ports: [
$.port,
],
type: 'ClusterIP',
},
}
先來寫一個部署文件:
my-nginx.jsonnet
local deploy = import 'deploy-base.jsonnet';
deploy {
name: 'my-nginx',
container: {
image: 'nginx:1.12',
},
}
我們看到部署文件就比較簡單, 只需提供最基礎參數完成配置.
接下來看看, 如何使用上面的工具, 進行格式轉換/部署.
jsonnet 作用是翻譯成json格式, 此時, 這個json文件也是可以被kubectl 提交部署的.
但是, 一般我們還是習慣了使用 yaml 格式. 先看下圖效果:
當然, 這時候, 如果這個yaml 沒有問題的話, 我們可以直接在後面 , 再跟一個部署指令就好:
jsonnet my-nginx.jsonnet | gojsontoyaml | kubectl apply -f -
但是, 我們還是希望提交前先驗證一下:
接下來, 再寫一個
Service
服務試一下:
local service = import 'service-base.jsonnet';
service {
name: 'my-nginx',
namespace: 'dev',
}
執行轉換: jsonnet demo-svc.jsonnet | gojsontoyaml
apiVersion: v1
kind: Service
metadata:
name: my-nginx
namespace: dev
spec:
ports:
- port: 8080
targetPort: 8080
selector:
app: my-nginx
type: ClusterIP
問題不大.
到這裏, 似乎可以結束了.
但是, 我們發現, 每一個部署, 都要單獨寫一個文件, 是不是有點不夠優雅?
要是能把 Deployment, Service 這些寫在一個文件裏, 應該真的很香.
解決方法, 也是參考了 這裏, 關於 YAML Stream Output
的描述.
我們把兩個文件結合後, 效果如下:
local deploy = import 'deploy-base.jsonnet';
local service = import 'service-base.jsonnet';
local
a = deploy {
name: 'my-nginx',
container: {
image: 'nginx:1.12',
},
},
b = service {
name: 'my-nginx',
namespace: 'dev',
};
[a, b]
此時, 解析的方式稍有不同, 需要以 yaml 流的方法進行解析:
jsonnet -y my-service.jsonnet
得到結果:
---
{
"apiVersion": "apps/v1",
"kind": "Deployment",
"metadata": {
"labels": {
"app": "my-nginx"
},
"name": "my-nginx"
},
"spec": {
"selector": {
"matchLabels": {
"app": "my-nginx"
}
},
"template": {
"metadata": {
"labels": {
"app": "my-nginx"
}
},
"spec": {
"containers": [
{
"image": "nginx:1.12",
"name": "my-nginx"
}
]
}
}
}
}
---
{
"apiVersion": "v1",
"kind": "Service",
"metadata": {
"name": "my-nginx",
"namespace": "dev"
},
"spec": {
"ports": [
{
"port": 8080,
"targetPort": 8080
}
],
"selector": {
"app": "my-nginx"
},
"type": "ClusterIP"
}
}
...
這裏拿 gojsontoyaml
去轉換, 只能拿到一個yaml對象:jsonnet -y my-service.jsonnet | gojsontoyaml
, 這個就有點拉垮了 - -!
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: my-nginx
name: my-nginx
spec:
selector:
matchLabels:
app: my-nginx
template:
metadata:
labels:
app: my-nginx
spec:
containers:
- image: nginx:1.12
name: my-nginx
但是不影響我們進行驗證可用性, 和部署.
是不是到這裏就可以結束了?
不不不, 是時候請出 kubecfg
了.
來, 我們直接用kubecfg 查看一下jsonnet的yaml格式:kubecfg show my-service.jsonnet
---
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: my-nginx
name: my-nginx
spec:
selector:
matchLabels:
app: my-nginx
template:
metadata:
labels:
app: my-nginx
spec:
containers:
- image: nginx:1.12
name: my-nginx
---
apiVersion: v1
kind: Service
metadata:
name: my-nginx
namespace: dev
spec:
ports:
- port: 8080
targetPort: 8080
selector:
app: my-nginx
type: ClusterIP
還可以進行和線上的對比和部署更新:
kubecfg diff my-service.jsonnet
kubecfg update my-service.jsonnet
0x03 總結
我們已經有了Kustomize
這樣的模板化工具, 還需要 jsonnet
麼?
我的答案是需要的, 特別是在臨時部署, 比如只需要增加一個Service 之類的場景.
只需要打開VSCode
, 新加一個svc.jsonnet , 再加一個命令行, 就可以搞定.
另一個總結: kubectl
支持 json
, yaml
格式的部署文件, 以 -f
參數指定; 同時以 -k
的參數 支持kustomize
文件.
但是 kubectl
目前不支持jsonnet
格式,有兩種方案:
- 直接使用
kubecfg
進行維護 - 通過格式轉換工具, 拿到 yaml 文件後, 再通過
kubectl
進行部署.