如何将Beem / Hive程序在AWS Lambda上运行 (How to deploy beem application to AWS Lambda)

Words
1237
Reading
6 min
Listen
Play
6y

大约两,三年前就开始在VPS上跑Steem的程序了,后来有了Hive链,也开始跑Hive的程序。其实Steem/Hive的Python库还是很好用的。于是就有了几个Cronjob,点点赞,领取一些收益之类的。但近期随着对AWS服务了解的越来越多。感觉再在VPS跑Cronjob似乎有点Out了。于是开始考虑把一系列的Cronjob都搬到AWS上来,这样做最大的优势就是避免了以后服务器的维护成本。不用再考虑升级Ubuntu的各个版本/打各种安全补丁了。同时,也能节省一些银子。相信我,AWS的一系列Serverless服务真正用起来之后,在这些服务上的花费真的比想象中的要低不少。

image

下面就以一个最简单的Beem/Hive程序为例来说明。假设我们想把下面这个Python程序挪到AWS Lambda中去:

from beem.vote import Vote

vote = Vote(u"@aafeng/bolton-abbey|abit")
print(vote.json())

上面这个程序非常简单,只是返回一个包含A神对我的一篇文章的点赞数据。

下面来说说如何在AWS Lambda中运行这个程序。整个过程中遇到了两个坑,下面会详细说。

这里有一个前提条件,就是已经安装了serverless框架。如果没有安装,请先自行安装,并配置好AWS的账号信息(~/.aws/credentials)。

创建Lambda依赖库(layer)

这一步需要在一个AWS Linux的EC2中运行,后面说到第一个坑的时候会详细介绍。当然,在网上也看到有人说可以创建一个AWS Linux的docker镜像,然后在docker镜像中运行pip来安装Python依赖库。但我并没有尝试。应该也可以吧。

如果我们想要写一系列的Beem/Hive程序,肯定不想把依赖库打包到每一个Lambda中。因此这里可以创建一个AWS中共享的依赖库(Layer)。

运行:

sls create --template aws-python3 --name beem-layer --path beem-layer

这就会创建如下目录和文件:

beem-layer
├── handler.py
└── serverless.yml

接下来创建目录:

cd beem-layer
mkdir libs
touch libs/requirements.txt

目录结构如下:

→  beem-layer tree .
.
├── handler.py
├── libs
│   └── requirements.txt
└── serverless.yml

requirements.txt内容如下:

beem

安装依赖库:

cd libs
pip install -t python/lib/python3.8/site-packages -r requirements.txt

修改serverless.yml文件如下:

service: my-layers
frameworkVersion: '2'

provider:
  name: aws
  runtime: python3.8
  region: eu-west-1

layers:
  beem-dependencies:
    path: libs
    compatibleRuntimes:
      - python3.8
    description: "Python beem dependencies"

在上面并没有定义Lambda函数,只是定义了layer,因此无需修改默认的handler.py,因为根本不会用到这个文件。

部署:

sls deploy

可以看到,很容易就在AWS中创建了一个layer。

注意:这里有第一个坑! 在后面的应用中使用这个layer的时候,总是提示找不到.so库。花了不少时间才搞清楚其原因在于:在安装Python依赖库时候的环境是Ubuntu 18,而在运行Lambda时候的环境则是Amazon Linux。两者不匹配自然就找不到所有的依赖库了。

因此最为简单的办法就是在Amazon EC2 (with Amazon Linux)中安装Python的依赖库。这样就保持了开发/部署环境和运行环境的一致。

创建Lambda

首先运行如下命令创建serverless APP:

sls create --template aws-python3 --name beem-app --path beem-app

接下来修改serverless.yml:

service: beem-app
frameworkVersion: '2'

provider:
  name: aws
  runtime: python3.8
  region: eu-west-1

functions:
  hello:
    handler: handler.hello
    layers:
      - "YOUR_LAYER_ARN"

修改handler.py:

import json
from beem.vote import Vote

def hello(event, context):
    
    vote = Vote(u"@aafeng/bolton-abbey|abit")
    
    response = {
        "statusCode": 200,
        "body": vote.json()
    }

    return response

部署:

sls deploy

运行

sls invoke -f hello

结果,遇到了第二个坑。提示错误信息如下:

{
    "errorMessage": "[Errno 30] Read-only file system: '/home/sbx_user1051'",
    "errorType": "OSError",
    "stackTrace": [
        "  File \"/var/task/handler.py\", line 6, in hello\n    vote = Vote(u\"@aafeng/bolton-abbey|abit\")\n",
        "  File \"/opt/python/lib/python3.8/site-packages/beem/vote.py\", line 52, in __init__\n    self.blockchain = blockchain_instance or shared_blockchain_instance()\n",
        "  File \"/opt/python/lib/python3.8/site-packages/beem/instance.py\", line 29, in shared_blockchain_instance\n    default_chain = get_default_config_store()[\"default_chain\"]\n",
        "  File \"/opt/python/lib/python3.8/site-packages/beem/storage.py\", line 46, in get_default_config_store\n    return generate_config_store(SqliteConfigurationStore, blockchain=\"hive\")(*args, **kwargs)\n",
        "  File \"/opt/python/lib/python3.8/site-packages/beemstorage/sqlite.py\", line 200, in __init__\n    SQLiteFile.__init__(self, *args, **kwargs)\n",
        "  File \"/opt/python/lib/python3.8/site-packages/beemstorage/sqlite.py\", line 61, in __init__\n    os.makedirs(self.data_dir)\n",
        "  File \"/var/lang/lib/python3.8/os.py\", line 213, in makedirs\n    makedirs(head, exist_ok=exist_ok)\n",
        "  File \"/var/lang/lib/python3.8/os.py\", line 213, in makedirs\n    makedirs(head, exist_ok=exist_ok)\n",
        "  File \"/var/lang/lib/python3.8/os.py\", line 213, in makedirs\n    makedirs(head, exist_ok=exist_ok)\n",
        "  File \"/var/lang/lib/python3.8/os.py\", line 223, in makedirs\n    mkdir(name, mode)\n"
    ]
}

仔细读一下,原来是beem在运行的时候会尝试装载其配置文件,这个文件为~/.local/share/beem/beem.sqlite,如果该文件不存在,beem会尝试创建这个文件。而Lambda运行时只有对”/tmp“目录有写入权限的。因此出现了访问权限问题。

最快捷的解决方法就是直接修改文件:python/lib/python3.8/site-packages/beemstorage/sqlite.py

#self.sqlite_file = os.path.join(self.data_dir, self.storageDatabase)
self.data_dir = "/tmp/"
self.sqlite_file = "/tmp/beem.sqlite"

然后回到Amazon Linux,重新部署依赖库。

然后再调用Lambda:

sls invoke -f hello

返回结果为:

{
    "statusCode": 200,
    "body": {
        "percent": 5000,
        "reputation": "119989167017696",
        "rshares": "13053196760301",
        "time": "2020-10-27T11:27:18",
        "voter": "abit",
        "weight": 1202589,
        "authorpermvoter": "@aafeng/bolton-abbey|abit"
    }
}
如何将Beem / Hive程序在AWS Lambda上运行 (How to deploy beem application to A... | Ecency