Защитите поиск во время загрузки индекса

KubernetesIntermediate
Практиковаться сейчас

Введение

Meridian Museum помогает посетителям искать предметы по материалу и истории. Главная страница может отвечать раньше, чем заработает поиск по коллекции. Каждый новый поисковый контейнер загружает двенадцать подготовленных записей в словесный индекс в памяти. Загрузка намеренно идет с паузами, чтобы ее можно было наблюдать; заменяющий контейнер строит собственный индекс с самого начала.

Вы исключите загружающиеся Pod из посетительского Service, выделите достаточно времени на запуск и обновите импортер, пока существующие реплики продолжают выдавать правильные результаты поиска. Требуются базовые навыки терминала и знакомство с образами и работающими контейнерами. Объекты Kubernetes, YAML-патчи и настройки проб объясняются здесь. Кластер, кешированный образ музея и полноценный сайт подготовлены; установка, внешний аккаунт и программирование приложения не нужны.

Используйте Museum для действий посетителя, а Workstation — для команд. Работайте только в пространстве имен meridian и подготовленном каталоге музея. Это учебный кластер с одним узлом, а не подтверждение высокой доступности или гарантия отсутствия неудачных запросов. Каждая лабораторная начинается независимо.

Направляйте посетителей только к готовым к поиску Pod

Вы отличите работающий процесс от пригодного для поиска индекса и добавите проверку готовности для реальной задачи посетителя. Начните в Museum.

Пройдите обычный путь посетителя

Введите brass в Search the collection и выберите Find objects ↗. Результаты должны содержать Brass astrolabe и Brass telescope, а также 2 objects found. Откройте Brass astrolabe: появятся история, иллюстрация и место Gallery 1. Выберите See it at the museum ↗, прочитайте часы работы и сведения о входе без ступеней, затем нажмите Download collection list ↓. Откройте загруженный CSV: в нем двенадцать предметов, включая оба латунных инструмента. Вернитесь домой через MERIDIAN. После изменений все эти функции должны сохраниться.

Работающий поиск по коллекции Meridian Museum

Познакомьтесь с тремя объектами Kubernetes

Переключитесь в Workstation. pwd печатает текущий каталог, а ls перечисляет его файлы:

pwd
ls

Каталог — /home/labex/project/museum. Pod запускает контейнер музея. Deployment поддерживает две реплики Pod и заменяет их при изменении шаблона контейнера. Service предоставляет посетителям постоянный адрес и направляет запросы к выбранным готовым Pod. Объекты связаны метками: Service выбирает Pod с app: search. Пространство имен объединяет объекты курса; в каждой команде ниже явно указан meridian.

kubectl просит кластер прочитать или изменить объекты. get выводит их список, -n выбирает пространство имен. cat печатает текстовый файл, позволяя прочитать подготовленный вариант обновления:

kubectl get deployments,pods,services -n meridian
cat candidate.yaml

В YAML используются key: value, пробелы для отступов и - для элементов списка. Под spec.template контейнер использует кешированный образ meridian-museum:1. imagePullPolicy: Never требует использовать подготовленный образ без загрузки из реестра. IMPORT_INTERVAL: "2" задает двухсекундный интервал между записями: двенадцать записей займут около 24 секунд. Начальные посетительские реплики использовали короткий интервал, чтобы вы сначала увидели нормальный поиск.

Подготовленное скользящее обновление сохраняет replicas: 2, допускает один дополнительный кандидат (maxSurge: 1) и не разрешает недоступность существующей реплики (maxUnavailable: 0). Для этого нужна честная готовность: без пробы работающий процесс может попасть в обслуживание раньше, чем заработает поиск. Сохраните эти настройки, образы, метки и Service.

Наблюдайте преждевременный трафик в учебном Service

Браузер использует HTTP, протокол запросов и ответов. Статус 200 означает успешный ответ, 503 — временную невозможность обработать этот запрос. Работа главной страницы не доказывает, что другая операция, например поиск, пройдет успешно.

У этого музея нет настоящих клиентов. Вы намеренно продемонстрируете небезопасное обновление, а затем улучшите его. cp копирует кандидат в редактируемый search.yaml. apply -f отправляет YAML из файла; изменение шаблона Pod запускает обновление. python3 запускает подготовленный наблюдатель, работающий только на чтение; --seconds 30 проверяет настоящий посетительский Service в течение 30 секунд. Он ищет в ответе оба латунных предмета. Запустите обновление и наблюдение вместе:

cp candidate.yaml search.yaml
kubectl apply -f search.yaml
python3 observe.py --seconds 30

Пока новые незащищенные контейнеры загружаются, ожидаются строки HTTP=503 correct_search=false. Точное число меняется. Главная страница продолжает работать; ответ поиска 503 прямо сообщает о подготовке коллекции. Это настоящий ответ загружающегося Pod, а не заранее заданная анимация успеха или отказа.

rollout status ждет обновления этого Deployment, а --timeout ограничивает ожидание:

kubectl rollout status deployment/search -n meridian --timeout=90s

Команда может сообщить об успехе, хотя предыдущий период загрузки не был защищен пробой готовности. Перед продолжением дождитесь нормальных результатов brass. Если вместо HTTP-статуса появилась ошибка соединения, прочитайте таблицу Pod и повторите попытку: отсутствующий сервер отличается от сервера, возвращающего 503.

Добавьте проверку готовности для задачи музея

Проба готовности определяет, должен ли этот Pod принимать трафик Service. Неудача исключает его из обслуживания, но не перезапускает контейнер. В этом образе /health/process всегда сообщает о процессе HTTP, а /ready/search возвращает 200 лишь после индексации всех двенадцати записей и успешной известной проверки brass. Главная страница тоже возвращает 200 во время импорта, поэтому ни она, ни процессный эндпоинт здесь не подходят.

patch изменяет выбранные поля. --patch-file читает ваш файл; --type=strategic объединяет настройки контейнера с именем search, сохраняя остальные. Проба отправляет HTTP к именованному порту http этого Pod, проверяет раз в две секунды и после одной неудачи отмечает его неготовым. Запишите небольшой патч ниже. cat > readiness.yaml заменяет файл. <<'YAML' начинает буквальный here-document: вставьте весь блок, включая завершающий YAML на отдельной строке. Сохраните отступы:

cat > readiness.yaml <<'YAML'
spec:
  template:
    spec:
      containers:
        - name: search
          readinessProbe:
            httpGet:
              path: /ready/search
              port: http
            periodSeconds: 2
            failureThreshold: 1
YAML
kubectl patch deployment search -n meridian --type=strategic --patch-file readiness.yaml
python3 observe.py --seconds 30

Пока новая реплика импортирует записи, существующие должны продолжать выдавать правильные результаты.

EndpointSlice хранит фактические адреса Pod и их готовность для Service. -l фильтрует по метке имени сервиса, -o jsonpath выбирает только адрес и ready из структурированного ответа. Подготовленное выражение перебирает записи эндпоинтов и печатает эти поля, только читая состояние. Проверьте Pod и адреса Service:

kubectl get pods -n meridian
kubectl get endpointslices -n meridian -l kubernetes.io/service-name=museum -o jsonpath='{range .items[].endpoints[*]}{.addresses[0]} ready={.conditions.ready}{"\n"}{end}'
kubectl rollout status deployment/search -n meridian --timeout=90s
kubectl get pods -n meridian

Во время импорта можно увидеть новый Pod 0/1 Running и адрес с ready=false. Существующие готовые эндпоинты продолжают выполнять поиск. После загрузки кандидат становится готовым, и замена продолжается. Если короткое промежуточное состояние прошло незамеченным, следующие шаги дадут больше времени для наблюдения.

В конце должны остаться ровно два Pod 1/1 Running. Старый Pod Terminating может ненадолго остаться после успешного обновления; подождите и повторяйте get pods, пока он не исчезнет. В Museum повторите brass-поиск и откройте астролябию. При ошибке YAML исправьте патч и примените снова. При опечатке пути пробы замените только путь в том же патче и примените повторно. Не удаляйте другие пространства имен и не ускоряйте импорт, чтобы скрыть ошибку.

Дайте импортеру достаточно времени на запуск

Вы отличите ожидание готовности от сбоя запуска и рассчитаете время по настоящему импорту. Начните в Workstation.

Проба запуска ограничивает время инициализации нового контейнера. Пока она не прошла, Kubernetes откладывает проверки готовности. Когда число ошибок запуска достигает порога, kubelet перезапускает контейнер. Такая проба необязательна; слишком короткая может не дать исправному приложению стать готовым. После успешного запуска она не заменяет readiness.

Наблюдайте слишком короткое время запуска

startup-short.yaml — подготовленный учебный пример. Ошибка пробы запрашивает перезапуск, но завершение контейнера может задержать рост видимого счетчика. Следующее клиентское ожидание длится 60 секунд, чтобы вы увидели эту разницу. Прочитайте пример перед применением:

cat startup-short.yaml
kubectl patch deployment search -n meridian --type=strategic --patch-file startup-short.yaml
kubectl rollout status deployment/search -n meridian --timeout=60s

Команда обновления должна завершиться ошибкой error: timed out waiting for the condition. Ее настоящий код выхода ненулевой. Продолжайте в интерактивном терминале. Пример проверяет раз в две секунды и разрешает лишь две неудачи — примерно четыре секунды на запуск. Этого не хватит на 24-секундный импорт.

Прочитайте текущие свидетельства. logs показывает вывод приложения; --prefix указывает Pod, а --tail=4 ограничивает каждый журнал последними четырьмя строками. Селектор выбирает все поисковые Pod. get events читает наблюдения кластера; --field-selector reason=Unhealthy оставляет только неудачные проверки здоровья:

kubectl get pods -n meridian
kubectl logs -n meridian -l app=search --prefix --tail=4
kubectl get events -n meridian --field-selector reason=Unhealthy

Новый Pod остается неготовым, а RESTARTS должен увеличиться. Может появиться CrashLoopBackOff: Kubernetes откладывает очередную попытку перезапуска. Если при зарегистрированных сбоях запуска таблица еще показывает ноль, подождите и повторите get pods до изменения времени: таблица отражает один момент, а завершение занимает время. Каждый перезапуск уничтожает индекс в памяти контейнера, и замена загружает записи снова.

Поздняя строка index_complete от контейнера, чья startup-проверка уже провалилась, не отменяет ожидаемый перезапуск и не делает его готовым backend для Service. Читайте счетчик перезапусков вместе с событиями ошибок запуска. Старые Pod остаются 1/1 и обслуживают поиск по завершенным индексам.

В Museum найдите brass. Через Service по-прежнему приходят правильные результаты от существующих готовых реплик. Застрявшее обновление не откатилось автоматически: Deployment продолжает требовать ошибочный кандидат. Работа старых реплик не означает завершение обновления.

Рассчитайте и примените подходящее время

Перейдите в Workstation. Двенадцать записей по две секунды требуют примерно 24 секунды. Здесь выделите 60 секунд: это покрывает и следующий импорт на 36 секунд, и учебный запас 12 секунд. periodSeconds × failureThreshold — приближение для планирования, а не гарантия срока; планирование задач, тайм-ауты проб и реальная нагрузка вносят изменения. В эксплуатации измеряйте запуск и выбирайте запас осознанно.

Используйте тот же метод файла патча. Сохраните реальный прикладной путь и именованный порт:

cat > startup.yaml <<'YAML'
spec:
  template:
    spec:
      containers:
        - name: search
          startupProbe:
            httpGet:
              path: /ready/search
              port: http
            periodSeconds: 2
            failureThreshold: 30
YAML
kubectl patch deployment search -n meridian --type=strategic --patch-file startup.yaml
kubectl rollout status deployment/search -n meridian --timeout=120s
kubectl get pods -n meridian

Это создает заменяющие Pod с исправленными настройками запуска. Каждый должен завершить загрузку без перезапуска; в итоговой таблице нужны два Pod 1/1 Running с RESTARTS 0. Дождитесь исчезновения старых завершающихся Pod и при необходимости повторите таблицу. После успешного запуска readiness продолжает управлять трафиком.

Если обновление еще стоит, прочитайте те же журналы и события, сравните путь и время в файле, исправьте и примените снова. Удаление Pod не исправляет шаблон Deployment: они будут созданы с теми же неверными настройками. Отличайте 60-секундный бюджет пробы от --timeout=120s, который ограничивает только ожидание обновления клиентом.

Сохраните поиск при более медленном обновлении

Вы примените более медленный импорт и оцените обновление по ответам Service и готовым эндпоинтам. Начните в Workstation.

kubectl set env изменяет переменную окружения в шаблоне контейнера Deployment. Он запускает заменяющие Pod, а не меняет окружение уже работающих контейнеров. Задайте трехсекундный интервал. Двенадцать записей теперь требуют около 36 секунд и укладываются в 60 секунд запуска:

kubectl set env deployment/search -n meridian IMPORT_INTERVAL=3
kubectl get pods -n meridian
kubectl get endpointslices -n meridian -l kubernetes.io/service-name=museum -o jsonpath='{range .items[].endpoints[*]}{.addresses[0]} ready={.conditions.ready}{"\n"}{end}'
python3 observe.py --seconds 45

При импорте новый Pod должен быть 0/1 Running. Существующие готовые адреса продолжают выдавать правильные результаты brass. Наблюдатель использует тот же NodePort Service, что и Museum, и никогда не выбирает определенный исправный Pod. В наблюдавшемся запуске защищенные запросы оставались корректными. Конечная выборка не обещает отсутствие ошибок при любых реальных условиях сети, приложения и кластера.

Дождитесь полного обновления и проверьте итог:

kubectl rollout status deployment/search -n meridian --timeout=120s
kubectl get pods -n meridian
kubectl get endpointslices -n meridian -l kubernetes.io/service-name=museum -o jsonpath='{range .items[].endpoints[*]}{.addresses[0]} ready={.conditions.ready}{"\n"}{end}'

Когда все старые Pod Terminating исчезнут, должны быть ровно два текущих готовых Pod без перезапусков, а их два адреса эндпоинтов должны показывать ready=true. Исправная старая реплика полезна во время импорта, но итоговое обновление действительно должно сойтись к новой ревизии.

Проверьте весь посетительский сервис

В Museum вернитесь домой через MERIDIAN и снова найдите brass. Должны появиться оба инструмента; откройте телескоп и перейдите по ссылке посещения. Найдите volcano: страница должна сообщить об отсутствии предметов, а не сломаться. Откройте Collection, посмотрите предмет не из латуни и скачайте список из Visit. Проверьте двенадцать предметов и сохранность иллюстраций и навигации.

Перейдите в Workstation. curl запрашивает URL; -sS скрывает прогресс, но показывает ошибки соединения. 127.0.0.1 означает этот учебный экземпляр, а порт 30081 принадлежит настоящему Service музея. Кавычки сохраняют URL запроса одним аргументом оболочки:

curl -sS 'http://127.0.0.1:30081/search?q=brass'

Прочитайте два правильных названия в HTML, а не только успешный код HTTP. Если проверка запущена при завершении старых Pod, подождите и повторите; не убирайте пробы и не сокращайте импорт. Сохраните кластер, подготовленный образ, Service и двенадцать исходных записей. Итог объединяет честную прикладную проверку готовности, достаточное время запуска и завершенное обновление с сохранением музейного опыта.

Резюме

Вы связали готовность с настоящим индексом коллекции, увидели сбой и перезапуск кандидата из-за короткой startup-пробы и рассчитали подходящее время запуска. Вы обновили импортер с заданным интервалом, пока готовые существующие реплики выполняли поиск, а затем проверили текущие Pod, эндпоинты Service и полный путь посетителя. Работающий процесс, готовый backend и завершенное обновление — разные факты; упражнение с одним узлом не подтверждает высокую доступность в эксплуатации или отсутствие ошибок.