DevOps / SRE — шпаргалка к собеседованию
Быстрая навигация по темам с тезисами, командами и типовыми вопросами. Плотный формат: достаточно, чтобы освежить, а не чтобы выучить с нуля.
1. Linux (уровень администратора)
Загрузка системы
Последовательность: BIOS/UEFI → загрузчик (GRUB2 / systemd-boot) → ядро + initramfs → PID 1 (systemd) → target. UEFI работает с ESP (FAT32, /boot/efi), видит файлы напрямую; BIOS — через MBR/stage1. initramfs нужен, чтобы смонтировать корень, если на нём LVM/LUKS/NFS/RAID.
systemd: юниты лежат в /lib/systemd/system/ (ванильные) и /etc/systemd/system/ (админские overrides). Таргеты заменяют runlevels: multi-user.target ≈ rl3, graphical.target ≈ rl5. Текущий: systemctl get-default.
systemctl list-units --failed
systemctl cat myapp.service # весь собранный unit-файл
systemctl edit myapp.service # drop-in override (в /etc/...d/override.conf)
journalctl -u myapp -f --since "15 min ago"
journalctl -p err -b # только errors в текущем boot
Процессы и сигналы
- fork/exec: fork() клонирует процесс, exec() заменяет адресное пространство образом бинаря. В контейнерах важно, что PID 1 должен обрабатывать SIGTERM и жать ребёнкам (zombie reaping). Для shell-скриптов используют
tini/dumb-init. - Сигналы:
SIGTERM— вежливый (можно обработать, задать timeout),SIGKILL— ядро убивает немедленно (нельзя поймать),SIGHUP— обычно «перечитать конфиг» (nginx, haproxy),SIGINT≈ Ctrl+C,SIGSTOP/SIGCONT— заморозка. - Zombie — дочерний процесс завершился, но родитель не сделал
wait()— в PID-таблице остаётся запись; не ест CPU, но ест PID. Orphan — родитель умер, ребёнка усыновляет PID 1. В docker/k8s если контейнер как PID 1 не reap'ит — получаем zombies внутри pod.
ps -eo pid,ppid,stat,cmd # stat=Z → зомби, stat=D → uninterruptible sleep (обычно IO)
kill -l # список сигналов
pgrep -a nginx; pkill -HUP nginx
timeout 30 long-job # хорошая практика в cron/CI
Права и изоляция
| Механизм | Для чего | Как посмотреть |
|---|---|---|
| rwx / mode | Базовые права user/group/other | ls -l, stat |
| SUID (s вместо x на user) | Исполнять с правами владельца (напр. passwd, sudo) | find / -perm -4000 2>/dev/null |
| SGID | На файле — запускать с группой; на папке — новые файлы наследуют группу | -perm -2000 |
| sticky bit (t на other) | /tmp — удалять может только владелец | -perm -1000 |
| ACL | Тонкие права на пользователя помимо 3+3+3 | getfacl, setfacl -m u:deploy:rwx path |
| capabilities | Разбить root на гранулы (CAP_NET_BIND_SERVICE, CAP_SYS_ADMIN и т.д.) | getcap, setcap cap_net_bind_service+ep /usr/bin/node |
| umask | Маска вычитается из 0666/0777 при создании файла/каталога | umask (часто 022 → 644/755) |
Файловые системы и диск
- ext4 — дефолт в большинстве Debian/Ubuntu, журналируемая, шустрая, простая. XFS — лучше на больших объёмах и параллельных записях, не умеет shrink. btrfs/ZFS — CoW, снапшоты, но сложнее.
- inode — запись о файле (метаданные, блоки), имя лежит в каталоге как
{name → inode}. Переполнение inode → «No space left on device» при свободных блоках. Смотриdf -i. - LVM: PV → VG → LV. Снапшоты, resize на лету, thin-provisioning.
pvs/vgs/lvs,lvextend -L+10G -r /dev/vg0/data(-r ресайзит ФС сразу). - /etc/fstab: UUID → точка монтирования → тип → опции (
noatime,nofail— не вешать загрузку,x-systemd.automount). - Swap — файл или partition, включать через
swapon.vm.swappinessрегулирует «охоту» ядра свопить. На БД-хостах часто swappiness=1.
df -hT # размер + тип ФС
df -i # inode usage
du -xsh /var/* | sort -h
ncdu /var # интерактивно «что съело место»
iostat -xz 1 # %util, await, wKB/s — подсветит медленный диск
lsblk -f # дерево блочных устройств с UUID/ФС
LVM — подробно
LVM — слой между блочными устройствами и файловой системой. Позволяет объединять диски, ресайзить «на лету», делать снапшоты, thin-provisioning, миграцию данных между устройствами без downtime.
Иерархия
| Уровень | Что это | Команды |
|---|---|---|
| PV (Physical Volume) | Подготовленное блочное устройство: диск целиком (/dev/sdb) или партиция (/dev/sdb1 с типом 8e/lvm). На него кладётся LVM-метадата | pvcreate /dev/sdb, pvs, pvdisplay, pvscan |
| VG (Volume Group) | «Пул» ёмкости из одного или нескольких PV. Единица аллокации — PE (Physical Extent), обычно 4 MiB | vgcreate vg0 /dev/sdb, vgs, vgdisplay, vgextend vg0 /dev/sdc |
| LV (Logical Volume) | «Виртуальная партиция» внутри VG. На неё кладётся ФС (ext4/xfs), и она монтируется | lvcreate -L 50G -n var vg0, lvs, lvdisplay, lvextend, lvreduce |
pvs # PV VG Fmt Attr PSize PFree
vgs # VG #PV #LV Attr VSize VFree
lvs # LV VG Attr LSize ...
lsblk # дерево видно с именами LV (/dev/mapper/vg0-var)
Снапшоты и thin pool
- Thick snapshot:
lvcreate -s -L 10G -n snap /dev/vg0/var— CoW копия. Размер снапшота должен вмещать дельту изменений; переполнится — снапшот станет invalid. - Thin provisioning: из thin pool выделяются тонкие LV — заявленный размер больше физического. Быстрые снапшоты «бесплатно». Риск: переполнение пула = все thin-LV встанут read-only. Обязателен мониторинг
Data%вlvs -a. - Striping / mirroring:
lvcreate --stripes N(RAID0-подобный, быстрее),lvconvert --type raid1.
Подводные камни
- ext4 умеет и online grow, и offline shrink. XFS — только grow, shrink невозможен; если надо уменьшить — backup + mkfs + restore.
- После
lvextendФС сама не растёт — нуженresize2fs/xfs_growfs. Флаг-rуlvextendделает это автоматически (знает, какой ФС имеем). - Корень в LVM — нужен
lvm2в initramfs (обычно уже есть). После ресайза корня всё делается на живую, без перезагрузки. - SSD: включить
issue_discards=1в/etc/lvm/lvm.conf, чтобы приlvremove/lvreduceшёл TRIM. - Боевой риск с thin pool: забыли настроить алерты → пул заполнился → все БД разом встали. Включить
thin_pool_autoextend_threshold+thin_pool_autoextend_percent.
Кейс: «/var забит логами, сервер при смерти»
Фаза 1. Остановить кровотечение (0 ресурсов, критично)
# Смотрим общую картину
df -h
df -i # и inodes — на мелких файлах inodes закончатся раньше байтов!
# Что именно съело — не уходим в /proc, /sys, бинды
sudo du -xh --max-depth=1 /var 2>/dev/null | sort -h | tail
# Популярные виновники:
# /var/log (journal, nginx access, приложенческий stdout)
# /var/lib/docker (слои, volumes, overlay2/diff)
# /var/lib/containerd
# /var/cache/apt
# /var/lib/mysql, /var/lib/postgresql
# /var/spool (mail, cron, cups)
# journalctl: проверить текущее использование и срезать
journalctl --disk-usage
sudo journalctl --vacuum-size=500M
sudo journalctl --vacuum-time=7d
# «классика»: большой файл открыт удалённым процессом — df видит полный диск,
# но du этого файла не показывает (inode освободится только после закрытия)
sudo lsof +L1 | head # DEL/LINK=0 — файлы «удалены», но держатся fd
# фикс: рестарт соответствующего сервиса (иногда это единственный путь)
# docker — не чистить «руками» /var/lib/docker, использовать prune
sudo docker system df
sudo docker system prune -af --volumes
# rotate и сжатие старых логов nginx/app
sudo logrotate -f /etc/logrotate.conf
systemd-journald, rsyslogd, часто и sshd начинают сбоить. Не перезагружай до того как освободил ≥ 1-2% — можно не вернуться. Сначала vacuum-size, truncate -s 0 больших активных логов через тот же процесс (не rm!), потом разбираться.Фаза 2. Расширить /var через LVM (основной сценарий)
Допустим, /var — это LV /dev/vg0/var на ext4, и мы хотим добавить 50 GB.
Предполётная проверка — какой у нас сценарий:
df -h /var # точка монтирования → какое устройство
findmnt /var # TARGET SOURCE FSTYPE OPTIONS
mount | grep ' /var '
lsblk -f # дерево, тип ФС каждого LV
sudo vgs # есть ли свободное место в VG (VFree)?
sudo lvs vg0/var # текущий размер LV
Вариант A — в VG уже есть свободное место (VFree > 50G). Это самый частый кейс, если при инсталляции «оставили запас».
# ext4 — online grow; -r resize2fs делается автоматически
sudo lvextend -L +50G -r /dev/vg0/var
# или «съесть всё свободное место»
sudo lvextend -l +100%FREE -r /dev/vg0/var
# XFS — тоже online
sudo lvextend -L +50G /dev/vg0/var
sudo xfs_growfs /var
df -h /var # убеждаемся — размер вырос, данные на месте
Сеть
ip a; ip r; ip -s link show eth0
ss -tulpn # слушающие сокеты с PID
ss -ti '( dport = :443 )'
ethtool eth0 # speed/duplex, ring buffer
ethtool -S eth0 | grep -i err
# Маршрутизация
ip route add 10.0.0.0/24 via 192.168.1.1 dev eth0
ip route get 8.8.8.8
# VLAN / bridge / bonding
ip link add link eth0 name eth0.10 type vlan id 10
ip link add br0 type bridge
ip link add bond0 type bond mode=active-backup
MTU: по умолчанию 1500; в VPN/overlay часто 1400 (иначе фрагментация и «странные» таймауты). Проверить: ping -M do -s 1472 host (1472+28=1500).
NetworkManager vs systemd-networkd: NM — десктоп/ноутбуки, много GUI; networkd — сервера, декларативные .network файлы, легковесный.
Firewall
Стек: netfilter в ядре, iptables (legacy) / nftables (современный синтаксис). Большинство дистрибутивов перешли на nftables, но iptables остаётся как wrapper. conntrack отслеживает состояния (NEW/ESTABLISHED/RELATED) — именно это позволяет firewall-у корректно работать с ответными пакетами.
# nftables
nft list ruleset
nft add rule inet filter input tcp dport 22 accept
# iptables
iptables -L -n -v --line-numbers
iptables -I INPUT -p tcp --dport 80 -j ACCEPT
# SNAT / DNAT
iptables -t nat -A POSTROUTING -s 10.0.0.0/24 -o eth0 -j MASQUERADE
# conntrack
cat /proc/net/nf_conntrack | wc -l
sysctl net.nf_conntrack_max
nf_conntrack: table full, dropping packet. Увеличить nf_conntrack_max и hashsize, либо уменьшить таймауты (nf_conntrack_tcp_timeout_established).Инструменты траблшутинга (must-know)
| Симптом | Команды в первую очередь |
|---|---|
| Всё медленно | top/htop, uptime, vmstat 1, iostat -xz 1, pidstat 1 |
| Load avg высокий | Смотреть %wa (IO-wait) в top; dstat -tam; iotop; проверить swap-in/out |
| «Какой-то процесс жрёт диск» | iotop -oPa, pidstat -d 1, lsof +D /var |
| Процесс висит | strace -f -p PID, strace -e openat,connect -p PID, ltrace, gdb -p PID |
| Что слушает порт / какой процесс | ss -tulpn, lsof -i :443, fuser -n tcp 80 |
| Сетевые проблемы | tcpdump -ni eth0 host X and port 80 -w /tmp/a.pcap, mtr host, traceroute, dig +trace, curl -vk |
| Ядро / perf | perf top, perf record -p PID -g, bpftrace -e '...' |
| Память | free -h, /proc/meminfo, slabtop, smem -k |
| OOM kills | dmesg | grep -i oom, journalctl -k --grep oom |
systemd — свой сервис
# /etc/systemd/system/myapp.service
[Unit]
Description=My App
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=myapp
WorkingDirectory=/opt/myapp
EnvironmentFile=/etc/myapp.env
ExecStart=/opt/myapp/bin/server
Restart=on-failure
RestartSec=5
# Хардening:
ProtectSystem=strict
ProtectHome=true
PrivateTmp=true
NoNewPrivileges=true
LimitNOFILE=65536
[Install]
WantedBy=multi-user.target
systemctl daemon-reload && systemctl enable --now myapp
Таймеры vs cron: systemd-таймеры лучше интегрированы (persistent, OnBootSec, RandomizedDelaySec, логи в journald, можно зависеть от других unit-ов). Cron проще и везде есть. На K8s/контейнерах — CronJob.
SSH — best practices
- Ключ на ed25519:
ssh-keygen -t ed25519 -C "me@laptop". RSA — только ≥3072 бит. - ProxyJump (-J) — ходить через bastion без копирования ключей на него:
ssh -J user@bastion user@target. - Agent forwarding (
-A) — удобно, но опасно: на промежуточном хосте рутовый юзер может попросить ваш агент подписать challenge. Для CI лучшеscp/deploy keys. - known_hosts — защита от MITM. Очищать старые:
ssh-keygen -R host. - Hardening
/etc/ssh/sshd_config:PermitRootLogin no,PasswordAuthentication no,AllowUsers,MaxAuthTries 3,PubkeyAcceptedAlgorithms.
Типовые вопросы с ответами
У каталога те же три бита rwx, что и у файла, но значат они другое — именно это и проверяют на собеседовании:
| Бит | На файле | На каталоге |
|---|---|---|
| r | Читать содержимое файла | Листать имена в каталоге (ls). Без r — ls dir даст «Permission denied», но если знаешь имя — можешь к файлу обратиться (при наличии x) |
| w | Изменять содержимое файла | Создавать / удалять / переименовывать записи в каталоге. Важно: удаление файла зависит от прав на каталог, а не на сам файл. w на каталог + отсутствие w на файл = всё равно удалишь |
| x | Исполнять (бинарь/скрипт) | Входить (cd) и обращаться по имени к inode-ам внутри. Это самый важный бит для каталога: без x каталог становится «чёрной коробкой» |
Комбинации на практике:
r--— видно имена (ls), но ни открыть файлы, ниcd— нельзя. Редкий и почти бесполезный случай.--x— «drop-box»:cdможно, файлы по известному имени доступны, ноlsзапрещён. Часто на/home/<user>.r-x— стандартный read-only каталог: иls, иcd, но не создать/удалить.rwx— полный доступ.
Дополнительные биты на каталоге:
- SGID (
chmod g+s dir) — новые файлы/подкаталоги наследуют группу каталога (а не primary group пользователя). Классика для shared-директорий команды. - sticky (
chmod +t dir, букваtвls -ld) — удалять/переименовывать запись в каталоге может только её владелец, даже если у других естьwна каталог. Так устроен/tmp. - SUID на каталоге игнорируется Linux.
$ ls -ld /tmp /home
drwxrwxrwt 14 root root /tmp # t — sticky
drwxr-xr-x 5 root root /home
# Shared-папка команды: все пишут, новые файлы — в группу devs
sudo chgrp devs /srv/shared
sudo chmod 2775 /srv/shared # 2xxx = SGID; 775 = rwxrwxr-x
# SGID + umask 002 у пользователей — и все файлы автоматически
# создаются с правами rw-rw-r-- и группой devs.
Проверка «могу ли я это сделать» идёт на каждый компонент пути: чтобы прочитать /a/b/c/file, нужен x на /a, /a/b, /a/b/c и r на сам файл. Отсутствие x на промежуточном каталоге сломает доступ, даже если на конечный файл права есть.
df и du?Обе показывают «сколько занято», но смотрят с разных сторон и часто не сходятся — на этом расхождении обычно и ловят инциденты «диск забит, а du не видит кто».
df (disk free) | du (disk usage) | |
|---|---|---|
| Источник данных | Метаданные файловой системы: сколько блоков всего / свободно / занято на устройстве | Обход дерева каталогов: суммирует размеры файлов, которые видно |
| Единица | Per filesystem (точка монтирования / блочное устройство) | Per path (файл / каталог) |
| Скорость | Мгновенно (один syscall statfs()) | Долго — надо обойти и stat() каждый файл |
| Нужны права | Чтение метаданных, на смонтированные ФС видно всем | Права на чтение/обход каждого каталога (иначе «Permission denied» и заниженный результат) |
| Смотрит ли «скрытые» файлы | Да — учитывает весь занятый block space, включая удалённые-но-открытые и скрытые монтирования | Нет — только то, что видит в дереве поверх текущих mount-ов |
Когда df и du расходятся — и почему
- 1. Удалённый, но открытый файл
- Классика. Приложение пишет в
/var/log/app.log, кто-то сделалrm. Inode удалён из каталога (duего не видит), но блоки не освободятся, пока процесс держит файл открытым —dfпоказывает занято.sudo lsof +L1 | head # файлы, у которых link count = 0 (LINK=0) sudo ls -l /proc/$PID/fd/ | grep deleted # фикс: truncate -s 0 /proc/$PID/fd/N (не rm!) или рестарт сервиса - 2. Mount поверх непустого каталога
/var/logбыл набит на 10 GB, потом сверху примонтировали отдельный диск.dfвидит новую ФС (пустую).du /var/logвидит только новое содержимое, но старые 10 GB живы «под» mount'ом и учтены вdfкорня.sudo mount --bind / /mnt sudo du -xsh /mnt/var/log # то, что скрыто mount'ом, становится видно- 3. Резерв ФС для root (ext2/3/4)
- По умолчанию ext4 резервирует 5% блоков для
root.dfпоказывает «100% use» заметно раньше фактического конца, аduэтого резерва не видит.sudo tune2fs -m 1 /dev/sda2 # снизить резерв до 1% (на /var/log разумно) - 4. Sparse-файлы / «дыры»
duпоказывает реально занятые блоки (ключ--apparent-size— показать «заявленный» размер).dfотражает физику. У больших qcow2/vmdk/огромных sparse .log — цифры «размер на диске» и «размер файла» радикально разные.- 5. Разные ФС под одним путём
du /без-xуходит в/proc,/sys, смонтированные сетевые шары, bind-mounts. Всегда —du -x(не пересекать границы ФС).
Практические команды
# df — размер/тип всех ФС, сразу с человечными единицами
df -hT
df -hT /var # только по одной точке
# inode-exhaustion (миллионы мелких файлов — блоки есть, inode-ов нет)
df -i
# du — топ виновников под /var, без вылезания в /proc и другие ФС
sudo du -xh --max-depth=1 /var 2>/dev/null | sort -h | tail
sudo du -xh --max-depth=2 /var/lib 2>/dev/null | sort -h | tail
# быстрее на больших деревьях:
sudo ncdu -x /var
# Почему df показывает полный диск, а du — нет? Deleted-but-open:
sudo lsof +L1 | awk '$NF ~ /deleted/ || $(NF-1) == 0'
df спрашивает у файловой системы, сколько блоков занято, — отвечает мгновенно и видит всё (включая удалённые-но-открытые файлы и данные под mount-ами). du обходит дерево каталогов и суммирует видимые файлы — медленно, зависит от прав и не видит того, что «под» mount'ом или «удалено, но ещё открыто».Обе — способ иметь «ещё одно имя» для файла, но устроены принципиально по-разному.
Hard link (ln file hl) | Symlink / soft link (ln -s target sl) | |
|---|---|---|
| Что это физически | Ещё одна запись «имя → inode» в каталоге, указывающая на тот же inode, что и оригинальное имя. Равноправна с ним — «оригинала» нет | Отдельный файл (свой inode) с маленьким содержимым — строкой пути до target |
| Inode | Совпадает с оригиналом (ls -i) | Свой собственный |
| Link count | У inode растёт на 1 (ls -l, второй столбец). Файл удалится, когда count дойдёт до 0 и ни один процесс его не держит открытым | У target не меняется |
| Пересечение ФС | Нельзя — inode существует только внутри одной ФС | Можно — это просто путь |
| На каталог | Нельзя (только ядро создаёт . и .., чтобы не ломать обход дерева) | Можно |
| Что если оригинал удалить/переместить | «Оригинала» нет, данные живы, пока есть ещё хоть одна ссылка | Симлинк становится dangling (битым) — указывает на путь, которого больше нет |
| Права | Hard link = тот же inode → те же права и владелец (они у inode, не у имени) | У самого симлинка обычно lrwxrwxrwx; проверяются права target при разыменовании |
Видно в ls -l | Как обычный файл | С префиксом l и name -> target |
| Типичное применение | Snapshot-like бэкапы (rsync --link-dest), дедупликация одинаковых файлов | «Текущая версия» (/opt/app/current -> /opt/app/releases/2026-04-22/), cross-mount shortcuts, /etc/alternatives |
# Создание
ln /data/orig /data/hl # жёсткая (оригинал и hl равноправны)
ln -s /data/orig /data/sl # символическая
ls -li /data/
# 131073 -rw-r--r-- 2 u u 0 ... orig <- link count = 2, inode 131073
# 131073 -rw-r--r-- 2 u u 0 ... hl <- тот же inode, та же «двойка»
# 131090 lrwxrwxrwx 1 u u 10 ... sl -> /data/orig
rm /data/orig
cat /data/hl # ок — данные живы
cat /data/sl # No such file or directory — dangling symlink
# Полезное
readlink -f /path/sl # куда разыменовывается (рекурсивно)
find / -samefile /x # все имена, ссылающиеся на тот же inode
find /dir -xtype l # найти битые симлинки
stat file # Links: N (link count inode)
tar, rsync, скриптах часто путают -L (follow symlinks → архивирует содержимое target) и поведение по умолчанию (сохранить симлинк как есть). Не ту ноту → либо дублируешь данные, либо восстанавливаешь битые ссылки.Аналогия для объяснения интервьюеру: hard link — это второй паспорт на того же человека (тот же гражданин/inode); symlink — это бумажка «он живёт по адресу X», и если человек переехал — бумажка врёт.
2. Kubernetes
Ключевой блок. Ожидай глубоких вопросов про архитектуру, сеть, сторадж, отладку подов.
Архитектура кластера
- kube-apiserver — единственный entrypoint, REST-фасад к etcd. Без него кластер «не управляется» (но поды продолжают жить).
- etcd — distributed KV store, источник истины кластера. Raft, нужен нечётный кворум (3/5). Backup обязателен.
- kube-scheduler — назначает поды узлам (учитывая requests, taints, affinity).
- kube-controller-manager — reconcile-циклы (Deployment, ReplicaSet, Node, Endpoint и т.д.).
- cloud-controller-manager — интеграция с облаком (LB, volume, route).
- kubelet — агент узла, общается с apiserver, запускает контейнеры через CRI.
- kube-proxy — программирует правила iptables/ipvs/eBPF для Service→Endpoint.
- Container runtime (containerd/CRI-O) — запускает контейнеры через OCI.
- CNI-plugin (Calico/Cilium/Flannel) — сеть подов, NetworkPolicy.
etcd
- Кворум = N/2 + 1. 3 ноды — терпит 1 падение, 5 — 2.
- Backup:
etcdctl snapshot save /backup/etcd-$(date +%F).db. Восстановление —snapshot restore+ перезапуск членов из того же snapshot. - Deprecated: split-brain в случае сетевого разделения — Raft-лидер остаётся у большинства, меньшинство — read-only.
- Размер рекомендуют ≤ 8 ГБ; defrag при фрагментации.
Основные объекты
- Pod
- Минимальная планируемая единица. 1+ контейнер, общий network namespace и volume-ы. Обычно НЕ создают «руками» — через контроллеры.
- ReplicaSet
- Поддерживает N реплик Pod-ов по селектору. Редко создаётся напрямую — Deployment оборачивает.
- Deployment
- Stateless-приложения. Поддерживает rolling update (
maxSurge,maxUnavailable), rollback (kubectl rollout undo), ревизии. - StatefulSet
- Для stateful (БД, Kafka). Стабильные имена (
mysql-0,mysql-1), по PVC на под (headless-сервис для DNS), упорядоченный rollout. - DaemonSet
- По одному поду на (выбранных) узлах. Логи, сетевые агенты, мониторинг (node-exporter, fluent-bit).
- Job
- Запуск до успешного завершения (batch).
backoffLimit,parallelism,completions. - CronJob
- Job по расписанию.
concurrencyPolicy: Forbid/Allow/Replace,startingDeadlineSeconds,successfulJobsHistoryLimit.
Сеть
- CNI: Calico (BGP + iptables/eBPF, NetworkPolicy из коробки), Cilium (eBPF, L7-policies, замена kube-proxy), Flannel (простой VXLAN, без NetworkPolicy по умолчанию).
- Service types:
- ClusterIP — дефолт, L4, доступен внутри кластера.
- NodePort — открывает порт (30000-32767) на всех нодах.
- LoadBalancer — внешний LB от облака/MetalLB.
- Headless (
clusterIP: None) — без виртуального IP, DNS возвращает IP подов; для StatefulSet. - ExternalName — CNAME на внешний хост.
- Ingress — L7 (HTTP/S), host/path routing, TLS termination. Контроллеры: nginx, Traefik, HAProxy. Gateway API — новый стандарт, богаче (trafficMirror, header modification, cross-namespace refs), постепенно замещает Ingress.
- NetworkPolicy — L3/L4 firewall по лейблам. По умолчанию в k8s — allow all, NetworkPolicy переводит pod в «default deny» только для тех направлений, где есть хотя бы одна Policy.
- CoreDNS — DNS внутри кластера. Сервисы:
svc.namespace.svc.cluster.local. ndots: по умолчанию 5 — любой доменный запрос с <5 точками проходит через search list; отсюда знаменитое «DNS lookups slow» на облаках.
Storage
- PV — ресурс кластера (кусок стораджа). PVC — заявка пода на этот ресурс.
- StorageClass — шаблон для динамического provisioning (EBS, RBD, NFS, CSI-driver).
- ReclaimPolicy:
Retain(после удаления PVC PV остаётся → ручной cleanup),Delete(удаляется underlying),Recycle(deprecated). - AccessMode: RWO (single node), ROX (many read), RWX (many read-write — не всякий сторадж умеет), RWOP (single pod).
- VolumeMode: Filesystem (дефолт) vs Block (raw device).
- CSI — современный стандарт драйверов (EBS/CSI, rook-ceph, longhorn, openEBS).
Конфигурация
- ConfigMap — plain-text параметры. Инжектят как env, volume (файлы), command args.
- Secret — то же, но base64, не шифрование. Шифрование — этаж ниже (encryption at rest в etcd через
--encryption-provider-config), либо внешние вольты (SOPS, Sealed Secrets, ESO). - Обновление: mounted file обновится автоматически (~1-2 минуты), env — НЕ обновится, нужно пересоздать под.
kubectl create secret generic db-creds \
--from-literal=user=admin \
--from-literal=pass='s3cr3t' \
--dry-run=client -o yaml | kubectl apply -f -
Планирование
- requests / limits: requests — «гарантия» для scheduler-а и cgroup-а, limits — потолок. CPU можно throttle; memory — OOMKill.
- QoS-классы:
- Guaranteed — limits = requests на все ресурсы.
- Burstable — requests < limits (хоть у одного).
- BestEffort — ни requests, ни limits. Убивают первыми при нехватке.
- Taints/Tolerations: taint на узле отталкивает поды, toleration на поде позволяет «терпеть». Типичный кейс: GPU-узлы, spot-ноды, master без workload.
- Affinity: nodeAffinity (требовать зоны/labels ноды), podAffinity (держать вместе), podAntiAffinity (разносить реплики на разные ноды/зоны).
- TopologySpreadConstraints — равномерно разложить поды по топологическим ключам (zone, hostname).
- PriorityClass + preemption — высокоприоритетные поды могут «сбросить» низкоприоритетные.
Автоскейлинг
- HPA — по CPU/memory/custom metric. Читает из metrics.k8s.io (metrics-server) / custom.metrics.k8s.io (adapter → Prometheus).
kubectl autoscale deploy web --min=2 --max=10 --cpu-percent=70. - VPA — перестраивает requests/limits. Три режима: Off (только рекомендует), Auto (рестартит pod с новыми значениями), Initial (только при создании).
- Cluster Autoscaler — скейлит сами ноды (через провайдера облака) на основании unschedulable pending-подов.
- Karpenter — альтернатива CA от AWS, гибче (подбирает нужный instance type под нагрузку, не ограничен node groups).
Безопасность
- RBAC: Role/ClusterRole (набор verbs на resource'ы) + RoleBinding/ClusterRoleBinding (привязка к Subject — User/Group/ServiceAccount).
- ServiceAccount — identity для пода. Токен монтируется в
/var/run/secrets/kubernetes.io/serviceaccount/. - PodSecurityAdmission (заменил PSP в 1.25+): уровни
privileged/baseline/restricted, включается label'ом namespace. - seccomp/AppArmor — фильтрация syscall-ов. Включается на уровне пода/контейнера.
- OPA/Gatekeeper и Kyverno — admission controllers для политик («все image'ы только из trusted registry», «ни одного privileged», «resources обязательны»). Kyverno проще (YAML-native), Gatekeeper — Rego.
Обновление / drain
# Узел
kubectl cordon node-1 # пометить unschedulable
kubectl drain node-1 --ignore-daemonsets --delete-emptydir-data
# апгрейдим, возвращаем
kubectl uncordon node-1
# Deployment
kubectl rollout status deploy/web
kubectl rollout history deploy/web
kubectl rollout undo deploy/web --to-revision=3
PodDisruptionBudget (PDB) — гарантия «минимум X реплик всегда живых» при добровольных eviction (drain). Без PDB drain спокойно укатает все реплики.
Probes (liveness / readiness / startup)
| Probe | Что делает fail | Когда нужна |
|---|---|---|
| liveness | Рестартит контейнер | Приложение в deadlock, зависло — надо перезапустить |
| readiness | Исключает pod из endpoint'ов Service | Warm-up, temporary dep отказ — не гасим pod, но и трафик не лить |
| startup | До её success остальные не запускаются | Долгий старт (Java) — нельзя дать liveness убить pod раньше времени |
/health, который зависит от БД. БД моргнула → liveness fail → pod рестарт → всё стадо рестартит. Liveness должна проверять только «жив ли сам процесс»; зависимости — в readiness.Деплой кластера
| Инструмент | Плюсы | Минусы |
|---|---|---|
| kubeadm | Официальный, гибкий, идемпотентный | Нет LB, etcd и upgrade-процесса «из коробки» |
| kubespray | Ansible-based, много плагинов, prod-ready | Медленный, много параметров |
| Managed (EKS/GKE/AKS) | Control plane не ваш, auto-upgrade | Vendor lock, цена, меньше гибкости |
| k3s / k0s | Лёгкий, быстро, edge/dev | Не всё супер-стандартно |
Troubleshooting поды
| Статус | Причина | Что смотреть |
|---|---|---|
| Pending | Нет ресурсов / PVC не bind / taint | kubectl describe pod — events внизу |
| CrashLoopBackOff | Процесс падает сразу после старта | kubectl logs --previous, liveness probe, entrypoint |
| ImagePullBackOff | Кредов нет / тег не существует / registry недоступен | describe events; imagePullSecret; crictl pull с ноды |
| OOMKilled | Процесс превысил memory limit | describe → Last State: Terminated, Reason: OOMKilled. Смотри memory-метрики, тюнь limits или код |
| Evicted | Нода в memory/disk pressure, k8s выселил | describe pod + kubectl describe node → conditions |
| Error/Completed | Job завершился; не рестартится по спеке | Проверить restartPolicy и reason |
kubectl describe pod web-xxx
kubectl logs -f web-xxx -c sidecar
kubectl logs web-xxx --previous
kubectl exec -it web-xxx -- sh
kubectl get events --sort-by=.lastTimestamp -A | tail
kubectl top pod -A; kubectl top node
3. Docker и контейнеры
Образ и слои
Образ = набор read-only слоёв + manifest + config. Каждый RUN/COPY/ADD создаёт слой. Слои общие между образами → пул-экономия.
overlayfs (дефолтный storage driver): lower (read-only слои образа) + upper (writable layer контейнера) + merged (что видит контейнер). Копирование-при-записи: изменение файла из нижнего слоя «копирует» его в upper.
Кеш сборки: докер считает слой тем же, если инструкция совпадает И base не изменился. Поэтому COPY go.mod go.sum ./ && go mod download идёт раньше COPY . . — зависимости кешируются и не скачиваются при каждом изменении кода.
Dockerfile best practices
- Минимальная база:
alpine,distroless,debian:bookworm-slim. Чем меньше — тем меньше CVE и размер. - Multi-stage: собираем в builder-образе, копируем артефакт в runtime-образ.
- Non-root:
USER 10001:10001. Если требуется bind на :80 — лучше слушать :8080 и маппить снаружи. - Один процесс на контейнер (12-factor). Несколько — только через supervisor в спец. кейсах.
- Порядок команд: часто меняющиеся — вниз;
COPY package.jsonпередCOPY .. .dockerignore: уменьшить build context (node_modules,.git, логи).- HEALTHCHECK: полезно для swarm; в k8s игнорируется (есть probes).
# multi-stage пример (Go)
FROM golang:1.22-alpine AS build
WORKDIR /src
COPY go.* ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 go build -o /out/app ./cmd/app
FROM gcr.io/distroless/static:nonroot
COPY --from=build /out/app /app
USER nonroot:nonroot
ENTRYPOINT ["/app"]
Изоляция: namespaces + cgroups
- Namespaces (что контейнер «видит»): pid, net, mnt, uts (hostname), ipc, user, cgroup.
- cgroups (сколько ресурсов контейнер «может»): CPU shares/quota, memory, blkio, pids. v2 — единое дерево, лучше accounting.
- Дополнительно: capabilities (root-привилегии разбиты на флажки), seccomp (whitelist syscall), AppArmor/SELinux (MAC).
Runtime: containerd vs Docker vs CRI-O
Исторически Docker = docker-cli + dockerd + containerd + runc. Kubernetes ходил в Docker через dockershim. В 1.24 shim удалили — теперь k8s говорит напрямую с containerd/CRI-O по CRI. Образы и опыт разработчика этим не затрагивается; для админа k8s это значит, что docker ps на ноде не покажет контейнеры — используй crictl ps.
Сети Docker
| Driver | Когда |
|---|---|
| bridge (default) | Дефолтный bridge docker0; кастомные bridge-сети дают DNS по именам контейнеров |
| host | Контейнер делит сеть с хостом (без NAT, лучшая perf, нет изоляции портов) |
| none | Без сети вообще (для изолированных задач) |
| overlay | Swarm: мультихост-сеть через VXLAN |
| macvlan | Контейнер — отдельный MAC в физической сети (legacy-приложения, ожидающие L2) |
Volumes vs bind mounts vs tmpfs
- named volume — Docker управляет, лежит в
/var/lib/docker/volumes/. Переносимо между хостами (бекап черезdocker run --volumes-from). Правильный выбор для state. - bind mount — конкретный путь хоста. Удобно для dev, рискованно для prod (разные FS/uids).
- tmpfs — только в RAM, эфемерно.
Registry, подпись, сканирование
- Registry: Docker Hub, GitLab Registry, Harbor (on-prem), Nexus, Artifactory, GHCR.
- Подпись:
cosign sign/verify(Sigstore) — подписывает digest (SHA256), а не tag. Проверяется в admission controller (Kyverno/OPA). - Сканирование: Trivy (самый популярный, CVE + misconfig + secrets + SBOM), Grype, Clair, Snyk. В CI блокируем HIGH/CRITICAL.
- SBOM (Software Bill of Materials) — список всех зависимостей образа.
syftгенерит,grypeскормит.
trivy image --severity HIGH,CRITICAL myapp:latest
cosign sign --key cosign.key myrepo/app:1.2.3
cosign verify --key cosign.pub myrepo/app:1.2.3
4. CI/CD (GitLab CI и Jenkins)
GitLab CI — якорные понятия
- Stages — последовательные фазы (build → test → deploy). Job-ы в одном stage идут параллельно.
- Jobs — единица выполнения, привязывается к runner.
- Runners: shared (GitLab.com), group, specific (project). Executors: shell, docker, docker-in-docker, kubernetes, ssh, parallels, virtualbox, custom.
- cache vs artifacts: cache — для ускорения между job-ами в одной project (
node_modules,.m2), expire не задан; artifacts — результаты job-а, доступны следующим stage-ам/пользователям, версионируются с pipeline. - rules / only / except: современный синтаксис —
rulesсif,changes,exists.only/except— legacy. - needs / DAG: разрывает строгое порядковое выполнение stages — job может стартовать сразу как готовы его
needs.needs:сartifacts: true. - Parent-child / multi-project pipelines: trigger dynamic pipeline, trigger в другом проекте (
trigger: project: group/other). - Environments — dev/staging/prod, отслеживание деплоев; manual action → one-click deploy.
- Protected branches/tags + masked variables → секреты только в защищённых контекстах.
stages: [build, test, deploy]
variables:
DOCKER_TLS_CERTDIR: ""
build:
stage: build
image: docker:24
services: [docker:24-dind]
script:
- docker build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA .
- docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA
rules:
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
- if: '$CI_COMMIT_BRANCH == "main"'
deploy:prod:
stage: deploy
needs: [build]
environment: { name: prod, url: https://app.example.com }
rules:
- if: '$CI_COMMIT_BRANCH == "main"'
when: manual
script:
- helm upgrade --install web ./charts/web --set image.tag=$CI_COMMIT_SHORT_SHA
Jenkins
- Declarative (рекомендуется) vs Scripted (полная мощь Groovy, больше соблазнов ошибиться).
- Shared libraries — вынести общий Groovy-код в отдельный репо (
@Library('my-lib')). - Agents — master orchestrates, jobs идут на agents (static, docker, kubernetes plugin). Kubernetes-plugin создаёт pod-agent на лету.
- Credentials — binding через
withCredentials/credentialsId. Stored в Jenkins encrypted store. - Blue Ocean — UI для визуализации pipelines.
pipeline {
agent { kubernetes { yamlFile 'jenkins-agent.yaml' } }
options { timeout(30) }
stages {
stage('Test') { steps { sh 'make test' } }
stage('Build') { steps { sh 'make build' } }
stage('Deploy') {
when { branch 'main' }
steps {
withCredentials([string(credentialsId: 'kubeconfig', variable: 'KUBECONFIG')]) {
sh 'helm upgrade --install web charts/web'
}
}
}
}
post { always { junit 'reports/*.xml' } }
}
Стратегии деплоя
| Стратегия | Суть | Плюс | Минус |
|---|---|---|---|
| Rolling | Постепенно заменяем реплики старой версии новой | Простая, без extra ресурсов | Обе версии одновременно живут; совместимость обязательна |
| Blue-green | Полностью развернуть «green», переключить LB | Мгновенный rollback | 2x ресурсов во время смены |
| Canary | 5% → 25% → 100% трафика на новую версию, с метриками | Ограничивает blast radius | Нужен тулчейн (Argo Rollouts / Flagger) + метрики |
| A/B | Роутинг по признаку (header/cookie/user segment) | Product-experiments | Требует feature-flags / service mesh |
В k8s: native rolling — из Deployment. Canary/Blue-green — Argo Rollouts, Flagger (с Istio/Linkerd/Nginx).
Секреты в пайплайнах
- GitLab: masked + protected variables, file-type variables для key-файлов, integration с Vault (
secrets:в job). - Jenkins: credentials plugin, HashiCorp Vault plugin, AWS Secrets Manager plugin.
- Общее правило: никогда не print'ать секреты в логи.
set -x+ секрет в env = утечка.
Артефакты / репозитории
- Nexus / Artifactory — универсальные (Maven, npm, PyPI, Docker, generic). Прокси для внешних реестров + self-host.
- GitLab Package & Container Registry — встроены.
Безопасность пайплайна
| Класс | Инструменты | Что ловит |
|---|---|---|
| SAST | SonarQube, Semgrep, Checkmarx, Bandit (Py), gosec (Go) | Уязвимости в исходниках |
| DAST | OWASP ZAP, Burp | Уязвимости работающего приложения (XSS, SQLi) |
| SCA | Snyk, Dependency-Track, Trivy (fs), Renovate | Уязвимости в зависимостях |
| Secret scanning | gitleaks, trufflehog, GitLab Secret Detection | Утечки API-ключей в репо |
| Lint / config | hadolint, kube-linter, tflint, yamllint, ansible-lint | Bad practices |
| SBOM | syft, cyclonedx | Прозрачность зависимостей, соответствие требованиям |
5. GitOps и пакет-менеджеры K8s
Helm
- Chart — пакет шаблонов. Структура:
Chart.yaml,values.yaml,templates/*.yaml,charts/(subcharts). - Values — параметры, override через
-f values-prod.yamlи--set. - Templates — Go templates + sprig-функции (
default,quote,toYaml,include,tpl). - Release — инстанс чарта с именем/namespace. История в
Secret/ConfigMap. - Hooks (
helm.sh/hook: pre-install,pre-upgrade) — job-ы на разных стадиях. - Dependencies — subcharts в
Chart.yaml,helm dep update. - helmfile — декларативный wrapper: описать набор releases и параметры в одном YAML.
helm template web ./charts/web -f values-prod.yaml # отрендерить без установки
helm upgrade --install web ./charts/web -n prod --create-namespace
helm diff upgrade web ./charts/web # plugin helm-diff
helm rollback web 2
helm history web
Kustomize
- Base + overlays. Без шаблонизации — только наложение patch-ей на базовые manifest-ы.
- Плюсы: прозрачность (всё — валидный YAML), встроен в
kubectl -k, нет runtime-зависимостей. - Минусы: нет if/else/loop, сложные чарты писать больно.
- Комбинируется с Helm через
helmCharts:в kustomization.yaml.
Helm vs Kustomize
| Helm | Kustomize | |
|---|---|---|
| Шаблоны | Go tpl, powerful, но сложно читать | Plain YAML + patches |
| Упаковка | Chart = артефакт (репо) | Просто каталог в Git |
| Lifecycle | install/upgrade/rollback, history | Apply-only, состояние в Git |
| Для | Cторонних приложений (operators) | Собственные манифесты |
ArgoCD vs Flux
- ArgoCD — UI богатый, App/AppProject модель, ApplicationSet для генерации, sync waves (
argocd.argoproj.io/sync-wave), self-heal, SSO из коробки, App of Apps для больших кластеров. - Flux — CRDs GitRepository / HelmRepository / Kustomization / HelmRelease. Декларативнее, без UI (есть Capacitor/Weave GitOps); хорошо интегрируется с Flagger для canary.
- Общие принципы: Git — source of truth, контроллер периодически ресинкает кластер, расхождения (drift) подсвечиваются.
Секреты в GitOps
Положить «чистый» Secret в Git нельзя (base64 != encryption). Варианты:
- SOPS
- Шифрование YAML значений (age/GPG/KMS). Хранится в Git, расшифровывается controller-ом (ArgoCD sops-plugin / kustomize-sops).
- Sealed Secrets (Bitnami)
- Controller в кластере с парой ключей.
kubesealшифрует Secret публичным ключом → получается SealedSecret, кладётся в Git. Расшифровка только в этом кластере. - External Secrets Operator (ESO)
- CRD
ExternalSecretподтягивает значения из Vault/AWS SM/GCP SM/1Password. В Git — только ссылка, значения живут в external store. - Vault CSI Provider / Vault Agent Injector
- Секреты инжектятся в pod как файлы/env из Vault прямо на лету.
Принципы GitOps
- Желаемое состояние описано декларативно.
- Хранится в Git (единый source of truth, аудит, PR-based approval).
- Агент автоматически синхронизирует кластер с Git.
- Расхождения детектируются и алертят (drift detection).
6. Мониторинг и Observability
Три столпа (+ два)
| Столп | Что даёт | Инструменты |
|---|---|---|
| Metrics | Агрегированные числа во времени — CPU, latency, error rate | Prometheus, VictoriaMetrics, Datadog |
| Logs | Дискретные события с контекстом | ELK/EFK, Loki, Splunk |
| Traces | Путь одного запроса через сервисы (spans) | Jaeger, Tempo, Zipkin |
| Events | Деплои, pod evictions (k8s events), алерты — «что вообще происходит» | k8s, EventBridge |
| Profiles | CPU/memory профили во времени | Pyroscope, Parca, Grafana Phlare |
Prometheus
- Pull-модель: Prometheus сам ходит по
/metricsтаргетов. Для кратковременных job-ов — Pushgateway. - Exporters: node_exporter (Linux host), postgres_exporter, blackbox_exporter (ping/HTTP), kube-state-metrics (state объектов k8s).
- Data model: time series =
metric_name{label="v", ...}, тип: Counter (только растёт, reset при рестарте), Gauge (может туда-сюда), Histogram (buckets + _sum + _count), Summary (квантили клиентского подсчёта). - Remote write: отправляем «сырые» метрики в Thanos/VictoriaMetrics/Mimir для долгосрочного хранения.
- Federation: один Prometheus scrape'ит
/federateдругого (иерархия dc → global).
PromQL essentials
# Rate запросов за 5 мин, по service
sum by (service) (rate(http_requests_total[5m]))
# 99-й перцентиль latency из histogram
histogram_quantile(0.99,
sum by (le, service) (rate(http_request_duration_seconds_bucket[5m]))
)
# Error rate в процентах
100 * sum(rate(http_requests_total{status=~"5.."}[5m]))
/ sum(rate(http_requests_total[5m]))
# Сколько pod-ов в CrashLoop
sum by (namespace) (kube_pod_container_status_waiting_reason{reason="CrashLoopBackOff"})
# rate vs irate: rate — сглажённое по окну, irate — по двум последним точкам (шумнее, для алертов)
rate() под sum(... by le), иначе врёт. Без by (le) — бессмыслица.Правила
- Recording rules — предрасчёт часто используемых выражений (
job:http_errors:rate5m). - Alerting rules —
ALERTпо выражению +for: 10m(чтобы не сработать от спайка).
Alertmanager
- Routes — дерево маршрутизации по labels (team, severity) в receivers (Slack, Pagerduty, email).
- Grouping — склеивать похожие (по
group_by) в одно уведомление. - Inhibition — «если сработал X, не шлём Y» (напр. node_down → не шлём «pod unreachable» для каждого pod-а на этой ноде).
- Silences — временное подавление по label-matcher'у.
Grafana
- Datasources: Prometheus, Loki, Tempo, PostgreSQL, ClickHouse, ElasticSearch.
- Variables (template variables) — параметризуют дашборды (
$instance). - Unified Alerting — новая модель (замена legacy). Поддерживает многошаговые алерты (Grafana-managed и Prometheus-managed).
- Provisioning — дашборды и datasources как YAML/JSON, через GitOps.
Zabbix vs Prometheus
| Zabbix | Prometheus | |
|---|---|---|
| Модель | Push (agent) + pull; «хостоцентричная» | Pull, «метрикоцентричная», dimensional |
| Storage | MySQL/Postgres | TSDB on disk (+ remote_write) |
| Откуда взят | IT-monitoring 2001-го; агент-based | Cloud-native (2012), SoundCloud |
| Лучшее применение | «Железо», SNMP, сетевое оборудование, enterprise-оповещения | Сервисы, k8s, микросервисы, Service-level metrics |
Tracing — OpenTelemetry
- OTel = стандарт (API + SDK + collector + протоколы). Один SDK в приложении, экспорт в любой backend.
- OTel collector: receivers (OTLP, Prometheus scrape) → processors (batch, memory_limiter, attributes) → exporters (Jaeger, Tempo, Prometheus).
- Trace context (
traceparent, W3C) пробрасывается через заголовки.
Методологии
- RED
- Rate (RPS), Errors (rate ошибок), Duration (latency). Для request-driven сервисов.
- USE
- Utilization, Saturation, Errors. Для ресурсов (CPU, диск, сеть).
- Four Golden Signals (Google SRE)
- Latency, Traffic, Errors, Saturation.
SLI / SLO / SLA / Error budget
- SLI — измеряемая величина (availability, latency p99).
- SLO — целевой уровень SLI (99.9% за 30 дней).
- SLA — договор с клиентом, обычно слабее SLO (чтобы SLO был guard-rail-ом).
- Error budget = 1 − SLO. На 99.9% это 43m за 30 дней. Пока бюджет есть — катаем релизы, «сгорел» — замораживаем фичи и чиним надёжность.
Long-term storage
- Thanos — sidecar + object storage + querier. Prometheus-native, долгая история.
- Cortex / Grafana Mimir — multi-tenant, horizontally scalable.
- VictoriaMetrics — один бинарь, шустрее, меньше ресурсов, MetricsQL (расширение PromQL). cluster version на большие объёмы.
7. Логирование (EFK/ELK)
Архитектура стеков
приложение → [сборщик] → [обработчик] → [хранилище] → [UI]
Filebeat Logstash ES/OS Kibana
Fluent Bit Fluentd (альтернативы)
Vector Vector
- ELK — Elasticsearch + Logstash + Kibana.
- EFK — та же связка, но Fluentd/Fluent Bit вместо Logstash (часто в k8s).
- OpenSearch — форк Elasticsearch от AWS после смены лицензии ES на SSPL. API-совместим, Apache 2.0.
Elasticsearch — ключевое
- Индекс — логическая коллекция документов. Физически делится на shards (primary + replicas).
- Шардирование: новые документы распределяются по primary shard-ам по
_routing. Число primary фиксируется на создании. - Реплики: копии primary на других нодах. 1 replica → на shard отказоустойчивость + больший read throughput.
- Mapping — «схема» полей (типы, analyzers). Авто-mapping удобен, но в prod лучше явный.
- Analyzers — токенизация, стемминг для full-text search. Standard/keyword для логов чаще всего достаточно.
- Heap sizing: 50% RAM, но не больше 32 GB (compressed oops). Остальное — page cache.
- Split brain — исторически решалось
minimum_master_nodes; в 7+ — zen2 discovery, авто.
ILM (Index Lifecycle Management)
Фазы: hot (активно пишется) → warm (меньше ресурсов) → cold (сжатие, читается редко) → frozen (searchable snapshot) → delete.
{
"policy": {
"phases": {
"hot": { "actions": { "rollover": { "max_size": "50gb", "max_age": "7d" } } },
"warm": { "min_age": "7d", "actions": { "shrink": {"number_of_shards":1}, "forcemerge":{"max_num_segments":1}}},
"cold": { "min_age": "30d", "actions": { "searchable_snapshot": {"snapshot_repository":"s3"}}},
"delete": { "min_age": "90d", "actions": { "delete": {} } }
}
}
}
Rollover / curator / retention
- Rollover — переключение на новый индекс при достижении размера/возраста (
logs-000001 → logs-000002) по alias-уlogs. - Curator — legacy-инструмент; современный путь — ILM.
- Retention: для логов обычно 7-30 дней «в горячем», остальное в warm/cold/S3 snapshot.
Fluent Bit vs Fluentd
| Fluent Bit | Fluentd | |
|---|---|---|
| Язык | C | Ruby + C-плагины |
| Потребление | ~1 МБ RAM | десятки/сотни МБ |
| Плагинов | меньше | >500 |
| Для чего | Node-agent (DaemonSet в k8s), edge | Aggregator, богатая обработка |
Типовой паттерн k8s: Fluent Bit DaemonSet собирает stdout pod-ов → Fluentd aggregator (опц.) → Elastic/OpenSearch.
Парсинг и нормализация
- Приводим логи к единой схеме — ECS (Elastic Common Schema):
@timestamp,service.name,host.name,log.level,event.dataset. - Парсинг multiline (stacktrace Java) —
multiline.patternв Filebeat/Fluent Bit. - Лучше писать JSON-логи из приложения — не нужен grok.
- Ingest pipelines в ES — как «мини-Logstash» на уровне ES-кластера (grok, script, rename, date, geoip).
Производительность
- Bulk API: batch-размер 5-15 МБ, 1000-5000 документов — оптимум.
- Размер shard-а: 20-50 ГБ. Больше — replay медленный, меньше — overhead на управление.
- Отключать
_sourceнельзя, если нужен reindex. refresh_interval— при индексации поднять до 30s (дефолт 1s) — меньше IO.
Безопасность
- X-Pack Security / OpenSearch Security: native users, RBAC, index-level permissions, document-level security, field-masking.
- TLS везде: node↔node (transport), client↔node (REST), Kibana↔ES.
- Для PCI — маскирование PAN/CVV в логах на стороне приложения + ещё раз в processor (защита в глубину).
Альтернатива — Loki
Grafana Loki: индексирует только labels (как Prometheus), сами логи — сжатые чанки. Дёшево по storage, но LogQL ограничен по full-text.
8. PostgreSQL
Архитектура процессов
- postmaster — супервизор, слушает порт, форкает backend при каждом коннекте.
- backend — один процесс на коннект (дорого! отсюда pool-еры).
- autovacuum launcher + workers — чистят dead tuples, обновляют stats.
- wal writer — пишет WAL buffer на диск.
- checkpointer — сбрасывает грязные страницы shared_buffers на диск и отсекает старые WAL.
- background writer — помогает checkpointer-у непрерывно.
- walsender / walreceiver — для репликации.
MVCC, VACUUM, bloat
- Каждая строка — несколько версий (tuples) с xmin/xmax. UPDATE = insert + mark old as dead.
- VACUUM освобождает место внутри страниц (для reuse), VACUUM FULL — rewrite table с exclusive lock (простой недопустим).
- autovacuum срабатывает по порогам:
autovacuum_vacuum_scale_factor(0.2 по умолчанию — 20% dead). На больших таблицах хочется меньше (0.02–0.05), чтобы не пропускать. - Bloat — раздутые таблицы/индексы. Диагностика:
pgstattuple, запросы-checkers из pg_wiki. Починка:REINDEX CONCURRENTLY,pg_repack. - Wraparound: xid 32-битный; при достижении transaction-wraparound PostgreSQL уходит в read-only. Следим
age(datfrozenxid).
Репликация
| Тип | Что | Применение |
|---|---|---|
| Physical streaming | Побайтная копия WAL, всё или ничего | HA, read replicas |
| Logical | Публикация/подписка по таблицам, построчно | Гетерогенные версии, частичная репликация, миграции |
| Synchronous | Commit ждёт подтверждения standby (synchronous_commit=on + synchronous_standby_names) | Нет потери данных, но latency +RTT |
| Asynchronous | Standby отстаёт, возможна потеря | Performance, география |
Replication slots — гарантируют, что master не удалит WAL, пока standby/consumer не прочитает. Риск: «забытый» slot → WAL растёт бесконтрольно → pg_wal полон → база OOM по диску.
HA решения
- Patroni (+ etcd/Consul/ZooKeeper как DCS) — de-facto стандарт. Auto-failover, leader election, REST API для orchestration. Zalando.
- repmgr — проще, меньше зависимостей, ручной failover или script-driven.
- pg_auto_failover — MS + monitor, тройка узлов.
- Для routing — HAProxy + Patroni healthcheck (
/master,/replica), либо PgBouncer поверх.
Backup / Restore / PITR
- pg_dump (logical) — консистентный snapshot; не работает на очень больших БД (часы-дни на сотни ГБ).
- pg_basebackup — физический бэкап running-кластера. База для PITR.
- WAL-G / pgBackRest — инкрементальные бэкапы в S3, параллелизм, сжатие, delta, PITR с высокой гранулярностью.
- PITR: base backup + непрерывная archive WAL → восстановление на любую точку (recovery_target_time).
- Всегда проверяем восстановление (untested backup = no backup).
Пулеры соединений
| Session | Transaction | Statement | |
|---|---|---|---|
| Когда освобождается соединение | После disconnect клиента | После COMMIT/ROLLBACK | После каждого statement |
| Поддержка prepared statements, advisory locks, session state | Да | Ограниченно (могут сломаться) | Нет |
| Эффективность | Низкая | Отличная (дефолт PgBouncer) | Экстремальная, но ломает многое |
EXPLAIN — что читать
EXPLAIN (ANALYZE, BUFFERS, VERBOSE, FORMAT TEXT)
SELECT ... FROM ...;
-- Seq Scan vs Index Scan / Index Only Scan / Bitmap Heap Scan + Bitmap Index Scan
-- rows=estimate vs actual rows=... (если сильно расходятся — вакуум/статистика, re-ANALYZE)
-- Filter: ... rows removed (неэффективный индекс, или его нет)
-- Buffers: shared hit=X read=Y (read = с диска, много → холодный кеш или мало shared_buffers)
-- Sort Method: external merge Disk (work_mem мал)
-- Hash Join vs Merge Join vs Nested Loop (NL на больших = беда)
Индексы
- B-Tree — дефолт, для
= < > BETWEEN, ORDER BY. - GIN — для массивов, jsonb, full-text. Быстрый поиск, дорогие вставки.
- GiST — геометрия, полнотекст, ranges.
- BRIN — «block range», для огромных таблиц с природным порядком (timestamp логов), очень маленький.
- Partial:
CREATE INDEX ... WHERE status = 'active'— индекс только на часть строк. - Covering (INCLUDE):
CREATE INDEX ... (user_id) INCLUDE (email, name)— Index Only Scan без heap-touch. CREATE INDEX CONCURRENTLY— без блокировки пишущих запросов (дольше, может failать).
Партиционирование
- Declarative partitioning (PG 10+): RANGE (по дате), LIST, HASH.
- Partition pruning — planner исключает ненужные партиции.
- Использование: логи/events по месяцам/неделям; старые партиции drop'ом удаляются мгновенно.
- Шардинг — горизонтальное масштабирование по нодам: Citus (distributed tables с distribution_column), FDW + партиции (ручной шардинг).
Тюнинг (отправные точки для 64 GB RAM)
| Параметр | Значение | Смысл |
|---|---|---|
shared_buffers | 25% RAM (16 GB) | Внутренний кеш страниц |
effective_cache_size | 50-75% RAM | Planner: сколько ОС-кеша доступно |
work_mem | 16-64 MB (на каждый sort/hash!) | Поднятие = меньше disk sort, но ×N операций ×M коннектов |
maintenance_work_mem | 1-2 GB | VACUUM/CREATE INDEX |
wal_level | replica (или logical) | Нужен для streaming/logical репликации |
max_wal_size | 4-16 GB | Reduce checkpoint frequency |
checkpoint_completion_target | 0.9 | Размазать checkpoint |
random_page_cost | 1.1 (SSD) | Planner friendlier к index scan |
Locks и deadlocks
-- Что сейчас блокируется
SELECT blocked.pid AS blocked_pid, blocked.query AS blocked_query,
blocking.pid AS blocking_pid, blocking.query AS blocking_query
FROM pg_stat_activity blocked
JOIN pg_stat_activity blocking ON blocking.pid = ANY(pg_blocking_pids(blocked.pid))
WHERE blocked.wait_event_type = 'Lock';
-- Убить
SELECT pg_cancel_backend(pid); -- попросить
SELECT pg_terminate_backend(pid); -- жёстко
-- Долгие транзакции (виновники bloat + wraparound)
SELECT pid, state, xact_start, query FROM pg_stat_activity
WHERE state = 'idle in transaction' AND xact_start < now() - interval '10 min';
idle in transaction — тихий убийца: держит locks, блокирует VACUUM, раздувает таблицы. Нужен idle_in_transaction_session_timeout.Observability БД
- pg_stat_statements — топ-запросы по времени/вызовам.
- auto_explain — логировать план для медленных запросов.
- postgres_exporter → Prometheus → Grafana (стандартные дашборды: commits/rollbacks, cache hit, replication lag, disk space).
9. Configuration Management (Ansible / Salt)
Ansible базово
- Inventory — static (
hosts.yml,hosts.ini) или dynamic (плагины: AWS EC2, GCP, k8s, custom script). - Playbook — список
plays(hosts + tasks + handlers + vars). YAML. - Role — папка со стандартной структурой (
tasks/,handlers/,templates/,defaults/,vars/,files/,meta/). Переиспользуемая единица. - Handlers — «ленивые» таски: вызываются
notify, запускаются один раз в конце play (обычно restart service). - Templates — Jinja2 (
{{ var }},{% if %},{% for %}), filters (default,to_nice_json,b64encode), tests. - Lookup — получение данных вне inventory:
{{ lookup('env','HOME') }},{{ lookup('file','cert.pem') }},vault,etcd. - when / loop / tags: условия, циклы, группировка тасков для выборочного запуска.
- Ansible Vault:
ansible-vault encrypt_string,--vault-password-file. Шифрует YAML значения (AES256).
# Простой role task
- name: Install nginx
ansible.builtin.apt:
name: nginx
state: present
update_cache: true
cache_valid_time: 3600
- name: Render nginx config
ansible.builtin.template:
src: nginx.conf.j2
dest: /etc/nginx/nginx.conf
mode: "0644"
validate: "nginx -t -c %s" # проверка синтаксиса перед тем как положить
notify: Restart nginx
Идемпотентность
- Задача — описывать состояние, а не действие. «Пакет установлен», а не «запусти apt install».
- Декларативные модули (
apt,copy,template,systemd_service,user,lineinfile) — идемпотентны из коробки. command/shell— не идемпотентны; обязательноcreates:,removes:,changed_when:,failed_when:.- Проверка: второй прогон должен давать
changed=0. Это «zen of Ansible».
Push vs pull
- Push (ansible): запускаешь с control-машины, идёт по SSH. Простая модель, нужно SSH-доступ к узлам.
- ansible-pull: узел сам клонирует репо и применяет. Годно для больших флотов (edge, IoT), cron-based.
Тестирование ролей — Molecule
- Scenarios: create → prepare → converge (применить роль) → verify (тесты:
testinfra,ansible,shell) → destroy. - Драйверы: docker, podman, vagrant, ec2.
- Идеально в CI: каждый PR к роли — Molecule + lint + syntax-check.
Salt — обзор
- Модель: master/minion (push-event-driven). Salt-ssh — agentless (как Ansible).
- Grains — факты о minion-е (как Ansible facts).
- Pillar — приватные данные, назначаемые per-minion (параллель к Ansible vars/Vault).
- States (SLS) — YAML + Jinja, задают желаемое состояние.
- Reactor — реакция на события (подписался на event bus → запустил state).
- Плюс: скорость, масштаб (event-bus ZeroMQ). Минус: сложнее, меньше community, debug тяжёлый.
Сравнение CM-инструментов
| Ansible | Salt | Puppet | Chef | |
|---|---|---|---|---|
| Модель | Agentless, push | Master/minion (event bus) | Master/agent pull | Server/client pull |
| Язык | YAML + Jinja | YAML + Jinja (или Py) | Puppet DSL | Ruby DSL |
| Порог входа | Низкий | Средний | Высокий | Высокий |
| Сильная сторона | Простота, ad-hoc | Скорость, event-driven | Enterprise compliance | Infrastructure-as-code «по-настоящему» |
10. Микросервисная инфраструктура
Nginx (reverse proxy)
upstream api {
least_conn; # round_robin | least_conn | ip_hash | hash $var
server api1:8080 max_fails=3 fail_timeout=30s;
server api2:8080;
keepalive 64; # пул upstream-соединений (HTTP/1.1 keep-alive)
}
limit_req_zone $binary_remote_addr zone=api:10m rate=50r/s;
server {
listen 443 ssl http2;
server_name api.example.com;
ssl_certificate /etc/ssl/fullchain.pem;
ssl_certificate_key /etc/ssl/privkey.pem;
location / {
limit_req zone=api burst=100 nodelay;
proxy_pass http://api;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
proxy_read_timeout 60s;
}
location /static/ {
proxy_cache static_cache;
proxy_cache_valid 200 1h;
proxy_pass http://api;
}
}
- Балансировка: round_robin (default), least_conn, ip_hash (sticky),
hash $cookie_sid consistent. - Keepalive к upstream —
keepalive Nв upstream +proxy_http_version 1.1+ обнулитьConnection. - Rate limiting:
limit_req(leaky bucket),limit_conn. - TLS: Mozilla intermediate профиль, OCSP stapling, HSTS; сертификаты через certbot/cert-manager.
- Graceful reload —
nginx -s reload(SIGHUP): worker процессы дорабатывают запросы, новые принимают новые worker-ы.
HAProxy
- L4 (tcp) и L7 (http) — один из лучших балансировщиков.
- Active health checks:
check,httpchk,agent-check. Можно смотреть ответ (http-check expect). - Stick tables — хранилище per-IP/cookie для rate-limit, stickiness, abuse-detection.
- ACL — условная маршрутизация:
acl is_api path_beg /api→use_backend api_be if is_api. - Отличный stats endpoint (
stats uri /haproxy?stats), Prometheus exporter встроен.
Traefik
- Dynamic providers: Docker labels, Kubernetes Ingress/CRD (IngressRoute), Consul, File. Конфиг обновляется без рестартов.
- Middlewares: auth, headers, rate-limit, redirect, strip-prefix — цепочкой.
- Автоматический ACME/Let's Encrypt (TLS-ALPN, HTTP-01, DNS-01).
- Сильный UI (dashboard), хорошо в k8s для быстрой интеграции.
Kafka
- Topic делится на partitions. Порядок гарантирован только внутри partition.
- Replication factor: сколько реплик каждой partition (обычно 3). ISR (In-Sync Replicas) — те, что не отстают сверх
replica.lag.time.max.ms. - Producer:
acks=0/1/all(all = подтверждение от всех ISR, самая надёжная),retries,idempotent. - Consumer group: разбивка partitions между consumer-ами группы. Одна partition → один consumer в группе.
- Offset commit: auto (рискованно — потеря/дубли) vs manual (sync/async).
- Exactly-once: idempotent producer + transactions + read_committed на consumer-е.
- Kafka Connect — коннекторы (source/sink) для БД, S3, Elastic, без собственного кода.
- KRaft (Kafka Raft) — в 3.x заменяет ZooKeeper (метаданные внутри Kafka).
Redis
- Типы данных: String, List, Hash, Set, Sorted Set (ZSET), Stream, Bitmap, HyperLogLog, Geo, JSON (модуль).
- Persistence:
- RDB — snapshot на диск (fork + save). Компактно, быстрый restart, потеря последнего окна.
- AOF — append-only file всех записей. Надёжнее, большие файлы, rewrite периодически.
- Комбинация AOF+RDB (
aof-use-rdb-preamble yes) — snapshot + инкременты.
- Репликация master→replica (async). Sentinel — failover для одномастерной реплики.
- Cluster — шардирование на 16384 hash slots, multi-master.
- Eviction (
maxmemory-policy):noeviction,allkeys-lru,allkeys-lfu,volatile-ttl. - Кейсы: cache-aside, session store, pub/sub, rate limiter (INCR + EXPIRE), leaderboard (ZSET), distributed lock (
SET NX EX, Redlock-алгоритм).
Keycloak
- Realm — изолированная tenant-зона (свои юзеры, клиенты, роли).
- Client — приложение, которое интегрируется (confidential/public/bearer-only).
- Протоколы: OAuth2 (authorization_code, client_credentials, device_code), OIDC (расширение над OAuth2 с ID-token JWT), SAML.
- Federation — LDAP/AD/Kerberos.
- Brokering — вход через Google/GitHub/другой IdP.
- Fine-grained permissions: roles, groups, attributes, token-exchange, impersonation (с аудитом).
- HA: база (Postgres) +
infinispanраспределённый cache + shared cache stack; реплика без sticky session может терять session если cache не shared.
11. Безопасность и PCI-DSS
PCI-DSS — 12 требований (v4.0 — мнемоника)
- Установить и поддерживать сетевую защиту (firewall/NGFW, сегментация).
- Применять безопасные конфигурации (harden OS/Apps, не использовать vendor defaults).
- Защищать stored account data (шифрование, truncation, tokenization; CVV нельзя хранить после авторизации).
- Защищать CHD при передаче через публичные сети (TLS 1.2+, strong ciphers).
- Защищать системы от malware (AV/EDR).
- Разрабатывать и поддерживать secure software (SDLC, code review, SAST).
- Ограничить доступ к CHD по принципу need-to-know.
- Идентифицировать и аутентифицировать пользователей (MFA обязателен для админ-доступа и удалённого).
- Ограничить физический доступ к CHD.
- Логировать и мониторить доступ к сети и CHD (retention ≥ 1 год, 3 месяца «hot»).
- Регулярно тестировать безопасность (vuln scan, pentest, wireless scan).
- Поддерживать политику информационной безопасности (процессы, роли, обучение).
Сегментация и CDE
- CDE (Cardholder Data Environment) — сегмент, где обрабатываются/хранятся/передаются карточные данные.
- Сегментация снижает объём аудита (scope): всё вне CDE можно вывести из-под части требований, если firewall корректно изолирует.
- Jump host (bastion): единственная точка входа в CDE из admin-сегмента, с MFA, логированием, session recording.
- В k8s — отдельный кластер/namespace + NetworkPolicy default-deny + admission (Kyverno), можно усилить service mesh mTLS (Istio/Linkerd).
Шифрование
- At rest: LUKS (диск), dm-crypt, AWS EBS/KMS, pgcrypto/transparent data encryption.
- In motion: TLS 1.2/1.3, strong ciphers (Mozilla intermediate), HSTS.
- Key management: HSM (аппаратный security module), KMS (AWS/GCP/Azure), HashiCorp Vault (transit engine = crypto-as-a-service).
- Rotation: PCI — минимум ежегодно, при увольнении/компрометации — немедленно.
Identity / MFA
- Пароли: сложность, unique per account, password managers.
- MFA обязателен: TOTP (Google Authenticator/Authy), FIDO2/WebAuthn, SMS — не рекомендуется (SIM-swap).
- Least privilege: отдельные admin-аккаунты, just-in-time access (Teleport, Boundary, AWS IAM Identity Center).
Logging and monitoring
- Требуется хранить не менее 1 года; 3 месяца — быстрый доступ.
- Логируем: все доступы к CHD, admin-действия, изменения permissions, создание/удаление аккаунтов, access/init/stop audit-лога.
- Integrity: write-once хранилище, подписанные sinks (WORM S3 Object Lock).
- SIEM (Splunk/Elastic SIEM/Wazuh) для корреляции.
Vulnerability & patch management
- Внешние ASV-сканы (Approved Scanning Vendor) — ежеквартально.
- Внутренние — после «significant change».
- Инструменты: Nessus, Qualys, OpenVAS.
- SLA на патчи: critical — 30 дней, остальные — по risk matrix.
SAST / DAST / SCA
| Что анализирует | Инструменты | |
|---|---|---|
| SAST | Исходный код (white-box) | SonarQube, Semgrep, Checkmarx, Fortify |
| DAST | Работающее приложение (black-box) | OWASP ZAP, Burp Suite, Nikto |
| IAST | Инструментация runtime | Contrast, Checkmarx |
| SCA | Зависимости и их CVE | Snyk, Dependency-Track, Trivy (fs), OWASP Dep-Check |
| Secrets scanning | Утечки в git | gitleaks, trufflehog, GitLab Secret Detection |
Container security
- Минимальные базы, non-root, read-only root FS (
readOnlyRootFilesystem: true). - Подпись образов (cosign) и проверка в admission (Kyverno verifyImages).
- SBOM в pipeline + сравнение с CVE DB.
- Runtime security: Falco (syscall anomalies), Tracee, Sysdig Secure.
- Registry scanning: Trivy, Harbor встроенный сканер.
HashiCorp Vault
- KV secrets (v2 с versioning).
- Dynamic secrets: Vault генерит временного юзера БД/AWS при запросе — TTL, auto-revoke. Убийца static creds.
- Transit engine: crypto-as-a-service — приложение посылает данные, Vault возвращает шифртекст, ключи никогда не покидают Vault.
- Auth methods: AppRole, Kubernetes (SA token), JWT/OIDC, AWS IAM.
mTLS / Service Mesh
- mTLS — взаимная аутентификация сертификатами на обоих концах TLS. В микросервисах — must-have для zero-trust.
- Istio: богатый, sidecar Envoy, L7 политики, traffic mirroring, большая сложность.
- Linkerd: проще, легче, Rust-микропрокси. mTLS из коробки без конфиг-кошмара.
- Cilium Service Mesh (eBPF): без sidecar, одной нодой на каждом узле.
12. Scripting (Bash / Python)
Bash — каркас рабочего скрипта
#!/usr/bin/env bash
set -Eeuo pipefail
IFS=$'\n\t'
trap 'rc=$?; echo "ERR on line $LINENO: $BASH_COMMAND (rc=$rc)" >&2; exit $rc' ERR
trap 'tmp=${TMP:-}; [[ -n "$tmp" && -d "$tmp" ]] && rm -rf "$tmp"' EXIT
log() { printf '%(%F %T)T %s\n' -1 "$*" >&2; }
die() { log "FATAL: $*"; exit 1; }
usage() { cat <"$TMP/health"
jq -e '.status=="ok"' "$TMP/health" || die "unhealthy"
Гвозди, которые надо знать
set -e— exit на первой ошибке.-u— unset var = ошибка.-o pipefail— fail всего pipe при fail любого звена.-E— ERR trap наследуется в функции.- Разница:
[ ](test, POSIX),[[ ]](bash — regex, глоб, && || внутри),(( ))(арифметика, C-like). - Heredoc:
cat <<EOF(с подстановкой),<<'EOF'(буквально),<<-EOF(обрезка leading TAB). - Process substitution:
diff <(cmd1) <(cmd2). - Массивы:
arr=(a b c); echo "${arr[@]}",${#arr[@]}— длина,${arr[*]}— склеенная строка. - Trap:
trap 'cmd' EXIT ERR INT TERM. - Параллельность:
xargs -P N, GNUparallel,wait. - Не забываем
LC_ALL=Cдля стабильного лексикографического sort в скриптах.
Полезные one-liners
# Топ-10 IP в access.log
awk '{print $1}' access.log | sort | uniq -c | sort -rn | head
# Грохнуть старые файлы
find /var/log -type f -mtime +30 -name '*.log' -print0 | xargs -0 rm -f
# Считать 5xx в nginx за последний час
awk '$4 > "'"$(date -d '1 hour ago' +'[%d/%b/%Y:%H:%M:%S')"'"' access.log \
| awk '$9 ~ /^5/' | wc -l
# Массовые curl с лимитом параллелизма
xargs -a hosts.txt -P 10 -I {} curl -s -o /dev/null -w "{} %{http_code}\n" https://{}/health
# jq: вытащить поле и привести массив объектов к CSV
jq -r '.items[] | [.metadata.name, .status.phase] | @csv' pods.json
Python — когда переключаться
Если скрипт:
- > 100 строк ветвлений и data-structure manipulation — Python.
- Работает с JSON/YAML/XML глубоко — Python (bash+jq начинает душить).
- Требует хороших ошибок и тестов — Python.
- Работает с REST API, k8s API, БД, SSH-туннелями — Python.
Python — типовой стек
# venv + requirements
python3 -m venv .venv && source .venv/bin/activate
pip install requests pyyaml kubernetes psycopg2-binary paramiko
# HTTP
import requests
r = requests.get("https://api.example.com/v1/items",
headers={"Authorization": f"Bearer {token}"},
timeout=10)
r.raise_for_status()
data = r.json()
# K8s
from kubernetes import client, config
config.load_kube_config() # или load_incluster_config() внутри pod
v1 = client.CoreV1Api()
for p in v1.list_pod_for_all_namespaces(watch=False).items:
print(p.metadata.namespace, p.metadata.name, p.status.phase)
# SSH/паралелльно
import paramiko
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect("host", username="core", key_filename="~/.ssh/id_ed25519")
_, out, err = ssh.exec_command("uptime")
print(out.read().decode())
# Аргументы
import argparse
ap = argparse.ArgumentParser()
ap.add_argument("--host", required=True)
ap.add_argument("--dry-run", action="store_true")
args = ap.parse_args()
# Логирование
import logging
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s %(levelname)-7s %(name)s %(message)s",
)
log = logging.getLogger("deploy")
13. Сети и DNS
OSI / TCP/IP (кратко, но ТОЧНО)
| OSI | TCP/IP | Пример |
|---|---|---|
| 7 Application | Application | HTTP, DNS, SSH, SMTP |
| 6 Presentation | — | TLS (иногда уровень 5/6) |
| 5 Session | — | TLS handshake state |
| 4 Transport | Transport | TCP, UDP |
| 3 Network | Internet | IP, ICMP, routing |
| 2 Data Link | Link | Ethernet, ARP, VLAN, MAC |
| 1 Physical | Link | кабели, 802.11 |
Классика собеседования: «что происходит, когда ты вводишь https://x в браузере?» — DNS (recursive → authoritative) → TCP handshake (SYN, SYN-ACK, ACK) → TLS handshake (ClientHello + SNI → ServerHello + cert → key exchange → Finished) → HTTP-запрос → парсинг HTML → подгрузка ресурсов и т.д.
TCP — состояния и ловушки
- Handshake: SYN → SYN-ACK → ACK.
- 4-way teardown: FIN → ACK → FIN → ACK.
- TIME_WAIT: у инициатора закрытия, длится 2×MSL (≈60-120s). Защита от поздних пакетов и переиспользования портов. Сотни тысяч TIME_WAIT — симптом ephemeral-port exhaustion (настроить
net.ipv4.ip_local_port_range,tcp_tw_reuse, keep-alive). - CLOSE_WAIT: у того, кто получил FIN, но ещё не закрылся сам. Копящиеся CLOSE_WAIT — баг в приложении: не закрывает socket.
- Retransmit — потерянные пакеты → повторная передача с экспоненциальным backoff. Metric:
TcpExtRetransSegsв/proc/net/netstat. - Nagle's algorithm и TCP_NODELAY — аккуратно с latency-sensitive.
DNS
| Запись | Для чего |
|---|---|
| A / AAAA | IP v4 / v6 |
| CNAME | Алиас к другому имени (нельзя на apex зоны) |
| MX | Mail exchanger |
| TXT | Произвольный текст (SPF, DKIM, ACME-challenge) |
| SRV | Service record (порт + target), часто для XMPP, SIP, k8s |
| PTR | Обратная зона (IP → имя) |
| NS / SOA | Делегирование / метаданные зоны |
| CAA | Какие CA могут выдавать сертификаты на домен |
- Рекурсивный резолвер — ходит за клиента (8.8.8.8, 1.1.1.1, локальный).
- Авторитативный — отдаёт данные своей зоны.
- TTL — время кеширования. Перед миграцией за день-два снижают до 60s.
- Split-horizon — разные ответы внутренним vs внешним клиентам (одно имя — private IP внутри, public снаружи).
- DNSSEC — криптоподпись записей (RRSIG) + цепочка доверия до корня.
CoreDNS в Kubernetes
- Сервисы резолвятся как
<svc>.<ns>.svc.cluster.local. /etc/resolv.confв pod:search <ns>.svc.cluster.local svc.cluster.local cluster.local+options ndots:5.- Из-за
ndots:5запросapi.example.com(3 точки) сначала пройдёт через search-list → 4 запроса на NXDOMAIN + один успешный. Типовая причина «DNS лагает». - Решение: в приложении делать абсолютные имена с точкой в конце (
api.example.com.) или настроитьdnsConfig.options: ndots=2в поде.
HTTP/1.1 vs 2 vs 3
| HTTP/1.1 | HTTP/2 | HTTP/3 | |
|---|---|---|---|
| Транспорт | TCP + TLS | TCP + TLS (ALPN) | QUIC поверх UDP (встроен TLS 1.3) |
| Мультиплекс | Нет (pipelining провальный) | Да, streams в одном соединении | Да, без head-of-line блокировки TCP |
| Сжатие заголовков | Нет | HPACK | QPACK |
| Head-of-line | На соединение | На TCP-уровне (при потере пакета) | Нет (UDP streams) |
| Server push | Нет | Да (обесценено) | Нет (убран) |
Keep-alive: держим TCP/TLS соединение открытым для нескольких HTTP-запросов. В HTTP/2 это базовая модель.
Chunked encoding (HTTP/1.1): Transfer-Encoding: chunked — стримим ответ неизвестной длины (хекс-длина каждого чанка + CRLF + данные). В HTTP/2/3 — нативный framing.
TLS / сертификаты
- Handshake (TLS 1.2): ClientHello → ServerHello + Certificate + ServerKeyExchange → ClientKeyExchange → ChangeCipherSpec → Finished.
- TLS 1.3: один round-trip, 0-RTT опция; убраны RSA key exchange и слабые шифры.
- SNI (Server Name Indication) — клиент сообщает hostname в ClientHello → сервер выбирает cert для этого имени.
- Цепочка сертификатов: server cert → intermediate → root. Клиент должен получить полный
fullchainбез root (root в trust store). - Let's Encrypt / cert-manager: ACME HTTP-01 (
/.well-known/acme-challenge/) или DNS-01 (TXT в зоне). Обновление автоматом. - Диагностика:
openssl s_client -servername X -connect X:443,curl -v,testssl.sh, SSLLabs.
L4 vs L7 балансировка
| L4 (TCP/UDP) | L7 (HTTP/S) | |
|---|---|---|
| Видит | IP, порты | HTTP method, URL, headers, cookies |
| Производительность | Выше (меньше parsing) | Ниже, зато богаче роутинг |
| TLS | Обычно passthrough | Обычно terminate на LB |
| Примеры | HAProxy (tcp), AWS NLB, IPVS | nginx, Traefik, AWS ALB, Istio |
TLS termination: на LB — проще управлять сертификатами, есть возможность WAF/rate-limit. Passthrough — end-to-end шифрование нужно для PCI в CDE.
14. Highload, HA, масштабируемость
Вертикаль vs горизонталь
- Scale-up — больший инстанс. Предел железа, единая точка отказа, дёшево в начале.
- Scale-out — больше инстансов. Требует stateless/shared-state; лучше для отказоустойчивости.
Stateless дизайн
- Каждый запрос самодостаточный, любое состояние — во внешнем store (БД, Redis, S3).
- Sticky session — компромисс, когда нельзя сразу переписать.
- JWT для auth — stateless identity (есть нюансы revocation).
Кеширование (слои)
| Слой | Пример | Эффект |
|---|---|---|
| Client | Browser cache, Service Worker | 0 запросов на backend |
| CDN | Cloudflare, Fastly, Akamai | Разгрузка egress + TLS, edge close to user |
| Reverse proxy | Nginx proxy_cache, Varnish | Разгрузка backend |
| Application | Redis/Memcached | Дорогие вычисления и запросы |
| DB | shared_buffers, materialized views, result cache | Разгрузка IO |
Cache invalidation — одна из двух сложных вещей в CS. Паттерны: TTL, write-through, write-behind, cache-aside (lazy), read-through.
Очереди и async
- Kafka — distributed log, высокая пропускная способность, долгое хранение, replay.
- RabbitMQ — брокер с routing (direct/topic/fanout), DLX, priorities; меньше throughput, богаче семантика.
- NATS — очень быстрый, at-most-once (core) / at-least-once (JetStream).
- Зачем нужны: развязка сервисов (loose coupling), сглаживание нагрузки, retry с персистентностью, event sourcing.
CAP, PACELC
- CAP: при сетевом разделении (P) система может быть либо C (consistent, отказывать в записи), либо A (available, но с возможным split-brain).
- PACELC: если Partition — P vs C; Else (в норме) — L (latency) vs C.
- Примеры: Postgres/Spanner — CP (CAP), линеаризуемы; DynamoDB/Cassandra — AP; Redis — зависит от конфигурации.
- Eventual consistency: записи постепенно сходятся; устраивает для лент, счётчиков; плох для денег.
Репликация и шардинг
- Master-slave (primary-replica) — пишет один, читают многие. Риск: отставание, split-brain при failover.
- Multi-master: конфликты записей → нужен conflict resolution (Cassandra LWW, CRDT).
- Шардинг: hash (ровно), range (locality, hotspot risk), directory (lookup). Rebalance — боль.
Надёжность вызовов
- Rate limiting: токен-бакет / leaky bucket. Защита от перегруза и abuse.
- Circuit breaker: если upstream сыпется, не бить по нему (открыть цепь), пробовать иногда (half-open). Библиотеки: resilience4j, Hystrix (depr), Envoy outlier detection.
- Retry с backoff + jitter: иначе «thundering herd» после сбоя.
- Idempotency keys: клиент отправляет
Idempotency-Key: uuid, сервер дедуплицирует. Must-have в платежах. - Timeout-ы на всех уровнях: connect, read, total. Без них — каскадный отказ.
- Bulkhead: отдельные пулы ресурсов по сервисам/приоритетам, чтобы отказ одного не топил остальных.
Chaos engineering, graceful degradation
- Регулярные «game days» с инжекцией сбоев (Chaos Mesh, Litmus, Gremlin, AWS Fault Injection Simulator).
- Graceful degradation: при падении некритичного сервиса приложение работает в сокращённой функциональности (feature flag → «recommendations недоступны»).
- Feature flags (LaunchDarkly, Unleash, Flagsmith) — на A/B и аварийное выключение фич.
15. Incident management и SRE-практики
Ops vs DevOps vs SRE
- Ops
- Традиционная эксплуатация: разделение dev/ops, изменения через тикеты, ручные процедуры.
- DevOps
- Культура и практика: общая ответственность, автоматизация, CI/CD, «you build it, you run it».
- SRE
- Google-подход: инженерный взгляд на надёжность, SLI/SLO/error budget, toil reduction, post-mortem культура, «treat ops as a software problem».
On-call
- Ротации: primary/secondary, follow-the-sun (разные часовые пояса).
- Alert fatigue: убирать/тихо-хоронить алерты, которые не ведут к action. «Page-worthy» — только то, что требует немедленного вмешательства и что можно что-то сделать.
- Time-to-ack, escalation ladder, runbook-и обязательны.
Postmortem (blameless)
- Фокус на системе, не на людях. «What happened, why, what's next», без поиска виноватых.
- Структура: summary, impact (кто и как страдал), timeline (UTC, минута-в-минуту), root cause (5 whys), contributing factors, action items с owner/deadline, lessons learned.
- Action items должны быть конкретные и отслеживаемые до закрытия.
Метрики инцидентов
| Метрика | Что меряет |
|---|---|
| MTTD (Mean Time To Detect) | От появления до обнаружения |
| MTTA (Mean Time To Acknowledge) | От алерта до ack-а on-call-ом |
| MTTR (Mean Time To Restore/Repair/Recover) | От начала до восстановления |
| MTBF (Mean Time Between Failures) | Среднее между инцидентами |
Runbooks vs Playbooks
- Runbook — пошаговая инструкция «если алерт X — сделать 1-2-3». Ссылка прямо в alert annotation.
- Playbook — более общий сценарий (деплой, failover, DR).
- Цель — довести до автоматизации: сначала runbook → потом auto-remediation (кто-то должен реально это жать, пока не поймут, что безопасно).
Работа на инциденте — роли
- IC (Incident Commander) — координирует, принимает решения.
- Ops / Subject matter — фиксят.
- Comms — общается с наружным миром (status page, клиенты).
- Scribe — ведёт таймлайн, позже отдаст на postmortem.
Расскажи про самый сложный инцидент — шаблон ответа
- Контекст: что за продукт, масштаб, моя роль.
- Симптомы: что заметил, какие метрики/алерты.
- Первые гипотезы и как их проверил (методично отбрасывая, не «залочились» на одной).
- Что оказалось root cause — и чего не хватало, чтобы это увидеть раньше.
- Фикс: короткий (останавливает пожар) + долгий (устраняет класс проблемы).
- Уроки и действия (мониторинг, runbook, тест, архитектурное решение).
16. Живые кейсы — сценарные вопросы
kubectl describe pod— events (ImagePullBackOff? OOMKilled? FailedScheduling?). Last State / Reason / Exit code.kubectl logs --previous— логи предыдущего запуска.- Проверить probes — не бьёт ли liveness раньше, чем приложение успело стартовать (→ добавить startupProbe или поднять initialDelaySeconds).
- Entrypoint/args — совпадают ли с ожидаемым.
kubectl execв sleep-image с тем же образом, посмотреть файлы. - Ресурсы:
describe pod→ requests/limits;kubectl top pod; частое OOM — поднять memory limit или поправить heap. - Сеть/зависимости: не может достучаться до БД/Vault? NetworkPolicy? DNS?
kubectl exec ... -- nslookup mysql. - ConfigMap/Secret: правильно ли смонтированы?
kubectl exec ... -- env | grep.
- Смотрим на слой Ingress/LB: метрики по status (5xx rate), апстримы (какой именно сервис).
- Grafana — RED-дашборд сервиса: rate/errors/duration; сравнение per-pod (может быть «больной» pod).
- Логи (Kibana/Loki) по
trace_idили timestamp-корреляции. - Traces (Jaeger/Tempo): путь запроса → какой хоп кидает error. Часто это таймаут на удалённый сервис/БД.
- Сама БД: long-running queries, locks, replication lag.
- Событийное: проверяем — был ли деплой в это время (rollout revision), autoscaling, eviction нодом, network policy change.
- Если подозрение на один pod —
kubectl delete pod(scheduler пересоздаст); воспроизводится ли.
- Ресурсы хоста: CPU/IO-wait/диск (iostat,
df— не кончилось ли место → switch в read-only), memory pressure. pg_stat_activity: сколько активных коннектов, есть ли «idle in transaction», долгие queries.pg_stat_statements: топ по total_time / mean_time / calls — новичок ли в топе, изменилось ли что-то.- Плейны:
EXPLAIN (ANALYZE, BUFFERS)подозрительного запроса; rows estimate vs actual; seq scan на большой таблице. - VACUUM:
pg_stat_user_tables— когда последний раз vacuum/analyze, dead_tup, n_live_tup. - Blocking:
pg_blocking_pids(), long transactions. - Replication lag (
pg_stat_replication). - Внешние изменения: деплой приложения (новые запросы?), обновление версии, auto-tuning параметров, smaller instance.
- Совместимость API: новая версия должна принимать запросы/данные от старой и наоборот (expand-contract для БД-миграций — сначала добавили колонку nullable, задеплоили писателей, потом бекфилл, потом NOT NULL).
- Strategy: rolling (дешевле) или canary (безопаснее). В k8s: Deployment strategy,
maxSurge/maxUnavailable; Argo Rollouts / Flagger для canary с автометриками. - PDB — гарант «не менее N реплик».
- Readiness probe — чтобы не пустить трафик на not-ready pod. PreStop hook +
terminationGracePeriodSeconds— корректно завершать активные запросы. - Запас мощности:
HPAне «жмёт», пулы до БД/Redis выдерживают. - Мониторинг во время релиза: error rate / latency / saturation на обеих версиях. Автосгон canary при деградации (Flagger metrics-check).
- Процедура rollback заранее протестирована.
- Выходит ли приложение в stdout/stderr (12-factor) или в файл? Если в файл — собирает ли его агент (маунт, путь)?
- На ноде:
docker logs/crictl logsподтверждают, что runtime видит логи. - На collector'е (Fluent Bit/Filebeat DaemonSet):
kubectl logs— есть ли ошибки (not authorized to ES, backpressure, parse error). - Logstash/ingest pipeline: не дропает ли события grok-ом/условием.
- Elasticsearch: cluster health (
/_cluster/health), disk watermark (read-only при high watermark!), права роли, ILM не переместил ли индекс в cold/frozen без UI-дефолта. - Kibana: data view / index pattern совпадает с реальным именем индекса; выбран правильный timestamp field; time range корректный.
- Network: TLS-ошибки, firewall, k8s NetworkPolicy.
- Определить SLO — что значит «работает» с точки зрения клиента: availability, latency p95/p99, error rate. Пороги.
- RED метрики (rate/errors/duration) на HTTP-интерфейсе — стандартные Prometheus-дашборды.
- USE на ресурсах: CPU (node/container), memory, сеть, диск.
- Бизнес-метрики — что-то доменное (payments_succeeded_total, orders_in_queue).
- Логи в JSON с trace_id, уровнями, PII-маскированием; отгрузка в EFK/Loki.
- Tracing через OpenTelemetry — instrument HTTP-клиент и серверы, пропагируем traceparent.
- Health endpoints:
/livez(только сам процесс),/readyz(зависимости); k8s probes. - Алерты только на SLO-burning и жёсткие инфраструктурные события. Линки на runbook, owner, severity.
- Дашборд для сервиса (Grafana): RED, USE, SLO/error budget burn rate, deploy markers.
- Game day / load test — проверить, что метрики реально отражают проблему.
Поведенческое — что часто спрашивают
- Расскажи о сложной миграции / крупном инфраструктурном изменении.
- Конфликт с разработчиком/командой — как разрулил.
- Как учишься новому (курсы, книги, play-projects)?
- Какая твоя самая «любимая» неудача?
- Как принимаешь решение «fix vs rewrite»?
Что спросить у интервьюера (сигнал зрелости команды)
- Как устроен on-call, сколько page-ов в неделю?
- Есть ли формальные SLO и error budget?
- Процесс post-mortem — blameless? публикуются?
- Как идёт обновление кластеров / OS / БД — график и кто делает?
- Что за toil съедает основное время DevOps-команды сейчас, и план по его сокращению?
- Как устроен onboarding — документация, shadow-on-call, mentor?
Сгенерировано как подготовка к собеседованию на вакансию DevOps. Обновляй/правь прямо в /srv/cheatsheet/index.html — nginx отдаёт файл на лету, без перезапусков.