# Build Custom Templates

Exoscale provides various Compute instance [templates][templates] to choose
from. However, you might want to customize templates to further suit your needs.

In addition to using a 
[Cloud-Init configuration]({{< ref "product/compute/instances/how-to/custom-templates/#cloud-init" >}}) via an
instance's user data or using a configuration management tool such as
[Puppet][puppet] or [Ansible][ansible], you can also create your own customized
templates.

You can use custom templates to launch a custom operating system or custom
template configuration on Exoscale, which allows you to deploy ready-to-go
instances with minimal startup configuration.


## Create a Custom Template

### Using Packer

HashiCorp [Packer][packer] is a popular tool for building cloud infrastructure
compute images, which is the recommended method for creating custom templates
on Exoscale.

Starting from version 1.7, Packer supports a new `packer init` command which
allows automatic installation of Packer plugins, including the
`exoscale` [plugin][packer-exoscale-plugin]. You can read the
[Packer documentation][packer-doc-init] for more information.


#### Snapshot Instance Disk Using the `exoscale` Packer Builder (recommended)

The `exoscale` [Packer Builder][gh-exoscale-packer-builder-doc] creates an
instance in your Exoscale organization, logs into it via SSH to execute
configured provisioners, and then snapshots the storage volume of the instance
to register a custom template from the exported snapshot. This is the easiest
way to create custom templates if you can use an existing Exoscale template as
a base image.

#### Import a Disk Image Using the `exoscale-import` Packer Post-processor

The `exoscale-import` [Packer Post-processor][gh-exoscale-packer-post-processor-doc]
takes a local disk image file (built using the Packer
[QEMU][packer-builder-qemu-doc] or [File][packer-builder-file-doc] Builders)
and imports it to Exoscale as a new Compute instance template. This method is
useful if you need to build custom templates that are not based on an existing
Exoscale template.


### Manually

If you cannot use Packer, it is possible to build disk images and register
them as custom templates manually.


#### Prerequisites

- The template image must be a **true** KVM-compatible .QCOW2 image (if you just
rename your `.img`, `.iso` or `.vdmk` file, your template will fail).
- The image must have the preallocation mode set to `off`.
- The virtual size of the image must be between 10 GB and 1 TB. This size may
differ from the actual file size, but the QCOW2 format must be within this range.
- To deploy machines with attached local storage larger than 1.6 TB, you need a
GPT partitioning table and UEFI boot.
- To be registered, the template must be hosted on a publicly accessible HTTP or
HTTPS URL, such as Exoscale [Object Storage](https://www.exoscale.com/object-storage/).
- We strongly encourage you to [install cloud-init](#cloud-init) to get full
functionality.

KVM/QEMU tools are also required if you need to prepare your template to comply
to specific requirements. For example, to convert a third party template from
the `raw` format to QEMU .QCOW2 format:

```bash
qemu-img convert -f raw -O qcow2 -o preallocation=off source.img destination.qcow2
```

Additionally, you may need to resize the image to fit the minimum size required
by Exoscale:

```bash
qemu-img resize destination.qcow2 10G
```

We have Packer configuration examples in a [Git repository][packerex] to
help you get started using the `exoscale-import` custom template building method.


#### Cloud-Init

Although not mandatory, **we strongly recommend** you install
[cloud-init 19.3 or later][cloudinit] on Linux-based images. Cloud-init enables
full integration with Exoscale. We can only provide limited support if you do
not install cloud-init.

Known limitations **if you do not use cloud-init** on your template:

- The password reset functionality will not work
- During startup, the instance will not be able to resize the partition table on
the fly to match the desired VM local storage size. You will have to manually
resize the partition table and the filesystem
- Without cloud-init it will not be possible to pass user data to the instance
at boot
- The Exoscale Portal will present some inconsistencies and limited functionality

We will show an example with cloud-init 19.3, the native Exoscale cloud-init
datasource. During startup, cloud-init will determine the appropriate datasource
(Exoscale) by reading desktop management interface (DMI) information. No
specific customization is needed.

You can take a look at our documentation to learn more about 
[cloud-init]({{< ref "product/compute/instances/how-to/cloud-init-user-data/" >}}).

> [!NOTE]
> The Exoscale datasource is only available for cloud-init version 19.3 or later. In case the 19.3 version is not yet available on > your platform, please use the following legacy configuration instead:

```yaml
  datasource_list:
    - Cloudstack
```

> [!NOTE]
> Please note that the legacy datasource suffers from some known problems that might prevent some 
> Exoscale features from working as intended**.

#### Virtual Disk Size

The template's *Virtual Disk Size* will determine the initial space available
to the filesystem. Your template needs to have the ability to automatically
adapt the filesystem disk size to the actual volume size in order to use the
entire space at startup. Namely, it needs:

1. A template has a virtual disk size of 10 GB
2. The template is used to start an instance with a disk size of 200 GB
3. Without the ability to scale automatically, the filesystem has only 10 GB
available, and an extra non-partitioned and non-used space of 190 GB
4. You will still be invoiced for the full volume size, which is 200 GB

This ability is enabled through [cloud-init](#cloud-init). You can adapt your
filesystem partitions manually, but its important to keep these points in mind
to avoid unexpected results or billing changes.


#### Register a Custom Template

After your template image is ready, you must host it on a publicly accessible
HTTPS service such as Exoscale [Object Storage]({{< ref "/product/storage/object-storage/" >}}), as you will need to a
URL to point to during template registration.

You can register a template using the `exo` [CLI]({{< ref "/tools/command-line-interface/" >}}), the API, or the
Portal in the Templates section. The following information is required to
register a template:

* The template name
* The template image file checksum (MD5) to ensure import integrity
* The template location (a public URL to retrieve the template)

> [!NOTE]
> If the `from-snapshot` flag is used, the `url` and `checksum` flags are no longer required.

There are also optional properties you can set:

* A template description
* Whether the template allows user 
[password reset]({{< ref "/product/compute/instances/how-to/cloud-init-user-data/#adding-password-management-to-your-templates" >}})
* Whether the template allows a 
[SSH key]({{< ref "/product/compute/instances/how-to/ssh-keypairs/" >}}) to be copied during instance creation
* A username: this is used to better integrate with Exoscale tools, such as the
instance details view in the Portal or the CLI. This will allow shortcuts and
commands that connect to the instance to be correctly displayed.
* A template boot-mode (Legacy or UEFI)

Note: a Custom Template is registered per [zone][zone]. If you want to use your
template in multiple zones, you have to repeat this step for each zone you want
the template to be used in.

This is what a template registration looks like in the CLI:

```bash
exo compute instance-template register   \
    my-custom-template                     \
    https://example.net/my-template.qcow2  \
    15dc21cc9505a68cc0380a9a66654536       \
    --zone de-fra-1                        \
    --description "My custom template"     \
    --username "foo"
```

You can run the `exo compute instance-template --help` command for more
information on commands and options.

After you register your custom template, you can use the template to deploy an
instance with all Exoscale tools - the Portal, the CLI, the API or third-party
integrations.


#### From a Compute Instance Snapshot

In addition to building a custom template from scratch, you can also export a
Compute instance volume snapshot and register the exported file as you would do
with a manually created disk image. This allows you to effectively build a
template from a snapshot:

```bash
SNAPSHOT_ID=ce295d39-421e-49c4-81f7-9890c3db3600
TEMPLATE_ID=$(exo compute instance snapshot show --output-template {{.ID}} $SNAPSHOT_ID)
$ BOOTMODE=$(exo compute instance-template show --output-template {{.BootMode}} ${TEMPLATE_ID})
$ USERNAME=$(exo compute instance-template show --output-template {{.DefaultUser}} ${TEMPLATE_ID})
exo compute instance-template register \
    my-template \
    --zone de-fra-1 \
    --from-snapshot $SNAPSHOT_ID \
    --description "A template registered from a snapshot" \
    --boot-mode $BOOTMODE \
    --username $USERNAME
```

Output:

```bash
 ✔ Registering template "my-template"... 11m21s
┼──────────────────┼──────────────────────────────────────┼
│     TEMPLATE     │                                      │
┼──────────────────┼──────────────────────────────────────┼
│ ID               │ 0a7bfba5-9854-479b-8095-676ca73bcfcd │
│ Name             │ my-template                          │
│ Description      │ A template registered from a snapshot│
│ Family           │ other (64-bit)                       │
│ Creation Date    │ 2021-09-17 13:17:46 +0000 UTC        │
│ Visibility       │ private                              │
│ Size             │ 10 GiB                               │
│ Version          │                                      │
│ Build            │                                      │
│ Default User     │ centos                               │
│ SSH key enabled  │ true                                 │
│ Password enabled │ true                                 │
│ Boot Mode        │ legacy                               │
│ Checksum         │ 33d592a033bfe0aefafafeb0834d37d9     │
┼──────────────────┼──────────────────────────────────────┼
```

We have a blog post on [creating templates from snapshots][snapshottemplatepost]
if you want to learn more.

### Based on an ISO File

- Create a Linux [instance]({{< ref "/product/compute/instances/quick-start/" >}}) on the Exoscale Portal

- Install KVM, virt-manager and all necessary packages to configure a virtual instance.

- Download your ISO file on your instance


> [!NOTE]
> If you are using a Mac, you will need to install xquartz and reboot your machine.

- Connect to your instance using -Y option

- Make sure to add your user to the libvirt group

- Now that everything is set, you can start creating a new virtual machine (graphically):

```bash
virt-manager
```

Gives you the following selections:

```bash
Create new VM
Local browse for iso file
Begin Installation
```

You can refer to this article on *Tecmint* on
[how to create virtual machines in KVM using Virt-Manager](https://www.tecmint.com/create-virtual-machines-in-kvm-using-virt-manager/) 
for additional information.


> [!NOTE]
> Those actions can also be performed using Virtualbox or VMware.

- After installation is finished, an image will be created (.qcow2 file)

- Resize the image

```bash
qemu-img convert -C -O qcow2 -p source.qcow2 target.qcow2
```

- Calculate an MD5 checksum for registration

- Refer to Register a Custom Template (previous section)

## Limitations

- Custom Templates actively used by an instance cannot be deleted.
- Compute instances that run a Custom Template cannot be moved from one organization to another, as Custom Templates are organization-specific.
- Templates not using cloud-init will not integrate entirely with Exoscale, and require manual handling. See the [cloud init]({{< ref "/product/compute/instances/how-to/custom-templates#cloud-init" >}}) section for more details.

[templates]: https://www.exoscale.com/templates/
[puppet]: https://www.puppet.com/
[ansible]: https://www.redhat.com/en/ansible-collaborative
[packer]: https://developer.hashicorp.com/packer
[packer-doc-init]: https://developer.hashicorp.com/packer/docs/commands/init
[exopricing]: https://www.exoscale.com/pricing/
[gh-exoscale-packer-builder-doc]: https://github.com/exoscale/packer-plugin-exoscale/blob/main/docs/builders/exoscale.md
[packer-exoscale-plugin]: https://github.com/exoscale/packer-plugin-exoscale
[gh-exoscale-packer-post-processor-doc]: https://developer.hashicorp.com/packer/docs/commands/init
[packer-builder-qemu-doc]: https://github.com/exoscale/packer-plugin-exoscale/blob/main/docs/builders/exoscale.md
[packer-builder-file-doc]: https://developer.hashicorp.com/packer/docs/builders/file
[packerex]: https://github.com/exoscale/packer-examples
[cloudinit]: https://cloudinit.readthedocs.io/en/latest/index.html
[zone]: https://www.exoscale.com/datacenters/
[snapshottemplatepost]: https://www.exoscale.com/blog/exporting-snapshot-custom-template/

