.NET 用 Microsoft Azure HDInsight Containers 管理クライアント ライブラリ

Microsoft Azure HDInsgiht Containers(HDInsight On AKS) では、AKS に基づく hdinsight クラスターのデプロイが簡略化されます。

このライブラリでは、Microsoft Azure HDInsgiht Containers リソースの管理がサポートされています。

このライブラリは 、新しい Azure SDK ガイドラインに従い、多くのコア機能を提供します。

- Support MSAL.NET, Azure.Identity is out of box for supporting MSAL.NET.
- Support [OpenTelemetry](https://opentelemetry.io/) for distributed tracing.
- HTTP pipeline with custom policies.
- Better error-handling.
- Support uniform telemetry across all languages.

作業の開始

パッケージをインストールします (プライベート プレビューの状態になったので、次の方法は動作しません。プライベート nuget フィードから nuget をインストールするには、 に Askhilo@microsoft.com メールを送信してください)

NuGet を使用して .NET 用の AKS 管理ライブラリに Azure HDInsight をインストールします。

dotnet add package Azure.ResourceManager.HDInsight.Containers --prerelease

前提条件

クライアントを認証する

認証されたクライアントを作成し、Microsoft Azure リソースとの対話を開始するには、 こちらのクイックスタート ガイドを参照してください。

主要な概念

Microsoft Azure SDK for .NETの主な概念については、こちらを参照してください

ドキュメント

ドキュメントは、このパッケージの使用方法を学習するのに役立ちます。

この例の名前空間:

using System;
using System.Linq;
using Azure.ResourceManager;
using Azure.Identity;
using Azure.ResourceManager.Resources;
using Azure.Core;
using Azure.ResourceManager.HDInsight.Containers;
using Azure.ResourceManager.HDInsight.Containers.Models;

ARM クライアントを初めて作成するときは、作業するサブスクリプションを選択します。 メソッドを GetDefaultSubscription/GetDefaultSubscriptionAsync 使用して、ユーザー用に構成された既定のサブスクリプションを返すことができます。

ArmClient armClient = new ArmClient(new DefaultAzureCredential());
SubscriptionResource subscription = armClient.GetDefaultSubscription();

クラスター プールの作成

// define the prerequisites information: subscription, resource group and location where you want to create the resource
string subscriptionResourceId = "/subscriptions/{subscription id}"; // your subscription resource id like /subscriptions/{subscription id}
string resourceGroupName = "{your resource group name}"; // your resource group name
AzureLocation location = AzureLocation.EastUS; // your location

SubscriptionResource subscription = armClient.GetSubscriptionResource(new ResourceIdentifier(resourceId: subscriptionResourceId));
ResourceGroupResource resourceGroupResource = subscription.GetResourceGroup(resourceGroupName);
HDInsightClusterPoolCollection clusterPoolCollection = resourceGroupResource.GetHDInsightClusterPools();

// create the cluster pool
string clusterPoolName = "{your cluster pool name}";
string clusterPoolVmSize = "Standard_E4s_v3"; // the vmsize

// get the available cluster pool version
var availableClusterPoolVersion = subscription.GetAvailableClusterPoolVersionsByLocation(location).FirstOrDefault();

// initialize the ClusterPoolData instance
HDInsightClusterPoolData clusterPoolData = new HDInsightClusterPoolData(location)
{
    ComputeProfile = new ClusterPoolComputeProfile(clusterPoolVmSize),
    ClusterPoolVersion = availableClusterPoolVersion?.ClusterPoolVersionValue,
};

var clusterPoolResult = clusterPoolCollection.CreateOrUpdate(Azure.WaitUntil.Completed, clusterPoolName, clusterPoolData);

単純な Trino クラスターを作成する

// define the prerequisites information: subscription, resource group and location where you want to create the resource
string subscriptionResourceId = "/subscriptions/{subscription id}"; // your subscription resource id like /subscriptions/{subscription id}
string resourceGroupName = "{your resource group}"; // your resource group name
AzureLocation location = AzureLocation.EastUS; // your location

SubscriptionResource subscription = armClient.GetSubscriptionResource(new ResourceIdentifier(resourceId: subscriptionResourceId));
ResourceGroupResource resourceGroupResource = subscription.GetResourceGroup(resourceGroupName);
HDInsightClusterPoolCollection clusterPoolCollection = resourceGroupResource.GetHDInsightClusterPools();

// create the cluster
string clusterPoolName = "{your cluster pool name}";
string clusterName = "{your cluster name}";
string clusterType = "Trino"; // your cluster type

// get the available cluster version
var availableClusterVersion = subscription.GetAvailableClusterVersionsByLocation(location).Where(version => version.ClusterType.Equals(clusterType, StringComparison.OrdinalIgnoreCase)).FirstOrDefault();

// set the identity profile
string msiResourceId = "{your user msi resource id}";
string msiClientId = "{your user msi client id}";
string msiObjectId = "{your user msi object id}";
var identityProfile = new HDInsightIdentityProfile(msiResourceId: new ResourceIdentifier(msiResourceId), msiClientId: msiClientId, msiObjectId: msiObjectId);

// set the authorization profile
var userId = "{your aad user id}";
var authorizationProfile = new AuthorizationProfile();
authorizationProfile.UserIds.Add(userId);

// set the cluster node profile
string vmSize = "Standard_D8s_v3"; // your vms ize
int workerCount = 5;
ClusterComputeNodeProfile nodeProfile = new ClusterComputeNodeProfile(nodeProfileType: "worker", vmSize: vmSize, count: workerCount);

// initialize the ClusterData instance
var clusterData = new HDInsightClusterData(location)
{
    ClusterType = clusterType,
    ClusterProfile = new ClusterProfile(clusterVersion: availableClusterVersion?.ClusterVersion, ossVersion: availableClusterVersion?.OssVersion, identityProfile: identityProfile, authorizationProfile: authorizationProfile)
    {
        TrinoProfile = new TrinoProfile(),  // here is related with cluster type
    },
};
clusterData.ComputeNodes.Add(nodeProfile);

var clusterCollection = clusterPoolCollection.Get(clusterPoolName).Value.GetHDInsightClusters();

var clusterResult = clusterCollection.CreateOrUpdate(Azure.WaitUntil.Completed, clusterName, clusterData);

単純な Spark クラスターを作成する

// define the prerequisites information: subscription, resource group and location where you want to create the resource
string subscriptionResourceId = "/subscriptions/{subscription id}"; // your subscription resource id like /subscriptions/{subscription id}
string resourceGroupName = "{your resource group}"; // your resource group name
AzureLocation location = AzureLocation.EastUS; // your location

SubscriptionResource subscription = armClient.GetSubscriptionResource(new ResourceIdentifier(resourceId: subscriptionResourceId));
ResourceGroupResource resourceGroupResource = subscription.GetResourceGroup(resourceGroupName);
HDInsightClusterPoolCollection clusterPoolCollection = resourceGroupResource.GetHDInsightClusterPools();

// create the cluster
string clusterPoolName = "{your cluster pool name}";
string clusterName = "{your cluster name}";
string clusterType = "Spark"; // your cluster type here is Spark

// get the available cluster version
var availableClusterVersion = subscription.GetAvailableClusterVersionsByLocation(location).Where(version => version.ClusterType.Equals(clusterType, StringComparison.OrdinalIgnoreCase)).FirstOrDefault();

// set the identity profile
string msiResourceId = "{your user msi resource id}";
string msiClientId = "{your user msi client id}";
string msiObjectId = "{your user msi object id}";
var identityProfile = new HDInsightIdentityProfile(msiResourceId: new ResourceIdentifier(msiResourceId), msiClientId: msiClientId, msiObjectId: msiObjectId);

// set the authorization profile
var userId = "{your aad user id}";
var authorizationProfile = new AuthorizationProfile();
authorizationProfile.UserIds.Add(userId);

// set the cluster node profile
string vmSize = "Standard_D8s_v3"; // your vms ize
int workerCount = 5;
ClusterComputeNodeProfile nodeProfile = new ClusterComputeNodeProfile(nodeProfileType: "worker", vmSize: vmSize, count: workerCount);

// initialize the ClusterData instance
var clusterData = new HDInsightClusterData(location)
{
    ClusterType = clusterType,
    ClusterProfile = new ClusterProfile(clusterVersion: availableClusterVersion?.ClusterVersion, ossVersion: availableClusterVersion?.OssVersion, identityProfile: identityProfile, authorizationProfile: authorizationProfile)
    {
        SparkProfile = new SparkProfile(),  // here is related with cluster type
    },
};
clusterData.ComputeNodes.Add(nodeProfile);

var clusterCollection = clusterPoolCollection.Get(clusterPoolName).Value.GetHDInsightClusters();

var clusterResult = clusterCollection.CreateOrUpdate(Azure.WaitUntil.Completed, clusterName, clusterData);
// define the prerequisites information: subscription, resource group and location where you want to create the resource
string subscriptionResourceId = "/subscriptions/{subscription id}"; // your subscription resource id like /subscriptions/{subscription id}
string resourceGroupName = "{your resource group}"; // your resource group name
AzureLocation location = AzureLocation.EastUS; // your location

SubscriptionResource subscription = armClient.GetSubscriptionResource(new ResourceIdentifier(resourceId: subscriptionResourceId));
ResourceGroupResource resourceGroupResource = subscription.GetResourceGroup(resourceGroupName);
HDInsightClusterPoolCollection clusterPoolCollection = resourceGroupResource.GetHDInsightClusterPools();

// create the cluster
string clusterPoolName = "{your cluster pool name}";
string clusterName = "{your cluster name}";
string clusterType = "Flink"; // cluster type

// get the available cluster version
var availableClusterVersion = subscription.GetAvailableClusterVersionsByLocation(location).Where(version => version.ClusterType.Equals(clusterType, StringComparison.OrdinalIgnoreCase)).LastOrDefault();

// set the identity profile
string msiResourceId = "{your user msi resource id}";
string msiClientId = "{your user msi client id}";
string msiObjectId = "{your user msi object id}";
var identityProfile = new HDInsightIdentityProfile(msiResourceId: new ResourceIdentifier(msiResourceId), msiClientId: msiClientId, msiObjectId: msiObjectId);

// set the authorization profile
var userId = "{your aad user id}";
var authorizationProfile = new AuthorizationProfile();
authorizationProfile.UserIds.Add(userId);

// set the cluster node profile
string vmSize = "Standard_D8s_v3"; // your vm size
int workerCount = 5;
ClusterComputeNodeProfile nodeProfile = new ClusterComputeNodeProfile(nodeProfileType: "worker", vmSize: vmSize, count: workerCount);
// initialize the ClusterData instance
var clusterData = new HDInsightClusterData(location)
{
    ClusterType = clusterType,
    ClusterProfile = new ClusterProfile(clusterVersion: availableClusterVersion?.ClusterVersion, ossVersion: availableClusterVersion?.OssVersion, identityProfile: identityProfile, authorizationProfile: authorizationProfile),
};
clusterData.ComputeNodes.Add(nodeProfile);

// set flink profile
string storageUri = "abfs://{your storage account container name}@{yoru storage account}.dfs.core.windows.net"; // your adlsgen2 storage uri
FlinkStorageProfile flinkStorageProfile = new FlinkStorageProfile(storageUri);

ComputeResourceRequirement jobManager = new ComputeResourceRequirement((float)1.0, 2048);
ComputeResourceRequirement taskManager = new ComputeResourceRequirement((float)1.0, 2048);

clusterData.ClusterProfile.FlinkProfile = new FlinkProfile(storage: flinkStorageProfile, jobManager: jobManager, taskManager: taskManager);

var clusterCollection = clusterPoolCollection.Get(clusterPoolName).Value.GetHDInsightClusters();

var clusterResult = clusterCollection.CreateOrUpdate(Azure.WaitUntil.Completed, clusterName, clusterData);

Hms を使用して Trino クラスターを作成する

// define the prerequisites information: subscription, resource group and location where you want to create the resource
string subscriptionResourceId = "/subscriptions/{subscription id}"; // your subscription resource id like /subscriptions/{subscription id}
string resourceGroupName = "{your resource group}"; // your resource group name
AzureLocation location = AzureLocation.EastUS; // your location

SubscriptionResource subscription = armClient.GetSubscriptionResource(new ResourceIdentifier(resourceId: subscriptionResourceId));
ResourceGroupResource resourceGroupResource = subscription.GetResourceGroup(resourceGroupName);
HDInsightClusterPoolCollection clusterPoolCollection = resourceGroupResource.GetHDInsightClusterPools();

// create the cluster
string clusterPoolName = "{your cluster pool name}";
string clusterName = "{your cluster name}";
string clusterType = "Trino"; // your cluster type

// get the available cluster version
var availableClusterVersion = subscription.GetAvailableClusterVersionsByLocation(location).Where(version => version.ClusterType.Equals(clusterType, StringComparison.OrdinalIgnoreCase)).FirstOrDefault();

// set the identity profile
string msiResourceId = "{your user msi resource id}";
string msiClientId = "{your user msi client id}";
string msiObjectId = "{your user msi object id}";
var identityProfile = new HDInsightIdentityProfile(msiResourceId: new ResourceIdentifier(msiResourceId), msiClientId: msiClientId, msiObjectId: msiObjectId);

// set the authorization profile
var userId = "{your aad user id}";
var authorizationProfile = new AuthorizationProfile();
authorizationProfile.UserIds.Add(userId);

// set the cluster node profile
string vmSize = "Standard_D8s_v3"; // your vms ize
int workerCount = 5;
ClusterComputeNodeProfile nodeProfile = new ClusterComputeNodeProfile(nodeProfileType: "worker", vmSize: vmSize, count: workerCount);

// initialize the ClusterData instance
var clusterData = new HDInsightClusterData(location)
{
    ClusterType = clusterType,
    ClusterProfile = new ClusterProfile(clusterVersion: availableClusterVersion?.ClusterVersion, ossVersion: availableClusterVersion?.OssVersion, identityProfile: identityProfile, authorizationProfile: authorizationProfile),
};
clusterData.ComputeNodes.Add(nodeProfile);

// set secret profile
string kvResourceId = "{your key vault resource id}";
string secretName = "{your secret reference name}";
string keyVaultObjectName = "{your key vault secret name}";

var secretReference = new ClusterSecretReference(referenceName: secretName, KeyVaultObjectType.Secret, keyVaultObjectName: keyVaultObjectName);
clusterData.ClusterProfile.SecretsProfile = new ClusterSecretsProfile(new ResourceIdentifier(kvResourceId));
clusterData.ClusterProfile.SecretsProfile.Secrets.Add(secretReference);

// set trino profile
string catalogName = "{your catalog name}";
string metastoreDbConnectionUriString = "jdbc:sqlserver://{your sql server name}.database.windows.net;database={your database name};encrypt=true;trustServerCertificate=true;loginTimeout=30;";
string metastoreDbUserName = "{your db user name}";
string metastoreDbPasswordSecret = secretName;
string metastoreWarehouseDir = "abfs://{your adlsgen2 storage account container}@{your adlsgen2 storage account}.dfs.core.windows.net/{sub folder path}";

TrinoProfile trinoProfile = new TrinoProfile();
trinoProfile.CatalogOptionsHive.Add(
    new HiveCatalogOption(
        catalogName: catalogName,
        metastoreDBConnectionPasswordSecret: metastoreDbPasswordSecret,
        metastoreDBConnectionUriString: metastoreDbConnectionUriString,
        metastoreDBConnectionUserName: metastoreDbUserName,
        metastoreWarehouseDir: metastoreWarehouseDir)
);

clusterData.ClusterProfile.TrinoProfile = trinoProfile;

var clusterCollection = clusterPoolCollection.Get(clusterPoolName).Value.GetHDInsightClusters();

var clusterResult = clusterCollection.CreateOrUpdate(Azure.WaitUntil.Completed, clusterName, clusterData);

Hms を使用して Spark クラスターを作成する

// define the prerequisites information: subscription, resource group and location where you want to create the resource
string subscriptionResourceId = "/subscriptions/{subscription id}"; // your subscription resource id like /subscriptions/{subscription id}
string resourceGroupName = "{your resource group}"; // your resource group name
AzureLocation location = AzureLocation.EastUS; // your location

SubscriptionResource subscription = armClient.GetSubscriptionResource(new ResourceIdentifier(resourceId: subscriptionResourceId));
ResourceGroupResource resourceGroupResource = subscription.GetResourceGroup(resourceGroupName);
HDInsightClusterPoolCollection clusterPoolCollection = resourceGroupResource.GetHDInsightClusterPools();

// create the cluster
string clusterPoolName = "{your cluster pool name}";
string clusterName = "{your cluster name}";
string clusterType = "Spark"; // your cluster type here is Spark

// get the available cluster version
var availableClusterVersion = subscription.GetAvailableClusterVersionsByLocation(location).Where(version => version.ClusterType.Equals(clusterType, StringComparison.OrdinalIgnoreCase)).FirstOrDefault();

// set the identity profile
string msiResourceId = "{your user msi resource id}";
string msiClientId = "{your user msi client id}";
string msiObjectId = "{your user msi object id}";
var identityProfile = new HDInsightIdentityProfile(msiResourceId: new ResourceIdentifier(msiResourceId), msiClientId: msiClientId, msiObjectId: msiObjectId);

// set the authorization profile
var userId = "{your aad user id}";
var authorizationProfile = new AuthorizationProfile();
authorizationProfile.UserIds.Add(userId);

// set the cluster node profile
string vmSize = "Standard_D8s_v3"; // your vms ize
int workerCount = 5;
ClusterComputeNodeProfile nodeProfile = new ClusterComputeNodeProfile(nodeProfileType: "worker", vmSize: vmSize, count: workerCount);

// initialize the ClusterData instance
var clusterData = new HDInsightClusterData(location)
{
    ClusterType = clusterType,
    ClusterProfile = new ClusterProfile(clusterVersion: availableClusterVersion?.ClusterVersion, ossVersion: availableClusterVersion?.OssVersion, identityProfile: identityProfile, authorizationProfile: authorizationProfile),
};
clusterData.ComputeNodes.Add(nodeProfile);

// set secret profile
string kvResourceId = "{your key vault resource id}";
string secretName = "{your secret reference name}";
string keyVaultObjectName = "{your key vault secret name}";

var secretReference = new ClusterSecretReference(referenceName: secretName, KeyVaultObjectType.Secret, keyVaultObjectName: keyVaultObjectName);
clusterData.ClusterProfile.SecretsProfile = new ClusterSecretsProfile(new ResourceIdentifier(kvResourceId));
clusterData.ClusterProfile.SecretsProfile.Secrets.Add(secretReference);

// set spark profile
string defaultStorageUriString = "abfs://{your adlsgen2 storage account container}@{your adlsgen2 storage account}.dfs.core.windows.net/";
string dbServerHost = "{your sql server name}.database.windows.net";
string dbUserName = "{your db user name}";
string dbName = "{yoru db name}";
string dbPasswordSecretName = secretName;

SparkProfile sparkProfile = new SparkProfile();
sparkProfile.DefaultStorageUriString = defaultStorageUriString;
sparkProfile.MetastoreSpec = new SparkMetastoreSpec(dbServerHost: dbServerHost, dbName: dbName, dbUserName: dbUserName, dbPasswordSecretName: dbPasswordSecretName, keyVaultId: kvResourceId);

clusterData.ClusterProfile.SparkProfile = sparkProfile;

var clusterCollection = clusterPoolCollection.Get(clusterPoolName).Value.GetHDInsightClusters();

var clusterResult = clusterCollection.CreateOrUpdate(Azure.WaitUntil.Completed, clusterName, clusterData);
// define the prerequisites information: subscription, resource group and location where you want to create the resource
string subscriptionResourceId = "/subscriptions/{subscription id}"; // your subscription resource id like /subscriptions/{subscription id}
string resourceGroupName = "{your resource group}"; // your resource group name
AzureLocation location = AzureLocation.EastUS; // your location

SubscriptionResource subscription = armClient.GetSubscriptionResource(new ResourceIdentifier(resourceId: subscriptionResourceId));
ResourceGroupResource resourceGroupResource = subscription.GetResourceGroup(resourceGroupName);
HDInsightClusterPoolCollection clusterPoolCollection = resourceGroupResource.GetHDInsightClusterPools();

// create the cluster
string clusterPoolName = "{your cluster pool name}";
string clusterName = "{your cluster name}";
string clusterType = "Flink"; // cluster type

// get the available cluster version
var availableClusterVersion = subscription.GetAvailableClusterVersionsByLocation(location).Where(version => version.ClusterType.Equals(clusterType, StringComparison.OrdinalIgnoreCase)).LastOrDefault();

// set the identity profile
string msiResourceId = "{your user msi resource id}";
string msiClientId = "{your user msi client id}";
string msiObjectId = "{your user msi object id}";
var identityProfile = new HDInsightIdentityProfile(msiResourceId: new ResourceIdentifier(msiResourceId), msiClientId: msiClientId, msiObjectId: msiObjectId);

// set the authorization profile
var userId = "{your aad user id}";
var authorizationProfile = new AuthorizationProfile();
authorizationProfile.UserIds.Add(userId);

// set the cluster node profile
string vmSize = "Standard_D8s_v3"; // your vm size
int workerCount = 5;
ClusterComputeNodeProfile nodeProfile = new ClusterComputeNodeProfile(nodeProfileType: "worker", vmSize: vmSize, count: workerCount);

// initialize the ClusterData instance
var clusterData = new HDInsightClusterData(location)
{
    ClusterType = clusterType,
    ClusterProfile = new ClusterProfile(clusterVersion: availableClusterVersion?.ClusterVersion, ossVersion: availableClusterVersion?.OssVersion, identityProfile: identityProfile, authorizationProfile: authorizationProfile),
};
clusterData.ComputeNodes.Add(nodeProfile);

// set secret profile
string kvResourceId = "{your key vault resource id}";
string secretName = "{your secret reference name}";
string keyVaultObjectName = "{your key vault secret name}";

var secretReference = new ClusterSecretReference(referenceName: secretName, KeyVaultObjectType.Secret, keyVaultObjectName: keyVaultObjectName);
clusterData.ClusterProfile.SecretsProfile = new ClusterSecretsProfile(new ResourceIdentifier(kvResourceId));
clusterData.ClusterProfile.SecretsProfile.Secrets.Add(secretReference);

// set flink profile

string storageUri = "abfs://{your adlsgen2 storage account container}@{your adlsgen2 storage account}.dfs.core.windows.net";
FlinkStorageProfile flinkStorageProfile = new FlinkStorageProfile(storageUri);

ComputeResourceRequirement jobManager = new ComputeResourceRequirement((float)1.0, 2048);
ComputeResourceRequirement taskManager = new ComputeResourceRequirement((float)1.0, 2048);

// set flink catalog
string metastoreDbConnectionUriString = "jdbc:sqlserver://{your sql server name}.database.windows.net;database={your database name};encrypt=true;trustServerCertificate=true;loginTimeout=30;";
string metastoreDbUserName = "{your db user name}";
string metastoreDbPasswordSecret = secretName;

FlinkHiveCatalogOption flinkHiveCatalogOption = new FlinkHiveCatalogOption(metastoreDBConnectionPasswordSecret: metastoreDbPasswordSecret, metastoreDBConnectionUriString: metastoreDbConnectionUriString, metastoreDBConnectionUserName: metastoreDbUserName);
clusterData.ClusterProfile.FlinkProfile = new FlinkProfile(storage: flinkStorageProfile, jobManager: jobManager, taskManager: taskManager);
clusterData.ClusterProfile.FlinkProfile.CatalogOptionsHive = flinkHiveCatalogOption;

var clusterCollection = clusterPoolCollection.Get(clusterPoolName).Value.GetHDInsightClusters();
var clusterResult = clusterCollection.CreateOrUpdate(Azure.WaitUntil.Completed, clusterName, clusterData);

その他の例

.NET 用管理ライブラリを使用するためのその他のコード サンプルは、次の場所にあります。

トラブルシューティング

次のステップ

Microsoft Azure SDK の詳細については、 こちらの Web サイトを参照してください。

共同作成

このリポジトリへの投稿の詳細については、 投稿ガイドを参照してください。

このプロジェクトでは、共同作成と提案を歓迎しています。 ほとんどの共同作成では、共同作成者使用許諾契約書 (CLA) にご同意いただき、ご自身の共同作成内容を使用する権利を Microsoft に供与する権利をお持ちであり、かつ実際に供与することを宣言していただく必要があります。 詳細については、 https://cla.microsoft.com を参照してください。

pull request を送信すると、CLA を提供して PR (ラベルやコメントなど) を適宜装飾する必要があるかどうかを CLA ボットが自動的に決定します。 ボットによって提供される手順に従ってください。 このアクションは、CLA を使用してすべてのリポジトリで 1 回だけ実行する必要があります。

このプロジェクトは、「Microsoft のオープン ソースの倫理規定」を採用しています。 詳しくは、倫理規定についてよくある質問に関する記事を参照するか、opencode@microsoft.com 宛てに質問またはコメントをお送りください。