Skip to content

Workspace pre-builds #5325

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
bpmct opened this issue Dec 6, 2022 · 12 comments
Open

Workspace pre-builds #5325

bpmct opened this issue Dec 6, 2022 · 12 comments
Assignees
Labels
roadmap https://coder.com/roadmap. Only humans may set this.

Comments

@bpmct
Copy link
Member

bpmct commented Dec 6, 2022

Some of our users have templates with a long time to provision (e.g. Kubernetes clusters, OpenStack VMs, etc.) or large startup scripts / git clones that take 30+ minutes.

Overview

For users with templates with long-running scripts to initialize, this should allow starts to become near-instant. This does not speed up the provisioning of ephemeral resources (e.g. pods, containers, VMs).

This will also make Coder workspaces more useful for workspaces per-branch or per-PR as the start time is much faster

Improving build performance

In parallel, we are also working on making it easier to profile workspace start/stop time so template admins can understand how to optimize. While we've had prometheus metrics on start times, for a while we'll be adding API endpoints and a UI view for viewing resource provisioning time and script execution time (#14773):

image

We'll also write up some docs on optimizing build performance: #14858

References

Prior art: #9611

From: @ggjulio:

CDEs with a Prebuilds feature provides a way to use their workspaces as short-lived/ephemeral environnement on large/complex repositories.

Coder's closest way of achieving something similar is through startup scripts, which is fine for small code base. But it doesn't works well for large repositories.

As far as I know, there is currently 3 CDEs implementing it:

It usually works by building the main branches, (let's say the main/master branch) The "output" is stored and then any users can get a fresh workspace from it. Prebuilds are linked to the commit hash they have been built with.

Theses fresh workspaces may contain:

  • Object / bytecode files, final binaries / artefacts
  • Any dependencies such as libraries/modules, container images, etc
  • Debug related files -> symbols/map files, etc...
  • Indexes/Caches from developer's tools
  • ?

From the 3 CDE above, a prebuild may be triggered via:

  • push/merge
  • Scheduled
  • Manual trigger
  • On file change (like devcontainer.json)
  • Every N commits
  • ?

Why Prebuilds are worth to be implemented

The inability of using short lived/ephemeral workspaces on large repos have several impacts :

  • Long lived workspaces may drift and result in "works on my machine" issues.
  • Context switching takes time (reviewing PR, hotfix an issue, etc)
  • ?

Large companies tend to have large and complex repositories. Implementing it may help them significantly reduce time spent on the two issues above.

Could also:

  • Reduce resources consumption peaks (avoiding N builds by N developers when their workspaces starts)
  • ?

Implementation ?

All CDEs above currently supports only one isolation model and/or infrastructure. Coder doesn't make any assumptions on neither of the infra or isolation model. Which could make it hard for coder to implement such a feature.

What are you thoughts about it ?

Resources:

@ElliotG
Copy link
Contributor

ElliotG commented Dec 6, 2022

This is a combination of just documentation of best practices, as well as requiring that the end-user build some scripts/automation against our API? This won't be native?

@bpmct
Copy link
Member Author

bpmct commented Dec 7, 2022

It could be native! We could support "pooling" where, at a given time, a template has n running workspaces, which are then renamed to the user ID and given a new owner in the database, when a workspace is started.

@bpmct
Copy link
Member Author

bpmct commented Dec 7, 2022

For example, during an OpenShift workshop, there could be 100 clusters "ready" to be assigned to users, built in advance.

@ElliotG
Copy link
Contributor

ElliotG commented Dec 8, 2022

I helped product manage this feature at a previous role, and here are some complications to consider:

  • People set up pool sizes, and then forget about it. It turns into a cost hog. We'd want metrics, warnings, or UI elements that help people recognize this waste
  • Pool size needs it's cost allocated to someone, but it's in a limbo. Who "owns" the template?
  • Scheduled start/stop on pools. Boot up 10 workspaces by 8am cst, and drop it down to 4 workspaces by 8pm cst.
  • UI indicators that help people understand the state of a pool/exhausted pool

@github-actions

This comment has been minimized.

@github-actions github-actions bot added the stale This issue is like stale bread. label Mar 9, 2023
@MrPeacockNLB
Copy link
Contributor

For our UseCase a workspace is defined in a coder.yaml. So every start of a new workspace can have different settings.

@github-actions github-actions bot removed the stale This issue is like stale bread. label Mar 10, 2023
@bpmct bpmct changed the title 5-second workspace startup Workspace pre-builds Mar 27, 2023
@bpmct bpmct added roadmap https://coder.com/roadmap. Only humans may set this. roadmap-maybe Ideas we're considering! Only humans may set this. labels Mar 27, 2023
@github-actions github-actions bot added the stale This issue is like stale bread. label Jun 26, 2023
@github-actions github-actions bot closed this as not planned Won't fix, can't repro, duplicate, stale Jul 4, 2023
@matifali
Copy link
Member

Related to #9611

@matifali matifali reopened this Oct 9, 2023
@matifali matifali removed the stale This issue is like stale bread. label Oct 9, 2023
@ammario
Copy link
Member

ammario commented Apr 1, 2024

I think we can implement this relatively cleanly by splitting provisioning into two phases:

  1. Warming — we terraform apply the template without any user information. This state becomes an anonymous workspace.
  2. Assigning — we terraform apply the anonymous workspace with user information. If the template is well-designed only cheap resources will be rebuilt.

Then users can make their templates warm-able by following these two practices:

  1. Be resilient to missing user information when building
  2. Only depend on user information in the cheapest recourses. E.g., use a random ID for an instance name.

Edit April 3rd, 2024:

Instead of complicated the provisioning layer, we could wait until Workspace transfers are robust, and then assign pre-built workspaces to a dummy account until they're needed. Each transfer will have to constitute a rebuild.

@ggjulio
Copy link
Contributor

ggjulio commented Jul 14, 2024

Just my two cents about prebuilds for devcontainer.
I know it does not generalize outside devcontainers, but I think coder should have proper support for devcontainers anyway.

Resources:

They are just images pushed into an oci registry.

We could use any CI to build and push prebuilds. But would be nice to get a "ready" to use solution.
Codespaces automate this via github actions, we could use coder workspaces as builder.

However coder must be aware of git repositories to filter prebuilds from a given branch/ref. (using the git provider api)

The configuration should be specific to each repository.
Github do it via the settings tab of each repository, coder may use a file per repository.

# .coder/config.yaml
devcontainers:
  template_id: # id of the devcontainer terraform template to use ?
  prebuilds:
    configuration: .devcontainer/devcontainer.json # default value
    triggers:            # some params in trigger should not be set together.
      schedule: ... 
      on_change:
       - ".devcontainer/**/*"
       - "!.devcontainer/**/*.md"
       - "Dockerfile"
      commit_interval: 4 # new prebuild every 4 commits
      enable_manual_trigger: true # allow manual trigger via coder cli or UI ?
    branches:    # which branches to prebuild
      - main
      - develop:
        configuration: # override configuration for release/1.*
          - .devcontainer/devcontainer.json
          - .devcontainer/frontend/devcontainer.json
      - release/2.* :
        triggers:
          on_change: # override on_change
           - .devcontainer/**/*
           - old-folder/Dockerfile
    notify_failure: # notify coder users when failure happen.
      - dev1
      - dev2

Coder can schedule workspace creation based on the config in each repository.
During workspace creation coder fill in the repo, branch and configuration, run the prebuild script and then delete the workspace.

When a user create a workspace from a given branch/ref, they should see if a prebuild is available.

Or even have the possibility to select one among a list of prebuilds.
This probably requires asking parameters in a specific order, maybe a new field page to coder_parameters could to the job.
The page =1 to ask repository, branch, and configuration to use. (completion like codespaces would be nice)
The page =2 would ask which prebuild to use and other things like dotfile, etc...
(IMO paging improve the UX by avoiding scrolling down parameters.)

# Generic devcontainer template using envbuilder or devcontainer cli

resource "a_cloud_vm_instance" {
   startup_script = data.coder_agent.main.init_script
   # [...]
}

# get information about the repository
data "coder_repository" "me"{
  # external auth to assume the git provider for api calls (bitbucket, gitlab, github...)
  git_external_auth_id  : data.coder_external_auth.my_git_provider.id    
  
  repository_url = data.coder_param.repository_url.value
  # or
  repository_id = my_project/_my_repo
  selected_branch = data.coder_param.branch.value
} 

resource "coder_devcontainer_prebuild" { 
  # Can set default values, enforce quotas/limits or configure admin configuration ?
  registry: "dockerhub.com/org/${data.coder_repository.me.repository_name}:${data.coder_repository.me.head_short_sha}"
  script: <<-EOT
    # customize prebuild script if needed.
    devcontainer build --push true --image-name dockerhub.com/org/${data.coder_repository.me.repository_name}:${data.coder_repository.me.head_short_sha}
    # [...]
  EOT
}

locals {
  init_script = <<-EOT
  if [[ ${data.coder_repository.prebuild} ]]
      # use prebuild.
  else 
     # devcontainer build ...
  EOT
}

# [...]

@ammario ammario removed the roadmap-maybe Ideas we're considering! Only humans may set this. label Sep 20, 2024
@ammario
Copy link
Member

ammario commented Sep 20, 2024

Update: @dannykopping is actively working on this and we'll likely have a generally available solution in the next couple of months.

@bpmct
Copy link
Member Author

bpmct commented Sep 27, 2024

That's right! We're actively working on this. I added some updates to the issue body to reflect our current progress.

@dannykopping
Copy link
Contributor

This is now actively under development: https://github.com/orgs/coder/projects/44/views/3

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
roadmap https://coder.com/roadmap. Only humans may set this.
Projects
None yet
Development

No branches or pull requests

7 participants