## Compute ### Virtual machines # Compute Source: https://docs.nebius.com/compute/index.md Compute allows you to create and manage virtual machines. These virtual machines function similarly to your local machine but are hosted in the cloud. You can connect to them and use their GPUs and other computing resources in your ML/AI workloads. In the [web console](https://console.nebius.com), Compute virtual machines are grouped on the **Virtual machines** page into four tabs: **Standalone VMs**, **Kubernetes nodes**, **Container VMs** and **Job and endpoint VMs**. The service is available in all [Nebius AI Cloud regions](https://docs.nebius.com/overview/regions.md). *InfiniBand and InfiniBand Trade Association are registered trademarks of the InfiniBand Trade Association.* Create your first set of virtual machines and connect to them Learn about virtual machines configurations Learn how to create different types of virtual machines Learn how to connect to virtual machines using SSH and allow other users to access VMs Create a GPU cluster and add VMs to it to interconnect them with InfiniBand Learn how to run tests to check the InfiniBand network state and performance Choose a storage option for your VMs that fits your goals best Manage and configure disks and shared filesystems Use volumes that you created on virtual machines Control GPU and vCPU states of your VMs Control disks and filesystems states # Getting started with Compute: Create your first Nebius AI Cloud virtual machine Source: https://docs.nebius.com/compute/quickstart.md To set up infrastructure for ML workloads, create the following resources in the `eu-north1` region: * Virtual machine (VM) with eight GPUs and a shared filesystem for training * Virtual machine with one GPU for inference Then, connect to them. ## Prerequisites Generate an [SSH key pair](https://docs.nebius.com/compute/virtual-machines/ssh-keys.md). * [Install and configure](https://docs.nebius.com/cli/install.md) the Nebius AI Cloud CLI. * Install [jq](https://jqlang.github.io/jq/) to extract IDs from JSON data returned by the Nebius AI Cloud CLI: ```bash Ubuntu sudo apt-get install jq ``` ```bash macOS brew install jq ``` * Generate an [SSH key pair](https://docs.nebius.com/compute/virtual-machines/ssh-keys.md). * [Install and initialize the Nebius SDK for Go](https://docs.nebius.com/grpc-api/sdk/go.md). * Generate an [SSH key pair](https://docs.nebius.com/compute/virtual-machines/ssh-keys.md). * [Install and initialize the Nebius SDK for Python](https://docs.nebius.com/grpc-api/sdk/python.md). * Generate an [SSH key pair](https://docs.nebius.com/compute/virtual-machines/ssh-keys.md). * [Install and initialize the Nebius SDK for JavaScript](https://docs.nebius.com/grpc-api/sdk/javascript.md). * Generate an [SSH key pair](https://docs.nebius.com/compute/virtual-machines/ssh-keys.md). ## Create a VM with eight GPUs with InfiniBand™ and a shared filesystem for training 1. In the sidebar, go to  **Compute** → **Virtual machines**. 2. Click **Create resource** → **Virtual machine**. The creation flow is a step-by-step wizard. The sidebar shows your progress through the configuration sections. To move between sections, click **Back** and **Next**. 3. On the **Compute** step, configure computing resources: 1. In the **Platform** section, select **With GPUs** and **Regular**. Then, select a [platform](https://docs.nebius.com/compute/virtual-machines/types.md) with NVIDIA® H100, H200 or B200 GPUs. Only these platforms support GPU clusters. 2. In the **Settings** section, select a **Preset** with 8 GPUs. 3. Create a GPU cluster for the VM. InfiniBand in the GPU cluster interconnects the VM GPUs for high-speed networking and efficient training. To use a GPU cluster, select an existing one or create a new cluster: 1. Click  **Create** in the **GPU cluster** field. 2. In the window that opens, specify the cluster name and InfiniBand fabric. To select the fabric, see [InfiniBand fabrics](https://docs.nebius.com/compute/clusters/gpu/index.md#infiniband-fabrics). 3. Click **Create**. 4. In the same section, select the **Project** for the VM location and specify the **VM name**. 4. On the **Storage** step, configure the boot disk and attach a shared filesystem: 1. In the **Boot disk** section, click  next to the boot disk. In the window that opens, keep **New VM-managed disk** selected, choose an Ubuntu [operating system](https://docs.nebius.com/compute/storage/boot-disk-images.md#images-for-gpu-vms) with pre-installed NVIDIA® GPU drivers, set the size to 50 GiB and click **Save**. 2. In the **Shared filesystems** section, click  **Attach shared filesystem**. 3. In the window that opens, create a new filesystem: specify its name, set the size to 50 GiB and the block size to 4 KiB. Click **Attach filesystem**. 4. After the window is closed, in the **Mount tag** field, specify a tag for mounting the filesystem to the VM. Create your own tag, such as `my-filesystem`. Make sure that it is unique within the VM. 5. To mount the filesystem to the VM automatically, keep the **Auto mount** option enabled. 5. On the **Network** step, select the **Network** and **Subnet**. In the **Public IP address** field, select **Auto (dynamic)**, so you can later connect to the VM by SSH. 6. On the **Configuration** step, in the **Access** section, add credentials so you can connect to the VM: 1. In the **Username and SSH key** field, click  **Create**. 2. In the window that opens, specify the username of the VM user, a public key of your SSH key pair and the credentials name to recognize the key in the list. Do not use the `root` or `admin` usernames. They are reserved for internal needs and are not allowed to connect to a VM by SSH. 3. Click **Add credentials**. 7. On the **Review** step, check the full VM configuration. To change a section quickly, click  next to the corresponding block. The wizard opens the relevant step with your current settings. Then, click **Create VM**. For more information about the wizard settings, see [How to create a virtual machine in Nebius AI Cloud](https://docs.nebius.com/compute/virtual-machines/manage.md). 1. Create a shared filesystem and save its ID to an environment variable: ```bash export TR_VM_FILESYSTEM_ID=$(nebius compute filesystem create \ --name training-vm-filesystem-1 \ --size-gibibytes 50 \ --type network_ssd \ --block-size-bytes 4096 \ --format json | jq -r ".metadata.id") ``` The command creates a 50 GiB SSD shared filesystem with 4 KiB blocks. 2. Get the subnet ID and save it to an environment variable: ```bash export SUBNET_ID=$(nebius vpc subnet list \ --format json \ | jq -r ".items[0].metadata.id") ``` Possible subnet ID: `vpcsubnet-***`. 3. For high-speed networking and efficient training, consider interconnecting multiple VM GPUs in a GPU cluster using InfiniBand. To do this, before creating the VM, create a GPU cluster to connect the VM and get its ID: ```bash export GPU_CLUSTER_ID=$(nebius compute gpu-cluster create \ --name gpu-cluster-name \ --infiniband-fabric fabric-3 \ --format json \ | jq -r ".metadata.id") ``` 4. Create a VM with 8 GPUs for training: ```bash export USER_DATA=$(jq -Rrs '.' < 1. Create a boot disk: ```go trainingDiskOperation, err := sdk.Services().Compute().V1(). Disk().Create( ctx, &compute.CreateDiskRequest{ Metadata: &common.ResourceMetadata{ Name: "training-vm-disk-1", }, Spec: &compute.DiskSpec{ Size: &compute.DiskSpec_SizeGibibytes{ SizeGibibytes: 50, }, BlockSizeBytes: 4096, Type: compute.DiskSpec_NETWORK_SSD, Source: &compute.DiskSpec_SourceImageFamily{ SourceImageFamily: &compute.SourceImageFamily{ ImageFamily: "ubuntu24.04-cuda13.0", }, }, }, }, ) if err != nil { return err } if _, err = trainingDiskOperation.Wait(ctx); err != nil { return err } trainingBootDiskID := trainingDiskOperation.ResourceID() ``` The code creates a 50 GiB SSD disk with a 4 KiB block size and an Ubuntu boot image with pre-installed NVIDIA® GPU drivers. For details about boot disk images, see [Boot disk images for Compute virtual machines](https://docs.nebius.com/compute/storage/boot-disk-images.md). 2. Create a shared filesystem: ```go trainingFSOperation, err := sdk.Services().Compute().V1(). Filesystem().Create( ctx, &compute.CreateFilesystemRequest{ Metadata: &common.ResourceMetadata{ Name: "training-vm-filesystem-1", }, Spec: &compute.FilesystemSpec{ Size: &compute.FilesystemSpec_SizeGibibytes{ SizeGibibytes: 50, }, BlockSizeBytes: 4096, Type: compute.FilesystemSpec_NETWORK_SSD, }, }, ) if err != nil { return err } if _, err = trainingFSOperation.Wait(ctx); err != nil { return err } trainingFilesystemID := trainingFSOperation.ResourceID() ``` The code creates a 50 GiB SSD shared filesystem with 4 KiB blocks. 3. Get the subnet ID: ```go subnets, err := sdk.Services().VPC().V1(). Subnet().List( ctx, &vpc.ListSubnetsRequest{}, ) if err != nil { return err } if len(subnets.GetItems()) == 0 { return errors.New("no subnets found") } subnetID := subnets.GetItems()[0].GetMetadata().GetId() ``` Possible subnet ID: `vpcsubnet-e0dcbaa76x2024xyz8`. 4. For high-speed networking and efficient training, consider interconnecting multiple VM GPUs in a GPU cluster using InfiniBand™. To do this, before creating the VM, create a GPU cluster to connect the VM and get its ID: ```go gpuClusterOperation, err := sdk.Services().Compute().V1(). GpuCluster().Create( ctx, &compute.CreateGpuClusterRequest{ Metadata: &common.ResourceMetadata{ Name: "gpu-cluster-name", }, Spec: &compute.GpuClusterSpec{ InfinibandFabric: "fabric-3", }, }, ) if err != nil { return err } if _, err = gpuClusterOperation.Wait(ctx); err != nil { return err } gpuClusterID := gpuClusterOperation.ResourceID() ``` 5. Create a VM with 8 GPUs for training: ```go var gpuCluster *compute.InstanceGpuClusterSpec if gpuClusterID != "" { gpuCluster = &compute.InstanceGpuClusterSpec{ Id: gpuClusterID, } } trainingNetworkName := "multi-gpu-node-compute-api-" + "network-interface" trainingResources := &compute.ResourcesSpec{ Platform: "gpu-h100-sxm", Size: &compute.ResourcesSpec_Preset{ Preset: "8gpu-128vcpu-1600gb", }, } trainingBootDisk := &compute.AttachedDiskSpec{ AttachMode: compute.AttachedDiskSpec_READ_WRITE, Type: &compute.AttachedDiskSpec_ExistingDisk{ ExistingDisk: &compute.ExistingDisk{ Id: trainingBootDiskID, }, }, } trainingExistingFS := &compute.ExistingFilesystem{ Id: trainingFilesystemID, } trainingFilesystem := &compute.AttachedFilesystemSpec{ AttachMode: compute.AttachedFilesystemSpec_READ_WRITE, MountTag: "training-vm-filesystem-1", Type: &compute.AttachedFilesystemSpec_ExistingFilesystem{ ExistingFilesystem: trainingExistingFS, }, } trainingNetwork := &compute.NetworkInterfaceSpec{ Name: trainingNetworkName, SubnetId: subnetID, IpAddress: &compute.IPAddress{}, PublicIpAddress: &compute.PublicIPAddress{}, } trainingSpec := &compute.InstanceSpec{ Resources: trainingResources, GpuCluster: gpuCluster, BootDisk: trainingBootDisk, Filesystems: []*compute.AttachedFilesystemSpec{ trainingFilesystem, }, CloudInitUserData: userData, NetworkInterfaces: []*compute.NetworkInterfaceSpec{ trainingNetwork, }, } trainingVMOperation, err := sdk.Services().Compute().V1(). Instance().Create( ctx, &compute.CreateInstanceRequest{ Metadata: &common.ResourceMetadata{ Name: "training-vm", }, Spec: trainingSpec, }, ) if err != nil { return err } if _, err = trainingVMOperation.Wait(ctx); err != nil { return err } trainingVMID := trainingVMOperation.ResourceID() ``` The given example assumes that you work with VMs that have public addresses, so you can later [connect to these VMs by SSH](https://docs.nebius.com/compute/quickstart.md#connect-to-the-vms). However, if you need isolated VMs without public addresses, do not set `PublicIpAddress` in the network interface specification. To access the VM, you can [set up a WireGuard jump server](https://docs.nebius.com/compute/virtual-machines/wireguard.md) later. This approach enhances security and still provides access to the VM within the same subnet. For more information about creating VMs and managing their network parameters, see [How to create a virtual machine in Nebius AI Cloud](https://docs.nebius.com/compute/virtual-machines/manage.md). 1. Create a boot disk: ```python disk_service = DiskServiceClient(sdk) training_disk_operation = await disk_service.create( CreateDiskRequest( metadata=ResourceMetadata( name="training-vm-disk-1", ), spec=DiskSpec( block_size_bytes=4096, type=DiskSpec.DiskType.NETWORK_SSD, source_image_family=SourceImageFamily( image_family="ubuntu24.04-cuda13.0", ), size_gibibytes=50, ), ), ) await training_disk_operation.wait() training_boot_disk_id = training_disk_operation.resource_id ``` The code creates a 50 GiB SSD disk with a 4 KiB block size and an Ubuntu boot image with pre-installed NVIDIA® GPU drivers. For details about boot disk images, see [Boot disk images for Compute virtual machines](https://docs.nebius.com/compute/storage/boot-disk-images.md). 2. Create a shared filesystem: ```python filesystem_service = FilesystemServiceClient(sdk) training_fs_operation = await filesystem_service.create( CreateFilesystemRequest( metadata=ResourceMetadata( name="training-vm-filesystem-1", ), spec=FilesystemSpec( block_size_bytes=4096, type=FilesystemSpec.FilesystemType.NETWORK_SSD, size_gibibytes=50, ), ), ) await training_fs_operation.wait() training_filesystem_id = training_fs_operation.resource_id ``` The code creates a 50 GiB SSD shared filesystem with 4 KiB blocks. 3. Get the subnet ID: ```python subnet_service = SubnetServiceClient(sdk) subnets = await subnet_service.list(ListSubnetsRequest()) if not subnets.items: raise ValueError("no subnets found") subnet_id = subnets.items[0].metadata.id ``` Possible subnet ID: `vpcsubnet-e0dcbaa76x2024xyz8`. 4. For high-speed networking and efficient training, consider interconnecting multiple VM GPUs in a GPU cluster using InfiniBand™. To do this, before creating the VM, create a GPU cluster to connect the VM and get its ID: ```python gpu_cluster_service = GpuClusterServiceClient(sdk) gpu_cluster_operation = await gpu_cluster_service.create( CreateGpuClusterRequest( metadata=ResourceMetadata( name="gpu-cluster-name", ), spec=GpuClusterSpec( infiniband_fabric="fabric-3", ), ), ) await gpu_cluster_operation.wait() gpu_cluster_id = gpu_cluster_operation.resource_id ``` 5. Create a VM with 8 GPUs for training: ```python gpu_cluster = None if gpu_cluster_id: gpu_cluster = InstanceGpuClusterSpec(id=gpu_cluster_id) training_network_name = ( "multi-gpu-node-compute-api-" "network-interface" ) instance_service = InstanceServiceClient(sdk) training_vm_operation = await instance_service.create( CreateInstanceRequest( metadata=ResourceMetadata(name="training-vm"), spec=InstanceSpec( resources=ResourcesSpec( platform="gpu-h100-sxm", preset="8gpu-128vcpu-1600gb", ), gpu_cluster=gpu_cluster, boot_disk=AttachedDiskSpec( attach_mode=( AttachedDiskSpec.AttachMode.READ_WRITE ), existing_disk=ExistingDisk( id=training_boot_disk_id, ), ), filesystems=[ AttachedFilesystemSpec( attach_mode=( AttachedFilesystemSpec.AttachMode.READ_WRITE ), existing_filesystem=ExistingFilesystem( id=training_filesystem_id, ), mount_tag="training-vm-filesystem-1", ), ], cloud_init_user_data=user_data, network_interfaces=[ NetworkInterfaceSpec( name=training_network_name, subnet_id=subnet_id, ip_address=IPAddress(), public_ip_address=PublicIPAddress(), ), ], ), ), ) await training_vm_operation.wait() training_vm_id = training_vm_operation.resource_id ``` The given example assumes that you work with VMs that have public addresses, so you can later [connect to these VMs by SSH](https://docs.nebius.com/compute/quickstart.md#connect-to-the-vms). However, if you need isolated VMs without public addresses, do not set `public_ip_address` in the network interface specification. To access the VM, you can [set up a WireGuard jump server](https://docs.nebius.com/compute/virtual-machines/wireguard.md) later. This approach enhances security and still provides access to the VM within the same subnet. For more information about creating VMs and managing their network parameters, see [How to create a virtual machine in Nebius AI Cloud](https://docs.nebius.com/compute/virtual-machines/manage.md). 1. Create a boot disk: ```ts const diskService = new DiskService(sdk); const trainingDiskOperation = await diskService.create( CreateDiskRequest.create({ metadata: ResourceMetadata.create({ name: "training-vm-disk-1", }), spec: DiskSpec.create({ blockSizeBytes: 4096, type: DiskSpec_DiskType.NETWORK_SSD, source: { $case: "sourceImageFamily", sourceImageFamily: SourceImageFamily.create({ imageFamily: "ubuntu24.04-cuda13.0", }), }, size: { $case: "sizeGibibytes", sizeGibibytes: 50, }, }), }), ).result; await trainingDiskOperation.wait(); const trainingBootDiskId = trainingDiskOperation.resourceId(); ``` The code creates a 50 GiB SSD disk with a 4 KiB block size and an Ubuntu boot image with pre-installed NVIDIA® GPU drivers. For details about boot disk images, see [Boot disk images for Compute virtual machines](https://docs.nebius.com/compute/storage/boot-disk-images.md). 2. Create a shared filesystem: ```ts const filesystemService = new FilesystemService(sdk); const trainingFsOperation = await filesystemService.create( CreateFilesystemRequest.create({ metadata: ResourceMetadata.create({ name: "training-vm-filesystem-1", }), spec: FilesystemSpec.create({ blockSizeBytes: 4096, type: FilesystemSpec_FilesystemType.NETWORK_SSD, size: { $case: "sizeGibibytes", sizeGibibytes: 1024, }, }), }), ).result; await trainingFsOperation.wait(); const trainingFilesystemId = trainingFsOperation.resourceId(); ``` The code creates a 50 GiB SSD shared filesystem with 4 KiB blocks. 3. Get the subnet ID: ```ts const subnetService = new SubnetService(sdk); const subnets = await subnetService.list( ListSubnetsRequest.create({}), ); const subnetId = subnets.items[0]?.metadata?.id; if (!subnetId) { throw new Error("no subnets found"); } ``` Possible subnet ID: `vpcsubnet-e0dcbaa76x2024xyz8`. 4. For high-speed networking and efficient training, consider interconnecting multiple VM GPUs in a GPU cluster using InfiniBand™. To do this, before creating the VM, create a GPU cluster to connect the VM and get its ID: ```ts const gpuClusterService = new GpuClusterService(sdk); const gpuClusterOperation = await gpuClusterService.create( CreateGpuClusterRequest.create({ metadata: ResourceMetadata.create({ name: "gpu-cluster-name", }), spec: GpuClusterSpec.create({ infinibandFabric: "fabric-3", }), }), ).result; await gpuClusterOperation.wait(); let gpuClusterId = gpuClusterOperation.resourceId(); ``` 5. Create a VM with 8 GPUs for training: ```ts const gpuCluster = gpuClusterId ? InstanceGpuClusterSpec.create({ id: gpuClusterId }) : undefined; const trainingNetworkName = "multi-gpu-node-compute-api-" + "network-interface"; const instanceService = new InstanceService(sdk); const trainingVmOperation = await instanceService.create( CreateInstanceRequest.create({ metadata: ResourceMetadata.create({ name: "training-vm", }), spec: InstanceSpec.create({ resources: ResourcesSpec.create({ platform: "gpu-h100-sxm", size: { $case: "preset", preset: "8gpu-128vcpu-1600gb", }, }), gpuCluster, bootDisk: AttachedDiskSpec.create({ attachMode: AttachedDiskSpec_AttachMode.READ_WRITE, type: { $case: "existingDisk", existingDisk: ExistingDisk.create({ id: trainingBootDiskId, }), }, }), filesystems: [ AttachedFilesystemSpec.create({ attachMode: AttachedFilesystemSpec_AttachMode.READ_WRITE, mountTag: "training-vm-filesystem-1", type: { $case: "existingFilesystem", existingFilesystem: ExistingFilesystem.create({ id: trainingFilesystemId, }), }, }), ], cloudInitUserData: userData, networkInterfaces: [ NetworkInterfaceSpec.create({ name: trainingNetworkName, subnetId, ipAddress: IPAddress.create({}), publicIpAddress: PublicIPAddress.create({}), }), ], }), }), ).result; await trainingVmOperation.wait(); const trainingVmId = trainingVmOperation.resourceId(); ``` The given example assumes that you work with VMs that have public addresses, so you can later [connect to these VMs by SSH](https://docs.nebius.com/compute/quickstart.md#connect-to-the-vms). However, if you need isolated VMs without public addresses, do not set `publicIpAddress` in the network interface specification. To access the VM, you can [set up a WireGuard jump server](https://docs.nebius.com/compute/virtual-machines/wireguard.md) later. This approach enhances security and still provides access to the VM within the same subnet. For more information about creating VMs and managing their network parameters, see [How to create a virtual machine in Nebius AI Cloud](https://docs.nebius.com/compute/virtual-machines/manage.md). ## Create a VM with one GPU for inference 1. In the sidebar, go to  **Compute** → **Virtual machines**. 2. Click **Create resource** → **Virtual machine**. 3. On the **Compute** step, configure computing resources: 1. In the **Platform** section, select **With GPUs** and **Regular**. Then, select any [GPU platform](https://docs.nebius.com/compute/virtual-machines/types.md). 2. In the **Settings** section, select a **Preset** with one GPU and the **Project** for the VM location, and specify the **VM name**. 4. On the **Storage** step, in the **Boot disk** section, click  next to the boot disk. In the window that opens, keep **New VM-managed disk** selected, choose an Ubuntu operating system with pre-installed NVIDIA® GPU drivers, set the size to 50 GiB and click **Save**. 5. On the **Network** step, select the **Network** and **Subnet**. In the **Public IP address** field, select **Auto (dynamic)**, so you can later connect to the VM by SSH. 6. On the **Configuration** step, in the **Access** section, add the same username and SSH public key that you used for the VM with eight GPUs. 7. On the **Review** step, check the full VM configuration and click **Create VM**. Create a VM with one GPU for inference: ```bash export INF_VM_ID=$(nebius compute instance create \ --name inference-vm \ --resources-platform gpu-h100-sxm \ --resources-preset 1gpu-16vcpu-200gb \ --boot-disk-managed-disk-name inference-vm-disk-1 \ --boot-disk-managed-disk-type network_ssd \ --boot-disk-managed-disk-size-gibibytes 50 \ --boot-disk-managed-disk-block-size-bytes 4096 \ --boot-disk-managed-disk-source-image-family-image-family ubuntu24.04-cuda13.0 \ --boot-disk-attach-mode READ_WRITE \ --cloud-init-user-data "$USER_DATA" \ --network-interfaces "[{\"name\": \"eth0\", \"subnet_id\": \"$SUBNET_ID\", \"ip_address\": {}, \"public_ip_address\": {}}]" \ --format json | jq -r ".metadata.id") ``` The command creates the VM with a boot disk that has the same settings as the boot disk of the training VM. It uses the same `USER_DATA` variable and cloud-init configuration as the training VM. 1. Create a boot disk: ```go inferenceDiskOperation, err := sdk.Services().Compute().V1().Disk().Create( ctx, &compute.CreateDiskRequest{ Metadata: &common.ResourceMetadata{ Name: "inference-vm-disk-1", }, Spec: &compute.DiskSpec{ Size: &compute.DiskSpec_SizeGibibytes{ SizeGibibytes: 50, }, BlockSizeBytes: 4096, Type: compute.DiskSpec_NETWORK_SSD, Source: &compute.DiskSpec_SourceImageFamily{ SourceImageFamily: &compute.SourceImageFamily{ ImageFamily: "ubuntu24.04-cuda13.0", }, }, }, }, ) if err != nil { return err } if _, err = inferenceDiskOperation.Wait(ctx); err != nil { return err } inferenceBootDiskID := inferenceDiskOperation.ResourceID() ``` The code creates a 50 GiB SSD disk with a 4 KiB block size and an Ubuntu boot image with pre-installed NVIDIA® GPU drivers. For details about boot disk images, see [Boot disk images for Compute virtual machines](https://docs.nebius.com/compute/storage/boot-disk-images.md). 2. Create a VM with one GPU for inference: ```go inferenceNetworkName := "single-gpu-node-compute-api-" + "network-interface" inferenceResources := &compute.ResourcesSpec{ Platform: "gpu-h100-sxm", Size: &compute.ResourcesSpec_Preset{ Preset: "1gpu-16vcpu-200gb", }, } inferenceBootDisk := &compute.AttachedDiskSpec{ AttachMode: compute.AttachedDiskSpec_READ_WRITE, Type: &compute.AttachedDiskSpec_ExistingDisk{ ExistingDisk: &compute.ExistingDisk{ Id: inferenceBootDiskID, }, }, } inferenceNetwork := &compute.NetworkInterfaceSpec{ Name: inferenceNetworkName, SubnetId: subnetID, IpAddress: &compute.IPAddress{}, PublicIpAddress: &compute.PublicIPAddress{}, } inferenceSpec := &compute.InstanceSpec{ Resources: inferenceResources, BootDisk: inferenceBootDisk, CloudInitUserData: userData, NetworkInterfaces: []*compute.NetworkInterfaceSpec{ inferenceNetwork, }, } inferenceVMOperation, err := sdk.Services().Compute().V1(). Instance().Create( ctx, &compute.CreateInstanceRequest{ Metadata: &common.ResourceMetadata{ Name: "inference-vm", }, Spec: inferenceSpec, }, ) if err != nil { return err } if _, err = inferenceVMOperation.Wait(ctx); err != nil { return err } inferenceVMID := inferenceVMOperation.ResourceID() ``` 1. Create a boot disk: ```python inference_disk_service = DiskServiceClient(sdk) inference_disk_operation = await inference_disk_service.create( CreateDiskRequest( metadata=ResourceMetadata( name="inference-vm-disk-1", ), spec=DiskSpec( block_size_bytes=4096, type=DiskSpec.DiskType.NETWORK_SSD, source_image_family=SourceImageFamily( image_family="ubuntu24.04-cuda13.0", ), size_gibibytes=50, ), ), ) await inference_disk_operation.wait() inference_boot_disk_id = inference_disk_operation.resource_id ``` The code creates a 50 GiB SSD disk with a 4 KiB block size and an Ubuntu boot image with pre-installed NVIDIA® GPU drivers. For details about boot disk images, see [Boot disk images for Compute virtual machines](https://docs.nebius.com/compute/storage/boot-disk-images.md). 2. Create a VM with one GPU for inference: ```python inference_network_name = ( "single-gpu-node-compute-api-" "network-interface" ) inference_service = InstanceServiceClient(sdk) inference_vm_operation = await inference_service.create( CreateInstanceRequest( metadata=ResourceMetadata(name="inference-vm"), spec=InstanceSpec( resources=ResourcesSpec( platform="gpu-h100-sxm", preset="1gpu-16vcpu-200gb", ), boot_disk=AttachedDiskSpec( attach_mode=( AttachedDiskSpec.AttachMode.READ_WRITE ), existing_disk=ExistingDisk( id=inference_boot_disk_id, ), ), cloud_init_user_data=user_data, network_interfaces=[ NetworkInterfaceSpec( name=inference_network_name, subnet_id=subnet_id, ip_address=IPAddress(), public_ip_address=PublicIPAddress(), ), ], ), ), ) await inference_vm_operation.wait() inference_vm_id = inference_vm_operation.resource_id ``` 1. Create a boot disk: ```ts const inferenceDiskService = new DiskService(sdk); const inferenceDiskOperation = await inferenceDiskService.create( CreateDiskRequest.create({ metadata: ResourceMetadata.create({ name: "inference-vm-disk-1", }), spec: DiskSpec.create({ blockSizeBytes: 4096, type: DiskSpec_DiskType.NETWORK_SSD, source: { $case: "sourceImageFamily", sourceImageFamily: SourceImageFamily.create({ imageFamily: "ubuntu24.04-cuda13.0", }), }, size: { $case: "sizeGibibytes", sizeGibibytes: 50, }, }), }), ).result; await inferenceDiskOperation.wait(); const inferenceBootDiskId = inferenceDiskOperation.resourceId(); ``` The code creates a 50 GiB SSD disk with a 4 KiB block size and an Ubuntu boot image with pre-installed NVIDIA® GPU drivers. For details about boot disk images, see [Boot disk images for Compute virtual machines](https://docs.nebius.com/compute/storage/boot-disk-images.md). 2. Create a VM with one GPU for inference: ```ts const inferenceNetworkName = "single-gpu-node-compute-api-" + "network-interface"; const inferenceService = new InstanceService(sdk); const inferenceVmOperation = await inferenceService.create( CreateInstanceRequest.create({ metadata: ResourceMetadata.create({ name: "inference-vm", }), spec: InstanceSpec.create({ resources: ResourcesSpec.create({ platform: "gpu-h100-sxm", size: { $case: "preset", preset: "1gpu-16vcpu-200gb", }, }), bootDisk: AttachedDiskSpec.create({ attachMode: AttachedDiskSpec_AttachMode.READ_WRITE, type: { $case: "existingDisk", existingDisk: ExistingDisk.create({ id: inferenceBootDiskId, }), }, }), cloudInitUserData: userData, networkInterfaces: [ NetworkInterfaceSpec.create({ name: inferenceNetworkName, subnetId, ipAddress: IPAddress.create({}), publicIpAddress: PublicIPAddress.create({}), }), ], }), }), ).result; await inferenceVmOperation.wait(); const inferenceVmId = inferenceVmOperation.resourceId(); ``` ## Connect to the VMs Connect to the VM for training via SSH: 1. In the sidebar, go to  **Compute** → **Virtual machines**. 2. Open the page of the VM and copy its public IP address. 3. Use the public IP address to connect to the VM: ```bash ssh @ ``` Use the username that you specified when creating the VM. 1. Get your VM's public IP address and save it to an environment variable: ```bash export TR_PUBLIC_IP_ADDRESS=$(nebius compute instance get \ --id $TR_VM_ID \ --format json \ | jq -r '.status.network_interfaces[0].public_ip_address.address | split("/")[0]') ``` 2. Use the public IP address to connect to the VM: ```bash ssh user@$TR_PUBLIC_IP_ADDRESS ``` 1. Get your VM's public IP address: ```go trainingInstance, err := sdk.Services().Compute().V1(). Instance().Get( ctx, &compute.GetInstanceRequest{ Id: trainingVMID, }, ) if err != nil { return err } trainingAddress := trainingInstance.GetStatus(). GetNetworkInterfaces()[0]. GetPublicIpAddress().GetAddress() trainingPublicIP := strings.Split(trainingAddress, "/")[0] if trainingPublicIP == "" { return fmt.Errorf("training VM public IP is missing") } ``` 2. Use the public IP address to connect to the VM: ```bash ssh user@ ``` 1. Get your VM's public IP address: ```python training_ip_service = InstanceServiceClient(sdk) training_instance = await training_ip_service.get( GetInstanceRequest(id=training_vm_id), ) training_address = ( training_instance.status.network_interfaces[0] .public_ip_address.address ) training_public_ip = training_address.split("/")[0] ``` 2. Use the public IP address to connect to the VM: ```bash ssh user@ ``` 1. Get your VM's public IP address: ```ts const trainingIpService = new InstanceService(sdk); const trainingInstance = await trainingIpService.get( GetInstanceRequest.create({ id: trainingVmId, }), ); const trainingAddress = trainingInstance.status ?.networkInterfaces[0]?.publicIpAddress?.address; const trainingPublicIp = trainingAddress?.split("/")[0]; if (!trainingPublicIp) { throw new Error("training VM public IP is missing"); } ``` 2. Use the public IP address to connect to the VM: ```bash ssh user@ ``` Connect to the VM for inference via SSH: Do the same steps as for the training VM. Open the page of the inference VM, copy its public IP address and then connect to the inference VM: ```bash ssh @ ``` Use the username that you specified when creating the inference VM. 1. Get your VM's public IP address and save it to an environment variable: ```bash export INF_PUBLIC_IP_ADDRESS=$(nebius compute instance get \ --id $INF_VM_ID \ --format json \ | jq -r '.status.network_interfaces[0].public_ip_address.address | split("/")[0]') ``` 2. Use the public IP address to connect to the VM: ```bash ssh user@$INF_PUBLIC_IP_ADDRESS ``` 1. Get your VM's public IP address: ```go inferenceInstance, err := sdk.Services().Compute().V1(). Instance().Get( ctx, &compute.GetInstanceRequest{ Id: inferenceVMID, }, ) if err != nil { return err } inferenceAddress := inferenceInstance.GetStatus(). GetNetworkInterfaces()[0]. GetPublicIpAddress().GetAddress() inferencePublicIP := strings.Split(inferenceAddress, "/")[0] if inferencePublicIP == "" { return fmt.Errorf("inference VM public IP is missing") } ``` 2. Use the public IP address to connect to the VM: ```bash ssh user@ ``` 1. Get your VM's public IP address: ```python inference_ip_service = InstanceServiceClient(sdk) inference_instance = await inference_ip_service.get( GetInstanceRequest(id=inference_vm_id), ) inference_address = ( inference_instance.status.network_interfaces[0] .public_ip_address.address ) inference_public_ip = inference_address.split("/")[0] ``` 2. Use the public IP address to connect to the VM: ```bash ssh user@ ``` 1. Get your VM's public IP address: ```ts const inferenceIpService = new InstanceService(sdk); const inferenceInstance = await inferenceIpService.get( GetInstanceRequest.create({ id: inferenceVmId, }), ); const inferenceAddress = inferenceInstance.status ?.networkInterfaces[0]?.publicIpAddress?.address; const inferencePublicIp = inferenceAddress?.split("/")[0]; if (!inferencePublicIp) { throw new Error("inference VM public IP is missing"); } ``` 2. Use the public IP address to connect to the VM: ```bash ssh user@ ``` ## What's next * Learn about [VM and GPU types](https://docs.nebius.com/compute/virtual-machines/types.md) * Learn how to [create different types of VMs](https://docs.nebius.com/compute/virtual-machines/manage.md) * Learn more about [VM networking](https://docs.nebius.com/compute/virtual-machines/network.md) * Learn how to work with [GPU clusters](https://docs.nebius.com/compute/clusters/gpu/index.md) *InfiniBand and InfiniBand Trade Association are registered trademarks of the InfiniBand Trade Association.* # Getting started with Compute: Host an LLM on Nebius AI Cloud Source: https://docs.nebius.com/compute/quickstart-host-model.md You can create a virtual machine (VM) in Nebius AI Cloud, deploy the [Qwen/Qwen2.5-72B-Instruct](https://huggingface.co/Qwen/Qwen2.5-72B-Instruct) large language model (LLM) on the VM and then use [Open WebUI](https://openwebui.com/) to provide access to the model in a browser. ## Before you start Meet the following prerequisites, depending on the preferred interface: Generate an [SSH key pair](https://docs.nebius.com/compute/virtual-machines/ssh-keys.md). 1. [Install and configure](https://docs.nebius.com/cli/install.md) the Nebius AI Cloud CLI. 2. To extract JSON data from the CLI output, install [jq](https://jqlang.github.io/jq/): ```bash Ubuntu sudo apt-get install jq ``` ```bash macOS brew install jq ``` 3. Generate an [SSH key pair](https://docs.nebius.com/compute/virtual-machines/ssh-keys.md). 1. [Install and initialize the Nebius SDK for Go](https://docs.nebius.com/grpc-api/sdk/go.md). 2. Generate an [SSH key pair](https://docs.nebius.com/compute/virtual-machines/ssh-keys.md). 1. [Install and initialize the Nebius SDK for Python](https://docs.nebius.com/grpc-api/sdk/python.md). 2. Generate an [SSH key pair](https://docs.nebius.com/compute/virtual-machines/ssh-keys.md). 1. [Install and initialize the Nebius SDK for JavaScript](https://docs.nebius.com/grpc-api/sdk/javascript.md). 2. Generate an [SSH key pair](https://docs.nebius.com/compute/virtual-machines/ssh-keys.md). ## Create the VM 1. Go to the [web console](https://console.nebius.com), click **Create resource** and then select **Virtual machine**. 2. On the VM creation page that opens, set the following parameters: * **Platform**: NVIDIA® H100 NVLink with Intel Sapphire Rapids. * **Preset**: 1 GPU - 16 CPUs - 200 GiB RAM. * **Boot disk image**: Ubuntu 22.04 LTS for NVIDIA® GPUs (CUDA® 12). For details about boot disk images, see [Boot disk images for Compute virtual machines](https://docs.nebius.com/compute/storage/boot-disk-images.md). * **Boot disk size**: 300 GiB SSD. * **Network**: Select the **Public IP address: Auto assign static IP** option. * **Username and SSH key**: Select the public key that you created earlier. In this field, do not use the `root` or `admin` usernames. They are reserved for internal needs and are not allowed to connect to a VM by SSH. 3. Click **Create VM**. The given example assumes that you work with a VM that has a public address, so you can later [connect to this VM by SSH](https://docs.nebius.com/compute/quickstart-host-model.md#connect-to-the-vm). However, if you need an isolated VM, do not assign a public address. To access the VM, you can [set up a WireGuard jump server](https://docs.nebius.com/compute/virtual-machines/wireguard.md) later. This approach enhances security and still provides access to the VM within the same subnet. For more information about creating VMs and managing their network parameters, see [How to create a virtual machine in Nebius AI Cloud](https://docs.nebius.com/compute/virtual-machines/manage.md). 1. Create a boot disk and save its ID to an environment variable: ```bash export BOOT_DISK_ID=$(nebius compute disk create \ --name openwebui-disk-1 \ --size-gibibytes 300 \ --type network_ssd \ --source-image-family-image-family ubuntu24.04-cuda13.0 \ --block-size-bytes 4096 \ --format json | jq -r ".metadata.id") ``` The command creates a 300 GiB SSD disk with a 4 KiB block size, and an Ubuntu boot image with pre-installed NVIDIA® GPU drivers. For details about boot disk images, see [Boot disk images for Compute virtual machines](https://docs.nebius.com/compute/storage/boot-disk-images.md). 2. Get the default subnet ID and save it to an environment variable: ```bash export SUBNET_ID=$(nebius vpc subnet list \ --format json \ | jq -r ".items[0].metadata.id") ``` 3. Create the VM with one GPU: ```bash export USER_DATA=$(jq -Rrs '.' < sudo: ALL=(ALL) NOPASSWD:ALL shell: /bin/bash ssh_authorized_keys: - $(cat ~/.ssh/id_ed25519.pub) EOF ) export VM_ID=$(nebius compute instance create \ --name openwebui \ --resources-platform gpu-h100-sxm \ --resources-preset 1gpu-16vcpu-200gb \ --boot-disk-existing-disk-id "$BOOT_DISK_ID" \ --boot-disk-attach-mode READ_WRITE \ --cloud-init-user-data "$USER_DATA" \ --network-interfaces "[{\"name\": \"default-subnet\", \"subnet_id\": \"$SUBNET_ID\", \"ip_address\": {}, \"public_ip_address\": {}}]" \ --format json | jq -r ".metadata.id") ``` The given example assumes that you work with a VM that has a public address, so you can later [connect to this VM by SSH](https://docs.nebius.com/compute/quickstart-host-model.md#connect-to-the-vm). However, if you need an isolated VM without a public address, remove `"public_ip_address": {}` from the `--network-interfaces` parameter. To access the VM, you can [set up a WireGuard jump server](https://docs.nebius.com/compute/virtual-machines/wireguard.md) later. This approach enhances security and still provides access to the VM within the same subnet. For more information about creating VMs and managing their network parameters, see [How to create a virtual machine in Nebius AI Cloud](https://docs.nebius.com/compute/virtual-machines/manage.md). 1. Create a boot disk: ```go bootDiskOperation, err := sdk.Services().Compute().V1(). Disk().Create( ctx, &compute.CreateDiskRequest{ Metadata: &common.ResourceMetadata{ Name: "openwebui-disk-1", }, Spec: &compute.DiskSpec{ Size: &compute.DiskSpec_SizeGibibytes{ SizeGibibytes: 300, }, BlockSizeBytes: 4096, Type: compute.DiskSpec_NETWORK_SSD, Source: &compute.DiskSpec_SourceImageFamily{ SourceImageFamily: &compute.SourceImageFamily{ ImageFamily: "ubuntu24.04-cuda13.0", }, }, }, }, ) if err != nil { return err } if _, err = bootDiskOperation.Wait(ctx); err != nil { return err } bootDiskID := bootDiskOperation.ResourceID() ``` The code creates a 300 GiB SSD disk with a 4 KiB block size and an Ubuntu boot image with pre-installed NVIDIA® GPU drivers. For details about boot disk images, see [Boot disk images for Compute virtual machines](https://docs.nebius.com/compute/storage/boot-disk-images.md). 2. Get the default subnet ID: ```go subnets, err := sdk.Services().VPC().V1(). Subnet().List( ctx, &vpc.ListSubnetsRequest{}, ) if err != nil { return err } if len(subnets.GetItems()) == 0 { return errors.New("no subnets found") } subnetID := subnets.GetItems()[0].GetMetadata().GetId() ``` 3. Create the VM with one GPU: ```go hostResources := &compute.ResourcesSpec{ Platform: "gpu-h100-sxm", Size: &compute.ResourcesSpec_Preset{ Preset: "1gpu-16vcpu-200gb", }, } hostBootDisk := &compute.AttachedDiskSpec{ AttachMode: compute.AttachedDiskSpec_READ_WRITE, Type: &compute.AttachedDiskSpec_ExistingDisk{ ExistingDisk: &compute.ExistingDisk{ Id: bootDiskID, }, }, } hostNetworkInterface := &compute.NetworkInterfaceSpec{ Name: "default-subnet", SubnetId: subnetID, IpAddress: &compute.IPAddress{}, PublicIpAddress: &compute.PublicIPAddress{}, } hostInstanceSpec := &compute.InstanceSpec{ Resources: hostResources, BootDisk: hostBootDisk, NetworkInterfaces: []*compute.NetworkInterfaceSpec{ hostNetworkInterface, }, CloudInitUserData: userData, } hostOperation, err := sdk.Services().Compute().V1(). Instance().Create( ctx, &compute.CreateInstanceRequest{ Metadata: &common.ResourceMetadata{ Name: "openwebui", }, Spec: hostInstanceSpec, }, ) if err != nil { return err } if _, err = hostOperation.Wait(ctx); err != nil { return err } ``` The given example assumes that you work with a VM that has a public address, so you can later [connect to this VM by SSH](https://docs.nebius.com/compute/quickstart-host-model.md#connect-to-the-vm). However, if you need an isolated VM without a public address, remove the public IP address specification from the network interface parameters. To access the VM, you can [set up a WireGuard jump server](https://docs.nebius.com/compute/virtual-machines/wireguard.md) later. This approach enhances security and still provides access to the VM within the same subnet. For more information about creating VMs and managing their network parameters, see [How to create a virtual machine in Nebius AI Cloud](https://docs.nebius.com/compute/virtual-machines/manage.md). 1. Create a boot disk: ```python disk_service = DiskServiceClient(sdk) boot_disk_operation = await disk_service.create( CreateDiskRequest( metadata=ResourceMetadata( name="openwebui-disk-1", ), spec=DiskSpec( block_size_bytes=4096, type=DiskSpec.DiskType.NETWORK_SSD, source_image_family=SourceImageFamily( image_family="ubuntu24.04-cuda13.0", ), size_gibibytes=300, ), ), ) await boot_disk_operation.wait() boot_disk_id = boot_disk_operation.resource_id ``` The code creates a 300 GiB SSD disk with a 4 KiB block size and an Ubuntu boot image with pre-installed NVIDIA® GPU drivers. For details about boot disk images, see [Boot disk images for Compute virtual machines](https://docs.nebius.com/compute/storage/boot-disk-images.md). 2. Get the default subnet ID: ```python subnet_service = SubnetServiceClient(sdk) subnets = await subnet_service.list(ListSubnetsRequest()) if not subnets.items: raise ValueError("no subnets found") subnet_id = subnets.items[0].metadata.id ``` 3. Create the VM with one GPU: ```python instance_service = InstanceServiceClient(sdk) host_operation = await instance_service.create( CreateInstanceRequest( metadata=ResourceMetadata(name="openwebui"), spec=InstanceSpec( resources=ResourcesSpec( platform="gpu-h100-sxm", preset="1gpu-16vcpu-200gb", ), boot_disk=AttachedDiskSpec( attach_mode=( AttachedDiskSpec.AttachMode.READ_WRITE ), existing_disk=ExistingDisk(id=boot_disk_id), ), cloud_init_user_data=user_data, network_interfaces=[ NetworkInterfaceSpec( name="default-subnet", subnet_id=subnet_id, ip_address=IPAddress(), public_ip_address=PublicIPAddress(), ), ], ), ), ) await host_operation.wait() ``` The given example assumes that you work with a VM that has a public address, so you can later [connect to this VM by SSH](https://docs.nebius.com/compute/quickstart-host-model.md#connect-to-the-vm). However, if you need an isolated VM without a public address, remove the public IP address specification from the network interface parameters. To access the VM, you can [set up a WireGuard jump server](https://docs.nebius.com/compute/virtual-machines/wireguard.md) later. This approach enhances security and still provides access to the VM within the same subnet. For more information about creating VMs and managing their network parameters, see [How to create a virtual machine in Nebius AI Cloud](https://docs.nebius.com/compute/virtual-machines/manage.md). 1. Create a boot disk: ```ts const diskService = new DiskService(sdk); const bootDiskOperation = await diskService.create( CreateDiskRequest.create({ metadata: ResourceMetadata.create({ name: "openwebui-disk-1", }), spec: DiskSpec.create({ blockSizeBytes: 4096, type: DiskSpec_DiskType.NETWORK_SSD, source: { $case: "sourceImageFamily", sourceImageFamily: SourceImageFamily.create({ imageFamily: "ubuntu24.04-cuda13.0", }), }, size: { $case: "sizeGibibytes", sizeGibibytes: 300, }, }), }), ).result; await bootDiskOperation.wait(); const bootDiskId = bootDiskOperation.resourceId(); ``` The code creates a 300 GiB SSD disk with a 4 KiB block size and an Ubuntu boot image with pre-installed NVIDIA® GPU drivers. For details about boot disk images, see [Boot disk images for Compute virtual machines](https://docs.nebius.com/compute/storage/boot-disk-images.md). 2. Get the default subnet ID: ```ts const subnetService = new SubnetService(sdk); const subnets = await subnetService.list( ListSubnetsRequest.create({}), ); const subnetId = subnets.items[0]?.metadata?.id; if (!subnetId) { throw new Error("no subnets found"); } ``` 3. Create the VM with one GPU: ```ts const instanceService = new InstanceService(sdk); const hostOperation = await instanceService.create( CreateInstanceRequest.create({ metadata: ResourceMetadata.create({ name: "openwebui", }), spec: InstanceSpec.create({ resources: ResourcesSpec.create({ platform: "gpu-h100-sxm", size: { $case: "preset", preset: "1gpu-16vcpu-200gb", }, }), bootDisk: AttachedDiskSpec.create({ attachMode: AttachedDiskSpec_AttachMode.READ_WRITE, type: { $case: "existingDisk", existingDisk: ExistingDisk.create({ id: bootDiskId, }), }, }), cloudInitUserData: userData, networkInterfaces: [ NetworkInterfaceSpec.create({ name: "default-subnet", subnetId, ipAddress: IPAddress.create({}), publicIpAddress: PublicIPAddress.create({}), }), ], }), }), ).result; await hostOperation.wait(); ``` The given example assumes that you work with a VM that has a public address, so you can later [connect to this VM by SSH](https://docs.nebius.com/compute/quickstart-host-model.md#connect-to-the-vm). However, if you need an isolated VM without a public address, remove the public IP address specification from the network interface parameters. To access the VM, you can [set up a WireGuard jump server](https://docs.nebius.com/compute/virtual-machines/wireguard.md) later. This approach enhances security and still provides access to the VM within the same subnet. For more information about creating VMs and managing their network parameters, see [How to create a virtual machine in Nebius AI Cloud](https://docs.nebius.com/compute/virtual-machines/manage.md). ## Connect to the VM 1. Get the public IP address of the VM: 1. Open the VM page. 2. In the **Network** block, copy the **Public IPv4** value. Run the following command: ```bash export PUBLIC_IP_ADDRESS=$(nebius compute instance get-by-name \ --name openwebui \ --format json \ | jq -r '.status.network_interfaces[0].public_ip_address.address | split("/")[0]') ``` ```go publicInstance, err := sdk.Services().Compute().V1(). Instance().GetByName( ctx, &common.GetByNameRequest{ Name: "openwebui", }, ) if err != nil { return err } publicAddress := publicInstance.GetStatus(). GetNetworkInterfaces()[0]. GetPublicIpAddress().GetAddress() publicIPAddress := strings.Split(publicAddress, "/")[0] if publicIPAddress == "" { return fmt.Errorf("public IP address is missing") } ``` ```python public_ip_service = InstanceServiceClient(sdk) public_instance = await public_ip_service.get_by_name( GetByNameRequest(name="openwebui"), ) public_address = ( public_instance.status.network_interfaces[0] .public_ip_address.address ) public_ip_address = public_address.split("/")[0] ``` ```ts const publicIpService = new InstanceService(sdk); const publicInstance = await publicIpService.getByName( GetByNameRequest.create({ name: "openwebui", }), ); const publicAddress = publicInstance.status ?.networkInterfaces[0]?.publicIpAddress?.address; const publicIpAddress = publicAddress?.split("/")[0]; if (!publicIpAddress) { throw new Error("public IP address is missing"); } ``` 2. Connect to the VM: ```bash ssh @ ``` Specify the received public IP address and the username that you set during the VM creation. ## Create a virtual environment and install the necessary packages To work with Open WebUI, you need a dedicated [virtual environment](https://docs.python.org/3/tutorial/venv.html). It enables you to set up and run the OpenWebUI server in isolation from other software on the VM. To create a virtual environment, use [Miniconda](https://docs.anaconda.com/miniconda/). To configure the environment: 1. Download and install the latest Miniconda version: ```bash mkdir -p ~/miniconda3 wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh -O ~/miniconda3/miniconda.sh bash ~/miniconda3/miniconda.sh -b -u -p ~/miniconda3 rm ~/miniconda3/miniconda.sh ``` 2. Initialize Miniconda: ```bash source ~/miniconda3/bin/activate ``` On initialization, Miniconda activates its `base` environment. 3. Create an `OpenWebUI` environment with Python 3.11: ```bash conda create -n OpenWebUI python=3.11 conda init bash echo "conda activate OpenWebUI " >> ~/.bashrc source ~/.bashrc ``` This command creates and activates a new environment. 4. Install [Ollama](https://ollama.com/), which provides access to the model: ```bash curl -fsSL https://ollama.com/install.sh | sh ``` 5. Install Open WebUI: ```bash pip install open-webui ``` ## Start the Open WebUI server 1. Start the server: ```bash open-webui serve ``` 2. Open the Open WebUI interface in the browser. To do this, enter the `http://:8080` address in the search bar. 3. In the Open WebUI interface, create an account to work with LLMs locally within the VM. For details on working with Open WebUI, see [their documentation](https://docs.openwebui.com/). If you need to restart the server, use the same command: `open-webui serve`. ## Download the Qwen/Qwen2.5-72B-Instruct model 1. In Open WebUI, click **Select a model**. 2. Paste `qwen2.5:72b` into the search bar. 3. Click **Pull "qwen2.5:72b" from Ollama** and wait for the download to finish. 4. Click **Select a model** again and then choose Qwen/Qwen2.5-72B-Instruct. Now you can chat with the model in the browser. ## Make Open WebUI start automatically With the current configuration, you need to manually start the Open WebUI server every time you connect to your VM. Alternatively, you can configure the server to start up whenever the VM starts. To do this: 1. Create a `systemd` service file for Open WebUI and open the file in an editor: ```bash sudo nano /etc/systemd/system/openwebui.service ``` 2. Paste the following contents into the file and save it. Specify the username that you set during the VM creation: ```ini [Unit] Description=OpenWebUI Server After=network.target [Service] User= WorkingDirectory=/home// ExecStart=/home//miniconda3/envs/OpenWebUI/bin/open-webui serve Restart=always [Install] WantedBy=multi-user.target ``` 3. To make the new service file recognizable, reload `systemd`: ```bash sudo systemctl daemon-reload ``` 4. To start automatically and immediately, enable the `systemd` service: ```bash sudo systemctl enable openwebui.service sudo systemctl start openwebui.service ``` 5. Verify that the service is running: ```bash sudo systemctl status openwebui.service ``` Whenever you start up your VM in the web console, Open WebUI now automatically launches in the background. You can directly access it in the browser at `http://ip_address:8080` and work with the Qwen/Qwen2.5-72B-Instruct model. # Types of virtual machines and GPUs in Nebius AI Cloud Source: https://docs.nebius.com/compute/virtual-machines/types.md Compute offers the following platforms for virtual machines (VMs) ([private regions](https://docs.nebius.com/overview/regions.md) are marked with \*): | Platform name | Platform ID | CPU | [Regions](https://docs.nebius.com/overview/regions.md) | | ----------------------------------------------- | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | NVIDIA® B300 NVLink with Intel Granite Rapids | gpu-b300-sxm | [Intel Xeon 6776P](https://www.intel.com/content/www/us/en/products/sku/243691/intel-xeon-6776p-processor-336m-cache-2-30-ghz/specifications.html) | `uk-south1`, `eu-west2`*\** | | NVIDIA® B200 NVLink with Intel Emerald Rapids | gpu-b200-sxm | [Intel Xeon Platinum 8580](https://www.intel.com/content/www/us/en/products/sku/237250/intel-xeon-platinum-8580-processor-300m-cache-2-00-ghz/specifications.html) | `us-central1` | | NVIDIA® B200 NVLink with Intel Emerald Rapids | gpu-b200-sxm-a | [Intel Xeon Platinum 8570](https://www.intel.com/content/www/us/en/products/sku/237264/intel-xeon-platinum-8570-processor-300m-cache-2-10-ghz/specifications.html) | `me-west1` | | NVIDIA® RTX PRO™ 6000 with Intel Granite Rapids | gpu-rtx6000 | [Intel Xeon 6776P](https://www.intel.com/content/www/us/en/products/sku/243691/intel-xeon-6776p-processor-336m-cache-2-30-ghz/specifications.html) | `us-central1` | | NVIDIA® H200 NVLink with Intel Sapphire Rapids | gpu-h200-sxm | [Intel Xeon Platinum 8468](https://ark.intel.com/content/www/us/en/ark/products/231735/intel-xeon-platinum-8468-processor-105m-cache-2-10-ghz.html) | `eu-north1`, `eu-north2`*\**, `eu-west1`, `us-central1` | | NVIDIA® H100 NVLink with Intel Sapphire Rapids | gpu-h100-sxm | [Intel Xeon Platinum 8468](https://ark.intel.com/content/www/us/en/ark/products/231735/intel-xeon-platinum-8468-processor-105m-cache-2-10-ghz.html) | `eu-north1` | | NVIDIA® L40S PCIe with Intel Ice Lake | gpu-l40s-a | [Intel Xeon Gold 6338](https://ark.intel.com/content/www/us/en/ark/products/212285/intel-xeon-gold-6338-processor-48m-cache-2-00-ghz.html) | `eu-north1` | | NVIDIA® L40S PCIe with AMD EPYC Genoa | gpu-l40s-d | [AMD EPYC™ 9654](https://www.amd.com/en/products/processors/server/epyc/4th-generation-9004-and-8004-series/amd-epyc-9654.html) | `eu-north1` | | Non-GPU AMD EPYC Genoa | cpu-d3 | [AMD EPYC™ 9654](https://www.amd.com/en/products/processors/server/epyc/4th-generation-9004-and-8004-series/amd-epyc-9654.html) | `eu-north1`, `eu-west1`, `me-west1`, `us-central1`;
`eu-north2`*\**, `uk-south1`*\** | | Non-GPU Intel Ice Lake | cpu-e2 | [Intel Xeon Gold 6338](https://ark.intel.com/content/www/us/en/ark/products/212285/intel-xeon-gold-6338-processor-48m-cache-2-00-ghz.html) | `eu-north1` | Each platform offers different *presets* for creating VMs. The presets vary by the number of GPUs (for platforms with GPUs), vCPUs and RAM size. The exact amount of these resources is indicated in the preset name. Thus, `1gpu-16vcpu-200gb` preset stands for a VM with 1 GPU, 16 vCPUs and 200 Nebius uses binary units. For example, a gibibyte (GiB) is 230 (10243) bytes.}>GiB RAM. Availability of platforms depends on a region and project. You can [get a list](https://docs.nebius.com/compute/virtual-machines/list-platforms.md) of platforms and presets supported in a given project. For VM platforms with GPUs, you can also use the [capacity advisor](https://docs.nebius.com/compute/virtual-machines/capacity-advisor.md) to get information about the availability of computing resources based on your quotas and the current physical capacity. ## GPU types Compute provides VMs with the following GPU types: | GPU | Architecture | Form factor | GPU memory | Memory bandwidth | InfiniBand interconnect | Network adapter | Platform | CPU | | --------------------------------------------------------------------------------------------------------------------- | --------------- | ----------- | ------------ | ---------------- | ------------------------ | -------------------- | -------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | [NVIDIA B300](https://www.nvidia.com/en-us/data-center/dgx-b300/) | Blackwell Ultra | SXM | 288 GB HBM3e | 10 TB/s | 800 Gbps (8× ConnectX-8) | BlueField-3 400 Gbps | `gpu-b300-sxm` | [Intel Xeon 6776P](https://www.intel.com/content/www/us/en/products/sku/243691/intel-xeon-6776p-processor-336m-cache-2-30-ghz/specifications.html) | | [NVIDIA B200](https://www.nvidia.com/en-us/data-center/dgx-b200/) | Blackwell | SXM | 180 GB HBM3e | 8 TB/s | 400 Gbps (8× ConnectX-7) | BlueField-3 400 Gbps | `gpu-b200-sxm`, `gpu-b200-sxm-a` | [Intel Xeon Platinum 8580](https://www.intel.com/content/www/us/en/products/sku/237250/intel-xeon-platinum-8580-processor-300m-cache-2-00-ghz/specifications.html), [Intel Xeon Platinum 8570](https://www.intel.com/content/www/us/en/products/sku/237264/intel-xeon-platinum-8570-processor-300m-cache-2-10-ghz/specifications.html) | | [NVIDIA RTX PRO 6000 Server Edition](https://www.nvidia.com/en-us/data-center/rtx-pro-6000-blackwell-server-edition/) | Blackwell | PCIe Gen5 | 96 GB GDDR7 | 1.6 TB/s | — | BlueField-3 400 Gbps | `gpu-rtx6000` | [Intel Xeon 6776P](https://www.intel.com/content/www/us/en/products/sku/243691/intel-xeon-6776p-processor-336m-cache-2-30-ghz/specifications.html) | | [NVIDIA H200](https://www.nvidia.com/en-us/data-center/h200/) | Hopper | SXM | 141 GB HBM3e | 4.8 TB/s | 400 Gbps (8× ConnectX-7) | BlueField-3 200 Gbps | `gpu-h200-sxm` | [Intel Xeon Platinum 8468](https://ark.intel.com/content/www/us/en/ark/products/231735/intel-xeon-platinum-8468-processor-105m-cache-2-10-ghz.html) | | [NVIDIA H100](https://www.nvidia.com/en-us/data-center/h100/) | Hopper | SXM | 80 GB HBM3 | 3.35 TB/s | 400 Gbps (8× ConnectX-7) | ConnectX-6 100 Gbps | `gpu-h100-sxm` | [Intel Xeon Platinum 8468](https://ark.intel.com/content/www/us/en/ark/products/231735/intel-xeon-platinum-8468-processor-105m-cache-2-10-ghz.html) | | [NVIDIA L40S](https://www.nvidia.com/en-us/data-center/l40s/) | Ada Lovelace | PCIe | 48 GB GDDR6 | 864 GB/s | — | — | `gpu-l40s-a`, `gpu-l40s-d` | [Intel Xeon Gold 6338](https://ark.intel.com/content/www/us/en/ark/products/212285/intel-xeon-gold-6338-processor-48m-cache-2-00-ghz.html), [AMD EPYC™ 9654](https://www.amd.com/en/products/processors/server/epyc/4th-generation-9004-and-8004-series/amd-epyc-9654.html) | ## Presets for GPU platforms * NVIDIA® B300 NVLink with Intel Granite Rapids (gpu-b300-sxm), available in uk-south1 and eu-west2*\**: | Preset name | Number of GPUs | Number of vCPUs | RAM, Nebius uses binary units. For example, a gibibyte (GiB) is 230 (10243) bytes.}>GiB | | --------------------- | -------------- | --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | | `1gpu-24vcpu-346gb` | 1 | 24 | 346 | | `8gpu-192vcpu-2768gb` | 8 | 192 | 2768 | * NVIDIA® B200 NVLink with Intel Emerald Rapids (gpu-b200-sxm and gpu-b200-sxm-a), available in us-central1 and me-west1 respectively: | Preset name | Number of GPUs | Number of vCPUs | RAM, GiB | | --------------------- | -------------- | --------------- | -------- | | `1gpu-20vcpu-224gb` | 1 | 20 | 224 | | `8gpu-160vcpu-1792gb` | 8 | 160 | 1792 | * NVIDIA® H200 NVLink with Intel Sapphire Rapids (gpu-h200-sxm), available in eu-north1, eu-north2*\**, eu-west1 and us-central1: | Preset name | Number of GPUs | Number of vCPUs | RAM, GiB | [Regions](https://docs.nebius.com/overview/regions.md) | | --------------------- | -------------- | --------------- | -------- | ----------------------------------------------------------------------------------------------- | | `1gpu-16vcpu-200gb` | 1 | 16 | 200 | eu-north1, eu-west1, us-central1, eu-north2 | | `8gpu-128vcpu-1600gb` | 8 | 128 | 1600 | eu-north1, eu-west1, us-central1, eu-north2 | * NVIDIA® H100 NVLink with Intel Sapphire Rapids (gpu-h100-sxm), available in eu-north1: | Preset name | Number of GPUs | Number of vCPUs | RAM, GiB | | --------------------- | -------------- | --------------- | -------- | | `1gpu-16vcpu-200gb` | 1 | 16 | 200 | | `8gpu-128vcpu-1600gb` | 8 | 128 | 1600 | * NVIDIA® RTX PRO™ 6000 with Intel Granite Rapids (gpu-rtx6000), available in us-central1: | Preset name | Number of GPUs | Number of vCPUs | RAM, GiB | | --------------------- | -------------- | --------------- | -------- | | `1gpu-24vcpu-218gb` | 1 | 24 | 218 | | `8gpu-192vcpu-1744gb` | 8 | 192 | 1744 | * NVIDIA® L40S PCIe with Intel Ice Lake (gpu-l40s-a), available in eu-north1: | Preset name | Number of GPUs | Number of vCPUs | RAM, GiB | | ------------------- | -------------- | --------------- | -------- | | `1gpu-8vcpu-32gb` | 1 | 8 | 32 | | `1gpu-16vcpu-64gb` | 1 | 16 | 64 | | `1gpu-24vcpu-96gb` | 1 | 24 | 96 | | `1gpu-32vcpu-128gb` | 1 | 32 | 128 | | `1gpu-40vcpu-160gb` | 1 | 40 | 160 | * NVIDIA® L40S PCIe with AMD EPYC Genoa (gpu-l40s-d), available in eu-north1: | Preset name | Number of GPUs | Number of vCPUs | RAM, GiB | | --------------------- | -------------- | --------------- | -------- | | `1gpu-16vcpu-96gb` | 1 | 16 | 96 | | `1gpu-32vcpu-192gb` | 1 | 32 | 192 | | `1gpu-48vcpu-288gb` | 1 | 48 | 288 | | `2gpu-64vcpu-384gb` | 2 | 64 | 384 | | `2gpu-96vcpu-576gb` | 2 | 96 | 576 | | `4gpu-128vcpu-768gb` | 4 | 128 | 768 | | `4gpu-192vcpu-1152gb` | 4 | 192 | 1152 | ### Presets compatible with GPU clusters If you are adding a VM to a [GPU cluster](https://docs.nebius.com/compute/clusters/gpu/index.md), select from the following platforms and presets: | Platform | Presets | [Regions](https://docs.nebius.com/overview/regions.md) | | ----------------------------------------------------------------------- | --------------------- | ------------------------------------------------------------------------------------------------------------------------ | | NVIDIA® B300 NVLink with Intel Granite Rapids
(`gpu-b300-sxm`) | `8gpu-192vcpu-2768gb` | `uk-south1`, `eu-west2`*\** | | NVIDIA® B200 NVLink with Intel Emerald Rapids
(`gpu-b200-sxm`) | `8gpu-160vcpu-1792gb` | `us-central1` | | NVIDIA® B200 NVLink with Intel Emerald Rapids
(`gpu-b200-sxm-a`) | `8gpu-160vcpu-1792gb` | `me-west1` | | NVIDIA® H200 NVLink with Intel Sapphire Rapids
(`gpu-h200-sxm`) | `8gpu-128vcpu-1600gb` | `eu-north1`, `eu-north2`*\**, `eu-west1`, `us-central1` | | NVIDIA® H100 NVLink with Intel Sapphire Rapids
(`gpu-h100-sxm`) | `8gpu-128vcpu-1600gb` | `eu-north1` | Other presets and platforms are not compatible with GPU clusters. ## Presets for non-GPU platforms * Non-GPU AMD EPYC Genoa (cpu-d3): | Preset name | Number of vCPUs | RAM, GiB | [Regions](https://docs.nebius.com/overview/regions.md) | | ---------------- | --------------- | -------- | ----------------------------------------- | | `4vcpu-16gb` | 4 | 16 | All regions | | `8vcpu-32gb` | 8 | 32 | All regions | | `16vcpu-64gb` | 16 | 64 | All regions | | `32vcpu-128gb` | 32 | 128 | All regions | | `48vcpu-192gb` | 48 | 192 | All regions | | `64vcpu-256gb` | 64 | 256 | All regions | | `96vcpu-384gb` | 96 | 384 | All regions | | `128vcpu-512gb` | 128 | 512 | All regions | | `160vcpu-640gb` | 160 | 640 | All regions except eu-north1 | | `192vcpu-768gb` | 192 | 768 | All regions except eu-north1 | | `224vcpu-896gb` | 224 | 896 | All regions except eu-north1 | | `256vcpu-1024gb` | 256 | 1024 | All regions except eu-north1 | * Non-GPU Intel Ice Lake (cpu-e2), available in eu-north1: | Preset name | Number of vCPUs | RAM, GiB | | -------------- | --------------- | -------- | | `2vcpu-8gb` | 2 | 8 | | `4vcpu-16gb` | 4 | 16 | | `8vcpu-32gb` | 8 | 32 | | `16vcpu-64gb` | 16 | 64 | | `32vcpu-128gb` | 32 | 128 | | `48vcpu-192gb` | 48 | 192 | | `64vcpu-256gb` | 64 | 256 | | `80vcpu-320gb` | 80 | 320 | ## Compatibility with boot disk images Nebius AI Cloud provides boot disk images for GPU and non-GPU VMs. The image that you choose for a VM must be compatible with the VM's platform. For compatibility details, see [Boot disk images for Compute virtual machines](https://docs.nebius.com/compute/storage/boot-disk-images.md). ## Compatibility with VM types All platforms support regular VMs. All platforms with GPUs also support [preemptible VMs](https://docs.nebius.com/compute/virtual-machines/preemptible.md). To get an up-to-date list of platforms, run the `nebius compute platform list` [command](https://docs.nebius.com/cli/reference/compute/platform/list). The platforms available for preemptible VMs are marked as `allowed_for_preemptibles: true`. # How to find out platforms and presets available in a project Source: https://docs.nebius.com/compute/virtual-machines/list-platforms.md Different virtual machine platforms and presets are available for different regions and projects. All supported platforms and presets are listed in [Types of virtual machines and GPUs in Nebius AI Cloud](https://docs.nebius.com/compute/virtual-machines/types.md). ## Prerequisites [Install and configure](https://docs.nebius.com/cli/install.md) the Nebius AI Cloud CLI. [Install and initialize the Nebius SDK for Go](https://docs.nebius.com/grpc-api/sdk/go.md). [Install and initialize the Nebius SDK for Python](https://docs.nebius.com/grpc-api/sdk/python.md). [Install and initialize the Nebius SDK for JavaScript](https://docs.nebius.com/grpc-api/sdk/javascript.md). ## How to find out available platforms and presets To find out what platforms and presets are available in a given project: Run the following command: ```bash nebius compute platform list --parent-id ``` In the `--parent-id` parameter, specify the ID of the project for which you want to see the list. ```go platforms, err := sdk.Services().Compute().V1(). Platform().List( ctx, &compute.ListPlatformsRequest{ ParentId: "", }, ) if err != nil { return err } fmt.Println(platforms) ``` In the `ParentId` parameter, specify the ID of the project for which you want to see the list. ```python platform_service = PlatformServiceClient(sdk) platforms = await platform_service.list( ListPlatformsRequest(parent_id=""), ) print(platforms) ``` In the `parent_id` parameter, specify the ID of the project for which you want to see the list. ```ts const platformService = new PlatformService(sdk); const platforms = await platformService.list( ListPlatformsRequest.create({ parentId: "", }), ); console.log(platforms); ``` In the `parentId` parameter, specify the ID of the project for which you want to see the list. # How to create a virtual machine in Nebius AI Cloud Source: https://docs.nebius.com/compute/virtual-machines/manage.md You can create a Compute virtual machine (VM) in the [web console](https://console.nebius.com), or by using the [CLI](https://docs.nebius.com/cli/index.md), [Terraform provider](https://docs.nebius.com/terraform-provider/index.md) or SDKs. You can tailor the VM configuration to your needs and, for example, attach secondary disks and filesystems, or allocate GPU resources to your VM. ## Prerequisites If you use the web console, you don't need to complete any prerequisites. [Install and configure](https://docs.nebius.com/cli/install.md) the Nebius AI Cloud CLI. [Install and configure](https://docs.nebius.com/terraform-provider/install.md) the Nebius AI Cloud provider for Terraform. [Install and initialize the Nebius SDK for Go](https://docs.nebius.com/grpc-api/sdk/go.md). [Install and initialize the Nebius SDK for Python](https://docs.nebius.com/grpc-api/sdk/python.md). [Install and initialize the Nebius SDK for JavaScript](https://docs.nebius.com/grpc-api/sdk/javascript.md). The VM that you create this way is a *standalone VM*, which is a general-purpose Compute resource. In the [web console](https://console.nebius.com), standalone VMs are displayed on the **Standalone VMs** tab of the **Virtual machines** page. Other Compute resources, such as [container VMs](https://docs.nebius.com/compute/virtual-machines/containers.md), [Managed Service for Kubernetes®](https://docs.nebius.com/kubernetes/index.md) nodes or [Serverless AI](https://docs.nebius.com/serverless/index.md) job and endpoint VMs, are displayed on separate tabs. A standalone VM can be regular or [preemptible](https://docs.nebius.com/compute/virtual-machines/preemptible.md): regular VMs run until you stop them, while Compute may stop preemptible VMs at any time. ## Steps ### (Optional) Create a user data configuration You do not need to create a user data configuration in advance if you create a VM in the web console. To add a user for connections to a VM, create a configuration by using the [cloud-init](https://cloudinit.readthedocs.io/en/latest/reference/modules.html#users-and-groups) format: ```bash export USER_DATA=$(jq -Rrs '.' < 1. To add a user for connections to a VM, create a configuration by using the [cloud-init](https://cloudinit.readthedocs.io/en/latest/reference/modules.html#users-and-groups) format: ```bash export USER_DATA=$(jq -Rrs '.' < sudo: ALL=(ALL) NOPASSWD:ALL shell: /bin/bash ssh_authorized_keys: - ``` 4. Create the `variables.tf` file with the following contents: ```hcl variable "user_data" { description = "User data in the cloud-init format" type = string } ``` The file allows the Terraform provider to address the `TF_VAR_user_data` environment variable. 5. Initialize the working directory: ```bash terraform init ``` To add a user for connections to a VM, define `userData` as a string in the [cloud-init](https://cloudinit.readthedocs.io/en/latest/reference/modules.html#users-and-groups) format. ```go publicKeyBytes, err := os.ReadFile( os.ExpandEnv("$HOME/.ssh/id_ed25519.pub"), ) if err != nil { return err } publicKey := strings.TrimSpace(string(publicKeyBytes)) userData := "#cloud-config\nusers:\n" + " - name: user\n" + " sudo: ALL=(ALL) NOPASSWD:ALL\n" + " shell: /bin/bash\n" + " ssh_authorized_keys:\n" + " - " + publicKey ``` The configuration contains the following parameters: * `name`: Username for connecting to the VM. The example sets `user`; replace it with your username. Do not use the `root` or `admin` usernames. They are reserved for internal needs and are not allowed to connect to a VM by SSH. * `sudo`: Sudo policy. `ALL=(ALL) NOPASSWD:ALL` allows users unrestricted sudo access; `False` disables sudo access for users. * `shell`: Default shell. * `ssh_authorized_keys`: User's authorized keys. Allows configuring SSH access to the VM. To create the key pair, follow the instructions in [Generating SSH keys](https://docs.nebius.com/compute/virtual-machines/ssh-keys.md). You can specify several users and their public SSH keys. For more information, see [cloud-init configuration examples](https://cloudinit.readthedocs.io/en/latest/reference/examples.html). When you create the VM, pass this string to `InstanceSpec.CloudInitUserData`. The VM applies this configuration on first boot. To add a user for connections to a VM, define `user_data` as a string in the [cloud-init](https://cloudinit.readthedocs.io/en/latest/reference/modules.html#users-and-groups) format. ```python public_key = ( Path.home() .joinpath(".ssh/id_ed25519.pub") .read_text() .strip() ) user_data = "\n".join( [ "#cloud-config", "users:", " - name: user", " sudo: ALL=(ALL) NOPASSWD:ALL", " shell: /bin/bash", " ssh_authorized_keys:", f" - {public_key}", ], ) ``` The configuration contains the following parameters: * `name`: Username for connecting to the VM. The example sets `user`; replace it with your username. Do not use the `root` or `admin` usernames. They are reserved for internal needs and are not allowed to connect to a VM by SSH. * `sudo`: Sudo policy. `ALL=(ALL) NOPASSWD:ALL` allows users unrestricted sudo access; `False` disables sudo access for users. * `shell`: Default shell. * `ssh_authorized_keys`: User's authorized keys. Allows configuring SSH access to the VM. To create the key pair, follow the instructions in [Generating SSH keys](https://docs.nebius.com/compute/virtual-machines/ssh-keys.md). You can specify several users and their public SSH keys. For more information, see [cloud-init configuration examples](https://cloudinit.readthedocs.io/en/latest/reference/examples.html). When you create the VM, pass this string to `InstanceSpec.cloud_init_user_data`. The VM applies this configuration on first boot. To add a user for connections to a VM, define `userData` as a string in the [cloud-init](https://cloudinit.readthedocs.io/en/latest/reference/modules.html#users-and-groups) format. ```ts const publicKey = readFileSync( `${process.env.HOME}/.ssh/id_ed25519.pub`, "utf8", ).trim(); const userData = [ "#cloud-config", "users:", " - name: user", " sudo: ALL=(ALL) NOPASSWD:ALL", " shell: /bin/bash", " ssh_authorized_keys:", " - " + publicKey, ].join("\n"); ``` The configuration contains the following parameters: * `name`: Username for connecting to the VM. The example sets `user`; replace it with your username. Do not use the `root` or `admin` usernames. They are reserved for internal needs and are not allowed to connect to a VM by SSH. * `sudo`: Sudo policy. `ALL=(ALL) NOPASSWD:ALL` allows users unrestricted sudo access; `False` disables sudo access for users. * `shell`: Default shell. * `ssh_authorized_keys`: User's authorized keys. Allows configuring SSH access to the VM. To create the key pair, follow the instructions in [Generating SSH keys](https://docs.nebius.com/compute/virtual-machines/ssh-keys.md). You can specify several users and their public SSH keys. For more information, see [cloud-init configuration examples](https://cloudinit.readthedocs.io/en/latest/reference/examples.html). When you create the VM, pass this string to `InstanceSpec.cloudInitUserData`. The VM applies this configuration on first boot. ### Create a VM 1. In the sidebar, go to  **Compute** → **Virtual machines**. 2. Click **Create resource** → **Virtual machine**. The creation flow is a step-by-step wizard. The sidebar shows your progress through the configuration sections. To move between sections, click **Back** and **Next**. 3. If you have [capacity block groups](https://docs.nebius.com/overview/limits/capacity-block-groups.md), on the **General** step, choose how Compute allocates resources: * **Reserved VM**: Capacity is assured by your capacity block groups. This option is for regular VMs with GPUs. If you have active capacity block groups, the card shows how many are available. * **Pay-as-you-go VM**: Capacity is subject to availability. This option allows [preemptible VMs](https://docs.nebius.com/compute/virtual-machines/preemptible.md) and VMs without GPUs. If you do not have capacity block groups, the wizard skips the **General** step and opens **Compute** instead. 4. On the **Compute** step, configure computing resources: **Reserved VM:** 1. In the **Platform** section, select a [platform](https://docs.nebius.com/compute/virtual-machines/types.md). The list shows platforms that match your capacity block groups. Each platform card shows GPU memory, the platform ID and badges for associated capacity block groups. 2. In the **Reservation** section, configure how Compute uses your [reservations](https://docs.nebius.com/compute/virtual-machines/reservations.md). The **Reservation** section is only displayed if you have capacity block groups. 1. If you have capacity block groups in multiple regions, select a **Region**. 2. To let Compute choose among your capacity block groups automatically, select **Any (existing and future)**. 3. To use specific capacity block groups, select them. Each option shows the capacity block group ID, reservation period and GPU usage. 4. Under **Switch to PAYG**, choose whether the VM can start after you create or restart it without active intervals in selected capacity block groups: * **When reservation is exhausted**: The VM can start as a pay-as-you-go VM when no capacity is available in the selected capacity block groups. * **Never**: The VM cannot start without available capacity in the selected capacity block groups. This does not affect the VM when it is running. If an interval in a selected capacity block group expires while the VM is running, the VM always continues as a pay-as-you-go VM, regardless of this setting. 3. In the **Settings** section, configure the following: 1. Select a **Preset**. 2. (Optional) If you create a VM with 8 GPUs (for example, for training models), use a **GPU cluster** for the VM. InfiniBand™ in the cluster allows you to accelerate tasks that require high-performance computing (HPC) power. A single VM without InfiniBand™ cannot perform these tasks as quickly. To use a GPU cluster, select an existing one or create a new cluster: 1. Click  **Create** in the **GPU cluster** field. 2. In the window that opens, specify the cluster name and InfiniBand fabric. To select the fabric, see [InfiniBand fabrics](https://docs.nebius.com/compute/clusters/gpu/index.md#infiniband-fabrics). 3. Click **Create**. 3. Select the **Project** for the VM location. 4. Specify the **VM name**. **Pay-as-you-go VM:** 1. At the top of the platform list, select **With GPUs** or **Without GPUs** and the VM type **Regular** or [Preemptible](https://docs.nebius.com/compute/virtual-machines/preemptible.md). VMs without GPUs only support the regular type. 2. Select a [platform and preset](https://docs.nebius.com/compute/virtual-machines/types.md). Expand a platform card to compare available presets by region. You can also see the platforms that are not currently available. 3. In the **Settings** section, configure the following: 1. Select a **Preset**. 2. (Optional) If you create a VM with 8 GPUs (for example, for training models), use a **GPU cluster** for the VM. InfiniBand™ in the cluster allows you to accelerate tasks that require high-performance computing (HPC) power. A single VM without InfiniBand™ cannot perform these tasks as quickly. To use a GPU cluster, select an existing one or create a new cluster: 1. Click  **Create** in the **GPU cluster** field. 2. In the window that opens, specify the cluster name and InfiniBand fabric. To select the fabric, see [InfiniBand fabrics](https://docs.nebius.com/compute/clusters/gpu/index.md#infiniband-fabrics). 3. Click **Create**. 3. Select the **Project** for the VM location. 4. Specify the **VM name**. To check GPU availability across regions and presets before you create a VM, use the [capacity advisor](https://docs.nebius.com/compute/virtual-machines/capacity-advisor.md). 5. On the **Storage** step, configure disks and filesystems: 1. In the **Boot disk** section, set the boot disk settings: 1. Click  on the boot disk card. 2. In the window that opens, select an existing disk or create a new one. 3. If you create a new boot disk, choose an operating system image: either a [public image](https://docs.nebius.com/compute/storage/boot-disk-images.md) provided by Nebius or a [custom image or image family](https://docs.nebius.com/compute/storage/custom-disk-images.md) that you created yourself. Also, configure the type, encryption, size and block size. For more information about these settings, see [Volume parameters](https://docs.nebius.com/compute/storage/manage.md#volume-parameters). 2. (Optional) If you want to attach an additional disk to your VM, in the **Additional disks** section: 1. Click  **Attach disk**. 2. In the window that opens, select an existing secondary disk or create a new one. 3. If you create a new disk, specify its name and configure the type, encryption, size and block size. 4. Click **Attach disk**. After you create the VM, [mount the additional disks](https://docs.nebius.com/compute/storage/use.md#how-to-mount-volumes-to-vms) to it. Otherwise, the VM's operating system does not recognize these disks. 3. (Optional) If the selected platform supports local SSD disks, enable **Local SSD disks** to add ephemeral local storage. Local SSD disks are available only for supported platforms and presets. For details, see [Availability](https://docs.nebius.com/compute/storage/local-disks.md#availability). 4. (Optional) If you want to attach a filesystem to your VM, in the **Shared filesystems** section: 1. Click  **Attach shared filesystem**. 2. In the window that opens, select an existing filesystem or create a new one. 3. If you create a new filesystem, specify its name, size and the block size. 4. Click **Attach filesystem**. 5. After the window is closed, specify a mount tag for mounting the filesystem to the VM. Create your own tag, such as `my-filesystem`. Make sure that it is unique within the VM. 6. To mount the filesystem to the VM automatically, keep the **Auto mount** option enabled. 6. On the **Network** step, attach the VM to a [network and subnet](https://docs.nebius.com/vpc/overview.md): 1. Select the **Network** and **Subnet**. 2. In the **Primary private IP address** field, select whether to automatically assign a private IP address or select an already allocated one. For more information, see [Private IP addresses](https://docs.nebius.com/compute/virtual-machines/network.md#private-ip-addresses). 3. (Optional) In the **Secondary private IP address** field, assign secondary addresses. Use them as a backup option in case of incidents. For example, a backup node can take a secondary address of the main node when the main one fails. As a result, routing to this address can be preserved. After you click  **Add IP address**, you can specify a new address or select an already created allocation. You can assign no more than five secondary addresses. 4. In the **Public IP address** field, specify whether the VM should have a public address and whether this address should be dynamic, static or taken from an allocation. If you need to secure your VM and make it isolated, you can create a VM without a public IP address. If you need to connect to this VM from the internet, you can [set up a WireGuard jump server](https://docs.nebius.com/compute/virtual-machines/wireguard.md). It has an IP address in the internet and an IP address in the VM's network. As a result, you can access the VM via the jump server from the internet. This approach enhances security and still provides access to the VM. For more information, see [How to enable a public IP address for a VM](https://docs.nebius.com/compute/virtual-machines/network.md#how-to-enable-a-public-ip-address-for-a-vm). 5. In the **Hostname** field, specify whether to use the VM ID or a custom hostname for the VM's [FQDN](https://docs.nebius.com/compute/virtual-machines/fqdn.md): * **Same as VM ID**: The default FQDN uses the VM ID. * **Custom**: Specify your own hostname. 7. On the **Configuration** step, configure access, identity and VM startup settings: 1. In the **Access** section, add credentials so you can [connect to the VM](https://docs.nebius.com/compute/virtual-machines/connect.md): 1. Generate an [SSH key pair](https://docs.nebius.com/compute/virtual-machines/ssh-keys.md). 2. In the **Username and SSH key** field, click  **Create**. 3. In the window that opens, specify the username of the VM user, a public key of your SSH key pair and the credentials name to recognize the key in the list. Do not use the `root` or `admin` usernames. They are reserved for internal needs and are not allowed to connect to a VM by SSH. 4. Click **Add credentials**. 2. (Optional) In the **Additional** section, select an existing service account or click  **Create** to add a new one. The service account will perform actions on behalf of the VM, for example, run scripts. 3. (Optional) In the **User data** section, select **Enable custom cloud-init config** and set a configuration in the [cloud-init](https://cloudinit.readthedocs.io/en/latest/reference/modules.html#users-and-groups) format. This configuration affects the settings for shared filesystems and access that you set up earlier: * If you add a cloud-init configuration, you cannot manage the **Auto mount** option for filesystems. Their mounting settings automatically appear in the configuration. * The username and SSH key that you specify on the **Configuration** step are automatically added to a cloud-init configuration if you enable it. Ultimately, the settings from the configuration apply, not those from the **Configuration** step. The default configuration that only adds the user contains the following parameters: * `name`: Username for connecting to the VM. The above example sets the value of your machine's `USER` environment variable as the username for the VM. * `sudo`: Sudo policy. `ALL=(ALL) NOPASSWD:ALL` allows users unrestricted sudo access; `False` disables sudo access for users. * `shell`: Default shell. * `ssh_authorized_keys`: User's authorized keys. Allows configuring SSH access to the VM. You can specify several users and their public SSH keys. For more information, see [cloud-init configuration examples](https://cloudinit.readthedocs.io/en/latest/reference/examples.html). 8. On the **Review** step, check the full VM configuration. To change a section quickly, click  next to the corresponding block. The wizard opens the relevant step with your current settings. 9. Click **Create VM**. 1. (Optional) If you want to attach a filesystem to your VM, create this filesystem: ```bash nebius compute filesystem create \ --name \ --size-gibibytes 10 \ --type network_ssd \ --block-size-bytes 4096 ``` Save the filesystem ID from the output `metadata.id` parameter. For more information about filesystem creation, see [Managing Compute volumes](https://docs.nebius.com/compute/storage/manage.md). You don't need to create disks for the VM in advance. You can create them along with the VM. Such disks are called [VM-managed](https://docs.nebius.com/compute/storage/types.md#vm-managed-and-standalone-disks). They are tied to the VM lifecycle. 2. (Optional) To provide the VM with an [allocation](https://docs.nebius.com/vpc/overview.md#allocation) that reserves a static public IP address, create this allocation. As a result, the address is preserved even if you delete the VM. 1. [Get the required subnet ID](https://docs.nebius.com/vpc/networking/resources.md#how-to-get-a-subnet-id). 2. Run the following command: ```bash nebius vpc allocation create \ --ipv4-public-subnet-id \ --name ``` Save the allocation ID from the output `metadata.id` parameter. For more information about networking in Compute, see [Public IP addresses](https://docs.nebius.com/compute/virtual-machines/network.md#public-ip-addresses). 3. (Optional) If you create a VM with 8 GPUs (for example, for training models), use a GPU cluster for the VM. InfiniBand™ in the cluster allows you to accelerate tasks that require high-performance computing (HPC) power. A single VM without InfiniBand™ cannot perform these tasks as quickly. To create a GPU cluster, run the following command: ```bash nebius compute gpu-cluster create \ --name \ --infiniband-fabric ``` To select the fabric, see [InfiniBand™ fabrics](https://docs.nebius.com/compute/clusters/gpu/index.md#infiniband-fabrics). Save the cluster ID from the output `metadata.id` parameter. 4. (Optional) Create a [service account](https://docs.nebius.com/iam/service-accounts/manage.md) that will perform actions on behalf of the VM: ```bash nebius iam service-account create --name ``` 5. Create the VM: ```bash nebius compute instance create \ --name \ --stopped \ --resources-platform \ --resources-preset \ --boot-disk-managed-disk-name \ --boot-disk-managed-disk-type \ --boot-disk-managed-disk-size-gibibytes \ --boot-disk-managed-disk-source-image-family-image-family \ --boot-disk-attach-mode READ_WRITE \ --boot-disk-device-id \ --secondary-disks '[{"attach_mode": "READ_WRITE", "device_id": "", "managed_disk": { "name": "", "spec": { "type": "", "size_gibibytes": 10 }}}]' \ --filesystems '[{"existing_filesystem": {"id": ""}, "attach_mode": "READ_WRITE", "mount_tag": ""}]' \ --cloud-init-user-data "$USER_DATA" \ --network-interfaces '[{"name": "eth0", "ip_address": {}, "public_ip_address": {"allocation_id": ""}, "subnet_id": ""}]' \ --gpu-cluster-id \ --hostname \ --reservation-policy-policy \ --reservation-policy-reservation-ids \ --recovery-policy \ --preemptible-on-preemption stop \ --service-account-id ``` The command contains the following parameters: * `--name`: VM's name. * `--stopped` (optional): If you want to create a VM but not launch it, specify the `false` value. The VM will remain in the `Stopped` status. For more information, see [Lifecycle of a Compute virtual machine](https://docs.nebius.com/compute/virtual-machines/lifecycle.md). * `--resources-platform`: [VM platform](https://docs.nebius.com/compute/virtual-machines/types.md). * `--resources-preset`: VM preset. Depends on the chosen platform. * `--boot-disk-managed-disk-name`: Name of the [VM-managed boot disk](https://docs.nebius.com/compute/storage/types.md#vm-managed-and-standalone-disks) that you create along with the VM. * `--boot-disk-managed-disk-type`: [Disk type](https://docs.nebius.com/compute/storage/types.md#network-ssd-disks). * `--boot-disk-managed-disk-size-gibibytes`: Disk size in gibibytes. Maximum boot disk size is 30,720 GiB (30 TiB). * `--boot-disk-managed-disk-source-image-family-image-family`: Public image that Nebius AI Cloud supports. For the list of available public images, see [Boot disk images for Compute virtual machines](https://docs.nebius.com/compute/storage/boot-disk-images.md). * `--boot-disk-attach-mode`: Write permission of the boot disk, `READ_ONLY` or `READ_WRITE`. * `--boot-disk-device-id` (optional): User-defined ID for mounting the boot disk to the VM. The default value is `disk-n` where `n` is an integer index. A `virtio-` prefix is added to the specified (or default) device ID. * `--secondary-disks` (optional): Settings of additional VM-managed disks that you create along with the VM. You can attach one or several disks. * `attach_mode`: Write permission of the additional disk, `READ_ONLY` or `READ_WRITE`. * `device_id`: User-defined ID for mounting the disk to the VM. * `managed_disk.name`: Name of a new disk. * `managed_disk.spec.type`: Disk type. * `managed_disk.spec.size_gibibytes`: Disk size in gibibytes. * `--filesystems` (optional): Filesystem settings. You can attach several filesystems, if required. * `id`: ID of the filesystem created earlier. * `attach_mode`: Write permission of the filesystem, `READ_ONLY` or `READ_WRITE`. * `mount_tag`: Tag for mounting the filesystem to the VM. Create your own tag, such as `my-filesystem`. Make sure that it is unique within the VM. If you do not specify the tag, it takes the `filesystem-N` default value where `N` is an integer. For example, `filesystem-0`. After you create the VM, [mount the additional disks and filesystems](https://docs.nebius.com/compute/storage/use.md#how-to-mount-volumes-to-vms) to it. Otherwise, the VM's operating system does not recognize these volumes. * `--cloud-init-user-data` (optional): Configuration of VM users in the [cloud-init](https://cloud-init.io/) format. * `--network-interfaces`: Network settings. * To assign a dynamic public IP address, specify `"public_ip_address": {}`. A dynamic public IP address is randomly allocated from the [IPv4 public range](https://docs.nebius.com/compute/virtual-machines/manage.md#get-public-ip-range) of Nebius AI Cloud and is not persistent. If a VM with a dynamic address has the `Stopped` status for more than one hour, the address is automatically returned to the IPv4 public range. After that, Compute may allocate this address to a different VM. * To assign a static public IP address, specify `"public_ip_address": {"static": true}`. A static public IP address is also randomly allocated from the IPv4 public range of Nebius AI Cloud. If you stop a VM that has a static IP address, the address will not return to the range. However, if you delete this VM, the address will return. * To assign the allocation created earlier, specify `"public_ip_address": {"allocation_id": ""}`. An allocation allows you to use a reserved static public address for the VM. This address will not return to the IPv4 range even if you delete the VM. * To create a VM without a public IP address, remove the `public_ip_address` parameter from the JSON. The VM will only have a private address. If you need to secure your VM and make it isolated, you can create a VM without a public IP address. If you need to connect to this VM from the internet, you can [set up a WireGuard jump server](https://docs.nebius.com/compute/virtual-machines/wireguard.md). It has an IP address in the internet and an IP address in the VM's network. As a result, you can access the VM via the jump server from the internet. This approach enhances security and still provides access to the VM. * `--gpu-cluster-id` (optional): ID of the GPU cluster created earlier. * `--local-disks-passthrough-group-requested` (optional): Requests local SSD disks to be added to the VM when set to `true`. Local SSD disks are available only for supported platforms and presets. For details, see [Availability](https://docs.nebius.com/compute/storage/local-disks.md#availability). * `--hostname` (optional): Hostname for the VM's [FQDN](https://docs.nebius.com/compute/virtual-machines/fqdn.md). By default, the FQDN has the `..compute.internal.` format. If you want to customize it, use a hostname instead of the VM's ID in the FQDN. For example, if you specify `--hostname my-host`, the FQDN is `my-host.vpcnetwork-e00***.compute.internal.`. * `--reservation-policy-policy` (optional): Policy for reservation usage. You can use [reservations of capacity resources](https://docs.nebius.com/compute/virtual-machines/reservations.md) and run your VM based on them. As a result, the VM resources are reserved and always available. * `--reservation-policy-reservation-ids` (optional): IDs of specific reservations. These are capacity block groups that a Nebius manager has created. For information about how to configure `--reservation-policy-policy` and `--reservation-policy-reservation-ids`, see [How to add reservations to VMs](https://docs.nebius.com/compute/virtual-machines/reservations.md#how-to-add-reservations-to-vms). * `--recovery-policy` (optional): Defines what Compute does with the VM after it is preempted or fails. [Preemptible VMs](https://docs.nebius.com/compute/virtual-machines/preemptible.md) only support the `fail` value that stops the VM. They do not support the `recover` value that tries to restart the VM. If you set `recover` for a preemptible VM, it will cause an error. * `--preemptible-on-preemption` (optional; for preemptible VMs only): Specifies what happens when the VM is preempted. The only supported value is `stop`: Compute stops the VM without deleting or restarting it. * `--service-account-id` (optional): Service account associated with the VM. 1. (Optional) If you want to attach a filesystem to your VM, create this filesystem: ```hcl resource "nebius_compute_v1_filesystem" "my_filesystem" { name = "" parent_id = "" size_gibibytes = 10 type = "NETWORK_SSD" block_size_bytes = 4096 } ``` For more information, see [Volume parameters](https://docs.nebius.com/compute/storage/manage.md#volume-parameters). You don't need to create disks for the VM in advance. You can create them along with the VM. Such disks are called [VM-managed](https://docs.nebius.com/compute/storage/types.md#vm-managed-and-standalone-disks). They are tied to the VM lifecycle. 2. (Optional) To provide the VM with an [allocation](https://docs.nebius.com/vpc/overview.md#allocation) that reserves a static public IP address, create this allocation. As a result, the address is preserved even if you delete the VM. ```hcl resource "nebius_vpc_v1_allocation" "my_allocation" { name = "" parent_id = "" ipv4_public = { subnet_id = "" } } ``` To create the allocation, [get the required subnet ID](https://docs.nebius.com/vpc/networking/resources.md#how-to-get-a-subnet-id). For more information about networking in Compute, see [Public IP addresses](https://docs.nebius.com/compute/virtual-machines/network.md#public-ip-addresses). 3. (Optional) If you create a VM with 8 GPUs (for example, for training models), use a GPU cluster for the VM. InfiniBand™ in the cluster allows you to accelerate tasks that require high-performance computing (HPC) power. A single VM without InfiniBand™ cannot perform these tasks as quickly. To create a GPU cluster, use the following configuration: ```hcl resource "nebius_compute_v1_gpu_cluster" "my_gpu_cluster" { name = "" parent_id = "" infiniband_fabric = "" } ``` To select the fabric, see [InfiniBand™ fabrics](https://docs.nebius.com/compute/clusters/gpu/index.md#infiniband-fabrics). 4. (Optional) Create a [service account](https://docs.nebius.com/iam/service-accounts/manage.md) that will perform actions on behalf of the VM: ```hcl resource "nebius_iam_v1_service_account" "my_sa" { name = "" parent_id = "" } ``` 5. (Optional) If your `resources` block uses a platform and preset that support local SSD disks, add a `local_disks` block to the `nebius_compute_v1_instance` resource in the next step. The local SSD disks are provisioned as raw Non-Volatile Memory Express (NVMe) devices (`nvme0`, `nvme1`, and so on). You can enable local SSD disks only when you create the VM. For more information, see [Availability](https://docs.nebius.com/compute/storage/local-disks.md#availability). For example: ```hcl resource "nebius_compute_v1_instance" "my_vm" { # ... local_disks = { passthrough_group = { requested = true } } } ``` 6. Create the VM: ```hcl resource "nebius_compute_v1_instance" "my_vm" { name = "" parent_id = "" stopped = resources = { platform = "" preset = "" } boot_disk = { managed_disk = { name = "" spec = { type = "" size_gibibytes = source_image_family = { image_family = "" } } } attach_mode = "" device_id = "" } secondary_disks = [ { managed_disk = { name = "" spec = { type = "" size_gibibytes = } } attach_mode = "" device_id = "" } ] filesystems = [ { existing_filesystem = { id = nebius_compute_v1_filesystem.my_filesystem.id } attach_mode = "" mount_tag = "" } ] cloud_init_user_data = var.user_data network_interfaces = [ { name = "eth0" ip_address = {} public_ip_address = { allocation_id = nebius_vpc_v1_allocation.my_allocation.id } subnet_id = "" } ] gpu_cluster = { id = nebius_compute_v1_gpu_cluster.my_gpu_cluster.id } hostname = "" reservation_policy = { policy = "" reservation_ids = "" } recovery_policy = "" preemptible = { on_preemption = "STOP" } service_account_id = nebius_iam_v1_service_account.my_sa.id } ``` The configuration contains the following parameters: * `name`: VM's name. * `stopped` (optional): If you want to create a VM but not launch it, specify the `false` value. The VM will remain in the `Stopped` status. For more information, see [Lifecycle of a Compute virtual machine](https://docs.nebius.com/compute/virtual-machines/lifecycle.md). * `resources.platform`: [VM platform](https://docs.nebius.com/compute/virtual-machines/types.md). * `resources.preset`: VM preset. Depends on the chosen platform. * `boot_disk`: Settings of a [VM-managed boot disk](https://docs.nebius.com/compute/storage/types.md#vm-managed-and-standalone-disks) that you create along with the VM. * `managed_disk.name`: Name of the disk. * `managed_disk.spec.type`: [Disk type](https://docs.nebius.com/compute/storage/types.md#network-ssd-disks). * `managed_disk.spec.size_gibibytes`: Disk size in gibibytes. Maximum boot disk size is 30,720 GiB (30 TiB). * `managed_disk.spec.source_image_family.image_family`: Public image that Nebius AI Cloud supports. For the list of available public images, see [Boot disk images for Compute virtual machines](https://docs.nebius.com/compute/storage/boot-disk-images.md). * `attach_mode`: Write permission of the boot disk, `READ_ONLY` or `READ_WRITE`. * `device_id` (optional): User-defined ID for mounting the disk to the VM. The default value is `disk-n`, where `n` is an integer index. A `virtio-` prefix is added to the specified (or default) device ID. * `secondary_disks` (optional): Settings of additional VM-managed disks that you create along with the VM. You can attach one or several disks. * `managed_disk.name`: Name of a new disk. * `managed_disk.spec.type`: Disk type. * `managed_disk.spec.size_gibibytes`: Disk size in gibibytes. * `attach_mode`: Write permission of the additional disk, `READ_ONLY` or `READ_WRITE`. * `device_id`: User-defined ID for mounting the disk to the VM. * `filesystems` (optional): Filesystem settings. You can attach several filesystems, if required. * `existing_filesystem.id`: ID of the filesystem created earlier. * `attach_mode`: Write permission of the filesystem, `READ_ONLY` or `READ_WRITE`. * `mount_tag`: Tag for mounting the filesystem to the VM. Create your own tag, such as `my-filesystem`. Make sure that it is unique within the VM. If you do not specify the tag, it takes the `filesystem-N` default value where `N` is an integer. For example, `filesystem-0`. After you create the VM, [mount the additional disks and filesystems](https://docs.nebius.com/compute/storage/use.md#how-to-mount-volumes-to-vms) to it. Otherwise, the VM's operating system does not recognize these volumes. * `cloud_init_user_data` (optional): Configuration of VM users in the [cloud-init](https://cloud-init.io/) format. * `network_interfaces`: Network settings. * To assign a dynamic public IP address, specify `public_ip_address = {}`. A dynamic public IP address is randomly allocated from the [IPv4 public range](https://docs.nebius.com/compute/virtual-machines/manage.md#get-public-ip-range) of Nebius AI Cloud and is not persistent. If a VM with a dynamic address has the `Stopped` status for more than one hour, the address is automatically returned to the IPv4 public range. After that, Compute may allocate this address to a different VM. * To assign a static public IP address, specify `public_ip_address = {static = true}`. A static public IP address is also randomly allocated from the IPv4 public range of Nebius AI Cloud. If you stop a VM that has a static IP address, the address will not return to the range. However, if you delete this VM, the address will return. * To assign the allocation created earlier, specify `public_ip_address = {allocation_id = nebius_vpc_v1_allocation.my_allocation.id}`. An allocation allows you to use a reserved static public address for the VM. This address will not return to the IPv4 range even if you delete the VM. * To create a VM without a public IP address, remove the `public_ip_address` parameter from the configuration. The VM will only have a private address. If you need to secure your VM and make it isolated, you can create a VM without a public IP address. If you need to connect to this VM from the internet, you can [set up a WireGuard jump server](https://docs.nebius.com/compute/virtual-machines/wireguard.md). It has an IP address in the internet and an IP address in the VM's network. As a result, you can access the VM via the jump server from the internet. This approach enhances security and still provides access to the VM. * `gpu_cluster.id` (optional): ID of the GPU cluster created earlier. * `local_disks` (optional): Set `passthrough_group.requested = true` to request local SSD disks to be added to the VM. Local SSD disks are available only for supported platforms and presets. For details, see [Availability](https://docs.nebius.com/compute/storage/local-disks.md#availability). * `hostname` (optional): Hostname for the VM's [FQDN](https://docs.nebius.com/compute/virtual-machines/fqdn.md). By default, the FQDN has the `..compute.internal.` format. If you want to customize it, use a hostname instead of the VM's ID in the FQDN. For example, if you specify `hostname = "my-host"`, the FQDN is `my-host.vpcnetwork-e00***.compute.internal.`. * `reservation_policy.policy` (optional): Policy for reservation usage. You can use [reservations of capacity resources](https://docs.nebius.com/compute/virtual-machines/reservations.md) and run your VM based on them. As a result, VM resources are reserved and always available. * `reservation_policy.reservation_ids` (optional): IDs of specific reservations. These are capacity block groups that a Nebius manager has created. For information about how to configure `reservation_policy.policy` and `reservation_policy.reservation_ids`, see [How to add reservations to VMs](https://docs.nebius.com/compute/virtual-machines/reservations.md#how-to-add-reservations-to-vms). * `recovery_policy` (optional): Defines what Compute does with the VM after it is preempted or fails. [Preemptible VMs](https://docs.nebius.com/compute/virtual-machines/preemptible.md) only support the `FAIL` value that stops the VM. They do not support the `RECOVER` value that tries to restart the VM. If you set `RECOVER` for a preemptible VM, it will cause an error. * `preemptible.on_preemption` (optional; for preemptible VMs only): Specifies what happens when the VM is preempted. The only supported value is `STOP`: Compute stops the VM without deleting or restarting it. * `service_account_id` (optional): Service account associated with the VM. 7. Check that the configuration is correct: ```bash terraform validate ``` 8. Apply the changes: ```bash terraform apply ``` 1. (Optional) If you want to attach a filesystem to your VM, create this filesystem: ```go filesystemOperation, err := sdk.Services().Compute().V1(). Filesystem().Create( ctx, &compute.CreateFilesystemRequest{ Metadata: &common.ResourceMetadata{ Name: "", }, Spec: &compute.FilesystemSpec{ Size: &compute.FilesystemSpec_SizeGibibytes{ SizeGibibytes: 10, }, BlockSizeBytes: 4096, Type: compute.FilesystemSpec_NETWORK_SSD, }, }, ) if err != nil { return err } if _, err = filesystemOperation.Wait(ctx); err != nil { return err } ``` For more information about filesystem creation, see [Managing Compute volumes](https://docs.nebius.com/compute/storage/manage.md). You don't need to create disks for the VM in advance. You can create them along with the VM. Such disks are called [VM-managed](https://docs.nebius.com/compute/storage/types.md#vm-managed-and-standalone-disks). They are tied to the VM lifecycle. 2. (Optional) If you create a VM with 8 GPUs (for example, for training models), use a GPU cluster for the VM. InfiniBand™ in the cluster allows you to accelerate tasks that require high-performance computing (HPC) power. A single VM without InfiniBand™ cannot perform these tasks as quickly. Create a GPU cluster: ```go gpuClusterOperation, err := sdk.Services().Compute().V1(). GpuCluster().Create( ctx, &compute.CreateGpuClusterRequest{ Metadata: &common.ResourceMetadata{ Name: "", }, Spec: &compute.GpuClusterSpec{ InfinibandFabric: "", }, }, ) if err != nil { return err } if _, err = gpuClusterOperation.Wait(ctx); err != nil { return err } ``` To select the fabric, see [InfiniBand™ fabrics](https://docs.nebius.com/compute/clusters/gpu/index.md#infiniband-fabrics). 3. (Optional) Create a [service account](https://docs.nebius.com/iam/service-accounts/manage.md) that will perform actions on behalf of the VM: ```go serviceAccountOperation, err := sdk.Services().IAM().V1(). ServiceAccount().Create( ctx, &iam.CreateServiceAccountRequest{ Metadata: &common.ResourceMetadata{ Name: "", }, Spec: &iam.ServiceAccountSpec{}, }, ) if err != nil { return err } if _, err = serviceAccountOperation.Wait(ctx); err != nil { return err } serviceAccountID := serviceAccountOperation.ResourceID() ``` 4. Create the VM: ```go managedBootDisk := &compute.AttachedDiskSpec{ AttachMode: compute.AttachedDiskSpec_READ_WRITE, DeviceId: "", Type: &compute.AttachedDiskSpec_ManagedDisk{ ManagedDisk: &compute.ManagedDisk{ Name: "", Spec: &compute.DiskSpec{ Size: &compute.DiskSpec_SizeGibibytes{ SizeGibibytes: , }, Type: compute.DiskSpec_NETWORK_SSD, Source: &compute.DiskSpec_SourceImageFamily{ SourceImageFamily: &compute.SourceImageFamily{ ImageFamily: "", }, }, }, }, }, } managedSecondaryDisk := &compute.AttachedDiskSpec{ AttachMode: compute.AttachedDiskSpec_READ_WRITE, DeviceId: "device-2", Type: &compute.AttachedDiskSpec_ManagedDisk{ ManagedDisk: &compute.ManagedDisk{ Name: "managed-secondary-disk", Spec: &compute.DiskSpec{ Size: &compute.DiskSpec_SizeGibibytes{ SizeGibibytes: 10, }, Type: compute.DiskSpec_NETWORK_SSD, }, }, }, } managedFilesystem := &compute.AttachedFilesystemSpec{ AttachMode: compute.AttachedFilesystemSpec_READ_WRITE, MountTag: "", Type: &compute.AttachedFilesystemSpec_ExistingFilesystem{ ExistingFilesystem: &compute.ExistingFilesystem{ Id: filesystemID, }, }, } managedNetwork := &compute.NetworkInterfaceSpec{ Name: "eth0", SubnetId: subnetID, IpAddress: &compute.IPAddress{}, PublicIpAddress: &compute.PublicIPAddress{}, } managedVMOperation, err := sdk.Services().Compute().V1(). Instance().Create( ctx, &compute.CreateInstanceRequest{ Metadata: &common.ResourceMetadata{ Name: "", }, Spec: &compute.InstanceSpec{ ServiceAccountId: serviceAccountID, Stopped: , Resources: &compute.ResourcesSpec{ Platform: "", Size: &compute.ResourcesSpec_Preset{ Preset: "", }, }, GpuCluster: &compute.InstanceGpuClusterSpec{ Id: gpuClusterID, }, BootDisk: managedBootDisk, SecondaryDisks: []*compute.AttachedDiskSpec{ managedSecondaryDisk, }, Filesystems: []*compute.AttachedFilesystemSpec{ managedFilesystem, }, CloudInitUserData: userData, NetworkInterfaces: []*compute.NetworkInterfaceSpec{ managedNetwork, }, Hostname: "", ReservationPolicy: &compute.ReservationPolicy{ Policy: compute.ReservationPolicy_FORBID, }, RecoveryPolicy: compute.InstanceRecoveryPolicy_FAIL, Preemptible: &compute.PreemptibleSpec{ OnPreemption: compute.PreemptibleSpec_STOP, }, }, }, ) if err != nil { return err } if _, err = managedVMOperation.Wait(ctx); err != nil { return err } ``` The code contains the following parameters: * `Metadata.Name`: VM's name. * `Spec.ServiceAccountId` (optional): Service account associated with the VM. * `Spec.Stopped` (optional): If you want to create a VM but not launch it, specify the `true` value. The VM will remain in the `Stopped` status. * `Spec.Resources.Platform`: [VM platform](https://docs.nebius.com/compute/virtual-machines/types.md). * `Spec.Resources.Size.Preset`: VM preset. Depends on the chosen platform. * `Spec.GpuCluster.Id` (optional): ID of the GPU cluster created earlier. * `managedBootDisk.AttachMode`: Write permission of the boot disk, `READ_ONLY` or `READ_WRITE`. * `managedBootDisk.DeviceId` (optional): User-defined ID for mounting the boot disk to the VM. The default value is `disk-n` where `n` is an integer index. A `virtio-` prefix is added to the specified (or default) device ID. * `managedBootDisk.ManagedDisk.Name`: Name of the [VM-managed boot disk](https://docs.nebius.com/compute/storage/types.md#vm-managed-and-standalone-disks) that you create along with the VM. * `managedBootDisk.ManagedDisk.Spec.SizeGibibytes`: Disk size in gibibytes. Maximum boot disk size is 30,720 GiB (30 TiB). * `managedBootDisk.ManagedDisk.Spec.Type`: [Disk type](https://docs.nebius.com/compute/storage/types.md#network-ssd-disks). * `managedBootDisk.ManagedDisk.Spec.SourceImageFamily.ImageFamily`: Public image that Nebius AI Cloud supports. For the list of available public images, see [Boot disk images for Compute virtual machines](https://docs.nebius.com/compute/storage/boot-disk-images.md). * `managedSecondaryDisk.AttachMode`: Write permission of the additional disk, `READ_ONLY` or `READ_WRITE`. * `managedSecondaryDisk.DeviceId`: User-defined ID for mounting the additional disk to the VM. * `managedSecondaryDisk.ManagedDisk.Name`: Name of a new additional VM-managed disk. * `managedSecondaryDisk.ManagedDisk.Spec.SizeGibibytes`: Size of the additional disk in gibibytes. * `managedSecondaryDisk.ManagedDisk.Spec.Type`: Disk type of the additional disk. * `managedFilesystem.AttachMode`: Write permission of the filesystem, `READ_ONLY` or `READ_WRITE`. * `managedFilesystem.MountTag`: Tag for mounting the filesystem to the VM. * `managedFilesystem.ExistingFilesystem.Id`: ID of the filesystem created earlier. * `Spec.CloudInitUserData` (optional): Configuration of VM users in the [cloud-init](https://cloud-init.io/) format. * `managedNetwork.SubnetId`: ID of the subnet to attach the VM to. * `managedNetwork.IpAddress`: Private IP address settings. * `managedNetwork.PublicIpAddress`: Public IP address settings. In the example, an empty `PublicIPAddress` assigns a dynamic public IP address. * `Spec.Hostname` (optional): Hostname for the VM's [FQDN](https://docs.nebius.com/compute/virtual-machines/fqdn.md). By default, the FQDN has the `..compute.internal.` format. * `Spec.ReservationPolicy.Policy` (optional): Policy for reservation usage. You can use [reservations of capacity resources](https://docs.nebius.com/compute/virtual-machines/reservations.md) and run your VM based on them. * `Spec.RecoveryPolicy` (optional): Defines what Compute does with the VM after it is preempted or fails. * `Spec.Preemptible.OnPreemption` (optional; for preemptible VMs only): Specifies what happens when the VM is preempted. The only supported value is `STOP`: Compute stops the VM without deleting or restarting it. 1. (Optional) If you want to attach a filesystem to your VM, create this filesystem: ```python filesystem_service = FilesystemServiceClient(sdk) filesystem_operation = await filesystem_service.create( CreateFilesystemRequest( metadata=ResourceMetadata(name=""), spec=FilesystemSpec( block_size_bytes=4096, type=FilesystemSpec.FilesystemType.NETWORK_SSD, size_gibibytes=10, ), ), ) await filesystem_operation.wait() ``` For more information about filesystem creation, see [Managing Compute volumes](https://docs.nebius.com/compute/storage/manage.md). You don't need to create disks for the VM in advance. You can create them along with the VM. Such disks are called [VM-managed](https://docs.nebius.com/compute/storage/types.md#vm-managed-and-standalone-disks). They are tied to the VM lifecycle. 2. (Optional) If you create a VM with 8 GPUs (for example, for training models), use a GPU cluster for the VM. InfiniBand™ in the cluster allows you to accelerate tasks that require high-performance computing (HPC) power. A single VM without InfiniBand™ cannot perform these tasks as quickly. Create a GPU cluster: ```python gpu_cluster_service = GpuClusterServiceClient(sdk) gpu_cluster_operation = await gpu_cluster_service.create( CreateGpuClusterRequest( metadata=ResourceMetadata( name="", ), spec=GpuClusterSpec( infiniband_fabric="", ), ), ) await gpu_cluster_operation.wait() ``` To select the fabric, see [InfiniBand™ fabrics](https://docs.nebius.com/compute/clusters/gpu/index.md#infiniband-fabrics). 3. (Optional) Create a [service account](https://docs.nebius.com/iam/service-accounts/manage.md) that will perform actions on behalf of the VM: ```python service_account_service = ServiceAccountServiceClient(sdk) service_account_operation = await service_account_service.create( CreateServiceAccountRequest( metadata=ResourceMetadata( name="", ), spec=ServiceAccountSpec(), ), ) await service_account_operation.wait() service_account_id = service_account_operation.resource_id ``` 4. Create the VM: ```python instance_service = InstanceServiceClient(sdk) managed_vm_operation = await instance_service.create( CreateInstanceRequest( metadata=ResourceMetadata(name=""), spec=InstanceSpec( service_account_id=service_account_id, stopped=, resources=ResourcesSpec( platform="", preset="", ), gpu_cluster=InstanceGpuClusterSpec( id=gpu_cluster_id, ), boot_disk=AttachedDiskSpec( attach_mode=( AttachedDiskSpec.AttachMode.READ_WRITE ), managed_disk=ManagedDisk( name="", spec=DiskSpec( type=DiskSpec.DiskType.NETWORK_SSD, source_image_family=( SourceImageFamily( image_family="", ) ), size_gibibytes=, ), ), device_id="", ), secondary_disks=[ AttachedDiskSpec( attach_mode=( AttachedDiskSpec.AttachMode.READ_WRITE ), managed_disk=ManagedDisk( name="managed-secondary-disk", spec=DiskSpec( type=( DiskSpec.DiskType.NETWORK_SSD ), size_gibibytes=10, ), ), device_id="device-2", ), ], filesystems=[ AttachedFilesystemSpec( attach_mode=( AttachedFilesystemSpec.AttachMode.READ_WRITE ), existing_filesystem=ExistingFilesystem( id=filesystem_id, ), mount_tag="", ), ], cloud_init_user_data=user_data, network_interfaces=[ NetworkInterfaceSpec( name="eth0", subnet_id=subnet_id, ip_address=IPAddress(), public_ip_address=PublicIPAddress(), ), ], hostname="", reservation_policy=ReservationPolicy( policy=ReservationPolicy.Policy.FORBID, ), recovery_policy=InstanceRecoveryPolicy.FAIL, preemptible=PreemptibleSpec( on_preemption=( PreemptibleSpec.PreemptionPolicy.STOP ), ), ), ), ) await managed_vm_operation.wait() ``` The code contains the following parameters: * `metadata.name`: VM's name. * `spec.service_account_id` (optional): Service account associated with the VM. * `spec.stopped` (optional): If you want to create a VM but not launch it, specify the `True` value. The VM will remain in the `Stopped` status. * `spec.resources.platform`: [VM platform](https://docs.nebius.com/compute/virtual-machines/types.md). * `spec.resources.preset`: VM preset. Depends on the chosen platform. * `spec.gpu_cluster.id` (optional): ID of the GPU cluster created earlier. * `spec.boot_disk.attach_mode`: Write permission of the boot disk, `READ_ONLY` or `READ_WRITE`. * `spec.boot_disk.managed_disk.name`: Name of the [VM-managed boot disk](https://docs.nebius.com/compute/storage/types.md#vm-managed-and-standalone-disks) that you create along with the VM. * `spec.boot_disk.managed_disk.spec.type`: [Disk type](https://docs.nebius.com/compute/storage/types.md#network-ssd-disks). * `spec.boot_disk.managed_disk.spec.source_image_family.image_family`: Public image that Nebius AI Cloud supports. For the list of available public images, see [Boot disk images for Compute virtual machines](https://docs.nebius.com/compute/storage/boot-disk-images.md). * `spec.boot_disk.managed_disk.spec.size_gibibytes`: Disk size in gibibytes. Maximum boot disk size is 30,720 GiB (30 TiB). * `spec.boot_disk.device_id` (optional): User-defined ID for mounting the boot disk to the VM. The default value is `disk-n` where `n` is an integer index. A `virtio-` prefix is added to the specified (or default) device ID. * `spec.secondary_disks[].attach_mode`: Write permission of the additional disk, `READ_ONLY` or `READ_WRITE`. * `spec.secondary_disks[].managed_disk.name`: Name of a new additional VM-managed disk. * `spec.secondary_disks[].managed_disk.spec.type`: Disk type of the additional disk. * `spec.secondary_disks[].managed_disk.spec.size_gibibytes`: Size of the additional disk in gibibytes. * `spec.secondary_disks[].device_id`: User-defined ID for mounting the additional disk to the VM. * `spec.filesystems[].attach_mode`: Write permission of the filesystem, `READ_ONLY` or `READ_WRITE`. * `spec.filesystems[].existing_filesystem.id`: ID of the filesystem created earlier. * `spec.filesystems[].mount_tag`: Tag for mounting the filesystem to the VM. * `spec.cloud_init_user_data` (optional): Configuration of VM users in the [cloud-init](https://cloud-init.io/) format. * `spec.network_interfaces[].subnet_id`: ID of the subnet to attach the VM to. * `spec.network_interfaces[].ip_address`: Private IP address settings. * `spec.network_interfaces[].public_ip_address`: Public IP address settings. In the example, an empty `PublicIPAddress` assigns a dynamic public IP address. * `spec.hostname` (optional): Hostname for the VM's [FQDN](https://docs.nebius.com/compute/virtual-machines/fqdn.md). By default, the FQDN has the `..compute.internal.` format. * `spec.reservation_policy.policy` (optional): Policy for reservation usage. You can use [reservations of capacity resources](https://docs.nebius.com/compute/virtual-machines/reservations.md) and run your VM based on them. * `spec.recovery_policy` (optional): Defines what Compute does with the VM after it is preempted or fails. * `spec.preemptible.on_preemption` (optional; for preemptible VMs only): Specifies what happens when the VM is preempted. The only supported value is `STOP`: Compute stops the VM without deleting or restarting it. 1. (Optional) If you want to attach a filesystem to your VM, create this filesystem: ```ts const filesystemCreateService = new FilesystemService(sdk); const filesystemOperation = await filesystemCreateService.create( CreateFilesystemRequest.create({ metadata: ResourceMetadata.create({ name: "", }), spec: FilesystemSpec.create({ blockSizeBytes: 4096, type: FilesystemSpec_FilesystemType.NETWORK_SSD, size: { $case: "sizeGibibytes", sizeGibibytes: 10, }, }), }), ).result; await filesystemOperation.wait(); ``` For more information about filesystem creation, see [Managing Compute volumes](https://docs.nebius.com/compute/storage/manage.md). You don't need to create disks for the VM in advance. You can create them along with the VM. Such disks are called [VM-managed](https://docs.nebius.com/compute/storage/types.md#vm-managed-and-standalone-disks). They are tied to the VM lifecycle. 2. (Optional) If you create a VM with 8 GPUs (for example, for training models), use a GPU cluster for the VM. InfiniBand™ in the cluster allows you to accelerate tasks that require high-performance computing (HPC) power. A single VM without InfiniBand™ cannot perform these tasks as quickly. Create a GPU cluster: ```ts const gpuClusterCreateService = new GpuClusterService(sdk); const gpuClusterOperation = await gpuClusterCreateService.create( CreateGpuClusterRequest.create({ metadata: ResourceMetadata.create({ name: "", }), spec: GpuClusterSpec.create({ infinibandFabric: "", }), }), ).result; await gpuClusterOperation.wait(); ``` To select the fabric, see [InfiniBand™ fabrics](https://docs.nebius.com/compute/clusters/gpu/index.md#infiniband-fabrics). 3. (Optional) Create a [service account](https://docs.nebius.com/iam/service-accounts/manage.md) that will perform actions on behalf of the VM: ```ts const serviceAccountCreateService = new ServiceAccountService(sdk); const serviceAccountOperation = await serviceAccountCreateService.create( CreateServiceAccountRequest.create({ metadata: ResourceMetadata.create({ name: "", }), spec: ServiceAccountSpec.create({}), }), ).result; await serviceAccountOperation.wait(); const serviceAccountId = serviceAccountOperation.resourceId(); ``` 4. Create the VM: ```ts const managedVmService = new InstanceService(sdk); const managedVmOperation = await managedVmService.create( CreateInstanceRequest.create({ metadata: ResourceMetadata.create({ name: "", }), spec: InstanceSpec.create({ serviceAccountId, stopped: , resources: ResourcesSpec.create({ platform: "", size: { $case: "preset", preset: "", }, }), gpuCluster: InstanceGpuClusterSpec.create({ id: gpuClusterId, }), bootDisk: AttachedDiskSpec.create({ attachMode: AttachedDiskSpec_AttachMode.READ_WRITE, deviceId: "", type: { $case: "managedDisk", managedDisk: ManagedDisk.create({ name: "", spec: DiskSpec.create({ type: DiskSpec_DiskType.NETWORK_SSD, source: { $case: "sourceImageFamily", sourceImageFamily: SourceImageFamily.create({ imageFamily: "", }), }, size: { $case: "sizeGibibytes", sizeGibibytes: , }, }), }), }, }), secondaryDisks: [ AttachedDiskSpec.create({ attachMode: AttachedDiskSpec_AttachMode.READ_WRITE, deviceId: "device-2", type: { $case: "managedDisk", managedDisk: ManagedDisk.create({ name: "managed-secondary-disk", spec: DiskSpec.create({ type: DiskSpec_DiskType.NETWORK_SSD, size: { $case: "sizeGibibytes", sizeGibibytes: 10, }, }), }), }, }), ], filesystems: [ AttachedFilesystemSpec.create({ attachMode: AttachedFilesystemSpec_AttachMode.READ_WRITE, mountTag: "", type: { $case: "existingFilesystem", existingFilesystem: ExistingFilesystem.create({ id: filesystemId, }), }, }), ], cloudInitUserData: userData, networkInterfaces: [ NetworkInterfaceSpec.create({ name: "eth0", subnetId, ipAddress: IPAddress.create({}), publicIpAddress: PublicIPAddress.create({}), }), ], hostname: "", reservationPolicy: ReservationPolicy.create({ policy: ReservationPolicy_Policy.FORBID, }), recoveryPolicy: InstanceRecoveryPolicy.FAIL, preemptible: PreemptibleSpec.create({ onPreemption: PreemptibleSpec_PreemptionPolicy.STOP, }), }), }), ).result; await managedVmOperation.wait(); ``` The code contains the following parameters: * `metadata.name`: VM's name. * `spec.serviceAccountId` (optional): Service account associated with the VM. * `spec.stopped` (optional): If you want to create a VM but not launch it, specify the `true` value. The VM will remain in the `Stopped` status. * `spec.resources.platform`: [VM platform](https://docs.nebius.com/compute/virtual-machines/types.md). * `spec.resources.size.preset`: VM preset. Depends on the chosen platform. * `spec.gpuCluster.id` (optional): ID of the GPU cluster created earlier. * `spec.bootDisk.attachMode`: Write permission of the boot disk, `READ_ONLY` or `READ_WRITE`. * `spec.bootDisk.deviceId` (optional): User-defined ID for mounting the boot disk to the VM. The default value is `disk-n` where `n` is an integer index. A `virtio-` prefix is added to the specified (or default) device ID. * `spec.bootDisk.type.managedDisk.name`: Name of the [VM-managed boot disk](https://docs.nebius.com/compute/storage/types.md#vm-managed-and-standalone-disks) that you create along with the VM. * `spec.bootDisk.type.managedDisk.spec.type`: [Disk type](https://docs.nebius.com/compute/storage/types.md#network-ssd-disks). * `spec.bootDisk.type.managedDisk.spec.source.sourceImageFamily.imageFamily`: Public image that Nebius AI Cloud supports. For the list of available public images, see [Boot disk images for Compute virtual machines](https://docs.nebius.com/compute/storage/boot-disk-images.md). * `spec.bootDisk.type.managedDisk.spec.size.sizeGibibytes`: Disk size in gibibytes. Maximum boot disk size is 30,720 GiB (30 TiB). * `spec.secondaryDisks[].attachMode`: Write permission of the additional disk, `READ_ONLY` or `READ_WRITE`. * `spec.secondaryDisks[].deviceId`: User-defined ID for mounting the additional disk to the VM. * `spec.secondaryDisks[].type.managedDisk.name`: Name of a new additional VM-managed disk. * `spec.secondaryDisks[].type.managedDisk.spec.type`: Disk type of the additional disk. * `spec.secondaryDisks[].type.managedDisk.spec.size.sizeGibibytes`: Size of the additional disk in gibibytes. * `spec.filesystems[].attachMode`: Write permission of the filesystem, `READ_ONLY` or `READ_WRITE`. * `spec.filesystems[].mountTag`: Tag for mounting the filesystem to the VM. * `spec.filesystems[].type.existingFilesystem.id`: ID of the filesystem created earlier. * `spec.cloudInitUserData` (optional): Configuration of VM users in the [cloud-init](https://cloud-init.io/) format. * `spec.networkInterfaces[].subnetId`: ID of the subnet to attach the VM to. * `spec.networkInterfaces[].ipAddress`: Private IP address settings. * `spec.networkInterfaces[].publicIpAddress`: Public IP address settings. In the example, an empty `PublicIPAddress` assigns a dynamic public IP address. * `spec.hostname` (optional): Hostname for the VM's [FQDN](https://docs.nebius.com/compute/virtual-machines/fqdn.md). By default, the FQDN has the `..compute.internal.` format. * `spec.reservationPolicy.policy` (optional): Policy for reservation usage. You can use [reservations of capacity resources](https://docs.nebius.com/compute/virtual-machines/reservations.md) and run your VM based on them. * `spec.recoveryPolicy` (optional): Defines what Compute does with the VM after it is preempted or fails. * `spec.preemptible.onPreemption` (optional; for preemptible VMs only): Specifies what happens when the VM is preempted. The only supported value is `STOP`: Compute stops the VM without deleting or restarting it. ## Examples ### Create a VM without an additional disk or filesystem To create a VM, run the following command: ```bash nebius compute instance create \ --name \ --resources-platform \ --resources-preset \ --boot-disk-managed-disk-name managed-boot-disk \ --boot-disk-managed-disk-type network_ssd \ --boot-disk-managed-disk-size-gibibytes 10 \ --boot-disk-managed-disk-source-image-family-image-family ubuntu24.04-driverless \ --boot-disk-attach-mode READ_WRITE \ --network-interfaces '[{"name": "eth0", "ip_address": {}, "public_ip_address": {}, "subnet_id": ""}]' ``` The VM is provided with a dynamic public IPv4 address. For more information about the command parameters, see [Create a VM](https://docs.nebius.com/compute/virtual-machines/manage.md#create-a-vm). 1. [Install and configure](https://docs.nebius.com/terraform-provider/install.md) the Nebius AI Cloud provider for Terraform. 2. Create a VM: ```hcl resource "nebius_compute_v1_instance" "my_vm" { name = "" parent_id = "" resources = { platform = "" preset = "" } boot_disk = { managed_disk = { name = "managed-boot-disk" spec = { type = "network_ssd" size_gibibytes = 10 source_image_family = { image_family = "ubuntu24.04-driverless" } } } attach_mode = "" } network_interfaces = [ { name = "eth0" ip_address = {} public_ip_address = {} subnet_id = "" } ] } ``` The VM is provided with a dynamic public IPv4 address. For more information about the configuration parameters, see [Create a VM](https://docs.nebius.com/compute/virtual-machines/manage.md#create-a-vm). 3. Check that the configuration is correct: ```bash terraform validate ``` 4. Apply the changes: ```bash terraform apply ``` Create a VM: ```go simpleBootDisk := &compute.AttachedDiskSpec{ AttachMode: compute.AttachedDiskSpec_READ_WRITE, Type: &compute.AttachedDiskSpec_ManagedDisk{ ManagedDisk: &compute.ManagedDisk{ Name: "managed-boot-disk", Spec: &compute.DiskSpec{ Size: &compute.DiskSpec_SizeGibibytes{ SizeGibibytes: 10, }, Type: compute.DiskSpec_NETWORK_SSD, Source: &compute.DiskSpec_SourceImageFamily{ SourceImageFamily: &compute.SourceImageFamily{ ImageFamily: "ubuntu24.04-driverless", }, }, }, }, }, } simpleNetwork := &compute.NetworkInterfaceSpec{ Name: "eth0", SubnetId: subnetID, IpAddress: &compute.IPAddress{}, PublicIpAddress: &compute.PublicIPAddress{}, } simpleVMOperation, err := sdk.Services().Compute().V1(). Instance().Create( ctx, &compute.CreateInstanceRequest{ Metadata: &common.ResourceMetadata{ Name: "", }, Spec: &compute.InstanceSpec{ Resources: &compute.ResourcesSpec{ Platform: "", Size: &compute.ResourcesSpec_Preset{ Preset: "", }, }, BootDisk: simpleBootDisk, NetworkInterfaces: []*compute.NetworkInterfaceSpec{ simpleNetwork, }, }, }, ) if err != nil { return err } if _, err = simpleVMOperation.Wait(ctx); err != nil { return err } ``` The VM is provided with a dynamic public IPv4 address. For more information about the code parameters, see [Create a VM](https://docs.nebius.com/compute/virtual-machines/manage.md#create-a-vm). Create a VM: ```python instance_service = InstanceServiceClient(sdk) simple_vm_operation = await instance_service.create( CreateInstanceRequest( metadata=ResourceMetadata(name=""), spec=InstanceSpec( resources=ResourcesSpec( platform="", preset="", ), boot_disk=AttachedDiskSpec( attach_mode=( AttachedDiskSpec.AttachMode.READ_WRITE ), managed_disk=ManagedDisk( name="managed-boot-disk", spec=DiskSpec( type=DiskSpec.DiskType.NETWORK_SSD, source_image_family=( SourceImageFamily( image_family=( "ubuntu24.04-driverless" ), ) ), size_gibibytes=10, ), ), ), network_interfaces=[ NetworkInterfaceSpec( name="eth0", subnet_id=subnet_id, ip_address=IPAddress(), public_ip_address=PublicIPAddress(), ), ], ), ), ) await simple_vm_operation.wait() ``` The VM is provided with a dynamic public IPv4 address. For more information about the code parameters, see [Create a VM](https://docs.nebius.com/compute/virtual-machines/manage.md#create-a-vm). Create a VM: ```ts const simpleVmService = new InstanceService(sdk); const simpleVmOperation = await simpleVmService.create( CreateInstanceRequest.create({ metadata: ResourceMetadata.create({ name: "", }), spec: InstanceSpec.create({ resources: ResourcesSpec.create({ platform: "", size: { $case: "preset", preset: "", }, }), bootDisk: AttachedDiskSpec.create({ attachMode: AttachedDiskSpec_AttachMode.READ_WRITE, type: { $case: "managedDisk", managedDisk: ManagedDisk.create({ name: "managed-boot-disk", spec: DiskSpec.create({ type: DiskSpec_DiskType.NETWORK_SSD, source: { $case: "sourceImageFamily", sourceImageFamily: SourceImageFamily.create({ imageFamily: "ubuntu24.04-driverless", }), }, size: { $case: "sizeGibibytes", sizeGibibytes: 10, }, }), }), }, }), networkInterfaces: [ NetworkInterfaceSpec.create({ name: "eth0", subnetId, ipAddress: IPAddress.create({}), publicIpAddress: PublicIPAddress.create({}), }), ], }), }), ).result; await simpleVmOperation.wait(); ``` The VM is provided with a dynamic public IPv4 address. For more information about the code parameters, see [Create a VM](https://docs.nebius.com/compute/virtual-machines/manage.md#create-a-vm). ### Create a VM with an additional disk Create a VM, its boot disk and an additional disk together: ```bash nebius compute instance create \ --name \ --resources-platform \ --resources-preset \ --boot-disk-managed-disk-name managed-boot-disk \ --boot-disk-managed-disk-type network_ssd \ --boot-disk-managed-disk-size-gibibytes 10 \ --boot-disk-managed-disk-source-image-family-image-family ubuntu24.04-driverless \ --boot-disk-attach-mode READ_WRITE \ --secondary-disks "[{\"attach_mode\": \"READ_WRITE\", \"device_id\": \"device-1\", \"managed_disk\": { \"name\": \"managed-secondary-disk\", \"spec\": { \"type\": \"network_ssd\", \"size_gibibytes\": 10 }}}]" \ --network-interfaces '[{"name": "eth0", "ip_address": {}, "public_ip_address": {}, "subnet_id": ""}]' ``` The VM is provided with a dynamic public IPv4 address. For more information about the command parameters, see [Create a VM](https://docs.nebius.com/compute/virtual-machines/manage.md#create-a-vm). 1. [Install and configure](https://docs.nebius.com/terraform-provider/install.md) the Nebius AI Cloud provider for Terraform. 2. Create a VM, its boot disk and an additional disk together: ```hcl resource "nebius_compute_v1_instance" "my_vm" { name = "" parent_id = "" resources = { platform = "" preset = "" } boot_disk = { managed_disk = { name = "managed-boot-disk" spec = { type = "network_ssd" size_gibibytes = 10 source_image_family = { image_family = "ubuntu24.04-driverless" } } } attach_mode = "" } secondary_disks = [ { managed_disk = { name = "managed-additional-disk" spec = { type = "" size_gibibytes = } } attach_mode = "" device_id = "device-1" } ] network_interfaces = [ { name = "eth0" ip_address = {} public_ip_address = {} subnet_id = "" } ] } ``` The VM is provided with a dynamic public IPv4 address. For more information about the configuration parameters, see [Create a VM](https://docs.nebius.com/compute/virtual-machines/manage.md#create-a-vm). 3. Check that the configuration is correct: ```bash terraform validate ``` 4. Apply the changes: ```bash terraform apply ``` Create a VM, its boot disk and an additional disk together: ```go additionalBootDisk := &compute.AttachedDiskSpec{ AttachMode: compute.AttachedDiskSpec_READ_WRITE, Type: &compute.AttachedDiskSpec_ManagedDisk{ ManagedDisk: &compute.ManagedDisk{ Name: "managed-boot-disk", Spec: &compute.DiskSpec{ Size: &compute.DiskSpec_SizeGibibytes{ SizeGibibytes: 10, }, Type: compute.DiskSpec_NETWORK_SSD, Source: &compute.DiskSpec_SourceImageFamily{ SourceImageFamily: &compute.SourceImageFamily{ ImageFamily: "ubuntu24.04-driverless", }, }, }, }, }, } additionalDisk := &compute.AttachedDiskSpec{ AttachMode: compute.AttachedDiskSpec_READ_WRITE, DeviceId: "device-1", Type: &compute.AttachedDiskSpec_ManagedDisk{ ManagedDisk: &compute.ManagedDisk{ Name: "managed-secondary-disk", Spec: &compute.DiskSpec{ Size: &compute.DiskSpec_SizeGibibytes{ SizeGibibytes: , }, Type: compute.DiskSpec_NETWORK_SSD, }, }, }, } additionalNetwork := &compute.NetworkInterfaceSpec{ Name: "eth0", SubnetId: subnetID, IpAddress: &compute.IPAddress{}, PublicIpAddress: &compute.PublicIPAddress{}, } additionalVMOperation, err := sdk.Services().Compute().V1(). Instance().Create( ctx, &compute.CreateInstanceRequest{ Metadata: &common.ResourceMetadata{ Name: "", }, Spec: &compute.InstanceSpec{ Resources: &compute.ResourcesSpec{ Platform: "", Size: &compute.ResourcesSpec_Preset{ Preset: "", }, }, BootDisk: additionalBootDisk, SecondaryDisks: []*compute.AttachedDiskSpec{ additionalDisk, }, NetworkInterfaces: []*compute.NetworkInterfaceSpec{ additionalNetwork, }, }, }, ) if err != nil { return err } if _, err = additionalVMOperation.Wait(ctx); err != nil { return err } ``` The VM is provided with a dynamic public IPv4 address. For more information about the code parameters, see [Create a VM](https://docs.nebius.com/compute/virtual-machines/manage.md#create-a-vm). Create a VM, its boot disk and an additional disk together: ```python instance_service = InstanceServiceClient(sdk) additional_vm_operation = await instance_service.create( CreateInstanceRequest( metadata=ResourceMetadata(name=""), spec=InstanceSpec( resources=ResourcesSpec( platform="", preset="", ), boot_disk=AttachedDiskSpec( attach_mode=( AttachedDiskSpec.AttachMode.READ_WRITE ), managed_disk=ManagedDisk( name="managed-boot-disk", spec=DiskSpec( type=DiskSpec.DiskType.NETWORK_SSD, source_image_family=( SourceImageFamily( image_family=( "ubuntu24.04-driverless" ), ) ), size_gibibytes=10, ), ), ), secondary_disks=[ AttachedDiskSpec( attach_mode=( AttachedDiskSpec.AttachMode.READ_WRITE ), managed_disk=ManagedDisk( name="managed-secondary-disk", spec=DiskSpec( type=( DiskSpec.DiskType.NETWORK_SSD ), size_gibibytes=, ), ), device_id="device-1", ), ], network_interfaces=[ NetworkInterfaceSpec( name="eth0", subnet_id=subnet_id, ip_address=IPAddress(), public_ip_address=PublicIPAddress(), ), ], ), ), ) await additional_vm_operation.wait() ``` The VM is provided with a dynamic public IPv4 address. For more information about the code parameters, see [Create a VM](https://docs.nebius.com/compute/virtual-machines/manage.md#create-a-vm). Create a VM, its boot disk and an additional disk together: ```ts const additionalVmService = new InstanceService(sdk); const additionalVmOperation = await additionalVmService.create( CreateInstanceRequest.create({ metadata: ResourceMetadata.create({ name: "", }), spec: InstanceSpec.create({ resources: ResourcesSpec.create({ platform: "", size: { $case: "preset", preset: "", }, }), bootDisk: AttachedDiskSpec.create({ attachMode: AttachedDiskSpec_AttachMode.READ_WRITE, type: { $case: "managedDisk", managedDisk: ManagedDisk.create({ name: "managed-boot-disk", spec: DiskSpec.create({ type: DiskSpec_DiskType.NETWORK_SSD, source: { $case: "sourceImageFamily", sourceImageFamily: SourceImageFamily.create({ imageFamily: "ubuntu24.04-driverless", }), }, size: { $case: "sizeGibibytes", sizeGibibytes: 10, }, }), }), }, }), secondaryDisks: [ AttachedDiskSpec.create({ attachMode: AttachedDiskSpec_AttachMode.READ_WRITE, deviceId: "device-1", type: { $case: "managedDisk", managedDisk: ManagedDisk.create({ name: "managed-secondary-disk", spec: DiskSpec.create({ type: DiskSpec_DiskType.NETWORK_SSD, size: { $case: "sizeGibibytes", sizeGibibytes: , }, }), }), }, }), ], networkInterfaces: [ NetworkInterfaceSpec.create({ name: "eth0", subnetId, ipAddress: IPAddress.create({}), publicIpAddress: PublicIPAddress.create({}), }), ], }), }), ).result; await additionalVmOperation.wait(); ``` The VM is provided with a dynamic public IPv4 address. For more information about the code parameters, see [Create a VM](https://docs.nebius.com/compute/virtual-machines/manage.md#create-a-vm). ### Create a VM with a filesystem 1. Create a filesystem: ```bash nebius compute filesystem create \ --name \ --size-gibibytes 10 \ --type network_ssd \ --block-size-bytes 4096 ``` Save the filesystem ID from the output `metadata.id` parameter. [Mount filesystems](https://docs.nebius.com/compute/storage/use.md#shared-filesystems) after you create the VM. Otherwise, the filesystems are not attached to the VM. 2. Create the VM: ```bash nebius compute instance create \ --name \ --stopped \ --resources-platform \ --resources-preset \ --boot-disk-managed-disk-name managed-boot-disk \ --boot-disk-managed-disk-type network_ssd \ --boot-disk-managed-disk-size-gibibytes 10 \ --boot-disk-managed-disk-source-image-family-image-family ubuntu24.04-driverless \ --boot-disk-attach-mode READ_WRITE \ --filesystems '[{"existing_filesystem": {"id": ""}, "attach_mode": "READ_WRITE", "mount_tag": ""}]' \ --network-interfaces '[{"name": "eth0", "ip_address": {}, "public_ip_address": {}, "subnet_id": ""}]' ``` The VM is provided with a dynamic public IPv4 address. For more information about the command parameters, see [Create a VM](https://docs.nebius.com/compute/virtual-machines/manage.md#create-a-vm). 1. [Install and configure](https://docs.nebius.com/terraform-provider/install.md) the Nebius AI Cloud provider for Terraform. 2. Create a filesystem: ```hcl resource "nebius_compute_v1_filesystem" "my_filesystem" { name = "" parent_id = "" size_gibibytes = 10 type = "NETWORK_SSD" block_size_bytes = 4096 } ``` For more information, see [Volume parameters](https://docs.nebius.com/compute/storage/manage.md#volume-parameters). [Mount filesystems](https://docs.nebius.com/compute/storage/use.md#shared-filesystems) after you create the VM. Otherwise, the filesystems are not attached to the VM. 3. Create the VM: ```hcl resource "nebius_compute_v1_instance" "my_vm" { name = "" parent_id = "" resources = { platform = "" preset = "" } boot_disk = { managed_disk = { name = "managed-boot-disk" spec = { type = "network_ssd" size_gibibytes = 10 source_image_family = { image_family = "ubuntu24.04-driverless" } } } attach_mode = "" } filesystems = [ { existing_filesystem = { id = nebius_compute_v1_filesystem.my_filesystem.id } attach_mode = "" mount_tag = "" } ] network_interfaces = [ { name = "eth0" ip_address = {} public_ip_address = {} subnet_id = "" } ] } ``` The VM is provided with a dynamic public IPv4 address. For more information about the configuration parameters, see [Create a VM](https://docs.nebius.com/compute/virtual-machines/manage.md#create-a-vm). 4. Check that the configuration is correct: ```bash terraform validate ``` 5. Apply the changes: ```bash terraform apply ``` 1. Create a filesystem: ```go filesystemOperation, err := sdk.Services().Compute().V1(). Filesystem().Create( ctx, &compute.CreateFilesystemRequest{ Metadata: &common.ResourceMetadata{ Name: "", }, Spec: &compute.FilesystemSpec{ Size: &compute.FilesystemSpec_SizeGibibytes{ SizeGibibytes: 10, }, BlockSizeBytes: 4096, Type: compute.FilesystemSpec_NETWORK_SSD, }, }, ) if err != nil { return err } if _, err = filesystemOperation.Wait(ctx); err != nil { return err } ``` [Mount filesystems](https://docs.nebius.com/compute/storage/use.md#shared-filesystems) after you create the VM. Otherwise, the filesystems are not attached to the VM. 2. Create the VM: ```go filesystemBootDisk := &compute.AttachedDiskSpec{ AttachMode: compute.AttachedDiskSpec_READ_WRITE, Type: &compute.AttachedDiskSpec_ManagedDisk{ ManagedDisk: &compute.ManagedDisk{ Name: "managed-boot-disk", Spec: &compute.DiskSpec{ Size: &compute.DiskSpec_SizeGibibytes{ SizeGibibytes: 10, }, Type: compute.DiskSpec_NETWORK_SSD, Source: &compute.DiskSpec_SourceImageFamily{ SourceImageFamily: &compute.SourceImageFamily{ ImageFamily: "ubuntu24.04-driverless", }, }, }, }, }, } attachedFilesystem := &compute.AttachedFilesystemSpec{ AttachMode: compute.AttachedFilesystemSpec_READ_WRITE, MountTag: "", Type: &compute.AttachedFilesystemSpec_ExistingFilesystem{ ExistingFilesystem: &compute.ExistingFilesystem{ Id: filesystemID, }, }, } filesystemNetwork := &compute.NetworkInterfaceSpec{ Name: "eth0", SubnetId: subnetID, IpAddress: &compute.IPAddress{}, PublicIpAddress: &compute.PublicIPAddress{}, } filesystemVMOperation, err := sdk.Services().Compute().V1(). Instance().Create( ctx, &compute.CreateInstanceRequest{ Metadata: &common.ResourceMetadata{ Name: "", }, Spec: &compute.InstanceSpec{ Stopped: , Resources: &compute.ResourcesSpec{ Platform: "", Size: &compute.ResourcesSpec_Preset{ Preset: "", }, }, BootDisk: filesystemBootDisk, Filesystems: []*compute.AttachedFilesystemSpec{ attachedFilesystem, }, NetworkInterfaces: []*compute.NetworkInterfaceSpec{ filesystemNetwork, }, }, }, ) if err != nil { return err } if _, err = filesystemVMOperation.Wait(ctx); err != nil { return err } ``` The VM is provided with a dynamic public IPv4 address. For more information about the code parameters, see [Create a VM](https://docs.nebius.com/compute/virtual-machines/manage.md#create-a-vm). 1. Create a filesystem: ```python filesystem_service = FilesystemServiceClient(sdk) filesystem_operation = await filesystem_service.create( CreateFilesystemRequest( metadata=ResourceMetadata(name=""), spec=FilesystemSpec( block_size_bytes=4096, type=FilesystemSpec.FilesystemType.NETWORK_SSD, size_gibibytes=10, ), ), ) await filesystem_operation.wait() ``` [Mount filesystems](https://docs.nebius.com/compute/storage/use.md#shared-filesystems) after you create the VM. Otherwise, the filesystems are not attached to the VM. 2. Create the VM: ```python instance_service = InstanceServiceClient(sdk) filesystem_vm_operation = await instance_service.create( CreateInstanceRequest( metadata=ResourceMetadata(name=""), spec=InstanceSpec( stopped=, resources=ResourcesSpec( platform="", preset="", ), boot_disk=AttachedDiskSpec( attach_mode=( AttachedDiskSpec.AttachMode.READ_WRITE ), managed_disk=ManagedDisk( name="managed-boot-disk", spec=DiskSpec( type=DiskSpec.DiskType.NETWORK_SSD, source_image_family=( SourceImageFamily( image_family=( "ubuntu24.04-driverless" ), ) ), size_gibibytes=10, ), ), ), filesystems=[ AttachedFilesystemSpec( attach_mode=( AttachedFilesystemSpec.AttachMode.READ_WRITE ), existing_filesystem=ExistingFilesystem( id=filesystem_id, ), mount_tag="", ), ], network_interfaces=[ NetworkInterfaceSpec( name="eth0", subnet_id=subnet_id, ip_address=IPAddress(), public_ip_address=PublicIPAddress(), ), ], ), ), ) await filesystem_vm_operation.wait() ``` The VM is provided with a dynamic public IPv4 address. For more information about the code parameters, see [Create a VM](https://docs.nebius.com/compute/virtual-machines/manage.md#create-a-vm). 1. Create a filesystem: ```ts const filesystemCreateService = new FilesystemService(sdk); const filesystemOperation = await filesystemCreateService.create( CreateFilesystemRequest.create({ metadata: ResourceMetadata.create({ name: "", }), spec: FilesystemSpec.create({ blockSizeBytes: 4096, type: FilesystemSpec_FilesystemType.NETWORK_SSD, size: { $case: "sizeGibibytes", sizeGibibytes: 10, }, }), }), ).result; await filesystemOperation.wait(); ``` [Mount filesystems](https://docs.nebius.com/compute/storage/use.md#shared-filesystems) after you create the VM. Otherwise, the filesystems are not attached to the VM. 2. Create the VM: ```ts const filesystemVmService = new InstanceService(sdk); const filesystemVmOperation = await filesystemVmService.create( CreateInstanceRequest.create({ metadata: ResourceMetadata.create({ name: "", }), spec: InstanceSpec.create({ stopped: , resources: ResourcesSpec.create({ platform: "", size: { $case: "preset", preset: "", }, }), bootDisk: AttachedDiskSpec.create({ attachMode: AttachedDiskSpec_AttachMode.READ_WRITE, type: { $case: "managedDisk", managedDisk: ManagedDisk.create({ name: "managed-boot-disk", spec: DiskSpec.create({ type: DiskSpec_DiskType.NETWORK_SSD, source: { $case: "sourceImageFamily", sourceImageFamily: SourceImageFamily.create({ imageFamily: "ubuntu24.04-driverless", }), }, size: { $case: "sizeGibibytes", sizeGibibytes: 10, }, }), }), }, }), filesystems: [ AttachedFilesystemSpec.create({ attachMode: AttachedFilesystemSpec_AttachMode.READ_WRITE, mountTag: "", type: { $case: "existingFilesystem", existingFilesystem: ExistingFilesystem.create({ id: filesystemId, }), }, }), ], networkInterfaces: [ NetworkInterfaceSpec.create({ name: "eth0", subnetId, ipAddress: IPAddress.create({}), publicIpAddress: PublicIPAddress.create({}), }), ], }), }), ).result; await filesystemVmOperation.wait(); ``` The VM is provided with a dynamic public IPv4 address. For more information about the code parameters, see [Create a VM](https://docs.nebius.com/compute/virtual-machines/manage.md#create-a-vm). ### Create a VM with local SSD disks Local SSD disks are available only for supported platforms and presets. For details, see [Availability](https://docs.nebius.com/compute/storage/local-disks.md#availability). To create a VM with local SSD disks, run the following command: ```bash nebius compute instance create \ --name \ --stopped \ --resources-platform \ --resources-preset \ --boot-disk-managed-disk-name managed-boot-disk \ --boot-disk-managed-disk-type network_ssd \ --boot-disk-managed-disk-size-gibibytes 10 \ --boot-disk-managed-disk-source-image-family-image-family ubuntu24.04-driverless \ --boot-disk-attach-mode READ_WRITE \ --network-interfaces '[{"name": "eth0", "ip_address": {}, "public_ip_address": {}, "subnet_id": ""}]' \ --local-disks-passthrough-group-requested true ``` This adds ephemeral local storage to the VM. The example creates a private IPv4 address and doesn't assign a public IPv4 address. For more information about the command parameters, see [Create a VM](https://docs.nebius.com/compute/virtual-machines/manage.md#create-a-vm). 1. [Install and configure](https://docs.nebius.com/terraform-provider/install.md) the Nebius AI Cloud provider for Terraform. 2. Create the VM: ```hcl resource "nebius_compute_v1_instance" "my_vm" { name = "" parent_id = "" resources = { platform = "" preset = "" } boot_disk = { managed_disk = { name = "managed-boot-disk" spec = { type = "network_ssd" size_gibibytes = 10 source_image_family = { image_family = "ubuntu24.04-driverless" } } } attach_mode = "" } network_interfaces = [ { name = "eth0" ip_address = {} public_ip_address = {} subnet_id = "" } ] local_disks = { passthrough_group = { requested = true } } } ``` This provides a VM with ephemeral local storage. The example creates a private IPv4 address and doesn't assign a public IPv4 address. For more information about the configuration parameters, see [Create a VM](https://docs.nebius.com/compute/virtual-machines/manage.md#create-a-vm). 3. Check that the configuration is correct: ```bash terraform validate ``` 4. Apply the changes: ```bash terraform apply ``` Create a VM with local SSD disks: ```go localBootDisk := &compute.AttachedDiskSpec{ AttachMode: compute.AttachedDiskSpec_READ_WRITE, Type: &compute.AttachedDiskSpec_ManagedDisk{ ManagedDisk: &compute.ManagedDisk{ Name: "managed-boot-disk", Spec: &compute.DiskSpec{ Size: &compute.DiskSpec_SizeGibibytes{ SizeGibibytes: 10, }, Type: compute.DiskSpec_NETWORK_SSD, Source: &compute.DiskSpec_SourceImageFamily{ SourceImageFamily: &compute.SourceImageFamily{ ImageFamily: "ubuntu24.04-driverless", }, }, }, }, }, } localDiskNetwork := &compute.NetworkInterfaceSpec{ Name: "eth0", SubnetId: subnetID, IpAddress: &compute.IPAddress{}, PublicIpAddress: &compute.PublicIPAddress{}, } passthroughRequest := &compute.PassthroughGroupRequest{ Requested: true, } localDiskRequest := &compute.LocalDisksSpec_PassthroughGroup{ PassthroughGroup: passthroughRequest, } localDiskVMOperation, err := sdk.Services().Compute().V1(). Instance().Create( ctx, &compute.CreateInstanceRequest{ Metadata: &common.ResourceMetadata{ Name: "", }, Spec: &compute.InstanceSpec{ Stopped: , Resources: &compute.ResourcesSpec{ Platform: "", Size: &compute.ResourcesSpec_Preset{ Preset: "", }, }, BootDisk: localBootDisk, NetworkInterfaces: []*compute.NetworkInterfaceSpec{ localDiskNetwork, }, LocalDisks: &compute.LocalDisksSpec{ Request: localDiskRequest, }, }, }, ) if err != nil { return err } if _, err = localDiskVMOperation.Wait(ctx); err != nil { return err } ``` This adds ephemeral local storage to the VM. The example creates a private IPv4 address and doesn't assign a public IPv4 address. For more information about the code parameters, see [Create a VM](https://docs.nebius.com/compute/virtual-machines/manage.md#create-a-vm). Create a VM with local SSD disks: ```python instance_service = InstanceServiceClient(sdk) local_disk_vm_operation = await instance_service.create( CreateInstanceRequest( metadata=ResourceMetadata(name=""), spec=InstanceSpec( stopped=, resources=ResourcesSpec( platform="", preset="", ), boot_disk=AttachedDiskSpec( attach_mode=( AttachedDiskSpec.AttachMode.READ_WRITE ), managed_disk=ManagedDisk( name="managed-boot-disk", spec=DiskSpec( type=DiskSpec.DiskType.NETWORK_SSD, source_image_family=( SourceImageFamily( image_family=( "ubuntu24.04-driverless" ), ) ), size_gibibytes=10, ), ), ), network_interfaces=[ NetworkInterfaceSpec( name="eth0", subnet_id=subnet_id, ip_address=IPAddress(), public_ip_address=PublicIPAddress(), ), ], local_disks=LocalDisksSpec( passthrough_group=PassthroughGroupRequest( requested=True, ), ), ), ), ) await local_disk_vm_operation.wait() ``` This adds ephemeral local storage to the VM. The example creates a private IPv4 address and doesn't assign a public IPv4 address. For more information about the code parameters, see [Create a VM](https://docs.nebius.com/compute/virtual-machines/manage.md#create-a-vm). Create a VM with local SSD disks: ```ts const localDiskVmService = new InstanceService(sdk); const localDiskVmOperation = await localDiskVmService.create( CreateInstanceRequest.create({ metadata: ResourceMetadata.create({ name: "", }), spec: InstanceSpec.create({ stopped: , resources: ResourcesSpec.create({ platform: "", size: { $case: "preset", preset: "", }, }), bootDisk: AttachedDiskSpec.create({ attachMode: AttachedDiskSpec_AttachMode.READ_WRITE, type: { $case: "managedDisk", managedDisk: ManagedDisk.create({ name: "managed-boot-disk", spec: DiskSpec.create({ type: DiskSpec_DiskType.NETWORK_SSD, source: { $case: "sourceImageFamily", sourceImageFamily: SourceImageFamily.create({ imageFamily: "ubuntu24.04-driverless", }), }, size: { $case: "sizeGibibytes", sizeGibibytes: 10, }, }), }), }, }), networkInterfaces: [ NetworkInterfaceSpec.create({ name: "eth0", subnetId, ipAddress: IPAddress.create({}), publicIpAddress: PublicIPAddress.create({}), }), ], localDisks: LocalDisksSpec.create({ request: { $case: "passthroughGroup", passthroughGroup: PassthroughGroupRequest.create({ requested: true, }), }, }), }), }), ).result; await localDiskVmOperation.wait(); ``` This adds ephemeral local storage to the VM. The example creates a private IPv4 address and doesn't assign a public IPv4 address. For more information about the code parameters, see [Create a VM](https://docs.nebius.com/compute/virtual-machines/manage.md#create-a-vm). ### Create a VM with standalone boot and additional disks By default, when you create a VM, its disks are created along with this VM. Such disks are called [VM-managed](https://docs.nebius.com/compute/storage/types.md#vm-managed-and-standalone-disks): their lifecycle is tied to the VM, so when you delete the VM, its disks are deleted along with it. Alternatively, if you already have a disk or you want to keep the disk after the VM deletion, create a standalone disk first and attach it to the VM afterward. To create standalone disks and a VM with them, do the following: 1. Create a boot disk: ```bash nebius compute disk create \ --name \ --size-gibibytes 50 \ --type network_ssd \ --source-image-family-image-family ubuntu24.04-cuda13.0 \ --block-size-bytes 4096 ``` Save the disk ID from the output `metadata.id` parameter. For more information about disk creation, see [Managing Compute volumes](https://docs.nebius.com/compute/storage/manage.md). 2. Create an additional disk: ```bash nebius compute disk create \ --name \ --size-gibibytes 10 \ --type network_ssd \ --block-size-bytes 4096 ``` Save the disk ID from the output `metadata.id` parameter. After you create the VM, [mount the additional disks](https://docs.nebius.com/compute/storage/use.md#how-to-mount-volumes-to-vms) to it. Otherwise, the VM's operating system does not recognize these disks. 3. Create a VM: ```bash nebius compute instance create \ --name \ --resources-platform \ --resources-preset \ --boot-disk-existing-disk-id \ --boot-disk-attach-mode \ --boot-disk-device-id \ --secondary-disks "[{\"existing_disk\": {\"id\": \"\"}, \"attach_mode\": \"READ_WRITE\", \"device_id\": \"device-1\"}]" \ --network-interfaces '[{"name": "eth0", "ip_address": {}, "public_ip_address": {}, "subnet_id": ""}]' ``` The VM is provided with a dynamic public IPv4 address. For more information about the command parameters, see [Create a VM](https://docs.nebius.com/compute/virtual-machines/manage.md#create-a-vm). 1. [Install and configure](https://docs.nebius.com/terraform-provider/install.md) the Nebius AI Cloud provider for Terraform. 2. Create a boot disk by using the following configuration: ```hcl resource "nebius_compute_v1_disk" "my_boot_disk" { name = "" parent_id = "" size_gibibytes = "50" type = "NETWORK_SSD" source_image_family = { image_family = "ubuntu24.04-cuda13.0" } block_size_bytes = 4096 } ``` Set the `parent_id` to your [Project ID](https://docs.nebius.com/iam/manage-projects.md#terraform-3). For more information, see [Volume parameters](https://docs.nebius.com/compute/storage/manage.md#volume-parameters). 3. Create an additional disk: ```hcl resource "nebius_compute_v1_disk" "my_additional_disk" { name = "" parent_id = "" size_gibibytes = "10" type = "NETWORK_SSD" block_size_bytes = 4096 } ``` After you create the VM, [mount the additional disks](https://docs.nebius.com/compute/storage/use.md#how-to-mount-volumes-to-vms) to it. Otherwise, the VM's operating system does not recognize these disks. 4. Create a VM: ```hcl resource "nebius_compute_v1_instance" "my_vm" { name = "" parent_id = "" resources = { platform = "" preset = "" } boot_disk = { existing_disk = { id = nebius_compute_v1_disk.my_boot_disk.id } attach_mode = "" } secondary_disks = [ { existing_disk = { id = nebius_compute_v1_disk.my_additional_disk.id } attach_mode = "" device_id = "" } ] network_interfaces = [ { name = "eth0" ip_address = {} public_ip_address = {} subnet_id = "" } ] } ``` The VM is provided with a dynamic public IPv4 address. For more information about the configuration parameters, see [Create a VM](https://docs.nebius.com/compute/virtual-machines/manage.md#create-a-vm). 5. Check that the configuration is correct: ```bash terraform validate ``` 6. Apply the changes: ```bash terraform apply ``` 1. Create a boot disk: ```go bootDiskOperation, err := sdk.Services().Compute().V1(). Disk().Create( ctx, &compute.CreateDiskRequest{ Metadata: &common.ResourceMetadata{ Name: "", }, Spec: &compute.DiskSpec{ Size: &compute.DiskSpec_SizeGibibytes{ SizeGibibytes: 50, }, BlockSizeBytes: 4096, Type: compute.DiskSpec_NETWORK_SSD, Source: &compute.DiskSpec_SourceImageFamily{ SourceImageFamily: &compute.SourceImageFamily{ ImageFamily: "ubuntu24.04-cuda13.0", }, }, }, }, ) if err != nil { return err } if _, err = bootDiskOperation.Wait(ctx); err != nil { return err } ``` For more information about disk creation, see [Managing Compute volumes](https://docs.nebius.com/compute/storage/manage.md). 2. Create an additional disk: ```go addDiskOperation, err := sdk.Services().Compute().V1(). Disk().Create( ctx, &compute.CreateDiskRequest{ Metadata: &common.ResourceMetadata{ Name: "", }, Spec: &compute.DiskSpec{ Size: &compute.DiskSpec_SizeGibibytes{ SizeGibibytes: 10, }, BlockSizeBytes: 4096, Type: compute.DiskSpec_NETWORK_SSD, }, }, ) if err != nil { return err } if _, err = addDiskOperation.Wait(ctx); err != nil { return err } ``` After you create the VM, [mount the additional disks](https://docs.nebius.com/compute/storage/use.md#how-to-mount-volumes-to-vms) to it. Otherwise, the VM's operating system does not recognize these disks. 3. Create a VM: ```go standaloneNetwork := &compute.NetworkInterfaceSpec{ Name: "eth0", SubnetId: subnetID, IpAddress: &compute.IPAddress{}, PublicIpAddress: &compute.PublicIPAddress{}, } standaloneAttachMode := compute.AttachedDiskSpec_READ_WRITE standaloneVMOperation, err := sdk.Services().Compute().V1(). Instance().Create( ctx, &compute.CreateInstanceRequest{ Metadata: &common.ResourceMetadata{ Name: "", }, Spec: &compute.InstanceSpec{ Resources: &compute.ResourcesSpec{ Platform: "", Size: &compute.ResourcesSpec_Preset{ Preset: "", }, }, BootDisk: &compute.AttachedDiskSpec{ AttachMode: standaloneAttachMode, DeviceId: "", Type: &compute.AttachedDiskSpec_ExistingDisk{ ExistingDisk: &compute.ExistingDisk{ Id: bootDiskID, }, }, }, SecondaryDisks: []*compute.AttachedDiskSpec{ { AttachMode: standaloneAttachMode, DeviceId: "", Type: &compute.AttachedDiskSpec_ExistingDisk{ ExistingDisk: &compute.ExistingDisk{ Id: additionalDiskID, }, }, }, }, NetworkInterfaces: []*compute.NetworkInterfaceSpec{ standaloneNetwork, }, }, }, ) if err != nil { return err } if _, err = standaloneVMOperation.Wait(ctx); err != nil { return err } ``` The VM is provided with a dynamic public IPv4 address. For more information about the code parameters, see [Create a VM](https://docs.nebius.com/compute/virtual-machines/manage.md#create-a-vm). 1. Create a boot disk: ```python disk_service = DiskServiceClient(sdk) boot_disk_operation = await disk_service.create( CreateDiskRequest( metadata=ResourceMetadata(name=""), spec=DiskSpec( block_size_bytes=4096, type=DiskSpec.DiskType.NETWORK_SSD, source_image_family=SourceImageFamily( image_family="ubuntu24.04-cuda13.0", ), size_gibibytes=50, ), ), ) await boot_disk_operation.wait() ``` For more information about disk creation, see [Managing Compute volumes](https://docs.nebius.com/compute/storage/manage.md). 2. Create an additional disk: ```python disk_service = DiskServiceClient(sdk) additional_disk_operation = await disk_service.create( CreateDiskRequest( metadata=ResourceMetadata( name="", ), spec=DiskSpec( block_size_bytes=4096, type=DiskSpec.DiskType.NETWORK_SSD, size_gibibytes=10, ), ), ) await additional_disk_operation.wait() ``` After you create the VM, [mount the additional disks](https://docs.nebius.com/compute/storage/use.md#how-to-mount-volumes-to-vms) to it. Otherwise, the VM's operating system does not recognize these disks. 3. Create a VM: ```python instance_service = InstanceServiceClient(sdk) standalone_vm_operation = await instance_service.create( CreateInstanceRequest( metadata=ResourceMetadata(name=""), spec=InstanceSpec( resources=ResourcesSpec( platform="", preset="", ), boot_disk=AttachedDiskSpec( attach_mode=AttachedDiskSpec.AttachMode.READ_WRITE, existing_disk=ExistingDisk(id=boot_disk_id), device_id="", ), secondary_disks=[ AttachedDiskSpec( attach_mode=( AttachedDiskSpec.AttachMode.READ_WRITE ), existing_disk=ExistingDisk( id=additional_disk_id, ), device_id="", ), ], network_interfaces=[ NetworkInterfaceSpec( name="eth0", subnet_id=subnet_id, ip_address=IPAddress(), public_ip_address=PublicIPAddress(), ), ], ), ), ) await standalone_vm_operation.wait() ``` The VM is provided with a dynamic public IPv4 address. For more information about the code parameters, see [Create a VM](https://docs.nebius.com/compute/virtual-machines/manage.md#create-a-vm). 1. Create a boot disk: ```ts const bootDiskCreateService = new DiskService(sdk); const bootDiskOperation = await bootDiskCreateService.create( CreateDiskRequest.create({ metadata: ResourceMetadata.create({ name: "", }), spec: DiskSpec.create({ blockSizeBytes: 4096, type: DiskSpec_DiskType.NETWORK_SSD, source: { $case: "sourceImageFamily", sourceImageFamily: SourceImageFamily.create({ imageFamily: "ubuntu24.04-cuda13.0", }), }, size: { $case: "sizeGibibytes", sizeGibibytes: 50, }, }), }), ).result; await bootDiskOperation.wait(); ``` For more information about disk creation, see [Managing Compute volumes](https://docs.nebius.com/compute/storage/manage.md). 2. Create an additional disk: ```ts const additionalDiskCreateService = new DiskService(sdk); const additionalDiskOperation = await additionalDiskCreateService.create( CreateDiskRequest.create({ metadata: ResourceMetadata.create({ name: "", }), spec: DiskSpec.create({ blockSizeBytes: 4096, type: DiskSpec_DiskType.NETWORK_SSD, size: { $case: "sizeGibibytes", sizeGibibytes: 10, }, }), }), ).result; await additionalDiskOperation.wait(); ``` After you create the VM, [mount the additional disks](https://docs.nebius.com/compute/storage/use.md#how-to-mount-volumes-to-vms) to it. Otherwise, the VM's operating system does not recognize these disks. 3. Create a VM: ```ts const standaloneVmService = new InstanceService(sdk); const standaloneVmOperation = await standaloneVmService.create( CreateInstanceRequest.create({ metadata: ResourceMetadata.create({ name: "", }), spec: InstanceSpec.create({ resources: ResourcesSpec.create({ platform: "", size: { $case: "preset", preset: "", }, }), bootDisk: AttachedDiskSpec.create({ attachMode: AttachedDiskSpec_AttachMode.READ_WRITE, deviceId: "", type: { $case: "existingDisk", existingDisk: ExistingDisk.create({ id: bootDiskId, }), }, }), secondaryDisks: [ AttachedDiskSpec.create({ attachMode: AttachedDiskSpec_AttachMode.READ_WRITE, deviceId: "", type: { $case: "existingDisk", existingDisk: ExistingDisk.create({ id: additionalDiskId, }), }, }), ], networkInterfaces: [ NetworkInterfaceSpec.create({ name: "eth0", subnetId, ipAddress: IPAddress.create({}), publicIpAddress: PublicIPAddress.create({}), }), ], }), }), ).result; await standaloneVmOperation.wait(); ``` The VM is provided with a dynamic public IPv4 address. For more information about the code parameters, see [Create a VM](https://docs.nebius.com/compute/virtual-machines/manage.md#create-a-vm). ### Create a VM within a GPU cluster If you want to create a VM with 8 GPUs (for example, for training models), create a GPU cluster for the VM. By using InfiniBand™, the cluster accelerates tasks that require high-performance computing (HPC) power. 1. Create a GPU cluster: ```bash nebius compute gpu-cluster create \ --name \ --infiniband-fabric ``` To select the fabric, see [InfiniBand™ fabrics](https://docs.nebius.com/compute/clusters/gpu/index.md#infiniband-fabrics). Save the cluster ID from the output `metadata.id` parameter. 2. Create a VM: ```bash nebius compute instance create \ --name \ --resources-platform \ --resources-preset \ --boot-disk-managed-disk-name managed-boot-disk \ --boot-disk-managed-disk-type network_ssd \ --boot-disk-managed-disk-size-gibibytes 10 \ --boot-disk-managed-disk-source-image-family-image-family ubuntu24.04-cuda13.0 \ --boot-disk-attach-mode READ_WRITE \ --network-interfaces '[{"name": "eth0", "ip_address": {}, "public_ip_address": {}, "subnet_id": ""}]' \ --gpu-cluster-id ``` The VM is provided with a dynamic public IPv4 address. For more information about the command parameters, see [Create a VM](https://docs.nebius.com/compute/virtual-machines/manage.md#create-a-vm). 1. [Install and configure](https://docs.nebius.com/terraform-provider/install.md) the Nebius AI Cloud provider for Terraform. 2. Create a GPU cluster: ```hcl resource "nebius_compute_v1_gpu_cluster" "my_gpu_cluster" { name = "" parent_id = "" infiniband_fabric = "" } ``` To select the fabric, see [InfiniBand™ fabrics](https://docs.nebius.com/compute/clusters/gpu/index.md#infiniband-fabrics). 3. Create a VM: ```hcl resource "nebius_compute_v1_instance" "my_vm" { name = "" parent_id = "" resources = { platform = "" preset = "" } boot_disk = { managed_disk = { name = "managed-boot-disk" spec = { type = "network_ssd" size_gibibytes = 10 source_image_family = { image_family = "ubuntu24.04-cuda13.0" } } } attach_mode = "" } network_interfaces = [ { name = "eth0" ip_address = {} public_ip_address = {} subnet_id = "" } ] gpu_cluster = { id = nebius_compute_v1_gpu_cluster.my_gpu_cluster.id } } ``` The VM is provided with a dynamic public IPv4 address. For more information about the configuration parameters, see [Create a VM](https://docs.nebius.com/compute/virtual-machines/manage.md#create-a-vm). 4. Check that the configuration is correct: ```bash terraform validate ``` 5. Apply the changes: ```bash terraform apply ``` 1. Create a GPU cluster: ```go gpuClusterOperation, err := sdk.Services().Compute().V1(). GpuCluster().Create( ctx, &compute.CreateGpuClusterRequest{ Metadata: &common.ResourceMetadata{ Name: "", }, Spec: &compute.GpuClusterSpec{ InfinibandFabric: "", }, }, ) if err != nil { return err } if _, err = gpuClusterOperation.Wait(ctx); err != nil { return err } ``` To select the fabric, see [InfiniBand™ fabrics](https://docs.nebius.com/compute/clusters/gpu/index.md#infiniband-fabrics). 2. Create a VM: ```go clusterBootDisk := &compute.AttachedDiskSpec{ AttachMode: compute.AttachedDiskSpec_READ_WRITE, Type: &compute.AttachedDiskSpec_ManagedDisk{ ManagedDisk: &compute.ManagedDisk{ Name: "managed-boot-disk", Spec: &compute.DiskSpec{ Size: &compute.DiskSpec_SizeGibibytes{ SizeGibibytes: 10, }, Type: compute.DiskSpec_NETWORK_SSD, Source: &compute.DiskSpec_SourceImageFamily{ SourceImageFamily: &compute.SourceImageFamily{ ImageFamily: "ubuntu24.04-cuda13.0", }, }, }, }, }, } clusterNetwork := &compute.NetworkInterfaceSpec{ Name: "eth0", SubnetId: subnetID, IpAddress: &compute.IPAddress{}, PublicIpAddress: &compute.PublicIPAddress{}, } clusterVMOperation, err := sdk.Services().Compute().V1(). Instance().Create( ctx, &compute.CreateInstanceRequest{ Metadata: &common.ResourceMetadata{ Name: "", }, Spec: &compute.InstanceSpec{ Resources: &compute.ResourcesSpec{ Platform: "", Size: &compute.ResourcesSpec_Preset{ Preset: "", }, }, GpuCluster: &compute.InstanceGpuClusterSpec{ Id: gpuClusterID, }, BootDisk: clusterBootDisk, NetworkInterfaces: []*compute.NetworkInterfaceSpec{ clusterNetwork, }, }, }, ) if err != nil { return err } if _, err = clusterVMOperation.Wait(ctx); err != nil { return err } ``` The VM is provided with a dynamic public IPv4 address. For more information about the code parameters, see [Create a VM](https://docs.nebius.com/compute/virtual-machines/manage.md#create-a-vm). 1. Create a GPU cluster: ```python gpu_cluster_service = GpuClusterServiceClient(sdk) gpu_cluster_operation = await gpu_cluster_service.create( CreateGpuClusterRequest( metadata=ResourceMetadata( name="", ), spec=GpuClusterSpec( infiniband_fabric="", ), ), ) await gpu_cluster_operation.wait() ``` To select the fabric, see [InfiniBand™ fabrics](https://docs.nebius.com/compute/clusters/gpu/index.md#infiniband-fabrics). 2. Create a VM: ```python instance_service = InstanceServiceClient(sdk) cluster_vm_operation = await instance_service.create( CreateInstanceRequest( metadata=ResourceMetadata(name=""), spec=InstanceSpec( resources=ResourcesSpec( platform="", preset="", ), gpu_cluster=InstanceGpuClusterSpec( id=gpu_cluster_id, ), boot_disk=AttachedDiskSpec( attach_mode=( AttachedDiskSpec.AttachMode.READ_WRITE ), managed_disk=ManagedDisk( name="managed-boot-disk", spec=DiskSpec( type=DiskSpec.DiskType.NETWORK_SSD, source_image_family=( SourceImageFamily( image_family="ubuntu24.04-cuda13.0", ) ), size_gibibytes=10, ), ), ), network_interfaces=[ NetworkInterfaceSpec( name="eth0", subnet_id=subnet_id, ip_address=IPAddress(), public_ip_address=PublicIPAddress(), ), ], ), ), ) await cluster_vm_operation.wait() ``` The VM is provided with a dynamic public IPv4 address. For more information about the code parameters, see [Create a VM](https://docs.nebius.com/compute/virtual-machines/manage.md#create-a-vm). 1. Create a GPU cluster: ```ts const gpuClusterCreateService = new GpuClusterService(sdk); const gpuClusterOperation = await gpuClusterCreateService.create( CreateGpuClusterRequest.create({ metadata: ResourceMetadata.create({ name: "", }), spec: GpuClusterSpec.create({ infinibandFabric: "", }), }), ).result; await gpuClusterOperation.wait(); ``` To select the fabric, see [InfiniBand™ fabrics](https://docs.nebius.com/compute/clusters/gpu/index.md#infiniband-fabrics). 2. Create a VM: ```ts const clusterVmService = new InstanceService(sdk); const clusterVmOperation = await clusterVmService.create( CreateInstanceRequest.create({ metadata: ResourceMetadata.create({ name: "", }), spec: InstanceSpec.create({ resources: ResourcesSpec.create({ platform: "", size: { $case: "preset", preset: "", }, }), gpuCluster: InstanceGpuClusterSpec.create({ id: gpuClusterId, }), bootDisk: AttachedDiskSpec.create({ attachMode: AttachedDiskSpec_AttachMode.READ_WRITE, type: { $case: "managedDisk", managedDisk: ManagedDisk.create({ name: "managed-boot-disk", spec: DiskSpec.create({ type: DiskSpec_DiskType.NETWORK_SSD, source: { $case: "sourceImageFamily", sourceImageFamily: SourceImageFamily.create({ imageFamily: "ubuntu24.04-cuda13.0", }), }, size: { $case: "sizeGibibytes", sizeGibibytes: 10, }, }), }), }, }), networkInterfaces: [ NetworkInterfaceSpec.create({ name: "eth0", subnetId, ipAddress: IPAddress.create({}), publicIpAddress: PublicIPAddress.create({}), }), ], }), }), ).result; await clusterVmOperation.wait(); ``` The VM is provided with a dynamic public IPv4 address. For more information about the code parameters, see [Create a VM](https://docs.nebius.com/compute/virtual-machines/manage.md#create-a-vm). ## "Not enough resources" error Sometimes, demand for virtual machines and GPUs in certain [Nebius AI Cloud regions](https://docs.nebius.com/overview/regions.md) might be higher than the available supply. When this happens, you might see a "Not enough resources" error when creating or restarting VMs in the affected region. For more details, see ["Not enough resources" error for virtual machines in Nebius AI Cloud](https://docs.nebius.com/compute/virtual-machines/not-enough-resources.md). ## See also * [Private and public IP addresses of Compute virtual machines](https://docs.nebius.com/compute/virtual-machines/network.md) * [InfiniBand™ networking for Compute virtual machines with GPUs](https://docs.nebius.com/compute/clusters/gpu/index.md) * [Types of storage volumes in Compute](https://docs.nebius.com/compute/storage/types.md) * [Managing Compute volumes](https://docs.nebius.com/compute/storage/manage.md) * [Attaching and mounting Compute volumes to VMs](https://docs.nebius.com/compute/storage/use.md) *** *InfiniBand and InfiniBand Trade Association are registered trademarks of the InfiniBand Trade Association.* # Preemptible virtual machines Source: https://docs.nebius.com/compute/virtual-machines/preemptible.md *Preemptible VMs*, also known as spot VMs or spot instances, are virtual machines that Compute may stop at any time. This can happen when the system needs resources to launch a regular VM in the same region. Compute sends a `SIGTERM` signal 60 seconds before stopping the VM. If your system does not respond in time, Compute sends a `SIGKILL` signal to force shutdown. Compute preserves all data on the volumes attached to a stopped preemptible VM. It does not preserve dynamic resources, such as dynamic public IP addresses. Preemptible VMs [cost less than regular ones](https://docs.nebius.com/compute/resources/pricing.md#prices), but they do not provide guaranteed availability. You can create a preemptible VM, but you cannot change the type of an existing VM—either from regular to preemptible or from preemptible to regular. ## Supported platforms You can run preemptible VMs on all [VM platforms with GPUs](https://docs.nebius.com/compute/virtual-machines/types.md). To get an up-to-date list of platforms, run the `nebius compute platform list` [command](https://docs.nebius.com/cli/reference/compute/platform/list). The platforms available for preemptible VMs are marked as `allowed_for_preemptibles: true`. ## Prerequisites If you use the web console, you don't need to complete any prerequisites. [Install and configure](https://docs.nebius.com/cli/install.md) the Nebius AI Cloud CLI. [Install and configure](https://docs.nebius.com/terraform-provider/install.md) the Nebius AI Cloud provider for Terraform. [Install and initialize the Nebius SDK for Go](https://docs.nebius.com/grpc-api/sdk/go.md). [Install and initialize the Nebius SDK for Python](https://docs.nebius.com/grpc-api/sdk/python.md). [Install and initialize the Nebius SDK for JavaScript](https://docs.nebius.com/grpc-api/sdk/javascript.md). ## How to create a preemptible VM 1. In the sidebar, go to **Compute** → **Virtual machines**. 2. Click **Create resource** → **Virtual machine**. 3. If you have [capacity block groups](https://docs.nebius.com/overview/limits/capacity-block-groups.md), on the **General** step, select **Pay-as-you-go VM**. If you do not have capacity block groups, the wizard skips the **General** step and opens **Compute** instead. 4. On the **Compute** step, select **With GPUs** or **Without GPUs**, set the VM type to **Preemptible** and select a [platform and preset](https://docs.nebius.com/compute/virtual-machines/types.md). For more information about the full wizard, see [How to create a virtual machine](https://docs.nebius.com/compute/virtual-machines/manage.md#create-a-vm). When [creating a VM](https://docs.nebius.com/compute/virtual-machines/manage.md): * Select a [platform that supports preemptible VMs](https://docs.nebius.com/compute/virtual-machines/preemptible.md#supported-platforms). * Add the following parameters to the `nebius compute instance create` command: ```bash nebius compute instance create \ ... \ --recovery-policy fail \ --preemptible-on-preemption stop ``` In this configuration, the following values are specified: * `recovery_policy` defines what Compute does with a VM after it's preempted or fails. Preemptible VMs support only the `FAIL` value, which stops the VM. They do not support the `RECOVER` value, which tries to restart the VM. Setting `RECOVER` for a preemptible VM results in an error. * `on_preemption` specifies what happens when the VM is preempted. The only supported value is `STOP`: Compute stops the VM without deleting or restarting it. For details about the nebius compute instance create command, see the [Nebius AI Cloud CLI reference](https://docs.nebius.com/cli/reference/compute/instance/create). When creating a VM, select a [platform that supports preemptible VMs](https://docs.nebius.com/compute/virtual-machines/preemptible.md#supported-platforms) and set the following parameters in the VM configuration: ```hcl resource "nebius_compute_v1_instance" "instance" { ... recovery_policy = "FAIL" preemptible = { on_preemption = "STOP" } ... } ``` In this configuration, the following values are specified: * `recovery_policy` defines what Compute does with a VM after it's preempted or fails. Preemptible VMs support only the `FAIL` value, which stops the VM. They do not support the `RECOVER` value, which tries to restart the VM. Setting `RECOVER` for a preemptible VM results in an error. * `on_preemption` specifies what happens when the VM is preempted. The only supported value is `STOP`: Compute stops the VM without deleting or restarting it. For details about the nebius\_compute\_v1\_instance Terraform resource, see the [provider reference](https://docs.nebius.com/terraform-provider/reference/resources/compute_v1_instance). When [creating a VM](https://docs.nebius.com/compute/virtual-machines/manage.md): * Select a [platform that supports preemptible VMs](https://docs.nebius.com/compute/virtual-machines/preemptible.md#supported-platforms). * Set the preemptible VM parameters in the code: ```go resources := &compute.ResourcesSpec{ Platform: "gpu-l40s-a", Size: &compute.ResourcesSpec_Preset{ Preset: "1gpu-24vcpu-96gb", }, } bootDisk := &compute.AttachedDiskSpec{ AttachMode: compute.AttachedDiskSpec_READ_WRITE, Type: &compute.AttachedDiskSpec_ExistingDisk{ ExistingDisk: &compute.ExistingDisk{ Id: bootDiskID, }, }, } networkInterface := &compute.NetworkInterfaceSpec{ Name: "eth0", SubnetId: subnetID, IpAddress: &compute.IPAddress{}, PublicIpAddress: &compute.PublicIPAddress{}, } instanceSpec := &compute.InstanceSpec{ Resources: resources, BootDisk: bootDisk, NetworkInterfaces: []*compute.NetworkInterfaceSpec{ networkInterface, }, RecoveryPolicy: compute.InstanceRecoveryPolicy_FAIL, Preemptible: &compute.PreemptibleSpec{ OnPreemption: compute.PreemptibleSpec_STOP, }, } preemptibleOperation, err := sdk.Services().Compute().V1(). Instance().Create( ctx, &compute.CreateInstanceRequest{ Metadata: &common.ResourceMetadata{ Name: "preemptible-instance", }, Spec: instanceSpec, }, ) if err != nil { return err } if _, err = preemptibleOperation.Wait(ctx); err != nil { return err } ``` In this configuration, the following values are specified: * `RecoveryPolicy` defines what Compute does with a VM after it's preempted or fails. Preemptible VMs support only the `FAIL` value, which stops the VM. They do not support the `RECOVER` value, which tries to restart the VM. Setting `RECOVER` for a preemptible VM results in an error. * `OnPreemption` specifies what happens when the VM is preempted. The only supported value is `STOP`: Compute stops the VM without deleting or restarting it. When [creating a VM](https://docs.nebius.com/compute/virtual-machines/manage.md): * Select a [platform that supports preemptible VMs](https://docs.nebius.com/compute/virtual-machines/preemptible.md#supported-platforms). * Set the preemptible VM parameters in the code: ```python instance_service = InstanceServiceClient(sdk) preemptible_operation = await instance_service.create( CreateInstanceRequest( metadata=ResourceMetadata( name="preemptible-instance", ), spec=InstanceSpec( resources=ResourcesSpec( platform="gpu-l40s-a", preset="1gpu-24vcpu-96gb", ), boot_disk=AttachedDiskSpec( attach_mode=( AttachedDiskSpec.AttachMode.READ_WRITE ), existing_disk=ExistingDisk(id=boot_disk_id), ), network_interfaces=[ NetworkInterfaceSpec( name="eth0", subnet_id=subnet_id, ip_address=IPAddress(), public_ip_address=PublicIPAddress(), ), ], recovery_policy=InstanceRecoveryPolicy.FAIL, preemptible=PreemptibleSpec( on_preemption=( PreemptibleSpec.PreemptionPolicy.STOP ), ), ), ), ) await preemptible_operation.wait() ``` In this configuration, the following values are specified: * `recovery_policy` defines what Compute does with a VM after it's preempted or fails. Preemptible VMs support only the `FAIL` value, which stops the VM. They do not support the `RECOVER` value, which tries to restart the VM. Setting `RECOVER` for a preemptible VM results in an error. * `on_preemption` specifies what happens when the VM is preempted. The only supported value is `STOP`: Compute stops the VM without deleting or restarting it. When [creating a VM](https://docs.nebius.com/compute/virtual-machines/manage.md): * Select a [platform that supports preemptible VMs](https://docs.nebius.com/compute/virtual-machines/preemptible.md#supported-platforms). * Set the preemptible VM parameters in the code: ```ts const instanceService = new InstanceService(sdk); const preemptibleOperation = await instanceService.create( CreateInstanceRequest.create({ metadata: ResourceMetadata.create({ name: "preemptible-instance", }), spec: InstanceSpec.create({ resources: ResourcesSpec.create({ platform: "gpu-l40s-a", size: { $case: "preset", preset: "1gpu-24vcpu-96gb", }, }), bootDisk: AttachedDiskSpec.create({ attachMode: AttachedDiskSpec_AttachMode.READ_WRITE, type: { $case: "existingDisk", existingDisk: ExistingDisk.create({ id: bootDiskId, }), }, }), networkInterfaces: [ NetworkInterfaceSpec.create({ name: "eth0", subnetId, ipAddress: IPAddress.create({}), publicIpAddress: PublicIPAddress.create({}), }), ], recoveryPolicy: InstanceRecoveryPolicy.FAIL, preemptible: PreemptibleSpec.create({ onPreemption: PreemptibleSpec_PreemptionPolicy.STOP, }), }), }), ).result; await preemptibleOperation.wait(); ``` In this configuration, the following values are specified: * `recoveryPolicy` defines what Compute does with a VM after it's preempted or fails. Preemptible VMs support only the `FAIL` value, which stops the VM. They do not support the `RECOVER` value, which tries to restart the VM. Setting `RECOVER` for a preemptible VM results in an error. * `onPreemption` specifies what happens when the VM is preempted. The only supported value is `STOP`: Compute stops the VM without deleting or restarting it. A dynamic IP address is released when a preemptible VM stops. To keep your workload stable, consider using a static IP address instead. ## How to continue working with a stopped preemptible VM When Compute stops a preemptible VM, it preserves all data on the attached volumes. To resume work, [start the VM](https://docs.nebius.com/compute/virtual-machines/stop-start.md) again. If you used a dynamic IP address, update all systems that depended on the old IP address. If the VM uses local SSD disks, use them with caution. Local SSD disks are ephemeral, meaning any data stored on them will be lost when the preemptible VM stops. You can also [create a regular VM](https://docs.nebius.com/compute/virtual-machines/manage.md) with the same attached volumes. # Container virtual machines Source: https://docs.nebius.com/compute/virtual-machines/containers.md A container virtual machine (VM) is a VM with a container image deployed. You can use containers provided by Nebius AI Cloud or containers with custom Docker images from public registries. A container VM is based on the same settings as a [standalone VM](https://docs.nebius.com/compute/virtual-machines/manage.md). The key difference is that you select a container to deploy when you create a VM. In the [web console](https://console.nebius.com), container VMs are listed on the **Container VMs** tab of the **Virtual machines** page. You can also open them directly from **Compute** → **Container VMs** in the sidebar. By default, a VM with a dynamic public IPv4 address is created. This allows you to access the container after deployment. If you want to restrict access to the container and create a VM without a public address, you can change it in the advanced settings on the VM creation page. For more information, see [Private and public IP addresses of Compute virtual machines](https://docs.nebius.com/compute/virtual-machines/network.md). ## How to create a container VM 1. In the [web console](https://console.nebius.com), go to  **Compute** → **Container VMs**. 2. Click  **Create container VM**. 3. On the page that opens, select the project for the VM location. 4. Specify the VM name. 5. Select a container image to deploy on this VM. Certain container images require additional settings configured and access credentials stored (for example, save a token from the web console). If you want to deploy a custom Docker image from a public registry, select the **Custom image** option and then set Docker parameters. 6. Set computing resources. For detailed information about VM settings, see [Parameters of a virtual machine configuration in Compute](https://docs.nebius.com/compute/virtual-machines/params.md). 7. In the **Local storage** section, specify the size of the VM disk. 8. (Optional) Add shared filesystems to the VM. You can create a new filesystem or select an existing one. 9. In the **Access** section, add a username and an SSH key for the VM's user so you can [connect to the VM](https://docs.nebius.com/compute/virtual-machines/connect.md) on its behalf. You can add new credentials or select existing ones. Do not use the `root` or `admin` usernames. They are reserved for internal needs and are not allowed to connect to a VM by SSH. 10. (Optional) Add advanced settings: * [GPU cluster](https://docs.nebius.com/compute/clusters/gpu/index.md): Allows accelerating tasks that require high-performance computing (HPC) power, such as training a model. A GPU cluster only helps if you add at least two VMs with 8 GPUs each to the cluster. * Local storage: Select an existing disk or create a new one. For a new disk, you can configure [parameters](https://docs.nebius.com/compute/storage/manage.md#volume-parameters) such as a disk type, encryption, size and the block size. If you enable the advanced settings, you configure storage in them. The storage settings that you set earlier become disabled, and they do not apply. * Additional disks: Select an existing disk or create a new one as well. * Network settings: * Select a network and subnet to locate the VM. * Specify whether the VM's private IP address should be assigned automatically or be selected from a list of [allocations](https://docs.nebius.com/vpc/overview.md#allocation). * Specify whether the VM should have a public IP address. If you do not assign a public address to your VM, the [access to the container](https://docs.nebius.com/compute/virtual-machines/containers.md#how-to-access-a-deployed-container) is restricted. For more information about available options, see [Public IP addresses](https://docs.nebius.com/compute/virtual-machines/network.md#public-ip-addresses). * Service account: Specify a [service account](https://docs.nebius.com/iam/service-accounts/manage.md) that will perform actions on behalf of the VM, for example, run scripts. 11. Click **Create container VM**. The container is available about five minutes after the VM startup. ## How to access a deployed container Access depends on two major characteristics: * Whether a public IP address is assigned to a VM. If a public address is assigned, you can open the web interface of a container by a provided link. If a VM only has a private IP address, [configure a WireGuard jump server](https://docs.nebius.com/compute/virtual-machines/wireguard.md) for the VM. After that, you can connect to your VM via a configured VPN and access your container by using an additional VM. * Whether a given container requires credentials, such as a token or API key. If credentials are needed, they are displayed on the container creation and overview pages. After you open the web interface, you can apply the provided credentials there and access the web interface. To open a web interface of a deployed container: 1. In the [web console](https://console.nebius.com), go to **Compute** → **Container VMs**. 2. Open the page of the VM with the required container. 3. If the VM is assigned a public IP address, click the go-to-web-UI button. 4. If the VM only has a private address, configure a WireGuard jump server. For more information, click **How to connect** on the VM page. ## How to check that a custom image is deployed If you want to make sure that a custom Docker image is deployed in your VM: 1. [Connect](https://docs.nebius.com/compute/virtual-machines/connect.md) to the VM via SSH. 2. Check the Docker logs: ```bash sudo docker logs ``` If the container image is deployed, the logs display information about it. # Parameters of a virtual machine configuration in Compute Source: https://docs.nebius.com/compute/virtual-machines/params.md When you [create a virtual machine](https://docs.nebius.com/compute/virtual-machines/manage.md) (VM) or edit its configuration, you operate with VM settings. Below is the list of the VM settings available in the [web console](https://console.nebius.com) creation wizard and on the VM settings page. ## General If you have [capacity block groups](https://docs.nebius.com/overview/limits/capacity-block-groups.md), on the **General** step of the wizard, you choose how Compute allocates resources: * **Reserved VM**: Capacity is assured by your capacity block groups. This option is for regular VMs with GPUs. * **Pay-as-you-go VM**: Capacity is subject to availability. This option allows [preemptible VMs](https://docs.nebius.com/compute/virtual-machines/preemptible.md) and VMs without GPUs. If you do not have capacity block groups, the wizard skips the **General** step and opens **Compute** instead. ## Compute On the **Compute** step, you configure computing resources. The available settings depend on whether you selected **Reserved VM** or **Pay-as-you-go VM** on the **General** step. If the **General** step was skipped, use the **Pay-as-you-go VM** settings below. ### Reserved VM * [Platform](https://docs.nebius.com/compute/virtual-machines/types.md). The list shows platforms that match your capacity block groups. * [**Reservation**](https://docs.nebius.com/compute/virtual-machines/reservations.md) settings: **Region**, **Any (existing and future)**, specific capacity block groups, and **Switch to PAYG** with **When reservation is exhausted** or **Never**. * Preset. * (Optional) [GPU cluster](https://docs.nebius.com/compute/clusters/gpu/index.md). Allows accelerating tasks that require high-performance computing (HPC) power, such as training a model. A GPU cluster only helps if you add at least two VMs with 8 GPUs each to the cluster. For container VMs, you can assign a GPU cluster in the **Advanced settings** section. * VM name. * Project for the VM location. ### Pay-as-you-go VM * Select **With GPUs** or **Without GPUs** and the VM type **Regular** or [Preemptible](https://docs.nebius.com/compute/virtual-machines/preemptible.md). * [Platform and preset](https://docs.nebius.com/compute/virtual-machines/types.md). * Preset. * (Optional) [GPU cluster](https://docs.nebius.com/compute/clusters/gpu/index.md). Allows accelerating tasks that require HPC power, such as training a model. A GPU cluster only helps if you add at least two VMs with 8 GPUs each to the cluster. For container VMs, you can assign a GPU cluster in the **Advanced settings** section. * VM name. * Project for the VM location. ## Storage On the **Storage** step, you can add a boot disk, additional disks and shared filesystems. For disks, you specify their type, size and block size. A boot disk is additionally based on an operating system. For more information about these settings, see [Volume parameters](https://docs.nebius.com/compute/storage/manage.md#volume-parameters). Boot disks are unavailable for container VMs. Only additional disks are available in advanced settings. For shared filesystems, you specify the following settings: * [Name, size and block size](https://docs.nebius.com/compute/storage/manage.md#volume-parameters). * Mount tag for mounting the filesystem to the VM. Create your own tag, such as `my-filesystem`. Make sure that it is unique within the VM. * **Auto mount** option enabled to mount the filesystem to the VM automatically. ## Network On the **Network** step, you select a [network and subnet](https://docs.nebius.com/vpc/overview.md) and manage the VM addresses: * **Private address**: Select whether to allocate a random private IP address for the VM or to attach an allocation of a private address. * **Public address**: Specify whether the VM should have a public IP address and whether it should be static or dynamic. * **Hostname**: Select **Same as VM ID** or specify a **Custom** hostname for the VM's [FQDN](https://docs.nebius.com/compute/virtual-machines/fqdn.md). If you need to secure your VM and make it isolated, you can create a VM without a public IP address. If you need to connect to this VM from the internet, you can [set up a WireGuard jump server](https://docs.nebius.com/compute/virtual-machines/wireguard.md). It has an IP address in the internet and an IP address in the VM's network. As a result, you can access the VM via the jump server from the internet. This approach enhances security and still provides access to the VM. For more information about the settings of the addresses, see [Private and public IP addresses of Compute virtual machines](https://docs.nebius.com/compute/virtual-machines/network.md). ## Configuration On the **Configuration** step, you configure access, identity and VM startup settings for the VM. ### Access In the **Username and SSH key** field, you add credentials of the user on behalf of whom you can [connect to the VM](https://docs.nebius.com/compute/virtual-machines/connect.md). The access settings include the following: * Username of the VM user. Cannot be `root` or `admin`. These usernames are reserved for internal needs and are not allowed to connect to a VM by SSH. * [Public key of your SSH key pair](https://docs.nebius.com/compute/virtual-machines/ssh-keys.md#getting-the-public-key). * Name of credentials to recognize the key in the list of keys. ### Additional (Optional) **Service account**: Select an existing [service account](https://docs.nebius.com/iam/service-accounts/manage.md) or create a new one. The service account will perform actions on behalf of the VM, for example, run scripts. ### User data (Optional) Select **Enable custom cloud-init config** and set a configuration in the [cloud-init](https://cloudinit.readthedocs.io/en/latest/reference/modules.html#users-and-groups) format to customize how the VM starts. ## Review On the **Review** step, you see a summary of all settings before creating the VM. To edit a section, click next to the corresponding block on the **Review** step. # Maintenance of Compute virtual machines Source: https://docs.nebius.com/compute/virtual-machines/maintenance.md The Compute service performs maintenance for all virtual machines, including nodes of [Managed Service for Kubernetes®](https://docs.nebius.com/kubernetes/index.md) clusters and [Soperator](https://docs.nebius.com/slurm-soperator/overview/why-slurm-soperator.md) clusters. To ensure that maintenance is performed successfully, [stop and start VMs](https://docs.nebius.com/compute/virtual-machines/stop-start.md) until the specified date. You can open the list of VMs via the red banner on the top of the screen. For example: maintenance-banner If you do not stop VMs on time, the service will automatically stop them after the due date to perform maintenance. Delayed maintenance may cause VM instability. If you need to keep your VMs running, [contact the support team](https://console.nebius.com/support/create-ticket) to request rescheduling maintenance of the affected VMs. You can request to reschedule it up to two times, and you can postpone the maintenance by up to seven days each time. # Maintenance reasons in Nebius AI Cloud Source: https://docs.nebius.com/compute/virtual-machines/maintenance-reasons.md When Compute schedules maintenance for your virtual machine (VM), it assigns a *reason code* that describes why the maintenance was triggered. After you identify the reason, [stop and start your VM](https://docs.nebius.com/compute/virtual-machines/stop-start.md#how-to-stop-and-start-compute-virtual-machines) to prepare it for maintenance. The reason code helps you assess the severity of the error and decide whether additional action is needed. ## How to identify the reason code for a maintenance event You can view the reason code for maintenance events by: * Checking the maintenance notification banner in the [web console](https://console.nebius.com/); * Using the [Nebius AI Cloud CLI](https://docs.nebius.com/cli/index.md) to list all active maintenance events scheduled for resources in a project. Run the following command, and specify your [project ID](https://docs.nebius.com/iam/manage-projects.md#how-to-get-a-project-id). ```bash nebius compute maintenance list-active --parent-id ``` The output contains a list of all maintenance events that are scheduled for resources in the project you specified. ## Reason codes Maintenance events can be triggered by GPU, InfiniBand™ or node-level errors. The tables below show the reason codes that map to different types of errors. If maintenance was triggered by a condition that is not mapped to one of these reason codes, Compute assigns `OTHER` as the reason code. ### GPU errors | Reason code | Description | | ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `HW_GPU_PCI_FALLEN_OFF_BUS` | A GPU or NVSwitch has fallen off the PCI bus, typically due to critical thermal or power issues. The affected node is taken out of service for hardware inspection. | | `HW_GPU_PCI_CONFIG_ERROR` | Unexpected GPU PCI configuration detected, or critical PCI errors observed between the GPU, deltaboard and motherboard. Requires physical hardware maintenance. | | `HW_GPU_NVLINK_DOWN` | An NVLink connection is down on a Blackwell or newer GPU. Requires a GPU reset or VM restart to recover. | | `HW_GPU_XID_62` | The GPU internal micro-controller has halted (XID 62). Requires a GPU reset or VM restart. | | `HW_GPU_XID_109` | GPU context switch timeout (XID 109). Typically not fatal to running workloads, but may require a GPU reset or VM restart. | | `HW_GPU_XID_119` | GSP RPC timeout (XID 119). Requires a GPU reset or VM restart. | | `HW_GPU_FW_VERSION_UNAVAILABLE` | DCGM could not report the GPU firmware version. This is usually a symptom of other underlying hardware errors. | | `HW_GPU_DRIVER_INIT_FAILED` | The NVIDIA® driver failed to initialize one or more GPUs. Typically caused by other hardware errors. | ### InfiniBand™ errors | Reason code | Description | | -------------------------- | ----------------------------------------------------------------------------------------------------- | | `HW_IB_LINK_DOWN` | The InfiniBand link has been in a physically down state for more than 3 minutes. | | `HW_IB_PCI_FALLEN_OFF_BUS` | The InfiniBand adapter has fallen off the PCI bus, typically due to critical thermal or power issues. | | `HW_IB_PCI_CONFIG_ERROR` | Unexpected InfiniBand PCI configuration detected, typically due to critical PCI errors. | ### Node-level errors | Reason code | Description | | ----------------- | ----------------------------------------------------------------------------------------------------------------------------------- | | `HW_NODE_OFFLINE` | The node hosting the VM went offline. The cause may vary. Affected VMs are force-migrated and will experience an unexpected reboot. | *InfiniBand and InfiniBand Trade Association are registered trademarks of the InfiniBand Trade Association.* # How to stop and start Compute virtual machines Source: https://docs.nebius.com/compute/virtual-machines/stop-start.md To proceed with [maintenance](https://docs.nebius.com/compute/virtual-machines/maintenance.md), stop and start virtual machines [manually](https://docs.nebius.com/compute/virtual-machines/stop-start.md#how-to-stop-and-start-vms-manually) or [automatically](https://docs.nebius.com/compute/virtual-machines/stop-start.md#how-to-stop-and-start-vms-automatically-by-using-autohealing). If you need to keep your VMs running, [contact the support team](https://console.nebius.com/support/create-ticket) and consult them about the possibility of rescheduling maintenance of the affected VMs. Do not stop your VM by using Linux commands, such as `shutdown` or `halt`. Compute considers this as a failure, reboots the VM automatically and continues charging for this VM. Use Nebius AI Cloud interfaces instead and follow the instructions below. ## Prerequisites If you use the web console, you don't need to complete any prerequisites. [Install and configure](https://docs.nebius.com/cli/install.md) the Nebius AI Cloud CLI. [Install and initialize the Nebius SDK for Go](https://docs.nebius.com/grpc-api/sdk/go.md). [Install and initialize the Nebius SDK for Python](https://docs.nebius.com/grpc-api/sdk/python.md). [Install and initialize the Nebius SDK for JavaScript](https://docs.nebius.com/grpc-api/sdk/javascript.md). ## How to stop and start VMs manually 1. In the sidebar, go to **Compute** → **Virtual machines**. 2. On the **Standalone VMs** tab, find VMs with the maintenance label. maintenance-label 3. Click  → **Stop** for these VMs. 4. In the window that opens, confirm stopping the VM. 5. When the VM status changes to **Stopped**, click  → **Start**. 6. In the window that opens, confirm starting the VM. 1. Check whether maintenance is scheduled for a VM: ```bash nebius compute instance get --id ``` If the output contains the `status.maintenance_event_id` parameter, this means that you need to stop and start this VM. 2. Stop the VM: ```bash nebius compute instance stop --id ``` 3. Start the VM: ```bash nebius compute instance start --id ``` 1. Check whether maintenance is scheduled for a VM: ```go instance, err := sdk.Services().Compute().V1(). Instance().Get( ctx, &compute.GetInstanceRequest{ Id: "", }, ) if err != nil { return err } fmt.Println(instance) ``` If the response contains a maintenance event ID in the VM status, stop and start this VM. 2. Stop the VM: ```go stopInstanceOperation, err := sdk.Services().Compute().V1(). Instance().Stop( ctx, &compute.StopInstanceRequest{ Id: "", }, ) if err != nil { return err } if _, err = stopInstanceOperation.Wait(ctx); err != nil { return err } ``` 3. Start the VM: ```go startOperation, err := sdk.Services().Compute().V1(). Instance().Start( ctx, &compute.StartInstanceRequest{ Id: "", }, ) if err != nil { return err } if _, err = startOperation.Wait(ctx); err != nil { return err } ``` 1. Check whether maintenance is scheduled for a VM: ```python instance_service = InstanceServiceClient(sdk) instance = await instance_service.get( GetInstanceRequest(id=""), ) print(instance) ``` If the response contains a maintenance event ID in the VM status, stop and start this VM. 2. Stop the VM: ```python instance_service = InstanceServiceClient(sdk) stop_instance_operation = await instance_service.stop( StopInstanceRequest(id=""), ) await stop_instance_operation.wait() ``` 3. Start the VM: ```python instance_service = InstanceServiceClient(sdk) start_instance_operation = await instance_service.start( StartInstanceRequest(id=""), ) await start_instance_operation.wait() ``` 1. Check whether maintenance is scheduled for a VM: ```ts const getInstanceService = new InstanceService(sdk); const instance = await getInstanceService.get( GetInstanceRequest.create({ id: "", }), ); console.log(instance); ``` If the response contains a maintenance event ID in the VM status, stop and start this VM. 2. Stop the VM: ```ts const stopInstanceService = new InstanceService(sdk); const stopInstanceOperation = await stopInstanceService.stop( StopInstanceRequest.create({ id: "", }), ).result; await stopInstanceOperation.wait(); ``` 3. Start the VM: ```ts const startInstanceService = new InstanceService(sdk); const startInstanceOperation = await startInstanceService.start( StartInstanceRequest.create({ id: "", }), ).result; await startInstanceOperation.wait(); ``` ## How to stop and start VMs automatically by using autohealing You can create a VM with the autohealing function. It allows a VM to automatically stop and start each time maintenance is scheduled. As a result, the applications on this VM are highly available. Use autohealing only if the automatic VM shutdown is safe for the workloads on this VM. If you cannot stop the VM at any time, it is better to manage the VM [manually](https://docs.nebius.com/compute/virtual-machines/stop-start.md#how-to-stop-and-start-vms-manually). To create a VM that stops and starts automatically during maintenance events: 1. Make sure you are in a [group](https://docs.nebius.com/iam/authorization/groups/index.md) that has the `admin` role within your tenant or project; for example, the default `admins` group. You can check this in the [Administration → IAM](https://console.nebius.com/iam) section of the web console. 2. [Create a service account](https://docs.nebius.com/iam/service-accounts/manage.md#create-a-service-account). 3. Add it to the default `viewers` group: 1. Get the ID of the `viewers` group: ```bash nebius iam group get-by-name --name viewers \ --parent-id \ --format json | jq -r '.metadata.id' ``` In the command, specify your [Tenant ID](https://docs.nebius.com/iam/get-tenants.md#cli). 2. Get the ID of the service account: ```bash nebius iam service-account get-by-name \ --name \ --format json | jq -r '.metadata.id' ``` 3. Add the service account to the `viewers` group: ```bash nebius iam group-membership create \ --parent-id \ --member-id ``` 1. Get the ID of the `viewers` group: ```go viewersGroup, err := sdk.Services().IAM().V1(). Group().GetByName( ctx, &iam.GetGroupByNameRequest{ ParentId: "", Name: "viewers", }, ) if err != nil { return err } viewersID := viewersGroup.GetMetadata().GetId() if viewersID == "" { return errors.New("viewers group ID is missing") } ``` In the code, specify your [tenant ID](https://docs.nebius.com/iam/get-tenants.md). 2. Get the ID of the service account: ```go serviceAccount, err := sdk.Services().IAM().V1(). ServiceAccount().GetByName( ctx, &iam.GetServiceAccountByNameRequest{ Name: "", }, ) if err != nil { return err } serviceAccountID := serviceAccount.GetMetadata().GetId() if serviceAccountID == "" { return errors.New("service account ID is missing") } ``` In the code, specify the service account name. 3. Add the service account to the `viewers` group: ```go membershipOperation, err := sdk.Services().IAM().V1(). GroupMembership().Create( ctx, &iam.CreateGroupMembershipRequest{ Metadata: &common.ResourceMetadata{ ParentId: "", }, Spec: &iam.GroupMembershipSpec{ MemberId: "", }, }, ) if err != nil { return err } if _, err = membershipOperation.Wait(ctx); err != nil { return err } ``` In the code, specify the IDs of the `viewers` group and the service account. 1. Get the ID of the `viewers` group: ```python group_service = GroupServiceClient(sdk) viewers_group = await group_service.get_by_name( GetGroupByNameRequest( parent_id="", name="viewers", ), ) viewers_id = viewers_group.metadata.id ``` In the code, specify your [tenant ID](https://docs.nebius.com/iam/get-tenants.md). 2. Get the ID of the service account: ```python service_account_service = ServiceAccountServiceClient(sdk) service_account = await service_account_service.get_by_name( GetServiceAccountByNameRequest(name=""), ) service_account_id = service_account.metadata.id ``` In the code, specify the service account name. 3. Add the service account to the `viewers` group: ```python membership_service = GroupMembershipServiceClient(sdk) membership_operation = await membership_service.create( CreateGroupMembershipRequest( metadata=ResourceMetadata(parent_id=""), spec=GroupMembershipSpec(member_id=""), ), ) await membership_operation.wait() ``` In the code, specify the IDs of the `viewers` group and the service account. 1. Get the ID of the `viewers` group: ```ts const groupService = new GroupService(sdk); const viewersGroup = await groupService.getByName( GetGroupByNameRequest.create({ parentId: "", name: "viewers", }), ); const viewersId = viewersGroup.metadata?.id; if (!viewersId) { throw new Error("viewers group ID is missing"); } ``` In the code, specify your [tenant ID](https://docs.nebius.com/iam/get-tenants.md). 2. Get the ID of the service account: ```ts const saService = new ServiceAccountService(sdk); const serviceAccount = await saService.getByName( GetServiceAccountByNameRequest.create({ name: "", }), ); const serviceAccountId = serviceAccount.metadata?.id; if (!serviceAccountId) { throw new Error("service account ID is missing"); } ``` In the code, specify the service account name. 3. Add the service account to the `viewers` group: ```ts const membershipService = new GroupMembershipService(sdk); const membershipOperation = await membershipService.create( CreateGroupMembershipRequest.create({ metadata: ResourceMetadata.create({ parentId: "", }), spec: GroupMembershipSpec.create({ memberId: "", }), }), ).result; await membershipOperation.wait(); ``` In the code, specify the IDs of the `viewers` group and the service account. 4. [Create a VM](https://docs.nebius.com/compute/virtual-machines/manage.md). In its configuration, specify the following: * [Settings that allow connections](https://docs.nebius.com/compute/virtual-machines/connect.md#set-up-the-vm) to this VM. * Created service account: ```bash nebius compute instance create \ ... \ --service-account-id ``` ```go fsAttachMode := compute.AttachedFilesystemSpec_READ_WRITE existingFS := &compute.ExistingFilesystem{ Id: filesystemID, } fsType := &compute.AttachedFilesystemSpec_ExistingFilesystem{ ExistingFilesystem: existingFS, } instanceOperation, err := sdk.Services().Compute().V1(). Instance().Create( ctx, &compute.CreateInstanceRequest{ Metadata: &common.ResourceMetadata{ Name: "vm", }, Spec: &compute.InstanceSpec{ ServiceAccountId: "", Resources: &compute.ResourcesSpec{ Platform: "cpu-e2", Size: &compute.ResourcesSpec_Preset{ Preset: "2vcpu-8gb", }, }, BootDisk: &compute.AttachedDiskSpec{ AttachMode: compute.AttachedDiskSpec_READ_WRITE, Type: &compute.AttachedDiskSpec_ExistingDisk{ ExistingDisk: &compute.ExistingDisk{ Id: bootDiskID, }, }, }, Filesystems: []*compute.AttachedFilesystemSpec{ { AttachMode: fsAttachMode, MountTag: "filesystem-1", Type: fsType, }, }, NetworkInterfaces: []*compute.NetworkInterfaceSpec{ { Name: "eth0", SubnetId: subnetID, IpAddress: &compute.IPAddress{}, PublicIpAddress: &compute.PublicIPAddress{}, }, }, }, }, ) if err != nil { return err } if _, err = instanceOperation.Wait(ctx); err != nil { return err } ``` ```python instance_service = InstanceServiceClient(sdk) create_instance_operation = await instance_service.create( CreateInstanceRequest( metadata=ResourceMetadata(name="vm"), spec=InstanceSpec( service_account_id="", resources=ResourcesSpec( platform="cpu-e2", preset="2vcpu-8gb", ), boot_disk=AttachedDiskSpec( attach_mode=AttachedDiskSpec.AttachMode.READ_WRITE, existing_disk=ExistingDisk(id=boot_disk_id), ), filesystems=[ AttachedFilesystemSpec( attach_mode=( AttachedFilesystemSpec.AttachMode.READ_WRITE ), existing_filesystem=ExistingFilesystem( id=filesystem_id, ), mount_tag="filesystem-1", ), ], network_interfaces=[ NetworkInterfaceSpec( name="eth0", subnet_id=subnet_id, ip_address=IPAddress(), public_ip_address=PublicIPAddress(), ), ], ), ), ) await create_instance_operation.wait() ``` ```ts const createInstanceService = new InstanceService(sdk); const createInstanceOperation = await createInstanceService.create( CreateInstanceRequest.create({ metadata: ResourceMetadata.create({ name: "vm", }), spec: InstanceSpec.create({ serviceAccountId: "", resources: ResourcesSpec.create({ platform: "cpu-e2", size: { $case: "preset", preset: "2vcpu-8gb", }, }), bootDisk: AttachedDiskSpec.create({ attachMode: AttachedDiskSpec_AttachMode.READ_WRITE, type: { $case: "existingDisk", existingDisk: ExistingDisk.create({ id: bootDiskId, }), }, }), filesystems: [ AttachedFilesystemSpec.create({ attachMode: AttachedFilesystemSpec_AttachMode.READ_WRITE, mountTag: "filesystem-1", type: { $case: "existingFilesystem", existingFilesystem: ExistingFilesystem.create({ id: filesystemId, }), }, }), ], networkInterfaces: [ NetworkInterfaceSpec.create({ name: "eth0", subnetId: subnetId, ipAddress: IPAddress.create({}), publicIpAddress: PublicIPAddress.create({}), }), ], }), }), ).result; await createInstanceOperation.wait(); ``` 5. [Connect to the VM](https://docs.nebius.com/compute/virtual-machines/connect.md#connect-to-the-vm-by-using-ssh). 6. Install `jq` on the VM: ```bash Ubuntu sudo apt-get install jq ``` ```bash macOS brew install jq ``` 7. Go to the `/usr/local/bin/` directory: ```bash cd /usr/local/bin/ ``` 8. Create the `vm_maintenance.sh` file: ```bash sudo nano vm_maintenance.sh ``` 9. Add the following Bash script to the file: ```bash #!/bin/bash INSTANCE_ID_FILE="/mnt/cloud-metadata/instance-id" CHECK_INTERVAL=600 # 10 minutes in seconds # Check if the Nebius AI Cloud CLI is installed check_nebius_installed() { if ! command -v nebius &> /dev/null; then echo "$(date) - Nebius utility not found, exiting..." exit 1 fi } get_instance_id() { if [[ -f "$INSTANCE_ID_FILE" ]]; then cat "$INSTANCE_ID_FILE" else echo "File with the virtual machine ID is not found" exit 1 fi } # Handle a maintenance event handle_maintenance_event() { # Add custom actions before stopping the virtual machine echo "$(date) - Custom actions before stopping the virtual machine" sudo shutdown -h +1 "Restarting virtual machine due to maintenance" } check_nebius_installed # main loop while true; do INSTANCE_ID=$(get_instance_id) if [[ -z "$INSTANCE_ID" ]]; then echo "Virtual machine ID is empty" exit 1 fi RESPONSE=$(nebius compute instance get --id "$INSTANCE_ID" --format json) if echo "$RESPONSE" | jq -e '.status.maintenance_event_id' >/dev/null; then echo "$(date) - Maintenance event detected" handle_maintenance_event else echo "$(date) - No maintenance event detected" fi sleep "$CHECK_INTERVAL" done ``` 10. Make the file executable: ```bash sudo chmod +x /usr/local/bin/vm_maintenance.sh ``` 11. To make the script run continuously and restart it when the VM fails or reboots, add a `systemd` unit to the script: ```bash sudo bash -c 'cat > /etc/systemd/system/vm_maintenance.service << EOF [Unit] Description=VM Maintenance Event Handler After=network.target [Service] ExecStart=/usr/local/bin/vm_maintenance.sh Restart=always User=root Environment=PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin WorkingDirectory=/usr/local/bin StandardOutput=append:/var/log/vm_maintenance.log StandardError=append:/var/log/vm_maintenance.log [Install] WantedBy=multi-user.target EOF' ``` 12. Start the service created with the `systemd` unit, and let it restart in case of the VM reboot: ```bash sudo systemctl daemon-reload sudo systemctl start vm_maintenance sudo systemctl enable vm_maintenance sudo systemctl status vm_maintenance ``` The output example is the following: ```text Created symlink /etc/systemd/system/multi-user.target.wants/vm_maintenance.service → /etc/systemd/system/vm_maintenance.service. ● vm_maintenance.service - VM Maintenance Event Handler Loaded: loaded (/etc/systemd/system/vm_maintenance.service; enabled; vendor preset: enabled) Active: active (running) since Fri 2025-04-25 10:19:19 UTC; 214ms ago Main PID: 28530 (vm_maintenance.) Tasks: 6 (limit: 19056) Memory: 24.3M CPU: 25ms CGroup: /system.slice/vm_maintenance.service ├─28530 /bin/bash /usr/local/bin/vm_maintenance.sh └─28535 nebius compute instance get --id computeinstance-*** --format json Apr 25 10:19:19 computeinstance-*** systemd[1]: Started VM Maintenance Event Handler. ``` Now, the script runs continuously, and the VM stops and starts during maintenance events. # Lifecycle of a Compute virtual machine Source: https://docs.nebius.com/compute/virtual-machines/lifecycle.md Every virtual machine (VM) in Compute can have one of the following statuses: * `Stopped`: VM is stopped. * `Starting`: VM is launching. * `Running`: VM is running. * `Stopping`: VM is stopping. * `Deleting`: VM is being deleted. * `Error`: VM crashed and cannot be restored. When a VM assumes this status, delete this VM and create a new one. You cannot stop and start a VM with the `Error` status. ## Transitions between VM statuses ### VM is being created `Stopped` → `Starting` → `Running` If you [create a VM](https://docs.nebius.com/compute/virtual-machines/manage.md) by using the CLI or Terraform, you can specify `"stopped": true` in the VM configuration. In this case, the VM is created with the `Stopped` status. The status does not change until you [launch this VM](https://docs.nebius.com/compute/virtual-machines/stop-start.md). ### VM is being started `Stopped` → `Starting` → `Running` When a VM is `Starting`, its hypervisor launches the VM's operating system. Additionally, the service allocates computing resources to the VM, such as RAM, GPUs and CPUs. When a VM is `Running`, it functions fully. This influences [billing](https://docs.nebius.com/compute/virtual-machines/lifecycle.md#when-compute-charges-for-the-vm-usage) and [quotas](https://docs.nebius.com/compute/virtual-machines/lifecycle.md#when-compute-quotas-are-released). The service charges you for a running VM. Also, the number of resources occupied in the tenant or project increases. ### VM is being stopped `Running` → `Stopping` → `Stopped` When a VM is `Stopping`, its hypervisor shuts down the operating system of this VM. Before the OS is turned off completely, the hypervisor gracefully terminates all running processes within 60 seconds to prevent data loss. After that, the VM is `Stopped`. ### VM is being deleted `Running` → `Deleting` After the `Deleting` status, a VM is removed from the list of VMs and the occupied quotas are released. ### VM crashed and is being recovered If the VM recovery is successful, statuses of this VM change in the following order: `Running` → `Stopping` → `Stopped` → `Running` If Compute cannot start the VM properly during the recovery, for example, because of a lack of available resources, the VM goes through one of the following lifecycles: * `Running` → `Stopping` → `Stopped` → `Starting` → `Stopping` → `Stopped` or `Error` * `Running` → `Stopping` → `Stopped` or `Error` ## When Compute charges for the VM usage When you create a VM, Compute starts [charging](https://docs.nebius.com/compute/resources/pricing.md) for it once the VM assumes the `Running` status. When you delete a VM, Compute stops charging for it once you send the deletion command. For example, you click the  **Delete** button or run a [CLI command](https://docs.nebius.com/cli/reference/compute/instance/delete). When a VM has crashed, Compute stops charging for it when recovery begins. If the VM is recovered successfully, the service continues charging. If not, the charging does not start again. ## When Compute quotas are released [Compute quotas](https://docs.nebius.com/compute/resources/quotas-limits.md) are only released after the VM deletion. If a VM is `Stopped`, the quotas are still occupied. To avoid running out of the quotas, revise your list of VMs from time to time and delete unused VMs. Stopping them will not help. # How to enable automatic security updates Source: https://docs.nebius.com/compute/storage/automatic-updates.md The Ubuntu [images](https://docs.nebius.com/compute/storage/boot-disk-images.md) used on boot disks of VMs include the `unattended-upgrades` package that can install security updates automatically. However, unexpected updates might break running GPU workloads. For this reason, unattended upgrades are disabled by default. We recommend that you check the compatibility of new library versions on a test VM, and then apply the updates manually to all running GPU nodes. If you do need constant security updates, you can enable `unattended-upgrades`. ## For an existing VM 1. [Connect](https://docs.nebius.com/compute/virtual-machines/connect.md) to the VM. 2. Check that the updates are enabled in the configuration: ```bash sudo nano /etc/apt/apt.conf.d/20auto-upgrades ``` The following values should be equal to 1. If they are set to 0, change them to 1: ```bash APT::Periodic::Update-Package-Lists "1"; APT::Periodic::Unattended-Upgrade "1"; ``` 3. Start the upgrade services: ```bash sudo systemctl unmask apt-daily.service apt-daily-upgrade.service sudo systemctl enable apt-daily.timer apt-daily-upgrade.timer sudo systemctl start apt-daily.timer apt-daily-upgrade.timer ``` 4. Check the service status: ```bash systemctl status apt-daily.timer apt-daily-upgrade.timer ``` Output for active updates should look like the following: ```bash ● apt-daily.timer - Daily apt download activities Loaded: loaded (/usr/lib/systemd/system/apt-daily.timer; enabled; preset: enabled) Active: active (waiting) since Wed 2025-10-01 14:59:29 UTC; 7s ago Trigger: Thu 2025-10-02 04:54:23 UTC; 13h left Triggers: ● apt-daily.service ● apt-daily-upgrade.timer - Daily apt upgrade and clean activities Loaded: loaded (/usr/lib/systemd/system/apt-daily-upgrade.timer; enabled; preset: enabled) Active: active (waiting) since Wed 2025-10-01 14:59:29 UTC; 7s ago Trigger: Thu 2025-10-02 06:10:29 UTC; 15h left Triggers: ● apt-daily-upgrade.service ``` ## During VM creation When you create a new VM, you can enable unattended upgrades for the VM in the [user data configuration](https://docs.nebius.com/compute/virtual-machines/manage.md#optional-create-a-user-data-configuration). On the VM creation page in to the **User data** section, enable the custom cloud-init configuration. The window below contains the code that specifies users who can connect to the VM. Add the following code to enable updates: ```yaml users: - name: $USER sudo: ALL=(ALL) NOPASSWD:ALL shell: /bin/bash ssh_authorized_keys: - $(cat ~/.ssh/id_ed25519.pub) package_update: true packages: - unattended-upgrades write_files: - path: /etc/apt/apt.conf.d/20auto-upgrades permissions: '0644' content: | APT::Periodic::Update-Package-Lists "1"; APT::Periodic::Unattended-Upgrade "1"; runcmd: - systemctl unmask apt-daily.service apt-daily-upgrade.service - systemctl enable --now apt-daily.timer apt-daily-upgrade.timer - systemctl restart unattended-upgrades ``` Create a configuration in the [cloud-init](https://cloudinit.readthedocs.io/en/latest/explanation/about-cloud-config.html) format. Add the following code to enable updates for users who can connect to the VM: ```bash export USER_DATA=$(jq -Rrs '.' < Create a configuration in the [cloud-init](https://cloudinit.readthedocs.io/en/latest/explanation/about-cloud-config.html) format. Add the following code to enable updates for users who can connect to the VM: ```bash export USER_DATA=$(jq -Rrs '.' < Create a configuration in the [cloud-init](https://cloudinit.readthedocs.io/en/latest/explanation/about-cloud-config.html) format. Add the following code to enable updates for users who can connect to the VM: ```go publicKeyBytes, err := os.ReadFile( os.ExpandEnv("$HOME/.ssh/id_ed25519.pub"), ) if err != nil { return err } publicKey := strings.TrimSpace(string(publicKeyBytes)) userData := "#cloud-config\nusers:\n" + " - name: user\n" + " sudo: ALL=(ALL) NOPASSWD:ALL\n" + " shell: /bin/bash\n" + " ssh_authorized_keys:\n" + " - " + publicKey + "\n\n" + "package_update: true\n" + "packages:\n" + " - unattended-upgrades\n\n" + "write_files:\n" + " - path: /etc/apt/apt.conf.d/20auto-upgrades\n" + " permissions: '0644'\n" + " content: |\n" + " APT::Periodic::Update-Package-Lists \"1\";\n" + " APT::Periodic::Unattended-Upgrade \"1\";\n\n" + "runcmd:\n" + " - systemctl unmask apt-daily.service apt-daily-upgrade.service\n" + " - systemctl enable --now apt-daily.timer apt-daily-upgrade.timer\n" + " - systemctl restart unattended-upgrades" ``` Pass the configured user data to `InstanceSpec.CloudInitUserData` when creating the VM. Create a configuration in the [cloud-init](https://cloudinit.readthedocs.io/en/latest/explanation/about-cloud-config.html) format. Add the following code to enable updates for users who can connect to the VM: ```python public_key = ( Path.home() .joinpath(".ssh/id_ed25519.pub") .read_text() .strip() ) user_data = "\n".join( [ "#cloud-config", "users:", " - name: user", " sudo: ALL=(ALL) NOPASSWD:ALL", " shell: /bin/bash", " ssh_authorized_keys:", f" - {public_key}", "", "package_update: true", "packages:", " - unattended-upgrades", "", "write_files:", " - path: /etc/apt/apt.conf.d/20auto-upgrades", " permissions: '0644'", " content: |", ' APT::Periodic::Update-Package-Lists "1";', ' APT::Periodic::Unattended-Upgrade "1";', "", "runcmd:", " - systemctl unmask apt-daily.service apt-daily-upgrade.service", " - systemctl enable --now apt-daily.timer apt-daily-upgrade.timer", " - systemctl restart unattended-upgrades", ], ) ``` Pass the configured user data to `InstanceSpec.cloud_init_user_data` when creating the VM. Create a configuration in the [cloud-init](https://cloudinit.readthedocs.io/en/latest/explanation/about-cloud-config.html) format. Add the following code to enable updates for users who can connect to the VM: ```ts const publicKey = readFileSync( `${process.env.HOME}/.ssh/id_ed25519.pub`, "utf8", ).trim(); const userData = [ "#cloud-config", "users:", " - name: user", " sudo: ALL=(ALL) NOPASSWD:ALL", " shell: /bin/bash", " ssh_authorized_keys:", " - " + publicKey, "", "package_update: true", "packages:", " - unattended-upgrades", "", "write_files:", " - path: /etc/apt/apt.conf.d/20auto-upgrades", " permissions: '0644'", " content: |", ' APT::Periodic::Update-Package-Lists "1";', ' APT::Periodic::Unattended-Upgrade "1";', "", "runcmd:", " - systemctl unmask apt-daily.service apt-daily-upgrade.service", " - systemctl enable --now apt-daily.timer apt-daily-upgrade.timer", " - systemctl restart unattended-upgrades", ].join("\n"); ``` Pass the configured user data to `InstanceSpec.cloudInitUserData` when creating the VM. # Private and public IP addresses of Compute virtual machines Source: https://docs.nebius.com/compute/virtual-machines/network.md Virtual machines (VMs) in Compute can be reached at their private and public IP addresses. Assign them to manage access to the VM in a network. In addition, you can also configure [security groups](https://docs.nebius.com/vpc/security-groups/overview.md) to enable a firewall for your VMs and control ingress and egress traffic. For more information, see [Managing security groups and security rules](https://docs.nebius.com/vpc/security-groups/manage.md). ## Private IP addresses Each VM is created with a network interface that has a private IPv4 address. VMs can communicate with each other without internet access by using their private addresses. Private address ranges are randomly allocated from subnets within the `10.0.0.0/8` and `192.168.0.0/16` IPv4 CIDR blocks. Don't assign a private IPv4 address within the `172.17.0.0/16` CIDR block to a VM. The VMs running Docker cannot reach this address because the default boot disk images come with Docker preinstalled. As a result, this affects most VMs in the network. For more information, see [Virtual machine is unreachable due to a Docker subnet conflict](https://docs.nebius.com/compute/virtual-machines/docker-subnet-conflict.md). ## Prerequisites If you use the web console, you don't need to complete any prerequisites. [Install and configure](https://docs.nebius.com/cli/install.md) the Nebius AI Cloud CLI. [Install and initialize the Nebius SDK for Go](https://docs.nebius.com/grpc-api/sdk/go.md). [Install and initialize the Nebius SDK for Python](https://docs.nebius.com/grpc-api/sdk/python.md). [Install and initialize the Nebius SDK for JavaScript](https://docs.nebius.com/grpc-api/sdk/javascript.md). ### How to get a VM's private IP address 1. In the sidebar, go to **Compute** → **Virtual machines**. 2. On the **Standalone VMs** tab, open the page of the required VM. 3. Copy the **Private IPv4** value from the **Network** block. ```bash export PRIVATE_IP_ADDRESS=$(nebius compute instance get-by-name \ --name \ --format json \ | jq -r '.status.network_interfaces[0].ip_address.address | split("/")[0]') echo $PRIVATE_IP_ADDRESS ``` ```go privateIPInstance, err := sdk.Services().Compute().V1(). Instance().GetByName( ctx, &common.GetByNameRequest{ Name: "", }, ) if err != nil { return err } privateAddress := privateIPInstance.GetStatus(). GetNetworkInterfaces()[0].GetIpAddress().GetAddress() privateIPAddress := strings.Split(privateAddress, "/")[0] fmt.Println(privateIPAddress) ``` ```python instance_service = InstanceServiceClient(sdk) private_ip_instance = await instance_service.get_by_name( GetByNameRequest(name=""), ) private_address = ( private_ip_instance.status.network_interfaces[0] .ip_address.address ) private_ip_address = private_address.split("/")[0] print(private_ip_address) ``` ```ts const privateIpService = new InstanceService(sdk); const privateIpInstance = await privateIpService.getByName( GetByNameRequest.create({ name: "", }), ); const privateAddress = privateIpInstance.status ?.networkInterfaces[0]?.ipAddress?.address; const privateIpAddress = privateAddress?.split("/")[0]; console.log(privateIpAddress); ``` ### How to assign a secondary private IP address to a VM You can use secondary private IP addresses as a backup option in case of incidents. For example, a backup node can take a secondary address of the main node when the main one fails. As a result, routing to this address can be preserved. To assign a secondary private address to a VM: 1. In the sidebar, go to **Compute** → **Virtual machines**. 2. On the **Standalone VMs** tab, open the page of the required VM. 3. Click **Attach resource** → **Secondary private IP**. 4. In the window that opens, select whether you want to reuse an existing IP address as a secondary one or create a new address. 5. For an existing IP address, select an allocation and then click **Assign address**. 6. For a new address, specify the allocation name and address. After that, click **Create and assign address**. To assign a secondary private address to a VM, first create a private allocation with the required address. After that, add this allocation to the VM specification. 1. Get the [subnet ID](https://docs.nebius.com/vpc/networking/resources.md#how-to-get-a-subnet) for the allocation. 2. Check what private CIDR blocks this subnet includes: ```bash nebius vpc subnet get --id ``` The available CIDR blocks are specified in the `status.ipv4_private_cidrs` parameter in the output. 3. Create an allocation that reserves a private address. Use the address that belongs to one of the received private CIDR blocks. ```bash nebius vpc allocation create \ --name private_allocation \ --ipv4-private-subnet-id \ --ipv4-private-cidr ``` Copy the allocation ID from the output. 4. Assign the allocation to the required VM: ```bash nebius compute instance update \ --id \ --network-interfaces "[{\"aliases\": [{\"allocation_id\": \"\"}] }]" ``` For more information, see [Allocating custom private addresses to resources](https://docs.nebius.com/vpc/addressing/custom-private-addresses.md). To assign a secondary private address to a VM, first create a private allocation with the required address. After that, add this allocation to the VM specification. 1. Get the [subnet ID](https://docs.nebius.com/vpc/networking/resources.md#how-to-get-a-subnet) for the allocation. 2. Check what private CIDR blocks this subnet includes: ```go subnet, err := sdk.Services().VPC().V1(). Subnet().Get( ctx, &vpc.GetSubnetRequest{ Id: "", }, ) if err != nil { return err } fmt.Println(subnet) ``` The response includes the available CIDR blocks. 3. Create an allocation that reserves a private address. Use the address that belongs to one of the received private CIDR blocks. ```go privAllocOperation, err := sdk.Services().VPC().V1(). Allocation().Create( ctx, &vpc.CreateAllocationRequest{ Metadata: &common.ResourceMetadata{ Name: "private_allocation", }, Spec: &vpc.AllocationSpec{ IpSpec: &vpc.AllocationSpec_Ipv4Private{ Ipv4Private: &vpc.IPv4PrivateAllocationSpec{ Cidr: "", Pool: &vpc.IPv4PrivateAllocationSpec_SubnetId{ SubnetId: "", }, }, }, }, }, ) if err != nil { return err } if _, err = privAllocOperation.Wait(ctx); err != nil { return err } allocationID1 := privAllocOperation.ResourceID() ``` Copy the allocation ID from the response. 4. Assign the allocation to the required VM: ```go instanceForAlias, err := sdk.Services().Compute().V1(). Instance().Get( ctx, &compute.GetInstanceRequest{ Id: "", }, ) if err != nil { return err } if instanceForAlias.GetSpec() == nil { return errors.New("instance spec is missing") } networkInterfaces := instanceForAlias.Spec.NetworkInterfaces networkInterfaces[0].Aliases = []*compute.IPAlias{ { AllocationId: "", }, } aliasOperation, err := sdk.Services().Compute().V1(). Instance().Update( ctx, &compute.UpdateInstanceRequest{ Metadata: instanceForAlias.Metadata, Spec: instanceForAlias.Spec, }, ) if err != nil { return err } if _, err = aliasOperation.Wait(ctx); err != nil { return err } ``` For more information, see [Allocating custom private addresses to resources](https://docs.nebius.com/vpc/addressing/custom-private-addresses.md). To assign a secondary private address to a VM, first create a private allocation with the required address. After that, add this allocation to the VM specification. 1. Get the [subnet ID](https://docs.nebius.com/vpc/networking/resources.md#how-to-get-a-subnet) for the allocation. 2. Check what private CIDR blocks this subnet includes: ```python subnet_service = SubnetServiceClient(sdk) subnet = await subnet_service.get( GetSubnetRequest(id=""), ) print(subnet) ``` The response includes the available CIDR blocks. 3. Create an allocation that reserves a private address. Use the address that belongs to one of the received private CIDR blocks. ```python allocation_service = AllocationServiceClient(sdk) private_allocation_operation = await allocation_service.create( CreateAllocationRequest( metadata=ResourceMetadata(name="private_allocation"), spec=AllocationSpec( ipv4_private=IPv4PrivateAllocationSpec( cidr="", subnet_id="", ), ), ), ) await private_allocation_operation.wait() allocation_id_1 = private_allocation_operation.resource_id ``` Copy the allocation ID from the response. 4. Assign the allocation to the required VM: ```python instance_service = InstanceServiceClient(sdk) instance = await instance_service.get( GetInstanceRequest(id=""), ) if instance.spec is None: raise ValueError("instance spec is missing") instance.spec.network_interfaces[0].aliases = [ IPAlias(allocation_id=""), ] alias_operation = await instance_service.update( UpdateInstanceRequest( metadata=instance.metadata, spec=instance.spec, ), ) await alias_operation.wait() ``` For more information, see [Allocating custom private addresses to resources](https://docs.nebius.com/vpc/addressing/custom-private-addresses.md). To assign a secondary private address to a VM, first create a private allocation with the required address. After that, add this allocation to the VM specification. 1. Get the [subnet ID](https://docs.nebius.com/vpc/networking/resources.md#how-to-get-a-subnet) for the allocation. 2. Check what private CIDR blocks this subnet includes: ```ts const getSubnetService = new SubnetService(sdk); const subnet = await getSubnetService.get( GetSubnetRequest.create({ id: "", }), ); console.log(subnet); ``` The response includes the available CIDR blocks. 3. Create an allocation that reserves a private address. Use the address that belongs to one of the received private CIDR blocks. ```ts const privateAllocationService = new AllocationService(sdk); const privateAllocationOperation = await privateAllocationService.create( CreateAllocationRequest.create({ metadata: ResourceMetadata.create({ name: "private_allocation", }), spec: AllocationSpec.create({ ipSpec: { $case: "ipv4Private", ipv4Private: IPv4PrivateAllocationSpec.create({ cidr: "", pool: { $case: "subnetId", subnetId: "", }, }), }, }), }), ).result; await privateAllocationOperation.wait(); const allocationId1 = privateAllocationOperation.resourceId(); ``` Copy the allocation ID from the response. 4. Assign the allocation to the required VM: ```ts const aliasInstanceService = new InstanceService(sdk); const instanceForAlias = await aliasInstanceService.get( GetInstanceRequest.create({ id: "", }), ); if (!instanceForAlias.spec) { throw new Error("instance spec is missing"); } instanceForAlias.spec.networkInterfaces[0].aliases = [ IPAlias.create({ allocationId: "", }), ]; const aliasOperation = await aliasInstanceService.update( UpdateInstanceRequest.create({ metadata: instanceForAlias.metadata, spec: instanceForAlias.spec, }), ).result; await aliasOperation.wait(); ``` For more information, see [Allocating custom private addresses to resources](https://docs.nebius.com/vpc/addressing/custom-private-addresses.md). ## Public IP addresses When creating a VM, you can enable public IPv4 addressing for it. A VM's public address is mapped to its private address by using one-to-one NAT. All IP addresses assigned to a VM are [allocations](https://docs.nebius.com/vpc/overview.md#allocation). When you create a VM and automatically assign a static or dynamic public address, Compute creates an allocation for it and assigns this address to this VM. After that, Compute manages the lifecycle of this allocation. In particular, Compute deletes the allocation when the VM is deleted. Public IP addresses are allocated from the public IPv4 ranges available for a given project. The available range depends on the [region](https://docs.nebius.com/overview/regions.md) where you create a VM. For instructions on how to get these ranges, see [Getting public IPv4 ranges for projects](https://docs.nebius.com/vpc/addressing/public-address-ranges.md). If you assign an already existing allocation when you create a VM, Virtual Networks manages the lifecycle of this allocation. In this case, the allocation is preserved even if you delete the VM. If you need to secure your VM and make it isolated, you can create a VM without a public IP address. If you need to connect to this VM from the internet, you can [set up a WireGuard jump server](https://docs.nebius.com/compute/virtual-machines/wireguard.md). It has an IP address in the internet and an IP address in the VM's network. As a result, you can access the VM via the jump server from the internet. This approach enhances security and still provides access to the VM. ### How to enable a public IP address for a VM To enable a public address, either [create a VM](https://docs.nebius.com/compute/virtual-machines/network.md#how-to-create-a-vm-with-a-public-ip-address) with it or [assign a public address to an existing VM](https://docs.nebius.com/compute/virtual-machines/network.md#how-to-enable-a-public-ip-address-for-an-existing-vm). A VM must be in the same [region](https://docs.nebius.com/overview/regions.md) as the VM's subnet. An allocation assigned to a VM must belong to the VM's subnet. For more information, see [Virtual Networks documentation](https://docs.nebius.com/vpc/overview.md). #### How to create a VM with a public IP address On the **Network** step of the [VM creation wizard](https://docs.nebius.com/compute/virtual-machines/manage.md#create-a-vm), in the **Public IP address** field, select one of the following options: * **Auto assign dynamic IP** (default): A dynamic public IP address is randomly allocated from the [public IPv4 ranges available for the project](https://docs.nebius.com/vpc/addressing/public-address-ranges.md). Dynamic public IP addresses are not persistent. If a VM with a dynamic address has the `Stopped` status for more than one hour, the address automatically returns to the IPv4 public range of Nebius AI Cloud. After that, Compute may allocate this address to a different VM. If you want to preserve the address, assign a static address or an [allocation](https://docs.nebius.com/vpc/overview.md#allocation) to the VM. * **Auto assign static IP**: A static public IP address is randomly allocated from the public IPv4 ranges available for the project. If you stop a VM that has a static IP address, the address will not return to the range. However, if you delete this VM, the address will return. * **Select from already allocated**: A preliminarily created allocation is assigned to a VM. If you use an allocation, its address will not return to the IPv4 range even if you delete the VM. If you want to create a VM with a private address only, select the **No public IP** option. You can [create a VM](https://docs.nebius.com/compute/virtual-machines/manage.md) with a public IP address. This can be either a dynamic address, a static address or an [allocation](https://docs.nebius.com/vpc/overview.md#allocation): * A dynamic public IP address is randomly allocated from the [IPv4 public range](https://docs.nebius.com/compute/virtual-machines/network.md#get-public-ip-range) of Nebius AI Cloud and is not persistent. If a VM with a dynamic address has the `Stopped` status for more than one hour, the address is automatically returned to the IPv4 public range. After that, Compute may allocate this address to a different VM. * A static public IP address is also randomly allocated from the IPv4 public range of Nebius AI Cloud. If you stop a VM that has a static IP address, the address will not return to the range. However, if you delete this VM, the address will return. * An allocation allows you to use a reserved static public address for the VM. This address will not return to the IPv4 range even if you delete the VM. To create a VM with a **dynamic public IP address**: 1. Get the [subnet ID](https://docs.nebius.com/vpc/networking/resources.md#how-to-get-a-subnet-id) for the VM. 2. Run the following command and specify the subnet ID in it: ```bash nebius compute instance create \ ... \ --network-interfaces "[{\"name\": \"eth0\", \"ip_address\": {}, \"public_ip_address\": {}, \"subnet_id\": \"\"}]" ``` To create a VM with a **static public IP address**: 1. Get the [subnet ID](https://docs.nebius.com/vpc/networking/resources.md#how-to-get-a-subnet-id) for the VM. 2. Run the following command and specify the subnet ID in it: ```bash nebius compute instance create \ ... \ --network-interfaces "[{\"name\": \"eth0\", \"ip_address\": {}, \"public_ip_address\": {\"static\": true}, \"subnet_id\": \"\"}]" ``` To create a VM with an **already allocated public IP address**: 1. Get the [subnet ID](https://docs.nebius.com/vpc/networking/resources.md#how-to-get-a-subnet-id) for the VM. 2. Create an allocation that reserves a static public address: ```bash nebius vpc allocation create \ --ipv4-public-subnet-id \ --name ``` 3. Create the VM. Specify the subnet ID and the allocation ID in the command: ```bash nebius compute instance create \ ... \ --network-interfaces "[{\"name\": \"eth0\", \"ip_address\": {}, \"public_ip_address\": {\"allocation_id\": \"\"}, \"subnet_id\": \"\"}]" ``` If you want to create a VM with a private address only, omit the `public_ip_address` parameter in the `nebius compute instance create` command. You can [create a VM](https://docs.nebius.com/compute/virtual-machines/manage.md) with a public IP address. This can be either a dynamic address, a static address or an [allocation](https://docs.nebius.com/vpc/overview.md#allocation). To create a VM with a **dynamic public IP address**: 1. Get the [subnet ID](https://docs.nebius.com/vpc/networking/resources.md#how-to-get-a-subnet-id) for the VM. 2. Use the following code: ```go publicVMOperation, err := sdk.Services().Compute().V1(). Instance().Create( ctx, &compute.CreateInstanceRequest{ Metadata: &common.ResourceMetadata{ Name: "", }, Spec: &compute.InstanceSpec{ Resources: &compute.ResourcesSpec{ Platform: "cpu-e2", Size: &compute.ResourcesSpec_Preset{ Preset: "2vcpu-8gb", }, }, BootDisk: &compute.AttachedDiskSpec{ AttachMode: compute.AttachedDiskSpec_READ_WRITE, Type: &compute.AttachedDiskSpec_ExistingDisk{ ExistingDisk: &compute.ExistingDisk{ Id: publicBootDiskID, }, }, }, NetworkInterfaces: []*compute.NetworkInterfaceSpec{ { Name: "eth0", SubnetId: subnetID, IpAddress: &compute.IPAddress{}, PublicIpAddress: &compute.PublicIPAddress{}, }, }, }, }, ) if err != nil { return err } if _, err = publicVMOperation.Wait(ctx); err != nil { return err } ``` To create a VM with a **static public IP address**: 1. Get the [subnet ID](https://docs.nebius.com/vpc/networking/resources.md#how-to-get-a-subnet-id) for the VM. 2. Use the following code: ```go staticVMOperation, err := sdk.Services().Compute().V1(). Instance().Create( ctx, &compute.CreateInstanceRequest{ Metadata: &common.ResourceMetadata{ Name: "", }, Spec: &compute.InstanceSpec{ Resources: &compute.ResourcesSpec{ Platform: "cpu-e2", Size: &compute.ResourcesSpec_Preset{ Preset: "2vcpu-8gb", }, }, BootDisk: &compute.AttachedDiskSpec{ AttachMode: compute.AttachedDiskSpec_READ_WRITE, Type: &compute.AttachedDiskSpec_ExistingDisk{ ExistingDisk: &compute.ExistingDisk{ Id: staticBootDiskID, }, }, }, NetworkInterfaces: []*compute.NetworkInterfaceSpec{ { Name: "eth0", SubnetId: subnetID, IpAddress: &compute.IPAddress{}, PublicIpAddress: &compute.PublicIPAddress{ Static: true, }, }, }, }, }, ) if err != nil { return err } if _, err = staticVMOperation.Wait(ctx); err != nil { return err } ``` To create a VM with an **already allocated public IP address**: 1. Get the [subnet ID](https://docs.nebius.com/vpc/networking/resources.md#how-to-get-a-subnet-id) for the VM. 2. Create an allocation that reserves a static public address: ```go publicAllocationOperation, err := sdk.Services().VPC().V1(). Allocation().Create( ctx, &vpc.CreateAllocationRequest{ Metadata: &common.ResourceMetadata{ Name: "", }, Spec: &vpc.AllocationSpec{ IpSpec: &vpc.AllocationSpec_Ipv4Public{ Ipv4Public: &vpc.IPv4PublicAllocationSpec{ Pool: &vpc.IPv4PublicAllocationSpec_SubnetId{ SubnetId: "", }, }, }, }, }, ) if err != nil { return err } if _, err = publicAllocationOperation.Wait(ctx); err != nil { return err } allocationID := publicAllocationOperation.ResourceID() ``` 3. Create the VM: ```go allocationIP := &compute.PublicIPAddress_AllocationId{ AllocationId: "", } allocationVMOperation, err := sdk.Services().Compute().V1(). Instance().Create( ctx, &compute.CreateInstanceRequest{ Metadata: &common.ResourceMetadata{ Name: "", }, Spec: &compute.InstanceSpec{ Resources: &compute.ResourcesSpec{ Platform: "cpu-e2", Size: &compute.ResourcesSpec_Preset{ Preset: "2vcpu-8gb", }, }, BootDisk: &compute.AttachedDiskSpec{ AttachMode: compute.AttachedDiskSpec_READ_WRITE, Type: &compute.AttachedDiskSpec_ExistingDisk{ ExistingDisk: &compute.ExistingDisk{ Id: allocationBootDiskID, }, }, }, NetworkInterfaces: []*compute.NetworkInterfaceSpec{ { Name: "eth0", SubnetId: subnetID, IpAddress: &compute.IPAddress{}, PublicIpAddress: &compute.PublicIPAddress{ Allocation: allocationIP, }, }, }, }, }, ) if err != nil { return err } if _, err = allocationVMOperation.Wait(ctx); err != nil { return err } ``` Create a VM with a private address only: ```go privateOnlyOperation, err := sdk.Services().Compute().V1(). Instance().Create( ctx, &compute.CreateInstanceRequest{ Metadata: &common.ResourceMetadata{ Name: "", }, Spec: &compute.InstanceSpec{ Resources: &compute.ResourcesSpec{ Platform: "cpu-e2", Size: &compute.ResourcesSpec_Preset{ Preset: "2vcpu-8gb", }, }, BootDisk: &compute.AttachedDiskSpec{ AttachMode: compute.AttachedDiskSpec_READ_WRITE, Type: &compute.AttachedDiskSpec_ExistingDisk{ ExistingDisk: &compute.ExistingDisk{ Id: privateBootDiskID, }, }, }, NetworkInterfaces: []*compute.NetworkInterfaceSpec{ { Name: "eth0", SubnetId: subnetID, IpAddress: &compute.IPAddress{}, }, }, }, }, ) if err != nil { return err } if _, err = privateOnlyOperation.Wait(ctx); err != nil { return err } ``` You can [create a VM](https://docs.nebius.com/compute/virtual-machines/manage.md) with a public IP address. This can be either a dynamic address, a static address or an [allocation](https://docs.nebius.com/vpc/overview.md#allocation). To create a VM with a **dynamic public IP address**: 1. Get the [subnet ID](https://docs.nebius.com/vpc/networking/resources.md#how-to-get-a-subnet-id) for the VM. 2. Use the following code: ```python instance_service = InstanceServiceClient(sdk) public_vm_operation = await instance_service.create( CreateInstanceRequest( metadata=ResourceMetadata(name=""), spec=InstanceSpec( resources=ResourcesSpec( platform="cpu-e2", preset="2vcpu-8gb", ), boot_disk=AttachedDiskSpec( attach_mode=AttachedDiskSpec.AttachMode.READ_WRITE, existing_disk=ExistingDisk(id=public_boot_disk_id), ), network_interfaces=[ NetworkInterfaceSpec( name="eth0", subnet_id=subnet_id, ip_address=IPAddress(), public_ip_address=PublicIPAddress(), ), ], ), ), ) await public_vm_operation.wait() ``` To create a VM with a **static public IP address**: 1. Get the [subnet ID](https://docs.nebius.com/vpc/networking/resources.md#how-to-get-a-subnet-id) for the VM. 2. Use the following code: ```python instance_service = InstanceServiceClient(sdk) static_vm_operation = await instance_service.create( CreateInstanceRequest( metadata=ResourceMetadata(name=""), spec=InstanceSpec( resources=ResourcesSpec( platform="cpu-e2", preset="2vcpu-8gb", ), boot_disk=AttachedDiskSpec( attach_mode=AttachedDiskSpec.AttachMode.READ_WRITE, existing_disk=ExistingDisk(id=static_boot_disk_id), ), network_interfaces=[ NetworkInterfaceSpec( name="eth0", subnet_id=subnet_id, ip_address=IPAddress(), public_ip_address=PublicIPAddress(static=True), ), ], ), ), ) await static_vm_operation.wait() ``` To create a VM with an **already allocated public IP address**: 1. Get the [subnet ID](https://docs.nebius.com/vpc/networking/resources.md#how-to-get-a-subnet-id) for the VM. 2. Create an allocation that reserves a static public address: ```python allocation_service = AllocationServiceClient(sdk) public_allocation_operation = await allocation_service.create( CreateAllocationRequest( metadata=ResourceMetadata(name=""), spec=AllocationSpec( ipv4_public=IPv4PublicAllocationSpec( subnet_id="", ), ), ), ) await public_allocation_operation.wait() allocation_id = public_allocation_operation.resource_id ``` 3. Create the VM: ```python instance_service = InstanceServiceClient(sdk) allocation_vm_operation = await instance_service.create( CreateInstanceRequest( metadata=ResourceMetadata(name=""), spec=InstanceSpec( resources=ResourcesSpec( platform="cpu-e2", preset="2vcpu-8gb", ), boot_disk=AttachedDiskSpec( attach_mode=AttachedDiskSpec.AttachMode.READ_WRITE, existing_disk=ExistingDisk( id=allocation_boot_disk_id, ), ), network_interfaces=[ NetworkInterfaceSpec( name="eth0", subnet_id=subnet_id, ip_address=IPAddress(), public_ip_address=PublicIPAddress( allocation_id="", ), ), ], ), ), ) await allocation_vm_operation.wait() ``` Create a VM with a private address only: ```python instance_service = InstanceServiceClient(sdk) private_only_operation = await instance_service.create( CreateInstanceRequest( metadata=ResourceMetadata(name=""), spec=InstanceSpec( resources=ResourcesSpec( platform="cpu-e2", preset="2vcpu-8gb", ), boot_disk=AttachedDiskSpec( attach_mode=AttachedDiskSpec.AttachMode.READ_WRITE, existing_disk=ExistingDisk(id=private_boot_disk_id), ), network_interfaces=[ NetworkInterfaceSpec( name="eth0", subnet_id=subnet_id, ip_address=IPAddress(), ), ], ), ), ) await private_only_operation.wait() ``` You can [create a VM](https://docs.nebius.com/compute/virtual-machines/manage.md) with a public IP address. This can be either a dynamic address, a static address or an [allocation](https://docs.nebius.com/vpc/overview.md#allocation). To create a VM with a **dynamic public IP address**: 1. Get the [subnet ID](https://docs.nebius.com/vpc/networking/resources.md#how-to-get-a-subnet-id) for the VM. 2. Use the following code: ```ts const publicVmService = new InstanceService(sdk); const publicVmOperation = await publicVmService.create( CreateInstanceRequest.create({ metadata: ResourceMetadata.create({ name: "", }), spec: InstanceSpec.create({ resources: ResourcesSpec.create({ platform: "cpu-e2", size: { $case: "preset", preset: "2vcpu-8gb", }, }), bootDisk: AttachedDiskSpec.create({ attachMode: AttachedDiskSpec_AttachMode.READ_WRITE, type: { $case: "existingDisk", existingDisk: ExistingDisk.create({ id: publicBootDiskId, }), }, }), networkInterfaces: [ NetworkInterfaceSpec.create({ name: "eth0", subnetId, ipAddress: IPAddress.create({}), publicIpAddress: PublicIPAddress.create({}), }), ], }), }), ).result; await publicVmOperation.wait(); ``` To create a VM with a **static public IP address**: 1. Get the [subnet ID](https://docs.nebius.com/vpc/networking/resources.md#how-to-get-a-subnet-id) for the VM. 2. Use the following code: ```ts const staticVmService = new InstanceService(sdk); const staticVmOperation = await staticVmService.create( CreateInstanceRequest.create({ metadata: ResourceMetadata.create({ name: "", }), spec: InstanceSpec.create({ resources: ResourcesSpec.create({ platform: "cpu-e2", size: { $case: "preset", preset: "2vcpu-8gb", }, }), bootDisk: AttachedDiskSpec.create({ attachMode: AttachedDiskSpec_AttachMode.READ_WRITE, type: { $case: "existingDisk", existingDisk: ExistingDisk.create({ id: staticBootDiskId, }), }, }), networkInterfaces: [ NetworkInterfaceSpec.create({ name: "eth0", subnetId, ipAddress: IPAddress.create({}), publicIpAddress: PublicIPAddress.create({ static: true, }), }), ], }), }), ).result; await staticVmOperation.wait(); ``` To create a VM with an **already allocated public IP address**: 1. Get the [subnet ID](https://docs.nebius.com/vpc/networking/resources.md#how-to-get-a-subnet-id) for the VM. 2. Create an allocation that reserves a static public address: ```ts const publicAllocationService = new AllocationService(sdk); const publicAllocationOperation = await publicAllocationService.create( CreateAllocationRequest.create({ metadata: ResourceMetadata.create({ name: "", }), spec: AllocationSpec.create({ ipSpec: { $case: "ipv4Public", ipv4Public: IPv4PublicAllocationSpec.create({ pool: { $case: "subnetId", subnetId: "", }, }), }, }), }), ).result; await publicAllocationOperation.wait(); const allocationId = publicAllocationOperation.resourceId(); ``` 3. Create the VM: ```ts const allocationVmService = new InstanceService(sdk); const allocationVmOperation = await allocationVmService.create( CreateInstanceRequest.create({ metadata: ResourceMetadata.create({ name: "", }), spec: InstanceSpec.create({ resources: ResourcesSpec.create({ platform: "cpu-e2", size: { $case: "preset", preset: "2vcpu-8gb", }, }), bootDisk: AttachedDiskSpec.create({ attachMode: AttachedDiskSpec_AttachMode.READ_WRITE, type: { $case: "existingDisk", existingDisk: ExistingDisk.create({ id: allocationBootDiskId, }), }, }), networkInterfaces: [ NetworkInterfaceSpec.create({ name: "eth0", subnetId, ipAddress: IPAddress.create({}), publicIpAddress: PublicIPAddress.create({ allocation: { $case: "allocationId", allocationId: "", }, }), }), ], }), }), ).result; await allocationVmOperation.wait(); ``` Create a VM with a private address only: ```ts const privateOnlyService = new InstanceService(sdk); const privateOnlyOperation = await privateOnlyService.create( CreateInstanceRequest.create({ metadata: ResourceMetadata.create({ name: "", }), spec: InstanceSpec.create({ resources: ResourcesSpec.create({ platform: "cpu-e2", size: { $case: "preset", preset: "2vcpu-8gb", }, }), bootDisk: AttachedDiskSpec.create({ attachMode: AttachedDiskSpec_AttachMode.READ_WRITE, type: { $case: "existingDisk", existingDisk: ExistingDisk.create({ id: privateBootDiskId, }), }, }), networkInterfaces: [ NetworkInterfaceSpec.create({ name: "eth0", subnetId, ipAddress: IPAddress.create({}), }), ], }), }), ).result; await privateOnlyOperation.wait(); ``` If an allocation with a public address has not been assigned to any resource for 30 days, Nebius AI Cloud can delete this allocation and release its address. If you want to preserve the address, assign its allocation to a Nebius AI Cloud resource. #### How to enable a public IP address for an existing VM You can only assign one public IP address to a VM. If the VM already has a public address, you cannot assign one more. 1. In the [web console](https://console.nebius.com), go to **Compute** → **Virtual machines**. 2. On the **Standalone VMs** tab, open the page of the required VM. 3. Click **Attach resource** → **Public IP address**. 4. In the window that opens, select whether you want to assign an existing IP address or create a new one. 5. For an existing IP address, select the required one and then click **Assign address**. 6. For a new address, specify the address type: dynamic or static. After that, click **Create and assign address**. After you enable an IP address for a VM, you can change the type of this address: make it static or dynamic. To do so, go to the VM page, open the **Network interface** tab and then click  → **Edit type** in the line of the required address. To enable a **dynamic public IP address** for a VM, run the following command: ```bash nebius compute instance update \ --id \ --network-interfaces "[{\"public_ip_address\": {} }]" ``` To enable a **static public IP address** for a VM, run the following command: ```bash nebius compute instance update \ --id \ --network-interfaces "[{\"public_ip_address\": {\"static\": true}}]" ``` To assign an **already allocated public IP address** to a VM: 1. Get the [subnet ID](https://docs.nebius.com/vpc/networking/resources.md#how-to-get-a-subnet-id) for the VM. 2. Create an allocation that reserves a static public address: ```bash nebius vpc allocation create \ --ipv4-public-subnet-id \ --name ``` 3. Assign this allocation to the VM: ```bash nebius compute instance update \ --id \ --network-interfaces "[{\"public_ip_address\": {\"allocation_id\": \"\"}}]" ``` Enable a **dynamic public IP address** for a VM: ```go privateInstance1, err := sdk.Services().Compute().V1(). Instance().Get( ctx, &compute.GetInstanceRequest{ Id: "", }, ) if err != nil { return err } if privateInstance1.GetSpec() == nil { return errors.New("instance spec is missing") } privateInstance1.Spec.NetworkInterfaces[0]. PublicIpAddress = &compute.PublicIPAddress{} dynamicIPOperation, err := sdk.Services().Compute().V1(). Instance().Update( ctx, &compute.UpdateInstanceRequest{ Metadata: privateInstance1.Metadata, Spec: privateInstance1.Spec, }, ) if err != nil { return err } if _, err = dynamicIPOperation.Wait(ctx); err != nil { return err } ``` Enable a **static public IP address** for a VM: ```go privateInstance2, err := sdk.Services().Compute().V1(). Instance().Get( ctx, &compute.GetInstanceRequest{ Id: "", }, ) if err != nil { return err } if privateInstance2.GetSpec() == nil { return errors.New("instance spec is missing") } privateInstance2.Spec.NetworkInterfaces[0]. PublicIpAddress = &compute.PublicIPAddress{Static: true} staticIPOperation, err := sdk.Services().Compute().V1(). Instance().Update( ctx, &compute.UpdateInstanceRequest{ Metadata: privateInstance2.Metadata, Spec: privateInstance2.Spec, }, ) if err != nil { return err } if _, err = staticIPOperation.Wait(ctx); err != nil { return err } ``` To assign an **already allocated public IP address** to a VM: 1. Get the [subnet ID](https://docs.nebius.com/vpc/networking/resources.md#how-to-get-a-subnet-id) for the VM. 2. Create an allocation that reserves a static public address: ```go publicAllocationOperation, err := sdk.Services().VPC().V1(). Allocation().Create( ctx, &vpc.CreateAllocationRequest{ Metadata: &common.ResourceMetadata{ Name: "", }, Spec: &vpc.AllocationSpec{ IpSpec: &vpc.AllocationSpec_Ipv4Public{ Ipv4Public: &vpc.IPv4PublicAllocationSpec{ Pool: &vpc.IPv4PublicAllocationSpec_SubnetId{ SubnetId: "", }, }, }, }, }, ) if err != nil { return err } if _, err = publicAllocationOperation.Wait(ctx); err != nil { return err } allocationID := publicAllocationOperation.ResourceID() ``` 3. Assign this allocation to the VM: ```go privateInstance3, err := sdk.Services().Compute().V1(). Instance().Get( ctx, &compute.GetInstanceRequest{ Id: "", }, ) if err != nil { return err } if privateInstance3.GetSpec() == nil { return errors.New("instance spec is missing") } privateInstance3.Spec.NetworkInterfaces[0]. PublicIpAddress = &compute.PublicIPAddress{ Allocation: &compute.PublicIPAddress_AllocationId{ AllocationId: "", }, } allocationIPOperation, err := sdk.Services().Compute().V1(). Instance().Update( ctx, &compute.UpdateInstanceRequest{ Metadata: privateInstance3.Metadata, Spec: privateInstance3.Spec, }, ) if err != nil { return err } if _, err = allocationIPOperation.Wait(ctx); err != nil { return err } ``` Enable a **dynamic public IP address** for a VM: ```python instance_service = InstanceServiceClient(sdk) private_instance_1 = await instance_service.get( GetInstanceRequest(id=""), ) if private_instance_1.spec is None: raise ValueError("instance spec is missing") private_instance_1.spec.network_interfaces[0].public_ip_address = ( PublicIPAddress() ) dynamic_ip_operation = await instance_service.update( UpdateInstanceRequest( metadata=private_instance_1.metadata, spec=private_instance_1.spec, ), ) await dynamic_ip_operation.wait() ``` Enable a **static public IP address** for a VM: ```python instance_service = InstanceServiceClient(sdk) private_instance_2 = await instance_service.get( GetInstanceRequest(id=""), ) if private_instance_2.spec is None: raise ValueError("instance spec is missing") private_instance_2.spec.network_interfaces[0].public_ip_address = ( PublicIPAddress(static=True) ) static_ip_operation = await instance_service.update( UpdateInstanceRequest( metadata=private_instance_2.metadata, spec=private_instance_2.spec, ), ) await static_ip_operation.wait() ``` To assign an **already allocated public IP address** to a VM: 1. Get the [subnet ID](https://docs.nebius.com/vpc/networking/resources.md#how-to-get-a-subnet-id) for the VM. 2. Create an allocation that reserves a static public address: ```python allocation_service = AllocationServiceClient(sdk) public_allocation_operation = await allocation_service.create( CreateAllocationRequest( metadata=ResourceMetadata(name=""), spec=AllocationSpec( ipv4_public=IPv4PublicAllocationSpec( subnet_id="", ), ), ), ) await public_allocation_operation.wait() allocation_id = public_allocation_operation.resource_id ``` 3. Assign this allocation to the VM: ```python instance_service = InstanceServiceClient(sdk) private_instance_3 = await instance_service.get( GetInstanceRequest(id=""), ) if private_instance_3.spec is None: raise ValueError("instance spec is missing") private_instance_3.spec.network_interfaces[0].public_ip_address = ( PublicIPAddress(allocation_id="") ) allocation_ip_operation = await instance_service.update( UpdateInstanceRequest( metadata=private_instance_3.metadata, spec=private_instance_3.spec, ), ) await allocation_ip_operation.wait() ``` Enable a **dynamic public IP address** for a VM: ```ts const dynamicIpService = new InstanceService(sdk); const privateInstance1 = await dynamicIpService.get( GetInstanceRequest.create({ id: "", }), ); if (!privateInstance1.spec) { throw new Error("instance spec is missing"); } privateInstance1.spec.networkInterfaces[0].publicIpAddress = PublicIPAddress.create({}); const dynamicIpOperation = await dynamicIpService.update( UpdateInstanceRequest.create({ metadata: privateInstance1.metadata, spec: privateInstance1.spec, }), ).result; await dynamicIpOperation.wait(); ``` Enable a **static public IP address** for a VM: ```ts const staticIpService = new InstanceService(sdk); const privateInstance2 = await staticIpService.get( GetInstanceRequest.create({ id: "", }), ); if (!privateInstance2.spec) { throw new Error("instance spec is missing"); } privateInstance2.spec.networkInterfaces[0].publicIpAddress = PublicIPAddress.create({ static: true, }); const staticIpOperation = await staticIpService.update( UpdateInstanceRequest.create({ metadata: privateInstance2.metadata, spec: privateInstance2.spec, }), ).result; await staticIpOperation.wait(); ``` To assign an **already allocated public IP address** to a VM: 1. Get the [subnet ID](https://docs.nebius.com/vpc/networking/resources.md#how-to-get-a-subnet-id) for the VM. 2. Create an allocation that reserves a static public address: ```ts const publicAllocationService = new AllocationService(sdk); const publicAllocationOperation = await publicAllocationService.create( CreateAllocationRequest.create({ metadata: ResourceMetadata.create({ name: "", }), spec: AllocationSpec.create({ ipSpec: { $case: "ipv4Public", ipv4Public: IPv4PublicAllocationSpec.create({ pool: { $case: "subnetId", subnetId: "", }, }), }, }), }), ).result; await publicAllocationOperation.wait(); const allocationId = publicAllocationOperation.resourceId(); ``` 3. Assign this allocation to the VM: ```ts const allocationIpService = new InstanceService(sdk); const privateInstance3 = await allocationIpService.get( GetInstanceRequest.create({ id: "", }), ); if (!privateInstance3.spec) { throw new Error("instance spec is missing"); } privateInstance3.spec.networkInterfaces[0].publicIpAddress = PublicIPAddress.create({ allocation: { $case: "allocationId", allocationId: "", }, }); const allocationIpOperation = await allocationIpService.update( UpdateInstanceRequest.create({ metadata: privateInstance3.metadata, spec: privateInstance3.spec, }), ).result; await allocationIpOperation.wait(); ``` ### How to get a VM's public IP address 1. In the sidebar, go to **Compute** → **Virtual machines**. 2. On the **Standalone VMs** tab, open the page of the required VM. 3. Copy the **Public IPv4** value from the **Network** block. ```bash export PUBLIC_IP_ADDRESS=$(nebius compute instance get-by-name \ --name \ --format json \ | jq -r '.status.network_interfaces[0].public_ip_address.address | split("/")[0]') echo $PUBLIC_IP_ADDRESS ``` ```go publicIPInstance, err := sdk.Services().Compute().V1(). Instance().GetByName( ctx, &common.GetByNameRequest{ Name: "", }, ) if err != nil { return err } publicAddress := publicIPInstance.GetStatus(). GetNetworkInterfaces()[0].GetPublicIpAddress().GetAddress() publicIPAddress := strings.Split(publicAddress, "/")[0] fmt.Println(publicIPAddress) ``` ```python instance_service = InstanceServiceClient(sdk) public_ip_instance = await instance_service.get_by_name( GetByNameRequest(name=""), ) public_address = ( public_ip_instance.status.network_interfaces[0] .public_ip_address.address ) public_ip_address = public_address.split("/")[0] print(public_ip_address) ``` ```ts const publicIpLookupService = new InstanceService(sdk); const publicIpInstance = await publicIpLookupService.getByName( GetByNameRequest.create({ name: "", }), ); const publicAddress = publicIpInstance.status ?.networkInterfaces[0]?.publicIpAddress?.address; const publicIpAddress = publicAddress?.split("/")[0]; console.log(publicIpAddress); ``` ### How to migrate a public static IP address from one VM to another To reassign a public static IP address from one VM to another, detach this address from the source VM and attach it to the target VM. Before you begin, make sure that you have a VM with a public static IP address (the source VM) and a VM without a public address (the target VM). For information about creating VMs, see [How to create a virtual machine in Nebius AI Cloud](https://docs.nebius.com/compute/virtual-machines/manage.md). To migrate the address, do the following: 1. To get IDs of the source and target VMs, list all VMs: ```bash nebius compute instance list ``` 2. Store the VMs' IDs in environment variables: ```bash SOURCE_VM="" TARGET_VM="" ``` 3. Extract the allocation ID of the public static IP address currently attached to the source VM. This value is required to reassign the IP address to another VM. ```bash ALLOC_ID=$(nebius compute instance get \ --id "$SOURCE_VM" \ --format json | jq -r '.status.network_interfaces[] | select(.name=="eth0") | .public_ip_address.allocation_id') ``` 4. Pin the allocation in the source VM specification. This prevents the allocation from being deleted when you detach it in the next step. ```bash nebius compute instance update --patch \ --id "$SOURCE_VM" \ "$(jq -n --arg alloc "$ALLOC_ID" '{"spec":{"network_interfaces":[{"name":"eth0","public_ip_address":{"static":true,"allocation_id":$alloc}}]}}')" ``` 5. Remove the public IP address from the source VM. This makes the allocation available for reuse. ```bash nebius compute instance update --patch \ --id "$SOURCE_VM" \ '{"spec":{"network_interfaces": [{"name":"eth0","public_ip_address":null}]}}' ``` 6. Assign the same allocation ID to the target VM: ```bash nebius compute instance update --patch \ --id "$TARGET_VM" \ "$(jq -n --arg alloc "$ALLOC_ID" '{"spec":{"network_interfaces": [{"name":"eth0","public_ip_address":{"static":true,"allocation_id":$alloc}}]}}')" ``` The output of this command shows that the allocation is attached to the target VM. 1. To get IDs of the source and target VMs, list all VMs: ```go instances, err := sdk.Services().Compute().V1(). Instance().List( ctx, &compute.ListInstancesRequest{}, ) if err != nil { return err } fmt.Println(instances) ``` 2. Set `sourceVM` to the ID of the source VM and `targetVM` to the ID of the target VM. 3. Extract the allocation ID of the public static IP address currently attached to the source VM. This value is required to reassign the IP address to another VM. ```go sourceInstance, err := sdk.Services().Compute().V1(). Instance().Get( ctx, &compute.GetInstanceRequest{ Id: sourceVM, }, ) if err != nil { return err } allocID := sourceInstance.GetStatus(). GetNetworkInterfaces()[0].GetPublicIpAddress().GetAllocationId() if allocID == "" { return errors.New("allocation ID is missing") } ``` 4. Pin the allocation in the source VM specification. This prevents the allocation from being deleted when you detach it in the next step. ```go sourceInstanceForPin, err := sdk.Services().Compute().V1(). Instance().Get( ctx, &compute.GetInstanceRequest{ Id: sourceVM, }, ) if err != nil { return err } if sourceInstanceForPin.GetSpec() == nil { return errors.New("instance spec is missing") } sourceInstanceForPin.Spec.NetworkInterfaces[0]. PublicIpAddress = &compute.PublicIPAddress{ Static: true, Allocation: &compute.PublicIPAddress_AllocationId{ AllocationId: allocID, }, } pinAllocationOperation, err := sdk.Services().Compute().V1(). Instance().Update( ctx, &compute.UpdateInstanceRequest{ Metadata: sourceInstanceForPin.Metadata, Spec: sourceInstanceForPin.Spec, }, ) if err != nil { return err } if _, err = pinAllocationOperation.Wait(ctx); err != nil { return err } ``` 5. Remove the public IP address from the source VM. This makes the allocation available for reuse. ```go removeInstance, err := sdk.Services().Compute().V1(). Instance().Get( ctx, &compute.GetInstanceRequest{ Id: sourceVM, }, ) if err != nil { return err } if removeInstance.GetSpec() == nil { return errors.New("instance spec is missing") } removeInstance.Spec.NetworkInterfaces[0]. PublicIpAddress = nil removeAddressOperation, err := sdk.Services().Compute().V1(). Instance().Update( ctx, &compute.UpdateInstanceRequest{ Metadata: removeInstance.Metadata, Spec: removeInstance.Spec, }, ) if err != nil { return err } if _, err = removeAddressOperation.Wait(ctx); err != nil { return err } ``` 6. Assign the same allocation ID to the target VM: ```go assignInstance, err := sdk.Services().Compute().V1(). Instance().Get( ctx, &compute.GetInstanceRequest{ Id: targetVM, }, ) if err != nil { return err } if assignInstance.GetSpec() == nil { return errors.New("instance spec is missing") } assignInstance.Spec.NetworkInterfaces[0]. PublicIpAddress = &compute.PublicIPAddress{ Static: true, Allocation: &compute.PublicIPAddress_AllocationId{ AllocationId: allocID, }, } assignAddressOperation, err := sdk.Services().Compute().V1(). Instance().Update( ctx, &compute.UpdateInstanceRequest{ Metadata: assignInstance.Metadata, Spec: assignInstance.Spec, }, ) if err != nil { return err } if _, err = assignAddressOperation.Wait(ctx); err != nil { return err } ``` 1. To get IDs of the source and target VMs, list all VMs: ```python instance_service = InstanceServiceClient(sdk) instances = await instance_service.list(ListInstancesRequest()) print(instances) ``` 2. Set `source_vm` to the ID of the source VM and `target_vm` to the ID of the target VM. 3. Extract the allocation ID of the public static IP address currently attached to the source VM. This value is required to reassign the IP address to another VM. ```python instance_service = InstanceServiceClient(sdk) source_instance = await instance_service.get( GetInstanceRequest(id=source_vm), ) alloc_id = ( source_instance.status.network_interfaces[0] .public_ip_address.allocation_id ) if not alloc_id: raise ValueError("allocation ID is missing") ``` 4. Pin the allocation in the source VM specification. This prevents the allocation from being deleted when you detach it in the next step. ```python instance_service = InstanceServiceClient(sdk) source_instance_for_pin = await instance_service.get( GetInstanceRequest(id=source_vm), ) if source_instance_for_pin.spec is None: raise ValueError("instance spec is missing") source_interfaces = source_instance_for_pin.spec.network_interfaces source_interfaces[0].public_ip_address = ( PublicIPAddress(static=True, allocation_id=alloc_id) ) pin_operation = await instance_service.update( UpdateInstanceRequest( metadata=source_instance_for_pin.metadata, spec=source_instance_for_pin.spec, ), ) await pin_operation.wait() ``` 5. Remove the public IP address from the source VM. This makes the allocation available for reuse. ```python instance_service = InstanceServiceClient(sdk) source_instance_for_removal = await instance_service.get( GetInstanceRequest(id=source_vm), ) if source_instance_for_removal.spec is None: raise ValueError("instance spec is missing") source_instance_for_removal.spec.network_interfaces[ 0 ].public_ip_address = None remove_address_operation = await instance_service.update( UpdateInstanceRequest( metadata=source_instance_for_removal.metadata, spec=source_instance_for_removal.spec, ), ) await remove_address_operation.wait() ``` 6. Assign the same allocation ID to the target VM: ```python instance_service = InstanceServiceClient(sdk) target_instance = await instance_service.get( GetInstanceRequest(id=target_vm), ) if target_instance.spec is None: raise ValueError("instance spec is missing") target_instance.spec.network_interfaces[0].public_ip_address = ( PublicIPAddress(static=True, allocation_id=alloc_id) ) assign_address_operation = await instance_service.update( UpdateInstanceRequest( metadata=target_instance.metadata, spec=target_instance.spec, ), ) await assign_address_operation.wait() ``` 1. To get IDs of the source and target VMs, list all VMs: ```ts const listInstanceService = new InstanceService(sdk); const instances = await listInstanceService.list( ListInstancesRequest.create({}), ); console.log(instances); ``` 2. Set `sourceVm` to the ID of the source VM and `targetVm` to the ID of the target VM. 3. Extract the allocation ID of the public static IP address currently attached to the source VM. This value is required to reassign the IP address to another VM. ```ts const sourceInstanceService = new InstanceService(sdk); const sourceInstance = await sourceInstanceService.get( GetInstanceRequest.create({ id: sourceVm, }), ); const allocId = sourceInstance.status ?.networkInterfaces[0]?.publicIpAddress?.allocationId; if (!allocId) { throw new Error("allocation ID is missing"); } ``` 4. Pin the allocation in the source VM specification. This prevents the allocation from being deleted when you detach it in the next step. ```ts const pinAllocationService = new InstanceService(sdk); const sourceInstanceForPin = await pinAllocationService.get( GetInstanceRequest.create({ id: sourceVm, }), ); if (!sourceInstanceForPin.spec) { throw new Error("instance spec is missing"); } sourceInstanceForPin.spec.networkInterfaces[0].publicIpAddress = PublicIPAddress.create({ static: true, allocation: { $case: "allocationId", allocationId: allocId, }, }); const pinAllocationOperation = await pinAllocationService.update( UpdateInstanceRequest.create({ metadata: sourceInstanceForPin.metadata, spec: sourceInstanceForPin.spec, }), ).result; await pinAllocationOperation.wait(); ``` 5. Remove the public IP address from the source VM. This makes the allocation available for reuse. ```ts const removeAddressService = new InstanceService(sdk); const sourceInstanceForRemoval = await removeAddressService.get( GetInstanceRequest.create({ id: sourceVm, }), ); if (!sourceInstanceForRemoval.spec) { throw new Error("instance spec is missing"); } sourceInstanceForRemoval.spec.networkInterfaces[0].publicIpAddress = undefined; const removeAddressOperation = await removeAddressService.update( UpdateInstanceRequest.create({ metadata: sourceInstanceForRemoval.metadata, spec: sourceInstanceForRemoval.spec, }), ).result; await removeAddressOperation.wait(); ``` 6. Assign the same allocation ID to the target VM: ```ts const assignAddressService = new InstanceService(sdk); const targetInstance = await assignAddressService.get( GetInstanceRequest.create({ id: targetVm, }), ); if (!targetInstance.spec) { throw new Error("instance spec is missing"); } targetInstance.spec.networkInterfaces[0].publicIpAddress = PublicIPAddress.create({ static: true, allocation: { $case: "allocationId", allocationId: allocId, }, }); const assignAddressOperation = await assignAddressService.update( UpdateInstanceRequest.create({ metadata: targetInstance.metadata, spec: targetInstance.spec, }), ).result; await assignAddressOperation.wait(); ``` ## How to detach an IP address from a VM To detach a public address or a secondary private address from a VM: 1. In the [web console](https://console.nebius.com), go to **Compute** → **Virtual machines**. 2. On the **Standalone VMs** tab, open the page of the required VM and then go to the **Network interface** tab. 3. In the line of the allocation that you want to detach from a VM, click  → **Detach**. 4. In the window that opens, confirm the action. To detach a public IP address, set the `SOURCE_VM` environment variable to the VM ID and run the following command: ```bash nebius compute instance update --patch \ --id "$SOURCE_VM" \ '{"spec":{"network_interfaces": [{"name":"eth0","public_ip_address":null}]}}' ``` To detach a secondary private IP address, run the following command: ```bash nebius compute instance update \ --id \ --network-interfaces "[{\"aliases\": []}]" ``` If the VM has several secondary private IP addresses, keep the aliases that you do not want to detach in the `aliases` list. To detach a public IP address, set `sourceVM` to the VM ID: ```go removeInstance, err := sdk.Services().Compute().V1(). Instance().Get( ctx, &compute.GetInstanceRequest{ Id: sourceVM, }, ) if err != nil { return err } if removeInstance.GetSpec() == nil { return errors.New("instance spec is missing") } removeInstance.Spec.NetworkInterfaces[0]. PublicIpAddress = nil removeAddressOperation, err := sdk.Services().Compute().V1(). Instance().Update( ctx, &compute.UpdateInstanceRequest{ Metadata: removeInstance.Metadata, Spec: removeInstance.Spec, }, ) if err != nil { return err } if _, err = removeAddressOperation.Wait(ctx); err != nil { return err } ``` Detach a secondary private IP address: ```go detachAliasInstance, err := sdk.Services().Compute().V1(). Instance().Get( ctx, &compute.GetInstanceRequest{ Id: "", }, ) if err != nil { return err } if detachAliasInstance.GetSpec() == nil { return errors.New("instance spec is missing") } detachNetworkInterfaces := detachAliasInstance.Spec.NetworkInterfaces aliases := detachNetworkInterfaces[0].Aliases[:0] for _, alias := range detachNetworkInterfaces[0].Aliases { if alias.GetAllocationId() != "" { aliases = append(aliases, alias) } } detachNetworkInterfaces[0].Aliases = aliases detachAliasOperation, err := sdk.Services().Compute().V1(). Instance().Update( ctx, &compute.UpdateInstanceRequest{ Metadata: detachAliasInstance.Metadata, Spec: detachAliasInstance.Spec, }, ) if err != nil { return err } if _, err = detachAliasOperation.Wait(ctx); err != nil { return err } ``` To detach a public IP address, set `source_vm` to the VM ID: ```python instance_service = InstanceServiceClient(sdk) source_instance_for_removal = await instance_service.get( GetInstanceRequest(id=source_vm), ) if source_instance_for_removal.spec is None: raise ValueError("instance spec is missing") source_instance_for_removal.spec.network_interfaces[ 0 ].public_ip_address = None remove_address_operation = await instance_service.update( UpdateInstanceRequest( metadata=source_instance_for_removal.metadata, spec=source_instance_for_removal.spec, ), ) await remove_address_operation.wait() ``` Detach a secondary private IP address: ```python instance_service = InstanceServiceClient(sdk) detach_alias_instance = await instance_service.get( GetInstanceRequest(id=""), ) if detach_alias_instance.spec is None: raise ValueError("instance spec is missing") aliases = detach_alias_instance.spec.network_interfaces[0].aliases detach_alias_instance.spec.network_interfaces[0].aliases = [ alias for alias in aliases if alias.allocation_id != "" ] detach_alias_operation = await instance_service.update( UpdateInstanceRequest( metadata=detach_alias_instance.metadata, spec=detach_alias_instance.spec, ), ) await detach_alias_operation.wait() ``` To detach a public IP address, set `sourceVm` to the VM ID: ```ts const removeAddressService = new InstanceService(sdk); const sourceInstanceForRemoval = await removeAddressService.get( GetInstanceRequest.create({ id: sourceVm, }), ); if (!sourceInstanceForRemoval.spec) { throw new Error("instance spec is missing"); } sourceInstanceForRemoval.spec.networkInterfaces[0].publicIpAddress = undefined; const removeAddressOperation = await removeAddressService.update( UpdateInstanceRequest.create({ metadata: sourceInstanceForRemoval.metadata, spec: sourceInstanceForRemoval.spec, }), ).result; await removeAddressOperation.wait(); ``` Detach a secondary private IP address: ```ts const detachAliasService = new InstanceService(sdk); const detachAliasInstance = await detachAliasService.get( GetInstanceRequest.create({ id: "", }), ); if (!detachAliasInstance.spec) { throw new Error("instance spec is missing"); } const aliases = detachAliasInstance.spec.networkInterfaces[0].aliases ?? []; detachAliasInstance.spec.networkInterfaces[0].aliases = aliases.filter( (alias) => alias.allocationId !== "", ); const detachAliasOperation = await detachAliasService.update( UpdateInstanceRequest.create({ metadata: detachAliasInstance.metadata, spec: detachAliasInstance.spec, }), ).result; await detachAliasOperation.wait(); ``` # Tuning TCP window sizes on Linux virtual machines Source: https://docs.nebius.com/compute/virtual-machines/tcp-window-tuning.md TCP throughput depends on how much unacknowledged data a sender and receiver can keep in flight. On long-distance or high-latency connections, the default Linux TCP buffer limits can constrain a single flow before the network link is saturated. This article shows how to increase TCP receive and send window limits on a Linux virtual machine (VM) in Nebius AI Cloud. Use this tuning if your workload transfers large amounts of data over connections with both: * High bandwidth * Noticeable round-trip latency Typical examples include: * Cross-region replication * Large model or dataset transfers * Long-lived TCP sessions that need higher per-flow throughput If your traffic is short-lived, latency-sensitive, or limited by the application rather than the network path, this tuning may have little effect. ## Recommended values The following settings increase the maximum TCP buffer sizes while keeping default behavior unchanged: ```text net.ipv4.tcp_rmem = 4096 131072 268435456 net.ipv4.tcp_wmem = 4096 16384 268435456 net.core.rmem_max = 536870912 net.core.wmem_max = 536870912 net.ipv4.tcp_adv_win_scale = 1 ``` These values keep the minimum and default TCP buffer settings close to the Linux defaults, while increasing the maximum values for high-bandwidth links. The recommended maximum TCP window targets a single flow of about 3 Gbit/s over a 300 ms round-trip-time path. That bandwidth-delay product is about 108 MB, which is rounded up to 128 MiB and then doubled to account for the effect of `net.ipv4.tcp_adv_win_scale=1`. Larger TCP buffers can increase memory consumption under heavy connection fan-out. Verify available memory before applying this tuning on smaller VMs or on hosts with many simultaneous high-throughput flows. ## How to tune TCP window sizes ### Prerequisites Make sure that: 1. The VM runs Linux. 2. You can connect to the VM by using SSH. For more information, see [How to connect to virtual machines in Nebius AI Cloud](https://docs.nebius.com/compute/virtual-machines/connect.md). 3. You have `sudo` privileges on the VM. ### Apply the changes 1. Connect to the VM: ```bash ssh @ ``` 2. Create a sysctl configuration file: ```bash sudo tee /etc/sysctl.d/90-nebius-tcp-window.conf >/dev/null <<'EOF' net.ipv4.tcp_rmem = 4096 131072 268435456 net.ipv4.tcp_wmem = 4096 16384 268435456 net.core.rmem_max = 536870912 net.core.wmem_max = 536870912 net.ipv4.tcp_adv_win_scale = 1 EOF ``` 3. Apply the configuration: ```bash sudo sysctl --system ``` ### Verify the configuration Check that the VM reports the configured values: ```bash sysctl \ net.ipv4.tcp_rmem \ net.ipv4.tcp_wmem \ net.core.rmem_max \ net.core.wmem_max \ net.ipv4.tcp_adv_win_scale ``` Expected output: ```text net.ipv4.tcp_rmem = 4096 131072 268435456 net.ipv4.tcp_wmem = 4096 16384 268435456 net.core.rmem_max = 536870912 net.core.wmem_max = 536870912 net.ipv4.tcp_adv_win_scale = 1 ``` If your application still does not reach the expected throughput, check the end-to-end path for other limits such as application-level buffer sizing, rate limiting, packet loss or congestion on the remote side. ### Roll back the changes To remove the configuration: ```bash sudo rm /etc/sysctl.d/90-nebius-tcp-window.conf sudo sysctl --system ``` After rollback, the VM uses the remaining sysctl configuration from the operating system image and any other files in `/etc/sysctl.d`. # FQDN and hostname of a virtual machine Source: https://docs.nebius.com/compute/virtual-machines/fqdn.md When you create a virtual machine (VM), the service assigns an [FQDN](https://en.wikipedia.org/wiki/Fully_qualified_domain_name) to this VM. By using this FQDN, other VMs can access your VM within a single [network](https://docs.nebius.com/vpc/overview.md#network). You can configure the FQDN on your own or you can use the default FQDN: * The format of the default FQDN is the following: ```text ..compute.internal. ``` In this case, the FQDN (as well as the VM's ID) is only known after the VM is created. * The format of a custom FQDN is the following: ```text ..compute.internal. ``` You can [set the hostname](https://docs.nebius.com/compute/virtual-machines/fqdn.md#how-to-customize-an-fqdn) when you create or update a VM. You can configure an FQDN, but you cannot delete it. The guest OS hostname of the VM is set up during the VM creation; it matches the FQDN. If the FQDN is changed later, the guest OS hostname does not change; and it remains the same as the FQDN was when the VM was created. ## Prerequisites [Install and configure](https://docs.nebius.com/cli/install.md) the Nebius AI Cloud CLI. [Install and configure](https://docs.nebius.com/terraform-provider/install.md) the Nebius AI Cloud provider for Terraform. [Install and initialize the Nebius SDK for Go](https://docs.nebius.com/grpc-api/sdk/go.md). [Install and initialize the Nebius SDK for Python](https://docs.nebius.com/grpc-api/sdk/python.md). [Install and initialize the Nebius SDK for JavaScript](https://docs.nebius.com/grpc-api/sdk/javascript.md). ## How to get an FQDN To get an FQDN of a VM, run the following command: ```bash nebius compute instance get-by-name \ --name \ --format json \ | jq -r '.status.network_interfaces[0].fqdn | split("/")[0]' ``` The FQDN is specified in the `status.network_interfaces.fqdn` field of the output. Get an FQDN of a VM: ```go fqdnInstance, err := sdk.Services().Compute().V1(). Instance().GetByName( ctx, &common.GetByNameRequest{ Name: "", }, ) if err != nil { return err } fqdn := fqdnInstance.GetStatus().GetNetworkInterfaces()[0].GetFqdn() fmt.Println(strings.Split(fqdn, "/")[0]) ``` Get an FQDN of a VM: ```python fqdn_service = InstanceServiceClient(sdk) fqdn_instance = await fqdn_service.get_by_name( GetByNameRequest(name=""), ) fqdn = fqdn_instance.status.network_interfaces[0].fqdn print(fqdn.split("/")[0]) ``` Get an FQDN of a VM: ```ts const fqdnInstanceService = new InstanceService(sdk); const fqdnInstance = await fqdnInstanceService.getByName( GetByNameRequest.create({ name: "", }), ); const fqdn = fqdnInstance.status?.networkInterfaces[0]?.fqdn; console.log(fqdn?.split("/")[0]); ``` ## How to customize an FQDN If you do not want to use the default FQDN, you can use your own hostname instead of the VM's ID. To customize an FQDN, use the `hostname` parameter: * [Create a VM](https://docs.nebius.com/compute/virtual-machines/manage.md#create-a-vm) with a customized FQDN: ```bash nebius compute instance create \ ... \ --hostname ``` * Change an FQDN of an existing VM: ```bash nebius compute instance update --id --hostname ``` Use the following VM configuration: ```hcl resource "nebius_compute_v1_instance" "my_vm" { ... hostname = "" ... } ``` For more information, see [Create a VM](https://docs.nebius.com/compute/virtual-machines/manage.md#create-a-vm). * [Create a VM](https://docs.nebius.com/compute/virtual-machines/manage.md#create-a-vm) with a customized FQDN: ```go instanceOperation, err := sdk.Services().Compute().V1(). Instance().Create( ctx, &compute.CreateInstanceRequest{ Metadata: &common.ResourceMetadata{ Name: "vm-for-scenario", }, Spec: &compute.InstanceSpec{ Resources: &compute.ResourcesSpec{ Platform: "cpu-d3", Size: &compute.ResourcesSpec_Preset{ Preset: "4vcpu-16gb", }, }, BootDisk: &compute.AttachedDiskSpec{ AttachMode: compute.AttachedDiskSpec_READ_WRITE, DeviceId: "my-device", Type: &compute.AttachedDiskSpec_ExistingDisk{ ExistingDisk: &compute.ExistingDisk{ Id: bootDiskID, }, }, }, NetworkInterfaces: []*compute.NetworkInterfaceSpec{ { Name: "eth0", SubnetId: subnetID, IpAddress: &compute.IPAddress{}, PublicIpAddress: &compute.PublicIPAddress{}, }, }, Hostname: "", }, }, ) if err != nil { return err } if _, err = instanceOperation.Wait(ctx); err != nil { return err } vmID := instanceOperation.ResourceID() ``` * Change an FQDN of an existing VM: ```go instance, err = sdk.Services().Compute().V1(). Instance().Get( ctx, &compute.GetInstanceRequest{ Id: "", }, ) if err != nil { return err } if instance.GetSpec() == nil { return errors.New("instance spec is missing") } instance.Spec.Hostname = "" instanceOperation, err = sdk.Services().Compute().V1(). Instance().Update( ctx, &compute.UpdateInstanceRequest{ Metadata: instance.Metadata, Spec: instance.Spec, }, ) if err != nil { return err } if _, err = instanceOperation.Wait(ctx); err != nil { return err } ``` * [Create a VM](https://docs.nebius.com/compute/virtual-machines/manage.md#create-a-vm) with a customized FQDN: ```python instance_service = InstanceServiceClient(sdk) create_instance_operation = await instance_service.create( CreateInstanceRequest( metadata=ResourceMetadata(name="vm-for-scenario"), spec=InstanceSpec( resources=ResourcesSpec( platform="cpu-d3", preset="4vcpu-16gb", ), boot_disk=AttachedDiskSpec( attach_mode=AttachedDiskSpec.AttachMode.READ_WRITE, existing_disk=ExistingDisk(id=boot_disk_id), device_id="my-device", ), network_interfaces=[ NetworkInterfaceSpec( name="eth0", subnet_id=subnet_id, ip_address=IPAddress(), public_ip_address=PublicIPAddress(), ), ], hostname="", ), ), ) await create_instance_operation.wait() vm_id = create_instance_operation.resource_id ``` * Change an FQDN of an existing VM: ```python instance_service = InstanceServiceClient(sdk) instance = await instance_service.get( GetInstanceRequest(id=""), ) if instance.spec is None: raise ValueError("instance spec is missing") instance.spec.hostname = "" update_instance_operation = await instance_service.update( UpdateInstanceRequest( metadata=instance.metadata, spec=instance.spec, ), ) await update_instance_operation.wait() ``` * [Create a VM](https://docs.nebius.com/compute/virtual-machines/manage.md#create-a-vm) with a customized FQDN: ```ts const instanceService = new InstanceService(sdk); const createInstanceOperation = await instanceService.create( CreateInstanceRequest.create({ metadata: ResourceMetadata.create({ name: "vm-for-scenario", }), spec: InstanceSpec.create({ resources: ResourcesSpec.create({ platform: "cpu-d3", size: { $case: "preset", preset: "4vcpu-16gb", }, }), bootDisk: AttachedDiskSpec.create({ attachMode: AttachedDiskSpec_AttachMode.READ_WRITE, deviceId: "my-device", type: { $case: "existingDisk", existingDisk: ExistingDisk.create({ id: bootDiskId, }), }, }), networkInterfaces: [ NetworkInterfaceSpec.create({ name: "eth0", subnetId: subnetId, ipAddress: IPAddress.create({}), publicIpAddress: PublicIPAddress.create({}), }), ], hostname: "", }), }), ).result; await createInstanceOperation.wait(); const vmId = createInstanceOperation.resourceId(); ``` * Change an FQDN of an existing VM: ```ts const updateInstanceService = new InstanceService(sdk); const instanceForHostname = await updateInstanceService.get( GetInstanceRequest.create({ id: "", }), ); if (!instanceForHostname.spec) { throw new Error("instance spec is missing"); } instanceForHostname.spec.hostname = ""; const updateInstanceOperation = await updateInstanceService.update( UpdateInstanceRequest.create({ metadata: instanceForHostname.metadata, spec: instanceForHostname.spec, }), ).result; await updateInstanceOperation.wait(); ``` The hostname must be unique, and it cannot contain a full stop (`.`). For example, if you set `hostname` to `my-host`, the FQDN is the following: ```text my-host.vpcnetwork-e00***.compute.internal. ``` If you do not set `hostname`, the VM's ID is used instead of the hostname, according to the default FQDN. # How to generate SSH keys Source: https://docs.nebius.com/compute/virtual-machines/ssh-keys.md An *SSH key pair* is used to authenticate with a remote resource over SSH. It consists of: * A *public key* that you add to the resource or share with an administrator. * A *private key* that you keep on your local machine and use when connecting. You need an SSH key pair to: * Configure SSH access when [creating a virtual machine (VM)](https://docs.nebius.com/compute/virtual-machines/manage.md) and to [connect to your Compute VM](https://docs.nebius.com/compute/virtual-machines/connect.md) over SSH. * [Create a container VM](https://docs.nebius.com/compute/virtual-machines/containers.md). * [Give another user access to a VM](https://docs.nebius.com/compute/virtual-machines/connect.md#shared-access-to-the-vm). * [Connect to login and worker nodes in a Soperator cluster](https://docs.nebius.com/slurm-soperator/clusters/connect.md). * [Access a VM through a jump server](https://docs.nebius.com/compute/virtual-machines/wireguard.md) when the VM does not have a public IP address. ## Generating a key pair 1. In the terminal, create the `.ssh` directory if it does not exist: ```bash mkdir -p ~/.ssh chmod 700 ~/.ssh ``` 2. Go to the `~/.ssh` directory: ```bash cd ~/.ssh ``` 3. Generate an SSH key pair: ```bash ssh-keygen -t ed25519 ``` * To add a comment that identifies the key, add the optional `-C` parameter: ```bash ssh-keygen -t ed25519 -C "" ``` 4. When prompted, enter the file path where you want to save the key pair. * To save the key pair to the default location, press `Enter`. * If you already have a key in the default location, specify a custom file name, for example: ```bash /home//.ssh/nebius_ed25519 ``` 5. (Optional) When prompted, enter a passphrase for the private key. Press `Enter` to generate a key without a passphrase. However, using a passphrase protects the private key if someone gets access to your local machine. 6. Repeat the passphrase when prompted. The command creates two files: * The private key, for example `~/.ssh/id_ed25519`. * The public key, for example `~/.ssh/id_ed25519.pub`. ## Getting the public key You need the contents of the public key when a resource or configuration asks for an SSH public key. For example, you can add it to a VM to configure SSH access or send it to an administrator who manages access to the resource. To get the contents of the public key, run: ```bash cat ~/.ssh/id_ed25519.pub ``` If you saved the public key to a custom file when you generated the key, specify the name with the `.pub` extension: ```bash cat ~/.ssh/.pub ``` The output contains the contents of the public key, for example: ```text ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI*** user@example.com ``` ## Protecting the private key Follow these recommendations when using SSH keys: * Keep the private key only on your local machine and don't share it with others. * Share only the public key, which is stored in the file with the `.pub` extension. * Use a passphrase for the private key. * Use a separate key pair for each user. * Remove public keys that are no longer used from the resource. # How to connect to virtual machines in Nebius AI Cloud Source: https://docs.nebius.com/compute/virtual-machines/connect.md Safe connection to the VM over SSH uses a key pair: you place the public key on the VM and store the private key on your device. ## Prerequisites [Install and configure](https://docs.nebius.com/cli/install.md) the Nebius AI Cloud CLI. [Install and initialize the Nebius SDK for Go](https://docs.nebius.com/grpc-api/sdk/go.md). [Install and initialize the Nebius SDK for Python](https://docs.nebius.com/grpc-api/sdk/python.md). [Install and initialize the Nebius SDK for JavaScript](https://docs.nebius.com/grpc-api/sdk/javascript.md). ## Set up the VM To be able to connect to the VM, define specific information during the [VM creation](https://docs.nebius.com/compute/virtual-machines/manage.md). ### Generate a key pair Generate an [SSH key pair](https://docs.nebius.com/compute/virtual-machines/ssh-keys.md). You will need the [contents of the public key](https://docs.nebius.com/compute/virtual-machines/ssh-keys.md#getting-the-public-key) and the path to your private key in later steps. ### Configure the user data User configuration helps to quickly create VMs with identical user data: it stores your username and the public key for the access to the VM. Create a configuration in the [cloud-init](https://cloudinit.readthedocs.io/en/latest/reference/modules.html#users-and-groups) format: ```bash export USER_DATA=$(jq -Rrs '.' < Define `userData` as a string in the [cloud-init](https://cloudinit.readthedocs.io/en/latest/reference/modules.html#users-and-groups) format: ```go publicKeyBytes, err := os.ReadFile( os.ExpandEnv("$HOME/.ssh/id_ed25519.pub"), ) if err != nil { return err } publicKey := strings.TrimSpace(string(publicKeyBytes)) userData := "#cloud-config\nusers:\n" + " - name: user\n" + " sudo: ALL=(ALL) NOPASSWD:ALL\n" + " shell: /bin/bash\n" + " ssh_authorized_keys:\n" + " - " + publicKey ``` The configuration contains the following parameters: * `name`: Username for connecting to the VM. The example sets `user`; replace it with your username. Do not use the `root` or `admin` usernames. They are reserved for internal needs and are not allowed to connect to a VM by SSH. * `sudo`: Sudo policy. `ALL=(ALL) NOPASSWD:ALL` allows users unrestricted sudo access; `False` disables sudo access for users. * `shell`: Default shell. * `ssh_authorized_keys`: User's authorized keys. Allows configuring SSH access to the VM. To create the key pair, follow the instructions in [Generating SSH keys](https://docs.nebius.com/compute/virtual-machines/ssh-keys.md). You can specify several users and their public SSH keys. For more information, see [cloud-init configuration examples](https://cloudinit.readthedocs.io/en/latest/reference/examples.html). Pass `userData` to `InstanceSpec.CloudInitUserData` when you create the VM. Define `user_data` as a string in the [cloud-init](https://cloudinit.readthedocs.io/en/latest/reference/modules.html#users-and-groups) format: ```python public_key = ( Path.home() .joinpath(".ssh/id_ed25519.pub") .read_text() .strip() ) user_data = "\n".join( [ "#cloud-config", "users:", " - name: user", " sudo: ALL=(ALL) NOPASSWD:ALL", " shell: /bin/bash", " ssh_authorized_keys:", f" - {public_key}", ], ) ``` The configuration contains the following parameters: * `name`: Username for connecting to the VM. The example sets `user`; replace it with your username. Do not use the `root` or `admin` usernames. They are reserved for internal needs and are not allowed to connect to a VM by SSH. * `sudo`: Sudo policy. `ALL=(ALL) NOPASSWD:ALL` allows users unrestricted sudo access; `False` disables sudo access for users. * `shell`: Default shell. * `ssh_authorized_keys`: User's authorized keys. Allows configuring SSH access to the VM. To create the key pair, follow the instructions in [Generating SSH keys](https://docs.nebius.com/compute/virtual-machines/ssh-keys.md). You can specify several users and their public SSH keys. For more information, see [cloud-init configuration examples](https://cloudinit.readthedocs.io/en/latest/reference/examples.html). Pass `user_data` to `InstanceSpec.cloud_init_user_data` when you create the VM. Define `userData` as a string in the [cloud-init](https://cloudinit.readthedocs.io/en/latest/reference/modules.html#users-and-groups) format: ```ts const publicKey = readFileSync( `${process.env.HOME}/.ssh/id_ed25519.pub`, "utf8", ).trim(); const userData = [ "#cloud-config", "users:", " - name: user", " sudo: ALL=(ALL) NOPASSWD:ALL", " shell: /bin/bash", " ssh_authorized_keys:", ` - ${publicKey}`, ].join("\n"); ``` The configuration contains the following parameters: * `name`: Username for connecting to the VM. The example sets `user`; replace it with your username. Do not use the `root` or `admin` usernames. They are reserved for internal needs and are not allowed to connect to a VM by SSH. * `sudo`: Sudo policy. `ALL=(ALL) NOPASSWD:ALL` allows users unrestricted sudo access; `False` disables sudo access for users. * `shell`: Default shell. * `ssh_authorized_keys`: User's authorized keys. Allows configuring SSH access to the VM. To create the key pair, follow the instructions in [Generating SSH keys](https://docs.nebius.com/compute/virtual-machines/ssh-keys.md). You can specify several users and their public SSH keys. For more information, see [cloud-init configuration examples](https://cloudinit.readthedocs.io/en/latest/reference/examples.html). Pass `userData` to `InstanceSpec.cloudInitUserData` when you create the VM. ### Configure the VM When you [create the VM](https://docs.nebius.com/compute/virtual-machines/manage.md#create-a-vm), specify the user data, network settings and boot disk: In the `nebius compute instance create` command, set the following parameters: * `--cloud-init-user-data`: Pass the user data with your username and public key. * `--network-interfaces`: To enable public access to the VM, include `"public_ip_address": {}` in the network interface specification. Alternatively, to enable public access to the VM, set `"public_ip_address": {"allocation_id": ""}` with an [allocation](https://docs.nebius.com/vpc/overview.md#allocation) ID. This way the public IP address is preserved as an allocation object and you can reuse it for another VM after deleting this one. 1. Get the default subnet's ID: ```bash export SUBNET_ID=$(nebius vpc subnet list \ --format json \ | jq -r ".items[0].metadata.id") ``` 2. Create an [allocation](https://docs.nebius.com/vpc/overview.md#allocation) by using the default subnet's ID: ```bash export ALLOCATION_ID=$(nebius vpc allocation create \ --ipv4-public-subnet-id $SUBNET_ID \ --name allocation-name \ --format json \ | jq -r ".metadata.id") ``` If an allocation with a public address has not been assigned to any resource for 30 days, Nebius AI Cloud can delete this allocation and release its address. If you want to preserve the address, assign its allocation to a Nebius AI Cloud resource. Example: ```bash nebius compute instance create \ --name inference-vm \ --resources-platform \ --resources-preset \ --boot-disk-existing-disk-id \ --boot-disk-attach-mode READ_WRITE \ --cloud-init-user-data "$USER_DATA" \ --network-interfaces '[{"name": "eth0", "subnet_id": "", "ip_address": {}, "public_ip_address": {"allocation_id": ""}}]' ``` 1. Get the subnet ID: ```go subnets, err := sdk.Services().VPC().V1(). Subnet().List( ctx, &vpc.ListSubnetsRequest{}, ) if err != nil { return err } if len(subnets.GetItems()) == 0 { return errors.New("no subnets found") } subnetID := subnets.GetItems()[0].GetMetadata().GetId() ``` 2. Create a public allocation: ```go allocationOperation, err := sdk.Services().VPC().V1(). Allocation().Create( ctx, &vpc.CreateAllocationRequest{ Metadata: &common.ResourceMetadata{ Name: "allocation-name", }, Spec: &vpc.AllocationSpec{ IpSpec: &vpc.AllocationSpec_Ipv4Public{ Ipv4Public: &vpc.IPv4PublicAllocationSpec{ Pool: &vpc.IPv4PublicAllocationSpec_SubnetId{ SubnetId: subnetID, }, }, }, }, }, ) if err != nil { return err } if _, err = allocationOperation.Wait(ctx); err != nil { return err } allocationID := allocationOperation.ResourceID() ``` 3. Set the platform, preset, existing boot disk ID and cloud-init user data: ```go publicAllocation := &compute.PublicIPAddress_AllocationId{ AllocationId: allocationID, } instanceOperation, err := sdk.Services().Compute().V1(). Instance().Create( ctx, &compute.CreateInstanceRequest{ Metadata: &common.ResourceMetadata{ Name: "inference-vm", }, Spec: &compute.InstanceSpec{ Resources: &compute.ResourcesSpec{ Platform: "", Size: &compute.ResourcesSpec_Preset{ Preset: "", }, }, BootDisk: &compute.AttachedDiskSpec{ AttachMode: compute.AttachedDiskSpec_READ_WRITE, Type: &compute.AttachedDiskSpec_ExistingDisk{ ExistingDisk: &compute.ExistingDisk{ Id: "", }, }, }, CloudInitUserData: userData, NetworkInterfaces: []*compute.NetworkInterfaceSpec{ { Name: "eth0", SubnetId: subnetID, IpAddress: &compute.IPAddress{}, PublicIpAddress: &compute.PublicIPAddress{ Allocation: publicAllocation, }, }, }, }, }, ) if err != nil { return err } if _, err = instanceOperation.Wait(ctx); err != nil { return err } ``` 1. Get the subnet ID: ```python subnet_service = SubnetServiceClient(sdk) subnets = await subnet_service.list(ListSubnetsRequest()) if not subnets.items: raise ValueError("no subnets found") subnet_id = subnets.items[0].metadata.id ``` 2. Create a public allocation: ```python allocation_service = AllocationServiceClient(sdk) allocation_operation = await allocation_service.create( CreateAllocationRequest( metadata=ResourceMetadata(name="allocation-name"), spec=AllocationSpec( ipv4_public=IPv4PublicAllocationSpec( subnet_id=subnet_id, ), ), ), ) await allocation_operation.wait() allocation_id = allocation_operation.resource_id ``` 3. Set the platform, preset, existing boot disk ID and cloud-init user data: ```python instance_service = InstanceServiceClient(sdk) create_instance_operation = await instance_service.create( CreateInstanceRequest( metadata=ResourceMetadata(name="inference-vm"), spec=InstanceSpec( resources=ResourcesSpec( platform="", preset="", ), boot_disk=AttachedDiskSpec( attach_mode=AttachedDiskSpec.AttachMode.READ_WRITE, existing_disk=ExistingDisk(id=""), ), cloud_init_user_data=user_data, network_interfaces=[ NetworkInterfaceSpec( name="eth0", subnet_id=subnet_id, ip_address=IPAddress(), public_ip_address=PublicIPAddress( allocation_id=allocation_id, ), ), ], ), ), ) await create_instance_operation.wait() ``` 1. Get the subnet ID: ```ts const subnetService = new SubnetService(sdk); const subnets = await subnetService.list( ListSubnetsRequest.create({}), ); const subnetId = subnets.items[0]?.metadata?.id; if (!subnetId) { throw new Error("no subnets found"); } ``` 2. Create a public allocation: ```ts const allocationService = new AllocationService(sdk); const allocationOperation = await allocationService.create( CreateAllocationRequest.create({ metadata: ResourceMetadata.create({ name: "allocation-name", }), spec: AllocationSpec.create({ ipSpec: { $case: "ipv4Public", ipv4Public: IPv4PublicAllocationSpec.create({ pool: { $case: "subnetId", subnetId, }, }), }, }), }), ).result; await allocationOperation.wait(); const allocationId = allocationOperation.resourceId(); ``` 3. Set the platform, preset, existing boot disk ID and cloud-init user data: ```ts const connectInstanceService = new InstanceService(sdk); const connectInstanceOperation = await connectInstanceService.create( CreateInstanceRequest.create({ metadata: ResourceMetadata.create({ name: "inference-vm", }), spec: InstanceSpec.create({ resources: ResourcesSpec.create({ platform: "", size: { $case: "preset", preset: "", }, }), bootDisk: AttachedDiskSpec.create({ attachMode: AttachedDiskSpec_AttachMode.READ_WRITE, type: { $case: "existingDisk", existingDisk: ExistingDisk.create({ id: "", }), }, }), cloudInitUserData: userData, networkInterfaces: [ NetworkInterfaceSpec.create({ name: "eth0", subnetId, ipAddress: IPAddress.create({}), publicIpAddress: PublicIPAddress.create({ allocation: { $case: "allocationId", allocationId, }, }), }), ], }), }), ).result; await connectInstanceOperation.wait(); ``` For the full set of parameters and more examples, see [How to create a virtual machine in Nebius AI Cloud](https://docs.nebius.com/compute/virtual-machines/manage.md#examples). ## Connect to the VM by using SSH **Requirements to connect to a private IP address or FQDN** To connect to a VM from another VM by using a [private IP address](https://docs.nebius.com/compute/virtual-machines/network.md#private-ip-addresses) or an [FQDN](https://docs.nebius.com/compute/virtual-machines/fqdn.md), both VMs must be in the same network. 1. Get your VM's IP address: To connect to the VM from the internet (if you have enabled public access to it), get its public IP address: ```bash export PUBLIC_IP_ADDRESS=$(nebius compute instance get-by-name \ --name \ --format json \ | jq -r '.status.network_interfaces[0].public_ip_address.address | split("/")[0]') ``` ```go publicInstance, err := sdk.Services().Compute().V1(). Instance().GetByName( ctx, &common.GetByNameRequest{ Name: "", }, ) if err != nil { return err } publicAddress := publicInstance.GetStatus(). GetNetworkInterfaces()[0].GetPublicIpAddress().GetAddress() publicIPAddress := strings.Split(publicAddress, "/")[0] if publicIPAddress == "" { return fmt.Errorf("public IP address is missing") } ``` ```python public_ip_service = InstanceServiceClient(sdk) public_instance = await public_ip_service.get_by_name( GetByNameRequest(name=""), ) public_address = ( public_instance.status.network_interfaces[0] .public_ip_address.address ) public_ip_address = public_address.split("/")[0] ``` ```ts const publicIpInstanceService = new InstanceService(sdk); const publicIpInstance = await publicIpInstanceService.getByName( GetByNameRequest.create({ name: "", }), ); const publicAddress = publicIpInstance.status ?.networkInterfaces[0]?.publicIpAddress?.address; let publicIpAddress = publicAddress?.split("/")[0]; ``` To connect to the VM from another Compute VM, get the private IP address or FQDN of the VM that you connect to: * Private IP address: ```bash nebius compute instance get-by-name \ --name \ --format json \ | jq -r '.status.network_interfaces[0].ip_address.address | split("/")[0]' ``` * FQDN: ```bash nebius compute instance get-by-name \ --name \ --format json \ | jq -r '.status.network_interfaces[0].fqdn | split("/")[0]' ``` * Private IP address: ```go privateInstance, err := sdk.Services().Compute().V1(). Instance().GetByName( ctx, &common.GetByNameRequest{ Name: "", }, ) if err != nil { return err } privateAddress := privateInstance.GetStatus(). GetNetworkInterfaces()[0].GetIpAddress().GetAddress() fmt.Println(strings.Split(privateAddress, "/")[0]) ``` * FQDN: ```go fqdnInstance, err := sdk.Services().Compute().V1(). Instance().GetByName( ctx, &common.GetByNameRequest{ Name: "", }, ) if err != nil { return err } fqdn := fqdnInstance.GetStatus().GetNetworkInterfaces()[0].GetFqdn() fmt.Println(strings.Split(fqdn, "/")[0]) ``` * Private IP address: ```python private_ip_service = InstanceServiceClient(sdk) private_instance = await private_ip_service.get_by_name( GetByNameRequest(name=""), ) private_address = ( private_instance.status.network_interfaces[0] .ip_address.address ) print(private_address.split("/")[0]) ``` * FQDN: ```python fqdn_service = InstanceServiceClient(sdk) fqdn_instance = await fqdn_service.get_by_name( GetByNameRequest(name=""), ) fqdn = fqdn_instance.status.network_interfaces[0].fqdn print(fqdn.split("/")[0]) ``` * Private IP address: ```ts const privateIpInstanceService = new InstanceService(sdk); const privateIpInstance = await privateIpInstanceService.getByName( GetByNameRequest.create({ name: "", }), ); const privateAddress = privateIpInstance.status ?.networkInterfaces[0]?.ipAddress?.address; console.log(privateAddress?.split("/")[0]); ``` * FQDN: ```ts const fqdnInstanceService = new InstanceService(sdk); const fqdnInstance = await fqdnInstanceService.getByName( GetByNameRequest.create({ name: "", }), ); const fqdn = fqdnInstance.status?.networkInterfaces[0]?.fqdn; console.log(fqdn?.split("/")[0]); ``` 2. Connect to the VM: ```bash ssh @ ``` If your private key is stored in a custom location, specify the path to it with the `-i` parameter: ```bash ssh -i ~/.ssh/ @ ``` Use the received private address or FQDN: ```bash ssh @ ``` If your private key is stored in a custom location, specify the path to it with the `-i` parameter: ```bash ssh -i ~/.ssh/ @ ``` ## Shared access to the VM To let the other users connect to your VM: 1. Ask them to [generate an SSH key pair](https://docs.nebius.com/compute/virtual-machines/ssh-keys.md#generating-a-key-pair) and share the [contents of their public key](https://docs.nebius.com/compute/virtual-machines/ssh-keys.md#getting-the-public-key) with you. 2. Connect to the VM under the name used when creating the VM: ```bash ssh @ ``` 3. Create a new user for VM access, named `newuser` in this example: ```bash sudo useradd -m -d /home/newuser -s /bin/bash newuser ``` 4. Switch to the new user: ```bash sudo su - newuser ``` 5. Create the `ssh` directory: ```bash mkdir .ssh ``` 6. In the directory, create the `authorized_keys` file: ```bash cd .ssh touch authorized_keys ``` 7. Add the new user's public key to the created file: ```bash echo "" > /home/newuser/.ssh/authorized_keys ``` 8. Change the directory's access permissions: ```bash chmod 700 ~/.ssh chmod 600 ~/.ssh/authorized_keys ``` 9. Exit the new user's shell: ```bash exit ``` 10. Restart the VM: ```bash sudo reboot ``` 11. Ask the other user to check the connection: ```bash ssh newuser@ ``` ## Example Example of getting the public IP address of the VM named `training-instance` and connecting to it from the internet: ```bash export PUBLIC_IP_ADDRESS=$(nebius compute instance get-by-name \ --name training-instance \ --format json \ | jq -r '.status.network_interfaces[0].public_ip_address.address | split("/")[0]') ssh $USER@$PUBLIC_IP_ADDRESS ``` ```go trainingInstance, err := sdk.Services().Compute().V1(). Instance().GetByName( ctx, &common.GetByNameRequest{ Name: "training-instance", }, ) if err != nil { return err } trainingAddress := trainingInstance.GetStatus(). GetNetworkInterfaces()[0].GetPublicIpAddress().GetAddress() publicIPAddress = strings.Split(trainingAddress, "/")[0] fmt.Printf("ssh user@%s\n", publicIPAddress) ``` ```python training_ip_service = InstanceServiceClient(sdk) training_instance = await training_ip_service.get_by_name( GetByNameRequest(name="training-instance"), ) training_address = ( training_instance.status.network_interfaces[0] .public_ip_address.address ) public_ip_address = training_address.split("/")[0] print(f"ssh user@{public_ip_address}") ``` ```ts const trainingInstanceService = new InstanceService(sdk); const trainingInstance = await trainingInstanceService.getByName( GetByNameRequest.create({ name: "training-instance", }), ); const trainingAddress = trainingInstance.status ?.networkInterfaces[0]?.publicIpAddress?.address; publicIpAddress = trainingAddress?.split("/")[0]; console.log(`ssh user@${publicIpAddress}`); ``` # Creating a jump server with WireGuard installed on it Source: https://docs.nebius.com/compute/virtual-machines/wireguard.md You can create a jump server to build a reliable tunnel between two zones: * Secure zone that consists of virtual machine (VMs) created in Nebius AI Cloud * Demilitarized zone (DMZ) that consists of machines outside Nebius AI Cloud All connections from the DMZ to the secure zone go through the jump server. This solution provides several benefits: * You can use one public IP address to access all VMs. * You can keep the number of public addresses within a [quota](https://docs.nebius.com/compute/resources/quotas-limits.md#network). * You can limit access to the secure zone and allow only authorized machines to connect to the secure zone. To create a jump server, deploy a VM with [WireGuard](https://www.wireguard.com) installed and configure a VPN. The traffic between the zones is routed in an encrypted form via the jump server. To create a VM with WireGuard deployed, Nebius AI Cloud offers a Terraform-based solution. You can apply manifests that contain configuration of a VM with a WireGuard image. ## Costs The tutorial includes the following chargeable resources: * [Compute virtual machines](https://docs.nebius.com/compute/resources/pricing.md#virtual-machines-gpus-vcpus-ram) * [Compute disks](https://docs.nebius.com/compute/resources/pricing.md#disks) ## Prerequisites 1. [Install Terraform](https://developer.hashicorp.com/terraform/install). 2. [Install and configure](https://docs.nebius.com/cli/install.md) the Nebius AI Cloud CLI. The Terraform-based solution uses the CLI to get credentials. For enhanced security, [use a service account](https://docs.nebius.com/cli/configure.md#how-to-set-up-the-cli-for-a-service-account) to configure the CLI. Make sure that this account is in a [group](https://docs.nebius.com/iam/authorization/groups/index.md) that has at least the `editor` role within your tenant; for example, the default `editors` group. You can check this in the [Administration → IAM](https://console.nebius.com/iam) section of the web console. 3. Install `jq`: ```bash Ubuntu sudo apt-get install jq ``` ```bash macOS brew install jq ``` 4. Clone the [nebius-solution-library](https://github.com/nebius/nebius-solution-library/tree/main) repository from where the WireGuard solution is going to be deployed: ```bash git clone git@github.com:nebius/nebius-solution-library.git ``` 5. Generate an [SSH key pair](https://docs.nebius.com/compute/virtual-machines/ssh-keys.md). ## Steps ### Deploy infrastructure 1. In your terminal, go to the `wireguard` directory in the cloned repository: ```bash cd nebius-solution-library/wireguard ``` 2. In the `environment.sh` file in this directory, uncomment the following variables and specify values for them: * `NEBIUS_TENANT_ID`: [Tenant ID](https://docs.nebius.com/iam/get-tenants.md). * `NEBIUS_PROJECT_ID`: [Project ID](https://docs.nebius.com/iam/manage-projects.md#terraform-3). * `NEBIUS_REGION`: The [region](https://docs.nebius.com/overview/regions.md) where your project is located. You can find the region in the web console, in the list of projects. 3. Run the script that creates an access token for Terraform, saves the token to environment variables and configures Terraform state to be saved in Object Storage: ```bash source ./environment.sh ``` 4. Initialize Terraform in the `wireguard` directory: ```bash terraform init ``` 5. In the `terraform.tfvars` file in this directory, uncomment the following variables and specify values for them: * `ssh_user_name`: The user required for an SSH connection to the VM, for example `user1`. * `ssh_public_key`: The public SSH key that you [created earlier](https://docs.nebius.com/compute/virtual-machines/wireguard.md#prerequisites). Specify either the key body or the path to this key. * `public_ip_allocation_id`: An ID of an [allocation](https://docs.nebius.com/vpc/overview.md#allocation) with a public IP address. The WireGuard UI will be available at this address. To preserve the address even in case of the VM deletion, create the allocation: ```bash nebius vpc allocation create \ --ipv4-public-subnet-id \ --name wireguard_allocation \ --parent-id \ --format json \ | jq -r ".metadata.id" ``` The command returns the allocation ID. Specify it in the `public_ip_allocation_id` variable. 6. Preview the configuration that you are going to deploy: ```bash terraform plan ``` 7. Apply the changes: ```bash terraform apply ``` When the command is finished, it returns the VM public address: ```text Outputs: wg_instance_pib = "" ``` Copy the address: It is required to connect to the deployed VM. ### Access WireGuard 1. Connect to the VM: ```bash ssh -i @ ``` The command contains: * Path to the private SSH key that you [created earlier](https://docs.nebius.com/compute/virtual-machines/wireguard.md#prerequisites) * Username specified in the `terraform.tfvars` file * Public IP address of the deployed VM 2. Get the WireGuard UI password: ```bash sudo cat /var/lib/wireguard-ui/initial_password ``` 3. In the browser, open the WireGuard UI at `http://:5000`. 4. In the window that opens, sign in with the `admin` username and the password retrieved from the VM. The working space of the WireGuard UI opens. ### Configure WireGuard Set up a VPN and grant access to the VMs in the secure zone. To do this, add the DMZ machines as WireGuard clients: 1. Click  **New client**. 2. In the window that opens, specify details of the machines that require access. In the **Allowed IPs** field, enter CIDRs of these machines. 3. Click **Submit**. 4. After the window is closed, click **Apply config**. Click this button every time after you create, change or delete WireGuard clients. After that, the DMZ machines are able to connect to the VMs in the secure zone. You do not need to configure the same access for the jump server because it is located in the same subnet as the VMs in the secure zone. ## How to delete the created resources The created Compute virtual machine and its boot disk are chargeable. If you do not need them, delete these resources, so Nebius AI Cloud does not charge for it. Use the following command to delete all the created infrastructure at once: ```bash terraform destroy -target=nebius_compute_v1_instance.wireguard_instance ``` # InfiniBand™ networking for Compute virtual machines with GPUs Source: https://docs.nebius.com/compute/clusters/gpu/index.md You can group your virtual machines with GPUs into a *GPU cluster*. The cluster accelerates high-performance computing (HPC) tasks such as training and inference. These tasks require a lot of processing power that a single VM cannot provide. The GPU clusters are built with InfiniBand™ secure high-speed networking. Each GPU in a VM is connected through a network interface card (NIC) that provides 400 Gbps. As a compute VM for GPU clusters consists of 8 GPUs, the total bandwidth for a node is 3.2 Tbps. Nebius AI Cloud uses GPUDirect RDMA, an NVIDIA® technology of remote direct memory access (RDMA) that allows data to flow directly between each GPU and its NIC, avoiding CPU, thus boosting the data exchange speed. ## InfiniBand™ fabrics Each GPU cluster is created in one of the physical *InfiniBand™ fabrics*. This is where GPUs interconnected over InfiniBand™ are located. Each fabric has limited GPU capacity. When creating a GPU cluster, select an InfiniBand™ fabric for it. Take into account the type of GPUs you are going to use. For example, if you select `fabric-7`, you can only add NVIDIA® H200 NVLink with Intel Sapphire Rapids GPUs to this cluster. Available fabrics and corresponding regions ([private regions](https://docs.nebius.com/overview/regions.md) are marked with \*): | Fabric | GPU platform | [Region](https://docs.nebius.com/overview/regions.md) | | -------------------------- | --------------------------------------------------------------------------- | --------------------------- | | `fabric-2` | NVIDIA® H100 NVLink with Intel Sapphire Rapids (gpu-h100-sxm) | eu-north1 | | `fabric-3` | NVIDIA® H100 NVLink with Intel Sapphire Rapids (gpu-h100-sxm) | eu-north1 | | `fabric-4` | NVIDIA® H100 NVLink with Intel Sapphire Rapids (gpu-h100-sxm) | eu-north1 | | `fabric-5` | NVIDIA® H200 NVLink with Intel Sapphire Rapids (gpu-h200-sxm) | eu-west1 | | `fabric-6` | NVIDIA® H100 NVLink with Intel Sapphire Rapids (gpu-h100-sxm) | eu-north1 | | `fabric-7` | NVIDIA® H200 NVLink with Intel Sapphire Rapids (gpu-h200-sxm) | eu-north1 | | eu-north2-a | NVIDIA® H200 NVLink with Intel Sapphire Rapids (gpu-h200-sxm) | eu-north2\* | | eu-west2-a | NVIDIA® B300 NVLink with Intel Granite Rapids (gpu-b300-sxm) | eu-west2\* | | me-west1-a | NVIDIA® B200 NVLink with Intel Emerald Rapids (gpu-b200-sxm-a) | me-west1 | | uk-south1-a | NVIDIA® B300 NVLink with Intel Granite Rapids (gpu-b300-sxm) | uk-south1 | | us-central1-a | NVIDIA® H200 NVLink with Intel Sapphire Rapids (gpu-h200-sxm) | us-central1 | | us-central1-b | NVIDIA® B200 NVLink with Intel Emerald Rapids (gpu-b200-sxm) | us-central1 | In most cases, you do not need to change the preselected fabric. We recommend that you create a GPU cluster in another fabric only if it is better suited for a different platform or if you experience capacity issues with an existing GPU cluster. ## Isolation and security of InfiniBand™ traffic Nebius AI Cloud isolates InfiniBand™ traffic between GPU clusters by using InfiniBand™ *partition keys* (P-Keys). Each GPU cluster is assigned a unique P-Key to create isolation inside shared [physical InfiniBand™ fabrics](https://docs.nebius.com/compute/clusters/gpu/topology). This way, nodes in different GPU clusters cannot communicate over InfiniBand™ even if they use the same fabric infrastructure. This creates isolation between [tenants](https://docs.nebius.com/iam/overview.md#tenants) without requiring a dedicated physical fabric for each cluster. ## Prerequisites If you use the web console, you don't need to complete any prerequisites. [Install and configure](https://docs.nebius.com/cli/install.md) the Nebius AI Cloud CLI. [Install and initialize the Nebius SDK for Go](https://docs.nebius.com/grpc-api/sdk/go.md). [Install and initialize the Nebius SDK for Python](https://docs.nebius.com/grpc-api/sdk/python.md). [Install and initialize the Nebius SDK for JavaScript](https://docs.nebius.com/grpc-api/sdk/javascript.md). ## How to enable InfiniBand™ for VMs with GPUs 1. Create a GPU cluster: 1. In the sidebar, go to  **Compute** → **GPU clusters**. 2. Click  **Create GPU cluster**. 3. On the page that opens, specify the cluster name. It should contain from 3 to 63 characters: lowercase letters, numbers and hyphens. 4. Select the InfiniBand™ fabric. 5. Click **Create GPU cluster**. 2. Add VMs to the cluster. You can assign a GPU cluster only when creating a VM: All virtual machines added to the GPU cluster, including Managed Service for Kubernetes® nodes, must be in the same [project](https://docs.nebius.com/iam/overview.md#projects). 1. In the sidebar, go to  **Compute** → **Virtual machines**. 2. Click **Create resource** → **Virtual machine**. 3. On the **Compute** step of the VM creation wizard, select a platform and preset compatible with GPU clusters. For more information, see [Types of virtual machines and GPUs in Nebius AI Cloud](https://docs.nebius.com/compute/virtual-machines/types.md). 4. In the **Settings** section, select an existing GPU cluster in the **GPU cluster** field, or create a new one. 5. On the **Storage** step, select the boot disk for NVIDIA® GPUs. For details, see [Boot disk images for Compute virtual machines](https://docs.nebius.com/compute/storage/boot-disk-images.md). You can also create a GPU cluster while [creating the first VM in it](https://docs.nebius.com/compute/virtual-machines/manage.md): 1. On the **Compute** step of the VM creation wizard: 1. Select a platform and a preset compatible with GPU clusters. For more information, see [Types of virtual machines and GPUs in Nebius AI Cloud](https://docs.nebius.com/compute/virtual-machines/types.md). 2. In the **Settings** section, create or select a GPU cluster in the **GPU cluster** field. 2. On the **Storage** step, select the boot disk for NVIDIA® GPUs. For details, see [Boot disk images for Compute virtual machines](https://docs.nebius.com/compute/storage/boot-disk-images.md). 1. Check that your project ID is saved in the Nebius AI Cloud CLI profile configuration: ```bash cat ~/.nebius/config.yaml ``` 2. If you have not set your project ID as `parent-id`, or you want to create resources in a different project, [get the project ID](https://docs.nebius.com/iam/manage-projects.md#how-to-get-a-project-id) and update your [CLI profile](https://docs.nebius.com/cli/configure.md): ```bash nebius profile update --parent-id ``` 3. Depending on your project's [region](https://docs.nebius.com/overview/regions.md), select an [InfiniBand™ fabric](https://docs.nebius.com/compute/clusters/gpu/index.md#infiniband-fabrics) for VM interconnection and save it to an environment variable: ```bash export INFINIBAND_FABRIC= ``` 4. Create a GPU cluster and save its ID: ```bash export GPU_CLUSTER_ID=$(nebius compute gpu-cluster create \ --name \ --infiniband-fabric $INFINIBAND_FABRIC \ --format json \ | jq -r ".metadata.id") ``` Where: * `Name`: A cluster name that you can use to quickly find the cluster. 5. Create a boot disk optimized for VMs with NVIDIA® GPUs: ```bash export BOOT_DISK_ID=$(nebius compute disk create \ --name \ --size-gibibytes 200 \ --type network_ssd \ --source-image-family-image-family ubuntu24.04-cuda13.0 \ --block-size-bytes 4096 \ --format json \ | jq -r ".metadata.id") ``` For compatible boot disk images (`--source-image-family-image-family`), see [Boot disk images](https://docs.nebius.com/compute/storage/boot-disk-images.md). 6. [Create a virtual machine](https://docs.nebius.com/compute/virtual-machines/manage.md#create-a-vm) with GPUs and specify the GPU cluster ID in its parameters. All virtual machines added to the GPU cluster, including Managed Service for Kubernetes® nodes, must be in the same project. For example: ```bash nebius compute instance create \ --resources-platform gpu-h100-sxm \ --resources-preset 8gpu-128vcpu-1600gb \ --gpu-cluster-id $GPU_CLUSTER_ID \ --boot-disk-existing-disk-id $BOOT_DISK_ID \ ... ``` Specify a VM platform with GPUs in `--resources-platform`, and a preset compatible with GPU clusters in `--resources-preset`. For more information, see [Types of virtual machines and GPUs in Nebius AI Cloud](https://docs.nebius.com/compute/virtual-machines/types.md). 1. Depending on your project's [region](https://docs.nebius.com/overview/regions.md), select an [InfiniBand™ fabric](https://docs.nebius.com/compute/clusters/gpu/index.md#infiniband-fabrics) for VM interconnection and set it in the code: ```go infinibandFabric := "" ``` 2. Create a GPU cluster and save its ID: ```go gpuClusterOperation, err := sdk.Services().Compute().V1(). GpuCluster().Create( ctx, &compute.CreateGpuClusterRequest{ Metadata: &common.ResourceMetadata{ Name: "", }, Spec: &compute.GpuClusterSpec{ InfinibandFabric: infinibandFabric, }, }, ) if err != nil { return err } if _, err = gpuClusterOperation.Wait(ctx); err != nil { return err } gpuClusterID := gpuClusterOperation.ResourceID() ``` Where: * `Metadata.Name`: A cluster name that you can use to quickly find the cluster. 3. Create a boot disk optimized for VMs with NVIDIA® GPUs: ```go diskOperation, err := sdk.Services().Compute().V1(). Disk().Create( ctx, &compute.CreateDiskRequest{ Metadata: &common.ResourceMetadata{ Name: "", }, Spec: &compute.DiskSpec{ Size: &compute.DiskSpec_SizeGibibytes{ SizeGibibytes: 200, }, BlockSizeBytes: 4096, Type: compute.DiskSpec_NETWORK_SSD, Source: &compute.DiskSpec_SourceImageFamily{ SourceImageFamily: &compute.SourceImageFamily{ ImageFamily: "ubuntu24.04-cuda13.0", }, }, }, }, ) if err != nil { return err } if _, err = diskOperation.Wait(ctx); err != nil { return err } bootDiskID := diskOperation.ResourceID() ``` For compatible boot disk images, see [Boot disk images](https://docs.nebius.com/compute/storage/boot-disk-images.md). 4. [Create a virtual machine](https://docs.nebius.com/compute/virtual-machines/manage.md#create-a-vm) with GPUs and specify the GPU cluster ID in its parameters. All virtual machines added to the GPU cluster, including Managed Service for Kubernetes® nodes, must be in the same project. ```go attachMode := compute.AttachedDiskSpec_READ_WRITE instanceOperation, err := sdk.Services().Compute().V1(). Instance().Create( ctx, &compute.CreateInstanceRequest{ Metadata: &common.ResourceMetadata{ Name: "vm", }, Spec: &compute.InstanceSpec{ Stopped: true, Resources: &compute.ResourcesSpec{ Platform: "gpu-h100-sxm", Size: &compute.ResourcesSpec_Preset{ Preset: "8gpu-128vcpu-1600gb", }, }, GpuCluster: &compute.InstanceGpuClusterSpec{ Id: gpuClusterID, }, BootDisk: &compute.AttachedDiskSpec{ AttachMode: attachMode, Type: &compute.AttachedDiskSpec_ExistingDisk{ ExistingDisk: &compute.ExistingDisk{ Id: bootDiskID, }, }, }, NetworkInterfaces: []*compute.NetworkInterfaceSpec{ { Name: "ni", SubnetId: subnetID, IpAddress: &compute.IPAddress{}, PublicIpAddress: &compute.PublicIPAddress{}, }, }, }, }, ) if err != nil { return err } if _, err = instanceOperation.Wait(ctx); err != nil { return err } ``` Specify a VM platform with GPUs and a preset compatible with GPU clusters. For more information, see [Types of virtual machines and GPUs in Nebius AI Cloud](https://docs.nebius.com/compute/virtual-machines/types.md). 1. Depending on your project's [region](https://docs.nebius.com/overview/regions.md), select an [InfiniBand™ fabric](https://docs.nebius.com/compute/clusters/gpu/index.md#infiniband-fabrics) for VM interconnection and set it in the code: ```python infiniband_fabric = "" ``` 2. Create a GPU cluster and save its ID: ```python gpu_cluster_service = GpuClusterServiceClient(sdk) create_cluster_operation = await gpu_cluster_service.create( CreateGpuClusterRequest( metadata=ResourceMetadata( name="", ), spec=GpuClusterSpec( infiniband_fabric=infiniband_fabric, ), ), ) await create_cluster_operation.wait() gpu_cluster_id = create_cluster_operation.resource_id ``` Where: * `metadata.name`: A cluster name that you can use to quickly find the cluster. 3. Create a boot disk optimized for VMs with NVIDIA® GPUs: ```python disk_service = DiskServiceClient(sdk) create_disk_operation = await disk_service.create( CreateDiskRequest( metadata=ResourceMetadata( name="", ), spec=DiskSpec( block_size_bytes=4096, type=DiskSpec.DiskType.NETWORK_SSD, source_image_family=SourceImageFamily( image_family="ubuntu24.04-cuda13.0", ), size_gibibytes=200, ), ), ) await create_disk_operation.wait() boot_disk_id = create_disk_operation.resource_id ``` For compatible boot disk images, see [Boot disk images](https://docs.nebius.com/compute/storage/boot-disk-images.md). 4. [Create a virtual machine](https://docs.nebius.com/compute/virtual-machines/manage.md#create-a-vm) with GPUs and specify the GPU cluster ID in its parameters. All virtual machines added to the GPU cluster, including Managed Service for Kubernetes® nodes, must be in the same project. ```python instance_service = InstanceServiceClient(sdk) create_instance_operation = await instance_service.create( CreateInstanceRequest( metadata=ResourceMetadata( name="vm", ), spec=InstanceSpec( stopped=True, resources=ResourcesSpec( platform="gpu-h100-sxm", preset="8gpu-128vcpu-1600gb", ), gpu_cluster=InstanceGpuClusterSpec( id=gpu_cluster_id, ), boot_disk=AttachedDiskSpec( attach_mode=( AttachedDiskSpec.AttachMode.READ_WRITE ), existing_disk=ExistingDisk(id=boot_disk_id), ), network_interfaces=[ NetworkInterfaceSpec( name="ni", subnet_id=subnet_id, ip_address=IPAddress(), public_ip_address=PublicIPAddress(), ), ], ), ), ) await create_instance_operation.wait() ``` Specify a VM platform with GPUs and a preset compatible with GPU clusters. For more information, see [Types of virtual machines and GPUs in Nebius AI Cloud](https://docs.nebius.com/compute/virtual-machines/types.md). 1. Depending on your project's [region](https://docs.nebius.com/overview/regions.md), select an [InfiniBand™ fabric](https://docs.nebius.com/compute/clusters/gpu/index.md#infiniband-fabrics) for VM interconnection and set it in the code: ```ts const infinibandFabric = ""; ``` 2. Create a GPU cluster and save its ID: ```ts const gpuClusterService = new GpuClusterService(sdk); const createGpuClusterOperation = await gpuClusterService.create( CreateGpuClusterRequest.create({ metadata: ResourceMetadata.create({ name: "", }), spec: GpuClusterSpec.create({ infinibandFabric, }), }), ).result; await createGpuClusterOperation.wait(); const gpuClusterId = createGpuClusterOperation.resourceId(); ``` Where: * `metadata.name`: A cluster name that you can use to quickly find the cluster. 3. Create a boot disk optimized for VMs with NVIDIA® GPUs: ```ts const diskService = new DiskService(sdk); const createDiskOperation = await diskService.create( CreateDiskRequest.create({ metadata: ResourceMetadata.create({ name: "", }), spec: DiskSpec.create({ blockSizeBytes: 4096, type: DiskSpec_DiskType.NETWORK_SSD, source: { $case: "sourceImageFamily", sourceImageFamily: SourceImageFamily.create({ imageFamily: "ubuntu24.04-cuda13.0", }), }, size: { $case: "sizeGibibytes", sizeGibibytes: 200, }, }), }), ).result; await createDiskOperation.wait(); const bootDiskId = createDiskOperation.resourceId(); ``` For compatible boot disk images, see [Boot disk images](https://docs.nebius.com/compute/storage/boot-disk-images.md). 4. [Create a virtual machine](https://docs.nebius.com/compute/virtual-machines/manage.md#create-a-vm) with GPUs and specify the GPU cluster ID in its parameters. All virtual machines added to the GPU cluster, including Managed Service for Kubernetes® nodes, must be in the same project. ```ts const instanceService = new InstanceService(sdk); const createInstanceOperation = await instanceService.create( CreateInstanceRequest.create({ metadata: ResourceMetadata.create({ name: "vm", }), spec: InstanceSpec.create({ stopped: true, resources: ResourcesSpec.create({ platform: "gpu-h100-sxm", size: { $case: "preset", preset: "8gpu-128vcpu-1600gb", }, }), gpuCluster: InstanceGpuClusterSpec.create({ id: gpuClusterId, }), bootDisk: AttachedDiskSpec.create({ attachMode: AttachedDiskSpec_AttachMode.READ_WRITE, type: { $case: "existingDisk", existingDisk: ExistingDisk.create({ id: bootDiskId, }), }, }), networkInterfaces: [ NetworkInterfaceSpec.create({ name: "ni", subnetId, ipAddress: IPAddress.create({}), publicIpAddress: PublicIPAddress.create({}), }), ], }), }), ).result; await createInstanceOperation.wait(); ``` Specify a VM platform with GPUs and a preset compatible with GPU clusters. For more information, see [Types of virtual machines and GPUs in Nebius AI Cloud](https://docs.nebius.com/compute/virtual-machines/types.md). ## How to test the connection with the NCCL tests To test InfiniBand™ performance in a Compute cluster, you can run the NVIDIA® Collective Communications Library (NCCL) test in it. For instructions, see our tutorial on running distributed jobs with [MPIrun](https://docs.nebius.com/3p-integrations/mpirun.md): it uses the NCCL test as an example. ## How to delete a GPU cluster Before deleting a GPU cluster, make sure all virtual machines in the cluster are deleted or moved to another cluster. 1. In the sidebar, go to **Compute** → **GPU clusters**. 2. In the row of the GPU cluster you want to delete, click → **Delete**. 3. In the window that opens, confirm the deletion. 1. Get the ID of the GPU cluster you want to delete: ```bash nebius compute gpu-cluster list ``` 2. Delete the GPU cluster: ```bash nebius compute gpu-cluster delete ``` 1. Get the ID of the GPU cluster you want to delete: ```go gpuClusters, err := sdk.Services().Compute().V1(). GpuCluster().List( ctx, &compute.ListGpuClustersRequest{ ParentId: nbProject, }, ) if err != nil { return err } fmt.Println(gpuClusters) ``` 2. Delete the GPU cluster: ```go delClusterOp, err := sdk.Services().Compute().V1(). GpuCluster().Delete( ctx, &compute.DeleteGpuClusterRequest{ Id: "", }, ) if err != nil { return err } if _, err = delClusterOp.Wait(ctx); err != nil { return err } ``` 1. Get the ID of the GPU cluster you want to delete: ```python gpu_cluster_service = GpuClusterServiceClient(sdk) gpu_clusters = await gpu_cluster_service.list( ListGpuClustersRequest(parent_id=nb_project), ) print(gpu_clusters) ``` 2. Delete the GPU cluster: ```python gpu_cluster_service = GpuClusterServiceClient(sdk) delete_cluster_operation = await gpu_cluster_service.delete( DeleteGpuClusterRequest(id=""), ) await delete_cluster_operation.wait() ``` 1. Get the ID of the GPU cluster you want to delete: ```ts const listGpuClusterService = new GpuClusterService(sdk); const gpuClusters = await listGpuClusterService.list( ListGpuClustersRequest.create({ parentId: nbProject, }), ); console.log(gpuClusters); ``` 2. Delete the GPU cluster: ```ts const deleteGpuClusterService = new GpuClusterService(sdk); const deleteClusterOperation = await deleteGpuClusterService.delete( DeleteGpuClusterRequest.create({ id: "", }), ).result; await deleteClusterOperation.wait(); ``` ## See also * [How to test a GPU cluster physical state in Compute](https://docs.nebius.com/compute/clusters/gpu/test.md) * [InfiniBand™ networking for Compute virtual machines with GPUs](https://docs.nebius.com/kubernetes/gpu/clusters.md) * [How to create a virtual machine in Nebius AI Cloud](https://docs.nebius.com/compute/virtual-machines/manage.md) * [Running the all-reduce NCCL performance test in Soperator clusters](https://docs.nebius.com/slurm-soperator/jobs/examples/nccl-all-reduce.md) *** *InfiniBand and InfiniBand Trade Association are registered trademarks of the InfiniBand Trade Association.* # How to test a GPU cluster physical state in Compute Source: https://docs.nebius.com/compute/clusters/gpu/test.md In this article, you will learn how to test the physical state of the InfiniBand™ connection. The guides below will help you to check that InfiniBand connections are established between GPUs in a GPU cluster. ## Testing the port state 1. [Connect to the VM using SSH](https://docs.nebius.com/compute/virtual-machines/connect.md). 2. In the VM's shell, run `ibstatus` command that displays operational information about InfiniBand network devices. Result: ```bash Infiniband device 'mlx5_0' port 1 status: default gid: fe80:0000:0000:0000:****:****:****:03c5 base lid: 0x*** sm lid: 0x* state: 4: ACTIVE phys state: 5: LinkUp rate: 400 Gb/sec (4X NDR) link_layer: InfiniBand Infiniband device 'mlx5_1' port 1 status: default gid: fe80:0000:0000:0000:****:****:****:03c6 base lid: 0x*** sm lid: 0x* state: 4: ACTIVE phys state: 5: LinkUp rate: 400 Gb/sec (4X NDR) link_layer: InfiniBand ... ``` 3. For each device in the result, check the physical state (`phys state`): it should be `LinkUp`. ## Testing network performance You can also emulate the network activity by sending some data from GPUs on one VM to GPUs on another: 1. Install the [perftest](https://github.com/linux-rdma/perftest) package on each one of the test VMs: ```bash sudo apt install perftest ``` 2. [Connect to the first VM using SSH](https://docs.nebius.com/compute/virtual-machines/connect.md). 3. Run `ib_send_bw --report_gbits`. 4. Copy the first VM's [private IP address](https://docs.nebius.com/compute/virtual-machines/network.md). 5. [Connect to the second VM using SSH](https://docs.nebius.com/compute/virtual-machines/connect.md). 6. Run `ib_send_bw --report_gbits`. In the commands output, you should see non-zero values for the bytes sent, average bandwith speed, and average message rate. The bandwidth peak speed might not reach the theoretical maximum 400 Gbps. Example: ```text +--------------------------------------------------------------------------------+ | #bytes #iterations #BW peak[Gb/sec] #BW average[Gb/sec] #MsgRate[Mpps] | +--------------------------------------------------------------------------------+ | 65536 1000 360.39 359.91 0.686466 | +--------------------------------------------------------------------------------+ ``` ## See also * [InfiniBand™ networking for Compute virtual machines with GPUs](https://docs.nebius.com/compute/clusters/gpu/index.md) * [How to create a virtual machine in Nebius AI Cloud](https://docs.nebius.com/compute/virtual-machines/manage.md) *** *InfiniBand and InfiniBand Trade Association are registered trademarks of the InfiniBand Trade Association.* # InfiniBand™ topology of a GPU cluster Source: https://docs.nebius.com/compute/clusters/gpu/topology/index.md ## Why InfiniBand topology is important Workload managers like [Slurm](https://slurm.schedmd.com) and [Volcano](https://volcano.sh/en/docs/) allow you to specify the network topology of your virtual machines within a GPU cluster for *topology-aware job scheduling*. Topology files describe how the VMs are located relative to each other. When you provide a topology file to a workload manager, it schedules distributed jobs on the worker nodes that are topologically closest to each other. This reduces network latency in such jobs and leads to better performance in both real workloads and synthetic tests. > For example, the [AllReduce](https://github.com/NVIDIA/nccl-tests/blob/master/doc/PERFORMANCE.md#allreduce) tests from the [NCCL Tests suite](https://github.com/NVIDIA/nccl-tests) that we ran in Nebius AI Cloud as topology-aware jobs have shown performance gains of up to 20%, depending on cluster size, compared to the same tests without the topology provided. ## Architecture of InfiniBand topology Every virtual machine with GPUs is connected to a set of three nodes related to a particular [InfiniBand fabric](https://docs.nebius.com/compute/clusters/gpu/index.md#infiniband-fabrics). Every node is located on a separate network layer. The hierarchy of an InfiniBand network includes the following layers with different types of switches: 1. InfiniBand fabric layer. Contains a root switch. 2. Point of delivery (POD). Represents a set of racks with servers. Core switches interconnect PODs. 3. Scalable unit (SU). Consists of a set of servers. Leaf switches interconnect scalable units. image ## Cost of network communication The cost of network communication increases as you go to a higher layer. For example, if you need to transfer data from one POD to another, the data goes through a root switch. This leads to a higher cost of resources. Mutual connections between PODs or SUs do not influence the cost. If a connection or data exchange takes place within one entity (POD or SU), the cost of network communication does not change. *** *InfiniBand and InfiniBand Trade Association are registered trademarks of the InfiniBand Trade Association.* # Working with InfiniBand™ topology of a GPU cluster Source: https://docs.nebius.com/compute/clusters/gpu/topology/manage.md [InfiniBand™ topology](https://docs.nebius.com/compute/clusters/gpu/topology) can help you increase performance of multi-VM jobs in GPU clusters. ## Prerequisites [Install and configure](https://docs.nebius.com/cli/install.md) the Nebius AI Cloud CLI. [Install and initialize the Nebius SDK for Go](https://docs.nebius.com/grpc-api/sdk/go.md). [Install and initialize the Nebius SDK for Python](https://docs.nebius.com/grpc-api/sdk/python.md). [Install and initialize the Nebius SDK for JavaScript](https://docs.nebius.com/grpc-api/sdk/javascript.md). ## How to get InfiniBand™ topology of a GPU cluster After you [create a GPU cluster and add VMs to it](https://docs.nebius.com/compute/clusters/gpu/index.md#how-to-enable-infiniband-for-vms-with-gpus), you can view the InfiniBand™ topology of this cluster and its VMs. To get the topology for all VMs in a GPU cluster: Run the following command: ```bash nebius compute gpu-cluster get --id computegpucluster-*** ``` In the `--id` parameter, specify the GPU cluster ID. The output example is the following: ```text ... status: infiniband_topology_path: instances: - instance_id: computeinstance-***rnqz path: - ***27bf - ***bb9b - ***b7ad - instance_id: computeinstance-***pepp path: - ***27bf - ***bb9b - ***e1ff - ... ``` ```go gpuCluster, err := sdk.Services().Compute().V1(). GpuCluster().Get( ctx, &compute.GetGpuClusterRequest{ Id: "computegpucluster-***", }, ) if err != nil { return err } fmt.Println(gpuCluster) ``` In the code, specify the GPU cluster ID. ```python gpu_cluster_service = GpuClusterServiceClient(sdk) gpu_cluster = await gpu_cluster_service.get( GetGpuClusterRequest(id="computegpucluster-***"), ) print(gpu_cluster) ``` In the code, specify the GPU cluster ID. ```ts const getGpuClusterService = new GpuClusterService(sdk); const gpuCluster = await getGpuClusterService.get( GetGpuClusterRequest.create({ id: "computegpucluster-***", }), ); console.log(gpuCluster); ``` In the code, specify the GPU cluster ID. To get the topology for an individual VM: Run the following command: ```bash nebius compute instance get --id computeinstance-*** ``` In the `--id` parameter, specify the ID of the VM attached to the GPU cluster. The output example is the following: ```text ... status: infiniband_topology_path: path: - ***27bf - ***bb9b - ***e1ff ``` ```go instance, err := sdk.Services().Compute().V1(). Instance().Get( ctx, &compute.GetInstanceRequest{ Id: "computeinstance-***", }, ) if err != nil { return err } fmt.Println(instance) ``` In the code, specify the ID of the VM attached to the GPU cluster. ```python instance_service = InstanceServiceClient(sdk) instance = await instance_service.get( GetInstanceRequest(id="computeinstance-***"), ) print(instance) ``` In the code, specify the ID of the VM attached to the GPU cluster. ```ts const getInstanceService = new InstanceService(sdk); const instance = await getInstanceService.get( GetInstanceRequest.create({ id: "computeinstance-***", }), ); console.log(instance); ``` In the code, specify the ID of the VM attached to the GPU cluster. In the topology data, the `path` list shows components of the [InfiniBand™ network layers](https://docs.nebius.com/compute/clusters/gpu/topology#architecture-of-infiniband-topology): ```text ***27bf # 1st network layer (InfiniBand™ fabric) ***bb9b # 2nd network layer (point of delivery, POD) ***e1ff # 3rd network layer (scalable unit, SU) ``` ## How to create the Slurm topology configuration To set up topology in [Slurm](https://slurm.schedmd.com) and run jobs for ML workloads, you need the [topology.conf](https://slurm.schedmd.com/topology.conf.html) file. This file shows the network hierarchy: how nodes are interconnected, what layers they are located at and what switches are used. The `topology.conf` file represents InfiniBand™ topology. You can create this file based on the [information about a given GPU cluster](https://docs.nebius.com/compute/clusters/gpu/topology/manage.md#how-to-get-infiniband-topology-of-a-gpu-cluster). To create the file, run one of the scripts from the [Nebius AI Cloud solution library](https://github.com/nebius/nebius-solution-library/tree/main/scripts/ib-topology) on GitHub. *** *InfiniBand and InfiniBand Trade Association are registered trademarks of the InfiniBand Trade Association.* # Managing applications with the Virtual machine deployment option Source: https://docs.nebius.com/compute/virtual-machines/applications.md Nebius AI Cloud provides several applications that you can deploy by using the **Virtual machine** deployment option on [Compute virtual machines](https://docs.nebius.com/compute/virtual-machines/manage.md). For example, you can deploy AI models, development environments or data processing tools. For information about deploying applications, see [Deploying applications in Nebius AI Cloud](https://docs.nebius.com/applications/deploy.md). ## Prerequisites For managing an application with the Virtual machine deployment option: Make sure you are in a [group](https://docs.nebius.com/iam/authorization/groups/index.md) that has at least the `editor` role within your tenant or project; for example, the default `editors` group. You can check this in the [Administration → IAM](https://console.nebius.com/iam) section of the web console. ## How to find and deploy an application To see the list of applications with the **Virtual machine** deployment option and deploy an application: 1. In the sidebar, go to **Applications**. 2. In the **Deployment** dropdown, select **Virtual machine** to see only applications that support the **Virtual machine** deployment option. 3. Choose an application, open its page and click **Deploy**. 4. Configure the application. You can specify the VM platform, preset, network settings and other parameters according to your needs. 5. Click **Deploy application**. 6. Wait until the application is deployed and running. ## How to delete an application 1. In the sidebar, go to **Applications**. 2. Go to the **Installed** tab to see your deployed applications. 3. Find the application you want to delete and open it. 4. On the application details page, go to the **Settings** tab. 5. Click **Delete application**. 6. To confirm that you want to delete the application, enter its name and click **Delete application**. When you delete an application deployed with the **Virtual machine** deployment option, the underlying virtual machine is also deleted. Applications deployed with this option are subject to Compute [charges](https://docs.nebius.com/compute/resources/pricing.md) and [quotas](https://docs.nebius.com/compute/resources/quotas-limits.md). # Running applications and custom containers on virtual machines Source: https://docs.nebius.com/compute/virtual-machines/applications-containers.md In Nebius AI Cloud, you can run applications in [container virtual machines](https://docs.nebius.com/compute/virtual-machines/containers.md) (VMs). A container VM allows you to launch a VM with a pre-installed container image, such as Jupyter Notebook, or a custom Docker image from a public registry. Container VMs are useful when you want to quickly deploy an application environment without manually configuring the VM or installing dependencies. This tutorial demonstrates two alternative ways to run container VMs: * [Run a container VM with a pre-installed application image](https://docs.nebius.com/compute/virtual-machines/applications-containers.md#run-a-container-vm-with-a-pre-installed-application-image) * [Run a container VM with a custom Docker image from the public registry](https://docs.nebius.com/compute/virtual-machines/applications-containers.md#run-a-container-vm-with-a-custom-docker-image) ## Costs The tutorial includes the following chargeable resources: * [Compute virtual machines](https://docs.nebius.com/compute/resources/pricing.md#virtual-machines-gpus-vcpus-ram) * [Compute disks](https://docs.nebius.com/compute/resources/pricing.md#disks) ## Prerequisites Generate an [SSH key pair](https://docs.nebius.com/compute/virtual-machines/ssh-keys.md). ## Steps ### Run a container VM with a pre-installed application image #### Create a single-GPU VM with Jupyter Notebook 1. In the [web console](https://console.nebius.com), go to  **Compute** → **Container VMs**. 2. Click  **Create container VM**. 3. Specify the VM name. 4. Select the **Jupyter Notebook** container image. 5. Copy and save the token that appears. You will need this token later to access the JupyterLab web interface. 6. In **Computing resources**, configure the VM with one GPU. For example, select NVIDIA® L40S PCIe with Intel Ice Lake and keep the predefined preset with eight CPUs. 7. In **Local storage**, specify the disk size. 8. In **Access**, add new credentials or select existing ones. To add new credentials: 1. Specify the username. Do not use the `root` or `admin` usernames. They are reserved for internal needs and cannot be used for SSH access. 2. Copy the contents of the `.pub` file generated earlier and paste it into the **Public key** field. 3. Click **Add credentials**. 9. Click **Create container VM**. #### Launch Jupyter Notebook When the container VM is running, connect to the application: 1. In **Container VMs**, open the page of the created VM. 2. Click **Go to Web UI** at the top of the VM page. 3. When prompted, paste the token into the authentication field and click **Log in**. If you did not save the Jupyter token earlier, you can copy it from the **Container parameters** section on the container VM page. 4. In JupyterLab, create a new notebook. 5. Run the following code. It shows information about available GPUs: ```python import torch if torch.cuda.is_available(): print("CUDA is available. PyTorch can use your GPU.") print(f"Number of GPUs available: {torch.cuda.device_count()}") print(f"GPU Name: {torch.cuda.get_device_name()}") else: print("CUDA is not available. PyTorch will run on CPU.") ``` Example output: ```text CUDA is available. PyTorch can use your GPU. Number of GPUs available: 1 GPU Name: NVIDIA L40S ``` #### Benchmark a VM with one GPU Run a simple benchmark to measure how long the GPU takes to multiply large matrices. This test multiplies two 30,000×30,000 tensors several times and measures the total execution time. Later in the tutorial, you will repeat the same benchmark on a VM with eight GPUs and compare the results. Run the following code: ```python import torch import time device = torch.device("cuda" if torch.cuda.is_available() else "cpu") matrix_size = 30000 a = torch.randn(matrix_size, matrix_size, device=device) b = torch.randn(matrix_size, matrix_size, device=device) num_runs = 10 for _ in range(3): torch.matmul(a, b) torch.cuda.synchronize() start_time = time.time() for _ in range(num_runs): torch.matmul(a, b) torch.cuda.synchronize() end_time = time.time() average_time = (end_time - start_time) print(f"Time for {num_runs} matrix multiplications ({matrix_size}x{matrix_size}): {average_time:.4f} seconds") ``` Example output: ```text Time for 10 matrix multiplications (30000x30000): 16.7096 seconds ``` In this benchmark test, CUDA synchronization ensures that each multiplication finishes before the next one starts, which makes the timing more accurate. #### Replace the VM with an 8-GPU VM while preserving data To scale from one GPU to eight GPUs and keep your notebooks: 1. Delete the current VM. When deleting the VM, select the option to keep the boot disk. 2. Create a new container VM as described in the [Create a single-GPU VM with Jupyter Notebook](https://docs.nebius.com/compute/virtual-machines/applications-containers.md#create-a-single-gpu-vm-with-jupyter-notebook) section, but: * In **Computing resources**, choose a configuration with eight GPUs * Attach the existing disk that contains your data as an additional disk #### Benchmark a VM with eight GPUs Run the benchmark test again on the VM with eight GPUs to measure how the workload performs after scaling. 1. Go to Jupyter Notebook and open your existing notebook. 2. Replace the benchmark code with: ```python import torch import time num_gpus = torch.cuda.device_count() matrix_size = 30000 num_runs = 10 chunk_size = matrix_size // num_gpus B_cpu = torch.randn(matrix_size, matrix_size) B_chunks = [B_cpu.to(f"cuda:{i}") for i in range(num_gpus)] A_chunks = [torch.randn(chunk_size, matrix_size, device=f"cuda:{i}") for i in range(num_gpus)] start_time = time.time() for _ in range(num_runs): C_chunks = [] for i in range(num_gpus): C = A_chunks[i] @ B_chunks[i] C_chunks.append(C) for i in range(num_gpus): torch.cuda.synchronize(i) end_time = time.time() print(f"Time for {num_runs} multi-GPU matrix multiplications ({matrix_size}x{matrix_size}): {(end_time - start_time):.4f} seconds") ``` Example output: ```text Time for 10 multi-GPU matrix multiplications (30000x30000): 1.3283 seconds. ``` This demonstrates the performance improvement when scaling from one GPU to eight GPUs. ### Run a container VM with a custom Docker image In the previous section, you deployed a container by using a pre-installed Jupyter Notebook application image on a container VM. You can also deploy containers with custom Docker images from public registries. In this section, you will create a container VM by using a Docker image from Docker Hub and access the application running inside the container. The [TensorFlow Jupyter image](https://hub.docker.com/r/tensorflow/tensorflow) is used as an example. This image includes both TensorFlow and Jupyter Notebook, so you can run TensorFlow workloads directly in a notebook environment. #### Create a container VM with a custom Docker image 1. In the [web console](https://console.nebius.com), go to  **Compute** → **Container VMs**. 2. Click  **Create container VM**. 3. Specify the VM name. 4. Select **Custom Image**. 5. In **Docker Image**, enter `tensorflow/tensorflow:nightly-gpu-jupyter`. 6. In **Docker run arguments**, specify `--restart=always --gpus all --shm-size=16GB -p 8888:8888`. These arguments enable GPU access, allocate shared memory and expose port 8888 for Jupyter Notebook. 7. In **Computing resources**, use at least one GPU. 8. In **Local storage**, specify the disk size. 9. In **Access**, select the previously created credentials. 10. Click **Create container VM**. #### Connect to the VM When the container VM is running, connect to the application: 1. In the **Container VMs** section, open the page of the VM with the custom Docker image installed. 2. In the **Network** section, copy the **Public IPv4** address. 3. Connect to the VM by using SSH: ```bash ssh @ ``` 4. List the running containers and copy the name of the TensorFlow container: ```bash sudo docker ps ``` 5. Get the Jupyter token: ```bash sudo docker logs ``` 6. Open in browser `http://:8888/?token=`. 7. In JupyterLab, create a new notebook and run the following code to verify that TensorFlow works in the container: ```python import tensorflow as tf import time matrix_size = 10000 a = tf.random.normal([matrix_size, matrix_size]) b = tf.random.normal([matrix_size, matrix_size]) start = time.time() c = tf.matmul(a, b) _ = c.numpy() end = time.time() print(f"Matrix multiplication ({matrix_size}x{matrix_size}) took {end - start:.4f} ``` Example output: ```text Matrix multiplication (10000x10000) took 1.9316 seconds ``` This example performs large matrix multiplication by using TensorFlow and prints the execution time. ## How to delete the created resources The created Compute VMs and their boot disks are chargeable. If you do not need them, delete the resources created during this tutorial: 1. Go to  **Compute** → **Container VMs**. 2. Open the VM page. 3. Switch to **Settings**. 4. Click **Delete virtual machine**. 5. In the window that opens, select **Delete the boot disk**. 6. Confirm the deletion. 7. Repeat these steps for any other VMs created during this tutorial. # Capacity advisor for GPU availability in Nebius AI Cloud Source: https://docs.nebius.com/compute/virtual-machines/capacity-advisor.md export const RolePrerequisite = ({role, defaultGroup}) => { return <> Make sure that you are in a group that has at least the {role} role within your tenant {defaultGroup ? <>; for example, the default {defaultGroup} group : ""}. You can check this in the Administration → IAM section of the web console. ; }; Nebius AI Cloud's *capacity advisor* provides insights into GPU capacity availability for launching virtual machines (VMs) with specific hardware presets. It helps you understand where you can launch VMs based on your [quotas](https://docs.nebius.com/compute/resources/quotas-limits.md) and the current physical capacity in Nebius AI Cloud [regions](https://docs.nebius.com/overview/regions.md). ## Scope The capacity advisor provides data for the following virtual machines with GPUs: * **By service**: * VMs that you create directly in Compute * [Managed Soperator](https://docs.nebius.com/slurm-soperator/index.md) nodes * [Managed Kubernetes®](https://docs.nebius.com/kubernetes/index.md) nodes * VMs launched by [Serverless AI](https://docs.nebius.com/serverless/index.md) for running jobs and endpoints * **By type**: * [Regular VMs](https://docs.nebius.com/compute/virtual-machines/manage.md) * [Preemptible VMs](https://docs.nebius.com/compute/virtual-machines/preemptible.md) * [VMs with reservations](https://docs.nebius.com/compute/virtual-machines/reservations.md) * [Container VMs](https://docs.nebius.com/compute/virtual-machines/containers.md) Data about computing resource availability of [standalone applications](https://docs.nebius.com/applications/types.md) and VMs without GPUs isn't provided. Data provided by the capacity advisor is accurate as of a specific timestamp included in the data and doesn't guarantee availability of GPU resources at creation time. ## Prerequisites 1. [Install and configure](https://docs.nebius.com/cli/install.md) the Nebius AI Cloud CLI. 2. Nebius AI Cloud provider for Terraform doesn't support the capacity advisor. ## How to get data from the capacity advisor In the sidebar, go to  **Administration** → **Capacity dashboard**. For each VM platform, preset, region, InfiniBand™ fabric and VM type (regular, preemptible or with reservations), the capacity advisor shows: * How many VMs you can launch, based on your quotas and the current physical capacity (for regular and [preemptible](https://docs.nebius.com/compute/virtual-machines/preemptible.md) VMs) or on your active [capacity reservations](https://docs.nebius.com/compute/virtual-machines/reservations.md) (for VMs with reservations). * How likely you are to be able to launch the displayed number of regular or preemptible VMs. > For example, if your quota for a certain kind of VMs is 10 VMs, you have a high chance of launching them all when the overall capacity is in the hundreds, but a low chance when the capacity is less than 10 VMs. As reservations guarantee you a certain number of GPUs that aren't subject to quotas, the chance of launch isn't displayed for VMs with reservations. 1. Get the tenant ID. To get the tenant ID, go to the [web console](https://console.nebius.com) and expand the top-left list of tenants. Next to the tenant’s name, click → **Copy tenant ID**. 2. Run `nebius capacity resource-advice list` to get the capacity advisor data: ```bash nebius capacity resource-advice list --parent-id ``` In the output, each list item contains data for a single combination of VM platform, preset, region, InfiniBand fabric and VM type: ```yaml highlight={3-8,15-16,19-22,25-28} items: - spec: region: eu-north1 fabric: fabric-2 compute_instance: platform: gpu-h100-sxm preset: name: 1gpu-16vcpu-200gb resources: vcpu_count: 16 memory_gibibytes: 200 gpu_count: 1 gpu_memory_gigabytes: 80 status: reserved: availability_level: AVAILABILITY_LEVEL_LIMIT_REACHED data_state: DATA_STATE_FRESH effective_at: "2026-03-27T11:25:55.695087Z" on_demand: available: 24 limit: 32 availability_level: AVAILABILITY_LEVEL_HIGH data_state: DATA_STATE_FRESH effective_at: "2026-03-27T11:08:07.360Z" preemptible: available: 22 limit: 128 availability_level: AVAILABILITY_LEVEL_MEDIUM data_state: DATA_STATE_FRESH effective_at: "2026-03-27T11:08:07.360Z" ... ``` In the `.items[*].status` fields, `on_demand`, `preemptible` and `reserved` contain data about regular VMs, preemptible VMs and VMs with reservations, respectively. Each of these fields contains the following data: * `available`: Maximum number of VMs that you can launch, based on your quotas and the current physical capacity. * `limit`: Your current quota. * `availability_level`: Level of resource availability. Possible values: * `AVAILABILITY_LEVEL_LOW`: **Low chance of launch** — Available capacity is significantly lower than your quota. Creating resources might not be possible. * `AVAILABILITY_LEVEL_MEDIUM`: **Medium chance of launch** — Available capacity is lower than your quota. Creating resources is possible, but may fail. * `AVAILABILITY_LEVEL_HIGH`: **High chance of launch** — Available capacity is enough to fully satisfy your quota. * `AVAILABILITY_LEVEL_LIMIT_REACHED`: **Launch impossible** — No available capacity. * `data_state`: State of the data. Possible values: * `DATA_STATE_FRESH`: Data is up to date (fetched recently). * `DATA_STATE_STALE`: Data is stale (fetched a long time ago). * `DATA_STATE_UNKNOWN`: Capacity advisor failed to fetch data. * `effective_at`: Timestamp of the last update. # Capacity reservations for Compute virtual machines Source: https://docs.nebius.com/compute/virtual-machines/reservations.md To make sure that GPU capacity is always available for your virtual machines (VMs), you can reserve GPUs. A *reservation* represents a [capacity block group](https://docs.nebius.com/overview/limits/capacity-block-groups.md), and it reserves a specific number of GPUs that are allocated to your infrastructure. GPUs from a reservation remain available, even if a VM is stopped. Without reservations, GPU capacity is taken from a shared pool and returned when a VM is stopped (for example, by you or a [maintenance event](https://docs.nebius.com/compute/virtual-machines/maintenance.md)). To start using reservations, send a request to your Nebius manager. In this request, specify how many GPUs you would like to reserve and for what period. If you are not in contact with a Nebius manager, you can ask [technical support](https://console.nebius.com/support/create-ticket) to connect you with one. After reservations are ready, you can add them to your VMs when you create or update these VMs. You can also check your capacity block groups on the **Limits** page and get detailed information about them. For more information, see [List of capacity block groups](https://docs.nebius.com/overview/limits/capacity-block-groups.md#list-of-capacity-block-groups). GPUs allocated from reservations do not count towards [quotas on the number of GPUs](https://docs.nebius.com/compute/resources/quotas-limits.md#gpu-virtual-machines). ## How to add reservations to VMs VMs of a regular type and with GPUs support reservations. [Preemptible VMs](https://docs.nebius.com/compute/virtual-machines/preemptible.md) and VMs without GPUs do not support them. If you want to [create a VM](https://docs.nebius.com/compute/virtual-machines/manage.md#create-a-vm) and you have [capacity block groups](https://docs.nebius.com/overview/limits/capacity-block-groups.md), on the **General** step, select **Reserved VM**. On the **Compute** step, select a platform and configure the **Reservation** settings. If you do not have capacity block groups, the wizard skips the **General** step and opens **Compute** instead. If you want to modify an existing VM, [stop it](https://docs.nebius.com/compute/virtual-machines/stop-start.md#how-to-stop-and-start-vms-manually) first and then go to its **Settings** tab on the VM page. Next, update the reservation settings. The **Reservation** section is only displayed if you have capacity block groups. In the **Reservation** section, you can configure the following options: * **Any (existing and future)** (default): Compute selects among your matching capacity block groups automatically. * **Specific capacity block groups**: Select one or more capacity block groups. Each option shows the capacity block group ID, reservation period and GPU usage. Make sure the selected groups have enough capacity and do not expire soon. * **Switch to PAYG**: Choose whether the VM can start after you create or restart it without active intervals in selected capacity block groups: * **When reservation is exhausted** (default): The VM can start as a pay-as-you-go VM when no capacity is available in the selected capacity block groups. * **Never**: The VM cannot start without available capacity in the selected capacity block groups. This does not affect the VM when it is running. If an interval in a selected capacity block group expires while the VM is running, the VM always continues as a pay-as-you-go VM, regardless of this setting. If you have capacity block groups in multiple regions, select a **Region** first. Use the `--reservation-policy-*` parameters when creating or updating a VM: * To create a VM, use the following command: ```bash nebius compute instance create \ ... \ --reservation-policy-policy \ --reservation-policy-reservation-ids ``` * To update a VM, [stop it](https://docs.nebius.com/compute/virtual-machines/stop-start.md#how-to-stop-and-start-vms-manually) first and then use the following command: ```bash nebius compute instance update \ ... \ --reservation-policy-policy \ --reservation-policy-reservation-ids ``` Description of the parameters: * `--reservation-policy-policy`: Policy for reservation usage. Supports the following values: * `auto`: VM resources are allocated from reservations. If no reservations are currently available, the VM runs without them. In this case, resources for the VM are provided from the common pool. The `auto` value is default. If you don't have any reservations and you don't set the `--reservation-policy-policy` parameter, the `auto` value applies and the VM runs without reservations. * `forbid`: VM resources are provided from the common pool, and no reservations are used. * `strict`: VM resources are exclusively allocated from reservations. The VM doesn't run without the reservations. * `--reservation-policy-reservation-ids` (optional): IDs of specific reservations (capacity block groups). Use this parameter only if you need specific reservations. Specify the IDs in the order in which reservations should apply. For instance, resources should be allocated from the first specified reservation. When it is exhausted or expired, the service uses resources from the second specified reservation, and so on. Make sure to select reservations that have enough capacity and that do not expire in several days. To find out how different combinations of parameter values impact the result, see the table below: | `policy` | `reservation-ids` | **Behavior** | | -------- | ----------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `auto` | Not specified | Compute tries to launch a VM in any available and suitable reservation. If none is found, VM resources are provided from the common pool, not from a reservation. | | `auto` | Specified | Compute tries to launch a VM in one of the specified reservations. If none of them fit (for example, they are not currently active or there are not enough GPUs), VM resources are provided from the common pool. | | `forbid` | Not specified | VM resources are provided from the common pool. No reservations are used. | | `forbid` | Specified | Not supported. If you apply this combination, it will result in a validation error. | | `strict` | Not specified | Compute tries to launch a VM in any available and suitable reservation. If none is found, a request for creating or updating a VM fails. | | `strict` | Specified | Compute tries to launch a VM in one of the specified reservations. If none of them fit, a request for creating or updating a VM fails. | Use the `reservation_policy` parameter in the VM configuration: ```hcl resource "nebius_compute_v1_instance" "my_vm" { ... reservation_policy = { policy = "" reservation_ids = "" } ... } ``` Description of the parameters: * `policy`: Policy for reservation usage. Supports the following values: * `AUTO`: VM resources are allocated from reservations. If no reservations are currently available, the VM runs without them. In this case, resources for the VM are provided from the common pool. The `AUTO` value is default. If you don't have any reservations and you don't set the `policy` parameter, the `AUTO` value applies and the VM runs without reservations. * `FORBID`: VM resources are provided from the common pool, and no reservations are used. * `STRICT`: VM resources are exclusively allocated from reservations. The VM doesn't run without the reservations. * `reservation_ids`: IDs of specific reservations (capacity block groups). You can use this parameter with the `AUTO` and `STRICT` reservation usages: Specify the IDs in the order in which reservations should apply. For instance, resources should be allocated from the first specified reservation. When it is exhausted or expired, the service uses resources from the second specified reservation, and so on. Make sure to select reservations that have enough capacity and that do not expire in several days. To find out how different combinations of parameter values impact the result, see the table below: | `policy` | `reservation_ids` | **Behavior** | | -------- | ----------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `AUTO` | Not specified | Compute tries to launch a VM in any available and suitable reservation. If none is found, VM resources are provided from the common pool, not from a reservation. | | `AUTO` | Specified | Compute tries to launch a VM in one of the specified reservations. If none of them fit (for example, they are not currently active or there are not enough GPUs), VM resources are provided from the common pool. | | `FORBID` | Not specified | VM resources are provided from the common pool. No reservations are used. | | `FORBID` | Specified | Not supported. If you apply this combination, it will result in a validation error. | | `STRICT` | Not specified | Compute tries to launch a VM in any available and suitable reservation. If none is found, a request for creating or updating a VM fails. | | `STRICT` | Specified | Compute tries to launch a VM in one of the specified reservations. If none of them fit, a request for creating or updating a VM fails. | Use `ReservationPolicy` in `InstanceSpec` when creating or updating a VM: ```go reservationPolicy := &compute.ReservationPolicy{ Policy: compute.ReservationPolicy_STRICT, ReservationIds: []string{ "", }, } ``` Description of the parameters: * `Policy`: Policy for reservation usage. Supports the `AUTO`, `FORBID` and `STRICT` values. * `ReservationIds` (optional): IDs of specific reservations (capacity block groups). Use this parameter only if you need specific reservations. Specify the IDs in the order in which reservations should apply. For instance, resources should be allocated from the first specified reservation. When it is exhausted or expired, the service uses resources from the second specified reservation, and so on. Make sure to select reservations that have enough capacity and that do not expire in several days. To find out how different combinations of parameter values impact the result, see the table below: | `Policy` | `ReservationIds` | **Behavior** | | -------- | ---------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `AUTO` | Not specified | Compute tries to launch a VM in any available and suitable reservation. If none is found, VM resources are provided from the common pool, not from a reservation. | | `AUTO` | Specified | Compute tries to launch a VM in one of the specified reservations. If none of them fit (for example, they are not currently active or there are not enough GPUs), VM resources are provided from the common pool. | | `FORBID` | Not specified | VM resources are provided from the common pool. No reservations are used. | | `FORBID` | Specified | Not supported. If you apply this combination, it will result in a validation error. | | `STRICT` | Not specified | Compute tries to launch a VM in any available and suitable reservation. If none is found, a request for creating or updating a VM fails. | | `STRICT` | Specified | Compute tries to launch a VM in one of the specified reservations. If none of them fit, a request for creating or updating a VM fails. | Use `reservation_policy` in `InstanceSpec` when creating or updating a VM: ```python reservation_policy = ReservationPolicy( policy=ReservationPolicy.Policy.STRICT, reservation_ids=[""], ) ``` Description of the parameters: * `policy`: Policy for reservation usage. Supports the `AUTO`, `FORBID` and `STRICT` values. * `reservation_ids` (optional): IDs of specific reservations (capacity block groups). Use this parameter only if you need specific reservations. Specify the IDs in the order in which reservations should apply. For instance, resources should be allocated from the first specified reservation. When it is exhausted or expired, the service uses resources from the second specified reservation, and so on. Make sure to select reservations that have enough capacity and that do not expire in several days. To find out how different combinations of parameter values impact the result, see the table below: | `policy` | `reservation_ids` | **Behavior** | | -------- | ----------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `AUTO` | Not specified | Compute tries to launch a VM in any available and suitable reservation. If none is found, VM resources are provided from the common pool, not from a reservation. | | `AUTO` | Specified | Compute tries to launch a VM in one of the specified reservations. If none of them fit (for example, they are not currently active or there are not enough GPUs), VM resources are provided from the common pool. | | `FORBID` | Not specified | VM resources are provided from the common pool. No reservations are used. | | `FORBID` | Specified | Not supported. If you apply this combination, it will result in a validation error. | | `STRICT` | Not specified | Compute tries to launch a VM in any available and suitable reservation. If none is found, a request for creating or updating a VM fails. | | `STRICT` | Specified | Compute tries to launch a VM in one of the specified reservations. If none of them fit, a request for creating or updating a VM fails. | Use `reservationPolicy` in `InstanceSpec` when creating or updating a VM: ```ts const reservationPolicy = ReservationPolicy.create({ policy: ReservationPolicy_Policy.STRICT, reservationIds: [""], }); ``` Description of the parameters: * `policy`: Policy for reservation usage. Supports the `AUTO`, `FORBID` and `STRICT` values. * `reservationIds` (optional): IDs of specific reservations (capacity block groups). Use this parameter only if you need specific reservations. Specify the IDs in the order in which reservations should apply. For instance, resources should be allocated from the first specified reservation. When it is exhausted or expired, the service uses resources from the second specified reservation, and so on. Make sure to select reservations that have enough capacity and that do not expire in several days. To find out how different combinations of parameter values impact the result, see the table below: | `policy` | `reservationIds` | **Behavior** | | -------- | ---------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `AUTO` | Not specified | Compute tries to launch a VM in any available and suitable reservation. If none is found, VM resources are provided from the common pool, not from a reservation. | | `AUTO` | Specified | Compute tries to launch a VM in one of the specified reservations. If none of them fit (for example, they are not currently active or there are not enough GPUs), VM resources are provided from the common pool. | | `FORBID` | Not specified | VM resources are provided from the common pool. No reservations are used. | | `FORBID` | Specified | Not supported. If you apply this combination, it will result in a validation error. | | `STRICT` | Not specified | Compute tries to launch a VM in any available and suitable reservation. If none is found, a request for creating or updating a VM fails. | | `STRICT` | Specified | Compute tries to launch a VM in one of the specified reservations. If none of them fit, a request for creating or updating a VM fails. | ## How to find information about reservations for an already configured VM You can check the list of VMs and an overview of a given VM to find information about the VM reservations. ### List of VMs The [list of VMs](https://console.nebius.com/compute) provides the following: * The **Platform and VM type** column shows what configuration you have set up for a given VM. * The **Current reservations** column shows what reservations are currently used. Data in these columns does not always match: * If a VM is preemptible or stopped, **Current reservations** do not show any data (**N/A** is displayed). * If capacity in reservations is exhausted, **Current reservations** show that there are no reservations currently consumed. ### VM overview On the VM page, on the **VM overview** tab, in the **Resource capacity** block, you can find more detailed information: * The **VM type**, **Reservation usage** and **If no capacity** fields show the configuration that you have set up. * The **Current reservations** and **Next interval** fields show the current consumption of reservations. If the VM runs without reservations, no data about them is displayed. ## Billing for reservations Reservations and [billing models](https://docs.nebius.com/signup-billing/billing-models/overview.md) do not match directly. If your VMs run without reservations, this does not mean that the pay-as-you-go (PAYG) pricing applies by default for these VMs. It depends on whether you have an addendum for the commitment discounts. When a Nebius manager creates reservations for you, they also prepare an addendum for the commitment discounts. After the addendum comes into force, you are charged for VMs based on this billing model. If your VM runs without reservations, the service still charges you based on the commitment discounts because of the addendum. If you do not have the addendum, your VMs are based on PAYG. ## See also * [Capacity block groups in Nebius AI Cloud](https://docs.nebius.com/overview/limits/capacity-block-groups.md) * [Capacity reservations for Managed Service for Kubernetes® node groups](https://docs.nebius.com/kubernetes/node-groups/reservations.md) # Running AI workloads on VMs Source: https://docs.nebius.com/compute/clusters/ai-workloads.md You can run AI workloads on Compute VMs by using third-party tools. Information about how to do it is now located in separate documentation. See [Third-party integrations with Nebius AI Cloud](https://docs.nebius.com/3p-integrations/index.md). # Types of storage volumes in Compute Source: https://docs.nebius.com/compute/storage/types.md In Compute, storage resources that can be added to virtual machines (VMs) as separate managed resources are called *volumes*. Compute offers two types of managed volumes and one host-local storage option: * [Disks](https://docs.nebius.com/compute/storage/types.md#disks): * **Network SSD disks**: managed *block storage* volumes. * **Local SSD disks**: *ephemeral* host-local block storage. * [Shared filesystems](https://docs.nebius.com/compute/storage/types.md#shared-filesystems) are *file storage* volumes. A filesystem can be shared by multiple VMs. Nebius AI Cloud also provides *object storage* through a separate service, [Object Storage](https://docs.nebius.com/object-storage/index.md). Together, these block, file and object storage options cover all [use cases](https://docs.nebius.com/compute/storage/types.md#use-cases-and-suggestions) for data preparation, training and inference workloads, as well as associated infrastructure (boot disks, database hosts etc.) ## Disks *Disks* provide block storage for Compute VMs. Data that you put on disks is divided into blocks that are stored efficiently and reliably on underlying physical drives. You can create boot disks and additional disks. A *boot disk* is a core disk in a VM, and an *additional disk* is mainly for data storage. Compute provides different disk sources: * [Public disk images](https://docs.nebius.com/compute/storage/boot-disk-images.md) supported by the platform. * [Custom disk images](https://docs.nebius.com/compute/storage/custom-disk-images.md) that you create and tailor to your needs. * Custom image families that contain a series of custom images and provide the latest image for the disk. * [Disk snapshots](https://docs.nebius.com/compute/storage/disk-snapshots.md), which are point-in-time copies of a disk state. Alternatively, you can [create](https://docs.nebius.com/compute/storage/manage.md#how-to-create-a-disk) a blank disk. Images and image families are only supported for boot disks. ### Network and local SSD disks Compute offers two kinds of disks: * [Network SSD disks](https://docs.nebius.com/compute/storage/types.md#network-ssd-disks) can be created as a boot disk for a VM, from one of the boot disk images provided by Nebius AI Cloud, or as an empty additional disk. One Compute network SSD disk can only be added to one running VM at a time. * [Local SSD disks](https://docs.nebius.com/compute/storage/types.md#local-ssd-disks) are Non-Volatile Memory Express (NVMe) drives physically attached to the Compute host that runs a virtual machine (VM). They are not created or managed as separate storage resources, and you can only add them when [creating a VM](https://docs.nebius.com/compute/virtual-machines/manage.md#create-a-vm). #### Network SSD disks * **Network SSD** (`network_ssd`) Reliable disks backed by solid state drives (SSDs). Best used for infrastructure purposes: as VM boot disks, disks on Slurm controller VMs, etc. Reliability of Network SSD disks is ensured by means of [erasure coding](https://en.wikipedia.org/wiki/Erasure_code). A disk will tolerate up to two concurrent hardware failures in the Nebius AI Cloud [region](https://docs.nebius.com/overview/regions.md). * **Network SSD Non-replicated** (Network SSD NRD, `network_ssd_non_replicated`) High-performance disks backed by SSDs. Best used as temporary storage without strict reliability requirements, e.g., a boot disk for nodes in Managed Service for Kubernetes® clusters where redundancy is less important. Data blocks of Network SSD Non-replicated disks are stored in [NVMe namespaces](https://nvmexpress.org/resource/nvme-namespaces/) on underlying SSDs. The size of each namespace is 93 GiB, so the disk size must be a multiple of 93 GiB. Network SSD Non-replicated disks have no redundancy. It's not recommended to store any persistent data on these disks. If a disk fails, its data will be lost. * **Network SSD IO M3** (`network_ssd_io_m3`) High-performance and reliable disks backed by SSDs. Best used in performance-critical storage solutions, e.g., as storage disks in GlusterFS clusters. In addition to performance levels similar to Network SSD Non-replicated disks, Network SSD IO M3 disks are reliable through replication, with each disk's data mirrored to three physical drives. In the disk type name, "IO" stands for "input/output (optimized)" and "M3" stands for "mirrors 3". #### Local SSD disks Consider local SSD disks if your workload needs high-performance, low-latency storage for data that can be recreated. Local SSD disks are ephemeral, meaning temporary: their data is erased when the VM is stopped or deleted. Local SSD disks are available only on some platforms, presets and regions. For details, see [Availability](https://docs.nebius.com/compute/storage/local-disks.md#availability). Local SSD disks are useful for: * Scratch space for files and intermediate outputs that can be recreated. * Training or inference workloads that require low latency. * Read or write caches for data that can be recreated. ### Disk types comparison Network SSD disk types are differentiated by several characteristics: * **Performance** (bandwidth and IOPS): Local SSD > SSD IO M3 = SSD Non-replicated > SSD * **Reliability**: SSD IO M3 > SSD > SSD Non-replicated = Local SSD * **Price per 1 GiB per month**: SSD Non-replicated \< Local SSD \< SSD \< SSD IO M3 You can choose the size of a network disk, but local SSD disks are attached to the VM host as part of a predefined configuration for the selected platform and preset. For more details, see the following comparison table. The values for local SSD disks are the performance numbers per one local SSD disk. The bandwidth and IOPS values below are upper bounds; actual performance depends on workload. | **Disk type** | **Network SSD** | **Network SSD NRD** | **Network SSD IO M3** | **Local SSD disk**¹ | | -------------------------------------------------------- | ----------------------------------------------------------- | ------------------------------------------------ | ------------------------------------------------ | ----------------------------------- | | Capacity | 1–8192 GiB (= 8 TiB) | 93–262,074 GiB (\~ 256 TiB), multiples of 93 GiB | 93–262,074 GiB (\~ 256 TiB), multiples of 93 GiB | 3.5 TiB | | Read/write bandwidth | 450 MiB/s | 2 GiB/s | 2 GiB/s | Read: 6.8 GB/s
Write: 2.6 GB/s | | Read IOPS | 20,000 | 75,000 | 75,000 | 510,000 | | Write IOPS | 20,000 | 75,000 | 75,000 | 350,000 | | Reliability features | Erasure coding – tolerates two concurrent hardware failures | None | Replication – data mirrored to three drives | None | | [Price per 1 GiB per month](https://docs.nebius.com/compute/resources/pricing.md)² | \$0.071 | \$0.053 | \$0.118 | \$0.065 | ¹ For local SSD disks, the listed values are achieved under synthetic workload. ² The listed prices are valid as of March 9, 2026. For up-to-date prices, see [Price per 1 GiB per month](https://docs.nebius.com/compute/resources/pricing.md). ### VM-managed and standalone disks When you [create a VM](https://docs.nebius.com/compute/virtual-machines/manage.md), you can use either VM-managed or standalone disks: * *VM-managed disks* are the disks that you create along with the VM. Their lifecycle is tied to the VM. When you delete the VM, all of its VM-managed disks are deleted with the VM in a single operation. This makes VM-managed disks a good fit for ephemeral workloads, for example, training jobs or inference clusters where the VM and its storage should be cleaned up together. * *Standalone disks* are the disks that you create separately from the VM and attach them later to the VM by using the disk ID. Use standalone disks when you need them to persist independently after the VM is deleted, for example, to reattach them to another VM or to enable deletion protection. Renaming a VM-managed disk deletes the existing disk and creates a new one with a new name. All data on the disk is permanently lost. To rename a VM-managed disk without data loss, [convert it to a standalone disk](https://docs.nebius.com/compute/storage/manage.md#how-to-make-a-disk-vm-managed-or-standalone) and then rename it. ### Encryption of disks To store personal and other sensitive data securely, and to reduce the risk of unauthorized access, you can enable data encryption. To do so, [create a disk](https://docs.nebius.com/compute/storage/manage.md#how-to-create-a-disk) with data encryption enabled. For Network SSD disks, encryption is enabled by default and cannot be disabled. For Network SSD NRD and Network SSD IO M3 disks, encryption is optional and you can enable it. Encryption is available for both boot disks and secondary disks. Local SSD disks are not encrypted and no other data protection method is applied to them. Ensuring the protection of data stored on these devices is your responsibility. We don't recommend using local SSD disks for data that can't be recreated. For more information, see [Encryption in Nebius AI Cloud](https://docs.nebius.com/security/encryption.md). ### Disk performance Disk performance depends on both the disk type and its size — it increases as you add more allocation units. Every allocation unit contributes equally to the overall bandwidth and IOPS until you reach the [upper bounds](https://docs.nebius.com/compute/storage/types.md#disk-types-comparison) for the disk. While you have fewer allocation units than needed to reach the upper bounds, the disk performance equals the sum of each unit's performance. Once the sum reaches the upper bound for bandwidth or IOPS, adding more capacity does not increase performance any further. Disk performance metrics per allocation unit are shown in the following table. The bandwidth and IOPS values below are upper bounds; actual performance depends on workload. | **Disk type** | **Network SSD** | **Network SSD NRD** | **Network SSD IO M3** | **Local SSD disk**¹ | | ------------------------ | --------------- | ------------------- | --------------------- | ------------------- | | Allocation unit size | 32 GiB | 93 GiB | 93 GiB | 3.5 TiB | | Read bandwidth per unit | 15 MiB/s | 110 MiB/s | 110 MiB/s | 6.8 GB/s | | Write bandwidth per unit | 15 MiB/s | 82 MiB/s | 82 MiB/s | 2.6 GB/s | | Read IOPS per unit | 1,000 | 28,000 | 28,000 | 510,000 | | Write IOPS per unit | 1,000 | 5,600 | 5,600 | 350,000 | ¹ For local SSD disks, the listed values are peak numbers achieved per disk under synthetic workload. Disk encryption also affects the disk performance. Encryption requires additional processing of write operations; therefore, it can reduce performance by up to 15%. Local SSD disks can only be enabled during VM creation, cannot be scaled later, and are available only in fixed configurations. For supported configurations, see [Using local SSD disks on Compute virtual machines](https://docs.nebius.com/compute/storage/local-disks.md#availability). For other disks, you can choose your disk size in multiples of its allocation units to achieve the desired performance. Examples: How to reach the maximum for each disk performance metric: * Read/write bandwidth: * Maximum overall bandwidth is 450 MiB/s. * Number of allocation units needed to achieve it = Maximum overall read/write bandwidth ÷ Maximum read/write bandwidth per unit = 450 MiB/s ÷ 15 MiB/s = 30 units. * Minimum disk size = 30 × 32 GiB = 960 GiB. * Read IOPS: * Maximum overall read IOPS is 20,000. * Number of allocation units needed to achieve it = Maximum overall read IOPS ÷ Maximum overall read IOPS per unit = 20,000 ÷ 1,000 = 20 units. * Minimum disk size = 20 × 32 GiB = 640 GiB. * Write IOPS: * Maximum overall write IOPS is 20,000. * Number of allocation units needed to achieve it = Maximum overall write IOPS ÷ Maximum write IOPS per unit = 20,000 ÷ 1,000 = 20 units. * Minimum disk size = 20 × 32 GiB = 640 GiB. To achieve the maximum disk performance for all metrics, you need a disk of 960 GiB or more. How to reach the maximum for each disk performance metric: * Read bandwidth: * Maximum overall read bandwidth is 2 GiB/s. * Number of allocation units needed to achieve it = Maximum overall read bandwidth ÷ Maximum read bandwidth per unit = 2048 MiB/s ÷ 110 MiB/s ≈ 18.62, rounding up to 19 units. * Minimum disk size = 19 × 93 GiB = 1767 GiB. * Write bandwidth: * Maximum overall write bandwidth is 2 GiB/s. * Number of allocation units needed to achieve it = Maximum overall write bandwidth ÷ Maximum write bandwidth per unit = 2048 MiB/s ÷ 82 MiB/s ≈ 24.98, rounding up to 25 units. * Minimum disk size = 25 × 93 GiB = 2325 GiB. * Read IOPS: * Maximum overall read IOPS is 75,000. * Number of allocation units needed to achieve it = Maximum overall read IOPS ÷ Maximum read IOPS per unit = 75,000 ÷ 28,000 ≈ 2.68, rounding up to 3 units. * Minimum disk size = 3 × 93 GiB = 279 GiB. * Write IOPS: * Maximum overall write IOPS is 75,000. * Number of allocation units needed to achieve it = Maximum overall write IOPS ÷ Maximum write IOPS per unit = 75,000 ÷ 5,600 ≈ 13.39, rounding up to 14 units. * Minimum disk size = 14 × 93 GiB = 1302 GiB. To achieve the maximum disk performance for all metrics, you need a disk of 2325 GiB or more. ## Shared filesystems Shared filesystems provide file storage for Compute VMs. When VMs work with file storage, they work with a hierarchy of folders and files, as opposed to blocks when disks are involved. One shared filesystem can be attached to multiple VMs at once. All VMs that the filesystem is attached to must belong to the same [project](https://docs.nebius.com/iam/overview.md#projects). Sharing a filesystem across projects is not supported, even if the projects are in the same [region](https://docs.nebius.com/overview/regions.md). To use a shared filesystem on a VM that it is attached to, you must mount it as a virtiofs device. Filesystems support [data encryption](https://docs.nebius.com/security/encryption.md) by default; you cannot disable it. Encryption allows you to store personal and other sensitive data on filesystems securely, and reduce the risk of unauthorized access. ### Filesystem specifications Nebius provides shared filesystems that are generally based on solid state drives (`network_ssd` in developer tools such as Nebius AI Cloud CLI or provider for Terraform) to back them up. Shared filesystems have the following specifications: * Capacity: 1–5,242,880 GiB (= 5120 TiB = 5 PiB) * Read bandwidth per client: up to 12 GiB/s * Write bandwidth per client: up to 8 GiB/s * Aggregate read bandwidth: up to 940 GiB/s * Aggregate write bandwidth: up to 475 GiB/s * Maximum file size: 512 GiB × filesystem's [block size](https://docs.nebius.com/compute/storage/manage.md#type-encryption-and-size) in KiB (for example, for the default block size it will be 512 GiB × 4 = 2TiB) * Maximum number of [inodes](https://www.kernel.org/doc/html/v6.3/filesystems/vfs.html#the-inode-object): * For filesystems up to 256 GiB: 4,194,304 (4 × 220) * For filesystems larger than 256 GiB: filesystem's size ÷ 64 KiB For example, if the filesystem's size is 512 GiB, its maximum number of inodes is (512 × 230) ÷ (64 × 210) = 8 × 220 = 8,388,608. * Reliability features: Erasure coding – tolerates two concurrent hardware failures * [Price per 1 GiB per month](https://docs.nebius.com/compute/resources/pricing.md)¹: \$0.08 ¹ The price is shown as of July 2, 2025. For up-to-date prices, see [Price per 1 GiB per month](https://docs.nebius.com/compute/resources/pricing.md). ### Filesystem performance Filesystem performance depends on its size — performance increases with each 4 TiB of the filesystem size. Every 4 TiB contributes equally to the overall bandwidth until you reach the [upper bounds](https://docs.nebius.com/compute/storage/types.md#filesystem-specifications) for the filesystem. Each 4 TiB of SSD filesystem improves the performance metrics by the following values: * Read bandwidth: by up to 3.70 GiB/s. * Write bandwidth: by up to 1.89 GiB/s. ## Storage types comparison | Characteristic | [Local SSD disks](https://docs.nebius.com/compute/storage/types.md#local-ssd-disks) | [Network disks](https://docs.nebius.com/compute/storage/types.md#disks) | [Shared filesystems](https://docs.nebius.com/compute/storage/types.md#shared-filesystems) | | ---------------- | --------------------------------------------------------- | ------------------------------------------------------- | --------------------------------------------------------------- | | Durability | Ephemeral | Durable | Durable | | Attachment model | Tied to the VM run and physical host | Independent volume attached to one running VM at a time | Independent volume that can be shared by multiple VMs | | Capacity model | Preconfigured, all or none | User-defined | User-defined | ## Use cases and suggestions Here is an overview of various stages of ML/AI workloads and storage options that Compute and other Nebius AI Cloud services provide for these stages, as well as general suggestions for using Compute storage. ### Infrastructure * **VM boot disks: Network SSD disks** For OS and system data on your VMs, the main storage requirement is reliability, so the suggested disk type is Network SSD. * **VM storage disks: Network SSD IO M3 disks** If you are building storage solutions on VMs, e.g., GlusterFS clusters, use Network SSD IO M3 disks for speed and reliability. * **Managed Kubernetes node storage: Network SSD Non-replicated disks** For Kubernetes worker nodes where data reliability isn't a top priority (as the data is often transient), Network SSD Non-replicated disks provide high performance and low latency. * **Database hosts: Network SSD IO M3 disks** Database workloads often demand consistent and high input/output operations per second (IOPS), and Network SSD IO M3 disks offer the best combination of reliability and speed. ### Data preparation * **Storing and preprocessing datasets: Object Storage buckets** Object Storage is ideal for handling large, unstructured datasets and provides a scalable solution for preprocessing tasks like data normalization or augmentation. ### Training * **Streaming datasets to workers: SSD shared filesystems or Object Storage buckets** In most cases, SSD shared filesystems ensure fast access to datasets during training, without bottlenecks. For exceptionally large datasets (1 PiB+) or distributed training across external workers, Object Storage buckets provide a scalable solution. * **Sharing code between workers: SSD shared filesystems** By using SSD shared filesystems, multiple workers can efficiently access and synchronize code during distributed training, ensuring consistency and minimizing latency. * **Checkpoints: SSD shared filesystems, then Object Storage buckets** During training, SSD shared filesystems allow for quickly saving and loading checkpoints, thus ensuring minimal disruption. Once training is completed, asynchronous transfer to Object Storage reduces costs while maintaining accessibility for future use. * **Scratch space: local SSD disks** On [supported platforms, presets and regions](https://docs.nebius.com/compute/storage/local-disks.md#availability), [local SSD disks](https://docs.nebius.com/compute/storage/local-disks.md) provide host-local NVMe for data that can be recreated and benefits from high performance and low latency. Treat them as ephemeral and keep important data on durable storage. ### Inference * **Autoscaling, sharing weights between GPUs: SSD shared filesystems** When inference workloads require scaling across multiple VMs with GPUs, SSD shared filesystems allow for fast sharing of model weights, thus ensuring consistent performance across nodes during autoscaling. * **Sharing results: Object Storage buckets** Once inference tasks are completed, Object Storage is ideal for sharing outputs such as logs, predictions or reports with other users or systems, due to its scalable and cost-efficient nature. ### General suggestions * For maximum IOPS, reads and writes to a volume should be close to its [block size](https://docs.nebius.com/compute/storage/manage.md#type-encryption-and-size). * For maximum bandwidth, reads and writes to a volume should be in 4 MiB chunks. ## See also * [How to create a virtual machine](https://docs.nebius.com/compute/virtual-machines/manage.md#create-a-vm) * [Managing Compute volumes](https://docs.nebius.com/compute/storage/manage.md) * [Attaching and mounting Compute volumes to VMs](https://docs.nebius.com/compute/storage/use.md) * [How to detach additional volumes from virtual machines](https://docs.nebius.com/compute/storage/detach-volume.md) * [Local SSD disks for Compute virtual machines](https://docs.nebius.com/compute/storage/local-disks.md) # Managing Compute volumes Source: https://docs.nebius.com/compute/storage/manage.md In this article, you will learn how to manage [Compute volumes](https://docs.nebius.com/compute/storage/types.md): Network SSD disks and shared filesystems. Boot disks are added to virtual machines (VMs) immediately. To use secondary (additional) disks and shared filesystems on VMs after you create the volumes, you need to [attach and mount them to the VMs](https://docs.nebius.com/compute/storage/use.md). You can [detach these volumes](https://docs.nebius.com/compute/storage/detach-volume.md) later, if necessary. A VM and its volumes must be located in the same project. For more details about projects and resource hierarchy in Nebius AI Cloud, see [How resources, identities and access are managed in Nebius AI Cloud](https://docs.nebius.com/iam/overview.md). ## Prerequisites If you use the web console, you don't need to complete any prerequisites. [Install and configure](https://docs.nebius.com/cli/install.md) the Nebius AI Cloud CLI. [Install and configure](https://docs.nebius.com/terraform-provider/install.md) the Nebius AI Cloud provider for Terraform. [Install and initialize the Nebius SDK for Go](https://docs.nebius.com/grpc-api/sdk/go.md). [Install and initialize the Nebius SDK for Python](https://docs.nebius.com/grpc-api/sdk/python.md). [Install and initialize the Nebius SDK for JavaScript](https://docs.nebius.com/grpc-api/sdk/javascript.md). ## How to create a disk 1. In the sidebar, go to  **Storage** → **Disks**. 2. Click **Create disk**. 3. On the creation page, specify a disk name. 4. In **Disk source type**, select one of the supported sources for the disk: * **Blank disk**: Create a regular, blank disk. Suitable for any boot or additional disk. * **Public image**: Create a boot disk from one of [public images](https://docs.nebius.com/compute/storage/boot-disk-images.md) that Nebius AI Cloud provides. An image represents an operating system for the disk. * **Custom image**: Create a boot disk based on your [custom image](https://docs.nebius.com/compute/storage/custom-disk-images.md) that includes custom software. * **Custom image family**: Create a boot disk based on your custom image family. When you create custom images, you can add them to an arbitrary custom family. If an image family contains several images, the latest one is used. * **Snapshot**: Create a boot or additional disk based on a [disk snapshot](https://docs.nebius.com/compute/storage/disk-snapshots.md). 5. In **Storage configuration**, select the disk type. 6. (Optional) Enable [data encryption](https://docs.nebius.com/security/encryption.md) if you're creating a Network SSD Non-replicated or Network SSD IO M3 disk. Encryption is enabled by default for Network SSD disks. 7. Set the disk size and block size. 8. (Optional) Enable **Deletion protection** to prevent this disk from being accidentally deleted. 9. Click **Create disk**. Run the following command: ```bash nebius compute disk create \ --name \ --source-image-family-image-family \ --source-image-family-parent-id \ --source-image-id \ --source-snapshot-id \ --type network_ \ --disk-encryption-type disk_encryption_managed \ --size-gibibytes \ --block-size-bytes \ --forbid-deletion ``` For more information, see [Volume parameters](https://docs.nebius.com/compute/storage/manage.md#volume-parameters). 1. Create the following configuration: ```hcl resource "nebius_compute_v1_disk" "" { name = "" parent_id = "" type = "NETWORK_" size_gibibytes = block_size_bytes = # Only for boot disks. Use one of the supported disk sources. source_image_family = { image_family = "" parent_id = "" # Optional: for custom image families only } source_image_id = "" source_snapshot_id = "" # Optional: only for NETWORK_SSD_NON_REPLICATED and NETWORK_SSD_IO_M3 disk_encryption = { type = "DISK_ENCRYPTION_MANAGED" } # Optional: protect disk from deletion forbid_deletion = true } ``` For `parent_id`, use the [project ID](https://docs.nebius.com/iam/manage-projects.md#terraform-3). For more information about other parameters, see [Volume parameters](https://docs.nebius.com/compute/storage/manage.md#volume-parameters). For the full reference on the disk resource, see [nebius\_compute\_v1\_disk](https://docs.nebius.com/terraform-provider/reference/resources/compute_v1_disk). 2. Check that the configuration is correct: ```bash terraform validate ``` 3. Apply the changes: ```bash terraform apply ``` ```go // One of compute.DiskSpec_NETWORK_SSD, // compute.DiskSpec_NETWORK_SSD_NON_REPLICATED, // or compute.DiskSpec_NETWORK_SSD_IO_M3. diskType := compute.DiskSpec_NETWORK_SSD_NON_REPLICATED diskEncryptionType := compute.DiskEncryption_DISK_ENCRYPTION_MANAGED operation, err := sdk.Services().Compute().V1(). Disk().Create( ctx, &compute.CreateDiskRequest{ Metadata: &common.ResourceMetadata{ Name: "", }, Spec: &compute.DiskSpec{ Size: &compute.DiskSpec_SizeGibibytes{ SizeGibibytes: , }, BlockSizeBytes: , Type: diskType, Source: &compute.DiskSpec_SourceImageFamily{ SourceImageFamily: &compute.SourceImageFamily{ ImageFamily: "", }, }, DiskEncryption: &compute.DiskEncryption{ Type: diskEncryptionType, }, ForbidDeletion: true, }, }, ) if err != nil { return err } if _, err = operation.Wait(ctx); err != nil { return err } ``` For more information, see [Volume parameters](https://docs.nebius.com/compute/storage/manage.md#volume-parameters). ```python # One of DiskSpec.DiskType.NETWORK_SSD, # DiskSpec.DiskType.NETWORK_SSD_NON_REPLICATED, # or DiskSpec.DiskType.NETWORK_SSD_IO_M3. disk_type = DiskSpec.DiskType.NETWORK_SSD_NON_REPLICATED encryption_type = ( DiskEncryption.DiskEncryptionType.DISK_ENCRYPTION_MANAGED ) disk_service = DiskServiceClient(sdk) create_disk_operation = await disk_service.create( CreateDiskRequest( metadata=ResourceMetadata( name="", ), spec=DiskSpec( block_size_bytes=, type=disk_type, source_image_family=SourceImageFamily( image_family="", ), disk_encryption=DiskEncryption( type=encryption_type, ), forbid_deletion=True, size_gibibytes=, ), ), ) await create_disk_operation.wait() ``` For more information, see [Volume parameters](https://docs.nebius.com/compute/storage/manage.md#volume-parameters). ```ts // One of DiskSpec_DiskType.NETWORK_SSD, // DiskSpec_DiskType.NETWORK_SSD_NON_REPLICATED, // or DiskSpec_DiskType.NETWORK_SSD_IO_M3. const diskType = DiskSpec_DiskType.NETWORK_SSD_NON_REPLICATED; const createDiskService = new DiskService(sdk); const createDiskOperation = await createDiskService.create( CreateDiskRequest.create({ metadata: ResourceMetadata.create({ name: "", }), spec: DiskSpec.create({ blockSizeBytes: , type: diskType, source: { $case: "sourceImageFamily", sourceImageFamily: SourceImageFamily.create({ imageFamily: "", }), }, diskEncryption: DiskEncryption.create({ type: DiskEncryption_DiskEncryptionType.DISK_ENCRYPTION_MANAGED, }), forbidDeletion: true, size: { $case: "sizeGibibytes", sizeGibibytes: , }, }), }), ).result; await createDiskOperation.wait(); ``` For more information, see [Volume parameters](https://docs.nebius.com/compute/storage/manage.md#volume-parameters). For more information about how to start using secondary disks, see [Attaching and mounting Compute volumes to VMs](https://docs.nebius.com/compute/storage/use.md). ## How to create a shared filesystem 1. In the sidebar, go to  **Storage** → **Shared filesystems**. 2. Click **Create filesystem**. 3. On the creation page, specify a filesystem name. 4. Set the filesystem size and block size. 5. (Optional) Enable **Deletion protection** to prevent this filesystem from being accidentally deleted. 6. Click **Create filesystem**. Run the following command: ```bash nebius compute filesystem create \ --name \ --type network_ssd \ --size-gibibytes \ --block-size-bytes \ --forbid-deletion ``` For more details about volume parameters, see [Volume parameters](https://docs.nebius.com/compute/storage/manage.md#volume-parameters). 1. Create the following configuration: ```hcl resource "nebius_compute_v1_filesystem" "" { name = "" parent_id = "" type = "NETWORK_SSD" size_gibibytes = block_size_bytes = # Optional: protect filesystem from deletion forbid_deletion = true } ``` For `parent_id`, use [project ID](https://docs.nebius.com/iam/manage-projects.md#terraform-3). For more information about other parameters, see [Volume parameters](https://docs.nebius.com/compute/storage/manage.md#volume-parameters). For the full reference on the filesystem resource, see [nebius\_compute\_v1\_filesystem](https://docs.nebius.com/terraform-provider/reference/resources/compute_v1_filesystem). 2. Check that the configuration is correct: ```bash terraform validate ``` 3. Apply the changes: ```bash terraform apply ``` ```go operation, err = sdk.Services().Compute().V1(). Filesystem().Create( ctx, &compute.CreateFilesystemRequest{ Metadata: &common.ResourceMetadata{ Name: "", }, Spec: &compute.FilesystemSpec{ Size: &compute.FilesystemSpec_SizeGibibytes{ SizeGibibytes: , }, BlockSizeBytes: , Type: compute.FilesystemSpec_NETWORK_SSD, ForbidDeletion: true, }, }, ) if err != nil { return err } if _, err = operation.Wait(ctx); err != nil { return err } ``` For more details about volume parameters, see [Volume parameters](https://docs.nebius.com/compute/storage/manage.md#volume-parameters). ```python filesystem_service = FilesystemServiceClient(sdk) create_filesystem_operation = await filesystem_service.create( CreateFilesystemRequest( metadata=ResourceMetadata( name="", ), spec=FilesystemSpec( block_size_bytes=, type=FilesystemSpec.FilesystemType.NETWORK_SSD, forbid_deletion=True, size_gibibytes=, ), ), ) await create_filesystem_operation.wait() ``` For more details about volume parameters, see [Volume parameters](https://docs.nebius.com/compute/storage/manage.md#volume-parameters). ```ts const createFilesystemService = new FilesystemService(sdk); const createFilesystemOperation = await createFilesystemService.create( CreateFilesystemRequest.create({ metadata: ResourceMetadata.create({ name: "", }), spec: FilesystemSpec.create({ blockSizeBytes: , type: FilesystemSpec_FilesystemType.NETWORK_SSD, forbidDeletion: true, size: { $case: "sizeGibibytes", sizeGibibytes: , }, }), }), ).result; await createFilesystemOperation.wait(); ``` For more details about volume parameters, see [Volume parameters](https://docs.nebius.com/compute/storage/manage.md#volume-parameters). For more information about how to start using the created shared filesystem, see [Attaching and mounting Compute volumes to VMs](https://docs.nebius.com/compute/storage/use.md). ## Volume parameters Disks and shared filesystems share almost all of their parameters, except for boot disk image which can only be set for disks. CLI parameter names are shown in parentheses. Terraform uses the corresponding snake\_case attributes, and SDKs use the corresponding parameter names for each language, such as camelCase in JavaScript, as shown in the examples. ### Metadata **Name** (`name`): A Nebius AI Cloud resource name. It must be unique inside your tenant. Required at creation, cannot be changed after it. ### Type, encryption and size * **Type** (`type`): The volume type. See available types of [disks](https://docs.nebius.com/compute/storage/types.md#disk-types) and [shared filesystems](https://docs.nebius.com/compute/storage/types.md#filesystem-specifications). Required at creation, and cannot be changed later. * **Enable data encryption** (`disk-encryption-type`): Whether a volume should support [data encryption](https://docs.nebius.com/security/encryption.md). Encryption allows you to store personal and other sensitive data securely on volumes, and reduce the risk of unauthorized access. Use this parameter only for disks of the Network SSD Non-replicated and Network SSD IO M3 types. Filesystems and Network SSD disks support encryption by default, and you cannot disable it. For more information, see [Encryption of disks](https://docs.nebius.com/compute/storage/types.md#encryption-of-disks). In the CLI, use `--disk-encryption-type disk_encryption_managed` to enable encryption. * **Size** (`size-gibibytes`, `size-mebibytes`, `size-kibibytes` or `size-bytes`): The volume size. See requirements for sizes of [disks](https://docs.nebius.com/compute/storage/types.md#disk-types-comparison) and [shared filesystems](https://docs.nebius.com/compute/storage/types.md#filesystem-specifications) in their comparison tables. Required at creation. After creation, size can only be [increased](https://docs.nebius.com/compute/storage/manage.md#how-to-resize-a-volume). When using the CLI, you can set the volume size in GiB, MiB, KiB or B using a respective parameter. * **Block size** (`block-size-bytes`): The data block size for the volume. The data stored on the volume is divided into blocks of this size on the underlying physical drives. Cannot be changed after the volume is created. The block size must be a power of two between 4096 bytes (4 KiB) and 131,072 bytes (128 KiB). The default value is 4096 bytes (4 KiB). For maximum IOPS, reads and writes to a volume should be close to its block size. ### Disk sources Use one of the supported disk sources: * **Public image** (`source-image-family-image-family`): Create a boot disk from one of the [public images](https://docs.nebius.com/compute/storage/boot-disk-images.md) that Nebius AI Cloud provides. An image represents an operating system for the disk. * **Custom image** (`source-image-id`): Create a boot disk based on your [custom image](https://docs.nebius.com/compute/storage/custom-disk-images.md) that includes custom software. * **Custom image family** (both `source-image-family-image-family` and `source-image-family-parent-id`): Create a boot disk based on your custom image family. When you create custom images, you can add them to an arbitrary custom family. If an image family contains several images, the latest one is used. * **Snapshot** (`source-snapshot-id`): Create a boot or additional disk based on a [disk snapshot](https://docs.nebius.com/compute/storage/disk-snapshots.md). To create a blank additional disk, don't specify any disk source. ### Deletion protection * **Deletion protection** (`forbid-deletion`): Prevents the volume from being deleted. Use this parameter to protect disks and shared filesystems from accidental deletion, especially in automated environments such as CI/CD pipelines or Terraform configurations. Deletion protection can be enabled at creation time or changed at any time after creation. When enabled, any attempt to delete the volume fails with an error. To delete a protected volume, disable deletion protection first. ## How to resize a volume You can increase the size of an existing disk or shared filesystem. Reducing volume size is not possible. ### How to resize a disk Compute supports *hot resize*: the resize operation itself does not require stopping the VM. However, you need to restart the VM afterward for the operating system to recognize the new disk size. To resize a disk: 1. Change the disk size: 1. In the sidebar, go to  **Storage** → **Disks**. Alternatively, go to the virtual machine where the disk is attached and find it in the **Disks** tab. 2. Click the disk you want to resize and go to the **Settings** tab. 3. In the **Parameters** section, enter the new **Size** value or use the slider to set the new size. 4. Click **Save changes**. 1. If you haven't saved the disk's ID when creating it, get its ID: ```bash export DISK_ID=$(nebius compute disk get-by-name \ --parent-id \ --name \ --format json | jq -r ".metadata.id") ``` 2. Run [nebius compute disk update](https://docs.nebius.com/cli/reference/compute/disk/update) and set the new size by using one of the `--size-gibibytes`, `--size-mebibytes`, `--size-kibibytes` or `--size-bytes` parameters: ```bash nebius compute disk update \ --id $DISK_ID \ --size-gibibytes ``` 1. In your Terraform configuration, update the `size_gibibytes` value (or `size_mebibytes`, `size_kibibytes`, `size_bytes`) in the disk resource. For example: ```hcl highlight={4} resource "nebius_compute_v1_disk" "" { name = "" ... size_gibibytes = } ``` 2. Check that the configuration is correct: ```bash terraform validate ``` 3. Apply the changes: ```bash terraform apply ``` 1. If you haven't saved the disk or filesystem's ID when creating it, get its ID: ```go disk, err := sdk.Services().Compute().V1(). Disk().GetByName( ctx, &common.GetByNameRequest{ ParentId: "", Name: "", }, ) if err != nil { return err } diskID := disk.GetMetadata().GetId() ``` For a filesystem, get its ID by name with the same parameters. 2. Update the disk or filesystem size. Here is an example for a disk: ```go disk, err = sdk.Services().Compute().V1(). Disk().Get( ctx, &compute.GetDiskRequest{ Id: diskID, }, ) if err != nil { return err } if disk.GetSpec() == nil { return errors.New("disk spec is missing") } disk.Spec.Size = &compute.DiskSpec_SizeGibibytes{ SizeGibibytes: , } operation, err = sdk.Services().Compute().V1(). Disk().Update( ctx, &compute.UpdateDiskRequest{ Metadata: disk.Metadata, Spec: disk.Spec, }, ) if err != nil { return err } if _, err = operation.Wait(ctx); err != nil { return err } ``` 1. If you haven't saved the disk or filesystem's ID when creating it, get its ID: ```python disk_service = DiskServiceClient(sdk) disk = await disk_service.get_by_name( GetByNameRequest( parent_id="", name="", ), ) disk_id = disk.metadata.id ``` For a filesystem, get its ID by name with the same parameters. 2. Update the disk or filesystem size. Here is an example for a disk: ```python disk_service = DiskServiceClient(sdk) disk = await disk_service.get( GetDiskRequest(id=disk_id), ) if disk.spec is None: raise ValueError("disk spec is missing") disk.spec.size_gibibytes = update_disk_operation = await disk_service.update( UpdateDiskRequest( metadata=disk.metadata, spec=disk.spec, ), ) await update_disk_operation.wait() ``` 1. If you haven't saved the disk or filesystem's ID when creating it, get its ID: ```ts const getDiskByNameService = new DiskService(sdk); const diskByName = await getDiskByNameService.getByName( GetByNameRequest.create({ parentId: "", name: "", }), ); const diskId = diskByName.metadata?.id; if (!diskId) { throw new Error("disk ID is missing"); } ``` For a filesystem, get its ID by name with the same parameters. 2. Update the disk or filesystem size. Here is an example for a disk: ```ts const updateDiskService = new DiskService(sdk); const diskForResize = await updateDiskService.get( GetDiskRequest.create({ id: diskId, }), ); if (!diskForResize.spec) { throw new Error("disk spec is missing"); } diskForResize.spec.size = { $case: "sizeGibibytes", sizeGibibytes: , }; const updateDiskResizeOperation = await updateDiskService.update( UpdateDiskRequest.create({ metadata: diskForResize.metadata, spec: diskForResize.spec, }), ).result; await updateDiskResizeOperation.wait(); ``` 2. If you resized a secondary disk and it is currently attached to a running virtual machine, do the following: 1. [Restart](https://docs.nebius.com/compute/virtual-machines/stop-start.md#how-to-stop-and-start-vms-manually) this VM. 2. [Connect](https://docs.nebius.com/compute/virtual-machines/connect.md) to this VM. 3. Install the `cloud-guest-utils` package that manages the disk partitions: ```bash sudo apt-get update && sudo apt-get install -y cloud-guest-utils ``` 4. List disks and partitions: ```bash lsblk --paths ``` Output example: ```bash NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS /dev/vda 253:0 0 10G 0 disk ├─/dev/vda1 253:1 0 9G 0 part / ├─/dev/vda14 253:14 0 4M 0 part ├─/dev/vda15 253:15 0 106M 0 part /boot/efi └─/dev/vda16 259:0 0 913M 0 part /boot /dev/vdb 253:16 0 1M 0 disk /dev/vdc 253:32 0 20G 0 disk └─/dev/vdc1 253:33 0 10G 0 part /mnt/disk-0 ``` Find the device name of the resized disk and get the name of its last partition. The secondary disk is most likely the last one in the list. Also, check the `SIZE` column: it shows that the disk size is increased, but the partition size stays the same. In this example, the required device name is `/dev/vdc`, and the partition is `/dev/vdc1`. 5. Grow the partition to fill the disk: ```bash sudo growpart /dev/vdc 1 ``` If you work with a disk that has a device name other than `/dev/vdc`, change the device name and the partition index `1` in the current command and commands below. You can get the index of the partition from its name. Only the last partition may be grown. In the commands, you can use the device ID of the disk (`/dev/disk/by-id/virtio-disk-0`) instead of the device name (`/dev/vdc`). Run the `ls /dev/disk/by-id` command to get device IDs for all disks. 6. Refresh the kernel partition table for the disk and wait for the device information to be updated: ```bash sudo partprobe /dev/vdc && sudo udevadm settle ``` 7. Show information about partitions and check that the size of the partition has increased: ```bash lsblk -o NAME,SIZE,TYPE,FSTYPE,MOUNTPOINT /dev/vdc ``` Output example: ```bash NAME SIZE TYPE FSTYPE MOUNTPOINT vdc 25G disk └─vdc1 25G part ext4 /mnt/disk-0 ``` 8. Grow the `ext4` filesystem on the increased partition: ```bash sudo resize2fs /dev/vdc1 ``` 9. Check that the filesystem size has increased: ```bash df -hT ``` Output example: ```bash Filesystem Type Size Used Avail Use% Mounted on tmpfs tmpfs 795M 1.1M 794M 1% /run /dev/vda1 ext4 38G 3.3G 35G 9% / tmpfs tmpfs 3.9G 0 3.9G 0% /dev/shm tmpfs tmpfs 5.0M 0 5.0M 0% /run/lock cloud-metadata virtiofs 252G 16K 252G 1% /mnt/cloud-metadata /dev/vdc1 ext4 25G 24K 24G 1% /mnt/disk-0 /dev/vda16 ext4 881M 174M 645M 22% /boot /dev/vda15 vfat 105M 6.2M 99M 6% /boot/efi tmpfs tmpfs 795M 12K 795M 1% /run/user/1001 ``` ### How to resize a shared filesystem To resize a shared filesystem: 1. In the sidebar, go to  **Storage** → **Shared filesystems**. Alternatively, go to the virtual machine where the filesystem is attached and find it in the **Shared filesystems** tab. 2. Click the filesystem you want to resize and go to the **Settings** tab. 3. In the **Parameters** section, enter the new **Size** value or use the slider to set the new size. 4. Click **Save changes**. 1. If you haven't saved the filesystem's ID when creating it, get its ID by using [nebius compute filesystem get-by-name](https://docs.nebius.com/cli/reference/compute/filesystem/get-by-name). 2. Run [nebius compute filesystem update](https://docs.nebius.com/cli/reference/compute/filesystem/update) and set the new size by using one of the `--size-gibibytes`, `--size-mebibytes`, `--size-kibibytes` or `--size-bytes` parameters. 1. In your Terraform configuration, update the `size_gibibytes` value (or `size_mebibytes`, `size_kibibytes`, `size_bytes`) in the filesystem resource. For example: ```hcl highlight={4} resource "nebius_compute_v1_filesystem" "" { name = "" ... size_gibibytes = } ``` 2. Check that the configuration is correct: ```bash terraform validate ``` 3. Apply the changes: ```bash terraform apply ``` ## How to enable or disable deletion protection You can only change deletion protection of a [standalone disk](https://docs.nebius.com/compute/storage/types.md#vm-managed-and-standalone-disks). If you need to update a VM-managed disk, [convert it first to standalone](https://docs.nebius.com/compute/storage/manage.md#how-to-make-a-disk-vm-managed-or-standalone). To enable or disable deletion protection: 1. In the sidebar, go to **Storage** → **Disks** or **Storage** → **Shared filesystems**. 2. Click the volume you want to update and go to the **Settings** tab. 3. In the **Parameters** section, enable or disable **Deletion protection**. 4. Click **Save changes**. 1. If you haven't saved the disk or filesystem's ID when creating it, get its ID: ```bash export DISK_ID=$(nebius compute disk get-by-name \ --parent-id \ --name \ --format json | jq -r ".metadata.id") ``` For a filesystem, use [nebius compute filesystem get-by-name](https://docs.nebius.com/cli/reference/compute/filesystem/get-by-name) with the same parameters. 2. Run [nebius compute disk update](https://docs.nebius.com/cli/reference/compute/disk/update) for a disk, or [nebius compute filesystem update](https://docs.nebius.com/cli/reference/compute/filesystem/update) for a filesystem: ```bash nebius compute disk update \ --id $DISK_ID \ --forbid-deletion= ``` 1. In your Terraform configuration, set `forbid_deletion` to `true` or `false` in the disk or filesystem resource. For example, for a disk: ```hcl highlight={4} resource "nebius_compute_v1_disk" "" { name = "" ... forbid_deletion = true } ``` 2. Check that the configuration is correct: ```bash terraform validate ``` 3. Apply the changes: ```bash terraform apply ``` 1. If you haven't saved the disk or filesystem's ID when creating it, get its ID: ```go disk, err := sdk.Services().Compute().V1(). Disk().GetByName( ctx, &common.GetByNameRequest{ ParentId: "", Name: "", }, ) if err != nil { return err } diskID := disk.GetMetadata().GetId() ``` For a filesystem, get its ID by name with the same parameters. 2. Update the disk or filesystem deletion protection. Here is an example for a disk: ```go disk, err = sdk.Services().Compute().V1(). Disk().Get( ctx, &compute.GetDiskRequest{ Id: diskID, }, ) if err != nil { return err } if disk.GetSpec() == nil { return errors.New("disk spec is missing") } disk.Spec.ForbidDeletion = operation, err = sdk.Services().Compute().V1(). Disk().Update( ctx, &compute.UpdateDiskRequest{ Metadata: disk.Metadata, Spec: disk.Spec, }, ) if err != nil { return err } if _, err = operation.Wait(ctx); err != nil { return err } ``` 1. If you haven't saved the disk or filesystem's ID when creating it, get its ID: ```python disk_service = DiskServiceClient(sdk) disk = await disk_service.get_by_name( GetByNameRequest( parent_id="", name="", ), ) disk_id = disk.metadata.id ``` For a filesystem, get its ID by name with the same parameters. 2. Update the disk or filesystem deletion protection. Here is an example for a disk: ```python disk_service = DiskServiceClient(sdk) disk = await disk_service.get( GetDiskRequest(id=disk_id), ) if disk.spec is None: raise ValueError("disk spec is missing") disk.spec.forbid_deletion = update_disk_operation = await disk_service.update( UpdateDiskRequest( metadata=disk.metadata, spec=disk.spec, ), ) await update_disk_operation.wait() ``` 1. If you haven't saved the disk or filesystem's ID when creating it, get its ID: ```ts const getDiskByNameService = new DiskService(sdk); const diskByName = await getDiskByNameService.getByName( GetByNameRequest.create({ parentId: "", name: "", }), ); const diskId = diskByName.metadata?.id; if (!diskId) { throw new Error("disk ID is missing"); } ``` For a filesystem, get its ID by name with the same parameters. 2. Update the disk or filesystem deletion protection. Here is an example for a disk: ```ts const updateDiskDeletionService = new DiskService(sdk); const diskForDeletion = await updateDiskDeletionService.get( GetDiskRequest.create({ id: diskId, }), ); if (!diskForDeletion.spec) { throw new Error("disk spec is missing"); } diskForDeletion.spec.forbidDeletion = ; const updateDiskDeletionOperation = await updateDiskDeletionService.update( UpdateDiskRequest.create({ metadata: diskForDeletion.metadata, spec: diskForDeletion.spec, }), ).result; await updateDiskDeletionOperation.wait(); ``` If you try to delete a volume with deletion protection enabled, the operation will fail, and you'll see the following message: `Error: rpc error: code = FailedPrecondition desc = disk cannot be deleted because forbid_deletion is set`. Disable deletion protection first, then delete the volume. ## How to make a disk VM-managed or standalone Each disk is either [VM-managed or standalone](https://docs.nebius.com/compute/storage/types.md#vm-managed-and-standalone-disks). You can convert a disk from one state to another. To do so: 1. In the sidebar, go to  **Compute** → **Virtual machines**. 2. Open the page of the required VM and then go to the **Disks** tab. 3. In the line of the required disk, click  → **Convert to VM-managed** or  → **Convert to standalone**. ## How to delete a volume Deleting a volume permanently removes all data stored on it. Before deleting, make sure the volume is [detached](https://docs.nebius.com/compute/storage/detach-volume.md) from any virtual machine. 1. In the sidebar, go to **Storage** → **Disks** or **Storage** → **Shared filesystems**. 2. Open the page of the volume that you want to delete. 3. Go to the **Settings** tab. 4. Click **Delete disk** or **Delete filesystem**. 5. In the window that opens, confirm the deletion. 1. Get the ID of the volume you want to delete: ```bash nebius compute list ``` 2. Delete the disk: ```bash nebius compute disk delete ``` 3. Delete the filesystem: ```bash nebius compute filesystem delete ``` 1. In your Terraform configuration, remove the `nebius_compute_v1_disk` or `nebius_compute_v1_filesystem` resource block. If the resource has `forbid_deletion = true`, set it to `false` before removing the resource, then apply the configuration. Once done, remove the resource. 2. Check that the configuration is correct: ```bash terraform validate ``` 3. Apply the changes: ```bash terraform apply ``` 1. If you haven't saved the volume ID, get it as described in [How to resize a volume](https://docs.nebius.com/compute/storage/manage.md#how-to-resize-a-volume). 2. Delete the disk: ```go operation, err = sdk.Services().Compute().V1(). Disk().Delete( ctx, &compute.DeleteDiskRequest{ Id: "", }, ) if err != nil { return err } if _, err = operation.Wait(ctx); err != nil { return err } ``` 3. Delete the filesystem: ```go operation, err = sdk.Services().Compute().V1(). Filesystem().Delete( ctx, &compute.DeleteFilesystemRequest{ Id: "", }, ) if err != nil { return err } if _, err = operation.Wait(ctx); err != nil { return err } ``` 1. If you haven't saved the volume ID, get it as described in [How to resize a volume](https://docs.nebius.com/compute/storage/manage.md#how-to-resize-a-volume). 2. Delete the disk: ```python disk_service = DiskServiceClient(sdk) delete_disk_operation = await disk_service.delete( DeleteDiskRequest( id="", ), ) await delete_disk_operation.wait() ``` 3. Delete the filesystem: ```python filesystem_service = FilesystemServiceClient(sdk) delete_filesystem_operation = await filesystem_service.delete( DeleteFilesystemRequest( id="", ), ) await delete_filesystem_operation.wait() ``` 1. If you haven't saved the volume ID, get it as described in [How to resize a volume](https://docs.nebius.com/compute/storage/manage.md#how-to-resize-a-volume). 2. Delete the disk: ```ts const deleteDiskService = new DiskService(sdk); const deleteDiskOperation = await deleteDiskService.delete( DeleteDiskRequest.create({ id: "", }), ).result; await deleteDiskOperation.wait(); ``` 3. Delete the filesystem: ```ts const deleteFilesystemService = new FilesystemService(sdk); const deleteFilesystemOperation = await deleteFilesystemService.delete( DeleteFilesystemRequest.create({ id: "", }), ).result; await deleteFilesystemOperation.wait(); ``` ## See also * [Types of storage volumes in Compute](https://docs.nebius.com/compute/storage/types.md) * [Attaching and mounting Compute volumes to VMs](https://docs.nebius.com/compute/storage/use.md) # Boot disk images for Compute virtual machines Source: https://docs.nebius.com/compute/storage/boot-disk-images.md When you [create a boot disk](https://docs.nebius.com/compute/storage/manage.md#how-to-create-a-disk) for a virtual machine, you need to choose an image for the disk. Compute supports two types of boot disk images: * *Public images* are provided and supported by the platform by default. * *Custom images* are images that you [create](https://docs.nebius.com/compute/storage/custom-disk-images.md) yourself with customized software and architecture. Nebius AI Cloud provides public boot disk images for GPU and non-GPU VMs. ## Compatibility types The image that you choose for a VM must be compatible with the VM's [platform](https://docs.nebius.com/compute/virtual-machines/types.md). There are different types of compatibility: * *Recommended images* ensure stable VM performance. * *Alternative images* are compatible with the platform but do not guarantee stable performance. ## Image family Each image has a family. When you use the [Nebius AI Cloud CLI](https://docs.nebius.com/cli/reference/compute/disk/create) or the [provider for Terraform](https://docs.nebius.com/terraform-provider/reference/resources/compute_v1_disk) to create a boot disk, you need to specify its family. For example, the image Ubuntu 24.04 LTS for NVIDIA® GPUs (CUDA® 13) has the family `ubuntu24.04-cuda13.0`. ## Prerequisites [Install and configure](https://docs.nebius.com/cli/install.md) the Nebius AI Cloud CLI. [Install and initialize the Nebius SDK for Go](https://docs.nebius.com/grpc-api/sdk/go.md). [Install and initialize the Nebius SDK for Python](https://docs.nebius.com/grpc-api/sdk/python.md). [Install and initialize the Nebius SDK for JavaScript](https://docs.nebius.com/grpc-api/sdk/javascript.md). ## How to get a list of available public images To get a list of public boot disk images available in a [region](https://docs.nebius.com/overview/regions.md): Run the following command: ```bash nebius compute image list-public --region ``` ```go images, err := sdk.Services().Compute().V1(). Image().ListPublic( ctx, &compute.ListPublicRequest{ Region: "", }, ) if err != nil { return err } fmt.Println(images) ``` ```python image_service = ImageServiceClient(sdk) images = await image_service.list_public( ListPublicRequest( region="", ), ) print(images) ``` ```ts const imageService = new ImageService(sdk); const images = await imageService.listPublic( ListPublicRequest.create({ region: "", }), ); console.log(images); ``` In the output, you'll see public images available in the specified region, including image families and other metadata. To determine which VM platforms are compatible with a public image, check the following parameters in the output: * `recommended_platforms`: Platforms for which the image is recommended. * `unsupported_platforms`: Platforms for which the image is not supported (with reasons, if available). Availability of images and their compatibility with platforms differ by region. ## Images for GPU VMs For VMs with GPUs, create boot disks from the following images: * Ubuntu 24.04 LTS for NVIDIA® GPUs (CUDA® 12), `ubuntu24.04-cuda12` * Ubuntu 24.04 LTS for NVIDIA® GPUs (CUDA® 13), `ubuntu24.04-cuda13.0` The `ubuntu22.04-cuda12` image family is deprecated. Existing disks created from images in this family remain available, but creating new disks from this image family isn't supported. Migrate to newer images. The following boot disk images are compatible with GPU VMs: | VM platform | [Recommended images](https://docs.nebius.com/compute/storage/boot-disk-images.md#compatibility-types) | [Alternative images](https://docs.nebius.com/compute/storage/boot-disk-images.md#compatibility-types) | | -------------------------------------------------------------- | ------------------------------------------------------------------- | ----------------------------------------------------------------- | | NVIDIA® B300 NVLink with Intel Granite Rapids `gpu-b300-sxm` | Ubuntu 24.04 LTS for NVIDIA® GPUs (CUDA® 13) `ubuntu24.04-cuda13.0` | *None* | | NVIDIA® B200 NVLink with Intel Emerald Rapids `gpu-b200-sxm` | Ubuntu 24.04 LTS for NVIDIA® GPUs (CUDA® 13) `ubuntu24.04-cuda13.0` | *None* | | NVIDIA® B200 NVLink with Intel Emerald Rapids `gpu-b200-sxm-a` | Ubuntu 24.04 LTS for NVIDIA® GPUs (CUDA® 13) `ubuntu24.04-cuda13.0` | *None* | | NVIDIA® H200 NVLink with Intel Sapphire Rapids `gpu-h200-sxm` | Ubuntu 24.04 LTS for NVIDIA® GPUs (CUDA® 13) `ubuntu24.04-cuda13.0` | Ubuntu 24.04 LTS for NVIDIA® GPUs (CUDA® 12) `ubuntu24.04-cuda12` | | NVIDIA® H100 NVLink with Intel Sapphire Rapids `gpu-h100-sxm` | Ubuntu 24.04 LTS for NVIDIA® GPUs (CUDA® 13) `ubuntu24.04-cuda13.0` | Ubuntu 24.04 LTS for NVIDIA® GPUs (CUDA® 12) `ubuntu24.04-cuda12` | | NVIDIA® RTX PRO™ 6000 with Intel Granite Rapids `gpu-rtx6000` | Ubuntu 24.04 LTS for NVIDIA® GPUs (CUDA® 13) `ubuntu24.04-cuda13.0` | *None* | | NVIDIA® L40S PCIe with Intel Ice Lake `gpu-l40s-a` | Ubuntu 24.04 LTS for NVIDIA® GPUs (CUDA® 13) `ubuntu24.04-cuda13.0` | Ubuntu 24.04 LTS for NVIDIA® GPUs (CUDA® 12) `ubuntu24.04-cuda12` | | NVIDIA® L40S PCIe with AMD Epyc Genoa `gpu-l40s-d` | Ubuntu 24.04 LTS for NVIDIA® GPUs (CUDA® 13) `ubuntu24.04-cuda13.0` | Ubuntu 24.04 LTS for NVIDIA® GPUs (CUDA® 12) `ubuntu24.04-cuda12` | The `1gpu-20vcpu-224gb` preset for NVIDIA® B200 platforms (`gpu-b200-sxm` and `gpu-b200-sxm-a`) requires [driver](https://docs.nebius.com/compute/storage/boot-disk-images.md#gpu-drivers-and-other-components) version 580.x or newer. Earlier driver versions are not supported. ### GPU drivers and other components The boot disk images for VMs with GPUs include the following components:
Component `ubuntu24.04-cuda12` `ubuntu24.04-cuda13.0`
Drivers preset `cuda12.8` `cuda13.0`
CUDA Toolkit 12.8 ([release notes](https://docs.nvidia.com/cuda/archive/12.8.0/)) 13.0 ([release notes](https://docs.nvidia.com/cuda/archive/13.0.0/))
NVIDIA® Data Center GPU Driver 570.x 580.x
Linux kernel 6.11, NVIDIA® HWE 6.11, NVIDIA® HWE
Networking package [NVIDIA® DOCA](https://developer.nvidia.com/networking/doca) 2.9.2 ([release notes](https://docs.nvidia.com/doca/archive/2-9-2-lts-ovs-update/doca+release+notes/index.html)) NVIDIA® DOCA 3.1.0 ([release notes](https://docs.nvidia.com/doca/archive/3-1-0/doca+release+notes/index.html))
Other components
  • [NVIDIA® Collective Communications Library](https://developer.nvidia.com/nccl) (NCCL)
  • [NVIDIA® Container Toolkit](https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/latest/index.html)
  • [NVIDIA® Data Center GPU Manager](https://developer.nvidia.com/dcgm) (DCGM)
  • [Nebius AI Cloud monitoring agent](https://docs.nebius.com/observability/agents/monitoring-agent.md)
## Images for non-GPU VMs For VMs without GPUs, create boot disks from the Ubuntu 24.04 LTS, `ubuntu24.04-driverless` image without GPU drivers and components. The images without drivers are also compatible with GPU VMs, but you need to install the drivers and components manually. We recommend using the [dedicated images for GPU VMs](https://docs.nebius.com/compute/storage/boot-disk-images.md#images-for-gpu-vms). The following boot disk images are compatible with non-GPU VMs: | VM platform | [Recommended images](https://docs.nebius.com/compute/storage/boot-disk-images.md#compatibility-types) | [Alternative images](https://docs.nebius.com/compute/storage/boot-disk-images.md#compatibility-types) | | ------------------------------- | ------------------------------------------ | ------------------------------------------ | | Non-GPU AMD EPYC Genoa `cpu-d3` | Ubuntu 24.04 LTS `ubuntu24.04-driverless` | None | | Non-GPU Intel Ice Lake `cpu-e2` | Ubuntu 24.04 LTS `ubuntu24.04-driverless` | None | The `ubuntu22.04-driverless` image family is deprecated. Existing disks created from images in this family remain available, but creating new disks from this image family isn't supported. Migrate to newer images. ## Security updates Automatic security updates are disabled by default. We recommend that you check the compatibility of new library versions on a test VM, and then apply the updates manually to all running GPU nodes. If you do need automatic updates, you can [enable](https://docs.nebius.com/compute/storage/automatic-updates.md) them. *** *InfiniBand and InfiniBand Trade Association are registered trademarks of the InfiniBand Trade Association.* # Creating custom boot disk images Source: https://docs.nebius.com/compute/storage/custom-disk-images.md *Custom images* allow you to quickly [create virtual machines (VMs)](https://docs.nebius.com/compute/storage/custom-disk-images.md#how-to-create-a-vm-from-a-custom-image) or boot disks with all the necessary software, OS and configuration, which can greatly reduce infrastructure deployment time and ensure consistency across environments. You can [create](https://docs.nebius.com/compute/storage/custom-disk-images.md#how-to-create-a-custom-boot-disk-image), [edit or delete](https://docs.nebius.com/compute/storage/custom-disk-images.md#how-to-edit-or-delete-a-custom-boot-disk-image) custom [boot disk images](https://docs.nebius.com/compute/storage/boot-disk-images.md) in the web console, by using the CLI or by using a Nebius SDK. Alternatively, you can create custom boot disk images by using [Packer with the Nebius plug-in](https://docs.nebius.com/compute/storage/packer.md). ## Prerequisites 1. Make sure that you have enough quotas for images (**Number of images** and **Total storage capacity of all images**). You can view quotas and request changes on the [Administration → Limits → Quotas](https://console.nebius.com/limits/quotas) page of the web console. 2. Prepare the source from which the image inherits configuration and architecture. Choose one of the following types of sources: * Boot disk. [Create a VM](https://docs.nebius.com/compute/virtual-machines/manage.md#create-a-vm), [connect to it](https://docs.nebius.com/compute/virtual-machines/connect.md) and install the software that the image should inherit. The image will be based on the boot disk of this VM and will include the installed software. * Disk snapshot. [Create a snapshot](https://docs.nebius.com/compute/storage/disk-snapshots.md#how-to-create-a-snapshot) from a boot disk and reuse this snapshot for the image. * File with the ready image. [Upload an image file to a bucket](https://docs.nebius.com/object-storage/objects/upload-download.md#upload-a-single-file) in Object Storage and use this file to create the image. 1. [Install and configure](https://docs.nebius.com/cli/install.md) the Nebius AI Cloud CLI. 2. Make sure that you have enough quotas for images (**Number of images** and **Total storage capacity of all images**). You can view quotas and request changes on the [Administration → Limits → Quotas](https://console.nebius.com/limits/quotas) page of the web console. 3. Prepare the source from which the image inherits configuration and architecture. Choose one of the following types of sources: * Boot disk. [Create a VM](https://docs.nebius.com/compute/virtual-machines/manage.md#create-a-vm), [connect to it](https://docs.nebius.com/compute/virtual-machines/connect.md) and install the software that the image should inherit. The image will be based on the boot disk of this VM and will include the installed software. * Disk snapshot. [Create a snapshot](https://docs.nebius.com/compute/storage/disk-snapshots.md#how-to-create-a-snapshot) from a boot disk and reuse this snapshot for the image. * File with the ready image. [Upload an image file to a bucket](https://docs.nebius.com/object-storage/objects/upload-download.md#upload-a-single-file) in Object Storage and use this file to create the image. 1. [Install and initialize the Nebius SDK for Go](https://docs.nebius.com/grpc-api/sdk/go.md). 2. Make sure that you have enough quotas for images (**Number of images** and **Total storage capacity of all images**). You can view quotas and request changes on the [Administration → Limits → Quotas](https://console.nebius.com/limits/quotas) page of the web console. 3. Prepare the source from which the image inherits configuration and architecture. Choose one of the following types of sources: * Boot disk. [Create a VM](https://docs.nebius.com/compute/virtual-machines/manage.md#create-a-vm), [connect to it](https://docs.nebius.com/compute/virtual-machines/connect.md) and install the software that the image should inherit. The image will be based on the boot disk of this VM and will include the installed software. * Disk snapshot. [Create a snapshot](https://docs.nebius.com/compute/storage/disk-snapshots.md#how-to-create-a-snapshot) from a boot disk and reuse this snapshot for the image. * File with the ready image. [Upload an image file to a bucket](https://docs.nebius.com/object-storage/objects/upload-download.md#upload-a-single-file) in Object Storage and use this file to create the image. 1. [Install and initialize the Nebius SDK for Python](https://docs.nebius.com/grpc-api/sdk/python.md). 2. Make sure that you have enough quotas for images (**Number of images** and **Total storage capacity of all images**). You can view quotas and request changes on the [Administration → Limits → Quotas](https://console.nebius.com/limits/quotas) page of the web console. 3. Prepare the source from which the image inherits configuration and architecture. Choose one of the following types of sources: * Boot disk. [Create a VM](https://docs.nebius.com/compute/virtual-machines/manage.md#create-a-vm), [connect to it](https://docs.nebius.com/compute/virtual-machines/connect.md) and install the software that the image should inherit. The image will be based on the boot disk of this VM and will include the installed software. * Disk snapshot. [Create a snapshot](https://docs.nebius.com/compute/storage/disk-snapshots.md#how-to-create-a-snapshot) from a boot disk and reuse this snapshot for the image. * File with the ready image. [Upload an image file to a bucket](https://docs.nebius.com/object-storage/objects/upload-download.md#upload-a-single-file) in Object Storage and use this file to create the image. 1. [Install and initialize the Nebius SDK for JavaScript](https://docs.nebius.com/grpc-api/sdk/javascript.md). 2. Make sure that you have enough quotas for images (**Number of images** and **Total storage capacity of all images**). You can view quotas and request changes on the [Administration → Limits → Quotas](https://console.nebius.com/limits/quotas) page of the web console. 3. Prepare the source from which the image inherits configuration and architecture. Choose one of the following types of sources: * Boot disk. [Create a VM](https://docs.nebius.com/compute/virtual-machines/manage.md#create-a-vm), [connect to it](https://docs.nebius.com/compute/virtual-machines/connect.md) and install the software that the image should inherit. The image will be based on the boot disk of this VM and will include the installed software. * Disk snapshot. [Create a snapshot](https://docs.nebius.com/compute/storage/disk-snapshots.md#how-to-create-a-snapshot) from a boot disk and reuse this snapshot for the image. * File with the ready image. [Upload an image file to a bucket](https://docs.nebius.com/object-storage/objects/upload-download.md#upload-a-single-file) in Object Storage and use this file to create the image. ## How to create a custom boot disk image 1. In the [web console](https://console.nebius.com), go to **Storage** → **Disks**. 2. Click **Create resource** and then select **Image**. 3. In the window that opens, specify the name of your image. 4. Select the image source: * **Disk**: Create an image from a disk. Specify the following parameters: * **Project of source disk**: Project that the source disk of your image belongs to. * **Source disk**: Disk used as the source for your image. The image will retain the basic architecture, size and installed software of the source disk. You cannot create images from disks that are attached to a VM that is currently running. Stop the VM before attempting to create an image. * **Snapshot**: Create an image from a disk snapshot. Select the snapshot in the **Source snapshot** field. * **Object Storage file**: Import an image from a bucket. Specify the path to the file that you uploaded to the bucket. For example, `s3://nebius-bucket-test/my-image-file.qcow2`. You can copy and paste this value. To copy it, go to the bucket page. In the line of the uploaded image file, click  → **Copy key**. For information about requirements to the image file, see [Importing your own image into Compute](https://docs.nebius.com/compute/storage/import-image.md#prerequisites). 5. (Optional) Specify the image family. It represents a new or existing label used to group your custom images into a family. If you create a VM or a boot disk from this image family, you will use the latest image in the family. 6. (Optional) Specify the image description. 7. (Optional) Under **Advanced settings**, specify: * **Image family description**: Description of the family that your new image belongs to (if you specified one). * **Recommended platforms**: Comma-separated list of compatible [platforms](https://docs.nebius.com/compute/virtual-machines/types.md) that your image will use by default. * **Unsupported platforms**: Comma-separated list of platforms that your image architecture is *not* compatible with. Must be in the `=` format. For example, `gpu-l40s-d=not supported`. 8. Click **Create image**. The new image will appear on the **Images** tab in **Storage** → **Disks**. 1. If the source disk for your image is attached to a VM that is currently running, stop it: ```bash nebius compute instance stop --id ``` To get the VM ID, run nebius compute instance list. 2. Create an image: ```bash nebius compute image create \ --name \ --source-disk-id \ --parent-id \ --source-disk-snapshot-id \ --source-storage-bucket-name \ --source-storage-object-name \ --image-family \ --description \ --image-family-human-readable \ --recommended-platforms ",,..." \ --unsupported-platforms "=" ``` The CLI command includes the following parameters: * `--name`: Name of your image. * Image sources. Use one of the following: * `--source-disk-id`: ID of the source disk that you want to create an image from. Use together with `--parent-id`: ID of the project that the source disk belongs to. To get both `--parent-id` and `--source-disk-id`, run `nebius compute disk list`. * `--source-disk-snapshot-id`: ID of the [disk snapshot](https://docs.nebius.com/compute/storage/disk-snapshots.md) that you want to create an image from. To get the snapshot ID, run `nebius compute disk-snapshot list`. * `--source-storage-bucket-name` and `--source-storage-object-name`: Bucket and object that contain the source image. You can import an image from a file that meets certain [requirements](https://docs.nebius.com/compute/storage/import-image.md#prerequisites). To do so, upload this file to a bucket. Then, specify the name of this bucket in the `--source-storage-bucket-name` parameter and the name of the file in the `--source-storage-object-name` parameter. ```bash nebius compute image create \ --name \ --source-storage-bucket-name \ --source-storage-object-name ``` * `--image-family` (optional): New or existing label used to group your custom images into a family. If you create a VM or a boot disk from this image family, you will use the latest image in the family. * `--description` (optional): Description of your image. * `--image-family-human-readable` (optional): Description of the family that your new image belongs to (if you specified one). * `--recommended-platforms` (optional): Comma-separated list of compatible [platforms](https://docs.nebius.com/compute/virtual-machines/types.md) that your image will use by default. * `--unsupported-platforms` (optional): Comma-separated list of platforms that your image architecture is *not* compatible with. Must be in the `=` format. For example, `gpu-l40s-d=not supported`. 1. If the source disk for your image is attached to a VM that is currently running, stop it: ```go operation, err := sdk.Services().Compute().V1(). Instance().Stop( ctx, &compute.StopInstanceRequest{ Id: "", }, ) if err != nil { return err } if _, err = operation.Wait(ctx); err != nil { return err } ``` 2. Create an image: ```go familyDescription := "" recommendedPlatforms := []string{} for _, platform := range strings.Split( ",,...", ",", ) { platform = strings.TrimSpace(platform) if platform != "" { recommendedPlatforms = append(recommendedPlatforms, platform) } } unsupportedPlatforms := map[string]string{} for _, platform := range strings.Split( "=", ",", ) { parts := strings.SplitN(platform, "=", 2) if len(parts) == 2 && parts[0] != "" { unsupportedPlatforms[parts[0]] = parts[1] } } imageOperation, err := sdk.Services().Compute().V1(). Image().Create( ctx, &compute.CreateImageRequest{ Metadata: &common.ResourceMetadata{ ParentId: "", Name: "", }, Spec: &compute.ImageSpec{ Description: "", ImageFamily: "", Source: &compute.ImageSpec_SourceDiskId{ SourceDiskId: "", }, ImageFamilyHumanReadable: familyDescription, RecommendedPlatforms: recommendedPlatforms, UnsupportedPlatforms: unsupportedPlatforms, }, }, ) if err != nil { return err } if _, err = imageOperation.Wait(ctx); err != nil { return err } ``` The code includes the following parameters: * `Metadata.ParentId`: ID of the project that the source disk belongs to. * `Metadata.Name`: Name of your image. * `Spec.Description` (optional): Description of your image. * `Spec.ImageFamily` (optional): New or existing label used to group your custom images into a family. * `Spec.Source.SourceDiskId`: ID of the source disk that you want to create an image from. * `Spec.ImageFamilyHumanReadable` (optional): Description of the family that your new image belongs to. * `Spec.RecommendedPlatforms` (optional): Compatible platforms that your image will use by default. * `Spec.UnsupportedPlatforms` (optional): Platforms that your image architecture is not compatible with. The Object Storage example uses `Metadata.Name`, `Spec.Source.SourceStorage.BucketName` and `Spec.Source.SourceStorage.ObjectName`. ```go imageOperation, err = sdk.Services().Compute().V1(). Image().Create( ctx, &compute.CreateImageRequest{ Metadata: &common.ResourceMetadata{ Name: "", }, Spec: &compute.ImageSpec{ Source: &compute.ImageSpec_SourceStorage_{ SourceStorage: &compute.ImageSpec_SourceStorage{ BucketName: "", ObjectName: "", }, }, }, }, ) if err != nil { return err } if _, err = imageOperation.Wait(ctx); err != nil { return err } ``` 1. If the source disk for your image is attached to a VM that is currently running, stop it: ```python instance_service = InstanceServiceClient(sdk) stop_instance_operation = await instance_service.stop( StopInstanceRequest(id=""), ) await stop_instance_operation.wait() ``` 2. Create an image: ```python recommended_platforms = [ platform.strip() for platform in ",,...".split(",") if platform.strip() ] unsupported_platforms = dict( platform.split("=", 1) for platform in "=".split(",") if platform ) image_service = ImageServiceClient(sdk) create_image_operation = await image_service.create( CreateImageRequest( metadata=ResourceMetadata( parent_id="", name="", ), spec=ImageSpec( source_disk_id="", image_family="", description="", image_family_human_readable="", recommended_platforms=recommended_platforms, unsupported_platforms=unsupported_platforms, ), ), ) await create_image_operation.wait() ``` The code includes the following parameters: * `metadata.parent_id`: ID of the project that the source disk belongs to. * `metadata.name`: Name of your image. * `spec.source_disk_id`: ID of the source disk that you want to create an image from. * `spec.image_family` (optional): New or existing label used to group your custom images into a family. * `spec.description` (optional): Description of your image. * `spec.image_family_human_readable` (optional): Description of the family that your new image belongs to. * `spec.recommended_platforms` (optional): Compatible platforms that your image will use by default. * `spec.unsupported_platforms` (optional): Platforms that your image architecture is not compatible with. The Object Storage example uses `metadata.name`, `spec.source_storage.bucket_name` and `spec.source_storage.object_name`. ```python image_service = ImageServiceClient(sdk) create_image_operation = await image_service.create( CreateImageRequest( metadata=ResourceMetadata( name="", ), spec=ImageSpec( source_storage=ImageSpec.SourceStorage( bucket_name="", object_name="", ), ), ), ) await create_image_operation.wait() ``` 1. If the source disk for your image is attached to a VM that is currently running, stop it: ```ts const stopInstanceService = new InstanceService(sdk); const stopInstanceOperation = await stopInstanceService.stop( StopInstanceRequest.create({ id: "", }), ).result; await stopInstanceOperation.wait(); ``` 2. Create an image: ```ts const recommendedPlatforms = ",,..." .split(",") .map((platform) => platform.trim()) .filter(Boolean); const unsupportedPlatforms = Object.fromEntries( "=" .split(",") .filter(Boolean) .map((platform) => platform.split("=", 2)), ); const createImageService = new ImageService(sdk); const createImageOperation = await createImageService.create( CreateImageRequest.create({ metadata: ResourceMetadata.create({ parentId: "", name: "", }), spec: ImageSpec.create({ source: { $case: "sourceDiskId", sourceDiskId: "", }, imageFamily: "", description: "", imageFamilyHumanReadable: "", recommendedPlatforms, unsupportedPlatforms, }), }), ).result; await createImageOperation.wait(); ``` The code includes the following parameters: * `metadata.parentId`: ID of the project that the source disk belongs to. * `metadata.name`: Name of your image. * `spec.source.sourceDiskId`: ID of the source disk that you want to create an image from. * `spec.imageFamily` (optional): New or existing label used to group your custom images into a family. * `spec.description` (optional): Description of your image. * `spec.imageFamilyHumanReadable` (optional): Description of the family that your new image belongs to. * `spec.recommendedPlatforms` (optional): Compatible platforms that your image will use by default. * `spec.unsupportedPlatforms` (optional): Platforms that your image architecture is not compatible with. The Object Storage example uses `metadata.name`, `spec.source.sourceStorage.bucketName` and `spec.source.sourceStorage.objectName`. ```ts const createBucketImageService = new ImageService(sdk); const createBucketImageOperation = await createBucketImageService.create( CreateImageRequest.create({ metadata: ResourceMetadata.create({ name: "", }), spec: ImageSpec.create({ source: { $case: "sourceStorage", sourceStorage: ImageSpec_SourceStorage.create({ bucketName: "", objectName: "", }), }, }), }), ).result; await createBucketImageOperation.wait(); ``` ## How to edit or delete a custom boot disk image 1. In the [web console](https://console.nebius.com), go to **Storage** → **Disks**. 2. Switch to the **Images** tab and open the image you want to access. The **Image overview** tab shows detailed information about the image and the source disk that it's based on. 3. On the image page, switch to the **Settings** tab. 4. Update the image name or click **Delete image** to delete it. * To check the status of your image, run: ```bash nebius compute image get computeimage-e*** ``` To get the image ID, run nebius compute image list. * To edit your image (for example, rename it), run: ```bash nebius compute image update computeimage-e*** ``` For more information about the command parameters, see the [command reference](https://docs.nebius.com/cli/reference/compute/image/update). * To delete your image, run: ```bash nebius compute image delete computeimage-e*** ``` * Check the status of your image: ```go imageDetails, err := sdk.Services().Compute().V1(). Image().Get( ctx, &compute.GetImageRequest{ Id: "computeimage-e***", }, ) if err != nil { return err } fmt.Println(imageDetails) ``` * Edit your image, for example, rename it: ```go imageForUpdate, err := sdk.Services().Compute().V1(). Image().Get( ctx, &compute.GetImageRequest{ Id: "computeimage-e***", }, ) if err != nil { return err } if imageForUpdate.GetSpec() == nil { return errors.New("image spec is missing") } imageOperation, err = sdk.Services().Compute().V1(). Image().Update( ctx, &compute.UpdateImageRequest{ Metadata: imageForUpdate.Metadata, Spec: imageForUpdate.Spec, }, ) if err != nil { return err } if _, err = imageOperation.Wait(ctx); err != nil { return err } ``` * Delete your image: ```go deleteImageOperation, err := sdk.Services().Compute().V1(). Image().Delete( ctx, &compute.DeleteImageRequest{ Id: "computeimage-e***", }, ) if err != nil { return err } if _, err = deleteImageOperation.Wait(ctx); err != nil { return err } ``` * Check the status of your image: ```python image_service = ImageServiceClient(sdk) image = await image_service.get( GetImageRequest(id="computeimage-e***"), ) print(image) ``` * Edit your image, for example, rename it: ```python image_service = ImageServiceClient(sdk) image = await image_service.get( GetImageRequest(id="computeimage-e***"), ) if image.spec is None: raise ValueError("image spec is missing") update_image_operation = await image_service.update( UpdateImageRequest( metadata=image.metadata, spec=image.spec, ), ) await update_image_operation.wait() ``` * Delete your image: ```python image_service = ImageServiceClient(sdk) delete_image_operation = await image_service.delete( DeleteImageRequest(id="computeimage-e***"), ) await delete_image_operation.wait() ``` * Check the status of your image: ```ts const getImageService = new ImageService(sdk); const imageDetails = await getImageService.get( GetImageRequest.create({ id: "computeimage-e***", }), ); console.log(imageDetails); ``` * Edit your image, for example, rename it: ```ts const updateImageService = new ImageService(sdk); const imageForUpdate = await updateImageService.get( GetImageRequest.create({ id: "computeimage-e***", }), ); if (!imageForUpdate.spec) { throw new Error("image spec is missing"); } const updateImageOperation = await updateImageService.update( UpdateImageRequest.create({ metadata: imageForUpdate.metadata, spec: imageForUpdate.spec, }), ).result; await updateImageOperation.wait(); ``` * Delete your image: ```ts const deleteImageService = new ImageService(sdk); const deleteImageOperation = await deleteImageService.delete( DeleteImageRequest.create({ id: "computeimage-e***", }), ).result; await deleteImageOperation.wait(); ``` ## How to create a VM from a custom image After your custom boot disk image is ready, you can deploy a VM from it or create a boot disk based on this image. To create a VM from a custom image: 1. In the [web console](https://console.nebius.com), go to **Storage** → **Disks** → **Images**. 2. Next to the image, click  → **Create virtual machine**. 3. [Configure and create the VM](https://docs.nebius.com/compute/virtual-machines/manage.md#create-a-vm). You can also select a custom image on the VM creation page. To do that, click in the **Boot disk** section and select your custom image or image family in **Image configuration**. 1. Create a boot disk based on a custom image: ```bash nebius compute disk create \ --name \ --type network_ \ --size-gibibytes \ --block-size-bytes \ --source-image-id computeimage-*** ``` To get the image ID, run nebius compute image list. 2. [Create a VM](https://docs.nebius.com/compute/virtual-machines/manage.md#create-a-vm) with the new disk. Use the ID of the boot disk created earlier with the `--boot-disk-existing-disk-id` parameter. 1. Create a boot disk based on a custom image: ```go // One of compute.DiskSpec_NETWORK_SSD, // compute.DiskSpec_NETWORK_SSD_NON_REPLICATED, // or compute.DiskSpec_NETWORK_SSD_IO_M3. diskType := compute.DiskSpec_NETWORK_SSD diskOperation, err := sdk.Services().Compute().V1(). Disk().Create( ctx, &compute.CreateDiskRequest{ Metadata: &common.ResourceMetadata{ Name: "", }, Spec: &compute.DiskSpec{ Size: &compute.DiskSpec_SizeGibibytes{ SizeGibibytes: , }, BlockSizeBytes: , Type: diskType, Source: &compute.DiskSpec_SourceImageId{ SourceImageId: "computeimage-***", }, }, }, ) if err != nil { return err } if _, err = diskOperation.Wait(ctx); err != nil { return err } ``` 2. [Create a VM](https://docs.nebius.com/compute/virtual-machines/manage.md#create-a-vm) with the new disk. Use the ID of the boot disk created earlier. 1. Create a boot disk based on a custom image: ```python # One of DiskSpec.DiskType.NETWORK_SSD, # DiskSpec.DiskType.NETWORK_SSD_NON_REPLICATED, # or DiskSpec.DiskType.NETWORK_SSD_IO_M3. disk_type = DiskSpec.DiskType.NETWORK_SSD disk_service = DiskServiceClient(sdk) create_disk_operation = await disk_service.create( CreateDiskRequest( metadata=ResourceMetadata( name="", ), spec=DiskSpec( block_size_bytes=, type=disk_type, source_image_id="computeimage-***", size_gibibytes=, ), ), ) await create_disk_operation.wait() ``` 2. [Create a VM](https://docs.nebius.com/compute/virtual-machines/manage.md#create-a-vm) with the new disk. Use the ID of the boot disk created earlier. 1. Create a boot disk based on a custom image: ```ts // One of DiskSpec_DiskType.NETWORK_SSD, // DiskSpec_DiskType.NETWORK_SSD_NON_REPLICATED, // or DiskSpec_DiskType.NETWORK_SSD_IO_M3. const imageDiskType = DiskSpec_DiskType.NETWORK_SSD; const createDiskFromImageService = new DiskService(sdk); const createDiskFromImageOperation = await createDiskFromImageService.create( CreateDiskRequest.create({ metadata: ResourceMetadata.create({ name: "", }), spec: DiskSpec.create({ blockSizeBytes: , type: imageDiskType, source: { $case: "sourceImageId", sourceImageId: "computeimage-***", }, size: { $case: "sizeGibibytes", sizeGibibytes: , }, }), }), ).result; await createDiskFromImageOperation.wait(); ``` 2. [Create a VM](https://docs.nebius.com/compute/virtual-machines/manage.md#create-a-vm) with the new disk. Use the ID of the boot disk created earlier. # Creating boot disk images with Packer Source: https://docs.nebius.com/compute/storage/packer.md You can create custom boot disk images based on existing images by using [Packer](https://developer.hashicorp.com/packer) and the [Nebius Packer plug-in](https://github.com/nebius/packer-plugin-nebius/blob/main/README.md). The Nebius Packer plug-in creates a temporary virtual machine (VM) from a base image, connects to it over SSH, runs provisioners and then creates a new boot disk image. Use this workflow to: * Pre-install packages and system dependencies * Prepare versioned images for repeated VM creation * Standardize environments across teams or workloads ## Before you start 1. Install [Packer](https://developer.hashicorp.com/packer/downloads). 2. Make sure your project has sufficient [quotas](https://docs.nebius.com/overview/quotas.md) for image creation: * Number of images * Total storage capacity of all images 3. Set up authentication by using one of the following methods. * **Service account** 1. [Create a service account](https://docs.nebius.com/iam/service-accounts/manage.md) and [generate a key pair](https://docs.nebius.com/iam/service-accounts/authorized-keys.md#create-a-key-pair). The key pair is saved to a JSON file, for example, `~/.nebius/_credentials.json`. 2. Open the file and copy the value of the `private_key` field. 3. Save the key to the `private.pem` file: ```text -----BEGIN PRIVATE KEY----- ... -----END PRIVATE KEY----- ``` 4. Use the values from the JSON file in your Packer configuration. * **Access token** Generate an access token: ```bash nebius iam get-access-token ``` An access token is valid for 12 hours. After it expires, create a new one. ## Steps ### Install the Nebius Packer plug-in 1. Create the `config.pkr.hcl` file and add the Nebius plug-in configuration: ```hcl packer { required_plugins { nebius = { source = "github.com/nebius/nebius" version = ">= 0.0.4" } } } ``` 2. Initialize the plug-in in the directory that contains your Packer configuration files: ```bash packer init . ``` ### Build the disk image The Nebius image builder creates a VM from a base image, provisions it over SSH and publishes a new image. 1. Create the `build.pkr.hcl` file and add the `nebius-image` source to it: ```hcl source "nebius-image" "ubuntu2404" { communicator = "ssh" ssh_username = "ubuntu" # Service account credentials used for image creation service_account { private_key_file = "./private.pem" public_key_id = "" account_id = "" } # Alternatively, use an access token # token = # Boot disk configuration for the temporary VM disk { size_gibibytes = 60 } # Source image used to create the temporary VM base_image { family = "ubuntu24.04-driverless" } # Network configuration for the temporary VM network { subnet_id = "" associate_public_ip_address = true } # Compute resources for the temporary VM instance { platform = "cpu-d3" preset = "16vcpu-64gb" } # Parameters of the resulting image image { name = "ubuntu24.04-131-0.0.1" version = "0.0.1" image_family = "ubuntu24.04-131" cpu_architecture = "amd64" image_family_human_readable = "Ubuntu 24.04 CUDA 13.1 Hackathon" } # Project where the image will be created parent_id = "" } ``` The `nebius-image` source has the following parameters: **General parameters** * `communicator` (optional): Specifies how Packer connects to the VM. Supported value: `ssh` (default). * `parent_id`: ID of the project where the resulting image will be created. * `ssh_username`: Username used to connect to the VM. **Authentication** * `service_account.private_key_file`: Path to the private key file. * `service_account.public_key_id`: ID of the public key. * `service_account.account_id`: Service account ID. * `token`: Access token used for authentication. Use this as an alternative to `service_account`. **Disk configuration** * `disk.size_gibibytes`: Size of the disk in GiB. **Base image** * `base_image.family`: Image family name. * `base_image.id`: Specific image ID. **Network** * `network.subnet_id` (optional): ID of an existing subnet that will be used to create a VM. If not provided, the plug-in attempts to find the project's default network. * `network.associate_public_ip_address` (optional): Assigns a public IP address. Use a public IP if your build environment connects directly via SSH. **VM configuration** * `instance.platform`: VM [platform](https://docs.nebius.com/compute/virtual-machines/types.md). * `instance.preset`: VM platform preset (number of GPUs and vCPUs, RAM size). **Output image configuration** * `image.name`: Image name. * `image.version` (optional): Image version. * `image.image_family` (optional): Image family identifier. * `image.image_family_human_readable` (optional): Display name for the image family. * `image.cpu_architecture` (optional): CPU architecture. 2. Add the build block to the `build.pkr.hcl` file: ```hcl build { sources = ["source.nebius-image.ubuntu2404"] provisioner "file" { # Path to a local script in your project source = "some-local-file.txt" destination = "/tmp/helloworld.txt" } provisioner "shell" { inline = [ "cd /tmp", "echo Installing hello world text", "sudo mv /tmp/helloworld.txt /root", "echo Resetting cloud-init and caches", "sudo apt clean", "sudo uv cache clean", "sudo cloud-init clean --logs", "sudo sync", ] } } ``` 3. From the directory with the configuration files, run: ```bash packer init . packer build build.pkr.hcl ``` ### Check the image 1. In the [web console](https://console.nebius.com), go to  **Storage** → **Disks**. 2. Go to the **Images** tab and locate your image. ### Example: CUDA® 13.1 image The following example builds an image with CUDA 13.1 from a driverless image. It uses a single configuration file that includes both the plug-in and build configuration. ```hcl packer { required_plugins { nebius = { version = ">= 0.0.4" source = "github.com/nebius/nebius" } } } source "nebius-image" "ubuntu2404-cu131" { communicator = "ssh" ssh_username = "ubuntu" service_account { private_key_file = "./private.pem" public_key_id = "" account_id = "" } disk { size_gibibytes = 60 } base_image { family = "ubuntu24.04-driverless" } network { associate_public_ip_address = true } instance { platform = "cpu-d3" preset = "16vcpu-64gb" } image { name = "ubuntu24.04-131-0.0.1" version = "0.0.1" image_family = "ubuntu24.04-131" cpu_architecture = "amd64" image_family_human_readable = "Ubuntu 24.04 CUDA 13.1 Hackathon" } parent_id = "project-..." } build { sources = ["source.nebius-image.ubuntu2404-cu131"] provisioner "file" { source = "guest.config" destination = "/tmp/guest.config" } provisioner "file" { source = "install-gpu-cuda13.1-ubuntu24.04.sh" destination = "/tmp/install-gpu-cuda13.1-ubuntu24.04.sh" } provisioner "shell" { inline = [ "cd /tmp", "echo Installing cuda 13.1 et al", "sudo bash /tmp/install-gpu-cuda13.1-ubuntu24.04.sh", "echo Resetting cloud-init and caches", "sudo apt clean", "sudo uv cache clean", "sudo cloud-init clean --logs", "sudo sync", ] } } ``` The `file` and `shell` provisioners are used to copy files to the VM and execute commands during the build. Create your own scripts depending on the software and configuration you want to include in the image. # Importing your own image into Compute Source: https://docs.nebius.com/compute/storage/import-image.md You can import an image file into Nebius AI Cloud, and create boot disks and virtual machines (VMs) based on your custom image. To make an import, upload an image file to a bucket in Object Storage and create an image in Compute. ## Prerequisites 1. Make sure you are in a [group](https://docs.nebius.com/iam/authorization/groups/index.md) that has the `admin` role within your tenant or project; for example, the default `admins` group. You can check this in the [Administration → IAM](https://console.nebius.com/iam) section of the web console. 2. Prepare an image that meets the following requirements: * BIOS mode * AMD64 or ARM64 architecture * `.vmdk`, `.vhd`, `.raw` or `.qcow2` format for the image file 1. [Install and configure](https://docs.nebius.com/cli/install.md) the Nebius AI Cloud CLI. 2. Make sure you are in a [group](https://docs.nebius.com/iam/authorization/groups/index.md) that has the `admin` role within your tenant or project; for example, the default `admins` group. You can check this in the [Administration → IAM](https://console.nebius.com/iam) section of the web console. 3. Prepare an image that meets the following requirements: * BIOS mode * AMD64 or ARM64 architecture * `.vmdk`, `.vhd`, `.raw` or `.qcow2` format for the image file 1. [Install and initialize the Nebius SDK for Go](https://docs.nebius.com/grpc-api/sdk/go.md). 2. Make sure you are in a [group](https://docs.nebius.com/iam/authorization/groups/index.md) that has the `admin` role within your tenant or project; for example, the default `admins` group. You can check this in the [Administration → IAM](https://console.nebius.com/iam) section of the web console. 3. Prepare an image that meets the following requirements: * BIOS mode * AMD64 or ARM64 architecture * `.vmdk`, `.vhd`, `.raw` or `.qcow2` format for the image file 1. [Install and initialize the Nebius SDK for Python](https://docs.nebius.com/grpc-api/sdk/python.md). 2. Make sure you are in a [group](https://docs.nebius.com/iam/authorization/groups/index.md) that has the `admin` role within your tenant or project; for example, the default `admins` group. You can check this in the [Administration → IAM](https://console.nebius.com/iam) section of the web console. 3. Prepare an image that meets the following requirements: * BIOS mode * AMD64 or ARM64 architecture * `.vmdk`, `.vhd`, `.raw` or `.qcow2` format for the image file 1. [Install and initialize the Nebius SDK for JavaScript](https://docs.nebius.com/grpc-api/sdk/javascript.md). 2. Make sure you are in a [group](https://docs.nebius.com/iam/authorization/groups/index.md) that has the `admin` role within your tenant or project; for example, the default `admins` group. You can check this in the [Administration → IAM](https://console.nebius.com/iam) section of the web console. 3. Prepare an image that meets the following requirements: * BIOS mode * AMD64 or ARM64 architecture * `.vmdk`, `.vhd`, `.raw` or `.qcow2` format for the image file ## How to import an image and create a boot disk and a VM 1. [Create an Object Storage bucket](https://docs.nebius.com/object-storage/buckets/manage.md#how-to-create-buckets). The bucket, image and VM should be in the same region. 2. [Upload](https://docs.nebius.com/object-storage/objects/upload-download.md#upload-a-single-file) your image file to this bucket. 3. Create an image based on the uploaded file: 1. Copy the key of the file object: 1. In the [web console](https://console.nebius.com), go to  **Storage** → **Object Storage**. 2. Open the bucket page. 3. In the line of the uploaded object, click  → **Copy key**. 2. Create the image in Nebius AI Cloud: 1. In the web console, go to  **Storage** → **Disks**. 2. Click **Create resource** → **Image**. 3. In the window that opens, specify the name of your image. 4. In the **Source** field, select **Object Storage file**. 5. In the **Object Storage file** field, specify the copied object key. The value must meet the `s3:///` format. For example, `s3://nebius-bucket-test/my-image-file.qcow2`. 6. Click **Create image**. The new image appears on the **Images** tab in  **Storage** → **Disks**. ```bash nebius compute image create \ --name \ --source-storage-bucket-name \ --source-storage-object-name ``` For example, if the object of the image file has the `s3://nebius-bucket-test/my-image-file.qcow2` key: * `--source-storage-bucket-name` should be `nebius-bucket-test` * `--source-storage-object-name` should be `my-image-file.qcow2` By default, the AMD64 architecture is used for the image. If you want to use ARM64, add the `--cpu-architecture arm64` parameter to the command above. ```go imageOperation, err = sdk.Services().Compute().V1(). Image().Create( ctx, &compute.CreateImageRequest{ Metadata: &common.ResourceMetadata{ Name: "", }, Spec: &compute.ImageSpec{ Source: &compute.ImageSpec_SourceStorage_{ SourceStorage: &compute.ImageSpec_SourceStorage{ BucketName: "", ObjectName: "", }, }, }, }, ) if err != nil { return err } if _, err = imageOperation.Wait(ctx); err != nil { return err } ``` For example, if the object of the image file has the `s3://nebius-bucket-test/my-image-file.qcow2` key: * `BucketName` should be `nebius-bucket-test` * `ObjectName` should be `my-image-file.qcow2` ```python image_service = ImageServiceClient(sdk) create_image_operation = await image_service.create( CreateImageRequest( metadata=ResourceMetadata( name="", ), spec=ImageSpec( source_storage=ImageSpec.SourceStorage( bucket_name="", object_name="", ), ), ), ) await create_image_operation.wait() ``` For example, if the object of the image file has the `s3://nebius-bucket-test/my-image-file.qcow2` key: * `bucket_name` should be `nebius-bucket-test` * `object_name` should be `my-image-file.qcow2` ```ts const createBucketImageService = new ImageService(sdk); const createBucketImageOperation = await createBucketImageService.create( CreateImageRequest.create({ metadata: ResourceMetadata.create({ name: "", }), spec: ImageSpec.create({ source: { $case: "sourceStorage", sourceStorage: ImageSpec_SourceStorage.create({ bucketName: "", objectName: "", }), }, }), }), ).result; await createBucketImageOperation.wait(); ``` For example, if the object of the image file has the `s3://nebius-bucket-test/my-image-file.qcow2` key: * `bucketName` should be `nebius-bucket-test` * `objectName` should be `my-image-file.qcow2` 4. When the image is ready, [create a boot disk](https://docs.nebius.com/compute/storage/manage.md#how-to-create-a-disk) with it. 5. [Create a VM](https://docs.nebius.com/compute/virtual-machines/manage.md#create-a-vm) with the new boot disk. 6. (Optional) If you don't need the image file in the bucket, delete it. The image in Compute won't use it anymore. # Recommendations for configuring custom images in Compute Source: https://docs.nebius.com/compute/storage/image-recommendations.md If you work with [custom images](https://docs.nebius.com/compute/storage/custom-disk-images.md), we recommend optimizing them so your boot disks and virtual machines (VMs) work with higher productivity and speed. When you create a VM based on a custom image, this VM doesn't include some of the settings that a VM based on a public image includes. You can add these settings to your custom-image VM and optimize it. The additional settings aren't required for every custom image, but we recommend them for at least production-oriented images unless you have workload-specific reasons for not using these settings. ## Install the monitoring agent by Nebius AI Cloud The [monitoring agent](https://docs.nebius.com/observability/agents/monitoring-agent.md) is installed by default on VMs with public images. If you use a custom image, install the agent to collect and view [metrics for the VM](https://docs.nebius.com/compute/monitoring/virtual-machines.md). To install the monitoring agent, [connect to the VM](https://docs.nebius.com/compute/virtual-machines/connect.md#connect-to-the-vm-by-using-ssh) and then run the following commands: ```bash sudo curl https://dr.nebius.cloud/public.gpg -o /etc/apt/keyrings/nebius-public.gpg.pub echo deb [signed-by=/etc/apt/keyrings/nebius-public.gpg.pub] https://dr.nebius.cloud/ stable main | sudo tee /etc/apt/sources.list.d/nebius-public.list sudo apt-get update sudo apt-get install -y nebius-observability-agent nebius-observability-agent-updater ``` ## Collect serial logs To collect and view [serial logs](https://docs.nebius.com/compute/monitoring/serial-logs.md) of a VM on a custom image, configure the VM's [GRUB](https://en.wikipedia.org/wiki/GNU_GRUB) to initialize and use a serial port. GRUB is a boot loader package that boots an operating system and kernel configuration. To configure GRUB for Ubuntu-based disk images: 1. [Connect to the VM](https://docs.nebius.com/compute/virtual-machines/connect.md#connect-to-the-vm-by-using-ssh). 2. In the `/etc/default/grub` file, add the following line: ```text GRUB_CMDLINE_LINUX="console=tty1 console=ttyS0" ``` 3. Update GRUB: ```bash update-grub ``` 4. Reboot the VM: disconnect from it, and [stop and start it](https://docs.nebius.com/compute/virtual-machines/stop-start.md#how-to-stop-and-start-vms-manually). ## Change sysctl settings Apply the recommended `sysctl` settings to improve the networking and kernel characteristics of the VM. To do so, connect to the VM and update the following settings in two files: * File `/etc/sysctl.d/30-network.conf` ```text # Decrease default tcp keepalive time net.ipv4.tcp_keepalive_time = 120 net.ipv4.tcp_keepalive_intvl = 60 net.ipv4.tcp_keepalive_probes = 4 # Make conntrack more liberal to tcp out of window packets to prevent # spurious connection resets when masquerading is in use net.netfilter.nf_conntrack_tcp_be_liberal = 1 ``` * File `/etc/sysctl.d/90-kernel.conf` ```text kernel.panic = 10 kernel.printk = 7 4 1 7 ``` ## Adjust the virtiofs settings To speed up reading from volumes and writing to them, adjust the `virtiofs` settings. Connect to the VM and run the Bash script below. The script increases the `read_ahead_kb` value to improve the performance of the VM volumes. ```bash #!/usr/bin/env bash set -euo pipefail install -d /usr/local/bin install -d /etc/udev/rules.d cat > /usr/local/bin/tune_virtiofs_bdi.sh <<'EOF' #!/usr/bin/env bash kernel="${1:-}" while read -r dev on mp type fs opts; do dev=$(/bin/mountpoint -d "$mp") if [[ "$fs" == "virtiofs" ]]; then if [[ "$kernel" == "$dev" ]]; then exit 0 fi fi done < <(mount | grep virtiofs) exit 1 EOF chmod +x /usr/local/bin/tune_virtiofs_bdi.sh cat > /etc/udev/rules.d/99-virtiofs.rules <<'EOF' SUBSYSTEM=="bdi", ACTION=="add", PROGRAM="/usr/local/bin/tune_virtiofs_bdi.sh $kernel", ATTR{read_ahead_kb}="8192" EOF ``` ## Enable failure reporting by using pvpanic The `pvpanic` tool allows the guest OS kernel to report panic and crash events to the hypervisor. This helps with failure detection and troubleshooting. To start using `pvpanic` on Ubuntu, connect to the VM and install the package: ```bash sudo apt-get install -y linux-image-generic ``` # Managing disk snapshots in Compute Source: https://docs.nebius.com/compute/storage/disk-snapshots.md A *disk snapshot* captures a point-in-time copy of a disk. This is an instant disk backup that allows you to: * Clone and recover a certain state of the disk. * Eliminate data loss risks. * Prevent accidental deletion, corruption and security incidents. * Make a copy of a disk before risky operations, such as software upgrades, patches or configuration changes, so you can roll back in case of issues. * Fulfill compliance requirements for immutable system versions, if applicable. To clone a disk state, [create a snapshot](https://docs.nebius.com/compute/storage/disk-snapshots.md#how-to-create-a-snapshot). To restore a disk state, [create a new disk from a snapshot](https://docs.nebius.com/compute/storage/disk-snapshots.md#how-to-create-a-disk-from-a-snapshot). Snapshots support both boot and additional disks. They also support all [disk types](https://docs.nebius.com/compute/storage/types.md#disk-types): SSD, SSD Non-replicated and SSD IO M3. Every snapshot is only available in the project where it was created. Therefore, you can only work with snapshots and disks within the project. Nebius AI Cloud charges for a complete copy of a disk and applies separate pricing for snapshots. For more information, see [Compute pricing](https://docs.nebius.com/compute/resources/pricing.md#disk-snapshots). ## Prerequisites Make sure you are in a [group](https://docs.nebius.com/iam/authorization/groups/index.md) that has at least the `editor` role within your tenant or project; for example, the default `editors` group. You can check this in the [Administration → IAM](https://console.nebius.com/iam) section of the web console. * [Install and configure](https://docs.nebius.com/cli/install.md) the Nebius AI Cloud CLI. * Make sure you are in a [group](https://docs.nebius.com/iam/authorization/groups/index.md) that has at least the `editor` role within your tenant or project; for example, the default `editors` group. You can check this in the [Administration → IAM](https://console.nebius.com/iam) section of the web console. * [Install and initialize the Nebius SDK for Go](https://docs.nebius.com/grpc-api/sdk/go.md). * Make sure you are in a [group](https://docs.nebius.com/iam/authorization/groups/index.md) that has at least the `editor` role within your tenant or project; for example, the default `editors` group. You can check this in the [Administration → IAM](https://console.nebius.com/iam) section of the web console. * [Install and initialize the Nebius SDK for Python](https://docs.nebius.com/grpc-api/sdk/python.md). * Make sure you are in a [group](https://docs.nebius.com/iam/authorization/groups/index.md) that has at least the `editor` role within your tenant or project; for example, the default `editors` group. You can check this in the [Administration → IAM](https://console.nebius.com/iam) section of the web console. * [Install and initialize the Nebius SDK for JavaScript](https://docs.nebius.com/grpc-api/sdk/javascript.md). * Make sure you are in a [group](https://docs.nebius.com/iam/authorization/groups/index.md) that has at least the `editor` role within your tenant or project; for example, the default `editors` group. You can check this in the [Administration → IAM](https://console.nebius.com/iam) section of the web console. ## How to create a snapshot To create a snapshot, you don't need to stop a virtual machine. 1. In the sidebar, go to  **Storage** → **Disks**. 2. In the list of disks, find the disk that you want to create a snapshot for. 3. In the line of the required disk, click  → **Create snapshot**. 4. In the window that opens, specify the name and optionally the description of the snapshot. The ID of the selected disk is prefilled in the **Source disk** field. 5. Click **Create snapshot**. Once you create a snapshot, it appears on the disk page. There, you can find all snapshots created for a given disk. Run the following command: ```bash nebius compute disk-snapshot create \ --name \ --description "" \ --source-disk-id ``` The command contains the following parameters: * `--name`: Snapshot name. * `--description` (optional): Snapshot description. * `--source-disk-id`: ID of the disk that you want to create a snapshot for. To get the disk ID, run `nebius compute disk list`. ```go snapshotOperation, err := sdk.Services().Compute().V1(). DiskSnapshot().Create( ctx, &compute.CreateDiskSnapshotRequest{ Metadata: &common.ResourceMetadata{ Name: "", }, Spec: &compute.DiskSnapshotSpec{ SourceDiskId: "", Description: "", }, }, ) if err != nil { return err } if _, err = snapshotOperation.Wait(ctx); err != nil { return err } ``` The code contains the following parameters: * `Metadata.Name`: Snapshot name. * `Spec.SourceDiskId`: ID of the disk that you want to create a snapshot for. * `Spec.Description` (optional): Snapshot description. ```python snapshot_service = DiskSnapshotServiceClient(sdk) create_snapshot_operation = await snapshot_service.create( CreateDiskSnapshotRequest( metadata=ResourceMetadata( name="", ), spec=DiskSnapshotSpec( source_disk_id="", description="", ), ), ) await create_snapshot_operation.wait() ``` The code contains the following parameters: * `metadata.name`: Snapshot name. * `spec.source_disk_id`: ID of the disk that you want to create a snapshot for. * `spec.description` (optional): Snapshot description. ```ts const snapshotService = new DiskSnapshotService(sdk); const createSnapshotOperation = await snapshotService.create( CreateDiskSnapshotRequest.create({ metadata: ResourceMetadata.create({ name: "", }), spec: DiskSnapshotSpec.create({ sourceDiskId: "", description: "", }), }), ).result; await createSnapshotOperation.wait(); ``` The code contains the following parameters: * `metadata.name`: Snapshot name. * `spec.sourceDiskId`: ID of the disk that you want to create a snapshot for. * `spec.description` (optional): Snapshot description. ## How to create a disk from a snapshot After you [prepare a snapshot](https://docs.nebius.com/compute/storage/disk-snapshots.md#how-to-create-a-snapshot), you can create a disk based on this snapshot. Thus, you restore the needed disk state with data integrity verified. To create a disk from a snapshot: 1. In the sidebar, go to  **Storage** → **Disks** → **Snapshots**. 2. In the line of the required snapshot, click  → **Create disk**. 3. On the disk creation page that opens, check the **Disk source type** and **Snapshot** fields. They are prefilled: * **Disk source type**: Snapshot. * **Snapshot**: ID of the selected snapshot. 4. Set other needed [fields for the disk](https://docs.nebius.com/compute/storage/manage.md#how-to-create-a-disk) and click **Create disk**. Run the following command: ```bash nebius compute disk create \ --name \ --type network_ \ --size-gibibytes \ --block-size-bytes \ --source-snapshot-id ``` To get the snapshot ID, run `nebius compute disk-snapshot list`. ```go // One of compute.DiskSpec_NETWORK_SSD, // compute.DiskSpec_NETWORK_SSD_NON_REPLICATED, // or compute.DiskSpec_NETWORK_SSD_IO_M3. diskType := compute.DiskSpec_NETWORK_SSD diskOperation, err := sdk.Services().Compute().V1(). Disk().Create( ctx, &compute.CreateDiskRequest{ Metadata: &common.ResourceMetadata{ Name: "", }, Spec: &compute.DiskSpec{ Size: &compute.DiskSpec_SizeGibibytes{ SizeGibibytes: , }, BlockSizeBytes: , Type: diskType, Source: &compute.DiskSpec_SourceSnapshotId{ SourceSnapshotId: "", }, }, }, ) if err != nil { return err } if _, err = diskOperation.Wait(ctx); err != nil { return err } ``` The code contains the following parameters: * `diskType`: [Disk type](https://docs.nebius.com/compute/storage/types.md#network-ssd-disks). * `Metadata.Name`: Disk name. * `Spec.Size.SizeGibibytes`: Disk size in gibibytes. * `Spec.BlockSizeBytes`: Block size in bytes. * `Spec.Type`: Disk type set by `diskType`. * `Spec.Source.SourceSnapshotId`: ID of the snapshot to create the disk from. ```python # One of DiskSpec.DiskType.NETWORK_SSD, # DiskSpec.DiskType.NETWORK_SSD_NON_REPLICATED, # or DiskSpec.DiskType.NETWORK_SSD_IO_M3. disk_type = DiskSpec.DiskType.NETWORK_SSD disk_service = DiskServiceClient(sdk) create_disk_operation = await disk_service.create( CreateDiskRequest( metadata=ResourceMetadata( name="", ), spec=DiskSpec( block_size_bytes=, type=disk_type, source_snapshot_id="", size_gibibytes=, ), ), ) await create_disk_operation.wait() ``` The code contains the following parameters: * `disk_type`: [Disk type](https://docs.nebius.com/compute/storage/types.md#network-ssd-disks). * `metadata.name`: Disk name. * `spec.block_size_bytes`: Block size in bytes. * `spec.type`: Disk type set by `disk_type`. * `spec.source_snapshot_id`: ID of the snapshot to create the disk from. * `spec.size_gibibytes`: Disk size in gibibytes. ```ts // One of DiskSpec_DiskType.NETWORK_SSD, // DiskSpec_DiskType.NETWORK_SSD_NON_REPLICATED, // or DiskSpec_DiskType.NETWORK_SSD_IO_M3. const diskType = DiskSpec_DiskType.NETWORK_SSD; const diskService = new DiskService(sdk); const createDiskOperation = await diskService.create( CreateDiskRequest.create({ metadata: ResourceMetadata.create({ name: "", }), spec: DiskSpec.create({ blockSizeBytes: , type: diskType, source: { $case: "sourceSnapshotId", sourceSnapshotId: "", }, size: { $case: "sizeGibibytes", sizeGibibytes: , }, }), }), ).result; await createDiskOperation.wait(); ``` The code contains the following parameters: * `diskType`: [Disk type](https://docs.nebius.com/compute/storage/types.md#network-ssd-disks). * `metadata.name`: Disk name. * `spec.blockSizeBytes`: Block size in bytes. * `spec.type`: Disk type set by `diskType`. * `spec.source.sourceSnapshotId`: ID of the snapshot to create the disk from. * `spec.size.sizeGibibytes`: Disk size in gibibytes. After you create the disk, you can [create a virtual machine](https://docs.nebius.com/compute/virtual-machines/manage.md#create-a-vm) with it. ## How to update a snapshot In the web console, you can only change the snapshot name. In the CLI, you can change the snapshot name and description. 1. In the sidebar, go to  **Storage** → **Disks** → **Snapshots**. 2. In the line of the required snapshot, click  → **Settings**. 3. On the page of the snapshot settings that opens, update the snapshot name and click **Save changes**. Run the following command: ```bash nebius compute disk-snapshot update \ --id \ --name \ --description "" ``` In the command, specify the ID of the snapshot that you want to update. To get the snapshot ID, run `nebius compute disk-snapshot list`. ```go snapshotForUpdate, err := sdk.Services().Compute().V1(). DiskSnapshot().Get( ctx, &compute.GetDiskSnapshotRequest{ Id: "", }, ) if err != nil { return err } if snapshotForUpdate.GetMetadata() == nil || snapshotForUpdate.GetSpec() == nil { return errors.New("snapshot metadata or spec is missing") } snapshotForUpdate.Metadata.Name = "" snapshotForUpdate.Spec.Description = "" snapshotOperation, err = sdk.Services().Compute().V1(). DiskSnapshot().Update( ctx, &compute.UpdateDiskSnapshotRequest{ Metadata: snapshotForUpdate.Metadata, Spec: snapshotForUpdate.Spec, }, ) if err != nil { return err } if _, err = snapshotOperation.Wait(ctx); err != nil { return err } ``` The code contains the following parameters: * `GetDiskSnapshotRequest.Id`: ID of the snapshot that you want to update. * `Metadata.Name`: New snapshot name. * `Spec.Description`: New snapshot description. ```python snapshot_service = DiskSnapshotServiceClient(sdk) snapshot = await snapshot_service.get( GetDiskSnapshotRequest(id=""), ) if snapshot.metadata is None or snapshot.spec is None: raise ValueError("snapshot metadata or spec is missing") snapshot.metadata.name = "" snapshot.spec.description = "" update_snapshot_operation = await snapshot_service.update( UpdateDiskSnapshotRequest( metadata=snapshot.metadata, spec=snapshot.spec, ), ) await update_snapshot_operation.wait() ``` The code contains the following parameters: * `GetDiskSnapshotRequest.id`: ID of the snapshot that you want to update. * `metadata.name`: New snapshot name. * `spec.description`: New snapshot description. ```ts const updateSnapshotService = new DiskSnapshotService(sdk); const snapshotForUpdate = await updateSnapshotService.get( GetDiskSnapshotRequest.create({ id: "", }), ); if (!snapshotForUpdate.metadata || !snapshotForUpdate.spec) { throw new Error("snapshot metadata or spec is missing"); } snapshotForUpdate.metadata.name = ""; snapshotForUpdate.spec.description = ""; const updateSnapshotOperation = await updateSnapshotService.update( UpdateDiskSnapshotRequest.create({ metadata: snapshotForUpdate.metadata, spec: snapshotForUpdate.spec, }), ).result; await updateSnapshotOperation.wait(); ``` The code contains the following parameters: * `GetDiskSnapshotRequest.id`: ID of the snapshot that you want to update. * `metadata.name`: New snapshot name. * `spec.description`: New snapshot description. ## How to delete a snapshot 1. In the sidebar, go to  **Storage** → **Disks** → **Snapshots**. 2. In the line of the required snapshot, click  → **Delete**. 3. In the window that opens, confirm the deletion. Run the following command: ```bash nebius compute disk-snapshot delete ``` To get the snapshot ID, run `nebius compute disk-snapshot list`. ```go snapshotOperation, err = sdk.Services().Compute().V1(). DiskSnapshot().Delete( ctx, &compute.DeleteDiskSnapshotRequest{ Id: "", }, ) if err != nil { return err } if _, err = snapshotOperation.Wait(ctx); err != nil { return err } ``` In `DeleteDiskSnapshotRequest.Id`, specify the ID of the snapshot that you want to delete. ```python snapshot_service = DiskSnapshotServiceClient(sdk) delete_snapshot_operation = await snapshot_service.delete( DeleteDiskSnapshotRequest(id=""), ) await delete_snapshot_operation.wait() ``` In `DeleteDiskSnapshotRequest.id`, specify the ID of the snapshot that you want to delete. ```ts const deleteSnapshotService = new DiskSnapshotService(sdk); const deleteSnapshotOperation = await deleteSnapshotService.delete( DeleteDiskSnapshotRequest.create({ id: "", }), ).result; await deleteSnapshotOperation.wait(); ``` In `DeleteDiskSnapshotRequest.id`, specify the ID of the snapshot that you want to delete. # Attaching and mounting Compute volumes to VMs Source: https://docs.nebius.com/compute/storage/use.md In this article, you will learn how to use [Compute disks and shared filesystems](https://docs.nebius.com/compute/storage/types.md) on virtual machines (VMs). This article only covers additional volumes: non-boot disks and shared filesystems. You add a boot disk when you create a VM. After [creating a disk](https://docs.nebius.com/compute/storage/manage.md#how-to-create-a-disk) or a [shared filesystem](https://docs.nebius.com/compute/storage/manage.md#how-to-create-a-shared-filesystem), you need to do the following to use it on a VM: 1. [Attach it to the VM](https://docs.nebius.com/compute/storage/use.md#how-to-attach-volumes-to-vms) by using Nebius AI Cloud interfaces. 2. [Mount it to the VM](https://docs.nebius.com/compute/storage/use.md#how-to-mount-volumes-to-vms) inside the VM's operating system. A VM and its volumes must be located in the same project. For more details about projects and resource hierarchy in Nebius AI Cloud, see [How resources, identities and access are managed in Nebius AI Cloud](https://docs.nebius.com/iam/overview.md). ## Prerequisites [Install and configure](https://docs.nebius.com/cli/install.md) the Nebius AI Cloud CLI. [Install and initialize the Nebius SDK for Go](https://docs.nebius.com/grpc-api/sdk/go.md). [Install and initialize the Nebius SDK for Python](https://docs.nebius.com/grpc-api/sdk/python.md). [Install and initialize the Nebius SDK for JavaScript](https://docs.nebius.com/grpc-api/sdk/javascript.md). ## How to attach volumes to VMs To attach disks or shared filesystems to a VM: * **New VM** In the VM creation wizard ( **Compute** → **Virtual machines** → **Create resource** → **Virtual machine**), on the **Storage** step, do the following: 1. Click **Attach disk** or **Attach shared filesystem**. 2. Set up the volume: 1. Select whether you want to add a new or existing volume. If an existing disk is already added to another VM, you cannot add it to the new VM. A filesystem can be shared by multiple VMs. 2. For a new volume, set its [parameters](https://docs.nebius.com/compute/storage/manage.md#volume-parameters). 3. Set a device ID if you are adding a disk, or a mount tag if you are attaching a filesystem. Device IDs and mount tags are used to [mount volumes to VMs](https://docs.nebius.com/compute/storage/use.md#how-to-mount-volumes-to-vms). 3. Click the attach-volume button at the end of the window. When you click **Create and add disk** or **Create and attach filesystem**, the disk or filesystem is created immediately and [charged](https://docs.nebius.com/compute/resources/pricing.md#volumes) separately even if you remove it from the VM later or do not proceed with creating the VM. 4. If you want to [manually mount the filesystem](https://docs.nebius.com/compute/storage/use.md#shared-filesystems) that you added to the VM, turn off the **Auto mount** option for the filesystem. By default, Compute automatically mounts filesystems that you add to VMs via the web console. If you add a disk, you always need to [mount it manually](https://docs.nebius.com/compute/storage/use.md#disks). * **Existing VM** **Disks** 1. In the sidebar, go to **Compute** → **Virtual machines**. 2. On the **Standalone VMs** tab, open the page of the required VM. 3. Switch to the **Disks** tab. 4. Click **Attach resource** → **Disk**. 5. Select whether you want to attach a new or existing disk. If an existing disk is already attached to another VM, you cannot attach it to a new VM until you [detach](https://docs.nebius.com/compute/storage/detach-volume.md) it from the current VM. 6. For a new disk, set its [parameters](https://docs.nebius.com/compute/storage/manage.md#volume-parameters). 7. Set a device ID for the disk. Device IDs are used to [mount disks to VMs](https://docs.nebius.com/compute/storage/use.md#how-to-mount-volumes-to-vms). 8. Click the attach-volume button at the end of the window. **Shared filesystems** 1. In the sidebar, go to **Compute** → **Virtual machines**. 2. On the **Standalone VMs** tab, open the page of the required VM. 3. If the VM is not in the `Stopped` status, click **Stop VM** and then confirm the action. 4. After the VM has the `Stopped` status, switch to the **Filesystems** tab. 5. Click **Attach resource** → **Filesystem**. 6. Select whether you want to attach a new or existing filesystem. A filesystem can be shared by multiple VMs. 7. For a new filesystem, set its [parameters](https://docs.nebius.com/compute/storage/manage.md#volume-parameters). 8. Set a mount tag for the filesystem. Mount tags are used to [mount filesystems to VMs](https://docs.nebius.com/compute/storage/use.md#how-to-mount-volumes-to-vms). 9. Click the attach-volume button at the end of the window. 1. [Create the volumes](https://docs.nebius.com/compute/storage/manage.md). 2. Create the following files locally: * `secondary_disk.json` to attach disks: ```json [ { "attach_mode": "", "existing_disk": { "id": "" }, "device_id": "" } ] ``` Where: * Write permission, `READ_WRITE` (default) or `READ_ONLY`. * `existing_disk.id`: Disk ID to be added. To get the ID, run `nebius compute disk list`. * `device_id`: Disk device ID. This parameter is different from `existing_disk.id`, as `device_id` is used for [mounting a disk to a VM](https://docs.nebius.com/compute/storage/use.md#disks). Create your own device ID, such as `my-disk`. Make sure that it is unique within a VM. If you do not specify the device ID, it takes the `disk-N` default value where `N` is an integer. For example, `disk-0`. * `filesystem.json` to attach shared filesystems: ```json [ { "attach_mode": "", "existing_filesystem": { "id": "" }, "mount_tag": "" } ] ``` Where: * Write permission, `READ_WRITE` (default) or `READ_ONLY`. * `existing_filesystem.id`: Filesystem ID to be attached. To get the ID, run nebius compute filesystem list. * `mount_tag`: Tag for [mounting a filesystem to a VM](https://docs.nebius.com/compute/storage/use.md#shared-filesystems). Create your own tag, such as `my-filesystem`. Make sure that it is unique within a VM. If you do not specify the tag, it takes the `filesystem-N` default value where `N` is an integer. For example, `filesystem-0`. 3. Create or update a VM with the volumes configured: * To **create a VM**, run the following command: ```bash nebius compute instance create \ --secondary-disks "$(cat secondary_disk.json)" \ --filesystems "$(cat filesystem.json)" \ ``` * To **attach disks to an existing VM**, run the following command: ```bash nebius compute instance update \ --patch \ --secondary-disks "$(cat secondary_disk.json)" ``` To get the ID of an existing VM, run nebius compute instance list. The `--patch` parameter allows you to only update the specified parameters. Without it, the command resets the VM settings to their default values. * To **attach shared filesystems to an existing VM**, stop the VM first: ```bash nebius compute instance stop --id ``` Then update the VM: ```bash nebius compute instance update \ --patch \ --filesystems "$(cat filesystem.json)" ``` After the update, start the VM: ```bash nebius compute instance start --id ``` 1. [Create the volumes](https://docs.nebius.com/compute/storage/manage.md). 2. Set the attachment parameters in the code examples: In the code examples, set the attachment parameters: * For disks, set the attach mode, existing disk ID and device ID. * For shared filesystems, set the attach mode, existing filesystem ID and mount tag. Create your own mount tag, such as `my-filesystem`. Make sure that it is unique within a VM. If you do not specify the tag, it takes the `filesystem-N` default value where `N` is an integer. For example, `filesystem-0`. 3. Create or update a VM with the volumes configured: * **Create a VM**: ```go diskAttachMode := compute.AttachedDiskSpec_READ_WRITE filesystemAttachMode := compute.AttachedFilesystemSpec_READ_WRITE existingFS := &compute.ExistingFilesystem{ Id: filesystemID, } fsType := &compute.AttachedFilesystemSpec_ExistingFilesystem{ ExistingFilesystem: existingFS, } instanceOperation, err := sdk.Services().Compute().V1(). Instance().Create( ctx, &compute.CreateInstanceRequest{ Metadata: &common.ResourceMetadata{ Name: "vm-name", }, Spec: &compute.InstanceSpec{ Stopped: false, Resources: &compute.ResourcesSpec{ Platform: "cpu-e2", Size: &compute.ResourcesSpec_Preset{ Preset: "2vcpu-8gb", }, }, BootDisk: &compute.AttachedDiskSpec{ AttachMode: diskAttachMode, Type: &compute.AttachedDiskSpec_ExistingDisk{ ExistingDisk: &compute.ExistingDisk{ Id: bootDiskID1, }, }, }, SecondaryDisks: []*compute.AttachedDiskSpec{ { AttachMode: diskAttachMode, Type: &compute.AttachedDiskSpec_ExistingDisk{ ExistingDisk: &compute.ExistingDisk{ Id: additionalDiskID, }, }, DeviceId: "device-0", }, }, Filesystems: []*compute.AttachedFilesystemSpec{ { AttachMode: filesystemAttachMode, MountTag: "mount-tag-1", Type: fsType, }, }, NetworkInterfaces: []*compute.NetworkInterfaceSpec{ { Name: "ni", SubnetId: subnetID, IpAddress: &compute.IPAddress{}, PublicIpAddress: &compute.PublicIPAddress{}, }, }, }, }, ) if err != nil { return err } if _, err = instanceOperation.Wait(ctx); err != nil { return err } vmID := instanceOperation.ResourceID() ``` * **Attach disks to an existing VM**: ```go instance, err := sdk.Services().Compute().V1(). Instance().Get( ctx, &compute.GetInstanceRequest{ Id: "", }, ) if err != nil { return err } if instance.GetSpec() == nil { return errors.New("instance spec is missing") } instance.Spec.SecondaryDisks = []*compute.AttachedDiskSpec{ { AttachMode: compute.AttachedDiskSpec_READ_WRITE, Type: &compute.AttachedDiskSpec_ExistingDisk{ ExistingDisk: &compute.ExistingDisk{ Id: additionalDiskID, }, }, DeviceId: "device-0", }, } instanceOperation, err = sdk.Services().Compute().V1(). Instance().Update( ctx, &compute.UpdateInstanceRequest{ Metadata: instance.Metadata, Spec: instance.Spec, }, ) if err != nil { return err } if _, err = instanceOperation.Wait(ctx); err != nil { return err } ``` To get the ID of an existing VM: ```go instances, err := sdk.Services().Compute().V1(). Instance().List(ctx, &compute.ListInstancesRequest{}) if err != nil { return err } fmt.Println(instances) ``` When updating an existing VM, preserve the disks or shared filesystems that must stay attached. The examples replace the corresponding attachment list in the VM specification. * To **attach shared filesystems to an existing VM**, stop the VM first: ```go instanceOperation, err = sdk.Services().Compute().V1(). Instance().Stop( ctx, &compute.StopInstanceRequest{ Id: "", }, ) if err != nil { return err } if _, err = instanceOperation.Wait(ctx); err != nil { return err } ``` Then update the VM: ```go instance, err = sdk.Services().Compute().V1(). Instance().Get( ctx, &compute.GetInstanceRequest{ Id: "", }, ) if err != nil { return err } if instance.GetSpec() == nil { return errors.New("instance spec is missing") } instance.Spec.Filesystems = []*compute.AttachedFilesystemSpec{ { AttachMode: compute.AttachedFilesystemSpec_READ_WRITE, MountTag: "mount-tag-1", Type: &compute.AttachedFilesystemSpec_ExistingFilesystem{ ExistingFilesystem: &compute.ExistingFilesystem{ Id: filesystemID, }, }, }, } instanceOperation, err = sdk.Services().Compute().V1(). Instance().Update( ctx, &compute.UpdateInstanceRequest{ Metadata: instance.Metadata, Spec: instance.Spec, }, ) if err != nil { return err } if _, err = instanceOperation.Wait(ctx); err != nil { return err } ``` When updating an existing VM, preserve the disks or shared filesystems that must stay attached. The examples replace the corresponding attachment list in the VM specification. After the update, start the VM: ```go instanceOperation, err = sdk.Services().Compute().V1(). Instance().Start( ctx, &compute.StartInstanceRequest{ Id: "", }, ) if err != nil { return err } if _, err = instanceOperation.Wait(ctx); err != nil { return err } ``` 1. [Create the volumes](https://docs.nebius.com/compute/storage/manage.md). 2. Set the attachment parameters in the code examples: In the code examples, set the attachment parameters: * For disks, set the attach mode, existing disk ID and device ID. * For shared filesystems, set the attach mode, existing filesystem ID and mount tag. Create your own mount tag, such as `my-filesystem`. Make sure that it is unique within a VM. If you do not specify the tag, it takes the `filesystem-N` default value where `N` is an integer. For example, `filesystem-0`. 3. Create or update a VM with the volumes configured: * **Create a VM**: ```python instance_service = InstanceServiceClient(sdk) create_instance_operation = await instance_service.create( CreateInstanceRequest( metadata=ResourceMetadata( name="vm-name", ), spec=InstanceSpec( stopped=False, resources=ResourcesSpec( platform="cpu-e2", preset="2vcpu-8gb", ), boot_disk=AttachedDiskSpec( attach_mode=AttachedDiskSpec.AttachMode.READ_WRITE, existing_disk=ExistingDisk(id=boot_disk_id_1), ), secondary_disks=[ AttachedDiskSpec( attach_mode=( AttachedDiskSpec.AttachMode.READ_WRITE ), existing_disk=ExistingDisk(id=additional_disk_id), device_id="device-0", ), ], filesystems=[ AttachedFilesystemSpec( attach_mode=( AttachedFilesystemSpec.AttachMode.READ_WRITE ), existing_filesystem=ExistingFilesystem( id=filesystem_id, ), mount_tag="mount-tag-1", ), ], network_interfaces=[ NetworkInterfaceSpec( name="ni", subnet_id=subnet_id, ip_address=IPAddress(), public_ip_address=PublicIPAddress(), ), ], ), ), ) await create_instance_operation.wait() vm_id = create_instance_operation.resource_id ``` * **Attach disks to an existing VM**: ```python instance_service = InstanceServiceClient(sdk) instance = await instance_service.get( GetInstanceRequest(id=""), ) if instance.spec is None: raise ValueError("instance spec is missing") instance.spec.secondary_disks = [ AttachedDiskSpec( attach_mode=AttachedDiskSpec.AttachMode.READ_WRITE, existing_disk=ExistingDisk(id=additional_disk_id), device_id="device-0", ), ] attach_disk_operation = await instance_service.update( UpdateInstanceRequest( metadata=instance.metadata, spec=instance.spec, ), ) await attach_disk_operation.wait() ``` To get the ID of an existing VM: ```python instance_service = InstanceServiceClient(sdk) instances = await instance_service.list( ListInstancesRequest(), ) print(instances) ``` When updating an existing VM, preserve the disks or shared filesystems that must stay attached. The examples replace the corresponding attachment list in the VM specification. * To **attach shared filesystems to an existing VM**, stop the VM first: ```python instance_service = InstanceServiceClient(sdk) stop_instance_operation = await instance_service.stop( StopInstanceRequest(id=""), ) await stop_instance_operation.wait() ``` Then update the VM: ```python instance_service = InstanceServiceClient(sdk) instance = await instance_service.get( GetInstanceRequest(id=""), ) if instance.spec is None: raise ValueError("instance spec is missing") instance.spec.filesystems = [ AttachedFilesystemSpec( attach_mode=AttachedFilesystemSpec.AttachMode.READ_WRITE, existing_filesystem=ExistingFilesystem(id=filesystem_id), mount_tag="mount-tag-1", ), ] attach_filesystem_operation = await instance_service.update( UpdateInstanceRequest( metadata=instance.metadata, spec=instance.spec, ), ) await attach_filesystem_operation.wait() ``` When updating an existing VM, preserve the disks or shared filesystems that must stay attached. The examples replace the corresponding attachment list in the VM specification. After the update, start the VM: ```python instance_service = InstanceServiceClient(sdk) start_instance_operation = await instance_service.start( StartInstanceRequest(id=""), ) await start_instance_operation.wait() ``` 1. [Create the volumes](https://docs.nebius.com/compute/storage/manage.md). 2. Set the attachment parameters in the code examples: In the code examples, set the attachment parameters: * For disks, set the attach mode, existing disk ID and device ID. * For shared filesystems, set the attach mode, existing filesystem ID and mount tag. Create your own mount tag, such as `my-filesystem`. Make sure that it is unique within a VM. If you do not specify the tag, it takes the `filesystem-N` default value where `N` is an integer. For example, `filesystem-0`. 3. Create or update a VM with the volumes configured: * **Create a VM**: ```ts const createInstanceService = new InstanceService(sdk); const createInstanceOperation = await createInstanceService.create( CreateInstanceRequest.create({ metadata: ResourceMetadata.create({ name: "vm-name", }), spec: InstanceSpec.create({ stopped: false, resources: ResourcesSpec.create({ platform: "cpu-e2", size: { $case: "preset", preset: "2vcpu-8gb", }, }), bootDisk: AttachedDiskSpec.create({ attachMode: AttachedDiskSpec_AttachMode.READ_WRITE, type: { $case: "existingDisk", existingDisk: ExistingDisk.create({ id: bootDiskId1, }), }, }), secondaryDisks: [ AttachedDiskSpec.create({ attachMode: AttachedDiskSpec_AttachMode.READ_WRITE, deviceId: "device-0", type: { $case: "existingDisk", existingDisk: ExistingDisk.create({ id: additionalDiskId, }), }, }), ], filesystems: [ AttachedFilesystemSpec.create({ attachMode: AttachedFilesystemSpec_AttachMode.READ_WRITE, mountTag: "mount-tag-1", type: { $case: "existingFilesystem", existingFilesystem: ExistingFilesystem.create({ id: filesystemId, }), }, }), ], networkInterfaces: [ NetworkInterfaceSpec.create({ name: "ni", subnetId: subnetId, ipAddress: IPAddress.create({}), publicIpAddress: PublicIPAddress.create({}), }), ], }), }), ).result; await createInstanceOperation.wait(); const vmId = createInstanceOperation.resourceId(); ``` * **Attach disks to an existing VM**: ```ts const attachDiskService = new InstanceService(sdk); const instanceForDiskAttach = await attachDiskService.get( GetInstanceRequest.create({ id: "", }), ); if (!instanceForDiskAttach.spec) { throw new Error("instance spec is missing"); } instanceForDiskAttach.spec.secondaryDisks = [ AttachedDiskSpec.create({ attachMode: AttachedDiskSpec_AttachMode.READ_WRITE, deviceId: "device-0", type: { $case: "existingDisk", existingDisk: ExistingDisk.create({ id: additionalDiskId, }), }, }), ]; const attachDiskOperation = await attachDiskService.update( UpdateInstanceRequest.create({ metadata: instanceForDiskAttach.metadata, spec: instanceForDiskAttach.spec, }), ).result; await attachDiskOperation.wait(); ``` To get the ID of an existing VM: ```ts const listInstanceService = new InstanceService(sdk); const instanceList = await listInstanceService.list( ListInstancesRequest.create({}), ); console.log(instanceList); ``` When updating an existing VM, preserve the disks or shared filesystems that must stay attached. The examples replace the corresponding attachment list in the VM specification. * To **attach shared filesystems to an existing VM**, stop the VM first: ```ts const stopInstanceService = new InstanceService(sdk); const stopInstanceOperation = await stopInstanceService.stop( StopInstanceRequest.create({ id: "", }), ).result; await stopInstanceOperation.wait(); ``` Then update the VM: ```ts const attachFilesystemService = new InstanceService(sdk); const instanceForFilesystemAttach = await attachFilesystemService.get( GetInstanceRequest.create({ id: "", }), ); if (!instanceForFilesystemAttach.spec) { throw new Error("instance spec is missing"); } instanceForFilesystemAttach.spec.filesystems = [ AttachedFilesystemSpec.create({ attachMode: AttachedFilesystemSpec_AttachMode.READ_WRITE, mountTag: "mount-tag-1", type: { $case: "existingFilesystem", existingFilesystem: ExistingFilesystem.create({ id: filesystemId, }), }, }), ]; const attachFilesystemOperation = await attachFilesystemService.update( UpdateInstanceRequest.create({ metadata: instanceForFilesystemAttach.metadata, spec: instanceForFilesystemAttach.spec, }), ).result; await attachFilesystemOperation.wait(); ``` When updating an existing VM, preserve the disks or shared filesystems that must stay attached. The examples replace the corresponding attachment list in the VM specification. After the update, start the VM: ```ts const startInstanceService = new InstanceService(sdk); const startInstanceOperation = await startInstanceService.start( StartInstanceRequest.create({ id: "", }), ).result; await startInstanceOperation.wait(); ``` You can also attach a VM-managed boot disk to another VM, so you can investigate and troubleshoot this boot disk. For more information, see [How to inspect a VM and attach its boot disk to another VM](https://docs.nebius.com/compute/virtual-machines/inspect-boot-disk.md). ## How to mount volumes to VMs ### Disks 1. [Attach the disk to a VM](https://docs.nebius.com/compute/storage/use.md#how-to-attach-volumes-to-vms). 2. If you have not saved the disk's device ID, for example, when adding it to the VM, get it from the information about the VM: ```bash nebius compute instance get --id --format json \ | jq -r --arg disk_id \ '.spec.secondary_disks[] | select(.existing_disk.id == $disk_id) | .device_id' ``` To get the VM ID, run nebius compute instance list. To get the disk ID, run nebius compute disk list. ```go instance, err = sdk.Services().Compute().V1(). Instance().Get( ctx, &compute.GetInstanceRequest{ Id: "", }, ) if err != nil { return err } if instance.GetSpec() == nil { return errors.New("instance spec is missing") } deviceID := "" for _, secondaryDisk := range instance.GetSpec().GetSecondaryDisks() { existingDisk := secondaryDisk.GetExistingDisk() if existingDisk != nil && existingDisk.GetId() == "" { deviceID = secondaryDisk.GetDeviceId() break } } if deviceID == "" { return errors.New("device ID is missing") } fmt.Println(deviceID) ``` To get the VM ID, run: ```go instances, err := sdk.Services().Compute().V1(). Instance().List(ctx, &compute.ListInstancesRequest{}) if err != nil { return err } fmt.Println(instances) ``` For the disk ID, use the ID of the disk that you attached. ```python instance_service = InstanceServiceClient(sdk) instance = await instance_service.get( GetInstanceRequest(id=""), ) if instance.spec is None: raise ValueError("instance spec is missing") device_id = next( secondary_disk.device_id for secondary_disk in instance.spec.secondary_disks if secondary_disk.existing_disk is not None and secondary_disk.existing_disk.id == "" ) print(device_id) ``` To get the VM ID, run: ```python instance_service = InstanceServiceClient(sdk) instances = await instance_service.list( ListInstancesRequest(), ) print(instances) ``` For the disk ID, use the ID of the disk that you attached. ```ts const getDeviceIdService = new InstanceService(sdk); const instanceForDeviceLookup = await getDeviceIdService.get( GetInstanceRequest.create({ id: "", }), ); const deviceId = instanceForDeviceLookup.spec?.secondaryDisks.find( (secondaryDisk) => secondaryDisk.type?.$case === "existingDisk" && secondaryDisk.type.existingDisk.id === "", )?.deviceId; if (!deviceId) { throw new Error("device ID is missing"); } console.log(deviceId); ``` To get the VM ID, run: ```ts const listInstanceService = new InstanceService(sdk); const instanceList = await listInstanceService.list( ListInstancesRequest.create({}), ); console.log(instanceList); ``` For the disk ID, use the ID of the disk that you attached. 3. [Connect to the VM over SSH](https://docs.nebius.com/compute/virtual-machines/connect.md#connect-to-the-vm-by-using-ssh). 4. Switch to the `root` user: ```bash sudo su - ``` 5. Partition the device. For example, you can use `cfdisk`. In the example below, we assume that you have named the device `disk-0`; for disks, all device IDs are prefixed with `virtio-`: 1. Run `cfdisk`: ```bash cfdisk /dev/disk/by-id/virtio-disk-0 ``` Referring to a device by its name, e.g., `/dev/vdb`, does not guarantee it will function properly. Use the device ID instead, e.g., `/dev/disk/by-id/virtio-disk-0`. 2. Under **Select label type**, select **gpt** and press **Enter**. 3. Select **New** (partition) and press **Enter**. 4. Enter the partition size and press **Enter**. This will create a `/dev/disk/by-id/virtio-disk-0-part1` partition. 5. Select **Write** (the partition table to the device) and press **Enter**, then type `yes` and press **Enter**. 6. Select **Quit** and press **Enter**. 6. Format the partition: ```bash mkfs.ext4 /dev/disk/by-id/virtio-disk-0-part1 ``` 7. Mount the partition and configure permissions for it by using `chmod`. In the example below, the partition is mounted at `/mnt/disk-0`, and all VM users are granted write access to it: ```bash mkdir /mnt/disk-0 mount /dev/disk/by-id/virtio-disk-0-part1 /mnt/disk-0 chmod a+w /mnt/disk-0 ``` 8. If you want the partition to be mounted automatically after every VM restart, add it to `/etc/fstab` by its UUID: ```bash echo "UUID=$(blkid -s UUID -o value /dev/disk/by-id/virtio-disk-0-part1) /mnt/disk-0 ext4 defaults,nofail 0 2" >> /etc/fstab ``` Do not omit `nofail`. If it is not specified and the VM cannot find the partition on restart (for example, the disk has been repartitioned), the VM will not boot. 9. Exit the `root` user shell: ```bash exit ``` ### Shared filesystems If you create a VM in the web console, you can automatically attach and mount a shared filesystem to the VM by using the **Auto mount** option. If you do not use it, mount the filesystem manually. To do this: 1. [Attach the shared filesystem to a VM](https://docs.nebius.com/compute/storage/use.md#how-to-attach-volumes-to-vms). 2. If you have not saved the filesystem's mount tag, for example, when adding it to the VM, get the mount tag from the information about the VM: ```bash nebius compute instance get --id --format json \ | jq -r --arg fs_id \ '.spec.filesystems[] | select(.existing_filesystem.id == $fs_id) | .mount_tag' ``` To get the VM ID, run nebius compute instance list. To get the filesystem ID, run nebius compute filesystem list. ```go instance, err = sdk.Services().Compute().V1(). Instance().Get( ctx, &compute.GetInstanceRequest{ Id: "", }, ) if err != nil { return err } if instance.GetSpec() == nil { return errors.New("instance spec is missing") } mountTag := "" for _, filesystem := range instance.GetSpec().GetFilesystems() { existingFilesystem := filesystem.GetExistingFilesystem() if existingFilesystem != nil && existingFilesystem.GetId() == "" { mountTag = filesystem.GetMountTag() break } } if mountTag == "" { return errors.New("mount tag is missing") } fmt.Println(mountTag) ``` To get the VM ID, run: ```go instances, err := sdk.Services().Compute().V1(). Instance().List(ctx, &compute.ListInstancesRequest{}) if err != nil { return err } fmt.Println(instances) ``` For the filesystem ID, use the ID of the filesystem that you attached. ```python instance_service = InstanceServiceClient(sdk) instance = await instance_service.get( GetInstanceRequest(id=""), ) if instance.spec is None: raise ValueError("instance spec is missing") mount_tag = next( filesystem.mount_tag for filesystem in instance.spec.filesystems if filesystem.existing_filesystem is not None and filesystem.existing_filesystem.id == "" ) print(mount_tag) ``` To get the VM ID, run: ```python instance_service = InstanceServiceClient(sdk) instances = await instance_service.list( ListInstancesRequest(), ) print(instances) ``` For the filesystem ID, use the ID of the filesystem that you attached. ```ts const getMountTagService = new InstanceService(sdk); const instanceForMountLookup = await getMountTagService.get( GetInstanceRequest.create({ id: "", }), ); const mountTag = instanceForMountLookup.spec?.filesystems.find( (filesystem) => filesystem.type?.$case === "existingFilesystem" && filesystem.type.existingFilesystem.id === "", )?.mountTag; if (!mountTag) { throw new Error("mount tag is missing"); } console.log(mountTag); ``` To get the VM ID, run: ```ts const listInstanceService = new InstanceService(sdk); const instanceList = await listInstanceService.list( ListInstancesRequest.create({}), ); console.log(instanceList); ``` For the filesystem ID, use the ID of the filesystem that you attached. 3. [Connect to the VM over SSH](https://docs.nebius.com/compute/virtual-machines/connect.md#connect-to-the-vm-by-using-ssh). 4. Switch to the `root` user: ```bash sudo su - ``` 5. Mount the filesystem as a `virtiofs` device and configure permissions for it by using `chmod`. In the example below, a filesystem has the mount tag `filesystem-0` and is mounted at `/mnt/fs`. All VM users are granted write access to it: ```bash mkdir /mnt/fs mount -t virtiofs filesystem-0 /mnt/fs chmod a+w /mnt/fs ``` 6. If you want the filesystem to be mounted automatically after every VM restart, add it to `/etc/fstab`: ```bash echo "filesystem-0 /mnt/fs virtiofs rw,nofail 0 0" >> /etc/fstab ``` Do not omit `nofail`. If it is not specified and the VM cannot find the filesystem on restart (for example, it has been deleted), the VM will not boot. 7. Exit the `root` user shell: ```bash exit ``` ## See also * [How to detach additional volumes from virtual machines](https://docs.nebius.com/compute/storage/detach-volume.md) * [Types of storage volumes in Compute](https://docs.nebius.com/compute/storage/types.md) * [Managing Compute volumes](https://docs.nebius.com/compute/storage/manage.md) * [How to create a virtual machine in Nebius AI Cloud](https://docs.nebius.com/compute/virtual-machines/manage.md) # How to detach additional volumes from virtual machines Source: https://docs.nebius.com/compute/storage/detach-volume.md You can detach a [secondary disk](https://docs.nebius.com/compute/storage/types.md#disks) or a [shared filesystem](https://docs.nebius.com/compute/storage/types.md#shared-filesystems) from a VM. You cannot detach a boot disk. ## Prerequisites If you use the web console, you don't need to complete any prerequisites. [Install and configure](https://docs.nebius.com/cli/install.md) the Nebius AI Cloud CLI. [Install and initialize the Nebius SDK for Go](https://docs.nebius.com/grpc-api/sdk/go.md). [Install and initialize the Nebius SDK for Python](https://docs.nebius.com/grpc-api/sdk/python.md). [Install and initialize the Nebius SDK for JavaScript](https://docs.nebius.com/grpc-api/sdk/javascript.md). ## Steps ### Get the disk's device ID or the filesystem's mount tag 1. In the sidebar, go to  **Storage** → **Disks** or  **Storage** → **Shared filesystems**. 2. Copy the device ID from the list of disks or the mount tag from the list of filesystems. Get the VM's specification: ```bash nebius compute instance get ``` Alternatively, list all VMs: ```bash nebius compute instance list ``` In the output, you can find device IDs of disks and mount tags of filesystems in `.spec.secondary_disks[].device_id` and `.spec.filesystems[].mount_tag`, respectively: ```yaml spec: secondary_disks: - attach_mode: READ_WRITE existing_disk: id: computedisk-*** device_id: newdisk filesystems: - attach_mode: READ_WRITE existing_filesystem: id: computefilesystem-*** mount_tag: shared-fs ``` Get the VM's specification: ```go instance, err := sdk.Services().Compute().V1(). Instance().Get( ctx, &compute.GetInstanceRequest{ Id: "", }, ) if err != nil { return err } fmt.Println(instance) ``` Alternatively, list all VMs: ```go instances, err := sdk.Services().Compute().V1(). Instance().List(ctx, &compute.ListInstancesRequest{}) if err != nil { return err } fmt.Println(instances) ``` In the output, you can find device IDs of disks and mount tags of filesystems in `.spec.secondary_disks[].device_id` and `.spec.filesystems[].mount_tag`, respectively: ```yaml spec: secondary_disks: - attach_mode: READ_WRITE existing_disk: id: computedisk-*** device_id: newdisk filesystems: - attach_mode: READ_WRITE existing_filesystem: id: computefilesystem-*** mount_tag: shared-fs ``` Get the VM's specification: ```python instance_service = InstanceServiceClient(sdk) instance = await instance_service.get( GetInstanceRequest(id=""), ) print(instance) ``` Alternatively, list all VMs: ```python instance_service = InstanceServiceClient(sdk) instances = await instance_service.list( ListInstancesRequest(), ) print(instances) ``` In the output, you can find device IDs of disks and mount tags of filesystems in `.spec.secondary_disks[].device_id` and `.spec.filesystems[].mount_tag`, respectively: ```yaml spec: secondary_disks: - attach_mode: READ_WRITE existing_disk: id: computedisk-*** device_id: newdisk filesystems: - attach_mode: READ_WRITE existing_filesystem: id: computefilesystem-*** mount_tag: shared-fs ``` Get the VM's specification: ```ts const getInstanceService = new InstanceService(sdk); const instanceDetails = await getInstanceService.get( GetInstanceRequest.create({ id: "", }), ); console.log(instanceDetails); ``` Alternatively, list all VMs: ```ts const listInstanceService = new InstanceService(sdk); const instanceList = await listInstanceService.list( ListInstancesRequest.create({}), ); console.log(instanceList); ``` In the output, you can find device IDs of disks and mount tags of filesystems in `.spec.secondary_disks[].device_id` and `.spec.filesystems[].mount_tag`, respectively: ```yaml spec: secondary_disks: - attach_mode: READ_WRITE existing_disk: id: computedisk-*** device_id: newdisk filesystems: - attach_mode: READ_WRITE existing_filesystem: id: computefilesystem-*** mount_tag: shared-fs ``` ### Make sure that the VM does not mount the volume when the VM restarts 1. [Connect to the VM over SSH](https://docs.nebius.com/compute/virtual-machines/connect.md#connect-to-the-vm-by-using-ssh). 2. Switch to the `root` user: ```bash sudo su - ``` 3. If you want to detach a secondary disk, get its UUID: ```bash blkid /dev/disk/by-id/virtio-disk-0-part1 -o export | grep "^UUID" ``` In this example, we assume that you have named the device `disk-0`; for disks, all device IDs are prefixed with `virtio-`. 4. Open `/etc/fstab` with your preferred text editor, for example, `nano /etc/fstab`, and delete the lines that refer to the volumes: * The line for a disk should start with its UUID: ```text UUID= /mnt/disk-0 ext4 defaults,nofail 0 2 ``` * The line for a filesystem should start with the filesystem's mount tag from the VM specification: ```text filesystem-0 /mnt/fs virtiofs rw,nofail 0 0 ``` In this example, the filesystem has the mount tag `filesystem-0` and is mounted at `/mnt/fs`. 5. Disconnect from the VM. ### Remove the volume from the VM's specification 1. In the sidebar, go to **Compute** → **Virtual machines**. 2. On the **Standalone VMs** tab, open the page of the required VM. 3. Click  **Stop VM** and then confirm it. You can detach a disk from a running VM, but this can cause data loss or corruption. 4. After the VM's status becomes `Stopped`, switch to the **Disks** or **Filesystems** tab. 5. Next to the disk or filesystem, click  → **Detach**. 6. After the volume is detached, click  **Start VM** and then confirm it. 1. Stop the VM: ```bash nebius compute instance stop --id ``` You can detach a disk from a running VM, but this can cause data loss or corruption. 2. Start editing the VM specification: ```bash nebius compute instance edit ``` 3. In the text editor that opens, remove the disk or filesystem from the `.spec.secondary_disks` or `.spec.filesystems` list, respectively. If, after that, a list becomes empty, remove it entirely. For example: ```diff spec: boot_disk: attach_mode: READ_WRITE device_id: "" existing_disk: id: computedisk-*** - secondary_disks: - - attach_mode: READ_WRITE - existing_disk: - id: computedisk-*** - device_id: newdisk gpu_cluster: ... ``` 4. After making the changes, save the file. The CLI updates the VM automatically. 5. Start the VM: ```bash nebius compute instance start --id ``` 1. Stop the VM: ```go operation, err := sdk.Services().Compute().V1(). Instance().Stop( ctx, &compute.StopInstanceRequest{ Id: "", }, ) if err != nil { return err } if _, err = operation.Wait(ctx); err != nil { return err } ``` You can detach a disk from a running VM, but this can cause data loss or corruption. 2. Remove the volume from the VM's specification: ```go detachInstance, err := sdk.Services().Compute().V1(). Instance().Get( ctx, &compute.GetInstanceRequest{ Id: "", }, ) if err != nil { return err } if detachInstance.GetSpec() == nil { return errors.New("instance spec is missing") } secondaryDisks := detachInstance.Spec.SecondaryDisks[:0] for _, disk := range detachInstance.Spec.SecondaryDisks { if disk.GetDeviceId() != "" { secondaryDisks = append(secondaryDisks, disk) } } detachInstance.Spec.SecondaryDisks = secondaryDisks filesystems := detachInstance.Spec.Filesystems[:0] for _, filesystem := range detachInstance.Spec.Filesystems { if filesystem.GetMountTag() != "" { filesystems = append(filesystems, filesystem) } } detachInstance.Spec.Filesystems = filesystems detachOperation, err := sdk.Services().Compute().V1(). Instance().Update( ctx, &compute.UpdateInstanceRequest{ Metadata: detachInstance.Metadata, Spec: detachInstance.Spec, }, ) if err != nil { return err } if _, err = detachOperation.Wait(ctx); err != nil { return err } ``` In the code, specify the VM ID, the disk's `deviceId` or the filesystem's `mountTag`. 3. Start the VM: ```go operation, err = sdk.Services().Compute().V1(). Instance().Start( ctx, &compute.StartInstanceRequest{ Id: "", }, ) if err != nil { return err } if _, err = operation.Wait(ctx); err != nil { return err } ``` 1. Stop the VM: ```python instance_service = InstanceServiceClient(sdk) stop_instance_operation = await instance_service.stop( StopInstanceRequest(id=""), ) await stop_instance_operation.wait() ``` You can detach a disk from a running VM, but this can cause data loss or corruption. 2. Remove the volume from the VM's specification: ```python instance_service = InstanceServiceClient(sdk) detach_instance = await instance_service.get( GetInstanceRequest(id=""), ) if detach_instance.spec is None: raise ValueError("instance spec is missing") detach_instance.spec.secondary_disks = [ disk for disk in detach_instance.spec.secondary_disks if disk.device_id != "" ] detach_instance.spec.filesystems = [ filesystem for filesystem in detach_instance.spec.filesystems if filesystem.mount_tag != "" ] detach_operation = await instance_service.update( UpdateInstanceRequest( metadata=detach_instance.metadata, spec=detach_instance.spec, ), ) await detach_operation.wait() ``` In the code, specify the VM ID, the disk's `device_id` or the filesystem's `mount_tag`. 3. Start the VM: ```python instance_service = InstanceServiceClient(sdk) start_instance_operation = await instance_service.start( StartInstanceRequest(id=""), ) await start_instance_operation.wait() ``` 1. Stop the VM: ```ts const stopInstanceService = new InstanceService(sdk); const stopInstanceOperation = await stopInstanceService.stop( StopInstanceRequest.create({ id: "", }), ).result; await stopInstanceOperation.wait(); ``` You can detach a disk from a running VM, but this can cause data loss or corruption. 2. Remove the volume from the VM's specification: ```ts const detachInstanceService = new InstanceService(sdk); const detachInstance = await detachInstanceService.get( GetInstanceRequest.create({ id: "", }), ); if (!detachInstance.spec) { throw new Error("instance spec is missing"); } detachInstance.spec.secondaryDisks = ( detachInstance.spec.secondaryDisks ?? [] ).filter((disk) => disk.deviceId !== ""); detachInstance.spec.filesystems = ( detachInstance.spec.filesystems ?? [] ).filter((filesystem) => filesystem.mountTag !== ""); const detachOperation = await detachInstanceService.update( UpdateInstanceRequest.create({ metadata: detachInstance.metadata, spec: detachInstance.spec, }), ).result; await detachOperation.wait(); ``` In the code, specify the VM ID, the disk's `deviceId` or the filesystem's `mountTag`. 3. Start the VM: ```ts const startInstanceService = new InstanceService(sdk); const startInstanceOperation = await startInstanceService.start( StartInstanceRequest.create({ id: "", }), ).result; await startInstanceOperation.wait(); ``` You can [attach and mount](https://docs.nebius.com/compute/storage/use.md) different additional volumes to the VM later. # Exporting data from Compute disks and shared filesystems Source: https://docs.nebius.com/compute/storage/export.md You can export data that you store on [Compute volumes](https://docs.nebius.com/compute/storage/types.md) (boot disks, additional disks and shared filesystems) to local or virtual machines: 1. Check whether the disk or filesystem is used on any VMs: 1. In the [web console](https://console.nebius.com), go to **Storage** → **Disks** or **Storage** → **Shared filesystems**. 2. Click on the volume. 3. Under **General**, check the **Virtual machine** value. It lists the VMs that use the volume. * For a disk, run nebius compute disk list or nebius compute disk get \. If the disk is used on a VM, the output contains the VM's ID in the `.status.read_write_attachment` field: ```yaml status: read_write_attachment: computeinstance-e00*** ``` For more details about the commands, see the references for [nebius compute disk list](https://docs.nebius.com/cli/reference/compute/disk/list) and [nebius compute disk get](https://docs.nebius.com/cli/reference/compute/disk/get). * For a filesystem, run nebius compute filesystem list or nebius compute filesystem get \. If the filesystem is used on any VMs, the output lists their IDs in the `.status.read_write_attachments` field: ```yaml status: read_write_attachments: - computeinstance-e00*** - computeinstance-e00*** ``` For more details about the commands, see the references for [nebius compute filesystem list](https://docs.nebius.com/cli/reference/compute/filesystem/list) and [nebius compute filesystem get](https://docs.nebius.com/cli/reference/compute/filesystem/get). * For a disk, get or list disks and check `disk.GetStatus().GetReadWriteAttachment()`. If the disk is used on a VM, the response contains this VM's ID. * For a filesystem, get or list filesystems and check `filesystem.GetStatus().GetReadWriteAttachments()`. If the filesystem is used on any VMs, the response contains a list of their IDs. * For a disk, get or list disks and check `disk.status.read_write_attachment`. If the disk is used on a VM, the response contains this VM's ID. * For a filesystem, get or list filesystems and check `filesystem.status.read_write_attachments`. If the filesystem is used on any VMs, the response contains a list of their IDs. * For a disk, get or list disks and check `disk.status?.readWriteAttachment`. If the disk is used on a VM, the response contains this VM's ID. * For a filesystem, get or list filesystems and check `filesystem.status?.readWriteAttachments`. If the filesystem is used on any VMs, the response contains a list of their IDs. 2. If the disk or filesystem is not used on any VM, [attach and mount it to a VM](https://docs.nebius.com/compute/storage/use.md). 3. Check that you can [connect to the VM over SSH](https://docs.nebius.com/compute/virtual-machines/connect.md). * If the VM does not have a public IP address, you have the following options: * Connect to the VM's private address from another VM in the same [network](https://docs.nebius.com/vpc/overview.md#network). * Run nebius compute instance update with the `--network-interfaces` parameter to add a public address to the VM. For the command reference, see [nebius compute instance update](https://docs.nebius.com/cli/reference/compute/instance/update). * Create another VM with a public address and add the volume to it. For details and examples, see [How to create a virtual machine in Nebius AI Cloud](https://docs.nebius.com/compute/virtual-machines/manage.md). A disk can be attached to only one running VM at a time; shared filesystems can be used by several VMs at once. To add a disk to a new VM, [detach the disk](https://docs.nebius.com/compute/storage/detach-volume.md) from the original VM if it's a secondary disk, or [attach it to another VM for troubleshooting](https://docs.nebius.com/compute/virtual-machines/inspect-boot-disk.md) if it's the boot disk. * If you have not created this VM, ask its owner to perform the following steps themselves or add you to the VM as a user. * For other connection issues, [contact support](https://console.nebius.com/support/create-ticket). 4. On your local machine, run a tool for copying files, for example, `rsync` or `scp`: ```bash rsync @: ``` > For example, if a VM has the public IP address `195.242.11.11` and you work with it as `alice`, run the following command to recursively copy the contents of your home directory: > > ```bash > rsync -r alice@195.242.11.11:/home/alice ~/vm-home > ``` For more `rsync` details and parameters, run `man rsync`. ```bash scp @: ``` > For example, if a VM has the public IP address `195.242.11.11` and you work with it as `alice`, run the following command to recursively copy the contents of your home directory: > > ```bash > scp -r alice@195.242.11.11:/home/alice ~/vm-home > ``` For more `scp` details and parameters, see its [manpage](https://man.openbsd.org/scp.1) or run `man scp`. # Using local SSD disks on Compute virtual machines Source: https://docs.nebius.com/compute/storage/local-disks.md Local SSD disks are Non-Volatile Memory Express (NVMe) drives physically attached to the compute host that runs a virtual machine (VM). Local SSD disks offer low-latency storage, but they are *ephemeral*. When the VM is stopped or deleted, the data is lost. ## Availability Local SSD disks are available: * Only in the public `uk-south1` and private `eu-west2` [regions](https://docs.nebius.com/overview/regions.md). * Only on the NVIDIA® B300 NVLink with Intel Granite Rapids platform (`gpu-b300-sxm`) with the eight-GPU preset `8gpu-192vcpu-2768gb`. The capacity of local SSD disks is fixed by the platform and preset. This configuration adds `6 × 3.84 TB` of local storage. ## How to add local SSD disks Local SSD disks can be enabled when [creating a VM](https://docs.nebius.com/compute/virtual-machines/manage.md#create-a-vm). They are not created as a separate storage resource, and you cannot add them to an existing VM or change this setting later. You can create [RAID](https://en.wikipedia.org/wiki/RAID) on top of your local SSD disks, for example, to combine multiple disks into a single logical storage for higher performance or easier management. ## Lifecycle and data persistence Local SSD data persistence depends on whether the event affects the Compute VM or only the VM operating system: * If you reboot the VM operating system from inside the VM, for example by using `sudo reboot`, data is expected to persist because the Compute VM is not stopped or deleted. * If you stop or delete the VM in Compute, data on local SSD disks is lost. * If the host or a local disk fails, the Compute VM enters maintenance mode and data is lost. When a Compute VM is stopped or deleted, the local SSD disks are released and sanitized with additional cleanup checks to clear the disks of all data before reuse. ## When to use durable storage instead Use durable storage instead of local SSD disks if you need any of the following: * Data that must survive VM stop, deletion or rescheduling events. Use [Network disks](https://docs.nebius.com/compute/storage/types.md#disks), [shared filesystems](https://docs.nebius.com/compute/storage/types.md#shared-filesystems) or [Object Storage](https://docs.nebius.com/object-storage). * Data sharing across several VMs. Use [shared filesystems](https://docs.nebius.com/compute/storage/types.md#shared-filesystems) or [Object Storage](https://docs.nebius.com/object-storage). * Snapshots, backup workflows or long-term retention. Use [Network disks](https://docs.nebius.com/compute/storage/types.md#disks), [shared filesystems](https://docs.nebius.com/compute/storage/types.md#shared-filesystems) or [Object Storage](https://docs.nebius.com/object-storage). * User-defined capacity that is independent of the selected VM preset. Use [Network disks](https://docs.nebius.com/compute/storage/types.md#disks) or [shared filesystems](https://docs.nebius.com/compute/storage/types.md#shared-filesystems). ## See also * [Types of storage volumes in Compute](https://docs.nebius.com/compute/storage/types.md) * [How to create a virtual machine in Nebius AI Cloud](https://docs.nebius.com/compute/virtual-machines/manage.md#create-a-vm) * [Compute pricing](https://docs.nebius.com/compute/resources/pricing.md#local-ssd-disks) # Monitoring virtual machines in Nebius AI Cloud Source: https://docs.nebius.com/compute/monitoring/virtual-machines.md You can monitor GPUs, vCPUs and network statuses on the dashboards in the Nebius AI Cloud [web console](https://console.nebius.com). There are two ways to find the required dashboard: * Go to **Observability** → [Metrics](https://console.nebius.com/observability/metrics) and select the resource you would like to review. * Go to the page of the VM you would like to review and switch to the **Metrics** tab. Use the dashboard to monitor current resource utilization, get information to schedule [quota](https://docs.nebius.com/compute/resources/quotas-limits.md) increases and quickly identify anomalies. In case of VM issues, dashboards help the Nebius support team investigate the issue. Data for the dashboard is collected automatically. For more information about metrics collection, see [Monitoring agent on Compute virtual machines](https://docs.nebius.com/observability/agents/monitoring-agent.md). ## Explore the dashboard The VM usage data becomes available 5–10 minutes after the VM is created. Use time filters to view a specific period of usage. By default, the data is refreshed every 15 seconds. You can configure this interval to the right of the time filters. ## GPU monitoring metrics The corresponding [NVIDIA metrics](https://docs.nvidia.com/datacenter/dcgm/latest/dcgm-api/dcgm-api-field-ids.html) are shown next to the Nebius AI Cloud metric. * **GPU utilization** (`DCGM_FI_DEV_GPU_UTIL`) Percentage of time a GPU spends executing tasks. * **Memory utilization** (`DCGM_FI_DEV_MEM_COPY_UTIL`) Percentage of time GPU memory was in use (performing read or write tasks) in a dedicated period. * **Free frame buffer in MB** (`DCGM_FI_DEV_FB_FREE`) Amount of free frame buffer memory. * **Used frame buffer in MB** (`DCGM_FI_DEV_FB_USED`) Amount of used frame buffer memory. * **Total frame buffer of the GPU in MB** (`DCGM_FI_DEV_FB_TOTAL`) A constant. The total amount of frame buffer memory. * **Reserved frame buffer in MB** (`DCGM_FI_DEV_FB_RESERVED`) A constant. Amount of frame buffer memory reserved for the internal use of the hardware: drivers, firmware, etc. * **The number of bytes of active PCIe rx/tx** (`DCGM_FI_PROF_PCIE_RX_BYTES`, `DCGM_FI_PROF_PCIE_TX_BYTES`) Number of bytes a GPU received from (rx) or transmitted to (tx) its host VM and other devices over PCIe. Both header and payload of each PCIe packet are included. * **SM clock for the device** (`DCGM_FI_DEV_SM_CLOCK`) Frequency of the main GPU clock. * **Memory clock for the device** (`DCGM_FI_DEV_MEM_CLOCK`) Frequency and total amount of operations in time spans. * **Current clock throttle reasons** (`DCGM_FI_DEV_CLOCK_THROTTLE_REASONS`) A bitmask of [possible reasons for GPU throttling](https://docs.nvidia.com/datacenter/dcgm/2.2/dcgm-api/group__dcgmFieldConstants.html). For example, if the GPU is throttling because it has overheated and slowed down, the chart will show 72: code 0x40 for overheating (`DCGM_CLOCKS_THROTTLE_REASON_HW_THERMAL`) + code 0x8 for slowdown (`DCGM_CLOCKS_THROTTLE_REASON_HW_SLOWDOWN`) = 72 in decimal. * **Power usage for the device** (`DCGM_FI_DEV_POWER_USAGE`) Current energy consumption by a GPU in watts. * **Total energy consumption for the GPU since the driver was last reloaded** (`DCGM_FI_DEV_TOTAL_ENERGY_CONSUMPTION`) Cumulative energy consumption by a GPU since the recent driver reload in millijoules. * **Memory temperature for the device** (`DCGM_FI_DEV_MEMORY_TEMP`) Memory temperature in degrees Celsius. * **Current temperature readings for the device** (`DCGM_FI_DEV_GPU_TEMP`) GPU core temperature in degrees Celsius. * **Current power limit for the device** (`DCGM_FI_DEV_POWER_MGMT_LIMIT`) A constant. Power consumption limit after which the GPU will be throttled. * **Slowdown temperature for the device** (`DCGM_FI_DEV_SLOWDOWN_TEMP`) A constant. Temperature threshold after which the GPU will be throttled until it cools down. * **The number of bytes of active NVLink (RX/TX)**(`PROF_NVLINK_TX_BYTES`, `PROF_NVLINK_RX_BYTES`) Number of bytes a GPU received from (rx) or transmitted to (tx) its host VM and other devices over NVLink, not including protocol headers, in bytes per second. If you have a [GPU cluster](https://docs.nebius.com/compute/clusters/gpu/index.md), the following metrics become available and help monitor InfiniBand™ connection: * **Link Downed Total** Number of times the port failed to recover the link and downed it. * **Link Error Recovery Total** Number of times the port recovered the link after error. * **Port Data Total (RX/TX)** Number of bytes all GPUs received (rx) or transmitted (tx) via the port, including packets with errors. * **Port Discards TX Total** Number of transmitted packets discarded by the port when the port was down or not responding. * **Port Errors RX Total** Number of received packets with errors, including physical, mailformed data and link packet errors and overrun buffer. * **Port Packets Total (RX/TX)** Speed of receiving (rx) or transmitting (tx) packets on all GPUs, including packets with errors and excluding link packets. Calculated in packets per second. * **Transfer Rate** Data transferring speed, calculated in bytes per second. ## vCPU monitoring metrics * **CPU utilization** Percentage of time vCPUs spend executing tasks. * **RAM** Amount of total and used memory. * **Disk bytes** Average data transfer throughput of the VM's disks. Measured in bytes per second. * **Disk operations** Average IOPS of the VM's disks. Measured in operations per second. * **Network bytes** Average data transfer speed of the VM's network. Measured in bytes per second. * **Network packets** Average packets transfer speed of the VM's network. Measured in packets per second. *** *InfiniBand and InfiniBand Trade Association are registered trademarks of the InfiniBand Trade Association.* # Viewing serial logs of virtual machines Source: https://docs.nebius.com/compute/monitoring/serial-logs.md Compute virtual machines write logs from a serial console. Serial logs may help you with troubleshooting VM startup and shutdown failures, operating system incidents or other similar issues. Serial logs are kept for 14 days. The logs for deleted instances are also kept for 14 days, but you cannot see them in the [web console](https://docs.nebius.com/compute/monitoring/serial-logs.md#view-serial-logs-in-web-console). Use [Grafana®](https://docs.nebius.com/compute/monitoring/serial-logs.md#view-serial-logs-in-grafana) or [LogCLI](https://docs.nebius.com/compute/monitoring/serial-logs.md#query-serial-logs-with-logcli) to view logs of deleted instances. Serial logs for Compute are free of charge. ## View serial logs in web console To view the serial logs of a given virtual machine: 1. In the sidebar, go to **Compute** → **Virtual machines**. 2. On the **Standalone VMs** tab, select the virtual machine you need and switch to the **Serial logs** tab. To view all serial logs in one place: 1. In the sidebar, go to **Observability** → [Logs](https://console.nebius.com/observability/logs). 2. Select the serial logs bucket. 3. Optionally, filter the logs by virtual machine ID. ## View serial logs in Grafana® You can visualize the serial logs of services in Grafana. After you [connect Grafana](https://docs.nebius.com/observability/logs/grafana.md#how-to-connect-grafana), set the `__bucket__` label value to `sp_serial`. ## Query serial logs with LogCLI After you [set up LogCLI](https://docs.nebius.com/observability/logs/logcli.md), set the `__bucket__` label value to `sp_serial` in your queries, for example: ```bash logcli query '{__bucket__="sp_serial"}' --since 15m ``` *** *The Grafana Labs Marks are trademarks of Grafana Labs, and are used with Grafana Labs’ permission. We are not affiliated with, endorsed or sponsored by Grafana Labs or its affiliates.* # Monitoring volumes in Nebius AI Cloud Source: https://docs.nebius.com/compute/monitoring/volumes.md You can monitor disk and filesystem statuses on the dashboards in the Nebius AI Cloud [web console](https://console.nebius.com). There are two ways to find the required dashboard: * Go to **Observability** → [Metrics](https://console.nebius.com/observability/metrics) and select the resource you would like to review. * Go to the page of the resource you would like to review and switch to the **Metrics** tab. Use the dashboard to monitor current resource utilization, get information to schedule [quota](https://docs.nebius.com/compute/resources/quotas-limits.md) increases and quickly identify anomalies. In case of volume issues, dashboards help the Nebius support team investigate the issue. Data for the dashboard is collected automatically. ## Explore the dashboard The volume usage data becomes available 5–10 minutes after the volume is mounted. Use time filters to view a specific period of usage. By default, the data is refreshed every 15 seconds. You can configure this interval to the right of the time filters. ## Disk monitoring metrics * **Disk read latency by quantiles** Percentiles of the disk read requests latency. Measured in milliseconds. * **Disk write latency by quantiles** Percentiles of the disk write requests latency. Measured in milliseconds. * **Disk read throttler latency by quantiles** Percentiles of the disk write operations latency due to disk quota excess. Measured in milliseconds. * **Disk write throttler latency by quantiles** Percentiles of the disk write operations latency due to disk quota excess. Measured in milliseconds. * **Disk read operations** Average read IOPS. Measured in operations per second. * **Disk write operations** Average write IOPS. Measured in operations per second. * **Disk read bytes** Average read throughput. Measured in bytes per second. * **Disk write bytes** Average write throughput. Measured in bytes per second. * **Disk used quota** Percentage of disk quota on read and write operations per second utilization. ## Filesystem monitoring metrics * **Read latency by quantiles** Percentiles of the filesystem write requests latency. Measured in milliseconds. * **Write latency by quantiles** Percentiles of the filesystem read requests latency. Measured in milliseconds. * **Read operations** Average read IOPS. Measured in operations per second. * **Write operations** Average write IOPS. Measured in operations per second. * **Read bytes** Average read throughput. Measured in bytes per second. * **Write bytes** Average write throughput. Measured in bytes per second. * **Read errors** Number of times a filesystem fails to read data. * **Write errors** Number of times a filesystem fails to write data. * **Index operations** Number of indexing actions (reads, writes, updates and deletions) performed in a time period. * **Index errors** Number of failed indexing operations in a time period. # Using the serial console for virtual machines in Nebius AI Cloud Source: https://docs.nebius.com/compute/virtual-machines/serial-console.md The *serial console* is a browser-based, text-only session to your virtual machine’s serial port that you can use to connect to and troubleshoot a VM when normal network access is unavailable. You can also use it for the first-boot setup on custom or third-party images when SSH is not yet configured. Serial console for Compute VMs is [in preview](https://docs.nebius.com/overview/services.md#service-and-application-stages). ## Prerequisites * [Add a user for connections to the VM](https://docs.nebius.com/compute/virtual-machines/manage.md#optional-create-a-user-data-configuration) the serial console of which you want to access. * Make sure you are in a [default group](https://docs.nebius.com/iam/authorization/groups/index.md#default-groups) that has the `admin` [role](https://docs.nebius.com/iam/authorization/roles.md#compute) or in a [custom group](https://docs.nebius.com/iam/authorization/groups/index.md) that has at least the `compute.serial-console-user` role within your tenant or project. You can check this in the [Administration → IAM](https://console.nebius.com/iam) section of the web console. ## Using the serial console To open the serial console: 1. In the sidebar, go to  **Compute** → **Virtual machines**. 2. Select the virtual machine. 3. Click **Open serial console**. The console opens in the browser as a dedicated terminal view. The serial console session is **text-only** and doesn't support a graphical interface. ## Limits and concurrent sessions Only one serial console session can be active for a given VM at a time. If someone else already has a session open, a new connection will fail until the other session ends. Be sure to close any unused console windows in your browser if you no longer need the session. ## Troubleshooting ### Resource not found In this case, the VM might be stopped. [Start the VM](https://docs.nebius.com/compute/virtual-machines/stop-start.md#how-to-stop-and-start-vms-manually) and then open the serial console again. ### Connection failed Another serial console session is already open for this VM. Coordinate with other users, or wait and try again. ### Access denied If you can't access the serial console and you don't have permission to use it, contact the administrator of your tenant. Ask them to add you to the group with at least the `compute.serial-console-user` role. ### Checking Audit Logs for serial console events [Audit Logs](https://docs.nebius.com/audit-logs/index.md) records all serial console connection attempts, including failed ones. To find these events, [filter](https://docs.nebius.com/audit-logs/events/filter.md) them by the service: `"service.name='COMPUTE_CONSOLE'"`. For failed attempts, check the event's `response.error_message` field. For example, the `Permission denied` message in the field indicates access denied. ## See also * [Connecting to virtual machines](https://docs.nebius.com/compute/virtual-machines/connect.md) * [Viewing serial logs of virtual machines](https://docs.nebius.com/compute/monitoring/serial-logs.md) # "Not enough resources" error for virtual machines in Nebius AI Cloud Source: https://docs.nebius.com/compute/virtual-machines/not-enough-resources.md Sometimes, demand for virtual machines and GPUs in certain [Nebius AI Cloud regions](https://docs.nebius.com/overview/regions.md) might be higher than the available supply. When this happens, you might see a "Not enough resources" error when creating or restarting VMs in the affected region. ## Error creating a VM If you receive a "Not enough resources" error when [creating a VM](https://docs.nebius.com/compute/virtual-machines/manage.md) in an affected region, consider creating the VM with similar resources or in a different region. > For example, instead of creating the VM on the NVIDIA® H200 NVLink with Intel Sapphire Rapids platform in the eu-west1 region, you can try NVIDIA® H100 NVLink with Intel Sapphire Rapids in eu-north1. For VMs with GPUs, you can use the [capacity advisor](https://docs.nebius.com/compute/virtual-machines/capacity-advisor.md) to get information about the availability of computing resources based on your quotas and the current physical capacity. Availability of platforms and presets differs by region and project. To change the platform or preset of a VM, you might need to change its project as well. For more information about availability, see [Types of virtual machines and GPUs in Nebius AI Cloud](https://docs.nebius.com/compute/virtual-machines/types.md) and [How to find out platforms and presets available in a project](https://docs.nebius.com/compute/virtual-machines/list-platforms.md). If your workload does not work with another VM platform or preset, you can request to reserve the required capacity. For more details, [contact the Nebius sales team](https://nebius.com/#ai-contact-form). ## Error restarting a stopped VM If you get a "Not enough resources" error when restarting a stopped VM in an affected region, check the [capacity advisor](https://docs.nebius.com/compute/virtual-machines/capacity-advisor.md) for detailed information on available computing resources. # CUDA initialization error on virtual machines in Nebius AI Cloud Source: https://docs.nebius.com/compute/virtual-machines/cuda-init-error.md On Compute virtual machines with GPUs, CUDA may fail to initialize in rare cases, which may lead to problems when running GPU workloads. This can happen due to various reasons, including issues with NVIDIA Fabric Manager initialization. You can resolve this issue by restarting the NVIDIA Fabric Manager service, the GPUs on the VM or the entire VM. ## Issue On virtual machines with GPUs, CUDA may fail to initialize in rare cases, leading to errors when you run your workloads and tests. This can occur on any VM with GPUs, regardless of the specific platform, number of GPUs or boot disk image. > For example, executing PyTorch code may result in the following error: > > ```text > ERROR: The NVIDIA Driver is present, but CUDA failed to initialize. > GPU functionality will not be available. > [[ System not yet initialized (error 802) ]] > > /usr/local/lib/python3.12/dist-packages/torch/cuda/__init__.py:129: UserWarning: > CUDA initialization: Unexpected error from cudaGetDeviceCount(). Did you run some cuda functions > before calling NumCudaDevices() that might have already set an error? > Error 802: system not yet initialized (Triggered internally at > /opt/pytorch/pytorch/c10/cuda/CUDAFunctions.cpp:109.) > return torch._C._cuda_getDeviceCount() > 0 > ``` ## Possible cause One possible cause of CUDA initialization failures is an issue with the [NVIDIA Fabric Manager](https://docs.nvidia.com/datacenter/tesla/fabric-manager-user-guide/index.html), a component that provides NVLink and NVSwitch support for multi-GPU VMs. In rare cases, its service, `nvidia-fabricmanager`, does not initialize on VM startup because of a race condition or other timing issues. This can cause initialization issues for CUDA and GPUs on the VM. However, CUDA initialization failures can also occur due to other reasons. 1. [Connect to the VM](https://docs.nebius.com/compute/virtual-machines/connect.md). 2. Run the following command: ```bash sudo systemctl status nvidia-fabricmanager ``` If the service is not running, the `Active` line in the output indicates that: ```text ○ nvidia-fabricmanager.service - NVIDIA fabric manager service Loaded: loaded (/lib/systemd/system/nvidia-fabricmanager.service; enabled; ven> Active: inactive (dead) since Fri 2025-05-23 07:37:49 UTC; 27s ago Main PID: 3240 (code=exited, status=0/SUCCESS) CPU: 787ms ``` ## Solutions You can solve the issue on your existing VM without having to create a new VM. Try the following steps in order: 1. Start the NVIDIA Fabric Manager service: 1. [Connect to the VM](https://docs.nebius.com/compute/virtual-machines/connect.md). 2. Run the following command: ```bash sudo systemctl start nvidia-fabricmanager ``` 3. Check whether starting the service worked. To do this, you can try running your workload or get diagnostic information about the GPUs on the VM. For example, use the [NVIDIA System Management Interface](https://docs.nvidia.com/deploy/nvidia-smi/index.html) (`nvidia-smi`) to get the fabric states and statuses of the GPUs: ```bash nvidia-smi -q | grep -A 2 'Fabric' ``` In the output, all the GPUs should be in the `Completed` fabric state and the `Success` status: ```bash Fabric State : Completed Status : Success -- Fabric State : Completed Status : Success ... ``` If this step has not worked, stay connected to the VM and proceed to the next step. 2. Restart the GPUs on the VM: If your VM is a [Managed Service for Kubernetes®](https://docs.nebius.com/kubernetes/index.md) node (that is, its name starts with `mk8snodegroup`), skip this step and proceed to the next step. 1. Stop the services and workloads that use the GPUs. For example, if you are not running any workloads on the VM, you only need to stop the monitoring services: ```bash sudo systemctl stop nebius_observability_agent sudo systemctl stop nvidia-dcgm.service ``` 2. Run the `nvidia-smi` command that restarts GPUs: ```bash sudo nvidia-smi -r ``` This may take several minutes. You should see the following output: ```text GPU 00000000:8D:00.0 was successfully reset. GPU 00000000:91:00.0 was successfully reset. GPU 00000000:95:00.0 was successfully reset. GPU 00000000:99:00.0 was successfully reset. GPU 00000000:AB:00.0 was successfully reset. GPU 00000000:AF:00.0 was successfully reset. GPU 00000000:B3:00.0 was successfully reset. GPU 00000000:B7:00.0 was successfully reset. Note: The operation has successfully reset all GPUs and NVSwitches. If the services, such as nvidia-fabricmanager, which manage or monitor NVSwitches are running, they might have been affected by this operation. Please refer respective service status or logs for details. All done. ``` 3. Start the stopped workloads and services again. For example, to start the monitoring services, run the following command: ```bash sudo systemctl start nvidia-dcgm.service sudo systemctl start nebius_observability_agent ``` 4. Check whether restarting the GPUs worked. For example, you can run your workload or use `nvidia-smi`: ```bash nvidia-smi -q | grep -A 2 'Fabric' ``` If the step has not worked, e.g. there are GPUs that are not in the `Completed` fabric state and the `Success` status, proceed to the next step. 3. [Restart the VM](https://docs.nebius.com/compute/virtual-machines/stop-start.md). After that, [connect to it](https://docs.nebius.com/compute/virtual-machines/connect.md) and then check whether restarting the VM worked. For example, you can run your workload or use `nvidia-smi`: ```bash nvidia-smi -q | grep -A 2 'Fabric' ``` If the step has not worked, e.g. there are GPUs that are not in the `Completed` fabric state and the `Success` status, [contact support](https://console.nebius.com/support/create-ticket). # Charging for a virtual machine that was stopped by using Linux commands Source: https://docs.nebius.com/compute/virtual-machines/stopped-with-linux-commands.md If you connect to your virtual machine (VM) and shut it down by using Linux commands (for example, `shutdown` or `halt`), the VM is not stopped properly. Compute automatically reboots the VM and continues charging you for it. The service considers such a shutdown as a failure and therefore runs the recovery policy. To stop a VM properly, use Nebius AI Cloud interfaces, for instance, the web console or a CLI command. Then, the VM is stopped reliably, and you are not charged for it. For more information, see [How to stop and start Compute virtual machines](https://docs.nebius.com/compute/virtual-machines/stop-start.md). # How to collect diagnostic logs from Compute virtual machines Source: https://docs.nebius.com/compute/virtual-machines/logs.md *Diagnostic logs* from Compute virtual machines (VMs) help you troubleshoot issues with VM operations, networking and workloads. We strongly recommend collecting logs while the issue is still occurring, because they capture more information about the broken state than logs collected after the issue has been resolved. ## Types of logs This guide describes how to collect the following types of logs for troubleshooting: * GPU logs: `nvidia-bug-report.sh`. * General system logs, including more context about system services and package versions: `sos report`. * [NVIDIA® Mellanox®](https://www.nvidia.com/en-us/networking/management-software/) adapter (InfiniBand™/NVSwitch/Ethernet) logs: `sysinfo-snapshot`. ## Prerequisites Make sure that you have configured [SSH access to the VM](https://docs.nebius.com/compute/virtual-machines/connect.md). ## How to collect logs 1. [Connect to the VM by using SSH](https://docs.nebius.com/compute/virtual-machines/connect.md#connect-to-the-vm-by-using-ssh). 2. Generate GPU logs: ```bash sudo nvidia-bug-report.sh ``` This command usually runs for about five minutes and generates `nvidia-bug-report.log.gz` in the current working directory. If the command stops responding, run it in safe mode: ```bash sudo nvidia-bug-report.sh --safe-mode ``` 3. If you need more system information, generate general system logs: ```bash sudo sos report --batch ``` This command generates an archive in the following format: `/tmp/sosreport---.tar.gz`. 4. If you are troubleshooting Mellanox adapter issues, generate Mellanox adapter logs: ```bash sudo /opt/nebius/sysinfo-snapshot ``` This command generates an archive in the following format: `/tmp/sysinfo-snapshot---.tgz`. ## How to get generated log files 1. Check that the files were generated on your VM by running the following commands: * To check for GPU logs: ```bash ls nvidia-bug-report.log.gz ``` * To check for general system logs or Mellanox adapter logs: ```bash ls /tmp ``` 2. From your local shell, run the following command to copy the files from the VM to the current directory: ```bash scp -i ~/.ssh/id_ed25519 @: . ``` In the command, specify the path to the generated file on the VM, for example: `nvidia-bug-report.log.gz`, `/tmp/sosreport-*.tar.gz` or `/tmp/sysinfo-snapshot-*.tgz`. If copying files from the `/tmp` directory fails due to a permission error, this usually means the generated file is owned by root. To fix this issue, proceed to the next step. 3. [Reconnect to the VM](https://docs.nebius.com/compute/virtual-machines/connect.md#connect-to-the-vm-by-using-ssh) and set permissions to grant read access to non-root users. After that, you can rerun the `scp` command. If you successfully copied the generated log file, skip this step. ```bash sudo chmod 644 ``` In the command, set the `remote_file_path` to `/tmp/sosreport-*.tar.gz` or `/tmp/sysinfo-snapshot-*.tgz`. 4. Find the copied log files in your local directory. ## See also * [How to inspect a VM and attach its boot disk to another VM](https://docs.nebius.com/compute/virtual-machines/inspect-boot-disk.md) * [Support tickets: sending questions, bug reports and feature requests](https://docs.nebius.com/overview/support.md) *InfiniBand and InfiniBand Trade Association are registered trademarks of the InfiniBand Trade Association.* # Virtual machine is unreachable due to a Docker subnet conflict Source: https://docs.nebius.com/compute/virtual-machines/docker-subnet-conflict.md Virtual machines (VMs) running Docker cannot reach remote private IPv4 addresses in the `172.17.0.0/16` CIDR block. If you assign an address from this range to a VM, other VMs that run Docker cannot reach this address. Since the default boot disk images come with Docker preinstalled, this affects most VMs in the [network](https://docs.nebius.com/vpc/overview.md#network). This happens because Docker uses `172.17.0.0/16` for its default bridge network and adds a kernel route for that range on every host where it runs. When a VM running Docker sends traffic to an address in this range, the route directs the packets to the local Docker bridge instead of the network interface, so they never leave the VM or reach the network. To resolve the conflict, do one of the following: * [Assign the VM a subnet](https://docs.nebius.com/vpc/addressing/custom-private-addresses.md) outside `172.17.0.0/16`. * Reconfigure the default Docker bridge to use a non-overlapping range. To do this, on every VM that runs Docker and needs to reach an address in `172.17.0.0/16`, add the following parameters to the [cloud-init configuration](https://docs.nebius.com/compute/virtual-machines/manage.md#optional-create-a-user-data-configuration): ```yaml write_files: - path: /etc/docker/daemon.json content: | { "bip": "192.168.200.1/24" } owner: root:root permissions: '0644' runcmd: - systemctl restart docker ``` The `bip` value sets the subnet of the default Docker bridge. Replace `192.168.200.1/24` with any range that does not overlap with the private IP addresses used in your network. For more information about configuring the default Docker bridge, see the [Docker bridge network driver](https://docs.docker.com/engine/network/drivers/bridge/) documentation. #### See also * [Private and public IP addresses of Compute virtual machines](https://docs.nebius.com/compute/virtual-machines/network.md) * [Ranges of private IP addresses per region for a default private pool](https://docs.nebius.com/vpc/addressing/available-addresses.md) # How to inspect a VM and attach its boot disk to another VM Source: https://docs.nebius.com/compute/virtual-machines/inspect-boot-disk.md If a virtual machine (VM) does not start or you cannot connect to it, you can attach its boot disk to another VM as a secondary disk and inspect the boot disk from there. To do this: 1. [Create a VM](https://docs.nebius.com/compute/virtual-machines/manage.md) for debugging in the same project as the boot disk you want to inspect. [Set up the SSH connection](https://docs.nebius.com/compute/virtual-machines/connect.md#set-up-the-vm) to your new VM. 2. [Stop the original VM](https://docs.nebius.com/compute/virtual-machines/stop-start.md#how-to-stop-and-start-vms-manually) that you want to inspect. Otherwise, you can't attach its boot disk to another VM. 3. Get the ID of the original VM's boot disk: ```bash nebius compute instance get --id \ --format jsonpath='.spec.boot_disk.existing_disk.id' ``` ```go originalInstance, err := sdk.Services().Compute().V1(). Instance().Get( ctx, &compute.GetInstanceRequest{ Id: "", }, ) if err != nil { return err } if originalInstance.GetSpec() == nil { return errors.New("instance spec is missing") } bootDisk := originalInstance.GetSpec().GetBootDisk() if bootDisk == nil || bootDisk.GetExistingDisk() == nil { return errors.New("boot disk is missing") } fmt.Println(bootDisk.GetExistingDisk().GetId()) ``` Save the boot disk ID from the output as `originalBootDiskID`. ```python instance_service = InstanceServiceClient(sdk) original_instance = await instance_service.get( GetInstanceRequest(id=""), ) if original_instance.spec is None: raise ValueError("instance spec is missing") boot_disk = original_instance.spec.boot_disk if boot_disk is None or boot_disk.existing_disk is None: raise ValueError("boot disk is missing") print(boot_disk.existing_disk.id) ``` Save the boot disk ID from the output as `original_boot_disk_id`. ```ts const getOriginalInstanceService = new InstanceService(sdk); const originalInstance = await getOriginalInstanceService.get( GetInstanceRequest.create({ id: "", }), ); const originalBootDisk = originalInstance.spec?.bootDisk; const bootDiskId = originalBootDisk?.type?.$case === "existingDisk" ? originalBootDisk.type.existingDisk.id : undefined; if (!bootDiskId) { throw new Error("boot disk is missing"); } console.log(bootDiskId); ``` Save the boot disk ID from the output as `originalBootDiskId`. 4. Attach the boot disk to the debug VM as a secondary disk: ```bash nebius compute instance update \ --patch \ --secondary-disks '[{"existing_disk": {"id": ""}, "attach_mode": "READ_WRITE", "device_id": "original-boot-disk"}]' ``` In the code, specify the debug VM ID and use the `originalBootDiskID` value from the previous step: ```go instance, err = sdk.Services().Compute().V1(). Instance().Get( ctx, &compute.GetInstanceRequest{ Id: "", }, ) if err != nil { return err } if instance.GetSpec() == nil { return errors.New("instance spec is missing") } instance.Spec.SecondaryDisks = []*compute.AttachedDiskSpec{ { AttachMode: compute.AttachedDiskSpec_READ_WRITE, Type: &compute.AttachedDiskSpec_ExistingDisk{ ExistingDisk: &compute.ExistingDisk{ Id: originalBootDiskID, }, }, DeviceId: "original-boot-disk", }, } instanceOperation, err = sdk.Services().Compute().V1(). Instance().Update( ctx, &compute.UpdateInstanceRequest{ Metadata: instance.Metadata, Spec: instance.Spec, }, ) if err != nil { return err } if _, err = instanceOperation.Wait(ctx); err != nil { return err } ``` In the code, specify the debug VM ID and use the `original_boot_disk_id` value from the previous step: ```python instance_service = InstanceServiceClient(sdk) instance = await instance_service.get( GetInstanceRequest(id=""), ) if instance.spec is None: raise ValueError("instance spec is missing") instance.spec.secondary_disks = [ AttachedDiskSpec( attach_mode=AttachedDiskSpec.AttachMode.READ_WRITE, existing_disk=ExistingDisk(id=original_boot_disk_id), device_id="original-boot-disk", ), ] attach_boot_disk_operation = await instance_service.update( UpdateInstanceRequest( metadata=instance.metadata, spec=instance.spec, ), ) await attach_boot_disk_operation.wait() ``` In the code, specify the debug VM ID and use the `originalBootDiskId` value from the previous step: ```ts const attachBootDiskService = new InstanceService(sdk); const instanceForBootDiskAttach = await attachBootDiskService.get( GetInstanceRequest.create({ id: "", }), ); if (!instanceForBootDiskAttach.spec) { throw new Error("instance spec is missing"); } instanceForBootDiskAttach.spec.secondaryDisks = [ AttachedDiskSpec.create({ attachMode: AttachedDiskSpec_AttachMode.READ_WRITE, deviceId: "original-boot-disk", type: { $case: "existingDisk", existingDisk: ExistingDisk.create({ id: originalBootDiskId, }), }, }), ]; const attachBootDiskOperation = await attachBootDiskService.update( UpdateInstanceRequest.create({ metadata: instanceForBootDiskAttach.metadata, spec: instanceForBootDiskAttach.spec, }), ).result; await attachBootDiskOperation.wait(); ``` 5. [Connect to the debug VM by using SSH](https://docs.nebius.com/compute/virtual-machines/connect.md#connect-to-the-vm-by-using-ssh). 6. List the partitions and filesystems on the boot disk: ```bash lsblk -o NAME,SIZE,FSTYPE,MOUNTPOINTS /dev/disk/by-id/virtio-original-boot-disk ``` 7. Mount the filesystem you need to inspect. The root filesystem is on the largest ext4 (or xfs) partition — usually `-part1`. To mount it: ```bash sudo mkdir -p /mnt/original-boot-disk sudo mount -o ro /dev/disk/by-id/virtio-original-boot-disk-part1 /mnt/original-boot-disk ``` For safety, use the `-o ro` parameter to mount the filesystem in read-only mode. This prevents any accidental changes to the boot disk you are inspecting. 8. (Optional) If you need to repair the filesystem by writing to it, remount it in read-write mode: ```bash sudo mount -o remount,rw /mnt/original-boot-disk ``` 9. When done inspecting, unmount the filesystem: ```bash sudo umount /mnt/original-boot-disk ``` 10. [Detach](https://docs.nebius.com/compute/storage/detach-volume.md#remove-the-volume-from-the-vm's-specification) the boot disk of the original VM from the debug VM. 11. After the disk is detached, [start the original VM](https://docs.nebius.com/compute/virtual-machines/stop-start.md#how-to-stop-and-start-vms-manually). You can't start the VM if its boot disk is attached to another running VM. ## See also * [How to collect diagnostic logs from Compute virtual machines](https://docs.nebius.com/compute/virtual-machines/logs.md) * [Viewing serial logs of virtual machines](https://docs.nebius.com/compute/monitoring/serial-logs.md) * [How to detach additional volumes from virtual machines](https://docs.nebius.com/compute/storage/detach-volume.md) * [Attaching and mounting Compute volumes to VMs](https://docs.nebius.com/compute/storage/use.md) # Deleting a Compute virtual machine Source: https://docs.nebius.com/compute/virtual-machines/delete.md If [standalone disks](https://docs.nebius.com/compute/storage/types.md#vm-managed-and-standalone-disks) or filesystems are attached to your virtual machine (VM), Compute doesn't automatically delete them. To stop being charged for volumes you no longer need, [delete](https://docs.nebius.com/compute/storage/manage.md#how-to-delete-a-volume) these volumes separately. If VM-managed disks are attached to your VM, they are deleted along with the VM automatically. Charges for these disks stop immediately. To delete a VM: 1. In the sidebar, go to **Compute** → **Virtual machines**. On the **Standalone VMs** tab, click the virtual machine you want to delete. 2. On the VM page, go to the **Settings** tab. 3. Click **Delete virtual machine**. 4. In the window that opens, confirm the deletion. 1. Get the ID of the virtual machine you want to delete: ```bash nebius compute instance list ``` 2. Delete the virtual machine: ```bash nebius compute instance delete ``` 1. Get the ID of the virtual machine you want to delete: ```go instances, err := sdk.Services().Compute().V1(). Instance().List( ctx, &compute.ListInstancesRequest{}, ) if err != nil { return err } fmt.Println(instances) ``` 2. Delete the virtual machine: ```go deleteFinalOperation, err := sdk.Services().Compute().V1(). Instance().Delete( ctx, &compute.DeleteInstanceRequest{ Id: "", }, ) if err != nil { return err } if _, err = deleteFinalOperation.Wait(ctx); err != nil { return err } ``` 1. Get the ID of the virtual machine you want to delete: ```python instance_service = InstanceServiceClient(sdk) instances = await instance_service.list(ListInstancesRequest()) print(instances) ``` 2. Delete the virtual machine: ```python instance_service = InstanceServiceClient(sdk) delete_final_operation = await instance_service.delete( DeleteInstanceRequest(id=""), ) await delete_final_operation.wait() ``` 1. Get the ID of the virtual machine you want to delete: ```ts const manageListInstanceService = new InstanceService(sdk); const listedInstances = await manageListInstanceService.list( ListInstancesRequest.create({}), ); console.log(listedInstances); ``` 2. Delete the virtual machine: ```ts const finalVmDeleteService = new InstanceService(sdk); const deleteFinalVmOperation = await finalVmDeleteService.delete( DeleteInstanceRequest.create({ id: "", }), ).result; await deleteFinalVmOperation.wait(); ``` # How to access VM metadata Source: https://docs.nebius.com/compute/virtual-machines/instance-metadata.md The *instance metadata service* (IMDS) provides information about a running virtual machine (VM), including metadata, labels, resources, user and network data. The legacy `/mnt/cloud-metadata` mount on older Nebius VM images is deprecated and will be removed on **September 30, 2026**. After that date, use only the HTTP-based IMDS described in this article. To migrate, replace any reads from `/mnt/cloud-metadata` with the equivalent HTTP requests to IMDS. ## How to access IMDS IMDS is available only from within a VM itself. Once you connect to a VM, use the following base URL to request metadata: ``` http://metadata.nebius.internal ``` All IMDS requests must use the `GET` method and include the `Metadata: true` header. Requests without this header return `400 Bad Request`. Requests that use any method other than `GET` return `405 Method Not Allowed`. ### Metadata updates IMDS provides metadata captured at VM start time. The following endpoints are not refreshed in real time: * `instance-data` * `parent-data` * `network-data` * `user-data` To get updated values from these endpoints after a change, stop and restart the VM. Unlike the other endpoints, `instance-events` provides live updates and does not require a VM restart. A maintenance event may take up to five minutes to appear in the response. ## Example requests The following examples show how to retrieve different types of metadata from IMDS. ### Getting all VM metadata To get all available VM metadata in JSON format, run: ```bash curl http://metadata.nebius.internal/v1/instance-data \ -H "Metadata: true" ``` Example output: ```json { "id": "computeinstance-***", "parent_id": "project-***", "name": "example-vm", "hostname": "example-hostname", "platform": "gpu-h200-sxm", "preset": "1gpu-16vcpu-200gb", "labels": { "env": "example-env", "runners_count": "24" }, "resource_version": 1, "created_at": "2025-11-11T08:03:31.754114Z", "service_account_id": "serviceaccount-***", "gpu_cluster_id": "computegpucluster-***", "infiniband_fabric": "fabric-5", "infiniband_topology_path": ["hash-1", "hash-2", "hash-3"], "region": "eu-west1" } ``` `labels` is always returned as a JSON object. If no labels were set, IMDS returns an empty object. The following fields are optional and are returned only when available for the VM: * `hostname` * `service_account_id` * `gpu_cluster_id` * `infiniband_fabric` * `infiniband_topology_path` ### Getting a specific metadata field To get a specific metadata field as plain text, run: ```bash curl http://metadata.nebius.internal/v1/instance-data/ \ -H "Metadata: true" ``` Example: ```bash curl http://metadata.nebius.internal/v1/instance-data/id \ -H "Metadata: true" ``` Example output: ``` computeinstance-*** ``` ### Getting VM labels To get all labels for the VM, run: ```bash curl http://metadata.nebius.internal/v1/instance-data/labels \ -H "Metadata: true" ``` Example output: ```json { "env": "example-env", "runners_count": "24" } ``` To get a specific label, run: ```bash curl http://metadata.nebius.internal/v1/instance-data/labels/ \ -H "Metadata: true" ``` Example: ```bash curl http://metadata.nebius.internal/v1/instance-data/labels/env \ -H "Metadata: true" ``` Example output: ``` example-env ``` ### Getting parent resource metadata To get parent resource metadata in JSON format, run: ```bash curl http://metadata.nebius.internal/v1/parent-data \ -H "Metadata: true" ``` Example output: ```json { "id": "project-***", "parent_id": "tenant-***", "name": "example-project", "created_at": "2025-11-11T08:03:30.754114Z", "labels": { "teamcity_build_id": "13672974" } } ``` To access `parent-data`, the VM must have an attached service account with permissions to read the parent resource metadata. Otherwise, the request returns `403 Forbidden`. ### Getting user data To get the user data that was provided when the VM was created, run: ```bash curl http://metadata.nebius.internal/v1/user-data \ -H "Metadata: true" ``` Example output: ```yaml #cloud-config package_update: true packages: - nginx runcmd: - systemctl enable --now nginx ``` ### Getting network data To get the VM network data, run: ```bash curl http://metadata.nebius.internal/v1/network-data \ -H "Metadata: true" ``` This request returns the network data that cloud-init used to initialize the VM during its first boot. Example output: ```yaml version: 2 ethernets: interface0: match: macaddress: "XX:XX:XX:XX:XX:XX" set-name: "eth0" dhcp4: true mtu: 1450 ``` ### Getting service account information To get information about the service account attached to the VM and its IAM token, run: ```bash curl http://metadata.nebius.internal/v1/iam/sa \ -H "Metadata: true" ``` Example output: ```json { "service_account_id": "serviceaccount-***", "token": { "access_token": "", "expires_at": "2027-01-01T00:00:00Z" } } ``` To get only the IAM token object (the access token and its expiration time), run: ```bash curl http://metadata.nebius.internal/v1/iam/sa/token \ -H "Metadata: true" ``` Example output: ```json { "access_token": "", "expires_at": "2027-01-01T00:00:00Z" } ``` To get only the raw access token string, run: ```bash curl http://metadata.nebius.internal/v1/iam/sa/token/access_token \ -H "Metadata: true" ``` Example output: ``` ``` ### Getting maintenance events To check if a maintenance event is scheduled for the VM, run: ```bash curl http://metadata.nebius.internal/v1/instance-events \ -H "Metadata: true" ``` Example output: ```json { "data": [ { "id": "computemaintenance-***", "type": "maintenance", "status": "scheduled", "created_at": "2026-02-28T15:10:00Z", "not_before": "2026-03-01T10:00:00Z", "extra": { "support_center_ticket_id": "123456", "is_planned": "false" } } ] } ``` If there are no active maintenance events, IMDS returns an empty array: ```json { "data": [] } ``` ## Request throttling Nebius AI Cloud applies throttling to IMDS requests on a per-VM basis to reduce accidental overload and abuse: * 10 requests per second for regular requests * 20 requests per second for burst requests If you exceed the limit, IMDS returns `429 Too Many Requests`. ## Status codes | HTTP status code | Description | | --------------------------- | ------------------------------------------------------------------------------------------------------------- | | `200 OK` | The request succeeded. | | `400 Bad Request` | The `Metadata: true` header is missing or invalid. | | `403 Forbidden` | The VM does not have permission to access the requested resource. | | `404 Not Found` | The requested resource or field does not exist. | | `405 Method Not Allowed` | The request used a method other than `GET`. | | `429 Too Many Requests` | The request rate limit was exceeded. Retry the request. | | `500 Internal Server Error` | The server encountered an error. Retry the request. | | `501 Not Implemented` | The requested feature is not implemented. | | `503 Service Unavailable` | The service is temporarily unavailable, or the request could not be attributed to this VM. Retry the request. | # Quotas in Compute Source: https://docs.nebius.com/compute/resources/quotas-limits.md Compute has quotas on virtual machines (VMs), storage and InfiniBand™ usage. For details on what quotas are and how to manage them, see [Quotas in Nebius AI Cloud](https://docs.nebius.com/overview/quotas.md). ## Virtual machines A VM and its resources count towards the quotas throughout the VM's lifecycle, from its creation to deletion, regardless of whether it is running or stopped. These quotas apply to Compute VMs and also to Managed Service for Soperator and Managed Service for Kubernetes® nodes, which are based on Compute VMs. Compute has different quotas for GPU and non-GPU virtual machines. ### GPU virtual machines The default quota values depend on the [region](https://docs.nebius.com/overview/regions.md) in which you create GPU VMs. Private regions are marked with \*. | Quota name | Default value,
`eu-north1` | Default value,
`eu-west1` | Default value,
`me-west1` | Default value,
`us-central1` | Default value,
`uk-south1` | Default value,
`eu-north2`\* | Default value,
`eu-west2`\* | | ---------------------------------------------------------------------- | ------------------------------- | ------------------------------ | ------------------------------ | --------------------------------- | ------------------------------- | -------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------- | | [Regular VMs](https://docs.nebius.com/compute/virtual-machines/manage.md) | 12 | 12 | 12 | 12 | 12 | 0 | 12 | | [Preemptible VMs](https://docs.nebius.com/compute/virtual-machines/preemptible.md) | 8 | 8 | 8 | 8 | 8 | 0 | 8 | | Total number of NVIDIA® B300 GPUs for regular VMs without reservations | *N/A* | *N/A* | *N/A* | *N/A* | 32 | *N/A* | 32 | | Total NVIDIA® B200 GPUs for regular VMs without reservations | *N/A* | *N/A* | 0 | 0 | *N/A* | *N/A* | *N/A* | | Total NVIDIA® H200 GPUs for regular VMs without reservations | 32 | 8 | *N/A* | 0 | *N/A* | 0 | *N/A* | | Total NVIDIA® H100 GPUs for regular VMs without reservations | 32 | *N/A* | *N/A* | *N/A* | *N/A* | *N/A* | *N/A* | | Total NVIDIA® RTX PRO™ 6000 GPUs for regular VMs without reservations | *N/A* | *N/A* | *N/A* | 0 | *N/A* | *N/A* | *N/A* | | Total NVIDIA® L40S GPUs for regular VMs without reservations | 2 | *N/A* | *N/A* | *N/A* | *N/A* | *N/A* | *N/A* | ### Non-GPU virtual machines | Quota name | Default value,
`eu-north1`,
`eu-west1`,
`me-west1`,
`uk-south1`,
`us-central1`,
`eu-west2`\* | Default value,
`eu-north2`\* | | ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------- | | Virtual machines | 12 | 0 | | Total vCPUs across non-GPU VMs | 200 | 0 | ## Storage | Quota name | Default value,
`eu-north1` | Default value,
`eu-west1` | Default value,
`us-central1`,
`me-west1`,
`uk-south1`,
`eu-west2`\* | Default value,
`eu-north2`\* | | ------------------------------------------------ | ------------------------------- | ------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------- | | Disks | 32 | 32 | 32 | 0 | | Total disk capacity (Network SSD) | 4 TiB | 2 TiB | 5 TiB | 0 | | Total disk capacity (Network SSD Non-replicated) | 4 TiB | 2 TiB | 5 TiB | 0 | | Total disk capacity (Network SSD IO M3) | 4 TiB | 2 TiB | 5 TiB | 0 | | Shared filesystems | 32 | 32 | 32 | 0 | | Total shared filesystem capacity | 4 TiB | 2 TiB | 5 TiB | 0 | | Number of images | 0 | 0 | 0 | 0 | | Total storage capacity of all images | 0 | 0 | 0 | 0 | | Total number of disk snapshots | 0 | 0 | 0 | 0 | | Total storage capacity of all disk snapshots | 0 | 0 | 0 | 0 | ## InfiniBand GPU cluster quotas apply to Compute GPU clusters and GPU clusters used by Managed Soperator or Managed Kubernetes. | Quota name | Default value,
`eu-north1`,
`eu-west1`,
`me-west1`,
`us-central1`,
`uk-south1`,
`eu-west2`\* | Default value,
`eu-north2`\* | | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------- | | Number of GPU clusters | 5 | 0 | ## Network See [Quotas in Virtual Networks](https://docs.nebius.com/vpc/resources/quotas-limits.md). ## Quota usage recommendations Best practices for using VM quotas: * When you create new VMs, calculate your available quotas, even if you plan to keep the VMs mostly in a stopped state. * From time to time, review and delete unused VMs to free up quotas. * If you need to temporarily free up VM resources, delete VMs instead of just stopping them. *** *InfiniBand and InfiniBand Trade Association are registered trademarks of the InfiniBand Trade Association.* # Compute pricing in Nebius AI Cloud Source: https://docs.nebius.com/compute/resources/pricing.md This article provides detailed pricing for the Compute service in Nebius AI Cloud. ## How charges and prices work Each group of chargeable items in this article has two time units associated with it: * **Billing unit**: The minimum unit of usage for which you can be charged. * **Pricing unit**: The unit of usage for which the prices are shown. Charges for units smaller than the pricing unit are calculated proportionally. > For example, for GPUs on running VMs, the **billing unit** is 1 second, and the **pricing unit** is 1 hour (3600 seconds). For 30 minutes of usage, you will be charged half the hourly price. Prices in US dollars (USD, \$) apply to all customers except for companies from Israel, where prices in Israeli shekels (ILS, ₪) apply instead. All prices are shown without any applicable taxes, including VAT. Due to rounding errors, usage costs shown in the web console and final charges may slightly differ from calculations based on the prices in this article. ## Prices ### Virtual machines (GPUs, vCPUs, RAM) You are charged for computing resources (GPUs, vCPUs, RAM) of running virtual machines (VMs). Computing resources of stopped VMs are not charged (this does not apply to storage volumes; see [Volumes (disks and shared filesystems)](https://docs.nebius.com/compute/resources/pricing.md#volumes)). * **Billing unit**: 1 second * **Pricing unit**: 1 hour (3600 seconds) #### NVIDIA® B300 NVLink, gpu-b300-sxm The platform is only available in the `uk-south1` and `eu-west2`\* [regions](https://docs.nebius.com/overview/regions.md). | **Item** | **Price** | **Per** | | ------------------------------- | --------- | ---------- | | NVIDIA® B300 NVLink | \$7.85 | 1 GPU hour | | Preemptible NVIDIA® B300 NVLink | \$4.30 | 1 GPU hour | | **Item** | **Price** | **Per** | | ------------------------------- | --------- | ---------- | | NVIDIA® B300 NVLink | ₪24.335 | 1 GPU hour | | Preemptible NVIDIA® B300 NVLink | ₪13.33 | 1 GPU hour | #### NVIDIA® B200 NVLink, gpu-b200-sxm The platform is only available in the `us-central1` [region](https://docs.nebius.com/overview/regions.md). | **Item** | **Price** | **Per** | | ------------------------------- | --------- | ---------- | | NVIDIA® B200 NVLink | \$7.15 | 1 GPU hour | | Preemptible NVIDIA® B200 NVLink | \$3.95 | 1 GPU hour | | **Item** | **Price** | **Per** | | ------------------------------- | --------- | ---------- | | NVIDIA® B200 NVLink | ₪22.165 | 1 GPU hour | | Preemptible NVIDIA® B200 NVLink | ₪12.245 | 1 GPU hour | #### NVIDIA® B200 NVLink, gpu-b200-sxm-a The platform is only available in the `me-west1` [region](https://docs.nebius.com/overview/regions.md). | **Item** | **Price** | **Per** | | ------------------------------- | --------- | ---------- | | NVIDIA® B200 NVLink | \$7.15 | 1 GPU hour | | Preemptible NVIDIA® B200 NVLink | \$3.95 | 1 GPU hour | | **Item** | **Price** | **Per** | | ------------------------------- | --------- | ---------- | | NVIDIA® B200 NVLink | ₪22.165 | 1 GPU hour | | Preemptible NVIDIA® B200 NVLink | ₪12.245 | 1 GPU hour | #### NVIDIA® H200 NVLink The platform is available in the `eu-north1`, `eu-north2`\*, `eu-west1` and `us-central1` [regions](https://docs.nebius.com/overview/regions.md). | **Item** | **Price** | **Per** | | ------------------------------- | --------- | ---------- | | NVIDIA® H200 NVLink | \$4.50 | 1 GPU hour | | Preemptible NVIDIA® H200 NVLink | \$2.45 | 1 GPU hour | | **Item** | **Price** | **Per** | | ------------------------------- | --------- | ---------- | | NVIDIA® H200 NVLink | ₪13.95 | 1 GPU hour | | Preemptible NVIDIA® H200 NVLink | ₪7.595 | 1 GPU hour | #### NVIDIA® H100 NVLink The platform is only available in the `eu-north1` [region](https://docs.nebius.com/overview/regions.md). | **Item** | **Price** | **Per** | | ------------------------------- | --------- | ---------- | | NVIDIA® H100 NVLink | \$3.85 | 1 GPU hour | | Preemptible NVIDIA® H100 NVLink | \$2.15 | 1 GPU hour | | **Item** | **Price** | **Per** | | ------------------------------- | --------- | ---------- | | NVIDIA® H100 NVLink | ₪11.935 | 1 GPU hour | | Preemptible NVIDIA® H100 NVLink | ₪6.665 | 1 GPU hour | #### NVIDIA® RTX PRO™ 6000 The platform is only available in the `us-central1` [region](https://docs.nebius.com/overview/regions.md). | **Item** | **Price** | **Per** | | --------------------------------- | --------- | ---------- | | NVIDIA® RTX PRO™ 6000 | \$1.80 | 1 GPU hour | | Preemptible NVIDIA® RTX PRO™ 6000 | \$0.95 | 1 GPU hour | | **Item** | **Price** | **Per** | | --------------------------------- | --------- | ---------- | | NVIDIA® RTX PRO™ 6000 | ₪5.58 | 1 GPU hour | | Preemptible NVIDIA® RTX PRO™ 6000 | ₪2.945 | 1 GPU hour | #### NVIDIA® L40S Intel The platform is only available in the `eu-north1` [region](https://docs.nebius.com/overview/regions.md). | **Item** | **Price** | **Per** | | ----------------------------------- | --------- | ---------- | | NVIDIA® L40S Intel. GPU | \$1.35 | 1 GPU hour | | NVIDIA® L40S Intel. CPU | \$0.012 | 1 CPU hour | | NVIDIA® L40S Intel. RAM | \$0.0032 | 1 GiB hour | | Preemptible NVIDIA® L40S Intel. GPU | \$0.65 | 1 GPU hour | | Preemptible NVIDIA® L40S Intel. CPU | \$0.006 | 1 CPU hour | | Preemptible NVIDIA® L40S Intel. RAM | \$0.0016 | 1 GiB hour | | **Item** | **Price** | **Per** | | ----------------------------------- | --------- | ---------- | | NVIDIA® L40S Intel. GPU | ₪4.185 | 1 GPU hour | | NVIDIA® L40S Intel. CPU | ₪0.0372 | 1 CPU hour | | NVIDIA® L40S Intel. RAM | ₪0.00992 | 1 GiB hour | | Preemptible NVIDIA® L40S Intel. GPU | ₪2.015 | 1 GPU hour | | Preemptible NVIDIA® L40S Intel. CPU | ₪0.0186 | 1 CPU hour | | Preemptible NVIDIA® L40S Intel. RAM | ₪0.00496 | 1 GiB hour | #### NVIDIA® L40S AMD The platform is only available for projects in the `eu-north1` [region](https://docs.nebius.com/overview/regions.md). | **Item** | **Price** | **Per** | | --------------------------------- | --------- | ---------- | | NVIDIA® L40S AMD. GPU | \$1.35 | 1 GPU hour | | NVIDIA® L40S AMD. CPU | \$0.01 | 1 CPU hour | | NVIDIA® L40S AMD. RAM | \$0.0032 | 1 GiB hour | | Preemptible NVIDIA® L40S AMD. GPU | \$0.65 | 1 GPU hour | | Preemptible NVIDIA® L40S AMD. CPU | \$0.005 | 1 CPU hour | | Preemptible NVIDIA® L40S AMD. RAM | \$0.0016 | 1 GiB hour | | **Item** | **Price** | **Per** | | --------------------------------- | --------- | ---------- | | NVIDIA® L40S AMD. GPU | ₪4.185 | 1 GPU hour | | NVIDIA® L40S AMD. CPU | ₪0.031 | 1 CPU hour | | NVIDIA® L40S AMD. RAM | ₪0.00992 | 1 GiB hour | | Preemptible NVIDIA® L40S AMD. GPU | ₪2.015 | 1 GPU hour | | Preemptible NVIDIA® L40S AMD. CPU | ₪0.0155 | 1 CPU hour | | Preemptible NVIDIA® L40S AMD. RAM | ₪0.00496 | 1 GiB hour | #### Non-GPU AMD Epyc Genoa The platform is available in all [regions](https://docs.nebius.com/overview/regions.md). | **Item** | **Price** | **Per** | | --------------------------- | --------- | ---------- | | Non-GPU AMD Epyc Genoa. CPU | \$0.012 | 1 CPU hour | | Non-GPU AMD Epyc Genoa. RAM | \$0.0032 | 1 GiB hour | | **Item** | **Price** | **Per** | | --------------------------- | --------- | ---------- | | Non-GPU AMD Epyc Genoa. CPU | ₪0.0372 | 1 CPU hour | | Non-GPU AMD Epyc Genoa. RAM | ₪0.00992 | 1 GiB hour | #### Non-GPU Intel Ice Lake The platform is only available in the `eu-north1` [region](https://docs.nebius.com/overview/regions.md). | **Item** | **Price** | **Per** | | --------------------------- | --------- | ---------- | | Non-GPU Intel Ice Lake. CPU | \$0.012 | 1 CPU hour | | Non-GPU Intel Ice Lake. RAM | \$0.0032 | 1 GiB hour | | **Item** | **Price** | **Per** | | --------------------------- | --------- | ---------- | | Non-GPU Intel Ice Lake. CPU | ₪0.0372 | 1 CPU hour | | Non-GPU Intel Ice Lake. RAM | ₪0.00992 | 1 GiB hour | ### Volumes You are charged for existing volumes (disks, disk snapshots and shared filesystems), regardless of whether they are added to VMs. Charges are based on volume sizes, regardless of how much space is taken up on a volume. * **Billing unit**: 1 byte per 1 second * **Pricing unit**: 1 GiB per 730 hours (230 bytes per 2,628,000 seconds \~ 1 month) #### Disks | **Item** | **Price per 1 GiB per 730 hours** | | ------------------------------- | --------------------------------- | | Network SSD disk | \$0.071 | | Network SSD Non-replicated disk | \$0.053 | | Network SSD IO M3 disk | \$0.118 | | **Item** | **Price per 1 GiB per 730 hours** | | ------------------------------- | --------------------------------- | | Network SSD disk | ₪0.221 | | Network SSD Non-replicated disk | ₪0.164 | | Network SSD IO M3 disk | ₪0.366 | #### Disk snapshots | **Item** | **Price per 1 GiB per 730 hours** | | ------------- | --------------------------------- | | Disk snapshot | \$0.071 | | **Item** | **Price per 1 GiB per 730 hours** | | ------------- | --------------------------------- | | Disk snapshot | ₪0.22 | #### Shared filesystems | **Item** | **Price per 1 GiB per 730 hours** | | --------------------- | --------------------------------- | | Shared Filesystem SSD | \$0.08 | | **Item** | **Price per 1 GiB per 730 hours** | | --------------------- | --------------------------------- | | Shared Filesystem SSD | ₪0.248 | #### Local SSD disks | **Item** | **Price per 1 GiB per 730 hours** | | -------------- | --------------------------------- | | Local SSD disk | \$0.065 | | **Item** | **Price per 1 GiB per 730 hours** | | -------------- | --------------------------------- | | Local SSD disk | ₪0.2015 | Local SSD disks have finite write endurance defined by the manufacturer's Terabytes Written (TBW) rating. Workloads should not write more than the disk's total capacity per day. If a workload writes more data to a local SSD disk in a single day than the disk's total capacity, it exceeds the recommended write-endurance threshold. If you expect your workload to exceed this threshold, [contact support](https://console.nebius.com/support/create-ticket) in advance to discuss capacity planning. ### Slurm and Soperator in Nebius AI Cloud # Slurm and Soperator in Nebius AI Cloud Source: https://docs.nebius.com/slurm-soperator/index.md Soperator is an [open-source solution from Nebius](https://github.com/nebius/soperator) that allows you to consolidate Slurm and Kubernetes® into a single infrastructure. You can manage nodes by using standard Kubernetes resources and run machine learning experiments by using Slurm. You can use Soperator in the following different environments: * [Managed Service for Soperator](https://docs.nebius.com/slurm-soperator/deploy/overview.md#managed-service-for-soperator): Nebius AI Cloud service * [Pro Solution for Soperator](https://docs.nebius.com/slurm-soperator/deploy/overview.md#pro-solution-for-soperator): deployed by Nebius solution architects on Nebius AI Cloud * [Self-deployment on a Managed Service for Kubernetes cluster](https://docs.nebius.com/slurm-soperator/deploy/overview.md#self-deployment-in-nebius-ai-cloud) * [Other cloud platforms and on-premises](https://docs.nebius.com/slurm-soperator/deploy/overview.md#self-deployment-on-other-platforms-and-on-premises) *InfiniBand and InfiniBand Trade Association are registered trademarks of the InfiniBand Trade Association.* Get acquainted with key Soperator features Choose a deployment method that fits your use case best Get started with Slurm and Soperator in Nebius AI Cloud with minimum effort Connect to login and worker nodes, so you can start managing machine learning workloads Define, configure and launch your workloads in Slurm View and control current and historical jobs Check the NVLink and InfiniBand™ performance between GPUs on one or multiple nodes Create users, so they can connect to Slurm nodes Get up-to-date information about Slurm jobs and nodes Reuse reserved GPU capacity across training and inference workloads # Combining Slurm and Kubernetes by using Soperator Source: https://docs.nebius.com/slurm-soperator/overview/why-slurm-soperator.md [Slurm](https://slurm.schedmd.com) is widely used for managing machine learning (ML) workloads. It is dedicated to efficient resource management, allowing you to split large jobs into many steps, then run them in parallel for distributed ML training. But Slurm is not cloud-native. [Kubernetes®](https://kubernetes.io/) complements Slurm, as it provides auto-scaling and self-healing capabilities. However, Kubernetes is not tailored to model training needs. Features that Slurm and Kubernetes provide could be combined for an optimal solution. [Soperator](https://github.com/nebius/soperator) is an open-source Kubernetes operator that solves this problem. It runs Slurm nodes as Kubernetes Pods. A Soperator cluster is based on a Kubernetes cluster and uses Slurm as an additional infrastructure layer. Nebius AI Cloud offers [options to deploy Soperator clusters](https://docs.nebius.com/slurm-soperator/deploy/overview.md) that provide high availability and automatic scaling, to save computing resources and costs. ## Features of a Soperator cluster ### Easy scaling Thanks to the Kubernetes infrastructure layer, a Soperator cluster scales automatically to your current workload. This allows you to have sufficient resources during the compute-heavy stages of building your project and scale down when you do not need to use — and pay for — as much computing power. ### High availability The underlying Kubernetes cluster already has self-healing capabilities, such as automatic Pod restart. In addition, Soperator continuously monitors the state of the cluster and compares it to the configuration declared in the YAML manifests of Kubernetes resources. If there are any discrepancies, Soperator restores the configuration. ### Unified storage All login and worker nodes share the same root filesystem. This lets you work with a Soperator cluster in the same way as with other Slurm installations, such as an on-premises cluster. For example, you can run jobs with `sbatch` without any need to run each job in a container. With the shared filesystem, you do not need to keep nodes synchronized, because they have an identical state by default. The changes that you make on one node are spread across all other nodes. For example, these changes can include the installation of packages, the download of datasets or adding Linux users. ### Secure environment User actions are isolated in a dedicated container-like environment. This ensures that users cannot accidentally interfere with the cluster configuration. ### Out-of-the-box solution Soperator clusters are provisioned with all necessary software pre-installed and ready to use. The software versions have been thoroughly tested and work together, to ensure optimal performance. However, if you have specific requirements, you can change software versions. The configuration of the Slurm cluster is also fine-tuned and does not require additional setup on your side. In Nebius AI Cloud, you can deploy a managed Soperator cluster in just a few clicks, or apply for a professional solution from Nebius for larger or enterprise-scale GPU workloads. For more details, see [Deploying Soperator clusters](https://docs.nebius.com/slurm-soperator/deploy/overview.md). ### Automated health checks Soperator regularly runs the following health checks: 1. Quick checks that use Slurm's [HealthCheckProgram](https://slurm.schedmd.com/slurm.conf.html#OPT_HealthCheckProgram). They check that there are no critical software or hardware issues. 2. Longer checks that run [NVIDIA® Collective Communications Library (NCCL) tests](https://github.com/NVIDIA/nccl-tests) as regular Slurm jobs. They check GPU performance and drain nodes that do not meet the test benchmark. 3. Slurm [Prolog and Epilog](https://slurm.schedmd.com/prolog_epilog.html) scripts. They perform GPU health checks before and after each Slurm job runs. 4. Compute maintenance events. They monitor all GPU and InfiniBand™ devices for errors. Soperator uses maintenance events for Slurm and automatically replaces all faulty nodes. ### Monitoring You can monitor the performance and status of various parts of the system: * Underlying Kubernetes cluster metrics, including node metrics, Pod resource metrics and all event logs. * Slurm metrics, including job queue size, job statuses, node states and resource consumption. * GPU (NVIDIA DCGM) metrics. ## See also * [Soperator cluster architecture](https://docs.nebius.com/slurm-soperator/overview/architecture.md). * [Explaining Soperator, Nebius' open-source Kubernetes operator for Slurm](https://nebius.com/blog/posts/soperator-in-open-source-explained) in the Nebius blog. *** *InfiniBand and InfiniBand Trade Association are registered trademarks of the InfiniBand Trade Association.* # Soperator cluster architecture Source: https://docs.nebius.com/slurm-soperator/overview/architecture.md Soperator deploys Slurm to Kubernetes® clusters. In a Soperator cluster, Slurm nodes, storage and other components are Kubernetes resources: Pods, PersistentVolumes, etc. The diagram below outlines the architecture of a Soperator cluster: soperator-architecture ## Cluster specification and Slurm configuration When Soperator is installed in a Kubernetes cluster, it adds the SlurmCluster [custom resource](https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/) to it. This resource contains the specification of the Slurm cluster deployed in the Kubernetes cluster. The Slurm operator itself is a Pod that uses the SlurmCluster specification to create and reconcile the Kubernetes resources in the Slurm cluster, such as login, worker and controller nodes, and storage resources. The configuration files of Slurm itself (`slurm.conf`, `gres.conf`, `cgroup.conf`, `plugstack.conf`, etc.) are [Kubernetes ConfigMaps](https://kubernetes.io/docs/concepts/configuration/configmap/) controlled by the Slurm operator. ## Nodes In Soperator clusters, all Slurm nodes are Kubernetes Pods. The main [types of Slurm nodes](https://slurm.schedmd.com/quickstart_admin.html#nodes) in Soperator clusters are the following: * [Login nodes](https://docs.nebius.com/slurm-soperator/overview/architecture.md#login-node) provide users with access to the cluster. * [Worker nodes](https://docs.nebius.com/slurm-soperator/overview/architecture.md#worker-node) execute Slurm jobs. * [Controller nodes](https://docs.nebius.com/slurm-soperator/overview/architecture.md#controller-node) manage scheduling and orchestration. For simplicity, there are nodes that are not represented on the diagram in this article, for example, [DBD (database daemon) nodes](https://slurm.schedmd.com/quickstart_admin.html#dbd) for accounting, nodes that export metrics, nodes that other Kubernetes operators manage for backups and auto-healing. ### Login nodes To work with a Slurm (submit jobs, check their status, write `sbatch` scripts and prepare data for them, etc.), users connect to its *login nodes*. The `sshd` daemon runs on every login node. Soperator balances load between login nodes — each time a user connects to the cluster via SSH, they are directed to a random login node. ### Worker nodes *Worker nodes*, also known as *compute nodes*, perform computations for Slurm jobs. The [slurmd](https://slurm.schedmd.com/slurmd.html) daemon runs on every worker node. It monitors, launches and terminates jobs. For more information on how to work with login and worker nodes, see [Connecting to login and worker nodes](https://docs.nebius.com/slurm-soperator/clusters/connect.md). ### Controller nodes *Controller nodes* orchestrate Slurm activities, such as job queuing, monitoring node states and allocating resources. The central management daemon, [slurmctld](https://slurm.schedmd.com/slurmctld.html), runs on all controller nodes. ## Persistent storage Soperator's main storage feature is its *shared root filesystem*. It is mounted to all login and worker nodes in a special way — you see it as the root directory (`/`) in your SSH sessions and Slurm jobs. This helps maintain the traditional Slurm user experience where you work with the entire root filesystem on each node. The filesystem is shared, which means you do not need to keep it identical across nodes manually. When you make changes to the filesystem on one node, these changes automatically show up on other nodes. The shared root filesystem is implemented as a Kubernetes [PersistentVolume](https://kubernetes.io/docs/concepts/storage/persistent-volumes/) (PV) that ensures data is preserved when nodes restart. Soperator also uses PVs for system needs, like storing cluster and controller states, etc. ## Ephemeral storage [Local SSD disks](https://docs.nebius.com/compute/storage/types.md#local-ssd-disks) are available on [supported platforms, presets and regions](https://docs.nebius.com/compute/storage/local-disks.md#availability). Unlike the shared root filesystem, local SSD disks are added to an individual node and are not shared across the cluster. Use local SSD disks for data that can be recreated and benefits from high performance and low latency, such as scratch space, caches and intermediate files created by Slurm jobs. For durable or shared data, consider using persistent storage. ## See also For more information about the Soperator cluster architecture, see: * [Architecture](https://github.com/nebius/soperator/blob/dev/docs/architecture.md) in Soperator's GitHub repository. * [Explaining Soperator, Nebius' open-source Kubernetes operator for Slurm](https://nebius.com/blog/posts/soperator-in-open-source-explained) in the Nebius blog. # Deploying Soperator clusters Source: https://docs.nebius.com/slurm-soperator/deploy/overview.md Nebius AI Cloud offers two managed Slurm solutions powered by Soperator: Managed Service for Soperator and Pro Solution for Soperator. You can also deploy Soperator manually on a Managed Service for Kubernetes® cluster or on other cloud platforms. ## Nebius AI Cloud managed solutions If you share reserved GPU capacity between Soperator training workloads and inference in Managed Service for Kubernetes, see [Ephemeral nodes in Soperator](https://docs.nebius.com/slurm-soperator/capacity/ephemeral-nodes.md). ### Managed Service for Soperator Managed Service for Soperator allows you to deploy a Soperator cluster in any Nebius AI Cloud region with just a few clicks. The service takes care of the underlying infrastructure so that you can get started with Slurm and Soperator with minimum effort. GPU worker nodes in Soperator are only available if you have [capacity block groups](https://docs.nebius.com/overview/limits/capacity-block-groups.md) that reserve GPUs. For deployment steps, see [Creating and deleting Soperator clusters in Managed Service for Soperator](https://docs.nebius.com/slurm-soperator/managed-soperator/manage.md). For pricing and quotas, see [Pricing in Managed Service for Soperator](https://docs.nebius.com/slurm-soperator/managed-soperator/resources/pricing.md) and [Quotas in Managed Service for Soperator](https://docs.nebius.com/slurm-soperator/managed-soperator/resources/quotas.md). ### Pro Solution for Soperator Pro Solution for Soperator is an expert-run solution from Nebius for customized or enterprise-scale GPU workloads. Our team of high-performance computing experts assists you with deploying a Soperator cluster and your applications on it. Depending on the scope and nature of your usage, Pro Solution for Soperator offers contracts with reserved capacity and discounted pricing. To sign up for Pro Solution for Soperator, [contact sales](https://nebius.com/services/soperator#ai-contact-form). ## Self-deployment in Nebius AI Cloud If you want to manually deploy a Soperator cluster in Nebius AI Cloud, you can use the [Terraform recipe](https://github.com/nebius/nebius-solution-library/tree/main/soperator) from the Nebius solution library. The recipe creates a [Managed Service for Kubernetes](https://docs.nebius.com/kubernetes/index.md) cluster with Soperator and all additional Nebius AI Cloud resources, such as networks and shared filesystems. You can change settings in the recipe according to your needs. ## Self-deployment on other platforms and on-premises You can install Soperator on any Kubernetes cluster that you deployed on a cloud platform or on-premises. For details, see [Soperator's GitHub repository](https://github.com/nebius/soperator/blob/main/docs/self-deploy.md). Soperator has not been tested on platforms other than Nebius AI Cloud. If you experience a problem when installing or using it, create an [issue in the GitHub repository](https://github.com/nebius/soperator/issues). # Ephemeral nodes in Soperator Source: https://docs.nebius.com/slurm-soperator/capacity/ephemeral-nodes.md If you run both training and inference workloads on reserved GPU capacity, you can move nodes between them without taking down the entire Soperator cluster. *Ephemeral nodes* let you release specific worker nodes from a Soperator cluster and reuse the same [capacity block group](https://docs.nebius.com/overview/limits/capacity-block-groups.md) for other workloads, such as inference in a separate Managed Service for Kubernetes® cluster. Without ephemeral nodes, resizing a Soperator cluster to free GPUs for inference usually requires support-assisted operations. That process is slow, does not let you choose which nodes are removed and can interrupt running jobs or cause full-cluster downtime. Ephemeral nodes help you: * Reuse reserved GPU capacity across training and inference instead of buying pay-as-you-go capacity when demand shifts. * Release or add specific worker nodes without stopping the entire Soperator cluster. * Choose which nodes to deprovision, starting with idle nodes when possible. * Move capacity on your own schedule, without waiting for support to resize the cluster. Ephemeral nodes are available in Soperator clusters running version 3.0 or later. Nebius must also enable this feature in your cluster. ## How ephemeral nodes work Ephemeral nodes rely on a shared [capacity block group](https://docs.nebius.com/overview/limits/capacity-block-groups.md). A capacity block reserves a fixed number of GPUs in a region. Workloads that use the same capacity block draw GPUs from that pool. In the typical setup, you have two Managed Service for Kubernetes clusters that share one capacity block: * A **training cluster** that runs [Managed Service for Soperator](https://docs.nebius.com/slurm-soperator/managed-soperator/manage.md). * An **inference cluster** that runs inference workloads in one or more [node groups](https://docs.nebius.com/kubernetes/node-groups/manage.md). When you deprovision worker nodes in the Soperator cluster, those GPUs are released back to the capacity block. You can then assign them to an inference node group that uses the same capacity block. The reverse flow applies when you move capacity from inference back to training. Both clusters must use the same capacity block group and GPU platform. If you are not sure how your capacity is set up, check the **Capacity block groups** tab on the **Limits** page in the [web console](https://console.nebius.com) or contact your Nebius manager. ## Deployment scenarios How you move capacity depends on how your training and inference workloads are deployed. In both cases, GPUs move through the shared capacity block: worker nodes are released from Soperator, then consumed by an inference node group, or the other way around. ### Training and inference in separate Kubernetes clusters In this scenario, one Managed Service for Kubernetes cluster hosts Soperator for training and a separate cluster hosts inference workloads in one or more node groups. Both clusters use the same capacity block group. To move capacity in this layout, see [Moving capacity between training and inference workloads](https://docs.nebius.com/slurm-soperator/capacity/move-capacity.md). ### Training and inference in the same Kubernetes cluster Soperator and inference can also run in different node groups within a single Managed Service for Kubernetes cluster. You still release worker nodes from the Soperator node group and adjust the inference node group size in the same cluster. To move capacity in this layout, see [Moving capacity between training and inference workloads](https://docs.nebius.com/slurm-soperator/capacity/move-capacity.md). ## Slurm power management commands In a Soperator cluster with ephemeral nodes enabled, you can provision and deprovision worker nodes with standard Slurm [power management](https://slurm.schedmd.com/power_save.html) commands. Run them from a [login node](https://docs.nebius.com/slurm-soperator/clusters/connect.md#how-to-connect-to-login-nodes) after you connect to the cluster. | Command | Behavior | | --------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `scontrol power up ` | Provisions the specified nodes in the Soperator cluster if free GPUs are available in the capacity block. | | `scontrol power down ` | For each node, deprovisions the node when it is idle. Without the `asap` flag, power down has lower priority than starting new jobs from the queue, so Slurm may run queued jobs on the node before powering it down. | | `scontrol power down asap ` | Same as `power down`, but also [drains](https://docs.nebius.com/slurm-soperator/monitoring/statuses.md#how-to-drain-and-resume-a-node) the nodes so no new jobs are scheduled on them. Slurm waits only for the current job to finish (if any), then deprovisions the node. | | `scontrol power down force ` | Deprovisions the nodes immediately and cancels all jobs running on them. | Replace `` in the commands above with a Slurm hostlist of worker node names, for example `worker-10,worker-11`, `worker-[10,11]` or `worker-[0-3,5-8,13],worker-cpu-18`. To check node names and states before you run a command, see [How to monitor job and node statuses in a Soperator cluster](https://docs.nebius.com/slurm-soperator/monitoring/statuses.md). If `scontrol power` commands do not work, [contact technical support](https://console.nebius.com/support/) and ask to upgrade the cluster to Soperator 3.0 or later and enable ephemeral nodes on the relevant worker node sets. ### Automatic node provisioning Powered-down ephemeral nodes are automatically provisioned again when queued jobs need them. You can also trigger provisioning by submitting work with `srun` or `sbatch`: for ephemeral `CLOUD` nodes, these commands run `ResumeProgram`, and Soperator creates the corresponding worker Pods if capacity is available. If you want to release nodes and keep them powered down even when queued jobs target them, also [drain](https://docs.nebius.com/slurm-soperator/monitoring/statuses.md#how-to-drain-and-resume-a-node) the nodes: ```bash scontrol update NodeName= State=drain Reason="prevent power up" ``` Use the same Slurm hostlist as in your `power down` command. ## See also * [Moving capacity between training and inference workloads](https://docs.nebius.com/slurm-soperator/capacity/move-capacity.md) * [Capacity block groups](https://docs.nebius.com/overview/limits/capacity-block-groups.md) * [Health management of worker nodes in Soperator clusters](https://docs.nebius.com/slurm-soperator/worker-nodes-health.md) # Moving capacity between training and inference workloads Source: https://docs.nebius.com/slurm-soperator/capacity/move-capacity.md If you share a [capacity block group](https://docs.nebius.com/overview/limits/capacity-block-groups.md) between a Soperator cluster and an inference node group, you can move GPU capacity between them without stopping the entire Soperator cluster. The steps below are the same whether training and inference run in [separate Managed Service for Kubernetes clusters](https://docs.nebius.com/slurm-soperator/capacity/ephemeral-nodes.md#separate-kubernetes-clusters-for-training-and-inference) or in [different node groups within one cluster](https://docs.nebius.com/slurm-soperator/capacity/ephemeral-nodes.md#training-and-inference-in-the-same-kubernetes-cluster). Use Slurm power management commands to release or add worker nodes in Soperator, and change the inference node group size to consume or free capacity. For information on how ephemeral nodes work, see [Ephemeral nodes in Soperator](https://docs.nebius.com/slurm-soperator/capacity/ephemeral-nodes.md). ## Prerequisites 1. [Reserve a capacity block group](https://docs.nebius.com/overview/limits/capacity-block-groups.md) that your Soperator worker nodes and inference node group share. 2. Make sure your Soperator cluster runs version 3.0 or later and has ephemeral nodes enabled. Nebius enables this at cluster provisioning time; when you request the cluster, ask your Nebius manager or [technical support](https://console.nebius.com/support/) to enable ephemeral nodes on the relevant worker node sets. If `scontrol power` commands do not work, ask support to upgrade the cluster or enable ephemeral nodes. 3. Set up an inference [node group](https://docs.nebius.com/kubernetes/node-groups/manage.md#how-to-create-node-groups) that uses the same capacity block: * **Separate clusters:** [Create a Managed Service for Kubernetes cluster](https://docs.nebius.com/kubernetes/clusters/manage.md) for inference workloads and add a node group to it. * **Same cluster:** [Add a node group](https://docs.nebius.com/kubernetes/node-groups/manage.md#how-to-create-node-groups) for inference workloads to the cluster that already runs Soperator. 4. Make sure you are in a [group](https://docs.nebius.com/iam/authorization/groups/index.md) that has at least the `editor` role within your tenant or project; for example, the default `editors` group. You can check this in the [Administration → IAM](https://console.nebius.com/iam) section of the web console. 5. [Generate an SSH key pair](https://docs.nebius.com/compute/virtual-machines/ssh-keys.md) and set up [access to a login node](https://docs.nebius.com/slurm-soperator/clusters/connect.md#how-to-connect-to-login-nodes) in the Soperator cluster. ## How to move capacity from training to inference When training nodes are idle but inference needs more GPUs, release nodes from Soperator and add them to the inference node group. 1. [Connect to a login node](https://docs.nebius.com/slurm-soperator/clusters/connect.md#how-to-connect-to-login-nodes) in the Soperator cluster. 2. List worker nodes and their states: ```bash sinfo -Nel ``` Choose nodes that are `idle` or that you are ready to drain. See [node states](https://docs.nebius.com/slurm-soperator/monitoring/statuses.md#node-states) for details. 3. Release the chosen nodes from the Soperator cluster: * To deprovision nodes when they are idle, use plain `power down`. Without the `asap` parameter, power down has lower priority than starting new jobs from the queue, so Slurm may run queued jobs on the node before powering it down: ```bash scontrol power down Reason="move capacity to inference" ``` * To [drain](https://docs.nebius.com/slurm-soperator/monitoring/statuses.md#how-to-drain-and-resume-a-node) nodes so no new jobs are scheduled, wait for the current job to finish (if any), and then deprovision the nodes: ```bash scontrol power down asap Reason="move capacity to inference" ``` * To power down nodes immediately and cancel running jobs: ```bash scontrol power down force Reason="move capacity to inference" ``` Replace `` in the commands above with a Slurm hostlist of worker node names, for example `worker-10,worker-11`, `worker-[10,11]`, or `worker-[0-3,5-8,13],worker-cpu-18`. 4. To prevent the nodes from powering back up automatically when queued jobs target them, [drain](https://docs.nebius.com/slurm-soperator/monitoring/statuses.md#how-to-drain-and-resume-a-node) them: ```bash scontrol update NodeName= State=drain Reason="prevent power up" ``` Use the same Slurm hostlist as in the `power down` command. For details, see [Automatic node provisioning](https://docs.nebius.com/slurm-soperator/capacity/ephemeral-nodes.md#automatic-node-provisioning). 5. Wait until the nodes are powered down. Confirm their state with the following command: ```bash sinfo -N -o "%N %t %E" ``` Powered-down ephemeral nodes remain in the node list with a powered-down cloud state. They no longer run worker Pods. 6. In the Managed Service for Kubernetes cluster that hosts your inference workloads, [increase the inference node group size](https://docs.nebius.com/kubernetes/node-groups/manage.md#how-to-modify-node-groups) by the same number of nodes you released from Soperator. Use a node group that draws GPUs from the same capacity block group. The released GPUs are now available to inference workloads. ## How to move capacity from inference to training When inference traffic drops and you want to run training jobs on idle GPUs, scale down the inference node group and power worker nodes back on in Soperator. 1. In the Managed Service for Kubernetes cluster that hosts your inference workloads, [reduce the inference node group size](https://docs.nebius.com/kubernetes/node-groups/manage.md#how-to-modify-node-groups) by the number of nodes you want to move to training. Wait until the nodes are removed and the GPUs are released to the capacity block. 2. [Connect to a login node](https://docs.nebius.com/slurm-soperator/clusters/connect.md#how-to-connect-to-login-nodes) in the Soperator cluster. 3. If you drained the nodes when you released them, resume them: ```bash scontrol update NodeName= State=resume ``` 4. Power on worker nodes in Soperator: ```bash scontrol power up ``` Replace `` in the command above with a Slurm hostlist of worker node names to bring back, for example `worker-10,worker-11`, `worker-[10,11]`, or `worker-[0-3,5-8,13],worker-cpu-18`. Soperator creates worker Pods for the requested nodes if enough free GPUs remain in the capacity block. Alternatively, submit a job with `srun` or `sbatch` that needs those nodes; Slurm may power them on automatically. For details, see [Automatic node provisioning](https://docs.nebius.com/slurm-soperator/capacity/ephemeral-nodes.md#automatic-node-provisioning). 5. Confirm that the nodes are available for scheduling: ```bash sinfo -N -o "%N %t %E" ``` The powered-on nodes should move toward the `idle` state when they are ready for new jobs. ## See also * [Ephemeral nodes in Soperator](https://docs.nebius.com/slurm-soperator/capacity/ephemeral-nodes.md) * [How to monitor job and node statuses in a Soperator cluster](https://docs.nebius.com/slurm-soperator/monitoring/statuses.md) * [Creating and modifying Managed Service for Kubernetes® node groups](https://docs.nebius.com/kubernetes/node-groups/manage.md) # Creating and deleting Soperator clusters in Managed Service for Soperator Source: https://docs.nebius.com/slurm-soperator/managed-soperator/manage.md You can create and manage Soperator clusters in Managed Service for Soperator in the [web console](https://console.nebius.com). A cluster includes login, controller and worker nodes, and provides a full Slurm environment for batch and interactive workloads. ## Prerequisites * If you need worker nodes with GPUs, make sure that you have [capacity block groups](https://docs.nebius.com/overview/limits/capacity-block-groups.md) that reserve GPUs. * Make sure you are in a [group](https://docs.nebius.com/iam/authorization/groups/index.md) that has at least the `editor` role within your tenant or project; for example, the default `editors` group. You can check this in the [Administration → IAM](https://console.nebius.com/iam) section of the web console. * Generate at least one [SSH key pair](https://docs.nebius.com/compute/virtual-machines/ssh-keys.md) to connect to [Slurm login nodes](https://docs.nebius.com/slurm-soperator/overview/architecture.md#nodes) as the default `root` user. ## How to create a cluster 1. In the sidebar, go to  **AI orchestration** → **Soperator**. 2. Click **Create cluster**. 3. In the **Overview**, configure the cluster's general parameters: 1. Enter the cluster name. 2. Add one or more SSH public keys (`ssh-ed25519 AAA***`) to access the login node. 4. Configure node sets. A cluster must have a [login node set](https://docs.nebius.com/slurm-soperator/overview/architecture.md#login-nodes) and at least one [worker node set](https://docs.nebius.com/slurm-soperator/overview/architecture.md#worker-nodes). 1. For the login node set, specify a number of nodes. 2. For each worker node set, specify the following: * Name. * Whether the nodes should use GPUs. * [Platform and preset](https://docs.nebius.com/compute/virtual-machines/types.md). - Reservation ID from your [capacity block group](https://docs.nebius.com/overview/limits/capacity-block-groups.md). - Number of nodes. If you already have a worker node set and would like to create another one with the same configuration, next to the worker set, click  → **Clone node set**. Each cluster also contains [service nodes](https://docs.nebius.com/slurm-soperator/managed-soperator/service-nodes.md): controller nodes, accounting nodes and Soperator system nodes. They are subject to billing and quotas in the same way as login and worker nodes. 5. Add visible and, optionally, hidden partitions. You can use the default partitions or define your own ones. Partitions group nodes into logical (and possibly overlapping) sets and define how workloads are scheduled on those node sets. See details in the [Slurm quickstart on partitions](https://slurm.schedmd.com/quickstart.html#arch). In Managed Soperator, hidden partitions are not listed by Slurm CLI tools as available (per the `Hidden` parameter in [slurm.conf](https://slurm.schedmd.com/slurm.conf.html#OPT_Hidden)), but you can create and manage them in the web console and other Nebius AI Cloud interfaces. For each partition, specify: * [PartitionName](https://slurm.schedmd.com/slurm.conf.html#OPT_PartitionName): A unique partition name that you will use when submitting jobs. * [Nodes](https://slurm.schedmd.com/slurm.conf.html#OPT_Nodes_1): The worker node sets that the partition can schedule jobs on. A partition can include one or more node sets, and a node set can belong to more than one partition. * [PriorityTier](https://slurm.schedmd.com/slurm.conf.html#OPT_PriorityTier): Determines how Soperator prioritizes partitions when resources are limited. A higher partition priority means that more jobs from this partition are favored for the same resources. * [DefaultTime](https://slurm.schedmd.com/slurm.conf.html#OPT_DefaultTime): The default time limit for jobs submitted to the partition, in `HH:MM:SS` format. Jobs inherit this limit unless they have a different time in their submission settings. * [DefMemPerNode](https://slurm.schedmd.com/slurm.conf.html#OPT_DefMemPerNode): The default amount of memory available to each node for jobs scheduled in the partition. Must not exceed the node capacity. * [PreemptMode](https://slurm.schedmd.com/slurm.conf.html#OPT_PreemptMode): Preemption mode controls what happens to currently running jobs when higher priority jobs require resources. 6. Add volumes. A cluster can include shared, local and memory volumes. * **Cluster volumes** are created per cluster and are available to all node sets. * **Shared volumes** are created per project and are available to all node sets. * **Local volumes** are created per node and store temporary or runtime data. * **Memory volumes** store data in RAM. You cannot change them. For more information about cluster and shared volumes, see [Types of storage volumes in Compute](https://docs.nebius.com/compute/storage/types.md). 7. (Optional) If the selected platform and preset support local SSD disks, enable **Local SSD disks** to add ephemeral local storage to your cluster. Local SSD disks are available only for supported platforms and presets. For details, see [Availability](https://docs.nebius.com/compute/storage/local-disks.md#availability). 8. Review the configuration on the **Review** page and click **Create cluster**. ### What's next * [Connect to the cluster](https://docs.nebius.com/slurm-soperator/clusters/connect.md). * To save costs when you are not using the cluster, [stop and start it](https://docs.nebius.com/slurm-soperator/managed-soperator/stop-start.md). ## How to delete a cluster When you delete a cluster, all data stored on its nodes and volumes is permanently removed. If you want to stop using the cluster temporarily and save costs, see [stop and start it](https://docs.nebius.com/slurm-soperator/managed-soperator/stop-start.md). 1. In the sidebar, go to **Managed Soperator**. 2. In the list of clusters, find the one that you want to delete. 3. Next to the cluster, click  → **Delete**. 4. Enter the cluster name to confirm and click **Delete cluster**. *** *InfiniBand and InfiniBand Trade Association are registered trademarks of the InfiniBand Trade Association.* # Stopping and starting Soperator clusters in Managed Service for Soperator Source: https://docs.nebius.com/slurm-soperator/managed-soperator/stop-start.md If you are not using the Soperator cluster that you have deployed in Managed Service for Soperator, you can stop it in the [web console](https://console.nebius.com) to save costs. While the cluster is stopped, Managed Service for Soperator [charges you](https://docs.nebius.com/slurm-soperator/managed-soperator/resources/pricing.md) for the cluster's storage resources: the disks of worker, login and controller nodes, and the shared filesystem. The service does not charge you for the cluster's computing resources (GPUs, vCPUs and RAM). When you need the cluster again, you can start it. Starting the cluster takes around 15 minutes. The cluster keeps the data that you saved in it, although you can only access it after you restart the cluster. Computing and storage resources of a stopped cluster count towards [Compute quotas](https://docs.nebius.com/compute/resources/quotas-limits.md), just like a running cluster. ## Prerequisites Make sure you are in a [group](https://docs.nebius.com/iam/authorization/groups/index.md) that has at least the `editor` role within your tenant or project; for example, the default `editors` group. You can check this in the [Administration → IAM](https://console.nebius.com/iam) section of the web console. ## How to stop and start a cluster 1. In the sidebar, go to  **AI orchestration** → **Soperator**. 2. Find the required cluster in the list. 3. Next to the cluster, click  → **Stop**. # Managed Service for Soperator service nodes Source: https://docs.nebius.com/slurm-soperator/managed-soperator/service-nodes.md In addition to login and worker nodes that you [create](https://docs.nebius.com/slurm-soperator/managed-soperator/manage.md) in your Managed Service for Soperator clusters, every cluster contains *service nodes* that facilitate the cluster's operation. Service nodes are [billed](https://docs.nebius.com/slurm-soperator/managed-soperator/resources/pricing.md) and count towards [quotas](https://docs.nebius.com/slurm-soperator/managed-soperator/resources/quotas.md) on vCPUs. You cannot configure service nodes. ## Service node types Managed Soperator service nodes vary by function: * *Controller nodes* orchestrate Slurm activities, such as job queuing, monitoring node states and allocating resources. * *Accounting nodes,* also known as *database daemon nodes* or *DBD nodes,* collect accounting information for jobs and job steps that you run in the cluster. * *Soperator system nodes* host Soperator tools that manage Nebius AI Cloud resources, certificates and telemetry. For more details about controller and accounting nodes, see [Slurm documentation](https://slurm.schedmd.com/quickstart_admin.html#nodes). ## Service nodes in clusters Each Managed Soperator cluster contains the following service nodes: | Type | Number of nodes | Compute per node | Storage per node | | ---------------------- | --------------------------------- | ------------------------------------ | ---------------------------------------------------------------- | | Controller nodes | 2 | Non-GPU AMD EPYC Genoa, `8vcpu-32gb` | Network SSD disk, 512 GiB | | Accounting nodes | 1 | Non-GPU AMD EPYC Genoa, `8vcpu-32gb` | Network SSD disk, 256 GiB;
Network SSD IO M3 disk, 1024 GiB | | Soperator system nodes | 3–5, autoscaled depending on load | Non-GPU AMD EPYC Genoa, `8vcpu-32gb` | Network SSD disk, 512 GiB | Therefore, for billing and quota purposes, at least the following computing and storage resources are added to login and worker nodes of a cluster: * Non-GPU AMD EPYC Genoa: 48 vCPUs, 192 GiB RAM * Network SSD disks: 2816 GiB * Network SSD IO M3 disk: 1024 GiB # Quotas in Managed Service for Soperator Source: https://docs.nebius.com/slurm-soperator/managed-soperator/resources/quotas.md Managed Service for Soperator shares some quotas with Compute. For details on what quotas are and how to manage them, see [Quotas in Nebius AI Cloud](https://docs.nebius.com/overview/quotas.md). ## Nodes (virtual machines) Login, worker and [service nodes](https://docs.nebius.com/slurm-soperator/managed-soperator/service-nodes.md) in Managed Soperator clusters count towards the [Compute quota](https://docs.nebius.com/compute/resources/quotas-limits.md#virtual-machines) on the total number of vCPUs across non-GPU virtual machines (VMs). The quotas on GPUs by type for regular VMs without reservations don't apply to Managed Soperator nodes because they require [capacity block groups](https://docs.nebius.com/overview/limits/capacity-block-groups.md) that reserve GPUs. Compute quotas on total numbers of GPU VMs and non-GPU VMs are not affected by Managed Soperator nodes. ## Disks and shared filesystems Disks and shared filesystems for login, worker and [service nodes](https://docs.nebius.com/slurm-soperator/managed-soperator/service-nodes.md) count towards [Compute quotas on storage capacity](https://docs.nebius.com/compute/resources/quotas-limits.md#storage) (total sizes of disks and shared filesystems by type). Quotas on total numbers of disks and shared filesystems are not affected by Managed Soperator clusters. # Pricing in Managed Service for Soperator Source: https://docs.nebius.com/slurm-soperator/managed-soperator/resources/pricing.md This article provides pricing details for Managed Service for Soperator in Nebius AI Cloud. ## How charges and prices work Each group of chargeable items in this article has two time units associated with it: * **Billing unit**: The minimum unit of usage for which you can be charged. * **Pricing unit**: The unit of usage for which the prices are shown. Charges for units smaller than the pricing unit are calculated proportionally. > For example, for GPUs on running VMs, the **billing unit** is 1 second, and the **pricing unit** is 1 hour (3600 seconds). For 30 minutes of usage, you will be charged half the hourly price. Prices in US dollars (USD, \$) apply to all customers except for companies from Israel, where prices in Israeli shekels (ILS, ₪) apply instead. All prices are shown without any applicable taxes, including VAT. Due to rounding errors, usage costs shown in the web console and final charges may slightly differ from calculations based on the prices in this article. ## Prices ### Cluster resources You are charged for the following resources: * Login, worker and [service nodes](https://docs.nebius.com/slurm-soperator/managed-soperator/service-nodes.md) are Compute virtual machines. Their GPUs, vCPUs, RAM and boot disks are charged according to [Compute pricing](https://docs.nebius.com/compute/resources/pricing.md). * Shared filesystems provisioned for the cluster are also priced in Compute. See [Compute pricing](https://docs.nebius.com/compute/resources/pricing.md#shared-filesystems) for storage rates. * Any buckets used with the cluster are charged according to [Object Storage pricing](https://docs.nebius.com/object-storage/resources/pricing.md). # Connecting to login and worker nodes Source: https://docs.nebius.com/slurm-soperator/clusters/connect.md In Soperator clusters, all Slurm nodes are Kubernetes Pods. The main [types of Slurm nodes](https://slurm.schedmd.com/quickstart_admin.html#nodes) in Soperator clusters are the following: * [Login nodes](https://docs.nebius.com/slurm-soperator/overview/architecture.md#login-node) provide users with access to the cluster. * [Worker nodes](https://docs.nebius.com/slurm-soperator/overview/architecture.md#worker-node) execute Slurm jobs. * [Controller nodes](https://docs.nebius.com/slurm-soperator/overview/architecture.md#controller-node) manage scheduling and orchestration. You can connect to login and worker nodes. ## Prerequisites Before you connect to nodes of a Soperator cluster for the first time, make sure that the following requirements are met: 1. [Get the public endpoint of the cluster](https://docs.nebius.com/slurm-soperator/clusters/connect.md#get-the-public-endpoint-of-the-cluster). 2. [Create a user account](https://docs.nebius.com/slurm-soperator/clusters/connect.md#create-a-user-account). 3. [(Optional) Establish a connection in Visual Studio Code](https://docs.nebius.com/slurm-soperator/clusters/connect.md#optional-establish-a-connection-in-visual-studio-code). ### Get the public endpoint of the cluster If you deployed the cluster in Managed Service for Soperator yourself, get the endpoint in the [web console](https://console.nebius.com): 1. In the sidebar, go to  **AI orchestration** → **Soperator**. 2. Under **General**, copy the public endpoint. If you are using the Pro Solution for Soperator, get the endpoint from your personal manager. ### Create a user account Contact the cluster administrator (the `root` user) to [create a user](https://docs.nebius.com/slurm-soperator/users/manage.md#how-to-create-a-user) for you. [Generate an SSH key pair](https://docs.nebius.com/compute/virtual-machines/ssh-keys.md) and share your public SSH key with the administrator. ### (Optional) Establish a connection in Visual Studio Code If you want to establish a connection in [Visual Studio Code](https://code.visualstudio.com/), do the following: 1. Install the [Remote - SSH](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-ssh) extension. 2. Open your `~/.ssh/config` file and add the following configuration: ```bash Host slurm HostName User IdentityFile ~/slurm_ed25519 ``` ## How to connect to login nodes Connect to a login node, so you can run Slurm commands and manage data stored on the shared filesystem. By default, if a cluster has several login nodes, you connect to a random login node: ```bash ssh @ -i ``` If you are working in the terminal, you can choose which login node to connect to. If you use the [tmux](https://en.wikipedia.org/wiki/Tmux) terminal multiplexer, make sure to connect to the same node each time. `tmux` sessions are created on the node where they are started, so you can only access them on this node. To connect to a particular login node, use the cluster public endpoint as a jump host and the name of the required node. ```bash ssh -J @ @login- -i ``` Specify the parameters that were set during the user creation: * Username. The administrator has the `root` username. * Path to the private key. * Exact name of the node you need to connect to, if you are connecting to a specific node (`login-`). You can get the list of login nodes in your cluster from your personal manager. Output example: ```text username@login-0:~$ ``` Now, you can run Slurm commands, for example, `sinfo` to get a list of available Slurm nodes. To establish a connection, in the bottom-left corner of VS Code, click → **Connect to Host...** → **slurm**. The configuration already includes your username and the cluster endpoint, so you do not need to enter them to connect. Now, you can view and manage data in your cluster by using the VS Code interface. ## How to connect to worker nodes Connect to a worker node, so you can monitor, observe and manage Slurm jobs. You can only connect to a specific worker node. To establish a connection, do the following: 1. From your personal manager, get a list of worker nodes in your cluster. Usually, worker nodes are named as `worker-0`, `worker-1`, `worker-2`, depending on how many exist. 2. [Connect to a login node by using a terminal](https://docs.nebius.com/slurm-soperator/clusters/connect.md#how-to-connect-to-login-nodes). 3. Connect to a specific worker node: ```bash ssh worker- ``` For example, if you have `worker-0` and `worker-1`, specify one of these nodes. Output example: ```text username@worker-0:~$ ``` Now, you can [monitor system usage](https://docs.nebius.com/slurm-soperator/monitoring/statuses.md) with various tools, such as `htop`, `nvtop` or `nvidia-smi`. If you are working in the terminal, you can connect to a worker node directly by using the cluster public endpoint as a jump host and then connecting to the specific node by name. ```bash ssh -J @ @worker- -i ``` Enter the exact name of the node you need to connect to. In addition, specify the parameters that were set during the user creation: * Username. The administrator has the `root` username. * Path to the private key. Output example: ```text username@worker-0:~$ ``` # Running Slurm batch jobs Source: https://docs.nebius.com/slurm-soperator/jobs/index.md Slurm's main purpose is to run *batch jobs*. Batch jobs are limited in time and non-interactive. To run a batch job, you should define it in a shell script which is also called a *batch script*, and then run the `sbatch` command to submit the script. After that, Slurm allocates the requested resources, forming a *job allocation* (also known as *job*), and then runs the script on one of the allocated worker nodes. Batch scripts launch multi-node workloads by using `srun` commands, forming one or many *job steps*. A job step represents a separate unit of work within the job. The command that you pass to `srun` is executed in parallel on one or many worker nodes within the job allocation. One instance of the running command (a Linux process) is called *task*. By default, `srun` starts one task per allocated worker node, but you can configure it in job step settings. You can configure job settings in multiple ways, such as in `sbatch` and `srun` command parameters, special comments inside a batch script (`#SBATCH` directives) and environment variables. ## How to run a batch job 1. [Connect to a login node](https://docs.nebius.com/slurm-soperator/clusters/connect.md#how-to-connect-to-login-nodes). 2. Create a batch script and name it, for example, `my_ml_job.sh`. Here is a basic example of a job script that runs your training application written in Python: ```bash #!/bin/bash # Directives that define the job's settings #SBATCH --job-name=my_ml_job #SBATCH --output=%x_%j.out # _.out #SBATCH --error=%x_%j.err # _.err #SBATCH --time=01:00:00 # time limit = 1 hour #SBATCH --exclusive # allocate all CPUs on nodes #SBATCH --gpus-per-node=8 # allocate 8 GPUs per node #SBATCH --ntasks-per-node=8 # launch 8 tasks in each job step by default # Commands that the batch script runs export CHECKPOINT_PATH="/mnt/data/gpt3/checkpoints" export DATA_PATH="/mnt/data/c4_data" export DTYPE="fp16" source .venv/bin/activate # Launch a job step on 4 nodes with 8 tasks per node, each pinned to 16 CPUs. srun --cpus-per-task=16 python train.py ``` For more details about writing batch scripts, see [Job configuration](https://docs.nebius.com/slurm-soperator/jobs/index.md#job-configuration) and [Examples](https://docs.nebius.com/slurm-soperator/jobs/index.md#examples). 3. Prepare the environment on the login node. In Soperator clusters, all nodes [share a root filesystem](https://docs.nebius.com/slurm-soperator/overview/architecture.md), so files and dependencies that you set up on the login node automatically appear on other nodes. 1. Make sure that the files that the script uses are on the login node: create them from scratch, [upload them from another machine](https://docs.nebius.com/slurm-soperator/storage/download-data.md) or copy their contents to files on the login node. The example above requires `train.py` to be in the same directory as the batch script. 2. Install the script dependencies. > For example, if your workload uses Python packages listed in [requirements.txt](https://pip.pypa.io/en/stable/user_guide/#requirements-files), create a Python [virtual environment](https://docs.python.org/3/library/venv.html) and install the packages into it: > > ```bash > python -m venv .venv > source .venv/bin/activate > pip install -r requirements.txt > ``` You can make working with dependencies easier by turning your workload into a containerized job. For more details, see [Running jobs in containers in Soperator clusters](https://docs.nebius.com/slurm-soperator/jobs/containers/index.md). 3. Make sure all files have suitable permissions. 4. Define the required environment variables. Usually, you can put your environment variables right in the batch script, but there are cases when it's more convenient to define them inside your login shell. > For example, if your workload uses [Weights & Biases](https://docs.wandb.ai/quickstart/) (W\&B), define an environment variable for your W\&B API key: > > ```bash > export WANDB_API_KEY= > ``` 5. Submit the script to Slurm with `sbatch`, providing additional settings if needed. > For example, if you named your batch script `my_ml_job.sh` and you want to run the job on 4 worker nodes, run the following command: > > ```bash > sbatch --nodes=4 my_ml_job.sh > ``` The output contains the job ID, which you can use to [monitor the job's status](https://docs.nebius.com/slurm-soperator/monitoring/statuses.md): ```text Submitted batch job 610 ``` The job prints its standard and error outputs to the files specified in the script directives. In the example above, the name pattern for the job's standard output file is `output_%j.txt` where `%j` stands for the job ID (for more details about patterns, see the [Slurm documentation](https://slurm.schedmd.com/sbatch.html#SECTION_FILENAME-PATTERN)). You can print the file's current contents: ```bash cat output_.txt ``` If your job takes some time, you can stream the standard output rather than repeatedly printing it: ```bash tail -f output_.txt ``` ## Job configuration To define a job, you should configure its settings, and add the commands that it should run to its batch script. ### sbatch settings `sbatch` settings configure job allocations and provide default values for corresponding `srun` settings. You can configure `sbatch` settings in the following ways, from highest to lowest priority (for example, the value of a command parameter overrides the value of an input environment variable for the same setting): 1. **Command parameters**: `sbatch --time="02:00:00"` The `sbatch` command has parameters that work and behave like regular parameters of a Linux command. Use command parameters when you want to use different values for different job runs or to overwrite settings from other sources. 2. **Input environment variables**: `export SBATCH_TIMELIMIT="01:00:00"` in login shell, `/etc/profile` or `~/profile` Most (but not all) command parameters have corresponding input environment variables with the same meaning. Some of these environment variables have different names from their command parameters. > For example, the `--time` command parameter corresponds to the `SBATCH_TIMELIMIT` input environment variable. For the list of all environment variables, see the [Slurm documentation](https://slurm.schedmd.com/sbatch.html#SECTION_INPUT-ENVIRONMENT-VARIABLES). You can define them on different levels, from highest to lowest priority: 1. **Session variables**: environment variables that you export in your login shell. They disappear after you reconnect to the cluster. Use session variables when you want to launch a few jobs with the same setting without keeping it forever. 2. **User variables**: environment variables from `~/profile`. The login shell exports them every time *you* connect to the cluster; after that, session variables can override them. Use user variables to set your personal default values for settings. 3. **Cluster variables**: environment variables from `/etc/profile`. The login shell exports them every time *any user* connects to the cluster; after that, user variables and then session variables can override them. Use cluster variables to set default values for all users. 3. **#SBATCH directives**: `#SBATCH --time="01:30:00"` in a batch script `#SBATCH` directives are special comments at the beginning of a batch script. Use `#SBATCH` directives to define settings that should apply to most runs of this particular job. All `#SBATCH` directives must appear at the beginning of the script. As soon as `sbatch` encounters the first line that does not start with `#` or consist of whitespace (spaces, tab characters, etc.), it interprets the rest of the file as commands and silently ignores misplaced `#SBATCH` directives. 4. **Slurm defaults**: `time="00:30:00"` in `~/.slurm/defaults` Slurm defaults are key-value pairs in the `~/.slurm/defaults`. These values apply only to you and are not applicable to other users. Use Slurm defaults when you need a low-priority default value, or a default value for a command parameter that does not have a corresponding input environment variable. `~/.slurm/defaults` defines settings for both `sbatch` and `srun`. Do not use them for settings that have the same name but different meaning for these commands; for example, `--exclusive` ([sbatch](https://slurm.schedmd.com/sbatch.html#OPT_exclusive), [srun](https://slurm.schedmd.com/srun.html#OPT_exclusive)). #### Common sbatch settings
**Command parameter****Description****Environment variable****#SBATCH directive****Slurm default**
`--job-name=` or `-J=`The name of your job.`SBATCH_JOB_NAME``#SBATCH --job-name=` or `#SBATCH -J=``job-name=` or `J=`
`--nodes=` or `-N=`The number of worker nodes to allocate for the job.*N/A*`#SBATCH --nodes=` or `#SBATCH -N=``nodes=` or `N=`
`--nodelist=` or `-w=`The list of specific worker nodes to allocate for the job. For example, `--nodelist="worker-0,worker-2"` or `--nodelist="worker-[0-2,3]"`.*N/A*`#SBATCH --nodelist=` or `#SBATCH -w=``nodelist=` or `w=`
`--exclude=` or `-x=`The list of worker nodes to exclude from the job allocation. For example, `--exclude="worker-3"` or `--nodelist="worker-[4-7]"`.*N/A*`#SBATCH --exclude=` or `#SBATCH -x=``exclude=` or `x=`
`--output=` or `-o=`The path to the file for the job's standard output. The path can contain special replacement symbols; for example, `%j` is replaced by the job ID. For more details, see the [Slurm documentation](https://slurm.schedmd.com/sbatch.html#SECTION_FILENAME-PATTERN).`SBATCH_OUTPUT``#SBATCH --output=` or `#SBATCH -o=``output=` or `o=`
`--error=` or `-e=`The path to the file for the job's error output. The path can contain the replacement symbols as described for the `output` setting.`SBATCH_ERROR``#SBATCH --error=` or `#SBATCH -e=``error=` or `e=`
`--time=` or `-t=`The time limit for the job. When the job reaches the time limit, all its tasks (processes) are terminated. For example, `01:00` limits the job to one hour, and `1-00` limits the job to one day (24 hours).`SBATCH_TIMELIMIT``#SBATCH --time=` or `#SBATCH -t=``time=` or `t=`
`--gpus-per-node=`The number of GPUs to allocate for the job on each worker node.`SBATCH_GPUS_PER_NODE``#SBATCH --gpus-per-node=``gpus-per-node=`
`--ntasks-per-node=`The maximum number of tasks to run on each worker node. When you define resources for the job in per-task settings like `gpus-per-task`, `cpus-per-task`, etc., total resources in the job allocation are based on the value of `ntasks-per-node`.*N/A*`#SBATCH --ntasks-per-node=``ntasks-per-node=`
`--exclusive`Allocates all CPUs on the allocated worker nodes to the job, preventing other jobs from using these nodes. This allows the total number of tasks of the job to be unlimited.`SBATCH_EXCLUSIVE``#SBATCH --exclusive`*N/A*
`--cpus-per-task=` or `-c=`The number of CPUs to allocate for the job per task.*N/A*`#SBATCH --cpus-per-task=` or `#SBATCH -c=``cpus-per-task=` or `c=`
`--mem=[]` or `-m=[]`The RAM size to allocate for the job on each worker node. For example, `mem=4G`. To allocate all available RAM, specify `mem=0`.`SBATCH_MEM_PER_NODE``#SBATCH --mem=[]` or `#SBATCH -m=[]``mem=[]` or `m=[]`
`--partition=` or `-p=`The Slurm partition to allocate nodes from.`SBATCH_PARTITION``#SBATCH --partition=` or `#SBATCH -p=``partition=` or `p=`
`--account=` or `-A=`The Slurm account name.`SBATCH_ACCOUNT``#SBATCH --account=` or `#SBATCH -A=``account=` or `A=`
`--requeue`Requeues the job automatically: restarts it (with the same ID) when its worker nodes fail or other, higher-priority jobs preempt them.`SBATCH_REQUEUE``#SBATCH --requeue``requeue`
`--no-requeue`Disables automatically requeuing the job (see `requeue`).`SBATCH_NO_REQUEUE``#SBATCH --no-requeue``no-requeue`
`--dependency=` or `-d=`Dependencies of the job. For example:
  • `dependency=singleton` requires that the job only starts after other jobs with the same name and user are terminated. This means that at any moment, there can only be one job with this name and owned by this user.
  • `dependency=afterany:20:21` requires that the job only starts after the jobs with IDs 20 and 21 are terminated.
For more details, see the [Slurm documentation](https://slurm.schedmd.com/sbatch.html#OPT_dependency).
*N/A*`#SBATCH --dependency=` or `#SBATCH -d=``dependency=` or `d=`
`--parsable`Changes the standard output of `sbatch` from `Submitted batch job ` to just ``.*N/A*`#SBATCH --parsable``parsable`
`--verbose` or `-v`Increases the verbosity of `sbatch`'s informational messages. For more verbosity, use the parameter, `#SBATCH` directive or Slurm default multiple times, or set the `SBATCH_DEBUG` environment variable to `2`, `3`, etc.`SBATCH_DEBUG``#SBATCH --verbose` or `#SBATCH -v``verbose` or `v`
### Commands The commands block of a batch script defines commands that the batch script runs. Commands in a batch script are executed on one worker node. Typically, you would need to run your main computational commands on multiple worker nodes in parallel. To do that, use the `srun` command in the script. > In the [example above](https://docs.nebius.com/slurm-soperator/jobs/index.md#how-to-run-a-batch-job), `srun python train.py` makes `python train.py` run in parallel. If it was just `python train.py`, the Python script would run on one worker node. In commands, you can use the *output environment variables* set by [sbatch](https://slurm.schedmd.com/sbatch.html#SECTION_OUTPUT-ENVIRONMENT-VARIABLES) (general job details: ID, job allocation, launch node and worker nodes, etc.) and [srun](https://slurm.schedmd.com/srun.html#SECTION_OUTPUT-ENVIRONMENT-VARIABLES) (`sbatch`'s variables, plus details about the current job step and task: local and global ranks, world size, CPUs in use, etc.). For example: * `SLURM_JOB_NODELIST` is the list of worker nodes allocated to the job; `SLURM_NNODES` is the number of the worker nodes. * `SLURM_SUBMIT_DIR` is the directory where you executed `sbatch`. * `SLURM_NODEID` is the node ID for each worker node. ## Examples ### Training with Hugging Face Accelerate The following example uses [Hugging Face Accelerate](https://huggingface.co/docs/accelerate/index) to run a training workload (`train.py`) on two nodes with 8 GPUs each. It requires that you add Accelerate to `train.py`, as described in the [Accelerate documentation](https://huggingface.co/docs/accelerate/basic_tutorials/migration), and install it into your Python virtual environment (`pip install accelerate`). `llm_training.sh`: ```bash #!/bin/bash #SBATCH --job-name=llm_training #SBATCH --output=%x_%j.out #SBATCH --error=%x_%j.err #SBATCH --nodes=2 #SBATCH --gpus-per-node=8 #SBATCH --exclusive #SBATCH --mem=0 # Get the hostname of worker node where this sbatch script runs, # SLURMD_NODENAME is the Slurm output environment variable for sbatch. MAIN_PROCESS_ADDR=$SLURMD_NODENAME MAIN_PROCESS_PORT=12345 srun \ --cpus-per-task=64 \ --hint=nomultithread \ bash -c 'accelerate launch \ # SLURM_STEP_NUM_NODES is the number of worker nodes allocated for the step (2) --num_machines $SLURM_STEP_NUM_NODES \ # SLURM_NODEID is the ID of the current worker node (0 or 1) --machine_rank $SLURM_NODEID \ --main_process_ip $MAIN_PROCESS_ADDR \ --main_process_port $MAIN_PROCESS_PORT \ --num_processes $(($SLURM_STEP_NUM_NODES * $SLURM_GPUS_ON_NODE)) \ train.py' ``` For `accelerate launch` parameters, see [Accelerate documentation](https://huggingface.co/docs/accelerate/package_reference/cli#accelerate-launch). ### Fine-tuning with PyTorch (torchrun) The following example uses [PyTorch](https://pytorch.org/docs/stable/index.html) to fine-tune a model (`llama-3-8b`) on a sample dataset (`alpaca_dataset`). The job runs on three nodes with 8 GPUs each. For the full example, including `finetuning.py` with added PyTorch and instructions to download the model and the dataset, see the [Multi-node LLM fine-tuning on Slurm](https://github.com/alex000kim/multi-node-llm-finetuning-slurm) repository on GitHub. * `sbatch.sh`: ```bash #!/bin/bash #SBATCH --job-name=llama-finetune #SBATCH --nodes=3 #SBATCH --output=O-%x_%j.txt #SBATCH --error=E-%x_%j.txt #SBATCH --gres=gpu:8 #SBATCH --cpus-per-task=120 # Loads all environment variables into the job #SBATCH --export=ALL srun srun.sh ``` * `srun.sh`: ```bash #!/bin/bash export GPUS_PER_NODE=8 # Get the hostname of the first node from the list of the job's worker nodes # (SLURM_JOB_NODELIST, set by Slurm) HOST_ADDR=$(scontrol show hostnames $SLURM_JOB_NODELIST | head -n 1) MAIN_PROCESS_PORT=12345 echo "SLURM_NNODES=$SLURM_NNODES" echo "SLURM_NODEID=$SLURM_NODEID" echo "HOST_ADDR=$HOST_ADDR" echo "MAIN_PROCESS_PORT=$MAIN_PROCESS_PORT" source .venv/bin/activate torchrun --nnodes $SLURM_NNODES \ --nproc_per_node $GPUS_PER_NODE \ --master_addr $HOST_ADDR \ --master_port $MAIN_PROCESS_PORT \ --node_rank=$SLURM_NODEID \ finetuning.py \ --model_name ./llama-3-8b \ --output_dir saved_peft_model \ --use_peft \ --peft_method lora \ --enable_fsdp \ --use_fast_kernels \ --use_wandb \ --dataset alpaca_dataset ``` For details about `torchrun`, see the [PyTorch documentation](https://pytorch.org/docs/stable/elastic/run.html) and the source code of [torch.distributed.run](https://github.com/pytorch/pytorch/blob/main/torch/distributed/run.py) on GitHub. ### Containerized jobs You can run containerized jobs with batch scripts by using special `srun` parameters. For example: ```bash srun --container-image="nvcr.io#nvidia/tensorflow:23.02-tf1-py3" \ python -c "import tensorflow as tf; print (tf.__version__)" ``` For more details and examples, see [Running jobs in containers in Soperator clusters](https://docs.nebius.com/slurm-soperator/jobs/containers/index.md). # Running jobs in containers in Soperator clusters Source: https://docs.nebius.com/slurm-soperator/jobs/containers/index.md Soperator enables you to run jobs in containers. Containers allow you to run applications across different cloud providers, in a portable and consistent way. You can create a container image once and then run it in different cloud services. In addition, many widespread solutions are already available in container registries. Soperator clusters allow you to run jobs in containers by using the following tools: * [Enroot and Pyxis](https://docs.nebius.com/slurm-soperator/jobs/containers/pyxis-enroot.md) * [Apptainer](https://docs.nebius.com/slurm-soperator/jobs/containers/apptainer.md) * [Docker](https://docs.nebius.com/slurm-soperator/jobs/containers/docker.md) For the best performance, we recommend using Enroot and Pyxis, because Soperator includes performance optimizations for them. # Running jobs in containers by using Enroot and Pyxis Source: https://docs.nebius.com/slurm-soperator/jobs/containers/pyxis-enroot.md Soperator clusters support Enroot and Pyxis to run jobs in containers: * [Enroot](https://github.com/nvidia/enroot) is a simple container runtime. It was created by NVIDIA® specifically for machine learning and high-performance computing. Enroot supports Docker images and can execute the same containers, but works better with Slurm. It allows you to pull the images from container registries, such as [Docker Hub](https://hub.docker.com/), [NVIDIA NGC](https://catalog.ngc.nvidia.com/containers) (`nvcr.io`) or [Container Registry](https://docs.nebius.com/container-registry/index.md) by Nebius. * [Pyxis](https://github.com/NVIDIA/pyxis) is a plug-in for Slurm, which uses Enroot to allow cluster users to run containerized jobs by using the `srun` command with additional `--container-***` parameters. You can run a Slurm job within a container created from an image that is stored either [in a registry](https://docs.nebius.com/slurm-soperator/jobs/containers/pyxis-enroot.md#how-to-run-a-job-for-a-container-registry-image) or [locally](https://docs.nebius.com/slurm-soperator/jobs/containers/pyxis-enroot.md#how-to-run-a-job-for-a-local-image). ## How to run a job for a container registry image 1. Create the following job called `test.sbatch`: ```bash #!/bin/bash #SBATCH -J test #SBATCH --output=log.out #SBATCH --error=log.out #SBATCH --gpus=1 srun --container-image="nvcr.io#nvidia/tensorflow:23.02-tf1-py3" \ python -c "import tensorflow as tf; print (tf.__version__)" ``` This job pulls a TensorFlow image from the NVIDIA container registry, starts a container and executes a simple Python script within it. Use the `--container-image=""` parameter for the `srun` command, to specify a container image. In Soperator clusters, a container image is first pulled from the registry, then saved to the cluster's shared filesystem. Next, all worker nodes can use this image to start the container, without repeated downloads of the same data from the registry. You can disable this default behavior and add the `--container-image-save=""` parameter with an empty value to the `srun` command. In this parameter, you can also set the path where the image is stored in the filesystem: `--container-image-save=""`. For more information about other parameters available for `srun`, see [Pyxis documentation](https://github.com/NVIDIA/pyxis/wiki/Usage). 2. Run the job: ```bash sbatch test.sbatch ``` ### How to authenticate in a container registry Docker Hub and NVIDIA NGC container registries are configured by default, and you do not need to authenticate to pull public container images from them. If you need to pull images from another registry, or to pull private container images, configure credentials in the `~/.config/enroot/.credentials` file: ```bash machine login password ``` The password requirements depend on the image: * To pull a private container image, the password is required. For more information about the login and password, consult the documentation of the selected container registry. * To pull a public container image from a registry other than Docker Hub or NVIDIA NGC, you can use an arbitrary string instead of a password. The endpoint for Container Registry by Nebius is: * cr.eu-north1.nebius.cloud: For the eu-north1 region. * cr.eu-west1.nebius.cloud: For the eu-west1 region. For more information, see [Container Registry documentation](https://docs.nebius.com/container-registry/registries/manage.md) and [Enroot documentation](https://github.com/NVIDIA/enroot/blob/master/doc/cmd/import.md#description). ## How to run a job for a local image You can only use images in the [squashfs](https://www.kernel.org/doc/Documentation/filesystems/squashfs.txt) format (`.sqsh`, `.sqshfs`, `.squashfs`). You can get the images by using the [enroot import](https://github.com/NVIDIA/enroot/blob/master/doc/cmd/import.md) command. Alternatively, they can be saved when you pull the image from the registry by using `--container-image-save="/image.sqshfs"`. To run a job in a container with a local image, do the following: 1. Create the following job called `test.sbatch`: ```bash #!/bin/bash #SBATCH -J test #SBATCH --output=log.out #SBATCH --error=log.out #SBATCH --gpus=1 srun --container-image="./tensorflow.sqsh" \ python -c "import tensorflow as tf; print (tf.__version__)" ``` This job starts a container with a local image, then executes a simple Python script within the container. Use the `--container-image=""` parameter for the `srun` command, to specify the container image. For more information about other parameters available for `srun`, see [Pyxis documentation](https://github.com/NVIDIA/pyxis/wiki/Usage). 2. Run the job: ```bash sbatch test.sbatch ``` # Running jobs in containers by using Apptainer Source: https://docs.nebius.com/slurm-soperator/jobs/containers/apptainer.md Soperator clusters allow you to run jobs in containers by using [Apptainer](https://apptainer.org/). Apptainer is a secure and portable container runtime compatible with Slurm. It is designed for high-performance computing (HPC) and scientific computing. Apptainer was formerly known as Singularity and supports the same `.sif` container image format. Apptainer may provide lower performance than other [supported tools for running jobs in containers](https://docs.nebius.com/slurm-soperator/jobs/containers/index.md). We recommend using container runtimes that Soperator has performance optimizations for, such as Enroot. To run a containerized job by using Apptainer: 1. [Connect](https://docs.nebius.com/slurm-soperator/clusters/connect.md#how-to-connect-to-login-nodes) to a login node of your Soperator cluster. 2. Install Apptainer: ```bash sudo add-apt-repository -y ppa:apptainer/ppa sudo apt update sudo apt install -y apptainer ``` 3. Verify that the installation was successful by checking the Apptainer version: ```bash apptainer --version ``` Expected output: ```bash apptainer version 1.3.4 ``` 4. Use `srun` to pull a container image and convert it to the `.sif` format: ```bash srun apptainer pull cuda_image.sif docker://nvidia/cuda:12.4.1-cudnn-devel-rockylinux8 ``` The `pull` command can download or convert a container from the specified URL. In particular, you can pull an image from Docker Hub or another container registry. For more information, see the [Apptainer documentation](https://apptainer.org/docs/user/main/cli/apptainer_pull.html). 5. Create the `apptainer_job.sh` script with the following contents: ```bash #!/bin/bash #SBATCH --job-name=apptainer_job #SBATCH --gres=gpu:8 #SBATCH --output=output.log #SBATCH --error=error.log apptainer exec --nv cuda_image.sif nvidia-smi ``` This script uses the following parameters: * `--gres=gpu:8` requests 8 GPUs for the job. * `--nv` enables NVIDIA® GPU support inside the container. This script runs the [nvidia-smi monitoring utility by NVIDIA](https://docs.nvidia.com/deploy/nvidia-smi/index.html) to print information on GPU visibility inside the container. To run custom workloads, replace `cuda_image.sif` with a different container image. Also, replace `nvidia-smi` with the required application or command. For example: ```bash apptainer exec --nv my_custom_image.sif python train.py ``` Ensure that `my_custom_image.sif` contains Python and all other dependencies of `train.py`. 6. Run the job: ```bash sbatch apptainer_job.sh ``` The output contains the following confirmation: ```bash Submitted batch job ``` 7. When the job completes, check the logs. The `output.log` file contains the list of all 8 GPUs that are available for usage inside the container: ```bash cat output.log Wed Apr 16 13:55:48 2025 +-----------------------------------------------------------------------------------------+ | NVIDIA-SMI 550.54.15 Driver Version: 550.54.15 CUDA Version: 12.4 | |-----------------------------------------+------------------------+----------------------+ | GPU Name Persistence-M | Bus-Id Disp.A | Volatile Uncorr. ECC | | Fan Temp Perf Pwr:Usage/Cap | Memory-Usage | GPU-Util Compute M. | | | | MIG M. | |=========================================+========================+======================| | 0 NVIDIA H100 80GB HBM3 On | 00000000:8D:00.0 Off | 0 | | N/A 29C P0 73W / 700W | 0MiB / 81559MiB | 0% Default | | | | Disabled | +-----------------------------------------+------------------------+----------------------+ | 1 NVIDIA H100 80GB HBM3 On | 00000000:91:00.0 Off | 0 | | N/A 27C P0 67W / 700W | 0MiB / 81559MiB | 0% Default | | | | Disabled | +-----------------------------------------+------------------------+----------------------+ | 2 NVIDIA H100 80GB HBM3 On | 00000000:95:00.0 Off | 0 | | N/A 29C P0 67W / 700W | 0MiB / 81559MiB | 0% Default | | | | Disabled | +-----------------------------------------+------------------------+----------------------+ | 3 NVIDIA H100 80GB HBM3 On | 00000000:99:00.0 Off | 0 | | N/A 27C P0 71W / 700W | 0MiB / 81559MiB | 0% Default | | | | Disabled | +-----------------------------------------+------------------------+----------------------+ | 4 NVIDIA H100 80GB HBM3 On | 00000000:AB:00.0 Off | 0 | | N/A 29C P0 70W / 700W | 0MiB / 81559MiB | 0% Default | | | | Disabled | +-----------------------------------------+------------------------+----------------------+ | 5 NVIDIA H100 80GB HBM3 On | 00000000:AF:00.0 Off | 0 | | N/A 27C P0 70W / 700W | 0MiB / 81559MiB | 0% Default | | | | Disabled | +-----------------------------------------+------------------------+----------------------+ | 6 NVIDIA H100 80GB HBM3 On | 00000000:B3:00.0 Off | 0 | | N/A 29C P0 69W / 700W | 0MiB / 81559MiB | 0% Default | | | | Disabled | +-----------------------------------------+------------------------+----------------------+ | 7 NVIDIA H100 80GB HBM3 On | 00000000:B7:00.0 Off | 0 | | N/A 26C P0 68W / 700W | 0MiB / 81559MiB | 0% Default | | | | Disabled | +-----------------------------------------+------------------------+----------------------+ +-----------------------------------------------------------------------------------------+ | Processes: | | GPU GI CI PID Type Process name GPU Memory | | ID ID Usage | |=========================================================================================| | No running processes found | +-----------------------------------------------------------------------------------------+ ``` # Running jobs in containers by using Docker Source: https://docs.nebius.com/slurm-soperator/jobs/containers/docker.md Soperator clusters allow you to use Docker Engine to run jobs in containers. ## Limitations When using Docker Engine with Slurm, consider the following limitations: * **Docker Engine doesn't respect Slurm resource allocations.** Docker may use all resources of a node, regardless of the settings that you specify in `sbatch`. We recommend using [Enroot](https://docs.nebius.com/slurm-soperator/jobs/containers/pyxis-enroot.md) or [other supported container runtimes](https://docs.nebius.com/slurm-soperator/jobs/containers/index.md) to run Docker containers. If you want to use Docker Engine, use the `-N` and `--exclusive` settings to allocate entire nodes to Slurm jobs. * **Docker containers aren't managed as part of the Slurm job lifecycle.** If a job is canceled, fails or times out, containers started with `srun docker run` continue running. Stop them manually or adjust your job script to stop the containers when the job receives the `SIGTERM` or `SIGKILL` signals. * **Performance may be degraded without local disks.** If no local disk is available, Docker uses the [VFS storage driver](https://docs.docker.com/engine/storage/drivers/vfs-driver/), which leads to significantly lower performance. ## How to run a Docker container in a Slurm job 1. [Connect](https://docs.nebius.com/slurm-soperator/clusters/connect.md#how-to-connect-to-login-nodes) to a login node of your Soperator cluster. 2. Create a batch script that runs your workload in a container. For example, create the `test_nccl.sh` script with the following contents: ```bash #!/bin/bash #SBATCH -J docker-all-reduce #SBATCH -N 2 #SBATCH --exclusive #SBATCH --output=output.log srun docker run --device=/dev/infiniband nvidia/cuda:12.8.0-runtime-ubuntu24.04 bash -c ' echo "Installing additional dependencies..." apt update -y && apt install -y wget rdma-core ibverbs-utils echo "Installing NCCL tests..." wget -P /tmp https://github.com/nebius/slurm-deb-packages/releases/download/nccl_tests_12.8.0/nccl-tests-perf.tar.gz tar -xvzf /tmp/nccl-tests-perf.tar.gz -C /usr/bin && rm -rf /tmp/nccl-tests-perf.tar.gz echo "Starting all_reduce_perf..." /usr/bin/all_reduce_perf -b 512M -e 8G -f 2 -g 8 ' ``` This script pulls a Docker image with Ubuntu and CUDA® toolkit from NVIDIA®, then installs [NVIDIA Collective Communications Library (NCCL) tests](https://github.com/NVIDIA/nccl-tests) and their dependencies, and runs NCCL tests in a Docker container. The script uses the following parameters: * `#SBATCH -N` specifies how many nodes to allocate. * `#SBATCH --exclusive` specifies that no other jobs may be scheduled on these nodes until this job is completed. * `--device=/dev/infiniband` parameter for `docker` allows access to InfiniBand™ from inside Docker containers. If your workload needs access to the shared filesystem, you can add the `-v` parameter to make paths from the shared filesystem visible from inside the container: ```bash srun docker run -v : ``` 3. Start the job: ```bash sbatch test_nccl.sh ``` The output contains the job ID: ```bash Submitted batch job ``` 4. When the job is completed, review the contents of `output.log`. The output contains the logs of the container starting up and installing dependencies, followed by the results of NCCL tests. For example: ```bash ========== == CUDA == ========== CUDA Version 12.8.0 ... Installing additional dependencies... Get:3 https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2404/x86_64 Packages [1607 kB] ... Starting all_reduce_perf... # nThread 1 nGpus 8 minBytes 536870912 maxBytes 8589934592 step: 2(factor) warmup iters: 5 iters: 20 agg iters: 1 validation: 1 graph: 0 # # Using devices # Rank 0 Group 0 Pid 1 on 1ae1d8baa190 device 0 [0x8d] NVIDIA H100 80GB HBM3 # Rank 1 Group 0 Pid 1 on 1ae1d8baa190 device 1 [0x91] NVIDIA H100 80GB HBM3 # Rank 2 Group 0 Pid 1 on 1ae1d8baa190 device 2 [0x95] NVIDIA H100 80GB HBM3 # Rank 3 Group 0 Pid 1 on 1ae1d8baa190 device 3 [0x99] NVIDIA H100 80GB HBM3 # Rank 4 Group 0 Pid 1 on 1ae1d8baa190 device 4 [0xab] NVIDIA H100 80GB HBM3 # Rank 5 Group 0 Pid 1 on 1ae1d8baa190 device 5 [0xaf] NVIDIA H100 80GB HBM3 # Rank 6 Group 0 Pid 1 on 1ae1d8baa190 device 6 [0xb3] NVIDIA H100 80GB HBM3 # Rank 7 Group 0 Pid 1 on 1ae1d8baa190 device 7 [0xb7] NVIDIA H100 80GB HBM3 # # out-of-place in-place # size count type redop root time algbw busbw #wrong time algbw busbw #wrong # (B) (elements) (us) (GB/s) (GB/s) (us) (GB/s) (GB/s) 536870912 134217728 float sum -1 2145.0 250.29 438.01 0 2146.1 250.16 437.78 0 1073741824 268435456 float sum -1 4036.8 265.99 465.47 0 4041.8 265.66 464.90 0 2147483648 536870912 float sum -1 7917.9 271.22 474.63 0 7921.6 271.09 474.41 0 4294967296 1073741824 float sum -1 15729 273.06 477.85 0 15710 273.40 478.45 0 8589934592 2147483648 float sum -1 31257 274.81 480.93 0 31278 274.63 480.60 0 # Out of bounds values : 0 OK # Avg bus bandwidth : 467.303 ``` ## How to run a Docker container in an interactive mode 1. [Connect](https://docs.nebius.com/slurm-soperator/clusters/connect.md#how-to-connect-to-login-nodes) to a login node of your Soperator cluster. 2. To run an interactive session on a node and prevent any other allocations on this node, use [salloc](https://slurm.schedmd.com/salloc.html): ```bash salloc --exclusive ``` This command allocates a worker node to a new job and opens a terminal on this node. Output example: ```bash salloc: Granted job allocation @worker-:~$ ``` 3. Start a Docker container on a worker node: ```bash docker run --rm ``` The `--rm` parameter ensures that the container is automatically deleted when it exits. If your workload needs access to the shared filesystem, use the `-v` parameter to make paths from the shared filesystem visible from inside the container: ```bash docker run --rm -v : ``` For multi-node GPU workloads, use the `--device=/dev/infiniband` parameter for `docker` that allows access to InfiniBand from inside Docker containers. 4. After you finish the interactive session and exit, you can see the confirmation that the node is no longer allocated: ```bash exit salloc: Relinquishing job allocation salloc: Job allocation has been revoked. @login-0:~$ ``` ## How to get information about your Docker containers To list all containers, including the ones that are already finished, [connect](https://docs.nebius.com/slurm-soperator/clusters/connect.md#how-to-connect-to-worker-nodes) to a worker node and run the following command: ```bash docker ps -a ``` For more details on Docker commands and parameters, see the [Docker documentation](https://docs.docker.com/reference/cli/docker/container/). *** *InfiniBand and InfiniBand Trade Association are registered trademarks of the InfiniBand Trade Association.* # Managing jobs in Soperator clusters Source: https://docs.nebius.com/slurm-soperator/jobs/manage.md You can use Slurm commands to view and manage jobs in your Soperator cluster. To run these commands, [connect](https://docs.nebius.com/slurm-soperator/clusters/connect.md#how-to-connect-to-login-nodes) to the cluster's login node. ## How to view job list and details ### Jobs in queue To list all jobs that are currently in the queue, use the [squeue](https://slurm.schedmd.com/squeue.html) command. You can use various parameters to specify the output format: * `--long` to include more details. For example: ```bash squeue --long ``` Output example: ```bash JOBID PARTITION NAME USER STATE TIME TIME_LIMI NODES NODELIST(REASON) 837 main test-job user RUNNING 0:11 UNLIMITED 2 worker-[0-1] ``` * `--Format` to customize output columns and their width. For example: ```bash squeue --Format "JobID:8,Partition:10,Name,UserName,State:16,TimeUsed:8,NumNodes:6,ReasonList" ``` Output example: ```bash JOBID PARTITION NAME USER STATE TIME NODES NODELIST(REASON) 837 main test-job user RUNNING 0:05 2 worker-[0-1] ``` * `--steps` to show job steps, that is, sets of tasks within a job. For example: ```bash squeue --steps ``` Output example: ```bash Tue Apr 29 16:23:39 2025 STEPID NAME PARTITION USER TIME NODELIST 837.0 test main user 1:26 worker-[0-1] 837.batch batch main user 1:27 worker-1 ``` ### All jobs The `squeue` command doesn't list completed or failed jobs. To get the full details of all recently run jobs, use the [scontrol](https://slurm.schedmd.com/scontrol.html) command: ```bash scontrol show jobs | less ``` Output example: ```bash JobId= JobName= UserId=(1001) GroupId=(1001) MCS_label=N/A Priority=1 Nice=0 Account=(null) QOS=normal JobState=RUNNING Reason=None Dependency=(null) Requeue=1 Restarts=0 BatchFlag=1 Reboot=0 ExitCode=0:0 RunTime=00:00:38 TimeLimit=UNLIMITED TimeMin=N/A SubmitTime=2025-04-30T15:51:21 EligibleTime=2025-04-30T15:51:21 AccrueTime=2025-04-30T15:51:21 StartTime=2025-04-30T15:51:21 EndTime=Unknown Deadline=N/A PreemptEligibleTime=2025-04-30T15:51:21 PreemptTime=None SuspendTime=None SecsPreSuspend=0 LastSchedEval=2025-04-30T15:51:21 Scheduler=Main Partition=main AllocNode:Sid=login-0:919915 ReqNodeList=(null) ExcNodeList=(null) NodeList=worker-[0-1] BatchHost=worker-1 NumNodes=2 NumCPUs=256 NumTasks=2 CPUs/Task=1 ReqB:S:C:T=0:0:*:* ReqTRES=cpu=2,mem=3034G,node=2,billing=2 AllocTRES=cpu=256,mem=3034G,node=2,billing=256 Socks/Node=* NtasksPerN:B:S:C=0:0:*:* CoreSpec=* MinCPUsNode=1 MinMemoryNode=1517G MinTmpDiskNode=0 Features=(null) DelayBoot=00:00:00 OverSubscribe=NO Contiguous=0 Licenses=(null) Network=(null) Command= WorkDir= StdErr= StdIn=/dev/null StdOut= JobId= ... ... ``` By default, this command shows the jobs finished in the last 24 hours. The output is limited to 10,000 jobs. To find out how many jobs are displayed for your cluster, run the following command: ```bash scontrol show config | grep -E "MaxJobCount|MinJobAge" ``` Output for default settings: ```bash MaxJobCount = 10000 MinJobAge = 86400 sec ``` To list all jobs that were run on the cluster, use the [sacct](https://slurm.schedmd.com/sacct.html) command. ### Jobs and processes that run on specific nodes To get the list of jobs running on particular nodes, run the following command: ```bash squeue --nodelist="worker-[0-1]" ``` Change the `--nodelist` parameter value to include the nodes that you need. Output example: ```bash JOBID PARTITION NAME USER ST TIME NODES NODELIST(REASON) 837 main test user R 0:05 2 worker-[0-1] ``` To get the job processes that are currently running on a given worker node, [connect](https://docs.nebius.com/slurm-soperator/clusters/connect.md#how-to-connect-to-worker-nodes) to this node and use `scontrol listpids`. Run the following command: ```bash ssh worker-0 scontrol listpids ``` Output example: ```bash PID JOBID STEPID LOCALID GLOBALID 992342 933 0 0 1 992333 933 0 - - ``` ### Full details and batch script of a job To get the full details of a job, run the following command: ```bash scontrol show job ``` Output example: ```bash JobId= JobName= UserId=(1001) GroupId=(1001) MCS_label=N/A Priority=1 Nice=0 Account=(null) QOS=normal JobState=RUNNING Reason=None Dependency=(null) Requeue=1 Restarts=0 BatchFlag=1 Reboot=0 ExitCode=0:0 RunTime=00:00:38 TimeLimit=UNLIMITED TimeMin=N/A SubmitTime=2025-04-30T15:51:21 EligibleTime=2025-04-30T15:51:21 AccrueTime=2025-04-30T15:51:21 StartTime=2025-04-30T15:51:21 EndTime=Unknown Deadline=N/A PreemptEligibleTime=2025-04-30T15:51:21 PreemptTime=None SuspendTime=None SecsPreSuspend=0 LastSchedEval=2025-04-30T15:51:21 Scheduler=Main Partition=main AllocNode:Sid=login-0:919915 ReqNodeList=(null) ExcNodeList=(null) NodeList=worker-[0-1] BatchHost=worker-1 NumNodes=2 NumCPUs=256 NumTasks=2 CPUs/Task=1 ReqB:S:C:T=0:0:*:* ReqTRES=cpu=2,mem=3034G,node=2,billing=2 AllocTRES=cpu=256,mem=3034G,node=2,billing=256 Socks/Node=* NtasksPerN:B:S:C=0:0:*:* CoreSpec=* MinCPUsNode=1 MinMemoryNode=1517G MinTmpDiskNode=0 Features=(null) DelayBoot=00:00:00 OverSubscribe=NO Contiguous=0 Licenses=(null) Network=(null) Command= WorkDir= StdErr= StdIn=/dev/null StdOut= ``` You can also retrieve the batch script used to run the job: ```bash scontrol write batch_script ``` This command creates a `slurm-.sh` file with the contents of the script. ### Job states You can see the current job state in the `STATE` column when you list jobs with `squeue` or in the `JobState` parameter when you get job details with `scontrol show job(s)`. Some of the common job states include: | Job state | Description | | ---------------- | ------------------------------------------------------------------------------------------------ | | `PD` `PENDING` | The job is waiting for resource allocation. | | `R` `RUNNING` | The job is currently running. | | `S` `SUSPENDED` | The job execution was [suspended](https://docs.nebius.com/slurm-soperator/jobs/manage.md#suspend-and-resume-a-job). | | `CD` `COMPLETED` | The job has been completed successfully (processes on all nodes finished with a zero exit code). | | `RQ` `REQUEUED` | The job is being [requeued](https://docs.nebius.com/slurm-soperator/jobs/manage.md#requeue-a-job). | For a complete list of all possible job states, see the [Slurm documentation](https://slurm.schedmd.com/squeue.html#SECTION_JOB-STATE-CODES). ## How to manage jobs The `scontrol` command lets you manage the jobs in the queue. ### Suspend and resume a job You can suspend a job, which means that the job processes are terminated, but resource allocations are retained. Run the following command: ```bash scontrol suspend ``` The job is returned to the queue and waits in `SUSPENDED` status until you manually resume it: ```bash scontrol resume ``` The job is resumed and continues execution. ### Requeue a job You can requeue a job, which means that the job is terminated and returned to the queue. It restarts automatically when the resources are available. Run the following command to requeue a job: ```bash scontrol requeue ``` A requeued job keeps the same job ID. If your job writes some data at paths that depend only on the job ID, the data from the previous attempt may be overwritten by the requeued job. In Soperator clusters, some failed jobs are requeued by default. To check this setting for your cluster, run the following command: ```bash scontrol show config | grep JobRequeue ``` Output for default settings: ```bash JobRequeue = 1 ``` You may want to prevent a requeued job from being scheduled again automatically. To requeue a running job and put it on hold until you explicitly allow it to be scheduled, run the following command: ```bash scontrol requeuehold ``` To requeue and put on hold a job that hasn't started yet, run the following command: ```bash scontrol hold ``` To allow the job to be scheduled again as soon as there are available resources, run the following command: ```bash scontrol release ``` ### Cancel a job You can cancel job execution. Run the following command: ```bash scontrol cancel ``` The job is terminated and all resources are freed. # Running the all-reduce NCCL performance test in Soperator clusters Source: https://docs.nebius.com/slurm-soperator/jobs/examples/nccl-all-reduce.md Soperator includes pre-built [NVIDIA® Collective Communications Library (NCCL) tests](https://github.com/NVIDIA/nccl-tests) that you can use to validate collective communication between GPUs over the available high-performance network and assess network performance in your cluster. NCCL used in these benchmarks enables communication over NVLink for single-node runs, and over a combination of NVLink and InfiniBand™ for multi-node runs. There are two versions of NCCL tests included in Soperator: a single-node version (`all_reduce_perf`) and a multi-node version with the `_mpi` suffix (`all_reduce_perf_mpi`). In this article, you will run the `all_reduce_perf_mpi` NCCL test on multiple nodes. The all-reduce operation is important for synchronizing gradients during multi-GPU training, which makes `all_reduce_perf_mpi` useful for evaluating both network and compute resources. ## How to run the test 1. [Connect to a login node](https://docs.nebius.com/slurm-soperator/clusters/connect.md). 2. Create an output directory for Slurm logs: ```bash mkdir -p results ``` 3. Create an sbatch script for your platform and save it as `nccl_all_reduce.sbatch`: ```bash title="nccl_all_reduce.sbatch" #!/bin/bash #SBATCH --job-name=nccl_all_reduce #SBATCH --time=30:00 #SBATCH --output=results/%x-%j.out #SBATCH --error=results/%x-%j.out #SBATCH --nodes=8 #SBATCH --gpus-per-node=8 #SBATCH --ntasks-per-node=8 #SBATCH --cpus-per-task=16 #SBATCH --mem=0 echo "Job ID: ${SLURM_JOB_ID}" echo "Start time: $(date -u '+%Y-%m-%d %H:%M:%SZ')" export UCX_NET_DEVICES=mlx5_0:1,mlx5_1:1,mlx5_2:1,mlx5_3:1,mlx5_4:1,mlx5_5:1,mlx5_6:1,mlx5_7:1 export NCCL_IB_QPS_PER_CONNECTION=2 export NCCL_NVLS_ENABLE=1 export NCCL_BUFFSIZE=8388608 srun --mpi=pmix all_reduce_perf_mpi -b 512M -e 16G -f 2 -g 1 ``` ```bash title="nccl_all_reduce.sbatch" #!/bin/bash #SBATCH --job-name=nccl_all_reduce #SBATCH --time=30:00 #SBATCH --output=results/%x-%j.out #SBATCH --error=results/%x-%j.out #SBATCH --nodes=8 #SBATCH --gpus-per-node=8 #SBATCH --ntasks-per-node=8 #SBATCH --cpus-per-task=20 #SBATCH --mem=0 echo "Job ID: ${SLURM_JOB_ID}" echo "Start time: $(date -u '+%Y-%m-%d %H:%M:%SZ')" export UCX_NET_DEVICES=mlx5_4:1,mlx5_5:1,mlx5_6:1,mlx5_7:1,mlx5_8:1,mlx5_9:1,mlx5_10:1,mlx5_11:1 export NCCL_IB_QPS_PER_CONNECTION=2 export NCCL_NVLS_ENABLE=1 export NCCL_BUFFSIZE=8388608 srun --mpi=pmix all_reduce_perf_mpi -b 512M -e 16G -f 2 -g 1 ``` ```bash title="nccl_all_reduce.sbatch" #!/bin/bash #SBATCH --job-name=nccl_all_reduce #SBATCH --time=30:00 #SBATCH --output=results/%x-%j.out #SBATCH --error=results/%x-%j.out #SBATCH --nodes=8 #SBATCH --gpus-per-node=8 #SBATCH --ntasks-per-node=8 #SBATCH --cpus-per-task=24 #SBATCH --mem=0 echo "Job ID: ${SLURM_JOB_ID}" echo "Start time: $(date -u '+%Y-%m-%d %H:%M:%SZ')" export UCX_NET_DEVICES=mlx5_4:1,mlx5_5:1,mlx5_6:1,mlx5_7:1,mlx5_8:1,mlx5_9:1,mlx5_10:1,mlx5_11:1 export NCCL_IB_QPS_PER_CONNECTION=2 export NCCL_NVLS_ENABLE=1 export NCCL_BUFFSIZE=8388608 srun --mpi=pmix all_reduce_perf_mpi -b 512M -e 16G -f 2 -g 1 ``` 4. Submit the job: ```bash sbatch nccl_all_reduce.sbatch ``` The examples above assume the job is run on 8 nodes using the `#SBATCH --nodes` directive. To run on a different number of nodes, override this value using the command-line argument when submitting the job: `sbatch --nodes= nccl_all_reduce.sbatch`. Slurm uses the command-line value when both are present. For more details about running and configuring jobs, see [Running Slurm batch jobs](https://docs.nebius.com/slurm-soperator/jobs/index.md). ## Script structure and configuration The example scripts include three sections: 1. Slurm configuration parameters 2. Environment variables for NCCL tuning 3. Launch command for the parallel NCCL testing ### Slurm configuration parameters This section defines job parameters using `#SBATCH` directives. These directives configure job submission options. For more details, see [Job configuration](https://docs.nebius.com/slurm-soperator/jobs/index.md#job-configuration) and the [SBATCH documentation](https://slurm.schedmd.com/sbatch.html). * `--job-name`: Job name shown in the `squeue` and `sacct` output. * `--time`: Job time limit (30 minutes in these examples). * `--output`, `--error`: File names for the job output and error. You can use pattern substitution, for example: `%x` (job name) and `%j` (job ID). * `--nodes`: Number of Slurm worker nodes used for the test. You can override this with `sbatch --nodes=`. * `--gpus-per-node`: Number of GPUs per node. The examples use all available GPUs for each platform (for example, 8 GPUs on 8xH200 nodes). * `--ntasks-per-node`: Number of parallel processes per node. This example uses one process per GPU, so the value matches the number of GPUs (for example, 8). Some ML frameworks instead launch one process per node and handle parallelism internally; if you want to test how such frameworks would work, set this value to `1`. * `--cpus-per-task`: Number of CPUs per process. In these examples, all CPUs are evenly divided across processes (total cores ÷ number of GPUs). This helps ensure consistent performance and avoids interference from cluster defaults. For one-process-per-node setups, set the value to the total number of CPUs per node. For CPU counts for each platform, see [presets](https://docs.nebius.com/compute/virtual-machines/types.md#presets-for-gpu-platforms). * `--mem`: Amount of system memory per node. The examples use all available memory (`--mem=0`) to avoid unintended limitations from cluster defaults. You can also set a specific memory amount using units, for example: `--mem=4G`. ### Environment variables for NCCL tuning This section defines environment variables for NCCL and related parallel libraries. For more details, see the [NCCL environment variables documentation](https://docs.nvidia.com/deeplearning/nccl/user-guide/docs/env.html). * `UCX_NET_DEVICES`: Comma-separated list of high-speed network interfaces used by the [Unified Communication X](https://openucx.org/documentation/) (UCX) library. UCX is commonly used as a transport layer in [Message Passing Interface](https://www.mpi-forum.org/) (MPI) implementations and other libraries (for example, [NVIDIA Inference Xfer Library](https://github.com/ai-dynamo/nixl) — NIXL). Use platform-specific values of 8 specific InfiniBand ports to achieve maximum bandwidth. Otherwise, use an Ethernet interface with IP connectivity across all worker nodes, for example: `UCX_NET_DEVICES=eth0`. * NCCL tuning variables: * `NCCL_IB_QPS_PER_CONNECTION=2`: Sets the number of InfiniBand queue pairs per connection to 2 (instead of the default 1). Using more queue pairs may improve throughput by increasing routing entropy. * `NCCL_NVLS_ENABLE=1`: Enables NVLink SHARP support, allowing the NVSwitch to offload part of the computation work. This option is typically enabled by default, but may be disabled in some container images. * `NCCL_BUFFSIZE=8388608`: Sets the size of the internal NCCL communication buffer to 8 MB. A larger buffer can help improve performance in some scenarios by allowing more data to be processed in each communication step. ### Launch command configuration This section uses the `srun` command to start the application in parallel across multiple nodes and processes, and defines arguments for both `srun` and NCCL tests. * `srun --mpi=pmix`: Selects the [Process Management Interface for Exascale](https://pmix.org/) (PMIx) used to exchange rank information between Slurm's launcher (`srun`) and the MPI library (in the case of `all_reduce_perf_mpi`, [Open MPI](https://docs.open-mpi.org/)). * `all_reduce_perf_mpi`: Runs the NCCL benchmark for the all-reduce operation, built with support for multi-node execution. NCCL also provides similar benchmarks for other collective operations like AllGather and ReduceScatter. After the executable name, the following [NCCL test arguments](https://github.com/NVIDIA/nccl-tests#arguments) are used: * `-b 512M`: Sets the minimum message size, meaning the test begins with messages of 512 MB. * `-e 16G`: Defines the maximum message size, so the test will go up to 16 GB. * `-f 2`: Specifies the multiplication factor, so each step doubles the message size (for example, 512 MB → 1 GB → 2 GB, etc.). * `-g 1`: Indicates that each thread will use 1 GPU. * `-t 1`: Sets the number of threads per process to 1. ## How to validate the results When the job finishes, it saves both the standard output and standard error to a file named `results/nccl_all_reduce-.out`. A successful run should: * Complete without errors * Show `# Out of bounds values : 0 OK` * Show increasing bus bandwidth (`busbw`) as the collective message size grows. In most cases, `busbw` will reach a stable peak bandwidth at larger collective operation sizes. ### Example output This example was generated on a cluster of 8 virtual machines, each equipped with 8 NVIDIA H200 GPUs: ```text # Rank 0 Group 0 Pid 121061 on worker-0 device 0 [0000:8d:00] NVIDIA H200 ... # Rank 63 Group 0 Pid 89331 on worker-13 device 7 [0000:b7:00] NVIDIA H200 # # out-of-place in-place # size count type redop root time algbw busbw #wrong time algbw busbw #wrong # (B) (elements) (us) (GB/s) (GB/s) (us) (GB/s) (GB/s) 536870912 134217728 float sum -1 3489.1 153.87 302.94 0 3343.1 160.59 316.16 0 1073741824 268435456 float sum -1 6060.2 177.18 348.82 0 6061.9 177.13 348.72 0 2147483648 536870912 float sum -1 11523 186.36 366.89 0 11799 182.00 358.32 0 4294967296 1073741824 float sum -1 22312 192.49 378.97 0 22410 191.65 377.31 0 8589934592 2147483648 float sum -1 44596 192.62 379.22 0 44542 192.85 379.67 0 # Out of bounds values : 0 OK # Avg bus bandwidth : 355.703 # ``` The values above are provided for illustrative purposes. Actual results may vary depending on factors such as hardware or system configuration. The result file begins with a header that includes metadata about the run, such as the NCCL tests version, NCCL library version, the list of GPUs used and the rank assigned to each GPU on every allocated worker node. This is followed by multiple lines, with one line per collective message size. Each line contains several fields describing the test configuration and results for that message size, including: * Size of the exchange (in bytes) * Element count (based on the data type) * Data type (for example, floating point) * Reduction operation (for example sum) * Rank-related information For each message size, the test runs in two modes: * Out-of-place, where input and output buffers are separate * In-place, where input and output share the same buffer For each iteration of the test, three metrics are reported: * **Time:** The duration of a single collective operation iteration, measured in microseconds (μs). * **Algorithm bandwidth** (`algbw`): The size of the input array for collective operation divided by time. Shows how fast one iteration completes based on the data size. * **Bus bandwidth** (`busbw`): The algorithm bandwidth corrected for the number of communicating ranks to better estimate the peak hardware bandwidth. Due to this correction and the large speed difference of NVLink and InfiniBand, the final bus bandwidth value may not accurately reflect true hardware bandwidth. For example, in some scenarios, such as two-node runs that involve both NVLink and InfiniBand, the `busbw` value can overestimate the load on InfiniBand. `Avg bus bandwidth` is the average of all `busbw` values reported across the different message sizes. When interpreting or comparing this average, consider the range of message sizes used in the test (defined by the `-b`, `-e` and `-f 2` arguments, and visible in the `size` column). Smaller message sizes typically result in lower bus bandwidth, while larger sizes reach higher bandwidth. As a result, the average can vary significantly depending on the size range included in the test. For more details about the test and understanding its results, see [NCCL tests documentation](https://github.com/NVIDIA/nccl-tests/blob/master/doc/PERFORMANCE.md). *** *InfiniBand and InfiniBand Trade Association are registered trademarks of the InfiniBand Trade Association.* # Health management of worker nodes in Soperator clusters Source: https://docs.nebius.com/slurm-soperator/worker-nodes-health.md Soperator has built-in health checks that continuously monitor the fleet of worker nodes in your cluster, and an auto-healing system that isolates and replaces broken nodes. When deployed in Nebius AI Cloud (Managed Service for Soperator or Pro Solution for Soperator), Soperator also relies on maintenance events from the Compute service and Kubernetes® to auto-heal worker nodes. You can also use custom health checks to run additional checks on worker nodes. ## Health management in Soperator ### Built-in health checks For all deployment types, Soperator runs built-in health checks on a schedule for each worker node with GPUs. Most of these checks are considered critical: if a worker node fails a critical check, Soperator marks it as requiring further action. Critical checks include, but are not limited to, the following checks: * GPU checks: * [AllReduce](https://github.com/NVIDIA/nccl-tests/blob/master/doc/PERFORMANCE.md#allreduce), an [NCCL test](https://github.com/NVIDIA/nccl-tests/tree/master) (with and without InfiniBand™, outside and inside Docker containers) * [CUDA samples](https://github.com/NVIDIA/cuda-samples), such as [vectorAdd](https://github.com/NVIDIA/cuda-samples/blob/master/Samples/0_Introduction/vectorAdd), [simpleMultiGPU](https://github.com/NVIDIA/cuda-samples/tree/master/Samples/0_Introduction/simpleMultiGPU), [deviceQuery](https://github.com/NVIDIA/cuda-samples/blob/master/Samples/1_Utilities/deviceQuery) and [p2pBandwidthLatencyTest](https://github.com/NVIDIA/cuda-samples/tree/master/Samples/5_Domain_Specific/p2pBandwidthLatencyTest) * [NVIDIA® Data Center GPU Manager](https://docs.nvidia.com/datacenter/dcgm/latest/user-guide/index.html) (DCGM) diagnostics * GPU stress test * RAM checks: bandwidth and latency For technical details and the full list of checks, see these resources in the Soperator repository on GitHub: * [Active Checks – Health and system checks framework](https://github.com/nebius/soperator/blob/main/docs/active-checks.md): description of checks' architecture and implementation * `soperator-activechecks` Helm chart: * [values.yaml](https://github.com/nebius/soperator/blob/main/helm/soperator-activechecks/values.yaml): list of checks * [scripts/](https://github.com/nebius/soperator/tree/main/helm/soperator-activechecks/scripts): scripts for each check ### Node isolation When a critical check fails, Soperator performs the *extensive check procedure*: 1. Drains the node, waiting for running Slurm jobs to finish. The drain reason has the `[node_problem]` prefix. 2. Moves the node into the *suspicious reservation*, preventing new jobs from being scheduled on it. 3. Runs extensive checks on the node, which include hardware-level tests and re-runs of most critical checks. ### Node replacement If the extensive checks fail, Soperator drains the node. The drain reason now has the `[hardware_problem]` prefix — Soperator marks all worker nodes with this prefix as unhealthy Kubernetes nodes, which triggers automatic re-creation of the node. If the node passes the extensive checks, Soperator removes it from the suspicious reservation, and jobs can run on the node again. In Managed Service for Soperator and Pro Solution for Soperator, Compute may schedule maintenance for an underlying virtual machine (VM) of the worker node during the extensive check procedure. This typically indicates a hardware issue already detected by Compute. In this case, Soperator immediately stops the checks, and then drains and recreates the node. ### Custom health checks (Slurm prolog and epilog programs) All Soperator deployment types support Slurm *prolog and epilog programs* for job steps. You can configure them by using `--task-prolog` and `--task-epilog` parameters of `srun`, either in [batch scripts](https://docs.nebius.com/slurm-soperator/jobs/index.md) or in direct `srun` calls. The prolog and epilog programs specified in `--task-prolog` and `--task-epilog` run on each worker node before and after the job step that is launched by the `srun` call. You can use them to run custom health checks on worker nodes. > For example, you can run `nvidia-smi` before and after the training step in your batch script (`my_ml_job.sh`) to check the GPU utilization and health: > > > ```bash title="my_ml_job.sh" highlight={5} > #!/bin/bash > > # Directives, preparation steps, etc. > > srun --cpus-per-task=16 --task-prolog="/mnt/checks/smi.sh" --task-epilog="/mnt/checks/smi.sh" python train.py > ``` > > ```bash title="/mnt/checks/smi.sh" > #!/bin/bash > > nvidia-smi > ``` > For more details about prolog and epilog programs, see [Slurm documentation](https://slurm.schedmd.com/prolog_epilog.html). By default, Soperator doesn't auto-heal worker nodes that fail custom health checks. To set up custom auto-healing in your Managed Soperator or Pro Solution for Soperator clusters, [contact support](https://console.nebius.com/support/create-ticket) or your personal manager. ## Upstream health checks in Managed Soperator In Managed Soperator, worker nodes are Compute virtual machines that serve as nodes in a Managed Service for Kubernetes cluster. Both Compute and Managed Kubernetes run their own health checks on worker nodes with GPUs, and Managed Soperator uses these health checks to automatically heal worker nodes, in addition to the [built-in health management system](https://docs.nebius.com/slurm-soperator/worker-nodes-health.md#health-management-in-soperator). ### Compute Compute continuously monitors hardware problems on VMs. When such a problem is detected on a VM, Compute [issues a maintenance event](https://docs.nebius.com/compute/virtual-machines/maintenance.md) for it. If a VM with a maintenance event is associated with a GPU worker node in a Managed Soperator cluster, Managed Soperator drains the node, waiting for running Slurm jobs to finish, and then re-creates the node. ### Kubernetes When Managed Service for Kubernetes signals a Kubernetes-specific maintenance condition that was not triggered by Compute, Managed Soperator drains the worker node, waiting for running Slurm jobs to finish, and then restarts the node. For more details about maintenance events and automatic recovery of nodes, see [Managed Kubernetes documentation](https://docs.nebius.com/kubernetes/maintenance/index.md). *** *InfiniBand and InfiniBand Trade Association are registered trademarks of the InfiniBand Trade Association.* # Downloading data in Soperator clusters Source: https://docs.nebius.com/slurm-soperator/storage/download-data.md Tasks that run on a Soperator cluster need large amounts of data, for example, datasets and machine learning checkpoints. You can download the data either to the shared filesystem of your Soperator cluster or to a [bucket in Object Storage](https://docs.nebius.com/object-storage/overview.md). You can use various tools to download data, depending on the size of data and the source of the download: * To download data from other Slurm clusters via SSH: * For smaller files, like code, binaries or container images, use [rsync](https://docs.nebius.com/slurm-soperator/storage/download-data.md#how-to-download-data-by-using-rsync). * For larger files, like datasets or ML checkpoints, use [rclone](https://docs.nebius.com/slurm-soperator/storage/download-data.md#how-to-download-data-by-using-rclone). * To download data to or from an Object Storage bucket or other S3-compatible storage: * For smaller files (up to 10 TiB), use [AWS CLI](https://docs.nebius.com/slurm-soperator/storage/download-data.md#how-to-download-data-by-using-the-aws-cli). * For larger files (up to 100 TiB), use [rclone](https://docs.nebius.com/slurm-soperator/storage/download-data.md#how-to-download-data-by-using-rclone). ## How to download data by using rsync [Rsync](https://rsync.samba.org/) can transfer files via SSH between a Soperator cluster and a remote server. You can use `rsync` to migrate data from an external data source to a Soperator cluster. Use `rsync` to download binaries, configuration files, container images or other small files. It is not intended for transferring large files. Unlike other tools, `rsync` can preserve file permissions and ownerships. You can combine `rsync` with `rclone` to download the files with `rclone`, then update their permissions with `rsync`. For more information, see the [example](https://docs.nebius.com/slurm-soperator/storage/download-data.md#example-with-rclone-and-rsync-combined) below. You can transfer data with `rsync` [directly](https://docs.nebius.com/slurm-soperator/storage/download-data.md#download-data-directly) or [within a Slurm job](https://docs.nebius.com/slurm-soperator/storage/download-data.md#download-data-within-a-slurm-job). ### Download data directly For example, to download a directory via SSH from a remote server to the shared filesystem of your Soperator cluster: 1. [Connect to a login node](https://docs.nebius.com/slurm-soperator/clusters/connect.md#how-to-connect-to-login-nodes) of your Soperator cluster. 2. Run the following command: ```bash rsync -azP --no-sparse \ -e "ssh -i " \ @: \ ``` In this command, specify the following: * Private SSH key for the remote server * Username and host to connect to the remote server * Path to the remote directory with data * Path to the directory in the shared filesystem where the data should be downloaded ### Download data within a Slurm job A Slurm job uses a worker node that has more processing resources than a login node. In addition, data transfer via a Slurm job continues even if your connection to a login node is interrupted. To download data within a Slurm job: 1. [Connect to a login node](https://docs.nebius.com/slurm-soperator/clusters/connect.md#how-to-connect-to-login-nodes) of your Soperator cluster. 2. Create the `rsync_copy.batch` file in the shared filesystem of your Soperator cluster and paste the following contents into it: ```bash #!/bin/bash #SBATCH -J "rsync_copy" #SBATCH --nodes=1 #SBATCH --cpus-per-task=1 #SBATCH --mem=10G usage() { echo "usage: ${0} -f -t [-i ] [-h]" >&2 echo "" >&2 echo "Arguments and should follow the rsync syntax" >&2 echo "For example:" >&2 echo " -f bob@89.168.111.222:/home/bob/remote/path/ -t /home/bob/local/path/" >&2 echo " -f /home/bob/files -t /home/alice/files" >&2 echo "Argument is required if either or is an SSH endpoint" >&2 exit 1 } while getopts f:t:i:h flag do case "${flag}" in f) COPY_FROM=${OPTARG};; t) COPY_TO=${OPTARG};; i) COPY_SSH_KEY=${OPTARG};; h) usage;; *) usage;; esac done if [ -z "${COPY_FROM}" ] || [ -z "${COPY_TO}" ]; then usage fi echo "Copy data from ${COPY_FROM} to ${COPY_TO}" srun --export=COPY_FROM,COPY_TO,COPY_SSH_KEY \ rsync -azP --no-sparse \ -e "ssh -i ${COPY_SSH_KEY}" \ "${COPY_FROM}" \ "${COPY_TO}" ' echo "Done" ``` 3. Run a job to transfer data: ```bash sbatch rsync_copy.batch -- \ -i \ -f @: \ -t ``` In this command, specify the following: * Private SSH key for the remote server * Username and host to connect to the remote server * Path to the remote directory with data * Path to the directory in the shared filesystem where the data should be downloaded ## How to download data by using rclone [Rclone](https://rclone.org/docs/) is a versatile tool for downloading or uploading data between various locations. It needs more configuration than `rsync`, but after the initial setup it allows you to download large amounts of data (10-100 TiB) fast. To work with `rclone`, create the `~/.config/rclone/rclone.conf` configuration file on the machine from which you are running the commands. In this configuration file, create profiles for each remote location and specify in them information such as the address and type of the location, or credentials for connecting to it. For the full list of location types and possible settings for them, see the [rclone documentation](https://rclone.org/docs/). After you configure `rclone` profiles for several remote locations, you can move data between these locations or to the local machine. For example, to download data from an Object Storage bucket to a shared filesystem of a Soperator cluster: 1. [Connect to a login node](https://docs.nebius.com/slurm-soperator/clusters/connect.md#how-to-connect-to-login-nodes) of your cluster. 2. Create the `~/.config/rclone/rclone.conf` configuration file. For example, this file can have the following contents: ```ini [s3mlperf] type = s3 provider = AWS env_auth = false region = eu-north1 no_check_bucket = true endpoint = https://storage.eu-north1.nebius.cloud acl = private bucket_acl = private ``` This is a remote profile for an Object Storage bucket. Add more profiles for other locations if needed. 3. Create the `rclone_copy.batch` script that transfers data between remote locations that have `rclone` profiles configured, or to the shared filesystem of your Soperator cluster. Paste the following contents into the `rclone_copy.batch` file: ```bash #!/bin/bash #SBATCH -J "rclone_copy" #SBATCH --nodes=1 #SBATCH --cpus-per-task=64 #SBATCH --mem=500G usage() { echo "usage: ${0} -f -t [-h]" >&2 echo "" >&2 echo "Arguments and should follow the rclone syntax" >&2 echo "For example:" >&2 echo " -f my-s3-profile:s3-bucket/subpath -t /home/bob/local/path" >&2 echo " -f /home/bob/local/path -t my-ssh-profile:/home/bob/remote/path" >&2 exit 1 } while getopts f:t:h flag do case "${flag}" in f) COPY_FROM=${OPTARG};; t) COPY_TO=${OPTARG};; h) usage;; *) usage;; esac done if [ -z "${COPY_FROM}" ] || [ -z "${COPY_TO}" ]; then usage fi echo "Copy data from ${COPY_FROM} to ${COPY_TO}" srun --export=COPY_FROM,COPY_TO \ bash -c ' echo "Set umask so that new files have 666 permission" umask 000 echo "Start rclone" rclone copy "${COPY_FROM}" "${COPY_TO}" --progress --links \ --transfers=32 --buffer-size=128Mi \ --multi-thread-streams=24 --multi-thread-chunk-size=128Mi \ --multi-thread-cutoff=4Gi --multi-thread-write-buffer-size=128Mi \ --checkers=24 --size-only \ --update --use-server-modtime --fast-list \ --s3-no-head-object --s3-chunk-size=32M \ --sftp-chunk-size=120k --sftp-concurrency=64 ' echo "Done" ``` The [rclone sync](https://rclone.org/commands/rclone_sync/) command synchronizes the contents of directories in two locations. To download data into an empty directory, you can also use [rclone copy](https://rclone.org/commands/rclone_copy/) or other [rclone subcommands](https://rclone.org/docs/#subcommands). 4. Run a job to download the data from the `slurm-mlperf-training` Object Storage bucket to the `mlperf-data` directory in the shared filesystem of your Soperator cluster: ```bash sbatch rclone_copy.batch -- \ -f s3mlperf:slurm-mlperf-training \ -t /mlperf-data ``` The job runs on one of the worker nodes and downloads the data to the shared filesystem, so that all nodes can access it. ### How to use several nodes for data download `rclone` is a single-node utility and doesn't let you take full advantage of Slurm parallelism. However, to speed up large downloads, you can distribute the load manually. To do so, start several jobs by using the `rclone_copy.batch` script described above and specify a different subdirectory in each job. As the Soperator cluster has a shared filesystem, the downloaded data is available to all nodes. ## Example with rclone and rsync combined `rclone` downloads files from a remote server faster than `rsync`. However, `rsync` can preserve file ownerships and permissions. You can combine these two instruments: download the files first with `rclone`, which is fast, then adjust permissions with `rsync`. To download data from a remote location configured in the `rclone` configuration file to a local directory: 1. [Connect to a login node](https://docs.nebius.com/slurm-soperator/clusters/connect.md#how-to-connect-to-login-nodes) of your Soperator cluster. 2. Create the `~/.config/rclone/rclone.conf` configuration file. In this file, specify profiles for all remote locations that you are going to use. 3. Submit the job that runs the [rclone\_copy.batch](https://docs.nebius.com/slurm-soperator/storage/download-data.md#how-to-download-data-by-using-rclone) script: ```bash sbatch rclone_copy.batch \ -f : \ -t ``` In this command, specify the following: * Name of the remote profile configured in `rclone.conf` and path to the remote directory with data * Path to the directory in the shared filesystem where the data should be downloaded 4. Get the job ID from the output of the last command: ```bash Submitted batch job ``` 5. Submit the job that runs the [rsync\_copy.batch](https://docs.nebius.com/slurm-soperator/storage/download-data.md#how-to-download-data-by-using-rsync) script with the condition that it should start after the previous job completes: ```bash sbatch rsync_copy.batch \ --dependency=afterok: \ -i \ -f @: \ -t ``` In this command, specify: * ID of the job running `rclone` that you obtained in the previous step * Private SSH key for the remote server * Username and host to connect to the remote server, and path to the remote directory with data * Path to the directory in the shared filesystem where the data should be downloaded ## How to download data by using the AWS CLI The [AWS CLI](https://docs.aws.amazon.com/cli/latest/) allows you to download data from any S3-compatible storage, including buckets in Object Storage. You can use it for smaller amounts of data (no more than 10 TiB). 1. [Connect to a login node](https://docs.nebius.com/slurm-soperator/clusters/connect.md#how-to-connect-to-login-nodes) of your Soperator cluster. 2. Create the `aws_copy.batch` file with the following contents: ```bash #!/bin/bash #SBATCH -J "aws_copy" #SBATCH --nodes=1 #SBATCH --cpus-per-task=64 #SBATCH --mem=500G srun aws s3 sync s3:///[] ``` 3. Submit the `aws_copy.batch` job: ```bash sbatch aws_copy.batch ``` For more information, see the [AWS CLI reference](https://docs.aws.amazon.com/cli/latest/reference/s3/sync.html). # Managing file access in a Soperator cluster Source: https://docs.nebius.com/slurm-soperator/storage/manage-access.md As you run machine learning workloads on the Managed Service for Soperator cluster, you need to manage access to the training data and the results of training. You can create multiple groups and users to give people with separate roles different levels of access to your data. ## How to create user groups You can [create users](https://docs.nebius.com/slurm-soperator/users/manage.md#how-to-create-a-user) for everyone who works with your cluster and add multiple groups that give their members different access permissions. Each user may be a member of several groups. You need administrator privileges to create users and groups. ### Add a group ```bash sudo addgroup ``` ### Add a user to a group ```bash sudo adduser ``` For the group membership to take effect, after you add a user to a new group, ask them to log out and [reconnect](https://docs.nebius.com/slurm-soperator/clusters/connect.md) to your cluster. ## How to manage default permissions for created files When you create a new file or directory, its permissions are determined by the [`umask` value](https://docs.nebius.com/slurm-soperator/storage/manage-access.md#umask) and the [default group settings](https://docs.nebius.com/slurm-soperator/storage/manage-access.md#default-groups) on the directory where the file is created. ### umask The `umask` specifies which bits are removed from the full permissions (`666` for files and `777` for directories). All possible permissions are listed in full in the [Ubuntu documentation](https://help.ubuntu.com/community/FilePermissions). Check your `umask` value: ```bash umask ``` The usual default value is `0002`, which means that the permissions are the following: * For new files: `0666-0002 → 0664` — everyone can read, the owner and file group members can write. * For new directories `0777-0002 → 0775` — everyone can read and execute, the owner and file group members can write. To create new files and directories with more restrictive permissions, set a different `umask`, for example: ```bash umask 0022 ``` This setting removes the write permissions from anyone but the file owner. New files are created with `644` permission, and new directories with `775`. To make the `umask` setting permanent for the current user, add it to the shell configuration: ```bash echo 'umask 0022' >> ~/.bashrc ``` ### Default groups By default, a new file belongs to the primary group of the user who created it. For a shared directory owned by a group, you may want all new files created in the directory to inherit the same group. To do that, set the `setgid` bit in its permissions: `2` instead of `0` in the high-order octal digit of the group permissions. To set the group ownership and inherit file permissions, run the following commands: ```bash sudo chown : sudo chmod 2755 ``` ## How to set granular permissions with ACLs Access Control Lists (ACLs) let you override the default permissions and explicitly specify which users or groups have different levels of access to specific files or directories. Use the `setfacl` command to set the ACL for a file or directory. For example, to give a user read and write permissions to a file, run the following command: ```bash setfacl -m u::rw- ``` To give all group members read-only access to a file, run the following command: ```bash setfacl -m g::r-- ``` ### Set default access to a directory To set default permissions, add the `-d` parameter to the `setfacl` command. This modifies the default ACL, and all new files created in this directory inherit these permissions. For example, to give all group members read, write and execute permissions to a directory and all new files created in it, run the following command: ```bash setfacl -d -m g::rwx / ``` To give a specific user read and execute permissions to a directory and all new files created in it, run the following command: ```bash setfacl -d -m u::r-x / ``` ### View current ACLs To check the current ACLs for a file or directory, run the following command: ```bash getfacl ``` Example output for a file: ```bash # file: file.txt # owner: alice # group: developers user::rw- user:test_user:r-- group::rw- group:testers:r-- other::r-- ``` Example output for a directory: ```bash # file: mnt/data # owner: alice # group: developers user::rwx user:test_user:r-- group::rwx group:testers:r-- other::r-- ``` ## Main scenarios Depending on your workflow, you can create read-only datasets or read-write working directories and configure access for individual groups or all users. ### Read-only dataset shared with all users Create a shared dataset that contains source data for training or evaluation. Make it read-only to prevent accidental changes or data corruption and ensure consistency across all training runs. 1. Create a directory in a shared filesystem, for example: ```bash sudo mkdir /mnt/data/datasets/imagenet ``` 2. Set permissions so that all users can read files, but only administrators can modify them: ```bash sudo chown root:root /mnt/data/datasets/imagenet sudo chmod 755 /mnt/data/datasets/imagenet ``` 3. Make sure your users can access it: * Single jobs can access the shared filesystem and the directory in it. * If needed, the users can mount the shared directory as a volume to their jobs or containers, in read-only mode. If at some point the users need to write to this directory, they have to use `sudo`. ### Read-write directory for training results Use a separate directory to save checkpoints, model outputs and logs. Make it writable by the job owners or a specific team. 1. Create a directory for results: ``` sudo mkdir /mnt/data/results ``` 2. [Create user groups](https://docs.nebius.com/slurm-soperator/storage/manage-access.md#add-a-group) (for example, `mlteam`) and [add users to them](https://docs.nebius.com/slurm-soperator/storage/manage-access.md#add-a-user-to-a-group). For the group membership to take effect, ask the users to log out and reconnect to your cluster. 3. Grant write permissions to the required group, for example: ```bash sudo chown :mlteam /mnt/data/results sudo chmod 2775 /mnt/data/results ``` The `2` in `2775` sets the `setgid` bit to ensure that all new files in the directory inherit the group. Encourage users to organize their work into subdirectories by project or date to avoid file conflicts when writing to the directory. ### Collaboration between two groups When two groups work on related tasks, configure three shared directories: private to group A, private to group B and accessible to everyone. 1. [Create user groups](https://docs.nebius.com/slurm-soperator/storage/manage-access.md#add-a-group). For example, `groupA` and `groupB` for each of the teams, and `users` for everyone. 2. [Add users](https://docs.nebius.com/slurm-soperator/storage/manage-access.md#add-a-user-to-a-group) to the groups. For the group membership to take effect, ask the users to log out and reconnect to your cluster. 3. Create the directories: ```bash sudo mkdir -p /mnt/data/collab/groupA /mnt/data/collab/groupB /mnt/data/collab/common ``` 4. Set the `groupA` and `groupB` directory permissions to full access for the corresponding group and no access for anyone else: ```bash sudo chown :groupA /mnt/data/collab/groupA sudo chmod 2770 /mnt/data/collab/groupA sudo chown :groupB /mnt/data/collab/groupB sudo chmod 2770 /mnt/data/collab/groupB ``` The `2` in `2770` sets the `setgid` bit to ensure that all new files in the directory inherit the group. 5. Set the `common` directory permissions to let everyone in the `users` group have full access: ```bash sudo chown :users /mnt/data/collab/common sudo chmod 2775 /mnt/data/collab/common ``` This structure allows each group to store private data while sharing common outputs or logs with all users. # Managing users in a Soperator cluster Source: https://docs.nebius.com/slurm-soperator/users/manage.md Create users in a Soperator cluster so they can [connect to the cluster nodes](https://docs.nebius.com/slurm-soperator/clusters/connect.md). A Soperator cluster uses the [Ubuntu user management tools](https://documentation.ubuntu.com/server/how-to/security/user-management/index.html), so user administration on Soperator is similar to user administration on Ubuntu. The general difference is that you [create users](https://docs.nebius.com/slurm-soperator/users/manage.md#how-to-create-a-user) with the `soperator-createuser` command, Soperator's wrapper over Ubuntu's [adduser](https://manpages.ubuntu.com/manpages/jammy/en/man8/adduser.8.html) command. Every Soperator cluster has a default administrator called `root`. To manage users, connect to cluster nodes as `root`. Only users with administrator privileges can create and delete other users. If you are not the `root` user, run the creation and deletion commands with `sudo`. ## How to create a user 1. Ask a user to [generate an SSH key pair](https://docs.nebius.com/compute/virtual-machines/ssh-keys.md) and provide you with their SSH public key. They will use this key for connections. 2. [Connect to a login node](https://docs.nebius.com/slurm-soperator/clusters/connect.md#how-to-connect-to-login-nodes). 3. Run the user creation command and specify a new username: ```bash soperator-createuser [--with-password] [--without-sudo] [--without-docker] ``` You can add optional parameters. The `soperator-createuser` command supports the [same parameters](https://manpages.ubuntu.com/manpages/jammy/en/man8/adduser.8.html) as `adduser` and has several parameters of its own: * `--with-password`: Requires a password for the new user, in addition to their SSH key. * `--without-sudo`: Disables the default option to run commands with `sudo` for the user. * `--without-docker`: Disables the default option to run `docker` commands without `sudo` for the user. By default, `soperator-createuser` adds the user to the Unix `docker` group, which allows running `docker` commands without `sudo`. You can disable this by using the `--without-docker` parameter. For more information about the group, see the [Docker documentation](https://docs.docker.com/engine/install/linux-postinstall/#manage-docker-as-a-non-root-user). 4. At the prompt that appears, enter the following information: * Password of the user, if you specified the `--with-password` parameter. * Optional full name of the user. We recommend specifying it, especially if the username does not match the full name. This helps you recognize the user. * Additional optional information, such as their room number or work phone. * SSH public key of the user. ## How to get a list of users 1. [Connect to a login node](https://docs.nebius.com/slurm-soperator/clusters/connect.md#how-to-connect-to-login-nodes). 2. Run the user list command: ```bash getent passwd ``` Output example: ```text root:x:0:0:root:/root:/bin/bash daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin bin:x:2:2:bin:/bin:/usr/sbin/nologin sys:x:3:3:sys:/dev:/usr/sbin/nologin ... test-user-1:x:1004:1004:Test User Name,,,:/home/test-user-1:/bin/bash ``` System users have IDs that are less than `1000`. Regular users have IDs that are larger than or equal to `1000`. In the example above, the system `bin` user has the ID `2` and the regular `test-user-1` user has the ID `1004`. ## How to delete a user 1. [Connect to a login node](https://docs.nebius.com/slurm-soperator/clusters/connect.md#how-to-connect-to-login-nodes). 2. To copy the username, [get the list of users](https://docs.nebius.com/slurm-soperator/users/manage.md#how-to-get-a-list-of-users). 3. Run the user deletion command: ```bash deluser --remove-home ``` The command deletes the user and its home directory. Output example: ```text Looking for files to backup/remove ... Removing files ... Removing user `test-user-1' ... Warning: group `test-user-1' has no more members. Done. ``` For more information about deleting users by using `deluser`, see the [Ubuntu documentation](https://documentation.ubuntu.com/server/how-to/security/user-management/index.html#delete-a-user). # How to monitor job and node statuses in a Soperator cluster Source: https://docs.nebius.com/slurm-soperator/monitoring/statuses.md In a Soperator cluster, Slurm nodes run as Kubernetes® Pods. You can monitor the nodes by using Slurm commands, which are listed in a [cheat sheet](https://github.com/nebius/nebius-solution-library/blob/main/docs/SLURM-Quick-reference.pdf). For more information about monitoring an underlying Kubernetes cluster, see [Managed Service for Kubernetes® documentation](https://docs.nebius.com/kubernetes/monitoring.md). To run the monitoring commands, [connect to a login node](https://docs.nebius.com/slurm-soperator/clusters/connect.md#how-to-connect-to-login-nodes). ## Cluster status To list current worker nodes, run the following command: ```bash sinfo -Nel ``` This command returns a list of detailed information about the nodes. For more information about other parameters available for `sinfo`, see [Slurm documentation](https://slurm.schedmd.com/sinfo.html#SECTION_OPTIONS). Output example: ```text NODELIST NODES PARTITION STATE CPUS S:C:T MEMORY TMP_DISK WEIGHT AVAIL_FE REASON worker-0 1 main* idle 128 2:32:2 155340 0 1 (null) none worker-1 1 main* idle 128 2:32:2 155340 0 1 (null) none ``` Only worker nodes are listed in this view. If the node state has an asterisk next to it, for example, `idle*`, this means that the node did not respond and it is unavailable. The node goes `down` if it does not respond quickly. For more information about common node states, see [Node states](https://docs.nebius.com/slurm-soperator/monitoring/statuses.md#node-states). You can customize the columns in the `sinfo` output by using the `-o` parameter. For example, `sinfo -o "%20P %5D %14F %8z %10m %10d %11l %16f %N"` lists the partitions, gives you the total number of nodes and shows which nodes are free, how much memory is available and the time limits for jobs currently being executed. For more information about these parameters, see [Slurm documentation](https://slurm.schedmd.com/sinfo.html#OPT_format). To get more information about a particular node, run the following command: ```bash scontrol show node ``` ### Node states Some of the common node states include: | Node state | Description | State causes | | ----------- | ----------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------ | | `idle` | The node is not currently running any jobs and is available for scheduling. | No jobs assigned yet. | | `allocated` | The node is actively running one or more jobs. | A job has been assigned and is executing. | | `mixed` | Some CPUs on the node are allocated to jobs, while others remain idle. | Partial job allocations. | | `down` | The node is unavailable for use. | Hardware failure, maintenance or manual marking by an admin. | | `drained` | The node is excluded from the scheduling pool for new jobs. Jobs submitted before the node was drained may run to completion. | Marked for draining manually or by Soperator health checks. | | `unknown` | The node state cannot be determined. | Communication issues between the controller and the node. | | `fail` | The node has failed and cannot execute jobs. | Critical hardware or software issues. | For a complete list of all possible node states, see [Slurm documentation](https://slurm.schedmd.com/sinfo.html#SECTION_NODE-STATE-CODES). ### How to drain and resume a node To drain a node (that is, stop scheduling more jobs and make the node unavailable), run the following command: ```bash scontrol update NodeName= State=drain Reason="" ``` To resume a node that was drained, run the following command: ```bash scontrol update NodeName= State=resume ``` ## Job queue To list all jobs currently running or pending (that is, waiting for resources), run the following command: ```bash squeue -a ``` To list all jobs currently running, run the following command: ```bash squeue -tR ``` Output example: ```text JOBID PARTITION NAME USER ST TIME NODES NODELIST(REASON) 116 main nccl test-user R 0:17 1 worker-1 ``` For pending jobs with the `PD` status, the `NODELIST(REASON)` column shows the reason why the job is pending. For more information about possible reasons for this status, see [Slurm documentation](https://slurm.schedmd.com/squeue.html#SECTION_JOB-REASON-CODES). ### Job details To use the job ID to get more details about the job, run the following command: ```bash scontrol show job ``` ### Completed job statistics To get the details about the jobs already completed, run the following command: ```bash sacct -a ``` Output example: ```text JobID JobName Partition Account AllocCPUS State ExitCode ------------ ---------- ---------- ---------- ---------- ---------- -------- 24 nccl_test main root 16 COMPLETED 0:0 24.0 nccl_test root 16 COMPLETED 0:0 ``` For more information about additional parameters available for `sacct`, see [Slurm documentation](https://slurm.schedmd.com/sacct.html#SECTION_OPTIONS). # Monitoring metrics of Soperator clusters Source: https://docs.nebius.com/slurm-soperator/monitoring/metrics.md You can monitor the performance of your Soperator cluster on preconfigured dashboards in Grafana®. ## Prerequisites 1. [Connect](https://docs.nebius.com/slurm-soperator/clusters/connect.md) to your cluster. You should see the SSH welcome message. For example: ``` Welcome to Soperator cluster ... System information as of Thu May 8 10:43:02 UTC 2025: ... Slurm nodes: PARTITION CPUS MEMORY GRES NODES NODELIST STATE REASON main 128 1553408 gpu:nvidia_h100_80gb_hbm3:8(S:0-1) 2 worker-[0-1] idle none No user jobs in the queue No other users are currently logged in To open monitoring dashboards in your browser: 1. Execute this command on your local computer: `ssh -L 3000:metrics-grafana.monitoring-system.svc:80 -N @` 2. Open `localhost:3000` in your browser ... ``` 2. Get the command to open monitoring dashboards from the instructions in the SSH welcome message. In the example above, it is `ssh -L 3000:metrics-grafana.monitoring-system.svc:80 -N @`. The URL for your cluster might be different. ## How to view metrics in Grafana 1. On your local machine, run the command to open monitoring dashboards that you got from the SSH welcome message. For example: ```bash ssh -L 3000:metrics-grafana.monitoring-system.svc:80 -N @ ``` In this command, specify the `username` and `public_IP_address` that you use to [connect](https://docs.nebius.com/slurm-soperator/clusters/connect.md) to the cluster. Optionally, change port `3000` if it is already in use on your local machine. 2. Open `localhost:3000` (or `localhost:`) in your browser. 3. In the sidebar, select **Dashboards**. Review the metrics on these dashboards. For example, you can see the metrics of Slurm jobs and resource allocations. ## How to view metrics for worker nodes The nodes of your Soperator cluster are Compute virtual machines. You can view their metrics on Monitoring [dashboards in the web console](https://docs.nebius.com/compute/monitoring/virtual-machines.md#explore-the-dashboard). To find out the ID of the virtual machine for a worker node: 1. [Connect](https://docs.nebius.com/slurm-soperator/clusters/connect.md#how-to-connect-to-login-nodes) to a login node of your Soperator cluster. 2. Run the following command: ```bash scontrol show node worker- ``` Output example: ```bash NodeName=worker-0 Arch=x86_64 CoresPerSocket=32 CPUAlloc=0 CPUEfctv=128 CPUTot=128 CPULoad=0.97 AvailableFeatures=(null) ActiveFeatures=(null) Gres=gpu:nvidia_h100_80gb_hbm3:8(S:0-1) NodeAddr=10.0.35.138 NodeHostName=worker-0 Version=24.05.5 OS=Linux 5.15.0-133-generic #144-Ubuntu SMP Fri Feb 7 20:47:38 UTC 2025 RealMemory=1553408 AllocMem=0 FreeMem=1421003 Sockets=2 Boards=1 State=IDLE+DYNAMIC_NORM ThreadsPerCore=2 TmpDisk=0 Weight=1 Owner=N/A MCS_label=N/A Partitions=main BootTime=2025-03-11T11:28:45 SlurmdStartTime=2025-03-11T12:39:23 LastBusyTime=2025-05-08T13:42:21 ResumeAfterTime=None CfgTRES=cpu=128,mem=1517G,billing=128 AllocTRES= CurrentWatts=0 AveWatts=0 Extra={ "monitoring": "https://console.eu.nebius.com/project-e00x6706bdmd42yjyn/compute/instances/computeinstance-****/monitoring" } InstanceId=computeinstance-**** ``` Get the link from the `monitoring` parameter. 3. Open the link in your browser. There, you can view the dashboards for the virtual machine that runs the worker node. *** *The Grafana Labs Marks are trademarks of Grafana Labs, and are used with Grafana Labs' permission. We are not affiliated with, endorsed or sponsored by Grafana Labs or its affiliates.* # Viewing logs of Soperator clusters Source: https://docs.nebius.com/slurm-soperator/monitoring/logs.md You can view logs of your Soperator cluster either [in a browser](https://docs.nebius.com/slurm-soperator/monitoring/logs.md#how-to-view-logs-in-a-browser) or directly [on the worker nodes](https://docs.nebius.com/slurm-soperator/monitoring/logs.md#how-to-view-log-files-on-a-worker-node). ## Prerequisites 1. [Connect](https://docs.nebius.com/slurm-soperator/clusters/connect.md) to your cluster. You should see the SSH welcome message. For example: ``` Welcome to Soperator cluster ... System information as of Thu May 8 10:43:02 UTC 2025: ... Slurm nodes: PARTITION CPUS MEMORY GRES NODES NODELIST STATE REASON main 128 1553408 gpu:nvidia_h100_80gb_hbm3:8(S:0-1) 2 worker-[0-1] idle none ... To open logs explorer in your browser: 1. Execute this command on your local computer: `ssh -L 9428:vm-logs-victoria-logs-single-server.logs-system.svc:9428 -N @` 2. Open `localhost:9428/select/vmui` in your browser ... ``` 2. Get the command to open monitoring dashboards from the instructions in the SSH welcome message. In the example above, it is `ssh -L 9428:vm-logs-victoria-logs-single-server.logs-system.svc:9428 -N @`. The URL for your cluster might be different. ## How to view logs in a browser 1. On your local machine, run the command to open logs explorer that you got from the SSH welcome message. For example: ```bash ssh -L 9428:vm-logs-victoria-logs-single-server.logs-system.svc:9428 -N @ ``` In this command, specify the `username` and `public_IP_address` that you use to [connect](https://docs.nebius.com/slurm-soperator/clusters/connect.md) to the cluster. 2. Open `localhost:9428/select/vmui` in your browser. 3. Explore the logs. You can use the [LogsQL](https://docs.victoriametrics.com/victorialogs/logsql/) language to write queries that filter the logs you want to review. For example: * Logs of the Slurm daemon that runs on the `worker-0` node: ``` k8s.container.name: "slurmd" AND k8s.pod.name: "worker-0" ``` * Logs of all Slurm controllers: ``` kubernetes.container_name: "slurmctld" ``` * Logs of Slurm daemons and controllers that relate to the job with the ID `123`: ``` k8s.container.name: ~"slurmctld|slurmd" AND 123 ``` * Logs of the SSH daemon that runs on the `login-0` node: ``` k8s.container.name: "sshd" AND k8s.pod.name: "login-0" ``` * Errors in logs of Slurm daemons and controllers: ``` k8s.container.name: ~"slurmctld|slurmd" AND "error" ``` ## How to view log files on a worker node 1. [Connect](https://docs.nebius.com/slurm-soperator/clusters/connect.md#how-to-connect-to-worker-nodes) to a worker node of your Soperator cluster. 2. View the logs of the Slurm daemon that runs on this node: ```bash less /var/log/slurm/slurmd.log ``` ### Managed Service for Kubernetes® # Managed Service for Kubernetes® Source: https://docs.nebius.com/kubernetes/index.md With Kubernetes, you can efficiently manage and scale your containerized ML/AI applications and ensure they are portable and fault-tolerant. Nebius AI Cloud offers Managed Service for Kubernetes, which simplifies cluster deployment and management for Kubernetes. The service is available in all Nebius AI Cloud regions. *InfiniBand and InfiniBand Trade Association are registered trademarks of the InfiniBand Trade Association.* Create your first cluster for Kubernetes and connect to it Learn how to manage clusters and their parameters Manage node groups that form clusters for Kubernetes Use the Kubernetes native CLI to work with your clusters Add GPUs to nodes in your clusters for ML/AI workloads Accelerate your GPU-powered workloads with high-performance networking Control resource usage and health of your clusters and nodes # How to get started with Managed Service for Kubernetes®: Create your first cluster for Kubernetes Source: https://docs.nebius.com/kubernetes/quickstart.md With [Kubernetes](https://kubernetes.io/), you can efficiently manage and scale your containerized ML/AI applications and ensure they are portable and fault-tolerant. To get started, create a Managed Service for Kubernetes cluster and its child node group in the `eu-north1` region. Then, connect to the cluster. ## Prerequisites 1. [Install and configure](https://docs.nebius.com/cli/install.md) the Nebius AI Cloud CLI. You will use the CLI to get the cluster credentials for connecting with kubectl. 2. Install [kubectl](https://kubernetes.io/docs/tasks/tools/#kubectl), the Kubernetes command-line interface: ```bash Ubuntu curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl" sudo install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl ``` ```bash macOS curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/darwin/arm64/kubectl" chmod +x ./kubectl sudo mv ./kubectl /usr/local/bin/kubectl sudo chown root: /usr/local/bin/kubectl ``` 1. [Install and configure](https://docs.nebius.com/cli/install.md) the Nebius AI Cloud CLI. 2. Install [jq](https://jqlang.github.io/jq/) to extract IDs from JSON data returned by the Nebius AI Cloud CLI: ```bash Ubuntu sudo apt-get install jq ``` ```bash macOS brew install jq ``` 3. Install [kubectl](https://kubernetes.io/docs/tasks/tools/#kubectl), the Kubernetes command-line interface: ```bash Ubuntu curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl" sudo install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl ``` ```bash macOS curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/darwin/arm64/kubectl" chmod +x ./kubectl sudo mv ./kubectl /usr/local/bin/kubectl sudo chown root: /usr/local/bin/kubectl ``` ## Steps ### Create a cluster and a node group 1. In the sidebar, go to  **Compute** → **Kubernetes**. 2. Click  **Create cluster**. The creation flow is a step-by-step wizard. The sidebar shows your progress through the configuration sections. To move between sections, click **Back** and **Next**. 3. On the **Cluster** step, enter the cluster name and review the settings: * Select the network and subnet. * Keep the recommended Kubernetes version 1.34. For supported versions, see [Kubernetes® versions in Managed Service for Kubernetes](https://docs.nebius.com/kubernetes/versions.md). * Keep the public endpoint enabled. As a result, the cluster is available from the internet, and you can connect to it from any machine. 4. On the **Node groups** step, add a node group to the cluster: 1. Click  **Add node group**. 2. On the **General** step, enter the node group name. Under **Size**, set the **Number of nodes** to 2. Keep the rest of the settings unchanged. 3. On the **Compute resources** step, select **Without GPU**. Select the **Non-GPU Intel Ice Lake** [platform](https://docs.nebius.com/compute/virtual-machines/types.md) and the preset with 2 CPUs and 8 Nebius uses binary units. For example, a gibibyte (GiB) is 230 (10243) bytes.}>GiB of RAM. Then, select an operating system for the nodes, for example, Ubuntu 24.04 LTS. 4. On the **Storage** step, under **Node storage**, select the **SSD** disk type and set the size to 128 GiB. 5. On the **Additional** step, keep the default settings. 6. Click **Add node group**. 5. Go to the **Review** step, check the cluster configuration and click **Create**. 6. After the cluster is created, copy the cluster ID from its page and save the ID to an environment variable. You will need it to connect to the cluster: ```bash export CLUSTER_ID= ``` 1. Your cluster's control plane and nodes use private IP addresses from the default subnet. Get its ID: ```bash export SUBNET_ID=$(nebius vpc subnet list \ --format json \ | jq -r '.items[0].metadata.id') ``` 2. Create a cluster with a public endpoint allocated to its control plane, and get the cluster ID: ```bash export CLUSTER_ID=$(nebius mk8s cluster create \ --name quickstart-mk8s-cluster \ --control-plane-subnet-id $SUBNET_ID \ --control-plane-endpoints-public-endpoint=true \ --format json | jq -r '.metadata.id') ``` The cluster's control plane runs Kubernetes version 1.34, which is the default [version](https://docs.nebius.com/kubernetes/versions.md) for Managed Kubernetes clusters. 3. Create a node group and add it to the cluster: ```bash nebius mk8s node-group create \ --name quickstart-mk8s-nodes \ --parent-id $CLUSTER_ID \ --fixed-node-count 2 \ --template-resources-platform "cpu-e2" \ --template-resources-preset "2vcpu-8gb" \ --template-boot-disk-type network_ssd \ --template-boot-disk-size-bytes 137438953472 \ --template-network-interfaces "[{\"subnet_id\": \"$SUBNET_ID\"}]" ``` The command creates a group of 2 nodes. Each node is a non-GPU (`--template-resources-platform "cpu-e2"`) virtual machine that has 2 vCPUs, 8 Nebius uses binary units. For example, a gibibyte (GiB) is 230 (10243) bytes.}>GiB of RAM, and a 128 GiB Network SSD boot disk. ### Connect to the cluster 1. Create a kubeconfig file containing the cluster details for kubectl: ```bash nebius mk8s cluster get-credentials \ --id $CLUSTER_ID --external ``` 2. Check that the cluster is accessible. For example: * Get addresses of the control plane and cluster services: ```bash kubectl cluster-info ``` * Get the list of Pods: ```bash kubectl get pods -A ``` ## What's next * [How to create and modify Managed Service for Kubernetes® clusters](https://docs.nebius.com/kubernetes/clusters/manage.md) * [Creating and modifying Managed Service for Kubernetes® node groups](https://docs.nebius.com/kubernetes/node-groups/manage.md) # Components in Managed Service for Kubernetes® Source: https://docs.nebius.com/kubernetes/components.md This article provides a quick overview of the Managed Service for Kubernetes components, their interactions and functions. A Managed Service for Kubernetes cluster consists of: * [Control plane](https://docs.nebius.com/kubernetes/components.md#control-plane-components) * [Node components](https://docs.nebius.com/kubernetes/components.md#node-based-control-plane-components) * Sets of worker VMs ([nodes](https://docs.nebius.com/kubernetes/components.md#node) and [node groups](https://docs.nebius.com/kubernetes/components.md#node-group)) that run groups of containerized applications ([Pods](https://docs.nebius.com/kubernetes/components.md#pod)) ## Control plane components **Control plane** components manage the overall state of the cluster. ### API server The **API server** exposes the Kubernetes API to customers, acting as a frontend for [REST](https://www.geeksforgeeks.org/rest-api-introduction/) operations. To learn more, see the official Kubernetes documentation for [kube-apiserver](https://kubernetes.io/docs/concepts/overview/kubernetes-api/). ### Scheduler **Scheduler** is responsible for determining which [node](https://docs.nebius.com/kubernetes/components.md#node) runs a particular [Pod](https://docs.nebius.com/kubernetes/components.md#pod) with specified containers. When selecting a node to allocate a Pod, the scheduler takes into account quotas, resource requirements, deployments, taints and tolerations and other factors. To learn more, see the official Kubernetes documentation for [Kubernetes scheduler](https://kubernetes.io/docs/concepts/scheduling-eviction/kube-scheduler/). ### Cluster autoscaler In Managed Service for Kubernetes, the **cluster autoscaler** seamlessly adds nodes when there are unschedulable Pods, and removes underutilized nodes as needed. For more information, see [Autoscaling in Managed Service for Kubernetes](https://docs.nebius.com/kubernetes/node-groups/autoscaling.md). ### Controller manager **Controller manager** runs controllers to implement Kubernetes API behavior. To reduce complexity, multiple controllers are compiled into one binary and run as a single process. Below are examples of frequently used controllers: * **Node controller** ensures that each node is operational. If a node shuts down, node controller tries to restart it or relocate its Pods and containers to other nodes. * **Replication controller** ensures that the same Pods are deployed across multiple nodes if required. * **Endpoint controller** ensures that containers are accessible to users. To learn more, see the official Kubernetes documentation for [kube-controller-manager](https://kubernetes.io/docs/concepts/architecture/controller/). ### etcd **etcd** is a consistent and highly available key-value store for API server data. By default, a Managed Kubernetes cluster is [created](https://docs.nebius.com/kubernetes/clusters/manage.md#how-to-create-clusters) with three etcd stores. This ensures high availability: The cluster is more reliable; data stored in etcd is more likely to be accessed in case of failures. The enabled high availability does not affect the cost of the cluster. You can find in-depth information on etcd in its [official documentation](https://etcd.io/docs/). ## Node-based control plane components These components are located not in the control plane itself, but on each [node](https://docs.nebius.com/kubernetes/components.md#node) running on the cluster. ### kubelet **kubelet** ensures that [Pods](https://docs.nebius.com/kubernetes/components.md#pod) and their containers are running. It communicates with the [scheduler](https://docs.nebius.com/kubernetes/components.md#scheduler) and [controller manager](https://docs.nebius.com/kubernetes/components.md#controller-manager). To learn more, see the official Kubernetes documentation for [kubelet](https://kubernetes.io/docs/reference/command-line-tools-reference/kubelet/). ### kube-proxy **kube network proxy** manages traffic flow, ensuring that network rules work on [nodes](https://docs.nebius.com/kubernetes/components.md#node). To learn more, see the official Kubernetes documentation for [kube-proxy](https://kubernetes.io/docs/reference/command-line-tools-reference/kube-proxy/). ### Cilium **Cilium** ensures that only specific services and traffic can access certain [Pods](https://docs.nebius.com/kubernetes/components.md#pod). For example: * Some [Pods](https://docs.nebius.com/kubernetes/components.md#pod) might contain sensitive data, and Cilium enforces rules that only certain internal services or authorized users are allowed to access it. * If a [node](https://docs.nebius.com/kubernetes/components.md#node) requires restricted access, Cilium ensures that only internal services with proper credentials or traffic with specific labels are allowed. Also, Cilium provides observability into traffic between [Pods](https://docs.nebius.com/kubernetes/components.md#pod) and [nodes](https://docs.nebius.com/kubernetes/components.md#node) to optimize network paths and enforce network security policies. You can find in-depth information on Cilium in its [official documentation](https://docs.cilium.io/en/stable/index.html). ## Worker components This section describes the components that run and manage user workloads on your Managed Service for Kubernetes cluster. ### Node In Managed Service for Kubernetes, **nodes** are [Compute virtual machines](https://docs.nebius.com/compute/virtual-machines/types.md). There must be at least one node in a cluster for applications to function properly. On [supported platforms, presets and regions](https://docs.nebius.com/compute/storage/local-disks.md#availability), you can enable [local SSD disks](https://docs.nebius.com/compute/storage/types.md#local-ssd-disks) for worker nodes. Local SSD disks provide ephemeral storage intended for temporary data. By default, Managed Service for Kubernetes uses them as the node's [local ephemeral storage](https://kubernetes.io/docs/concepts/storage/ephemeral-storage/). Do **not** modify Managed Service for Kubernetes nodes in Compute. Kubernetes nodes are listed on the **Kubernetes nodes** tab of the **Virtual machines** page, but manage them in the **Managed Service for Kubernetes®** section instead. To learn more, see the official Kubernetes documentation for [nodes](https://kubernetes.io/docs/concepts/architecture/nodes/). ### Node group **Node groups** in Managed Service for Kubernetes organize [nodes](https://docs.nebius.com/kubernetes/components.md#node) that serve a specific purpose. All nodes in a group share the same template. The number of nodes per node group cannot exceed 100. See more details in [Creating and modifying Managed Service for Kubernetes® node groups](https://docs.nebius.com/kubernetes/node-groups/manage.md). Node groups can use the cluster autoscaler to seamlessly add or remove nodes as needed. For more information, see [Autoscaling in Managed Service for Kubernetes](https://docs.nebius.com/kubernetes/node-groups/autoscaling.md). ### Pod **Pod** is a group of one or more containers with shared storage and network resources. In a Managed Service for Kubernetes cluster, each Pod has a unique IP address so that workloads don't conflict. To learn more, see the official Kubernetes documentation for [Pods](https://kubernetes.io/docs/concepts/workloads/pods/). ### Taints and tolerations **Taints** act like restrictions or rules for specific [nodes](https://docs.nebius.com/kubernetes/components.md#node). **Tolerations** are like clearances or permissions that certain [Pods](https://docs.nebius.com/kubernetes/components.md#pod) have to be placed on specified [nodes](https://docs.nebius.com/kubernetes/components.md#node). To learn more, see the official Kubernetes documentation for [taints and tolerations](https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/). ### DaemonSets **DaemonSets** ensure that every node creates a Pod with a certain type of container. In Kubernetes, DaemonSets are used for infrastructure-related workloads, such as logging, monitoring or networking agents that must be deployed on every node. To learn more, see the official Kubernetes documentation for [DaemonSets](https://kubernetes.io/docs/concepts/workloads/controllers/daemonset/). # Kubernetes® versions in Managed Service for Kubernetes Source: https://docs.nebius.com/kubernetes/versions.md You can configure the [Kubernetes version](https://kubernetes.io/releases/) that is used on your Managed Kubernetes clusters and node groups. * **Clusters**: The Kubernetes version is used for [control plane components](https://kubernetes.io/docs/concepts/architecture/#control-plane-components). It is *required* when [creating a cluster](https://docs.nebius.com/kubernetes/clusters/manage.md#how-to-create-clusters). * **Node groups**: The Kubernetes version is used for node components. It is *optional* when [creating a node group](https://docs.nebius.com/kubernetes/node-groups/manage.md#how-to-create-node-groups). By default, a node group uses the same Kubernetes version as its parent cluster. A node group cannot have a higher version than the cluster. ## Available Kubernetes versions The following Kubernetes versions are currently supported for clusters and node groups: * [1.34](https://kubernetes.io/releases/#release-v1-34): Recommended. New clusters use this version. * [1.33](https://kubernetes.io/releases/#release-v1-33) * [1.32](https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG/CHANGELOG-1.32.md), [1.31](https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG/CHANGELOG-1.31.md) and [1.30](https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG/CHANGELOG-1.30.md): Not recommended as they reached end of life. These versions are supported for clusters created earlier, but we recommend upgrading to the newest version. For the version deprecation policy and end-of-life timeline, see [Kubernetes® version deprecation policy in Managed Service for Kubernetes](https://docs.nebius.com/kubernetes/version-deprecation.md). ## Upgrading Kubernetes version You can upgrade a cluster to a newer Kubernetes version manually; automatic upgrade is not supported. To do so, upgrade the control plane first and then the node groups. Node groups are not upgraded automatically together with the cluster, even if you created the cluster and node groups with the same version. Consider possible downtimes during the upgrade: * If the control plane is not highly available—that is, it has only one [etcd store](https://docs.nebius.com/kubernetes/components.md#etcd)—the cluster becomes unavailable during the control plane upgrade. * When you upgrade a node group, the nodes are replaced one by one, according to the node group's [deployment strategy](https://docs.nebius.com/kubernetes/node-groups/manage.md#node-group-parameters). If `.spec.strategy.max_unavailable` is greater than `0`, some nodes might be unavailable during the upgrade. You can check the node group specifications by using the following command: ```bash nebius mk8s node-group get --id ``` See detailed instructions in [Setting and upgrading Kubernetes® versions in Managed Service for Kubernetes](https://docs.nebius.com/kubernetes/manage-versions.md). # Setting and upgrading Kubernetes® versions in Managed Service for Kubernetes Source: https://docs.nebius.com/kubernetes/manage-versions.md You can set the [Kubernetes version](https://kubernetes.io/releases/) that is used on your Managed Kubernetes clusters and node groups during creation. For existing clusters and node groups, you can upgrade the version. For more information about available versions and the upgrade, see [Kubernetes® versions in Managed Service for Kubernetes](https://docs.nebius.com/kubernetes/versions.md). ## How to set a Kubernetes version 1. In the sidebar, go to  **Compute** → **Kubernetes**. 2. Click  **Create cluster**. 3. In the **Control plane** section, select the Kubernetes version from the drop-down list. It is not currently possible to set a Kubernetes version for a node group in the web console. Use the following parameters: * For clusters ([nebius mk8s cluster create](https://docs.nebius.com/cli/reference/mk8s/cluster/create)): ```sh --control-plane-version ``` * For node groups ([nebius mk8s node-group create](https://docs.nebius.com/cli/reference/mk8s/node-group/create)): ```sh --version ``` The Kubernetes version for a node group must not be higher than for the control plane. ## How to upgrade a Kubernetes version To upgrade a Managed Kubernetes cluster to a new version, upgrade the control plane first and then the node groups. 1. Get the ID of the cluster: ```bash nebius mk8s cluster get-by-name \ --name --format json | jq -r '.metadata.id' ``` 2. Upgrade the control plane: ```bash nebius mk8s cluster update \ --id \ --control-plane-version ``` 3. After the upgrade is completed, get the ID of the node group: ```bash nebius mk8s node-group get-by-name \ --parent-id \ --name --format json | jq -r '.metadata.id' ``` 4. Upgrade the node group: ```bash nebius mk8s node-group update \ --id \ --version ``` The Kubernetes version for a node group must not be higher than for the control plane. # Kubernetes® version deprecation policy in Managed Service for Kubernetes Source: https://docs.nebius.com/kubernetes/version-deprecation.md This article describes how Managed Service for Kubernetes handles Kubernetes version deprecation. ## How many versions are available Managed Service for Kubernetes supports a limited set of Kubernetes minor versions. At any time, no more than four Kubernetes minor versions are available: * No more than three supported versions: fully supported for new and existing clusters. * One deprecated version: supported for existing clusters, receives updates from Managed Service for Kubernetes, but **isn't available** for creating new clusters. See the current list in [Kubernetes® versions in Managed Service for Kubernetes](https://docs.nebius.com/kubernetes/versions.md). ## When a version becomes deprecated A version becomes **deprecated** when a newer minor version is introduced and the oldest supported version moves out of the supported set. A deprecated version stays available for existing clusters for **two months**, after which it becomes unavailable. Creating new clusters with that version isn't possible. The end-of-life date for each version is shown in [nebius mk8s cluster list-control-plane-versions](https://docs.nebius.com/cli/reference/mk8s/cluster/list-control-plane-versions). If your cluster uses a deprecated version, you'll see a notification in the [web console](https://console.nebius.com/mk8s), when using Terraform, or when reading cluster info via [nebius mk8s cluster get](https://docs.nebius.com/cli/reference/mk8s/cluster/get). When a version reaches its end-of-life date, clusters using it are upgraded automatically within a short period. ## How clusters are upgraded by the service Managed Service for Kubernetes keeps clusters within the supported version window to maintain security and reliability. * **Control plane**: upgraded automatically when your cluster with a deprecated version reaches end of life. * **Node groups**: upgraded automatically only when required to keep the control plane within the [Kubernetes version skew policy](https://kubernetes.io/releases/version-skew-policy/#kubelet) (no more than three minor versions behind the control plane). Node groups are upgraded to match the control plane version, so they can jump several versions at once. > For example, if your cluster's control plane is running 1.33 and worker nodes are running 1.30, when 1.33 is deprecated the control plane is upgraded to 1.34 and the worker nodes to 1.33. ## How to upgrade your cluster yourself You can upgrade your cluster on your own schedule. This gives you control over timing and allows you to prepare workloads in advance. See the step-by-step guide in [Setting and upgrading Kubernetes® versions in Managed Service for Kubernetes](https://docs.nebius.com/kubernetes/manage-versions.md). ## Risks of not upgrading a cluster yourself If you don't upgrade a cluster in time, Managed Service for Kubernetes will upgrade your cluster automatically. This can introduce the following risks: * The cluster specification and status don’t match. Managed Service for Kubernetes doesn’t modify the cluster specification; however, the cluster continues to be updated, as reflected in its status. * Unexpected maintenance timing for control plane or node group upgrades. * Workload disruption from node replacements during node group upgrades. * Compatibility issues due to Kubernetes API removals. * Larger version jumps, which are harder to validate than planned, gradual upgrades. To reduce risk, plan upgrades ahead of deprecation dates and keep clusters on supported versions. # How to create and modify Managed Service for Kubernetes® clusters Source: https://docs.nebius.com/kubernetes/clusters/manage.md Managed Service for Kubernetes clusters manage and run containerized applications, providing automatic scaling, load balancing and streamlined deployment and management. In this guide, you will learn how to create, modify and delete clusters in Managed Service for Kubernetes. For more information on managing node groups and adding them to clusters, see [Creating and modifying Managed Service for Kubernetes® node groups](https://docs.nebius.com/kubernetes/node-groups/manage.md). ## How to create clusters 1. In the sidebar, go to  **Compute** → **Kubernetes**. 2. Click  **Create cluster**. 3. On the **Cluster** step, configure the cluster: 1. In the **General** section: * Enter the cluster name. * (Optional) Enter labels in the `key:value` format. 2. In the **Network** section, review the network and subnet. They are selected by default. 3. In the **Control plane** section: * The Kubernetes version is set by default. For supported versions, see [Kubernetes® versions in Managed Service for Kubernetes](https://docs.nebius.com/kubernetes/versions.md). * A public endpoint is allocated by default. As a result, the cluster is available from the internet, you can connect to it from any machine. If you want to prevent access to the cluster from the internet, disable the public endpoint option. Then, you can connect to the cluster only from a virtual machine (VM) located in the same subnet as the cluster. To only allow certain addresses to connect to the cluster, enable the public endpoint and [configure an allowlist of IP addresses](https://docs.nebius.com/kubernetes/networking/limit-access-to-public-endpoint.md) for the cluster. 4. (Optional) In the **Observability** section, enable **Audit logs** to record metadata about operations that modify the cluster. For details, see [Logs in Managed Service for Kubernetes](https://docs.nebius.com/kubernetes/logs.md). 5. Click **Next**. 4. On the **Node groups** step, optionally configure one or more node groups. You can create a cluster without node groups and add them later. For more information, see [Creating and modifying Managed Service for Kubernetes® node groups](https://docs.nebius.com/kubernetes/node-groups/manage.md). To add a node group during cluster creation: 1. Click **Add node group**. 2. Configure the node group. If you have [capacity block groups](https://docs.nebius.com/overview/limits/capacity-block-groups.md), the **Reservations** step is also shown between **General** and **Compute resources**. 1. On the **General** step: * Enter the node group name. * (Optional) Enable **Assign public IPv4 addresses** if you want the nodes to be accessible from the internet. * Under **Size**: * (Optional) Enable **Autoscaling** if you want to let the node group scale up or down depending on the workload. * Specify the initial **Number of nodes**. * Under **Advanced**: * **Auto-repair** is enabled by default. When enabled, Managed Kubernetes automatically replaces unhealthy nodes. * (Optional) Specify **Max pods per node** to limit how many Pods can run on each node in the group. 2. If the **Reservations** step is shown, select **Reservation usage**: * **With reservations**: Resources are allocated from reservations ([capacity block groups](https://docs.nebius.com/overview/limits/capacity-block-groups.md)). This ensures that resources are always available, even if VMs in the node group are stopped (for example, by you or a [maintenance event](https://docs.nebius.com/kubernetes/maintenance/index.md)). In the **Reservation** section, you can configure the following options: * **Any (existing and future)** (default): Compute selects among your matching capacity block groups automatically. * **Specific capacity block groups**: Select one or more capacity block groups. Each option shows the capacity block group ID, reservation period and GPU usage. Make sure the selected groups have enough capacity and do not expire soon. * **Switch to PAYG**: Choose whether the VM can start after you create or restart it without active intervals in selected capacity block groups: * **When reservation is exhausted** (default): The VM can start as a pay-as-you-go VM when no capacity is available in the selected capacity block groups. * **Never**: The VM cannot start without available capacity in the selected capacity block groups. This does not affect the VM when it is running. If an interval in a selected capacity block group expires while the VM is running, the VM always continues as a pay-as-you-go VM, regardless of this setting. If you have capacity block groups in multiple regions, select a **Region** first. * **Without reservations**: Resources are allocated from a common pool, and no reservations are used for the node group. 3. On the **Compute resources** step: * Select whether the node group should have GPUs. * Select a regular or preemptible VM type. VMs without GPUs only support the regular type. For information about preemptible node groups, see [Creating and modifying Managed Service for Kubernetes® node groups — Preemptible node groups](https://docs.nebius.com/kubernetes/node-groups/manage.md#preemptible-node-groups). * If you create the node group with reservations, specify a **Reservation ID**. * Select an available [platform and preset](https://docs.nebius.com/compute/virtual-machines/types.md) (a combination of GPUs, vCPUs and RAM) that fits your workload requirements. * (Optional) If you create a node group with 8 GPUs (for example, for training models), use a GPU cluster for the node group. InfiniBand™ in the cluster allows you to accelerate tasks that require high-performance computing (HPC) power. To use a GPU cluster, select an existing one or click  **Create** in the **GPU cluster** field and specify the cluster name and InfiniBand fabric. To select the fabric, see [InfiniBand fabrics](https://docs.nebius.com/compute/clusters/gpu#infiniband-fabrics). * (Optional) Enable or disable **GPU settings**. They are enabled by default, and they allow Managed Kubernetes to pre-install NVIDIA drivers and the [Container Toolkit](https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/latest/index.html). You can also select a specific NVIDIA CUDA driver version. * Select an operating system for the nodes (for example, `Ubuntu 24.04 LTS`). 4. On the **Storage** step, select the disk type and specify the size in GiB. Supported [disk types](https://docs.nebius.com/compute/storage/types.md#disk-types) are **SSD**, **SSD NRD** and **SSD IO**. (Optional) To attach a shared filesystem, click  **Attach shared filesystem**, select an existing filesystem or create a new one, and specify a mount tag. 5. On the **Additional** step: * (Optional) In the **Username and SSH key** field, add credentials, so you can [connect to the node group](https://docs.nebius.com/compute/virtual-machines/connect.md): 1. Generate an [SSH key pair](https://docs.nebius.com/compute/virtual-machines/ssh-keys.md). 2. In the **Username and SSH key** field, select an existing key or click  **Create** to add a new one. * (Optional) Select or create a [service account](https://docs.nebius.com/iam/overview.md) that will perform actions on behalf of the nodes. 3. To add another node group with a different configuration, click **Add node group**. 4. To remove a node group, click **Delete** next to its name. 5. Click **Next**. 5. (Optional) On the **Applications** step, select applications to deploy to the cluster. Each application requires at least one node group. For more information, see [Deploying and deleting applications for Managed Service for Kubernetes®](https://docs.nebius.com/kubernetes/manage-applications.md). 1. Click **Next**. 6. On the **Review** step, check the cluster configuration and click **Create cluster**. 1. [Install and configure](https://docs.nebius.com/cli/install.md) the Nebius AI Cloud CLI. 2. Create a cluster: ```bash nebius mk8s cluster create \ --name \ --labels \ --control-plane-endpoints-public-endpoint= \ --control-plane-endpoints-public-endpoint-allowed-cidrs \ --control-plane-version 1.34 \ --control-plane-subnet-id \ --control-plane-etcd-cluster-size ``` The command contains the following parameters: * `--name`: The cluster name. * `--labels`: Labels in the `key=value` format. - `--control-plane-endpoints-public-endpoint`: Enables a public endpoint. As a result, the cluster is available from the internet, one can connect to it from any machine. If you want to disable access to the cluster from the internet, set the parameter to `false`. Then, one can connect to the cluster only from a virtual machine located in the same subnet with the cluster. - `--control-plane-endpoints-public-endpoint-allowed-cidrs` (optional): Allowed CIDR blocks for the public endpoint. Only the IP addresses of these CIDR blocks are allowed to connect to the cluster. Specify the CIDR blocks in the IPv4 format with bits for hosts equal to zero. For example, `192.168.0.0/24` or `8.8.8.64/26`. Pass over each CIDR block as a separate `--control-plane-endpoints-public-endpoint-allowed-cidrs` parameter. For more information, see [Access restriction for a public endpoint of a Managed Service for Kubernetes® cluster](https://docs.nebius.com/kubernetes/networking/limit-access-to-public-endpoint.md). * `--control-plane-version`: The Kubernetes version. The default and recommended version is 1.34. For supported versions, see [Kubernetes® versions in Managed Service for Kubernetes](https://docs.nebius.com/kubernetes/versions.md). * `--control-plane-subnet-id`: The [subnet ID](https://docs.nebius.com/vpc/networking/resources.md#how-to-get-a-subnet-id). * `--control-plane-etcd-cluster-size`: Number or [etcd stores](https://docs.nebius.com/kubernetes/components.md#etcd). If you do not specify the number, the cluster is created with three etcd stores. This ensures high availability and makes the cluster more reliable; data stored in etcd is accessible even in case of failures. You can specify a lower number. However, the enabled high availability does not affect the cost of the cluster. 1. [Install and configure](https://docs.nebius.com/terraform-provider/install.md) the Nebius AI Cloud provider for Terraform. 2. Create the following configuration file: ```hcl resource "nebius_mk8s_v1_cluster" "" { name = "" parent_id = "" labels = { = "" = "" ... = "" } control_plane = { endpoints = { public_endpoint = {} } version = "1.34" subnet_id = "" etcd_cluster_size = } } ``` The file contains the following parameters: * `name`: The cluster name. * `parent_id`: [Project ID](https://docs.nebius.com/iam/manage-projects.md#terraform-3). * `labels`: Labels in the `key=value` format. * `control_plane`: Settings of the cluster's [control plane](https://docs.nebius.com/kubernetes/components.md#control-plane-components): * `endpoints.public_endpoint`: Its value `{}` enables a public endpoint. As a result, the cluster is available from the internet, you can connect to it from any machine. If you want to limit access to the cluster, delete the parameter. Then, one can connect to the cluster only from a virtual machine located in the same subnet with the cluster. * `version`: The Kubernetes version. The default and recommended version is 1.34. For supported versions, see [Kubernetes® versions in Managed Service for Kubernetes](https://docs.nebius.com/kubernetes/versions.md). * `subnet-id`: The [subnet ID](https://docs.nebius.com/vpc/networking/resources.md#how-to-get-a-subnet-id). * `etcd_cluster_size`: Number or [etcd stores](https://docs.nebius.com/kubernetes/components.md#etcd). If you do not specify the number, the cluster is created with three etcd stores. This ensures high availability and makes the cluster more reliable; data stored in etcd is accessible even in case of failures. You can specify a lower number. However, the enabled high availability does not affect the cost of the cluster. 3. Check that the configuration is correct: ```bash terraform validate ``` 4. Apply the changes: ```bash terraform apply ``` ## How to modify clusters 1. Get the ID of the cluster via its name: ```bash export K8S_CLUSTER_ID=$(nebius mk8s cluster get-by-name \ --name --format json | jq -r '.metadata.id') ``` Alternatively, you can use the listing command: nebius mk8s cluster list. 2. Update the cluster settings: ```bash nebius mk8s cluster update \ --id $K8S_CLUSTER_ID \ --labels \ --control-plane-endpoints-public-endpoint= \ --control-plane-endpoints-public-endpoint-allowed-cidrs \ --control-plane-etcd-cluster-size ``` The command contains the following parameters: * `--labels`: Labels in the `key=value` format. - `--control-plane-endpoints-public-endpoint`: Enables a public endpoint. As a result, the cluster is available from the internet, one can connect to it from any machine. If you want to disable access to the cluster from the internet, set the parameter to `false`. Then, one can connect to the cluster only from a virtual machine located in the same subnet with the cluster. - `--control-plane-endpoints-public-endpoint-allowed-cidrs` (optional): Allowed CIDR blocks for the public endpoint. Only the IP addresses of these CIDR blocks are allowed to connect to the cluster. Specify the CIDR blocks in the IPv4 format with bits for hosts equal to zero. For example, `192.168.0.0/24` or `8.8.8.64/26`. Pass over each CIDR block as a separate `--control-plane-endpoints-public-endpoint-allowed-cidrs` parameter. For more information, see [Access restriction for a public endpoint of a Managed Service for Kubernetes® cluster](https://docs.nebius.com/kubernetes/networking/limit-access-to-public-endpoint.md). * `--control-plane-etcd-cluster-size`: Number or [etcd stores](https://docs.nebius.com/kubernetes/components.md#etcd). Three of them ensure high availability of the cluster. Only the parameters from the command above can be changed. To perform a full cluster update, add `--full` to the command. This will update all parameters with the default values or the values specified in the `--full` command. 1. Modify the manifest with the deployed infrastructure: ```hcl resource "nebius_mk8s_v1_cluster" "" { name = "" labels = { = "" = "" ... = "" } control_plane = { endpoints = { public_endpoint = {} } etcd_cluster_size = } } ``` You can change the following parameters: * `name`: The cluster name. * `labels`: Labels in the `key=value` format. * `control_plane`: Settings of the cluster's [control plane](https://docs.nebius.com/kubernetes/components.md#control-plane-components): * `endpoints.public_endpoint`: Its value `{}` enables a public endpoint. As a result, the cluster is available from the internet, you can connect to it from any machine. If you want to limit access to the cluster, delete the parameter. Then, one can connect to the cluster only from a virtual machine located in the same subnet with the cluster. * `etcd_cluster_size`: Number or [etcd stores](https://docs.nebius.com/kubernetes/components.md#etcd). If you do not specify the number, the cluster is created with three etcd stores. This ensures high availability and makes the cluster more reliable; data stored in etcd is accessible even in case of failures. You can specify a lower number. However, the enabled high availability does not affect the cost of the cluster. 2. Check that the configuration is correct: ```bash terraform validate ``` 3. Apply the changes: ```bash terraform apply ``` ## How to delete clusters To delete a cluster, get its ID as shown in [How to modify clusters](https://docs.nebius.com/kubernetes/clusters/manage.md#how-to-modify-clusters) and run the following command: ```bash nebius mk8s cluster delete --id $K8S_CLUSTER_ID ``` ## Examples Creating a cluster with the Kubernetes version 1.34 and a public endpoint for the control plane: ```bash nebius mk8s cluster create \ --name cluster-example \ --control-plane-version 1.34 \ --control-plane-subnet-id \ $(nebius vpc subnet list --format json \ | jq -r '.items[0].metadata.id') \ --control-plane-endpoints-public-endpoint=true ``` # Creating and modifying Managed Service for Kubernetes® node groups Source: https://docs.nebius.com/kubernetes/node-groups/manage.md Clusters in Managed Service for Kubernetes use Compute virtual machines as nodes to run applications. In this guide, you will learn how to create node groups, add them to clusters, modify and delete them. In the web console, you can create node groups together with a new cluster during [cluster creation](https://docs.nebius.com/kubernetes/clusters/manage.md#how-to-create-clusters). To learn how to manage clusters outside of their node groups, see [How to create and modify Managed Service for Kubernetes® clusters](https://docs.nebius.com/kubernetes/clusters/manage.md). ## Prerequisites You do not need to complete any prerequisites if you create or modify node groups in the web console. 1. [Install and configure](https://docs.nebius.com/cli/install.md) the Nebius AI Cloud CLI. 2. [Create a cluster](https://docs.nebius.com/kubernetes/clusters/manage.md#how-to-create-clusters) and save its ID to an environment variable: ```bash export K8S_CLUSTER_ID=$(nebius mk8s cluster get-by-name \ --name --format json | jq -r '.metadata.id') ``` 1. [Install and configure](https://docs.nebius.com/terraform-provider/install.md) the Nebius AI Cloud provider for Terraform. 2. [Create a cluster](https://docs.nebius.com/kubernetes/clusters/manage.md#how-to-create-clusters). ## How to create node groups Node groups define the characteristics of the virtual machines (VMs) that run your workloads. Each node group includes identical nodes created with the same template. You can create different types of node groups depending on your performance, cost and availability requirements. For example, you can choose high-performance GPUs for compute-intensive workloads or preemptible VMs to reduce costs for interruptible tasks. ### Regular node groups 1. In the sidebar, go to  **Compute** → **Kubernetes**. 2. Open the page of the cluster where you want to create a node group. 3. Switch to the **Node groups** tab. 4. Click  **Create node group**. 5. On the page that opens, specify a name for the node group (for example, `mk8s-node-group-test`). 6. (Optional) Enable the **Assign public IPv4 addresses** option if you want the nodes to be accessible from the internet. 7. Under **Size**, specify the initial **Number of nodes**. If you want to let the node group scale up or down depending on the workload, enable autoscaling. After that, specify the minimum and maximum number of nodes that the group can have. 8. Configure the **Computing resources** section: 1. Select whether the node group should have GPUs. 2. Select a regular VM type. VMs without GPUs only support the regular type. For information about creating preemptible node groups, see [instructions below](https://docs.nebius.com/kubernetes/node-groups/manage.md#preemptible-node-groups). 3. (Optional) For a regular VM with GPUs, select **Reservation usage**. Specify whether Managed Kubernetes should allocate resources for the node group from [reservations](https://docs.nebius.com/kubernetes/node-groups/reservations.md). The **Reservation usage** field is only displayed if you have [capacity block groups](https://docs.nebius.com/overview/limits/capacity-block-groups.md). * **With reservations**: The resources are allocated from reservations ([capacity block groups](https://docs.nebius.com/overview/limits/capacity-block-groups.md)). For example, if a Nebius manager has created a capacity block group for you, Managed Kubernetes allocates GPUs for the node group from this capacity block group. This ensures that resources are always available, even if VMs in the node group are stopped (for example, by you or a [maintenance event](https://docs.nebius.com/kubernetes/maintenance/index.md)). In the **Reservation** section, you can configure the following options: * **Any (existing and future)** (default): Compute selects among your matching capacity block groups automatically. * **Specific capacity block groups**: Select one or more capacity block groups. Each option shows the capacity block group ID, reservation period and GPU usage. Make sure the selected groups have enough capacity and do not expire soon. * **Switch to PAYG**: Choose whether the VM can start after you create or restart it without active intervals in selected capacity block groups: * **When reservation is exhausted** (default): The VM can start as a pay-as-you-go VM when no capacity is available in the selected capacity block groups. * **Never**: The VM cannot start without available capacity in the selected capacity block groups. This does not affect the VM when it is running. If an interval in a selected capacity block group expires while the VM is running, the VM always continues as a pay-as-you-go VM, regardless of this setting. If you have capacity block groups in multiple regions, select a **Region** first. * **Without reservations**: The resources are allocated from a common pool, and no reservations are used for the node group. 4. Select an available [platform and a preset](https://docs.nebius.com/compute/virtual-machines/types.md) (a combination of GPUs, vCPUs and RAM) that fits your workload requirements. 5. (Optional) If you create a node group with 8 GPUs (for example, for training models), use a GPU cluster for the node group. InfiniBand™ in the cluster allows you to accelerate tasks that require high-performance computing (HPC) power. A single node group without InfiniBand cannot perform these tasks as quickly. To use a GPU cluster, select an existing one or create a new cluster: 1. Click  **Create** in the **GPU cluster** field. 2. In the window that opens, specify the cluster name and InfiniBand fabric. To select the fabric, see [InfiniBand fabrics](https://docs.nebius.com/compute/clusters/gpu/index.md#infiniband-fabrics). 3. Click **Create**. 6. (Optional) Enable or disable **GPU settings**. They are enabled by default, and they allow Managed Kubernetes to pre-install NVIDIA drivers and the [Container Toolkit](https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/latest/index.html). You can also select a specific NVIDIA CUDA driver version. Disable **GPU settings** only if you need to [install specific driver versions manually](https://docs.nebius.com/kubernetes/gpu/set-up.md#how-to-install-the-drivers-and-components-on-existing-node-groups) or use a custom operator. Disabling is not recommended. 7. Select an operating system for the nodes (for example, `Ubuntu 24.04 LTS`). 9. Under **Node storage**, select the disk type and specify the size in Nebius uses binary units. For example, a gibibyte (GiB) is 230 (10243) bytes.}>GiB. Supported [disk types](https://docs.nebius.com/compute/storage/types.md#network-ssd-disks) are the following: * **SSD**: Standard solid-state drive for general-purpose workloads. * **SSD NRD**: Network-replicated SSD providing higher reliability through data duplication across the network. * **SSD IO**: High-performance SSD optimized for I/O-intensive operations with lower latency. 10. (Optional) If the selected platform and preset support local SSD disks, enable **Local SSD disks** to add ephemeral local storage to your node group. Local SSD disks are available only for supported platforms and presets. For details, see [Availability](https://docs.nebius.com/compute/storage/local-disks.md#availability). 11. (Optional) If you want to attach a filesystem to your node group, in the **Shared filesystems** section, specify the settings of this filesystem: 1. Click  **Attach shared filesystem**. 2. In the window that opens, select an existing filesystem or create a new one. 3. If you create a new filesystem, specify its name, size and the block size. 4. Click **Attach filesystem** or **Create and attach filesystem**. 5. After the window is closed, specify a mount tag for mounting the filesystem to the VM. Create your own tag, such as `my-filesystem`. Make sure that it is unique within the VM. 6. To mount the filesystem to the node group automatically, keep the **Auto mount** option enabled. 12. (Optional) In the **Username and SSH key** field, add credentials, so you can [connect to the node group](https://docs.nebius.com/compute/virtual-machines/connect.md): 1. Generate an [SSH key pair](https://docs.nebius.com/compute/virtual-machines/ssh-keys.md). 2. In the **Username and SSH key** field, click . 3. If you added an SSH key earlier and you want to reuse it, select the key from the drop-down list. If you want to add a new key, click  **Add credentials**. 4. In the window that opens, specify the username of the node group user, a public key of your SSH key pair and the credentials name to recognize the key in the list. 5. Click **Add credentials**. 13. (Optional) Under **Additional**, select or create a [service account](https://docs.nebius.com/iam/overview.md) that will perform actions on behalf of the nodes. 14. Click **Create node group**. Create a node group: ```bash nebius mk8s node-group create \ --parent-id $K8S_CLUSTER_ID \ --name \ --fixed-node-count \ --template-resources-platform \ --template-resources-preset \ --template-gpu-settings-drivers-preset ``` For descriptions of node group parameters, see [Node group parameters](https://docs.nebius.com/kubernetes/node-groups/manage.md#node-group-parameters). If you need to modify the NVIDIA device plug-in (for example, to enable multi-instance GPU), don't add the `--template-gpu-settings-drivers-preset` parameter to the command. Instead, [manually install the GPU operator](https://docs.nebius.com/kubernetes/gpu/set-up.md#how-to-install-the-drivers-and-components-on-existing-node-groups). For more details about GPUs in node groups, see [Working with GPUs in the Managed Service for Kubernetes®](https://docs.nebius.com/kubernetes/gpu/set-up.md) and [Interconnecting GPUs in Managed Service for Kubernetes® clusters using InfiniBand™](https://docs.nebius.com/kubernetes/gpu/clusters.md). 1. Create a node group configuration file: ```hcl resource "nebius_mk8s_v1_node_group" "" { name = "" parent_id = "" fixed_node_count = template = { resources = { platform = "" preset = "" } gpu_settings = { drivers_preset = "" } } } ``` For descriptions of node group parameters, see [Node group parameters](https://docs.nebius.com/kubernetes/node-groups/manage.md#node-group-parameters). 2. Check that the configuration is correct: ```bash terraform validate ``` 3. Apply the changes: ```bash terraform apply ``` ### Preemptible node groups Preemptible nodes use virtual machines that can be stopped by Nebius AI Cloud at any time. These VMs are more cost-efficient than regular ones and suitable for workloads with interruptions, such as batch processing or training ML models. For more information about how preemptible VMs work, see [Preemptible virtual machines](https://docs.nebius.com/compute/virtual-machines/preemptible.md). 1. In the sidebar, go to  **Compute** → **Kubernetes**. 2. [Create a cluster](https://docs.nebius.com/kubernetes/clusters/manage.md#how-to-create-clusters) or choose an existing one. 3. On the cluster page, switch to the **Node groups** tab. 4. Click  **Create node group**. 5. When creating a node group, under **Computing resources**, select: * **With GPU** * **Preemptible** VM type For information about other node group parameters, see [instructions about creating regular node groups](https://docs.nebius.com/kubernetes/node-groups/manage.md#regular-node-groups). Run the Nebius AI Cloud CLI command [nebius mk8s node-group create](https://docs.nebius.com/cli/reference/mk8s/node-group/create) with the `--template-preemptible` parameter: ```bash nebius mk8s node-group create \ ... \ --template-preemptible ``` Create a node group configuration file and set the `.template.preemptible` block to enable preemptibility: ```hcl resource "nebius_mk8s_v1_node_group" "example" { name = "preemptible-ng" ... template = { preemptible = {} ... } } ``` ## How to modify node groups Modifying the node group template triggers a [rolling update](https://docs.nebius.com/kubernetes/node-groups/manage.md#deployment-strategy-and-quotas). Managed Kubernetes replaces each node with another one, with a new configuration. To check the list of the template parameters, see all `--template-*` parameters in [CLI reference](https://docs.nebius.com/cli/reference/mk8s/node-group/create) or the nested schema for `template` in [Terraform reference](https://docs.nebius.com/terraform-provider/reference/resources/mk8s_v1_node_group#nested-schema-for-template). If you modify other parameters, Managed Kubernetes does not replace the nodes, they remain unchanged. During a node group update, Managed Kubernetes uses the default values of the deployment strategy [parameters](https://docs.nebius.com/kubernetes/node-groups/manage.md#node-group-parameters). By default, one node at a time can be unavailable during the update, and no additional compute quota is required. You can change the deployment strategy when you modify a node group. To modify a node group: 1. In the sidebar, go to  **Compute** → **Kubernetes**. 2. Open the page of the required cluster and then go to the **Node groups** tab. 3. Open the page of the node group that you wish to change. 4. Switch to the **Settings** tab and then modify the required parameters. Parameters available for editing: * **Name**: Name of the node group. * **Size**: * **Number of nodes**: Target and fixed number of nodes (if autoscaling is disabled). The maximum number is 100. * **Enable autoscaling**: Allows you to set the range of nodes within which the [cluster autoscaler](https://docs.nebius.com/kubernetes/node-groups/autoscaling.md) adds or removes nodes as needed. * **Computing resources**: Select whether the node group should have GPUs, and then specify the hardware configuration: * **VM type**: * **Regular**: Standard VMs for high-availability production workloads. * **Preemptible**: Lower-cost VMs that may be terminated by the platform at any time. * **Available platform** and **Preset**: Combination of GPUs, vCPUs and RAM that fits your workload requirements. For more information, see [Types of virtual machines and GPUs in Nebius AI Cloud](https://docs.nebius.com/compute/virtual-machines/types.md). * **GPU cluster**: GPU cluster with InfiniBand. Allows you to accelerate tasks that require HPC power. Available only if the node group contains 8 GPUs. * **GPU settings**: If enabled, the system pre-installs NVIDIA drivers and the [Container Toolkit](https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/latest/index.html). You can also select a specific NVIDIA CUDA driver version. Disable **GPU settings** only if you need to [install specific driver versions manually](https://docs.nebius.com/kubernetes/gpu/set-up.md#how-to-install-the-drivers-and-components-on-existing-node-groups) or use a custom operator. * **Drivers**: CUDA driver version based on enabled **GPU settings**. * **Operating system**: OS for the nodes, for example, `Ubuntu 24.04 LTS`. * **Node storage**: * **Disk type**: [Type of the boot disk](https://docs.nebius.com/compute/storage/types.md#network-ssd-disks). * **Size**: Size of the boot disk in GiB. 5. Click **Save changes**. The status of the node group changes to **Updating** while the new configuration is being applied. 1. Get the node group ID and save it to an environment variable: ```bash export K8S_NODE_GROUP_ID=$(nebius mk8s node-group get-by-name \ --parent-id $K8S_CLUSTER_ID \ --name --format json | jq -r '.metadata.id') ``` 2. Update the node group: ```bash nebius mk8s node-group update \ --id $K8S_NODE_GROUP_ID \ (parameters) ``` Only the parameters specified in the CLI command can be changed. You can do a full update instead by adding `--full` to the command. This will update all parameters with the values specified in the command or the default values. For more information, see [Specifying parameters](https://docs.nebius.com/kubernetes/node-groups/manage.md#specifying-parameters). 1. In the node group configuration file, update the [parameters](https://docs.nebius.com/kubernetes/node-groups/manage.md#node-group-parameters) of the `nebius_mk8s_v1_node_group` resource. 2. Check that the configuration is correct: ```bash terraform validate ``` 3. Apply the changes: ```bash terraform apply ``` ## Deployment strategy and quotas Managed Kubernetes performs a *rolling update* to each node in the group when you modify the node group template. To check the list of the template parameters, see all `--template-*` parameters in [CLI reference](https://docs.nebius.com/cli/reference/mk8s/node-group/create) or the nested schema for `template` in [Terraform reference](https://docs.nebius.com/terraform-provider/reference/resources/mk8s_v1_node_group#nested-schema-for-template). With the default values of the deployment strategy [parameters](https://docs.nebius.com/kubernetes/node-groups/manage.md#node-group-parameters), Managed Kubernetes updates one node at a time in the following order: 1. Cordons the existing node (marks it as unschedulable). 2. Drains the existing node (evicts all Pods from it). 3. Deletes the existing node. 4. Creates a replacement node. This default behavior does not require additional compute quota during an update. Managed Kubernetes uses the node group's *deployment strategy* to determine how, in what order and to how many nodes at a time it performs the listed steps. You can configure the deployment strategy using the corresponding [parameters](https://docs.nebius.com/kubernetes/node-groups/manage.md#node-group-parameters). If you prefer Managed Kubernetes to create replacement nodes before removing the existing ones, for example to minimize workload disruption, configure a deployment strategy that allows the node group to temporarily exceed its target size during an update. In this case, make sure that your [quotas on underlying Compute resources](https://docs.nebius.com/compute/resources/quotas-limits.md) allow for the additional nodes that can be created during a rolling update. If there is no quota available for any of the required resources, the update fails. You can check your remaining quotas on the [Administration → Limits → Quotas](https://console.nebius.com/quota) page of the web console. > For example, each node uses 8 GPUs, 128 vCPUs, 1600 GiB RAM and a public IP address. If your deployment strategy allows up to two additional nodes during the update, you need quotas for the following additional resources: > > * 16 GPUs (2 × 8) > * 256 vCPUs (2 × 128) > * 3200 GiB RAM (2 × 1600) > * 2 public IP addresses When you or the [autoscaler](https://docs.nebius.com/kubernetes/node-groups/autoscaling.md) scales a node group up or down, Managed Kubernetes does not recreate any nodes. ## Node group parameters The `nebius mk8s node-group create` and `nebius mk8s node-group update` commands support the following parameters. * **Metadata** * `--name`: Node group name. Must be unique within the tenant. Cannot be changed after creation. * **Kubernetes version on nodes** * `--version`: Kubernetes version in `.` format. Recommended version is 1.34. For more information, see [Kubernetes versions in Managed Service for Kubernetes](https://docs.nebius.com/kubernetes/versions.md). * **Node group size** * `--fixed-node-count`: Number of nodes per group. The maximum is 100. * `--autoscaling-min-node-count`, `--autoscaling-max-node-count`: Allow you to set the range of nodes within which the [cluster autoscaler](https://docs.nebius.com/kubernetes/node-groups/autoscaling.md) adds or removes nodes as needed. * **Node template** All nodes in a group are identical and are created based on a *node template*. A node template is similar to a virtual machine specification in Compute. The node template has the following parameters: * `--template-taints`: Array of Kubernetes [taints](https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/) (rules that repel Pods from nodes) for all nodes in the group. * `--template-resources-platform`: A platform with GPUs, see [Interconnecting GPUs in Managed Service for Kubernetes® clusters using InfiniBand™](https://docs.nebius.com/kubernetes/gpu/clusters.md). * `--template-resources-preset`: A compatible preset (number of GPUs and vCPUs, RAM size), see [Types of virtual machines and GPUs in Nebius AI Cloud](https://docs.nebius.com/compute/virtual-machines/types.md). * `--template-gpu-settings-drivers-preset`: GPU drivers preset, see [GPU drivers and other components](https://docs.nebius.com/kubernetes/gpu/set-up.md#gpu-drivers-and-other-components). * `--template-gpu-cluster-id`: GPU cluster ID. * `--template-service-account-id`: Service account ID. You can add a service account, for example, to [pull images from Container Registry](https://docs.nebius.com/kubernetes/workloads/images-container-registry.md). * `--template-network-interfaces`: Network interface configuration (for example, subnet ID, see [How to use a non-default subnet for Managed Service for Kubernetes® clusters and node groups](https://docs.nebius.com/kubernetes/networking/non-default-subnet.md)). * `--template-filesystems`: Filesystem for nodes, see [How to attach volumes to VMs](https://docs.nebius.com/compute/storage/use.md#how-to-attach-volumes-to-vms). The filesystem that you are adding to a node group must be located in the same project as the node group's parent cluster. For more details about projects and resource hierarchy in Nebius AI Cloud, see [How resources, identities and access are managed in Nebius AI Cloud](https://docs.nebius.com/iam/overview.md). * `--template-local-disks-passthrough-group-requested` (optional): Requests [local SSD disks](https://docs.nebius.com/compute/storage/types.md#local-ssd-disks) when set to `true`. You can configure how the local SSD disks are added to your node group with one of the following parameters: * `--template-local-disks-config-kubelet-ephemeral`: Set to `true` to use the requested local SSD disks as the node's [local ephemeral storage](https://kubernetes.io/docs/concepts/storage/ephemeral-storage/). Managed Kubernetes prepares, formats and mounts the resulting storage for node ephemeral data. This is the default configuration mode. * `--template-local-disks-config-none`: Set to `true` to provision the requested local SSD disks with no preparation. Local SSD disks are available only for supported platforms and presets. For details, see [Availability](https://docs.nebius.com/compute/storage/local-disks.md#availability). * `--template-reservation-policy-policy`: Policy for reservation usage. You can use [reservations of capacity resources](https://docs.nebius.com/kubernetes/node-groups/reservations.md) and run your node group based on them. As a result, the node group resources are reserved and always available. * `--template-reservation-policy-reservation-ids`: IDs of specific reservations. These are capacity block groups that a Nebius manager has created. For information about how to configure `--template-reservation-policy-policy` and `--template-reservation-policy-reservation-ids`, see [How to add reservations to node groups](https://docs.nebius.com/kubernetes/node-groups/reservations.md#how-to-add-reservations-to-node-groups). * **Deployment strategy** The *deployment strategy* of a node group defines how it is updated when necessary — for example, when you modify the group's node template or Kubernetes version, or when nodes fail and need to be replaced. For more details, see [Deployment strategy and quotas](https://docs.nebius.com/kubernetes/node-groups/manage.md#deployment-strategy-and-quotas). The following parameters specify the deployment strategy: * `--strategy-max-unavailable-percent`, `--strategy-max-unavailable-count`: The maximum number of nodes in a group that can be unavailable at any time during an update, set as a percentage of the group's target size or a number of nodes. When a percentage is used, the number of nodes is calculated by rounding down. > For example, if the value of `--strategy-max-unavailable-percent` is 40 and the group's target size is 3, at most ⌊3 × 40%⌋ = ⌊1.2⌋ = 1 node can be unavailable at any time during the update. The default value is `--strategy-max-unavailable-count 1`. Cannot be set to 0 if `--strategy-max-surge-count` or `--strategy-max-surge-percent` is 0. * `--strategy-max-surge-percent`, `--strategy-max-surge-count`: The maximum number of nodes in a group that can exceed the group's target size at any time during an update, set as a percentage of the target size or as a number of nodes. > For example, if the value of `--strategy-max-surge-count` is 2 and the group's target size is 3, then the group can only have 3 + 2 = 5 nodes at any time during the update. The default value is `--strategy-max-surge-count 0`. Cannot be set to 0 if `--strategy-max-unavailable-count` or `--strategy-max-unavailable-percent` is 0. * `--strategy-drain-timeout`: The maximum amount of time it can take to drain a node during the update. If the timeout is set, a node in the updated group is deleted when it reaches the timeout, even if its draining is not complete. The timeout is not set by default and nodes are deleted only after the draining is complete. The `nebius_mk8s_v1_node_group` resource supports the following parameters: * **Metadata** * `parent_id`: Cluster ID. * `name`: Node group name. Must be unique within the tenant. Cannot be changed after creation. * **Kubernetes version on nodes** * `version`: Kubernetes version in `.` format. Recommended version is 1.34. For more information, see [Kubernetes versions in Managed Service for Kubernetes](https://docs.nebius.com/kubernetes/versions.md). * **Node group size** * `fixed_node_count`: Number of nodes per group. The maximum is 100. Cannot be set together with `autoscaling`. * `autoscaling.min_node_count`, `autoscaling.max_node_count`: Allow you to set the range of nodes within which the [cluster autoscaler](https://docs.nebius.com/kubernetes/node-groups/autoscaling.md) adds or removes nodes as needed. Cannot be set together with `fixed_node_count`. * **Node template** All nodes in a group are identical and are created based on a *node template*. A node template is similar to a virtual machine specification in Compute. The node template is configured in the `template` block and supports the following parameters: * `template.taints`: Array of Kubernetes [taints](https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/) (rules that repel Pods from nodes) for all nodes in the group. * `template.resources.platform`: A platform with GPUs, see [Interconnecting GPUs in Managed Service for Kubernetes® clusters using InfiniBand™](https://docs.nebius.com/kubernetes/gpu/clusters.md). * `template.resources.preset`: A compatible preset (number of GPUs and vCPUs, RAM size), see [Types of virtual machines and GPUs in Nebius AI Cloud](https://docs.nebius.com/compute/virtual-machines/types.md). * `template.gpu_settings.drivers_preset`: GPU drivers preset. For more information, see [GPU drivers and other components](https://docs.nebius.com/kubernetes/gpu/set-up.md#gpu-drivers-and-other-components). * `template.gpu_cluster.id`: GPU cluster ID. * `template.service_account_id`: Service account ID. You can add a service account, for example, to [pull images from Container Registry](https://docs.nebius.com/kubernetes/workloads/images-container-registry.md). * `template.network_interfaces`: Network interface configuration (for example, subnet ID, see [How to use a non-default subnet for Managed Service for Kubernetes® clusters and node groups](https://docs.nebius.com/kubernetes/networking/non-default-subnet.md)). * `template.filesystems`: Filesystem for nodes, see [How to attach volumes to VMs](https://docs.nebius.com/compute/storage/use.md#how-to-attach-volumes-to-vms). The filesystem that you are adding to a node group must be located in the same project as the node group's parent cluster. For more details about projects and resource hierarchy in Nebius AI Cloud, see [How resources, identities and access are managed in Nebius AI Cloud](https://docs.nebius.com/iam/overview.md). * `template.local_disks.passthrough_group.requested`: Requests [local SSD disks](https://docs.nebius.com/compute/storage/types.md#local-ssd-disks) when set to `true`. You can configure how the local SSD disks are added to your node group with one of the following parameters: * `template.local_disks.config.kubelet_ephemeral`: Set to `true` to use the requested local SSD disks as the node's [local ephemeral storage](https://kubernetes.io/docs/concepts/storage/ephemeral-storage/). Managed Kubernetes prepares, formats and mounts the resulting storage for node ephemeral data. This is the default configuration mode. * `template.local_disks.config.none`: Set to `true` to provision the requested local SSD disks with no configuration. Local SSD disks are available only for supported platforms and presets. For details, see [Availability](https://docs.nebius.com/compute/storage/local-disks.md#availability). * `template.reservation_policy.policy`: Policy for reservation usage. You can use [reservations of capacity resources](https://docs.nebius.com/kubernetes/node-groups/reservations.md) and run your node group based on them. As a result, the node group resources are reserved and always available. * `template.reservation_policy.reservation_ids`: IDs of specific reservations. These are capacity block groups that a Nebius manager has created. For information about how to configure `template.reservation_policy.policy` and `template.reservation_policy.reservation_ids`, see [How to add reservations to node groups](https://docs.nebius.com/kubernetes/node-groups/reservations.md#how-to-add-reservations-to-node-groups). * **Deployment strategy** The *deployment strategy* of a node group defines how it is updated when necessary — for example, when you modify the group's node template or Kubernetes version, or when nodes fail and need to be replaced. For more details, see [Deployment strategy and quotas](https://docs.nebius.com/kubernetes/node-groups/manage.md#deployment-strategy-and-quotas). The deployment strategy is configured in the `strategy` block: * `strategy.max_unavailable.percent`, `strategy.max_unavailable.count`: The maximum number of nodes in a group that can be unavailable at any time during an update, set as a percentage of the group's target size or a number of nodes. When a percentage is used, the number of nodes is calculated by rounding down. > For example, if `strategy.max_unavailable.percent = 40` and the group's target size is 3, at most ⌊3 × 40%⌋ = ⌊1.2⌋ = 1 node can be unavailable at any time during the update. The default value is 1. Cannot be set to 0 if `strategy.max_surge.count` or `strategy.max_surge.percent` is set to 0. * `strategy.max_surge.percent`, `strategy.max_surge.count`: The maximum number of nodes in a group that can exceed the group's target size at any time during an update, set as a percentage of the target size or as a number of nodes. > For example, if `strategy.max_surge.count = 2` and the group's target size is 3, then the group can have up to 3 + 2 = 5 nodes at any time during the update. The default value is `strategy.max_surge.count = 0`. Cannot be set to 0 if `strategy.max_unavailable.count` or `strategy.max_unavailable.percent` is set to 0. * `strategy.drain_timeout`: The maximum amount of time it can take to drain a node during the update. If the timeout is set, a node in the updated group is deleted when it reaches the timeout, even if its draining is not complete. The timeout is not set by default and nodes are deleted only after the draining is complete. ## How to delete node groups 1. In the sidebar, go to  **Compute** → **Kubernetes**. 2. Open the cluster page and then go to the **Node groups** tab. 3. Open the page of the node group that you want to remove. 4. Switch to the **Settings** tab. 5. Click **Delete node group**. 6. Confirm the deletion. To delete a node group, get its ID as shown in [How to modify node groups](https://docs.nebius.com/kubernetes/node-groups/manage.md#how-to-modify-node-groups) and run the following command: ```bash nebius mk8s node-group delete --id $K8S_NODE_GROUP_ID ``` 1. Remove the corresponding `nebius_mk8s_v1_node_group` resource from the node group configuration file. 2. Check that the configuration is correct: ```bash terraform validate ``` 3. Apply the changes: ```bash terraform apply ``` ## Examples * Creating a node group with two nodes, each with 8 NVIDIA H100 GPUs, 128 vCPUs, 1600 GiB of RAM, a 100 GiB Network SSD disk and the Kubernetes version 1.34: ```bash export SUBNET_ID=$(nebius vpc subnet list --format json \ | jq -r '.items[0].metadata.id') nebius mk8s node-group create \ --parent-id $K8S_CLUSTER_ID \ --name node-group-example \ --version 1.34 \ --fixed-node-count 2 \ --template-resources-platform gpu-h100-sxm \ --template-resources-preset 8gpu-128vcpu-1600gb \ --template-gpu-settings-drivers-preset cuda13.0 \ --template-boot-disk-type NETWORK_SSD \ --template-boot-disk-size-gibibytes 100 \ --template-network-interfaces "[{\"subnet_id\": \"$SUBNET_ID\"}]" ``` * Modifying the node group from the previous example (ID `$K8S_NODE_GROUP_ID`) to add a node and enable public IP addresses for all nodes: ```bash nebius mk8s node-group update \ --id $K8S_NODE_GROUP_ID \ --fixed-node-count 3 \ --template-network-interfaces "[{\"subnet_id\": \"$SUBNET_ID\", \"public_ip_address\": {}}]" ``` Creating a node group with two nodes, each with 8 NVIDIA H100 GPUs, 128 vCPUs, 1600 GiB of RAM, a 100 GiB Network SSD disk and the Kubernetes version 1.34: ```hcl resource "nebius_mk8s_v1_node_group" "node-group-example" { name = "node-group-example" parent_id = $K8S_CLUSTER_ID version = "1.34" fixed_node_count = 2 template = { resources = { platform = "gpu-h100-sxm" preset = "8gpu-128vcpu-1600gb" } gpu_settings = { drivers_preset = "cuda12.8" } boot_disk = { type = "NETWORK_SSD" size_gibibytes = 100 } } } ``` *** *InfiniBand and InfiniBand Trade Association are registered trademarks of the InfiniBand Trade Association.* # kubeReserved values on worker nodes in Managed Service for Kubernetes® Source: https://docs.nebius.com/kubernetes/node-groups/kube-reserved.md In Managed Service for Kubernetes, the kubelet sets `kubeReserved` values on worker nodes to reserve resources for Kubernetes system components. This article describes the default values and how the `memory` reservation is calculated. ## Default values By default, worker nodes use the following `kubeReserved` values: * `cpu`: `100m` * `ephemeral-storage`: `1Gi` * `memory`: `512Mi` However, for worker nodes with GPUs, Managed Kubernetes calculates the `memory` reservation value from the size of RAM you select for the node. This helps account for a known Kubernetes issue where the kubelet may not observe `MemoryPressure` right away. For more information, see [Node-pressure Eviction](https://kubernetes.io/docs/concepts/scheduling-eviction/node-pressure-eviction/#known-issues) in the official Kubernetes documentation. The calculation uses the following tiered approach: * `255Mi` for nodes with less than 1 GiB of RAM * `25%` of the first 4 GiB * `20%` of the next 4 GiB (up to 8 GiB) * `10%` of the next 8 GiB (up to 16 GiB) * `6%` of the next 112 GiB (up to 128 GiB) * `2%` of RAM above 128 GiB * Plus `100Mi` on every node to handle Pod eviction ## Examples The following table shows the resulting `memory` value in `kubeReserved` for the selected RAM size in your GPU nodes: | Node RAM | `kubeReserved.memory` | | -------- | --------------------- | | 8 GiB | `1944Mi` | | 16 GiB | `2763Mi` | | 128 GiB | `9644Mi` | | 256 GiB | `12266Mi` | ## See also * [Node groups](https://docs.nebius.com/kubernetes/components.md#node-group) * [Creating and modifying node groups](https://docs.nebius.com/kubernetes/node-groups/manage.md) # Capacity reservations for Managed Service for Kubernetes® node groups Source: https://docs.nebius.com/kubernetes/node-groups/reservations.md To make sure that GPU capacity is always available for your nodes (virtual machines, VMs), you can reserve GPUs. A *reservation* represents a [capacity block group](https://docs.nebius.com/overview/limits/capacity-block-groups.md), and it reserves a specific number of GPUs that are allocated to your infrastructure. GPUs from a reservation remain available, even if a VM is stopped. Without reservations, GPU capacity is taken from a shared pool and returned when a VM is stopped (for example, by you or a [maintenance event](https://docs.nebius.com/kubernetes/maintenance/index.md)). To start using reservations, send a request to your Nebius manager. In this request, specify how many GPUs you would like to reserve and for what period. If you are not in contact with a Nebius manager, you can ask [technical support](https://console.nebius.com/support/create-ticket) to connect you with one. After reservations are ready, you can add them to your existing node groups or create new ones with reservations. You can also check your capacity block groups on the **Limits** page and get detailed information about them. For more information, see [List of capacity block groups](https://docs.nebius.com/overview/limits/capacity-block-groups.md#list-of-capacity-block-groups). GPUs allocated from reservations do not count towards [quotas on the number of GPUs](https://docs.nebius.com/compute/resources/quotas-limits.md#gpu-virtual-machines). ## How to add reservations to node groups Node groups of a regular type with GPUs support reservations. [Preemptible node groups](https://docs.nebius.com/kubernetes/node-groups/manage.md#preemptible-node-groups) and node groups without GPUs do not support reservations. If you want to [create a node group](https://docs.nebius.com/kubernetes/node-groups/manage.md#regular-node-groups), in the creation form, under **Computing resources**, select **With GPU** and a regular VM type. After that, specify the **Reservation usage** settings. If you want to modify an existing node group, go to its **Settings** tab on the node group page. Next, update the **Reservation usage** settings. The **Reservation usage** settings are only displayed if you have capacity block groups. Available **Reservation usage** options: * **With reservations**: Resources are allocated from reservations. In the **Reservation** section, you can configure the following options: * **Any (existing and future)** (default): Compute selects among your matching capacity block groups automatically. * **Specific capacity block groups**: Select one or more capacity block groups. Each option shows the capacity block group ID, reservation period and GPU usage. Make sure the selected groups have enough capacity and do not expire soon. * **Switch to PAYG**: Choose whether the VM can start after you create or restart it without active intervals in selected capacity block groups: * **When reservation is exhausted** (default): The VM can start as a pay-as-you-go VM when no capacity is available in the selected capacity block groups. * **Never**: The VM cannot start without available capacity in the selected capacity block groups. This does not affect the VM when it is running. If an interval in a selected capacity block group expires while the VM is running, the VM always continues as a pay-as-you-go VM, regardless of this setting. If you have capacity block groups in multiple regions, select a **Region** first. * **Without reservations**: Resources are allocated from the common pool, and no reservations are used for the node group. To configure reservations, use the `--template-reservation-policy-*` parameters when creating or updating a node group: * Create a node group: ```bash nebius mk8s node-group create \ ... \ --template-reservation-policy-policy \ --template-reservation-policy-reservation-ids ``` * Update a node group: ```bash nebius mk8s node-group update \ ... \ --template-reservation-policy-policy \ --template-reservation-policy-reservation-ids ``` Description of the parameters: * `--template-reservation-policy-policy`: Policy for reservation usage. Supports the following values: * `auto`: Node group resources are allocated from reservations. If no reservations are currently available, the node group runs without them. In this case, resources for the node group are provided from the common pool. The `auto` value is default. If you don't have any reservations and you don't set the `--template-reservation-policy-policy` parameter, the `auto` value applies and the node group runs without reservations. * `forbid`: Node group resources are provided from the common pool, and no reservations are used. * `strict`: Node group resources are exclusively allocated from reservations. The node group doesn't run without the reservations. * `--template-reservation-policy-reservation-ids` (optional): IDs of specific reservations (capacity block groups). Use this parameter only if you need specific reservations. Specify the IDs in the order in which reservations should apply. For instance, resources should be allocated from the first specified reservation. When it is exhausted or expired, the service uses resources from the second specified reservation, and so on. Make sure to select reservations that have enough capacity and that do not expire in several days. To find out how different combinations of parameter values impact the result, see the table below: | `policy` | `reservation-ids` | **Behavior** | | | -------- | ----------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | - | | `auto` | Not specified |

Managed Kubernetes tries to launch a node group in any available and suitable reservation. If none is found, resources for all nodes in the node group are provided from the common pool, not from a reservation.

If a reservation doesn't have enough capacity for the whole node group, it uses all the resources available in this reservation and also takes resources from the common pool. In other words, resources for some nodes are provided from the reservation, and resources for the rest of the nodes are provided from the common pool.

| | | `auto` | Specified | Managed Kubernetes tries to launch a node group in one of the specified reservations. If none of them fit (for example, they are not currently active or there are not enough GPUs), the same logic of the `auto` policy applies. | | | `forbid` | Not specified | Node group resources are provided from the common pool. No reservations are used. | | | `forbid` | Specified | Not supported. If you apply this combination, it will result in a validation error. | | | `strict` | Not specified | Managed Kubernetes tries to launch a node group in any available and suitable reservation. If none is found, a request for creating or updating a node group fails. | | | `strict` | Specified | Managed Kubernetes tries to launch a node group in one of the specified reservations. If none of them fit, a request for creating or updating a node group fails. | |
To configure reservations in the node group, use the `reservation_policy` parameter: ```hcl resource "nebius_mk8s_v1_node_group" "my_node_group" { ... reservation_policy = { policy = "" reservation_ids = "" } ... } ``` Description of the parameters: * `policy`: Policy for reservation usage. Supports the following values: * `AUTO`: Node group resources are allocated from reservations. If no reservations are currently available, the node group runs without them. In this case, resources for the node group are provided from the common pool. The `AUTO` value is default. If you don't have any reservations and you don't set the `policy` parameter, the `AUTO` value applies and the node group runs without reservations. * `FORBID`: Node group resources are provided from the common pool, and no reservations are used. * `STRICT`: Node group resources are exclusively allocated from reservations. The node group doesn't run without the reservations. * `reservation_ids`: IDs of specific reservations (capacity block groups). You can use this parameter with the `AUTO` and `STRICT` reservation usages: Specify the IDs in the order in which reservations should apply. For instance, resources should be allocated from the first specified reservation. When it is exhausted or expired, the service uses resources from the second specified reservation, and so on. Make sure to select reservations that have enough capacity and that do not expire in several days. To find out how different combinations of parameter values impact the result, see the table below: | `policy` | `reservation_ids` | **Behavior** | | -------- | ----------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `AUTO` | Not specified |

Managed Kubernetes tries to launch a node group in any available and suitable reservation. If none is found, resources for all nodes in the node group are provided from the common pool, not from a reservation.

If a reservation doesn't have enough capacity for the whole node group, it uses all the resources available in this reservation and also takes resources from the common pool. In other words, resources for some nodes are provided from the reservation, and resources for the rest of the nodes are provided from the common pool.

| | `AUTO` | Specified | Managed Kubernetes tries to launch a node group in one of the specified reservations. If none of them fit (for example, they are not currently active or there are not enough GPUs), the same logic of the `AUTO` policy applies. | | `FORBID` | Not specified | Node group resources are provided from the common pool. No reservations are used. | | `FORBID` | Specified | Not supported. If you apply this combination, it will result in a validation error. | | `STRICT` | Not specified | Managed Kubernetes tries to launch a node group in any available and suitable reservation. If none is found, a request for creating or updating a node group fails. | | `STRICT` | Specified | Managed Kubernetes tries to launch a node group in one of the specified reservations. If none of them fit, a request for creating or updating a node group fails. |
## What's next To find information about reservations, check the pages of your VMs (nodes). The VM page and the list of VMs show what reservation policy you have configured and what reservations currently apply. For more information, see [How to find information about reservations for an already configured VM](https://docs.nebius.com/compute/virtual-machines/reservations.md#how-to-find-information-about-reservations-for-an-already-configured-vm). For details about how billing works when you use reservations, see [Billing for reservations](https://docs.nebius.com/compute/virtual-machines/reservations.md#billing-for-reservations). ## See also * [Capacity block groups in Nebius AI Cloud](https://docs.nebius.com/overview/limits/capacity-block-groups.md) * [Capacity reservations for Compute virtual machines](https://docs.nebius.com/compute/virtual-machines/reservations.md) # Maintenance in Managed Service for Kubernetes® Source: https://docs.nebius.com/kubernetes/maintenance/index.md The goal of the Managed Service for Kubernetes maintenance is to terminate a node as gracefully as possible. When a node termination is required, Nebius AI Cloud issues a maintenance event. Maintenance events are triggered when software or hardware fails on the physical machines that host your nodes, or when Nebius AI Cloud runs planned maintenance. Software and hardware failures account for the vast majority of maintenance events. Managed Kubernetes listens to maintenance events that underlying services launch. In particular, as every Kubernetes node represents a Compute virtual machine, Managed Kubernetes tracks [Compute maintenance events](https://docs.nebius.com/compute/virtual-machines/maintenance.md). ## How maintenance occurs 1. Nebius AI Cloud issues a maintenance event. When the event is issued, Managed Kubernetes assigns the `NebiusMaintenanceScheduled` [Kubernetes condition](https://kubernetes.io/docs/reference/node/node-status/#condition). You can [check the list of conditions](https://docs.nebius.com/kubernetes/maintenance/manage.md#how-to-check-that-a-maintenance-event-is-issued) to make sure that the service has issued the event. 2. The Managed Kubernetes service detects an event on a node. The service groups nodes into batches within a given node group. If a lot of maintenance events are expected in a Managed Kubernetes cluster, batches allow you to avoid stopping all nodes at once. The batch size equals either `1` or the [.spec.strategy.max\_unavailable](https://docs.nebius.com/kubernetes/node-groups/manage.md#node-group-parameters) value if this value is greater than `1`. You can check the `.spec.strategy.max_unavailable` parameter by using the following command: ```bash nebius mk8s node-group get --id ``` 3. To stop scheduling new Pods, Managed Kubernetes cordons the node. 4. The service waits for workloads on the node to finish. They should finish at least one hour before the *SLA deadline* of the maintenance event. This is the latest time the maintenance event should take place. You can check the SLA deadline [together with Kubernetes conditions](https://docs.nebius.com/kubernetes/maintenance/manage.md#how-to-check-that-a-maintenance-event-is-issued). 5. To remove existing Pods, Managed Kubernetes drains the node. The drain takes up to one hour. 6. Nebius AI Cloud stops the Compute VM (that is, the node). 7. Nebius AI Cloud starts the VM. 8. Managed Kubernetes uncordons the node and enables scheduling new Pods. 9. Managed Kubernetes removes the `NebiusMaintenanceScheduled` condition from the node. After that, the node is considered to be healthy. Workloads can run on this node again. ## Manual launch of maintenance The service runs maintenance automatically. However, you can launch it manually as well if a maintenance event is issued for your node. For more information, see [How to launch maintenance manually in Managed Kubernetes](https://docs.nebius.com/kubernetes/maintenance/manage.md#how-to-launch-maintenance-manually-in-managed-kubernetes). # Managing maintenance in Managed Service for Kubernetes® Source: https://docs.nebius.com/kubernetes/maintenance/manage.md [Maintenance in Managed Service for Kubernetes](https://docs.nebius.com/kubernetes/maintenance/index.md) is scheduled automatically when Nebius AI Cloud issues a maintenance event. However, you also have an option to [launch maintenance manually](https://docs.nebius.com/kubernetes/maintenance/manage.md#how-to-launch-maintenance-manually-in-managed-kubernetes). You can only do that if a maintenance event is issued for a given node. You can [check the event](https://docs.nebius.com/kubernetes/maintenance/manage.md#how-to-check-that-a-maintenance-event-is-issued) upfront, before you proceed with the manual maintenance launch. ## How to check that a maintenance event is issued 1. [Connect](https://docs.nebius.com/kubernetes/connect.md) to your Managed Kubernetes cluster. 2. Get the node ID: ```bash kubectl get nodes -o name ``` Output: ```text node/computeinstance-*** node/computeinstance-*** ... ``` The node ID is `computeinstance-***`. 3. Check that a maintenance event is issued and the time that it is scheduled for: ```bash kubectl describe node | grep -A 10 "Conditions:" ``` If the event is issued, the command shows the `NebiusMaintenanceScheduled` [Kubernetes condition](https://kubernetes.io/docs/reference/node/node-status/#condition). For example: ```text Conditions: Type Status LastHeartbeatTime LastTransitionTime Reason Message ---- ------ ----------------- ------------------ ------ ------- NebiusMaintenanceScheduled True Wed, 08 Aug 2025 14:28:31 +0200 Wed, 08 Aug 2025 14:28:31 +0200 MaintenanceScheduled Node scheduled for urgent maintenance, SLA deadline is 2025-08-13T12:26:00Z ... ``` In the `Message` column, the command shows the SLA deadline: the latest time the maintenance event should take place. ## How to launch maintenance manually in Managed Kubernetes 1. [Connect](https://docs.nebius.com/kubernetes/connect.md) to your Managed Kubernetes cluster. 2. [Make sure](https://docs.nebius.com/kubernetes/maintenance/manage.md#how-to-check-that-a-maintenance-event-is-issued) that a maintenance event is issued. 3. Change the maintenance event time: ```bash kubectl label node \ nebius.com/perform-maintenance= \ --overwrite ``` If you want to start the node drain and the maintenance as soon as possible, set the `true` value for the `nebius.com/perform-maintenance` Kubernetes label. Alternatively, you can set a specific time for the maintenance. For a specific time, make sure that the following conditions are met: * The time should not be in the past. If you set a time in the past, the `true` value applies instead, and the node drain starts as soon as possible. * The time should be at least five minutes earlier than the SLA deadline. Otherwise, the time is ignored, and the `true` value applies. Managed Kubernetes supports the following two formats for the time value: * Unix time in seconds, for example, `1262304000`. This format implies the UTC timezone by default. * [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) modified for Kubernetes labels: * Use a full stop `.` as a separator, instead of a colon `:`. * Use the `_hh.mm` format to specify a UTC+N timezone (for example, `_02.00` for UTC+2). * Use the `-hh.mm` format to specify a UTC-N timezone (for example, `-03.00` for UTC-3). You may opt not to specify a timezone in the value. In this case, Managed Kubernetes uses the UTC timezone by default. Examples of RFC 3339 values: | **Time in a given timezone** | **Value** | **Time in UTC** | | ---------------------------- | --------------------------- | ---------------------------------------------------- | | June 12, 2025, 8:05 UTC-2 | `2025-06-12T08.05.00-02.00` | June 12, 2025, 10:05 UTC,
`2025-06-12T10.05.00` | | June 12, 2025, 8:05 UTC+2 | `2025-06-12T08.05.00_02.00` | June 12, 2025, 6:05 UTC,
`2025-06-12T06.05.00` | # Health checks and automatic recovery of Managed Service for Kubernetes® nodes Source: https://docs.nebius.com/kubernetes/maintenance/health-checks.md Managed Service for Kubernetes runs *[Node Problem Detector](https://kubernetes.io/docs/tasks/debug/debug-cluster/monitor-node-health/)* (NPD) to monitor health checks. NPD is an open-source Kubernetes daemon that checks a node's health, detects problems on a node and reports them as [Kubernetes conditions](https://kubernetes.io/docs/reference/node/node-status/#condition) or [events](https://kubernetes.io/docs/reference/kubernetes-api/cluster-resources/event-v1/). Managed Kubernetes runs NPD on each node in the cluster as a systemd service by default. NPD collects information about CPU usage, disk usage and network status. Based on health checks, Managed Kubernetes automatically recovers nodes in a cluster. The service applies health checks in the following cases: * A Network SSD Non-replicated (Network SSD NRD) boot disk experiences [input/output (I/O) issues](https://docs.nebius.com/kubernetes/maintenance/health-checks.md#i%2Fo-issues-of-a-network-ssd-nrd-boot-disk) and does not work correctly. * A node is reporting a [false or unknown status](https://docs.nebius.com/kubernetes/maintenance/health-checks.md#false-or-unknown-status-of-a-node). * A node is experiencing [problems with GPUs](https://docs.nebius.com/kubernetes/maintenance/health-checks.md#issues-with-gpus-on-a-node). For information about the availability of health checks, see [How to enable or disable health checks in a Managed Service for Kubernetes® cluster](https://docs.nebius.com/kubernetes/maintenance/enable-disable-health-checks.md). ## I/O issues of a Network SSD NRD boot disk If a Network SSD NRD boot disk on a node is unavailable for reading data from the disk or writing to it, the boot disk reports I/O errors. If the errors persist for 30 seconds or more, Managed Kubernetes sets the Kubernetes condition `NebiusBootDiskIOError = True` for the node. To fix the I/O issues, the service runs an automatic recovery: it deletes the node and then creates a new one with a different name and healthy boot disk. ## False or unknown status of a node Managed Kubernetes runs health checks and sets the `NodeReady` Kubernetes condition to check a node's status. If the condition remains in the `False` status for more than five minutes, or if the condition remains in the `Unknown` status for more than 15 minutes, the service runs an automatic recovery. It deletes the node and then creates a healthy one with a different name. ## Issues with GPUs on a node Managed Kubernetes runs several health checks for components of a GPU-based cluster. For example, the service checks GPUs, [InfiniBand™](https://docs.nebius.com/kubernetes/gpu/clusters.md) and NVLink by using the `nvidia-smi`, `dcgmi` and `dmesg` tools. Also, the service checks if a GPU node experiences [Xid errors](https://docs.nvidia.com/deploy/xid-errors/introduction.html) or problems with the [error correction code memory](https://en.wikipedia.org/wiki/ECC_memory). Each GPU health check runs every five minutes. If all GPU health checks have passed, the `NebiusGPUError` Kubernetes condition is set to the `False` status. If the condition is set to the `True` status, Managed Kubernetes automatically recovers the node: 1. To stop scheduling new Pods, Managed Kubernetes cordons the node. 2. The service waits until all workloads that consume GPUs are finished or stopped, and until these GPUs are released. 3. To remove existing Pods, Managed Kubernetes drains the node. The drain takes up to one hour. 4. Nebius AI Cloud stops the node (the Compute virtual machine which the node is based on). 5. Nebius AI Cloud starts the node. 6. Managed Kubernetes uncordons the node and enables scheduling new Pods. As a result, Managed Kubernetes migrates the node to a different, healthy virtual machine. Sometimes, a GPU-related issue is solved before Managed Kubernetes starts to drain the node. In this case, the service does not drain the node but uncordons it instead. *** *InfiniBand and InfiniBand Trade Association are registered trademarks of the InfiniBand Trade Association.* # How to enable or disable health checks in a Managed Service for Kubernetes® cluster Source: https://docs.nebius.com/kubernetes/maintenance/enable-disable-health-checks.md ## How to enable health checks [Health checks](https://docs.nebius.com/kubernetes/maintenance/health-checks.md) are enabled by default in Managed Service for Kubernetes clusters created on December 1, 2025, or later. If you created your cluster before this date and you want to enable the health checks, [contact technical support](https://console.nebius.com/support/create-ticket). Alternatively, [create a cluster](https://docs.nebius.com/kubernetes/clusters/manage.md#how-to-create-clusters) and [move your workloads](https://docs.nebius.com/kubernetes/node-groups/moving-workload.md) there. ## How to disable health checks The commands for disabling health checks depend on the issue type to which the health checks are applied. ### How to stop processing I/O issues of a Network SSD NRD boot disk If you want to prevent Managed Kubernetes from deleting a node when a Network SSD Non-replicated boot disk reports [input/output (I/O) issues](https://docs.nebius.com/kubernetes/maintenance/health-checks.md#i%2Fo-issues-of-a-network-ssd-nrd-boot-disk), run the following command and disable a health check: ```bash nebius mk8s node-group update --id \ --auto-repair-conditions '[{"type":"NebiusBootDiskIOError","status":"TRUE","disabled":true}]' ``` ### False or unknown status of a node If you want to prevent Managed Kubernetes from deleting a node when it reports a [false or unknown status](https://docs.nebius.com/kubernetes/maintenance/health-checks.md#false-or-unknown-status-of-a-node), disable a health check: 1. Disable the health check for the `Unknown` status of the node: ```bash nebius mk8s node-group update --id \ --auto-repair-conditions '[{"type":"NodeReady","status":"UNKNOWN","disabled":true}]' ``` 2. Disable the health check for the `False` status of the node: ```bash nebius mk8s node-group update --id \ --auto-repair-conditions '[{"type":"NodeReady","status":"FALSE","disabled":true}]' ``` ### How to stop processing issues with GPUs on a node If you want to prevent Managed Kubernetes from cordoning, draining and stopping a node when the service detects [issues with GPUs](https://docs.nebius.com/kubernetes/maintenance/health-checks.md#issues-with-gpus-on-a-node) on it, run the following command and disable a health check: ```bash nebius mk8s node-group update --id \ --auto-repair-conditions '[{"type":"NebiusGPUError","status":"TRUE","disabled":true}]' ``` # How to connect to Managed Service for Kubernetes® clusters using kubectl Source: https://docs.nebius.com/kubernetes/connect.md Use the public endpoint to connect to the cluster from the internet and the private endpoint to connect from a Compute virtual machine. 1. Generate a kubeconfig file: ```bash nebius mk8s cluster get-credentials \ --id --external ``` 2. Use kubectl: ```bash kubectl cluster-info ``` You can limit access to the public endpoint and only allow certain IP addresses to connect to the cluster. For more information, see [Access restriction for a public endpoint of a Managed Service for Kubernetes® cluster](https://docs.nebius.com/kubernetes/networking/limit-access-to-public-endpoint.md). **Requirements to connect to a VM with private IP address** To connect to a Managed Service for Kubernetes cluster from a Compute VM using a [private IP address](https://docs.nebius.com/compute/virtual-machines/network.md#private-ip) or another cluster using a private load balancer, both must be in the same [region](https://docs.nebius.com/overview/regions.md) and subnet. 1. Generate a kubeconfig file: ```bash nebius mk8s cluster get-credentials \ --id --internal ``` 2. Use kubectl: ```bash kubectl cluster-info ``` # Network requirements for Managed Service for Kubernetes® clusters Source: https://docs.nebius.com/kubernetes/networking/requirements.md A Managed Service for Kubernetes cluster requires several blocks of IP addresses for its components. Before creating a cluster, make sure that you meet the IP address requirements: * The required allocations fit into your free [quotas](https://docs.nebius.com/vpc/resources/quotas-limits.md). * The [subnet](https://docs.nebius.com/vpc/overview.md#subnet) you select during cluster creation has enough free CIDR blocks. If you use a default subnet, it already meets the CIDR block requirement. If you plan to [use a non-default subnet](https://docs.nebius.com/kubernetes/networking/non-default-subnet.md), check that the subnet has the necessary IP address allocations available. If Managed Kubernetes is unable to allocate the IP addresses, cluster creation fails. ## Private IP address allocations For the [control plane](https://docs.nebius.com/kubernetes/components.md#control-plane-components): * 5 `/32` allocations: * 1 for the internal load balancer. * 4 for the control plane instances in case of high availability (3 for `etcd` instances and 1 more to enable control plane updates). If control plane high availability is disabled, 3 `/32` allocations are enough. * 1 allocation for Kubernetes services. By default, a `/16` CIDR block is allocated, but you can set the `spec.kube_network.service_cidrs` parameter during cluster creation to specify a custom CIDR block, in range from `/12` to `/28`. For [node groups](https://docs.nebius.com/kubernetes/components.md#node-group), per node: * 1 `/24` allocation for Pods assigned to a node. * 1 `/32` allocation for the internal IP address of a node. With the default [deployment strategy](https://docs.nebius.com/kubernetes/node-groups/manage.md#node-group-parameters), a rolling update does not require quota for additional nodes. If you configure a surge-based deployment strategy, make sure that you have enough available quota for the additional nodes that can be created during the update. If you set a specific subnet for a node group or for the control plane, make sure that the required CIDR blocks are available within that subnet. ## Public IP address allocations The public IP address of the cluster is allocated automatically from the Managed Kubernetes project and does not use up your quota. If you have enabled public IP addresses for nodes in a node group (with the `spec.template.network_interfaces.public_ip_address` parameter), you need 1 `/32` public IP allocation for each node. To allocate the public IP addresses for the nodes from a fixed list, create an [allocation](https://docs.nebius.com/vpc/overview.md#allocation) in your subnet's pool of public IP addresses and pass it to the `spec.template.network_interfaces.public_ip_address.allocation_id` parameter. # Access restriction for a public endpoint of a Managed Service for Kubernetes® cluster Source: https://docs.nebius.com/kubernetes/networking/limit-access-to-public-endpoint.md If a Managed Service for Kubernetes cluster has a public endpoint, one can access it from any IP address in the internet. You can limit this access and only allow certain IP addresses to reach the cluster. To do so, specify allowed CIDR blocks in the cluster configuration. When you enable a public endpoint for a Managed Kubernetes cluster, Nebius AI Cloud allocates a public IP address and provisions a load balancer to the cluster. This load balancer routes traffic to the [control plane instances](https://docs.nebius.com/kubernetes/components.md#control-plane-components). With access restriction set for a public endpoint, the allowlist of IP addresses takes effect at the network interface level of those instances based on [security groups](https://docs.nebius.com/vpc/security-groups/overview.md). The access restriction doesn't affect the private endpoint and internal traffic. The private endpoint remains open as before. ## How to set an allowlist to access a Managed Kubernetes cluster Set allowed CIDR blocks when you create or update a cluster. Pass over each CIDR block as a separate `--control-plane-endpoints-public-endpoint-allowed-cidrs` parameter. The CIDR blocks must follow the IPv4 format. Bits for hosts must be equal to zero. Examples of valid CIDR blocks: * `192.168.0.0/24` where the last eight bits are allocated to hosts and equal to zero. * `8.8.8.64/26` where the last six bits are allocated to hosts and equal to zero (64 in the decimal system is 01000000 in the binary system). To set an allowlist of CIDR blocks, do one of the following: * Create a cluster with limited access to the public endpoint: ```bash nebius mk8s cluster create \ --control-plane-endpoints-public-endpoint=true \ --control-plane-endpoints-public-endpoint-allowed-cidrs "203.0.113.0/24" \ --control-plane-endpoints-public-endpoint-allowed-cidrs "198.51.100.128/25" \ ... ``` * Update a cluster and restrict access to the public endpoint: ```bash nebius mk8s cluster update \ --control-plane-endpoints-public-endpoint-allowed-cidrs "203.0.113.0/24" \ --control-plane-endpoints-public-endpoint-allowed-cidrs "198.51.100.128/25" ``` The `update` command overwrites a list of CIDR blocks. If you added any CIDR blocks earlier and you want to preserve them, specify these CIDR blocks in the `update` command. For more information about other command parameters, see [How to create and modify Managed Service for Kubernetes® clusters](https://docs.nebius.com/kubernetes/clusters/manage.md). # Security groups in Managed Service for Kubernetes® Source: https://docs.nebius.com/kubernetes/networking/security-groups.md Managed Service for Kubernetes integrates with Virtual Networks security groups to control traffic to and from your cluster's nodes. For a general overview of network security groups and how to create them, see [Security groups overview](https://docs.nebius.com/vpc/security-groups). ## System security groups Nebius automatically creates and manages a *system security group* per cluster for your worker nodes. This security group guarantees that core Kubernetes connectivity, such as connectivity between the API server and kubelets, works correctly regardless of any additional security groups that you configure on your node groups. The system security group is visible in your project, but it's marked as managed. You can't edit it or assign it to your own resources. ## User-defined security groups You can [assign](https://docs.nebius.com/kubernetes/networking/assign-security-groups.md) your own security groups to node groups. When you do, each node in that group has both your security groups and the system security group assigned. The system security group is always present and can't be overridden or removed. If you don't specify any security groups when creating a node group, the network's default security group is assigned alongside the system security group. This means you can use your own security groups to restrict or allow additional traffic, such as traffic between node groups or to external services, without risking disruption to cluster operations. ## Default security groups Every virtual machine (VM) in Nebius AI Cloud is always assigned at least one security group: the network's *default security group*. This applies automatically and can't be removed. It ensures that VMs always have a baseline set of rules even before any cluster-level or user-defined groups are applied. ## See also * [Configuring security groups on a node group](https://docs.nebius.com/kubernetes/networking/assign-security-groups.md) # How to assign security groups to a node group in Managed Service for Kubernetes® Source: https://docs.nebius.com/kubernetes/networking/assign-security-groups.md Assign network security groups to Managed Kubernetes node groups to control traffic to and from your cluster's nodes. ## Prerequisites Before assigning security groups to a node group, you need to create them. See [Managing security groups](https://docs.nebius.com/vpc/security-groups/manage.md) for instructions on creating groups and defining rules. If you use your own security groups to restrict egress traffic, make sure that the cluster can still access the resources it needs. For example, blocking outbound internet access can break functionality that depends on it, such as pulling images from external registries. ## How to assign security groups when creating a node group Use `--template-network-interfaces` to assign security groups when creating a node group: ```bash nebius mk8s node-group create \ --parent-id \ --name \ --fixed-node-count 1 \ --template-resources-platform \ --template-resources-preset \ --template-network-interfaces "[{\"subnet_id\": \"\", \"security_groups\": [{\"id\": \"\"}, {\"id\": \"\"}]}]" ``` ## How to update security groups on an existing node group ```bash nebius mk8s node-group update \ --template-network-interfaces "[{\"subnet_id\": \"\", \"security_groups\": [{\"id\": \"\"}, {\"id\": \"\"}]}]" \ ``` # Exposing services with load balancers Source: https://docs.nebius.com/kubernetes/clusters/load-balancer.md You can expose a [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/) in your Managed Service for Kubernetes cluster using a *load balancer*. The load balancer receives traffic on a public or private IP address, depending on how you [set it up](https://docs.nebius.com/kubernetes/clusters/load-balancer.md#how-to-set-up-a-load-balancer), and distributes the traffic between the service's Pods automatically. **Requirements to connect to a VM with private IP address** To connect to a Managed Service for Kubernetes cluster from a Compute VM using a [private IP address](https://docs.nebius.com/compute/virtual-machines/network.md#private-ip) or another cluster using a private load balancer, both must be in the same [region](https://docs.nebius.com/overview/regions.md) and subnet. ## Prerequisites Before you start setting up a load balancer, you need to [create a Managed Kubernetes cluster](https://docs.nebius.com/kubernetes/clusters/manage.md#how-to-create-clusters) and [connect to it](https://docs.nebius.com/kubernetes/connect.md) using kubectl. ## Load balancers types By default, load balancers are created with public IP addresses. To expose your service on a private IP address instead, add `nebius.com/load-balancer-type: internal` to the annotations of the service. To retain an IP address that was automatically allocated to a load balancer and reuse it after deleting or recreating the service, follow the [How to convert a dynamically assigned public IP address to a reusable allocation](https://docs.nebius.com/kubernetes/networking/dynamic-to-static.md) guide. If you have created an IP address allocation ([example for public IP addresses](https://docs.nebius.com/compute/virtual-machines/network.md#public-ip-addresses)) and want to use it to allocate an IP address to a load balancer, add its ID to the service annotation `nebius.com/load-balancer-allocation-id`. The allocation type (public or private) must match the load balancer type. The table below explains how these two annotations work together: | Type is `internal` | Allocation ID is set | Result | | ------------------ | -------------------- | ---------------------------------------------------------------------------- | | Yes | Yes | Load balancer gets a **private** IP address from the **provided** allocation | | Yes | No | Load balancer gets a **private** IP address from a **new** allocation | | No | Yes | Load balancer gets a **public** IP address from the **provided** allocation | | No | No | Load balancer gets a **public** IP address from a **new** allocation | To allocate a public IP address from a specific IP pool, add the pool ID to the `nebius.com/load-balancer-pool-id` service annotation. When this annotation is set, the IP address is allocated from the specified pool instead of the default user subnet pool. For more information about IP pools, see the [Virtual Networks overview](https://docs.nebius.com/vpc/overview.md#pool). ```yaml annotations: nebius.com/load-balancer-pool-id: "" ``` ## How to set up a load balancer 1. Create the manifest to set up the internal load balancer service with a private IP address (we will refer to it later as `service.yaml`): ```yaml apiVersion: v1 kind: Service metadata: name: nginx annotations: nebius.com/load-balancer-type: "internal" spec: selector: app: nginx ports: - protocol: TCP port: 80 targetPort: 80 type: LoadBalancer ``` 2. Create the manifest for nginx deployment (we will refer to it later as `deployment.yaml`): ```yaml apiVersion: apps/v1 kind: Deployment metadata: name: nginx-deployment spec: replicas: 1 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx:latest ports: - containerPort: 80 ``` 3. Apply the configurations: ```bash kubectl apply -f deployment.yaml kubectl apply -f service.yaml ``` 4. Check the service and the allocated IP address: ```bash kubectl get svc nginx ``` You will receive an output like the one below: ```bash NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE nginx LoadBalancer 10.158.250.188 192.168.0.112 80:30512/TCP 4s ``` 1. Create the manifest to set up the internal load balancer service with a public IP address (we will refer to it later as `service.yaml`): ```yaml apiVersion: v1 kind: Service metadata: name: nginx spec: selector: app: nginx ports: - protocol: TCP port: 80 targetPort: 80 type: LoadBalancer ``` 2. Create the manifest for nginx deployment (we will refer to it later as `deployment.yaml`): ```yaml apiVersion: apps/v1 kind: Deployment metadata: name: nginx-deployment spec: replicas: 1 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx:latest ports: - containerPort: 80 ``` 3. Apply the configurations: ```bash kubectl apply -f deployment.yaml kubectl apply -f service.yaml ``` 4. Check the service and the allocated IP address: ```bash kubectl get svc nginx ``` You will see an output like the one below: ```bash NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE nginx LoadBalancer 10.158.105.48 195.242.8.219 80:30816/TCP 13s ``` 5. Use the `EXTERNAL-IP` from the previous command output to connect to the service from outside of the Kubernetes cluster: ```bash curl -i ``` You will see an output like the one below: ```bash HTTP/1.1 200 OK Server: nginx/1.27.1 ``` # How to use a non-default subnet for Managed Service for Kubernetes® clusters and node groups Source: https://docs.nebius.com/kubernetes/networking/non-default-subnet.md By default, when you create a Managed Service for Kubernetes cluster, its control plane uses the [default subnet of the default network](https://docs.nebius.com/vpc/overview.md#default-virtual-networks-resources) in your project. Node groups inherit the control plane's subnet. You might want to use custom subnets that you created, for example, to ensure [resource isolation](https://docs.nebius.com/vpc/networking/isolation.md), [allocate custom private IP addresses](https://docs.nebius.com/vpc/addressing/custom-private-addresses.md) to nodes or [disable public IP addresses](https://docs.nebius.com/vpc/addressing/disable-public-addresses.md) for them. To ensure connectivity, the control plane subnet and the node group subnet must belong to the same [network](https://docs.nebius.com/vpc/overview.md#network). Their [CIDR blocks](https://en.wikipedia.org/wiki/Classless_Inter-Domain_Routing), however, can be different. ## A non-default network for clusters To use a custom subnet for a cluster, [get its ID](https://docs.nebius.com/vpc/networking/resources.md) and pass it to the `--control-plane-subnet-id` parameter when [creating the cluster](https://docs.nebius.com/kubernetes/clusters/manage.md#how-to-create-clusters): ```bash nebius mk8s cluster create \ ... \ --control-plane-subnet-id ``` ## A non-default network for node groups To use a custom subnet for a node group, [get its ID](https://docs.nebius.com/vpc/networking/resources.md) and pass it in one of the following ways: * Add the subnet ID to the [node group creation command](https://docs.nebius.com/kubernetes/node-groups/manage.md#how-to-create-node-groups) by using the `--template-network-interfaces` CLI parameter: ```bash nebius mk8s node-group create \ ... \ --template-network-interfaces '[{"public_ip_address": {}, "subnet_id": ""}]' ``` * Pass the subnet ID to the `spec.template.network_interfaces.subnet_id` field of the [node group configuration](https://docs.nebius.com/kubernetes/node-groups/manage.md#node-group-parameters). For more details, see [How to create node groups](https://docs.nebius.com/kubernetes/node-groups/manage.md#how-to-create-node-groups). # How to create a fixed set of public IP addresses for a node group Source: https://docs.nebius.com/kubernetes/networking/defined-ips.md When you enable public IP addresses for nodes in a node group, the IP addresses are dynamically assigned from the general pool of public IP addresses managed by Nebius AI Cloud. The assigned addresses may change when nodes are recreated or updated. If you need a fixed set of public IP addresses—for example, to configure firewall rules, define an allowlist, register DNS records or integrate external systems—create a subnet with a dedicated public IP address range. While individual node IP addresses may still change, they will always be selected from the range defined in this subnet. ## Prerequisites 1. [Install and configure](https://docs.nebius.com/cli/install.md) the Nebius AI Cloud CLI. 2. Make sure you are in a [group](https://docs.nebius.com/iam/authorization/groups/index.md) that has at least the `editor` role within your tenant or project; for example, the default `editors` group. You can check this in the [Administration → IAM](https://console.nebius.com/iam) section of the web console. 3. Make sure that you have enough quota on IP addresses to support your node group [deployment strategy](https://docs.nebius.com/kubernetes/node-groups/manage.md#node-group-parameters). You can check the quota on the [Administration → Limits → Quotas](https://console.nebius.com/quota) page of the web console. By default, no additional public IP addresses are required during an update. If you configure a surge-based strategy, reserve enough extra public IP addresses for the additional nodes that can be created during the update. Otherwise, updates or upgrades can stop when trying to create a new node. ## How to create a fixed set of IP addresses To create a fixed set of public IP addresses for a node group, create a subnet with dedicated public IP address pool and configure the node group to use this subnet: 1. Create a subnet with public IP address CIDRs: ```bash nebius vpc subnet create \ --name \ --network-id \ --ipv4-public-pools-use-network-pools=false \ --ipv4-public-pools-pools='[ { "cidrs": [ {"cidr": "/32"}, {"cidr": "/32"}, {"cidr": "/32"} ] }]' ``` Specify the following parameters: * `name`: Name of the subnet with a dedicated IP addresses set. * `network-id`: [Network ID](https://docs.nebius.com/vpc/networking/resources.md#how-to-get-a-network-id). * `ipv4-public-pools-pools.cidrs`: One or more IPv4 [CIDR blocks](https://en.wikipedia.org/wiki/Classless_Inter-Domain_Routing#CIDR_blocks). The number of these blocks define how many public IP addresses the subnet has. The nodes in the node group receive these addresses randomly. In the example, three CIDR blocks are defined, each with one public IP address. In the output, copy the `metadata.id` value — this is the subnet ID. 2. [Create a node group](https://docs.nebius.com/kubernetes/node-groups/manage.md) with the `--template-network-interfaces` parameter. Specify the new subnet ID in it: ```bash nebius mk8s node-group create \ ... \ --template-network-interfaces "[{\"public_ip_address\": {}, \"subnet_id\": \"\"}]" ``` This configuration assigns random public IP addresses from the CIDR blocks defined in the subnet. Now, the nodes in the node group get public IP addresses from the dedicated set. This enables you to predefine a fixed range of IP addresses for use in an allowlist or for DNS mapping, even if individual IP addresses are reassigned across nodes. # How to convert a dynamically assigned public IP address to a reusable allocation Source: https://docs.nebius.com/kubernetes/networking/dynamic-to-static.md When you [expose a Kubernetes® service](https://docs.nebius.com/kubernetes/clusters/load-balancer.md) in your Managed Service for Kubernetes cluster by using a load balancer, the system automatically creates an allocation with a reserved public IP address and the `nebius.com/managed-by: mk8s` label. However, if the service is deleted, this allocation is also removed by default. To retain the allocated public IP address and reuse it in future, convert the system-managed allocation into a persistent one and manually link it to your service by using an annotation. ## Prerequisites 1. Make sure you are in a [group](https://docs.nebius.com/iam/authorization/groups/index.md) that has at least the `editor` role within your tenant or project; for example, the default `editors` group. You can check this in the [Administration → IAM](https://console.nebius.com/iam) section of the web console. 2. Install [jq](https://jqlang.github.io/jq/) to extract IDs and tokens from the JSON data returned by the Nebius AI Cloud CLI: ```bash Ubuntu sudo apt-get install jq ``` ```bash macOS brew install jq ``` 3. [Create a Managed Service for Kubernetes cluster](https://docs.nebius.com/kubernetes/quickstart.md#create-a-cluster-and-a-node-group) if you have not done it before. 4. [Install kubectl](https://kubernetes.io/docs/tasks/tools/#kubectl) and [connect to the cluster](https://docs.nebius.com/kubernetes/quickstart.md#connect-to-the-cluster). ## How to convert a dynamic IP address 1. Get the public IP address of your load balancer: ```bash kubectl get svc nginx ``` Copy the IP address from the `EXTERNAL-IP` column. 2. Get the ID of the allocation associated with the IP address: ```bash nebius vpc allocation list --format json | jq -r ' .items[] | select( .status.details.allocated_cidr == "/32" and .metadata.labels["nebius.com/managed-by"] == "mk8s" ) | .metadata.id' ``` Specify the IP address that you copied in the previous step. Alternatively, list all allocations by using the [nebius vpc allocation list](https://docs.nebius.com/cli/reference/vpc/allocation/list) command. In the output, look for a block that contains the matching IP address under `status.details.allocated_cidr` and a `labels` field containing `nebius.com/managed-by: mk8s`. Copy the allocation ID. It has the `vpcallocation-***` format. 3. To detach the allocation from automatic deletion, remove system-managed labels of this allocation: 1. Open the editor to edit the allocation: ```bash nebius vpc allocation edit ``` Specify the ID that you copied in the previous step. For details on using the `edit` command, see [How to edit resources via the Nebius AI Cloud CLI](https://docs.nebius.com/cli/edit.md). 2. In the editor, delete all labels from the `labels` list: ```yaml ... labels: {} ... ``` 3. Save the changes and close the editor. Now, the allocation is user-managed, so it will remain even if the associated service is deleted. 4. Update your Kubernetes load balancer manifest (for example, [service.yaml](https://docs.nebius.com/kubernetes/clusters/load-balancer.md#how-to-set-up-a-load-balancer)) with the following annotation: ```yaml metadata: annotations: nebius.com/load-balancer-allocation-id: ``` 5. Apply the updated manifest: ```bash kubectl apply -f service.yaml ``` Now, the public IP allocation is preserved and can be reused if you re-create the service or replace it with another one. For more information, see [Load balancers types](https://docs.nebius.com/kubernetes/clusters/load-balancer.md#load-balancers-types). # Networking add-ons in Managed Service for Kubernetes® Source: https://docs.nebius.com/kubernetes/networking/add-ons.md Managed Service for Kubernetes clusters have the following networking add-ons installed by default: * [CoreDNS](https://coredns.io/) is a cluster DNS server. * [Cilium](https://www.cilium.io/) is a networking solution that provides security and observability. The add-ons are configured and maintained by Managed Service for Kubernetes, to ensure consistent cluster operation. The configuration of these add-ons is not exposed via API and there are only limited options to customize them: * For CoreDNS, [use a custom ConfigMap](https://docs.nebius.com/kubernetes/networking/add-ons.md#coredns). * For Cilium, [edit the default ConfigMap](https://docs.nebius.com/kubernetes/networking/add-ons.md#cilium). Do not use `helm upgrade` to customize, as the changes it makes may be rolled back immediately. ## CoreDNS **CoreDNS** is a flexible DNS server for Kubernetes clusters. It replaces kube-dns to handle service discovery and name resolution within the cluster. To view the current CoreDNS configuration, run the following command: ```bash kubectl get configmap -n kube-system coredns -o yaml ``` Do not use `kubectl edit configmap` to make changes to this configuration, because the Managed Service for Kubernetes overwrites the default ConfigMap. Instead, use a custom ConfigMap: 1. Create a custom ConfigMap `coredns-custom.yaml`. It should contain the keys with the `.override` and `.server` extensions. * `.override` keys allow you to add plugins to the default [Server Block](https://coredns.io/manual/configuration/#server-blocks) of CoreDNS. You cannot override the parameters already specified in the default ConfigMap. * `.server` keys allow you to specify additional Server Blocks for CoreDNS. An example of a custom ConfigMap: ```yaml apiVersion: v1 kind: ConfigMap metadata: name: coredns-custom namespace: kube-system data: log.override: | log custom.server: | example.io:8053 { forward . 8.8.8.8 } ``` This ConfigMap: * Adds the `log` plug-in to start logging at the system level. * Creates a new Server Block for the `example.io` domain. All requests directed to `example.io` at port 8053 should be forwarded to another DNS server at `8.8.8.8`. See the CoreDNS documentation for more information on the [Corefile parameters](https://coredns.io/2017/07/23/corefile-explained/) and the list of [available plug-ins](https://coredns.io/plugins/). 1. Apply the custom configuration: ```bash kubectl apply -f coredns-custom.yaml ``` ## Cilium **Cilium** ensures that only specific services and traffic can access certain [Pods](https://docs.nebius.com/kubernetes/components.md#pod). For example: * Some [Pods](https://docs.nebius.com/kubernetes/components.md#pod) might contain sensitive data, and Cilium enforces rules that only certain internal services or authorized users are allowed to access it. * If a [node](https://docs.nebius.com/kubernetes/components.md#node) requires restricted access, Cilium ensures that only internal services with proper credentials or traffic with specific labels are allowed. Also, Cilium provides observability into traffic between [Pods](https://docs.nebius.com/kubernetes/components.md#pod) and [nodes](https://docs.nebius.com/kubernetes/components.md#node), to optimize network paths and enforce network security policies. To make changes to Cilium configuration, run the following command: ```bash kubectl edit configmap -n kube-system cilium-config ``` For more information about available ConfigMap parameters, see the Cilium documentation that matches your cluster's Cilium version: 1. Get the Cilium version used in your cluster: ```bash helm status -n kube-system cilium ``` 2. In the command output, copy the link to the version documentation (remove `/gettinghelp` if present). 3. Open the following page for your version: ```bash /network/kubernetes/configuration/#configmap-options ``` For example, see [https://docs.cilium.io/en/v1.16/network/kubernetes/configuration/#configmap-options](https://docs.cilium.io/en/v1.16/network/kubernetes/configuration/#configmap-options) for Cilium version v1.16. ### Integration with Istio To make [Istio](https://istio.io/latest/) work with a Cilium-enabled Managed Kubernetes cluster, do the following: 1. [Install Istio](https://istio.io/latest/docs/setup/install/). 2. In the Cilium ConfigMap, set the `bpf-lb-sock-hostns-only` parameter to `true`: ```bash kubectl -n kube-system patch configmap cilium-config \ --type merge \ -p='{"data":{"bpf-lb-sock-hostns-only":"true"}}' kubectl -n kube-system rollout restart ds/cilium ``` 3. Wait until all Cilium Pods are restarted. For more information on Istio integration, see the Cilium documentation that matches your cluster's Cilium version: 1. Get the Cilium version used in your cluster: ```bash helm status -n kube-system cilium ``` 2. In the command output, copy the link to the version documentation (remove `/gettinghelp` if present). 3. Open the following page for your version: ```bash /network/servicemesh/istio/ ``` For example, see [https://docs.cilium.io/en/v1.16/network/servicemesh/istio/](https://docs.cilium.io/en/v1.16/network/servicemesh/istio/) for Cilium version v1.16. ### Host firewall If your Managed Kubernetes cluster was created on or after April 17, 2025, [Cilium's host firewall](https://docs.cilium.io/en/latest/security/host-firewall/) is already enabled on the cluster. You can check the creation dates of your clusters in the [web console](https://console.nebius.com/mk8s). If your cluster is older, you need to enable the host firewall manually: 1. [Connect to the cluster](https://docs.nebius.com/kubernetes/connect.md). 2. Run the script that enables the host firewall: ```bash #!/usr/bin/env bash set -euo pipefail # This script ensures that Cilium Host Firewall feature is enabled if all nodes run with the "set-name" feature. kubectl_args=("$@") cluster_name=$(kubectl "${kubectl_args[@]}" config current-context) current_value=$( kubectl "${kubectl_args[@]}" get configmap cilium-config \ -n kube-system \ -o jsonpath='{.data.enableHostFirewall}' \ 2>/dev/null || echo "" ) if [[ "$current_value" == "true" ]]; then echo "Cilium Host Firewall feature is already enabled in cluster \"$cluster_name\". Nothing to do." exit 0 fi echo "Verifying that every node has \"set-name\": \"eth0\" in network-data" for node_ref in $(kubectl "${kubectl_args[@]}" get nodes -o name); do echo "Inspecting $node_ref" node_name="${node_ref#node/}" output=$( kubectl "${kubectl_args[@]}" debug "$node_ref" \ --profile=general \ --image=busybox \ -i -- \ chroot /host sh -c \ 'if grep -q "\"set-name\": \"eth0\"" /var/lib/cloud/instance/network-config.json 2>/dev/null; then echo OK else echo BAD fi' 2>&1 \ | grep -Eo 'OK|BAD' ) echo "Cleaning up debug pod" kubectl "${kubectl_args[@]}" delete $(kubectl "${kubectl_args[@]}" get pod -o name | grep node-debugger-"$node_name") 2>/dev/null if [[ "$output" != "OK" ]]; then echo "ERROR: $node_ref does not have \"set-name\": \"eth0\" in network-data." echo "Ensure that all node groups are upgraded with the following command:" echo " nebius mk8s node-group upgrade --latest-infra-version" exit 1 fi done echo -e "\nAll nodes verified. Enabling Cilium Host Firewall" kubectl "${kubectl_args[@]}" patch configmap cilium-config -n kube-system \ --type=merge \ --patch $'data:\n enable-host-firewall: "true"' echo "Patched cilium-config ConfigMap; new enable-host-firewall value:" kubectl "${kubectl_args[@]}" get configmap cilium-config -n kube-system \ -o yaml \ | sed -n 's/^[[:space:]]*enable-host-firewall:.*/&/p' echo "Restarting Cilium DaemonSet to pick up the new config" kubectl "${kubectl_args[@]}" -n kube-system rollout restart daemonset cilium echo -e "\nDone" ``` ## How the add-ons affect autoscaling node groups Both CoreDNS and Cilium can run on one node, but it's optimal to run on two. If your cluster has at least one node group with [autoscaling](https://docs.nebius.com/kubernetes/node-groups/autoscaling.md), this node group may scale up just to ensure that there are two nodes to run CoreDNS and Cilium, even if there is no workload. If you have GPU node groups in your cluster, also create a CPU node group with at least two nodes (or with autoscaling). In this case, when there are no tasks to perform, CoreDNS and Cilium can run on CPU nodes, so that the GPU node group can scale down and save you the costs. # Setting up NodeLocal DNSCache with Cilium network policy controller in Managed Service for Kubernetes® Source: https://docs.nebius.com/kubernetes/networking/nodelocal-dns-cache.md To improve the DNS performance in a Managed Service for Kubernetes cluster, you can use the [NodeLocal DNSCache](https://kubernetes.io/docs/tasks/administer-cluster/nodelocaldns/) feature. With this feature, a DNS caching agent runs on each cluster node to resolve DNS requests locally on the same nodes as the Pods. In this tutorial, you will learn to configure a NodeLocal DNSCache for the [Cilium network policy controller](https://docs.cilium.io/en/stable/) by using [local redirect policy](https://docs.cilium.io/en/stable/network/kubernetes/local-redirect-policy/). ## Costs Nebius AI Cloud charges you only for running a Managed Kubernetes cluster. For more details, see the [Managed Kubernetes pricing](https://docs.nebius.com/kubernetes/resources/pricing.md). ## Prerequisites * [Create a Managed Service for Kubernetes cluster](https://docs.nebius.com/kubernetes/quickstart.md#create-a-cluster-and-a-node-group) if you have not done it before. * [Install kubectl](https://kubernetes.io/docs/tasks/tools/#kubectl) and [connect to the cluster](https://docs.nebius.com/kubernetes/quickstart.md#connect-to-the-cluster). ## Steps ### Prepare manifests for NodeLocal DNSCache and local redirect policy 1. Retrieve the service IP address for `coredns`: ```bash kubectl get svc coredns -n kube-system -o jsonpath={.spec.clusterIP} ``` 2. Create a manifest file named `node-local-dns.yaml`. In the `DaemonSet` specification (`spec.template.spec.containers.args`), replace the coredns\_IP\_address with the IP address of the `coredns` service you obtained in the previous step. ```yaml --- apiVersion: v1 kind: ServiceAccount metadata: name: node-local-dns namespace: kube-system --- apiVersion: v1 kind: Service metadata: name: node-local-dns-upstream namespace: kube-system labels: k8s-app: node-local-dns-upstream kubernetes.io/name: "NodeLocalDnsUpstream" kubernetes.io/cluster-service: "true" spec: ports: - name: dns port: 53 protocol: UDP targetPort: 53 - name: dns-tcp port: 53 protocol: TCP targetPort: 53 selector: k8s-app: coredns --- apiVersion: v1 kind: ConfigMap metadata: name: node-local-dns namespace: kube-system data: Corefile: | cluster.local:53 { errors cache { success 9984 30 denial 9984 5 } reload loop bind 0.0.0.0 forward . __PILLAR__CLUSTER__DNS__ { prefer_udp } prometheus :9253 health } in-addr.arpa:53 { errors cache 30 reload loop bind 0.0.0.0 forward . __PILLAR__CLUSTER__DNS__ { prefer_udp } prometheus :9253 } ip6.arpa:53 { errors cache 30 reload loop bind 0.0.0.0 forward . __PILLAR__CLUSTER__DNS__ { prefer_udp } prometheus :9253 } .:53 { errors cache 30 reload loop bind 0.0.0.0 forward . __PILLAR__CLUSTER__DNS { prefer_udp } prometheus :9253 } --- apiVersion: apps/v1 kind: DaemonSet metadata: name: node-local-dns namespace: kube-system labels: k8s-app: node-local-dns spec: updateStrategy: rollingUpdate: maxUnavailable: 10% selector: matchLabels: k8s-app: node-local-dns template: metadata: labels: k8s-app: node-local-dns annotations: prometheus.io/port: "9253" prometheus.io/scrape: "true" spec: priorityClassName: system-node-critical serviceAccountName: node-local-dns dnsPolicy: Default # Don't use cluster DNS. tolerations: - key: "CriticalAddonsOnly" operator: "Exists" - effect: "NoExecute" operator: "Exists" - effect: "NoSchedule" operator: "Exists" containers: - name: node-cache image: registry.k8s.io/dns/k8s-dns-node-cache:1.24.0 resources: requests: cpu: 25m memory: 5Mi args: [ "-localip", "coredns_IP_address", "-conf", "/etc/Corefile", "-upstreamsvc", "node-local-dns-upstream", "-skipteardown=true", "-setupinterface=false", "-setupiptables=false" ] securityContext: privileged: true ports: - containerPort: 53 name: dns protocol: UDP - containerPort: 53 name: dns-tcp protocol: TCP - containerPort: 9253 name: metrics protocol: TCP livenessProbe: httpGet: path: /health port: 8080 initialDelaySeconds: 60 timeoutSeconds: 5 volumeMounts: - mountPath: /run/xtables.lock name: xtables-lock readOnly: false - name: config-volume mountPath: /etc/coredns - name: kube-dns-config mountPath: /etc/kube-dns volumes: - name: xtables-lock hostPath: path: /run/xtables.lock type: FileOrCreate - name: kube-dns-config configMap: name: kube-dns optional: true - name: config-volume configMap: name: node-local-dns items: - key: Corefile path: Corefile.base ``` This manifest declares a DaemonSet for NodeLocal DNSCache and a service account, service and ConfigMap needed for its operation. 3. Create a manifest file named `node-local-dns-lrp.yaml`. ```yaml --- apiVersion: "cilium.io/v2" kind: CiliumLocalRedirectPolicy metadata: name: "node-local-dns" namespace: kube-system spec: redirectFrontend: serviceMatcher: serviceName: coredns namespace: kube-system toPorts: - port: "53" name: dns protocol: UDP - port: "53" name: dns-tcp protocol: TCP redirectBackend: localEndpointSelector: matchLabels: k8s-app: node-local-dns toPorts: - port: "53" name: dns protocol: UDP - port: "53" name: dns-tcp protocol: TCP ``` This manifest declares a local redirect policy that directs DNS requests at the `node-local-dns` DaemonSet for resolution. ### Apply the manifests and create resources 1. Create resources for NodeLocal DNSCache: ```bash kubectl apply -f node-local-dns.yaml ``` 2. Create the local redirect policy: ```bash kubectl apply -f node-local-dns-lrp.yaml ``` ### Test NodeLocal DNSCache #### Create a test environment 1. Create a manifest file named `dnsutils.yaml`. ```yaml --- apiVersion: v1 kind: Pod metadata: name: dnsutils namespace: default spec: containers: - name: dnsutils image: registry.k8s.io/e2e-test-images/agnhost:2.9 imagePullPolicy: IfNotPresent restartPolicy: Always ``` 2. Launch the `dnsutils` Pod: ```bash kubectl apply -f dnsutils.yaml ``` 3. Find out which node is running the `dnsutils` Pod: ```bash kubectl get pod dnsutils -o wide ``` The result looks like the following: ```bash NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES dnsutils 1/1 Running 0 16s 10.57.100.14 computeinstance-xxxxxxxxx ``` Once the Pod status is `Running`, get the ID of the node from the `NODE` column. 4. Use the ID of the node to find out the IP address of the Pod that runs NodeLocal DNSCache on this node: ```bash export POD_IP_ADDRESS=$(kubectl get pod -o wide -n kube-system | grep 'node-local.*' | awk '{print $6}') ``` #### Run tests 1. Get the values of the metrics for DNS requests before testing: ```bash kubectl exec -ti dnsutils -- curl http://$POD_IP_ADDRESS:9253/metrics | grep coredns_dns_requests_total ``` The result looks like the following: ```bash # HELP coredns_dns_requests_total Counter of DNS requests made per zone, protocol and family. # TYPE coredns_dns_requests_total counter coredns_dns_requests_total{family="1",proto="udp",server="dns://0.0.0.0:53",type="other",view="",zone="."} 1 coredns_dns_requests_total{family="1",proto="udp",server="dns://0.0.0.0:53",type="other",view="",zone="cluster.local."} 1 coredns_dns_requests_total{family="1",proto="udp",server="dns://0.0.0.0:53",type="other",view="",zone="in-addr.arpa."} 1 coredns_dns_requests_total{family="1",proto="udp",server="dns://0.0.0.0:53",type="other",view="",zone="ip6.arpa."} 1 ``` 2. Run several DNS requests: ```bash kubectl exec -ti dnsutils -- nslookup kubernetes && kubectl exec -ti dnsutils -- nslookup kubernetes.default && kubectl exec -ti dnsutils -- nslookup nebius.com ``` 3. Now check the metrics again: ```bash kubectl exec -ti dnsutils -- curl http://$POD_IP_ADDRESS:9253/metrics | grep coredns_dns_requests_total ``` The values of the metrics should increase, for example: ```bash # HELP coredns_dns_requests_total Counter of DNS requests made per zone, protocol and family. # TYPE coredns_dns_requests_total counter coredns_dns_requests_total{family="1",proto="udp",server="dns://0.0.0.0:53",type="A",view="",zone="."} 1 coredns_dns_requests_total{family="1",proto="udp",server="dns://0.0.0.0:53",type="A",view="",zone="cluster.local."} 6 coredns_dns_requests_total{family="1",proto="udp",server="dns://0.0.0.0:53",type="AAAA",view="",zone="."} 1 coredns_dns_requests_total{family="1",proto="udp",server="dns://0.0.0.0:53",type="AAAA",view="",zone="cluster.local."} 2 coredns_dns_requests_total{family="1",proto="udp",server="dns://0.0.0.0:53",type="other",view="",zone="."} 1 coredns_dns_requests_total{family="1",proto="udp",server="dns://0.0.0.0:53",type="other",view="",zone="cluster.local."} 1 coredns_dns_requests_total{family="1",proto="udp",server="dns://0.0.0.0:53",type="other",view="",zone="in-addr.arpa."} 1 coredns_dns_requests_total{family="1",proto="udp",server="dns://0.0.0.0:53",type="other",view="",zone="ip6.arpa."} 1 ``` If the tests don't show the expected metrics increase, there may be an error in your configuration. #### Troubleshoot issues and inspect logs * Check that the local redirect policy is enabled in the Cilium configuration: ```bash kubectl get configmap cilium-config -n kube-system -o yaml | grep redirect ``` The expected result is: ```bash enable-local-redirect-policy: "true" ``` * Check that the `node-local-dns` local redirect policy declared [earlier](https://docs.nebius.com/kubernetes/networking/nodelocal-dns-cache.md#prepare-manifests-for-nodelocal-dnscache-and-local-redirect-policy) is properly applied: ```bash kubectl get ciliumlocalredirectpolicies -A ``` The expected result is something like the following: ```bash NAMESPACE NAME AGE kube-system node-local-dns 3h18m ``` * Check the local redirect policy rules on any of the Cilium Pods: * Get the list of Cilium Pods: ```bash kubectl -n kube-system get pod | grep '^cilium-[^o]' ``` * Get the local redirect policy rules on one of these Pods: ```bash kubectl exec -it -n kube-system -- cilium-dbg lrp list ``` The expected result is something like the following: ```bash LRP namespace LRP name FrontendType Matching Service kube-system nodelocaldns clusterIP + named ports kube-system/coredns | coredns_IP_address:53/UDP -> 10.57.43.185:53(kube-system/node-local-dns-2cdjt), | coredns_IP_address:53/TCP -> 10.57.43.185:53(kube-system/node-local-dns-2cdjt), ``` * Check the contents of the `resolv.conf` file in the `dnsutils` Pod: ```bash kubectl exec -ti dnsutils -- cat /etc/resolv.conf ``` The expected result is something like the following: ```bash search default.svc.cluster.local svc.cluster.local cluster.local nameserver coredns_IP_address options ndots:5 ``` * Check DNS logs. To enable logs for Pods running DNS services, create a custom ConfigMap `coredns-custom.yaml` that contains a `log.override` key: ```yaml apiVersion: v1 kind: ConfigMap metadata: name: coredns-custom namespace: kube-system data: log.override: | log ``` Apply the custom ConfigMap: ```bash kubectl apply -f coredns-custom.yaml ``` To enable logs for the `node-local-dns` service, edit the ConfigMap: ```bash kubectl -n kube-system edit configmap node-local-dns ``` Add the `log` config parameter within the `Corefile` section: ```bash .:53 { log errors ``` Now you can get the logs of the Pods running DNS services: ```bash kubectl logs --namespace=kube-system -l k8s-app=coredns -f kubectl logs --namespace=kube-system -l k8s-app=node-local-dns -f ``` #### Delete testing resources Delete the `dnsutils` Pod: ```bash kubectl delete -f dnsutils.yaml ``` ## How to disable NodeLocal DNSCache If you no longer want to use NodeLocal DNSCache in your cluster, you can disable it: 1. Delete the local redirect policy: ```bash kubectl delete -f node-local-dns-lrp.yaml ``` 2. Delete the resources you created for NodeLocal DNSCache: ```bash kubectl delete -f node-local-dns.yaml ``` ## How to delete the created resources\\ The Managed Kubernetes cluster you used in this tutorial is chargeable. If you do not need it, [delete this resource](https://docs.nebius.com/kubernetes/clusters/manage.md#how-to-delete-clusters), so Nebius AI Cloud does not charge for it. # Pulling images from Container Registry for workloads in Managed Service for Kubernetes® clusters Source: https://docs.nebius.com/kubernetes/workloads/images-container-registry.md If a node group in a Managed Service for Kubernetes cluster has a [service account](https://docs.nebius.com/iam/overview.md#accounts-and-members) added to it, Pods hosted by the group's nodes can pull images from Container Registry without additional authentication. We recommend using the service account from the same [project](https://docs.nebius.com/iam/overview.md#projects) as the node group. To set up pulling images without authentication: 1. Make sure that you, or the service account that you use on your behalf, is in a [group](https://docs.nebius.com/iam/authorization/groups/index.md) that has the `admin` role within your tenant; for example, the default `admins` group. You can check this in the [Administration → IAM](https://console.nebius.com/iam) section of the web console. 2. In your Managed Kubernetes cluster, [create or modify a node group](https://docs.nebius.com/kubernetes/node-groups/manage.md) so that a service account from a group with at least the `viewer` role is added to it. A service account for node groups that your project came with, `k8s-node-group-sa`, is in the default `viewers` group. Currently, it is not possible to create a node group with a service account using the web console. For example: The commands below assume that the Nebius AI Cloud CLI is configured as described in its [documentation](https://docs.nebius.com/cli/configure.md), including adding the [project](https://docs.nebius.com/iam/overview.md#projects) ID in the CLI profile's `parent-id`, and that the Managed Kubernetes cluster ID is stored in the `MK8S_CLUSTER_ID` environment variable. ```bash export MK8S_SA_ID=$( nebius iam service-account get-by-name \ --name k8s-node-group-sa --format json \ | jq -r '.metadata.id' ) nebius mk8s node-group create \ --parent-id $MK8S_CLUSTER_ID \ --name node-group-example \ --fixed-node-count 2 \ --template-service-account-id $MK8S_SA_ID \ --template-resources-platform cpu-e2 \ --template-resources-preset 2vcpu-8gb ``` For details about nebius mk8s node-group create, see the [CLI reference](https://docs.nebius.com/cli/reference/mk8s/node-group/create). The configuration below assumes that the [project](https://docs.nebius.com/iam/overview.md#projects) ID and Managed Kubernetes cluster ID are stored in the `project_id` and `mk8s_cluster_id` [Terraform input variables](https://developer.hashicorp.com/terraform/language/values/variables), respectively. ```hcl data "nebius_iam_v1_service_account" "k8s_node_group" { parent_id = var.project_id name = "k8s-node-group-sa" } resource "nebius_mk8s_v1_node_group" "example" { parent_id = var.mk8s_cluster_id name = "node-group-example" fixed_node_count = 2 template = { service_account_id = data.nebius_iam_v1_service_account.k8s_node_group.id resources = { platform = "cpu-e2" preset = "2vcpu-8gb" } } } ``` For details about the nebius\_mk8s\_v1\_node\_group Terraform resource, see the [provider reference](https://docs.nebius.com/terraform-provider/reference/resources/mk8s_v1_node_group). After setting up node groups, you can just refer to Container Registry images in your manifests (for Pods or other resources that manage Pods, such as deployments) without providing credentials to pull them. > For example, if your nginx image is at cr.eu-north1.nebius.cloud/\/nginx:mynginx (you can get the registry ID in the web console or with the [nebius registry list](https://docs.nebius.com/cli/reference/registry/list)) CLI command), here is how to refer to it in a deployment manifest: > > ```yaml > apiVersion: apps/v1 > kind: Deployment > metadata: > name: nginx-deployment > spec: > replicas: 1 > selector: > matchLabels: > app: nginx > template: > metadata: > labels: > app: nginx > spec: > containers: > - name: nginx > image: cr.eu-north1.nebius.cloud//nginx:mynginx > ports: > - containerPort: 80 > ``` # Working with GPUs in the Managed Service for Kubernetes® Source: https://docs.nebius.com/kubernetes/gpu/set-up.md To run ML, AI and high-performance computing (HPC) workloads in your Managed Service for Kubernetes cluster, you need to add nodes with GPUs to it. Managed Kubernetes nodes are Compute virtual machines, and you can choose VMs with GPUs to serve as nodes in your clusters. In this article, you will learn how to set up GPUs in a Managed Kubernetes cluster. The article also touches on interconnecting GPUs using InfiniBand™ to accelerate your workloads; this topic is covered in detail in [another article](https://docs.nebius.com/kubernetes/gpu/clusters.md). ## How to add nodes with GPUs to a cluster When [creating a node group](https://docs.nebius.com/kubernetes/node-groups/manage.md) in a Managed Service for Kubernetes cluster, specify a virtual machine platform that supports GPUs: In the node group creation form ( **Compute** → **Kubernetes** → your cluster → **Node groups** → **Create node group**), under **Computing resources**: 1. Select **With GPU**. 2. Select a platform and a preset. For available platforms and presets, see [Types of virtual machines and GPUs in Nebius AI Cloud](https://docs.nebius.com/compute/virtual-machines/types.md) and [How to find out platforms and presets available in a project](https://docs.nebius.com/compute/virtual-machines/list-platforms.md). 3. Under **GPU settings**, keep the **Install NVIDIA GPU drivers and other components** option enabled. 4. Under **Drivers**, select a CUDA driver version. For available driver versions, see [GPU drivers and other components](https://docs.nebius.com/kubernetes/gpu/set-up.md#gpu-drivers-and-other-components). 5. Under **Operating system**, select an OS. Available operating systems depend on the selected driver. If you need to modify the NVIDIA device plug-in (for example, to enable multi-instance GPU), disable the **Install NVIDIA GPU drivers and other components** option. Then, [manually install the GPU operator](https://docs.nebius.com/kubernetes/gpu/set-up.md#how-to-install-the-drivers-and-components-on-existing-node-groups). Add GPU parameters to the [nebius mk8s node-group create](https://docs.nebius.com/cli/reference/mk8s/node-group/create) command: ```bash nebius mk8s node-group create \ --template-resources-platform gpu-h100-sxm \ --template-resources-preset 8gpu-128vcpu-1600gb \ --template-gpu-settings-drivers-preset cuda13.0 \ ... ``` * In `--template-resources-platform`, specify a platform with GPUs. In `--template-resources-preset`, specify a compatible preset (number of GPUs and vCPUs, RAM size). For available platforms and presets, see [Types of virtual machines and GPUs in Nebius AI Cloud](https://docs.nebius.com/compute/virtual-machines/types.md) and [How to find out platforms and presets available in a project](https://docs.nebius.com/compute/virtual-machines/list-platforms.md). * In `--template-gpu-settings-drivers-preset`, specify a supported preset to use a boot disk image that contains drivers and other components for GPUs. For more details, see [GPU drivers and other components](https://docs.nebius.com/kubernetes/gpu/set-up.md#gpu-drivers-and-other-components). If you want to [install the drivers manually](https://docs.nebius.com/kubernetes/gpu/set-up.md#drivers-install), omit the `--template-gpu-settings-drivers-preset` parameter. If you need to modify the NVIDIA device plug-in (for example, to enable multi-instance GPU), omit the `--template-gpu-settings-drivers-preset` parameter. Then, [manually install the GPU operator](https://docs.nebius.com/kubernetes/gpu/set-up.md#how-to-install-the-drivers-and-components-on-existing-node-groups). See an [example](https://docs.nebius.com/kubernetes/node-groups/manage.md#examples) of a full specification and CLI command. To enable InfiniBand interconnect between the nodes with GPUs, specify a GPU cluster when creating the node group. For more details, see [Interconnecting GPUs in Managed Service for Kubernetes® clusters using InfiniBand™](https://docs.nebius.com/kubernetes/gpu/clusters.md). You cannot change the VM platform and preset or the GPU cluster of an existing node group. Create a new node group instead. ## GPU drivers and other components For node groups with GPUs, Managed Kubernetes offers boot disk images with GPU drivers and other components required for GPUs. You can specify Managed Kubernetes GPU images with `--template-gpu-settings-drivers-preset`. The preset determines the CUDA toolkit and NVIDIA driver series. Each preset has a default operating system (OS), you can optionally override it with `--template-os`. | Driver preset | `cuda12.8` | `cuda13.0` | | ----------------------------- | ------------- | ------------- | | NVIDIA Data Center GPU Driver | 570.x | 580.x | | OS | `ubuntu24.04` | `ubuntu24.04` | If your cluster's control plane is on Kubernetes 1.30 (deprecated), use `cuda12` instead of `cuda12.8` (Ubuntu 24.04). Kubernetes 1.31 and later support `cuda12.8`, so there is no need to use `cuda12` on these versions. To confirm which `drivers_preset` and `os` values are supported for your platform and Kubernetes version, check the compatibility matrix: ```bash nebius mk8s node-group get-compatibility-matrix \ --cluster-kubernetes-version 1.34 \ --platform gpu-h200-sxm ``` Example output: ```yaml versions: - items: - compatible_platforms: - gpu-h200-sxm os: ubuntu24.04 - compatible_platforms: - gpu-h200-sxm drivers_preset: cuda12.8 os: ubuntu24.04 - compatible_platforms: - gpu-h200-sxm drivers_preset: cuda12 os: ubuntu24.04 - compatible_platforms: - gpu-h200-sxm drivers_preset: cuda13.0 os: ubuntu24.04 kubernetes_version: "1.34" ``` Use the returned `drivers_preset` and `os` values to select the driver branch and, optionally, an operating system (OS) in a node group configuration. For instructions on how to specify these parameters when creating a node group, see [How to add nodes with GPUs to a cluster](https://docs.nebius.com/kubernetes/gpu/set-up.md#how-to-add-nodes-with-gpus-to-a-cluster). ### How to change the driver preset To change the driver preset for an existing node group, run: ```bash nebius mk8s node-group update \ --id \ --template-gpu-settings-drivers-preset ``` When you change the driver preset, Managed Kubernetes recreates all nodes in the group according to the group's [deployment strategy](https://docs.nebius.com/kubernetes/node-groups/manage.md#node-group-parameters). ### How to install the drivers and components on existing node groups You can create a node group without the boot disk image. For example, you may opt not use the **Install NVIDIA GPU drivers and other components** option when you create the node group in the web console. In this case, you can choose one of the following options to install the drivers and components: * **Create a new node group with the image and migrate your workloads to it** (recommended) For instructions, see [Moving workload from the existing node group](https://docs.nebius.com/kubernetes/node-groups/moving-workload.md). * **Modify the node group to use the image** When you modify a node group, Managed Kubernetes recreates each node according to the group's [deployment strategy](https://docs.nebius.com/kubernetes/node-groups/manage.md#node-group-parameters). Run the [nebius mk8s node-group update](https://docs.nebius.com/cli/reference/mk8s/node-group/update) command: ```bash nebius mk8s node-group update \ --id \ --template-gpu-settings-drivers-preset cuda13.0 ``` * **Manually install NVIDIA operators** You can install Kubernetes operators from NVIDIA that manage components required for GPUs and their networking: * **NVIDIA Network Operator** Installing NVIDIA Network Operator is required when at least one node group in the cluster does not use the boot disk image offered by Managed Kubernetes and satisfies any of the following conditions: * The node group uses NVIDIA B200 GPUs. * The node group is added to a GPU cluster for [InfiniBand interconnection](https://docs.nebius.com/kubernetes/gpu/clusters.md). In all other cases, NVIDIA Network Operator is optional. * **NVIDIA GPU Operator** Any cluster with at least one node group that has GPUs and does not use the boot disk image offered by Managed Kubernetes, must have NVIDIA GPU Operator installed. To install the operators, follow the instructions, depending on whether you enabled the InfiniBand interconnection: Install and check the operators in the exact order presented in these instructions. The operators depend on each other. 1. Prepare your environment: 1. Configure kubectl, the Kubernetes CLI, to work with your cluster: ```bash nebius mk8s cluster get-credentials \ --id --external ``` For more details, see [How to connect to Managed Service for Kubernetes® clusters using kubectl](https://docs.nebius.com/kubernetes/connect.md). 2. Install [Helm](https://helm.sh/docs/), the package manager for Kubernetes that we will use to install the operator: ```bash curl -fsSL -o get_helm.sh \ https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 chmod 700 get_helm.sh ./get_helm.sh ``` For more ways to install, see the [Helm documentation](https://helm.sh/docs/intro/install/). 2. Install the NVIDIA Network Operator from the Nebius AI Cloud chart repository: ```bash helm install network-operator \ oci://cr.eu-north1.nebius.cloud/marketplace/nebius/nvidia-network-operator/chart/network-operator \ --version 25.7.0 \ -n nvidia-network-operator --create-namespace \ --wait ``` 3. Verify that the NVIDIA Network Operator installed its components correctly. Get the `NICClusterPolicy` instance status: ```bash kubectl get nicclusterpolicy.mellanox.com nic-cluster-policy \ -n nvidia-network-operator -o json | jq -r '.status' ``` The output example is the following: ```json { "appliedStates": [ ... { "name": "state-OFED", "state": "ready" }, ... ], "state": "ready" } ``` While `state-OFED` is `notReady`, you can check the driver installation logs: ```bash kubectl logs -n nvidia-network-operator \ $(kubectl get pods -n nvidia-network-operator \ | grep mofed | head -1 | awk '{print $1}') ``` 4. Install the NVIDIA GPU Operator from the Nebius AI Cloud chart repository: ```bash For NVIDIA B300 GPUs helm install gpu-operator \ oci://cr.eu-north1.nebius.cloud/marketplace/nebius/nvidia-gpu-operator/chart/gpu-operator \ --version v25.10.0 \ --set driver.version=580.95.05 \ -n nvidia-gpu-operator \ --create-namespace \ --wait ``` ```bash For any other GPUs helm install gpu-operator \ oci://cr.eu-north1.nebius.cloud/marketplace/nebius/nvidia-gpu-operator/chart/gpu-operator \ --version v25.10.0 \ -n nvidia-gpu-operator \ --create-namespace \ --wait ``` [GPUDirect RDMA](https://docs.nvidia.com/datacenter/cloud-native/gpu-operator/latest/gpu-operator-rdma.html) is enabled by default and uses the recommended DMA-BUF Linux kernel module. For more command parameters, see the [NVIDIA GPU Operator documentation](https://docs.nvidia.com/datacenter/cloud-native/gpu-operator/latest/getting-started.html#common-chart-customization-options). 5. Verify that the GPU driver is installed correctly. Do not check the GPU driver until you install both operators. Get the last log line from each DaemonSet that installs the driver: ```bash for pod in $(kubectl get pods -n nvidia-gpu-operator \ | grep nvidia-driver-daemonset | awk '{print $1}'); do echo -e "$pod:\n\t$(kubectl logs -n nvidia-gpu-operator $pod --tail 1)"; done ``` If the last lines are `Done, now waiting for signal`, the driver should work correctly. 1. Prepare your environment: 1. Configure kubectl, the Kubernetes CLI, to work with your cluster: ```bash nebius mk8s cluster get-credentials \ --id --external ``` For more details, see [How to connect to Managed Service for Kubernetes® clusters using kubectl](https://docs.nebius.com/kubernetes/connect.md). 2. Install [Helm](https://helm.sh/docs/), the package manager for Kubernetes that we will use to install the operator: ```bash curl -fsSL -o get_helm.sh \ https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 chmod 700 get_helm.sh ./get_helm.sh ``` For more ways to install, see the [Helm documentation](https://helm.sh/docs/intro/install/). 2. Install the NVIDIA GPU Operator from the Nebius AI Cloud chart repository: ```bash For NVIDIA B300 GPUs helm install gpu-operator \ oci://cr.eu-north1.nebius.cloud/marketplace/nebius/nvidia-gpu-operator/chart/gpu-operator \ --version v25.10.0 \ --set driver.version=580.95.05 \ -n nvidia-gpu-operator --create-namespace \ --wait ``` ```bash For any other GPUs helm install gpu-operator \ oci://cr.eu-north1.nebius.cloud/marketplace/nebius/nvidia-gpu-operator/chart/gpu-operator \ --version v25.10.0 \ -n nvidia-gpu-operator --create-namespace \ --wait ``` For more options, see the [NVIDIA GPU Operator documentation](https://docs.nvidia.com/datacenter/cloud-native/gpu-operator/latest/getting-started.html#common-chart-customization-options). 3. Verify that the GPU driver is installed correctly. Get the last log line from each DaemonSet that installs the driver: ```bash for pod in $(kubectl get pods -n nvidia-gpu-operator \ | grep nvidia-driver-daemonset | awk '{print $1}'); do echo -e "$pod:\n\t$(kubectl logs -n nvidia-gpu-operator $pod --tail 1)"; done ``` If the last lines are `Done, now waiting for signal`, the driver should work correctly. ## Example: Using CUDA for vector addition To test CUDA support in the cluster with GPU nodes and drivers installed on them, you can run a small CUDA application, which adds two vectors together: 1. [Connect to the cluster using kubectl](https://docs.nebius.com/kubernetes/connect.md). 2. Follow instructions in the [NVIDIA GPU Operator documentation](https://docs.nvidia.com/datacenter/cloud-native/gpu-operator/latest/getting-started.html#cuda-vectoradd). ## See also * [Interconnecting GPUs in a Managed Kubernetes cluster using InfiniBand](https://docs.nebius.com/kubernetes/gpu/clusters.md) * [Tutorial: Running NCCL tests in a cluster with InfiniBand-connected GPUs](https://docs.nebius.com/kubernetes/gpu/nccl-test.md) * [Creating and modifying node groups](https://docs.nebius.com/kubernetes/node-groups/manage.md) *** *InfiniBand and InfiniBand Trade Association are registered trademarks of the InfiniBand Trade Association.* # Interconnecting GPUs in Managed Service for Kubernetes® clusters using InfiniBand™ Source: https://docs.nebius.com/kubernetes/gpu/clusters.md To accelerate ML, AI and high-performance computing (HPC) workloads that you run in your [Managed Service for Kubernetes clusters with GPUs](https://docs.nebius.com/kubernetes/gpu/set-up.md), you can interconnect the GPUs using [InfiniBand](https://www.infinibandta.org/about-infiniband/), a high-throughput, low-latency networking standard. For more details about InfiniBand in Nebius AI Cloud, see the [Compute documentation](https://docs.nebius.com/compute/clusters/gpu). In this article, you will learn how to set up InfiniBand in a Managed Kubernetes cluster. ## How to enable InfiniBand for a node group In the node group creation form ( **Compute** → **Kubernetes** → your cluster → **Node groups** → **Create node group**), under **Computing resources**: 1. Select **With GPU**. 2. Select a platform and a preset compatible with GPU clusters. The compatible platforms and presets: | Platform | Presets | [Regions](https://docs.nebius.com/overview/regions.md) | | ----------------------------------------------------------------------- | --------------------- | ------------------------------------------------------------------------------------------------------------------------ | | NVIDIA® B300 NVLink with Intel Granite Rapids
(`gpu-b300-sxm`) | `8gpu-192vcpu-2768gb` | `uk-south1`, `eu-west2`*\** | | NVIDIA® B200 NVLink with Intel Emerald Rapids
(`gpu-b200-sxm`) | `8gpu-160vcpu-1792gb` | `us-central1` | | NVIDIA® B200 NVLink with Intel Emerald Rapids
(`gpu-b200-sxm-a`) | `8gpu-160vcpu-1792gb` | `me-west1` | | NVIDIA® H200 NVLink with Intel Sapphire Rapids
(`gpu-h200-sxm`) | `8gpu-128vcpu-1600gb` | `eu-north1`, `eu-north2`*\**, `eu-west1`, `us-central1` | | NVIDIA® H100 NVLink with Intel Sapphire Rapids
(`gpu-h100-sxm`) | `8gpu-128vcpu-1600gb` | `eu-north1` | 3. Select a GPU cluster or create one. If the field is inactive, make sure you have selected a compatible platform and preset. 4. Under **GPU settings**, keep the **Install NVIDIA GPU drivers and other components** option enabled. If you want to [install the drivers manually](https://docs.nebius.com/kubernetes/gpu/set-up.md#how-to-install-the-drivers-and-components-on-existing-node-groups), disable this option.
1. Depending on your project's [region](https://docs.nebius.com/overview/regions.md), select an [InfiniBand fabric](https://docs.nebius.com/compute/clusters/gpu#infiniband-fabrics) and save it to an environment variable: ```bash export INFINIBAND_FABRIC= ``` 2. Create a GPU cluster and save its ID: ```bash export GPU_CLUSTER_ID=$(nebius compute gpu-cluster create \ --name gpu-cluster-name \ --infiniband-fabric $INFINIBAND_FABRIC \ --format json \ | jq -r ".metadata.id") ``` 3. [Create a node group](https://docs.nebius.com/kubernetes/node-groups/manage.md) with GPUs and specify the GPU cluster ID in its parameters by using the [nebius mk8s node-group create](https://docs.nebius.com/cli/reference/mk8s/node-group/create) command: ```bash nebius mk8s node-group create \ --template-resources-platform gpu-h100-sxm \ --template-resources-preset 8gpu-128vcpu-1600gb \ --template-gpu-cluster-id $GPU_CLUSTER_ID \ --template-gpu-settings-drivers-preset cuda13.0 \ ... ``` * In `--template.gpu-cluster-id`, specify the GPU cluster ID. * In `--template-resources-platform`, specify a platform with GPUs. In `--template-resources-preset`, specify a compatible preset (number of GPUs and vCPUs, RAM size). The compatible platforms and presets are: | Platform | Presets | [Regions](https://docs.nebius.com/overview/regions.md) | | ----------------------------------------------------------------------- | --------------------- | ------------------------------------------------------------------------------------------------------------------------ | | NVIDIA® B300 NVLink with Intel Granite Rapids
(`gpu-b300-sxm`) | `8gpu-192vcpu-2768gb` | `uk-south1`, `eu-west2`*\** | | NVIDIA® B200 NVLink with Intel Emerald Rapids
(`gpu-b200-sxm`) | `8gpu-160vcpu-1792gb` | `us-central1` | | NVIDIA® B200 NVLink with Intel Emerald Rapids
(`gpu-b200-sxm-a`) | `8gpu-160vcpu-1792gb` | `me-west1` | | NVIDIA® H200 NVLink with Intel Sapphire Rapids
(`gpu-h200-sxm`) | `8gpu-128vcpu-1600gb` | `eu-north1`, `eu-north2`*\**, `eu-west1`, `us-central1` | | NVIDIA® H100 NVLink with Intel Sapphire Rapids
(`gpu-h100-sxm`) | `8gpu-128vcpu-1600gb` | `eu-north1` | * In `--template-gpu-settings-drivers-preset`, specify a supported preset to use a boot disk image that contains drivers and other components for GPUs. For more details, see [GPU drivers and other components](https://docs.nebius.com/kubernetes/gpu/set-up.md#gpu-drivers-and-other-components). If you want to [install the drivers manually](https://docs.nebius.com/kubernetes/gpu/set-up.md#drivers-install), omit the `--template-gpu-settings-drivers-preset` parameter.
## Example: NCCL tests To test InfiniBand performance in a Managed Service for Kubernetes cluster, you can run the NVIDIA NCCL test in it. For instructions, see our [tutorial](https://docs.nebius.com/kubernetes/gpu/nccl-test.md). ## See also * [Working with GPUs in a Managed Kubernetes cluster](https://docs.nebius.com/kubernetes/gpu/set-up.md) * [Creating and modifying node groups](https://docs.nebius.com/kubernetes/node-groups/manage.md) *** *InfiniBand and InfiniBand Trade Association are registered trademarks of the InfiniBand Trade Association.* # Topology-aware scheduling for GPU workloads in Managed Service for Kubernetes® Source: https://docs.nebius.com/kubernetes/gpu/topology-aware-scheduling.md Modern AI/ML workloads depend heavily on high-throughput, low-latency communication between nodes. In GPU clusters connected via InfiniBand™, the physical network topology has a direct impact on performance. Topology-aware scheduling (TAS) enables Kubernetes schedulers to optimize workload placement based on how nodes are physically connected within the InfiniBand fabric. With this feature, Nebius AI Cloud exposes InfiniBand topology information as *node labels*, allowing schedulers to place workloads on nodes that are closer in the network hierarchy. This can improve communication efficiency and provide performance gains for distributed workloads. For more information about Kubernetes scheduling, see the [Kubernetes scheduler documentation](https://kubernetes.io/docs/concepts/scheduling-eviction/kube-scheduler/). ## Prerequisites 1. [Create a Managed Service for Kubernetes cluster](https://docs.nebius.com/kubernetes/clusters/manage.md) and [attach at least one GPU node group](https://docs.nebius.com/kubernetes/node-groups/manage.md) to it. 2. [Install kubectl](https://kubernetes.io/docs/tasks/tools/#kubectl). 3. [Connect to the cluster by using kubectl](https://docs.nebius.com/kubernetes/connect.md). ## How to view topology labels in your cluster View the topology labels on GPU nodes with the following command: ```bash kubectl get nodes -L topology.nebius.com/gpu-cluster-id,topology.nebius.com/tier-2,topology.nebius.com/tier-1,kubernetes.io/hostname ``` The following labels can be present on GPU nodes: | Label | Description | | ------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `topology.nebius.com/gpu-cluster-id` | Identifies a connected high-speed network domain. Nodes with the same value have high-speed network connectivity between each other. | | `topology.nebius.com/tier-0` | The closest topology level. For example, this can represent a direct accelerator interconnect, such as multi-node NVLink between NVIDIA GPUs. This label is set only for nodes that support this type of communication. | | `topology.nebius.com/tier-1` | A lower-level network locality domain. For example, this can represent rack-level switches that connect nodes in one or more racks into a single block. | | `topology.nebius.com/tier-2` | A wider network locality domain. For example, this can represent spine-level switches that connect multiple blocks inside a data center. | The lower the tier level shared by two nodes, the better the expected communication performance between them. For example, two nodes with the same `topology.nebius.com/tier-1` value are expected to be closer to each other than two nodes that only share the same `topology.nebius.com/tier-2` value. ### Example output ```text NAME STATUS ROLES AGE VERSION GPU-CLUSTER-ID TIER-2 TIER-1 HOSTNAME computeinstance-e00f4wsk77x4vsr58s Ready 144d v1.32.9 computegpucluster-e00agxzkvne8558nv8 959d125cbd887219574193fdba27b2c8 282cfcbf8e735653e4ce9884052cb523 computeinstance-e00f4wsk77x4vsr58s computeinstance-e00nm33x3y9597zzxj Ready 54d v1.32.9 computeinstance-e00nm33x3y9597zzxj computeinstance-e00tw5jypq4zvfrsrx Ready 77d v1.32.9 computegpucluster-e00z7ftxx6dacdbra5 5ca19afc3d62844695b08033aeba635b 297bbb6a0db40d875c266b589dc95f5b computeinstance-e00tw5jypq4zvfrsrx computeinstance-e00v7g42bam61yqzp3 Ready 144d v1.32.9 computegpucluster-e00agxzkvne8558nv8 959d125cbd887219574193fdba27b2c8 04011d5d2b17ec74672df94efbbeeb15 computeinstance-e00v7g42bam61yqzp3 ``` Nodes that share the same value for a label belong to the same *topology domain* at that level. A topology domain is a group of nodes that are physically close to each other in the network hierarchy and are therefore expected to have faster communication between them. For example, in the sample output: * `computeinstance-e00f4wsk77x4vsr58s` and `computeinstance-e00v7g42bam61yqzp3` share the same `GPU-CLUSTER-ID` and `TIER-2` values, which means they belong to the same high-speed network domain and the same wider network locality domain. These nodes have different `TIER-1` values, which indicates that they belong to different lower-level locality domains. * `computeinstance-e00tw5jypq4zvfrsrx` belongs to a different GPU cluster and topology hierarchy because all of its topology label values are different. * `computeinstance-e00nm33x3y9597zzxj` does not have topology labels. This usually means that the node is not attached to a GPU cluster, or TAS is not enabled. The exact physical meaning of each tier depends on the infrastructure configuration and is not guaranteed to match these examples. ## How to enable topology-aware scheduling [Kueue](https://kueue.sigs.k8s.io/docs/concepts/topology_aware_scheduling/) is used below as an example scheduler. You can also use other schedulers that support TAS, such as [Volcano](https://volcano.sh/en/docs/network_topology_aware_scheduling/). ### Steps #### Install and configure Kueue 1. [Install Kueue](https://kueue.sigs.k8s.io/docs/getting-started/installation/#install-a-released-version). 2. Enable TAS: ```bash kubectl -n kueue-system patch deployment kueue-controller-manager \ --type json \ -p='[{"op": "add", "path": "/spec/template/spec/containers/0/args/-", "value": "--feature-gates=TopologyAwareScheduling=true"}]' ``` 3. Create a file named `kueue-tas.yaml` to configure the Kueue resources: ```yaml apiVersion: kueue.x-k8s.io/v1beta2 kind: Topology metadata: name: ib-topology spec: levels: - nodeLabel: "topology.nebius.com/gpu-cluster-id" - nodeLabel: "topology.nebius.com/tier-2" - nodeLabel: "topology.nebius.com/tier-1" - nodeLabel: "kubernetes.io/hostname" --- apiVersion: kueue.x-k8s.io/v1beta2 kind: ResourceFlavor metadata: name: gpu-flavor-tas spec: nodeLabels: nebius.com/node-group-id: "" topologyName: "ib-topology" tolerations: - key: "nvidia.com/gpu" operator: "Exists" effect: "NoSchedule" --- apiVersion: kueue.x-k8s.io/v1beta2 kind: ClusterQueue metadata: name: gpu-cluster-queue-tas spec: namespaceSelector: {} resourceGroups: - coveredResources: ["cpu", "memory", "nvidia.com/gpu"] flavors: - name: "gpu-flavor-tas" resources: - name: "cpu" nominalQuota: 100 - name: "memory" nominalQuota: "100Gi" - name: "nvidia.com/gpu" nominalQuota: "16" --- apiVersion: kueue.x-k8s.io/v1beta2 kind: LocalQueue metadata: name: gpu-user-queue-tas namespace: default spec: clusterQueue: gpu-cluster-queue-tas ``` To get the ``, open your Kubernetes cluster in the web console, go to the **Node groups** tab and copy the node group ID. 4. Apply the configuration: ```bash kubectl apply -f kueue-tas.yaml ``` 5. Check that the Kueue resources were created: ```bash kubectl get topology,resourceflavor,clusterqueue,localqueue ``` #### Schedule workloads with TAS using Kueue To request TAS, add a topology annotation to the Pod template of your workload. 1. Create a file named `job-tas.yaml` that requests TAS for the workload: ```yaml apiVersion: batch/v1 kind: Job metadata: name: job-tas namespace: default labels: kueue.x-k8s.io/queue-name: gpu-user-queue-tas spec: parallelism: completions: completionMode: Indexed template: metadata: annotations: spec: containers: - name: dummy-job image: registry.k8s.io/e2e-test-images/agnhost:2.53 args: ["pause"] resources: requests: cpu: "100m" memory: "100Mi" nvidia.com/gpu: 8 limits: nvidia.com/gpu: 8 restartPolicy: Never ``` Replace the following variables: * ``: Number of Pods that are running in parallel. * ``: Requested topology constraint. See the following table for available values: | Scenario | Description | Value of `` | | ----------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------- | | Required to run within a GPU cluster | Kueue admits the workload only if enough resources are available within the same GPU cluster. Otherwise, the workload remains pending until resources become available or the topology constraint changes. | `kueue.x-k8s.io/podset-required-topology: "topology.nebius.com/gpu-cluster-id"` | | Required to run within a topology domain | Kueue admits the workload only if enough resources are available within the same topology domain. Otherwise, the workload remains pending until resources become available or the topology constraint changes. | `kueue.x-k8s.io/podset-required-topology: "topology.nebius.com/tier-2"` | | Preferred to run within a topology domain | Kueue tries to schedule Pods within the same topology domain. If this is not possible, Kueue can place Pods across multiple topology domains. | `kueue.x-k8s.io/podset-preferred-topology: "topology.nebius.com/tier-2"` | In Kueue, a *podset* represents a group of Pods belonging to the same workload (for example, replicas of a Job). 2. Create the Job: ```bash kubectl apply -f job-tas.yaml ``` 3. Check admission status: ```bash kubectl get workloads -A kubectl describe workload -n ``` If Kueue does not admit the workload, reduce parallelism, use less restrictive topology constraints or increase available GPU capacity. *** *InfiniBand and InfiniBand Trade Association are registered trademarks of the InfiniBand Trade Association.* # Running NCCL tests in a Managed Service for Kubernetes® cluster with InfiniBand™-connected GPUs Source: https://docs.nebius.com/kubernetes/gpu/nccl-test.md To boost performance of the high-performance computing (HPC) and AI workloads that you run in a Managed Service for Kubernetes cluster, you can set it up so that the GPUs on its nodes are interconnected directly using InfiniBand. In this tutorial, you will create a Managed Service for Kubernetes cluster with GPUs interconnected using InfiniBand, install operators and drivers from NVIDIA on it, and run NVIDIA NCCL tests to check InfiniBand performance. ## Costs The tutorial includes the following chargeable resources: * [Compute virtual machines with GPUs](https://docs.nebius.com/compute/resources/pricing.md) * [Managed Service for Kubernetes cluster](https://docs.nebius.com/kubernetes/resources/pricing.md) ## Prerequisites 1. [Install and configure](https://docs.nebius.com/cli/install.md) the Nebius AI Cloud CLI. 2. Save IDs of the default subnet and the `k8s-node-group-sa` default service account to environment variables: ```bash export SUBNET_ID=$(nebius vpc subnet list --format json \ | jq -r '.items[0].metadata.id') export SA_ID=$(nebius iam service-account get-by-name \ --name k8s-node-group-sa --format json \ | jq -r '.metadata.id') ``` 3. [Install kubectl](https://kubernetes.io/docs/tasks/tools/#kubectl) and [Helm](https://helm.sh/docs/intro/install/). ## Steps ### Set up a Managed Service for Kubernetes cluster with GPUs and InfiniBand 1. Create a GPU cluster: ```bash export GPU_CLUSTER_ID=$(nebius compute gpu-cluster create \ --name k8s-gpus --infiniband-fabric fabric-3 \ --format json | jq -r ".metadata.id") ``` 2. Create a Managed Service for Kubernetes cluster with a public endpoint: ```bash export MK8S_CLUSTER_ID=$(nebius mk8s cluster create \ --name nccl \ --control-plane-version 1.34 \ --control-plane-endpoints-public-endpoint=true \ --control-plane-subnet-id $SUBNET_ID \ --format json | jq -r '.metadata.id') ``` 3. Create a node group in the cluster: ```bash nebius mk8s node-group create \ --name nccl-gpu-nodes \ --parent-id $MK8S_CLUSTER_ID \ --fixed-node-count 2 \ --template-service-account-id $SA_ID \ --template-resources-platform "gpu-h100-sxm" \ --template-resources-preset "8gpu-128vcpu-1600gb" \ --template-boot-disk-type network_ssd \ --template-boot-disk-size-bytes 137438953472 \ --template-gpu-settings-drivers-preset cuda13.0 \ --template-gpu-cluster-id $GPU_CLUSTER_ID ``` For this tutorial, it is required that: * The node group has the GPU cluster specified. * The node group includes at least two nodes. * The nodes use a [VM platform and preset](https://docs.nebius.com/compute/virtual-machines/types.md) compatible with GPU clusters: | Platform | Presets | [Regions](https://docs.nebius.com/overview/regions.md) | | ----------------------------------------------------------------------- | --------------------- | ------------------------------------------------------------------------------------------------------------------------ | | NVIDIA® B300 NVLink with Intel Granite Rapids
(`gpu-b300-sxm`) | `8gpu-192vcpu-2768gb` | `uk-south1`, `eu-west2`*\** | | NVIDIA® B200 NVLink with Intel Emerald Rapids
(`gpu-b200-sxm`) | `8gpu-160vcpu-1792gb` | `us-central1` | | NVIDIA® B200 NVLink with Intel Emerald Rapids
(`gpu-b200-sxm-a`) | `8gpu-160vcpu-1792gb` | `me-west1` | | NVIDIA® H200 NVLink with Intel Sapphire Rapids
(`gpu-h200-sxm`) | `8gpu-128vcpu-1600gb` | `eu-north1`, `eu-north2`*\**, `eu-west1`, `us-central1` | | NVIDIA® H100 NVLink with Intel Sapphire Rapids
(`gpu-h100-sxm`) | `8gpu-128vcpu-1600gb` | `eu-north1` | In this command, the nodes use the gpu-h100-sxm VM platform with the `8gpu-128vcpu-1600gb` preset. * The nodes use a boot disk image offered by Managed Kubernetes that contains drivers and other components for GPUs. Without this image, you need to install the drivers and components manually. For more details, see [GPU drivers and other components](https://docs.nebius.com/kubernetes/gpu/set-up.md#gpu-drivers-and-other-components). 4. Generate a kubeconfig file with the cluster details for kubectl: ```bash nebius mk8s cluster get-credentials \ --id $MK8S_CLUSTER_ID --external ``` To verify that kubectl is connected to the cluster, you can run `kubectl cluster-info`. ### Run the NCCL tests 1. Install the [Kubeflow Training Operator](https://www.kubeflow.org/docs/components/trainer/legacy-v1/overview/) (also known as Kubeflow Trainer). ```bash kubectl apply --server-side -k "github.com/kubeflow/training-operator/manifests/overlays/standalone?ref=v1.9.3" ``` 2. Create a namespace for the tests, named `nccl-test` in this tutorial: ``` kubectl create ns nccl-test ``` 3. Create `nccl-test.yaml` with an `MPIJob` for your tests. This example is for 2 nodes. If you [created a node group](https://docs.nebius.com/kubernetes/gpu/nccl-test.md#set-up-a-managed-service-for-kubernetes-cluster-with-gpus-and-infiniband) with a different number of nodes, change accordingly the `mpirun` command in `.spec.mpiReplicaSpecs.Launcher.template.spec.containers[0].args` and the number of workers in `.spec.mpiReplicaSpecs.Worker.replicas`. ```yaml apiVersion: kubeflow.org/v1 kind: MPIJob metadata: name: nccl-test-nebius spec: slotsPerWorker: 8 # Number of GPUs on each node mpiReplicaSpecs: Launcher: replicas: 1 template: spec: containers: - args: # In `-np 16`, 16 is the total number of GPUs on all nodes # (`.spec.slotsPerWorker` × `.spec.mpiReplicaSpecs.Worker.replicas`) - 'mpirun -np 16 -bind-to none -x LD_LIBRARY_PATH -x NCCL_DEBUG=INFO -x NCCL_SOCKET_IFNAME=eth0 -mca coll ^hcoll -x UCX_NET_DEVICES=eth0 -x NCCL_IB_HCA=mlx5 -x SHARP_COLL_ENABLE_PCI_RELAXED_ORDERING=1 -x NCCL_COLLNET_ENABLE=0 /opt/nccl_tests/build/all_reduce_perf -b 512M -e 8G -f 2 -g 1' command: - /bin/bash - -c env: - name: OMPI_ALLOW_RUN_AS_ROOT value: "1" - name: OMPI_ALLOW_RUN_AS_ROOT_CONFIRM value: "1" image: cr.eu-north1.nebius.cloud/nebius-benchmarks/nccl-tests:2.26.5-ubu22.04-cu12.8 name: nccl resources: requests: cpu: 2 memory: 1208Mi securityContext: privileged: true initContainers: - command: - sh - -c - ulimit -Hl unlimited && ulimit -Sl unlimited image: busybox:1.27.2 name: init-limit securityContext: privileged: true Worker: replicas: 2 # Number of nodes template: spec: automountServiceAccountToken: false containers: - image: cr.eu-north1.nebius.cloud/nebius-benchmarks/nccl-tests:2.26.5-ubu22.04-cu12.8 name: nccl resources: # If you have other applications running in your cluster, # adjust the `cpu` and `memory` values according to # the resources available on the nodes limits: cpu: 96 memory: 1600G nvidia.com/gpu: 8 requests: cpu: 96 memory: 1600G nvidia.com/gpu: 8 securityContext: privileged: true volumeMounts: - mountPath: /dev/shm name: dshm enableServiceLinks: false initContainers: - command: - sh - -c - ulimit -Hl unlimited && ulimit -Sl unlimited image: busybox:1.27.2 name: init-limit securityContext: privileged: true volumes: - emptyDir: medium: Memory name: dshm runPolicy: cleanPodPolicy: Running ``` ```yaml apiVersion: kubeflow.org/v1 kind: MPIJob metadata: name: nccl-test-nebius spec: slotsPerWorker: 8 # Number of GPUs on each node mpiReplicaSpecs: Launcher: replicas: 1 template: spec: containers: - args: # In `-np 16`, 16 is the total number of GPUs on all nodes # (`.spec.slotsPerWorker` × `.spec.mpiReplicaSpecs.Worker.replicas`) - 'mpirun -np 16 -bind-to none -x LD_LIBRARY_PATH -x NCCL_DEBUG=INFO -x NCCL_SOCKET_IFNAME=eth0 -x NCCL_IB_HCA=mlx5 -x UCX_NET_DEVICES=eth0 -x SHARP_COLL_ENABLE_PCI_RELAXED_ORDERING=1 -x NCCL_COLLNET_ENABLE=0 /opt/nccl_tests/build/all_reduce_perf -b 512M -e 8G -f 2 -g 1' command: - /bin/bash - -c env: - name: OMPI_ALLOW_RUN_AS_ROOT value: "1" - name: OMPI_ALLOW_RUN_AS_ROOT_CONFIRM value: "1" image: cr.eu-north1.nebius.cloud/nebius-benchmarks/nccl-tests:2.23.4-ubu22.04-cu12.4 name: nccl resources: requests: cpu: 2 memory: 1208Mi securityContext: privileged: true initContainers: - command: - sh - -c - ulimit -Hl unlimited && ulimit -Sl unlimited image: busybox:1.27.2 name: init-limit securityContext: privileged: true Worker: replicas: 2 # Number of nodes template: spec: automountServiceAccountToken: false containers: - image: cr.eu-north1.nebius.cloud/nebius-benchmarks/nccl-tests:2.23.4-ubu22.04-cu12.4 name: nccl resources: # If you have other applications running in your cluster, # adjust the `cpu` and `memory` values according to # the resources available on the nodes limits: cpu: 96 memory: 1600G nvidia.com/gpu: 8 requests: cpu: 96 memory: 1600G nvidia.com/gpu: 8 securityContext: privileged: true volumeMounts: - mountPath: /dev/shm name: dshm enableServiceLinks: false initContainers: - command: - sh - -c - ulimit -Hl unlimited && ulimit -Sl unlimited image: busybox:1.27.2 name: init-limit securityContext: privileged: true volumes: - emptyDir: medium: Memory name: dshm runPolicy: cleanPodPolicy: Running ``` 4. Deploy the `MPIJob` in `nccl-test`: ```text kubectl apply -f nccl-test.yaml -n nccl-test ``` 5. Check that the test Pods are running: ```bash kubectl get pods -w -n nccl-test ``` Wait until all the Pods are running, like this: ```text NAME READY STATUS RESTARTS AGE nccl-test-nebius-launcher 1/1 Running 0 24s nccl-test-nebius-worker-0 1/1 Running 0 24s nccl-test-nebius-worker-1 1/1 Running 0 24s ``` 6. Check the test logs: ```bash kubectl logs -f nccl-test-nebius-launcher -n nccl-test \ | grep -v "NCCL INFO" ``` In the result, check the average bus bandwidth. If its value is higher than 300 GB/sec, the connection is stable. Example: ``` ... # out-of-place in-place # size count type redop root time algbw busbw #wrong time algbw busbw #wrong # (B) (elements) (us) (GB/s) (GB/s) (us) (GB/s) (GB/s) 536870912 134217728 float sum -1 3674.4 146.11 283.09 0 3648.4 147.15 285.11 0 1073741824 268435456 float sum -1 6411.6 167.47 324.47 0 6416.7 167.33 324.21 0 2147483648 536870912 float sum -1 12735 168.62 326.71 0 12979 165.45 320.57 0 4294967296 1073741824 float sum -1 25389 169.17 327.76 0 25598 167.79 325.09 0 8589934592 2147483648 float sum -1 50979 168.50 326.47 0 50799 169.10 327.63 0 # Out of bounds values : 0 OK # Avg bus bandwidth : 317.11 ``` The average bus bandwidth is not equal to the InfiniBand one as some of the NCCL operations it measures use NVLink. Nevertheless, it accurately estimates the connection. To stop streaming logs, press **Ctrl** + **C**. 7. Delete the `MPIJob`. ```text kubectl delete -f nccl-test.yaml -n nccl-test ``` You should delete the `MPIJob` even if you want to run another test. In this case, redeploy the `MPIJob` as described in steps 2–3. ## How to delete the created resources Some of the created resources are chargeable. If you do not need them, delete these resources, so Nebius AI Cloud does not charge for them: * Delete the installed operator: ```bash kubectl delete -k "github.com/kubeflow/training-operator/manifests/overlays/standalone?ref=v1.9.3" ``` * Delete the node group with GPUs: ```bash export MK8S_CLUSTER_ID=$(nebius mk8s cluster get-by-name \ --name nccl --format json | jq -r '.metadata.id') nebius mk8s node-group delete --id \ $(nebius mk8s node-group get-by-name \ --name nccl-gpu-nodes --parent-id $MK8S_CLUSTER_ID \ --format json | jq -r '.metadata.id') ``` * Delete the entire cluster: ```bash nebius mk8s cluster delete --id \ $(nebius mk8s cluster get-by-name \ --name nccl --format json | jq -r '.metadata.id') ``` *** *InfiniBand and InfiniBand Trade Association are registered trademarks of the InfiniBand Trade Association.* # Managing AI workloads across Managed Service for Kubernetes® clusters with SkyPilot Source: https://docs.nebius.com/kubernetes/skypilot.md You can use [SkyPilot](https://docs.skypilot.co/en/latest/docs/index.html) as a single, declarative job surface that runs your AI workloads across one or more [Managed Service for Kubernetes](https://docs.nebius.com/kubernetes) clusters. SkyPilot picks the best cluster for each job based on hardware availability and the constraints in the task definition, and ensures fault tolerance across clusters when capacity is tight in the preferred one. The SkyPilot placement logic combines constraint matching with policy: * With *capability match*, SkyPilot filters clusters by whether they meet the requested hardware and features, such as the GPU model, the number of GPUs per node, InfiniBand™ or a shared filesystem. * With *capacity chasing*, SkyPilot chases capacity across other clusters or regions when the preferred cluster has insufficient capacity. * With *failover and retries*, SkyPilot handles provisioning failures, such as preemptions or insufficient capacity, by automatically retrying with other matching clusters. ## Costs Nebius AI Cloud charges you for the following billing items: * [Managed SkyPilot API Server](https://docs.nebius.com/applications/standalone/pricing.md#standalone-applications) (standalone application) * [Managed Kubernetes nodes](https://docs.nebius.com/kubernetes/resources/pricing.md) ## Steps ### Install dependencies 1. Make sure you have Python 3.10 or higher [installed](https://www.python.org/downloads/). 2. Install SkyPilot with Kubernetes and Nebius support: ```bash pip3 install "skypilot[kubernetes,nebius]" ``` ### Prepare infrastructure 1. Deploy the Managed SkyPilot API Server: 1. In the Nebius AI Cloud console, go to  **AI orchestration** → **SkyPilot**. 2. Enter a name for the application or keep the default one. 3. Select a **Platform** and a **Preset** (vCPUs and RAM) for the API server virtual machine. 4. Click **Deploy application**. 2. Connect to the SkyPilot API server. On the application page in the web console, click **How to connect** and copy the `sky api login` command. Then run the command in your terminal: ```bash sky api login -e "https://.skypilot.gw.msp..nebius.cloud" ``` 3. Check that SkyPilot can reach your project: ```bash sky check kubernetes ``` At this stage, no Managed Kubernetes clusters have been added yet, so the output looks similar to the following: ```text Checking credentials to enable infra for SkyPilot. Kubernetes: disabled Reason [compute]: No available context found in kubeconfig. 🎉 Enabled infra 🎉 No infra to check/enabled. ``` You will run the same command again later to confirm that the contexts are picked up. 4. [Create](https://docs.nebius.com/kubernetes/clusters/manage.md) at least one Managed Kubernetes cluster with a GPU node group. To demonstrate cross-cluster fault tolerance, create two or more clusters. For more information about how to install SkyPilot and connect to it, see [Managing AI workloads on Compute virtual machines with SkyPilot](https://docs.nebius.com/3p-integrations/skypilot.md). ### Add Managed Kubernetes clusters to SkyPilot The Managed SkyPilot API Server auto-discovers all Managed Kubernetes clusters in the same project. You don't need to add a local kubeconfig or configure a service account. 1. Open the SkyPilot dashboard. On the application page in the web console, click **How to connect** and then click on the public endpoint URL. 2. On the dashboard, go to the **Infra** tab and click **Refresh**. The dashboard lists the Managed Kubernetes clusters available to SkyPilot. 3. Verify that SkyPilot can access the clusters: ```bash sky check kubernetes ``` The output lists the enabled contexts: ```text Kubernetes: enabled [compute] Allowed contexts: ├── : enabled. └── : enabled. 🎉 Enabled infra 🎉 Kubernetes [compute] Allowed contexts: ├── └── ``` 4. (Optional) For detailed per-cluster and per-node GPU availability, run: ```bash sky show-gpus ``` The output shows the available GPUs and per-node availability: ```text GPU REQUESTABLE_QTY_PER_NODE UTILIZATION H100 1, 2, 4, 8 24 of 24 free Kubernetes per-node GPU availability CONTEXT NODE vCPU Memory (GB) GPU GPU UTILIZATION NODE STATUS computeinstance- - - H100 8 of 8 free Healthy computeinstance- - - H100 8 of 8 free Healthy ``` ### (Optional) Limit clusters that SkyPilot uses By default, SkyPilot can place jobs on any Managed Kubernetes cluster it discovers. To restrict SkyPilot to a subset of clusters for every user of this Managed SkyPilot API Server, set `kubernetes.allowed_contexts` in the dashboard: 1. In the SkyPilot dashboard, click **Configuration**. 2. In the **Edit SkyPilot API Server Configuration** textbox, paste the following YAML, listing the contexts in the order in which SkyPilot should evaluate them: ```yaml kubernetes: allowed_contexts: - - ``` 3. Click **Apply**. To verify which contexts are enabled, run `sky check kubernetes` again. ### Run a job Decide how SkyPilot should choose the target Managed Kubernetes cluster: * **To let SkyPilot fail over across clusters**, run `sky launch` without specifying a cluster: ```bash sky launch --gpus H100 --infra k8s echo 'Hello World' ``` SkyPilot picks the first context that satisfies the request and submits the job: ```text Considered resources (1 node): ---------------------------------------------------------------------------------------------------- INFRA INSTANCE vCPUs Mem(GB) GPUS COST ($) CHOSEN ---------------------------------------------------------------------------------------------------- Kubernetes () - 4 16 H100:1 0.00 ✔ ---------------------------------------------------------------------------------------------------- Launching a new cluster 'sky-...'. Proceed? [Y/n]: y ``` * **To target a specific Managed Kubernetes cluster**, set `--infra k8s/`: ```bash sky launch --gpus H100 --infra k8s/ echo 'Hello World' ``` If the targeted cluster does not have the requested resources, SkyPilot returns an error: ```text sky.exceptions.ResourcesUnavailableError: Kubernetes cluster does not contain any instances satisfying the request: 1x Kubernetes({'H100': 1}, region=). To fix: relax or change the resource requirements. ``` In the `--gpus` parameter, set the node group [platform](https://docs.nebius.com/compute/virtual-machines/types.md), such as `H100`, `B300` or `L40S`. Both examples run a Bash command as the entrypoint. You can also pass a YAML task definition instead. For examples, see the [SkyPilot quickstart](https://docs.skypilot.co/en/latest/getting-started/quickstart.html). ### (Optional) Monitor jobs To list all SkyPilot jobs created during this tutorial and their statuses, run: ```bash sky status ``` To stream the logs of a job, run: ```bash sky logs ``` ## How to delete the created resources Some of the created resources are chargeable. If you don't need them, delete these resources, so Nebius AI Cloud doesn't charge for them: * Delete SkyPilot jobs created during this tutorial: ```bash sky down --all -y ``` * [Delete Managed Kubernetes clusters](https://docs.nebius.com/kubernetes/clusters/manage.md#how-to-delete-clusters). * If you no longer need the Managed SkyPilot API Server, delete it in the Nebius AI Cloud console. Go to  **AI orchestration** → **SkyPilot**, open the application, go to the **Settings** tab and click **Delete application**. *** *InfiniBand and InfiniBand Trade Association are registered trademarks of the InfiniBand Trade Association.* # Mounting disks to Pods in a Managed Service for Kubernetes® cluster Source: https://docs.nebius.com/kubernetes/storage/disk-over-csi.md Nebius AI Cloud offers persistent storage for Pods in Managed Service for Kubernetes clusters. In this tutorial, you will mount a Compute disk as a persistent volume to a Pod in your cluster. ## Background By default, files created or modified by a container in a Kubernetes Pod are lost when the container crashes, or is stopped or restarted. [Persistent volumes](https://kubernetes.io/docs/concepts/storage/persistent-volumes/) help you avoid this: they keep the files for the lifetime of the Pod, regardless of the states of its individual containers to the Pod. These volumes are mounted to a node that is running the Pod. In Nebius AI Cloud, Managed Service for Kubernetes offers a native solution for persistent volumes in your clusters. You can mount disks from another Nebius AI Cloud service, Compute, to your Pods as persistent volumes. Compute provides multiple disk types that vary in performance, reliability and price, and you can choose between them depending on your use case. For more details, see the [Compute documentation](https://docs.nebius.com/compute/storage/types.md#disks). Mounting disks to Pods relies on support for Container Storage Interface (CSI), which is enabled on newer Managed Kubernetes clusters and can be enabled for older clusters (see prerequisites below). A disk can be used on one node at a time. If you need to share data between Pods and nodes, use Compute shared filesystems instead of disks. See [Mounting shared filesystems to Pods in a Managed Service for Kubernetes® cluster](https://docs.nebius.com/kubernetes/storage/filesystem-over-csi.md) for details. ## Costs Nebius AI Cloud only charges for a Compute disk. For more details, see the [Compute pricing](https://docs.nebius.com/compute/resources/pricing.md#disks). ## Prerequisites 1. [Create a Managed Kubernetes cluster](https://docs.nebius.com/kubernetes/clusters/manage.md) or choose an existing one. 2. If you are working with an existing cluster, [verify that it supports CSI](https://docs.nebius.com/kubernetes/storage/disk-over-csi.md#verify-that-your-cluster-supports-csi). 3. [Install kubectl](https://kubernetes.io/docs/tasks/tools/#kubectl) and [connect to the cluster](https://docs.nebius.com/kubernetes/connect.md). [Nebius AI Cloud disks](https://docs.nebius.com/compute/storage/types.md#disks) are created automatically; you do not need to create them beforehand. ### Verify that your cluster supports CSI If your Managed Kubernetes cluster was created on or after January 7, 2025, it already supports CSI and no additional configuration is required. Proceed to the tutorial's [steps](https://docs.nebius.com/kubernetes/storage/disk-over-csi.md#steps). If your cluster was created before January 7, 2025, enable CSI support in it: 1. Get IDs of the node groups in the cluster: 1. In [Managed Kubernetes](https://console.nebius.com/mk8s), open your cluster. 2. Switch to the **Node groups** tab. 3. For each node group, find its ID under its name and click to copy it. 1. Run nebius mk8s cluster list or nebius mk8s cluster get-by-name --name \ to get the cluster ID. It is returned in the `.metadata.id` field. 2. Get the list of the cluster's node groups, by using the cluster ID as parent ID: ```bash nebius mk8s node-group list --parent-id ``` The IDs of the node groups are returned in the `.metadata.id` fields. 2. Upgrade each node group: ```bash nebius mk8s node-group upgrade --id --latest-infra-version ``` 3. [Contact support](https://console.nebius.com/support) or your solution architect to enable CSI support. ## Steps ### Create a storage class for custom provisioning (optional) Before using Compute disks as persistent volumes, you can choose how disks are provisioned: the [disk type](https://docs.nebius.com/compute/storage/types.md#disk-types), the filesystem type (ext4 or xfs) and when a disk should be created (together with a persistent volume claim or when the claim is used by a Pod). To do this, define a custom Kubernetes storage class. The default storage class offered by Managed Kubernetes, `compute-csi-default-sc`, creates a [Network SSD disk](https://docs.nebius.com/compute/storage/types.md#disk-types) with an ext4 filesystem, and does so when a Pod that uses a persistent volume claim with this storage class is created. If this configuration suits you, you can skip this step and proceed to [creating a persistent volume claim](https://docs.nebius.com/kubernetes/storage/disk-over-csi.md#create-a-persistent-volume-claim). To create a custom storage class: 1. Create a manifest, for example `storage-class.yaml`, that defines the storage class. For example: ```yaml apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: storage-test-class provisioner: compute.csi.nebius.com volumeBindingMode: WaitForFirstConsumer parameters: csi.storage.k8s.io/fstype: xfs type: "NETWORK_SSD" ``` * `.metadata.name` — The name of the storage class. Use it when referring to the class in [persistent volume claims](https://docs.nebius.com/kubernetes/storage/disk-over-csi.md#create-a-persistent-volume-claim) (`.spec.storageClassName`). * `.provisioner` — The volume [provisioner](https://kubernetes.io/docs/concepts/storage/storage-classes/#provisioner). For Nebius AI Cloud disks, the provisioner is `compute.csi.nebius.com`. * `.volumeBindingMode` — The [volume binding mode](https://kubernetes.io/docs/concepts/storage/storage-classes/#volume-binding-mode) that determines when a Nebius AI Cloud disk is created for a persistent volume claim of this storage class. Supported values are `WaitForFirstConsumer` (the disk is created together with a Pod that uses the claim) or `Immediate` (the disk is created together with the claim, even if no Pods use it yet). Disks created in the `Immediate` binding mode may start to be [charged](https://docs.nebius.com/compute/resources/pricing.md#disks) and to count towards [quotas](https://docs.nebius.com/compute/resources/quotas-limits.md#storage) before being actually used in Pods. To avoid this, use the `WaitForFirstConsumer` binding mode. * `.parameters."csi.storage.k8s.io/fstype"` — The filesystem for disks: `ext4` or `xfs`. * `.parameters.type` — The Nebius AI Cloud disk type. See the [list of disk types and their IDs](https://docs.nebius.com/compute/storage/types.md#disk-types). Write IDs in uppercase, for example, `NETWORK_SSD`, `NETWORK_SSD_IO_M3`. 2. Apply the manifest to your cluster: ```bash kubectl apply -f storage-class.yaml ``` ### Create a persistent volume claim Persistent volume claims are requests that Pods make for persistent volumes. These requests include what kind of storage should be provided (in our case, a Compute disk with the default or a custom storage class) and how large it should be. To create a persistent volume claim: 1. Create a manifest, for example `pvc.yaml`, that defines the claim. For example: ```yaml apiVersion: v1 kind: PersistentVolumeClaim metadata: name: storage-test-claim spec: accessModes: - ReadWriteOnce storageClassName: compute-csi-default-sc resources: requests: storage: 4Gi ``` * `.metadata.name` — The name of your claim. Use it when referring to the claim in Pod configurations. * `.spec.accessModes` — An array of [access modes](https://kubernetes.io/docs/concepts/storage/persistent-volumes/#access-modes) that determine how the persistent volume can be mounted to nodes. The only mode supported for Nebius AI Cloud block storage is `ReadWriteOnce`; the volume can be mounted as read-write by a single node. For storage that can be mounted to multiple nodes (`ReadWriteMany`), see [Mounting shared filesystems to Pods in a Managed Service for Kubernetes® cluster](https://docs.nebius.com/kubernetes/storage/filesystem-over-csi.md). * `.spec.storageClassName` — The [storage class](https://kubernetes.io/docs/concepts/storage/storage-classes/) of the volume. The default storage class for Nebius AI Cloud block storage, `compute-csi-default-sc`, creates a [Network SSD disk](https://docs.nebius.com/compute/storage/types.md#disk-types) with an ext4 filesystem. To use another disk type or filesystem, [create a custom storage class](https://docs.nebius.com/kubernetes/storage/disk-over-csi.md#create-a-storage-class-for-custom-provisioning-optional) by using the Nebius AI Cloud provisioner and specify its name here. * `.spec.resources.requests.storage` — The volume size. 2. Apply the manifest to your cluster: ```bash kubectl apply -f pvc.yaml ``` ### Mount a volume to a Pod and test it When a persistent volume claim is used in a Pod's specification, the Compute disk created for the claim is mounted to the Pod as a persistent volume. A disk created for a claim is mounted to each Pod that uses the claim, and is deleted together with the claim. Do not use a claim on multiple Pods at one time, as a disk can only be mounted to a single node. For a solution that shares storage between nodes, see [Mounting shared filesystems to Pods in a Managed Service for Kubernetes® cluster](https://docs.nebius.com/kubernetes/storage/filesystem-over-csi.md). To create a Pod with a volume and test it: 1. Create a manifest, for example `pod.yaml`, that defines the Pod. For example, in the manifest below, a volume named `persistent-storage`, created from the `test-claim` persistent volume claim, is mounted to the Pod's container at `/data`: ```yaml apiVersion: v1 kind: Pod metadata: name: storage-test-app spec: volumes: - name: persistent-storage persistentVolumeClaim: claimName: storage-test-claim containers: - name: app image: centos command: ["/bin/sh"] args: ["-c", "while true; do echo $(date -u) >> /data/out.txt; sleep 5; done"] volumeMounts: - name: persistent-storage mountPath: /data ``` * `.spec.volumes[0].name`: The name of the volume that is created for the Pod. * `.spec.volumes[0].persistentVolumeClaim.claimName`: The name of the persistent volume claim that is used to create a volume. * `.spec.containers[0].volumeMounts[0].name`: The same volume name as in `.spec.volumes[0].name`. * `.spec.containers[0].volumeMounts[0].mountPath`: The mount point for the volume. You can configure volumes in Kubernetes resources that manage Pods, like [Deployments](https://kubernetes.io/docs/concepts/workloads/controllers/deployment/) or [StatefulSets](https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/), in the same way, by using sub-fields of `.spec.template.spec.volumes` and `.spec.template.spec.containers`. 2. Apply the manifest to your cluster: ```bash kubectl apply -f pod.yaml ``` 3. Wait until the Pod is ready: ```bash kubectl wait --for condition=Ready=true pod/storage-test-app ``` 4. Test that the container has written into `/data/out.txt`: ```bash kubectl exec storage-test-app -- cat /data/out.txt ``` ## How to delete the created resources The created Compute disk is chargeable. If you do not need it, delete the Pod and the persistent volume claim, so that the disk is deleted and Nebius AI Cloud does not charge for it: ```bash kubectl delete pod/storage-test-app pvc/storage-test-claim ``` ## See also * [Mounting shared filesystems to Pods in a Managed Service for Kubernetes® cluster](https://docs.nebius.com/kubernetes/storage/filesystem-over-csi.md) * [Types of storage volumes in Compute](https://docs.nebius.com/compute/storage/types.md) # Mounting shared filesystems to Pods in a Managed Service for Kubernetes® cluster Source: https://docs.nebius.com/kubernetes/storage/filesystem-over-csi.md In this tutorial, you will use a Container Storage Interface (CSI) driver offered by Nebius AI Cloud to mount a Compute shared filesystem to nodes in a Managed Service for Kubernetes and use it as a persistent volume shared between Pods running on the nodes. To work with disks that can be mounted to a single node instead of shared filesystems, see [Mounting disks to Pods in a Managed Service for Kubernetes® cluster](https://docs.nebius.com/kubernetes/storage/disk-over-csi.md). ## Costs The tutorial includes the following chargeable resources: * [Compute shared filesystem](https://docs.nebius.com/compute/resources/pricing.md#shared-filesystems) * [Compute virtual machines](https://docs.nebius.com/compute/resources/pricing.md) that make up a node group ## Prerequisites 1. Make sure you are in a [group](https://docs.nebius.com/iam/authorization/groups/index.md) that has at least the `editor` role within your tenant or project; for example, the default `editors` group. You can check this in the [Administration → IAM](https://console.nebius.com/iam) section of the web console. 2. [Install and configure](https://docs.nebius.com/cli/install.md) the Nebius AI Cloud CLI. The CLI commands in this article assume that the CLI is properly configured. For example, they omit the ID of the parent project, as it is assumed to be set in the CLI profile. 3. [Install kubectl](https://kubernetes.io/docs/tasks/tools/#kubectl) and [Helm](https://helm.sh/docs/intro/install/). 4. Install `jq`: ```bash Ubuntu sudo apt-get install jq ``` ```bash macOS brew install jq ``` 5. [Create a Managed Kubernetes cluster](https://docs.nebius.com/kubernetes/clusters/manage.md) or use an existing one. ## Steps ### Create a shared filesystem Run the command below to create a 256 GiB SSD shared filesystem: ```bash nebius compute filesystem create \ --name mk8s-csi-storage \ --size-gibibytes 256 \ --type network_ssd \ --block-size-bytes 4096 ``` When setting the filesystem size (`size-gibibytes`), make sure it is enough for all your Pods to store their data. The filesystem that you are adding to a node group must be located in the same project as the node group's parent cluster. For more details about projects and resource hierarchy in Nebius AI Cloud, see [How resources, identities and access are managed in Nebius AI Cloud](https://docs.nebius.com/iam/overview.md). ### Create a node group and mount the filesystem to nodes 1. Create the cloud-init user data that will mount the shared filesystem to nodes: ```bash export MOUNT_POINT=/mnt/data export MOUNT_TAG=csi-storage export USER_DATA=$(jq -Rrs '.' < Do not omit `nofail`. If it is not specified and a node cannot find the filesystem on restart (for example, it has been deleted), the node will not boot. 2. Create the node group: ```bash nebius mk8s node-group create \ --parent-id \ --name "ng-1" \ --fixed-node-count 2 \ --template-resources-platform "cpu-e2" \ --template-resources-preset "2vcpu-8gb" \ --template-filesystems "[{\"existing_filesystem\": {\"id\": \"\"}, \"attach_mode\": \"READ_WRITE\", \"mount_tag\": \"$MOUNT_TAG\"}]" \ --template-cloud-init-user-data "$USER_DATA" ``` ### Install the CSI driver 1. Pull the driver's Helm chart: ```bash helm pull \ oci://cr.eu-north1.nebius.cloud/mk8s/helm/csi-mounted-fs-path \ --version 0.1.7 ``` 2. Install the chart: ```bash helm upgrade csi-mounted-fs-path ./csi-mounted-fs-path-0.1.7.tgz --install \ --set dataDir=$MOUNT_POINT/csi-mounted-fs-path-data/ ``` The chart creates the `csi-mounted-fs-path-sc` `StorageClass`. By default, this `StorageClass` uses the `WaitForFirstConsumer` [volume binding mode](https://kubernetes.io/docs/concepts/storage/storage-classes/#volume-binding-mode), which delays volume provisioning until a Pod uses the `PersistentVolumeClaim`. To provision a volume as soon as the `PersistentVolumeClaim` is created, add `--set storageClass.volumeBindingMode=Immediate` to the installation command. ### Mount the filesystem to Pods Here is an example of a `PersistentVolumeClaim` that claims space on the shared filesystem, and a Pod that mounts the filesystem at `/data` through the `PersistentVolumeClaim`: ```yaml apiVersion: v1 kind: PersistentVolumeClaim metadata: name: csi-pvc spec: accessModes: - ReadWriteMany resources: requests: storage: 1Gi storageClassName: csi-mounted-fs-path-sc --- kind: Pod apiVersion: v1 metadata: name: my-csi-app spec: containers: - name: my-csi-app image: busybox volumeMounts: - mountPath: "/data" name: my-csi-volume command: [ "sleep", "1000000" ] securityContext: allowPrivilegeEscalation: false privileged: false volumes: - name: my-csi-volume persistentVolumeClaim: claimName: csi-pvc ``` ## How to delete the created resources Some of the created resources are chargeable. If you do not need them, delete these resources, so Nebius AI Cloud does not charge for them: 1. Delete the node group: 1. In the sidebar, go to  **Compute** → **Kubernetes**. 2. Open the page of the required cluster and then go to the **Node groups** tab. 3. In the row of the required node group, click  → **Delete**. 4. Confirm the node group deletion. 1. Get the ID of the node group that you want to delete: ```bash nebius mk8s node-group list --parent-id ``` 2. Delete the node group: ```bash nebius mk8s node-group delete --id ``` 2. Delete the Compute shared filesystem: 1. In the sidebar, go to  **Storage** → **Shared filesystems**. 2. Next to the filesystem's name, click → **Delete**. 3. Enter the filesystem's name and confirm deletion. ```bash nebius compute filesystem delete --id ``` ## See also * [Mounting disks to Pods in a Managed Service for Kubernetes® cluster](https://docs.nebius.com/kubernetes/storage/disk-over-csi.md) * [Types of storage volumes in Compute](https://docs.nebius.com/compute/storage/types.md) # Deploying and deleting applications for Managed Service for Kubernetes® Source: https://docs.nebius.com/kubernetes/manage-applications.md Nebius AI Cloud provides several applications that you can deploy by using the **Kubernetes** deployment option on [Managed Kubernetes clusters](https://docs.nebius.com/kubernetes/clusters/manage.md). For example, you can deploy a database, a certificate manager or libraries for LLM inference. You can use popular tools, such as [Argo CD](https://argo-cd.readthedocs.io/en/stable/) and [Grafana Loki](https://grafana.com/oss/loki/). For information about deploying applications, see [Deploying applications in Nebius AI Cloud](https://docs.nebius.com/applications/deploy.md). Each application requires at least one node group in a cluster. You can create it [beforehand](https://docs.nebius.com/kubernetes/node-groups/manage.md#how-to-create-node-groups) or during the [application deployment](https://docs.nebius.com/kubernetes/manage-applications.md#how-to-find-and-deploy-an-application). ## Prerequisites Make sure you are in a [group](https://docs.nebius.com/iam/authorization/groups/index.md) that has at least the `editor` role within your tenant or project; for example, the default `editors` group. You can check this in the [Administration → IAM](https://console.nebius.com/iam) section of the web console. ## How to find and deploy an application To see the list of applications for Managed Kubernetes and deploy an application: 1. In the sidebar, go to **Applications**. 2. In the **Deployment** dropdown, select **Kubernetes** to see only applications that support Kubernetes deployment. 3. Choose an application, open its page and click **Deploy on cluster**. 4. Configure the application. If you do not have a suitable Managed Kubernetes cluster to deploy the application, you can create a new cluster on this step. The application creates the necessary node groups in the new or existing cluster automatically. 5. Click **Deploy application**. 6. Wait until the statuses of the cluster and application are `Running`. ## How to delete an application 1. In the sidebar, go to **Applications**. 2. Go to the **Installed** tab to see your deployed applications. 3. Find the application you want to delete and open it. 4. On the application details page, go to the **Settings** tab. 5. Click **Delete application**. 6. To confirm that you want to delete the application, enter its name and click **Delete application**. When you delete an application, node groups created with it remain in the cluster and are subject to Managed Kubernetes [charges](https://docs.nebius.com/kubernetes/resources/pricing.md) and [quotas](https://docs.nebius.com/kubernetes/resources/quotas-limits.md). If you do not need these node groups, [delete them](https://docs.nebius.com/kubernetes/node-groups/manage.md#how-to-delete-node-groups). # Monitoring clusters and nodes in Managed Service for Kubernetes® Source: https://docs.nebius.com/kubernetes/monitoring.md You can monitor Managed Service for Kubernetes cluster and nodes states on the dashboards in the Nebius AI Cloud web console. Use the dashboards to monitor current resource utilization, get information to schedule [quota](https://docs.nebius.com/kubernetes/resources/quotas-limits.md) increases and quickly identify anomalies. In case of issues with your cluster, dashboards help the Nebius support team investigate the issue. Data for the dashboards is collected automatically. For more information about metrics collection, see [Monitoring agent on Compute virtual machines](https://docs.nebius.com/observability/agents/monitoring-agent.md). ## Explore the dashboards The cluster usage data becomes available 5–10 minutes after nodes are created in the cluster. You can view it on the **Monitoring** tab of the cluster and the node group pages. You can select specific nodes to check their health separately. On the cluster monitoring page, you can also select specific node groups. Use time filters to view a specific period of usage. By default, the data is refreshed every 15 seconds. You can configure this interval to the right of the time filters. ## Monitoring metrics Managed Service for Kubernetes nodes are hosted by Compute virtual machines and produce the same metrics. You can read about them in [Monitoring virtual machines in Nebius AI Cloud](https://docs.nebius.com/compute/monitoring/virtual-machines.md). # Logs in Managed Service for Kubernetes® Source: https://docs.nebius.com/kubernetes/logs.md Managed Service for Kubernetes provides logs about clusters and node groups. Use these logs for troubleshooting and tracking actions on Managed Kubernetes resources. The logs are available in the web console: on the  [Observability → Logs](https://console.nebius.com/observability/logs) page or on the **Logs** tab of a cluster page. The service supports two types of logs: * **Audit logs**: Contain metadata about operations that modify a cluster. For example, who and when created or deleted a Pod. Disabled by default; you can [enable them](https://docs.nebius.com/kubernetes/logs.md#how-to-enable-audit-logs). * **Control plane logs**: Show actions recorded by [control plane components](components#control-plane-components) of a cluster. For example, you can learn about the cluster scaling, Pod scheduling or node availability. The control plane logs are collected from the following components: * API server ([kube-apiserver](https://kubernetes.io/docs/concepts/overview/kubernetes-api/)) * Scheduler ([kube-scheduler](https://kubernetes.io/docs/concepts/scheduling-eviction/kube-scheduler/)) * [Cluster autoscaler](https://docs.nebius.com/kubernetes/node-groups/autoscaling.md) * Controller manager ([kube-controller-manager](https://kubernetes.io/docs/concepts/architecture/controller/)) * Cloud controller manager In addition, Kubernetes generates node events. They provide information about Kubernetes resources, for example, state changes, node errors, Pod errors or scheduling failures. The control plane logs are enabled by default; you cannot disable them. ## How to enable audit logs Audit logs in Managed Kubernetes are disabled by default. To enable them, run the following command: ```bash nebius mk8s cluster update --id --control-plane-audit-logs ``` ## How to view logs 1. In the sidebar, go to  **Compute** → **Kubernetes**. 2. Open the page of the required cluster and then go to the **Logs** tab. 3. In the **Bucket** field, select **Managed Kubernetes audit logs** or **Managed Kubernetes control planes**. 4. (Optional) To check logs for a specific control plane component, select it in the **Component** field. 5. Apply the required period. ## See also * [Logs in Nebius AI Cloud](https://docs.nebius.com/observability/logging.md) # Autoscaling in Managed Service for Kubernetes Source: https://docs.nebius.com/kubernetes/node-groups/autoscaling.md In Managed Service for Kubernetes, the **cluster autoscaler** integrates with the underlying infrastructure to monitor and manage [node groups](https://docs.nebius.com/kubernetes/components.md#node-group) in your cluster, to add or remove nodes seamlessly as needed. It makes scaling decisions based on the following principles: * If there are unschedulable Pods in the cluster due to resource constraints, the cluster autoscaler adds new nodes to accommodate these Pods. * If nodes in the cluster are underutilized, the cluster autoscaler removes these nodes in order to optimize resource usage and reduce costs. If you have a GPU node group with autoscaling, add a CPU node group with at least two nodes (or with autoscaling) to the cluster. In this case, when there are no tasks to perform, [CoreDNS and Cilium networking add-ons](https://docs.nebius.com/kubernetes/networking/add-ons.md) can run on CPU nodes, so that the GPU node group can scale down and reduce your costs. ## Set up autoscaling for new node groups You can set up autoscaling when creating a new node group: When [creating a node group](https://docs.nebius.com/kubernetes/node-groups/manage.md#how-to-create-node-groups): 1. Under **Size**, select **Enable autoscaling**. 2. Specify the **Min. nodes** and **Max. nodes** numbers in the group. When [creating a node group](https://docs.nebius.com/kubernetes/node-groups/manage.md#how-to-create-node-groups), add the following parameters to the [nebius mk8s node-group create](https://docs.nebius.com/cli/reference/mk8s/node-group/create) command: ```bash nebius mk8s node-group create \ ... \ --autoscaling-min-node-count \ --autoscaling-max-node-count ``` For example, to set the autoscaling from 2 to 4 nodes, add `--autoscaling-min-node-count 2 --autoscaling-max-node-count 4` to the `nebius mk8s node-group create` command. ## Set up autoscaling for existing node groups You can only manage autoscaling for existing node groups by using the Nebius AI Cloud CLI. To enable autoscaling for an existing node group, add the following parameters to the [nebius mk8s node-group update](https://docs.nebius.com/cli/reference/mk8s/node-group/update) command: ```bash nebius mk8s node-group update --id \ --autoscaling-min-node-count \ --autoscaling-max-node-count ``` For example, to set the autoscaling from 2 to 4 nodes, add `--autoscaling-min-node-count 2 --autoscaling-max-node-count 4` to the `nebius mk8s node-group create` command. ## Configure autoscaling parameters You can only configure autoscaling parameters for existing node groups by using the Nebius AI Cloud CLI. To configure the minimum and maximum numbers of nodes for autoscaling, add the following parameters to the [nebius mk8s node-group update](https://docs.nebius.com/cli/reference/mk8s/node-group/update) command: ```bash nebius mk8s node-group update --id \ --autoscaling-min-node-count \ --autoscaling-max-node-count ``` For example, to set the autoscaling from 2 to 4 nodes, add `--autoscaling-min-node-count 2 --autoscaling-max-node-count 4` to the `nebius mk8s node-group update` command. ## Troubleshooting ### More GPU nodes than required * **Issue**: When a Managed Kubernetes cluster has the NVIDIA GPU Operator and the NVIDIA Network Operator installed, and workloads on a GPU node group are run with autoscaling, the cluster autoscaler can create more nodes in the group than the workloads require. * **Possible reason**: A bug in Kubernetes Autoscaler that causes inconsistency in how nodes are considered ready or not ready for Pods. For more information, see [Excess multiGPU nodes when using GPU + network operators](https://github.com/kubernetes/autoscaler/issues/7956) in the Kubernetes Autoscaler repository on GitHub. * **Solution**: 1. Uninstall the NVIDIA operators. 2. [Create a GPU node group](https://docs.nebius.com/kubernetes/gpu/set-up.md#how-to-add-nodes-with-gpus-to-a-cluster) and [migrate your workloads](https://docs.nebius.com/kubernetes/node-groups/moving-workload.md) to it. A node group created this way uses the GPU-adapted boot disk image offered by Managed Kubernetes, which solves the issue because the NVIDIA operators are no longer required. ## See also * [Cluster autoscaler parameters](https://github.com/kubernetes/autoscaler/blob/master/cluster-autoscaler/FAQ.md#what-are-the-parameters-to-ca) in the official GitHub repository. # Moving workload from the existing node group Source: https://docs.nebius.com/kubernetes/node-groups/moving-workload.md The workload is moved automatically after you evict it from the existing node group. Before moving your workload, you need to: 1. Install [jq](https://jqlang.github.io/jq/download/) if you don't have it on your system: ```bash Ubuntu sudo apt-get install jq ``` ```bash macOS brew install jq ``` 2. [Get your cluster ID](https://docs.nebius.com/kubernetes/clusters/manage.md#how-to-modify-clusters) which is returned in the `.metadata.id` field of the cluster resource. The CLI commands in this guide assume that the cluster ID is saved to an environment variable `K8S_CLUSTER_ID`. To move your workload: 1. [Create a node group](https://docs.nebius.com/kubernetes/node-groups/manage.md#how-to-create-node-groups). > For example, the following command creates a group of two nodes, each with one NVIDIA H100 GPU, and all drivers and components required for the GPU: > > ```bash > nebius mk8s node-group create \ > --parent-id $K8S_CLUSTER_ID \ > --name mk8s-node-group-test \ > --fixed-node-count 2 \ > --template-resources-platform gpu-h100-sxm \ > --template-resources-preset 1gpu-16vcpu-200gb \ > --template-gpu-settings-drivers-preset cuda12 > ``` 2. Export to an environment variable the name of the node group from which you want to move the workload. For example, you can get it by the node group's name (if you have set and know it) and the parent cluster's ID: ```bash export K8S_NODE_GROUP_ID=$(nebius mk8s node-group get-by-name \ --parent-id $K8S_CLUSTER_ID \ --name node-group-name \ --format jsonpath='{.metadata.id}') ``` 3. Get the list of node names in the node group from which you want to move the workload: ```sh export OLD_NODES=$(kubectl get nodes -o json \ | jq '.items[].metadata | select(.annotations."cluster.x-k8s.io/owner-name" = "$K8S_NODE_GROUP_ID") | .name') ``` 4. Cordon off the old nodes so that no new Pods are scheduled on them: ```sh for node in $OLD_NODES; do kubectl cordon $node; done ``` 5. Drain the old nodes so that the existing Pods can be evicted from them: ```sh for node in $OLD_NODES; do kubectl drain --force --ignore-daemonsets --delete-emptydir-data $node; done ``` Kubernetes will automatically move evicted Pods to suitable nodes. 6. Delete the old node group: ```bash nebius mk8s node-group delete --id $K8S_NODE_GROUP_ID ``` # "Unable to allocate CIDR from the pool" error Source: https://docs.nebius.com/kubernetes/troubleshooting/cidr-allocation-error.md When you create a Managed Service for Kubernetes® cluster, it may get stuck in the `Provisioning` status with the following error: ```text "rpc error: code = FailedPrecondition desc = Unable to allocate private ipv4 cidr /32 from the pool. Please verify the availability of the cidrs and retry the allocation." ``` This error usually indicates that there is not enough CIDR space available for IP address allocation. Possible causes: * [Quota for IP addresses is exceeded](https://docs.nebius.com/kubernetes/troubleshooting/cidr-allocation-error.md#quota-for-ip-addresses-is-exceeded) * [Selected subnet is too small](https://docs.nebius.com/kubernetes/troubleshooting/cidr-allocation-error.md#selected-subnet-is-too-small) * [CIDR block is too large](https://docs.nebius.com/kubernetes/troubleshooting/cidr-allocation-error.md#cidr-block-is-too-large) ## Quota for IP addresses is exceeded You may not have enough free [quota](https://docs.nebius.com/vpc/resources/quotas-limits.md) for the IP addresses the cluster requires. To find out if that is the case, get and compare the following information: * See the complete list of required allocations in [Network requirements for Managed Service for Kubernetes® clusters](https://docs.nebius.com/kubernetes/networking/requirements.md). * Check your free quota on the [Administration → Limits → Quotas](https://console.nebius.com/quotas) page in the web console. To fix this, use one of the following solutions: * Remove unused resources to free up quota. * Request a quota increase on the **Administration** → **Limits** → **Quotas** page. ## Selected subnet is too small The [subnet](https://docs.nebius.com/vpc/overview.md#subnet) you specified during cluster creation may not have enough CIDR blocks. To find out if that is the case, get and compare the following information: * See the complete list of required allocations in [Network requirements for Managed Service for Kubernetes® clusters](https://docs.nebius.com/kubernetes/networking/requirements.md). * Get the subnet metadata: ```bash nebius vpc subnet get --id ``` To find the available CIDR blocks, check the `cidr` values in the `spec.ipv4_private_pools.pools.cidrs` list in the response. To fix this, use one of the following solutions: * Add a [pool](https://docs.nebius.com/vpc/overview.md#pool) with more CIDR blocks to the subnet. * Use another, larger subnet for your cluster. ## CIDR block is too large If you specified a CIDR block for Kubernetes services that is too large, no free blocks for other control plane requirements may be left in the subnet. To find out if that is the case, get and compare the following information: * Get the subnet metadata: ```bash nebius vpc subnet get --id ``` To find the available CIDR blocks, check the `cidr` values in the `spec.ipv4_private_pools.pools.cidrs` list in the response. * Check the value of the `spec.kube_network.service_cidrs` parameter that you set during cluster creation. To fix this, use one of the following solutions: * Specify a smaller block for services in the `spec.kube_network.service_cidrs` parameter. * Add a [pool](https://docs.nebius.com/vpc/overview.md#pool) with more CIDR blocks to the subnet. * Use another, larger subnet for your cluster. # How to collect diagnostic logs from Managed Service for Kubernetes® nodes Source: https://docs.nebius.com/kubernetes/troubleshooting/logs.md Managed Service for Kubernetes [nodes](https://docs.nebius.com/kubernetes/components.md#node) are Compute virtual machines (VMs). *Diagnostic logs* from Managed Kubernetes nodes help you troubleshoot issues with VM operations, networking and workloads. The procedure for collecting diagnostic logs depends on the GPU and access settings you configured when you [created the node group](https://docs.nebius.com/kubernetes/node-groups/manage.md#regular-node-groups). We strongly recommend collecting logs while the issue is still occurring, because they capture more information about the broken state than logs collected after the issue has been resolved. Determine which of the following cases applies to your environment, and follow the relevant procedure: * Nodes that have one or more GPUs, without SSH configuration: [connect to the cluster with kubectl to start a debug session](https://docs.nebius.com/kubernetes/troubleshooting/logs.md#how-to-collect-logs-by-using-kubectl). * Nodes that have one or more GPUs, with SSH configuration: [connect to the node with SSH to collect logs](https://docs.nebius.com/kubernetes/troubleshooting/logs.md#how-to-collect-logs-by-using-ssh). * Nodes without GPUs: [contact our support team](https://docs.nebius.com/kubernetes/troubleshooting/logs.md#how-to-request-log-collection-from-support). ## Types of logs This guide describes how to collect the following types of logs for troubleshooting: * GPU logs: `nvidia-bug-report.sh`. * General system logs, including more context about system services and package versions: `sos report`. * [NVIDIA® Mellanox®](https://www.nvidia.com/en-us/networking/management-software/) adapter (InfiniBand™/NVSwitch/Ethernet) logs: `sysinfo-snapshot`. ## How to collect logs by using kubectl If your nodes have GPUs and you have `kubectl` access to the cluster, but no SSH access to the nodes, do the following to collect the logs: 1. Connect to the cluster with [kubectl](https://docs.nebius.com/kubernetes/connect.md). 2. Start a debugging session for the required node and open an interactive shell in the debug container: ```bash kubectl debug node/ -it --image ubuntu --profile sysadmin -- bash ``` In the command, specify: * `node_ID`: The node to debug. To get the nodes in the cluster, run: ```bash kubectl get nodes ``` Alternatively, in the [web console](https://console.nebius.com/), go to **Compute** → **Virtual machines**. On the **Kubernetes nodes** tab, click next to the node ID to copy it. * `--image`: Container image to use for the debug container. We recommend setting it to `ubuntu` to start a temporary debug container. * `--profile`: Set to `sysadmin` to use the built-in debugging profile. Refer to the [Kubernetes documentation](https://kubernetes.io/docs/reference/kubectl/generated/kubectl_debug/) for more information. * `-it`: Starts an interactive terminal session in the debug container. * `bash`: Starts the Bash shell in the debug container. In the output, note the name of the temporary debug Pod that was created. You will need it in a later step. 3. Switch to the host filesystem: ```bash chroot /host ``` 4. Generate GPU logs: ```bash nvidia-bug-report.sh ``` This command usually runs for about five minutes and generates `nvidia-bug-report.log.gz` in the current working directory. If the command stops responding, run it in safe mode: ```bash nvidia-bug-report.sh --safe-mode ``` 5. If you need more system information, generate general system logs: ```bash sos report --batch ``` This command generates an archive in the following format: `/tmp/sosreport---.tar.gz`. 6. If you are troubleshooting Mellanox adapter issues, generate Mellanox adapter logs: ```bash /opt/nebius/sysinfo-snapshot ``` This command generates an archive in the following format: `/tmp/sysinfo-snapshot---.tgz`. 7. From your local shell, copy the generated log file(s) from the debug Pod: Don't exit the shell. This will terminate the debug Pod, and you will not be able to copy files from it. Instead, open a new terminal to run the `kubectl cp` command. ```bash kubectl cp :/host/ ./ ``` In the command, specify: * `debug_Pod_name`: The name of the temporary debug Pod created when you ran `kubectl debug`. * `generated_file_path`: The path to the generated log file on the node, for example, `/tmp/sosreport-*.tar.gz`. * `local_file_name`: The name to save the file as on your local machine, for example, `/tmp/sosreport.tar.gz`. ## How to collect logs by using SSH If your nodes have GPUs, and you have configured SSH access, do the following to collect the logs: 1. Connect to the node over SSH. Nodes are Compute VMs, therefore, you connect the same way you would [connect to a VM by using SSH](https://docs.nebius.com/compute/virtual-machines/connect.md#connect-to-the-vm-by-using-ssh). 2. Generate the logs as described in [How to collect logs](https://docs.nebius.com/compute/virtual-machines/logs.md#how-to-collect-logs). 3. Retrieve the generated log files as described in [How to get generated log files](https://docs.nebius.com/compute/virtual-machines/logs.md#how-to-get-generated-log-files). ## How to request log collection from support If your nodes don't have GPUs, [create a support ticket](https://docs.nebius.com/overview/support.md) to get assistance with troubleshooting. When you create the ticket, write that you give the support team explicit permission to access your logs. *InfiniBand and InfiniBand Trade Association are registered trademarks of the InfiniBand Trade Association.* # Managed Service for Kubernetes® quotas and constraints Source: https://docs.nebius.com/kubernetes/resources/quotas-limits.md ## Quotas Managed Service for Kubernetes has quotas on the number of clusters and uses the same quotas on nodes and IP addresses as Compute. For details on what quotas are and how to manage them, see [Quotas in Nebius AI Cloud](https://docs.nebius.com/overview/quotas.md). ### Clusters | Quota name | Default value | | :--------------------------------------- | :------------ | | Clusters per [region](https://docs.nebius.com/overview/regions.md) | 2 | ### Nodes Managed Service for Kubernetes nodes comply with the same quotas as Compute virtual machines. You can find them in [Quotas in Compute](https://docs.nebius.com/compute/resources/quotas-limits.md). ### Network See [Quotas in Virtual Networks](https://docs.nebius.com/vpc/resources/quotas-limits.md). ## Constraints Certain Managed Kubernetes resources have technical constraints that may depend on your quotas, but can't be changed directly. ### Nodes The number of nodes you can create in a Managed Kubernetes cluster depends on the type of used IP address and whether high availability control plane is enabled. This number is limited by your **Total number of allocations** [quota](https://docs.nebius.com/vpc/resources/quotas-limits.md). > For example, with the default **Total number of allocations** quota of 1000, you can create up to 498 nodes across all clusters when using only private IP addresses with no high availability, or up to 331 nodes when using both private and public IP addresses with high availability enabled. For more information, see [Network requirements for Managed Service for Kubernetes® clusters](https://docs.nebius.com/kubernetes/networking/requirements.md). # Pricing in Managed Service for Kubernetes® Source: https://docs.nebius.com/kubernetes/resources/pricing.md This article provides detailed pricing for the Managed Service for Kubernetes in Nebius AI Cloud. ## How charges and prices work Each group of chargeable items in this article has two time units associated with it: * **Billing unit**: The minimum unit of usage for which you can be charged. * **Pricing unit**: The unit of usage for which the prices are shown. Charges for units smaller than the pricing unit are calculated proportionally. > For example, for GPUs on running VMs, the **billing unit** is 1 second, and the **pricing unit** is 1 hour (3600 seconds). For 30 minutes of usage, you will be charged half the hourly price. Prices in US dollars (USD, \$) apply to all customers except for companies from Israel, where prices in Israeli shekels (ILS, ₪) apply instead. All prices are shown without any applicable taxes, including VAT. Due to rounding errors, usage costs shown in the web console and final charges may slightly differ from calculations based on the prices in this article. ## Prices ### Nodes You are charged for running nodes in your Managed Kubernetes clusters. As Managed Kubernetes nodes are Compute virtual machines, their computing resources (GPUs, vCPUs, RAM) and storage are charged according to Compute pricing. For more details, see [Compute pricing in Nebius AI Cloud](https://docs.nebius.com/compute/resources/pricing.md). ## Storage ### Object Storage # Object Storage Source: https://docs.nebius.com/object-storage/index.md Most ML/AI workloads involve large files, such as datasets and artifacts of trained models. To store, access and share them efficiently, you can use Object Storage, a simple storage service offered by Nebius AI Cloud. The service is available in all [Nebius AI Cloud regions](https://docs.nebius.com/overview/regions.md). Create your first bucket and upload files Learn about the main service resources Learn how to manage buckets and their parameters Explore how to upload files to buckets and download them Learn how to list, rename and delete objects Learn about the actions available to different roles Discover how to optimize operations on your buckets and objects Learn how to set up and use the AWS CLI Control resource usage and monitor your bucket health Set up and view control plane and data plane logs from your buckets # About Object Storage Source: https://docs.nebius.com/object-storage/overview.md Object Storage stores data for your ML/AI workloads. For example, you train a text-to-text model with a dataset of several petabytes. Here is how you can use Object Storage for it: 1. **Data storage**: Upload your training data to a bucket. Each object in the bucket is a file with a piece of text data for training. Set this bucket as a data source for your training scripts. 2. **Checkpoint storage**: During the model training and running experiments, set the scripts to upload each model checkpoint to the dedicated bucket. 3. **Model registry**: Use Object Storage to distribute models across your services or consumers, or to leverage autoscaling during inference. 4. **Inference results storage**: During the model inference, store the inference results in an Object Storage bucket. Your data in Object Storage is stored as *objects*: files in various formats together with their metadata. To organize the objects, you create containers called *buckets* in your [project](https://docs.nebius.com/iam/overview.md#projects) and upload objects into them. ## Buckets A bucket is a container in Object Storage for storing files. ### Naming A bucket name should be unique across the [region](https://docs.nebius.com/overview/regions.md). If you try to create a bucket with a name that is already taken by another bucket in the region, you will get a message about it. The name must be 3 to 63 characters long and may contain lowercase Latin letters, numbers, dots and hyphens. It is used as a part of a URL for data access. ### URLs Use the following template to access a bucket: ```url https://storage..nebius.cloud/ ``` In the URL above: * `region_id`: the ID of the [region](https://docs.nebius.com/overview/regions.md) where the bucket is located. * `bucket_name`: the name of the bucket you want to access. For example, the URL for the `training-artifacts` bucket located in eu-north1 (Finland) is: ```url https://storage.eu-north1.nebius.cloud/training-artifacts ``` ## Objects An object is a file in Object Storage together with its metadata. ### Naming To avoid issues with your objects, follow these naming requirements: * Object keys can be up to 1024 bytes long, case sensitive. * Use UTF-8 alphanumeric characters, slashes (`/`) and certain [special characters](https://docs.aws.amazon.com/AmazonS3/latest/userguide/object-keys.html#object-key-guidelines). ### Keys, prefixes and object hierarchy Each Object Storage object has an ID string called *key*. The key can contain *prefixes* that act similarly to directories, organizing objects into groups. Buckets have a flat structure: they have no directories in them, all objects in a bucket are at the same level of hierarchy. However, interfaces and tools supported by Object Storage, such as the [AWS CLI](https://docs.nebius.com/object-storage/interfaces/aws-cli.md), can emulate directories. If you upload a couple of objects with the same part of their IDs ending with `/`, they will be shown like they are in the same directory. The two uploaded files will be accessible as {`https://storage..nebius.cloud///`} and {`https://storage..nebius.cloud///`}. ### Storage classes Object Storage provides [storage classes](https://docs.nebius.com/object-storage/storage-classes.md) to control settings for stored objects. You can set the default storage class for each bucket and upload individual objects to specific classes. In addition, you can [set up lifecycle rules](https://docs.nebius.com/object-storage/objects/lifecycles.md) to transition objects between classes. ### URLs Use the following templates to access an object: * {`https://storage..nebius.cloud//`} * {`http://.storage..nebius.cloud/`} For example, the URL for the `requests.txt` object in the `training-artifacts` bucket located in eu-north1 (Finland) is: ```url https://storage.eu-north1.nebius.cloud/training-artifacts/requests.txt ``` ### Encryption Nebius enforces strong encryption across all layers of data handling: * **At rest:** all objects in Object Storage are encrypted using AES-256 by default. * **In transit:** all communications use HTTPS (TLS 1.2 or higher). ## Actions with buckets and objects In your project, you can [create buckets](https://docs.nebius.com/object-storage/buckets/manage.md), [upload objects](https://docs.nebius.com/object-storage/objects/upload-download.md#how-to-upload) to them and [download objects](https://docs.nebius.com/object-storage/objects/upload-download.md#how-to-download) from your buckets. # How to get started with Object Storage: Create your first bucket Source: https://docs.nebius.com/object-storage/quickstart.md Most ML/AI workloads involve large files, such as datasets and artifacts of trained models. To efficiently store, access and share them, you can use Object Storage, a simple storage service offered by Nebius AI Cloud. In this guide, you will learn how to start using Object Storage. You will set up your environment to work with Object Storage, create your first *bucket*, a data container and upload a test file. For visual guidance on creating a bucket and uploading objects in the web console, watch the video below. If you prefer other interfaces or written instructions, follow the steps further down.