Aspnetcore: IIS -> Bloquear archivo DLL de la aplicación .NET Core

Creado en 7 jul. 2016  ·  114Comentarios  ·  Fuente: dotnet/aspnetcore

Cuando trato de sobrescribir el archivo DLL de la aplicación .NET Core usando FTP en el archivo del servidor IIS de producción está bloqueado y no se puede sobrescribir.

Para implementar la nueva versión, necesito detener la aplicación en IIS para liberar el bloqueo y luego sobrescribir.
No es posible implementar sin detener la aplicación.

affected-medium area-servers bug servers-iis severity-nice-to-have

Comentario más útil

👍

No apoyar el reciclaje superpuesto es una regresión.

Todos 114 comentarios

Consulte app_offline.htm: https://docs.asp.net/en/latest/hosting/aspnet-core-module.html#asp -net-core-module-app-offline-htm

Si termina deseando una forma de PowerShell de hacerlo, puede usar los cmdlets de administración de IIS: https://technet.microsoft.com/en-us/library/ee790599.aspx

Stop-WebAppPool -Name $appPoolName

... deploy ...

Start-WebAppPool -Name $appPoolName

Gracias por la explicación @Tratcher .
No estoy seguro de si esto está en sus planes, pero creo que funcionó para ASP.NET MVC anterior.
¿Planea implementar esta función o no?

@GuardRex No puedo hacerlo porque es un entorno de alojamiento compartido y no tengo permiso para detener AppPool

¿Puede "simplemente funcionar" con msdeploy.exe y Azure? Si entiendo correctamente, el sitio web debe reiniciarse para evitar el bloqueo de archivos. -enableRule:AppOffline funciona, pero todo el sitio web está fuera de línea durante unos minutos, lo que no es una gran experiencia para el usuario, especialmente dado que implementamos pocas veces al día.

Véase también http://stackoverflow.com/q/40276582/14131

@chuchuva tal vez, pero toda la magia tiene un costo. Las versiones anteriores de ASP.NET hacían algunas instantáneas complicadas para solucionar los problemas de bloqueo de archivos.

Magia o no, funcionó bien. Lo extraño un poco ahora después de la migración al núcleo ASP.NET ...

De acuerdo con @HarelM. Hemos tenido problemas con esto desde nuestras implementaciones automatizadas hasta la experiencia del usuario final. Hemos pasado de implementar unas 10 veces al día con el antiguo MVC a tal vez una implementación diaria por la noche y aceptar que las personas que usan la aplicación Core se molestarán cuando la desconectemos. Si bien no es un obstáculo, se agrega fricción hacia la adopción de Core.

👍

No apoyar el reciclaje superpuesto es una regresión.

¿Hay planes para volver a visitar esta función y ponerla en la hoja de ruta? Es muy inconveniente / antipático exigir que todos los que implementen un sitio web .Net Core implementen manualmente una estrategia de ranuras de ensayo si desean admitir implementaciones sin tiempo de inactividad.

Tener esta función facilitaría mucho la transición a los sitios web .Net Core para muchas personas y permitiría una adopción más rápida de los sitios web .Net Core.

Nos gustaría saberlo también. Poner un archivo app_offline.htm dentro del directorio de aplicaciones no funciona.

Me acabo de dar cuenta de esta 'característica' después de mover varios sitios a AspNetCore. ¡No puedo creer que se considere aceptable desconectar sus sitios durante unos minutos cada vez que quiera publicar!

Esto ya es suficientemente malo para mí como líder de un equipo pequeño. ¿Quienes practican la integración continua a gran escala están evitando AspNetCore? ¡No hay forma de que puedan tener su sitio fuera de línea durante minutos cada hora para volver a publicarlo!

¿Está implementando el uso de FTP o xcopying? ¿O estás usando webdeploy?

Estoy publicando a través de webdeploy en IIS.

Actualmente estamos solucionando este problema eliminando primero web.config (matando efectivamente la aplicación), pero esta no es realmente una solución aceptable a largo plazo.

@DaleMckeown, idealmente con un flujo de trabajo de integración continua, tendría varios servidores detrás de un equilibrador de carga. Luego, extraería un servidor, lo actualizaría, lo volvería a colocar y pasaría al siguiente. Por supuesto, esto no siempre es posible (como en nuestro caso), por lo que tendrá que vivir con unos minutos de inactividad. En nuestro caso, la aplicación se recupera en 30 segundos, por lo que esto no es realmente un problema.

@DaleMckeown

Estoy publicando a través de webdeploy en IIS.

Hay algunas opciones que se pueden utilizar para que la implementación mediante webdeploy funcione bien (admite el cambio de nombre de los archivos bloqueados y la desconexión automática de la aplicación). ¿Es ese el caso por defecto @shirhatti ?

@ajeckmans

Actualmente estamos solucionando este problema eliminando primero web.config (matando efectivamente la aplicación), pero esta no es realmente una solución aceptable a largo plazo.

¿Eso significa que estás haciendo una implementación de xcopy?

Hay algunas opciones que se pueden utilizar para que la implementación mediante webdeploy funcione bien (admite el cambio de nombre de los archivos bloqueados y la desconexión automática de la aplicación). ¿Es ese el caso por defecto @shirhatti ?

Gracias David, suena mejor que lo que estoy haciendo actualmente (detener manualmente el sitio y el grupo de aplicaciones en IIS). ¿Puede señalar algunos recursos para que pueda investigar las implicaciones de estos enfoques?

@DaleMckeown algo de información hasta que encuentre la fuente de la verdad https://github.com/Microsoft/vsts-tasks/issues/5259#issuecomment -346202503

@davidfowl Estamos usando webdeploy para implementar en nuestro servidor de pruebas (que por cierto nunca nos da problemas), desde allí copiamos los archivos a nuestros servidores en vivo usando robocopy

@ajeckmans

Actualmente estamos solucionando este problema eliminando primero web.config

Cuando se elimina web.config de la implementación, IIS entregará archivos confidenciales de la implementación. Un atacante podría simplemente solicitar archivos continuamente día y noche hasta que se abra la ventana de los 30.

@DaleMckeown

Siguiendo el consejo de @ajeckmans, si alguna vez quieres meterte un poco en la maleza con un enfoque de PS para hacerlo, puedes programar el proceso para soltar AppPools de uno en uno para su implementación en una granja web. Para ver un ejemplo de cómo se puede hacer eso, consulte https://github.com/guardrex/aspnetcore-iis-ps-publish ... pero mírelo como un ejemplo experimental y no como un script de calidad de producción. No he jugado con eso por un tiempo, pero debería (en teoría) seguir funcionando.

@guardrex tienes razón. Primero copiamos un app_offline.htm al directorio, luego volvemos a vivir el web.config, copiamos la aplicación, volvemos a colocar el web.config y eliminamos el app_offline (todo con un script ofc). Desafortunadamente, el simple hecho de colocar el archivo app_offline en el directorio de sitios web no rompe el bloqueo de las DLL. Necesitamos eliminar web.config, una acción que no necesitamos hacer para las aplicaciones completas de asp.net antiguas (como formularios web antiguos, etc.)

@ajeckmans Eso no debería funcionar. Cuando se elimina el archivo web.config , IIS recoge ese cambio de inmediato, por lo que debe enviar las solicitudes predeterminadas al módulo de archivos estáticos y comenzar a entregar archivos. Pruébelo y vea si eso es lo que sucede ...

  1. Agregue app_offline.htm .
  2. Confirme que el sitio publica app_offline.htm .
  3. Extraiga web.config .
  4. Solicite un archivo sensible (por ejemplo, http://localhost:<PORT>/<ASSEMBLY_NAME>.deps.json ... sustituyendo el PORT y ASSEMBLY_NAME).
  5. Debería obtener el archivo deps.json si su módulo de archivo estático funciona correctamente.

No confiaría simplemente en eliminar el módulo con ...

<configuration> 
 <system.webServer> 
   <modules> 
     <remove name="StaticFileModule" /> 
   </modules> 
 </system.webServer> 
</configuration>

... ya que otros módulos permanecerían y posiblemente presentarían otros vectores de ataque. Quizás uno podría eliminar todos los módulos no esenciales, pero nos estamos metiendo en aguas desconocidas con un movimiento como ese solo para cubrir una implementación mediante la eliminación de web.config . Esa nunca ha sido una opción bajo la guía oficial, por lo que no está respaldada por completo. Recomiendo las secuencias de comandos de PS, por ejemplo, para eliminar AppPool, o alguna otra estrategia.

Supongo que debería agregar una nota de simpatía a eso ... levantó algunas cejas desde una perspectiva de seguridad. Cuando se realizó ese cambio en el diseño de la implementación, se discutió, incluido volver a colocar el archivo en wwwroot , consulte ...

Discusión para: Publicar para cambios de IIS en la ubicación web.config (IISIntegration 158)
Verifique si mueve web.config nuevo a wwwroot (IISIntegration 164)

[EDITAR] Quizás esa sea su solución alternativa (no admitida): mueva web.config de nuevo a wwwroot , luego continúe con lo que está haciendo. Aún así, ... da miedo romper la aplicación para desconectarla de esa manera.

Esto me deja aún más confundido sobre lo que deberíamos estar haciendo en esta situación.

¿Cuál es la recomendación actual para publicar sitios AspNetCore en IIS a través de la implementación web de una manera que pueda evitar bloqueos de archivos?

Me gustaría saber también. Esto se está convirtiendo en un obstáculo importante para la adopción del núcleo de .net en mi organización.

Cuando mi aplicación web .net core se está ejecutando y estoy tratando de publicar una nueva compilación, me da un error de que las DLL están en uso. Así que tengo que detener el grupo de aplicaciones, luego actualizar las DLL e iniciar el grupo de aplicaciones.

¿Existe alguna solución alternativa en .Net Core mediante la cual pueda publicar la nueva compilación / DLL sin detener el grupo de aplicaciones?

Esto se admite de forma predeterminada en .Net framework mediante el mecanismo de instantáneas. Desafortunadamente, han pasado 2 años desde el lanzamiento de .Net core y parece que todavía no hay soporte para una funcionalidad tan básica y requerida. ¿Hay planes para solucionar esto en el futuro?

Gracias de antemano por cualquier ayuda.

@guardrex , de hecho, da miedo romper la aplicación para que IIS (o lo que sea que esté bloqueando) libere los dll, sin embargo, es aún más aterrador no poder enviar revisiones a un producto. Por el momento, romper la aplicación es lo único que podemos hacer, pero estamos investigando otros enfoques más modernos para manejar esto :)

@ shahjay748 no contengas la respiración. Si tuviera que rehacer el proceso aquí, pondría la aplicación dentro de un contenedor y simplemente colocaría un nuevo contenedor y cambiaría el tráfico y bajaría la versión anterior (o algo así). Parece que lo más sensato que se puede hacer y, dado que .net core tiene que ver con nuevas formas modernas, solo lanzar una nueva versión de la aplicación simplemente copiando los nuevos archivos se considera (y estoy de acuerdo) un poco arcano. para hacerlo.
Lo cual no nos ayuda a nosotros que, por el momento, estamos estancados con procesos antiguos :)

Lo que hago (no estoy seguro de si es una forma adecuada de hacerlo) es cargar el sitio en otro directorio y cambiar de ruta en iis

Hicimos una investigación interna sobre este tema. Por lo que puedo decir, ANCM no contiene ningún archivo / identificador en la aplicación implementada. Parece ser un problema con webdeploy en sí mismo, y falla flacantemente la implementación. Nunca tuve fallas consistentes en implementar la aplicación después de volver a intentarlo varias veces una vez que se eliminó app_offline.

Agregando una nota al margen rápida de PowerShell a eso: el bloqueo en el ensamblaje de la aplicación siempre se libera ... Nunca he tenido un problema ( ¡todavía! Lol).

@ bpetersen1 ... Su enfoque de "puesta en escena" tiene el dulce efecto secundario de ofrecer una opción de reversión rápida si la nueva implementación fracasa. Eso debería ser fácil de escribir si es necesario.

Esto sigue siendo molesto desde el punto de vista externo ... hemos decidido buscar una solución de Docker para dejar atrás IIS.

Voy a experimentar con una solución. Manténganse al tanto.

También tengo este problema al usar FTP.

¿Cuál es el consejo de Microsoft al respecto?

También tengo este problema al usar FTP.

¿Cuál es el consejo de Microsoft al respecto?

Suelta un archivo appoffline.htm, luego ftp y luego elimínalo.

@davidfowl Sí, eso es lo que estoy haciendo ahora mismo con un archivo por lotes. IIS tarda unos segundos en liberar el bloqueo y luego copiar los archivos.

Gracias, por interés, ¿cómo está ejecutando el archivo por lotes?

También se agradece un enlace a la documentación de MIcrosoft sobre esto; No puedo encontrarlo en google. Gracias.

@ niico100 Básicamente, el archivo por lotes simplemente copia los archivos al directorio del proyecto, y primero hago una carpeta de respaldo antes de hacerlo. Antes de copiar los archivos, coloque appoffline.htm en la carpeta del proyecto.
Debido al problema de bloqueo del archivo, la copia se reintentará. Estoy usando robcopy
https://docs.microsoft.com/en-us/windows-server/administration/windows-commands/robocopy

Si alguien está interesado, el siguiente script descarga el archivo de implementación de appveyor, detiene el sitio, copia los archivos requeridos y vuelve a activar el sitio:
https://github.com/IsraelHikingMap/Site/blob/master/Scripts/Deploy.ps1
Sin embargo, es necesario ejecutarlo como administrador. con suerte Docker resolverá todo este sinsentido una vez que migremos ...
utiliza los comandos Stop-WebAppPool y Start-WebAppPool powershell.

Para el desarrollo local, WebDeploy no funcionó para mí. Intenté usarlo contra mi IIS local y todavía se quejaba de archivos bloqueados. Luego intenté usar los commandlets de powershell anteriores de los eventos de compilación VS Pre / Post, pero eso tampoco funcionó para mí, probablemente porque los powershell de 32 bits no pueden modificar la configuración de IIS de 64 bits. De todos modos, lo que parece funcionar bien son los siguientes eventos pre / post compilación en mi proyecto ASP.Net Core:

Evento previo a la construcción:
echo "App Offline" /a > $(ProjectDir)app_offline.htm

Evento posterior a la construcción:
del $(ProjectDir)app_offline.htm

Revisé brevemente las quejas aquí, y parece que esto puede estar relacionado. Moví las implementaciones de CI desde la implementación de pulpo, que generalmente "simplemente funcionó", a la utilización de versiones de devops azure con las tareas de administración de iis, y todavía tengo problemas para implementar nuevos archivos porque incluso después de detener la aplicación web, detener el dominio de la aplicación, los archivos todavía están en utilizar.

Probablemente se trate de al menos 1 de cada 3 implementaciones y no se ha encontrado nada que parezca mejorar la situación o que las implementaciones sean más confiables.

@Tratcher @ronnyek Esto parece estar relacionado con Application Insights; después de agregar la extensión de App Insights, la DLL de mi aplicación web es repentinamente muy difícil de actualizar, sin problemas antes de eso.

Esto tendría sentido dado que App Insights tiene que conectar el generador de perfiles al proceso de la aplicación y a las DLL.

Todavía me enfrento a este problema. Utilizo la bandera -e nableRule: AppOffline , a veces funciona bien, pero la mayoría de las veces la implementación falla y muestra "ERROR_FILE_IN_USE".

Después de iniciar una versión, superviso la carpeta de la aplicación web y veo el archivo App_Offline.html eliminado por msdeploy. A continuación, el lanzamiento falló con el mensaje anterior y observe que el archivo App_Offline todavía está en la carpeta, comienzo el lanzamiento nuevamente, esta vez está funcionando bien ya que el módulo ve el archivo en la carpeta.

último tiempo de ejecución del núcleo de asp.net instalado -> aspnetcore.dll 12.1.18263.2

Algunas ideas ? ¿Sigue siendo un error?

@dhtek Si intenta reemplazar los archivos inmediatamente después de colocar app_offline.htm , entonces el servidor simplemente no tuvo tiempo suficiente para cerrar la aplicación. Debe esperar un poco antes de intentar reemplazar los archivos.

Ok, lo entiendo, pero estoy usando la opción -e

También sigo viendo este problema. Los archivos de mi proyecto hacen referencia a Microsoft.NET.Sdk.Web , pero no suelta un archivo app_offline.htm automáticamente, como se indica en los documentos.

Hola chicos. Este problema molesto todavía está presente con Core 2.1 con el último VS 2017. Yo uso appoffline, aún así, el dll del proyecto principal siempre está en uso y requiere una parada completa del sitio web durante la publicación. Esto hace que la implementación web sea casi inútil.

Si no puede desconectar su host detrás del equilibrador de carga y desea hacerlo más rápido, aquí hay una forma con enlaces simbólicos y algo de PowerShell.
Estaba pensando en hacer algo como esto.

Es más rápido, ya que no tiene que detener el grupo de aplicaciones durante la copia y el reciclaje es mejor que una parada completa, ya que permite completar las solicitudes actuales, por lo que se reduce el tiempo de inactividad.

# Setup
Import-Module WebAdministration
# create 2 site root directories
$a = 'C:\inetpub\AspNetCoreSampleA'
$b = 'C:\inetpub\AspNetCoreSampleB'
$siteRoot = 'C:\inetpub\aspnetcoresample'
$siteName = 'AspNetCoreSample'
$poolName = "aspnetcore"
New-Item -Type Directory $a
New-Item -Type Directory $b
# create a symlink to targeting one side
New-Item -Type SymbolicLink -Path $siteRoot -Target $a
# point the site root to the symlink
Set-ItemProperty "IIS:\Sites\$siteName" -name physicalPath -value $siteRoot
# make sure it get's picked up
Restart-WebAppPool -Name $poolName

# this tells you the active side
Get-Item -Path $siteRoot | Select-Object -ExpandProperty target

# Flip the symlink
$current = (Get-Item -Path $siteRoot).Target
$newTarget = if ($current -eq $a) {$b} else {$a}
New-Item -Type SymbolicLink -Path $siteRoot -Target $newTarget -Force
# at this point w3wp.exe still locks the current target folder until it's getting recycled
# Deploy new version to the symlink which is now pointing to the other side which should have no locks
robocopy \\myshare\myapp $siteRoot /mir
# recycle app pool, so it picks up the new files
Restart-WebAppPool -Name $poolName

# bonus point: rollback is easy
$current = (Get-Item -Path $siteRoot).Target
$newTarget = if ($current -eq $a) {$b} else {$a}
New-Item -Type SymbolicLink -Path $siteRoot -Target $newTarget -Force
Restart-WebAppPool -Name $poolName

Aquí está la esencia
https://gist.github.com/csharmath/b2af0f50700ce9fbdd8c5c3e582fd41b

Restart-WebAppPool es básicamente reciclaje, lo cual es útil si tiene habilitado el reciclaje superpuesto (el valor predeterminado), ya que generará un nuevo w3wp.exe y todas las solicitudes nuevas serán atendidas por ese nuevo proceso, mientras que las que se están ejecutando actualmente se completarán. por el antiguo w3wp.exe.
De esta manera, se superponen hasta que lo anterior termina con las solicitudes, luego termina con un solo w3wp.exe apuntando a la nueva versión y no hay problema de bloqueo.

Esto es algo similar a la copia instantánea, pero no al 100%, ya que proporciona un escenario xcopy mucho más agradable y fluido.

Hasta ahora, parece ser el mejor enfoque en el que puedo pensar si necesita permanecer en línea durante un lanzamiento.

@csharmath o también hay

Claro, eso es incluso mejor, por supuesto. suspiro, no todos los lugares tienen eso todavía.
Para el resto de las configuraciones de la vieja escuela, debe afeitarlo hasta que funcione para usted con un tiempo de inactividad mínimo o nulo.

@csharmath De acuerdo, pero en este punto, dado que este ha sido un problema sin resolver durante _ años_, también podría adaptarse e ir tras soluciones que funcionen en lugar de esperar un milagro ...

He usado el siguiente script de Power Shell y se bloqueó el IIS e incluso afectó al otro grupo de aplicaciones y tengo que reiniciar la máquina para recuperar todo ... este proceso lo obtuve del documento oficial y fue un desastre, así que mi consejo es NO UTILICE la aplicación_offline.htm mejor para usar el script que detiene el grupo de aplicaciones y lo inicia de nuevo, uno que encontré en este hilo https://github.com/IsraelHikingMap/Site/blob/master/Scripts/Deploy .ps1

$pathToApp = 'G:\prod_web_core'
$pathToAppOfflineHtml = 'G:\prod_web_core\app_offline.htm'
# Stop the AppPool 
New-Item -Path $pathToApp -Name app_offline.htm
# Provide script commands here to deploy the app
Copy-Item "G:\prod_web_core_temp\*" -Destination $pathToApp -Recurse -Force
# Restart the AppPool 
Remove-Item -Path $pathToAppOfflineHtml
Get-ChildItem -Path "G:\prod_web_core_temp" -Recurse | Remove-Item -Force

Me veo obligado a detener AppPool para una implementación exitosa, ¿hay algún progreso para solucionar este problema?

Acabamos de encontrar este problema de bloqueo de archivos por primera vez hoy desde que dotnet core es nuevo para nosotros. Esto realmente me tomó por sorpresa. Es curioso que la razón número 1 por la que cambié de ASP clásico a .Net Framework mientras todavía estaba en beta (~ 2001) es porque podía hacer implementaciones en caliente sin bloqueo de archivos. ¡Fue asombroso! Casi 18 años después y ahora estoy de vuelta donde comencé. Bueno, a veces ganas, a veces pierdes.

Acabo de hacer referencia a mi problema ... en mi caso, la implementación de soluciones Blazor Server Side ...
Hace un par de días fue una pesadilla ... apliqué el archivo app_offline.htm, cerré los grupos de aplicaciones e incluso reinicié instancias completas de IIS para desbloquear archivos. El siguiente paso habría sido reiniciar todo el servidor, afortunadamente después de 5 minutos los .dlls se desbloquearon solos.

2019, el mismo problema para mí ... y este problema se creó en 2016 ... ¿todavía no hay solución?

2020, mismo problema para mí. La mayor regresión de la historia. .Net 4.6 reemplaza los archivos dll y la aplicación se vuelve a cargar en la nueva versión. .Net core bloquea todo.

@bladefist Tu mejor

@kanadaj gracias, pero Dockers es otro nivel de dolores de cabeza con los que lidiar. Finalmente descubrí una solución que consistía en usar App_offline.htm y luego esperar un minuto y esperar que los archivos estuvieran libres. El 99% de las veces, solo tienes que esperar, supongo que mi aplicación tarda un poco en apagarse.

Atrás quedaron los días de .net 4.6 en los que simplemente copiaba sus dlls y su aplicación se reciclaba automáticamente. Supongo que fue demasiado simple. Lo que es doblemente frustrante es que esto no es un problema en Linux. Puede reemplazar archivos en uso en Linux.

Bueno, sí, supongo, pero ese método no es muy sencillo en un entorno de producción. Sin HA, su aplicación terminará sin responder durante un minuto, y con HA obtendrá algunas solicitudes incorrectas aleatorias hasta que el equilibrador de carga descubra que la aplicación está inactiva ... A menos que realice un ciclo manual de los hosts en su equilibrador de carga. Pero eso suena como un problema aún mayor de configurar.

@kanadaj sí, usamos un balanceador de carga y actualiza linealmente los servidores. Sin tiempo de inactividad.

Hemos tenido éxito con

  • Uso de un enlace simbólico para el directorio de la aplicación
  • Implementar una nueva versión del sitio en un directorio diferente
  • Actualizar el enlace simbólico
  • Reinicie el grupo de aplicaciones usando la utilidad appcmd que viene con IIS.

@davidglassborow esa es una solución creativa. Gracias. Sin embargo, las soluciones creativas no deberían ser necesarias.

En mi experiencia, el mecanismo anterior no era confiable cuando el sitio estaba bajo carga de todos modos, terminamos colocando proxies inversos de todos modos para sitios de alto tráfico.

Correcto, las implementaciones en el lugar nunca fueron confiables o atómicas, sin embargo, si tenía suerte o no tenía mucho tráfico, estaría bien. Supongo que la mayoría de las quejas se refieren a esos escenarios. Buscaremos mejorar las cosas en el marco de tiempo de .NET 5.0. Algunas advertencias:

  • Buscaremos mejorar las cosas para las aplicaciones que dependen del marco. Si implementa un sistema autónomo, no tendrá suerte. Bloqueará los archivos nativos y administrados en la carpeta de salida. El problema de bloqueo de las DLL nativas siempre ha existido y no se solucionará con ninguna mitigación que implementemos.
  • Planeamos buscar la carga de ensamblajes de aplicaciones en la memoria como bytes en lugar de cargarlos desde el disco y bloquear el archivo. Esto debería estar bien en la mayoría de los casos, pero puede resultar en un mayor uso de memoria en algunos casos.
  • Para reciclar la aplicación, aún debe agregar y eliminar un archivo de aplicación sin conexión. Agregar el archivo appoffline es una forma de indicar que desea que la aplicación se reinicie como resultado de la implementación.

@davidfowl El plan que delineó para 5.0 suena muy bien. Usamos el marco dependiente como estoy seguro de que la mayoría lo hace.

No estoy de acuerdo respetuosamente sobre la confiabilidad de las implementaciones in situ. Lo he estado haciendo durante años en sitios con una carga extremadamente alta, nunca tuve un problema, ni una sola vez. El primer cambio detectado hace que la aplicación se reinicie, el equilibrador de carga ve que la instancia no responde, la desconecta, una vez que se reemplazan todas las DLL, el equilibrador de carga completa una verificación de estado y vuelve a estar en línea. Ahora bien, si no hubo una verificación de estado del balanceador de carga, entonces sí, es una apuesta, pero quiero decir, ¿quién está reemplazando los archivos DLL en producción con una carga alta sin un proxy de algún tipo? Centrémonos en la regla y no en la excepción. Sin un proxy, no puedo pensar en ninguna forma de actualizar la aplicación sin causar una interrupción. Incluso si admitiera la recarga en caliente, es probable que algunas solicitudes se bloqueen o fallen.

No estoy de acuerdo respetuosamente sobre la confiabilidad de las implementaciones in situ. Lo he estado haciendo durante años en sitios con una carga extremadamente alta, nunca tuve un problema, ni una sola vez. El primer cambio detectado hace que la aplicación se reinicie, el equilibrador de carga ve que la instancia no responde, la desconecta, una vez que se reemplazan todas las DLL, el equilibrador de carga completa una verificación de estado y vuelve a estar en línea. Ahora bien, si no hubo una verificación de estado del balanceador de carga, entonces sí, es una apuesta, pero quiero decir, ¿quién está reemplazando los archivos DLL en producción con una carga alta sin un proxy de algún tipo? Centrémonos en la regla y no en la excepción. Sin un proxy, no puedo pensar en ninguna forma de actualizar la aplicación sin causar una interrupción. Incluso si admitiera la recarga en caliente, es probable que algunas solicitudes se bloqueen o fallen.

Tienes un equilibrador de carga. Mucha gente no tiene un equilibrador de carga y solo está reemplazando archivos en el disco en su lugar y esperando magia 😄

@davidfowl Correcto pero alto tráfico + no lb = imprudente

Además, el problema con app_offline.htm es que desde un proceso ci / cd no tienes idea de cuándo se detiene el proceso. Tuvimos que agregar un comando de suspensión enorme entre la creación de ese archivo y el envío de las DLL porque nuestro proceso de apagado puede demorar entre 1 segundo y 1 minuto. Cuando equilibra la carga de toneladas de instancias, esas interrupciones se suman a un ciclo de implementación muy largo.

Sin embargo, cargar los archivos en la memoria soluciona todo eso.

@davidfowl Correcto pero alto tráfico + no lb = imprudente

👍

Además, el problema con app_offline.htm es que desde un proceso ci / cd no tienes idea de cuándo se detiene el proceso. Tuvimos que agregar un comando de suspensión enorme entre la creación de ese archivo y el envío de las DLL porque nuestro proceso de apagado puede demorar entre 1 segundo y 1 minuto. Cuando equilibra la carga de toneladas de instancias, esas interrupciones se suman a un ciclo de implementación muy largo.

Bien, entonces el problema es que soltar ese archivo no le dice cuándo está bien comenzar la implementación, ya que los archivos todavía están bloqueados hasta que ANCM reciba la notificación.

Además, el problema con app_offline.htm es que desde un proceso ci / cd no tienes idea de cuándo se detiene el proceso.

Correcto, el editor de VS usa suspensiones cortas y varios reintentos.

  • Para reciclar la aplicación, aún debe agregar y eliminar un archivo de aplicación sin conexión. Agregar el archivo appoffline es una forma de indicar que desea que la aplicación se reinicie como resultado de la implementación.

¿Sería posible tener un archivo "apprestart" para marcar la aplicación para ser reciclada sin tener que eliminar el archivo appoffline después?

@Socolin ¿

@Socolin ¿

Si lo entiendo bien (dígame si me equivoco), ¿lo que planea es eliminar el bloqueo, pero aún tendremos que crear una aplicación fuera de línea para indicar a IIS que recicle la aplicación después de que se complete la compilación?

Para hacerlo, tendremos que crear el archivo appoffline y luego eliminarlo. ¿Se puede eliminar este archivo inmediatamente después de su creación? ¿O deberíamos esperar a que IIS lo detecte? Si es necesario esperar un poco, preferiría tener un archivo como "apprestart" que IIS escuchará, luego eliminarlo una vez que lo detecte y comenzar a reciclar.


Además, tengo otra pregunta en mente. Se trata de la optimización de IDE durante la compilación.

Actualmente, trabajo en un proyecto que usa dependencias, tenemos un proyecto para la capa web y otro proyecto para Logic and Data. Cuando trabajo en la capa web (ASP.NET Core) durante la compilación, creo un archivo de aplicación sin conexión antes de la compilación, luego lo elimino después de la compilación y funciona.

Pero cuando trabajo en una de las dependencias, cuando las construyo desde Rider (creo que está haciendo lo mismo en VS ya que usa msbuild) cuando miro lo que está haciendo msbuild, una vez que la construcción del proyecto está completa dll se copia directamente en el directorio .Web / bin sin reconstruir el proyecto .Web. Y dado que el dll está bloqueado, falla silenciosamente y tengo que reiniciar manualmente el servidor o activar manualmente la compilación del proyecto .Web.

¿Tienes alguna solución para esto?
Hasta ahora, la solución que he encontrado es escribir un pequeño programa que se ejecute en segundo plano y que busque el / bin de mi proyecto .Web. Cuando un archivo cambia, crea un archivo appoffline en el directorio donde escucha IIS, luego copia los archivos modificados y luego elimina la appoffline. Pero se siente un poco extraño, pero hasta ahora es la única forma que he encontrado para poder construir, luego presione F5 y pruebe mis cambios.

Para hacerlo, tendremos que crear el archivo appoffline y luego eliminarlo. ¿Se puede eliminar este archivo inmediatamente después de su creación? ¿O deberíamos esperar a que IIS lo detecte? Si es necesario esperar un poco, preferiría tener un archivo como "apprestart" que IIS escuchará, luego eliminarlo una vez que lo detecte y comenzar a reciclar.

¿Cómo sabría IIS cuando terminó de copiar archivos? ¿Cómo evitas el estado desgarrado? Básicamente, necesita señalar el inicio y la finalización de una transacción. La creación del archivo señala el inicio y la eliminación señala el final.

¿Tienes alguna solución para esto?
Hasta ahora, la solución que he encontrado es escribir un pequeño programa que se ejecute en segundo plano y que busque el / bin de mi proyecto .Web. Cuando un archivo cambia, crea un archivo appoffline en el directorio donde escucha IIS, luego copia los archivos modificados y luego elimina la appoffline. Pero se siente un poco extraño, pero hasta ahora es la única forma que he encontrado para poder construir, luego presione F5 y pruebe mis cambios.

VS maneja esto matando el proceso antes de iniciar un nuevo archivo para cualquier cosa que pueda afectar la construcción de ese proyecto.

Para hacerlo, tendremos que crear el archivo appoffline y luego eliminarlo. ¿Se puede eliminar este archivo inmediatamente después de su creación? ¿O deberíamos esperar a que IIS lo detecte? Si es necesario esperar un poco, preferiría tener un archivo como "apprestart" que IIS escuchará, luego eliminarlo una vez que lo detecte y comenzar a reciclar.

¿Cómo sabría IIS cuando terminó de copiar archivos? ¿Cómo evitas el estado desgarrado? Básicamente, necesita señalar el inicio y la finalización de una transacción. La creación del archivo señala el inicio y la eliminación señala el final.

Si no hay bloqueo, ¿por qué notificar a IIS cuando comience la compilación? ¿No podemos simplemente señalar cuando todos los archivos están actualizados y la aplicación necesita ser reciclada? Creo que entendí mal algo.

Si no hay bloqueo, ¿por qué notificar a IIS cuando comience la compilación? ¿No podemos simplemente señalar cuando todos los archivos están actualizados y la aplicación necesita ser reciclada? Creo que entendí mal algo.

Sí, eso funcionaría. Pensé que estabas describiendo el estado actual de la técnica. Incluso podría ser posible hacer esto hoy con web.config. Si toca el archivo, se reiniciará la aplicación.

Tuve éxito con la implementación en el lugar (https://flukefan.github.io/ZipDeploy/), por:

  1. Cambiar el nombre de los archivos de ensamblaje (aparentemente puede cambiar el nombre aunque no pueda eliminar / sobrescribir);
  2. Copiar en los nuevos ensamblajes;
  3. Toque la configuración web para reiniciar la aplicación;
  4. Elimine los antiguos ensamblajes renombrados.

Sin equilibrio de carga; instancia única de IIS; sin cambios en IIS. YMMV.

@FlukeFan ¿Cómo puede evitar despliegues desgarrados o eso no le preocupa? Por rasgado, me refiero a que hay una ventana en la que la aplicación anterior carga un nuevo ensamblaje antes de reiniciar la aplicación.

No toco el web.config hasta que todos los ensamblajes cambien de nombre o se actualicen. Supongo que existe una pequeña posibilidad de que algo más pueda hacer que un grupo de aplicaciones se recicle durante ese tiempo, pero aún no ha sucedido.

Por lo general, desactivo todas las demás opciones de reciclaje automático y también deshabilito el reciclaje superpuesto en la configuración del grupo de aplicaciones de IIS.

@FlukeFan no es un reciclaje, pero si aún no ha cargado el ensamblaje que se reemplazó. Por ejemplo, supongamos que tiene un ensamblado A.dll y B.dll. Digamos que B se usa cuando vas a la página de configuración, por lo que se carga entonces. Si fue a la página de configuración cuando B.dll fue reemplazado por el nuevo, podría terminar con la aplicación anterior ejecutándose con un nuevo B.dll.

Me pregunto si deberíamos crear una herramienta global dotnet para ayudar en este tipo de implementación. Básicamente, la herramienta podría hacer todas las cosas difíciles que la gente ha mencionado en este hilo.

Pensamientos

@FlukeFan no es un reciclaje, pero si aún no ha cargado el ensamblaje que se reemplazó. Por ejemplo, supongamos que tiene un ensamblado A.dll y B.dll. Digamos que B se usa cuando vas a la página de configuración, por lo que se carga entonces. Si fue a la página de configuración cuando B.dll fue reemplazado por el nuevo, podría terminar con la aplicación anterior ejecutándose con un nuevo B.dll.

Así que no me ocupo de ese caso ahora. https://github.com/FlukeFan/ZipDeploy/blob/master/ZipDeploy/ZipDeploy.cs#L55

Supongo que podría hacer las cosas en un orden diferente, tocar web.config primero, esperar a que finalicen todas las 'otras' solicitudes, luego, finalmente, hacer el reemplazo justo antes de que finalice la última solicitud (mientras IIS pone en cola nuevas solicitudes para el próximo reciclar el grupo de aplicaciones), pero lo que tengo funciona para mí en este momento.

Probablemente no sea actualmente lo suficientemente robusto para el escenario que está describiendo (pero no he estado haciendo nada elegante con la carga dinámica del ensamblaje que no sea en el momento del inicio).

¿Hay planes para volver a visitar esta función y ponerla en la hoja de ruta? Es muy inconveniente / antipático exigir que todos los que implementen un sitio web .Net Core implementen manualmente una estrategia de ranuras de ensayo si desean admitir implementaciones sin tiempo de inactividad.

Tener esta función facilitaría mucho la transición a los sitios web .Net Core para muchas personas y permitiría una adopción más rápida de los sitios web .Net Core.

Nunca pensé en eso. Pero es muy posible que hayas dado en el clavo. Esta podría ser una decisión empresarial nefasta para obligar a las personas a usar las tragamonedas azules. Si fue posible en el pasado, ¿por qué ha tardado tanto en "arreglarlo" ahora? No está roto desde una perspectiva empresarial lo que eso en mente. Quizás soy un poco cínico. Pero poco a poco he observado que las características azules que solían ser gratuitas se redujeron y se trasladaron a niveles más caros.

Me pregunto si deberíamos crear una herramienta global dotnet para ayudar en este tipo de implementación. Básicamente, la herramienta podría hacer todas las cosas difíciles que la gente ha mencionado en este hilo.

Pensamientos

Esto es para ejecutarse en el servidor CI, digamos. ¿Cómo enviaría los binarios / paquete al servidor de destino?

Nunca pensé en eso. Pero es muy posible que hayas dado en el clavo. Esta podría ser una decisión empresarial nefasta para obligar a las personas a usar las tragamonedas azules. Si fue posible en el pasado, ¿por qué ha tardado tanto en "arreglarlo" ahora? No está roto desde una perspectiva empresarial lo que eso en mente. Quizás soy un poco cínico. Pero poco a poco he observado que las características azules que solían ser gratuitas se redujeron y se trasladaron a niveles más caros.

Las implementaciones en el lugar sin coordinación son fundamentalmente poco confiables por las razones mencionadas anteriormente. Nunca volveremos a implementar instantáneas porque esa característica históricamente no ha sido confiable y ha causado muchos problemas en ASP.NET en .NET Framework. También solo funciona para un tipo específico de implementación, dependiente del marco, que es compatible con .NET Framework. .NET core admite archivos individuales y autónomos, lo que hace que sea mucho más difícil de admitir. Incluso la sugerencia anterior no cubre esos casos.

Todavía creemos que realizar implementaciones en el lugar debe ser lo más atómico posible y muchos de los problemas en este tema provienen de errores y la falta de confiabilidad de la detección y el reciclaje de aplicaciones fuera de línea, por lo que pasamos mucho tiempo arreglando eso (y también el bloqueo de pdb).

La implementación web es la única herramienta actual que incorpora el flujo con el que creemos que tiene sentido implementar, pero está atrapada en esa tecnología, por lo que no ayuda si está implementando ftp en sus servidores o copiando a un recurso compartido de archivos (aunque podría).

Una herramienta global de dotnet podría ser una respuesta aquí.

Esto es para ejecutarse en el servidor CI, digamos. ¿Cómo enviaría los binarios / paquete al servidor de destino?

No lo creo. Probablemente admitiría FTP y una copia directa. Cualquier otra cosa que no sea probablemente sea un protocolo propietario.

Con suerte, cuando dices FTP también te refieres a ftp sobre ssh. Una herramienta así sería muy valiosa.

Con suerte, cuando dices FTP también te refieres a ftp sobre ssh. Una herramienta así sería muy valiosa.

No, me refiero a ftp. Pero haríamos cualquier cosa que tuviera sentido. Tal vez sea mejor ser una herramienta de copia que necesite ejecutar en la máquina de destino. Eso nos saca del negocio de tener que enviar bits a cualquier parte.

¿También está utilizando SSH en sus máquinas con Windows para implementarlo en IIS?

@davidfowl Agregue (opt-in) soporte para ranuras de implementación.
https://github.com/dotnet/aspnetcore/issues/3719#issuecomment -473183712
https://github.com/dotnet/aspnetcore/issues/3793#issuecomment -335666414

Planeamos buscar la carga de ensamblajes de aplicaciones en la memoria como bytes en lugar de cargarlos desde el disco y bloquear el archivo. Esto debería estar bien para la mayoría de los casos, pero puede resultar en un mayor uso de memoria en algunos casos .

Además, eso no nos permitirá lograr un tiempo de inactividad cero.

No hay forma de que vayamos a invertir en una función como esa con el módulo.

Con suerte, cuando dices FTP también te refieres a ftp sobre ssh. Una herramienta así sería muy valiosa.

No, me refiero a ftp. Pero haríamos cualquier cosa que tuviera sentido. Tal vez sea mejor ser una herramienta de copia que necesite ejecutar en la máquina de destino. Eso nos saca del negocio de tener que enviar bits a cualquier parte.

¿También está utilizando SSH en sus máquinas con Windows para implementarlo en IIS?

Si. Usamos CI / CD y lo implementamos en sistemas Linux y Windows, por lo que fue mucho más fácil instalar openssh en Windows Box.

$ appPool = 'predeterminado'
Stop-WebAppPool -Name $ appPool -Passthru
... desplegar ...

Inicio-WebAppPool -Name $ appPool -Passthru
...desplegar.....

o

$ appPool = 'predeterminado'
Stop-WebAppPool -Name $ appPool
while ((Get-WebAppPoolState -Name $ appPool) .Value -ne 'Detener') {
dormir 1 #segundo
}
... desplegar ...

Start-WebAppPool -Name $ appPool
while ((Get-WebAppPoolState -Name $ appPool) .Value -ne 'Inicio') {
dormir 1 #segundo
}

...desplegar.....

Ranuras de despliegue de hombres pobres
Hace aproximadamente un año publiqué sobre la creación de 2 carpetas raíz del sitio y tengo un enlace simbólico que apunta a una de ellas configurada para el sitio IIS.
El beneficio es que su tiempo de inactividad es menor en comparación con otras soluciones más simples.
Si el reciclaje superpuesto está habilitado, no hay tiempo de inactividad, solo penalización de calentamiento para la primera solicitud, que es el caso de todos modos.

Si la operación de implementación / copia tarda N segundos en completarse, no es necesario que detenga el grupo de aplicaciones durante N segundos.
No te metas con la aplicación cuestionable sin conexión.
Simplemente copie a la carpeta inactiva, intercambie el enlace simbólico cuando los archivos estén allí y luego recicle el grupo de aplicaciones.
Implementación atómica, sin tiempo de inactividad, solo una primera solicitud más lenta como de costumbre.

https://github.com/dotnet/aspnetcore/issues/3793#issuecomment -459870870

¿Alguien intentó eso?
Si algo como esto funciona, entonces podría convertirse en un servicio con una herramienta de implementación del lado del cliente.

  • cliente -> servidor ¿cuál es la carpeta / recurso compartido inactivo?
  • S: aquí
  • C: ok desplegado / copiado
  • S: enlace simbólico intercambiado y reciclado
  • C: gracias, http get / healthcheck (opcional)
  • C: uf, lo arruiné, retroceda por favor
  • S: intercambio de enlace simbólico, reciclaje (de vuelta al negocio)
  • C: enjuague repetir hasta que funcione

Así que también tengo problemas con la implementación de archivos bloqueados. en el alojamiento de aplicaciones. Intenté detener el grupo de aplicaciones, pero los archivos permanecen bloqueados. He intentado enviar app_offline.htm pero tampoco tuve suerte.
Además, si desea administrar la eliminación del archivo app_offline.htm, puede hacerlo fácilmente al iniciar la aplicación en program.cs. De esta manera sabemos cuándo comienza a estar en línea.

El problema actual al que me enfrento es que los dll están bloqueados e incluso si cambia el nombre y luego copia los archivos, el proceso anterior aún se ejecuta en los archivos renombrados. Entonces, cuando intentemos implementar nuevamente, tendríamos que cambiar el nombre de los archivos nuevamente. Supongo que podríamos usar una fecha de algún tipo como reemplazo del nombre del archivo.
Estamos usando dotnet core 3.1.4 para esto en el servidor IIS Windows 2012 R2

@foxjazz ¿cómo se mantienen bloqueados los archivos si se detiene el grupo / proceso de aplicaciones? ¿Puedes elaborar?

@foxjazz ¿cómo se mantienen bloqueados los archivos si se detiene el grupo / proceso de aplicaciones? ¿Puedes elaborar?

image

image

Al intentar eliminar los dll usados, la imagen dice usado por otro proceso.
El grupo de aplicaciones ha estado fuera de línea durante un tiempo.

Consulte el administrador de tareas para ver si el proceso aún se está ejecutando. Pulsar el botón de parada no significa que finalice inmediatamente.

Consulte el administrador de tareas para ver si el proceso aún se está ejecutando. Pulsar el botón de parada no significa que finalice inmediatamente.

la imagen de arriba es del administrador de tareas. No estoy seguro de cuál es, pero si los elimino, se liberará el archivo. Supongo que puedo usar el identificador para averiguar el pid para terminar. No pensé que tendría que llegar tan lejos para el despliegue. El identificador dice que los procesos de w3wp.exe 2 tienen uno de los archivos bloqueado. aunque el grupo de aplicaciones esté cerrado.

Lo que sería realmente bueno es tener una ruta para detener el proceso.
api \ KillDeathKill
{
Program.KillProcess ()
}

Eso es improbable. El archivo está bloqueado por un proceso. Si w3wp es ese proceso, entonces nunca se mató para empezar o se activó uno nuevo con un pid diferente bloqueando el mismo archivo. Es por eso que primero debe asegurarse de que la aplicación fuera de línea esté inactiva para asegurarse de que no haya un nuevo proceso para bloquear el archivo, eliminar el proceso existente, implementar nuevos bits, eliminar la aplicación fuera de línea

Eso es improbable. El archivo está bloqueado por un proceso. Si w3wp es ese proceso, entonces nunca se mató para empezar o se activó uno nuevo con un pid diferente bloqueando el mismo archivo. Es por eso que primero debe asegurarse de que la aplicación fuera de línea esté inactiva para asegurarse de que no haya un nuevo proceso para bloquear el archivo, eliminar el proceso existente, implementar nuevos bits, eliminar la aplicación fuera de línea

cuando dices que app_offline.htm está caído primero. Sí, este fue el caso. Tengo una ruta de estado que puedo verificar a través de una solicitud de obtención, y definitivamente está fuera de línea. También detuvo el grupo de aplicaciones manualmente. Pero el proceso w3wp todavía colgaba el archivo.

Entonces el proceso no se detuvo

Entonces el proceso no se detuvo

Entonces, ¿por qué detener el grupo de aplicaciones no detener el proceso?

El grupo de aplicaciones representa el proceso y si detiene el grupo de aplicaciones, el proceso se cagará. El archivo no se puede bloquear si no hay un proceso para bloquearlo, por lo que una de esas otras teorías parece más probable.

El grupo de aplicaciones representa el proceso y si detiene el grupo de aplicaciones, el proceso se cagará. El archivo no se puede bloquear si no hay un proceso para bloquearlo, por lo que una de esas otras teorías parece más probable.

ja, dijiste una mierda. No quiero parecer que te estoy engañando. Estoy diciendo que detener el grupo de aplicaciones NO funciona como se anuncia en toda la documentación. El proceso no es una mierda, incluso después de 90 segundos, todavía se está ejecutando. El archivo está bloqueado incluso cuando puede ver claramente que el grupo de aplicaciones se ha detenido. El proceso contiene un singleton para obtener algunos datos. Y otros controladores. Sería bueno tener una secuencia de comandos que cierre el proceso en función del archivo bloqueado. Entonces podría desplegarme sin miedo. El cambio de nombre también puede funcionar. Se puede cambiar el nombre de los archivos. (dotnet core 3.1.4) sabor

Hace aproximadamente un año publiqué sobre la creación de 2 carpetas raíz del sitio y tengo un enlace simbólico que apunta a una de ellas configurada para el sitio IIS.

¿Alguien intentó eso?
Si algo como esto funciona, entonces podría convertirse en un servicio con una herramienta de implementación del lado del cliente.

@CJHarmath :

Si publiqué más actualizaciones, podría considerar una herramienta de implementación de cliente, pero en realidad puedo simplemente acceder a un shell remoto en el servidor IIS y ejecutar el script de PowerShell para darle la vuelta.
psexec.exe \\IIS_SERVER cmd /c "powershell -noninteractive -file C:\FlipSymLink.ps1"

# FlipSymLink.ps1

Import-Module WebAdministration # run as admin
# create 2 site root directories
$a = 'C:\Websites\MySiteA'
$b = 'C:\Websites\MySiteB'
$appRoot  = 'C:\Websites\MySite'
$appName  = 'MyAppName'
$siteName = 'MySiteName'
$poolName = "MyPoolName"
New-Item -Type Directory $a -ErrorAction SilentlyContinue
New-Item -Type Directory $b -ErrorAction SilentlyContinue

# create a symlink to targeting one side
New-Item -Type SymbolicLink -Path $appRoot -Target $a -Name A -ErrorAction SilentlyContinue
New-Item -Type SymbolicLink -Path $appRoot -Target $b -Name B -ErrorAction SilentlyContinue

# point the site root to the symlink
$currentPath = (Get-ItemProperty "IIS:\Sites\$siteName\$appName" -name physicalPath)
if ($currentPath -eq "$appRoot\A") {
    Write-Host "Switched to B"
    New-Item $b\active.txt
    Remove-Item $a\active.txt
    Set-ItemProperty "IIS:\Sites\$siteName\$appName" -name physicalPath -value $appRoot\B
} else {
    Write-Host "Switched to A"
    New-Item $a\active.txt
    Remove-Item $b\active.txt
    Set-ItemProperty "IIS:\Sites\$siteName\$appName" -name physicalPath -value $appRoot\A
}
Restart-WebAppPool -Name $poolName

psexec.exe \\IIS_SERVER cmd /c "powershell -noninteractive -file C:\FlipSymLink.ps1"

Esto también podría convertirse en un punto final JEA , por lo que puede ejecutar flip como un usuario no elevado (por ejemplo, desde un paso de implementación del servidor CI / CD)
Invoke-Command -ComputerName IIS_SERVER -ConfigurationName IIS-Flip -ScriptBlock { Switch-SymlinkTarget -SiteName MySite}
Usó Switch lugar de Flip ya que es un verbo aprobado.

Se usó Switch lugar de Flip ya que es un verbo aprobado.

Swap es el verbo que se usa cuando se trata de tragamonedas. ¿Parece que tendría sentido reutilizarlo aquí?

tener el mismo problema descrito hace 4 años.
¿Algún avance en esto?
No quiero abrir el escritorio remoto para simplemente cargar un nuevo archivo dll.

Cuando trato de sobrescribir el archivo DLL de la aplicación .NET Core usando FTP en el archivo del servidor IIS de producción está bloqueado y no se puede sobrescribir.

Para implementar la nueva versión, necesito detener la aplicación en IIS (abriendo RDP) para liberar el bloqueo y luego sobrescribir.
No es posible implementar sin detener la aplicación.

¿Alguna solución para esto? Gracias

Si no puede desconectar su host detrás del equilibrador de carga y desea hacerlo más rápido, aquí hay una forma con enlaces simbólicos y algo de PowerShell.
Estaba pensando en hacer algo como esto.

Es más rápido, ya que no tiene que detener el grupo de aplicaciones durante la copia y el reciclaje es mejor que una parada completa, ya que permite completar las solicitudes actuales, por lo que se reduce el tiempo de inactividad.

# Setup
Import-Module WebAdministration
# create 2 site root directories
$a = 'C:\inetpub\AspNetCoreSampleA'
$b = 'C:\inetpub\AspNetCoreSampleB'
$siteRoot = 'C:\inetpub\aspnetcoresample'
$siteName = 'AspNetCoreSample'
$poolName = "aspnetcore"
New-Item -Type Directory $a
New-Item -Type Directory $b
# create a symlink to targeting one side
New-Item -Type SymbolicLink -Path $siteRoot -Target $a
# point the site root to the symlink
Set-ItemProperty "IIS:\Sites\$siteName" -name physicalPath -value $siteRoot
# make sure it get's picked up
Restart-WebAppPool -Name $poolName

# this tells you the active side
Get-Item -Path $siteRoot | Select-Object -ExpandProperty target

# Flip the symlink
$current = (Get-Item -Path $siteRoot).Target
$newTarget = if ($current -eq $a) {$b} else {$a}
New-Item -Type SymbolicLink -Path $siteRoot -Target $newTarget -Force
# at this point w3wp.exe still locks the current target folder until it's getting recycled
# Deploy new version to the symlink which is now pointing to the other side which should have no locks
robocopy \\myshare\myapp $siteRoot /mir
# recycle app pool, so it picks up the new files
Restart-WebAppPool -Name $poolName

# bonus point: rollback is easy
$current = (Get-Item -Path $siteRoot).Target
$newTarget = if ($current -eq $a) {$b} else {$a}
New-Item -Type SymbolicLink -Path $siteRoot -Target $newTarget -Force
Restart-WebAppPool -Name $poolName

Aquí está la esencia
https://gist.github.com/csharmath/b2af0f50700ce9fbdd8c5c3e582fd41b

Aquí hay algo que creo que he solucionado. Solo lo he intentado con ASP.NET, pero imagino que funcionaría igual con el módulo de alojamiento para net core. La primera ejecución detiene el sitio por un momento, por lo que es posible que desee modificarlo un poco.

param(
    [Parameter(Mandatory = $true)]
    [string] $iisRootPath,
    [Parameter(Mandatory = $true)]
    [string] $siteName,
    [Parameter(Mandatory = $true)]
    [string] $artifactPath,
    [Parameter(Mandatory = $false)]
    [string] $siteFolderName,
    [Parameter(Mandatory = $false)]
    [string] $appPoolName
)
Import-Module WebAdministration

#populate optional parameters
if (!($PSBoundParameters.ContainsKey('siteFolderName'))) { $siteFolderName = $siteName }
if (!($PSBoundParameters.ContainsKey('appPoolName'))) { $appPoolName = $siteName }

#set A, B and C paths
$a = "$iisRootPath\$siteFolderName" + 'A'
$b = "$iisRootPath\$siteFolderName" + 'B'
$c = "$iisRootPath\$siteFolderName"

#existence test
$cName = Get-Item -Path $c -ErrorAction SilentlyContinue | Select-Object -ExpandProperty name -ErrorAction SilentlyContinue
$bName = Get-Item -Path $b -ErrorAction SilentlyContinue | Select-Object -ExpandProperty name -ErrorAction SilentlyContinue

#get the shudown timeout for the app pool
$shutdownTimeout = Get-WebConfigurationProperty -Filter 'system.web/httpRuntime' -PSPath "IIS:\Sites\$siteName" -Name shutdownTimeout | Select-Object -ExpandProperty Value

#create symlink, if symlink source is an existing directory, rename existing 
if($cName -eq $null) 
{
    Write-Output "Creating SymbolicLink $c -> $a" 
    New-Item -Type SymbolicLink -Path $c -Target $a
} 
else
{
    #directories don't have a target property
    $cTarget = Get-Item -Path $c | Select-Object -ExpandProperty target -ErrorAction SilentlyContinue

    #this is a directory, rename and create symlink
    if($cTarget -eq $null)
    {
        #restart AppPool first so no locked files
        #Write-Output "Restarting AppPool $appPoolName" 
        #Restart-WebAppPool -Name $appPoolName

        #stop AppPool first so no locked files
        Write-Output "Stopping AppPool $appPoolName" 
        Stop-WebAppPool -Name $appPoolName

        #sleep for shutdownTimeout
        Write-Output "Sleeping for $shutdownTimeout" 
        Start-Sleep -Seconds (([System.TimeSpan]::Parse("$shutdownTimeout").TotalSeconds) * 1.1)

        try {
             #if the rename fails, there are files in use. stop the script
            $newName = $siteFolderName + 'A'
            Write-Output "Renaming $c to $newName" 
            Rename-Item -Path $c -NewName $newName -ErrorAction Stop
        }
        catch {
            Write-Error -Message "Failed to rename $c to $newName due to files in use."

            #start AppPool 
            Write-Output "Starting AppPool $appPoolName due to failed folder rename. Consider trying again durring a time with reduced traffic." 
            Start-WebAppPool -Name $appPoolName

        }

        #create symlink
        Write-Output "Creating SymbolicLink $c -> $a" 
        New-Item -Type SymbolicLink -Path $c -Target $a

        #start AppPool 
        Write-Output "Starting AppPool $appPoolName" 
        Start-WebAppPool -Name $appPoolName

        #copy a to b to pick up directory permissions
        if($bName -eq $null) 
        {
            Write-Output "Copying Directory $a to $b"  
            robocopy $a $b /e /sec /sl
        }
    }
}

#existence test
$aName = Get-Item -Path $a -ErrorAction SilentlyContinue | Select-Object -ExpandProperty name -ErrorAction SilentlyContinue
$bName = Get-Item -Path $b -ErrorAction SilentlyContinue | Select-Object -ExpandProperty name -ErrorAction SilentlyContinue

#create if needed
if($aName -eq $null) 
{
    Write-Output "Creating Directory $a"  
    New-Item -Type Directory $a 
}
if($bName -eq $null) 
{
    Write-Output "Creating Directory $b"  
    New-Item -Type Directory $b 
}

#make sure site pointing to symlink
Write-Output "Pointing Website $siteName to Path $c" 
Set-ItemProperty "IIS:\Sites\$siteName" -name physicalPath -value $c

#restart so we know it's loading from symlink
Write-Output "Restarting AppPool $appPoolName" 
Restart-WebAppPool -Name $appPoolName

#sleep for shutdownTimeout 
Write-Output "Sleeping for $shutdownTimeout" 
Start-Sleep -Seconds ([System.TimeSpan]::Parse("$shutdownTimeout").TotalSeconds)

#get current symlink target and set new target
Get-Item -Path $c | Select-Object -ExpandProperty target
$current = (Get-Item -Path $c).Target
$newTarget = if ($current -eq $a) {$b} else {$a}

$fileOrDirectoryName = Get-Item $artifactPath | Select-Object -ExpandProperty name

#test for .zip
if(($fileOrDirectoryName).ToLower().EndsWith(".zip") -eq $true)
{
    #copy to temp location
    $guid = [System.Guid]::NewGuid()
    $tempPath = "$iisRootPath\temp-$guid"
    $tempDest = "$iisRootPath\temp-dest-$guid"

    Write-Output "Creating temp directory $tempPath" 
    New-Item -Type Directory $tempPath

    $artifactDirectory = [System.IO.Path]::GetDirectoryName($artifactPath)
    $artifactFile = [System.IO.Path]::GetFileName($artifactPath);

    #TODO: first robocopy arg needs to be a directory, not a file
    Write-Output "Copying archive from $artifactPath to $tempPath" 
    robocopy $artifactDirectory $tempPath $artifactFile

    #extract to temp destination (seems a failed extract can leave empty folders)
    Write-Output "Extracting archive to $tempDest" 
    Expand-Archive -Path "$tempPath\$fileOrDirectoryName" -DestinationPath $tempDest -Force

    #copy from temp destination to destination
    Write-Output "Copying files from $tempDest to $newTarget" 
    robocopy $tempDest $newTarget /e

    #delete temp directory
    Write-Output "Removing temp directory $tempPath" 
    Remove-Item -Path $tempPath -Recurse -Force

    #delete temp directory
    Write-Output "Removing temp directory $tempDest" 
    Remove-Item -Path $tempDest -Recurse -Force
}
else 
{
    #copy new files
    Write-Output "Copying files from $artifactPath to $newTarget" 
    robocopy $artifactPath $newTarget /e
}

#swap symlink
Write-Output "Pointing SymbolicLink $c -> $newTarget" 
New-Item -Type SymbolicLink -Path $c -Target $newTarget -Force

#restart so it loads from newly swapped symlink
Write-Output "Restarting AppPool $appPoolName" 
Restart-WebAppPool -Name $appPoolName

@LucidObscurity ¿qué es eso? un código cmd? ¿Dónde tengo que agregar ese código?
Gracias

¿Qué pasa con la idea de aumentar el número de reintentos (parámetro: -retryAttempts:X ) o el intervalo de tiempo de reintento (parámetro: -retryInterval:XXXX ) para el comando msdeploy , hasta que el proceso libere el bloqueo de archivo?

Creo que @davidfowl tiene razón, el proceso sigue ahí de alguna manera y bloquea los archivos. Incluso Reset IIS no ayuda, todavía espera el proceso hasta que se agote el tiempo de espera. Si suelta app_offline.htm y espera 90 segundos (configuración de tiempo de espera predeterminada para apagar AppPool) y vuelve a intentarlo, verá que funciona.
Para mí en local, no quiero esperar tanto tiempo, así que actualicé este Límite de tiempo de apagado (segundos) a 5 y actualicé el archivo del proyecto para generar app_offline.htm antes de compilar, eliminarlo después de compilar. Funciona bien.
Para el servidor, uso msdeploy para eliminar app_offline.htm, sincronizar la nueva versión y luego eliminar app_offline.htm. Con msdeploy, vuelve a intentarlo si los archivos están bloqueados pero en algún momento se rindió antes de los 90 segundos, así que tengo que activar la implementación nuevamente, luego funciona en el segundo intento

¿Alguna actualización sobre esto? ¿Cuándo estará lista esta nueva versión?

Gracias por contactarnos.
Estamos moviendo este problema al hito Next sprint planning para una evaluación / consideración futura. Evaluaremos la solicitud cuando estemos planificando el trabajo para el próximo hito. Para obtener más información sobre qué esperar a continuación y cómo se manejará este problema, puede leer más sobre nuestro proceso de clasificación aquí .

Descubrí este problema esta semana, después de haber convertido una aplicación .NET 4.5.2 a .NET 5.0. Tengo otro enfoque para superar esto. Creé un servicio de Windows que se ejecuta en el servidor IIS. En ese servicio, tengo un servidor HTTP simple que se ejecuta en un puerto personalizado. La aplicación web puede realizar una solicitud posterior a ese servidor para iniciar una actualización. Detiene el grupo de aplicaciones, se asegura de eliminar todos los procesos para esa aplicación, crear una copia de seguridad de la versión actual, eliminar la versión actual, descargar el paquete de actualización y extraerlo. Luego vuelve a iniciar el grupo de aplicaciones.

Creé una aplicación simple de Windows Forms para crear paquetes de actualización que se envían a un repositorio del que obtiene el servicio de Windows mencionado anteriormente.

¿Fue útil esta página
0 / 5 - 0 calificaciones