Custom Deployment for Azure Web Apps using CAKE
GitHub のソースから Azure WebApps にデプロイするときの Kudu カスタムデプロイ機能にて、
CAKE(C#) を使ったビルドを試してみました。
CAKE とは
C# のスクリプトでビルドのタスクを書くプロジェクトです。Roslyn と Mono で動くので、クロスプラットフォームなビルドシステムになります。
オープンソースです。
ググるときは、CakePHP がひっかかってしまうで、"CAKE build" "cakebuild" がいいです。(C# Make が由来っぽいけど…。)
↓このような感じで C# でビルドタスクを記述します。
今回は、デプロイに加え、Web.config の置換をアドインでやってみました。ソースは、ASP.NET なプロジェクトを前提とします。
試してみた手順
GitHub と Azure WebApps の連携
まず、GitHub のリポジトリ・Azure WebApps・ASP.NET なプロジェクトを用意します。
GitHub には、ASP.NET のプロジェクトを push しておきます。
次に、ポータルの Azure WebApps にて、「デプロイ オプション」を選択し、WebApps と GitHub を紐づけます。
項目について:
似た項目が2つ「デプロイ オプション」と「継続的配信(プレビュー)」とありますが、
前者は Kudu が「MSBuild.exe」でビルドしますが、後者は、Visual Studio Team Service のビルドエージェントにてビルドを行います。
後者は Visual Studio Team Service にてビルドされますが、ソースは GitHub に置くことも可能です。
「継続的配信(プレビュー)」については、次の2つのドキュメントが参考になりました。
Visual Studio Team Servicesのサーバービルド機能を使う(8日目) - kkamegawa's weblog
Continuous delivery to Azure App Service from Release Management
Kudu のカスタムデプロイ
上記のように、GitHub と Azure WebApps を連携すると、すぐにデプロイが開始されます。
この仕組みについては、Azure Web App のカスタムデプロイを使って特定のディレクトリをGithubと同期する - tech.guitarrapc.cóm が参考になりました。
デプロイは、WebApps の「D:\home\site\deployments\tools」配下にある「deploy.cmd」が実行されます。
(↑ https://{webappsの名前}.scm.azurewebsites.net/DebugConsole でアクセスできる Kudu の CMD 画面。)
カスタムデプロイを試す一歩として、GitHub リポジトリの root フォルダに「.deployment」ファイルを作成し、次のように記述します。
.deployment:
[config] command = deploy.cmd
deploy.cmd は、先ほどの「D:\home\site\deployments\tools」配下からコピーし、GitHub リポジトリの root フォルダに配置します。
(↑ GitHub リポジトリのフォルダ)
この状態で GitHub に push すると、deploy.cmd が実行されデプロイが行われます。
この「.deployment」ファイルや「deploy.cmd」等をカスタマイズすることが、いわゆる Kudu の カスタムデプロイと言われます。
カスタマイズ方法については:
Customizing deployments · projectkudu/kudu Wiki · GitHub
Configurable settings · projectkudu/kudu Wiki · GitHub
CAKE でビルドする
Kudu のカスタムデプロイ時に、CAKE でビルドを行うようにします。
Cake - Cake Kudu - Azure Web Deployment Addin こちらのサイトが参考になりました。が、そのままコピペするとエラーになります。
(余計な
先ほど作成した deploy.cmd ファイルを、次のように変更します。
deploy.cmd:
@echo off IF NOT EXIST "Tools" (md "Tools") IF NOT EXIST "Tools\Addins" (md "Tools\Addins") nuget install Cake -ExcludeVersion -OutputDirectory "Tools" Tools\Cake\Cake.exe deploy.cake -verbosity=Verbose
次に、同じく GitHub リポジトリの root フォルダに「deploy.cake」ファイルを作成し、次のように記述します。
deploy.cake:
#tool "KuduSync.NET" "https://www.nuget.org/api/v2/" #addin "Cake.Kudu" "https://www.nuget.org/api/v2/" /////////////////////////////////////////////////////////////////////////////// // ARGUMENTS /////////////////////////////////////////////////////////////////////////////// var target = Argument<string>("target", "Default"); var configuration = Argument<string>("configuration", "Release"); /////////////////////////////////////////////////////////////////////////////// // GLOBAL VARIABLES /////////////////////////////////////////////////////////////////////////////// var websitePath = MakeAbsolute(Directory("./MisoDep")); var solutionPath = MakeAbsolute(File("./MisoDep.sln")); if (!Kudu.IsRunningOnKudu) { throw new Exception("Not running on Kudu"); } var deploymentPath = Kudu.Deployment.Target; if (!DirectoryExists(deploymentPath)) { throw new DirectoryNotFoundException( string.Format( "Deployment target directory not found {0}", deploymentPath ) ); } /////////////////////////////////////////////////////////////////////////////// // TASK DEFINITIONS /////////////////////////////////////////////////////////////////////////////// Task("Clean") .Does(() => { //Clean up any binaries Information("Cleaning {0}", websitePath); CleanDirectories(websitePath + "/bin"); }); Task("Restore") .Does(() => { // Restore all NuGet packages. Information("Restoring {0}...", solutionPath); NuGetRestore(solutionPath); }); Task("Build") .IsDependentOn("Clean") .IsDependentOn("Restore") .Does(() => { // Build all solutions. Information("Building {0}", solutionPath); MSBuild(solutionPath, settings => settings.SetPlatformTarget(PlatformTarget.MSIL) .WithProperty("TreatWarningsAsErrors","true") .WithTarget("Build") .SetConfiguration(configuration)); }); Task("Publish") .IsDependentOn("Build") .Does(() => { Information("Deploying web from {0} to {1}", websitePath, deploymentPath); Kudu.Sync(websitePath); }); Task("Default") .IsDependentOn("Publish"); /////////////////////////////////////////////////////////////////////////////// // EXECUTION /////////////////////////////////////////////////////////////////////////////// RunTarget(target);
ここで、次の行を環境に合わせて編集します。
configuration の第二引数には、ビルドのモードを設定します。(Release など)
edit deploy.cake:
var target = Argument<string>("target", "Default"); var configuration = Argument<string>("configuration", "vsbuildrelease");
websitePath には、GitHub リポジトリ内の、発行対象となるフォルダを、
websitePath には、.sln ファイルパスを記述します。
edit deploy.cake:
var websitePath = MakeAbsolute(Directory("./MisoDep")); var solutionPath = MakeAbsolute(File("./MisoDep.sln"));
以上のように編集した後、push を行うと CAKE によるビルドが走ると思います。
確認するには、Azure WebApps のポータルの「デプロイオプション」にてログを表示します。
Web.config を変換する
このままでは、Web.config が適した Web.**.config へ変換されません。変換するには、GitHub - nengberg/cake-envxmltransform: A plugin for Cake for environment-based configuration transformations こちらのアドインを追加します。
ASP.NET のプロジェクトに第三のソリューション構成を作成して試してみます。
ビルド>構成マネージャー を開き、「vsbuildrelease」という名前で追加してみました。
Web.config が置換されたかどうか確認するために、構成ごとの appSettings の値をサイトに表示する、という手段をとります。
「Web.config」ファイルを右クリックし、「Config 変換を追加」をクリックします。「Web.vsbuildrelease.config」が追加されます。
「Web.config」ファイルにて、appSettings を追加します。
<appSettings> <add key="Environment" value="Dev"/>
「Web.vsbuildrelease.config」には、次のように記述します。
<appSettings> <add key="Environment" value="vsbuildrelease" xdt:Transform="SetAttributes" xdt:Locator="Match(key)"/>
ASP.NET のプロジェクト内にて、適当なページに次のように記述します。(例は Home.cshtml ファイルにて)
<div> Environment: @System.Configuration.ConfigurationManager.AppSettings["Environment"] </div>
CALE ビルドを設定します。
3行目あたりに「#addin Cake.EnvXmlTransform」を追加します。
deploy.cake:
#tool "KuduSync.NET" "https://www.nuget.org/api/v2/" #addin "Cake.Kudu" "https://www.nuget.org/api/v2/" #addin Cake.EnvXmlTransform
deploy.cake L55 あたりに追加:
Task("Apply-Config-Transformations") .Does(() => { Information("Apply-Config-Transformations"); var configFileFolder = "./*/*.config"; var environment = configuration; ConfigTransform.ApplyTransformations(configFileFolder, environment); });
64行目あたりで、次のように「.IsDependentOn("Apply-Config-Transformations")」を追加します。
deploy.cake L64:
Task("Build") .IsDependentOn("Clean") .IsDependentOn("Restore") .IsDependentOn("Apply-Config-Transformations") .Does(() => { // Build all solutions. Information("Building {0}", solutionPath); MSBuild(solutionPath, settings => settings.SetPlatformTarget(PlatformTarget.MSIL) .WithProperty("TreatWarningsAsErrors","true") .WithTarget("Build") .SetConfiguration(configuration)); });
これでデプロイすると、Web.config が置換されてデプロイされるはずです。
ログを見ると次のように表示されました。
CAKE のパッケージやアドインは、「D:\home\site\repository\Tools」配下にあります。
その後、CAKE.Kudu 0.4.0 が更新され .NET Core に移行したみたいです。
Cake.Kudu 0.4.0 released - ported to .NET Core https://t.co/w4zzP2qLPh #azure #dotnet #devops pic.twitter.com/UXAzV4JJlT
— WCOMAB (@WCOMAB) 2017年1月13日
また、こちら