mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
docs: restructure docs (#14421)
Closes #13434 Supersedes #14182 --------- Co-authored-by: Ethan <39577870+ethanndickson@users.noreply.github.com> Co-authored-by: Ethan Dickson <ethan@coder.com> Co-authored-by: Ben Potter <ben@coder.com> Co-authored-by: Stephen Kirby <58410745+stirby@users.noreply.github.com> Co-authored-by: Stephen Kirby <me@skirby.dev> Co-authored-by: EdwardAngert <17991901+EdwardAngert@users.noreply.github.com> Co-authored-by: Edward Angert <EdwardAngert@users.noreply.github.com>
This commit is contained in:
co-authored by
Ethan
Ethan Dickson
Ben Potter
Stephen Kirby
Stephen Kirby
EdwardAngert
Edward Angert
parent
288df75686
commit
419eba5fb6
@@ -0,0 +1,164 @@
|
||||
# Creating Templates
|
||||
|
||||
Users with the `Template Administrator` role or above can create templates
|
||||
within Coder.
|
||||
|
||||
## From a starter template
|
||||
|
||||
In most cases, it is best to start with a starter template.
|
||||
|
||||
<div class="tabs">
|
||||
|
||||
### Web UI
|
||||
|
||||
After navigating to the Templates page in the Coder dashboard, choose
|
||||
`Create Template > Choose a starter template`.
|
||||
|
||||

|
||||
|
||||
From there, select a starter template for desired underlying infrastructure for
|
||||
workspaces.
|
||||
|
||||

|
||||
|
||||
Give your template a name, description, and icon and press `Create template`.
|
||||
|
||||

|
||||
|
||||
> **⚠️ Note**: If template creation fails, Coder is likely not authorized to
|
||||
> deploy infrastructure in the given location. Learn how to configure
|
||||
> [provisioner authentication](#TODO).
|
||||
|
||||
### CLI
|
||||
|
||||
You can the [Coder CLI](../../install/cli.md) to manage templates for Coder.
|
||||
After [logging in](#TODO) to your deployment, create a folder to store your
|
||||
templates:
|
||||
|
||||
```sh
|
||||
# This snippet applies to macOS and Linux only
|
||||
mkdir $HOME/coder-templates
|
||||
cd $HOME/coder-templates
|
||||
```
|
||||
|
||||
Use the [`templates init`](../../reference/cli/templates_init.md) command to
|
||||
pull a starter template:
|
||||
|
||||
```sh
|
||||
coder templates init
|
||||
```
|
||||
|
||||
After pulling the template to your local machine (e.g. `aws-linux`), you can
|
||||
rename it:
|
||||
|
||||
```sh
|
||||
# This snippet applies to macOS and Linux only
|
||||
mv aws-linux universal-template
|
||||
cd universal-template
|
||||
```
|
||||
|
||||
Next, push it to Coder with the
|
||||
[`templates push`](../../reference/cli/templates_push.md) command:
|
||||
|
||||
```sh
|
||||
coder templates push
|
||||
```
|
||||
|
||||
> ⚠️ Note: If `template push` fails, Coder is likely not authorized to deploy
|
||||
> infrastructure in the given location. Learn how to configure
|
||||
> [provisioner authentication](../provisioners.md).
|
||||
|
||||
You can edit the metadata of the template such as the display name with the
|
||||
[`templates edit`](../../reference/cli/templates_edit.md) command:
|
||||
|
||||
```sh
|
||||
coder templates edit universal-template \
|
||||
--display-name "Universal Template" \
|
||||
--description "Virtual machine configured with Java, Python, Typescript, IntelliJ IDEA, and Ruby. Use this for starter projects. " \
|
||||
--icon "/emojis/2b50.png"
|
||||
```
|
||||
|
||||
### CI/CD
|
||||
|
||||
Follow the [change management](./managing-templates/change-management.md) guide
|
||||
to manage templates via GitOps.
|
||||
|
||||
</div>
|
||||
|
||||
## From an existing template
|
||||
|
||||
You can duplicate an existing template in your Coder deployment. This will copy
|
||||
the template code and metadata, allowing you to make changes without affecting
|
||||
the original template.
|
||||
|
||||
<div class="tabs">
|
||||
|
||||
### Web UI
|
||||
|
||||
After navigating to the page for a template, use the dropdown menu on the right
|
||||
to `Duplicate`.
|
||||
|
||||

|
||||
|
||||
Give the new template a name, icon, and description.
|
||||
|
||||

|
||||
|
||||
Press `Create template`. After the build, you will be taken to the new template
|
||||
page.
|
||||
|
||||

|
||||
|
||||
### CLI
|
||||
|
||||
First, ensure you are logged in to the control plane as a user with permissions
|
||||
to read and write permissions.
|
||||
|
||||
```console
|
||||
coder login
|
||||
```
|
||||
|
||||
You can list the available templates with the following CLI invocation.
|
||||
|
||||
```console
|
||||
coder templates list
|
||||
```
|
||||
|
||||
After identified the template you'd like to work from, clone it into a directory
|
||||
with a name you'd like to assign to the new modified template.
|
||||
|
||||
```console
|
||||
coder templates pull <template-name> ./<new-template-name>
|
||||
```
|
||||
|
||||
Then, you can make modifications to the existing template in this directory and
|
||||
push them to the control plane using the `-d` flag to specify the directory.
|
||||
|
||||
```console
|
||||
coder templates push <new-template-name> -d ./<new-template-name>
|
||||
```
|
||||
|
||||
You will then see your new template in the dashboard.
|
||||
|
||||
</div>
|
||||
|
||||
## From scratch (advanced)
|
||||
|
||||
There may be cases where you want to create a template from scratch. You can use
|
||||
[any Terraform provider](https://registry.terraform.com) with Coder to create
|
||||
templates for additional clouds (e.g. Hetzner, Alibaba) or orchestrators
|
||||
(VMware, Proxmox) that we do not provide example templates for.
|
||||
|
||||
Refer to the following resources:
|
||||
|
||||
- [Tutorial: Create a template from scratch](../../tutorials/template-from-scratch.md)
|
||||
- [Extending templates](./extending-templates/index.md): Features and concepts
|
||||
around templates (agents, parameters, variables, etc)
|
||||
- [Coder Registry](https://registry.coder.com/templates): Official and community
|
||||
templates for Coder
|
||||
- [Coder Terraform Provider Reference](https://registry.terraform.io/providers/coder/coder)
|
||||
|
||||
### Next steps
|
||||
|
||||
- [Extending templates](./extending-templates/index.md)
|
||||
- [Managing templates](./managing-templates/index.md)
|
||||
@@ -0,0 +1,148 @@
|
||||
# Agent metadata
|
||||
|
||||

|
||||
|
||||
You can show live operational metrics to workspace users with agent metadata. It
|
||||
is the dynamic complement of [resource metadata](./resource-metadata.md).
|
||||
|
||||
You specify agent metadata in the
|
||||
[`coder_agent`](https://registry.terraform.io/providers/coder/coder/latest/docs/resources/agent).
|
||||
|
||||
## Examples
|
||||
|
||||
All of these examples use
|
||||
[heredoc strings](https://developer.hashicorp.com/terraform/language/expressions/strings#heredoc-strings)
|
||||
for the script declaration. With heredoc strings, you can script without messy
|
||||
escape codes, just as if you were working in your terminal.
|
||||
|
||||
Some of the examples use the [`coder stat`](../../../reference/cli/stat.md)
|
||||
command. This is useful for determining CPU and memory usage of the VM or
|
||||
container that the workspace is running in, which is more accurate than resource
|
||||
usage about the workspace's host.
|
||||
|
||||
Here's a standard set of metadata snippets for Linux agents:
|
||||
|
||||
```tf
|
||||
resource "coder_agent" "main" {
|
||||
os = "linux"
|
||||
...
|
||||
metadata {
|
||||
display_name = "CPU Usage"
|
||||
key = "cpu"
|
||||
# Uses the coder stat command to get container CPU usage.
|
||||
script = "coder stat cpu"
|
||||
interval = 1
|
||||
timeout = 1
|
||||
}
|
||||
|
||||
metadata {
|
||||
display_name = "Memory Usage"
|
||||
key = "mem"
|
||||
# Uses the coder stat command to get container memory usage in GiB.
|
||||
script = "coder stat mem --prefix Gi"
|
||||
interval = 1
|
||||
timeout = 1
|
||||
}
|
||||
|
||||
metadata {
|
||||
display_name = "CPU Usage (Host)"
|
||||
key = "cpu_host"
|
||||
# calculates CPU usage by summing the "us", "sy" and "id" columns of
|
||||
# top.
|
||||
script = <<EOT
|
||||
top -bn1 | awk 'FNR==3 {printf "%2.0f%%", $2+$3+$4}'
|
||||
EOT
|
||||
interval = 1
|
||||
timeout = 1
|
||||
}
|
||||
|
||||
metadata {
|
||||
display_name = "Memory Usage (Host)"
|
||||
key = "mem_host"
|
||||
script = <<EOT
|
||||
free | awk '/^Mem/ { printf("%.0f%%", $4/$2 * 100.0) }'
|
||||
EOT
|
||||
interval = 1
|
||||
timeout = 1
|
||||
}
|
||||
|
||||
metadata {
|
||||
display_name = "Disk Usage"
|
||||
key = "disk"
|
||||
script = "df -h | awk '$6 ~ /^\\/$/ { print $5 }'"
|
||||
interval = 1
|
||||
timeout = 1
|
||||
}
|
||||
|
||||
metadata {
|
||||
display_name = "Load Average"
|
||||
key = "load"
|
||||
script = <<EOT
|
||||
awk '{print $1,$2,$3}' /proc/loadavg
|
||||
EOT
|
||||
interval = 1
|
||||
timeout = 1
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Useful utilities
|
||||
|
||||
You can also show agent metadata for information about the workspace's host.
|
||||
|
||||
[top](https://manpages.ubuntu.com/manpages/jammy/en/man1/top.1.html) is
|
||||
available in most Linux distributions and provides virtual memory, CPU and IO
|
||||
statistics. Running `top` produces output that looks like:
|
||||
|
||||
```text
|
||||
%Cpu(s): 65.8 us, 4.4 sy, 0.0 ni, 29.3 id, 0.3 wa, 0.0 hi, 0.2 si, 0.0 st
|
||||
MiB Mem : 16009.0 total, 493.7 free, 4624.8 used, 10890.5 buff/cache
|
||||
MiB Swap: 0.0 total, 0.0 free, 0.0 used. 11021.3 avail Mem
|
||||
```
|
||||
|
||||
[vmstat](https://manpages.ubuntu.com/manpages/jammy/en/man8/vmstat.8.html) is
|
||||
available in most Linux distributions and provides virtual memory, CPU and IO
|
||||
statistics. Running `vmstat` produces output that looks like:
|
||||
|
||||
```text
|
||||
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
|
||||
r b swpd free buff cache si so bi bo in cs us sy id wa st
|
||||
0 0 19580 4781680 12133692 217646944 0 2 4 32 1 0 1 1 98 0 0
|
||||
```
|
||||
|
||||
[dstat](https://manpages.ubuntu.com/manpages/jammy/man1/dstat.1.html) is
|
||||
considerably more parseable than `vmstat` but often not included in base images.
|
||||
It is easily installed by most package managers under the name `dstat`. The
|
||||
output of running `dstat 1 1` looks like:
|
||||
|
||||
```text
|
||||
--total-cpu-usage-- -dsk/total- -net/total- ---paging-- ---system--
|
||||
usr sys idl wai stl| read writ| recv send| in out | int csw
|
||||
1 1 98 0 0|3422k 25M| 0 0 | 153k 904k| 123k 174k
|
||||
```
|
||||
|
||||
## Managing the database load
|
||||
|
||||
Agent metadata can generate a significant write load and overwhelm your Coder
|
||||
database if you're not careful. The approximate writes per second can be
|
||||
calculated using the formula:
|
||||
|
||||
```text
|
||||
(metadata_count * num_running_agents * 2) / metadata_avg_interval
|
||||
```
|
||||
|
||||
For example, let's say you have
|
||||
|
||||
- 10 running agents
|
||||
- each with 6 metadata snippets
|
||||
- with an average interval of 4 seconds
|
||||
|
||||
You can expect `(10 * 6 * 2) / 4`, or 30 writes per second.
|
||||
|
||||
One of the writes is to the `UNLOGGED` `workspace_agent_metadata` table and the
|
||||
other to the `NOTIFY` query that enables live stats streaming in the UI.
|
||||
|
||||
## Next Steps
|
||||
|
||||
- [Resource metadata](./resource-metadata.md)
|
||||
- [Parameters](./parameters.md)
|
||||
@@ -0,0 +1,461 @@
|
||||
# Docker in Workspaces
|
||||
|
||||
There are a few ways to run Docker within container-based Coder workspaces.
|
||||
|
||||
| Method | Description | Limitations |
|
||||
| ---------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| [Sysbox container runtime](#sysbox-container-runtime) | Install the Sysbox runtime on your Kubernetes nodes or Docker host(s) for secure docker-in-docker and systemd-in-docker. Works with GKE, EKS, AKS, Docker. | Requires [compatible nodes](https://github.com/nestybox/sysbox#host-requirements). [Limitations](https://github.com/nestybox/sysbox/blob/master/docs/user-guide/limitations.md) |
|
||||
| [Envbox](#envbox) | A container image with all the packages necessary to run an inner Sysbox container. Removes the need to setup sysbox-runc on your nodes. Works with GKE, EKS, AKS. | Requires running the outer container as privileged (the inner container that acts as the workspace is locked down). Requires compatible [nodes](https://github.com/nestybox/sysbox/blob/master/docs/distro-compat.md#sysbox-distro-compatibility). |
|
||||
| [Rootless Podman](#rootless-podman) | Run Podman inside Coder workspaces. Does not require a custom runtime or privileged containers. Works with GKE, EKS, AKS, RKE, OpenShift | Requires smarter-device-manager for FUSE mounts. [See all](https://github.com/containers/podman/blob/main/rootless.md#shortcomings-of-rootless-podman) |
|
||||
| [Privileged docker sidecar](#privileged-sidecar-container) | Run Docker as a privileged sidecar container. | Requires a privileged container. Workspaces can break out to root on the host machine. |
|
||||
|
||||
## Sysbox container runtime
|
||||
|
||||
The [Sysbox](https://github.com/nestybox/sysbox) container runtime allows
|
||||
unprivileged users to run system-level applications, such as Docker, securely
|
||||
from the workspace containers. Sysbox requires a
|
||||
[compatible Linux distribution](https://github.com/nestybox/sysbox/blob/master/docs/distro-compat.md)
|
||||
to implement these security features. Sysbox can also be used to run systemd
|
||||
inside Coder workspaces. See [Systemd in Docker](#systemd-in-docker).
|
||||
|
||||
### Use Sysbox in Docker-based templates
|
||||
|
||||
After [installing Sysbox](https://github.com/nestybox/sysbox#installation) on
|
||||
the Coder host, modify your template to use the sysbox-runc runtime:
|
||||
|
||||
```tf
|
||||
resource "docker_container" "workspace" {
|
||||
# ...
|
||||
name = "coder-${data.coder_workspace.me.owner}-${lower(data.coder_workspace.me.name)}"
|
||||
image = "codercom/enterprise-base:ubuntu"
|
||||
env = ["CODER_AGENT_TOKEN=${coder_agent.main.token}"]
|
||||
command = ["sh", "-c", coder_agent.main.init_script]
|
||||
# Use the Sysbox container runtime (required)
|
||||
runtime = "sysbox-runc"
|
||||
}
|
||||
|
||||
resource "coder_agent" "main" {
|
||||
arch = data.coder_provisioner.me.arch
|
||||
os = "linux"
|
||||
startup_script = <<EOF
|
||||
#!/bin/sh
|
||||
|
||||
# Start Docker
|
||||
sudo dockerd &
|
||||
|
||||
# ...
|
||||
EOF
|
||||
}
|
||||
```
|
||||
|
||||
### Use Sysbox in Kubernetes-based templates
|
||||
|
||||
After
|
||||
[installing Sysbox on Kubernetes](https://github.com/nestybox/sysbox/blob/master/docs/user-guide/install-k8s.md),
|
||||
modify your template to use the sysbox-runc RuntimeClass. This requires the
|
||||
Kubernetes Terraform provider version 2.16.0 or greater.
|
||||
|
||||
```tf
|
||||
terraform {
|
||||
required_providers {
|
||||
coder = {
|
||||
source = "coder/coder"
|
||||
}
|
||||
kubernetes = {
|
||||
source = "hashicorp/kubernetes"
|
||||
version = "2.16.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
variable "workspaces_namespace" {
|
||||
default = "coder-namespace"
|
||||
}
|
||||
|
||||
data "coder_workspace" "me" {}
|
||||
|
||||
resource "coder_agent" "main" {
|
||||
os = "linux"
|
||||
arch = "amd64"
|
||||
dir = "/home/coder"
|
||||
startup_script = <<EOF
|
||||
#!/bin/sh
|
||||
|
||||
# Start Docker
|
||||
sudo dockerd &
|
||||
|
||||
# ...
|
||||
EOF
|
||||
}
|
||||
|
||||
resource "kubernetes_pod" "dev" {
|
||||
count = data.coder_workspace.me.start_count
|
||||
metadata {
|
||||
name = "coder-${data.coder_workspace.me.owner}-${data.coder_workspace.me.name}"
|
||||
namespace = var.workspaces_namespace
|
||||
annotations = {
|
||||
"io.kubernetes.cri-o.userns-mode" = "auto:size=65536"
|
||||
}
|
||||
}
|
||||
|
||||
spec {
|
||||
runtime_class_name = "sysbox-runc"
|
||||
# Use the Sysbox container runtime (required)
|
||||
security_context {
|
||||
run_as_user = 1000
|
||||
fs_group = 1000
|
||||
}
|
||||
container {
|
||||
name = "dev"
|
||||
env {
|
||||
name = "CODER_AGENT_TOKEN"
|
||||
value = coder_agent.main.token
|
||||
}
|
||||
image = "codercom/enterprise-base:ubuntu"
|
||||
command = ["sh", "-c", coder_agent.main.init_script]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Envbox
|
||||
|
||||
[Envbox](https://github.com/coder/envbox) is an image developed and maintained
|
||||
by Coder that bundles the sysbox runtime. It works by starting an outer
|
||||
container that manages the various sysbox daemons and spawns an unprivileged
|
||||
inner container that acts as the user's workspace. The inner container is able
|
||||
to run system-level software similar to a regular virtual machine (e.g.
|
||||
`systemd`, `dockerd`, etc). Envbox offers the following benefits over running
|
||||
sysbox directly on the nodes:
|
||||
|
||||
- No custom runtime installation or management on your Kubernetes nodes.
|
||||
- No limit to the number of pods that run envbox.
|
||||
|
||||
Some drawbacks include:
|
||||
|
||||
- The outer container must be run as privileged
|
||||
- Note: the inner container is _not_ privileged. For more information on the
|
||||
security of sysbox containers see sysbox's
|
||||
[official documentation](https://github.com/nestybox/sysbox/blob/master/docs/user-guide/security.md).
|
||||
- Initial workspace startup is slower than running `sysbox-runc` directly on the
|
||||
nodes. This is due to `envbox` having to pull the image to its own Docker
|
||||
cache on its initial startup. Once the image is cached in `envbox`, startup
|
||||
performance is similar.
|
||||
|
||||
Envbox requires the same kernel requirements as running sysbox directly on the
|
||||
nodes. Refer to sysbox's
|
||||
[compatibility matrix](https://github.com/nestybox/sysbox/blob/master/docs/distro-compat.md#sysbox-distro-compatibility)
|
||||
to ensure your nodes are compliant.
|
||||
|
||||
To get started with `envbox` check out the
|
||||
[starter template](https://github.com/coder/coder/tree/main/examples/templates/envbox)
|
||||
or visit the [repo](https://github.com/coder/envbox).
|
||||
|
||||
### Authenticating with a Private Registry
|
||||
|
||||
Authenticating with a private container registry can be done by referencing the
|
||||
credentials via the `CODER_IMAGE_PULL_SECRET` environment variable. It is
|
||||
encouraged to populate this
|
||||
[environment variable](https://kubernetes.io/docs/tasks/inject-data-application/distribute-credentials-secure/#define-container-environment-variables-using-secret-data)
|
||||
by using a Kubernetes
|
||||
[secret](https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/#registry-secret-existing-credentials).
|
||||
|
||||
Refer to your container registry documentation to understand how to best create
|
||||
this secret.
|
||||
|
||||
The following shows a minimal example using a the JSON API key from a GCP
|
||||
service account to pull a private image:
|
||||
|
||||
```bash
|
||||
# Create the secret
|
||||
$ kubectl create secret docker-registry <name> \
|
||||
--docker-server=us.gcr.io \
|
||||
--docker-username=_json_key \
|
||||
--docker-password="$(cat ./json-key-file.yaml)" \
|
||||
--docker-email=<service-account-email>
|
||||
```
|
||||
|
||||
```tf
|
||||
env {
|
||||
name = "CODER_IMAGE_PULL_SECRET"
|
||||
value_from {
|
||||
secret_key_ref {
|
||||
name = "<name>"
|
||||
key = ".dockerconfigjson"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Rootless podman
|
||||
|
||||
[Podman](https://docs.podman.io/en/latest/) is Docker alternative that is
|
||||
compatible with OCI containers specification. which can run rootless inside
|
||||
Kubernetes pods. No custom RuntimeClass is required.
|
||||
|
||||
Before using Podman, please review the following documentation:
|
||||
|
||||
- [Basic setup and use of Podman in a rootless environment](https://github.com/containers/podman/blob/main/docs/tutorials/rootless_tutorial.md)
|
||||
|
||||
- [Shortcomings of Rootless Podman](https://github.com/containers/podman/blob/main/rootless.md#shortcomings-of-rootless-podman)
|
||||
|
||||
1. Enable
|
||||
[smart-device-manager](https://gitlab.com/arm-research/smarter/smarter-device-manager#enabling-access)
|
||||
to securely expose a FUSE devices to pods.
|
||||
|
||||
```shell
|
||||
cat <<EOF | kubectl create -f -
|
||||
apiVersion: apps/v1
|
||||
kind: DaemonSet
|
||||
metadata:
|
||||
name: fuse-device-plugin-daemonset
|
||||
namespace: kube-system
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
name: fuse-device-plugin-ds
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
name: fuse-device-plugin-ds
|
||||
spec:
|
||||
hostNetwork: true
|
||||
containers:
|
||||
- name: fuse-device-plugin-ctr
|
||||
image: soolaugust/fuse-device-plugin:v1.0
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
capabilities:
|
||||
drop: ["ALL"]
|
||||
volumeMounts:
|
||||
- name: device-plugin
|
||||
mountPath: /var/lib/kubelet/device-plugins
|
||||
volumes:
|
||||
- name: device-plugin
|
||||
hostPath:
|
||||
path: /var/lib/kubelet/device-plugins
|
||||
imagePullSecrets:
|
||||
- name: registry-secret
|
||||
EOF
|
||||
```
|
||||
|
||||
2. Be sure to label your nodes to enable smarter-device-manager:
|
||||
|
||||
```shell
|
||||
kubectl get nodes
|
||||
kubectl label nodes --all smarter-device-manager=enabled
|
||||
```
|
||||
|
||||
> ⚠️ **Warning**: If you are using a managed Kubernetes distribution (e.g.
|
||||
> AKS, EKS, GKE), be sure to set node labels via your cloud provider.
|
||||
> Otherwise, your nodes may drop the labels and break podman functionality.
|
||||
|
||||
3. For systems running SELinux (typically Fedora-, CentOS-, and Red Hat-based
|
||||
systems), you might need to disable SELinux or set it to permissive mode.
|
||||
|
||||
4. Use this
|
||||
[kubernetes-with-podman](https://github.com/coder/community-templates/tree/main/kubernetes-podman)
|
||||
example template, or make your own.
|
||||
|
||||
```shell
|
||||
echo "kubernetes-with-podman" | coder templates init
|
||||
cd ./kubernetes-with-podman
|
||||
coder templates create
|
||||
```
|
||||
|
||||
> For more information around the requirements of rootless podman pods, see:
|
||||
> [How to run Podman inside of Kubernetes](https://www.redhat.com/sysadmin/podman-inside-kubernetes)
|
||||
|
||||
## Privileged sidecar container
|
||||
|
||||
A
|
||||
[privileged container](https://docs.docker.com/engine/containers/run/#runtime-privilege-and-linux-capabilities)
|
||||
can be added to your templates to add docker support. This may come in handy if
|
||||
your nodes cannot run Sysbox.
|
||||
|
||||
> ⚠️ **Warning**: This is insecure. Workspaces will be able to gain root access
|
||||
> to the host machine.
|
||||
|
||||
### Use a privileged sidecar container in Docker-based templates
|
||||
|
||||
```tf
|
||||
resource "coder_agent" "main" {
|
||||
os = "linux"
|
||||
arch = "amd64"
|
||||
}
|
||||
|
||||
resource "docker_network" "private_network" {
|
||||
name = "network-${data.coder_workspace.me.id}"
|
||||
}
|
||||
|
||||
resource "docker_container" "dind" {
|
||||
image = "docker:dind"
|
||||
privileged = true
|
||||
name = "dind-${data.coder_workspace.me.id}"
|
||||
entrypoint = ["dockerd", "-H", "tcp://0.0.0.0:2375"]
|
||||
networks_advanced {
|
||||
name = docker_network.private_network.name
|
||||
}
|
||||
}
|
||||
|
||||
resource "docker_container" "workspace" {
|
||||
count = data.coder_workspace.me.start_count
|
||||
image = "codercom/enterprise-base:ubuntu"
|
||||
name = "dev-${data.coder_workspace.me.id}"
|
||||
command = ["sh", "-c", coder_agent.main.init_script]
|
||||
env = [
|
||||
"CODER_AGENT_TOKEN=${coder_agent.main.token}",
|
||||
"DOCKER_HOST=${docker_container.dind.name}:2375"
|
||||
]
|
||||
networks_advanced {
|
||||
name = docker_network.private_network.name
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Use a privileged sidecar container in Kubernetes-based templates
|
||||
|
||||
```tf
|
||||
terraform {
|
||||
required_providers {
|
||||
coder = {
|
||||
source = "coder/coder"
|
||||
}
|
||||
kubernetes = {
|
||||
source = "hashicorp/kubernetes"
|
||||
version = "2.16.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
variable "workspaces_namespace" {
|
||||
default = "coder-namespace"
|
||||
}
|
||||
|
||||
data "coder_workspace" "me" {}
|
||||
|
||||
resource "coder_agent" "main" {
|
||||
os = "linux"
|
||||
arch = "amd64"
|
||||
}
|
||||
|
||||
resource "kubernetes_pod" "main" {
|
||||
count = data.coder_workspace.me.start_count
|
||||
metadata {
|
||||
name = "coder-${data.coder_workspace.me.owner}-${data.coder_workspace.me.name}"
|
||||
namespace = var.namespace
|
||||
}
|
||||
spec {
|
||||
# Run a privileged dind (Docker in Docker) container
|
||||
container {
|
||||
name = "docker-sidecar"
|
||||
image = "docker:dind"
|
||||
security_context {
|
||||
privileged = true
|
||||
run_as_user = 0
|
||||
}
|
||||
command = ["dockerd", "-H", "tcp://127.0.0.1:2375"]
|
||||
}
|
||||
container {
|
||||
name = "dev"
|
||||
image = "codercom/enterprise-base:ubuntu"
|
||||
command = ["sh", "-c", coder_agent.main.init_script]
|
||||
security_context {
|
||||
run_as_user = "1000"
|
||||
}
|
||||
env {
|
||||
name = "CODER_AGENT_TOKEN"
|
||||
value = coder_agent.main.token
|
||||
}
|
||||
# Use the Docker daemon in the "docker-sidecar" container
|
||||
env {
|
||||
name = "DOCKER_HOST"
|
||||
value = "localhost:2375"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Systemd in Docker
|
||||
|
||||
Additionally, [Sysbox](https://github.com/nestybox/sysbox) can be used to give
|
||||
workspaces full `systemd` capabilities.
|
||||
|
||||
After
|
||||
[installing Sysbox on Kubernetes](https://github.com/nestybox/sysbox/blob/master/docs/user-guide/install-k8s.md),
|
||||
modify your template to use the sysbox-runc RuntimeClass. This requires the
|
||||
Kubernetes Terraform provider version 2.16.0 or greater.
|
||||
|
||||
```tf
|
||||
terraform {
|
||||
required_providers {
|
||||
coder = {
|
||||
source = "coder/coder"
|
||||
}
|
||||
kubernetes = {
|
||||
source = "hashicorp/kubernetes"
|
||||
version = "2.16.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
variable "workspaces_namespace" {
|
||||
default = "coder-namespace"
|
||||
}
|
||||
|
||||
data "coder_workspace" "me" {}
|
||||
|
||||
resource "coder_agent" "main" {
|
||||
os = "linux"
|
||||
arch = "amd64"
|
||||
dir = "/home/coder"
|
||||
}
|
||||
|
||||
resource "kubernetes_pod" "dev" {
|
||||
count = data.coder_workspace.me.start_count
|
||||
metadata {
|
||||
name = "coder-${data.coder_workspace.me.owner}-${data.coder_workspace.me.name}"
|
||||
namespace = var.workspaces_namespace
|
||||
annotations = {
|
||||
"io.kubernetes.cri-o.userns-mode" = "auto:size=65536"
|
||||
}
|
||||
}
|
||||
|
||||
spec {
|
||||
|
||||
# Use Sysbox container runtime (required)
|
||||
runtime_class_name = "sysbox-runc"
|
||||
|
||||
# Run as root in order to start systemd (required)
|
||||
security_context {
|
||||
run_as_user = 0
|
||||
fs_group = 0
|
||||
}
|
||||
|
||||
container {
|
||||
name = "dev"
|
||||
env {
|
||||
name = "CODER_AGENT_TOKEN"
|
||||
value = coder_agent.main.token
|
||||
}
|
||||
image = "codercom/enterprise-base:ubuntu"
|
||||
command = ["sh", "-c", <<EOF
|
||||
# Start the Coder agent as the "coder" user
|
||||
# once systemd has started up
|
||||
sudo -u coder --preserve-env=CODER_AGENT_TOKEN /bin/bash -- <<-' EOT' &
|
||||
while [[ ! $(systemctl is-system-running) =~ ^(running|degraded) ]]
|
||||
do
|
||||
echo "Waiting for system to start... $(systemctl is-system-running)"
|
||||
sleep 2
|
||||
done
|
||||
${coder_agent.main.init_script}
|
||||
EOT
|
||||
|
||||
exec /sbin/init
|
||||
EOF
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,96 @@
|
||||
# External Authentication
|
||||
|
||||
Coder integrates with any OpenID Connect provider to automate away the need for
|
||||
developers to authenticate with external services within their workspace. This
|
||||
can be used to authenticate with git providers, private registries, or any other
|
||||
service that requires authentication.
|
||||
|
||||
## External Auth Providers
|
||||
|
||||
External auth providers are configured using environment variables in the Coder
|
||||
Control Plane. See
|
||||
|
||||
## Git Providers
|
||||
|
||||
When developers use `git` inside their workspace, they are prompted to
|
||||
authenticate. After that, Coder will store and refresh tokens for future
|
||||
operations.
|
||||
|
||||
<video autoplay playsinline loop>
|
||||
<source src="https://github.com/coder/coder/blob/main/site/static/external-auth.mp4?raw=true" type="video/mp4">
|
||||
Your browser does not support the video tag.
|
||||
</video>
|
||||
|
||||
### Require git authentication in templates
|
||||
|
||||
If your template requires git authentication (e.g. running `git clone` in the
|
||||
[startup_script](https://registry.terraform.io/providers/coder/coder/latest/docs/resources/agent#startup_script)),
|
||||
you can require users authenticate via git prior to creating a workspace:
|
||||
|
||||

|
||||
|
||||
### Native git authentication will auto-refresh tokens
|
||||
|
||||
<blockquote class="info">
|
||||
<p>
|
||||
This is the preferred authentication method.
|
||||
</p>
|
||||
</blockquote>
|
||||
|
||||
By default, the coder agent will configure native `git` authentication via the
|
||||
`GIT_ASKPASS` environment variable. Meaning, with no additional configuration,
|
||||
external authentication will work with native `git` commands.
|
||||
|
||||
To check the auth token being used **from inside a running workspace**, run:
|
||||
|
||||
```shell
|
||||
# If the exit code is non-zero, then the user is not authenticated with the
|
||||
# external provider.
|
||||
coder external-auth access-token <external-auth-id>
|
||||
```
|
||||
|
||||
Note: Some IDE's override the `GIT_ASKPASS` environment variable and need to be
|
||||
configured.
|
||||
|
||||
**VSCode**
|
||||
|
||||
Use the
|
||||
[Coder](https://marketplace.visualstudio.com/items?itemName=coder.coder-remote)
|
||||
extension to automatically configure these settings for you!
|
||||
|
||||
Otherwise, you can manually configure the following settings:
|
||||
|
||||
- Set `git.terminalAuthentication` to `false`
|
||||
- Set `git.useIntegratedAskPass` to `false`
|
||||
|
||||
### Hard coded tokens do not auto-refresh
|
||||
|
||||
If the token is required to be inserted into the workspace, for example
|
||||
[GitHub cli](https://cli.github.com/), the auth token can be inserted from the
|
||||
template. This token will not auto-refresh. The following example will
|
||||
authenticate via GitHub and auto-clone a repo into the `~/coder` directory.
|
||||
|
||||
```tf
|
||||
data "coder_external_auth" "github" {
|
||||
# Matches the ID of the external auth provider in Coder.
|
||||
id = "github"
|
||||
}
|
||||
|
||||
resource "coder_agent" "dev" {
|
||||
os = "linux"
|
||||
arch = "amd64"
|
||||
dir = "~/coder"
|
||||
env = {
|
||||
GITHUB_TOKEN : data.coder_external_auth.github.access_token
|
||||
}
|
||||
startup_script = <<EOF
|
||||
if [ ! -d ~/coder ]; then
|
||||
git clone https://github.com/coder/coder
|
||||
fi
|
||||
EOF
|
||||
}
|
||||
```
|
||||
|
||||
See the
|
||||
[Terraform provider documentation](https://registry.terraform.io/providers/coder/coder/latest/docs/data-sources/external_auth)
|
||||
for all available options.
|
||||
@@ -0,0 +1,80 @@
|
||||
# Icons
|
||||
|
||||
Coder uses icons in several places, including ones that can be configured
|
||||
throughout the app, or specified in your Terraform. They're specified by a URL,
|
||||
which can be to an image hosted on a CDN of your own, or one of the icons that
|
||||
come bundled with your Coder deployment.
|
||||
|
||||
- **Template Icons**:
|
||||
|
||||
- Make templates and workspaces visually recognizable with a relevant or
|
||||
memorable icon
|
||||
|
||||
- [**Terraform**](https://registry.terraform.io/providers/coder/coder/latest/docs):
|
||||
|
||||
- [`coder_app`](https://registry.terraform.io/providers/coder/coder/latest/docs/resources/app#icon)
|
||||
- [`coder_parameter`](https://registry.terraform.io/providers/coder/coder/latest/docs/data-sources/parameter#icon)
|
||||
and
|
||||
[`option`](https://registry.terraform.io/providers/coder/coder/latest/docs/data-sources/parameter#nested-schema-for-option)
|
||||
blocks
|
||||
- [`coder_script`](https://registry.terraform.io/providers/coder/coder/latest/docs/resources/script#icon)
|
||||
- [`coder_metadata`](https://registry.terraform.io/providers/coder/coder/latest/docs/resources/metadata#icon)
|
||||
|
||||
These can all be configured to use an icon by setting the `icon` field.
|
||||
|
||||
```tf
|
||||
data "coder_parameter" "my_parameter" {
|
||||
icon = "/icon/coder.svg"
|
||||
|
||||
option {
|
||||
icon = "/emojis/1f3f3-fe0f-200d-26a7-fe0f.png"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- [**Authentication Providers**](https://coder.com/docs/admin/external-auth):
|
||||
|
||||
- Use icons for external authentication providers to make them recognizable.
|
||||
You can set an icon for each provider by setting the
|
||||
`CODER_EXTERNAL_AUTH_X_ICON` environment variable, where `X` is the number
|
||||
of the provider.
|
||||
|
||||
```env
|
||||
CODER_EXTERNAL_AUTH_0_ICON=/icon/github.svg
|
||||
CODER_EXTERNAL_AUTH_1_ICON=/icon/google.svg
|
||||
```
|
||||
|
||||
- [**Support Links**](../../setup/appearance.md#support-links):
|
||||
|
||||
- Use icons for support links to make them recognizable. You can set the
|
||||
`icon` field for each link in `CODER_SUPPORT_LINKS` array.
|
||||
|
||||
## Bundled icons
|
||||
|
||||
Coder is distributed with a bundle of icons for popular cloud providers and
|
||||
programming languages. You can see all of the icons (or suggest new ones) in our
|
||||
repository on
|
||||
[GitHub](https://github.com/coder/coder/tree/main/site/static/icon).
|
||||
|
||||
You can also view the entire list, with search and previews, by navigating to
|
||||
/icons on your Coder deployment. E.g. [https://coder.example.com/icons](#). This
|
||||
can be particularly useful in airgapped deployments.
|
||||
|
||||

|
||||
|
||||
## External icons
|
||||
|
||||
You can use any image served over HTTPS as an icon, by specifying the full URL
|
||||
of the image. We recommend that you use a CDN that you control, but it can be
|
||||
served from any source that you trust.
|
||||
|
||||
You can also embed an image by using data: URLs.
|
||||
|
||||
- Only the https: and data: protocols are supported in icon URLs (not http:)
|
||||
|
||||
- Be careful when using images hosted by someone else; they might disappear or
|
||||
change!
|
||||
|
||||
- Be careful when using data: URLs. They can get rather large, and can
|
||||
negatively impact loading times for pages and queries they appear in. Only use
|
||||
them for very small icons that compress well.
|
||||
@@ -0,0 +1,93 @@
|
||||
# Extending templates
|
||||
|
||||
There are a variety of Coder-native features to extend the configuration of your
|
||||
development environments. Many of the following features are defined in your
|
||||
templates using the
|
||||
[Coder Terraform provider](https://registry.terraform.io/providers/coder/coder/latest/docs).
|
||||
The provider docs will provide code examples for usage; alternatively, you can
|
||||
view our
|
||||
[example templates](https://github.com/coder/coder/tree/main/examples/templates)
|
||||
to get started.
|
||||
|
||||
## Workspace agents
|
||||
|
||||
For users to connect to a workspace, the template must include a
|
||||
[`coder_agent`](https://registry.terraform.io/providers/coder/coder/latest/docs/resources/agent).
|
||||
The associated agent will facilitate
|
||||
[workspace connections](../../../user-guides/workspace-access/index.md) via SSH,
|
||||
port forwarding, and IDEs. The agent may also display real-time
|
||||
[workspace metadata](./agent-metadata.md) like resource usage.
|
||||
|
||||
```tf
|
||||
resource "coder_agent" "dev" {
|
||||
os = "linux"
|
||||
arch = "amd64"
|
||||
dir = "/workspace"
|
||||
display_apps {
|
||||
vscode = true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
You can also leverage [resource metadata](./resource-metadata.md) to display
|
||||
static resource information from your template.
|
||||
|
||||
Templates must include some computational resource to start the agent. All
|
||||
processes on the workspace are then spawned from the agent. It also provides all
|
||||
information displayed in the dashboard's workspace view.
|
||||
|
||||

|
||||
|
||||
Multiple agents may be used in a single template or even a single resource. Each
|
||||
agent may have it's own apps, startup script, and metadata. This can be used to
|
||||
associate multiple containers or VMs with a workspace.
|
||||
|
||||
## Resource persistence
|
||||
|
||||
The resources you define in a template may be _ephemeral_ or _persistent_.
|
||||
Persistent resources stay provisioned when workspaces are stopped, where as
|
||||
ephemeral resources are destroyed and recreated on restart. All resources are
|
||||
destroyed when a workspace is deleted.
|
||||
|
||||
> You can read more about how resource behavior and workspace state in the
|
||||
> [workspace lifecycle documentation](../../../user-guides/workspace-lifecycle.md).
|
||||
|
||||
Template resources follow the
|
||||
[behavior of Terraform resources](https://developer.hashicorp.com/terraform/language/resources/behavior#how-terraform-applies-a-configuration)
|
||||
and can be further configured using the
|
||||
[lifecycle argument](https://developer.hashicorp.com/terraform/language/meta-arguments/lifecycle).
|
||||
|
||||
A common configuration is a template whose only persistent resource is the home
|
||||
directory. This allows the developer to retain their work while ensuring the
|
||||
rest of their environment is consistently up-to-date on each workspace restart.
|
||||
|
||||
When a workspace is deleted, the Coder server essentially runs a
|
||||
[terraform destroy](https://www.terraform.io/cli/commands/destroy) to remove all
|
||||
resources associated with the workspace.
|
||||
|
||||
> Terraform's
|
||||
> [prevent-destroy](https://www.terraform.io/language/meta-arguments/lifecycle#prevent_destroy)
|
||||
> and
|
||||
> [ignore-changes](https://www.terraform.io/language/meta-arguments/lifecycle#ignore_changes)
|
||||
> meta-arguments can be used to prevent accidental data loss.
|
||||
|
||||
## Coder apps
|
||||
|
||||
Additional IDEs, documentation, or services can be associated to your workspace
|
||||
using the
|
||||
[`coder_app`](https://registry.terraform.io/providers/coder/coder/latest/docs/resources/app)
|
||||
resource.
|
||||
|
||||

|
||||
|
||||
Note that some apps are associated to the agent by default as
|
||||
[`display_apps`](https://registry.terraform.io/providers/coder/coder/latest/docs/resources/agent#nested-schema-for-display_apps)
|
||||
and can be hidden directly in the
|
||||
[`coder_agent`](https://registry.terraform.io/providers/coder/coder/latest/docs/resources/agent)
|
||||
resource. You can arrange the display orientation of Coder apps in your template
|
||||
using [resource ordering](./resource-ordering.md).
|
||||
|
||||
Check out our [module registry](https://registry.coder.com/modules) for
|
||||
additional Coder apps from the team and our OSS community.
|
||||
|
||||
<children></children>
|
||||
@@ -0,0 +1,198 @@
|
||||
# Reusing template code
|
||||
|
||||
To reuse code across different Coder templates, such as common scripts or
|
||||
resource definitions, we suggest using
|
||||
[Terraform Modules](https://developer.hashicorp.com/terraform/language/modules).
|
||||
|
||||
You can store these modules externally from your Coder deployment, like in a git
|
||||
repository or a Terraform registry. This example shows how to reference a module
|
||||
from your template:
|
||||
|
||||
```tf
|
||||
data "coder_workspace" "me" {}
|
||||
|
||||
module "coder-base" {
|
||||
source = "github.com/my-organization/coder-base"
|
||||
|
||||
# Modules take in variables and can provision infrastructure
|
||||
vpc_name = "devex-3"
|
||||
subnet_tags = { "name": data.coder_workspace.me.name }
|
||||
code_server_version = 4.14.1
|
||||
}
|
||||
|
||||
resource "coder_agent" "dev" {
|
||||
# Modules can provide outputs, such as helper scripts
|
||||
startup_script=<<EOF
|
||||
#!/bin/sh
|
||||
${module.coder-base.code_server_install_command}
|
||||
EOF
|
||||
}
|
||||
```
|
||||
|
||||
Learn more about
|
||||
[creating modules](https://developer.hashicorp.com/terraform/language/modules)
|
||||
and
|
||||
[module sources](https://developer.hashicorp.com/terraform/language/modules/sources)
|
||||
in the Terraform documentation.
|
||||
|
||||
## Coder modules
|
||||
|
||||
Coder publishes plenty of modules that can be used to simplify some common tasks
|
||||
across templates. Some of the modules we publish are,
|
||||
|
||||
1. [`code-server`](https://registry.coder.com/modules/code-server) and
|
||||
[`vscode-web`](https://registry.coder.com/modules/vscode-web)
|
||||
2. [`git-clone`](https://registry.coder.com/modules/git-clone)
|
||||
3. [`dotfiles`](https://registry.coder.com/modules/dotfiles)
|
||||
4. [`jetbrains-gateway`](https://registry.coder.com/modules/jetbrains-gateway)
|
||||
5. [`jfrog-oauth`](https://registry.coder.com/modules/jfrog-oauth) and
|
||||
[`jfrog-token`](https://registry.coder.com/modules/jfrog-token)
|
||||
6. [`vault-github`](https://registry.coder.com/modules/vault-github)
|
||||
|
||||
For a full list of available modules please check
|
||||
[Coder module registry](https://registry.coder.com/modules).
|
||||
|
||||
## Offline installations
|
||||
|
||||
In offline and restricted deploymnets, there are 2 ways to fetch modules.
|
||||
|
||||
1. Artifactory
|
||||
2. Private git repository
|
||||
|
||||
### Artifactory
|
||||
|
||||
Air gapped users can clone the [coder/modules](htpps://github.com/coder/modules)
|
||||
repo and publish a
|
||||
[local terraform module repository](https://jfrog.com/help/r/jfrog-artifactory-documentation/set-up-a-terraform-module/provider-registry)
|
||||
to resolve modules via [Artifactory](https://jfrog.com/artifactory/).
|
||||
|
||||
1. Create a local-terraform-repository with name `coder-modules-local`
|
||||
2. Create a virtual repository with name `tf`
|
||||
3. Follow the below instructions to publish coder modules to Artifactory
|
||||
|
||||
```shell
|
||||
git clone https://github.com/coder/modules
|
||||
cd modules
|
||||
jf tfc
|
||||
jf tf p --namespace="coder" --provider="coder" --tag="1.0.0"
|
||||
```
|
||||
|
||||
4. Generate a token with access to the `tf` repo and set an `ENV` variable
|
||||
`TF_TOKEN_example.jfrog.io="XXXXXXXXXXXXXXX"` on the Coder provisioner.
|
||||
5. Create a file `.terraformrc` with following content and mount at
|
||||
`/home/coder/.terraformrc` within the Coder provisioner.
|
||||
|
||||
```tf
|
||||
provider_installation {
|
||||
direct {
|
||||
exclude = ["registry.terraform.io/*/*"]
|
||||
}
|
||||
network_mirror {
|
||||
url = "https://example.jfrog.io/artifactory/api/terraform/tf/providers/"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
6. Update module source as,
|
||||
|
||||
```tf
|
||||
module "module-name" {
|
||||
source = "https://example.jfrog.io/tf__coder/module-name/coder"
|
||||
version = "1.0.0"
|
||||
agent_id = coder_agent.example.id
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
> Do not forget to replace example.jfrog.io with your Artifactory URL
|
||||
|
||||
Based on the instructions
|
||||
[here](https://jfrog.com/blog/tour-terraform-registries-in-artifactory/).
|
||||
|
||||
#### Example template
|
||||
|
||||
We have an example template
|
||||
[here](https://github.com/coder/coder/blob/main/examples/jfrog/remote/main.tf)
|
||||
that uses our
|
||||
[JFrog Docker](https://github.com/coder/coder/blob/main/examples/jfrog/docker/main.tf)
|
||||
template as the underlying module.
|
||||
|
||||
### Private git repository
|
||||
|
||||
If you are importing a module from a private git repository, the Coder server or
|
||||
[provisioner](../../provisioners.md) needs git credentials. Since this token
|
||||
will only be used for cloning your repositories with modules, it is best to
|
||||
create a token with access limited to the repository and no extra permissions.
|
||||
In GitHub, you can generate a
|
||||
[fine-grained token](https://docs.github.com/en/rest/overview/permissions-required-for-fine-grained-personal-access-tokens?apiVersion=2022-11-28)
|
||||
with read only access to the necessary repos.
|
||||
|
||||
If you are running Coder on a VM, make sure that you have `git` installed and
|
||||
the `coder` user has access to the following files:
|
||||
|
||||
```shell
|
||||
# /home/coder/.gitconfig
|
||||
[credential]
|
||||
helper = store
|
||||
```
|
||||
|
||||
```shell
|
||||
# /home/coder/.git-credentials
|
||||
|
||||
# GitHub example:
|
||||
https://your-github-username:your-github-pat@github.com
|
||||
```
|
||||
|
||||
If you are running Coder on Docker or Kubernetes, `git` is pre-installed in the
|
||||
Coder image. However, you still need to mount credentials. This can be done via
|
||||
a Docker volume mount or Kubernetes secrets.
|
||||
|
||||
#### Passing git credentials in Kubernetes
|
||||
|
||||
First, create a `.gitconfig` and `.git-credentials` file on your local machine.
|
||||
You might want to do this in a temporary directory to avoid conflicting with
|
||||
your own git credentials.
|
||||
|
||||
Next, create the secret in Kubernetes. Be sure to do this in the same namespace
|
||||
that Coder is installed in.
|
||||
|
||||
```shell
|
||||
export NAMESPACE=coder
|
||||
kubectl apply -f - <<EOF
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: git-secrets
|
||||
namespace: $NAMESPACE
|
||||
type: Opaque
|
||||
data:
|
||||
.gitconfig: $(cat .gitconfig | base64 | tr -d '\n')
|
||||
.git-credentials: $(cat .git-credentials | base64 | tr -d '\n')
|
||||
EOF
|
||||
```
|
||||
|
||||
Then, modify Coder's Helm values to mount the secret.
|
||||
|
||||
```yaml
|
||||
coder:
|
||||
volumes:
|
||||
- name: git-secrets
|
||||
secret:
|
||||
secretName: git-secrets
|
||||
volumeMounts:
|
||||
- name: git-secrets
|
||||
mountPath: "/home/coder/.gitconfig"
|
||||
subPath: .gitconfig
|
||||
readOnly: true
|
||||
- name: git-secrets
|
||||
mountPath: "/home/coder/.git-credentials"
|
||||
subPath: .git-credentials
|
||||
readOnly: true
|
||||
```
|
||||
|
||||
### Next steps
|
||||
|
||||
- JFrog's
|
||||
[Terraform Registry support](https://jfrog.com/help/r/jfrog-artifactory-documentation/terraform-registry)
|
||||
- [Configuring the JFrog toolchain inside a workspace](../../integrations/jfrog-artifactory.md)
|
||||
- [Coder Module Registry](https://registry.coder.com/modules)
|
||||
@@ -0,0 +1,300 @@
|
||||
# Parameters
|
||||
|
||||
A template can prompt the user for additional information when creating
|
||||
workspaces with
|
||||
[_parameters_](https://registry.terraform.io/providers/coder/coder/latest/docs/data-sources/parameter).
|
||||
|
||||

|
||||
|
||||
The user can set parameters in the dashboard UI and CLI.
|
||||
|
||||
You'll likely want to hardcode certain template properties for workspaces, such
|
||||
as security group. But you can let developers specify other properties with
|
||||
parameters like instance size, geographical location, repository URL, etc.
|
||||
|
||||
This example lets a developer choose a Docker host for the workspace:
|
||||
|
||||
```tf
|
||||
data "coder_parameter" "docker_host" {
|
||||
name = "Region"
|
||||
description = "Which region would you like to deploy to?"
|
||||
icon = "/emojis/1f30f.png"
|
||||
type = "string"
|
||||
default = "tcp://100.94.74.63:2375"
|
||||
|
||||
option {
|
||||
name = "Pittsburgh, USA"
|
||||
value = "tcp://100.94.74.63:2375"
|
||||
icon = "/emojis/1f1fa-1f1f8.png"
|
||||
}
|
||||
|
||||
option {
|
||||
name = "Helsinki, Finland"
|
||||
value = "tcp://100.117.102.81:2375"
|
||||
icon = "/emojis/1f1eb-1f1ee.png"
|
||||
}
|
||||
|
||||
option {
|
||||
name = "Sydney, Australia"
|
||||
value = "tcp://100.127.2.1:2375"
|
||||
icon = "/emojis/1f1e6-1f1f9.png"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
From there, a template can refer to a parameter's value:
|
||||
|
||||
```tf
|
||||
provider "docker" {
|
||||
host = data.coder_parameter.docker_host.value
|
||||
}
|
||||
```
|
||||
|
||||
## Types
|
||||
|
||||
A Coder parameter can have one of these types:
|
||||
|
||||
- `string`
|
||||
- `bool`
|
||||
- `number`
|
||||
- `list(string)`
|
||||
|
||||
To specify a default value for a parameter with the `list(string)` type, use a
|
||||
JSON array and the Terraform
|
||||
[jsonencode](https://developer.hashicorp.com/terraform/language/functions/jsonencode)
|
||||
function. For example:
|
||||
|
||||
```tf
|
||||
data "coder_parameter" "security_groups" {
|
||||
name = "Security groups"
|
||||
icon = "/icon/aws.png"
|
||||
type = "list(string)"
|
||||
description = "Select appropriate security groups."
|
||||
mutable = true
|
||||
default = jsonencode([
|
||||
"Web Server Security Group",
|
||||
"Database Security Group",
|
||||
"Backend Security Group"
|
||||
])
|
||||
}
|
||||
```
|
||||
|
||||
## Options
|
||||
|
||||
A `string` parameter can provide a set of options to limit the user's choices:
|
||||
|
||||
```tf
|
||||
data "coder_parameter" "docker_host" {
|
||||
name = "Region"
|
||||
description = "Which region would you like to deploy to?"
|
||||
type = "string"
|
||||
default = "tcp://100.94.74.63:2375"
|
||||
|
||||
option {
|
||||
name = "Pittsburgh, USA"
|
||||
value = "tcp://100.94.74.63:2375"
|
||||
icon = "/emojis/1f1fa-1f1f8.png"
|
||||
}
|
||||
|
||||
option {
|
||||
name = "Helsinki, Finland"
|
||||
value = "tcp://100.117.102.81:2375"
|
||||
icon = "/emojis/1f1eb-1f1ee.png"
|
||||
}
|
||||
|
||||
option {
|
||||
name = "Sydney, Australia"
|
||||
value = "tcp://100.127.2.1:2375"
|
||||
icon = "/emojis/1f1e6-1f1f9.png"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Incompatibility in Parameter Options for Workspace Builds
|
||||
|
||||
When creating Coder templates, authors have the flexibility to modify parameter
|
||||
options associated with rich parameters. Such modifications can involve adding,
|
||||
substituting, or removing a parameter option. It's important to note that making
|
||||
these changes can lead to discrepancies in parameter values utilized by ongoing
|
||||
workspace builds.
|
||||
|
||||
Consequently, workspace users will be prompted to select the new value from a
|
||||
pop-up window or by using the command-line interface. While this additional
|
||||
interactive step might seem like an interruption, it serves a crucial purpose.
|
||||
It prevents workspace users from becoming trapped with outdated template
|
||||
versions, ensuring they can smoothly update their workspace without any
|
||||
hindrances.
|
||||
|
||||
Example:
|
||||
|
||||
- Bob creates a workspace using the `python-dev` template. This template has a
|
||||
parameter `image_tag`, and Bob selects `1.12`.
|
||||
- Later, the template author Alice is notified of a critical vulnerability in a
|
||||
package installed in the `python-dev` template, which affects the image tag
|
||||
`1.12`.
|
||||
- Alice remediates this vulnerability, and pushes an updated template version
|
||||
that replaces option `1.12` with `1.13` for the `image_tag` parameter. She
|
||||
then notifies all users of that template to update their workspace
|
||||
immediately.
|
||||
- Bob saves their work, and selects the `Update` option in the UI. As their
|
||||
workspace uses the now-invalid option `1.12`, for the `image_tag` parameter,
|
||||
they are prompted to select a new value for `image_tag`.
|
||||
|
||||
## Required and optional parameters
|
||||
|
||||
A parameter is _required_ if it doesn't have the `default` property. The user
|
||||
**must** provide a value to this parameter before creating a workspace:
|
||||
|
||||
```tf
|
||||
data "coder_parameter" "account_name" {
|
||||
name = "Account name"
|
||||
description = "Cloud account name"
|
||||
mutable = true
|
||||
}
|
||||
```
|
||||
|
||||
If a parameter contains the `default` property, Coder will use this value if the
|
||||
user does not specify any:
|
||||
|
||||
```tf
|
||||
data "coder_parameter" "base_image" {
|
||||
name = "Base image"
|
||||
description = "Base machine image to download"
|
||||
default = "ubuntu:latest"
|
||||
}
|
||||
```
|
||||
|
||||
Admins can also set the `default` property to an empty value so that the
|
||||
parameter field can remain empty:
|
||||
|
||||
```tf
|
||||
data "coder_parameter" "dotfiles_url" {
|
||||
name = "dotfiles URL"
|
||||
description = "Git repository with dotfiles"
|
||||
mutable = true
|
||||
default = ""
|
||||
}
|
||||
```
|
||||
|
||||
## Mutability
|
||||
|
||||
Immutable parameters can only be set in these situations:
|
||||
|
||||
- Creating a workspace for the first time.
|
||||
- Updating a workspace to a new template version. This sets the initial value
|
||||
for required parameters.
|
||||
|
||||
The idea is to prevent users from modifying fragile or persistent workspace
|
||||
resources like volumes, regions, and so on.
|
||||
|
||||
Example:
|
||||
|
||||
```tf
|
||||
data "coder_parameter" "region" {
|
||||
name = "Region"
|
||||
description = "Region where the workspace is hosted"
|
||||
mutable = false
|
||||
default = "us-east-1"
|
||||
}
|
||||
```
|
||||
|
||||
You can modify a parameter's `mutable` attribute state anytime. In case of
|
||||
emergency, you can temporarily allow for changing immutable parameters to fix an
|
||||
operational issue, but it is not advised to overuse this opportunity.
|
||||
|
||||
## Ephemeral parameters
|
||||
|
||||
Ephemeral parameters are introduced to users in the form of "build options." Use
|
||||
ephemeral parameters to model specific behaviors in a Coder workspace, such as
|
||||
reverting to a previous image, restoring from a volume snapshot, or building a
|
||||
project without using cache.
|
||||
|
||||
Since these parameters are ephemeral in nature, subsequent builds proceed in the
|
||||
standard manner:
|
||||
|
||||
```tf
|
||||
data "coder_parameter" "force_rebuild" {
|
||||
name = "force_rebuild"
|
||||
type = "bool"
|
||||
description = "Rebuild the Docker image rather than use the cached one."
|
||||
mutable = true
|
||||
default = false
|
||||
ephemeral = true
|
||||
}
|
||||
```
|
||||
|
||||
## Validating parameters
|
||||
|
||||
Coder supports rich parameters with multiple validation modes: min, max,
|
||||
monotonic numbers, and regular expressions.
|
||||
|
||||
### Number
|
||||
|
||||
You can limit a `number` parameter to `min` and `max` boundaries.
|
||||
|
||||
You can also specify its monotonicity as `increasing` or `decreasing` to verify
|
||||
the current and new values. Use the `monotonic` attribute for resources that
|
||||
can't be shrunk or grown without implications, like disk volume size.
|
||||
|
||||
```tf
|
||||
data "coder_parameter" "instances" {
|
||||
name = "Instances"
|
||||
type = "number"
|
||||
description = "Number of compute instances"
|
||||
validation {
|
||||
min = 1
|
||||
max = 8
|
||||
monotonic = "increasing"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
It is possible to override the default `error` message for a `number` parameter,
|
||||
along with its associated `min` and/or `max` properties. The following message
|
||||
placeholders are available `{min}`, `{max}`, and `{value}`.
|
||||
|
||||
```tf
|
||||
data "coder_parameter" "instances" {
|
||||
name = "Instances"
|
||||
type = "number"
|
||||
description = "Number of compute instances"
|
||||
validation {
|
||||
min = 1
|
||||
max = 4
|
||||
error = "Sorry, we can't provision too many instances - maximum limit: {max}, wanted: {value}."
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**NOTE:** as of
|
||||
[`terraform-provider-coder` v0.19.0](https://registry.terraform.io/providers/coder/coder/0.19.0/docs),
|
||||
`options` can be specified in `number` parameters; this also works with
|
||||
validations such as `monotonic`.
|
||||
|
||||
### String
|
||||
|
||||
You can validate a `string` parameter to match a regular expression. The `regex`
|
||||
property requires a corresponding `error` property.
|
||||
|
||||
```tf
|
||||
data "coder_parameter" "project_id" {
|
||||
name = "Project ID"
|
||||
description = "Alpha-numeric project ID"
|
||||
validation {
|
||||
regex = "^[a-z0-9]+$"
|
||||
error = "Unfortunately, this isn't a valid project ID"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Create Autofill
|
||||
|
||||
When the template doesn't specify default values, Coder may still autofill
|
||||
parameters.
|
||||
|
||||
1. Coder will look for URL query parameters with form `param.<name>=<value>`.
|
||||
This feature enables platform teams to create pre-filled template creation
|
||||
links.
|
||||
2. Coder will populate recently used parameter key-value pairs for the user.
|
||||
This feature helps reduce repetition when filling common parameters such as
|
||||
`dotfiles_url` or `region`.
|
||||
@@ -0,0 +1,315 @@
|
||||
# Workspace Process Logging
|
||||
|
||||
The workspace process logging feature allows you to log all system-level
|
||||
processes executing in the workspace.
|
||||
|
||||
> **Note:** This feature is only available on Linux in Kubernetes. There are
|
||||
> additional requirements outlined further in this document.
|
||||
|
||||
Workspace process logging adds a sidecar container to workspace pods that will
|
||||
log all processes started in the workspace container (e.g., commands executed in
|
||||
the terminal or processes created in the background by other processes).
|
||||
Processes launched inside containers or nested containers within the workspace
|
||||
are also logged. You can view the output from the sidecar or send it to a
|
||||
monitoring stack, such as CloudWatch, for further analysis or long-term storage.
|
||||
|
||||
Please note that these logs are not recorded or captured by the Coder
|
||||
organization in any way, shape, or form.
|
||||
|
||||
> This is an [Premium or Enterprise](https://coder.com/pricing) feature. To
|
||||
> learn more about Coder Enterprise, please
|
||||
> [contact sales](https://coder.com/contact).
|
||||
|
||||
## How this works
|
||||
|
||||
Coder uses [eBPF](https://ebpf.io/) (which we chose for its minimal performance
|
||||
impact) to perform in-kernel logging and filtering of all exec system calls
|
||||
originating from the workspace container.
|
||||
|
||||
The core of this feature is also open source and can be found in the
|
||||
[exectrace](https://github.com/coder/exectrace) GitHub repo. The enterprise
|
||||
component (in the `enterprise/` directory of the repo) is responsible for
|
||||
starting the eBPF program with the correct filtering options for the specific
|
||||
workspace.
|
||||
|
||||
## Requirements
|
||||
|
||||
The host machine must be running a Linux kernel >= 5.8 with the kernel config
|
||||
`CONFIG_DEBUG_INFO_BTF=y` enabled.
|
||||
|
||||
To check your kernel version, run:
|
||||
|
||||
```shell
|
||||
uname -r
|
||||
```
|
||||
|
||||
To validate the required kernel config is enabled, run either of the following
|
||||
commands on your nodes directly (_not_ from a workspace terminal):
|
||||
|
||||
```shell
|
||||
cat /proc/config.gz | gunzip | grep CONFIG_DEBUG_INFO_BTF
|
||||
```
|
||||
|
||||
```shell
|
||||
cat "/boot/config-$(uname -r)" | grep CONFIG_DEBUG_INFO_BTF
|
||||
```
|
||||
|
||||
If these requirements are not met, workspaces will fail to start for security
|
||||
reasons.
|
||||
|
||||
Your template must be a Kubernetes template. Workspace process logging is not
|
||||
compatible with the `sysbox-runc` runtime due to technical limitations, but it
|
||||
is compatible with our `envbox` template family.
|
||||
|
||||
## Example templates
|
||||
|
||||
We provide working example templates for Kubernetes, and Kubernetes with
|
||||
`envbox` (for [Docker support in workspaces](./docker-in-workspaces.md)). You
|
||||
can view these templates in the
|
||||
[exectrace repo](https://github.com/coder/exectrace/tree/main/enterprise/templates).
|
||||
|
||||
## Configuring custom templates to use workspace process logging
|
||||
|
||||
If you have an existing Kubernetes or Kubernetes with `envbox` template that you
|
||||
would like to add workspace process logging to, follow these steps:
|
||||
|
||||
1. Ensure the image used in your template has `curl` installed.
|
||||
|
||||
1. Add the following section to your template's `main.tf` file:
|
||||
|
||||
<!--
|
||||
If you are updating this section, please also update the example templates
|
||||
in the exectrace repo.
|
||||
-->
|
||||
|
||||
```hcl
|
||||
locals {
|
||||
# This is the init script for the main workspace container that runs before the
|
||||
# agent starts to configure workspace process logging.
|
||||
exectrace_init_script = <<EOT
|
||||
set -eu
|
||||
pidns_inum=$(readlink /proc/self/ns/pid | sed 's/[^0-9]//g')
|
||||
if [ -z "$pidns_inum" ]; then
|
||||
echo "Could not determine process ID namespace inum"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Before we start the script, does curl exist?
|
||||
if ! command -v curl >/dev/null 2>&1; then
|
||||
echo "curl is required to download the Coder binary"
|
||||
echo "Please install curl to your image and try again"
|
||||
# 127 is command not found.
|
||||
exit 127
|
||||
fi
|
||||
|
||||
echo "Sending process ID namespace inum to exectrace sidecar"
|
||||
rc=0
|
||||
max_retry=5
|
||||
counter=0
|
||||
until [ $counter -ge $max_retry ]; do
|
||||
set +e
|
||||
curl \
|
||||
--fail \
|
||||
--silent \
|
||||
--connect-timeout 5 \
|
||||
-X POST \
|
||||
-H "Content-Type: text/plain" \
|
||||
--data "$pidns_inum" \
|
||||
http://127.0.0.1:56123
|
||||
rc=$?
|
||||
set -e
|
||||
if [ $rc -eq 0 ]; then
|
||||
break
|
||||
fi
|
||||
|
||||
counter=$((counter+1))
|
||||
echo "Curl failed with exit code $${rc}, attempt $${counter}/$${max_retry}; Retrying in 3 seconds..."
|
||||
sleep 3
|
||||
done
|
||||
if [ $rc -ne 0 ]; then
|
||||
echo "Failed to send process ID namespace inum to exectrace sidecar"
|
||||
exit $rc
|
||||
fi
|
||||
|
||||
EOT
|
||||
}
|
||||
```
|
||||
|
||||
1. Update the `command` of your workspace container like the following:
|
||||
|
||||
<!--
|
||||
If you are updating this section, please also update the example templates
|
||||
in the exectrace repo.
|
||||
-->
|
||||
|
||||
```hcl
|
||||
resource "kubernetes_pod" "main" {
|
||||
...
|
||||
spec {
|
||||
...
|
||||
container {
|
||||
...
|
||||
// NOTE: this command is changed compared to the upstream kubernetes
|
||||
// template
|
||||
command = [
|
||||
"sh",
|
||||
"-c",
|
||||
"${local.exectrace_init_script}\n\n${coder_agent.main.init_script}",
|
||||
]
|
||||
...
|
||||
}
|
||||
...
|
||||
}
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
> **Note:** If you are using the `envbox` template, you will need to update
|
||||
> the third argument to be
|
||||
> `"${local.exectrace_init_script}\n\nexec /envbox docker"` instead.
|
||||
|
||||
1. Add the following container to your workspace pod spec.
|
||||
|
||||
<!--
|
||||
If you are updating this section, please also update the example templates
|
||||
in the exectrace repo.
|
||||
-->
|
||||
|
||||
```hcl
|
||||
resource "kubernetes_pod" "main" {
|
||||
...
|
||||
spec {
|
||||
...
|
||||
// NOTE: this container is added compared to the upstream kubernetes
|
||||
// template
|
||||
container {
|
||||
name = "exectrace"
|
||||
image = "ghcr.io/coder/exectrace:latest"
|
||||
image_pull_policy = "Always"
|
||||
command = [
|
||||
"/opt/exectrace",
|
||||
"--init-address", "127.0.0.1:56123",
|
||||
"--label", "workspace_id=${data.coder_workspace.me.id}",
|
||||
"--label", "workspace_name=${data.coder_workspace.me.name}",
|
||||
"--label", "user_id=${data.coder_workspace_owner.me.id}",
|
||||
"--label", "username=${data.coder_workspace_owner.me.name}",
|
||||
"--label", "user_email=${data.coder_workspace_owner.me.email}",
|
||||
]
|
||||
security_context {
|
||||
// exectrace must be started as root so it can attach probes into the
|
||||
// kernel to record process events with high throughput.
|
||||
run_as_user = "0"
|
||||
run_as_group = "0"
|
||||
// exectrace requires a privileged container so it can control mounts
|
||||
// and perform privileged syscalls against the host kernel to attach
|
||||
// probes.
|
||||
privileged = true
|
||||
}
|
||||
}
|
||||
...
|
||||
}
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
> **Note:** `exectrace` requires root privileges and a privileged container
|
||||
> to attach probes to the kernel. This is a requirement of eBPF.
|
||||
|
||||
1. Add the following environment variable to your workspace pod:
|
||||
|
||||
<!--
|
||||
If you are updating this section, please also update the example templates
|
||||
in the exectrace repo.
|
||||
-->
|
||||
|
||||
```hcl
|
||||
resource "kubernetes_pod" "main" {
|
||||
...
|
||||
spec {
|
||||
...
|
||||
env {
|
||||
name = "CODER_AGENT_SUBSYSTEM"
|
||||
value = "exectrace"
|
||||
}
|
||||
...
|
||||
}
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
Once you have made these changes, you can push a new version of your template
|
||||
and workspace process logging will be enabled for all workspaces once they are
|
||||
restarted.
|
||||
|
||||
## Viewing workspace process logs
|
||||
|
||||
To view the process logs for a specific workspace you can use `kubectl` to print
|
||||
the logs:
|
||||
|
||||
```bash
|
||||
kubectl logs pod-name --container exectrace
|
||||
```
|
||||
|
||||
The raw logs will look something like this:
|
||||
|
||||
```json
|
||||
{
|
||||
"ts": "2022-02-28T20:29:38.038452202Z",
|
||||
"level": "INFO",
|
||||
"msg": "exec",
|
||||
"fields": {
|
||||
"labels": {
|
||||
"user_email": "jessie@coder.com",
|
||||
"user_id": "5e876e9a-121663f01ebd1522060d5270",
|
||||
"username": "jessie",
|
||||
"workspace_id": "621d2e52-a6987ef6c56210058ee2593c",
|
||||
"workspace_name": "main"
|
||||
},
|
||||
"cmdline": "uname -a",
|
||||
"event": {
|
||||
"filename": "/usr/bin/uname",
|
||||
"argv": ["uname", "-a"],
|
||||
"truncated": false,
|
||||
"pid": 920684,
|
||||
"uid": 101000,
|
||||
"gid": 101000,
|
||||
"comm": "bash"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### View logs in AWS EKS
|
||||
|
||||
If you're using AWS' Elastic Kubernetes Service, you can
|
||||
[configure your cluster](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/Container-Insights-EKS-logs.html)
|
||||
to send logs to CloudWatch. This allows you to view the logs for a specific user
|
||||
or workspace.
|
||||
|
||||
To view your logs, go to the CloudWatch dashboard (which is available on the
|
||||
**Log Insights** tab) and run a query similar to the following:
|
||||
|
||||
```text
|
||||
fields @timestamp, log_processed.fields.cmdline
|
||||
| sort @timestamp asc
|
||||
| filter kubernetes.container_name="exectrace"
|
||||
| filter log_processed.fields.labels.username="zac"
|
||||
| filter log_processed.fields.labels.workspace_name="code"
|
||||
```
|
||||
|
||||
## Usage considerations
|
||||
|
||||
- The sidecar attached to each workspace is a privileged container, so you may
|
||||
need to review your organization's security policies before enabling this
|
||||
feature. Enabling workspace process logging does _not_ grant extra privileges
|
||||
to the workspace container itself, however.
|
||||
- `exectrace` will log processes from nested Docker containers (including deeply
|
||||
nested containers) correctly, but Coder does not distinguish between processes
|
||||
started in the workspace and processes started in a child container in the
|
||||
logs.
|
||||
- With `envbox` workspaces, this feature will detect and log startup processes
|
||||
begun in the outer container (including container initialization processes).
|
||||
- Because this feature logs **all** processes in the workspace, high levels of
|
||||
usage (e.g., during a `make` run) will result in an abundance of output in the
|
||||
sidecar container. Depending on how your Kubernetes cluster is configured, you
|
||||
may incur extra charges from your cloud provider to store the additional logs.
|
||||
@@ -0,0 +1,48 @@
|
||||
# Provider Authentication
|
||||
|
||||
<blockquote class="danger">
|
||||
<p>
|
||||
Do not store secrets in templates. Assume every user has cleartext access
|
||||
to every template.
|
||||
</p>
|
||||
</blockquote>
|
||||
|
||||
The Coder server's
|
||||
[provisioner](https://registry.terraform.io/providers/coder/coder/latest/docs/data-sources/provisioner)
|
||||
process needs to authenticate with other provider APIs to provision workspaces.
|
||||
There are two approaches to do this:
|
||||
|
||||
- Pass credentials to the provisioner as parameters.
|
||||
- Preferred: Execute the Coder server in an environment that is authenticated
|
||||
with the provider.
|
||||
|
||||
We encourage the latter approach where supported:
|
||||
|
||||
- Simplifies the template.
|
||||
- Keeps provider credentials out of Coder's database, making it a less valuable
|
||||
target for attackers.
|
||||
- Compatible with agent-based authentication schemes, which handle credential
|
||||
rotation or ensure the credentials are not written to disk.
|
||||
|
||||
Generally, you can set up an environment to provide credentials to Coder in
|
||||
these ways:
|
||||
|
||||
- A well-known location on disk. For example, `~/.aws/credentials` for AWS on
|
||||
POSIX systems.
|
||||
- Environment variables.
|
||||
|
||||
It is usually sufficient to authenticate using the CLI or SDK for the provider
|
||||
before running Coder, but check the Terraform provider's documentation for
|
||||
details.
|
||||
|
||||
These platforms have Terraform providers that support authenticated
|
||||
environments:
|
||||
|
||||
- [Google Cloud](https://registry.terraform.io/providers/hashicorp/google/latest/docs)
|
||||
- [Amazon Web Services](https://registry.terraform.io/providers/hashicorp/aws/latest/docs)
|
||||
- [Microsoft Azure](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs)
|
||||
- [Kubernetes](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs)
|
||||
|
||||
Other providers might also support authenticated environments. Check the
|
||||
[documentation of the Terraform provider](https://registry.terraform.io/browse/providers)
|
||||
for details.
|
||||
@@ -0,0 +1,111 @@
|
||||
# Resource Metadata
|
||||
|
||||
Expose key workspace information to your users with
|
||||
[`coder_metadata`](https://registry.terraform.io/providers/coder/coder/latest/docs/resources/metadata)
|
||||
resources in your template code.
|
||||
|
||||
You can use `coder_metadata` to show Terraform resource attributes like these:
|
||||
|
||||
- Compute resources
|
||||
- IP addresses
|
||||
- [Secrets](../../security/secrets.md#displaying-secrets)
|
||||
- Important file paths
|
||||
|
||||

|
||||
|
||||
<blockquote class="info">
|
||||
Coder automatically generates the <code>type</code> metadata.
|
||||
</blockquote>
|
||||
|
||||
You can also present automatically updating, dynamic values with
|
||||
[agent metadata](./agent-metadata.md).
|
||||
|
||||
## Example
|
||||
|
||||
Expose the disk size, deployment name, and persistent directory in a Kubernetes
|
||||
template with:
|
||||
|
||||
```tf
|
||||
resource "kubernetes_persistent_volume_claim" "root" {
|
||||
...
|
||||
}
|
||||
|
||||
resource "kubernetes_deployment" "coder" {
|
||||
# My deployment is ephemeral
|
||||
count = data.coder_workspace.me.start_count
|
||||
...
|
||||
}
|
||||
|
||||
resource "coder_metadata" "pvc" {
|
||||
resource_id = kubernetes_persistent_volume_claim.root.id
|
||||
item {
|
||||
key = "size"
|
||||
value = kubernetes_persistent_volume_claim.root.spec[0].resources[0].requests.storage
|
||||
}
|
||||
item {
|
||||
key = "dir"
|
||||
value = "/home/coder"
|
||||
}
|
||||
}
|
||||
|
||||
resource "coder_metadata" "deployment" {
|
||||
count = data.coder_workspace.me.start_count
|
||||
resource_id = kubernetes_deployment.coder[0].id
|
||||
item {
|
||||
key = "name"
|
||||
value = kubernetes_deployment.coder[0].metadata[0].name
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Hiding resources in the dashboard
|
||||
|
||||
Some resources don't need to be exposed in the dashboard's UI. This helps keep
|
||||
the workspace view clean for developers. To hide a resource, use the `hide`
|
||||
attribute:
|
||||
|
||||
```tf
|
||||
resource "coder_metadata" "hide_serviceaccount" {
|
||||
count = data.coder_workspace.me.start_count
|
||||
resource_id = kubernetes_service_account.user_data.id
|
||||
hide = true
|
||||
item {
|
||||
key = "name"
|
||||
value = kubernetes_deployment.coder[0].metadata[0].name
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Using a custom resource icon
|
||||
|
||||
To use custom icons for your resource metadata, use the `icon` attribute. It
|
||||
must be a valid path or URL.
|
||||
|
||||
```tf
|
||||
resource "coder_metadata" "resource_with_icon" {
|
||||
count = data.coder_workspace.me.start_count
|
||||
resource_id = kubernetes_service_account.user_data.id
|
||||
icon = "/icon/database.svg"
|
||||
item {
|
||||
key = "name"
|
||||
value = kubernetes_deployment.coder[0].metadata[0].name
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
To make it easier for you to customize your resource we added some built-in
|
||||
icons:
|
||||
|
||||
- Folder `/icon/folder.svg`
|
||||
- Memory `/icon/memory.svg`
|
||||
- Image `/icon/image.svg`
|
||||
- Widgets `/icon/widgets.svg`
|
||||
- Database `/icon/database.svg`
|
||||
|
||||
We also have other icons related to the IDEs. You can see more information on
|
||||
how to use the builtin icons [here](./icons.md).
|
||||
|
||||
## Up next
|
||||
|
||||
- [Secrets](../../security/secrets.md)
|
||||
- [Agent metadata](./agent-metadata.md)
|
||||
@@ -0,0 +1,183 @@
|
||||
# UI Resource Ordering
|
||||
|
||||
In Coder templates, managing the order of UI elements is crucial for a seamless
|
||||
user experience. This page outlines how resources can be aligned using the
|
||||
`order` Terraform property or inherit the natural order from the file.
|
||||
|
||||
The resource with the lower `order` is presented before the one with greater
|
||||
value. A missing `order` property defaults to 0. If two resources have the same
|
||||
`order` property, the resources will be ordered by property `name` (or `key`).
|
||||
|
||||
## Using "order" property
|
||||
|
||||
### Coder parameters
|
||||
|
||||
The `order` property of `coder_parameter` resource allows specifying the order
|
||||
of parameters in UI forms. In the below example, `project_id` will appear
|
||||
_before_ `account_id`:
|
||||
|
||||
```tf
|
||||
data "coder_parameter" "project_id" {
|
||||
name = "project_id"
|
||||
display_name = "Project ID"
|
||||
description = "Specify cloud provider project ID."
|
||||
order = 2
|
||||
}
|
||||
|
||||
data "coder_parameter" "account_id" {
|
||||
name = "account_id"
|
||||
display_name = "Account ID"
|
||||
description = "Specify cloud provider account ID."
|
||||
order = 1
|
||||
}
|
||||
```
|
||||
|
||||
### Agents
|
||||
|
||||
Agent resources within the UI left pane are sorted based on the `order`
|
||||
property, followed by `name`, ensuring a consistent and intuitive arrangement.
|
||||
|
||||
```tf
|
||||
resource "coder_agent" "primary" {
|
||||
...
|
||||
|
||||
order = 1
|
||||
}
|
||||
|
||||
resource "coder_agent" "secondary" {
|
||||
...
|
||||
|
||||
order = 2
|
||||
}
|
||||
```
|
||||
|
||||
The agent with the lowest order is presented at the top in the workspace view.
|
||||
|
||||
### Agent metadata
|
||||
|
||||
The `coder_agent` exposes metadata to present operational metrics in the UI.
|
||||
Metrics defined with Terraform `metadata` blocks can be ordered using additional
|
||||
`order` property; otherwise, they are sorted by `key`.
|
||||
|
||||
```tf
|
||||
resource "coder_agent" "main" {
|
||||
...
|
||||
|
||||
metadata {
|
||||
display_name = "CPU Usage"
|
||||
key = "cpu_usage"
|
||||
script = "coder stat cpu"
|
||||
interval = 10
|
||||
timeout = 1
|
||||
order = 1
|
||||
}
|
||||
metadata {
|
||||
display_name = "CPU Usage (Host)"
|
||||
key = "cpu_usage_host"
|
||||
script = "coder stat cpu --host"
|
||||
interval = 10
|
||||
timeout = 1
|
||||
order = 2
|
||||
}
|
||||
metadata {
|
||||
display_name = "RAM Usage"
|
||||
key = "ram_usage"
|
||||
script = "coder stat mem"
|
||||
interval = 10
|
||||
timeout = 1
|
||||
order = 1
|
||||
}
|
||||
metadata {
|
||||
display_name = "RAM Usage (Host)"
|
||||
key = "ram_usage_host"
|
||||
script = "coder stat mem --host"
|
||||
interval = 10
|
||||
timeout = 1
|
||||
order = 2
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Applications
|
||||
|
||||
Similarly to Coder agents, `coder_app` resources incorporate the `order`
|
||||
property to organize button apps in the app bar within a `coder_agent` in the
|
||||
workspace view.
|
||||
|
||||
Only template defined applications can be arranged. _VS Code_ or _Terminal_
|
||||
buttons are static.
|
||||
|
||||
```tf
|
||||
resource "coder_app" "code-server" {
|
||||
agent_id = coder_agent.main.id
|
||||
slug = "code-server"
|
||||
display_name = "code-server"
|
||||
...
|
||||
|
||||
order = 2
|
||||
}
|
||||
|
||||
resource "coder_app" "filebrowser" {
|
||||
agent_id = coder_agent.main.id
|
||||
display_name = "File Browser"
|
||||
slug = "filebrowser"
|
||||
...
|
||||
|
||||
order = 1
|
||||
}
|
||||
```
|
||||
|
||||
## Inherit order from file
|
||||
|
||||
### Coder parameter options
|
||||
|
||||
The options for Coder parameters maintain the same order as in the file
|
||||
structure. This simplifies management and ensures consistency between
|
||||
configuration files and UI presentation.
|
||||
|
||||
```tf
|
||||
data "coder_parameter" "database_region" {
|
||||
name = "database_region"
|
||||
display_name = "Database Region"
|
||||
|
||||
icon = "/icon/database.svg"
|
||||
description = "These are options."
|
||||
mutable = true
|
||||
default = "us-east1-a"
|
||||
|
||||
// The order of options is stable and inherited from .tf file.
|
||||
option {
|
||||
name = "US Central"
|
||||
description = "Select for central!"
|
||||
value = "us-central1-a"
|
||||
}
|
||||
option {
|
||||
name = "US East"
|
||||
description = "Select for east!"
|
||||
value = "us-east1-a"
|
||||
}
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
### Coder metadata items
|
||||
|
||||
In cases where multiple item properties exist, the order is inherited from the
|
||||
file, facilitating seamless integration between a Coder template and UI
|
||||
presentation.
|
||||
|
||||
```tf
|
||||
resource "coder_metadata" "attached_volumes" {
|
||||
resource_id = docker_image.main.id
|
||||
|
||||
// Items will be presented in the UI in the following order.
|
||||
item {
|
||||
key = "disk-a"
|
||||
value = "60 GiB"
|
||||
}
|
||||
item {
|
||||
key = "disk-b"
|
||||
value = "128 GiB"
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,93 @@
|
||||
# Resource persistence
|
||||
|
||||
By default, all Coder resources are persistent, but production templates
|
||||
**must** use the practices laid out in this document to prevent accidental
|
||||
deletion.
|
||||
|
||||
Coder templates have full control over workspace ephemerality. In a completely
|
||||
ephemeral workspace, there are zero resources in the Off state. In a completely
|
||||
persistent workspace, there is no difference between the Off and On states.
|
||||
|
||||
The needs of most workspaces fall somewhere in the middle, persisting user data
|
||||
like filesystem volumes, but deleting expensive, reproducible resources such as
|
||||
compute instances.
|
||||
|
||||
## Disabling persistence
|
||||
|
||||
The Terraform
|
||||
[`coder_workspace` data source](https://registry.terraform.io/providers/coder/coder/latest/docs/data-sources/workspace)
|
||||
exposes the `start_count = [0 | 1]` attribute. To make a resource ephemeral, you
|
||||
can assign the `start_count` attribute to resource's
|
||||
[`count`](https://developer.hashicorp.com/terraform/language/meta-arguments/count)
|
||||
meta-argument.
|
||||
|
||||
In this example, Coder will provision or tear down the `docker_container`
|
||||
resource:
|
||||
|
||||
```tf
|
||||
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:
|
||||
|
||||
```tf
|
||||
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 will recreate the volume (wiping its data!) the next time
|
||||
that Coder starts the workspace.
|
||||
|
||||
To prevent this, use immutable IDs:
|
||||
|
||||
- `coder_workspace.me.owner_id`
|
||||
- `coder_workspace.me.id`
|
||||
|
||||
```tf
|
||||
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 your persistent resource depends exclusively on immutable IDs, a change
|
||||
to the `name` format or other attributes would cause Terraform to rebuild the
|
||||
resource.
|
||||
|
||||
You can prevent Terraform from recreating a 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).
|
||||
|
||||
```tf
|
||||
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
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,126 @@
|
||||
# Terraform template-wide variables
|
||||
|
||||
In Coder, Terraform templates offer extensive flexibility through template-wide
|
||||
variables. These variables, managed by template authors, facilitate the
|
||||
construction of customizable templates. Unlike parameters, which are primarily
|
||||
for workspace customization, template variables remain under the control of the
|
||||
template author, ensuring workspace users cannot modify them.
|
||||
|
||||
```tf
|
||||
variable "CLOUD_API_KEY" {
|
||||
type = string
|
||||
description = "API key for the service"
|
||||
default = "1234567890"
|
||||
sensitive = true
|
||||
}
|
||||
```
|
||||
|
||||
Given that variables are a
|
||||
[fundamental concept in Terraform](https://developer.hashicorp.com/terraform/language/values/variables),
|
||||
Coder endeavors to fully support them. Native support includes `string`,
|
||||
`number`, and `bool` formats. However, other types such as `list(string)` or
|
||||
`map(any)` will default to being treated as strings.
|
||||
|
||||
## Default value
|
||||
|
||||
Upon adding a template variable, it's mandatory to provide a value during the
|
||||
first push. At this stage, the template administrator faces two choices:
|
||||
|
||||
1. _No `default` property_: opt not to define a default property. Instead,
|
||||
utilize the `--var name=value` command-line argument during the push to
|
||||
supply the variable's value.
|
||||
2. _Define `default` property_: set a default property for the template
|
||||
variable. If the administrator doesn't input a value via CLI, Coder
|
||||
automatically uses this default during the push.
|
||||
|
||||
After the initial push, variables are stored in the database table, associated
|
||||
with the specific template version. They can be conveniently managed via
|
||||
_Template Settings_ without requiring an extra push.
|
||||
|
||||
### Resolved values vs. default values
|
||||
|
||||
It's crucial to note that Coder templates operate based on resolved values
|
||||
during a push, rather than default values. This ensures that default values do
|
||||
not inadvertently override the configured variable settings during the push
|
||||
process.
|
||||
|
||||
This approach caters to users who prefer to avoid accidental overrides of their
|
||||
variable settings with default values during pushes, thereby enhancing control
|
||||
and predictability.
|
||||
|
||||
If you encounter a situation where you need to override template settings for
|
||||
variables, you can employ a straightforward solution:
|
||||
|
||||
1. Create a `terraform.tfvars` file in in the template directory:
|
||||
|
||||
```tf
|
||||
coder_image = newimage:tag
|
||||
```
|
||||
|
||||
2. Push the new template revision using Coder CLI:
|
||||
|
||||
```
|
||||
coder templates push my-template -y # no need to use --var
|
||||
```
|
||||
|
||||
This file serves as a mechanism to override the template settings for variables.
|
||||
It can be stored in the repository for easy access and reference. Coder CLI
|
||||
automatically detects it and loads variable values.
|
||||
|
||||
## Input options
|
||||
|
||||
When working with Terraform configurations in Coder, you have several options
|
||||
for providing values to variables using the Coder CLI:
|
||||
|
||||
1. _Manual input in CLI_: You can manually input values for Terraform variables
|
||||
directly in the CLI during the deployment process.
|
||||
2. _Command-line argument_: Utilize the `--var name=value` command-line argument
|
||||
to specify variable values inline as key-value pairs.
|
||||
3. _Variables file selection_: Alternatively, you can use a variables file
|
||||
selected via the `--variables-file values.yml` command-line argument. This
|
||||
approach is particularly useful when dealing with multiple variables or to
|
||||
avoid manual input of numerous values. Variables files can be versioned for
|
||||
better traceability and management, and it enhances reproducibility.
|
||||
|
||||
Here's an example of a YAML-formatted variables file, `values.yml`:
|
||||
|
||||
```yaml
|
||||
region: us-east-1
|
||||
bucket_name: magic
|
||||
zone_types: '{"us-east-1":"US East", "eu-west-1": "EU West"}'
|
||||
cpu: 1
|
||||
```
|
||||
|
||||
In this sample file:
|
||||
|
||||
- `region`, `bucket_name`, `zone_types`, and `cpu` are Terraform variable names.
|
||||
- Corresponding values are provided for each variable.
|
||||
- The `zone_types` variable demonstrates how to provide a JSON-formatted string
|
||||
as a value in YAML.
|
||||
|
||||
## Terraform .tfvars files
|
||||
|
||||
In Terraform, `.tfvars` files provide a convenient means to define variable
|
||||
values for a project in a reusable manner. These files, ending with either
|
||||
`.tfvars` or `.tfvars.json`, streamline the process of setting numerous
|
||||
variables.
|
||||
|
||||
By utilizing `.tfvars` files, you can efficiently manage and organize variable
|
||||
values for your Terraform projects. This approach offers several advantages:
|
||||
|
||||
- Clarity and consistency: Centralize variable definitions in dedicated files,
|
||||
enhancing clarity, instead of input values on template push.
|
||||
- Ease of maintenance: Modify variable values in a single location under version
|
||||
control, simplifying maintenance and updates.
|
||||
|
||||
Coder automatically loads variable definition files following a specific order,
|
||||
providing flexibility and control over variable configuration. The loading
|
||||
sequence is as follows:
|
||||
|
||||
1. `terraform.tfvars`: This file contains variable values and is loaded first.
|
||||
2. `terraform.tfvars.json`: If present, this JSON-formatted file is loaded after
|
||||
`terraform.tfvars`.
|
||||
3. `\*.auto.tfvars`: Files matching this pattern are loaded next, ordered
|
||||
alphabetically.
|
||||
4. `\*.auto.tfvars.json`: JSON-formatted files matching this pattern are loaded
|
||||
last.
|
||||
@@ -0,0 +1,376 @@
|
||||
# Web IDEs
|
||||
|
||||
In Coder, web IDEs are defined as
|
||||
[coder_app](https://registry.terraform.io/providers/coder/coder/latest/docs/resources/app)
|
||||
resources in the template. With our generic model, any web application can be
|
||||
used as a Coder application. For example:
|
||||
|
||||
```tf
|
||||
# Add button to open Portainer in the workspace dashboard
|
||||
# Note: Portainer must be already running in the workspace
|
||||
resource "coder_app" "portainer" {
|
||||
agent_id = coder_agent.main.id
|
||||
slug = "portainer"
|
||||
display_name = "Portainer"
|
||||
icon = "https://simpleicons.org/icons/portainer.svg"
|
||||
url = "https://localhost:9443/api/status"
|
||||
|
||||
healthcheck {
|
||||
url = "https://localhost:9443/api/status"
|
||||
interval = 6
|
||||
threshold = 10
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## code-server
|
||||
|
||||
[code-server](https://github.com/coder/coder) is our supported method of running
|
||||
VS Code in the web browser. A simple way to install code-server in Linux/macOS
|
||||
workspaces is via the Coder agent in your template:
|
||||
|
||||
```console
|
||||
# edit your template
|
||||
cd your-template/
|
||||
vim main.tf
|
||||
```
|
||||
|
||||
```tf
|
||||
resource "coder_agent" "main" {
|
||||
arch = "amd64"
|
||||
os = "linux"
|
||||
startup_script = <<EOF
|
||||
#!/bin/sh
|
||||
# install code-server
|
||||
# add '-s -- --version x.x.x' to install a specific code-server version
|
||||
curl -fsSL https://code-server.dev/install.sh | sh -s -- --method=standalone --prefix=/tmp/code-server
|
||||
|
||||
# start code-server on a specific port
|
||||
# authn is off since the user already authn-ed into the coder deployment
|
||||
# & is used to run the process in the background
|
||||
/tmp/code-server/bin/code-server --auth none --port 13337 &
|
||||
EOF
|
||||
}
|
||||
```
|
||||
|
||||
For advanced use, we recommend installing code-server in your VM snapshot or
|
||||
container image. Here's a Dockerfile which leverages some special
|
||||
[code-server features](https://coder.com/docs/code-server/):
|
||||
|
||||
```Dockerfile
|
||||
FROM codercom/enterprise-base:ubuntu
|
||||
|
||||
# install the latest version
|
||||
USER root
|
||||
RUN curl -fsSL https://code-server.dev/install.sh | sh
|
||||
USER coder
|
||||
|
||||
# pre-install VS Code extensions
|
||||
RUN code-server --install-extension eamodio.gitlens
|
||||
|
||||
# directly start code-server with the agent's startup_script (see above),
|
||||
# or use a process manager like supervisord
|
||||
```
|
||||
|
||||
You'll also need to specify a `coder_app` resource related to the agent. This is
|
||||
how code-server is displayed on the workspace page.
|
||||
|
||||
```tf
|
||||
resource "coder_app" "code-server" {
|
||||
agent_id = coder_agent.main.id
|
||||
slug = "code-server"
|
||||
display_name = "code-server"
|
||||
url = "http://localhost:13337/?folder=/home/coder"
|
||||
icon = "/icon/code.svg"
|
||||
subdomain = false
|
||||
|
||||
healthcheck {
|
||||
url = "http://localhost:13337/healthz"
|
||||
interval = 2
|
||||
threshold = 10
|
||||
}
|
||||
|
||||
}
|
||||
```
|
||||
|
||||

|
||||
|
||||
## VS Code Web
|
||||
|
||||
VS Code supports launching a local web client using the `code serve-web`
|
||||
command. To add VS Code web as a web IDE, you have two options.
|
||||
|
||||
1. Install using the
|
||||
[vscode-web module](https://registry.coder.com/modules/vscode-web) from the
|
||||
coder registry.
|
||||
|
||||
```tf
|
||||
module "vscode-web" {
|
||||
source = "registry.coder.com/modules/vscode-web/coder"
|
||||
version = "1.0.14"
|
||||
agent_id = coder_agent.main.id
|
||||
accept_license = true
|
||||
}
|
||||
```
|
||||
|
||||
2. Install and start in your `startup_script` and create a corresponding
|
||||
`coder_app`
|
||||
|
||||
```tf
|
||||
resource "coder_agent" "main" {
|
||||
arch = "amd64"
|
||||
os = "linux"
|
||||
startup_script = <<EOF
|
||||
#!/bin/sh
|
||||
# install VS Code
|
||||
curl -Lk 'https://code.visualstudio.com/sha/download?build=stable&os=cli-alpine-x64' --output vscode_cli.tar.gz
|
||||
mkdir -p /tmp/vscode-cli
|
||||
tar -xf vscode_cli.tar.gz -C /tmp/vscode-cli
|
||||
rm vscode_cli.tar.gz
|
||||
# start the web server on a specific port
|
||||
/tmp/vscode-cli/code serve-web --port 13338 --without-connection-token --accept-server-license-terms >/tmp/vscode-web.log 2>&1 &
|
||||
EOF
|
||||
}
|
||||
```
|
||||
|
||||
> `code serve-web` was introduced in version 1.82.0 (August 2023).
|
||||
|
||||
You also need to add a `coder_app` resource for this.
|
||||
|
||||
```tf
|
||||
# VS Code Web
|
||||
resource "coder_app" "vscode-web" {
|
||||
agent_id = coder_agent.coder.id
|
||||
slug = "vscode-web"
|
||||
display_name = "VS Code Web"
|
||||
icon = "/icon/code.svg"
|
||||
url = "http://localhost:13338?folder=/home/coder"
|
||||
subdomain = true # VS Code Web does currently does not work with a subpath https://github.com/microsoft/vscode/issues/192947
|
||||
share = "owner"
|
||||
}
|
||||
```
|
||||
|
||||
## Jupyter Notebook
|
||||
|
||||
To use Jupyter Notebook in your workspace, you can install it by using the
|
||||
[Jupyter Notebook module](https://registry.coder.com/modules/jupyter-notebook)
|
||||
from the Coder registry:
|
||||
|
||||
```tf
|
||||
module "jupyter-notebook" {
|
||||
source = "registry.coder.com/modules/jupyter-notebook/coder"
|
||||
version = "1.0.19"
|
||||
agent_id = coder_agent.example.id
|
||||
}
|
||||
```
|
||||
|
||||

|
||||
|
||||
## JupyterLab
|
||||
|
||||
Configure your agent and `coder_app` like so to use Jupyter. Notice the
|
||||
`subdomain=true` configuration:
|
||||
|
||||
```tf
|
||||
data "coder_workspace" "me" {}
|
||||
|
||||
resource "coder_agent" "coder" {
|
||||
os = "linux"
|
||||
arch = "amd64"
|
||||
dir = "/home/coder"
|
||||
startup_script = <<-EOF
|
||||
pip3 install jupyterlab
|
||||
$HOME/.local/bin/jupyter lab --ServerApp.token='' --ip='*'
|
||||
EOF
|
||||
}
|
||||
|
||||
resource "coder_app" "jupyter" {
|
||||
agent_id = coder_agent.coder.id
|
||||
slug = "jupyter"
|
||||
display_name = "JupyterLab"
|
||||
url = "http://localhost:8888"
|
||||
icon = "/icon/jupyter.svg"
|
||||
share = "owner"
|
||||
subdomain = true
|
||||
|
||||
healthcheck {
|
||||
url = "http://localhost:8888/healthz"
|
||||
interval = 5
|
||||
threshold = 10
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Or Alternatively, you can use the JupyterLab module from the Coder registry:
|
||||
|
||||
```tf
|
||||
module "jupyter" {
|
||||
source = "registry.coder.com/modules/jupyter-lab/coder"
|
||||
version = "1.0.0"
|
||||
agent_id = coder_agent.main.id
|
||||
}
|
||||
```
|
||||
|
||||
If you cannot enable a
|
||||
[wildcard subdomain](../../../admin/setup/index.md#wildcard-access-url), you can
|
||||
configure the template to run Jupyter on a path. There is however
|
||||
[security risk](../../../reference/cli/server.md#--dangerous-allow-path-app-sharing)
|
||||
running an app on a path and the template code is more complicated with coder
|
||||
value substitution to recreate the path structure.
|
||||
|
||||

|
||||
|
||||
## RStudio
|
||||
|
||||
Configure your agent and `coder_app` like so to use RStudio. Notice the
|
||||
`subdomain=true` configuration:
|
||||
|
||||
```tf
|
||||
resource "coder_agent" "coder" {
|
||||
os = "linux"
|
||||
arch = "amd64"
|
||||
dir = "/home/coder"
|
||||
startup_script = <<EOT
|
||||
#!/bin/bash
|
||||
# start rstudio
|
||||
/usr/lib/rstudio-server/bin/rserver --server-daemonize=1 --auth-none=1 &
|
||||
EOT
|
||||
}
|
||||
|
||||
resource "coder_app" "rstudio" {
|
||||
agent_id = coder_agent.coder.id
|
||||
slug = "rstudio"
|
||||
display_name = "R Studio"
|
||||
icon = "https://upload.wikimedia.org/wikipedia/commons/d/d0/RStudio_logo_flat.svg"
|
||||
url = "http://localhost:8787"
|
||||
subdomain = true
|
||||
share = "owner"
|
||||
|
||||
healthcheck {
|
||||
url = "http://localhost:8787/healthz"
|
||||
interval = 3
|
||||
threshold = 10
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
If you cannot enable a
|
||||
[wildcard subdomain](https://coder.com/docs/admin/configure#wildcard-access-url),
|
||||
you can configure the template to run RStudio on a path using an NGINX reverse
|
||||
proxy in the template. There is however
|
||||
[security risk](https://coder.com/docs/reference/cli/server#--dangerous-allow-path-app-sharing)
|
||||
running an app on a path and the template code is more complicated with coder
|
||||
value substitution to recreate the path structure.
|
||||
|
||||
[This](https://github.com/sempie/coder-templates/tree/main/rstudio) is a
|
||||
community template example.
|
||||
|
||||

|
||||
|
||||
## Airflow
|
||||
|
||||
Configure your agent and `coder_app` like so to use Airflow. Notice the
|
||||
`subdomain=true` configuration:
|
||||
|
||||
```tf
|
||||
resource "coder_agent" "coder" {
|
||||
os = "linux"
|
||||
arch = "amd64"
|
||||
dir = "/home/coder"
|
||||
startup_script = <<EOT
|
||||
#!/bin/bash
|
||||
# install and start airflow
|
||||
pip3 install apache-airflow
|
||||
/home/coder/.local/bin/airflow standalone &
|
||||
EOT
|
||||
}
|
||||
|
||||
resource "coder_app" "airflow" {
|
||||
agent_id = coder_agent.coder.id
|
||||
slug = "airflow"
|
||||
display_name = "Airflow"
|
||||
icon = "/icon/airflow.svg"
|
||||
url = "http://localhost:8080"
|
||||
subdomain = true
|
||||
share = "owner"
|
||||
|
||||
healthcheck {
|
||||
url = "http://localhost:8080/healthz"
|
||||
interval = 10
|
||||
threshold = 60
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
or use the [Airflow module](https://registry.coder.com/modules/apache-airflow)
|
||||
from the Coder registry:
|
||||
|
||||
```tf
|
||||
module "airflow" {
|
||||
source = "registry.coder.com/modules/airflow/coder"
|
||||
version = "1.0.13"
|
||||
agent_id = coder_agent.main.id
|
||||
}
|
||||
```
|
||||
|
||||

|
||||
|
||||
## File Browser
|
||||
|
||||
To access the contents of a workspace directory in a browser, you can use File
|
||||
Browser. File Browser is a lightweight file manager that allows you to view and
|
||||
manipulate files in a web browser.
|
||||
|
||||
Show and manipulate the contents of the `/home/coder` directory in a browser.
|
||||
|
||||
```tf
|
||||
resource "coder_agent" "coder" {
|
||||
os = "linux"
|
||||
arch = "amd64"
|
||||
dir = "/home/coder"
|
||||
startup_script = <<EOT
|
||||
#!/bin/bash
|
||||
|
||||
curl -fsSL https://raw.githubusercontent.com/filebrowser/get/master/get.sh | bash
|
||||
filebrowser --noauth --root /home/coder --port 13339 >/tmp/filebrowser.log 2>&1 &
|
||||
|
||||
EOT
|
||||
}
|
||||
|
||||
resource "coder_app" "filebrowser" {
|
||||
agent_id = coder_agent.coder.id
|
||||
display_name = "file browser"
|
||||
slug = "filebrowser"
|
||||
url = "http://localhost:13339"
|
||||
icon = "https://raw.githubusercontent.com/matifali/logos/main/database.svg"
|
||||
subdomain = true
|
||||
share = "owner"
|
||||
|
||||
healthcheck {
|
||||
url = "http://localhost:13339/healthz"
|
||||
interval = 3
|
||||
threshold = 10
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Or alternatively, you can use the
|
||||
[`filebrowser`](https://registry.coder.com/modules/filebrowser) module from the
|
||||
Coder registry:
|
||||
|
||||
```tf
|
||||
module "filebrowser" {
|
||||
source = "registry.coder.com/modules/filebrowser/coder"
|
||||
version = "1.0.8"
|
||||
agent_id = coder_agent.main.id
|
||||
}
|
||||
```
|
||||
|
||||

|
||||
|
||||
## SSH Fallback
|
||||
|
||||
If you prefer to run web IDEs in localhost, you can port forward using
|
||||
[SSH](../../../user-guides/workspace-access/index.md#ssh) or the Coder CLI
|
||||
`port-forward` sub-command. Some web IDEs may not support URL base path
|
||||
adjustment so port forwarding is the only approach.
|
||||
@@ -0,0 +1,87 @@
|
||||
# Workspace Tags
|
||||
|
||||
Template administrators can leverage static template tags to limit workspace
|
||||
provisioning to designated provisioner groups that have locally deployed
|
||||
credentials for creating workspace resources. While this method ensures
|
||||
controlled access, it offers limited flexibility and does not permit users to
|
||||
select the nodes for their workspace creation.
|
||||
|
||||
By using `coder_workspace_tags` and `coder_parameter`s, template administrators
|
||||
can enable dynamic tag selection and modify static template tags.
|
||||
|
||||
## Dynamic tag selection
|
||||
|
||||
Here is a sample `coder_workspace_tags` data resource with a few workspace tags
|
||||
specified:
|
||||
|
||||
```tf
|
||||
data "coder_workspace_tags" "custom_workspace_tags" {
|
||||
tags = {
|
||||
"zone" = "developers"
|
||||
"runtime" = data.coder_parameter.runtime_selector.value
|
||||
"project_id" = "PROJECT_${data.coder_parameter.project_name.value}"
|
||||
"cache" = data.coder_parameter.feature_cache_enabled.value == "true" ? "with-cache" : "no-cache"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Legend**
|
||||
|
||||
- `zone` - static tag value set to `developers`
|
||||
- `runtime` - supported by the string-type `coder_parameter` to select
|
||||
provisioner runtime, `runtime_selector`
|
||||
- `project_id` - a formatted string supported by the string-type
|
||||
`coder_parameter`, `project_name`
|
||||
- `cache` - an HCL condition involving boolean-type `coder_parameter`,
|
||||
`feature_cache_enabled`
|
||||
|
||||
Review the
|
||||
[full template example](https://github.com/coder/coder/tree/main/examples/workspace-tags)
|
||||
using `coder_workspace_tags` and `coder_parameter`s.
|
||||
|
||||
## Constraints
|
||||
|
||||
### Tagged provisioners
|
||||
|
||||
It is possible to choose tag combinations that no provisioner can handle. This
|
||||
will cause the provisioner job to get stuck in the queue until a provisioner is
|
||||
added that can handle its combination of tags.
|
||||
|
||||
Before releasing the template version with configurable workspace tags, ensure
|
||||
that every tag set is associated with at least one healthy provisioner.
|
||||
|
||||
### Parameters types
|
||||
|
||||
Provisioners require job tags to be defined in plain string format. When a
|
||||
workspace tag refers to a `coder_parameter` without involving the string
|
||||
formatter, for example,
|
||||
(`"runtime" = data.coder_parameter.runtime_selector.value`), the Coder
|
||||
provisioner server can transform only the following parameter types to strings:
|
||||
_string_, _number_, and _bool_.
|
||||
|
||||
### Mutability
|
||||
|
||||
A mutable `coder_parameter` can be dangerous for a workspace tag as it allows
|
||||
the workspace owner to change a provisioner group (due to different tags). In
|
||||
most cases, `coder_parameter`s backing `coder_workspace_tags` should be marked
|
||||
as immutable and set only once, during workspace creation.
|
||||
|
||||
### HCL syntax
|
||||
|
||||
When importing the template version with `coder_workspace_tags`, the Coder
|
||||
provisioner server extracts raw partial queries for each workspace tag and
|
||||
stores them in the database. During workspace build time, the Coder server uses
|
||||
the [Hashicorp HCL library](https://github.com/hashicorp/hcl) to evaluate these
|
||||
raw queries on-the-fly without processing the entire Terraform template. This
|
||||
evaluation is simpler but also limited in terms of available functions,
|
||||
variables, and references to other resources.
|
||||
|
||||
**Supported syntax**
|
||||
|
||||
- Static string: `foobar_tag = "foobaz"`
|
||||
- Formatted string: `foobar_tag = "foobaz ${data.coder_parameter.foobaz.value}"`
|
||||
- Reference to `coder_parameter`:
|
||||
`foobar_tag = data.coder_parameter.foobar.value`
|
||||
- Boolean logic: `production_tag = !data.coder_parameter.staging_env.value`
|
||||
- Condition:
|
||||
`cache = data.coder_parameter.feature_cache_enabled.value == "true" ? "with-cache" : "no-cache"`
|
||||
@@ -0,0 +1,62 @@
|
||||
# Template
|
||||
|
||||
Templates are written in
|
||||
[Terraform](https://developer.hashicorp.com/terraform/intro) and define the
|
||||
underlying infrastructure that all Coder workspaces run on.
|
||||
|
||||

|
||||
|
||||
<small>The "Starter Templates" page within the Coder dashboard.</small>
|
||||
|
||||
## Learn the concepts
|
||||
|
||||
While templates are written in standard Terraform, it's important to learn the
|
||||
Coder-specific concepts behind templates. The best way to learn the concepts is
|
||||
by
|
||||
[creating a basic template from scratch](../../tutorials/template-from-scratch.md).
|
||||
If you are unfamiliar with Terraform, see
|
||||
[Hashicorp's Tutorials](https://developer.hashicorp.com/terraform/tutorials) for
|
||||
common cloud providers.
|
||||
|
||||
## Starter templates
|
||||
|
||||
After learning the basics, use starter templates to import a template with
|
||||
sensible defaults for popular platforms (e.g. AWS, Kubernetes, Docker, etc).
|
||||
Docs:
|
||||
[Create a template from a starter template](./creating-templates.md#from-a-starter-template).
|
||||
|
||||
## Extending templates
|
||||
|
||||
It's often necessary to extend the template to make it generally useful to end
|
||||
users. Common modifications are:
|
||||
|
||||
- Your image(s) (e.g. a Docker image with languages and tools installed). Docs:
|
||||
[Image management](./managing-templates/image-management.md).
|
||||
- Additional parameters (e.g. disk size, instance type, or region). Docs:
|
||||
[Template parameters](./extending-templates/parameters.md).
|
||||
- Additional IDEs (e.g. JetBrains) or features (e.g. dotfiles, RDP). Docs:
|
||||
[Adding IDEs and features](./extending-templates/index.md).
|
||||
|
||||
Learn more about the various ways you can
|
||||
[extend your templates](./extending-templates/index.md).
|
||||
|
||||
## Best Practices
|
||||
|
||||
We recommend starting with a universal template that can be used for basic
|
||||
tasks. As your Coder deployment grows, you can create more templates to meet the
|
||||
needs of different teams.
|
||||
|
||||
- [Image management](./managing-templates/image-management.md): Learn how to
|
||||
create and publish images for use within Coder workspaces & templates.
|
||||
- [Dev Container support](./managing-templates/devcontainers.md): Enable dev
|
||||
containers to allow teams to bring their own tools into Coder workspaces.
|
||||
- [Template hardening](./extending-templates/resource-persistence.md#-bulletproofing):
|
||||
Configure your template to prevent certain resources from being destroyed
|
||||
(e.g. user disks).
|
||||
- [Manage templates with Ci/Cd pipelines](./managing-templates/change-management.md):
|
||||
Learn how to source control your templates and use GitOps to ensure template
|
||||
changes are reviewed and tested.
|
||||
- [Permissions and Policies](./template-permissions.md): Control who may access
|
||||
and modify your template.
|
||||
|
||||
<children></children>
|
||||
@@ -0,0 +1,95 @@
|
||||
# Template Change Management
|
||||
|
||||
We recommend source-controlling your templates as you would other any code, and
|
||||
automating the creation of new versions in CI/CD pipelines.
|
||||
|
||||
These pipelines will require tokens for your deployment. To cap token lifetime
|
||||
on creation,
|
||||
[configure Coder server to set a shorter max token lifetime](../../../reference/cli/server.md#--max-token-lifetime).
|
||||
|
||||
## coderd Terraform Provider
|
||||
|
||||
The
|
||||
[coderd Terraform provider](https://registry.terraform.io/providers/coder/coderd/latest)
|
||||
can be used to push new template versions, either manually, or in CI/CD
|
||||
pipelines. To run the provider in a CI/CD pipeline, and to prevent drift, you'll
|
||||
need to store the Terraform state
|
||||
[remotely](https://developer.hashicorp.com/terraform/language/backend).
|
||||
|
||||
```tf
|
||||
terraform {
|
||||
required_providers {
|
||||
coderd = {
|
||||
source = "coder/coderd"
|
||||
}
|
||||
}
|
||||
backend "gcs" {
|
||||
bucket = "example-bucket"
|
||||
prefix = "terraform/state"
|
||||
}
|
||||
}
|
||||
|
||||
provider "coderd" {
|
||||
// Can be populated from environment variables
|
||||
url = "https://coder.example.com"
|
||||
token = "****"
|
||||
}
|
||||
|
||||
// Get the commit SHA of the configuration's git repository
|
||||
variable "TFC_CONFIGURATION_VERSION_GIT_COMMIT_SHA" {
|
||||
type = string
|
||||
}
|
||||
|
||||
resource "coderd_template" "kubernetes" {
|
||||
name = "kubernetes"
|
||||
description = "Develop in Kubernetes!"
|
||||
versions = [{
|
||||
directory = ".coder/templates/kubernetes"
|
||||
active = true
|
||||
# Version name is optional
|
||||
name = var.TFC_CONFIGURATION_VERSION_GIT_COMMIT_SHA
|
||||
tf_vars = [{
|
||||
name = "namespace"
|
||||
value = "default4"
|
||||
}]
|
||||
}]
|
||||
/* ... Additional template configuration */
|
||||
}
|
||||
```
|
||||
|
||||
For an example, see how we push our development image and template
|
||||
[with GitHub actions](https://github.com/coder/coder/blob/main/.github/workflows/dogfood.yaml).
|
||||
|
||||
## Coder CLI
|
||||
|
||||
You can also [install Coder](../../../install/cli.md) to automate pushing new
|
||||
template versions in CI/CD pipelines.
|
||||
|
||||
```console
|
||||
# Install the Coder CLI
|
||||
curl -L https://coder.com/install.sh | sh
|
||||
# curl -L https://coder.com/install.sh | sh -s -- --version=0.x
|
||||
|
||||
# To create API tokens, use `coder tokens create`.
|
||||
# If no `--lifetime` flag is passed during creation, the default token lifetime
|
||||
# will be 30 days.
|
||||
# These variables are consumed by Coder
|
||||
export CODER_URL=https://coder.example.com
|
||||
export CODER_SESSION_TOKEN=*****
|
||||
|
||||
# Template details
|
||||
export CODER_TEMPLATE_NAME=kubernetes
|
||||
export CODER_TEMPLATE_DIR=.coder/templates/kubernetes
|
||||
export CODER_TEMPLATE_VERSION=$(git rev-parse --short HEAD)
|
||||
|
||||
# Push the new template version to Coder
|
||||
coder templates push --yes $CODER_TEMPLATE_NAME \
|
||||
--directory $CODER_TEMPLATE_DIR \
|
||||
--name=$CODER_TEMPLATE_VERSION # Version name is optional
|
||||
```
|
||||
|
||||
### Next steps
|
||||
|
||||
- [Coder CLI Reference](../../../reference/cli/templates.md)
|
||||
- [Coderd Terraform Provider Reference](https://registry.terraform.io/providers/coder/coderd/latest/docs)
|
||||
- [Coderd API Reference](../../../reference/index.md)
|
||||
@@ -0,0 +1,114 @@
|
||||
# Template Dependencies
|
||||
|
||||
When creating Coder templates, it is unlikely that you will just be using
|
||||
built-in providers. Part of Terraform's flexibility stems from its rich plugin
|
||||
ecosystem, and it makes sense to take advantage of this.
|
||||
|
||||
That having been said, here are some recommendations to follow, based on the
|
||||
[Terraform documentation](https://developer.hashicorp.com/terraform/tutorials/configuration-language/provider-versioning).
|
||||
|
||||
Following these recommendations will:
|
||||
|
||||
- **Prevent unexpected changes:** Your templates will use the same versions of
|
||||
Terraform providers each build. This will prevent issues related to changes in
|
||||
providers.
|
||||
- **Improve build performance:** Coder caches provider versions on each build.
|
||||
If the same provider version can be re-used on subsequent builds, Coder will
|
||||
simply re-use the cached version if it is available.
|
||||
- **Improve build reliability:** As some providers are hundreds of megabytes in
|
||||
size, interruptions in connectivity to the Terraform registry during a
|
||||
workspace build can result in a failed build. If Coder is able to re-use a
|
||||
cached provider version, the likelihood of this is greatly reduced.
|
||||
|
||||
## Lock your provider and module versions
|
||||
|
||||
If you add a Terraform provider to `required_providers` without specifying a
|
||||
version requirement, Terraform will always fetch the latest version on each
|
||||
invocation:
|
||||
|
||||
```terraform
|
||||
terraform {
|
||||
required_providers {
|
||||
coder = {
|
||||
source = "coder/coder"
|
||||
}
|
||||
frobnicate = {
|
||||
source = "acme/frobnicate"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Any new releases of the `coder` or `frobnicate` providers will be picked up upon
|
||||
the next time a workspace is built using this template. This may include
|
||||
breaking changes.
|
||||
|
||||
To prevent this, add a
|
||||
[version constraint](https://developer.hashicorp.com/terraform/language/expressions/version-constraints)
|
||||
to each provider in the `required_providers` block:
|
||||
|
||||
```terraform
|
||||
terraform {
|
||||
required_providers {
|
||||
coder = {
|
||||
source = "coder/coder"
|
||||
version = ">= 0.2, < 0.3"
|
||||
}
|
||||
frobnicate = {
|
||||
source = "acme/frobnicate"
|
||||
version = "~> 1.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
In the above example, the `coder/coder` provider will be limited to all versions
|
||||
above or equal to `0.2.0` and below `0.3.0`, while the `acme/frobnicate`
|
||||
provider will be limited to all versions matching `1.0.x`.
|
||||
|
||||
The above also applies to Terraform modules. In the below example, the module
|
||||
`razzledazzle` is locked to version `1.2.3`.
|
||||
|
||||
```terraform
|
||||
module "razzledazzle" {
|
||||
source = "registry.example.com/modules/razzle/dazzle"
|
||||
version = "1.2.3"
|
||||
foo = "bar"
|
||||
}
|
||||
```
|
||||
|
||||
## Use a Dependency Lock File
|
||||
|
||||
Terraform allows creating a
|
||||
[dependency lock file](https://developer.hashicorp.com/terraform/language/files/dependency-lock)
|
||||
to track which provider versions were selected previously. This allows you to
|
||||
ensure that the next workspace build uses the same provider versions as with the
|
||||
last build.
|
||||
|
||||
To create a new Terraform lock file, run the
|
||||
[`terraform init` command](https://developer.hashicorp.com/terraform/cli/commands/init)
|
||||
inside a folder containing the Terraform source code for a given template.
|
||||
|
||||
This will create a new file named `.terraform.lock.hcl` in the current
|
||||
directory. When you next run
|
||||
[`coder templates push`](../../../reference/cli/templates_push.md), the lock
|
||||
file will be stored alongside with the other template source code.
|
||||
|
||||
> Note: Terraform best practices also recommend checking in your
|
||||
> `.terraform.lock.hcl` into Git or other VCS.
|
||||
|
||||
The next time a workspace is built from that template, Coder will make sure to
|
||||
use the same versions of those providers as specified in the lock file.
|
||||
|
||||
If, at some point in future, you need to update the providers and versions you
|
||||
specified within the version constraints of the template, run
|
||||
|
||||
```console
|
||||
terraform init -upgrade
|
||||
```
|
||||
|
||||
This will check each provider, check the newest satisfiable version based on the
|
||||
version constraints you specified, and update the `.terraform.lock.hcl` with
|
||||
those new versions. When you next run `coder templates push`, again, the updated
|
||||
lock file will be stored and used to determine the provider versions to use for
|
||||
subsequent workspace builds.
|
||||
@@ -0,0 +1,112 @@
|
||||
# Dev Containers
|
||||
|
||||
[Development containers](https://containers.dev) are an open source
|
||||
specification for defining development environments.
|
||||
|
||||
[Envbuilder](https://github.com/coder/envbuilder) is an open source project by
|
||||
Coder that runs dev containers via Coder templates and your underlying
|
||||
infrastructure. It can run on Docker or Kubernetes.
|
||||
|
||||
There are several benefits to adding a devcontainer-compatible template to
|
||||
Coder:
|
||||
|
||||
- Drop-in migration from Codespaces (or any existing repositories that use dev
|
||||
containers)
|
||||
- Easier to start projects from Coder. Just create a new workspace then pick a
|
||||
starter devcontainer.
|
||||
- Developer teams can "bring their own image." No need for platform teams to
|
||||
manage complex images, registries, and CI pipelines.
|
||||
|
||||
## How it works
|
||||
|
||||
A Coder admin adds a devcontainer-compatible template to Coder (envbuilder).
|
||||
Then developers enter their repository URL as a
|
||||
[parameter](../extending-templates/parameters.md) when they create their
|
||||
workspace. [Envbuilder](https://github.com/coder/envbuilder) clones the repo and
|
||||
builds a container from the `devcontainer.json` specified in the repo.
|
||||
|
||||
When using the [Envbuilder Terraform provider](#provider), a previously built
|
||||
and cached image can be re-used directly, allowing instantaneous dev container
|
||||
starts.
|
||||
|
||||
Developers can edit the `devcontainer.json` in their workspace to rebuild to
|
||||
iterate on their development environments.
|
||||
|
||||
## Example templates
|
||||
|
||||
- [Devcontainers (Docker)](https://github.com/coder/coder/tree/main/examples/templates/devcontainer-docker)
|
||||
provisions a development container using Docker.
|
||||
- [Devcontainers (Kubernetes)](https://github.com/coder/coder/tree/main/examples/templates/devcontainer-kubernetes)
|
||||
provisioners a development container on the Kubernetes.
|
||||
- [Google Compute Engine (Devcontainer)](https://github.com/coder/coder/tree/main/examples/templates/gcp-devcontainer)
|
||||
runs a development container inside a single GCP instance. It also mounts the
|
||||
Docker socket from the VM inside the container to enable Docker inside the
|
||||
workspace.
|
||||
- [AWS EC2 (Devcontainer)](https://github.com/coder/coder/tree/main/examples/templates/aws-devcontainer)
|
||||
runs a development container inside a single EC2 instance. It also mounts the
|
||||
Docker socket from the VM inside the container to enable Docker inside the
|
||||
workspace.
|
||||
|
||||

|
||||
|
||||
Your template can prompt the user for a repo URL with
|
||||
[Parameters](../extending-templates/parameters.md).
|
||||
|
||||
## Authentication
|
||||
|
||||
You may need to authenticate to your container registry, such as Artifactory, or
|
||||
git provider such as GitLab, to use Envbuilder. See the
|
||||
[Envbuilder documentation](https://github.com/coder/envbuilder/blob/main/docs/container-registry-auth.md)
|
||||
for more information.
|
||||
|
||||
## Caching
|
||||
|
||||
To improve build times, dev containers can be cached. There are two main forms
|
||||
of caching:
|
||||
|
||||
1. **Layer Caching** caches individual layers and pushes them to a remote
|
||||
registry. When building the image, Envbuilder will check the remote registry
|
||||
for pre-existing layers. These will be fetched and extracted to disk instead
|
||||
of building the layers from scratch.
|
||||
2. **Image Caching** caches the _entire image_, skipping the build process
|
||||
completely (except for post-build lifecycle scripts).
|
||||
|
||||
Refer to the
|
||||
[Envbuilder documentation](https://github.com/coder/envbuilder/blob/main/docs/caching.md)
|
||||
for more information.
|
||||
|
||||
## Envbuilder Terraform Provider
|
||||
|
||||
To support resuming from a cached image, use the
|
||||
[Envbuilder Terraform Provider](https://github.com/coder/terraform-provider-envbuilder)
|
||||
in your template. The provider will:
|
||||
|
||||
1. Clone the remote Git repository,
|
||||
2. Perform a 'dry-run' build of the dev container in the same manner as
|
||||
Envbuilder would,
|
||||
3. Check for the presence of a previously built image in the provided cache
|
||||
repository,
|
||||
4. Output the image remote reference in SHA256 form, if found.
|
||||
|
||||
The above example templates will use the provider if a remote cache repository
|
||||
is provided.
|
||||
|
||||
If you are building your own Devcontainer template, you can consult the
|
||||
[provider documentation](https://registry.terraform.io/providers/coder/envbuilder/latest/docs/resources/cached_image).
|
||||
You may also wish to consult a
|
||||
[documented example usage of the `envbuilder_cached_image` resource](https://github.com/coder/terraform-provider-envbuilder/blob/main/examples/resources/envbuilder_cached_image/envbuilder_cached_image_resource.tf).
|
||||
|
||||
## Other features & known issues
|
||||
|
||||
Envbuilder provides two release channels:
|
||||
|
||||
- **Stable:** available at
|
||||
[`ghcr.io/coder/envbuilder`](https://github.com/coder/envbuilder/pkgs/container/envbuilder).
|
||||
Tags `>=1.0.0` are considered stable.
|
||||
- **Preview:** available at
|
||||
[`ghcr.io/coder/envbuilder-preview`](https://github.com/coder/envbuilder/pkgs/container/envbuilder-preview).
|
||||
This is built from the tip of `main`, and should be considered
|
||||
**experimental** and prone to **breaking changes**.
|
||||
|
||||
Refer to the [Envbuilder GitHub repo](https://github.com/coder/envbuilder/) for
|
||||
more information and to submit feature requests or bug reports.
|
||||
@@ -0,0 +1,73 @@
|
||||
# Image Management
|
||||
|
||||
While Coder provides example
|
||||
[base container images](https://github.com/coder/enterprise-images) for
|
||||
workspaces, it's often best to create custom images that matches the needs of
|
||||
your users. This document serves a guide to operational maturity with some best
|
||||
practices around managing workspaces images for Coder.
|
||||
|
||||
1. Create a minimal base image
|
||||
2. Create golden image(s) with standard tooling
|
||||
3. Allow developers to bring their own images and customizations with Dev
|
||||
Containers
|
||||
|
||||
> Note: An image is just one of the many properties defined within the template.
|
||||
> Templates can pull images from a public image registry (e.g. Docker Hub) or an
|
||||
> internal one., thanks to Terraform.
|
||||
|
||||
## Create a minimal base image
|
||||
|
||||
While you may not use this directly in Coder templates, it's useful to have a
|
||||
minimal base image is a small image that contains only the necessary
|
||||
dependencies to work in your network and work with Coder. Here are some things
|
||||
to consider:
|
||||
|
||||
- `curl`, `wget`, or `busybox` is required to download and run
|
||||
[the agent](https://github.com/coder/coder/blob/main/provisionersdk/scripts/bootstrap_linux.sh)
|
||||
- `git` is recommended so developers can clone repositories
|
||||
- If the Coder server is using a certificate from an internal certificate
|
||||
authority (CA), you'll need to add or mount these into your image
|
||||
- Other generic utilities that will be required by all users, such as `ssh`,
|
||||
`docker`, `bash`, `jq`, and/or internal tooling
|
||||
- Consider creating (and starting the container with) a non-root user
|
||||
|
||||
> See Coder's
|
||||
> [example base image](https://github.com/coder/enterprise-images/tree/main/images/minimal)
|
||||
> for reference.
|
||||
|
||||
## Create general-purpose golden image(s) with standard tooling
|
||||
|
||||
It's often practical to have a few golden images that contain standard tooling
|
||||
for developers. These images should contain a number of languages (e.g. Python,
|
||||
Java, TypeScript), IDEs (VS Code, JetBrains, PyCharm), and other tools (e.g.
|
||||
`docker`). Unlike project-specific images (which are also important), general
|
||||
purpose images are great for:
|
||||
|
||||
- **Scripting:** Developers may just want to hop in a Coder workspace to run
|
||||
basic scripts or queries.
|
||||
- **Day 1 Onboarding:** New developers can quickly get started with a familiar
|
||||
environment without having to browse through (or create) an image
|
||||
- **Basic Projects:** Developers can use these images for simple projects that
|
||||
don't require any specific tooling outside of the standard libraries. As the
|
||||
project gets more complex, its best to move to a project-specific image.
|
||||
- **"Golden Path" Projects:** If your developer platform offers specific tech
|
||||
stacks and types of projects, the golden image can be a good starting point
|
||||
for those projects.
|
||||
|
||||
> This is often referred to as a "sandbox" or "kitchen sink" image. Since large
|
||||
> multi-purpose container images can quickly become difficult to maintain, it's
|
||||
> important to keep the number of general-purpose images to a minimum (2-3 in
|
||||
> most cases) with a well-defined scope.
|
||||
|
||||
Examples:
|
||||
|
||||
- [Universal Dev Containers Image](https://github.com/devcontainers/images/tree/main/src/universal)
|
||||
|
||||
## Allow developers to bring their own images and customizations with Dev Containers
|
||||
|
||||
While golden images are great for general use cases, developers will often need
|
||||
specific tooling for their projects. The [Dev Container](https://containers.dev)
|
||||
specification allows developers to define their projects dependencies within a
|
||||
`devcontainer.json` in their Git repository.
|
||||
|
||||
- [Learn how to integrate Dev Containers with Coder](./devcontainers.md)
|
||||
@@ -0,0 +1,95 @@
|
||||
# Working with templates
|
||||
|
||||
You create and edit Coder templates as [Terraform](../../../start/coder-tour.md)
|
||||
configuration files (`.tf`) and any supporting files, like a README or
|
||||
configuration files for other services.
|
||||
|
||||
## Who creates templates?
|
||||
|
||||
The [Template Admin](../../../admin/users/groups-roles.md#roles) role (and
|
||||
above) can create templates. End users, like developers, create workspaces from
|
||||
them. Templates can also be [managed with git](./change-management.md), allowing
|
||||
any developer to propose changes to a template.
|
||||
|
||||
You can give different users and groups access to templates with
|
||||
[role-based access control](../template-permissions.md).
|
||||
|
||||
## Starter templates
|
||||
|
||||
We provide starter templates for common cloud providers, like AWS, and
|
||||
orchestrators, like Kubernetes. From there, you can modify them to use your own
|
||||
images, VPC, cloud credentials, and so on. Coder supports all Terraform
|
||||
resources and properties, so fear not if your favorite cloud provider isn't
|
||||
here!
|
||||
|
||||

|
||||
|
||||
If you prefer to use Coder on the
|
||||
[command line](../../../reference/cli/index.md), `coder templates init`.
|
||||
|
||||
> Coder starter templates are also available on our
|
||||
> [GitHub repo](https://github.com/coder/coder/tree/main/examples/templates).
|
||||
|
||||
## Community Templates
|
||||
|
||||
As well as Coder's starter templates, you can see a list of community templates
|
||||
by our users
|
||||
[here](https://github.com/coder/coder/blob/main/examples/templates/community-templates.md).
|
||||
|
||||
## Editing templates
|
||||
|
||||
Our starter templates are meant to be modified for your use cases. You can edit
|
||||
any template's files directly in the Coder dashboard.
|
||||
|
||||

|
||||
|
||||
If you'd prefer to use the CLI, use `coder templates pull`, edit the template
|
||||
files, then `coder templates push`.
|
||||
|
||||
> Even if you are a Terraform expert, we suggest reading our
|
||||
> [guided tour of a template](../../../tutorials/template-from-scratch.md).
|
||||
|
||||
## Updating templates
|
||||
|
||||
Coder tracks a template's versions, keeping all developer workspaces up-to-date.
|
||||
When you publish a new version, developers are notified to get the latest
|
||||
infrastructure, software, or security patches. Learn more about
|
||||
[change management](./change-management.md).
|
||||
|
||||

|
||||
|
||||
### Template update policies (enterprise) (premium)
|
||||
|
||||
Enterprise template admins may want workspaces to always remain on the latest
|
||||
version of their parent template. To do so, enable **Template Update Policies**
|
||||
in the template's general settings. All non-admin users of the template will be
|
||||
forced to update their workspaces before starting them once the setting is
|
||||
applied. Workspaces which leverage autostart or start-on-connect will be
|
||||
automatically updated on the next startup.
|
||||
|
||||

|
||||
|
||||
## Delete templates
|
||||
|
||||
You can delete a template using both the coder CLI and UI. Only
|
||||
[template admins and owners](../../users/groups-roles.md#roles) can delete a
|
||||
template, and the template must not have any running workspaces associated to
|
||||
it.
|
||||
|
||||
In the UI, navigate to the template you want to delete, and select the dropdown
|
||||
in the right-hand corner of the page to delete the template.
|
||||
|
||||

|
||||
|
||||
Using the CLI, login to Coder and run the following command to delete a
|
||||
template:
|
||||
|
||||
```shell
|
||||
coder templates delete <template-name>
|
||||
```
|
||||
|
||||
## Next steps
|
||||
|
||||
- [Image management](./image-management.md)
|
||||
- [Devcontainer templates](./devcontainers.md)
|
||||
- [Change management](./change-management.md)
|
||||
@@ -0,0 +1,103 @@
|
||||
# Workspace Scheduling
|
||||
|
||||
You can configure a template to control how workspaces are started and stopped.
|
||||
You can also manage the lifecycle of failed or inactive workspaces.
|
||||
|
||||

|
||||
|
||||
## Schedule
|
||||
|
||||
Template [admins](../../users/index.md) may define these default values:
|
||||
|
||||
- [**Default autostop**](../../../user-guides/workspace-scheduling.md#autostop):
|
||||
How long a workspace runs without user activity before Coder automatically
|
||||
stops it.
|
||||
- [**Autostop requirement**](#autostop-requirement-enterprise-premium): Enforce
|
||||
mandatory workspace restarts to apply template updates regardless of user
|
||||
activity.
|
||||
- **Activity bump**: The duration of inactivity that must pass before a
|
||||
workspace is automatically stopped.
|
||||
- **Dormancy**: This allows automatic deletion of unused workspaces to reduce
|
||||
spend on idle resources.
|
||||
|
||||
## Allow users scheduling
|
||||
|
||||
For templates where a uniform autostop duration is not appropriate, admins may
|
||||
allow users to define their own autostart and autostop schedules. Admins can
|
||||
restrict the days of the week a workspace should automatically start to help
|
||||
manage infrastructure costs.
|
||||
|
||||
## Failure cleanup (enterprise) (premium)
|
||||
|
||||
Failure cleanup defines how long a workspace is permitted to remain in the
|
||||
failed state prior to being automatically stopped. Failure cleanup is an
|
||||
enterprise-only feature.
|
||||
|
||||
## Dormancy threshold (enterprise) (premium)
|
||||
|
||||
Dormancy Threshold defines how long Coder allows a workspace to remain inactive
|
||||
before being moved into a dormant state. A workspace's inactivity is determined
|
||||
by the time elapsed since a user last accessed the workspace. A workspace in the
|
||||
dormant state is not eligible for autostart and must be manually activated by
|
||||
the user before being accessible. Coder stops workspaces during their transition
|
||||
to the dormant state if they are detected to be running. Dormancy Threshold is
|
||||
an enterprise-only feature.
|
||||
|
||||
## Dormancy auto-deletion (enterprise) (premium)
|
||||
|
||||
Dormancy Auto-Deletion allows a template admin to dictate how long a workspace
|
||||
is permitted to remain dormant before it is automatically deleted. Dormancy
|
||||
Auto-Deletion is an enterprise-only feature.
|
||||
|
||||
## Autostop requirement (enterprise) (premium)
|
||||
|
||||
Autostop requirement is a template setting that determines how often workspaces
|
||||
using the template must automatically stop. Autostop requirement ignores any
|
||||
active connections, and ensures that workspaces do not run in perpetuity when
|
||||
connections are left open inadvertently.
|
||||
|
||||
Workspaces will apply the template autostop requirement on the given day in the
|
||||
user's timezone and specified quiet hours (see below). This ensures that
|
||||
workspaces will not be stopped during work hours.
|
||||
|
||||
The available options are "Days", which can be set to "Daily", "Saturday" or
|
||||
"Sunday", and "Weeks", which can be set to any number from 1 to 16.
|
||||
|
||||
"Days" governs which days of the week workspaces must stop. If you select
|
||||
"daily", workspaces must be automatically stopped every day at the start of the
|
||||
user's defined quiet hours. When using "Saturday" or "Sunday", workspaces will
|
||||
be automatically stopped on Saturday or Sunday in the user's timezone and quiet
|
||||
hours.
|
||||
|
||||
"Weeks" determines how many weeks between required stops. It cannot be changed
|
||||
from the default of 1 if you have selected "Daily" for "Days". When using a
|
||||
value greater than 1, workspaces will be automatically stopped every N weeks on
|
||||
the day specified by "Days" and the user's quiet hours. The autostop week is
|
||||
synchronized for all workspaces on the same template.
|
||||
|
||||
Autostop requirement is disabled when the template is using the deprecated max
|
||||
lifetime feature. Templates can choose to use a max lifetime or an autostop
|
||||
requirement during the deprecation period, but only one can be used at a time.
|
||||
|
||||
## User quiet hours (enterprise) (premium)
|
||||
|
||||
User quiet hours can be configured in the user's schedule settings page.
|
||||
Workspaces on templates with an autostop requirement will only be forcibly
|
||||
stopped due to the policy at the start of the user's quiet hours.
|
||||
|
||||

|
||||
|
||||
Admins can define the default quiet hours for all users with the
|
||||
`--default-quiet-hours-schedule` flag or `CODER_DEFAULT_QUIET_HOURS_SCHEDULE`
|
||||
environment variable. The value should be a cron expression such as
|
||||
`CRON_TZ=America/Chicago 30 2 * * *` which would set the default quiet hours to
|
||||
2:30 AM in the America/Chicago timezone. The cron schedule can only have a
|
||||
minute and hour component. The default schedule is UTC 00:00. It is recommended
|
||||
to set the default quiet hours to a time when most users are not expected to be
|
||||
using Coder.
|
||||
|
||||
Admins can force users to use the default quiet hours with the
|
||||
[CODER_ALLOW_CUSTOM_QUIET_HOURS](../../../reference/cli/server.md#allow-custom-quiet-hours)
|
||||
environment variable. Users will still be able to see the page, but will be
|
||||
unable to set a custom time or timezone. If users have already set a custom
|
||||
quiet hours schedule, it will be ignored and the default will be used instead.
|
||||
@@ -0,0 +1,120 @@
|
||||
# Open in Coder
|
||||
|
||||
You can embed an "Open in Coder" button into your git repos or internal wikis to
|
||||
let developers quickly launch a new workspace.
|
||||
|
||||
<video autoplay playsinline loop>
|
||||
<source src="https://github.com/coder/coder/blob/main/docs/images/templates/open-in-coder.mp4?raw=true" type="video/mp4">
|
||||
Your browser does not support the video tag.
|
||||
</video>
|
||||
|
||||
## How it works
|
||||
|
||||
To support any infrastructure and software stack, Coder provides a generic
|
||||
approach for "Open in Coder" flows.
|
||||
|
||||
### 1. Set up git authentication
|
||||
|
||||
See [External Authentication](../external-auth.md) to set up git authentication
|
||||
in your Coder deployment.
|
||||
|
||||
### 2. Modify your template to auto-clone repos
|
||||
|
||||
The id in the template's `coder_external_auth` data source must match the
|
||||
`CODER_EXTERNAL_AUTH_X_ID` in the Coder deployment configuration.
|
||||
|
||||
If you want the template to clone a specific git repo:
|
||||
|
||||
```hcl
|
||||
# Require external authentication to use this template
|
||||
data "coder_external_auth" "github" {
|
||||
id = "primary-github"
|
||||
}
|
||||
|
||||
resource "coder_agent" "dev" {
|
||||
# ...
|
||||
dir = "~/coder"
|
||||
startup_script =<<EOF
|
||||
|
||||
# Clone repo from GitHub
|
||||
if [ ! -d "coder" ]
|
||||
then
|
||||
git clone https://github.com/coder/coder
|
||||
fi
|
||||
|
||||
EOF
|
||||
}
|
||||
```
|
||||
|
||||
> Note: The `dir` attribute can be set in multiple ways, for example:
|
||||
>
|
||||
> - `~/coder`
|
||||
> - `/home/coder/coder`
|
||||
> - `coder` (relative to the home directory)
|
||||
|
||||
If you want the template to support any repository via
|
||||
[parameters](./extending-templates/parameters.md)
|
||||
|
||||
```hcl
|
||||
# Require external authentication to use this template
|
||||
data "coder_external_auth" "github" {
|
||||
id = "primary-github"
|
||||
}
|
||||
|
||||
# Prompt the user for the git repo URL
|
||||
data "coder_parameter" "git_repo" {
|
||||
name = "git_repo"
|
||||
display_name = "Git repository"
|
||||
default = "https://github.com/coder/coder"
|
||||
}
|
||||
|
||||
locals {
|
||||
folder_name = try(element(split("/", data.coder_parameter.git_repo.value), length(split("/", data.coder_parameter.git_repo.value)) - 1), "")
|
||||
}
|
||||
|
||||
resource "coder_agent" "dev" {
|
||||
# ...
|
||||
dir = "~/${local.folder_name}"
|
||||
startup_script =<<EOF
|
||||
|
||||
# Clone repo from GitHub
|
||||
if [ ! -d "${local.folder_name}" ]
|
||||
then
|
||||
git clone ${data.coder_parameter.git_repo.value}
|
||||
fi
|
||||
|
||||
EOF
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Embed the "Open in Coder" button with Markdown
|
||||
|
||||
```md
|
||||
[](https://YOUR_ACCESS_URL/templates/YOUR_TEMPLATE/workspace)
|
||||
```
|
||||
|
||||
Be sure to replace `YOUR_ACCESS_URL` with your Coder access url (e.g.
|
||||
<https://coder.example.com>) and `YOUR_TEMPLATE` with the name of your template.
|
||||
|
||||
### 4. Optional: pre-fill parameter values in the "Create Workspace" page
|
||||
|
||||
This can be used to pre-fill the git repo URL, disk size, image, etc.
|
||||
|
||||
```md
|
||||
[](https://YOUR_ACCESS_URL/templates/YOUR_TEMPLATE/workspace?param.git_repo=https://github.com/coder/slog¶m.home_disk_size%20%28GB%29=20)
|
||||
```
|
||||
|
||||

|
||||
|
||||
### 5. Optional: disable specific parameter fields by including their names as
|
||||
|
||||
specified in your template in the `disable_params` search params list
|
||||
|
||||
```md
|
||||
[](https://YOUR_ACCESS_URL/templates/YOUR_TEMPLATE/workspace?disable_params=first_parameter,second_parameter)
|
||||
```
|
||||
|
||||
### Example: Kubernetes
|
||||
|
||||
For a full example of the Open in Coder flow in Kubernetes, check out
|
||||
[this example template](https://github.com/bpmct/coder-templates/tree/main/kubernetes-open-in-coder).
|
||||
@@ -0,0 +1,21 @@
|
||||
# Permissions (enterprise) (premium)
|
||||
|
||||
Licensed Coder administrators can control who can use and modify the template.
|
||||
|
||||

|
||||
|
||||
Permissions allow you to control who can use and modify the template. Both
|
||||
individual user and groups can be added to the access list for a template.
|
||||
Members can be assigned either a `Use` role, granting use of the template to
|
||||
create workspaces, or `Admin`, allowing a user or members of a group to control
|
||||
all aspects of the template. This offers a way to elevate the privileges of
|
||||
ordinary users for specific templates without granting them the site-wide role
|
||||
of `Template Admin`.
|
||||
|
||||
By default the `Everyone` group is assigned to each template meaning any Coder
|
||||
user can use the template to create a workspace. To prevent this, disable the
|
||||
`Allow everyone to use the template` setting when creating a template.
|
||||
|
||||

|
||||
|
||||
Permissions is an enterprise-only feature.
|
||||
@@ -0,0 +1,155 @@
|
||||
# Troubleshooting templates
|
||||
|
||||
Occasionally, you may run into scenarios where a workspace is created, but the
|
||||
agent is either not connected or the
|
||||
[startup script](https://registry.terraform.io/providers/coder/coder/latest/docs/resources/agent#startup_script)
|
||||
has failed or timed out.
|
||||
|
||||
## Agent connection issues
|
||||
|
||||
If the agent is not connected, it means the agent or
|
||||
[init script](https://github.com/coder/coder/tree/main/provisionersdk/scripts)
|
||||
has failed on the resource.
|
||||
|
||||
```console
|
||||
$ coder ssh myworkspace
|
||||
⢄⡱ Waiting for connection from [agent]...
|
||||
```
|
||||
|
||||
While troubleshooting steps vary by resource, here are some general best
|
||||
practices:
|
||||
|
||||
- Ensure the resource has `curl` installed (alternatively, `wget` or `busybox`)
|
||||
- Ensure the resource can `curl` your Coder
|
||||
[access URL](../../admin/setup/index.md#access-url)
|
||||
- Manually connect to the resource and check the agent logs (e.g.,
|
||||
`kubectl exec`, `docker exec` or AWS console)
|
||||
- The Coder agent logs are typically stored in `/tmp/coder-agent.log`
|
||||
- The Coder agent startup script logs are typically stored in
|
||||
`/tmp/coder-startup-script.log`
|
||||
- The Coder agent shutdown script logs are typically stored in
|
||||
`/tmp/coder-shutdown-script.log`
|
||||
- This can also happen if the websockets are not being forwarded correctly when
|
||||
running Coder behind a reverse proxy.
|
||||
[Read our reverse-proxy docs](../../admin/setup/index.md#tls--reverse-proxy)
|
||||
|
||||
## Startup script issues
|
||||
|
||||
Depending on the contents of the
|
||||
[startup script](https://registry.terraform.io/providers/coder/coder/latest/docs/resources/agent#startup_script),
|
||||
and whether or not the
|
||||
[startup script behavior](https://registry.terraform.io/providers/coder/coder/latest/docs/resources/agent#startup_script_behavior)
|
||||
is set to blocking or non-blocking, you may notice issues related to the startup
|
||||
script. In this section we will cover common scenarios and how to resolve them.
|
||||
|
||||
### Unable to access workspace, startup script is still running
|
||||
|
||||
If you're trying to access your workspace and are unable to because the
|
||||
[startup script](https://registry.terraform.io/providers/coder/coder/latest/docs/resources/agent#startup_script)
|
||||
is still running, it means the
|
||||
[startup script behavior](https://registry.terraform.io/providers/coder/coder/latest/docs/resources/agent#startup_script_behavior)
|
||||
option is set to blocking or you have enabled the `--wait=yes` option (for e.g.
|
||||
`coder ssh` or `coder config-ssh`). In such an event, you can always access the
|
||||
workspace by using the web terminal, or via SSH using the `--wait=no` option. If
|
||||
the startup script is running longer than it should, or never completing, you
|
||||
can try to [debug the startup script](#debugging-the-startup-script) to resolve
|
||||
the issue. Alternatively, you can try to force the startup script to exit by
|
||||
terminating processes started by it or terminating the startup script itself (on
|
||||
Linux, `ps` and `kill` are useful tools).
|
||||
|
||||
For tips on how to write a startup script that doesn't run forever, see the
|
||||
[`startup_script`](#startup_script) section. For more ways to override the
|
||||
startup script behavior, see the
|
||||
[`startup_script_behavior`](#startup_script_behavior) section.
|
||||
|
||||
Template authors can also set the
|
||||
[startup script behavior](https://registry.terraform.io/providers/coder/coder/latest/docs/resources/agent#startup_script_behavior)
|
||||
option to non-blocking, which will allow users to access the workspace while the
|
||||
startup script is still running. Note that the workspace must be updated after
|
||||
changing this option.
|
||||
|
||||
### Your workspace may be incomplete
|
||||
|
||||
If you see a warning that your workspace may be incomplete, it means you should
|
||||
be aware that programs, files, or settings may be missing from your workspace.
|
||||
This can happen if the
|
||||
[startup script](https://registry.terraform.io/providers/coder/coder/latest/docs/resources/agent#startup_script)
|
||||
is still running or has exited with a non-zero status (see
|
||||
[startup script error](#startup-script-error)). No action is necessary, but you
|
||||
may want to
|
||||
[start a new shell session](#session-was-started-before-the-startup-script-finished-web-terminal)
|
||||
after it has completed or check the
|
||||
[startup script logs](#debugging-the-startup-script) to see if there are any
|
||||
issues.
|
||||
|
||||
### Session was started before the startup script finished
|
||||
|
||||
The web terminal may show this message if it was started before the
|
||||
[startup script](https://registry.terraform.io/providers/coder/coder/latest/docs/resources/agent#startup_script)
|
||||
finished, but the startup script has since finished. This message can safely be
|
||||
dismissed, however, be aware that your preferred shell or dotfiles may not yet
|
||||
be activated for this shell session. You can either start a new session or
|
||||
source your dotfiles manually. Note that starting a new session means that
|
||||
commands running in the terminal will be terminated and you may lose unsaved
|
||||
work.
|
||||
|
||||
Examples for activating your preferred shell or sourcing your dotfiles:
|
||||
|
||||
- `exec zsh -l`
|
||||
- `source ~/.bashrc`
|
||||
|
||||
### Startup script exited with an error
|
||||
|
||||
When the
|
||||
[startup script](https://registry.terraform.io/providers/coder/coder/latest/docs/resources/agent#startup_script)
|
||||
exits with an error, it means the last command run by the script failed. When
|
||||
`set -e` is used, this means that any failing command will immediately exit the
|
||||
script and the remaining commands will not be executed. This also means that
|
||||
[your workspace may be incomplete](#your-workspace-may-be-incomplete). If you
|
||||
see this error, you can check the
|
||||
[startup script logs](#debugging-the-startup-script) to figure out what the
|
||||
issue is.
|
||||
|
||||
Common causes for startup script errors:
|
||||
|
||||
- A missing command or file
|
||||
- A command that fails due to missing permissions
|
||||
- Network issues (e.g., unable to reach a server)
|
||||
|
||||
### Debugging the startup script
|
||||
|
||||
The simplest way to debug the
|
||||
[startup script](https://registry.terraform.io/providers/coder/coder/latest/docs/resources/agent#startup_script)
|
||||
is to open the workspace in the Coder dashboard and click "Show startup log" (if
|
||||
not already visible). This will show all the output from the script. Another
|
||||
option is to view the log file inside the workspace (usually
|
||||
`/tmp/coder-startup-script.log`). If the logs don't indicate what's going on or
|
||||
going wrong, you can increase verbosity by adding `set -x` to the top of the
|
||||
startup script (note that this will show all commands run and may output
|
||||
sensitive information). Alternatively, you can add `echo` statements to show
|
||||
what's going on.
|
||||
|
||||
Here's a short example of an informative startup script:
|
||||
|
||||
```shell
|
||||
echo "Running startup script..."
|
||||
echo "Run: long-running-command"
|
||||
/path/to/long-running-command
|
||||
status=$?
|
||||
echo "Done: long-running-command, exit status: ${status}"
|
||||
if [ $status -ne 0 ]; then
|
||||
echo "Startup script failed, exiting..."
|
||||
exit $status
|
||||
fi
|
||||
```
|
||||
|
||||
> **Note:** We don't use `set -x` here because we're manually echoing the
|
||||
> commands. This protects against sensitive information being shown in the log.
|
||||
|
||||
This script tells us what command is being run and what the exit status is. If
|
||||
the exit status is non-zero, it means the command failed and we exit the script.
|
||||
Since we are manually checking the exit status here, we don't need `set -e` at
|
||||
the top of the script to exit on error.
|
||||
|
||||
> **Note:** If you aren't seeing any logs, check that the `dir` directive points
|
||||
> to a valid directory in the file system.
|
||||
Reference in New Issue
Block a user