本文主要介绍cloud foundry的service框架,主要内容包括(1)service_gateway的启动过程;(2)service_node的启动过程;以及几个重点流程分析包括(3)服务的注册和注销;(4)服务实例的生成、删除、绑定、解绑
一个服务的启动过程从VCAP::Services::Base::Gateway(vcap_services_base/lib/base/gateway.rb)的实例化和start方法开始。比如mysql服务:
VCAP::Services::Mysql::Gateway.new.start
启动方法逻辑并不复杂,根据具体的服务生成一个VCAP::Services::Base::Provisioner实例,并以该实例为基础生成VCAP::Services::AsynchronousServiceGateway的实例,VCAP::Services::AsynchronousServiceGateway是sintra/base的子类,从而启动一个以sinatra框架的HTTP服务器,接受请求。
VCAP::Services::Base::Provisioner的实例化过程包括VCAP::Services::Base::Base的initialize过程和VCAP::Services::Base::Provisioner的initialize过程。
1)连接nats服务器,连接成功之后,首先注册component组件提供状态查询功能,然后调用on_connect_node方法。
2)定期更新varz
3)定期检测service_nodes的状态是否过期
重点工作在on_connect_node方法,在该方法中
1)注册announce、node_handles、handles、update_service_handle事件
%w[announce node_handles handles update_service_handle].each do |op| eval %[@node_nats.subscribe("#{service_name}.#{op}") { |msg, reply| on_#{op}(msg, reply) }] end
2)发布service node discover消息,通过service node向该gateway注册自己
node_nats.publish("#{service_name}.discover")
VCAP::Services::AsynchronousServiceGateway是Sinatra::Base的子类。
初始化过程主要在setup方法中
def initialize(opts) super setup(opts) end首先启动一个周期性的定时器向cloud controller发送heart beat信息,同时也是向cloud controller注册服务
EM.add_periodic_timer(@hb_interval) { send_heartbeat }
然后通过Kernel实现系统退出时的回调:向cloud controller发送注销信息
send_deactivation_notice接着从cloud controller获取所有的handles(service_configs),委托provisioner更新状态
最后provisioner注册handle call back。
(3)启动HTTP服务
Service Gateway的HTTP接口可以参见VCAP::Services::AsynchronousServiceGateway,包括
post '/gateway/v1/configurations'
delete '/gateway/v1/configurations/:service_id'
post '/gateway/v1/configurations/:service_id/handles'
delete '/gateway/v1/configurations/:service_id/handles/:handle_id'
post "/gateway/v1/configurations/:service_id/snapshots"
get "/gateway/v1/configurations/:service_id/snapshots/:snapshot_id"
get "/gateway/v1/configurations/:service_id/snapshots"
put "/gateway/v1/configurations/:service_id/snapshots/:snapshot_id"
delete "/gateway/v1/configurations/:service_id/snapshots/:snapshot_id"
post "/gateway/v1/configurations/:service_id/serialized/url/snapshots/:snapshot_id"
get "/gateway/v1/configurations/:service_id/serialized/url/snapshots/:snapshot_id"
put "/gateway/v1/configurations/:service_id/serialized/url"
put "/gateway/v1/configurations/:service_id/serialized/data"
get "/gateway/v1/configurations/:service_id/jobs/:job_id"
post '/service/internal/v1/restore'
post '/service/internal/v1/recover'
post '/service/internal/v1/check_orphan'
delete '/service/internal/v1/purge_orphan'
post "/service/internal/v1/migration/:node_id/:instance_id/:action"
get "/service/internal/v1/migration/:node_id/instances"
一个服务节点的启动过程从VCAP::Services::Base::NodeBin的实例化和start方法开始,比如mysql的节点
VCAP::Services::Mysql::NodeBin.new.start
服务节点的启动过程就是生成VCAP::Services::Base::Node 实例的过程
EM.run do node = node_class.new(options) trap("INT") {shutdown(node)} trap("TERM") {shutdown(node)} end
VCAP::Services::Base::Node同VCAP::Services::Base::Provisioner一样是VCAP::Services::Base::Base的子类,除了读取配置、启动组件服务器之外,连接nats server,主要实现还是由on_connect_node方法中。
在on_connect_node中,node注册了一系列的nats主题
provision、unprovision、bind、unbind、restore、disable_instance、enable_instance、import_instance、update_instance、cleanupnfs_instance、purge_orphan
还有discover和check_orphan。
完成之后将发送send_node_announcement,通过nats消息告诉相应的service_gateway,这个节点可以提供服务了。
publish(reply || "#{service_name}.announce", Yajl::Encoder.encode(a))
Cloud Foundry平台支持的每种服务都有一个service gateway。service gateway通过HTTP主动向cloud controller发送POST请求完成服务的注册和注销。
Cloud clontroller接收服务注册和解除的uri为:#{@cld_ctrl_uri}/services/v1/offerings。
Service gateway向Cloud Controller发送的信息包括服务的label、url、plans等。
标志性字段active=true,表示注册该服务。
@svc_json = { :label => @service[:label], :url => @service[:url], :plans => @service[:plans], :cf_plan_id => @service[:cf_plan_id], :tags => @service[:tags], :active => true, :description => @service[:description], :plan_options => @service[:plan_options], :acls => @service[:acls], :timeout => @service[:timeout], }.to_json
Service gateway向Cloud Controller发送的信息包括服务的label、url。
标志性字段active=false,表示注销该服务。
@deact_json = { :label => @service[:label], :url => @service[:url], :active => false }.to_json
首先解析出要创建的service的基础信息,包括label(name 和 version)和plan
req = VCAP::Services::Api::GatewayProvisionRequest.decode(request_body)
如果名称和版本号不匹配,则返回错误。
name, version = VCAP::Services::Api::Util.parse_label(req.label) unless (name == @service[:name]) && (version == @service[:version]) error_msg = ServiceError.new(ServiceError::UNKNOWN_LABEL).to_hash abort_request(error_msg) end
如果该服务名称和版本号匹配,则委托provisioner创建服务实例、
@provisioner.provision_service(req) do |msg|
根据参数service_id委托provisioner删除服务实例
@provisioner.unprovision_service(params['service_id'])
首先解析出绑定请求信息:req = VCAP::Services::Api::GatewayBindRequest.decode(request_body)
然后委托provisioner绑定实例
@provisioner.bind_instance(req.service_id, req.binding_options)
同样解析出解绑信息后委托provision实例解绑
@provisioner.unbind_instance(req.service_id, req.handle_id, req.binding_options)
先写到这里吧。后面会接着写一篇专门用来理清cloud controller和service gateway以及service gateway和service node之间的信息交互。