Running a Docker image on a VM using Terraform
To run a Docker image on a VM using a Yandex Container Registry registry via Terraform:
- Prepare your cloud.
- Create an infrastructure.
- Build and upload the Docker image to Container Registry.
- Download the Docker image to a VM.
- Check the result.
If you no longer need the resources you created, delete them.
Prepare your cloud
Sign up for Yandex Cloud and create a billing account:
- Go to the management console
and log in to Yandex Cloud or create an account if you do not have one yet. - On the Yandex Cloud Billing
page, make sure you have a billing account linked and it has theACTIVE
orTRIAL_ACTIVE
status. If you do not have a billing account, create one.
If you have an active billing account, you can go to the cloud page
Learn more about clouds and folders.
Required paid resources
The infrastructure support costs include:
- Fee for a continuously running VM (see Yandex Compute Cloud pricing).
- Fee for using a dynamic or static public IP address (see Yandex Virtual Private Cloud pricing).
- Fee for storing a Docker image in the registry and outgoing traffic (see Yandex Container Registry pricing).
Configure the environment
- Install the Yandex Cloud command line interface.
- Prepare an SSH key for VM access.
- Create a registry in Container Registry and upload a Docker image into it for testing.
- Install and configure Docker.
Create an infrastructure
Terraform
For more information about the provider resources, see the documentation on the Terraform
If you change the configuration files, Terraform automatically detects which part of your configuration is already deployed, and what should be added or removed.
To create an infrastructure using Terraform:
-
Install Terraform, get the authentication credentials, and specify the source for installing the Yandex Cloud provider (see Configure a provider, step 1).
-
Prepare files with the infrastructure description:
Ready-made configurationManually-
Clone the repository
with configuration files:git clone https://github.com/yandex-cloud-examples/yc-run-docker-on-vm.git
-
Go to the directory with the repository. There you should see the
run-docker-on-vm-config.tf
file with the configuration of the infrastructure to create.
-
Create a directory for the file with the infrastructure description.
-
In the directory, create a configuration file named
run-docker-on-vm.tf
:Contents of the run-docker-on-vm.tf file
# Declaring variables for confidential parameters locals { zone = "<default_availability_zone>" username = "<VM_user_name>" ssh_key_path = "<path_to_public_SSH_key>" target_folder_id = "<ID_of_folder_to_place_VM_in>" registry_name = "<registry_name>" sa_name = "<service_account_name>" network_name = "<cloud_network_name>" subnet_name = "<subnet_name>" vm_name = "<VM_name>" image_id = "<image_ID>" } # Configuring a provider terraform { required_providers { yandex = { source = "yandex-cloud/yandex" version = ">= 0.47.0" } } } provider "yandex" { zone = local.zone } # Creating a Container Registry repository resource "yandex_container_registry" "my-registry" { name = local.registry_name folder_id = local.target_folder_id } # Creating a service account resource "yandex_iam_service_account" "registry-sa" { name = local.sa_name folder_id = local.target_folder_id } # Assigning roles to a service account resource "yandex_resourcemanager_folder_iam_member" "registry-sa-role-images-puller" { folder_id = local.target_folder_id role = "container-registry.images.puller" member = "serviceAccount:${yandex_iam_service_account.registry-sa.id}" } # Creating a cloud network resource "yandex_vpc_network" "docker-vm-network" { name = local.network_name } # Creating a subnet resource "yandex_vpc_subnet" "docker-vm-network-subnet-a" { name = local.subnet_name zone = local.zone v4_cidr_blocks = ["192.168.1.0/24"] network_id = yandex_vpc_network.docker-vm-network.id } # Creating a boot disk resource "yandex_compute_disk" "boot-disk" { name = "bootvmdisk" type = "network-hdd" zone = local.zone size = "10" image_id = local.image_id } # Creating a VM instance resource "yandex_compute_instance" "docker-vm" { name = local.vm_name platform_id = "standard-v3" zone = local.zone service_account_id = "${yandex_iam_service_account.registry-sa.id}" resources { cores = 2 memory = 2 } boot_disk { disk_id = yandex_compute_disk.boot-disk.id } network_interface { subnet_id = "${yandex_vpc_subnet.docker-vm-network-subnet-a.id}" nat = true } metadata = { user-data = "#cloud-config\nusers:\n - name: ${local.username}\n groups: sudo\n shell: /bin/bash\n sudo: 'ALL=(ALL) NOPASSWD:ALL'\n ssh_authorized_keys:\n - ${file("${local.ssh_key_path}")}" } }
For more information about the parameters of resources used in Terraform, see the provider documentation:
-
-
Under
locals
, set the parameters for resources to create:zone
: Availability zone that will host the VM.username
: Name of the user to be created on the VM.ssh_key_path
: Path to the file with a public SSH key to authenticate the user on the VM. For more information, see Creating an SSH key pair.target_folder_id
: ID of the folder to host the VM.registry_name
: Container Registry registry name.sa_name
: Service account name.network_name
: Name of the cloud network.subnet_name
: Subnet name.vm_name
: VM name.image_id
: ID of the image to create the VM from. For more information, see Getting a list of public images.
-
Create resources:
-
In the terminal, change to the folder where you edited the configuration file.
-
Make sure the configuration file is correct using the command:
terraform validate
If the configuration is correct, the following message is returned:
Success! The configuration is valid.
-
Run the command:
terraform plan
The terminal will display a list of resources with parameters. No changes are made at this step. If the configuration contains errors, Terraform will point them out.
-
Apply the configuration changes:
terraform apply
-
Confirm the changes: type
yes
in the terminal and press Enter.
-
After creating the infrastructure, build and upload the Docker image to Container Registry.
Build and upload the Docker image to Container Registry
-
To make command execution easier, add the following variables:
-
Username and your VM's public IP to the
${PUBLIC_IP}
variable:export PUBLIC_IP=<username>@<VM_public_IP_address>
-
ID of the previously created registry in
crpc9qeoft23********
format to the${REGISTRY_ID}
variable:export REGISTRY_ID=<registry_ID>
-
-
Authenticate as yourself:
OAuth tokenIAM tokenDocker credential helper-
If you do not have an OAuth token yet, get one by following this link
. -
Run this command:
echo <OAuth_token> | docker login --username oauth --password-stdin cr.yandex
Result:
Login succeeded
Note
The IAM token has a short lifetime: no more than 12 hours. This makes it a good method for applications that automatically request an IAM token.
-
Get an Identity and Access Management token.
-
Run this command:
yc iam create-token | docker login --username iam --password-stdin cr.yandex
Result:
... Login succeeded
-
If you do not have a YC CLI profile yet, create one.
-
Configure Docker to use
docker-credential-yc
:yc container registry configure-docker
Result:
Credential Helper is configured in '/home/<user>/.docker/config.json'
Settings are saved in the current user's profile.
Warning
Credential Helper only works when using Docker without
sudo
. You can learn how to configure Docker to run under current user withoutsudo
in the official documentation . -
Make sure that Docker is configured.
The following line must appear in the
/home/<user>/.docker/config.json
configuration file:"cr.yandex": "yc"
-
You can now use Docker, for example, to push Docker images. You do not need to run the
docker login
command for that.
-
-
Create a file called Dockerfile:
touch .dockerfile
-
Open Dockerfile in a text editor, e.g.:
nano .dockerfile
-
Add the lines below to the file:
FROM ubuntu:latest CMD echo "Hi, I'm inside"
-
Build a Docker image:
docker build . -t cr.yandex/${REGISTRY_ID}/ubuntu:hello -f .dockerfile
Result:
... Successfully built b68ee9b6b1af Successfully tagged cr.yandex/crpmnjr98tm5********/ubuntu:hello
-
Push the built Docker image to Container Registry:
docker push cr.yandex/${REGISTRY_ID}/ubuntu:hello
Result:
The push refers to repository [cr.yandex/crpc9qeoft23********/ubuntu] cc9d18e90faa: Pushed 0c2689e3f920: Pushed 47dde53750b4: Pushed hello: digest: sha256:42068479274f1d4c7ea095482430dcba24dcfe8c23ebdf6d32305928******** size: 943
Download the Docker image to the VM
-
Use SSH to connect to the VM.
-
Authenticate under the service account tied to the machine:
curl --header Metadata-Flavor:Google 169.254.169.254/computeMetadata/v1/instance/service-accounts/default/token | \ cut -f1 -d',' | \ cut -f2 -d':' | \ tr -d '"' | \ docker login --username iam --password-stdin cr.yandex
Result:
Login Succeeded
-
Download the Docker image to the VM:
docker pull cr.yandex/${REGISTRY_ID}/ubuntu:hello
Result:
hello: Pulling from crpc9qeoft23********/ubuntu 6a5697faee43: Pulling fs layer ba13d3bc422b: Pulling fs layer ... Digest: sha256:42068479274f1d4c7ea095482430dcba24dcfe8c23ebdf6d32305928******** Status: Downloaded newer image for cr.yandex/crpc9qeoft23********/ubuntu:hello cr.yandex/crpc9qeoft23********/ubuntu:hello
Check the result
Run the Docker image on the VM:
docker run cr.yandex/${REGISTRY_ID}/ubuntu:hello
Result:
Hi, I'm inside
How to delete the resources you created
To delete the infrastructure and stop paying for the resources you created:
-
Open the
run-docker-on-vm-config.tf
configuration file and delete from it the description of the infrastructure you created. -
Apply the changes:
-
In the terminal, change to the folder where you edited the configuration file.
-
Make sure the configuration file is correct using the command:
terraform validate
If the configuration is correct, the following message is returned:
Success! The configuration is valid.
-
Run the command:
terraform plan
The terminal will display a list of resources with parameters. No changes are made at this step. If the configuration contains errors, Terraform will point them out.
-
Apply the configuration changes:
terraform apply
-
Confirm the changes: type
yes
in the terminal and press Enter.
-