Перейти к основному содержимому

Краткое введение в Java-клиент Kubernetes

· 6 мин. чтения

1. Введение

В этом руководстве мы покажем, как использовать API Kubernetes из приложений Java, используя его официальную клиентскую библиотеку.

2. Зачем использовать Kubernetes API?

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

В большинстве случаев наши приложения могут игнорировать тот факт, что они работают в Kubernetes. Это хорошо, так как позволяет нам разрабатывать их локально и с помощью нескольких команд и заклинаний YAML быстро развертывать их на нескольких облачных провайдерах с небольшими изменениями.

Однако есть несколько интересных вариантов использования, когда нам нужно поговорить с Kubernetes API для достижения определенных функций:

  • Запустите внешнюю программу для выполнения какой-либо задачи, а затем получите статус ее выполнения.
  • Динамически создавать/изменять какую-либо услугу в ответ на запрос клиента
  • Создайте настраиваемую панель мониторинга для решения, работающего в нескольких кластерах Kubernetes, даже у облачных провайдеров.

Конечно, эти варианты использования не так уж распространены, но благодаря его API мы увидим, что их довольно просто реализовать.

Кроме того, поскольку Kubernetes API является открытой спецификацией, мы можем быть уверены, что наш код будет работать без каких-либо изменений в любой сертифицированной реализации .

3. Местная среда разработки

Самое первое, что нам нужно сделать, прежде чем мы перейдем к созданию приложения, — это получить доступ к работающему кластеру Kubernetes. Хотя для этого мы можем использовать поставщика общедоступного облака, локальная среда обычно обеспечивает больший контроль над всеми аспектами ее настройки.

Есть несколько легковесных дистрибутивов, подходящих для этой задачи:

Фактические этапы настройки выходят за рамки этой статьи, но какой бы вариант вы ни выбрали, просто убедитесь, что kubectl работает нормально, прежде чем начинать какую-либо разработку.

4. Зависимости Maven

Во-первых, давайте добавим зависимость Java API Kubernetes в pom.xml нашего проекта :

<dependency>
<groupId>io.kubernetes</groupId>
<artifactId>client-java</artifactId>
<version>11.0.0</version>
</dependency>

Последнюю версию client-java можно загрузить с Maven Central.

5. Привет, Кубернетес

Теперь давайте создадим очень простое приложение Kubernetes, в котором будут перечислены доступные узлы вместе с некоторой информацией о них.

Несмотря на свою простоту, это приложение иллюстрирует необходимые шаги, которые мы должны выполнить, чтобы подключиться к работающему кластеру и выполнить вызов API. Независимо от того, какой API мы используем в реальном приложении, эти шаги всегда будут одинаковыми.

5.1. Инициализация API- клиента

Класс ApiClient — один из самых важных классов в API, поскольку он содержит всю логику для выполнения вызова к серверу API Kubernetes . Рекомендуемый способ создания экземпляра этого класса — использование одного из доступных статических методов класса Config . В частности, проще всего это сделать с помощью метода defaultClient() :

ApiClient client = Config.defaultClient();

Использование этого метода гарантирует, что наш код будет работать как удаленно, так и внутри кластера. Кроме того, он автоматически выполнит те же шаги, что и утилита kubectl для поиска файла конфигурации.

  • Файл конфигурации, определяемый переменной среды KUBECONFIG.
  • $HOME/.kube/ файл конфигурации
  • Токен учетной записи службы в /var/run/secrets/kubernetes.io/serviceaccount
  • Прямой доступ к http://localhost:8080

Третий шаг — это тот, который позволяет нашему приложению работать внутри кластера как часть любого модуля , если ему доступна соответствующая учетная запись службы.

Также обратите внимание, что если в файле конфигурации определено несколько контекстов, эта процедура выберет «текущий» контекст, определенный с помощью команды kubectl config set-context .

5.2. Создание заглушки API

Получив экземпляр ApiClient , мы можем использовать его для создания заглушки для любого из доступных API. В нашем случае мы будем использовать класс CoreV1Api , который содержит метод, необходимый для получения списка доступных узлов:

CoreV1Api api = new CoreV1Api(client);

Здесь мы используем уже существующий ApiClient для создания заглушки API.

Обратите внимание, что также доступен конструктор без аргументов, но в целом мы должны воздерживаться от его использования . Причиной отказа от его использования является тот факт, что внутри он будет использовать глобальный ApiClient , который должен быть предварительно установлен с помощью Configuration.setDefaultApiClient() . Это создает неявную зависимость от того, кто вызывает этот метод перед использованием заглушки, что, в свою очередь, может привести к ошибкам во время выполнения и проблемам обслуживания.

Лучший подход состоит в том, чтобы использовать любую структуру внедрения зависимостей для выполнения этой первоначальной проводки, внедряя полученную заглушку везде, где это необходимо.

5.3. Вызов API Kubernetes

Наконец, давайте перейдем к фактическому вызову API, который возвращает доступные узлы. В заглушке CoreApiV1 есть метод, который делает именно это, так что это становится тривиальным:

V1NodeList nodeList = api.listNode(null, null, null, null, null, null, null, null, 10, false);
nodeList.getItems()
.stream()
.forEach((node) -> System.out.println(node));

В нашем примере мы передаем null для большинства параметров метода, поскольку они являются необязательными. Последние два параметра актуальны для всех вызовов listXXX , так как они определяют время ожидания вызова и является ли это вызовом Watch или нет. Проверка подписи метода показывает оставшиеся аргументы:

public V1NodeList listNode(
String pretty,
Boolean allowWatchBookmarks,
String _continue,
String fieldSelector,
String labelSelector,
Integer limit,
String resourceVersion,
String resourceVersionMatch,
Integer timeoutSeconds,
Boolean watch) {
// ... method implementation
}

В этом кратком введении мы просто проигнорируем аргументы пейджинга, просмотра и фильтрации. Возвращаемое значение в этом случае — это POJO с Java-представлением возвращаемого документа . Для этого вызова API документ содержит список объектов V1Node с несколькими фрагментами информации о каждом узле. Вот типичный вывод, выдаваемый на консоли этим кодом:

class V1Node {
metadata: class V1ObjectMeta {
labels: {
beta.kubernetes.io/arch=amd64,
beta.kubernetes.io/instance-type=k3s,
// ... other labels omitted
}
name: rancher-template
resourceVersion: 29218
selfLink: null
uid: ac21e09b-e3be-49c3-9e3a-a9567b5c2836
}
// ... many fields omitted
status: class V1NodeStatus {
addresses: [class V1NodeAddress {
address: 192.168.71.134
type: InternalIP
}, class V1NodeAddress {
address: rancher-template
type: Hostname
}]
allocatable: {
cpu=Quantity{number=1, format=DECIMAL_SI},
ephemeral-storage=Quantity{number=18945365592, format=DECIMAL_SI},
hugepages-1Gi=Quantity{number=0, format=DECIMAL_SI},
hugepages-2Mi=Quantity{number=0, format=DECIMAL_SI},
memory=Quantity{number=8340054016, format=BINARY_SI},
pods=Quantity{number=110, format=DECIMAL_SI}
}
capacity: {
cpu=Quantity{number=1, format=DECIMAL_SI},
ephemeral-storage=Quantity{number=19942490112, format=BINARY_SI},
hugepages-1Gi=Quantity{number=0, format=DECIMAL_SI},
hugepages-2Mi=Quantity{number=0, format=DECIMAL_SI},
memory=Quantity{number=8340054016, format=BINARY_SI},
pods=Quantity{number=110, format=DECIMAL_SI}}
conditions: [
// ... node conditions omitted
]
nodeInfo: class V1NodeSystemInfo {
architecture: amd64
kernelVersion: 4.15.0-135-generic
kubeProxyVersion: v1.20.2+k3s1
kubeletVersion: v1.20.2+k3s1
operatingSystem: linux
osImage: Ubuntu 18.04.5 LTS
// ... more fields omitted
}
}
}

Как видим, информации довольно много. Для сравнения, это эквивалентный вывод kubectl с настройками по умолчанию:

root@rancher-template:~# kubectl get nodes
NAME STATUS ROLES AGE VERSION
rancher-template Ready control-plane,master 24h v1.20.2+k3s1

6. Заключение

В этой статье мы представили краткое введение в API Kubernetes для Java. В следующих статьях мы углубимся в этот API и рассмотрим некоторые из его дополнительных функций:

  • Объясните разницу между доступными вариантами вызовов API.
  • Использование Watch для мониторинга событий кластера в реальном времени
  • Как использовать подкачку для эффективного извлечения большого объема данных из кластера

Как обычно, полный исходный код примеров можно найти на GitHub .