Deno Deploy の実行環境を紐解いてみた

# はじめに

[Ateam Lifestyle Inc. Advent Calendar 2021](https://qiita.com/advent-calendar/2021/ateam-lifestyle)　5日目は、エイチームライフスタイル CTO室 室長の @tsutorm がお送りします。

[DenoのAdvent Calendar](https://qiita.com/advent-calendar/2021/deno) もあるので、この内容ならそっちに投下するべきだったんじゃないかと内心思いながらお送りします:innocent:

# Deno Deployとは

簡単に言うと、DenoのコードがEdgeでシュッと動く[Cloudflare Workers](https://workers.cloudflare.com/)みたいなやつです。
[Deno Deploy](https://deno.com/deploy/docs)の詳しい説明は色々な皆さんがされてるので、こちらを御覧ください。

- [新しい CDN Edge Worker, Deno Deploy について](https://zenn.dev/mizchi/scraps/8e09ff87540a40)
- [Deno Deployをやってみた](https://qiita.com/access3151fq/items/582c5f10fa9910bd4e0c)
- [Deno Deploy Beta 3が来たぞ](https://zenn.dev/kawarimidoll/articles/b8128d11223bf6)

Githubにリポジトリがなくても、[playground](https://deno.com/blog/deploy-beta3#playgrounds)でシュッと試せるので、Githubアカウントある方はぜひ触ってみてください。

# Deno Deployって中身どうなってんだ？:thinking:

説明資料にもあるようにエッジサーバー上で動作する V8 ランタイムプロセス内のisolateで動作してるのはわかるんですが、もうちょっと具体的にどうなってんの？ってところに興味があり調べてみました。

## GCEで動作しているっぽい

Projectを立ち上げると `xxxxx-yyyyyy-NN.deno.dev` みたいなURLが発行されます。このドメインから引けるAレコードの管理ドメインを見てみるとGoogle/GCPの管理となってました

```shell-session
$ dig xxxxx-yyyyyy-NN.deno.dev
# 略
;; ANSWER SECTION:
xxxxx-yyyyyy-NN.deno.dev. 54 IN      A       34.120.54.XX
# 略

$ whois 34.120.54.XX
NetRange:       34.64.0.0 - 34.127.255.255
CIDR:           34.64.0.0/10
NetName:        GOOGL-2
NetHandle:      NET-34-64-0-0-1
Parent:         NET34 (NET-34-0-0-0-0)
NetType:        Direct Allocation
OriginAS:       
Organization:   Google LLC (GOOGL-2)
RegDate:        2018-09-28
Updated:        2018-09-28
Ref:            https://rdap.arin.net/registry/ip/34.64.0.0



OrgName:        Google LLC
OrgId:          GOOGL-2
Address:        1600 Amphitheatre Parkway
City:           Mountain View
StateProv:      CA
PostalCode:     94043
Country:        US
RegDate:        2006-09-29
Updated:        2019-11-01
Comment:        *** The IP addresses under this Org-ID are in use by Google Cloud customers *** 
# 略
```

Deno Deployの[Regionドキュメントに記載のリージョン名](https://deno.com/deploy/docs/regions)と[GCPのリージョン名](https://cloud.google.com/about/locations#asia-pacific)が同じだし、GCP上で動作してるみたいですね。

GCPだとして、なんのサービスで動作してるのか。うーん。tracerouteしてみたらなんかわかるかな

```shell-session
$ traceroute 34.120.54.XX
# 略
10  XX.54.120.34.bc.googleusercontent.com (34.120.54.XX)  13.370 ms  13.211 ms  13.072 ms
```

bc.googleusercontent.com は[ComputeEngineの外部IP](https://groups.google.com/g/google-appengine/c/7a4VapNerGg/m/rhPdW0uZAgAJ)とあるので、GCEみたいですね。

エイチームライフスタイルは名古屋に本社があり、私のエッジロケーションとして大阪リージョンのGCEに向いている模様。

GCE大阪リージョンってEdgeか?というとちょっとEdgeじゃない気もしますけど、まだ本稿執筆時点ではbeta3ですしね。

## インスタンスの詳細は全くわかりませんでした

この辺はDeno DeployのSandboxがしっかりしてました。

V8 Isolateで起動しているとすると、Isolateは1つのインスタンススペックを共有していると想定されます。

一応[Pricing & Limits](https://deno.com/deploy/docs/pricing-and-limits)ではメモリが512MB, CPUは50ms/1req(短い!)となってます。

[Denoの標準API](https://doc.deno.land/deno/stable/~/Deno)とかから読み取れる情報からなにか見えるものがあるかもしれないと思い、こんなコードを Playgroundで実行してみました。

```typescript
import { serve } from "https://deno.land/std@0.114.0/http/server.ts";
import { exec, OutputMode } from "https://deno.land/x/exec/mod.ts";

function getNumOfCores(): number {
  try {
    return navigator.hardwareConcurrency;
  } catch (e) {
    console.log(e);
    return NaN;
  }
}

function getMemoryUsages(): Deno.MemoryUsage | null {
  try {
    return Deno.memoryUsage()
  } catch (e) {
    console.log(e);
    return null;
  }
}

async function showRoot(): Promise<string> {
    try {
        let response = await exec('ls -la / ', {output: OutputMode.Capture});
        return response.output
    } catch (e) {
        console.log(e)
        return e.message
    }
}

async function handler(_: Request): Promise<Response> {
  try {
    return new Response(`
build is ${JSON.stringify(Deno.build)}
env is ${JSON.stringify(Deno.env.toObject())}
cwd is ${Deno.cwd()}
numOfCores is ${getNumOfCores()}
memoryUsage is ${JSON.stringify(getMemoryUsages())}
showRoot is ${await showRoot()}
`);
  } catch(e) {
    console.log(e)
    return new Response(`oops. error ${e}`);
  }
}

console.log("Listening on http://localhost:8000");
serve(handler, {addr: ":8000"})
```

結果はこんな感じ

```text
build is {"target":"x86_64-unknown-linux-gnu","arch":"x86_64","os":"linux","vendor":"unknown","env":"gnu"}
env is {"DENO_DEPLOYMENT_ID":"94955XXX","DENO_REGION":"asia-northeast1"}
cwd is /src
numOfCores is NaN
memoryUsage is null
showRoot is Deno.run is not a function
```

びっくりするほど何も情報が得られませんでした。

メモリ利用の状況が見えないですね。
制限の512MB中どの程度利用しているのかの情報がダッシュボードなどで見えるといいんですけど・・・

Denoには[permission](https://deno.land/manual/getting_started/permissions)があり、こいつが機能しているのかな？と思ったんですが、`Deno.run`がパーミッションエラーではなく、`not a function`であること、`navigator`もコンソールに表示されたエラーでは`ReferenceError: navigator is not defined`となってたので、通常のDenoランタイムとは完全に別のDeno Deploy用にビルドされたランタイムで動作してるみたいです。

## LimitsのCPUTime 50ms/reqはちゃんとCPUTimeの制限なの？

これLimitみてて疑問だったやつです。一応CPUTimeと明記されてるんでIOによる待ちはノーカンだと思うんですが、、、実験してみましょう。

```typescript
import { serve } from "https://deno.land/std@0.114.0/http/server.ts";
import { sleep } from "https://deno.land/x/sleep/mod.ts";

async function handler(req: Request): Response {
  await sleep(1);
  return new Response("1sec sleep Hello world!!!!!!!");
}

console.log("Listening on http://localhost:8000");
await serve(handler);
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/76630/048a4dd0-ad06-5fb3-0811-e6bb3a563cf0.png)

ちゃんとレスポンスしますね。トータルタイムではなくCPUTimeでの制限なんで演算以外による待ち時間はノーカンのようです。

# まとめ

- Beta3 時点でDeno DeployはGCP(GCE)で動いてるみたい
- インスタンスレベルの情報は何もわからない
    - どうもDeno Deploy用のランタイムで動いてるっぽい

Deno Deploy 引き続き色々と遊べそうなので触っていきたいと思います :smile: 

# おわりに

明日は @odn_chi がなんか書くそうです！初Qiita投稿っぽいので私も楽しみです :eyes: