chore(templates): Added IaaS Instance
This commit is contained in:
6
.gitignore
vendored
Normal file
6
.gitignore
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
.coder/
|
||||
.terraform/
|
||||
.terraform.lock.hcl
|
||||
terraform.tfvars
|
||||
terraform.tfstate
|
||||
terraform.tfstate.backup
|
||||
17
README.md
Normal file
17
README.md
Normal file
@@ -0,0 +1,17 @@
|
||||
# Coder Templates
|
||||
|
||||

|
||||
|
||||
Local registry for [Coder Wokerspaces](https://coder.phorge.fr/)
|
||||
|
||||
## Temaplates
|
||||
|
||||
- [Iaas-Instance](./iaas-instance/README.md) Run Workspaces on [Phorge IaaS](https://iaas.phorge.fr/)
|
||||
|
||||
## Push a new template
|
||||
|
||||
Go into your template, follow the `README.md` and run :
|
||||
|
||||
```bash
|
||||
coder template push <new-template> -d .
|
||||
```
|
||||
56
iaas-instance/README.md
Normal file
56
iaas-instance/README.md
Normal file
@@ -0,0 +1,56 @@
|
||||
> Based on the work of [umair](https://github.com/l-nmch/registry/tree/main/registry/umair)
|
||||
|
||||
# Incus VM Template for Coder
|
||||
|
||||
Provision Linux VMs & Containers on Incus/LXD as [Coder workspaces](https://coder.phorge.fr). The template deploys an instance with cloud-init, and runs the Coder agent under the workspace owner's Linux user.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Incus server / cluster with exposed API
|
||||
|
||||
### Setup the template
|
||||
|
||||
1. Create an Incus trust token:
|
||||
|
||||
```bash
|
||||
incus config trust add coder # Save the token
|
||||
```
|
||||
|
||||
2. Setup an Incus project with a network:
|
||||
|
||||
```bash
|
||||
incus project create Coder -c features.network=true
|
||||
incus network create Main --project Coder
|
||||
```
|
||||
|
||||
3. Prepare `terraform.tfvars` in your environment:
|
||||
|
||||
```py
|
||||
remote_name = "iaas"
|
||||
remote_address = "https://iaas.phorge.fr:443"
|
||||
remote_token = "<token>"
|
||||
|
||||
remote_coder_project = "Coder"
|
||||
remote_coder_network = "Main"
|
||||
remote_coder_storage_pool = "local"
|
||||
remote_coder_profiles = ["1vCPU-1GiB-20GB", "2vCPU-2GiB-20GB"]
|
||||
remote_coder_images = ["images:ubuntu/24.04/cloud", "images:debian/13/cloud", "images:alpine/3.23/cloud"]
|
||||
```
|
||||
|
||||
## Use
|
||||
|
||||
```bash
|
||||
coder template push iaas-instance -d .
|
||||
```
|
||||
|
||||
## Warnings
|
||||
|
||||
Incus often works with cloud image, please use `cloud` tagged images such as `images:ubuntu/22.04/cloud` to be able to use cloud-init (Using non cloud tagged images will lead into your workspaces not working as the coder agent installs through cloud-init)
|
||||
|
||||
## References
|
||||
|
||||
- Incus: [source](https://linuxcontainers.org/incus/)
|
||||
- Incus Terraform Provider: [source](https://registry.terraform.io/providers/lxc/incus/latest/docs)
|
||||
- Coder – Best practices & templates:
|
||||
- https://coder.com/docs/tutorials/best-practices/speed-up-templates
|
||||
- https://coder.com/docs/tutorials/template-from-scratch
|
||||
53
iaas-instance/cloud-init/user-data.tftpl
Normal file
53
iaas-instance/cloud-init/user-data.tftpl
Normal file
@@ -0,0 +1,53 @@
|
||||
#cloud-config
|
||||
hostname: ${hostname}
|
||||
|
||||
users:
|
||||
- name: ${linux_user}
|
||||
groups: [sudo]
|
||||
shell: /bin/bash
|
||||
sudo: ["ALL=(ALL) NOPASSWD:ALL"]
|
||||
|
||||
package_update: false
|
||||
package_upgrade: false
|
||||
packages:
|
||||
- curl
|
||||
- ca-certificates
|
||||
- git
|
||||
- jq
|
||||
|
||||
write_files:
|
||||
- path: /opt/coder/init.sh
|
||||
permissions: "0755"
|
||||
owner: root:root
|
||||
encoding: b64
|
||||
content: |
|
||||
${coder_init_script_b64}
|
||||
|
||||
- path: /etc/systemd/system/coder-agent.service
|
||||
permissions: "0644"
|
||||
owner: root:root
|
||||
content: |
|
||||
[Unit]
|
||||
Description=Coder Agent
|
||||
Wants=network-online.target
|
||||
After=network-online.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=${linux_user}
|
||||
WorkingDirectory=/home/${linux_user}
|
||||
Environment=HOME=/home/${linux_user}
|
||||
Environment=CODER_AGENT_TOKEN=${coder_token}
|
||||
ExecStart=/opt/coder/init.sh
|
||||
OOMScoreAdjust=-1000
|
||||
Restart=always
|
||||
RestartSec=5
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
|
||||
runcmd:
|
||||
- systemctl daemon-reload
|
||||
- systemctl enable --now coder-agent.service
|
||||
|
||||
final_message: "Cloud-init complete on ${hostname}"
|
||||
196
iaas-instance/main.tf
Normal file
196
iaas-instance/main.tf
Normal file
@@ -0,0 +1,196 @@
|
||||
terraform {
|
||||
required_providers {
|
||||
coder = {
|
||||
source = "coder/coder"
|
||||
}
|
||||
incus = {
|
||||
source = "lxc/incus"
|
||||
version = "1.0.2"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
provider "coder" {}
|
||||
|
||||
provider "incus" {
|
||||
accept_remote_certificate = true
|
||||
generate_client_certificates = true
|
||||
default_remote = var.remote_name
|
||||
remote {
|
||||
name = var.remote_name
|
||||
address = var.remote_address
|
||||
token = var.remote_token
|
||||
}
|
||||
}
|
||||
|
||||
variable "remote_name" {
|
||||
description = "Incus remote host/cluster name"
|
||||
type = string
|
||||
default = "remote"
|
||||
}
|
||||
|
||||
variable "remote_address" {
|
||||
description = "Incus remote address (e.g. https://lxc.example.com:8443)"
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "remote_token" {
|
||||
description = "Incus remote API token with permissions to manage instances"
|
||||
type = string
|
||||
sensitive = true
|
||||
}
|
||||
|
||||
variable "remote_coder_project" {
|
||||
description = "Incus remote project to use for instances"
|
||||
type = string
|
||||
default = "default"
|
||||
}
|
||||
|
||||
variable "remote_coder_network" {
|
||||
description = "Incus remote network to attach instances to"
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "remote_coder_profiles" {
|
||||
description = "Incus remote profiles to use for instances"
|
||||
type = list(string)
|
||||
default = []
|
||||
}
|
||||
|
||||
variable "remote_coder_images" {
|
||||
description = "Incus remote images to use for instances"
|
||||
type = list(string)
|
||||
default = []
|
||||
}
|
||||
|
||||
variable "remote_coder_instance_type" {
|
||||
description = "Incus remote instance type (e.g. virtual-machine or container)"
|
||||
type = string
|
||||
default = "virtual-machine"
|
||||
}
|
||||
|
||||
variable "remote_coder_storage_pool" {
|
||||
description = "Incus remote storage pool to use for instances"
|
||||
type = string
|
||||
}
|
||||
|
||||
data "coder_workspace" "me" {}
|
||||
data "coder_workspace_owner" "me" {}
|
||||
|
||||
# data "coder_parameter" "isolated" { # TO BE IMPLEMENTED - requires network configuration in the module
|
||||
# name = "isolated"
|
||||
# display_name = "Isolated Environment(dedicated network)"
|
||||
# type = "bool"
|
||||
# mutable = true
|
||||
# default = false
|
||||
# }
|
||||
|
||||
data "coder_parameter" "profile" {
|
||||
name = "profile"
|
||||
display_name = "Instance Profile"
|
||||
type = "string"
|
||||
mutable = true
|
||||
|
||||
dynamic "option" {
|
||||
for_each = [for p in var.remote_coder_profiles : { name = title(p), value = p }]
|
||||
content {
|
||||
name = option.value.name
|
||||
value = option.value.value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
data "coder_parameter" "image" {
|
||||
name = "image"
|
||||
display_name = "Instance Image"
|
||||
type = "string"
|
||||
mutable = true
|
||||
|
||||
dynamic "option" {
|
||||
for_each = [for img in var.remote_coder_images : { name = title(img), value = img }]
|
||||
content {
|
||||
name = option.value.name
|
||||
value = option.value.value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resource "coder_agent" "dev" {
|
||||
arch = "amd64"
|
||||
os = "linux"
|
||||
|
||||
env = {
|
||||
GIT_AUTHOR_NAME = data.coder_workspace_owner.me.name
|
||||
GIT_AUTHOR_EMAIL = data.coder_workspace_owner.me.email
|
||||
}
|
||||
|
||||
startup_script_behavior = "non-blocking"
|
||||
startup_script = <<-EOT
|
||||
set -e
|
||||
# Add any startup scripts here
|
||||
EOT
|
||||
|
||||
metadata {
|
||||
display_name = "CPU Usage"
|
||||
key = "cpu_usage"
|
||||
script = "coder stat cpu"
|
||||
interval = 10
|
||||
timeout = 1
|
||||
order = 1
|
||||
}
|
||||
|
||||
metadata {
|
||||
display_name = "RAM Usage"
|
||||
key = "ram_usage"
|
||||
script = "coder stat mem"
|
||||
interval = 10
|
||||
timeout = 1
|
||||
order = 2
|
||||
}
|
||||
|
||||
metadata {
|
||||
display_name = "Disk Usage"
|
||||
key = "disk_usage"
|
||||
script = "coder stat disk"
|
||||
interval = 600
|
||||
timeout = 30
|
||||
order = 3
|
||||
}
|
||||
}
|
||||
|
||||
locals {
|
||||
hostname = lower(data.coder_workspace.me.name)
|
||||
vm_name = "coder-${lower(data.coder_workspace_owner.me.name)}-${local.hostname}"
|
||||
snippet_filename = "${local.vm_name}.yml"
|
||||
base_user = replace(replace(replace(lower(data.coder_workspace_owner.me.name), " ", "-"), "/", "-"), "@", "-") # to avoid special characters in the username
|
||||
linux_user = contains(["root", "admin", "daemon", "bin", "sys"], local.base_user) ? "${local.base_user}1" : local.base_user # to avoid conflict with system users
|
||||
|
||||
rendered_user_data = templatefile("${path.module}/cloud-init/user-data.tftpl", {
|
||||
coder_token = coder_agent.dev.token
|
||||
coder_init_script_b64 = base64encode(coder_agent.dev.init_script)
|
||||
hostname = local.vm_name
|
||||
linux_user = local.linux_user
|
||||
})
|
||||
}
|
||||
|
||||
resource "incus_instance" "workspace" {
|
||||
count = data.coder_workspace.me.start_count
|
||||
remote = var.remote_name
|
||||
name = local.vm_name
|
||||
image = data.coder_parameter.image.value
|
||||
type = var.remote_coder_instance_type
|
||||
profiles = data.coder_parameter.profile.value != "" ? [data.coder_parameter.profile.value] : [] # if profile is not selected, use no profile instead of default
|
||||
project = var.remote_coder_project
|
||||
running = true
|
||||
|
||||
config = {
|
||||
"cloud-init.user-data" = local.rendered_user_data
|
||||
}
|
||||
}
|
||||
|
||||
module "code-server" {
|
||||
count = data.coder_workspace.me.start_count
|
||||
source = "registry.coder.com/coder/code-server/coder"
|
||||
version = "1.3.1"
|
||||
agent_id = coder_agent.dev.id
|
||||
}
|
||||
Reference in New Issue
Block a user