例: Redisを使用したPHPのゲストブックアプリケーションのデプロイ

このチュートリアルでは、KubernetesとDockerを使用した、シンプルなマルチティアのウェブアプリケーションのビルドとデプロイの方法を紹介します。この例は、以下のコンポーネントから構成されています。

  • ゲストブックのエントリーを保存するための、シングルインスタンスのRedisマスター
  • 読み込みデータ配信用の、複数のレプリケーションされたRedisインスタンス
  • 複数のウェブフロントエンドのインスタンス

目標

  • Redisのマスターを起動する。
  • Redisのスレーブを起動する。
  • ゲストブックのフロントエンドを起動する。
  • フロントエンドのServiceを公開して表示を確認する。
  • クリーンアップする。

始める前に

Kubernetesクラスターが必要、かつそのクラスターと通信するためにkubectlコマンドラインツールが設定されている必要があります。 このチュートリアルは、コントロールプレーンのホストとして動作していない少なくとも2つのノードを持つクラスターで実行することをおすすめします。 まだクラスターがない場合、minikubeを使って作成するか、 以下のいずれかのKubernetesプレイグラウンドも使用できます:

バージョンを確認するには次のコマンドを実行してください: kubectl version.

Redisのマスターを起動する

ゲストブックアプリケーションでは、データを保存するためにRedisを使用します。ゲストブックはRedisのマスターインスタンスにデータを書き込み、複数のRedisのスレーブインスタンスからデータを読み込みます。

RedisのマスターのDeploymentを作成する

以下のマニフェストファイルは、シングルレプリカのRedisのマスターPodを実行するDeploymentコントローラーを指定しています。

apiVersion: apps/v1 # for versions before 1.9.0 use apps/v1beta2
kind: Deployment
metadata:
  name: redis-master
  labels:
    app: redis
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: registry.k8s.io/redis:e2e  # or just image: redis
        resources:
          requests:
            cpu: 100m
            memory: 100Mi
        ports:
        - containerPort: 6379
  1. マニフェストファイルをダウンロードしたディレクトリ内で、ターミナルウィンドウを起動します。

  2. redis-master-deployment.yamlファイルから、RedisのマスターのDeploymentを適用します。

    kubectl apply -f https://k8s.io/examples/application/guestbook/redis-master-deployment.yaml
    
  3. Podのリストを問い合わせて、RedisのマスターのPodが実行中になっていることを確認します。

    kubectl get pods
    

    結果は次のようになるはずです。

    NAME                            READY     STATUS    RESTARTS   AGE
    redis-master-1068406935-3lswp   1/1       Running   0          28s
    
  4. 次のコマンドを実行して、RedisのマスターのPodからログを表示します。

    kubectl logs -f POD-NAME
    

RedisのマスターのServiceを作成する

ゲストブックアプリケーションは、データを書き込むためにRedisのマスターと通信する必要があります。そのためには、Serviceを適用して、トラフィックをRedisのマスターのPodへプロキシーしなければなりません。Serviceは、Podにアクセスするためのポリシーを指定します。

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
  1. 次のredis-master-service.yamlから、RedisのマスターのServiceを適用します。

    kubectl apply -f https://k8s.io/examples/application/guestbook/redis-master-service.yaml
    
  2. Serviceのリストを問い合わせて、RedisのマスターのServiceが実行中になっていることを確認します。

    kubectl get service
    

    The response should be similar to this:

    NAME           TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)    AGE
    kubernetes     ClusterIP   10.0.0.1     <none>        443/TCP    1m
    redis-master   ClusterIP   10.0.0.151   <none>        6379/TCP   8s
    

Redisのスレーブを起動する

Redisのマスターは1つのPodですが、レプリカのRedisのスレーブを追加することで、トラフィックの需要を満たすための高い可用性を持たせることができます。

RedisのスレーブのDeploymentを作成する

Deploymentはマニフェストファイル内に書かれた設定に基づいてスケールします。ここでは、Deploymentオブジェクトは2つのレプリカを指定しています。

もし1つもレプリカが実行されていなければ、このDeploymentは2つのレプリカをコンテナクラスター上で起動します。逆に、もしすでに2つ以上のレプリカが実行されていれば、実行中のレプリカが2つになるようにスケールダウンします。

apiVersion: apps/v1 # for versions before 1.9.0 use apps/v1beta2
kind: Deployment
metadata:
  name: redis-slave
  labels:
    app: redis
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:v3
        resources:
          requests:
            cpu: 100m
            memory: 100Mi
        env:
        - name: GET_HOSTS_FROM
          value: dns
          # Using `GET_HOSTS_FROM=dns` requires your cluster to
          # provide a dns service. As of Kubernetes 1.3, DNS is a built-in
          # service launched automatically. However, if the cluster you are using
          # does not have a built-in DNS service, you can instead
          # access an environment variable to find the master
          # service's host. To do so, comment out the 'value: dns' line above, and
          # uncomment the line below:
          # value: env
        ports:
        - containerPort: 6379
  1. redis-slave-deployment.yamlファイルから、RedisのスレーブのDeploymentを適用します。

    kubectl apply -f https://k8s.io/examples/application/guestbook/redis-slave-deployment.yaml
    
  2. Podのリストを問い合わせて、RedisのスレーブのPodが実行中になっていることを確認します。

    kubectl get pods
    

    結果は次のようになるはずです。

    NAME                            READY     STATUS              RESTARTS   AGE
    redis-master-1068406935-3lswp   1/1       Running             0          1m
    redis-slave-2005841000-fpvqc    0/1       ContainerCreating   0          6s
    redis-slave-2005841000-phfv9    0/1       ContainerCreating   0          6s
    

RedisのスレーブのServiceを作成する

ゲストブックアプリケーションは、データを読み込むためにRedisのスレーブと通信する必要があります。Redisのスレーブが発見できるようにするためには、Serviceをセットアップする必要があります。Serviceは一連のPodに対する透過的なロードバランシングを提供します。

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
  1. 次のredis-slave-service.yamlファイルから、RedisのスレーブのServiceを適用します。

    kubectl apply -f https://k8s.io/examples/application/guestbook/redis-slave-service.yaml
    
  2. Serviceのリストを問い合わせて、RedisのスレーブのServiceが実行中になっていることを確認します。

    kubectl get services
    

    結果は次のようになるはずです。

    NAME           TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)    AGE
    kubernetes     ClusterIP   10.0.0.1     <none>        443/TCP    2m
    redis-master   ClusterIP   10.0.0.151   <none>        6379/TCP   1m
    redis-slave    ClusterIP   10.0.0.223   <none>        6379/TCP   6s
    

ゲストブックのフロントエンドをセットアップして公開する

ゲストブックアプリケーションには、HTTPリクエストをサーブするPHPで書かれたウェブフロントエンドがあります。このアプリケーションは、書き込みリクエストに対してはredis-master Serviceに、読み込みリクエストに対してはredis-slave Serviceに接続するように設定されています。

ゲストブックのフロントエンドのDeploymentを作成する

apiVersion: apps/v1 # for versions before 1.9.0 use apps/v1beta2
kind: Deployment
metadata:
  name: frontend
  labels:
    app: guestbook
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
          # Using `GET_HOSTS_FROM=dns` requires your cluster to
          # provide a dns service. As of Kubernetes 1.3, DNS is a built-in
          # service launched automatically. However, if the cluster you are using
          # does not have a built-in DNS service, you can instead
          # access an environment variable to find the master
          # service's host. To do so, comment out the 'value: dns' line above, and
          # uncomment the line below:
          # value: env
        ports:
        - containerPort: 80
  1. frontend-deployment.yamlファイルから、フロントエンドのDeploymentを適用します。

    kubectl apply -f https://k8s.io/examples/application/guestbook/frontend-deployment.yaml
    
  2. Podのリストを問い合わせて、3つのフロントエンドのレプリカが実行中になっていることを確認します。

    kubectl get pods -l app=guestbook -l tier=frontend
    

    結果は次のようになるはずです。

    NAME                        READY     STATUS    RESTARTS   AGE
    frontend-3823415956-dsvc5   1/1       Running   0          54s
    frontend-3823415956-k22zn   1/1       Running   0          54s
    frontend-3823415956-w9gbt   1/1       Running   0          54s
    

フロントエンドのServiceを作成する

適用したredis-slaveおよびredis-master Serviceは、コンテナクラスター内部からのみアクセス可能です。これは、デフォルトのServiceのtypeがClusterIPであるためです。ClusterIPは、Serviceが指している一連のPodに対して1つのIPアドレスを提供します。このIPアドレスはクラスター内部からのみアクセスできます。

もしゲストの人にゲストブックにアクセスしてほしいのなら、フロントエンドServiceを外部から見えるように設定しなければなりません。そうすれば、クライアントはコンテナクラスターの外部からServiceにリクエストを送れるようになります。Minikubeでは、ServiceをNodePortでのみ公開できます。

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
  1. frontend-service.yamlファイルから、フロントエンドのServiceを提供します。

    kubectl apply -f https://k8s.io/examples/application/guestbook/frontend-service.yaml
    
  2. Serviceのリストを問い合わせて、フロントエンドのServiceが実行中であることを確認します。

    kubectl get services
    

    結果は次のようになるはずです。

    NAME           TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)        AGE
    frontend       NodePort    10.0.0.112   <none>       80:31323/TCP   6s
    kubernetes     ClusterIP   10.0.0.1     <none>        443/TCP        4m
    redis-master   ClusterIP   10.0.0.151   <none>        6379/TCP       2m
    redis-slave    ClusterIP   10.0.0.223   <none>        6379/TCP       1m
    

フロントエンドのServiceをNodePort経由で表示する

このアプリケーションをMinikubeやローカルのクラスターにデプロイした場合、ゲストブックを表示するためのIPアドレスを見つける必要があります。

  1. 次のコマンドを実行すると、フロントエンドServiceに対するIPアドレスを取得できます。

    minikube service frontend --url
    

    結果は次のようになるはずです。

    http://192.168.99.100:31323
    
  2. IPアドレスをコピーして、ブラウザー上でページを読み込み、ゲストブックを表示しましょう。

フロントエンドのServiceをLoadBalancer経由で表示する

もしfrontend-service.yamlマニフェストをtype: LoadBalancerでデプロイした場合、ゲストブックを表示するためのIPアドレスを見つける必要があります。

  1. 次のコマンドを実行すると、フロントエンドServiceに対するIPアドレスを取得できます。

    kubectl get service frontend
    

    結果は次のようになるはずです。

    NAME       TYPE        CLUSTER-IP      EXTERNAL-IP        PORT(S)        AGE
    frontend   ClusterIP   10.51.242.136   109.197.92.229     80:32372/TCP   1m
    
  2. 外部IPアドレス(EXTERNAL-IP)をコピーして、ブラウザー上でページを読み込み、ゲストブックを表示しましょう。

ウェブフロントエンドをスケールする

サーバーがDeploymentコントローラーを使用するServiceとして定義されているため、スケールアップやスケールダウンは簡単です。

  1. 次のコマンドを実行すると、フロントエンドのPodの数をスケールアップできます。

    kubectl scale deployment frontend --replicas=5
    
  2. Podのリストを問い合わせて、実行中のフロントエンドのPodの数を確認します。

    kubectl get pods
    

    結果は次のようになるはずです。

    NAME                            READY     STATUS    RESTARTS   AGE
    frontend-3823415956-70qj5       1/1       Running   0          5s
    frontend-3823415956-dsvc5       1/1       Running   0          54m
    frontend-3823415956-k22zn       1/1       Running   0          54m
    frontend-3823415956-w9gbt       1/1       Running   0          54m
    frontend-3823415956-x2pld       1/1       Running   0          5s
    redis-master-1068406935-3lswp   1/1       Running   0          56m
    redis-slave-2005841000-fpvqc    1/1       Running   0          55m
    redis-slave-2005841000-phfv9    1/1       Running   0          55m
    
  3. 次のコマンドを実行すると、フロントエンドのPodの数をスケールダウンできます。

    kubectl scale deployment frontend --replicas=2
    
  4. Podのリストを問い合わせて、実行中のフロントエンドのPodの数を確認します。

    kubectl get pods
    

    結果は次のようになるはずです。

    NAME                            READY     STATUS    RESTARTS   AGE
    frontend-3823415956-k22zn       1/1       Running   0          1h
    frontend-3823415956-w9gbt       1/1       Running   0          1h
    redis-master-1068406935-3lswp   1/1       Running   0          1h
    redis-slave-2005841000-fpvqc    1/1       Running   0          1h
    redis-slave-2005841000-phfv9    1/1       Running   0          1h
    

クリーンアップ

DeploymentとServiceを削除すると、実行中のPodも削除されます。ラベルを使用すると、複数のリソースを1つのコマンドで削除できます。

  1. 次のコマンドを実行すると、すべてのPod、Deployment、Serviceが削除されます。

    kubectl delete deployment -l app=redis
    kubectl delete service -l app=redis
    kubectl delete deployment -l app=guestbook
    kubectl delete service -l app=guestbook
    

    結果は次のようになるはずです。

    deployment.apps "redis-master" deleted
    deployment.apps "redis-slave" deleted
    service "redis-master" deleted
    service "redis-slave" deleted
    deployment.apps "frontend" deleted
    service "frontend" deleted
    
  2. Podのリストを問い合わせて、実行中のPodが存在しないことを確認します。

    kubectl get pods
    

    結果は次のようになるはずです。

    No resources found.
    

次の項目