Rolling Updates e Rollbacks
Quando estamos criando um deployment podemos definir estratégias de atualização.
Recreate: destrói os velhos e cria novos deixando a aplicação fora do ar enquanto o processo termina.RollingUpdate(default): vai destruindo um e subindo outro mantendo a aplicação no ar.

Podemos fazer update de várias coisas:
- Nova imagem
- Labels
- Número de replicas
- Argumentos
- Variáveis de ambiente
- etc
A melhor maneira de fazer isso configurando novamente o arquivo de manifesto e usando o comando kubectl apply -f manifesto.yaml, para manter um arquivo de configuração fiel ao que está deployado no cluster.
Através do edit ou do comando set image como mostrando abaixo:
k create deployment nginx --image nginx
deployment.apps/nginx created
# nginx é o nome da imagem
k set image deployment/nginx nginx=1.17
deployment.apps/nginx image updated
# Vamos deployar um pod com dois containers por exemplo.
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
name: pod-com-dois-containers
spec:
containers:
- name: alpha
image: nginx
ports:
- containerPort: 80
- name: beta
image: alpine
command: ["/bin/sh", "-c"]
args:
- sleep 4800
EOF
# Vamos atualizar somente a imagem do nginx no pod
kubectl set image pods/pod-com-dois-containers alpha=nginx:1.17
pod/pod-com-dois-containers image updated
Veja a diferença dos eventos que acontecem usando essas duas estratégias.

O Recreate escalou para 0 e depois para 5 novamente e o RollingUpdate foi reduzindo e aumentando gradativamente.
O deployment cria o replicaset que deploya um conjunto de pods. Quando atualizamos o deployment ele irá criar outro replicaset que deployará novos pods e manterá o antigo zerado, mas ainda esta presente.

É por isso que conseguimos fazer um rollback da aplicação para o replicaset antigo caso o novo esteja com algum problema.
O deployment cria revisões apontando para os replicaset corretos e através disso podemos voltar com o comando rollout.

kubectl create deployment nginx --image nginx:1.24 --replicas 2 -o yaml --dry-run=client > nginx.yaml
kubectl apply -f nginx1.24.yaml
deployment.apps/nginx created
kubectl get deploy
NAME READY UP-TO-DATE AVAILABLE AGE
nginx 2/2 2 2 11s
kubectl get rs
NAME DESIRED CURRENT READY AGE
nginx-69d846b5c6 2
# Criei outro arquivo baseado no 1.24 mas com a imagem de 1.25
kubectl apply -f nginx1.25.yaml
deployment.apps/nginx configured # Observe que não foi criado, só configurado
kubectl describe deployments.apps nginx
Name: nginx
Namespace: default
CreationTimestamp: Sat, 30 Dec 2023 11:26:06 -0300
Labels: app=nginx
# usa annotations para definir a revisão
Annotations: deployment.kubernetes.io/revision: 2
Selector: app=nginx
Replicas: 2 desired | 2 updated | 2 total | 2 available | 0 unavailable
# Observe que RollingUpdate é default e ele mata 25% e sobe 25%
StrategyType: RollingUpdate
MinReadySeconds: 0
RollingUpdateStrategy: 25% max unavailable, 25% max surge
Pod Template:
Labels: app=nginx
Containers:
nginx:
Image: nginx:1.25
Port: <none>
Host Port: <none>
Environment: <none>
Mounts: <none>
Volumes: <none>
Conditions:
Type Status Reason
---- ------ ------
Available True MinimumReplicasAvailable
Progressing True NewReplicaSetAvailable
# Veja que ele mostra o replicaset anterior e o novo
OldReplicaSets: nginx-69d846b5c6 (0/0 replicas created)
NewReplicaSet: nginx-7b8df77865 (2/2 replicas created)
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal ScalingReplicaSet 2m9s deployment-controller Scaled up replica set nginx-69d846b5c6 to 2
Normal ScalingReplicaSet 30s deployment-controller Scaled up replica set nginx-7b8df77865 to 1
Normal ScalingReplicaSet 23s deployment-controller Scaled down replica set nginx-69d846b5c6 to 1 from 2
Normal ScalingReplicaSet 23s deployment-controller Scaled up replica set nginx-7b8df77865 to 2 from 1
Normal ScalingReplicaSet 16s deployment-controller Scaled down replica set nginx-69d846b5c6 to 0 from 1
kubectl rollout history deployment nginx
deployment.apps/nginx
REVISION CHANGE-CAUSE
1 <none>
2 <none>
# O undo volta para revisão anterior, ou seja usando o old-replica
# O rollout funciona para daemonset deployment statefulset
kubectl rollout undo deployment nginx
deployment.apps/nginx rolled back
kubectl describe deployments.apps nginx
Name: nginx
Namespace: default
CreationTimestamp: Sat, 30 Dec 2023 11:26:06 -0300
Labels: app=nginx
Annotations: deployment.kubernetes.io/revision: 3
Selector: app=nginx
Replicas: 2 desired | 2 updated | 2 total | 2 available | 0 unavailable
StrategyType: RollingUpdate
MinReadySeconds: 0
RollingUpdateStrategy: 25% max unavailable, 25% max surge
Pod Template:
Labels: app=nginx
Containers:
nginx:
Image: nginx:1.24
Port: <none>
Host Port: <none>
Environment: <none>
Mounts: <none>
Volumes: <none>
Conditions:
Type Status Reason
---- ------ ------
Available True MinimumReplicasAvailable
Progressing True NewReplicaSetAvailable
OldReplicaSets: nginx-7b8df77865 (0/0 replicas created)
NewReplicaSet: nginx-69d846b5c6 (2/2 replicas created)
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal ScalingReplicaSet 10m deployment-controller Scaled up replica set nginx-69d846b5c6 to 2
Normal ScalingReplicaSet 8m22s deployment-controller Scaled up replica set nginx-7b8df77865 to 1
Normal ScalingReplicaSet 8m15s deployment-controller Scaled down replica set nginx-69d846b5c6 to 1 from 2
Normal ScalingReplicaSet 8m15s deployment-controller Scaled up replica set nginx-7b8df77865 to 2 from 1
Normal ScalingReplicaSet 8m8s deployment-controller Scaled down replica set nginx-69d846b5c6 to 0 from 1
Normal ScalingReplicaSet 6m54s deployment-controller Scaled up replica set nginx-69d846b5c6 to 1 from 0
Normal ScalingReplicaSet 6m52s deployment-controller Scaled down replica set nginx-7b8df77865 to 1 from 2
Normal ScalingReplicaSet 6m52s deployment-controller Scaled up replica set nginx-69d846b5c6 to 2 from 1
Normal ScalingReplicaSet 6m51s deployment-controller Scaled down replica set nginx-7b8df77865 to 0 from 1
kubectl get replicasets.apps
NAME DESIRED CURRENT READY AGE
nginx-69d846b5c6 2 2 2 10m
nginx-7b8df77865 0 0 0 9m6s
# Mesmo que ele volte para usar o primeiro replicaset, ele cria uma nova revisão
❯ kubectl rollout history deployment nginx
deployment.apps/nginx
REVISION CHANGE-CAUSE
2 <none>
3 <none>
# Poderíamos voltar para uma revisão específica
kubectl rollout undo deployment nginx --to-revision 2
deployment.apps/nginx rolled bac
# Voltou para a revisão 2 mas criou a 4, pois ele sempre cria uma revisão, pois o que importa para ele é o replicaset que será utilizado.
kubectl rollout history deployment nginx
deployment.apps/nginx
REVISION CHANGE-CAUSE
3 <none>
4 <none>
# Ele descarta antigos
kubectl rollout undo deployment nginx --to-revision 1
error: unable to find specified revision 1 in history
Para manter mais revisões poderíamos definir a tag revisionHistoryLimit.
Para que as causas das mudanças apareçam corretamente basta usar annotations
apiVersion: apps/v1
kind: Deployment
metadata:
creationTimestamp: null
labels:
app: nginx
name: nginx
annotations:
kubernetes.io/change-cause: "Atualização de imagem para versão 1.25"
spec:
replicas: 2
selector:
matchLabels:
app: nginx
template:
metadata:
creationTimestamp: null
labels:
app: nginx
spec:
containers:
- image: nginx:1.25
name: nginx
resources: {}
# Poderíamos mudar também alguns parâmetros e definir as estratégias
strategy:
rollingUpdate:
maxSurge: 1
maxUnavailable: 1
type: RollingUpdate
revisionHistoryLimit: 10 # Assim