From 72e42ade7d03fd108d95be67270fd39d44b43e3d Mon Sep 17 00:00:00 2001 From: Muhammad Atif Ali Date: Sun, 17 Dec 2023 16:41:57 +0300 Subject: [PATCH 1/9] feat(examples/templates): add aws vm devcontainer template --- examples/templates/aws-devcontainer/main.tf | 175 ++++++++++++++++++++ 1 file changed, 175 insertions(+) create mode 100644 examples/templates/aws-devcontainer/main.tf diff --git a/examples/templates/aws-devcontainer/main.tf b/examples/templates/aws-devcontainer/main.tf new file mode 100644 index 0000000000000..bb180ee0447ff --- /dev/null +++ b/examples/templates/aws-devcontainer/main.tf @@ -0,0 +1,175 @@ +terraform { + required_providers { + coder = { + source = "coder/coder" + } + aws = { + source = "hashicorp/aws" + } + } +} + +module "aws_region" { + source = "https://registry.coder.com/modules/aws-region" + default = "us-east-1" +} + +data "coder_parameter" "instance_type" { + name = "instance_type" + display_name = "Instance type" + description = "What instance type should your workspace use?" + default = "t3.micro" + mutable = false + option { + name = "2 vCPU, 1 GiB RAM" + value = "t3.micro" + } + option { + name = "2 vCPU, 2 GiB RAM" + value = "t3.small" + } + option { + name = "2 vCPU, 4 GiB RAM" + value = "t3.medium" + } + option { + name = "2 vCPU, 8 GiB RAM" + value = "t3.large" + } + option { + name = "4 vCPU, 16 GiB RAM" + value = "t3.xlarge" + } + option { + name = "8 vCPU, 32 GiB RAM" + value = "t3.2xlarge" + } +} + +provider "aws" { + region = module.aws_region.value +} + +data "coder_workspace" "me" { +} + +data "aws_ami" "ubuntu" { + most_recent = true + filter { + name = "name" + values = ["ubuntu/images/hvm-ssd/ubuntu-jammy-22.04-amd64-server-*"] + } + filter { + name = "virtualization-type" + values = ["hvm"] + } + owners = ["099720109477"] # Canonical +} + +data "coder_parameter" "repo_url" { + name = "repo_url" + display_name = "Repository URL" + default = "https://github.com/coder/envbuilder-starter-devcontainer" + description = "Repository URL" + mutable = true +} + +resource "coder_agent" "dev" { + count = data.coder_workspace.me.start_count + arch = "amd64" + auth = "token" + os = "linux" + dir = "/worskpaces" + connection_timeout = 0 + + metadata { + key = "cpu" + display_name = "CPU Usage" + interval = 5 + timeout = 5 + script = "coder stat cpu" + } + metadata { + key = "memory" + display_name = "Memory Usage" + interval = 5 + timeout = 5 + script = "coder stat mem" + } +} + +locals { + linux_user = "coder" + user_data = <<-EOT + Content-Type: multipart/mixed; boundary="//" + MIME-Version: 1.0 + + --// + Content-Type: text/cloud-config; charset="us-ascii" + MIME-Version: 1.0 + Content-Transfer-Encoding: 7bit + Content-Disposition: attachment; filename="cloud-config.txt" + + #cloud-config + cloud_final_modules: + - [scripts-user, always] + hostname: ${lower(data.coder_workspace.me.name)} + users: + - name: ${local.linux_user} + sudo: ALL=(ALL) NOPASSWD:ALL + shell: /bin/bash + + --// + Content-Type: text/x-shellscript; charset="us-ascii" + MIME-Version: 1.0 + Content-Transfer-Encoding: 7bit + Content-Disposition: attachment; filename="userdata.txt" + + #!/bin/bash + # Install Docker + if ! command -v docker &> /dev/null + then + echo "Docker not found, installing..." + curl -fsSL https://get.docker.com -o get-docker.sh && sh get-docker.sh 2>&1 >/dev/null + usermod -aG docker ${local.linux_user} + newgrp docker + else + echo "Docker is already installed." + fi + + # Start envbuilder + docker run --rm \ + -v /tmp/envbuilder:/workspaces \ + -e CODER_AGENT_TOKEN="${try(coder_agent.dev[0].token, "")}" \ + -e CODER_AGENT_URL="${data.coder_workspace.me.access_url}" \ + -e GIT_URL="${data.coder_parameter.repo_url.value}" \ + -e INIT_SCRIPT="echo ${base64encode(try(coder_agent.dev[0].init_script, ""))} | base64 -d | sh" \ + -e FALLBACK_IMAGE="codercom/enterprise-base:ubuntu" \ + ghcr.io/coder/envbuilder + --//-- + EOT +} + +resource "aws_instance" "vm" { + ami = data.aws_ami.ubuntu.id + availability_zone = "${module.aws_region.value}a" + instance_type = data.coder_parameter.instance_type.value + root_block_device { + volume_size = 30 + } + + user_data = local.user_data + tags = { + Name = "coder-${data.coder_workspace.me.owner}-${data.coder_workspace.me.name}" + # Required if you are using our example policy, see template README + Coder_Provisioned = "true" + } + lifecycle { + ignore_changes = [ami] + } +} + +resource "aws_ec2_instance_state" "vm" { + instance_id = aws_instance.vm.id + state = data.coder_workspace.me.transition == "start" ? "running" : "stopped" +} From a34ceb59dda968f407d9f09f4e993cdd025b16bf Mon Sep 17 00:00:00 2001 From: Muhammad Atif Ali Date: Sun, 17 Dec 2023 16:48:36 +0300 Subject: [PATCH 2/9] Create README.md --- examples/templates/aws-devcontainer/README.md | 93 +++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100644 examples/templates/aws-devcontainer/README.md diff --git a/examples/templates/aws-devcontainer/README.md b/examples/templates/aws-devcontainer/README.md new file mode 100644 index 0000000000000..c34912bfb8f48 --- /dev/null +++ b/examples/templates/aws-devcontainer/README.md @@ -0,0 +1,93 @@ +--- +display_name: AWS EC2 (Devcontainer) +description: Provision AWS EC2 VMs with a devcontainer as Coder workspaces +icon: ../../../site/static/icon/aws.png +maintainer_github: coder +verified: true +tags: [vm, linux, aws, persistent, devcontainer] +--- + +# Remote Development on AWS EC2 VMs using a Devcontainer + +Provision AWS EC2 VMs as [Coder workspaces](https://coder.com/docs/v2/latest) with this example template. + + + +## Prerequisites + +### Authentication + +By default, this template authenticates to AWS using the provider's default [authentication methods](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#authentication-and-configuration). + +The simplest way (without making changes to the template) is via environment variables (e.g. `AWS_ACCESS_KEY_ID`) or a [credentials file](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-files.html#cli-configure-files-format). If you are running Coder on a VM, this file must be in `/home/coder/aws/credentials`. + +To use another [authentication method](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#authentication), edit the template. + +## Required permissions / policy + +The following sample policy allows Coder to create EC2 instances and modify +instances provisioned by Coder: + +```json +{ + "Version": "2012-10-17", + "Statement": [ + { + "Sid": "VisualEditor0", + "Effect": "Allow", + "Action": [ + "ec2:GetDefaultCreditSpecification", + "ec2:DescribeIamInstanceProfileAssociations", + "ec2:DescribeTags", + "ec2:DescribeInstances", + "ec2:DescribeInstanceTypes", + "ec2:CreateTags", + "ec2:RunInstances", + "ec2:DescribeInstanceCreditSpecifications", + "ec2:DescribeImages", + "ec2:ModifyDefaultCreditSpecification", + "ec2:DescribeVolumes" + ], + "Resource": "*" + }, + { + "Sid": "CoderResources", + "Effect": "Allow", + "Action": [ + "ec2:DescribeInstanceAttribute", + "ec2:UnmonitorInstances", + "ec2:TerminateInstances", + "ec2:StartInstances", + "ec2:StopInstances", + "ec2:DeleteTags", + "ec2:MonitorInstances", + "ec2:CreateTags", + "ec2:RunInstances", + "ec2:ModifyInstanceAttribute", + "ec2:ModifyInstanceCreditSpecification" + ], + "Resource": "arn:aws:ec2:*:*:instance/*", + "Condition": { + "StringEquals": { + "aws:ResourceTag/Coder_Provisioned": "true" + } + } + } + ] +} +``` + +## Architecture + +This template provisions the following resources: + +- AWS Instance + +Coder uses `aws_ec2_instance_state` to start and stop the VM. This example template is fully persistent, meaning the full filesystem is preserved when the workspace restarts. See this [community example](https://github.com/bpmct/coder-templates/tree/main/aws-linux-ephemeral) of an ephemeral AWS instance. + +> **Note** +> This template is designed to be a starting point! Edit the Terraform to extend the template to support your use case. + +## code-server + +`code-server` is installed via the [`code-server`](https://registry.coder.com/modules/code-server) registry module. For a list of all modules and templates pplease check [Coder Registry](https://registry.coder.com). From 6142e2a69489969cc89bc11c69f8ce07e83f85d2 Mon Sep 17 00:00:00 2001 From: Muhammad Atif Ali Date: Sun, 17 Dec 2023 16:50:07 +0300 Subject: [PATCH 3/9] add code-server --- examples/templates/aws-devcontainer/main.tf | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/examples/templates/aws-devcontainer/main.tf b/examples/templates/aws-devcontainer/main.tf index bb180ee0447ff..ac46433157a3f 100644 --- a/examples/templates/aws-devcontainer/main.tf +++ b/examples/templates/aws-devcontainer/main.tf @@ -98,6 +98,11 @@ resource "coder_agent" "dev" { } } +module "code-server" { + source = "https://registry.coder.com/modules/code-server" + agent_id = coder_agent.dev.id +} + locals { linux_user = "coder" user_data = <<-EOT From c8c61e0b407ce60ce9482a4cbb98b2f065e9c74f Mon Sep 17 00:00:00 2001 From: Muhammad Atif Ali Date: Sun, 17 Dec 2023 16:52:58 +0300 Subject: [PATCH 4/9] fix code-server --- examples/templates/aws-devcontainer/main.tf | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/templates/aws-devcontainer/main.tf b/examples/templates/aws-devcontainer/main.tf index ac46433157a3f..e46ed259c7601 100644 --- a/examples/templates/aws-devcontainer/main.tf +++ b/examples/templates/aws-devcontainer/main.tf @@ -99,8 +99,9 @@ resource "coder_agent" "dev" { } module "code-server" { + count = data.coder_workspace.me.start_count source = "https://registry.coder.com/modules/code-server" - agent_id = coder_agent.dev.id + agent_id = coder_agent.dev[0].id } locals { From 6941594a2aea43c690eee4070e55fc6d70ca8256 Mon Sep 17 00:00:00 2001 From: Muhammad Atif Ali Date: Sun, 17 Dec 2023 13:57:34 +0000 Subject: [PATCH 5/9] `make fmt` --- examples/templates/aws-devcontainer/main.tf | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/examples/templates/aws-devcontainer/main.tf b/examples/templates/aws-devcontainer/main.tf index e46ed259c7601..58300c9664b99 100644 --- a/examples/templates/aws-devcontainer/main.tf +++ b/examples/templates/aws-devcontainer/main.tf @@ -10,7 +10,7 @@ terraform { } module "aws_region" { - source = "https://registry.coder.com/modules/aws-region" + source = "https://registry.coder.com/modules/aws-region" default = "us-east-1" } @@ -75,11 +75,11 @@ data "coder_parameter" "repo_url" { } resource "coder_agent" "dev" { - count = data.coder_workspace.me.start_count - arch = "amd64" - auth = "token" - os = "linux" - dir = "/worskpaces" + count = data.coder_workspace.me.start_count + arch = "amd64" + auth = "token" + os = "linux" + dir = "/worskpaces" connection_timeout = 0 metadata { @@ -99,14 +99,14 @@ resource "coder_agent" "dev" { } module "code-server" { - count = data.coder_workspace.me.start_count - source = "https://registry.coder.com/modules/code-server" + count = data.coder_workspace.me.start_count + source = "https://registry.coder.com/modules/code-server" agent_id = coder_agent.dev[0].id } locals { linux_user = "coder" - user_data = <<-EOT + user_data = <<-EOT Content-Type: multipart/mixed; boundary="//" MIME-Version: 1.0 From 4dca8c69ac6733b5ea2544a23d2b4365b162d7be Mon Sep 17 00:00:00 2001 From: Muhammad Atif Ali Date: Tue, 19 Dec 2023 22:58:54 +0300 Subject: [PATCH 6/9] Add files via upload --- examples/templates/aws-devcontainer/architecture.svg | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 examples/templates/aws-devcontainer/architecture.svg diff --git a/examples/templates/aws-devcontainer/architecture.svg b/examples/templates/aws-devcontainer/architecture.svg new file mode 100644 index 0000000000000..737db7402e0db --- /dev/null +++ b/examples/templates/aws-devcontainer/architecture.svg @@ -0,0 +1,8 @@ +AWSAWSHostingHostingVirtual MachineVirtual MachineLinux HardwareLinux HardwareCoder WorkspaceCoder WorkspaceDevcontainerDevcontainerenvbuilder created filesytemenvbuilder created filesytemA Clone of your repoA Clone of your repoSource codeSource codeLanguagesLanguagesPython. Go, etcPython. Go, etcToolingToolingExtensions, linting, formatting, etcExtensions, linting, formatting, etcCPUsCPUsDisk StorageDisk StorageCode EditorCode EditorVS Code DesktopVS Code DesktopLocal InstallationLocal InstallationVS Code DesktopVS Code DesktopLocal InstallationLocal Installationcode-servercode-serverA web IDEA web IDEJetBrains GatewayJetBrains GatewayLocal InstallationLocal InstallationCommand LineCommand LineSSH via Coder CLISSH via Coder CLI \ No newline at end of file From 63130ed7104af1f1a109a552caaba6592fb49de3 Mon Sep 17 00:00:00 2001 From: Muhammad Atif Ali Date: Tue, 19 Dec 2023 22:59:24 +0300 Subject: [PATCH 7/9] Update README.md --- examples/templates/aws-devcontainer/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/templates/aws-devcontainer/README.md b/examples/templates/aws-devcontainer/README.md index c34912bfb8f48..7267f62928d37 100644 --- a/examples/templates/aws-devcontainer/README.md +++ b/examples/templates/aws-devcontainer/README.md @@ -10,6 +10,7 @@ tags: [vm, linux, aws, persistent, devcontainer] # Remote Development on AWS EC2 VMs using a Devcontainer Provision AWS EC2 VMs as [Coder workspaces](https://coder.com/docs/v2/latest) with this example template. +![Architecture Diagram](./architecture.svg) From 32e1fa34cda832475404b29b819934c2a6ce5570 Mon Sep 17 00:00:00 2001 From: Muhammad Atif Ali Date: Wed, 20 Dec 2023 00:34:30 +0300 Subject: [PATCH 8/9] fix typo and persist workspace --- examples/templates/aws-devcontainer/main.tf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/templates/aws-devcontainer/main.tf b/examples/templates/aws-devcontainer/main.tf index 58300c9664b99..876faaaabc0dc 100644 --- a/examples/templates/aws-devcontainer/main.tf +++ b/examples/templates/aws-devcontainer/main.tf @@ -79,7 +79,7 @@ resource "coder_agent" "dev" { arch = "amd64" auth = "token" os = "linux" - dir = "/worskpaces" + dir = "/workspaces" connection_timeout = 0 metadata { @@ -145,7 +145,7 @@ locals { # Start envbuilder docker run --rm \ - -v /tmp/envbuilder:/workspaces \ + -v /home/${local.linux_user}/envbuilder:/workspaces \ -e CODER_AGENT_TOKEN="${try(coder_agent.dev[0].token, "")}" \ -e CODER_AGENT_URL="${data.coder_workspace.me.access_url}" \ -e GIT_URL="${data.coder_parameter.repo_url.value}" \ From 3bf33b0f9285a068a73339af03f36a3602a025f3 Mon Sep 17 00:00:00 2001 From: Muhammad Atif Ali Date: Wed, 20 Dec 2023 00:54:31 +0300 Subject: [PATCH 9/9] always land in the repo directory --- examples/templates/aws-devcontainer/main.tf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/templates/aws-devcontainer/main.tf b/examples/templates/aws-devcontainer/main.tf index 876faaaabc0dc..74d380723a8e0 100644 --- a/examples/templates/aws-devcontainer/main.tf +++ b/examples/templates/aws-devcontainer/main.tf @@ -79,7 +79,7 @@ resource "coder_agent" "dev" { arch = "amd64" auth = "token" os = "linux" - dir = "/workspaces" + dir = "/workspaces/${trimsuffix(basename(data.coder_parameter.repo_url.value), ".git")}" connection_timeout = 0 metadata {