Сжатый справочник архитектурных шаблонов, проверяемых на экзамене CKA. Читайте сверху вниз или переходите к нужному разделу.
Архитектура, установка и настройка кластера
Требование выполнить резервное копирование состояния кластера для аварийного восстановления.
Используйте `etcdctl snapshot save` с соответствующими TLS-сертификатами (`--cacert`, `--cert`, `--key`) и конечной точкой.
Почему: etcd хранит все состояние кластера. Прямое создание снимков - это канонический способ резервного копирования. В кластере kubeadm TLS включен, поэтому сертификаты обязательны для аутентификации `etcdctl`.
Восстановить кластер из резервной копии для аварийного восстановления.
Используйте `etcdctl snapshot restore` в новый каталог данных. Затем обновите манифест статического пода `etcd.yaml`, чтобы его монтирование тома `--data-dir` указывало на новое место, и перезапустите kubelet.
Почему: Восстановление создает новый каталог данных. Манифест статического пода должен быть обновлен для использования этих новых данных, иначе etcd запустится со старым (или пустым) каталогом данных.
Выполнить обновление версии кластера, управляемого kubeadm.
1. На управляющем узле: обновите `kubeadm`, выполните `kubeadm upgrade plan`, затем `kubeadm upgrade apply`. 2. На каждом рабочем узле: `kubectl drain`, обновите `kubelet`, перезапустите службу kubelet, `kubectl uncordon`.
Почему: Процесс многоэтапный и последовательный. `kubeadm` обновляет только компоненты управляющего узла; `kubelet` должен быть обновлен вручную на каждом узле. Отключение узлов обеспечивает безопасное вытеснение рабочих нагрузок перед обслуживанием.
Срок действия сертификатов кластера истекает, и их необходимо проверить или обновить.
Используйте `kubeadm certs check-expiration` для просмотра сроков действия. Используйте `kubeadm certs renew all` (или для конкретных компонентов) для их обновления. Перезапустите поды управляющего узла после обновления.
Почему: Сертификаты, сгенерированные kubeadm, имеют срок действия 1 год. Обновление - это обычная задача обслуживания. Компоненты управляющего узла должны быть перезапущены для загрузки новых сертификатов.
Компонент управляющего узла (например, API-сервер) нуждается в настройке или перезапуске.
Измените манифест компонента в `/etc/kubernetes/manifests/`. Kubelet на узле автоматически обнаружит изменение и перезапустит под.
Почему: Компоненты управляющего узла в kubeadm запускаются как статические поды, управляемые непосредственно kubelet, а не API-сервером. Все управление происходит через файлы манифестов в отслеживаемом каталоге.
Определить управление доступом для пользователей или приложений.
Используйте `Role` и `RoleBinding` для разрешений, ограниченных пространством имен. Используйте `ClusterRole` и `ClusterRoleBinding` для разрешений в масштабе кластера.
Почему: Это фундаментальное разделение в RBAC. Role всегда привязана к пространству имен, тогда как ClusterRole может предоставлять доступ к ресурсам, не привязанным к пространствам имен (например, узлам), или к ресурсам во всех пространствах имен.
Учетная запись службы должна получить доступ к ресурсам во всех пространствах имен.
Создайте `ClusterRole`, определяющий разрешения. Создайте `ClusterRoleBinding`, чтобы предоставить этот ClusterRole конкретной `ServiceAccount`.
Почему: Хотя ServiceAccount привязан к пространству имен, ClusterRoleBinding может предоставить ему разрешения в масштабе кластера. `RoleBinding` предоставил бы разрешения только в рамках собственного пространства имен RoleBinding.
Сервисы и сети
Предоставить доступ к приложению для внешнего трафика без облачного балансировщика нагрузки.
Используйте Service с `type: NodePort`. Это открывает службу на статическом порту (диапазон по умолчанию: 30000-32767) по IP-адресу каждого узла.
Почему: NodePort - это простой способ получить внешний трафик в кластер. Он менее дорогой и платформенно-независимый по сравнению с `type: LoadBalancer`, но требует, чтобы клиенты знали IP-адрес узла.
Предоставить доступ к нескольким HTTP/S-службам по одному IP-адресу с маршрутизацией на основе хоста или пути.
Разверните Ingress Controller (например, NGINX). Создайте ресурсы `Ingress`, которые определяют правила маршрутизации от хостов/путей к внутренним `Services`.
Почему: Ingress - это стандартный ресурс Kubernetes для маршрутизации L7. Для фактической реализации логики маршрутизации требуется отдельный контроллер. Это разделяет правила маршрутизации от реализации прокси.
Защитить пространство имен, запретив весь входящий трафик по умолчанию.
Создайте `NetworkPolicy`, который выбирает все поды (`podSelector: {}`) и указывает пустое правило входящего трафика (`ingress: []`).
Почему: Как только под выбран любой NetworkPolicy, весь трафик, который не разрешен явно, отклоняется. Политика, выбирающая все поды с пустым правилом входящего трафика, фактически создает брандмауэр "запретить все" для пространства имен.
Разрешить подам в пространстве имен "frontend" доступ к подам в пространстве имен "backend".
В пространстве имен "backend" создайте NetworkPolicy. В правиле `ingress.from` используйте `namespaceSelector` для сопоставления меток ресурса `Namespace` "frontend".
Почему: `podSelector` работает только в пределах пространства имен политики. Чтобы разрешить трафик из других пространств имен, необходимо использовать `namespaceSelector`. Это требует маркировки самих объектов `Namespace`.
Приложение должно подключиться к другой службе в кластере.
Используйте внутреннее DNS-имя службы: `<service-name>.<namespace>.svc.cluster.local`. Если в том же пространстве имен, достаточно `<service-name>`.
Почему: Kubernetes обеспечивает стабильное обнаружение служб на основе DNS через CoreDNS. Это отделяет приложения от конкретных IP-адресов подов, которые являются эфемерными.
Состояниезависимому приложению (например, набору реплик базы данных) требуется прямая сетевая идентификация для каждого пода.
Создайте безголовый `Service` (`clusterIP: None`) для `StatefulSet`. Это предоставляет уникальные записи DNS A для каждого пода (например, `pod-0.my-service.my-ns...`).
Почему: Безголовая служба не выполняет балансировку нагрузки. Вместо этого она предоставляет DNS-записи для каждого пода, позволяя клиентам подключаться к конкретным экземплярам, что крайне важно для выбора лидера или обнаружения узлов в состояниезависимых системах.
Внешняя служба должна видеть исходный IP-адрес клиента для журналирования или фильтрации по IP-адресу.
Установите `externalTrafficPolicy: Local` для Service `NodePort` или `LoadBalancer`.
Почему: Политика `Cluster` по умолчанию скрывает IP клиента через SNAT. `Local` позволяет избежать этого дополнительного сетевого перехода, маршрутизируя трафик только к подам на узле, который получил трафик, сохраняя исходный IP.
Рабочие нагрузки и планирование
Разместить поды вместе или распределить их для повышения производительности или высокой доступности.
Используйте `podAffinity` для планирования подов на том же узле/зоне, что и другие конкретные поды. Используйте `podAntiAffinity`, чтобы избежать их совместного планирования.
Почему: Это обеспечивает более расширенный контроль планирования, чем привязка на уровне узла. Anti-affinity с `requiredDuringScheduling...` критически важна для распределения реплик службы по узлам или зонам для обеспечения высокой доступности.
Выделить узлы для определенных рабочих нагрузок или запретить запуск определенных рабочих нагрузок на них.
Примените `taint` к узлу (например, `gpu=true:NoSchedule`). Добавьте соответствующую `toleration` к подам, которым разрешено запускаться на этом узле.
Почему: Taints отталкивают поды, а tolerations позволяют им. Это основной механизм выделения узлов. Эффект `NoExecute` вытеснит уже запущенные поды, у которых нет этой toleration.
Развернуть агент мониторинга или журналирования на каждом узле кластера.
Используйте `DaemonSet`. Он гарантирует, что копия пода будет запущена на каждом узле, который соответствует его критериям планирования.
Почему: DaemonSet предназначен именно для этой цели. Он автоматически развертывается на новых узлах и управляет подами на уровне узлов, что было бы сложно с Deployment.
Запустить одноразовую пакетную задачу или повторяющуюся запланированную задачу.
Используйте `Job` для задачи, которая выполняется один раз до завершения. Используйте `CronJob` для создания задач по повторяющемуся расписанию (например, ночные резервные копии).
Почему: Jobs гарантируют, что поды будут работать до указанного количества завершений. CronJobs - это контроллер более высокого уровня, который управляет Jobs на основе расписания cron.
Обновить приложение до новой версии без простоя.
Используйте `Deployment` со стратегией `RollingUpdate` по умолчанию. Настройте `maxSurge` и `maxUnavailable` для контроля скорости обновления и доступности.
Почему: Постепенные обновления постепенно заменяют старые поды новыми, обеспечивая доступность службы. `maxUnavailable` гарантирует запуск минимального количества подов, а `maxSurge` позволяет превысить желаемое количество реплик для ускорения развертывания.
Обеспечить подам гарантированные ресурсы и предотвратить чрезмерное потребление ресурсов на узле.
Установите `resources.requests` (CPU/память), чтобы гарантировать минимум для планирования. Установите `resources.limits`, чтобы предотвратить превышение контейнером определенного объема.
Почему: Запросы используются планировщиком для размещения и гарантирования ресурсов. Лимиты enforced kubelet и средой выполнения контейнера; превышение лимита памяти приводит к OOMKill.
Развернуть состояниезависимое приложение, которое требует стабильных, уникальных сетевых идентификаторов и постоянного хранилища для каждой реплики.
Используйте `StatefulSet` с `volumeClaimTemplate`. Это создает уникальный `PersistentVolumeClaim` для каждого пода, гарантируя повторное присоединение данных к той же идентификации пода при перезапуске.
Почему: StatefulSets предоставляют стабильные имена подов (например, `web-0`, `web-1`) и уникальный, постоянный PVC для каждого. Это крайне важно для приложений, которые полагаются на стабильную идентификацию и хранилище.
Хранилище
Предоставить постоянное хранилище для приложения без предварительного выделения томов.
Создайте `StorageClass`, который определяет поставщика хранилища. Затем создайте `PersistentVolumeClaim` (PVC), который запрашивает хранилище из этого класса. `PersistentVolume` (PV) будет динамически выделен.
Почему: Это отделяет приложения от базовой инфраструктуры хранилища. Разработчики запрашивают хранилище через PVC, а администратор кластера определяет, как это хранилище выделяется через StorageClass.
Контролировать, что происходит с постоянным томом после удаления его заявки.
Установите `persistentVolumeReclaimPolicy` для PV или StorageClass. `Delete` автоматически удаляет базовое хранилище. `Retain` оставляет том и данные нетронутыми, требуя ручной очистки.
Почему: `Retain` - самый безопасный вариант для производственных данных, так как он предотвращает случайную потерю данных. `Delete` удобен для эфемерных или тестовых сред. По умолчанию зависит от поставщика.
Определить, как том может быть смонтирован подами.
Используйте `accessModes`: `ReadWriteOnce` (RWO) для одноузлового чтения-записи, `ReadOnlyMany` (ROX) для многоузлового чтения-записи, `ReadWriteMany` (RWX) для многоузлового чтения-записи.
Почему: Режим доступа должен поддерживаться базовым поставщиком хранилища. Несоответствие потребностей приложения (например, требуется RWX) с возможностями хранилища (поддерживается только RWO) является частой причиной зависших PVC.
Внедрить файлы конфигурации или конфиденциальные данные в под.
Смонтируйте `ConfigMap` или `Secret` как том. Каждый ключ в объекте данных становится файлом в пути монтирования.
Почему: Это стандартный способ предоставления конфигурации подам. Он позволяет управлять конфигурацией как объектом Kubernetes и обновлять ее независимо от образа пода.
Приложению требуется больше места для хранения в существующем постоянном томе.
Убедитесь, что `StorageClass` имеет `allowVolumeExpansion: true`. Измените `PVC`, чтобы запросить больший размер в `spec.resources.requests.storage`.
Почему: Расширение тома - это функция, которую необходимо явно включить. StorageClass должен явно разрешать это, а базовый драйвер CSI должен поддерживать это. Возможно, потребуется перезапустить под для изменения размера файловой системы.
Устранение неполадок
Под застрял в состоянии `Pending` и не планируется.
Выполните `kubectl describe pod <pod-name>`. Проверьте раздел `Events` на наличие сообщений от планировщика.
Почему: Команда `describe` - это основной инструмент для этого. Она покажет причины, такие как "Недостаточно CPU/памяти", "узел(ы) имел(и) taint(ы), которые под не tolerował", или "не совпал селектор узла".
Под многократно запускается и завершается сбоем, имея статус `CrashLoopBackOff`.
1. `kubectl logs <pod-name> --previous` для просмотра логов из упавшего контейнера. 2. `kubectl describe pod <pod-name>` для проверки кода выхода и причины.
Почему: `CrashLoopBackOff` означает, что приложение внутри контейнера завершает работу. Логи предыдущего экземпляра (`--previous`) критически важны, так как текущий контейнер, возможно, еще не записал ничего полезного. Код выхода также может указывать на тип ошибки.
Под не запускается со статусом `ImagePullBackOff` или `ErrImagePull`.
`kubectl describe pod <pod-name>` для просмотра сообщения о событии. Убедитесь, что имя и тег образа верны. Для частных реестров убедитесь, что `imagePullSecrets` настроен, а секрет действителен.
Почему: Это проблема реестра или имени образа, а не приложения. Распространенные причины - опечатки, неверные теги или сбой аутентификации в частном реестре.
Узел имеет статус `NotReady`.
Подключитесь по SSH к затронутому узлу. Проверьте статус службы kubelet с помощью `systemctl status kubelet`. Просмотрите ее логи с помощью `journalctl -u kubelet`.
Почему: `kubelet` - это агент, отвечающий за отчеты о состоянии узла. Если он не работает или не может связаться с API-сервером, узел будет помечен как NotReady. Его логи - первое место, куда следует заглянуть.
Служба существует, но трафик не достигает внутренних подов.
1. `kubectl describe svc <service-name>` и убедитесь, что `Selector` соответствует меткам подов. 2. `kubectl get endpoints <service-name>` и убедитесь, что он перечисляет правильные IP-адреса подов. Если нет, метки не совпадают.
Почему: Связь между Service и его подами - это селектор меток. Если селектор неверен или поды не имеют правильных меток, объект Endpoints будет пустым, и служба не сможет маршрутизировать трафик.
Поды не могут разрешить имена служб или внешние имена хостов.
1. Проверьте, запущены ли поды CoreDNS в `kube-system`. 2. Проверьте логи CoreDNS. 3. Запустите отладочный под (например, `busybox`) и используйте `nslookup` для проверки разрешения внутри кластера.
Почему: DNS - критическая зависимость кластера. Сбои обычно связаны с самим развертыванием CoreDNS, его конфигурацией (в ConfigMap) или сетевыми политиками, блокирующими DNS-трафик на портах UDP/TCP 53.
Узел должен быть выведен из эксплуатации для обслуживания.
Сначала `kubectl cordon <node-name>`, чтобы пометить его как непланируемый. Затем `kubectl drain <node-name> --ignore-daemonsets`, чтобы безопасно вытеснить все пользовательские поды.
Почему: `cordon` предотвращает планирование новых подов. `drain` соблюдает PodDisruptionBudgets и изящно вытесняет поды. `--ignore-daemonsets` необходим, потому что поды DaemonSet не могут быть вытеснены.
Определить, какие поды или узлы потребляют больше всего CPU или памяти.
Используйте `kubectl top pods` и `kubectl top nodes`. Для этого требуется, чтобы `metrics-server` был развернут в кластере.
Почему: `kubectl top` предоставляет быстрый просмотр потребления ресурсов в реальном времени, что крайне важно для выявления ресурсоемких приложений или нагрузки на ресурсы узлов.
Под долгое время находится в состоянии `Terminating` и не удаляется.
Принудительно удалите под с помощью `kubectl delete pod <pod-name> --grace-period=0 --force`.
Почему: Это может произойти, если финализатор застрял или kubelet не может очистить ресурсы. Принудительное удаление немедленно удаляет под с API-сервера, но его следует использовать в крайнем случае, так как это может оставить безхозные ресурсы на узле.