Разбираем Kubernetes пример

Kubernetes пример

К моему глубочайшему удивлению, начиная с прошлой недели Kubernetes стал неотъемлемой частью моей работы. То есть теперь я не просто должен им интересоваться, его нужно ещё и понимать. А с этим, как можно судить по прошлому Kubernetes посту, есть проблемы. Вроде ж и пример тогда простой был, и по всем шагам прошёлся, но всё равно осталось какое-то ощущение недосказанности.

Я всё думал, почему же так получилось, и, кажется, проблема кроется в неудачном выборе инструментов (а не в мозгах, как мог подумать чрезмерно проницательный читатель). Нюанс в том, что сконфигурировать Kubernetes приложение можно как минимум двумя с половиной способами. Например, есть команды для создания k8s объектов «на лету», вроде kubectl run  или kubectl expose, которыми я и пользовался в том злосчастном посте. Они простые, понятные, но скрывают пару-тройку важных абстракций, и по итогу картина остаётся неполной.

А оставшиеся полтора способа — это создание объектов из конфигурационных файлов. По одному (первый способ), или сразу пачкой целиком (ещё половина). И, хотя этот подход более громоздкий и менее простой, после него в картине мира вообще не остаётся белых пятен.

Так что сегодня мы снова сделаем что-нибудь простое, вроде реплицированного nginx сервера, но в этот раз каждый объект будет создаваться явно, из файла конфигурации, и полным пониманием того, зачем он нужен.

Предварительная подготовка

Нам понадобятся только VirtualBox, для создания виртуальных машин, minikube, чтобы делать из них Kubernetes кластер, и kubectl, чтобы этот кластер надругивать. Как только всё это установилось, minikube start сделает свою тёмную магию и Kubernetes кластер заодно.

Pod (язык больше не поворачивается называть его «подом»)

Как вы уже наверное знаете, pod — это самый маленький юнит работы в Kubernetes, обёртка вокруг одного или нескольких контейнеров со своей айпишкой, именем, идентификатором и наверняка богатым внутренним миром.

Как и в прошлый раз, мы сделаем наш первый pod вокруг Docker контейнера с nginx. Только в этот раз — из файла конфигурации:

YAML файлы эстетически и практически прекрасны. Их просто читать, просто создавать. Запороть, правда, тоже легко, но это ко многим вещам относится. В нашем YAML мы задали тип (kind) создаваемого объекта, имя, и из каких контейнеров он создан. То есть «Pod», «single-nginx-pod» и «nginx» соответственно.

Чтобы создать из него реальный объект, этот файл нужно скормить команде kubectl apply, и гештальт будет завершён.

Pod создался не сразу, ведь nginx образ ещё нужно было и скачать, но через пару секунд всё будет готово. В этот pod можно даже зайти и осмотреться:

Смотреть особо не на что, так что я установил htop, чтобы порадовать себя ядовито зелёными цветами и заодно убедиться, что процесс с nginx на месте:

htop

Правда, pod-одиночка — уязвим и удивительно бесполезен. Во-первых, снаружи по HTTP к нему не достучаться. Во-вторых, если к контейнеру или хосту придёт костлявая, то, собственно, история nginx на этом и закончится. Если же нам нужно будет его отмасштабировать, то команду apply придётся повторить ещё кучу раз.

pod-одиночка

С другой стороны, существуют различные контроллеры, которые как раз и помогают от таких напастей.

Деплоймент-контроллер

Контроллеры — это такие Kubernetes объекты, которые могут манипулировать pod’ами. Например, есть Cron Job контроллер, который умеет запускать их по расписанию. Или ещё есть Replica Set, который может их масштабировать. Но самый универсальный контроллер — это Deployment. Он и воскресить может, и отмасштабировать, и апдэйт накатить, если попросят.

Но сейчас нам важно, чтобы деплоймент следил за здоровьем nginx, воскрешал его в случае чего, и масштабировал иногда. В общем, создаём.

Эта конфигурация уже по-сложнее. Но, с другой стороны, и объект тоже возмужал. Вот, как выглядит его настройка по частям:

  1. replicas , разумеется, задаёт, сколько копий pod’а нужно держать живыми.
  2. selector, в свою очередь, как отличать свои pod’ы от чужих. В нашем случае если на pod’е есть метка  app: webserver, то клиент — наш.
  3. template — он же шаблон — описывает, каким образом создавать pod, если тот скоропостижно скончался, либо вообще ещё никогда не существовал. Этот кусок очень похож на наш первый YAML код, где мы создавали pod-одиночку. В довесок к описанию контейнера мы повесили на него метку — app: webserver, чтобы деплоймент мог его найти.

Как и в прошлый раз, kubectl create сделает всё, что нужно:

Через пару секунд мы можем убедиться, что в кластере появилась новая ячейка общества: деплоймент и его pod:

Поддерживаем заявленную конфигурацию

А теперь смотрите, какой deployment, оказывается, полезный. Представим, что вмешались высшие силы (сегодня это я), и унесли бедолагу-pod’а в лучший из миров (полагаю, это AWS):

Ещё до того, как непечатное слово сорвётся с уст возмущённого кластер-администратора, деплоймент всё исправит:

Масштабирование

Ещё один пример полезности деплоймента — масштабирование вверх и вниз. Если в какой-то момент мы осознали, что наш убийца фейсбука всё-таки «стрельнул»,  и одним контейнером с nginx больше не отделаешься, за одну команду (либо через YAML) их можно превратить в десяток:

Правда, даже после масштабирования у pod’ов с nginx есть существенный недостаток — к ним всё ещё не достучаться снаружи. Нужна какая-то точка входа.

deployment

Сервисы

Точку входа реально тяжело сделать, если pod’ы то умирают, то воскресают, то мигрируют по кластеру. Сервис-объект, в свою очередь, может эти pod’ы отыскать по меткам и общаться с миром от их лица.

Что здорово, сервис может работать даже без pod’ов. Это полезно тогда, когда у нас есть какой-то сервис вне кластера, но мы не хотим, чтобы pod’ы лазили к нему напрямую.

Но сегодня мы сделаем простейший и дефолтный ClusterIP сервис, который позволит общаться к pod’ами по внутренней айпишке:

Бесплатный DNS и балансировщик нагрузки

И хотя внутренняя айпишка на то и внутренняя, что ей снаружи не воспользуешься, у нас появилась пара интересных полезностей. Сервис умеет распределять входящие запросы среди всех своих pod’ов, тем самым работая балансировщиком нагрузки, и кроме этого его имя теперь есть в кластерном DNS, так что с ним можно общаться даже не зная айпишки.

Это легко проверить. Для простоты я уменьшил количество реплик nginx’а до двух и поменял слово «nginx» в их дефолтном HTML на имя хоста. Ну чтобы видеть, с кем общаемся. К тому же у нас всё ещё висит pod-одиночка — single-nginx-pod, в который можно зайти и попинать наш сервис тем же curl.

Видели? Это же офигенно. nginx-service разбрасывает запросы между двумя оставшимися pod’ами и это чётко видно по ответам. То же самое, кстати, умели делать сервисы в Docker Swarm.

service

Но основная проблема-то никуда не ушла! К pod’ам всё не достучаться снаружи. Ладно, это легко исправить.

Ingress

Ингресс — это могущественный чёрный ящик, который может маршрутизировать запросы из внешнего мира к конкретным сервисам внутри кластера. Он умеет делать не только это, но нам сегодня нужно просто провести HTTP запрос к nginx-service. Так что, без лишней болтовни:

Если я правильно помню, то сначала ingress ещё нужно было и включить командой minikube addons enable ingress. Хотя, может, показалось.

После того, как бессменный kubectl create превратит ingress в нечто большее, чем тыква, мы разузнаем айпишку единственной машины кластера через minikube ip и начнём любоваться и на дефолтную страницу nginx:

nginx-first

как и на то, что она каждый раз приходит из разного pod’а:

nginx-second

Сильное колдунство.

Ingress

Мораль

Надеюсь, что теперь всё стало понятнее. Лично мне насоздавать стайку объектов по одному и руками определённо помогло.

Но есть ещё один момент, который не вылазит у меня из головы до сих пор. Если посмотреть на конфигурационный файлы, то, в принципе, их можно создавать в любом порядке. Например, создать сначала сервис, а с pod’ами и деплойментами — подождать. И ничего не упадёт. Оно, конечно, и понятно, объекты же ищут друг друга по селекторам, а не по какой-то жёсткой связке. Но мне интересно, это изначально было частью гуглового плана, или просто они сделали грамотный дизайн, а независимость объектов — его естественный побочный эффект? Вот как они к этому пришли? Интересно же.

Но я отвлёкся. Конфигурационный файлы — трушный путь, Kubernetes теперь классный, двигаемся дальше.

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *