Interview
Preparing to Interview
Resources: 1. https://github.com/Swfuse/devops-interview?tab=readme-ov-file 2. https://github.com/rmntrvn/adm_linux_ops_questions
Общее
У вас есть компьютер. Вы нажали на кнопку включения. Расскажите максимально подробно, что происходит, до загрузки ОС.
Подается сигнал о подаче питания, запускается BIOS/UEFI (программа подготовки к загрузке ОС). Загрузчик проверяет целостность своей программы, инициализирует устройства. После успешного прохождения тестов BIOS ищет загрузчик ОС:
- ищется загрузочный сектор (MBR)
- считывается код из этого раздела и управление передается ему,
- этот код ищет активный раздел ("system partition"), в первом разделе которого находится загрузочный код GRUB,
- GRUB загружает и выполняет образы ядра и initrd,
- передает управление ядру,
- ядро монтируется в файловую систему и выполняет процесс init,
- init загружает программы уровней выполнения (runlevel) из
/etc/rc.d/rc*.d/.
Пример программ:
S12syslog— запуск демона syslog,S80sendmail— запуск демона sendmail.
Таким образом, syslog будет запущен перед sendmail.
Источник: https://habr.com/ru/post/518972/
Открыли linux консоль, ввели curl www.tinkoff.ru - нажали энтер. Что происходит, максимально подробно.
curl — утилита для взаимодействия с хостами по протоколам: FTP, FTPS, HTTP, HTTPS, TFTP, SCP, SFTP, Telnet, DICT, LDAP, POP3, IMAP и SMTP.
Без дополнительных параметров curl выполняется с методом GET по протоколу HTTP (уровень L7). Перед этим:
- происходит разрешение DNS имени в IP-адрес по протоколу DNS,
- Протокол: DNS
- Уровни OSI:
- Прикладной (7) — DNS
- Транспортный (4) — UDP (или TCP)
- Сетевой (3) — IP
- запрос уходит на DNS-сервер, далее по цепочке — к корневым DNS и авторитетным,
- Протоколы: DNS → через UDP или TCP (53 порт)
- Уровни OSI:
- Прикладной (7) — DNS
- Транспортный (4) — UDP/TCP
- Сетевой (3) — IP
- Канальный (2) — Ethernet/Wi-Fi
- Физический (1)
- получив IP, устанавливается соединение по TCP (трехстороннее рукопожатие),
- TCP (3-way handshake: SYN, SYN-ACK, ACK)
- Уровни OSI:
- Транспортный (4) — TCP
- Сетевой (3) — IP
- Канальный (2), Физический (1)
- используется стек TCP/IP и таблицы маршрутизации,
- Протоколы: IP (routing), TCP (session)
- Уровни OSI:
- Сетевой (3) — IP
- Транспортный (4) — TCP
- Канальный (2), Физический (1)
- далее отправляется HTTP-запрос на порт 80,
- Протоколы: HTTP
- Уровни OSI:
- Прикладной (7) — HTTP
- Транспортный (4) — TCP
- Сетевой (3) — IP
- получаем ответ от сервера.
- Протоколы: HTTP (ответ), TCP (доставка)
- Уровни OSI:
- Прикладной (7) — HTTP
- Транспортный (4) — TCP
- Сетевой (3) — IP
Зачем маска подсети на клиентском компьютере
Маска подсети нужна, чтобы определить, будет ли передача данных происходить на канальном уровне (L2) напрямую, или нужно использовать маршрутизацию на сетевом уровне (L3).
Как это работает:
-
Компьютер сравнивает свой IP и IP назначения через маску подсети (битовая операция AND).
-
Если результат одинаковый (одна сеть):
-
Узел считается “локальным”
-
Передача идёт на уровне L2 (Ethernet, ARP)
-
Пакет отправляется напрямую адресату, без маршрутизатора используется широковещание (broadcast) для всех устройств в сети
-
-
Если результат разный (другая сеть):
-
Узел считается внешним
-
Передача идёт через маршрутизатор (gateway) на уровне L3
-
Применяется IP-маршрутизация, NAT и т.д.
-
Маска подсети определяет границы локальной сети. Клиентское устройство использует её, чтобы понять, к какому уровню обращаться для доставки пакета:
-
если получатель внутри той же подсети → L2-коммуникация через ARP и прямую отправку;
-
если в другой подсети → пакет отправляется на маршрутизатор (gateway), и далее обрабатывается на уровне L3 и выше.
Это позволяет устройству избежать лишней маршрутизации, минимизировать задержки и правильно формировать ARP-запросы только внутри локального сегмента.
Что такое LoadAverage?
LoadAverage — средняя загрузка CPU за 1, 5 и 15 минут.
- Что означает? Процент утилизируемого времени от общего времени простоя.
- В чем измеряется? Измеряется в тиках (единицы времени CPU), сколько тиков отдано на выполнение процессов. Если > 100%, значит есть очередь из ожидающих процессов.
- Какое нормальное значение? До 1 на 1 CPU (1.0 на одно ядро).
- Если LA = 1000 — это нормально? Нет, это плохо, если только не 1000 ядер в системе.
- Что влияет на LA? Например, iowait.
Высокие значения wa (wait I/O) и LA часто говорят о D-state (ожидание ввода/вывода), может быть связано с дисками, сетью, USB, сокетами и др.
Упрощенная модель состояний процесса в Linux
- D — ожидание ввода/вывода
- R — выполняется
- S — спящий, ждет события
- T — остановлен
- Z — зомби
Посмотреть процессы: ps aux
Если wa (wait I/O) > 10-30%, желательно найти причину.
Источник: https://firstvds.ru/technology/nagruzka-na-server-opredelenie-prichin
Кто и при каких условиях может менять группу у файла?
Команда: chown
- Требуется: либо быть владельцем файла, либо иметь права root.
Пример:
-rw------- 1 user1 user1 147746 мар 27 12:19 somefile
-
chown user1:user2 somefile -
chown user1:www-data somefile -
Если не root: сработает, если user1 состоит в этих группах.
-
Если root: сработает, если группы и пользователи существуют.
Свободное место #1
df (disk free) - Показывает использование файловой системы в целом, на уровне блочного устройства. - Смотрит на таблицу inodes и блоков, чтобы узнать, сколько данных физически занято. - Учитывает все данные, включая: - удалённые, но всё ещё открытые файлы; - данные в сокетах, pipes, tmpfs и т.п. 🔸 Типичный источник правды — ядро, через системные вызовы statfs().
du (disk usage) - Считает файлы и папки, доступные в текущем namespace. - Обходит файловую систему и суммирует размеры только доступных (видимых) файлов. - Не считает: - удалённые, но ещё открытые файлы; - tmpfs, сокеты, pipes и другие неклассические файловые объекты. 🔸 Типичный источник правды — просмотр содержимого директорий.
lsof (List Open Files) — это утилита в Linux/Unix, которая показывает все открытые файлы и сокеты в системе. В Linux всё — это файл, включая:
- обычные файлы (/var/log/...)
- директории
- устройства (/dev/sda)
- сокеты (/tmp/.X11-unix)
- каналы (pipes)
- сетевые соединения (TCP, UDP)
df -Th показывает, что место есть. Но touch file — ошибка "No space left on device".
Причины:
-
Файлы были удалены, но заняты процессами.
-
Проверка:
sudo lsof / | grep deleted -
Исчерпаны inodes —
df -i -
Плохие блоки — использовать
fsck -vcck /dev/sdX -
Ограничения файловой системы (например, FAT — макс. файл 4GB)
Источник: https://rtfm.co.ua/unix-df-i-du-raznye-znacheniya/ https://zalinux.ru/?p=3001
Свободное место #2
Корень 100ГБ, df показывает занято всё, а du -sh /* — только 10ГБ.
Возможные причины:
- Файлы удалены, но заняты процессами.
- Найти процессы:
lsof | grep deleted
Пояснение: файловые дескрипторы и inodes
-
inode — уникальный ID файла, метаданные.
-
fd (file descriptor) — "билет" на доступ к файлу для конкретного процесса, с конкретными правами.
-
Один файл может быть открыт многими fd.
-
После закрытия fd доступ к файлу теряется (если нет других открытых).
Гипервизор
Гипервизор — это низкоуровневая оболочка (программа или аппаратная схема), обеспечивающая параллельное выполнение нескольких ОС на одном хост-компьютере.
Функции: - изоляция ОС, - безопасность и защита, - управление и разделение ресурсов, - виртуализация оборудования, - включение/перезагрузка/выключение ВМ, - взаимодействие между ОС (например, по сети).
Гипервизор можно считать микроядром — минимальной ОС, управляющей виртуальными машинами.
Как работает контейнеризация и чем отличается от виртуализации?
Контейнеризация: изоляция приложений с использованием общего ядра ОС (через namespaces, cgroups). Контейнер — это изолированный процесс, а не отдельная ОС.
Виртуализация: запуск полноценной ОС поверх гипервизора. Каждая виртуальная машина имеет собственное ядро и ресурсы.
Контейнеры легче, запускаются быстрее, используют меньше ресурсов.
Linux
Виды памяти
Основные термины
| Вид памяти | Что это такое | Где смотрим |
|---|---|---|
| VSS (VSZ) – Virtual Set Size | Вся виртуальная память процесса (вкл. библиотеки, mmap, кэш, зарезервированную). | ps, top, smem |
| RSS – Resident Set Size | Реально загруженная в RAM память процесса (без свопа). | ps, top, smem, /proc/[pid]/statm |
| PSS – Proportional Set Size | RSS, но shared-страницы делятся пропорционально между процессами. | smem, /proc/[pid]/smaps |
| USS – Unique Set Size | Только та память, которую использует только данный процесс. | smem, /proc/[pid]/smaps |
| Shared memory | Общая память, используемая несколькими процессами (например, библиотеки). | smem, pmap, /proc/[pid]/maps |
| Swap | Страницы, выгруженные на диск (в swap). | free, vmstat, top, smem |
| Page Cache | Кэш файловых данных, недавно прочитанных с диска. Используется ядром. | free, vmstat, /proc/meminfo |
| Buffers | Кэш метаданных файловой системы и блочных устройств. | free, vmstat, /proc/meminfo |
| Slab | Кэш структур ядра (inode, dentry, файловые дескрипторы и пр.). | /proc/meminfo, slabtop |
| PageTables | Память, занимаемая таблицами страниц виртуальной памяти процессов. | /proc/meminfo, smem, top |
| KernelStack | Стек ядра, выделенный для каждого потока. | /proc/meminfo, smem |
| #### Области памяти процесса |
| Область | Назначение |
|---|---|
| Text (code) | Исполняемый код |
| Data | Глобальные переменные |
| Heap | Динамическая память (malloc, new) |
| Stack | Локальные переменные, вызовы функций |
| mmap | Отображения файлов, shared libraries, анонимная память |
| Можно посмотреть с помощью: |
cat /proc/<pid>/maps
📊 Пример smem
sudo smem -r
| PID | User | USS | PSS | RSS | Command |
|---|---|---|---|---|---|
| 123 | root | 10M | 12M | 14M | nginx |
💡 Как использовать это на практике:
• Высокий VSS — не всегда проблема (может быть много mmap’ов, но физически не используется). • Высокий RSS — показывает реальное использование RAM. • PSS — хорош для понимания, сколько “в среднем” процесс реально занимает. • USS — полезен для оценки того, что можно выгрузить без ущерба другим процессам. • Swap > 0 — может сигнализировать о нехватке RAM.
Namespaces and Cgroups
namespaces и cgroups — это два столпа изоляции в Linux. Они лежат в основе контейнеризации (например, Docker, Kubernetes) и вообще любой виртуализации на уровне ОС.
Давай разложим на понятном уровне:
🧱 Что такое Linux namespaces?
Namespaces позволяют изолировать системные ресурсы между процессами.
То есть каждый процесс “видит” только то, что разрешено его namespace’у.
📦 Основные типы namespace
| Namespace | Изолирует | Пример |
|---|---|---|
| mnt | файловую систему | отдельный /, /proc |
| pid | процессы и PID’ы | ps покажет “свои” PID |
| net | сетевые интерфейсы, IP | отдельный eth0 |
| uts | имя хоста (hostname) | hostname будет разным |
| ipc | очереди сообщений, semaphors | ipcs |
| user | пользователей и UID/GID | root внутри, но не снаружи |
| cgroup | иерархию cgroups | отдельная область ресурсов |
📌 Каждый namespace изолирует свою подсистему.
🔧 Пример изоляции с unshare:
sudo unshare --pid --fork --mount-proc bash
Теперь ты в новом PID namespace → ps покажет только текущий процесс.
🔒 Что такое Linux cgroups?
Cgroups (Control Groups) — это способ ограничить и контролировать ресурсы, которые может потреблять процесс.
📌 Возможности cgroups:
• Ограничение CPU, RAM, disk IO, pids • Приоритет (через weight) • Мониторинг использования ресурсов • Группировка процессов в иерархию
Примеры ресурсов:
| Тип | Что ограничивает |
|---|---|
| cpu | использование CPU |
| memory | объём RAM |
| pids | число процессов |
| blkio | доступ к диску |
| devices | доступ к устройствам |
| Пример ограничения памяти: |
mkdir /sys/fs/cgroup/memory/mygroup
echo 100000000 > /sys/fs/cgroup/memory/mygroup/memory.limit_in_bytes
echo $$ > /sys/fs/cgroup/memory/mygroup/tasks
📌 Теперь текущий процесс не может использовать больше 100Мб RAM.
📦 Как работают вместе
Контейнер (например, docker run) использует:
• Namespaces → чтобы изолировать окружение (видимость процессов, файлов, сети) • Cgroups → чтобы ограничить, сколько он может потреблять ресурсов
🐳 Пример: как работает Docker контейнер под капотом
- Создаётся новый PID, NET, UTS, MNT, USER namespace → у контейнера “своя” ОС
- Создаются cgroups для CPU, memory и pids
- Монтируется overlayfs → своя корневая файловая система
- Внутри запускается твой ENTRYPOINT в изолированной среде
✅ Сравнение:
| Namespaces | Cgroups | |
|---|---|---|
| Что делают? | Изолируют | Ограничивают |
| Применение | Видимость ресурсов | Потребление ресурсов |
| Пример | свой hostname | максимум 512Mi памяти |
Bash переменные $?, $0, $1, $@, $\$
$\$
echo $$
Это команда, которая выводит PID (Process ID) текущего shell-процесса.
🔍 Подробно:
• $ — это префикс для переменной окружения в bash.
• $\$ — специальная переменная в bash, которая содержит PID текущего процесса, в котором выполняется команда.
📦 Пример:
$ echo $$
12345
Это означает, что оболочка (shell), в которой ты работаешь — имеет PID 12345.
🧠 Когда полезно?
- Чтобы:
• добавить текущий процесс в cgroup:
echo $$ > /sys/fs/cgroup/memory/mygroup/tasks
- Отлаживать скрипты:
echo "This script is running with PID $$"
- Смотреть, какие процессы запущены от конкретного shell:
ps -fp $$
Special variables short
Иногда их также называют:
• параметрами окружения shell’а • позиционными параметрами ($0, $1, $2, …, $@, $) • встроенными переменными shell (builtin shell variables)*
📘 Расшифровка самых важных:
| Переменная | Значение |
|---|---|
| $$ | PID текущего shell-процесса |
| $? | Код возврата последней команды (0 = успех, ≠0 = ошибка) |
| $0 | Имя скрипта (или имя текущего shell) |
| $1, $2, … | Параметры, переданные скрипту или функции |
| $@ | Все аргументы как список ("$1", "$2"…) |
| $* | Все аргументы как одна строка ("$1 $2 ...") |
🔍 Примеры:
#!/bin/bash
echo "Script name: $0"
echo "First arg: $1"
echo "Exit code of last cmd: $?"
echo "All args (\$@): $@"
echo "All args (\$*): $*"
Если ты вызовешь:
./myscript.sh hello world
То получишь:
Script name: ./myscript.sh
First arg: hello
Exit code of last cmd: 0
All args ($@): hello world
All args ($*): hello world
🧠 Резюме
| Имя | Что делает | Категория |
|---|---|---|
| $$ | PID текущего shell | спец. переменная |
| $? | Код выхода последней команды | спец. переменная |
| $0 | Имя скрипта или shell | позиционный параметр |
| $1, $2 | Аргументы | позиционные параметры |
| $@, $* | Все аргументы | позиционные параметры |
Что такое zombie процесс и чем это плохо, как его убить?
Zombie (зомби) — завершившийся процесс, чья запись ещё хранится в системе (ожидает, пока родитель вызовет wait() для чтения exit-кода).
- Не использует CPU/RAM, но потребляет PID.
- При большом числе зомби — может закончиться пул PID.
Убить: нельзя напрямую, нужно убить родителя:
ps -ef | grep defunct
# найти родителя, затем:
sudo kill -9 <PID>
Чем опасно хранение большого количества маленьких файлов на файловой системе?
- Заканчиваются inodes — метаданные для файлов.
- Медленное выполнение операций (поиск, open/read).
- Проблемы с резервным копированием и производительностью.
Что делать: - Использовать базы данных (например, SQLite, PostgreSQL). - Разбивать по подпапкам (sharding по префиксу ID). - Использовать объектное хранилище (S3, GCS).
GIT
Как внести изменения в последний коммит?
Можно использовать команду git commit с флагом --amend.
Как добавить забытые файлы в последний коммит?
Если забыли включить в коммит часть файлов, можно:
git add dir1
git commit
# забыли dir2:
git add dir2
git commit --amend --no-edit
Флаг --no-edit позволяет оставить прежнее сообщение коммита.
Чем отличается git revert от git reset?
git revertотменяет один конкретный коммит, создав новый коммит с обратными изменениями.git resetвозвращает проект к прошлому состоянию, удаляя все последующие коммиты (если hard).
Сеть
OSI
Open Systems Interconnection
📶 Модель OSI — 7 уровней сетевого взаимодействия
| № | Уровень | Описание | Примеры |
|---|---|---|---|
| 7 | Прикладной (Application) | То, что видит пользователь | HTTP, FTP, DNS, SSH |
| 6 | Представления (Presentation) | Формат данных, кодировка, шифрование | TLS/SSL, JPEG, MP3 |
| 5 | Сеансовый (Session) | Управление сессиями | SSH-сессия, RPC, NetBIOS |
| 4 | Транспортный (Transport) | Доставка данных, надёжность | TCP, UDP |
| 3 | Сетевой (Network) | Адресация и маршрутизация | IP, ICMP |
| 2 | Канальный (Data Link) | Доставка кадров между узлами | Ethernet, Wi-Fi, PPP |
| 1 | Физический (Physical) | Биты, кабели, сигналы | RJ-45, оптоволокно, Wi-Fi |
| Мнемоника: |
🔽 Снизу вверх:
Please Do Not Throw Sausage Pizza Away
(Physical, Data Link, Network, Transport, Session, Presentation, Application)
🔍 Пример передачи HTTP-запроса:
- HTTP-запрос (Application)
- Шифруется в TLS (Presentation)
- Управление сеансом TLS (Session)
- Делится на сегменты TCP (Transport)
- Достаётся через IP-адрес (Network)
- Отправляется по Ethernet/Wi-Fi (Data Link)
- Через физический кабель или сигнал (Physical)
L4/L7 LB
Разберём L4, L7 и другие типы балансировщиков, и в чём их особенности.
🌐 Уровни балансировки нагрузки (по OSI-модели)
✅ L4-балансировка (транспортный уровень)
📌 Основана на: IP-адресах + TCP/UDP-портах
🛠 Как работает:
• Перенаправляет трафик, не заглядывая внутрь пакета.
• Работает по 5-tuple: src IP, src port, dst IP, dst port, protocol.
🔧 Примеры:
• iptables / ipvs • Linux LVS • HAProxy (L4 режим) • AWS Network Load Balancer (NLB) • MetalLB в Kubernetes
➕ Плюсы:
• Быстро • Низкие накладные расходы • Подходит для TCP/UDP
➖ Минусы:
• Не видит содержимого (например, URL, cookie) • Не может принимать решения по содержимому запроса
✅ L7-балансировка (прикладной уровень)
📌 Основана на: содержимом HTTP/HTTPS, gRPC, WebSocket и т.д.
🛠 Как работает:
• Анализирует запросы полностью: путь, заголовки, куки, тело и т.п. • Может делать маршрутизацию по URL, хосту, методу, и даже по содержимому.
🔧 Примеры:
• NGINX, Envoy, Traefik, HAProxy (L7) • Kubernetes Ingress Controllers • AWS Application Load Balancer (ALB) • Istio / Linkerd (в сервисной mesh’е)
➕ Плюсы:
• Гибкая маршрутизация • Поддержка канареек, A/B, blue/green • Можешь делать rate limiting, аутентификацию, логирование
➖ Минусы:
• Выше нагрузка • Медленнее, чем L4 • Не подходит для “сырого” TCP/UDP
📦 Есть ли другие уровни?
✅ L3-балансировка (сетевой уровень)
📌 Маршрутизация по IP без портов
• Очень базовая, почти не используется в приложениях напрямую • Пример: BGP + ECMP (Equal-cost multi-path routing), IP-routing
✅ L2-балансировка (канальный уровень)
📌 Балансировка через MAC-адреса и ARP
• Используется в некоторых виртуализированных или железных решениях • Пример: балансировка через L2-мосты, ARP spoofing/rewriting (редкость)
🧠 Сравнение коротко
| Уровень | Что видит? | Примеры | Особенности |
|---|---|---|---|
| L7 | HTTP, gRPC, Headers | ALB, Ingress, NGINX | Умная маршрутизация |
| L4 | TCP/UDP | NLB, LVS, iptables | Быстро, не читает запросы |
| L3 | IP-адреса | BGP, ECMP | Очень низкий уровень, routing |
| L2 | MAC-адреса | ARP proxy, мосты | Почти не используется в клауде |
🧪 В Kubernetes
• Service type: LoadBalancer — обычно L4 (NLB или аналог) • Ingress Controller — L7 (работает с HTTP) • Service Mesh (Istio, Linkerd) — L7 прокси с deep inspection
В Kubernetes уровни L4 и L7 чаще всего используются вместе, потому что они решают разные задачи на пути трафика к приложению. Давай разберём пошагово и наглядно, как они сочетаются.
🧭 Кратко: как трафик проходит от клиента к приложению
Client → L4 LoadBalancer → NodePort / ClusterIP (L4) → Ingress Controller (L7) → App
🔷 1. L4 в Kubernetes
L4 балансировка основана на IP + TCP/UDP портах. В Kubernetes это:
✅ Примеры L4-объектов:
| Тип объекта | Что делает | Уровень |
|---|---|---|
| Service: ClusterIP | L4 внутри кластера | L4 |
| Service: NodePort | Открывает порт на всех нодах | L4 |
| Service: LoadBalancer | Интеграция с внешним L4 балансером (например, NLB) | L4 |
📌 Важно: LoadBalancer — это внешний L4-балансер, например, AWS NLB или GCP TCP balancer, который умеет “раздавать” трафик на NodePort сервиса.
🔶 2. L7 в Kubernetes
✅ Как только L4-трафик доходит до Ingress Controller (например, NGINX, Traefik, Envoy):
• Начинается L7-балансировка:
Разбор HTTP-запросов → маршрутизация по:
• host (например, api.example.com)
• path (например, /v1/ → один сервис, /admin → другой)
• заголовкам, методам, и т.п.
✅ Примеры L7:
• Ingress ресурс
• IngressRoute (Traefik CRD)
• VirtualService (в Istio)
🧪 Пример трафика:
👉 Ты открываешь браузер:
https://app.example.com/login
Что происходит:
-
🌍 Запрос уходит на внешний IP LoadBalancer’а (например, AWS NLB) — L4
-
🚪 Он перенаправляет трафик на NodePort внутри кластера (все ноды слушают нужный порт) — L4
-
📦 Попадает на pod с Ingress Controller’ом (например, NGINX) — теперь включается L7
-
🧠 NGINX смотрит:
• Host: app.example.com
• Path: /login
- 🛣 Направляет трафик на нужный backend-сервис (например, auth-service) — уже внутри кластера
🔁 Схема
[ Client ]
|
[ L4 LoadBalancer ] ← external (AWS NLB, GCP LB)
|
[ NodePort Service ] ← kube-proxy, iptables (L4)
|
[ Ingress Controller Pod ] ← nginx, envoy (L7)
|
[ Target App Service / Pod ]
🤓 А если Service Mesh (например, Istio)?
• Istio вставляет L7-прокси (Envoy) перед каждым pod’ом
• Трафик идёт:
• L4 → Ingress Gateway (L7)
• Потом между подами тоже L7 → полный контроль, трассировка, канареечные релизы и т.п.
🧠 Резюме
| Компонент | Уровень | Назначение |
|---|---|---|
| LoadBalancer Service | L4 | Доступ снаружи кластера |
| NodePort / ClusterIP | L4 | Роутинг на pod’ы внутри |
| Ingress Controller | L7 | HTTP/HTTPS маршрутизация |
| Service Mesh | L7 | Продвинутая маршрутизация между подами |
TCP vs UDP. Разница
- TCP — протокол с гарантией доставки, устанавливает соединение перед передачей пакетов.
- UDP — не устанавливает соединение, работает быстрее, не гарантирует доставку. Используется для потокового видео, DNS и других приложений, где важна скорость.
Как происходит TCP-handshake?
Кратко: 1. Клиент отправляет SYN с seq=A. 2. Сервер отвечает SYN+ACK с seq=B и ack=A+1. 3. Клиент отправляет ACK с seq=A+1 и ack=B+1.
Подробно: 1. Клиент отправляет сегмент с SYN и случайным seq (A). 2. Сервер запоминает seq клиента, выделяет сокет, отправляет SYN+ACK (seq=B, ack=A+1) и переходит в SYN-RECEIVED. При ошибке — RST. 3. Клиент получает SYN+ACK, запоминает seq сервера и отправляет ACK. Переходит в ESTABLISHED. Если получил RST — завершает попытку. При таймауте — повтор. 4. Сервер при получении ACK переходит в ESTABLISHED. Если нет ACK — закрывает соединение.
Как работают сертификаты? Как подтверждается соединение? (https соединение)
Процесс работает следующим образом:
- Браузер или сервер пытается подключиться к веб-сайту (веб-серверу), защищенному с помощью SSL.
- Браузер или сервер запрашивает идентификацию у веб-сервера.
- В ответ веб-сервер отправляет браузеру или серверу копию своего SSL-сертификата и публичный ключ.
- Браузер или сервер проверяет, является ли этот SSL-сертификат доверенным. У него уже зашиты сервера с помощью которых нужно производить проверку, с помощью центров сертификации. Если это так, он сообщает об этом веб-серверу. Генерирует сенасовый ключ, шифрует пебличным ключом и отправляет на сервер.
- Сеервер расшифровывает сообщение и сохраняет сеансовый ключ. Затем веб-сервер возвращает подтверждение с цифровой подписью и начинает сеанс, зашифрованный с использованием SSL.
- Зашифрованные данные используются совместно браузером или сервером и веб-сервером.
Опиши принцип работы ssl-шифрования
В основе любого метода шифрования лежит ключ. Ключ — это способ зашифровать или расшифровать сообщение. В работе SSL-сертификата участвуют три ключа: публичный, приватный и сеансовый.
Публичный ключ зашифровывает сообщение.
Браузер использует его, когда нужно отправить пользовательские данные серверу. Например, после того как вы ввели данные банковской карты и нажали «Оплатить». Этот ключ виден всем, браузер прикрепляет его к сообщению.
Приватный ключ расшифровывает сообщение.
Его использует сервер, когда получает сообщение от браузера. Этот ключ хранится на сервере и никогда не передаётся вместе с сообщением.
Сеансовый ключ одновременно зашифровывает и расшифровывает сообщения.
Браузер генерирует его на время, которое пользователь проводит на сайте. Стоит пользователю закрыть вкладку, сеанс закончится и ключ перестанет работать.
Публичный и приватный ключи генерируются один раз при создании запроса на выпуск сертификата. Поэтому приватный ключ нужно хранить осторожно. Если ключ попадёт в руки другому человеку, он сможет расшифровывать сообщения, а вам придётся переустанавливать сертификат.
Шифрование с двумя разными ключами называют асимметричным. Использовать такой метод более безопасно, но медленно. Поэтому браузер и сервер используют его один раз: чтобы создать сеансовый ключ.
Шифрование с одним ключом называют симметричным. Этот метод удобен, но не так безопасен. Поэтому браузер и делает уникальный ключ для каждого сеанса вместо того, чтобы хранить его на сервере.
Симметричное и асимметричное шифрование — это два основных метода шифрования данных. Они отличаются механизмом использования ключей, безопасностью и производительностью.
Симметричное шифрование
🔑 Один ключ для шифрования и дешифрования
В симметричном шифровании используется один и тот же ключ для шифрования и дешифрования данных.
Как работает?
- Отправитель и получатель обмениваются секретным ключом.
- Отправитель шифрует сообщение с помощью этого ключа.
- Получатель расшифровывает сообщение, используя тот же ключ.
Примеры алгоритмов:
• AES (Advanced Encryption Standard) – широко используется в современных системах. • DES (Data Encryption Standard) – устарел, но был стандартом в прошлом. • 3DES (Triple DES) – улучшенная версия DES. • RC4 – потоковый алгоритм, сейчас считается небезопасным.
Плюсы
✅ Быстрое шифрование и дешифрование. ✅ Эффективно при работе с большими объемами данных.
Минусы
❌ Необходимо безопасно передавать ключ между отправителем и получателем. ❌ Если ключ украдут, злоумышленник сможет расшифровать данные.
Асимметричное шифрование
🔑 Два разных ключа: публичный и приватный
В асимметричном шифровании используются пара ключей:
• Публичный ключ – используется для шифрования. • Приватный ключ – используется для дешифрования.
Как работает?
- Отправитель получает публичный ключ получателя.
- Отправитель шифрует данные с помощью публичного ключа.
- Получатель дешифрует данные с помощью приватного ключа.
Примеры алгоритмов:
• RSA (Rivest-Shamir-Adleman) – один из самых распространенных алгоритмов. • ECC (Elliptic Curve Cryptography) – более безопасный при меньших размерах ключей. • DSA (Digital Signature Algorithm) – используется для цифровых подписей.
Плюсы
✅ Не нужно передавать секретный ключ, только публичный. ✅ Безопаснее, так как взлом требует вычисления обратного преобразования (например, факторизации больших чисел).
Минусы
❌ Медленнее, чем симметричное шифрование (из-за сложных математических операций). ❌ Менее эффективно при обработке больших объемов данных.
Основные отличия
| Симметричное шифрование | Асимметричное шифрование | |
|---|---|---|
| 🔑 Ключи | Один общий ключ | Пара ключей (публичный + приватный) |
| ⚡ Скорость | Быстрее | Медленнее |
| 🔐 Безопасность | Уязвимо при передаче ключа | Более безопасно |
| 🔁 Использование | Хорошо для шифрования больших данных | Используется для ключевого обмена и цифровых подписей |
| ### Когда что использовать? |
📌 Симметричное шифрование – для быстрого и эффективного шифрования больших объемов данных (например, файлов, дисков, VPN).
📌 Асимметричное шифрование – для безопасного обмена ключами, цифровых подписей, шифрования электронной почты (PGP), TLS/SSL в интернете.
💡 Гибридный подход: в реальных системах часто используется комбинация. Например, в HTTPS клиент и сервер сначала обмениваются ключами через асимметричное шифрование (RSA), а затем используют симметричное шифрование (AES) для передачи данных.
Вывод
• Симметричное шифрование быстрее, но требует безопасного обмена ключами. • Асимметричное шифрование медленнее, но решает проблему передачи ключей. • В реальных сценариях они часто используются вместе!
Что такое таблица маршрутизации?
Это таблица, содержащая маршруты для отправки пакетов в разные подсети и сети. Используется для выбора интерфейса и следующего хопа (gateway).
Проверка маршрута до IP 1.2.3.4:
traceroute 1.2.3.4
ip route get 1.2.3.4
IPTables: SNAT, DNAT, Маскарадинг
Основные таблицы:
1. Filter Table
- Используется по умолчанию.
- Для фильтрации пакетов (DROP, LOG, ACCEPT, REJECT).
- Цепочки:
- INPUT (пакеты для сервера)
- OUTPUT (исходящие локальные)
- FORWARD (транзитные)
2. NAT Table
- Для преобразования сетевых адресов.
- Только первый пакет потока проходит через эту таблицу.
- Цепочки:
- PREROUTING — DNAT
- POSTROUTING — SNAT
- OUTPUT — NAT для локально сгенерированных
3. Mangle Table
- Для изменения заголовков: TOS, TTL, MARK и др.
- Цепочки:
- PREROUTING, INPUT, FORWARD, OUTPUT, POSTROUTING
4. Raw Table
- До connection tracking (state machine)
- Цепочки: PREROUTING, OUTPUT
Цепочки IPTables:
- PREROUTING — до маршрутизации
- INPUT — для сервера
- FORWARD — транзитные
- OUTPUT — локальные исходящие
- POSTROUTING — после маршрутизации
Что означает запись 10.12.15.35/22?
CIDR-блок /22:
- Маска: 255.255.252.0
- Диапазон: 10.12.12.0 – 10.12.15.255
- Пример частной сети с 1024 адресами, 64 подсети.
DNS
Структура записи DNS (RR):
-
NAME — домен
-
TYPE — тип записи (A, AAAA, MX, CNAME...)
-
CLASS — тип сети (обычно IN)
-
TTL — срок жизни в кэше
-
RDLEN — длина данных
-
RDATA — содержимое
Типы записей:
-
A — IPv4 адрес
-
AAAA — IPv6 адрес
-
CNAME — псевдоним (каноническое имя)
-
MX — почтовый обменник
-
NS — DNS сервер зоны
-
PTR — обратная запись IP → имя
-
SOA — начальная запись зоны
-
SRV — серверы сервисов (например, для Jabber, Active Directory)
Рекурсивный и не рекурсивный запрос
При рекурсивном запросе Вы просто обращаетесь к серверу, а он, если не найдет у себя нужной записи, идет к другим серверам и спрашивает у них.
Нерекурсивный dns сервер в данном случае просто говорит - "я не знаю, но спроси у этого сервера". И клиент будет слать ещё один запрос. Понятное дело, что при медленном интернете первый вариант лучше.
Сетевые утилиты
Проверка открытых портов и сокетов
ss -tlpn
Проверка сетевых интерфейсов
ip a
Проверка маршрутов
ip route
NetCat (nc)
Проверка порта:
nc -vn 192.168.1.100 12345
Сканирование портов:
nc -vnz 192.168.1.100 20-24
Источник: https://habr.com/ru/post/336596/
Nmap
Поиск всех хостов в подсети:
nmap -sP 192.168.1.0/24
nmap -sn 192.168.1.0/24
Tcpdump
Пример:
tcpdump -i any -s0
-i— интерфейс-s— размер захвата пакета (0 — весь)
Docker
Как внутри Docker понять что ты в Docker?
1. Проверка файла /.dockerenv
test -f /.dockerenv && echo "Inside Docker"
• Плюсы: Надёжно, этот файл создаёт Docker при запуске контейнера. • Минусы: Некоторые среды (например, Kubernetes) могут не создавать этот файл.
Также, если ты используешь другой runtime (containerd, Podman), файл может отсутствовать.
2. Чтение cgroup
cat /proc/1/cgroup
Если ты видишь что-то вроде:
0::/docker/abc123...
или
1:name=systemd:/docker/abc123
— то ты, скорее всего, в Docker.
Пример проверки в bash:
grep -qE "/docker/|/kubepods/" /proc/1/cgroup && echo "Inside container"
• kubepods → ты внутри Kubernetes.
• docker → в Docker напрямую.
3. Проверка hostname
Иногда можно увидеть, что hostname = короткий случайный hash (Docker генерирует его как container ID). Пример:
hostname
Может быть что-то вроде 0a1b2c3d4e5f.
📌 Не надёжный способ, но может быть косвенным признаком.
⚠️ 4. Проверка ограничений cgroups
Если внутри контейнера у тебя:
cat /sys/fs/cgroup/memory/memory.limit_in_bytes
И значение сильно меньше, чем у твоей машины (например, 512MB или 1GB), ты, вероятно, в контейнере с ограничением ресурсов.
🧠 Какой способ лучше?
| Метод | Надёжность | Комментарий |
|---|---|---|
| /.dockerenv | ✅ Очень высокая | Стандарт для Docker |
| /proc/1/cgroup | ✅ Очень высокая | Работает и в k8s |
| hostname | ⚠️ Низкая | Косвенный признак |
| cgroup limits | ✅ | Полезно для анализа, но не строго |
🛠 Рекомендуемый способ (универсальный скрипт)
if [ -f /.dockerenv ] || grep -qa 'docker\|kubepods' /proc/1/cgroup; then
echo "Running inside a container"
else
echo "Not in container"
fi
В чем отличие CMD и ENTRYPOINT
Эти инструкции Dockerfile задают команду, исполняемую при запуске контейнера. При их использовании есть несколько правил, например:
- Должна быть минимум одна из них, CMD или ENTRYPOINT, в Dockerfile.
- Если контейнер используется как исполняемый файл — ENTRYPOINT должна быть определена.
- Если контейнер запускается с другими аргументами — CMD будет переопределена.
Инструкция RUN позволяет вам установить ваше приложение и необходимые для него пакеты. Он выполняет любые команды поверх текущего изображения и создает новый слой, фиксируя результаты. Часто в Dockerfile вы найдете несколько инструкций RUN.
Хорошей иллюстрацией инструкции RUN может быть установка нескольких пакетов систем контроля версий:
RUN apt-get update && apt-get install -y \
bzr \
cvs \
git \
mercurial \
subversion
Обратите внимание, что apt-get updateи apt-get installвыполняются в одной инструкции RUN. Это делается для того, чтобы убедиться, что будут установлены самые последние пакеты. Если бы apt-get installэто была отдельная инструкция RUN, то она бы повторно использовала слой, добавленный apt-get update, который мог быть создан давным-давно.
Инструкция CMD позволяет вам установить команду по умолчанию , которая будет выполняться только тогда, когда вы запускаете контейнер без указания команды. Если контейнер Docker запускается с командой, команда по умолчанию будет игнорироваться. Если Dockerfile содержит более одной инструкции CMD, все инструкции CMD, кроме последней, игнорируются.
CMD имеет три формы:
-
CMD ["executable","param1","param2"](исполнительная форма, предпочтительнее)
-
CMD ["param1","param2"]exec(устанавливает дополнительные параметры по умолчанию для ENTRYPOINT в форме
-
CMD command param1 param2(форма оболочки)
docker run -it <image> /bin/bash- тут при наличии CMD он будет проигнорирован, и будет запущен баш
Инструкция ENTRYPOINT позволяет настроить контейнер, который будет работать как исполняемый файл. Он похож на CMD, потому что также позволяет указать команду с параметрами. Разница заключается в том, что команда ENTRYPOINT и параметры не игнорируются, когда контейнер Docker запускается с параметрами командной строки. (Есть способ игнорировать ENTTRYPOINT, но вряд ли вы это сделаете.)
Докерфайл
ENTRYPOINT ["/bin/echo", "Hello"]
CMD ["world"]
когда контейнер запускается, как docker run -it <image>будет производиться вывод
Hello world
но когда контейнер запускается, docker run -it <image> Johnэто приведет к
Hello John
- Краткий ответ
cmd подставится после entrypoint при запуске. Тем самым можно запускать контейнер с нужными параметрами.
То есть в entrypoint можно передать бинарь, а в cmd передать параметры.
CMD может перетереться просто.
Что такое Docker? Как он устроен? На каких технологиях основывается?
Docker — это платформа контейнеризации, позволяющая запускать приложения в изолированной среде (контейнере).
Технологии: - cgroups и namespaces (пространства имён) для изоляции - union файловые системы (OverlayFS) - контейнерный движок containerd/runc
Пространства имён, используемые Docker:
- pid — изоляция процессов
- net — отдельные сетевые интерфейсы
- ipc — управление IPC-ресурсами (взаимодействие процессов)
- mnt — управление точками монтирования
- uts — имя хоста и домена (hostname)
Разница между Docker и VMware
- Docker — уровень ОС (использует ядро хоста, быстрая и лёгкая изоляция)
- VMware — полноценная виртуализация (каждая ВМ — своя ОС, медленнее, ресурсоёмко)
Зачем нужен Docker? Какие проблемы решает?
- Решает проблему "работает у меня, не работает у тебя"
- Позволяет создавать воспроизводимую среду
- Быстрое развёртывание и масштабирование приложений
Основные директивы Dockerfile
FROM— базовый образRUN— выполнение команд в контейнере при сборкеCOPY/ADD— копирование файловCMD/ENTRYPOINT— команда запускаEXPOSE— открытие портовENV— переменные окруженияWORKDIR— рабочая директория
Разница между Dockerfile и docker-compose
- Dockerfile — инструкция для создания образа
- docker-compose.yml — инструмент для описания и запуска многоконтейнерных приложений (описывает сервисы, сети, тома)
Как перенести docker image с одной машины на другую без registry?
docker save myimage > image.tar
scp image.tar user@remote:/tmp/
docker load < image.tar
Или:
docker export <container> > file.tar
# и далее docker import
Best practices по написанию Dockerfile и безопасности контейнеров
- Использовать минимальные образы (например,
alpine) - Указывать конкретные версии пакетов
- Не использовать root внутри контейнера
- Минимизировать количество слоёв
- Удалять временные файлы после установки пакетов
- Не хранить секреты в образах
- Использовать
USERдля запуска приложений - Ограничивать доступ к хосту (AppArmor, seccomp, read-only FS)
Сетевые драйверы Docker
- bridge — дефолтная сеть, контейнеры в одной подсети, могут общаться между собой через виртуальный bridge-интерфейс
- host — контейнер использует сетевой стек хоста
- macvlan — каждому контейнеру назначается отдельный MAC-адрес, прямой доступ к сети
- overlay — сеть между несколькими хостами (используется в Swarm)
- swarm — кластерная сеть для контейнеров, работающих в Swarm-режиме
В чем отличие ARG от ENV?
ENV позволяет создавать переменные окружения, которые будут работать во время работы контейнера.
ARG позволяет закинуть переменные, которые будут доступны во время сборки. Но они недоступны в контейнере. Однако через ARG можно задавать значения переменных по умолчанию для ENV
🧱 Как работают слои в Docker
Docker использует многоуровневую файловую систему (Union FS) — это означает, что каждый RUN, COPY, ADD создаёт отдельный слой, который накладывается поверх предыдущих.
✔️ Основные моменты:
• Каждый слой неизменяемый (immutable). • Новый слой ссылается на предыдущие и добавляет или переопределяет файлы. • Итоговый образ — это stack слоёв:
FROM python:3.10 # базовый слой
RUN apt install curl # + новый слой с curl
COPY . /app # + слой с приложением
🔗 Где тут хардлинки и симлинки?
⚙️ При сборке Docker образа:
• Docker использует copy-on-write и может применять хардлинки на уровне хостовой файловой системы (например, OverlayFS).
• Это позволяет экономить диск — одинаковые файлы не дублируются, а представляются как ссылки на один и тот же inode.
🧷 Разница между хардлинками и симлинками:
| Тип ссылки | Хардлинк | Симлинк |
|---|---|---|
| Что ссылается | На inode (сам файл) | На путь (имя файла) |
| После удаления оригинала | Файл остаётся | Ссылка “битая” |
| Видна в ls -li | Да, имеет одинаковый inode | Нет, свой inode |
| Используется в Docker | Да, но внутренне, на уровне слоёв | Иногда в COPY или вручную |
📁 Пример использования симлинков в Docker
RUN ln -s /usr/bin/python3 /usr/bin/python
• Создаётся симлинк внутри образа.
• Работает как обычный путь, но при копировании между слоями — это просто символическая ссылка.
🧠 Почему это важно на собеседовании
Ты можешь сказать примерно так:
Docker использует слоистую файловую систему, где каждый слой строится на предыдущем. Это обеспечивает кэширование и повторное использование слоёв. На уровне системы, Docker может использовать хардлинки между слоями, чтобы экономить диск и ускорить сборку. Симлинки используются внутри образов, но не влияют на кэш слоёв напрямую.
💡 Хинт для оптимизации:
Чтобы кэш Docker работал эффективно, нужно:
• Сначала ставить зависимости (requirements.txt) → потом копировать исходники.
• Объединять RUN-команды.
• Удалять ненужные файлы внутри одного слоя.
Хочешь, покажу пример Dockerfile до и после оптимизации с учётом слоёв и кэша?
Bash
Обработка access логов (CSV): timestamp, status, url, user-agent
Количество уникальных URL:
cut -d',' -f3 access.csv | sort | uniq | wc -l
Количество запросов на каждый URL:
cut -d',' -f3 access.csv | sort | uniq -c | sort -nr
Количество 400-404 по каждому URL:
awk -F',' '$2 ~ /^40[0-4]$/ {print $3}' access.csv | sort | uniq -c | sort -nr
Что делает set -eu -o pipefail?
Используется в начале bash-скриптов для надёжности:
- set -e — завершает скрипт, если любая команда завершилась с ошибкой.
- set -u — завершает скрипт, если используется необъявленная переменная.
- set -o pipefail — если одна из команд в пайпе завершилась с ошибкой, скрипт завершится.
- set -x (дополнительно) — выводит команды в stdout перед выполнением (для отладки).
Как выполнить одну и ту же команду на 50 серверах?
Варианты:
- С помощью ssh в цикле:
for host in $(cat hosts.txt); do
ssh user@$host 'команда' &
done
wait
- Использовать
pssh(parallel-ssh):
pssh -h hosts.txt -l user -i 'команда'
- Использовать Ansible:
ansible all -i hosts.ini -m shell -a 'команда'
- Использовать
tmux,dsh,fabricи другие инструменты массового управления.
Балансировщики нагрузки
Зачем нужны?
- Распределение нагрузки между приложениями
- Высокая доступность и отказоустойчивость
- Масштабируемость приложений
Nginx
Ошибки по статус-кодам
- 5xx — ошибка на стороне сервера (например, 500)
- 4xx — ошибка на стороне клиента (например, 400, 404, 413 — превышен размер запроса)
HTTP-методы, изменяющие состояние
POST,PUT,DELETE
Как Nginx решает проблему C10K?
За счёт событийно-ориентированной архитектуры: - неблокирующая модель - master + многопроцессная модель workers - каждый worker — однопоточный, обрабатывает тысячи соединений - минимизация переключений контекста (в отличие от Apache)
Важные параметры
worker_processes auto;
worker_connections 1024;
# max_clients = worker_processes * worker_connections
Как выбирается location?
Порядок:
1. = — точное совпадение
2. ^~ — приоритетный префикс
3. ~ / ~* — регулярные выражения (учитывает/не учитывает регистр)
4. Без модификаторов — префиксные совпадения
Как дебажить location?
- Логи:
access.log,error.log - Временный вывод переменных через
return,add_header - Консоль разработчика браузера
- Проверка фактического URI и проксируемого пути
Что реально приходит на приложение?
Проверить на стороне приложения (например, на localhost:3000) фактический URL запроса, заголовки и путь (X-Forwarded-For, X-Real-IP, Host)
Преимущества Nginx перед Apache
- Лучшая производительность при отдаче статики (x2.5)
- Эффективная архитектура (event loop против процессов)
- Меньшее потребление памяти
- Часто используется как frontend прокси к Apache/php-fpm и др.
Могут ли работать вместе?
Да. Пример связки: - Nginx — фронтенд, отдает статику, проксирует - Apache — бэкенд, генерирует динамику
HAProxy
- Высокопроизводительный L4/L7-балансировщик
- Поддержка TCP и HTTP
- Поддержка ACL, health checks, sticky sessions
- Часто используется в продакшене как фронтенд балансер
Envoy
- Прокси и сервис-меш от Lyft
- Поддерживает HTTP/2, gRPC, TLS termination
- Используется в Istio
- Расширенные возможности маршрутизации и мониторинга
Google Cloud Load Balancer
- Балансировка на уровне L4 и L7
- Автоматическое масштабирование и Anycast IP
- Интеграция с Cloud CDN, Cloud Armor
- Управляется через GCP Console или
gcloud
AWS Load Balancers
Classic Load Balancer (CLB)
- Устаревший, L4/L7
Application Load Balancer (ALB)
- L7 балансировка (HTTP/HTTPS)
- Поддержка path-based, host-based routing
Network Load Balancer (NLB)
- L4 балансировка (TCP/UDP)
- Высокая пропускная способность и низкая задержка
Обычно используется вместе с Auto Scaling и ECS/EKS
Прокси vs Реверс-прокси
Что такое прокси (forward proxy)?
Прокси-сервер действует от имени клиента: - Клиент отправляет запрос не напрямую к целевому серверу, а через прокси. - Прокси перенаправляет запрос и возвращает ответ обратно клиенту. - Пример: сотрудник офиса выходит в интернет через корпоративный прокси-сервер.
Используется для: - Контроля доступа (фильтрация) - Кеширования - Анонимизации - Обхода блокировок
Что такое реверс-прокси (reverse proxy)?
Реверс-прокси действует от имени сервера: - Клиент делает запрос на один публичный адрес. - Реверс-прокси принимает запрос и перенаправляет его одному из внутренних серверов. - Ответ возвращается клиенту от имени прокси.
Используется для: - Балансировки нагрузки - SSL termination - Кеширования - Ограничения доступа и аутентификации - Защиты внутренних сервисов
Сравнение
| Характеристика | Прокси | Реверс-прокси |
|---|---|---|
| Работает для кого? | От имени клиента | От имени сервера |
| Кто знает о нём? | Клиент | Сервер (а клиент — нет) |
| Основная задача | Доступ к внешним ресурсам | Защита и маршрутизация к внутренним ресурсам |
| Пример | Squid | Nginx, HAProxy, Envoy |
| ## Kubernetes |
Architecture
Kubernetes-кластер построен по распределённой архитектуре и состоит из двух основных типов компонентов: Control Plane (плоскость управления) и Worker Nodes (рабочие узлы). Эти части взаимодействуют между собой, обеспечивая автоматизированное развертывание контейнеров, масштабирование, балансировку нагрузки и восстановление после сбоев.
-
Control Plane — отвечает за глобальное управление кластером. Он принимает решения о размещении Pod’ов, отслеживает состояние системы и обеспечивает соответствие текущего состояния — желаемому. Включает в себя несколько ключевых компонентов:
- kube-apiserver — центральная точка входа в кластер. Обрабатывает все REST-запросы (kubectl, контроллеры и т.д.), валидирует их и взаимодействует с другими компонентами через API.
- etcd — распределённое key-value хранилище, где сохраняется всё состояние кластера: манифесты объектов, конфигурации, секреты и др.
- kube-scheduler — определяет, на какие ноды размещать новые Pod’ы, основываясь на доступных ресурсах и заданных правилах.
- kube-controller-manager — управляет контроллерами (Deployment, ReplicaSet, Node и др.), следя за тем, чтобы система соответствовала желаемому состоянию.
- (опционально) cloud-controller-manager — взаимодействует с API облачного провайдера (например, AWS или GCP), управляя такими ресурсами, как балансировщики, маршруты и диски.
-
Worker Nodes — это узлы, на которых фактически запускаются контейнеры. Каждый node включает:
- kubelet — агент, взаимодействующий с API Server и отвечающий за запуск и мониторинг Pod’ов на узле.
- container runtime (например, containerd, cri-o) — низкоуровневый компонент, запускающий контейнеры.
- kube-proxy — обеспечивает сетевую маршрутизацию между Pod’ами и доступ к сервисам, настраивая правила iptables/ipvs.
Таким образом, Control Plane управляет кластером как системой, а Worker Nodes исполняют рабочие нагрузки (контейнеры), подчиняясь этим правилам и решениям.
Что происходит при kubectl apply
- 💬 Клиент
kubectlсчитывает манифест:
bash
kubectl apply -f my-deployment.yaml
Считывается YAML-файл, описывающий желаемое состояние объекта (например, Deployment, Service и т.д.)
- 📤
kubectlотправляет запрос в API Server:
Манифест отправляется через HTTP-запрос к API Server — это центральная точка взаимодействия в Kubernetes.
-
🔍 API Server сравнивает текущее и желаемое состояние:
-
API Server проверяет, существует ли объект уже в
etcd(через свой внутренний слой хранения). - Если объект уже существует — выполняется \"patch\" (обновление), сохраняются только изменения.
- Если объекта ещё нет — он создаётся с нуля.
kubectl applyиспользует \"server-side apply\" или \"client-side apply\" (в зависимости от версии и флагов) — это способ вычислить, какие поля нужно обновить.
- 📦
etcdобновляет хранилище состояния:
API Server сохраняет обновлённое состояние объекта в etcd — распределённой key-value базе.
- ⚙️ Контроллеры приводят кластер к нужному состоянию:
Если применён объект типа Deployment:
- Deployment Controller обнаруживает изменения.
- Создаёт или удаляет ReplicaSet.
- ReplicaSet создаёт или удаляет Pod'ы.
- 🔁 Scheduler размещает новые Pod'ы:
Если нужно создать новые Pod'ы: - Scheduler выбирает подходящий Worker Node. - Назначает Pod на выбранный узел.
- 🧩 Kubelet запускает контейнеры:
На выбранной ноде: - Kubelet получает инструкции от API Server. - Запускает контейнеры через Container Runtime (например, containerd, cri-o, Docker).
- 🌐 Kube Proxy настраивает сеть:
Если объект включает в себя сервис или взаимодействие по сети: - Kube Proxy обновляет сетевые правила (iptables/ipvs). - Обеспечивает доступ к Pod'ам по сервису.
QOS (Pod Quality of Service Classes)
QoS-класс определяет приоритет Pod’а при вытеснении (eviction), а также влияет на поведение в случае давления по CPU/памяти. (QoS) в Kubernetes — это один из ключевых механизмов, который влияет на то, как kubelet управляет Pod-ами, особенно при нехватке ресурсов.
В Kubernetes есть три класса QoS:
1. Guaranteed
✅ Наивысший приоритет, вытесняется в последнюю очередь.
Условия:
• Для всех контейнеров в Pod-е заданы requests и limits, и они равны друг другу.
resources:
requests:
memory: "512Mi"
cpu: "500m"
limits:
memory: "512Mi"
cpu: "500m"
Такой Pod получает гарантированный кусок ресурсов и защищён от вытеснения при OOM (Out of Memory) до последнего.
2. Burstable
⚠️ Средний приоритет.
Условия:
• У некоторых контейнеров заданы requests, и:
• либо они не равны limits,
• либо limits не заданы вовсе.
resources:
requests:
memory: "256Mi"
cpu: "250m"
limits:
memory: "512Mi"
cpu: "1"
Такой Pod получает доступ к гарантированным ресурсам (requests), но может использовать больше при наличии свободных ресурсов на узле.
3. BestEffort
❌ Наименьший приоритет, вытесняется первым.
Условия:
• У ни одного контейнера нет requests и limits.
resources: {}
Этот Pod работает «на удачу» — использует то, что осталось на узле. Он первым попадает под OOM killer.
Как проверить QoS класс у уже запущенного Pod?
kubectl get pod <pod-name> -o jsonpath='{.status.qosClass}'
Управление шедулингом в Kubernetes: Tolerations, Affinity, Labels и назначение Pod'ов на ноды
В Kubernetes автоматическое размещение Pod'ов на ноды происходит через scheduler. Чтобы управлять этим процессом, можно использовать labels, tolerations, taints, node affinity, pod affinity/anti-affinity.
1. Labels (лейблы)
Лейблы — это пары ключ/значение, которые можно назначать как Pod'ам, так и нодам. Они служат основой для:
- выбора подходящих нод (через nodeAffinity);
- группировки и фильтрации ресурсов (например, при kubectl get pods -l app=frontend);
- определения соседства между Pod'ами (podAffinity, antiAffinity);
- назначения сервисов (selector).
metadata:
labels:
app: \"frontend\"
disktype: \"ssd\"
2. Taints и Tolerations
- Taint — это метка на ноде, которая не позволяет размещать на ней Pod'ы, если только у Pod'а нет соответствующей toleration.
- Используются для защиты нод, на которых должны работать только определённые приложения (например, GPU-ноды или системные).
kubectl taint nodes my-node key=value:NoSchedule
- Это значит: не размещай Pod'ы на
my-node, если у них нетtolerationдляkey=value.
Пример Toleration в Pod-манифесте:
tolerations:
- key: \"key\"
operator: \"Equal\"
value: \"value\"
effect: \"NoSchedule\"
3. Node Affinity
Позволяет предпочесть или требовать размещение Pod'а на ноде с определёнными лейблами.
Типы Node Affinity:
- requiredDuringSchedulingIgnoredDuringExecution — обязательное условие.
- preferredDuringSchedulingIgnoredDuringExecution — желательное, но не строгое.
Пример:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: \"disktype\"
operator: \"In\"
values:
- \"ssd\"
Этот Pod может быть размещён только на нодах с меткой
disktype=ssd.
4. Pod Affinity / Anti-Affinity
Управление тем, рядом с какими Pod'ами может (или не может) быть размещён новый Pod. Использует лейблы других Pod'ов.
Pod Affinity (соседство):
affinity:
podAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: \"app\"
operator: \"In\"
values:
- \"frontend\"
topologyKey: \"kubernetes.io/hostname\"
Под будет размещён на той же ноде, где уже есть Pod с меткой
app=frontend.
Pod Anti-Affinity (разделение):
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: \"app\"
operator: \"In\"
values:
- \"frontend\"
topologyKey: \"kubernetes.io/hostname\"
Под не будет размещён на той же ноде, где уже есть другой
frontendPod.
Kubernetes предоставляет гибкие механизмы управления размещением Pod'ов: - Labels — фундаментальный инструмент для выбора, группировки и фильтрации ресурсов. - Taints/Tolerations — позволяют исключать неподходящие ноды. - Affinity/Anti-Affinity — дают контроль над предпочтениями и ограничениями по нодам и другим Pod'ам.
Грамотная настройка этих параметров позволяет добиться надёжности, предсказуемости и оптимального использования кластера.
Pod Lifecycle
Жизненный цикл Pod-а. Это основа для понимания, как Pod-ы создаются, переходят между состояниями, завершаются и удаляются.
🚦 Жизненный цикл Pod-а
📌 Основные состояния (PodPhase):
Это высокоуровневые стадии, которые можно увидеть через kubectl get pod.
- Pending — Pod был принят API сервером, но ещё не запущен (например, ждёт скачивания образов или размещения на ноде).
- Running — хотя бы один контейнер запущен, и Pod успешно размещён.
- Succeeded — все контейнеры завершились успешно (с кодом 0), и Pod не будет перезапускаться.
- Failed — хотя бы один контейнер завершился неуспешно, и Pod не может быть перезапущен.
- Unknown — kubelet не может определить статус (обычно из-за сетевых проблем).
📌 Состояния контейнеров (ContainerState)
Каждый контейнер внутри Pod-а может быть в:
• Waiting — ожидает запуска. Причины можно увидеть в .state.waiting.reason (например, CrashLoopBackOff, ImagePullBackOff).
• Running — контейнер успешно запущен.
• Terminated — контейнер завершил выполнение (по exit code или сигналу).
Пример:
kubectl get pod mypod -o jsonpath='{.status.containerStatuses[*].state}'
🔁 Restart Policy
Указывается в манифесте Pod-а. Возможные значения:
• Always (по умолчанию, используется в Deployment)
• OnFailure (для Job)
• Never
Это влияет на то, будет ли kubelet перезапускать контейнер при сбое.
🔄 Container Lifecycle Hooks
Можно задать обработчики событий:
lifecycle:
postStart:
exec:
command: ["/bin/sh", "-c", "echo Hello from postStart"]
preStop:
exec:
command: ["/bin/sh", "-c", "echo Goodbye from preStop"]
• postStart — вызывается после запуска контейнера, но до его marked as Running. • preStop — вызывается до завершения контейнера (например, при kubectl delete pod или Scale down).
⏱ Termination Grace Period
• По умолчанию: 30 секунд.
• Kubernetes отправляет SIGTERM, ждёт terminationGracePeriodSeconds, затем — SIGKILL.
terminationGracePeriodSeconds: 10
📉 Final Pod Termination Flow
- kubelet отправляет SIGTERM контейнерам.
- Ждёт terminationGracePeriodSeconds.
- Выполняется preStop hook (если есть).
- По истечении времени — SIGKILL.
- Pod удаляется из etcd (если без finalizer).
preStop && finalizer
Иногда выполняют похожие задачи (что-то “почистить перед удалением”), но они работают на совершенно разных уровнях. Давай разберёмся по-честному, без воды:
🔁 Кратко: разница между preStop и finalizer
| preStop hook | finalizer | |
|---|---|---|
| Уровень | Уровень контейнера внутри Pod-а | Уровень Kubernetes-объекта (Pod, PVC, CRD и т.п.) |
| Когда вызывается | Перед остановкой контейнера (например, SIGTERM) | При удалении объекта, но до физического удаления |
| Кто исполняет | kubelet на ноде | Контроллер (например, твой оператор/внешний процесс) |
| Для чего нужен | Подготовить контейнер к остановке (напр., завершить соединения) | Выполнить финальную логику: удалить ресурсы, почистить связи |
| Можно ли “зависнуть” | Нет — ограничен terminationGracePeriod | Да — пока не удалишь finalizer, объект не удалится |
| Работает при kill -9? | ❌ Нет — SIGKILL игнорирует preStop | ✅ Да, потому что finalizer выше по уровню |
🔍 Примеры сценариев
preStop:
• Подключено 100 клиентов к веб-серверу. preStop может:
• отправить сигнал приложению: «заверши активные соединения»;
• дождаться 10 секунд;
• завершиться сам.
lifecycle:
preStop:
exec:
command: ["/bin/sh", "-c", "echo 'shutting down' >> /log"]
Это выполняется в контейнере, как скрипт или команда.
finalizer:
• У тебя Pod, при удалении которого нужно удалить запись из внешней БД, освободить IP-адрес, уведомить систему логирования.
• Эти действия нельзя сделать изнутри Pod-а, ты хочешь делать это в контроллере.
metadata:
finalizers:
- cleanup.mycompany.com
Пока контроллер не уберёт этот finalizer — Pod не удалится.
🎯 Ключевые различия в использовании
| Вопрос | Использовать |
|---|---|
| Нужно что-то сделать внутри контейнера перед его остановкой? | ✅ preStop |
| Нужно удалить внешний ресурс или логически “попрощаться” с объектом на уровне кластера? | ✅ finalizer |
🩺 Probes
Probes — это специальные проверки, которые Kubernetes выполняет, чтобы понять:
• жив ли контейнер (livenessProbe)
• готов ли контейнер принимать трафик (readinessProbe)
• запустился ли контейнер корректно (startupProbe)
Они помогают kubelet принимать решения:
• Перезапустить ли контейнер?
• Начать ли направлять на него трафик?
• Подождать ли подольше, если сервис стартует долго?
🔍 1. livenessProbe
“Контейнер завис? Надо перезапустить.”
Если livenessProbe неудачна — kubelet перезапускает контейнер.
Пример:
livenessProbe:
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 5
periodSeconds: 10
🕒 2. readinessProbe
“Готов ли контейнер принимать запросы?”
Если readinessProbe неудачна — Pod выводится из service endpoints (на него не будет идти трафик).
Пример:
readinessProbe:
exec:
command: ["cat", "/tmp/ready"]
initialDelaySeconds: 2
periodSeconds: 5
🐢 3. startupProbe
“Дай контейнеру больше времени на запуск — не убивай его раньше времени.”
Полезно для медленно стартующих приложений. До тех пор, пока startupProbe не прошла, Kubernetes не выполняет livenessProbe. То есть она защищает от ложных срабатываний.
startupProbe:
httpGet:
path: /startup
port: 8080
failureThreshold: 30
periodSeconds: 10
В этом примере даётся ~5 минут на запуск (30 × 10 секунд).
🔧 Типы probe’ов:
• httpGet — делает HTTP GET-запрос и проверяет код ответа (200-399 — успех).
• exec — выполняет команду внутри контейнера.
• tcpSocket — проверяет TCP-порт на доступность.
🧠 Когда использовать что:
| Задача | Использовать |
|---|---|
| Перезапустить зависший контейнер | livenessProbe |
| Управлять трафиком к Pod’у | readinessProbe |
| Дать приложению время на запуск | startupProbe |
| #### В какой последовательности работают пробы (startupProbe, readinessProbe, livenessProbe) |
✅ Очередность и логика работы
- startupProbe — первая запускается
• Используется, чтобы дать приложению время “проснуться” (например, если долго стартует).
• Пока startupProbe не успешна, ни liveness, ни readiness не запускаются.
• Если startupProbe проваливается, контейнер считается “неживым” и перезапускается.
- readinessProbe — включается после startupProbe
• Проверяет, готов ли контейнер обслуживать запросы (например, подключился к БД, прогрел кэш и т.д.).
• Пока readinessProbe не проходит, Pod не получает трафик от сервисов.
• Даже если контейнер жив, но не готов — сервис не будет к нему направлять запросы.
- livenessProbe — также запускается после startupProbe
• Проверяет, жив ли контейнер (например, не завис ли, не утёк ли в вечную обработку).
• Если livenessProbe проваливается, контейнер перезапускается.
📌 Важные детали
• После того как startupProbe прошла, она больше не запускается.
• readinessProbe и livenessProbe продолжают выполняться периодически всё время, пока контейнер жив.
• readinessProbe может возвращать “не готов”, например, если БД недоступна — и в это время сервис перестаёт слать трафик на этот pod.
• livenessProbe провалилась → kubelet рестартит контейнер.
🔁 Тайминги
Ты можешь задать параметры для всех проб:
• initialDelaySeconds — сколько подождать перед первой проверкой.
• periodSeconds — интервал между проверками.
• timeoutSeconds — сколько ждать ответа.
• failureThreshold — сколько раз подряд должно не пройти, чтобы считать контейнер неработающим.
🧠 На собесе можно сказать:
Kubernetes запускает startupProbe, чтобы убедиться, что контейнер успеет инициализироваться. Пока она не прошла, readiness и liveness не работают. После успешного старта readinessProbe управляет трафиком, а livenessProbe следит, чтобы контейнер не повис. Это разделение позволяет избегать лишних рестартов при долгом старте приложения.
InitContainers
initContainer — это специальный контейнер, который выполняется до основного контейнера в Pod-е. Он завершает свою работу, и только после этого запускаются обычные containers.
🔑 Ключевые особенности:
• Выполняются последовательно, в порядке их объявления. • Каждый должен успешно завершиться (exit 0) — иначе Pod остаётся в состоянии Init. • Имеют отдельные образы и команды от основного контейнера. • Могут монтировать те же тома, что и основной контейнер.
🧪 Зачем использовать initContainers?
• Задержка старта, пока не готов внешний сервис (БД, Redis).
• Копирование файлов в volume перед стартом приложения.
• Генерация конфигураций, ключей, секретов.
• Прогрев кэша или база данных миграций.
🔧 Пример: Ожидание БД перед стартом приложения
apiVersion: v1
kind: Pod
metadata:
name: app-with-init
spec:
initContainers:
- name: wait-for-db
image: busybox
command: ['sh', '-c', 'until nc -z db 5432; do echo waiting for db; sleep 2; done']
containers:
- name: main-app
image: myapp:latest
ports:
- containerPort: 80
Этот initContainer будет проверять доступность базы данных на порту 5432. Как только она станет доступна — приложение стартует.
📁 Пример: копирование файлов в том
spec:
volumes:
- name: config-volume
emptyDir: {}
initContainers:
- name: copy-config
image: busybox
command: ['sh', '-c', 'cp /etc/config/* /config/']
volumeMounts:
- name: config-volume
mountPath: /config
- name: config-source
mountPath: /etc/config
containers:
- name: app
image: myapp
volumeMounts:
- name: config-volume
mountPath: /app/config
🧠 Советы: • Лучше использовать initContainers, чем городить логику ожидания или подготовки в основном контейнере. • Они хорошо сочетаются с emptyDir и другими volume-типами. • Можно использовать разные образы, в т.ч. alpine, busybox, curlimages/curl для утилит.
Service Mesh
Это слой инфраструктуры, который управляет сетевыми коммуникациями между сервисами в распределённой системе.
Он отвечает за:
• 📦 Service-to-Service communication (обмен трафиком) • 🔒 Шифрование трафика (MTLS) • 🎯 Routing & Canary (маршрутизация, A/B, Canary) • 📊 Наблюдаемость (метрики, трассировки, логи) • 🔁 Retry, timeout, circuit breaker (механики надёжности) • 🚦 Policy control (авторизация, ACL)
🔧 Как работает?
Ключевая идея — Sidecar Proxy.
Каждому Pod-у автоматически добавляется прокси-контейнер (обычно Envoy), через который весь трафик между сервисами идёт:
[service A] <=> [Envoy A] <===> [Envoy B] <=> [service B]
Управляется централизованно через control-plane (например, Istiod в Istio).
🎯 Зачем нужен?
| Без Service Mesh | С Service Mesh |
|---|---|
| Сам пишешь retry, timeout | Задаёшь в YAML, работает из коробки |
| TLS надо встраивать в код | MTLS автоматом между сервисами |
| Логика маршрутизации в коде | Traffic shifting через CRD |
| Метрики в app | Авто-интеграция с Prometheus/Grafana/Jaeger |
| Manual discovery | Встроенное сервис-обнаружение |
🛠 Примеры популярных Service Mesh
Istio (де-факто стандарт, мощный, но тяжеловат)
• Control-plane: istiod
• Data-plane: Envoy
• CRD’ы: VirtualService, DestinationRule, Gateway, AuthorizationPolicy, и др.
• Сильная поддержка MTLS, трассировки, observability.
🧪 Пример: управление маршрутом в Istio
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: reviews-route
spec:
hosts:
- reviews
http:
- route:
- destination:
host: reviews
subset: v1
weight: 90
- destination:
host: reviews
subset: v2
weight: 10
90% трафика пойдёт в v1, 10% — в v2. Это пример canary deployment без изменения кода.
🔐 MTLS — всё шифруется автоматически
Трафик между Pod-ами автоматически зашифрован, и можно включать политику Zero Trust — только определённые сервисы могут общаться.
apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
name: default
spec:
mtls:
mode: STRICT
📊 Observability из коробки
Сбор метрик, логов, трассировок:
• 📈 Prometheus / Grafana
• 🔎 Kiali (визуализация mesh-а)
• 🧵 Jaeger / Zipkin (трассировки)
🔧 Service
| Тип | Внешний доступ | Где используется | Пример подключения |
|---|---|---|---|
| ClusterIP | ❌ Нет | Внутри кластера | curl my-svc.default.svc.cluster.local |
| NodePort | ✅ Да | Bare-metal, Minikube | curl http://<\NodeIP>:30080 |
| LoadBalancer | ✅ Да (облако) | GKE, EKS, AKS, MetalLB | curl http://\<\EXTERNAL-IP> |
| ExternalName | ⚠️ Через DNS | Доступ к внешним сервисам | curl http://external-service.local (CNAME) |
| Headless | ❌ Нет (IP нет) | StatefulSet, Service Discovery | dig my-svc.default.svc.cluster.local → IP подов |
Это базовый ресурс Kubernetes, который обеспечивает:
• сервис-дискавери по имени (DNS), • стабильный IP, • маршрутизацию трафика на Pod-ы по label’ам.
apiVersion: v1
kind: Service
metadata:
name: reviews
spec:
selector:
app: reviews
ports:
- port: 80
targetPort: 8080
Все Pod-ы с app=reviews получат трафик через этот Service.
🧱 ClusterIP (по умолчанию)
apiVersion: v1
kind: Service
metadata:
name: my-svc
spec:
selector:
app: my-app
ports:
- port: 80 # Внутри кластера
targetPort: 8080
- Описание: Доступен только внутри кластера.
- Применение: Для связи между подами разных приложений.
- Пример использования: Бэкенд-сервис, к которому обращается фронтенд.
spec:
type: ClusterIP
🌐 NodePort
apiVersion: v1
kind: Service
metadata:
name: my-nodeport-svc
spec:
type: NodePort
selector:
app: my-app
ports:
- port: 80
targetPort: 8080
nodePort: 30080
Доступ: http://<NodeIP>:30080
- Описание: Открывает порт на всех нодах кластера.
- Доступ извне: Да, по IP-адресу ноды и указанному порту.
- Диапазон портов: 30000–32767 (по умолчанию).
- Применение: Простой способ опубликовать приложение наружу без Ingress.
🌎 LoadBalancer
apiVersion: v1
kind: Service
metadata:
name: my-lb-svc
spec:
type: LoadBalancer
selector:
app: my-app
ports:
- port: 80
targetPort: 8080
В облаках — выдаст EXTERNAL-IP через kubectl get svc
- Описание: Создает внешний балансировщик нагрузки (обычно в облаке).
- Применение: Доступ к сервису из интернета, production-ready подход.
- Зависимость: Работает при наличии интеграции с облачным провайдером (GKE, EKS, AKS и др).
🔗 ExternalName
spec:
type: ExternalName
externalName: my.external.service.com
- Описание: Проксирует запросы к внешнему DNS-имени.
- Применение: Используется для обращения к внешним сервисам через DNS, как будто это обычный сервис в кластере.
- Особенность: Не создает собственный IP, работает через CNAME.
🧪 Headless Service
spec:
clusterIP: None
- Описание: Не назначает IP-адрес; возвращает список IP подов.
- Применение: Используется для сервисов, где важен прямой доступ к подам, например, StatefulSet, сервис discovery.
- Особенность: Вместо баланса — полное управление с клиентской стороны.
🔧 Дополнительные сценарии
Не являются новыми типами, но часто используются
- Ingress — не сервис, а контроллер маршрутизации. Используется для HTTP/HTTPS входа и более гибкого роутинга.
- Service Mesh (например, Istio, Linkerd) — добавляют абстракции над сервисами, например, виртуальные сервисы, маршруты на уровне L7.
- MetalLB / Kube-vip — расширяют возможности LoadBalancer в on-premise кластерах, где нет встроенного облачного балансировщика.
🕹 Istio VirtualService
Это ресурс уровня Istio, который определяет:
• Как именно маршрутизировать трафик внутри Service • Делать canary, A/B, header-based routing и т.д. • Управлять retry, timeout, fault injection и т.п.
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: reviews-routing
spec:
hosts:
- reviews
http:
- match:
- headers:
end-user:
exact: test-user
route:
- destination:
host: reviews
subset: v2
- route:
- destination:
host: reviews
subset: v1
Это правило: если юзер — test-user, отдать reviews:v2, иначе — v1.
🔄 Как они работают вместе
• Service — отвечает за “куда”: набор Pod-ов (endpoints)
• VirtualService — отвечает за “как”: правила маршрутизации, версии, условия
Трафик идёт так:
Client → Kubernetes Service → Istio Proxy (Envoy) → VirtualService → Target Pod
📦 А что такое subset?
Чтобы VirtualService мог выбрать v1, v2, ты должен создать DestinationRule:
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
name: reviews-dest
spec:
host: reviews
subsets:
- name: v1
labels:
version: v1
- name: v2
labels:
version: v2
Теперь Istio сможет направлять трафик только на те Pod-ы, у которых version: v1 или v2.
Ingress
Kubernetes ресурс, который описывает правила входа HTTP/HTTPS-трафика в кластер и маршрутизацию к сервисам.
Пример:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-ingress
spec:
rules:
- host: mysite.local
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: my-service
port:
number: 80
📌 Но сам Ingress ничего не делает без контроллера!
🎮 Ingress Controller — что это?
Приложение (под/деплоймент), которое читает ресурсы Ingress и настраивает прокси-сервер (например, NGINX) для обработки внешнего трафика.
Популярные контроллеры:
• nginx-ingress ✅ (де-факто стандарт)
• traefik
• HAProxy
• Istio Gateway (в рамках Istio)
• AWS ALB Controller (в AWS)
🔁 Как это работает:
[Браузер]
↓ HTTP/HTTPS
[Ingress Controller Pod (например, NGINX)]
↓
[Ingress rules → Service → Pod]
📌 Что делает Ingress:
• Правила маршрутизации (host + path)
• Поддержка HTTPS (через TLS-секреты)
• Может использовать аннотации для настроек (timeouts, redirects и т.д.)
📌 Что делает Ingress Controller:
• Слушает порт (80/443)
• Считывает Ingress-объекты
• Настраивает внутренний прокси (например, nginx.conf)
• Обрабатывает входящие соединения
🧠 Кратко:
| Компонент | Роль |
|---|---|
| Ingress | Правила маршрутизации |
| Ingress Controller | Прокси, который эти правила реализует |
ReplicaSet (низкоуровневый)
Поддерживает заданное количество Pod-ов. Сам по себе редко используется напрямую.
apiVersion: apps/v1
kind: ReplicaSet
spec:
replicas: 3
• Обеспечивает: N реплик • Не поддерживает обновления, стратегии, rollback • Используется внутри Deployment
📌 Не используй напрямую — почти всегда используешь Deployment.
Deployment (стандарт для stateless приложений)
Самый популярный контроллер. Обеспечивает масштабируемость, обновления, откат.
apiVersion: apps/v1
kind: Deployment
spec:
replicas: 3
strategy:
type: RollingUpdate
• Позволяет обновлять версии без даунтайма
• Есть стратегии обновления (RollingUpdate, Recreate)
• Поддерживает rollback, pause, resume
📌 Используется для web-приложений, API, сервисов.
DaemonSet
Запускает по одному Pod-у на каждой Node.
apiVersion: apps/v1
kind: DaemonSet
• Полезен для: логгера, мониторинга, агента (Prometheus, Fluentd)
• Новые ноды автоматически получают Pod
• Без replicas — он сам знает, сколько нод
📌 Используется для инфраструктурных компонентов.
StatefulSet
Используется для stateful-приложений (БД, кэш, очереди), где важен порядок и имена Pod-ов.
apiVersion: apps/v1
kind: StatefulSet
spec:
serviceName: my-headless
• Поддерживает стабильные имена Pod-ов: mongo-0, mongo-1
• Использует PersistentVolumeClaim templates
• Запускает/удаляет Pod’ы поочерёдно
📌 Используется для: PostgreSQL, Cassandra, Kafka, Redis Cluster
Job
Выполняет одиночную задачу, дожидается завершения.
apiVersion: batch/v1
kind: Job
spec:
completions: 1
• Создаёт Pod для выполнения задачи
• Повторяет, если задача неуспешна
• Сам удаляется по завершении (или можно сохранить логи)
📌 Используется для: миграций, импортов, аналитических задач
CronJob
Периодически запускает Job по расписанию (cron-выражение)
apiVersion: batch/v1
kind: CronJob
spec:
schedule: "*/5 * * * *"
📌 Используется для: бэкапов, проверок, периодических отчётов
Pod controllers comparation
| Контроллер | Масштабируемость | Хранит стейт | Периодичность | Одна задача | Пример использования |
|---|---|---|---|---|---|
| Deployment | ✅ Да | ❌ Нет | ❌ Нет | ❌ Нет | web-app, API, worker |
| ReplicaSet | ✅ Да | ❌ Нет | ❌ Нет | ❌ Нет | (внутри Deployment) |
| DaemonSet | ❌ 1 на Node | ❌ Нет | ❌ Нет | ❌ Нет | node exporter, log-агенты |
| StatefulSet | ✅ Да | ✅ Да | ❌ Нет | ❌ Нет | PostgreSQL, Redis cluster |
| Job | ❌ (один запуск) | ❌ Нет | ❌ Нет | ✅ Да | миграция, ETL, init-task |
| CronJob | ❌ | ❌ Нет | ✅ Да | ✅ Да | бэкап каждые N минут |
PVC
PVC (PersistentVolumeClaim) — это заявка от Pod-а на хранилище. Это как “бронирование диска”: ты говоришь, какой объём и доступ тебе нужен — а Kubernetes сам выделяет подходящее хранилище (PersistentVolume) или создаёт его (в случае dynamic provisioning).
🧱 Компоненты хранения в Kubernetes
- PersistentVolume (PV) — физический или логический диск (долговечный том).
- PersistentVolumeClaim (PVC) — запрос от Pod-а: “дай мне диск на 1Gi, с RW доступом”.
- StorageClass — шаблон, описывающий, как именно создавать PV (например, тип диска в облаке: SSD, HDD, reclaim policy и т.п.).
🔄 Жизненный цикл: как всё связано
Pod → PersistentVolumeClaim (PVC) → PersistentVolume (PV) → Physical disk (GCE, EBS, NFS, Ceph, etc)
🔧 Пример 1: Простой PVC + Pod
📄 PVC:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: my-pvc
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
📄 Под, использующий этот PVC:
apiVersion: v1
kind: Pod
metadata:
name: my-pod
spec:
containers:
- name: app
image: nginx
volumeMounts:
- name: my-storage
mountPath: /usr/share/nginx/html
volumes:
- name: my-storage
persistentVolumeClaim:
claimName: my-pvc
📦 Контейнер получает путь /usr/share/nginx/html, примонтированный из PVC.
📚 Ключевые параметры PVC
| Параметр | Значение |
|---|---|
| storage | Сколько нужно (например, 1Gi) |
| accessModes | ReadWriteOnce, ReadOnlyMany, ReadWriteMany |
| volumeMode | Filesystem (по умолчанию) или Block |
| storageClassName | Какой StorageClass использовать |
🔁 Static vs Dynamic provisioning
| Тип | Что происходит |
|---|---|
| Static | Админ заранее создаёт PV, ты делаешь PVC и ждёшь совпадения по параметрам |
| Dynamic ✅ | PVC автоматически вызывает StorageClass, который создаёт PV на лету (например, EBS в AWS, Persistent Disk в GCP) |
📄 Пример: PVC с StorageClass
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: fast-storage
spec:
storageClassName: "fast-ssd"
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 5Gi
🧠 Как посмотреть:
kubectl get pvc
kubectl describe pvc my-pvc
kubectl get pv
Статус PVC должен быть Bound, если всё ок.
🗑 Reclaim Policy (что делать после удаления PVC)
• Delete — PV будет удалён вместе с PVC (часто в динамическом сценарии)
• Retain — диск останется, нужно очищать вручную
• Recycle (устаревший)
📦 Где используются PVC?
• Базы данных (PostgreSQL, MongoDB)
• CMS (WordPress)
• Кэш (Redis с persistence)
• Хостинг статики в Nginx
• Kafka, MinIO, Ceph, и т.д.
GitOps vs Helm
🎯 Суть обоих подходов:
| Подход | Что делает |
|---|---|
| Helm CLI | Ты вручную применяешь Helm чарты с локальной машины или CI/CD |
| GitOps | Ты хранишь всё в Git, а оператор в кластере сам синхронизирует состояние |
⚙️ Как работает каждый подход
📦 1. Helm deployment (классический)
• Ты запускаешь команду:
helm upgrade --install my-app ./chart --values values.yaml
• Или через CI (например, GitLab CI).
• Helm устанавливает/обновляет всё напрямую в кластер.
• Состояние — в Helm и в кластере, не обязательно в Git.
🔻 Проблемы:
• Нет 100% гарантий, что Git = кластер.
• Нужно самому следить за порядком обновлений.
• Можно “вмешаться вручную” и не зафиксировать в Git.
🔁 2. GitOps (ArgoCD, FluxCD)
• Ты кладёшь манифесты или Helm values в Git.
• Git = источник правды.
• В кластере работает оператор (ArgoCD/Flux), который:
• Смотрит в Git
• Применяет манифесты/Helm чарты в кластер
• Следит, чтобы кластер всегда соответствовал Git
Git → автосинхронизация → кластер
📊 Сравнение по ключевым аспектам:
| Категория | GitOps | Helm (ручной) |
|---|---|---|
| 🧠 Источник правды | Git | Helm state / CI конфигурация / память |
| 🔁 Автоматичность | Да (pull model) | Нет (push model) |
| 🔒 Безопасность доступа | Не нужен доступ к кластеру — только Git | Требуется доступ к кластеру |
| 🛠 Откат изменений | Git revert → автооткат | Надо вручную запускать helm rollback |
| 👀 Observability | UI (ArgoCD/Flux) с дифами и статусами | helm status, logs |
| ✍️ Изменения вне Git | Автоматически возвращаются к Git-состоянию | Сохраняются (drift!) |
| 🔁 Частота обновлений | Постоянная синхронизация | Только по запуску команды |
🤖 ArgoCD + Helm = ❤️
Ты можешь использовать Helm внутри GitOps, просто зафиксировав чарты и values в Git:
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: my-app
spec:
source:
repoURL: https://github.com/my-org/my-repo
targetRevision: main
path: charts/my-app
helm:
valueFiles:
- values-prod.yaml
Таким образом, ты не теряешь гибкость Helm, но получаешь автоматизацию GitOps.
💡 Когда использовать что?
| Сценарий | Подход |
|---|---|
| Маленький pet-проект | Helm CLI |
| Команда/прод/много окружений | GitOps |
| Требуется аудит, откат, видимость | GitOps |
| Развёртывание из CI (ручной контроль) | Helm CLI |
| Много компонентов, инфраструктура как код | GitOps |
RBAC
RBAC (Role-Based Access Control) — это система контроля доступа в Kubernetes, основанная на ролях. Она позволяет разграничить, кто что может делать в кластере.
RBAC управляется через четыре основных ресурса:
• Role • ClusterRole • RoleBinding • ClusterRoleBinding
!!! rolebinding можно применить на clusterrole binding и дать права конкретному юзеру в рамках неймспейса !!!
🧱 Основные сущности
| Объект | Где действует | Что делает |
|---|---|---|
| Role | в пределах namespace | Определяет разрешения на действия |
| ClusterRole | действует кластерно | Может применяться глобально или к namespace |
| RoleBinding | в пределах namespace | Назначает Role пользователю/группе |
| ClusterRoleBinding | глобально | Назначает ClusterRole пользователю/группе на весь кластер или несколько NS |
📌 Пример 1: Простой Role и RoleBinding
# role.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: dev
name: pod-reader
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "watch", "list"]
# rolebinding.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: read-pods
namespace: dev
subjects:
- kind: User
name: alice
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: Role
name: pod-reader
apiGroup: rbac.authorization.k8s.io
📌 Это даёт пользователю alice доступ на чтение подов в namespace dev.
📌 Пример 2: ClusterRole + ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: node-reader
rules:
- apiGroups: [""]
resources: ["nodes"]
verbs: ["get", "watch", "list"]
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: read-nodes
subjects:
- kind: User
name: bob
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: node-reader
apiGroup: rbac.authorization.k8s.io
📌 Пользователь bob получает доступ на чтение нод во всём кластере.
🧠 Что можно указывать в rules?
rules:
- apiGroups: ["", "apps", "batch"]
resources: ["pods", "deployments", "jobs"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
• apiGroups: например, "" — core, "apps" — для deployments и т.д.
• resources: "pods", "services", "configmaps" и т.д.
• verbs: "get", "list", "create", "delete", "update", "patch"…
🔍 Проверка доступа
Хочешь понять, имеет ли пользователь/сервис-аккаунт доступ?
kubectl auth can-i get pods --as alice --namespace=dev
или для сервис-аккаунта:
kubectl auth can-i create deployments --as=system:serviceaccount:dev:sa-name
⚠️ RBAC и сервис-аккаунты
Для pod’ов, которые взаимодействуют с Kubernetes API, используется сервис-аккаунт (SA).
📌 Назначение ClusterRole на SA:
subjects:
- kind: ServiceAccount
name: my-sa
namespace: dev
🔐 Используется, например, для Prometheus, ArgoCD, Jenkins, etc.
🎯 Частые паттерны:
• view, edit, admin — встроенные ClusterRole • Least Privilege — даём только то, что нужно • aggregated ClusterRole — сборка нескольких прав в одну роль • Используй kubectl auth reconcile для безопасного обновления RBAC
🔐 1. Предустановленные роли: view, edit, admin
Kubernetes из коробки предоставляет несколько встроенных ClusterRole, которые ты можешь сразу привязать:
| Роль | Что умеет? |
|---|---|
| view | Только чтение (get, list, watch) |
| edit | Чтение и изменение всех ресурсов (кроме RBAC, NS, finalizers) |
| admin | Всё в пределах namespace, включая RBAC (но не ClusterRole) |
Пример:
kind: RoleBinding
metadata:
name: give-access
namespace: dev
subjects:
- kind: User
name: alice
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: view
apiGroup: rbac.authorization.k8s.io
📌 Очень удобно давать людям или бэку доступ “на посмотреть”.
🧃 2. Least Privilege (минимально необходимые права)
⚠️ Золотое правило безопасности: давай минимум, что нужно.
Никаких * в verbs, resources, apiGroups без острой необходимости!
Плохой пример:
verbs: ["*"]
resources: ["*"]
apiGroups: ["*"]
Хороший пример:
verbs: ["get", "list"]
resources: ["pods"]
apiGroups: [""]
📌 Принцип “чем меньше — тем лучше” особенно важен для сервис-аккаунтов CI/CD, мониторинга и автоматизации.
🧬 3. ServiceAccount + RoleBinding: доступ только Pod’ам
Часто сервис в кластере (например, Prometheus, Argo, Karpenter) нуждается в доступе к API. Вместо привязки прав к пользователю — создаём ServiceAccount + RoleBinding.
apiVersion: v1
kind: ServiceAccount
metadata:
name: my-agent
namespace: monitoring
kind: RoleBinding
metadata:
name: my-agent-binding
namespace: monitoring
subjects:
- kind: ServiceAccount
name: my-agent
namespace: monitoring
roleRef:
kind: Role
name: pod-reader
apiGroup: rbac.authorization.k8s.io
📌 Затем у pod’а в spec.serviceAccountName: my-agent.
🧩 4. Aggregated ClusterRoles — комбинация нескольких
Можно объединять несколько ClusterRole через метки, а не писать одну большую.
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: my-viewer
labels:
rbac.authorization.k8s.io/aggregate-to-view: "true"
rules:
- apiGroups: ["batch"]
resources: ["jobs"]
verbs: ["get", "list", "watch"]
Если в другом месте уже есть ClusterRole с меткой aggregate-to-view=true, то твоя роль автоматически добавится.
Используется во встроенных admin / edit / view.
🧪 5. Dynamic access (например, через GitOps)
Когда используешь ArgoCD, Flux или Helm — можно генерировать RBAC через шаблоны или Git-папки:
• Сервис argo-server использует SA с ClusterRole admin
• Helm chart устанавливает нужные Role/RoleBinding через values.yaml
📁 6. Мульти-Namespace RBAC
Role работает только внутри одного NS. Чтобы дать доступ в несколько NS — используй ClusterRole + несколько RoleBinding:
# reusable ClusterRole
kind: ClusterRole
metadata:
name: read-pods
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list"]
# в dev
kind: RoleBinding
metadata:
name: bind-in-dev
namespace: dev
subjects:
- kind: User
name: alice
roleRef:
kind: ClusterRole
name: read-pods
# в staging
kind: RoleBinding
metadata:
name: bind-in-staging
namespace: staging
subjects:
- kind: User
name: alice
roleRef:
kind: ClusterRole
name: read-pods
🧠 Финальные советы:
• kubectl auth can-i — твой друг.
• Смотри kubectl describe rolebinding и clusterrolebinding — видно, кто к чему привязан.
• Всегда проверяй права через dry-run или в dev-NS.
• GitOps-friendly подход: все роли и биндинги — в yaml и под версионным контролем.
Terraform
Отличие ansible и terraform
Terraform - Предназначен для представления инфраструктуры как код и автоматизации ее развертывания.
Ansible - Предназначен для автоматизации развертывания и конфигурации приложений.
То есть Terraform используется что бы разворачивать инфраструктуру (виртуальные машины, сети, диски, и тп.). Ansible предназначен для работы с существующими ресурсами, чтобы устанавливать и настраивать окружение (программы, операционные системы) на этих виртуалках.
Нюансы: Terraform отслеживает состояние и делает инкрементные изменения, что особенно полезно при работе с облачной инфраструктурой. Ansible не управляет состоянием, и каждая задача считается независимой.
Нужно понимать, что это инструменты. И в ряде случаев с помощью Ansible равзвернуть инфраструктуру всё таки можно. Как и для терраформа написать провайдер, который будет делать что-то свое. Вопрос лишь в применимости инструментов.
Что такое Terraform state?
• State-файл (terraform.tfstate) хранит текущее состояние инфраструктуры и сопоставляет описанные в HCL ресурсы с реальными объектами в облаке.
• Это позволяет Terraform определять, какие изменения нужно внести при terraform apply.
- Где его хранят?
• Локально (terraform.tfstate в рабочей директории) → не подходит для командной работы.
• Удаленно (S3, GCS, Azure Blob, Terraform Cloud) → позволяет совместную работу и контроль версий.
- Какие проблемы могут возникнуть?
• Конфликты при одновременной работе → решается блокировками (dynamodb для S3 backend).
• Компрометация чувствительных данных → решается с terraform state encrypt, terraform_remote_state, использование vault.
• Потеря state-файла → если удален без бэкапа, теряется возможность управлять ресурсами Terraform. • Если state удален, но инфраструктура еще есть → terraform import поможет. • Если state удален и инфраструктуры нет → потеряно безвозвратно. • Вывод: Обязательно настраивай бэкапы state-файлов! (S3 + DynamoDB, GCS, Azure Blob).
Что такое провайдер в terraform
Это утилита, прослойка, которая позволяет Terraform взаимодействовать с определенным API облачного провадйера.
Провайдеры используются для настройки и управления ресурсами, которые разворачиваются в облаке этого провайдера.
Что такое ресурс в terraform
Это какой то блок кода, который описывает объект в инфраструктуре. Каждый ресурс имеет свои какие то аргументы, свои параметры, свою конфигурацию. Ресурс имеет свой какой то уникальный идентификатор (ID, ARN и тд).
Виртуальная машина, сеть, диск, порт, балансировщик и тд.
Ansible
Основные примитивы Ansible
Инвентарь (Inventory)
- cписок хостов, может быть статичным в виде текcтового файла в формате
.iniили динамическим в виде скрипта или плагина, который подгружает структуру данных из стороннего источника, например, Openstack API или база LDAP.
$ cat hosts
[web]
nginx01
nginx02
nginx03
[mysql]
mysql01
mysql02
mysql03
[prod:children]
web
mysql
[devel]
dev-nginx01
dev-mysql01
Данный пример описывает группы хостов web, mysql, prod и devel, группа prod наследует содержимое групп web и mysql.
Задание (Task)
- атомарная операция, выполняемая на управляемом хосте, например:
apt:
package: nginx
state: present
Данный пример аналогичен команде apt install nginx
Сценарий (Play или Плейбук (Playbook)
- сценарий или скрипт, содержащий одно или несколько заданий на выполнение, например:
$ cat prod-playbook.yml
---
- hosts: nginx
tasks:
- apt:
package: nginx
state: present
- shell: whoami
Роль (Role)
- более сложная абстракция, выглядит как структура директорий и файлов, которые описывают набор дефолтных переменных, зависимостей от других ролей, может содержать файлы и темплейты, содержит задания(Tasks).
Факты (Facts)
- структура данных, которая содержит информацию о хосте, например, версию дистрибутива, IP адреса и файловые системы. Ansible забирает эту информацию с хоста, и на нее можно ссылаться в коде плейбуков и ролей.
Сбор фактов хоста занимает некоторое время, поэтому их можно кэшировать или отключить их сбор при выполнении плейбука.
Порядок приоритета переменных в Ansible
В Ansible переменные можно задавать в разных местах: в инвентаре, в ролях, через set_fact, в playbook, через командную строку и т.д. Если одна и та же переменная определена в нескольких местах — Ansible использует значение с наивысшим приоритетом.
📊 Порядок от низшего к высшему:
defaultsв ролях — значения по умолчанию (roles/myrole/defaults/main.yml)- Инвентарь:
- переменные в
inventory.ini(host var,group:vars) group_vars/— переменные для группhost_vars/— переменные для конкретных хостовansible_facts— автоматически собранные или заданы черезset_factvarsв playbook — переменные внутриvars:блокаvarsв task — локальные переменные в задачеregister— результат выполнения задач--extra-vars— переменные из CLI (самый высокий приоритет)
🧩 Примеры по уровням
1. defaults в ролях (самый низкий приоритет)
# roles/myrole/defaults/main.yml
app_port: 5000
env: \"dev\"
2. Инвентарь
[web]
web01 ansible_host=192.168.0.10 app_port=8081
[web:vars]
region=eu
3. group_vars/ и host_vars/
Файлы:
group_vars/web.ymlhost_vars/web01.yml
Пример:
# group_vars/web.yml
app_port: 8080
env: \"staging\"
# host_vars/web01.yml
app_port: 9090
→ Значение из host_vars переопределит group_vars.
4. ansible_facts (в том числе set_fact)
- name: Set fact
set_fact:
app_port: 7070
5. vars в playbook
- hosts: all
vars:
app_port: 6060
6. vars в task
- name: Show port
debug:
msg: \"Port is {{ app_port }}\"
vars:
app_port: 5050
7. register
- name: Get hostname
command: hostname
register: hostname_output
→ Используется как {{ hostname_output.stdout }}.
8. --extra-vars (наивысший приоритет)
ansible-playbook site.yml --extra-vars \"app_port=4040 env=prod\"
🧠 Заключение
Ansible позволяет гибко управлять переменными, и понимание порядка приоритетов критично для предсказуемости поведения плейбуков.
Рекомендации:
- Используй
defaultsв ролях для значений по умолчанию. - Задавай хост-специфичные данные в
host_vars/иgroup_vars/. - Для временных и приоритетных значений — используй
--extra-vars.
Для чего нужны хендлеры, handlers?
Задачу можно дополнить обработчиками, которые будут срабатывать, если задача была выполнена успешно.
Например, мы установили nginx и хотим его запустить
---
- hosts: testbox
sudo: yes
tasks:
- name: Install Nginx
yum: pkg=nginx state=latest
notify:
- NGINX start
handlers:
- name: NGINX start
service: name=nginx state=started
IAC and Идемпотентность
Идемпотентность - это такая характеристика действия, согласно которой повторное выполнение этого действия будет давать тот же результат, что и первый запуск.
В контексте систем управления конфигурациями это означает, что сценарии, написанные с соблюдением такого подхода, не изменят, не сломают и не выдадут ошибок на управляемом хосте при повторном запуске.
Например, нам нужно добавить пользователя на хост, для bash это будет выглядеть так:
useradd newuser -ms /bin/bash
Но если мы запустим команду второй раз, то получим ошибку
useradd newuser -ms /bin/bash
useradd: user 'newuser' already exists
Поэтому нам нужно дополнительно добавлять проверку, например так:
id newuser || useradd newuser -ms /bin/bash
В случае Ansible мы только декларируем состояние, например:
- hosts: localhost
gather_facts: no
tasks:
- user:
name: newuser
shell: /bin/bash
state: present
При первом запуске плейбук Ansible ответит:
TASK [user] ***
changed: [localhost] => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python3"
},
"changed": true,
"comment": "",
"create_home": true,
"group": 1001,
"home": "/home/newuser",
"name": "newuser",
"shell": "/bin/bash",
"state": "present",
"system": false,
"uid": 1001
}
При повторном:
TASK [user] ***
ok: [localhost] => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python3"
},
"append": false,
"changed": false,
"comment": "",
"group": 1001,
"home": "/home/newuser",
"move_home": false,
"name": "newuser",
"shell": "/bin/bash",
"state":
"present",
"uid": 1001
}
Обратите внимание, что статус задания сменился с changed на ok и повторный запуск вернул значение "changed": false
Таким образом, сценарии, написанные с учетом идемпотентности, реализуют ту самую декларативность в описании состояния инфраструктуры, а инфраструктура соответствует состоянию, описанному в коде нашего скрипта.
Это и есть IaС - Infrastructure as Code - инфраструктура как код
Для чего нужен ad hoc в ansible?
Это режим работы ансибл когда запрос к серверу выполняется напрямую из командной строки, без создания дополнительных файлов.