目次


IBM Cloud Kubernetes Service を利用して MongoDB レプリカ・セットをデプロイする

StatefulSet を使用して Kubernetes と Docker コンテナーを上手く連動させる方法を学ぶ

Comments

Docker コンテナーと Kubernetes にはそれぞれに明らかなメリットがあるものの、開発者コミュニティーの中にはこの 2 つが上手く連動しないことに懸念を表しているメンバーがいます。そこでこの記事では、Kubernetes の開発者たちがそのような懸念を解消するために導入した StatefulSet を紹介します。チュートリアルの手順に従って、Kubernetes ベースの IBM Cloud Kubernetes Service 内で MongoDB レプリカ・セットをデプロイする方法を学んでください。手順の中で、MongoDB のクラスター要件を概説し、Kubernetes の StatefulSet をデプロイする方法を説明します。最後は、これらのツールを本番環境内で利用する際のアドバイスで記事を締めくくります。

必要となるもの

この記事では、読者が以下のテクノロジーについて、少なくとも入門者レベルの知識を持っていることを前提とします。

上記のテクノロジーについてすでに深い知識があり、早速デプロイメントの手順に取り掛かりたいとしたら、「IBM Cloud Kubernetes Service 上で MongoDB レプリカ・セットを作成する」のセクションまでスキップしてください。

はじめに: 2 つの考慮事項

Andrew Morgan 氏はこのリンク先のブログ投稿「Running MongoDB as a Microservice with Docker and Kubernetes」の中で、コンテナーと、Kubernetes のようなオーケストレーション・テクノロジーを使用して MongoDB を実行する際の考慮事項を概説しています。これらの考慮事項のうち、特に注目すべきなのは以下の 2 つです。

  • MongoDB データベース・ノードはステートフルです。
  • レプリカ・セットに含まれる MongoDB データベース・ノードは互いに通信する必要があります。これには、再スケジュール後の通信も含まれます (つまり、新しいノードが作成される時点での通信)。

Docker について少なくとも入門者レベルの知識があれば、最初に挙げられている考慮事項が Docker コンテナーの基本原則の 1 つに反していることを認識できるでしょう。つまり、Docker のガイドラインでは、「コンテナーは可能な限り短命にすべき」であり、ステートフルであってはならないと述べています。しかも、ステートフルネスを Docker コンテナーに追加するのは簡単なことではありません。ステートフルネスが正しく追加されていなければ、Docker コンテナーの別の設計原則「迅速で一貫性のあるアプリケーション・デリバリー」が破られてしまう可能性があります。

Morgan 氏が挙げた 2 番目の考慮事項は、コンテナーのネットワーキングに関連します。特に考慮しなければならないのは、ホスト名です。なぜなら、自動再スケジュールが行われた後、コンテナーのインスタンス (「ポッド」) は自動的に破棄されて、新しいホスト名を使用して再作成されるためです。したがって、コンテナー化されたアプリケーションのデプロイメント、スケーリング、管理を自動化するシステムとして Kubernetes を魅力的なものにしている機能は、コンテナー間の通信を不可能にする可能性があります。

Docker コンテナーと Kubernetes にはそれぞれにメリットがあるものの、多くのアーキテクトは以上の点から、この 2 つのテクノロジーが有効な MongoDB レプリカ・セットを作成する手段にはならないと見なしています。Kubernetes コミュニティーがこのような懸念に対処するために導入したのが、StatefulSet です。

Kubernetes の StatefulSet

バージョン 1.5 でベータ版リリースとしてKubernetes 内に導入された StatefulSet は、バージョン 1.9 で安定版となり、一般に利用可能になりました。StatefulSet は、MongoDB をはじめとするステートフルなアプリケーションの管理を目的に設計された機能です。

Kubernetes のドキュメントでは、以下のように説明しています。

デプロイメントと同じように、StatefulSet は同じコンテナー仕様に基づくポッドを管理します。ただしデプロイメントとは異なり、StatefulSet はポッドそれぞれに固定された ID を維持します。これらのポッドは同じ仕様から作成されますが、ポッドを互いに置き換えることはできません。各ポッドは再スケジュールされた後も、その永続 ID を維持するためです。


決定的な点として、StatefulSet が提供する 5 つの機能のうち、以下の 2 つは Docker と Kubernetes を使用してマイクロサービスとして MongoDB を実行する際の考慮事項に関連します。

  • 安定した永続ストレージ
  • 安定した固有のネットワーク ID

要するに、単一の MongoDB Docker コンテナーを使用して Kubernetes 内で StatefulSet 構成を定義すれば、Kubernetes によって自動的に MongoDB レプリカ・セット・ノード用の永続ストレージを作成してノードに接続できるということです。新しいノードがいくつ作成されるとしても、この MongoDB レプリカ・セット・ノードには、固有の既知のネットワーク名を使用してアドレスを指定できます。

IBM Cloud Kubernetes Service を使用する場合の StatefulSet

MongoDB の主要な目的は保管されたデータへのアクセスを提供することであるという点を踏まえると、基礎となる永続ストレージに、アプリケーションまたはビジネスのさまざまな非機能要件に対処できる特性が備わっていることが非常に重要です。

例えば、多くのアプリケーションでは IOPS が予測可能であることが要件となります。企業や政府機関の要件で、アプリケーション・ストレージを保管時に暗号化すること、あるいは (MongoDB にはレプリケーション機能が備わっているにも関わらず) アプリケーション・ストレージを複製して冗長性を確保することが規定されている場合もあります。

デフォルトでは、IBM Cloud Kubernetes Service は IBM Cloud の NFS ベースのファイル・ストレージ・オファリング (つまり、エンデュランス・ストレージとパフォーマンス・ストレージ) を使用するように構成されます。このサービスには事前定義された 8 つのストレージ・クラスが用意されているため、クラスター管理者がストレージ・クラスを作成する必要はありません。

StatefulSet を使用するとしても、サービスの構成ではアプリケーション要件またはビジネス要件に応じて既存のストレージ・クラスから 1 つがそのまま選択されるため、ほかのクラスは必要になりません。

IBM Cloud のファイル・ストレージ・オファリングには、以下を含め、多数のメリットがあります。

  • flash-backed ストレージ
  • データ保存時の暗号化
  • スナップショットとレプリケーション
  • ボリューム複製
  • 拡張可能なボリューム
  • 調整可能な IOPS

: IBM Cloud Kubernetes Service のワーカー・ノードは、デフォルトで、暗号化された SSD を使用します。

ステップ 1. IBM Cloud Kubernetes Service 上で MongoDB レプリカ・セットを作成する

IBM Cloud Kubernetes Service に使用する構成と、他の Kubernetes プロバイダーが使用している構成との間には、ほとんど違いがありません。これが、Kubernetes を提供するプロバイダーに投資している数々の理由のうちの 1 つです。storageClassName の値が、唯一の本質的な違いとなります。

: この手順では、Kubernetes Service クラスターを作成済みであることを前提としています。IBM Cloud Kubernetes Service クラスターの作成方法について詳しくは、このリンク先の資料「クラスターのセットアップ」を参照してください。

: クラスターは Kubernetes バージョン 1.9.2 以降で稼働するようにしてください。それには、クラスターを作成するコマンドに --kube-version 1.9.2 を渡すか、既存のクラスターとそのワーカー・ノードを更新します (このリンク先の IBM Cloud の資料を参照)。

このセクションの手順を完了すると、IBM Cloud Kubernetes Service 内で稼働する Kubernetes クラスター内に 3 つのノードからなる MongoDB レプリカ・セットが作成された状態になります。永続ボリュームには、IBM Cloud File Storage オファリングが利用されます。

下の図に、これから作成する以下の 3 つの主要なコンポーネントと、これらのコンポーネントがアプリケーション・デプロイメントの全体像の中で論理的に位置する場所を示します。

  • ヘッドレス・サービス
  • MongoDB コンテナーおよび関連する永続ボリューム・クレームが含まれる StatefulSet
  • 永続ボリューム (IBM Cloud ファイル・ストレージ)
図 1. 3 つのノードからなる MongoDB レプリカ・セットの主要コンポーネント

: エッジ・サービス、セキュリティー、LoadBalancer/Ingress サービス、アプリケーション・コンポーネントについては、この記事では取り上げません。クラスター内にアプリをデプロイする方法について詳しくは、アプリを公開する際のネットワークの選択肢を含め、このリンク先の資料「NodePort、LoadBalancer、または Ingress サービスを使用したネットワーキングの計画」を参照してください。

ステップ 2. ヘッドレス・サーバー構成ファイルを作成する

Kubernetes ヘッドレス・サービスは、他のタイプの Kubernetes サービスと同じように、ポッドのドメインを管理しますが、ロード・バランサー・サービスや既存の IP アドレスを必要としません。このサービスは、サービスのセレクターと一致するポッドを 1 のグループにまとめます。

ヘッドレス・サービスの構成ファイルは、以下のように作成してください。

リスト 1. mongo-headless-service.yaml
apiVersion: v1
kind: Service
metadata:
  name: mongo
  labels:
    app: mongo
spec:
  ports:
  - name: mongo
    port: 27017
    targetPort: 27017
  clusterIP: None
  selector:
    app: mongo

ヘッドレス・サービスを作成する場合は、clusterIP の値を Node に設定します (行 12)。

targetPort には、必ず該当する適切なポート番号を使用してください (行 11)。ポート番号は、以下のステップ 3 で作成する StatefulSet 構成ファイル内で使用する値 (行 37) と一致していなければなりません。この値は、mongod サービスが使用するポートを表します。デフォルトのポート番号は 27017 です。この port パラメーターに設定する値に対応するポート上で、あらゆる MongoDB クライアントがサービスに接続することになります。

ステップ 3. StatefulSet 構成ファイルを作成する

StatefulSet の構成ファイルは、以下のように作成してください。

リスト 2. mongo-statefulset.yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: mongo
spec:
  selector:
    matchLabels:
      app: mongo
  serviceName: "mongo"
  replicas: 3
  podManagementPolicy: Parallel
  template:
    metadata:
      labels:
        app: mongo
    spec:
      terminationGracePeriodSeconds: 10
      affinity:
         podAntiAffinity:
           requiredDuringSchedulingIgnoredDuringExecution:
           - labelSelector:
               matchExpressions:
               - key: "app"
                 operator: In
                 values:
                 - mongo
             topologyKey: "kubernetes.io/hostname"
      containers:
      - name: mongo
        image: mongo
        command: 
        - mongod 
        - "--bind_ip_all"
        - "--replSet"
        - rs0
        ports:
        - containerPort: 27017
        volumeMounts:
        - name: mongo-data
          mountPath: /data/db
  volumeClaimTemplates:
  - metadata:
      name: mongo-data
    spec:
      accessModes: [ "ReadWriteOnce" ]
      storageClassName: ibmc-file-bronze
      resources:
        requests:
          storage: 20Gi

: affinity セクション (行 18 ~ 27) で、すでにポッドを実行中のクラスター・ワーカー・ノード上で MongoDB レプリカ・セット・ポッドが実行されるようにスケジューリングされることを防ぎます。このようにしなければ、3 つすべてのポッドが単一のワーカー・ノード上で実行されて、そのノードで障害が発生した場合、それが障害点になってしまいます。

構成ファイルの作成が完了したので、次はリソースをデプロイします。

ステップ 4. サービスと StatefulSet をデプロイする

ヘッドレス・サービスと StatefulSet をデプロイするには、IBM Cloud CLI の Bluemix または bx と、Kubernetes CLI の kubectl を使用して kubectl コマンドを実行すればよいだけです。

  1. まず、IBM Cloud CLI にログインします。
    	$ bx login
  2. 次に、CLI でクラスターのコンテキストを設定します。
    	$ $(bx cs cluster-config sandbox-cluster | grep KUBECONFIG)
  3. 続いて以下のコマンド (行 1 と行 4) を実行します。以下のコードには、それぞれに期待される出力も示されています。
    	$ kubectl apply -f mongo-headless-service.yaml
    	service "mongo" created
    	
        $ kubectl apply -f mongo-statefulset.yaml
    	statefulset "mongo" created

    : ヘッドレス・サービスの構成ファイルと StatefulSet の構成ファイルは、1 つのファイルに結合することもできます。その場合、それぞれの構成を行「---」で分離します。

  4. 確認のために、以下のコマンド (行 1 と行 5) を使用して、各オブジェクトを取得します。以下のコードには、それぞれに期待される出力も示されています。
    	$ kubectl get service mongo
    	NAME    TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)     AGE
    	mongo   ClusterIP   None         <none>        27017/TCP   5s
    	
    	$ kubectl get statefulset mongo
    	NAME    DESIRED   CURRENT   AGE
    	mongo   3         3         1m
  5. StatefulSet がデプロイされた後は、Kubernetes が自動的にポッドを作成して、仕様に従ったポッドの名前 (例えば、mongo-0mongo-1mongo-2) を指定します。自動的に作成されたポッドをリストアップするには、以下のようにポッドのラベル app=mongo を使用してポッド・オブジェクトを取得します。
    	$ kubectl get pod -l app=mongo
    	NAME      READY     STATUS    RESTARTS   AGE
    	mongo-0   1/1       Running   0          30s
    	mongo-1   1/1       Running   0          30s
    	mongo-2   1/1       Running   0          30s
  6. さらに、Kubernetes は自動的に永続ボリューム・クレーム (pvc) を作成して、永続ボリュームをポッドにバインドします。永続ボリューム・クレームをリストアップするには、以下のコマンドを使用して pvc オブジェクトを取得します。
    	$ kubectl get pvc
    	NAME                 STATUS    VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS       AGE
    	mongo-data-mongo-0   Bound     pvc-3ed73cf3-0940-11e8-ac45-925e6fdab1e7   20Gi       RWO            ibmc-file-bronze   1m
    	mongo-data-mongo-1   Bound     pvc-3ed82f17-0940-11e8-ac45-925e6fdab1e7   20Gi       RWO            ibmc-file-bronze   1m
    	mongo-data-mongo-2   Bound     pvc-3ed90d7e-0940-11e8-ac45-925e6fdab1e7   20Gi       RWO            ibmc-file-bronze   1m

    これで、MongoDB レプリカ・セット・ノードのそれぞれが、(内部で) DNS でアドレス指定可能な Kubernetes ポッドとして作成され、独自の永続ストレージにバインドされた状態になりました。

    具体的に言うと、各ポッドの内部 Kubernetes DNS ホスト名は一貫して、以下のように StatefulSet 名の後にポッド番号が続いた形になります。

    $(statefulset name)-$(ordinal)

    また、ヘッドレス・サービスを使用したドメイン管理対象サービスの名前は、以下の形になります。

    $(servicename).$(namespace).svc.cluster.local
  7. ポッドを参照するには、以下のサブドメイン・パターンを使用します。
    $(podname).$(servicename)

    例えば、指定された構成に従い、各 MongoDB ノードは以下の DNS 名を使用して参照することができます。
    mongo-0.mongo, mongo-1.mongo, mongo-2.mongo

永続ストレージは、各ポッド内の /data/db マウント・パス上でアクセス可能になるように構成され、デフォルトで IBM Cloud ファイル・ストレージ・オファリングを使用します。ポッドが破棄された場合、そのポッドと同じ名前を使用して具現化されたポッドは、自動的に同じ永続ストレージにマウントされます (ただし、永続ストレージ・クレームが手作業で破棄された場合は、その限りではありません)。

残る作業は、各ノードを使用してレプリカ・セットを初期化することだけです。

ステップ 5. MongoDB レプリカ・セットを初期化して構成する

MongoDB レプリカ・セットが作成された後は、それぞれのレプリカ・セット自体を初期化して構成する必要があります。それには、最初のノードにアクセスして、一連の mongo コマンドを実行します。

: 以降に記載するコマンドは、新しいノードが追加または削除される際の CI/CD プロセスの一部としてスクリプトにすることができます。

  1. まず、最初のレプリカ・セット・ノードに対して以下の MongoDB シェルを実行します。
    	$ kubectl exec -it mongo-0 -- mongo
  2. 次に、MongoDB レプリカ・セットを初期化します。
    	> rs.initiate()
  3. レプリカ・セットの最初のメンバーを、正しい DNS 名を使用して再構成します。
    	> var cfg = rs.conf();cfg.members[0].host="mongo-0.mongo:27017";rs.reconfig(cfg)
  4. 残りのレプリカ・セット・ノードを追加します。
    rs.add("mongo-1.mongo:27017")
    rs.add("mongo-2.mongo:27017")
  5. 最後に、新しい構成をレビューして、レプリカ・セットを確認します。
    > rs.status()

新しい構成には、それぞれのホスト名に対応する「_id」値が設定された 3 つのノードが示されていなければなりません。

これで、MongoDB レプリカ・セットが初期化されて構成されました。この時点で、MongoDB レプリカ・セットには、基本的に同じ Kubernetes 名前空間内で稼働するクライアント・アプリケーションがアクセスできる状態になっています。

: Kubernetes 外部から MongoDB レプリカ・セットにアクセスするには、Kubernetes の「NodePort」または「LoadBalancer」タイプのサービスが必要です。外部ネットワーキングを計画する方法について詳しくは、このリンク先の IBM Cloud Kubernetes Service の資料を参照してください。

この記事に記載した構成を使用している場合、MongoDB レプリカ・セットの URI 接続文字列は以下のようになります。

mongodb://mongo-0.mongo:27017,mongo-1.mongo:27017,mongo-2.mongo/myproject?replicaSet=rs0

本番に関する考慮事項

この記事は、入門ガイドだと思ってください。Kubernetes を使用して本番環境内で MongoDB を実行する際には、他にも多数の考慮事項があります。そのほとんどは、すでに他の記事やブログで取り上げられているので、今後の記事では、IBM Cloud Kubernetes Service オファリングに固有の注意点について説明したいと思います。

例えば、少なくとも以下の点を考慮せずに、この記事に記載した構成を本番環境内で使用することは推奨されません (これらの話題についての詳細は、以下の「関連トピック」にリストアップされているリンク先のページを参照してください)。

  • 認証 (mongoDb)
  • root 以外として実行すること
  • MongoDB Enterprise Edition の使用 (mongoDb)
  • クラスターのシャーディング (mongoDb)
  • 最大メンバー数への対応 (mongoDb)
  • 計算リソースの管理 (Kubernetes)
  • プライベート Docker イメージを、IBM Container Registry を利用した高可用性のあるスケーラブルなアーキテクチャー内に安全に保管してアクセスすること (IBM Cloud)

まとめ

この記事では、Kubernetes ベースの IBM Cloud Kubernetes Service 内に MongoDB レプリカ・セットをデプロイするという方法を実現する手法を具体的に説明しました。

Kubernetes の StatefulSet を使用すると、コンテナー・テクノロジーを使用して MongoDB を実行する際のさまざまな懸念事項に対処して、Kubernetes がもたらすメリットを実現することができます。

さらに、IBM Cloud Kubernetes Service を利用することによってもたらされるメリットを、特にこのサービスを支える IBM Cloud ファイル・ストレージ・オファリングにハイライトを当てて紹介しました。

そして最後に、この記事に記載した手順に従って、わずか数分で IBM Cloud Kubernetes Service 上に MongoDB レプリカ・セットを作成し、開発とテストの環境の基盤を築きました。さらに考慮を重ねれば、本番環境を構築することも可能です。


ダウンロード可能なリソース


関連トピック


コメント

コメントを登録するにはサインインあるいは登録してください。

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=Cloud computing
ArticleID=1063063
ArticleTitle=IBM Cloud Kubernetes Service を利用して MongoDB レプリカ・セットをデプロイする
publish-date=10042018