构建你的服务
概述
本文档是将你已有的云服务变成tsuru服务的实战指南。为了创建一个服务,你需要为自己的服务实现配置API,当用户创建一个新的实例或者把应用绑定到实例上时,tsuru会通过HTTP协议
调用。还需要创建一个YAML文档,作为服务的清单。我们提供一个命令行工具帮助你创建这个清单和管理你的服务。
创建你的service API
你可以用任意的编程语言和框架实现你的service API。本教程中我们采用Flask
。
验证
tsuru使用最基本的验证方式来验证服务,更多关于验证的内容请查看API工作流。
使用Flask,你可以通过这个Flask代码段中的修饰符来管理最基本的验证。
准备条件
首先确保Python和pip已经安装:
$ python --version
Python 2.7.2
$ pip
Usage: pip COMMAND [OPTIONS]
pip: error: You must give a command (use "pip help" to see a list of commands)
更多关于如何安装Python的内容请查看Python 下载文档,以及如何安装pip请查看pip安装指南。安装完python和pip后,就可以使用pip去安装Flask了:
$ pip install flask
安装完Flask后,是时候创建名为api.py的文件并且添加创建最小的Flask应用的代码:
from flask import Flask
app = Flask(__name__)
@app.route("/")
def hello():
return "Hello World!"
if __name__ == "__main__":
app.run()
为了运行这个应用可以这么做:
$ python api.py
* Running on http://127.0.0.1:5000/
打开浏览器访问http://127.0.0.1:5000/这个地址,会看到"Hello World!"这个消息。然后,你需要实现tsuru service API的资源,如tsuru service API workflow </services/api>
所述。
列出可用计划
tsuru可以通过发送GET请求到/resources/plans
获得可用的计划列表。让我们创建处理这个请求的视图:
import json
@app.route("/resources/plans", methods=["GET"])
def plans():
plans = [{"name": "small", "description": "small instance"},
{"name": "medium", "description": "medium instance"},
{"name": "big", "description": "big instance"},
{"name": "giant", "description": "giant instance"}]
return json.dumps(plans)
创建新的实例
对于新的实例,tsuru会发送POST请求到/resources加上必要参数去创建一个实例。如果服务实例创建成功,你的API应该返回201状态码。让我们为这个动作创建视图:
from flask import request
@app.route("/resources", methods=["POST"])
def add_instance():
name = request.form.get("name")
plan = request.form.get("plan")
team = request.form.get("team")
# use the given parameters to create the instance
return "", 201
把实例绑定到应用
在绑定动作中,tsuru通过发送POST请求加上必要参数到/resources/<service-instance-name>/bind-app
来调用服务去把应用绑定到服务实例。如果绑定操作成功,API返回201状态码,同时在JSON消息体中会包含应用应当设置的环境变量。让我们创建一个返回伪造的名为"SOMEVAR"变量的视图,这个变量可以被插入到应用的环境中:
import json
from flask import request
@app.route("/resources/<name>/bind-app", methods=["POST"])
def bind_app(name):
app_host = request.form.get("app-host")
# use name and app_host to bind the service instance and the #
application
envs = {"SOMEVAR": "somevalue"}
return json.dumps(envs), 201
从应用解绑定实例
In the unbind action, tsuru issues a DELETE
request to the URL/resources/<service-instance-name>/bind-app
.
If the unbind operation succeeds, the API should return 200 as status code.Let's create the view for this action:
@app.route("/resources/<name>/bind-app", methods=["DELETE"])
def unbind_app(name):
app_host = request.form.get("app-host")
# use name and app-host to remove the bind
return "", 200
白名单单元
绑定和解绑定服务实例到应用时,tsuru同时会提供关于访问服务实例的单元的信息,因此service API任何需要的白名单(比如,在网络交换机写入ACL规则或者在防火墙授权访问)。
tsuru会发送POST和DELETE请求,加上应用的主机以及单元,到路由到/resources/<name>/bind
,所以API可以处理任何的访问控制:
@app.route("/resources/<name>/bind", methods=["POST", "DELETE"])
def access_control(name):
app_host = request.form.get("app-host")
unit_host = request.form.get("unit-host")
# use unit-host and app-host, according to the access control tool, and
# the request method.
return "", 201
删除实例
tsuru会通过发送DELETE请求到/resources/<service_name>
来执行删除操作。如果服务实例成功删除,API应担返回201状态码。让我们为这个动作创建视图:
@app.route("/resources/<name>", methods=["DELETE"])
def remove_instance(name):
# remove the instance named "name"
return "", 200
检查实例的状态
tsuru通过发送GET请求到/resources/<service_name>/status
来检查一个实例的状态。如果实例完好,这个链接应当返回204。让我们为这个动作创建视图:
@app.route("/resources/<name>/status", methods=["GET"])
def status(name):
# check the status of the instance named "name"
return "", 204
我们用Flask开发的“伪API”的最终代码如下:
import json
from flask import Flask, request
app = Flask(__name__)
@app.route("/resources/plans", methods=["GET"])
def plans():
plans = [{"name": "small", "description": "small instance"},
{"name": "medium", "description": "medium instance"},
{"name": "big", "description": "big instance"},
{"name": "giant", "description": "giant instance"}]
return json.dumps(plans)
@app.route("/resources", methods=["POST"])
def add_instance():
name = request.form.get("name")
plan = request.form.get("plan")
team = request.form.get("team")
# use the given parameters to create the instance
return "", 201
@app.route("/resources/<name>/bind-app", methods=["POST"])
def bind_app(name):
app_host = request.form.get("app-host")
# use name and app_host to bind the service instance and the #
application
envs = {"SOMEVAR": "somevalue"}
return json.dumps(envs), 201
@app.route("/resources/<name>/bind-app", methods=["DELETE"])
def unbind_app(name):
app_host = request.form.get("app-host")
# use name and app-host to remove the bind
return "", 200
@app.route("/resources/<name>", methods=["DELETE"])
def remove_instance(name):
# remove the instance named "name"
return "", 200
@app.route("/resources/<name>/bind", methods=["POST", "DELETE"])
def access_control(name):
app_host = request.form.get("app-host")
unit_host = request.form.get("unit-host")
# use unit-host and app-host, according to the access control tool, and
# the request method.
return "", 201
@app.route("/resources/<name>/status", methods=["GET"])
def status(name):
# check the status of the instance named "name"
return "", 204
if __name__ == "__main__":
app.run()
.. _service_manifest:
创建一个服务清单
可以使用crane去创建一个清单的模板:
$ crane template
这会在当前路径下创建包含如下内容的manifest.yaml文件:
id: servicename
password: abc123
endpoint:
production: production-endpoint.com
manifest.yaml是crane用来定义ID,密码和服务的产品环境端点的文件。在清单中修改这些信息,然后提交服务
:
id: servicename
username: username_to_auth
password: 1CWpoX2Zr46Jhc7u
endpoint:
production: production-endpoint.com
test: test-endpoint.com:8080
submit your service
: Submiting your service API
提交你的service API
可以运行下面的命令来提交service API:
$ crane create manifest.yaml
更多内容,请查看service API workflow </services/api>
and thecrane usage guide </services/usage>
.