ganache-cliを利用して、docker内にローカルネットを立ち上げてみる

木内智史之介(シャッチョー)
ミンカさんけっこんしてくださいおねがいします(ズザー SEGAさん、DIVAの筐体ください(ズザー

先日の記事では、Ganacheを利用して、イーサリアムのローカルネット構築を行いました。
それは、大変優れた、素晴らしいものだったんですが、残された最後の一つの欲求がありまして…。

そう。私、ローカルネットワークをDockerコンテナ内に閉じ込めたいんです…!
別プロジェクトの内容が、同じ開発環境に積まれるのが嫌なんです…!

という訳で、今回は、Dockerコンテナ内で完結するローカルネットの構築をおこないたいと思います。

ついでにと言うかなんて言うかですが、通常起動だとganacheはデータを永続化しない(次回起動時には、デプロイしたデータが飛んでる)ので、永続化もしてしまいましょう。

ganache-cliを使ってみる

Truffleチームが公開しているリポジトリの中に ganache-cliというものがあります。

これ、わりと最初から存在には気づいていたんですが、「cli」という名前が付いていたので、 ローカルネットを立ち上げて待ち構える「server」系のプロダクトではないように感じてしまったんですね。

なので、あまりよく見ないで敬遠していたんですが、よく見てみると、ethereumjs-testrpcが名前を変えたものだったんですね。

こいつが使えそうです。

docker系の諸々を整える

まずは、ganache-cliのDockerfileから。

docker/ganache/Dockerfile
FROM node:8-alpine
RUN npm install -g ganache-cli
RUN mkdir -p /var/ganache
ENV DOCKER true
ENV DATADIR /var/ganache
# データを永続化する場合、次回以降も同じmnemonicとnetworkIdで立ち上げる必要性があります
# https://github.com/trufflesuite/ganache-cli/issues/407
ENV MNEMONIC pillows andymori al tomoyuki spitz abc quruli whoops fukurouz air bluehearts highlows
ENV NETWORKID 5777
EXPOSE 8545
ENTRYPOINT ["sh", "-c", "ganache-cli --host=0.0.0.0 --db=${DATADIR} --mnemonic=\"${MNEMONIC}\" --networkId=${NETWORKID}"]

これ、もしかしたら ENV DOCKER true さえあれば、 --host=0.0.0.0 の指定は不要かもです。
また、上記にコメントで記載していますが、データを永続化したい場合、mnemonicとnetworkIdの指定が必須になります。

services:
truffle:
image: 8823scholar/truffle
working_dir: /app
volumes:
- ./src:/app:cached
depends_on:
- ganache
ganache:
# 例によって、上記のDockerfileをDockerHubに上げているので下記のように書けます
image: 8823scholar/ganache
#build: ./docker/ganache
volumes:
- ganache-data:/var/ganache
volumes:
ganache-data:

ganache-cliの方は /var/ganache にデータを永続化するようにして立ち上げているので、ボリュームを割り当て、再度dockerを立ち上げてもブロックチェーンを引き継げるようにします。

docker-composeで立ち上げる

docker-composeでコンテナを立ち上げてみると、非常にそれらしい出力を確認できました…!

$ docker-compose up
ganache_1 | Ganache CLI v6.1.6 (ganache-core: 2.1.5)
ganache_1 |
ganache_1 | Available Accounts
ganache_1 | ==================
ganache_1 | (0) 0x60956241cca6c196565b49a623d9fc3398eeb3db (~100 ETH)
ganache_1 | (1) 0xcf14b514dc3f9ca5a23675f1a61ef1542e43b0a1 (~100 ETH)
ganache_1 | (2) 0x3842c4534b3c7c77e647bffc8fbca03510c87759 (~100 ETH)
ganache_1 | (3) 0x7964fcb002932afb33fba1b7a614f13820515e3e (~100 ETH)
ganache_1 | (4) 0x387a8ed24858d8543f522e30e8ad04fec1e1a30b (~100 ETH)
ganache_1 | (5) 0xfd27fcea4168c0a07f57d071671490074d888f85 (~100 ETH)
ganache_1 | (6) 0xe4cb4662d1cc859e8ec2c6d057f442c7d86d677e (~100 ETH)
ganache_1 | (7) 0x6e3b53b8cc856eb59a790582378f34ea1b347b63 (~100 ETH)
ganache_1 | (8) 0xb3b0422f924ebe03396ea65f569ac672728c7b05 (~100 ETH)
ganache_1 | (9) 0x645406a8ce4f3682a2cdd5d64215793c23b086e5 (~100 ETH)
ganache_1 |
ganache_1 | Private Keys
ganache_1 | ==================
ganache_1 | (0) 0xf05af3ab62b247ce69e920a6fcb4cc71c4065e27a692e6d724582dc32c50e561
ganache_1 | (1) 0x8661df7baf4bf5a846cc91237493f6b68c0fc6511c1da42bdc582ff15a01ba34
ganache_1 | (2) 0xc5481db137a40521f71d95971974cd8eec30831b74d414e66434cecd4020b253
ganache_1 | (3) 0x799aea602f767aa6b62cbfa07682009c07b96249be1df42f69881cf01820055d
ganache_1 | (4) 0x4c3278b622025900ee44f1a0ce3e951f11f3cb584b3832c52855baccd64c8a4e
ganache_1 | (5) 0x07201c4ab5d9e1005f40f2899cf69d7ce9e9487af070649ea3b30545a2871802
ganache_1 | (6) 0x10f4eb60e48ab6daf442f8467f285c819bba738ae55bf4e1a21d010261635202
ganache_1 | (7) 0x9857e1bfae25237e582121278d7132d97947335cb416cbc2e1ff5c308076477d
ganache_1 | (8) 0x1986bf7d2081c7e73f7e965bdb390f6e465bd736dcb09c2f140086940892e8aa
ganache_1 | (9) 0xd736e9ccea5e1f11734853d486c099b6e3ef3564c122a1e616e3a91ed21e004b
ganache_1 |
ganache_1 | HD Wallet
ganache_1 | ==================
ganache_1 | Mnemonic: pillows andymori al tomoyuki spitz abc quruli whoops fukurouz air bluehearts highlows
ganache_1 | Base HD Path: m/44'/60'/0'/0/{account_index}
ganache_1 |
ganache_1 | Gas Price
ganache_1 | ==================
ganache_1 | 20000000000
ganache_1 |
ganache_1 | Gas Limit
ganache_1 | ==================
ganache_1 | 6721975
ganache_1 |
ganache_1 | Listening on 0.0.0.0:8545

truffleから接続してみる

他コンテナで起動しているtruffleから接続できるか確認してみます。

truffle.jsの修正

ネットワークの設定をいじる必要性があります。
truffleも、ganacheも、共にdockerコンテナで立ち上がるので、ホストの参照を変えなくてはなりません。

src/truffle.js
module.exports = {
networks: {
development: {
host: "ganache", // docker-composeでは、サービス名がそのままホスト名になる
port: 8545, // ganache-cliはデフォルトで8545で待ち受ける
network_id: "*",
},
},
};

consoleで接続可能か確認

$ docker-compose run truffle console
Starting solidity-test_ganache_1 ... done
truffle(development)>

おお。できてるっぽい。
もし、接続できない場合は、この時点でエラーになるので、ここまで表示されれば接続は完璧です。

デプロイしてみる

では、デプロイしてみましょう…!ドキドキ。

$ docker-compose run truffle migrate
Starting solidity-test_ganache_1 ... done
Using network 'development'.
Running migration: 1_initial_migration.js
Deploying Migrations...
... 0x6c8cc3ee504a173880f2272e0f7900a9028f48131ac745d454ac1a8485b4c0b3
Migrations: 0x808253c9562a2919a2d4cd362f11a1ffa7998531
Saving successful migration to network...
... 0x720c970a2cad3dc4aa24eab9a6671571208cd55f97eaa409fa9d868fa9cdce6f
Saving artifacts...
Running migration: 1533839889_hello_world.js
Deploying HelloWorld...
... 0x6ef5ebe76adfc1a90447bce15d31426db2ec28bf2987f961a634492d2313ce08
HelloWorld: 0xd4eb19f1ce0036093d47dbf511a6fec09817ec87
Saving successful migration to network...
... 0xc6f60bd60eba04310f18909012a4c05927c45f4e43da3ca417b45766479b1e85
Saving artifacts...

できたっぽい?
念のため、一度docker-composeを落とし、再度立ち上げて、再実行してみます。

$ docker-compose down
$ docker-compose run truffle migrate
Starting solidity-test_ganache_1 ... done
Using network 'development'.
Network up to date.

ganacheを再起動してもデータが残ってるっぽいですね!完璧です。