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


はじめに

Ateam Lifestyle Inc. Advent Calendar 2021 5日目は、エイチームライフスタイル CTO室 室長の @tsutorm がお送りします。

DenoのAdvent Calendar もあるので、この内容ならそっちに投下するべきだったんじゃないかと内心思いながらお送りします

Deno Deployとは

簡単に言うと、DenoのコードがEdgeでシュッと動くCloudflare Workersみたいなやつです。
Deno Deployの詳しい説明は色々な皆さんがされてるので、こちらを御覧ください。

Githubにリポジトリがなくても、playgroundでシュッと試せるので、Githubアカウントある方はぜひ触ってみてください。

Deno Deployって中身どうなってんだ?

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

GCEで動作しているっぽい

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

$ 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ドキュメントに記載のリージョン名GCPのリージョン名が同じだし、GCP上で動作してるみたいですね。

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

$ 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とあるので、GCEみたいですね。

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

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

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

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

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

一応Pricing & Limitsではメモリが512MB, CPUは50ms/1req(短い!)となってます。

Denoの標準APIとかから読み取れる情報からなにか見えるものがあるかもしれないと思い、こんなコードを Playgroundで実行してみました。

import { serve } from "https://deno.land/[email protected]/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"})

結果はこんな感じ

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があり、こいつが機能しているのかな?と思ったんですが、Deno.runがパーミッションエラーではなく、not a functionであること、navigatorもコンソールに表示されたエラーではReferenceError: navigator is not definedとなってたので、通常のDenoランタイムとは完全に別のDeno Deploy用にビルドされたランタイムで動作してるみたいです。

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

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

import { serve } from "https://deno.land/[email protected]/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);

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

まとめ

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

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

おわりに

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