Uruchom kubectl run nginx --image=nginx:1.27, a Kubernetes utworzy dokładnie jeden Pod o nazwie nginx. Usuń go poleceniem kubectl delete pod nginx i zniknie na dobre — nikt tego nie zauważy, nikt go nie zastąpi. Pod to najmniejsza jednostka wdrożeniowa w Kubernetes: jeden lub więcej kontenerów dzielących namespace sieciowy i zestaw wolumenów, zaplanowanych razem na jednym Node.

Taki pojedynczy Pod to ślepy zaułek w produkcji. Jeśli kontener w nim się wywali, kubelet uruchomi go ponownie w tym samym miejscu. Jeśli Node się zrestartuje albo ktoś usunie Pod, nic go nie odtworzy. Goły Pod nie wie, że w ogóle powinien istnieć.

Co Deployment dodaje do Poda

Deployment to obiekt Kubernetes, który określa, ile kopii Poda powinno istnieć i jak wdrażać w nich zmiany. Przestajesz zarządzać Podami bezpośrednio i opisujesz stan docelowy; pętla kontrolna dba o to, żeby ten stan się urzeczywistnił. To ta sama pętla, która stoi za wszystkim innym w Kubernetes.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-app
spec:
  replicas: 3
  selector:
    matchLabels:
      app: web-app
  template:
    metadata:
      labels:
        app: web-app
    spec:
      containers:
        - name: web-app
          image: nginx:1.27
          ports:
            - containerPort: 80
1
2
kubectl apply -f web-app-deployment.yaml
kubectl get pods
1
2
3
4
NAME                       READY   STATUS    RESTARTS   AGE
web-app-7d9f8c7b86-4kxqz   1/1     Running   0          8s
web-app-7d9f8c7b86-9wj2p   1/1     Running   0          8s
web-app-7d9f8c7b86-x2p6t   1/1     Running   0          8s

Trzy Pody, nie jeden, i żaden nie nazywa się web-app. Ten schemat nazewnictwa (web-app-7d9f8c7b86-4kxqz) to pierwszy sygnał, że zarządza nimi coś innego.

replicas: 3 robi to samo, co docker compose up --scale web=3 w Docker Compose. Różnica polega na tym, że tutaj kontroler egzekwuje tę liczbę długo po zakończeniu wykonania polecenia.

Jak Deployment naprawdę tworzy Pody: rola ReplicaSet

Deployment nie tworzy Podów bezpośrednio. Tworzy ReplicaSet, a to ReplicaSet tworzy Pody. Cały łańcuch widać na własne oczy:

1
2
3
kubectl get deployment web-app
kubectl get replicaset -l app=web-app
kubectl get pods -l app=web-app
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
NAME      READY   UP-TO-DATE   AVAILABLE   AGE
web-app   3/3     3            3           2m

NAME                 DESIRED   CURRENT   READY   AGE
web-app-7d9f8c7b86   3         3         3       2m

NAME                       READY   STATUS    RESTARTS   AGE
web-app-7d9f8c7b86-4kxqz   1/1     Running   0          2m
web-app-7d9f8c7b86-9wj2p   1/1     Running   0          2m
web-app-7d9f8c7b86-x2p6t   1/1     Running   0          2m

Nazwa ReplicaSet to nazwa Deployment plus hash szablonu Poda (7d9f8c7b86); nazwa każdego Poda to nazwa ReplicaSet plus losowy sufiks. kubectl describe pod web-app-7d9f8c7b86-4kxqz pokazuje tę zależność wprost, w polu Controlled By: ReplicaSet/web-app-7d9f8c7b86.

Usuń jeden z tych Podów, a licznik spadnie do 2. W ciągu kilku sekund pojawi się zastępca. To ReplicaSet zauważa brak i tworzy nowy Pod z tego samego szablonu — Deployment nie robi tego bezpośrednio. ReplicaSet pilnuje. Deployment istnieje dla jednej rzeczy, której ReplicaSet nie potrafi zrobić sam: zastąpić szablon Poda stopniowo, zamiast od razu wszystkiego naraz.

Co rollout robi z ReplicaSetami

Zmień obraz i zastosuj:

1
2
kubectl set image deployment/web-app web-app=nginx:1.27.1
kubectl rollout status deployment/web-app
1
2
3
Waiting for deployment "web-app" rollout to finish: 1 out of 3 new replicas have been updated...
Waiting for deployment "web-app" rollout to finish: 2 out of 3 new replicas have been updated...
deployment "web-app" successfully rolled out

W tle Deployment utworzył drugi ReplicaSet dla nowego szablonu Poda i skalował go w górę, jednocześnie skalując stary w dół. Przy domyślnej strategii RollingUpdate i 3 replikach oznacza to wymianę jednego Poda na raz:

1
kubectl get replicaset -l app=web-app
1
2
3
NAME                 DESIRED   CURRENT   READY   AGE
web-app-7d9f8c7b86   0         0         0       6m
web-app-6b8f6d9c4d   3         3         3       40s

Stary ReplicaSet nie jest usuwany. Zostaje przy zerze replik, zachowując poprzedni szablon Poda jako zapis. Dzięki temu rollback jest szybki:

1
kubectl rollout undo deployment/web-app

Kubernetes skaluje stary ReplicaSet z powrotem w górę, a nowy w dół — bez przebudowy, bez ponownego pobierania starego obrazu, jeśli nadal jest w cache na Node. kubectl rollout history deployment/web-app --revision=1 nadal pokazuje dokładnie, jaki obraz uruchamiała ta rewizja.

Kiedy goły Pod to dobry wybór

Goły Pod nie jest błędem w każdym kontekście, tylko w większości z nich:

  1. Jednorazowy kontener diagnostyczny, który usuniesz za pięć minut: kubectl run debug --image=busybox -it --rm -- sh.
  2. Job albo CronJob, który tworzy Pody przez własny kontroler, bo praca ma dobiec końca, a nie zostać uruchomiona na stałe.
  3. Sprawdzanie lub poznawanie samej spec Poda, zanim zostanie owinięta w coś, co nią zarządza.

Wszystko, co ma przetrwać awarię, padnięcie Node’a albo aktualizację, powinno być zarządzane przez Deployment. Albo przez StatefulSet, dla Podów, które potrzebują stabilnej tożsamości i własnego storage — to inny problem i inny obiekt. Domyślnie pisz manifest Deployment, a do gołego Poda schodź tylko w trzech powyższych przypadkach.

Pod, ReplicaSet i Deployment obok siebie

PodReplicaSetDeployment
Czym zarządzaKonteneramiPodamiReplicaSetami
Zastępuje usuniętą instancjęNieTakTak, przez swój ReplicaSet
Skaluje do N replikNieTakTak
Rolling updateNieNieTak
Rollback do wcześniejszej wersjiNieNieTak
Tworzysz go bezpośrednioRzadkoPrawie nigdyZwykle

Sprawdź, czy Twoje Pody są zarządzane przez Deployment

Uruchom to na tym, co już masz w klastrze:

1
kubectl get deployment,replicaset,pod -l app=<twoj-label>

Jeśli wracają tylko wiersze Pod, to są gołe Pody. To luka, którą warto załatać, zanim kolejny drain Node’a zabierze razem z nimi także twoją aplikację.

Powiązane artykuły