[Serverless] OpenWhisk

OpenWhisk 是由 IBM 开源的一个 FaaS 计算平台,在2016年贡献给了开源社区,2019年正式成为 Apache 基金会的顶级项目。

OpenWhisk 本身是一个事件驱动 (Event driven architecture) 的 FaaS (Function as a Service) 计算平台,用户只需要关注业务代码的逻辑,将操作代码发送给 OpenWhisk ,并提供所需的数据流,OpenWhisk 就能自动的对计算资源进行扩展。开发者无需关心相关的基础设施架构,虽说理论上有效的提高了开发效率,可以使开发人员可以将精力放在代码逻辑上,不过 Serverless 平台的开发体验还是颇受诟病的,由于无法接触到实际的运行环境,不管是开发还是 debug 都比较不方便,只通过 log 方式调试错误。

准备工作

试水 OpenWhisk ,你可以直接试试 IBM Bluemix, 这是 IBM 公司提供的一个 FaaS 服务,参考这篇文章

或者你也可以在本地自己构建一个 OpenWhisk 的平台,由于官方提供了完善的部署方案,所以现在你只需要:

  • Ubuntu (其他发行版也是可以的)

  • Git

依赖

比较棒的是,官方提供了脚本解决所有依赖的问题

1
2
3
4
5
6
7
8
9
10
11
# Install git if it is not installed
$ sudo apt-get install git -y

# Clone openwhisk
$ git clone https://github.com/apache/openwhisk.git openwhisk

# 转移到 openwhisk 文件夹
$ cd openwhisk

# 安装所有依赖
$ cd tools/ubuntu-setup && ./all.sh

数据库

这里需要一个 NoSQL 数据来支撑 OpenWhisk 的数据持久化、用户鉴权认证等能力,就决定是你了—— CouchDB.

1
2
3
4
5
6
7
8
9
10
11
# 校验
$ curl -L https://couchdb.apache.org/repo/bintray-pubkey.asc | apt-key add -

# 添加apache软件源
$ echo "deb https://apache.bintray.com/couchdb-deb bionic main" | tee -a /etc/apt/sources.list

# 更新软件源
$ sudo apt-get update

# 安装 couchdb
$ sudo apt-get install -y couchdb

此时会看到下图,选择单节点 standalone:

安装模式.png

绑定 IP 0.0.0.0 :

绑定地址.png

接下来设置并确认用户 admin 的密码,就不放图了。

安装完成后,可以使用 $ sudo service couchdb status 查看 couchdb 的运行状态:

couchdb.png

也可以试着访问 http://127.0.0.1:5984/_utils/ ,可以看到 CouchDB 的管理界面。

couchdb界面.png

当然也可以直接使用 REST API 来对数据库进行操作:

1
2
3
4
5
$ curl http://admin:password@127.0.0.1:5984/_all_dbs
["_global_changes","_replicator","_users"]

$ curl http://admin:password@127.0.0.1:5984/_global_changes
{"db_name":"_global_changes","update_seq":"4-g1AAAAFTeJzLYWBg4MhgTmEQTM4vTc5ISXLIyU9OzMnILy7JAUoxJTIkyf___z8rkQGPoiQFIJlkD1bHiE-dA0hdPGHzEkDq6gmal8cCJBkagBRQ6Xz8ZkLULoCo3U-M2gMQtfeJUfsAohboXqYsANYbbzI","sizes":{"file":13699,"external":16,"active":860},"purge_seq":0,"other":{"data_size":16},"doc_del_count":0,"doc_count":4,"disk_size":13699,"disk_format_version":6,"data_size":860,"compact_running":false,"cluster":{"q":8,"n":1,"w":1,"r":1},"instance_start_time":"0"}

安装 OpenWhisk

之前已经将 OpenWhisk 的仓库拉取下来了,现在请先回到 $ cd openwhisk 的目录下,OpenWhisk 还提供了 ansible 工具,极大简化了安装的过程。

  • 首先请先确保一下端口没有被占用:

    • 80, 443, 9000, 9001, and 9090 for the API Gateway

    • 6379 for Redis

    • 2181 for Zookeeper

    • 5984 for CouchDB

    • 8085, 9333 for OpenWhisk’s Invoker

    • 8888, 9222 for OpenWhisk’s Controller

    • 9092 for Kafka

    • 8001 for Kafka Topics UI

      注意:

      所有涉及 Ansible 的操作都需要在 ansible 路径下执行,这是由于 ansible/ansible.cfg 中包含了所有的通用设定。

  • 切换到 ansible 路径

    1
    $ cd ansible
  • 设置数据库的环境变量

    1
    2
    3
    4
    5
    $ export OW_DB_PROTOCOL=http
    $ export OW_DB_HOST=<public IP>
    $ export OW_DB_PORT=5984
    $ export OW_DB_USERNAME=admin
    $ export OW_DB_PASSWORD=password

    注:

    <public IP> 填写本机 IP,可以用 ip a 查看

    password 填写之前设置的数据库密码

  • 生成初始配置,这一步在开发环境中必须先执行,它会根据你的环境生成一个 hosts 配置文件

    1
    $ ansible-playbook setup.yml

    如果需要,可以在配置文件中加入多个节点的信息,在使用 Ansible 时加入 -e mode=HA 的选项启用高可用,在多个服务器中配置多个 Kafka, invokers 的实例。

    这一步有问题,可以尝试 (后同):

    1
    $ ansible-playbook -i environments/local setup.yml
  • 在所有 openwhisk 节点上安装环境依赖 (其实在单节点的配置中,这一步可以不做,所有依赖都已经装上了)

    1
    $ ansible-playbook prereq.yml
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    Gathering Facts ------------------------ 0.78s
    prereq : install docker for python ----- 0.66s
    prereq : install requests -------------- 0.64s
    prereq : install httplib2 -------------- 0.64s
    Gathering Facts ------------------------ 0.55s
    Gathering Facts ------------------------ 0.55s
    Gathering Facts ------------------------ 0.55s
    prereq : check for pip ----------------- 0.44s
    prereq : install pip ------------------- 0.03s
    prereq : remove docker ----------------- 0.03s
    prereq : remove requests --------------- 0.03s
    prereq : remove httplib2 --------------- 0.02s
  • 构建 docker 镜像

    1
    2
    3
    4
    5
    # 切换到 openwhisk 目录
    $ cd ..

    # 构建镜像
    $ ./gradlew distDocker
  • 部署安装

    1
    2
    3
    4
    5
    6
    $ cd ./ansible

    $ ansible-playbook initdb.yml
    $ ansible-playbook wipe.yml
    $ ansible-playbook openwhisk.yml
    $ ansible-playbook postdeploy.yml

    注:

    initdb.yml 在每次新部署并初始化 CounchDB 时都需要运行一次

    wipe.yml 每次部署前需要运行一次

    $ ansible-playbook openwhisk.yml 避免在重启后数据库数据丢失,这一步会拉取很多镜像,花的时间很长,耐心等待

    同样的用法使用 apigateway.ymlroutermgmt.yml 启用 API 网关

  • 安装完成后,可以使用 docker ps -a 查看所有容器的运行状态:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    CONTAINER ID        IMAGE                            COMMAND                  CREATED             STATUS              PORTS                                                                                                 NAMES
    73c17753ad74 nginx:1.13 "nginx -g 'daemon of…" 2 minutes ago Up 2 minutes 0.0.0.0:80->80/tcp, 0.0.0.0:443->443/tcp, 0.0.0.0:8443->8443/tcp nginx
    b51d882d6295 openwhisk/nodejs6action:latest "/bin/sh -c 'node --…" 2 minutes ago Up 2 minutes wsk00_4_prewarm_nodejs6
    cb6d90d7fce5 openwhisk/nodejs6action:latest "/bin/sh -c 'node --…" 2 minutes ago Up 2 minutes wsk00_2_prewarm_nodejs6
    e83e0a8ff8a3 whisk/invoker:latest "/bin/sh -c 'exec /i…" 2 minutes ago Up 2 minutes 0.0.0.0:17000->17000/tcp, 0.0.0.0:18000->18000/tcp, 0.0.0.0:12001->8080/tcp invoker0
    3f1287e56e07 whisk/controller:latest "/bin/sh -c 'exec /i…" 10 minutes ago Up 10 minutes 0.0.0.0:15000->15000/tcp, 0.0.0.0:16000->16000/tcp, 0.0.0.0:8000->2551/tcp, 0.0.0.0:10001->8080/tcp controller0
    e4f4b8a35182 wurstmeister/kafka:0.11.0.1 "start-kafka.sh" 10 minutes ago Up 10 minutes 0.0.0.0:9072->9072/tcp, 0.0.0.0:9093->9093/tcp kafka0
    db10c72113e4 zookeeper:3.4 "/docker-entrypoint.…" 10 minutes ago Up 10 minutes 0.0.0.0:2181->2181/tcp, 0.0.0.0:2888->2888/tcp, 0.0.0.0:3888->3888/tcp zookeeper0
    71df5847d252 redis:3.2 "docker-entrypoint.s…" 22 minutes ago Up 22 minutes 0.0.0.0:6379->6379/tcp redis
  • 将二进制文件加入到 PATH

    1
    2
    $ cd ../bin
    $ export PATH=$PATH:$PWD
  • 安装完成

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    $ wsk


    ____ ___ _ _ _ _ _
    /\ \ / _ \ _ __ ___ _ __ | | | | |__ (_)___| | __
    /\ /__\ \ | | | | '_ \ / _ \ '_ \| | | | '_ \| / __| |/ /
    / \____ \ / | |_| | |_) | __/ | | | |/\| | | | | \__ \ <
    \ \ / \/ \___/| .__/ \___|_| |_|__/\__|_| |_|_|___/_|\_\
    \___\/ tm |_|

    Usage:
    wsk [command]

    Available Commands:
    action work with actions
    activation work with activations
    package work with packages
    rule work with rules
    trigger work with triggers
    sdk work with the sdk
    property work with whisk properties
    namespace work with namespaces
    list list entities in the current namespace
    api work with APIs
    project The OpenWhisk Project Management Tool

    Flags:
    --apihost HOST whisk API HOST
    --apiversion VERSION whisk API VERSION
    -u, --auth KEY authorization KEY
    --cert string client cert
    -d, --debug debug level output
    -h, --help help for wsk
    -i, --insecure bypass certificate checking
    --key string client key
    -v, --verbose verbose output

    可以看到 wsk 命令的相关说明。


Demo

设置 API host,在单机配置中的 IP 应该为 172.17.0.1。

1
$ wsk property set –apihost 172.17.0.1

设置 key (注意在 openwhisk 路径下执行)

1
$ wsk property set --auth `cat ansible/files/auth.guest`

创建一个测试文件 hello.js

1
$ sudo nano hello.js

简单的demo,复制以下代码

1
2
3
4
5
6
7
/**
* Hello world as an OpenWhisk action.
*/
function main(params) {
var name = params.name || 'World';
return {payload: 'Hello, ' + name + '!'};
}

创建 action

1
$ wsk -i action create hello hello.js

通过 wsk 命令调用上面的 action ,加入 -i 可以禁用认证服务

1
2
3
4
$ wsk -i action invoke hello --result
{
"payload": "Hello, World!"
}

参考