|
| 1 | +# Provisioners |
| 2 | + |
| 3 | +By default, the Coder server runs |
| 4 | +[built-in provisioner daemons](../cli/server.md#provisioner-daemons), which |
| 5 | +execute `terraform` during workspace and template builds. However, there are |
| 6 | +sometimes benefits to running external provisioner daemons: |
| 7 | + |
| 8 | +- **Secure build environments:** Run build jobs in isolated containers, |
| 9 | + preventing malicious templates from gaining shell access to the Coder host. |
| 10 | + |
| 11 | +- **Isolate APIs:** Deploy provisioners in isolated environments (on-prem, AWS, |
| 12 | + Azure) instead of exposing APIs (Docker, Kubernetes, VMware) to the Coder |
| 13 | + server. See [Provider Authentication](../templates/authentication.md) for more |
| 14 | + details. |
| 15 | + |
| 16 | +- **Isolate secrets**: Keep Coder unaware of cloud secrets, manage/rotate |
| 17 | + secrets on provisioner servers. |
| 18 | + |
| 19 | +- **Reduce server load**: External provisioners reduce load and build queue |
| 20 | + times from the Coder server. See |
| 21 | + [Scaling Coder](scaling/scale-utility.md#recent-scale-tests) for more details. |
| 22 | + |
| 23 | +Each provisioner can run a single |
| 24 | +[concurrent workspace build](scaling/scale-testing.md#control-plane-provisionerd). |
| 25 | +For example, running 30 provisioner containers will allow 30 users to start |
| 26 | +workspaces at the same time. |
| 27 | + |
| 28 | +Provisioners are started with the |
| 29 | +[coder provisionerd start](../cli/provisionerd_start.md) command. |
| 30 | + |
| 31 | +## Authentication |
| 32 | + |
| 33 | +The provisioner daemon must authenticate with your Coder deployment. |
| 34 | + |
| 35 | +Set a |
| 36 | +[provisioner daemon pre-shared key (PSK)](../cli/server.md#--provisioner-daemon-psk) |
| 37 | +on the Coder server and start the provisioner with |
| 38 | +`coder provisionerd start --psk <your-psk>`. If you are |
| 39 | +[installing with Helm](../install/kubernetes.md#install-coder-with-helm), see |
| 40 | +the [Helm example](#example-running-an-external-provisioner-with-helm) below. |
| 41 | + |
| 42 | +> Coder still supports authenticating the provisioner daemon with a |
| 43 | +> [token](../cli.md#--token) from a user with the Template Admin or Owner role. |
| 44 | +> This method is deprecated in favor of the PSK, which only has permission to |
| 45 | +> access provisioner daemon APIs. We recommend migrating to the PSK as soon as |
| 46 | +> practical. |
| 47 | +
|
| 48 | +## Types of provisioners |
| 49 | + |
| 50 | +Provisioners can broadly be categorized by scope: `organization` or `user`. The |
| 51 | +scope of a provisioner can be specified with |
| 52 | +[`-tag=scope=<scope>`](../cli/provisionerd_start.md#t---tag) when starting the |
| 53 | +provisioner daemon. Only users with at least the |
| 54 | +[Template Admin](../admin/users.md#roles) role or higher may create |
| 55 | +organization-scoped provisioner daemons. |
| 56 | + |
| 57 | +There are two exceptions: |
| 58 | + |
| 59 | +- [Built-in provisioners](../cli/server.md#provisioner-daemons) are always |
| 60 | + organization-scoped. |
| 61 | +- External provisioners started using a |
| 62 | + [pre-shared key (PSK)](../cli/provisionerd_start.md#psk) are always |
| 63 | + organization-scoped. |
| 64 | + |
| 65 | +### Organization-Scoped Provisioners |
| 66 | + |
| 67 | +**Organization-scoped Provisioners** can pick up build jobs created by any user. |
| 68 | +These provisioners always have the implicit tags `scope=organization owner=""`. |
| 69 | + |
| 70 | +```shell |
| 71 | +coder provisionerd start |
| 72 | +``` |
| 73 | + |
| 74 | +### User-scoped Provisioners |
| 75 | + |
| 76 | +**User-scoped Provisioners** can only pick up build jobs created from |
| 77 | +user-tagged templates. Unlike the other provisioner types, any Coder user can |
| 78 | +run user provisioners, but they have no impact unless there exists at least one |
| 79 | +template with the `scope=user` provisioner tag. |
| 80 | + |
| 81 | +```shell |
| 82 | +coder provisionerd start \ |
| 83 | + --tag scope=user |
| 84 | + |
| 85 | +# In another terminal, create/push |
| 86 | +# a template that requires user provisioners |
| 87 | +coder templates push on-prem \ |
| 88 | + --provisioner-tag scope=user |
| 89 | +``` |
| 90 | + |
| 91 | +### Provisioner Tags |
| 92 | + |
| 93 | +You can use **provisioner tags** to control which provisioners can pick up build |
| 94 | +jobs from templates (and corresponding workspaces) with matching explicit tags. |
| 95 | + |
| 96 | +Provisioners have two implicit tags: `scope` and `owner`. Coder sets these tags |
| 97 | +automatically. |
| 98 | + |
| 99 | +- Organization-scoped provisioners always have the implicit tags |
| 100 | + `scope=organization owner=""` |
| 101 | +- User-scoped provisioners always have the implicit tags |
| 102 | + `scope=user owner=<uuid>` |
| 103 | + |
| 104 | +For example: |
| 105 | + |
| 106 | +```shell |
| 107 | +# Start a provisioner with the explicit tags |
| 108 | +# environment=on_prem and datacenter=chicago |
| 109 | +coder provisionerd start \ |
| 110 | + --tag environment=on_prem \ |
| 111 | + --tag datacenter=chicago |
| 112 | + |
| 113 | +# In another terminal, create/push |
| 114 | +# a template that requires the explicit |
| 115 | +# tag environment=on_prem |
| 116 | +coder templates push on-prem \ |
| 117 | + --provisioner-tag environment=on_prem |
| 118 | + |
| 119 | +# Or, match the provisioner's explicit tags exactly |
| 120 | +coder templates push on-prem-chicago \ |
| 121 | + --provisioner-tag environment=on_prem \ |
| 122 | + --provisioner-tag datacenter=chicago |
| 123 | +``` |
| 124 | + |
| 125 | +A provisioner can run a given build job if one of the below is true: |
| 126 | + |
| 127 | +1. A job with no explicit tags can only be run on a provisioner with no explicit |
| 128 | + tags. This way you can introduce tagging into your deployment without |
| 129 | + disrupting existing provisioners and jobs. |
| 130 | +1. If a job has any explicit tags, it can only run on a provisioner with those |
| 131 | + explicit tags (the provisioner could have additional tags). |
| 132 | + |
| 133 | +The external provisioner in the above example can run build jobs with tags: |
| 134 | + |
| 135 | +- `environment=on_prem` |
| 136 | +- `datacenter=chicago` |
| 137 | +- `environment=on_prem datacenter=chicago` |
| 138 | + |
| 139 | +However, it will not pick up any build jobs that do not have either of the |
| 140 | +`environment` or `datacenter` tags set. It will also not pick up any build jobs |
| 141 | +from templates with the tag `scope=user` set. |
| 142 | + |
| 143 | +This is illustrated in the below table: |
| 144 | + |
| 145 | +| Provisioner Tags | Job Tags | Can Run Job? | |
| 146 | +| ----------------------------------------------------------------- | ---------------------------------------------------------------- | ------------ | |
| 147 | +| scope=organization owner= | scope=organization owner= | ✅ | |
| 148 | +| scope=organization owner= environment=on-prem | scope=organization owner= environment=on-prem | ✅ | |
| 149 | +| scope=organization owner= environment=on-prem datacenter=chicago | scope=organization owner= environment=on-prem | ✅ | |
| 150 | +| scope=organization owner= environment=on-prem datacenter=chicago | scope=organization owner= environment=on-prem datacenter=chicago | ✅ | |
| 151 | +| scope=user owner=aaa | scope=user owner=aaa | ✅ | |
| 152 | +| scope=user owner=aaa environment=on-prem | scope=user owner=aaa | ✅ | |
| 153 | +| scope=user owner=aaa environment=on-prem | scope=user owner=aaa environment=on-prem | ✅ | |
| 154 | +| scope=user owner=aaa environment=on-prem datacenter=chicago | scope=user owner=aaa environment=on-prem | ✅ | |
| 155 | +| scope=user owner=aaa environment=on-prem datacenter=chicago | scope=user owner=aaa environment=on-prem datacenter=chicago | ✅ | |
| 156 | +| scope=organization owner= | scope=organization owner= environment=on-prem | ❌ | |
| 157 | +| scope=organization owner= environment=on-prem | scope=organization owner= | ❌ | |
| 158 | +| scope=organization owner= environment=on-prem | scope=organization owner= environment=on-prem datacenter=chicago | ❌ | |
| 159 | +| scope=organization owner= environment=on-prem datacenter=new_york | scope=organization owner= environment=on-prem datacenter=chicago | ❌ | |
| 160 | +| scope=user owner=aaa | scope=organization owner= | ❌ | |
| 161 | +| scope=user owner=aaa | scope=user owner=bbb | ❌ | |
| 162 | +| scope=organization owner= | scope=user owner=aaa | ❌ | |
| 163 | +| scope=organization owner= | scope=user owner=aaa environment=on-prem | ❌ | |
| 164 | +| scope=user owner=aaa | scope=user owner=aaa environment=on-prem | ❌ | |
| 165 | +| scope=user owner=aaa environment=on-prem | scope=user owner=aaa environment=on-prem datacenter=chicago | ❌ | |
| 166 | +| scope=user owner=aaa environment=on-prem datacenter=chicago | scope=user owner=aaa environment=on-prem datacenter=new_york | ❌ | |
| 167 | + |
| 168 | +> **Note to maintainers:** to generate this table, run the following command and |
| 169 | +> copy the output: |
| 170 | +> |
| 171 | +> ``` |
| 172 | +> go test -v -count=1 ./coderd/provisionerdserver/ -test.run='^TestAcquirer_MatchTags/GenTable$' |
| 173 | +> ``` |
| 174 | +
|
| 175 | +## Example: Running an external provisioner with Helm |
| 176 | +
|
| 177 | +Coder provides a Helm chart for running external provisioner daemons, which you |
| 178 | +will use in concert with the Helm chart for deploying the Coder server. |
| 179 | +
|
| 180 | +1. Create a long, random pre-shared key (PSK) and store it in a Kubernetes |
| 181 | + secret |
| 182 | +
|
| 183 | + ```shell |
| 184 | + kubectl create secret generic coder-provisioner-psk --from-literal=psk=`head /dev/urandom | base64 | tr -dc A-Za-z0-9 | head -c 26` |
| 185 | + ``` |
| 186 | +
|
| 187 | +1. Modify your Coder `values.yaml` to include |
| 188 | + |
| 189 | + ```yaml |
| 190 | + provisionerDaemon: |
| 191 | + pskSecretName: "coder-provisioner-psk" |
| 192 | + ``` |
| 193 | +
|
| 194 | +1. Redeploy Coder with the new `values.yaml` to roll out the PSK. You can omit |
| 195 | + `--version <your version>` to also upgrade Coder to the latest version. |
| 196 | + |
| 197 | + ```shell |
| 198 | + helm upgrade coder coder-v2/coder \ |
| 199 | + --namespace coder \ |
| 200 | + --version <your version> \ |
| 201 | + --values values.yaml |
| 202 | + ``` |
| 203 | + |
| 204 | +1. Create a `provisioner-values.yaml` file for the provisioner daemons Helm |
| 205 | + chart. For example |
| 206 | + |
| 207 | + ```yaml |
| 208 | + coder: |
| 209 | + env: |
| 210 | + - name: CODER_URL |
| 211 | + value: "https://coder.example.com" |
| 212 | + replicaCount: 10 |
| 213 | + provisionerDaemon: |
| 214 | + pskSecretName: "coder-provisioner-psk" |
| 215 | + tags: |
| 216 | + location: auh |
| 217 | + kind: k8s |
| 218 | + ``` |
| 219 | + |
| 220 | + This example creates a deployment of 10 provisioner daemons (for 10 |
| 221 | + concurrent builds) with the listed tags. For generic provisioners, remove the |
| 222 | + tags. |
| 223 | + |
| 224 | + > Refer to the |
| 225 | + > [values.yaml](https://github.com/coder/coder/blob/main/helm/provisioner/values.yaml) |
| 226 | + > file for the coder-provisioner chart for information on what values can be |
| 227 | + > specified. |
| 228 | + |
| 229 | +1. Install the provisioner daemon chart |
| 230 | + |
| 231 | + ```shell |
| 232 | + helm install coder-provisioner coder-v2/coder-provisioner \ |
| 233 | + --namespace coder \ |
| 234 | + --version <your version> \ |
| 235 | + --values provisioner-values.yaml |
| 236 | + ``` |
| 237 | + |
| 238 | + You can verify that your provisioner daemons have successfully connected to |
| 239 | + Coderd by looking for a debug log message that says |
| 240 | + `provisionerd: successfully connected to coderd` from each Pod. |
| 241 | + |
| 242 | +## Example: Running an external provisioner on a VM |
| 243 | + |
| 244 | +```shell |
| 245 | +curl -L https://coder.com/install.sh | sh |
| 246 | +export CODER_URL=https://coder.example.com |
| 247 | +export CODER_SESSION_TOKEN=your_token |
| 248 | +coder provisionerd start |
| 249 | +``` |
| 250 | + |
| 251 | +## Example: Running an external provisioner via Docker |
| 252 | + |
| 253 | +```shell |
| 254 | +docker run --rm -it \ |
| 255 | + -e CODER_URL=https://coder.example.com/ \ |
| 256 | + -e CODER_SESSION_TOKEN=your_token \ |
| 257 | + --entrypoint /opt/coder \ |
| 258 | + ghcr.io/coder/coder:latest \ |
| 259 | + provisionerd start |
| 260 | +``` |
| 261 | + |
| 262 | +## Disable built-in provisioners |
| 263 | + |
| 264 | +As mentioned above, the Coder server will run built-in provisioners by default. |
| 265 | +This can be disabled with a server-wide |
| 266 | +[flag or environment variable](../cli/server.md#provisioner-daemons). |
| 267 | + |
| 268 | +```shell |
| 269 | +coder server --provisioner-daemons=0 |
| 270 | +``` |
| 271 | + |
| 272 | +## Prometheus metrics |
| 273 | + |
| 274 | +Coder provisioner daemon exports metrics via the HTTP endpoint, which can be |
| 275 | +enabled using either the environment variable `CODER_PROMETHEUS_ENABLE` or the |
| 276 | +flag `--prometheus-enable`. |
| 277 | + |
| 278 | +The Prometheus endpoint address is `http://localhost:2112/` by default. You can |
| 279 | +use either the environment variable `CODER_PROMETHEUS_ADDRESS` or the flag |
| 280 | +`--prometheus-address <network-interface>:<port>` to select a different listen |
| 281 | +address. |
| 282 | + |
| 283 | +If you have provisioners daemons deployed as pods, it is advised to monitor them |
| 284 | +separately. |
0 commit comments