> ## Documentation Index
> Fetch the complete documentation index at: https://gcore-doc-1256a.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Configure a placement group

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

export const MethodSwitch = ({children}) => {
  const tabs = React.Children.toArray(children).filter(c => c && c.props && c.props.id);
  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 (_) {}
  }, [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">
    ## Create a placement group

    <p>In the "Placement Groups" section, create a new group. Give it a name and select a policy — affinity or anti-affinity — and click Create Placement Group.</p>

    <Accordion title="Types of placement groups">
      You can place your Virtual Machine in one of three types of groups:

      * **Affinity** groups assemble Virtual Machines on the same hardware. Machines launched in one affinity group will exchange data faster because they are located on the same server.

      * **Anti-affinity** groups work the opposite way: All Virtual Machines in this group will be separated across different physical hardware. This increases fault tolerance of a cluster: Even if something happens to one server, machines on the other(s) will remain available.

      * **Soft anti-affinity** groups encourage, but don't strictly enforce, the separation of Virtual Machines. Unlike a strict anti-affinity policy, where machines may never be placed together, soft anti-affinity allows placement on the same hardware when it is necessary due to factors like resource constraints or high demand. It is suitable for users who want to use the anti-affinity policy by default while also avoiding machine creation failures if an unused host was not found.
    </Accordion>

    <Frame>
      <img src="https://mintcdn.com/gcore-doc-1256a/OVY0oVOQXvzV_lPN/images/docs/cloud/virtual-instances/placement-groups/configure-a-placement-group/image-6.png?fit=max&auto=format&n=OVY0oVOQXvzV_lPN&q=85&s=758d0e7a63bb93497e86951e19b0e65c" alt="Additional options" width="1807" height="612" data-path="images/docs/cloud/virtual-instances/placement-groups/configure-a-placement-group/image-6.png" />
    </Frame>

    ## Create a Virtual Machine included in a placement group

    <p>When creating a Virtual Machine, in the "Additional options" section, move the "Add to placement group" slider and select a group or create a new one — the machine will be a member of it.</p>

    <Frame>
      <img src="https://mintcdn.com/gcore-doc-1256a/OVY0oVOQXvzV_lPN/images/docs/cloud/virtual-instances/placement-groups/configure-a-placement-group/image-8.png?fit=max&auto=format&n=OVY0oVOQXvzV_lPN&q=85&s=ff32359c850c66be4516044b6701b11b" alt="Placement Group" width="960" height="945" data-path="images/docs/cloud/virtual-instances/placement-groups/configure-a-placement-group/image-8.png" />
    </Frame>

    ## Add a previously created Virtual Machine to a group

    <p>In the Virtual Machine menu, open the "Placement Group" tab. Select the previously created group where you want to add the VM to, or create a new one. Click "Add".</p>

    <Frame>
      <img src="https://mintcdn.com/gcore-doc-1256a/OVY0oVOQXvzV_lPN/images/docs/cloud/virtual-instances/placement-groups/configure-a-placement-group/image-9.png?fit=max&auto=format&n=OVY0oVOQXvzV_lPN&q=85&s=4769f5c8000a33220050f22726f8acc7" alt="Placement Group" width="1541" height="576" data-path="images/docs/cloud/virtual-instances/placement-groups/configure-a-placement-group/image-9.png" />
    </Frame>

    ## Move a Virtual Machine from one group to another

    <p>In the Virtual Machine menu, open the "Placement Group" tab. Remove a machine from one group and add it to another —you can add it to a new one or to a previously created one.</p>

    <Frame>
      <img src="https://mintcdn.com/gcore-doc-1256a/OVY0oVOQXvzV_lPN/images/docs/cloud/virtual-instances/placement-groups/configure-a-placement-group/image-10.png?fit=max&auto=format&n=OVY0oVOQXvzV_lPN&q=85&s=80946c258fba26c9ff531d0ade2e85d0" alt="Placement Group" width="1541" height="577" data-path="images/docs/cloud/virtual-instances/placement-groups/configure-a-placement-group/image-10.png" />
    </Frame>

    <Frame>
      <img src="https://mintcdn.com/gcore-doc-1256a/OVY0oVOQXvzV_lPN/images/docs/cloud/virtual-instances/placement-groups/configure-a-placement-group/image-11.png?fit=max&auto=format&n=OVY0oVOQXvzV_lPN&q=85&s=f6b3973e91c58b7bf1e0e990fa14b742" alt="Placement Group" width="1541" height="578" data-path="images/docs/cloud/virtual-instances/placement-groups/configure-a-placement-group/image-11.png" />
    </Frame>
  </MethodSection>

  <MethodSection id="api" label="REST API">
    Placement groups control how VMs are distributed across physical hosts — grouping them together for low-latency communication or spreading them apart for fault tolerance.

    <Info>
      A permanent [API token](/account-settings/api-tokens) is required, along with a [project ID](https://api.gcore.com/docs/cloud#tag/Projects/operation/ProjectsListV1.get) and [region ID](https://api.gcore.com/docs/cloud#tag/Regions/operation/RegionListV1.get).
    </Info>

    Set environment variables before running any of the examples below:

    ```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 IMAGE_ID="{YOUR_IMAGE_ID}"
    export FLAVOR_ID="{YOUR_FLAVOR_ID}"
    ```

    <Info>
      To find the values for each variable:

      * **IMAGE\_ID**: the UUID of a public or private image. Use `GET /cloud/v1/images/{project_id}/{region_id}` to list available images.
      * **FLAVOR\_ID**: the flavor identifier for the VM size. Use `GET /cloud/v1/flavors/{project_id}/{region_id}` to list flavors available in your region.
    </Info>

    ## Create a placement group

    A [placement group](https://api.gcore.com/docs/cloud#tag/Placement-groups) defines the policy that controls how VMs assigned to it are distributed across physical hosts.

    | Parameter | Required | Description                                                                                                                                                                         |
    | --------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
    | `name`    | Yes      | A label for the group.                                                                                                                                                              |
    | `policy`  | Yes      | `affinity` places VMs on the same host; `anti-affinity` places them on different hosts; `soft-anti-affinity` attempts separation but allows sharing when resources are constrained. |

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

        client = Gcore()

        group = client.cloud.placement_groups.create(
            name="my-group",
            policy="anti-affinity",
        )
        group_id = group.servergroup_id
        print(f"Group ID: {group_id}  policy: {group.policy}")
        ```
      </Tab>

      <Tab title="Go SDK">
        ```go theme={null}
        import (
            "context"
            "fmt"
            "log"

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

        client := gcore.NewClient()
        ctx := context.Background()

        group, err := client.Cloud.PlacementGroups.New(ctx, cloud.PlacementGroupNewParams{
            Name:   "my-group",
            Policy: cloud.PlacementGroupNewParamsPolicyAntiAffinity,
        })
        if err != nil {
            log.Fatal(err)
        }
        groupID := group.ServergroupID
        fmt.Printf("Group ID: %s  policy: %s\n", groupID, group.Policy)
        ```
      </Tab>

      <Tab title="curl">
        ```bash theme={null}
        curl -X POST "https://api.gcore.com/cloud/v1/servergroups/$GCORE_CLOUD_PROJECT_ID/$GCORE_CLOUD_REGION_ID" \
          -H "Authorization: APIKey $GCORE_API_KEY" \
          -H "Content-Type: application/json" \
          -d '{"name": "my-group", "policy": "anti-affinity"}'
        ```

        Response:

        ```json theme={null}
        {
          "servergroup_id": "390bf8f5-c2e6-490a-b8a6-b80341a61d18",
          "policy": "anti-affinity",
          "name": "my-group",
          "instances": []
        }
        ```
      </Tab>
    </Tabs>

    ## Create a VM in a placement group

    Passing `servergroup_id` in the instance creation request assigns the VM to the group at launch time. The scheduler places the VM according to the group policy — on the same host as other group members (affinity) or on a different host (anti-affinity).

    | Parameter        | Required | Description                                                                                                                                |
    | ---------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
    | `servergroup_id` | Yes      | The placement group ID.                                                                                                                    |
    | `flavor`         | Yes      | Flavor ID — region-specific; list available flavors via <code>GET /cloud/v1/flavors/{project_id}/{region_id}</code>.                       |
    | `image_id`       | Yes      | Public image ID — region-specific; list available images via <code>GET /cloud/v1/images/{project_id}/{region_id}?visibility=public</code>. |

    <Tabs>
      <Tab title="Python SDK">
        ```python theme={null}
        instance = client.cloud.instances.create_and_poll(
            flavor=os.environ["FLAVOR_ID"],
            name="my-vm",
            volumes=[{
                "source": "image",
                "image_id": os.environ["IMAGE_ID"],
                "boot_index": 0,
                "size": 20,
                "type_name": "standard",
            }],
            interfaces=[{"type": "external"}],
            servergroup_id=group_id,
        )
        instance_id = instance.id
        print(f"Instance ID: {instance_id}  status: {instance.status}")
        ```
      </Tab>

      <Tab title="Go SDK">
        ```go theme={null}
        instance, err := client.Cloud.Instances.NewAndPoll(ctx, cloud.InstanceNewParams{
            Flavor:        os.Getenv("FLAVOR_ID"),
            Name:          gcore.String("my-vm"),
            ServergroupID: gcore.String(groupID),
            Volumes: []cloud.InstanceNewParamsVolumeUnion{
                {OfImage: &cloud.InstanceNewParamsVolumeImage{
                    ImageID:   os.Getenv("IMAGE_ID"),
                    BootIndex: gcore.Int(0),
                    Size:      gcore.Int(20),
                    TypeName:  "standard",
                }},
            },
            Interfaces: []cloud.InstanceNewParamsInterfaceUnion{
                {OfExternal: &cloud.InstanceNewParamsInterfaceExternal{Type: "external"}},
            },
        })
        if err != nil {
            log.Fatal(err)
        }
        instanceID := instance.ID
        fmt.Printf("Instance ID: %s  status: %s\n", instanceID, instance.Status)
        ```
      </Tab>

      <Tab title="curl">
        ```bash theme={null}
        curl -X POST "https://api.gcore.com/cloud/v2/instances/$GCORE_CLOUD_PROJECT_ID/$GCORE_CLOUD_REGION_ID" \
          -H "Authorization: APIKey $GCORE_API_KEY" \
          -H "Content-Type: application/json" \
          -d '{
            "flavor": "$FLAVOR_ID",
            "name": "my-vm",
            "volumes": [{
              "source": "image",
              "image_id": "$IMAGE_ID",
              "boot_index": 0,
              "size": 20,
              "type_name": "standard"
            }],
            "interfaces": [{"type": "external"}],
            "servergroup_id": "GROUP_ID"
          }'
        ```

        Response:

        ```json theme={null}
        {
          "tasks": ["b63f0fff-8b45-4b6d-a712-example00001"]
        }
        ```

        Poll <code>GET /cloud/v1/tasks/{task_id}</code> every 5 seconds until `state` is `FINISHED`. The instance ID is in `created_resources.instances[0]`.
      </Tab>
    </Tabs>

    ## Add an existing VM to a group

    An existing VM can be moved into a placement group without recreating it. The scheduler migrates the VM to a host that satisfies the group policy if necessary.

    | Parameter        | Required | Description                    |
    | ---------------- | -------- | ------------------------------ |
    | `instance_id`    | Yes      | The ID of the VM to add.       |
    | `servergroup_id` | Yes      | The target placement group ID. |

    <Tabs>
      <Tab title="Python SDK">
        ```python theme={null}
        client.cloud.instances.add_to_placement_group_and_poll(
            instance_id=instance_id,
            servergroup_id=group_id,
        )
        print("VM added to group")
        ```
      </Tab>

      <Tab title="Go SDK">
        ```go theme={null}
        if _, err = client.Cloud.Instances.AddToPlacementGroupAndPoll(
            ctx, instanceID, cloud.InstanceAddToPlacementGroupParams{
                ServergroupID: groupID,
            },
        ); err != nil {
            log.Fatal(err)
        }
        fmt.Println("VM added to group")
        ```
      </Tab>

      <Tab title="curl">
        ```bash theme={null}
        curl -X POST \
          "https://api.gcore.com/cloud/v1/instances/$GCORE_CLOUD_PROJECT_ID/$GCORE_CLOUD_REGION_ID/$INSTANCE_ID/put_into_servergroup" \
          -H "Authorization: APIKey $GCORE_API_KEY" \
          -H "Content-Type: application/json" \
          -d '{"servergroup_id": "GROUP_ID"}'
        ```

        Response:

        ```json theme={null}
        {
          "tasks": ["b63f0fff-8b45-4b6d-a712-example00002"]
        }
        ```

        Poll <code>GET /cloud/v1/tasks/{task_id}</code> every 5 seconds until `state` is `FINISHED`.
      </Tab>
    </Tabs>

    ## Get group details

    Retrieving a group shows which VMs are currently assigned to it and confirms that the placement policy applied correctly.

    <Tabs>
      <Tab title="Python SDK">
        ```python theme={null}
        details = client.cloud.placement_groups.get(group_id=group_id)
        print(f"Policy: {details.policy}  members: {len(details.instances)}")
        for vm in details.instances:
            print(f"  {vm.instance_id}  {vm.instance_name}")
        ```
      </Tab>

      <Tab title="Go SDK">
        ```go theme={null}
        details, err := client.Cloud.PlacementGroups.Get(ctx, groupID, cloud.PlacementGroupGetParams{})
        if err != nil {
            log.Fatal(err)
        }
        fmt.Printf("Policy: %s  members: %d\n", details.Policy, len(details.Instances))
        for _, vm := range details.Instances {
            fmt.Printf("  %s  %s\n", vm.InstanceID, vm.InstanceName)
        }
        ```
      </Tab>

      <Tab title="curl">
        ```bash theme={null}
        curl "https://api.gcore.com/cloud/v1/servergroups/$GCORE_CLOUD_PROJECT_ID/$GCORE_CLOUD_REGION_ID/$GROUP_ID" \
          -H "Authorization: APIKey $GCORE_API_KEY"
        ```

        Response:

        ```json theme={null}
        {
          "servergroup_id": "390bf8f5-c2e6-490a-b8a6-b80341a61d18",
          "policy": "anti-affinity",
          "name": "my-group",
          "instances": [
            {
              "instance_id": "7710bd12-3c1c-4566-b2d0-76e3ff51a1a3",
              "instance_name": "my-vm"
            }
          ]
        }
        ```
      </Tab>
    </Tabs>

    ## Remove a VM from a group

    Removing a VM from a placement group releases the placement constraint. The VM keeps running on its current host — it is not migrated.

    <Tabs>
      <Tab title="Python SDK">
        ```python theme={null}
        client.cloud.instances.remove_from_placement_group_and_poll(
            instance_id=instance_id,
        )
        print("VM removed from group")
        ```
      </Tab>

      <Tab title="Go SDK">
        ```go theme={null}
        if _, err = client.Cloud.Instances.RemoveFromPlacementGroupAndPoll(
            ctx, instanceID, cloud.InstanceRemoveFromPlacementGroupParams{},
        ); err != nil {
            log.Fatal(err)
        }
        fmt.Println("VM removed from group")
        ```
      </Tab>

      <Tab title="curl">
        ```bash theme={null}
        curl -X POST \
          "https://api.gcore.com/cloud/v1/instances/$GCORE_CLOUD_PROJECT_ID/$GCORE_CLOUD_REGION_ID/$INSTANCE_ID/remove_from_servergroup" \
          -H "Authorization: APIKey $GCORE_API_KEY"
        ```

        Response:

        ```json theme={null}
        {
          "tasks": ["b63f0fff-8b45-4b6d-a712-example00003"]
        }
        ```

        Poll <code>GET /cloud/v1/tasks/{task_id}</code> every 5 seconds until `state` is `FINISHED`.
      </Tab>
    </Tabs>

    ## Delete a placement group

    Deleting a placement group does not delete the VMs in it — the VMs keep running without a placement constraint. Remove VMs from the group first if the group has an active policy that should no longer apply.

    <Tabs>
      <Tab title="Python SDK">
        ```python theme={null}
        task = client.cloud.placement_groups.delete(group_id=group_id)
        client.cloud.tasks.poll(task.tasks[0])
        print(f"Deleted group {group_id}")
        ```
      </Tab>

      <Tab title="Go SDK">
        ```go theme={null}
        if err = client.Cloud.PlacementGroups.DeleteAndPoll(
            ctx, groupID, cloud.PlacementGroupDeleteParams{},
        ); err != nil {
            log.Fatal(err)
        }
        fmt.Printf("Deleted group %s\n", groupID)
        ```
      </Tab>

      <Tab title="curl">
        ```bash theme={null}
        curl -X DELETE \
          "https://api.gcore.com/cloud/v1/servergroups/$GCORE_CLOUD_PROJECT_ID/$GCORE_CLOUD_REGION_ID/$GROUP_ID" \
          -H "Authorization: APIKey $GCORE_API_KEY"
        ```

        Response:

        ```json theme={null}
        {
          "tasks": ["f95daa1e-cd16-4ec5-b43b-example00004"]
        }
        ```

        Poll <code>GET /cloud/v1/tasks/{task_id}</code> every 5 seconds until `state` is `FINISHED`.
      </Tab>
    </Tabs>
  </MethodSection>
</MethodSwitch>
