Initial commit: interview prep repo (resume, legend, stack cases, Kubernetes course)
This commit is contained in:
146
stack/linux-bash/CASE.md
Normal file
146
stack/linux-bash/CASE.md
Normal file
@@ -0,0 +1,146 @@
|
||||
# Кейс: Linux (Astra/CentOS) и Bash — диагностика и внутренности
|
||||
|
||||
Связь с легендой: [../../legend/LEGEND.md](../../legend/LEGEND.md) — Astra Linux (АО ТНИИС) как базовая ОС серверного парка, CentOS (ОКБ СУХОЙ) как ОС тестовых стендов, Bash — повседневная автоматизация в обеих ролях.
|
||||
|
||||
## Что нужно реально сделать
|
||||
|
||||
Практикум на Linux-контейнере/WSL: живые bash-скрипты для обслуживания и прогон диагностических сценариев, которые реально спрашивали на собеседованиях («сервер тормозит — с чего начнёшь», «упал сервер — что делать»).
|
||||
|
||||
### 1. Реальные bash-скрипты для обслуживания
|
||||
|
||||
**Ротация и архивация логов:**
|
||||
```bash
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
LOG_DIR="/var/log/myapp"
|
||||
ARCHIVE_DIR="/var/log/myapp/archive"
|
||||
DAYS_TO_KEEP=7
|
||||
|
||||
mkdir -p "$ARCHIVE_DIR"
|
||||
find "$LOG_DIR" -maxdepth 1 -name "*.log" -mtime +1 -exec gzip {} \;
|
||||
find "$LOG_DIR" -maxdepth 1 -name "*.log.gz" -exec mv {} "$ARCHIVE_DIR" \;
|
||||
find "$ARCHIVE_DIR" -name "*.log.gz" -mtime +"$DAYS_TO_KEEP" -delete
|
||||
```
|
||||
|
||||
**Проверка места на диске с алертом в лог:**
|
||||
```bash
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
THRESHOLD=85
|
||||
USAGE=$(df -h / | awk 'NR==2 {gsub("%","",$5); print $5}')
|
||||
|
||||
if [ "$USAGE" -ge "$THRESHOLD" ]; then
|
||||
echo "$(date '+%Y-%m-%d %H:%M:%S') WARNING: disk usage ${USAGE}% >= ${THRESHOLD}%" >> /var/log/disk-check.log
|
||||
exit 1
|
||||
fi
|
||||
```
|
||||
|
||||
**Обвязка перезапуска стенда из [../monitoring/CASE.md](../monitoring/CASE.md):**
|
||||
```bash
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
cd "$(dirname "$0")"
|
||||
docker compose down
|
||||
docker compose up -d
|
||||
sleep 5
|
||||
docker compose ps --filter "status=running" | grep -q prometheus || {
|
||||
echo "prometheus не поднялся" >&2
|
||||
exit 1
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Systemd: unit-файл + таймер вместо cron
|
||||
|
||||
```ini
|
||||
# /etc/systemd/system/disk-check.service
|
||||
[Unit]
|
||||
Description=Проверка места на диске
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
ExecStart=/usr/local/bin/disk-check.sh
|
||||
```
|
||||
|
||||
```ini
|
||||
# /etc/systemd/system/disk-check.timer
|
||||
[Unit]
|
||||
Description=Запуск disk-check каждые 15 минут
|
||||
|
||||
[Timer]
|
||||
OnBootSec=5min
|
||||
OnUnitActiveSec=15min
|
||||
|
||||
[Install]
|
||||
WantedBy=timers.target
|
||||
```
|
||||
|
||||
```bash
|
||||
systemctl daemon-reload
|
||||
systemctl enable --now disk-check.timer
|
||||
systemctl list-timers | grep disk-check
|
||||
journalctl -u disk-check.service
|
||||
```
|
||||
|
||||
### 3. Диагностический сценарий «сервер тормозит — первые 3–5 команд»
|
||||
|
||||
Порядок, который реально прогонял на своих стендах:
|
||||
|
||||
1. `uptime` — load average за 1/5/15 минут, первое ощущение масштаба проблемы.
|
||||
2. `top` (или `htop`) — какой процесс ест CPU/память прямо сейчас.
|
||||
3. `free -h` — сколько реально свободной памяти (`available`, а не `free`, см. QUESTIONS.md).
|
||||
4. `df -h` — не закончилось ли место на диске (частая причина зависаний записи).
|
||||
5. `iostat -x 1` / `vmstat 1` — I/O-нагрузка на диск, если `top` не показал явного виновника по CPU.
|
||||
|
||||
### 4. Диагностический сценарий «df показывает, что место закончилось, а du — что всё в порядке»
|
||||
|
||||
Воспроизвести самому:
|
||||
```bash
|
||||
# терминал 1: занимаем место большим файлом внутри работающего процесса
|
||||
dd if=/dev/zero of=/tmp/bigfile bs=1M count=2000 &
|
||||
PID=$!
|
||||
sleep 1
|
||||
rm /tmp/bigfile # удаляем файл, пока процесс его ещё держит открытым
|
||||
|
||||
df -h /tmp # место всё ещё занято
|
||||
du -sh /tmp # du не видит файл — его уже нет в дереве каталогов
|
||||
|
||||
ls -l /proc/$PID/fd | grep bigfile # но дескриптор в /proc/<pid>/fd всё ещё жив
|
||||
wait $PID
|
||||
df -h /tmp # только теперь место освобождается
|
||||
```
|
||||
|
||||
Причина: `du` считает по дереву каталогов (файла там уже нет — он удалён), а `df` считает по факту занятых блоков на файловой системе, которые освобождаются только когда закрывается последний файловый дескриптор, ссылающийся на inode. Пока процесс держит файл открытым, место физически занято, хотя ссылки на файл в каталоге уже нет.
|
||||
|
||||
### 5. Права, владение, поиск в логах
|
||||
|
||||
```bash
|
||||
chmod 755 /usr/local/bin/disk-check.sh
|
||||
chown appuser:appgroup /var/log/myapp
|
||||
|
||||
# поиск всех строк с ошибкой в большом логе
|
||||
grep -c "connection timeout" /var/log/myapp/app.log
|
||||
awk '/connection timeout/ {print $0}' /var/log/myapp/app.log | tail -20
|
||||
```
|
||||
|
||||
### 6. Сигналы и процессы
|
||||
|
||||
```bash
|
||||
ps aux | grep myapp
|
||||
kill -15 <pid> # SIGTERM — вежливая просьба завершиться
|
||||
kill -9 <pid> # SIGKILL — принудительное убийство, процесс не может его перехватить/игнорировать
|
||||
pkill -f myapp # найти и убить по имени/паттерну команды
|
||||
```
|
||||
|
||||
## Что это даёт в разговоре с интервьюером
|
||||
|
||||
- Реальные, лично написанные и прогнанные bash-скрипты для обслуживания, а не абстрактные примеры.
|
||||
- Практический опыт systemd unit + timer как альтернативы cron.
|
||||
- Воспроизведённый вживую «фокус» df vs du — конкретный, запоминающийся ответ вместо зазубренной теории.
|
||||
- Уверенная диагностическая последовательность на вопрос «сервер тормозит».
|
||||
|
||||
## Как это ложится в легенду
|
||||
|
||||
Linux и Bash — сквозной инструмент в обеих ролях (тестировщик на CentOS, инженер сопровождения на Astra). Скрипты и диагностика в этом кейсе — обобщённая практика повседневного обслуживания серверов, характерная для роли инженера сопровождения, без привязки к вымышленным деталям конкретных внутренних систем компаний.
|
||||
79
stack/linux-bash/QUESTIONS.md
Normal file
79
stack/linux-bash/QUESTIONS.md
Normal file
@@ -0,0 +1,79 @@
|
||||
# Вопросы: Linux и Bash
|
||||
|
||||
Опираются на кейс: [CASE.md](CASE.md). Источники — [VK Cloud.md](../../interview/VK%20Cloud.md) (основной объём), [Dit Moscow.md](../../interview/Dit%20Moscow.md), [Alfa-Bank.md](../../interview/Alfa-Bank.md).
|
||||
|
||||
### Есть load average в Linux — как считается?
|
||||
|
||||
Скользящее экспоненциально взвешенное среднее числа процессов в состоянии "runnable" (готовы выполняться/выполняются) плюс процессов в непрерываемом ожидании ввода-вывода (D-state), усреднённое за 1/5/15 минут. Число выше количества ядер не всегда значит перегрузку CPU — часто виноват диск или сеть (процессы висят в D-state), поэтому смотрю load average вместе с `top`/`vmstat`, а не отдельно.
|
||||
|
||||
### Free и available в выводе free — чем отличаются, и если free почти 0, а available много — это плохо?
|
||||
|
||||
`free` — буквально свободная, ничем не занятая память. `available` — память, реально доступная для новых приложений без свопинга, с учётом того, что ядро может быстро освободить часть кеша страниц (page cache) и буферов при необходимости. Linux агрессивно использует свободную память под кеш файловой системы — это не потеря, а разумное использование ресурса. Поэтому если `free` близко к 0, а `available` большое — это нормально и даже хорошо: система эффективно использует память под кеш, который мгновенно отдаст приложениям по запросу. Плохой признак — низкий именно `available` вместе с активным использованием swap.
|
||||
|
||||
### Кейс: сервер тормозит, с каких 3-5 команд начнёшь диагностику?
|
||||
|
||||
`uptime` (load average, масштаб проблемы) → `top`/`htop` (кто ест CPU/память прямо сейчас) → `free -h` (память) → `df -h` (не кончилось ли место, особенно если есть запись логов) → `iostat -x 1`/`vmstat 1` (I/O, если по CPU и памяти виновник не найден). Порядок именно такой — от общей картины к частностям, чтобы не тратить время на глубокую диагностику не в том направлении.
|
||||
|
||||
### Как найти pid нужного процесса и убить его?
|
||||
|
||||
`ps aux | grep <имя>` или `pgrep -f <паттерн>` — найти pid. Убить: `kill -15 <pid>` (SIGTERM, вежливое завершение, процесс может перехватить сигнал и корректно закрыть ресурсы) или `kill -9 <pid>` (SIGKILL, безусловное принудительное убийство ядром — процесс не может его ни перехватить, ни проигнорировать). Второй способ — `pkill -f <паттерн>` находит и убивает сразу по паттерну имени команды, без отдельного поиска pid.
|
||||
|
||||
### Команда kill и её популярные сигналы, 2 способа убить процесс
|
||||
|
||||
Основные сигналы: `SIGTERM` (15, по умолчанию у `kill`) — просьба завершиться корректно; `SIGKILL` (9) — принудительное безусловное завершение ядром; `SIGHUP` (1) — исторически «повесить трубку», многие демоны используют его как сигнал перечитать конфиг без полного рестарта; `SIGINT` (2) — то же, что Ctrl+C. Два способа убить: `kill <pid>` (по идентификатору процесса) и `pkill -f <паттерн>` (по имени/паттерну командной строки, без предварительного поиска pid).
|
||||
|
||||
### Что делают df и du — с подвохом (df говорит место закончилось, du — что всё в порядке)
|
||||
|
||||
`df` считает занятое место по факту использованных блоков файловой системы. `du` считает по дереву каталогов, суммируя размеры файлов, которые там реально видны. Расхождение возникает, когда файл удалён (`rm`), но его всё ещё держит открытым какой-то процесс — файла больше нет в дереве каталогов (`du` его не видит), но место физически не освобождается, пока не закроется последний файловый дескриптор, ссылающийся на inode этого файла (`df` показывает место как занятое). Я воспроизвёл это вживую: `dd` создаёт большой файл в фоне, `rm` его удаляет, пока процесс жив — `df` и `du` расходятся, пока процесс не завершится (`ls -l /proc/<pid>/fd` при этом показывает "живой" дескриптор на уже удалённый файл).
|
||||
|
||||
### Что покажет ps -aux / ps -ef?
|
||||
|
||||
Оба показывают список всех процессов в системе, но в разном формате: `ps aux` — BSD-стиль (USER, PID, %CPU, %MEM, VSZ, RSS, TTY, STAT, START, TIME, COMMAND), `ps -ef` — System V-стиль (UID, PID, PPID — родительский процесс явно виден, C, STIME, TTY, TIME, CMD). `ps -ef` удобнее, когда нужно явно видеть иерархию процессов через PPID; `aux` привычнее для быстрой оценки потребления ресурсов.
|
||||
|
||||
### Как назначить владельца папки в Linux? Как выдаются права, что такое 777 и 755?
|
||||
|
||||
`chown user:group /path/to/dir` — сменить владельца (пользователя) и группу; `chown -R` — рекурсивно для содержимого. Права задаются тремя цифрами (владелец/группа/остальные), каждая — сумма: read=4, write=2, execute=1. `755` = владелец rwx (7), группа и остальные r-x (5) — типично для исполняемых скриптов и директорий, куда нужен доступ на чтение всем. `777` = rwx всем без ограничений — практически всегда небезопасно на проде, разрешает любому пользователю системы читать, менять и исполнять файл.
|
||||
|
||||
### Что делает awk и варианты использования?
|
||||
|
||||
Текстовый процессор, работающий построчно и разбивающий каждую строку на поля по разделителю (по умолчанию — пробел/таб): `$1`, `$2` — первое/второе поле, `$0` — вся строка, `NR` — номер текущей строки. Типичное использование: `awk '{print $1}' file` — вывести первую колонку, `awk -F: '{print $1}' /etc/passwd` — сменить разделитель на `:`, `awk 'NR==2 {print $5}'` — взять конкретное поле конкретной строки (я так парсил вывод `df -h` в скрипте disk-check из [CASE.md](CASE.md)), `awk '/pattern/ {print}'` — фильтрация строк по регулярке, аналог grep, но с доступом к полям.
|
||||
|
||||
### У тебя большой лог — как найти все строки с ошибкой connection timeout?
|
||||
|
||||
`grep -c "connection timeout" file.log` — посчитать количество вхождений; `grep -n "connection timeout" file.log` — вывести с номерами строк; для действительно больших файлов и потоковой обработки в реальном времени — `tail -f file.log | grep --line-buffered "connection timeout"`. Если нужен контекст вокруг ошибки — `grep -B2 -A2 "connection timeout" file.log` (2 строки до и после).
|
||||
|
||||
### Что такое cgroups и namespaces в Linux?
|
||||
|
||||
Namespaces — механизм ядра, изолирующий, что процесс видит: свой PID namespace (процесс видит только «свои» процессы, начиная нумерацию с 1), сетевой namespace (свои интерфейсы, таблицы маршрутизации), mount namespace (своя файловая система), UTS (своё hostname) и т.д. Cgroups (control groups) — механизм, ограничивающий и учитывающий, сколько ресурсов процесс может использовать (CPU, память, I/O). Вместе это и есть технический фундамент контейнеризации: контейнер — это обычный процесс на хосте, которому через namespaces ограничили видимость системы, а через cgroups — доступные ресурсы (без отдельной виртуализации ядра, в отличие от полноценных VM). Подробнее в контексте Docker — [../docker/QUESTIONS.md](../docker/QUESTIONS.md).
|
||||
|
||||
### Что такое inode?
|
||||
|
||||
Структура данных файловой системы, хранящая метаданные файла (владелец, права, размер, время изменения, указатели на блоки данных на диске) — но не само имя файла. Имя файла — это просто запись-ссылка в каталоге, указывающая на inode. Отсюда и разница между df/du из вопроса выше: пока хотя бы один процесс держит открытым файловый дескриптор, указывающий на inode, место на диске не освобождается, даже если все имена (ссылки в каталогах) на этот inode уже удалены.
|
||||
|
||||
### Что такое дескрипторы и reference count в файловом дескрипторе?
|
||||
|
||||
Файловый дескриптор — небольшое целое число, которым процесс ссылается на открытый файл/сокет/пайп внутри ядра (0, 1, 2 — stdin/stdout/stderr зарезервированы). Reference count в контексте inode — счётчик количества ссылок на него: это и жёсткие ссылки в каталогах (`ln`), и открытые файловые дескрипторы процессов. Данные на диске реально освобождаются только тогда, когда reference count падает до нуля — то есть удалены все имена (hard links) и закрыты все процессы, державшие файл открытым.
|
||||
|
||||
### Ссылки жёсткие и мягкие (hard/soft) — в чём разница и что происходит при удалении файла?
|
||||
|
||||
Жёсткая ссылка (`ln`) — ещё одно имя, указывающее прямо на тот же inode: у файла и его hard link одинаковый inode-номер, и оба «равноправны» — удаление одного из имён не трогает данные, пока жива хотя бы одна ссылка (см. reference count выше). Мягкая/символическая ссылка (`ln -s`) — отдельный маленький файл, который просто хранит путь к другому файлу; если оригинал удалить, symlink останется, но будет указывать в никуда («битая ссылка»). Hard link не может пересекать границы файловых систем и не может указывать на директорию (за редкими системными исключениями), symlink может — это одно из отличий на практике.
|
||||
|
||||
### Как проверить, что порт открыт/слушается, и как найти порт нужного процесса?
|
||||
|
||||
`ss -tulpn` (современный аналог `netstat`) — покажет все слушающие TCP/UDP порты и какой процесс их держит. Для конкретного процесса: `ss -tulpn | grep <pid или имя>` либо через `/proc/<pid>/net/tcp` (низкоуровнево). Для проверки доступности порта на удалённом хосте: `nc -zv host port` или `curl -v telnet://host:port`.
|
||||
|
||||
### Как будешь менять параметры ядра Linux?
|
||||
|
||||
Через `sysctl`: временно — `sysctl -w vm.swappiness=10` (действует до перезагрузки), постоянно — правка `/etc/sysctl.conf` или файла в `/etc/sysctl.d/*.conf` с последующим `sysctl -p` для применения без перезагрузки. Типичные параметры, которые встречаются на практике: `vm.swappiness` (насколько активно система уходит в своп), `net.core.somaxconn` (размер очереди входящих TCP-соединений), `fs.file-max` (лимит открытых файловых дескрипторов на систему).
|
||||
|
||||
### Что такое systemd? Зачем нужна директория /etc/systemd/system?
|
||||
|
||||
Systemd — современная система инициализации и менеджер служб в большинстве дистрибутивов Linux (включая Astra и современные CentOS/RHEL) — управляет запуском, остановкой, зависимостями и мониторингом состояния сервисов через unit-файлы. `/etc/systemd/system` — стандартное место для unit-файлов, добавленных администратором вручную (в отличие от `/usr/lib/systemd/system`, куда unit-файлы кладут пакеты дистрибутива) — сюда я клал свои unit и timer для скрипта disk-check из [CASE.md](CASE.md).
|
||||
|
||||
### Что такое zombie/orphan процесс?
|
||||
|
||||
Zombie — процесс, который уже завершился, но его родитель ещё не вызвал `wait()`, чтобы забрать его код возврата — запись о процессе висит в таблице процессов (виден в `ps` со статусом `Z`), но сам процесс уже не потребляет ресурсов кроме этой записи. Orphan — процесс, чей родитель завершился раньше него; такой процесс автоматически «усыновляется» init-процессом (PID 1 или ближайшим subreaper), который и заберёт его код возврата, когда тот завершится — то есть orphan сам по себе не проблема, в отличие от накопления zombie-процессов, что говорит об ошибке в родительском процессе (не вызывает wait()).
|
||||
|
||||
### Что будешь делать, если упал сервер? Если сервер на VMware — как будешь спасать VM и какую диагностику проведёшь?
|
||||
|
||||
Порядок действий: сначала проверить, отвечает ли хост вообще (ping, SSH) — если нет, для VM это часто означает проблему на уровне гипервизора, а не гостевой ОС. Дальше — зайти через консоль гипервизора (у VMware это vSphere/ESXi console, доступ к которой не зависит от сетевого стека самой VM) и посмотреть состояние виртуалки: зависла ли она (нет отклика на клавиатуру в консоли), ушла в панику ядра (виден текст паники на консоли), или процесс просто не отвечает по сети из-за исчерпания ресурсов. Дальнейшая диагностика по возможности зайти в саму гостевую ОС: `dmesg`/`journalctl -xb` на предмет OOM killer или паники ядра, проверка диска (не забился ли под 100%, что часто останавливает запись логов и сервисов), проверка сети гипервизора (не отвалился ли виртуальный сетевой адаптер). Если гостевая ОС совсем не отвечает — крайняя мера восстановления это перезапуск VM средствами гипервизора (soft reset через ACPI-сигнал, если возможно, иначе hard reset) с последующим разбором причины по логам, которые сохранились до сбоя. Личного опыта администрирования именно VMware у меня нет — это разбор на уровне общей логики диагностики сбоя виртуальной машины, применимой к любому гипервизору.
|
||||
Reference in New Issue
Block a user