1. はじめに
ウェブサイトやアプリケーションの運営は簡単ではありません。
予期せぬ問題が起きたり、サーバーがクラッシュしたり、需要の増加によって利用されるリソースが増加したりします。また、ダウンタイムなしで変更を加えるのは複雑でストレスがかかります。
これらすべてに役立ち、自動化もできるツールを想像してみてください。GKE を使用すれば、これらすべてが可能なだけでなく、簡単に実現できます。この Codelab では、架空の会社 Fancy Store で e コマース ウェブサイトを運営するデベロッパーの役割を前提としています。スケーリングとサービス停止の問題により、アプリケーションを GKE にデプロイする必要があります。
ここでは、一般的なクラウド デベロッパーのエクスペリエンスに沿って次の順序で演習を進めます。
- GKE クラスタを作成する。
- Docker コンテナを作成する。
- コンテナを GKE にデプロイする。
- サービスを介してコンテナを公開する。
- コンテナを複数のレプリカにスケーリングする。
- ウェブサイトを変更する。
- ダウンタイムなしで新しいバージョンをロールアウトします。
アーキテクチャの図
学習内容
- GKE クラスタの作成方法
- Docker イメージの作成方法
- Docker イメージを Kubernetes にデプロイする方法
- Kubernetes でアプリケーションをスケーリングする方法
- Kubernetes でローリング アップデートを実行する方法
前提条件
- プロジェクトを作成するための管理者権限を持つ Google アカウント、またはプロジェクト オーナーのロールを持つプロジェクト
- Docker と Kubernetes の基本知識(基礎知識がない場合は、Docker と Kubernetes を復習してください)
2. 環境のセットアップ
セルフペース型の環境設定
Google アカウントをまだお持ちでない場合は、アカウントを作成してください。Google Cloud コンソールにログインして、新しいプロジェクトを作成します。
プロジェクト ID は、すべての Google Cloud プロジェクトで一意の名前であることにご注意ください(上の名前はすでに使用されているため、使用できません)。これ以降は PROJECT_ID
と呼びます。
次に、Google Cloud リソースを使用するために、Cloud コンソールで課金を有効にする必要があります。Google Cloud の新規ユーザーは、$300 分の無料トライアルをご利用いただけます。この Codelab の費用は数ドル以内なので、新規ユーザーでなくても心配はいりません。ただし、この Codelab では、使用するリソースを増やしたり、実行したままにしたりすると、費用が増える可能性があります(最後の「クリーンアップ」セクションをご覧ください)。詳細は、料金をご覧ください。
Cloud Shell
ノートパソコンを使って Google Cloud と GKE をリモートで操作することもできますが、この Codelab では Cloud Shell(Google Cloud で実行されるコマンドライン環境)を使用します。
この Debian ベースの仮想マシンには、必要な開発ツールがすべて揃っています。永続的なホーム ディレクトリが 5 GB 用意されており、Google Cloud で稼働するため、ネットワークのパフォーマンスと認証が大幅に向上しています。つまり、この Codelab に必要なのはブラウザだけです(はい、Chromebook で動作します)。
- Cloud Console から Cloud Shell を有効にするには、[Cloud Shell をアクティブにする] をクリックします(環境のプロビジョニングと接続に若干時間を要します)。
Cloud Shell に接続すると、すでに認証は完了しており、プロジェクトに各自の PROJECT_ID
が設定されていることがわかります。
gcloud auth list
コマンド出力
Credentialed accounts: - <myaccount>@<mydomain>.com (active)
gcloud config list project
コマンド出力
[core] project = <PROJECT_ID>
なんらかの理由でプロジェクトが設定されていない場合は、次のコマンドを実行します。
gcloud config set project <PROJECT_ID>
PROJECT_ID
が見つからない場合は、設定手順で使用した ID を確認するか、Cloud コンソール ダッシュボードで確認します。
Cloud Shell では、デフォルトで環境変数もいくつか設定されます。これらの変数は、以降のコマンドを実行する際に有用なものです。
echo $GOOGLE_CLOUD_PROJECT
コマンド出力
<PROJECT_ID>
- 最後に、デフォルトのゾーンとプロジェクト構成を設定します。
gcloud config set compute/zone us-central1-f
さまざまなゾーンを選択できます。詳しくは、リージョンとゾーン。
3. GKE クラスタを作成する
作業用の開発環境が整ったので、ウェブサイトをデプロイする GKE クラスタが必要です。クラスタを作成する前に、適切な API が有効になっていることを確認する必要があります。次のコマンドを実行して、コンテナ API を有効にします。
gcloud services enable container.googleapis.com
これで、クラスタを作成できるようになりました。以下の手順に沿って、3 つのノードを持つ fancy-cluster という名前のクラスタを作成します。
gcloud container clusters create fancy-cluster --num-nodes 3
クラスタの作成には数分かかることがあります。その後、次のコマンドを実行して、クラスタの 3 つのワーカー仮想マシン(VM)インスタンスを確認します。
gcloud compute instances list
出力:
NAME ZONE MACHINE_TYPE PREEMPTIBLE INTERNAL_IP EXTERNAL_IP STATUS gke-fancy-cluster-default-pool-ad92506d-1ng3 us-east4-a n1-standard-1 10.150.0.7 XX.XX.XX.XX RUNNING gke-fancy-cluster-default-pool-ad92506d-4fvq us-east4-a n1-standard-1 10.150.0.5 XX.XX.XX.XX RUNNING gke-fancy-cluster-default-pool-ad92506d-4zs3 us-east4-a n1-standard-1 10.150.0.6 XX.XX.XX.XX RUNNING
Cloud コンソールでクラスタと関連情報を確認することもできます。左上のメニューボタンをクリックし、[Kubernetes Engine] まで下にスクロールして、[クラスタ] をクリックします。fancy-cluster というクラスタが表示されます。
これで、最初のクラスタが作成されました。
4. ソース リポジトリのクローンを作成する
これは既存のウェブサイトであるため、リポジトリからソースのクローンを作成するだけで、Docker イメージの作成と GKE へのデプロイに集中できます。
次のコマンドを実行して、ソース リポジトリのクローンを Cloud Shell インスタンスに作成し、適切なディレクトリに移動します。また、Node.js の依存関係もインストールするので、アプリケーションをデプロイする前にテストできます。
cd ~ git clone https://github.com/googlecodelabs/monolith-to-microservices.git cd ~/monolith-to-microservices ./setup.sh
これにより、リポジトリのクローンが作成され、ディレクトリが変更され、アプリケーションをローカルで実行するために必要な依存関係がインストールされます。スクリプトの実行には数分かかる場合があります。
デュー デリジェンスを実施し、アプリケーションをテストしてください。次のコマンドを実行して、ウェブサーバーを起動します。
cd ~/monolith-to-microservices/monolith npm start
出力:
Monolith listening on port 8080!
アプリケーションをプレビューするには、Cloud Shell メニューで「ウェブでプレビュー」アイコンをクリックし、[ポート 8080 でプレビュー] を選択します。
新しいウィンドウが開き、動作中の Fancy Store が表示されます。
ウェブサイトを閲覧した後、このウィンドウは閉じることができます。ターミナル ウィンドウで Control+C
(Windows または Mac)を押してウェブサーバー プロセスを停止します。
5. Cloud Build を使用して Docker コンテナを作成する
ソースファイルを使用できる状態になったので、次はアプリケーションを Docker 化します。
通常は、Docker コンテナを構築し、それをレジストリに push して GKE が pull するイメージを保存するという 2 段階のアプローチを取る必要があります。ただし、Cloud Build を使用して 1 つのコマンドで Docker コンテナを作成し、イメージを Container Registry に配置することで、作業を楽にすることができます。(手動で Docker ファイルを作成して push するプロセスを確認するには、Container Registry のクイックスタートをご覧ください)。
Cloud Build は、ディレクトリにあるファイルを圧縮して Cloud Storage バケットに移動します。次に、ビルドプロセスでバケットからファイルを取得し、Dockerfile を使用して Docker ビルドプロセスを実行します。Docker イメージのホストを gcr.io
として --tag
フラグを指定したため、生成された Docker イメージは Container Registry に push されます。
まず、次のコマンドを実行して Cloud Build API を有効にする必要があります。
gcloud services enable cloudbuild.googleapis.com
API が有効になったら、Cloud Shell で次のコマンドを実行してビルドプロセスを開始します。
cd ~/monolith-to-microservices/monolith gcloud builds submit --tag gcr.io/${GOOGLE_CLOUD_PROJECT}/monolith:1.0.0 .
このプロセスには数分かかります。完了すると、ターミナルに次の出力が表示されます。
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ID CREATE_TIME DURATION SOURCE IMAGES STATUS 1ae295d9-63cb-482c-959b-bc52e9644d53 2019-08-29T01:56:35+00:00 33S gs://<PROJECT_ID>_cloudbuild/source/1567043793.94-abfd382011724422bf49af1558b894aa.tgz gcr.io/<PROJECT_ID>/monolith:1.0.0 SUCCESS
ビルド履歴を表示したり、プロセスをリアルタイムで確認したりするには、Cloud コンソールに移動します。左上のメニューボタンをクリックして [CI/CD] までスクロールし、[Cloud Build]、[履歴] の順にクリックします。以前のビルドのリストが表示されますが、ここには作成したビルドのみが表示されるはずです。
[Build id] をクリックすると、そのビルドのすべての詳細が表示されます。詳細にはログ出力も含まれます。
[ビルドの詳細] ページで、ビルド情報セクションの [イメージ] 名をクリックすると、作成されたコンテナ イメージが表示されます。
6. コンテナを GKE にデプロイする
ウェブサイトをコンテナ化して、そのコンテナを Container Registry に push したので、次はコンテナを Kubernetes にデプロイできます。
GKE クラスタにアプリケーションをデプロイして管理するには、Kubernetes クラスタ管理システムと通信する必要があります。これには通常、kubectl コマンドライン ツールを使用します。
Kubernetes では、アプリケーションは Pod として表されます。Pod は、1 つのコンテナ(または密結合されたコンテナのグループ)を表す単位です。Pod は、Kubernetes でデプロイ可能な最小単位です。ここでは、各 Pod には monolith コンテナのみが含まれています。
アプリケーションをデプロイするには、Deployment を作成する必要があります。Deployment は、アプリケーションの複数のコピー(レプリカと呼ばれる)を管理し、クラスタ内の個々のノードで実行されるようにスケジュールします。この場合、Deployment はアプリケーションの 1 つの Pod のみを実行します。Deployment は、ReplicaSet を作成することによって、これを実現します。ReplicaSet の役割は、指定された数のレプリカが常に実行されるようにすることです。
kubectl create deployment
コマンドを実行すると、Kubernetes は、1 個のレプリカを持つクラスタに monolith という名前の Deployment を作成します。
次のコマンドを実行して、アプリケーションをデプロイします。
kubectl create deployment monolith --image=gcr.io/${GOOGLE_CLOUD_PROJECT}/monolith:1.0.0
デプロイメントを確認する
次のコマンドを実行して、Deployment が正常に作成されたことを確認します(Pod のステータスが「Running」になるまで少し時間がかかることがあります)。
kubectl get all
出力:
NAME READY STATUS RESTARTS AGE pod/monolith-7d8bc7bf68-htm7z 1/1 Running 0 6m21s NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/kubernetes ClusterIP 10.27.240.1 <none> 443/TCP 24h NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE deployment.apps/monolith 1 1 1 1 20m NAME DESIRED CURRENT READY AGE replicaset.apps/monolith-7d8bc7bf68 1 1 1 20m
この出力から、いくつかのことがわかります。現在の Deployment が表示されます。目的の Pod 数が 1 の ReplicaSet。そして実行中の Pod です。すべて正常に作成されたようです。
リソースを個別に表示するには、次のコマンドを実行します。
# Show pods kubectl get pods # Show deployments kubectl get deployments # Show replica sets kubectl get rs #You can also combine them kubectl get pods,deployments
サーバー クラッシュをシミュレートし、Pod を削除して、どうなるかを確認して、Kubernetes のメリットをすべて確かめましょう。
前のコマンドで取得した Pod 名をコピーし、次のコマンドを実行して削除します。
kubectl delete pod/<POD_NAME>
十分な速さが得られた場合は、前のコマンドを実行してもう一度すべてを表示できます。2 つの Pod(1 つは終了し、もう 1 つは作成中または実行中)が表示されます。
kubectl get all
出力:
NAME READY STATUS RESTARTS AGE pod/monolith-7d8bc7bf68-2bxts 1/1 Running 0 4s pod/monolith-7d8bc7bf68-htm7z 1/1 Terminating 0 9m35s NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/kubernetes ClusterIP 10.27.240.1 <none> 443/TCP 24h NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE deployment.apps/monolith 1 1 1 1 24m NAME DESIRED CURRENT READY AGE replicaset.apps/monolith-7d8bc7bf68 1 1 1 24m
なぜそのようなことが起きたのでしょうか?Pod の終了を検出した ReplicaSet が、目的のレプリカ数を維持するために新しい Pod をトリガーしたからです。後ほど、複数のインスタンスを実行して、1 つのインスタンスがダウンしてもユーザーのダウンタイムが発生しないようにスケールする方法を紹介します。
7. GKE Deployment を公開する
アプリケーションを GKE にデプロイしましたが、クラスタの外部からアクセスする方法がありません。GKE で実行するコンテナには外部 IP アドレスがないため、デフォルトでは、このコンテナにインターネットからアクセスすることはできません。Service リソースを使用して、アプリケーションをインターネットからのトラフィックに明示的に公開する必要があります。Service は、アプリの Pod にネットワーキングと IP サポートを提供します。GKE は、アプリの外部 IP とロードバランサ(課金対象)を作成します。
次のコマンドを実行して、ウェブサイトをインターネットに公開します。
kubectl expose deployment monolith --type=LoadBalancer --port 80 --target-port 8080
出力:
service/monolith exposed
サービスへのアクセス
GKE は、Deployment ではなく Service リソースに外部 IP アドレスを割り当てます。GKE によってアプリケーション用にプロビジョニングされた外部 IP を確認するには、kubectl get service コマンドを使用して Service を調べます。
kubectl get service
出力:
NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE monolith 10.3.251.122 203.0.113.0 80:30877/TCP 3d
アプリの外部 IP アドレスを確認したら、それをコピーします。ブラウザでその URL(http://203.0.113.0 など)にアクセスして、アプリにアクセスできるかどうかを確認します。
先ほどテストしたときと同じウェブサイトが表示されるはずです。これで、あなたのウェブサイトは Kubernetes で完全に稼働しています。
8. GKE Deployment をスケーリングする
アプリのインスタンスが GKE で実行され、インターネットに公開されたことで、ウェブサイトへのアクセスが急増しました。トラフィックを処理できるように、アプリを複数のインスタンスにスケーリングする方法が必要です。アプリケーションを最大 3 つのレプリカにスケーリングする方法について説明します。
次のコマンドを実行して、Deployment を 3 つのレプリカにスケーリングします。
kubectl scale deployment monolith --replicas=3
出力:
deployment.apps/monolith scaled
スケーリングされたデプロイを確認する
Deployment が正常にスケーリングされたことを確認するには、次のコマンドを実行します。
kubectl get all
出力:
NAME READY STATUS RESTARTS AGE pod/monolith-7d8bc7bf68-2bxts 1/1 Running 0 36m pod/monolith-7d8bc7bf68-7ds7q 1/1 Running 0 45s pod/monolith-7d8bc7bf68-c5kxk 1/1 Running 0 45s NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/kubernetes ClusterIP 10.27.240.1 <none> 443/TCP 25h service/monolith LoadBalancer 10.27.253.64 XX.XX.XX.XX 80:32050/TCP 6m7s NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE deployment.apps/monolith 3 3 3 3 61m NAME DESIRED CURRENT READY AGE replicaset.apps/monolith-7d8bc7bf68 3 3 3 61m
Pod の 3 つのインスタンスが実行されていることがわかります。また、Deployment と ReplicaSet の必要数が 3 になっていることにも注目してください。
9. ウェブサイトに変更を加える
マーケティング チームから、ウェブサイトのホームページを変更するよう依頼されました。同社は、会社の概要と実際に販売しているものを説明することで、より有益な情報を提供するべきだと考えています。このセクションでは、マーケティング チームの満足度を高めるために、ホームページにテキストを追加します。Google のデベロッパーの 1 人が、index.js.new
という名前のファイルですでに変更を作成したようです。ファイルを index.js
にコピーすると、変更が反映されます。以下の手順に沿って適切な変更を行います。
次のコマンドを実行し、更新したファイルを正しいファイル名でコピーし、その内容を出力して変更を確認します。
cd ~/monolith-to-microservices/react-app/src/pages/Home mv index.js.new index.js cat ~/monolith-to-microservices/react-app/src/pages/Home/index.js
変更後のコードは次のようになっています。
/* Copyright 2019 Google LLC Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ import React from "react"; import { makeStyles } from "@material-ui/core/styles"; import Paper from "@material-ui/core/Paper"; import Typography from "@material-ui/core/Typography"; const useStyles = makeStyles(theme => ({ root: { flexGrow: 1 }, paper: { width: "800px", margin: "0 auto", padding: theme.spacing(3, 2) } })); export default function Home() { const classes = useStyles(); return ( <div className={classes.root}> <Paper className={classes.paper}> <Typography variant="h5"> Fancy Fashion & Style Online </Typography> <br /> <Typography variant="body1"> Tired of mainstream fashion ideas, popular trends and societal norms? This line of lifestyle products will help you catch up with the Fancy trend and express your personal style. Start shopping Fancy items now! </Typography> </Paper> </div> ); }
これで React コンポーネントは更新されましたが、React アプリをビルドして静的ファイルを生成する必要があります。次のコマンドを実行して React アプリをビルドし、monolith の公開ディレクトリにコピーします。
cd ~/monolith-to-microservices/react-app npm run build:monolith
コードが更新されたので、次は Docker コンテナを再ビルドして Container Registry に公開する必要があります。前と同じコマンドを使用できますが、今回はバージョン ラベルを更新します。
次のコマンドを実行し、更新後のイメージ バージョン 2.0.0 を指定して新しい Cloud Build をトリガーします。
cd ~/monolith-to-microservices/monolith #Feel free to test your application npm start gcloud builds submit --tag gcr.io/${GOOGLE_CLOUD_PROJECT}/monolith:2.0.0 .
ターミナル ウィンドウで Control+C
(Windows または Mac)を押してウェブサーバー プロセスを停止します。
次のセクションでは、そのイメージを使用して、ダウンタイムなしでアプリケーションを更新します。
10. ダウンタイムなしでウェブサイトを更新する
変更が完了し、マーケティング チームも更新内容に満足してくれました。次は、ユーザーへのサービスを中断させずにウェブサイトを更新します。以下の手順に沿ってウェブサイトを更新してください。
GKE のローリング アップデートにより、実行中のすべてのレプリカで古いコンテナ イメージのインスタンスを新しいコンテナ イメージのインスタンスがシステムによって置き換えられた場合でも、アプリケーションは稼働状態を維持します。
Deployment のイメージを新しいバージョンに更新するよう Kubernetes に指示するには、コマンドラインで次のコマンドを使用します。
kubectl set image deployment/monolith monolith=gcr.io/${GOOGLE_CLOUD_PROJECT}/monolith:2.0.0
出力:
deployment.apps/monolith image updated
Deployment を確認する
Deployment の更新を検証するには、次のコマンドを実行します。
kubectl get pods
出力:
NAME READY STATUS RESTARTS AGE monolith-584fbc994b-4hj68 1/1 Terminating 0 60m monolith-584fbc994b-fpwdw 1/1 Running 0 60m monolith-584fbc994b-xsk8s 1/1 Terminating 0 60m monolith-75f4cf58d5-24cq8 1/1 Running 0 3s monolith-75f4cf58d5-rfj8r 1/1 Running 0 5s monolith-75f4cf58d5-xm44v 0/1 ContainerCreating 0 1s
3 つの新しい Pod が作成され、古い Pod がシャットダウンされます。どの年齢が新しいか、どの古いかがわかります。最終的には、再び 3 つの Pod(更新された 3 つの Pod)のみが表示されます。
変更を確認するには、ロードバランサの外部 IP に再度アクセスして、アプリが更新されたことを確認します。
次のコマンドを実行してサービスを一覧表示し、IP アドレスを忘れた場合は確認します。
kubectl get svc
ウェブサイトには、ホームページ コンポーネントに追加したテキストが表示されます。
11. クリーンアップ
Git リポジトリを削除する
cd ~ rm -rf monolith-to-microservices
Container Registry イメージを削除する
注: 他のバージョンを作成した場合は、同じ構文を使用してそれらのイメージも削除できます。この Codelab では、タグが 2 つしかないことを前提としています。
# Delete the container image for version 1.0.0 of our monolith gcloud container images delete gcr.io/${GOOGLE_CLOUD_PROJECT}/monolith:1.0.0 --quiet # Delete the container image for version 2.0.0 of our monolith gcloud container images delete gcr.io/${GOOGLE_CLOUD_PROJECT}/monolith:2.0.0 --quiet
Cloud Storage から Cloud Build アーティファクトを削除する
注: この Codelab 以外のアーティファクトに Cloud Build を使用した場合は、Cloud Storage バケット gs://<PROJECT_ID>_cloudbuild/source
からソースを手動で削除する必要があります。
# The following command will take all source archives from all builds and delete them from cloud storage # Run this command to print all sources: # gcloud builds list | awk 'NR > 1 {print $4}' gcloud builds list | awk 'NR > 1 {print $4}' | while read line; do gsutil rm $line; done
GKE サービスを削除する
kubectl delete service monolith kubectl delete deployment monolith
GKE クラスタを削除
gcloud container clusters delete fancy-cluster
注: このコマンドには少し時間がかかる場合があります。
12. 完了
GKE でウェブサイトのデプロイ、スケーリング、更新を行いました。これで、Docker と Kubernetes の操作に慣れました。