Скрипт автоматического сбора и сравнения параметров микросервисов (Deployments), ConfigMap и HPA между LT и PROD кластерами Kubernetes.
Работает в Git Bash (Windows) и Linux. Не требует Python, Node.js, доступа в интернет и дополнительных зависимостей.
- Возможности
- Требования
- Структура проекта
- Установка и настройка
- Запуск
- Режимы работы
- Что сравнивается
- Выходные файлы
- Чтение HTML-отчёта
- Переменные окружения
- Дебаг
- Jenkins
- Безопасность
- .gitignore
- FAQ
- Changelog
- Сравнение Deployments — версия, количество реплик, ресурсы контейнеров
applicationиfluent-bit(CPU/Memory Limits и Requests) - Сравнение HPA — minReplicas, maxReplicas, targetCPUUtilizationPercentage
- Построчное сравнение ConfigMap — unified diff с подсветкой (аналог compare в VS Code)
- HTML-отчёт — таблица расхождений с цветовой подсветкой, diff ConfigMap в виде раскрывающихся спойлеров
- CSV-отчёт — разделитель
;для корректного открытия в русском Excel - Параллельный сбор данных — LT и PROD собираются одновременно
- Маппинг неймспейсов — поддержка различных имён неймспейсов между кластерами
- Автоочистка — сертификаты, приватные ключи и служебные Kubernetes-метаданные автоматически вырезаются из ConfigMap перед сравнением
- Прогресс-бар — визуальный индикатор обработки неймспейсов
- Совместимость — трёхуровневый fallback для извлечения данных (jsonpath новый → jsonpath старый → go-template), работает с kubectl 1.20+
- Git Bash (Windows) или bash 4+ (Linux/macOS)
- kubectl версии 1.20 и выше (включая 1.27+, где изменился синтаксис jsonpath-фильтров)
- Сетевой доступ к API-серверам обоих кластеров Kubernetes
├── compare.sh # Основной скрипт
├── config.env # Учётные данные подключения (НЕ коммитить в Git)
├── kubectl.exe # kubectl для Windows (НЕ коммитить в Git)
├── namespace_mappings.conf # Маппинг неймспейсов LT ↔ PROD
├── README.md # Документация
└── .gitignore # Исключения для Git
После запуска скрипт создаёт папку artifacts/ со следующей структурой:
artifacts/
└── compare_20260505_141445/ # Имя папки = дата и время запуска
├── LT/
│ ├── all_deployments_info.csv # Все деплойменты LT (сводный файл)
│ ├── namespace1_deployments.csv # Деплойменты по отдельным неймспейсам
│ └── namespace2_deployments.csv
├── PROD/
│ ├── all_deployments_info.csv # Все деплойменты PROD (сводный файл)
│ ├── namespace1_deployments.csv
│ └── namespace2_deployments.csv
├── ALL/
│ ├── report.html # HTML-отчёт (основной выходной файл)
│ ├── comparison.csv # Таблица расхождений (CSV, разделитель ;)
│ └── comparison_summary.txt # Текстовый отчёт для консоли/CI
└── configmaps/
├── LT/
│ └── namespace1/
│ ├── config-app.yaml # Скачанные ConfigMap в формате YAML
│ └── config-db.yaml
├── PROD/
│ └── namespace1/
│ ├── config-app.yaml
│ └── config-db.yaml
├── diffs/
│ ├── namespace1__config-app.diff # Unified diff для изменённых ConfigMap
│ └── namespace1__config-db.diff
└── configmap_summary.txt # Сводка по различиям в ConfigMap
Файл с учётными данными для подключения к кластерам. Располагается в одной папке со скриптом.
Пример config.env:
# ====== LT-кластер ======
export LT_KUBE_HOST="https://api.lt-cluster.example.ru:443"
export LT_KUBE_USERNAME="svc-compare-lt"
export LT_KUBE_PASSWORD="P@ssw0rd_LT"
# ====== PROD-кластер ======
export PROD_KUBE_HOST="https://api.prod-cluster.example.ru:443"
export PROD_KUBE_USERNAME="svc-compare-prod"
export PROD_KUBE_PASSWORD="P@ssw0rd_PROD"
# ====== Путь к kubectl ======
export KUBECTL_PATH="./kubectl.exe"Обязательные переменные:
| Переменная | Описание |
|---|---|
LT_KUBE_HOST |
URL API-сервера LT-кластера |
LT_KUBE_USERNAME |
Логин для LT-кластера |
LT_KUBE_PASSWORD |
Пароль для LT-кластера |
PROD_KUBE_HOST |
URL API-сервера PROD-кластера |
PROD_KUBE_USERNAME |
Логин для PROD-кластера |
PROD_KUBE_PASSWORD |
Пароль для PROD-кластера |
Опциональные переменные:
| Переменная | По умолчанию | Описание |
|---|---|---|
KUBECTL_PATH |
kubectl (из PATH) |
Путь к бинарнику kubectl |
Внимание: файл
config.envсодержит пароли. Будьте аккуратны.
Файл маппинга определяет, какие неймспейсы LT с какими неймспейсами PROD сравнивать.
Формат: НЕЙМСПЕЙС_LT=НЕЙМСПЕЙС_PROD — по одной паре на строку.
Пример namespace_mappings.conf:
# Основные сервисы
lk5-dev-app-01=lk5-prod-app-01
lk5-dev-app-02=lk5-prod-app-02
# Платёжный контур
lk5-dev-payment-01=lk5-prod-payment-01
# Неймспейсы с одинаковыми именами — тоже нужно указывать
shared-services=shared-services
Правила заполнения:
- Одна пара на строку, разделитель — знак
= - Пустые строки игнорируются
- Строки, начинающиеся с
#, считаются комментариями - В конце файла оставить одну пустую строку (обязательно для корректного чтения в bash)
- Пробелы вокруг
=допустимы (автоматически удаляются)
Важно: сбор данных выполняется из всех неймспейсов обоих кластеров, но сравнение — строго по указанным в маппинге парам. Неспаренные неймспейсы в отчёт о различиях не попадают.
Если файл маппинга отсутствует, скрипт переходит в режим прямого сравнения одноимённых неймспейсов.
./compare.shПосле запуска появится интерактивное меню выбора режима.
===========================================
Выберите режим работы скрипта:
[1] Собрать данные (LT/PROD) и сравнить
[2] Сравнить уже сохранённые данные
[3] Только сравнение ConfigMap
===========================================
Полный цикл работы:
- Логин в оба кластера
- Параллельный сбор данных (деплойменты, ConfigMap, HPA) из всех неймспейсов
- Сравнение по парам из маппинга
- Генерация HTML-отчёта и CSV
- Архивация результатов в
.tar.gz - Очистка временных файлов
Это основной рабочий режим.
Работает без обращения к кластерам. Использует ранее собранные данные:
- Выводит список папок в
artifacts/ - Предлагает выбрать нужный набор данных
- Заново выполняет сравнение и генерирует HTML-отчёт
Полезно, когда нужно пересравнить данные (например, после изменения файла маппинга) без повторного обращения к кластерам.
Логинится в кластеры, собирает и сравнивает только ConfigMap. Деплойменты не затрагиваются. Быстрее режима 1, если интересуют только различия в конфигурациях.
| Параметр | Источник в Kubernetes |
|---|---|
| Версия | metadata.labels["app.kubernetes.io/version"] |
| Кол-во подов | spec.replicas |
| Application CPU Limit | spec.template.spec.containers[application].resources.limits.cpu |
| Application Memory Limit | spec.template.spec.containers[application].resources.limits.memory |
| Application CPU Request | spec.template.spec.containers[application].resources.requests.cpu |
| Application Memory Request | spec.template.spec.containers[application].resources.requests.memory |
| Fluent-bit CPU Limit | spec.template.spec.containers[fluent-bit].resources.limits.cpu |
| Fluent-bit Memory Limit | spec.template.spec.containers[fluent-bit].resources.limits.memory |
| Fluent-bit CPU Request | spec.template.spec.containers[fluent-bit].resources.requests.cpu |
| Fluent-bit Memory Request | spec.template.spec.containers[fluent-bit].resources.requests.memory |
Контейнер application определяется по имени: либо буквально application, либо совпадающее с именем деплоймента.
| Параметр | Источник в Kubernetes |
|---|---|
| minReplicas | spec.minReplicas |
| maxReplicas | spec.maxReplicas |
| targetCPU | spec.targetCPUUtilizationPercentage |
HPA ищется по spec.scaleTargetRef.name, совпадающему с именем деплоймента.
Полное построчное сравнение YAML-содержимого через diff -u (unified diff).
Перед сравнением автоматически удаляются:
- Сертификаты (
-----BEGIN CERTIFICATE-----...-----END CERTIFICATE-----) - Приватные ключи (
-----BEGIN ... PRIVATE KEY-----...-----END ... PRIVATE KEY-----) - Публичные ключи (
-----BEGIN PUBLIC KEY-----...-----END PUBLIC KEY-----) - Kubernetes-метаданные:
resourceVersion,uid,creationTimestamp,selfLink,generation,namespace,managedFields
Эти поля всегда различаются между кластерами и не несут полезной информации при сравнении конфигураций.
Основной выходной файл. Открывается двойным кликом в любом браузере.
Содержит:
- Сводку — количество различий в деплойментах и ConfigMap
- Таблицу расхождений — каждое отличие в отдельной строке с цветовой подсветкой
- Diff ConfigMap — раскрывающиеся спойлеры для каждого изменённого ConfigMap с подсветкой синтаксиса
- Список ConfigMap, существующих только в одном кластере
Таблица расхождений в деплойментах. Кодировка UTF-8 с BOM, разделитель — ; (точка с запятой).
Корректно открывается в русском Excel без дополнительных настроек импорта.
Столбцы: Микросервис; Неймспейс LT; Неймспейс PROD; Параметр; Значение в LT; Значение в PROD
Текстовая сводка для чтения в консоли или парсинга в CI/CD пайплайнах.
Отдельный .diff файл для каждого изменённого ConfigMap.
Формат — unified diff. Открывается в VS Code (автоподсветка), Notepad++ (Language → Diff) или любом текстовом редакторе.
YAML-дампы всех ConfigMap. Сертификаты и служебные метаданные уже вырезаны. Файлы не модифицируются после скачивания — пригодны для ручного анализа или сравнения другими инструментами.
| Цвет строки | Значение |
|---|---|
| Жёлтый фон | Параметр различается между кластерами |
| Красный фон | Деплоймент или контейнер отсутствует в одном из кластеров |
| Серый фон | Разделитель неймспейсов |
Каждый ConfigMap отображается в виде раскрывающегося спойлера. В заголовке указано количество изменений (+N добавлено, -N удалено).
| Цвет строки | Значение |
|---|---|
Зелёный (+) |
Строка из PROD (добавлена или изменена) |
Красный (-) |
Строка из LT (удалена или изменена) |
Синий (@@) |
Заголовок блока изменений (позиция в файле) |
| Серый | Контекст (совпадающие строки вокруг изменений) |
Формат заголовка блока: @@ -45,16 +43,16 @@ означает «в LT файле — со строки 45, блок 16 строк; в PROD файле — со строки 43, блок 16 строк».
Все параметры задаются через config.env или экспортируются в shell перед запуском.
| Переменная | Обязательная | По умолчанию | Описание |
|---|---|---|---|
LT_KUBE_HOST |
да | — | URL API-сервера LT |
LT_KUBE_USERNAME |
да | — | Логин LT |
LT_KUBE_PASSWORD |
да | — | Пароль LT |
PROD_KUBE_HOST |
да | — | URL API-сервера PROD |
PROD_KUBE_USERNAME |
да | — | Логин PROD |
PROD_KUBE_PASSWORD |
да | — | Пароль PROD |
KUBECTL_PATH |
нет | kubectl |
Путь к бинарнику kubectl |
NS_MAPPING_FILE |
нет | ./namespace_mappings.conf |
Путь к файлу маппинга |
BUILD_NUMBER |
нет | текущая дата/время | Имя папки артефактов |
DEBUG |
нет | 0 |
1 — подробный вывод |
Пример config.env:
# ====== LT-кластер ======
export LT_KUBE_HOST="https://api.lt-cluster.example.ru:443"
export LT_KUBE_USERNAME="usernameForKubernetesLT"
export LT_KUBE_PASSWORD="P@ssw0rd_LT"
# ====== PROD-кластер ======
export PROD_KUBE_HOST="https://api.prod-cluster.example.ru:443"
export PROD_KUBE_USERNAME="usernameForKubernetesPROD"
export PROD_KUBE_PASSWORD="P@ssw0rd_PROD"
# ====== Путь к kubectl ======
export KUBECTL_PATH="./kubectl.exe"
Для подробного вывода (каждый обрабатываемый деплоймент, raw-данные):
export DEBUG=1
./compare.shПри наличии переменной окружения JENKINS_HOME скрипт выводит сводку в формате, удобном для Jenkins Console Output:
====== СРАВНЕНИЕ ЗАВЕРШЕНО ======
Артефакты: /path/to/artifacts/compare_20260505_143000
🚨 ОБНАРУЖЕНО РАЗЛИЧИЙ: 12
=================================
Пример использования в Jenkinsfile:
stage('Compare K8s Clusters') {
steps {
sh 'echo "1" | ./compare.sh'
}
post {
always {
archiveArtifacts artifacts: 'artifacts/**', fingerprint: true
publishHTML([
reportName: 'K8s Comparison',
reportDir: "artifacts/compare_${BUILD_NUMBER}/ALL",
reportFiles: 'report.html'
])
}
}
}- Скрипт не содержит учётных данных — все креды загружаются из
config.env - KUBECONFIG-файлы создаются во временной директории и удаляются после завершения
- Сертификаты и приватные ключи автоматически вырезаются из сохранённых ConfigMap
- Kubernetes-метаданные (
uid,resourceVersionи т.д.) удаляются из ConfigMap перед сравнением
Рекомендуемый .gitignore для репозитория:
# Учётные данные
config.env
config.env.bak
# Бинарные файлы
kubectl.exe
kubectl
# Результаты работы
artifacts/В Git коммитятся только: compare.sh, namespace_mappings.conf, README.md, .gitignore.
Данные собираются из всех неймспейсов, но в маппинге указан только один. Это нормально?
Да. Сбор данных — полный, по всем неймспейсам. Сравнение — только по парам из маппинга. CSV-файлы по отдельным неймспейсам остаются на случай, если потребуется сравнить другие пары позже (режим 2).
Можно ли добавить маппинг и пересравнить без обращения к кластерам?
Да. Изменить namespace_mappings.conf, запустить скрипт и выбрать режим [2].
Почему в Excel CSV отображается в одну колонку?
Скрипт использует ; как разделитель. Если Excel всё равно не разделяет — проверить региональные настройки Windows (Панель управления → Региональные стандарты → Дополнительные параметры → Разделитель элементов списка). Должен стоять ;.
Скрипт упал с ошибкой jsonpath. Что делать?
Экспортировать DEBUG=1 и запустить повторно. Скрипт использует три стратегии извлечения данных; если первая не работает — автоматически переключается на следующую. Если все три упали — вероятно, структура деплоймента нестандартная.
Как прочитать .diff файл?
Открыть в VS Code (автоподсветка) или Notepad++ (Language → Diff). Строки с + — из PROD, строки с - — из LT, без префикса — контекст.
- Построчное сравнение ConfigMap (unified diff)
- HTML-отчёт с подсветкой различий и раскрывающимися спойлерами
- CSV с разделителем
;для совместимости с русским Excel - Параллельный сбор LT и PROD
- Сравнение HPA (minReplicas, maxReplicas, targetCPU)
- Прогресс-бар обработки неймспейсов
- Режим «Только ConfigMap» (пункт 3 в меню)
- Автоматическое вырезание сертификатов, ключей и служебных метаданных из ConfigMap
- Извлечение данных переписано с grep на jsonpath/go-template с трёхуровневым fallback
- Сбор и сравнение деплойментов (версия, реплики, ресурсы)
- CSV-отчёт с разделителем
, - Маппинг неймспейсов
- Два режима работы: сбор+сравнение и сравнение сохранённых данных