Azure SQL Database に接続する WCF サービスを Windows コンテナのプロセス分離モードで動かす実験

はじめに

最近、自分の中で Docker 熱、というか Windows コンテナ熱が再燃。Windows コンテナのプロセス分離モードで WCF サービスをホストするのと、Windows コンテナの中から Azure SQL Database に繋ぐところまでは、以前実験した。

tnakamura.hatenablog.com

tnakamura.hatenablog.com

今度はこれらを合体。Azure SQL Database に接続する WCF サービスを、Windows コンテナのプロセス分離モードで動かしてみる。

WCF サービス

Azure SQL Database に接続して、バージョンを取得する SQL を実行するだけの簡単な WCF サービスを作成。接続文字列は環境変数で渡せるようにしておく。

using System;
using System.Data.SqlClient;
using System.ServiceModel;
using System.Threading;

namespace WcfWCOW
{
    class Program
    {
        static void Main(string[] args)
        {
            if (string.IsNullOrEmpty(TestService.ConnectionString))
            {
                Console.WriteLine("環境変数 CONNECTION_STRING を設定してください。");
                return;
            }

            var host = new ServiceHost(typeof(TestService));
            try
            {
                var binding = new NetTcpBinding();
                binding.Security.Mode = SecurityMode.None;

                host.AddServiceEndpoint(
                    typeof(ITestService),
                    binding,
                    "net.tcp://localhost:8080/TestService");
                host.Open();

                foreach (var endpoint in host.Description.Endpoints)
                {
                    Console.WriteLine(endpoint.ListenUri);
                }

                Thread.Sleep(-1);

            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                Console.WriteLine(ex.StackTrace);
                host.Close();
            }
        }
    }

    [ServiceContract]
    public interface ITestService
    {
        [OperationContract]
        string Test();
    }

    [ServiceBehavior(IncludeExceptionDetailInFaults = true)]
    public class TestService : ITestService
    {
        public static string ConnectionString { get; }

        static TestService()
        {
            ConnectionString = Environment.GetEnvironmentVariable("CONNECTION_STRING");
        }

        public string Test()
        {
            try
            {
                using (var connection = new SqlConnection(ConnectionString))
                {
                    connection.Open();
                    using (var command = connection.CreateCommand())
                    {
                        command.CommandText = @"SELECT @@VERSION";
                        return (string)command.ExecuteScalar();
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                Console.WriteLine(ex.StackTrace);
                throw;
            }
        }
    }
}

WCF クライアント

WCF サービスが動くコンテナの IP アドレスは起動するたび変わるので、コマンドライン引数で渡せるようにしておく。

using System;
using System.ServiceModel;
using System.ServiceModel.Channels;
using WcfWCOW;

namespace ConsoleClient
{
    class Program
    {
        static void Main(string[] args)
        {
            if (args.Length == 0)
            {
                Console.WriteLine("ホスト名または IP アドレスを指定してください。");
                return;
            }
            var host = args[0];
            var factory = new ChannelFactory<ITestService>(
                new NetTcpBinding(SecurityMode.None),
                $"net.tcp://{host}:8080/TestService");
            var channel = factory.CreateChannel();

            var result = channel.Test();
            Console.WriteLine(result);

            Console.WriteLine("Enter で終了");
            Console.ReadLine();

            ((IChannel)channel).Close();
        }
    }
}

namespace WcfWCOW
{
    [ServiceContract]
    public interface ITestService
    {
        [OperationContract]
        string Test();
    }
}

Dockerfile

あらかじめビルドしておいた WCF サービスのファイル一式をコピーして起動するように、Dockerfile を記述。

FROM mcr.microsoft.com/dotnet/framework/wcf:4.8
WORKDIR /app
EXPOSE 8080
COPY ./WcfWCOW/bin/Release/ .
ENTRYPOINT ["WcfWCOW.exe"]

起動

Dockerfile からコンテナイメージをビルドし、起動。Azure SQL Database の接続文字列を環境変数で渡している。

> docker build -t tnakamura/wcfwcow:1.0 .
> docker run --rm --isolation process -e CONNECTION_STRING="接続文字列" --name wcfwcow tnakamura/wcfwcow:1.0

エンドポイントのアドレスが表示されたら、WCF サービスの起動に成功したことになる。

f:id:griefworker:20201124103250p:plain

接続

docker inspect で起動したコンテナの IP アドレスを調べ、その IP アドレスを引数にクライアントを起動。

> docker inspect -f "{{ .NetworkSettings.Networks.nat.IPAddress }}" wcfwcow
> .\ConsoleClient.exe コンテナのIPアドレス

Azure SQL Database のバージョンが表示されたら実験成功。

f:id:griefworker:20201124103306p:plain

おわりに

Azure SQL Database に接続する WCF サービスを Windows コンテナのプロセス分離モードで動かすことに成功した。次のステップは、Azure Kubernetes Service かな。実験もいよいよ最終段階。

実をいうと、Windows コンテナのホスト側で動かしている SQL Server Express にも繋ぎたかったけど、host.docker.internal で繋げなかった。Windows コンテナだったから?プロセス分離だったから?今回も解決できず時間切れ。いずれリベンジしたい。