当人们一说到某某即服务的时候总是想到PaaS、SaaS或者IaaS,没错!这次搭建的BaaS也和前面几个类似采用PaaS的设计架构,即用容器的方式搭建BaaS平台。提到容器,就不得不想到现在最流行的Docker+Kubernetes的方式,Docker提供了单机条件下的容器运行环境,Kubernetes提供了一套高可用的容器编排管理系统。本次使用的就是在代码级对Kubernetes做了升级和改造的,由Red Hat公司推出的OpenShift,它使用Kuberenetes作为其内核,对它网络功能做了补充,增加了Web界面,又对原有的Ingress做了优化和升级,所以我们选择它作为本次BaaS的基础平台。
BaaS平台部署图如下图所示:
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界面,选择刚才的模版,输入变量的内容,最后点击生成,如下图所示:
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]
6月22日正式上课,点击阅读原文链接即可报名。