Vypublikovat hotovou ASP.NET aplikaci na server přes FTP nebo Web Management Service je snadné: stačí ve Visual Studiu vytvořit publishing profil a klepnout na Publish. Ale co když chcete aplikaci nasadit na server s Linuxem, kde chcete použít SCP, třeba na Raspberry Pi z našeho seriálu? Je to možné, ale vyžaduje to trochu ručních zásahů do projektového souboru.

Tento článek vznikl na základě dotazu, který mi poslal čtenář tohoto blogu Michal Krchnavy. Budiž vám to inspirací: pokud máte nějaké dotazy nebo náměy, napište mi. Nezaručuji vám odpověď, ale možná z toho bude článek. Pokud chcete mít radu s jistotou, nabízím placené konzultace.

Předpoklady

Níže popsaný postup je možné použít pro jakoukoliv aplikaci a jakýkoliv server, na který se lze připojit přes SSH, potažmo kopírovat soubory přes SCP. Aby fungoval jak je popsán, musíte mít nastavenu autentizaci výchozím SSH klíčem a tento klíč nesmí být chráněn lokální passphrasí (heslem).

Tento postup také smaže všechny soubory ve vzdáleném adresáři a nahraje tam nové, což nemusí být zcela žádoucí, jak bude popsáno dále.

Postup

Pozor, následující text je zastaralý. V současnosti už existuje 64-bitový MSBuild, kde lze již SSH a SCP volat přímo.

Připravil jsem návod, jak z publishing profilu kompletně administrovat celé nasazení, včetně zastavení webu atd. Najdete ho ve videu na kanálu Z-TECH nebo v bezplatném online školení.

Publishing profily (soubory ~/Properties/PublishProfiles/*.pubxml) jsou ve své podstatě standardní MSBuild projektové soubory. Můžeme tedy celkem snadno přidat akci, která se spustí ve správný okamžik při zpracování tohoto souboru, v tomto případě po dokončení publikování.

Začněte tím, že vytvoříte standardní publishing profil, který bude publikovat do složky. Jak, to jsem popisoval ve třetím dílu seriálu o běhu ASP.NET na Raspberry Pi. Otevřete výsledný soubor a téměř na jeho konec (před uzavírací tag </Project>) přidejte následující kód:

<Target Name="ScpUploadAfterPublish" AfterTargets="AfterPublish">
    <PropertyGroup>
        <SshUserName>pi</SshUserName>
        <SshServerName>10.7.0.126</SshServerName>
        <SshServerPath>~/AskMe/</SshServerPath>
    </PropertyGroup>
    <Exec Command="%WINDIR%\sysnative\cmd /C ssh $(SshUserName)@$(SshServerName) &quot;rm -rf $(SshServerPath)*&quot;" />
    <Exec Command="%WINDIR%\sysnative\cmd /C scp -r &quot;$(PublishDir)*&quot; &quot;$(SshUserName)@$(SshServerName):$(SshServerPath)&quot;" />
</Target>

Jeho název (Name) může být jakýkoliv, ale důležité je, aby atribut AfterTargets měl hodnotu AfterPublish. V elementu PropertyGroup pak definujeme tři proměnné (nenechte se zmást tím, že vám je IntelliSense podtrhá jako neznámé):

Následující dva elementy Exec pak smažou všechno, co na serveru je a nahrají tam aktuální verzi. Nejprve se pomocí SSH vzdáleně zavolá příkaz rm -rf ~/AskMe/*, který smaže veškerý obsah adresáře, ale ne adresář samotný. Potom se pomocí SCP do téhož adresáře nahraje výsledek publishingu.

Možné zákeřnosti a úpravy

Nepodařilo se mi přijít na způsob, jak přesměrovat výstup ze SCP do konzole Visual Studia. V průběhu publikace tedy není vypisován žádný průběh, což může působit dojmem, že se proces někde zasekl. Buďte trpěliví.

Tento kód předpokládá, že bude spouštěn na 64-bitovém počítači z Visual Studia, v němž běží 32-bitový MSBuild, což je výchozí nastavení. Z tohoto důvodu používám ono podivné volání %WINDIR%\sysnative\cmd /C, protože příkazy scp a ssh jsou 64-bitové a normálně pro 32-bitový MSBuild nejsou vidět.

Při nasazení postupuji tak, že na serveru úplně všechno smažu a nahraju tam novou vypublikovanou verzi. Což nemusí být úplně dobrý nápad, například ve chvíli, kdy se v adresáři aplikace nacházejí nějaká aplikační data, jako třeba SQLite databáze v App_Data/ask.db v případě ukázkové aplikace AskMe. Nejjednodušší řešení v tomto případě je ukládat data někam jinam, mimo adresář do kterého se nasazuje.

Uvedený postup také není úplně nejefektivnější. Mnohem lepší by bylo třeba použít rsync, ale ten (zatím?) na Windows není standardně dostupný.

Pomocí syntaxe ssh user@server "..." můžete vzdáleně na serveru vykonat jakýkoliv příkaz. Lze tedy například po dobu nasazování ručně zastavit službu Kestrelu nebo nějak jinak zkonfigurovat, aby se po dobu nasazování ukázala nějaká hláška typu "aplikace se právě aktualizuje".