Files
DevOpsLab/Makefile
Сергей Антропов 9677aea281 feat: автоматическое обновление Ingress хостов при изменениях
- Добавлен вызов manage_hosts.py после:
  - make k8s manifest apply
  - make k8s addon
  - make k8s helm apply
  - make k8s helm update
- Создан тестовый манифест grafana-ingress
- Автоматическое обновление /etc/hosts при любых изменениях Ingress
2025-10-26 10:06:41 +03:00

1696 lines
93 KiB
Makefile
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# =============================================================================
# AnsibleLab - Универсальная система тестирования Ansible ролей
# Автор: Сергей Антропов
# Сайт: https://devops.org.ru
# =============================================================================
SHELL := /bin/bash
# =============================================================================
# ПЕРЕМЕННЫЕ
# =============================================================================
# Цвета для вывода
RED := \033[0;31m
GREEN := \033[0;32m
YELLOW := \033[0;33m
BLUE := \033[0;34m
PURPLE := \033[0;35m
CYAN := \033[0;36m
WHITE := \033[0;37m
RESET := \033[0m
# Глобальные переменные
PROJECT_NAME ?= ansible-lab
VERSION ?= 0.1.0
AUTHOR ?= "Сергей Антропов"
SITE ?= "https://devops.org.ru"
DOCKER_IMAGE ?= inecs/ansible-lab:ansible-controller-latest
DOCKER_K8S_IMAGE ?= inecs/ansible-lab:k8s-latest
DOCKER_DIND_IMAGE ?= docker:27-dind
CONTAINER_NAME ?= ansible-controller
# Переменные для Docker Hub
DOCKER_REGISTRY ?= inecs/ansible-lab
DOCKER_VERSION ?= latest
DOCKER_IMAGES := ansible-controller alt-linux astra-linux redos rhel centos7 centos8 centos9 alma rocky ubuntu20 ubuntu22 ubuntu24 debian9 debian10 debian11 debian12
# Multi-arch поддержка
DOCKER_PLATFORMS ?= linux/amd64,linux/arm64
DOCKER_BUILDX_BUILDER ?= multiarch-builder
# Базовые образы и их теги
BASE_IMAGES := altlinux/p9 astralinux/astra-1.7 redos/redos:9 registry.access.redhat.com/ubi8/ubi centos:7 quay.io/centos/centos:8 quay.io/centos/centos:stream9 almalinux:8 rockylinux:8 ubuntu:20.04 ubuntu:22.04 ubuntu:24.04 debian:9 debian:10 debian:11 debian:bookworm
.PHONY: role vault git docker presets controller k8s help update-playbooks generate-docs setup-cicd list create delete
# =============================================================================
# КОМАНДЫ ДЛЯ РАБОТЫ С РОЛЯМИ
# =============================================================================
role:
@case "$(word 2, $(MAKECMDGOALS))" in \
lint) \
ROLE_NAME="$(word 3, $(MAKECMDGOALS))"; \
if [ -z "$$ROLE_NAME" ]; then \
echo "🔍 Проверка синтаксиса всех ролей ..."; \
docker run --rm --name $(CONTAINER_NAME) -v "$(PWD):/workspace" -w /workspace -e ANSIBLE_FORCE_COLOR=1 $(DOCKER_IMAGE) bash -c "ansible-lint roles/ --config-file .ansible-lint || true"; \
else \
echo "🔍 Проверка синтаксиса роли: $$ROLE_NAME"; \
if [ -d "roles/$$ROLE_NAME" ]; then \
docker run --rm --name $(CONTAINER_NAME) -v "$(PWD):/workspace" -w /workspace -e ANSIBLE_FORCE_COLOR=1 $(DOCKER_IMAGE) bash -c "ansible-lint roles/$$ROLE_NAME/ --config-file .ansible-lint || true"; \
else \
echo "❌ Роль '$$ROLE_NAME' не найдена в roles/"; \
echo "📋 Доступные роли:"; \
ls -1 roles/ | grep -v "\.yml$$" | sed 's/^/ - /'; \
exit 1; \
fi; \
fi; \
echo ""; \
echo "✅ Lint завершен";; \
test) \
echo "🚀 Тестирование ролей ..."; \
PRESET="default"; \
ARGS="$(wordlist 3,10,$(MAKECMDGOALS))"; \
if [ -n "$$ARGS" ]; then \
PRESET="$$(echo $$ARGS | cut -d' ' -f1)"; \
fi; \
echo "📋 Используется пресет: $$PRESET"; \
if [ ! -f "molecule/presets/$$PRESET.yml" ]; then \
echo "❌ Ошибка: Пресет '$$PRESET' не найден!"; \
echo "💡 Доступные пресеты:"; \
ls -1 molecule/presets/*.yml 2>/dev/null | sed 's|molecule/presets/||g' | sed 's|\.yml||g' | sed 's/^/ - /' || echo " ⚠️ Пресеты не найдены"; \
exit 1; \
fi; \
echo ""; \
echo "🔧 Запуск ansible-controller контейнера..."; \
docker run --rm --name $(CONTAINER_NAME) -v "$(PWD):/workspace" -w /workspace \
-v /var/run/docker.sock:/var/run/docker.sock \
-u root \
-e ANSIBLE_FORCE_COLOR=1 \
-e MOLECULE_PRESET=$$PRESET \
-e MOLECULE_EPHEMERAL_DIRECTORY=/tmp/molecule_workspace \
$(DOCKER_IMAGE) \
bash -c "mkdir -p /tmp/molecule_workspace/inventory && cd molecule/default && ansible-playbook -i localhost, create.yml --connection=local -e molecule_ephemeral_directory=/tmp/molecule_workspace && ansible-playbook -i /tmp/molecule_workspace/inventory/hosts.ini site.yml; ansible-playbook -i localhost, destroy.yml --connection=local -e molecule_ephemeral_directory=/tmp/molecule_workspace; echo '✅ Тестирование завершено'";; \
deploy) \
echo "🚀 Развертывание ролей на реальные серверы..."; \
echo ""; \
if [ ! -f "inventory/hosts.ini" ]; then \
echo "❌ Ошибка: Файл inventory/hosts.ini не найден!"; \
echo "💡 Создайте файл inventory/hosts.ini с вашими серверами"; \
exit 1; \
fi; \
echo "📋 Используется inventory: inventory/hosts.ini"; \
echo "📄 Содержимое inventory:"; \
docker run --rm -v "$(PWD):/workspace" -w /workspace $(DOCKER_IMAGE) cat inventory/hosts.ini || cat inventory/hosts.ini; \
echo ""; \
echo "🚀 Запуск развертывания (в контейнере)..."; \
docker run --rm --name $(CONTAINER_NAME) -v "$(PWD):/workspace" -w /workspace \
-v ~/.ssh:/root/.ssh:ro \
-e ANSIBLE_FORCE_COLOR=1 \
$(DOCKER_IMAGE) \
bash -c "ansible-playbook -i inventory/hosts.ini roles/deploy.yml --check"; \
echo ""; \
read -p "Продолжить развертывание? (y/N): " confirm; \
if [ "$$confirm" = "y" ] || [ "$$confirm" = "Y" ]; then \
docker run --rm --name $(CONTAINER_NAME) -v "$(PWD):/workspace" -w /workspace \
-v ~/.ssh:/root/.ssh:ro \
-e ANSIBLE_FORCE_COLOR=1 \
$(DOCKER_IMAGE) \
bash -c "ansible-playbook -i inventory/hosts.ini roles/deploy.yml"; \
else \
echo "❌ Развертывание отменено"; \
fi;; \
list) \
./scripts/role-manager.sh list;; \
create) \
./scripts/role-manager.sh create < /dev/tty;; \
delete) \
./scripts/role-manager.sh delete < /dev/tty;; \
*) \
echo "🎯 Доступные команды:"; \
echo ""; \
echo " 🚀 make role test [preset] - протестировать роли с preset'ом"; \
echo " 💡 Примеры:"; \
echo " make role test # с default preset"; \
echo " make role test minimal # с minimal preset"; \
echo " make role test all-images # со всеми образами"; \
echo " make role test etcd-patroni # с etcd-patroni preset"; \
echo ""; \
echo " 🚀 make role deploy - развернуть роли на реальные серверы"; \
echo " 💡 Требует: inventory/hosts.ini"; \
echo " 💡 Примеры:"; \
echo " make role deploy # развертывание всех ролей"; \
echo " ansible-playbook -i inventory/hosts.ini roles/deploy.yml --tags web"; \
echo " ansible-playbook -i inventory/hosts.ini roles/deploy.yml --limit webservers"; \
echo " ansible-playbook -i inventory/hosts.ini roles/deploy.yml --check"; \
echo " 💡 Документация: docs/deploy-yml-customization.md"; \
echo ""; \
echo " 🔍 make role lint [role] - проверить синтаксис ролей"; \
echo " 💡 Использует: ansible-lint"; \
echo " 💡 Без параметра: проверяет все роли"; \
echo " 💡 С параметром: проверяет конкретную роль"; \
echo " 💡 Валидация: показывает доступные роли при ошибке"; \
echo " 💡 Примеры:"; \
echo " make role lint # проверить все роли"; \
echo " make role lint devops # проверить только devops"; \
echo " make role lint ping # проверить только ping"; \
echo ""; \
echo " 📋 make role list - показать все роли"; \
echo " 💡 Показывает: список всех ролей в roles/"; \
echo ""; \
echo " make role create - создать новую роль"; \
echo " 💡 Интерактивно: запрашивает имя роли"; \
echo " 💡 Создает: структуру папок и файлов"; \
echo " 💡 Обновляет: roles/deploy.yml"; \
echo ""; \
echo " 🗑️ make role delete - удалить роль"; \
echo " 💡 Интерактивно: запрашивает имя роли"; \
echo " 💡 Удаляет: папку роли и файлы"; \
echo " 💡 Обновляет: roles/deploy.yml"; \
echo ""; \
echo " 🔧 ДОПОЛНИТЕЛЬНАЯ ИНФОРМАЦИЯ О ЛИНТИНГЕ:"; \
echo " 💡 Линтинг проверяет: синтаксис, стиль, лучшие практики"; \
echo " 💡 Профили: production, basic, min"; \
echo " 💡 Конфигурация: .ansible-lint"; \
echo " 💡 Ошибки: показываются с номерами строк"; \
echo " 💡 Валидация: автоматическая проверка существования роли";; \
esac
# =============================================================================
# КОМАНДЫ ДЛЯ РАБОТЫ С PRESET'АМИ
# =============================================================================
presets:
@case "$(word 2, $(MAKECMDGOALS))" in \
list) \
echo "📋 Доступные пресеты:"; \
echo ""; \
preset_count=0; \
for preset in molecule/presets/*.yml; do \
if [ -f "$$preset" ]; then \
preset_name=$$(basename "$$preset" .yml); \
preset_desc=$$(grep -E "^#description:" "$$preset" | head -1 | sed 's/^#description: *//' || echo "Описание отсутствует"); \
host_count=$$(grep -c "^- name:" "$$preset" 2>/dev/null || echo "?"); \
printf " 📄 %s - %s (%s хостов)\n" "$$preset_name" "$$preset_desc" "$$host_count"; \
preset_count=$$((preset_count + 1)); \
fi; \
done; \
if [ $$preset_count -eq 0 ]; then \
echo " ⚠️ Пресеты не найдены"; \
fi;; \
info) \
if [ -z "$(PRESET)" ]; then \
echo "❌ Ошибка: Укажите PRESET=имя_пресета"; \
echo "💡 Пример: make presets info PRESET=etcd-patroni"; \
exit 1; \
fi; \
if [ ! -f "molecule/presets/$(PRESET).yml" ]; then \
echo "❌ Ошибка: Пресет '$(PRESET)' не найден!"; \
echo "💡 Доступные пресеты:"; \
make presets list; \
exit 1; \
fi; \
echo "📋 Информация о пресете: $(PRESET)"; \
echo ""; \
echo "📄 Описание:"; \
grep -E "^#description:" "molecule/presets/$(PRESET).yml" | head -1 | sed 's/^#description: *//' || echo "Описание отсутствует"; \
echo ""; \
echo "🏠 Хосты:"; \
grep -E "^- name:" "molecule/presets/$(PRESET).yml" | sed 's/^- name: / - /' || echo "Хосты не найдены"; \
echo ""; \
echo "🌐 Сеть:"; \
grep -E "^docker_network:" "molecule/presets/$(PRESET).yml" | sed 's/^docker_network: / - /' || echo "Сеть не указана"; \
echo ""; \
echo "🐳 Образы:"; \
grep -E "^- " "molecule/presets/$(PRESET).yml" | grep -E "family:" | sed 's/.*family: / - /' || echo "Образы не найдены";; \
test) \
if [ -z "$(PRESET)" ]; then \
echo "❌ Ошибка: Укажите PRESET=имя_пресета"; \
echo "💡 Пример: make presets test PRESET=etcd-patroni"; \
exit 1; \
fi; \
if [ ! -f "molecule/presets/$(PRESET).yml" ]; then \
echo "❌ Ошибка: Пресет '$(PRESET)' не найден!"; \
echo "💡 Доступные пресеты:"; \
make presets list; \
exit 1; \
fi; \
echo "🚀 Тестирование с пресетом: $(PRESET)"; \
echo ""; \
docker run --rm --name $(CONTAINER_NAME) -v "$(PWD):/workspace" -w /workspace \
-v /var/run/docker.sock:/var/run/docker.sock \
-e ANSIBLE_FORCE_COLOR=1 \
-e MOLECULE_PRESET=$(PRESET) \
$(DOCKER_IMAGE) \
bash -c "cd molecule/default && molecule test" || echo "✅ Тестирование завершено";; \
*) \
echo "🎯 Доступные команды:"; \
echo ""; \
echo " 📋 make presets list - показать список всех preset'ов"; \
echo " 💡 Показывает: название, описание, количество хостов"; \
echo ""; \
echo " 📄 make presets info - подробная информация о preset'е"; \
echo " 💡 Показывает: описание, хосты, сеть, образы"; \
echo " 💡 Требует: PRESET=имя_пресета"; \
echo ""; \
echo " 🚀 make presets test - запустить тест с preset'ом"; \
echo " 💡 Запускает: molecule test с выбранным preset'ом"; \
echo " 💡 Требует: PRESET=имя_пресета"; \
echo ""; \
echo "💡 Примеры:"; \
echo " make presets list # показать все preset'ы"; \
echo " make presets info PRESET=etcd-patroni # информация о etcd-patroni"; \
echo " make presets test PRESET=minimal # тест с minimal preset"; \
echo " make presets test PRESET=performance # тест с performance preset";; \
esac
# =============================================================================
# КОМАНДЫ ДЛЯ РАБОТЫ С VAULT
# =============================================================================
vault:
@case "$(word 2, $(MAKECMDGOALS))" in \
init) \
echo "🔐 Инициализация vault..."; \
if [ ! -f "vault/.vault" ]; then \
echo "📝 Создание файла vault/.vault..."; \
read -sp "Введите пароль для vault: " PASSWORD; \
echo ""; \
echo "$$PASSWORD" > vault/.vault; \
chmod 600 vault/.vault; \
echo "✅ Файл vault/.vault создан"; \
else \
echo "✅ Файл vault/.vault уже существует"; \
fi;; \
create) \
if [ ! -f "vault/.vault" ]; then \
echo "⚠️ Файл vault/.vault не найден!"; \
echo "💡 Сначала создайте файл: make vault init"; \
exit 1; \
fi; \
echo "🔐 Создание файла секретов..."; \
read -p "Введите имя файла (без .yml): " FILE; \
docker run --rm -it -v "$(PWD):/workspace" -w /workspace \
$(DOCKER_IMAGE) \
ansible-vault create --encrypt-vault-id default --vault-password-file vault/.vault vault/$$FILE.yml;; \
edit) \
echo "🔐 Редактирование секретов..."; \
ls -la vault/*.yml 2>/dev/null || echo "Нет зашифрованных файлов"; \
echo ""; \
read -p "Введите имя файла (без .yml): " FILE; \
docker run --rm -it -v "$(PWD):/workspace" -w /workspace \
$(DOCKER_IMAGE) \
ansible-vault edit --vault-password-file vault/.vault vault/$$FILE.yml;; \
show) \
echo "🔐 Просмотр секретов..."; \
ls -la vault/*.yml 2>/dev/null || echo "Нет зашифрованных файлов"; \
echo ""; \
read -p "Введите имя файла (без .yml): " FILE; \
docker run --rm -v "$(PWD):/workspace" -w /workspace \
$(DOCKER_IMAGE) \
ansible-vault view --vault-password-file vault/.vault vault/$$FILE.yml;; \
delete) \
echo "🔐 Удаление секретов..."; \
ls -la vault/*.yml 2>/dev/null || echo "Нет зашифрованных файлов"; \
echo ""; \
read -p "Введите имя файла (без .yml): " FILE; \
rm -f vault/$$FILE.yml;; \
encrypt) \
echo "🔐 Шифрование файла..."; \
ls -la vault/*.yml 2>/dev/null || echo "Нет файлов для шифрования"; \
echo ""; \
read -p "Введите имя файла (без .yml): " FILE; \
docker run --rm -v "$(PWD):/workspace" -w /workspace \
$(DOCKER_IMAGE) \
ansible-vault encrypt --encrypt-vault-id default --vault-password-file vault/.vault vault/$$FILE.yml;; \
decrypt) \
echo "🔐 Расшифровка файла..."; \
ls -la vault/*.yml 2>/dev/null || echo "Нет зашифрованных файлов"; \
echo ""; \
read -p "Введите имя файла (без .yml): " FILE; \
docker run --rm -v "$(PWD):/workspace" -w /workspace \
$(DOCKER_IMAGE) \
ansible-vault decrypt --vault-password-file vault/.vault vault/$$FILE.yml;; \
rekey) \
echo "🔐 Смена пароля..."; \
ls -la vault/*.yml 2>/dev/null || echo "Нет зашифрованных файлов"; \
echo ""; \
read -p "Введите имя файла (без .yml): " FILE; \
docker run --rm -it -v "$(PWD):/workspace" -w /workspace \
$(DOCKER_IMAGE) \
ansible-vault rekey --vault-password-file vault/.vault vault/$$FILE.yml;; \
check) \
echo "🔍 Проверка vault файлов..."; \
if [ ! -d "vault" ]; then \
echo "❌ Директория vault не найдена"; \
exit 1; \
fi; \
vault_files=$$(find vault -name "*.yml" -type f 2>/dev/null); \
if [ -z "$$vault_files" ]; then \
echo "⚠️ Vault файлы не найдены"; \
exit 0; \
fi; \
echo "📋 Найденные vault файлы:"; \
for file in $$vault_files; do \
echo " 📄 $$file"; \
done; \
echo ""; \
echo "🔍 Проверка структуры..."; \
for file in $$vault_files; do \
if grep -q "ANSIBLE_VAULT" "$$file"; then \
echo "$$file - зашифрован"; \
else \
echo " ⚠️ $$file - не зашифрован"; \
fi; \
done;; \
scan) \
echo "🔍 Поиск секретов в проекте..."; \
echo "📋 Поиск потенциальных секретов:"; \
find . -name "*.yml" -o -name "*.yaml" | grep -v ".git" | while read file; do \
if grep -qE "(password|secret|key|token|api_key)" "$$file" 2>/dev/null; then \
echo " ⚠️ $$file - содержит потенциальные секреты"; \
fi; \
done; \
echo ""; \
echo "💡 Рекомендации:"; \
echo " - Используйте ansible-vault для шифрования секретов"; \
echo " - Не храните секреты в открытом виде"; \
echo " - Регулярно проверяйте файлы на наличие секретов";; \
*) \
echo "🎯 Доступные команды:"; \
echo ""; \
echo " 🔑 make vault init - инициализировать vault (создать vault/.vault)"; \
echo " 💡 Первая команда для настройки vault"; \
echo ""; \
echo " 🔐 make vault create - создать новый файл секретов"; \
echo " 💡 Интерактивное создание зашифрованного файла"; \
echo ""; \
echo " ✏️ make vault edit - редактировать существующие секреты"; \
echo " 💡 Открывает редактор для изменения секретов"; \
echo ""; \
echo " 👁️ make vault show - показать содержимое секретов"; \
echo " 💡 Расшифровывает и показывает содержимое"; \
echo ""; \
echo " 🗑️ make vault delete - удалить файл секретов"; \
echo " 💡 Безвозвратное удаление файла"; \
echo ""; \
echo " 🔒 make vault encrypt - зашифровать существующий файл"; \
echo " 💡 Шифрует незашифрованный файл"; \
echo ""; \
echo " 🔓 make vault decrypt - расшифровать файл"; \
echo " 💡 Создает незашифрованную копию"; \
echo ""; \
echo " 🔑 make vault rekey - сменить пароль шифрования"; \
echo " 💡 Изменяет пароль для существующего файла"; \
echo ""; \
echo " ✅ make vault check - проверить vault файлы"; \
echo " 💡 Проверяет структуру и статус файлов"; \
echo ""; \
echo " 🔍 make vault scan - поиск потенциальных секретов"; \
echo " 💡 Сканирует проект на наличие незашифрованных секретов";; \
esac
# =============================================================================
# КОМАНДЫ ДЛЯ РАБОТЫ С GIT
# =============================================================================
git:
@case "$(word 2, $(MAKECMDGOALS))" in \
push) \
echo "📤 Отправка изменений в репозиторий..."; \
git add .; \
git commit -m "Обновление проекта"; \
git push origin main;; \
pull) \
echo "📥 Получение изменений из репозитория..."; \
git pull origin main;; \
new) \
echo "🌿 Создание новой ветки..."; \
read -p "Введите имя ветки: " BRANCH; \
git checkout -b "$$BRANCH"; \
echo "✅ Ветка '$$BRANCH' создана";; \
*) \
echo "🎯 Доступные команды:"; \
echo ""; \
echo " 📤 make git push - отправить изменения в репозиторий"; \
echo " 💡 Выполняет: git add . && git commit && git push"; \
echo ""; \
echo " 📥 make git pull - получить изменения из репозитория"; \
echo " 💡 Выполняет: git pull origin main"; \
echo ""; \
echo " 🌿 make git new - создать новую ветку"; \
echo " 💡 Интерактивно запрашивает имя ветки"; \
echo " 💡 Выполняет: git checkout -b имя_ветки";; \
esac
# =============================================================================
# КОМАНДЫ ДЛЯ РАБОТЫ С DOCKER
# =============================================================================
docker:
@case "$(word 2, $(MAKECMDGOALS))" in \
prepare) \
echo "🔧 Подготовка Docker образов для Docker Hub..."; \
echo "📋 Registry: $(DOCKER_REGISTRY)"; \
echo "📋 Version: $(DOCKER_VERSION)"; \
echo "📋 Images: $(DOCKER_IMAGES)"; \
echo ""; \
echo "💡 Для работы с Docker Hub выполните:"; \
echo " docker login - авторизация в Docker Hub"; \
echo " make docker build - сборка образов"; \
echo " make docker push - отправка в Docker Hub";; \
build) \
echo "🐳 Сборка Docker образов (multi-arch)..."; \
echo "📋 Платформы: $(DOCKER_PLATFORMS)"; \
echo "📋 Builder: $(DOCKER_BUILDX_BUILDER)"; \
echo "📋 Registry: $(DOCKER_REGISTRY)"; \
echo "📋 Version: $(DOCKER_VERSION)"; \
echo "📋 Images: $(DOCKER_IMAGES)"; \
echo "⚠️ ВНИМАНИЕ: RED OS и Astra Linux собираются только для AMD64"; \
echo ""; \
$(MAKE) docker setup-builder; \
for image in $(DOCKER_IMAGES); do \
echo "🔨 Сборка $(DOCKER_REGISTRY)/$$image:$(DOCKER_VERSION)"; \
$(MAKE) docker-build-image IMAGE=$$image; \
done; \
echo "✅ Образы собраны";; \
rebuild) \
echo "🔄 Полная пересборка Docker образов (multi-arch)..."; \
echo "📋 Платформы: $(DOCKER_PLATFORMS)"; \
echo "📋 Builder: $(DOCKER_BUILDX_BUILDER)"; \
echo "📋 Registry: $(DOCKER_REGISTRY)"; \
echo "📋 Version: $(DOCKER_VERSION)"; \
echo "📋 Images: $(DOCKER_IMAGES)"; \
echo "⚠️ ВНИМАНИЕ: RED OS и Astra Linux собираются только для AMD64"; \
echo "🧹 Очистка кеша и старых образов..."; \
echo ""; \
$(MAKE) docker clean; \
$(MAKE) docker clean-builder; \
$(MAKE) docker setup-builder; \
for image in $(DOCKER_IMAGES); do \
echo "🔨 Пересборка $(DOCKER_REGISTRY):$$image-$(DOCKER_VERSION)"; \
$(MAKE) docker-build-image IMAGE=$$image; \
done; \
echo "✅ Образы пересобраны с нуля";; \
push) \
echo "📤 Отправка Docker образов в Docker Hub..."; \
for image in $(DOCKER_IMAGES); do \
echo "📤 Отправка $(DOCKER_REGISTRY):$$image-$(DOCKER_VERSION)"; \
docker push $(DOCKER_REGISTRY):$$image-$(DOCKER_VERSION); \
done; \
echo "✅ Образы отправлены в Docker Hub";; \
pull) \
echo "📥 Загрузка Docker образов из Docker Hub..."; \
for image in $(DOCKER_IMAGES); do \
echo "📥 Загрузка $(DOCKER_REGISTRY):$$image-$(DOCKER_VERSION)"; \
docker pull $(DOCKER_REGISTRY):$$image-$(DOCKER_VERSION) || echo "⚠️ Образ $$image не найден в Docker Hub"; \
done; \
echo "✅ Загрузка завершена";; \
clean) \
echo "🧹 Очистка Docker образов и builds..."; \
for image in $(DOCKER_IMAGES); do \
echo "🗑️ Удаление $(DOCKER_REGISTRY):$$image-$(DOCKER_VERSION)"; \
docker rmi $(DOCKER_REGISTRY):$$image-$(DOCKER_VERSION) 2>/dev/null || true; \
done; \
echo "🗑️ Удаление кеша builds для наших образов..."; \
docker buildx prune --filter type=exec.cachemount --filter type=source.local --filter type=source.git.checkout --force 2>/dev/null || true; \
echo "✅ Образы и кеш builds очищены";; \
info) \
echo "📊 Информация об образах..."; \
for image in $(DOCKER_IMAGES); do \
if docker images | grep -q "$(DOCKER_REGISTRY):$$image"; then \
echo "📦 $(DOCKER_REGISTRY):$$image-$(DOCKER_VERSION)"; \
docker images | grep "$(DOCKER_REGISTRY):$$image" | head -1; \
fi; \
done;; \
update) \
echo "🔄 Обновление всех образов..."; \
$(MAKE) docker pull; \
$(MAKE) docker build; \
$(MAKE) docker push; \
echo "✅ Все образы обновлены";; \
purge) \
echo "🧹 Полная очистка Docker..."; \
echo "⚠️ ВНИМАНИЕ: Это удалит ВСЕ Docker данные!"; \
echo ""; \
read -p "Продолжить? (y/N): " confirm; \
if [ "$$confirm" = "y" ] || [ "$$confirm" = "Y" ]; then \
echo "🛑 Остановка всех контейнеров..."; \
docker stop $$(docker ps -aq) 2>/dev/null || true; \
echo "🗑️ Удаление всех контейнеров..."; \
docker rm $$(docker ps -aq) 2>/dev/null || true; \
echo "🗑️ Удаление всех образов..."; \
docker rmi $$(docker images -aq) 2>/dev/null || true; \
echo "🗑️ Удаление всех томов..."; \
docker volume rm $$(docker volume ls -q) 2>/dev/null || true; \
echo "🗑️ Удаление всех сетей..."; \
docker network rm $$(docker network ls -q) 2>/dev/null || true; \
echo "🧹 Очистка системы..."; \
docker system prune -af --volumes; \
echo "✅ Docker полностью очищен"; \
else \
echo "❌ Очистка отменена"; \
fi;; \
clean-builder) \
echo "🧹 Очистка multi-arch builder..."; \
$(MAKE) docker-reset-builder;; \
build-image) \
if [ -z "$(IMAGE)" ]; then \
echo "❌ Ошибка: Укажите IMAGE=имя_образа"; \
echo "💡 Пример: make docker build-image IMAGE=centos"; \
echo "💡 Доступные образы: $(DOCKER_IMAGES)"; \
exit 1; \
fi; \
if [ ! -d "dockerfiles/$(IMAGE)" ]; then \
echo "❌ Ошибка: Директория dockerfiles/$(IMAGE) не найдена!"; \
echo "💡 Доступные образы:"; \
for img in $(DOCKER_IMAGES); do \
if [ -d "dockerfiles/$$img" ]; then \
echo " - $$img"; \
fi; \
done; \
exit 1; \
fi; \
echo "🔨 Сборка отдельного образа: $(IMAGE)"; \
echo "📋 Платформы: $(DOCKER_PLATFORMS)"; \
echo "📋 Builder: $(DOCKER_BUILDX_BUILDER)"; \
echo "📋 Registry: $(DOCKER_REGISTRY)"; \
echo ""; \
$(MAKE) docker setup-builder; \
$(MAKE) docker-build-image IMAGE=$(IMAGE); \
echo "✅ Образ $(IMAGE) собран";; \
setup-builder) \
echo "🔧 Настройка multi-arch builder в контейнере..."; \
if $(MAKE) docker-check-builder >/dev/null 2>&1; then \
echo "✅ Builder $(DOCKER_BUILDX_BUILDER) уже существует и готов"; \
docker buildx use $(DOCKER_BUILDX_BUILDER); \
else \
echo "📦 Создание builder $(DOCKER_BUILDX_BUILDER)..."; \
$(MAKE) docker-create-builder; \
fi; \
echo "🔍 Финальная проверка builder..."; \
$(MAKE) docker-check-builder;; \
diagnose) \
echo "🔍 Диагностика buildx проблем..."; \
$(MAKE) docker-diagnose-buildx;; \
reset-builder) \
echo "🔄 Сброс buildx builder..."; \
$(MAKE) docker-reset-builder;; \
*) \
echo "🎯 Доступные команды:"; \
echo ""; \
echo " 🔧 make docker prepare - подготовка к работе с Docker Hub"; \
echo " 💡 Показывает: registry, version, список образов"; \
echo " 💡 Рекомендует: docker login перед работой"; \
echo ""; \
echo " 🐳 make docker build - собрать все Docker образы (multi-arch)"; \
echo " 💡 Собирает: ansible-controller, alt-linux, astra-linux, redos"; \
echo " 💡 Собирает: rhel, centos, alma, rocky, ubuntu, debian"; \
echo " 💡 Платформы: $(DOCKER_PLATFORMS)"; \
echo " 💡 Ограничения: RED OS и Astra Linux только AMD64"; \
echo " 💡 Тегирует: inecs/образ:<tag> (автоматически извлекает теги)"; \
echo " 💡 Отправляет: автоматически в Docker Hub"; \
echo ""; \
echo " 🔨 make docker build-image IMAGE=<имя> - собрать отдельный образ"; \
echo " 💡 Пример: make docker build-image IMAGE=centos"; \
echo " 💡 Собирает: только указанный образ (multi-arch)"; \
echo " 💡 Доступные образы: $(DOCKER_IMAGES)"; \
echo " 💡 Платформы: $(DOCKER_PLATFORMS)"; \
echo ""; \
echo " 🔄 make docker rebuild - полная пересборка с очисткой кеша"; \
echo " 💡 Очищает: все локальные образы и кеш"; \
echo " 💡 Пересобирает: все образы с нуля"; \
echo " 💡 Полезно: при проблемах с кешем или зависимостями"; \
echo " 💡 Выполняет: clean + clean-builder + setup-builder + build"; \
echo ""; \
echo " 📤 make docker push - отправить образы в Docker Hub"; \
echo " 💡 Требует: docker login"; \
echo " 💡 Отправляет: все образы в registry inecs"; \
echo ""; \
echo " 📥 make docker pull - загрузить образы из Docker Hub"; \
echo " 💡 Загружает: все образы из registry inecs"; \
echo " 💡 Пропускает: отсутствующие образы"; \
echo ""; \
echo " 🧹 make docker clean - удалить локальные образы и кеш builds"; \
echo " 💡 Удаляет: все образы inecs/ansible-lab:*"; \
echo " 💡 Очищает: кеш builds (exec.cachemount, source.local, git.checkout)"; \
echo " 💡 Сохраняет: другие builds в системе"; \
echo " 💡 Безопасно: игнорирует ошибки"; \
echo ""; \
echo " 🧹 make docker clean-builder - очистка multi-arch builder"; \
echo " 💡 Удаляет: builder контейнер и buildkit контейнеры"; \
echo " 💡 Полезно: при проблемах со сборкой";; \
setup-builder) \
echo "🔧 Настройка multi-arch builder в контейнере..."; \
if $(MAKE) docker-check-builder >/dev/null 2>&1; then \
echo "✅ Builder $(DOCKER_BUILDX_BUILDER) уже существует и готов"; \
docker buildx use $(DOCKER_BUILDX_BUILDER); \
else \
echo "📦 Создание builder $(DOCKER_BUILDX_BUILDER)..."; \
$(MAKE) docker-create-builder; \
fi; \
echo "🔍 Финальная проверка builder..."; \
$(MAKE) docker-check-builder;; \
diagnose) \
echo "🔍 Диагностика buildx проблем..."; \
$(MAKE) docker-diagnose-buildx;; \
reset-builder) \
echo "🔄 Сброс buildx builder..."; \
$(MAKE) docker-reset-builder;; \
*) \
echo "🎯 Доступные команды:"; \
echo ""; \
echo " 🔧 make docker prepare - подготовка к работе с Docker Hub"; \
echo " 💡 Показывает: registry, version, список образов"; \
echo " 💡 Рекомендует: docker login перед работой"; \
echo ""; \
echo " 🐳 make docker build - собрать все Docker образы (multi-arch)"; \
echo " 💡 Собирает: ansible-controller, alt-linux, astra-linux, redos"; \
echo " 💡 Собирает: rhel, centos, alma, rocky, ubuntu, debian"; \
echo " 💡 Платформы: $(DOCKER_PLATFORMS)"; \
echo " 💡 Ограничения: RED OS и Astra Linux только AMD64"; \
echo " 💡 Тегирует: inecs/образ:<tag> (автоматически извлекает теги)"; \
echo " 💡 Отправляет: автоматически в Docker Hub"; \
echo ""; \
echo " 🔨 make docker build-image IMAGE=<имя> - собрать отдельный образ"; \
echo " 💡 Пример: make docker build-image IMAGE=centos"; \
echo " 💡 Собирает: только указанный образ (multi-arch)"; \
echo " 💡 Доступные образы: $(DOCKER_IMAGES)"; \
echo " 💡 Платформы: $(DOCKER_PLATFORMS)"; \
echo ""; \
echo " 🔄 make docker rebuild - полная пересборка с очисткой кеша"; \
echo " 💡 Очищает: все локальные образы и кеш"; \
echo " 💡 Пересобирает: все образы с нуля"; \
echo " 💡 Полезно: при проблемах с кешем или зависимостями"; \
echo " 💡 Выполняет: clean + clean-builder + setup-builder + build"; \
echo ""; \
echo " 📤 make docker push - отправить образы в Docker Hub"; \
echo " 💡 Требует: docker login"; \
echo " 💡 Отправляет: все образы в registry inecs"; \
echo ""; \
echo " 📥 make docker pull - загрузить образы из Docker Hub"; \
echo " 💡 Загружает: все образы из registry inecs"; \
echo " 💡 Пропускает: отсутствующие образы"; \
echo ""; \
echo " 🧹 make docker clean - удалить локальные образы и кеш builds"; \
echo " 💡 Удаляет: все образы inecs/ansible-lab:*"; \
echo " 💡 Очищает: кеш builds (exec.cachemount, source.local, git.checkout)"; \
echo " 💡 Сохраняет: другие builds в системе"; \
echo " 💡 Безопасно: игнорирует ошибки"; \
echo ""; \
echo " 🧹 make docker clean-builder - очистка multi-arch builder"; \
echo " 💡 Удаляет: builder контейнер и buildkit контейнеры"; \
echo " 💡 Полезно: при проблемах со сборкой"; \
echo ""; \
echo " 🔧 make docker setup-builder - настройка multi-arch builder"; \
echo " 💡 Создает: builder в контейнере (не в системе)"; \
echo " 💡 Поддерживает: amd64 и arm64 архитектуры"; \
echo " 💡 Безопасно: использует inspect вместо buildx ls"; \
echo ""; \
echo " 🔍 make docker diagnose - диагностика buildx проблем"; \
echo " 💡 Проверяет: версии, контексты, builder, registry"; \
echo " 💡 Показывает: рекомендации по устранению проблем"; \
echo ""; \
echo " 🔄 make docker reset-builder - сброс buildx builder"; \
echo " 💡 Удаляет: старый builder и buildkit контейнеры"; \
echo " 💡 Создает: новый builder с предварительной загрузкой образа"; \
echo ""; \
echo " 📊 make docker info - информация о собранных образах"; \
echo " 💡 Показывает: размер, дата создания, теги"; \
echo ""; \
echo " 🔄 make docker update - обновить все образы"; \
echo " 💡 Выполняет: pull + build + push"; \
echo " 💡 Полный цикл обновления"; \
echo ""; \
echo " 💥 make docker purge - ПОЛНАЯ очистка Docker"; \
echo " ⚠️ УДАЛЯЕТ: все контейнеры, образы, тома, сети"; \
echo " ⚠️ ОСТАНОВИТ: все запущенные контейнеры"; \
echo " ⚠️ ТРЕБУЕТ: подтверждение пользователя"; \
echo "";; \
esac
# =============================================================================
# ВСПОМОГАТЕЛЬНЫЕ ФУНКЦИИ ДЛЯ DOCKER
# =============================================================================
# Надежная проверка существования buildx builder без использования buildx ls
# Использует docker buildx inspect вместо buildx ls для избежания зависаний
.PHONY: docker-check-builder
docker-check-builder:
@echo "🔍 Проверка buildx builder $(DOCKER_BUILDX_BUILDER)..."
@if docker buildx inspect $(DOCKER_BUILDX_BUILDER) >/dev/null 2>&1; then \
echo "✅ Builder $(DOCKER_BUILDX_BUILDER) существует и готов"; \
exit 0; \
else \
echo "❌ Builder $(DOCKER_BUILDX_BUILDER) не найден"; \
exit 1; \
fi
# Безопасное создание buildx builder с предварительной очисткой
.PHONY: docker-create-builder
docker-create-builder:
@echo "🔧 Создание buildx builder $(DOCKER_BUILDX_BUILDER)..."
@echo "📦 Предварительная загрузка образа buildkit..."
@docker pull moby/buildkit:buildx-stable-1 || echo "⚠️ Не удалось загрузить moby/buildkit:buildx-stable-1, будет использован авто-пулл"
@echo "🗑️ Удаление существующего builder (если есть)..."
@docker buildx rm -f $(DOCKER_BUILDX_BUILDER) 2>/dev/null || true
@echo "📦 Создание нового builder..."
@docker buildx create \
--name $(DOCKER_BUILDX_BUILDER) \
--driver docker-container \
--driver-opt image=moby/buildkit:buildx-stable-1 \
--use || exit 1
@echo "⏳ Ожидание запуска buildkit контейнера..."
@sleep 3
@echo "🔍 Проверка готовности builder..."
@docker buildx inspect --builder $(DOCKER_BUILDX_BUILDER) --bootstrap >/dev/null || exit 1
@echo "✅ Builder $(DOCKER_BUILDX_BUILDER) создан и готов к работе"
# Диагностика проблем с buildx
.PHONY: docker-diagnose-buildx
docker-diagnose-buildx:
@echo "🔍 ДИАГНОСТИКА BUILDX ПРОБЛЕМ"
@echo "=========================================="
@echo ""
@echo "📊 1. Версии Docker и Buildx:"
@docker version --format "Docker: {{.Server.Version}}" 2>/dev/null || echo "❌ Docker недоступен"
@docker buildx version 2>/dev/null || echo "❌ Buildx недоступен"
@echo ""
@echo "📋 2. Docker контексты (поиск мертвых tcp://):"
@docker context ls 2>/dev/null || echo "❌ Не удалось получить список контекстов"
@echo ""
@echo "🔍 3. Проверка builder $(DOCKER_BUILDX_BUILDER):"
@if docker buildx inspect $(DOCKER_BUILDX_BUILDER) >/dev/null 2>&1; then \
echo "✅ Builder $(DOCKER_BUILDX_BUILDER) существует"; \
docker buildx inspect $(DOCKER_BUILDX_BUILDER) --bootstrap >/dev/null 2>&1 && echo "✅ Builder готов" || echo "❌ Builder не готов"; \
else \
echo "❌ Builder $(DOCKER_BUILDX_BUILDER) не найден"; \
fi
@echo ""
@echo "🐳 4. Buildkit контейнеры:"
@docker ps -a --filter "name=buildx_buildkit" --format "table {{.Names}}\t{{.Status}}\t{{.CreatedAt}}" 2>/dev/null || echo "❌ Не удалось получить список контейнеров"
@echo ""
@echo "🌐 5. Проверка доступа к registry:"
@echo "📥 Тест загрузки moby/buildkit:buildx-stable-1..."
@timeout 30 docker pull moby/buildkit:buildx-stable-1 >/dev/null 2>&1 && echo "✅ Доступ к registry OK" || echo "❌ Проблемы с доступом к registry"
@echo ""
@echo "🔧 6. Docker socket доступ:"
@if [ -S /var/run/docker.sock ]; then \
echo "✅ Docker socket доступен: /var/run/docker.sock"; \
ls -la /var/run/docker.sock; \
else \
echo "❌ Docker socket недоступен: /var/run/docker.sock"; \
fi
@echo ""
@echo "💡 РЕКОМЕНДАЦИИ:"
@echo " - Если buildx ls зависает: удалите мертвые контексты (docker context rm <name>)"
@echo " - Если pull зависает: настройте прокси или используйте mirror registry"
@echo " - Если builder не создается: проверьте права доступа к Docker socket"
@echo " - Для полной очистки: make docker clean-builder && make docker-create-builder"
# Быстрая очистка и пересоздание builder
.PHONY: docker-reset-builder
docker-reset-builder:
@echo "🔄 Сброс buildx builder..."
@echo "🗑️ Удаление builder $(DOCKER_BUILDX_BUILDER)..."
@docker buildx rm -f $(DOCKER_BUILDX_BUILDER) 2>/dev/null || true
@echo "🧹 Очистка buildkit контейнеров..."
@docker ps -a --filter "name=buildx_buildkit" --format "{{.Names}}" | xargs -r docker rm -f 2>/dev/null || true
@echo "📦 Создание нового builder..."
@$(MAKE) docker-create-builder
@echo "✅ Builder сброшен и готов к работе"
# Извлечение тега из базового образа
docker-get-base-tag:
@if [ -z "$(IMAGE)" ]; then \
echo "❌ Ошибка: IMAGE не указан"; \
exit 1; \
fi; \
case "$(IMAGE)" in \
alt-linux) \
BASE_IMAGE="alt:p9"; \
echo "📦 Загрузка базового образа $$BASE_IMAGE..." >&2; \
docker pull $$BASE_IMAGE >/dev/null 2>&1 || echo "⚠️ Не удалось загрузить $$BASE_IMAGE" >&2; \
TAG=$$(docker inspect --format='{{.RepoTags}}' $$BASE_IMAGE 2>/dev/null | tr -d '[]' | cut -d',' -f1 | cut -d':' -f2 | tr -d ' ' || echo "latest");; \
astra-linux) \
BASE_IMAGE="registry.astralinux.ru/library/astra/ubi17:1.7.6.uu2"; \
echo "📦 Загрузка базового образа $$BASE_IMAGE..." >&2; \
docker pull $$BASE_IMAGE >/dev/null 2>&1 || echo "⚠️ Не удалось загрузить $$BASE_IMAGE" >&2; \
TAG=$$(docker inspect --format='{{.RepoTags}}' $$BASE_IMAGE 2>/dev/null | tr -d '[]' | cut -d',' -f1 | cut -d':' -f2 | tr -d ' ' || echo "latest");; \
redos) \
BASE_IMAGE="registry.red-soft.ru/ubi7/ubi"; \
echo "📦 Загрузка базового образа $$BASE_IMAGE..." >&2; \
docker pull $$BASE_IMAGE >/dev/null 2>&1 || echo "⚠️ Не удалось загрузить $$BASE_IMAGE" >&2; \
TAG=$$(docker inspect --format='{{.RepoTags}}' $$BASE_IMAGE 2>/dev/null | tr -d '[]' | cut -d',' -f1 | cut -d':' -f2 | tr -d ' ' || echo "latest");; \
rhel) \
BASE_IMAGE="registry.access.redhat.com/ubi8/ubi"; \
echo "📦 Загрузка базового образа $$BASE_IMAGE..." >&2; \
docker pull $$BASE_IMAGE >/dev/null 2>&1 || echo "⚠️ Не удалось загрузить $$BASE_IMAGE" >&2; \
TAG=$$(docker inspect --format='{{.RepoTags}}' $$BASE_IMAGE 2>/dev/null | tr -d '[]' | cut -d',' -f1 | cut -d':' -f2 | tr -d ' ' || echo "latest");; \
centos7) \
BASE_IMAGE="centos:7"; \
echo "📦 Загрузка базового образа $$BASE_IMAGE..." >&2; \
docker pull $$BASE_IMAGE >/dev/null 2>&1 || echo "⚠️ Не удалось загрузить $$BASE_IMAGE" >&2; \
TAG=$$(docker inspect --format='{{.RepoTags}}' $$BASE_IMAGE 2>/dev/null | tr -d '[]' | cut -d',' -f1 | cut -d':' -f2 | tr -d ' ' || echo "latest");; \
centos8) \
BASE_IMAGE="quay.io/centos/centos:8"; \
echo "📦 Загрузка базового образа $$BASE_IMAGE..." >&2; \
docker pull $$BASE_IMAGE >/dev/null 2>&1 || echo "⚠️ Не удалось загрузить $$BASE_IMAGE" >&2; \
TAG=$$(docker inspect --format='{{.RepoTags}}' $$BASE_IMAGE 2>/dev/null | tr -d '[]' | cut -d',' -f1 | cut -d':' -f2 | tr -d ' ' || echo "latest");; \
centos9) \
BASE_IMAGE="quay.io/centos/centos:stream9"; \
echo "📦 Загрузка базового образа $$BASE_IMAGE..." >&2; \
docker pull $$BASE_IMAGE >/dev/null 2>&1 || echo "⚠️ Не удалось загрузить $$BASE_IMAGE" >&2; \
TAG=$$(docker inspect --format='{{.RepoTags}}' $$BASE_IMAGE 2>/dev/null | tr -d '[]' | cut -d',' -f1 | cut -d':' -f2 | tr -d ' ' || echo "latest");; \
alma) \
BASE_IMAGE="almalinux:8"; \
echo "📦 Загрузка базового образа $$BASE_IMAGE..." >&2; \
docker pull $$BASE_IMAGE >/dev/null 2>&1 || echo "⚠️ Не удалось загрузить $$BASE_IMAGE" >&2; \
TAG=$$(docker inspect --format='{{.RepoTags}}' $$BASE_IMAGE 2>/dev/null | tr -d '[]' | cut -d',' -f1 | cut -d':' -f2 | tr -d ' ' || echo "latest");; \
rocky) \
BASE_IMAGE="rockylinux:8"; \
echo "📦 Загрузка базового образа $$BASE_IMAGE..." >&2; \
docker pull $$BASE_IMAGE >/dev/null 2>&1 || echo "⚠️ Не удалось загрузить $$BASE_IMAGE" >&2; \
TAG=$$(docker inspect --format='{{.RepoTags}}' $$BASE_IMAGE 2>/dev/null | tr -d '[]' | cut -d',' -f1 | cut -d':' -f2 | tr -d ' ' || echo "latest");; \
ubuntu20) \
BASE_IMAGE="ubuntu:20.04"; \
echo "📦 Загрузка базового образа $$BASE_IMAGE..." >&2; \
docker pull $$BASE_IMAGE >/dev/null 2>&1 || echo "⚠️ Не удалось загрузить $$BASE_IMAGE" >&2; \
TAG=$$(docker inspect --format='{{.RepoTags}}' $$BASE_IMAGE 2>/dev/null | tr -d '[]' | cut -d',' -f1 | cut -d':' -f2 | tr -d ' ' || echo "latest");; \
ubuntu22) \
BASE_IMAGE="ubuntu:22.04"; \
echo "📦 Загрузка базового образа $$BASE_IMAGE..." >&2; \
docker pull $$BASE_IMAGE >/dev/null 2>&1 || echo "⚠️ Не удалось загрузить $$BASE_IMAGE" >&2; \
TAG=$$(docker inspect --format='{{.RepoTags}}' $$BASE_IMAGE 2>/dev/null | tr -d '[]' | cut -d',' -f1 | cut -d':' -f2 | tr -d ' ' || echo "latest");; \
ubuntu24) \
BASE_IMAGE="ubuntu:24.04"; \
echo "📦 Загрузка базового образа $$BASE_IMAGE..." >&2; \
docker pull $$BASE_IMAGE >/dev/null 2>&1 || echo "⚠️ Не удалось загрузить $$BASE_IMAGE" >&2; \
TAG=$$(docker inspect --format='{{.RepoTags}}' $$BASE_IMAGE 2>/dev/null | tr -d '[]' | cut -d',' -f1 | cut -d':' -f2 | tr -d ' ' || echo "latest");; \
debian9) \
BASE_IMAGE="debian:9"; \
echo "📦 Загрузка базового образа $$BASE_IMAGE..." >&2; \
docker pull $$BASE_IMAGE >/dev/null 2>&1 || echo "⚠️ Не удалось загрузить $$BASE_IMAGE" >&2; \
TAG=$$(docker inspect --format='{{.RepoTags}}' $$BASE_IMAGE 2>/dev/null | tr -d '[]' | cut -d',' -f1 | cut -d':' -f2 | tr -d ' ' || echo "latest");; \
debian10) \
BASE_IMAGE="debian:10"; \
echo "📦 Загрузка базового образа $$BASE_IMAGE..." >&2; \
docker pull $$BASE_IMAGE >/dev/null 2>&1 || echo "⚠️ Не удалось загрузить $$BASE_IMAGE" >&2; \
TAG=$$(docker inspect --format='{{.RepoTags}}' $$BASE_IMAGE 2>/dev/null | tr -d '[]' | cut -d',' -f1 | cut -d':' -f2 | tr -d ' ' || echo "latest");; \
debian11) \
BASE_IMAGE="debian:11"; \
echo "📦 Загрузка базового образа $$BASE_IMAGE..." >&2; \
docker pull $$BASE_IMAGE >/dev/null 2>&1 || echo "⚠️ Не удалось загрузить $$BASE_IMAGE" >&2; \
TAG=$$(docker inspect --format='{{.RepoTags}}' $$BASE_IMAGE 2>/dev/null | tr -d '[]' | cut -d',' -f1 | cut -d':' -f2 | tr -d ' ' || echo "latest");; \
debian12) \
BASE_IMAGE="debian:bookworm"; \
echo "📦 Загрузка базового образа $$BASE_IMAGE..." >&2; \
docker pull $$BASE_IMAGE >/dev/null 2>&1 || echo "⚠️ Не удалось загрузить $$BASE_IMAGE" >&2; \
TAG=$$(docker inspect --format='{{.RepoTags}}' $$BASE_IMAGE 2>/dev/null | tr -d '[]' | cut -d',' -f1 | cut -d':' -f2 | tr -d ' ' || echo "latest");; \
ansible-controller) \
TAG="latest";; \
k8s) \
TAG="latest";; \
k8s-portforward) \
TAG="latest";; \
*) \
echo "❌ Неизвестный образ: $(IMAGE)"; \
exit 1;; \
esac; \
echo "$$TAG"
# Сборка одного образа с multi-arch
docker-build-image:
@if [ -z "$(IMAGE)" ]; then \
echo "❌ Ошибка: IMAGE не указан"; \
exit 1; \
fi; \
TAG=$$($(MAKE) docker-get-base-tag IMAGE=$(IMAGE)); \
if [ "$(IMAGE)" = "redos" ] || [ "$(IMAGE)" = "astra-linux" ]; then \
PLATFORMS="linux/amd64"; \
echo ""; \
echo "=========================================="; \
echo "🔨 СБОРКА ОБРАЗА: $(DOCKER_REGISTRY):$(IMAGE)-$$TAG"; \
echo "📋 Платформы: $$PLATFORMS (только AMD64)"; \
echo "📋 Тег: $$TAG"; \
echo "📋 Registry: $(DOCKER_REGISTRY)"; \
echo "⚠️ ВНИМАНИЕ: Базовый образ поддерживает только AMD64"; \
echo "=========================================="; \
else \
PLATFORMS="$(DOCKER_PLATFORMS)"; \
echo ""; \
echo "=========================================="; \
echo "🔨 СБОРКА ОБРАЗА: $(DOCKER_REGISTRY):$(IMAGE)-$$TAG"; \
echo "📋 Платформы: $$PLATFORMS"; \
echo "📋 Тег: $$TAG"; \
echo "📋 Registry: $(DOCKER_REGISTRY)"; \
echo "=========================================="; \
fi; \
echo ""; \
cd dockerfiles/$(IMAGE) && \
docker buildx build \
--platform $$PLATFORMS \
--tag $(DOCKER_REGISTRY):$(IMAGE)-$$TAG \
--tag $(DOCKER_REGISTRY):$(IMAGE)-latest \
--push \
.; \
echo ""; \
echo "✅ УСПЕШНО: $(DOCKER_REGISTRY):$(IMAGE)-$$TAG собран и отправлен"; \
echo "=========================================="
# =============================================================================
# КОМАНДЫ ДЛЯ РАБОТЫ С ANSIBLE-CONTROLLER
# =============================================================================
controller:
@case "$(word 2, $(MAKECMDGOALS))" in \
build) \
echo "🔨 Сборка ansible-controller (multi-arch)..."; \
echo "📋 Платформы: $(DOCKER_PLATFORMS)"; \
$(MAKE) docker setup-builder; \
cd dockerfiles/ansible-controller && \
docker buildx build \
--platform $(DOCKER_PLATFORMS) \
--tag $(DOCKER_REGISTRY):ansible-controller-$(DOCKER_VERSION) \
--tag $(DOCKER_REGISTRY):ansible-controller-latest \
--push \
.; \
echo "✅ ansible-controller собран и отправлен";; \
rebuild) \
echo "🔄 Пересборка ansible-controller с исправлениями..."; \
echo "📋 Платформы: $(DOCKER_PLATFORMS)"; \
echo "🔧 Исправления: добавлен passlib для хеширования паролей"; \
$(MAKE) docker setup-builder; \
cd dockerfiles/ansible-controller && \
docker buildx build \
--platform $(DOCKER_PLATFORMS) \
--tag $(DOCKER_REGISTRY):ansible-controller-$(DOCKER_VERSION) \
--tag $(DOCKER_REGISTRY):ansible-controller-latest \
--push \
--no-cache \
.; \
echo "✅ ansible-controller пересобран с исправлениями";; \
run) \
echo "🚀 Запуск ansible-controller..."; \
cd dockerfiles/ansible-controller && docker-compose up -d; \
echo "✅ ansible-controller запущен";; \
stop) \
echo "🛑 Остановка ansible-controller..."; \
cd dockerfiles/ansible-controller && docker-compose down; \
echo "✅ ansible-controller остановлен";; \
*) \
echo "🎯 Доступные команды:"; \
echo ""; \
echo " 🔨 make controller build - собрать ansible-controller (multi-arch)"; \
echo " 💡 Собирает: inecs/ansible-lab:ansible-controller-latest"; \
echo " 💡 Платформы: $(DOCKER_PLATFORMS)"; \
echo " 💡 Использует: dockerfiles/ansible-controller/Dockerfile"; \
echo " 💡 Requirements: dockerfiles/ansible-controller/requirements.yml"; \
echo ""; \
echo " 🔄 make controller rebuild - пересобрать ansible-controller с исправлениями"; \
echo " 💡 Пересобирает: с --no-cache для применения исправлений"; \
echo " 💡 Исправления: добавлен passlib для хеширования паролей"; \
echo " 💡 Платформы: $(DOCKER_PLATFORMS)"; \
echo ""; \
echo " 🚀 make controller run - запустить ansible-controller"; \
echo " 💡 Запускает: docker-compose up -d"; \
echo " 💡 Использует: dockerfiles/ansible-controller/docker-compose.yml"; \
echo ""; \
echo " 🛑 make controller stop - остановить ansible-controller"; \
echo " 💡 Останавливает: docker-compose down"; \
echo " 💡 Удаляет: контейнеры и сети";; \
esac
# =============================================================================
# КОМАНДЫ ДЛЯ РАБОТЫ С KUBERNETES KIND
# =============================================================================
k8s:
@case "$(word 2, $(MAKECMDGOALS))" in \
create) \
echo "☸️ Создание Kind кластера..."; \
PRESET_ARG="$(word 3, $(MAKECMDGOALS))"; \
if [ -z "$$PRESET_ARG" ]; then \
PRESET=k8s-minimal; \
echo "📋 Используется preset по умолчанию: $$PRESET (минимальный без аддонов)"; \
else \
PRESET=$$PRESET_ARG; \
echo "📋 Используется preset: $$PRESET"; \
fi; \
if [ ! -f "molecule/presets/k8s/$$PRESET.yml" ]; then \
echo "❌ Ошибка: Пресет '$$PRESET' не найден!"; \
echo "💡 Доступные пресеты:"; \
ls -1 molecule/presets/k8s/*.yml 2>/dev/null | sed 's|molecule/presets/k8s/||g' | sed 's|\.yml||g' | sed 's/^/ - /' || echo " - k8s-minimal"; \
exit 1; \
fi; \
CONTAINER_NAME=k8s-controller; \
docker run -d --name $$CONTAINER_NAME --rm \
-v "$(PWD):/workspace" -w /workspace \
-v /var/run/docker.sock:/var/run/docker.sock \
-u root \
-e ANSIBLE_FORCE_COLOR=1 \
-e MOLECULE_PRESET=$$PRESET \
-e MOLECULE_EPHEMERAL_DIRECTORY=/tmp/molecule_workspace \
$(DOCKER_K8S_IMAGE) \
/bin/bash -c 'sleep infinity'; \
echo "🚀 Запуск создания кластера..."; \
docker exec $$CONTAINER_NAME bash -c "cd /workspace && python3 /workspace/scripts/create_k8s_cluster.py molecule/presets/k8s/$$PRESET.yml $$CONTAINER_NAME"; \
echo "✅ Kind кластер создан"; \
echo "🔌 Автоматическое создание port-forward..."; \
python3 scripts/portforward.py create || echo "⚠️ Не удалось создать port-forward автоматически"; \
echo "📝 Добавление Ingress хостов в /etc/hosts..."; \
sudo python3 scripts/manage_hosts.py add 2>/dev/null || echo "⚠️ Не удалось добавить Ingress хосты (требуется sudo)"; \
echo "💡 Для подключения используйте: make k8s kubeconfig"; \
echo "💡 Для остановки используйте: make k8s stop";; \
destroy) \
echo "🗑️ Удаление Kind кластера и контейнеров..."; \
PRESET_ARG="$(word 3, $(MAKECMDGOALS))"; \
PRESET=$${PRESET_ARG:-k8s-minimal}; \
CONTAINER_NAME=k8s-controller; \
echo "🔌 Очистка port-forward..."; \
python3 scripts/portforward.py clear || echo "⚠️ Не удалось очистить port-forward"; \
echo "📝 Удаление Ingress хостов из /etc/hosts..."; \
sudo python3 scripts/manage_hosts.py remove 2>/dev/null || echo "⚠️ Не удалось удалить Ingress хосты (требуется sudo)"; \
if docker ps | grep -q $$CONTAINER_NAME; then \
echo "🗑️ Удаление Kind кластеров..."; \
docker exec $$CONTAINER_NAME bash -c "kind delete clusters --all" 2>/dev/null || true; \
else \
echo "⚠️ Контейнер $$CONTAINER_NAME не запущен"; \
fi; \
docker rm -f $$CONTAINER_NAME 2>/dev/null || true; \
echo "🗑️ Удаление контейнеров из пресета..."; \
if [ -f "molecule/presets/k8s/$$PRESET.yml" ]; then \
if docker ps | grep -q $$CONTAINER_NAME; then \
docker exec $$CONTAINER_NAME bash -c "python3 /workspace/scripts/delete_hosts.py /workspace/molecule/presets/k8s/$$PRESET.yml" 2>/dev/null || true; \
else \
python3 scripts/delete_hosts.py molecule/presets/k8s/$$PRESET.yml 2>/dev/null || true; \
fi; \
fi; \
echo "✅ Удаление завершено";; \
stop) \
echo "🛑 Остановка Kind кластера..."; \
PRESET_ARG="$(word 3, $(MAKECMDGOALS))"; \
if [ -z "$$PRESET_ARG" ]; then \
echo "❌ Ошибка: Укажите пресет"; \
echo "💡 Пример: make k8s stop kubernetes"; \
exit 1; \
fi; \
CONTAINER_NAME=k8s-controller; \
if docker ps | grep -q $$CONTAINER_NAME; then \
docker exec $$CONTAINER_NAME bash -c "kind get clusters | xargs -I {} kind stop cluster --name {}" 2>/dev/null || true; \
echo "✅ Kind кластер остановлен"; \
else \
echo "⚠️ Контейнер $$CONTAINER_NAME не запущен"; \
fi; \
echo "💡 Кластер остановлен, но не удален"; \
echo "💡 Для перезапуска: make k8s start $$PRESET_ARG"; \
echo "💡 Для полного удаления: make k8s destroy $$PRESET_ARG";; \
start) \
echo "🚀 Запуск Kind кластера..."; \
PRESET_ARG="$(word 3, $(MAKECMDGOALS))"; \
if [ -z "$$PRESET_ARG" ]; then \
echo "❌ Ошибка: Укажите пресет"; \
echo "💡 Пример: make k8s start kubernetes"; \
exit 1; \
fi; \
CONTAINER_NAME=k8s-controller; \
if ! docker ps | grep -q $$CONTAINER_NAME; then \
echo "❌ Контейнер $$CONTAINER_NAME не запущен"; \
echo "💡 Запустите: make k8s create $$PRESET_ARG"; \
exit 1; \
fi; \
docker exec $$CONTAINER_NAME bash -c "kind get clusters | xargs -I {} kind start cluster --name {}" 2>/dev/null || true; \
echo "✅ Kind кластер запущен";; \
status) \
echo "📊 Статус Kind кластеров:"; \
PRESET_ARG="$(word 3, $(MAKECMDGOALS))"; \
if [ -z "$$PRESET_ARG" ]; then \
echo "❌ Ошибка: Укажите пресет"; \
echo "💡 Пример: make k8s status kubernetes"; \
exit 1; \
fi; \
CONTAINER_NAME=k8s-controller; \
if docker ps | grep -q $$CONTAINER_NAME; then \
docker exec $$CONTAINER_NAME bash -c "kind get clusters" 2>/dev/null || echo " Нет кластеров"; \
docker exec $$CONTAINER_NAME bash -c "kind get clusters | while read cluster; do echo \"Кластер: \$$cluster\"; kubectl --context kind-\$$cluster get nodes 2>/dev/null || true; done" 2>/dev/null || true; \
else \
echo "⚠️ Контейнер $$CONTAINER_NAME не запущен"; \
echo "💡 Запустите: make k8s create $$PRESET_ARG"; \
fi;; \
config) \
echo "📋 Получение kubeconfig..."; \
PRESET_ARG="$(word 3, $(MAKECMDGOALS))"; \
if [ -z "$$PRESET_ARG" ]; then \
echo "❌ Ошибка: Укажите пресет"; \
echo "💡 Пример: make k8s config kubernetes"; \
exit 1; \
fi; \
CONTAINER_NAME=k8s-controller; \
if ! docker ps | grep -q $$CONTAINER_NAME; then \
echo "❌ Контейнер $$CONTAINER_NAME не запущен"; \
echo "💡 Запустите: make k8s create $$PRESET_ARG"; \
exit 1; \
fi; \
KUBECONFIG_FILE="$$(pwd)/kubeconfig"; \
docker exec $$CONTAINER_NAME bash -c "kind get kubeconfig" > $$KUBECONFIG_FILE 2>/dev/null || true; \
if [ -f $$KUBECONFIG_FILE ] && [ -s $$KUBECONFIG_FILE ]; then \
echo "✅ kubeconfig сохранен в: $$KUBECONFIG_FILE"; \
echo ""; \
echo "💡 Для использования:"; \
echo " export KUBECONFIG=$$KUBECONFIG_FILE"; \
echo " kubectl get nodes"; \
echo ""; \
echo "💡 Или для однократного использования:"; \
echo " kubectl --kubeconfig=$$KUBECONFIG_FILE get nodes"; \
else \
echo "❌ Не удалось получить kubeconfig"; \
rm -f $$KUBECONFIG_FILE; \
fi;; \
addon) \
echo "📦 Установка аддона..."; \
PRESET_ARG="$(word 3, $(MAKECMDGOALS))"; \
MANIFEST_ARG="$(word 4, $(MAKECMDGOALS))"; \
if [ -z "$$PRESET_ARG" ]; then \
echo "❌ Ошибка: Укажите пресет"; \
echo "💡 Пример: make k8s addon kubernetes https://example.com/manifest.yaml"; \
exit 1; \
fi; \
if [ -z "$$MANIFEST_ARG" ]; then \
echo "❌ Ошибка: Укажите URL манифеста"; \
echo "💡 Пример: make k8s addon kubernetes https://example.com/manifest.yaml"; \
exit 1; \
fi; \
CONTAINER_NAME=k8s-controller; \
if ! docker ps | grep -q $$CONTAINER_NAME; then \
echo "❌ Контейнер $$CONTAINER_NAME не запущен"; \
echo "💡 Запустите: make k8s create $$PRESET_ARG"; \
exit 1; \
fi; \
CLUSTER_NAME=$$(docker exec $$CONTAINER_NAME kind get clusters | head -1); \
echo "📥 Установка аддона из $$MANIFEST_ARG..."; \
docker exec $$CONTAINER_NAME bash -c "CLUSTER_NAME=$$CLUSTER_NAME; kubectl --server=https://\$${CLUSTER_NAME}-control-plane:6443 --insecure-skip-tls-verify apply -f $$MANIFEST_ARG"; \
echo "✅ Аддон установлен"; \
echo "📝 Обновление Ingress хостов..."; \
sudo python3 scripts/manage_hosts.py add 2>/dev/null || echo "⚠️ Не удалось обновить Ingress хосты (требуется sudo)";; \
nodes) \
echo "🖥️ Просмотр узлов кластера..."; \
PRESET_ARG="$(word 3, $(MAKECMDGOALS))"; \
if [ -z "$$PRESET_ARG" ]; then \
echo "❌ Ошибка: Укажите пресет"; \
echo "💡 Пример: make k8s nodes kubernetes"; \
exit 1; \
fi; \
CONTAINER_NAME=k8s-controller; \
if ! docker ps | grep -q $$CONTAINER_NAME; then \
echo "❌ Контейнер $$CONTAINER_NAME не запущен"; \
echo "💡 Запустите: make k8s create $$PRESET_ARG"; \
exit 1; \
fi; \
CLUSTER_NAME=$$(docker exec $$CONTAINER_NAME kind get clusters | head -1); \
docker exec $$CONTAINER_NAME bash -c "CLUSTER_NAME=$$CLUSTER_NAME; kubectl --server=https://\$${CLUSTER_NAME}-control-plane:6443 --insecure-skip-tls-verify get nodes";; \
shell) \
echo "🐚 Открытие shell в контейнере..."; \
PRESET_ARG="$(word 3, $(MAKECMDGOALS))"; \
if [ -z "$$PRESET_ARG" ]; then \
echo "❌ Ошибка: Укажите пресет"; \
echo "💡 Пример: make k8s shell kubernetes"; \
exit 1; \
fi; \
CONTAINER_NAME=k8s-controller; \
if docker ps | grep -q $$CONTAINER_NAME; then \
docker exec -it $$CONTAINER_NAME bash; \
else \
echo "❌ Контейнер $$CONTAINER_NAME не запущен"; \
echo "💡 Запустите: make k8s create $$PRESET_ARG"; \
fi;; \
manifest) \
echo "📄 Работа с манифестами..."; \
MANIFEST_CMD="$(word 3, $(MAKECMDGOALS))"; \
PRESET_ARG="$(word 4, $(MAKECMDGOALS))"; \
MANIFEST_ARG="$(word 5, $(MAKECMDGOALS))"; \
if [ -z "$$MANIFEST_CMD" ] || [ -z "$$PRESET_ARG" ] || [ -z "$$MANIFEST_ARG" ]; then \
echo "❌ Ошибка: Укажите команду, пресет и путь к манифесту"; \
echo "💡 Пример: make k8s manifest apply kubernetes https://example.com/manifest.yaml"; \
exit 1; \
fi; \
CONTAINER_NAME=k8s-controller; \
if ! docker ps | grep -q $$CONTAINER_NAME; then \
echo "❌ Контейнер $$CONTAINER_NAME не запущен"; \
echo "💡 Запустите: make k8s create $$PRESET_ARG"; \
exit 1; \
fi; \
CLUSTER_NAME=$$(docker exec $$CONTAINER_NAME kind get clusters | head -1); \
case "$$MANIFEST_CMD" in \
apply) \
echo "📥 Применение манифеста: $$MANIFEST_ARG"; \
docker exec $$CONTAINER_NAME bash -c "CLUSTER_NAME=$$CLUSTER_NAME; kubectl --server=https://\$${CLUSTER_NAME}-control-plane:6443 --insecure-skip-tls-verify apply -f $$MANIFEST_ARG"; \
echo "📝 Обновление Ingress хостов..."; \
sudo python3 scripts/manage_hosts.py add 2>/dev/null || echo "⚠️ Не удалось обновить Ingress хосты (требуется sudo)";; \
delete) \
echo "🗑️ Удаление ресурсов из манифеста: $$MANIFEST_ARG"; \
docker exec $$CONTAINER_NAME bash -c "CLUSTER_NAME=$$CLUSTER_NAME; kubectl --server=https://\$${CLUSTER_NAME}-control-plane:6443 --insecure-skip-tls-verify delete -f $$MANIFEST_ARG";; \
update) \
echo "🔄 Обновление манифеста: $$MANIFEST_ARG"; \
docker exec $$CONTAINER_NAME bash -c "CLUSTER_NAME=$$CLUSTER_NAME; kubectl --server=https://\$${CLUSTER_NAME}-control-plane:6443 --insecure-skip-tls-verify apply -f $$MANIFEST_ARG --force";; \
*) \
echo "❌ Неизвестная команда: $$MANIFEST_CMD"; \
echo "💡 Доступные команды: apply, delete, update"; \
exit 1;; \
esac;; \
helm) \
echo "📦 Работа с Helm..."; \
HELM_CMD="$(word 3, $(MAKECMDGOALS))"; \
PRESET_ARG="$(word 4, $(MAKECMDGOALS))"; \
RELEASE_ARG="$(word 5, $(MAKECMDGOALS))"; \
CHART_ARG="$(word 6, $(MAKECMDGOALS))"; \
if [ -z "$$HELM_CMD" ] || [ -z "$$PRESET_ARG" ]; then \
echo "❌ Ошибка: Укажите команду и пресет"; \
echo "💡 Пример: make k8s helm list kubernetes"; \
exit 1; \
fi; \
CONTAINER_NAME=k8s-controller; \
if ! docker ps | grep -q $$CONTAINER_NAME; then \
echo "❌ Контейнер $$CONTAINER_NAME не запущен"; \
echo "💡 Запустите: make k8s create $$PRESET_ARG"; \
exit 1; \
fi; \
CLUSTER_NAME=$$(docker exec $$CONTAINER_NAME kind get clusters | head -1); \
case "$$HELM_CMD" in \
apply) \
if [ -z "$$RELEASE_ARG" ] || [ -z "$$CHART_ARG" ]; then \
echo "❌ Ошибка: Укажите имя релиза и чарт"; \
echo "💡 Пример: make k8s helm apply kubernetes my-release stable/nginx-ingress"; \
exit 1; \
fi; \
echo "📦 Установка Helm чарта: $$CHART_ARG как $$RELEASE_ARG"; \
docker exec $$CONTAINER_NAME bash -c "CLUSTER_NAME=$$CLUSTER_NAME; helm upgrade --install $$RELEASE_ARG $$CHART_ARG --kube-apiserver=https://\$${CLUSTER_NAME}-control-plane:6443 --kube-token=dummy --kube-context=dummy 2>&1 | grep -v '^WARNING' || true"; \
echo "📝 Обновление Ingress хостов..."; \
sudo python3 scripts/manage_hosts.py add 2>/dev/null || echo "⚠️ Не удалось обновить Ingress хосты (требуется sudo)";; \
delete) \
if [ -z "$$RELEASE_ARG" ]; then \
echo "❌ Ошибка: Укажите имя релиза"; \
echo "💡 Пример: make k8s helm delete kubernetes my-release"; \
exit 1; \
fi; \
echo "🗑️ Удаление Helm релиза: $$RELEASE_ARG"; \
docker exec $$CONTAINER_NAME bash -c "CLUSTER_NAME=$$CLUSTER_NAME; helm uninstall $$RELEASE_ARG --kube-apiserver=https://\$${CLUSTER_NAME}-control-plane:6443 --kube-token=dummy --kube-context=dummy 2>&1 | grep -v '^WARNING' || true";; \
update) \
if [ -z "$$RELEASE_ARG" ] || [ -z "$$CHART_ARG" ]; then \
echo "❌ Ошибка: Укажите имя релиза и чарт"; \
echo "💡 Пример: make k8s helm update kubernetes my-release stable/nginx-ingress"; \
exit 1; \
fi; \
echo "🔄 Обновление Helm релиза: $$RELEASE_ARG"; \
docker exec $$CONTAINER_NAME bash -c "CLUSTER_NAME=$$CLUSTER_NAME; helm upgrade $$RELEASE_ARG $$CHART_ARG --kube-apiserver=https://\$${CLUSTER_NAME}-control-plane:6443 --kube-token=dummy --kube-context=dummy 2>&1 | grep -v '^WARNING' || true"; \
echo "📝 Обновление Ingress хостов..."; \
sudo python3 scripts/manage_hosts.py add 2>/dev/null || echo "⚠️ Не удалось обновить Ingress хосты (требуется sudo)";; \
rollback) \
if [ -z "$$RELEASE_ARG" ]; then \
echo "❌ Ошибка: Укажите имя релиза"; \
echo "💡 Пример: make k8s helm rollback kubernetes my-release"; \
exit 1; \
fi; \
echo "⏪ Откат Helm релиза: $$RELEASE_ARG"; \
docker exec $$CONTAINER_NAME bash -c "CLUSTER_NAME=$$CLUSTER_NAME; helm rollback $$RELEASE_ARG --kube-apiserver=https://\$${CLUSTER_NAME}-control-plane:6443 --kube-token=dummy --kube-context=dummy 2>&1 | grep -v '^WARNING' || true";; \
list) \
echo "📋 Список Helm релизов:"; \
docker exec $$CONTAINER_NAME bash -c "CLUSTER_NAME=$$CLUSTER_NAME; helm list --kube-apiserver=https://\$${CLUSTER_NAME}-control-plane:6443 --kube-token=dummy --kube-context=dummy --all-namespaces 2>&1 | grep -v '^WARNING' || true";; \
status) \
if [ -z "$$RELEASE_ARG" ]; then \
echo "❌ Ошибка: Укажите имя релиза"; \
echo "💡 Пример: make k8s helm status kubernetes my-release"; \
exit 1; \
fi; \
echo "📊 Статус Helm релиза: $$RELEASE_ARG"; \
docker exec $$CONTAINER_NAME bash -c "CLUSTER_NAME=$$CLUSTER_NAME; helm status $$RELEASE_ARG --kube-apiserver=https://\$${CLUSTER_NAME}-control-plane:6443 --kube-token=dummy --kube-context=dummy 2>&1 | grep -v '^WARNING' || true";; \
*) \
echo "❌ Неизвестная команда: $$HELM_CMD"; \
echo "💡 Доступные команды: apply, delete, update, rollback, list, status"; \
exit 1;; \
esac;; \
helmrepo) \
echo "🏪 Работа с Helm репозиториями..."; \
REPO_CMD="$(word 3, $(MAKECMDGOALS))"; \
PRESET_ARG="$(word 4, $(MAKECMDGOALS))"; \
NAME_ARG="$(word 5, $(MAKECMDGOALS))"; \
URL_ARG="$(word 6, $(MAKECMDGOALS))"; \
if [ -z "$$REPO_CMD" ] || [ -z "$$PRESET_ARG" ]; then \
echo "❌ Ошибка: Укажите команду и пресет"; \
echo "💡 Пример: make k8s helmrepo list kubernetes"; \
exit 1; \
fi; \
CONTAINER_NAME=k8s-controller; \
if ! docker ps | grep -q $$CONTAINER_NAME; then \
echo "❌ Контейнер $$CONTAINER_NAME не запущен"; \
echo "💡 Запустите: make k8s create $$PRESET_ARG"; \
exit 1; \
fi; \
case "$$REPO_CMD" in \
add) \
if [ -z "$$NAME_ARG" ] || [ -z "$$URL_ARG" ]; then \
echo "❌ Ошибка: Укажите имя и URL репозитория"; \
echo "💡 Пример: make k8s helmrepo add kubernetes stable https://charts.helm.sh/stable"; \
exit 1; \
fi; \
echo " Добавление Helm репозитория: $$NAME_ARG"; \
docker exec $$CONTAINER_NAME bash -c "helm repo add $$NAME_ARG $$URL_ARG 2>&1 | grep -v '^WARNING' || true; helm repo update";; \
list) \
echo "📋 Список Helm репозиториев:"; \
docker exec $$CONTAINER_NAME bash -c "helm repo list 2>&1 | grep -v '^WARNING' || true";; \
delete) \
if [ -z "$$NAME_ARG" ]; then \
echo "❌ Ошибка: Укажите имя репозитория"; \
echo "💡 Пример: make k8s helmrepo delete kubernetes stable"; \
exit 1; \
fi; \
echo "🗑️ Удаление Helm репозитория: $$NAME_ARG"; \
docker exec $$CONTAINER_NAME bash -c "helm repo remove $$NAME_ARG 2>&1 | grep -v '^WARNING' || true";; \
update) \
echo "🔄 Обновление Helm репозиториев"; \
docker exec $$CONTAINER_NAME bash -c "helm repo update 2>&1 | grep -v '^WARNING' || true";; \
packages) \
if [ -z "$$NAME_ARG" ]; then \
echo "❌ Ошибка: Укажите имя репозитория"; \
echo "💡 Пример: make k8s helmrepo packages kubernetes stable"; \
exit 1; \
fi; \
echo "📦 Пакеты в репозитории: $$NAME_ARG"; \
docker exec $$CONTAINER_NAME bash -c "helm search repo $$NAME_ARG 2>&1 | grep -v '^WARNING' || true";; \
*) \
echo "❌ Неизвестная команда: $$REPO_CMD"; \
echo "💡 Доступные команды: add, list, delete, update, packages"; \
exit 1;; \
esac;; \
portforward) \
PORTFWD_CMD="$(word 3, $(MAKECMDGOALS))"; \
PORT_ARG="$(word 4, $(MAKECMDGOALS))"; \
if [ -z "$$PORTFWD_CMD" ]; then \
echo "❌ Ошибка: Укажите команду"; \
echo "💡 Пример: make k8s portforward create"; \
exit 1; \
fi; \
case "$$PORTFWD_CMD" in \
create) \
echo "🔌 Создание port-forward..."; \
python3 scripts/portforward.py create;; \
list) \
echo "📋 Список активных port-forward..."; \
python3 scripts/portforward.py list;; \
clear) \
echo "🗑️ Очистка всех port-forward..."; \
python3 scripts/portforward.py clear;; \
recreate) \
echo "🔄 Пересоздание port-forward..."; \
python3 scripts/portforward.py recreate;; \
delete) \
if [ -z "$$PORT_ARG" ]; then \
echo "❌ Ошибка: Укажите порт"; \
echo "💡 Пример: make k8s portforward delete 3000"; \
exit 1; \
fi; \
echo "🗑️ Удаление port-forward на порту $$PORT_ARG..."; \
python3 scripts/portforward.py delete $$PORT_ARG;; \
*) \
echo "❌ Неизвестная команда: $$PORTFWD_CMD"; \
echo "💡 Доступные команды: create, list, clear, recreate, delete"; \
exit 1;; \
esac;; \
*) \
echo "☸️ Доступные команды:"; \
echo ""; \
echo " make k8s create [preset] - создать Kind кластер"; \
echo " 💡 Без параметра: используется k8s-minimal (без аддонов)"; \
echo " 💡 С параметром: используется указанный пресет"; \
echo " 💡 Кластер НЕ удаляется автоматически"; \
echo ""; \
echo " make k8s destroy [preset] - удалить Kind кластер полностью"; \
echo " 💡 Удалит: кластер и контейнер ansible-controller"; \
echo ""; \
echo " make k8s stop [cluster] - остановить Kind кластер (без удаления)"; \
echo " 💡 Можно указать имя кластера или остановить все"; \
echo " 💡 Для перезапуска: make k8s start"; \
echo ""; \
echo " make k8s start [cluster] - запустить остановленный кластер"; \
echo " 💡 Можно указать имя кластера или запустить все"; \
echo ""; \
echo " make k8s status [cluster] - показать статус кластеров"; \
echo " 💡 Можно указать имя конкретного кластера"; \
echo ""; \
echo " make k8s config [cluster] - получить kubeconfig для подключения"; \
echo " 💡 Сохраняет: kubeconfig в корне проекта"; \
echo " 💡 Можно указать имя конкретного кластера"; \
echo ""; \
echo " make k8s addon [preset] [url] - установить аддон из манифеста"; \
echo " 💡 Требует: пресет и URL манифеста"; \
echo " 💡 Пример: make k8s addon kubernetes https://example.com/manifest.yaml"; \
echo ""; \
echo " make k8s nodes [preset] - показать узлы кластера"; \
echo " 💡 Требует: пресет"; \
echo " 💡 Пример: make k8s nodes kubernetes"; \
echo ""; \
echo " make k8s shell [preset] - открыть shell в контейнере"; \
echo " 💡 Для: ручного управления kubectl/kind"; \
echo " 💡 Пример: make k8s shell kubernetes"; \
echo ""; \
echo " make k8s manifest [cmd] [preset] [url] - работа с манифестами"; \
echo " 💡 Команды: apply, delete, update"; \
echo " 💡 Пример: make k8s manifest apply kubernetes https://example.com/deploy.yaml"; \
echo ""; \
echo " make k8s helm [cmd] [preset] [release] [chart] - работа с Helm"; \
echo " 💡 Команды: apply, delete, update, rollback, list, status"; \
echo " 💡 Пример: make k8s helm apply kubernetes nginx stable/nginx-ingress"; \
echo ""; \
echo " make k8s helmrepo [cmd] [preset] [name] [url] - работа с Helm репозиториями"; \
echo " 💡 Команды: add, list, delete, update, packages"; \
echo " 💡 Пример: make k8s helmrepo add kubernetes stable https://charts.helm.sh/stable"; \
echo ""; \
echo " make k8s portforward [cmd] - управление port-forward"; \
echo " 💡 Команды: create, list, clear, recreate, delete [port]"; \
echo " 💡 Пример: make k8s portforward create"; \
echo ""; \
echo "💡 Примеры:"; \
echo " make k8s create # создать минимальный кластер"; \
echo " make k8s create kubernetes # создать кластер с аддонами"; \
echo " make k8s nodes kubernetes # показать узлы кластера"; \
echo " make k8s config kubernetes # получить kubeconfig для кластера"; \
echo " export KUBECONFIG=kubeconfig # использовать конфиг"; \
echo " kubectl get nodes # проверить узлы"; \
echo " make k8s addon kubernetes https://example.com/manifest.yaml # установить аддон"; \
echo " make k8s stop kubernetes # остановить кластер"; \
echo " make k8s start kubernetes # запустить кластер"; \
echo " make k8s destroy kubernetes # удалить кластер с пресетом kubernetes";; \
esac
# =============================================================================
# СПРАВКА
# =============================================================================
help:
@echo "=========================================="
@echo "AnsibleLab - Универсальная система"
@echo "тестирования Ansible ролей"
@echo "=========================================="
@echo ""
@echo "📁 Структура проекта:"
@echo " scripts/ - Скрипты автоматизации"
@echo " inventory/ - Инвентори файлы"
@echo " molecule/default/ - Molecule конфигурация"
@echo " roles/ - Ansible роли"
@echo " vault/ - Зашифрованные секреты"
@echo " dockerfiles/ - Docker образы для тестирования"
@echo ""
@echo "🚀 ОСНОВНЫЕ КОМАНДЫ:"
@echo " make role lint [role] - проверить синтаксис ролей (все или конкретную)"
@echo " 💡 Примеры: make role lint, make role lint devops"
@echo " make role test [preset] - протестировать роли с preset'ом"
@echo " make role deploy - развернуть роли на реальные серверы"
@echo " make role list - показать все роли"
@echo " make role create - создать новую роль (интерактивно)"
@echo " make role delete - удалить роль (интерактивно)"
@echo ""
@echo "📖 ДОКУМЕНТАЦИЯ:"
@echo " docs/deploy-yml-customization.md - полное руководство по кастомизации"
@echo " docs/linting-guide.md - руководство по линтингу ролей"
@echo ""
@echo "🔍 ЛИНТИНГ РОЛЕЙ:"
@echo " make role lint [role] - проверить синтаксис (все или конкретную роль)"
@echo " 💡 Профили: production, basic, min"
@echo " 💡 Конфигурация: .ansible-lint"
@echo " 💡 Валидация: автоматическая проверка существования роли"
@echo ""
@echo "📋 PRESET'Ы (тестовые окружения):"
@echo " make presets list - показать все доступные preset'ы"
@echo " make presets info - подробная информация о preset'е"
@echo " make presets test - запустить тест с preset'ом"
@echo ""
@echo "🖼️ СОБСТВЕННЫЕ ОБРАЗЫ (AnsibleLab):"
@echo " make custom-images test [minimal|full|performance] - тест с собственными образами"
@echo " make custom-images check - проверить наличие собственных образов"
@echo " make custom-images build - собрать все образы для тестирования"
@echo ""
@echo "🐳 DOCKER ОБРАЗЫ (Multi-Arch):"
@echo " make docker prepare - подготовка к работе с Docker Hub"
@echo " make docker build - собрать все Docker образы (amd64 + arm64)"
@echo " make docker build-image IMAGE=<имя> - собрать отдельный образ"
@echo " make docker rebuild - полная пересборка с очисткой кеша"
@echo " make docker push - отправить образы в Docker Hub"
@echo " make docker pull - загрузить образы из Docker Hub"
@echo " make docker clean - удалить локальные образы"
@echo " make docker info - информация о собранных образах"
@echo " make docker update - обновить все образы (pull + build + push)"
@echo " make docker purge - ПОЛНАЯ очистка Docker (ОСТОРОЖНО!)"
@echo ""
@echo "🔧 DOCKER BUILDER (Multi-Arch):"
@echo " make docker setup-builder - настройка multi-arch builder в контейнере"
@echo " make docker clean-builder - очистка multi-arch builder"
@echo " make docker diagnose - диагностика buildx проблем"
@echo " make docker reset-builder - сброс buildx builder"
@echo " 💡 Поддерживает: amd64, arm64, riscv64, ppc64le, s390x, 386, arm/v7, arm/v6"
@echo ""
@echo "🔧 АВТОМАТИЗАЦИЯ:"
@echo " make update-playbooks - обновление playbook'ов при добавлении ролей"
@echo " make generate-docs - генерация документации для ролей"
@echo " make setup-cicd - настройка CI/CD для всех платформ"
@echo " 💡 Безопасно: использует inspect вместо buildx ls (избегает зависаний)"
@echo ""
@echo "🔐 VAULT (управление секретами):"
@echo " make vault init - инициализировать vault (создать vault/.vault)"
@echo " make vault create - создать новый файл секретов"
@echo " make vault edit - редактировать существующие секреты"
@echo " make vault show - показать содержимое секретов"
@echo " make vault delete - удалить файл секретов"
@echo " make vault encrypt - зашифровать файл"
@echo " make vault decrypt - расшифровать файл"
@echo " make vault rekey - сменить пароль шифрования"
@echo " make vault check - проверить vault файлы"
@echo " make vault scan - поиск потенциальных секретов"
@echo ""
@echo "🌿 GIT (управление версиями):"
@echo " make git push - отправить изменения в репозиторий"
@echo " make git pull - получить изменения из репозитория"
@echo " make git new - создать новую ветку"
@echo ""
@echo "🎮 CONTROLLER (ansible-controller Multi-Arch):"
@echo " make controller build - собрать ansible-controller (amd64 + arm64)"
@echo " make controller run - запустить ansible-controller"
@echo " make controller stop - остановить ansible-controller"
@echo ""
@echo "☸️ KUBERNETES (Kind кластеры):"
@echo " make k8s create [preset] - создать Kind кластер (по умолчанию: k8s-minimal)"
@echo " make k8s destroy [preset] - удалить Kind кластер"
@echo " make k8s start [preset] - запустить Kind кластер"
@echo " make k8s stop [preset] - остановить Kind кластер"
@echo " make k8s status [preset] - показать статус кластера"
@echo " make k8s nodes [preset] - показать узлы кластера"
@echo " make k8s config [preset] - получить kubeconfig для подключения"
@echo " make k8s addon [preset] [url] - установить аддон из манифеста"
@echo " make k8s shell [preset] - открыть shell в контейнере k8s"
@echo ""
@echo "💡 ПРИМЕРЫ ИСПОЛЬЗОВАНИЯ:"
@echo " make presets list # показать все preset'ы"
@echo " make presets test PRESET=etcd-patroni # тест с etcd-patroni"
@echo " make role test minimal # быстрый тест"
@echo " make role test all-images # тест всех образов"
@echo " make docker setup-builder # настройка multi-arch builder"
@echo " make docker diagnose # диагностика buildx проблем"
@echo " make docker reset-builder # сброс buildx builder"
@echo " make docker build # собрать все образы (amd64 + arm64)"
@echo " make docker rebuild # полная пересборка с очисткой кеша"
@echo " make controller build # собрать ansible-controller (multi-arch)"
@echo " make docker clean-builder # очистка builder'а"
@echo " make docker purge # полная очистка Docker"
@echo " make vault init # инициализировать vault"
@echo " make vault create # создать секреты"
@echo ""
@echo "📖 Подробная справка: make [команда]"
@echo "=========================================="
# =============================================================================
# КОМАНДЫ ДЛЯ РАБОТЫ С СОБСТВЕННЫМИ ОБРАЗАМИ
# =============================================================================
custom-images:
@case "$(word 2, $(MAKECMDGOALS))" in \
test) \
echo "🧪 Тестирование с собственными образами AnsibleLab..."; \
if [ -z "$(word 3, $(MAKECMDGOALS))" ]; then \
echo "💡 Использование: make custom-images test [minimal|full|performance]"; \
echo "💡 По умолчанию: minimal"; \
./scripts/test-custom-images.sh minimal; \
else \
./scripts/test-custom-images.sh $(word 3, $(MAKECMDGOALS)); \
fi;; \
check) \
echo "🔍 Проверка наличия собственных образов..."; \
./scripts/test-custom-images.sh check;; \
build) \
echo "🔨 Сборка всех образов для тестирования..."; \
$(MAKE) docker build;; \
*) \
echo "🎯 Доступные команды:"; \
echo ""; \
echo " 🧪 make custom-images test [minimal|full|performance] - тест с собственными образами"; \
echo " 💡 minimal - минимальный тест (4 хоста)"; \
echo " 💡 full - полный тест (все образы)"; \
echo " 💡 performance - тест производительности (8 хостов)"; \
echo ""; \
echo " 🔍 make custom-images check - проверить наличие собственных образов"; \
echo " 💡 Показывает: какие образы есть, какие отсутствуют"; \
echo " 💡 Предлагает: команды для сборки отсутствующих образов"; \
echo ""; \
echo " 🔨 make custom-images build - собрать все образы для тестирования"; \
echo " 💡 Выполняет: make docker build"; \
echo " 💡 Собирает: все образы AnsibleLab"; \
echo ""; \
echo "💡 Пресеты для тестирования:"; \
echo " - custom-minimal.yml - минимальный тест (4 хоста)"; \
echo " - custom-images.yml - полный тест (все образы)"; \
echo " - custom-performance.yml - тест производительности (8 хостов)"; \
echo ""; \
echo "💡 Собственные образы:"; \
echo " - inecs/ansible-lab:ansible-controller-latest"; \
echo " - inecs/ansible-lab:alt-linux-latest"; \
echo " - inecs/ansible-lab:astra-linux-latest"; \
echo " - inecs/ansible-lab:redos-latest"; \
echo " - inecs/ansible-lab:rhel-latest"; \
echo " - inecs/ansible-lab:centos-latest"; \
echo " - inecs/ansible-lab:alma-latest"; \
echo " - inecs/ansible-lab:rocky-latest"; \
echo " - inecs/ansible-lab:ubuntu-latest"; \
echo " - inecs/ansible-lab:debian-latest";; \
esac
# =============================================================================
# АВТОМАТИЗАЦИЯ
# =============================================================================
update-playbooks:
@echo "🔄 Обновление playbook'ов..."
@chmod +x scripts/update-playbooks.sh
@./scripts/update-playbooks.sh
generate-docs:
@echo "📚 Генерация документации..."
@chmod +x scripts/generate-role-docs.sh
@./scripts/generate-role-docs.sh
setup-cicd:
@echo "🔧 Настройка CI/CD..."
@chmod +x scripts/setup-cicd.sh
@./scripts/setup-cicd.sh
# Очистка контейнеров Molecule
.PHONY: clean-containers
clean-containers:
@echo "🧹 Очистка контейнеров Molecule..."
@echo "📋 Поиск контейнеров проекта..."
@docker ps -a --filter "ancestor=inecs/ansible-lab" --format "table {{.Names}}\t{{.Status}}\t{{.Image}}" || true
@echo ""
@echo "🗑️ Удаление контейнеров..."
@docker ps -a --filter "ancestor=inecs/ansible-lab" --format "{{.ID}}" | xargs -r docker rm -f 2>/dev/null || true
@docker ps -a --filter "network=labnet" --format "{{.ID}}" | xargs -r docker rm -f 2>/dev/null || true
@echo "🧹 Очистка сетей..."
@docker network rm labnet 2>/dev/null || true
@echo "✅ Очистка завершена"
# Пустые цели для совместимости
view create edit show delete lint deploy new advanced list info test build push pull clean prepare update run stop purge clean-builder setup-builder diagnose reset-builder build-image:
@true
# Универсальный таргет для всех пресетов и других динамических целей
%:
@: