Самовосстанавливающиеся приложения с Kubernetes и Spring Boot

1. Вступление

В этом руководстве мы поговорим о Kubernetes 's исследует и демонстрирует, как мы можем использовать Actuator 's HealthIndicator чтобы иметь точное представление о состоянии нашего приложения.

Для целей данного учебного пособия мы собираемся предположить некоторый ранее существовавший опыт работы с Spring Boot Actuator , Kubernetes и [ Docker .

2. Кубернетес Зонды

Kubernetes определяет два разных зонда, которые мы можем использовать для периодической проверки, все ли работает должным образом: liveness и readiness .

2.1. Живость и Готовность

  • С помощью зондов Liveness и Readiness Kubelet могут действовать, как только он обнаруживает, что что-то отключено, и минимизировать время простоя нашего приложения. **

Оба настроены одинаково, но имеют разную семантику и Kubelet выполняет разные действия в зависимости от того, какой из них запущен

  • Readiness - Readiness проверяет, готов ли наш Pod к запуску

получение трафика. Наш Pod готов, когда все его контейнеры готовы ** Liveness - В отличие от readiness , liveness проверяет, является ли наш Pod

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

Мы настраиваем оба типа зондов на уровне контейнера:

apiVersion: v1
kind: Pod
metadata:
  name: goproxy
  labels:
    app: goproxy
spec:
  containers:
  - name: goproxy
    image: k8s.gcr.io/goproxy:0.1
    ports:
    - containerPort: 8080
    readinessProbe:
      tcpSocket:
        port: 8080
      initialDelaySeconds: 5
      periodSeconds: 10
      timeoutSeconds: 2
      failureThreshold: 1
      successThreshold: 1
    livenessProbe:
      tcpSocket:
        port: 8080
      initialDelaySeconds: 15
      periodSeconds: 20
      timeoutSeconds: 2
      failureThreshold: 1
      successThreshold: 1

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

  • initialDelaySeconds - После создания контейнера ** подождите

_n секунд до начала проверки periodSeconds_ - Как часто должен выполняться этот зонд , по умолчанию

10 секунд; минимум 1 секунда timeoutSeconds - Как долго мы ждем ** , прежде чем тайм-аут исследования,

по умолчанию до 1 секунды; минимум снова 1 секунда failureThreshold - Попробуйте n раз, прежде чем сдаться ** . В этом случае

из readiness , наш модуль будет помечен как не готовый, а отказавшись в случае liveness означает перезапуск Pod . По умолчанию здесь 3 сбои, с минимумом 1 successThreshold - это минимальное количество последовательных

Успешно, чтобы зонд считался успешным после провала ** . По умолчанию это 1 успех, а также минимум 1

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

2.2. Зонд Т Тип

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

К счастью, у Kubernetes есть три разных типа зондов, которые мы можем использовать:

  • exec - Выполняет bash инструкции в нашем контейнере . За

Например, проверьте, существует ли определенный файл. Если инструкция возвращает код ошибки, зонд не работает tcpSocket - Пытается установить tcp соединение с контейнером,

используя указанный порт . Если не удается установить соединение, зонд не работает httpGet - Отправляет HTTP-запрос GET на сервер , который работает

в контейнере и прослушивание по указанному порту. Любой код больше или равен 200 и меньше 400 указывает на успех

Важно отметить, что у зондов HTTP есть дополнительные поля, помимо тех, которые мы упоминали ранее:

  • host - имя хоста для подключения, по умолчанию IP-адрес нашего модуля

  • scheme - схема, которую следует использовать для подключения, HTTP или HTTPS ,

по умолчанию HTTP path ** - Путь для доступа на веб-сервере

  • httpHeaders - Пользовательские заголовки для установки в запросе

  • port - Имя или номер порта для доступа в контейнере

3. Spring Actuator и Kubernetes Самовосстановление Возможности

Теперь, когда у нас есть общее представление о том, как Kubernetes может определять, находится ли наше приложение в нерабочем состоянии, давайте посмотрим, как мы можем воспользоваться преимуществами Spring Actuator , чтобы сохранить пристальный взгляд не только на наше приложение, но и на его зависимости!

Для целей этих примеров мы будем полагаться на Minikube .

3.1. Actuator и его __HealthIndicator __s

Учитывая, что у Spring есть несколько готовых к использованию _HealthIndicator , отразить состояние некоторых зависимостей нашего приложения от зондов Kubernetes так же просто, как добавить Actuator . зависимость от нашего pom.xml: _

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

3.2. Пример жизни

Давайте начнем с приложения, которое будет нормально загружаться и через 30 секунд будет переходить в сломанное состояние .

Мы собираемся эмулировать нарушенное состояние с помощью creating HealthIndicator , который проверяет, является ли переменная boolean true .

Мы инициализируем переменную как true , а затем планируем задачу изменить ее на false через 30 секунд:

@Component
public class CustomHealthIndicator implements HealthIndicator {

    private boolean isHealthy = true;

    public CustomHealthIndicator() {
        ScheduledExecutorService scheduled =
          Executors.newSingleThreadScheduledExecutor();
        scheduled.schedule(() -> {
            isHealthy = false;
        }, 30, TimeUnit.SECONDS);
    }

    @Override
    public Health health() {
        return isHealthy ? Health.up().build() : Health.down().build();
    }
}

С нашим индикатором работоспособности мы должны докеризировать вашу заявку:

FROM openjdk:8-jdk-alpine
RUN mkdir -p/usr/opt/service
COPY target/** .jar/usr/opt/service/service.jar
EXPOSE 8080
ENTRYPOINT exec java -jar/usr/opt/service/service.jar

Затем мы создаем наш шаблон Kubernetes :

apiVersion: apps/v1
kind: Deployment
metadata:
  name: liveness-example
spec:
  ...
    spec:
      containers:
      - name: liveness-example
        image: dbdock/liveness-example:1.0.0
        ...
        readinessProbe:
          httpGet:
            path:/health
            port: 8080
          initialDelaySeconds: 10
          timeoutSeconds: 2
          periodSeconds: 3
          failureThreshold: 1
        livenessProbe:
          httpGet:
            path:/health
            port: 8080
          initialDelaySeconds: 20
          timeoutSeconds: 2
          periodSeconds: 8
          failureThreshold: 1
  • Мы используем зонд httpGet , указывающий на конечную точку работоспособности __Actuator. ** Любое изменение состояния нашего приложения (и его зависимостей) будет отражаться на работоспособности нашего развертывания.

После развертывания нашего приложения на Kubernetes мы сможем увидеть оба датчика в действии: примерно через 30 секунд наш Pod будет помечен как неготовый и удален из ротации; Через несколько секунд Pod перезапустится.

Мы можем видеть события нашего Pod выполнения kubectl describe pod liveness-example :

Warning  Unhealthy 3s (x2 over 7s)   kubelet, minikube  Readiness probe failed: HTTP probe failed ...
Warning  Unhealthy 1s                kubelet, minikube  Liveness probe failed: HTTP probe failed ...
Normal   Killing   0s                kubelet, minikube  Killing container with id ...

3.3. Пример готовности

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

Давайте использовать его в другом случае: предположим, что наше приложение нуждается бит времени до того, как сможет получить трафик Например, ему нужно загрузить файл в память и проверить его содержимое.

Это хороший пример того, когда мы можем воспользоваться зондом readiness .

Давайте изменим шаблоны HealthIndicator и Kubernetes из предыдущего примера и адаптируем их к этому варианту использования:

@Component
public class CustomHealthIndicator implements HealthIndicator {

    private boolean isHealthy = false;

    public CustomHealthIndicator() {
        ScheduledExecutorService scheduled =
          Executors.newSingleThreadScheduledExecutor();
        scheduled.schedule(() -> {
            isHealthy = true;
        }, 40, TimeUnit.SECONDS);
    }

    @Override
    public Health health() {
        return isHealthy ? Health.up().build() : Health.down().build();
    }
}

Мы инициализируем переменную как false , и через 40 секунд задача выполнится и установит для нее true.

Далее мы докеризируем и разворачиваем наше приложение, используя следующий шаблон:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: readiness-example
spec:
  ...
    spec:
      containers:
      - name: readiness-example
        image: dbdock/readiness-example:1.0.0
        ...
        readinessProbe:
          httpGet:
            path:/health
            port: 8080
          initialDelaySeconds: 40
          timeoutSeconds: 2
          periodSeconds: 3
          failureThreshold: 2
        livenessProbe:
          httpGet:
            path:/health
            port: 8080
          initialDelaySeconds: 100
          timeoutSeconds: 2
          periodSeconds: 8
          failureThreshold: 1

Несмотря на то, что в конфигурации зондов есть несколько изменений, на которые мы должны обратить внимание:

  • Поскольку мы знаем, что нашему приложению требуется около 40 секунд, чтобы стать

готовы принять трафик, мы увеличили initialDelaySeconds из наш readiness зонд до 40 секунд Аналогично, мы увеличили initialDelaySeconds ** из

наш liveness зонд до 100 секунд, чтобы избежать преждевременной гибели Kubernetes

Если он все еще не закончился через 40 секунд, у него все еще есть приблизительно 60 секунд, чтобы закончить. После этого наш liveness зонд включится и перезапустит Pod.

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

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

Полную реализацию этих примеров можно найти по адресу over на Github .