# Custom VM images

This guide explains how to create a custom **Virtual machine (VM)** image and use it as a sandbox host in a track.

## Advantages of custom VMs

#### Faster and more reliable

The main benefit of using a custom VM image is that it allows you to pre-install your software and the files needed for a track. Your track will start faster, since software does not need to be installed as part of the track setup script.

#### Increased image size

Custom images can be have any disk size you like and are not restricted to the default 10GB that ships with the stock Instruqt images.

## Custom VM image requirements

For custom VM images to work as part of an Instruqt sandbox environment, the following requirements need to be met:

* Google guest environment needs to be installed
  * The guest environment is used to bootstrap the VM into the sandbox environment, by injecting a metadata startup script.
* Allows TCP traffic to the Instruqt agent listening on ports 15778 and 15779
  * These ports are used to facilitate [Terminal and Editor tabs](https://docs.instruqt.com/tracks/challenges/challenge-tabs) for end users, as well as running [lifecycle scripts](https://docs.instruqt.com/sandboxes/lifecycle-scripts) by the platform.

## Create custom VM images

There are two ways to create a custom VM image:

* [Using the Instruqt Host images ](#instruqt-host-images)
* [Using your own GCP project](#using-your-own-gcp-project)

{% hint style="info" %}
We recommend using Instruqt Host images if you are not familiar with Google Cloud, or want to avoid the complexity of managing a cloud account.
{% endhint %}

### Instruqt Host images

Instruqt Host images allow you to create VM images directly inside your Instruqt team. You create Host images using the Web UI.&#x20;

{% tabs %}
{% tab title="🌐 Web UI" %}

1. Click **Settings** → **Host images**.
2. Click **Create image** in the upper-right corner.&#x20;
3. On the *Image* details page, enter an image name, and optionally provide a description and disk size (the default disk is 10GB).
4. Select a base image. You can use an Instruqt preset image, or choose your own.
   * Custom image names follow a `PROJECT_ID/IMAGE_NAME` format.
   * [Here is a helpful link for finding public images](https://cloud.google.com/compute/docs/images#os-compute-support)
5. At the bottom of the page, click **Next.**
6. On the *Customize your image* page, use the terminal and code editor tabs to edit your image by running install commands, adding files, etc.&#x20;
7. Once you've finished customizing your image, click **Save** in the upper-right corner.
8. You can now reference your image in your sandboxes.
   * Instruqt host images follow a `TEAM_NAME/IMAGE_NAME` format.
     {% endtab %}
     {% endtabs %}

{% hint style="info" %}
Need to edit an existing host image? Open the *Host images* page. Select the image you want to edit. Click **Edit** in the top right corner, and then follow Step 3-7 again.&#x20;
{% endhint %}

### Using your own GCP project

#### Before you begin

You should have a **Google Cloud Platform (GCP)** project available or have your GCP admin [create a GCP project](https://developers.google.com/workspace/marketplace/create-gcp-project) for you.

{% hint style="warning" %}
**Importing an existing image?**\
If you are importing an existing image to GCP make sure to install the [Google Guest Environment](https://cloud.google.com/compute/docs/images/install-guest-environment) in your image. Instruqt requires the guest environment to bootstrap VMs.
{% endhint %}

{% tabs %}
{% tab title="☁️ Google Cloud Console" %}

#### Step 1: Create a VM

1. Open your browser and navigate to your GCP project on the Google Cloud Platform.
2. Click **Compute Engine** → **VM instances**.
3. Click **\[+] CREATE INSTANCE**.
4. In the **Name** field, enter a name of your liking (ex: **my-build-instance**).
5. Click **Change** under *Boot disk*.
6. In the **Operating system** list, select your desired OS (ex: **Ubuntu**).
7. In the **Version** list, select the desired OS version (ex: **Ubuntu 23.04 LTS**).
8. Click **Select**.
9. Click **Create**.

#### Step 2: Customize the VM

1. Click **SSH** on the VM instance you created in step 1.\
   ↳ This opens a new `SSH-IN-BROWSER` window.
2. Modify your VM by running whatever commands you'd like.&#x20;
3. Close the terminal.
4. Click ••• on your newly created VM instance, followed by **Stop**. And click **Stop** to confirm.

#### Step 3: Create an image

1. Under **Storage**, click **Images** on the navigation menu.
2. Click **\[+] Create Image.**
3. In the **Name** field, enter a name of your liking (ex: **ubuntu23-custom**).
4. In the **Source Disk** list, select the disk from your instance (ex: **my-build-instance**).
5. For **Location**, choose **Regional.**
6. In the **Select location** list, select **europe-west1 (Belgium)**.
7. Click **Create.**\
   ↳ The custom image is built for you and shown on the *Image page*. Your custom image is ready when the *Status* column shows a green checkmark.

{% hint style="danger" %}
In Google Cloud there are *Disk Images* and *Machine Images*. In this guide, we only work with *Disk Images.* **Machine Images will not work in Instruqt.**
{% endhint %}

#### Step 4: Grant permissions to Instruqt

1. Click **IAM & Admin** → **IAM** on the navigation menu.
2. Click  **+ Grant access** to add a new principal.
3. In the **New principals** field, enter the following:\
   `instruqt-track@instruqt-prod.iam.gserviceaccount.com`
4. In the **Select a role** list, select `Compute Image User`
5. Click **Save**.
   {% endtab %}
   {% endtabs %}

#### Step 5: Use the custom VM image in your track

You are ready to incorporate the custom VM into your track.

Head over to your Web UI or Instruqt CLI to incorporate the custom VM image into your track:

{% tabs %}
{% tab title="🌐 Web UI" %}

1. Open your track from your *Content*.
2. In the **Sandbox** section, click **Edit**.
3. Click **+ Add a host**.
4. Select the **Virtual machine** host type.
5. In the **Hostname** field, enter a name of your liking (ex: `workstation`).
6. Select the **Choose your own** image type.
7. In the **GCP compute image** field, enter `<YOUR-GCPPROJECT-ID>/<YOUR-IMAGE-NAME>`
8. Select a machine type.
9. Click **Show optional settings**.
10. In the **Shell** field, enter `/bin/bash`
11. Click **Save host.**
    {% endtab %}

{% tab title="💻 Instruqt CLI" %}

1. Open the `config.yml` file of your track in your code editor.
2. Enter or adjust the following code into the `config.yml` file:

   ```
   virtualmachines:
   - name: workstation
     image: YOUR_GCPPROJECT_ID/YOUR_IMAGE_NAME
     shell: /bin/bash
     machine_type: n1-standard-1
   ```

   ⇨ Replace `YOUR_GCPPROJECT_ID` and `YOUR_IMAGE_NAME` with your GCP project id and image name (ex: `root-fort-99999/ubuntu22-openjdk11).`
3. Save the `config.yml` file and [deploy your track](https://docs.instruqt.com/sandboxes/hosts/broken-reference) to the Instruqt platform.

Now you can add a Terminal tab to a challenge and refer in this tab to the new host.
{% endtab %}
{% endtabs %}

#### Video tutorial

Watch the video tutorial on how to use your own GCP project to host VM images.

{% embed url="<https://drive.google.com/file/d/1hwgdx8PDMUKr5Ao_Rsm1_JhIYZOGzjkO/view?usp=sharing>" %}
Video walkthrough of creating a custom image.
{% endembed %}

{% hint style="info" %}
**Automate image building**

[Packer](https://www.packer.io/) is an open-source tool for creating identical VM images for multiple platforms from a single source configuration. See the [Google Cloud documentation](https://cloud.google.com/build/docs/building/build-vm-images-with-packer) for how to build VM images using Packer.
{% endhint %}
