2010-08-19 11 views
9

He estado investigando las nuevas funciones de compilación e implementación de TFS2010 con MSDeploy. Hasta ahora todo va bien (aunque ha sido difícil encontrar información sobre escenarios específicos).TFS2010 Definición de compilación para implementar en varios servidores?

¿Puedo modificar mi definición de compilación para especificar 2 o más servidores para implementar? Lo que necesito hacer es implementarlo en varios servidores (ya que tengo dos en mi entorno de prueba que usa un NLB).

Lo que tengo ahora es una definición de compilación que compila, ejecuta mis pruebas y luego se implementa en UNO de mis servidores de prueba (que tiene el MsDeployAgentService ejecutándose en él). Funciona bien, y cada proyecto web se implementa como configurado en su archivo de proyecto. Los argumentos de MSBuild que utilizo son:

* /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: Yo no uso/p: DeployIISAppPath = "xyz", como es imposible desplegar todos mis proyectos y anula mi config proyecto.

¿Puedo agregar otro argumento de compilación para que llame a más de un MSDeployServiceURL? ¿Te gusta algo así como un argumento second/p: MSDeployServiceURL que especifica otro servidor?

¿O tengo que buscar otra solución, como editar el WF?

Vi una pregunta casi exacta aquí publicada hace 2 meses: TFS 2010 - Deploy to Multiple Servers After Build, por lo que no parece que soy el único que intenta resolver esto.

También publiqué en los foros de IIS.NET donde se discute MSDeploy: http://forums.iis.net/t/1170741.aspx. Ha tenido bastantes puntos de vista, pero de nuevo, no hay respuestas.

Respuesta

7

No tiene que crear el proyecto dos veces para implementar en dos servidores. El proceso de compilación construirá un conjunto de archivos de implementación. Luego puede usar InvokeProcess para implementar en varios servidores.

Primero crea una variable llamada ProjectName. A continuación, agregue una actividad Asignar a la secuencia "Compilar el proyecto". Esto se encuentra en la secuencia "Intentar compilar el proyecto". Estas son las propiedades del Asignar:

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

aquí son las propiedades de nuestra actividad InvokeProcess que se despliega al servidor de prueba:

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. 

Si necesita implementar manualmente a un servidor puede ejecutar el comando debajo de su carpeta de compilación:

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

Esto parece lo correcto si tuviera la oportunidad de volver a hacer la implementación. Es una lástima que no salga de la caja con algo como esto. ¡Gracias! – Arkiliknam

+0

He actualizado nuestro proceso, por lo que ahora están parametrizados. Para los argumentos de MSBuild, también puede especificar la ruta de acceso de la aplicación IIS. Esto también se puede parametrizar si necesita implementar varias instancias en el mismo servidor. – 37Stars

0

Soy el autor de la otra publicación similar. Todavía tengo que encontrar una solución. Creo que va a modificar el flujo de trabajo para agregar una tarea de sincronización MSBUILD posterior al procesamiento. Eso parece ser el más elegante, pero aún esperaba encontrar algo menos intrusivo.

+0

Iba a seguir ese camino. Hay una entrada de blog aquí: 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 que cubre cómo hacerlo. Pero al final agregué una segunda llamada a MSBUILD y reutilicé la idea de Arguments que nos proporcionan (como se detalla en mi respuesta). – Arkiliknam

6

No pude encontrar la solución que estaba buscando, pero esto es lo que se me ocurrió al final.

Quería mantener la solución simple y configurable dentro de los argumentos de TFS, al mismo tiempo, mantenerme en línea con el método MSBuildArguments ya proporcionado que se ha promocionado mucho. Así que creé una nueva Plantilla de compilación y agregué un nuevo argumento TFS WorkFlow llamado MSBuildArguments2 en la pestaña Argumentos de WorkFlow.

alt text

he buscado en el BuildTemplate de flujo de trabajo para todas las ocurrencias de la MSBuildArguments (había dos ocurrencias).

Las dos tareas que usan MSBuildArguments se llaman Run MSBuild for Project. Directamente debajo de esta tarea, he añadido un nuevo "Si" bloque con la condición:

Not String.IsNullOrEmpty(MSBuildArguments2) 

que luego se copia la opción "Ejecutar MSBuild para el Proyecto" tarea y lo pegó en el bloque de la nueva Si "Entonces", la actualización de su título en consecuencia. También necesitará actualizar la nueva propiedad ConmmandLineArguments de la Tarea para usar su nuevo Argumento.

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

Después de estas modificaciones, el flujo de trabajo se parece a esto:

alt text

Guardar y hora de llegada del nuevo flujo de trabajo. Actualice su Definición de compilación para usar este nuevo Flujo de trabajo, luego en la pestaña Proceso de la definición de compilación encontrará una nueva sección llamada Varios con el nuevo argumento listo para ser utilizado. Debido a que simplemente estoy usando este nuevo argumento para la implementación, copié exactamente los mismos argumentos que usé para MSBuild Arguments y actualicé MSDeployServiceURL a mi segundo servidor de implementación.

alt text

Y eso es todo. Supongo que un método más elegante sería convertir MSBuildArguments en una matriz de cadenas y luego recorrerlas durante el proceso de WorkFlow. Pero esto se adapta a nuestros 2 requisitos de servidor.

Espero que esto ayude!

2

Mi solución a esto es un nuevo objetivo que se ejecuta después del paquete. Cada proyecto que necesita producir un paquete incluye este archivo de objetivos, y elegí hacer que Include sea condicional en una propiedad "DoDeployment" establecida externamente. Además, cada proyecto define la propiedad DeploymentServerGroup para que los servidores de destino se filtren adecuadamente según el tipo de proyecto que sea.

Como puede ver hacia abajo, simplemente estoy ejecutando el archivo de comandos con la lista de servidores, bastante 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> 

+0

Interesante ... por lo que está retirando el trabajo de TFS Workflow y volviendo a ponerlo en un MSBUILD Script. ¿Cada proyecto en su solución llama a este objetivo después de la compilación? Y aquí pensé que MSBUILD estaba muerto y enterrado :) – Arkiliknam

+0

Una vez que logré escribir archivos de MSBuild, comencé a preferir que utilizaran el diseñador WorkFlow, torpe y propenso a fallas. Cada proyecto que necesita implementar su paquete incluye este archivo de objetivos desde su csproj, y la invocación de destino es automática ya que se realiza después del objetivo del paquete. –

Cuestiones relacionadas