Validate Kubernetes Configuration files(YAML) [closed]
Asked Answered
S

4

8

I would like to implement a functionality - that validates Kubernetes deployment files(deployments yaml or service yaml or rc yaml) using k8s JSON schema /Yaml Schema.

Currently I need the setup kubectl and k8s cluster available in order to validate. But without this set up , would like to validate using Go-Client (K8s) api.

Can anyone tell me if there are any libraries that I can use to validate the files?How can I obtains the K8s schemas. are there any tools/libraries to generate schemas ? can you point me the direction, since I am totally new to kubernetes stuff.

Does anyone know how kubectl implements this? I would like to use similar libraries if possible

Skyline answered 9/8, 2017 at 11:44 Comment(1)
Possible duplicate of Possible to do a "dry run" validation of files?Thunderbolt
J
-1

To validate your Kubernetes schema without having a connection to your cluster you can use two OSS tools:

I know that kubeconform can also be imported as a Go Module, I don't know if this is the case with kubeval.

If you want to learn more about the differences between the two tools and running schema validation with kubectl --dry-run, you can check out the blog post that I wrote on this topic - A Deep Dive Into Kubernetes Schema Validation

Johan answered 2/6, 2021 at 12:58 Comment(0)
R
-1

the best way to validate kube files is to use helm charts. Helm is a package manager for kubernetes. just like you have pip, yum etc. helm commands like below

helm lint, helm --dry-run install

it will help you check the correctness of you yamls. --dry-run is very helpful as it gives a complete rendered helm chart with all the values populated. Learn about helm here

for templates you can use the below command

helm create my-chart

this generates a default chart so you just need to change a few things as per your requirement.

If you want to add your own custom checks and validation you can write your own functions in helm using Helm template language based on jinja2. Learn more at Template functions and pipelines

Rotor answered 12/8, 2022 at 6:19 Comment(0)
L
-1

Pluto validates k8s objects for deprecated apis https://github.com/FairwindsOps/pluto

Langham answered 2/2, 2023 at 20:38 Comment(1)
I do not see how this answers the question at the top of this page, but it should. Please edit according to How to Answer or delete the answer. Otherwise it risks being flagged as "not an answer" and being deleted.Cleaver
B
-2

I've faced with the same task and take k8s.io/kubernetes/pkg/apis/apps/validation and k8s.io/kubernetes/pkg/apis/core/validation using this script:

#!/bin/sh
set -euo pipefail

VERSION=${1#"v"}
if [ -z "$VERSION" ]; then
    echo "Must specify version!"
    exit 1
fi
MODS=($(
    curl -sS https://raw.githubusercontent.com/kubernetes/kubernetes/v${VERSION}/go.mod |
    sed -n 's|.*k8s.io/\(.*\) => ./staging/src/k8s.io/.*|k8s.io/\1|p'
))
for MOD in "${MODS[@]}"; do
    V=$(
        go mod download -json "${MOD}@kubernetes-${VERSION}" |
        sed -n 's|.*"Version": "\(.*\)".*|\1|p'
    )
    go mod edit "-replace=${MOD}=${MOD}@${V}"
done
go get "k8s.io/kubernetes@v${VERSION}"

Than you can write a test like this to validate manifest with a Service and Deployment:

import (
    "github.com/stretchr/testify/assert"
    appsV1 "k8s.io/api/apps/v1"
    coreV1 "k8s.io/api/core/v1"
    "k8s.io/client-go/kubernetes/scheme"
    kubernetesApps "k8s.io/kubernetes/pkg/apis/apps"
    kubernetesAppsV1 "k8s.io/kubernetes/pkg/apis/apps/v1"
    kubernetesAppsValidation "k8s.io/kubernetes/pkg/apis/apps/validation"
    kubernetesCore "k8s.io/kubernetes/pkg/apis/core"
    kubernetesCoreV1 "k8s.io/kubernetes/pkg/apis/core/v1"
    kubernetesCoreValidation "k8s.io/kubernetes/pkg/apis/core/validation"
    "strings"
    "testing"
    "text/template"
)

const RedisTemplate = `
---
apiVersion: v1
kind: Service
metadata:
  name: redis
spec:
  type: ClusterIP
  internalTrafficPolicy: Cluster
  sessionAffinity: None
  ports:
  - name: redis-port
    protocol: TCP
    port: 6379
    targetPort: 6379
--- 
apiVersion: apps/v1
kind: Deployment
metadata:
  name: redis
....
`

func Test_RedisManifest(t *testing.T) {
    for _, m := range strings.Split(RedisTemplate, "---") {
        if len(strings.Trim(m, "\n")) == 0 {
            continue
        }

        obj, _, err := scheme.Codecs.UniversalDeserializer().Decode([]byte(m), nil, nil)
        assert.NoError(t, err)
        assert.NotEmptyf(t, obj.GetObjectKind().GroupVersionKind().Kind, "parsed k8s object kind is empty")

        if service, ok := obj.(*coreV1.Service); ok {
            kubernetesService := &kubernetesCore.Service{}
            conversionErr := kubernetesCoreV1.Convert_v1_Service_To_core_Service(service, kubernetesService, nil)
            assert.NoError(t, conversionErr)
            kubernetesService.ObjectMeta.Namespace = "default"
            validationErrs := kubernetesCoreValidation.ValidateService(kubernetesService)
            assert.Empty(t, validationErrs)

        }

        if deployment, ok := obj.(*appsV1.Deployment); ok {
            kubernetesDeployment := &kubernetesApps.Deployment{}
            conversionErr := kubernetesAppsV1.Convert_v1_Deployment_To_apps_Deployment(deployment, kubernetesDeployment, nil)
            assert.NoError(t, conversionErr)

            kubernetesDeployment.ObjectMeta.Namespace = "default"
            validationErrs := kubernetesAppsValidation.ValidateDeployment(kubernetesDeployment, kubernetesCoreValidation.PodValidationOptions{})
            assert.Empty(t, validationErrs)
        }
    }
}

This approach really helps to find cases like spec.template.spec.containers[0].ports[0].name: Invalid value: "something-redis-port": must be no more than 15 characters which is great, but there several disadvantages:

  1. Direct import of k8s.io/kubernetes is not recommended by K8s team.
  2. Direct import of k8s.io/kubernetes can create a troubles in the future.
  3. Validation funcs ValidateService and ValidateDeployment are expecting that optional fields like namespace, internalTrafficPolicy, sessionAffinity and a lot of others must have values. Maybe there some other funcs which can fill optional fields with default values but I've not found them on the current moment.
Broody answered 7/8, 2022 at 16:9 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.