Azure SQL Database に接続する WCF サービスの Windows コンテナを Azure Kubernetes Service で動かす

はじめに

Azure SQL Database に接続する WCF サービスを、Windows コンテナのプロセス分離モードで動かすところまで漕ぎつけた。

tnakamura.hatenablog.com

一連の実験もいよいよ今回で最後。Azure SQL Database に接続する WCF サービスを、Azure Kubernetes Service(以下 AKS) で動かすことに挑戦した。

WCFサービス作成

AKS で動かす WCF サービスを作成。前回の WCF サービスとほぼ同じ。名前空間とポートが違うだけ。接続文字列を環境変数で受け取るのがポイント。

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

namespace WcfAks
{
    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:443/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クライアント作成

AKS でホストした WCF サービスにアクセスするクライアントを作成。こちらも前回とほとんど同じ。名前空間とポートが違うだけ。 IP アドレスが現時点では不明なので、外から渡せるようにしておく。

using System;
using System.ServiceModel;
using System.ServiceModel.Channels;
using WcfAks;

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}:443/TestService");
            var channel = factory.CreateChannel();

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

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

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

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

Dockerfile 作成

Windows コンテナをビルドするために Dockerfile を作成。

FROM mcr.microsoft.com/dotnet/framework/wcf:4.8-windowsservercore-ltsc2019
WORKDIR /app
EXPOSE 443
COPY ./WcfAks/bin/Release/ .
ENTRYPOINT ["WcfAks.exe"]

AKS 上でホストとなる Windows ノードのバージョンが 1809 のようだったので、ベースイメージを 1809 のものに変更している。 WCF サービスの待ち受けポートが 443 に変わったので、EXPOSE で指定するポートは 443。

イメージをビルド

docker build -t tnakamura/wcfaks:1.0 .

リソースグループの作成

Azure 上に実験用のリソースグループを作成する。今回は Azure ポータルではなく、Azure CLI を使って作業してみた。

az group create --name wcfaks --location japaneast

Azure Container Registry の作成

AKS で動かすコンテナのイメージは Azure Container Registry(以下 ACR) から pull したいので、実験用の ACR を作成。

az acr create -g wcfaks -n tnakamuraacr --sku basic

作成した ACR にログイン

az acr login -n tnakamuraacr

tnakamura/wcfaks にタグを設定

予め作成しておいたイメージを ACR に push するために、タグを設定する必要がある。

docker tag tnakamura/wcfaks:v1 tnakamuraacr.azurecr.io/wcfaks:v1

ACR にイメージをプッシュ

docker push tnakamuraacr.azurecr.io/wcfaks:v1

AKS クラスタの作成

Windows コンテナを動かすための AKS クラスタを作成。

az aks create --resource-group wcfaks \
  --name wcfAKSCluster \
  --node-count 1 \
  --generate-ssh-keys \
  --attach-acr tnakamuraacr \
  --enable-addons monitoring \
  --windows-admin-password <password> \
  --windows-admin-username azureuser \
  --vm-set-type VirtualMachineScaleSets \
  --network-plugin azure

--attach-acr で先ほど作成した ACR をアタッチすることで、AKS が ACR からコンテナイメージを pull できるようになる。

Windows Serverノードプールを追加

Windows コンテナを動かせるのは Windows ノードだけなので、Windows ノードを追加する必要がある。

az aks nodepool add --resource-group wcfaks \
  --cluster-name wcfAKSCluster \
  --os-type Windows \
  --name npwin \
  --node-count 1

最初から Windows ノードを作成できるようになったらいいんだけどね…。

kubectlをインストール

Kubernetes の操作は kubectl を使う。

az aks install-cli

作成したAKSクラスタへの接続

az aks get-credentials --resource-group wcfaks --name wcfAKSCluster

Kubernetesマニフェストファイルを作成

docs.microsoft.com

上記のドキュメントのマニフェストファイルをベースに、イメージ名や環境変数、ポートを変更。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: sample
  labels:
    app: sample
spec:
  replicas: 1
  template:
    metadata:
      name: sample
      labels:
        app: sample
    spec:
      nodeSelector:
        "beta.kubernetes.io/os": windows
      containers:
      - name: sample
        image: tnakamuraacr.azurecr.io/wcfaks:v1
        env:
          - name: CONNECTION_STRING
            value: "Azure SQL Database の接続文字列"
        resources:
          limits:
            cpu: 1
            memory: 800M
          requests:
            cpu: .1
            memory: 300M
        ports:
          - containerPort: 443
  selector:
    matchLabels:
      app: sample
---
apiVersion: v1
kind: Service
metadata:
  name: sample
spec:
  type: LoadBalancer
  ports:
  - protocol: TCP
    port: 443
  selector:
    app: sample

アプリケーションをデプロイ

kubectl apply -f wcfaks.yaml

イメージサイズが大きいせいで Pod が動くまで時間がかかるため、kubectl get pods --watch で確認しながら気長に待つ。

WCFクライアントから接続

まずは kubectl get services で、ロードバランサーの外部 IP アドレスを確認。

f:id:griefworker:20201221155709p:plain

判明した IP アドレスを引数に、クライアントを起動。

f:id:griefworker:20201221155726p:plain

SQL Server のバージョンが表示された。ということは、AKS で動いている WCF サービスが Azure SQL Database に無事接続できたことになる。

AKS クラスタ削除

用済みなので、リソースグループごと削除。

az group delete --name wcfaks --yes --no-wait

おわりに

Azure SQL Database に接続する WCF サービスの Windows コンテナを Azure Kubernetes Service で動かすことに成功した。Windows コンテナ関連の実験で設定していたゴールに、ついに到達。達成感ハンパない。

Kubernetes は入門したばかりなので、Kubernetes を習得することを次の目標にしよう