この記事は、クラウドでのコンテナー化されたワークロードのデプロイと管理に関するウェビナーシリーズを補足するものです。 このシリーズでは、コンテナライフサイクルの管理、マルチコンテナアプリケーションのデプロイ、ワークロードのスケーリング、Kubernetesの操作など、コンテナの基本事項について説明します。 また、ステートフルアプリケーションを実行するためのベストプラクティスについても説明します。

このチュートリアルには、シリーズの5番目のセッションであるKubernetesでのマイクロサービスのデプロイとスケーリングの概念とコマンドが含まれています。

序章

Kubernetes は、コンテナー化されたアプリケーションを管理するためのオープンソースのコンテナーオーケストレーションツールです。 このシリーズの前回のチュートリアルでは、 Kubernetesの詳細で、Kubernetesの構成要素を学習しました。

このチュートリアルでは、前のチュートリアルの概念を適用して、Kubernetesでエンドツーエンドのマイクロサービスアプリケーションを構築、デプロイ、管理します。 このチュートリアルで使用するサンプルWebアプリケーションは、MongoDBをデータベースとして使用するNode.jsで記述された「todoリスト」アプリケーションです。 これは、チュートリアルコンテナ化されたアプリケーションの構築で使用したものと同じアプリケーションです。

このアプリのコンテナーイメージをDockerfileからビルドし、イメージをDocker Hubにプッシュしてから、クラスターにデプロイします。 次に、需要の増加に合わせてアプリをスケーリングします。

前提条件

このチュートリアルを完了するには、次のものが必要です。

  • このチュートリアルシリーズの第3部であるKubernetes入門で構成できるKubernetesクラスター。

  • イメージを保存するためのアクティブなDockerHubアカウント。

  • Gitがローカルマシンにインストールされています。 チュートリアルオープンソースへの貢献:Git入門に従って、コンピューターにGitをインストールしてセットアップすることができます。

ステップ1-Dockerfileを使用してイメージを構築する

まず、WebアプリケーションをDockerイメージにパッケージ化してコンテナー化します。

まずホームディレクトリに移動し、Gitを使用してこのチュートリアルのサンプルWebアプリケーションをGitHubの公式リポジトリから複製します。

  1. cd ~
  2. git clone https://github.com/janakiramm/todo-app.git

Dockerfileからコンテナイメージをビルドします。 -tスイッチを使用して、レジストリのユーザー名、イメージ名、およびオプションのタグでイメージにタグを付けます。

  1. docker build -t sammy/todo .

出力は、イメージが正常に構築され、適切にタグ付けされたことを確認します。

Output
Sending build context to Docker daemon  8.238MB Step 1/7 : FROM node:slim  ---> 286b1e0e7d3f Step 2/7 : LABEL maintainer = "[email protected]"  ---> Using cache  ---> ab0e049cf6f8 Step 3/7 : RUN mkdir -p /usr/src/app  ---> Using cache  ---> 897176832f4d Step 4/7 : WORKDIR /usr/src/app  ---> Using cache  ---> 3670f0147bed Step 5/7 : COPY ./app/ ./  ---> Using cache  ---> e28c7c1be1a0 Step 6/7 : RUN npm install  ---> Using cache  ---> 7ce5b1d0aa65 Step 7/7 : CMD node app.js  ---> Using cache  ---> 2cef2238de24 Successfully built 2cef2238de24 Successfully tagged sammy/todo-app:latest

docker imagesコマンドを実行して、イメージが作成されていることを確認します。

  1. docker images

画像のサイズと作成後の時間を確認できます。

Output
REPOSITORY                                       TAG                 IMAGE ID            CREATED             SIZE sammy/todo-app                                   latest              81f5f605d1ca        9 minutes ago       236MB

次に、イメージをDockerHubのパブリックレジストリにプッシュします。 これを行うには、DockerHubアカウントにログインします。

  1. docker login

クレデンシャルを入力したら、DockerHubユーザー名を使用してイメージにタグを付けます。

  1. docker tag your_docker_hub_username/todo-app

次に、イメージをDockerHubにプッシュします。

  1. docker push

WebブラウザでDockerHub を検索すると、新しいイメージが利用可能であることを確認できます。

Dockerイメージをレジストリにプッシュしたら、Kubernetes用のアプリケーションをパッケージ化します。

ステップ2–KubernetesにMongoDBポッドをデプロイする

このアプリケーションは、MongoDBを使用して、Webアプリケーションを介して作成されたToDoリストを保存します。  KubernetesでMongoDBを実行するには、ポッドとしてパッケージ化する必要があります。 このポッドを起動すると、MongoDBの単一インスタンスが実行されます。

db-pod.yamlという名前の新しいYAMLファイルを作成します。

  1. nano db-pod.yaml

MongoDBに基づいて1つのコンテナーでポッドを定義する次のコードを追加します。 MongoDBで使用される標準ポートであるポート27017を公開します。 定義にラベルnameおよびappが含まれていることに注意してください。 これらのラベルを使用して、特定のポッドを識別および構成します。

db-pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: db
  labels:
    name: mongo
    app: todoapp

spec:
      containers:
      - image: mongo
        name: mongo
        ports:
        - name: mongo
          containerPort: 27017

        volumeMounts:
          - name: mongo-storage
            mountPath: /data/db

      volumes:
          - name: mongo-storage
            hostPath:
              path: /data/db

データは、ノードの/data/dbの場所にマップされているmongo-storageと呼ばれるボリュームに保存されます。 ボリュームの詳細については、公式のKubernetesボリュームのドキュメントを参照してください。

次のコマンドを実行して、ポッドを作成します。

  1. kubectl create -f db-pod.yml

次の出力が表示されます。

Output
pod "db" created

次に、ポッドの作成を確認します。

  1. kubectl get pods

出力にはポッドが表示され、ポッドが実行中であることが示されます。

Output
NAME      READY     STATUS    RESTARTS   AGE db   1/1       Running   0          2m

このポッドをクラスターの内部コンシューマーがアクセスできるようにしましょう。

db-service.yamlという名前の新しいファイルを作成します。このファイルには、MongoDBのサービスを定義する次のコードが含まれています。

db-service.yaml
apiVersion: v1
kind: Service
metadata:
  name: db
  labels:
    name: mongo
    app: todoapp

spec:
  selector:
    name: mongo

  type: ClusterIP
  ports:
    - name: db
      port: 27017
      targetPort: 27017

サービスは、name: dbのラベルと一致する同じ名前空間内のすべてのポッドを検出します。 YAMLファイルのselectorセクションは、この関連付けを明示的に定義します。

宣言type: ClusterIPを使用して、サービスがクラスター内に表示されるように指定します。

ファイルを保存して、エディターを終了します。 次に、kubectlを使用してクラスターに送信します。

  1. kubectl create -f db-service.yml

サービスが正常に作成されたことを示す次の出力が表示されます。

Output
service "db" created

ポッドが使用可能なポートを取得しましょう。

  1. kubectl get services

次の出力が表示されます。

Output
NAME         TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)     AGE db           ClusterIP   10.109.114.243   <none>        27017/TCP   14s kubernetes   ClusterIP   10.96.0.1        <none>        443/TCP     47m

この出力から、サービスがポート27017で利用可能であることがわかります。 Webアプリケーションは、このサービスを介してMongoDBに到達できます。 ホスト名dbを使用する場合、Kubernetes内で実行されているDNSサービスは、サービスに関連付けられたClusterIPにアドレスを解決します。 このメカニズムにより、ポッドは相互に検出して通信できます。

データベースのポッドとサービスを配置したら、Webアプリケーションのポッドを作成しましょう。

ステップ3–Node.JSWebアプリをポッドとしてデプロイする

このチュートリアルの最初のステップで作成したDockerイメージをポッドとしてパッケージ化し、クラスターにデプロイしてみましょう。 これは、エンドユーザーがアクセスできるフロントエンドWebアプリケーションレイヤーとして機能します。

web-pod.yamlという名前の新しいYAMLファイルを作成します。

  1. nano web-pod.yaml

sammy/todo-appDockerイメージに基づいて1つのコンテナーでポッドを定義する次のコードを追加します。 TCPプロトコルを介してポート3000で公開されます。

web-pod.yaml
apiVersion: v1
kind: Pod

metadata:
  name: web
  labels:
    name: web
    app: todoapp

spec:
  containers:
    - image: sammy/todo-app
      name: myweb
      ports:
        - containerPort: 3000

定義にラベルnameおよびappが含まれていることに注意してください。 サービスはこれらのラベルを使用して、インバウンドトラフィックを適切なポートにルーティングします。

次のコマンドを実行してポッドを作成します。

  1. kubectl create -f web-pod.yaml
Output
pod "web" created

ポッドの作成を確認しましょう。

  1. kubectl get pods
Output
NAME      READY     STATUS    RESTARTS   AGE db        1/1       Running   0          8m web       1/1       Running   0          9s

MongoDBデータベースとWebアプリの両方がポッドとして実行されていることに注意してください。

次に、webポッドをパブリックインターネットにアクセスできるようにします。

サービスは、ポッドのセットを内部または外部に公開します。 webポッドを公開するサービスを定義しましょう。 これは、クラスターの各ノードで開かれた任意のポートを介してポッドにアクセスできるようにするスキームであるNodePortを介して公開します。

アプリのサービスを定義する次のコードを含むweb-service.yamlという名前の新しいファイルを作成します。

apiVersion: v1
kind: Service
metadata:
  name: web
  labels:
    name: web
    app: todoapp

spec:
  selector:
    name: web
  type: NodePort
  ports:
   - name: http
     port: 3000
     targetPort: 3000
     protocol: TCP

サービスは、webという名前のラベルと一致する同じ名前空間内のすべてのポッドを検出します。 YAMLファイルのセレクターセクションは、この関連付けを明示的に定義します。

type: NodePort宣言により、サービスのタイプがNodePortであることを指定します。

kubectlを使用して、これをクラスターに送信します。

  1. kubectl create -f web-service.yml

サービスが正常に作成されたことを示す次の出力が表示されます。

Output
service "web" created

ポッドが使用可能なポートを取得しましょう。

  1. kubectl get services
Output
NAME         TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)          AGE db           ClusterIP   10.109.114.243   <none>        27017/TCP        12m kubernetes   ClusterIP   10.96.0.1        <none>        443/TCP          59m web          NodePort    10.107.206.92    <none>        3000:30770/TCP   12s

この出力から、サービスがポート30770で利用可能であることがわかります。 ワーカーノードの1つに接続してみましょう。

DigitalOceanコンソールを使用して、Kubernetesクラスターに関連付けられているワーカーノードの1つのパブリックIPアドレスを取得します。

DigitalOcean console showing worker nodes

IPアドレスを取得したら、curlコマンドを使用して、ポート30770のノードの1つにHTTPリクエストを送信します。

  1. curl http://your_worker_ip_address:30770

次のような出力が表示されます。

Output
<!DOCTYPE html> <html>   <head>     <title>Containers Todo Example</title>     <link rel='stylesheet' href='/stylesheets/screen.css' />     <!--[if lt IE 9]>     <script src="https://html5shiv.googlecode.com/svn/trunk/html5.js"></script>     <![endif]-->   </head>   <body>     <div id="layout"> <h1 id="page-title">Containers Todo Example</h1> <div id="list">   <form action="/create" method="post" accept-charset="utf-8">     <div class="item-new">       <input class="input" type="text" name="content" />     </div>   </form> </div>       <div id="layout-footer"></div>     </div>     <script src="/javascripts/ga.js"></script>   </body> </html>

Webポッドとサービスを定義しました。 次に、レプリカセットを使用してスケーリングする方法を見てみましょう。

ステップ5–Webアプリケーションのスケーリング

レプリカセットにより、クラスター内で常に最小数のポッドが実行されていることが保証されます。 ポッドがレプリカセットとしてパッケージ化されている場合、Kubernetesは常に仕様で定義されている最小数のポッドを実行します。

現在のポッドを削除し、レプリカセットを使用して2つのポッドを再作成しましょう。 ポッドを実行したままにすると、レプリカセットの一部にはなりません。 したがって、カウントが1つだけの場合でも、レプリカセットを介してポッドを起動することをお勧めします。

まず、既存のポッドを削除します。

  1. kubectl delete pod web
Output
pod "web" deleted

次に、新しいレプリカセット宣言を作成します。 レプリカセットの定義はポッドと同じです。 主な違いは、実行する必要のあるポッドの数を定義するreplica要素が含まれていることです。 ポッドと同様に、サービス検出に役立つメタデータとしてのラベルも含まれています。

ファイルweb-rs.yamlを作成し、次のコードをファイルに追加します。

apiVersion: extensions/v1beta1
kind: ReplicaSet
metadata:
  name: web
  labels:
    name: web
    app: todoapp

spec:
  replicas: 2
  template:
    metadata:
      labels:
        name: web
    spec:
      containers:
      - name: web
        image: sammy/todo-app
        ports:
        - containerPort: 3000

ファイルを保存して閉じます。

次に、レプリカセットを作成します。

  1. kubectl create -f web-rs.yaml
Output
replicaset "web" created

次に、ポッドの数を確認します。

  1. kubectl get pods
Output
NAME        READY     STATUS    RESTARTS   AGE db          1/1       Running   0          18m web-n5l5h   1/1       Running   0          25s web-wh6nf   1/1       Running   0          25s

NodePortを介してサービスにアクセスすると、レプリカセットによって管理されているポッドの1つにリクエストが送信されます。

ポッドの1つを削除し、何が起こるかを確認して、レプリカセットの機能をテストしてみましょう。

  1. kubectl delete pod web-wh6nf
Output
pod "web-wh6nf" deleted

ポッドをもう一度見てください。

  1. kubectl get pods
Output
NAME        READY     STATUS              RESTARTS   AGE db          1/1       Running             0          19m web-n5l5h   1/1       Running             0          1m web-wh6nf   1/1       Terminating         0          1m web-ws59m   0/1       ContainerCreating   0          2s

ポッドが削除されるとすぐに、Kubernetesは別のポッドを作成して、目的のカウントが維持されるようにします。

レプリカセットをスケーリングして、追加のWebポッドを実行できます。

次のコマンドを実行して、Webアプリケーションを10ポッドにスケーリングします。

  1. kubectl scale rs/web --replicas=10
Output
replicaset "web" scaled

ポッド数を確認します。

  1. kubectl get pods

次の出力が表示されます。

Output
NAME        READY     STATUS              RESTARTS   AGE db          1/1       Running             0          22m web-4nh4g   1/1       Running             0          21s web-7vbb5   1/1       Running             0          21s web-8zd55   1/1       Running             0          21s web-f8hvq   0/1       ContainerCreating   0          21s web-ffrt6   1/1       Running             0          21s web-k6zv7   0/1       ContainerCreating   0          21s web-n5l5h   1/1       Running             0          3m web-qmdxn   1/1       Running             0          21s web-vc45m   1/1       Running             0          21s web-ws59m   1/1       Running             0          2m

Kubernetesは、webポッドをスケーリングするプロセスを開始しました。 リクエストがNodePortを介してサービスに到着すると、レプリカセット内のポッドの1つにルーティングされます。

トラフィックと負荷が落ち着くと、2つのポッドの元の構成に戻すことができます。

kubectl scale rs/web --replicas=2
Output
replicaset "web" scaled

このコマンドは、2つを除くすべてのポッドを終了します。

  1. kubectl get pods
Output
NAME        READY     STATUS        RESTARTS   AGE db          1/1       Running       0          24m web-4nh4g   1/1       Terminating   0          2m web-7vbb5   1/1       Terminating   0          2m web-8zd55   1/1       Terminating   0          2m web-f8hvq   1/1       Terminating   0          2m web-ffrt6   1/1       Terminating   0          2m web-k6zv7   1/1       Terminating   0          2m web-n5l5h   1/1       Running       0          5m web-qmdxn   1/1       Terminating   0          2m web-vc45m   1/1       Terminating   0          2m web-ws59m   1/1       Running       0          4m

レプリカセットの可用性を確認するには、ポッドの1つを削除して、カウントを確認してください。

  1. kubectl delete pod web-ws59m
Output
pod "web-ws59m" deleted
  1. kubectl get pods
Output
NAME        READY     STATUS              RESTARTS   AGE db          1/1       Running             0          25m web-n5l5h   1/1       Running             0          7m web-ws59m   1/1       Terminating         0          5m web-z6r2g   0/1       ContainerCreating   0          5s

ポッドカウントが変更されるとすぐに、KubernetesはYAMLファイルで定義されたカウントと一致するようにポッドカウントを調整します。 レプリカセット内のWebポッドの1つが削除されると、必要な数を維持するために別のポッドがすぐに作成されます。 これにより、最小数のポッドが常に実行されるようになり、アプリケーションの高可用性が保証されます。

次のコマンドを使用して、このチュートリアル中に作成されたすべてのオブジェクトを削除できます。

  1. kubectl delete -f db-pod.yaml -f db-service.yaml -f web-rs.yaml -f web-service.yaml
Output
pod "db" deleted service "db" deleted replicaset "web" deleted service "web" deleted

結論

このチュートリアルでは、シリーズで取り上げたすべての概念を適用して、マイクロサービスアプリケーションをパッケージ化、デプロイ、スケーリングしました。

このシリーズの次のパートでは、MongoDBをStatefulSetとして実行して高可用性を実現する方法を学習します。