emahiro/b.log

Drastically Repeat Yourself !!!!

Deno on Cloud Run

Overview

Deno を CloudRun で動作させるまでをまとめました。

How to get started

インストール手順 に則って Deno で簡単な Web サーバーを起動します。

Install Deno

Mac では brew が使えるらしいのでとりあえず brew を使って deno を入れます。

$ brew install deno
$ deno --version
deno 1.0.2
v8 8.4.300
typescript 3.9.2

そしてドキュメントにも記載されてる通り簡単な動作確認は以下

$ deno run https://deno.land/std/examples/welcome.ts
Download https://deno.land/std/examples/welcome.ts
Warning Implicitly using master branch https://deno.land/std/examples/welcome.ts
Compile https://deno.land/std/examples/welcome.ts
Welcome to Deno 🦕

Sample web server

次に簡単な Web サーバーを立ち上げて見ます。

Deno で Web server を立ち上げるためには直で https://deno.land/std@0.53.0/http/server.ts を import して使うのが簡単のようです。import に https://deno.land/... のフォーマットで書いておけば、実行時に依存関係を取得できます。

お試しで動かしたいケースにおいては最適ですね。

Go みたいに自動的に取得してくれたりしないのかな。。。

import { serve } from "https://deno.land/std@0.53.0/http/server.ts";

const port = 8080;
const s = serve({ port: port });
console.log("Starting server port: ", port);
for await (const req of s) {
    req.respond({ body: "Hello World\n" });
}

このコードを書いた後 Deno を起動する。

$ deno run --allow-net ./main.ts
Download https://deno.land/std@0.53.0/http/server.ts
Download https://deno.land/std@0.53.0/encoding/utf8.ts
Download https://deno.land/std@0.53.0/io/bufio.ts
Download https://deno.land/std@0.53.0/testing/asserts.ts
Download https://deno.land/std@0.53.0/async/mod.ts
Download https://deno.land/std@0.53.0/http/_io.ts
Download https://deno.land/std@0.53.0/async/deferred.ts
Download https://deno.land/std@0.53.0/async/delay.ts
Download https://deno.land/std@0.53.0/async/mux_async_iterator.ts
Download https://deno.land/std@0.53.0/textproto/mod.ts
Download https://deno.land/std@0.53.0/http/http_status.ts
Download https://deno.land/std@0.53.0/io/util.ts
Download https://deno.land/std@0.53.0/fmt/colors.ts
Download https://deno.land/std@0.53.0/testing/diff.ts
Download https://deno.land/std@0.53.0/bytes/mod.ts
Download https://deno.land/std@0.53.0/path/mod.ts
Download https://deno.land/std@0.53.0/path/win32.ts
Download https://deno.land/std@0.53.0/path/posix.ts
Download https://deno.land/std@0.53.0/path/common.ts
Download https://deno.land/std@0.53.0/path/separator.ts
Download https://deno.land/std@0.53.0/path/interface.ts
Download https://deno.land/std@0.53.0/path/glob.ts
Download https://deno.land/std@0.53.0/path/_constants.ts
Download https://deno.land/std@0.53.0/path/_util.ts
Download https://deno.land/std@0.53.0/path/_globrex.ts
Compile file:///$pathToDir/myFirstDeno/main.ts
Starting server port:  8080

$ curl localhost:8080
Hello World # console.log で指定した内容が出力されます。

import で https://deno.land/std@0.53.0/http/server.ts のようにバージョンを指定して import する方法が少し気になったので調べてみます。

Deno の serve のドキュメントを読むと以下のようになっています。

/**
 * Create a HTTP server
 *
 *     import { serve } from "https://deno.land/std/http/server.ts";
 *     const body = "Hello World\n";
 *     const s = serve({ port: 8000 });
 *     for await (const req of s) {
 *       req.respond({ body });
 *     }
 */

https://deno.land/std/http/server.ts というバージョンなし import で依存を解決してます。

試しに標準の http モジュールを使って実行してみました。

import serve from "https://deno.land/std/http/server.ts"

に書き換えただけです。実行結果は以下。

$ deno run --allow-net main.ts
Download https://deno.land/std/http/server.ts
Warning Implicitly using master branch https://deno.land/std/http/server.ts
Download https://deno.land/std/encoding/utf8.ts
Download https://deno.land/std/io/bufio.ts
Download https://deno.land/std/testing/asserts.ts
Download https://deno.land/std/async/mod.ts
Download https://deno.land/std/http/_io.ts
Warning Implicitly using master branch https://deno.land/std/testing/asserts.ts

#略 

Warning Implicitly using master branch という警告が出るようになってしまいました。

これは一体どういうことなのだろう?標準ライブラリでもバージョニングをいれることが推奨されているのかもしれないですが、ちょっとまだお作法がよくわかっていません。

もしかして暗黙的に master を使っていると master はよく変更が加わるもので、何かのアップデートがあった時にコードが壊れてしまう可能性があるから暗黙的に master の標準ライブラリを使用するのは避けるべきなのかもしれません、とか考えてたら書いてありました。

Denoでは、バージョン管理も簡単、importしているURLに@^${バージョン番号}を追加するだけです。

qiita.com

ファイルレベルでバージョン管理されてるのは確かに良さそうです。
この辺ルールを決めないと自由度上がりすぎてプロジェクト全体で特定バージョンを使いたいユースケースに対応し切れないですが、そういうことを嫌った結果なのかもしれませんね。知らんけど。
(...node_modules はデカイしいやだよね)

また、別にdeps.tsというファイルを用意し、そこでバージョンを一括管理することもできます。

deps.ts なんてものもあるんですね。これは別の機会に調べてみようと思います。

VSCode plugin

Deno の VSCodeプラグインがすでに登場してました。Install extentions で検索するとわかりますが、いくつか Deno 関連のプラグインが出てきます。

僕は現時点(20200527) で公式の以下を使ってみることにしました。

marketplace.visualstudio.com

Configuration に記載されてる設定の property を Setting.json に追加します。

// deno
"deno.enable": true,
"deno.alwaysShowStatus": true,
"deno.importmap": null,
"deno.autoFmtOnSave": "", //未実装なのでなし

Node Modules

最初にサーバーを起動した時に Download... と表示されたように deno は import に宣言しておけば、local に存在しない依存は実行時に自動で取得してくれるっぽいです。
(なんとなく Go Modules みたいだなと感じました。)

node のエコシステムは deno には必要ないんですね。
(感動)

Working on docker

Deno の動作をローカルで確認したところで次に Docker で Deno を動かします。

Deno の公式の Dokcer イメージは以下です。

https://github.com/hayd/deno-docker

Build & Run

Dockerfile を用意します。

FROM hayd/alpine-deno:1.0.2

EXPOSE 1993 # The port my application listen to.

WORKDIR /app 

USER deno

COPY deps.ts .
RUN deno cache deps.ts

COPY . .

RUN deno cache main.ts

CMD ["run", "--allow-net", "main.ts"]
$ docker build -t emahiro-deno .
Sending build context to Docker daemon  8.192kB
Step 1/9 : FROM hayd/alpine-deno:1.0.2
1.0.2: Pulling from hayd/alpine-deno
c9b1b535fdd9: Already exists
052c7836b622: Pull complete
9460a82e0a88: Pull complete
eef61d161c0b: Pull complete
Digest: sha256:1a759550e5cc76980f5ebc3a599c79e6fc6e5cc34827083edd1225a25ac4dd12
Status: Downloaded newer image for hayd/alpine-deno:1.0.2
 ---> 8f192534bc9d
Step 2/9 : EXPOSE 8080
 ---> Running in 13d038204325
Removing intermediate container 13d038204325
 ---> 31e5525dd8a6
Step 3/9 : WORKDIR /app
 ---> Running in 7f5d89735bd2
Removing intermediate container 7f5d89735bd2
 ---> b9b01c114460
Step 4/9 : USER deno
 ---> Running in 90aea4eca3b0
Removing intermediate container 90aea4eca3b0
 ---> 9bba107b8b99
Step 5/9 : COPY deps.ts .
 ---> a05bfbd4d8a7
Step 6/9 : RUN deno cache deps.ts
 ---> Running in 24022494bfd8
Compile file:///app/deps.ts
Removing intermediate container 24022494bfd8
 ---> c4517e93e4d6
Step 7/9 : COPY . .
 ---> c03cb478f6df
Step 8/9 : RUN deno cache main.ts
 ---> Running in 8df5fad63cbd
Download https://deno.land/std@0.53.0/http/server.ts
Download https://deno.land/std@0.53.0/encoding/utf8.ts
Download https://deno.land/std@0.53.0/io/bufio.ts
Download https://deno.land/std@0.53.0/testing/asserts.ts
Download https://deno.land/std@0.53.0/async/mod.ts
Download https://deno.land/std@0.53.0/http/_io.ts
Download https://deno.land/std@0.53.0/textproto/mod.ts
Download https://deno.land/std@0.53.0/http/http_status.ts
Download https://deno.land/std@0.53.0/io/util.ts
Download https://deno.land/std@0.53.0/fmt/colors.ts
Download https://deno.land/std@0.53.0/testing/diff.ts
Download https://deno.land/std@0.53.0/async/deferred.ts
Download https://deno.land/std@0.53.0/async/delay.ts
Download https://deno.land/std@0.53.0/async/mux_async_iterator.ts
Download https://deno.land/std@0.53.0/path/mod.ts
Download https://deno.land/std@0.53.0/bytes/mod.ts
Download https://deno.land/std@0.53.0/path/win32.ts
Download https://deno.land/std@0.53.0/path/posix.ts
Download https://deno.land/std@0.53.0/path/common.ts
Download https://deno.land/std@0.53.0/path/separator.ts
Download https://deno.land/std@0.53.0/path/interface.ts
Download https://deno.land/std@0.53.0/path/glob.ts
Download https://deno.land/std@0.53.0/path/_globrex.ts
Download https://deno.land/std@0.53.0/path/_constants.ts
Download https://deno.land/std@0.53.0/path/_util.ts
Compile file:///app/main.ts
Removing intermediate container 8df5fad63cbd
 ---> 7c68bae2e695
Step 9/9 : CMD ["run", "--allow-net", "main.ts"]
 ---> Running in 8b34e2020b18
Removing intermediate container 8b34e2020b18
 ---> 8d26b2c23903
Successfully built 8d26b2c23903
Successfully tagged emahiro-deno:latest
$ docker run --name deno-app -d -it --rm -p 8080:8080 emahiro-deno
{$ContainerID}
$ docker ps -a
CONTAINER ID        IMAGE               COMMAND                  CREATED              STATUS              PORTS                    NAMES
7651ddde92f8        emahiro-deno        "deno run --allow-ne…"   About a minute ago   Up About a minute   0.0.0.0:1993->1993/tcp   deno-app

コンテナが起動した状態で curl でHTTPリクエストを送ってみます。

$ curl localhost:8080
Hello World

Docker を使ってローカルでサーバーを起動させることができました。

Deploy to Cloud Run

Cloud Run にデプロイしてみます。

デプロイ手順は こちら

Regionの指定

Cloud Run のリージョンは既に東京があるので東京( asia-northeast1 ) を使用します。これは gcloud run deploy 時に --region フラグで指定しもいいし、 gcloud コマンドの設定を追加しても大丈夫です。

ref: https://cloud.google.com/run/docs/locations?hl=ja

# gcloud の設定を確認
$ gcloud config list

# 東京リージョンの設定
$ gcloud config set run/region asia-northeast1

ref: gcloud config コマンドのリファレンス

Setting Cloud Build

Cloud Run を使うには Cloud Build を有効にする必要があります。

Cloud Build, Cloud Run, Container Registry, and Resource Manager API を有効にします。

ref: Cloud Run へのデプロイ#始める前に

ビルド済みの既存のイメージからコンテナを作成しない場合は Container Registry は必要ありません。

Cloud Build は API を有効にしたのち Cloud Build を使うサービスに 権限 を付与しないといけないので Cloud Build > 設定 で Cloud Run 管理者を有効にします。Cloud Run を有効にすると追加でサービスアカウントへの権限付与も求められるので権限を付与します。

最終的には以下のようになります。

Deploy

コンテナを Cloud Registry に登録

$ gcloud builds submit --tag gcr.io/$PROJECT_NAME/emahiro-deno:latest

Deploy to Cloud Run

gcloud run deploy hello-deno --image gcr.io/$PROJECT_NAME/emahiro-deno --region asia-northeast1 --platform managed --allow-unauthenticated 
Deploying container to Cloud Run service [hello-deno] in project [$PROJECT_NAME] region [asia-northeast1]
✓ Deploying new service... Done.
  ✓ Creating Revision...
  ✓ Routing traffic...
  ✓ Setting IAM Policy...
Done.
Service [hello-deno] revision [hello-deno-00001-geh] has been deployed and is serving 100 percent of traffic at https://hello-deno-$HASH.a.run.app

--platform : 実行環境のPFを指定する。 managed or gke or kubernetes が入ります。基本的には managed で良いです。(ただし region の option が必須。gcloud config set run/region していない場合は)

--allow-unauthenticated : 認証付きリクエストにするかどうか。認証必須の場合は --no-allow-unauthenticated になります。

ref: gcloud run deploy のリファレンス

その他

price

気になったので価格表だけ久しぶりに調べました。まぁ遊ぶくらいなら無料枠で余裕かなと思います。

Cloud Build

Cloud Run