【译文】如何在Akash网络上部署Solana节点

译者注:

本篇文章将指导你在Akashnet上部署Solana节点。我将尽量使其简短,同时保持所有必要的步骤,并贯穿整个部署流程。

特别提醒:

作者指出,这不是Solana节点的生产环境部署,而是测试环境的部署,原因在文末有提到。

我使用Ubuntu 20.04.2 LTS Linux发行版及以下软件:

  • akash: v0.12.1 (在Akashnet上运行)。
  • solana:v1.6.10(用于在Akashnet上部署)。

先认识这两个新东西:

  • Akashnet 是未来的去中心化云;
  • Solana 是一个高性能的区块链,支持全球范围内的开发者创建如今可扩展的加密货币应用程序。

这个想法很简单–利用 Akashnet decloud 来部署 Solana 节点。

在运行一个实例的情况下,Akashnet 要比亚马逊 AWS 服务器便宜将近 86%,这是 Akashlytics 给出的几个云平台价格对比:Akashlytics

话不多说,为了节省你我的时间,以下让我们直接跳到命令行界面的步骤。

一、安装 Akash 客户端

AKASH_VERSION="$(curl -s "$AKASH_NET/version.txt")"
curl https://raw.githubusercontent.com/ovrclk/akash/master/godownloader.sh | sh -s -- "v$AKASH_VERSION"

译者注:

为了后续命令能执行,你需要安装 jq 工具,对命令的 JSON 结果美化和过滤。

检查 jq 工具是否安装:

$ jq --version
jq-1.6

安装后将返回 jq 版本,如果没有安装,可以使用如下命令:

sudo apt install -y jq

二、创建你的 Akash 钱包

akash keys add default

这个命令将输出助记词,确保将其保存在一个安全的地方。

它还会输出你的地址,在我的例子中,地址是 akash1h24fljt7p0nh82cq0za0uhsct3sfwsfu9w3c9h

export AKASH_ACCOUNT_ADDRESS=akash1h24fljt7p0nh82cq0za0uhsct3sfwsfu9w3c9h

更多关于 Akash 钱包介绍请参考:Page not found - Akash Guidebook

三、为你的 Akash 钱包充值

你需要大约10个 AKT(Akash 代币)来开始,你可以在这里提到的任何一个交易所购买:https://akash.network/token。

译者注:

这里实际只需要大于 5AKT即可。

查询你的钱包的余额:

export AKASH_NET="https://raw.githubusercontent.com/ovrclk/net/master/mainnet"
export AKASH_NODE="$(curl -s "$AKASH_NET/rpc-nodes.txt" | shuf -n 1)"

akash \
  --node "$AKASH_NODE" \
  query bank balances "$AKASH_ACCOUNT_ADDRESS"

换算:1 akt = 1000000 uakt (akt*10^6)

或者你也可以执行如下命令进行换算:

akash \
  --node "$AKASH_NODE" \
  query bank balances "$AKASH_ACCOUNT_ADDRESS" \
  -o json | jq -r '(.balances[0].amount | tonumber / pow(10; 6))'

我正在使用生产环境 Akashnet-2 网络,更多关于 Akash 不同网络的信息请参考:Page not found - Akash Guidebook

四、创建证书文件

要创建一个部署,首先必须创建一个证书。命令如下:

export AKASH_CHAIN_ID="$(curl -s "$AKASH_NET/chain-id.txt")"
akash tx cert create client \
  --from default \
  --chain-id $AKASH_CHAIN_ID \
  --node $AKASH_NODE \
  --gas-prices="0.025uakt" --gas="auto" --gas-adjustment=1.15

每个帐户只需要创建一次证书,并且可以在所有部署中使用。

更多关于证书的信息请参考:Page not found - Akash Guidebook

五、准备部署清单文件

创建一个名为solana.yml的文件,内容如下:

---
version: "2.0"

services:
  solana:
    image: solanalabs/solana:v1.6.10
    expose:
      - port: 8899
        as: 8899
        proto: tcp
        to:
          - global: true

profiles:
  compute:
    solana:
      resources:
        cpu:
          units: 0.1
        memory:
          size: 512Mi
        storage:
          size: 512Mi
  placement:
    akash:
      attributes:
        host: akash
      signedBy:
        anyOf:
          - "akash1365yvmc4s7awdyj3n2sav7xfx76adc6dnmlx63"
      pricing:
        solana: 
          denom: uakt
          amount: 10

deployment:
  solana:
    akash:
      profile: solana
      count: 1

清单文件中的关键字说明:

  • pricing

    请注意,可能有多个不同供应商的出价。在这种情况下,两个供应商恰好都愿意接受 1uAKT 的价格,这意味着可以使用每个区块 1 uAKT或 0.000001 AKT 创建租赁来执行容器。

    有了定价的限制,供应商就能知道如何对你的部署进行投标。即您愿意支付的每个区块的 uakt 数量(每个区块每 6 秒发生一次)。

    因此,如果使用 1uakt,您将每月支付 1.44 美元(截至 2021年5月31日 1akt 价值3.28美元)。

    计算公式:((1*((60/6)*60*24*30.436875))/10^6)*3.28=$1.44

  • signedBy

    必须是:akash1365yvmc4s7awdyj3n2sav7xfx76adc6dnmlx63

    相关文档:Akash Deploy UI (Web App) - Akash Guidebook

    signedBy是一种“验证”,在供应商获得 akash 批准后,他们会得到 akash 的签名以确保安全性和可靠性。

注:

更多关于编写 Akash 清单的 SDL(堆栈定义语言)的信息:Page not found - Akash Guidebook

六、创建你的部署

akash tx deployment create solana.yml \
  --from default \
  --node $AKASH_NODE \
  --chain-id $AKASH_CHAIN_ID \
  --gas-prices="0.025uakt" --gas="auto" --gas-adjustment=1.15

如果这个命令出现如下错误:Error: RPC error -32603 - Internal error: timed out waiting for tx to be included in a block,请不用担心,您可以查询 akash 区块链以找到您的部署 ID:

$ akash query txs \
  --events "message.sender=$AKASH_ACCOUNT_ADDRESS&message.action=create-deployment" \
  --page 1 --limit 999999 \
  | jq -r '.txs[] | [ .tx.body.messages[].id[] ] | @csv' | \
  tail -5

# 下面是命令返回:
"akash1h24fljt7p0nh82cq0za0uhsct3sfwsfu9w3c9h","1172777"

译者注:

执行后会返回部署的 DSEQ ,后面会使用到。例如这里的 1172777

查询部署情况:

注:

为了避免后面执行命令akash tx deployment create出现这个错误:failed to execute message; message index: 0: Deployment closed,我实际没有“导出”以下 3 个“SEQ”变量。

如果你遇到了这个错误,可以使用 unset AKASH_DSEQ

$ AKASH_DSEQ=1172777
$ AKASH_GSEQ=1
$ AKASH_OSEQ=1

$ akash query deployment get \
  --owner $AKASH_ACCOUNT_ADDRESS \
  --node $AKASH_NODE \
  --dseq $AKASH_DSEQ

deployment:
  created_at: "1172779"
  deployment_id:
    dseq: "1172777"
    owner: akash1h24fljt7p0nh82cq0za0uhsct3sfwsfu9w3c9h
  state: active
  version: R+bMsK3+N7Wtf8MWmUqoIJTgagXPunxFJqV4EXZahYE=
escrow_account:
  balance:
    amount: "5000000"
    denom: uakt
  id:
    scope: deployment
    xid: akash1h24fljt7p0nh82cq0za0uhsct3sfwsfu9w3c9h/1172777
  owner: akash1h24fljt7p0nh82cq0za0uhsct3sfwsfu9w3c9h
  settled_at: "1172791"
  state: open
  transferred:
    amount: "0"
    denom: uakt
groups:
- created_at: "1172779"
  group_id:
    dseq: "1172777"
    gseq: 1
    owner: akash1h24fljt7p0nh82cq0za0uhsct3sfwsfu9w3c9h
  group_spec:
    name: akash
    requirements:
      attributes:
      - key: host
        value: akash
      signed_by:
        all_of: []
        any_of:
        - akash1365yvmc4s7awdyj3n2sav7xfx76adc6dnmlx63
    resources:
    - count: 1
      price:
        amount: "10"
        denom: uakt
      resources:
        cpu:
          attributes: []
          units:
            val: "100"
        endpoints:
        - kind: RANDOM_PORT
        memory:
          attributes: []
          quantity:
            val: "536870912"
        storage:
          attributes: []
          quantity:
            val: "536870912"
  state: open

你可能已经注意到,这5个AKT现在已经在 escrow_account 下,你的 Akash 钱包余额也相应减少。在你创建一个租赁时,这些代币将被此部署使用。当你关闭租赁/部署时,它们将被退回(除去少数用于租赁本身的代币)。

更多关于部署的信息:Page not found - Akash Guidebook

七、查询市场的出价

现在,我们想实际运行我们的部署,我们需要看看市场的报价,接受我们感到满意的出价,创建租赁并发送部清单,使其启动并运行。

$ akash query market bid list \
  --owner=$AKASH_ACCOUNT_ADDRESS \
  --node $AKASH_NODE \
  --dseq $AKASH_DSEQ \
  --state open

bids:
- bid:
    bid_id:
      dseq: "1172777"
      gseq: 1
      oseq: 1
      owner: akash1h24fljt7p0nh82cq0za0uhsct3sfwsfu9w3c9h
      provider: akash10cl5rm0cqnpj45knzakpa4cnvn5amzwp4lhcal
    created_at: "1172780"
    price:
      amount: "1"
      denom: uakt
    state: open
  escrow_account:
    balance:
      amount: "50000000"
      denom: uakt
    id:
      scope: bid
      xid: akash1h24fljt7p0nh82cq0za0uhsct3sfwsfu9w3c9h/1172777/1/1/akash10cl5rm0cqnpj45knzakpa4cnvn5amzwp4lhcal
    owner: akash10cl5rm0cqnpj45knzakpa4cnvn5amzwp4lhcal
    settled_at: "1172780"
    state: open
    transferred:
      amount: "0"
      denom: uakt
- bid:
    bid_id:
      dseq: "1172777"
      gseq: 1
      oseq: 1
      owner: akash1h24fljt7p0nh82cq0za0uhsct3sfwsfu9w3c9h
      provider: akash1f6gmtjpx4r8qda9nxjwq26fp5mcjyqmaq5m6j7
    created_at: "1172780"
    price:
      amount: "1"
      denom: uakt
    state: open
  escrow_account:
    balance:
      amount: "50000000"
      denom: uakt
    id:
      scope: bid
      xid: akash1h24fljt7p0nh82cq0za0uhsct3sfwsfu9w3c9h/1172777/1/1/akash1f6gmtjpx4r8qda9nxjwq26fp5mcjyqmaq5m6j7
    owner: akash1f6gmtjpx4r8qda9nxjwq26fp5mcjyqmaq5m6j7
    settled_at: "1172780"
    state: open
    transferred:
      amount: "0"
      denom: uakt
pagination:
  next_key: null
  total: "0"

AKASH_PROVIDER环境变量设置为你从可用市场出价中选择的那个:

AKASH_PROVIDER=akash10cl5rm0cqnpj45knzakpa4cnvn5amzwp4lhcal

如果akash query market bid list没有显示任何出价,请确保使用这个命令unset AKASH_PROVIDER来重置环境变量。

八、创建租赁/接受投标

akash tx market lease create \
  --chain-id $AKASH_CHAIN_ID \
  --node $AKASH_NODE \
  --owner $AKASH_ACCOUNT_ADDRESS \
  --dseq $AKASH_DSEQ \
  --gseq $AKASH_GSEQ \
  --oseq $AKASH_OSEQ \
  --provider $AKASH_PROVIDER \
  --from default \
  --gas-prices="0.025uakt" --gas="auto" --gas-adjustment=1.15

注:

一旦创建租约,提供商将开始从您部署的托管账户中扣除费用,即使您尚未通过在以下步骤中上传清单来完成部署过程。

九、发送部署清单到 Solana 节点

现在,为了开始部署你的 Solana,你需要将清单发送给供应商。

akash provider send-manifest solana.yml \
  --node $AKASH_NODE \
  --dseq $AKASH_DSEQ \
  --provider $AKASH_PROVIDER \
  --from default

几分钟后,你就能看到你的部署。

akash provider lease-status \
  --node $AKASH_NODE \
  --dseq $AKASH_DSEQ \
  --provider $AKASH_PROVIDER \
  --from default

你将看到如下返回:

{
  "services": {
    "solana": {
      "name": "solana",
      "available": 1,
      "total": 1,
      "uris": null,
      "observed_generation": 1,
      "replicas": 1,
      "updated_replicas": 1,
      "ready_replicas": 1,
      "available_replicas": 1
    }
  },
  "forwarded_ports": {
    "solana": [
      {
        "host": "cluster.sjc1p0.mainnet.akashian.io",
        "port": 8899,
        "externalPort": 32509,
        "proto": "TCP",
        "available": 1,
        "name": "solana"
      }
    ]
  }
}

端点 URI 是cluster.sjc1p0.mainnet.akashian.io:32509,现在为什么端口是32509而不是8899? 你会在这篇文章的结尾找到原因(见 nodePort)。

十、在 Akashnet 上查看你的 Solana 容器的日志

您可以在这里看到 Solana 节点的助记词:

$ akash \
  --node "$AKASH_NODE" \
  provider lease-logs \
  --dseq "$AKASH_DSEQ" \
  --gseq "$AKASH_GSEQ" \
  --oseq "$AKASH_OSEQ" \
  --provider "$AKASH_PROVIDER" \
  --from default \
  --follow
[solana-648bbc8979-hrjq6] solana-faucet 1.6.10 (src:5d4654d2; feat:3533521759)
[solana-648bbc8979-hrjq6] solana-genesis 1.6.10 (src:5d4654d2; feat:3533521759)
[solana-648bbc8979-hrjq6] solana-keygen 1.6.10 (src:5d4654d2; feat:3533521759)
[solana-648bbc8979-hrjq6] solana-validator 1.6.10 (src:5d4654d2; feat:3533521759)
[solana-648bbc8979-hrjq6] + solana address
[solana-648bbc8979-hrjq6] Error: No such file or directory (os error 2)
[solana-648bbc8979-hrjq6] + echo Generating default keypair
[solana-648bbc8979-hrjq6] Generating default keypair
[solana-648bbc8979-hrjq6] + solana-keygen new --no-passphrase
[solana-648bbc8979-hrjq6] Generating a new keypair
[solana-648bbc8979-hrjq6] Wrote new keypair to /root/.config/solana/id.json
[solana-648bbc8979-hrjq6] ==============================================================================
[solana-648bbc8979-hrjq6] pubkey: 2tpqeMBuqQNd2F6pmQmb2Dyj1A6k2yqqCnWXuWh2pX14
[solana-648bbc8979-hrjq6] ==============================================================================
[solana-648bbc8979-hrjq6] Save this seed phrase to recover your new keypair:
[solana-648bbc8979-hrjq6] wagon layer regret misery divorce wild noodle rent actress reflect sister lift
[solana-648bbc8979-hrjq6] ==============================================================================
...
[solana-648bbc8979-hrjq6] [2021-05-31T13:06:27.045978808Z INFO  solana_core::cluster_info] 
[solana-648bbc8979-hrjq6]     IP Address        |Age(ms)| Node identifier                              | Version |Gossip| TPU  |TPUfwd| TVU  |TVUfwd|Repair|ServeR|ShredVer
[solana-648bbc8979-hrjq6]     ------------------+-------+----------------------------------------------+---------+------+------+------+------+------+------+------+--------
[solana-648bbc8979-hrjq6]     127.0.0.1       me|  4558 | 3QDTDmtqV3rLDdkLVPzP5RLg9TdXLFA7QPzv6Eeo72fi | 1.6.10  | 8001 | 8003 | 8004 | 8000 | 8002 | 8006 | 8007 | 48122
[solana-648bbc8979-hrjq6]     Nodes: 1
[solana-648bbc8979-hrjq6]     
[solana-648bbc8979-hrjq6]     RPC Address       |Age(ms)| Node identifier                              | Version | RPC  |PubSub|ShredVer
[solana-648bbc8979-hrjq6]     ------------------+-------+----------------------------------------------+---------+------+------+--------
[solana-648bbc8979-hrjq6]     127.0.0.1       me|  4558 | 3QDTDmtqV3rLDdkLVPzP5RLg9TdXLFA7QPzv6Eeo72fi | 1.6.10  | 8899 | 8900 | 48122
[solana-648bbc8979-hrjq6]     RPC Enabled Nodes: 1
...

十一、在 Akashnet 上查询你的 Solana 节点

使用 Solana 的 json RPC API,你可以查询到你的 Solana 节点。

译者注:

为了读者能正确执行命令和区分,这里修改了命令格式,并将三条命令分开展示且加了注释。

查询当前块的时间:

$ curl -s http://cluster.sjc1p0.mainnet.akashian.io:32509 -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":1, "method":"getBlockTime","params":[5]}' | jq -r '.result | todate'

查询验证者:

$ curl -s http://cluster.sjc1p0.mainnet.akashian.io:32509 -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":1, "method":"getIdentity"}'

查询集群节点:

$ curl -s http://cluster.sjc1p0.mainnet.akashian.io:32509 -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0", "id":1, "method":"getClusterNodes"}' | jq .

十二、终止部署

当你完成测试后,你可以终止部署。

akash tx deployment close \
  --node $AKASH_NODE \
  --chain-id $AKASH_CHAIN_ID \
  --dseq $AKASH_DSEQ \
  --owner $AKASH_ACCOUNT_ADDRESS \
  --from default \
  --gas-prices="0.025uakt" --gas="auto" --gas-adjustment=1.15

十三、存入更多的 AKT 以供部署

如果你对部署感到满意,并不想有一天停止,你可以存入更多AKT代币到托管账户:

akash tx deployment deposit \
  --from default \
  --chain-id $AKASH_CHAIN_ID \
  --node $AKASH_NODE 1000000uakt \
  --dseq $AKASH_DSEQ \
  --gas-prices="0.025uakt" --gas="auto" --gas-adjustment=1.15

十四、生产环境 Solana 验证者节点

对于生产环境 Solana 验证者节点部署,您将需要按照如下方式修改您的清单文件,可能还需要按照推荐的方式提高 cpu、内存和储存限制。

Solana 验证者运行文档:Validator Requirements | Solana Docs

---
version: "2.0"

services:
  solana:
    image: solanalabs/solana:v1.6.10
    expose:
      - port: 8899
        as: 8899
        proto: tcp
        to:
          - global: true
      - port: 8001
        as: 8001
        proto: tcp
        to:
          - global: true
      - port: 8900
        as: 8900
        proto: tcp
        to:
          - global: true
      - port: 8010
        as: 8010
        proto: udp
        to:
          - global: true
      - port: 8011
        as: 8011
        proto: udp
        to:
          - global: true
      - port: 8012
        as: 8012
        proto: udp
        to:
          - global: true
      - port: 8013
        as: 8013
        proto: udp
        to:
          - global: true
      - port: 8014
        as: 8014
        proto: udp
        to:
          - global: true
      - port: 8015
        as: 8015
        proto: udp
        to:
          - global: true
      - port: 8016
        as: 8016
        proto: udp
        to:
          - global: true
      - port: 8017
        as: 8017
        proto: udp
        to:
          - global: true
      - port: 8018
        as: 8018
        proto: udp
        to:
          - global: true
      - port: 8019
        as: 8019
        proto: udp
        to:
          - global: true
      - port: 8020
        as: 8020
        proto: udp
        to:
          - global: true
    env:
      - SOLANA_RUN_SH_CLUSTER_TYPE=mainnet-beta
      - |
        SOLANA_RUN_SH_VALIDATOR_ARGS=
        --trusted-validator 7Np41oeYqPefeNQEHSv1UDhYrehxin3NStELsSKCT4K2
        --trusted-validator GdnSyH3YtwcxFvQrVVJMm1JhTS4QVX7MFsX56uJLUfiZ
        --trusted-validator DE1bawNcRJB9rVm3buyMVfr8mBEoyyu73NBovf2oXJsJ
        --trusted-validator CakcnaRDHka2gXyfbEd2d3xsvkJkqsLw2akB3zsN1D2S
        --no-untrusted-rpc
        --private-rpc
        --entrypoint entrypoint.mainnet-beta.solana.com:8001
        --entrypoint entrypoint2.mainnet-beta.solana.com:8001
        --entrypoint entrypoint3.mainnet-beta.solana.com:8001
        --entrypoint entrypoint4.mainnet-beta.solana.com:8001
        --entrypoint entrypoint5.mainnet-beta.solana.com:8001
        --expected-genesis-hash 5eykt4UsFv8P8NJdTREpY1vzqKqZKvdpKuc147dw2N9d
        --wal-recovery-mode skip_any_corrupted_record
        --limit-ledger-size
        --dynamic-port-range 8010-8020

profiles:
  compute:
    solana:
      resources:
        cpu:
          units: 0.1
        memory:
          size: 512Mi
        storage:
          size: 512Mi
  placement:
    akash:
      attributes:
        host: akash
      signedBy:
        anyOf:
          - "akash1365yvmc4s7awdyj3n2sav7xfx76adc6dnmlx63"
      pricing:
        solana: 
          denom: uakt
          amount: 10

deployment:
  solana:
    akash:
      profile: solana
      count: 1

您可能需要公开更多端口,例如--dynamic-port-range 8010-8020参数中指定的端口。

唯一要注意的是,它无法直接映射出非 HTTP / HTTPS(80/443)TCP 端口,这就是所说的 nodePort 端口,如8899/tcp8010:8020/udp。Akashnet 供应商在后台使用 Kubernetes 来实际运行您的容器。Kubernetes 控制平面从--service-node-port-range标志(default: 30000-32767)(nodePort)指定的范围内分配一个端口,这意味着运营商必须首先部署 Solana 节点,然后检查提供商的 Kubernetes 分配给您的 Akash 部署的端口。然后使用一些负载均衡器/反向代理(即nginx/haprorxy/traefik)转发到这些端口。您还需要通过--public-rpc-address 来指定 Solana 验证者节点的参数,告诉 Solana 验证器使用负载平衡器的主机名。

然而,本文的目标是展示 Akashnet 而不是完整的生产 Solana 节点。
Solana 官方文档不推荐将 Docker 用于生产部署,尽管生产 Solana 节点应该在12 核、128Gi RAM、500Gi+ SSD 上运行,但 Akashnet 目前还没有提供,因为它是一个非常新的网络并且没有这么多供应商呢。这也不是一个投资建议。

如果你喜欢这篇文章,请在这里投票https://forum.akash.network/t/twitter-deploy-challenge-solana-on-akash/160

附加说明:

对我自己(或其他任何想从这里学习并进一步推动它的人)的注意事项: