diff --git a/examples/examples.go b/examples/examples.go index e9631c2b2de5a..5f8f37bb5075e 100644 --- a/examples/examples.go +++ b/examples/examples.go @@ -25,8 +25,6 @@ var ( //go:embed templates/azure-linux //go:embed templates/do-linux //go:embed templates/docker - //go:embed templates/docker-code-server - //go:embed templates/docker-image-builds //go:embed templates/docker-with-dotfiles //go:embed templates/gcp-linux //go:embed templates/gcp-vm-container diff --git a/examples/examples_test.go b/examples/examples_test.go index caa7d4a5bb05f..e4a3c38a0ea79 100644 --- a/examples/examples_test.go +++ b/examples/examples_test.go @@ -36,7 +36,7 @@ func TestTemplate(t *testing.T) { func TestSubdirs(t *testing.T) { t.Parallel() - tarData, err := examples.Archive("docker-image-builds") + tarData, err := examples.Archive("docker") require.NoError(t, err) tarReader := tar.NewReader(bytes.NewReader(tarData)) @@ -51,6 +51,6 @@ func TestSubdirs(t *testing.T) { entryPaths[header.Typeflag] = append(entryPaths[header.Typeflag], header.Name) } - require.Subset(t, entryPaths[tar.TypeDir], []string{"images"}) - require.Subset(t, entryPaths[tar.TypeReg], []string{"README.md", "main.tf", "images/base.Dockerfile"}) + require.Subset(t, entryPaths[tar.TypeDir], []string{"build"}) + require.Subset(t, entryPaths[tar.TypeReg], []string{"README.md", "main.tf", "build/Dockerfile"}) } diff --git a/examples/lima/README.md b/examples/lima/README.md index ade54e52a7d00..9828201ae9d80 100644 --- a/examples/lima/README.md +++ b/examples/lima/README.md @@ -22,7 +22,7 @@ This will: - Install Docker and Terraform from the official repos - Install Coder using the [installation script](https://coder.com/docs/coder-oss/latest/install#installsh) - Generates an initial user account `admin@coder.com` with a randomly generated password (stored in the VM under `/home/${USER}.linux/.config/coderv2/password`) -- Initializes a [sample Docker template](https://github.com/coder/coder/tree/main/examples/templates/docker-code-server) for creating workspaces +- Initializes a [sample Docker template](https://github.com/coder/coder/tree/main/examples/templates/docker) for creating workspaces Once this completes, you can visit `http://localhost:3000` and start creating workspaces! diff --git a/examples/lima/coder.yaml b/examples/lima/coder.yaml index c806051067507..7b4382e19742f 100644 --- a/examples/lima/coder.yaml +++ b/examples/lima/coder.yaml @@ -103,7 +103,7 @@ provision: fi DOCKER_HOST=$(docker context inspect --format '{{.Endpoints.docker.Host}}') printf 'docker_arch: "%s"\ndocker_host: "%s"\n' "${DOCKER_ARCH}" "${DOCKER_HOST}" | tee "${temp_template_dir}/params.yaml" - coder templates create "docker-code-server-${DOCKER_ARCH}" --directory "${temp_template_dir}" --parameter-file "${temp_template_dir}/params.yaml" --yes + coder templates create "docker-${DOCKER_ARCH}" --directory "${temp_template_dir}" --parameter-file "${temp_template_dir}/params.yaml" --yes rm -rfv "${temp_template_dir}" probes: - description: "docker to be installed" diff --git a/examples/templates/docker-code-server/README.md b/examples/templates/docker-code-server/README.md deleted file mode 100644 index 75fb980fde22e..0000000000000 --- a/examples/templates/docker-code-server/README.md +++ /dev/null @@ -1,26 +0,0 @@ ---- -name: Develop code-server in Docker -description: Run code-server in a Docker development environment -tags: [local, docker] -icon: /icon/docker.png ---- - -# code-server in Docker - -## Getting started - -Run `coder templates init` and select this template. Follow the instructions that appear. - -## Supported Parameters - -You can create a file containing parameters and pass the argument -`--parameter-file` to `coder templates create`. -See `params.sample.yaml` for more information. - -This template has the following predefined parameters: - -- `docker_host`: Path to (or address of) the Docker socket. - > You can determine the correct value for this by running - > `docker context ls`. -- `docker_arch`: Architecture of the host running Docker. - This can be `amd64`, `arm64`, or `armv7`. diff --git a/examples/templates/docker-code-server/main.tf b/examples/templates/docker-code-server/main.tf deleted file mode 100644 index b8284fe99011c..0000000000000 --- a/examples/templates/docker-code-server/main.tf +++ /dev/null @@ -1,124 +0,0 @@ -terraform { - required_providers { - coder = { - source = "coder/coder" - version = "~> 0.6.17" - } - docker = { - source = "kreuzwerker/docker" - version = "~> 3.0.1" - } - } -} - -data "coder_provisioner" "me" { -} - -provider "docker" { -} - -data "coder_workspace" "me" { -} - -resource "coder_agent" "main" { - arch = data.coder_provisioner.me.arch - os = "linux" - login_before_ready = false - startup_script_timeout = 180 - startup_script = <<-EOT - set -e - code-server --auth none >/tmp/code-server.log 2>&1 & - EOT - - # These environment variables allow you to make Git commits right away after creating a - # workspace. Note that they take precedence over configuration defined in ~/.gitconfig! - # You can remove this block if you'd prefer to configure Git manually or using - # dotfiles. (see docs/dotfiles.md) - env = { - GIT_AUTHOR_NAME = "${data.coder_workspace.me.owner}" - GIT_COMMITTER_NAME = "${data.coder_workspace.me.owner}" - GIT_AUTHOR_EMAIL = "${data.coder_workspace.me.owner_email}" - GIT_COMMITTER_EMAIL = "${data.coder_workspace.me.owner_email}" - } -} - -resource "coder_app" "code-server" { - agent_id = coder_agent.main.id - slug = "code-server" - display_name = "code-server" - url = "http://localhost:8080/?folder=/home/coder" - icon = "/icon/code.svg" - subdomain = false - share = "owner" - - healthcheck { - url = "http://localhost:8080/healthz" - interval = 3 - threshold = 10 - } -} - -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.me.owner - } - labels { - label = "coder.owner_id" - value = data.coder_workspace.me.owner_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_container" "workspace" { - count = data.coder_workspace.me.start_count - image = "codercom/code-server:latest" - # Uses lower() to avoid Docker restriction on container names. - name = "coder-${data.coder_workspace.me.owner}-${lower(data.coder_workspace.me.name)}" - # Hostname makes the shell more user friendly: coder@my-workspace:~$ - hostname = data.coder_workspace.me.name - # Use the docker gateway if the access URL is 127.0.0.1 - entrypoint = ["sh", "-c", replace(coder_agent.main.init_script, "/localhost|127\\.0\\.0\\.1/", "host.docker.internal")] - env = ["CODER_AGENT_TOKEN=${coder_agent.main.token}"] - host { - host = "host.docker.internal" - ip = "host-gateway" - } - volumes { - container_path = "/home/coder/" - volume_name = docker_volume.home_volume.name - read_only = false - } - # Add labels in Docker to keep track of orphan resources. - labels { - label = "coder.owner" - value = data.coder_workspace.me.owner - } - labels { - label = "coder.owner_id" - value = data.coder_workspace.me.owner_id - } - labels { - label = "coder.workspace_id" - value = data.coder_workspace.me.id - } - labels { - label = "coder.workspace_name" - value = data.coder_workspace.me.name - } -} diff --git a/examples/templates/docker-code-server/params.sample.yaml b/examples/templates/docker-code-server/params.sample.yaml deleted file mode 100644 index 580e0ed137d30..0000000000000 --- a/examples/templates/docker-code-server/params.sample.yaml +++ /dev/null @@ -1,2 +0,0 @@ -docker_host: "unix:///var/run/docker.sock" -docker_arch: "amd64" diff --git a/examples/templates/docker-image-builds/README.md b/examples/templates/docker-image-builds/README.md deleted file mode 100644 index 6cdbacd91d29f..0000000000000 --- a/examples/templates/docker-image-builds/README.md +++ /dev/null @@ -1,167 +0,0 @@ ---- -name: Develop in Docker with custom image builds -description: Build images and run workspaces on the Docker host with no image registry required -tags: [local, docker] -icon: /icon/docker.png ---- - -# docker-image-builds - -This example bundles Dockerfiles with the Coder template, allowing the Docker host to build images itself instead of relying on an external registry. - -For large use cases, we recommend building images using CI/CD pipelines and registries instead of at workspace runtime. However, this example is practical for tinkering and iterating on Dockerfiles. - -## Getting started - -Run `coder templates init`. When prompted, select this template, and follow the -on-screen instructions to proceed. - -## Adding images - -Create a Dockerfile (e.g `images/golang.Dockerfile`): - -```console -vim images/golang.Dockerfile -``` - -```Dockerfile -# Start from base image (built on Docker host) -FROM coder-base:latest - -# Install everything as root -USER root - -# Install go -RUN curl -L "https://dl.google.com/go/go1.18.1.linux-amd64.tar.gz" | tar -C /usr/local -xzvf - - -# Setup go env vars -ENV GOROOT /usr/local/go -ENV PATH $PATH:$GOROOT/bin - -ENV GOPATH /home/coder/go -ENV GOBIN $GOPATH/bin -ENV PATH $PATH:$GOBIN - -# Set back to coder user -USER coder -``` - -Edit the Terraform template (`main.tf`): - -```console -vim main.tf -``` - -Edit the validation to include the new image: - -```diff -variable "docker_image" { - description = "What Docker image would you like to use for your workspace?" - default = "base" - - # List of images available for the user to choose from. - # Delete this condition to give users free text input. - validation { -- condition = contains(["base", "java", "node"], var.docker_image) -+ condition = contains(["base", "java", "node", "golang], var.docker_image) - error_message = "Invalid Docker image!" - } -} -``` - -Bump the image tag to a new version: - -```diff -resource "docker_image" "coder_image" { - name = "coder-base-${data.coder_workspace.me.owner}-${lower(data.coder_workspace.me.name)}" - build { - path = "./images/" - dockerfile = "${var.docker_image}.Dockerfile" -- tag = ["coder-${var.docker_image}:v0.1"] -+ tag = ["coder-${var.docker_image}:v0.2"] - } - - # Keep alive for other workspaces to use upon deletion - keep_locally = true -} -``` - -Update the template: - -```console -coder template push docker-image-builds -``` - -You can also remove images from the validation list. Workspaces using older template versions will continue using -the removed image until you update the workspace to the latest version. - -## Updating images - -Edit the Dockerfile (or related assets): - -```console -vim images/node.Dockerfile -``` - -```diff -# Install Node -- RUN curl -sL https://deb.nodesource.com/setup_14.x | bash - -+ RUN curl -sL https://deb.nodesource.com/setup_16.x | bash - -RUN DEBIAN_FRONTEND="noninteractive" apt-get update -y && \ - apt-get install -y nodejs -``` - -1. Edit the Terraform template (`main.tf`) - -```console -vim main.tf -``` - -Bump the image tag to a new version: - -```diff -resource "docker_image" "coder_image" { - name = "coder-base-${data.coder_workspace.me.owner}-${lower(data.coder_workspace.me.name)}" - build { - path = "./images/" - dockerfile = "${var.docker_image}.Dockerfile" -- tag = ["coder-${var.docker_image}:v0.1"] -+ tag = ["coder-${var.docker_image}:v0.2"] - } - - # Keep alive for other workspaces to use upon deletion - keep_locally = true -} -``` - -Update the template: - -```console -coder template push docker-image-builds -``` - -Optional: Update workspaces to the latest template version - -```console -coder ls -coder update [workspace name] -``` - -## code-server - -`code-server` is installed via the `startup_script` argument in the `coder_agent` -resource block. The `coder_app` resource is defined to access `code-server` through -the dashboard UI over `localhost:13337`. - -## Extending this template - -See the [kreuzwerker/docker](https://registry.terraform.io/providers/kreuzwerker/docker) Terraform provider documentation to -add the following features to your Coder template: - -- SSH/TCP docker host -- Build args -- Volume mounts -- Custom container spec -- More - -We also welcome all contributions! diff --git a/examples/templates/docker-image-builds/images/base.Dockerfile b/examples/templates/docker-image-builds/images/base.Dockerfile deleted file mode 100644 index 620b0fa0cd088..0000000000000 --- a/examples/templates/docker-image-builds/images/base.Dockerfile +++ /dev/null @@ -1,33 +0,0 @@ -FROM ubuntu:20.04 - -RUN apt-get update && \ - DEBIAN_FRONTEND="noninteractive" apt-get install --yes \ - bash \ - build-essential \ - ca-certificates \ - curl \ - htop \ - locales \ - man \ - python3 \ - python3-pip \ - software-properties-common \ - sudo \ - systemd \ - systemd-sysv \ - unzip \ - vim \ - wget && \ - # Install latest Git using their official PPA - add-apt-repository ppa:git-core/ppa && \ - DEBIAN_FRONTEND="noninteractive" apt-get install --yes git - -# Add a user `coder` so that you're not developing as the `root` user -RUN useradd coder \ - --create-home \ - --shell=/bin/bash \ - --uid=1000 \ - --user-group && \ - echo "coder ALL=(ALL) NOPASSWD:ALL" >>/etc/sudoers.d/nopasswd - -USER coder diff --git a/examples/templates/docker-image-builds/images/java.Dockerfile b/examples/templates/docker-image-builds/images/java.Dockerfile deleted file mode 100644 index a35fc20230786..0000000000000 --- a/examples/templates/docker-image-builds/images/java.Dockerfile +++ /dev/null @@ -1,57 +0,0 @@ -# From the base image (built on Docker host) -FROM coder-base:v0.1 - -# Install everything as root -USER root - -# Install JDK (OpenJDK 8) -RUN DEBIAN_FRONTEND="noninteractive" apt-get update -y && \ - apt-get install -y openjdk-11-jdk -ENV JAVA_HOME /usr/lib/jvm/java-11-openjdk-amd64 -ENV PATH $PATH:$JAVA_HOME/bin - -# Install Maven -ARG MAVEN_VERSION=3.6.3 -ARG MAVEN_SHA512=c35a1803a6e70a126e80b2b3ae33eed961f83ed74d18fcd16909b2d44d7dada3203f1ffe726c17ef8dcca2dcaa9fca676987befeadc9b9f759967a8cb77181c0 - -ENV MAVEN_HOME /usr/share/maven -ENV MAVEN_CONFIG "/home/coder/.m2" - -RUN mkdir -p $MAVEN_HOME $MAVEN_HOME/ref \ - && echo "Downloading Maven" \ - && curl -fsSL -o /tmp/apache-maven.tar.gz https://apache.osuosl.org/maven/maven-3/${MAVEN_VERSION}/binaries/apache-maven-${MAVEN_VERSION}-bin.tar.gz \ - \ - && echo "Checking downloaded file hash" \ - && echo "${MAVEN_SHA512} /tmp/apache-maven.tar.gz" | sha512sum -c - \ - \ - && echo "Unzipping Maven" \ - && tar -xzf /tmp/apache-maven.tar.gz -C $MAVEN_HOME --strip-components=1 \ - \ - && echo "Cleaning and setting links" \ - && rm -f /tmp/apache-maven.tar.gz \ - && ln -s $MAVEN_HOME/bin/mvn /usr/bin/mvn - -# Install Gradle -ENV GRADLE_VERSION=6.7 -ARG GRADLE_SHA512=d495bc65379d2a854d2cca843bd2eeb94f381e5a7dcae89e6ceb6ef4c5835524932313e7f30d7a875d5330add37a5fe23447dc3b55b4d95dffffa870c0b24493 - -ENV GRADLE_HOME /usr/bin/gradle - -RUN mkdir -p /usr/share/gradle /usr/share/gradle/ref \ - && echo "Downloading Gradle" \ - && curl -fsSL -o /tmp/gradle.zip https://services.gradle.org/distributions/gradle-${GRADLE_VERSION}-bin.zip \ - \ - && echo "Checking downloaded file hash" \ - && echo "${GRADLE_SHA512} /tmp/gradle.zip" | sha512sum -c - \ - \ - && echo "Unziping gradle" \ - && unzip -d /usr/share/gradle /tmp/gradle.zip \ - \ - && echo "Cleaning and setting links" \ - && rm -f /tmp/gradle.zip \ - && ln -s /usr/share/gradle/gradle-${GRADLE_VERSION} /usr/bin/gradle - -ENV PATH $PATH:$GRADLE_HOME/bin - -# Set back to coder user -USER coder diff --git a/examples/templates/docker-image-builds/images/node.Dockerfile b/examples/templates/docker-image-builds/images/node.Dockerfile deleted file mode 100644 index 1c371f8bb40a1..0000000000000 --- a/examples/templates/docker-image-builds/images/node.Dockerfile +++ /dev/null @@ -1,18 +0,0 @@ -# Start from base image (built on Docker host) -FROM coder-base:v0.1 - -# Install everything as root -USER root - -# Install Node -RUN curl -sL https://deb.nodesource.com/setup_14.x | bash - -RUN DEBIAN_FRONTEND="noninteractive" apt-get update -y && \ - apt-get install -y nodejs - -# Install Yarn -RUN curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - -RUN echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list -RUN DEBIAN_FRONTEND="noninteractive" apt-get update && apt-get install -y yarn - -# Set back to coder user -USER coder diff --git a/examples/templates/docker-image-builds/main.tf b/examples/templates/docker-image-builds/main.tf deleted file mode 100644 index 5ba1cf0caf56a..0000000000000 --- a/examples/templates/docker-image-builds/main.tf +++ /dev/null @@ -1,162 +0,0 @@ - -terraform { - required_providers { - coder = { - source = "coder/coder" - version = "~> 0.6.17" - } - docker = { - source = "kreuzwerker/docker" - version = "~> 3.0.1" - } - } -} - -data "coder_provisioner" "me" { -} - -provider "docker" { -} - -data "coder_workspace" "me" { -} - -resource "coder_agent" "main" { - arch = data.coder_provisioner.me.arch - os = "linux" - login_before_ready = false - startup_script_timeout = 180 - startup_script = <<-EOT - set -e - - # install and start code-server - curl -fsSL https://code-server.dev/install.sh | sh -s -- --method=standalone --prefix=/tmp/code-server --version 4.11.0 - /tmp/code-server/bin/code-server --auth none --port 13337 >/tmp/code-server.log 2>&1 & - EOT -} - -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 - share = "owner" - - healthcheck { - url = "http://localhost:13337/healthz" - interval = 3 - threshold = 10 - } -} - -data "coder_parameter" "docker_image" { - name = "What Docker image would you like to use for your workspace?" - description = "The Docker image will be used to build your workspace. You can choose from a list of pre-built images or provide your own." - default = "base" - icon = "/icon/docker.png" - type = "string" - mutable = false - option { - name = "Base" - value = "base" - icon = "/icon/code.svg" - } - option { - name = "Java" - value = "java" - icon = "/icon/java.svg" - } - option { - name = "Node" - value = "node" - icon = "/icon/node.svg" - } -} - -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.me.owner - } - labels { - label = "coder.owner_id" - value = data.coder_workspace.me.owner_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_image" "coder_image" { - name = "coder-base-${data.coder_workspace.me.owner}-${lower(data.coder_workspace.me.name)}" - build { - context = "./images/" - dockerfile = "${data.coder_parameter.docker_image.value}.Dockerfile" - tag = ["coder-${data.coder_parameter.docker_image.value}:v0.1"] - } - # Keep alive for other workspaces to use upon deletion - keep_locally = true -} - -resource "docker_container" "workspace" { - count = data.coder_workspace.me.start_count - image = docker_image.coder_image.image_id - # Uses lower() to avoid Docker restriction on container names. - name = "coder-${data.coder_workspace.me.owner}-${lower(data.coder_workspace.me.name)}" - # Hostname makes the shell more user friendly: coder@my-workspace:~$ - hostname = data.coder_workspace.me.name - # Use the docker gateway if the access URL is 127.0.0.1 - entrypoint = ["sh", "-c", replace(coder_agent.main.init_script, "/localhost|127\\.0\\.0\\.1/", "host.docker.internal")] - env = ["CODER_AGENT_TOKEN=${coder_agent.main.token}"] - host { - host = "host.docker.internal" - ip = "host-gateway" - } - volumes { - container_path = "/home/coder/" - volume_name = docker_volume.home_volume.name - read_only = false - } - # Add labels in Docker to keep track of orphan resources. - labels { - label = "coder.owner" - value = data.coder_workspace.me.owner - } - labels { - label = "coder.owner_id" - value = data.coder_workspace.me.owner_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 = "image" - value = data.coder_parameter.docker_image.value - } -}