朝から昼寝

ITや家計、身近なことの整理

[お知らせ]
当サイトは、2024年1月1日に
新URL(happynap.net)に引っ越しました





このページの内容は、最新ではない場合がありますので、新URLをご確認ください。






当サイトには広告を含みます。"オススメ"として紹介している商品やサービスは、個人的にそう思えたものだけです。
共感、興味をもっていただけるものがあればご利用ください (広告掲載ポリシー)。

1回のGet-VMで色々なVMプロパティを取得(PowerCLI)

概要

PowerCLIでvCenterから仮想マシン情報を取得可能ですが、目的のプロパティ群がGet-VMやGet-VMGuestなど複数のコマンドレットの出力にまたがる場合、各コマンドレットを実行しそれらの出力をマージするというのは煩雑です。
本記事は、シンプルに1回のGet-VMコマンドレット実行から、Get-VMの出力に含まれないプロパティ情報も合わせて取得し、CSVファイルに保存する方法をまとめたものです。

本記事の目的

  • 1回のGet-VMコマンドレット実行で仮想マシンの各プロパティを取得する。


目次

基本

環境設定

既に以下の環境設定は完了しているものとします。

  • PowerCLIのインストール
  • PowerCLIからvCenterへの接続確認(Connect-VIServer)

仮想マシンの各プロパティを取得するスクリプト

Connect-VIServerにてvCenterに接続後、以下の例のようにスクリプトを実行すると、各プロパティを取得できます。取得するプロパティは変更可能です。

vmlist.ps1

## 複数NICを持つVMのVLAN/NetworkAdapterプロパティは複数値になるので":"で結合する関数を用意
function concatNetworkAdapters {
    Param($VM)
    $var = @()
    $Adapters = @(Get-NetworkAdapter -VM $VM | Select Name, NetworkName)

    ForEach ($Adapter in  $Adapters) {
        $var += $Adapter.NetworkName + "(" + $Adapter.Name + ")"
    }

    Return [String]::join(":", $var)
}

$date = Get-Date

## Get-VMにて全VMのオブジェクトを取得し、目的のプロパティをハッシュテーブルに格納
$out = Get-VM | Select Name, 
    @{N="PowerState"; E={[String] $_.PowerState}},
    @{N="Host"; E={$_.VMHost.name}},
    NumCpu,
    MemoryGB,
    @{N="ProvisionedSpaceGB"; E={[Math]::Round(($_.ProvisionedSpaceGB),0)}},
    @{N="UsedSpaceGB"; E={[Math]::Round(($_.UsedSpaceGB),0)}},
    @{N="GuestOS"; E={$_.Guest.OSFullName}},
    HardwareVersion,
    @{N="IPAddress"; E={[string]::Join(':',$_.Guest.IPAddress)}},
    @{N="VLAN"; E={concatNetworkAdapters $_.Name}},
    @{N="VmxPath"; E={$_.ExtensionData.Summary.Config.VmPathName}},
    CreateDate,
    @{N="UptimeDays";E={(New-TimeSpan -Start $_.Extensiondata.Runtime.BootTime.ToLocalTime() -End $date).Days}},
    @{N="ToolsInstallType"; E={$_.ExtensionData.Guest.ToolsInstallType}},
    @{N="ToolsVersion"; E={$_.ExtensionData.Guest.ToolsVersion}},
    @{N="ToolsStatus"; E={$_.ExtensionData.Guest.ToolsStatus}},
    Notes

## CSVファイルに出力
$out | Export-CSV -NoTypeInformation -encoding UTF8 "C:\vmlist\vmlist.csv"

CSV出力例

出力されたCSVファイルの例です。(列が多いので画像2枚に分けてあります。また例なので1行分のみですが実際には全VM分の行が出力されます)

CSV出力例CSV出力例
CSV出力例

スクリプトの注意点

以下、注意点です。

  • スクリプトの中でファイルパス等にマルチバイト文字(非Ascii文字)を使用する場合、PowerShellの環境の都合上、スクリプト文字コードUTF-8(BOM付)で保存する等の対応が必要です(参考情報はこちら)。

  • 上記の例では、型指定([String]等)の有無等は統一しきれていません。

詳細

スクリプトの説明

このスクリプトは、後述の参考URL等にあるVMwareのコミュニティ情報を元にしたものです。内容を簡単に説明します。

  • function concatNetworkAdapters
    複数NICを持つVMのVLAN(ポートグループ)やNetworkAdapterの情報は、複数値になるので、各値を":"で結合し、CSVの1フィールドに収まるよう整形する関数(適切なプロパティが別途あるかもしれないが、この関数の中ではGet-NetworkAdapterを使用)
  • $out = Get-VM |
    Get-VMにて全VMのオブジェクトを取得し、パイプラインに渡す。パイプライン以降の処理が終わった結果を変数outに格納する。
  • | select以降
    VMのオブジェクトを渡された後は、Select経由でハッシュテーブル(@{Name=xxx, Expression=xxx}、もしくは省略形の@{N=xxx, E=xxx})に格納する。
    Get-VMの出力に含まれるプロパティのままで良いものは、ハッシュテーブルの記載(@{})を省略可。
    逆に、Get-VMの出力に含まれないプロパティを参照するときは、$_.ExtensionData.xxxのように、オブジェクトのメンバ情報から目的のプロパティを指定する(目的のプロパティ名の探し方は後述)。
    • Name : 仮想マシン
    • @{N="PowerState"; E={[String] $_.PowerState}} : 電源状態
    • @{N="Host"; E={$_.VMHost.name}} : 稼働ホスト
    • NumCpu : 仮想CPU数(総コア数)
    • MemoryGB : メモリ量[GB]
    • @{N="ProvisionedSpaceGB"; E={[Math]::Round(($_.ProvisionedSpaceGB),0)}}, @{N="UsedSpaceGB"; E={[Math]::Round(($_.UsedSpaceGB),0)}} : それぞれ、プロビジョニングした容量[GB]、使用容量[GB] ※小数点以下はRound()で四捨五入
    • @{N="GuestOS"; E={$_.Guest.OSFullName}} : ゲストOS名
    • HardwareVersion : 仮想マシンバージョン
    • @{N="IPAddress"; E={[string]::Join(':',$_.Guest.IPAddress)}} : IPアドレス ※複数のIPアドレスがある場合、Join()にて":"で結合
    • @{N="VLAN"; E={concatNetworkAdapters $_.Name}} : 前述の concatNetworkAdapters関数にて取得したVLAN(ポートグループ)情報
    • @{N="VmxPath"; E={$_.ExtensionData.Summary.Config.VmPathName}} : 格納先データストア(vmxファイルのパス)
    • CreateDate : 仮想マシンの作成日時 ※参考までに、Cross vCenter VMotion実行された仮想マシンは、その実行日時にリセットされるようです
    • @{N="UptimeDays";E={(New-TimeSpan -Start $_.Extensiondata.Runtime.BootTime.ToLocalTime() -End $date).Days}} :稼働日数(Uptimeから日数だけを取り出したもの)
    • @{N="ToolsInstallType"; E={$_.ExtensionData.Guest.ToolsInstallType}},@{N="ToolsVersion"; E={$_.ExtensionData.Guest.ToolsVersion}},@{N="ToolsStatus"; E={$_.ExtensionData.Guest.ToolsStatus}} : VMwareTools関連の情報
    • Notes : vCenter上の"注"

目的のプロパティ名の探し方

  • Get-Member
    適当な仮想マシンのオブジェクトをGet-VM等で取得し、Get-Memberで辿りながら地道に探す方法があります。ExtensionDataExtensionData.Guest仮想マシン管理に使えるプロパティがあると思います。
> $vm = Get-VM -name vm01
> $vm | Get-Member
> $vm.ExtensionData | Get-Member
> $vm.ExtensionData.Guest | Get-Member
  • VMware社公式ドキュメント (例:Get-VM RelatedObject)
    2022/5現在、Beta版のようですが、VMware Developer Documentation等でコマンドレットのRelatedObjectを参照すると、各プロパティを参照できます。ただ、Get-VM で取得したオブジェクトから全プロパティを簡単にリンクで辿れる訳ではなさそうです。
    その他、vSphere Web Services APIでもプロパティの説明など参考になりそうな記載があります。

あとは、後述のVMwareコミュニティのやり取りを参考にするのが一番実用的のように思います。

参考URL等

VMwareコミュニティのやり取りから、目的のプロパティの記載が見つかる場合もあります。PowerCLI関連の話題は、詳細に回答されて方がいるようで、非常に参考になります。

VSCode v1.61以降のテレメトリー無効化(自動データ送信)

概要

VSCode v1.61以降、自動データ送信(テレメトリー)の設定パラメタが変更になったようです。
本記事は、VSCodeテレメトリー設定の無効化についてまとめたものです。

本記事の目的


目次

基本

VSCodeテレメトリー無効化設定(設定画面)

VSCodeの設定画面にてTelemetry LevelをOffに設定すると、すべてのテレメトリー機能を無効化できます。

Setting: Telemetry Level
Setting: Telemetry Level

VSCodeテレメトリー無効化設定(settings.json)

VSCodesettings.jsonを直接編集して設定する場合は、以下の行を追加すると、すべてのテレメトリー機能を無効化できます。

"telemetry.telemetryLevel": "off"

従来のテレメトリー設定パラメタ

新たな設定パラメタtelemetry.telemetryLevelが実装されたため、従来のパラメタであるtelemetry.enableTelemetrytelemetry.enableCrashReporterは非推奨(deprecation)となりました。
ただし、これら従来のパラメタも今のところは(v1.67時点)、引き続き使用できるようです(リリースノートに「but will continue to be respected」の記載あり )。

以下のように、新パラメタ(telemetry.telemetryLevel)は、従来パラメタ(telemetry.enableTelemetrytelemetry.enableCrashReporter)より優先されます。

  • 新パラメタがoffの場合、従来パラメタに関係なくテレメトリは無効化される
  • 新パラメタがoff以外に設定され、かつ従来パラメタでテレメトリが無効になっている場合、テレメトリは無効化される

詳細

defaultSettings.jsonの記載(日本語)

日本語環境のVSCodedefaultSettings.jsonを参照すると、日本語訳を確認できます。

  // 
  // Visual Studio Code テレメトリ、ファースト パーティ拡張テレメトリ機能、および参加しているサード パーティの拡張機能テレメトリを制御します。一部のサード パーティの拡張機能では、この設定が考慮されない場合があります。確認するには、特定の拡張機能のドキュメントを参照してください。テレメトリにより、Visual Studio Code のパフォーマンス、改善が必要な場所、および機能の使用方法について理解しやすくなります。 [収集するデータ](https://aka.ms/vscode-telemetry) と[プライバシーに関する声明](https://go.microsoft.com/fwlink/?LinkId=786907) を参照してください。 クラッシュ レポートの変更を有効にするには、アプリケーションを完全に再起動する必要があります。
  // 
  //  
  // 
  // 次の表は、各設定で送信されるデータの概要を示しています。
  // 
  // |       | クラッシュ レポート | エラー テレメトリ | 使用状況データ |
  // |:------|:---------------------:|:---------------:|:--------------:|
  // | all   |            ✓          |        ✓        |        ✓       |
  // | error |            ✓          |        ✓        |        -       |
  // | crash |            ✓          |        -        |        -       |
  // | off   |            -          |        -        |        -       |
  // 
  // 
  //  
  // 
  // ****注:*** この設定が 'off' の場合、他のテレメトリ設定に関係なくテレメトリは送信されません。この設定が 'off' 以外に設定されていて、非推奨の設定でテレメトリが無効になっている場合、テレメトリは送信されません。*
  // 
  //  - all: 使用状況データ、エラー、クラッシュ レポートを送信します。
  //  - error: 一般的なエラー テレメトリとクラッシュ レポートを送信します。
  //  - crash: OS レベルのクラッシュ レポートを送信します。
  //  - off: すべての製品テレメトリを無効にします。
  "telemetry.telemetryLevel": "all",
  // この設定が false の場合、新しい設定の値に関係なくテレメトリは送信されません。`telemetry.telemetryLevel`設定を優先して非推奨になりました。
  // 診断データの収集を有効にします。これにより、Visual Studio Code の実行状況と改善が必要な箇所について理解を深めることができます。収集する情報とプライバシーに関する声明についての [Read more] (https://go.microsoft.com/fwlink/?LinkId=786907) をご覧ください。
  "telemetry.enableTelemetry": true,
  // この設定が false の場合、新しい設定の値に関係なくテレメトリは送信されません。`telemetry.telemetryLevel`設定に結合されているため、非推奨になりました。
  // クラッシュ レポートの収取を有効にします。これにより、安定性が向上します。
  // このオプションを有効にするには、再起動が必要です。
  "telemetry.enableCrashReporter": true,

参考URL等

Systemdのネットワーク関連ユニット (After=network.targetあたり)

概要

Systemdのユニットファイルの中にAfter=network.targetという記述をよく見かけますが、ちょっとややこしい仕様です。

本記事は、Systemdのそのあたりのネットワーク関連ユニットの概要をまとめたものです。対象は主にRHEL7、CentOS7以降です。

Systemdに関する基本的な内容は、以下の記事にまとめてあります。

happy-nap.hatenablog.com

本記事の目的

  • After=network.targetの意味を把握する。
  • ネットワークが起動してからサービス起動する設定を把握する (network-online.target)。
  • ネットワーク関連ユニットの概要を把握する。

基本

After=network.target ≠ ネットワーク疎通可

サービスのユニットファイルにAfter=network.targetが記載されていても、それは「ネットワーク疎通できるようになった後にそのサービスを起動する」ということを保証するものではありません。

httpdやpostfixが起動失敗するケース

例えば、httpd サービスのユニットファイル (httpd.service) には、After=network.target が記載されています。
httpd.conf にて特定のIPアドレスのみを Listen するよう指定している環境において、OS起動時に、そのIPアドレスが使用可能になる前に httpd サービスの起動が開始されてしまうと、Cannot assign requested address: AH00072: make_sock: could not bind to address x.x.x.x:443といったエラーで起動失敗します。

postfixのinet_interfacesの指定でも同様の事象が起きることがあります (fatal: parameter inet_interfaces: no local interface found for x.x.x.x)。

network.target でなく network-online.target

ネットワークの起動が完了した後にそのサービスを起動したい場合は、network-online.targetというユニットとの順序関係を指定します。

順に説明していきます。

ネットワークを待ってサービス起動する設定(network-online.target)

ネットワーク疎通(※)ができるようになってからサービスを起動する設定について説明します。
(※)本記事では、ネットワークインタフェースの設定(IPアドレス割り当てなど)が完了した状態を指します。そのIPアドレスに対するソケット割り当て(バインド)ができる状態です。

元のユニットファイルを直接編集しても良いですが、保守性を考慮し、以下のようにドロップインスニペット (drop-in file、別の設定ファイル) を利用します。ユニットファイルのカスタマイズの全般的なことについては、以下の記事にまとめてあります。

happy-nap.hatenablog.com

例としてhttpdの場合の手順を記載しますが、他のサービスでも同様です。

# systemctl edit httpd にて、以下を記載します。

[Unit]
After=network-online.target
Wants=network-online.target

エディタはデフォルトでvimでなくnanoが起動します(参考1参考2)。
nanoでは、上記を記載後、Ctrl+"S"(上書き保存)→Ctrl+"X"(閉じる)で保存と終了ができます。もしくは、Ctrl+"X"(閉じる)→保存するか聞かれたら"Y"(はい)→ファイル名の確認でEnterでも同様です。

# systemctl edit httpdにて設定変更した際は、# systemctl daemon-reloadを実行しなくても自動的にsystemdが再読み込みしてくれるようです。
(ユニットファイルを手動変更した場合には、systemdに再読み込みさせるため# systemctl daemon-reloadが必要)

この設定により、httpdはネットワーク疎通できるようになってからサービス起動するようになります。

詳細は、後述します。

詳細

ドロップインスニペット (drop-in file) の管理TIPS

ドロップインスニペットを設定すると、以下のようにファイルが作成されます。インストール時に配置された元のユニットファイルを変更せず、別ファイルに設定を追加する形です。

$ cat /etc/systemd/system/httpd.service.d/override.conf

[Unit]
After=network-online.target
Wants=network-online.target

ドロップインスニペットの存在確認

あるユニットにドロップインスニペットが存在していることは、以下のようにsystemctl statusの結果にDrop-In:行が表示されることでも確認できます。

$ systemctl status httpd

● httpd.service - The Apache HTTP Server
   Loaded: loaded (/usr/lib/systemd/system/httpd.service; enabled; vendor preset: disabled)
  Drop-In: /etc/systemd/system/httpd.service.d
           └override.conf

ドロップインスニペットの修正

ドロップインスニペットを修正したいときは、前述の手順と同様に、systemctl editで可能です。

ドロップインスニペットの削除

ドロップインスニペットを削除したいときは、編集画面で中身を空にして保存してもキャンセルされてしまい削除できないので注意が必要です。

# systemctl edit httpd

(ドロップインスニペットのファイルを空にして保存しようとした場合)
Editing "/etc/systemd/system/httpd.service.d/override.conf" canceled: temporary file is empty.

ドロップインスニペットを削除したいときは、以下のようにsystemctl revertを利用できます。ただし、必要なファイルも削除されないか注意が必要です。
# systemctl revert httpd

Removed /etc/systemd/system/httpd.service.d/override.conf.
Removed /etc/systemd/system/httpd.service.d.

systemctl revertにより、指定したユニットのドロップインスニペットが削除されますが、他に手動で修正したユニットファイルも削除(※)されるようなので注意が必要です。systemctl revertではどうしても支障がある場合は、手動でドロップインスニペットのファイルを削除する方が無難でしょう。
(※)詳細な動作は確認していませんが、/usr/lib/配下のオリジナルのユニットファイル(vendor-supplied)を/etc/system/system配下等にコピーしてから修正した同名のユニットファイルがあればそれが削除され、オリジナルのユニットファイルのみが存在する状態に戻るようです。なお、オリジナルのユニットファイルが無く、自作したユニットファイルが1つあるだけであれば、それは削除されずに残るはずです。

ドロップインスニペットによる設定の反映確認

ドロップインスニペットで追加した設定が反映されていることは、systemctl showでも確認できます。 $ systemctl show httpd

…
After=remote-fs.target nss-lookup.target system.slice systemd-tmpfiles-setup.service httpd-init.service tmp.mount systemd-journald.socket basic.target sysinit.target -.mount network-online.target network.target
(お使いの環境によって、改行されず見切れるので続きを見る場合は → キーで最後まで見られます)
…

ネットワーク関連ユニットの把握

After=network.targetの意味や、関連する特殊ユニットについて説明します。

概要

システム起動時、以下のnetwork-pre.targetから順にユニットが起動されます。

  1. network-pre.target
    ↑After
  2. NetworkManager.service
    ↓Before(,Wants)
  3. network.target (After=network-pre.target含む)
    ↑ Requires
  4. NetworkManager-wait-online.service (After=NetworkManager.service含む)
    ↓ Before(,WantedBy)
  5. network-online.target (After=network.target含む)

※NetworkManager-dispatcher.serviceについては省略

グレーの矢印 (↑、↓) や補記は、矢印の元のユニットにおいてBefore,After等の順序関係が矢印の先のユニットに対して指定されていることを示しています。依存関係 (Wants,Requires等) も記載しています。

「network~」はsystemdにおけるネットワーク関連の特殊ユニット(詳細はman systemd.special)、「NetworkManager~」はOS標準のネットワーク管理サービスであるNetworkManager関連のユニットです。

systemctl list-dependenciesでユニットの依存関係を確認してみると、システム起動時には、NetworkManager.serviceが起動するよう指定されていることが分かります(NetworkManager.serviceは、WantedBy=multi-user.targetが指定されています)。

$ systemctl list-dependencies

default.target
…
● ├NetworkManager.service
…

また参考までに、各ユニットは以下のように有効化(enabled)、もしくは特殊ユニットの場合はstaticになっていることが分かります。

# systemctl list-unit-files | grep NetworkManager

NetworkManager-dispatcher.service                                      enabled
NetworkManager-wait-online.service                                     enabled
NetworkManager.service                                                 enabled

# systemctl list-unit-files | grep network

network-online.target                                                  static
network-pre.target                                                     static
network.target                                                         static

次に、各ユニットの説明をします。

1. network-pre.target

特殊ユニットの1つで、サービスの起動順序の制御等に使用されます。
ネットワークインタフェースの設定前に実行されるユニットです。

なお、network-pre.targetは、network.targetと同様にパッシブユニットです。パッシブユニットについては後述のnetwork.targetの箇所で説明します。

2. NetworkManager.service

特殊ユニットではなく、通常のユニットです。
NetworkManagerのメインのユニットです。ネットワークインタフェースの設定処理等を実行します。

3. network.target (重要)

特殊ユニットの1つで、サービスの起動順序の制御等に使用されます。

After=network.targetが指定されたユニット(サービス)の起動は、ネットワーク疎通可能になるまで遅延される訳ではありません。
systemdがnetwork.targetを起動すると、ネットワークの設定を行うサービスが開始した状態にはなりますが、それはネットワークデバイスの設定(IPアドレス設定等)までが完了した状態ではありません。
そのため、After=network.targetが指定されたユニットは、OS起動時にはnetwork.targetの起動後に自身のサービスを起動し始めるのですが、まだその時点ではIPアドレスが使用可能になっていないこともあるので、その場合にはソケット割り当て(バインド)が失敗してしまいます。

では、何のためにAfter=network.targetが指定されているサービスがあるのかと言うと、それは起動時でなく停止時の順序制御のためのようです。
After=network.targetが指定されたユニットが停止するまで、network.targetの停止処理が開始されることはありません。
つまり、自身が停止するまでネットワークが起動していないといけないサービスには、After=network.targetを指定しておくべきということになります。
このように、停止時の順序の話になると、「After」という単語の意味とは逆の働きをするので、ややこしいです。

network.targetはパッシブユニットです。パッシブユニットについては後述します。

4. NetworkManager-wait-online.service

特殊ユニットではなく、通常のユニットです。
これもNetworkManager関連のユニットです。

NetworkManager-wait-online.serviceは、後述のnetwork-online.targetより先に起動します。After=network-online.targetを設定したときに実質的なネットワーク起動完了を判定するのが、このNetworkManager-wait-online.serviceなのだと思います。

NetworkManager-wait-online.serviceのユニットファイルには、Before=network-online.targetが記載されています。

つまり、NetworkManager-wait-online.serviceが起動完了(=ネットワーク起動完了)してから、network-online.targetの起動が開始されるということです。

5. network-online.target (重要)

特殊ユニットの1つで、サービスの起動順序の制御等に使用されます。

network.targetの場合とは異なり、After=network-online.targetが指定されたユニットの起動は、ネットワーク疎通可能になるまで遅延されます。
前述のNetworkManager-wait-online.serviceがネットワーク起動(IPアドレス設定等)が完了したことを判定後、network-online.targetが起動完了となります。その後にAfter=network-online.targetが指定されたユニットが起動開始されますので、確かにネットワーク疎通可になってから起動できます。
network-online.target自体のタイムアウトは90秒のようです。

なお、開発元によると、ネットワークを利用するサーバソフトウェアのサービスにおいてAfter=network-online.targetを多用しないことが強く推奨されているようです (後述)。これは、例えばサーバソフトウェアはネットワーク起動前であってもローカルコネクションを受け付ける方が一般的には望ましく、そもそもAfter=network-online.targetの主目的がネットワーク無しでは動作できないクライアントソフトウェアのためにあると説明されています。
また、開発者向けに、ネットワーク設定が動的に変わっても動作するようプログラムを修正することを求めています。
ただ、実際には例えばhttpdの自動起動失敗を回避するためAfter=network-online.targetを指定したいケースもあるので、システム管理者からすると、なかなかこの思想の通りに運用するのは難しいところです。

以下、開発元のページより引用。

It is strongly recommended not to make use of this target too liberally: for example network server software should generally not pull this in (since server software generally is happy to accept local connections even before any routable network interface is up). Its primary purpose is network client software that cannot operate without network.

If you are a developer, instead of wondering what to do about network.target, please just fix your program to be friendly to dynamically changing network configuration.

 
出典:systemd.io

ちなみに、network-online.targetは、network.targetとは異なりパッシブユニットではありません。

(参考)NetworkManager-dispatcher.service

特殊ユニットではなく、通常のユニットです。

これもNetworkManager関連のユニットで、dispatcherはネットワークイベントが発生した場合に、スクリプトを実行するもののようです。
詳細は省略します。

(補足) Systemdの用語

※公式ドキュメントにハッキリとした定義が見当たらないので、私が理解している範囲でまとめています。

passive unit

パッシブユニットとアクティブユニットに関する簡単な説明です (開発元のドキュメント)。

パッシブユニットは、直接起動 (systemctl start) することはできません。他のサービス (provider) によって依存関係が指定される場合があります。通常、他のサービス (consumer) によって依存関係は指定されません。これには、パッシブユニットがトランザクションの一部でなく、順序のために存在するという理由があるようです。

例えば、パッシブユニットであるnetwork.targetは、consumer によって After=network.target のように順序関係を指定される場合がありますが、Wants=network.targetRequires=network.targetのように依存関係は通常指定されません。

一方、非パッシブユニット (通常のユニット?アクティブユニット?) については、そのようなことは無いようです。

例えば、非パッシブユニット (active target?) である network-online.targetは、consumer によって Wants=network.targetRequires=network.targetのように依存関係を指定される場合があります。順序関係を指定される場合もあります。
実際、前述の設定例では、httpd (consumer) において、After=network.targetWants=network.target の両方を指定しています(開発元の設定例と同等)。

なお、パッシブユニットのユニットファイルには、RefuseManualStart=yesが記載されているようです (明確な説明はありませんが)。

provider、consumer

前述のproviderとconsumerについても、公式ドキュメントに詳細な記述が見当たらないのですが、基本的には、あるユニットが他のユニットを利用する場合、利用する側のユニットがconsumer、利用される側のユニットがproviderという意味のようです (つまり文脈依存)。

例えば、systemd-resolved というユニットが、他のパッケージによって管理されている /etc/resolv.conf 内の設定を参照するケースでは、systemd-resolved は provider でなく consumer となるようです (開発元のドキュメント)。

参考URL等

関連記事

happy-nap.hatenablog.com

happy-nap.hatenablog.com

happy-nap.hatenablog.com

happy-nap.hatenablog.com

時刻ズレを安全に復旧する(Linux,chrony)

概要

「時刻同期できておらず、気付いたら時刻がズレていた!」という場合、復旧方法を間違えると大きなトラブルにつながることも。

本記事は、時刻ズレを安全に復旧する方法として、復旧手順の一例と、復旧計画の策定までの流れをまとめたものです。

主に、RHEL7、CentOS7以降でOS標準のchronyを使用した環境を対象としていますが、基本的な考え方はどのシステムでも共通です。

chrony全般の説明は以下の記事にまとめてあります。

happy-nap.hatenablog.com

happy-nap.hatenablog.com

なお、本記事はあくまで参考情報です。実際の復旧作業に際しては二次トラブルが生じないよう十分な検討と準備が必要です。

Stable Diffusionで作成 (プロンプト:time synchronization effect, cyber space background, dark terminal prompt)
Stable Diffusionで作成 (プロンプト:time synchronization effect, cyber space background, dark terminal prompt)

本記事の目的
  • 時刻ズレによるトラブル発生リスクを把握する。
  • 時刻ズレの復旧計画を適切に検討する。

まずは復旧手順の一例

稼働させたまま時刻をゆっくり修正(slew)

本記事では、状況整理や復旧計画の流れ全体について説明しますが、ひとまず例として「サーバや業務サービスを稼働させたまま時刻をゆっくり修正(slew)する」手順を記載します。
※この手順が適切かどうかは状況によるので、詳細は記事の続きをご覧ください。

仮定として、既に存在しない古いNTPサーバを参照する設定になったままのNTPクライアントについて、参照先NTPサーバの修正(+その反映のためにchronyサービスの再起動)が必要といったケースを想定します。

時刻をゆっくり修正(slew)する場合、以下のようにchrony.confのmakestep 1.0 3行をコメントアウトしてから、chronyサービスを再起動します。

# vi /etc/chrony.conf

#makestep 1.0 3 ←コメントアウト
※さらに、必要に応じserver行やpool行の参照先NTPサーバの指定等も設定する

# systemctl restart chronyd

chrony(chronyd) のデフォルト設定では、chronyのサービス起動時にNTPサーバと大幅に時刻がズレていた場合、一気に時刻修正(stepモード)が行われます。上記の手順は、そのstepモードによる時刻修正を無効化してからchronyサービスを再起動するものです。

chronyサービスの再起動後、正常にNTPサーバと同期が開始できたとして、以下のように通常のslewモードによりゆっくり時刻同期されることを監視します。chronyはデフォルトで1秒の時刻ズレを最速12秒間で修正します(maxslewrate)。1分間の時刻ズレを修正するのにかかる時間が最速で720秒(12分)です。

$ chronyc sourcesにて、行頭が ^* になっている行が表示され、NTPサーバと時刻同期できていることを確認します。

(★マークは説明用の目印です)
MS Name/IP address         Stratum Poll Reach LastRx Last sample               
========================================================
^*★ ntp-server1.domain.com          1   3   111    22  -1000us[ -100ms] +/-   10ms
^?  ntp-server2.domain.com          1   3   111    22  -1000us[ -100ms] +/-   10ms
※値はダミーです

また、$ chronyc trackingを間隔を置きながら何度か実行し、System time行のX.XXXX second slow(もしくはfast)…の数値が徐々に小さくなり、時刻修正が進んでいることを確認します。
$ chronyc tracking

(★マークは説明用の目印です)
Reference ID    : AB00123C (domain.com)
…
System time     :  0.000000555 seconds slow of NTP time ★
…
※値はダミーです。

各設定やコマンドの詳細は、こちらの記事にまとめてあります。

業務サービスを稼働させたまま上記の操作を行う場合は、業務サービスの方に影響が無いかも随時確認します。

時刻修正が完了した後は、コメントアウトしたmakestep 1.0 3行のコメントを解除し、再度chronyを再起動しておきます。コメントアウトしたままが良ければそのままで良いです。

基本

ここからは、時刻ズレが発生した際の状況整理や復旧計画について説明します。

時刻ズレによるトラブル発生リスク

時刻を正確に扱うシステムでは、少しの時刻ズレが深刻なデータ不整合やサービス停止を引き起こす場合があります。データベースシステム、認証系システム(SSO全般、Kerberos、TOTP)等です。
時刻ズレを発見した場合には、速やかに復旧計画を立てましょう。

時刻ズレを発見したときにすべきこと

以下のようなポイントを整理する必要性があります。

  • 時刻ズレにより、既にトラブルが発生していないか
  • 時刻ズレが生じているサーバを全て洗い出したか
  • 時刻ズレの状況は、サーバ側の「時刻が遅れている」か「時刻が進んでいる」か (あるいは仮想基盤上のゲストの場合、ホストと時刻同期されているか、等)
  • 時刻ズレが生じた原因が明確か

サーバ側の「時刻が遅れている」よりも「時刻が進んでいる」方が、仮に一気に時刻修正してしまった場合には時刻が戻る(逆進する)ので危険なケースが多いです(一概には言えませんが)。

また「時刻ズレの原因」も正確に把握すべきです。NTP設定自体が漏れていた、設定していたがNTPサーバと正常に通信できなくなっていた、等。どこをどう直せば時刻同期できるようになるのかを明確にすることが重要です。

復旧計画の立案

以下のようなポイントを整理する必要性があります。

  1. 基本的な復旧手順の確立
  2. 制約事項の整理
  3. 復旧計画の確定

順に説明します。

1. 基本的な復旧手順の確立

まず「時刻ズレの原因」に応じ、基本的な復旧手順を確立します。NTP設定やネットワーク設定の見直しなどです。サーバの再起動やNTPサービス(chrony)の再起動が必要か、等も整理しておきます。

手順確立のため使用できるテスト機があれば、先に試しておきましょう。

2. 制約事項の整理

焦って復旧方法を間違えると、さらに大きなトラブルに発展する可能性もあります。適切な復旧方法を選ぶため、例えば以下の優先度順で状況を整理します。

もちろん、影響を受けるデータやサービスがそもそも無い場合は、気にせず復旧させてしまえば良いです。

a. 時刻修正のために、対象のサーバやサービス(業務アプリ等)を停止可能か

停止可能な場合は、まずサーバやサービスを停止してから安全に復旧作業を開始する計画を立てます。これにより、サービスと関連するデータやプロセスが時刻修正による影響を受けないことを担保できます。

停止不可の場合は、次の項目を確認します。

b. 対象のサーバやサービス(業務アプリ等)は、稼働したまま時刻を一気に修正(step)しても問題が無いか

問題が無い場合(時刻を正確に扱わないシステムの場合)は、サーバやサービスを稼働させたまま一気に時刻修正する計画を立てます。

時刻修正が逆進かどうかもここで考慮します。サーバ側の「時刻が遅れている」場合は、一気に時刻修正するとサーバ上の時刻が急に進みます。逆に「時刻が進んでいる」場合は、一気に時刻修正するとサーバ上の時刻が急に戻ります。使用している業務アプリ等で不都合が無いかを慎重に判断します。

問題がある場合は、次の項目を確認します。

c. 対象のサーバやサービス(業務アプリ等)は、稼働したまま時刻をゆっくり修正(slew)すれば問題ないか

問題が無い場合は、サーバやサービスを稼働させたままゆっくり時刻修正(slew)する計画を立てます。

時刻修正の「ゆっくり」の程度はここで考慮します。chronyの場合、chrony.confのmakestep行をコメントアウトすることで、次回のchronyサービス起動時のstepモードでの時刻修正を回避でき、その後slewモードで時刻が修正されます。slewモードの時刻修正の速度(maxslewrate)のデフォルト値は83333.333 ppmで、これは「1秒の時刻ズレを最速12秒間で修正」するものです。さらにゆっくり修正したい場合はmaxslewrateを小さくします。詳細はこちらの記事にまとめてあります。

なお、ゆっくり時刻修正することですら問題がある場合は、そもそも現実的に復旧計画を立てられる状況にないので、再度サーバやサービスの停止可否から調整し直しましょう。

3. 復旧計画の確定

上記で整理した、復旧手順や、サーバ/サービスの停止可否、一気に時刻修正(step) or ゆっくり時刻修正(slew)を考慮して復旧計画を確定します。

一気に時刻修正(step)しても良ければ、正常に時刻同期ができるよう対処すれば良いだけです。

c.のゆっくり時刻修正(slew)する場合には、本記事の冒頭に記載したような手順が必要です。

なお、復旧すべき対象サーバが複数ある場合には、相互に連携する機能の有無を考慮し、対処タイミングを検討します。

上記により復旧計画を立案できたら、実行しましょう。

(ケースごとに手順が異なるので、本記事の説明はここまでです)

まとめ

本記事では、時刻ズレを安全に復旧する方法として、復旧手順の一例と、復旧計画の策定までの流れをまとめてみました。

参考

関連記事

happy-nap.hatenablog.com

happy-nap.hatenablog.com

happy-nap.hatenablog.com

happy-nap.hatenablog.com

happy-nap.hatenablog.com

ESXiサーバのLAG設定

概要

VMware vSphere環境において、ESXiサーバの性能向上のためLAGを使用することがあります。リンクアグリゲーション、IEEE802.3ad(IEEE802.1AX-2008)のことです。呼び方は、ポートチャネルや、CiscoではEtherChannel、HPEではトランク等…。
本記事は、ESXiサーバにおけるLAG設定の概要をまとめたものです。 主な対象はESXi 6系、7系です。

本記事の目的

  • ESXiサーバのLAG設定の概要を把握する。
  • 設定のポイントや、接続先の物理スイッチと一致させる設定箇所を把握する。


目次

基本

ESXiサーバで利用可能なLAG構成

使用する仮想スイッチの種類により、サポートされるLAG構成が異なります。

仮想スイッチ種別 サポートされるLAG構成
標準仮想スイッチ(vSS) static LAG(静的)のみ
分散仮想スイッチ(vDS) static LAG(静的)、およびLACP(動的)

vDSは、vSphere Enterprise Plus相当で利用可能です。vSphere Standardでは利用できません。
当然ですが、ESXiサーバの接続先となる物理スイッチでも使用するLAG構成をサポートしている必要性があります。

ESXiサーバにおけるLAGの用途や基本構成

LAGを構成することで、より大きなネットワーク帯域の確保や、ネットワーク障害時にも運用継続するためのNIC冗長性の確保ができます。
例えば、以下のトラフィック用にLAGを適用する構成が考えられます。

  • 仮想マシン(ゲスト)がESXiサーバの外と通信する際のトラフィック
  • ESXiホストがストレージと通信する際のトラフィック
    ※ただし、iSCSIマルチパスとの併用は未サポート(後述)

LAG構成では、必要に応じて以下の構成も検討します。

  • 10Gbps NIC (もしくはより大きな帯域:40Gbps等)
  • ジャンボフレーム
  • ESXiサーバ側でLAGを構成する物理ポートは、複数のネットワークカードから構成(1つのネットワークカード障害時の運用継続)
  • 物理スイッチ側でLAGを構成する物理ポートは、複数の筐体から構成(1つの筐体の障害時の運用継続)
    ※スタック構成やマルチシャーシLAG(MLAG)等

static LAGの設定

標準仮想スイッチもしくは分散仮想スイッチにて対象NICのチーミングを構成し、物理スイッチのstatic LAGを設定したポートと接続します。

static LAGの場合、仮想スイッチ側の設定におけるポイントは以下です。

  • 仮想スイッチのロードバランシングモードは「IPハッシュに基づいたルート」
  • ネットワーク障害検出ポリシーは「リンクステータスのみ」
  • すべてのNICを「アクティブ」

以下、参考になるVMwareのdocsです。

LACPの設定

分散仮想スイッチにて対象NICのチーミング(LAGという設定項目)を構成し、物理スイッチのLACPを設定したポートと接続します。
LACPの場合、仮想スイッチ側の設定におけるポイントは以下です。

  • 仮想スイッチのLAGのロードバランシングモード(ハッシュアルゴリズム)は物理スイッチ側のハッシュアルゴリズムと一致
  • 物理NICでなく作成したLAGを「アクティブ」なアップリンクに設定

以下、参考になるVMwareのdocsです。

詳細

注意点

LAGとiSCSIマルチパスの併用は未サポート

ESXiにてLAGを構成するNICを、iSCSIマルチパスに使用することはVMware社にてサポートされていません(iSCSIマルチパス:複数のvmnicをそれぞれiSCSI用にポートバインドさせるソフトウェアベースの冗長パス構成)。
異なるレイヤの冗長化機能を同時に使用することになるためと思われます。
分かりやすい説明が見当たりませんでしたが、VMware社のKBに、「iSCSI ソフトウェアのマルチパスには使用しないでください」といった記載があります。

LAGの動作確認、通信不可時の切り分け

LAGを構成したポートが意図通りに動作しているか動作確認の観点についてです。

うまく通信ができない場合や、あるいはうまく通信できているように見えても実は設定が間違っている場合があるかもしれません。例えば、設定が間違っている場合、パケットロスが一部発生して通信が不安定になる等、ハッキリとしたトラブルとして捉えづらい現象が発生する可能性もあります。
本稼働後のトラブルを防ぐために、本番運用における負荷や利用形態を想定した動作確認をお勧めします。

以下のような観点が挙げられます。

  • ESXiサーバ側(あるいは物理スイッチ側)の対象NICを一部切断し冗長性の確認
  • 物理スイッチ側のログやステータス確認コマンドにて、LAGのネゴシエーションが意図通りに成功していることの確認(特にLACP使用時)
  • 動作確認用にトラフィックを発生させ、スループットの十分性や、遅延やロスが無いことの確認
    • スループット:大きな/多くのファイルコピー等によるトラフィック発生
    • 遅延やロス:ping等の遅延やロスを集計可能なツールの使用
    • その他:本番運用を想定したアプリケーション動作によるトラフィック発生
    • さらに上記の冗長性の確認と組み合わせ、NICの冗長性が失われた際にもアプリケーションレベルで動作に影響が無いことの確認
  • ジャンボフレームを使用している場合は、ジャンボフレーム疎通の十分性
    • ジャンボフレームのping疎通確認方法については、別記事に記載あり

ESXiサーバのジャンボフレーム疎通確認(vmkping)

概要

VMware vSphere環境において、ESXiサーバの性能向上のためジャンボフレームを使用することがあります。NFSiSCSIを用いたストレージ通信や、VMotionの通信などです。
本記事は、ESXiサーバにおけるジャンボフレームの疎通確認方法をまとめたものです。
主な対象はESXi 6系、7系です。MTUの説明などは主にIPv4環境について記載しています(IPv6でなく)。

本記事の目的

  • ESXiサーバが任意の通信相手とジャンボフレーム疎通できているか確認する。
  • ジャンボフレーム疎通できない場合に、切り分けする。


目次

基本

ESXiサーバからのpingによる疎通確認(vmkping)

ESXiサーバにsshログイン後、CLIにて以下のコマンドを実行します。
# vmkping -I (送信元vmkernel) -d -s (送信サイズ) (送信先IPアドレス)

オプション 説明
-I (vmk名) 送信元vmkernelポート指定
-d DF bit(Don’t Fragmentフラグ)指定
-s (サイズ) 送信サイズ指定(単位:バイト)
ICMPヘッダを含まないICMPデータ部のサイズ
デフォルトは56バイト

疎通確認したい経路や送信先に対して適切にping送信できるようオプション指定します。
-Iオプションでは、ping送信元のインタフェースを指定します。vmkernelの名前(vmk0等)を指定可能です。ESXiサーバは複数のvmkernelで構成することが多いので、明示的に指定した方が分かりやすいです。
-dオプションは、ジャンボフレームの疎通確認時には必須のオプションです。このオプションの指定が漏れた場合、経路上でフラグメント(分割)が可能なDF bitオフのpingデータを送信することになるため、本当はMTU 1500の経路なのにping疎通が成功してしまうといった動作が生じ得ます。
-sオプションは、送信するpingデータの大きさを指定します。このオプションで指定したバイト数+28バイトが経路のMTU範囲内であれば、ping疎通が成功します。具体的には以下の通りです。

  • MTU 9000の経路における疎通確認時
    • -s 8972 を指定 (+28すると9000):ping成功する
    • -s 8973 を指定 (+28すると9001):ping失敗する
  • MTU 1500の経路における疎通確認時
    • -s 1472 を指定 (+28すると1500):ping成功する
    • -s 1473 を指定 (+28すると1501):ping失敗する

この+28の意味については、後述します。

VMware社のKBに詳細な説明があります。

また、ESXiサーバ上でvmkping --helpを実行することでvmkpingコマンドのヘルプを参照できます。

vmkpingが失敗する場合の切り分け

ジャンボフレームを指定したvmkpingが失敗する場合、以下のようにオプションを変更しながらvmkpingを再実行することにより、経路上のどの箇所でジャンボフレームの疎通ができなくなっているかを切り分けます。

  • -sで指定する値を小さくしていき、どの値までなら疎通可能かを確認する。
  • 送信先IPアドレスが別ネットワークである場合、まず同一ネットワーク内のIPアドレスでジャンボフレーム疎通なものがあればそれを送信先IPアドレスとして指定する。
  • 可能であれば、vmkpingを実行したホストとは別のホスト(ストレージ等)から同様にジャンボフレームの疎通確認を行う。

基本的には、送信元と送信先の間の経路にあるすべての機器や仮想スイッチが意図したサイズのジャンボフレームを許可するよう設定できている必要性があります。

詳細

vmkpingの-sオプションの値とMTUサイズの違い

vmkpingの-s オプションで指定する値は、「ICMPヘッダを含まないICMPデータ部のサイズ」です。
以下の説明にあるように28バイトを加えることで、IPレイヤまでのデータのサイズになります。

  • ICMPデータ部のサイズ(-sオプションで指定する値)
  • ICMPヘッダのサイズ(8バイト)
  • IPv4ヘッダのサイズ(20バイト)

上記の合計サイズが経路のMTU範囲内であれば疎通可となります。

ちなみ、上記の合計サイズに対してさらに、

も加えると、それがイーサネットフレームのサイズです。
(さらに余談ですがフレッツ網などPPPoEの場合は別ですがESXi環境とはほぼ関係無いので省略します)

Systemdによるサービス管理ノウハウ (基本)

概要

Systemdは、RHEL7、CentOS7以降における基本的なサービス管理機能 (等を含むシステム管理デーモンやツールの一式) です。従来はUpstart、SysVinitがありました。

本記事では、SystemdによるRHEL、CentOSのサービス管理に関する基本的なポイントをまとめます。

関連記事として、Systemdのネットワーク関連ユニットについて以下にまとめてあります。

happy-nap.hatenablog.com

本記事の目的

  • Systemdで管理されているサービスやその設定を確認する。
  • Systemdで管理されているサービスを手動で停止、起動する。
  • 自身で作成したプログラム等をSystemdのサービスとして登録する。

基本

Systemd の基本的なサービス管理コマンドについて説明します。

操作対象とするサービスは、httpd.serviceを例にします。

httpd.service は Apache HTTP Server のサービスが Systemd に登録されたものです。適宜、サービス名を読み替えてください。

サービス管理 (systemctl)

基本的なサービス管理コマンド、systemctl です。

各項目の詳細は$ man systemctlで確認できます。

サービスの起動状態の一覧表示(systemctl list-units)

現在のサービスの起動状態を一覧で確認する方法です。

$ systemctl list-units --all --type=service

UNIT          LOAD   ACTIVE SUB     DESCRIPTION
…
httpd.service loaded active running The Apache HTTP Server 
…
  • ACTIVE列にてサービス起動状態を確認可能
    • active : サービスが起動した状態である
    • inactive : サービスが停止した状態である
    • failed : サービスが何らかエラーの状態である(サービス起動失敗等)
    • (その他) reloading, activating, deactivating


  • SUB列でもサービス起動状態を確認可能(typeがサービスの場合)
    • running: プロセスが起動した状態である
    • exited: 処理を終えてプロセスが終了した状態である

--type serviceはサービスのみを表示するためのオプションです。省略するとサービス以外のUnitも表示されます。
特定のサービスのみ表示させる場合は、$ systemctl list-units httpd*のようにパターン指定するか、$ systemctl list-units | grep httpdのように実行します。

ACTIVE列とSUB列の違いは微妙ですが、プロセスが常時起動するサービスの場合、基本的にACTIVE列がactiveのときはSUB列はrunningになっているはずです。対して、処理の実行後、プロセスが終了する類の特殊なサービスはACTIVE列がactiveかつSUB列がexitedになります。

参考までに、コマンド実行時に以下の説明が表示されます。

ACTIVE = The high-level unit activation state, i.e. generalization of SUB.
SUB    = The low-level unit activation state, values depend on unit type. 

サービスの自動起動設定の一覧表示(systemctl list-unit-files)

サービスが自動起動する設定かどうかを確認する方法です。

$ systemctl list-unit-files --type service

UNIT FILE                                     STATE   
…
httpd.service                                enabled 
…
  • STATE列にてサービスの自動起動設定を確認可能
    • enabled : 自動起動が有効
    • disabled : 自動起動が無効
    • static : 単体では自動起動しない (staticはsystemctlで有効化、無効化できないもの。他サービスとの依存関係に従い起動するもの等)

サービスの起動/停止/再起動/リロード(systemctl start / stop / restart / reload)

サービスの起動や停止等の操作方法です。

(例としてhttpdサービスに対するコマンドを記載)

  • サービス起動
    # systemctl start httpd

  • サービス停止
    # systemctl stop httpd

  • サービス再起動
    # systemctl restart httpd

  • サービスリロード
    # systemctl reload httpd

reloadは、設定ファイルの変更点を反映する際に使用されます。

例えばhttpdであれば、httpd.confの変更点の反映などです。そのサービスの詳細仕様によりますが、reloadはrestartと異なり、基本的にサービス停止せず設定反映できます。ただし、サービスによってはreloadに対応していない場合があります(ユニットファイルにExecReloadが定義されていない場合)。

補足として、httpdの場合は reload により、内部的には httpd -k graceful が実行されるはずです。詳細はhttpdのマニュアルやユニットファイル (後述) を参照願います。

サービスの状態確認(systemctl status)

現在のサービスの起動状態を確認する方法です。

(例としてhttpdサービスに対するコマンドを記載)

$ systemctl status httpd  (★マークは説明用の目印です)

● httpd.service - The Apache HTTP Server
  Loaded: loaded (/usr/lib/systemd/system/httpd.service; enabled★; vendor preset: disabled)
  Active: active (running)★ since Thu 2022-05-01 02:02:02 UTC; 2min 2s ago
    Docs: man:httpd(8)
          man:apachectl(8)
Main PID: 5001 (httpd)
  Status: "Total requests: 0; Current requests/sec: 0; Current traffic:   0 B/sec"
  CGroup: /system.slice/httpd.service
          ├─5002 /usr/sbin/httpd -DFOREGROUND
          ├─5003 /usr/sbin/httpd -DFOREGROUND
 …

Loaded:行は、Unitファイルのパスと、サービスの自動起動設定(enabled or disabled)が表示されます。前述のサービスの自動起動設定の一覧表示と同様の内容です。

Active:行は、サービスの起動状態(active or inactive等)が表示されます。前述のサービスの起動状態の一覧表示(systemctl list-units)と同様の内容です。

Main PID:行、CGroup:行は、それぞれメインプロセスと、メインプロセスからフォークされた子プロセスです。

詳細

もう少し詳しい内容です。

Unitの構成、種類

systemdはサービス等をUnitの単位で扱います。

ここでは、Unitの構成や配置について簡単に説明します。

ユニットファイル

Unitはファイル形式で定義されます。

そのファイル名の書式はunit_name.type_extensionです。

unit_nameは、そのユニットの名前(サービスであればサービス名)です。
type_extensionは、.service(サービスを定義するもの)、.target(複数のサービスをまとめるためのもの)、.device(デバイス)、.timer(cronのように使えるもの)等、他にもあります。
詳細は、man systemd.unitや、 RedHat社のマニュアルが参考になります。

ユニットファイルに関する主なパス

ユニットファイルの主な格納パスは以下です。

  • /usr/lib/systemd/system/:パッケージマネージャによって配置
  • /etc/systemd/system/:システム管理者によって配置

前者が、RPM等にデフォルトで含まれるユニットファイルが格納されるパスです。後者は、システム管理者が個別にユニットファイルを用意して格納するためのパスです。

同名のユニットファイルが /usr/lib/systemd/system//etc/systemd/system/ の両方に配置された場合、/etc/systemd/system 内のファイルが優先されます。

詳細は、 man systemd.unit の "UNIT FILE LOAD PATH" セクションや、開発元のドキュメントに記載があります。

例:httpdの場合

例えば、httpdの場合、関連するユニットファイルは以下です。

$ ls -l /usr/lib/systemd/system/

(★マークは説明用の目印です)
…
-rw-r--r--  1 root root  314  3月 22 02:27  httpd-init.service
-rw-r--r--  1 root root  944  3月 22 02:27  httpd.service ★
drwxr-xr-x  2 root root   26  4月 13 09:32  httpd.service.d
-rw-r--r--  1 root root  244  3月 22 02:27  httpd.socket
drwxr-xr-x  2 root root   31  4月 13 13:17  httpd.socket.d
-rw-r--r--  1 root root  662  3月 22 02:27  httpd@.service
…

ファイルがたくさんありますが、通常のWebサーバとして使用するhttpdサービスのユニットファイルはhttpd.serviceです。

ユニットを有効化した際の動作

# systemctl enable httpdによりユニットを有効化すると、そのユニットファイル内の定義 (後述の[Install]セクション) に従い動作します。

一般的なサービスであれば、/etc/systemd/system/multi-user.target.wants/配下にシンボリックリンクが作成されます。

このディレクトリ配下にあるユニットファイルは通常のマルチユーザモード(multi-user.target)でのシステム起動時に読み込まれますので、システム起動時にサービス自動起動することになります。

例として、httpd.serviceユニットファイル内の[Install]セクションは以下のように記載されています。

[Install]
WantedBy=multi-user.target

上記の記載により、このユニットを有効化すると、multi-user.target配下にシンボリックリンクが作成されるということです。

作成されたシンボリックリンクは以下です。
$ ls -l /etc/systemd/system/multi-user.target.wants/

…
lrwxrwxrwx  1 root root 37  4月 14 11:29 httpd.service -> /usr/lib/systemd/system/httpd.service
… 

ユニットファイルをカスタマイズする場合

サービス起動時のオプション変更等、ユニットファイルをカスタマイズしたい場合については、以下の記事にまとめてあります。

happy-nap.hatenablog.com

ユニットファイルの読み方

任意のプログラム等をSystemdのサービスとして登録にまとめて記載してあります。

(補足)テンプレート形式のユニット(name@xxx.service)

httpd@.serviceのように@(アットマーク)がついたサービスは、テンプレートです。例えば仮想コンソール(gettyやvnd等)で複数インスタンス起動するようなサービスの場合に使用されます。
systemctl start name@1.servicesystemctl enable name@1.serviceのように、@の後に任意の文字列を指定できます。(getty@tty1.service等)
@の後に指定した文字列は、ユニットファイル内の%l %i 変数に置き換えられます。

任意のプログラム等をSystemdのサービスとして登録

以下の流れです。

  1. サービスとして実行するプログラムを準備
  2. ユニットファイルを作成
  3. 作成したユニットファイルを読み込み、有効化

1. サービスとして実行するプログラムを準備

任意のプログラムを準備します。
プログラムの例として、簡単なシェルスクリプトを作成します。
# vi /usr/local/bin/sleeping.sh

#!/bin/sh
while true; do echo "zzz..." >> /tmp/sleeping.log; sleep 5 ; done

2. ユニットファイルを作成

/etc/systemd/system/配下にユニットファイルを作成します。各オプションの詳細はman systemd.serviceman systemd.unitで確認できます。
# vi /etc/systemd/system/sleeping.service

[Unit]
Description = just keep sleeping process

[Service]
ExecStart = /usr/local/bin/sleeping.sh
Type = simple

[Install]
WantedBy = multi-user.target

上記はとてもシンプルなユニットファイルの例です。実際の運用に際しては、マニュアルを参照の上、各オプションの精査が必要です。

  • [Unit]セクションのオプション ([Unit]セクションは任意)

    • Description:ユニットの説明
    • After:このAfterオプションで指定したユニットの起動開始後に自身のユニットを起動開始する。
    • Before:Afterの逆。
    • Wants:自身のユニットの起動時に、このWantsオプションで指定したユニットを起動する。緩い依存関係を指定しており、指定したユニットの起動が失敗しても自身のユニットは起動しようとする。
    • Requires:Wantsと同様に依存関係を指定するが、必須の依存関係を指定しており、指定したユニットの起動が失敗した場合に自身のユニットは起動失敗として扱われる。

    After、Beforeはサービス起動の「順序関係」を指定するオプションです。Wants、Requiresは「依存関係」を指定するオプションです。なお、Wants、Requiresを指定しても、起動の「順序」は制御されません。

  • [Service]セクションのオプション ([Service]セクションは必須)
    [Service]セクションは、サービス定義において重要です。いくつか記載しますが、他にも多くのオプションがあります。

    • ExecStart:サービス起動時(systemctl start)に実行するコマンド。
    • ExecStop:サービス停止時(systemctl stop)に実行するコマンド。
    • ExecReload:サービスリロード時(systemctl reload)に実行するコマンド。
    • Restart:サービスのプロセス停止時の挙動を指定。デフォルトはno(再起動しない)。例えばalwaysに指定するとプロセスが終了時には再起動される。
    • Type:サービスの起動方法。この指定に従いサービスが正常起動したかを判定する。例えば、プログラム単体を実行し続けるものであればsimpleを指定、子プロセスがそのサービスのメインプロセスになるものであればforkingを指定する。より詳細にサービスの起動判定を行いたい場合はnotify(やdbus)の指定が推奨される。
      • simple:ExecStartで指定したコマンドがサービスのメインプロセスである場合に使用する。プロセス生成した時点でサービス起動完了と判定する。ただし、プロセス生成後にExecStartで指定したコマンドを正常に実行できなくてもサービス起動が成功した扱いとなる(例:Userオプションで指定したユーザが存在しない場合でもサービス起動成功となる、等)。
      • forking:ExecStartで指定したコマンドにより実行されたプロセス(親)から起動(フォーク)された子プロセスがサービスとして動作する場合に使用する。親プロセスが終了した時点で起動完了と判定する。PIDFileオプションの使用が推奨される。なお、man systemd.serviceには、近年PIDFileが使用されないため、特に必要性が無ければType=notifyかType=simpleを使用するよう記載がある。
      • notify:simpleと同様、ExecStartで指定したコマンドがサービスのメインプロセスである場合に使用するが、そのプロセスがsystemdのライブラリ関数sd_notify()に対応している場合に使用する。プロセスは自身の起動完了をsd_notify()にてsystemdに通知する。
      • oneshot:simpleと同様、ExecStartで指定したコマンドがサービスのメインプロセスである場合に使用するが、そのプロセスが終了した時点で起動完了と判定する。その後、(RemainAfterExit=yesを指定しない限り)activeになることはなく、そのままサービスは停止(deactivatingやdead)となる。なお、RemainAfterExit=yesを指定した場合、コマンド終了後もサービスはactiveな状態となる。
    • PIDFile:PIDファイルのパスを指定する。主に、Type=forkingのサービスではこのオプションでメインプロセスのPIDファイルを指定することが推奨される。
       
  • [Install]セクションのオプション ([Install]セクションは任意)
    • WantedBy:このWantedByオプションで指定したユニットの起動時、自身のユニットを起動する。

    [Install]セクションでは、systemctl enablesystemctl disableでユニットを有効化、無効化した際の処理を定義します。例えば、enable時にはWantedByで指定したユニットの.wantsディレクトリに自身のユニットを登録する等です。 前述のWantsの逆でWantedBy、Requiresの逆でRequiredByというオプションがあります。これらは、そのオプションで指定したユニットの起動時に自身のユニットを起動するものです。

3. 作成したユニットファイルを読み込み、有効化

ユニットファイルを作成後、以下のように反映、有効化することでシステム起動時に自動起動するサービスとして設定完了です。

ユニットファイルの変更後は以下のようにsystemdにて読み込みが必要です。
# systemctl daemon-reload

作成したユニットファイルのサービスを有効化します。
# systemctl enable sleeping

手動でサービスを起動する際には以下のコマンドを実行します。
# systemctl start sleeping

上記のシェルスクリプトは、ファイル/tmp/sleeping.logに文字列を出力するものなので、ファイルの中身を確認すると、その動作を確認できます。
# tail -f /tmp/sleeping.log

参考

サービス起動時のエラー等

systemctlコマンドによるサービス起動が失敗した際には以下のようなメッセージが表示されます。
# systemctl start httpd

(サービス起動失敗時のメッセージ例)
Job for httpd.service failed because the control process exited with error code.
See "systemctl status httpd.service" and "journalctl -xe" for details. 

メッセージの指示に従い、# systemctl status httpd.service and journalctl -xeにてログを確認することが可能です。あるいは、messagesにもログが出力されている場合があります。

ユニットファイルの例

備忘用に、httpdデフォルトのユニットファイルを記載しておきます(RHEL8系)。

httpd.service (httpd本体)

/usr/lib/systemd/system/httpd.service

# See httpd.service(8) for more information on using the httpd service.

# Modifying this file in-place is not recommended, because changes
# will be overwritten during package upgrades.  To customize the
# behaviour, run "systemctl edit httpd" to create an override unit.

# For example, to pass additional options (such as -D definitions) to
# the httpd binary at startup, create an override unit (as is done by
# systemctl edit) and enter the following:

#       [Service]
#       Environment=OPTIONS=-DMY_DEFINE

[Unit]
Description=The Apache HTTP Server
Wants=httpd-init.service
After=network.target remote-fs.target nss-lookup.target httpd-init.service
Documentation=man:httpd.service(8)

[Service]
Type=notify
Environment=LANG=C

ExecStart=/usr/sbin/httpd $OPTIONS -DFOREGROUND
ExecReload=/usr/sbin/httpd $OPTIONS -k graceful
# Send SIGWINCH for graceful stop
KillSignal=SIGWINCH
KillMode=mixed
PrivateTmp=true

[Install]
WantedBy=multi-user.target

httpd-init.service (TLS用の鍵生成をするためのoneshotのサービス)

/usr/lib/systemd/system/httpd-init.service

[Unit]
Description=One-time temporary TLS key generation for httpd.service
Documentation=man:httpd-init.service(8)

ConditionPathExists=|!/etc/pki/tls/certs/localhost.crt
ConditionPathExists=|!/etc/pki/tls/private/localhost.key

[Service]
Type=oneshot
RemainAfterExit=no

ExecStart=/usr/libexec/httpd-ssl-gencerts

httpd\@.service (テンプレート)

/usr/lib/systemd/system/httpd\@.service

# This is a template for httpd instances.
# See httpd@.service(8) for more information.

[Unit]
Description=The Apache HTTP Server
After=network.target remote-fs.target nss-lookup.target
Documentation=man:httpd@.service(8)

[Service]
Type=notify
Environment=LANG=C
Environment=HTTPD_INSTANCE=%i
ExecStartPre=/bin/mkdir -m 710 -p /run/httpd/instance-%i
ExecStartPre=/bin/chown root.apache /run/httpd/instance-%i
ExecStart=/usr/sbin/httpd $OPTIONS -DFOREGROUND -f conf/%i.conf
ExecReload=/usr/sbin/httpd $OPTIONS -k graceful -f conf/%i.conf
# Send SIGWINCH for graceful stop
KillSignal=SIGWINCH
KillMode=mixed
PrivateTmp=true

[Install]
WantedBy=multi-user.target

まとめ

本記事では、SystemdによるRHEL、CentOSのサービス管理に関する基本的なポイントをまとめてみました。

参考

開発プロジェクト (アップストリーム)

RHELのマニュアル

関連記事

happy-nap.hatenablog.com

happy-nap.hatenablog.com

happy-nap.hatenablog.com

happy-nap.hatenablog.com