From d889c6415dcfdd61e284f500e3eef2658e832d0f Mon Sep 17 00:00:00 2001 From: Jo Franchetti Date: Wed, 8 May 2024 09:56:56 +0100 Subject: [PATCH] updating subhosting documentation (#436) --- sidebars/subhosting.js | 40 ++++- subhosting/api/authentication.md | 44 +++++ .../images}/subhosting-org-structure.svg | 0 subhosting/api/index.md | 159 +++++++++++++----- subhosting/manual/acceptable_use_policy.md | 30 ++++ subhosting/manual/domains.md | 6 - subhosting/manual/index.md | 150 ++++++----------- ...nts.md => planning_your_implementation.md} | 21 +-- subhosting/manual/pricing_and_limits.md | 28 +++ .../{getting_started.md => quick_start.md} | 53 +++++- 10 files changed, 367 insertions(+), 164 deletions(-) create mode 100644 subhosting/api/authentication.md rename subhosting/{manual => api/images}/subhosting-org-structure.svg (100%) create mode 100644 subhosting/manual/acceptable_use_policy.md delete mode 100644 subhosting/manual/domains.md rename subhosting/manual/{projects_and_deployments.md => planning_your_implementation.md} (82%) create mode 100644 subhosting/manual/pricing_and_limits.md rename subhosting/manual/{getting_started.md => quick_start.md} (74%) diff --git a/sidebars/subhosting.js b/sidebars/subhosting.js index 651e7fc5..62f3b3e2 100644 --- a/sidebars/subhosting.js +++ b/sidebars/subhosting.js @@ -1,20 +1,48 @@ const sidebars = { - subhosting: [ + subhosting: [], + + subhostGuideHome: [ { type: "html", value: "
Getting Started
", className: "section-header", }, - "manual/index", - "manual/getting_started", - "manual/projects_and_deployments", - "manual/events", + { + type: "doc", + label: "About Subhosting", + id: "manual/index", + }, + { + type: "doc", + label: "Quick Start", + id: "manual/quick_start", + }, + { + type: "doc", + label: "Planning your implementation", + id: "manual/planning_your_implementation", + }, + { + type: "doc", + label: "Pricing and Limits", + id: "manual/pricing_and_limits", + }, { type: "html", value: "
REST API
", className: "section-header", }, - "api/index", + { + type: "doc", + label: "Resources", + id: "api/index", + }, + { + type: "doc", + label: "Authentication", + id: "api/authentication", + }, + "manual/events", { type: "link", label: "API Reference Docs", diff --git a/subhosting/api/authentication.md b/subhosting/api/authentication.md new file mode 100644 index 00000000..9e4a32e6 --- /dev/null +++ b/subhosting/api/authentication.md @@ -0,0 +1,44 @@ +# Authentication + +Developers can provision projects, domains, KV databases, and other resources +using the Subhosting REST API. + +## Endpoint and authentication + +The base URL for the Subhosting REST API v1 is below. + +```console +https://api.deno.com/v1/ +``` + +The v1 API uses +[HTTP bearer token](https://swagger.io/docs/specification/authentication/bearer-authentication/) +authentication. You can create an access token to use the API in the dashboard +[here](https://dash.deno.com/account#access-tokens). Most API requests will also +require your organization ID. You can retrieve yours from the Deno Deploy +dashboard for your organization. + +![Find your org ID here](./images/org-id.png) + +Using both your organization ID and your access token, you can test your API +access by listing all the projects associated with your organization. Here is an +example Deno script you can use to access the API. + +```typescript +// Replace these with your own! +const organizationId = "a75a9caa-b8ac-47b3-a423-3f2077c58731"; +const token = "ddo_u7mo08lBNHm8GMGLhtrEVfcgBsCuSp36dumX"; + +const res = await fetch( + `https://api.deno.com/v1/organizations/${organizationId}/projects`, + { + method: "GET", + headers: { + Authorization: `Bearer ${token}`, + }, + }, +); + +const response = await res.json(); +console.log(response); +``` diff --git a/subhosting/manual/subhosting-org-structure.svg b/subhosting/api/images/subhosting-org-structure.svg similarity index 100% rename from subhosting/manual/subhosting-org-structure.svg rename to subhosting/api/images/subhosting-org-structure.svg diff --git a/subhosting/api/index.md b/subhosting/api/index.md index 529f80c4..dddf14ad 100644 --- a/subhosting/api/index.md +++ b/subhosting/api/index.md @@ -1,47 +1,128 @@ -# Subhosting REST API +# Subhosting Resources -Developers can provision projects, domains, KV databases, and other resources -using the Subhosting REST API. +To build Subhosting with Deno Deploy, it helps to understand some key resources +within the system. These resources are also represented in the +[REST API](../api/index.md). -## Endpoint and authentication +![overview of subhosting resources](./images/subhosting-org-structure.svg) -The base URL for the Subhosting REST API v1 is below. + -```console -https://api.deno.com/v1/ -``` +## Organizations + +[**Organizations**](https://apidocs.deno.com/#get-/organizations/-organizationId-) +are a container for all data related to a subhosting implementation. Your +organization will have a name and an ID. Each organization has an analytics +endpoint which can be used to get metrics (such as request count and bandwidth +used) from across the organization. + +Other Deploy users can be invited to collaborate on an organization, and +[access tokens](https://dash.deno.com/account#access-tokens) can give developers +with organization access the ability to modify resources within the org via API. +New organizations can be created in the +[Deploy dashboard](https://dash.deno.com/orgs/new). + + + +## Projects + +[**Projects**](https://apidocs.deno.com/#get-/organizations/-organizationId-/projects) +act as organizational containers for deployments. A project contains its +deployments and the analytics and usage information for those deployments. + +Projects are free and can be set up as required. + +To track usage by individual users for billing there is an API endpoint that +reports analytics (bandwidth usage, request count, etc), per project, with 15 +minute granularity. + +> All deployments (whether within a same project or between different projects) +> share nothing by default. Projects are a way to organize your deployments and +> do not cost anything. However analytics are reported on a per-project basis, +> if you have multiple tenants we recommend setting up a project for each. +> Particularly if you expect to bill your users for their usage. + + + +## Deployments + +[**Deployments**](https://apidocs.deno.com/#get-/projects/-projectId-/deployments): +a deployment is a set of configuration, runnable code, and supporting static +files that can run on an isolate in Deno Deploy. Deployments have an entry file +that can launch a server, can have a [Deno KV](/deploy/kv/manual) database +associated with them, and can be set up to run on custom domains. + +A deployment is an immutable object that consists of: + +- Source code to run +- Static assets +- Environment variables +- Database bindings +- Other settings + +We provide endpoints for querying or streaming build logs and querying or +streaming execution logs. + +If you need to block or unblock a deployment you can do so by deleting the +deployment that you need to block or by unassigning its domains. This will make +the deployment unreachable. + +The Subhosting system is built so that the behavior or load on one deployment +does not affect other deployments. This also applies to different deployments +within one organization. Capacity is auto-scaled on demand. If you want to limit +resources to a particular deployment or application you can use the analytics +API to provide you with detailed metrics (request count, bandwidth, etc) at +project level granularity. You can use this to decide whether to shut off +deployments and make them unreachable. + +> NB. **Deployments are immutable**, however, you can create a new deployment +> and then remap its domain to the new deployment. The redeploy endpoint can +> create a new deployment from an existing one with different settings. + + + +## Custom domains + +[**Custom domains**](https://apidocs.deno.com/#get-/organizations/-organizationId-/domains) +can be dynamically mapped to deployments, giving them a unique URL (eg +`mycompany.com`). + +Before a domain can be used you need to +[verify ownership and provision +or upload TLS certificates](https://github.com/denoland/deploy-api/blob/main/samples.ipynb). + +If you are on the [Builder tier](https://deno.com/deploy/pricing?subhosting) you +can use wildcard domains. Once you have a wildcard domain registered, you can +use it in two ways: + +- Send all requests for `*.mycompany.com` to a specific deployment +- (Coming soon) Assign different subdomains (e.g. `foo.mycompany.com` and + `bar.mycompany.com`) to separate deployments. + +### Staging vs Production Environments + +The Deno Deploy end-user platform automatically creates preview deployments when +a developer opens a github pull request, and commits to the “main” branch are +automatically turned into production deployments. Although subhosting does not +provide github integration out of the box, it has all the primitives you need to +define your own semantics for creating preview and production deployments. + + + +## Connecting a KV Database + +A (KV) database stores key-value pairs You can make a database accessible to a +deployment when you make the deployment. KV databases can be used by multiple +deployments at the same time. + +To use KV with Subhosting: + +- [Create a database using the API](https://docs.deno.com/deploy/kv/manual) +- When you create a deployment using the Subhosting API, specify the database + you created. + +> NB. Deno Cron and Queues do not currently work for Subhosting. -The v1 API uses -[HTTP bearer token](https://swagger.io/docs/specification/authentication/bearer-authentication/) -authentication. You can create an access token to use the API in the dashboard -[here](https://dash.deno.com/account#access-tokens). Most API requests will also -require your organization ID. You can retrieve yours from the Deno Deploy -dashboard for your organization. - -![Find your org ID here](./images/org-id.png) - -Using both your organization ID and your access token, you can test your API -access by listing all the projects associated with your organization. Here is an -example Deno script you can use to access the API. - -```typescript -// Replace these with your own! -const organizationId = "a75a9caa-b8ac-47b3-a423-3f2077c58731"; -const token = "ddo_u7mo08lBNHm8GMGLhtrEVfcgBsCuSp36dumX"; - -const res = await fetch( - `https://api.deno.com/v1/organizations/${organizationId}/projects`, - { - method: "GET", - headers: { - Authorization: `Bearer ${token}`, - }, - }, -); - -const response = await res.json(); -console.log(response); -``` ## OpenAPI specification and tooling diff --git a/subhosting/manual/acceptable_use_policy.md b/subhosting/manual/acceptable_use_policy.md new file mode 100644 index 00000000..bb2dbf17 --- /dev/null +++ b/subhosting/manual/acceptable_use_policy.md @@ -0,0 +1,30 @@ +# Acceptable use policy + +The Deno Subhosting service includes resources (CPU time, request counts) that +are subject to this Acceptable Use policy. This document can give a rough +estimate to what we consider as "Acceptable Use", and what we do not. + +### Examples of Acceptable Use + +- ✅ Server-side rendered websites +- ✅ Jamstack sites and apps +- ✅ Single page applications +- ✅ APIs that query a DB or external API +- ✅ A personal blog +- ✅ A company website +- ✅ An e-commerce site + +### Not Acceptable Use + +- ❌ Crypto mining +- ❌ Highly CPU-intensive load (e.g. machine learning) +- ❌ Media hosting for external sites +- ❌ Scrapers +- ❌ Proxy or VPN + +## Guidelines + +We expect most projects to fall well within the usage limits. We will notify you +if your projects usage significantly deviates from the norm. We will reach out +to you where possible before taking any action to address unreasonable burdens +on our infrastructure. diff --git a/subhosting/manual/domains.md b/subhosting/manual/domains.md deleted file mode 100644 index de1ad08d..00000000 --- a/subhosting/manual/domains.md +++ /dev/null @@ -1,6 +0,0 @@ -# Working with custom domains - -TODO - talk about provisioning domains and associating them with deployments. - -For now, reference: -https://github.com/denoland/deploy-api/blob/main/samples.ipynb diff --git a/subhosting/manual/index.md b/subhosting/manual/index.md index f51aea61..2c80761d 100644 --- a/subhosting/manual/index.md +++ b/subhosting/manual/index.md @@ -1,105 +1,65 @@ # About Subhosting -A powerful use case for Deno Deploy is using our isolate cloud to run untrusted -code on behalf of your end users. There are a number of scenarios where you -might be interested in doing this: - -- You are a SaaS provider that wants to empower your customers to extend your - platform with custom code -- You are an infrastructure provider that would like to enable your customers to - run Deno-powered edge functions -- You are building a browser-based editor for user code (possibly for - education), and you'd like a place to execute that code in a controlled and - secure way - -In cases like these, you might consider using Deno Deploy's full-featured -[REST API](../api/index.md) to implement -[**subhosting**](https://deno.com/subhosting). "Subhosting" is what we call the -scenario where you use Deno Deploy to run your users' untrusted code in a secure -and scalable environment designed for -[multitenancy](https://www.ibm.com/topics/multi-tenant). - -## Quick start example - -Looking for the smallest possible example that shows how to deploy code to -Deno's isolate cloud? We've got you covered below. Once you've skimmed over it, -you can read on for more details about subhosting. - -```ts -// 1.) Get API access info ready -const accessToken = Deno.env.get("DEPLOY_ACCESS_TOKEN"); -const orgId = Deno.env.get("DEPLOY_ORG_ID"); -const API = "https://api.deno.com/v1"; -const headers = { - Authorization: `Bearer ${accessToken}`, - "Content-Type": "application/json", -}; - -// 2.) Create a new project -const pr = await fetch(`${API}/organizations/${orgId}/projects`, { - method: "POST", - headers, - body: JSON.stringify({ - name: null, // randomly generates project name - }), -}); -const project = await pr.json(); - -// 3.) Deploy a "hello world" server to the new project -const dr = await fetch(`${API}/projects/${project.id}/deployments`, { - method: "POST", - headers, - body: JSON.stringify({ - entryPointUrl: "main.ts", - assets: { - "main.ts": { - "kind": "file", - "content": `Deno.serve(() => new Response("Hello, World!"));`, - "encoding": "utf-8", - }, - }, - envVars: {}, - }), -}); -console.log(dr.status); -``` - -## How subhosting works - -To build subhosting with Deno Deploy, it helps to understand some key resources -within the system. These resources are also represented in the -[REST API](../api/index.md). - -![overview of subhosting resources](./subhosting-org-structure.svg) - -- [**Organizations**](https://apidocs.deno.com/#get-/organizations/-organizationId-): - Organizations are a container for all data related to a subhosting - implementation. Other Deploy users can be invited to collaborate on an - organization, and [access tokens](https://dash.deno.com/account#access-tokens) - can give developers with organization access the ability to modify resources - within the org via API. New organizations can be created in the - [Deploy dashboard](https://dash.deno.com/orgs/new). -- [**Projects**](https://apidocs.deno.com/#get-/organizations/-organizationId-/projects): - a project is a container for **deployments**, and the analytics and usage - information for all deployments within a project. -- [**Deployments**](https://apidocs.deno.com/#get-/projects/-projectId-/deployments): - a deployment is a set of configuration, runnable code, and supporting static - files that can run on an isolate in Deno Deploy. Deployments have an entry - file that can launch a server, can have a [Deno KV](/deploy/kv/manual) - database associated with them, and can be set up to run on custom domains. -- [**Domains**](https://apidocs.deno.com/#get-/organizations/-organizationId-/domains): - custom domains that can be associated with deployments, giving them a unique - URL. +Deno Subhosting is a robust platform designed to allow Software as a Service +(SaaS) providers to securely run code written by their customers. The Subhosting +API allows you to deploy untrusted code programmatically and at scale. + +## Key Features + +- **Ease of Use:** Developers can write code in generic JavaScript or TypeScript + without needing specific knowledge of Deno. +- **Standards Compliance:** Deno supports standard JavaScript and TypeScript and + integrates widely-used web APIs like `fetch` and `web cache`. +- **Deno-Specific Advanced Features:** Offers advanced features like `KV` + (Key-Value stores) which extend beyond typical browser capabilities. +- **Rapid Deployment:** Deno’s cloud products are designed to support extremely + short deployment times that range from less than a second for simple + applications, to around ten seconds for complex websites with numerous + dependencies. +- **Improved developer experience**: Subhosting will manage the extensive effort + of setting up secure infrastructure to run untrusted code in a public cloud + for you. + +## Overview of Deno Cloud Offerings - Deno Deploy and Deno Subhosting + +Deno provides two distinct cloud offerings, Deno Deploy and Deno Subhosting, +each designed to support specific use cases while leveraging the same underlying +infrastructure. + +### Deno Deploy + +Deno Deploy is optimized for individual developers and small teams focused on +developing and iterating on a limited set of first-party projects. This solution +is ideal for hosting websites or applications, with deployment processes +typically managed through GitHub integrations. + +- Target Audience: Individual developers and small development teams. +- Deployment Integration: Primarily through GitHub for continuous integration + and delivery. +- Use Cases: Hosting websites and applications. + +### Deno Subhosting + +In contrast, Deno Subhosting is engineered to securely manage a larger volume of +projects and deployments. It supports the deployment of untrusted code or +functions through an API, making it suitable for scenarios involving multiple +end-users contributing code. + +- Target Audience: SaaS platforms requiring the capability to host + customer-generated, untrusted code securely. +- Deployment Mechanism: Through a robust API designed for scalability and + security. +- Use Cases: Large scale project hosting where end-users contribute the code. The steps to implement subhosting are roughly as follows: -1. [Create an organization](./getting_started.md) and get an access token for - the REST API -1. [Create a project](./projects_and_deployments.md), and then create your first - deployment for that project +1. [Create an organization](./quick_start.md) and get an access token for the + REST API +1. [Create a project](./planning_your_implementation.md), and then create your + first deployment for that project Using these techniques, you can package up user code as "deployments", and -execute that code on a Deno-provisioned URL or a custom URL you can configure +execute that code on a Deno-provisioned URL or a [custom URL](../api/#custom-domains) you can configure yourself. ## REST API reference and OpenAPI spec diff --git a/subhosting/manual/projects_and_deployments.md b/subhosting/manual/planning_your_implementation.md similarity index 82% rename from subhosting/manual/projects_and_deployments.md rename to subhosting/manual/planning_your_implementation.md index 1262d198..36934317 100644 --- a/subhosting/manual/projects_and_deployments.md +++ b/subhosting/manual/planning_your_implementation.md @@ -1,17 +1,8 @@ -# Projects and deployments +# Planning your implementation -In the [domain model for subhosting](./index.md), a **project** is a container -for **deployments**. You can track aggregate analytics for a project (like how -many requests are being processed, KV database usage, etc). But actual code that -runs and serves requests is contained in a **deployment**. Depending on the data -model for your application, you might choose to map projects and deployments in -different ways. - -## Planning your implementation - -For example - let's say that you were building a SaaS CRM platform like -Salesforce, and you wanted to empower your customers to write JavaScript code -that would be executed every time a new lead was captured. +Let's say, for example, that you are building a SaaS CRM platform like +Salesforce. You want to empower your customers to write JavaScript code that +would be executed every time a new lead was captured. If you were going to implement this feature using Deno Deploy, here's how you might think about building it: @@ -35,8 +26,8 @@ Let's look at an example of the API endpoint required to make this happen. ## Creating a deployment for a project -In the [previous chapter](./getting_started.md), you created a new project and -noted its `id` property. In the example in the previous chapter, the ID was: +In the [previous chapter](./quick_start.md), you created a new project and noted +its `id` property. In the example in the previous chapter, the ID was: ```console f084712a-b23b-4aba-accc-3c2de0bfa26a diff --git a/subhosting/manual/pricing_and_limits.md b/subhosting/manual/pricing_and_limits.md new file mode 100644 index 00000000..74774ac3 --- /dev/null +++ b/subhosting/manual/pricing_and_limits.md @@ -0,0 +1,28 @@ +# Pricing and Limits + +## Deployment size + +Deployments should be less than 1GB across all source code and assets in +aggregate, per deployment. + +## Deployment frequency + +The maximum number of deployments per hour that a subhosting user can make is +either 60 (on the free tier) or 300 (on the builder tier). Higher limits are +available for organizations on the enterprise plan. + +## CPU time per request + +- 50ms or 200ms, depending on tier. +- CPU time limit per request is limited on the average across many requests. It + is not strictly enforced on a per-request basis. +- Does not include time that a deployment is waiting for I/O (e.g. while waiting + for the remote server while making a fetch() request) + +## Blocking the event loop + +Programs should not block the event loop for more than 1s. + +## Available memory + +512MB max memory is available. diff --git a/subhosting/manual/getting_started.md b/subhosting/manual/quick_start.md similarity index 74% rename from subhosting/manual/getting_started.md rename to subhosting/manual/quick_start.md index c4fc5a54..cd446ef9 100644 --- a/subhosting/manual/getting_started.md +++ b/subhosting/manual/quick_start.md @@ -1,4 +1,51 @@ -# Getting started with subhosting +# Subhosting Quick Start + +Looking for the smallest possible example that shows how to deploy code to +Deno's isolate cloud? We've got you covered below, or you can skip to the +[more detailed getting started guide](#getting_started). + +```ts +// 1.) Get API access info ready +const accessToken = Deno.env.get("DEPLOY_ACCESS_TOKEN"); +const orgId = Deno.env.get("DEPLOY_ORG_ID"); +const API = "https://api.deno.com/v1"; +const headers = { + Authorization: `Bearer ${accessToken}`, + "Content-Type": "application/json", +}; + +// 2.) Create a new project +const pr = await fetch(`${API}/organizations/${orgId}/projects`, { + method: "POST", + headers, + body: JSON.stringify({ + name: null, // randomly generates project name + }), +}); +const project = await pr.json(); + +// 3.) Deploy a "hello world" server to the new project +const dr = await fetch(`${API}/projects/${project.id}/deployments`, { + method: "POST", + headers, + body: JSON.stringify({ + entryPointUrl: "main.ts", + assets: { + "main.ts": { + "kind": "file", + "content": `Deno.serve(() => new Response("Hello, World!"));`, + "encoding": "utf-8", + }, + }, + envVars: {}, + }), +}); +console.log(dr.status); +``` + + + +## Getting started with subhosting To get started with subhosting, you will need to create an organization in the [Deno Deploy dashboard](https://dash.deno.com/orgs/new). Follow the on-screen @@ -6,7 +53,7 @@ instructions to create a new organization for subhosting. Going through the onboarding flow, you will likely also generate an **access token**, which you will use to access the [REST API](../api/index.md). If you -didn't do this (or lost the token you generated), you can +didn't do this (or your token has expired), you can [generate a new one here](https://dash.deno.com/account#access-tokens). :::caution Save your token in a safe place @@ -118,4 +165,4 @@ Note the `id` of the project that was returned with this repsonse - this is the project ID we'll use in the next step. Now that we have REST API access configured and a project set up, we can move on -to [creating our first deployment](./projects_and_deployments). +to [creating our first deployment](./planning_your_implementation).