失敗編からの続きです。
前提
こんな人には役に立つかもしれない
- Ethreumを使ってガシガシ開発したいから、開発に使えるEthreumノードが必要。
- どこかのVPSにノードを立ち上げたりInfura.ioのtestnetを使えばよいのだけど、立ち上げは手軽じゃないし、まだ開発中だからtestnetじゃなくてやプライベートでやりたい、そして、Wifiがなくても開発機内で完結したい、という欲求がある。
- docker-composeを使いたい。
- コンテナを終了してもチェーンDATAは残したい(永続化したい)。次にコンテナを立ち上げたときには次のブロックからマイニングが始まるようにしたい。
そんな需要があったので頑張ってやってみました。
当初戦略
- gethは公式のDockerイメージを使う。
- Dockerfile内でgethのinitやテストアカウントのimportをする。
- chain_dataはホスト内に保存されるようにマウントする。
- コンテナを立ち上げるときにプライベートネットのnetworkIdを引数で渡す
困ったこと
- マウント無しでDockerfile, docker-compose.ymlを以下のようにするとすんなりとプライベートネットが立ち上がるが、永続化されていないので、一旦コンテナを削除すると、ジェネシスブロックからの作り直しになってしまう。
- data_dirをマウントして立ち上げると、今度はnetworkIdが1(つまりmainnet)になってしまう。
マウントするとmainnetになってしまう原因
- buildのイメージ内にプライベートネットのジェネシスブロックが生成されていても、ホストのディレクトリをマウントした時点で消えてしまう
- そうするとコンテナ立ち上げのときにgethの引数でdatadirとnetworkIdを指定しても、ジェネシスブロックが存在しないので、デフォルトでmainnetとなるようになっている。
解決手順
マウント=>ジェネシスブロック生成(geth init)=>geth立ち上げ という順序にすることは不可能なので以下のような手順をふむようにした。
- まずは、ジェネシスブロック生成用のコンテナを立ち上げる(geth_initコンテナ)
- ホストの
./geth_data
にgeth_initコンテナの/tmp
(空)をマウントする - geth_initコンテナに生成されたdatadirを
/tmp
に同期するとホストの./geth_data
にチェーンデータができる。 マイニング用のgethコンテナを先程の
./geth_data
をマウントして立ち上げる。プライベートネットのnetworkIdとマウントされたディレクトリをdatadireとして引数を与えてれば、gethコンテナのgethはそこを参照して、プライベートネットが立ち上がる。
gethコンテナを終了しても、生成されたブロックはホストの
./geth_data
に残っている。再びgethコンテナを立ち上げると、既存のチェーンデータが参照され、続きからマイニングされる。
コマンド
$ git clone https://github.com/imaichel/ethereum-docker.git
$ cd ethereum-docker/standalone/
$ docker build -f geth/Dockerfile_gethinit -t gethinit:1.0.0 geth
~略~
Successfully built f524701f5b3a
Successfully tagged gethinit:1.0.0
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
gethinit 1.0.0 f524701f5b3a About a minute ago 48.1MB
$ mkdir volume
$ docker run -d -v $PWD/volume:/tmp --name gethinit gethinit:1.0.0 --networkid 1234 --datadir=/root/.ethereum
$ docker exec -it gethinit /bin/bash
# rsync -av /root/.ethereum /tmp/
# exit
$ docker-compose up -d --build
$ docker-compose logs -f