Translation to Russian some tech docs
Перевод на русский язык некоторой технической документации, полезно для подготовки к собеседованию. Сделано на github pages и mdbook.
Так же некоторые мои заметки по технологиям.
Flash карточки по некоторым технологиям https://flashcards.wizardzines.com/
Иллюстрированное руководство по TLS 1.2 и 1.3, DTLS, QUIC https://tls12.xargs.org/
Объяснения про редис, бд и проч https://architecturenotes.co/
Книга по флагам strace с примерами https://nanxiao.github.io/strace-little-book
Вольный перевод части репы
What happens when... https://github.com/alex/what-happens-when
Часть перевода взял с https://habr.com/ru/company/htmlacademy/blog/254825/
Определение DNS
Система доменных имен предоставляет распределенную базу данных которая хранит "записи о ресурсах" доменных имен. Локальных хост может участвовать в процессе разрешения доменного имени несколькими способами, самый простой показан ниже:
Host side resolving: Разрешение:
Локальный хост | Удаленный хост
|
+------------------+ +----------+ | +----------+
| | пользовательские запросы | | запросы | | |
| Пользовательская |------------------------->| |----------|->|Удаленный |
| программа | | Резолвер | | | сервер |
| |<-------------------------| |<---------|--| имен |
| | ответы пользователю | | ответы | | |
+------------------+ +----------+ | +----------+
| A |
проверка кэша | | сохраненные |
V | ответы |
+----------+ |
| кэш | |
+----------+ |
-
Браузер проверяет наличие домена в своём кэше. Например, чтоб увидеть кэш Google Chrome следует ввести в адресной строке chrome://net-internals/#dns.
-
Если домена там нет, то браузер вызывает библиотечную функцию gethostbyname (отличается в разных ОС) для поиска нужного адреса.
-
Прежде, чем искать домен по DNS gethostbyname пытается найти нужный адрес в файле hosts (его расположение отличается в разных ОС).
- В Linux порядок поиска можно настроить в файле /etc/nsswitch.conf, например, поведение по умолчанию:
hosts: files dns
-
Если домен нигде не закэширован и отсутствует в файле hosts, gethostbyname отправляет запрос к сетевому DNS-серверу. Как правило, это локальный роутер или DNS-сервер интернет-провайдера.
-
При отправке запроса к DNS-серверу будет использоваться настройка приоритета использования интерфейсов для исходящего трафика (например, файл /etc/gai.conf).
-
Если DNS-сервер находится в той же подсети, то сетевая библиотека выполняет ARP-запрос, который отправляется этому серверу.
-
Если DNS-сервер находится в другой подсети, , то сетевая библиотека выполняет ARP-запрос, который отправляется на IP-адрес шлюза по умолчанию (default gateway).
-
Если DNS-сервер не может найти IP-адрес имени хоста в кэше, он отправляет запрос резолверу, который специально настроен для получения IP-адреса любого имени хоста.
- Когда резолвер задействован, он сначала проверяет свой собственный кэш, но если он не может найти запись, он связывается с TLD (домен верхнего уровня), вероятно, с сервером com-зоны. Com - это домен верхнего уровня.
- TLD содержит информацию о серверах имен конкретных имен хостов. Зная имя хоста, которое пытается идентифицировать распознаватель, он может найти IP-адреса сервера имен вместе с их именами.
- Резолвер использует IP-адреса для запроса от серверов имен, информацию об IP-адресах, которую он ищет для своего конкретного имени хоста. В зависимости от сервера имен и какой зоны он обрабатывает, он должен найти IP хоста.
- После того, как резолвер обнаружил соответствующий IP-адрес, он возвращается на DNS-сервер, который возвращается в браузер. Повсюду серверы кэшируют имя хоста и его IP в соответствии с ограничениями времени жизни (TTL).
Процесс отправки ARP-запроса
Для того, чтобы отправить широковещательный ARP-запрос необходимо отыскать целевой IP-адрес, а также знать MAC-адрес интерфейса, который будет использоваться для отправки ARP-запроса (например, настройки из /etc/gai.conf)
Кэш ARP проверяется для каждого целевого IP-адреса — если адрес есть в кэше, то библиотечная функция возвращает результат: Target IP = MAC.
Если же записи в кэше нет:
- Проверяется таблица маршрутизации — это делается для того, чтобы узнать, есть ли искомый IP-адрес в какой-либо из подсетей локальной таблицы. Если он там, то запрос посылается с помощью интерфейса, связанного с этой подсетью. Если адрес в таблице не обнаружен, то используется интерфейс подсети шлюза по умолчанию.
- Определяется MAC-адрес выбранного сетевого интерфейса.
- Отправляется ARP-запрос (второй или канальный(data link) уровень модели OSI):
ARP-запрос:
Sender MAC: interface:mac:address:here
Sender IP: interface.ip.goes.here
Target MAC: FF:FF:FF:FF:FF:FF (Broadcast)
Target IP: target.ip.goes.here
В зависимости от того, какое «железо» расположено между компьютером и роутером (маршрутизатором):
Прямое соединение:
- Если компьютер напрямую подключён к роутеру, то это устройство отправляет ARP-ответ (ARP Reply).
Между ними концентратор (Хаб):
- Если компьютер подключён к сетевому концентратору, то этот хаб отправляет широковещательный ARP-запрос со всех своих портов. Если роутер подключён по тому же «проводу», то отправит ARP-ответ.
Между ними коммутатор (свитч):
- Если компьютер соединён с сетевым коммутатором, то этот свитч проверит локальную CAM/MAC-таблицу, чтобы узнать, какой порт в ней имеет нужный MAC-адрес. Если нужного адреса в таблице нет, то он заново отправит широковещательный ARP-запрос по всем портам, за исключением порта, откуда пришел запрос.
- Если в CAM/MAC-таблице коммутатора есть нужная запись, то свитч отправит ARP-запрос на порт с искомым MAC-адресом. Если входящий MAC-адрес отличается от существующего, то свитч добавит входящий MAC-адрес отправителя в таблицу CAM/MAC, затем он отправит широковещательную рассылку ARP на все порты, кроме порта, с которого поступил запрос.
- Если роутер «на одной линии» со свитчем, то он ответит (ARP Reply).
ARP-ответ:
Sender MAC: target:mac:address:here
Sender IP: target.ip.goes.here
Target MAC: interface:mac:address:here
Target IP: interface.ip.goes.here
Теперь у сетевой библиотеки есть MAC-адрес либо DNS-сервера либо шлюза по умолчанию, который можно использовать для разрешения доменного имени:
- DNS-клиент устанавливает сокет для UDP-порта 53 на DNS-сервере, используя номер порта источника выше 1023.
- Если размер ответа слишком велик, то вместо него будет использоваться TCP.
- Если локальный или на стороне провайдера DNS-сервер «не знает» нужный адрес, то запрашивается рекурсивный поиск, который проходит по списку вышестоящих DNS-серверов, пока не будет найдена SOA-запись, а затем возвращается результат.
Открытие сокета
Когда браузер получает IP-адрес конечного сервера, то он берёт эту информацию и данные об используемом порте из URL (80 порт для HTTP, 443 для HTTPS) и осуществляет вызов функции socket системной библиотеки и запрашивает поток TCP сокета — AF_INET и SOCK_STREAM.
- Этот запрос сначала проходит через транспортный уровень, где собирается TCP-сегмент. В заголовок добавляется порт назначения, исходный порт выбирается из динамического пула ядра (настройка net.ipv4.ip_local_port_range в Linux).
- Получившийся сегмент отправляется на сетевой уровень, на котором добавляется дополнительный IP-заголовок. Также включаются IP-адрес сервера назначения и адрес текущей машины — после этого пакет сформирован. Тут же происходит выбор исходящего интерфейса, будет использоваться настройка приоритета использования интерфейсов для исходящего трафика (например, файл /etc/gai.conf).
- Пакет передаётся на канальный уровень. Добавляется заголовок кадра, включающий MAC-адрес сетевой карты (NIC) компьютера, а также MAC-адрес шлюза (локального роутера). Как и на предыдущих этапах, если ядру ничего не известно о MAC-адресе шлюза, то для его нахождения отправляется широковещательный ARP-запрос.
На этой точке пакет готов к передаче через:
- Ethernet
- WiFi
- По сотовой связи
В случае интернет-соединения большинства частных пользователей или небольших компаний пакет будет отправлен с компьютера, через локальную сеть, а затем через модем (MOdulator/DEModulator), который транслирует цифровые единицы и нули в аналоговый сигнал, подходящий для передачи по телефонной линии, кабелю или беспроводным телефонным соединениям. На другой стороне соединения расположен другой модем, который конвертирует аналоговый сигнал в цифровые данные и передаёт их следующему сетевому узлу, где происходит дальнейший анализ данных об отправителе и получателе.
В конечном итоге пакет доберётся до маршрутизатора, управляющего локальной подсетью, так же называемого шлюзом. Этот шлюз-маршрутизатор может иметь много VLAN (виртуальных локальных сетей), которые разделяет IP-подсети. В зависимости от IP и подсети, входящий фрейм данных будет приземляться на физический порт, затем заголовок Ethernet пакета (в случае Ethernet
)
будет удален, останется IP-адрес источника, IP-адрес назначения и информация о портах. Маршрутизаторы поддерживают свою таблицу маршрутизации пакетов от входящего интерфейса к исходящему интерфейсу, этот маршрутизатор читает заголовок IP-пакета и выполняет поиск в локальной таблице маршрутизации (которая строится с использованием
статических маршрутов или с использованием динамических протоколов, таких как BGP, OSPF), чтобы найти исходящий интерфейс. Перед маршрутизацией пакета в заголовке IP из поля TTL (time to live) будет вычтена 1 (используется для предотвращения бесконечного зацикливания пакетов, пакет будет отброшен, если поле TTL достигнет нуля или если текущий маршрутизатор не имеет места в своей очереди / буферах (возможно, из-за перегрузки сети) или из-за ошибочных соединений и плохого CRC.). Помимо изменения TTL могут быть изменены другие поля, например если пакеты будут фрагментированы из-за меньшего размера MTU на исходящем интерфейсе, то маршрутизатор пошлет IP пакеты в так называемых чанках (chunks) - порции, и маршрутизатор перепишет IP-заголовки основываясь на оригинальном IP-пакете, также будут изменены контрольные суммы и т.д. Наконец, эти пакеты снова будут инкапсулированы во
фрейм Ethernet или в любой другой поддерживаемый тип, который поддерживается на интерфейсе и отправлены
следующему сетевому узлу
для аналогичной обработки. Оттуда он продолжит движение к маршрутизаторам на пути, проходящем через различные автономные системы (ASN - это уникальный номер, назначенный поставщикам интернет-услуг для идентификации себя в Интернете и маршрутизации интернет-трафика. Протокол BGP-Border Gateway Protocol поддерживает большие таблицы маршрутизации в маршрутизаторах ISP и ретрансляции пакетов в пункт назначения), а затем, наконец, достигает сервера назначения, где он передается в стек TCP / IP на сервере для дальнейшей обработки и доставки приложениям.
Во время TCP-соединения происходит множество подобных запросов и ответов.
Жизненный цикл TCP-соединения
a. Клиент выбирает номер начальной последовательности (ISN) и отправляет пакет серверу с установленным битом SYN для открытия соединения.
b. Сервер получает пакет с битом SYN и, если готов к установлению соединения, то:
- Выбирает собственный номер начальной последовательности;
- Устанавливает SYN-бит, чтобы сообщить о выборе начальной последовательности;
- Копирует ISN клиента +1 в поле ACK и добавляет ACK-флаг для обозначения подтверждения получения первого пакета.
c. Клиент подтверждает соединение путём отправки пакета:
- Увеличивает номер своей начальной последовательности;
- Увеличивает номер подтверждения получения;
- Устанавливает поле ACK.
d. Данные передаются следующим образом:
- Когда одна сторона отправляет N байтов, то увеличивает значение поля SEQ на это число.
- Когда вторая сторона подтверждает получение этого пакета (или цепочки пакетов), она отправляет пакет ACK, в котором значение поля ACK равняется последней полученной последовательности.
e. Закрытие соединения:
- Сторона, которая хочет закрыть соединение, отправляет пакет FIN;
- Другая сторона подтверждает FIN (с помощью ACK) и отправляет собственный FIN-пакет;
- Инициатор прекращения соединения подтверждает получение FIN отправкой собственного ACK.
TCP Windowing
Чтобы установить максимально возможную и надежную пропускную способность, отправитель и получатель устанавливает идеальный объем данных для отправки в каждом пакете, используя опцию / поле TCP Window. Получатель объявляет отправителю сколько данных он может получить в каждом пакете ACK, который соответствует свободное пространство буфера для сокета (SO_RCVBUF) и по умолчанию составляет 65535 байт.
Верхний предел отправителя является объявленным окном получателя. Отправитель не должен отправлять больше неиспользованных данных, чем это ограничение, иначе это приведет к переполнению буфера, в результате чего получатель отбросит дополнительные пакеты.
Окно перегрузки - это управление потоком, которое динамически настраивается на пропускную способность и надежность сети. Окно перегрузки запускает окно, в два раза превышающее максимальный размер сегмента. Он увеличивается механизмом медленного запуска TCP на каждом ACKed-пакете на 1. С этим алгоритмом окно перегрузки фактически удваивается для каждого времени прохождения туда-обратно.
По достижении порога медленного старта TCP переходит от использования алгоритма медленного старта к алгоритму предотвращения скопления. Окно увеличивается на 1 сегмент за каждое путешествие туда и обратно.
Балансировщик нагрузки
Поскольку многие люди могут пытаться получить доступ к одной и той же веб-странице в одно и то же время, для обслуживания веб-страницы используется несколько серверов, поэтому для распределения трафика между серверами используется балансировщик нагрузки.
Ниже приведены преимущества использования балансировщика нагрузки:
- Уменьшена нагрузка на отдельный сервер.
- Больший объем работы, выполненный в одно и то же время за счет параллелизма.
- Увеличение производительности веб-страницы/приложения из-за более быстрого отклика.
- Нет единой точки отказа. В среде с балансировкой нагрузки, если происходит сбой сервера, веб-страница/приложение все еще работает и обслуживается другими серверами в кластере.
- Когда используется соответствующий алгоритм балансировки нагрузки, он обеспечивает оптимальное и эффективное использование ресурсов, поскольку исключает сценарий использования ресурсов одних серверов, чем других.
- Масштабируемость: мы можем увеличивать или уменьшать количество серверов на лету, не отключая приложение.
- Балансировка нагрузки повышает надежность веб-страницы/приложения
- Повышенная безопасность, поскольку физические серверы и IP-адреса являются абстрактными в определенных случаях.
TLS handshake
- Клиентский компьютер отправляет сообщение ClientHello серверу со своей версией протокола TLS, списком поддерживаемых алгоритмов шифрования и методов компрессии данных.
- Сервер отвечает клиенту сообщением ServerHello, содержащим версию TLS, выбранный метод шифрования, выбранные методы компрессии и публичный сертификат сервиса, подписанный центром сертификации. Сертификат содержит публичный ключ, который будет использоваться клиентом для шифрования оставшейся части процедуры «рукопожатия» (handshake), пока не будет согласован симметричный ключ.
- Клиент подтверждает сертификат сервера с помощью своего списка центров сертификации. Если сертификат подписан центром из списка, то серверу можно доверять, и клиент генерирует строку псевдослучайных байтов и шифрует её с помощью публичного ключа сервера. Эти случайные байты могут быть использованы для определения симметричного ключа.
- Сервер расшифровывает случайные байты с помощью своего секретного ключа и использует эти байты для генерации своей копии симметричного мастер-ключа.
- Клиент отправляет серверу сообщение Finished, шифруя хеш передачи с помощью симметричного ключа.
- Сервер генерирует собственный хеш, а затем расшифровывает полученный от клиента хеш, чтобы проверить, совпадёт ли он с собственным. Если совпадение обнаружено, сервер отправляет клиенту собственный ответ Finished, также зашифрованный симметричным ключом.
- После этого TLS-сессия передаёт данные приложения (HTTP), зашифрованные с помощью подтверждённого симметричного ключа.
Протокол HTTP
Если используемый браузер был создан Google, то вместо отправки HTTP-запроса для получения страницы, он отправит запрос, чтобы попытаться «договориться» с сервером об «апгрейде» протокола с HTTP до SPDY («спиди»).
Если клиент использует HTTP-протокол и не поддерживает SPDY, то отправляет серверу запрос следующей формы:
GET / HTTP/1.1
Host: google.com
Connection: close
[другие заголовки]
где [другие заголовки] — это серия пар «ключ: значение», разбитых переносом строки. (Здесь предполагается, что в использованном браузере нет никаких ошибок, нарушающих спецификацию HTTP. Также предполагается, что браузер использует HTTP/1.1, в противном случае он может не включать заголовок Host в запрос и версия, отданная в ответ на GET-запрос может быть HTTP/1.0 или HTTP/0.9).
HTTP/1.1 определяет опцию закрытия соединения («close») для отправителя — с её помощью происходит уведомление о закрытии соединения после завершения ответа. К примеру:
Connection: close
Приложения HTTP/1.1, которые не поддерживают постоянные соединения, обязаны включать опцию «close» в каждое сообщение.
После отправки запроса и заголовков, браузер отправляет серверу единичную пустую строку, сигнализируя о том, что содержимое сообщения закончилось.
Сервер отвечает специальным кодом, который обозначает статус запроса и включает ответ следующей формы:
200 OK
[заголовки ответа]
После этого посылается пустая строка, а затем оставшийся контент HTML-страницы www.google.com. Сервер может затем закрыть соединение, или, если того требуют отправленные клиентом заголовки, сохранять соединение открытым для его использования следующими запросами.
Если HTTP-заголовки отправленные веб-браузером включают информацию, которой серверу достаточно для определения версии файла, закэшированного в браузере и этот файл не менялся со времени последнего запроса, то ответ может принять следующую форму:
304 Not Modified
[заголовки ответа]
и, соответственно, клиенту не посылается никакого контента, вместо этого браузер «достаёт» HTML из кэша.
После разбора HTML, браузер (и сервер) повторяет процесс загрузки для каждого ресурса (изображения, стили, скрипты, favicon.ico и так далее), на который ссылается HTML-страница, но при этом изменяется адрес каждого запроса c GET / HTTP/1.1 на GET /$(относительный URL ресурса www.google.com) HTTP/1.1.
Если HTML ссылается на ресурс, размещённый на домене, отличном от google.com, то браузер возвращается к шагам, включающим разрешение доменного имени, а затем заново проходит процесс до текущего состояния, но уже для другого домена. Заголовок Host в запросе вместо google.com будет установлен на нужное доменное имя.
Методы HTTP-запросов
Спецификация HTTP определяет ряд «методов» или действий, которые пользователь может выполнить на конкретном ресурсе.
Наиболее распространенным является «GET», который также используется почти все время, когда пользователь вводит URL-адрес в адресную строку своего браузера или щелкает гиперссылку. Этот метод представляет загрузку данных с сервера, не затрагивая их (хотя сервер может изменить сам ответ на запросы GET, если понадобится).
Следующим наиболее популярным методом является «POST», который обычно используется, когда пользователь нажимает кнопку «Отправить» после ввода текста в формы или выбора файла на своем компьютере. Этот метод представляет добавление нового контента на страницу, уже сохраненную на сервере.
Другие методы включают «PUT» и «DELETE», которые добавляют и удаляют целые ресурсы; «PATCH», который изменяет существующий ресурс; и «CONNECT», который используется, когда браузер сообщает прокси-серверу HTTP, что нужно пересылать запросы пользователя, а не делать запросы напрямую.
Обработка HTTP-запросов на сервере
HTTPD (HTTP Daemon) является одним из инструментов обработки запросов/ответов на стороне сервера. Наиболее популярные HTTPD-серверы это Apache или Nginx для Linux и IIS для Windows.
-
HTTPD (HTTP Daemon) получает запрос.
-
Сервер разбирает запрос по следующим параметрам:
- Метод HTTP-запроса (GET, HEAD, POST, PUT, PATCH, DELETE, CONNECT, OPTIONS или TRACE). В случае URL-адреса, который пользователь напечатал в строке браузера, мы имеем дело с GET-запросом.
- Домен. В нашем случае — google.com.
- Запрашиваемые пути/страницы, в нашем случае — / (нет запрошенных путей, / — это путь по умолчанию).
-
Сервер проверяет существование виртуального хоста, который соответствует google.com.
-
Сервер проверяет, что google.com может принимать GET-запросы.
-
Сервер проверяет, имеет ли клиент право использовать этот метод (на основе IP-адреса, аутентификации и прочее).
-
Если на сервере установлен модуль перезаписи (mod_rewrite для Apache или URL Rewrite для IIS), то он сопоставляет запрос с одним из сконфигурированных правил. Если находится совпадающее правило, то сервер использует его, чтобы переписать запрос.
-
Сервер находит контент, который соответствует запросу, в нашем случае он изучит индексный файл.
-
Далее сервер разбирает («парсит») файл с помощью обработчика. Если Google работает на PHP, то сервер использует PHP для интерпретации индексного файла и направляет результат клиенту.
Вольный перевод части репы
What happens when ... Kubernetes edition! https://github.com/jamiehannaford/what-happens-when-k8s
Часть перевода взял с https://habr.com/ru/company/flant/blog/342658/
Представим, что я хочу задеплоить nginx в кластере Kubernetes. Я введу в терминале нечто такое:
kubectl run --image=nginx --replicas=3 … и нажму на Enter. Через несколько секунд увижу 3 пода с nginx, распределённые по всем рабочим узлам. Работает — словно по волшебству, и это здорово! Но что на самом деле происходит под капотом?
Одно из замечательных свойств Kubernetes — как эта система обслуживает развёртывание рабочих нагрузок в инфраструктуре через дружелюбные к пользователям API. Вся сложность скрыта простой абстракцией. Однако для того, чтобы полностью осознать ценность, которую приносит K8s, полезно понимать внутреннюю кухню. Тут будет описан весь жизненный цикл запроса от клиента до kubelet, при необходимости будут ссылки на исходный код для иллюстрации происходящего.
Кратко
kubectl
- Валидирует запрос — проверяет что он понимает что это за запрос.
- Составляет http запрос к apiserver в соответствии с вычисленным типом ресурса — под, деплоймент и прочие разные штуки kube’а.
- Договаривается с apiserver об используемой версии api.
- Аутентифицируется в apiserver — по сертификатам, токену или паролю.
kube-apiserver
- Аутентифицирует клиента разрешенными = указанными при старте способами.
- Авторизует запрос — что вам его можно выполнять. По цепочке авторизаторов — по файлам политик и проч.
- Контроль допуска — проверяет что вообще такого типа запросы на этом кластере разрешены — лимиты, квоты и т.п.
- Формирует соответствующий запросу ресурс — runtime представления заказанного пода, деплоймента и т.п.
- Сохраняет его в etcd через “поставщик хранилища”, но в неинициализированном виде — не ставится галка.
- Поставщик хранилища его сохраняет и get’ает, чтобы проверить успешное сохранение.
- Apiserver отправляет http ответ.
- Поставщик хранилища вызывает post-hooks.
Инициализаторы
Если у вновь записанного типа ресурса есть какие-то предварительные шаги, то на его создание зарегистрированы соответствующие инициалайзеры, как например, ижектеры проксей для пода и т.п.
- Эти инициализаторы записываются в pending список этому ресурсу.
- И начиная с первого выполняются по одному — они подписаны на объекты и если видят себя в голове списка, то отрабатывают.
- Пустой список означает, что ресурс initialized. И он становится доступен контроллерам.
Контроллеры
- Каждый из них считывает состояние каких-то etcd нод, за которые он отвечает. Например, Deployment controller видит, что появился новый деплоймент nginx’ов и его ответственность — создать нужные ReplicaSet’ы. Создать в смысле записать в etcd в нужном виде.
- Когда записаны новые ReplicaSet’ы, то в свою очередь ReplicaSet controller видит, что его понимание о том какие поды существуют не соответствует тому какие ReplicaSet’ы указаны в etcd. И он начинает создавать нужные pod’ы согласно правилам, например, соблюдая ReplicaSet burst count — количество подов создаваемых за раз.
- Контроллеры узнают об изменении в хранилище через Informer’ы — специальный механизм листенеров над etcd.
Шедулер
- Когда все контроллеры отработали и завели все нужные поды, поды будут тем не менее находиться в Pending состоянии, т.к. они еще не были назначены на конкретные ноды.
- Шедулер работает примерно так же как другие контроллеры — он слушает все события про поды и отфильтровывает поды, у которых NodeName пустой и пытается найти им подходящие Ноды.
- Шедулинг происходит так:
- Прежде всего проверяется цепочка предикатов, которые отфильтровывают неподходящие ноды. Например, если в PodSpec’е указаны CPU ресурс, а на какой-то ноде столько нет.
- Дальше выполняются функции приоритета, по которым оставшиеся ноды ранжируются. Например, выше ставится нода с большим количеством свободных ресурсов. Когда нода выбрана, шедулер создает Binding запрос к apiserver’у — который запишет имя ноды в NodeName PodSpec’и и установит PodScheduled статус в True .
kubelet
- Это компонент запущенный на всех нодах Кубернетес кластера и занимающийся среди прочего жизненным циклом подов на этой ноде — он транслирует все необходимое из абстрации “Под” в реальные контейнеры, volum’ы и т.п.
- kubelet так же как контроллеры и шедулер получает статус всех подов назначеных его ноде от apiserver’а и проверяет, что всё это соответсвует его локальной действительности.
- А если что-то не соответствует, то он пытается отсинхронизовать действительность под желаемые аписервером требования. Вот что он делает:
- Создает объект PodStatus, в котором отслеживается изменения его состояния, такие как Pending, Running, Succeeded, Failed. Например, определив какие контейнеры надо запустить, кублет понимает, что они еще не созданы, и поэтому Pod находится в Pending состоянии.
- Затем этот PodStatus отдается статус-менеджеру Пода, который ассинхронно будет записывать обновления в apiserver.
- Запускаются секьюрити хендлеры, которые, например, проверяют профили Apparmor. Поды не прошедшие эти хендлеры навсегда остаются в состоянии Pending.
- Если был установлен флаг cgroups-per-qos, то kubelet создает cgroup’ы для пода и ставит туда ограничения ресурсов.
- Кублет создает дата-директории для пода — /var/run/kubelet/pods/
для самого пода, /volumes для вольюмов и /plugins для плагинов. - Volume manager будет ожидать соответствующих PodSpec’е вольюмов.
- Кублет получит все соответвующие поду секреты от аписервера, чтобы позже их заинжектить в контейнер.
- Container runtime запускает контейнер:
ContainerRuntimeInterface
- CRI это абстракция между kubelet’ом и, например, docker’ом, которая нужна, чтобы кубернетес мог работать не только поверх docker’а, но и поверх rkt или вообще вирутальных машин.
- kubelet запускает вызов RunPodSandbox, где “sandbox” это CRI термин обозначающий под. Т.е. это может быть как группа контейнеров, так и виртуалка или что-то подобное.
- В случае docker’а создание sandbox’а соответствует созданию запаузенного (paused) контейнера — родительского контейнера для пода, через который все контейнеры пода будут шарить ресурсы — Linux неймспейсы (IPC, network, PID).
ContainerNetworkInterface
- CNI это тоже интерфейс абстракция, которая позволяет подключать различные провайдеры организации сетей.
- Если у Pod’а был сконфигурирован интерфейс типа bridge:
- Плагин bridge создаст локальный линуксовый сетевой мост на ноде.
- Затем вторая пара от veth будет заинжектена внутрь paused родительского контейнера, т.е. в его network namespace.
- CNI присвоит этому интерфейсу IP и назначит роутинг. Делает это он через ipam (address manager) плагин, который, например, создает host-local конфигурацию.
- CNI получив информацию о DNS сервере от kublet’а, пропишет ее в resolve.conf контейнеру.
Межнодовое сетевое взаимодействие
Обычно оно организовывается с помощью overlay сети, например, это может быть layer-3 IPv4 межнодовая сеть, которая энкапсулирует ip пакеты в UDP реальной сети.
Запуск контейнеров
После того как sandbox подготовлен, kubelet запускает уже реальные контейнеры Пода — сначала запускаются init контейнеры, если такие есть в спеке Пода, и только потом основные контейнеры.
- Pull’ится соответствующий образ.
- CRI создает контейнер внутри родительского paused контейнера.
- Если нужно, контейнер регистрируется в CPU manager’е — ему приписывается набор ЦПУ, на которых он будет работать.
- Контейнера запускается!
- Запускаются post-start хуки.
kubectl
Валидация и генераторы
В первую очередь kubectl выполнит валидацию на стороне клиента. Он убедится, что нерабочие запросы (например, создание ресурса, который не поддерживается, или использование образа с неправильно указанным названием) быстро прервутся и не будут отправлены в kube-apiserver. Так улучшается производительность системы — благодаря снижению ненужной нагрузки.