銀の光と碧い空

クラウドなインフラとC#なアプリ開発の狭間にいるエンジニアの日々

OpenFeature .NET SDKを試してみた(2) 名前付きクライアント

前回の記事のにコメントをいただいたので名前付きクライアントを試してみました。

tech.tanaka733.net

プロバイダーは一度に1つ登録できるのですが、名前を付けることで複数登録してクライアント取得時に分けることができます。前回の記事では前半だけ書いていたので不正確になっていました。

openfeature.dev

github.com

openfeature.dev

名前付きクライアントを利用するサンプルコードとしては引用したドキュメントの通りなのですが、実際に試すためにflagdのJSONファイルを変えて複数起動し、別々のプロバイダーとして登録しました。

以下をdemo1.jsonとして保存し、

{
  "flags": {
    "myStringFlag": {
      "state": "ENABLED",
      "variants": {
        "key1": "val1",
        "key2": "val2",
        "key3": "val3"
      },
      "defaultVariant": "key1"
    }
  }
}

defaultVariantだけ変えたこれをdemo2.jsonとして保存し、

{
  "flags": {
    "myStringFlag": {
      "state": "ENABLED",
      "variants": {
        "key1": "val1",
        "key2": "val2",
        "key3": "val3"
      },
      "defaultVariant": "key2"
    }
  }
}

コンテナを分けて起動します。

docker run --rm -it --name flagd1 -p 8013:8013 -v ${PWD}:/etc/flagd ghcr.io/open-feature/flagd:latest start --uri file:./etc/flagd/demo1.json
docker run --rm -it --name flagd2 -p 8014:8013 -v ${PWD}:/etc/flagd ghcr.io/open-feature/flagd:latest start --uri file:./etc/flagd/demo2.json

そして、C#コードでは別のProviderとして作成します。

var flagdProvider1 = new FlagdProvider(new Uri("http://localhost:8013"));
var flagdProvider2 = new FlagdProvider(new Uri("http://localhost:8014"));

そしていくつかのパターンで試してみました。

//名前を指定しないとデフォルトのプロバイダーが使われる
var client = Api.Instance.GetClient();
var val = await client.GetStringValue("myStringFlag", "null");
Console.WriteLine(val); //val1

//名前を指定すると指定した名前で登録されたプロバイダーが使われる
client = Api.Instance.GetClient("provider2");
val = await client.GetStringValue("myStringFlag", "null");
Console.WriteLine(val); //val2

//指定した名前が存在しないとデフォルトのプロバイダーが使われる
client = Api.Instance.GetClient("provider3");
val = await client.GetStringValue("myStringFlag", "null");
Console.WriteLine(val); //val1

//同じ名前で別のプロバイダーを登録すると上書きされる
Api.Instance.SetProvider("provider2", flagdProvider1);
client = Api.Instance.GetClient("provider2");
val = await client.GetStringValue("myStringFlag", "null");
Console.WriteLine(val); //val1

GetClient メソッドの引数に指定した名前で登録されたプロバイダーがあれば、それが使われます。指定した名前がない場合はデフォルトのプロバイダーが登録されます。.NET SDKには説明が見つからなかったのですが、OpenFeatureが定めている仕様にはこの動作が書かれており、期待される通りの挙動です。

openfeature.dev

前回はbool型の値、今回はstring型の値を使ったので、次回はOpenFeatureではどんな型とその値を取得するどんな評価APIが用意されているかを確認します。

Radiusを知る(10) v0.29のリリースとロードマップ

Radiusに関してしばらく記事を書いていなかったので最近のRadiusについてまとめようと思います。

v0.29のリリース

最新版は1/6にリリースされたv0.29です。

github.com

ハイライトとしては2点あり、1つはエッジバージョン(edge version)の公開です。最新の機能を取り込んだバージョンをエッジバージョンとして利用できるようになりました。以下のドキュメントから手順を確認できます。

edge.docs.radapp.io

2つ目はdevcontainer機能としてrad CLIが利用できるようになりました。devcontainerやCodespaces にrad CLIとその依存関係を自動的にインストールできるようになります。

github.com

またリリースノートには記載なく、どの時点で更新されたかわかりませんが、Visual Studio Codeで利用するBicepの拡張機能ですが、Radiusを使う場合には本家のBicep拡張機能をアンインストールし、Radius Bicepをインストールするように案内されています。

edge.docs.radapp.io

ロードマップ

ロードマップが公開され、ブログ記事が出ています。

blog.radapp.io

github.com

ロードマップのポイントとしては、

  • 現在の目標と計画を表している
  • 実装予定時期などは公開しない
  • リリースのたびに評価しなおす
  • 現時点ではプロジェクト管理者の優先順位が反映されているが、パートナーが増えるにつれて見直される可能性がある

といったところです。

現時点でのロードマップで個人的に興味があるのは、レシピについては、AzureだけでなくAWSなどさまざまなリソースを対象にすることRadiusで展開する前にすでにプロビジョニングされているリソースに接続できるようにすることRadiusのアプリケーショングラフに関するダッシュボードサーバーレスコンテナランタイムへの対応、といったあたりです。

OpenFeature .NET SDKを試してみた(1)

OpenFeatureとは

OpenFeatureは2023年12月CNCFのincubationプロジェクトに昇格したプロジェクトです。以下の記事の冒頭を翻訳して引用する形でOpenFeatureを紹介します。

www.cncf.io

OpenFeature は、さまざまな機能フラグ管理ツールと互換性のある、機能フラグ設定用のベンダーに依存しないコミュニティ主導の API を提供するオープン仕様です。機能フラグは、チームがソース コードを変更せずに、製品またはサービスの特定の機能またはコード パスの動作を有効化、無効化、または変更できるようにするソフトウェア開発の手法です。

OpenFeature による機能フラグの標準化により、共通インターフェイスの背後でツールとベンダーが統合され、コード レベルでのベンダー ロックインを回避し、コミュニティ全体で共有できる拡張機能や統合を構築するためのフレームワークが提供されます。

もし機能フラグが1つしかなかったり、複数あっても担当するチームとソフトウェアが独立していれば、データベースなり環境変数に値を保存した値を取り出すコードとif文、そして関数呼び出しだけで済むはずです。が、なぜわざわざ標準化が必要なのかというのはOpenFeatureのブログに書かれています。

openfeature.dev

このOpenFeatureを .NET アプリの中で利用できるSDKがOpenFeature .NET SDK です。何回かに分けてこのSDKを試してみたいと思います。

github.com

OpenFeature .NET SDKを試す

flagdを動かす

サンプルコードを動かそうとするといきなり問題にあたります。InMemoryProviderというクラスが見つからないからです。Issueが立っていて実は未実装です。

github.com

Providerというのは後述しますがフラグの値を評価するレイヤーで、フラグの値を管理しているツールとSDK間の問い合わせを抽象化します。InMemoryProviderはその名の通りメモリ上にフラグの値を保管するものなのでお試しするには使いやすいですが、運用する際には別のものに置き換えられるはずです。間もなく実装されることを期待して、今回は別のProviderを使うことにします。

OpenFeature .NET SDKで利用可能なプロバイダーの一覧はこちらにありますが、今回はDockerですぐに起動できるflagdを使ってみました。

openfeature.dev

github.com

flagdはDockerで動くので、以下の手順に従ってフラグの値のJSONファイルを準備し起動します。

flagd.dev

PowerShellで起動する場合はこうです。

docker run --rm -it --name flagd -p 8013:8013 -v ${PWD}:/etc/flagd ghcr.io/open-feature/flagd:latest start --uri file:./etc/flagd/demo.flagd.json

.NET アプリ側でコードを記述する

これでSDKが利用できます。SDK本体を利用するにはOpenFeatureというNuGetライブラリを、さらにflagdをプロバイダーとして利用するためにOpenFeature.Contrib.Providers.Flagdというライブラリを参照します。

<PackageReference Include="OpenFeature" Version="1.3.1" />
<PackageReference Include="OpenFeature.Contrib.Providers.Flagd" Version="0.1.7" />

サンプルコードは以下のようになります。おそらく実際にはアプリケーションの中で一度プロバイダーの作成と登録を行い、必要な場所でクライアントの作成と機能フラグの値の取得を行うことになります。

using OpenFeature;
using OpenFeature.Contrib.Providers.Flagd;

//プロバイダーを作成する(今回はflagdの接続先のみをオプションで指定)
var flagdProvider = new FlagdProvider(new Uri("http://localhost:8013"));
//プロバイダーを登録する
Api.Instance.SetProvider(flagdProvider);
//クライアントを作成する
var client = Api.Instance.GetClient();
//機能フラグの値を取得する。第2引数はデフォルト値。
var val = await client.GetBooleanValue("show-welcome-banner", false);
Console.WriteLine(val.ToString());

プロバイダーとは

OpenFeatureのプロバイダーはフラグ評価の責務を持っており、OpenFeature SDKのAPI呼び出しに応じてフラグ管理システムに問い合わせて値を返します。今回の場合はコンテナで動いているflagdに問い合わせてその結果を返しているため、上の例ではTrueが表示されます。

openfeature.dev

OpenFeatureではプロバイダーは1つしか登録できずあと勝ちになります。また、プロバイダーを登録していない場合やフラグの名前が存在しない場合は、第2引数で指定したデフォルト値が返されます。 また、プロバイダーを開発することもできます。まだOpenFeatureに対応していないフラグ管理システムのSDKのブリッジとしてや、自分たちで管理しているデータベースやファイルシステムへの問い合わせをProviderとして抽象化することができます。