2022年12月19日

Continuous Delivery

Harnes UIサービスにCDNを実装した方法

このブログでは、CDNとは何か、そしてHarnessがCDNを環境に実装した方法について説明します。

banner_image.png

複雑な機能と複数の共同作業者により、Webアプリケーションの構築と管理はますます困難になっています。デプロイの複雑さが増し、テクノロジーがあらゆる業界で普及するにつれて、この効率性は組織のビジネス目標にとって重要になります。Harnessは、ユーザーインターフェイス(UI)サービスにコンテンツ配信ネットワーク(CDN)を実装することで、この複雑さを管理しています。CDNによって、プラットフォームの速度と安定性が保証されるのです。


このブログでは、CDNとは何か、そしてHarnessがCDNを環境に実装した方法について説明します。また、私たちが遭遇したいくつかの課題と、それらにどのように対処したかについて説明します。

 

「CDN」とは?

では、CDNとは何でしょうか?CDNは、世界中に分散された一連のサーバーです。Gartnerによると次のようになります:

コンテンツ配信ネットワーク(CDN)は、分散コンピューティングインフラストラクチャーの一種であり、デバイス(サーバーまたはアプライアンス)は、インターネットなどのマルチホップパケットルーティングネットワーク、またはプライベートWAN上の複数のポイントオブプレゼンスに存在します。CDNを使用して、リッチメディアのダウンロードまたはストリームを配信し、ソフトウェアパッケージと更新を配信し、グローバルロードバランシング、Secure Sockets Layerアクセラレーション、およびWAN最適化技術による動的アプリケーションアクセラレーションなどのサービスを提供できます。

CDN サーバーが必要な理由

使用例はシンプルです。

キャッシングと読み込みの高速化:リソースはCDNにキャッシュされ、地理的にユーザーに最も近いサーバーから配信されるため、リソースの読み込みが高速になります。

アプリケーションサーバーの負荷の軽減:リソースはキャッシュされ、CDNから提供されます。これは、ダウンストリームアプリサーバーがこれらの静的リソースに対する要求を受信しないことを意味し、負荷が軽減されます。

CDNを使わないHarness UIサービスの場合、バンドルされている全てのファイル(index.html、およびJavascript、スタイル、画像などのその他の静的ファイルを含む)はアプリサーバーから取得します。しかしCDNでは、index.htmlのみがアプリサーバーから取得されます。残りの全ての静的ファイルは、CDNサーバー(ここではstatic.harness.ioから取得します。

639ce9f1a35ee303ddd195c2_CDNdiagram.png

CDNの実装方法は?

まず、要件と制約をリスト化します。Harnessでは、次のようなものでした。

  • CDNは、NextGen UIサービスの複数のリソースファイル(js、css、画像、動画)を提供する必要がある。
  • 公開されている本番環境だけでなく、テスト/QA環境など、複数の環境で実行できる必要がある。
  • CDNをオンまたはオフにするための簡単なスイッチが必要(問題が発生した場合)。

この情報を文書化して実装を開始したところ、いくつかの課題に直面しました。
 

CDNの課題

課題1:実行時とビルド時のPublic Pathの比較

異なる環境と展開タイプ(SaaSとオンプレミス)に同じビルドを使いました。ビルドのバンドルと作成にはwebpackを使いました

Public Pathは、アプリケーション内の全てのアセットのベースパスを設定するのに役立ちます。簡単に言えばPublic Pathは、アセットの提供元となるホストまたはディレクトリを定義します。

以前は、ビルド時のpublicPathを使っていました。Webpackには、実行時のオンザフライpublicPathを定義するサポートが組み込まれているため、コードを少し変更し、CDNサーバーのホスト名をpublicPathとして追加しました。


 


 

image_Harness_9.png

ここでstatic.harness.ioはCDNホスト名です。

課題 2:GCSへのアップロード手順とgsutilの比較

当社のCDNはGoogle Cloud Platformでホストしています。静的アセットはGoogle Cloud Storage(GCS)バケットに保存しています。Harnessのデプロイには、Harness CDを使用しています。

Harnessには、基本的な「クイックスタート」の便利な手順である"Uploading Artifacts to GCS"のサポートが組み込まれています。

image_Harness_1.png

私たちのユースケースには、次のことも含まれていました。

  • ファイルを圧縮(g-zip)
  • アップロードするファイルにカスタム権限を追加する

上記ユースケースでバンドルされた最新のファイルが、確実にGCSにアップロードされるために、“Upload Artifacts to GCS”ステップを使う代わりに、“Run”ステップを使用してカスタムスクリプトを追加します。そのスクリプトでは、gsutilを使います

image_Harness_2.png

gsutilはGoogleが作成したPythonアプリケーションで、コマンドラインからCloud Storageにアクセスできます。これを使用して、バンドルされたアセットを圧縮(g-zip)し、権限を設定しました。参照用のスニペットを次に示します。

image_Harness_17.png

課題3:Web Workers

コード編集機能にはMonaco Editorを使っています。Harnessの使用経験がある方は、Visual-vs-YAMLビューを見たことがあるでしょう。YAMLビューにはMonacoEditorが必要です。

image_Harness_5.png

Monaco Editorはウェブワーカーを使って、メインのJSスレッドとは別のスレッドで実行します。

ただし、ウェブブラウザーはクロスドメインのウェブワーカーを許可しません。

image_Harness_14.png

この制限は、ウェブサイトのアドレスが「app.harness.io」で始まる場合、MonacoEditor言語用のJavascriptファイルが「static.harness.io」(CDN)からロードしようとすると、ウェブブラウザーがそれらをブロックすることを意味します。オートコンプリートなどの一部のMonacoEditor機能は動作しません。

 

試行錯誤

これを修正するために、monaco-editor-webpack-pluginworker-loaderを試しました

このmonaco-editor-webpack-pluginは、webpackと同様のpublicPath提供し、どのホストからワーカースクリプトをロードするかを指示します。

image_Harness_10.png

しかし…私たちにはうまくいきませんでした。webpackのランタイムpublicPathに「勝つ」ことはできませんでした。

次に、worker-loaderを試してみました。ここも同じ話でした。また、webpackのランタイムpublicPathにも「勝て」ませんでした。

image_Harness_11.png

monaco-editor-webpack-pluginのバージョンを更新することも考えましたが、新しいバージョンはMonacoEditorのバージョンと強く結びついていることが分かりました。monaco-editorとmonaco-editor-webpack-pluginの両方のバージョンを更新する必要があったのです。そして、それは長時間かかる作業になります。

image_Harness_4.png

customLanguagesのサポートにより簡単に感じられましたが、このやり方は採用しませんでした。

image_Harness_13.png

次に、CDNを「app.harness.io」の背後に配置するように構成することを考えました。つまり、赤いパスではなく、緑のパスを使用します。(下図)

image_Harness_8.png

これは、「customer.harness.io」などのバニティーURL(訳注:短縮URLなど読みやすくカスタマイズされたURL)では機能しません。なぜなら「app.harness.io」の背後にCDNを構成したため、ブラウザーが引き続きワーカー呼び出しをブロックするためです。

ソリューション

私たちは2つのステップで解決策を考え出しました。

まずはworker-loader、つまりBlobとしてロードされるworkerです。

image_Harness_3.png

しかし、worker-loaderはwebpack v5をサポートしており、非推奨/アーカイブされているため、使いませんでした。

workerファイルを個別にビルドし、base-pathを手動で変更しようとするとどうなるでしょうか?これには、カスタマイズしたwebpack構成が必要でした。このwebpackの新しい「entry」ですが、monacoファイルのlazy-load (遅延読み込み)するという意味ではありません。

image_Harness_6.png

しかし、私たちはこのソリューションをさらに発展させ、ひねりを加えました。workerを構築しましたが、別のwebpack構成を使ったのです。

image_Harness_15.png

コンポーネント内からビルドされたファイルを参照するときは、current window.locationを使う必要がありました。worker-loaderを取り除き、workerに推奨されるwebpack v5の方法を使いました(getWorker()new Workerを使用)。

image_Harness_7.png

workerのバンドルファイルにハッシュがないなどの 隠れた問題があるため、ファイル名に手動でバージョン「2」を追加しました(ファイル名はeditorWorker2およびyamlWorker2です)。workerファイルの更新が必要な場合は、ハッシュとして機能するバージョン2を手動で変更する必要があります。私たちはこの制限を認識しており、これを自動化するのは複雑になる可能性があるため、それを受け入れました

CDN と Harness の次は?

複雑な課題を解決し、何千人ものユーザーのアップタイムを確保することは、簡単ではありません。CDNの実装により、Harnessはこの分散ネットワークモデルを通じて速度を向上させ、アップタイムを確保することができました。

CDN実装のパート2にご注目ください。ここでは、マイクロフロントエンドの子アプリにCDNを実装する方法を共有します。


この記事はHarness社のウェブサイトで公開されているものをDigital Stacksが日本語に訳したものです。無断複製を禁じます。原文はこちらです。

Harnessに関するお問い合わせはお気軽にお寄せください。

お問い合わせ