[Yandex Cloud documentation](../../index.md) > [Tutorials](../index.md) > [Container infrastructure](index.md) > Running a Docker image on a VM using Cloud Registry

# Running a Docker image on a VM using Yandex Cloud Registry

In this tutorial, you will deploy a [Docker image](../../cloud-registry/concepts/artifacts/docker.md) from a [registry](../../cloud-registry/concepts/registry.md) in Yandex Cloud Registry and run a container on a Yandex Compute Cloud VM instance.

To run a Docker image on a VM:

1. [Get your cloud ready](#before-you-begin).
1. [Create a registry in Cloud Registry](#create-registry).
1. [Create a service account](#create-sa).
1. [Create an authorized key for the service account](#create-authorized-key).
1. [Create a cloud network with a subnet](#create-network).
1. [Create a VM](#create-vm).
1. [Build a Docker image and push it to Cloud Registry](#create-image).
1. [Push the Docker image to the VM](#run).

If you no longer need the resources you created, [delete them](#clear-out).


## Get your cloud ready {#before-you-begin}

Sign up for Yandex Cloud and create a [billing account](../../billing/concepts/billing-account.md):
1. Navigate to the [management console](https://console.yandex.cloud) and log in to Yandex Cloud or create a new account.
1. On the **[Yandex Cloud Billing](https://center.yandex.cloud/billing/accounts)** page, make sure you have a billing account linked and it has the `ACTIVE` or `TRIAL_ACTIVE` [status](../../billing/concepts/billing-account-statuses.md). If you do not have a billing account, [create one](../../billing/quickstart/index.md) and [link](../../billing/operations/pin-cloud.md) a cloud to it.

If you have an active billing account, you can create or select a [folder](../../resource-manager/concepts/resources-hierarchy.md#folder) for your infrastructure on the [cloud page](https://console.yandex.cloud/cloud).

[Learn more about clouds and folders here](../../resource-manager/concepts/resources-hierarchy.md).


### Required paid resources {#paid-resources}

The cost of resources for running a Docker image includes:

* Fee for a continuously running VM (see [Yandex Compute Cloud pricing](../../compute/pricing.md)).
* Fee for storing created images (see [Yandex Cloud Registry pricing](../../cloud-registry/pricing.md)).
* Fee for outbound traffic from Yandex Cloud to the internet (see [Yandex Compute Cloud pricing](../../compute/pricing.md)).


### Create an SSH key pair {#create-ssh}

Prepare an SSH key for [VM access](../../compute/operations/vm-connect/ssh.md).

{% list tabs group=operating_system %}

- Linux/macOS {#linux-macos}

  1. Open the terminal.
  1. Use the `ssh-keygen` command to create a new key:
  
      ```bash
      ssh-keygen -t ed25519 -C "<optional_comment>"
      ```
  
      You can specify an empty string in the `-C` parameter to avoid adding a comment, or you may not specify the `-C` parameter at all: in this case, a default comment will be added.
  
      After running this command, you will be prompted to specify the name and path to the key files, as well as enter the password for the private key. If you only specify the name, the key pair will be created in the current directory. The public key will be saved in a file with the `.pub` extension, while the private key, in a file without extension.
  
      By default, the command prompts you to save the key under the `id_ed25519` name in the following directory: `/home/<username>/.ssh`. If there is already an SSH key named `id_ed25519` in this directory, you may accidentally overwrite it and lose access to the resources it is used in. Therefore, you may want to use unique names for all SSH keys.

- Windows 10/11 {#windows}

  If you do not have [OpenSSH](https://en.wikipedia.org/wiki/OpenSSH) installed yet, follow this [guide](https://learn.microsoft.com/en-us/windows-server/administration/openssh/openssh_install_firstuse?tabs=gui) to install it.
  
  1. Run `cmd.exe` or `powershell.exe` (make sure to update PowerShell before doing so).
  1. Use the `ssh-keygen` command to create a new key:
  
      ```shell
      ssh-keygen -t ed25519 -C "<optional_comment>"
      ```
  
      You can specify an empty string in the `-C` parameter to avoid adding a comment, or you may not specify the `-C` parameter at all: in this case, a default comment will be added.
  
      After running this command, you will be prompted to specify the name and path to the key files, as well as enter the password for the private key. If you only specify the name, the key pair will be created in the current directory. The public key will be saved in a file with the `.pub` extension, while the private key, in a file without extension.
  
      By default, the command prompts you to save the key under the `id_ed25519` name in the following folder: `C:\Users\<username>/.ssh`. If there is already an SSH key named `id_ed25519` in this directory, you may accidentally overwrite it and lose access to the resources it is used in. Therefore, you may want to use unique names for all SSH keys.

- Windows 7/8 {#windows7-8}

  Create keys using the PuTTY app:
  
  1. [Download](https://www.putty.org) and install PuTTY.
  1. Add the folder with PuTTY to the `PATH` variable:
  
      1. Click **Start** and type **Change system environment variables** in the Windows search bar.
      1. Click **Environment Variables...** at the bottom right.
      1. In the window that opens, find the `PATH` parameter and click **Edit**.
      1. Add your folder path to the list.
      1. Click **OK**.
  
  1. Launch the PuTTYgen app.
  1. Select **EdDSA** as the pair type to generate. Click **Generate** and move the cursor in the field above it until key creation is complete.
  
      ![ssh_generate_key](../../_assets/compute/ssh-putty/ssh_generate_key.png)
  
  1. In **Key passphrase**, enter a strong password. Enter it again in the field below.
  1. Click **Save private key** and save the private key. Do not share its key phrase with anyone.
  1. Click **Save public key** and save the public key to a file named `<key_name>.pub`.

{% endlist %}

{% note warning %}

Store your private key securely, as you will not be able to connect to the VM without it.

{% endnote %}


### Install and configure Docker {#configure-docker}

{% list tabs group=operating_system %}

- Linux {#linux}

    1. Install Docker Engine. Use [this guide](https://docs.docker.com/engine/install/#supported-platforms) to install and run Docker for your operating system.

    1. After the installation is complete, add the current user to the `docker` group:

        ```bash
        sudo groupadd docker
        sudo usermod -aG docker $USER
        newgrp docker
        ```

    For groups to update successfully, you may need to log back into the OS or reboot the computer.

    For information about additional Docker settings for Linux, see the [developer documentation](https://docs.docker.com/engine/install/linux-postinstall/).

    If you are working on a device with a GUI, you can also [install](https://docs.docker.com/desktop/install/linux-install/) Docker Desktop for Linux.

- macOS {#macos}

  [Download](https://docs.docker.com/get-docker/) and install the Docker Desktop distribution for macOS. For more information, see the [developer documentation](https://docs.docker.com/desktop/install/mac-install/).

- Windows {#windows}

    1. [Download](https://docs.docker.com/get-docker/) and install the Docker Desktop distribution for Windows.

    1. After the installation is complete, add the current user to the `docker-users` group:

        1. Run **Computer Management** as administrator:

            ```powershell
            compmgmt.msc
            ```
        
        1. Expand the **(Local) Computer Management** menu, then go **Utilities** → **Local Users and Groups** → **Groups** and open the `docker-users` group.
        1. Click **Add** and add the required user to the group.
        1. Click **OK**.
    1. Run Docker Desktop and make sure the app's status is `running`.

    For information about additional Docker settings for Windows, see the [developer documentation](https://docs.docker.com/desktop/install/windows-install/).

{% endlist %}


## Create a registry in Cloud Registry {#create-registry}

Create a registry for storing Docker images.

{% list tabs group=instructions %}

- Management console {#console}

  1. In the [management console](https://console.yandex.cloud), select the [folder](../../resource-manager/concepts/resources-hierarchy.md#folder) you want to create a registry in.
  1. Navigate to **Cloud Registry**.
  1. Click **Create registry**.
  1. Select ![image](../../_assets/console-icons/logo-docker.svg) **Docker** for the format.
  1. Set the registry type to **Local**.
  1. Enter a name for the registry. The naming requirements are as follows:

      * It must be from 3 to 62 characters long.
      * It can only contain lowercase Latin letters, numbers, and hyphens.
      * It must start with a letter and cannot end with a hyphen.

  1. Click **Create**.

- CLI {#cli}

  If you do not have the Yandex Cloud CLI yet, [install and initialize it](../../cli/quickstart.md#install).

  The folder used by default is the one specified when [creating](../../cli/operations/profile/profile-create.md) the CLI profile. To change the default folder, use the `yc config set folder-id <folder_ID>` command. You can also specify a different folder for any command using `--folder-name` or `--folder-id`. If you access a resource by its name, the search will be limited to the default folder. If you access a resource by its ID, the search will be global, i.e., through all folders based on access permissions.

  1. See the description of the CLI command for creating a registry:

      ```bash
      yc cloud-registry registry create --help
      ```

  1. Create a registry:

      ```bash
      yc cloud-registry registry create \
        --name docker-ycr \
        --description "Created with CLI" \
        --registry-kind docker \
        --registry-type local
      ```

      Result:

      ```text
      id: cn191rncdrhd********
      folder_id: b1g681qpemb4********
      name: docker-ycr
      kind: DOCKER
      type: LOCAL
      status: ACTIVE
      description: Created with CLI
      created_at: "2025-12-12T04:56:32.681439Z"
      modified_at: "2025-12-12T04:56:34.171714Z"
      ```

- API {#api}

  Use the [create](../../cloud-registry/api-ref/Registry/create.md) REST API method for the [Registry](../../cloud-registry/api-ref/Registry/index.md) resource or the [RegistryService/Create](../../cloud-registry/api-ref/grpc/Registry/create.md) gRPC API call.

{% endlist %}


## Create a service account {#create-sa}

Create a [service account](../../iam/concepts/users/service-accounts.md) you will use to pull the Docker image to the VM. Assign it the `cloud-registry.artifacts.puller` [role](../../cloud-registry/security/index.md#cloud-registry-artifacts-puller) for the created registry.

{% list tabs group=instructions %}

- Management console {#console}

  1. In the [management console](https://console.yandex.cloud), select the relevant folder.
  1. Navigate to **Identity and Access Management**.
  1. Click **Create service account**.
  1. Name the [service account](../../iam/concepts/users/service-accounts.md): `docker-puller`.
  1. Click **Create**.
  1. Navigate to **Cloud Registry**.
  1. Select the previously created registry.
  1. Navigate to the ![image](../../_assets/console-icons/persons.svg) **Access bindings** tab.
  1. Click **Assign roles**.
  1. In the window that opens, select the `docker-puller` service account.
  1. Click ![image](../../_assets/console-icons/plus.svg) **Add role** and select `cloud-registry.artifacts.puller`.
  1. Click **Save**.

- CLI {#cli}

  1. Create a service account:

      ```bash
      yc iam service-account create --name docker-puller
      ```

      Result:

      ```text
      id: ajelabcde12f********
      folder_id: b0g12ga82bcv********
      created_at: "2020-11-30T14:32:18.900092Z"
      name: docker-puller
      ```

  1. Assign the `cloud-registry.artifacts.puller` role to the service account:

      ```bash
      yc cloud-registry registry add-access-binding <registry_name_or_ID> \
        --role cloud-registry.artifacts.puller \
        --subject serviceAccount:<service_account_ID>
      ```

      Where `--subject` is the `docker-puller` service account ID.

      Result:

      ```text
      ...1s...done (5s)
      ```

- API {#api}

  1. To create a service account, use the [create](../../iam/api-ref/ServiceAccount/create.md) REST API method for the [ServiceAccount](../../iam/api-ref/ServiceAccount/index.md) resource.
  1. To assign the service account a role for the registry, use the [updateAccessBindings](../../cloud-registry/api-ref/Registry/updateAccessBindings.md) REST API method for the [Registry](../../cloud-registry/api-ref/Registry/index.md) resource.

{% endlist %}

## Create an authorized key for the service account {#create-authorized-key}

Create an [authorized key](../../iam/concepts/authorization/key.md) for the `docker-puller` service account An authorized key will allow the service account to get an IAM token for authentication in the Yandex Cloud API.

{% list tabs group=instructions %}

- Management console {#console}

  1. Navigate to **Identity and Access Management**.
  1. In the list that opens, select the `docker-puller` service account.
  1. In the top panel, click ![plus](../../_assets/console-icons/plus.svg) **Create new key** and select `Create authorized key`.
  1. Click **Create**.
  1. In the window that opens, click **Download file with keys** and then **Close**

  The action will download to your computer a file named `authorized_key.json` containing the authorized key. You will need this key later to set up Docker on your VM.

- CLI {#cli}

  Run this command:

  ```bash
  yc iam key create \
    --service-account-name docker-puller \
    -o authorized_key.json
  ```

  Result:

  ```text
  id: ajetn5b1efv2********
  service_account_id: ajefbp899mcl********
  created_at: "2025-12-17T04:57:16.241850455Z"
  key_algorithm: RSA_2048
  ```

  The action will download to your computer a file named `authorized_key.json` containing the authorized key. You will need this key later to set up Docker on your VM.

- API {#api}

  Use the [create](../../iam/api-ref/Key/create.md) REST API method for the [Key](../../iam/api-ref/Key/index.md) resource or the [KeyService/Create](../../iam/api-ref/grpc/Key/create.md) gRPC API call.

{% endlist %}


## Create a cloud network with a subnet {#create-network}

Create a [cloud network](../../vpc/concepts/network.md) with a [subnet](../../vpc/concepts/network.md#subnet) to host the VM.

{% list tabs group=instructions %}

- Management console {#console}

  1. Navigate to **Virtual Private Cloud**.
  1. Click **Create network**.
  1. In the **Name** field, specify `docker-ycr-network`.
  1. In the **Advanced** field, disable **Create subnets**.
  1. Click **Create network**.
  1. Select `vipnet-network`.
  1. Click ![image](../../_assets/console-icons/nodes-right.svg) **Create subnet** at the top right.
  1. In the **Name** field, specify `docker-ycr-subnet-ru-central1-b`.
  1. In the **Availability zone** field, select `ru-central1-b`.
  1. In the **CIDR** field, specify `192.168.1.0/24`.
  1. Click **Create subnet**.

- CLI {#cli}

  1. Create a cloud network named `docker-ycr-network`:

      ```bash
      yc vpc network create docker-ycr-network
      ```

      Result:

      ```text
      id: enp1gg8kr3pv********
      folder_id: b1gt6g8ht345********
      created_at: "2023-12-20T20:08:11Z"
      name: docker-ycr-network
      default_security_group_id: enppne4l2eg5********
      ```

      For more information about the `yc vpc network create` command, see the [CLI reference](../../cli/cli-ref/vpc/cli-ref/network/create.md).

  1. Create a subnet in the `ru-central1-b` [availability zone](../../overview/concepts/geo-scope.md):

      ```bash
      yc vpc subnet create docker-ycr-subnet-ru-central1-b \
        --zone ru-central1-b \
        --network-name docker-ycr-network \
        --range 192.168.1.0/24
      ```

      Result:

      ```text
      id: e2li9tcgi7ii********
      folder_id: b1gt6g8ht345********
      created_at: "2023-12-20T20:11:16Z"
      name: docker-ycr-subnet-ru-central1-b
      network_id: enp1gg8kr3pv********
      zone_id: ru-central1-b
      v4_cidr_blocks:
        - 192.168.1.0/24
      ```

      For more information about the `yc vpc subnet create` command, see the [CLI reference](../../cli/cli-ref/vpc/cli-ref/subnet/create.md).

- API {#api}

  1. To create a cloud network, use the [create](../../vpc/api-ref/Network/create.md) REST API method or the [NetworkService/Create](../../vpc/api-ref/grpc/Network/create.md) gRPC API call.
  1. To create a subnet, use the [create](../../vpc/api-ref/Subnet/create.md) REST API method or the [SubnetService/Create](../../vpc/api-ref/grpc/Subnet/create.md) gRPC API call.

{% endlist %}


## Create a VM {#create-vm}

Create a VM with a public IP address and associate it with the service account you created.

{% list tabs group=instructions %}

- Management console {#console}

  1. Navigate to **Compute Cloud**.
  1. Click **Create virtual machine**.
  1. Under **Boot disk image**, select an image and a Linux-based OS version.
  1. Under **Location**, select an [availability zone](../../overview/concepts/geo-scope.md) where your VM will reside.
  1. Under **Network settings**:
      * In the **Subnet** field, select the previously created network and subnet.
      * In the **Public IP address** field, leave the **Auto** value to assign a random external IP address from the Yandex Cloud pool.

  1. Under **Access**, specify the VM access credentials:
      * In the **Login** field, enter a username.
      * In the **SSH key** field, paste the contents of the [public key](../../compute/operations/vm-connect/ssh.md#creating-ssh-keys) file.

  1. Under **General information**, specify the VM name: `docker-vm`.
  1. Under **Additional**, select the `docker-puller` service account you created earlier.
  1. Click **Create VM**.

- CLI {#cli}

  Create a VM in the default folder:

  ```bash
  yc compute instance create \
    --name docker-vm \
    --zone ru-central1-b \
    --network-interface subnet-name=docker-ycr-subnet-ru-central1-b,nat-ip-version=ipv4 \
    --create-boot-disk image-folder-id=standard-images,image-family=ubuntu-2004-lts \
    --ssh-key <public_SSH_key_file_path> \
    --service-account-name docker-puller
  ```

  Where:

  * `--name`: VM name.
  * `--zone`: Availability zone matching the subnet.
  * `subnet-name`: Name of the subnet you created earlier.
  * `image-family`: [Image family](../../compute/concepts/image.md#family).
  * `--ssh-key`: Public SSH key path.
  * `--service-account-name`: Service account name.

  Result:

  ```text
  id: epd6kj8giu79********
  folder_id: b1g681qpemb4********
  created_at: "2025-12-12T16:14:50Z"
  name: docker-vm
  zone_id: ru-central1-b
  platform_id: standard-v2
  resources:
    memory: "2147483648"
    cores: "2"
    core_fraction: "100"
  status: RUNNING
  metadata_options:
    gce_http_endpoint: ENABLED
    aws_v1_http_endpoint: ENABLED
    gce_http_token: ENABLED
    aws_v1_http_token: DISABLED
  boot_disk:
    mode: READ_WRITE
    device_name: epdvqn83lud9********
    auto_delete: true
    disk_id: epdvqn83lud9********
  network_interfaces:
    - index: "0"
      mac_address: d0:0d:**:**:**:**
      subnet_id: e2l8hdblgki4********
      primary_v4_address:
        address: 192.168.1.7
        one_to_one_nat:
          address: 158.***.**.***
          ip_version: IPV4
  serial_port_settings:
    ssh_authorization: OS_LOGIN
  gpu_settings: {}
  fqdn: epd6kj8giu79********.auto.internal
  scheduling_policy: {}
  service_account_id: ajes3g9rg94s********
  network_settings:
    type: STANDARD
  placement_policy: {}
  hardware_generation:
    legacy_features:
      pci_topology: PCI_TOPOLOGY_V2
  application: {}
  ```

- API {#api}

  Use the [Create](../../compute/api-ref/Instance/create.md) REST API method for the [Instance](../../compute/api-ref/Instance/index.md) resource or the [InstanceService/Create](../../compute/api-ref/grpc/Instance/create.md) gRPC API call.

{% endlist %}


## Build a Docker image and push it to Cloud Registry {#create-image}

Build a Docker image and push it to the registry.

{% list tabs group=programming_language %}

- Bash {#bash}

  1. [Get authenticated](../../cloud-registry/operations/docker/authentication.md) in Cloud Registry.
  1. Create a file called Dockerfile:

      ```bash
      echo "FROM ubuntu:latest" > Dockerfile
      echo "CMD echo 'Hello World'" >> Dockerfile
      ```

  1. Build the Docker image:

      ```bash
      docker build . -t registry.yandexcloud.net/<registry_ID>/ubuntu:hello
      ```

      Where `<registry_ID>` is the ID of the registry you created [earlier](#create-registry).

      Result:

      ```text
      ...
      Successfully built db45********
      Successfully tagged registry.yandexcloud.net/cn1k31pgpovl********/ubuntu:hello
      ```

  1. Push the Docker image to the registry:

      ```bash
      docker push registry.yandexcloud.net/<registry_ID>/ubuntu:hello
      ```

      Result:

      ```text
      e8bc********: Pushed 
      hello: digest: sha256:96d... size: 529
      ```

{% endlist %}


## Push the Docker image to the VM {#run}

Set up the environment on the VM, pull the Docker image, and run it.

{% list tabs group=programming_language %}

- Bash {#bash}

  1. [Connect](../../compute/operations/vm-connect/ssh.md) to the VM over SSH.
  1. [Install](../../cli/quickstart.md#install) the CLI and restart the terminal:

      ```bash
      curl -sSL https://storage.yandexcloud.net/yandexcloud-yc/install.sh | bash
      exec -l $SHELL
      ```

  1. Create a file named `key.json` and paste the contents of the `docker-puller` service account key file to it:

      ```bash
      sudo nano key.json
      ```

  1. Configure the CLI for the service account:

      ```bash
      yc config profile create docker-puller
      yc config set service-account-key key.json
      yc config set folder-id <folder_ID>
      ```

      For `folder-id`, specify the ID of the folder containing the registry.

      Result:

      ```text
      Profile 'docker-puller' created and activated
      ```

  1. Install Docker:

      ```bash
      sudo apt update
      sudo apt install docker.io
      ```

  1. Add the current user to the `docker` group and disconnect from the VM:

      ```bash
      sudo usermod -aG docker $USER
      exit
      ```

  1. [Reconnect](../../compute/operations/vm-connect/ssh.md) to the VM over SSH.
  1. Set up Docker:

      ```bash
      mkdir -p ~/.docker
      cat > ~/.docker/config.json <<'EOF'
      {
        "credHelpers": {
          "registry.yandexcloud.net": "yc"
        }
      }
      EOF

      sudo tee /usr/local/bin/docker-credential-yc >/dev/null <<'EOF'
      #!/usr/bin/env bash
      exec yc cloud-registry docker-credential "$@"
      EOF

      sudo chmod +x /usr/local/bin/docker-credential-yc
      ```

  1. Push the Docker image to the VM:

      ```bash
      docker pull registry.yandexcloud.net/<registry_ID>/ubuntu:hello
      ```

      Result:

      ```text
      hello: Pulling from cn191rncdrhd********/ubuntu
      02de********: Pull complete
      Digest: sha256:96d...
      Status: Downloaded newer image for registry.yandexcloud.net/cn191rncdrhd********/ubuntu:hello
      registry.yandexcloud.net/cn191rncdrhd********/ubuntu:hello
      ```

  1. Run the Docker image:

      ```bash
      docker run registry.yandexcloud.net/<registry_ID>/ubuntu:hello
      ```

      Result:

      ```text
      Hello World
      ```

{% endlist %}


## How to delete the resources you created {#clear-out}

Delete the resources you no longer need to avoid [paying](#paid-resources) for them:

1. [Delete](../../compute/operations/vm-control/vm-delete.md) the VM.
1. [Delete](../../vpc/operations/address-delete.md) the static public IP address if you reserved one.
1. Delete the [network](../../vpc/operations/network-delete.md) and the [subnets](../../vpc/operations/subnet-delete.md).
1. Delete the [Docker image](../../cloud-registry/concepts/artifacts/docker.md) from the registry.
1. Delete the [registry](../../cloud-registry/concepts/registry.md).


#### See also {#see-also}

* [Working with Cloud Registry](../../cloud-registry/operations/index.md)
* [Creating a VM from a Container Optimized Image](../../cos/tutorials/vm-create.md)