- 
                Notifications
    
You must be signed in to change notification settings  - Fork 775
 
Upgrade masters last when upgrading ES clusters #8871
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
Signed-off-by: Michael Montgomery <[email protected]>
          ✅ Snyk checks have passed. No issues have been found so far.
 💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse.  | 
    
Signed-off-by: Michael Montgomery <[email protected]>
Signed-off-by: Michael Montgomery <[email protected]>
| 
           buildkite test this -f p=kind,t=TestNonMasterFirstUpgradeComplexTopology -m s=9.1.2  | 
    
Signed-off-by: Michael Montgomery <[email protected]>
updated. Signed-off-by: Michael Montgomery <[email protected]>
Signed-off-by: Michael Montgomery <[email protected]>
…/cloud-on-k8s into fix-sts-upgrade-issue-recreation
Signed-off-by: Michael Montgomery <[email protected]>
| 
           buildkite test this -f p=kind,t=TestHandleUpscaleAndSpecChanges_VersionUpgradeDataFirstFlow -m s=9.1.2  | 
    
Signed-off-by: Michael Montgomery <[email protected]>
Signed-off-by: Michael Montgomery <[email protected]>
Signed-off-by: Michael Montgomery <[email protected]>
Signed-off-by: Michael Montgomery <[email protected]>
Signed-off-by: Michael Montgomery <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR implements a non-master-first upgrade strategy for Elasticsearch clusters. The key change ensures that during version upgrades, non-master nodes (data, ingest, coordinating nodes) are upgraded before master nodes, which helps maintain cluster stability during upgrades.
- Adds logic to separate master and non-master StatefulSets during version upgrades
 - Implements upgrade order validation to ensure non-master nodes complete their upgrades first
 - Adds comprehensive unit and e2e tests to verify the upgrade flow
 
Reviewed Changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.
| File | Description | 
|---|---|
| pkg/controller/elasticsearch/driver/upgrade.go | Adds check to identify new clusters vs upgrades by checking if status version is empty | 
| pkg/controller/elasticsearch/driver/upscale.go | Implements non-master-first upgrade logic with resource separation and upgrade status checking | 
| pkg/controller/elasticsearch/driver/upscale_test.go | Adds comprehensive unit test for version upgrade flow and minor formatting fixes | 
| test/e2e/es/non_master_first_upgrade_test.go | Adds e2e test that validates non-master-first upgrade behavior with a watcher | 
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| return | ||
| } | ||
| 
               | 
          ||
| // Check if any master StatefulSet has it's version higher than any non-master StatefulSet | 
    
      
    
      Copilot
AI
    
    
    
      Oct 29, 2025 
    
  
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Corrected spelling of 'it's' to 'its' (possessive form, not contraction).
| // Check if any master StatefulSet has it's version higher than any non-master StatefulSet | |
| // Check if any master StatefulSet has its version higher than any non-master StatefulSet | 
Signed-off-by: Michael Montgomery <[email protected]>
Signed-off-by: Michael Montgomery <[email protected]>
| // If the StatefulSet is not at the target version, it is not upgraded | ||
| // so don't even bother looking at the state/status of the StatefulSet. | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it is possible to enter a kind of "deadlock" when the master role is added to an existing nodeSet.
In that case:
- The updated sts is detected here as a "not (yet) master sst"
 - But it is never going to be upgraded because it is considered as a 
masterResourcesinadjusted 
Simple manifest to replicate the deadlock:
apiVersion: elasticsearch.k8s.elastic.co/v1
kind: Elasticsearch
metadata:
  name: elasticsearch-sample
spec:
  version: 9.1.6
  nodeSets:
  - name: ns1
    config:
      node.roles: ["master","data"]
      node.store.allow_mmap: false
    count: 1
  - name: ns2
    config:
      node.roles: ["data", "ingest", "ml"]
      node.store.allow_mmap: false
    count: 3Then upgrade to 9.2.0 with:
apiVersion: elasticsearch.k8s.elastic.co/v1
kind: Elasticsearch
metadata:
  name: elasticsearch-sample
spec:
  version: 9.2.0
  nodeSets:
  - name: ns1
    config:
      node.roles: ["master","data"]
      node.store.allow_mmap: false
    count: 1
  - name: ns2
    config:
      node.roles: ["master", "data", "ingest", "ml"]
      node.store.allow_mmap: false
    count: 3There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we also have a problem when we increase the master replicas:
Initial manifest
apiVersion: elasticsearch.k8s.elastic.co/v1
kind: Elasticsearch
metadata:
  name: elasticsearch-sample
spec:
  version: 9.1.6
  nodeSets:
  - name: ns1
    config:
      node.roles: ["master"]
      node.store.allow_mmap: false
    count: 1
  - name: ns2
    config:
      node.roles: ["data", "ingest", "ml"]
      node.store.allow_mmap: false
    count: 3Updated manifest
apiVersion: elasticsearch.k8s.elastic.co/v1
kind: Elasticsearch
metadata:
  name: elasticsearch-sample
spec:
  version: 9.2.0
  nodeSets:
  - name: ns1
    config:
      node.roles: ["master"]
      node.store.allow_mmap: false
    count: 3
  - name: ns2
    config:
      node.roles: ["data", "ingest", "ml"]
      node.store.allow_mmap: false
    count: 3Operator is stuck in:
    inProgressOperations:
      downscale:
        lastUpdatedTime: "2025-11-03T10:04:05Z"
      upgrade:
        lastUpdatedTime: "2025-11-03T10:04:05Z"
      upscale:
        lastUpdatedTime: "2025-11-03T10:13:51Z"
        nodes:
        - message: Creating master node
          name: elasticsearch-sample-es-ns1-1
          status: EXPECTED
        - message: Limiting master nodes creation to one at a time
          name: elasticsearch-sample-es-ns1-2
          status: PENDING
    observedGeneration: 3
    phase: ApplyingChanges
    version: 9.1.6
| // Check if this StatefulSet has pending updates | ||
| if statefulSet.Status.UpdatedReplicas != statefulSet.Status.Replicas { | ||
| return false, nil | ||
| } | ||
| 
               | 
          ||
| // Check if there are any pods that need to be upgraded | ||
| pods, err := es_sset.GetActualPodsForStatefulSet(client, k8s.ExtractNamespacedName(&statefulSet)) | ||
| if err != nil { | ||
| return false, err | ||
| } | ||
| 
               | 
          ||
| for _, pod := range pods { | ||
| // Check if pod revision matches StatefulSet update revision | ||
| if statefulSet.Status.UpdateRevision != "" && sset.PodRevision(pod) != statefulSet.Status.UpdateRevision { | ||
| // This pod still needs to be upgraded | ||
| return false, nil | ||
| } | ||
| } | ||
| } | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this whole logic assumes that the StatefulSet controller has updated the status, which is not necessarily true from my experiments. I hit several cases where the StatefulSet spec has been updated but not its status. A non master sts is then detected as reconciled while it is not the case.
| } | ||
| 
               | 
          ||
| // Check if all non-master StatefulSets have completed their upgrades before proceeding with master StatefulSets | ||
| if len(masterResources) > 0 { | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was wondering in which cases we are expecting this to be false?
| if len(masterResources) > 0 { | 
Fixes #8429
What is changing?
This ensure that the master StatefulSets are always upgraded last when doing a version upgrade of Elasticsearch.
Validation