멀티 노드 배포

이 문서는 멀티 노드 셋업에서 loom을 구동하는 방법에 대해서 설명합니다.

설치하기

이 단계는 각 노드에서 실행되어야 합니다.

  1. 여러분만의 작업 디렉토리를 선택하세요. 이 예제에서는 다음을 사용합니다 /home/ubuntu

    cd /home/ubuntu
    
  2. 바이너리를 다운로드하세요:

    curl https://raw.githubusercontent.com/loomnetwork/loom-sdk-documentation/master/scripts/get_loom.sh | sh
    
  3. 설정 파일을 초기화하기 위해서 작업 디렉토리에서 ./loom init을 실행하세요.

  4. 작업 디렉토리에 loom.yml 파일을 추가하세요

    DPOSVersion: 3
    

구성하기

두 개의 genesis.json 파일을 결합 할 필요가 있습니다.

genesis.json #1 - 작업디렉토리에 있는

The genesis.json that was generated should look something like below. You should NOT copy the file below as it is an example. Use the file generated in your working directory.

{
  "contracts": [
    {
      "vm": "plugin",
      "format": "plugin",
      "name": "coin",
      "location": "coin:1.0.0",
      "init": null
    },
    {
      "vm": "plugin",
      "format": "plugin",
      "name": "dposV3",
      "location": "dposV3:3.0.0",
      "init": {
        "params": {
          "validatorCount": "21"
        },
        "validators": [
          {
            "pubKey": "2MysikRZ8Yzk3KPDVEl/g2tHSyX0i3DGrAMwtDcYH10=",
            "power": "10"
          }
        ]
      }
    },
    {
      "vm": "plugin",
      "format": "plugin",
      "name": "addressmapper",
      "location": "addressmapper:0.1.0",
      "init": null
    },
    {
      "vm": "plugin",
      "format": "plugin",
      "name": "chainconfig",
      "location": "chainconfig:1.0.0",
      "init": {
        "owner": {
          "chainId": "default",
          "local": "aMt0mxDIxz5MCYKp9c0jEzG1en8="
        },
        "params": {
          "voteThreshold": "67",
          "numBlockConfirmations": "10"
        },
        "features": [
          {
            "name": "test",
            "status": "WAITING"
          }
        ]
      }
    }
  ]
}

Next, collect all validators from each node, combine them into an array, and save everything to a new file. This old file will now need to be replaced with the new combined file. Do this for all nodes. For a two-node cluster, the validators array should look something like this:

  "validators": [
    {
      "pubKey": "2MysikRZ8Yzk3KPDVEl/g2tHSyX0i3DGrAMwtDcYH10=",
      "power": "10"
    },
    {
      "pubKey": "gCn5WayR3cgQjNlNXYiBSYgQ3c1pGIsFWajVGczByZulGa09mb",
      "power": "10"
    }
  ]

genesis.json #2 - chaindata/config 내부에 있는

You will find it at chaindata/config/genesis.json. It is not to be confused with the one in the working directory. You should NOT copy the file below as it is an example and it should look something like:

{
  "genesis_time": "2019-06-20T08:58:17.011337021Z",
  "chain_id": "default",
  "consensus_params": {
    "block_size": {
      "max_bytes": "22020096",
      "max_gas": "-1"
    },
    "evidence": {
      "max_age": "100000"
    },
    "validator": {
      "pub_key_types": [
        "ed25519"
      ]
    }
  },
  "validators": [
    {
      "address": "825F1AE812A4395EFF0F88A032AAB2CE42F120EE",
      "pub_key": {
        "type": "tendermint/PubKeyEd25519",
        "value": "2MysikRZ8Yzk3KPDVEl/g2tHSyX0i3DGrAMwtDcYH10="
      },
      "power": "10",
      "name": ""
    }
  ],
  "app_hash": ""
}

Next, collect all the validators from each node, combine them into an array, and save everything to a new file. The old file will now need to be replaced with the new combined file. Do this for all nodes. For a two-node cluster, the validators array should look something like this:

  "validators": [
    {
      "address": "825F1AE812A4395EFF0F88A032AAB2CE42F120EE",
      "pub_key": {
        "type": "tendermint/PubKeyEd25519",
        "value": "2MysikRZ8Yzk3KPDVEl/g2tHSyX0i3DGrAMwtDcYH10="
      },
      "power": "10",
      "name": ""
    },
    {
      "address": "825F1AE812A4395EFF0F88A032AAB2CE42F120EE",
      "pub_key": {
        "type": "tendermint/PubKeyEd25519",
        "value": "gCn5WayR3cgQjNlNXYiBSYgQ3c1pGIsFWajVGczByZulGa09mb"
      },
      "power": "10",
      "name": ""
    }
  ],

실행하기

먼저, 각 노드로부터 노드 키를 얻는 것이 필요합니다. 작업 디렉토리로 가서 loom nodekey를 실행하세요:

$ loom nodekey
47cd3e4cc27ac621ff8bc59b776fa228adab827e

어떤 노드 키가 어떤 노드인지를 명확하게 기록하는 것을 잊지 마십시오. Private IP (또는 노드가 서로 통신 할 수 있는 IP) 도 중요합니다. 일반적으로, 클라우드 환경에서는 security와 latency 때문에 public IP를 사용합니다.

이제, 4개의 노드를 가지고 있는 있는 예제를 사용해 봅시다:

Node IP Node key
1 10.2.3.4 47cd3e4cc27ac621ff8bc59b776fa228adab827e
2 10.6.7.8 e728bada822af677b95cb8ff126ca72cc4e3dc74
3 10.3.2.1 4953e5726664985cc1cc92ae2edcfc6e089ba50d
4 10.7.6.5 02c90b57d241c3c014755ecb07e0c0d232e07fff

Loom을 실행하기 위해서, 각 노드에게 피어가 누구인지 알려주어야 합니다. 일반적인 포맷은 다음과 같습니다:

loom run --persistent-peers tcp://<node1_key>@<node1_ip>:46656,tcp://<node2_key>@<node2_ip>:46656,...tcp://<nodeN_key>@<nodeN_ip>:46656

위 테이블을 사용하는 예제를 봅시다.

노드 1:

loom run --persistent-peers tcp://[email protected]:46656,tcp://[email protected]:46656,tcp://[email protected]:46656

노드 2:

loom run --persistent-peers tcp://[email protected]:46656,tcp://[email protected]:46656,tcp://[email protected]:46656

노드 3와 노드 4도 동일하게 적용됩니다. 우리는 노드 자신의 키와 IP주소는 제외합니다.

모든 커맨드는 작업 디렉토리 내에서 실행되어야 한다는 것을 잊지마세요.

systemd Startup Script

다음 startup script는 systemd를 이용해서 서비스를 컨트롤하는데 사용됩니다. 설정이 반영되도록 WorkingDirectory와/또는 ExecStart을 변경하세요.

ExecStart을 주목하세요, loom을 직접 실행했던 이전 섹션과 동일한 컨셉으로 구성되었습니다. 이것은 각 노드가 다른 startup script를 가진다는 것을 의미합니다.

[Unit]
Description=Loom
After=network.target

[Service]
Type=simple
User=ubuntu
WorkingDirectory=/home/ubuntu
ExecStart=/home/ubuntu/loom run --persistent-peers tcp://[email protected]:46656,tcp://[email protected]:46656,tcp://[email protected]:46656
Restart=always
RestartSec=2
StartLimitInterval=0
LimitNOFILE=500000
StandardOutput=syslog
StandardError=syslog

[Install]
WantedBy=multi-user.target

/etc/systemd/system/loom.service에 저장하세요. 활성화를 위해서 실행하세요:

sudo systemctl daemon-reload
sudo systemctl start loom.service

다음과 같이 출력을 검사할 수 있습니다:

sudo journalctl -u loom.service

의도한 대로 모든것이 구동 되었다고 판단될때, 다음을 실행하면 부팅시에 시작되도록 서비스를 활성화 할 것입니다:

sudo systemctl enable loom.service

검증하기

리스닝 포트

모든 것이 잘 되고 있다면, 각 노드에서 이런 포트가 열려 있는 것을 볼 수 있을 것입니다.

$ sudo netstat -tpnl
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
tcp6       0      0 :::46656                :::*                    LISTEN      2135/loom
tcp6       0      0 :::46657                :::*                    LISTEN      2135/loom
tcp6       0      0 :::46658                :::*                    LISTEN      2135/loom

자동화

설정 파일과 startup 커맨드를 조합하는 것이 많은 노력이 들어간다면, Ansible을 사용하여 자동화하는 방법이 있습니다.

Ansible 로컬에 설치되어야 합니다.

Playbook은 여기서 확인 가능합니다

여러분의 노드와 작업 디렉토리를 맞추기위해서 inventory를 변경해야할 필요가 있습니다.

노드에 SSH와 sudo 권한이 가능하도록 하세요

Inventory: inventory.yaml

Inventory는 노드와 노드의 IP 주소를 지정합니다. 노드가 오직 하나의 IP만 가지고 있다면, ansible_hostprivate_ip에 동일한 것을 사용하세요. Ansible는 ansible_host를 host와 연결하기 위해서 사용하며, 반면에 private_ip는 노드들이 서로 통신하기 위해서 사용된다.

---
all:
  vars:
    loom_build: build-404
    ansible_ssh_common_args: '-o StrictHostKeyChecking=no'
    working_directory: /home/ubuntu
    user: ubuntu
  hosts:
    loom-0:
      ansible_host: 1.2.3.4
      private_ip: 10.2.3.4
    loom-1:
      ansible_host: 5.6.7.8
      private_ip: 10.6.7.8
    loom-2:
      ansible_host: 4.3.2.1
      private_ip: 10.3.2.1
    loom-3:
      ansible_host: 8.7.6.5
      private_ip: 10.7.6.5

노드의 세부사항과 함께 inventory을 수정한 후, playbook을 실행하세요:

ansible-playbook -i inventory.yml -vv loom-playbook.yml

더 많은 자동화: Vagrant

전체 cluster를 provision 하기 위해 포함된Vagrantfile도 있습니다. Ansible는 호스트 머신에 설치되어야 합니다.

VirtualBox provider로 테스트 됩니다. 왠만한 머신에서 4개의 노드를 생성하고 provision 하는데 2분이 채 걸리지 않습니다.

다음 변수는 필요에 따라 변경될 수 있습니다.

# Vagrant로 생성된 cluster 사이즈
num_instances = 4

# Private Network Prefix
private_network_prefix = "172.31.99."

# 빌드 넘버
loom_build = "build-208"

주의: Vagrant는 자신만의 inventory를 만들기 때문에 inventory.yml이 사용되지 않습니다.