在Docker容器中创建以太坊Geth专用网络



如果您需要基于Geth部署专用的以太坊网络,则可以例如通过在物理服务器或虚拟机上创建网络节点来完成。 但是,使用Docker集线器存储库中的Geth容器要容易得多。 在这种情况下,您甚至可以在一台虚拟机或一台物理服务器上安装整个节点网络。

在本文中,我们将告诉您如何在运行Debian 9(虚拟或物理)的服务器上安装Docker,如何在运行Geth的情况下创建多个容器并将它们组合到专用网络中。 我们将为Node.js提供一个示例脚本,该脚本访问在容器中工作的Geth节点。

安装Docker


Docker安装在官方网站上有描述。 对于Debian 9和10,您可以在https://docs.docker.com/install/linux/docker-ce/debian/中找到详细的说明。

安装Docker
首先,更新软件包:

# apt-get update 

接下来,使用以下命令安装必要的软件包:

 # apt-get install apt-transport-https ca-certificates curl gnupg2 software-properties-common 

添加官方GPG密钥:

 # curl -fsSL https://download.docker.com/linux/debian/gpg | sudo apt-key add - 

确保您获得的指纹为9DC8 5822 9FC7 DD38 854A E2D8 8D81 803C 0EBF CD88

 # apt-key fingerprint 0EBFCD88 pub 4096R/0EBFCD88 2017-02-22 Key fingerprint = 9DC8 5822 9FC7 DD38 854A E2D8 8D81 803C 0EBF CD88 uid Docker Release (CE deb) docker@docker.com sub 4096R/F273FCD8 2017-02-22 

添加一个稳定的Docker仓库:

 # add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/debian $(lsb_release -cs) stable" 

更新软件包并安装Docker:

 # apt-get update # apt-get install docker-ce docker-ce-cli containerd.io 

现在仅需验证所有操作是否正确。 为此,请运行(Image)hello-world图像:

 # docker run hello-world 

此命令将下载所需的图像,并运行它以执行。 如您所料,您将在控制台上看到消息“ Hello from Docker!”。

如您所见,没有什么复杂的! 现在,您可以开始创建一个私有的Geth网络,其中的节点在容器中运行。

创建用户,目录和文件


在用户的服务器上以及其主目录中的以下子目录中创建一本书:

 /home/book/dock-test /home/book/dock-test/distr 

接下来,在/ home / book / dock-test目录中,创建一个Dockerfile:

清单1.文件/ home / book / dock-test / Dockerfile
 FROM ubuntu:16.04 LABEL version="1.0" LABEL maintainer="alexandre@frolov.pp.ru" ENV DEBIAN_FRONTEND=noninteractive RUN apt-get update && apt-get install --yes software-properties-common RUN add-apt-repository ppa:ethereum/ethereum RUN apt-get update && apt-get install --yes geth RUN adduser --disabled-login --gecos "" eth_book COPY distr /home/eth_book/distr RUN chown -R eth_book:eth_book /home/eth_book/distr USER eth_book WORKDIR /home/eth_book RUN geth --nousb init distr/genesis.json ENTRYPOINT bash 


创建Docker容器时将使用此文件。

您还需要创建/home/book/dock-test/distr/genesis.json文件,这是初始化以太坊网络节点所必需的:

清单2.文件/home/book/dock-test/distr/genesis.json
 { "config": { "chainId": 98760, "homesteadBlock": 0, "eip150Block": 0, "eip155Block": 0, "eip158Block": 0 }, "difficulty": "10", "gasLimit": "5100000", "alloc": {} } 


在这里,我们将专用网络的标识符设置为98760,为便于挖掘,我们在难度参数中指定了10,这将使我们能够在内存量相对较小(例如4 GB)的虚拟机上工作。

创建一个网络和容器


为了使我们的节点相互交换数据,我们将在容器之间创建一个网络:

 # docker network create PRIVATENET 

接下来,您需要创建Dockerfile所在的当前目录/ home / book / dock-test。 然后创建所需数量的容器,例如三个:

 # docker build -t node01 . # docker build -t node02 . # docker build -t node03 . 

创建第一个容器需要相对较长的时间,因为 您需要下载必要的图像。 但是,以下容器几乎是立即创建的-与创建虚拟机的速度相比,即使通过克隆也是如此。

现在打开四个控制台窗口。 在其中三个中,我们将使用容器,在第四个中,我们将接收有关容器和网络所需的数据。

在第一个控制台窗口中,发出以下命令:

 # docker run --rm -it -p 8545:8545 --net=PRIVATENET node01 

您将看到如下提示:

 eth_book@304bf4f09063:~$ 

在第二个和第三个控制台窗口中,分别输入以下命令:

 # docker run --rm -it -p 8546:8546 --net=PRIVATENET node02 # docker run --rm -it -p 8547:8547 --net=PRIVATENET node03 

创建以太坊专用网络节点和帐户


目前,我们有3个与Geth在一起的集装箱。 让我们在其中的每一个中创建我们以太坊专用网络和帐户的节点。

在前三个控制台窗口中输入命令:

 $ geth account new 

您将需要输入密码。 为简单起见,请在每个节点上使用相同的密码进行测试,但将其写下来。 如果您忘记了密码,那么它将无法以任何方式恢复。

在控制台上创建帐户后,将显示类似于以下内容的公钥地址:

 Public address of the key: 0xc5Df10a76Bb559332c385F8cA789C0F37dD77A54 Public address of the key: 0x0C976006a5762779bA36AC590D1D8Ebac1Ca2981 Public address of the key: 0xaB627feab4e962222a3333F3b09182dF68bB9422 

将地址(您将拥有其他地址)另存为 我们需要它们来运行节点。

现在,您需要开始节点的初始化。 使用以下命令完成此操作:

 $ geth --nousb init distr/genesis.json 

在我们容器的所有控制台窗口中输入此命令。 --nousb选项禁用与USB设备的所有通信。

运行Geth节点


现在依次打开每个控制台窗口,并使用以下命令在其中运行Geth。

第一个窗口:

 $ geth --identity="Node01" --etherbase "0xc5Df10a76Bb559332c385F8cA789C0F37dD77A54" --mine --minerthreads 1 --verbosity 3 --networkid 98760 --rpc --rpcaddr 127.0.0.1 --nousb --rpcapi="db,eth,net,web3,personal,web3" console 

第二个窗口:

 $ geth --identity="Node02" --etherbase "0x0C976006a5762779bA36AC590D1D8Ebac1Ca2981" --mine --minerthreads 1 --verbosity 3 --networkid 98760 --rpc --rpcaddr 127.0.0.1 --rpcport=8546 --nousb --rpcapi="db,eth,net,web3,personal,web3" console 

第三个窗口:

 $ geth --identity="Node03" --etherbase "0xaB627feab4e962222a3333F3b09182dF68bB9422" --mine --minerthreads 1 --verbosity 3 --networkid 98760 --rpc --rpcaddr 127.0.0.1 --rpcport=8547 --nousb --rpcapi="db,eth,net,web3,personal,web3" console 

在每个打开的窗口中,将显示有关DAG生成的消息:

 … INFO [12-19|17:57:44.072] Generating DAG in progress epoch=0 percentage=34 elapsed=29.740s INFO [12-19|17:57:44.898] Generating DAG in progress epoch=0 percentage=35 elapsed=30.566s INFO [12-19|17:57:45.671] Generating DAG in progress epoch=0 percentage=36 elapsed=31.339s … 

等到生成完成。 之后,eth.hashrate和eth.blockNumber将不同于0:

 > eth.hashrate 4 > eth.blockNumber 2 

您可以按以下方式检查当前帐户余额:

 > web3.fromWei( eth.getBalance(eth.coinbase) ) 

为了避免被控制台窗口中有关创建新块的消息和其他消息所困扰,请使用exit命令退出Geth,然后将verbosity参数设置为1重新启动。

网络节点


首先,我们将查看正在运行的容器的列表。 从第四个控制台窗口发出以下命令:

 # docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES fa70a5418618 node03 "/bin/sh -c bash" 2 hours ago Up 2 hours 0.0.0.0:8547->8547/tcp gifted_curran 49a028744b4b node02 "/bin/sh -c bash" 2 hours ago Up 2 hours 0.0.0.0:8546->8546/tcp reverent_wescoff 5a9ade2947eb node01 "/bin/sh -c bash" 2 hours ago Up 2 hours 0.0.0.0:8545->8545/tcp clever_ellis 

在这里,对于每个容器,将显示其标识符,图像名称,容器名称和其他信息。

要将容器加入网络,您将需要我们专用PRIVATENET网络中容器的IP地址。 您可以通过容器ID获取这些地址,例如,如下所示:

 # docker inspect 5a9ade2947eb | grep IPAddress "SecondaryIPAddresses": null, "IPAddress": "", "IPAddress": "172.21.0.2", 

您还可以使用docker network inspect PRIVATENET命令:

码头工人网络检查PRIVATENET
 [ { "Name": "PRIVATENET", "Id": "576ec7edba5b4c228740deaf7fabb5e2ba003d310086153dd7f15e2c7de0c1b2", "Created": "2019-12-20T11:52:07.90695857+03:00", "Scope": "local", "Driver": "bridge", "EnableIPv6": false, "IPAM": { "Driver": "default", "Options": {}, "Config": [ { "Subnet": "172.21.0.0/16", "Gateway": "172.21.0.1" } ] }, "Internal": false, "Attachable": false, "Ingress": false, "ConfigFrom": { "Network": "" }, "ConfigOnly": false, "Containers": { "49a028744b4b6073f6dbca23e78625bc58fc0cdacadec7cded4bb0e888c7e37b": { "Name": "reverent_wescoff", "EndpointID": "11006b596b5a46df9bf9f95a9456784795d333a3e6901b15bd2db746fd4b5513", "MacAddress": "02:42:ac:15:00:03", "IPv4Address": "172.21.0.3/16", "IPv6Address": "" }, "5a9ade2947ebd8e55594ede9763aac71f5e6529c03e762ef723adb2c592c5ccd": { "Name": "clever_ellis", "EndpointID": "41ef69a0a93b5b1de495836028bac1742c303de92ffe42a0855ed32c93c28953", "MacAddress": "02:42:ac:15:00:02", "IPv4Address": "172.21.0.2/16", "IPv6Address": "" }, "fa70a54186185de01db3647e7333bf6c71250162fafefb78dbe9998e5ac93f34": { "Name": "gifted_curran", "EndpointID": "d368c032bc0886c27ad4895d1856e4f00cf1b25ce040f3b42393dbff778c18e5", "MacAddress": "02:42:ac:15:00:04", "IPv4Address": "172.21.0.4/16", "IPv6Address": "" } }, "Options": {}, "Labels": {} } ] 

比较这些命令接收的数据,我们将列出容器的IP地址列表:

 node01 - 172.21.0.2 node02 - 172.21.0.3 node03 - 172.21.0.4 

当然,您将有一个不同的列表,并且当您重新启动容器时,这些地址可能会更改。

收到地址列表后,在所有容器中重新启动geth,并在--rpcaddr参数中指定容器的地址。 当然,您可以设置地址0.0.0.0,但是从安全角度来看,这很不好-任何人或任何事物都可以连接到该节点。 例如,可能是僵尸程序试图从这些节点“提取”所有资金,等待该节点被解锁。

要合并节点,您将需要使用admin.addPeer命令。 作为此命令的参数,您需要以enode格式传递URL。 使用admin.nodeInfo.enode命令为每个容器获取此URL:

 > admin.nodeInfo.enode "enode://0a84e562c9b22e43269b7dca215cf2ed8c20bbf35da67bae8d5ee81b36d8bbb69e3ec704b9b6f7501059fe861843a836b2fbab641f36616cdd77365b1a522d5b@62.152.63.28:30303?discport=1350" "enode://ee49f69e25c068e006fec4a8d74370370b1d2be9715b86eddd99f97a3a5a9c692a265ab7d01fb36410d59c3f6e2b253a22f652ecbf1941eef0b3f1d30b19a535@62.152.63.28:30303?discport=1345" "enode://156d43648b47078439c7481e54f697bbf1c6b6e762029ba2969f1556ceb94e51ad03f8bd2bed35f466073165810600f52925d155f0fceef832ae86fc39a8c135@62.152.63.28:30303?discport=1348" 

收到的地址保存。

为了将一个节点连接到另一个节点,请打开第一个节点的控制台窗口,然后在其中输入以下命令:

 > admin.addPeer( "enode://0a84e562c9b22e43269b7dca215cf2ed8c20bbf35da67bae8d5ee81b36d8bbb69e3ec704b9b6f7501059fe861843a836b2fbab641f36616cdd77365b1a522d5b@172.21.0.3:30303") 

在这里,我们传递了URL地址,其中指出了所连接主机的IP地址。 在其他网络节点上遵循相同的步骤。

要验证已建立连接,请使用admin.peers命令。 如果没有连接,该命令将返回空结果:

 > admin.peers [] 

在我们的示例中,该命令显示地址为172.21.0.2的第一个节点已连接到地址为172.21.0.3和172.21.0.4的节点:

有连接时查看结果
 > admin.peers [{ caps: ["eth/63", "eth/64"], enode: "enode://156d43648b47078439c7481e54f697bbf1c6b6e762029ba2969f1556ceb94e51ad03f8bd2bed35f466073165810600f52925d155f0fceef832ae86fc39a8c135@172.21.0.4:30303", id: "4dac1d10cb6ae8bfc1fdebd3f5334b24ee62ec38a50bc92c89104cfc3251b5fc", name: "Geth/Node03/v1.9.9-stable-01744997/linux-amd64/go1.13.4", network: { inbound: false, localAddress: "172.21.0.2:40652", remoteAddress: "172.21.0.4:30303", static: true, trusted: false }, protocols: { eth: { difficulty: 98414119, head: "0x6b31a5bb9cde06fab5a8cc1ae9b18bada30de0d1b76cb3286c1081e76dbf5b83", version: 64 } } }, { caps: ["eth/63", "eth/64"], enode: "enode://ee49f69e25c068e006fec4a8d74370370b1d2be9715b86eddd99f97a3a5a9c692a265ab7d01fb36410d59c3f6e2b253a22f652ecbf1941eef0b3f1d30b19a535@172.21.0.3:30303", id: "b74277d278c15317fa7f7fa492daca60492ea22053bfc53281dd0071eba1c16b", name: "Geth/Node02/v1.9.9-stable-01744997/linux-amd64/go1.13.4", network: { inbound: false, localAddress: "172.21.0.2:42576", remoteAddress: "172.21.0.3:30303", static: true, trusted: false }, protocols: { eth: { difficulty: 99041423, head: "0x0ec44735bbb425cb8db96103f52300dfaae1147ba0e03aa4892d041250ce4408", version: 64 } } }] 

请注意,在成功合并并同步了节点之后,当在我们的三个容器中的任何一个中启动eth.blockNumber命令时,它将返回相同的值。

相反,web3.fromWei命令(eth.getBalance(eth.coinbase))将在不同节点上显示不同的平衡,因为 每个节点都有自己的帐户。

使用Node.js处理主机


在清单3中,我们提供了一个运行Node.js的简单脚本,该脚本在控制台上显示了指定节点的帐户列表以及每个帐户的余额:

清单3. File / home / book / list_accounts.js
 var Web3 = require('web3') var web3 = new Web3(new Web3.providers.HttpProvider("http://172.21.0.2:8545")); web3.eth.getAccounts() .then(accList => { return accList; }) .then(function (accounts) { var balancePromeses = []; for(let i = 0; i < accounts.length; i++) { balancePromeses[i] = web3.eth.getBalance(accounts[i]); } Promise.all(balancePromeses).then(values => { for(let i = 0; i < values.length; i++) { console.log('Account: ', accounts[i], 'balance: ', values[i], 'wei, ', web3.utils.fromWei(values[i], 'ether'), 'ether'); } }); }) .catch(function (error) { console.error(error); }); 


您可以在另一个单独的窗口中运行此脚本,例如,在第四个控制台窗口中:

 # node list_accounts.js Account: 0x0C976006a5762779bA36AC590D1D8Ebac1Ca2981 balance: 3350000000000000000000 wei, 3350 ether 

接下来是什么


一般而言,加密货币,特别是以太坊的软件开发主题非常引人入胜。 如果在阅读本文后有疑问并想了解更多,请阅读我的书“为以太坊区块链创建Solidity智能合约”。 实用指南” ,由Liters出版社出版。

您可能还需要一个好的Docker备忘单

对于本文和本书的任何评论和补充,我将不胜感激!

Source: https://habr.com/ru/post/zh-CN481052/


All Articles