How does 'kubectl apply -f' update a deployment behind the scenes? - kubernetes

I have a deployment created with a YAML file, the image for the containers is image:v1.
Now I update the file to image:v2, and do kubectl apply -f newDeploymentFile.yml. Does Kubernetes use rolling update behind the scenes to update my deployment or some other way?

What happens exactly is controlled by the Deployment itself:
.spec.stategy: RollingUpdate (default) or Recreate
.spec.strategy.rollingUpdate: see the docs I've linked for the explanation of the maxSurge and maxUnavailable
(I assumed that by deployment you actually mean a Deployment type object and not speaking in general.)

Related

Is kubectl apply safe enough to update all pods no matter how they were created?

A pod can be created by Deployment or ReplicaSet or DaemonSet, if I am updating a pod's container specs, is it OK for me to simply modify the yaml file that created the pod? Would it be erroneous once I have done that?
Brief Question:
Is kubectl apply -f xxx.yml the silver bullet for all pod update?
...if I am updating a pod's container specs, is it OK for me to simply modify the yaml file that created the pod?
The fact that the pod spec is part of the controller spec (eg. deployment, daemonset), to update the container spec you naturally start with the controller spec. Also, a running pod is largely immutable, there isn't much you can change directly unless you do a replace - which is what the controller already doing.
you should not make changes to the pods directly, but update the spec.template.spec section of the deployment used to create the pods.
reason for this is that the deployment is the controller that manages the replicasets and therefore the pods that are created for your application. that means if you apply changes to the pods manifest directly, and something like a pod rescheduling/restart happens, the changes made to the pod will be lost because the replicaset will recreate the pod according to its own specification and not the specification of the last running pod.
you are safe to use kubectl apply to apply changes to existing resources but if you are unsure, you can always extract the current state of the deployment from kubernetes and pipe that output into a yaml file to create a backup:
kubectl get deploy/<name> --namespace <namespace> -o yaml > deploy.yaml
another option is to use the internal rollback mechanism of kubernetes to restore a previous revision of your deployment. see https://learnk8s.io/kubernetes-rollbacks for more infos on that.

Difference between kubernetes recreate update strategy vs simply uninstall, install

When deciding on update strategy for a kubernetes application, there is an option to use Recreate strategy.
How would this be different from just uninstalling and installing the app?
I assume that by "just uninstalling and installing the app" you mean complete deletion of your deployment e.g.:
kubectl delete deployment nginx-deployment
and creating it again:
kubectl apply -f nginx-deployment.yaml
Note that when using Recreate strategy there is no complete deletion of the deployment so there is fundamental difference here. By choosing this strategy you only inform kubernetes that all the pods managed by your deployment should be deleted and recreated when you update them (e.g. you update the image version of the container) rather than deleting and recreating their new versions one at a time what takes place when using RollingUpdate strategy. This way you make sure that certain number of pods serving an old version of the application are still available when the update occurs and pods with a new version of the image appear.
When you delete your deployment and create a new one, your new deployment has nothing to do with the old one. In other words, completely new Deployment resource is created and no history of the changes you made is preserved.
I believe the best way of explaining things is always an example. So let's move on to the following one.
Let's say you've created a new nginx deployment based on your yaml manifest:
kubectl apply -f nginx-deployment.yaml
and then you decided to update the image version, either by editing nginx-deployment.yaml manifest and re-applying it or this way:
kubectl set image deployment.v1.apps/nginx-deployment nginx=nginx:1.161 --record=true
In either case you will be able to check rollout history by running:
kubectl rollout history deployment nginx-deployment
and you should see something like this:
$ kubectl rollout history deployment nginx-deployment
deployment.apps/nginx-deployment
REVISION CHANGE-CAUSE
1 kubectl apply --filename=nginx-deployment.yaml --record=true
2 kubectl set image deployment nginx-deployment nginx=nginx:1.16.1 --record=true
When you have rollout history you're able to undo your latest change and go back to the previous revision:
kubectl rollout undo deployment.v1.apps/nginx-deployment
Now your rollout history for this deployment may look like this:
$ kubectl rollout history deployment nginx-deployment
deployment.apps/nginx-deployment
REVISION CHANGE-CAUSE
2 kubectl set image deployment nginx-deployment nginx=nginx:1.16.1 --record=true
3 kubectl apply --filename=nginx-deployment.yaml --record=true
When you simply delete your deployment and recreate it again you will have nothing in rollout history for newly created deployment and you won't be able to roll it back to some older revision in such an easy way.
Recreate strategy will delete your Pods and then add new Pods - you will get short downtime, but on the other side you will not use much extra resources during upgrade.
You typically want RollingUpgrade since that takes a few Pods at a time and you can deploy stateless applications without downtime.

Strategy Replace for StatefulSet

I have simple issue with StatefulSet update on my dev environment and CI.
I want to replace all StatefulSet replicas instantly without using Kubectl delete first.
Is it possible to change the manifest to strategy: Replace as in Deployments and continue using kubectl apply ...
Currently the StatefulSets support only two kinds of update strategies:
RollingUpdate: The RollingUpdate update strategy implements automated, rolling update for the Pods in a StatefulSet. It is the default strategy when .spec.updateStrategy is left unspecified. When a StatefulSet's .spec.updateStrategy.type is set to RollingUpdate, the StatefulSet controller will delete and recreate each Pod in the StatefulSet. It will proceed in the same order as Pod termination (from the largest ordinal to the smallest), updating each Pod one at a time. It will wait until an updated Pod is Running and Ready prior to updating its predecessor.
OnDelete: The OnDelete update strategy implements the legacy (1.6 and prior) behavior. When a StatefulSet's .spec.updateStrategy.type is set to OnDelete, the StatefulSet controller will not automatically update the Pods in a StatefulSet. Users must manually delete Pods to cause the controller to create new Pods that reflect modifications made to a StatefulSet's .spec.template.
However, there is a plan to implement a MaxUnavailable Rolling Update to StatefulSet. It would allow you to update X number of replicas together based on a maxUnavailble strategy. It led to this update proposal but it is not done yet and judging from the latest comments it should be set as a milestone for Kubernetes 1.20.

Kubernetes pod Rollback and Restart

Deployment resource object is still not supported in our cluster and not enabled.
We are using Pod resource object Yaml file. something like below:
apiVersion: v1
kind: Pod
metadata:
name: sample-test
namespace: default
spec:
automountServiceAccountToken: false
containers:
I have explored patch and Put rest api for Pod(Kubectl patch and replace) - it will update to new image version and pod restarts.
I need help in below:
When the image version is same, it will not update and pod will not restart.
How can i acheive Pod restart, is there any API for this or any alternate
approach for this. Because My pod also refers configmap and secret. After i
make changes to secret, i want to restart pod so that it can take updated
value.
Suppose when patch applied with new container image and it fails status is failed, I want to rollback to previous version, How can i acheive this with standalone pod without using deployment. Is there any alternate approach.
Achieving solutions for your scenario, can be handled like this:
When the image version is same, it will not update and pod will not restart. How can i acheive Pod restart, is there any API for this or any alternate approach for this. Because My pod also refers configmap and secret. After i make changes to secret, i want to restart pod so that it can take updated value
Create a new secret/configmap each time and update the pod yaml to use the new configmap/secret rather than the old name.
Suppose when patch applied with new container image and it fails status is failed, I want to rollback to previous version, How can i acheive this with standalone pod without using deployment. Is there any alternate approach
Before you do a Pod update, get the current Pod yaml using kubectl like this,
kubectl get pod <pod-name> -o yaml -n <namespace>
After getting the yaml, generate the new pod yaml and apply it. In case of failure, clean up the new resources created(configmaps & secrets) and apply the older version of pod to achieve rollback

Pod deletion policy when scaling down the deployment?

Is there a way to tell k8s to delete the oldest pods in the deployment first?
For instance I have a deployment which consist of 3 pods. I then decided to scale it up by adding 3 more pods:
kubectl scale deployment some-deployment --replicas=6
After finishing my tests I want it to be 3 pods again, so I scale it down:
kubectl scale deployment some-deployment --replicas=3
Is there a way to configure deployment in a way so that during the scale down process the oldest pods would be removed first? What if I need it the other way around, delete more recent pods first?
This is an open issue. You may find this related item interesting. Currently you are not able to do it. Let's hope it will be fixed soon.