tl;dr: Kubernetes 1.16 is removing support for some deprecated APIs that are still in wide use. The solution is theoretically easy: just use for example version: apps/v1 instead of version: extensions/v1beta1. However, there is one side effect: default values might change.
Something that Kubernetes does very well is dealing with constant change and improvement of APIs, while also avoiding to break backwards compatibility. The way this works is that each API has a specific version declared, and if you keep using that version, the API should continue doing the same thing as before when upgrade Kubernetes.
The same concept for backwards compatibility is used when Kubernetes developers want to change the default values of some parameters in the API. New defaults can be introduced when new versions of an API are published. If you use an old version of an API, you get the old default values, if you use the new version, you get the new defaults. It’s a beautiful concept, but also possibly surprising for users when they just change the version if their resource definitions.
Now that some API versions will be removed, you should be aware of what is changing when using new versions of those APIs.
What is removed in 1.16
Kubernetes is removing support for some beta APIs that have been since long replaced by GA APIs (in Kubernetes 1.9). Most of these are part of the Core Workloads API, which are the APIs that are often used to define applications in Kubernetes. Here is a list, taken from the release notes of Kubernetes 1.16, of Core Workload APIs that will be only supported with the version apps/v1:
Other APIs that are removed (for reference, we will focus on the above for for the rest of this article):
- NetworkPolicy (extensions/v1beta1, use networking.k8s.io/v1 instead)
- PodSecurityPolicy (extensions/v1beta1, use policy/v1beta1 instead)
How to fix your workloads
The fix is easy enough: just change your resource definitions to use the new API versions. So if you have for example:
Just change the first line:
Is that all? Almost… As explained above, you should consider that changing the API version of your resource definition has an effect on the default values that are used for parameters that you don’t define. The section below contains a list of changed defaults in the Core Workloads API.
DaemonSets are used to deploy pods that need to be present on each node. These default values where changed beginning with v1:
- spec.updateStrategy.type: OnDelete -> RollingUpdate
With “RollingUpdate”, pods will be automatically recreated when the DaemonSet definition changes. That’s a big change from OnDelete, where you had to manually delete pods for the new version to be rolled out.
Deployments are probably the most used way to define workloads. These default values where changed beginning with v1beta2:
- spec.progressDeadlineSeconds: 2147483647 → 600
progressDeadlineSeconds determines how long the Deployment will remain “in progress” before being declared as failed (for example because of failing readiness checks).
- spec.revisionHistoryLimit: 2147483647 → 10
revisionHistoryLimit limits the number of ReplicaSet objects that will be left before being deleted by the Deployment controller.
- spec.strategy.rollingUpdate.maxSurge: 1 → 25%
maxSurge defines the maximum number of pods that a rolling update can create over the desired number of pods as specified in spec.replicas.
- spec.strategy.rollingUpdate.maxUnavailable: 1 → 25%
The rolling update only continues when the number of unavailable (non-ready) pods are below this number. If its a percentage, its a percentage of spec.replicas.
ReplicaSets are rarely used directly and are mostly seen as child objects owned by Deployments. The ReplicaSet defaults didn’t change between extensions/v1beta1 and apps/v1.
StatefulSets are similar to Deployment, but are more appropriate for stateful applications that require storage, addressable instances, control on creation order, etc. The same parameter as for DaemonSet changed beginning with v1beta2:
- spec.updateStrategy.type: OnDelete → RollingUpdate
With “RollingUpdate”, pods will be automatically recreated when the StatefulSet definition changes. That’s a big change from OnDelete, where you had to manually delete pods for the new version to be rolled out.
Removal of default selector and selector immutability
You might notice something else when moving to the non-beta Core Workloads APIs. If you have Deployments or StatefuSet where the pod selector (spec.selector) is not defined, you will now get an error that that field is missing. In the beta APIs, you could omit spec.selector, and it would be inferred from labels in the pod template.
Another thing that is not allowed anymore is changing the selector in an existing resources. The spec.selector field is now considered immutable.
You can find more details about the reason for these changes in the Core Workloads API GA announcement.
A note on the version that you get with kubectl get
In order to prepare for the removal of these resources in Kubernetes 1.16, you should change the versions in your resource definitions before you upgrade. When you start using the new versions (e.g. apps/v1), you might notice something strange: the version is apparently not registered:
$ cat test-deployment.yaml
...$ kubectl apply -f test-deployment.yaml
$ kubectl get deployment test -o yaml
What’s happening? The reason, as explained here, is that “kubectl get deployment” is ambiguous on what API version for Deployment you want to use. The same resource can be retrieved using the different versions of the API that are available, and Kubernetes < 1.16 is still serving all these old API versions for Deployment. For backwards compatibility, when the version is ambiguous, the oldest version of the API is served.
You can retrieve a specific API version with the following syntax:
$ kubectl get deployment.v1.apps test -o yaml
Thanks for reading!
Thanks to Balazs Pinter and Janet Kuo for their help in writing this article.