SMF-Solarisでのサービス管理

最近「記事からSolaris用のパッケージを作成しています」という記事を読んで、SMF機能がHabrでまったくカバーされていないことに気付きました。

この状況を修正して、SMFとは何か、それが管理者に与える利点を見てみましょう。



はじめに



サービス管理機能(SMF)は、Solaris 10で導入されたサービス管理システムです。SMFを使用すると、プロセスをより柔軟に管理し、依存関係を割り当て、必要に応じて再起動できます。 これに加えて、SMFでは、ルート以外のユーザーにサービス管理権限を委任できます。

SMFを制御するには、次の3つのコマンドで十分です。



独自のサービスを追加する例を使用して、SMFを管理する方法を理解してみましょう。

最近、Solaris用のnginxが必要になりました。パッケージをコンパイルし、共通のサービスシステムに統合する必要がありました。その例を使用して、SMFを介した管理用にサービスを設計する方法を確認してください



サービスを追加する



サービスをSMFに統合するには、サービスのマニフェスト(依存関係、起動方法、およびその他のパラメーターの説明を含むXMLファイル)を記述する必要があります。 基本サービスの場合、これで十分です。より複雑なサービスの場合は、起動スクリプト(/etc/init.d/serviceに類似)も必要です。



SMFマニフェストコンテンツ


 <?xml version = "1.0"?> 
 <!DOCTYPE service_bundle SYSTEM "/usr/share/lib/xml/dtd/service_bundle.dtd.1"> 

 <service_bundle type = 'manifest' name = 'nginx'> 

 <サービス 
         name = 'network / nginx' 
        タイプ= 'サービス' 
        バージョン= '1'> 

         <create_default_instance enabled = 'false' /> 
         <single_instance /> 

         <依存名= 'ループバック' 
            グループ化= 'require_all' 
             restart_on = 'エラー' 
            タイプ= 'サービス'> 
                 <service_fmri値= 'svc:/ network / loopback:default' /> 
         </ dependency> 

         <依存名= '物理的' 
            グループ化= 'optional_all' 
             restart_on = 'エラー' 
            タイプ= 'サービス'> 
                 <service_fmri値= 'svc:/ network / physical:default' /> 
         </ dependency> 

         <依存名= 'multiuser-server' 
            グループ化= 'require_all' 
             restart_on = 'エラー' 
            タイプ= 'サービス'> 
                 <service_fmri値= 'svc:/ milestone / multi-user-server:default' /> 
         </ dependency> 

         <exec_method 
            タイプ= 'メソッド' 
            名前= '開始' 
             exec = '/ opt / nginx / svc / nginx start' 
             timeout_seconds = '60 '/> 

         <exec_method 
            タイプ= 'メソッド' 
            名前= '停止' 
             exec = ':kill -QUIT' 
             timeout_seconds = '60 '/> 

         <exec_method 
            タイプ= 'メソッド' 
             name = 'refresh' 
             exec = '/ opt / nginx / svc / nginx refresh' 
             timeout_seconds = '60 '/> 

         <property_group name = 'nginx' type = 'application'> 
                 <propval name = 'config' type = 'astring' 
                    値= '/ opt / nginx / etc / nginx.conf' /> 
                 <propval name = 'pid' type = 'astring' 
                    値= '/ opt / nginx / var / run / nginx.pid' /> 
         </ property_group> 

         <property_group name = 'startd' type = 'framework'> 
                 <!-サブプロセスのコアダンプは再起動しない 
                     セッション-> 
                 <propval name = 'ignore_error' type = 'astring' 
                         値= 'コア、シグナル' /> 
         </ property_group> 

         <テンプレート> 
                 <common_name> 
                         <loctext xml:lang = 'C'> 
                                 Nginx httpサーバー 
                         </ loctext> 
                 </ common_name> 
                 <ドキュメント> 
                         <manpage title = 'nginx' section = '1M' /> 
                         <doc_link name = 'nginx.org' 
                                 uri = 'http://www.nginx.org/' /> 
                 </ドキュメント> 
         </ template> 
 </ service> 
 </ service_bundle>


順番に分析します。



ご覧のとおり、マニフェスト自体はサービスをかなり詳細に説明し、実際にはサービスの開始を担当する外部スクリプト/ opt / nginx / svc / nginxも参照しています。 今すぐ分析しましょう:

 #!/ sbin / sh
 #

 。  /lib/svc/share/smf_include.sh

 #SMF_FMRIは、ターゲットサービスの名前です。 これにより、複数のインスタンスが許可されます
 #同じスクリプトを使用します。

 if [-z $ SMF_FMRI]; それから
 echo "SMFフレームワーク変数は初期化されていません。"
 exit $ SMF_EXIT_ERR
 fi

 getproparg(){
 val = `svcprop -p $ 1 $ SMF_FMRI`
 [-n "$ val"] && echo $ val
 }

 NGINX_HOME = / opt / nginx
 HTTPD = "$ {NGINX_HOME} / sbin / nginx"
 CONF_FILE = `getproparg nginx / config`
 PIDFILE = `getproparg nginx / pid`

 if [-z $ CONF_FILE]; それから
 echo "nginx / configプロパティが設定されていません"
 exit $ SMF_EXIT_ERR_CONFIG
 fi

 if [-z $ PIDFILE]; それから
 echo "nginx / pidプロパティが設定されていません"
 exit $ SMF_EXIT_ERR_CONFIG
 fi

 [!  -f $ {CONF_FILE}]; それから
 echo "nginx / config:構成ファイルが見つかりませんでした"
 exit $ SMF_EXIT_ERR_CONFIG
 fi

ケース「$ 1」
開始)
         $ HTTPD -t -c $ {CONF_FILE} 2>&1
         [$?  -ne 0]; それから
                 exit $ SMF_EXIT_ERR_CONFIG
         fi
         $ HTTPD -c $ {CONF_FILE} 2>&1
         ;;
更新)
         if [-f "$ PIDFILE"]; それから
                 / usr / bin / kill -HUP `/ usr / bin / cat $ PIDFILE`
         fi
         ;;
停止)
         if [-f "$ PIDFILE"]; それから
                 / usr / bin / kill -KILL `/ usr / bin / cat $ PIDFILE`
         fi
         ;;
 *)
         echo "使用法:$ 0 {start | stop | refresh}"
         1番出口
         ;;
エサック

 exit $ SMF_EXIT_OK


これは、いくつかのヘルパー関数を備えた通常のinit.dスクリプトです。 最初に、システム変数を含むファイルが含まれており、将来的に役立ちます。 それらの1つはSMF_FRMIです。これには、サービスの完全な名前が含まれています。 SMF_FRMIは、マニフェスト(getpropargヘルパー関数)から構成パラメーターを取得するために使用されます。 このアプローチの利点は、後で同じサービスの異なるインスタンスを検討するときに明らかになります。



ファイルの完全なセットができたので、システムから見えるようにします。

 #svccfg -v import nginx.xml
 svccfg:svc:/ network / nginx:の「初期」スナップショットを取る:デフォルト。
 svccfg:svc:/ network / nginx:の「最後のインポート」スナップショットの取得:デフォルト。
 svccfg:更新されたsvc:/ network / nginx:デフォルト。
 svccfg:インポートに成功しました。


マニフェストに「デフォルトインスタンスの作成」と記述されているため、1つのデフォルトインスタンスを持つnetwork / nginxサービスがあります。 また、このインスタンスはオフ状態で作成する必要があります:

 #svcs nginx
ステートスタイムFMRI
無効19:11:07 svc:/ network / nginx:デフォルト


管理コマンドで完全なFRMI(Eng。Fault Managed Resource Identifier)サービスを送信する必要はありません。名前(たとえば、nginx)だけで十分ですが、同じ名前の異なるカテゴリのサービスが複数ある場合は、完全な名前を指定する必要があります。 サービスに複数のインスタンスがある場合は、インスタンスも指定する必要があります(nginx:デフォルト)(FRMIが不完全な場合、svcsコマンドは比較されるすべてのサービスのステータスを表示します)。



無効状態のサービスは、OSの起動時に上昇しません。 したがって、有効にする必要があります。

 #svcadm -v enable nginx
 svc:/ network / nginx:デフォルトで有効。


サービスが実行されていることを確認します。

 #svcs nginx
ステートスタイムFMRI
メンテナンス19:26:28 svc:/ network / nginx:デフォルト


失望は私たちを待っています-オンラインステータスの代わりにメンテナンスがあります。 メンテナンスステータスは、サービスの特定のエラーに対応しています。 SMFは、startメソッドがOK以外の値を返すか、サービスの停止に3回連続で失敗した場合、サービスをこの状態にします。 私たちのケースで何が原因になったのか見てみましょう。 これを行うには、サービスの展開状態を確認します。

 #svcs -x nginx
 svc:/ network / nginx:デフォルト(Nginx HTTPサーバー)
 状態:2011年3月24日木曜日19:26:28以降のメンテナンス
理由:$ SMF_EXIT_ERR_CONFIGで開始メソッドが終了しました。
   参照:http://sun.com/msg/SMF-8000-KS
   参照:nginx(1M)
   参照:/var/svc/log/network-nginx:default.log
影響:このサービスは実行されていません。


ご覧のとおり、展開されたステータスには、テンプレートマニフェストの説明も含まれています。 開始方法が失敗したことが示され、詳細を確認できるログが示されます。 ログには以下が表示されます。

 [3月24日19:26:28有効。  ]
 [3月24日19:26:28開始メソッドの実行( "/ opt / nginx / svc / nginx start")]
 nginx / config:構成ファイルが見つかりませんでした
 [3月24日19:26:28メソッド「start」がステータス96で終了しました]


起動スクリプトは、構成ファイルが見つからないと言っています。 はい、作成するのを忘れました。 ファイルを作成した後、サービスを再起動してみましょう。 メンテナンスステータスは有効/無効のサービスに影響しないことに注意してください-これは一時的な停止です。 したがって、サービスを「クリーン」するだけで、修正したことをシステムに伝えます。

 #svcadm clear nginx
 #svcs -x nginx
 svc:/ network / nginx:デフォルト(Nginx HTTPサーバー)
 状態:2011年3月24日(木)19:40:03以降のオンライン
   参照:nginx(1M)
   参照:/var/svc/log/network-nginx:default.log
影響:なし。

 #ps -fe |  grep nginx
    ルート5864 1 0 19:40:04?  0:00 / opt / nginx / sbin / nginx -c /opt/nginx/etc/nginx.conf
  誰も5865 5864 0 19:40:04?  0:00 / opt / nginx / sbin / nginx -c /opt/nginx/etc/nginx.conf


サービスが開始され、その機能が正常に実行されます。 この場合、次のログが記録されます。

 [3月24日19:40:03クリアが要求されたためメンテナンスを終了します。  ]
 [3月24日19:40:03有効。  ]
 [3月24日19:40:03開始メソッドの実行(「/ opt / nginx / svc / nginxstart」)]
構成ファイルの/opt/nginx/etc/nginx.conf構文は問題ありません
設定ファイル/opt/nginx/etc/nginx.confテストが成功しました
 [3月24日19:40:03メソッド「start」がステータス0で終了しました]


現在、サービスが予期せず停止した場合、SMFは(startd / ignore_errorパラメーターに従って)サービスを自動的に再起動します。 kill -9でこの状況を作成し、ログを確認します。

 [3月24日19:42:25サービス中のすべてのプロセスが終了したため停止しています。  ]
 [3月24日19:42:25停止メソッドの実行(:kill)]
 [3月24日19:42:25開始メソッドの実行( "/ opt / nginx / svc / nginx start")]
構成ファイルの/opt/nginx/etc/nginx.conf構文は問題ありません
設定ファイル/opt/nginx/etc/nginx.confテストが成功しました
 [3月24日19:42:25メソッド「start」がステータス0で終了しました]




追加機能


そのため、OSレベルでパフォーマンスが制御されるサービスがあります。 しかし、2つまたは3つの同一のサービス(たとえば、複数のpostgresqlサーバーまたは異なるタスクを備えたnginx)が必要な場合は、何のマニフェストを作成しますか? その場合の利点は何ですか?

ここでは、1つのサービスの複数のインスタンスを作成する機会を提供します。 これを行うには、マニフェストのcreate_default_instanceタグとsingle_serviceタグを削除し、明示的に独自のインスタンスを作成して、そこに一意のパラメーターを転送する必要があります。

 <インスタンス名= 'default' enabled = 'false'>
   <property_group name = 'nginx' type = 'application'> 
      <propval name = 'config' type = 'astring' 
              値= '/ opt / nginx / etc / nginx.conf' /> 
      <propval name = 'pid' type = 'astring' 
              値= '/ opt / nginx / var / run / nginx.pid' /> 
   </ property_group> 

   <property_group name = 'startd' type = 'framework'> 
      <!-サブプロセスのコアダンプは再起動しない 
          セッション-> 
      <propval name = 'ignore_error' type = 'astring' 
              値= 'コア、シグナル' /> 
   </ property_group> 
 </ instance>


インポートによってマニフェストをリロードする必要があります。 SMFは、何が変更されたかを判別します。

 #svccfg -v import nginx.xml 
 svccfg:svc:/ network / nginx:の「前の」スナップショットを取得します:デフォルト。
 svccfg:インスタンス「デフォルト」に従ってsvc:/ network / nginxのプロパティをアップグレードします。
 svccfg:svc:/ network / nginx:プロパティグループ "nginx"を削除しています。
 svccfg:svc:/ network / nginx:プロパティグループ「general」を削除しています。
 svccfg:svc:/ network / nginx:プロパティグループ「startd」を削除しています。
 svccfg:svc:/ network / nginx:の「最後のインポート」スナップショットの取得:デフォルト。
 svccfg:更新されたsvc:/ network / nginx:デフォルト。
 svccfg:インポートに成功しました。


その結果、複数のインスタンスを構成できるようになり、サービスの説明が同じになりました。 マニフェストで直接追加のインスタンスを指定できます。

 <インスタンス名= 'monitoring' enabled = 'false'>
   <property_group name = 'nginx' type = 'application'> 
      <propval name = 'config' type = 'astring' 
              値= '/ opt / nginx / etc / nginx-munin.conf' /> 
      <propval name = 'pid' type = 'astring' 
              値= '/ opt / nginx / var / run / nginx-munin.pid' /> 
   </ property_group> 

   <property_group name = 'startd' type = 'framework'> 
      <!-サブプロセスのコアダンプは再起動しない 
          セッション-> 
      <propval name = 'ignore_error' type = 'astring' 
              値= 'コア、シグナル' /> 
   </ property_group> 
 </ instance>


そしてインポート:

 #svccfg -v import nginx.xml 
 svccfg:svc:/ network / nginx:の「前の」スナップショットを取得します:デフォルト。
 svccfg:新しいサービスsvc:/ network / nginx:の「前の」スナップショットを取得しています。
 svccfg:インスタンス「デフォルト」に従ってsvc:/ network / nginxのプロパティをアップグレードします。
 svccfg:svc:/ network / nginx:監視の「初期」スナップショットを取得しています。
 svccfg:svc:/ network / nginx:の「最後のインポート」スナップショットを取得しています。
 svccfg:svc:/ network / nginx:の「最後のインポート」スナップショットの取得:デフォルト。
 svccfg:更新されたsvc:/ network / nginx:モニタリング。
 svccfg:更新されたsvc:/ network / nginx:デフォルト。
 svccfg:インポートに成功しました。


これで、2つのサービスインスタンスができました(デフォルトのインスタンスは有効なままです)。

 #svcs nginx
ステートスタイムFMRI
無効20:16:31 svc:/ network / nginx:監視
オンライン20:16:31 svc:/ network / nginx:デフォルト


ここで、サービスを開始するには、インスタンスを明示的に指定する必要があります。そうでない場合、システムは警告を表示します。

 #svcadm enable nginx
 svcadm:パターン 'nginx'は複数のインスタンスに一致します:
	 svc:/ network / nginx:監視
	 svc:/ network / nginx:デフォルト

 #svcadm -v enable nginx:監視
 svc:/ network / nginx:監視が有効になっています。


サービス設定を変更するsvccfgコマンドを使用して、マニフェストを編集せずにインスタンスを追加することもできます(ただし、マニフェストは複数のインスタンスに対して既に構成され、デフォルトを含む必要があります)。 大まかに言って、マニフェストをインポートした後、ソースファイルはSMFデータベースにインポートされるため、もはや役割を果たしません。 現在のサービス設定でマニフェストを取得するには、svccfg exportコマンドを使用できます。 オンザフライでインスタンスを追加すると、プロセスを自動化できます。

 #svccfg -s nginx add phpfpm
 #svccfg -s nginx:phpfpm addpg nginxアプリケーション
 #svccfg -s nginx:phpfpm setprop nginx / config = astring:/opt/nginx/etc/fpm.conf
 #svccfg -s nginx:phpfpm setprop nginx / pid = astring:/opt/nginx/run/fpm.pid
 #svcadm disable nginx:phpfpm#これによりシステムプロパティが自動的に追加されます
 #svcs nginx
ステートスタイムFMRI
無効20:37:30 svc:/ network / nginx:phpfpm
オンライン20:16:31 svc:/ network / nginx:デフォルト
オンライン20:21:09 svc:/ network / nginx:監視


rootユーザーからではなくサービスを開始する必要がある場合は、ここですべてが可能です。 追加するだけ
  <method_context> <method_credential user = 'munin' group = 'munin' /> </ method_context> 
インスタンスまたは別のメソッドの説明(別のユーザーからメソッドのみを実行する必要がある場合):

 #ps -fe |  grep nginx
   munin 6254 1 0 21:10:52?  0:00 / opt / nginx / sbin / nginx -c /opt/nginx/etc/nginx-munin.conf
   munin 6255 6254 0 21:10:52?  0:00 / opt / nginx / sbin / nginx -c /opt/nginx/etc/nginx-munin.conf 
  ルート5884 1 0 19:42:25?  0:00 / opt / nginx / sbin / nginx -c /opt/nginx/etc/nginx.conf
  誰も6015 5884 0 21:05:04?  0:00 / opt / nginx / sbin / nginx -c /opt/nginx/etc/nginx.conf


同様の方法で、個々のプロジェクトでサービスを実行できます(プロジェクト-リソース制限)。 また、rootだけでなくサービスも管理できるようにしたい場合、SMFはSolaris RBACと統合されます!

ユーザーには、メソッド、依存関係、「アプリケーション」/「フレームワーク」グループのパラメーター、および特定のグループの権限を変更するための両方のグローバルロールを割り当てることができます。 各グループに対して、特別な属性(プロパティ値)modify_authorization、value_authorization、action_authorizationを割り当てて、操作に必要な「承認」を書き込むことができます。



最初に、ある種の「承認」をユーザーに追加します。簡単に説明しますが、承認を意味のある形で呼び出す必要があるという合意があります(たとえば、solaris.smf.manage.nginx / monitoring)。 (/ etc / security / auth_attrには多くの定義済みの承認もありますが、RBACは別の大きな記事の主題です):

 #echo "solaris.munin ::: Munin認証::" >> / etc / security / auth_attr
 #usermod -A solaris.munin munin


これまでのところ、サービスを設定しておらず、ユーザーは何もできません。

 munin @ sol2 $ / usr / sbin / svcadm restart nginx:モニタリング
 svcadm:svc:/ network / nginx:監視:許可が拒否されました。
 munin @ sol2 $ / usr / sbin / svcadm disable nginx:モニタリング
 svcadm:svc:/ network / nginx:監視:許可が拒否されました。


「承認」solaris.muninのサービスを再起動する機能を追加します。

 #svccfg -s nginx:setprop general / action_authorization = astring:solaris.muninの監視
 #svcadm refresh nginx:監視


(マニフェストの変更後、SMFが現在のサービスの構成を再読み取りできるように、更新サービスを実行する必要があります)



私たちはチェックします:

 munin @ sol2 $ / usr / sbin / svcadm -v restart nginx:モニタリング
 svc:/ network / nginx:監視用に設定されたアクション再起動。
 munin @ sol2 $ / usr / sbin / svcadm -v nginxを無効にする:監視
 svcadm:svc:/ network / nginx:監視:「一般」プロパティグループを変更できませんでした(許可は拒否されました)。


ユーザーがサービスを再起動できることは明らかですが、SMFデータベースのプロパティを変更することはできません。 このアプローチにより、ユーザーは構成ファイルを変更するときに「それらの」サービスを再ロードできます。 ユーザーにサービスを完全に停止する機会を与える必要がある場合、「一般」プロパティグループを変更する機会をユーザーに与えます。

 #svccfg -s nginx:setprop generalの監視/ value_authorization = astring:solaris.munin
 #svcadm refresh nginx:監視


私たちはチェックします:

 munin @ sol2 $ / usr / sbin / svcadm -v nginxを無効にする:監視
 svc:/ network / nginx:監視が無効です。
 munin @ sol2 $ / usr / sbin / svcadm -v enable nginx:モニタリング
 svc:/ network / nginx:監視が有効になっています。




上記の手法を使用すると、ユーザーの権利を柔軟に制限しながら、ユーザーにとって便利なシステムを作成できます。



この記事が誰かがSMFとは何かをよりよく理解するのに役立つこと、あるいはSMF、RBAC、およびSolarisのより深い理解を促すことさえ期待しています。



All Articles