Каждый, кто работал с Helm чартами, сталкивался с необходимостью валидации values.yaml
. Стандартный подход с использованием JSON Schema работает, но часто становится громоздким и ограниченным. В этой статье я хочу представить Helm CEL — плагин, который позволяет использовать Common Expression Language (CEL) от Google для валидации конфигурации Helm чартов.
Что такое CEL и почему это важно?
Common Expression Language (CEL) — это простой и мощный язык выражений, разработанный Google. Он активно используется в экосистеме Kubernetes, например, для валидации CRD и конфигурации Istio. CEL предоставляет простой, но выразительный синтаксис для описания правил валидации.
Основные преимущества CEL:
Типобезопасность
Детерминированное выполнение
Простой и понятный синтаксис
Поддержка сложных условий и выражений
Встроенные функции для работы со строками, числами и коллекциями
Установка и базовое использование
Установка плагина выполняется одной командой:
helm plugin install https://github.com/idsulik/helm-cel
Вместо создания values.schema.json
, мы создаем файл values.cel.yaml
в директории чарта. Пример простой конфигурации:
rules:
- expr: "has(values.service) && has(values.service.port)"
desc: "Необходимо указать port в конфигурации service"
- expr: "values.service.port >= 1 && values.service.port <= 65535"
desc: "Port должен быть в диапазоне от 1 до 65535"
- expr: "!(has(values.replicaCount)) || values.replicaCount >= 1"
desc: "Если указан replicaCount, он должен быть больше или равен 1"
Запуск валидации:
helm cel ./mychart
Практические примеры
Давайте рассмотрим несколько реальных сценариев валидации и сравним их реализацию в JSON Schema и CEL.
1. Проверка обязательных полей
JSON Schema:
{
"required": ["service"],
"properties": {
"service": {
"required": ["port", "type"],
"properties": {
"port": {
"type": "integer"
},
"type": {
"type": "string",
"enum": ["ClusterIP", "NodePort", "LoadBalancer"]
}
}
}
}
}
CEL:
rules:
- expr: "has(values.service) && has(values.service.port) && has(values.service.type)"
desc: "service должен содержать port и type"
- expr: has(values.service.type) && values.service.type in ['ClusterIP', 'NodePort', 'LoadBalancer']
desc: "type должен быть одним из: ClusterIP, NodePort, LoadBalancer"
2. Условная валидация
Например, если включено persistence, требуется указать storageClass:
JSON Schema:
{
"if": {
"properties": {
"persistence": {
"const": true
}
}
},
"then": {
"required": ["storageClass"],
"properties": {
"storageClass": {
"type": "string",
"minLength": 1
}
}
}
}
CEL:
rules:
- expr: |
!has(values.persistence) ||
!values.persistence ||
(has(values.persistence.storageClass) && size(values.persistence.storageClass) > 0)
desc: "При включенном persistence необходимо указать storageClass"
Информативные сообщения об ошибках
Одно из главных преимуществ Helm CEL — понятные сообщения об ошибках:
❌ Validation failed: Запрошенная память не может превышать лимит
Rule: values.resources.requests.memory <= values.resources.limits.memory
Path: resources.requests.memory
Current value: "2Gi" (limits: "1Gi")
Производительность
CEL-выражения компилируются перед выполнением, что обеспечивает высокую производительность. Плагин добавляет минимальные накладные расходы к процессу работы с Helm, что делает его подходящим как для разработки, так и для CI/CD пайплайнов.
Расширенные возможности
Работа с типами данных
CEL предоставляет богатый набор функций для работы с различными типами данных:
rules:
# Проверка строк
- expr: "has(values.name) && size(values.name) >= 3 && size(values.name) <= 63"
desc: "Имя должно быть от 3 до 63 символов"
# Работа с числами
- expr: "type(values.timeout) == int && values.timeout > 0"
desc: "Timeout должен быть положительным числом"
# Проверка списков
- expr: |
!has(values.labels) ||
values.labels.all(k, k.matches('^[a-z0-9]([-a-z0-9]*[a-z0-9])?$'))
desc: "Labels должны соответствовать формату Kubernetes"
Комбинирование правил
rules:
- expr: |
!has(values.autoscaling) ||
!values.autoscaling.enabled ||
(has(values.autoscaling.minReplicas) &&
has(values.autoscaling.maxReplicas) &&
has(values.autoscaling.targetCPUUtilizationPercentage) &&
values.autoscaling.minReplicas <= values.autoscaling.maxReplicas &&
values.autoscaling.targetCPUUtilizationPercentage > 0 &&
values.autoscaling.targetCPUUtilizationPercentage <= 100)
desc: "Некорректная конфигурация автомасштабирования"
Интеграция с CI/CD
Пример использования в GitLab CI:
validate_helm:
image: alpine/helm:3.9.0
script:
- helm plugin install https://github.com/idsulik/helm-cel
- helm cel ./chart
rules:
- changes:
- chart/**/*
Заключение
Helm CEL предоставляет мощный и гибкий способ валидации Helm чартов. По сравнению с JSON Schema, он позволяет писать более понятные и поддерживаемые правила валидации. Комбинация знакомого синтаксиса, выразительных возможностей и четких сообщений об ошибках делает его отличным инструментом для работы с Helm чартами.
Просьба поставить ? для репозитория, если вы думаете, что плагин полезный.
Полезные ссылки
Комментарии (5)
linoles
17.11.2024 06:48Отличная статья о Helm CEL! Я впечатлён тем, как вы объяснили преимущества использования CEL для валидации Helm чартов. Примеры, приведенные в сравнении с JSON Schema, действительно помогают понять, насколько более гибким и читаемым является подход с CEL. Особенно полезно было увидеть применение условной валидации и информативные сообщения об ошибках. Это значительно упрощает процесс отладки. Было бы интересно узнать больше о возможностях интеграции Helm CEL с другими инструментами в CI/CD пайплайнах. Спасибо за ценный материал!
Cykooz
И один из главных недостатков, т.к. текст ошибки должен полностью написать человек самостоятельно. И поддерживать его актуальность в будущем, что может быть не совсем просто из-за человеческого фактора.
А что насчёт переводов текстов ошибок на разные языки?
Может там есть режим автоматической генерации описания ошибки, на основе выражения?
idsulik Автор
можно опустить описание, тогда будет ошибка без описания:
Насчет автогенерации описания, хорошая идея, но это наверно подойдет для простых выражений, а для сложных выйдет большое описание, что наверное так себе.
Постараюсь реализовать, если у кого есть желание, то welcome в pull requests)