177 lines
17 KiB
HTML
177 lines
17 KiB
HTML
---
|
||
title: Создание сервиса для открытия доступа к приложению
|
||
weight: 10
|
||
description: |-
|
||
Узнайте о сервисах в Kubernetes.
|
||
Разберитесь, какое отношение к сервисам имеют лейблы и селекторы.
|
||
Сделайте приложение доступным вне кластера Kubernetes.
|
||
---
|
||
|
||
<!DOCTYPE html>
|
||
|
||
<html lang="ru">
|
||
|
||
<body>
|
||
|
||
<div class="layout" id="top">
|
||
|
||
<main class="content">
|
||
|
||
<div class="row">
|
||
<div class="col-md-8">
|
||
<h3>Цели</h3>
|
||
<ul>
|
||
<li>Узнать о сервисах в Kubernetes</li>
|
||
<li>Разобраться, какое отношение к сервисам имеют лейблы и селекторы</li>
|
||
<li>Сделать приложение доступным вне кластера Kubernetes</li>
|
||
</ul>
|
||
</div>
|
||
|
||
<div class="col-md-8">
|
||
<h3>Обзор сервисов Kubernetes</h3>
|
||
<p><a href="/docs/concepts/workloads/pods/pod-overview/">Под</a> — это расходный материал в Kubernetes. У них есть свой <a href="/docs/concepts/workloads/pods/pod-lifecycle/">жизненный цикл</a>. Когда рабочий узел прекращает работу, запущенные поды в узле также уничтожаются. После этого <a href="/docs/concepts/workloads/controllers/replicaset/">ReplicaSet</a> попытается автоматически вернуть кластер обратно в требуемое состояние, создавая новые поды, чтобы поддержать работоспособность приложения. Другим примером жизни и смерти подов может служить бэкенд для обработки изображений с 3 репликами. Поскольку это взаимозаменяемые реплики, они не влияют на фронтенд-часть, даже если под был уничтожен и пересоздан. Тем не менее, каждый под в кластере Kubernetes имеет уникальный IP-адрес — даже под на одном и том же узле. Поэтому необходим способ автоматической координации изменений между подами, чтобы приложения продолжали функционировать.</p>
|
||
|
||
<p>Сервис (Service) в Kubernetes — это абстрактный объект, который определяет логический набор подов и политику доступа к ним. Сервисы создают слабую связь между подами, которые от них зависят. Сервис создаётся в формате YAML <a href="/docs/concepts/configuration/overview/#general-configuration-tips">(рекомендуемый формат)</a> или JSON, как и все остальные объекты в Kubernetes. Как правило, набор подов для сервиса определяется <i>селектором лейблов</i> (label selector) — ниже будет описано, в каких случаях может понадобиться сервис без указания селектора (<code>selector</code>) в его спецификации.</p>
|
||
|
||
<p>Хотя у каждого пода есть уникальный IP-адрес, эти IP-адреса не доступны за пределами кластера без использования сервиса. Сервисы позволяют приложениям принимать трафик. Сервисы могут быть по-разному открыты, в зависимости от значения поля <code>type</code>, указанного в спецификации сервиса:</p>
|
||
<ul>
|
||
<li><i>ClusterIP</i> (по умолчанию) — открывает доступ к сервису по внутреннему IP-адресу в кластере. Этот тип делает сервис доступным только внутри кластера;</li>
|
||
<li><i>NodePort</i> — открывает сервис на том же порту каждого выбранного узла в кластере с помощью NAT. Делает сервис доступным вне кластера через <code><NodeIP>:<NodePort></code>. Является надмножеством ClusterIP.</li>
|
||
<li><i>LoadBalancer</i> — создает внешний балансировщик нагрузки в текущем облаке (если это поддерживается) и назначает фиксированный внешний IP-адрес для сервиса. Является надмножеством NodePort.</li>
|
||
<li><i>ExternalName</i> — открывает доступ к сервису по содержимому поля <code>externalName</code> (например, <code>foo.bar.example.com</code>), возвращая запись <code>CNAME</code> с его значением. При этом прокси не используется. Для этого типа требуется версия <code>kube-dns</code> 1.7+ или CoreDNS 0.0.8+.</li>
|
||
</ul>
|
||
<p>Более подробно узнать о различных типах сервисах можно в руководстве <a href="/docs/tutorials/services/source-ip/">Использование IP-порта источника</a>. Также изучите <a href="/docs/concepts/services-networking/connect-applications-service">Подключение приложений к сервисам</a>.</p>
|
||
<p>Кроме этого, обратите внимание, что в некоторых случаях в сервисах не определяется <code>selector</code> в спецификации. Сервис без <code>selector</code> не будет создавать соответствующий эндпоинт (Endpoint). Таким образом, пользователь может вручную определить эндпоинты для сервиса. Ещё один возможный сценарий создания сервиса без селектора — это строгое использование <code>type: ExternalName</code>.</p>
|
||
</div>
|
||
<div class="col-md-4">
|
||
<div class="content__box content__box_lined">
|
||
<h3>Краткое содержание</h3>
|
||
<ul>
|
||
<li>Открытие внешнего трафика для подов</li>
|
||
<li>Балансировка нагрузки трафика между подов</li>
|
||
<li>Использование лейблов</li>
|
||
</ul>
|
||
</div>
|
||
<div class="content__box content__box_fill">
|
||
<p><i>Сервис Kubernetes (Service) — это уровень абстракции, который определяет логический набор подов, перенаправляет внешний трафик, балансирует нагрузку и реализует service discovery для этих подов.</i></p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<br>
|
||
|
||
<div class="row">
|
||
<div class="col-md-8">
|
||
<h3>Сервисы и лейблы</h3>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="row">
|
||
<div class="col-md-8">
|
||
<p><img src="/docs/tutorials/kubernetes-basics/public/images/module_04_services.svg" width="150%" height="150%"></p>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="row">
|
||
<div class="col-md-8">
|
||
<p>Сервис направляет трафик через набор подов. Сервисы — это абстракция, позволяющая взаимозаменять поды Kubernetes без ущерба для работы приложения. Сервисы в Kubernetes находят и маршрутизируют трафик между зависимыми подами (это могут быть фронтенд- и бэкенд-компоненты приложения).</p>
|
||
<p>Сервисы для выбора набора подов используют <a href="/docs/concepts/overview/working-with-objects/labels">лейблы и селекторы</a>. Лейблы — пары ключ-значение, добавленные к объектам; например, они могут использоваться чтобы:</p>
|
||
<ul>
|
||
<li> идентифицировать объекты для окружений разработки, тестирования и production;</li>
|
||
<li> встроить теги версии;</li>
|
||
<li> классифицировать объекты через теги.</li>
|
||
</ul>
|
||
</div>
|
||
|
||
</div>
|
||
|
||
<br>
|
||
|
||
<div class="row">
|
||
<div class="col-md-8">
|
||
<p><img src="/docs/tutorials/kubernetes-basics/public/images/module_04_labels.svg"></p>
|
||
</div>
|
||
</div>
|
||
<br>
|
||
<div class="row">
|
||
<div class="col-md-8">
|
||
<p>Лейблы могут добавляться во время создания объектов или после этого. Они также могут быть изменены в любое время. Теперь давайте откроем доступ к приложению с помощью создания сервиса и добавим лейблы.</p>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="row">
|
||
<div class="col-md-12">
|
||
<h3>Создание нового сервиса</h3>
|
||
<p>Давайте убедимся, что приложение работает. Воспользуемся командой <code>kubectl get</code> и посмотрим на существующие поды:</p>
|
||
<p><code><b>kubectl get pods</b></code></p>
|
||
<p>Если работающих подов нет, объекты из предыдущих разделов руководства была удалены. В таком случае вернитесь и повторно создайте деплоймент по инструкциям из раздела <a href="/ru/docs/tutorials/kubernetes-basics/deploy-app/deploy-intro#deploy-an-app">Использование kubectl для развёртывания приложения</a>.
|
||
После этого подождите несколько секунд и повторно запросите список подов. Как только увидите работающий под, можно следовать инструкциям ниже.</p>
|
||
<p>Далее посмотрим на список уже имеющихся сервисов в кластере:</p>
|
||
<p><code><b>kubectl get services</b></code></p>
|
||
<p>У нас есть сервис под названием <tt>kubernetes</tt>. Его по умолчанию создаёт minikube при запуске кластера.
|
||
Чтобы создать новый сервис и сделать его доступным для внешних пользователей, воспользуемся командой <code>expose</code> с указанием типа сервиса NodePort в качестве параметра.</p>
|
||
<p><code><b>kubectl expose deployment/kubernetes-bootcamp --type="NodePort" --port 8080</b></code></p>
|
||
<p>Попробуем подкоманду <code>get services</code> ещё раз:</p>
|
||
<p><code><b>kubectl get services</b></code></p>
|
||
<p>Теперь у нас есть сервис под названием <tt>kubernetes-bootcamp</tt>. Мы можем увидеть, что у этого сервиса уникальный cluster-IP, внутренний порт и external-IP (IP соответствующего узла).</p>
|
||
<p>Чтобы выяснить, какой порт был открыт для внешнего мира (для сервиса со спецификацией <tt>type: NodePort</tt>), выполним подкоманду <code>describe service</code>:</p>
|
||
<p><code><b>kubectl describe services/kubernetes-bootcamp</b></code></p>
|
||
<p>Объявим переменную окружения <tt>NODE_PORT</tt>, в которую запишем значение назначенного порта узла:</p>
|
||
<p><code><b>export NODE_PORT="$(kubectl get services/kubernetes-bootcamp -o go-template='{{(index .spec.ports 0).nodePort}}')"</b></code><br />
|
||
<code><b>echo "NODE_PORT=$NODE_PORT"</b></code></p>
|
||
<p>Теперь можно проверить, что приложение доступно вне кластера, с помощью <code>curl</code>, IP-адреса узла и порта, проброшенного вовне:</p>
|
||
<p><code><b>curl http://"$(minikube ip):$NODE_PORT"</b></code></p>
|
||
<p>Получим ответ от сервера. Сервис доступен внешнему миру.</p>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="row">
|
||
<div class="col-md-12">
|
||
<h3>Шаг 2: использование лейблов</h3>
|
||
<div class="content">
|
||
<p>Deployment автоматически создаёт лейбл для пода. Подкоманда <code>describe deployment</code> покажет его название (<em>key</em>):</p>
|
||
<p><code><b>kubectl describe deployment</b></code></p>
|
||
<p>Воспользуемся этим лейблом при выводе списка подов. Для этого вызовем команду <code>kubectl get pods</code> с флагом <tt>-l</tt> и нужными значениями лейблов в качестве параметра:</p>
|
||
<p><code><b>kubectl get pods -l app=kubernetes-bootcamp</b></code></p>
|
||
<p>То же самое можно делать при выводе списка сервисов:</p>
|
||
<p><code><b>kubectl get services -l app=kubernetes-bootcamp</b></code></p>
|
||
<p>Получим имя пода и запишем его в переменную окружения <tt>POD_NAME</tt>:</p>
|
||
<p><code><b>export POD_NAME="$(kubectl get pods -o go-template --template '{{range .items}}{{.metadata.name}}{{"\n"}}{{end}}')"</b></code><br />
|
||
<code><b>echo "Name of the Pod: $POD_NAME"</b></code></p>
|
||
<p>Чтобы добавить новый лейбл, воспользуемся подкомандой <code>label</code>, для которой укажем тип объекта, имя объекта и значение нового лейбла:</p>
|
||
<p><code><b>kubectl label pods "$POD_NAME" version=v1</b></code></p>
|
||
<p>Новый лейбл добавится к поду (мы зафиксировали версию приложения для этого пода), а мы сможем убедиться в этом с помощью команды <code>describe pod</code>:</p>
|
||
<p><code><b>kubectl describe pods "$POD_NAME"</b></code></p>
|
||
<p>Как видно, лейбл добавился к нашему поду. Теперь мы можем получить список всех подов, использующих новый лейбл:</p>
|
||
<p><code><b>kubectl get pods -l version=v1</b></code></p>
|
||
<p>Наш под будет в этом списке.</p>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="row">
|
||
<div class="col-md-12">
|
||
<h3>Удаление сервиса</h3>
|
||
<p>Чтобы удалить сервис, воспользуйтесь подкомандой <code>delete service</code>. В ней могут указываться и лейблы:</p>
|
||
<p><code><b>kubectl delete service -l app=kubernetes-bootcamp</b></code></p>
|
||
<p>Убедитесь, что сервис удалился:</p>
|
||
<p><code><b>kubectl get services</b></code></p>
|
||
<p>Вывод подтвердит, что сервис был удалён. Убедиться в том, что удалился соответствующий маршрут для внешнего трафика, можно через <tt>curl</tt> к доступному ранее IP и порту:</p>
|
||
<p><code><b>curl http://"$(minikube ip):$NODE_PORT"</b></code></p>
|
||
<p>Так можно убедиться, что приложение более недоступно снаружи кластера.
|
||
Проверить, что приложение всё ещё работает, можно через <tt>curl</tt>, который будет выполнен внутри пода:</p>
|
||
<p><code><b>kubectl exec -ti $POD_NAME -- curl http://localhost:8080</b></code></p>
|
||
<p>Мы увидим, что приложение запущено. Оно функционирует, потому что за его работу отвечает деплоймент (Deployment). Чтобы остановить приложение, потребуется также удалить и его деплоймент.</p>
|
||
</div>
|
||
</div>
|
||
<div class="row">
|
||
<p>
|
||
Когда всё готово, переходите к разделу <a href="/ru/docs/tutorials/kubernetes-basics/scale/scale-intro/" title="Запуск нескольких экземпляров приложения">Запуск нескольких экземпляров приложения</a>.</p>
|
||
</p>
|
||
</div>
|
||
|
||
</div>
|
||
</main>
|
||
</div>
|
||
|
||
</body>
|
||
</html>
|