diff --git a/envbuilder-dogfood/README.md b/envbuilder-dogfood/README.md new file mode 100644 index 0000000000000..568fdd4fe77e7 --- /dev/null +++ b/envbuilder-dogfood/README.md @@ -0,0 +1,15 @@ +# envbuilder dogfood template + +This template uses the same image as the [dogfood](../dogfood) template, but +builds it on-demand using the latest _preview_ version of [envbuilder](https://github.com/coder/envbuilder). + +In theory, it should work with any Git repository containing a `devcontainer.json`. +The Git repository specified by `devcontainer_repo` is cloned into `/workspaces` upon startup and the container is built from the devcontainer located under the path specified by `devcontainer_dir`. +The `region` parameters are the same as for the [dogfood](../dogfood) template. + +The `/workspaces` directory is persisted as a Docker volume, so any changes you make to the dogfood Dockerfile or devcontainer.json will be applied upon restarting your workspace. + +## Personalization + +The startup script runs your `~/personalize` file if it exists. +You also have a persistent home directory under `/home/coder`. diff --git a/envbuilder-dogfood/main.tf b/envbuilder-dogfood/main.tf new file mode 100644 index 0000000000000..97134b2b8bb6e --- /dev/null +++ b/envbuilder-dogfood/main.tf @@ -0,0 +1,417 @@ +terraform { + required_providers { + coder = { + source = "coder/coder" + } + docker = { + source = "kreuzwerker/docker" + version = "~> 3.0.0" + } + } +} + +locals { + // These are cluster service addresses mapped to Tailscale nodes. + // Ask #dogfood-admins for help. + // NOTE: keep these up to date with those in ../dogfood/main.tf! + docker_host = { + "" = "tcp://dogfood-ts-cdr-dev.tailscale.svc.cluster.local:2375" + "us-pittsburgh" = "tcp://dogfood-ts-cdr-dev.tailscale.svc.cluster.local:2375" + "eu-helsinki" = "tcp://reinhard-hel-cdr-dev.tailscale.svc.cluster.local:2375" + "ap-sydney" = "tcp://wolfgang-syd-cdr-dev.tailscale.svc.cluster.local:2375" + "sa-saopaulo" = "tcp://oberstein-sao-cdr-dev.tailscale.svc.cluster.local:2375" + "za-jnb" = "tcp://greenhill-jnb-cdr-dev.tailscale.svc.cluster.local:2375" + } + + envbuilder_repo = "ghcr.io/coder/envbuilder-preview" + container_name = "coder-${data.coder_workspace_owner.me.name}-${lower(data.coder_workspace.me.name)}" + // Envbuilder clones repos to /workspaces by default. + repo_dir = "/workspaces/coder" +} + +data "coder_parameter" "devcontainer_repo" { + type = "string" + name = "Devcontainer Repository" + default = "https://github.com/coder/coder" + description = "Repo containing a devcontainer.json. This is only cloned once." + mutable = false +} + +data "coder_parameter" "devcontainer_dir" { + type = "string" + name = "Devcontainer Directory" + default = "dogfood/" + description = "Directory containing a devcontainer.json relative to the repository root" + mutable = true +} + +data "coder_parameter" "region" { + type = "string" + name = "Region" + icon = "/emojis/1f30e.png" + default = "us-pittsburgh" + option { + icon = "/emojis/1f1fa-1f1f8.png" + name = "Pittsburgh" + value = "us-pittsburgh" + } + option { + icon = "/emojis/1f1eb-1f1ee.png" + name = "Helsinki" + value = "eu-helsinki" + } + option { + icon = "/emojis/1f1e6-1f1fa.png" + name = "Sydney" + value = "ap-sydney" + } + option { + icon = "/emojis/1f1e7-1f1f7.png" + name = "São Paulo" + value = "sa-saopaulo" + } + option { + icon = "/emojis/1f1ff-1f1e6.png" + name = "Johannesburg" + value = "za-jnb" + } +} + +provider "docker" { + host = lookup(local.docker_host, data.coder_parameter.region.value) +} + +provider "coder" {} + +data "coder_external_auth" "github" { + id = "github" +} + +data "coder_workspace" "me" {} +data "coder_workspace_owner" "me" {} + +module "slackme" { + source = "registry.coder.com/modules/slackme/coder" + version = "1.0.2" + agent_id = coder_agent.dev.id + auth_provider_id = "slack" +} + +module "dotfiles" { + source = "registry.coder.com/modules/dotfiles/coder" + version = "1.0.15" + agent_id = coder_agent.dev.id +} + +module "personalize" { + source = "registry.coder.com/modules/personalize/coder" + version = "1.0.2" + agent_id = coder_agent.dev.id +} + +module "code-server" { + source = "registry.coder.com/modules/code-server/coder" + version = "1.0.15" + agent_id = coder_agent.dev.id + folder = local.repo_dir + auto_install_extensions = true +} + +module "jetbrains_gateway" { + source = "registry.coder.com/modules/jetbrains-gateway/coder" + version = "1.0.13" + agent_id = coder_agent.dev.id + agent_name = "dev" + folder = local.repo_dir + jetbrains_ides = ["GO", "WS"] + default = "GO" + latest = true +} + +module "filebrowser" { + source = "registry.coder.com/modules/filebrowser/coder" + version = "1.0.8" + agent_id = coder_agent.dev.id +} + +module "coder-login" { + source = "registry.coder.com/modules/coder-login/coder" + version = "1.0.15" + agent_id = coder_agent.dev.id +} + +resource "coder_agent" "dev" { + arch = "amd64" + os = "linux" + dir = local.repo_dir + env = { + OIDC_TOKEN : data.coder_workspace_owner.me.oidc_access_token, + } + startup_script_behavior = "blocking" + + # The following metadata blocks are optional. They are used to display + # information about your workspace in the dashboard. You can remove them + # if you don't want to display any information. + metadata { + display_name = "CPU Usage" + key = "cpu_usage" + order = 0 + script = "coder stat cpu" + interval = 10 + timeout = 1 + } + + metadata { + display_name = "RAM Usage" + key = "ram_usage" + order = 1 + script = "coder stat mem" + interval = 10 + timeout = 1 + } + + metadata { + display_name = "CPU Usage (Host)" + key = "cpu_usage_host" + order = 2 + script = "coder stat cpu --host" + interval = 10 + timeout = 1 + } + + metadata { + display_name = "RAM Usage (Host)" + key = "ram_usage_host" + order = 3 + script = "coder stat mem --host" + interval = 10 + timeout = 1 + } + + metadata { + display_name = "Swap Usage (Host)" + key = "swap_usage_host" + order = 4 + script = <&1 | awk ' $0 ~ "Word of the Day: [A-z]+" { print $5; exit }' + EOT + interval = 86400 + timeout = 5 + } + + startup_script = <<-EOT + set -eux -o pipefail + + # Allow synchronization between scripts. + trap 'touch /tmp/.coder-startup-script.done' EXIT + + # BUG: Kaniko does not symlink /run => /var/run properly, resulting in + # /var/run/ owned by root:root + # WORKAROUND: symlink it manually + sudo ln -s /run /var/run + # Start Docker service + sudo service docker start + + # Chown /var/run/docker.sock as even though we are a member of the Docker group + # it did not exist at the start of the workspace. This can be worked around with + # `newgrp docker` but this is annoying to have to do manually. + for attempt in $(seq 1 10); do + if sudo docker info > /dev/null; then break; fi + sleep 1 + done + sudo chmod a+rw /var/run/docker.sock + + # Install playwright dependencies + # We want to use the playwright version from site/package.json + # Check if the directory exists At workspace creation as the coder_script runs in parallel so clone might not exist yet. + while ! [[ -f "${local.repo_dir}/site/package.json" ]]; do + sleep 1 + done + cd "${local.repo_dir}/site" && pnpm install && pnpm playwright:install + EOT +} + +resource "docker_volume" "home_volume" { + name = "coder-${data.coder_workspace.me.id}-home" + # Protect the volume from being deleted due to changes in attributes. + lifecycle { + ignore_changes = all + } + # Add labels in Docker to keep track of orphan resources. + labels { + label = "coder.owner" + value = data.coder_workspace_owner.me.name + } + labels { + label = "coder.owner_id" + value = data.coder_workspace_owner.me.id + } + labels { + label = "coder.workspace_id" + value = data.coder_workspace.me.id + } + # This field becomes outdated if the workspace is renamed but can + # be useful for debugging or cleaning out dangling volumes. + labels { + label = "coder.workspace_name_at_creation" + value = data.coder_workspace.me.name + } +} + +resource "docker_volume" "workspaces" { + name = "coder-${data.coder_workspace.me.id}" + # Protect the volume from being deleted due to changes in attributes. + lifecycle { + ignore_changes = all + } + # Add labels in Docker to keep track of orphan resources. + labels { + label = "coder.owner" + value = data.coder_workspace_owner.me.name + } + labels { + label = "coder.owner_id" + value = data.coder_workspace_owner.me.id + } + labels { + label = "coder.workspace_id" + value = data.coder_workspace.me.id + } + # This field becomes outdated if the workspace is renamed but can + # be useful for debugging or cleaning out dangling volumes. + labels { + label = "coder.workspace_name_at_creation" + value = data.coder_workspace.me.name + } +} + +# This file is mounted as a Kubernetes secret on provisioner pods. +# It contains the required credentials for the envbuilder cache repo. +data "local_sensitive_file" "envbuilder_cache_dockerconfigjson" { + filename = "/home/coder/envbuilder-cache-dockerconfig.json" +} + +data "docker_registry_image" "envbuilder" { + name = "${local.envbuilder_repo}:latest" +} + +resource "docker_image" "envbuilder" { + name = "${local.envbuilder_repo}@${data.docker_registry_image.envbuilder.sha256_digest}" + pull_triggers = [data.docker_registry_image.envbuilder.sha256_digest] + keep_locally = true +} + +resource "docker_container" "workspace" { + count = data.coder_workspace.me.start_count + image = docker_image.envbuilder.name + name = local.container_name + # Hostname makes the shell more user friendly: coder@my-workspace:~$ + hostname = data.coder_workspace.me.name + # CPU limits are unnecessary since Docker will load balance automatically + memory = 32768 + runtime = "sysbox-runc" + env = [ + "CODER_AGENT_TOKEN=${coder_agent.dev.token}", + "CODER_AGENT_URL=${data.coder_workspace.me.access_url}", + "ENVBUILDER_GIT_USERNAME=${data.coder_external_auth.github.access_token}", + "ENVBUILDER_GIT_URL=${data.coder_parameter.devcontainer_repo.value}", + "ENVBUILDER_DEVCONTAINER_DIR=${data.coder_parameter.devcontainer_dir.value}", + "ENVBUILDER_INIT_SCRIPT=${coder_agent.dev.init_script}", + "ENVBUILDER_FALLBACK_IMAGE=codercom/oss-dogfood:latest", # This image runs if builds fail + # "ENVBUILDER_PUSH_IMAGE=1", # Push the image to the remote cache + "ENVBUILDER_CACHE_REPO=us-central1-docker.pkg.dev/coder-dogfood-v2/envbuilder-cache/coder-dogfood", + "ENVBUILDER_DOCKER_CONFIG_BASE64=${data.local_sensitive_file.envbuilder_cache_dockerconfigjson.content_base64}", + "USE_CAP_NET_ADMIN=true", + # Set git commit details correctly + "GIT_AUTHOR_NAME=${coalesce(data.coder_workspace_owner.me.full_name, data.coder_workspace_owner.me.name)}", + "GIT_AUTHOR_EMAIL=${data.coder_workspace_owner.me.email}", + "GIT_COMMITTER_NAME=${coalesce(data.coder_workspace_owner.me.full_name, data.coder_workspace_owner.me.name)}", + "GIT_COMMITTER_EMAIL=${data.coder_workspace_owner.me.email}", + ] + host { + host = "host.docker.internal" + ip = "host-gateway" + } + volumes { + container_path = "/home/coder/" + volume_name = docker_volume.home_volume.name + read_only = false + } + volumes { + container_path = local.repo_dir + volume_name = docker_volume.workspaces.name + read_only = false + } + capabilities { + add = ["CAP_NET_ADMIN", "CAP_SYS_NICE"] + } + # Add labels in Docker to keep track of orphan resources. + labels { + label = "coder.owner" + value = data.coder_workspace_owner.me.name + } + labels { + label = "coder.owner_id" + value = data.coder_workspace_owner.me.id + } + labels { + label = "coder.workspace_id" + value = data.coder_workspace.me.id + } + labels { + label = "coder.workspace_name" + value = data.coder_workspace.me.name + } +} + +resource "coder_metadata" "container_info" { + count = data.coder_workspace.me.start_count + resource_id = docker_container.workspace[0].id + item { + key = "memory" + value = docker_container.workspace[0].memory + } + item { + key = "runtime" + value = docker_container.workspace[0].runtime + } + item { + key = "region" + value = data.coder_parameter.region.option[index(data.coder_parameter.region.option.*.value, data.coder_parameter.region.value)].name + } +} pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy