Kubernetes工做負載最經常使用YAML格式的文件來定義。javascript
YAML的問題之一就是很難描述清單文件之間的約束或關係。
若是你但願檢查是否已從受信任的註冊表中提取部署到羣集中的全部映像,該怎麼辦?
如何防止沒有Pod安全策略的工做負載提交到集羣?
集成靜態檢查能夠在更接近開發生命週期的時間內捕獲錯誤和違反策略的行爲。
而且因爲改善了資源定義的有效性和安全性,所以你能夠相信生產工做負載遵循最佳實踐。java
Kubernetes YAML文件的靜態檢查生態系統能夠分爲如下幾類:node
在本文中,你將學習到六個不一樣的工具:python
Kubeval Kube-score Config-lint Copper Conftest Polaris
Let's Go ~~~linux
首先部署一個基準服務,以便後面測試對比git
apiVersion: apps/v1 kind: Deployment metadata: name: http-echo spec: replicas: 2 selector: matchLabels: app: http-echo template: metadata: labels: app: http-echo spec: containers: - name: http-echo image: hashicorp/http-echo args: ["-text", "hello-world"] ports: - containerPort: 5678 --- apiVersion: v1 kind: Service metadata: name: http-echo spec: ports: - port: 5678 protocol: TCP targetPort: 5678 selector: app: http-echo
部署完成並驗證以下:github
[root@k8s-node001 Test]# kubectl get po NAME READY STATUS RESTARTS AGE http-echo-57dd74545-rtxzm 1/1 Running 0 65s http-echo-57dd74545-trst7 1/1 Running 0 65s [root@k8s-node001 Test]# kubectl get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE http-echo ClusterIP 10.102.221.64 <none> 5678/TCP 70s [root@k8s-node001 Test]# curl 10.102.221.64:5678 hello-world
以上YAML文件能部署成功,可是,它遵循最佳作法嗎?docker
Let's start.shell
kubeval的前提是與Kubernetes的任何交互都經過其REST API進行。
所以,可使用API模式來驗證給定的YAML輸入是否符合該模式。express
安裝kubeval
wget https://github.com/instrumenta/kubeval/releases/latest/download/kubeval-linux-amd64.tar.gz tar xf kubeval-linux-amd64.tar.gz cp kubeval /usr/local/bin
如今咱們來改下base.yaml,刪除
selector: matchLabels: app: http-echo
而後使用kubeval對base.yaml檢查
[root@k8s-node001 Test]# kubeval base.yaml WARN - base.yaml contains an invalid Deployment (http-echo) - selector: selector is required PASS - base.yaml contains a valid Service (http-echo)
輸出看到一個WARN,提示selector是必須的字段
而後恢復selector,再次檢查
[root@k8s-node001 Test]# kubeval base.yaml PASS - base.yaml contains a valid Deployment (http-echo) PASS - base.yaml contains a valid Service (http-echo)
檢查PASS
kubeval之類的工具的優點在於,我們能夠在部署週期的早期發現此類錯誤。
另外,您不須要訪問集羣便可運行檢查-它們能夠脫機運行。
默認狀況下,kubeval會根據最新的未發佈的Kubernetes API模式驗證資源。
更多用法詳情請參見官網
kube-score會對你提供的YAML清單進行分析,並針對集羣的內置檢查對其進行評分。
kube-score提供在線版和離線版
本文偷懶就用在線版了
首先打開https://kube-score.com/ ,而後在輸入框貼入寫好的YAML清單,這裏以上文base.yaml來分析
解析結果以下
從如上能夠看到針對這個文件給出的建議,好比資源限制、鏡像TAG、Pod網絡策略等。不錯吧,很是好用的工具。。。
固然,kube-score並不可擴展,而且您不能添加或調整策略。
若是要編寫自定義檢查以符合組織策略,則可使用如下四個工具之一:config-lint,copper,conftest或Polaris。
Config-lint是用於驗證以YAML,JSON,Terraform,CSV和Kubernetes清單編寫的配置文件的工具。
安裝Config-lint
wget https://github.com/stelligent/config-lint/releases/download/v1.6.0/config-lint_Linux_x86_64.tar.gz tar -zxf config-lint_Linux_x86_64.tar.gz mv config-lint /usr/local/bin/
Config-lint並無對Kubernetes清單進行內置檢查。你必須編寫本身的規則才能執行任何驗證。
規則被寫爲YAML文件,稱爲規則集,並具備如下結構:
version: 1 description: Rules for Kubernetes spec files type: Kubernetes files: - "*.yaml" rules: # list of rules
假設我們但願檢查部署中的鏡像是否老是從可信任的倉庫(例如kubeops.net/app:1.0 )中提取。
實施此類檢查的config-lint規則以下所示:
- id: MY_DEPLOYMENT_IMAGE_TAG severity: FAILURE message: Deployment must use a valid image tag resource: Deployment assertions: - every: key: spec.template.spec.containers expressions: - key: image op: starts-with value: "kubeops.net/"
一個完整的規則集以下所示:
version: 1 description: Rules for Kubernetes spec files type: Kubernetes files: - "*.yaml" rules: - id: DEPLOYMENT_IMAGE_REPOSITORY severity: FAILURE message: Deployment must use a valid image repository resource: Deployment assertions: - every: key: spec.template.spec.containers expressions: - key: image op: starts-with value: "kubeops.net/"
若是要測試檢查,能夠將規則集另存爲check_image_repo.yaml。
而後使用config-lint執行檢查
[root@k8s-node001 Test]# config-lint -rules check_image_repo.yaml base.yaml [ { "AssertionMessage": "Every expression fails: And expression fails: image does not start with kubeops.net/", "Category": "", "CreatedAt": "2020-11-02T08:28:43Z", "Filename": "base.yaml", "LineNumber": 0, "ResourceID": "http-echo", "ResourceType": "Deployment", "RuleID": "DEPLOYMENT_IMAGE_REPOSITORY", "RuleMessage": "Deployment must use a valid image repository", "Status": "FAILURE" } ]
能夠看到Every expression fails,檢測不經過。
如今咱們來改下images地址爲image: kubeops.net/http-echo
,再來檢查一次
[root@k8s-node001 Test]# config-lint -rules check_image_repo.yaml base.yaml []
輸出不報錯即爲成功。
Config-lint是一個頗有前途的框架,可讓你使用YAML DSL爲Kubernetes YAML清單編寫自定義檢查。
可是,若是您想表達更復雜的邏輯和檢查該怎麼辦?
YAML對此是否也有限制?
若是您可使用真正的編程語言來表達這些檢查,該怎麼辦?接下來看Copper
Copper V2是一個使用自定義檢查來驗證清單的框架,就像config-lint同樣。
可是,Copper不使用YAML定義檢查。
相反,測試是用JavaScript編寫的,而Copper提供了一個包含一些基本幫助程序的庫,以幫助讀取Kubernetes對象和報告錯誤。
安裝Copper
https://github.com/cloud66-oss/copper/releases/download/2.0.1/linux_amd64_2.0.1 mv linux_amd64_2.0.1 copper chmod + x copper mv copper /usr/local/bin/
與config-lint類似,Copper並無提供內置檢查。
讓咱們自定義一個檢查,以確保部署鏡像tag必須非latest。
check_image_repo.js
$$.forEach(function($){ if ($.kind === 'Deployment') { $.spec.template.spec.containers.forEach(function(container) { var image = new DockerImage(container.image); if (image.tag === 'latest') { errors.add_error('no_latest',"latest is used in " + $.metadata.name, 1) } }); } });
執行檢查
[root@k8s-node001 Test]# copper validate --in=base.yaml --validator=check_image_tag.js Check no_latest failed with severity 1 due to latest is used in http-echo Validation failed
如今修改成image: kubeops.net/http-echo:v1.0.0
[root@k8s-node001 Test]# copper validate --in=base.yaml --validator=check_image_tag.js Validation successful
更多用法參見
Conftest是用於配置數據的測試框架,可用於檢查和驗證Kubernetes清單。
測試使用專用查詢語言Rego編寫的。
安裝Conftest
wget https://github.com/open-policy-agent/conftest/releases/download/v0.21.0/conftest_0.21.0_Linux_x86_64.tar.gz tar -xzf conftest_0.21.0_Linux_x86_64.tar.gz mv conftest /usr/local/bin
與config-lint和copper相似,conftest沒有任何內置檢查。
首先建立一個新目錄conftest-checks和一個名爲check_image_registry.rego的文件,其內容以下:
package main deny[msg] { input.kind == "Deployment" image := input.spec.template.spec.containers[_].image not startswith(image, "kubeops.net/") msg := sprintf("image '%v' doesn't come from kubeops.net repository", [image]) }
先修改base.yaml,image: docker.io/http-echo
使用conftest執行檢測
[root@k8s-node001 Test]# conftest test --policy ./conftest-checks base.yaml FAIL - base.yaml - image 'docker.io/http-echo:v1.0.0' doesn't come from kubeops.net repository 2 tests, 1 passed, 0 warnings, 1 failure, 0 exceptions
再次修改成base.yaml,image: kubeops.net/http-echo
[root@k8s-node001 Test]# conftest test --policy ./conftest-checks base.yaml 2 tests, 2 passed, 0 warnings, 0 failures, 0 exceptions
更多用法參見
最後一個工具了,Polaris既能夠安裝在集羣內部,也能夠做爲命令行工具來靜態分析Kubernetes清單。
做爲命令行工具運行時,它包含多個內置檢查,涉及諸如安全性和最佳實踐等方面,相似於kube-score。
另外,你可使用它來編寫相似於config-lint,copper和conftest的自定義檢查。
換句話說,Polaris結合了兩類的優勢:內置和自定義檢查器。
安裝Polaris,這裏只安裝命令行模式
wget https://github.com/FairwindsOps/polaris/releases/download/1.2.1/polaris_1.2.1_linux_amd64.tar.gz tar -zxf polaris_1.2.1_linux_amd64.tar.gz mv polaris /usr/local/bin/
安裝完成後,就可使用Polaris對base.yaml進行檢查
[root@k8s-node001 Test]# polaris audit --audit-path base.yaml
結果以下,信息比較多,這裏只截取部分信息,本身能夠仔細看看分析出來的結果。
"PolarisOutputVersion": "1.0", "AuditTime": "0001-01-01T00:00:00Z", "SourceType": "Path", "SourceName": "base.yaml", "DisplayName": "base.yaml", "ClusterInfo": { "Version": "unknown", "Nodes": 0, "Pods": 1, "Namespaces": 0, "Controllers": 1 }, "Results": [ { "Name": "http-echo", "Namespace": "", "Kind": "Deployment", "Results": {}, "PodResult": { "Name": "", "Results": { "hostIPCSet": { "ID": "hostIPCSet", "Message": "Host IPC is not configured", "Success": true, "Severity": "danger", "Category": "Security" .............. "tagNotSpecified": { "ID": "tagNotSpecified", "Message": "Image tag is specified", "Success": true, "Severity": "danger", "Category": "Images" } } } ] }, "CreatedTime": "0001-01-01T00:00:00Z" } ] }
另外,能夠只輸出評分
[root@k8s-node001 Test]# polaris audit --audit-path base.yaml --format score 66
下面使用YAML代碼段定義了一個稱爲checkImageRepo的新檢查:
config_with_custom_check.yaml
checks: checkImageRepo: danger customChecks: checkImageRepo: successMessage: Image registry is valid failureMessage: Image registry is not valid category: Images target: Container schema: '$schema': http://json-schema.org/draft-07/schema type: object properties: image: type: string pattern: ^kubeops.net/.+$
如今base.yaml的image爲:image: docker.io/http-echo:v1.0.0
咱們來使用自定義的規則執行檢查
[root@k8s-node001 Test]# polaris audit --config config_with_custom_check.yaml --audit-path base.yaml { "PolarisOutputVersion": "1.0", "AuditTime": "0001-01-01T00:00:00Z", "SourceType": "Path", "SourceName": "base.yaml", "DisplayName": "base.yaml", "ClusterInfo": { "Version": "unknown", "Nodes": 0, "Pods": 1, "Namespaces": 0, "Controllers": 1 }, "Results": [ { "Name": "http-echo", "Namespace": "", "Kind": "Deployment", "Results": {}, "PodResult": { "Name": "", "Results": {}, "ContainerResults": [ { "Name": "http-echo", "Results": { "checkImageRepo": { "ID": "checkImageRepo", "Message": "Image registry is not valid", "Success": false, "Severity": "danger", "Category": "Images" } } } ] }, "CreatedTime": "0001-01-01T00:00:00Z" } ] }
結果顯示"Message": "Image registry is not valid", "Success": false,
而後修改base.yaml的image爲:image: kubeops.net/http-echo:v1.0.0
再次執行檢查
[root@k8s-node001 Test]# polaris audit --config config_with_custom_check.yaml --audit-path base.yaml { "PolarisOutputVersion": "1.0", "AuditTime": "0001-01-01T00:00:00Z", "SourceType": "Path", "SourceName": "base.yaml", "DisplayName": "base.yaml", "ClusterInfo": { "Version": "unknown", "Nodes": 0, "Pods": 1, "Namespaces": 0, "Controllers": 1 }, "Results": [ { "Name": "http-echo", "Namespace": "", "Kind": "Deployment", "Results": {}, "PodResult": { "Name": "", "Results": {}, "ContainerResults": [ { "Name": "http-echo", "Results": { "checkImageRepo": { "ID": "checkImageRepo", "Message": "Image registry is valid", "Success": true, "Severity": "danger", "Category": "Images" } } } ] }, "CreatedTime": "0001-01-01T00:00:00Z" } ] }
從輸出看到 "Message": "Image registry is valid","Success": true,,檢查經過。。。
更多用法參見
儘管有不少工具能夠對Kubernetes YAML文件進行驗證,評分和整理,但重要的是要有一個健康的模型來設計和執行檢查。例如,若是你要考慮經過管道的Kubernetes清單,則kubeval多是該管道中的第一步,由於它能夠驗證對象定義是否符合Kubernetes API模式。一旦此檢查成功,你能夠繼續進行更詳盡的測試,例如標準最佳實踐和自定義策略。Kube-score和Polaris是比較好的選擇。若是你有複雜的要求,而且想要自定義檢查的細節,則應考慮使用copper ,config-lint和conftest。儘管conftest和config-lint都使用更多的YAML來定義自定義驗證規則,可是Copper容許訪問一種真正的編程語言,這使其頗具吸引力。可是,你應該使用其中之一併從頭開始編寫全部檢查嗎?仍是應該使用Polaris並僅編寫其餘自定義檢查?這都取決於你本身,合適本身的纔是最好的。。。