2016年8月28日日曜日

GCPのBigQueryを使ってみました

BigQueryを使ってみたので、関連情報をまとめました

GCP NoSQL を使ってデータ処理したい時

主なサービスはこの辺りだと思います。

今回は、格安で比較的枯れているBigQueryを使ってみました。 以降の記事はBigQueryについてです。

オライリー本もあります。 Google BigQuery

課金について

ビッグデータをCloudサービスで使う時、課金方式をよく把握しておくのは必須です。

  • データ保存による: 1TB 1ヶ月 $20
  • スキャンデータ量による
  • BigQueryで150万円溶かした人の顔
  • 300GBに対して、フルスキャンを数百回繰り返した。(テーブル切り分けのために、select insert)
  • 価格体系が今後変わる。computing量による感じに。
  • ストリーミングは課金: 10万行単位などバルクインサートより高い。
  • 費用的には、Cloud Storageなどにデータを置いて、バルクインサートが良い。
  • ストリーミングの方が手間は少ない(Fluentdや、以下のPandasなどで直接インサートできる)
  • ストリーミングはデータ落ちなどが発生する模様。

BigQuery の課金仕様と注意点をまとめてみた(2015-07 時点)

課金対策ツール

使い方

Pythonから使う場合がメインです。

データ分析基盤としての BigQuery 運用のベストプラクティス Python使いのためのBigQuery連携

また、SDKが提供されてない言語でも、REST APIから使えます。 BigQuery クライアント ライブラリ

その場合、OAUTH2認証が必要です。

CLIで使う

Googleが提供している、基本のbqコマンドです。

bq コマンドライン ツール クイックスタート

インタラクティブに使う

GCPのコンソールからのやり方です。

Quickstart Using the Web UI

Jupyter(IPython)ベースのインタラクティブツールもあります。
Betaですが、Jupyterはかなり使いやすいので、こちらもオススメです。

Google Cloud Datalab 上のページのCLOUD DATALAB を起動は使えなくなってる模様。立ち上げはこちらから。dockerを使って起動する。 quickstart

アプリで使う(ライブラリ)

  • Pandas: io.gbqパッケージがあり、read_gbqto_gbqが用意されてます。pandas使っている方ならこれ一択かと。かなり使いやすいです。
  • Pythonのclientライブラリ: BigQuery-Pythonがあります。Pandas使ってない方はこちらが候補になると思います。使いやすいです。
  • 公式API:上記でできないことがある場合以外、直接触ることはないです。ライブラリ作成者向けだと思います。
Pandas

to_gbqinsertすると、ストリーミングになり、課金対象になります。
大量データを入れる場合は計算した方が良いです。

pandas連携が詳しく載ってるので再掲します。

Python使いのためのBigQuery連携 pandas.io.gbq.read_gbq pandas.io.gbq.to_gbq

Python client

BigQuery-Python PythonからBigQueryを操作するときは BigQuery-Python が便利だった

公式API

BigQuery API クイックスタート BigQuery API Client Library for Python getting_started.py Google Application Default Credentials

Google Compute Engine インスタンス間でやり取り(service account と mysql in Debian)

Google Compute Engine間でやり取りをするときの設定です。

gcloudを既存のインスタンスで使う

Service Accountsを作って、その認証情報をgcloudに設定します。

認証エラーが出ます

認証設定してない時は、このようなエラーが出ます。

$ gcloud compute instances list
ERROR: (gcloud.compute.instances.list) Some requests did not succeed:
 - Insufficient Permission

auth loginでセットアップしようとすると...

$ gcloud auth login

You are running on a Google Compute Engine virtual machine.
It is recommended that you use service accounts for authentication.

service accountsを使った方が良いと勧められます。

サービスアカウントを作成

今回は、コンソールからサービスアカウントを追加しました。 詳細手順は、公式ドキュメントのCONSOLEタブにあります。

Creating and Managing Service Accounts

gcloudの設定

上記で取得した、キーファイルをインスタンス上に設置して、アクティベイトします。

$ vi ~/.cred.json
$ chmod 400 ~/.cred.json
$ gcloud auth activate-service-account --key-file ~/.cred.json
$ gcloud compute instances list
...

参考: gcloud auth activate-service-account Creating and Enabling Service Accounts for Instances

MySQLをインスタンス間で接続する

MySQLを設定して、インスタンス間のネットワークを設定します。

とりあえずつなぐと疎通出来ませんでした。

$ telnet 10.240.0.4 3306
Trying 10.240.0.4...
telnet: Unable to connect to remote host: Connection refused

Compute Engine

  • インスタンスのネットワーク設定を確認する
  • デフォルトで、default-allow-internalがついてる。変えて無ければOK。

How to Set Up Remote Access to MySQL on Google Compute Engine Google Compute Engineのファイヤーウォールを理解する

mysqlの設定

クライアント側でmysql-clinetをインストール

sudo apt-get install mysql-client

Debianでは、セキュリティ上の理由から、MySQLサーバは、デフォルトでリモートアクセスを停止しています。

  • /etc/my.cnfbind-address=${instance-ip}に設定します
  • mysqlをリスタートします。

    $ sudo systemctl restart mysql
    $ systemctl status mysql

mysql server

あとは、ユーザの権限を確認します

select user, host from mysq.user

確認

クライアント側のtelnetで疎通確認

$ telnet XXX 3306
Trying XXX...
Connected to XXX.
Escape character is '^]'.

クライアント側のmysqlコマンドで接続

mysql -u xxx -p -h xxx
2016年8月27日土曜日

pandasでの簡単な日付処理

pandasは、日付処理も充実しています。

すぐに使える関数をまとめました。

準備

import pandas as pd

日付に変換

Stringから作成する場合。

> pd.to_datetime('2016-08-26 00:00:00')
Timestamp('2016-08-26 00:00:00')

to_datetimeは、かなり賢く以下のような入力がデフォルトで正しくパースされます。

> pd.to_datetime('2016/8/26 0:0')
> pd.to_datetime('2016/8/26')
> pd.to_datetime('20160826')
> pd.to_datetime('160826 0000')
Timestamp('2016-08-26 00:00:00')

ただし、日付6桁は欧米式にパースされます。

> pd.to_datetime('260816 0100')
Timestamp('2016-08-26 01:00:00')

Python pandas で日時関連のデータ操作をカンタンに

日ごと、月ごと、年ごとに処理

年月日を取り出します。

> pd.to_datetime('2016-08-26 0:0:0').year
2016

> pd.to_datetime('2016-08-26 0:0:0').month
8

> pd.to_datetime('2016-08-26 0:0:0').day
26

dtを使うとdatetime64型の要素のプロパティに直接アクセスできます。

> df['date1']
0   2016-08-26
1   2016-08-27
Name: date1, dtype: datetime64[ns]

> df['date1'].dt.month
8

groupbyする場合です。

# 各カラムを月別に合計
df.groupby(df['date1'].dt.month).sum()

# グルーピングしたデータを取得
df.groupby(df['date1'].dt.month).groups

Python pandas アクセサ / Grouperで少し高度なグルーピング/集計

2016年8月26日金曜日

pandasでmysqlに接続する in debian

ライブラリインストールから、接続までまとめました。

mysql-connector-python + pandas.io.sqlです。

setup

リポジトリからが簡単に入ります。

$  git clone https://github.com/mysql/mysql-connector-python.git
$  cd mysql-connector-python
$  python ./setup.py build
$  sudo python ./setup.py install

condaを使ってる場合です。

$ conda install -c https://conda.anaconda.org/anaconda mysql-connector-python 

ディストリビューションからも取れる模様。

$ sudo apt-get install python3-mysql.connector

参考

python+pandasで大規模データを扱うときのメモ
Python3でMySQLに接続する環境をLinuxで整える
macでのmysql-connector-pythonインストール方法

DataFrameをテーブルから直接作る

import mysql.connector as mc
import pandas.io.sql as pdsql

con = mc.connect(
  user ='USER',
  password='PW',
  host='localhost',
  database='DB')

sql = 'SELECT * FROM table'

df = pdsql.read_sql(sql, con)
# ここでそのまま使えます。

con.close

参考

pandasでRDBの読み書きをする

2016年8月25日木曜日

Haskellでさくっとデータ処理をする

Haskellの強みの一つは、関数合成やパターンマッチを使って複雑なロジックをバグを抑えながら書けることだと思います。

さくっとデータ処理をやりたい時に使えそうなところをまとめました。

まずはシンプルに

ghciとdoctest

対話型のghciを使うと試しながらできるのでオススメです。

そこである程度固まってきたら、hsファイルにまとめたくなると思います。

doctestは、簡単な実行環境としても使えます。 Haskellの単体テスト最前線

Listを使う

列ごとにListとして取り込みます。

行は、Listをzipしてtupleを作ると柔軟に使えます。

Record構文は、さくっとやりたい時には、手間がかかります。

>>> id = ["a","b","c"]
>>> num = [1,2,3]
>>> data = zip id num
>>> data
[("a", 1), ("b", 2), ("c", 3)]

モナドについて

IOは出力に必要ですが、それ以外は最低限必要なものだけを使います。

実践的にモナドを使う方針と具体的な使い方が参考になります。

Haskellで競技プログラミング IO編

Maybeは、欠損値がある場合に使います。

型宣言しない

型宣言をつけると格好がつきますが、さくっとやる場合は、基本つけなくてもいいと思います。

少し実践的に

Vector

パフォーマンスを考えたらぜひ使いたいライブラリです。

List操作は楽ですが、パフォーマンスがネックになる場合があります。

その時に使えます。

また、データ処理系のライブラリでは、デフォルトで使われています。

https://github.com/haskell/vector

csvを使う

cassavaがシンプルに使えて便利です。

https://github.com/hvr/cassava

サクッと使うならば、ヘッダなしがオススメ。 レコードごとに処理するサンプルコードです。

{-# LANGUAGE ScopedTypeVariables #-}

import qualified Data.ByteString.Lazy as BL
import Data.Csv
import qualified Data.Vector as V

main :: IO ()
main = do
    csvData <- BL.readFile "salaries.csv"
    case decode NoHeader csvData of
        Left err -> putStrLn err
        Right v -> V.forM_ v $ \ (name, salary :: Int) ->
            putStrLn $ name ++ " earns " ++ show salary ++ " dollars"

ここで、decode NoHeader csvDataは、Vectorを返すので、forM_以外のVectorの関数にも慣れておくといいです。

joinを作ってみた

Haskellはロジック記述力が高いので、シンプルにいろいろと書けます。

SQLのjoinに相当する操作(結合条件を指定して、二つの表をつなげる)を探しましたが、意外とありませんでした。

実際にデータを処理するときは、キー結合したいときは結構多いため、書いてみました。

キーを条件に要素をつなげてますが、結合条件を関数で渡してもよかったと思います。 inner joinは、zip, filter, intersectなどでそのまま書けます。

import Data.List
import Data.Maybe as M

-- | Join 
--
-- Examples:
--
-- >>> fullJoin [1,2] [10,20] [2,3] [200, 300]
-- [(1,Just 10,Nothing),(2,Just 20,Just 200),(3,Nothing,Just 300)]
--
-- >>> leftJoin [1,2] [10,20] [2,3] [200, 300]
-- [(1,Just 10,Nothing),(2,Just 20,Just 200)]
--
-- >>> rightJoin [1,2] [10,20] [2,3] [200, 300]
-- [(2,Just 20,Just 200),(3,Nothing,Just 300)]
-- 
-- >>> innerJoin [1,2] [10,20] [2,3] [200, 300]
-- [(2,Just 20,Just 200)]
--
-- >>> data Row = Row { col1 :: Integer , col2 :: Integer } deriving (Eq, Show)
-- >>> type Table = [Row]
-- >>> let table = [Row {col1 = 10, col2 = 11}, Row{col1 = 20, col2 = 21}]
-- >>> fullJoin [1,2] table [2,3] [200,300]
-- [(1,Just (Row {col1 = 10, col2 = 11}),Nothing),(2,Just (Row {col1 = 20, col2 = 21}),Just 200),(3,Nothing,Just 300)]
--
-- >>> let { f i (Just x) Nothing = (i, col1 x, col2 x, 0); f i (Just x) (Just y) = (i, col1 x, col2 x, y); f i Nothing (Just y) = (i, 0, 0, y); f i Nothing Nothing = (i, 0, 0, 0); }
-- >>> fullJoinWith f [1,2] table [2,3] [200,300]
-- [(1,10,11,0),(2,20,21,200),(3,0,0,300)]

fullJoinWith f ks1 vs1 ks2 vs2 = map (\(i, x, y) -> f i x y) $ fullJoin ks1 vs1 ks2 vs2

leftJoin :: Ord k => [k] -> [a] -> [k] -> [b] -> [(k, M.Maybe a, M.Maybe b)]
leftJoin ks1 vs1 ks2 vs2 = _join ks1 ks1 vs1 ks2 vs2

rightJoin :: Ord k => [k] -> [a] -> [k] -> [b] -> [(k, M.Maybe a, M.Maybe b)]
rightJoin ks1 vs1 ks2 vs2 = map (\(x, y, z) -> (x, z, y)) $ _join ks2 ks2 vs2 ks1 vs1

fullJoin :: Ord k => [k] -> [a] -> [k] -> [b] -> [(k, M.Maybe a, M.Maybe b)]
fullJoin ks1 vs1 ks2 vs2 = _join (union ks1 ks2) ks1 vs1 ks2 vs2

innerJoin :: Ord k => [k] -> [a] -> [k] -> [b] -> [(k, M.Maybe a, M.Maybe b)]
innerJoin ks1 vs1 ks2 vs2 = _join (intersect ks1 ks2) ks1 vs1 ks2 vs2

_join :: Ord k => [k] -> [k] -> [a] -> [k] -> [b] -> [(k, M.Maybe a, M.Maybe b)]
_join ids ks1 vs1 ks2 vs2 = zipWith(\(x, y) (_, y2) -> (x, y, y2)) zs1 zs2
  where
    zs1 = mkZs ks1 vs1 
    zs2 = mkZs ks2 vs2
    mkZs ks vs = sortByFst . filterByFst . (++) (zipWith(\k v -> (k, Just v)) ks vs) $ zip (ids \\ ks) (repeat Nothing) 
    sortByFst = sortBy (\(x1, _) (x2, _) -> compare x1 x2)
    filterByFst = filter (flip elem ids . fst) 
2016年8月21日日曜日

tensorflow の sample を動かす

以下は、tensorflowの公式チュートリアルの一つ、手書き数字認識のサンプルです。

TensorFlow MNIST tutorial

インストール時にエラーが出る場合があります。 最新版を入れて、protobufを入れ直して解決しました。

インストール

このsampleを試す場合、tensorflowのインストールは、このやり方がオススメです。

少し古いバージョンを直接指定したところ、input_dataのパッケージパスの指定が、tutorialのやり方ではうまくいきませんでした。 また、最新が欲しい方は、githubからcloneする方法もあります。 https://github.com/tensorflow/tensorflow/issues/890

export TF_BINARY_URL=https://storage.googleapis.com/tensorflow/linux/cpu/tensorflow-0.10.0rc0-cp27-none-linux_x86_64.whl
pip install --upgrade $TF_BINARY_URL --trusted-host storage.googleapis.com

データインポート

tutorial に従ってデータをインポートすると以下のようなエラーが出ました。

> from tensorflow.examples.tutorials.mnist import input_data
...
ImportError: Traceback (most recent call last):
  File "/home/YutakaNishimura/tensorflow/lib/python2.7/site-packages/tensorflow/python/__init__.py", line 52, in <module>
      from tensorflow.core.framework.graph_pb2 import *
        File "/home/YutakaNishimura/tensorflow/lib/python2.7/site-packages/tensorflow/core/framework/graph_pb2.py", line 6, in <module>
            from google.protobuf import descriptor as _descriptor
            ImportError: No module named google.protobuf


Error importing tensorflow.  Unless you are using bazel,
you should not try to import tensorflow from its source directory;
please exit the tensorflow source tree, and relaunch your python interpreter
from there.

protobufを確認すると入ってました。
インストールし直しました。

pip uninstall protobuf
pip install protobuf

再度実行すると成功しました。

In [1]: from tensorflow.examples.tutorials.mnist import input_data

In [2]: mnist = input_data.read_data_sets('MNIST_data', one_hot=True)

Successfully downloaded train-images-idx3-ubyte.gz 9912422 bytes.
Extracting MNIST_data/train-images-idx3-ubyte.gz
Successfully downloaded train-labels-idx1-ubyte.gz 28881 bytes.
Extracting MNIST_data/train-labels-idx1-ubyte.gz
Successfully downloaded t10k-images-idx3-ubyte.gz 1648877 bytes.
Extracting MNIST_data/t10k-images-idx3-ubyte.gz
Successfully downloaded t10k-labels-idx1-ubyte.gz 4542 bytes.
Extracting MNIST_data/t10k-labels-idx1-ubyte.gz

Pandasの基本的でよく使いそうな機能のメモ

Pandasの基本的ですが、実際によく使いそうな使い方のメモです。

インストールについて

こちらが非常に詳しいです。 anacondaを使って環境構築します。

Google Compute Engine + Debian で実行しましたが、問題なく動いてます。

データサイエンティストを目指す人のpython環境構築 2016

csv形式のStringからデータを読み取る。

Stringから直接csvデータを読み込むこともできます。 http://stackoverflow.com/questions/22604566/how-to-create-a-pandas-dataframe-from-string

import sys
from io import StringIO

d = StringIO("""a,b,c
1,2,3
11,12,13
""")

df = pd.read_csv(d)

データフレームを連結する

Python Pandasでのデータ操作の初歩まとめ − 前半:データ作成&操作編 pandasでindexの連番を振り直す

concatもしくは、append関数を使います。

行を追加する場合も、DataFrameの連結で行います。

  • concatは対象とするDataFrameをリストにして渡します。
  • appendはdf.appendという書き方になるので、直接行を追加する場合に便利です。
  • どちらもデフォルトでは、非破壊的な動作になっています。

行方向に追加

concatを使って連結

// axis=0 (デフォルト。省略可能)
concated_df = pd.concat([df1, df2])

ちなみに、カラム名が異なると、カラムは全て残り、互いの欠損箇所には、NA値が挿入されます。

欠損値を埋めたい場合は、fillnaを使います。統計処理で必要とされる、平均値補完、線形補間なども簡単にできます。

// 0埋め
df.fillna(0)
// 平均値
df.fillna(df.mean())
// 線形補間
df.interpolate()
// na値削除(行ベース)
df.dropna()
// na値削除(列ベース)
df.dropna(axis=1)

appendを使って行をその場で追加

// columnsを既存のものから取ってきて同じ構造にします
appended_df = df.appned(pd.DataFrame([[1,2,3]], columns = df.columns.tolist())

列方向に追加

pd.concat([df1, df2], axis=1)

同じくインデックスが違うと列方向にNA値が挿入される。

新しい列をその場で追加する方法は、こちらが簡単です。 ただ、dfを直接書き換えるので注意が必要です。

df['c_new'] = [1,2,3]

インデックス・カラムの貼り直し

行番号の貼り直し

concated_df.reset_index(drop=True)

//直接生成時に貼り直すこともできる
pd.concat([df1,df2]).reset_index(drop=True)

カラム名の貼り直し

// dfインスタンスに対して設定
concated_df.columns = ["c1","c2","c3","c4","c5","c6"]

表記ブレをなくすよう変更

// 全て小文字にして、スネークケースにする。記号も開きました。
df.columns = [s.lower().replace(' ', '_').replace('?', '_bool') for s in df.columns.tolist()]

SQLのような処理を行う

よくまとまっていてオススメです。

pandasにsqlでよくやる処理をやらせてみる

sort

sort_valuesを使う方が推奨のようです。

df.sort_values(by="col1")

ERROR

CSVのパースエラー

CSVを読み込む時に、パースエラーが発生しました。

> df = pd.read_csv("file.csv")

pandas/parser.pyx in pandas.parser.TextReader.read (pandas/parser.c:8748)()

pandas/parser.pyx in pandas.parser.TextReader._read_low_memory (pandas/parser.c:9003)()

pandas/parser.pyx in pandas.parser.TextReader._read_rows (pandas/parser.c:9731)()

pandas/parser.pyx in pandas.parser.TextReader._tokenize_rows (pandas/parser.c:9602)()

pandas/parser.pyx in pandas.parser.raise_parser_error (pandas/parser.c:23325)()

CParserError: Error tokenizing data. C error: EOF inside string starting at line 244276

ここで line 244276 は、ファイル上の行数でないので注意が必要です。

この時は結果的に、csvファイルの最終行のデータがおかしくなっていためエラーになっていました。

それでも解決しない場合は、この辺りが参考になると思います。

ISSUEが立っていますが、この問題は現在は、フィックスされてるよう。 https://github.com/pydata/pandas/issues/5501

カラムが多すぎるとExceptionを吐くが、それらを削除して読み込む。

pd.read_csv("file.csv", error_bad_lines=False)

エンコーディングとエンジンを指定する

pd.read_csv("file.csv", encoding='utf-8', engine='c')
pd.read_csv("file.csv", encoding='utf-8', engine='python')

quotingを指定する

import csv
pd.read_csv("file.csv", quoting=csv.QUOTE_NONE)

文字列として読み込んで解析する

f = open("file.csv")
s = f.read()
l = f.readlines()
2016年8月20日土曜日

Pandasで実践的(というか実務的)なデータを扱う

実務的なデータをさっと処理したい場合、

  • SQL
  • スクリプト言語
  • Shell/AWK
  • Excel

あたりがよく使われると思います。

ここでは、スクリプト言語の一つになると思いますが、Python+Pandas紹介します。

Pandasは、Pythonのデータ処理用ライブラリで、DataFrameというExcelのスプレッドシートのようなオブジェクトを使って処理します。DataFrameはもともとS言語/Rに実装されていたものです。

Pandasの特徴である強力で豊富な統計処理の紹介が多いですが、実務データの処理もかなり使えます。

準備

ipython

pythonの対話実行環境としては、ipythonは必須です。 ファイルのタブ補完も効くのでサクサクできます。

pip install ipython

Pandasのimport

ここからは、事前にこのようにimportしていることを前提とします。

import pandas as pd
import numpy as np

データ読み取り

csvファイルの場合。

df = pd.read_csv("a.csv")

URLや桁区切りのカンマにも強いtsvファイルはこちら。

df = pd.read_csv("a.tsv", sep="\t")

ファイルにはヘッダを入れた方がいいです。

PandasのDataFrameはヘッダ情報もきちんと読み取り、列名称で値を指定することが可能なためです。

マージ(join)

現実の業務処理では、joinはかなり需要があると思います。

Pandasももちろんできますが、どちらかというと、統計処理で必要な行を追加していく(union系)の処理の紹介が多いと思います。

Pandasでのマージの仕方。

// キー名が違う場合
merged = pd.merge(df1, df2, left_on = 'id1', right_on = 'id2')
// キー名が同じ場合
merged = pd.merge(df1, df2, on = 'id') 

mergeメソッドは、オプションも豊富です。

行ごとに処理

必要なデータが一つの表にまとまったら、行ごとに処理をしたいですね。

しかもこのロジックはかなり複雑になることがあります。

SQLで複雑なCASE文を書くよりもスクリプト言語で書いた方がすっきりする場合も多いです。

オススメはiterrowsを使うことです。applymapを使うと、関数を渡してシンプルに記述できるのですが、カラム名が使えなくなります。

df['new'] = ""
for key, record in df.iterrows():
  if record["column1"] in ["a", "b"]:
    ...複雑なロジック
    df.loc[key, 'new'] =  "column1 is " + record["column1"]

また、ここはPandasの強力なスライシング処理によって、必要なデータを取得することが可能なのでロジックを簡潔にすることが可能です。

こちらはapplyを使って行ごとに処理する場合。

def f(s):
  print s

df.apply(f, axis=1)

csv/tsvへの出力

非常にシンプルです

csv

df.to_csv("b.csv")

import csv
df.to_csv("b.csv", quoting=csv.QUOTE_ALL)

tsv

df.to_csv("b.csv", sep="\t")

まとめ

各ステップでは、そこに強い言語やツールがあるかと思います。

Python+Pandasは一通り扱えることがメリットだと思います。

一旦、DataFrameに取り込んでしまえば、手続き的な処理、集計処理ともにかなり柔軟に処理ができます。

2016年8月14日日曜日

Google Container Engine(kubernates)をDebianで試すときのポイント

kubernatesは現在も活発に開発が進んでいるプロダクトです。

コンテナを日常的に使っていると前提条件になっていることは省略されていて、意外とまとまったものが出てきません。

初めてセットアップするときのポイントをまとめました。

セットアップの流れ

  1. dockerのインストール
  2. Google Cloud Platformのクライアント(gcloud)をインストール
  3. kubernates(kubectl)のインストール(gcloudで入らない場合)
  4. Googleの公式ドキュメントに従う
  5. kubernatesのサンプルに従う

その他注意点

  • 数百MB〜数GBのデータ通信が発生する
  • dockerイメージを使ってるとすぐに数GB~数十GB使う

参考

kubectl リファレンス Quickstart Google Container Engine

dockerのインストール

  • apt-get では、docker.ioをインストールする必要がある。

    $ sudo apt-get install docker.io
  • インストールしたら、rebootしてください。(日常的に使ってないとつい忘れて諸々エラーが出る)

    $ sudo reboot
  • dockerグループに追加しておく。

    $ sudo gpasswd -a ${user} docker 
  • dockerコマンドはきちんと設定すれば、基本sudoなくてOKです。

    $ docker info

ここまでやったら、Googleの公式ドキュメントに従って進める。

Container Engine 開始方法

  • gcloudからkubectlを入れる箇所がありますが、できない場合は、次のkubernatesのインストールをします。

    $ gcloud components update kubectl
    $ rehash
    $ kubectl version
  • gcloud とGKEを組み合わせるとかなり簡単にクラスターを作れる。
  • CoreOSを複数立ち上げて、その上にクラスターを乗せるのは、GKEができてからでいいと思います。

kubernates(と関連ツール)のインストール

kubectlのインストールをしておきます。

gcloudコマンドでkubectlがインストールできれば、この箇所は飛ばして問題ないです。

  • パッケージ管理では提供されてないです。
  • githubのリリースから取ってきます。(以下はv1.3.5)

    $ curl -OL https://github.com/kubernetes/kubernetes/releases/download/v1.3.5/kubernetes.tar.gz
    $ tar xzvf kubernetes.tar.gz
  • リリースには、ビルド後の全てが入ってます。
  • kubectlのインストールです。

    $ sudo cp kubernetes/platforms/linux/amd64/kubectl /usr/local/bin/kubectl
    $ sudo chmod +x /usr/local/bin/kubectl
  • 参考: Installing and Setting up kubectl

kubernates サンプルを試す。

上記ページの一番下に、kubernatesのサンプルのリンクがあります。 例えばnode.jsを使ってみるなどがあります。

node.jsを使う例

2016年8月11日木曜日

API-gateway + Lambdaの連携で多少込み入った処理をやる

Api gatewayとLambdaの連携でどの程度のAPIをサーバレスにできるか調べました。 Lambdaをチェーンすれば、いろいろとできる反面、AWS依存がさらに高まります。

メリット

インフラコストカット 管理コストカット(ノウハウが蓄積したのち)

デメリット

導入コストアップ ベンダーロックイン

実際にどの程度使えるか?

Lambda単発だと実行時間等制限があるが、チェーンすることで混みいった処理が可能。

  • 外向きのAPIは、受け取ったデータをシンプルに保存。
  • Lambdaを入れて、ここでちょっとした処理はできる。基本その場でステータスを返す
  • 保存イベント(もしくは、定期的に)から別のLambdaを起動。
  • これは、Dynamoもしくは、/tmpを使いながらanother apiを叩く。
  • ログやエラー処理をちゃんと見直す必要がある。

    api gateway -> Lambda(1) -> DynamoDB(or s3) -> Lambda(2) -> DynamoDB(or s3 or local /tmp) -> another api server
  • Javaは立ち上がりの遅さがネック(外部連携などだとタイムアウト発生する可能性)
  • Lambdaのプログラミングモデルに合わせる必要があるため、既存コード流用はライブラリ設計が汎用的になってないと厳しい。
  • また、LambdaのNode->バイナリ呼び出しも可能。
  • 処理内容によるが、NodeやPythonで書き直したほうがいいケースが多そう。

参考

【新機能】Amazon DynamoDB Triggersを使ってDynamoDB StreamsとAWS Lambdaを連携する

DynamoDB

API Gateway と Lambdaの連携

サンプルコード

API-gateway と Lambda のサンプルを改造。

dynamo streamをトリガーにしたLambda

from __future__ import print_function

import json
import boto3

print('Loading function')


def lambda_handler(event, context):
    
    dynamodb = boto3.resource('dynamodb')
    table = dynamodb.Table('calc_table_log')
   
    #print("Received event: " + json.dumps(event, indent=2))
    for record in event['Records']:
        print(record['eventID'])
        print(record['eventName'])
        print("DynamoDB Record: " + json.dumps(record['dynamodb'], indent=2))

        table.put_item(Item={
            "Id": record['dynamodb']['NewImage']['id']['N'],
            "ans": record['dynamodb']['NewImage']['ans']['N']})

    return 'Successfully processed {} records.'.format(len(event['Records']))

API-gateway から呼び出されるLambda

import boto3
import random

def my_handler(event, context):
    
    dynamodb = boto3.resource('dynamodb')
    table = dynamodb.Table('calc_table')

    res = {}
    res['a'] = int(event['a'])
    res['b'] = int(event['b'])
    
    if event['op'] == 'add':
        res['op'] = '+'
        res['c'] = res['a'] + res['b']
        try:
          id = random.randint(1,100)
          table.put_item(Item={
              'id': id,
              'ans':res['c']
              })
          res['dynamo_id'] = id
        except Exception, e:
            print (e)
    else:
        res['op'] = 'na'
        res['c'] = 0
        
    return res

今後の検討点など

サーバーレスにしても、権限など管理は残る。 これらをどうやって管理・運用するのか?

また、複数サービスの連携を一元的に管理する方法については、まだまだノウハウが少ない。(ここを管理するサーバーレスフレームワークがあるがまだまだこれから)

それらに伴う運用変更コストと、新しい運用の経験値の蓄積が必要。

また、開発における導入コスト。 テストなどまた新しいノウハウが必要。

上記に加えて、ベンダーロックイン。

数年続くかわからないものか、数年で全書き換え(するくらいコストかけても問題ないくらいのところ)一回書いたら、そのまま、使い続けたいものには向かなそう。

Apache Beam in Debian で Word count

Apache Beamでword countしてみました。

なぜ Apache Beam なのか : Dataflow のライバル参入を促す理由 http://googlecloudplatform-japan.blogspot.jp/2016/05/apache-beam-dataflow.html

Cloud Dataflow の Python SDK がベータに http://googlecloudplatform-japan.blogspot.jp/2016/08/cloud-dataflow-python-sdk.html

Dataflow Quickstarts https://cloud.google.com/dataflow/docs/quickstarts/quickstart-java-maven?hl=ja

Apache Beam は、Google Cloud Dataflow をオープンソース化したプロジェクトです。

http://beam.incubator.apache.org/

ビッグデータ処理の最も抽象化の高い層に位置するフレームワークです。

ビックデータのバッチ処理とストリーミング処理双方をサポートし、 処理基盤としてApache Sparkなどを使えます。

また、Googleの各種ビッグデータ処理サービスと連携して機能します。

現在は、Apache incubator プロジェクトで、ドキュメントは必要最小限です。 また、日本語の資料も少ないのが現状です。

Mavenを日常的に使っていればすぐに試せますが、Hello worldがサクッとできるREADMEが用意されているわけではないので、まとめました。

環境について

今回は、Cloud Dataflow を処理基盤(Runner)に指定しました。 そのため、Dataflowジョブを実行するプロジェクト内に、GCEインスタンス、Storageの作業バケット/ディレクトリを作りました。

maven-3.3.Xをインストールする

apt-get install mavenでは、3.0.5など古いのが入ました。これだとBeamのビルドができません。

以下を参考に、最新のMavenをインストールします。

http://maven.apache.org/install.html http://maven.apache.org/download.cgi

$ curl -OL http://ftp.yz.yamagata-u.ac.jp/pub/network/apache/maven/maven-3/3.3.9/binaries/apache-maven-3.3.9-bin.zip
$ unzip apache-maven-3.3.9-bin.zip
$ sudo mv apache-maven-3.3.9 /opt
$ PATH=$PATH:/opt/apache-maven-3.3.9/bin
$ mvn -v

Maven3のはじめかた https://www.gitbook.com/book/kengotoda/what-is-maven/details

Beam のセットアップ

githubから取得して、実行してみます。

$ git clone https://github.com/apache/incubator-beam.git
$ cd incubator-beam
$ mvn test

Spark関連のテストでエラーが出てしまいました。 が、コンパイルは通っているようなので、一旦進めました。

 -------------------------------------------------------
   T E S T S
 -------------------------------------------------------
 Running org.apache.beam.runners.spark.EmptyInputTest

サンプルを動かす

example内にサンプルコードがあります。 ここにもpom.xmlが設定してあるので、必要な箇所を修正すれば、実際に動かすことができます。

GCP Dataflowをrunnerとして設定する

基本、コメント欄のコピペでいいのですが、以下のsetTempLocationが使えなくなっています。

    //   dataflowOptions.setTempLocation("gs://SET_YOUR_BUCKET_NAME_HERE/AND_TEMP_DIRECTORY");

setGcpTempLocationを使用します。

dataflowOptions.setGcpTempLocation("gs://SET_YOUR_BUCKET_NAME_HERE/AND_TEMP_DIRECTORY");

また、必要なライブラリをimportします。

+++ b/examples/java8/src/main/java/org/apache/beam/examples/MinimalWordCountJava8.java
@@ -28,6 +28,9 @@ import org.apache.beam.sdk.transforms.MapElements;
 import org.apache.beam.sdk.values.KV;
 import org.apache.beam.sdk.values.TypeDescriptors;

+import org.apache.beam.runners.dataflow.options.DataflowPipelineOptions;
+import org.apache.beam.runners.dataflow.BlockingDataflowRunner;
+

あとは、プロジェクトID, Storageのパスを設定します。

 import java.util.Arrays;

 /**
@@ -53,8 +56,14 @@ public class MinimalWordCountJava8 {
     // for more details.
     //   options.as(FlinkPipelineOptions.class)
     //      .setRunner(FlinkRunner.class);
+    DataflowPipelineOptions dataflowOptions = options.as(DataflowPipelineOptions.class);
+
+    dataflowOptions.setRunner(BlockingDataflowRunner.class);
+    dataflowOptions.setProject("project-id");
+    dataflowOptions.setGcpTempLocation("gs://");

-    Pipeline p = Pipeline.create(options);
+    Pipeline p = Pipeline.create(dataflowOptions);

     p.apply(TextIO.Read.from("gs://dataflow-samples/shakespeare/*"))
      .apply(FlatMapElements.via((String word) -> Arrays.asList(word.split("[^a-zA-Z']+")))
@@ -66,7 +75,7 @@ public class MinimalWordCountJava8 {
          .withOutputType(TypeDescriptors.strings()))

      // CHANGE 3/3: The Google Cloud Storage path is required for outputting the results to.
-     .apply(TextIO.Write.to("gs://YOUR_OUTPUT_BUCKET/AND_OUTPUT_PREFIX"));
+     .apply(TextIO.Write.to("gs://"));

     p.run();
   }

compileして確認します。

$ mvn compile

認証設定をする

JavaからCloud Storageにアクセスするために、認証情報を設定します。 まず実行してみます。

$ mvn exec:java -Dexec.mainClass=org.apache.beam.examples.MinimalWordCountJava8

認証がうまくいってないと、ERRORメッセージが出ます。解消方法の例も出るので、参考にします。

今回は、GCEのインスタンスからアクセスしたので、gcloudコマンドで認証をしました。

$ gcloud auth login

再度、上記コマンドで実行します。SUCCESSになったら、GCP上で結果を確認します。

  • Cloud Dataflowのジョブ一覧に出てきます。
  • アウトプットは、Storageにでます。

上記でうまくいかない場合は、GCP SDKの認証方法が幾つかあるので、この辺りが参考になりそうです。

Google Cloud Dataflowを試してみた http://qiita.com/harukasan/items/019da8a6e76b341f6c73

Mavenリポジトリにもあります

すでに、Mavenリポジトリに上がっているので、ライブラリはそのまま使うことも可能です。

https://mvnrepository.com/artifact/org.apache.beam

2016年8月6日土曜日

プロジェクトのドキュメントをgitで管理する

プロジェクトの文書管理は頭痛のタネですが、少しでもエンジニアらしく管理したいですね。

対象は、自社開発プロジェクトレベル、つまり、ドキュメント自体が商品になるわけではなく、あくまで補助ツールという位置付けの、手順、マニュアル、内部仕様などです。

Readmeに書く、コメントに入れる、ソースコード自体をわかりやすくする、などしても管理する必要があるドキュメントは0というわけにはいかないですよね。

試験的に、git+markdownで文書管理したことがあり、使いやすかったので、ドキュメントをgit+markdownに持って行けないか考えました。

以下参考記事

プロジェクトの文書管理といえば、この辺りがメジャーかと思います。

  • Excel(MS Office)
  • Trac/RedmineのWiki
  • GoogleDocsやEvernoteなどWebドキュメント系

業務がらみとなるとExcelが必須になることが多いですが、それ以外は、基本、使い慣れたgit+markdownにしたいです。

ポイントになりそうなところ

  • 扱うデータ
    • テキスト
    • 画像(イメージ・ベクター)
    • バイナリ
  • 作成
    • トピック(ページ)の新規作成しやすさ
    • 他のプロジェクト管理ツールとの連携
  • 更新
    • 履歴管理
    • ドキュメントの信頼性
    • 更新フロー

この中で、git+markdownが強いのは、更新回りです。 特に、複数人で、継続的に更新をかける場合、プルリクの仕組みがそのまま使えます。

TracなどのWikiに比べると、他のプロジェクト管理ツールとの連携は弱いですが、相互に直リンクを張る、Webhookでチャットへポストするなどのゆるい連携でも十分なイメージです。

逆に弱いのは、画像・バイナリの扱いですね。ここが解消すれば、かなりのドキュメントが移行できるのではないでしょうか。

以下、画像やバイナリを扱う参考記事。

2016年8月4日木曜日

Elixir 1.3 を OTP18指定でDebianにインストール

Elixir1.3 + OTP19 は、一部ライブラリがコンパイルできない問題があります。
早晩、対応されると思いますが2016年8月3日時点でちゃんと動くインストール方法です。

今回出たのは、これです。結局OTP19にElixirが対応してないので、示されてるコマンドでは復旧できなかったです。

** (Mix) Could not compile dependency :erlware_commons, "/home/YutakaNishimura/.mix/rebar3 bare compile --paths "/home/YutakaNishimura/scrape_exs2/_build/dev/lib/*/ebin"" command failed. You can recompile this dependency with "mix deps.compile erlware_commons", update it with "mix deps.update erlware_commons" or clean it with "mix deps.clean erlware_commons"

インストールのポイントは、ErlangのOTP18を先に入れておくことです。
公式の手順通りにいきなりElixirをインストールすると自動的にOTP19が入ってしまって、復旧に手間取ります。

Erlangのインストール

以下ライブラリが入ってないとインストールに失敗するので入れておきます。

$ sudo apt-get update
$ sudo apt-get install -y libwxbase3.0-dev libwxgtk3.0-dev

Erlang Solutionsのページから自分のプラットフォームにあったOTP18のdebを探します。

https://www.erlang-solutions.com/resources/download.html

$ wget https://packages.erlang-solutions.com/erlang/esl-erlang/FLAVOUR_1_general/esl-erlang_18.3.4-1~debian~jessie_amd64.deb && sudo dpkg -i esl-erlang_18.3.4-1*
$ # check
$ erl -v

Elixirのインストール

Erlang Solutionsのリポジトリを登録して、Elixirをインストールします。

$ wget https://packages.erlang-solutions.com/erlang-solutions_1.0_all.deb && sudo dpkg -i erlang-solutions_1.0_all.deb
$ sudo apt-get install -y elixir
$ # check
$ iex -v

トラブルした時のコマンド

dpkgとaptコマンドを駆使します。

$ # リスト 
$ dpkg -l | grep erlang
$ # 削除
$ dpkg -r ${pkg}
$ # パッケージ名検索 
$ apt-cache search ${pkg}
$ # 削除
$ apt-get remove ${pkg}

詳細はここ http://qiita.com/white_aspara25/items/723ae4ebf0bfefe2115c

Elixir で Sinatra 風なマイクロフレームワーク

新しい言語でシンプルなWeb APIを作りたいとき、とりあえず、言語名+Sinatraで検索することがあります。

Elixrだと、Phoenixを使うほどでもないと思うときですね。

簡単なスクリプトでも、Elixirでは基本サーバープロセスを立ち上げてというアーキテクチャになりやすいので、REST APIをインターフェースとして使えると便利です。

Plug

Elixir公式プロジェクトのPlugをそのまま組み合わせて使う方法です。 Phoenix内部で使っていますし、安心して使えます。

詳細はここ

https://elixirschool.com/jp/lessons/specifics/plug/

Trot

上のPlugを使って、MicroWebFrameworkに仕上げたプロジェクトです。 Plugは組み合わせなどを考えないとですが、こちらはFrameworkに従って書くだけなので気軽に使えます。

詳細はここ

http://qiita.com/techno-tanoC/items/23e5d3d6ed54e0e23156

2016年8月3日水曜日

tensorflow を Debian にインストール

tensorflowをインストールしました。

tensorflowは、Googleが作った機械学習ライブラリです。ティープラーニングに強いことで有名です。

いつもながら、Ubuntuの記事はよく出てきますが、Debianは出てきません。 Debianでも動作することを確認しました。

とりあえずインストール

Ubuntuにとあるが、debianでも問題ない
http://qiita.com/yudsuzuk/items/092c38fee18e4484ece9

virtualenvを使った場合
http://blog.btrax.com/jp/2015/11/29/tensorflow/

virtualenvの使い方
http://www.lifewithpython.com/2013/08/virtualenv.html

SSLエラーが出たとき

Google Cloud Platform の インスタンスからアクセスしたら、以下が出ました。

SSLError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:581)

以下、SSLエラーを出さないコマンド(--trusted-hostを追加)です

(tensorflow) % pip install --upgrade https://storage.googleapis.com/tensorflow/linux/cpu/tensorflow-0.5.0-cp27-none-linux_x86_64.whl --trusted-host storage.googleapis.com

よい tensorflow life を!