#Google Cloud Platform (GCP)

0 フォロワー · 5 投稿

Google Cloud Platform(GCP)は、Googleが提供するパブリッククラウドコンピューティングサービスのスイートです。 このプラットフォームには、Googleハードウェア上で実行される、コンピューティング、ストレージおよびアプリケーション開発のためのさまざまなホスティングサービスが含まれています。 GCPサービスに対しては、ソフトウェア開発者、クラウド管理者およびその他のエンタープライズITプロフェッショナルは、パブリックなインターネットまたは専用ネットワーク接続を介してアクセスできます。 詳細はこちら

記事 Toshihiko Minamoto · 11月 5, 2025 8m read

新しい InterSystems IRIS® Cloud SQL と InterSystems IRIS® Cloud IntegratedML® クラウド製品のユーザーであり、デプロイメントのメトリクスにアクセスして独自の可観測性プラットフォームに送信しようと考えている方のために、メトリクスを Google Cloud Platform Monitoring(旧称 StackDriver)に送信して手っ取り早く行う方法をご紹介します。

クラウドポータルには、概要メトリクス表示用のトップレベルのメトリクスが含まれており、ユーザーに公開されているメトリクスエンドポイントを使用しますが、ある程度探索しなければ、そこにあることには気づきません。

🚩 このアプローチは、「今後名前が付けられる予定の機能」を利用している可能性があるため、それを踏まえると将来性があるものではなく、確実に InterSystemsでサポートされているアプローチではありません。


では、より包括的なセットをエクスポートしたい場合はどうでしょうか?この技術的な記事/例では、メトリクスを取得して可観測性に転送する方法を紹介します。Open Telemetry Collector を使用して、任意のメトリクスターゲットを取得し、任意の可観測性プラットフォーム送信できるように、ニーズに合わせて変更することができます。

上記の結果に導く仕組みは多数の方法で得られますが、ここでは Kubernetes pod を使用して、1 つのコンテナーで Python スクリプトを実行し、もう 1 つのコンテナーで Otel を実行して、メトリクスのプルとプッシュを行います... 自分のやり方を選択することはできますが、この例と記事では、k8s を主人公に Python を使って行います。

手順:

  • 前提条件
  • Python
  • コンテナー
  • Kubernetes
  • Google Cloud Monitoring

前提要件:

  • IRIS®  Cloud SQL の有効なサブスクリプション
  • 実行中の 1 つのデプロイメント(オプションで Integrated ML を使用)
  • 環境に提供するシークレット

環境変数

 
 シークレットの取得
この内容は少し複雑で本題から少し外れているためティーザーに入れましたが、これがシークレットの生成に必要なる値です。
ENV IRIS_CLOUDSQL_USER 'user'
ENV IRIS_CLOUDSQL_PASS 'pass'

☝ これは https://portal.live.isccloud.io の認証情報です。

ENV IRIS_CLOUDSQL_USERPOOLID 'userpoolid'
ENV IRIS_CLOUDSQL_CLIENTID 'clientid'
ENV IRIS_CLOUDSQL_API 'api'

☝ これはブラウザの開発ツールから取得する必要があります。

  • `aud` = clientid
  • `userpoolid`= iss
  • `api` = request utl

ENV IRIS_CLOUDSQL_DEPLOYMENTID 'deploymentid'

☝これはクラウドサービスポータルから取得できます

 

Python:

以下に、クラウドポータルからメトリクスを取得し、それを Otel Collectorが取得するメトリクスとしてローカルにエクスポートする Python ハッキングを示します。

 
iris_cloudsql_exporter.py
import time
import os
import requests
import json

from warrant import Cognito from prometheus_client.core import GaugeMetricFamily, REGISTRY, CounterMetricFamily from prometheus_client import start_http_server from prometheus_client.parser import text_string_to_metric_families

classIRISCloudSQLExporter(object):definit(self): self.access_token = self.get_access_token() self.portal_api = os.environ['IRIS_CLOUDSQL_API'] self.portal_deploymentid = os.environ['IRIS_CLOUDSQL_DEPLOYMENTID']

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">collect</span><span class="hljs-params">(self)</span>:</span>
    <span class="hljs-comment"># Requests fodder</span>
    url = self.portal_api
    deploymentid = self.portal_deploymentid
    print(url)
    print(deploymentid)

    headers = {
        <span class="hljs-string">'Authorization'</span>: self.access_token, <span class="hljs-comment"># needs to be refresh_token, eventually</span>
        <span class="hljs-string">'Content-Type'</span>: <span class="hljs-string">'application/json'</span>
    }

    metrics_response = requests.request(<span class="hljs-string">"GET"</span>, url + <span class="hljs-string">'/metrics/'</span> + deploymentid, headers=headers)
    metrics = metrics_response.content.decode(<span class="hljs-string">"utf-8"</span>)

    <span class="hljs-keyword">for</span> iris_metrics <span class="hljs-keyword">in</span> text_string_to_metric_families(metrics):
        <span class="hljs-keyword">for</span> sample <span class="hljs-keyword">in</span> iris_metrics.samples:

            labels_string = <span class="hljs-string">"{1}"</span>.format(*sample).replace(<span class="hljs-string">'\''</span>,<span class="hljs-string">"\""</span>)
            labels_dict = json.loads(labels_string)
            labels = []

            <span class="hljs-keyword">for</span> d <span class="hljs-keyword">in</span> labels_dict:
                labels.extend(labels_dict)
            <span class="hljs-keyword">if</span> len(labels) &gt; <span class="hljs-number">0</span>:
                g = GaugeMetricFamily(<span class="hljs-string">"{0}"</span>.format(*sample), <span class="hljs-string">'Help text'</span>, labels=labels)
                g.add_metric(list(labels_dict.values()), <span class="hljs-string">"{2}"</span>.format(*sample))
            <span class="hljs-keyword">else</span>:
                g = GaugeMetricFamily(<span class="hljs-string">"{0}"</span>.format(*sample), <span class="hljs-string">'Help text'</span>, labels=labels)
                g.add_metric([<span class="hljs-string">""</span>], <span class="hljs-string">"{2}"</span>.format(*sample))
            <span class="hljs-keyword">yield</span> g

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">get_access_token</span><span class="hljs-params">(self)</span>:</span>
    <span class="hljs-keyword">try</span>:
        user_pool_id = os.environ[<span class="hljs-string">'IRIS_CLOUDSQL_USERPOOLID'</span>] <span class="hljs-comment"># isc iss </span>
        username = os.environ[<span class="hljs-string">'IRIS_CLOUDSQL_USER'</span>]
        password = os.environ[<span class="hljs-string">'IRIS_CLOUDSQL_PASS'</span>]
        clientid = os.environ[<span class="hljs-string">'IRIS_CLOUDSQL_CLIENTID'</span>] <span class="hljs-comment"># isc aud </span>
        print(user_pool_id)
        print(username)
        print(password)
        print(clientid)
        
        <span class="hljs-keyword">try</span>:
            u = Cognito(
                user_pool_id=user_pool_id,
                client_id=clientid,
                user_pool_region=<span class="hljs-string">"us-east-2"</span>, <span class="hljs-comment"># needed by warrant, should be derived from poolid doh</span>
                username=username
            )
            u.authenticate(password=password)
        <span class="hljs-keyword">except</span> Exception <span class="hljs-keyword">as</span> p:
            print(p)
    <span class="hljs-keyword">except</span> Exception <span class="hljs-keyword">as</span> e:
        print(e)

    <span class="hljs-keyword">return</span> u.id_token

ifname == 'main':

start_http_server(<span class="hljs-number">8000</span>)
REGISTRY.register(IRISCloudSQLExporter())
<span class="hljs-keyword">while</span> <span class="hljs-keyword">True</span>:
    REGISTRY.collect()
    print(<span class="hljs-string">"Polling IRIS CloudSQL API for metrics data...."</span>)
    <span class="hljs-comment">#looped e loop</span>
    time.sleep(<span class="hljs-number">120</span>)</code></pre>

 

Docker:

 
Dockerfile
FROM python:3.8ADD src /src
RUN pip install prometheus_client
RUN pip install requests
WORKDIR /src
ENV PYTHONPATH '/src/'ENV PYTHONUNBUFFERED=1ENV IRIS_CLOUDSQL_USERPOOLID 'userpoolid'ENV IRIS_CLOUDSQL_CLIENTID 'clientid'ENV IRIS_CLOUDSQL_USER 'user'ENV IRIS_CLOUDSQL_PASS 'pass'ENV IRIS_CLOUDSQL_API 'api'ENV IRIS_CLOUDSQL_DEPLOYMENTID 'deploymentid'RUN pip install -r requirements.txt
CMD ["python" , "/src/iris_cloudsql_exporter.py"]
docker build -t iris-cloudsql-exporter .
docker image tag iris-cloudsql-exporter sween/iris-cloudsql-exporter:latest
docker push sween/iris-cloudsql-exporter:latest


デプロイメント:

k8s、ネームスペースを作成します:

kubectl create ns iris

k8s、シークレットを追加します:

kubectl create secret generic iris-cloudsql -n iris \
    --from-literal=user=$IRIS_CLOUDSQL_USER \
    --from-literal=pass=$IRIS_CLOUDSQL_PASS \
    --from-literal=clientid=$IRIS_CLOUDSQL_CLIENTID \
    --from-literal=api=$IRIS_CLOUDSQL_API \
    --from-literal=deploymentid=$IRIS_CLOUDSQL_DEPLOYMENTID \
    --from-literal=userpoolid=$IRIS_CLOUDSQL_USERPOOLID

otel、構成を作成します:

apiVersion: v1
data:
  config.yaml: |
    receivers:
      prometheus:
        config:
          scrape_configs:
          - job_name: 'IRIS CloudSQL'
              # Override the global default and scrape targets from this job every 5 seconds.
            scrape_interval: 30s
            scrape_timeout: 30s
            static_configs:
                    - targets: ['192.168.1.96:5000']
            metrics_path: /
exporters:
  googlemanagedprometheus:
    project: "pidtoo-fhir"
service:
  pipelines:
    metrics:
      receivers: [prometheus]
      exporters: [googlemanagedprometheus]

kind: ConfigMap metadata: name: otel-config namespace: iris

k8s、otel 構成を configmap としてロードします:

kubectl -n iris create configmap otel-config --from-file config.yaml

k8s、ロードバランサー(確実にオプション)、MetalLB をデプロイします。これはクラスタ外部からグスクレイピングして検査するために行っています。

cat <<EOF | kubectl apply -f -n iris -
apiVersion: v1
kind: Service
metadata:
  name: iris-cloudsql-exporter-service
spec:
  selector:
    app: iris-cloudsql-exporter
  type: LoadBalancer
  ports:
  - protocol: TCP
    port: 5000
    targetPort: 8000
EOF

gcp、Google Cloud へのキーが必要です。サービスアカウントにスコープを設定する必要があります

  • roles/monitoring.metricWriter
kubectl -n iris create secret generic gmp-test-sa --from-file=key.json=key.json

k8s; deployment/pod そのもの。2 つのコンテナー:

 
deployment.yaml
kubectl -n iris apply -f deployment.yaml

実行

特に問題がなければ、ネームスペースを詳しく調べて、状況を確認してみましょう。

✔ GCP と Otel 用の 2 つの configmap

 

✔ 1 つのロードバランサー

 

✔ 1 つの pod、2 つのコンテナーが正しくスクレイピングされます

  

Google Cloud Monitoring

可観測性を調べてメトリクスが正しく受信されていることを確認し、可観測性を高めましょう!

 

0
0 20
記事 Toshihiko Minamoto · 3月 17, 2021 31m read

この記事では、従来のIRISミラーリング構成の代わりに、Kubernetesの Deploymentと分散永続ストレージを使って高可用性IRIS構成を構築します。 このデプロイでは、ノード、ストレージ、アベイラビリティーゾーンといったインフラストラクチャ関連の障害に耐えることが可能です。 以下に説明する方法を使用することで、RTOがわずかに延長されますが、デプロイの複雑さが大幅に軽減されます。

図1 - 従来のミラーリング構成と分散ストレージを使ったKubernetesの比較

この記事に記載されているすべてのソースコードは、https://github.com/antonum/ha-iris-k8s より入手できます。
要約

3ノードクラスタを実行しており、Kubernetesにいくらか詳しい方は、このまま以下のコードを使用してください。

kubectl apply -f https://raw.githubusercontent.com/longhorn/longhorn/master/deploy/longhorn.yaml
kubectl apply -f https://github.com/antonum/ha-iris-k8s/raw/main/tldr.yaml

上記の2行の意味がよくわからない方、またはこれらを実行できるシステムがない場合は、「高可用性要件」のセクションにお進みください。 説明しながら進めていきます。

最初の行は、Longhornというオープンソースの分散Kubernetesストレージをインストールしています。 2行目は、DurableSYS用にLonghornベースのボリュームを使って、InterSystems IRISデプロイをインストールしています。

すべてのポッドが実行状態になるまで待ちます。 kubectl get pods -A

上記の手順を済ませると、http://<IRIS Service Public IP>:52773/csp/sys/%25CSP.Portal.Home.zenにあるIRIS管理ポータル(デフォルトのパスワードは「SYS」)にアクセスできるようになります。また、次のようにしてIRISコマンドラインも使用できるようになります。

kubectl exec -it iris-podName-xxxx -- iris session iris

障害をシミュレートする

では、実際に操作してみましょう。 ただし、操作の前に、データベースにデータを追加して、IRISがオンラインになったときに存在することを確認してください。

kubectl exec -it iris-6d8896d584-8lzn5 -- iris session iris
USER>set ^k8stest($i(^k8stest))=$zdt($h)_" running on "_$system.INetInfo.LocalHostName()
USER>zw ^k8stest
^k8stest=1
^k8stest(1)="01/14/2021 14:13:19 running on iris-6d8896d584-8lzn5"

ここからが「カオスエンジニアリング」の始まりです。

# IRISを停止 - コンテナは自動的に再開します
kubectl exec -it iris-6d8896d584-8lzn5 -- iris stop iris quietly
 
# ポッドを削除 - ポッドが再作成されます
kubectl delete pod iris-6d8896d584-8lzn5
 
# irisポッドの配信によりノードを「強制ドレイン」 - ポッドは別のノードで再作成されます
kubectl drain aks-agentpool-29845772-vmss000001 --delete-local-data --ignore-daemonsets --force
 
# ノードを削除 - ポッドは別のノードで再作成されます
# ただし、kubectlでは削除できないので、 そのインスタンスまたはVMを見つけて、強制終了します。
マシンにアクセスできる場合は、電源を切るかネットワークケーブルを外します。 冗談ではありません!

高可用性要件

 

以下の障害に耐えられるシステムを構築しています。

  • コンテナ/VM内のIRISインスタンス。 IRIS - レベル障害
  • ポッド/コンテナの障害
  • 個々のクラスタノードの一時的な使用不能。 アベイラビリティーゾーンが一時的にオフラインになる場合などが挙げられます。
  • 個々のクラスタノードまたはディスクの永久的障害。

基本的に、「障害をシミュレートする」セクションで試したシナリオです。

上記のいずれかの障害が発生すると、システムは人間が手をいれなくてもオンラインになり、データも失われません。 データの永続性が保証する範囲には一応制限がありますが、 ジャーナルサイクルとアプリケーション内のトランザクションの使用状況に応じて、IRISで実現されます(https://docs.intersystems.com/irisforhealthlatestj/csp/docbook/Doc.View.cls?KEY=GCDI_journal#GCDI_journal_writecycle)。いずれにしても、RPO(目標復旧ポイント)は2秒未満です。

システムの他のコンポーネント(Kubernetes APIサービス、etcdデータベース、ロードバランサーサービス、DNSなど)はスコープ外であり、通常、Azure AKSやAWS EKSなどのマネージドKubernetesサービスで管理されます。

別の言い方をすれば、個別の計算コンポーネントやストレージコンポーネントの障害はユーザーが処理するものであり、その他のコンポーネントの障害はインフラストラクチャ/クラウドプロバイダーが対処するものと言えます。

アーキテクチャ

InterSystems IRISの高可用性について言えば、これまでミラーリングの使用が勧められてきました。 ミラーリングでは、データは、常時オンライン状態にある2つのIRISインスタンスが同期的に複製されます。 各ノードにはデータベースの完全なコピーが維持され、プライマリノードがオフラインになると、ユーザーはバックアップノードに接続し直すことができます。 基本的に、ミラーリング手法では、計算とストレージの両方の冗長性は、IRISが管理するものです。

ミラーをさまざまなアベイラビリティーゾーンにデプロイしたミラーリングにより、計算処理とストレージの障害に備えた必要な冗長性を実現し、わずか数秒という優れたRTO(目標復旧時間または障害後にシステムがオンラインに復旧するまでにかかる時間)を達成することができます。 AWSクラウドでミラーリングされたIRISのデプロイテンプレートは、https://jp.community.intersystems.com/node/486206から入手できます。

一方で、ミラーリングには、設定やバックアップ/復旧手順が複雑で、セキュリティ設定とローカルのデータベース以外のファイルの複製機能が不足しているという欠点があります。

コンテナオーケストレータ―にはKubernetesなど(今や2021年。ほかにオーケストレーターってありますか?!)がありますが、これらは、障害時に、Deploymentオブジェクトが障害のあるIRISポッド/コンテナを自動的に再起動することで、計算冗長性を実現しています。 Kubernetesアーキテクチャ図に、実行中のIRISノードが1つしかないのはこのためです。 2つ目のIRISノードを常時実行し続ける代わりに、計算可用性をKubernetesにアウトソースしています。 Kubernetesは、元のIRISポッドが何らかの理由でエラーとなった場合に、IRISポッドの再作成を確保します。

図2 フェイルオーバーのシナリオ

ここまでよろしいでしょうか。 IRISノードに障害が発生すると、Kubernetesは単に新しいノードを作成します。 クラスタによって異なりますが、計算障害が発生してからIRISがオンラインになるまでには、10~90秒かかります。 ミラーリングではわずか2秒で復旧されるわけですから、これはダウングレードとなりますが、万が一サービス停止となった場合に許容できる範囲であれば、複雑さが緩和されることは大きなメリットと言えます。 ミラーリングの構成は不要です。 セキュリティ設定やファイル複製を気にする必要もありません。

率直に言うと、KubernetesでIRISを実行し、コンテナにログインしても、高可用性環境で実行していることには気づくこともないでしょう。 単一インスタンスのIRISデプロイと全く同じように見え、何ら感触にも変化はありません。

では、ストレージはどうでしょうか。 データベースを扱っているわけですから気になります。 どのようなフェイルオーバーのシナリオであっても、システムはデータの永続性も処理する必要があります。 ミラーリングは、IRISノードのローカルである計算ノードに依存しているため、 ノードが停止するか、一時的に使用不可になってしまえば、そのノードのストレージも停止してしまいます。 ミラーリング構成では、IRISがIRISレベルでデータベースを複製するのはこれに対処するためです。

コンテナの再起動時に元の状態を維持したデータベースを使用できるだけでなく、ノードやネットワークのセグメント全体(アベイラビリティーゾーン)が停止するといったイベントに備えて、冗長性を提供できるストレージが必要です。 ほんの数年前、これを解決できる簡単な答えは存在しませんでした。 上の図から推測できるように、今ではその答えを得ています。 分散コンテナストレージです。

分散ストレージは、基盤のホストボリュームを抽象化し、k8sクラスタのすべてのノードが使用できる共同の1つのクラスターとして提示します。 この記事では、インストールが非常に簡単なLonghorn(https://longhorn.io)という無料のオープンソースのストレージを使用しますが、 OpenEBS、Porworx、StorageOSといったほかのストレージも利用できます。同じ機能が提供されています。 CNCF IncubatingプロジェクトであるRook Cephも検討する価値があるでしょう。 この種のハイエンドとしては、NetAppやPureStorageといったエンタープライズ級のストレージソリューションがあります。

手順

「要約」セクションでは、1回にすべてをインストールしました。 インストールと検証の手順の説明は、付録Bをご覧ください。

Kubernetesストレージ

まずは、コンテナとストレージ全般について、またIRISがどこに適合するのかについて説明しましょう。

デフォルトでは、コンテナ内のすべてのデータは揮発性であるため、 コンテナが停止すればデータは消失します。 Dockerでは、ボリュームの概念を使用することができるため、 基本的に、ホストOSのディレクトリをコンテナに公開することができます。

docker run --detach
  --publish 52773:52773
  --volume /data/dur:/dur
  --env ISC_DATA_DIRECTORY=/dur/iconfig
  --name iris21 --init intersystems/iris:2020.3.0.221.0

上記の例では、IRISコンテナを起動し、host-localの「/data/dur」ディレクトリを、「/dur」マウントポイントのコンテナからアクセスできるようにしています。 つまり、コンテナがこのディレクトリに何かを格納している場合、それは保持され、コンテナの次回起動時に使用できるようになります。

IRIS側では、ISC_DATA_DIRECTORYを指定することで、IRISに、コンテナの再起動時に損失してはいけないすべてのデータを特定のディレクトリに格納するように指示することができます。 ドキュメントの「Durable SYS」というIRISの機能をご覧ください( https://docs.intersystems.com/irisforhealthlatestj/csp/docbook/Doc.View.cls?KEY=ADOCK#ADOCK_iris_durable_running)。

Kubernetesでの構文は異なりますが、概念は同じです。

IRISの基本的なKubernetes Deploymentは以下のようになります。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: iris
spec:
  selector:
    matchLabels:
      app: iris
  strategy:
    type: Recreate
  replicas: 1
  template:
    metadata:
      labels:
        app: iris
    spec:
      containers:
      - image: store/intersystems/iris-community:2020.4.0.524.0
        name: iris
        env:
        - name: ISC_DATA_DIRECTORY
          value: /external/iris
        ports:
        - containerPort: 52773
          name: smp-http
        volumeMounts:
        - name: iris-external-sys
          mountPath: /external
      volumes:
      - name: iris-external-sys
        persistentVolumeClaim:
          claimName: iris-pvc

 

上記のデプロイ仕様では、「volumes」の部分にストレージボリュームがリストされています。 このボリュームには、「iris-pvc」などのpersistentVolumeClaimを介して、コンテナの外部からアクセスできます。 volumeMountsは、このボリュームをコンテナ内に公開します。 「iris-external-sys」は、ボリュームマウントを特定のボリュームに関連付ける識別子です。 実際には複数のボリュームが存在する可能性があり、ほかのボリュームと区別するためにこの名前が使用されるわけですから、 「steve」と名付けることも可能です。

すでにお馴染みのISC_DATA_DIRECTORYは、IRISが特定のマウントポイントを使用して、コンテナの再起動後も存続する必要のあるすべてのデータを格納するように指示する環境変数です。

では、persistentVolumeClaimのiris-pvcを見てみましょう。

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: iris-pvc
spec:
  storageClassName: longhorn
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 10Gi

 

かなりわかりやすいと思います。 「longhorn」ストレージクラスを使って、1つのノードでのみ読み取り/書き込みとしてマウント可能な、10ギガバイトを要求しています。

ここで重要なのは、storageClassName: longhornです。

AKSクラスタで利用できるストレージクラスを確認してみましょう。

kubectl get StorageClass
NAME                             PROVISIONER                     RECLAIMPOLICY   VOLUMEBINDINGMODE   ALLOWVOLUMEEXPANSION   AGE
azurefile                        kubernetes.io/azure-file        Delete          Immediate           true                   10d
azurefile-premium                kubernetes.io/azure-file        Delete          Immediate           true                   10d
default (default)                kubernetes.io/azure-disk        Delete          Immediate           true                   10d
longhorn                         driver.longhorn.io              Delete          Immediate           true                   10d
managed-premium                  kubernetes.io/azure-disk        Delete          Immediate           true                   10d

Azureのストレージクラスはほとんどありませんが、これらは、デフォルトでインストールされたクラスと、以下の一番最初のコマンドの一部でインストールしたLonghornのクラスです。

kubectl apply -f https://raw.githubusercontent.com/longhorn/longhorn/master/deploy/longhorn.yaml

永続ボリュームクレームの定義に含まれる#storageClassName: longhornをコメントアウトすると、現在「default」としてマークされているストレージクラスが使用されます。これは、通常のAzureディスクです。

分散ストレージが必要な理由を説明するために、この記事の始めに説明した、longhornストレージを使用しない「カオスエンジニアリング」実験をもう一度行ってみましょう。 最初の2つのシナリオ(IRISの停止とポッドの削除)は正常に完了し、システムは稼働状態に回復します。 ノードをドレインまたは強制終了しようとすると、システムは障害状態になります。

#forcefully drain the node
kubectl drain aks-agentpool-71521505-vmss000001 --delete-local-data --ignore-daemonsets

kubectl describe pods ...   Type     Reason            Age                  From               Message   ----     ------            ----                 ----               -------   Warning  FailedScheduling  57s (x9 over 2m41s)  default-scheduler  0/3 nodes are available: 1 node(s) were unschedulable, 2 node(s) had volume node affinity conflict.

基本的に、KubernetesはクラスタのIRISポッドを再起動しようとしますが、最初に起動されていたノードは利用できないため、ほかの2つのノードに「ボリュームノードアフィニティの競合」が発生しています。 このストレージタイプでは、基本的にボリュームはノードホストで使用可能なディスクに関連付けられているため、最初に作成されたノードでしか使用できないのです。

ストレージクラスにlonghornを使用すると、「強制ドレイン」と「ノードの強制終了」の2つの実験は正常に完了し、間もなくしてIRISポッドの動作が再開します。 これを実現するために、Longhornは3ノードクラスタをで使用可能なストレージを制御し、3つのすべてのノードにデータを複製しています。 ノードの1つが永久的に使用不可になると、Longhornは迅速にクラスタストレージを修復します。 「ノードの強制終了」シナリオでは、IRISポッドはほかの2つのボリュームレプリカを使ってすぐに別のノードで再起動されます。 するとAKSは失われたノードに置き換わる新しいノードをプロビジョニングし、準備ができたら、Longhorn がそのノードに必要なデータを再構築します。 すべては自動的に行われるため、ユーザーが手を入れる必要はありません。

図3 置換されたノードにボリュームレプリカを再構築するLonghorn

k8sデプロイについて

デプロイの他の側面をいくつか見てみましょう。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: iris
spec:
  selector:
    matchLabels:
      app: iris
  strategy:
    type: Recreate
  replicas: 1
  template:
    metadata:
      labels:
        app: iris
    spec:
      containers:
      - image: store/intersystems/iris-community:2020.4.0.524.0
        name: iris
        env:
        - name: ISC_DATA_DIRECTORY
          value: /external/iris
        - name: ISC_CPF_MERGE_FILE
          value: /external/merge/merge.cpf
        ports:
        - containerPort: 52773
          name: smp-http
        volumeMounts:
        - name: iris-external-sys
          mountPath: /external
        - name: cpf-merge
          mountPath: /external/merge
        livenessProbe:
          initialDelaySeconds: 25
          periodSeconds: 10
          exec:
            command:
            - /bin/sh
            - -c
            - "iris qlist iris | grep running"
      volumes:
      - name: iris-external-sys
        persistentVolumeClaim:
          claimName: iris-pvc
      - name: cpf-merge
        configMap:
          name: iris-cpf-merge

 

strategy: Recreateとreplicas: 1では、Kubernetesに、常にIRISポッドの1つのインスタンスのみを実行し続けることを指示しています。 これが「ポッドの削除」シナリオを処理する部分です。

livenessProbeのセクションでは、IRISが常時、コンテナ内で稼働し、「IRIS停止」シナリオを処理できるようにしています。 initialDelaySecondsは、IRISが起動するまでの猶予期間です。 IRISがデプロイを起動するのにかなりの時間が掛かっている場合は、これを増やすと良いでしょう。

IRISのCPF MERGE機能を使用すると、コンテナの起動時に、iris.cpf構成ファイルのコンテンツを変更することができます。 関連するドキュメントについては、 https://docs.intersystems.com/irisforhealthlatestj/csp/docbook/DocBook.UI.Page.cls?KEY=RACS_cpf#RACS_cpf_edit_mergeをご覧ください。 この例では、Kubernetesの構成図を使って、マージファイルのコンテンツを管理しています( https://github.com/antonum/ha-iris-k8s/blob/main/iris-cpf-merge.yaml)。ここでは、IRISインスタンスが使用するグローバルバッファとgmheapの値を調整していますが、iris.cpfファイルにあるものはすべて調整できます。 デフォルトのIRISパスワードでさえも、CPFマージファイルの「PasswordHash」フィールドで変更可能です。 詳細については、https://docs.intersystems.com/irisforhealthlatestj/csp/docbook/Doc.View.cls?KEY=ADOCK#ADOCK_iris_images_password_authをご覧ください。

永続ボリュームクレーム(https://github.com/antonum/ha-iris-k8s/blob/main/iris-pvc.yaml)デプロイ(https://github.com/antonum/ha-iris-k8s/blob/main/iris-deployment.yaml)とCPFマージコンテンツを使った構成図(https://github.com/antonum/ha-iris-k8s/blob/main/iris-cpf-merge.yaml)のほかに、デプロイには、IRISデプロイをパブリックインターネットに公開するサービスが必要です(https://github.com/antonum/ha-iris-k8s/blob/main/iris-svc.yaml)。

kubectl get svc
NAME         TYPE           CLUSTER-IP    EXTERNAL-IP     PORT(S)           AGE
iris-svc     LoadBalancer   10.0.18.169   40.88.123.45   52773:31589/TCP   3d1h
kubernetes   ClusterIP      10.0.0.1      <none>          443/TCP           10d

iris-svcの外部IPは、http://40.88.123.45:52773/csp/sys/%25CSP.Portal.Home.zenを介してIRIS管理ポータルにアクセスするために使用できます。 デフォルトのパスワードは「SYS」です。

ストレージのバックアップ/復元とスケーリング

Longhornには、ボリュームの構成と管理を行えるウェブベースのUIがあります。

kubectlを使用して、ポッドや実行中のlonghorn-uiコンポーネントを特定し、ポート転送を確立できます。

kubectl -n longhorn-system get pods
# longhorn-uiのポッドIDに注意してください。

kubectl port-forward longhorn-ui-df95bdf85-gpnjv 9000:8000 -n longhorn-system

Longhorn UIは、http://localhost:9000で利用できるようになります。

図4 LonghornのUI

Kubernetesコンテナストレージのほとんどのソリューションでは、高可用性のほか、バックアップ、スナップショット、および復元のための便利なオプションが用意されています。 詳細は実装によって異なりますが、一般的には、バックアップをVolumeSnapshotに関連付ける方法です。 この方法はLonghornでも利用できます。 使用しているKubernetesのバージョンとプロバイダーによっては、ボリュームスナップショット機能( https://github.com/kubernetes-csi/external-snapshotter)もインストールする必要があります。

そのようなボリュームショットの例には、「iris-volume-snapshot.yaml」が挙げられます。 使用する前に、バックアップを、LonghornのS3バケットまたはNFSボリュームに構成する必要があります。 https://longhorn.io/docs/1.0.1/snapshots-and-backups/backup-and-restore/set-backup-target/

# IRISボリュームのクラッシュコンシステントなバックアップを取得する
kubectl apply -f iris-volume-snapshot.yaml

IRISでは、バックアップ/スナップショットを取得する前にExternal Freezeを実行し、後でThawを実行することをお勧めします。 詳細については、https://docs.intersystems.com/irisforhealthlatestj/csp/documatic/%25CSP.Documatic.cls?LIBRARY=%25SYS&CLASSNAME=Backup.General#ExternalFreezeをご覧ください。  

IRISボリュームのサイズを増やすには、IRISが使用する、永続ボリュームクレーム(iris-pvc.yamlファイル)のストレージリクエストを調整します。

...
  resources:
    requests:
      storage: 10Gi #change this value to required

そして、pvcの仕様を再適用します。 Longhornは、実行中のポッドにボリュームが接続されている場合、この変更を実際に適用することはできません。 そのため、ボリュームサイズが増えるように、デプロイでレプリカ数を一時的にゼロに変更します。

高可用性 - 概要

この記事の冒頭で、高可用性の基準を設定しました。 このアーキテクチャでは、次のようにそれを実現します。

障害の領域

自動的に緩和処置を行う機能

コンテナ/VM内のIRISインスタンス。 IRIS - レベル障害

IRISが機能停止となった場合、デプロイのLiveness Probeによってコンテナが再起動されます。

ポッド/コンテナの障害

デプロイによってポッドが再作成されます。

個々のクラスタノードの一時的な使用不能。 アベイラビリティーゾーンがオフラインになる場合などが挙げられます。

デプロイによって別のノードにポッドが再作成されます。 Longhornによって、別のノードでデータが使用できるようになります。

個々のクラスタノードまたはディスクの永久的障害。

上記と同様かつ、k8sクラスタオートスケーラーによって、破損したノードが新しいノードに置き換えられます。 Longhornによって、新しいノードにデータが再構築されます。

ゾンビやその他の考慮事項

DockerコンテナでのIRISの実行を理解している方であれば、「--init」フラグを使用したことがあるでしょう。

docker run --rm -p 52773:52773 --init store/intersystems/iris-community:2020.4.0.524.0

このフラグは、「ゾンビプロセス」の形成を防止することを目的としています。 Kubernetesでは、「shareProcessNamespace: true」を使用する(セキュリティの考慮事項が適用されます)か、コンテナで「tini」を使用することができます。 以下に、tiniを使用したDockerfileの例を示します。

FROM iris-community:2020.4.0.524.0
...
# Tiniを追加します
USER root
ENV TINI_VERSION v0.19.0
ADD https://github.com/krallin/tini/releases/download/${TINI_VERSION}/tini /tini
RUN chmod +x /tini
USER irisowner
ENTRYPOINT ["/tini", "--", "/iris-main"]

2021年以降、すべてのInterSystemsが提供するコンテナイメージには、デフォルトでtiniが含まれています。

いくつかのパラメーターを調整することで、「ノードの強制ドレイン/ノードの強制終了」シナリオのフェイルオーバー時間をさらに短縮することができます。

Longhornのポッド削除ポリシー(https://longhorn.io/docs/1.1.0/references/settings/#pod-deletion-policy-when-node-is-down)およびkubernetes taintベースのエビクション機能(https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/#taint-based-evictions)をご覧ください。

免責事項

InterSystemsに勤務する者として、この内容を記載しておく必要があります。この記事では、分散型Kubernetesブロックストレージの一例としてLonghornを使用しています。 InterSystemsは、個々のストレージソリューションや製品を検証ないしは公式なサポート声明を発行していません。 特定のストレージソリューションがニーズに適合しているかどうかは、ユーザー自身がテストして検証する必要があります。

分散ストレージには、ノードローカルストレージとは大きく異なるパフォーマンス特性も備わっています。 特に書き込み操作の場合、データが永続化された状態とみなされるには、データを複数の場所に書き込む必要があります。 必ずワークロードをテストし、CSIドライバが提供する特定の動作とオプションを理解するようにしてください。

InterSystemsでは基本的に、Longhornなどの特定のストレージjソリューションを検証あるいは承認していません。これは、個々のHDDブランドやサーバーハードウェアメーカーを検証しないのと同じです。 個人的には、Longhornは扱いやすいと感じています。プロジェクトのGitHubページ(https://github.com/longhorn/longhorn)では、その開発チームは積極的に応答し、よく助けていただいています。 

まとめ

Kubernetesエコシステムは、過去数年間で大きな進化を遂げました。今日では、分散ブロックストレージソリューションを使用することで、IRISインスタンスやクラスタノード、さらにはアベイラビリティーゾーンの障害を維持できる高可用性構成を構築できるようにもなっています。

計算とストレージの高可用性をKubernetesコンポーネントにアウトソースできるため、従来のIRISミラーリングに比べ、システムの構成と管理が大幅に単純化しています。 ただしこの構成では、ミラーリング構成ほどのRTOとストレージレベルのパフォーマンスは得られないことがあります。

この記事では、Azure AKSをマネージドKubernetesとLonghorn分散ストレージシステムとして使用し、可用性の高いIRIS構成を構築しました。 ほかにも、AWS EKS、マネージドK8s向けのGoogle Kubernetes Engine、StorageOS、Portworx、OpenEBSなどの様々な分散コンテナストレージを探ってみると良いでしょう。エンタープライズ級のストレージソリューションには、NetApp、PureStorage、Dell EMCなどもあります。

付録A: クラウドでのKubernetesクラスタの作成

パブリッククラウドプロバイダーが提供するマネージドKubernetesサービスを使うと、このセットアップに必要なk8sクラスタを簡単に作成できます。 この記事で説明したデプロイには、AzureのAKSデフォルト構成をそのまますぐに使用することができます。

3ノードで新しいAKSクラスタを作成します。 それ以外はすべてデフォルトのままにします。

図5 AKSクラスタの作成

ローカルコンピュータにkubectlをインストールします。https://kubernetes.io/docs/tasks/tools/install-kubectl/

ローカルkubectlにASKクラスタを登録します。

 

図6 kubectlにAKSクラスタを登録

登録が済んだら、この記事の最初に戻って、longhornとIRISデプロイをインストールします。

AWS EKSでのインストールは、もう少し複雑です。 ノードグループのすべてのインスタンスにopen-iscsiがインストトールされていることを確認する必要があります。

sudo yum install iscsi-initiator-utils -y

GKEでのLonghornのインストールには追加の手順があります。https://longhorn.io/docs/1.0.1/advanced-resources/os-distro-specific/csi-on-gke/をご覧ください。

付録B: インストール手順

手順1 - Kubernetesクラスタとkubectl

3ノードk8sクラスタが必要です。 Azureでのクラスタの構成方法は付録Aをご覧ください。

$ kubectl get nodes
NAME                                STATUS   ROLES   AGE   VERSION
aks-agentpool-29845772-vmss000000   Ready    agent   10d   v1.18.10
aks-agentpool-29845772-vmss000001   Ready    agent   10d   v1.18.10
aks-agentpool-29845772-vmss000002   Ready    agent   10d   v1.18.10

手順2 - Longhornをインストールする

kubectl apply -f https://raw.githubusercontent.com/longhorn/longhorn/master/deploy/longhorn.yaml

「longhorn-system」ネームスペースのすべてのポッドが実行状態であることを確認してください。 これには数分かかる場合があります。

$ kubectl get pods -n longhorn-system
NAME                                       READY   STATUS    RESTARTS   AGE
csi-attacher-74db7cf6d9-jgdxq              1/1     Running   0          10d
csi-attacher-74db7cf6d9-l99fs              1/1     Running   1          11d
...
longhorn-manager-flljf                     1/1     Running   2          11d
longhorn-manager-x76n2                     1/1     Running   1          11d
longhorn-ui-df95bdf85-gpnjv                1/1     Running   0          11d

詳細とトラブルシューティングについては、Longhornインストールガイド(https://longhorn.io/docs/1.1.0/deploy/install/install-with-kubectl)をご覧ください。

手順3 - GitHubリポジトリのクローンを作成する

$ git clone https://github.com/antonum/ha-iris-k8s.git
$ cd ha-iris-k8s
$ ls
LICENSE                   iris-deployment.yaml      iris-volume-snapshot.yaml
README.md                 iris-pvc.yaml             longhorn-aws-secret.yaml
iris-cpf-merge.yaml       iris-svc.yaml             tldr.yaml

手順4 - コンポーネントを1つずつデプロイして検証する

tldr.yamlファイルには、デプロイに必要なすべてのコンポーンネントが1つのバンドルとして含まれています。 ここでは、コンポーネントを1つずつインストールし、それぞれのセットアップを個別に検証します。

# 以前にtldr.yamlを適用したことがある場合は、削除します。
$ kubectl delete -f https://github.com/antonum/ha-iris-k8s/raw/main/tldr.yaml

永続ボリュームクレームを作成します

$ kubectl apply -f iris-pvc.yaml persistentvolumeclaim/iris-pvc created

$ kubectl get pvc NAME       STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE iris-pvc   Bound    pvc-fbfaf5cf-7a75-4073-862e-09f8fd190e49   10Gi       RWO            longhorn       10s

構成図を作成します

$ kubectl apply -f iris-cpf-merge.yaml

$ kubectl describe cm iris-cpf-merge Name:         iris-cpf-merge Namespace:    default Labels:       <none> Annotations:  <none>

Data

merge.cpf:

[config] globals=0,0,800,0,0,0 gmheap=256000 Events:  <none>

irisデプロイを作成します

$  kubectl apply -f iris-deployment.yaml deployment.apps/iris created

$ kubectl get pods                     NAME                    READY   STATUS              RESTARTS   AGE iris-65dcfd9f97-v2rwn   0/1     ContainerCreating   0          11s

ポッド名を書き留めます。 この名前は、次のコマンドでポッドに接続する際に使用します。

$ kubectl exec -it iris-65dcfd9f97-v2rwn   -- bash

irisowner@iris-65dcfd9f97-v2rwn:~$ iris session iris Node: iris-65dcfd9f97-v2rwn, Instance: IRIS

USER>w $zv IRIS for UNIX (Ubuntu Server LTS for x86-64 Containers) 2020.4 (Build 524U) Thu Oct 22 2020 13:04:25 EDT

h<enter>でIRISシェルを終了

exit<enter>でポッドを終了

IRISコンテナのログにアクセスします

$ kubectl logs iris-65dcfd9f97-v2rwn ... [INFO] ...started InterSystems IRIS instance IRIS 01/18/21-23:09:11:312 (1173) 0 [Utility.Event] Private webserver started on 52773 01/18/21-23:09:11:312 (1173) 0 [Utility.Event] Processing Shadows section (this system as shadow) 01/18/21-23:09:11:321 (1173) 0 [Utility.Event] Processing Monitor section 01/18/21-23:09:11:381 (1323) 0 [Utility.Event] Starting TASKMGR 01/18/21-23:09:11:392 (1324) 0 [Utility.Event] [SYSTEM MONITOR] System Monitor started in %SYS 01/18/21-23:09:11:399 (1173) 0 [Utility.Event] Shard license: 0 01/18/21-23:09:11:778 (1162) 0 [Database.SparseDBExpansion] Expanding capacity of sparse database /external/iris/mgr/iristemp/ by 10 MB.

irisサービスを作成します

$ kubectl apply -f iris-svc.yaml    service/iris-svc created

$ kubectl get svc NAME         TYPE           CLUSTER-IP     EXTERNAL-IP    PORT(S)           AGE iris-svc     LoadBalancer   10.0.214.236   20.62.241.89   52773:30128/TCP   15s

手順5 - 管理ポータルにアクセスする

最後に、サービスの外部IP(http://20.62.241.89:52773/csp/sys/%25CSP.Portal.Home.zen)を使って、IRISの管理ポータルに接続します。ユーザー名は「_SYSTEM」、パスワードは「SYS」です。 初回ログイン時にパスワードの変更が求められます。

 

0
0 1217
記事 Toshihiko Minamoto · 11月 26, 2020 17m read

前回は GKE サービスを使用して IRIS アプリケーションを Google Cloud 上で起動しました。

また、クラスターを手動で(または gcloud を介して)作成するのは簡単ですが、最新の Infrastructure-as-Code(IaC)手法では、Kubernetesクラスターの説明もコードとしてリポジトリに格納する必要があります。 このコードの記述方法は、IaC に使用されるツールによって決まります。

Google Cloud の場合は複数のオプションが存在し、その中には Deployment ManagerTerraform があります。 どちらが優れているかにつては意見が分かれています。詳細を知りたい場合は、この Reddit のスレッド「Opinions on Terraform vs. Deployment Manager?」と Medium の記事「Comparing GCP Deployment Manager and Terraform」を参照してください。 

この記事では特定のベンダーとの結びつきが少なく、さまざまなクラウドプロバイダーで IaC を使用できる Terraform を選択します。

ここでは過去の記事を読み、Googleアカウントを作成し、前回の記事と同様に「開発」という名前のプロジェクトを作成しているものと仮定します。 この記事ではその ID は <PROJECT_ID> として表示されます。 以下の例では、それを自分のプロジェクトの IDに変更してください。 

Google には無料枠がありますが、無料ではないことに注意してください。 必ず出費をコントロールするようにしてください。

また、ここではすでに元のリポジトリをフォークしていることを前提にしています。 この記事全体を通してこのフォークを「my-objectscript-rest-docker-template」と呼び、そのルートディレクトリを「<root_repo_dir>」として参照します。

コピーと貼り付けを簡単にするため、すべてのコードサンプルをこのリポジトリに格納しています。

次の図では、デプロイプロセス全体を 1 つの図で表しています。

では、次のように執筆時点での Terraform の最新バージョンをインストールしましょう。

$ terraform version
Terraform v0.12.17

インターネット上の多くの例では旧バージョンが使用されており、0.12 では多くの変更が加えられているため、ここではバージョンが重要になります。

ここでは GCP アカウントで Terraform に特定のアクションを実行(特定の API を使用)させたいと考えています。 これを可能にするには「terraform」という名前のサービスアカウントを作成し、Kubernetes Engine API を有効にしてください。 その実施方法についてはご心配なく。この記事を読み進めるだけで、あなたの疑問は解消します。

Web Console を使用することもできますが、ここでは gcloud ユーティリティを使った例を試してみましょう。

次の例では、数種類のコマンドを使用します。 これらのコマンドや機能の詳細については、次のドキュメントのトピックを参照指定してください。

  • gcloud iam service-accounts create
  • 特定のリソースのサービスアカウントへの役割の付与
  • gcloud iam service-accounts keys create
  • Google Cloud プロジェクトでの API の有効化
  • それでは、例を見ていきましょう。

    $ gcloud init

    前回の記事で gcloud を取り上げましたので、ここではセットアップの詳細は説明しません。 この例では、次のコマンドを実行します。

    $ cd <root_repo_dir>
    $ mkdir terraform; cd terraform
    $ gcloud iam service-accounts create terraform --description "Terraform" --display-name "terraform"

    次に、「Kubernetes Engine Admin」(container.admin)の他にいくつかのロールを terraform サービスアカウントに追加しましょう。 これらのロールは今後役に立つことでしょう。

    $ gcloud projects add-iam-policy-binding <PROJECT_ID> \
      --member serviceAccount:terraform@<PROJECT_ID>.iam.gserviceaccount.com \
      --role roles/container.admin

    $ gcloud projects add-iam-policy-binding <PROJECT_ID> \
      --member serviceAccount:terraform@<PROJECT_ID>.iam.gserviceaccount.com \
      --role roles/iam.serviceAccountUser

    $ gcloud projects add-iam-policy-binding <PROJECT_ID> \
      --member serviceAccount:terraform@<PROJECT_ID>.iam.gserviceaccount.com \
      --role roles/compute.viewer

    $ gcloud projects add-iam-policy-binding <PROJECT_ID> \
      --member serviceAccount:terraform@<PROJECT_ID>.iam.gserviceaccount.com \
      --role roles/storage.admin

    $ gcloud iam service-accounts keys create account.json \
    --iam-account terraform@<PROJECT_ID>.iam.gserviceaccount.com

    最後の入力では、account.json ファイルを作成していることに注意してください。 このファイルは必ず秘密にしてください。

    $ gcloud projects list
    $ gcloud config set project <PROJECT_ID>
    $ gcloud services list --available | grep 'Kubernetes Engine'
    $ gcloud services enable container.googleapis.com
    $ gcloud services list --enabled | grep 'Kubernetes Engine'
    container.googleapis.com Kubernetes Engine API

    次に、Terraform の HCL 言語で GKE クラスターを記述しましょう。 ここではいくつかのプレースホルダーを使用していますが、これらは実際の値に置き換えてください。

    <td style="text-align: center;">
      意味
    </td>
    
    <td style="text-align: center;">
      例
    </td>
    
    <td>
        GCP のプロジェクト ID
    </td>
    
    <td>
        possible-symbol-254507
    </td>
    
    <td>
        Terraform のステート/ロック用のストレージ(一意である必要があります)
    </td>
    
    <td>
        circleci-gke-terraform-demo
    </td>
    
    <td>
        リソースが作成されるリージョン
    </td>
    
    <td>
        europe-west1
    </td>
    
    <td>
        リソースが作成されるゾーン
    </td>
    
    <td>
        europe-west1-b
    </td>
    
    <td>
        GKE クラスター名
    </td>
    
    <td>
        dev-cluster
    </td>
    
    <td>
        GKE ワーカーノードのプール名
    </td>
    
    <td>
        dev-cluster-node-pool
    </td>
    
    プレースホルダー
      <PROJECT_ID>
      <BUCKET_NAME>
      <REGION>
      <LOCATION>
      <CLUSTER_NAME>
      <NODES_POOL_NAME>

     

    以下に実際のクラスターの HCL 構成を示します。

    $ cat main.tf
    terraform {
      required_version = "~> 0.12"
      backend "gcs" {
        bucket = "<BUCKET_NAME>"
        prefix = "terraform/state"
        credentials = "account.json"
      }
    }

    provider "google" {
      credentials = file("account.json")
      project = "<PROJECT_ID>"
      region = "<REGION>"
    }

    resource "google_container_cluster" "gke-cluster" {
      name = "<CLUSTER_NAME>"
      location = "<LOCATION>"
      remove_default_node_pool = true
      # In regional cluster (location is region, not zone) 
      # this is a number of nodes per zone 
      initial_node_count = 1
    }

    resource "google_container_node_pool" "preemptible_node_pool" {
      name = "<NODES_POOL_NAME>"
      location = "<LOCATION>"
      cluster = google_container_cluster.gke-cluster.name
      # In regional cluster (location is region, not zone) 
      # this is a number of nodes per zone
      node_count = 1

      node_config {
        preemptible = true
        machine_type = "n1-standard-1"
        oauth_scopes = [
          "storage-ro",
          "logging-write",
          "monitoring"
        ]
      }
    }

    HCL コードを適切に整形できるよう、Terraform には次の便利な整形コマンドが用意されています。

    $ terraform fmt

    上記のコードスニペットは、作成されたリソースが Google によって提供され、リソース自体は google_container_cluster と google_container_node_pool であることを示しています。また、ここではコスト削減のために preemptible を指定しています。 また、デフォルトの代わりに独自のプールを作成しています。

    次の設定を簡単に説明します。

    terraform {
      required_version = "~> 0.12"
      backend "gcs" {
        Bucket = "<BUCKET_NAME>"
        Prefix = "terraform/state"
        credentials = "account.json"
      }
    }

    Terraform はすべての実行結果をステータスファイルに書き込み、このファイルを他の作業に使用します。 このファイルは共有しやすいように、離れた場所に保存することをお勧めします。 一般的にはGoogle バケットに保存されます。

    このバケットを作成しましょう。 プレースホルダー <BUCKET_NAME> の代わりに自分のバケットの名前を使用してください。 バケットを作成する前に、<BUCKET_NAME> が使用できるかどうかを次のコマンドで確認してください。すべての GCP で一意である必要があるためです。

    $ gsutil acl get gs://<BUCKET_NAME>

    期待する応答:

    BucketNotFoundException: 404 gs://<BUCKET_NAME> bucket does not exist

    「Busy」という応答があった場合、別の名前を選択する必要があります。

    AccessDeniedException: 403 <YOUR_ACCOUNT> does not have storage.buckets.get access to <BUCKET_NAME>

    Terraform の推奨どおりにバージョン管理も有効にしましょう。

    $ gsutil mb -l EU gs://<BUCKET_NAME>

    $ gsutil versioning get gs://<BUCKET_NAME>
    gs://<BUCKET_NAME>: Suspended

    $ gsutil versioning set on gs://<BUCKET_NAME>

    $ gsutil versioning get gs://<BUCKET_NAME>
    gs://<BUCKET_NAME>: Enabled

    Terraform はモジュール方式であり、GCP で何かを作成するにはGoogle Provider プラグインを追加する必要があります。 これを行うには、次のコマンドを使用します。

    $ terraform init

    Terraform が GKE クラスターを作成する際の実行計画を見てみましょう。

    $ terraform plan -out dev-cluster.plan

    コマンドの出力には、計画の詳細が含まれています。 特に問題なければ、次のコマンドでこの計画を実行しましょう。

    $ terraform apply dev-cluster.plan

    ちなみに、Terraform によって作成されたリソースを削除するには、このコマンドを <root_repo_dir>/terraform/ ディレクトリから実行してください。

    $ terraform destroy -auto-approve

    しばらくクラスターから離れて先に進みましょう。 ただし、何もかもリポジトリにプッシュされないように、先にいくつかのファイルを例外に追加しましょう。

    $ cat <root_repo_dir>/.gitignore
    .DS_Store
    terraform/.terraform/
    terraform/*.plan
    terraform/*.json

    Helm の使用

    前回の記事では、Kubernetes のマニフェストを yaml ファイルとして <root_repo_dir>/k8s/ ディレクトリに保存し、それを「kubectl apply」コマンドを使用してクラスターに送信しました。 

    今回は別の手法を試してみましょう。最近バージョン 3にアップデートされた Kubernetes のパッケージマネージャーである Helm を使用します。 バージョン 2 には Kubernetes 側のセキュリティの問題があったため、バージョン 3 以降を使用してください(詳細については、Running Helm in production: Security best practices を参照してください)。 まず、Kubernetes のマニフェストを k8s/ ディレクトリからチャートとして知られる Helm パッケージにまとめます。 Kubernetes にインストールされている Helm チャートはリリースと呼ばれます。 最小構成では、チャートは次のような複数のファイルで構成されます。

    $ mkdir <root_repo_dir>/helm; cd <root_repo_dir>/helm
    $ tree <root_repo_dir>/helm/
    helm/
    ├── Chart.yaml
    ├── templates
    │   ├── deployment.yaml
    │   ├── _helpers.tpl
    │   └── service.yaml
    └── values.yaml

    これらのファイルの目的は、公式サイトで詳細に説明されています。 独自チャートを作成するためのベストプラクティスは、Helm ドキュメントの The Chart Best Practices Guide に記載されています。 

    次にファイルの内容を示します。

    $ cat Chart.yaml
    apiVersion: v2
    name: iris-rest
    version: 0.1.0
    appVersion: 1.0.3
    description: Helm for ObjectScript-REST-Docker-template application
    sources:
    - https://github.com/intersystems-community/objectscript-rest-docker-template
    - https://github.com/intersystems-community/gke-terraform-circleci-objectscript-rest-docker-template
    $ cat templates/deployment.yaml
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: {{ template "iris-rest.name" . }}
      labels:
        app: {{ template "iris-rest.name" . }}
        chart: {{ template "iris-rest.chart" . }}
        release: {{ .Release.Name }}
        heritage: {{ .Release.Service }}
    spec:
      replicas: {{ .Values.replicaCount }}
      strategy:
        {{- .Values.strategy | nindent 4 }}
      selector:
        matchLabels:
          app: {{ template "iris-rest.name" . }}
          release: {{ .Release.Name }}
      template:
        metadata:
          labels:
            app: {{ template "iris-rest.name" . }}
            release: {{ .Release.Name }}
        spec:
          containers:
          - image: {{ .Values.image.repository }}:{{ .Values.image.tag }}
            name: {{ template "iris-rest.name" . }}
            ports:
            - containerPort: {{ .Values.webPort.value }}
              name: {{ .Values.webPort.name }}
    $ cat templates/service.yaml
    {{- if .Values.service.enabled }}
    apiVersion: v1
    kind: Service
    metadata:
      name: {{ .Values.service.name }}
      labels:
        app: {{ template "iris-rest.name" . }}
        chart: {{ template "iris-rest.chart" . }}
        release: {{ .Release.Name }}
        heritage: {{ .Release.Service }}
    spec:
      selector:
        app: {{ template "iris-rest.name" . }}
        release: {{ .Release.Name }}
      ports:
      {{- range $key, $value := .Values.service.ports }}
        - name: {{ $key }}
    {{ toYaml $value | indent 6 }}
      {{- end }}
      type: {{ .Values.service.type }}
      {{- if ne .Values.service.loadBalancerIP "" }}
      loadBalancerIP: {{ .Values.service.loadBalancerIP }}
      {{- end }}
    {{- end }}
    $ cat templates/_helpers.tpl
    {{/* vim: set filetype=mustache: */}}
    {{/*
    Expand the name of the chart.
    */}}

    {{- define "iris-rest.name" -}}
    {{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
    {{- end -}}

    {{/*
    Create chart name and version as used by the chart label.
    */}}
    {{- define "iris-rest.chart" -}}
    {{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}}
    {{- end -}}

    $ cat values.yaml
    namespaceOverride: iris-rest

    replicaCount: 1

    strategy: |
      type: Recreate

    image:
      repository: eu.gcr.io/iris-rest
      tag: v1

    webPort:
      name: web
      value: 52773

    service:
      enabled: true
      name: iris-rest
      type: LoadBalancer
      loadBalancerIP: ""
      ports:
        web:
          port: 52773
          targetPort: 52773
          protocol: TCP

    Helm チャートを作成するには、Helm クライアント kubectl コマンドラインユーティリティをインストールします。

    $ helm version
    version.BuildInfo{Version:"v3.0.1", GitCommit:"7c22ef9ce89e0ebeb7125ba2ebf7d421f3e82ffa", GitTreeState:"clean", GoVersion:"go1.13.4"}

    iris というネームスペースを作成します。 デプロイ中にこれが作成されていれば良かったのですが、現時点ではその動作は実装されていません

    まず、Terraform によって作成されたクラスターの資格情報を kube-config に追加します。

    $ gcloud container clusters get-credentials <CLUSTER_NAME> --zone <LOCATION> --project <PROJECT_ID>
    $ kubectl create ns iris

    Helm が Kubernetes で以下を作成することを(実際にデプロイを開始せずに)確認します。

    $ cd <root_repo_dir>/helm
    $ helm upgrade iris-rest \
      --install \
      . \
      --namespace iris \
      --debug \
      --dry-run

    ここでは、出力(Kubernetes のマニフェスト)をスペースを確保するために省略しています。 特に問題がなければ、デプロイしましょう。

    $ helm upgrade iris-rest --install . --namespace iris
    $ helm list -n iris --all
    Iris-rest  iris  1  2019-12-14 15:24:19.292227564  +0200  EET  deployed    iris-rest-0.1.0  1.0.3

    Helm がアプリケーションをデプロイしたことはわかりますが、Docker イメージ eu.gcr.io/iris-rest:v1 をまだ作成していないため、Kubernetes がそのイメージをプルすることはできません(ImagePullBackOff)。

    $ kubectl -n iris get po
    NAME                                           READY  STATUS                       RESTARTS  AGE
    iris-rest-59b748c577-6cnrt 0/1         ImagePullBackOff  0                    10m

    とりあえず、今はここで終わっておきましょう。

    $ helm delete iris-rest -n iris

    CircleCI 側

    Terraform と Helm クライアントを試しましたので、それらを CircleCI 側のデプロイプロセスで使用できるようにしましょう。

    $ cat <root_repo_dir>/.circleci/config.yml
    version: 2.1

    orbs:
      gcp-gcr: circleci/gcp-gcr@0.6.1

    jobs:
      terraform:
        docker:
        # Terraform image version should be the same as when
        # you run terraform before from the local machine
          - image: hashicorp/terraform:0.12.17
        steps:
          - checkout
          - run:
              name: Create Service Account key file from environment variable
              working_directory: terraform
              command: echo ${TF_SERVICE_ACCOUNT_KEY} > account.json
          - run:
              name: Show Terraform version
              command: terraform version
          - run:
              name: Download required Terraform plugins
              working_directory: terraform
              command: terraform init
          - run:
              name: Validate Terraform configuration
              working_directory: terraform
              command: terraform validate
          - run:
              name: Create Terraform plan
              working_directory: terraform
              command: terraform plan -out /tmp/tf.plan
          - run:
              name: Run Terraform plan
              working_directory: terraform
              command: terraform apply /tmp/tf.plan
      k8s_deploy:
        docker:
          - image: kiwigrid/gcloud-kubectl-helm:3.0.1-272.0.0-218
        steps:
          - checkout
          - run:
              name: Authorize gcloud on GKE
              working_directory: helm
              command: |
                echo ${GCLOUD_SERVICE_KEY} > gcloud-service-key.json
                gcloud auth activate-service-account --key-file=gcloud-service-key.json
                gcloud container clusters get-credentials ${GKE_CLUSTER_NAME} --zone ${GOOGLE_COMPUTE_ZONE} --project ${GOOGLE_PROJECT_ID}
          - run:
              name: Wait a little until k8s worker nodes up
              command: sleep 30 # It’s a place for improvement
          - run:
              name: Create IRIS namespace if it doesn't exist
              command: kubectl get ns iris || kubectl create ns iris
          - run:
              name: Run Helm release deployment
              working_directory: helm
              command: |
                helm upgrade iris-rest \
                  --install \
                  . \
                  --namespace iris \
                  --wait \
                  --timeout 300s \
                  --atomic \
                  --set image.repository=eu.gcr.io/${GOOGLE_PROJECT_ID}/iris-rest \
                  --set image.tag=${CIRCLE_SHA1}
          - run:
              name: Check Helm release status
              command: helm list --all-namespaces --all
          - run:
              name: Check Kubernetes resources status
              command: |
                kubectl -n iris get pods
                echo
                kubectl -n iris get services
    workflows:
      main:
        jobs:
          - terraform
          - gcp-gcr/build-and-push-image:
              dockerfile: Dockerfile
              gcloud-service-key: GCLOUD_SERVICE_KEY
              google-compute-zone: GOOGLE_COMPUTE_ZONE
              google-project-id: GOOGLE_PROJECT_ID
              registry-url: eu.gcr.io
              image: iris-rest
              path: .
              tag: ${CIRCLE_SHA1}
          - k8s_deploy:
              requires:
                - terraform
                - gcp-gcr/build-and-push-image

    CircleCI 側のプロジェクトに次のようないくつかの環境変数 を追加する必要があります。

    GCLOUD_SERVICE_KEY は CircleCI のサービスアカウントキーであり、TF_SERVICE_ACCOUNT_KEY は Terraform のサービスアカウントキーです。 サービスアカウントキーが account.json ファイル全体の内容であることを思い出してください。

    次に、変更をリポジトリにプッシュしましょう。

    $ cd <root_repo_dir>
    $ git add .circleci/ helm/ terraform/ .gitignore
    $ git commit -m "Add Terraform and Helm"
    $ git push

    CircleCI UI ダッシュボードには、次のようにすべてが正常であることが示されているはずです。

    Terraform は冪等性のあるツールであり、GKE クラスターが存在する場合、「terraform」ジョブは何も実行しません。 クラスターが存在しない場合は、Kubernetes をデプロイする前に作成されます。
    最後に、IRIS の可用性を確認しましょう。

    $ gcloud container clusters get-credentials <CLUSTER_NAME> --zone <LOCATION> --project <PROJECT_ID>

    $ kubectl -n iris get svc
    NAME        TYPE                     CLUSTER-IP     EXTERNAL-IP   PORT(S)                     AGE
    Iris-rest    LoadBalancer  10.23.249.42    34.76.130.11    52773:31603/TCP   53s

    $ curl -XPOST -H "Content-Type: application/json" -u _system:SYS 34.76.130.11:52773/person/ -d '{"Name":"John Dou"}'

    $ curl -XGET -u _system:SYS 34.76.130.11:52773/person/all
    [{"Name":"John Dou"},]

    まとめ

    Terraform と Helm は標準の DevOps ツールであり、IRIS のデプロイと緊密に統合する必要があります。

    これらはある程度の学習を必要としますが、何度か実践した後は大幅に時間と労力を節約できるようになります。

    0
    0 838
    記事 Toshihiko Minamoto · 8月 11, 2020 44m read

    Google Cloud Platform(GCP)は、IaaS(サービスとしてのインフラストラクチャ)向けの機能性豊かな環境をクラウドとして提供しています。最新の InterSystems IRIS データプラットフォームなど、InterSystems の全製品に完全に対応していますが、 あらゆるプラットフォームやデプロイメントモデルと同様に、パフォーマンス、可用性、運用、管理手順などの環境に関わるすべての側面が正しく機能するように注意を払う必要があります。 この記事では、こういった各分野の詳細について説明しています。

    以下の概要と詳細は Google が提供しているものであり、こちらから参照できます。

    概要

    GCP リソース

    GCP は、コンピュータやハードドライブといった一連の物理アセットと、仮想マシン(VM)といった仮想リソースから構成されており、世界中の Google データセンターに保管されています。 それぞれのデータセンターの場所は 1 つのグローバルリージョンにあります。 そして、それぞれのリージョンはゾーンのコレクションであり、これらのコレクションはリージョン内で互いに分離されています。 各ゾーンには、文字識別子とリージョン名を合わせた名前が付けられています。

    このようなリソースの分散には、障害発生に備えて冗長性を得たり、リソースをクライアントに近い場所に配置することでレイテンシを軽減できたりなど、さまざまなメリットがあります。 また、このような分散によって、リソースをどのように合わせて使用できるかに関するルールも導入することができます。

    GCP リソースへのアクセス

    クラウドコンピューティングでは、物理的なハードウェアとソフトウェアがサービスとなります。 これらは基盤リソースへのアクセスを提供するサービスです。 InterSystems IRIS ベースのアプリケーションを GCP で開発する場合、必要としているインフラストラクチャを得られるようにこれらのサービスを組み合わせ、コードを追加することで、構成しようとしているシナリオを実現することができます。 利用可能なサービスの詳細は、こちらを参照してください。

    プロジェクト

    割り当てて使用する GCP は、プロジェクトに属するものである必要があります。 プロジェクトは、設定、権限、およびアプリケーションを説明するその他のメタデータで構成されます。 単一のプロジェクト内のリソースは、リージョンとゾーンのルールに従って、内部ネットワークを介した通信などによって簡単に連携することができます。 各プロジェクトに含まれるリソースは、プロジェクトの境界で分離されたままであるため、外部ネットワーク接続を介してしか相互接続することはできません。

    サービスとの対話

    GCP でサービスとリソースを操作するには、基本的に 3 つの方法があります。

    コンソール

    Google Cloud Platform Console は、Web ベースのグラフィカルユーザーインターフェースを提供しており、ユーザーは、それを使用して GCP のプロジェクトとリソースを管理することができます。 GCP Console を使用する場合、新規プロジェクトを作成するか既存のプロジェクトを選択すると、作成するリソースをプロジェクトの文脈で使用できます。 複数のプロジェクトを作成できるため、ユーザーに意味のある方法で、プロジェクトを使用して分類することができます。 たとえば、リソースにアクセスできるユーザーを特定のチームメンバーに限定する場合は新しいプロジェクトを開始し、すべてのチームメンバーは引き続き別のプロジェクトのリソースにアクセスすることができます。

    コマンドラインインターフェース

    ターミナルウィンドウで作業する場合、Google Cloud SDK の gcloud コマンドラインツールを使用して、必要なコマンドにアクセスすることができます。 gcloud ツールでは、開発ワークフローと GCP リソースの両方の管理を行えます。 gcloud のリファレンスについては、こちらをご覧ください。

    GCP には、Cloud Shell という、ブラウザで使用する GCP 向けのインタラクティブシェル環境も用意されています。 Cloud Shell には、GCP Console からアクセスできます。 以下に、Cloud Shell の特徴を示します。

  • 一時的な Compute Engine 仮想マシンインスタンス
  • Web ブラウザからインスタンスへのコマンドラインアクセス
  • ビルトインのコードエディタ
  • 5 GB の永続ディスクストレージ
  • プレインストールされた Google Cloud SDK およびその他のツール
  • Java、Go、Python、Node.js、PHP、Ruby、および .NET 言語のサポート
  • Web プレビュー機能
  • GCP Console プロジェクトとリソースへのアクセスの組み込み認証
  • クライアントライブラリ

    Cloud SDK には、リソースを簡単に作成して管理できるクライアントライブラリが含まれています。 GCP クライアントライブラリは、主に 2 つの目的で API を公開しています。

    • アプリ API はサービスへのアクセスを提供します。 アプリ API は、Node.js や Python といったサポート対象の言語用に最適化されています。 ライブラリは、サービスのメタファーを軸に設計されているため、ユーザーはサービスをより自然に操作し、より少ないボイラープレートコードを記述することができます。 ライブラリは、認証と承認のヘルパーも提供しています。 詳細は、こちらを参照してください。
    • 管理 API は、リソース管理機能を提供します。 たとえば、独自の自動化ツールを構築する場合、管理 API を使用できます。

    また、Google API クライアントライブラリを使用して、Google マップ、Google ドライブ、および YouTube といった製品用の API にアクセスすることもできます。 GCP クライアントライブラリの詳細は、こちらを参照してください。

    InterSystems IRIS サンプルアーキテクチャ

    この記事の一部として、アプリケーション固有のデプロイメントの出発点として、GCP 向けの InterSystems IRIS サンプルデプロイメントを提供しています。 デプロイメントの可能性には多数ありますが、これらのサンプルをガイドラインとしてご利用ください。 このリファレンスアーキテクチャでは、規模の小さなデプロイメントから非常にスケーラブルなワークロードまで、コンピューティングとデータの両方の要件に対応する非常に堅牢なデプロイメントオプションを紹介しています。

    このドキュメントでは、高可用性と災害復旧に関するオプション、そしてその他の推奨システム運用について説明しています。 組織の標準的なやり方やセキュリティポリシーに応じて変更してください。

    InterSystems では、ユーザー固有のアプリケーションについて、GCP ベースの InterSystems IRIS デプロイメントに関するご相談またはご質問をお受けしています。


    サンプルリファレンスアーキテクチャ

    以下のサンプルアーキテクチャでは、キャパシティと機能を高めるさまざまな構成を提供します。 小規模な開発、本番、大規模な本番、およびシャードクラスタを使用した本番を検討してください。開発作業用の規模の小さな構成から、ゾーン全体に適した高可用性とマルチリージョン災害復旧を備えた非常にスケーラブルなソリューションへと構成が増大していく様子を確認できます。 さらに、SQL クエリの超並列処理によるハイブリッドワークロードに対する InterSystems IRIS データプラットフォームの新しいシャーディング機能を使用するサンプルアーキテクチャも用意されています。

     

    小規模開発の構成

    この例では、最小構成を使用して、開発者数最大10 人と 100 GB のデータに対応できる小規模な開発環境を示します。 仮想マシンのインスタンスの種類を変更し、永続ディスクのストレージを適切に増加するだけで、より多くの開発者とデータ量を簡単にサポートできるようになります。

    これは、開発作業をサポートし、InterSystems IRIS の機能性と、必要であれば Docker コンテナの構築とオーケストレーションに慣れる上で十分な構成です。 小規模な構成では通常、データベースミラーリングによる高可用性を使用することはありませんが、高可用性が必要な場合にはいつでも追加することができます。

    小規模な構成のサンプル図

    以下の図 2.1.1-a のサンプル図は、図 2.1.1-b のリソーステーブルを示します。 含まれているゲートウェイは単なる例であり、組織の標準的なネットワークに合わせて調整できます。

    以下の GCP VPC プロジェクト内のリソースは、最低限の小規模構成としてプロビジョニングされています。 GCP リソースは必要に応じて追加または削除することができます。

    小規模構成の GCP リソース

    以下のテーブルは、小規模構成 GCP リソースのサンプルを示しています。

    VPC への不要なアクセスを防止するには、適切なネットワークセキュリティとファイアウォールのルールを検討する必要があります。 Google は、これに取り掛かるためのネットワークセキュリティに関するベストプラクティスをこちらで提供しています。

    注意: VM インスタンスが GCP サービスにアクセスするには、パブリック IP アドレスが必要です。 このやり方では懸念を生じてしまう可能性がありますが、Google は、ファイアウォールのルールを使用して、これらの VM インスタンスへの受信トラフィックを制限することを推奨しています。

    セキュリティポリシーで VM インスタンスが完全に内部化されていることが要求されている場合、ネットワークと対応するルートに手動で NAT プロキシを設定し、内部インスタンスがインターネットにアクセスできるようにする必要があります。 SSH を使用して、完全に内部化された VM インスタンスを直接接続することはできないことに注意しておくことが重要です。 そのような内部マシンに接続するには、外部 IP アドレスを持つ踏み台インスタンスをセットアップしてから、それを通過するトンネルをセットアップする必要があります。 外部に面する VPC へのエントリポイントを提供する踏み台ホストをプロビジョニングすることができます。

    踏み台ホストの詳細は、こちらを参照してください。

    本番構成

    この例では、InterSystems IRIS データベースミラーリング機能を組み込んで高可用性と災害復旧をサポートする本番構成の例として、より大規模な構成を示しています。

    この構成には、自動フェイルオーバーを行うための、region-1 内で 2 つのゾーンに分割された InterSystems IRIS データベースサービスの同期ミラーペアと、GCP リージョン全体がオフラインになるという稀なイベントにおいて災害復旧を行うための、region-2 の 3 番目の DR 非同期ミラーメンバーが含まれます。

    InterSystems Arbiter と ICM サーバーは、回復力を得るために、別の 3 番目のゾーンにデプロイされています。 サンプルアーキテクチャには、Web 対応アプリケーションをサポートするためのオプションとして、一連の負荷分散された Web サーバーも含まれています。 InterSystems Gateway を備えたこれらの Web サーバーは、必要に応じて個別に拡張することができます。

    本番構成のサンプル図

    以下の図 2.2.1-a のサンプル図は、図 2.2.1-b のリソーステーブルを示します。 含まれているゲートウェイは単なる例であり、組織の標準的なネットワークに合わせて調整できます。

    以下の GCP VPC プロジェクト内のリソースは、シャードクラスタをサポートするための最低推奨事項として推奨されています。 GCP リソースは必要に応じて追加または削除することができます。

    本番構成の GCP リソース

    以下のテーブルは、本番構成 GCP リソースのサンプルを示しています。

    大規模な本番の構成

    この例では、InterSystems IRIS の機能を拡張することで、InterSystems Cache プロトコル(ECP)を使用したアプリケーションを導入してユーザーの大規模な水平スケーリングも提供できる、大規模な構成を示しています。 この例にはさらに高レベルの高可用性が含まれており、データベースインスタントのフェイルオーバーが発生した場合でも ECP クライアントがセッション情報を保持できるようになっています。 複数のリージョンにデプロイされた ECP ベースのアプリケーションサーバーとデータベースメンバーには、複数の GCP ゾーンが使用されています。 この構成では、毎秒数千万件のデータベースアクセスと数テラバイトのデータをサポートできます。

    大規模な本番構成のサンプル図

    図 2.3.1-a のサンプル図は、図 2.3.1-b のリソーステーブルを示します。 含まれているゲートウェイは単なる例であり、組織の標準的なネットワークに合わせて調整できます。

    この構成には、フェイルオーバーミラーペア、4 つ以上の ECP クライアント(アプリケーションサーバー)、およびアプリケーションサーバー当たり 1 つ以上の Web サーバーが含まれます。 フェイルオーバーデータベースミラーのペアは、同一のリージョン内で 2 つの異なる GCP ゾーンで分割されており、3 番目のゾーンに個別にデプロイされた InterSystems Arbiter と ICM サーバーでフォールトドメインの保護を確立し、さらなる回復力を備えています。

    災害復旧は、前の例と同様に、2 番目の GCP リージョンとゾーンに拡張されています。 複数の DR リージョンは、必要に応じて複数の DR 非同期ミラーメンバーターゲットと使用できます。

    以下の GCP VPC プロジェクト内のリソースは、大規模な本番デプロイメントをサポートするための最低推奨事項として推奨されています。 GCP リソースは必要に応じて追加または削除することができます。

    大規模な本番構成の GCP リソース

    以下のテーブルは、大規模な本番構成 GCP リソースのサンプルを示しています。

    InterSystems IRIS シャードクラスタを使用した本番構成

    この例では、SQL を使用したハイブリッドワークロード向けに水平スケーリングされた構成を示しています。InterSystems IRIS の新しいシャードクラスタ機能が含まれており、複数のシステムをまたぐ SQL クエリとテーブルの大規模な水平スケーリングを提供しています。 InterSystems IRIS のシャードクラスタとその機能の詳細については、この記事の後半で説明します。

    InterSystems IRIS シャードクラスタを使用した本番構成

    図 2.4.1-a のサンプル図は、図 2.4.1-b のリソーステーブルを示します。 含まれているゲートウェイは単なる例であり、組織の標準的なネットワークに合わせて調整できます。

    この構成には、データノードとして 4 つのミラーペアが含まれます。 それぞれのフェイルオーバーデータベースミラーのペアは、同一のリージョン内で 2 つの異なる GCP ゾーンで分割されており、3 番目のゾーンに個別にデプロイされた InterSystems Arbiter と ICM サーバーでフォールトドメインの保護を確立し、さらなる回復力を備えています。

    この構成では、クラスタ内のあらゆるデータノードからすべてのデータベースアクセスメソッドを利用することができます。 大規模な SQL テーブルのデータは、すべてのノード間で物理的に分割されているため、クエリ処理とデータ量の大規模な並列化が実現されます。 これらすべての機能を組み合わせることで、単一の InterSystems IRIS データプラットフォーム内で、新しいデータの取り込みと同時に大規模な分析 SQL クエリを実行するなど、あらゆる複雑なハイブリッドワークロードをサポートできるようになります。

    上の図と、下のテーブルの「リソースタイプ」列にある「Compute [Engine]」とは、このドキュメントのセクション 3.1 で説明されているとおり、GCP(仮想)サーバーインスタンスを表す GCP 用語です。 この記事の後半で説明するクラスタアーキテクチャでの「計算ノード」の使用を表したり暗示するものではありません。

    以下の GCP VPC プロジェクト内のリソースは、シャードクラスタをサポートするための最低推奨事項として推奨されています。 GCP リソースは必要に応じて追加または削除することができます。

    シャードクラスタを使用した本番構成の GCP リソース

    以下のテーブルは、シャードクラスタ構成 GCP リソースのサンプルを示しています。


    クラウドの基礎概念

    Google Cloud Platform(GCP)は、IaaS(サービスとしてのインフラストラクチャ)向けの機能性豊かなクラウド環境を提供しています。新しい InterSystems IRIS データプラットフォームによるコンテナベースの開発運用など、InterSystems の全製品に完全に対応していますが、 あらゆるプラットフォームやデプロイメントモデルと同様に、パフォーマンス、可用性、システム運用、高可用性、災害復旧、セキュリティ制御、およびその他の管理手順などの環境に関わるすべての側面が正しく機能するように注意を払う必要があります。 このドキュメントでは、Compute、Storage、および Networking という、すべてのクラウドデプロイメントの 3 つの主要コンポーネントについて説明します。

    Compute Engine(仮想マシン)

    GCP 内には、仮想 CPU とメモリの仕様と関連するストレージオプションを数多く備えた Compute Engine リソースで利用できるオプションがいくつかあります。 GCP 内で注意する項目の 1 つとして、あるマシンタイプの vCPU 数は、1 つの vCPU に相当することです。これはハイパーバイザー層にある物理ホスト上の 1 つのハイパースレッドということになります。

    このドキュメントでは、n1-standard* と n1-highmem* インスタンスタイプが使用されており、ほとんどの GCP デプロイメントリージョンで最も広く利用できるインスタンスです。 ただし、大量のデータをメモリにキャッシュする非常に大型の作業データセットにおいては、n1-ultramem* インスタンスタイプを使用することが優れたオプションと言えます。 特記されている場合を除き、インスタンス可用性ポリシーなどのデフォルトのインスタンス設定やその他の高度な機能が使用されています。 さまざまなマシンタイプの詳細は、こちらを参照してください。

    ディスクストレージ

    InterSystems 製品に最も直接関係しているストレージタイプは、永続ディスクタイプですが、データ可用性の制限を理解して対応できる場合には、ローカルストレージを使用して高度なパフォーマンスを実現することができます。 Cloud Storage(バケット)といったその他のオプションもいくつかありますが、それらは InterSystems IRIS データプラットフォームの運用をサポートするというよりも、個別のアプリケーションの要件に特化したオプションです。

    ほかのほとんどのクラウドプロバイダと同様に、GCP でも、各 Compute Engine に関連付けられる永続ストレージの容量に制限があります。 これらの制限には、各ディスクの最大サイズ、各 Compute Engine に接続される永続ディスクの数量、永続ディスク当たりの IOPS 量と各 Compute Engine インスタンスの総合的な IOPS 限界などがあります。 さらに、ディスク容量 1 GB あたりの IOPS 制限もあるため、希望する IOPS レートを得るには、より多くのディスク容量をプロビジョニングする必要があります。

    これらの制限は、時間の経過とともに変化する可能性があるため、適宜、Google に確認する必要があります。

    ディスクボリュームの永続ストレージタイプには、標準永続ディスクと SSD 永続ディスクの 2 種類があります。 予測可能な低レイテンシ IOPS とより高いスループットを必要とする本番ワークロードには、SSD 永続ディスクがより適しています。 標準永続ディスクは、非本番環境の開発とテストやアーカイブタイプのワークロード向けのより経済的なオプションです。

    さまざまなディスクタイプと制限の詳細については、こちらを参照してください。

    VPC ネットワーキング

    InterSystems IRIS データプラットフォームの多様なコンポーネントのサポートとともに、適切なネットワークセキュリティコントロール、各種ゲートウェイ、ルーティング、内部 IP アドレス割り当て、ネットワークインターフェース分離、およびアクセス制御を提供するには、仮想プライベートクラウド(VPC)ネットワークの使用が強く推奨されます。 VPC の例は、このドキュメントに含まれる例で詳しく説明します。

    VPC ネットワーキングとファイアウォールの詳細については、こちらを参照してください。


    仮想プライベートクラウド(VPC)の概要

    GCP VPC はほかのクラウドプロバイダとは少し異なり、簡素化とより優れた柔軟性を実現しています。 概念の比較は、こちらを参照してください。

    GCP プロジェクト内では、プロジェクトごとに複数の VPC を使用でき(現在、プロジェクトあたり最大 5 個)、自動モードとカスタムモードの 2 つのオプションで VPC ネットワークを作成できます。

    それぞれの詳細は、こちらを参照してください。

    ほとんどの大規模なクラウドデプロイメントでは、複数の VPC をプロビジョニングして、さまざまなゲートウェイタイプをアプリケーション中心の VPC から分離し、インバウンドとアウトバウンドの通信に VPC ピアリングを活用しています。 会社で使用されているサブネットと組織のファイアウォールルールの詳細について、ネットワーク管理者に相談することを強くお勧めします。 VPC ピアリングについては、このドキュメントで説明していません。

    このドキュメントに含まれる例では、3 つのサブネットを持つ単一の VPC を使用して、予測可能なレイテンシと帯域幅、およびさまざまな InterSystems IRIS コンポーネントのセキュリティ分離を得るために、コンポーネントのネットワーク分離を行っています。

    ネットワークゲートウェイとサブネットの定義

    このドキュメントでは、インターネットとセキュア VPN 接続をサポートするために、2 つのゲートウェイを使用した例を示しています。 アプリケーションに適度なセキュリティを提供するために、各侵入アクセスには、適切なファイアウォールとルーティングのルールが必要です。 ルートの使用方法に関する詳細については、こちらを参照してください。

    InterSystems IRIS データプラットフォーム専用のアーキテクチャ例では、3 つのサブネットが使用されています。 これらの個別のネットワークサブネットとネットワークインターフェースを使用することで、セキュリティコントロールと帯域幅の保護に柔軟性を持たせ、上記の 3 つの主要コンポーネントをそれぞれ監視することができます。 さまざまな使用事例に関する詳細は、こちらを参照してください。

    複数のネットワークインターフェースを備えた仮想マシンインスタンスの作成に関する詳細は、こちらを参照してください。

    これらの例には、次のサブネットが含まれます。

  • インバウンド接続ユーザーとクエリ用のユーザースペースネットワーク
  • シャードノード間通信用のシャードネットワーク
  • 各データノードの同期レプリケーションと自動フェイルオーバーを使用して高可用性を実現するミラーリングネットワーク
  • 注意: フェイルオーバー同期データベースミラーリングは、単一の GCP リージョン内で相互接続のレイテンシが低い複数のゾーンでのみ推奨されます。 リージョン間のレイテンシは非常に高いことが通例であるため、特に更新が頻繁に行われるデプロイメントにおいては、良好なユーザーエクスペリエンスを提供することができません。

    内部ロードバランサー

    ほとんどの IaaS クラウドプロバイダーには、自動データベースフェイルオーバー設計で一般的に使用される仮想 IP(VIP)アドレスに対応できる能力が欠けています。 これを解決するために、ミラー対応かつ自動化する VIP 機能に依存しないように、最も一般的に使用されるいくつかの接続方法(特に ECP クライアントや Web ゲートウェイ)が InterSystems IRIS 内で強化されています。

    xDBC、ダイレクト TCP/IP ソケット、またはその他のダイレクトコネクトプロトコルなどの接続方法には VIP のようなアドレスを使用する必要があります。 そういったインバウンドプロトコルをサポートするために、InterSystems のデータベースミラーリング技術では、<span class="Characteritalic" style="font-style:italic">mirror_status.cxw</span> というヘルスチェックステータスページを使って、それらの接続方法の自動フェイルオーバーを GCP 内で提供できるようになっています。VIP のようなロードバランサーの機能性を達成するためにロードバランサーと対話し、アクティブなプライマリメンバーにのみトラフィックをダイレクトすることで、完全かつ堅牢な高可用性設計を GCP 内で作り上げています。

    ロードバランサーを使用して VIP のような機能を提供する方法の詳細については、こちらを参照してください。

    VPC トポロジの例

    以下の図 4.3-a では、すべてのコンポーネントを組み合わせて、次の特性を持つ VPC のレイアウトを示しています。

  • 高可用性を得るために、リージョン内の複数のゾーンを活用する
  • 災害復旧を可能にするために、2 つのリージョンを提供する
  • ネットワーク分離を実施するために、複数のサブネットを使用する
  • インターネットと VPN の両方の接続を得るために、個別のゲートウェイを含める
  • ミラーメンバーが IP フェイルオーバーを行えるように、クラウドロードバランサーを使用する

  • 永続ストレージの概要

    はじめに説明したとおり、GCP 永続ディスク、特に SSD 永続ディスクタイプの使用をお勧めしています。 読み取りと書き込みの IOPS レートがより高く、トランザクションと分析用のデータベースワークロードに必要なレイテンシが低いため、SSD 永続ディスクが推奨されています。 特定の状況で ローカル SSD を使用できることもありますが、ローカル SSD のパフォーマンス向上には、可用性、耐久性、および柔軟性のトレードオフが伴うことに注意してください。

    ローカル SSD データ永続性の詳細については、こちらを参照してください。ローカル SSD データが保持される場合とされない場合を理解することができます。

    LVM ストライピング

    ほかのクラウドプロバイダと同様に、GCP においても、IOPS、容量、および仮想マシンインスタンス当たりのデバイス数に関してストレージに対する制限を課しています。 GCP ドキュメンテーションで現在の制限を確認してください。こちらから参照できます。

    これらの制限により、データベースインスタンスの単一ディスクデバイスの IOPS 以上に最大化するために、LVM ストライピングが必要となります。 提供されている仮想マシンインスタンスの例では、以下のディスクレイアウトが推奨されています。 SSD 永続ディスクに関連するパフォーマンス制限については、こちらを参照してください。

    注意: 現在の仮想マシンインスタンス当たりの最大永続ディスク数は 16 個ですが、GCP では「ベータ版」として 128 個への増加を記載しています。喜ばしい拡張です。

    LVM ストライピングのメリットによって、ランダムな IO ワークロードをより多くのデバイスに分散し、ディスクキューを継承することができます。 以下は、データベースボリュームグループに対して、Linux で LVM ストライピングを使用する方法の例を示しています。 この例では、物理エクステント(PE)サイズが 4 MB の LVM PE ストライプで 4 つのディスクを使用します。 または、必要に応じて、より大きな PE サイズを使用することもできます。

    • 手順 1: 必要に応じて、標準または SSD 永続ディスクを作成します
    • 手順 2: “lsblk -do NAME,SCHED” を使用して、各ディスクデバイスの IO スケジューラが NOOP であることを確認します
    • 手順 3: “lsblk -do KNAME,TYPE,SIZE,MODEL” を使用して、ディスクデバイスを識別します
    • 手順 4: 新しいディスクデバイスでボリュームグループを作成します
      • vgcreate s 4M  
      • : vgcreate -s 4M vg_iris_db /dev/sd[h-k]
    • 手順 4: 論理ボリュームを作成します
      • lvcreate n -L -i -I 4MB
      • : lvcreate -n lv_irisdb01 -L 1000G -i 4 -I 4M vg_iris_db
    • 手順 5: ファイルシステムを作成します
      • mkfs.xfs K
      • : mkfs.xfs -K /dev/vg_iris_db/lv_irisdb01
    • 手順 6: ファイルシステムをマウントします
      • 次のマウントエントリで /etc/fstab を編集します
        • /dev/mapper/vg_iris_db-lv_irisdb01    /vol-iris/db    xfs  defaults 0 0
        • mount /vol-iris/db

    上記の表を使用すると、各 InterSystems IRIS サーバーに、SYS 用ディスク 2 個、DB 用ディスク 4 個、プライマリジャーナル用ディスク 2 個、および代替ジャーナル用ディスク 2 個を備えた以下の構成が作られます。

    成長に関しては、LVM では中断することなく、必要に応じてデバイスと論理ボリュームを拡張できます。 LVM ボリュームの継続的な管理と拡張のベストプラクティスについては、Linux のドキュメンテーションを参照してください。

    注意: データベースと書き込みイメージジャーナルファイルの両方で非同期 IO を有効にすることを強くお勧めします。 Linux での有効化に関する詳細については、次のコミュニティ記事を参照してください: https://community.intersystems.com/post/lvm-pe-striping-maximize-hyper-converged-storage-throughput

    プロビジョニング

    InterSystem IRIS に InterSystems Cloud Manager(ICM)という新しいツールがあります。 ICM は、多くのタスクを実行し、InterSystems IRIS データプラットフォームをプロビジョニングするためのオプションを多数提供しています。 ICM は Docker イメージとして提供され、堅牢な GCP クラウドベースのソリューションをプロビジョニングするために必要なすべての機能を含んでいます。

    ICM は現在、以下のプラットフォームでのプロビジョニングをサポートしています。

    • Google Cloud Platform(GCP)
    • GovCloud を含む Amazon Web Services(AWS / GovCloud)
    • 政府を含む Microsoft Azure Resource Manager(ARM / MAG)
    • VMware vSphere(ESXi)

    ICM と Docker は、デスクトップ/ノートブックワークステーションから実行することも、小規模な専用の集中型「プロビジョニング」サーバーと集中型レポジトリを持つことも可能です。  

    アプリケーションのライフサイクルにおける ICM の役割は、 定義 -> プロビジョン -> デプロイ -> 管理です。

    ICM のインストールと Docker との使用に関する詳細は、こちらを参照してください。

    注意: クラウドデプロイメントでは、ICM を使用する必要はありません。 tar-ball ディストリビューションを使用した従来のインストールとデプロイメントは完全にサポートされており、提供されていますが、 クラウドデプロイメントでのプロビジョニングと管理を簡単化できる ICM の使用をお勧めします。

    コンテナの監視

    ICM には、コンテナベースのデプロイメント向けに Weave Scope を使用した基本的な監視機能が含まれています。 デフォルトではデプロイされないため、defaults ファイルの Monitor フィールドを使用して指定する必要があります。

    ICM を使用した監視、オーケストレーション、およびスケジューリングに関する詳細は、こちらを参照してください。

    Weave Scope の概要とドキュメンテーションは、こちらをご覧ください。


    高可用性

    InterSystems のデータベースミラーリングは、あらゆるクラウド環境で最も高度な可用性を提供します。 直接インスタンスレベルである程度の仮想マシンの回復力を提供するオプションがあります。 GCP で利用できる各種ポリシーに関する詳細は、こちらを参照してください。

    前の方のセクションでは、クラウドロードバランサーがデータベースミラーリングを使用して仮想 IP(VIP のような)機能に自動 IP アドレスフェイルオーバーを提供する方法について説明しました。 クラウドロードバランサーは、前の「内部ロードバランサー」セクションで述べた mirror_status.cxw というヘルスチェックステータスページを使用します。 データベースミラーリングには、自動フェイルオーバー付きの同期ミラーリングと非同期ミラーリングとうい 2 つのモードがありますが、 この例では、同期フェイルオーバーミラーリングについて説明しています。 ミラーリングの詳細については、こちらを参照してください。

    最も基本的なミラーリング構成は、アービター制御構成で一組のフェイルオーバーミラーメンバーを使用する構成です。 アービターは同一リージョン内の 3 番目のゾーンに配置されており、アービターと片方のミラーメンバーに影響を与える可能性のあるゾーンの停止から保護します。

    ネットワーク構成でミラーリングをセットアップする方法はたくさんありますが、 この例では、このドキュメントの「ネットワークゲートウェイとサブネットの定義」セクションで定義したネットワークサブネットを使用します。 IP アドレススキームの例は以下のセクションで提供しています。このセクションでは、ネットワークインターフェースと指定されたサブネットについてのみ示しています。


    災害復旧

    InterSystems のデータベースミラーリングは、高可用性機能を拡張することで、別の GCP 地理リージョンへの災害復旧もサポートし、GCP の全リージョンがオフラインになるという万が一の事態に備え、運営の弾力性をサポートします。 アプリケーションがそのような停止にどのようにして耐えるかは、目標復旧時間(RTO)と目標復旧ポイント(RPO)によって異なります。 これらは、適切な災害復旧計画を作成するために必要な分析の初期フレームを提供するものです。 以下のリンクでは、アプリケーションの災害復旧計画を作成する際に検討すべき項目のガイドが提供されています。 https://cloud.google.com/solutions/designing-a-disaster-recovery-plan および https://cloud.google.com/solutions/disaster-recovery-cookbook

    非同期データベースミラーリング

    InterSystems IRIS データプラットフォームのデータベースミラーリングは、GCP ゾーンとリージョン間のデータレプリケーションを非同期に実行する堅牢な機能を提供しているため、災害復旧計画の RTO と RPO の目標をサポートする上で役立ちます。 非同期ミラーメンバーの詳細については、こちらを参照してください。

    前の高可用性のセクションと同様に、クラウドロードバランサーは、自動 IP アドレスフェイルオーバーを仮想 IP(VIP のような)機能に提供して、前の「 内部ロードバランサー 」セクションで述べたのと同じ mirror_status.cxw ヘルスチェックステータスページを使用してDR 非同期ミラーリングも提供することができます。

    この例では、DR 非同期フェイルオーバーミラーリングは、InterSystems IRIS デプロイメントが稼働しているゾーンやリージョンに関係なく、上流システムとクライアントワークステーションに単一のエニーキャスト IP アドレスを提供する GCP Global Load Balancing サービスの導入とともにカバーされるようになります。

    GCP のメリットの 1 つは、ロードバランサーがソフトウェアによって定義されたグローバルリソースであり、特定のリージョンにバインドされないことです。 このため、そしてインスタンスやデバイスベースのソリューションでないため、リージョン全体で単一のサービスを活用できる特有の機能が可能になります。 単一のエニーキャスト IP を使用した GCP Global Load Balancing の詳細については、こちらを参照してください。

    上の例では、3 つすべての InterSystems IRIS インスタンスは GCP Global Load Balancer に渡され、ゾーンやリージョンに関係なく、プライマリミラーとして動作しているミラーメンバーにのみトラフィックが転送されるようになります。


    シャードクラスタ

    InterSystems IRIS には包括的な機能セットが含まれており、ワークロードの性質とワークロードが直面している特定のパフォーマンスの課題に応じて、単独または組み合わせて適用できます。 機能セットの 1 つであるシャーディングは、データとその関連するキャッシュの両方を複数のサーバーに分割することで、クエリとデータの取り込みを行うための柔軟で安価なパフォーマンスの拡張を行いながら、リソースを非常に効率的に利用することで、インフラストラクチャの価値を最大化することができます。 InterSystems IRIS のシャードクラスタは、広範なアプリケーション、特に以下の 1 つ以上の項目を含むワークロードを使用するアプリケーションに、大きなパフォーマンスのメリットを提供できます。

    • 大量または高速データ取り込み、またはその両方。
    • 比較的大規模なデータセット、大量のデータを返すクエリ、またはその両方。
    • ディスク上の大量のデータをスキャンしたり、重要な計算作業を伴ったりなど、大量のデータ処理を行う複雑なクエリ。

    こういった要因は、それ自体でシャーディングから得られる可能性のある利益に変化をもたらしますが、これらが組み合わさった場合はそのメリットがさらに高まる可能性があります。 たとえば、大量データの迅速な取り込み、大規模なデータセット、および大量のデータを取得して処理する複雑なクエリという 3 つのすべての要因が組み合わさった場合、今日の分析ワークロードの多くでシャーディングを利用する価値が非常に高くなります。

    これらの特性はすべてデータに関係しています。InterSystems IRIS のシャーディングの主な機能は、データボリュームに対して拡張することだからです。 ただし、シャードクラスタには、一部またはすべてのデータ関連の要因が伴うワークロードで、多数のユーザーから非常に高いクエリ量が発生する場合に、ユーザーのボリュームに合わせて拡張する機能も含められます。 シャーディングは、垂直スケーリングと組み合わせることもできます。

    運用の概要

    シャードアーキテクチャの目的は、データとそれに関連するキャッシュを複数のシステム間で分割することにあります。 シャードクラスタは、データノードと呼ばれる複数の InterSystems IRIS インスタンス間で、大量のデータベーステーブルを物理的に水平に(行ごとに)分割します。その一方で、アプリケーションが任意のノードを介してこれらのテーブルに透過的にアクセスし、1 つの論理的な結合としてデータセット全体を捉えられるようにします。 このアーキテクチャには、次の 3 つのメリットがあります。

    • 並列処理: クエリは、データノードで並列に実行され、結果は、アプリケーションが接続されたノードによってマージ、結合され、完全なクエリ結果としてアプリケーションに返されます。多くの場合、実行速度が大幅に改善されます。
    • 分割されたキャッシュ:単一のインスタンスのキャッシュをデータセット全体で使用するのではなく、各ノードにそれが格納するシャーディングされたテーブルのデータ分割専用の独自キャッシュがあります。そのため、キャッシュのオーバーフローやパフォーマンスを低下するディスク読み取りのリスクが大幅に軽減されます。
    • 並列読み込み:データをデータノードに並列に読み込めるため、取り込みワークロードとクエリワークロード間のキャッシュとディスクの競合が緩和され、両者のパフォーマンスが改善されます。

    InterSystems IRIS のシャードクラスタの詳細については、こちらを参照してください。

    シャーディングの要素とインスタンスタイプ

    シャードクラスタは、少なくとも 1 つのデータノードと、特定のパフォーマンスやワークロード要件に必要な場合は、オプションの数の計算ノードで構成されます。 これら 2 つのノードタイプは単純なビルディングブロックで、シンプルで透過的かつ効果的なスケーリングモデルを提供しています。

    データノード

    データノードはデータを格納します。 物理レベルでは、シャーディングされたテーブル [1] のデータはクラスタ内のすべてのデータノードに分散され、シャーディングされていないテーブルのデータは、最初のデータノードのみに物理的に格納されます。 この区別は、ユーザーに透過的です。最初のノードのストレージ消費量はほかのノードに比べてわずかに高いことがあるという唯一の例外がありますが、シャーディングされたテーブルデータは通常、シャーディングされていないテーブルデータをわずかに上回る程度であるめ、この差は無視することができます。

    シャーディングされたテーブルデータは、必要に応じて、通常は新しいデータノードを追加した後で、クラスタ全体で再調整できます。 この調整により、分散するデータが均等になるようにノード間でデータの「バケツ」が移動されます。

    論理レベルでは、シャーディングされていないテーブルデータとシャーディングされたテーブルのすべてのデータの結合はあらゆるノードから可視状態であるため、クライアントは接続しているノードに関係なく、データセット全体を見ることができます。 メタデータとコードも、すべてのデータノードで共有されます。

    シャードクラスタの基本的なアーキテクチャ図は、クラスタ全体で均一に見えるデータノードで構成されています。 クライアントアプリケーションは、任意のノードに接続でき、データがローカルであるかのように処理されます。


    [1] 便宜上、ドキュメントを通して「シャーディングされたテーブルデータ」という用語によって、シャーディングとしてマークされる、シャーディングをサポートするデータモデルの「エクステント」データを表しています。 「シャーディングされていないテーブルデータ」と「シャーディングされていないデータ」は、シャーディング可能なエクステントにあり、そのようにマークされていないデータ、またはシャーディングをまだサポートしていないデータモデルのデータを指します。

    データノード

    低レイテンシが必要となる高度なシナリオでは、潜在的にデータの一定した流入が発生する可能性があるため、クエリを処理するための透過的なキャッシング層を提供するために計算ノードを追加することができます。

    計算ノードはデータをキャッシュします。 各計算ノードは、対応するシャーディングされたテーブルデータをキャッシュするデータノードに関連付けられています。さらに、そのデータに加え、クエリを満たすために必要に応じてシャーディングされていないテーブルデータもキャッシュします。

    計算ノードは物理的にデータを格納せず、クエリ実行をサポートすることを目的としているため、メモリと CPU に重点を置いてストレージを最小限に抑えるなどによって、そのハードウェアプロファイルをニーズに合わせて調整することができます。 取り込みは、ドライバー(xDBC、Spark)で直接、または計算ノードで「ベア」アプリケーションコードが実行されるときにシャーディングマネージャーコードによって暗黙的にデータノードに転送されます。


    シャードクラスタの図説

    シャードクラスタのデプロイにはさまざまな組み合わせがあります。 以下の概要図は、最も一般的なデプロイメントモデルを説明しています。 これらの図には、ネットワークゲートウェイと詳細は含まれておらず、シャードクラスタコンポーネントのみに焦点が当てられています。

    基本的なシャードクラスタ

    以下の図は、単一のリージョンと単一のゾーンにデプロイされた 4 つのデータノードを持つ最も単純なシャードクラスタです。 クライアント接続をシャードクラスタノードに分散するために、GCP Cloud Load Balancer が使用されています。

    この基本モデルでは、単一の仮想マシンとそれに接続された SSD 永続ストレージに GCP が提供するものを超える回復力や高可用性は提供されていません。 インバウンドクライアント接続のネットワークセキュリティ分離と、クライアントトラフィックとシャードクラスタ通信間の帯域幅分離の両方を提供するには、2 つのネットワークインターフェイスアダプターを個別に用意することをお勧めします。

    高可用性を備えた基本的なシャードクラスタ

    以下の図は、単一のリージョンにデプロイされた 4 つのミラーデータノードとゾーン間で分岐した各ノードのミラーを持つ最も単純なシャードクラスタです。 クライアント接続をシャードクラスタノードに分散するために、GCP Cloud Load Balancer が使用されています。

    高可用性は、リージョン内のセカンダリゾーンで同期的に複製されたミラーを維持する InterSystems のデータベースミラーリングを使用して提供されています。

    インバウンドクライアント接続のネットワークセキュリティ分離と、クライアントトラフィック、シャードクラスタ通信、およびノードペア間の同期ミラートラフィック間の帯域幅分離を提供するには、3 つのネットワークインターフェイスアダプターを個別に用意することをお勧めします。

    このデプロイメントモデルでは、このドキュメントの前のセクションで説明したミラーアービターも導入されています。

    個別の計算ノードを持つシャードクラスタ

    以下の図は、大規模なユーザー/クエリ同時実行向けに、個別の計算ノードと 4 つのデータノードを持つシャードクラスタを拡張しています。 Cloud Load Balancer サーバープールには、計算ノードのアドレスのみが含まれます。 更新とデータの取り込みは、以前と同様にデータノードに直接更新され続け、超低レイテンシパフォーマンスを維持し、リアルタイムデータ取り込みによるクエリ/分析ワークロード間のリソースの干渉と輻輳を回避します。

    このモデルでは、計算/クエリと取り込みを個別にスケーリングできるようにリソースの割り当てを微調整することで、計算またはデータをスケーリングするためだけにリソースを不要に無駄にする代わりに、必要なときに「ジャストインタイム」でリソースを最適化し、経済的でありながらも単純なソリューションを維持することができます。

    計算ノードは GCP 自動スケールグループ(自動スケーリング)を非常に簡単に使用できるため、負荷の増減に基づいて、管理されたインスタンスグループへのインスタンスの追加または削除を自動的に実行することができます。 自動スケーリングは、負荷が高まるとインスタンスグループにインスタンスを追加し(アップスケーリング)、インスタンスのニーズが低下するとインスタンスを削除(ダウンスケーリング)します。

    GCP 自動スケーリングの詳細については、こちらを参照してください。

    自動スケーリングを使用すると、クラウドベースのアプリケーションは、トラフィックの増加を適切に処理し、リソースのニーズが低下するとコストを削減するのに役立ちます。 自動スケーリングポリシーを定義するだけで、オートスケーラーは、測定された負荷に基づいて、自動的にスケーリングを実行します。


    バックアップ操作

    バックアップ操作には、いくつかのオプションがあります。 InterSystems IRIS を使用した GCP デプロイメントでは、次の 3 つのオプションを使用できます。

    最初の 2 つのオプションは、以下で説明するとおり、スナップショットを作成する前にデータベースによるディスクへの書き込みを一時停止し、スナップショットに成功したら更新を再開するというスナップショットタイプの手順を使用しています。

    いずれかのスナップショット方式を使用してクリーンなバックアップを作成するには、次のおおまかな手順を実行します。

    • データベースの External Freeze API 呼び出しにより、データベースへの書き込みを一時停止する。
    • OSとデータディスクのスナップショットを作成する。
    • External Thaw API 呼び出しにより、データベースの書き込みを再開する。
    • バックアップファシリティはバックアップ場所にアーカイブする。

    External Freeze/Thaw API に関する詳細は、こちらを参照してください。

    注意: このドキュメントにはバックアップのサンプルスクリプトは含まれていませんが、InterSystems 開発者コミュニティに掲載される例を定期的に確認してください。 www.community.intersystems.com

    3 つ目のオプションは、InterSystems Online のバックアップです。 これは、非常にシンプルな使用事例とインターフェイスを備えたより小規模なデプロイメント向けのエントリーレベルのアプローチです。 ただし、データベースのサイズが大きくなるにつれ、スナップショットテクノロジーを使った外部バックアップがベストプラクティスとして推奨されます。外部ファイルのバックアップ、より高速な復元時間、エンタープライズ全体のデータビューと管理ツールなどのメリットがあります。

    クリーンで一貫したバックアップを確保するために、整合性チェックなどの追加手順を定期的に追加することができます。

    どのオプションを使用するかという決定ポイントは、組織の運用要件とポリシーによって異なります。 さまざまなオプションをさらに詳しく検討するには、InterSystems にご相談ください。

    GCP 永続ディスクスナップショットのバックアップ

    バックアップ操作は、GCP gcloud コマンドライン API と InterSystems External Freeze/Thaw API 機能を使用して実行できます。 これにより、本来の 24 時間 365 日の運用弾力性とクリーンな定期バックアップの保証が可能になります。 GCP 永続ディスクスナップショットの管理と作成および自動化の詳細については、こちらを参照してください。

    論理ボリュームマネージャー(LVM)のスナップショット

    別の方法として、市場に出回っている多くのサードパーティ製バックアップツールを使用する場合は、VM そのものにバックアップエージェントを展開し、論理ボリュームマネージャ(LVM)のスナップショットと組み合わせてファイルレベルのバックアップを活用することができます。

    このモデルには、Windows または Linux ベースの VM をファイルレベルで復元できるというメリットがあります。 このソリューションで注意すべき点は、GCP やほとんどの IaaS クラウドプロバイダはテープメディアを提供しないため、すべてのバックアップリポジトリは、短期アーカイブ用のディスクベースであり、長期保管(LTR)には BLOB またはバケットタイプの低コストストレージを活用できるということです。 このモデルを使用する場合は、ディスクベースのバックアップリポジトリを最も効率的に使用できるように、重複除去テクノロジーをサポートするバックアップ製品を使用することを強くお勧めします。

    こういったクラウド対応のバックアップ製品には、Commvault、EMC Networker、HPE Data Protector、Veritas Netbackup などさまざまな製品があります。

    注意: InterSystems では、これらの製品の比較検証や推奨は行っておりません。 個々のお客様の責任の下、バックアップ管理ソフトウェアをお選びください。

    Online Backup

    小さなデプロイメントでは、組み込みの Online Backup ファシリティもオプションとして考えられます。 InterSystems のデータベースオンラインバックアップユーティリティは、データベース内のすべてのブロックをキャプチャしてデータベースファイルにデータをバックアップし、出力をシーケンシャルファイルに書き込みます。 この、InterSystems 独自のバックアップメカニズムは、本番システムのユーザーにダウンタイムを引き起こさないように設計されています。 Online Backup の詳細については、こちらを参照してください。

    GCP では、オンラインバックアップが完了した後、バックアップ出力ファイルとシステムで使用中のほかのすべてのファイルを、その仮想マシンインスタンスの外部にあるほかのストレージの場所にコピーする必要があります。 これには、バックアップ/オブジェクトストレージが適しています。

    GCP Storatge バケットを使用するには、2 つのオプションがあります。

    • gcloud スクリプト API を直接使用して、新しく作成したオンラインバックアップ(とほかの非データベース)ファイルをコピーして操作する。詳細は、こちらを参照してください。
    • Cloud Storage バケットはオブジェクトストレージですが、ストレージバケットをファイルシステムとしてマウントし、永続ディスクと同様に使用する。

    Cloud Storage FUSE を使って Cloud Storage バケットをマウントする詳細については、こちらを参照してください。

    0
    0 1662
    記事 Mihoko Iijima · 7月 6, 2020 12m read

    この連載記事では、InterSystemsの技術とGitLabを使用したソフトウェア開発に向けていくつかの可能性のあるアプローチをを紹介し、議論したいと思います。 今回は以下のようなトピックを取り上げます。 

    • Git 101 
    • Gitフロー(開発プロセス) 
    • GitLabのインストール 
    • GitLabワークフロー 
    • 継続的デリバリー 
    • GitLabのインストールと構成 
    • GitLab CI/CD 
    • コンテナを使用する理由 
    • コンテナインフラストラクチャ 
    • コンテナを使用したCD 
    • ICMを使用したCD 

    この記事では、InterSystems Cloud Managerを使用して継続的デリバリーを構築ドします。 ICMは、InterSystems IRISをベースとしたアプリケーション用のクラウドプロビジョニングおよびデプロイメントソリューションです。これにより、 必要なデプロイ構成を定義することができ、ICMが自動的にプロビジョニングします。 詳細については、First Look: ICM をご覧ください。

     ワークフロー

    継続的デリバリーの構成では、次のようになります。

    0
    0 521