上一篇Dapr的运行时环境已经安装完成。今天我们在Standalone模式部署第一个Dapr程序。
程序来自Dapr官方的quickstarts教程里的Hello World,我们用目前的最新版本v1.0.0-rc.2。

$ git clone -b v1.0.0-rc.2 https://github.com/dapr/quickstarts.git
$ cd quickstarts

hello-world下面是Standalone版的,进去看看。

程序很简单,一个Node的程序,提供3个Endpoint(在StateStore里保存,取得,删除发过来的OrderId)。

还有一个Python的程序,每秒发1个HTTP Request给Node程序。

dapr架构 dapr部署_redis

下面开始部署。Standalone模式下首先要先安装Node和Python的运行环境。不然dapr run的时候会报错。
Node的运行环境:

$ sudo apt update
$ sudo apt install nodejs
$ sudo apt install npm
$ sudo npm install
$ npm list

里面有express和body-parser的话就可以用Dapr启动node的程序了。

$ dapr run --app-id nodeapp --app-port 3000 --dapr-http-port 3500 node app.js
ℹ️  Starting Dapr with id nodeapp. HTTP Port: 3500. gRPC Port: 43509
INFO[0000] starting Dapr Runtime -- version 1.0.0-rc.2 -- commit 196483d  app_id=nodeapp instance=PC57-064 scope=dapr.runtime type=log ver=1.0.0-rc.2
INFO[0000] log level set to: info                        app_id=nodeapp instance=PC57-064 scope=dapr.runtime type=log ver=1.0.0-rc.2
INFO[0000] metrics server started on :37057/             app_id=nodeapp instance=PC57-064 scope=dapr.metrics type=log ver=1.0.0-rc.2
INFO[0000] standalone mode configured                    app_id=nodeapp instance=PC57-064 scope=dapr.runtime type=log ver=1.0.0-rc.2
INFO[0000] app id: nodeapp                               app_id=nodeapp instance=PC57-064 scope=dapr.runtime type=log ver=1.0.0-rc.2
INFO[0000] mTLS is disabled. Skipping certificate request and tls validation  app_id=nodeapp instance=PC57-064 scope=dapr.runtime type=log ver=1.0.0-rc.2
INFO[0000] local service entry announced: nodeapp -> 172.17.183.23:44399  app_id=nodeapp instance=PC57-064 scope=dapr.contrib type=log ver=1.0.0-rc.2
INFO[0000] Initialized name resolution to standalone     app_id=nodeapp instance=PC57-064 scope=dapr.runtime type=log ver=1.0.0-rc.2
INFO[0000] component loaded. name: pubsub, type: pubsub.redis  app_id=nodeapp instance=PC57-064 scope=dapr.runtime type=log ver=1.0.0-rc.2
INFO[0000] waiting for all outstanding components to be processed  app_id=nodeapp instance=PC57-064 scope=dapr.runtime type=log ver=1.0.0-rc.2
INFO[0000] component loaded. name: statestore, type: state.redis  app_id=nodeapp instance=PC57-064 scope=dapr.runtime type=log ver=1.0.0-rc.2
INFO[0000] all outstanding components processed          app_id=nodeapp instance=PC57-064 scope=dapr.runtime type=log ver=1.0.0-rc.2
INFO[0000] enabled gRPC tracing middleware               app_id=nodeapp instance=PC57-064 scope=dapr.runtime.grpc.api type=log ver=1.0.0-rc.2
INFO[0000] enabled gRPC metrics middleware               app_id=nodeapp instance=PC57-064 scope=dapr.runtime.grpc.api type=log ver=1.0.0-rc.2
INFO[0000] API gRPC server is running on port 43509      app_id=nodeapp instance=PC57-064 scope=dapr.runtime type=log ver=1.0.0-rc.2
INFO[0000] enabled metrics http middleware               app_id=nodeapp instance=PC57-064 scope=dapr.runtime.http type=log ver=1.0.0-rc.2
INFO[0000] enabled tracing http middleware               app_id=nodeapp instance=PC57-064 scope=dapr.runtime.http type=log ver=1.0.0-rc.2
INFO[0000] http server is running on port 3500           app_id=nodeapp instance=PC57-064 scope=dapr.runtime type=log ver=1.0.0-rc.2
INFO[0000] enabled gRPC tracing middleware               app_id=nodeapp instance=PC57-064 scope=dapr.runtime.grpc.internal type=log ver=1.0.0-rc.2
INFO[0000] enabled gRPC metrics middleware               app_id=nodeapp instance=PC57-064 scope=dapr.runtime.grpc.internal type=log ver=1.0.0-rc.2
INFO[0000] internal gRPC server is running on port 44399  app_id=nodeapp instance=PC57-064 scope=dapr.runtime type=log ver=1.0.0-rc.2
INFO[0000] application host: 127.0.0.1. application protocol: http. waiting on port 3000.  This will block until the app is listening on that port.  app_id=nodeapp instance=PC57-064 scope=dapr.runtime type=log ver=1.0.0-rc.2
== APP == Node App listening on port 3000!

INFO[0000] application discovered on port 3000           app_id=nodeapp instance=PC57-064 scope=dapr.runtime type=log ver=1.0.0-rc.2
INFO[0000] application configuration loaded              app_id=nodeapp instance=PC57-064 scope=dapr.runtime type=log ver=1.0.0-rc.2
INFO[0000] actor runtime started. actor idle timeout: 1h0m0s. actor scan interval: 30s  app_id=nodeapp instance=PC57-064 scope=dapr.runtime.actor type=log ver=1.0.0-rc.2
INFO[0000] dapr initialized. Status: Running. Init Elapsed 418.37829999999997ms  app_id=nodeapp instance=PC57-064 scope=dapr.runtime type=log ver=1.0.0-rc.2
INFO[0000] placement tables updated, version: 0          app_id=nodeapp instance=PC57-064 scope=dapr.runtime.actor.internal.placement type=log ver=1.0.0-rc.2
ℹ️  Updating metadata for app command: node app.js
✅  You're up and running! Both Dapr and your app logs will appear here.

log显示Node程序已经跑起来了。APP自己的HTTP Endpoint端口是3000,Dapr(Sidecar)的HTTP端口是3500。
现在再开另一个窗口,用Dapr CLI执行:

$ dapr invoke --app-id nodeapp --method neworder --data '{"data": { "orderId": "42" } }'
✅  App invoked successfully

成功了。再看看原来的窗口,多了下面两条:

== APP == Got a new order! Order ID: 42

== APP == Successfully persisted state.

显示持久化成功。
用Node程序的GET API确认一下:

$ curl http://localhost:3000/order
{"orderId":42}

用Dapr的API确认一下:

$ curl http://localhost:3500/v1.0/invoke/nodeapp/method/order
{"orderId":"42"}

我们看看数据存在了哪里。用docker ps看看redis跑在哪个Container里:

$ docker ps
CONTAINER ID   IMAGE               COMMAND                  CREATED          STATUS                    PORTS                              NAMES
a51c086c8bbe   daprio/dapr         "./placement"            31 minutes ago   Up 31 minutes             0.0.0.0:50005->50005/tcp           dapr_placement
fdca40421094   redis               "docker-entrypoint.s…"   31 minutes ago   Up 31 minutes             0.0.0.0:6379->6379/tcp             dapr_redis
9dc60b00db4d   openzipkin/zipkin   "start-zipkin"           31 minutes ago   Up 31 minutes (healthy)   9410/tcp, 0.0.0.0:9411->9411/tcp   dapr_zipkin

Container名是dapr_redis。进去看看:

$ docker exec -it dapr_redis redis-cli
127.0.0.1:6379>

看看有什么Key:

127.0.0.1:6379> keys *
1) "nodeapp||order"
127.0.0.1:6379> type nodeapp||order
hash
127.0.0.1:6379> hgetall nodeapp||order
1) "data"
2) "{\"orderId\":\"42\"}"
3) "version"
4) "3"

OK,刚才的orderId(42)找到了。
除了用Dapr CLI保存OrderId,我们还可以用Dapr的API。

$ curl -XPOST -d @sample.json -H "Content-Type:application/json" http://localhost:3500/v1.0/invoke/nodeapp/method/neworder

其中sample.json的内容如下。调用Dapr的invoke API可以起到Dapr CLI(dapr invoke)一样的效果。

{"data":{"orderId":"42"}}

当然我们也可以用Node程序自己的Endpoint,这样不通过Dapr Sidecar。

$ curl -XPOST -d @sample.json -H "Content-Type:application/json" http://localhost:3000/neworder

你也许会问,为什么Redis直接就能用了呢?答案就是Dapr Runtime安装的时候,自动就跑起来了Redis的服务用的Docker Container(配置文件在~/.dapr/components/下面的statestore.yaml和pubsub.yaml),所以基于Redis的statestore和pubsub是开箱即用的。

OK。接下来部署Python的程序。Python也得先装运行环境:

$ sudo apt install python3-pip

用Dapr CLI启动Python程序:

$ dapr run --app-id pythonapp --dapr-http-port 3501 python3 app.py
ℹ️  Starting Dapr with id pythonapp. HTTP Port: 3501. gRPC Port: 34093
ℹ️  Checking if Dapr sidecar is listening on HTTP port 3501
INFO[0000] starting Dapr Runtime -- version 1.0.0-rc.2 -- commit 196483d  app_id=pythonapp instance=PC57-064 scope=dapr.runtime type=log ver=1.0.0-rc.2
INFO[0000] log level set to: info                        app_id=pythonapp instance=PC57-064 scope=dapr.runtime type=log ver=1.0.0-rc.2
INFO[0000] metrics server started on :37435/             app_id=pythonapp instance=PC57-064 scope=dapr.metrics type=log ver=1.0.0-rc.2
INFO[0000] standalone mode configured                    app_id=pythonapp instance=PC57-064 scope=dapr.runtime type=log ver=1.0.0-rc.2
INFO[0000] app id: pythonapp                             app_id=pythonapp instance=PC57-064 scope=dapr.runtime type=log ver=1.0.0-rc.2
INFO[0000] mTLS is disabled. Skipping certificate request and tls validation  app_id=pythonapp instance=PC57-064 scope=dapr.runtime type=log ver=1.0.0-rc.2
INFO[0000] local service entry announced: pythonapp -> 172.17.183.23:44129  app_id=pythonapp instance=PC57-064 scope=dapr.contrib type=log ver=1.0.0-rc.2
INFO[0000] Initialized name resolution to standalone     app_id=pythonapp instance=PC57-064 scope=dapr.runtime type=log ver=1.0.0-rc.2
INFO[0000] component loaded. name: pubsub, type: pubsub.redis  app_id=pythonapp instance=PC57-064 scope=dapr.runtime type=log ver=1.0.0-rc.2
INFO[0000] waiting for all outstanding components to be processed  app_id=pythonapp instance=PC57-064 scope=dapr.runtime type=log ver=1.0.0-rc.2
INFO[0000] component loaded. name: statestore, type: state.redis  app_id=pythonapp instance=PC57-064 scope=dapr.runtime type=log ver=1.0.0-rc.2
INFO[0000] all outstanding components processed          app_id=pythonapp instance=PC57-064 scope=dapr.runtime type=log ver=1.0.0-rc.2
INFO[0000] enabled gRPC tracing middleware               app_id=pythonapp instance=PC57-064 scope=dapr.runtime.grpc.api type=log ver=1.0.0-rc.2
INFO[0000] enabled gRPC metrics middleware               app_id=pythonapp instance=PC57-064 scope=dapr.runtime.grpc.api type=log ver=1.0.0-rc.2
INFO[0000] API gRPC server is running on port 34093      app_id=pythonapp instance=PC57-064 scope=dapr.runtime type=log ver=1.0.0-rc.2
INFO[0000] enabled metrics http middleware               app_id=pythonapp instance=PC57-064 scope=dapr.runtime.http type=log ver=1.0.0-rc.2
INFO[0000] enabled tracing http middleware               app_id=pythonapp instance=PC57-064 scope=dapr.runtime.http type=log ver=1.0.0-rc.2
INFO[0000] http server is running on port 3501           app_id=pythonapp instance=PC57-064 scope=dapr.runtime type=log ver=1.0.0-rc.2
INFO[0000] enabled gRPC tracing middleware               app_id=pythonapp instance=PC57-064 scope=dapr.runtime.grpc.internal type=log ver=1.0.0-rc.2
INFO[0000] enabled gRPC metrics middleware               app_id=pythonapp instance=PC57-064 scope=dapr.runtime.grpc.internal type=log ver=1.0.0-rc.2
INFO[0000] internal gRPC server is running on port 44129  app_id=pythonapp instance=PC57-064 scope=dapr.runtime type=log ver=1.0.0-rc.2
INFO[0000] actor runtime started. actor idle timeout: 1h0m0s. actor scan interval: 30s  app_id=pythonapp instance=PC57-064 scope=dapr.runtime.actor type=log ver=1.0.0-rc.2
WARN[0000] failed to read from bindings: app channel not initialized   app_id=pythonapp instance=PC57-064 scope=dapr.runtime type=log ver=1.0.0-rc.2
INFO[0000] dapr initialized. Status: Running. Init Elapsed 4.716900000000001ms  app_id=pythonapp instance=PC57-064 scope=dapr.runtime type=log ver=1.0.0-rc.2
INFO[0000] placement tables updated, version: 0          app_id=pythonapp instance=PC57-064 scope=dapr.runtime.actor.internal.placement type=log ver=1.0.0-rc.2
ℹ️  Checking if Dapr sidecar is listening on GRPC port 34093
ℹ️  Dapr sidecar is up and running.
ℹ️  Updating metadata for app command: python3 app.py
✅  You're up and running! Both Dapr and your app logs will appear here.

启动成功了。因为Python自己不提供服务,所以--app-port不用指定。--dapr-http-port是3501,这是自己的Sidecar用的端口,不能跟别人的重了。再看看刚才Node的窗口,不停的有新的Request过来,就是Python程序来的每隔一秒的Request。
最后看一下dapr list的结果:

$ dapr list
  APP ID     HTTP PORT  GRPC PORT  APP PORT  COMMAND         AGE  CREATED              PID
  nodeapp    3500       35485      3000      node app.js     41m  2020-12-27 00:54.54  18395
  pythonapp  40175      33349      0         python3 app.py  1m   2020-12-27 01:36.27  31185

要结束这两个APP,在各自窗口里Ctrl+c就可以。如果在别的窗口,可以用Dapr CLI的命令:

$ dapr stop --app-id nodeapp
$ dapr stop --app-id pythonapp

至此在Standalone模式下的第一个Dapr程序部署成功!下一篇讲讲在Kubernetes模式下部署的方法。