ここでは、フロントエンドに node.js を、バックエンドに MySQL を使用する Logbook アプリをビルドする手順について、高度なサンプルを通じて詳細に説明します。また、テンプレートを使用して、2 つのゾーン間で負荷分散を行う HTTP ロードバランサと、アプリを自動的にスケールするオートスケーラーを作成して接続します。
このサンプルでは、ユーザーが Docker コンテナについて十分に理解していること、そして HTTP 負荷分散や自動スケーリング、マネージド インスタンス グループ、インスタンス テンプレートなど、Compute Engine リソースについて十分に理解していることを前提としています。
詳細なチュートリアルについては、スタートガイドまたは手順ガイドをご覧ください。
始める前に
- このガイドのコマンドラインの例を使用する場合、gcloud コマンドライン ツールをインストールします。
- このガイドの API の例を使用する場合は、API アクセスを設定します。
- Compute Engine HTTP 負荷分散について十分に理解してください。
- Docker コンテナについて十分に理解してください。
テンプレートの作成
このサンプルでは、さまざまなリソースタイプを含むデプロイメントを作成します。初めに、各リソースを個別に定義する再利用可能なテンプレートを作成します。その後、最終構成において各テンプレートを利用します。
このサンプルを完了すると、次のリソースを含むデプロイが作成されます。
- バックエンド MySQL 仮想マシン用の 1 つの Compute Engine インスタンス。
- Docker イメージを使用するインスタンス テンプレート。
- 2 つの異なるゾーンでそれぞれフロントエンド node.js サービスを実行する 2 つの自動スケーリング マネージド インスタンス グループ。
- 静的データを提供するさらに 2 つの自動スケーリング マネージド インスタンス グループ。
- ヘルスチェックと、各マネージド インスタンス グループ間でトラフィックを分散する HTTP ロードバランサ。
バックエンド テンプレートの作成
このアプリのバックエンドは、単一の Compute Engine インスタンスで、MySQL Docker コンテナを実行します。コンテナ最適化イメージを使用する Compute Engine インスタンスを定義するテンプレートを作成します。ファイルに container_vm.[py|jinja]
という名前を付けます。
Jinja
Python
このテンプレートは containerImage
、manifest
などのさまざまな変数を定義します。これらは、構成を定義する際に指定されます。このテンプレートのみの場合、単一の仮想マシン インスタンスのみが作成されます。
Compute Engine インスタンス上でコンテナ イメージを使用する場合は、Deployment Manager マニフェストとは別のマニフェスト ファイルを用意して、使用するコンテナ イメージを Compute Engine に伝える必要があります。container_helper.[py|jinja]
というヘルパー メソッドを作成して、コンテナ マニフェストを動的に定義します。
Jinja
Python
フロントエンド テンプレートの作成
このアプリのフロントエンドで Node.js を実行し、ユーザーがウェブページにメッセージを投稿できるようにします。それぞれ 2 つのインスタンスを含む 2 つのマネージド インスタンス グループを作成します。一方はメインのマネージド インスタンス グループで、もう一方は負荷分散用のサブのマネージド インスタンス グループとなります。
次の手順でこうしたフロントエンド テンプレートを作成します。
インスタンス テンプレートを作成します。
マネージド インスタンス グループを作成するには、インスタンス テンプレート リソースが必要です。マネージド インスタンス グループとは、一元的に管理されるまったく同一の VM インスタンスで構成されるグループです。このサンプルではフロントエンド node.js インスタンス用のマネージド インスタンス グループを作成しますが、まず先にインスタンス テンプレートを作成する必要があります。
container_instance_template.[py|jinja]
という名前のファイルを定義します。Jinja
Python
自動スケーリングされるマネージド インスタンス グループを作成します。
インスタンス テンプレートの作成が完了したので、このインスタンス テンプレートを使用して自動スケーリング マネージド インスタンス グループを作成するテンプレートを定義できます。次の内容のファイルを
autoscaled_group.[py|jinja]
という名前で新規に作成します。Jinja
Python
対応するスキーマ ファイルを作成します。
Jinja
Python
テンプレートを使用してリソースを作成します。
この時点までで、リソースのプロパティを決定するベース テンプレートの定義が完了しています。このテンプレートを使用して、フロントエンドのセットアップを定義します。次の内容のファイルを
service.[py|jinja]
という名前で新規に作成します。Jinja
Python
対応するスキーマ ファイルを作成します。
Jinja
Python
このテンプレートによって何が作成されるのか、分解して確認してみましょう。
2 つのマネージド インスタンス グループ(メインとサブ)を作成します。
このテンプレートは、
autoscaled_group.[py|jinja]
テンプレートを使用して、メインとサブの自動スケーリング マネージド インスタンス グループを作成します。次に、バックエンド サービスとヘルス チェッカーを作成します。バックエンド サービスは HTTP 負荷分散に必要とされ、テンプレートによって、バックエンド サービス内のインスタンス グループのサービス容量が定義されます。今回の場合、メインとサブのマネージド インスタンス グループは、どちらもバックエンドの一部であり、バックエンド サービスのデフォルト プロパティが適用されます。
デフォルトでは、バックエンド サービスは関連インスタンス グループの CPU 利用率に基づいて負荷分散を実行しますが、リクエスト数/秒(RPS)に基づいて負荷分散を実行させることもできます。
注: バックエンド サービスを作成する場合は、常にヘルスチェックが必要となります。
統合テンプレートの作成
最後に、バックエンド テンプレートとフロントエンド テンプレートを結合する統合テンプレートを作成します。application.[py|jinja]
という名前の新しいファイルを作成します。
Jinja
Python
対応するスキーマ ファイルを作成します。
Jinja
Python
このテンプレートは、フロントエンドとバックエンドに加え、次の追加リソースも定義します。
メインとサブのマネージド インスタンス グループを持つ静的サービス。この静的サービスは、アプリ内の
/static
パスにあるウェブページを提供します。URL マップリソース。HTTP 負荷分散は、さまざまな URL を正しいパスにマッピングするための URL マップを必要とします。今回の場合、
defaultService
プロパティで示されるデフォルトパスは、すでに作成済みのバックエンド サービスとなります。/static
に移動すると、URL マップは、pathMatchers
セクションで定義されているとおりに、パスを静的サービスにマッピングします。グローバル転送ルールとターゲット HTTP プロキシ。アプリは 2 つのゾーンで負荷分散が実行されるため、単一の外部 IP アドレスを提供するグローバル転送ルールが必要となります。また、HTTP 負荷分散をセットアップするために、ターゲット HTTP プロキシが必要となります。
ポート 8080 を通じたトラフィックを許可するファイアウォール ルール。
構成の作成
テンプレートと関連するスキーマの準備が整ったので、リソースをデプロイする構成を作成できます。次のコンテンツを含む application.yaml
という名の構成ファイルを作成します。ZONE_TO_RUN
と SECONDARY_ZONE_TO_RUN
は、デベロッパーが選択したメインゾーンとサブゾーンにそれぞれ置き換えてください。
Jinja
Python
構成のデプロイ
リソースをデプロイします。Google Cloud CLI で次のコマンドを実行します。必要に応じて、advanced-configuration-l7
のところは、任意のデプロイメント名で置き換えることもできます。なお、リソース名の設定時には、デベロッパーのデプロイメント名が自動的に使用されます。
このサンプルのデプロイメント名は advanced-configuration-l7
です。デプロイメント名を変更するよう選択した場合は、下記のすべてのサンプルで必ずそのデプロイメント名を使用するようにしてください。
gcloud deployment-manager deployments create advanced-configuration-l7 --config application.yaml
返されるレスポンスは、次のリソースのようになります。
Waiting for create operation-1469468950934-5387966d431f0-49b11bc4-1421b2f0...done. Create operation operation-1469468950934-5387966d431f0-49b11bc4-1421b2f0 completed successfully. NAME TYPE STATE ERRORS advanced-configuration-l7-application-fw compute.v1.firewall COMPLETED [] advanced-configuration-l7-application-l7lb compute.v1.globalForwardingRule COMPLETED [] advanced-configuration-l7-application-targetproxy compute.v1.targetHttpProxy COMPLETED [] advanced-configuration-l7-application-urlmap compute.v1.urlMap COMPLETED [] advanced-configuration-l7-backend compute.v1.instance COMPLETED [] advanced-configuration-l7-frontend-bes compute.v1.backendService COMPLETED [] advanced-configuration-l7-frontend-hc compute.v1.httpHealthCheck COMPLETED [] advanced-configuration-l7-frontend-it compute.v1.instanceTemplate COMPLETED [] advanced-configuration-l7-frontend-pri-as compute.v1.autoscaler COMPLETED [] advanced-configuration-l7-frontend-pri-igm compute.v1.instanceGroupManager COMPLETED [] advanced-configuration-l7-frontend-sec-as compute.v1.autoscaler COMPLETED [] advanced-configuration-l7-frontend-sec-igm compute.v1.instanceGroupManager COMPLETED [] advanced-configuration-l7-static-service-bes compute.v1.backendService COMPLETED [] advanced-configuration-l7-static-service-hc compute.v1.httpHealthCheck COMPLETED [] advanced-configuration-l7-static-service-it compute.v1.instanceTemplate COMPLETED [] advanced-configuration-l7-static-service-pri-as compute.v1.autoscaler COMPLETED [] advanced-configuration-l7-static-service-pri-igm compute.v1.instanceGroupManager COMPLETED [] advanced-configuration-l7-static-service-sec-as compute.v1.autoscaler COMPLETED [] advanced-configuration-l7-static-service-sec-igm compute.v1.instanceGroupManager COMPLETED []
サービスラベルの追加
次に、マネージド インスタンス グループに対して、適切なサービスラベルを指定します。サービスラベルは、負荷分散サービスがリソースをグループ化する際に使用するメタデータです。
サービスラベルを追加するには、次のコマンドを実行します。メインゾーンとサブゾーンは、それぞれデプロイメント構成ファイルで選択したゾーンに合わせてください。
gcloud compute instance-groups unmanaged set-named-ports advanced-configuration-l7-frontend-pri-igm \
--named-ports http:8080,httpstatic:8080 \
--zone [PRIMARY_ZONE]
gcloud compute instance-groups unmanaged set-named-ports advanced-configuration-l7-frontend-sec-igm \
--named-ports http:8080,httpstatic:8080 \
--zone [SECONDARY_ZONE]
構成のテスト
構成をテストするには、転送ルールのクエリを行うことで、トラフィックにサービスを提供する外部 IP アドレスを取得します。
gcloud compute forwarding-rules list | grep advanced-configuration-l7-l7lb advanced-configuration-l7-l7lb 107.178.249.126 TCP advanced-configuration-l7-targetproxy
この場合の外部 IP アドレスは 107.178.249.126
です。
ブラウザで、ポート 8080 を使用して外部 IP アドレスにアクセスします。たとえば、外部 IP が 107.178.249.126
の場合、URL は次のようになります。
http://107.178.249.126:8080
空白のページが表示されるはずです。これは想定どおりです。次に、メッセージをページに投稿します。次の URL に移動します。
http://107.178.249.126:8080?msg=hello_world!
メッセージが追加されたことを確認するメッセージが表示されます。メイン URL に戻ると、ページにメッセージが表示されているはずです。
hello_world!
また、作成した静的ページにアクセスして、アプリの状態をチェックすることもできます。次の URL にアクセスしてください。
# Static web page
http://107.178.249.126:8080/static
# Health check
http://107.178.249.126:8080/_ah/health
これで構成は正常にデプロイされました。
(省略可)Docker イメージの作成
Docker を利用すると、コンテナ内でソフトウェアを自動的に実行できます。コンテナにより、各種サービスをコンテナ内で分離し、すべてを単一の Linux インスタンス上で実行できます。
今回のサンプルでは既存の Docker イメージを使用していますが、独自バージョンの Docker イメージを作成することもできます。MySQL バックエンド イメージと Node.js フロントエンド イメージの作成手順については、Docker イメージの作成をご覧ください。
静的ウェブページを提供する Docker イメージを作成するには:
コンテナ最適化イメージを備えた新しい VM インスタンスを作成します。
gcloud compute instances create docker-playground \ --image-family container-vm \ --image-project google-containers \ --zone us-central1-a \ --machine-type f1-micro
インスタンスに接続します。
gcloud compute ssh --zone us-central1-a docker-playground
次の内容のファイルを
Dockerfile
という名前で作成します。FROM node:latest RUN mkdir /var/www/ ADD service.js /var/www/service.js WORKDIR /var/www/ RUN npm install mysql CMD ["node", "service.js"]
次の内容のファイルを
service.js
という名前で作成します。var http = require('http'); var url = require('url'); console.log('Started static node server') http.createServer(function (req, res) { reqUrl = url.parse(req.url, true); res.useChunkedEncodingByDefault = false; res.writeHead(200, {'Content-Type': 'text/html'}); if (reqUrl.pathname == '/_ah/health') { res.end('ok'); } else if (reqUrl.pathname == '/exit') { process.exit(-1) } else { res.end('static server'); } }).listen(8080, '0.0.0.0'); console.log('Static server running at http://127.0.0.1:8080/');
Docker イメージをビルドします。
username
は、各自の Docker Hub ユーザー名に置き換えてください。Docker Hub ユーザー名を持っていない場合は、Docker イメージをビルドする前に、まずアカウントを作成してください。sudo docker build --no-cache -t username/nodejsservicestatic .
イメージを Docker リポジトリに push します。
sudo docker push username/nodejsservicestatic
Node.js と MySQL を実行する Docker イメージが完成しました。イメージ名を検索することで、リポジトリ上でイメージを見つけることができます。イメージを試してみる場合は、gcr.io/deployment-manager-examples/mysql
と gcr.io/deployment-manager-examples/nodejsservice
のすべてのインスタンスを各自のイメージと置き換えてください。
次のステップ
このサンプルを完成させた後は、次のステップに進めます。