通过Docker搭建4节点的Tendermint集群

Tendermint:0.34.24
Docker:20.10.21
Docker-Compose:2.20.2
OS:Ubuntu 20.04
Go:1.19.2 Linux/amd64

1 修改Tendermint源码

1.1 修改监听IP

为什么要将127.0.1修改成0.0.0.0呢?因为容器内的服务如果是以127.0.0.1暴露的话,外部是无法通过端口映射访问docker容器内对应服务的。
127.0.0.1是一个特殊的IP地址,称为本地回环地址,只能用于在同一台计算机上的进程之间进行通信。当您将服务绑定到127.0.0.1地址时,它将只能在本机进行访问,无法通过外部网络访问该应用程序。
在这里插入图片描述

1.2 不产生空区块

在这里插入图片描述

1.3 统一ChainID

在这里插入图片描述

1.4 修改AddBookStrict为false,用来支持局域网通信

在这里插入图片描述

2 编译生成二进制可执行文件

make install
make install_abci

3 编写dockerfile定制镜像

FROM ubuntu
ENV MYPATH /usr/local
WORKDIR $MYPATH
ADD ./tendermint $MYPATH
ADD ./abci-cli $MYPATH

注意要将abci-cli和tendermint可执行文件与dockerfile文件放在同一目录下:
cp $GOPATH/bin/tendermint ./

在这里插入图片描述
查看定制的docker镜像:
在这里插入图片描述

4 编写docker-compose编排容器

网络采用桥接模式,并对每个节点的RPC服务端口26657进行外部映射。

version: "3"
services:
        node0:
                image: tm
                container_name: node0
                ports:
                        - "26657:26657"
                volumes:
                        - /usr/local/node0:$HOME/.tendermint
                networks:
                        mynet:
                                ipv4_address: 172.20.20.0
                command: 
                        - /bin/bash
                        - -c
                        - |
                                ./tendermint init
                                ./tendermint show-node-id > $HOME/.tendermint/nodeid.txt
                                tail -f /dev/null

        node1:
                image: tm
                container_name: node1
                ports:
                        - "36657:26657"
                volumes:
                        - /usr/local/node1:$HOME/.tendermint
                networks:
                        mynet:
                                ipv4_address: 172.20.20.1
                command:
                        - /bin/bash
                        - -c
                        - |
                                ./tendermint init
                                ./tendermint show-node-id > $HOME/.tendermint/nodeid.txt
                                tail -f /dev/null


        node2:
                image: tm
                container_name: node2
                ports:
                        - "46657:26657"
                networks:
                        mynet:
                                ipv4_address: 172.20.20.2
                volumes:
                        - /usr/local/node2:$HOME/.tendermint
                command:
                        - /bin/bash
                        - -c
                        - |
                                ./tendermint init
                                ./tendermint show-node-id > $HOME/.tendermint/nodeid.txt
                                tail -f /dev/null


        node3:  
                image: tm
                container_name: node3
                ports:
                        - "56657:26657"
                networks:
                        mynet:
                                ipv4_address: 172.20.20.3
                volumes:  
                        - /usr/local/node3:$HOME/.tendermint
                command:
                        - /bin/bash
                        - -c
                        - |
                                ./tendermint init
                                ./tendermint show-node-id > $HOME/.tendermint/nodeid.txt
                                tail -f /dev/null
networks:
        mynet:
                ipam:
                        driver: default
                        config:
                                - subnet: 172.20.0.0/16

启动容器:
docker-compose up -d
在这里插入图片描述

5 统一的genesis.json

因为容器卷的缘故,宿主机本地可以直接查看每个节点的config和data目录。
集群要求每个节点的genesis.json文件完全相同,并且包含所有节点的validator信息。
这里通过一个简单的Python脚本快速构建统一的genesis.json文件:

linesArr = []

for i in range(0, 4):
    f = open("/usr/local/node%d/config/genesis.json" % i, 'r')
    linesArr.append(f.readlines())
    f.close()

f = open("./genesis.json", 'w')

for i in range(len(linesArr)):
    lines = linesArr[i]

    if i == 0:
        for j in range(23):
            f.write(lines[j])

    for j in range(23, 32):
        if i == len(linesArr) - 1:
            f.write(lines[j])
        else:
            if j < 31:
                f.write(lines[j])
            else:
                f.write(lines[j][:len(lines[j]) - 1])
                f.write(",\n")

for i in range(32, len(linesArr[0])):
    f.write(linesArr[0][i])

f.close()

生成的统一的genesis.json创世文件:

{
  "genesis_time": "2024-01-06T02:17:15.806171802Z",
  "chain_id": "test-chain",
  "initial_height": "0",
  "consensus_params": {
    "block": {
      "max_bytes": "22020096",
      "max_gas": "50",
      "time_iota_ms": "1000"
    },
    "evidence": {
      "max_age_num_blocks": "100000",
      "max_age_duration": "172800000000000",
      "max_bytes": "1048576"
    },
    "validator": {
      "pub_key_types": [
        "ed25519"
      ]
    },
    "version": {}
  },
  "validators": [
    {
      "address": "6DE6C6F2CD5AD081A1B6C7A87FC915E04B1E2219",
      "pub_key": {
        "type": "tendermint/PubKeyEd25519",
        "value": "iKt2epWBuZHFayrS4qb7AJAwbfSlrJxOsLSbwwsUn9A="
      },
      "power": "10",
      "name": ""
    },
    {
      "address": "5993A76300771C1EF633D6801FF53D5B6527127A",
      "pub_key": {
        "type": "tendermint/PubKeyEd25519",
        "value": "uGc87MkuEtnMTcIQGUD22mNdTAQ7400FDqtIOkctbDg="
      },
      "power": "10",
      "name": ""
    },
    {
      "address": "039D64F5C23FD4CA0E4563B282B0B6F96CE278CB",
      "pub_key": {
        "type": "tendermint/PubKeyEd25519",
        "value": "FWFS6CuHP+iOk8tktKfMm1A8WJIldFP+chjDj9AbD78="
      },
      "power": "10",
      "name": ""
    },
    {
      "address": "73BFE884FB6C97F170FED9A9699EDB1B3E5341C4",
      "pub_key": {
        "type": "tendermint/PubKeyEd25519",
        "value": "xpPW7WNXZYJnUCOLT/Uv1czyfLEhpiDo7jN/DS/Ad2s="
      },
      "power": "10",
      "name": ""
    }
  ],
  "app_hash": ""
}

覆盖掉原来的genesis.json文件:
在这里插入图片描述

#!/bin/bash
for((i=0;i<=3;i++))
do
	cp genesis.json node${i}/config/genesis.json
done

6 启动集群

如果没在docker-compose手动指定各容器的IP,则通过docker inspect查询各容器的IP:
在这里插入图片描述
查看每个节点的nodeID,由于容器卷以及容器启动时会将nodeID重定向到nodeid.txt文件,我们在宿主机本地就能够访问。
在这里插入图片描述

构造启动命令:

#!/bin/bash

echo "nohup ./tendermint node --p2p.persistent_peers="$(cat node0/nodeid.txt)@172.20.20.0:26656,$(cat node1/nodeid.txt)@172.20.20.1:26656,$(cat node2/nodeid.txt)@172.20.20.2:26656,$(cat node3/nodeid.txt)@172.20.20.3:26656" --proxy_app=persistent_kvstore &"

./tendermint node --p2p.persistent_peers=“15352fccfb6a2a177fa18253bfb4bd6cd71c0894@172.20.20.0:26656,c61f1ed46fef14b5d518dbe5f9831134cba72518@172.20.20.1:26656,891df109a91fb4fc97c936594aa694206fdbb8de@172.20.20.2:26656,fba18b7bc2d04a6a5aac41a40ab5f230be51b031@172.20.20.3:26656” --proxy_app=persistent_kvstore &

通过脚本批量启动:

#!/bin/bash

runCmd="nohup ./tendermint node --p2p.persistent_peers="$(cat node0/nodeid.txt)@172.20.20.0:26656,$(cat node1/nodeid.txt)@172.20.20.1:26656,$(cat node2/nodeid.txt)@172.20.20.2:26656,$(cat node3/nodeid.txt)@172.20.20.3:26656" --proxy_app=persistent_kvstore &"

for((i=0;i<4;i++))
do
    docker exec -d node${i} ${runCmd}
done

7 验证集群是否启动成功

7.1 第一种验证方式:

在这里插入图片描述
可以看到,node2的peer数量为3

7.2 第二种验证方式:

向node0发送一条name=jackie的交易:
在这里插入图片描述

分别从node1、node2、node3查询交易,得到的结果是base64格式:
在这里插入图片描述

对返回的结果进行base64解码:
在这里插入图片描述
不过,通过命令行提交交易太繁琐了,我们干脆写个简单的测试程序,向node0提交500个交易:

func main() {
	cli, err := http.New("http://localhost:26657", "/websocket")
	if err != nil {
		panic(err)
	}
	for i := 0; i < 500; i++ {
		_, err = cli.BroadcastTxAsync(context.TODO(), types.Tx(strconv.Itoa(i)))
		if err != nil {
			panic(err)
		}
	}
}

会发现四个节点的区块全部同步到同一个高度:
在这里插入图片描述
如果我们让节点node0宕机,会发现其他三个节点会打印出node0宕机的信息:
在这里插入图片描述
最后优雅关闭所有容器:
在这里插入图片描述

好的,以下是基于Docker搭建节点Hadoop集群的详细教程: 1. 安装DockerDocker Compose 首先您需要在每个节点上安装DockerDocker Compose。您可以使用以下命令来进行安装: ``` sudo apt-get update sudo apt-get install docker.io sudo systemctl start docker sudo systemctl enable docker sudo curl -L "https://github.com/docker/compose/releases/download/1.28.5/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose sudo chmod +x /usr/local/bin/docker-compose ``` 2. 创建Docker镜像 在每个节点上,您需要创建一个Docker镜像。您可以使用以下命令来创建Docker镜像: ``` sudo docker pull sequenceiq/hadoop-docker:2.7.0 ``` 3. 创建Docker Compose文件 在每个节点上,您需要创建一个Docker Compose文件。您可以使用以下模板文件来创建Docker Compose文件: ``` version: '2.7' services: namenode: image: sequenceiq/hadoop-docker:2.7.0 container_name: namenode hostname: namenode ports: - "8088:8088" - "50070:50070" - "8020:8020" volumes: - ./hadoop:/opt/hadoop-2.7.0 environment: - CLUSTER_NAME=hadoop-cluster - NODE_TYPE=namenode datanode1: image: sequenceiq/hadoop-docker:2.7.0 container_name: datanode1 hostname: datanode1 ports: - "50075:50075" volumes: - ./hadoop:/opt/hadoop-2.7.0 environment: - CLUSTER_NAME=hadoop-cluster - NODE_TYPE=datanode datanode2: image: sequenceiq/hadoop-docker:2.7.0 container_name: datanode2 hostname: datanode2 ports: - "50075:50075" volumes: - ./hadoop:/opt/hadoop-2.7.0 environment: - CLUSTER_NAME=hadoop-cluster - NODE_TYPE=datanode ``` 在此文件中,您需要定义三个服务:namenode、datanode1、datanode2。您需要在每个服务中指定Docker镜像名称、容器名称、主机名、端口号、数据卷和环境变量。您需要将此文件保存为docker-compose.yml。 4. 启动集群 接下来,您需要在每个节点上使用以下命令来启动集群: ``` sudo docker-compose up -d ``` 这将启动集群并在后台运行。 5. 验证集群 最后,您需要验证Hadoop集群是否成功启动。您可以使用以下命令来验证: ``` sudo docker exec -it namenode bash hadoop fs -mkdir /test hadoop fs -ls / ``` 如果您在上述命令中看到/test目录,则表明您成功地启动了Hadoop集群。 希望这个教程对您有所帮助!
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值