> ## Documentation Index
> Fetch the complete documentation index at: https://docs.gcore.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Upgrade a Kubernetes cluster

export const MethodSection = ({children}) => children ?? null;

export const MethodSwitch = ({children}) => {
  const tabs = React.Children.toArray(children).map(c => {
    if (!c || !c.props) return null;
    if (c.props.id) return c;
    const inner = c.props.children;
    if (inner && inner.props && inner.props.id) return inner;
    return null;
  }).filter(Boolean);
  const firstId = tabs.length > 0 ? tabs[0].props.id : "";
  const [active, setActive] = React.useState(firstId);
  React.useEffect(() => {
    try {
      const saved = localStorage.getItem("gcore_docs_method");
      if (saved && tabs.find(t => t.props.id === saved)) {
        setActive(saved);
      }
    } catch (_) {}
  }, []);
  React.useEffect(() => {
    try {
      document.querySelectorAll("h2[id], h3[id]").forEach(heading => {
        const visible = heading.offsetParent !== null;
        document.querySelectorAll(`a[href="#${heading.id}"]`).forEach(link => {
          if (link.closest("h1,h2,h3,h4,h5,h6")) return;
          const li = link.closest("li");
          if (li) li.style.display = visible ? "" : "none";
        });
      });
    } catch (_) {}
    window.dispatchEvent(new Event("scroll"));
  }, [active]);
  const handleClick = id => {
    setActive(id);
    try {
      localStorage.setItem("gcore_docs_method", id);
    } catch (_) {}
  };
  return <div>
      <div className="not-prose flex gap-0 border-b border-zinc-200 dark:border-zinc-800 mb-8 mt-2" role="tablist">
        {tabs.map(tab => {
    const isActive = active === tab.props.id;
    return <button key={tab.props.id} role="tab" aria-selected={isActive} onClick={() => handleClick(tab.props.id)} className={["px-4 py-2 text-sm font-medium border-b-2 -mb-px transition-colors cursor-pointer", isActive ? "border-primary text-primary" : "border-transparent text-zinc-500 hover:text-zinc-800 dark:hover:text-zinc-200"].join(" ")}>
              {tab.props.label}
            </button>;
  })}
      </div>

      {tabs.map(tab => <div key={tab.props.id} style={{
    display: active === tab.props.id ? "" : "none"
  }}>
          {tab.props.children}
        </div>)}
    </div>;
};

<MethodSwitch>
  <MethodSection id="portal" label="Customer Portal">
    <p>In the [Gcore Customer Portal](https://portal.gcore.com), upgrade a Managed Kubernetes cluster to a newer Kubernetes version. The rolling update replaces worker nodes one at a time.</p>

    ## Before upgrading

    <p>Gcore uses a rolling update — worker nodes are replaced one at a time, so the cluster stays available but performance may be impacted when spare capacity is limited. The upgrade may also change available Kubernetes APIs, so confirm that deprecated APIs are removed in the target version before proceeding.</p>

    * Test the upgrade in a non-production environment first.
    * Use [Managed Logging](/cloud/logging-as-a-service/configure-logging-and-view-your-logs) to monitor activity during the upgrade.

    <Info>
      A running [Kubernetes cluster](/cloud/kubernetes/clusters/create-a-kubernetes-cluster) is required.
    </Info>

    ## Step 1. Select a cluster

    1. Navigate to **Cloud** > **Managed Kubernetes**.
    2. Select a cluster from the list.

    <Frame>
      <img src="https://mintcdn.com/gcore/-tGG7PWTFMtYIhJ9/images/docs/cloud/kubernetes/clusters/upgrade/upgrade-kubernetes-clusters-list.png?fit=max&auto=format&n=-tGG7PWTFMtYIhJ9&q=85&s=327db6588a0a34c55f8600a6bca8e193" alt="Kubernetes Clusters page with the Create Cluster button" width="1665" height="384" data-path="images/docs/cloud/kubernetes/clusters/upgrade/upgrade-kubernetes-clusters-list.png" />
    </Frame>

    <p>If a newer Kubernetes version is available, a **Change** link appears next to the version under **General Info**.</p>

    3. Click **Change** to open the version selector.

    <Frame>
      <img src="https://mintcdn.com/gcore/-tGG7PWTFMtYIhJ9/images/docs/cloud/kubernetes/clusters/upgrade/upgrade-3.png?fit=max&auto=format&n=-tGG7PWTFMtYIhJ9&q=85&s=851e1f32de46504e406a2acf62a28237" alt="Cluster General Info section with Kubernetes version and Change link" width="1389" height="436" data-path="images/docs/cloud/kubernetes/clusters/upgrade/upgrade-3.png" />
    </Frame>

    <p>The **Change Kubernetes cluster version** dialog opens.</p>

    ## Step 2. Initialize the cluster upgrade

    1. Select a new version from the **Kubernetes Version** dropdown.
    2. Click **Change**.

    <Warning>
      Downgrade is only supported for one patch version down (for example, from 1.24.9 to 1.24.8). Changing the cluster version takes several minutes, during which API access to the cluster may be unstable.
    </Warning>

    <Frame>
      <img src="https://mintcdn.com/gcore/-tGG7PWTFMtYIhJ9/images/docs/cloud/kubernetes/clusters/upgrade/upgrade-4.png?fit=max&auto=format&n=-tGG7PWTFMtYIhJ9&q=85&s=6c87888114232255dc3e6d2fe8646e01" alt="Change Kubernetes cluster version dialog with version dropdown and Change button" width="904" height="624" data-path="images/docs/cloud/kubernetes/clusters/upgrade/upgrade-4.png" />
    </Frame>

    <p>A confirmation dialog asks to confirm the version upgrade. Click **Yes, upgrade** to start the upgrade.</p>

    <Frame>
      <img src="https://mintcdn.com/gcore/-tGG7PWTFMtYIhJ9/images/docs/cloud/kubernetes/clusters/upgrade/upgrade-5.png?fit=max&auto=format&n=-tGG7PWTFMtYIhJ9&q=85&s=bad5f51b2de4aa34faaf1e8be2c96ea2" alt="Upgrade cluster version confirmation dialog with Yes, upgrade button" width="613" height="527" data-path="images/docs/cloud/kubernetes/clusters/upgrade/upgrade-5.png" />
    </Frame>

    <p>When the upgrade starts, both dialogs close and a loading indicator appears while the upgrade is in progress.</p>

    ## Step 3. Finalize

    <p>After the upgrade completes, confirm that the version under **General Info** matches the selected version.</p>

    <Frame>
      <img src="https://mintcdn.com/gcore/-tGG7PWTFMtYIhJ9/images/docs/cloud/kubernetes/clusters/upgrade/upgrade-6.png?fit=max&auto=format&n=-tGG7PWTFMtYIhJ9&q=85&s=d613730939537246d143f88ebf7f764d" alt="Cluster General Info showing updated Kubernetes version after upgrade" width="1382" height="446" data-path="images/docs/cloud/kubernetes/clusters/upgrade/upgrade-6.png" />
    </Frame>
  </MethodSection>

  <MethodSection id="api" label="REST API">
    <p>Upgrading replaces worker nodes one by one via a rolling update. Before triggering the upgrade, fetch the list of available target versions — Gcore only allows upgrading one minor version at a time, and the list reflects what is currently permitted for the cluster.</p>

    <Info>
      An [API token](/account-settings/api-tokens) is required, along with a [project ID](/api-reference/cloud/projects/list-projects) and [region ID](/api-reference/cloud/regions/list-regions).
    </Info>

    <p>Open a terminal and set these environment variables before running the examples:</p>

    ```bash theme={null}
    export GCORE_API_KEY="{YOUR_API_KEY}"
    export GCORE_CLOUD_PROJECT_ID="{YOUR_PROJECT_ID}"
    export GCORE_CLOUD_REGION_ID="{YOUR_REGION_ID}"
    export CLUSTER_NAME="{YOUR_CLUSTER_NAME}"
    ```

    <Info>
      `CLUSTER_NAME` is the cluster name set at creation — find it in the [Kubernetes clusters](/cloud/kubernetes/clusters/create-a-kubernetes-cluster) list.
    </Info>

    ## Quickstart

    <p>The scripts below list available upgrade versions and upgrade the cluster to the permitted next version, then verify the result.</p>

    <Tabs>
      <Tab title="Python SDK">
        ```python theme={null}
        import os
        from gcore import Gcore

        client = Gcore()

        cluster_name = os.environ["CLUSTER_NAME"]

        # Step 1. List versions available for upgrade.
        versions = client.cloud.k8s.clusters.list_versions_for_upgrade(cluster_name)
        if versions.count == 0:
            print("No upgrade versions available")
            exit(0)
        target_version = versions.results[0].version  # typically one version is returned
        print(f"Upgrading to: {target_version}")

        # Step 2. Trigger the upgrade and poll until done.
        task = client.cloud.k8s.clusters.upgrade(cluster_name, version=target_version)
        client.cloud.tasks.poll(task.tasks[0])

        # Step 3. Verify the new version.
        cluster = client.cloud.k8s.clusters.get(cluster_name)
        print(f"Version: {cluster.version}  Status: {cluster.status}")
        ```
      </Tab>

      <Tab title="Go SDK">
        ```go theme={null}
        package main

        import (
            "context"
            "fmt"
            "log"
            "os"

            "github.com/G-Core/gcore-go"
            "github.com/G-Core/gcore-go/cloud"
        )

        func main() {
            client := gcore.NewClient()
            ctx := context.Background()
            clusterName := os.Getenv("CLUSTER_NAME")

            // Step 1. List versions available for upgrade.
            versions, err := client.Cloud.K8S.Clusters.ListVersionsForUpgrade(
                ctx,
                clusterName,
                cloud.K8SClusterListVersionsForUpgradeParams{},
            )
            if err != nil {
                log.Fatal(err)
            }
            if versions.Count == 0 {
                fmt.Println("No upgrade versions available")
                return
            }
            targetVersion := versions.Results[0].Version // typically one version is returned
            fmt.Printf("Upgrading to: %s\n", targetVersion)

            // Step 2. Trigger upgrade and wait for completion.
            upgraded, err := client.Cloud.K8S.Clusters.UpgradeAndPoll(
                ctx,
                clusterName,
                cloud.K8SClusterUpgradeParams{
                    Version: targetVersion,
                },
            )
            if err != nil {
                log.Fatal(err)
            }

            // Step 3. Verify the new version.
            fmt.Printf("Version: %s  Status: %s\n", upgraded.Version, upgraded.Status)
        }
        ```
      </Tab>
    </Tabs>

    ## Step-by-step

    <p>Each step below explains what the call does, which parameters matter, and what the response looks like.</p>

    <Accordion title="Show all steps">
      ### Step 1. List available versions for upgrade

      <p>This call returns the versions currently permitted for the cluster. Check this before submitting the upgrade request.</p>

      <Tabs>
        <Tab title="Python SDK">
          ```python theme={null}
          versions = client.cloud.k8s.clusters.list_versions_for_upgrade(cluster_name)
          print(f"Count: {versions.count}")
          for v in versions.results:
              print(f"  {v.version}")
          ```
        </Tab>

        <Tab title="Go SDK">
          ```go theme={null}
          versions, err := client.Cloud.K8S.Clusters.ListVersionsForUpgrade(
              ctx,
              clusterName,
              cloud.K8SClusterListVersionsForUpgradeParams{},
          )
          if err != nil {
              log.Fatal(err)
          }
          fmt.Printf("Count: %d\n", versions.Count)
          for _, v := range versions.Results {
              fmt.Printf("  %s\n", v.Version)
          }
          ```
        </Tab>

        <Tab title="curl">
          ```bash theme={null}
          curl "https://api.gcore.com/cloud/v2/k8s/clusters/$GCORE_CLOUD_PROJECT_ID/$GCORE_CLOUD_REGION_ID/$CLUSTER_NAME/upgrade_versions" \
            -H "Authorization: APIKey $GCORE_API_KEY"
          ```

          Response:

          ```json theme={null}
          {
            "count": 1,
            "results": [
              {"version": "v1.33.10"}
            ]
          }
          ```
        </Tab>
      </Tabs>

      <p>Select a `version` value from the returned list and pass it to the upgrade call. The [upgrade versions](/api-reference/cloud#tag/Managed-Kubernetes/operation/K8sClusterUpdateVersionViewSet.get) endpoint accepts only path parameters — no request body is required.</p>

      ### Step 2. Upgrade the cluster

      <p>Submit the target version to the [upgrade](/api-reference/cloud#tag/Managed-Kubernetes/operation/K8sClusterUpgradeActionViewSetV2.post) endpoint to start the rolling update. The API returns a task ID immediately; the actual node replacement takes several minutes.</p>

      | Parameter | Required | Description                           |
      | --------- | -------- | ------------------------------------- |
      | `version` | Yes      | Target Kubernetes version from Step 1 |

      <Tabs>
        <Tab title="Python SDK">
          ```python theme={null}
          task = client.cloud.k8s.clusters.upgrade(cluster_name, version=target_version)
          print(f"Task: {task.tasks[0]}")

          result = client.cloud.tasks.poll(task.tasks[0])
          print(f"State: {result.state}")

          cluster = client.cloud.k8s.clusters.get(cluster_name)
          print(f"Version: {cluster.version}  Status: {cluster.status}")
          ```
        </Tab>

        <Tab title="Go SDK">
          ```go theme={null}
          upgraded, err := client.Cloud.K8S.Clusters.UpgradeAndPoll(
              ctx,
              clusterName,
              cloud.K8SClusterUpgradeParams{
                  Version: targetVersion,
              },
          )
          if err != nil {
              log.Fatal(err)
          }
          fmt.Printf("Version: %s  Status: %s\n", upgraded.Version, upgraded.Status)
          ```
        </Tab>

        <Tab title="curl">
          ```bash theme={null}
          curl -X POST \
            "https://api.gcore.com/cloud/v2/k8s/clusters/$GCORE_CLOUD_PROJECT_ID/$GCORE_CLOUD_REGION_ID/$CLUSTER_NAME/upgrade" \
            -H "Authorization: APIKey $GCORE_API_KEY" \
            -H "Content-Type: application/json" \
            -d '{"version": "v1.33.10"}'
          ```

          The API returns a task ID:

          ```json theme={null}
          {
            "tasks": ["a73025eb-071a-400d-beb3-f6818428a99f"]
          }
          ```

          Poll `GET /cloud/v1/tasks/{task_id}` every 5 seconds until `state` is `FINISHED`. The upgrade has no `created_resources` in the task response.

          ```bash theme={null}
          curl "https://api.gcore.com/cloud/v1/tasks/a73025eb-071a-400d-beb3-f6818428a99f" \
            -H "Authorization: APIKey $GCORE_API_KEY"
          ```

          While running:

          ```json theme={null}
          {
            "state": "RUNNING",
            "task_type": "upgrade_k8s_cluster"
          }
          ```

          When complete:

          ```json theme={null}
          {
            "state": "FINISHED",
            "task_type": "upgrade_k8s_cluster"
          }
          ```
        </Tab>
      </Tabs>

      <p>After the task finishes, the cluster returns to `"Provisioned"` status with the new version.</p>
    </Accordion>
  </MethodSection>

  <MethodSection id="terraform" label="Terraform">
    <p>Upgrade a managed Kubernetes cluster to the next minor version. Edit `version` in [`gcore_cloud_k8s_cluster`](https://registry.terraform.io/providers/G-Core/gcore/latest/docs/resources/cloud_k8s_cluster) and run `terraform apply` to trigger a rolling node replacement.</p>

    <Warning>
      The rolling update creates replacement nodes before removing existing ones — confirm the project quota can accommodate a second full node pool during the transition.
    </Warning>

    ## Upgrade a cluster

    <p>Edit the `version` field in the cluster resource block and run `terraform apply`. Terraform detects the change and triggers the rolling upgrade automatically.</p>

    ```hcl theme={null}
    resource "gcore_cloud_k8s_cluster" "example" {
      project_id    = var.project_id
      region_id     = var.region_id
      name          = "my-k8s-cluster"
      fixed_network = var.network_id
      fixed_subnet  = var.subnet_id
      keypair       = "my-keypair"
      version       = "v1.33.10"  # update to the target version

      pools = [{
        name               = "default-pool"
        flavor_id          = "g2-standard-2-4"  # example; available flavors are region-specific
        servergroup_policy = "anti-affinity"
        min_node_count     = 1
        max_node_count     = 2
        boot_volume_size   = 50
        boot_volume_type   = "ssd_hiiops"
        auto_healing_enabled = true
      }]
    }
    ```

    ```bash theme={null}
    terraform apply
    ```
  </MethodSection>
</MethodSwitch>
