在 edgecore 啓動階段註冊模塊由 kubeedge/edge/cmd/app
包下的 registerModules
函數完成,註冊的模塊包括:
- Edged:一個運行在 edge 節點的 agent 程序,管理邊緣的容器化應用程序
- EdgeHub:邊緣的通信接口模塊。這是一個 Web 套接字客戶端,負責邊緣計算與雲服務的交互。包括同步雲端資源到邊緣端,以及報告邊緣端 host 和 device 狀態到雲端
- EdgeController:管理邊緣節點。它是一個擴展的 Kubernetes 控制器,管理邊緣節點和 pod 元數據,以便數據可以面向特定的邊緣節點
- EventBus:使用 MQTT 處理內部邊緣通信。MQTT 客戶端與 MQTT 服務器(mosquitto)交互,爲其他組件提供發佈和訂閱功能
- DeviceTwin:處理設備元數據的設備軟件鏡像。該模塊有助於處理設備狀態並將其同步到雲上。它還爲應用程序提供查詢接口,它連接到一個輕量級數據庫(SQLite)
- MetaManager:管理邊緣節點上的元數據。這是 Edged 和 Edgehub 之間的消息處理器。負責在輕量級數據庫(SQLite)中存儲 / 檢索元數據
// registerModules register all the modules started in edgecore func registerModules() { devicetwin.Register() edged.Register() edgehub.Register() eventbus.Register() edgemesh.Register() metamanager.Register() servicebus.Register() test.Register() dbm.InitDBManager() }
1. main 函數
一看挺熟悉的格式,kubernetes 代碼都是這麼搞的,使用了 cobra 框架
func main() {
command := app.NewEdgeCoreCommand()
logs.InitLogs()
defer logs.FlushLogs()
if err := command.Execute(); err != nil {
os.Exit(1)
}
}
1.1 NewEdgeCoreCommand 函數
registerModules 註冊模塊 (第 2 章節講解)
Run 函數真正的運行階段,啓動各個模塊,以及設置優雅的終止程序 (第 3 章節講解)
// NewEdgeCoreCommand create edgecore cmd
func NewEdgeCoreCommand() *cobra.Command {
opts := options.NewEdgeCoreOptions()
cmd := &cobra.Command{
Use: "edgecore",
......
Run: func(cmd *cobra.Command, args []string) {
verflag.PrintAndExitIfRequested()
flag.PrintFlags(cmd.Flags())
// To help debugging, immediately log version
klog.Infof("Version: %+v", version.Get())
registerModules()
// start all modules
core.Run()
},
2. registerModules
通過 registerModules 函數註冊相應的模塊,下面看看這些模塊怎麼註冊的
// registerModules register all the modules started in edgecore
func registerModules() {
devicetwin.Register()
edged.Register()
edgehub.Register()
eventbus.Register()
edgemesh.Register()
metamanager.Register()
servicebus.Register()
test.Register()
dbm.InitDBManager()
}
2.1 Register 函數
路徑 github.com/kubeedge/beehive/pkg/core/module.go 引入了 beehive 包,使用全局 modules 和 disableModules 需要加載的與禁止的模塊,各個模塊需要所實現 Module 接口,需要實現下面的方法:
- Name() string
- Group() string
- Start()
- Cleanup()
var (
// Modules map
modules map[string]Module
disabledModules map[string]Module
)
func init() {
modules = make(map[string]Module)
disabledModules = make(map[string]Module)
config.AddConfigChangeCallback(moduleChangeCallback{})
eventListener := config.EventListener{Name: "eventListener1"}
config.CONFIG.RegisterListener(eventListener, "modules.enabled")
}
看看其中一個模塊的實現,devicetwin.go,路徑 kubeege/edge/pkg/devicetwin/devicetwin.go
2.2 devicetwin
簡單明瞭,調用 beehive 的 Register 函數註冊模塊
//DeviceTwin the module
type DeviceTwin struct {
HeartBeatToModule map[string]chan interface{}
DTContexts *dtcontext.DTContext
DTModules map[string]dtmodule.DTModule
cancel context.CancelFunc
}
// Register register devicetwin
func Register() {
dtclient.InitDBTable()
dt := DeviceTwin{}
core.Register(&dt)
}
2.2.1 DeviceTwin 方法 Name 和 Group
可以得到 DeviceTwin 模塊的 name 爲 twin,group 爲 twin
//Name get name of the module
func (dt *DeviceTwin) Name() string {
return "twin"
}
//Group get group of the module
func (dt *DeviceTwin) Group() string {
return modules.TwinGroup
}
2.2.2 DeviceTwin 方法 Start
deviceTwin 模塊和輕量級數據庫 sqlite 交互,SyncDeviceFromSqlite 函數從數據庫同步數據,應該有表 device,device_attr,device_twin
//Start run the module
func (dt *DeviceTwin) Start() {
var ctx context.Context
dtContexts, _ := dtcontext.InitDTContext()
dt.HeartBeatToModule = make(map[string]chan interface{})
dt.DTModules = make(map[string]dtmodule.DTModule)
dt.DTContexts = dtContexts
ctx, dt.cancel = context.WithCancel(context.Background())
err := SyncSqlite(dt.DTContexts)
if err != nil {
klog.Errorf("Start DeviceTwin Failed, Sync Sqlite error:%v", err)
return
}
dt.runDeviceTwin(ctx)
}
3. StartModules 函數
// StartModules starts modules that are registered
func StartModules() {
beehiveContext.InitContext(beehiveContext.MsgCtxTypeChannel)
modules := GetModules()
for name, module := range modules {
//Init the module
beehiveContext.AddModule(name)
//Assemble typeChannels for sendToGroup
beehiveContext.AddModuleGroup(name, module.Group())
go module.Start()
klog.Infof("Starting module %v", name)
}
}
3.1 InitContext 函數
beehive 採用 golang 的 channel 方式實現模塊間通訊,未來可能有 unix socke t的通訊方式。kubernetes CSI 等模塊間使用的時 socket 通訊方式,初始化全局上下文 context,context 包含兩個對象 moduleContext,messageContext
// Context is global context object
type Context struct {
moduleContext ModuleContext
messageContext MessageContext
}
// InitContext gets global context instance
func InitContext(contextType string) {
once.Do(func() {
context = &Context{}
switch contextType {
case MsgCtxTypeChannel:
channelContext := NewChannelContext()
context.messageContext = channelContext
context.moduleContext = channelContext
default:
klog.Fatalf("Do not support context type:%s", contextType)
}
})
}
3.1.1 moduleContext 模塊管理
AddModule
爲模塊創建默認 buffer 大小爲 1024 的channel,channels
成員中將模塊名字映射到該 channel,用於“單播”AddModuleGroup
將一個模塊對應的 channel 添加到所屬 group,也就是將ChannelContext
的typeChannels[group][module]
設置爲模塊對應channel,用於“組播”
//constants for channel context
const (
ChannelSizeDefault = 1024
MessageTimeoutDefault = 30 * time.Second
TickerTimeoutDefault = 20 * time.Millisecond
)
3.1.1.1 結構體 ChannelContext
channel channels,typeChannels,anonChannels,定義的組如下:
const (
// BusGroup group
BusGroup = "bus"
// HubGroup group
HubGroup = "hub"
// TwinGroup group
TwinGroup = "twin"
// MetaGroup group
MetaGroup = "meta"
//EdgedGroup group
EdgedGroup = "edged"
// UserGroup is ServiceBus group
UserGroup = "user"
// MeshGroup group
MeshGroup = "mesh"
)
// ChannelContext is object for Context channel
type ChannelContext struct {
//ConfigFactory goarchaius.ConfigurationFactory
channels map[string]chan model.Message
chsLock sync.RWMutex
typeChannels map[string]map[string]chan model.Message
typeChsLock sync.RWMutex
anonChannels map[string]chan model.Message
anonChsLock sync.RWMutex
}
//ModuleContext is interface for context module management
type ModuleContext interface {
AddModule(module string)
AddModuleGroup(module, group string)
Cleanup(module string)
}
3.1.2 messageContext 消息同步
實現了模塊間消息的同步與異步發送
//MessageContext is interface for message syncing
type MessageContext interface {
// async mode
Send(module string, message model.Message)
Receive(module string) (model.Message, error)
// sync mode
SendSync(module string, message model.Message, timeout time.Duration) (model.Message, error)
SendResp(message model.Message)
// group broadcast
SendToGroup(moduleType string, message model.Message)
SendToGroupSync(moduleType string, message model.Message, timeout time.Duration) error
}
edgecore 啓動流程總結:
- 調用 registerModules 函數主冊各個模塊
- 啓動各個模塊調用
StartModules
函數創建模塊間通訊機制,並啓動協程調用每個模塊的Start
函數