init
This commit is contained in:
203
06-monitoring/02-debugging/README.md
Normal file
203
06-monitoring/02-debugging/README.md
Normal file
@@ -0,0 +1,203 @@
|
||||
# Урок 6.2 — Отладка проблем с политиками
|
||||
|
||||
## Файлы
|
||||
|
||||
| Файл | Описание |
|
||||
|------|----------|
|
||||
| `policy-exception-example.yaml` | Пример PolicyException |
|
||||
| `debug-context-inspector.yaml` | DEBUG политика для инспекции переменных |
|
||||
|
||||
## Диагностический чеклист
|
||||
|
||||
Когда политика не работает — проверяйте по порядку:
|
||||
|
||||
### Шаг 1: Политика применена и Ready?
|
||||
|
||||
```bash
|
||||
kubectl get clusterpolicies
|
||||
# Колонка READY должна быть True
|
||||
|
||||
kubectl get clusterpolicy my-policy -o yaml | grep -A 10 "status:"
|
||||
# conditions[0].status: "True"
|
||||
# conditions[0].type: Ready
|
||||
```
|
||||
|
||||
### Шаг 2: Match срабатывает?
|
||||
|
||||
```bash
|
||||
# Kyverno CLI — самый быстрый способ проверить
|
||||
kyverno apply my-policy.yaml \
|
||||
--resource my-resource.yaml \
|
||||
--detailed-results
|
||||
|
||||
# Вывод:
|
||||
# Rule my-rule -> resource: PASS/FAIL/SKIP
|
||||
# SKIP = match не сработал
|
||||
```
|
||||
|
||||
### Шаг 3: Ресурс не попадает в exclude?
|
||||
|
||||
```bash
|
||||
# Проверить лейблы namespace
|
||||
kubectl get namespace my-namespace --show-labels
|
||||
|
||||
# Проверить лейблы ресурса
|
||||
kubectl get pod my-pod --show-labels
|
||||
```
|
||||
|
||||
### Шаг 4: Логи admission controller
|
||||
|
||||
```bash
|
||||
# Включить более детальные логи временно
|
||||
kubectl set env deployment/kyverno-admission-controller \
|
||||
-n kyverno \
|
||||
KYVERNO_LOG_LEVEL=4
|
||||
|
||||
# Затем смотреть логи
|
||||
kubectl logs -n kyverno \
|
||||
-l app.kubernetes.io/component=admission-controller \
|
||||
--tail=50 -f | grep "my-policy\|my-resource"
|
||||
|
||||
# Вернуть обратно
|
||||
kubectl set env deployment/kyverno-admission-controller \
|
||||
-n kyverno \
|
||||
KYVERNO_LOG_LEVEL=2
|
||||
```
|
||||
|
||||
### Шаг 5: Dry-run для проверки мутаций
|
||||
|
||||
```bash
|
||||
# Видеть итоговый ресурс после мутации без создания
|
||||
kubectl apply -f my-pod.yaml --dry-run=server -o yaml
|
||||
|
||||
# Diff оригинала и мутированной версии
|
||||
diff <(cat my-pod.yaml) \
|
||||
<(kubectl apply -f my-pod.yaml --dry-run=server -o yaml 2>/dev/null)
|
||||
```
|
||||
|
||||
## Типичные ошибки и решения
|
||||
|
||||
### Ошибка 1: JMESPath — экранирование аннотаций
|
||||
|
||||
```yaml
|
||||
# НЕПРАВИЛЬНО — парсер не поймёт /
|
||||
key: "{{ request.object.metadata.annotations.company.com/env }}"
|
||||
|
||||
# ПРАВИЛЬНО — экранировать / через \"
|
||||
key: "{{ request.object.metadata.annotations.\"company.com/env\" }}"
|
||||
```
|
||||
|
||||
### Ошибка 2: Опциональные поля
|
||||
|
||||
```yaml
|
||||
# НЕПРАВИЛЬНО — упадёт если поле не задано
|
||||
pattern:
|
||||
spec:
|
||||
securityContext:
|
||||
runAsNonRoot: true
|
||||
|
||||
# ПРАВИЛЬНО — = для опциональных полей
|
||||
pattern:
|
||||
spec:
|
||||
=(securityContext):
|
||||
=(runAsNonRoot): true
|
||||
```
|
||||
|
||||
### Ошибка 3: foreach по несуществующему массиву
|
||||
|
||||
```yaml
|
||||
# НЕПРАВИЛЬНО — упадёт если initContainers не задан
|
||||
foreach:
|
||||
- list: "request.object.spec.initContainers"
|
||||
|
||||
# ПРАВИЛЬНО — fallback на пустой массив
|
||||
foreach:
|
||||
- list: "request.object.spec.initContainers || `[]`"
|
||||
```
|
||||
|
||||
### Ошибка 4: Match по kind без учёта controller
|
||||
|
||||
```yaml
|
||||
# Если хотите проверять Deployment — матчите Deployment
|
||||
match:
|
||||
resources:
|
||||
kinds:
|
||||
- Deployment # проверяет сам Deployment
|
||||
|
||||
# Если хотите проверять Pod через Deployment — матчите Pod
|
||||
# (Deployment controller создаёт Pod — Kyverno поймает его)
|
||||
match:
|
||||
resources:
|
||||
kinds:
|
||||
- Pod
|
||||
```
|
||||
|
||||
## Инспекция переменных через debug-политику
|
||||
|
||||
```bash
|
||||
# Создать namespace для отладки
|
||||
kubectl create namespace debug-namespace
|
||||
|
||||
# Применить debug политику (она всегда выдаёт fail с данными)
|
||||
kubectl apply -f debug-context-inspector.yaml
|
||||
|
||||
# Создать тестовый под — получить ошибку с содержимым переменных
|
||||
kubectl run debug-pod --image=nginx:1.25.3 \
|
||||
--restart=Never -n debug-namespace \
|
||||
--dry-run=server 2>&1
|
||||
|
||||
# Вывод покажет все переменные в сообщении ошибки:
|
||||
# [DEBUG] Pod: debug-pod
|
||||
# Namespace: debug-namespace
|
||||
# Namespace labels: map[kubernetes.io/metadata.name:debug-namespace]
|
||||
# ...
|
||||
|
||||
# Удалить debug политику после использования
|
||||
kubectl delete -f debug-context-inspector.yaml
|
||||
kubectl delete namespace debug-namespace
|
||||
```
|
||||
|
||||
## Работа с PolicyException
|
||||
|
||||
```bash
|
||||
# Применить исключение
|
||||
kubectl apply -f policy-exception-example.yaml
|
||||
|
||||
# Проверить что исключение работает
|
||||
kubectl run legacy-app-test \
|
||||
--image=nginx:1.25.3 \
|
||||
--restart=Never \
|
||||
-n production
|
||||
# Под без limits должен создаться без ошибок
|
||||
|
||||
# Посмотреть все активные исключения
|
||||
kubectl get policyexceptions -A
|
||||
|
||||
# Найти истекающие исключения (скрипт)
|
||||
kubectl get policyexceptions -A -o json | \
|
||||
jq -r '.items[] |
|
||||
.metadata.name + " expires: " +
|
||||
.metadata.annotations["exception.company.com/expires"]' | \
|
||||
sort
|
||||
```
|
||||
|
||||
## Анализ PolicyReport для диагностики
|
||||
|
||||
```bash
|
||||
# Найти ресурс который нарушает политику
|
||||
POLICY="require-resource-limits"
|
||||
kubectl get policyreports -A -o json | \
|
||||
jq --arg p "$POLICY" \
|
||||
-r '.items[] | .metadata.namespace as $ns |
|
||||
.results[] |
|
||||
select(.policy == $p and .result == "fail") |
|
||||
"\($ns)/\(.resources[0].name): \(.message)"'
|
||||
|
||||
# Сводная статистика
|
||||
kubectl get policyreports -A -o json | \
|
||||
jq '{
|
||||
total: [.items[].results[]] | length,
|
||||
pass: [.items[].results[] | select(.result=="pass")] | length,
|
||||
fail: [.items[].results[] | select(.result=="fail")] | length
|
||||
}'
|
||||
```
|
||||
42
06-monitoring/02-debugging/debug-context-inspector.yaml
Normal file
42
06-monitoring/02-debugging/debug-context-inspector.yaml
Normal file
@@ -0,0 +1,42 @@
|
||||
apiVersion: kyverno.io/v1
|
||||
kind: ClusterPolicy
|
||||
metadata:
|
||||
name: debug-context-inspector
|
||||
annotations:
|
||||
policies.kyverno.io/title: "DEBUG: Инспектор контекстных переменных"
|
||||
policies.kyverno.io/description: >-
|
||||
ТОЛЬКО ДЛЯ ОТЛАДКИ. Всегда отклоняет запрос, выводя содержимое
|
||||
переменных в сообщении ошибки. Помогает понять, что видит политика.
|
||||
УДАЛИТЕ после отладки — не держите в production.
|
||||
spec:
|
||||
validationFailureAction: Enforce
|
||||
background: false # не запускать в background — только для живых запросов
|
||||
rules:
|
||||
- name: print-context
|
||||
match:
|
||||
resources:
|
||||
kinds:
|
||||
- Pod
|
||||
namespaces:
|
||||
- debug-namespace # применяем только в отдельном namespace
|
||||
context:
|
||||
- name: nsLabels
|
||||
apiCall:
|
||||
urlPath: "/api/v1/namespaces/{{ request.object.metadata.namespace }}"
|
||||
jmesPath: "metadata.labels"
|
||||
validate:
|
||||
# Всегда fail — выводим данные в сообщении
|
||||
message: >-
|
||||
[DEBUG] Pod: {{ request.object.metadata.name }}
|
||||
Namespace: {{ request.object.metadata.namespace }}
|
||||
Namespace labels: {{ nsLabels }}
|
||||
Pod labels: {{ request.object.metadata.labels }}
|
||||
User: {{ request.userInfo.username }}
|
||||
Groups: {{ request.userInfo.groups }}
|
||||
Operation: {{ request.operation }}
|
||||
Containers: {{ request.object.spec.containers[].name }}
|
||||
deny:
|
||||
conditions:
|
||||
- key: "true"
|
||||
operator: Equals
|
||||
value: "true"
|
||||
24
06-monitoring/02-debugging/policy-exception-example.yaml
Normal file
24
06-monitoring/02-debugging/policy-exception-example.yaml
Normal file
@@ -0,0 +1,24 @@
|
||||
apiVersion: kyverno.io/v2beta1
|
||||
kind: PolicyException
|
||||
metadata:
|
||||
name: legacy-app-resource-limits-exception
|
||||
namespace: production
|
||||
annotations:
|
||||
# Обязательные поля для аудита — заполняйте всегда
|
||||
exception.company.com/expires: "2025-06-01"
|
||||
exception.company.com/reason: "Legacy приложение в процессе миграции. JIRA-4321"
|
||||
exception.company.com/approved-by: "platform-team"
|
||||
exception.company.com/created-by: "john.doe"
|
||||
spec:
|
||||
exceptions:
|
||||
- policyName: require-resource-limits
|
||||
ruleNames:
|
||||
- check-container-limits
|
||||
match:
|
||||
resources:
|
||||
kinds:
|
||||
- Pod
|
||||
namespaces:
|
||||
- production
|
||||
names:
|
||||
- legacy-app-* # только legacy поды
|
||||
Reference in New Issue
Block a user