痛いところは煙に巻く

製造業のしがない社内SEが日記代わりにいろいろ書く

Hello,World

Üben Sie es nur recht fleißig, so wird es schon gehen

WSUS構築 私的な勘所

おはこんばんにちは、ビショップです。
久々の更新。ただのサボり。

最近Windows7の延長サポート期限が終わったことが話題ですが、Windows Server 2008も地味に一緒に期限切れしてますので入れ替え対応を結構してました。で、久々にWSUSの設定をいくつかしたんですが、忘れがちなのとMicrosoftのサイトが分かりにくいのと、やっぱり安定稼働しづらいのでメモ代わりに記事にしようと思います。

ハード的なところ

  • CPU:どうでもいい
  • メモリ:8GB以上
  • WSUSコンテンツの保存先ディスク容量:800GB以上

体感的に安定して稼働する構成はこんなところ。保存先は好みで、私の場合はDドライブを作って直下にwsusというフォルダを作ってWSUSコンテンツの保存先に指定しています。このDドライブの容量は800GBくらいあるとなんとなく安定するイメージです。500GBだとクリーンアップウィザードが失敗しがち。この手の情報は調べても意外と見つかりません。正解はないんだと思います。ですので、環境によっては必ずしも充分ではない可能性があります。余裕を持ったスペックが必要だと思います。

必要な機能・ソフトウェア

  • Windows Server Update Services(当たり前だな)
  • Webサーバ(IIS
  • Windows Internal Database
  • Microsoft Report Viewer 2008 SP1 再頒布可能パッケージ
  • SQL Server Management Studio

Windows Internal Databaseはデフォルトだと使います。SQL Serverとか使ってもいいんですが、面倒なのでそのまま。Report Viewerはレポート表示に必要。SSMSはWSUSのメンテに必要。ということで5つの役割・機能とソフトを使用します。インストール方法とかは割愛。

設定的なところ

IIS

IISのマネージャーからアプリケーションプールの「WsusPool」を右クリックして「詳細設定」を表示。下の方のプライベートメモリ制限を「4000000」に設定する。

f:id:bishop03428:20200128112415j:plain
WsusPool
f:id:bishop03428:20200128112436j:plain
WsusPoolProperty

WSUS

WSUSの主要な設定は割愛します。環境次第なので!見落としやすいところで、ポート番号の変更が必要になる場合があります。Windows Server 2012以降のWSUSではWSUSサーバとクライアント間で利用されるポートのデフォルトが80から8530に変更されました。なので、会社などの環境、クライアントの参照先設定によってはクライアントがWSUSサーバを正常に参照できずコンピュータがいつまでたってもWSUSに表示されない場合があります。そういった場合は、WSUSサーバ側のポート番号を80に変更してあげる必要があります。
WSUSサーバのコマンドプロンプトで下記コマンドを実行します。

"C:\Program Files\Update Services\Tools\wsusutil.exe" UseCustomWebSite false

少し時間がかかることがありますが、”ポート番号の仕様: 80”と表示されれば変更されます。WSUSで使用されるポート番号の確認は、WSUSの管理ツールを開いて、左ペインのサーバ名をクリックしたときに表示される概要から確認できます。

定期メンテナンス

WSUSは定期的にメンテナンスが必要です。Microsoftは少なくとも月に1回のメンテナンスを推奨しています。いちいち手動でやるのは面倒なので、定期的に実行されるようにタスクを仕込んでおきます。手動でやる場合は別途調べてください。

インデックスの再構築

SQLコマンドが必要です。下記のSQLをコピーしてSQLファイルを作成してください。Microsoftのサイトからもダウンロードできたと思ったのですが、ちょっとサイトが見つからないので、興味のある方は探してください。一応注意になりますが、WIDを使用していること前提なので、SQLServerを使用している人は別途調べてください。

/****************************************************************************** 
This sample T-SQL script performs basic maintenance tasks on SUSDB 
1. Identifies indexes that are fragmented and defragments them. For certain 
   tables, a fill-factor is set in order to improve insert performance. 
   Based on MSDN sample at http://msdn2.microsoft.com/en-us/library/ms188917.aspx 
   and tailored for SUSDB requirements 
2. Updates potentially out-of-date table statistics. 
******************************************************************************/ 
 
USE SUSDB; 
GO 
SET NOCOUNT ON; 
 
-- Rebuild or reorganize indexes based on their fragmentation levels 
DECLARE @work_to_do TABLE ( 
    objectid int 
    , indexid int 
    , pagedensity float 
    , fragmentation float 
    , numrows int 
) 
 
DECLARE @objectid int; 
DECLARE @indexid int; 
DECLARE @schemaname nvarchar(130);  
DECLARE @objectname nvarchar(130);  
DECLARE @indexname nvarchar(130);  
DECLARE @numrows int 
DECLARE @density float; 
DECLARE @fragmentation float; 
DECLARE @command nvarchar(4000);  
DECLARE @fillfactorset bit 
DECLARE @numpages int 
 
-- Select indexes that need to be defragmented based on the following 
-- * Page density is low 
-- * External fragmentation is high in relation to index size 
PRINT 'Estimating fragmentation: Begin. ' + convert(nvarchar, getdate(), 121)  
INSERT @work_to_do 
SELECT 
    f.object_id 
    , index_id 
    , avg_page_space_used_in_percent 
    , avg_fragmentation_in_percent 
    , record_count 
FROM  
    sys.dm_db_index_physical_stats (DB_ID(), NULL, NULL , NULL, 'SAMPLED') AS f 
WHERE 
    (f.avg_page_space_used_in_percent < 85.0 and f.avg_page_space_used_in_percent/100.0 * page_count < page_count - 1) 
    or (f.page_count > 50 and f.avg_fragmentation_in_percent > 15.0) 
    or (f.page_count > 10 and f.avg_fragmentation_in_percent > 80.0) 
 
PRINT 'Number of indexes to rebuild: ' + cast(@@ROWCOUNT as nvarchar(20)) 
 
PRINT 'Estimating fragmentation: End. ' + convert(nvarchar, getdate(), 121) 
 
SELECT @numpages = sum(ps.used_page_count) 
FROM 
    @work_to_do AS fi 
    INNER JOIN sys.indexes AS i ON fi.objectid = i.object_id and fi.indexid = i.index_id 
    INNER JOIN sys.dm_db_partition_stats AS ps on i.object_id = ps.object_id and i.index_id = ps.index_id 
 
-- Declare the cursor for the list of indexes to be processed. 
DECLARE curIndexes CURSOR FOR SELECT * FROM @work_to_do 
 
-- Open the cursor. 
OPEN curIndexes 
 
-- Loop through the indexes 
WHILE (1=1) 
BEGIN 
    FETCH NEXT FROM curIndexes 
    INTO @objectid, @indexid, @density, @fragmentation, @numrows; 
    IF @@FETCH_STATUS < 0 BREAK; 
 
    SELECT  
        @objectname = QUOTENAME(o.name) 
        , @schemaname = QUOTENAME(s.name) 
    FROM  
        sys.objects AS o 
        INNER JOIN sys.schemas as s ON s.schema_id = o.schema_id 
    WHERE  
        o.object_id = @objectid; 
 
    SELECT  
        @indexname = QUOTENAME(name) 
        , @fillfactorset = CASE fill_factor WHEN 0 THEN 0 ELSE 1 END 
    FROM  
        sys.indexes 
    WHERE 
        object_id = @objectid AND index_id = @indexid; 
 
    IF ((@density BETWEEN 75.0 AND 85.0) AND @fillfactorset = 1) OR (@fragmentation < 30.0) 
        SET @command = N'ALTER INDEX ' + @indexname + N' ON ' + @schemaname + N'.' + @objectname + N' REORGANIZE'; 
    ELSE IF @numrows >= 5000 AND @fillfactorset = 0 
        SET @command = N'ALTER INDEX ' + @indexname + N' ON ' + @schemaname + N'.' + @objectname + N' REBUILD WITH (FILLFACTOR = 90)'; 
    ELSE 
        SET @command = N'ALTER INDEX ' + @indexname + N' ON ' + @schemaname + N'.' + @objectname + N' REBUILD'; 
    PRINT convert(nvarchar, getdate(), 121) + N' Executing: ' + @command; 
    EXEC (@command); 
    PRINT convert(nvarchar, getdate(), 121) + N' Done.'; 
END 
 
-- Close and deallocate the cursor. 
CLOSE curIndexes; 
DEALLOCATE curIndexes; 
 
 
IF EXISTS (SELECT * FROM @work_to_do) 
BEGIN 
    PRINT 'Estimated number of pages in fragmented indexes: ' + cast(@numpages as nvarchar(20)) 
    SELECT @numpages = @numpages - sum(ps.used_page_count) 
    FROM 
        @work_to_do AS fi 
        INNER JOIN sys.indexes AS i ON fi.objectid = i.object_id and fi.indexid = i.index_id 
        INNER JOIN sys.dm_db_partition_stats AS ps on i.object_id = ps.object_id and i.index_id = ps.index_id 
 
    PRINT 'Estimated number of pages freed: ' + cast(@numpages as nvarchar(20)) 
END 
GO 
 
 
--Update all statistics 
PRINT 'Updating all statistics.' + convert(nvarchar, getdate(), 121)  
EXEC sp_updatestats 
PRINT 'Done updating statistics.' + convert(nvarchar, getdate(), 121)  
GO 

上記のSQLをsqlwid_reindex.sqlという名前で保存したとします。それをWSUSサーバのDドライブ直下に保存したとします。タスクスケジューラに下記コマンドを登録します。

"C:\Program Files\Microsoft SQL Server\110\Tools\Binn\SQLCMD.exe" -S \\.\pipe\Microsoft##WID\tsql\query -i D:\sqlwid_reindex.sql -I -o D:\wsus\reindexout.txt

起動タイミングなどは好きに設定してください。同期の時間とは被らないようにしましょう。このコマンドはDドライブのwsusフォルダにログが出力されるようになっています。

クリーンアップウィザードをPowerShellで実行

不要な更新ファイルや古いコンピュータなどは溜まっていく一方なので邪魔になります。クリーンアップウィザードで定期的に削除してあげる必要がありますが、通常はWSUSの管理ツールから実行してあげないといけません。ですがPowerShellからコマンドで起動する方法があります。これを利用してタスクスケジューラにPowerShellコマンドを仕込んであげます。

Powershell -Command "Invoke-WsusServerCleanup -CompressUpdates -CleanupObsoleteUpdates -CleanupObsoleteComputers -CleanupUnneededContentFiles -DeclineExpiredUpdates -DeclineSupersededUpdates" > D:\wsus\wsusClean.txt

こちらも起動タイミングなどは好きなように設定してください。かなりの時間がかかります。同期の時間とは被らないようにしましょう。このコマンドもDドライブのwsusフォルダにログが出力されるようになっています。

トラブル対応

ディスク容量が小さいと、WSUSコンテンツの容量に追いつかず、WSUS管理ツールが頻繁にタイムアウトしたり、クリーンアップウィザードが失敗したりします。そういった場合は最初からWSUSを再セットアップしちゃいましょう。IISから何からすべてなかったことにしてから再セットアップすることでなんとかなる場合があります。勇気をもって機能の削除とファイルの削除を行いましょう。

まとめ

  • ハードウェアスペックは余裕のある構成で。特にディスク容量
  • 旧環境からのバージョンアップなどによってはWSUSポートの変更が必要
  • 手動メンテナンスは面倒なのでタスク化しよう
  • トラブル時は思い切って最初から設定しなおそう

スポンサーリンク