どうも、こんにちは。 Ginco CTOの森下(@guiltymorishita)です。
今回は、【Ginco Engineer Meetup】Firebaseを使ったモダンなブロックチェーンアプリ開発の裏側で話した内容の解説と補足の記事になります。
発表では Ginco におけるKubernetesを使ったブロックチェーンノードの運用方法を環境構築について話しました。
発表資料はこちらです。
Kubernetesとは
Kubernetes(クーベネティス/クーベルネイテス、よくK8sと略記される)は、コンテナ化したアプリケーションのデプロイ、スケーリング、および管理を行うための、オープンソースのコンテナオーケストレーションシステムである。元々Googleが設計したシステムであるが、現在はCloud Native Computing Foundation(英語版)がメンテナンスを行っている。Kubernetesの目的は、「ホストのクラスターを横断してアプリケーションコンテナを自動デプロイ、スケーリング、操作するためのプラットフォーム」を提供することとされている。Dockerを含む多数のコンテナツールと連携して動作する。[1]
Kubernetesの主な機能としては以下が挙げられます。
Kuberntesについて解説されている記事はたくさんありますので詳細はこの記事では省略しますが、詳しくは公式ドキュメントなどをご参照ください。
GincoでのKubernetesのアーキテクチャ
GincoではGoogle Kubernetes Serviceを使ってKubernetesを運用しています。 ブロックチェーンノードのイメージはContainer RegistoryにPushしてKubernetesからPullする一般的なアーキテクチャです。
5つの開発環境
さらに、Gincoでは5つ開発環境をKubernetesのクラスタで分けて構築しています。
それぞれ、NodeTest
, Develop
, QA
, Staging
, Production
です。
これらについて説明していきます。
NodeTest環境
NodeTest環境はサンドボックス的な環境です。新しいブロックチェーンの開発はこの環境にノードを立てるところから始まります。 主に、Podのサイズやブロックチェーンノードのパラメータの調整、APIの挙動の確認などを行います。 APIのエンドポイントはパブリックになっており、インターン生でもすぐに試せるようになっています。
Develop環境
Gincoのアプリ開発はこの環境で行います。ブロックチェーンノードはすべてTestnetに設定しています。 この環境ではNodeTest環境での設定がクライアントアプリと組み合わせたときに正常に動作するかを確かめます。 Develop以降の環境はノードのエンドポイントはすべてPrivateになっています。
QA環境
ある程度の開発ができたらQAエンジニアがこの環境でQAをします。 ブロックチェーンノードはすべてTestnetに設定しています。 想定した仕様通りに動いているかを検証端末でテストします。
Staging環境
QAでのテストが通ったらこの環境で更にテストします。 この環境のブロックチェーンノードはすべてLivenetに設定しています。 検証するのに実際の仮想通貨を消費するので気をつけなければならない。
Production環境
Stagingでのテストが通ったらこの環境へマージします。 当然ですがブロックチェーンノードはすべてLivenetに設定しています。
QA環境とStaging環境がある理由
この2つはほぼ同じ環境で、違う点はブロックチェーンネットワークがTestnetかLivenetかだけです。 Bitcoinのように、ブロックチェーンの中にはTestnetとLivenetの仕様が違うものも存在しており、Testnetでテストが通ったからと言ってそのままLivenetでうまくいくとは限りません。 したがって、ネットワークだけが違う環境を用意して実際に試して見る必要があるというわけです。
この仕様の違いというのはドキュメントに書いてあったりなかったりするので非常に厄介です。 しかし、実際動かしてみて「何故かうまくいかない!」というところから、仕様の違いを発見して、さらにその仕様が違う理由までわかるとかなり理解できます。 こういったところがブロックチェーン開発の面白さかもしれません。
Kubernetesでの設定
Kubernetesを使うと上で述べた5つの環境が定義された設定ファイルから自動的に構築できるので非常に便利です。
ここではGincoが使用しているGethの deployment.yaml
と service.yaml
の例を以下に示します。
これを使えばとりあえずGethがKubernetes上に立てることができ、RPCを叩けるようになります。
しかし、永続ボリュームを割り当ててないのでこのままではPodが再起動するたびにデータの同期が毎回起こってしまいます。
したがって、実際にはコメントアウトした部分を使って永続ボリュームのマウントが必要になります。
これについてはKubernetesを運用しているプラットフォームによって設定が違うのでそちらのドキュメントをご参照ください。
あくまで例なので実際にこの設定を使っているわけではありません。セキュリティ面は考慮していませんので本番環境で使う場合はよく考えてから使ってください。
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: geth
labels:
app: geth
spec:
replicas: 1
selector:
matchLabels:
app: geth
template:
metadata:
labels:
app: geth
spec:
containers:
- name: geth
image: ethereum/client-go:v1.8.17
args:
- "--testnet"
- "--syncmode=fast"
- "--rpc"
- "--rpcaddr=0.0.0.0"
- "--rpcapi=web3,eth,net,personal,debug"
- "--rpccorsdomain=*"
ports:
- containerPort: 8545
name: rpc
resources:
limits:
cpu: 8
memory: 64Gi
requests:
cpu: 8
memory: 64Gi
# volumeMounts:
# - name: geth-data
# mountPath: /root/.ethereum
readinessProbe:
httpGet:
path: /
port: 8545
initialDelaySeconds: 15
timeoutSeconds: 5
# データを永続化させる場合はボリュームを割り当てる
# volumes:
# - name: geth-data
---
apiVersion: v1
kind: Service
metadata:
name: geth
spec:
type: LoadBalancer
# loadBalancerIP: xxx.xxx.xxx.xxx
ports:
- name: rpc
port: 8545
targetPort: 8545
selector:
app: geth
モニタリング
GincoではGKEを使っているので、モニタリングはすべてStackdriverで行っています。GKEであればすべてGUIでの設定だけでインテグレーションできるので非常に便利です。 リソースのメトリクスはStackdriver Monitoringで行っています。
ブロックチェーンノードから出力されるログに関してもStackdriver Loggingを使用して収集しています。 標準出力を自動的に収集してくれて、クエリを書けられる状態になります。 さらにそれに対してアラートを設定することもできるので同期が止まったなどの通知ができて非常に便利です。
Kubernetesでノード運用したときの欠点
ノードのオートスケールを試みた際に、StatefulSetで定義すると新しいPodに対して空のディスクが割り当てられてしまうので、初めてできるPodは毎回同期が必要になってしまう。 ブロックチェーンノードは基本的に同期に非常に長い時間がかかるため、これでは使い物にならない。 StatefulSetのPVCでGCEのディスクスナップショットを指定することができれば、同期の時間を一気に短縮できるのでこの機能がつかないかな〜って思ってます。 もしすでにあったり、他の方法で実現できるようなら教えていただきたいです!
まとめ
本記事では、Ginco での Kubernetesを利用したブロックチェーンノード運用について解説しました。 Kubernetesは概念の理解が難しくとっつきづらいものではありますが、使えるようになると非常に簡単にアプリケーションをデプロイしたりアップデートしたりすることができるので触ってみる価値はあると思います。 また、ブロックチェーンノードのように設定のパラメータが多いようなものに関しては設定ファイルをGitで管理できるので相性が良いのではないでしょうか。
Tip us!
エンジニアチームがブログを書くモチベーションが上がります!