2.2. すべてのノードでのログ収集エージェントのインストール
OpenStack 環境内の全システムからログを収集し、それらを集中ロギングサーバーに送信するには、すべての OpenStack システムで以下のコマンドを実行します。
Operational Tools リポジトリーを有効にします。
# subscription-manager repos --enable=rhel-7-server-openstack-8-optools-rpmsfluentdおよびrubygem-fluent-plugin-addをインストールします。# yum install fluentd rubygem-fluent-plugin-addすべての OpenStack ログファイルを読み取るパーミッションを持つように
Fluentdユーザーを設定します。これを行うには、以下のコマンドを実行します。# for user in {keystone,nova,neutron,cinder,glance}; do usermod -a -G $user fluentd; doneグループが欠落していることについて一部のノードでエラーが発生する可能性があることに注意してください。これは、すべてのノードがすべてのサービスを実行しているわけではないため無視できます。
Fluentdを設定します。/etc/fluentd/fluent.confが以下のようになっていることを確認してください。LOGGING_SERVER を、上記で設定した集中ロギングサーバーのホスト名または IP アドレスに置き換えます。# In v1 configuration, type and id are @ prefix parameters. # @type and @id are recommended. type and id are still available for backward compatibility # Nova compute <source> @type tail path /var/log/nova/nova-compute.log tag nova.compute format /(?<time>[^ ]* [^ ]*) (?<pid>[^ ]*) (?<loglevel>[^ ]*) (?<class>[^ ]*) \[(?<context>.*)\] (?<message>.*)/ time_format %F %T.%L </source> <match nova.compute> type add <pair> service nova.compute hostname "#{Socket.gethostname}" </pair> </match> # Nova API <source> @type tail path /var/log/nova/nova-api.log tag nova.api format multiline format_firstline /(?<time>[^ ]* [^ ]*) (?<pid>[^ ]*) (?<loglevel>[^ ]*) (?<class>[^ ]*) \[(?<context>.*)\] (?<message>.*)/ format /(?<time>[^ ]* [^ ]*) (?<pid>[^ ]*) (?<loglevel>[^ ]*) (?<class>[^ ]*) \[(?<context>.*)\] (?<message>.*)/ time_format %F %T.%L </source> <match nova.api> type add <pair> service nova.api hostname "#{Socket.gethostname}" </pair> </match> # Nova Cert <source> @type tail path /var/log/nova/nova-cert.log tag nova.cert format multiline format_firstline /(?<time>[^ ]* [^ ]*) (?<pid>[^ ]*) (?<loglevel>[^ ]*) (?<class>[^ ]*) \[(?<context>.*)\] (?<message>.*)/ format /(?<time>[^ ]* [^ ]*) (?<pid>[^ ]*) (?<loglevel>[^ ]*) (?<class>[^ ]*) \[(?<context>.*)\] (?<message>.*)/ time_format %F %T.%L </source> <match nova.cert> type add <pair> service nova.cert hostname "#{Socket.gethostname}" </pair> </match> # Nova Conductor <source> @type tail path /var/log/nova/nova-conductor.log tag nova.conductor format multiline format_firstline /(?<time>[^ ]* [^ ]*) (?<pid>[^ ]*) (?<loglevel>[^ ]*) (?<class>[^ ]*) \[(?<context>.*)\] (?<message>.*)/ format /(?<time>[^ ]* [^ ]*) (?<pid>[^ ]*) (?<loglevel>[^ ]*) (?<class>[^ ]*) \[(?<context>.*)\] (?<message>.*)/ time_format %F %T.%L </source> <match nova.conductor> type add <pair> service nova.conductor hostname "#{Socket.gethostname}" </pair> </match> # Nova Consoleauth <source> @type tail path /var/log/nova/nova-consoleauth.log tag nova.consoleauth format multiline format_firstline /(?<time>[^ ]* [^ ]*) (?<pid>[^ ]*) (?<loglevel>[^ ]*) (?<class>[^ ]*) \[(?<context>.*)\] (?<message>.*)/ format /(?<time>[^ ]* [^ ]*) (?<pid>[^ ]*) (?<loglevel>[^ ]*) (?<class>[^ ]*) \[(?<context>.*)\] (?<message>.*)/ time_format %F %T.%L </source> <match nova.consoleauth> type add <pair> service nova.consoleauth hostname "#{Socket.gethostname}" </pair> </match> # Nova Scheduler <source> @type tail path /var/log/nova/nova-scheduler.log tag nova.scheduler format multiline format_firstline /(?<time>[^ ]* [^ ]*) (?<pid>[^ ]*) (?<loglevel>[^ ]*) (?<class>[^ ]*) \[(?<context>.*)\] (?<message>.*)/ format /(?<time>[^ ]* [^ ]*) (?<pid>[^ ]*) (?<loglevel>[^ ]*) (?<class>[^ ]*) \[(?<context>.*)\] (?<message>.*)/ time_format %F %T.%L </source> <match nova.scheduler> type add <pair> service nova.scheduler hostname "#{Socket.gethostname}" </pair> </match> # Neutron Openvswitch Agent <source> @type tail path /var/log/neutron/openvswitch-agent.log tag neutron.openvswitch format /(?<time>[^ ]* [^ ]*) (?<pid>[^ ]*) (?<loglevel>[^ ]*) (?<class>[^ ]*) \[(?<context>.*)\] (?<message>.*)/ time_format %F %T.%L </source> <match neutron.openvswitch> type add <pair> service neutron.openvswitch hostname "#{Socket.gethostname}" </pair> </match> # Neutron Server <source> @type tail path /var/log/neutron/server.log tag neutron.server format multiline format_firstline /(?<time>[^ ]* [^ ]*) (?<pid>[^ ]*) (?<loglevel>[^ ]*) (?<class>[^ ]*) \[(?<context>.*)\] (?<message>.*)/ format /(?<time>[^ ]* [^ ]*) (?<pid>[^ ]*) (?<loglevel>[^ ]*) (?<class>[^ ]*) \[(?<context>.*)\] (?<message>.*)/ time_format %F %T.%L </source> <match neutron.server> type add <pair> service neutron.server hostname "#{Socket.gethostname}" </pair> </match> # Neutron DHCP Agent <source> @type tail path /var/log/neutron/dhcp-agent.log tag neutron.dhcp format multiline format_firstline /(?<time>[^ ]* [^ ]*) (?<pid>[^ ]*) (?<loglevel>[^ ]*) (?<class>[^ ]*) \[(?<context>.*)\] (?<message>.*)/ format /(?<time>[^ ]* [^ ]*) (?<pid>[^ ]*) (?<loglevel>[^ ]*) (?<class>[^ ]*) \[(?<context>.*)\] (?<message>.*)/ time_format %F %T.%L </source> <match neutron.dhcp> type add <pair> service neutron.dhcp hostname "#{Socket.gethostname}" </pair> </match> # Neutron L3 Agent <source> @type tail path /var/log/neutron/l3-agent.log tag neutron.l3 format multiline format_firstline /(?<time>[^ ]* [^ ]*) (?<pid>[^ ]*) (?<loglevel>[^ ]*) (?<class>[^ ]*) \[(?<context>.*)\] (?<message>.*)/ format /(?<time>[^ ]* [^ ]*) (?<pid>[^ ]*) (?<loglevel>[^ ]*) (?<class>[^ ]*) \[(?<context>.*)\] (?<message>.*)/ time_format %F %T.%L </source> <match neutron.l3> type add <pair> service neutron.l3 hostname "#{Socket.gethostname}" </pair> </match> # Neutron Metadata Agent <source> @type tail path /var/log/neutron/metadata-agent.log tag neutron.metadata format multiline format_firstline /(?<time>[^ ]* [^ ]*) (?<pid>[^ ]*) (?<loglevel>[^ ]*) (?<class>[^ ]*) \[(?<context>.*)\] (?<message>.*)/ format /(?<time>[^ ]* [^ ]*) (?<pid>[^ ]*) (?<loglevel>[^ ]*) (?<class>[^ ]*) \[(?<context>.*)\] (?<message>.*)/ time_format %F %T.%L </source> <match neutron.metadata> type add <pair> service neutron.metadata hostname "#{Socket.gethostname}" </pair> </match> # Keystone <source> @type tail path /var/log/keystone/keystone.log tag keystone format multiline format_firstline /(?<time>[^ ]* [^ ]*) (?<pid>[^ ]*) (?<loglevel>[^ ]*) (?<class>[^ ]*) \[(?<context>.*)\] (?<message>.*)/ format /(?<time>[^ ]* [^ ]*) (?<pid>[^ ]*) (?<loglevel>[^ ]*) (?<class>[^ ]*) \[(?<context>.*)\] (?<message>.*)/ time_format %F %T.%L </source> <match keystone> type add <pair> service keystone hostname "#{Socket.gethostname}" </pair> </match> # Glance API <source> @type tail path /var/log/glance/api.log tag glance.api format multiline format_firstline /(?<time>[^ ]* [^ ]*) (?<pid>[^ ]*) (?<loglevel>[^ ]*) (?<class>[^ ]*) \[(?<context>.*)\] (?<message>.*)/ format /(?<time>[^ ]* [^ ]*) (?<pid>[^ ]*) (?<loglevel>[^ ]*) (?<class>[^ ]*) \[(?<context>.*)\] (?<message>.*)/ time_format %F %T.%L </source> <match glance.api> type add <pair> service glance.api hostname "#{Socket.gethostname}" </pair> </match> # Glance Registry <source> @type tail path /var/log/glance/registry.log tag glance.registry format multiline format_firstline /(?<time>[^ ]* [^ ]*) (?<pid>[^ ]*) (?<loglevel>[^ ]*) (?<class>[^ ]*) \[(?<context>.*)\] (?<message>.*)/ format /(?<time>[^ ]* [^ ]*) (?<pid>[^ ]*) (?<loglevel>[^ ]*) (?<class>[^ ]*) \[(?<context>.*)\] (?<message>.*)/ time_format %F %T.%L </source> <match glance.registry> type add <pair> service glance.registry hostname "#{Socket.gethostname}" </pair> </match> # Cinder API <source> @type tail path /var/log/cinder/api.log tag cinder.api format multiline format_firstline /(?<time>[^ ]* [^ ]*) (?<pid>[^ ]*) (?<loglevel>[^ ]*) (?<class>[^ ]*) \[(?<context>.*)\] (?<message>.*)/ format /(?<time>[^ ]* [^ ]*) (?<pid>[^ ]*) (?<loglevel>[^ ]*) (?<class>[^ ]*) \[(?<context>.*)\] (?<message>.*)/ time_format %F %T.%L </source> <match cinder.api> type add <pair> service cinder.api hostname "#{Socket.gethostname}" </pair> </match> # Cinder Scheduler <source> @type tail path /var/log/cinder/scheduler.log tag cinder.scheduler format multiline format_firstline /(?<time>[^ ]* [^ ]*) (?<pid>[^ ]*) (?<loglevel>[^ ]*) (?<class>[^ ]*) \[(?<context>.*)\] (?<message>.*)/ format /(?<time>[^ ]* [^ ]*) (?<pid>[^ ]*) (?<loglevel>[^ ]*) (?<class>[^ ]*) \[(?<context>.*)\] (?<message>.*)/ time_format %F %T.%L </source> <match cinder.scheduler> type add <pair> service cinder.scheduler hostname "#{Socket.gethostname}" </pair> </match> # Cinder Volume <source> @type tail path /var/log/cinder/volume.log tag cinder.volume format multiline format_firstline /(?<time>[^ ]* [^ ]*) (?<pid>[^ ]*) (?<loglevel>[^ ]*) (?<class>[^ ]*) \[(?<context>.*)\] (?<message>.*)/ format /(?<time>[^ ]* [^ ]*) (?<pid>[^ ]*) (?<loglevel>[^ ]*) (?<class>[^ ]*) \[(?<context>.*)\] (?<message>.*)/ time_format %F %T.%L </source> <match cinder.volume> type add <pair> service cinder.volume hostname "#{Socket.gethostname}" </pair> </match> <match greped.**> @type forward heartbeat_type tcp <server> name LOGGING_SERVER host LOGGING_SERVER port 4000 </server> </match>Fluentdが設定されたので、Fluentdサービスを起動し、これを起動時に有効にします。# systemctl start fluentd # systemctl enable fluentd
これで、http://LOGGING_SERVER/index.html#/dashboard/file/logstash.json で実行されている Kibana にアクセスでき、ログが表示されることを確認できるはずです。Kibana 設定で HTTP Basic 認証を有効にしている場合、このページにアクセスするには有効なユーザー名とパスワードを入力する必要があります。
デフォルトでは、ロギングサーバーのフロントページ http://LOGGING_SERVER/ は、技術的な要件と追加の設定情報を提供する Kibana のウェルカム画面です。ログをここで利用可能にする必要がある場合は、Kibana アプリケーションディレクトリーの default.json ファイルを logstash.json に置き換えますが、今後このファイルを再度必要とする場合に、最初に default.json のバックアップコピーを作成します。
# mv /usr/share/kibana/app/dashboards/default.json /usr/share/kibana/app/dashboards/default.json.orig
# cp /usr/share/kibana/app/dashboards/logstash.json /usr/share/kibana/app/dashboards/default.json