kubernetes kubectl

Шпаргалка

КомандаЧто делает
kubectl apply -f файл.yamlприменить манифест: создать или обновить объект
kubectl get podsсписок подов и их статусы
kubectl get deploymentsсписок Deployment
kubectl get servicesсписок Service с их адресами
kubectl logs имя-подалоги контейнера в поде
kubectl describe pod имя-подаподробности и события пода
kubectl delete pod имя-подаудалить под (Deployment тут же поднимет новый)
kubectl rollout status deployment/webследить за выкатом новой версии
kubectl port-forward service/web 8080:80прокинуть сервис на свой компьютер

Pod, Deployment, Service – три слова, которые нужно запомнить

Из шага про архитектуру вы знаете, кто внутри кластера работает. Теперь разберем то, чем пользуются каждый день: три объекта, из которых собирается почти любое приложение в Kubernetes. Все трое описываются YAML-манифестами и применяются одной командой `kubectl apply`, как в скринкасте. Идем от самого мелкого к самому верхнему, чтобы каждый следующий объект опирался на предыдущий.

Начинается все с Pod

Сам под вам уже знаком, это обертка вокруг контейнера со своим IP. Вот как выглядит его манифест целиком:

apiVersion: v1
kind: Pod
metadata:
  name: web
  labels:
    app: web
spec:
  containers:
    - name: nginx
      image: nginx:1.27
      ports:
        - containerPort: 80

Структура у всех манифестов Kubernetes одинаковая, поэтому разберем ее один раз. `apiVersion` и `kind` говорят, что за объект описывается. `metadata` это имя объекта и лейблы (про них через минуту, они важнее, чем кажутся). `spec` это желаемое состояние, здесь один контейнер из образа nginx.27, слушающий порт 80.

Применяем и смотрим:

kubectl apply -f pod.yaml
kubectl get pods
NAME   READY   STATUS    RESTARTS   AGE
web    1/1     Running   0          10s

Под запущен. Заглянуть в его логи можно через `kubectl logs web`, а подробности и события через `kubectl describe pod web`.

И сразу правда жизни: вот так напрямую, руками, поды почти никогда не создают. Этот под одинок: если умрет узел, на котором он живет, пересоздавать его будет некому, ведь никто в кластере не обещал, что подов с именем web должно быть сколько-то. Подовый манифест мы разобрали потому, что он целиком ляжет внутрь следующего объекта.

Лейблы, на которых все держится

Строчка `labels: app: web` из манифеста это лейбл: произвольная пара ключ-значение, стикер на объекте. Сам по себе стикер не делает ничего. Но именно по стикерам объекты в Kubernetes находят друг друга: Deployment узнает свои поды, Service понимает, кому слать трафик. Механизм называется селектором и читается как «мне нужны все поды со стикером app: web». Запомните эту пару строк, она клей всего, о чем дальше пойдет речь.

Deployment следит за копиями

Формулировка из заголовка, «хочу 3 копии этого пода, и если один упадет, подними новый», это дословное описание Deployment:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: web
spec:
  replicas: 3
  selector:
    matchLabels:
      app: web
  template:
    metadata:
      labels:
        app: web
    spec:
      containers:
        - name: nginx
          image: nginx:1.27
          ports:
            - containerPort: 80

Три составные части. `replicas` это сколько копий держать. `selector` это каких подов считать своими, всех со стикером app: web. `template` это шаблон, по которому штамповать поды, и присмотритесь: внутри template лежит ровно тот подовый манифест из начала, с теми же контейнерами и лейблом. Deployment это количество, селектор и шаблон пода, и ничего больше.

Одна деталь устройства, которую полезно знать: напрямую подами Deployment не управляет. Он создает промежуточный объект ReplicaSet, и уже тот следит, чтобы число подов совпадало с `replicas`. В повседневной работе вы имеете дело с Deployment, а ReplicaSet делает свое дело тихо, но при выкате новой версии вы увидите его в выводе команд, и теперь понятно, откуда он берется.

Применяем:

kubectl apply -f deployment.yaml
kubectl get pods
NAME                   READY   STATUS    RESTARTS   AGE
web-7c9f8d6b4-2xkq9    1/1     Running   0          15s
web-7c9f8d6b4-8jzwm    1/1     Running   0          15s
web-7c9f8d6b4-tg5rp    1/1     Running   0          15s

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

Теперь лучший пятиминутный аттракцион в Kubernetes, убить под и посмотреть, что будет:

kubectl delete pod web-7c9f8d6b4-2xkq9
kubectl get pods
NAME                   READY   STATUS    RESTARTS   AGE
web-7c9f8d6b4-8jzwm    1/1     Running   0          2m
web-7c9f8d6b4-tg5rp    1/1     Running   0          2m
web-7c9f8d6b4-x4nd2    1/1     Running   0          4s

Подов снова три, у одного возраст четыре секунды. ReplicaSet под управлением Deployment заметил «заявлено три, вижу два» и пересоздал недостающий, тот самый self-healing из шага про архитектуру, теперь вызванный вашими руками.

Здесь же живет и rolling update из шага «Зачем Kubernetes»: поменяйте в манифесте образ на nginx.28, выполните apply, и Deployment по очереди заменит старые поды новыми. Следить за процессом можно командой `kubectl rollout status deployment/web`.

Service дает постоянный адрес

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

apiVersion: v1
kind: Service
metadata:
  name: web
spec:
  selector:
    app: web
  ports:
    - port: 80
      targetPort: 80

Снова селектор, снова те же стикеры: Service направляет трафик всем живым подам с лейблом app: web, какими бы они ни были сегодня. `port` это на каком порту слушает сам Service, `targetPort` это на какой порт пода передавать.

kubectl apply -f service.yaml
kubectl get services
NAME   TYPE        CLUSTER-IP    PORT(S)
web    ClusterIP   10.96.45.12   80/TCP

У Service появился постоянный адрес, ClusterIP, который не изменится, сколько бы поды под ним ни пересоздавались. Больше того, внутри кластера к нему можно обращаться просто по имени: у Kubernetes есть свой DNS, и другое приложение в кластере пойдет на http://web, не зная вообще никаких IP.

Тип ClusterIP означает «адрес доступен внутри кластера». Чтобы заглянуть на сервис со своего компьютера во время экспериментов, есть удобный прием из скринкаста:

kubectl port-forward service/web 8080:80

После этого http://localhost:8080 на вашей машине ведет в кластер, на один из подов, и там встречает страница nginx. Полноценный вход трафика снаружи это Ingress, оставленный за рамками еще на прошлом шаге.

Как трое работают вместе

                Deployment "web"
                (replicas: 3, шаблон пода)
                      │ через ReplicaSet штампует и пересоздает
        ┌─────────────┼─────────────┐
      [под]         [под]         [под]     лейбл app: web
        ▲             ▲             ▲
        └─────────────┼─────────────┘
                      │ селектор app: web
                Service "web"
                (постоянный адрес, балансировка)
                      ▲
                 трафик к приложению

Роли распределены так: Pod это где работает контейнер, Deployment это сколько их должно быть и какими, Service это как до них добраться.

Связаны они не ссылками друг на друга, а лейблами: Deployment штампует поды со стикером, Service по тому же стикеру их находит. Эта тройка минимальный комплект практически любого приложения в Kubernetes, ведь объектов в кубере десятки, но эти три встречаются в каждом проекте без исключений, отсюда и заголовок.