如何用EOS和OpenShift部署一个BaaS系统


现在区块链技术很是热门,很多大公司都纷纷开辟了自己关于区块链的相关业务部门,比如数字金融,产品溯源等,那么什么是区块链技术呢?区块链是分布式数据存储、点对点传输、共识机制、加密算法等计算机技术的新型应用模式。在区块链技术的迭代过程中,大家公认比特币是区块链1.0版本的应用,以太坊是2.0版本,现在在链圈炒的最为火热的就是自称是区块链3.0版本的EOS。它以BFT+DPos的公式机制和石墨烯网络为基础,号称公网上线以后能够达到3000-4000左右的TPS(比特币为6-7笔,以太坊是30-40笔,但是笔者亲测EOS的3.0版本是1000tps左右,可能是受环境和主机性能所限吧)。越来越多的人开始关注区块链技术,越来越多的企业级应用开始搬上区块链,现在我就带领大家搭建一套最简单的BaaS系统(block chain as a service:区块链即服务)。

当人们一说到某某即服务的时候总是想到PaaS、SaaS或者IaaS,没错!这次搭建的BaaS也和前面几个类似采用PaaS的设计架构,即用容器的方式搭建BaaS平台。提到容器,就不得不想到现在最流行的Docker+Kubernetes的方式,Docker提供了单机条件下的容器运行环境,Kubernetes提供了一套高可用的容器编排管理系统。本次使用的就是在代码级对Kubernetes做了升级和改造的,由Red Hat公司推出的OpenShift,它使用Kuberenetes作为其内核,对它网络功能做了补充,增加了Web界面,又对原有的Ingress做了优化和升级,所以我们选择它作为本次BaaS的基础平台。

BaaS平台部署图如下图所示:
server.png

1、首先开始制作EOS镜像

1)下面是EOS代码获取方法:
git clone https://github.com/EOSIO/eos --recursive

然后进入代码目录执行:
cd eos
./eosio_build.sh

2)在代码的EOS目录下会生成一个build目录,把EOS的二进制文件NodeOS、keosd、cleos等复制到要制作镜像的子目录下,下面是Dockerfile文件的内容,其中基础镜像选用了CentOS,这个系统的版本好要和刚才编译EOS的一致,否则可能会出现NodeOS无法运行的错误。
From docker.io/centos
ADD cleos /cleos
ADD nodeos /nodeos
ADD genesis.json /genesis.json
ADD config.ini /config.ini
ADD nodeosd.sh /opt/eosio/bin/
USER 0
CMD /opt/eosio/bin/nodeosd.sh

3)除了有必要的二进制文件外,我们还要为NodeOS启动配置必要的启动脚本和两个配置文件。

下面是启动脚本:
#!/bin/sh
mkdir -p /opt/eosio/config-dir
mkdir -p /opt/eosio/data-dir
mkdir -p /opt/eosio/bin
cp /config.ini /opt/eosio/config-dir
cp /genesis.json /opt/eosio/config-dir
cp /cleos /opt/eosio/bin
cp /nodeos /opt/eosio/bin
cp -r /contracts /opt/eosio/bin

CONFIG_DIR="--config-dir=/opt/eosio/config-dir"
DATA_DIR="--data-dir=/opt/eosio/data-dir"

replace agent name

sed -i 's/AGENT-NAME/'$HOSTNAME'/g' /opt/eosio/config-dir/config.ini

replace producer name

sed -i 's/EOSIO/'$BP'/g' /opt/eosio/config-dir/config.ini

replace p2p-peer-address

sed -i 's/EOSIO/'$BP'/g' /opt/eosio/config-dir/config.ini

replace p2p-server-address

sed -i 's/EOSIO/'$BP'/g' /opt/eosio/config-dir/config.ini

sed -i 's/P2P_PEER_ADDRESS/'${BP_LIST}'/g' /opt/eosio/config-dir/config.ini

sed -i 's/P2P_SERVER_ADDRESS/'${HOSTNAME}'/g' /opt/eosio/config-dir/config.ini

replace keys

sed -i 's/PRIVATE-KEY/'${PRIVATE_KEY}'/g' /opt/eosio/config-dir/config.ini
sed -i 's/PUBLIC-KEY/'${PUBLIC_KEY}'/g' /opt/eosio/config-dir/config.ini

exec /opt/eosio/bin/nodeos -e $CONFIG_DIR $DATA_DIR $@

genesis.json文件内容:
# cat genesis.json
{
"initial_timestamp": "2018-03-02T12:00:00.000",
"initial_key": "EOSxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"initial_configuration": {
"max_block_net_usage": 1048576,
"target_block_net_usage_pct": 1000,
"max_transaction_net_usage": 524288,
"base_per_transaction_net_usage": 12,
"net_usage_leeway": 500,
"context_free_discount_net_usage_num": 20,
"context_free_discount_net_usage_den": 100,
"max_block_cpu_usage": 100000,
"target_block_cpu_usage_pct": 500,
"max_transaction_cpu_usage": 50000,
"min_transaction_cpu_usage": 100,
"max_transaction_lifetime": 3600,
"deferred_trx_expiration_window": 600,
"max_transaction_delay": 3888000,
"max_inline_action_size": 4096,
"max_inline_action_depth": 4,
"max_authority_depth": 6,
"max_generated_transaction_count": 16
},
"initial_chain_id": "0000000000000000000000000000000000000000000000000000000000000000"


# cat config.ini

File to read Genesis State from (eosio::chain_plugin)

genesis-json = "genesis.json"

override the initial timestamp in the Genesis State file (eosio::chain_plugin)

genesis-timestamp =

the location of the block log (absolute path or relative to application data dir) (eosio::chain_plugin)

block-log-dir = "blocks"

Pairs of [BLOCK_NUM,BLOCK_ID] that should be enforced as checkpoints. (eosio::chain_plugin)

checkpoint =

Override default WASM runtime (eosio::chain_plugin)

wasm-runtime =

Maximum size MB of database shared memory file (eosio::chain_plugin)

shared-memory-size-mb = 1024

Track only transactions whose scopes involve the listed accounts. Default is to track all transactions. (eosio::history_plugin)

filter_on_accounts =

The local IP and port to listen for incoming http connections; set blank to disable. (eosio::http_plugin)

http-server-address = 0.0.0.0:8888

The local IP and port to listen for incoming https connections; leave blank to disable. (eosio::http_plugin)

https-server-address =

Filename with the certificate chain to present on https connections. PEM format. Required for https. (eosio::http_plugin)

https-certificate-chain-file =

Filename with https private key in PEM format. Required for https (eosio::http_plugin)

https-private-key-file =

Specify the Access-Control-Allow-Origin to be returned on each request. (eosio::http_plugin)

access-control-allow-origin =

Specify the Access-Control-Allow-Headers to be returned on each request. (eosio::http_plugin)

access-control-allow-headers =

Specify if Access-Control-Allow-Credentials: true should be returned on each request. (eosio::http_plugin)

access-control-allow-credentials = false

The actual host:port used to listen for incoming p2p connections. (eosio::net_plugin)

p2p-listen-endpoint = 0.0.0.0:9876

An externally accessible host:port for identifying this node. Defaults to p2p-listen-endpoint. (eosio::net_plugin)

p2p-peer-address = P2P_PEER_ADDRESS:9876

The public endpoint of a peer node to connect to. Use multiple p2p-peer-address options as needed to compose a network. (eosio::net_plugin)

p2p-server-address = P2P_SERVER_ADDRESS

The name supplied to identify this node amongst the peers. (eosio::net_plugin)

agent-name = "AGENT-NAME"

Can be 'any' or 'producers' or 'specified' or 'none'. If 'specified', peer-key must be specified at least once. If only 'producers', peer-key is not required. 'producers' and 'specified' may be combined. (eosio::net_plugin)

allowed-connection = any

Optional public key of peer allowed to connect. May be used multiple times. (eosio::net_plugin)

peer-key =

Tuple of [PublicKey, WIF private key] (may specify multiple times) (eosio::net_plugin)

peer-private-key =

Maximum number of clients from which connections are accepted, use 0 for no limit (eosio::net_plugin)

max-clients = 25

number of seconds to wait before cleaning up dead connections (eosio::net_plugin)

connection-cleanup-period = 30

True to require exact match of peer network version. (eosio::net_plugin)

network-version-match = 0

number of blocks to retrieve in a chunk from any individual peer during synchronization (eosio::net_plugin)

sync-fetch-span = 100

maximum sizes of transaction or block messages that are sent without first sending a notice (eosio::net_plugin)

max-implicit-request = 1500

Enable block production, even if the chain is stale. (eosio::producer_plugin)

enable-stale-production = false

Limits the maximum time (in milliseconds) that is allowed a pushed transaction's code to execute before being considered invalid (eosio::producer_plugin)

max-transaction-time = 30

Percent of producers (0-100) that must be participating in order to produce blocks (eosio::producer_plugin)

required-participation = 33

ID of producer controlled by this node (e.g. inita; may specify multiple times) (eosio::producer_plugin)

producer-name = EOSIO

Tuple of [public key, WIF private key] (may specify multiple times) (eosio::producer_plugin)

private-key = ["PUBLIC-KEY","PRIVATE-KEY"]

Lag in number of blocks from the head block when selecting the reference block for transactions (-1 means Last Irreversible Block) (eosio::txn_test_gen_plugin)

txn-reference-block-lag = 0

The path of the wallet files (absolute path or relative to application data dir) (eosio::wallet_plugin)

wallet-dir = "."

Timeout for unlocked wallet in seconds (default 900 (15 minutes)). Wallets will automatically lock after specified number of seconds of inactivity. Activity is defined as any wallet command e.g. list-wallets. (eosio::wallet_plugin)

unlock-timeout = 900

eosio key that will be imported automatically when a wallet is created. (eosio::wallet_plugin)

eosio-key =

Plugin(s) to enable, may be specified multiple times

plugin =

plugin = eosio::producer_plugin
plugin = eosio::chain_api_plugin
plugin = eosio::wallet_api_plugin
plugin = eosio::http_plugin
plugin = eosio::history_api_plugin
plugin = eosio::history_plugin

4)运行下面命令生成image并推送到私有的Registry。
docker build . -t registryhost:5000/eos/eos
docker push registryhost:5000/eos/eos

2、EOS节点部署

1)当镜像推送到Registry后,我们就可以进行Yaml文件的编写并且配置了,下面是Yaml文件的内容:
at nodeos.yaml 
apiVersion: v1
kind: Template
metadata:
name: nodeos
annotations:
openshift.io/display-name: nodeos
description: nodeos of eos.
iconClass: icon-wildfly
tags: nodeos

objects:
- apiVersion: v1
kind: Service
metadata:
annotations:
  description: Exposes and load balances the application pods
name: ${BP}
spec:
ports:
- name: http-8888-tcp
  port: 8888
  protocol: TCP
  targetPort: 8888
- name: admin-9876-tcp
  port: 9876
  protocol: TCP
  targetPort: 9876
selector:
  name: ${BP}
type: ClusterIP

  • apiVersion: v1
    kind: Route
    metadata:
    name: nodeos-http
    spec:
    host: nodeos
    to:
    kind: Service
    name: ${BP}
    port:
    targetPort: http-8888-tcp

  • apiVersion: v1
    kind: DeploymentConfig
    metadata:
    annotations:
    description: Defines how to deploy the nodeos
    name: ${BP}
    spec:
    replicas: 1
    selector:
    name: ${BP}
    strategy:
    type: Rolling
    template:
    metadata:
    labels:
    name: ${BP}
    spec:
    containers:
    - image: "192.168.20.2:5000/eosio/eos"
    env:
    - name: BP
    value: ${BP}
    - name: PUBLIC_KEY
    value: ${PUBLIC_KEY}
    - name: PRIVATE_KEY
    value: ${PRIVATE_KEY}
    - name: BP_LIST
    value: ${BP_LIST}

    imagePullPolicy: Always
    name: nodeos-bp
    ports:
    - containerPort: 8888
    protocol: "TCP"
    - containerPort: 9876
    protocol: "TCP"

    resources:
    requests:
    memory: 4096Mi
    cpu: 2000m
    dnsPolicy: ClusterFirst
    restartPolicy: Always
    securityContext:
    - runAsUser: 0

parameters:
- name: BP
description: Block Producer
displayName: Block Producer
value: eosio
- name: PUBLIC_KEY
description: PUBLIC_KEY.
displayName: PUBLIC_KEY
value: EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV
- name: PRIVATE_KEY
description: PRIVATE_KEY.
displayName: PRIVATE_KEY
value: 5KQwrPbwdL6PhXujxW37FSSQZ1JiwsST4cqQzDeyXtP79zkvFD3
- name: BP_LIST
description: A IP list of Block Producer
displayName: A IP list of Block Producer
value: bp's hostname and port

2)有了Yaml文件,我们就可以把我们的Yaml文件推送到OpenShift中当成模版,然后通过模版进行EOS节点的实例化,这里面有一个问题需要注意,所有节点的公私钥不可能一样,需要通过模版的参数在实例化的时候传入容器里,然后启动NodeOS的时候,调用NodeOS启动脚本把传入的变量(每一个传入变量都会生成一个环境变量)替换到config.ini文件中,然后启动EOS的主进程NodeOS。当然,这里还有一个问题也需要注意,那就是4.1的EOS配置文件里需要配置两个参数,一个是自己自身的IP(p2p-server-address),和对端IP(p2p-peer-address)第一个地址可以用这个Pod的hostname代替,第二个可以通过指定之前节点的hostname来填充。

3)使用oc create -f eos.yaml 进行模版的部署,然后通过Web界面,选择刚才的模版,输入变量的内容,最后点击生成,如下图所示:
eos_template.png

3、既然环境已经设置完成,现在我们来初始化整个EOS的环境。

1)首先通过cleos wallet create创建一个默认的钱包,如果-n可以指定钱包的名字,这个钱包默认的存储路径是/root/eosio-wallet/目录下,看下面的输出:
# cleos wallet create 
"/usr/local/bin/keosd" launched
Creating wallet: default
Save password to use in the future to unlock this wallet.
Without password imported keys will not be retrievable.
"PW5J2SGNDmhZFiVnbZY6V669XLEksGs13KnhCnkuqQZScj5ieNV5j"

其中下面的是这个钱包的密码,需要记住,因为现在4.1版本的钱包900秒后就会自动上锁,需要这个密码来解锁。

2)创建一对公私钥,创建账户,并部署合约。

创建私钥公钥:
# cleos create key 
"/usr/local/bin/keosd" launched Private key: 5Kgh744izqDCNyuRZcBu4nMjgJbBwWBdqQZuQi53qPB9L69Cj9X Public key: EOS6CYWY1q4AAsVV3rzcT1GGQmZcg7yDnA6jZx2KUjHvmZWPv8DQg

创建代币账户:
#cleos -u http://nodeos:80 create account eosio eosio.token EOS6CYWY1q4AAsVV3rzcT1GGQmZcg7yDnA6jZx2KUjHvmZWPv8DQg EOS6CYWY1q4AAsVV3rzcT1GGQmZcg7yDnA6jZx2KUjHvmZWPv8DQg

部署代币合约:
#cleos -u http://nodeos:80  set contract eosio.token  eos/build/contracts/eosio.token/
Reading WAST/WASM from /eos_code/dawn-v4.1.0/eos/build/contracts/eosio.token/eosio.token.wasm...
Using already assembled WASM...
Publishing contract...
executed transaction: 9ff87dffe3eb2eeac29a4afd8eec8faa563f6be43cf5142e71cd61d0c4b66244  8072 bytes  976 us

eosio <= eosio::setcode {"account":"eosio.token","vmtype":0,"vmversion":0,"code":"0061736d01000000017f1560037f7e7f0060057f7e...

eosio <= eosio::setabi {"account":"eosio.token","abi":"0e656f73696f3a3a6162692f312e30010c6163636f756e745f6e616d65046e616d65...

warning: transaction executed locally, but may not be confirmed by the network yet

创建代币:
#cleos -u http://nodeos:80  push action eosio.token create '["eosio","1000000000.0000 SYS",0,0,0]' -p eosio.token
executed transaction: 8d7e472fa7309abfa051eed367c552e3e3e8f283530dc3375761d7da2cb298e9  120 bytes  453 us

eosio.token <= eosio.token::create {"issuer":"eosio","maximum_supply":"1000000000.0000 SYS"}

>> warning: transaction executed locally, but may not be confirmed by the network yet

发布代币:
#cleos -u http://nodeos:80 push action eosio.token issue '["eosio","1000000000.0000 SYS","issue"]' -p eosio
cleos -u http://nodeos:80 push action eosio.token issue '["eosio","1000000000.0000 SYS","issue"]' -p eosio
executed transaction: bdf099816554de5849f030a1d26cc40ade29b74c87aff4180796c7c26507d677  128 bytes  343 us

eosio.token <= eosio.token::issue {"to":"eosio","quantity":"1000000000.0000 SYS","memo":"issue"}

warning: transaction executed locally, but may not be confirmed by the network yet

查询代币余额:
#cleos -u http://nodeos:80 get currency balance eosio.token eosio
1000000000.0000 SYS

创建账号:
#cleos -u http://nodeos:80  create account eosio alex EOS6CYWY1q4AAsVV3rzcT1GGQmZcg7yDnA6jZx2KUjHvmZWPv8DQg EOS6CYWY1q4AAsVV3rzcT1GGQmZcg7yDnA6jZx2KUjHvmZWPv8DQg

EOS转账 :
#cleos -u http://nodeos:80  push action eosio.token transfer '["eosio", "alex", "10000.0000 SYS", ""]' -p eosio


3)创建BP,所谓BP就是EOS上的出块节点(block producer),到6月2日 EOS主网上线,全网应该一共21个BP节点,每个节点都要经过EOS的投票选举产生,现在我们的环境里还没有一个被选举的BP节点,所以需要通过抵押EOS的方式进行投票,当投票超过150M个EOS的时候,得票最多的前21个节点就是BP节点了,当然我们的BaaS受部署规模限制,不一样定要到21个节点,所以我们选举4个BP节点,执行如下命令:
部署系统合约

cleos -u http://nodeos:80 set contract eosio eos/build/contracts/eosio.system

Reading WAST/WASM from ./build/contracts/eosio.system/eosio.system.wasm...
Using already assembled WASM...
Publishing contract...
executed transaction: cd1975d3628c1306f1fb58e49d5474d61c829bad42bffb4aeca7488bb041bd4d  40488 bytes  3969 us

eosio <= eosio::setcode {"account":"eosio","vmtype":0,"vmversion":0,"code":"0061736d0100000001ba022f60027f7e0060067f7e7e7f7f...

eosio <= eosio::setabi {"account":"eosio","abi":"0e656f73696f3a3a6162692f312e30050c6163636f756e745f6e616d65046e616d650f7065...

>> warning: transaction executed locally, but may not be confirmed by the network yet 

创建账户bp1作为出块节点:
cleos -u http://nodeos:80 system newaccount eosio bp1 EOS7FNpU6P3yhT7bkf3fs7aNUxb3yNbMXPbn4nsYgh3ZkEhtchEAH EOS7FNpU6P3yhT7bkf3fs7aNUxb3yNbMXPbn4nsYgh3ZkEhtchEAH --stake-net '500.00 SYS' --stake-cpu '500.00 SYS'
1697946ms thread-0   main.cpp:419                  create_action        ] result: {"binargs":"0000000000ea3055000000000000423d00200000"} arg: {"code":"eosio","action":"buyrambytes","args":{"payer":"eosio","receiver":"bp1","bytes":8192}} 
1697948ms thread-0   main.cpp:419                  create_action        ] result: {"binargs":"0000000000ea3055000000000000423d404b4c00000000000453595300000000404b4c0000000000045359530000000000"} arg: {"code":"eosio","action":"delegatebw","args":{"from":"eosio","receiver":"bp1","stake_net_quantity":"500.0000 SYS","stake_cpu_quantity":"500.0000 SYS","transfer":false}} 
executed transaction: bbdeb7aa13953746e93c47b53729ce36ca2d89f16d87b872ebbacd71c2f4fc6b  336 bytes  1831 us

eosio <= eosio::newaccount {"creator":"eosio","name":"bp1","owner":{"threshold":1,"keys":[{"key":"EOS7FNpU6P3yhT7bkf3fs7aNUxb3y...

>> 

eosio <= eosio::buyrambytes {"payer":"eosio","receiver":"bp1","bytes":8192}

>> 

eosio <= eosio::delegatebw {"from":"eosio","receiver":"bp1","stake_net_quantity":"500.0000 SYS","stake_cpu_quantity":"500.0000 ...

>> warning: transaction executed locally, but may not be confirmed by the network yet

导入刚才bp1的私钥:
# cleos -u http://nodeos:80 wallet import 5Je4PsFWinBPXgWQasz7usbv8MLu5AbkcjU41JQr4Suhh34yKPu
imported private key for: EOS7FNpU6P3yhT7bkf3fs7aNUxb3yNbMXPbn4nsYgh3ZkEhtchEAH

注册bp1为bp节点:
# cleos -u http://nodeos:80 system regproducer bp1 EOS7FNpU6P3yhT7bkf3fs7aNUxb3yNbMXPbn4nsYgh3ZkEhtchEAH http://bp1:8888
2155333ms thread-0   main.cpp:419                  create_action        ] result: {"binargs":"000000000000423d000336d1c7309f8c40f9a2d7bf11b6ba3f6b1c699a67d2ad26c003e5313ff1ce1c940f687474703a2f2f6270313a383838380000"} arg: {"code":"eosio","action":"regproducer","args":{"producer":"bp1","producer_key":"EOS7FNpU6P3yhT7bkf3fs7aNUxb3yNbMXPbn4nsYgh3ZkEhtchEAH","url":"http://bp1:8888","location":0}} 
executed transaction: 294568630bd6c733db853ba2aac2245ffeb199d47767b80ddadc1cbf421c6d46  152 bytes  623 us

eosio <= eosio::regproducer {"producer":"bp1","producer_key":"EOS7FNpU6P3yhT7bkf3fs7aNUxb3yNbMXPbn4nsYgh3ZkEhtchEAH","url":"http...

>> warning: transaction executed locally, but may not be confirmed by the network yet

eosio抵押EOS,投票给bp1:
#cleos -u http://nodeos:80 system delegatebw bp1 bp1 '100000000.0000 SYS' '50000000.0000 SYS' --transfer


460701ms thread-0   main.cpp:1083                 operator()           ] act_payload: {"from":"eosio","receiver":"bp1","stake_net_quantity":"100000000.0000 SYS","stake_cpu_quantity":"50000000.0000 SYS","transfer":true} 
2460702ms thread-0   main.cpp:419                  create_action        ] result: {"binargs":"0000000000ea3055000000000000423d0010a5d4e800000004535953000000000088526a74000000045359530000000001"} arg: {"code":"eosio","action":"delegatebw","args":{"from":"eosio","receiver":"bp1","stake_net_quantity":"100000000.0000 SYS","stake_cpu_quantity":"50000000.0000 SYS","transfer":true}} 
executed transaction: 98314189243cf8a38619e9f887c5430d9285f19a6a2977eccc07d838611dd17a  144 bytes  676 us

eosio <= eosio::delegatebw {"from":"eosio","receiver":"bp1","stake_net_quantity":"100000000.0000 SYS","stake_cpu_quantity":"500...

>> warning: transaction executed locally, but may not be confirmed by the network yet

用抵押的EOS投票给bp1:
#cleos -u http://nodeos:80 system voteproducer prods bp1 bp1
2531150ms thread-0   main.cpp:419                  create_action        ] result: {"binargs":"000000000000423d000000000000000001000000000000423d"} arg: {"code":"eosio","action":"voteproducer","args":{"voter":"bp1","proxy":"","producers":["bp1"]}} 
executed transaction: 15c7cd6bd19f41654abb2d4f52f23953f80fd76b2698ef2a713d67c6fa022ee7  120 bytes  905 us

eosio <= eosio::voteproducer {"voter":"bp1","proxy":"","producers":["bp1"]}

>> warning: transaction executed locally, but may not be confirmed by the network yet

到这一步一个最最基本的EOS BaaS就算部署完毕了。

此时你就可以在你的终端上看到类似如下输出:
3302000ms thread-0   producer_plugin.cpp:585       block_production_loo ] Produced block 00000d279a442987... #3367 @ 2018-05-22T15:55:02.000 signed by bp1 [trxs: 0, lib: 3366, confirmed: 0]

0 个评论

要回复文章请先登录注册