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
Что такое 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\"
Под не будет размещён на той же ноде, где уже есть другой
frontend
Pod.
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
🧱 Основные сущности
Объект | Где действует | Что делает |
---|---|---|
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_fact
vars
в 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.yml
host_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?
Это режим работы ансибл когда запрос к серверу выполняется напрямую из командной строки, без создания дополнительных файлов.