Cloud Service Mesh は、分散アプリケーションを管理し、モニタリングするための強力なツールです。Cloud Service Mesh を最大限に活用するには、コンテナと Kubernetes を含む基盤となる抽象概念の理解が役に立ちます。このチュートリアルでは、Cloud Service Mesh をインストールする直前までに、Cloud Service Mesh をインストールするアプリケーション(ソースコードから GKE 上で実行されるコンテナまで)を準備する方法について説明します。
Kubernetes とサービス メッシュのコンセプトにすでに精通している場合は、このチュートリアルをスキップして Cloud Service Mesh のインストール ガイドに進んでください。
目標
- シンプルなマルチサービス「Hello World」アプリケーションを探索する。
- ソースからアプリケーションを実行する
- アプリケーションをコンテナ化する。
- Kubernetes クラスタを作成する。
- コンテナをクラスタにデプロイする。
始める前に
次の手順に沿って Cloud Service Mesh API を有効にします。- Google Cloud コンソールで [Kubernetes Engine] ページにアクセスします。
- プロジェクトを作成または選択します。
- API と関連サービスが有効になるのを待ちます。 これには数分かかることがあります。
-
Make sure 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.
At the bottom of the Google Cloud console, a Cloud Shell session starts and displays a command-line prompt. Cloud Shell is a shell environment with the Google Cloud CLI already installed and with values already set for your current project. It can take a few seconds for the session to initialize.
サンプルコードをダウンロードする
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:8080
server
が応答します。Hello World!
サンプルコードをダウンロードしたディレクトリから、
loadgen
を含むディレクトリに移動します。cd YOUR_WORKING_DIRECTORY/anthos-service-mesh-samples/docs/helloserver/loadgen
次の環境変数を作成します。
export SERVER_ADDR=http://localhost:8080 export REQUESTS_PER_SECOND=5
virtualenv
を開始します。virtualenv --python python3 env
仮想環境をアクティブにします。
source env/bin/activate
loadgen
の要件をインストールします。pip3 install -r requirements.txt
loadgen
を実行します。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-b
Google 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
)はhelloserver
Pod 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
loadgen
Pod からアプリケーション ログを取得します。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 のコンセプトについて詳しく学習します。