投稿者:ソリューション担当



はじめに

皆様Bluemixのログの長期保管はどうされていますか?残念ながらBluemixの内部ではElasticSearchを利用しているのにログを自由に検索出来るサービスはありません。そこで今回はBluemixで利用することが出来る Compose ElasticSearchに対してログを転送することを考えて見たいと思います。仕組み的には非常に単純でBluemixのLoggregatorの機能を利用して行います。

構成を考えた場合

[CF Application ] -> [Custom Service] -> [logstash] -> [Compose ElasticSearch] <- [kibana]

のようになります。その際に、残念ながら[logstash]と[kibana]を個別に用意する必要があります。この辺もサービスでで提供されていればよいのに。嘆いても仕方ないので今回は [logstash] を Dockerコンテナを利用して行いたいと思います。

手順としては

  1. サービス(Compose ElasticSearch)のオーダー
  2. logstash Dockerコンテナカスタマイズ
  3. logstashコンテナの起動
  4. Custom Serviceの作成

作業においてはローカルの端末においてDockerをBuild出来る環境が必要になります。また bx コマンドや Contaienrを利用するためのプラグインは入れておく必要があります。

$ bx plugin list                                                                                                インストール済みプラグインをリストしています...

プラグイン名         バージョン
IBM-Containers       1.0.1028
container-registry   0.1.171
container-service    0.1.283

サービス(Compose ElasticSearch)のオーダー

手順としては通常通りオーダーをします。ここではプランは一番安いモノを選択しておきます。オーダが完了したら「資格情報」の確認を行います。

サービスの確認をします

$ bx service list
'cf services' を起動しています...

hide@gmail.com として組織 orgname / スペース tokida 内のサービスを取得しています...
OK

名前                           サービス                        プラン     バインド済みアプリ     最後の操作
composeelastic                     compose-for-elasticsearch       Standard                          create は成功しました

資格情報の名前を確認します。

$ bx service keys composeelastic
'cf service-keys composeelastic' を起動しています...

hide@gmail.com としてサービス・インスタンス composeelastic のキーを取得しています...

名前
Credentials-1

資格情報の中身を確認します。

$ bx service key-show composeelastic Credentials-1 
cf service-key composeelastic Credentials-1' を起動しています...

hide@gmail.com としてサービス・インスタンス composeelastic のキー Credentials-1 を取得しています...

{
 "ca_certificate_base64": "LS0t...(略)...LQo=",
 "db_type": "elastic_search",
 "deployment_id": "58b7...(略)...015001d8f",
 "name": "bmix_dal_yp...(略)...80b_07f88692b488",
 "uri": "https://admin:DTJ...(略)...GCFSWWD@sl-us-dal-9-portal7.dblayer.com:xxxxx/",
 "uri_direct_1": "https://admin:DT...(略)...@sl-us-dal-9-portal5.dblayer.com:2xxx/",
 "uri_health": "curl -u admin:DTJ...(略)...D 'https://sl-us-dal-9-portal.7.dblayer.com:20xxx/_cluster/health?pretty'",
 "uri_health_1": "curl -u admin:DT...(略)...WD 'https://sl-us-dal-9-portal.5.dblayer.com:2xxx/_cluster/health?pretty'"
}

ここでの値は、logstashの設定で利用されます。

logstash Dockerコンテナカスタマイズ

次にコンテナサービス上で動かすために dockerイメージを作成します。logstash自身はDocker公式レポジトリにも含まれているのでそちらを素直に利用します。引数などで設定ファイルなどを変更できますがBluemix上のコンテナで動かすことを考えると面倒なのでファイルを含めた状態でBuildしてしまいます。

FROM logstash
COPY logstash.conf /config-dir/
CMD ["-f", "/config-dir/logstash.conf"]

次にlogstashの設定を変更します。以下のファイルの中に有る elasticsearch部分を先ほどの資格情報の値で修正してください。

logstash.conf
input {
        tcp {
                port => 1540
                type => syslog
        }
}

filter {
  if [type] == "syslog" {
    grok {
      match => { "message" => '%{WORD:id} %{SYSLOG5424PRI}%{NONNEGINT:syslog_ver} +(?:%{TIMESTAMP_ISO8601:syslog_ts}|-) +(?:%{HOSTNAME:syslog_host}|-) +(?:%{NOTSPACE:cfapp_id}|-) +(?:%{NOTSPACE:proc}|-) +(?:%{WORD:msgid}|-) +(?:%{SYSLOG5424SD:sd}|-|) +%{GREEDYDATA:syslog_msg}' }
    }
    grok {
      match => { "syslog_host" => '%{WORD:org}.%{WORD:space}.%{GREEDYDATA:cfapp_name}'}
    }
    syslog_pri { }
    date {
      match => [ "syslog_timestamp", "MMM  d HH:mm:ss", "MMM dd HH:mm:ss" ]
    }
    if !("_grokparsefailure" in [tags]) {
      mutate {
        replace => [ "@source_host", "%{syslog_host}" ]
        replace => [ "@message", "%{syslog_msg}" ]
      }
    }
    mutate {
      remove_field => [ "syslog_hostname", "syslog_message", "syslog_timestamp", "host" ]
    }
  }
}

output {
  elasticsearch {
    ssl => true
    hosts => ["slXXXXXXXXXXXXXX.dblayer.com:XXXXXX"]   <-- 修正
    index => "cfapp" <-- 任意
    user => "admin"
    password => "PASSWORD"   <-- 修正
    healthcheck_path => "_cluster/health?pretty"
  }
  stdout { codec => rubydebug }
}

上記の2ファイルを任意のディレクトリに配置してBuildしてください。

docker build -t my-logstash .

次にどのContainerサービスを利用するかにもよりますが今回はシングルコンテナを利用して動かしたいと思います。実際のBluemix上の設定等は完了している状態を想定して以下のコマンドを実施します。実際にすることは bx icコマンドでimageをBluemix側のレポジトリにpushすることです。

docker tag my-logstash registry.ng.bluemix.net/htokida/logstash:latest

この場合には、Bluemix上のContainerのNamespaceが htokida であり、米国南部のContainerレポジトリをしていしたタグを付けます。

bx login
bx ic init
docker push registry.ng.bluemix.net/htokida/logstash:latest

bx ic initをするとdocker環境変数の設定が出てきますが 不要 です。docker cliはローカルのdocker観葉を向いた状態で操作する必要があります。環境変数をセットしてしまうと docker cli がBluemix側を向いてしまいます。

logstashコンテナの起動

Bluemix上では、現在(2017/07/28) KubenetesベースのClusterと今回利用する単体のシングル構成が利用できます。シングルの場合には単にコンテナを起動しコンテナに対してIPアドレスを割り当てて利用できます。

IPアドレスを確認します。ない場合には ip-requestオプションで発行します。

$ bx ic ips
「<organization>」の IP アドレスをリスト中です...
割り振られたパブリック IP アドレスの数: 1

現在のスペースの IP アドレスをリスト中です...
IP アドレス     コンテナー ID
169.44.aaa.bbb

次にコンテナを起動します

$ bx ic run -p 1540 -m 512 --name logstashTest registry.ng.bluemix.net/htokida/logstash 
07474dcf-280c-4e07-861b-eefea73ff06c

syslogを外部から受信するためにポート 1540をオープンします。次に、先ほどのIPアドレスを割り当て(Bind)します。

$bx ic ip-bind 169.46.xxx.xxx 07474dcf-280c-4e07-861b-eefea73ff06c
IP アドレスは正常にバインドされました。

$ bx ic ips
「<org>」の IP アドレスをリスト中です...
割り振られたパブリック IP アドレスの数: 2

現在のスペースの IP アドレスをリスト中です...
IP アドレス     コンテナー ID
169.46.xxx.xxx   07474dcf-280c-4e07-861b-eefea73ff06c

Custom Serviceの作成

さて最後にBluemix側の設定を行います。Bluemix側での設定については色々記事があるので詳細は省きますが以下のコマンドを利用してsyslogデータを先ほどのコンテナに向かって送信する設定を行います。どのCFアプリケーションのログを送信するかはBINDするアプリケーションになります。

cf create-user-provided-service syslogContainer -l syslog://169.46.xxx.xxx:1540
cf bind-service sample syslogContainer

これで sampleというアプリに作成した syslogContainer をBINDしておりsampleで発生するログはすべて転送されます。

bx service show syslogContainer
'cf service syslogContainer' を起動しています...

サービス・インスタンス: syslogContainer
サービス: ユーザー提供
バインド済みアプリ: sample

確認

幾つか確認するポイントが有ります。同時に画面に出しログが正しく動いていることを確認してください。

CFアプリケーショログ

$ cf logs sample

logstashのログ

$ bx logs -f 07474dcf-280c-4e07-861b-eefea73ff06c

コンテナIDは bx ic psで確認すること

ElasticSearchのログ

curl 'https://admin:PASSWORD@slxxxxxx.dblayer.com:xxxxx/cfapp/_search?q=*' | jq .

上記はelasticsearchのURLになります。
最終的にこのelasticsearch上にデータが格納されていれば完了です。後はKibana等からアクセスを行うことで視覚的な管理が出来ることと思います。

      {
        "_index": "cfapp",
        "_type": "syslog",
        "_id": "AV2HKrVQFXEWn1GXwoIl",
        "_score": 1,
        "_source": {
          "syslog_host": "orgname.tokida.sample",
          "proc": "[CELL]",
          "syslog_severity_code": 5,
          "org": "solct3",
          "syslog_facility": "user-level",
          "cfapp_id": "85f02321-ca4d-43dc-a69f-afcf019c9f30",
          "syslog_facility_code": 1,
          "message": "142 <14>1 2017-07-28T03:08:28.391425+00:00 orgname.tokida.sample 85f02321-ca4d-43dc-a69f-afcf019c9f30 [CELL] - - Exit status 0",
          "type": "syslog",
          "space": "tokida",
          "syslog_severity": "notice",
          "cfapp_name": "sample",
          "@message": "Exit status 0",
          "@timestamp": "2017-07-28T03:08:28.586Z",
          "@source_host": "orgname.tokida.sample",
          "port": 36220,
          "syslog5424_pri": "14",
          "syslog_ts": "2017-07-28T03:08:28.391425+00:00",
          "@version": "1",
          "syslog_msg": "Exit status 0",
          "id": "142",
          "syslog_ver": "1"
        }

今回の定義ファイル(logstash.conf)では上記の用にスロットを定義しました。他にも色々出来るとは思いますので適宜参考にしてみてください。

まとめ

本来はこのあたりのログはBluemix側の方で提供されていると嬉しいのですが現状ではこのような方法で実装することが出来ます。ElasticSearch部分はCompose社のマネージドサービスのためある程度は考えることが少なくなると思いますが logstash は自身で運用管理が必要です。停止した時などを考えて自動起動するようにするとかクラスタ化するとかを検討する必要があります。また監視面でもBluemix上のコンテナサービスがあまり手厚くないので何らか必要となります。現時点ではlogstashコンテナが停止していても誰も気が付かないため問題になってしまうでしょう。またトラフィックが増大した時に ElasticSearch側でデータが受け取れるかなども気になるところがあります。