1. 概要
このラボでは、コンテナ化された環境で NodeJS アプリケーションを開発するソフトウェア エンジニア向けに、開発ワークフローを効率化するための特長と機能を紹介します。一般的なコンテナ開発では、ユーザーがコンテナの詳細とコンテナのビルドプロセスを理解する必要があります。さらに、デベロッパーは通常、作業の中断を余儀なくされ、IDE から離れてリモート環境でアプリケーションのテストやデバッグを行う必要もあります。このチュートリアルで説明するツールとテクノロジーを使用すると、デベロッパーは IDE を離れることなく、コンテナ化されたアプリケーションを効果的に操作できます。
学習内容
このラボでは、Google Cloud でコンテナを使用して開発するための次のような方法について学びます。
- スターター Nodejs アプリケーションの作成
- コンテナ開発用に Nodejs アプリケーションを構成する
- 単純な CRUD REST サービスのコーディング
- GKE へのデプロイ
- エラー状態のデバッグ
- ブレークポイント / ログの利用
- 変更を GKE にホット デプロイして戻す
- 省略可: バックエンドの永続性を確保するための Cloud SQL の統合
2. 設定と要件
セルフペース型の環境設定
- Google Cloud Console にログインして、プロジェクトを新規作成するか、既存のプロジェクトを再利用します。Gmail アカウントも Google Workspace アカウントもまだお持ちでない場合は、アカウントを作成してください。
- プロジェクト名は、このプロジェクトの参加者に表示される名称です。Google API では使用されない文字列です。この値はいつでも更新できます。
- プロジェクト ID は、すべての Google Cloud プロジェクトにおいて一意でなければならず、不変です(設定後は変更できません)。Cloud コンソールでは一意の文字列が自動生成されます。通常、それが何であるかは関係ありません。ほとんどの Codelab では、プロジェクト ID を参照する必要があります(通常は
PROJECT_ID
として識別されます)。生成された ID が気に入らない場合は、別のランダムな ID を生成できます。または、ご自身でお試しになることもできます。このステップを終えた後は変更できず、プロジェクト期間中は維持されます。 - なお、3 つ目の値は、一部の API で使用される [プロジェクト番号] です。これら 3 つの値について詳しくは、こちらのドキュメントをご覧ください。
- 次に、Cloud のリソースや API を使用するために、Cloud コンソールで課金を有効にする必要があります。この Codelab の操作をすべて行って、費用が生じたとしても、少額です。このチュートリアルの終了後に課金が発生しないようにリソースをシャットダウンするには、作成したリソースを削除するか、プロジェクト全体を削除します。Google Cloud の新規ユーザーは、300 米ドル分の無料トライアル プログラムをご利用いただけます。
Cloudshell エディタを起動する
このラボは、Google Cloud Shell エディタで使用するように設計、テストされています。エディタにアクセスするには、
- https://console.cloud.google.com から Google プロジェクトにアクセスします。
- 右上にある Cloud Shell エディタのアイコンをクリックします。
- ウィンドウの下部に新しいペインが開きます
- [エディタを開く] ボタンをクリックします。
- エディタが開き、右側にエクスプローラ、中央部分にエディタが表示されます
- 画面の下部にターミナル ペインも表示されます。
- ターミナルが開いていない場合は、`Ctrl+` キーの組み合わせを使用して新しいターミナル ウィンドウを開きます。
gcloud を設定する
Cloud Shell で、プロジェクト ID とアプリケーションのデプロイ先のリージョンを設定します。これらを PROJECT_ID
変数と REGION
変数として保存します。
export PROJECT_ID=$(gcloud config get-value project)
export PROJECT_NUMBER=$(gcloud projects describe $PROJECT_ID --format='value(projectNumber)')
このラボで使用するインフラストラクチャをプロビジョニングする
このラボでは、GKE にコードをデプロイし、Cloud SQL データベースに保存されているデータにアクセスします。以下の設定スクリプトは、このインフラストラクチャを準備します。
- 設定スクリプトをダウンロードして、実行可能にします。
wget https://raw.githubusercontent.com/GoogleCloudPlatform/container-developer-workshop/main/labs/nodejs/setup_with_cw.sh
chmod +x setup_with_cw.sh
setup_with_cw.sh
ファイルを開き、現在 CHANGEME に設定されているパスワードの値を編集します- 設定スクリプトを実行して、このラボで使用する GKE クラスタと Cloud SQL データベースを立ち上げます。
./setup_with_cw.sh &
Cloud Workstations クラスタ
- Cloud コンソールで Cloud Workstations を開きます。クラスタが
READY
ステータスになるまで待ちます。
ワークステーション構成の作成
- Cloud Shell セッションが切断された場合は、[再接続] をクリックします。gcloud cli コマンドを実行してプロジェクト ID を設定しますコマンドを実行する前に、以下のサンプル プロジェクト ID を Qwiklabs プロジェクト ID に置き換えてください。
gcloud config set project qwiklabs-gcp-project-id
- 以下のスクリプトをダウンロードしてターミナルで実行し、Cloud Workstations 構成を作成します。
wget https://raw.githubusercontent.com/GoogleCloudPlatform/container-developer-workshop/main/labs/nodejs/workstation_config_setup.sh
chmod +x workstation_config_setup.sh
./workstation_config_setup.sh
- [構成] セクションで結果を確認します。READY ステータスに移行するまでに 2 分かかります。
- コンソールで Cloud Workstations を開き、新しいインスタンスを作成します。
- 名前を
my-workstation
に変更し、既存の構成(codeoss-js
)を選択します。
- [ワークステーション] セクションで結果を確認します。
ワークステーションを起動
- ワークステーションを起動して起動します。ワークステーションの起動には数分かかります。
- アドレスバーのアイコンをクリックして、サードパーティ Cookie を許可します。
- [サイトが動作していない場合] をクリックします。
- [Cookie を許可] をクリックします。
- ワークステーションを起動すると、Code OSS IDE が表示されます。[完了マークを付ける] をクリックしますワークステーションの IDE では
3. 新しい Nodejs スターター アプリケーションの作成
このセクションでは、新しい Nodejs アプリケーションを作成します。
- 新しいターミナルを開きます。
- Cloud Shell で、
mynodejsapp
という名前の新しいディレクトリを作成します。
mkdir mynodejsapp
このメッセージが表示された場合は [Allow] ボタンをクリックし、ワークステーションにコピーして貼り付けられるようにします。
- このディレクトリに移動し、ワークスペースとして開きます。これにより、新しく作成されたフォルダにワークスペース構成が作成され、エディタが再読み込みされます。
cd mynodejsapp && code-oss-cloud-workstations -r --folder-uri="$PWD"
- 新しいターミナルをもう一度開きます。NVM を使用してノードと NPM をインストールする。
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.2/install.sh | bash
# This loads nvm bash_completion
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm
[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion"
nvm install stable
nvm alias default stable
4. 新しいスターター アプリケーションを作成する
- アプリケーションを初期化する
次のコマンドを実行して package.json
ファイルを作成する
npm init
Choose the `entry point: (index.js) src/index.js` and leave default values for the rest of the parameters. This will create the `package.json` file with following contents
{ "name": "mynodejsapp", "version": "1.0.0", "description": "", "main": "src/index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "author": "", "license": "ISC" }
- エントリ ポイントを追加する
IDE で package.json
ファイルを開いて編集し、スクリプト "start": "node src/index.js",
に起動コマンドを含めます。変更後のスクリプトは、次のコード スニペットのようになります。
"scripts": {
"start": "node src/index.js",
"test": "echo \"Error: no test specified\" && exit 1"
},
- Express 依存関係を追加する
追加するコードでも express
を使用しているため、この package.json
ファイルにその依存関係を追加しましょう。すべての変更が完了すると、package.json
ファイルは次のようになります。
{
"name": "mynodejsapp",
"version": "1.0.0",
"description": "",
"main": "src/index.js",
"scripts": {
"start": "node src/index.js",
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"express": "^4.17.3"
}
}
- index.js ファイルを作成する
エクスプローラ ビューで [New Folder] を選択して、「src」というソース ディレクトリを作成します。
src/index.js ファイルを作成する
これを次のコードに置き換えます。
const express = require('express');
const app = express();
const PORT = 8080;
app.get('/', (req, res) => {
var message="Greetings from Node";
res.send({ message: message });
});
app.listen(PORT, () => {
console.log(`Server running at: http://localhost:${PORT}/`);
});
PORT が 8080
値に設定されていることに注目
マニフェストを生成する
Skaffold には、コンテナ開発を簡素化する統合ツールが用意されています。このステップでは、ベース Kubernetes YAML ファイルを自動的に作成する Skaffold を初期化します。以下のコマンドを実行してプロセスを開始します。
ターミナルで次のコマンドを実行します。
skaffold init --generate-manifests
プロンプトが表示されたら、次の操作を行います。
- ポートに「8080」と入力します。
- 「y」と入力して構成を保存します。
ワークスペースのビジュアリゼーションに skaffold.yaml
と deployment.yaml
の 2 つのファイルが追加されます。
アプリ名を更新
現在、構成に含まれるデフォルト値は、アプリケーションの名前と一致していません。デフォルト値ではなく、アプリケーション名を参照するようにファイルを更新します。
- Skaffold 構成のエントリを変更する
skaffold.yaml
を開きます。- 現在
package-json-image
として設定されているイメージ名を選択します - 右クリックして [すべてのオカレンスを変更] を選択します。
- 新しい名前として「
mynodejsapp
」と入力します。
- Kubernetes 構成のエントリを変更する
deployment.yaml
ファイルを開く- 現在
package-json-image
として設定されているイメージ名を選択します - 右クリックして [すべてのオカレンスを変更] を選択します。
- 新しい名前として「
mynodejsapp
」と入力します。
skaffold.yaml
ファイルの build
セクションで buildpacks
を使用してアプリケーションをコンテナ化しています。このコードには Dockerfile がなく、デベロッパーはこのアプリケーションをコンテナ化するために Docker の知識は必要ありません。
また、この skaffold 構成により、エディタと実行中のコンテナの間でホット同期が自動的に有効になります。ホット同期を有効にするために、追加の構成は必要ありません。
5. 開発プロセスの説明
このセクションでは、Cloud Code プラグインを使用して基本的なプロセスを学習し、スターター アプリケーションの構成と設定を検証する手順をいくつか紹介します。
Cloud Code を skaffold と統合して開発プロセスを効率化できます。次の手順で GKE にデプロイすると、Cloud Code と Skaffold が自動的にコンテナ イメージをビルドして Container Registry に push し、アプリケーションを GKE にデプロイします。この処理はバックグラウンドで行われ、デベロッパー フローでは詳細が抽象化されます。また、Cloud Code は、コンテナベースの開発に従来のデバッグ機能とホットシンク機能を提供することで開発プロセスを強化します。
Google Cloud にログインする
- Cloud Code アイコンをクリックし、[Sign in to Google Cloud] を選択します。
- [ログインに進む] をクリックします。
- ターミナルで出力を確認し、リンクを開きます。
- Qwiklabs の受講者用認証情報でログインします。
- [許可] を選択:
- 確認コードをコピーして、[ワークステーション] タブに戻ります。
- 確認コードを貼り付けて、Enter キーを押します。
Kubernetes クラスタを追加
- クラスタを追加する
- Google Kubernetes Engine を選択します。
- プロジェクトを選択します。
- [mycluster] を選択します。初期セットアップで作成された すべてのジョブに適用されます
- Cloud Code の Kubernetes クラスタリストにクラスタが表示されます。ここからクラスタを操作、探索します。
gcloud CLI を使用して現在のプロジェクト ID を設定する
- Qwiklabs ページからこのラボのプロジェクト ID をコピーします。
- ターミナルで gcloud cli コマンドを実行してプロジェクト ID を設定します。コマンドを実行する前に、サンプル プロジェクト ID を置き換えます。プロジェクト ID を置き換えてから、以下のコマンドを実行します。
gcloud config set project qwiklabs-gcp-project-id
Kubernetes へのデプロイ
- Cloud Shell エディタの下部にあるペインで、[Cloud Code] を選択します。
- 上部の [開発セッション] の下に表示されるパネルで、[Run on Kubernetes] を選択します。プロンプトが表示されたら、[はい] を選択して現在の Kubernetes コンテキストを使用します。
- コマンドを初めて実行すると、画面の上部に現在の Kubernetes コンテキストが必要かどうかを尋ねるプロンプトが表示されます。[はい] を選択します。現在のコンテキストを受け入れて使用します。
- 次に、使用する Container Registry を尋ねるプロンプトが表示されます。Enter キーを押して、指定されたデフォルト値を受け入れます。
- 下部のペインで [Output] タブを選択し、プルダウンから [Kubernetes: Run/Debug] を選択して、進行状況と通知を表示します。
- [Kubernetes: Run/Debug - Detailed] を選択します。右側のチャネル プルダウンから、追加の詳細情報や、コンテナからライブ ストリーミングされるログを確認できます。
- [Kubernetes: Run/Debug] を選択すると、簡素化されたビューに戻ります。プルダウンから
- ビルドとテストが完了すると、[Output] タブに
Resource deployment/mynodejsapp status completed successfully
と表示され、URL として「Forwarded URL from service demo-app: http://localhost:8080」が表示されます。 - Cloud Code ターミナルで、出力の URL(http://localhost:8080)にカーソルを合わせ、表示されたツールチップで [Follow Link] を選択します。
レスポンスは次のようになります。
{"message":"Greetings from Node"}
ホットリロード
src/index.js
に移動します。挨拶メッセージのコードを'Hello from Node'
に変更します。
すぐに、Output
ウィンドウの Kubernetes: Run/Debug
ビューで、ウォッチャーが更新されたファイルを Kubernetes のコンテナと同期します。
Update initiated File sync started for 1 files for gcr.io/myproject/mynodejsapp:latest@sha256:f554756b3b4d6c301c4b26ef96102227cfa2833270db56241248ae42baa1971a File sync succeeded for 1 files for gcr.io/myproject/mynodejsapp:latest@sha256:f554756b3b4d6c301c4b26ef96102227cfa2833270db56241248ae42baa1971a Update succeeded
Kubernetes: Run/Debug - Detailed
ビューに切り替えると、ファイルの変更が認識され、ノードが再起動されます。
files modified: [src/index.js] Copying files:map[src/index.js:[/workspace/src/index.js]]togcr.io/myproject/mynodejsapp:latest@sha256:f554756b3b4d6c301c4b26ef96102227cfa2833270db56241248ae42baa1971a Syncing 1 files for gcr.io/myproject/mynodejsapp:latest@sha256:f554756b3b4d6c301c4b26ef96102227cfa2833270db56241248ae42baa1971a Watching for changes... [mynodejsapp] [mynodejsapp]> mynodejsapp@1.0.0 start /workspace [mynodejsapp]> node src/index.js [mynodejsapp] [mynodejsapp]Server running at: http://localhost:8080/
- ブラウザを更新して、更新された結果を確認してください。
デバッグ
- デバッグビューに移動し、現在のスレッド を停止します。
- 下部のメニューで
Cloud Code
をクリックし、Debug on Kubernetes
を選択して、アプリをdebug
モードで実行します。
Output
ウィンドウのKubernetes Run/Debug - Detailed
ビューで、skaffold がこのアプリケーションをデバッグモードでデプロイします。- アプリケーションのビルドとデプロイには数分かかります。今度はデバッガがアタッチされているのがわかります。
Port forwarding pod/mynodejsapp-6bbcf847cd-vqr6v in namespace default, remote port 9229 -> http://127.0.0.1:9229 [mynodejsapp]Debugger attached.
- 下部のステータスバーの色が青からオレンジ色に変わり、デバッグモードになっていることを示します。
Kubernetes Run/Debug
ビューで、Debuggable コンテナが開始されていることを確認します。
**************URLs***************** Forwarded URL from service mynodejsapp-service: http://localhost:8080 Debuggable container started pod/mynodejsapp-deployment-6bc7598798-xl9kj:mynodejsapp (default) Update succeeded ***********************************
ブレークポイントの活用
src/index.js
を開きます。- 「
var message="Hello from Node";
」というステートメントを見つけます。 - 行番号の左側にある空白スペースをクリックして、その行にブレークポイントを追加します。ブレークポイントが設定されたことを示す赤いインジケーターが表示される
- ブラウザを再読み込みすると、デバッガがブレークポイントでプロセスを停止し、GKE でリモートで実行されているアプリケーションの変数と状態を調査できるようになります。
"message"
変数が見つかるまで、変数セクションをクリックします。- Step over を押して行を実行します。
"message"
変数の現在の値が"Hello from Node"
に変わることを確認します。- 変数名「target」をダブルクリックします。ポップアップで、値を
"Hi from Node"
など別のものに変更します。 - デバッグ用コントロール パネルで [続行] ボタンをクリックします。
- ブラウザでレスポンスを確認します。入力した値が更新されています。
- 「Debug」と表示モードに切り替えるには停止ボタン を押します。ブレークポイントをもう一度クリックすると、ブレークポイントを削除できます。
6. シンプルな CRUD REST サービスを開発する
これで、アプリケーションはコンテナ化された開発用に完全に構成され、Cloud Code での基本的な開発ワークフローはひととおり確認できました。以降のセクションでは、Google Cloud のマネージド データベースに接続する REST サービス エンドポイントを追加して、学習した内容を実践します。
依存関係を構成する
アプリケーション コードは、データベースを使用して残りのサービスデータを保持します。package.json
ファイルに次の行を追加して、依存関係が利用可能であることを確認します。
- さらに 2 つの依存関係
pg
とsequelize
をpackage.json
ファイルに追加して、CRUD アプリケーション Postgres を構築します。変更後は、依存関係セクションは次のようになります。
"dependencies": {
"express": "^4.17.3",
"pg": "^8.8.0",
"sequelize": "^6.25.7"
}
REST サービスをコーディングする
- このアプリケーションに CRUD アプリケーション コードを追加します
wget -O app.zip https://github.com/GoogleCloudPlatform/container-developer-workshop/raw/main/labs/nodejs/app.zip
unzip app.zip
このコードは
item
のエンティティ モデルを含む models フォルダ- CRUD オペレーションを行うコードを含む controllers フォルダ
- routes フォルダ。特定の URL パターンを異なる呼び出しにルーティングします。
- データベース接続の詳細を含む config フォルダ
db.config.js
ファイルのデータベース構成は、データベースに接続するために指定する必要がある環境変数を参照します。また、URL エンコード用に受信リクエストを解析する必要もあります。src/index.js
に次のコード スニペットを追加して、app.listen(PORT, () => {
で始まる最後のセクションの直前に、メインの JavaScript ファイルの CRUD コードに接続できるようにします。
const bodyParser = require('body-parser')
app.use(bodyParser.json())
app.use(
bodyParser.urlencoded({
extended: true,
})
)
const db = require("../app/models");
db.sequelize.sync();
require("../app/routes/item.routes")(app);
deployment.yaml
ファイルの Deployment を編集して、データベースの接続情報を指定する環境変数を追加します。
次の定義と一致するように、ファイルの最後の spec エントリを更新します。
spec:
containers:
- name: mynodejsapp
image: mynodejsapp
env:
- name: DB_HOST
value: ${DB_INSTANCE_IP}
- name: DB_PORT
value: "5432"
- name: DB_USER
valueFrom:
secretKeyRef:
name: gke-cloud-sql-secrets
key: username
- name: DB_PASS
valueFrom:
secretKeyRef:
name: gke-cloud-sql-secrets
key: password
- name: DB_NAME
valueFrom:
secretKeyRef:
name: gke-cloud-sql-secrets
key: database
- DB_HOST の値をデータベースのアドレスに置き換えます。
export DB_INSTANCE_IP=$(gcloud sql instances describe mytest-instance \
--format=json | jq \
--raw-output ".ipAddresses[].ipAddress")
envsubst < deployment.yaml > deployment.new && mv deployment.new deployment.yaml
アプリケーションのデプロイと検証
- Cloud Shell エディタの下部にあるペインで
Cloud Code
を選択し、画面上部のDebug on Kubernetes
を選択します。 - ビルドとテストが完了すると、[Output] タブに
Resource deployment/mynodejsapp status completed successfully
と表示され、URL として「Forwarded URL from service mynodejsapp: http://localhost:8080」が表示されます。 - アイテムをいくつか追加します。
cloudshell ターミナルから、以下のコマンドを実行します。
URL=localhost:8080
curl -X POST $URL/items -d '{"itemName":"Body Spray", "itemPrice":3.2}' -H "Content-Type: application/json"
curl -X POST $URL/items -d '{"itemName":"Nail Cutter", "itemPrice":2.5}' -H "Content-Type: application/json"
- ブラウザで $URL/items を実行して、GET をテストします。コマンドラインから curl コマンドを実行することもできます。
curl -X GET $URL/items
- 削除をテストする: 次のコマンドを実行して、アイテムを削除してみます。必要に応じて、item-id の値を変更します。
curl -X DELETE $URL/items/1
This throws an error message
{"message":"Could not delete Item with id=[object Object]"}
問題を特定して修正する
- アプリケーションはデバッグモードで実行されています。そのため、ブレークポイントを使用して問題を見つけます。次のヒントを参考にしてください。
- DELETE が意図した結果を返さないため、何か問題があることがわかります。そのため、ブレークポイントは
itemcontroller.js
->exports.delete
メソッドで設定します。 - ステップごとに実行し、各ステップの変数を監視して、左側のウィンドウでローカル変数の値を確認します。
request.params
などの特定の値をモニタリングするには、この変数を [Watch] ウィンドウに追加します。
id
に割り当てられた値がundefined
であることに注意してください。コードを変更して問題を解決してください。
固定コード スニペットは次のようになります。
// Delete a Item with the specified id in the request exports.delete = (req, res) => { const id = req.params.id;
- アプリケーションが再起動したら、削除してもう一度テストします。
- デバッグ ツールバーの赤い正方形 をクリックして、デバッグ セッションを停止します
7. クリーンアップ
これで、このラボでは、新しい Nodejs アプリケーションをゼロから作成し、コンテナを使ってホット デプロイ モードで動作するように構成しました。その後、従来のアプリケーション スタックで見られるのと同じデベロッパー フローに従って、アプリケーションをリモート GKE クラスタにデプロイし、デバッグしました。
ラボの完了後にクリーンアップするには:
- ラボで使用したファイルを削除する
cd ~ && rm -rf mynodejsapp && rm -f setup.sh
- プロジェクトを削除して、関連するすべてのインフラストラクチャとリソースを削除する