kubernetes: changing update strategy and "applying" is not allowed

I have a replicaset running without a deployment strategy pre-defined.

When defining one in the template, and setting its type to Recreate, when deploying with kubectl apply, I get:

spec.strategy.rollingUpdate: Forbidden: may not be specified when strategy `type` is 'Recreate'

I would expect the strategy to be allowed to change using apply, and have it apply to the current rollout as well.

About this issue

  • Original URL
  • State: closed
  • Created 8 years ago
  • Comments: 22 (13 by maintainers)

Commits related to this issue

Most upvoted comments

I can confirm this worked for me under Kubernetes 1.6.1 using explicit null.

I did a test like this:

[tony@localhost kubernetes]$ cluster/kubectl.sh create -f deployment.yaml
deployment "nginx-deployment" created
[tony@localhost kubernetes]$ cluster/kubectl.sh get deployment nginx-deployment -o yaml
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  annotations:
    deployment.kubernetes.io/revision: "1"
  creationTimestamp: 2016-04-21T04:01:28Z
  generation: 2
  labels:
    name: nginx-deployment
  name: nginx-deployment
  namespace: default
  resourceVersion: "59"
  selfLink: /apis/extensions/v1beta1/namespaces/default/deployments/nginx-deployment
  uid: b93e65ba-0775-11e6-b7bf-b05adacd35f7
spec:
  replicas: 3
  selector:
    matchLabels:
      name: nginx
  strategy:
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 1
    type: RollingUpdate
  template:
    metadata:
      creationTimestamp: null
      labels:
        name: nginx
    spec:
      containers:
      - image: nginx
        imagePullPolicy: IfNotPresent
        name: nginx
        ports:
        - containerPort: 80
          protocol: TCP
        resources: {}
        terminationMessagePath: /dev/termination-log
      dnsPolicy: ClusterFirst
      restartPolicy: Always
      securityContext: {}
      terminationGracePeriodSeconds: 30
status:
  availableReplicas: 3
  observedGeneration: 2
  replicas: 3
  updatedReplicas: 3
[tony@localhost kubernetes]$ cat deployment.yaml
apiVersion: extensions/v1beta1 
kind: Deployment
metadata:
  name: nginx-deployment
  labels:
    name: nginx-deployment
spec:
  replicas: 3
  selector:
    matchLabels:
      name: nginx
  template:
    metadata:
      labels:
        name: nginx
    spec:
      containers:
      - name: nginx
        image: nginx
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 80

Then apply:

[tony@localhost kubernetes]$ cluster/kubectl.sh apply -f deployment_2.yaml
The Deployment "nginx-deployment" is invalid.
spec.strategy.rollingUpdate: Forbidden: may not be specified when strategy `type` is 'Recreate'
[tony@localhost kubernetes]$ cat deployment_2.yaml
apiVersion: extensions/v1beta1 
kind: Deployment
metadata:
  name: nginx-deployment
  labels:
    name: nginx-deployment
spec:
  replicas: 3
  strategy:
    type: Recreate
    rollingUpdate: null
  selector:
    matchLabels:
      name: nginx
  template:
    metadata:
      labels:
        name: nginx
    spec:
      containers:
      - name: nginx
        image: nginx
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 80

It’s not a bug in apply as much as a shortcoming. apply merges changes by the user with the live state. There’s no way for apply to know that those 2 fields are related. The rollingUpdate field would need to be explicitly nulled.

I’m trying to support the following configuration syntax to generate a patch that includes null values given by the user.

# Configuration file includes:
  strategy:
    type: Recreate
    rollingUpdate: null

# Kubectl patch submitted to Apiserver should include:
    "strategy": {
      "type": "Recreate",
      "rollingUpdate": null
    }

To achieve this we need:

  • Alter 3 ThreeWayMergePatch to propagate fields with null values to the end patch (3d7ccf4cb8fcab54a84ee77fc0a2e9ac4a7e42ea)
  • Find a way to read and preserve user defined null values from the configuration file (WIP: 08da2281c64685bc9c37361f3de33efd4b8d635f)

The problem rises by the fact that we:

  1. Unmarshal the configuration file from the user,
  2. represent it as structs in Go
  3. Marshal it to make the diff and create the patch (CreateThreeWayMergePatch accepts []byte)

Between steps 1 and 2, null values are not preserved. In other words there is no way to distinct a field that is declared with null and a non existing field. Step 3 also has the problem that there is no way to print a null value.

To overcome those issues, I tried to get the configuration file as []byte (read it from source) and merge it with info.VersionedObject.

I’ll create a PR soon to discuss the issue more explicitly but any early feedback is more than welcomed.

(I’ll pick up this issue)

you could not setup spec.strategy.rollingUpdate while you are using Recreate strategy.

type DeploymentStrategy struct {
    // Type of deployment. Can be "Recreate" or "RollingUpdate". Default is RollingUpdate.
    Type DeploymentStrategyType `json:"type,omitempty"`

    // Rolling update config params. Present only if DeploymentStrategyType =
    // RollingUpdate.
    //---
    // TODO: Update this to follow our convention for oneOf, whatever we decide it
    // to be.
    RollingUpdate *RollingUpdateDeployment `json:"rollingUpdate,omitempty"`
}

so if you decide to use Recreate, just try omitting the rollingUpdate part.