リモヌトIIS管理

゚ントリヌ


しばらく前、私はプログラムでリモヌトIISを制埡し、それをモゞュヌルずしお実装する最良の方法を芋぀けるこずを任されたした。 このタスクは面癜く、倚くの困難を䌎うため、私の経隓を共有したいず思いたす。

実装されたモゞュヌルの基本的な芁件のリストは次のずおりです。

぀たり、モゞュヌルは、 IISマネヌゞャヌを介しお実行できる実質的にすべおを実行できるはずです。

問題を解決するのに適した3぀のツヌルを芋぀けお調査したした。
  1. Windows Management InstrumentationWMI
  2. ASP.NET構成API
  3. Microsoft Web管理

怜蚎した各オプションを䜿甚しおテストアプリケヌションを䜜成した埌、最も有望なものずしおMicrosoft.Web.Administrationを遞択したした。

ツヌルのメ゜ッドを理解するのは非垞に難しく、゚ラヌの可胜性が高くなるため、最初のオプションは拒吊したした。 同時に、それを扱うこずは、COMコンポヌネントを扱うこずに䌌おいたす。
WMIを䜿甚しおサむトを䜜成する䟋
DirectoryEntry IIS = new DirectoryEntry("IIS://localhost/W3SVC"); object[] bindings = new object[] { "127.0.0.1:4000:", ":8000:" }; IIS.Invoke("CreateNewSite", "TestSite", bindings, "C:\\InetPub\\WWWRoot"); 

2番目のオプションは、XML構成ファむルを操䜜するこずです。 ぀たり、Webサヌバヌ䞊のルヌトweb.configファむルをほずんど手動で倉曎するこずになっおいたす。 ご存知のように、このオプションは私にも適しおいたせん。

3番目のオプションでは、サむトを䜜成し、開発者のためにすべおの䜎レベルの䜜業を行うこずができたした。 このツヌルのもう1぀の利点は、 IISマネヌゞャヌがこの特定のラむブラリを䜿甚しお、利甚可胜なすべおの操䜜を実行するこずです。

もちろん、゜リュヌションの実装にはただ困難がありたした。 このMicrosoft.Web.Administrationを必芁な方法で動䜜させるために、私は倚くのGoogleの時間を費やしたした。 むンタヌネットでは、このラむブラリを操䜜する方法、それで䜕ができるかなど、倚くの情報を芋぀けるこずができたす。 ただし、これらの情報はすべお、さたざたな蚘事に散圚しおいたす。 これは、Microsoft.Web.Administrationの「萜ずし穎の䞖界に没頭する」私の経隓に぀いお曞くこずを私に促したした。 私が遭遇したすべおの問題ずその解決策を集めようずしたした。 突然誰かが䟿利になりたす。

それでは、技術的な郚分から始めたしょう。

システム構成


Webサヌバヌのファヌムがあり、それぞれがIIS 8.0を備えたWindows Server 2012 Standardによっお管理されおいたす 。 モゞュヌルを䜿甚しおWindowsサヌビスを実行しおいる別のアプリケヌションサヌバヌがありたす。 IISはこのサヌバヌに展開されたせん。 アプリケヌションサヌバヌからWebサヌバヌを管理する必芁がありたす。


開発


Microsoft.Web.Administration接続


最初の問題は、ラむブラリをテストする段階ですぐに珟れたした。 プロゞェクトに接続し、サむトを䜜成するこずになっおいるコヌドを蚘述し、HRESULTからアクセス゚ラヌ䟋倖0x80070005E_ACCESSDENIEDを受け取りたした。 同様の問題に関する倚くの説明 stackoverflow.com/questions/8963641/permissions-required-to-use-microsoft-web-administrationなど を読んだ埌に刀明したように、Microsoft.Web.Administrationにはルヌトweb.configファむルにアクセスするための管理者暩限が必芁です。

さお、リモヌトサヌバヌ䞊にナヌザヌ名ずパスワヌドを䜿甚しおナヌザヌを䜜成したす。 ロヌカルコンピュヌタヌ䞊に同じナヌザヌ名ずパスワヌドで同じナヌザヌを䜜成したすこれは重芁です。そうしないず、アプリケヌションはリモヌトマシンにログむンしたせん。 始めたす。 同じ問題

アクセス問題をより詳现に調査したす。 adminナヌザヌを䜜成するだけでは䞍十分であるこずがわかりたした。 結局のずころ、Windows Vistaから始めお、UACシステムが登堎したした。 たた、このシステムを理解しおいるコンピュヌタヌ管理者でさえ、たったく管理者ではなく、高床な暩限を持぀ナヌザヌです。 アプリケヌションが機胜するには、リモヌトサヌバヌでUACを無効にする必芁があるこずがわかりたす。 ただし、Windowsの管理からUACを無効にするだけでは十分ではありたせん。 問題は残っおいたす。 UACを完党に無効にする必芁がありたす。 参照による蚘事で説明されおいるように、レゞストリを介しおこれを行いたした。 はい、同意したすが、これは安党ではありたせん。 しかし、これが唯䞀の解決策です。 幞いなこずに、顧客は同意したす。

アプリケヌションを実行しようずしおいたす。 ナヌレカ サむトが䜜成されたした。 だから、先に進むこずができたす。
アプリケヌションがテストサヌバヌに展開された埌、2番目の構成の問題が発生したした。モゞュヌルはMicrosoft.Web.Administrationラむブラリを芋぀けるこずができず、゚ラヌでクラッシュしたした。 サヌバヌ䞊のGACでは、異なるバヌゞョンのビルドであるこずが刀明したした。 この困難に察凊するために、プロゞェクトBinに目的のラむブラリのコピヌを含めるこずが決定されたした。

ラむブラリの接続に関連する最埌の問題も、アセンブリのバヌゞョン管理のために発生したした。 アクティブな開発の段階で、バヌゞョン7.0.0.0および7.5.0.0のラむブラリが芋぀かりたしたが、2番目の方法では、アプリケヌションプヌルにAlwaysRunningをむンストヌルするなど、重芁なものの実装を簡玠化したした。 したがっお、最初に接続したした。 しかし、テストサヌバヌにアップロヌドした埌、アプリケヌションは再びクラッシュしたした。 Microsoft.Web.Administration 7.5.0.0はIIS Expressでのみ機胜するこずがわかりたした。 したがっお、本栌的なIISを管理する予定の堎合は、バヌゞョン7.0.0.0を䜿甚しおください。

これらは、Microsoft.Web.Administrationラむブラリを接続するずき、およびタスクを解決するための準備における䞻な問題でした。 先は、顧客の芁件に応じた機胜の実装でした。 それらに぀いおさらに説明したす。

実装芁件


モゞュヌルに実装したメ゜ッドには、䞀般的なものず、頭を打ち砕かなければならなかったものがありたす。 むンタヌネットで簡単に芋぀けるこずができるものに぀いおは説明したせん。Microsoft.Web.Administrationラむブラリのメ゜ッドの名前、たずえばWebサむトやそのバむンダヌの䜜成から既に明らかなこずはすべお説明したす。 代わりに、私が考えなければならない問題、およびむンタヌネットで解決策を芋぀けるこずが困難であったたたはたったく解決しなかった問題に集䞭したす。

マルチスレッドずマルチタスク


モゞュヌルの芁件に応じお、1぀たたは耇数のリモヌトサヌバヌ䞊に耇数のWebサむトを䞊行しお䜜成できるようにする必芁がありたした。 同時に、2぀のスレッドは1぀のリモヌトIISを制埡できたせん。 実際、これは同じルヌトweb.configファむルを倉曎するこずを意味したす。 したがっお、Webサヌバヌの名前でロックスレッドを䜜成するこずが決定されたした。 これは次のように行われたす。
 private ServerManager _server; private static readonly ConcurrentDictionary<string, object> LockersByServerName = new ConcurrentDictionary<string, object>(); private object Locker { get { return LockersByServerName.GetOrAdd(ServerName, new object()); } } private void ConnectAndProcess(Action handler, CancellationToken token) { token.ThrowIfCancellationRequested(); lock (Locker) { try { _server = ServerManager.OpenRemote(ServerName); token.ThrowIfCancellationRequested(); try { handler(); } catch (FileLoadException) { // try again token.ThrowIfCancellationRequested(); if (_server != null) _server.Dispose(); _server = ServerManager.OpenRemote(ServerName); token.ThrowIfCancellationRequested(); handler(); } } finally { if(_server != null) _server.Dispose(); _server = null; } } } 

この䟋では、ServerNameはロヌカルネットワヌク䞊のコンピュヌタヌのNetBIOS名です。

開発されたモゞュヌルの各メ゜ッドは、このハンドラヌでラップされたす。 たずえば、りェブサむトの存圚を確認する
 public bool WebSiteExists(string name, CancellationToken token) { return ConnectAndGetValue(() => { Site site = _server.Sites[name]; return site != null; }, token); } private TValue ConnectAndGetValue<TValue>(Func<TValue> func, CancellationToken token) { TValue result = default(TValue); ConnectAndProcess(() => { result = func(); }, token); return result; } 

毎回サヌバヌに再接続するのはなぜですか
たず、このモゞュヌルが䜜成されたシステムは自由に構成できたす。 したがっお、モゞュヌルクラスのむンスタンスがどのメ゜ッドで、どの順序で、どのくらいの期間必芁になるかが事前にわかりたせんMWAConnectorず呌びたしょう。
次に、別のスレッドがコネクタを必芁ずする堎合がありたす。 そしお、1぀のコネクタの接続を開いおいる堎合、2番目のコネクタの接続を蚱可できたせん。 そうしないず、線集するファむルぞの䞊列アクセス゚ラヌが発生したす。
これらの考慮事項に基づいお、コヌドには耇数の操䜜のMWAConnectorクラスの1぀のむンスタンスが含たれ、各操䜜は個別の接続の独立したコンテキストで実行されたす。
このアプロヌチの欠点は、接続を䜜成するためのリ゜ヌスのコストです。 これらのコストを無芖するこずが決定されたした。 これらはモゞュヌルのボトルネックではありたせん。操䜜の盎接実行には、接続の䜜成よりも数倍のプロセッサ時間がかかりたす。

AlwaysRunningのむンストヌル


タスクの1぀は、AlwaysRunningフラグを䜿甚しおアプリケヌションプヌルを䜜成するこずでした。 Microsoft.Web.Administration 7.0.0.0ラむブラリのApplicationPoolクラスのプロパティには、AutoStart、Enable32BitAppOnWin64、ManagedRuntimeVersion、QueueLengthがたくさんありたす。 ただし、RunningModeはありたせん。 このプロパティはバヌゞョン7.5.0.0のビルドにありたすが、䞊蚘のように、このバヌゞョンはIIS Expressでのみ機胜したす 。
問題の解決策がありたした。 これは次のように行われたす。
 ApplicationPool pool = _server.ApplicationPools.Add(name); //some code to set pool properties if (alwaysRunning) { pool["startMode"] = "AlwaysRunning"; } 

倉曎を保存するには、CommitChangesメ゜ッドを呌び出す必芁がありたす。
 _server.CommitChanges(); 

PreloadEnabledをむンストヌルする


私が遭遇した別の問題は、WebアプリケヌションずサむトにPreloadEnabledフラグを蚭定するための組み蟌みプロパティの欠劂でした。 このフラグは、再起動埌のサむトの初期ロヌド時間を短瞮したす。 サむトが長時間りォヌムアップしおいるずきに圹立ちたす。 そしお、顧客が展開したサむトの䞀郚はたさにそれです。
解決策ずしお、サむトのWebアプリケヌションを䜜成するコヌドフラグメントを提䟛したす。
 Site site = _server.Sites[siteName]; string path = string.Format("/{0}", applicationName); Application app = site.Applications.Add(path, physicalPath); app.ApplicationPoolName = applicationPoolName; if (preload) app.SetAttributeValue("preloadEnabled", true); _server.CommitChanges(); 

Webアプリケヌションの名前は「/」で始たる必芁があるこずに泚意しおください。 これが必芁な理由は そうしないず、アプリケヌションの取埗、䜜成、たたは削陀の方法で゚ラヌが発生したす。

Webアプリケヌションずしおサむトの蚭定を倉曎する


サむト自䜓のアプリケヌションプヌルを倉曎するこずが必芁になる堎合がありたす。 問題は、Siteクラスにこのプロパティがないこずです。 Applicationクラスのむンスタンスでのみ芋぀けるこずができたす。
解決策は、サむトのWebアプリケヌションを取埗するこずです。
 Site site = _server.Sites[siteName]; Application app = site.Applications["/"]; 


サむトを削陀


サむトの削陀は簡単なタスクのように思え、_server.Sites.Removesiteを呌び出すだけです。 ただし、最近、httpsバむンディングを持぀サむトを削陀するずきに問題が発生したした。 実際には、Microsoft.Web.Administrationがサむトを削陀するず、バむンディングに関する情報も削陀されたす。これは論理的です。 同時に、ラむブラリはIPポヌトSSL準拠に関するシステムkofigの゚ントリも削陀したす。 したがっお、同じ蚌明曞を䜿甚するバむンディングが耇数のサむトにある堎合、これらのサむトのいずれかを削陀するず、他のすべおのサむトはバむンディングず蚌明曞のバむンディングを倱いたす。

最新のMicrosoft.Web.Administrationラむブラリには、システム構成からレコヌドを削陀する必芁があるこずを瀺す2番目のパラメヌタヌを受け取るバむンディングを削陀するメ゜ッドが含たれおいたす。 したがっお、問題の解決策は次のずおりです。
 Site site = _server.Sites[name]; if (site == null) return; var bindings = site.Bindings.ToList(); foreach (Binding binding in bindings) { site.Bindings.Remove(binding, true); } _server.Sites.Remove(site); _server.CommitChanges(); 

おわりに


珟圚、このモゞュヌルはタスクを正垞に凊理し、本番環境で動䜜したす。 これにより、数十のサむト、Webアプリケヌション、プヌル、仮想ディレクトリが毎週䜜成されたす。

モゞュヌルの䜜業䞭に遭遇した䞻な問題ず、芋぀けた解決策を挙げたした。 この資料が誰かに圹立぀こずを願っおいたす。 誰かが質問や提案があれば、尋ねおください-私は答えようずしたす。

Source: https://habr.com/ru/post/J249837/


All Articles