Валідацыя Kubernetes YAML на адпаведнасць лепшым практыкам і палітыкам

Заўв. перав.: З ростам колькасці YAML-канфігурацый для K8s-акружэнняў усё больш актуальнай становіцца патрэбнасць у іх аўтаматызаванай праверцы. Аўтар гэтага агляду не проста адабраў існуючыя рашэнні для гэтай задачы, але і на прыкладзе Deployment'а паглядзеў, як яны працуюць. Атрымалася вельмі інфарматыўна для тых, каму гэтая тэма цікавая.

Валідацыя Kubernetes YAML на адпаведнасць лепшым практыкам і палітыкам

TL, д-р: У артыкуле параўноўваюцца шэсць статычных інструментаў праверкі і ацэнкі YAML-файлаў Kubernetes на адпаведнасць лепшым практыкам і патрабаванням.

Рабочыя нагрузкі Kubernetes, як правіла, вызначаюцца ў форме YAML-дакументаў. Адна з праблем з YAML'ом - складанасць задання абмежаванняў або ўзаемаадносін паміж файламі маніфестаў.

Што, калі нам трэба пераканацца, што ўсе выявы, якія разгортваюцца ў кластары, бяруцца з даверанага рэестра?

Як прадухіліць адпраўку ў кластар Deployment'аў, для якіх не зададзены PodDisruptionBudgets?

Інтэграцыя статычнага тэсціравання дазваляе выяўляць памылкі і парушэнні палітык яшчэ на стадыі распрацоўкі. Тым самым павялічваюцца гарантыі правільнасці і бяспекі азначэнняў рэсурсаў і павялічваецца верагоднасць таго, што production-нагрузкі будуць прытрымлівацца лепшым практыкам.

Экасістэму статычнай праверкі YAML-файлаў Kubernetes можна падзяліць на наступныя катэгорыі:

  • API-валідатары. Інструменты ў гэтай катэгорыі правяраюць YAML-маніфест на адпаведнасць патрабаванням API-сервера Kubernetes.
  • Гатовыя тэстары. Інструменты з дадзенай катэгорыі ідуць з гатовымі тэстамі на бяспеку, адпаведнасць лепшым практыкам і да т.п.
  • Кастомныя валідатары. Прадстаўнікі гэтай катэгорыі дазваляюць ствараць карыстацкія тэсты на розных мовах, напрыклад, на Rego і Javascript.

У гэтым артыкуле мы апішам і параўнаем шэсць розных інструментаў:

  1. kubeval;
  2. kube-score;
  3. config-lint;
  4. медзь;
  5. conftest;
  6. Палярыс.

Што ж, давайце прыступім!

Праверка Deployment'аў

Перш чым прыступіць да параўнання інструментаў, давайце створым некаторую аснову, на якой будзем іх тэсціраваць.

Прыведзены ніжэй маніфест змяшчае шэраг памылак і неадпаведнасцяў лепшым практыкам: колькі з іх вы зможаце знайсці?

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

(base-valid.yaml)

Мы будзем выкарыстоўваць гэты YAML для параўнання розных інструментаў.

Вышэйпрыведзены маніфест base-valid.yaml і іншыя маніфесты з гэтага артыкула можна знайсці ў Git-рэпазітары.

Маніфест апісвае вэб-дадатак, асноўная задача якога - адказваць паведамленнем "Hello World" на порт 5678. Яго можна разгарнуць наступнай камандай:

kubectl apply -f hello-world.yaml

А так - праверыць працу:

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

Цяпер перайдзіце на http://localhost:8080 і пацвердзіце, што прыкладанне працуе. Але ці варта яно лепшым практыкам? Давайце праверым.

1. Kubeval

У аснове kubeval ляжыць ідэя аб тым, што любое ўзаемадзеянне з Kubernetes адбываецца праз яго REST API. Іншымі словамі, можна выкарыстоўваць схему API для праверкі таго, ці адпавядае ёй дадзены YAML. Давайце разгледзім прыклад.

Інструкцыі па ўстаноўцы kubeval даступныя на сайце праекту.

На момант напісання арыгінальнага артыкула была даступная версія 0.15.0.

Пасля ўстаноўкі давайце "скормім" яму маніфест, прыведзены вышэй:

$ 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 завершыць працу з exit-кодам 0. Праверыць яго можна наступным чынам:

$ echo $?
0

Давайце зараз паспрабуем 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-invalid.yaml)

Можаце на вока вызначыць праблему? Запускаем:

$ 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)

# проверим код возврата
$ echo $?
1

Рэсурс не праходзіць праверку.

Deployment'ы, якія выкарыстоўваюць версію API apps/v1, павінны ўключаць селектар, які адпавядае пазнацы pod'а. Маніфест вышэй не ўключае селектар, таму kubeval паведаміў пра памылку і выйшаў з ненулявым кодам.

Цікава, што адбудзецца, калі выканаць 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. Выправіць яе можна, дадаўшы селектар:

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

(base-valid.yaml)

Перавага прылад накшталт kubeval у тым, што падобныя памылкі можна адлоўліваць на ранніх стадыях цыклу разгортвання.

Акрамя таго, для гэтых праверак не патрэбен доступ у кластар: іх можна праводзіць афлайн.

Па змаўчанні kubeval правярае рэсурсы на адпаведнасць самай апошняй схеме Kubernetes API. Аднак у большасці выпадкаў вам можа запатрабавацца правесці праверку на адпаведнасць канкрэтнаму рэлізу Kubernetes. Зрабіць гэта можна з дапамогай сцяга --kubernetes-version:

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

Звярніце ўвагу, што версія павінна ўказвацца ў фармаце Major.Minor.Patch.

Каб прагледзець спіс версій, для якіх падтрымліваецца праверка, звярніцеся да JSON-схеме на GitHubkubeval выкарыстоўвае для валідацыі. Калі трэба запусціць kubeval афлайн, запампуйце схемы і пазначце іх лакальнае месцазнаходжанне з дапамогай сцяга --schema-location.

Акрамя асобных YAML-файлаў, kubeval таксама можа працаваць з дырэкторыямі і stdin.

Акрамя таго, Kubeval лёгка інтэгруецца ў пайплайн CI. Жадаючыя праводзіць тэсты перад адпраўкай маніфэстаў у кластар будуць рады даведацца, што kubeval падтрымлівае тры фарматы вываду:

  1. Звычайны тэкст;
  2. JSON;
  3. Test Anything Protocol (TAP).

І любы з фарматаў можна выкарыстоўваць для далейшага парсінгу высновы, каб фармаваць зводку вынікаў жаданага выгляду.

Адзін з недахопаў kubeval – у цяперашні час ён не ўмее правяраць на адпаведнасць Custom Resource Definitions (CRDs). Аднак можна наладзіць kubeval ігнараваць іх.

Kubeval - выдатны інструмент для праверкі і ацэнкі рэсурсаў; праўда, трэба падкрэсліць, што паспяховае праходжанне тэсту не гарантуе, што рэсурс адпавядае лепшым практыкам.

Напрыклад, выкарыстанне тэга latest у кантэйнеры не адпавядае лепшым практыкам. Аднак kubeval не лічыць гэта памылкай і не паведамляе аб ёй. Гэта значыць, праверка такога YAML завершыцца без папярэджанняў.

Але што, калі трэба ацаніць YAML і выявіць парушэнні накшталт тэга latest? Як праверыць YAML-файл на адпаведнасць найлепшым практыкам?

2. Kube-score

Kube-score аналізуе маніфесты YAML і ацэньвае іх па ўбудаваным тэстах. Гэтыя тэсты выбіраюцца на аснове рэкамендацый па бяспецы і лепшых практык, напрыклад:

  • Запуск кантэйнера не пад root'ом.
  • Наяўнасць праверак здароўя pod'аў.
  • Заданне request'аў і limit'ов рэсурсаў.

Па выніках тэсту выдаецца тры вынікі: OK, ПАПЯРЭДЖАНЬНЕ и Крытычныя.

Kube-score можна паспрабаваць анлайн або ўсталяваць яго лакальна.

На момант напісання арыгінальнага артыкула самай свежай версіяй kube-score была 1.7.0.

Давайце выпрабуем яго на нашым маніфесце base-valid.yaml:

$ kube-score score 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 паказвае на наступныя недахопы:

  • Не настроены праверкі гатоўнасці.
  • Адсутнічаюць request'ы і limit'ы на рэсурсы CPU і памяць.
  • Не зададзены Pod disruption budgets.
  • Адсутнічаюць правілы раздзельнага існавання (anti-affinity) для максімізацыі даступнасці.
  • Кантэйнер выконваецца пад root'ам.

Усё гэта – слушныя заўвагі аб недахопах, якія варта ўхіліць, каб Deployment стаў больш эфектыўным і надзейным.

Каманда kube-score выводзіць інфармацыю ў лёгкачытальнай форме з уключэннем усіх парушэнняў тыпу ПАПЯРЭДЖАНЬНЕ и Крытычныя, Што вельмі дапамагае падчас распрацоўкі.

Жадаючыя выкарыстоўваць гэтую прыладу ў рамках пайплайна CI могуць уключыць больш сціснутую выснову з дапамогай сцяга --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, kube-score вяртае ненулявы код выхаду пры наяўнасці цеста, які завяршыўся памылкай Крытычныя. Таксама можна ўключыць падобную апрацоўку і для ПАПЯРЭДЖАНЬНЕ.

Акрамя таго, маецца магчымасць праверкі рэсурсаў на адпаведнасць розным версіям API (як і ў kubeval). Аднак гэтая інфармацыя за'hardcode'на ў самім kube-score: абраць іншую версію Kubernetes нельга. Падобнае абмежаванне можа стаць вялікай праблемай, калі вы маюць намер абнавіць кластар ці ў вас ёсць некалькі кластараў з рознымі версіямі K8s.

Звярніце ўвагу, што ужо ёсць issue з прапановай рэалізаваць гэтую магчымасць.

Падрабязней пра kube-score можна даведацца на афіцыйным сайце.

Тэсты kube-score - выдатны інструмент для ўкаранення лепшых практык, але што, калі неабходна ўнесці змены ў тэст або дадаць уласныя правілы? Нажаль, гэтага не атрымаецца зрабіць.

Kube-score не пашыраем: у яго нельга дадаць палітыкі ці падстроіць іх.

Калі патрабуецца пісаць карыстацкія тэсты для праверак на адпаведнасць палітыкам, прынятым у кампаніі, можна выкарыстоўваць адну з наступных чатырох прылад: config-lint, copper, conftest або polaris.

3. Config-lint

Config-lint - гэта інструмент для валідацыі канфігурацыйных файлаў фармату YAML, JSON, Terraform, CSV і маніфестаў Kubernetes.

Усталяваць яго можна з дапамогай інструкцый на сайце праекту.

Бягучы рэліз па стане на момант напісання арыгінальнага артыкула - 1.5.0.

Config-lint не ўтрымоўвае убудаваных тэстаў для праверкі маніфестаў Kubernetes.

Для правядзення любых тэстаў неабходна ствараць адпаведныя правілы. Яны запісваюцца ў YAML-файлы, званыя "наборамі правіл" (rulesets), і маюць наступную структуру:

version: 1
description: Rules for Kubernetes spec files
type: Kubernetes
files:
  - "*.yaml"
rules:
   # список правил

(rule.yaml)

Давайце вывучым яе больш уважліва:

  • Поле type паказвае, які тып канфігурацыі будзе выкарыстоўваць config-lint. Для маніфестаў K8s гэта заўсёды Kubernetes.
  • У полі 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/"

(rule-trusted-repo.yaml)

Для кожнага правіла павінны быць указаны наступныя атрыбуты:

  • id - Унікальны ідэнтыфікатар правілы;
  • severity - можа быць ПАДРАБОТКА, ПАПЯРЭДЖАНЬНЕ и NON_COMPLIANT;
  • message - пры парушэнні правіла адлюстроўваецца змесціва гэтага радка;
  • resource - Тып рэсурсу, да якога ўжываецца гэтае правіла;
  • assertions - спіс умоў, якія будуць ацэньвацца ў дачыненні да дадзенага рэсурсу.

У правіле вышэй assertion пад назвай every правярае, што ўсе кантэйнеры ў Deployment'е (key: spec.templates.spec.containers) выкарыстоўваюць давераныя вобразы (г.зн., якія пачынаюцца з my-company.com/).

Поўны ruleset выглядае наступным чынам:

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/"

(ruleset.yaml)

Каб выпрабаваць тэст, давайце захаваем яго як 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"
  }
]

Праверка завяршылася няўдала. Цяпер давайце праверым наступны маніфест з правільным рэпазітаром вобразаў:

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

(image-valid-mycompany.yaml)

Запускаем той жа самы тэст з прыведзеным вышэй маніфестам. Праблем не выяўлена:

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

Config-lint – перспектыўны фрэймворк, які дазваляе ствараць уласныя тэсты для праверкі YAML-маніфестаў Kubernetes з дапамогай YAML DSL.

Але што рабіць, калі патрабуецца больш складаная логіка і выпрабаванні? Няўжо магчымасці YAML не занадта малыя для гэтага? Што, калі можна было б ствараць тэсты на паўнавартаснай мове праграмавання?

4. Медзь

Copper V2 - гэта фрэймворк для валідацыі маніфестаў з дапамогай карыстацкіх тэстаў (аналаг config-lint).

Аднак ад апошняга ён адрозніваецца тым, што не выкарыстоўвае YAML для апісання тэстаў. Замест гэтага тэсты можна ствараць на JavaScript. Copper дае бібліятэку з некалькімі базавымі інструментамі, якія дапамагаюць счытваць інфармацыю аб аб'ектах Kubernetes і паведамляць аб памылках.

Паслядоўнасць крокаў для ўстаноўкі Copper можна знайсці ў афіцыйнай дакументацыі.

2.0.1 - самы свежы рэліз гэтай утыліты на момант напісання арыгінальнага артыкула.

Як і config-lint, Copper не мае убудаваных тэстаў. Давайце напішам адзін. Хай ён правярае, што deployment'ы выкарыстоўваюць кантэйнерныя выявы выключна з давераных рэпазітароў накшталт 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, выкарыстоўвайце каманду 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

Зразумела, што з дапамогай copper можна праводзіць больш складаныя тэсты - напрыклад, правяраць даменныя імёны ў маніфестах Ingress або адпрэчваць pod'ы, якія працуюць у прывілеяваным рэжыме.

У Copper убудаваны розныя службовыя функцыі:

  • DockerImage счытвае ўказаны ўваходны файл і стварае аб'ект з наступнымі атрыбутамі:
    • name - імя выявы,
    • tag - Тэг выявы,
    • registry - рэестр вобразаў,
    • registry_url - пратакол (https://) і рэестр вобразаў,
    • fqin - поўнае месцазнаходжанне выявы.
  • Функцыя findByName дапамагае знайсці рэсурс па зададзеным тыпе (kind) і імя (name) з уваходнага файла.
  • Функцыя findByLabels дапамагае знайсці рэсурс па паказаным тыпе (kind) і пазнакам (labels).

З усімі даступнымі службовымі функцыямі можна азнаёміцца тут.

Па змаўчанні ён загружае ўвесь уваходны YAML-файл у зменную $$ і робіць яе даступнай для скрыптоў (знаёмы метад для тых, хто мае досвед працы з jQuery).

Галоўны плюс Copper відавочны: вам не трэба асвойваць спецыялізаваную мову і можна карыстацца рознымі магчымасцямі JavaScript для стварэння ўласных тэстаў, такімі як інтэрпаляцыя радкоў, функцыі і г.д.

Варта таксама адзначыць, што бягучая версія Copper працуе з версіяй ES5 рухавічка JavaScript, а не з ES6.

Падрабязнасці даступныя на афіцыйным сайце праекта.

Зрэшты, калі вы не вельмі кахаеце JavaScript і аддаеце перавагу мову, адмыслова прызначаны для стварэння запытаў і апісанні палітык, вам варта звярнуць увагу на conftest.

5. Conftest

Conftest - гэта фрэймворк для праверкі канфігурацыйных дадзеных. Падыходзіць і для тэсціравання/верыфікацыі маніфестаў Kubernetes. Тэсты апісваюцца з дапамогай спецыялізаванай мовы запытаў Рего.

Усталяваць conftest можна з дапамогай інструкцый, прыведзеных на сайце праекта.

На момант напісання арыгінальнага артыкула самай апошняй даступнай версіяй была 0.18.2.

Па аналогіі з 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])
}

Цяпер давайце пратэстуем base-valid.yaml праз conftest:

$ 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. Яго сапраўднасць разглядаецца як парушэнне. Калі блокаў deny некалькі, conftest правярае іх незалежна адзін ад аднаго, і сапраўднасць любога з блокаў тлумачыцца як парушэнне.

Акрамя высновы па змаўчанні conftest падтрымлівае JSON, TAP і таблічны фармат - вельмі карысная магчымасць, калі трэба ўбудаваць справаздачы ў існуючы пайплайн CI. Задаць патрэбны фармат можна з дапамогай сцяга --output.

Для палягчэння адладкі палітык у conftest маецца сцяг --trace. Ён выводзіць трасіроўку таго, як conftest парсіць паказаныя файлы палітык.

Палітыкі conftest можна публікаваць і дзяліцца імі ў OCI-рэестрах (Open Container Initiative) у выглядзе артэфактаў.

каманды push и pull дазваляюць апублікаваць артэфакт або атрымаць існуючы артэфакт з выдаленага рэестра. Давайце паспрабуем апублікаваць створаную намі палітыку ў лакальны рэестр Docker з дапамогай conftest push.

Запусціце лакальны рэестр 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. Яна запампуе ў яе пакет, створаны папярэдняй камандай:

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

У часовай дырэкторыі з'явіцца падкаталог policy, які змяшчае наш файл з палітыкай:

$ 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) ці свой уласны рэестр.

Фармат артэфактаў - такі ж, як у пакетаў Open Policy Agent (OPA), што дазваляе выкарыстоўваць conftest для запуску тэстаў з наяўных пакетаў OPA.

Больш пра сумеснае выкарыстанне палітык і іншыя асаблівасці conftest можна даведацца на афіцыйным сайце праекта.

6. палярная зорка

Апошні інструмент, аб якім пойдзе гаворка ў гэтым артыкуле, - гэта Палярная зорка. (Яго леташні анонс мы ужо перакладалі - заўв. перав.)

Polaris можна ўсталяваць у кластар або выкарыстоўваць у рэжыме каманднага радка. Як вы ўжо здагадаліся, ен дазваляе статычна аналізаваць маніфесты Kubernetes.

Пры працы ў рэжыме каманднага радка даступныя ўбудаваныя тэсты, якія ахопліваюць такія вобласці, як бяспека і лепшыя практыкі (па аналогіі з kube-score). Акрамя таго, можна ствараць уласныя тэсты (як у config-lint, copper і conftest).

Іншымі словамі, Polaris спалучае ў сабе плюсы абедзвюх катэгорый прылад: са ўбудаванымі і карыстацкімі тэстамі.

Для ўсталёўкі Polaris у рэжыме каманднага радка скарыстайцеся інструкцыямі на сайце праекту.

На момант напісання арыгінальнага артыкула даступная версія 1.0.3.

Пасля завяршэння ўстаноўкі можна запусціць polaris на маніфесце base-valid.yaml з дапамогай наступнай каманды:

$ polaris audit --audit-path base-valid.yaml

Яна выведзе радок у фармаце 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": [
    /* длинный список */
  ]
}

Поўная выснова даступны тут.

Як і kube-score, Polaris выяўляе праблемы ў тых галінах, у якіх маніфест не адпавядае лепшым практыкам:

  • Адсутнічаюць праверкі здароўя pod'аў.
  • Не пазначаны тэгі для кантэйнерных вобразаў.
  • Кантэйнер выконваецца пад root'ам.
  • Не пазначаны request'ы і limit'ы для памяці і CPU.

Кожнаму тэсту ў залежнасці ад яго вынікаў прысвойваецца ступень крытычнасці: папярэджанне або небяспека. Каб даведацца больш аб наяўных убудаваных тэстах, звернецеся да дакументацыі.

Калі падрабязнасці не патрэбны, можна пазначыць сцяг --format score. У гэтым выпадку Polaris выведзе лік у дыяпазоне ад 1 да 100 кошт (г.зн. ацэнку):

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

Чым ацэнка бліжэй да 100, тым вышэй ступень адпаведнасці. Калі праверыць exit-код каманды polaris audit, апынецца, што ён роўны 0.

Прымусіць polaris audit завяршаць працу з ненулявым кодам можна з дапамогай двух сцягоў:

  • сцяг --set-exit-code-below-score прымае ў якасці аргументу парогавае значэнне ў дыяпазоне 1-100. У гэтым выпадку каманда завершыцца з exit-кодам 4, калі ацэнка апынецца ніжэй парогавай. Гэта вельмі зручна, калі ў вас ёсць нейкае парогавае значэнне (скажам, 75), і вам неабходна атрымаць alert, калі ацэнка апусціцца ніжэй.
  • сцяг --set-exit-code-on-danger прывядзе да таго, што каманда завершыцца з кодам 3, калі адзін з danger-тэстаў завершыцца няўдала.

Цяпер давайце паспрабуем стварыць карыстацкі тэст, які правярае, ці бярэцца выява з даверанага рэпазітара. Карыстальніцкія тэсты задаюцца ў фармаце 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 - паказвае на адну з катэгорый: Images, Health Checks, Security, Networking и Resources;
  • target– вызначае, да якога тыпу аб'екта (spec) прымяняецца тэст. Магчымыя значэнні: Container, Pod або Controller;
  • Сам тэст задаецца ў аб'екце schema з дапамогай JSON schema. У дадзеным тэсце ключавое слова pattern выкарыстоўваецца для параўнання крыніцы выявы з патрабаваным.

Для запуску вышэйпрыведзенага цеста неабходна стварыць наступную канфігурацыю 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/.+$

(polaris-conf.yaml)

Разбяром файл:

  • У полі checks прапісваюцца тэсты і іх узровень крытычнасці. Паколькі пажадана атрымліваць папярэджанне, калі выява бярэцца з ненадзейнай крыніцы, ставім тут узровень danger.
  • Сам тэст checkImageRepo затым прапісваецца ў аб'екце customChecks.

Захавайце файл як custom_check.yaml. Цяпер можна запусціць polaris audit з YAML-маніфестам, якія патрабуюць праверкі.

Пратэстуем наш маніфест base-valid.yaml:

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

Каманда polaris audit выканала толькі карыстацкі тэст, зададзены вышэй, і ён не ўвянчаўся поспехам.

Калі выправіць вобраз на my-company.com/http-echo:1.0, Polaris завершыцца паспяхова. Маніфест са зменамі ўжо ёсць у рэпазітары, так што вы можаце праверыць папярэднюю каманду на маніфесце image-valid-mycompany.yaml.

Цяпер узнікае пытанне: як запускаць убудаваныя тэсты сумесна з карыстацкімі? Лёгка! Проста трэба дадаць ідэнтыфікатары убудаваных тэстаў у файл канфігурацыі. У выніку ён набудзе наступны выгляд:

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/.+$

(config_with_custom_check.yaml)

Прыклад поўнага файла канфігурацыі даступны тут.

Праверыць маніфест base-valid.yaml, выкарыстоўваючы ўбудаваныя і карыстацкія тэсты, можна з дапамогай каманды:

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

Polaris дапаўняе ўбудаваныя тэсты карыстацкімі, тым самым спалучаючы лепшае з двух міроў.

З іншага боку, немагчымасць выкарыстоўваць больш магутныя мовы, такія як Rego або JavaScript, можа стаць абмяжоўвалым фактарам, якія перашкаджаюць стварэнню больш выдасканаленых тэстаў.

Дадатковая інфармацыя аб Polaris даступная на сайце праекта.

Рэзюмэ

Хоць існуе мноства прылад для праверкі і адзнакі YAML-файлаў Kubernetes, важна мець дакладнае ўяўленне аб тым, як тэсты будуць праектавацца і выконвацца.

Напрыклад, калі ўзяць маніфесты Kubernetes, якія праходзяць праз пайплайн, kubeval мог бы стаць першым крокам у такім пайплайне. Ён бы сачыў за тым, ці адпавядаюць вызначэнні аб'ектаў схеме API Kubernetes.

Пасля завяршэння падобнай праверкі можна было б перайсці да больш выдасканаленых тэстаў, такіх як адпаведнасць стандартным лепшым практыкам і асаблівым палітыкам. І тут бы спатрэбіліся kube-score і Polaris.

Тым, у каго складаныя патрабаванні і ёсць неабходнасць дэталёва наладжваць тэсты, падышлі б copper, config-lint і conftest..

Conftest і config-lint выкарыстоўваюць YAML для задання карыстацкіх тэстаў, а copper дае доступ да паўнавартаснай мовы праграмавання, што робіць яе даволі прывабным выбарам.

З іншага боку, ці варта скарыстацца адным з гэтых інструментаў і, такім чынам, ствараць усе тэсты ўручную, ці аддаць перавагу Polaris, і дапісаць у яго толькі тое, што трэба? Адназначнага адказу на гэтае пытанне няма.

Табліца ніжэй змяшчае кароткае апісанне кожнага інструмента:

Інструмент
прызначэнне
Недахопы
Карыстальніцкія тэсты

kubeval
Правярае YAML-маніфесты на адпаведнасць пэўнай версіі схемы API
Не ўмее працаваць з CRD
Няма

kube-score
Аналізуе маніфесты YAML на адпаведнасць лепшым практыкам
Нельга абраць сваю версію API Kubernetes для праверкі рэсурсаў
Няма

медзь
Агульны фрэймфорк для стварэння ўласных JavaScript-тэстаў для YAML-маніфестаў
Няма убудаваных тэстаў. Бедная дакументацыя
Так

config-lint
Агульны фрэймворк для стварэння тэстаў на прадметна-арыентаванай мове, убудаваным у YAML. Падтрымлівае розныя фарматы канфігурацый (напрыклад, Terraform)
Няма гатовых тэстаў. Убудаваных assertions і функцый можа аказацца недастаткова
Так

conftest
Фрэймворк для стварэння ўласных тэстаў на Rego (спецыялізаванай мове запытаў). Дазваляе дзяліцца палітыкамі праз OCI bundles
Няма убудаваных тэстаў. Даводзіцца вывучаць Rego. Docker Hub не падтрымліваецца пры публікацыі палітык
Так

Палярная зорка
Аналізуе YAML-маніфесты на адпаведнасць стандартным найлепшым практыкам. Дазваляе ствараць уласныя тэсты з дапамогай JSON Schema
Магчымасцяў тэстаў, заснаваных на JSON Schema, можа не хапіць
Так

Паколькі гэтыя прылады не залежаць ад доступу ў кластар Kubernetes, іх лёгка усталёўваць. Яны дазваляюць фільтраваць зыходныя файлы і забяспечваюць хуткую зваротную сувязь аўтарам pull request'аў у праектах.

PS ад перакладчыка

Чытайце таксама ў нашым блогу:

Крыніца: habr.com

Дадаць каментар