はじめに
Azure App Service の Web App for Containers は、Windowsコンテナをサポートしているみたい。.NET Framework + WCFのサービスを動かせるかも。
試してみた。
WCFサービスとクライアント
サービスコントラクトとデータコントラクト
using System; using System.Runtime.Serialization; using System.ServiceModel; namespace NetHttpSample.Shared { [ServiceContract] publicinterface ISampleService { [OperationContract] ServerInfo GetServerInfo(); } [DataContract] publicclassServerInfo { [DataMember] publicstring MachineName { get; set; } [DataMember] publicstring HostName { get; set; } [DataMember] publicstring[] IPAddresses { get; set; } } }
WCFサービス
サービス側は NetHttpBinding を使う。Web App for Containers だとフロントで TLSが終端されるみたいなので、コンテナ側では HTTP で待ち受ける。
using System; using System.Linq; using System.Net; using System.ServiceModel; using System.Threading; using NetHttpSample.Shared; namespace NetHttpSample.Server { internalclassProgram { staticvoid Main(string[] args) { var host =new ServiceHost( typeof(SampleService), new Uri("http://localhost:80")); try { var binding =new NetHttpBinding(); host.AddServiceEndpoint( typeof(ISampleService), binding, "/SampleService"); host.Open(); foreach (var endpoint in host.Description.Endpoints) { Console.WriteLine(endpoint.ListenUri); } Thread.Sleep(-1); } catch { host.Close(); } } } [ServiceBehavior(AddressFilterMode = AddressFilterMode.Any)] publicclassSampleService : ISampleService { public ServerInfo GetServerInfo() { var hostName = Dns.GetHostName(); var ipAddresses = Dns.GetHostAddresses(hostName); returnnew ServerInfo { MachineName = Environment.MachineName, HostName = hostName, IPAddresses = ipAddresses.Select(x => x.ToString()).ToArray(), }; } } }
Dockerfile
# ベースイメージとして公式の .NET Framework ランタイムイメージを使用 FROM mcr.microsoft.com/dotnet/framework/runtime:4.8-windowsservercore-ltsc2019 # アプリケーションのディレクトリを作成 WORKDIR /app # WCF サービスのバイナリをコンテナにコピー COPY ./bin/Debug/ /app # 必要なポートを公開 EXPOSE 80# サービスを起動するためのエントリーポイント ENTRYPOINT ["/app/NetHttpSample.Server.exe"]
WCFクライアント
クライアント側は NetHttpsBinding を使う。アドレス違うし、バインディングも違うから通信できるか心配だったけど、特に問題なかった。
using System; using System.Net; using System.Net.Security; using System.ServiceModel; using System.ServiceModel.Channels; using NetHttpSample.Shared; namespace NetHttpSample.Client { internal class Program { static void Main(string[] args){ string host;if (args.Length >0){ host = args[0];}else{ Console.Write("ホスト[localhost]:"); host = Console.ReadLine();if (string.IsNullOrEmpty(host)){ host ="localhost";}} ServicePointManager.ServerCertificateValidationCallback =new RemoteCertificateValidationCallback((a, b, c, d) => true); for (var z =0; z <3; z++) { var binding = new NetHttpsBinding { AllowCookies =true, UseDefaultWebProxy =false, }; var factory = new ChannelFactory<ISampleService>( binding, new EndpointAddress( new Uri($"https://{host}:443/SampleService"), EndpointIdentity.CreateDnsIdentity("azurewebsites.net"))); factory.Credentials.ServiceCertificate.Authentication.CertificateValidationMode = System.ServiceModel.Security.X509CertificateValidationMode.None;for(var y =0; y <3; y++){ var channel = factory.CreateChannel();for(var x =0; x <10; x++){ var result = channel.GetServerInfo(); Console.WriteLine($"{nameof(result.MachineName)}: {result.MachineName}");}((IChannel)channel).Close(); Console.WriteLine("----------"); } factory.Close(); Console.WriteLine("===================="); } Console.WriteLine("Enter で終了"); Console.ReadLine(); } } }
デプロイ
- Azure ポータルでリソースグループ作成
- Azure ポータルでコンテナレジストリ作成
- アクセスキーの管理者ユーザーを ON にする
- コンテナイメージ作成
sh docker build -t nethttpsample:1.0.0 .
- コンテナイメージをコンテナレジストリにプッシュ
sh az acr login -n <コンテナレジストリ名> docker tag nethttpsample:1.0.0 <コンテナレジストリ名>.azurecr.io/nethttpsample:1.0.0 docker push <コンテナレジストリ名>.azurecr.io/nethttpsample:1.0.0
- App Service の Web App for Containers を作成
- 基本
- 公開:コンテナー
- オペレーティングシステム:Windows
- Docker
- セッションアフィニティ:有効
- チャンネルがオープンしている間は同じインスタンスにアクセスして欲しいので
- 基本
実行
Web App for Containers のインスタンスを 3 つに増やしてクライアントを実行したら、channel はオープンしている間、同じサーバーにアクセスし続けた。 channel を作り直した場合でも、作成元の ChannelFactory が同じなら、同じサーバーにアクセスし続けた。 ChannelFactory を作り直したら、違うサーバーにアクセスした。
NetTcpBinding と同じで、ChannelFactory が同じなら、channel は同じサーバーに接続し続けることを確認。期待通りの結果だ。
おわりに
レガシーな WCFサービスをどうにかしてモダンなインフラで動かしたいので、Web App for Containers というのはかなりアリだと思った。.NET Frameworkから .NETに移行するのがベストなのは理解している。ただ、あまりにも工数がかかり過ぎるのでね。