UZABASE Tech Blog

株式会社ユーザベースの技術チームブログです。 主に週次の持ち回りLTやセミナー・イベント情報について書きます。

【k8s合宿】 Kubernetesのログ分析環境を作る

こんにちは、SPEEDAのSREチームでエンジニアをしている阿南です。SPEEDAのSREチームでは、昨年末kubernetesについて理解を深めるために合宿を行いました。やり方はA〜Cの3チームに分けて、それぞれのチームでkubernetesに関することを調査、構築するという形式で、今回はAチームが実際にやってみた内容についてブログを書きたいと思います。(それぞれのチームでかなりボリュームがあるので、複数回に渡って連載的な形でお届けしたいと思います。) Aチームでは、kubernetesを本番環境に投入するにあたり、ログ収集周りをあまり調査できてないなと感じ、GCP上に環境を作ってみることにしました。

構築する環境

f:id:uzabase:20180115151549p:plain

GKEでKubernetesクラスターを構築し、その上にwordpress(Apache) + MySQLコンテナを稼働させました。ログ収集と言っても、kubernetesクラスター自体のログとその上で稼働するコンテナのログでは取得する設定も若干違ってきますので、今回はコンテナのログを収集する環境を作りました。 またポイントとして、GKEの公式DocumentではStackdriverにログを送ってBigQueryにエクスポートするという構成が紹介されているのですが、BigQueryに直接送る構成はあまり情報がなく、SPEEDAのコアな部分はオンプレ環境で運用しているため、BigQueryに直接送る構成にしました。

構築手順

ログを収集するという単純な環境ですが、意外と設定項目が多いです。手順を一つずつまとめるとかなり分量があるため、設定内容も含めてgithubに手順をまとめました。

github.com

1から構築してみたいという方はぜひご参考にしてください。 本ブログ内では、私が重要だと思った点や注意点のみ記載したいと思います。

クラスター構築

GKEは下記コマンドのみでkubernetesのクラスターを構築することができます。

$ gcloud container clusters create sample-cluster

デフォルトではGCEのインスタンスが3台起動し、そのVMを利用してkubernetesのclusterが作成されます。

wordpress + MySQL構築

続いて、wordpress + MySQL です。こちらについては、GCPの公式ページのステップ2〜5を参考にしました。wordpressのコンテンツファイルやDBのデータを永続化するために、 volumes で外部ディスクを指定し、containersvolumeMounts でマウント設定しています。

spec:
containers:
- image: mysql:5.6
name: mysql
env:
- name: MYSQL_ROOT_PASSWORD
valueFrom:
secretKeyRef:
name: mysql
key: password
ports:
- containerPort: 3306
name: mysql
volumeMounts:
- name: mysql-persistent-storage
mountPath: /var/lib/mysql
volumes:
- name: mysql-persistent-storage
gcePersistentDisk:
pdName: mysql-disk
fsType: ext4
view raw part_of_mysql.yaml hosted with ❤ by GitHub
gist.github.com

Fluentdイメージの作成

利用するイメージは、GCPのリポジトリを参考にイメージを作成すればOKです。ポイントとして今回はbigqueryに直接ログをアップロードするため、gemfileで、fluentdのバージョンをv0.14に変更し、fluent-plugin-bigqueryを追記しています。このgemfileを保存して、docker buildしてください。 fluentd.conf の設定は全てConfigMapで記載します。

source 'https://rubygems.org'
gem 'fluentd', '~>0.14.0'
gem 'fluent-plugin-bigquery', '~>1.1.1'
gem 'fluent-plugin-record-reformer', '~>0.8.3'
gem 'fluent-plugin-systemd', '~>0.0.8'
gem 'fluent-plugin-google-cloud', '~>0.6.12'
gem 'fluent-plugin-detect-exceptions', '~>0.0.8'
gem 'fluent-plugin-prometheus', '~>0.2.1'
gem 'fluent-plugin-multi-format-parser', '~>0.1.1'
gem 'oj', '~>2.18.1'
view raw Gemfile hosted with ❤ by GitHub
gist.github.com

ConfigMap設定

ConfigMapは、設定情報(環境変数やファイル)を定義できるkubernetesの機能です。これを使うと、kubernetes上でコンテナを実行した際に、ConfigMapに設定した情報を読み取ってくれます。例えば、fluentdのイメージをDocker単体で実行した場合、configをホストマウントしたりしますよね。kubernetesだとホストが頻繁に変わる可能性もあるのでホストマウントするわけにもいきません。そのような場合に、ConfigMapを利用すればconfigをimageに含めなくてもよくなり、ノードが変更した時にも追従できるということでクラスターのノードを捨てやすくなると思います。

kind: ConfigMap
apiVersion: v1
data:
containers.input.conf: |-
<source>
type tail
format json
time_key time
path /var/log/containers/*.log
pos_file /var/log/gcp-containers.log.pos
time_format %Y-%m-%dT%H:%M:%S.%N%Z
tag reform.*
read_from_head true
</source>
gist.github.com

実際のfluentdの設定についてはファイルを確認して頂ければと思いますが、注意点としてfluent-plugin-bigqueryの現在のバージョンでは inject セクションが追加されているようです。過去のブログ記事で設定にinjectがないものもあり、そのまま設定するとBigQueryのtimeだけnullになってしまうことになりますのでご注意を。

<inject>
    time_key "time"
    time_format "%s"
</inject>

DaemonSet設定

DaemonSetはクラスターの各ノードにコンテナをデーモンで動作させることができるkubernetesの機能です。コンテナのログは各ノードに出力されるようになっています。このDaemonSetを利用してfluentdを各ノードに稼働させ、各ノードのログを収集します。

spec:
containers:
- name: fluentd-gcp
image: xxxx
volumeMounts:
- name: config-volume
mountPath: /etc/fluent/config.d
volumes:
- name: config-volume
configMap:
name: fluentd-gcp-config
gist.github.com

長いので、かなり省略していますが、 volumes で先ほど設定した configMap を指定し、 containersvolumeMounts に設定しています。これで、ConfigMapで定義したファイルをfluentdが起動時に読み込み、ログ収集ができるようになります。

f:id:uzabase:20180115173310p:plain

ちなみに、下記コマンドでwordpressのpodと同じノードで稼働しているfluentdのpodを確認し、shellを起動するとfluentdのログを見ることができます。うまくfluentdのログがアップロードできない等の場合は見てみるといいかもしれません。

$ kubectl get pods -o wide
NAME                         READY     STATUS    RESTARTS   AGE       IP           NODE
fluentd-gcp-v2.0-5t96f       1/1       Running   0          5h        10.52.2.9    gke-sample-cluster-default-pool-a7431f33-rqbs
fluentd-gcp-v2.0-j45c7       1/1       Running   0          13m       10.52.0.13   gke-sample-cluster-default-pool-a7431f33-4x57
fluentd-gcp-v2.0-wmv3h       1/1       Running   0          5h        10.52.1.10   gke-sample-cluster-default-pool-a7431f33-nv5h
mysql-3368603707-ng8pr       1/1       Running   0          6h        10.52.0.7    gke-sample-cluster-default-pool-a7431f33-4x57
wordpress-3479901767-tc9p6   1/1       Running   0          6h        10.52.0.8    gke-sample-cluster-default-pool-a7431f33-4x57

$ kubectl exec -it fluentd-gcp-v2.0-j45c7 /bin/sh
# tail -f /var/log/fluentd.log

最終的に、下記のようにアップロードされました。現状だと全てのコンテナログが同じテーブルにinsertされてしまいますので、この辺りは別途テーブルやfluentdを細かく設計した方が良さそうです。

f:id:uzabase:20180118112409p:plain

まとめ

ログをアップロードするために必要な設定を見ていきました。使ってる機能が意外と多いので、少し時間がかかりましたが、本番環境で運用するにはマストの機能ばかりかと思います。また、fluentdから直接BigQueryに送ることにより、マルチクラウドでも対応できるし、OutputをBigQueryから他サービスに変更(もしくは追加)することも簡単にできますので、シーンに応じて使い分けできると思います。結構つまづいたのがfluentdで、jsonログをparseし、特定のキーに対してさらに複雑な加工をしたい場合にちょうどいいプラグインが見つからなかったのでその辺りは調査、もしくは、自分でプラグインを作るのもありかなと思います。 次回以降で、データの可視化やkubernetesのメトリクス収集等も紹介していきますのでこちらも乞うご期待。

お知らせ

SREチームでは「No Challenge, No SRE, No SPEEDA」を掲げ、ユーザベースグループのミッションである「経済情報で、世界をかえる」の実現に向けて、日々業務に取り組んでいます。 興味を持ってくださった方はこちらをご確認ください。