Модуль 03 — Программирование для DevOps
DevOps без скриптинга — это «клик-инженер». Senior DevOps пишет кода больше, чем некоторые разработчики. Эта дисциплина — инвестиция, которая окупается каждый день.
Стек для DevOps
| Язык | Уровень | Применение |
|---|---|---|
| Bash | Свободно | Скрипты автоматизации, CI/CD jobs, healthcheck'и |
| Python | Уверенно | Сложная автоматизация, AWS Lambda, REST API скрипты, тесты |
| Go | Чтение | K8s операторы, контрибуции в Terraform/etcd, CLI-утилиты |
| YAML | Свободно | K8s, Ansible, GitHub Actions, Docker Compose |
| HCL | Свободно | Terraform, Vault, Consul |
| JSON | Свободно | API, IAM-политики, CloudFormation |
| Jinja2 | Уверенно | Ansible templates, Helm-аналоги |
| SQL | Базово | Запросы, EXPLAIN, бекапы |
Bash — must-have ⭐
Скелет «защищённого» скрипта
#!/usr/bin/env bash
set -euo pipefail # строгий режим: stop on error, undefined var, pipe fail
IFS=$'\n\t' # безопасный разделитель
readonly SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
readonly LOG_FILE="/tmp/$(basename "$0").log"
trap 'echo "Error on line $LINENO" >&2' ERR
trap 'rm -f "$tmpfile"' EXIT # cleanup при выходе
usage() {
cat <<EOF
Usage: $0 [-h] -e ENV -r REGION
-e environment (dev|staging|prod)
-r AWS region
EOF
exit 1
}
main() {
local env="${1:?Usage: $0 ENV}"
local region="${2:-eu-west-1}"
if [[ ! "$env" =~ ^(dev|staging|prod)$ ]]; then
echo "Invalid env: $env" >&2
return 1
fi
echo "Deploying to $env in $region..."
}
main "$@"
Bash idioms
# Параметр expansion
${var:-default} # default если пусто
${var:?error} # exit с ошибкой если пусто
${var/find/replace}# замена
${#var} # длина
${var^^} # UPPERCASE
# Условия
[[ -f file ]] # файл существует
[[ -d dir ]] # директория
[[ -z "$var" ]] # пустое
[[ "$a" == "$b" ]] # равенство
[[ "$str" =~ ^prod ]] # regex
(( x > 5 )) # арифметика
# Циклы
for f in *.log; do echo "$f"; done
while IFS= read -r line; do
echo "$line"
done < file.txt
# Process substitution
diff <(cmd1) <(cmd2)
# Heredoc
cat <<EOF > config.yaml
key: $value
EOF
Линтер обязателен: shellcheck script.sh. Проверь свой скрипт перед коммитом.
Bash: до 50 строк, простая последовательность shell-команд, glue-код в CI.
Python: парсинг сложного, REST API, JSON/YAML, что-то с тестами, что-то на 100+ строк.
Python — обязательно
Что освоить
- Синтаксис, типы, операторы, dict/list/set, comprehensions
- Функции, *args, **kwargs, decorators (на уровне понимания)
- Классы, dataclasses
pathlibвместоos.pathjson,yaml(PyYAML),tomlrequestsилиhttpx— HTTP клиентargparseдля CLI; для красивого CLI —click/typersubprocess.runдля shell-командloggingвместо printvenv/uv(новый быстрый менеджер)pytestдля тестов- Type hints (PEP 484),
mypy - Линтеры: ruff (быстрый, заменил black+isort+flake8)
Типичный DevOps-скрипт
#!/usr/bin/env python3
"""Деплой Lambda через AWS API."""
from __future__ import annotations
import argparse
import logging
import sys
from pathlib import Path
import boto3
from botocore.exceptions import ClientError
logging.basicConfig(level=logging.INFO, format="%(asctime)s %(levelname)s %(message)s")
log = logging.getLogger(__name__)
def deploy(name: str, zip_path: Path, role_arn: str) -> None:
client = boto3.client("lambda")
log.info("Deploying %s from %s", name, zip_path)
try:
client.update_function_code(FunctionName=name, ZipFile=zip_path.read_bytes())
except ClientError as e:
log.error("AWS error: %s", e)
sys.exit(1)
def main() -> None:
p = argparse.ArgumentParser()
p.add_argument("--name", required=True)
p.add_argument("--zip", type=Path, required=True)
p.add_argument("--role", required=True)
args = p.parse_args()
deploy(args.name, args.zip, args.role)
if __name__ == "__main__":
main()
DevOps-библиотеки Python
- boto3 — AWS SDK
- kubernetes — клиент K8s API
- paramiko, fabric — SSH-автоматизация
- pydantic — валидация данных, типизация
- requests / httpx — HTTP
- typer / click — современный CLI
- rich — красивый вывод в терминале
- prefect, airflow — workflow оркестрация
Go — для роста к Senior
Go — язык DevOps-инструментов: Docker, Kubernetes, Terraform, Prometheus, etcd, Consul, Vault — всё на Go. Знание Go = можешь читать сорцы и контрибьютить.
Учить когда: после уверенного Python и Bash, ближе к Senior уровню.
Минимум: уметь читать чужой Go-код. Понимать goroutines, channels, structs, interfaces. Уметь собрать проект через go build.
// Минимальный пример
package main
import (
"fmt"
"os"
)
func main() {
if len(os.Args) < 2 {
fmt.Fprintln(os.Stderr, "usage: app NAME")
os.Exit(1)
}
fmt.Printf("Hello, %s!\n", os.Args[1])
}
Регулярные выражения
Без regex ты не парсер логов. Используй regex101.com для отладки — это must.
| Паттерн | Значение |
|---|---|
. | любой символ (кроме \n) |
\d \w \s | цифра / слово / whitespace |
+ * ? | 1+, 0+, 0 или 1 |
{n,m} | от n до m повторений |
^ $ | начало / конец строки |
(...) | группа |
(?:...) | не-захватывающая группа |
(?=...) | positive lookahead |
.*? | ленивый (не жадный) квантификатор ⭐ |
Чек-лист
- ☐ Пишу bash-скрипты с
set -euo pipefailи trap - ☐
shellcheck— обязательная часть workflow - ☐ Понимаю Python venv, не путаю pip и pip3
- ☐ Могу написать Python CLI с argparse и логированием
- ☐ Знаю когда брать Bash, а когда Python
- ☐ Могу прочитать Go-код, объяснить что делает
- ☐ Не боюсь YAML с anchors и multi-document
- ☐ Использую regex101.com для отладки regex
Лучшие источники
- Bash: «Pro Bash Programming» — Chris F.A. Johnson; Google Shell Style Guide
- Python: «Automate the Boring Stuff» — Al Sweigart (бесплатно онлайн), потом «Fluent Python» — Luciano Ramalho
- Go: Go by Example; A Tour of Go
- Regex: regex101.com
- Линтеры: shellcheck.net (онлайн)
Программирование освоено. Теперь — Git и GitHub.