Aspnetcore: IIS -> Заблокировать файл DLL приложения .NET Core

Созданный на 7 июл. 2016  ·  114Комментарии  ·  Источник: dotnet/aspnetcore

Когда я пытаюсь перезаписать файл DLL приложения .NET Core с помощью FTP на рабочем сервере, файл IIS блокируется и не может быть перезаписан.

Чтобы развернуть новую версию, мне нужно остановить приложение в IIS, чтобы снять блокировку, а затем перезаписать.
Развернуть без остановки приложения невозможно.

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

Самый полезный комментарий

👍

Отказ от поддержки повторной переработки - это регресс.

Все 114 Комментарий

См. App_offline.htm: https://docs.asp.net/en/latest/hosting/aspnet-core-module.html#asp -net-core-module-app-offline-htm

Если вы в конечном итоге захотите сделать это с помощью PowerShell, вы можете использовать командлеты IIS Admin: https://technet.microsoft.com/en-us/library/ee790599.aspx

Stop-WebAppPool -Name $appPoolName

... deploy ...

Start-WebAppPool -Name $appPoolName

Спасибо за объяснение @Tratcher .
Я не уверен, входит ли это в ваши планы, но я думаю, что это работало для предыдущего ASP.NET MVC?
Планируете ли вы реализовать эту функцию или нет?

@GuardRex Я не могу этого сделать, потому что это среда общего хостинга и у меня нет разрешения на остановку AppPool

Сможете ли вы заставить его «просто работать» с msdeploy.exe и Azure? Если я правильно понимаю, необходимо перезапустить веб-сайт, чтобы предотвратить блокировку файлов. -enableRule:AppOffline работает, но весь веб-сайт отключен на несколько минут, что не очень удобно для пользователя, особенно с учетом того, что мы выполняем развертывание несколько раз в день.

См. Также http://stackoverflow.com/q/40276582/14131

@chuchuva может быть, но вся магия имеет свою цену. Предыдущие версии ASP.NET выполняли сложное теневое копирование для решения проблем с блокировкой файлов.

Магия или нет, но это сработало. Я скучаю по нему сейчас, после перехода на ядро ​​ASP.NET ...

Согласен с @HarelM. У нас возникли проблемы с этим из-за наших автоматических развертываний до удобства конечного пользователя. Мы перешли от развертывания примерно 10 раз в день со старым MVC к ежедневному развертыванию в ночное время и согласились с тем, что люди, использующие приложение Core, будут раздражены, когда мы отключим его. Хотя это не препятствие для шоу, это добавило трения к принятию Core.

👍

Отказ от поддержки повторной переработки - это регресс.

Есть ли планы пересмотреть эту функцию и включить ее в дорожную карту? Очень неудобно / недружелюбно требовать от всех, кто развертывает веб-сайт .Net Core, вручную реализовывать стратегию промежуточных слотов, если они хотят поддерживать развертывания с нулевым временем простоя.

Наличие этой функции сделало бы переход на веб-сайты .Net Core намного более плавным для многих людей и позволило бы быстрее внедрить веб-сайты .Net Core.

Мы тоже хотели бы знать. Помещение app_offline.htm в каталог приложений не работает.

Я только что осознал эту «особенность» после переноса ряда сайтов на AspNetCore. Я не могу поверить, что считается приемлемым отключать ваши сайты на несколько минут каждый раз, когда вы хотите их опубликовать!

Это достаточно плохо для меня, как руководителя небольшой команды - неужели те, кто практикует непрерывную интеграцию в больших масштабах, избегают AspNetCore? У них нет возможности отключать свой сайт на несколько минут каждый час для повторной публикации!

Вы используете FTP или xcopying? Или вы используете webdeploy?

Я публикую через webdeploy в IIS.

В настоящее время мы работаем над этой проблемой, просто удаляя сначала файл web.config (фактически убивая приложение), но это не совсем приемлемое решение в долгосрочной перспективе.

@DaleMckeown в идеале с непрерывным рабочим процессом интеграции у вас будет несколько серверов за балансировщиком нагрузки. Затем вы извлекаете один сервер, обновляете его, кладете обратно и переходите к следующему. Конечно, это не всегда возможно (как в нашем случае), поэтому придется смириться с простоями в несколько минут. В нашем случае резервное копирование приложения выполняется в течение 30 секунд, так что это не проблема.

@DaleMckeown

Я публикую через webdeploy в IIS.

Есть несколько вариантов, которые можно использовать для правильной работы развертывания с помощью webdeploy (он поддерживает переименование заблокированных файлов и автоматическое отключение приложения). Так ли это по умолчанию @shirhatti ?

@ajeckmans

В настоящее время мы работаем над этой проблемой, просто удаляя сначала файл web.config (фактически убивая приложение), но это не совсем приемлемое решение в долгосрочной перспективе.

Означает ли это, что вы выполняете развертывание xcopy?

Есть несколько вариантов, которые можно использовать для правильной работы развертывания с помощью webdeploy (он поддерживает переименование заблокированных файлов и автоматическое отключение приложения). Так ли это по умолчанию @shirhatti ?

Спасибо, Дэвид - звучит лучше, чем то, что я сейчас делаю (вручную останавливает сайт и пул приложений в IIS). Не могли бы вы указать на некоторые ресурсы, чтобы я мог исследовать последствия этих подходов?

@DaleMckeown некоторую информацию, пока я не найду источник истины https://github.com/Microsoft/vsts-tasks/issues/5259#issuecomment -346202503

@davidfowl Мы используем webdeploy для развертывания на нашем тестовом сервере (что, кстати, никогда не доставляет нам проблем), оттуда мы копируем файлы на наши живые серверы с помощью robocopy

@ajeckmans

В настоящее время мы работаем над этой проблемой, просто удалив сначала файл web.config.

Когда web.config удаляется из развертывания, IIS будет обслуживать конфиденциальные файлы из развертывания. Злоумышленник может просто запрашивать файлы непрерывно днем ​​и ночью, пока не откроется ваше 30-е окно.

@DaleMckeown

Следуя совету @ajeckmans, если вы когда-нибудь захотите немного разобраться с сорняками, используя для этого подход PS, вы можете создать сценарий для удаления AppPools по одному для развертывания в веб-ферме. Пример того, как это можно сделать, можно найти на странице https://github.com/guardrex/aspnetcore-iis-ps-publish ... но просто посмотрите на это как на экспериментальный пример, а не на сценарий производственного качества. Я не играл с этим какое-то время, но он (теоретически) все еще должен работать.

@guardrex , ты прав. Сначала мы копируем app_offline.htm в каталог, затем повторно загружаем web.config, копируем приложение, возвращаем web.config и удаляем app_offline (все с помощью скрипта ofc). К сожалению, простое размещение файла app_offline в каталоге веб-сайтов не нарушает блокировку dll. Нам нужно удалить web.config, действие, которое нам не нужно делать для старых полных приложений asp.net (например, старых веб-форм и т. Д.)

@ajeckmans Это не должно работать. Когда файл web.config удаляется, IIS немедленно выбирает это изменение, поэтому он должен по умолчанию запрашивать модуль статического файла и начать обслуживание файлов. Попробуйте и посмотрите, что произойдет ...

  1. Добавьте app_offline.htm .
  2. Подтвердите, что сайт обслуживает app_offline.htm .
  3. Вытащите web.config .
  4. Запросите конфиденциальный файл (например, http://localhost:<PORT>/<ASSEMBLY_NAME>.deps.json ... заменив ПОРТ и ИМЯ СБОРА).
  5. Вы должны получить файл deps.json, если ваш статический файловый модуль работает правильно.

Я бы не стал доверять простому удалению модуля с помощью ...

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

... поскольку другие модули останутся и, возможно, представят другие векторы атаки. Возможно, можно было бы удалить все несущественные модули, но мы попадаем в неизведанные воды с таким ходом, просто чтобы прикрыть развертывание путем удаления web.config . Это никогда не было вариантом под официальным руководством, поэтому оно полностью не поддерживается. Я рекомендую, например, сценарий PS для отключения AppPool или какую-либо другую стратегию.

Думаю, я должен добавить к этому нотку сочувствия ... это действительно вызвало недоумение с точки зрения безопасности. Когда это изменение схемы развертывания было внесено, оно обсуждалось, включая возвращение файла в wwwroot , см. ...

Обсуждение: Опубликовать для IIS изменения в расположении web.config (IISIntegration 158)
Проверка на перемещение web.config обратно в wwwroot (IISIntegration 164)

[РЕДАКТИРОВАТЬ] Возможно, это ваш (неподдерживаемый) обходной путь: переместите файл web.config обратно в wwwroot , а затем продолжайте делать то, что делаете вы. Тем не менее ... довольно страшно сломать приложение, чтобы вот так отключить его.

Это оставляет меня еще более запутанным в отношении того, что нам следует делать в этой ситуации.

Каковы текущие рекомендации по публикации сайтов AspNetCore в IIS через веб-развертывание таким образом, чтобы избежать блокировок файлов?

Я тоже хотел бы знать. Это становится серьезным препятствием на пути внедрения ядра .net в моей организации.

Когда мое базовое веб-приложение .net запущено, и я пытаюсь опубликовать новую сборку, возникает ошибка, связанная с использованием библиотек DLL. Поэтому мне нужно остановить пул приложений, затем обновить библиотеки DLL и запустить пул приложений.

Есть ли какое-либо обходное решение в .Net Core, с помощью которого я могу публиковать новые сборки / библиотеки DLL без остановки пула приложений?

Это по умолчанию поддерживается в .Net framework с использованием механизма теневого копирования. К сожалению, с момента запуска ядра .Net прошло 2 года, и кажется, что до сих пор нет поддержки такой базовой и необходимой функциональности. Есть ли планы исправить это в будущем?

Заранее благодарю за любую помощь.

@guardrex действительно страшно сломать приложение, чтобы заставить IIS (или что-то еще, что удерживает блокировку) освободить dll, однако еще страшнее не иметь возможности загружать исправления в продукт. Пока что взломать приложение - единственное, что мы можем сделать, но мы изучаем другие, более современные подходы к решению этой проблемы :)

@ shahjay748 не задерживайте дыхание. Если бы мне пришлось повторить процесс здесь, я бы поместил приложение в контейнер и просто установил бы новый контейнер, переключил трафик и сбросил старую версию (или что-то в этом роде). Похоже, что более разумный поступок, поскольку ядро ​​.net - это все о новых современных способах, простое продвижение новой версии приложения путем простого копирования новых файлов считается (и я согласен) немного загадочным способом сделать это.
Что из того, что не помогает нам, пока что застряли на старых процессах :)

Что я делаю (не уверен, что это правильный способ сделать), это загружаю сайт в другой каталог и переключаю пути в iis

Мы провели внутреннее расследование по этому поводу. Насколько я могу судить, ANCM не содержит файлов / дескрипторов в развернутом приложении. Кажется, проблема связана с самим webdeploy, и развертывание происходит нестабильно. У меня никогда не было постоянных сбоев в развертывании приложения после нескольких повторных попыток после удаления app_offline.

Добавим к этому небольшое примечание к PowerShell: блокировка сборки приложения всегда снимается ... У меня никогда не было проблем ( пока! Lol).

@ bpetersen1 ... Ваш "промежуточный" подход имеет приятный побочный эффект, предлагая возможность быстрого отката, если новое развертывание не сработает. При необходимости это должно быть легко написать скрипт.

Это все еще внешне раздражает ... мы решили изучить решение для докеров, чтобы оставить IIS позади.

Я собираюсь поэкспериментировать с решением. Оставайтесь в курсе.

У меня тоже проблема с FTP.

Что советует Microsoft по этому поводу ?!

У меня тоже проблема с FTP.

Что советует Microsoft по этому поводу ?!

Перетащите файл appoffline.htm, затем ftp и удалите его.

@davidfowl Да, именно этим я сейчас занимаюсь с пакетным файлом. IIS требуется несколько секунд, чтобы снять блокировку и затем скопировать файлы.

Спасибо - из интереса, как вы запускаете батник?

Также приветствуется ссылка на документацию MIcrosoft по этому поводу; Не могу найти в гугле. Благодарю.

@ niico100 По сути, командный файл просто копирует файлы в каталог проекта, и я сначала делаю резервную копию папки, прежде чем делать это. Перед копированием файлов поместите appoffline.htm в папку проекта.
Причина проблемы с блокировкой файла, копирование будет повторяться. Я использую robcopy
https://docs.microsoft.com/en-us/windows-server/administration/windows-commands/robocopy

Если кому-то интересно, следующий сценарий загружает файл развертывания из appveyor, останавливает сайт, копирует необходимые файлы и восстанавливает сайт:
https://github.com/IsraelHikingMap/Site/blob/master/Scripts/Deploy.ps1
Однако он требует запуска от имени администратора. Надеюсь, Docker решит всю эту бессмыслицу после миграции ...
он использует команды Stop-WebAppPool и Start-WebAppPool powershell.

Для локальной разработки у меня не работал WebDeploy. Я пробовал использовать его против своего локального IIS, но он все равно жаловался на заблокированные файлы. Затем я попытался использовать приведенные выше командлеты PowerShell из событий сборки VS Pre / Post, но у меня это тоже не сработало, вероятно, потому, что 32-разрядная оболочка PowerShell не может изменять параметры 64-разрядной IIS? Во всяком случае, в моем проекте ASP.Net Core, похоже, работают следующие события до и после сборки:

Событие перед сборкой:
echo "App Offline" /a > $(ProjectDir)app_offline.htm

Событие после сборки:
del $(ProjectDir)app_offline.htm

Я кратко просмотрел здесь жалобы, и похоже, что это может быть связано. Я переместил развертывание CI для нас с развертывания осьминога, которое обычно «просто работало», на использование выпусков azure DevOps с задачами управления iis, и все еще довольно часто возникают проблемы с развертыванием новых файлов, потому что даже после остановки веб-приложения, остановки домена приложения файлы все еще находятся в использовать.

Вероятно, это по крайней мере 1 из каждых 3 развертываний, и мы не нашли ничего, что могло бы улучшить ситуацию или более надежное развертывание.

@Tratcher @ronnyek Похоже, это связано с Application Insights; после добавления расширения App Insights мою DLL веб-приложения внезапно стало очень трудно обновить, до этого проблем не было.

Это имело бы смысл, учитывая, что App Insights должен подключать профилировщик к процессу приложения и библиотекам DLL.

Я все еще сталкиваюсь с этой проблемой. Я использую флаг -e nableRule: AppOffline , иногда он работает хорошо, но в большинстве случаев развертывание не выполняется с сообщением «ERROR_FILE_IN_USE».

После запуска выпуска я слежу за папкой веб-приложения и вижу, что файл App_Offline.html был удален с помощью msdeploy. Затем выпуск завершился неудачно с указанным выше сообщением, и обратите внимание, что файл App_Offline все еще находится в папке, я снова запускаю выпуск, на этот раз он работает хорошо, поскольку модуль видит файл в папке.

последняя установленная среда выполнения asp.net -> aspnetcore.dll 12.1.18263.2

Есть идеи ? Все еще ошибка?

@dhtek Если вы попытаетесь заменить файлы сразу после размещения app_offline.htm , тогда серверу просто не хватит времени, чтобы закрыть приложение. Вам следует немного подождать, прежде чем пытаться заменить файлы.

Хорошо, я понимаю, но я использую параметр -e nableRule: AppOffline из msdeploy, и страница автоматически помещается в папку, и синхронизация выполняется сразу. Сам я ничего не делаю.

Я все еще вижу эту проблему. Мои файлы проекта ссылаются на Microsoft.NET.Sdk.Web , но он не удаляет файл app_offline.htm автоматически, как указано в документации.

Привет, ребята. Эта досадная проблема все еще присутствует в Core 2.1 с последней версией VS 2017. Я использую appoffline, но всегда используется основная dll проекта и требует полной остановки веб-сайта во время публикации. Это делает веб-развертывание практически бесполезным.

Если вы не можете отключить свой хост за балансировщиком нагрузки и хотите сделать это быстрее, вот один из способов с символическими ссылками и некоторой оболочкой PowerShell.
Я думал о том, чтобы сделать что-то подобное.

Это быстрее, так как вам не нужно останавливать пул приложений во время копирования + перезапись лучше, чем жесткая остановка, поскольку она позволяет завершать текущие запросы, что сокращает время простоя.

# 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

Вот суть
https://gist.github.com/csharmath/b2af0f50700ce9fbdd8c5c3e582fd41b

Restart-WebAppPool в основном является перезапуском, что полезно, если у вас включена перекрывающаяся перезагрузка (по умолчанию), поскольку он порождает новый w3wp.exe, и все новые запросы будут обслуживаться этим новым процессом, в то время как выполняющиеся в настоящее время будут завершены старым w3wp.exe.
Таким образом, они перекрываются до тех пор, пока старые запросы не закончатся, в результате вы получите единственный файл w3wp.exe, указывающий на новую версию, и проблемы с блокировкой не будет.

Это похоже на теневое копирование, но не на 100%, поскольку это обеспечивает гораздо более приятный и простой сценарий xcopy.

Пока что это лучший подход, который я могу придумать, если вам нужно оставаться в сети во время выпуска.

@csharmath или есть еще докер. Таким образом не блокируются файлы, и он может выполнять скользящие обновления через swarm / k8s / okd.

Конечно, это даже лучше, конечно. вздох, это еще не во всех местах.
Что касается остальных старых установок, вам нужно их выбрить, пока они не станут работать для вас без простоев или с минимальным временем простоя.

@csharmath Согласен, но на данный момент, учитывая, что эта проблема не решалась в течение _лет, с таким же успехом можно адаптироваться и искать решения, которые работают, вместо того, чтобы ждать чуда ...

Я использовал нижеприведенный сценарий оболочки питания, и он разбил IIS и даже повлиял на другой пул приложений, и мне нужно перезагрузить компьютер, чтобы вернуть все ... этот процесс я получил из официального документа, и это было катастрофой, поэтому мой совет: НЕ ИСПОЛЬЗУЙТЕ app_offline.htm, лучше используйте сценарий, который останавливает пул приложений и запускает его снова, который я нашел в этом потоке 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

Я вынужден остановить AppPool для успешного развертывания, есть ли прогресс в решении этой проблемы ?!

Мы только что впервые столкнулись с этой проблемой блокировки файлов сегодня, поскольку ядро ​​dotnet является для нас новым. Меня это действительно застало врасплох. Забавно, что причина номер 1, по которой я переключился с классического ASP на .Net Framework, когда он был еще в бета-версии (~ 2001 г.), заключается в том, что я мог выполнять горячее развертывание без блокировки файлов. Было круто! Почти 18 лет спустя, и теперь я вернулся к тому, с чего начал. Ну, что-то выигрываешь, что-то теряешь.

Я только что сослался на свою проблему ... в моем случае развертывание решений на стороне сервера Blazor ....
Пару дней назад это был кошмар ... Я применил app_offline.htm, отключил пулы приложений и даже перезапустил целые экземпляры IIS, чтобы разблокировать файлы. Следующим шагом был бы перезапуск всего сервера, к счастью, через 5 минут .dll разблокировались сами.

2019 год, такая же проблема для меня ... и эта проблема возникла в 2016 году ... все еще нет решения?

2020 год, у меня такая же проблема. Самый большой регресс за всю историю. .Net 4.6 вы заменяете файлы dll, и приложение перезагружается с новой версией. .Net core блокирует все.

@bladefist На сегодняшний день

@kanadaj, спасибо, но Dockers - это еще одна

Прошли те времена .net 4.6, когда вы просто копировали свои DLL, а ваше приложение автоматически перерабатывалось. Думаю, это было слишком просто. Вдвойне неприятно то, что это не проблема Linux. Вы можете заменить файлы, используемые в Linux.

Что ж, да, я думаю, но этот метод не очень прост в производственной среде. Без HA ваше приложение в конечном итоге не будет отвечать в течение минуты, а с HA вы получите несколько случайных неверных запросов, пока балансировщик нагрузки не обнаружит, что приложение не работает ... Если вы вручную не переключите узлы в балансировщике нагрузки. Но это звучит как еще большая проблема для настройки.

@kanadaj да, мы используем балансировщик нагрузки, который линейно обновляет серверы. Без простоев.

Мы добились успеха с

  • Использование символической ссылки для каталога приложения
  • Развернуть новую версию сайта в другой каталог
  • Обновите символическую ссылку
  • Перезапустите пул приложений с помощью служебной программы appcmd , поставляемой с IIS.

@davidglassborow , это творческое решение. Благодарю. Однако креативные решения не нужны.

По моему опыту, старый механизм был ненадежным, когда сайт все равно был загружен, мы все равно поставили обратные прокси для сайтов с высоким трафиком.

Верно, развертывание на месте никогда не было надежным или атомарным, но если вам повезет или у вас не будет большого трафика, все будет в порядке. Я предполагаю, что большинство жалоб связаны с этими сценариями. Мы постараемся улучшить ситуацию во временных рамках .NET 5.0. Некоторые предостережения:

  • Мы постараемся улучшить работу приложений, зависящих от платформы. Если вы развертываете автономный, вам не повезло. Он заблокирует как собственные, так и управляемые файлы в выходной папке. Проблема блокировки собственных dll существовала всегда и не будет исправлена ​​какими бы то ни было мерами по смягчению последствий.
  • Мы планируем изучить загрузку сборок приложений в память в виде байтов вместо загрузки их с диска и блокировки файла. В большинстве случаев это нормально, но в некоторых случаях может привести к большему использованию памяти.
  • Чтобы повторно использовать приложение, вам все равно необходимо добавить и удалить автономный файл приложения. Добавление файла appoffline - это способ сообщить, что вы хотите, чтобы приложение перезапустилось в результате развертывания.

@davidfowl План, который вы изложили для 5.0, звучит великолепно. Мы используем зависимые от фреймворка, как я уверен, что большинство из них.

С уважением не согласен с надежностью развертывания на месте. Я делал это годами на сайтах с очень высокой нагрузкой, никогда не было проблем, ни разу. Первое обнаруженное изменение приводит к сбросу приложения, балансировщик нагрузки видит, что экземпляр не отвечает, переводит его в автономный режим, после замены всех библиотек DLL балансировщик нагрузки завершает проверку работоспособности и возвращается в оперативный режим. Теперь, если не было проверки работоспособности балансировщика нагрузки, то да, это игра, но я имею в виду, кто заменяет библиотеки DLL в рабочей среде при высокой нагрузке без какого-либо прокси? Давайте сосредоточимся на правиле, а не на исключении. Без прокси я не могу придумать способ обновить приложение, не вызывая сбоя. Даже если вы поддерживаете горячую перезагрузку, некоторые запросы, вероятно, зависнут или завершатся ошибкой.

С уважением не согласен с надежностью развертывания на месте. Я делал это годами на сайтах с очень высокой нагрузкой, никогда не было проблем, ни разу. Первое обнаруженное изменение приводит к сбросу приложения, балансировщик нагрузки видит, что экземпляр не отвечает, переводит его в автономный режим, после замены всех библиотек DLL балансировщик нагрузки завершает проверку работоспособности и возвращается в оперативный режим. Теперь, если не было проверки работоспособности балансировщика нагрузки, то да, это игра, но я имею в виду, кто заменяет библиотеки DLL в рабочей среде при высокой нагрузке без какого-либо прокси? Давайте сосредоточимся на правиле, а не на исключении. Без прокси я не могу придумать способ обновить приложение, не вызывая сбоя. Даже если вы поддерживаете горячую перезагрузку, некоторые запросы, вероятно, зависнут или завершатся ошибкой.

У вас есть балансировщик нагрузки. У многих людей нет балансировщика нагрузки, они просто заменяют файлы на диске и ждут волшебства 😄

@davidfowl Правильно, но трафик высокий + без фунта = безрассудство

Кроме того, проблема с app_offline.htm заключается в том, что из процесса ci / cd вы не знаете, когда процесс останавливается. Нам пришлось добавить огромную команду сна между созданием этого файла и отправкой DLL, потому что наш процесс завершения может занять от 1 секунды до 1 минуты. Когда вы балансируете нагрузку на множество экземпляров, эти спящие режимы составляют очень долгий цикл развертывания.

Однако загрузка файлов в память все это исправляет.

@davidfowl Правильно, но трафик высокий + без фунта = безрассудство

👍

Кроме того, проблема с app_offline.htm заключается в том, что из процесса ci / cd вы не знаете, когда процесс останавливается. Нам пришлось добавить огромную команду сна между созданием этого файла и отправкой DLL, потому что наш процесс завершения может занять от 1 секунды до 1 минуты. Когда вы балансируете нагрузку на множество экземпляров, эти спящие режимы составляют очень долгий цикл развертывания.

Итак, проблема в том, что удаление этого файла не сообщает вам, когда можно начать развертывание, поскольку файлы все еще заблокированы, пока уведомление не будет получено ANCM.

Кроме того, проблема с app_offline.htm заключается в том, что из процесса ci / cd вы не знаете, когда процесс останавливается.

Правильно, издатель VS использует короткие паузы и несколько повторных попыток.

  • Чтобы повторно использовать приложение, вам все равно необходимо добавить и удалить автономный файл приложения. Добавление файла appoffline - это способ сообщить, что вы хотите, чтобы приложение перезапустилось в результате развертывания.

Можно ли иметь файл "apprestart", чтобы пометить приложение для повторного использования, не удаляя впоследствии файл appoffline?

@ Соколин, почему это так?

@ Соколин, почему это так?

Если я хорошо понимаю (скажите, если я ошибаюсь), вы планируете снять блокировку, но нам все равно придется создать приложение в автономном режиме, чтобы сигнализировать IIS о необходимости перезапуска приложения после завершения сборки?

Для этого нам нужно создать файл appoffline, а затем удалить его. Можно ли удалить этот файл сразу после его создания? или нам следует подождать, пока IIS его обнаружит? Если требуется немного подождать, я бы предпочел иметь файл типа "apprestart", который IIS будет прослушивать, а затем удалить, как только он его обнаружит, и начать переработку.


Кроме того, у меня есть еще один вопрос. Речь идет об оптимизации IDE во время сборки.

В настоящее время я работаю над проектом, который использует зависимости, у нас есть проект для веб-слоя и другой проект для логики и данных. Когда я работаю на веб-уровне (ASP.NET Core) во время сборки, я создаю файл appoffline перед сборкой, затем удаляю его после сборки, и он работает.

Но когда я работаю с одной из зависимостей, когда я создаю их из Rider (я думаю, что он делает то же самое в VS, поскольку он использует msbuild), когда я смотрю, что делает msbuild, после завершения сборки проекта dll копируется непосредственно в каталог .Web / bin без перекомпоновки проекта .Web. А поскольку dll заблокирована, она молча выходит из строя, и мне приходится вручную перезапускать сервер или вручную запускать сборку проекта .Web.

Есть ли у вас какое-нибудь решение?
На данный момент я нашел обходной путь - написать небольшую программу, работающую в фоновом режиме, которая ищет / bin моего проекта .Web. При изменении файла он создает файл appoffline в каталоге, где IIS прослушивает, затем копирует измененные файлы, а затем удаляет appoffline. Но это кажется немного взломанным, но пока что это единственный способ, который я нашел, чтобы собрать, затем нажмите F5 и проверьте мои изменения.

Для этого нам нужно создать файл appoffline, а затем удалить его. Можно ли удалить этот файл сразу после его создания? или нам следует подождать, пока IIS его обнаружит? Если требуется немного подождать, я бы предпочел иметь файл типа "apprestart", который IIS будет прослушивать, а затем удалить, как только он его обнаружит, и начать переработку.

Как IIS узнает, что вы закончили копирование файлов? Как избежать рваного состояния? Вам в основном нужно сигнализировать о начале и завершении транзакции. Создание файла означает начало, а удаление - конец.

Есть ли у вас какое-нибудь решение?
На данный момент я нашел обходной путь - написать небольшую программу, работающую в фоновом режиме, которая ищет / bin моего проекта .Web. При изменении файла он создает файл appoffline в каталоге, где IIS прослушивает, затем копирует измененные файлы, а затем удаляет appoffline. Но это кажется немного взломанным, но пока что это единственный способ, который я нашел, чтобы собрать, затем нажмите F5 и проверьте мои изменения.

VS обрабатывает это, убивая процесс перед запуском нового файла для всего, что может повлиять на сборку этого проекта.

Для этого нам нужно создать файл appoffline, а затем удалить его. Можно ли удалить этот файл сразу после его создания? или нам следует подождать, пока IIS его обнаружит? Если требуется немного подождать, я бы предпочел иметь файл типа "apprestart", который IIS будет прослушивать, а затем удалить, как только он его обнаружит, и начать переработку.

Как IIS узнает, что вы закончили копирование файлов? Как избежать рваного состояния? Вам в основном нужно сигнализировать о начале и завершении транзакции. Создание файла означает начало, а удаление - конец.

Если блокировки нет, зачем уведомлять IIS при запуске сборки? Разве мы не можем просто сигнализировать, когда все файлы обновлены и приложение нужно переработать? Думаю, я что-то неправильно понял.

Если блокировки нет, зачем уведомлять IIS при запуске сборки? Разве мы не можем просто сигнализировать, когда все файлы обновлены и приложение нужно переработать? Думаю, я что-то неправильно понял.

Да, это сработает. Я думал, вы описываете текущее состояние дел. Возможно, это даже можно сделать сегодня с помощью web.config. Если коснуться файла, приложение перезагрузится.

У меня было успешное развертывание на месте (https://flukefan.github.io/ZipDeploy/):

  1. Переименовать файлы сборки (видимо, вы можете переименовать, даже если вы не можете удалить / перезаписать);
  2. Скопируйте в новые сборки;
  3. Коснитесь веб-конфигурации, чтобы перезапустить приложение;
  4. Удалите старые переименованные сборки.

Нет балансировки нагрузки; единственный экземпляр IIS; никаких изменений IIS. YMMV.

@FlukeFan Как избежать разрыва при развертывании или это вас не беспокоит? Под разрывом я подразумеваю, что есть окно, в котором старое приложение загружает новую сборку перед перезапуском приложения.

Я не трогаю web.config, пока все сборки не будут переименованы / обновлены. Я предполагаю, что есть небольшая вероятность того, что что-то еще может вызвать перезапуск пула приложений в течение этого времени, но этого еще не произошло.

Я обычно отключаю все остальные параметры автоматической перезагрузки, а также отключаю перекрывающуюся перезагрузку в настройках пула приложений IIS.

@FlukeFan не является переработкой, но если вы еще не загрузили замененную сборку. Например, предположим, что у вас есть сборка A.dll и B.dll. Допустим, B используется, когда вы переходите на страницу настроек, поэтому затем загружается. Если вы перешли на страницу настроек, когда B.dll был заменен новым, вы могли бы получить старое приложение, работающее с новым B.dll.

Мне действительно интересно, стоит ли нам создать глобальный инструмент dotnet для помощи в этом типе развертывания. Инструмент может в основном делать все сложные вещи, о которых люди упоминали в этой теме.

Мысли?

@FlukeFan не является переработкой, но если вы еще не загрузили замененную сборку. Например, предположим, что у вас есть сборка A.dll и B.dll. Допустим, B используется, когда вы переходите на страницу настроек, поэтому затем загружается. Если вы перешли на страницу настроек, когда B.dll был заменен новым, вы могли бы получить старое приложение, работающее с новым B.dll.

Так что я сейчас не занимаюсь этим делом. https://github.com/FlukeFan/ZipDeploy/blob/master/ZipDeploy/ZipDeploy.cs#L55

Думаю, я мог бы сделать что-то в другом порядке, сначала прикоснуться к web.config, дождаться завершения всех «других» запросов, а затем, наконец, выполнить замену непосредственно перед завершением последнего запроса (в то время как IIS ставит в очередь новые запросы для приближающегося recycle app-pool), но то, что у меня есть, работает для меня только сейчас.

Вероятно, в настоящее время он недостаточно надежен для сценария, который вы описываете (но я не делал ничего особенного с динамической загрузкой сборки, кроме как во время запуска).

Есть ли планы пересмотреть эту функцию и включить ее в дорожную карту? Очень неудобно / недружелюбно требовать от всех, кто развертывает веб-сайт .Net Core, вручную реализовывать стратегию промежуточных слотов, если они хотят поддерживать развертывания с нулевым временем простоя.

Наличие этой функции сделало бы переход на веб-сайты .Net Core намного более плавным для многих людей и позволило бы быстрее внедрить веб-сайты .Net Core.

Никогда об этом не думал. Но вы вполне могли попасть в самую точку. Это могло быть гнусным бизнес-решением, заставляющим людей использовать лазурные слоты. Если в прошлом это было возможно, почему на «исправление» потребовалось так много времени? Это не нарушено с точки зрения бизнеса. Может, я немного циничен. Но я медленно наблюдал за лазурными функциями, которые раньше были бесплатно убраны и перемещены на более дорогие уровни.

Мне действительно интересно, стоит ли нам создать глобальный инструмент dotnet для помощи в этом типе развертывания. Инструмент может в основном делать все сложные вещи, о которых люди упоминали в этой теме.

Мысли?

Это должно работать на сервере CI, скажем? Как бы он отправил двоичные файлы / пакет на целевой сервер?

Никогда об этом не думал. Но вы вполне могли попасть в самую точку. Это могло быть гнусным бизнес-решением, заставляющим людей использовать лазурные слоты. Если в прошлом это было возможно, почему на «исправление» потребовалось так много времени? Это не нарушено с точки зрения бизнеса. Может, я немного циничен. Но я медленно наблюдал за лазурными функциями, которые раньше были бесплатно убраны и перемещены на более дорогие уровни.

Развертывание на месте без согласования принципиально ненадежно по причинам, указанным выше. Мы никогда больше не собираемся внедрять теневое копирование, потому что эта функция исторически была ненадежной и вызывала множество проблем в ASP.NET на платформе .NET. Он также работает только для определенного типа развертывания, зависящего от платформы, которая поддерживается всей .NET Framework. Ядро .NET поддерживает автономный и отдельный файл, что значительно усложняет его поддержку. Даже приведенное выше предложение не распространяется на эти случаи.

Мы по-прежнему считаем, что развертывание на месте должно быть как можно более атомарным, и многие проблемы в этом вопросе возникают из-за ошибок и ненадежности обнаружения и повторного использования app_offline, поэтому мы потратили много времени на исправление этого (а также блокировку pdb).

Веб-развертывание - единственный сегодня инструмент, который воплощает поток, который, по нашему мнению, имеет смысл развертывать, но он застрял в этой технологии, поэтому он не помогает, если вы выполняете развертывание по ftp на свои серверы или копируете в общий файловый ресурс (хотя он мог).

Ответом здесь может быть глобальный инструмент dotnet.

Это должно работать на сервере CI, скажем? Как бы он отправил двоичные файлы / пакет на целевой сервер?

Я так не думаю. Вероятно, он будет поддерживать FTP и прямую копию. Все остальное, скорее всего, является проприетарным протоколом.

Надеюсь, когда вы говорите FTP, вы также имеете в виду ftp over ssh. Такой инструмент был бы очень ценным.

Надеюсь, когда вы говорите FTP, вы также имеете в виду ftp over ssh. Такой инструмент был бы очень ценным.

Нет, я имел ввиду ftp. Но мы сделали бы то, что имело смысл. Может быть, лучше быть инструментом копирования, который вам нужно запустить на целевой машине. Это избавляет нас от необходимости отправлять биты куда угодно.

Также вы подключаетесь к своим машинам с Windows по SSH для развертывания в IIS?

@davidfowl Добавьте (
https://github.com/dotnet/aspnetcore/issues/3719#issuecomment -473183712
https://github.com/dotnet/aspnetcore/issues/3793#issuecomment -335666414

Мы планируем изучить загрузку сборок приложений в память в виде байтов вместо загрузки их с диска и блокировки файла. В большинстве случаев это нормально, но в некоторых случаях может привести к большему использованию памяти .

Более того, это не позволит нам добиться нулевого времени простоя.

Мы не собираемся вкладывать средства в подобную функцию с модулем.

Надеюсь, когда вы говорите FTP, вы также имеете в виду ftp over ssh. Такой инструмент был бы очень ценным.

Нет, я имел ввиду ftp. Но мы сделали бы то, что имело смысл. Может быть, лучше быть инструментом копирования, который вам нужно запустить на целевой машине. Это избавляет нас от необходимости отправлять биты куда угодно.

Также вы подключаетесь к своим машинам с Windows по SSH для развертывания в IIS?

Да. Мы используем CI / CD и развертываем как в системах Linux, так и в Windows, поэтому было намного проще установить openssh в окнах Windows.

$ appPool = 'по умолчанию'
Stop-WebAppPool -Name $ appPool -Passthru
... развернуть ...

Start-WebAppPool -Name $ appPool -Passthru
... развернуть .....

или же

$ appPool = 'по умолчанию'
Stop-WebAppPool -Name $ appPool
while ((Get-WebAppPoolState -Name $ appPool) .Value -ne 'Stop') {
сон 1 # секунда
}
... развернуть ...

Start-WebAppPool -Name $ appPool
while ((Get-WebAppPoolState -Name $ appPool) .Value -ne 'Start') {
сон 1 # секунда
}

... развернуть .....

Слоты развертывания бедных мужчин
Около года назад я писал о создании двух корневых папок сайта и имел точку символической ссылки на одну из них, настроенную для сайта IIS.
Преимущество заключается в том, что ваше время простоя меньше по сравнению с другими более простыми решениями.
Если перекрывающаяся перезагрузка включена, то время простоя отсутствует, только штраф за прогрев для первого запроса, что в любом случае имеет место.

Если операция развертывания / копирования занимает N секунд, вам не нужно останавливать пул приложений на N секунд.
Не стоит возиться с сомнительным приложением в автономном режиме.
Просто скопируйте в неактивную папку, замените символическую ссылку, когда файлы там, а затем перезапустите пул приложений.
Атомарное развертывание, без простоев, просто медленный первый запрос, как обычно.

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

Кто-нибудь пробовал?
Если что-то подобное сработает, то его можно превратить в сервис с помощью инструмента развертывания на стороне клиента.

  • клиент -> сервер, что это за неактивная папка / общий ресурс?
  • S: здесь
  • C: нормально развернуто / скопировано
  • S: символическая ссылка заменена и переработана
  • C: thx, http get / healthcheck (необязательно)
  • C: тьфу я напортачил, откатитесь пожалуйста
  • S: обмен символическими ссылками, переработка (снова в бизнесе)
  • C: повторять полоскание, пока не сработает

Так что у меня также возникла проблема с заблокированными файлами при развертывании. в хостинге приложений. Я попытался остановить пул приложений, но файлы остались заблокированными. Я попытался нажать app_offline.htm, но и там не повезло.
Также, если вы хотите управлять удалением файла app_offline.htm, вы можете легко сделать это при запуске приложения в program.cs. Таким образом мы узнаем, когда он запускается, он становится онлайн.

Текущая проблема, с которой я сталкиваюсь, заключается в том, что библиотеки DLL зависают, и даже если вы переименовываете, а затем копируете файлы, старый процесс все еще работает с переименованными файлами. Поэтому, когда мы попытаемся выполнить повторное развертывание, нам придется снова переименовать файлы. Думаю, мы могли бы использовать какую-то дату в качестве замены имени файла.
Мы используем dotnet core 3.1.4 для этого на сервере IIS Windows 2012 R2

@foxjazz, как файлы остаются заблокированными, если пул / процесс приложений остановлен? Вы можете уточнить?

@foxjazz, как файлы остаются заблокированными, если пул / процесс приложений остановлен? Вы можете уточнить?

image

image

При попытке удалить использованные библиотеки DLL на картинке говорится, что используется другим процессом.
Пул приложений какое-то время был отключен.

Проверьте диспетчер задач, чтобы узнать, выполняется ли процесс. Нажатие кнопки остановки не означает, что она немедленно прекращается.

Проверьте диспетчер задач, чтобы узнать, выполняется ли процесс. Нажатие кнопки остановки не означает, что она немедленно прекращается.

изображение выше из диспетчера задач. Не уверен, какой именно, но если я удалю их, он освободит файл. Думаю, я могу использовать дескриптор, чтобы определить pid для завершения. Я не думал, что мне придется идти на все это для развертывания. Дескриптор говорит, что в процессе w3wp.exe 2 заблокирован один из файлов. даже если пул приложений для него закрыт.

Что было бы действительно хорошо, так это иметь способ остановить процесс.
api \ KillDeathKill
{
Program.KillProcess ()
}

Это маловероятно. Файл заблокирован процессом. Если этим процессом является w3wp, то он либо никогда не был убит с самого начала, либо был создан новый с другим pid, блокирующим тот же файл. Вот почему вам нужно сначала убедиться, что приложение отключено, чтобы убедиться, что нет нового процесса для блокировки файла, уничтожения существующего процесса, развертывания новых битов, удаления приложения в автономном режиме.

Это маловероятно. Файл заблокирован процессом. Если этим процессом является w3wp, то он либо никогда не был убит с самого начала, либо был создан новый с другим pid, блокирующим тот же файл. Вот почему вам нужно сначала убедиться, что приложение отключено, чтобы убедиться, что нет нового процесса для блокировки файла, уничтожения существующего процесса, развертывания новых битов, удаления приложения в автономном режиме.

когда вы говорите, что app_offline.htm не работает первым. Да, это было так. У меня есть путь к статусу, который я могу проверить с помощью запроса на получение, и он определенно не в сети. Также остановил пул приложений вручную. Но процесс w3wp все еще висел файл.

Тогда процесс не остановился

Тогда процесс не остановился

Так почему же остановка пула приложений, а не остановка процесса?

Пул приложений действительно представляет процесс, и если вы остановите пул приложений, он остановит процесс. Файл не может быть заблокирован, если нет процесса для его блокировки, поэтому одна из этих теорий кажется более вероятной.

Пул приложений действительно представляет процесс, и если вы остановите пул приложений, он остановит процесс. Файл не может быть заблокирован, если нет процесса для его блокировки, поэтому одна из этих теорий кажется более вероятной.

ха, ты сказал дерьмо. Я не хочу показаться, будто бью тебя. Я говорю, что остановка пула приложений НЕ работает так, как рекламируется во всей документации. Процесс не гадит, даже через 90 секунд все еще работает. Файл заблокирован, даже если вы четко видите, что пул приложений остановлен. Процесс содержит синглтон для получения данных. И другие контроллеры. Было бы неплохо иметь скрипт, который бы останавливал процесс на основе заблокированного файла. Тогда я смогу развернуться без страха. Переименование также может работать. Файлы можно переименовывать. (ядро dotnet 3.1.4) аромат

Около года назад я писал о создании двух корневых папок сайта и имел точку символической ссылки на одну из них, настроенную для сайта IIS.

Кто-нибудь пробовал?
Если что-то подобное сработает, то его можно превратить в сервис с помощью инструмента развертывания на стороне клиента.

@CJHarmath - Я попробовал, и у меня есть модифицированный код, который я использую ниже. Работает очень хорошо, спасибо!

Если бы я публиковал больше обновлений, я мог бы рассмотреть инструмент развертывания клиента, но на самом деле я могу просто удалить оболочку на сервер IIS и выполнить сценарий PowerShell, чтобы перевернуть его.
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"

Это также можно превратить в конечную точку JEA , чтобы вы могли запустить flip как пользователь без повышенных прав (например, на этапе развертывания сервера CI / CD)
Invoke-Command -ComputerName IIS_SERVER -ConfigurationName IIS-Flip -ScriptBlock { Switch-SymlinkTarget -SiteName MySite}
Использовал Switch вместо Flip поскольку это утвержденный глагол.

Использовал Switch вместо Flip поскольку это утвержденный глагол.

Swap - это глагол, используемый при работе со слотами - кажется, имеет смысл использовать здесь повторно?

с той же проблемой, что описана 4 года назад.
Есть новости по этому поводу?
Я не хочу открывать удаленный рабочий стол, чтобы просто загрузить новый файл dll.

Когда я пытаюсь перезаписать файл DLL приложения .NET Core с помощью FTP на рабочем сервере, файл IIS блокируется и не может быть перезаписан.

Чтобы развернуть новую версию, мне нужно остановить приложение в IIS (открытие RDP), чтобы снять блокировку, а затем перезаписать.
Развернуть без остановки приложения невозможно.

Любое решение для этого? благодаря

Если вы не можете отключить свой хост за балансировщиком нагрузки и хотите сделать это быстрее, вот один из способов с символическими ссылками и некоторой оболочкой PowerShell.
Я думал о том, чтобы сделать что-то подобное.

Это быстрее, так как вам не нужно останавливать пул приложений во время копирования + перезапись лучше, чем жесткая остановка, поскольку она позволяет завершать текущие запросы, что сокращает время простоя.

# 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

Вот суть
https://gist.github.com/csharmath/b2af0f50700ce9fbdd8c5c3e582fd41b

Вот кое-что, что, как мне кажется, я исправил. Я пробовал только с ASP.NET, но полагаю, будет работать так же с модулем хостинга для ядра сети. Первый запуск действительно останавливает сайт на некоторое время, поэтому, возможно, вы захотите немного его настроить.

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 что это? код cmd? где мне добавить этот код?
благодаря

Как насчет идеи увеличения количества повторных попыток (параметр: -retryAttempts:X ) или временного интервала повторных попыток (параметр: -retryInterval:XXXX ) для команды msdeploy , пока процесс не освободит блокировка файла?

Я думаю, что @davidfowl прав, процесс все еще как-то там и блокирует файлы. Даже Reset IIS не помогает, все равно ждёт процесс до таймаута. Если вы удалите app_offline.htm и подождите 90 секунд (время ожидания по умолчанию для выключения AppPool) и повторите попытку, вы увидите, что он работает.
Для меня на локальном компьютере я не хочу так долго ждать, поэтому я обновил этот предел времени выключения (в секундах) до 5 и обновил файл проекта, чтобы сгенерировать
Для сервера я использую msdeploy, чтобы удалить app_offline.htm, синхронизировать новую версию, а затем удалить app_offline.htm. С msdeploy он повторяет попытку, если файлы заблокированы, но когда-то сдавался до 90 секунд, поэтому мне нужно снова запустить развертывание, тогда он работает со второй попытки

Есть новости об этом? Когда будет готов этот новый релиз?

Спасибо что связались с нами.
Мы переносим эту проблему на этап Next sprint planning для будущей оценки / рассмотрения. Мы оценим запрос, когда будем планировать работу на следующем этапе. Чтобы узнать больше о том, чего ожидать дальше и как будет решена эта проблема, вы можете узнать больше о нашем процессе сортировки здесь .

Об этой проблеме я узнал на этой неделе, после преобразования приложения .NET 4.5.2 в .NET 5.0. У меня есть другой подход, чтобы преодолеть это. Я создал службу Windows, работающую на сервере IIS. В этой службе у меня есть простой HTTP-сервер, работающий на настраиваемом порту. Веб-приложение может выполнять пост-запрос к этому серверу, чтобы инициировать обновление. Он останавливает пул приложений, чтобы убить все процессы для этого приложения, создать резервную копию текущего выпуска, удалить текущий выпуск, загрузить пакет обновления и извлечь его. Затем снова запускает app-pool.

Я создал простое приложение Windows Forms для создания пакетов обновления, которые отправляются в репо, из которого извлекается вышеупомянутая служба Windows.

Была ли эта страница полезной?
0 / 5 - 0 рейтинги