在使用GitHub Actions和kubeconform工具自动检查Kubernetes清单文件的语法

这篇文章是2023年Kubernetes Advent Calendar的第2天文章。

梗概

kubeconform是一个用于验证Kubernetes清单文件的工具。
您可以将其集成到CI中,或在本地使用它来验证Kubernetes的配置。

    • install方法

 

    • https://github.com/yannh/kubeconform#installation

 

    • 以下からダウンロードも可能

 

    https://github.com/yannh/kubeconform/releases

运用方式

例として以下のmanifestを使用します。

$ cat nginx-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  labels:
    app: nginx
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:latest
        ports:
        - containerPort: 80
        resources:
          requests:
            memory: 100M
            cpu: 100m
            ephemeral-storage: 100M
          limits:
            memory: 200M
            cpu: 200m
            ephemeral-storage: 100M

对于上述的manifest执行kubeconform

    正常パターン
$ ~/kubeconform -summary -output json nginx-deployment.yaml
{
  "resources": [],
  "summary": {
    "valid": 1,
    "invalid": 0,
    "errors": 0,
    "skipped": 0
  }
}

    • エラーパターン

 

    port番号を文字列で定義すると、誤りを検出してくれます。
$ ~/kubeconform -summary -output json nginx-deployment.yaml
{
  "resources": [
    {
      "filename": "nginx-deployment.yaml",
      "kind": "Deployment",
      "name": "nginx-deployment",
      "version": "apps/v1",
      "status": "statusInvalid",
      "msg": "problem validating schema. Check JSON formatting: jsonschema: '/spec/template/spec/containers/0/ports/0/containerPort' does not validate with https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/master-standalone/deployment-apps-v1.json#/properties/spec/properties/template/properties/spec/properties/containers/items/properties/ports/items/properties/containerPort/type: expected integer, but got string",
      "validationErrors": [
        {
          "path": "/spec/template/spec/containers/0/ports/0/containerPort",
          "msg": "expected integer, but got string"
        }
      ]
    }
  ],
  "summary": {
    "valid": 0,
    "invalid": 1,
    "errors": 0,
    "skipped": 0
  }
}

如果正在使用kustomize

    フォルダ構成
.
├── base
│   ├── kustomization.yaml
│   └── nginx.yaml
└── overlay
    ├── dev
    │   ├── kustomization.yaml
    │   └── patch.yaml
    :
    :
    実行コマンド
$ kustomize build overlay/dev/ | kubeconform -summary -output json
{
  "resources": [],
  "summary": {
    "valid": 1,
    "invalid": 0,
    "errors": 0,
    "skipped": 0
  }
}

カスタムリソースを扱う場合

    schemaについて

カスタムリソースを扱う場合は、schemaファイルを用意する必要があります。
以下記載の通り、-schema-locationというオプションがあり、指定しない場合はdefaultのschemaが使用されます。defaultの場合、カスタムリソースに対応していません。
https://github.com/yannh/kubeconform/tree/master#usage

例えば、カスタムリソースであるtargetgroupbindingを例にdefaultのschemaでkubeconformを実行すると以下のようにエラーになります。

$ ~/kubeconform -summary -output json targegroup.yaml
{
  "resources": [
    {
      "filename": "targegroup.yaml",
      "kind": "TargetGroupBinding",
      "name": "nginx-tg",
      "version": "elbv2.k8s.aws/v1beta1",
      "status": "statusError",
      "msg": "could not find schema for TargetGroupBinding"
    }
  ],
  "summary": {
    "valid": 0,
    "invalid": 0,
    "errors": 1,
    "skipped": 0
  }
}
    schemaファイルの作成方法

通过执行以下脚本,可以创建schema文件。

 

    作成手順

首先,获取目标资源的crd信息。

$ kubectl get crd targetgroupbindings.elbv2.k8s.aws -o yaml > targetgroup_crd.yaml

为了执行openapi2jsonschema.py,克隆存储库。

$ git clone  https://github.com/yannh/kubeconform.git

schemaファイルのフォーマットを定義
(ソースを見るとkind,group,fullgroup,versionが指定できそう)

$ export FILENAME_FORMAT={kind}_{version}

使用获取的crd信息,执行openapi2jsonschema.py并指定。

$ python kubeconform/scripts/openapi2jsonschema.py targetgroup_crd.yaml
JSON schema written to targetgroupbinding_v1alpha1.json
JSON schema written to targetgroupbinding_v1beta1.json
    kubeconform実行

取得したjsonファイルは適当にschemaフォルダに格納し、以下のように-schema-locationでschemaファイルを指定して実行すればカスタムリソースも扱うことができるようになります。

$ ~/kubeconform -summary -output json -schema-location "schemas/{{ .ResourceKind }}_{{ .ResourceAPIVersion }}.json" targegroup.yaml
{
  "resources": [],
  "summary": {
    "valid": 1,
    "invalid": 0,
    "errors": 0,
    "skipped": 0
  }
}

また、-schema-locationは複数指定できるので、defaultのschemaも使用したい場合は以下のように記載することができます。

$ kubeconform -summary -output json -schema-location default -schema-location "schemas/{{ .ResourceKind }}_{{ .ResourceAPIVersion }}.json" xxx.yaml

以下のように指定することで、schemaファイルが複数あってもファイル名が指定したフォーマットに準拠していればすべて適用してくれます。
“schemas/{{ .ResourceKind }}_{{ .ResourceAPIVersion }}.json”

从GitHub Actions的工作流程中执行

以下链接中提供了一个例子,展示了workflow的使用方式。
https://github.com/yannh/kubeconform#github-workflow

然而,我个人建议使用以下选项。
原因是,run命令可执行命令,因此具有相当高的自由度。
https://github.com/yokawasa/action-setup-kube-tools

    workflow例

运行kubeconform来对以下以该结构进行管理的manifest进行验证。

.
├── schemas
│   ├── rollout_v1alpha1.json
:   :            :
│   └── targetgroupbinding_v1beta1.json
└── template
    └── kustomize
        ├── base
        │   ├── kustomization.yaml
        │   └── nginx.yaml
        └── overlay
           ├── dev
           │   ├── kustomization.yaml
           │   └── patch.yaml
           ├── prod
           │   ├── kustomization.yaml
           │   └── patch.yaml
           └── stg
               ├── kustomization.yaml
               └── patch.yaml

通过使用action-setup-kube-tools工具,您可以按照以下方式创建工作流,以便在创建PR时一次性检查多个清单。

name: Check manifest

on:
  pull_request:  

jobs:
  kubeconform:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v3
    - uses: yokawasa/action-setup-kube-tools@v0.9.2
      with:
        setup-tools: |
          kubeconform
          kustomize
        kubeconform: '0.5.0'
        kustomize: '5.0.0'
    - run: |
        for ENV_NAME in dev stg prod
        do
          kustomize build template/kustomize/overlay/$ENV_NAME |
          kubeconform -summary \
          -schema-location default \
          -schema-location "schemas/{{ .ResourceKind }}_{{ .ResourceAPIVersion }}.json" \
          -output json
        done

使用action-setup-kube-tools工具可以避免在执行环境中安装kustomize和kubeconform,也能消除对执行环境的依赖,这是一个优点。

image.png

通过将CI集成到其中,我们可以在PullRequest阶段确保能够准确地检测出语法等错误,这非常不错。

广告
将在 10 秒后关闭
bannerAds