2010-08-19 61 views
9

我一直在研究使用MSDeploy的TFS2010新構建和部署功能。到目前爲止,一切進展順利(儘管很難找到關於特定場景的信息)。TFS2010構建定義以部署到多個服務器?

我可以修改我的構建定義以指定2個或更多的服務器部署到?我需要做的是部署到多個服務器(因爲我有兩個使用NLB的測試環境)。

我現在擁有一個構建定義,它構建,運行我的測試,然後部署到我的一個測試服務器(其上運行有MsDeployAgentService)。它工作正常,並且每個Web項目都按其項目文件中的配置進行部署。我使用的MSBuild的參數是:

* /p:DeployOnBuild=True 
* /p:DeployTarget=MsDeployPublish 
* /p:MSDeployServiceURL=http://oawww.testserver1.com.au/MsDeployAgentService 
* /p:CreatePackageOnPublish=True 
* /p:MsDeployPublishMethod=RemoteAgent 
* /p:AllowUntrustedCertificated=True 
* /p:UserName=myusername 
* /p:Password=mypassword 

注意:我不使用/ P:DeployIISAppPath =「XYZ」因爲它不部署我的所有項目和覆蓋我的項目配置。

我可以添加另一個構建參數讓它調用多個MSDeployServiceURL嗎?像第二個/ p:MSDeployServiceURL參數那樣指定另一個服務器?

還是我必須尋找另一種解決方案,比如編輯WF?

我在2個月前發佈了一個幾乎完全相同的問題:TFS 2010 - Deploy to Multiple Servers After Build,所以它看起來不像我是唯一一個試圖解決這個問題的人。

我也發佈在討論MSDeploy的IIS.NET論壇上:http://forums.iis.net/t/1170741.aspx。它有很多意見,但是再次沒有答案。

回答

7

您不需要兩次構建項目以部署到兩臺服務器。構建過程將構建一組部署文件。然後您可以使用InvokeProcess將其部署到多個服務器。

首先創建一個名爲ProjectName的變量。然後將「分配」活動添加到「編譯項目」序列。這位於「嘗試編譯項目」序列中。下面是分配的屬性:

To: ProjectName 
Value: System.IO.Path.GetFileNameWithoutExtension(localProject) 

這是我們InvokeProcess活動的可部署到測試服務器的性能:

Arguments: "/y /M:<server> /u:<domain>\<user> /p:<password>" 
FileName: String.Format("{0}\{1}.deploy.cmd", BuildDetail.DropLocation, ProjectName) 

You will need to change <server>, <domain>, <user>, and <password> to the values that reflect your environment. 

如果您需要手動部署到服務器可以運行命令以下從您的生成文件夾:

deploy.cmd /y /M:<server> /u:<domain>\<user> /p:<password> 
+0

如果我有機會重做我的實現,這看起來像是正確的做法。這只是一個可惜的是,它並沒有像這樣的東西出來。謝謝! – Arkiliknam 2011-01-05 06:42:40

+0

我已經更新了我們的過程,所以現在這些參數已被參數化。對於MSBuild參數,您還可以指定IIS App Path。如果您需要將多個實例部署到同一臺服務器,則也可以對其進行參數化。 – 37Stars 2011-02-15 21:03:05

0

我是其他類似帖子的作者。我還沒有找到解決方案。我相信它會修改工作流程以添加後處理MSBUILD - 同步任務。這似乎是最優雅的,但仍希望找到一些少一些侵擾性的東西。

+0

我正要走這條路。這裏有一個博客條目:http://blogs.blackmarble.co.uk/blogs/rfennell/archive/2010/08/13/running-msdeploy-to-a-remote-box-from-inside-a-tfs- 2010-build-part-2.aspx涵蓋了如何做到這一點。但最後我又給MSBUILD增加了第二個電話,並重復使用了他們爲我們提供的參數理念(詳見我的答案)。 – Arkiliknam 2010-08-23 07:43:10

6

我找不到我期待的解決方案,但這是我最終想到的。

我想在TFS參數中保持簡單和可配置的解決方案,同時與已經提供的MSBuildArguments方法保持一致,該方法已經提升了很多。所以我創建了一個新的生成模板,並在WorkFlow的Arguments選項卡中添加了一個名爲MSBuildArguments2的新TFS WorkFlow參數。

alt text

我通過工作流BuildTemplate搜索了MSBuildArguments的所有出現(有兩個occurances)。

使用MSBuildArguments的兩個任務被稱爲Run MSBuild for Project。直接低於這個任務,我添加了一個新的「如果」與條件塊:

Not String.IsNullOrEmpty(MSBuildArguments2) 

我再複製「運行的MSBuild項目」任務,並粘貼到新的If的「然後」塊,更新它的標題因此。您還需要更新新的任務的ConmmandLineArguments屬性以使用新的參數。

CommandLineArguments = String.Format("/p:SkipInvalidConfigurations=true {0}", MSBuildArguments2)

這些修改之後,工作流程是這樣的:

alt text

保存並檢查在新的工作流程。更新你的構建定義來使用這個新的WorkFlow,然後在構建定義的Process選項卡中,你會發現一個新的部分叫做Misc,並且可以使用新的參數。因爲我只是使用這個新參數進行部署,所以我複製了我用於MSBuild Arguments的完全相同的參數,並將MSDeployServiceURL更新到了我的第二個部署服務器。

alt text

而且就是這樣。我想一個更優雅的方法是將MSBuildArguments轉換爲一個字符串數組,然後在WorkFlow過程中循環它們。但是這符合我們2臺服務器的要求。

希望這會有所幫助!

2

我的解決方案是一個新的目標,運行後包。每個需要生成包的項目都包含這個目標文件,並且我選擇在外部設置的「DoDeployment」屬性中設置Include條件。此外,每個項目都會定義DeploymentServerGroup屬性,以便根據目標服務器的類型對目標服務器進行適當篩選。

正如你可以看到的底部,我只是簡單地執行與服務器列表的命令文件,非常簡單。

<!-- 
This targets file allows a project to deploy its package 

As it is used by all project typesconditionally included from the project file 

- >

<UsingTask TaskName="Microsoft.TeamFoundation.Build.Tasks.BuildStep" AssemblyFile="$(TeamBuildRefPath)\Microsoft.TeamFoundation.Build.ProcessComponents.dll" /> 

<!-- Each Server needs the Group metadatum, either Webservers, Appservers, or Batch. --> 
<Choose> 
    <When Condition="'$(Configuration)' == 'DEV'"> 
     <ItemGroup> 
      <Servers Include="DevWebServer"> 
       <Group>Webservers</Group> 
      </Servers> 
      <Servers Include="DevAppServer"> 
       <Group>Appservers</Group> 
      </Servers> 
     </ItemGroup> 
    </When> 
    <When Condition="'$(Configuration)' == 'QA'"> 
     <ItemGroup> 
      <Servers Include="QAWebServer1"> 
       <Group>Webservers</Group> 
      </Servers> 
      <Servers Include="QAWebServer2"> 
       <Group>Webservers</Group> 
      </Servers> 
      <Servers Include="QAAppServer1"> 
       <Group>Appservers</Group> 
      </Servers> 
      <Servers Include="QAAppServer2"> 
       <Group>Appservers</Group> 
      </Servers> 
     </ItemGroup> 
    </When> 
</Choose> 

<!-- DoDeploy can be set in the build defintion --> 
<Target Name="StartDeployment" AfterTargets="Package"> 

    <PropertyGroup> 
     <!-- The _PublishedWebsites area --> 
     <PackageLocation>$(WebProjectOutputDir)_Package</PackageLocation> 

     <!-- Override for local testing --> 
     <PackageLocation Condition="$(WebProjectOutputDirInsideProject)">$(IntermediateOutputPath)Package\</PackageLocation> 

    </PropertyGroup> 

    <Message Text="Tier servers are @(Servers)" /> 

    <!-- A filtered list of the servers. DeploymentServerGroup is defined in each project that does deployment --> 
    <ItemGroup> 
     <DestinationServers Include="@(Servers)" Condition="'%(Servers.Group)' == '$(DeploymentServerGroup)'" /> 
    </ItemGroup> 

    <Message Text="Dest servers are @(DestinationServers)" /> 

</Target> 

<!-- Only perform the deployment if any servers fit the filters --> 
<Target Name="PerformDeployment" AfterTargets="StartDeployment" Condition="'@(DestinationServers)' != ''"> 

    <Message Text="Deploying $(AssemblyName) to @(DestinationServers)" /> 

    <!-- Fancy build steps so that they better appear in the build explorer --> 
    <BuildStep 
        TeamFoundationServerUrl="$(TeamFoundationServerUrl)" 
        BuildUri="$(BuildUri)" 
        Message="Deploying $(AssemblyName) to @(DestinationServers)..."> 
     <Output TaskParameter="Id" PropertyName="StepId" /> 
    </BuildStep> 

    <!-- The deployment command will be run for each item in the DestinationServers collection. --> 
    <Exec Command="$(AssemblyName).deploy.cmd /Y /M:%(DestinationServers.Identity)" WorkingDirectory="$(PackageLocation)" /> 

    <BuildStep 
        TeamFoundationServerUrl="$(TeamFoundationServerUrl)" 
        BuildUri="$(BuildUri)" 
        Id="$(StepId)" 
        Status="Succeeded" 
        Message="Deployed $(AssemblyName) to @(DestinationServers)"/> 
    <OnError ExecuteTargets="MarkDeployStepAsFailed" /> 
</Target> 

<Target Name="MarkDeployStepAsFailed"> 
    <BuildStep 
      TeamFoundationServerUrl="$(TeamFoundationServerUrl)" 
      BuildUri="$(BuildUri)" 
      Id="$(StepId)" 
      Status="Failed" /> 
</Target> 

+0

有意思......所以你正在將工作從TFS工作流中提取出來並放回到MSBUILD腳本中。您的解決方案中的每個項目是否在構建後調用此目標?在這裏,我認爲MSBUILD已經死了,並且被埋沒了:) – Arkiliknam 2011-12-13 09:26:27

+0

一旦我寫了MSBuild文件,我開始更喜歡使用笨重且容易出錯的WorkFlow設計器。每個需要部署其包的項目都包含來自其csproj的這個目標文件,並且目標調用是自動的,因爲它是在包目標之後完成的。 – 2011-12-13 19:48:08