Tips & Tricks Tips & Tricks How to rollout or rollback a deployment on a Kubernetes cluster?

Short answer

Rollout a new version

Using a kubectl patch one-liner, using the current rollout strategy:

kubectl patch deployment $DEPLOYMENT \
        -p'{"spec":{"template":{"spec":{"containers":[{"name":"site","image":"$HOST/$USER/$IMAGE:$VERSION"}]}}}}'

Note

You should have tested it before, but if you have the right configuration (see details below) in your rollout strategy and your health checks are correctly setup, you won't have any downtime and the old containers won't be terminated before the new ones kicked in (as in, «answers successfully to health checks»).

Check the rollout status

kubectl rollout status deployment/$DEPLOYMENT

Read the deployment history

kubectl rollout history deployment/$DEPLOYMENT
kubectl rollout history deployment/$DEPLOYMENT --revision 42

Rollback to the previous deployed version

kubectl rollout undo deployment/$DEPLOYMENT

Rollback to a specific previously deployed version

kubectl rollout undo deployment/$DEPLOYMENT --to-revision 21

Details

Kubernetes will upgrade your deployment by creating a new ReplicaSet. New pods will be created according to your update strategy, here is an example configuration that will create new version pods one by one, and wait for a new pod to be available before destroying one of the old pods.

spec:
  # ...
  replicas: 10
  strategy:
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 0
    type: RollingUpdate
  # ...

Now what does "available" means? It means that your readinessProbe found your new pod healthy, here is an example configuration to use an http probe on an hypothetic backend service that is meant to listen to the pod's 8080 port:

spec:
  # ...
  containers:
  - # ...
    readinessProbe:
      failureThreshold: 3
      httpGet:
        path: /ping
        port: 8080
        scheme: HTTP
      initialDelaySeconds: 5
      periodSeconds: 2
      successThreshold: 1
      timeoutSeconds: 1

As soon as the new version pod's will answer a 200 to a GET /ping on the 8080 port, kubernetes will consider it healthy and destroy its ancestor, then proceed with the next pods if the rolling update is not finished.

Bonus

You can combine those techniques with a few git and GNU Make features to make rollouts easy as hell (adapt this to your environment):

NAME ?= awebsome
STAGE ?= staging
K8S_DEPLOYMENT ?= $(NAME)-$(STAGE)
VERSION ?= $(shell git describe)

.PHONY: rollout rollback

rollout:
    kubectl patch deployment $(K8S_DEPLOYMENT) \
            -p'{"spec":{"template":{"spec":{"containers":[{"name":"$(NAME)","image":"$(DOCKER_REGISTRY)/$(DOCKER_REGISTRY_USER)/$(NAME):$(VERSION)"}]}}}}'

rollback:
    kubectl rollout undo deployment/$(K8S_DEPLOYMENT)

Now, you can rollout to current git version...

make rollout

Then maybe rollback...

make rollback

Share the love!

Liked this article? Please consider sharing it on your favorite network, it really helps me a lot!

You can also add your valuable insights by commenting below.