驗證Kubernetes YAML的最佳實踐和策略

語言: CN / TW / HK

行業解決方案、產品招募中!想賺錢就來傳!>>>

本文來自Rancher Labs

Kubernetes工作負載最常見的定義是YAML格式的檔案。使用YAML所面臨的挑戰之一是,它相當難以表達manifest檔案之間的約束或關係。

如果你想檢查所有部署到叢集中的映象是否從受信任的映象倉庫中提取應該怎麼做?如何防止沒有PodDisruptionBudgets的部署被提交到叢集?

整合靜態檢查可以在接近開發生命週期的時候發現錯誤和策略違規。而且由於圍繞資源定義的有效性和安全性的保證得到了改善,你可以相信生產工作負載是遵循最佳實踐的。

Kubernetes YAML檔案靜態檢查的生態系統可以分為以下幾類:

  • API驗證器:這一類工具可以針對Kubernetes API伺服器驗證給定的YAML manifest。

  • 內建檢查器:這一類工具捆綁了安全、最佳實踐等方面的意見檢查。

  • 自定義驗證器:這一類工具允許用幾種語言編寫自定義檢查,如Rego和Javascript。

在本文中,你將學習並比較六種不同的工具:

  • Kubeval

  • Kube-score

  • Config-lint

  • Copper

  • Conftest

  • Polaris

讓我們開始吧!

驗證Deployment

在開始比較工具之前,你應該設定一個基準。以下manifest並沒有遵循最佳實踐,可能存在一些問題,你能發現幾個問題呢?

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

我們將會使用這個YAML檔案來對比不同的工具。

你可以在這個git倉庫中找到上面的YAML清單、檔案 base-valid.yaml以及文章中提到的其他manifest:

https://github.com/amitsaha/kubernetes-static-checkers-demo

manifest描述了一個總是在5678埠回覆“Hello World”訊息的web應用程式。

你可以通過以下方式部署該應用程式:

kubectl apply -f hello-world.yaml

你可以使用以下命令測試它:

kubectl port-forward svc/http-echo 8080:5678

你可以訪問http://localhost:8080 並確認該應用程式能否按照預期執行。但是它是否遵循了最佳實踐呢?

讓我們往下看。

Kubeval

主頁:https://www.kubeval.com/

Kubeval的前提是,與Kubernetes的任何互動都要通過它的REST API。因此,你可以使用API模式來驗證一個給定的YAML輸入是否符合該模式。我們來看看一個例子。

你可以按照專案網站上的說明來安裝kubeval,撰寫此文時最新版本 是0.15.0。安裝完成之後,讓我們用前文討論的manifest來執行它:

kubeval base-valid.yaml
PASS - base-valid.yaml contains a valid Deployment (http-echo)
PASS - base-valid.yaml contains a valid Service (http-echo)

當成功之後,kubeval退出時程式碼為0。你可以使用以下程式碼驗證退出程式碼:

echo $?
0

現在,讓我們使用另一個manifest來測試kubeval:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: http-echo
spec:
  replicas: 2
  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

你能發現問題嗎?

讓我們執行kubeval:

kubeval kubeval-invalid.yaml
WARN - kubeval-invalid.yaml contains an invalid Deployment (http-echo) - selector: selector is required
PASS - kubeval-invalid.yaml contains a valid Service (http-echo)

# let's check the return value
echo $?
1

資源並沒有通過驗證。使用app/v1 API版本的Deployment必須包含一個匹配Pod標籤的selector。上面的manifest沒有包含selector,針對manifest執行kubeval報告了一個錯誤和一個非零的退出程式碼。

你可能想知道,當你用上面的manifest執行kubectl apply -f時會發生什麼?

讓我們試一試:

kubectl apply -f kubeval-invalid.yaml
error: error validating "kubeval-invalid.yaml": error validating data: ValidationError(Deployment.spec):
missing required field "selector" in io.k8s.api.apps.v1.DeploymentSpec; if you choose to ignore these errors,
turn validation off with --validate=false

這正是kubeval警告你的錯誤。你可以通過新增像這樣的selector來修復資源。

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

像kubeval這樣的工具的好處是,你可以在部署週期的早期發現這樣的錯誤。此外,你不需要訪問叢集來執行檢查——它們可以離線執行。預設情況下,kubeval會根據最新的未釋出的Kubernetes API模式驗證資源。然而,在大多數情況下,你可能希望根據特定的Kubernetes版本執行驗證。你可以使用標誌--kubernetes-version來測試特定的API版本:

kubeval --kubernetes-version 1.16.1 base-valid.yaml

請注意,版本應該是Major.Minor.Patch.的形式。要檢視可用於驗證的版本,請檢視GitHub上的JSON schema,kubeval使用它來執行驗證。

如果你需要離線執行kubeval,你可以下載schemas,然後使用--schema-location標誌來使用本地目錄。除了單個YAML檔案,你還可以針對目錄以及標準輸入執行kubeval。你還應該知道,Kubeval易於與你的持續整合流水線整合。如果你想在提交你的manifest到叢集之前包含檢查,那麼kubeval支援三種輸出格式也許能夠對你有所幫助。

  • 純文字

  • JSON

  • 測試任何東西協議(TAP)

而且你可以使用其中一種格式來進一步解析輸出,以建立一個自定義的結果摘要。但是,kubeval存在一個侷限性,就是它目前還不能對自定義資源定義(CRD)進行驗證。不過kubeval可以忽略它們。

儘管Kubeval是檢查和驗證資源的絕佳選擇,但請注意,通過測試的資源並不能保證符合最佳實踐。舉個例子,在容器映象中使用最新的標籤被認為不是最佳實踐。然而,Kubeval並不會將其作為錯誤報告,它會在沒有警告的情況下驗證YAML。

如果你想對YAML進行打分,並抓住諸如使用最新的標籤這樣的違規行為怎麼辦?如何根據最佳實踐檢查你的YAML檔案?

Kube-score

主頁:https://github.com/zegl/kube-score

Kube-score分析YAML清單,並根據內建的檢查進行評分。這些檢查是根據安全建議和最佳實踐而選擇的,例如:

  • 以非root使用者身份執行容器。

  • 為pods指定健康檢查。

  • 定義資源請求和限制。

  • 檢查的結果可以是OK、WARNING或CRITICAL。

你可以線上試用kube-score,也可以在本地安裝。在寫這篇文章時,最新的版本是1.7.0讓我們試著用之前的manifest base-valid.yaml來執行它:

apps/v1/Deployment http-echo
[CRITICAL] Container Image Tag
  · http-echo -> Image with latest tag
      Using a fixed tag is recommended to avoid accidental upgrades
[CRITICAL] Pod NetworkPolicy
  · The pod does not have a matching network policy
      Create a NetworkPolicy that targets this pod
[CRITICAL] Pod Probes
  · Container is missing a readinessProbe
      A readinessProbe should be used to indicate when the service is ready to receive traffic.
      Without it, the Pod is risking to receive traffic before it has booted. It is also used during
      rollouts, and can prevent downtime if a new version of the application is failing.
      More information: https://github.com/zegl/kube-score/blob/master/README_PROBES.md
[CRITICAL] Container Security Context
  · http-echo -> Container has no configured security context
      Set securityContext to run the container in a more secure context.
[CRITICAL] Container Resources
  · http-echo -> CPU limit is not set
      Resource limits are recommended to avoid resource DDOS. Set resources.limits.cpu
  · http-echo -> Memory limit is not set
      Resource limits are recommended to avoid resource DDOS. Set resources.limits.memory
  · http-echo -> CPU request is not set
      Resource requests are recommended to make sure that the application can start and run without
      crashing. Set resources.requests.cpu
  · http-echo -> Memory request is not set
      Resource requests are recommended to make sure that the application can start and run without crashing.
      Set resources.requests.memory
[CRITICAL] Deployment has PodDisruptionBudget
  · No matching PodDisruptionBudget was found
      It is recommended to define a PodDisruptionBudget to avoid unexpected downtime during Kubernetes
      maintenance operations, such as when draining a node.
[WARNING] Deployment has host PodAntiAffinity
  · Deployment does not have a host podAntiAffinity set
      It is recommended to set a podAntiAffinity that stops multiple pods from a deployment from
      being scheduled on the same node. This increases availability in case the node becomes unavailable.

YAML檔案通過了kubeval檢查,但kube-score指出了幾個不足之處。

  • 缺少了readiness probe

  • 缺少記憶體和CPU請求和限制。

  • 缺少Poddisruptionbudgets

  • 缺少反親和規則以最大化可用性。

  • 容器以root身份執行。

這些都是你應該解決的有效點,以使你的部署更加健壯和可靠。kube-score命令會輸出一個可讀性高的結果,包含所有的WARNING和CRITICAL違規行為,這在開發過程中是非常好的。如果你打算把它作為持續整合流水線的一部分,你可以用--output-format ci這個標誌來使用更簡潔的輸出,它還可以列印級別為OK的檢查:

kube-score score base-valid.yaml --output-format ci
[OK] http-echo apps/v1/Deployment
[OK] http-echo apps/v1/Deployment
[CRITICAL] http-echo apps/v1/Deployment: (http-echo) CPU limit is not set
[CRITICAL] http-echo apps/v1/Deployment: (http-echo) Memory limit is not set
[CRITICAL] http-echo apps/v1/Deployment: (http-echo) CPU request is not set
[CRITICAL] http-echo apps/v1/Deployment: (http-echo) Memory request is not set
[CRITICAL] http-echo apps/v1/Deployment: (http-echo) Image with latest tag
[OK] http-echo apps/v1/Deployment
[CRITICAL] http-echo apps/v1/Deployment: The pod does not have a matching network policy
[CRITICAL] http-echo apps/v1/Deployment: Container is missing a readinessProbe
[CRITICAL] http-echo apps/v1/Deployment: (http-echo) Container has no configured security context
[CRITICAL] http-echo apps/v1/Deployment: No matching PodDisruptionBudget was found
[WARNING] http-echo apps/v1/Deployment: Deployment does not have a host podAntiAffinity set
[OK] http-echo v1/Service
[OK] http-echo v1/Service
[OK] http-echo v1/Service
[OK] http-echo v1/Service

與kubeval類似,當有一個CRITICAL檢查失敗時,kube-score會返回一個非零的退出程式碼,但你配置它在WARNINGs時也會失敗。還有一個內建的檢查來驗證不同API版本的資源,類似於kubeval。然而,這些資訊是硬編碼在kube-score本身,你不能選擇不同的Kubernetes版本。因此,如果你升級你的叢集或你有幾個不同的叢集執行不同的版本,這可能會限制你使用這一工具。

請注意,有一個open issue可以實現這個功能。你可以在官方網站上了解更多關於kube-score的資訊:https://github.com/zegl/kube-score

Kube-score檢查是執行最佳實踐的優秀工具,但如果你想自定義,或者新增自己的規則呢?暫時不可以,Kube-score的設計不是可擴充套件的,你不能新增或調整政策。如果你想寫自定義檢查來遵守你的組織政策,你可以使用接下來的四個選項之——config-lint、copper、conftest或polaris。

Config-lint

Config-lint是一個旨在驗證以YAML、JSON、Terraform、CSV和Kubernetes manifest編寫的配置檔案的工具。你可以使用專案網站上的說明安裝它:

https://stelligent.github.io/config-lint/#/install

在撰寫本文時,最新的版本是1.5.0。

Config-lint沒有內建對Kubernetes manifest的檢查。你必須編寫自己的規則來執行驗證。這些規則被寫成YAML檔案,稱為規則集,具有以下結構:

version: 1
description: Rules for Kubernetes spec files
type: Kubernetes
files:
  - "*.yaml"
rules:
   # list of rules

讓我們來詳細看看。type欄位表示你將用config-lint檢查什麼型別的配置——一般是Kubernetes manifest。

files欄位除了接受單個檔案外,還接受一個目錄作為輸入。

rules欄位是你可以定義自定義檢查的地方。比方說,你希望檢查Deployment中的映象是否總是從受信任的映象倉庫(如my-company.com/myapp: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: "my-company.com/"

每條規則必須具有以下屬性。

  • id——這是對規則的唯一標識。

  • severity——它必須是FAILURE、WARNING和NON_COMPLIANT中的一個。

  • message——如果違反了一個規則,這個字串的內容會被顯示出來。

  • resource——你希望這個規則被應用到的資源種類。

  • assertions——將對指定資源進行評估的條件列表。

在上面的規則中,every assertion檢查每個容器中的Deployment(key:spec.templates.spec.contains)是否使用受信任的映象(即以 "my-company.com/"開頭的映象)。

完整的規則集看起來如下:

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: "my-company.com/"

如果你想要測試檢查,你可以將規則集儲存為check_image_repo.yaml

現在,讓我們對base-valid.yaml檔案進行驗證。


config-lint -rules check_image_repo.yaml base-valid.yaml
[
  {
  "AssertionMessage": "Every expression fails: And expression fails: image does not start with my-company.com/",
  "Category": "",
  "CreatedAt": "2020-06-04T01:29:25Z",
  "Filename": "test-data/base-valid.yaml",
  "LineNumber": 0,
  "ResourceID": "http-echo",
  "ResourceType": "Deployment",
  "RuleID": "DEPLOYMENT_IMAGE_REPOSITORY",
  "RuleMessage": "Deployment must use a valid image repository",
  "Status": "FAILURE"
  }
]

它失敗了。現在,讓我們考慮以下manifest和有效的映象倉庫:

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: my-company.com/http-echo:1.0
        args: ["-text", "hello-world"]
        ports:
        - containerPort: 5678

使用以上manifest執行相同的檢查並且將不會報告違規:

config-lint -rules check_image_repo.yaml image-valid-mycompany.yaml
[]

Config-lint是一個很有前途的框架,它可以讓你使用YAML DSL為Kubernetes YAML manifest編寫自定義檢查。但如果你想表達更復雜的邏輯和檢查呢?是不是YAML的限制性太大?如果你能用真正的程式語言來表達這些檢查呢?

Copper

主頁:https://github.com/cloud66-oss/copper

Copper V2是一個使用自定義檢查來驗證清單的框架——就像config-lint一樣。然而,Copper並沒有使用YAML來定義檢查。取而代之的是,測試是用JavaScript編寫的,Copper提供了一個庫,裡面有一些基本的幫助程式來協助讀取Kubernetes物件和報告錯誤。

你可以按照官方文件來安裝Copper。在寫這篇文章的時候,最新的版本是2.0.1:

https://github.com/cloud66-oss/copper#installation

與config-lint類似,Copper沒有內建檢查。讓我們寫一個檢查,以確保部署只能從受信任的倉庫(如my-company.com)拉取容器映象。建立一個新檔案check_image_repo.js,內容如下:

$$.forEach(function($){
    if ($.kind === 'Deployment') {
        $.spec.template.spec.containers.forEach(function(container) {
            var image = new DockerImage(container.image);
            if (image.registry.lastIndexOf('my-company.com/') != 0) {
                errors.add_error('no_company_repo',"Image " + $.metadata.name + " is not from my-company.com repo", 1)
            }
        });
    }
});

現在,要根據我們的base-valid.yaml manifest執行這項檢查,可以使用copper validate命令:

copper validate --in=base-valid.yaml --validator=check_image_tag.js
Check no_company_repo failed with severity 1 due to Image http-echo is not from my-company.com repo
Validation failed

正如你所想的,你可以編寫更復雜的檢查,比如驗證Ingress manifest的域名,或者拒絕任何作為特權執行的Pod。Copper有一些內建的助手:

DockerImage函式讀取指定的輸入檔案並建立一個包含以下屬性的物件:

  • name-包含映象名稱

  • tag-包含映象tag

  • registry-映象倉庫

  • registry_url-包含協議和映象倉庫

  • fqin代表整個完全合格的映象位置。

  • findByName函式可以幫助從輸入檔案中找到給定kind和name的資源。

  • findByLabels函式可以幫助查詢資源提供的kindlabels

你可以在這裡看到所有可用的幫助程式:

https://github.com/cloud66-oss/copper/tree/master/libjs

預設情況下,它將整個輸入的YAML檔案載入到$$變數中,並使其在你的指令碼中可用(如果你過去使用jQuery,你可能會發現這個模式很熟悉)。

除了不用學習自定義語言外,你還可以使用整個JavaScript語言來編寫你的檢查,如字串插值、函式等。值得注意的是,目前的copper版本嵌入了ES5版本的JavaScript引擎,而不是ES6。想要了解更多,可以訪問專案官網:

https://github.com/cloud66-oss/copper

如果Javascript不是你的首選語言,或者你更喜歡用於查詢和描述策略的語言,你應該看看conftest。

Conftest

Conftest是一個配置資料的測試框架,可用於檢查和驗證Kubernetes manifest。測試使用專門構建的查詢語言Rego編寫。

你可以按照專案網站上的說明安裝conftest,在撰寫本文時,最新的版本是0.18.2:

https://www.conftest.dev/install/

與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, "my-company.com/")
  msg := sprintf("image '%v' doesn't come from my-company.com repository", [image])
}

現在讓我們執行conftest來驗證manifest base-valid.yaml

conftest test --policy ./conftest-checks base-valid.yaml
FAIL - base-valid.yaml - image 'hashicorp/http-echo' doesn't come from my-company.com repository
1 tests, 1 passed, 0 warnings, 1 failure

當然,它是失敗的,因為映象不受信任。上面的Rego檔案指定了一個deny塊,當為true時就會評估為違規。當你有多個deny塊時,conftest會獨立檢查它們,總體結果是任何一個塊的違規都會導致整體違規。

除了預設的輸出格式外,conftest還支援JSON、TAP和通過--output標誌的表格格式,如果你希望將報告與現有的持續整合流水線整合,那麼這些格式將會很有幫助。為了幫助除錯策略,conftest有一個方便的--trace標誌,它可以列印conftest如何解析指定策略檔案的跟蹤。

Conftest策略可以作為artefacts在OCI(Open Container Initiative)倉庫中釋出和共享。命令push和pull允許釋出一個工件和從遠端倉庫中提取一個現有的artefact。

讓我們看看使用conftest push將上述策略釋出到本地docker倉庫的演示。使用以下命令啟動本地docker倉庫:

docker run -it --rm -p 5000:5000 registry

從另一個終端,導航到上面建立的conftest-checks目錄,並執行以下命令:

conftest push 127.0.0.1:5000/amitsaha/opa-bundle-example:latest

該命令應成功完成,並顯示以下資訊:

2020/06/10 14:25:43 pushed bundle with digest: sha256:e9765f201364c1a8a182ca637bc88201db3417bacc091e7ef8211f6c2fd2609c

現在,建立一個臨時目錄,執行conftest pull命令,將上述bundle下載到臨時目錄中:

cd $(mktemp -d)
conftest pull 127.0.0.1:5000/amitsaha/opa-bundle-example:latest

你會看到,在包含之前push的策略檔案的臨時目錄中,有一個新的子目錄策略:

tree
.
└── policy
  └── check_image_registry.rego

你甚至可以直接從倉庫中執行測試:

conftest test --update 127.0.0.1:5000/amitsaha/opa-bundle-example:latest base-valid.yaml
..
FAIL - base-valid.yaml - image 'hashicorp/http-echo' doesn't come from my-company.com repository
2 tests, 1 passed, 0 warnings, 1 failure

不幸的是,DockerHub還不是支援的映象倉庫之一。然而,如果你正在使用Azure容器倉庫(ACR)或執行你的容器倉庫,可能會通過測試。

artefact格式與開放策略代理 (OPA) 繫結使用的格式相同,這使得使用 conftest 從現有的 OPA 繫結中執行測試成為可能。

你可以在官方網站上了解更多關於共享策略和conftest的其他功能:

https://www.conftest.dev/

Polaris

主頁:https://github.com/FairwindsOps/polaris

本文將探討的最後一個工具是polaris。Polaris既可以安裝在叢集內部,也可以作為命令列工具靜態地分析Kubernetes manifest。當作為命令列工具執行時,它包括幾個內建的檢查,涵蓋安全和最佳實踐等領域,類似於kube-score。此外,你還可以用它來編寫類似config-lint、copper和conftest的自定義檢查。換句話說,polaris結合了兩個類別中最好的:內建和自定義檢查器。

你可以按照專案網站上的說明安裝polaris命令列工具。在寫這篇文章的時候,最新的版本是1.0.3:

https://github.com/FairwindsOps/polaris/blob/master/docs/usage.md#cli

安裝完成後,你可以使用以下命令針對base-valid.yaml manifest執行polaris:

polaris audit --audit-path base-valid.yam

上述命令將列印一個JSON格式的字串,詳細說明執行的檢查和每個測試的結果。輸出結果的結構如下:

{
  "PolarisOutputVersion": "1.0",
  "AuditTime": "0001-01-01T00:00:00Z",
  "SourceType": "Path",
  "SourceName": "test-data/base-valid.yaml",
  "DisplayName": "test-data/base-valid.yaml",
  "ClusterInfo": {
    "Version": "unknown",
    "Nodes": 0,
    "Pods": 2,
    "Namespaces": 0,
    "Controllers": 2
  },
  "Results": [
    /* long list */
  ]
}

你可以在下方連結中獲取完整的輸出:

https://github.com/amitsaha/kubernetes-static-checkers-demo/blob/master/base-valid-polaris-result.json

與kube-score類似,polaris也發現了一些manifest未達到建議的最佳實踐的情況,其中包括:

  • 缺少健康檢查的pod。

  • 容器映象沒有指定標籤。

  • 容器以root身份執行。

  • 沒有設定CPU和記憶體請求和限制。

  • 每項檢查都被劃分為警告或危險的嚴重程度。

要了解有關當前內建檢查的更多資訊,請參閱文件:

https://github.com/FairwindsOps/polaris/blob/master/docs/usage.md#checks

如果你對詳細的結果不感興趣,傳遞標誌--format score會列印一個範圍為1-100的數字,polaris將其稱為分數(score):

polaris audit --audit-path test-data/base-valid.yaml --format score
68

分數越接近100,符合度越高。如果你檢查polaris audit命令的退出程式碼,你會發現它是0。要使polaris審計退出時的程式碼是非0,可以利用另外兩個標誌。

--set-exit-code-below-score標誌接受範圍為1-100的閾值分數,當分數低於閾值時,將以4的退出程式碼退出。當你的基線分數是75分,而你想在分數低於75分時發出警報時,這非常有用。

當任何危險檢查失敗時,--set-exit-code-on-danger標誌將以3的退出程式碼退出。

現在讓我們看看如何為polaris定義一個自定義檢查,以測試Deployment中的容器映象是否來自可信任的映象倉庫。自定義檢查以YAML格式定義,測試本身使用JSON Schema描述。下面的YAML程式碼段定義了一個新的檢查checkImageRepo:

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: ^my-company.com/.+$

讓我們仔細看看:

  • successMessage是檢查成功時顯示的字串。

  • failureMessage是指當測試不成功時顯示的資訊。

  • category指的是其中一個類別—映象、健康檢查、安全、網路和資源。

  • target是一個字串,用於確定檢查所針對的規範物件,應該是Container、Pod或Controller中的一個。

  • 測試本身是在schema物件中使用JSON模式定義的。這裡的檢查使用模式關鍵字來匹配映象是否來自允許的倉庫。

要執行上面定義的檢查,你需要建立一個Polaris配置檔案,如下所示:

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: ^my-company.com/.+$

讓我們來分析一下這個檔案。

  • check欄位指定了檢查和它們的嚴重性。由於你想在映象不受信任時發出警報,所以checkImageRepo被分配了一個danger嚴重程度。

  • 然後在customChecks物件中定義checkImageRepo檢查本身。

你可以將上面的檔案儲存為custom_check.yaml,然後用你想要驗證的YAML manifest執行polaris audit

你可以用base-valid.yaml manifest進行測試:

polaris audit --config custom_check.yaml --audit-path base-valid.yaml

你會發現,polaris audit只運行了上面定義的自定義檢查,但沒有成功。如果你將容器映象修改為my-company.com/http-echo:1.0,polaris將報告成功。Github倉庫中包含了修改後的manifest,所以你可以根據image-valid-mycompany.yaml manifest測試前面的命令。

但是如何同時執行內建和自定義檢查呢?上面的配置檔案應該更新所有內建的檢查識別符號,看起來應該如下:

checks:
  cpuRequestsMissing: warning
  cpuLimitsMissing: warning
  # Other inbuilt checks..
  # ..
  # custom 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: ^my-company.com/.+$

你可以在這裡看到一個完整的配置檔案的例子:

https://github.com/amitsaha/kubernetes-static-checkers-demo/blob/master/polaris-configs/config_with_custom_check.yaml

你可以用自定義和內建檢查來測試base-valid.yaml manifest:

polaris audit --config config_with_custom_check.yaml --audit-path base-valid.yaml

Polaris用你的自定義檢查增強了內建檢查,從而結合了兩種方式的最佳狀態。然而,如果不能使用更強大的語言,如Rego或JavaScript,可能會限制編寫更復雜的檢查。

要了解更多關於polaris的資訊,請檢視專案網站:

https://github.com/FairwindsOps/polaris

總 結

雖然有很多工具可以驗證、打分和精簡Kubernetes YAML檔案,但重要的是要有一個心理模型來了解你將如何設計和執行檢查。舉個例子,如果你想讓Kubernetes manifest通過一個流水線,kubeval可以是這樣一個流水線的第一步,因為它驗證物件定義是否符合Kubernetes API模式。一旦這項檢查成功,也許你可以繼續進行更詳細的測試,比如標準最佳實踐和自定義策略。Kube-score和polaris在這裡是最優秀的選擇。

如果你有複雜的需求,並且想要自定義檢查的細節,你應該考慮copper、config-lint和conftest。雖然conftest和config-lint都使用了更多的YAML來定義自定義驗證規則,但copper給你提供了一個真正的程式語言,使其相當有吸引力。但是,你應該使用其中的一個,從頭開始寫所有的檢查,還是應該使用Polaris,只寫額外的自定義檢查?這要根據情況而定。