diff --git a/docs/images/icons/infinity.svg b/docs/images/icons/infinity.svg new file mode 100644 index 0000000000000..f1d11dccfaa1c --- /dev/null +++ b/docs/images/icons/infinity.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/docs/manifest.json b/docs/manifest.json index b10d2de0f9824..361e39cacdf68 100644 --- a/docs/manifest.json +++ b/docs/manifest.json @@ -100,6 +100,13 @@ "path": "./templates.md", "icon_path": "./images/icons/picture.svg", "children": [ + { + "title": "Resource Persistence", + "description": "Learn how resource persistence works in Coder", + "path": "./templates/resource-persistence.md", + "icon_path": "./images/icons/infinity.svg", + "last_updated": "2022-10-23" + }, { "title": "Provider Authentication", "description": "Learn how to authenticate the provisioner", diff --git a/docs/templates.md b/docs/templates.md index 5d09b56e0217b..6e8c98a0f5c31 100644 --- a/docs/templates.md +++ b/docs/templates.md @@ -164,13 +164,10 @@ resource "docker_image" "workspace" { } ``` -### Persistent vs. ephemeral resources - -You can use the workspace state to ensure some resources in Coder are -persistent, while others are ephemeral. - #### Start/stop +[Learn about resource persistence in Coder](./templates/resource-persistence.md) + Coder workspaces can be started/stopped. This is often used to save on cloud costs or enforce ephemeral workflows. When a workspace is started or stopped, the Coder server runs an additional @@ -180,7 +177,7 @@ Coder provider that the workspace has a new transition state. This template sample has one persistent resource (docker volume) and one ephemeral resource (docker image). -```sh +```hcl data "coder_workspace" "me" { } diff --git a/docs/templates/resource-persistence.md b/docs/templates/resource-persistence.md new file mode 100644 index 0000000000000..44ab17977ea22 --- /dev/null +++ b/docs/templates/resource-persistence.md @@ -0,0 +1,88 @@ +# Resource Persistence + +Coder templates have full control over workspace ephemerality. In a +completely ephemeral workspace, there are zero resources in the On state. In +a completely persistent workspace, there is no difference between the Off and +On states. + +Most workspaces fall somewhere in the middle, persisting user data +such as filesystem volumes, but deleting expensive, reproducible resources +such as compute instances. + +By default, all Coder resources are persistent, but +production templates **must** employ the practices laid out in this document +to prevent accidental deletion. + +## Disabling Persistence + +The [`coder_workspace` data source](https://registry.terraform.io/providers/coder/coder/latest/docs/data-sources/workspace) exposes the `start_count = [0 | 1]` attribute that other +resources reference to become ephemeral. + +For example: + +```hcl +data "coder_workspace" "me" { +} + +resource "docker_container" "workspace" { + # When `start_count` is 0, `count` is 0, so no `docker_container` is created. + count = data.coder_workspace.me.start_count # 0 (stopped), 1 (started) + # ... other config +} +``` + +## ⚠️ Persistence Pitfalls + +Take this example resource: + +```hcl +data "coder_workspace" "me" { +} + +resource "docker_volume" "home_volume" { + name = "coder-${data.coder_workspace.me.owner}-home" +} +``` + +Because we depend on `coder_workspace.me.owner`, if the owner changes their +username, Terraform would recreate the volume (wiping its data!) the next +time the workspace restarts. + +Therefore, persistent resource names must only depend on immutable IDs such as: +* `coder_workspace.me.owner_id` +* `coder_workspace.me.id` + +```hcl +data "coder_workspace" "me" { +} + +resource "docker_volume" "home_volume" { + # This volume will survive until the Workspace is deleted or the template + # admin changes this resource block. + name = "coder-${data.coder_workspace.id}-home" +} +``` + +## 🛡 Bulletproofing +Even if our persistent resource depends exclusively on static IDs, a change to +the `name` format or other attributes would cause Terraform to rebuild the resource. + +Prevent Terraform from recreating the resource under any circumstance by setting the [`ignore_changes = all` directive in the `lifecycle` block](https://developer.hashicorp.com/terraform/language/meta-arguments/lifecycle#ignore_changes). + +```hcl +data "coder_workspace" "me" { +} + +resource "docker_volume" "home_volume" { + # This resource will survive until either the entire block is deleted + # or the workspace is. + name = "coder-${data.coder_workspace.me.id}-home" + lifecycle { + ignore_changes = all + } +} +``` + +## Up next + +- [Templates](../templates.md) diff --git a/docs/workspaces.md b/docs/workspaces.md index 5839a7e056ceb..3537356692872 100644 --- a/docs/workspaces.md +++ b/docs/workspaces.md @@ -27,9 +27,8 @@ any activity or if there was a [template update](./templates.md#manage-templates) available. Resources are often destroyed and re-created when a workspace is restarted, -though the exact behavior depends on the template's definitions. For more -information, see [persistent vs. ephemeral -resources](./templates.md#persistent-vs-ephemeral-resources). +though the exact behavior depends on the template. For more +information, see [Resource Persistence](./templates/resource-persistence.md). > ⚠️ To avoid data loss, refer to your template documentation for information on > where to store files, install software, etc., so that they persist. Default diff --git a/dogfood/main.tf b/dogfood/main.tf index 0b757336b812c..7e473a5a6491c 100644 --- a/dogfood/main.tf +++ b/dogfood/main.tf @@ -54,6 +54,9 @@ resource "coder_app" "code-server" { resource "docker_volume" "home_volume" { name = "coder-${data.coder_workspace.me.owner}-${data.coder_workspace.me.name}-home" + lifecycle { + ignore_changes = all + } } resource "coder_metadata" "home_info" {