読者です 読者をやめる 読者になる 読者になる

銀の光と碧い空

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

TopShelf と MSDeploy で作る、Windowsサービスお手軽自動展開環境

Windows上で長期間に渡ってバックグランドで動くようなプログラムを作るのに、Windowsサービスを使うことができます。

Windows サービス アプリケーションの概要

なんですが、WindowsサービスをVisual Studioにデフォルトで用意されているものだけで作ると割と面倒だったりします。これを解決するのに、TopShelfというツール(ライブラリ)があります。詳しくは以下のサイトに使い方から詳しく紹介されています。

Windowsサービスを楽に開発~TopShelf~ | 84zume Works

ここにもある通り、なにが便利かというと、普通のコンソールアプリケーションとして開発することができて、デバッグなどが用意になります。そして、面倒なWindowsサービスとしての設定の部分は、TopShelfのライブラリを参照してC# コードとして記述できることです。

こうやって作成したコンソールアプリケーションのビルド成果物(通常 bin\Release フォルダ以下に作られる exe一式)を動かすとコンソール上、そしてWindowsサービスへのインストールが簡単に実現できます。

さて、これで成果物一式はできたのですが、この成果物を特定のサーバーで動かしたくて、かつCI環境を使って、リポジトリにコミットしたら自動もしくはワンポチでそのサーバーに展開したい、という要件が出てきたとしましょう。

まず、成果物一式を特定のサーバーに転送するには、MSDeployコマンドを使うことができます。MSDeployコマンドが RoboCopy と比べて優れている点は、転送先のフォルダをUNCの共有フォルダでなくても転送できる点です。逆にデメリットとしては、ファイルを受け取る側で2つの必要なサービスをインストールして動いていないといけないことと、特定のポートが開いていないといけない点があります。以前書いたエントリでも紹介しています。

あるディレクトリ以下のファイルを MSDeploy でIIS Webサイトにデプロイする - 銀の光と碧い空

このエントリではIISのWebサイトとして~とありますが、IISとは全く関係ない、普通のディレクトリにも転送(同期)することができます。

これで自動でexeを更新できる...といいたいところですが、Windowsサービスとして動いているのでこのままではうまくいきません。サービスとして動いているプロセスがexeファイルなどをつかんでいるため、そのままでは上書きできないのです。サービスを一時停止していい場合では、この問題に対しMSDeploy の runCommand プロバイダーを使うことで解決することができます。

Web 配置 runCommand プロバイダー

操作設定 -presync および -postSync と共に runCommand を使うことによって、MSDeployによるファイル同期の前後に指定したコマンドを実行できます。この場合、サービスの停止と開始を指定してあげるとうまくいきます。

MSDeploy.exe -preSync:runCommand="net stop MyService" -verb:sync -source:dirPath="C:\Tool\bin" -dest:computerName="http://ww.xx.yy.zz/MSDeployAgentService",userName="administrator",password="password",includeAcls="False",dirPath="C:\Tools\bin"  -postSync:Command="net start MyServoce"

更新対象のexeを MyServiceというサービスで動かしている場合、このコマンドでMyServiceを止めてから同期が実行され、MyServiceを起動することになります。

という感じでこの2つを組み合わせると、割と簡単にWindowsサービスの自動展開環境を作ることができます。

そして、前回のエントリで紹介した Config Transform を使うと、展開先が複数あって設定を切り替えたい場合も、コードは1つで App.XXX.config を展開先ごとに用意することで対応することができます。

App.config の config変換をしてくれる便利すぎるVisual Studio 拡張「Configuration Transform」 - 銀の光と碧い空