最近話題のDockerやGoogle Cloud Platformを用いて大規模データのための解析基盤を作ります。今回はデータソースとしてTwitter Streaming APIを利用しますが、アクセスログなどに応用することももちろん可能です。コードは一行も書きません。解析基盤をつくためにマシンを用意する必要はもちろんありません。
BigQueryについては、
Googleの虎の子「BigQuery」をFluentdユーザーが使わない理由がなくなった理由 #gcpja
が参考になります。
利用するプロダクト/サービス
想定する環境
- mac os x 10.9
- docker / boot2docker インストール済み
- python 2.* インストール済み (
gcloud
コマンドは3系では動きません)
方針
- fluentdを使ってTwitter Streaming APIから取得したツイートをBigQueryに保存する
- Googleが提供しているDockerに最適化されたGoogle Compute EngineのOSイメージを利用 (参考)
- ローカル上でfluentdのコンテナを作成し、それをGoogle Compute Engine上で動かす
- つまり fluentd on Docker on Google Computed Engine
- container-agentを利用してインスタンス起動時にdocker上でfluentdのコマンドが自動的に実行されるようにする
Step 1 - fluentdコンテナの構築
Dockerの動作確認
$ boot2docker up # Dockerの起動
[2014-06-07 13:06:44] Starting boot2docker-vm...
[2014-06-07 13:07:16] Started.
$ export DOCKER_HOST=tcp://localhost:4243 # Dockerコマンドをlocalhost:4243に向ける
$ docker version # バージョンの確認
Client version: 0.11.1
Client API version: 1.11
Go version (client): go1.2.1
Git commit (client): fb99f99
Server version: 0.11.1
Server API version: 1.11
Git commit (server): fb99f99
Go version (server): go1.2.1
コンテナの構築
(私が作成したコンテナtacke/fluentd
を利用すれば、この作業はスキップできます。)
$ mkdir oreore-fluentd
$ cd !$
$ cat Dockerfile
FROM ubuntu:12.04
ENV DEBIAN_FRONTEND noninteractive
RUN echo "deb http://archive.ubuntu.com/ubuntu precise main universe" > /etc/apt/sources.list
RUN apt-get update && apt-get -y upgrade
RUN apt-get -y install curl
RUN curl -O http://packages.treasure-data.com/debian/RPM-GPG-KEY-td-agent && apt-key add RPM-GPG-KEY-td-agent && rm RPM-GPG-KEY-td-agent
RUN curl -L http://toolbelt.treasuredata.com/sh/install-ubuntu-precise.sh | sh
RUN apt-get -y install libssl-dev
RUN apt-get -y install build-essential
RUN /usr/lib/fluent/ruby/bin/fluent-gem install fluent-plugin-twitter
RUN /usr/lib/fluent/ruby/bin/fluent-gem install fluent-plugin-bigquery
RUN echo "" > /etc/td-agent/td-agent.conf
$ docker build -t <YOUR_TAG_NAME> . # コンテナのビルド
/etc/td-agent/td-agent.config
は意図的に空にしています。
Dockerコンテナはimmutableなので、設定内容をコンテナに含めてしまうと複数のfluentdサーバーを異なる設定で起動したい場合に、それぞれ別のコンテナを作らなければいけません。
また、twitterの認証トークンが書き込まれたコンテナをDockerのリポジトリにアップロードするのはセキュリティ上問題があります。
そのため今回は、後に出てくるように、td-agentコマンドのオプションに直接設定を渡す方法を取ることにします。(別の方法でも可能だと思います。)
$ docker push <YOUR_TAG_NAME> # コンテナを docker index にアップロード
The push refers to a repository [<YOUR_TAG_NAME>] (len: 1)
Sending image list
Pushing repository <YOUR_TAG_NAME> (1 tags)
...
Pushing tag for rev [] on {https://registry-1.docker.io/v1/repositories/<YOUR_TAG_NAME>/tags/latest}
これでGoogle Compute Engine上のDockerにコンテナをインストールする準備が整いました。
Step 2 - GCE上でDockerコンテナ動かす
Google Cloud SDKのインストール
$ curl https://sdk.cloud.google.com | bash # Google Cloud SDKのインストール
/Users/yuki.takeichi/google-cloud-sdk/install.sh
Welcome to the Google Cloud SDK!
The Google Cloud SDK is currently in developer preview. To help improve the
quality of this product, we collect anonymized data on how the SDK is used.
You may choose to opt out of this collection now (by choosing 'N' at the below
prompt), or at any time in the future by running the following command:
gcloud config --global-only set disable_usage_reporting true
(略)
For more information on how to get started, please visit:
https://developers.google.com/cloud/sdk/gettingstarted
SDKはデフォルトだと$HOME/google-cloud-sdk
にインストールされます。
bash_profile
やコマンド補完や$PATH
もよきに設定してくれます。
$ gcloud auth login # Google Cloud Platformにログイン
Your browser has been opened to visit:
https://accounts.google.com/o/oauth2/auth?redirect_uri...
You are now logged in as [_____@gmail.com].
Your current project is [None]. You can change this setting by running:
$ gcloud config set project <project>
ブラウザが立ち上がるのでログインをしてOAuthの認証を許可しましょう。
GCPプロジェクトの作成
プロジェクトを設定しろと言われるので、まずはConsoleでプロジェクトを作成します。
project idは適当な英単語と数字を組み合わせたものを自動生成してくれますが、わかりにくいのでプロジェクト名と同一にしておくほうがよいです。
GCPのDeveloper ConsoleのCloud Develop -> リリース
でリポジトリの設定を行います。
設定が完了すると、GCP上にデプロイ用のリモートリポジトリが作成されます。
その後、ターミナルに戻りprojectの設定を行います。
$ mkdir ~/gcp
$ cd !$
$ gcloud init <PROJECT_ID> # プロジェクトリポジトリを取得
Initialized gcloud directory in [/Users/<USER_NAME>/gcp/<PROJECT_ID>/.gcloud].
Cloning [https://source.developers.google.com/p/<PROJECT_ID>/r/default] into [default].
Initialized empty Git repository in /Users/<USER_NAME>/gcp/<PROJECT_ID>/default/.git/
Project [<PROJECT_ID>] was initialized in [/Users/<USER_NAME>/gcp/<PROJECT_ID>].
$ cd <PROJECT_ID>/
$ gcloud config set project <PROJECT_ID> # コマンドにプロジェクトを設定
DockerのOSイメージを利用してGCEインスタンスを作成
https://developers.google.com/compute/docs/containers を参考に進めます。
Googleが提供しているDockerに最適化されたOSイメージを利用します。
ゾーンはasia-east1-a
(もしくはasia-east1-b
)にします。
マシンタイプはとりあえず一番ロースペックのf1-micro
(CPU1コア RAM0.6GB)を選択します。
$ gcloud compute instances create <VM_NAME> \
--image projects/google-containers/global/images/container-vm-v20140522 \
--zone asia-east1-a \
--machine-type f1-micro
ERROR: (gcloud.compute.instances.create) some requests did not succeed:
- Project projects/<PROJECT_ID> cannot accept requests to insert while in an inactive billing state. Billing state may take several minutes to update.
課金情報を登録しろと言われました。Consoleに戻って登録します。
完了したら再び上記コマンドを実行します。
$ gcloud compute instances create <VM_NAME> \
--image projects/google-containers/global/images/container-vm-v20140522 \
--zone asia-east1-a \
--machine-type f1-micro
---
canIpForward: false
creationTimestamp: '2014-06-06T19:28:23.364-07:00'
disks:
- autoDelete: true
boot: true
deviceName: persistent-disk-0
index: 0
kind: compute#attachedDisk
mode: READ_WRITE
source: <VM_NAME>
type: PERSISTENT
id: '000000000000'
kind: compute#instance
machineType: f1-micro
metadata:
fingerprint: aaaaaaaaa=
kind: compute#metadata
name: <VM_NAME>
networkInterfaces:
- accessConfigs:
- kind: compute#accessConfig
name: external-nat
natIP: YYY.YYY.YYY.YYY
type: ONE_TO_ONE_NAT
name: nic0
network: default
networkIP: XXX.XXX.XXX.XXX
scheduling:
automaticRestart: false
onHostMaintenance: MIGRATE
selfLink: https://www.googleapis.com/compute/v1/projects/<PROJECT_ID>/zones/asia-east1-a/instances/<VM_NAME>
serviceAccounts:
- email: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX@developer.gserviceaccount.com
scopes:
- https://www.googleapis.com/auth/devstorage.read_only
status: RUNNING
tags:
fingerprint: bbbbbbb=
zone: asia-east1-a
正常にインスタンスが作成されたようです。ちゃんと動いているか確認するためSSHでログインしてみます。
$ gcloud compute ssh --zone asia-east1-a <VM_NAME>
WARNING: You don't have an ssh key for Google Compute Engine. Creating one now...
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
<USER_NAME>@XXX.XXX.XXX.XXX's password: # 空
INFO: Running command line: ssh -o UserKnownHostsFile=/dev/null -o CheckHostIP=no -o StrictHostKeyChecking=no -i /Users/<USER_NAME>/.ssh/google_compute_engine -A -p 22 <USER_NAME>@XXX.XXX.XXX.XXX --
Warning: Permanently added 'XXX.XXX.XXX.XXX' (RSA) to the list of known hosts.
Linux oreore-vm 3.14-0.bpo.1-amd64 #1 SMP Debian 3.14.4-1~bpo70+1 (2014-05-14) x86_64
The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.
Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
<YOUR_USER>@<VM_NAME>:~$
ログインできましたね。初回時のみ鍵を作成する必要があります。
VM上で以下を実行します。パスワードは必要ありません。
$ sudo docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
Dockerが起動していることが確認できました。
それではローカルのコンソールに戻ってインスタンスを削除しておきましょう。
$ gcloud compute instances delete <VM_NAME> --zone asia-east1-a # インスタンス削除
Step 3 - fluentd on Docker on GCE
それでは、Step1でpushしたコンテナを利用してfluentdをGCE上で動かします。
その前に、BigQueryのテーブルを作成します。
$ bq mk my_dataset # データセットの作成
Dataset '<PROJECT_ID>:my_dataset' successfully created.
$ bq mk -t my_dataset.twitter id:integer,id_str:string,text:string,lang:string # テーブルスキーマの作成
Table '<PROJECT_ID>:my_dataset.twitter' successfully created.
正常に作成されました。
それでは次はいよいよGCE上でfluentdを動かします。
Googleが提供しているOSイメージにはcontainer-agentがインストールされています。
container-agentはインスタンスが起動したタイミングでインスタンスのメタ情報を読み取って、Dockerコンテナをダウンロードし、コンテナ上で予め設定したコマンドを実行します。
containter-agentのための設定をcontainers.yaml
に記述します。
$ cat containers.yaml
version: v1beta1
containers:
- name: twitter-public-stream
image: tacke/fluentd
command: ['td-agent', '-i', '<source> \n type twitter \n consumer_key XXX \n consumer_secret XXX \n oauth_token XXX \n oauth_token_secret XXX \n tag input.twitter.test \n timeline sampling \n output_format nest \n </source> \n \n <match input.twitter.**> \n type bigquery \n \n auth_method compute_engine \n \n project oreore-project \n dataset oreore_dataset \n table twitter \n field_integer id \n field_string id_str,text,lang \n </match>']
コンテナ上で実行するtd-agentコマンドにはインラインコマンドオプション(-i
)を利用して直接設定を渡しています。
XXX
の部分はTwitterの各認証トークンで置き換えてください。
ちなみに元々のfluentd.conf
は、
# fluentd.conf
<source>
type twitter
consumer_key XXX
consumer_secret XXX
oauth_token XXX
oauth_token_secret XXX
tag input.twitter.test
timeline sampling
output_format nest
</source>
<match input.twitter.**>
type bigquery
auth_method compute_engine
project oreore-project
dataset oreore_dataset
table twitter
field_integer id
field_string id_str,text,lang
</match>
このような姿でした。
そして、インスタンスを立ち上げます。
$ gcloud compute instances create <VM_NAME> \
--image projects/google-containers/global/images/container-vm-v20140522 \
--zone asia-east1-a \
--machine-type f1-micro \
--scopes bigquery \
--restart-on-failure \
--metadata-from-file google-container-manifest=containers.yaml
--metadata-from-file
はkey=value
の形式でインスタンスにメタ情報を与えます。
--scopes bigquery
でインスタンスに対してBigQueryへのアクセス許可を与えています。--restart-on-failure
を付けておくと問題が発生してVMが終了した際に自動的に再起動されます。
インスタンスが立ち上がりしばらくするとDocker上でfluentdが起動し、
取得されたツイートのBigQueryへの保存が開始します。
BigQuery上でクエリを叩く
取得されたツイートがちゃんとBigQueryに保存されているか確認してみましょう。
$ bq query "select count(*) from my_dataset.twitter"
Waiting on bqjob_r231b79b42efff050_00000146763c4855_1 ... (0s) Current status: DONE
+-------+
| f0_ |
+-------+
| 78450 |
+-------+
ちゃんと保存されているのが確認できましたね!
お疲れ様でした!
最後に
ログ収集プラットフォームであるfluentdを使って簡単にストリームデータの収集が行えるようになりました。Dockerを使えば他人が作ったインストール済みコンテナを利用して、煩わしいセットアップを抜きにミドルウェアを試すことができるようになりました。BigQueryを利用すればTB級のビッグデータへのクエリを、フレンドリーなSQLで記述することができ、ものの数秒で結果を得ることができるようになりました。
このような技術の進歩によって、特別なマシンを持っていない個人やベンチャーでも、簡単にデータ解析基盤を手に入れることができるようになりました。素晴らしいことだと思います。
特別な技術は必要ありません。解析したい大規模データがあるのに、リソースや技術が無いために今まで行えなかった人にとって、この記事が参考になれば幸いです。