Cloud Service Mesh は、分散アプリケーションを管理し、モニタリングするための優れたツールです。Cloud Service Mesh を最大限に活用するには、コンテナと Kubernetes を含む、基盤となる抽象概念の理解が役に立ちます。このチュートリアルでは、ソースコードから GKE 上で実行されるコンテナまで、Cloud Service Mesh 向けにアプリケーションを準備する方法を説明します。ここでは Cloud Service Mesh をインストールする直前までの部分を扱います。
Kubernetes とサービス メッシュのコンセプトにすでに精通している場合は、このチュートリアルをスキップして Cloud Service Mesh のインストール ガイドに進んでください。
目標
- シンプルなマルチサービス「Hello World」アプリケーションを探索する。
- ソースからアプリケーションを実行する。
- アプリケーションをコンテナ化する。
- Kubernetes クラスタを作成する。
- コンテナをクラスタにデプロイする。
始める前に
次の手順に沿って Cloud Service Mesh API を有効にします。- Google Cloud コンソールの Kubernetes Engine ページにアクセスします。
- プロジェクトを作成または選択します。
- API と関連サービスが有効になるのを待ちます。 これには数分かかることがあります。
-
Verify that billing is enabled for your Google Cloud project.
このチュートリアルでは、Cloud Shell を使用して、Debian ベースの Linux オペレーティング システムを実行している g1-small Compute Engine 仮想マシン(VM)をプロビジョニングします。
Cloud Shell を準備する
Cloud Shell を使用する利点は次のとおりです。
- Python 2 と Python 3 の両方の開発環境(
virtualenvを含む)がすべて設定されています。 - このチュートリアルで使用する
gcloud、docker、git、kubectlコマンドライン ツールがすでにインストールされています。 テキスト エディタを選択できます。
コードエディタ。Cloud Shell ウィンドウの上部にある をクリックしてアクセスします。
Emacs、Vim、Nano。Cloud Shell のコマンドラインからアクセスします。
In the Google Cloud console, activate Cloud Shell.
サンプルコードをダウンロードする
helloserverソースコードをダウンロードします。git clone https://github.com/GoogleCloudPlatform/anthos-service-mesh-samplesサンプルコードのディレクトリに移動します。
cd anthos-service-mesh-samples/docs/helloserver
マルチサービス アプリケーションを確認する
サンプル アプリケーションは Python で記述されており、REST を使用して通信する 2 つのコンポーネントを含んでいます。
server: 1 つのGETエンドポイント(/)を持つシンプルなサーバー。Console に「hello world」を出力します。loadgen:serverにトラフィックを送信するスクリプト。1 秒あたりのリクエスト数(RPS)を構成できます。
ソースからアプリケーションを実行する
サンプル アプリケーションに慣れるため、Cloud Shell で実行します。
sample-apps/helloserverディレクトリからserverを実行します。python3 server/server.py起動時に、
serverには次のとおりに表示されます。INFO:root:Starting server...
別のターミナル ウィンドウを開き、
serverにリクエストを送信できるようにします。[] をクリックして別のセッションを開きます。serverにリクエストを送信します。curl http://localhost:8080serverが応答します。Hello World!
サンプルコードをダウンロードしたディレクトリから、
loadgenを含むディレクトリに移動します。cd YOUR_WORKING_DIRECTORY/anthos-service-mesh-samples/docs/helloserver/loadgen
次の環境変数を作成します。
export SERVER_ADDR=http://localhost:8080 export REQUESTS_PER_SECOND=5virtualenvを開始します。virtualenv --python python3 env仮想環境をアクティブにします。
source env/bin/activateloadgenの要件をインストールします。pip3 install -r requirements.txtloadgenを実行します。python3 loadgen.py起動時に、
loadgenによって次のようなメッセージが出力されます。Starting loadgen: 2019-05-20 10:44:12.448415 5 request(s) complete to http://localhost:8080
もう一方のターミナル ウィンドウで、
serverは次のようなメッセージをコンソールに出力します。127.0.0.1 - - [21/Jun/2019 14:22:01] "GET / HTTP/1.1" 200 - INFO:root:GET request, Path: / Headers: Host: localhost:8080 User-Agent: python-requests/2.22.0 Accept-Encoding: gzip, deflate Accept: */*
ネットワーキングの観点からは、現時点でアプリケーション全体が同じホスト上で実行されています。このため、
localhostを使用してserverにリクエストを送信できます。loadgenとserverを停止するには、各ターミナル ウィンドウでCtrl-cを入力します。loadgenターミナル ウィンドウで、仮想環境を無効にします。deactivate
アプリケーションをコンテナ化する
GKE でアプリケーションを実行するには、サンプル アプリケーション(server と loadgen の両方)をコンテナにパッケージ化する必要があります。コンテナは、基盤となる環境から分離されるようにアプリケーションをパッケージ化する方法です。
アプリケーションをコンテナ化するには、Dockerfile が必要です。Dockerfile は、アプリケーション ソースコードとその依存関係を Docker イメージにアセンブルするために必要なコマンドを定義するテキスト ファイルです。イメージをビルドしたら、そのイメージを Docker Hub や Container Registry などのコンテナ レジストリにアップロードします。
このサンプルには、server と loadgen の両方の Dockerfile に、イメージのビルドに必要なすべてのコマンドが用意されています。以下は、server 用の Dockerfile です。
FROM python:3-slim as baseコマンドは、最新の Python 3 イメージをベースイメージとして使用するように Docker に指示します。COPY . .コマンドは、現在の作業ディレクトリ(この場合はserver.pyのみ)のソースファイルをコンテナのファイル システムにコピーします。ENTRYPOINTは、コンテナを実行するために使用するコマンドを定義します。この場合のコマンドは、ソースコードからserver.pyを実行したときに使用したコマンドとほぼ同じです。EXPOSEコマンドは、serverがポート8080でリッスンすることを指定します。このコマンドはポートを公開しませんが、コンテナの実行時にポート8080を開く必要があることを示すドキュメントとして機能します。
アプリケーションのコンテナ化を準備する
次の環境変数を設定します。
PROJECT_IDは、Google Cloud プロジェクトの ID に置き換えます。export PROJECT_ID="PROJECT_ID"
export GCR_REPO="asm-ready"
ビルドするときに
PROJECT_IDとGCR_REPOの値を使用して Docker イメージにタグ付けし、プライベートの Container Registry に push します。Google Cloud CLI のデフォルト Google Cloud プロジェクトを設定します。
gcloud config set project $PROJECT_ID
Google Cloud CLI のデフォルト ゾーンを設定します。
gcloud config set compute/zone us-central1-bGoogle Cloud プロジェクトで Container Registry サービスが有効になっていることを確認します。
gcloud services enable containerregistry.googleapis.com
server をコンテナ化する
サンプル
serverがあるディレクトリに移動します。cd YOUR_WORKING_DIRECTORY/anthos-service-mesh-samples/docs/helloserver/server/
Dockerfileと以前に定義済みの環境変数を使用してイメージをビルドします。docker build -t gcr.io/$PROJECT_ID/$GCR_REPO/helloserver:v0.0.1 .-tフラグは Docker タグを表します。これは、コンテナのデプロイ時に使用するイメージの名前です。イメージを Container Registry に push します。
docker push gcr.io/$PROJECT_ID/$GCR_REPO/helloserver:v0.0.1
loadgen をコンテナ化する
サンプル
loadgenがあるディレクトリに移動します。cd ../loadgenイメージをビルドします。
docker build -t gcr.io/$PROJECT_ID/$GCR_REPO/loadgen:v0.0.1 .イメージを Container Registry に push します。
docker push gcr.io/$PROJECT_ID/$GCR_REPO/loadgen:v0.0.1
イメージのリストを表示する
リポジトリ内のイメージのリストを取得して、イメージが push されたことを確認します。
gcloud container images list --repository gcr.io/$PROJECT_ID/asm-ready
コマンドは、先ほど push したイメージ名を返します。
NAME gcr.io/PROJECT_ID/asm-ready/helloserver gcr.io/PROJECT_ID/asm-ready/loadgen
GKE クラスタを作成する
Cloud Shell VM でこれらのコンテナを実行するには、docker run コマンドを使用します。ただし、本番環境では、より統合された方法でコンテナをオーケストレートする必要があります。たとえば、コンテナが常に走行していることを保証するシステムが必要です。また、トラフィックの増加に対応するためにコンテナの追加のインスタンスを起動してスケールアップする必要があります。
GKE を使用してコンテナ化されたアプリケーションを実行できます。GKE は、VM をクラスタに接続することで機能するコンテナ オーケストレーション プラットフォームです。各 VM はノードと呼ばれます。GKE クラスタでは、Kubernetes オープンソース クラスタ管理システムが使用されます。クラスタの操作には、Kubernetes のメカニズムが使用されます。
GKE クラスタを作成するには:
クラスタを作成します。
gcloud container clusters create asm-ready \ --cluster-version latest \ --machine-type=n1-standard-4 \ --num-nodes 4
gcloudコマンドは、前に設定したGoogle Cloud プロジェクトとゾーンにクラスタを作成します。Cloud Service Mesh の実行には、少なくとも 4 つのノードと n1-standard-4 マシンタイプを使うことをおすすめします。クラスタを作成するコマンドが完了するまで数分かかります。クラスタの準備が整うと、コマンドは次のようなメッセージを出力します。
NAME LOCATION MASTER_VERSION MASTER_IP MACHINE_TYPE NODE_VERSION NUM_NODES STATUS asm-ready us-central1-b 1.13.5-gke.10 203.0.113.1 n1-standard-2 1.13.5-gke.10 4 RUNNING
kubectlコマンドライン ツールに認証情報を提供して、クラスタの管理に使用できるようにします。gcloud container clusters get-credentials asm-readyこれで、
kubectlを使用して Kubernetes と通信できるようになりました。たとえば、次のコマンドを実行してノードのステータスを取得できます。kubectl get nodesこのコマンドは、次のようなノードのリストを返します。
NAME STATUS ROLES AGE VERSION gke-asm-ready-default-pool-dbeb23dc-1vg0 Ready <none> 99s v1.13.6-gke.13 gke-asm-ready-default-pool-dbeb23dc-36z5 Ready <none> 100s v1.13.6-gke.13 gke-asm-ready-default-pool-dbeb23dc-fj7s Ready <none> 99s v1.13.6-gke.13 gke-asm-ready-default-pool-dbeb23dc-wbjw Ready <none> 99s v1.13.6-gke.13
Kubernetes の主なコンセプトを理解する
次の図は、GKE で実行されるアプリケーションを示しています。
コンテナを GKE にデプロイする前に、Kubernetes の主なコンセプトを確認しておきましょう。このチュートリアルの最後には、各コンセプトの詳細を確認するためのリンクが用意されています。
ノードとクラスタ: GKE では、ノードは VM です。その他の Kubernetes プラットフォームでは、ノードは物理マシンまたは仮想マシンになります。クラスタとは、1 つのマシンとしてひとまとめに処理できる一連のノードのことで、コンテナ化されたアプリケーションをデプロイする場所になります。
Pod: Kubernetes では、コンテナは Pod 内で実行されます。Pod は Kubernetes の最小単位です。Pod は 1 つ以上のコンテナを保持します。
serverコンテナとloadgenコンテナをそれぞれ独自の Pod にデプロイします。Pod で複数のコンテナ(たとえば、アプリケーション サーバーとプロキシ サーバー)が実行される場合、コンテナは単一のエンティティとして管理され、Pod のリソースを共有します。Deployment: Deployment は、一連の同一の Pod を表す Kubernetes オブジェクトです。Deployment は、クラスタのノード間で分散された Pod の複数のレプリカを実行します。Deployment は、失敗した Pod や応答しなくなった Pod を自動的に置き換えます。
Kubernetes Service: GKE でアプリケーション コードを実行すると、
loadgenとserverの間のネットワーキングが変更されます。Cloud Shell VM でサービスを実行するとき、アドレスlocalhost:8080を使用してserverにリクエストを送信できます。GKE にデプロイすると、Pod は使用可能なノードで走行するようにスケジュールされます。デフォルトでは、Pod を実行するノードを制御できないため、Pod には安定した IP アドレスがありません。serverの IP アドレスを取得するには、Kubernetes Service と呼ばれる、Pod に対するネットワーク抽象化を定義する必要があります。Kubernetes Service は、一連の Pod に安定したネットワーク エンドポイントを提供します。Service にはいくつかの種類があります。クラスタの外部からserverにアクセスできるように、serverは外部 IP アドレスを公開するLoadBalancerを使用します。Kubernetes には組み込みの DNS システムもあります。これは DNS 名(たとえば、
helloserver.default.cluster.local)を Service に割り当てます。これにより、クラスタ内の Pod が安定したアドレスでクラスタ内の他の Pod にアクセスできます。この DNS 名は、Cloud Shell などクラスタの外部からは使用できません。
Kubernetes マニフェスト
ソースコードからアプリケーションを実行したとき、命令型コマンド python3 server.py を使用しました。
命令型とは、「これをしろ」のような動詞駆動という意味です。
対照的に、Kubernetes は宣言型モデルで動作します。つまり、Kubernetes には、実際の処理を指示するのではなく、望ましい状態を提示します。たとえば、実際のシステム状態が望ましい状態になるように、Kubernetes は必要に応じて Pod を起動または停止します。
望ましい状態は、一連のマニフェスト、YAML ファイルで指定します。YAML ファイルには、1 つ以上の Kubernetes オブジェクトの仕様が含まれています。
このサンプルには、server と loadgen のための YAML ファイルが含まれています。各 YAML ファイルは、Kubernetes Deployment オブジェクトと Service に対して望ましい状態を指定します。
サーバー
kindはオブジェクトの種類を示します。metadata.nameで Deployment の名前を指定します。- 最初の
specフィールドには、望ましい状態の説明が含まれています。 spec.replicasで目的の Pod の数を指定します。spec.templateセクションで Pod テンプレートを定義します。Pod の仕様には、Container Registry から pull するイメージの名前であるimageフィールドが含まれています。
Service は、次のように定義されます。
LoadBalancer: クライアントは、安定した IP アドレスを持ち、クラスタの外部からアクセス可能なネットワーク ロードバランサの IP アドレスにリクエストを送信します。targetPort:DockerfileのEXPOSE 8080コマンドでは実際にはポートが公開されないことに注意してください。ポート8080を公開して、クラスタの外部にあるserverコンテナにアクセスできるようにします。この場合、hellosvc.default.cluster.local:80(略称:hellosvc)はhelloserverPod IP のポート8080にマッピングされます。port: クラスタ内の他のサービスでリクエストを送信するときに使用するポート番号です。
負荷生成ツール
loadgen.yaml の Deployment オブジェクトは server.yaml に類似します。大きな違いとして、Deployment オブジェクトには env というセクションが含まれています。このセクションでは、以前にソースからアプリケーションを実行したときに設定した loadgen で必要とされる環境変数を定義します。
loadgen は受信リクエストを受け付けないため、type フィールドは ClusterIP に設定されます。このタイプはクラスタ内のサービスが使用できる安定した IP アドレスを提供しますが、その IP アドレスは外部クライアントには公開されません。
コンテナを GKE にデプロイする
サンプル
serverがあるディレクトリに移動します。cd YOUR_WORKING_DIRECTORY/anthos-service-mesh-samples/docs/helloserver/server/
テキスト エディタで
server.yamlを開きます。imageフィールド内の名前を Docker イメージの名前に置き換えます。image: gcr.io/PROJECT_ID/asm-ready/helloserver:v0.0.1
PROJECT_IDは、実際の Google Cloud プロジェクト ID に置き換えます。server.yamlを保存して閉じます。YAML ファイルを Kubernetes にデプロイします。
kubectl apply -f server.yaml成功すると、コマンドは次のレスポンスを返します。
deployment.apps/helloserver created service/hellosvc created
loadgenがあるディレクトリに移動します。cd ../loadgenテキスト エディタで
loadgen.yamlを開きます。imageフィールド内の名前を Docker イメージの名前に置き換えます。image: gcr.io/PROJECT_ID/asm-ready/loadgen:v0.0.1
PROJECT_IDは、実際の Google Cloud プロジェクト ID に置き換えます。loadgen.yamlを保存して閉じ、テキスト エディタを閉じます。YAML ファイルを Kubernetes にデプロイします。
kubectl apply -f loadgen.yaml成功すると、コマンドは次のレスポンスを返します。
deployment.apps/loadgenerator created service/loadgensvc created
Pod のステータスを確認します。
kubectl get podsこのコマンドは、次のようなステータスを返します。
NAME READY STATUS RESTARTS AGE helloserver-69b9576d96-mwtcj 1/1 Running 0 58s loadgenerator-774dbc46fb-gpbrz 1/1 Running 0 57s
loadgenPod からアプリケーション ログを取得します。POD_IDは、前の出力の ID に置き換えます。kubectl logs loadgenerator-POD_ID
hellosvcの外部 IP アドレスを取得します。kubectl get serviceコマンドのレスポンスは次のようになります。
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE hellosvc LoadBalancer 10.81.15.158 192.0.2.1 80:31127/TCP 33m kubernetes ClusterIP 10.81.0.1 <none> 443/TCP 93m loadgensvc ClusterIP 10.81.15.155 <none> 80/TCP 4m52s
hellosvcにリクエストを送信します。EXTERNAL_IPはhellosvcの外部 IP アドレスに置き換えます。curl http://EXTERNAL_IP
Cloud Service Mesh の準備
これで、GKE にアプリケーションがデプロイされました。Kubernetes DNS(hellosvc:80)を使用した loadgen による server へのリクエスト送信や、外部 IP アドレスを使用したユーザーによる server へのリクエスト送信が可能です。Kubernetes には多くの機能が用意されていますが、サービスに関する一部の情報が不足しています。
- サービス間のやり取りはどのように行われるのか。サービス間の関係とは何か。トラフィックはサービス間でどのように流れるか。
loadgenがserverにリクエストを送信するという知識はあっても、アプリケーションには精通していないかもしれません。GKE で実行中の Pod のリストを確認しても、こうした疑問に対する答えは得られません。 - 指標:
serverは受信したリクエストに応答するまでにどれくらいかかるか。serverが受信するリクエストの 1 秒あたりの件数(RPS)はいくつか。エラー レスポンスはあるか。 - セキュリティ情報:
loadgenとserverプレーン間のトラフィックはHTTPか mTLS か。
Cloud Service Mesh は、こうした疑問を解決できます。Cloud Service Mesh は、オープンソースの Istio プロジェクトの Google Cloudマネージド バージョンです。Cloud Service Mesh は、各 Pod に Envoy サイドカー プロキシを配置することで機能します。Envoy プロキシは、アプリケーション コンテナへのすべての受信トラフィックと送信トラフィックを傍受します。つまり、server と loadgen はそれぞれ Envoy サイドカー プロキシを取得し、loadgen から server へのすべてのトラフィックは Envoy プロキシによって仲介されます。これらの Envoy プロキシ間の接続がサービス メッシュを形成します。このサービス メッシュ アーキテクチャは、Kubernetes の上に制御レイヤを提供します。
Envoy プロキシは各自のコンテナ内で実行されるため、アプリケーション コードに大きな変更を加えることなく、Cloud Service Mesh を GKE クラスタ上にインストールできます。ただし、Cloud Service Mesh でインストゥルメント化するためにアプリケーションを準備するには、いくつかの重要なポイントがあります。
- すべてのコンテナのサービス:
serverとloadgenの両方の Deployment に Kubernetes サービスが接続されています。受信リクエストを受信しないloadgenにも、サービスがあります。 - サービスのポートには名前を付ける必要がある: GKE では名前のないサービスポートを定義できますが、Cloud Service Mesh ではポートのプロトコルと一致するポートの名前を指定する必要があります。YAML ファイルでは、
serverはHTTP通信プロトコルを使用するため、server用のポートはhttpという名前になります。serviceがgRPCを使用した場合は、ポートにgrpcと名付けます。 - Deployment がラベル付けされる: これにより、同じサービスの複数のバージョン間でトラフィックを分割するなど、Cloud Service Mesh のトラフィック管理機能を使用できます。
Cloud Service Mesh をインストールする
Cloud Service Mesh のインストール ガイドの手順で、クラスタに Cloud Service Mesh をインストールします。
クリーンアップ
このチュートリアルで使用したリソースについて、Google Cloud アカウントに課金されないようにするには、リソースを含むプロジェクトを削除するか、プロジェクトを維持して個々のリソースを削除します。
クリーンアップするには、GKE クラスタを削除します。クラスタの削除では、コンテナ クラスタを構成するすべてのリソース(コンピューティング インスタンス、ディスク、ネットワーク リソースなど)が削除されます。
gcloud container clusters delete asm-ready
次のステップ
このチュートリアルで使用した技術について詳しく学習します。
以下のツールついて詳しく学習します。
Kubernetes のコンセプトについて詳しく学習します。