Гайд, который можно открыть перед техническим собеседованием
Ядро работает в привилегированном режиме и управляет железом. Пользовательские программы работают в ограниченном режиме и обращаются к ядру через системные вызовы. Если программа падает, обычно падает только она, а не вся система. Если же падает ядро, это kernel panic.
Практическое значение: когда вы видите, что процесс «висит», важно понять, где он застрял, в коде приложения или в вызове ядра. Это делается через strace или состояние процесса в ps.
Так работает запуск команд в shell: сначала fork, затем exec.
| Код | Состояние | Что значит |
|---|---|---|
| R | Running / Runnable | Выполняется или ждёт процессора |
| S | Sleeping (interruptible) | Ждёт события, например ответа сети. Обычное состояние |
| D | Uninterruptible sleep | Ждёт ввода-вывода, прервать нельзя. Частая причина высокого load average |
| T | Stopped | Остановлен сигналом, например Ctrl+Z |
| Z | Zombie | Завершился, но родитель не забрал его статус через wait() |
Load average показывает среднюю длину очереди задач за 1, 5 и 15 минут. В очередь попадают процессы в состоянии R и D.
nproc). Load 4 на 4 ядрах — система загружена полностью, load 8 — перегружена.iostat -x 1 или vmstat 1.uptime # load average
nproc # количество ядер
vmstat 1 5 # поле wa — ожидание I/O, поле r — очередь
iostat -x 1 # загрузка дисков
top — интерактивный монитор процессов. Важные поля:
Горячие клавиши: 1 — показать каждое ядро, M — сортировка по памяти, P — по CPU, k — убить процесс.
htop (удобнее) или btop. На проде для быстрой картины подойдёт top -bn1 | head -20.Linux использует свободную память под кэш и буферы. Это нормально: память, которая не нужна приложениям, заполняется кэшем диска. Поэтому:
free -h
# колонка available — главное число
Когда памяти не хватает, ядро вызывает OOM killer и убивает процесс с наибольшим «весом». Код выхода 137 = 128 + 9 (SIGKILL). В контейнерах это частая история: процесс упёрся в memory limit.
dmesg -T | grep -i "killed process"
journalctl -k | grep -i oom
Классическая ситуация: процесс открыл лог-файл, его удалили, но процесс продолжает писать в него. Место не освобождается, пока процесс не закрыл файл.
df -h # общий объём и заполненность
du -xh / --max-depth=1 | sort -h | tail # крупнейшие каталоги
lsof +L1 # удалённые, но открытые файлы
Решение: перезапустить процесс или очистить лог через truncate -s 0 файл, если он ещё нужен.
df -i. Тогда много мелких файлов, например в каталоге сессий или кэша.kill.Zombie — это процесс, который завершился, но его родитель не вызвал wait() и не забрал код возврата. Сам зомби не занимает CPU и память, но занимает запись в таблице процессов.
Избавиться можно, исправив родительский процесс или перезапустив его. Убить зомби через kill нельзя, он уже мёртв.
Права делятся на три группы: владелец, группа, остальные. Каждая группа имеет r (4), w (2) и x (1).
chmod 755 file — владелец rwx, группа и остальные rx;chmod 600 key.pem — только владелец читает и пишет (так и должны храниться ключи);chown user:group file — смена владельца.Для каталогов x означает право войти в каталог.
Inode хранит метаданные файла: владельца, права, размер, адреса блоков на диске. Имя файла — это просто ссылка на inode, которая лежит в каталоге. Поэтому одно и то же содержимое может иметь несколько имён (hard link).
Hard link и symbolic link: hard link указывает на тот же inode, symlink — на путь. Если удалить исходный файл, symlink станет битым.
ss -tulpn # современная замена netstat
# -t tcp, -u udp, -l слушающие, -p процесс, -n без DNS
Команда lsof -i :80 показывает то же самое для конкретного порта.
systemctl status nginx # состояние и последние строки лога
systemctl restart nginx
systemctl enable nginx # автозапуск
journalctl -u nginx -f # логи сервиса в реальном времени
journalctl -u nginx --since "1 hour ago"
Cron запускает задачи с минимальным окружением: без вашего PATH, без профиля shell. Поэтому команда, которая работает в терминале, в cron может «не найтись». Решение: указывать полные пути (/usr/bin/python3) или явно задавать PATH в crontab.
Каждый открытый файл, сокет или канал получает числовой дескриптор. У процесса есть лимит (ulimit -n). Если приложение не закрывает соединения, лимит быстро заканчивается.
ulimit -n # текущий лимит
ls /proc/PID/fd | wc -l # сколько дескрипторов использует процесс
Этот ответ хорош тем, что показывает весь путь. Интервьюер часто задаёт этот вопрос, чтобы понять ширину знаний.
| TCP | UDP | |
|---|---|---|
| Соединение | Устанавливается (handshake) | Нет |
| Надёжность | Гарантирует доставку и порядок | Нет гарантий |
| Скорость | Ниже из-за контроля | Выше, меньше накладных расходов |
| Примеры | HTTP, SSH, базы данных | DNS, видеозвонки, метрики (StatsD) |
DNS превращает имена в IP. Типы записей: A (IPv4), AAAA (IPv6), CNAME (алиас), MX (почта), TXT (проверки, SPF), NS (серверы зоны).
dig example.com A +short
dig @8.8.8.8 example.com # спросить конкретный DNS
nslookup example.com
cat /etc/resolv.conf # какой резолвер используется
В Kubernetes имена сервисов резолвятся через CoreDNS: service.namespace.svc.cluster.local.
Число после слеша — это количество бит, отведённых под сеть. /24 даёт 256 адресов, из них 254 пригодны для хостов (первый адрес — сеть, последний — broadcast).
| Маска | Адресов |
|---|---|
| /24 | 256 |
| /16 | 65 536 |
| /28 | 16 |
Частые ошибки: перекрывающиеся подсети при VPN и в Kubernetes, неправильная маска на маршрутизаторе.
Для DevOps важно: 502 и 504 на балансировщике часто означают, что приложение упало или медленно отвечает. Сначала проверяйте поды или процесс за балансировщиком.
ping — есть ли связь по IP вообще (учтите, что ICMP может быть закрыт).dig или nslookup — резолвится ли имя.nc -vz host 443 или curl -v — открыт ли порт и отвечает ли сервис.traceroute / mtr — где теряются пакеты или растёт задержка.ss -tanp — состояния соединений на своей стороне.tcpdump -i any port 443 — что реально уходит в сеть.iptables -L -n, security group в облаке.После закрытия TCP-соединения сторона, которая закрыла первой, держит сокет в состоянии TIME_WAIT около минуты. Это нужно, чтобы поздние пакеты не попали в новое соединение. Много TIME_WAIT — нормально для сервера с короткими HTTP-запросами. Опасно, когда исчерпываются порты.
ss -s # сводка по состояниям сокетов
Канал 1 Гбит/с с пингом 200 мс может иметь высокую пропускную способность, но медленный отклик на каждый запрос. Для API важнее latency, для бэкапов — throughput.
iptables и nftables — инструменты фильтрации и NAT в ядре. nftables — современный преемник с единым синтаксисом. Kubernetes через kube-proxy создаёт правила, чтобы перенаправлять трафик на сервисы и поды. Поэтому проблемы сервисов часто лежат в правилах NAT.
Режимы reset: --soft оставляет изменения в индексе, --mixed (по умолчанию) — в рабочей копии, --hard удаляет их.
fetch только скачивает изменения и обновляет удалённые ссылки (origin/main). pull = fetch + merge (или rebase). Привычка делать fetch, смотреть, и только потом merge, помогает не получить неожиданный конфликт.
HEAD указывает не на ветку, а прямо на коммит. Так бывает после git checkout коммит. Новые коммиты останутся «висящими» и потеряются при переключении. Чтобы не потерять работу, создайте ветку: git switch -c новая-ветка.
Stash временно прячет незакоммиченные изменения, чтобы переключиться на другую задачу. git stash сохраняет, git stash pop возвращает, git stash list показывает список.
git bisect start
git bisect bad # текущий коммит сломан
git bisect good v1.2.0 # последний рабочий
# Git предложит коммиты, вы отмечаете good или bad, пока не найдёт виновника
git bisect reset
Для автоматического поиска можно передать скрипт: git bisect run ./test.sh.
Reflog записывает все перемещения HEAD локально. Если вы случайно сделали reset --hard, коммит можно вернуть через reflog. Это страховка, а не замена нормальной работы с ветками.
git reflog
git reset --hard HEAD@{2}
.gitignore указывает, какие файлы не отслеживать. Но если секрет уже попал в коммит, удаление файла в новом коммите его не спрячет: он остаётся в истории.
Образ — неизменяемый шаблон, набор слоёв с файлами и метаданными. Контейнер — запущенный экземпляр образа с собственным слоем для записи. Из одного образа можно запустить много контейнеров.
Аналогия: образ — это класс, контейнер — объект.
Каждая инструкция Dockerfile создаёт слой. Docker кэширует слои: если слой не изменился, он берётся из кэша. Поэтому частые изменения (код) ставят в конец, а редкие (установка зависимостей) — в начало.
# Плохо: любое изменение кода пересобирает pip install
COPY . /app
RUN pip install -r requirements.txt
# Лучше: зависимости кэшируются отдельно
COPY requirements.txt /app/
RUN pip install -r /app/requirements.txt
COPY . /app
Если указаны оба, CMD становится аргументами для ENTRYPOINT. Типичный приём: ENTRYPOINT ["python"], CMD ["app.py"].
Данные в контейнере без volume пропадают при удалении контейнера.
Контейнер живёт, пока работает его главный процесс (PID 1). Если процесс завершился, контейнер останавливается. Частые причины:
docker logs CONTAINER # причина обычно здесь
docker run -it IMAGE sh # зайти и проверить вручную
Сборка в одном образе с компилятором и инструментами раздувает размер. Multi-stage: первый этап собирает приложение, второй копирует только готовый результат в лёгкий базовый образ. Итоговый образ меньше и безопаснее, потому что в нём нет компиляторов.
latest не означает «последняя стабильная версия», это просто тег по умолчанию. Образ под этим тегом может измениться, и вы получите разные версии на разных серверах. Используйте конкретные версии (nginx:1.27.2), а лучше digest (@sha256:...).
Контейнер — это не виртуальная машина, а обычный процесс Linux, изолированный двумя механизмами:
Поэтому контейнер быстрый и легковесный, но ядро у него общее с хостом.
Под — минимальная единица развёртывания. В нём один или несколько контейнеров, которые делят сеть (один IP) и могут делить тома. Контейнеры внутри пода видят друг друга через localhost. Поды эфемерны: их можно пересоздать, и у них меняется IP.
| Ресурс | Для чего |
|---|---|
| ReplicaSet | Поддерживает нужное число одинаковых подов. Обычно не создают напрямую |
| Deployment | Stateless-приложения: обновления, откаты, управление ReplicaSet |
| StatefulSet | Stateful-приложения: стабильные имена подов и своё хранилище на каждый |
| DaemonSet | По одному поду на каждом узле: агенты логов, мониторинга |
| Job | Задача, которая выполняется до успешного завершения |
| CronJob | Job по расписанию |
Для HTTP часто удобнее один Ingress вместо множества LoadBalancer.
Service — это внутренняя точка доступа к подам с балансировкой. Ingress — правила маршрутизации HTTP/HTTPS снаружи: по доменам и путям, с TLS. Для работы Ingress нужен контроллер (nginx ingress, Traefik и другие).
QoS-классы: Guaranteed (requests = limits), Burstable (что-то задано), BestEffort (ничего не задано). При нехватке ресурсов первыми убиваются BestEffort.
kubectl describe pod POD_NAME # раздел Events
kubectl get events --sort-by=.lastTimestamp
Частые причины: не хватает CPU или памяти на узлах для requests, не подходит nodeSelector или affinity, taint без toleration, PVC не привязан к тому.
Контейнер падает, Kubernetes его перезапускает с растущей паузой. Смотрим:
kubectl logs POD_NAME --previous # логи упавшего контейнера
kubectl describe pod POD_NAME # код выхода, OOMKilled, probe failures
ConfigMap хранит несекретную конфигурацию. Secret — для паролей и ключей. Но по умолчанию Secret хранится в etcd в base64, а это кодирование, а не шифрование. Чтобы защитить, включайте шифрование at rest в etcd, ограничивайте RBAC и используйте внешние хранилища секретов (Vault, External Secrets).
Deployment заменяет поды постепенно. Два параметра:
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0 # без простоя
kubectl rollout status deployment/app
kubectl rollout undo deployment/app
RBAC определяет, кто и что может делать: Role и ClusterRole задают права, RoleBinding и ClusterRoleBinding назначают их пользователям или ServiceAccount. Главное правило: принцип минимальных прав. Не давайте cluster-admin приложениям, а ServiceAccount по умолчанию не должен иметь лишних прав.
kubectl auth can-i list pods --as=system:serviceaccount:app:default
Horizontal Pod Autoscaler меняет число реплик по метрикам, обычно CPU. Частые причины, почему он не работает: не заданы requests (без них нельзя посчитать процент), не установлен metrics-server, метрика стабильно ниже порога.
kubectl get hpa
kubectl top pods
Это отличный вопрос, потому что по нему видно, понимает ли кандидат архитектуру, а не только команды.
Если пересобирать образ под каждое окружение, в staging и production окажутся немного разные сборки, и баг, найденный в тестах, может не воспроизвестись в продакшне. Правильно: собрать один раз, пометить версией или digest, и продвигать этот же артефакт по окружениям.
Описание пайплайна хранится в репозитории вместе с кодом: Jenkinsfile, .gitlab-ci.yml, workflow в GitHub Actions. Изменения проходят ревью, история видна в git, и пайплайн воспроизводим. Пайплайн, настроенный кликами в интерфейсе, сложно аудировать и восстановить.
kubectl rollout undo, переключение Blue/Green, деплой прошлого тега).Ключевой принцип: сначала восстановить сервис, потом искать виноватого. Если откат невозможен, нужен план миграции назад, например для схемы базы.
Флаг позволяет включать или выключать функцию без нового деплоя. Код с новой функцией можно выкатить в продакшн, а показывать пользователям постепенно или только тестовой группе. Это снижает риск релиза.
Типичная связка: Terraform поднимает серверы, Ansible их настраивает.
Операция идемпотентна, если многократный запуск даёт тот же результат, что и однократный. В Ansible модули проверяют текущее состояние и меняют только то, что отличается. Так можно безопасно перезапускать плейбук после сбоя.
State хранит соответствие между описанием в коде и реальными ресурсами. Без него Terraform не знает, что уже создано, и может создать дубликаты или удалить лишнее. Хранить его нужно удалённо, с блокировкой (например, S3 с DynamoDB или Terraform Cloud), потому что два одновременных apply испортят состояние.
Drift — расхождение между кодом и реальной инфраструктурой, например если кто-то поменял правило файрвола вручную. Обнаруживается через terraform plan: план покажет, что Terraform хочет вернуть к описанию. Регулярные plan в CI помогают ловить дрейф рано.
plan ничего не меняет, показывает, что будет создано, изменено и удалено. apply выполняет план. Хорошая практика: сохранять план в файл (terraform plan -out=tfplan) и применять именно его, чтобы между проверкой и применением ничего не поменялось.
count создаёт ресурсы по индексу: удаление элемента из середины сдвигает остальные и приводит к пересозданию. for_each использует ключи, поэтому удаление одного элемента не трогает остальные. Для большинства случаев предпочтительнее for_each.
Ansible Vault шифрует файлы с переменными. Пароль от vault передаётся через --ask-vault-pass или файл, который не должен попадать в git. Для параметров задачи с секретами используется no_log: true.
Мониторинг отвечает на заранее известные вопросы: «жив ли сервис», «не превышен ли порог». Наблюдаемость позволяет задавать новые вопросы о системе, которые не предусмотрели заранее, опираясь на метрики, логи и трассировки.
Prometheus сам опрашивает (pull) HTTP-эндпоинты приложений и сохраняет метрики во временной базе. Плюсы: контроль частоты опроса, легко понять, что цель недоступна (метрика up = 0). Для коротких задач есть Pushgateway.
rate(http_requests_total[5m])
histogram_quantile(0.95, sum(rate(http_request_duration_seconds_bucket[5m])) by (le))
RED смотрит на опыт пользователя, USE — на состояние железа и ресурсов.
Логи, трассировки, сертификаты, TOTP и Kerberos зависят от времени. Если часы расходятся, по логам невозможно восстановить порядок событий, а TLS может отказаться работать. Используйте NTP или chrony и проверяйте timedatectl.
Toil — ручная, повторяющаяся, не приносящая долгосрочной пользы работа, которая растёт вместе с сервисом. Например, ручной перезапуск упавшего сервиса каждую ночь. Бороться: автоматизировать, устранять первопричину, ограничивать долю времени на toil (часто ориентир до половины времени SRE).
Для современных сервисов ключевой метрикой чаще называют MTTR: как быстро возвращаемся в норму.
Разбор инцидента без поиска виноватого. Фокус на системе: почему процесс позволил ошибке случиться и почему её не поймали раньше. Структура: краткое описание, таймлайн, влияние, корневая причина, что сработало хорошо, action items с владельцами и сроками.
Canary-анализ сравнивает метрики новой и старой версии на небольшом трафике и решает, продолжать ли выкат. SLO-based alerting поднимает тревогу, когда скорость расходования error budget слишком высока, а не на каждую ошибку. Это уменьшает шум и привязывает алерты к влиянию на пользователей.
Shift left — переносить проверки безопасности раньше в цикл разработки: в IDE, в pull request, в сборку. DevSecOps — безопасность как часть общего процесса, а не отдельный этап в конце, который всех тормозит.
USER;Каждому пользователю, сервису и процессу даётся только минимально необходимый набор прав. На практике: отдельные сервисные аккаунты для каждого приложения, RBAC в Kubernetes без cluster-admin, IAM-роли с узкими политиками в облаке, запрет root в контейнерах.
Атаки на цепочку поставок: злоумышленник подменяет зависимость или сборку. Защита: фиксировать версии, проверять хеши и подписи, вести SBOM (Software Bill of Materials), то есть список всех компонентов. SBOM помогает быстро понять, затронуты ли вы новой уязвимостью.
Очередь ожидания велика, но процессы не считают CPU, а ждут. Скорее всего, это состояние D — ожидание диска или сети в ядре. Проверяем vmstat 1 (поле wa и b), iostat -x 1, ps -eo stat,pid,cmd | grep '^D'. Вероятные причины: медленный или перегруженный диск, зависшая NFS-монтировка.
Идём по ресурсам: CPU (top, загрузка на ядро), память (нет ли свопа и OOM), диск (iostat, await), сеть (ss, retransmits), зависимости (базы, внешние API по трассировкам). Важно сравнивать с базовой линией: что изменилось, когда началась проблема? Часто виноват последний деплой или рост данных.
kill по умолчанию шлёт SIGTERM, процесс может завершиться корректно. kill -9 шлёт SIGKILL, его нельзя перехватить. docker stop шлёт SIGTERM главному процессу контейнера и через 10 секунд SIGKILL. Поэтому приложение в контейнере должно обрабатывать SIGTERM, иначе оно не сможет завершиться корректно.
Если процесс запущен через shell-форму CMD, главным процессом становится shell, который не передаёт сигналы дочернему. Решение: использовать exec-форму CMD ["python", "app.py"] или init-процесс (docker run --init). Также процесс должен явно обрабатывать SIGTERM.
Pod Running не означает, что приложение готово. Проверьте readiness, endpoints сервиса (kubectl get endpoints), соответствие портов в Service и containerPort, а также таймауты между ingress и приложением. Ещё частая причина: приложение слушает 127.0.0.1 вместо 0.0.0.0.
Если ConfigMap смонтирован как переменные окружения, при изменении он не обновится в работающем поде: переменные задаются при старте. Для томов ConfigMap обновляется со временем, но приложение должно перечитать файл. Практичное решение: менять имя ConfigMap или добавлять хеш в аннотацию пода, чтобы Deployment перезапустил поды.
Варианты: индекс не используется из-за функции над колонкой, например WHERE lower(email) = ..., неправильный тип данных с неявным приведением, устаревшая статистика, выросшая таблица, блокировки от долгих транзакций. Смотрите EXPLAIN ANALYZE и журнал медленных запросов.
ss -tulpn | grep :8080
lsof -i :8080
Если процесс — от прошлого запуска, его можно остановить. Частая причина в Docker: контейнер с тем же портом уже запущен, или docker-proxy держит порт.
Возможные объяснения: кэш ядра (смотрите available, а не free), утечка памяти в ядре или в слабом месте (slab, /proc/meminfo), tmpfs, который занимает память (df -h /dev/shm /tmp), или много процессов, каждый из которых учитывается по RSS. Используйте smem или ps aux --sort=-rss.
Контейнеры используют часы хоста. Синхронизировать нужно хост, а не контейнер. В Kubernetes это делает узел. Проверка: timedatectl status на хосте и chronyc sources.
Маленькие релизы безопаснее: меньше изменений, проще найти причину, проще откатить. Это основа практики CD. Но у каждого релиза есть накладные расходы, поэтому цель — автоматизировать процесс, а не просто делать редкие большие релизы.
Используйте структуру STAR: Situation (контекст), Task (ваша задача), Action (что сделали именно вы), Result (итог и что изменили потом). Особенно важен последний пункт: что сделали, чтобы такое не повторилось. Говорите «мы» для команды, но показывайте свою конкретную роль.
Оцениваю влияние на пользователей и бизнес, срочность и стоимость. Инциденты и риски безопасности — выше плановых задач. Важно проговорить компромиссы с руководителем и не молчать, если сроки нереальны.
Говорю языком последствий: что сломано, кто затронут, сколько стоит простой, что делаем и когда станет лучше. Без жаргона, с цифрами. Например: «Сайт недоступен 10% пользователей, исправление займёт 2 часа, риск потери заказов — оценка такая-то».
Ищу общую цель: надёжный и быстрый релиз. Стараюсь автоматизировать спорное, например проверки в пайплайне, чтобы не быть «полицией». Объясняю причины через риски, а не через запреты, и готов обсуждать исключения с понятными условиями.
Честно говорю, что не знаю точно, рассуждаю вслух, что бы проверил, и показываю, как бы нашёл ответ. Интервьюеры ценят честность и методичность больше, чем попытку угадать.
Подготовьте ответ заранее: изучите продукт, стек, публичные статьи о технологиях компании. Связывайте свой опыт с задачами, которые они решают. Общие фразы вроде «хочу расти» звучат слабо.