BOOK Preview インサイドMicrosoft Windows 第4版 上 第2章 システムアーキテクチャ 2.4 キーシステムコンポーネント 書籍情報のページ 2005/08/19 |
|
本コーナーは、Windowsシステム管理者向けの書籍から、主要なチャプターをそのまま転載し、その内容を紹介するものです。 今回ご紹介する『インサイドWindows 第4版』は、Windowsオペレーティング・システムの内部を詳細に解説した決定版です。Windowsカーネルの内部について、ここまで詳しく解説した情報はほかにありません。 著者の1人であるデビット・ソロモン氏は、Windows NTの開発リーダーだったデビット・カトラー氏とは旧知の仲で、本書の前々版(『インサイドWindows NT 第2版』)を執筆するにあたり、Windowsカーネルのソースコードにアクセスする許可をカトラー氏から与えられました。それだけでなく、デビッド・カトラー氏は、本書の一部(プロセス管理の部分)について、技術校閲も担当しています。 またもう1人の筆者であるマーク・ルシノビッチ氏は、Windowsオペレーティング・システムの機能を縦横に駆使したツール開発者として著名で、前出のカトラー氏も一目置く存在です。「かゆいところに手が届く」彼のツールは、多くのWindowsエンジニアにとって不可欠な存在となっています(フリー・ツールの入手先はこちら:SysInternals)。 つまり本書は、Windowsコア・システムの開発責任者と、OS解説のエキスパートが、二人三脚で執筆し、Windowsの歴史とともに改版を重ねてきた希有な書籍なのです。今回の第4版では、Windows XPとWindows Server 2003に加えられたカーネルの変更点や、Windowsの64bitサポートなどについて加筆されています。情報システムの設計者やシステム管理者など、作り手や管理者としてWindowsシステムに接する必要があるなら、本書にまとめられた情報が仕事の随所で役立つはずです。 本稿では、Windowsカーネルの概要を解説した第2章「システムアーキテクチャ」の部分を何回かに分けて転載しています。 なお、書籍の詳細については書籍情報のページをご覧ください。 |
|
2.4 キーシステムコンポーネント
Windowsアーキテクチャの概要説明は完了しましたから、ここからは、内部構造体とキーとなるシステムコンポーネントを詳しく検討していきます。図2-3は、Windowsシステムアーキテクチャとコンポーネントを詳しく図解した図2-2の詳細版です。ただし、第13章で取り上げるネットワーク機能などは含まれていません。
これ以降の節では、この図2-3に含まれている主要なシステムコンポーネントを詳しく説明していきます。第3章では、システムが使用している主要なコントロールメカニズム(オブジェクトマネージャ、割り込みなど)を取り上げます。第5章では、Windowsシステムの起動とシャットダウンプロセスを説明します。第4章では、レジストリ、サービスプロセスなどの管理メカニズムとWMI(WindowsManagement Instrumentation)を取り上げます。そして、その後の各章では、プロセス、スレッドなどの内部構造と動作、メモリ管理、セキュリティ、I/Oマネージャ、ストレージ管理、キャッシュマネージャ、Windowsファイルシステム(NTFS)、ネットワークを詳述します。
図2-3 Windowsアーキテクチャの詳細 |
2.4.1 環境サブシステムとサブシステムDLL
図2-3に示されているように、Windows は元々、OS/2、POSIX、およびWindowsという3種類の環境サブシステムを持っていました。既に触れたように、OS/2サブシステムのサポートはWindows 2000出荷時に打ち切られました。POSIXはWindows XPから同じように削除されましたが、その高機能バージョンはWindowsServices for UNIX製品の一部として無料提供されています。
3種類の環境サブシステムの中では、Windowsサブシステムは特殊な意味を持っています。つまり、Windowsはその環境サブシステムなくして動作しないのです。Windows環境サブシステムは、キーボード、マウス、ディスプレイを所有し、ログイン対話ユーザーを持たないサーバーシステムでも必要とされます。残りの2つの環境サブシステムは、オンデマンドで組み入れられるにすぎません。
サブシステムの起動情報は、HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\SubSystems レジストリキーの下に格納されています。
図2-4 Windows起動情報格納レジストリ |
Required値は、システムブート時にロードされるサブシステムに関する情報を保持しています。この値は、WindowsとDebugという2つの文字列で構成されています。Windows文字列には、WindowsサブシステムのファイルCsrss.exeが格納されます。Csrss.exeは、後で触れるように、Client/Server Run-Time Subsystemを表します。Debug文字列は、内部テスト用に使用されているだけですから、空白となっています。Optional値は、OS/2とPOSIXサブシステムがオンデマンドで起動されることを示しています。Kmode値は、後述するWindows サブシステムのカーネルモードコードであるWin32k.sysが入っています。
環境サブシステムは、Windowsエグゼキュティブシステムサービスの一部をアプリケーションプログラムに公開する役割を担っています。個々の環境サブシステムは、固有のWindowsネイティブサービスセットへのアクセスを提供しています。このため、あるサブシステム上で開発されたアプリケーションは、別のサブシステムが公開するWindowsサービスを利用できるわけではありません。たとえば、Windowsアプリケーションは、POSIXのfork関数を呼び出せません。
すべての実行イメージ(.exe)は、1つのサブシステムに接続されます。イメージが実行されるとき、プロセス作成コードは、イメージヘッダー内のサブシステム種別コードを調べ、適切なサブシステムに新規プロセスの作成を通知します。このサブシステム種別コードは、Microsoft Visual C++のlinkコマンドの/SUBSYSTEMオプションから指定できます。
注
|
|||||
|
サブシステムが異なれば、呼び出される関数も異なります。POSIXアプリケーションは、POSIXサブシステムが公開するサービスのみを呼び出すことができます。同じようにWindowsアプリケーションは、Windowsサブシステムが公開するサービスを呼び出せるだけです。このような制限が発生した背景には、オリジナルなPOSIXサブシステムは、(POSIX1003.1仕様に沿って)一部の関数セットを実装するだけで、UNIXアプリケーションを移植する環境としては貧弱だったという事情があります。
既に触れたように、ユーザーアプリケーションはWindowsシステムサービスを直接呼び出すことはできません。ユーザーアプリケーションは、複数のサブシステムDLL経由でWindowsサービスを利用する設計になっています。
それらのライブラリは、必要なインターフェイスを公開してくれますから、アプリケーションプログラムはサブシステムにリンクし、インターフェイスを呼び出します。たとえば、Kernel32.dll、Advapi32.dll、User32.dll、Gdi32.dllなどのWindowsサブシステムDLLは、Windows API関数を実装しています。Psxdll.dll というPOSIXサブシステムDLLは、POSIX API 関数を実装しています。
|
アプリケーションがサブシステムDLL内の関数を呼び出すと、次のいずれかの動作が開始されます。
-
サブシステムDLL 内部に実装されている関数が呼び出され、ユーザーモードで実行される ― この動作では、ユーザーモードとカーネルモード間のモード遷移は発生しません。表現を変えると、環境サブシステムプロセスにメッセージが送信されないため、Windowsエグゼキュティブサービスが呼び出されることはありません。呼び出された関数はユーザーモードでのみ実行され、実行結果はそのまま呼び出し元スレッドに返されます。たとえば、GetCurrentProcessやGetCurrentProcessIdなどの関数はユーザーモードで実行されます。前者は、現在のプロセスを示す-1という値を常に返してきます。後者は、キャッシュされている一定の値を持つプロセス識別子を返してきます(カーネル内の内部ルーチンの呼び出しを避けています)。
-
内部で複数のWindowsエグゼキュティブ呼び出しを行う関数の実行 ― たとえば、Windows関数であるReadFileとWriteFile関数は、NtReadFileとNtWriteFileという未公開の内部関数をそれぞれ呼び出し、Windows I/O システムサービスを実行します。
-
処理の一部を環境サブシステムプロセスに依存する関数の実行 ― ユーザーモードで動作する環境サブシステムプロセスは、自分がコントロールしているクライアントアプリケーションの状態を管理する必要があります。このような場合、クライアントとサーバー間で交換される要求は、サブシステムに送信されるメッセージ経由で環境サブシステムに送られます。サブシステムDLLは、処理結果を呼び出し元に返す前に、環境サブシステムからの応答を待っています。
CreateProcessやCreateThreadなどのWindows関数のいくつかは、2番目と3番目の動作を兼ね備えています。
相互に独立した複数の環境サブシステムをサポートするように設計されたのは事実ですが、個々の環境サブシステムは似たようなコードを重複しながら実装しています。たとえば、それぞれの環境サブシステムがウィンドウ表示と関連するI/O処理を実行するコードを持っています。このため、システムのサイズとパフォーマンスに悪影響を与えています。Windowsは第1サブシステムであるため、設計者たちは共通に使用できる基本機能(たとえば、画面とのI/O)をWindowsサブシステムに実装し、他のサブシステムから呼び出してもらうという方針を採用することを決断しました。こうした事情もあり、POSIXとOS/2サブシステムは、Windowsサブシステムのサービスを呼び出すことになっています。実際、POSIXとOS/2サブシステムのイメージのサブシステム種別を調べてみるとわかりますが、Windows実行ファイルとなっています。
それでは次に、個々の環境サブシステムをより詳しく検討してみましょう。
■Windowsサブシステム
Windowsサブシステムは、次のような主要コンポーネントで構成されています。
-
環境サブシステムプロセス(Csrss.exe) ― このコンポーネントは次のような機能をサポートしています。
-
コンソール(テキスト)ウィンドウ
-
プロセスとスレッドの生成消滅
-
16ビット仮想DOSマシン(VDM)プロセス
-
その他の関数(GetTempFile、DefineDosDevice、ExitWindowsEx、いくつかの自然言語サポート関数)
-
-
カーネルモードデバイスドライバ(Win32k.sys) ― このコンポーネントは次のような機能を実装しています。
-
ウィンドウマネージャ(ウィンドウ表示制御、画面出力の管理、キーボード/マウス/各デバイスからの入力収集、ユーザーメッセージのアプリケーションへの配送)
-
グラフィックデバイスインターフェイス(GDIと略称され、グラフィック出力デバイス操作用の関数ライブラリ。直線、テキスト、図形などの描画関数とグラフィック操作関数の提供)
-
-
サブシステムDLL(Kernel32.dll、Advapi32.dll、User32.dll、Gdi32.dll) ― 公開されているWindows API関数を(非公開の)カーネルモードシステムサービス(Ntoskrnl.exeとWin32k.sysに実装されている)呼び出しに適切に変換します。
-
グラフィックデバイスドライバ ― 固有のハードウェアを制御するグラフィックディスプレイドライバ、プリンタドライバ、およびビデオミニポートドライバ。
アプリケーションは、標準のUSER関数を呼び出し、ウィンドウやボタンなどのユーザーインターフェイスコントロールを画面上に作成します。ウィンドウマネージャは、ユーザーからの要求をGDIに伝えます。GDIは、受け取った要求をグラフィックデバイスドライバに渡します。ドライバは、ディスプレイデバイス用にフォーマットを変換します。ディスプレイドライバは、ビデオミニドライバと協調し、ビデオ表示処理を実行します。
GDIは、標準的な2次元関数セットを提供しています。アプリケーションは、提供される関数を使用すれば、デバイスの詳しい仕様を意識することなく、グラフィックデバイスと通信できます。このため、GDI関数は、アプリケーションとディスプレイドライバやプリンタドライバなどのグラフィックデバイス間の仲介を行っているといってよいでしょう。GDIは、アプリケーションからのグラフィック出力要求を解釈し、ドライバに中継します。また、標準的なインターフェイスをアプリケーションに提供し、出力デバイスの仕様上の相違を隠ぺいします。つまり、アプリケーションコードは、標準インターフェイスを使用すれば、ハードウェアデバイスとドライバから独立したコードを書けるわけです。GDIは、アプリケーションから送信されてくるメッセージをデバイス性能に合わせて調整します。この調整では、要求メッセージを管理しやすいように細分化することがよくあります。たとえば、デバイスによっては命令を直接解釈し、楕円を描画します。また、異なるデバイスによってはピクセル情報を直接理解できないため、GDI側でその情報を座標値ペアに事前変換する必要もあります。グラフィックとビデオドライバのアーキテクチャに関する詳細については、Windows DDKを参照してください。
Windows NT 4が出荷される以前は、ウィンドウマネージャとグラフィックサービスは、ユーザーモードWindowsサブシステムプロセスの一部として実装されていました。Windows NT 4では、ウィンドウとグラフィック処理コードは、Windowsサブシステムプロセスコンテキストで動作するのではなく、カーネルモードで動作する、呼び出し可能なサービス(Win32k.sys)として実装変更されました。この変更は、全体的なシステムパフォーマンスを改善するために必要だったのです。Windowsグラフィックサブシステムを含む独立したサーバープロセスは、複数のスレッドとプロセスのコンテキスト切り替えを必要とします。このようなコンテキスト切り替えは、設計上にどのような工夫が施されていたとしても、膨大なCPUサイクルとメモリを消費することになります。
たとえば、クライアント側には通常多数のスレッドが生成され、Windowsサブシステムプロセス側にはそれぞれのクライアント側スレッドに対してサービスを提供するスレッドが作成されるとしましょう。サーバー側スレッドは、クライアント側から送られている要求をひたすら待ちます。以前は、高速LPCと呼ばれる特殊なプロセス間通信技術が導入され、クライアントとサーバースレッド間のメッセージ交換を担当していました。高速LPC経由でのスレッド切り替えは、通常のスレッドコンテキスト切り替えと異なり、カーネル内部での再スケジューリングを必要としません。つまり、サーバースレッドはカーネルのプリエンプティブスレッド切り替えの影響を受けないため(有無を言わさず切り替えられない、ということ)、クライアントスレッドの残りタイムスライス(クォンタム)の間もそのまま活動を続けられます。また、ビットマップなどの大量のデータ構造体の受け渡しを高速化するために、共有メモリバッファが使用されています。クライアントはキーとなるサーバーデータ構造体に直接読み取りアクセスが可能となっていますから、クライアントとサーバー間のコンテキスト切り替えは最小に抑えられています。さらに、GDI処理はバッチ化されます。この場合の「バッチ化」というのは、Windowsアプリケーションの一連のグラフィック呼び出しがその都度サーバー側に送られ、出力デバイス上に描画されるのではなく、まず、GDIの持つバッチ化行列に入れられる、ということなのです。簡単に言えば、GDIは専用の待ち行列を用意し、そこにグラフィック呼び出し要求を整理する、ということです。待ち行列の大きさは、Windows GdiSetBatchLimit関数で設定変更が可能です。もちろん、GdiFlush関数を呼び出せば、待ち行列内の呼び出し要求を吐き出すこともできます。一方、Windowsサブシステム側からの読み出し専用プロパティとデータ構造体は、クライアント側にキャッシュされ、以降の処理が高速化されるようになっています。
以上のように、高速LPC技術ではいろいろな最適化が行われています。しかし、システム全体のパフォーマンスは十分ではありませんでした。特に、グラフィックアプリケーションの実行時には、不十分であることがわかりました。結論を急げば、スレッドの生成を抑え、コンテキスト切り替え回数を減らす必要がありました。このため、ウィンドウとグラフィック処理システムコードは、カーネルモードに移動されたのです。アプリケーションはWindowsマネージャとGDIを1回呼び出すだけで、Windowsエグゼキュティブコンポーネントが自動的に呼び出されます。つまり、カーネルモードで動作するサブシステムコードが、アプリケーションからの要求に応じて必要な処理を行ってくれるわけです。この処理では、ユーザーモードとカーネルモードのコンテキスト切り替えは一切発生しません。これは、GDIによるビデオドライバの直接アクセスであり、パフォーマンスが向上します。特に、ビデオハードウェアとの間で高速/広帯域通信を必要とするプロセスの動作は高速化されます。
それではここで、Windowsサブシステムのユーザーモードプロセス部にそのまま残された機能を説明しておきます。結論を言ってしまえば、コンソールとテキストウィンドウを描画更新するすべてのコードは、ユーザーモードプロセス内に残されています。残された理由はきわめて単純です。コンソールアプリケーションは、ご承知のようにウィンドウという概念を持たないからです。たとえば、コマンドプロンプトを起動し、他のウィンドウをその上にドラッグしてみてください。Windowsサブシステムはコンソールウィンドウを再描画するために、CPU時間を確かに消費していることがわかります。しかし、Windowsサブシステムプロセスにメッセージを送信するWindows関数(プロセスとスレッドの生成消滅、ネットワークドライバ文字のマッピング、一時ファイルの作成などを担当する関数)は、2、3個だけです。Windowsアプリケーションを実行しても、Windowsサブシステムプロセスへのコンテキスト切り替えは発生しない、といってもよいでしょう。
■POSIXサブシステム
POSIXはPortable Operating System Interface based on UNIXの略語で、UNIXスタイルオペレーティングシステムの国際標準仕様の集合を指しています。POSIX標準仕様を策定することにより、各開発ベンダーにUNIXスタイルのインターフェイスの実装が期待されました。実装されたインターフェイスを使用している限り、アプリケーションはあるシステムから他のシステムに簡単に移植できることになります。
Windowsは、多数のPOSIX標準仕様の中の1つである、POSIX.1を実装しています。この仕様は、正式にはISO/IEC 9945-1:1990、あるいはIEEE POSIX仕様1003.1-1990という名称を持っています。ここで注意してもらいたいのは、Windowsは数ある仕様の中で、このPOSIX.1だけを実装しているにすぎないことです。このPOSIX.1仕様は、米国政府が1980年代半ばから後半に定めていた調達基準を満たすために作成されました。米国NIST(National Institute of Standardsand Technology)は連邦情報処理仕様(FIPS:Federal Information ProcessingStandard)151-2を策定し、その中でPOSIX.1準拠を定めました。WindowsNT 3.5、3.51、および4は公式のテストに合格し、FIPS 151-2認定を受けています。
POSIX.1準拠はWindows必須の開発条件ですから、設計段階から、POSIX.1仕様は基本システムサポートとして実装されることが決まっていました(たとえば、fork関数はWindowsエグゼキュティブに、ハードファイルリンクサポートはWindowsファイルシステムにそれぞれ実装されました)。しかし、POSIX.1仕様は、サービスの一部(プロセス制御、プロセス間通信、単純なキャラクタセルI/Oなど)をサポート必須として定めているだけですから、Windows 2000に実装されているPOSIXサブシステムは完全なプログラミング環境というわけではありません。また、アプリケーション内ではサブシステム境界をまたぐような呼び出しは許可されていないため、POSIXアプリケーションはPOSIX.1が定義しているサービスセットを呼び出せるだけとなります。これでは、Windows上で動作するPOSIXプログラムは、スレッドやウィンドウを作成できないだけではなく、リモートプロシージャコール(RPC)やソケットを使用することもできません。
このような制限は緩和される必要があります。Microsoftは、Windows Services for UNIXと呼ばれる製品を出荷し、制限の回避を目指しました。この製品は、ほぼ2000個に上るUNIX関数と300種類のUNIXライクなツールやユーティリティを提供する、拡張版POSIXサブシステムです。製品の詳細については、www.microsoft.com/windows/sfu/を参照してください。
拡張版POSIXサブシステムを使用すると、UNIXアプリケーションのWindowsへの移植が簡単になります。しかし、プログラムはあくまでもPOSIX バイナリとしてリンクされますから、Windows関数を直接呼び出すことはできません。UNIXアプリケーションのWindowsへの移植ができ、かつ、Windows関数を直接呼び出すためには、MKSツールキットという専用パッケージを導入する必要があります。このパッケージは、Mortice Kern Systems(www.mkssoftware.com)から販売されています。パッケージを使用すれば、UNIXアプリケーションをその環境でWindows実行ファイルとしてリビルドできます。
|
Windows環境でPOSIXアプリケーションをコンパイル/リンクするためには、Platform SDKに含まれるPOSIXヘッダーとライブラリが必要になります。POSIX実行ファイルは、POSIXサブシステムライブラリであるPsxdll.dllとリンクされます。Windowsはデフォルトでは、オンデマンドでPOSIXサブシステムを起動するように構成されていますから、POSIXアプリケーションを最初に起動した段階で、POSIXサブシステムプロセス(Psxss.exe)は起動されなければなりません。POSIXサブシステムはいったん起動すると、システムがリブートされるまで、その動作を継続します。POSIXサブシステムプロセスを強制終了した場合には、システムを再起動するまで、他のPOSIXアプリケーションを実行することはできません。POSIXイメージ自体は直接実行されるのではなく、Posix.exeと呼ばれる特殊なサポートイメージが起動されます。そのイメージは子プロセスを作成し、POSIXアプリケーションを実行させます。
■OS/2サブシステム
OS/2環境サブシステムは、POSIXサブシステムと同じように、OS/2 1.2の16ビットキャラクタベースあるいはビデオI/O(VIO)アプリケーションのみをサポートする点で、かなりの使用上の制限があります。Microsoftは、Windows NT 4出荷時、差し替え版OS/2 1.2プレゼンテーションマネージャサブシステムを販売しましたが、OS/2 2.x以降のアプリケーションをサポートすることはありませんでした。
Windowsはユーザーアプリケーションからのハードウェアアクセスを許しませんから、IN/OUT命令(ハードウェアデバイスへ直接アクセスする命令)を実行しようとするI/O特権セグメントを持つOS/2プログラムをサポートしません。高度なビデオI/O(AVIO)機能を持つOS/2プログラムも同じ理由からサポートしません。CLI/STI命令を使用するアプリケーションはサポートされますが、システム内の他のすべてのOS/2アプリケーションと、CLI命令を実行するOS/2プロセス内の他のすべてのスレッドは、STI命令が実行されるまで、一時停止状態に置かれます。
ネイティブOS/2にある16MBメモリという制限は、Windowsには適応されません。OS/2サブシステムはWindowsの32ビット仮想アドレススペースを使用し、図2-5のように最大512MBまでのメモリをOS/2アプリケーションに提供します。
図2-5 OS/2サブシステムの仮想メモリ配置 |
タイル領域は512MBの仮想アドレススペースです。このスペースは事前に予約され、16ビットアプリケーションがセグメントを必要とする時点で、コミットあるいはデコミットされます。OS/2サブシステムは個々のプロセス用のローカル記述子テーブル(LDT)を維持管理し、すべてのOS/2プロセス用の共有メモリセグメントも同一のLDTスロットに置かれます。
第6章で詳述するように、スレッドはプログラムの要素であり、実行単位です。このため、スレッドはスケジューリングロジックに応じて、プロセッサ時間が割り当てられます。Windowsの優先度レベルは0から31までの範囲にありますが、OS/2は0から63までの優先度レベルを持っています。64のOS/2優先度レベルは、1から15までのWindows優先度に動的にマッピングされます。OS/2スレッドは、16から31の範囲のWindowsリアルタイム優先度を受け取るようなことはありません。
POSIXサブシステムと同じように、OS/2サブシステムは、OS/2互換イメージを最初に起動したときに、自動的に動作を開始します。動作をいったん開始すると、システムが再起動されるまでそのまま動き続けます。
WindowsとPOSIXあるいはOS/2アプリケーションの詳しい関係については、「6.2 CreateProcessの動作フロー」を参照してください。
INDEX | ||
インサイドMicrosoft Windows 第4版 上 | ||
第2章 システムアーキテクチャ | ||
2.1 要求と設計目標/2.2 オペレーティングシステムモデル | ||
2.3 アーキテクチャ概要/2.3.1 移植性/2.3.2 対称型マルチプロセッシング | ||
2.3.3 スケーラビリティ/2.3.4 クライアントとサーバー間の違い/2.3.5 チェックビルド | ||
2.4 キーシステムコンポーネント/2.4.1 環境サブシステムとサブシステムDLL | ||
2.4.2 Ntdll.dll/2.4.3 エグゼキュティブ | ||
2.4.4 カーネル/2.4.5 ハードウェア抽象化層(HAL)/2.4.6 デバイスドライバ | ||
2.4.7 システムプロセス/まとめ | ||
「BOOK Preview」 |
- Azure Web Appsの中を「コンソール」や「シェル」でのぞいてみる (2017/7/27)
AzureのWeb Appsはどのような仕組みで動いているのか、オンプレミスのWindows OSと何が違うのか、などをちょっと探訪してみよう - Azure Storage ExplorerでStorageを手軽に操作する (2017/7/24)
エクスプローラのような感覚でAzure Storageにアクセスできる無償ツール「Azure Storage Explorer」。いざというときに使えるよう、事前にセットアップしておこう - Win 10でキーボード配列が誤認識された場合の対処 (2017/7/21)
キーボード配列が異なる言語に誤認識された場合の対処方法を紹介。英語キーボードが日本語配列として認識された場合などは、正しいキー配列に設定し直そう - Azure Web AppsでWordPressをインストールしてみる (2017/7/20)
これまでのIaaSに続き、Azureの大きな特徴といえるPaaSサービス、Azure App Serviceを試してみた! まずはWordPressをインストールしてみる
|
|