こんにちは、SPEEDAのSREチームでエンジニアをしている阿南です。SPEEDAのSREチームでは、昨年末kubernetesについて理解を深めるために合宿を行いました。やり方はA〜Cの3チームに分けて、それぞれのチームでkubernetesに関することを調査、構築するという形式で、今回はAチームが実際にやってみた内容についてブログを書きたいと思います。(それぞれのチームでかなりボリュームがあるので、複数回に渡って連載的な形でお届けしたいと思います。) Aチームでは、kubernetesを本番環境に投入するにあたり、ログ収集周りをあまり調査できてないなと感じ、GCP上に環境を作ってみることにしました。
構築する環境
GKEでKubernetesクラスターを構築し、その上にwordpress(Apache) + MySQLコンテナを稼働させました。ログ収集と言っても、kubernetesクラスター自体のログとその上で稼働するコンテナのログでは取得する設定も若干違ってきますので、今回はコンテナのログを収集する環境を作りました。 またポイントとして、GKEの公式DocumentではStackdriverにログを送ってBigQueryにエクスポートするという構成が紹介されているのですが、BigQueryに直接送る構成はあまり情報がなく、SPEEDAのコアな部分はオンプレ環境で運用しているため、BigQueryに直接送る構成にしました。
構築手順
ログを収集するという単純な環境ですが、意外と設定項目が多いです。手順を一つずつまとめるとかなり分量があるため、設定内容も含めてgithubに手順をまとめました。
1から構築してみたいという方はぜひご参考にしてください。 本ブログ内では、私が重要だと思った点や注意点のみ記載したいと思います。
クラスター構築
GKEは下記コマンドのみでkubernetesのクラスターを構築することができます。
$ gcloud container clusters create sample-cluster
デフォルトではGCEのインスタンスが3台起動し、そのVMを利用してkubernetesのclusterが作成されます。
wordpress + MySQL構築
続いて、wordpress + MySQL です。こちらについては、GCPの公式ページのステップ2〜5を参考にしました。wordpressのコンテンツファイルやDBのデータを永続化するために、 volumes で外部ディスクを指定し、containers の volumeMounts でマウント設定しています。
| 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 |
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' |
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> |
実際の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 |
長いので、かなり省略していますが、 volumes で先ほど設定した configMap を指定し、 containers の volumeMounts に設定しています。これで、ConfigMapで定義したファイルをfluentdが起動時に読み込み、ログ収集ができるようになります。
ちなみに、下記コマンドで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を細かく設計した方が良さそうです。
まとめ
ログをアップロードするために必要な設定を見ていきました。使ってる機能が意外と多いので、少し時間がかかりましたが、本番環境で運用するにはマストの機能ばかりかと思います。また、fluentdから直接BigQueryに送ることにより、マルチクラウドでも対応できるし、OutputをBigQueryから他サービスに変更(もしくは追加)することも簡単にできますので、シーンに応じて使い分けできると思います。結構つまづいたのがfluentdで、jsonログをparseし、特定のキーに対してさらに複雑な加工をしたい場合にちょうどいいプラグインが見つからなかったのでその辺りは調査、もしくは、自分でプラグインを作るのもありかなと思います。 次回以降で、データの可視化やkubernetesのメトリクス収集等も紹介していきますのでこちらも乞うご期待。
お知らせ
SREチームでは「No Challenge, No SRE, No SPEEDA」を掲げ、ユーザベースグループのミッションである「経済情報で、世界をかえる」の実現に向けて、日々業務に取り組んでいます。 興味を持ってくださった方はこちらをご確認ください。