Смотрю, я собираюсь сказать нечто, что может привести к тому, что меня запретят посещать вечеринки DevOps: не каждая задача по автоматизации заслуживает модного конвейера CI/CD. Я знаю, я знаю — это звучит кощунственно в 2026 году. Нас приучили верить, что больше, сложнее, более «корпоративно» — всегда лучше. Но что, если я скажу вам, что иногда хорошо написанный скрипт Bash, тихо сидящий в вашем репозитории, может быть именно тем, что нужно вашей команде?
Прежде чем вы отмахнётесь от этого, считая это бреднями человека, который только вчера открыл для себя shell-скрипты, выслушайте меня. Я не выступаю за отказ от вашей инфраструктуры CI/CD. Скорее, я отстаиваю идею признания того, что скрипты Bash могут быть подходящим инструментом для работы — не заменой конвейеров, а дополнением, которое может сохранить ваше здравомыслие.
Неудобная правда о переоптимизации
Давайте представим ситуацию. У вас небольшая команда, достаточно стабильное приложение и набор задач по развёртыванию, которые нужно выполнять время от времени. Кто-то предлагает: «Эй, мы должны автоматизировать это!» Внезапно, три недели спустя, у вас есть сервер Jenkins с тремя заданиями, конфигурация GitLab CI на 200 строк и бегун на базе Kubernetes, который стоит больше, чем ваш бюджет на кофе. Тем временем фактический скрипт автоматизации? Это 47 строк Bash, и никто в вашей команде не может вспомнить, почему Jenkins нужен доступ к четырём разным провайдерам учётных данных.
Вот где Bash выигрывает. Он побеждает не потому, что является передовым — это абсолютно не так, — а потому, что он предсказуем, портативен и требует минимальных когнитивных усилий.
Когда Bash сияет ярче всего
Вот в чём дело с Bash: он не пытается быть всем. Он не пытается стать платформой для оркестрации DevOps полного цикла. Он не пытается быть облачным, с поддержкой AI или синергетическим. Он просто… работает.
Bash отлично подходит для коротких, компонуемых рабочих процессов. Думайте об этом как о клейкой ленте для DevOps — не всегда красивой, но выполняющей работу, когда она вам нужна быстро. Где это наиболее важно?
Лёгкая автоматизация и логика склейки
Ваша система CI/CD оркеструет шаги, но кому-то всё равно нужно фактически выполнить работу. Bash — это тот, кто выполняет эту работу. Он объединяет инструменты командной строки, анализирует выходные данные, проверяет конфигурации и выполняет неприглядные, но важные задачи, такие как установка зависимостей, запуск сборок, упаковка выходных данных и загрузка артефактов.
Рассмотрим такой сценарий: вам нужен скрипт, который проверяет конфигурации Terraform перед их применением. Скрипт должен проверять входные данные, убедиться, что настроен правильный бэкенд, и запускать terraform plan с проверками политик. Вы можете создать для этого целую конфигурацию рабочего пространства Terraform Cloud или написать это:
#!/bin/bash
set -euo pipefail
ENVIRONMENT="${1:-staging}"
TF_DIR="./infrastructure"
# Проверка среды
if [[ ! "$ENVIRONMENT" =~ ^(staging|production)$ ]]; then
echo "Ошибка: среда должна быть 'staging' или 'production'"
exit 1
fi
# Убедиться, что настроена правильная конфигурация бэкенда
if ! grep -q "backend \"s3\"" "$TF_DIR/main.tf"; then
echo "Ошибка: S3 бэкенд не настроен"
exit 1
fi
# Инициализация Terraform
cd "$TF_DIR"
terraform init -backend-config="key=terraform-${ENVIRONMENT}.tfstate"
# Запуск плана с проверками политик
terraform plan -out="tfplan-${ENVIRONMENT}"
echo "✓ План Terraform проверен успешно"
Это 22 строки простого кода. Никаких акробатических упражнений с YAML. Никаких ожиданий выделения ресурсов. Он запускается на любой Unix-подобной системе немедленно.
Пользовательское нагрузочное тестирование и проверка производительности
Здесь всё становится действительно интересным. Если вы когда-либо пытались интегрировать инструмент нагрузочного тестирования в свой конвейер, вы знаете боль: затраты на лицензирование, сложная настройка, накладные расходы на память и радость отладки чуждого вам чёрного ящика.
Один из подходов? Напишите собственный скрипт Bash, который использует Apache Benchmark. В Etsy инженеры хорошо понимали это и создавали свои собственные скрипты Bash для нагрузочного тестирования, интегрируя их без проблем в свои конвейеры CI/CD. Это как создание собственного доспеха, идеально подходящего к потребностям вашего приложения.
Вот практический пример:
#!/bin/bash
set -euo pipefail
# Проверка входных данных
if [[ $# -lt 3 ]]; then
echo "Использование: $0 <url> <параллельность> <продолжительность>"
exit 1
fi
TARGET_URL="$1"
CONCURRENCY="$2"
DURATION="$3"
LOG_FILE="load_test_$(date +%s).json"
RAW_LOG="${LOG_FILE%.json}_raw.txt"
# Запуск нагрузочного теста с Apache Benchmark
echo "Запуск нагрузочного теста: $TARGET_URL с $CONCURRENCY параллельных запросов в течение ${DURATION} секунд"
ab -c "$CONCURRENCY" -t "$DURATION" -g "$RAW_LOG" "$TARGET_URL" > /dev/null 2>&1 || true
# Анализ результатов
local total_requests=$(grep "Complete requests:" "$RAW_LOG" | awk '{print $3}')
local failed_requests=$(grep "Failed requests:" "$RAW_LOG" | awk '{print $3}' | grep -oE '[0-9]+' || echo 0)
local mean_time=$(grep "Mean:" "$RAW_LOG" | awk '{print $4}')
local max_time=$(grep "Max:" "$RAW_LOG" | awk '{print $4}')
# Генерация вывода в формате JSON
cat > "$LOG_FILE" <<EOF
{
"timestamp": "$(date -u +%Y-%m-%dT%H:%M:%SZ)",
"url": "$TARGET_URL",
"configuration": {
"concurrent_requests": $CONCURRENCY,
"duration": $DURATION
},
"results": {
"total_requests": $total_requests,
"failed_requests": $failed_requests,
"success_rate": $(echo "scale=2; ($total_requests-$failed_requests)/$total_requests*100" | bc),
"mean_response_time": $mean_time,
"max_response_time": $max_time
}
}
EOF
echo "Результаты сохранены в $LOG_FILE"
cat "$LOG_FILE"
Почему этот подход выигрывает:
- Настраиваемость: адаптируйте скрипт к конкретным требованиям, таким как журналирование, продолжительность теста или уникальные заголовки.
- Эффективность: выполняется на любой Unix-подобной системе без дополнительного программного обеспечения или библиотек.
- Интеграция: легко интегрируется с существующими конвейерами, позволяя автоматизированное тестирование производительности.
Никаких модных пользовательских интерфейсов. Никаких абонентских плат. Просто метрики в формате JSON, которые вы можете направить прямо в свою систему мониторинга.
Аргумент переносимости, который никогда не устареет
Вот что меня беспокоит: хрупкость инфраструктуры CI/CD. У вас есть Jenkins, работающий на одном компьютере, GitLab CI в облаке и Travis CI для какого-то устаревшего проекта. У каждого свой диалект YAML, своё управление секретами, свои особенности.
Bash? Bash работает на Linux, macOS и большинстве облачных контейнеров «из коробки». Используйте POSIX sh, когда скрипт должен работать в различных средах (Alpine, минимальные контейнеры, случайные бегуны CI). Используйте Bash, когда вы контролируете среду выполнения.
Это означает, что ваш скрипт не привязан к определённому поставщику CI/CD. Вы можете выполнить его локально для тестирования, на компьютере разработчика, в контейнере или в любом конвейере, который вы сейчас используете. Сам скрипт остаётся независимым от среды выполнения.
Практический пошаговый подход: создание надёжной системы автоматизации на основе Bash
Позвольте мне показать вам, как создать производственную систему автоматизации на основе Bash, которая не будет вызывать у вашей команды отвращения во время обзоров кода.
Шаг 1: Установите согласованную структуру
Создайте каталог /ci в вашем репозитории для хранения всех скриптов автоматизации:
.
├── ci/
│ ├── lib/
│ │ ├── common.sh # Общие утилиты
│ │ └── validation.sh # Проверка входных данных
│ ├── deploy.sh # Сценарий развёртывания
│ ├── validate.sh # Сценарий проверки
│ └── test-load.sh # Сценарий нагрузочного тестирования
├── src/
└── README.md
Шаг 2: Создайте общие утилиты
Создайте библиотеку повторно используемых функций в ci/lib/common.sh:
#!/bin/bash
set -euo pipefail
# Цветной вывод для удобочитаемости
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # Нет цвета
log
