В прошлой статье мы говорили о  создании подов. В этой статье поговорим о том, что такое сервис, типы  сервисов, метки и селекторы, а также создадим свой сервис. Мы помним, что поды по своей сути эфемерны, они создаются и  уничтожаются в любой момент, и конечный адрес пода может меняться по  любой причине - будь то пересоздание самого пода на той же ноде, переезд  на другую ноду и т.п. Так как адрес постоянно меняется, мы не сможем  использовать его как конечную точку. А что, если у нас несколько одинаковых,  на которые надо «разделить» трафик и проверять доступность самого пода. В  этом всем нам поможет ресурс типа service.  Service — это абстракция, определяющая набор подов и доступ к ним.  Он является объектом REST в API K8S, а службы самого K8S настраивают прокси  (iptables, ipvs) на пересылку и фильтрацию трафика только тем контейнерам,  которые были выбраны в его селекторе. При создании сервиса ему также  присваивается внутренний IP- адрес сети K8S.   Сеть сервисов также, как и у подов является виртуальной, однако с  некоторым НО. Если мы посмотрим на рабочую ноду и ее список интерфейсов с  помощью того же ifconfig, то мы увидим, что в сетях подов 10.0.0.0/14  существуют фактические интерфейсы для каждого хоста в этой сети. Но мы не  найдем хостов в сервисной сети 10.3.240.0/20. Сервисной сети не существует,  но, тогда откуда же кластер знает, куда перенаправлять пакеты и на какой под.  Этим занимается компонент K8S под названием kube-proxy.  Kube-proxy — это сетевой прокси-сервер, который работает на каждом  узле кластера. Он занимается реализацией виртуальных ip, установкой правил  проксирования и фильтрацией трафика. У него есть два режима: В этом режиме kube-proxy следит через API за control plane K8S. Если  появился новый под или же пересоздался старый и сменился адрес, то kube- proxy сразу поменяет правила проксирования. Для каждой службы он  устанавливает правила iptables, которые фиксируют трафик на кластерный  адрес и порт сервиса и дальше перенаправляет этот трафик на один из  внутренних адресов подов. Для каждого объекта конечной точки (пода) он  устанавливает правила iptables. Если kube-proxy работает в режиме iptables, а первый выбранный под не  отвечает, соединение прерывается. Kube-proxy обнаружит, что соединение с  первым подом не удалось, и автоматически повторит попытку с другим  подом. По умолчанию kube-прокси в режиме iptables выбирает поды  случайным образом. Вы можете использовать readiness probes, чтобы убедиться, что  внутренние модули работают нормально, чтобы kube-proxy в режиме iptables  видел только те бэкенды, которые проверяются как исправные. Это означает,  что вы избежите отправки трафика через kube-прокси на под, который, вышел  из строя. В режиме ipvs отслеживает службы и конечные точки Kubernetes,  вызывает интерфейс netlink для создания соответствующих правил IPVS и  периодически синхронизирует правила IPVS со службами и конечными  точками Kubernetes. При доступе к сервису IPVS направляет трафик на один из  внутренних модулей.  IPVS предоставляет больше возможностей для балансировки трафика на  поды: rr: round-robin; lc: least connection (smallest number of open connections); dh: destination hashing; sh: source hashing; sed: shortest expected delay; nq: never queue. Чтобы указать, где будет размещен наш сервис, будет ли он доступен  снаружи или только внутри, используются типы сервиса. По умолчанию это  всегда ClusterIP, то есть сервис будет доступен только внутри самого кластера. Типы: ClusterIP - присевает IP в сервисной сети, который доступен только  внутри кластера. NodePort - предоставляет порт на внешнем ip самого узла (ноды),  сервис будет доступен из вне по выделенному порту на каждой  ноде. При этом создается и внутренний сервис ClusterIP. LoadBalancer - используется для внешних облачных  балансировщиков, таких как Google Cloud, которые имеют своего провайдера. Сервис будет доступен через внешний  балансировщик вашего провайдера, при этом создаются NodePort  с портами, куда будет приходить трафик от провайдера и ClusterIP. Сопоставляет сервис с содержимым поля Host (например  foo.bar.example.com), возвращая запись CNAME с ее значением.  Проксирование в этом режиме не производится. Стоит отметить режим NodePort, который позволяет использовать свои  решения внешней балансировки, привязав ваш сервис к внешнему порту  ноды кубера, если в манифесте порт не задан, то K8S сам назначит ему порт  из диапазона 30000–32767. При указании вручную, вы также должны будете  выбрать порт из этого же диапазона. Для того чтобы наш сервис знал, на какие поды мы хотим  перенаправлять трафик с него, необходимо указать селектор spec.selector.  Пример конфига: С помощью лейбла, заданного в манифесте deployments нашего пода,  kube-proxy через API выбирает и следит за подами, которые соответствуют только заданному селектору. Selector и label очень частые гости в манифестах K8S и будут встречаться  нам практически постоянно, поэтому давайте посмотрим, что это такое. Развертываемые поды являются многомерными, один и тот же набор  подов или контейнеров могут отличаться версией, окружением, названием  ПО внутри и тд. Чтобы правильно отфильтровать и отсортировать поды,  применяются label. Пример конфига deployments: В манифесте мы указываем label метку, которая будет присвоена подам  при их создании. В metadata.labels указываем пару в виде ключ: значение.  Можно использовать свои метки.  Пример: "release" : "stable", "release" : "canary" "environment" : "dev", "environment" : "qa", "environment" : "production" "tier" : "frontend", "tier" : "backend", "tier" : "cache" "partition" : "customerA", "partition" : "customerB"  "track" : "daily", "track" : "weekly" Метки не гарантируют уникальность одного пода, у вас скорее всего  будет группа подов с одинаковыми метками, но набор этих меток может быть  разный. С помощью селектора selector мы можем идентифицировать  определенный набор объектов или подов. Селектор меток — основное  средство группировки в Kubernetes. Пока есть только два типа селекторов: на равенстве и на наборе.  Условия равенства или неравенства позволяют отфильтровать объекты  по ключам и значениям меток. Условие меток на основе набора фильтрует ключи в соответствии с  набором значений. Поддерживаются три вида операторов: in, notin и exists.   Например: Условие набора поддерживают только Job, Deployment, ReplicaSet и  DaemonSet. Все остальные, как и сервис, только равенство. Создание под с demo-nginx в неймспейсе test, как мы делали это в предыдущей статье. Сделаем для него сервис, напишем манифест svc-nginx.yml:  Применим его Посмотрим создался ли сервис Сделаем describe  Как видим, наш сервис был создан с выбранным нами селектором. Узнаем внутренний IP нашего пода  Давайте теперь проверим, что сервис действительно работает  Запустим под, где есть curl  И сделаем curl на IP нашего сервиса или по имени  Вывод    Как видим, наш под отдает через сервис ответ.  Удалим под, чтобы контроллер deployments его пересоздал и узнаем его  новый IP:  Проверим опять наш сервис:  Запустим под, где есть curl  И сделаем curl на IP нашего сервиса или по имени. Сервис уже направляет к новому поду. Как только мы удалили под, kubeproxy пересоздал правила проксирования. С NodePort все гораздо проще, изменим наш манифест. Добавим type: NodePort и nodePort: 30008 и применим наш манифест. После  применения можно зайти на http://ip_любой_ноды:30008 и увидеть, что  отдает nginx. Вот вы и ознакомились со второй частью серии «K8S для начинающих». А  следующая часть будет посвящена ingress контроллеру, где мы расскажем о  persistent volume, затронем тему создания пользователей и их прав. Если у вас остались вопросы или пожелания к теме, которой нужно уделить  больше внимания, буду рад обсудить в комментариях. В NUT.Tech, где я  сейчас работаю, я уделяю много времени внедрению и развитию K8S в  высоконагруженных видеопроектах. Вполне возможно, что мой опыт может  быть вам полезен.   Системный инженер