CloudFunctionsアプリをDevContainerでさくっと開発する

クラウドコンピューティング、とりわけサーバーレス環境は
周りのめんどくさい事に煩わされずに「提供するモノの中身に注力できる」という点でより素早く、品質の良いサービスを提供できるシカケでもあります。

本稿では、開発環境でも「より中身に注力」するためにさくっと環境を立ち上げてデプロイする事について触れようと思います。

##TL;DR
- VisualStudioCodeのDevContainerでコンテナ内に開発環境を作る  
- ローカルでCloudFunctionsを実行する  
- 開発環境からCloudへデプロイする  

##想定環境  
- Windows10
- GoogleCloud(CloudFunctions)
- node.js
- VisualStudioCode

##ローカルマシンにインストールするのはふたつ  
クラウドのアプリケーション開発に携わる方にとって、同時に複数のサービスを開発したりメンテナンスする必要に迫られる事はありませんか？

それぞれのアプリケーションが違うバージョンのフレームワークやプラグインを使っていたり、そもそも稼働するクラウドやリポジトリが違ったりしてそれらの切り替え（アタマの切り替えも含めて）が煩わしかったり間違えたりすることは出来るだけ避けたいものです。

その為に、
個々の開発環境はコンテナの中に閉じ込めましょう。

ローカルマシンにインストールするのは、
  ・  [DockerDesktop](https://www.docker.com/products/docker-desktop)
  ・  [VisualStudioCode](https://azure.microsoft.com/ja-jp/products/visual-studio-code/)＋[DevContainer拡張機能](https://code.visualstudio.com/docs/remote/containers)
の、二つだけです。

##node.jsを使ったCloudFunctions開発環境をさくっと作ります
###node.js開発コンテナを作ります
今回はWindowsでの操作を例示しますが、Macではキーやコマンドがやや違います。

####ローカルマシンに開発用フォルダを作ってそこに移動します。
```winbatch
> mkdir myFirstFunction
> cd myFirstFunction
```

####そこでVisualStudioCode（以下VSCode）を立ち上げます。
```winbatch
> code
```

VSCodeが立ち上がったらコンテナの設定をします。
Shift+Ctrl+Pでメニューを開いて、`open container`と入力して、フィルタされた選択肢の中から「Open Folder in Container...」を選択、Enterを押します。
![スクリーンショット 2021-12-02 105037.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/49021/204f46a5-5e4d-75da-2c40-322af233d109.png)

今回はnode.js 14のコンテナで開発しましょう。
![スクリーンショット 2021-12-02 105229.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/49021/029c9181-4884-bd2c-e94c-96b050b7c3ea.png)
![スクリーンショット 2021-12-02 105304.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/49021/134fee5a-d5ee-34a1-076c-32903e062335.png)

あとはデフォルトでOKです。

ネットワーク帯域等の条件により異なりますが、数分程度でコンテナの作成が終わると思います。
そうすると、自動でターミナルが表示されます。
![スクリーンショット 2021-12-02 110212.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/49021/9ff757a4-4415-1b70-052b-81cc9df9754f.png)

###さぁ、開発を始めます  
まず、node.jsを初期化しましょう。
ここからはVSCode(DevContainer)のターミナルでの作業になります。  

```bash
node ➜ /workspaces/myFirstFunction $ npm init
```
いくつかプロンプトで聞かれますが、特にこだわりがなければすべてデフォルト（Enter）で構いません。

package.jsonが出来上がりました。  

```json:package.json
{
  "name": "myfirstfunction",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC"
}
```


それではアプリケーションを作りこみます。
まずはシンプルなWebサービスです。
index.jsファイルを作りましょう。

```javascript:index.js
exports.myFirstFunction = (req, res) => {
  const name = req.query.name || req.body.name || 'World';

  res.send(`Hello, ${name}!`);
}
```
###ローカルで動作確認します  
これをローカルで実行するために、
@google-cloud/functions-frameworkをインストールします。

```bash
$ npm install --save-dev @google-cloud/functions-framework
```
package.json のdevDependenciesに追加されていることが分かります。

```json:package.json(抜粋)
  ...
  "license": "ISC",
  "devDependencies": {
    "@google-cloud/functions-framework": "^2.0.0"
  }
}
```

では、実行してみましょう。  

```bash
$ npx functions-framework --target=myFirstFunction --signature-type=http
```

![スクリーンショット 2021-12-02 171442.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/49021/2d66a492-22fd-c0b3-2c8b-2213df511a61.png)
こんな画面が現れますので、[OpenInBrowser]を押してやると...
ブラウザに表示されました。
![スクリーンショット 2021-12-02 171542.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/49021/d79dff76-6fe7-d2c8-4d16-48a240059316.png)
ポートの自動フォワードについてはターミナルの隣のタブ「PORTS」で確認できます。
![スクリーンショット 2021-12-02 171656.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/49021/427437ab-ecf0-2813-14bc-dd89f7fb96c9.png)

##GoogleCloudへデプロイしましょう
###gcloudツールをインストールします

デプロイの為にはgcloudコマンドを使います。
これも簡単にインストールします。

```bash
$ curl https://sdk.cloud.google.com | bash
```
プロンプトへはすべてデフォルト（Enterのみ）でOKです。
インストールしたgcloudコマンドを有効にするために新しいターミナル画面を開きます。
![スクリーンショット 2021-12-03 084417.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/49021/67aa010f-72ae-dbc3-7282-6f046eac3f00.png)

gcloudを設定します。

```bash
$ gcloud init
```
プロンプト
`You must log in to continue. Would you like to log in (Y/n)?  `
に`Y`
（デフォルト）で答えます。

すると、以下の様に認証画面へのurlが表示されますので、ctrl+click

```
Go to the following link in your browser:

    https://accounts.google.com/o/oauth2/auth?response_type=code&client_id=3...（略）

Enter verification code: 
```

googleの認証画面が表示されますので、gcloudへアクセスできるアカウントで認証します。
GoogleCloudSDKへの許可をします。
![スクリーンショット 2021-12-02 175009.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/49021/2563bc4e-1bad-f41b-d3c3-e64b6e0ceebd.png)

そこで認証キーが表示されるので、コピーボタンでコピーして、
![スクリーンショット 2021-12-02 175135.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/49021/f7854e2e-8b54-da8e-193b-d1dcd7d2e1b3.png)
VSCodeのプロンプトへペーストしてEnterを押します。

```bash
Enter verification code: 4/1AX...（略）
```
続いてデプロイ先のプロジェクトを選んだらOK。

###GoogleCloud側でビルドAPIを有効にします
GCPコンソールのナビゲーションメニュー→APIとサービス→ライブラリで、APIライブラリ画面が開きます。
APIとサービスを検索の窓に、`cloud build api`と入力して、恐らく1番目に表示される「Cloud Build API」をクリック、
表示された画面で「有効にする」をクリックします。
![スクリーンショット 2021-12-02 180808.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/49021/92df5626-4876-8f16-6902-eabbcda14e5c.png)

###いよいよデプロイ  
対象のプロジェクトへ先程作ったアプリをデプロイします。

```bash
$ gcloud beta functions deploy myFunction \
--runtime=nodejs14 \
--entry-point=myFirstFunction \
--trigger-http \
--allow-unauthenticated
```
何か聞かれたらデフォルト（Enter）でOKです。

###動作確認しましょう  

ナビゲーションメニュー→CloudFunctionsを選びます。
![スクリーンショット 2021-12-02 181534.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/49021/9301a2b3-048b-762b-412e-a758e131ce1c.png)

表示されていますね。
このmyFunctionをクリック、トリガータブを選ぶとURLが見えますのでクリックしてみましょう。
![スクリーンショット 2021-12-02 183146.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/49021/b0ddcfba-d784-3208-1889-38364e689918.png)
出ました！

##おしまい  
ここでご案内した手順についてはもちろん[本家サイト](https://cloud.google.com/blog/ja/topics/developers-practitioners/learn-cloud-functions-snap)に詳しく記載されています。
本稿ではチートシート的に必要な手順を抜き出してみました。
あなたのプロジェクトで、より「中身に注力」するためにご参考になれば嬉しいです。