Устранение неполадок с подключением в Kubernetes: эффективное использование exec и port-forward

Уверенно устраняйте неполадки с подключением и внутренними проблемами приложений в Kubernetes. Это руководство содержит практические примеры использования `kubectl exec` для выполнения команд внутри контейнеров и `kubectl port-forward` для безопасного доступа к сервисам с локальной машины. Узнайте, как диагностировать сетевые проблемы, проверять конфигурации и получать глубокое понимание поведения вашего приложения внутри кластера.

Устранение неполадок с подключением в Kubernetes: эффективное использование exec и port-forward

Когда сервис Kubernetes перестает отвечать, обычно нужно ответить на один простой вопрос, прежде чем что-то исправлять: где именно обрывается соединение? kubectl exec позволяет тестировать изнутри кластера, рядом с приложением. kubectl port-forward позволяет перенести один под или сервис на ваш ноутбук без изменения Ingress, LoadBalancer, правил брандмауэра или DNS-записей.

Используемые вместе, эти две команды помогают избежать догадок. Вы можете проверить, слушает ли приложение, работает ли кластерный DNS, указывает ли Service на правильные поды, и находится ли проблема в сетевой инфраструктуре Kubernetes или в самом приложении.

Понимание kubectl exec

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

Используйте ее осторожно в продакшене. Вы выполняете команду внутри реального контейнера с рабочей нагрузкой. Безобидные env, cat, curl или ss — это нормально. Установка пакетов, изменение файлов или запуск дорогостоящей диагностики внутри живого пода могут скрыть исходную проблему или создать новую.

Базовый синтаксис

Основной синтаксис для kubectl exec:

kubectl exec <имя-пода> -- <команда> [аргументы...]
  • <имя-пода>: Имя пода, в котором вы хотите выполнить команду.
  • --: Этот разделитель критически важен. Он различает флаги kubectl и команду, которую вы хотите выполнить внутри контейнера.
  • <команда>: Команда для выполнения внутри контейнера (например, ls, cat, ping).
  • [аргументы...]: Любые аргументы для команды.

Интерактивный доступ к оболочке

Одно из наиболее распространенных применений kubectl exec — получение интерактивной оболочки (например, bash или sh) внутри контейнера. Это позволяет исследовать файловую систему контейнера и выполнять несколько команд.

Для получения интерактивной оболочки:

kubectl exec -it <имя-пода> -- /bin/bash
  • -i (или --stdin): Держит stdin открытым, даже если не подключен.
  • -t (или --tty): Выделяет псевдо-TTY, что необходимо для интерактивных сессий оболочки.

Пример: Доступ к оболочке bash в поде с именем my-app-pod:

kubectl exec -it my-app-pod -- /bin/bash

Попав внутрь, вы можете использовать стандартные команды Linux. Чтобы выйти из оболочки, введите exit или нажмите Ctrl+D. Если /bin/bash отсутствует, попробуйте /bin/sh; многие маленькие образы не содержат Bash.

Выполнение одной команды

Вы также можете выполнить одну команду без интерактивной оболочки. Это полезно для быстрых проверок или написания скриптов.

Пример: Проверка файлов в каталоге /app пода my-app-pod:

kubectl exec my-app-pod -- ls /app

Пример: Просмотр содержимого файла конфигурации config.yaml:

kubectl exec my-app-pod -- cat /etc/my-app/config.yaml

Указание контейнера внутри пода

Если ваш под содержит несколько контейнеров, вам нужно указать, в каком контейнере выполнять команду, используя флаг -c.

kubectl exec <имя-пода> -c <имя-контейнера> -- <команда>

Пример: Выполнение env в sidecar-container пода multi-container-pod:

kubectl exec multi-container-pod -c sidecar-container -- env

Понимание kubectl port-forward

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

Это не путь для продакшен-трафика. Это отладочный туннель через ваше соединение с API Kubernetes. Если соединение с API-сервером прерывается, ваш локальный туннель также прерывается.

Базовый синтаксис

Общий синтаксис:

kubectl port-forward <имя-пода> <локальный-порт>:<удаленный-порт>
  • <имя-пода>: Имя пода, к которому вы хотите подключиться.
  • <локальный-порт>: Порт на вашей локальной машине, который будет прослушивать соединения.
  • <удаленный-порт>: Порт на поде, который будет принимать перенаправленный трафик.

Пример: Перенаправление локального порта 8080 на порт 80 пода my-app-pod:

kubectl port-forward my-app-pod 8080:80

После запуска этой команды вы можете получить доступ к вашему приложению, перейдя по адресу http://localhost:8080 в веб-браузере или используя такие инструменты, как curl на вашей локальной машине.

Перенаправление на сервис

Вы также можете перенаправлять трафик на сервис Kubernetes вместо конкретного пода. kubectl автоматически выберет под, поддерживающий этот сервис.

kubectl port-forward service/<имя-сервиса> <локальный-порт>:<порт-сервиса>

Пример: Перенаправление локального порта 3000 на порт 80 сервиса my-service:

kubectl port-forward service/my-service 3000:80

При перенаправлении на сервис помните, что kubectl выбирает один поддерживающий под. Если сломан только один реплика, перенаправление на уровне сервиса может его пропустить. Например, Deployment с тремя подами может иметь два здоровых пода и один под с плохой конфигурацией. Перенаправление на service/my-service может выбрать здоровый под, и сервис будет выглядеть исправным. Если вы подозреваете проблему, специфичную для реплики, перенаправляйте на точное имя пода.

Перенаправление на Deployment или StatefulSet

Аналогично, вы можете перенаправлять на Deployment или StatefulSet. kubectl выберет один из подов, управляемых указанным ресурсом.

kubectl port-forward deployment/<имя-deployment> <локальный-порт>:<порт-контейнера>
kubectl port-forward statefulset/<имя-statefulset> <локальный-порт>:<порт-контейнера>

Привязка к конкретному адресу

По умолчанию port-forward привязывается к localhost. Вы можете указать другой локальный адрес с помощью флага --address.

kubectl port-forward --address 127.0.0.1 <имя-пода> <локальный-порт>:<удаленный-порт>

Перенаправление нескольких портов

kubectl port-forward может перенаправлять несколько портов одновременно.

kubectl port-forward my-app-pod 8080:80 9090:90

Эта команда перенаправляет локальный порт 8080 на порт пода 80 и локальный порт 9090 на порт пода 90.

Распространенные сценарии устранения неполадок и решения

Сценарий 1: Приложение не отвечает, но под выглядит здоровым.

  • Проблема: Под работает, но запросы к его сервису завершаются ошибкой или истекают по тайм-ауту. Возможно, у приложения есть внутренние проблемы с конфигурацией или оно зависло.
  • Решение с помощью kubectl exec:
    1. Получите интерактивную оболочку в поде: kubectl exec -it <имя-пода> -- /bin/bash
    2. Внутри оболочки проверьте логи приложения (например, tail -f /var/log/myapp.log).
    3. Проверьте внутренние файлы конфигурации приложения.
    4. Проверьте сетевое подключение из пода к другим сервисам с помощью ping или curl (если они установлены).
  • Решение с помощью kubectl port-forward:
    1. Перенаправьте порт на порт, который слушает приложение: kubectl port-forward <имя-пода> 8080:<порт-приложения>
    2. Попробуйте получить доступ к приложению локально через http://localhost:8080. Это помогает определить, связана ли проблема с обнаружением сервисов Kubernetes или Ingress, или же само приложение не отвечает.

Если port-forward работает, а обычный URL сервиса — нет, проверьте селектор Service и endpoints:

kubectl get service <имя-сервиса> -n <пространство-имен> -o yaml
kubectl get endpoints <имя-сервиса> -n <пространство-имен>
kubectl get pods -n <пространство-имен> --show-labels

Очень распространенная ошибка — несовпадение меток. Поды здоровы, сервис существует, но селектор не соответствует меткам подов, поэтому у Service нет endpoints.

Сценарий 2: Необходимо отладить базу данных, работающую в поде.

  • Проблема: Вам нужно подключить ваш локальный клиент базы данных к базе данных, работающей внутри пода Kubernetes, чтобы просмотреть данные или выполнить запросы.
  • Решение с помощью kubectl port-forward:
    1. Определите под, на котором работает база данных, и его порт (например, mysql-pod, порт 3306).
    2. Перенаправьте локальный порт на порт базы данных: kubectl port-forward mysql-pod 3306:3306
    3. Настройте ваш локальный клиент базы данных для подключения к localhost:3306, используя соответствующие учетные данные базы данных.

Сценарий 3: Диагностика проблем с разрешением DNS внутри пода.

  • Проблема: Приложение внутри пода не может достичь других сервисов по их именам, что указывает на проблему с DNS.
  • Решение с помощью kubectl exec:
    1. Получите интерактивную оболочку в поде: kubectl exec -it <имя-пода> -- /bin/bash
    2. Внутри оболочки попробуйте разрешить известное имя сервиса: nslookup <имя-сервиса>.<пространство-имен>.svc.cluster.local или dig <имя-сервиса>.<пространство-имен>.svc.cluster.local.
    3. Проверьте содержимое /etc/resolv.conf, чтобы убедиться, что конфигурация DNS кластера внутри пода правильная.

Если образ не содержит nslookup, dig или curl, используйте временный отладочный под в том же пространстве имен:

kubectl run net-debug -n <пространство-имен> --rm -it --image=curlimages/curl -- sh

Оттуда протестируйте то же имя сервиса, которое использует ваше приложение. Это поможет отделить ситуацию "в образе моего приложения нет инструментов" от "кластерный DNS сломан".

Сценарий 4: Port-forward подключается, но сразу закрывается.

  • Проблема: kubectl port-forward выводит сообщение о перенаправлении, но соединение закрывается, когда вы открываете браузер или запускаете curl.
  • Вероятные причины: Целевой процесс не слушает удаленный порт, приложение привязывается только к 127.0.0.1 внутри контейнера, или под перезапускается, пока туннель открыт.
  • Проверки:
    kubectl exec <имя-пода> -n <пространство-имен> -- ss -lntp
    kubectl get pod <имя-пода> -n <пространство-имен> -w
    kubectl logs <имя-пода> -n <пространство-имен> --tail=100
    

Если процесс слушает порт 8080, а вы перенаправляете на 80, сам туннель в порядке; цель неверна. Если под перезапускается во время тестирования, сначала исправьте причину перезапуска, прежде чем разбираться с сетью.

Сценарий 5: Сервис работает из одного пода, но не из другого.

  • Проблема: Бэкенд может достичь Redis, но рабочий под в другом пространстве имен — нет.
  • Проверки с помощью exec:
    kubectl exec <исходный-под> -n <исходное-пространство-имен> -- curl -v http://<сервис>.<целевое-пространство-имен>.svc.cluster.local:<порт>
    kubectl exec <исходный-под> -n <исходное-пространство-имен> -- cat /etc/resolv.conf
    

Если DNS разрешается, но TCP не работает, проверьте NetworkPolicies, endpoints сервиса и принимает ли целевое приложение трафик из этого пространства имен. Если DNS не разрешается, сначала протестируйте полное доменное имя сервиса, прежде чем винить приложение.

Простая лестница подключения

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

  1. Внутри пода протестируйте локальный процесс приложения:
    kubectl exec <под> -n <пространство-имен> -- curl -v http://127.0.0.1:<порт>/health
    
  2. Из другого пода в том же пространстве имен протестируйте Service:
    kubectl run curl-test -n <пространство-имен> --rm -it --image=curlimages/curl -- curl -v http://<сервис>:<порт>/health
    
  3. С вашего ноутбука протестируйте через port-forward:
    kubectl port-forward service/<сервис> -n <пространство-имен> 8080:<порт-сервиса>
    curl -v http://localhost:8080/health
    
  4. Только после того, как эти шаги пройдены, переходите к Ingress, балансировщикам нагрузки, DNS и правилам брандмауэра.

Этот порядок экономит время, потому что каждый шаг доказывает один слой. Если localhost внутри пода не работает, Ingress не имеет значения. Если pod-local успешен, но доступ к Service не работает, приложение, вероятно, в порядке, и нужно обратить внимание на обнаружение сервисов Kubernetes.

Еще одна полезная привычка: во время отладки явно указывайте пространство имен. Многие запутанные сессии возникают из-за выполнения kubectl exec в пространстве имен default, в то время как сломанная рабочая нагрузка находится где-то еще. Либо установите пространство имен в вашем контексте для сессии, либо добавляйте -n <пространство-имен> к каждой команде. Дополнительный набор текста дешевле, чем тестирование не того пода.

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

Лучшие практики и советы

  • Держите port-forward работающим: kubectl port-forward работает в фоновом режиме. Вам нужно будет держать окно терминала открытым. Чтобы запустить его в фоне, вы можете использовать такие инструменты, как nohup или screen/tmux.
  • Используйте конкретные поды при отладке: Хотя перенаправление на сервисы удобно, для выявления проблем с конкретным экземпляром часто эффективнее перенаправлять на конкретный под по его имени.
  • Безопасность: Помните о том, какие порты вы открываете. Избегайте перенаправления чувствительных портов, если это не absolutely необходимо, и убедитесь, что ваша локальная машина защищена.
  • Использование ресурсов: kubectl exec может потреблять ресурсы. Используйте его разумно, особенно на продакшен-кластерах.
  • Разрешения: Убедитесь, что ваш контекст kubectl имеет необходимые разрешения для выполнения команд в подах или перенаправления портов.

Что записать после того, как вы это исправили

Хорошая отладка оставляет след. Зафиксируйте неработающий URL, исходный под, целевой сервис, пространство имен, точную команду, которая воспроизвела проблему, и слой, на котором произошел сбой. "Проблема с подключением" — слишком расплывчато, чтобы помочь в следующий раз. "Селектор сервиса не соответствовал подам после переименования метки" — это исправимый шаблон.