TFS2010 构建定义部署到多个服务器?

发布于 2024-09-14 16:19:15 字数 1141 浏览 8 评论 0原文

我一直在研究 TFS2010 新的构建和 MSDeploy 部署功能。到目前为止,一切进展顺利(尽管很难找到有关特定场景的信息)。

我可以修改构建定义以指定要部署到的 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?

我在两个月前发布了一个几乎完全相同的问题: TFS 2010 -构建后部署到多个服务器,所以看起来我不是唯一一个试图解决这个问题的人。

我还在讨论 MSDeploy 的 IIS.NET 论坛上发帖:http://forums.iis。 net/t/1170741.aspx 。它有很多观点,但同样没有答案。

I've been looking into TFS2010 new build and deployment features with MSDeploy. So far everything is going well (although its been hard to find information about specific scenarios).

Can I modify my Build Definition to specify 2 or more servers to deploy to? What I need to do is deploy to multiple servers (as I have two in my testing environment which uses a NLB).

What I have now is a Build definition which Builds, runs my tests, and then Deploys to ONE of my testing servers (which has the MsDeployAgentService running on it). It works fine, and each web project is deployed as configured in its project file. The MSBuild Arguments I use are:

* /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 

NB: I dont use /p:DeployIISAppPath="xyz" as it doesnt deploy all my projects and overrides my project config.

Can I add another build argument to get it to call more than one MSDeployServiceURL? Like something like a second /p:MSDeployServiceURL argument that specifies another server?

Or do I have to look for another solution, such as editing the WF?

I saw an almost exact same question here posted 2 months ago: TFS 2010 - Deploy to Multiple Servers After Build , so it doesn't look like I'm the only one trying to solve this.

I also posted on the IIS.NET forums where MSDeploy is discussed: http://forums.iis.net/t/1170741.aspx . It's had quite a lot of views, but again, no answers.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

痞味浪人 2024-09-21 16:19:15

您不必构建项目两次即可部署到两台服务器。构建过程将构建一组部署文件。然后,您可以使用 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>

You don't have to build the project twice to deploy to two servers. The build process will build a set of deployment files. You can then use the InvokeProcess to deploy to multiple servers.

First create a variable named ProjectName. Then add an Assign activity to the "Compile the Project" sequence. This is located in the "Try to Compile the Project" sequence. Here are the properties of the Assign:

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

Here are the properties of our InvokeProcess activity that deploys to the test server:

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.

If you need to manually deploy to a server you can run the command below from your build folder:

deploy.cmd /y /M:<server> /u:<domain>\<user> /p:<password>
奢华的一滴泪 2024-09-21 16:19:15

我找不到我正在寻找的解决方案,但这就是我最终想到的。

我希望在 TFS 参数中保持解决方案的简单性和可配置性,同时与已提供的 MSBuildArguments 方法保持一致,该方法已得到广泛推广。因此,我创建了一个新的构建模板,并在工作流的“参数”选项卡中添加了一个名为 MSBuildArguments2 的新 TFS 工作流参数。

alt text

我在 BuildTemplate 工作流程中搜索了所有出现的 MSBuildArguments(出现了两次)。

使用 MSBuildArguments 的两个任务称为运行 MSBuild for Project。在此任务正下方,我添加了一个带有条件的新“If”块:

Not String.IsNullOrEmpty(MSBuildArguments2)

然后复制“Run MSBuild for Project”任务并将其粘贴到新 If 的“Then”块中,相应地更新其标题。您还需要更新新任务的 ConmmandLineArguments 属性以使用新的参数。

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

经过这些修改,工作流程如下所示:

alt text

保存并签入新的工作流程。更新您的构建定义以使用这个新的工作流程,然后在构建定义的“流程”选项卡中,您将找到一个名为“杂项”的新部分,其中包含可供使用的新参数。因为我只是使用这个新参数进行部署,所以我复制了用于 MSBuild Arguments 的完全相同的参数,并将 MSDeployServiceURL 更新到我的第二个部署服务器。

alt text

就是这样。我认为更优雅的方法是将 MSBuildArguments 转换为字符串数组,然后在工作流程过程中循环遍历它们。但这适合我们 2 个服务器的要求。

希望这有帮助!

I couldn't find the solution I was looking for, but here's what I came up with in the end.

I wanted to keep the solution simple and configurable within the TFS arguments while at the same time staying in line with the already provided MSBuildArguments method which has been promoted a lot. So I created a new Build Template, and added a new TFS WorkFlow Argument called MSBuildArguments2 in the Arguments tab of the WorkFlow.

alt text

I searched through the BuildTemplate WorkFlow for all occurances of the MSBuildArguments (there were two occurances).

The two tasks that use MSBuildArguments are called Run MSBuild for Project. Directly below this task, I added a new "If" block with the condition:

Not String.IsNullOrEmpty(MSBuildArguments2)

I then copied the "Run MSBuild for Project" task and pasted it into the new If's "Then" block, updating its title accordingly. You'll also need to update the new Task's ConmmandLineArguments property to use your new Argument.

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

After these modifications, the WorkFlow looks like this:

alt text

Save and Check In the new WorkFlow. Update your Build Definition to use this new WorkFlow, then in the build definition's Process tab you will find a new section called Misc with the new argument ready to be used. Because I'm simply using this new argument for deployment, I copied the exact same arguments I used for MSBuild Arguments and updated the MSDeployServiceURL to my second deployment server.

alt text

And that's that. I suppose a more elegant method would be to convert MSBuildArguments into an array of strings and then loop through them during the WorkFlow process. But this suits our 2 server requirements.

Hope this helps!

秋风の叶未落 2024-09-21 16:19:15

我的解决方案是在 Package 之后运行一个新的 Target。每个需要生成包的项目都包含此目标文件,并且我选择使“包含”以外部设置的“DoDeployment”属性为条件。此外,每个项目都定义 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>

My solution to this is a new Target that runs after Package. Each project that needs to produce a package includes this targets file, and I chose to make the Include conditional on an externally-set "DoDeployment" property. Additionally each project defines the DeploymentServerGroup property so that the destination server(s) are properly filtered depending on what kind of project it is.

As you can see towards the bottom I'm simply executing the command file with the server list, pretty simple.

<!-- 
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>

杯别 2024-09-21 16:19:15

我是另一篇类似文章的作者。我还没有找到解决办法。我相信它将修改工作流程以添加后处理 MSBUILD 同步任务。这似乎是最优雅的,但仍然希望找到一些不那么打扰的东西。

I am the author of the other similar post. I have yet to find a solution. I believe it is going to be modifying the workflow to add a postprocessing MSBUILD -sync task. That seems to be the most elegant, but was still hoping to find something a bit less intrusive.

小傻瓜 2024-09-21 16:19:15

我不确定这是否可以帮助您使用 TFS 2010,但我有一篇关于 TFS 2012 的博客文章:将多个 Web 项目从 TFS 2012 部署到支持 NLB 的环境

I'm not sure if that could help you with TFS 2010, but I have a blog post for TFS 2012: Multiple web projects deployment from TFS 2012 to NLB enabled environment.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文