次の方法で共有


ビルド処理について理解する

作成者: Jason Lee

このトピックでは、エンタープライズ規模のビルドおよびデプロイ プロセスに関するチュートリアルを提供します。 このトピックで説明するアプローチでは、Microsoft Build Engine (MSBuild) のカスタム プロジェクト ファイルを使用し、プロセスのあらゆる側面をきめ細かく制御します。 プロジェクト ファイル内では、カスタム MSBuild ターゲットを使用して、インターネット インフォメーション サービス (IIS) Web 配置ツール (MSDeploy.exe) やデータベース デプロイ ユーティリティ VSDBCMD.exe などの各種デプロイ ユーティリティを実行します。

Note

前のトピック「プロジェクト ファイルについて」では、MSBuild プロジェクト ファイルの主要なコンポーネントについて説明し、複数のターゲット環境へのデプロイをサポートするための分割プロジェクト ファイルの概念を紹介しました。 これらの概念をまだ十分に理解していない場合は、このトピックに取り組む前に「プロジェクト ファイルについて」を再確認してください。

このトピックは、Fabrikam, Inc. という架空の会社のエンタープライズ デプロイ要件を題材にしたチュートリアル シリーズの一部です。このシリーズでは、サンプル ソリューション (Contact Manager ソリューション) を使用して、現実的なレベルの複雑さを持った、ASP.NET MVC 3 アプリケーション、Windows Communication Foundation (WCF) サービス、データベース プロジェクトなどを含んだ Web アプリケーションを取り上げます。

これらのチュートリアルの核心であるデプロイ方法は、「プロジェクト ファイルについて」で説明した分割プロジェクト ファイルのアプローチを基にして、ビルド プロセスを 2 つのプロジェクト ファイル (すべてのデプロイ先環境に適用されるビルド命令を含んだファイルと、環境に特化したビルド設定やデプロイ設定を含んだファイル) で制御するものになっています。 ビルド時には、環境に特化したプロジェクト ファイルが環境に依存しないプロジェクト ファイルにマージされ、ビルド命令の完全なセットが形成されます。

ビルドとデプロイの概要

Contact Manager ソリューションでは、ビルドとデプロイのプロセスを以下 3 つのファイルで制御します。

  • ユニバーサル プロジェクト ファイル (Publish.proj)。 これには、デプロイ先環境の違いに左右されないビルドとデプロイの手順が含まれています。
  • 環境固有のプロジェクト ファイル (Env-Dev.proj)。 これには、個々のデプロイ先環境に特化したビルドとデプロイの設定が含まれています。 たとえば、開発者環境およびテスト環境向けの設定を含んだ Env-Dev.proj ファイルと、ステージング環境向けの設定を含んだ Env-Stage.proj という代替ファイルを作成し、2 つを使い分けるようにすることが考えられます。
  • コマンド ファイル (Publish-Dev.cmd)。 これには、どのプロジェクト ファイルを実行するかを指定する MSBuild.exe コマンドが含まれています。 デプロイ先環境ごとに異なるコマンド ファイルを作成し、それぞれの環境に特化したプロジェクト ファイルを指定する MSBuild.exe コマンドを含めることができます。 そうすると、開発者が適切なコマンド ファイルを実行するだけで各種環境へのデプロイを実行できるようになります。

このサンプル ソリューションの場合、Publish ソリューション フォルダー内にこれら 3 つのファイルがあります。

In the sample solution, you can find three files in the Publish solution folder.

3 つのファイルを詳しく説明する前に、このアプローチにおけるビルド プロセス全体のしくみを見てみましょう。 ビルドとデプロイのプロセスを大まかに示すと以下の図のようになります。

What the build and deployment process looks like at a high level.

まず、2 つのプロジェクト ファイル (ユニバーサルなビルドおよびデプロイ手順のファイルと、環境に特化した設定のファイル) を 1 つのプロジェクト ファイルにマージします。 その後、MSBuild がプロジェクト ファイル内の命令を処理します。 MSBuild は、ソリューション内の各プロジェクトを、各プロジェクト用のプロジェクト ファイルに基づいてビルドした後、 他のツール (Web 配置ツール MSDeploy.exe、VSDBCMD ユーティリティなど) を呼び出して、Web コンテンツとデータベースをターゲット環境にデプロイします。

ビルドとデプロイのプロセスにおいて実行するタスクを最初から最後まで順に示すと、以下のようになります。

  1. 新しいビルドを実行する準備の一環として、出力ディレクトリの内容が削除されます。

  2. ソリューション内の各プロジェクトがビルドされます。

    1. Web プロジェクト (この例では、ASP.NET MVC Web アプリケーションと WCF Web サービス) については、プロジェクトごとの Web 配置パッケージがビルド プロセスによって作成されます。
    2. データベース プロジェクトについては、プロジェクトごとにデプロイ マニフェスト (.deploymanifest ファイル) がビルド プロセスによって作成されます。
  3. VSDBCMD.exe ユーティリティを使用してソリューション内の各データベース プロジェクトがデプロイされます。このとき、deploymanifest ファイルに加え、プロジェクト ファイルのさまざまなプロパティ (ターゲット接続文字列、データベース名) が使用されます。

  4. MSDeploy.exe ユーティリティを使用してソリューション内の各 Web プロジェクトがデプロイされます。このとき、プロジェクト ファイルのさまざまなプロパティがデプロイ プロセスの制御に使用されます。

サンプル ソリューションでは、このプロセスのさらに詳細な内容をたどることができます。

Note

環境に特化したプロジェクト ファイルを、実際にお使いのサーバー環境に合わせてカスタマイズする方法については、「ターゲット環境のデプロイ プロパティを構成する」のガイダンスを参照してください。

ビルドおよびデプロイ プロセスの呼び出し

Contact Manager ソリューションを開発者テスト環境にデプロイするには、開発者が Publish-Dev.cmd コマンド ファイルを実行します。 このファイルでは、MSBuild.exe に対し、実行のプロジェクト ファイルとして Publish.proj、パラメーター値として Env-Dev.proj を指定して呼び出しを行います。

msbuild.exe Publish.proj /fl /p:TargetEnvPropsFile=EnvConfig\Env-Dev.proj

Note

/fl スイッチ (/fileLogger の短縮形) は、現在のディレクトリにある msbuild.log というファイルにビルド出力を記録する指示です。 詳細については、「MSBuild コマンド ライン リファレンス」を参照してください。

この時点で MSBuild の実行が始まり、Publish.proj ファイルの読み込みと、その中の命令の処理が開始されます。 最初の命令は、TargetEnvPropsFile パラメーターで指定したプロジェクト ファイルを MSBuild にインポートさせる指示です。

<Import Project="$(TargetEnvPropsFile)" />

TargetEnvPropsFile パラメーターで Env-Dev.proj ファイルが指定されているため、MSBuild は、Env-Dev.proj ファイルの内容を Publish.proj ファイルにマージします。

マージされたプロジェクト ファイルによって MSBuild に伝えられる 2 番目の要素は、プロパティ グループです。 プロパティは、このファイル内に記述された順に上から処理されます。 MSBuild は、指定された条件のいずれかに合致した場合、各プロパティのキーと値のペアを作成します。 ファイル内に同じ名前のプロパティが複数回出現する場合は、下に記述されたプロパティ定義が優先され、上方にある定義は上書きされます。 たとえば、以下の OutputRoot プロパティ定義が含まれているとします。

<OutputRoot Condition=" '$(OutputRoot)'=='' ">..\Publish\Out\</OutputRoot>
<OutputRoot Condition=" '$(BuildingInTeamBuild)'=='true' ">$(OutDir)</OutputRoot>

MSBuild が最初の OutputRoot 要素を処理するときは、同じ名前のパラメーターがまだ設定されていない場合に、OutputRoot プロパティの値を ..\publish\Out に設定します。その後、2 番目の OutputRoot 要素を処理するときは、指定された条件が true と評価された場合に、OutputRoot プロパティの値を OutDir パラメーターの値で上書きします。

MSBuild が次に検出する要素は、ProjectsToBuild という項目を含んだ単一の項目グループです。

<ItemGroup>
   <ProjectsToBuild Include="$(SourceRoot)ContactManager-WCF.sln"/>
</ItemGroup>

MSBuild は、この命令を処理すると、ProjectsToBuild という名前の項目リストを作成します。 この例では、項目リストに含まれる値は 1 つだけです (ソリューション ファイルのパスとファイル名)。

これ以降に残っている要素は、各種のターゲットです。 ターゲットはプロパティや項目とは異なる方法で処理されます。簡単にいえば、あるターゲットが処理されるのは、ユーザーから明示的に指定された場合か、同じプロジェクト ファイル内の別のコンストラクトによって呼び出された場合のみです。 ここで、Project 開始タグに DefaultTargets 属性が含まれていたことを思い出してください。

<Project ToolsVersion="4.0" 
         DefaultTargets="FullPublish" 
         xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

この属性には、MSBuild.exe の呼び出し時にターゲットが指定されていない場合 FullPublish ターゲットを呼び出すという指示が記述されています。 FullPublish ターゲットには、タスクは 1 つも含まれておらず、依存関係リストだけが指定されています。

<PropertyGroup>   
  <FullPublishDependsOn>
     Clean;
     BuildProjects;      
     GatherPackagesForPublishing;
     PublishDbPackages;
     PublishWebPackages;
  </FullPublishDependsOn>
</PropertyGroup>
<Target Name="FullPublish" DependsOnTargets="$(FullPublishDependsOn)" />

この依存関係は、MSBuild に対し、FullPublish ターゲットを実行するにはこのターゲットの一覧を、以下のとおり指定順に呼び出す必要があることを指示するものです。

  1. Clean ターゲットを呼び出します。
  2. BuildProjects ターゲットを呼び出します。
  3. GatherPackagesForPublishing ターゲットを呼び出します。
  4. PublishDbPackages ターゲットを呼び出します。
  5. PublishWebPackages ターゲットを呼び出します。

Clean ターゲット

Clean ターゲットでは、簡単にいえば、新しいビルドを行うための準備として、出力ディレクトリとその内容をすべて削除します。

<Target Name="Clean" Condition=" '$(BuildingInTeamBuild)'!='true' ">
  <Message Text="Cleaning up the output directory [$(OutputRoot)]"/>
  <ItemGroup>
     <_FilesToDelete Include="$(OutputRoot)**\*"/>
  </ItemGroup>
  <Delete Files="@(_FilesToDelete)"/>
  <RemoveDir Directories="$(OutputRoot)"/>
</Target>

このターゲットには ItemGroup 要素が含まれていることに注目してください。 Target 要素内でこのようにプロパティや項目を定義することには、プロパティや項目を "動的に" 作成する効果があります。 つまり、それらのプロパティまたは項目は、ターゲットが実行される時点までは処理されません。 出力ディレクトリとその中のファイルは、ビルド プロセスの開始以前にはまだ存在していない可能性があるため、_FilesToDelete リストを静的な項目としてビルドすることはできず、実行の開始後まで待つ必要があります。 そのため、このリストはターゲット内の動的項目としてビルドする必要があります。

Note

この例の Clean ターゲットは最初に実行されるため、動的項目グループを使用することは実際には不要です。 しかし、この種類のシナリオでは、後でターゲットの実行順序を変更する状況が発生する可能性を考慮し、動的なプロパティと項目を使用することをお勧めします。
また、決して使用されない項目はできるだけ宣言しないようにすることが望ましいという面もあります。 特定の 1 つのターゲットでしか使用されない項目がある場合は、それらの項目の宣言をターゲット内に記述すると、ビルド プロセスから不要なオーバーヘッドを取り除ける可能性があります。

Clean ターゲットの内容は、動的項目以外は非常に単純です。組み込みタスクである MessageDeleteRemoveDir を使用して以下のことを実行しています。

  1. ロガーにメッセージを送信します。
  2. 削除対象ファイルのリストを作成します。
  3. ファイルを削除します。
  4. 出力ディレクトリを削除します。

BuildProjects ターゲット

BuildProjects ターゲットでは、簡単にいえば、サンプル ソリューション内のすべてのプロジェクトをビルドします。

<Target Name="BuildProjects" Condition=" '$(BuildingInTeamBuild)'!='true' ">
   <MSBuild Projects="@(ProjectsToBuild)"
            Properties="OutDir=$(OutputRoot);
                        Configuration=$(Configuration);
                        DeployOnBuild=true;
                        DeployTarget=Package"
            Targets="Build" />
  </Target>

このターゲットに関しては、前のトピック「プロジェクト ファイルについて」において、タスクとターゲットがプロパティや項目を参照する方法などを詳細に説明しました。 したがって、現在のトピックでは主に MSBuild タスクについて説明します。 このタスクでは複数のプロジェクトをビルドできます。 ただし、MSBuild.exe の新しいインスタンスを作成するのではなく、現在実行中のインスタンスを使用して各プロジェクトをビルドします。 この例における重要ポイントは、デプロイに関する以下のプロパティです。

  • DeployOnBuild プロパティでは、各プロジェクトのビルドが完了した時点でプロジェクト設定内のデプロイ手順を実行するよう MSBuild に指示しています。
  • DeployTarget プロパティでは、プロジェクトのビルド後に呼び出す特定のターゲットを示しています。 この例では、Package ターゲットを使用して、プロジェクトの出力から、デプロイ可能な Web パッケージをビルドします。

Note

この Package ターゲットは、MSBuild と Web 配置の統合を実現する Web 発行パイプライン (WPP) を呼び出します。 WPP に用意されている各種の組み込みターゲットを確認するには、%PROGRAMFILES(x86)%\MSBuild\Microsoft\VisualStudio\v10.0\Web フォルダー内の Microsoft.Web.Publishing.targets ファイルを参照してください。

GatherPackagesForPublishing ターゲット

GatherPackagesForPublishing ターゲットをよく調べると、実際のタスクは 1 つもないことがわかります。 含まれているのは、3 つの動的項目を定義する 1 つの項目グループだけです。

<Target Name="GatherPackagesForPublishing">
   <ItemGroup>
      <PublishPackages 
         Include="$(_ContactManagerDest)ContactManager.Mvc.deploy.cmd">
         <WebPackage>true</WebPackage>
         <!-- More item metadata -->  
      </PublishPackages>
      <PublishPackages 
         Include="$(_ContactManagerSvcDest)ContactManager.Service.deploy.cmd">
         <WebPackage>true</WebPackage>
         <!-- More item metadata -->
      </PublishPackages>
      <DbPublishPackages Include="$(_DbDeployManifestPath)">
         <DbPackage>true</DbPackage>
         <!-- More item metadata -->
      </DbPublishPackages>
   </ItemGroup>
</Target>

これらの項目では、BuildProjects ターゲットの実行によって作成されたデプロイ パッケージを参照しています。 これらの項目は、BuildProjects ターゲットの実行前には参照先ファイルが存在しないため、プロジェクト ファイル内に静的に定義することはできません。 BuildProjects ターゲットの実行後に初めて呼び出されるようなターゲットの中で、動的に項目を定義する必要があります。

また、このターゲットは、項目のビルドと、各項目の値に関連付けられたメタデータのビルドを行うだけのものであるため、これらの項目はこのターゲット内では使用されません。 それらの要素が処理された後、PublishPackages 項目には、ContactManager.Mvc.deploy.cmd ファイルへのパス、および ContactManager.Service.deploy.cmd ファイルへのパスという 2 つの値が含まれます。 この 2 つは、Web 配置によって各プロジェクトの Web パッケージの要素として作成されるファイルであり、パッケージをデプロイする際は、これらをデプロイ先サーバー上で呼び出す必要があります。 どちらかを開いてみるとわかりますが、基本的には、ビルドに特化したさまざまなパラメーター値を指定して MSDeploy.exe コマンドを実行する内容です。

DbPublishPackages 項目には、ContactManager.Database.deploymanifest ファイルへのパスという 1 つの値が含まれます。

Note

データベース プロジェクトをビルドすると、MSBuild プロジェクト ファイルと同じスキーマを使用する .deploymanifest ファイルが生成されます。 このファイルには、データベースをデプロイするために欠かせない、データベース スキーマ (.dbschema) の場所や、デプロイ前スクリプトとデプロイ後スクリプトの詳細など、すべての情報が含まれています。 詳細については、「データベースのビルドとデプロイの概要」を参照してください。

デプロイ パッケージとデータベース デプロイ マニフェストの作成方法、使用方法については、「Web アプリケーション プロジェクトのビルドとパッケージ化」および「データベース プロジェクトをデプロイする」で詳しく説明します。

PublishDbPackages ターゲット

PublishDbPackages ターゲットでは、簡単にいえば、VSDBCMD ユーティリティを呼び出して ContactManager データベースをターゲット環境にデプロイします。 データベースのデプロイを構成する際には、さまざまな決断や微妙な問題についての検討が必要です。これについては、「データベース プロジェクトをデプロイする」および「複数の環境のためにデータベース デプロイをカスタマイズする」で詳しく説明します。 このトピックでは、このターゲットが機能する実際のしくみについて説明します。

まず、開始タグに Outputs 属性が含まれていることに注目してください。

<Target Name="PublishDbPackages" Outputs="%(DbPublishPackages.Identity)">

これは、"ターゲット バッチ処理" の例です。 MSBuild プロジェクト ファイルにおけるバッチ処理は、コレクションの各要素に対して反復的に処理を実行する手法の 1 つです。 Outputs 属性の値 "%(DbPublishPackages.Identity)" では、DbPublishPackages 項目リストの Identity メタデータ プロパティを参照しています。 この Outputs=%(ItemList.ItemMetadataName) という表記は以下のように解釈されます。

  • DbPublishPackages 内の項目を、同じ Identity メタデータ値を持った項目群のバッチに分けます。
  • 各バッチごとに 1 回ずつターゲットを実行します。

Note

Identity は、すべてのアイテムの作成時に割り当てられる組み込みメタデータ値 の 1 つです。 これは、Item 要素の Include 属性の値、つまり項目のパスとファイル名を参照します。

この例の場合、同じパスとファイル名を持つ項目が複数存在してはならないため、基本的にバッチ サイズは 1 になります。 ターゲットは、データベース パッケージ 1 つにつき 1 回ずつ実行されます。

同様の表記方法は _Cmd プロパティでも、適切なスイッチの指定を含んだ VSDBCMD コマンドを組み立てるために使用されています。

<_Cmd>"$(VsdbCmdExe)" 
   /a:Deploy 
   /cs:"%(DbPublishPackages.DatabaseConnectionString)" 
   /p:TargetDatabase=%(DbPublishPackages.TargetDatabase)             
   /manifest:"%(DbPublishPackages.FullPath)" 
   /script:"$(_CmDbScriptPath)" 
   $(_DbDeployOrScript)
</_Cmd>

この例に含まれる %(DbPublishPackages.DatabaseConnectionString)%(DbPublishPackages.TargetDatabase)、および %(DbPublishPackages.FullPath) は、いずれも DbPublishPackages 項目コレクションのメタデータ値を参照しています。 _Cmd プロパティは、コマンドを呼び出す Exec タスクによって使用されます。

<Exec Command="$(_Cmd)"/>

結果的に、この Exec タスクでは、メタデータ値 DatabaseConnectionStringTargetDatabaseFullPath の一意な組み合わせを含んだ反復のバッチが作成され、各バッチごとに 1 回ずつタスクが実行されます。 つまり、これは "タスクのバッチ処理" の例です。 ただし、この例の項目コレクションはターゲット レベルのバッチ処理によってあらかじめ単一項目のバッチに分割されているため、Exec タスクは、ターゲットの反復ごとに 1 回だけ実行されます。 したがって、このタスクでは、ソリューション内の各データベース パッケージについて VSDBCMD ユーティリティが 1 回ずつ呼び出されることになります。

Note

ターゲットとタスクのバッチ処理の詳細については、「MSBuild バッチ」、「ターゲットのバッチの項目メタデータ」、および「タスクのバッチの項目メタデータ」を参照してください。

PublishWebPackages ターゲット

ここまでの時点で、BuildProjects ターゲットは既に呼び出され、サンプル ソリューション内の各プロジェクトについて Web 配置パッケージが生成されています。 各パッケージには、deploy.cmd ファイル (パッケージをターゲット環境にデプロイするために必要な MSDeploy.exeコマンドを含む) と、SetParameters.xml ファイル (ターゲット環境について必要な詳細情報を指定する) があります。 また、GatherPackagesForPublishing ターゲットが呼び出され、皆様の関心の対象である deploy.cmd ファイルを含んだ項目コレクションが生成されています。 PublishWebPackages ターゲットでは、簡単にいえば以下の機能を実行します。

  • XmlPoke タスクを使用して各パッケージの SetParameters.xml ファイルを操作し、ターゲット環境に応じた正しい詳細情報を含めます。
  • 各パッケージに対し、適切なスイッチを使用して deploy.cmd ファイルを呼び出します。

PublishDbPackages ターゲットの場合と同じく PublishWebPackages ターゲットでも、ターゲット バッチ処理によって、Web パッケージ 1 つにつき 1 回ずつターゲットを実行します。

<Target Name="PublishWebPackages" Outputs="%(PublishPackages.Identity)">

このターゲット内では、各 Web パッケージに対し、Exec タスクを使用して deploy.cmd ファイルを実行しています。

<PropertyGroup>
   <_Cmd>
      %(PublishPackages.FullPath) 
      $(_WhatifSwitch) 
      /M:$(MSDeployComputerName) 
      %(PublishPackages.AdditionalMSDeployParameters)
   </_Cmd>
</PropertyGroup>
<Exec Command="$(_Cmd)"/>

Web パッケージのデプロイを構成する方法の詳細については、「Web アプリケーション プロジェクトのビルドとパッケージ化」を参照してください。

まとめ

このトピックでは、Contact Manager サンプル ソリューションのビルドとデプロイのプロセスを、分割プロジェクト ファイルの手法で最初から最後まで制御する方法について、順を追って説明しました。 このアプローチを使用すると、複雑なエンタープライズ規模のデプロイ作業を、環境に特化したコマンド ファイルを 1 つ実行するという単一の反復可能な手順で実行できます。

もっと読む

プロジェクト ファイルと WPP の詳細については、書籍『Inside the Microsoft Build Engine: Using MSBuild and Team Foundation Build』(Sayed Ibrahim Hashimi、William Bartholomew 共著、ISBN: 978-0-7356-4524-0) を参照してください。