관리 메뉴

멍개의 연구소

[ethereum] docker를 활용한 이더리움 네트워크 구축 - 1편 본문

블록체인

[ethereum] docker를 활용한 이더리움 네트워크 구축 - 1편

멍개. 2022. 8. 27. 15:31

docker를 활용하여 geth를 설치하고 이더리움 네트워크를 구축하는 방법에 대해서 알아보겠습니다. 오랜만에 도커를 다뤄서 그런지 하루종일 엄청난 삽질을 했네요 ㅠㅠ

도커를 사용하여 환경설정을 자동화 하기 위해서는 Dockerfile과 docker-compose.yml을 이용하면 간단하게 구축할 수 있습니다. 

해당 글에서 도커를 설치하는 과정은 생략하고 진행합니다

● 디렉토리 구조

multi-ethereum-network
├── go-ethereum/
├── docker-compose.yml
├── Dockerfile
├── genesis.json
└── start.sh

genesis.json파일과 go-ethereum 디렉터리는 도커로 생성되는 컨테이너 안에다가 copy로 옮깁니다.

· go-ethereum 설치

$ git clone https://github.com/ethereum/go-ethereum

go-ethereum은 git에서 clone하여 받아주기만 하면 됩니다. 

· genesis.json 작성하기

초기블록 정보를 가지고 있는 genesis.json 파일을 작성합니다.

{
    "nonce" : "0x0000000000000042",
    "timestamp" : "0x0",
    "parentHash" : "0000000000000000000000000000000000000000000000000000000000000000",
    "extraData" : "0x0",
    "gasLimit" : "0x80000000",
    "difficulty" : "0x4000",
    "mixhash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
    "coinbase" : "0x3333333333333333333333333333333333333333",
    "alloc" : {}
}

각 수치는 바뀌어도 됩니다.

· Dockerfile 작성하기

Dockerfile을 이미지를 만들기 위해 사용하는 파일입니다. Dockerfile에는 ubuntu를 설치하고 호스트 OS에 있는 genesis.json과 go-ethereum을 옮긴후 geth를 make합니다. 그리고 genesis.json을 이용하여 초기블록을 생성하는 작업을 합니다.

FROM ubuntu

COPY ./go-ethereum /home/go-ethereum
WORKDIR /home/go-ethereum/

RUN apt-get update
RUN apt-get install -y build-essential libgmp3-dev golang git

RUN git checkout refs/tags/v1.5.5
RUN make geth
RUN cp build/bin/geth /usr/local/bin/

WORKDIR /home/DATA_STORE/
COPY ./genesis.json /home/DATA_STORE

RUN geth --datadir "/home/DATA_STORE" init /home/DATA_STORE/genesis.json

- from ubuntu는 ubuntu를 사용하게 됩니다.

- COPY는 호스트OS에서 생성할 이미지로 복사하는 것을 의미합니다. 해당 디렉토리에 있는 go-ethereum을 생성하는 이미지의 /home/go-ethereum으로 복사하는 것을 의미합니다.

- WORKDIR은 작업 디렉토리를 의미합니다.

- RUN은 bash에서 실행되는 명령어를 의미합니다.

해당 파일은 우분투에 geth에 필요한 것들을 옮긴 후 genesis 블록을 생성한 후 이미지 파일을 만들어 줍니다. 

· Dockerfile로 이미지 파일 생성

$ docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
ubuntu              latest              f975c5035748        3 weeks ago         112MB

build를 이용하여 이미지 파일을 만들어 줍니다. -t 옵션은 이미지 이름을 의미합니다.

마지막에 마침표(.)는 반드시 넣어줄 것! 없으면 에러가 발생합니다.

해당 명령어를 실행하면 Dockerfile에 적힌 명령어들을 실행하면서 이미지를 만들어 줍니다.

 
$ docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
ethereum            latest              445670501b8f        22 seconds ago      1.22GB
ubuntu              latest              f975c5035748        3 weeks ago         112MB

ethereum이 추가 됬습니다. 해당 이미지를 이용하여 컨테이너를 생성해보겠습니다.

· 컨테이너 생성해보기

run을 이용하면 이미지를 컨테이너로 생성할 수 있습니다.

$ docker run -it -p 8545:8545 ethereum bash
$ root@2bda185d1d5d:/home/DATA_STORE# ls
genesis.json  geth  keystore

ps를 활용하여 실행되고 있는 컨테이너를 확인할 수 있습니다.

$ docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS                    NAMES
2bda185d1d5d        ethereum            "bash"              29 seconds ago      Up 28 seconds       0.0.0.0:8545->8545/tcp   naughty_fermat​

컨테이너를 생성할 때마다 옵션을 다 작성하는 건 상당히 비효율 적입니다. docker-compose.yml을 이용하면 컨테이너를 생성하는 과정을 자동화 할 수 있습니다.

· docker-compose.yml을 이용한 자동화

version: '2'

services:
    ether.node1.com:
        image: 'ethereum'
        tty: true
        ports:
            - 8545:8545
            - 30305:30305
        environment:
            ENV: ETHERNODE1
            RPCPORT: 8545
            PORT: 30305
        container_name: ether.node1.com
        command :  geth --networkid 4649 --maxpeers 3 --datadir /home/DATA_STORE --rpc --rpcport 8545 --rpcaddr "0.0.0.0" --rpccorsdomain "*" --rpcapi "admin,db,eth,debug,miner,net,shh,txpool,personal,web3" --port 30305
        working_dir: /home/DATA_STORE

services안에는 생성할 컨테이너 정보가 들어갑니다.

ether.node1.com이름을 가진 컨테이너를 생성한 후 컨테이저 정보를 그 아래에 포함합니다.

image는 어떤 이미지를 이용하여 컨테이너를 생성할지에 대한 정보입니다. ethereum을 로컬에서 이미지를 찾은 후 없다면 docker hub에서 찾습니다. 
tty는 해당 컨테이너에서 인터프리터를 제공할지 말지에 대한 옵션입니다.
ports는 포워딩을 의미합니다. 도커는 따로 아이피를 할당받거나 하지 않습니다. 호스트 OS를 공유하기 때문에 호스트 OS로 접속된 포트번호에 따라서 해당 컨테이너로 포워딩을 해야합니다.
environment는 환경설정 값 입니다. 
container_name은 컨테이너 이름입니다.
command는 해당 컨테이너가 생성되고 실행할 명령어를 입력합니다.
working_dir은 작업 디렉토리를 설정합니다

· docker-compose.yml 실행

$ docker-compose up -d
 
-d 옵션을 주어서 백그라운드로 실행할 수 있습니다.
$ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                                              NAMES
e8a46276465f        ethereum            "geth --networkid ..."   12 seconds ago      Up 9 seconds        0.0.0.0:8545->8545/tcp, 0.0.0.0:30305->30305/tcp   ether.node1.com

docker-compose.yml에서 service만 추가하면 매우 간편하게 여러 노드를 생성할 수 있습니다.

version: '2'

services:
    ether.node1.com:
        image: 'ethereum'
        tty: true
        ports:
            - 8545:8545
            - 30305:30305
        environment:
            ENV: ETHERNODE1
            RPCPORT: 8545
            PORT: 30305
        container_name: ether.node1.com
        command :  geth --networkid 4649 --maxpeers 3 --datadir /home/DATA_STORE --rpc --rpcport 8545 --rpcaddr "0.0.0.0" --rpccorsdomain "*" --rpcapi "admin,db,eth,debug,miner,net,shh,txpool,personal,web3" --port 30305
        working_dir: /home/DATA_STORE

    ether.node2.com:
        image: 'ethereum'
        tty: true
        ports:
            - 8546:8546
            - 30306:30306
        environment:
            ENV: ETHERNODE2
            RPCPORT: 8546
            PORT: 30306
        container_name: ether.node2.com
        command :  geth --networkid 4649 --maxpeers 3 --datadir /home/DATA_STORE --rpc --rpcport 8546 --rpcaddr "0.0.0.0" --rpccorsdomain "*" --rpcapi "admin,db,eth,debug,miner,net,shh,txpool,personal,web3" --port 30306
        working_dir: /home/DATA_STORE

    ether.node3.com:
        image: 'ethereum'
        tty: true
        ports:
            - 8547:8547
            - 30307:30307
        environment:
            ENV: ETHERNODE3
            RPCPORT: 8547
            PORT: 30307
        container_name: ether.node3.com
        command :  geth --networkid 4649 --maxpeers 3 --datadir /home/DATA_STORE --rpc --rpcport 8547 --rpcaddr "0.0.0.0" --rpccorsdomain "*" --rpcapi "admin,db,eth,debug,miner,net,shh,txpool,personal,web3" --port 30307
        working_dir: /home/DATA_STORE
$ docker-compose up -d
Creating ether.node2.com ... 
Creating ether.node3.com ... 
Creating ether.node1.com ... 
Creating ether.node2.com
Creating ether.node3.com
Creating ether.node3.com ... done

$ docker ps 
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                                              NAMES
59c167bf69ea        ethereum            "geth --networkid ..."   12 seconds ago      Up 10 seconds       0.0.0.0:8546->8546/tcp, 0.0.0.0:30306->30306/tcp   ether.node2.com
ba0df13e0343        ethereum            "geth --networkid ..."   12 seconds ago      Up 9 seconds        0.0.0.0:8545->8545/tcp, 0.0.0.0:30305->30305/tcp   ether.node1.com
6970e60e5a75        ethereum            "geth --networkid ..."   12 seconds ago      Up 9 seconds        0.0.0.0:8547->8547/tcp, 0.0.0.0:30307->30307/tcp   ether.node3.com

3개의 이더리움 네트워크가 생성되었습니다. 

· geth 직접실행

version: '2'

services:
    ether.node1.com:
        image: 'ethereum'
        tty: true
        ports:
            - 8545:8545
            - 30305:30305
        environment:
            ENV: ETHERNODE1
            RPCPORT: 8545
            PORT: 30305
        container_name: ether.node1.com
        command :  /bin/bash
        working_dir: /home/DATA_STORE

command를 /bin/bash로 바꾼 후 docker-compose를 실행하면 다음과 같이 컨테이너가 생성됩니다.

$ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                                              NAMES
78da5358a511        ethereum            "/bin/bash"              8 seconds ago       Up 8 seconds        0.0.0.0:8545->8545/tcp, 0.0.0.0:30305->30305/tcp   ether.node1.com

해당 컨테이너를 접속하여 직접 다뤄보도록 하겠습니다.

$ docker exec -it ether.node1.com /bin/bash
root@78da5358a511:/home/DATA_STORE#

exec를 이용하여 실행중인 컨테이너를 직접 명령어를 줄 수 있습니다. -it는 인터프리터 형태로 사용하겠다는 의미이고 NAMES가 ether.node1.com을 찾은 후 /bin/bash를 실행합니다. 

root@78da5358a511:/home/DATA_STORE# echo $RPCPORT $PORT
8545 30305

docker-compose 파일에 environment로 설정한 환경변수가 잘 설정되어 있습니다.

root@78da5358a511:/home/DATA_STORE# geth --networkid 4649 --maxpeers 3 --datadir /home/DATA_STORE --rpc --rpcport $RPCPORT --rpcaddr "0.0.0.0" --rpccorsdomain "*" --rpcapi "admin,db,eth,debug,miner,net,shh,txpool,personal,web3" --port $PORT console

I0401 12:38:16.672852 cmd/utils/flags.go:615] WARNING: No etherbase set and no accounts found as default
I0401 12:38:16.673008 ethdb/database.go:83] Allotted 128MB cache and 1024 file handles to /home/DATA_STORE/geth/chaindata
I0401 12:38:16.721313 ethdb/database.go:176] closed db:/home/DATA_STORE/geth/chaindata
I0401 12:38:16.722546 node/node.go:176] instance: Geth/v1.5.5-stable-ff07d548/linux/go1.6.2
I0401 12:38:16.722596 ethdb/database.go:83] Allotted 128MB cache and 1024 file handles to /home/DATA_STORE/geth/chaindata
I0401 12:38:16.752408 eth/backend.go:191] Protocol Versions: [63 62], Network Id: 4649
I0401 12:38:16.754436 eth/backend.go:219] Chain config: {ChainID: 0 Homestead: <nil> DAO: <nil> DAOSupport: false EIP150: <nil> EIP155: <nil> EIP158: <nil>}
I0401 12:38:16.755875 core/blockchain.go:219] Last header: #0 [04d8be6f…] TD=16384
I0401 12:38:16.756043 core/blockchain.go:220] Last block: #0 [04d8be6f…] TD=16384
I0401 12:38:16.756150 core/blockchain.go:221] Fast block: #0 [04d8be6f…] TD=16384
I0401 12:38:16.758519 p2p/server.go:342] Starting Server
I0401 12:38:18.909806 p2p/discover/udp.go:227] Listening, enode://e90665a79192eef1c2f9de32b6527b7dd8130d636fe50ed5f3cf4593a5a07b977adb73e367a715c3b48e4239c697ecfb3c487db1d076af044a2bcb0d81b8cd32@[::]:30305
I0401 12:38:18.911419 node/node.go:411] HTTP endpoint opened: http://0.0.0.0:8888
I0401 12:38:18.925522 p2p/server.go:610] Listening on [::]:30305
I0401 12:38:18.928201 node/node.go:341] IPC endpoint opened: /home/DATA_STORE/geth.ipc
Welcome to the Geth JavaScript console!

instance: Geth/v1.5.5-stable-ff07d548/linux/go1.6.2
 modules: admin:1.0 debug:1.0 eth:1.0 miner:1.0 net:1.0 personal:1.0 rpc:1.0 txpool:1.0 web3:1.0

>

컨테이너를 생성할 때 추가한 환경변수를 이용하여 RPCPORT와 PORT를 설정해주었습니다.

· 컨테이너 중지/삭제

컨테이너를 중지하거나 삭제할 수 있습니다.

$ docker stop [컨테이너 ID 또는 컨테이너 이름]
$ docker rm [컨테이너 ID 또는 컨테이너 이름]

rm을 하기위해서는 컨테이너가 동작중이면 안됩니다.

$ docker ps  # docker ps -a

  ps 옵션은 동작중인 컨테이너를 보여줍니다. 여기에 -a를 추가하면 모든 컨테이너를 보여주게 됩니다.

docker-compose를 이용하여 컨테이너를 생성하면 다수의 컨테이너를 동시에 실행시키게 됩니다. 모든 컨테이너를 다 중지하고 삭제하고 싶다면 다음과 같이 실행하면 됩니다.

$ docker stop $(docker ps -qa)
$ docker rm $(docker ps -qa)

이렇게 하면 모든 컨테이너를 중지하고 제거하게 됩니다.

docker-compose를 사용할 때 중요한 점은 image가 반드시 설치되어 있거나 docker hub에 존재해야 합니다. 하지만 ethereum 이미지는 도커 허브에 제공되지 않기 때문에 앞에서 Dockerfile로 반드시 추가를 해주어야 합니다. 

다음번에는 geth 사용법을 다뤄보고 다수의 노드를 서로 연결하여 마이닝 경쟁을 하여 그럴듯한 private한 환경의 이더리움 네트워크를 만들어 보겠습니다.

Comments