From ace18550b74f9a6f67c13f65779d1feb86d60dd4 Mon Sep 17 00:00:00 2001 From: Ammar Bandukwala Date: Mon, 24 Jul 2023 23:11:51 +0000 Subject: [PATCH] =?UTF-8?q?docs:=20explain=20JFrog=20integration=20?= =?UTF-8?q?=F0=9F=90=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/manifest.json | 25 +-- docs/platforms/jfrog.md | 152 ++++++++++++++++++ examples/templates/jfrog-docker/README.md | 26 +++ .../templates/jfrog-docker/build/Dockerfile | 21 +++ examples/templates/jfrog-docker/main.tf | 137 ++++++++++++++++ site/static/icon/jfrog.svg | 1 + 6 files changed, 352 insertions(+), 10 deletions(-) create mode 100644 docs/platforms/jfrog.md create mode 100644 examples/templates/jfrog-docker/README.md create mode 100644 examples/templates/jfrog-docker/build/Dockerfile create mode 100644 examples/templates/jfrog-docker/main.tf create mode 100644 site/static/icon/jfrog.svg diff --git a/docs/manifest.json b/docs/manifest.json index 423bb33353a70..96b5e9048cccb 100644 --- a/docs/manifest.json +++ b/docs/manifest.json @@ -85,6 +85,18 @@ "path": "./platforms/aws.md", "icon_path": "./images/aws.svg" }, + { + "title": "Azure", + "description": "Set up Coder on an Azure VM", + "path": "./platforms/azure.md", + "icon_path": "./images/azure.svg" + }, + { + "title": "Docker", + "description": "Set up Coder with Docker", + "path": "./platforms/docker.md", + "icon_path": "./images/icons/docker.svg" + }, { "title": "GCP", "description": "Set up Coder on a GCP Compute Engine VM", @@ -92,10 +104,9 @@ "icon_path": "./images/google-cloud.svg" }, { - "title": "Azure", - "description": "Set up Coder on an Azure VM", - "path": "./platforms/azure.md", - "icon_path": "./images/azure.svg" + "title": "JFrog", + "description": "Integrate Coder with JFrog", + "path": "./platforms/jfrog.md" }, { "title": "Kubernetes", @@ -109,12 +120,6 @@ } ] }, - { - "title": "Docker", - "description": "Set up Coder with Docker", - "path": "./platforms/docker.md", - "icon_path": "./images/icons/docker.svg" - }, { "title": "Other platforms", "description": "Set up Coder on an another provider", diff --git a/docs/platforms/jfrog.md b/docs/platforms/jfrog.md new file mode 100644 index 0000000000000..d680654308a5c --- /dev/null +++ b/docs/platforms/jfrog.md @@ -0,0 +1,152 @@ +# JFrog + +Coder and JFrog work together to provide seamless security and compliance for +your development environments. With Coder, you can automatically authenticate +every workspace to use Artifactory as a package registry. + +In this page, we'll show you how to integrate both products using Docker +as the underlying compute. But, these concepts apply to any compute platform. The full example template can be found [here](https://github.com/coder/coder/tree/main/examples/jfrog-docker). + +## Requirements + +- A JFrog Artifactory instance +- 1:1 mapping of users in Coder to users in Artifactory by email address + +## Provisioner Authentication + +The most straight-forward way to authenticate your template with Artifactory is +by using +[Terraform-managed variables](https://coder.com/docs/v2/latest/templates/parameters#terraform-template-wide-variables). + +See the following example: + +```hcl +terraform { + required_providers { + coder = { + source = "coder/coder" + version = "~> 0.11.1" + } + docker = { + source = "kreuzwerker/docker" + version = "~> 3.0.1" + } + artifactory = { + source = "registry.terraform.io/jfrog/artifactory" + version = "6.22.3" + } + } +} + +variable "jfrog_url" { + type = string + description = "The URL of the JFrog instance." +} + +variable "artifactory_access_token" { + type = string + description = "The admin-level access token to use for JFrog." +} + +# Configure the Artifactory provider +provider "artifactory" { + url = "${var.jfrog_url}/artifactory" + access_token = "${var.artifactory_access_token}" +} +``` + +When pushing the template, you can pass in the variables using the `--variable` flag: + +```sh +coder templates push --variable 'jfrog_url=https://YYY.jfrog.io' --variable 'artifactory_access_token=XXX' +``` + +## Installing jf + +`jf` is the JFrog CLI. It can do many things across the JFrog platform, but +we'll focus on its ability to configure package managers, as that's the relevant +functionality for most developers. + +The generic method of installing the JFrog CLI is the following command: + +```sh +curl -fL https://install-cli.jfrog.io | sh +``` + +Other methods are listed [here](https://jfrog.com/help/r/jfrog-cli/download-and-installation). + +In our Docker-based example, we install `jf` by adding these lines to our `Dockerfile`: + +```Dockerfile +RUN curl -fL https://install-cli.jfrog.io | sh +RUN chmod 755 $(which jf) +``` + +and use this `coder_agent` block: + +```hcl +resource "coder_agent" "main" { + arch = data.coder_provisioner.me.arch + os = "linux" + 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 & + + # The jf CLI checks $CI when determining whether to use interactive + # flows. + export CI=true + + jf c rm 0 || true + echo ${artifactory_access_token.me.access_token} | \ + jf c add --access-token-stdin --url ${var.jfrog_url} 0 + EOT +} +``` + +You can verify that `jf` is configured correctly in your workspace by +running `jf c show`. It should display output like: + +```text +coder@jf:~$ jf c show +Server ID: 0 +JFrog Platform URL: https://cdr.jfrog.io/ +Artifactory URL: https://cdr.jfrog.io/artifactory/ +Distribution URL: https://cdr.jfrog.io/distribution/ +Xray URL: https://cdr.jfrog.io/xray/ +Mission Control URL: https://cdr.jfrog.io/mc/ +Pipelines URL: https://cdr.jfrog.io/pipelines/ +User: ammar@....com +Access token: ... +Default: true +``` + +## Configuring npm + +Add the following line to your `startup_script` to configure `npm` to use +Artifactory: + +```sh + # Configure the `npm` CLI to use the Artifactory "npm" registry. + cat << EOF > ~/.npmrc + email = ${data.coder_workspace.me.owner_email} + registry=${var.jfrog_url}/artifactory/api/npm/npm/ + EOF + jf rt curl /api/npm/auth >> .npmrc +``` + +Now, your developers can run `npm install`, `npm audit`, etc. and transparently +use Artifactory as the package registry. You can verify that `npm` is configured +correctly by running `npm install --loglevel=http react` and checking that +npm is only hitting your Artifactory URL. + +You can apply the same concepts to Docker, Go, Maven, and other package managers +supported by Artifactory. + +## More reading + +- See the full example template [here](https://github.com/coder/coder/tree/main/examples/jfrog-docker). +- To serve extensions from your own VS Code Marketplace, check out [code-marketplace](https://github.com/coder/code-marketplace#artifactory-storage). diff --git a/examples/templates/jfrog-docker/README.md b/examples/templates/jfrog-docker/README.md new file mode 100644 index 0000000000000..ac1a3a128643f --- /dev/null +++ b/examples/templates/jfrog-docker/README.md @@ -0,0 +1,26 @@ +--- +name: JFrog and Docker +description: Develop inside Docker containers using your local daemon +tags: [local, docker, jfrog] +icon: /icon/docker.png +--- + +# jfrog-docker + +To get started, run `coder templates init`. When prompted, select this template. +Follow the on-screen instructions to proceed. + +## Editing the image + +Edit the `Dockerfile` and run `coder templates push` to update workspaces. + +## 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`. + +# Next steps + +Check out our [Docker](../docker/) template for a more fully featured Docker +example. diff --git a/examples/templates/jfrog-docker/build/Dockerfile b/examples/templates/jfrog-docker/build/Dockerfile new file mode 100644 index 0000000000000..1dfaa77015f32 --- /dev/null +++ b/examples/templates/jfrog-docker/build/Dockerfile @@ -0,0 +1,21 @@ +FROM ubuntu + +RUN apt-get update \ + && apt-get install -y \ + curl \ + git \ + golang \ + sudo \ + vim \ + wget \ + npm \ + && rm -rf /var/lib/apt/lists/* + +ARG USER=coder +RUN useradd --groups sudo --no-create-home --shell /bin/bash ${USER} \ + && echo "${USER} ALL=(ALL) NOPASSWD:ALL" >/etc/sudoers.d/${USER} \ + && chmod 0440 /etc/sudoers.d/${USER} +RUN curl -fL https://install-cli.jfrog.io | sh +RUN chmod 755 $(which jf) +USER ${USER} +WORKDIR /home/${USER} diff --git a/examples/templates/jfrog-docker/main.tf b/examples/templates/jfrog-docker/main.tf new file mode 100644 index 0000000000000..0c409d5ebe54b --- /dev/null +++ b/examples/templates/jfrog-docker/main.tf @@ -0,0 +1,137 @@ +terraform { + required_providers { + coder = { + source = "coder/coder" + version = "~> 0.11.1" + } + docker = { + source = "kreuzwerker/docker" + version = "~> 3.0.1" + } + artifactory = { + source = "registry.terraform.io/jfrog/artifactory" + version = "6.22.3" + } + } +} + +locals { + username = data.coder_workspace.me.owner +} + +data "coder_provisioner" "me" { +} + +provider "docker" { +} + +data "coder_workspace" "me" { +} + +variable "jfrog_url" { + type = string + description = "The URL of the JFrog instance." +} + +variable "artifactory_access_token" { + type = string + description = "The admin-level access token to use for JFrog." +} + + +# Configure the Artifactory provider +provider "artifactory" { + url = "${var.jfrog_url}/artifactory" + access_token = var.artifactory_access_token +} + +resource "artifactory_access_token" "me" { + username = data.coder_workspace.me.owner_email + # The token should live for the duration of the workspace. + end_date_relative = "0s" +} + +resource "coder_agent" "main" { + arch = data.coder_provisioner.me.arch + os = "linux" + 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 & + + # The jf CLI checks $CI when determining whether to use interactive + # flows. + export CI=true + + jf c rm 0 || true + echo ${artifactory_access_token.me.access_token} | \ + jf c add --access-token-stdin --url ${var.jfrog_url} 0 + + # Configure the `npm` CLI to use the Artifactory "npm" registry. + cat << EOF > ~/.npmrc + email = ${data.coder_workspace.me.owner_email} + registry=${var.jfrog_url}/artifactory/api/npm/npm/ + EOF + jf rt curl /api/npm/auth >> .npmrc + 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/${local.username}" + icon = "/icon/code.svg" + subdomain = false + share = "owner" + + healthcheck { + url = "http://localhost:13337/healthz" + interval = 5 + threshold = 6 + } +} + +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 + } +} + +resource "docker_image" "main" { + name = "coder-${data.coder_workspace.me.id}" + build { + context = "./build" + build_args = { + USER = local.username + } + } + triggers = { + dir_sha1 = sha1(join("", [for f in fileset(path.module, "build/*") : filesha1(f)])) + } +} + +resource "docker_container" "workspace" { + count = data.coder_workspace.me.start_count + image = docker_image.main.name + # 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 + entrypoint = ["sh", "-c", coder_agent.main.init_script] + env = ["CODER_AGENT_TOKEN=${coder_agent.main.token}"] + host { + host = "host.docker.internal" + ip = "host-gateway" + } + volumes { + container_path = "/home/${local.username}" + volume_name = docker_volume.home_volume.name + read_only = false + } +} diff --git a/site/static/icon/jfrog.svg b/site/static/icon/jfrog.svg new file mode 100644 index 0000000000000..5e0c6337f3bb8 --- /dev/null +++ b/site/static/icon/jfrog.svg @@ -0,0 +1 @@ + \ No newline at end of file