Redis と PHP を使用したゲストブックの作成

このチュートリアルでは、GKE を使用して簡単な多層ウェブ アプリケーションを構築する方法を説明します。チュートリアル アプリケーションとして使用するゲストブックでは、訪問者がログにテキストを入力し、最新のログエントリを何件か見ることができます。

このチュートリアルでは、ロードバランサを使用して外部 IP にゲストブック ウェブサービスを設定する方法、および単一のマスターと複数のワーカーを使用して Redis クラスタを実行する方法を説明します。

この例では GKE の重要なコンセプトをいくつか取り上げます。

  • 宣言型の構成: 構成には YAML マニフェスト ファイルを使用します
  • Deployments: 複製された一連の Pod の構成を決定する Kubernetes リソースです。
  • Service: 一連の Pod 用の内部および外部ロードバランサを作成します。

目標

GKE でゲストブック アプリケーションをデプロイして実行するには、次の手順に従う必要があります。

  1. Redis マスターの設定
  2. Redis ワーカーを設定します
  3. ゲストブック ウェブ フロントエンドを設定します
  4. ゲストブックのウェブサイトにアクセスします
  5. ゲストブック ウェブ フロントエンドをスケールアップします

始める前に

次の手順で Kubernetes Engine API を有効にします。
  1. Google Cloud Console で Kubernetes Engine ページにアクセスします。
  2. プロジェクトを作成または選択します。
  3. API と関連サービスが有効になるのを待ちます。 これには数分かかることがあります。
  4. Google Cloud プロジェクトに対して課金が有効になっていることを確認します。 プロジェクトに対して課金が有効になっていることを確認する方法を学習する

このチュートリアルで使用されている以下のコマンドライン ツールをインストールします。

  • gcloud は、Kubernetes Engine クラスタの作成と削除に使用されます。gcloud は、Google Cloud SDK に含まれています。
  • kubectl は、Kubernetes Engine で使用されるクラスタ オーケストレーション システムである Kubernetes の管理に使用されます。gcloud を使用して kubectl をインストールできます。
    gcloud components install kubectl

gcloud コマンドライン ツールのデフォルトの設定

次のようにしてデフォルト値を設定しておくと、gcloud コマンドライン ツールでプロジェクト ID および Compute Engine ゾーン オプションを入力する時間が節約されます。
    gcloud config set project [PROJECT_ID]
    gcloud config set compute/zone [COMPUTE_ENGINE_ZONE]

構成ファイルをダウンロードする

Kubernetes GitHub サンプル リポジトリにアクセスし、このチュートリアルで使用する構成ファイルをダウンロードします。

GKE クラスタを作成する

まず、ゲストブック アプリケーションと Redis サービスを実行する GKE クラスタを作成します。

2 ノードからなる guestbook という名前のコンテナ クラスタを作成します。

gcloud container clusters create guestbook --num-nodes=2

次のコマンドを使用すると、プロジェクト内のクラスタの一覧表示や、単一のクラスタの詳細の取得ができます。

gcloud container clusters list
    gcloud container clusters describe guestbook

ステップ 1: Redis マスターを設定する

ゲストブック アプリケーションは Redis を使用してデータを保存します。Redis マスター インスタンスにデータを書き込み、複数の Redis ワーカー(スレーブ)インスタンスからデータを読み取ります。最初のステップは、Redis マスターをデプロイすることです。

redis-master-deployment という名前のマニフェスト ファイルを使用して、Redis マスターをデプロイします。このマニフェスト ファイルで、単一のレプリカ Redis マスター Pod を実行する Deployment コントローラを指定します。

apiVersion: apps/v1 #  for k8s versions before 1.9.0 use apps/v1beta2  and before 1.8.0 use extensions/v1beta1
    kind: Deployment
    metadata:
      name: redis-master
    spec:
      selector:
        matchLabels:
          app: redis
          role: master
          tier: backend
      replicas: 1
      template:
        metadata:
          labels:
            app: redis
            role: master
            tier: backend
        spec:
          containers:
          - name: master
            image: k8s.gcr.io/redis:e2e  # or just image: redis
            resources:
              requests:
                cpu: 100m
                memory: 100Mi
            ports:
            - containerPort: 6379
    

次のコマンドを実行して、Redis マスターをデプロイします。

kubectl create -f redis-master-deployment.yaml

Redis マスター Pod が kubectl get pods を実行していることを確認します。

    kubectl get pods
    
出力:
    NAME                           READY     STATUS    RESTARTS   AGE
    redis-master-343230949-qfvrq   1/1       Running   0          43s
    

前のコマンドの出力から Pod 名をコピーし、次のコマンドを実行して Redis マスター Pod のログを確認します。

    kubectl logs -f [POD_NAME]
    

redis-master サービスの作成

ゲストブック アプリケーションは、データを書き込むために Redis マスターと通信する必要があります。Redis マスター Pod にトラフィックをプロキシする Service を作成する必要があります。

Service とは Kubernetes の抽象化機能の 1 つで、Pod の論理セットと、Pod へのアクセス時に準拠するポリシーを定義したものです。これは実質的に、トラフィックを 1 つまたは複数の Pod にプロキシする名前付きロードバランサといえます。Service を設定するときに、プロキシ先の Pod を Pod のラベルで指定します。

Redis マスターの Service リソースが記述されている redis-master-service.yaml マニフェスト ファイルを次に示します。

apiVersion: v1
    kind: Service
    metadata:
      name: redis-master
      labels:
        app: redis
        role: master
        tier: backend
    spec:
      ports:
      - port: 6379
        targetPort: 6379
      selector:
        app: redis
        role: master
        tier: backend
    

このマニフェスト ファイルは、ラベルセレクタのセットを使用して、redis-master という名前の Service を作成します。これらのラベルは、前のステップでデプロイしたラベルのセットと一致します。したがって、この Service は、ステップ 1 で作成した Redis マスター Pod にネットワーク トラフィックをルーティングします。

マニフェストの ports セクションでは、1 つのポート マッピングが宣言されています。この例では、port: 6379 上のトラフィックが、指定された selector ラベルと一致するコンテナの targetPort: 6379 にルーティングされます。Deployment にトラフィックをルーティングするには、Deployment で使用されている containerPorttargetPort と一致する必要があります。

次のコマンドを実行して、Redis マスターの Service を起動します。

    kubectl create -f redis-master-service.yaml
    

Service が作成されたことを確認します。

    kubectl get service
    
出力:
    NAME           CLUSTER-IP      EXTERNAL-IP   PORT(S)    AGE
    kubernetes     10.51.240.1     <none>        443/TCP    42s
    redis-master   10.51.242.233   <none>        6379/TCP   12s
    

ステップ 2: Redis ワーカーを設定する

Redis マスターは単一のポッドですが、少数の Redis ワーカー レプリカを追加することで、可用性を高め、トラフィックの需要を満たすことができます。

Redis ワーカーポッドの Deployment が記述されている redis-slave-deployment.yaml マニフェスト ファイルを次に示します。

apiVersion: apps/v1 #  for k8s versions before 1.9.0 use apps/v1beta2  and before 1.8.0 use extensions/v1beta1
    kind: Deployment
    metadata:
      name: redis-slave
    spec:
      selector:
        matchLabels:
          app: redis
          role: slave
          tier: backend
      replicas: 2
      template:
        metadata:
          labels:
            app: redis
            role: slave
            tier: backend
        spec:
          containers:
          - name: slave
            image: gcr.io/google_samples/gb-redisslave:v1
            resources:
              requests:
                cpu: 100m
                memory: 100Mi
            env:
            - name: GET_HOSTS_FROM
              value: dns
              # If your cluster config does not include a dns service, then to
              # instead access an environment variable to find the master
              # service's host, comment out the 'value: dns' line above, and
              # uncomment the line below:
              # value: env
            ports:
            - containerPort: 6379
    

デプロイを行うと、マニフェスト ファイルで宣言されている構成を実現されます。たとえば、このマニフェスト ファイルでは、Redis ワーカーの 2 つのレプリカが定義されています。実行中のレプリカがない場合、Deployment はコンテナ クラスタで 2 つのレプリカを開始します。3 つ以上のレプリカが実行中の場合は、指定された構成を満たすためにいくつかのレプリカを停止させます。

この例では、Deployment オブジェクトは 2 つのレプリカを指定します。Redis ワーカーの Deployment を作成するには、次のコマンドを実行します。

    kubectl create -f redis-slave-deployment.yaml
    

Pod のリストをクエリして、2 つの Redis ワーカー レプリカが実行されていることを確認します。

    kubectl get pods
    
出力:
    NAME                           READY     STATUS    RESTARTS   AGE
    redis-master-343230949-qfvrq   1/1       Running   0          17m
    redis-slave-132015689-dp23k    1/1       Running   0          2s
    redis-slave-132015689-xq9v0    1/1       Running   0          2s
    

redis-slave サービスの作成

ゲストブック アプリケーションは、データを読み取るために Redis ワーカーと通信する必要があります。Redis ワーカーを検出可能にするには、Service を設定する必要があります。Service は、一連の Pod に対して透過的な負荷分散を提供します。

redis-slave-service.yaml は、Redis ワーカーの Service 構成を定義します。

apiVersion: v1
    kind: Service
    metadata:
      name: redis-slave
      labels:
        app: redis
        role: slave
        tier: backend
    spec:
      ports:
      - port: 6379
      selector:
        app: redis
        role: slave
        tier: backend
    

このファイルは、ポート 6379 で実行される redis-slave という名前の Service を定義します。Service の selector フィールドは、前のステップで作成した Redis ワーカー Pod と一致することに注意してください。

次のコマンドを実行して redis-slave Service を作成します。

    kubectl create -f redis-slave-service.yaml
    

Service が作成されたことを確認します。

    kubectl get service
    
出力:
    NAME           CLUSTER-IP      EXTERNAL-IP   PORT(S)    AGE
    kubernetes     10.51.240.1     <none>        443/TCP    1m
    redis-master   10.51.242.233   <none>        6379/TCP   49s
    redis-slave    10.51.247.238   <none>        6379/TCP   3s
    

ステップ 3: ゲストブックのウェブ フロントエンドを設定する

ゲストブックの Redis ストレージが稼働したので、次にゲストブックのウェブサーバーを起動します。Redis ワーカーと同様、これは Deployment によって管理される複製されたアプリケーションです。

このチュートリアルでは簡単な PHP フロントエンドを使用します。フロントエンドは、リクエストが読み取りか書き込みかに応じて、Redis ワーカー Service またはマスター Service と通信するように構成されます。フロントエンドは簡単な JSON インターフェースを公開し、jQuery-Ajax ベースの UX を提供します。

ゲストブックのウェブサーバーの Deployment が記述された frontend-deployment.yaml マニフェスト ファイルを次に示します。

apiVersion: apps/v1 #  for k8s versions before 1.9.0 use apps/v1beta2  and before 1.8.0 use extensions/v1beta1
    kind: Deployment
    metadata:
      name: frontend
    spec:
      selector:
        matchLabels:
          app: guestbook
          tier: frontend
      replicas: 3
      template:
        metadata:
          labels:
            app: guestbook
            tier: frontend
        spec:
          containers:
          - name: php-redis
            image: gcr.io/google-samples/gb-frontend:v4
            resources:
              requests:
                cpu: 100m
                memory: 100Mi
            env:
            - name: GET_HOSTS_FROM
              value: dns
              # If your cluster config does not include a dns service, then to
              # instead access environment variables to find service host
              # info, comment out the 'value: dns' line above, and uncomment the
              # line below:
              # value: env
            ports:
            - containerPort: 80
    

ゲストブックのウェブ フロントエンド Deployment を作成するには、次のコマンドを実行します。

    kubectl create -f frontend-deployment.yaml
    

ウェブ フロントエンドを識別するラベルのリストをクエリして、3 つのレプリカが実行されていることを確認します。

    kubectl get pods -l app=guestbook -l tier=frontend
    
出力:
    NAME                      READY     STATUS    RESTARTS   AGE
    frontend-88237173-5p257   1/1       Running   0          40s
    frontend-88237173-84036   1/1       Running   0          40s
    frontend-88237173-j3rvr   1/1       Running   0          40s
    

上記のマニフェスト ファイルでは、環境変数 GET_HOSTS_FROM=dns が指定されています。この構成が与えられたゲストブック ウェブ フロントエンド アプリケーションは、ホスト名 redis-slaveredis-master を使用して DNS ルックアップを実行し、前のステップで作成した各 Service の IP アドレスを検索します。このコンセプトは、DNS サービス検出と呼ばれます。

外部 IP アドレスでのフロントエンドの公開

前のステップで作成した redis-slave Service と redis-master Service は、デフォルトの Service タイプが ClusterIP であるため、コンテナ クラスタ内でのみアクセスできます。ClusterIP は、Service が参照している Pod のセットに対して単一の IP アドレスを提供します。この IP アドレスは、クラスタ内でのみアクセスできます。

しかし、ゲストブックのウェブ フロントエンド Service は外部から認識できる必要があります。つまり、クライアントがコンテナ クラスタの外部から Service をリクエストできるようにする必要があります。これを行うには、必要に応じて Service 構成で type: LoadBalancer または type: NodePort を指定する必要があります。この例では、type: LoadBalancer を使用します。この構成が指定された frontend-service.yaml マニフェスト ファイルは次のようになります。

apiVersion: v1
    kind: Service
    metadata:
      name: frontend
      labels:
        app: guestbook
        tier: frontend
    spec:
      # comment or delete the following line if you want to use a LoadBalancer
      type: NodePort
      # if your cluster supports it, uncomment the following to automatically create
      # an external load-balanced IP for the frontend service.
      # type: LoadBalancer
      ports:
      - port: 80
      selector:
        app: guestbook
        tier: frontend
    

frontend Service の作成時には、GKE によりロードバランサと外部 IP アドレスが作成されます。これらのリソースは課金の対象となることに注意してください。ports セクションのポートの宣言では port: 80 が指定されており、targetPort は指定されていません。targetPort プロパティを省略した場合、デフォルトで port フィールドの値が使用されます。この場合、この Service はポート 80 の外部トラフィックを frontend Deployment のコンテナのポート 80 に転送します。

Service を作成するには、まず、frontend-service.yaml ファイルの次の行をコメント化解除します。

type: LoadBalancer

それから、次のコマンドを実行してサービスを作成します。

    kubectl create -f frontend-service.yaml
    

ステップ 4: ゲストブックのウェブサイトにアクセスする

ゲストブックの Service にアクセスするには、次のコマンドを実行して、先に設定した Service の外部 IP を見つける必要があります。

    kubectl get service frontend
    
出力:
    NAME       CLUSTER-IP      EXTERNAL-IP        PORT(S)        AGE
    frontend   10.51.242.136   109.197.92.229     80:32372/TCP   1m
    

EXTERNAL-IP 列の IP アドレスをコピーし、ブラウザにページを読み込みます。

GKE で実行しているゲストブック

完了しました。ゲストブックのエントリを追加してみてください。

ステップ 5: ウェブ フロントエンドをスケールアップする

ゲストブック アプリをしばらく運用していたら、アプリが突然注目を集めるようになったとします。そこで、フロントエンドのウェブサーバーを増やすことになりました。サーバーは Deployment コントローラを使用する Service として定義されているので、増やすのは簡単です。

次のコマンドを実行して、frontend Pod の数を 5 に増やします。

    kubectl scale deployment frontend --replicas=5
    

Deployment の構成が、5 つのレプリカを実行するように更新されます。それに合わせて、Deployment で実行されている Pod の数が調整されます。これを確認するには、次のコマンドを実行します。

    kubectl get pods
    
出力:
    NAME                           READY     STATUS    RESTARTS   AGE
    frontend-88237173-3s3sc        1/1       Running   0          1s
    frontend-88237173-twgvn        1/1       Running   0          1s
    frontend-88237173-5p257        1/1       Running   0          23m
    frontend-88237173-84036        1/1       Running   0          23m
    frontend-88237173-j3rvr        1/1       Running   0          23m
    redis-master-343230949-qfvrq   1/1       Running   0          54m
    redis-slave-132015689-dp23k    1/1       Running   0          37m
    redis-slave-132015689-xq9v0    1/1       Running   0          37m
    

サイトへのアクセスが元のように少なくなったら、同じ方法でウェブサーバー Pod の数を減らすことができます。

クリーンアップ

このチュートリアルで使用したリソースについて、Google Cloud Platform アカウントに課金されないようにする手順は次のとおりです。

ステップ 6: クリーンアップする

このチュートリアルを完了したら、アカウントで不要な請求が発生しないように、以下の手順でリソースを削除します。

  1. Service を削除する: frontend Service に作成した Cloud Load Balancer の割り当てを解除します。

    kubectl delete service frontend

  2. ロードバランサが frontend Service の削除を待機する: ロードバランサは、kubectl delete の実行時にバックグラウンドで非同期的に削除されます。次のコマンドの出力を監視して、ロードバランサが削除されるまで待ちます。

    gcloud compute forwarding-rules list

  3. コンテナ クラスタを削除する: コンテナ クラスタを構成するリソース(Compute インスタンス、ディスク、ネットワーク リソースなど)を削除します。

    gcloud container clusters delete guestbook

次のステップ