This is an automated email from the ASF dual-hosted git repository.

alexstocks pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/dubbo-admin.git


The following commit(s) were added to refs/heads/develop by this push:
     new ca9fb03b feat: support kubernetes as a backend engine (#1340)
ca9fb03b is described below

commit ca9fb03b8badb75577397bc9df8b916379eedadc
Author: robb <[email protected]>
AuthorDate: Sun Nov 2 16:59:49 2025 +0800

    feat: support kubernetes as a backend engine (#1340)
    
    * feat: implement runtime engine using kubernetes
---
 api/mesh/v1alpha1/instance.pb.go                   | 181 ++++++-------
 api/mesh/v1alpha1/instance.proto                   |  16 +-
 api/mesh/v1alpha1/rpc_instance_metadata.pb.go      |  38 +--
 api/mesh/v1alpha1/rpc_instance_metadata.proto      |   6 +-
 api/mesh/v1alpha1/runtime_instance.pb.go           | 282 +++++++++++++++++----
 api/mesh/v1alpha1/runtime_instance.proto           |  39 ++-
 .../mesh/v1alpha1/runtime_instance_helper.go       |  10 +-
 api/mesh/v1alpha1/service_provider_metadata.pb.go  |  28 +-
 api/mesh/v1alpha1/service_provider_metadata.proto  |   2 +-
 app/dubbo-admin/cmd/root.go                        |   2 -
 app/dubbo-admin/cmd/run.go                         |  27 +-
 app/dubbo-admin/dubbo-admin.yaml                   |  49 +++-
 go.mod                                             |   7 +
 pkg/config/discovery/config.go                     |   8 +-
 pkg/config/engine/config.go                        |  55 +++-
 pkg/console/component.go                           |   2 +-
 pkg/core/bootstrap/init.go                         |   3 +
 pkg/core/consts/const.go                           |   4 +
 pkg/core/controller/informer.go                    |  26 +-
 pkg/core/controller/listwatcher.go                 |   6 +-
 pkg/core/discovery/component.go                    |  30 ++-
 pkg/core/engine/component.go                       | 111 +++++---
 pkg/core/engine/factory.go                         |  10 +-
 pkg/core/engine/subscriber/runtime_instance.go     | 186 ++++++++++++++
 pkg/core/events/component.go                       |  44 ++--
 pkg/core/events/eventbus.go                        |  29 ++-
 pkg/core/manager/component.go                      |   2 +-
 .../apis/mesh/v1alpha1/affinityroute_types.go      |  11 +
 .../apis/mesh/v1alpha1/application_types.go        |  11 +
 .../apis/mesh/v1alpha1/conditionroute_types.go     |  11 +
 .../apis/mesh/v1alpha1/dynamicconfig_types.go      |  11 +
 .../resource/apis/mesh/v1alpha1/instance_types.go  |  11 +
 .../apis/mesh/v1alpha1/rpcinstance_types.go        |  11 +
 .../mesh/v1alpha1/rpcinstancemetadata_types.go     |  61 +++--
 .../apis/mesh/v1alpha1/runtimeinstance_types.go    |  11 +
 .../resource/apis/mesh/v1alpha1/service_types.go   |  11 +
 .../mesh/v1alpha1/serviceconsumermetadata_types.go |  11 +
 .../mesh/v1alpha1/serviceprovidermapping_types.go  |  11 +
 .../mesh/v1alpha1/serviceprovidermetadata_types.go |  17 +-
 .../resource/apis/mesh/v1alpha1/tagroute_types.go  |  11 +
 pkg/core/resource/model/resource.go                |   2 +
 pkg/core/runtime/runtime.go                        |  26 +-
 pkg/core/store/component.go                        |   2 +-
 pkg/core/store/index/registry.go                   |  24 +-
 pkg/diagnostics/server.go                          |  22 +-
 .../listwatcher.go => discovery/mock/factory.go}   |  25 +-
 pkg/engine/kubernetes/engine.go                    | 230 +++++++++++++++++
 pkg/engine/kubernetes/factory.go                   |  75 ++++++
 pkg/store/memory/store_test.go                     |   8 +
 pkg/store/{db => mysql}/mysql.go                   |   2 +-
 scripts/resourcegen/gen.go                         |  11 +
 51 files changed, 1438 insertions(+), 391 deletions(-)

diff --git a/api/mesh/v1alpha1/instance.pb.go b/api/mesh/v1alpha1/instance.pb.go
index fea32bda..b9e14fa6 100644
--- a/api/mesh/v1alpha1/instance.pb.go
+++ b/api/mesh/v1alpha1/instance.pb.go
@@ -46,7 +46,8 @@ type Instance struct {
        WorkloadType   string            
`protobuf:"bytes,56,opt,name=workloadType,proto3" json:"workloadType,omitempty"`
        WorkloadName   string            
`protobuf:"bytes,57,opt,name=workloadName,proto3" json:"workloadName,omitempty"`
        Node           string            
`protobuf:"bytes,58,opt,name=node,proto3" json:"node,omitempty"`
-       Probes         []*Instance_Probe 
`protobuf:"bytes,59,rep,name=probes,proto3" json:"probes,omitempty"`
+       Probes         []*Probe          
`protobuf:"bytes,59,rep,name=probes,proto3" json:"probes,omitempty"`
+       Conditions     []*Condition      
`protobuf:"bytes,60,rep,name=conditions,proto3" json:"conditions,omitempty"`
 }
 
 func (x *Instance) Reset() {
@@ -212,64 +213,18 @@ func (x *Instance) GetNode() string {
        return ""
 }
 
-func (x *Instance) GetProbes() []*Instance_Probe {
+func (x *Instance) GetProbes() []*Probe {
        if x != nil {
                return x.Probes
        }
        return nil
 }
 
-type Instance_Probe struct {
-       state         protoimpl.MessageState
-       sizeCache     protoimpl.SizeCache
-       unknownFields protoimpl.UnknownFields
-
-       Type string `protobuf:"bytes,1,opt,name=type,proto3" 
json:"type,omitempty"`
-       Port int32  `protobuf:"varint,2,opt,name=port,proto3" 
json:"port,omitempty"`
-}
-
-func (x *Instance_Probe) Reset() {
-       *x = Instance_Probe{}
-       mi := &file_api_mesh_v1alpha1_instance_proto_msgTypes[1]
-       ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
-       ms.StoreMessageInfo(mi)
-}
-
-func (x *Instance_Probe) String() string {
-       return protoimpl.X.MessageStringOf(x)
-}
-
-func (*Instance_Probe) ProtoMessage() {}
-
-func (x *Instance_Probe) ProtoReflect() protoreflect.Message {
-       mi := &file_api_mesh_v1alpha1_instance_proto_msgTypes[1]
+func (x *Instance) GetConditions() []*Condition {
        if x != nil {
-               ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
-               if ms.LoadMessageInfo() == nil {
-                       ms.StoreMessageInfo(mi)
-               }
-               return ms
-       }
-       return mi.MessageOf(x)
-}
-
-// Deprecated: Use Instance_Probe.ProtoReflect.Descriptor instead.
-func (*Instance_Probe) Descriptor() ([]byte, []int) {
-       return file_api_mesh_v1alpha1_instance_proto_rawDescGZIP(), []int{0, 0}
-}
-
-func (x *Instance_Probe) GetType() string {
-       if x != nil {
-               return x.Type
-       }
-       return ""
-}
-
-func (x *Instance_Probe) GetPort() int32 {
-       if x != nil {
-               return x.Port
+               return x.Conditions
        }
-       return 0
+       return nil
 }
 
 var File_api_mesh_v1alpha1_instance_proto protoreflect.FileDescriptor
@@ -279,59 +234,62 @@ var file_api_mesh_v1alpha1_instance_proto_rawDesc = 
[]byte{
        0x68, 0x61, 0x31, 0x2f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 
0x2e, 0x70, 0x72, 0x6f,
        0x74, 0x6f, 0x12, 0x13, 0x64, 0x75, 0x62, 0x62, 0x6f, 0x2e, 0x6d, 0x65, 
0x73, 0x68, 0x2e, 0x76,
        0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x1a, 0x16, 0x61, 0x70, 0x69, 
0x2f, 0x6d, 0x65, 0x73,
-       0x68, 0x2f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 
0x6f, 0x74, 0x6f, 0x22,
-       0xb7, 0x06, 0x0a, 0x08, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 
0x12, 0x12, 0x0a, 0x04,
-       0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 
0x6e, 0x61, 0x6d, 0x65,
-       0x12, 0x0e, 0x0a, 0x02, 0x69, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 
0x52, 0x02, 0x69, 0x70,
-       0x12, 0x18, 0x0a, 0x07, 0x72, 0x70, 0x63, 0x50, 0x6f, 0x72, 0x74, 0x18, 
0x03, 0x20, 0x01, 0x28,
-       0x05, 0x52, 0x07, 0x72, 0x70, 0x63, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x18, 
0x0a, 0x07, 0x71, 0x6f,
-       0x73, 0x50, 0x6f, 0x72, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 
0x07, 0x71, 0x6f, 0x73,
-       0x50, 0x6f, 0x72, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x70, 0x70, 0x4e, 
0x61, 0x6d, 0x65, 0x18,
-       0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x70, 0x70, 0x4e, 0x61, 
0x6d, 0x65, 0x12, 0x26,
-       0x0a, 0x0e, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x56, 0x65, 0x72, 
0x73, 0x69, 0x6f, 0x6e,
-       0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x72, 0x65, 0x6c, 0x65, 
0x61, 0x73, 0x65, 0x56,
-       0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x22, 0x0a, 0x0c, 0x72, 0x65, 
0x67, 0x69, 0x73, 0x74,
-       0x65, 0x72, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 
0x52, 0x0c, 0x72, 0x65,
-       0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x26, 
0x0a, 0x0e, 0x75, 0x6e,
-       0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x54, 0x69, 0x6d, 0x65, 
0x18, 0x08, 0x20, 0x01,
-       0x28, 0x09, 0x52, 0x0e, 0x75, 0x6e, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 
0x65, 0x72, 0x54, 0x69,
-       0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 
0x6f, 0x6c, 0x18, 0x09,
-       0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 
0x6f, 0x6c, 0x12, 0x24,
-       0x0a, 0x0d, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 
0x69, 0x6f, 0x6e, 0x18,
-       0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x73, 0x65, 0x72, 0x69, 0x61, 
0x6c, 0x69, 0x7a, 0x61,
-       0x74, 0x69, 0x6f, 0x6e, 0x12, 0x3b, 0x0a, 0x04, 0x74, 0x61, 0x67, 0x73, 
0x18, 0x32, 0x20, 0x03,
-       0x28, 0x0b, 0x32, 0x27, 0x2e, 0x64, 0x75, 0x62, 0x62, 0x6f, 0x2e, 0x6d, 
0x65, 0x73, 0x68, 0x2e,
-       0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x49, 0x6e, 0x73, 
0x74, 0x61, 0x6e, 0x63,
-       0x65, 0x2e, 0x54, 0x61, 0x67, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 
0x04, 0x74, 0x61, 0x67,
-       0x73, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x18, 0x33, 
0x20, 0x01, 0x28, 0x09,
-       0x52, 0x05, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x63, 
0x72, 0x65, 0x61, 0x74,
-       0x65, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x34, 0x20, 0x01, 0x28, 0x09, 0x52, 
0x0a, 0x63, 0x72, 0x65,
-       0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x73, 
0x74, 0x61, 0x72, 0x74,
-       0x54, 0x69, 0x6d, 0x65, 0x18, 0x35, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 
0x73, 0x74, 0x61, 0x72,
-       0x74, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x72, 0x65, 0x61, 
0x64, 0x79, 0x54, 0x69,
-       0x6d, 0x65, 0x18, 0x36, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x72, 0x65, 
0x61, 0x64, 0x79, 0x54,
-       0x69, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x70, 0x6c, 0x6f, 
0x79, 0x53, 0x74, 0x61,
-       0x74, 0x65, 0x18, 0x37, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 
0x70, 0x6c, 0x6f, 0x79,
-       0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x22, 0x0a, 0x0c, 0x77, 0x6f, 0x72, 
0x6b, 0x6c, 0x6f, 0x61,
-       0x64, 0x54, 0x79, 0x70, 0x65, 0x18, 0x38, 0x20, 0x01, 0x28, 0x09, 0x52, 
0x0c, 0x77, 0x6f, 0x72,
-       0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x54, 0x79, 0x70, 0x65, 0x12, 0x22, 0x0a, 
0x0c, 0x77, 0x6f, 0x72,
-       0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x39, 0x20, 
0x01, 0x28, 0x09, 0x52,
-       0x0c, 0x77, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x4e, 0x61, 0x6d, 
0x65, 0x12, 0x12, 0x0a,
-       0x04, 0x6e, 0x6f, 0x64, 0x65, 0x18, 0x3a, 0x20, 0x01, 0x28, 0x09, 0x52, 
0x04, 0x6e, 0x6f, 0x64,
-       0x65, 0x12, 0x3b, 0x0a, 0x06, 0x70, 0x72, 0x6f, 0x62, 0x65, 0x73, 0x18, 
0x3b, 0x20, 0x03, 0x28,
-       0x0b, 0x32, 0x23, 0x2e, 0x64, 0x75, 0x62, 0x62, 0x6f, 0x2e, 0x6d, 0x65, 
0x73, 0x68, 0x2e, 0x76,
-       0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x49, 0x6e, 0x73, 0x74, 
0x61, 0x6e, 0x63, 0x65,
-       0x2e, 0x50, 0x72, 0x6f, 0x62, 0x65, 0x52, 0x06, 0x70, 0x72, 0x6f, 0x62, 
0x65, 0x73, 0x1a, 0x2f,
-       0x0a, 0x05, 0x50, 0x72, 0x6f, 0x62, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x74, 
0x79, 0x70, 0x65, 0x18,
-       0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 
0x12, 0x0a, 0x04, 0x70,
-       0x6f, 0x72, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x70, 
0x6f, 0x72, 0x74, 0x1a,
+       0x68, 0x2f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 
0x6f, 0x74, 0x6f, 0x1a,
+       0x28, 0x61, 0x70, 0x69, 0x2f, 0x6d, 0x65, 0x73, 0x68, 0x2f, 0x76, 0x31, 
0x61, 0x6c, 0x70, 0x68,
+       0x61, 0x31, 0x2f, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x69, 
0x6e, 0x73, 0x74, 0x61,
+       0x6e, 0x63, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xbd, 0x06, 
0x0a, 0x08, 0x49, 0x6e,
+       0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 
0x6d, 0x65, 0x18, 0x01,
+       0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x0e, 
0x0a, 0x02, 0x69, 0x70,
+       0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x70, 0x12, 0x18, 
0x0a, 0x07, 0x72, 0x70,
+       0x63, 0x50, 0x6f, 0x72, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 
0x07, 0x72, 0x70, 0x63,
+       0x50, 0x6f, 0x72, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x71, 0x6f, 0x73, 0x50, 
0x6f, 0x72, 0x74, 0x18,
+       0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x71, 0x6f, 0x73, 0x50, 0x6f, 
0x72, 0x74, 0x12, 0x18,
+       0x0a, 0x07, 0x61, 0x70, 0x70, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x05, 0x20, 
0x01, 0x28, 0x09, 0x52,
+       0x07, 0x61, 0x70, 0x70, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x26, 0x0a, 0x0e, 
0x72, 0x65, 0x6c, 0x65,
+       0x61, 0x73, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x06, 
0x20, 0x01, 0x28, 0x09,
+       0x52, 0x0e, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x56, 0x65, 0x72, 
0x73, 0x69, 0x6f, 0x6e,
+       0x12, 0x22, 0x0a, 0x0c, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 
0x54, 0x69, 0x6d, 0x65,
+       0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x72, 0x65, 0x67, 0x69, 
0x73, 0x74, 0x65, 0x72,
+       0x54, 0x69, 0x6d, 0x65, 0x12, 0x26, 0x0a, 0x0e, 0x75, 0x6e, 0x72, 0x65, 
0x67, 0x69, 0x73, 0x74,
+       0x65, 0x72, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 
0x52, 0x0e, 0x75, 0x6e,
+       0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x54, 0x69, 0x6d, 0x65, 
0x12, 0x1a, 0x0a, 0x08,
+       0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x18, 0x09, 0x20, 0x01, 
0x28, 0x09, 0x52, 0x08,
+       0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x12, 0x24, 0x0a, 0x0d, 
0x73, 0x65, 0x72, 0x69,
+       0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x0a, 0x20, 
0x01, 0x28, 0x09, 0x52,
+       0x0d, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 
0x6f, 0x6e, 0x12, 0x3b,
+       0x0a, 0x04, 0x74, 0x61, 0x67, 0x73, 0x18, 0x32, 0x20, 0x03, 0x28, 0x0b, 
0x32, 0x27, 0x2e, 0x64,
+       0x75, 0x62, 0x62, 0x6f, 0x2e, 0x6d, 0x65, 0x73, 0x68, 0x2e, 0x76, 0x31, 
0x61, 0x6c, 0x70, 0x68,
+       0x61, 0x31, 0x2e, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x2e, 
0x54, 0x61, 0x67, 0x73,
+       0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x04, 0x74, 0x61, 0x67, 0x73, 0x12, 
0x14, 0x0a, 0x05, 0x69,
+       0x6d, 0x61, 0x67, 0x65, 0x18, 0x33, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 
0x69, 0x6d, 0x61, 0x67,
+       0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 
0x69, 0x6d, 0x65, 0x18,
+       0x34, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 
0x65, 0x54, 0x69, 0x6d,
+       0x65, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x74, 0x61, 0x72, 0x74, 0x54, 0x69, 
0x6d, 0x65, 0x18, 0x35,
+       0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x74, 0x61, 0x72, 0x74, 0x54, 
0x69, 0x6d, 0x65, 0x12,
+       0x1c, 0x0a, 0x09, 0x72, 0x65, 0x61, 0x64, 0x79, 0x54, 0x69, 0x6d, 0x65, 
0x18, 0x36, 0x20, 0x01,
+       0x28, 0x09, 0x52, 0x09, 0x72, 0x65, 0x61, 0x64, 0x79, 0x54, 0x69, 0x6d, 
0x65, 0x12, 0x20, 0x0a,
+       0x0b, 0x64, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x53, 0x74, 0x61, 0x74, 0x65, 
0x18, 0x37, 0x20, 0x01,
+       0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x53, 0x74, 
0x61, 0x74, 0x65, 0x12,
+       0x22, 0x0a, 0x0c, 0x77, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x54, 
0x79, 0x70, 0x65, 0x18,
+       0x38, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x77, 0x6f, 0x72, 0x6b, 0x6c, 
0x6f, 0x61, 0x64, 0x54,
+       0x79, 0x70, 0x65, 0x12, 0x22, 0x0a, 0x0c, 0x77, 0x6f, 0x72, 0x6b, 0x6c, 
0x6f, 0x61, 0x64, 0x4e,
+       0x61, 0x6d, 0x65, 0x18, 0x39, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x77, 
0x6f, 0x72, 0x6b, 0x6c,
+       0x6f, 0x61, 0x64, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 
0x6f, 0x64, 0x65, 0x18,
+       0x3a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x6f, 0x64, 0x65, 0x12, 
0x32, 0x0a, 0x06, 0x70,
+       0x72, 0x6f, 0x62, 0x65, 0x73, 0x18, 0x3b, 0x20, 0x03, 0x28, 0x0b, 0x32, 
0x1a, 0x2e, 0x64, 0x75,
+       0x62, 0x62, 0x6f, 0x2e, 0x6d, 0x65, 0x73, 0x68, 0x2e, 0x76, 0x31, 0x61, 
0x6c, 0x70, 0x68, 0x61,
+       0x31, 0x2e, 0x50, 0x72, 0x6f, 0x62, 0x65, 0x52, 0x06, 0x70, 0x72, 0x6f, 
0x62, 0x65, 0x73, 0x12,
+       0x3e, 0x0a, 0x0a, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 
0x73, 0x18, 0x3c, 0x20,
+       0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x64, 0x75, 0x62, 0x62, 0x6f, 0x2e, 
0x6d, 0x65, 0x73, 0x68,
+       0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x43, 0x6f, 
0x6e, 0x64, 0x69, 0x74,
+       0x69, 0x6f, 0x6e, 0x52, 0x0a, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 
0x6f, 0x6e, 0x73, 0x1a,
        0x37, 0x0a, 0x09, 0x54, 0x61, 0x67, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 
0x12, 0x10, 0x0a, 0x03,
        0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 
0x65, 0x79, 0x12, 0x14,
        0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 
0x09, 0x52, 0x05, 0x76,
        0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x3a, 0x23, 0xaa, 0x8c, 
0x89, 0xa6, 0x01, 0x1d,
        0x0a, 0x08, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x09, 
0x49, 0x6e, 0x73, 0x74,
        0x61, 0x6e, 0x63, 0x65, 0x73, 0x1a, 0x04, 0x6d, 0x65, 0x73, 0x68, 0x20, 
0x01, 0x4a, 0x04, 0x08,
-       0x0b, 0x10, 0x32, 0x4a, 0x04, 0x08, 0x3c, 0x10, 0x65, 0x42, 0x31, 0x5a, 
0x2f, 0x67, 0x69, 0x74,
+       0x0b, 0x10, 0x32, 0x4a, 0x04, 0x08, 0x3d, 0x10, 0x65, 0x42, 0x31, 0x5a, 
0x2f, 0x67, 0x69, 0x74,
        0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x61, 0x70, 0x61, 0x63, 
0x68, 0x65, 0x2f, 0x64,
        0x75, 0x62, 0x62, 0x6f, 0x2d, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2f, 0x61, 
0x70, 0x69, 0x2f, 0x6d,
        0x65, 0x73, 0x68, 0x2f, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 
0x62, 0x06, 0x70, 0x72,
@@ -350,20 +308,22 @@ func file_api_mesh_v1alpha1_instance_proto_rawDescGZIP() 
[]byte {
        return file_api_mesh_v1alpha1_instance_proto_rawDescData
 }
 
-var file_api_mesh_v1alpha1_instance_proto_msgTypes = 
make([]protoimpl.MessageInfo, 3)
+var file_api_mesh_v1alpha1_instance_proto_msgTypes = 
make([]protoimpl.MessageInfo, 2)
 var file_api_mesh_v1alpha1_instance_proto_goTypes = []any{
-       (*Instance)(nil),       // 0: dubbo.mesh.v1alpha1.Instance
-       (*Instance_Probe)(nil), // 1: dubbo.mesh.v1alpha1.Instance.Probe
-       nil,                    // 2: dubbo.mesh.v1alpha1.Instance.TagsEntry
+       (*Instance)(nil),  // 0: dubbo.mesh.v1alpha1.Instance
+       nil,               // 1: dubbo.mesh.v1alpha1.Instance.TagsEntry
+       (*Probe)(nil),     // 2: dubbo.mesh.v1alpha1.Probe
+       (*Condition)(nil), // 3: dubbo.mesh.v1alpha1.Condition
 }
 var file_api_mesh_v1alpha1_instance_proto_depIdxs = []int32{
-       2, // 0: dubbo.mesh.v1alpha1.Instance.tags:type_name -> 
dubbo.mesh.v1alpha1.Instance.TagsEntry
-       1, // 1: dubbo.mesh.v1alpha1.Instance.probes:type_name -> 
dubbo.mesh.v1alpha1.Instance.Probe
-       2, // [2:2] is the sub-list for method output_type
-       2, // [2:2] is the sub-list for method input_type
-       2, // [2:2] is the sub-list for extension type_name
-       2, // [2:2] is the sub-list for extension extendee
-       0, // [0:2] is the sub-list for field type_name
+       1, // 0: dubbo.mesh.v1alpha1.Instance.tags:type_name -> 
dubbo.mesh.v1alpha1.Instance.TagsEntry
+       2, // 1: dubbo.mesh.v1alpha1.Instance.probes:type_name -> 
dubbo.mesh.v1alpha1.Probe
+       3, // 2: dubbo.mesh.v1alpha1.Instance.conditions:type_name -> 
dubbo.mesh.v1alpha1.Condition
+       3, // [3:3] is the sub-list for method output_type
+       3, // [3:3] is the sub-list for method input_type
+       3, // [3:3] is the sub-list for extension type_name
+       3, // [3:3] is the sub-list for extension extendee
+       0, // [0:3] is the sub-list for field type_name
 }
 
 func init() { file_api_mesh_v1alpha1_instance_proto_init() }
@@ -371,13 +331,14 @@ func file_api_mesh_v1alpha1_instance_proto_init() {
        if File_api_mesh_v1alpha1_instance_proto != nil {
                return
        }
+       file_api_mesh_v1alpha1_runtime_instance_proto_init()
        type x struct{}
        out := protoimpl.TypeBuilder{
                File: protoimpl.DescBuilder{
                        GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
                        RawDescriptor: 
file_api_mesh_v1alpha1_instance_proto_rawDesc,
                        NumEnums:      0,
-                       NumMessages:   3,
+                       NumMessages:   2,
                        NumExtensions: 0,
                        NumServices:   0,
                },
diff --git a/api/mesh/v1alpha1/instance.proto b/api/mesh/v1alpha1/instance.proto
index 33ec8719..b475261c 100644
--- a/api/mesh/v1alpha1/instance.proto
+++ b/api/mesh/v1alpha1/instance.proto
@@ -5,6 +5,7 @@ package dubbo.mesh.v1alpha1;
 option go_package = "github.com/apache/dubbo-admin/api/mesh/v1alpha1";
 
 import "api/mesh/options.proto";
+import "api/mesh/v1alpha1/runtime_instance.proto";
 
 // Instance is merged from RuntimeInstance and RPCInstance, indicates a 
runtime entity of a specific dubbo application
 message Instance {
@@ -13,19 +14,14 @@ message Instance {
   option (dubbo.mesh.resource).package = "mesh";
   option (dubbo.mesh.resource).is_experimental = true;
 
-  message Probe {
-    string type = 1;
-    int32 port = 2;
-  }
+  string name = 1;
+
+  string ip = 2;
 
   /*
   FROM RPCInstance
    */
 
-  string name = 1;
-
-  string ip = 2;
-
   int32 rpcPort = 3;
 
   int32 qosPort = 4;
@@ -68,5 +64,7 @@ message Instance {
 
   repeated Probe probes = 59;
 
-  reserved 60 to 100;
+  repeated Condition conditions = 60;
+
+  reserved 61 to 100;
 }
\ No newline at end of file
diff --git a/api/mesh/v1alpha1/rpc_instance_metadata.pb.go 
b/api/mesh/v1alpha1/rpc_instance_metadata.pb.go
index 31360155..117f4ede 100644
--- a/api/mesh/v1alpha1/rpc_instance_metadata.pb.go
+++ b/api/mesh/v1alpha1/rpc_instance_metadata.pb.go
@@ -21,7 +21,7 @@ const (
        _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
 )
 
-type RPCInstanceMetaData struct {
+type RPCInstanceMetadata struct {
        state         protoimpl.MessageState
        sizeCache     protoimpl.SizeCache
        unknownFields protoimpl.UnknownFields
@@ -32,20 +32,20 @@ type RPCInstanceMetaData struct {
        Services map[string]*ServiceInfo 
`protobuf:"bytes,4,rep,name=services,proto3" json:"services,omitempty" 
protobuf_key:"bytes,1,opt,name=key,proto3" 
protobuf_val:"bytes,2,opt,name=value,proto3"`
 }
 
-func (x *RPCInstanceMetaData) Reset() {
-       *x = RPCInstanceMetaData{}
+func (x *RPCInstanceMetadata) Reset() {
+       *x = RPCInstanceMetadata{}
        mi := &file_api_mesh_v1alpha1_rpc_instance_metadata_proto_msgTypes[0]
        ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
        ms.StoreMessageInfo(mi)
 }
 
-func (x *RPCInstanceMetaData) String() string {
+func (x *RPCInstanceMetadata) String() string {
        return protoimpl.X.MessageStringOf(x)
 }
 
-func (*RPCInstanceMetaData) ProtoMessage() {}
+func (*RPCInstanceMetadata) ProtoMessage() {}
 
-func (x *RPCInstanceMetaData) ProtoReflect() protoreflect.Message {
+func (x *RPCInstanceMetadata) ProtoReflect() protoreflect.Message {
        mi := &file_api_mesh_v1alpha1_rpc_instance_metadata_proto_msgTypes[0]
        if x != nil {
                ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
@@ -57,26 +57,26 @@ func (x *RPCInstanceMetaData) ProtoReflect() 
protoreflect.Message {
        return mi.MessageOf(x)
 }
 
-// Deprecated: Use RPCInstanceMetaData.ProtoReflect.Descriptor instead.
-func (*RPCInstanceMetaData) Descriptor() ([]byte, []int) {
+// Deprecated: Use RPCInstanceMetadata.ProtoReflect.Descriptor instead.
+func (*RPCInstanceMetadata) Descriptor() ([]byte, []int) {
        return 
file_api_mesh_v1alpha1_rpc_instance_metadata_proto_rawDescGZIP(), []int{0}
 }
 
-func (x *RPCInstanceMetaData) GetApp() string {
+func (x *RPCInstanceMetadata) GetApp() string {
        if x != nil {
                return x.App
        }
        return ""
 }
 
-func (x *RPCInstanceMetaData) GetRevision() string {
+func (x *RPCInstanceMetadata) GetRevision() string {
        if x != nil {
                return x.Revision
        }
        return ""
 }
 
-func (x *RPCInstanceMetaData) GetServices() map[string]*ServiceInfo {
+func (x *RPCInstanceMetadata) GetServices() map[string]*ServiceInfo {
        if x != nil {
                return x.Services
        }
@@ -186,13 +186,13 @@ var 
file_api_mesh_v1alpha1_rpc_instance_metadata_proto_rawDesc = []byte{
        0x70, 0x68, 0x61, 0x31, 0x1a, 0x16, 0x61, 0x70, 0x69, 0x2f, 0x6d, 0x65, 
0x73, 0x68, 0x2f, 0x6f,
        0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 
0x22, 0xaf, 0x02, 0x0a,
        0x13, 0x52, 0x50, 0x43, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 
0x4d, 0x65, 0x74, 0x61,
-       0x44, 0x61, 0x74, 0x61, 0x12, 0x10, 0x0a, 0x03, 0x61, 0x70, 0x70, 0x18, 
0x01, 0x20, 0x01, 0x28,
+       0x64, 0x61, 0x74, 0x61, 0x12, 0x10, 0x0a, 0x03, 0x61, 0x70, 0x70, 0x18, 
0x01, 0x20, 0x01, 0x28,
        0x09, 0x52, 0x03, 0x61, 0x70, 0x70, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 
0x76, 0x69, 0x73, 0x69,
        0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x72, 0x65, 
0x76, 0x69, 0x73, 0x69,
        0x6f, 0x6e, 0x12, 0x52, 0x0a, 0x08, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 
0x65, 0x73, 0x18, 0x04,
        0x20, 0x03, 0x28, 0x0b, 0x32, 0x36, 0x2e, 0x64, 0x75, 0x62, 0x62, 0x6f, 
0x2e, 0x6d, 0x65, 0x73,
        0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x52, 
0x50, 0x43, 0x49, 0x6e,
-       0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x44, 0x61, 
0x74, 0x61, 0x2e, 0x53,
+       0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 
0x74, 0x61, 0x2e, 0x53,
        0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 
0x52, 0x08, 0x73, 0x65,
        0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x1a, 0x5d, 0x0a, 0x0d, 0x53, 0x65, 
0x72, 0x76, 0x69, 0x63,
        0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 
0x65, 0x79, 0x18, 0x01,
@@ -201,8 +201,8 @@ var 
file_api_mesh_v1alpha1_rpc_instance_metadata_proto_rawDesc = []byte{
        0x2e, 0x6d, 0x65, 0x73, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 
0x61, 0x31, 0x2e, 0x53,
        0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x05, 
0x76, 0x61, 0x6c, 0x75,
        0x65, 0x3a, 0x02, 0x38, 0x01, 0x3a, 0x37, 0xaa, 0x8c, 0x89, 0xa6, 0x01, 
0x31, 0x0a, 0x13, 0x52,
-       0x70, 0x63, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x4d, 0x65, 
0x74, 0x61, 0x64, 0x61,
-       0x74, 0x61, 0x12, 0x14, 0x52, 0x70, 0x63, 0x49, 0x6e, 0x73, 0x74, 0x61, 
0x6e, 0x63, 0x65, 0x4d,
+       0x50, 0x43, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x4d, 0x65, 
0x74, 0x61, 0x64, 0x61,
+       0x74, 0x61, 0x12, 0x14, 0x52, 0x50, 0x43, 0x49, 0x6e, 0x73, 0x74, 0x61, 
0x6e, 0x63, 0x65, 0x4d,
        0x65, 0x74, 0x61, 0x44, 0x61, 0x74, 0x61, 0x73, 0x1a, 0x04, 0x6d, 0x65, 
0x73, 0x68, 0x22, 0x96,
        0x02, 0x0a, 0x0b, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x6e, 
0x66, 0x6f, 0x12, 0x12,
        0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 
0x52, 0x04, 0x6e, 0x61,
@@ -242,15 +242,15 @@ func 
file_api_mesh_v1alpha1_rpc_instance_metadata_proto_rawDescGZIP() []byte {
 
 var file_api_mesh_v1alpha1_rpc_instance_metadata_proto_msgTypes = 
make([]protoimpl.MessageInfo, 4)
 var file_api_mesh_v1alpha1_rpc_instance_metadata_proto_goTypes = []any{
-       (*RPCInstanceMetaData)(nil), // 0: 
dubbo.mesh.v1alpha1.RPCInstanceMetaData
+       (*RPCInstanceMetadata)(nil), // 0: 
dubbo.mesh.v1alpha1.RPCInstanceMetadata
        (*ServiceInfo)(nil),         // 1: dubbo.mesh.v1alpha1.ServiceInfo
-       nil,                         // 2: 
dubbo.mesh.v1alpha1.RPCInstanceMetaData.ServicesEntry
+       nil,                         // 2: 
dubbo.mesh.v1alpha1.RPCInstanceMetadata.ServicesEntry
        nil,                         // 3: 
dubbo.mesh.v1alpha1.ServiceInfo.ParamsEntry
 }
 var file_api_mesh_v1alpha1_rpc_instance_metadata_proto_depIdxs = []int32{
-       2, // 0: dubbo.mesh.v1alpha1.RPCInstanceMetaData.services:type_name -> 
dubbo.mesh.v1alpha1.RPCInstanceMetaData.ServicesEntry
+       2, // 0: dubbo.mesh.v1alpha1.RPCInstanceMetadata.services:type_name -> 
dubbo.mesh.v1alpha1.RPCInstanceMetadata.ServicesEntry
        3, // 1: dubbo.mesh.v1alpha1.ServiceInfo.params:type_name -> 
dubbo.mesh.v1alpha1.ServiceInfo.ParamsEntry
-       1, // 2: 
dubbo.mesh.v1alpha1.RPCInstanceMetaData.ServicesEntry.value:type_name -> 
dubbo.mesh.v1alpha1.ServiceInfo
+       1, // 2: 
dubbo.mesh.v1alpha1.RPCInstanceMetadata.ServicesEntry.value:type_name -> 
dubbo.mesh.v1alpha1.ServiceInfo
        3, // [3:3] is the sub-list for method output_type
        3, // [3:3] is the sub-list for method input_type
        3, // [3:3] is the sub-list for extension type_name
diff --git a/api/mesh/v1alpha1/rpc_instance_metadata.proto 
b/api/mesh/v1alpha1/rpc_instance_metadata.proto
index ecccdd2f..045b6f71 100644
--- a/api/mesh/v1alpha1/rpc_instance_metadata.proto
+++ b/api/mesh/v1alpha1/rpc_instance_metadata.proto
@@ -6,9 +6,9 @@ option go_package = 
"github.com/apache/dubbo-admin/api/mesh/v1alpha1";
 
 import "api/mesh/options.proto";
 
-message RPCInstanceMetaData {
-  option (dubbo.mesh.resource).name = "RpcInstanceMetadata";
-  option (dubbo.mesh.resource).plural_name = "RpcInstanceMetaDatas";
+message RPCInstanceMetadata {
+  option (dubbo.mesh.resource).name = "RPCInstanceMetadata";
+  option (dubbo.mesh.resource).plural_name = "RPCInstanceMetaDatas";
   option (dubbo.mesh.resource).package = "mesh";
   option (dubbo.mesh.resource).is_experimental = false;
 
diff --git a/api/mesh/v1alpha1/runtime_instance.pb.go 
b/api/mesh/v1alpha1/runtime_instance.pb.go
index 97e5effc..8772e5a5 100644
--- a/api/mesh/v1alpha1/runtime_instance.pb.go
+++ b/api/mesh/v1alpha1/runtime_instance.pb.go
@@ -27,15 +27,19 @@ type RuntimeInstance struct {
        sizeCache     protoimpl.SizeCache
        unknownFields protoimpl.UnknownFields
 
-       Name         string `protobuf:"bytes,1,opt,name=name,proto3" 
json:"name,omitempty"`
-       Ip           string `protobuf:"bytes,2,opt,name=ip,proto3" 
json:"ip,omitempty"`
-       Port         string `protobuf:"bytes,3,opt,name=port,proto3" 
json:"port,omitempty"`
-       Image        string `protobuf:"bytes,4,opt,name=image,proto3" 
json:"image,omitempty"`
-       AppName      string `protobuf:"bytes,5,opt,name=appName,proto3" 
json:"appName,omitempty"`
-       CreateTime   string `protobuf:"bytes,6,opt,name=createTime,proto3" 
json:"createTime,omitempty"`
-       StartTime    string `protobuf:"bytes,7,opt,name=startTime,proto3" 
json:"startTime,omitempty"`
-       ReadyTime    string `protobuf:"bytes,8,opt,name=readyTime,proto3" 
json:"readyTime,omitempty"`
-       RegisterTime string `protobuf:"bytes,9,opt,name=registerTime,proto3" 
json:"registerTime,omitempty"`
+       Name         string       `protobuf:"bytes,1,opt,name=name,proto3" 
json:"name,omitempty"`
+       Ip           string       `protobuf:"bytes,2,opt,name=ip,proto3" 
json:"ip,omitempty"`
+       Image        string       `protobuf:"bytes,3,opt,name=image,proto3" 
json:"image,omitempty"`
+       AppName      string       `protobuf:"bytes,4,opt,name=appName,proto3" 
json:"appName,omitempty"`
+       CreateTime   string       
`protobuf:"bytes,5,opt,name=createTime,proto3" json:"createTime,omitempty"`
+       StartTime    string       `protobuf:"bytes,6,opt,name=startTime,proto3" 
json:"startTime,omitempty"`
+       ReadyTime    string       `protobuf:"bytes,7,opt,name=readyTime,proto3" 
json:"readyTime,omitempty"`
+       Phase        string       `protobuf:"bytes,8,opt,name=phase,proto3" 
json:"phase,omitempty"`
+       WorkloadName string       
`protobuf:"bytes,9,opt,name=workloadName,proto3" json:"workloadName,omitempty"`
+       WorkloadType string       
`protobuf:"bytes,10,opt,name=workloadType,proto3" json:"workloadType,omitempty"`
+       Node         string       `protobuf:"bytes,11,opt,name=node,proto3" 
json:"node,omitempty"`
+       Probes       []*Probe     `protobuf:"bytes,12,rep,name=probes,proto3" 
json:"probes,omitempty"`
+       Conditions   []*Condition 
`protobuf:"bytes,13,rep,name=conditions,proto3" json:"conditions,omitempty"`
 }
 
 func (x *RuntimeInstance) Reset() {
@@ -82,13 +86,6 @@ func (x *RuntimeInstance) GetIp() string {
        return ""
 }
 
-func (x *RuntimeInstance) GetPort() string {
-       if x != nil {
-               return x.Port
-       }
-       return ""
-}
-
 func (x *RuntimeInstance) GetImage() string {
        if x != nil {
                return x.Image
@@ -124,9 +121,175 @@ func (x *RuntimeInstance) GetReadyTime() string {
        return ""
 }
 
-func (x *RuntimeInstance) GetRegisterTime() string {
+func (x *RuntimeInstance) GetPhase() string {
+       if x != nil {
+               return x.Phase
+       }
+       return ""
+}
+
+func (x *RuntimeInstance) GetWorkloadName() string {
+       if x != nil {
+               return x.WorkloadName
+       }
+       return ""
+}
+
+func (x *RuntimeInstance) GetWorkloadType() string {
+       if x != nil {
+               return x.WorkloadType
+       }
+       return ""
+}
+
+func (x *RuntimeInstance) GetNode() string {
+       if x != nil {
+               return x.Node
+       }
+       return ""
+}
+
+func (x *RuntimeInstance) GetProbes() []*Probe {
+       if x != nil {
+               return x.Probes
+       }
+       return nil
+}
+
+func (x *RuntimeInstance) GetConditions() []*Condition {
+       if x != nil {
+               return x.Conditions
+       }
+       return nil
+}
+
+type Probe struct {
+       state         protoimpl.MessageState
+       sizeCache     protoimpl.SizeCache
+       unknownFields protoimpl.UnknownFields
+
+       Type string `protobuf:"bytes,1,opt,name=type,proto3" 
json:"type,omitempty"`
+       Port int32  `protobuf:"varint,2,opt,name=port,proto3" 
json:"port,omitempty"`
+}
+
+func (x *Probe) Reset() {
+       *x = Probe{}
+       mi := &file_api_mesh_v1alpha1_runtime_instance_proto_msgTypes[1]
+       ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+       ms.StoreMessageInfo(mi)
+}
+
+func (x *Probe) String() string {
+       return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Probe) ProtoMessage() {}
+
+func (x *Probe) ProtoReflect() protoreflect.Message {
+       mi := &file_api_mesh_v1alpha1_runtime_instance_proto_msgTypes[1]
+       if x != nil {
+               ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+               if ms.LoadMessageInfo() == nil {
+                       ms.StoreMessageInfo(mi)
+               }
+               return ms
+       }
+       return mi.MessageOf(x)
+}
+
+// Deprecated: Use Probe.ProtoReflect.Descriptor instead.
+func (*Probe) Descriptor() ([]byte, []int) {
+       return file_api_mesh_v1alpha1_runtime_instance_proto_rawDescGZIP(), 
[]int{1}
+}
+
+func (x *Probe) GetType() string {
+       if x != nil {
+               return x.Type
+       }
+       return ""
+}
+
+func (x *Probe) GetPort() int32 {
+       if x != nil {
+               return x.Port
+       }
+       return 0
+}
+
+// reference: 
https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#pod-conditions
+type Condition struct {
+       state         protoimpl.MessageState
+       sizeCache     protoimpl.SizeCache
+       unknownFields protoimpl.UnknownFields
+
+       Type               string `protobuf:"bytes,1,opt,name=type,proto3" 
json:"type,omitempty"`
+       Status             string `protobuf:"bytes,2,opt,name=status,proto3" 
json:"status,omitempty"`
+       LastTransitionTime string 
`protobuf:"bytes,3,opt,name=lastTransitionTime,proto3" 
json:"lastTransitionTime,omitempty"`
+       Reason             string `protobuf:"bytes,4,opt,name=reason,proto3" 
json:"reason,omitempty"`
+       Message            string `protobuf:"bytes,5,opt,name=message,proto3" 
json:"message,omitempty"`
+}
+
+func (x *Condition) Reset() {
+       *x = Condition{}
+       mi := &file_api_mesh_v1alpha1_runtime_instance_proto_msgTypes[2]
+       ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+       ms.StoreMessageInfo(mi)
+}
+
+func (x *Condition) String() string {
+       return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Condition) ProtoMessage() {}
+
+func (x *Condition) ProtoReflect() protoreflect.Message {
+       mi := &file_api_mesh_v1alpha1_runtime_instance_proto_msgTypes[2]
+       if x != nil {
+               ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+               if ms.LoadMessageInfo() == nil {
+                       ms.StoreMessageInfo(mi)
+               }
+               return ms
+       }
+       return mi.MessageOf(x)
+}
+
+// Deprecated: Use Condition.ProtoReflect.Descriptor instead.
+func (*Condition) Descriptor() ([]byte, []int) {
+       return file_api_mesh_v1alpha1_runtime_instance_proto_rawDescGZIP(), 
[]int{2}
+}
+
+func (x *Condition) GetType() string {
+       if x != nil {
+               return x.Type
+       }
+       return ""
+}
+
+func (x *Condition) GetStatus() string {
+       if x != nil {
+               return x.Status
+       }
+       return ""
+}
+
+func (x *Condition) GetLastTransitionTime() string {
+       if x != nil {
+               return x.LastTransitionTime
+       }
+       return ""
+}
+
+func (x *Condition) GetReason() string {
+       if x != nil {
+               return x.Reason
+       }
+       return ""
+}
+
+func (x *Condition) GetMessage() string {
        if x != nil {
-               return x.RegisterTime
+               return x.Message
        }
        return ""
 }
@@ -139,30 +302,53 @@ var file_api_mesh_v1alpha1_runtime_instance_proto_rawDesc 
= []byte{
        0x61, 0x6e, 0x63, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x13, 
0x64, 0x75, 0x62, 0x62,
        0x6f, 0x2e, 0x6d, 0x65, 0x73, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 
0x68, 0x61, 0x31, 0x1a,
        0x16, 0x61, 0x70, 0x69, 0x2f, 0x6d, 0x65, 0x73, 0x68, 0x2f, 0x6f, 0x70, 
0x74, 0x69, 0x6f, 0x6e,
-       0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xac, 0x02, 0x0a, 0x0f, 
0x52, 0x75, 0x6e, 0x74,
+       0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xda, 0x03, 0x0a, 0x0f, 
0x52, 0x75, 0x6e, 0x74,
        0x69, 0x6d, 0x65, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x12, 
0x12, 0x0a, 0x04, 0x6e,
        0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 
0x61, 0x6d, 0x65, 0x12,
        0x0e, 0x0a, 0x02, 0x69, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 
0x02, 0x69, 0x70, 0x12,
-       0x12, 0x0a, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 
0x09, 0x52, 0x04, 0x70,
-       0x6f, 0x72, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x6d, 0x61, 0x67, 0x65, 
0x18, 0x04, 0x20, 0x01,
-       0x28, 0x09, 0x52, 0x05, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x12, 0x18, 0x0a, 
0x07, 0x61, 0x70, 0x70,
-       0x4e, 0x61, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 
0x61, 0x70, 0x70, 0x4e,
-       0x61, 0x6d, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 
0x65, 0x54, 0x69, 0x6d,
-       0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x63, 0x72, 0x65, 
0x61, 0x74, 0x65, 0x54,
-       0x69, 0x6d, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x74, 0x61, 0x72, 0x74, 
0x54, 0x69, 0x6d, 0x65,
-       0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x74, 0x61, 0x72, 
0x74, 0x54, 0x69, 0x6d,
-       0x65, 0x12, 0x1c, 0x0a, 0x09, 0x72, 0x65, 0x61, 0x64, 0x79, 0x54, 0x69, 
0x6d, 0x65, 0x18, 0x08,
-       0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x72, 0x65, 0x61, 0x64, 0x79, 0x54, 
0x69, 0x6d, 0x65, 0x12,
-       0x22, 0x0a, 0x0c, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x54, 
0x69, 0x6d, 0x65, 0x18,
-       0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x72, 0x65, 0x67, 0x69, 0x73, 
0x74, 0x65, 0x72, 0x54,
-       0x69, 0x6d, 0x65, 0x3a, 0x31, 0xaa, 0x8c, 0x89, 0xa6, 0x01, 0x2b, 0x0a, 
0x0f, 0x52, 0x75, 0x6e,
-       0x74, 0x69, 0x6d, 0x65, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 
0x12, 0x10, 0x52, 0x75,
-       0x6e, 0x74, 0x69, 0x6d, 0x65, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 
0x65, 0x73, 0x1a, 0x04,
-       0x6d, 0x65, 0x73, 0x68, 0x20, 0x01, 0x42, 0x31, 0x5a, 0x2f, 0x67, 0x69, 
0x74, 0x68, 0x75, 0x62,
-       0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x61, 0x70, 0x61, 0x63, 0x68, 0x65, 0x2f, 
0x64, 0x75, 0x62, 0x62,
-       0x6f, 0x2d, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2f, 0x61, 0x70, 0x69, 0x2f, 
0x6d, 0x65, 0x73, 0x68,
-       0x2f, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x62, 0x06, 0x70, 
0x72, 0x6f, 0x74, 0x6f,
-       0x33,
+       0x14, 0x0a, 0x05, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x18, 0x03, 0x20, 0x01, 
0x28, 0x09, 0x52, 0x05,
+       0x69, 0x6d, 0x61, 0x67, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x70, 0x70, 
0x4e, 0x61, 0x6d, 0x65,
+       0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x70, 0x70, 0x4e, 
0x61, 0x6d, 0x65, 0x12,
+       0x1e, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 
0x65, 0x18, 0x05, 0x20,
+       0x01, 0x28, 0x09, 0x52, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 
0x69, 0x6d, 0x65, 0x12,
+       0x1c, 0x0a, 0x09, 0x73, 0x74, 0x61, 0x72, 0x74, 0x54, 0x69, 0x6d, 0x65, 
0x18, 0x06, 0x20, 0x01,
+       0x28, 0x09, 0x52, 0x09, 0x73, 0x74, 0x61, 0x72, 0x74, 0x54, 0x69, 0x6d, 
0x65, 0x12, 0x1c, 0x0a,
+       0x09, 0x72, 0x65, 0x61, 0x64, 0x79, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x07, 
0x20, 0x01, 0x28, 0x09,
+       0x52, 0x09, 0x72, 0x65, 0x61, 0x64, 0x79, 0x54, 0x69, 0x6d, 0x65, 0x12, 
0x14, 0x0a, 0x05, 0x70,
+       0x68, 0x61, 0x73, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 
0x70, 0x68, 0x61, 0x73,
+       0x65, 0x12, 0x22, 0x0a, 0x0c, 0x77, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, 
0x64, 0x4e, 0x61, 0x6d,
+       0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x77, 0x6f, 0x72, 
0x6b, 0x6c, 0x6f, 0x61,
+       0x64, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x22, 0x0a, 0x0c, 0x77, 0x6f, 0x72, 
0x6b, 0x6c, 0x6f, 0x61,
+       0x64, 0x54, 0x79, 0x70, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 
0x0c, 0x77, 0x6f, 0x72,
+       0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x54, 0x79, 0x70, 0x65, 0x12, 0x12, 0x0a, 
0x04, 0x6e, 0x6f, 0x64,
+       0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x6f, 0x64, 
0x65, 0x12, 0x32, 0x0a,
+       0x06, 0x70, 0x72, 0x6f, 0x62, 0x65, 0x73, 0x18, 0x0c, 0x20, 0x03, 0x28, 
0x0b, 0x32, 0x1a, 0x2e,
+       0x64, 0x75, 0x62, 0x62, 0x6f, 0x2e, 0x6d, 0x65, 0x73, 0x68, 0x2e, 0x76, 
0x31, 0x61, 0x6c, 0x70,
+       0x68, 0x61, 0x31, 0x2e, 0x50, 0x72, 0x6f, 0x62, 0x65, 0x52, 0x06, 0x70, 
0x72, 0x6f, 0x62, 0x65,
+       0x73, 0x12, 0x3e, 0x0a, 0x0a, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 
0x6f, 0x6e, 0x73, 0x18,
+       0x0d, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x64, 0x75, 0x62, 0x62, 
0x6f, 0x2e, 0x6d, 0x65,
+       0x73, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 
0x43, 0x6f, 0x6e, 0x64,
+       0x69, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0a, 0x63, 0x6f, 0x6e, 0x64, 0x69, 
0x74, 0x69, 0x6f, 0x6e,
+       0x73, 0x3a, 0x31, 0xaa, 0x8c, 0x89, 0xa6, 0x01, 0x2b, 0x0a, 0x0f, 0x52, 
0x75, 0x6e, 0x74, 0x69,
+       0x6d, 0x65, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x10, 
0x52, 0x75, 0x6e, 0x74,
+       0x69, 0x6d, 0x65, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 
0x1a, 0x04, 0x6d, 0x65,
+       0x73, 0x68, 0x20, 0x01, 0x22, 0x2f, 0x0a, 0x05, 0x50, 0x72, 0x6f, 0x62, 
0x65, 0x12, 0x12, 0x0a,
+       0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 
0x04, 0x74, 0x79, 0x70,
+       0x65, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x02, 0x20, 
0x01, 0x28, 0x05, 0x52,
+       0x04, 0x70, 0x6f, 0x72, 0x74, 0x22, 0x99, 0x01, 0x0a, 0x09, 0x43, 0x6f, 
0x6e, 0x64, 0x69, 0x74,
+       0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 
0x01, 0x20, 0x01, 0x28,
+       0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x73, 
0x74, 0x61, 0x74, 0x75,
+       0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x74, 0x61, 
0x74, 0x75, 0x73, 0x12,
+       0x2e, 0x0a, 0x12, 0x6c, 0x61, 0x73, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 
0x69, 0x74, 0x69, 0x6f,
+       0x6e, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 
0x12, 0x6c, 0x61, 0x73,
+       0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x54, 
0x69, 0x6d, 0x65, 0x12,
+       0x16, 0x0a, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18, 0x04, 0x20, 
0x01, 0x28, 0x09, 0x52,
+       0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x6d, 
0x65, 0x73, 0x73, 0x61,
+       0x67, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 
0x73, 0x73, 0x61, 0x67,
+       0x65, 0x42, 0x31, 0x5a, 0x2f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 
0x63, 0x6f, 0x6d, 0x2f,
+       0x61, 0x70, 0x61, 0x63, 0x68, 0x65, 0x2f, 0x64, 0x75, 0x62, 0x62, 0x6f, 
0x2d, 0x61, 0x64, 0x6d,
+       0x69, 0x6e, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x6d, 0x65, 0x73, 0x68, 0x2f, 
0x76, 0x31, 0x61, 0x6c,
+       0x70, 0x68, 0x61, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
 }
 
 var (
@@ -177,16 +363,20 @@ func 
file_api_mesh_v1alpha1_runtime_instance_proto_rawDescGZIP() []byte {
        return file_api_mesh_v1alpha1_runtime_instance_proto_rawDescData
 }
 
-var file_api_mesh_v1alpha1_runtime_instance_proto_msgTypes = 
make([]protoimpl.MessageInfo, 1)
+var file_api_mesh_v1alpha1_runtime_instance_proto_msgTypes = 
make([]protoimpl.MessageInfo, 3)
 var file_api_mesh_v1alpha1_runtime_instance_proto_goTypes = []any{
        (*RuntimeInstance)(nil), // 0: dubbo.mesh.v1alpha1.RuntimeInstance
+       (*Probe)(nil),           // 1: dubbo.mesh.v1alpha1.Probe
+       (*Condition)(nil),       // 2: dubbo.mesh.v1alpha1.Condition
 }
 var file_api_mesh_v1alpha1_runtime_instance_proto_depIdxs = []int32{
-       0, // [0:0] is the sub-list for method output_type
-       0, // [0:0] is the sub-list for method input_type
-       0, // [0:0] is the sub-list for extension type_name
-       0, // [0:0] is the sub-list for extension extendee
-       0, // [0:0] is the sub-list for field type_name
+       1, // 0: dubbo.mesh.v1alpha1.RuntimeInstance.probes:type_name -> 
dubbo.mesh.v1alpha1.Probe
+       2, // 1: dubbo.mesh.v1alpha1.RuntimeInstance.conditions:type_name -> 
dubbo.mesh.v1alpha1.Condition
+       2, // [2:2] is the sub-list for method output_type
+       2, // [2:2] is the sub-list for method input_type
+       2, // [2:2] is the sub-list for extension type_name
+       2, // [2:2] is the sub-list for extension extendee
+       0, // [0:2] is the sub-list for field type_name
 }
 
 func init() { file_api_mesh_v1alpha1_runtime_instance_proto_init() }
@@ -200,7 +390,7 @@ func file_api_mesh_v1alpha1_runtime_instance_proto_init() {
                        GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
                        RawDescriptor: 
file_api_mesh_v1alpha1_runtime_instance_proto_rawDesc,
                        NumEnums:      0,
-                       NumMessages:   1,
+                       NumMessages:   3,
                        NumExtensions: 0,
                        NumServices:   0,
                },
diff --git a/api/mesh/v1alpha1/runtime_instance.proto 
b/api/mesh/v1alpha1/runtime_instance.proto
index 9e4d08de..65abb130 100644
--- a/api/mesh/v1alpha1/runtime_instance.proto
+++ b/api/mesh/v1alpha1/runtime_instance.proto
@@ -17,17 +17,44 @@ message RuntimeInstance {
 
   string ip = 2;
 
-  string port = 3;
+  string image = 3;
 
-  string image = 4;
+  string appName = 4;
 
-  string appName = 5;
+  string createTime = 5;
 
-  string createTime = 6;
+  string startTime = 6;
 
-  string startTime = 7;
+  string readyTime = 7;
 
-  string readyTime = 8;
+  string phase = 8;
 
+  string workloadName = 9;
 
+  string workloadType = 10;
+
+  string node = 11;
+
+  repeated Probe probes = 12;
+
+  repeated Condition conditions = 13;
+}
+
+message Probe {
+  string type = 1;
+  int32 port = 2;
+}
+
+// reference: 
https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#pod-conditions
+message Condition{
+
+  string type = 1;
+
+  string status = 2;
+
+  string lastTransitionTime = 3;
+
+  string reason = 4;
+
+  string message = 5;
 }
\ No newline at end of file
diff --git a/pkg/store/db/mysql.go 
b/api/mesh/v1alpha1/runtime_instance_helper.go
similarity index 83%
copy from pkg/store/db/mysql.go
copy to api/mesh/v1alpha1/runtime_instance_helper.go
index 43e59a33..c69c002a 100644
--- a/pkg/store/db/mysql.go
+++ b/api/mesh/v1alpha1/runtime_instance_helper.go
@@ -15,6 +15,12 @@
  * limitations under the License.
  */
 
-package db
+package v1alpha1
 
-// TODO implement memory resource store, refer to GORM https://gorm.io/docs/
+const (
+       LivenessProbe  = "liveness"
+       ReadinessProbe = "readiness"
+       StartupProbe   = "startup"
+)
+
+const InstanceTerminating = "Terminating"
diff --git a/api/mesh/v1alpha1/service_provider_metadata.pb.go 
b/api/mesh/v1alpha1/service_provider_metadata.pb.go
index f81530b0..73a3bd3c 100644
--- a/api/mesh/v1alpha1/service_provider_metadata.pb.go
+++ b/api/mesh/v1alpha1/service_provider_metadata.pb.go
@@ -21,7 +21,7 @@ const (
        _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
 )
 
-type ServiceProviderMetaData struct {
+type ServiceProviderMetadata struct {
        state         protoimpl.MessageState
        sizeCache     protoimpl.SizeCache
        unknownFields protoimpl.UnknownFields
@@ -32,20 +32,20 @@ type ServiceProviderMetaData struct {
        Group           string `protobuf:"bytes,4,opt,name=group,proto3" 
json:"group,omitempty"` // TODO add more fields
 }
 
-func (x *ServiceProviderMetaData) Reset() {
-       *x = ServiceProviderMetaData{}
+func (x *ServiceProviderMetadata) Reset() {
+       *x = ServiceProviderMetadata{}
        mi := 
&file_api_mesh_v1alpha1_service_provider_metadata_proto_msgTypes[0]
        ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
        ms.StoreMessageInfo(mi)
 }
 
-func (x *ServiceProviderMetaData) String() string {
+func (x *ServiceProviderMetadata) String() string {
        return protoimpl.X.MessageStringOf(x)
 }
 
-func (*ServiceProviderMetaData) ProtoMessage() {}
+func (*ServiceProviderMetadata) ProtoMessage() {}
 
-func (x *ServiceProviderMetaData) ProtoReflect() protoreflect.Message {
+func (x *ServiceProviderMetadata) ProtoReflect() protoreflect.Message {
        mi := 
&file_api_mesh_v1alpha1_service_provider_metadata_proto_msgTypes[0]
        if x != nil {
                ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
@@ -57,33 +57,33 @@ func (x *ServiceProviderMetaData) ProtoReflect() 
protoreflect.Message {
        return mi.MessageOf(x)
 }
 
-// Deprecated: Use ServiceProviderMetaData.ProtoReflect.Descriptor instead.
-func (*ServiceProviderMetaData) Descriptor() ([]byte, []int) {
+// Deprecated: Use ServiceProviderMetadata.ProtoReflect.Descriptor instead.
+func (*ServiceProviderMetadata) Descriptor() ([]byte, []int) {
        return 
file_api_mesh_v1alpha1_service_provider_metadata_proto_rawDescGZIP(), []int{0}
 }
 
-func (x *ServiceProviderMetaData) GetServiceName() string {
+func (x *ServiceProviderMetadata) GetServiceName() string {
        if x != nil {
                return x.ServiceName
        }
        return ""
 }
 
-func (x *ServiceProviderMetaData) GetProviderAppName() string {
+func (x *ServiceProviderMetadata) GetProviderAppName() string {
        if x != nil {
                return x.ProviderAppName
        }
        return ""
 }
 
-func (x *ServiceProviderMetaData) GetVersion() string {
+func (x *ServiceProviderMetadata) GetVersion() string {
        if x != nil {
                return x.Version
        }
        return ""
 }
 
-func (x *ServiceProviderMetaData) GetGroup() string {
+func (x *ServiceProviderMetadata) GetGroup() string {
        if x != nil {
                return x.Group
        }
@@ -100,7 +100,7 @@ var 
file_api_mesh_v1alpha1_service_provider_metadata_proto_rawDesc = []byte{
        0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x1a, 0x16, 0x61, 0x70, 
0x69, 0x2f, 0x6d, 0x65,
        0x73, 0x68, 0x2f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 
0x72, 0x6f, 0x74, 0x6f,
        0x22, 0xd6, 0x01, 0x0a, 0x17, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 
0x50, 0x72, 0x6f, 0x76,
-       0x69, 0x64, 0x65, 0x72, 0x4d, 0x65, 0x74, 0x61, 0x44, 0x61, 0x74, 0x61, 
0x12, 0x20, 0x0a, 0x0b,
+       0x69, 0x64, 0x65, 0x72, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 
0x12, 0x20, 0x0a, 0x0b,
        0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x18, 
0x01, 0x20, 0x01, 0x28,
        0x09, 0x52, 0x0b, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4e, 0x61, 
0x6d, 0x65, 0x12, 0x28,
        0x0a, 0x0f, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x41, 0x70, 
0x70, 0x4e, 0x61, 0x6d,
@@ -133,7 +133,7 @@ func 
file_api_mesh_v1alpha1_service_provider_metadata_proto_rawDescGZIP() []byte
 
 var file_api_mesh_v1alpha1_service_provider_metadata_proto_msgTypes = 
make([]protoimpl.MessageInfo, 1)
 var file_api_mesh_v1alpha1_service_provider_metadata_proto_goTypes = []any{
-       (*ServiceProviderMetaData)(nil), // 0: 
dubbo.mesh.v1alpha1.ServiceProviderMetaData
+       (*ServiceProviderMetadata)(nil), // 0: 
dubbo.mesh.v1alpha1.ServiceProviderMetadata
 }
 var file_api_mesh_v1alpha1_service_provider_metadata_proto_depIdxs = []int32{
        0, // [0:0] is the sub-list for method output_type
diff --git a/api/mesh/v1alpha1/service_provider_metadata.proto 
b/api/mesh/v1alpha1/service_provider_metadata.proto
index df402ff0..abbf4a26 100644
--- a/api/mesh/v1alpha1/service_provider_metadata.proto
+++ b/api/mesh/v1alpha1/service_provider_metadata.proto
@@ -6,7 +6,7 @@ option go_package = 
"github.com/apache/dubbo-admin/api/mesh/v1alpha1";
 
 import "api/mesh/options.proto";
 
-message ServiceProviderMetaData {
+message ServiceProviderMetadata {
   option (dubbo.mesh.resource).name = "ServiceProviderMetadata";
   option (dubbo.mesh.resource).plural_name = "ServiceProviderMetaDatas";
   option (dubbo.mesh.resource).package = "mesh";
diff --git a/app/dubbo-admin/cmd/root.go b/app/dubbo-admin/cmd/root.go
index 363d1c77..e49deda3 100644
--- a/app/dubbo-admin/cmd/root.go
+++ b/app/dubbo-admin/cmd/root.go
@@ -30,8 +30,6 @@ import (
        "github.com/apache/dubbo-admin/pkg/core/cmd/version"
 )
 
-var adminLog = core.Log.WithName("admin")
-
 // newRootCmd represents the base command when called without any subcommands.
 func newRootCmd() *cobra.Command {
        args := struct {
diff --git a/app/dubbo-admin/cmd/run.go b/app/dubbo-admin/cmd/run.go
index 6bd94b9c..67e14f4c 100644
--- a/app/dubbo-admin/cmd/run.go
+++ b/app/dubbo-admin/cmd/run.go
@@ -18,7 +18,6 @@
 package cmd
 
 import (
-       "fmt"
        "time"
 
        "github.com/spf13/cobra"
@@ -27,11 +26,10 @@ import (
        "github.com/apache/dubbo-admin/pkg/config/app"
        "github.com/apache/dubbo-admin/pkg/core/bootstrap"
        dubbocmd "github.com/apache/dubbo-admin/pkg/core/cmd"
+       "github.com/apache/dubbo-admin/pkg/core/logger"
        dubboversion "github.com/apache/dubbo-admin/pkg/version"
 )
 
-var runLog = adminLog.WithName("run")
-
 const gracefullyShutdownDuration = 3 * time.Second
 
 // This is the open file limit below which the control plane may not
@@ -51,44 +49,43 @@ func newRunCmdWithOpts(opts dubbocmd.RunCmdOpts) 
*cobra.Command {
                        cfg := app.DefaultAdminConfig()
                        err := config.Load(args.configPath, &cfg)
                        if err != nil {
-                               runLog.Error(err, "could not load the 
configuration")
+                               logger.Errorf("could not load the 
configuration, err: %s", err.Error())
                                return err
 
                        }
                        cfgForDisplay, err := config.ConfigForDisplay(&cfg)
                        if err != nil {
-                               runLog.Error(err, "unable to prepare config for 
display")
+                               logger.Errorf("unable to prepare config for 
display, err: %s", err.Error())
                                return err
                        }
                        cfgBytes, err := config.ToJson(cfgForDisplay)
                        if err != nil {
-                               runLog.Error(err, "unable to convert config to 
json")
+                               logger.Errorf("unable to convert config to 
json, err: %s", err.Error())
                                return err
                        }
-                       runLog.Info(fmt.Sprintf("Current config %s", cfgBytes))
-                       runLog.Info(fmt.Sprintf("Running in mode `%s`", 
cfg.Mode))
+                       logger.Infof("Current config %s", cfgBytes)
+                       logger.Infof("Running in mode `%s`", cfg.Mode)
 
                        // 2. build components
                        gracefulCtx, ctx := opts.SetupSignalHandler()
                        rt, err := bootstrap.Bootstrap(gracefulCtx, cfg)
                        if err != nil {
-                               runLog.Error(err, "unable to bootstrap")
+                               logger.Errorf("unable to bootstrap, err: %s", 
err.Error())
                                return err
                        }
 
                        // 3. start components
-                       runLog.Info("starting Admin......", "version", 
dubboversion.Build.Version)
+                       logger.Infof("starting Admin......, version: %s", 
dubboversion.Build.Version)
                        if err := rt.Start(gracefulCtx.Done()); err != nil {
-                               runLog.Error(err, "problem running Admin")
+                               logger.Errorf("problem running Admin, err: %s", 
err.Error())
                                return err
                        }
-
-                       runLog.Info("stop signal received. Waiting 3 seconds 
for components to stop gracefully...")
+                       logger.Info("stop signal received. Waiting 3 seconds 
for components to stop gracefully...")
                        select {
                        case <-ctx.Done():
-                               runLog.Info("all components have stopped")
+                               logger.Info("all components have stopped")
                        case <-time.After(gracefullyShutdownDuration):
-                               runLog.Info("forcefully stopped")
+                               logger.Info("forcefully stopped")
                        }
                        return nil
                },
diff --git a/app/dubbo-admin/dubbo-admin.yaml b/app/dubbo-admin/dubbo-admin.yaml
index 6147444d..932304ea 100644
--- a/app/dubbo-admin/dubbo-admin.yaml
+++ b/app/dubbo-admin/dubbo-admin.yaml
@@ -45,11 +45,54 @@ discovery:
       registry: nacos://47.76.94.134:8848?username=nacos&password=nacos
       configCenter: nacos://47.76.94.134:8848?username=nacos&password=nacos
       metadataReport: nacos://47.76.94.134:8848?username=nacos&password=nacos
-  - type: istio
+
+  - type: etcd
+    id: etcd-44.33
+    address: http://127.0.0.1:2379
+
+  # mock discovery is only for development
+  - type: mock
 engine:
   name: k8s1.28.6
   type: kubernetes
   properties:
-    apiServerAddress: https://192.168.1.1:6443
-    kubeConfig: /etc/kubernetes/admin.conf
+    # [Kubernetes] Path to kubernetes config file, if not set, will use in 
cluster config
+    kubeConfigPath: /root/.kube/config
+    # [Kubernetes] Watch pods with specified labels, if not set, will watch 
all pods
+    # podWatchSelector: org.apache.dubbo/dubbo-apps=true
+    # [Kubernetes] Identify which Dubbo app the pod belongs to, if not set, 
[type = ByIP] will be used
+    # 1. ByLabels: Use the label value corresponding to the labelKey as the 
dubbo app name
+    # e.g.
+    #    type: ByLabel
+    #    labelKey: org.apache.dubbo/dubbo-app-name
+    # 2. ByAnnotation: Use the annotation value corresponding to the 
annotationKey as the dubbo app name
+    # e.g.
+    #    type: ByAnnotation
+    #    annotationKey: org.apache.dubbo/dubbo-app-name
+    # 3. ByIP(default): Use pod's IP to find if there is a same ip of an 
instance and use the instance's app name as the identifier,
+    # if there is no such association, the pod will not be seen as a pod of 
dubbo application.
+    # e.g.
+    #    type: ByIP
+#    dubboAppIdentifier:
+#      type: ByLabel
+#      labelKey: org.apache.dubbo/dubbo-app-name
+    # [Kubernetes] Strategy of choosing the main container, if not set, [type 
= ByIndex] and [index = 0] will be used
+    # 1. ByLast: choose the last container as the main container
+    # e.g.
+    #    type: ByLast
+    # 2. ByIndex(default): choose the container at the specified index 
location as the main container
+    # e.g.
+    #    type: ByIndex
+    #    index: 0
+    # 3. ByName: choose the container with the specified name
+    # e.g.
+    #    type: ByName
+    #    name: main
+    # 4. ByAnnotation: choose the container with the annotation key, specified 
annotation value will be used as the container name
+    # e.g.
+    #    type: ByAnnotation
+    #    annotationKey: org.apache.dubbo/main-container-name=${app-name}
+    mainContainerChooseStrategy:
+      type: ByIndex
+      index: 0
 controlPlane:
\ No newline at end of file
diff --git a/go.mod b/go.mod
index 04925354..c60caef1 100644
--- a/go.mod
+++ b/go.mod
@@ -55,6 +55,7 @@ require (
        google.golang.org/grpc v1.73.0
        google.golang.org/protobuf v1.36.6
        gopkg.in/natefinch/lumberjack.v2 v2.2.1
+       k8s.io/api v0.32.0
        k8s.io/apimachinery v0.32.0
        k8s.io/client-go v0.32.0
        k8s.io/klog/v2 v2.130.1
@@ -78,7 +79,9 @@ require (
        github.com/gabriel-vasile/mimetype v1.4.8 // indirect
        github.com/gin-contrib/sse v1.0.0 // indirect
        github.com/go-jose/go-jose/v4 v4.0.5 // indirect
+       github.com/go-openapi/jsonpointer v0.21.0 // indirect
        github.com/go-openapi/jsonreference v0.21.0 // indirect
+       github.com/go-openapi/swag v0.23.0 // indirect
        github.com/go-playground/locales v0.14.1 // indirect
        github.com/go-playground/universal-translator v0.18.1 // indirect
        github.com/go-playground/validator/v10 v10.26.0 // indirect
@@ -92,9 +95,11 @@ require (
        github.com/gorilla/securecookie v1.1.2 // indirect
        github.com/gorilla/sessions v1.4.0 // indirect
        github.com/inconshreveable/mousetrap v1.1.0 // indirect
+       github.com/josharian/intern v1.0.0 // indirect
        github.com/json-iterator/go v1.1.12 // indirect
        github.com/klauspost/cpuid/v2 v2.2.10 // indirect
        github.com/leodido/go-urn v1.4.0 // indirect
+       github.com/mailru/easyjson v0.7.7 // indirect
        github.com/mattn/go-isatty v0.0.20 // indirect
        github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // 
indirect
        github.com/modern-go/reflect2 v1.0.2 // indirect
@@ -121,9 +126,11 @@ require (
        golang.org/x/tools v0.28.0 // indirect
        google.golang.org/genproto/googleapis/api 
v0.0.0-20250324211829-b45e905df463 // indirect
        google.golang.org/genproto/googleapis/rpc 
v0.0.0-20250324211829-b45e905df463 // indirect
+       gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect
        gopkg.in/inf.v0 v0.9.1 // indirect
        gopkg.in/yaml.v2 v2.4.0 // indirect
        gopkg.in/yaml.v3 v3.0.1 // indirect
+       k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f // indirect
        k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 // indirect
        sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 // indirect
        sigs.k8s.io/structured-merge-diff/v4 v4.4.2 // indirect
diff --git a/pkg/config/discovery/config.go b/pkg/config/discovery/config.go
index e748ff23..fe4dfd00 100644
--- a/pkg/config/discovery/config.go
+++ b/pkg/config/discovery/config.go
@@ -22,8 +22,10 @@ import "github.com/apache/dubbo-admin/pkg/config"
 type Type string
 
 const (
-       zookeeper Type = "zookeeper"
-       nacos     Type = "nacos"
+       Zookeeper Type = "zookeeper"
+       Nacos     Type = "nacos"
+       // Mock is only for develop and test
+       Mock Type = "mock"
 )
 
 // Config defines Discovery configuration
@@ -44,7 +46,7 @@ type AddressConfig struct {
 func DefaultDiscoveryEnginConfig() *Config {
        return &Config{
                Name: "localhost",
-               Type: nacos,
+               Type: Nacos,
                Address: AddressConfig{
                        Registry:       
"nacos://127.0.0.1:8848?username=nacos&password=nacos",
                        ConfigCenter:   
"nacos://127.0.0.1:8848?username=nacos&password=nacos",
diff --git a/pkg/config/engine/config.go b/pkg/config/engine/config.go
index 706404f3..299620ed 100644
--- a/pkg/config/engine/config.go
+++ b/pkg/config/engine/config.go
@@ -28,15 +28,62 @@ const (
 
 type Config struct {
        config.BaseConfig
-       Name       string            `json:"name"`
-       Type       Type              `json:"type"`
-       Properties map[string]string `json:"properties"`
+       Name       string     `json:"name"`
+       Type       Type       `json:"type"`
+       Properties Properties `json:"properties"`
+}
+
+type Properties struct {
+       KubeConfigPath              string                       
`json:"kubeConfigPath"`
+       PodWatchSelector            string                       
`json:"podWatchSelector"`
+       DubboAppIdentifier          *DubboAppIdentifier          
`json:"dubboAppIdentifier"`
+       MainContainerChooseStrategy *MainContainerChooseStrategy 
`json:"mainContainerChooseStrategy"`
+}
+
+func (p *Properties) GetOrDefaultMainContainerChooseStrategy() 
*MainContainerChooseStrategy {
+       if p.MainContainerChooseStrategy == nil {
+               return &MainContainerChooseStrategy{
+                       Type:  ChooseByIndex,
+                       Index: 0,
+               }
+       }
+       return p.MainContainerChooseStrategy
+}
+
+type MainContainerChooseStrategyType string
+
+const (
+       ChooseByLast       MainContainerChooseStrategyType = "ByLast"
+       ChooseByIndex      MainContainerChooseStrategyType = "ByIndex"
+       ChooseByName       MainContainerChooseStrategyType = "ByName"
+       ChooseByAnnotation MainContainerChooseStrategyType = "ByAnnotation"
+)
+
+type MainContainerChooseStrategy struct {
+       Type          MainContainerChooseStrategyType `json:"type"`
+       Index         int                             `json:"index"`
+       Name          string                          `json:"name"`
+       AnnotationKey string                          `json:"annotationKey"`
+}
+
+type DubboAppIdentifierType string
+
+const (
+       IdentifyByLabel      DubboAppIdentifierType = "ByLabel"
+       IdentifyByAnnotation DubboAppIdentifierType = "ByAnnotation"
+       IdentifyByIP         DubboAppIdentifierType = "ByIP"
+)
+
+type DubboAppIdentifier struct {
+       Type          DubboAppIdentifierType `json:"type"`
+       LabelKey      string                 `json:"labelKey"`
+       AnnotationKey string                 `json:"annotationKey"`
 }
 
 func DefaultResourceEngineConfig() *Config {
        return &Config{
                Name:       "default",
                Type:       VM,
-               Properties: map[string]string{},
+               Properties: Properties{},
        }
 }
diff --git a/pkg/console/component.go b/pkg/console/component.go
index fd4f94db..1672b95f 100644
--- a/pkg/console/component.go
+++ b/pkg/console/component.go
@@ -53,7 +53,7 @@ func (c *consoleWebServer) Type() runtime.ComponentType {
 }
 
 func (c *consoleWebServer) Order() int {
-       return math.MaxInt
+       return math.MaxInt - 5
 }
 
 func (c *consoleWebServer) Init(ctx runtime.BuilderContext) error {
diff --git a/pkg/core/bootstrap/init.go b/pkg/core/bootstrap/init.go
index 2fecda05..32d94f36 100644
--- a/pkg/core/bootstrap/init.go
+++ b/pkg/core/bootstrap/init.go
@@ -17,6 +17,7 @@
 
 package bootstrap
 
+// import all components registered by init function
 import (
        _ "github.com/apache/dubbo-admin/pkg/console"
        _ "github.com/apache/dubbo-admin/pkg/core/discovery"
@@ -24,5 +25,7 @@ import (
        _ "github.com/apache/dubbo-admin/pkg/core/events"
        _ "github.com/apache/dubbo-admin/pkg/core/manager"
        _ "github.com/apache/dubbo-admin/pkg/core/store"
+       _ "github.com/apache/dubbo-admin/pkg/discovery/mock"
+       _ "github.com/apache/dubbo-admin/pkg/engine/kubernetes"
        _ "github.com/apache/dubbo-admin/pkg/store/memory"
 )
diff --git a/pkg/core/consts/const.go b/pkg/core/consts/const.go
index 785c84f4..0bacadee 100644
--- a/pkg/core/consts/const.go
+++ b/pkg/core/consts/const.go
@@ -101,3 +101,7 @@ const (
        NotEqual = "!="
        Equal    = "="
 )
+
+const (
+       TimeFormatStr = "2006-01-02 15:04:05"
+)
diff --git a/pkg/core/controller/informer.go b/pkg/core/controller/informer.go
index 28cf884b..e2ab1393 100644
--- a/pkg/core/controller/informer.go
+++ b/pkg/core/controller/informer.go
@@ -43,6 +43,17 @@ type Informer interface {
        // Adding event handlers to already stopped informers is not possible.
        // An informer already stopped will never be started again.
        IsStopped() bool
+
+       // SetTransform The TransformFunc is called for each object which is 
about to be stored.
+       //
+       // This function is intended for you to take the opportunity to
+       // remove, transform, or normalize fields. One use case is to strip 
unused
+       // metadata fields out of objects to save on RAM cost.
+       //
+       // Must be set before starting the informer.
+       //
+       // Please see the comment on TransformFunc for more details.
+       SetTransform(handler cache.TransformFunc) error
 }
 
 // Options configures an informer.
@@ -91,13 +102,11 @@ type informer struct {
        transform cache.TransformFunc
 }
 
-func NewInformerWithOptions(lw cache.ListerWatcher, emitter events.Emitter, 
store store.ResourceStore,
-       exampleObject runtime.Object, options Options) Informer {
+func NewInformerWithOptions(lw cache.ListerWatcher, emitter events.Emitter, 
store store.ResourceStore, options Options) Informer {
        return &informer{
                indexer:           store,
                listerWatcher:     lw,
                emitter:           emitter,
-               objectType:        exampleObject,
                resyncCheckPeriod: options.ResyncPeriod,
        }
 }
@@ -126,6 +135,17 @@ func (s *informer) SetTransform(handler 
cache.TransformFunc) error {
        return nil
 }
 
+func (s *informer) SetObjectType(objectType runtime.Object) error {
+       s.startedLock.Lock()
+       defer s.startedLock.Unlock()
+
+       if s.started {
+               return fmt.Errorf("informer has already started")
+       }
+       s.objectType = objectType
+       return nil
+}
+
 func (s *informer) Run(stopCh <-chan struct{}) {
        defer utilruntime.HandleCrash()
        defer func() {
diff --git a/pkg/core/controller/listwatcher.go 
b/pkg/core/controller/listwatcher.go
index f15006b7..e90580f0 100644
--- a/pkg/core/controller/listwatcher.go
+++ b/pkg/core/controller/listwatcher.go
@@ -24,6 +24,10 @@ import (
 )
 
 type ResourceListerWatcher interface {
-       ResourceKind() coremodel.ResourceKind
        cache.ListerWatcher
+       // ResourceKind returns the kind of resource this listerwatcher is for
+       ResourceKind() coremodel.ResourceKind
+       // TransformFunc transform the raw resource into your need before the 
raw resource pushing into the delta fifo,
+       // return nil if there is no need to transform, see 
cache.SharedInformer for detail
+       TransformFunc() cache.TransformFunc
 }
diff --git a/pkg/core/discovery/component.go b/pkg/core/discovery/component.go
index 8751bfb1..2bc0476b 100644
--- a/pkg/core/discovery/component.go
+++ b/pkg/core/discovery/component.go
@@ -18,8 +18,11 @@
 package discovery
 
 import (
+       "fmt"
        "math"
+       "reflect"
 
+       "github.com/apache/dubbo-admin/pkg/common/bizerror"
        "github.com/apache/dubbo-admin/pkg/config/discovery"
        "github.com/apache/dubbo-admin/pkg/core/controller"
        "github.com/apache/dubbo-admin/pkg/core/events"
@@ -57,7 +60,7 @@ func (d *discoveryComponent) Type() runtime.ComponentType {
 }
 
 func (d *discoveryComponent) Order() int {
-       return math.MaxInt
+       return math.MaxInt - 2
 }
 
 func (d *discoveryComponent) Init(ctx runtime.BuilderContext) error {
@@ -110,21 +113,26 @@ func (d *discoveryComponent) newInformers(cfg 
*discovery.Config, ctx runtime.Bui
        if err != nil {
                return nil, err
        }
-       emitter := eventBusComponent.(events.Emitter)
+       emitter, ok := eventBusComponent.(events.Emitter)
+       if !ok {
+               return nil, bizerror.NewAssertionError("Emitter", 
reflect.TypeOf(eventBusComponent).Name())
+       }
        storeComponent, err := ctx.GetActivatedComponent(runtime.ResourceStore)
        if err != nil {
-               return nil, err
+               return nil, fmt.Errorf("can not retrieve store from runtime in 
engine %s, %w", cfg.Name, err)
+       }
+       storeRouter, ok := storeComponent.(store.Router)
+       if !ok {
+               return nil, bizerror.NewAssertionError("store.Router", 
reflect.TypeOf(storeComponent).Name())
        }
-       resourceStore := storeComponent.(store.ResourceStore)
-       var informers Informers
-       for _, lw := range lwList {
-               rk := lw.ResourceKind()
-               newFunc, err := 
coremodel.ResourceSchemaRegistry().NewResourceFunc(rk)
+       var informers = make([]controller.Informer, len(lwList))
+       for i, lw := range lwList {
+               resourceStore, err := 
storeRouter.ResourceKindRoute(lw.ResourceKind())
                if err != nil {
-                       return nil, err
+                       return nil, fmt.Errorf("cannot find store for resource 
kind %s", lw.ResourceKind())
                }
-               informer := controller.NewInformerWithOptions(lw, emitter, 
resourceStore, newFunc(), controller.Options{ResyncPeriod: 0})
-               informers = append(informers, informer)
+               informer := controller.NewInformerWithOptions(lw, emitter, 
resourceStore, controller.Options{ResyncPeriod: 0})
+               informers[i] = informer
        }
        return informers, nil
 }
diff --git a/pkg/core/engine/component.go b/pkg/core/engine/component.go
index 6aa5fa74..783aa340 100644
--- a/pkg/core/engine/component.go
+++ b/pkg/core/engine/component.go
@@ -20,11 +20,15 @@ package engine
 import (
        "fmt"
        "math"
+       "reflect"
 
+       "github.com/apache/dubbo-admin/pkg/common/bizerror"
+       enginecfg "github.com/apache/dubbo-admin/pkg/config/engine"
        "github.com/apache/dubbo-admin/pkg/core/controller"
+       "github.com/apache/dubbo-admin/pkg/core/engine/subscriber"
        "github.com/apache/dubbo-admin/pkg/core/events"
        "github.com/apache/dubbo-admin/pkg/core/logger"
-       coremodel "github.com/apache/dubbo-admin/pkg/core/resource/model"
+       meshresource 
"github.com/apache/dubbo-admin/pkg/core/resource/apis/mesh/v1alpha1"
        "github.com/apache/dubbo-admin/pkg/core/runtime"
        "github.com/apache/dubbo-admin/pkg/core/store"
 )
@@ -41,25 +45,59 @@ type Component interface {
 var _ Component = &engineComponent{}
 
 type engineComponent struct {
-       name      string
-       informers []controller.Informer
+       name                string
+       storeRouter         store.Router
+       informers           []controller.Informer
+       subscriptionManager events.SubscriptionManager
+       subscribers         []events.Subscriber
 }
 
 func newEngineComponent() Component {
        return &engineComponent{
-               informers: make([]controller.Informer, 0),
+               informers:   make([]controller.Informer, 0),
+               subscribers: make([]events.Subscriber, 0),
        }
 }
-func (b *engineComponent) Type() runtime.ComponentType {
+func (e *engineComponent) Type() runtime.ComponentType {
        return runtime.ResourceEngine
 }
 
-func (b *engineComponent) Order() int {
-       return math.MaxInt
+func (e *engineComponent) Order() int {
+       return math.MaxInt - 3
 }
 
-func (b *engineComponent) Init(ctx runtime.BuilderContext) error {
+func (e *engineComponent) Init(ctx runtime.BuilderContext) error {
        cfg := ctx.Config().Engine
+       e.name = cfg.Name
+       eventBusComponent, err := ctx.GetActivatedComponent(runtime.EventBus)
+       if err != nil {
+               return fmt.Errorf("can not retrieve event bus from runtime in 
engine %s, %w", cfg.Name, err)
+       }
+       eventBus, ok := eventBusComponent.(events.EventBus)
+       if !ok {
+               return bizerror.NewAssertionError("EventBus", 
reflect.TypeOf(eventBusComponent).Name())
+       }
+       e.subscriptionManager = eventBus
+       storeComponent, err := ctx.GetActivatedComponent(runtime.ResourceStore)
+       if err != nil {
+               return fmt.Errorf("can not retrieve store from runtime in 
engine %s, %w", e.name, err)
+       }
+       storeRouter, ok := storeComponent.(store.Router)
+       if !ok {
+               return bizerror.NewAssertionError("store.Router", 
reflect.TypeOf(storeComponent).Name())
+       }
+       e.storeRouter = storeRouter
+       if err = e.initInformers(cfg, eventBus); err != nil {
+               return fmt.Errorf("init informer failed, %w", err)
+       }
+       if err = e.initSubscribers(eventBus); err != nil {
+               return fmt.Errorf("init subscribers failed, %w", err)
+       }
+       logger.Infof("resource engine %s has been inited successfully", e.name)
+       return nil
+}
+
+func (e *engineComponent) initInformers(cfg *enginecfg.Config, emitter 
events.Emitter) error {
        factory, err := FactoryRegistry().GetListWatcherFactory(cfg.Type)
        if err != nil {
                return err
@@ -69,40 +107,45 @@ func (b *engineComponent) Init(ctx runtime.BuilderContext) 
error {
                return err
        }
        for _, lw := range lwList {
-               eventBusComponent, err := 
ctx.GetActivatedComponent(runtime.EventBus)
-               if err != nil {
-                       return err
-               }
-               emitter, ok := eventBusComponent.(events.Emitter)
-               if !ok {
-                       return fmt.Errorf("type assertion failed, event bus 
component in runtime is not an Emitter")
-               }
-               storeComponent, err := 
ctx.GetActivatedComponent(runtime.ResourceStore)
-               if err != nil {
-                       return err
-               }
-               resourceStore, ok := storeComponent.(store.ResourceStore)
-               if !ok {
-                       return fmt.Errorf("type assertion failed, resource 
store component in runtime is not a ResourceStore")
-               }
                rk := lw.ResourceKind()
-               newFunc, err := 
coremodel.ResourceSchemaRegistry().NewResourceFunc(rk)
+               rs, err := e.storeRouter.ResourceKindRoute(rk)
                if err != nil {
-                       return err
+                       return fmt.Errorf("can not find store for resource kind 
%s, %w", rk, err)
+               }
+               informer := controller.NewInformerWithOptions(lw, emitter, rs, 
controller.Options{ResyncPeriod: 0})
+               if lw.TransformFunc() != nil {
+                       err = informer.SetTransform(lw.TransformFunc())
+                       if err != nil {
+                               return fmt.Errorf("can not set transform for 
informer of resource kind %s, %w", rk, err)
+                       }
                }
-               informer := controller.NewInformerWithOptions(lw, emitter, 
resourceStore,
-                       newFunc(), controller.Options{ResyncPeriod: 0})
-               b.informers = append(b.informers, informer)
+               e.informers = append(e.informers, informer)
+               logger.Infof("resource engine %s has added informer for 
resource kind %s", e.name, rk)
+       }
+       return nil
+}
+
+func (e *engineComponent) initSubscribers(eventbus events.EventBus) error {
+       rs, err := e.storeRouter.ResourceKindRoute(meshresource.InstanceKind)
+       if err != nil {
+               return fmt.Errorf("can not find store for resource kind %s, 
%w", meshresource.RuntimeInstanceKind, err)
        }
-       b.name = cfg.Name
-       logger.Infof("resource engine %s has been inited successfully", b.name)
+       runtimeInstanceSub := subscriber.NewRuntimeInstanceEventSubscriber(rs, 
eventbus)
+       e.subscribers = append(e.subscribers, runtimeInstanceSub)
        return nil
 }
 
-func (b *engineComponent) Start(_ runtime.Runtime, ch <-chan struct{}) error {
-       for _, informer := range b.informers {
+func (e *engineComponent) Start(_ runtime.Runtime, ch <-chan struct{}) error {
+       // 1. subscribe resource changed events
+       for _, sub := range e.subscribers {
+               if err := e.subscriptionManager.Subscribe(sub); err != nil {
+                       return fmt.Errorf("could not subscribe %s to eventbus, 
%w", sub.Name(), err)
+               }
+       }
+       // 2. start informers
+       for _, informer := range e.informers {
                go informer.Run(ch)
        }
-       logger.Infof("resource engine %s has started successfully", b.name)
+       logger.Infof("resource engine %s has started successfully", e.name)
        return nil
 }
diff --git a/pkg/core/engine/factory.go b/pkg/core/engine/factory.go
index 4b86df96..19f27d46 100644
--- a/pkg/core/engine/factory.go
+++ b/pkg/core/engine/factory.go
@@ -20,7 +20,7 @@ package engine
 import (
        "fmt"
 
-       "github.com/apache/dubbo-admin/pkg/config/engine"
+       enginecfg "github.com/apache/dubbo-admin/pkg/config/engine"
        "github.com/apache/dubbo-admin/pkg/core/controller"
 )
 
@@ -36,12 +36,12 @@ func FactoryRegistry() Registry {
 
 // Factory defines if a specific engine type is supported and how to create 
ListWatchers
 type Factory interface {
-       Support(engine.Type) bool
-       NewListWatchers(*engine.Config) ([]controller.ResourceListerWatcher, 
error)
+       Support(enginecfg.Type) bool
+       NewListWatchers(*enginecfg.Config) ([]controller.ResourceListerWatcher, 
error)
 }
 
 type Registry interface {
-       GetListWatcherFactory(engine.Type) (Factory, error)
+       GetListWatcherFactory(enginecfg.Type) (Factory, error)
 }
 
 type RegistryMutator interface {
@@ -70,7 +70,7 @@ func (e *listWatchFactoryRegistry) Register(factory Factory) {
        e.factories = append(e.factories, factory)
 }
 
-func (e *listWatchFactoryRegistry) GetListWatcherFactory(t engine.Type) 
(Factory, error) {
+func (e *listWatchFactoryRegistry) GetListWatcherFactory(t enginecfg.Type) 
(Factory, error) {
        for _, factory := range e.factories {
                if factory.Support(t) {
                        return factory, nil
diff --git a/pkg/core/engine/subscriber/runtime_instance.go 
b/pkg/core/engine/subscriber/runtime_instance.go
new file mode 100644
index 00000000..212a114f
--- /dev/null
+++ b/pkg/core/engine/subscriber/runtime_instance.go
@@ -0,0 +1,186 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package subscriber
+
+import (
+       "errors"
+       "reflect"
+
+       "github.com/duke-git/lancet/v2/strutil"
+       "k8s.io/client-go/tools/cache"
+
+       "github.com/apache/dubbo-admin/pkg/common/bizerror"
+       "github.com/apache/dubbo-admin/pkg/core/events"
+       "github.com/apache/dubbo-admin/pkg/core/logger"
+       meshresource 
"github.com/apache/dubbo-admin/pkg/core/resource/apis/mesh/v1alpha1"
+       coremodel "github.com/apache/dubbo-admin/pkg/core/resource/model"
+       "github.com/apache/dubbo-admin/pkg/core/store"
+       "github.com/apache/dubbo-admin/pkg/core/store/index"
+)
+
+type RuntimeInstanceEventSubscriber struct {
+       instanceResourceStore store.ResourceStore
+       eventEmitter          events.Emitter
+}
+
+func (s *RuntimeInstanceEventSubscriber) ResourceKind() coremodel.ResourceKind 
{
+       return meshresource.RuntimeInstanceKind
+}
+
+func (s *RuntimeInstanceEventSubscriber) Name() string {
+       return "Engine-" + s.ResourceKind().ToString()
+}
+
+func (s *RuntimeInstanceEventSubscriber) ProcessEvent(event events.Event) 
error {
+       newObj, ok := event.NewObj().(*meshresource.RuntimeInstanceResource)
+       if !ok && newObj != nil {
+               return 
bizerror.NewAssertionError(meshresource.RuntimeInstanceKind, 
reflect.TypeOf(event.NewObj()).Name())
+       }
+       oldObj, ok := event.OldObj().(*meshresource.RuntimeInstanceResource)
+       if !ok && oldObj != nil {
+               return 
bizerror.NewAssertionError(meshresource.RuntimeInstanceKind, 
reflect.TypeOf(event.OldObj()).Name())
+       }
+       var processErr error
+       switch event.Type() {
+       case cache.Added, cache.Updated, cache.Replaced, cache.Sync:
+               if newObj == nil {
+                       errStr := "process runtime instance upsert event, but 
new obj is nil, skipped processing"
+                       logger.Error(errStr)
+                       return errors.New(errStr)
+               }
+               processErr = s.processUpsert(newObj)
+       case cache.Deleted:
+               if oldObj == nil {
+                       errStr := "process runtime instance delete event, but 
old obj is nil, skipped processing"
+                       logger.Error(errStr)
+                       return errors.New(errStr)
+               }
+               processErr = s.processDelete(oldObj)
+       }
+       eventStr := event.String()
+       if processErr == nil {
+               logger.Infof("process runtime instance event successfully, 
event: %s", eventStr)
+       } else {
+               logger.Errorf("process runtime instance event failed, event: 
%s, err: %s", eventStr, processErr.Error())
+       }
+       return processErr
+}
+
+func (s *RuntimeInstanceEventSubscriber) getRelatedInstanceResource(
+       rtInstance *meshresource.RuntimeInstanceResource) 
(*meshresource.InstanceResource, error) {
+       resources, err := 
s.instanceResourceStore.ListByIndexes(map[string]string{
+               index.ByInstanceIpIndex: rtInstance.Spec.Ip,
+       })
+       if err != nil {
+               return nil, err
+       }
+       if len(resources) == 0 {
+               return nil, nil
+       }
+       instanceResources := make([]*meshresource.InstanceResource, 
len(resources))
+       for i, item := range resources {
+               if res, ok := item.(*meshresource.InstanceResource); ok {
+                       instanceResources[i] = res
+               } else {
+                       return nil, 
bizerror.NewAssertionError("InstanceResource", reflect.TypeOf(item).Name())
+               }
+       }
+       return instanceResources[0], nil
+}
+
+func (s *RuntimeInstanceEventSubscriber) mergeRuntimeInstance(
+       instanceRes *meshresource.InstanceResource,
+       rtInstanceRes *meshresource.RuntimeInstanceResource) {
+       instanceRes.Name = rtInstanceRes.Name
+       instanceRes.Spec.Name = rtInstanceRes.Spec.Name
+       instanceRes.Spec.Ip = rtInstanceRes.Spec.Ip
+       instanceRes.Labels = rtInstanceRes.Labels
+       instanceRes.Spec.Image = rtInstanceRes.Spec.Image
+       instanceRes.Spec.CreateTime = rtInstanceRes.Spec.CreateTime
+       instanceRes.Spec.StartTime = rtInstanceRes.Spec.StartTime
+       instanceRes.Spec.ReadyTime = rtInstanceRes.Spec.ReadyTime
+       instanceRes.Spec.DeployState = rtInstanceRes.Spec.Phase
+       instanceRes.Spec.WorkloadType = rtInstanceRes.Spec.WorkloadType
+       instanceRes.Spec.WorkloadName = rtInstanceRes.Spec.WorkloadName
+       instanceRes.Spec.Node = rtInstanceRes.Spec.Node
+       instanceRes.Spec.Probes = rtInstanceRes.Spec.Probes
+       instanceRes.Spec.Conditions = rtInstanceRes.Spec.Conditions
+}
+
+func (s *RuntimeInstanceEventSubscriber) fromRuntimeInstance(
+       rtInstanceRes *meshresource.RuntimeInstanceResource) 
*meshresource.InstanceResource {
+       instanceRes := 
meshresource.NewInstanceResourceWithAttributes(rtInstanceRes.Name, 
rtInstanceRes.Mesh)
+       s.mergeRuntimeInstance(instanceRes, rtInstanceRes)
+       return instanceRes
+}
+
+// processUpsert when runtime instance added or updated, we should add/update 
the corresponding instance resource
+func (s *RuntimeInstanceEventSubscriber) processUpsert(rtInstanceRes 
*meshresource.RuntimeInstanceResource) error {
+       instanceResource, err := s.getRelatedInstanceResource(rtInstanceRes)
+       if err != nil {
+               return err
+       }
+       // If instance resource exists, the rpc instance resource exists in 
remote registry and has been watched by discovery.
+       // So we should merge the runtime info into it
+       if instanceResource != nil {
+               s.mergeRuntimeInstance(instanceResource, rtInstanceRes)
+               return s.instanceResourceStore.Update(instanceResource)
+       }
+       // If instance resource does not exist, we should create a new instance 
resource by runtime instance
+       // If the app name is empty, we cannot identify it as a dubbo app, so 
we skip it
+       if strutil.IsBlank(rtInstanceRes.Spec.AppName) {
+               logger.Warnf("cannot identify runtime instance %s as a dubbo 
app, skipped updating instance", rtInstanceRes.Name)
+               return nil
+       }
+       // Otherwise we can create a new instance resource by runtime instance
+       instanceRes := s.fromRuntimeInstance(rtInstanceRes)
+       if err = s.instanceResourceStore.Add(instanceRes); err != nil {
+               logger.Errorf("add instance resource failed, instance: %s, err: 
%s", instanceRes.ResourceKey(), err.Error())
+               return err
+       }
+       instanceAddEvent := events.NewResourceChangedEvent(cache.Added, nil, 
instanceRes)
+       s.eventEmitter.Send(instanceAddEvent)
+       logger.Debugf("runtime instance upsert trigger instance add event, 
event: %s", instanceAddEvent.String())
+       return nil
+}
+
+// processDelete when runtime instance deleted, we should delete the 
corresponding instance resource
+func (s *RuntimeInstanceEventSubscriber) processDelete(rtInstanceRes 
*meshresource.RuntimeInstanceResource) error {
+       instanceResource, err := s.getRelatedInstanceResource(rtInstanceRes)
+       if err != nil {
+               return err
+       }
+       if instanceResource == nil {
+               return nil
+       }
+       if err = 
s.instanceResourceStore.Delete(instanceResource.ResourceKey()); err != nil {
+               logger.Errorf("delete instance resource failed, instance: %s, 
err: %s", instanceResource.ResourceKey(), err.Error())
+               return err
+       }
+       instanceDeleteEvent := events.NewResourceChangedEvent(cache.Deleted, 
instanceResource, nil)
+       s.eventEmitter.Send(instanceDeleteEvent)
+       logger.Debugf("runtime instance delete trigger instance delete event, 
event: %s", instanceDeleteEvent.String())
+       return nil
+}
+
+func NewRuntimeInstanceEventSubscriber(instanceResourceStore 
store.ResourceStore, emitter events.Emitter) events.Subscriber {
+       return &RuntimeInstanceEventSubscriber{
+               instanceResourceStore: instanceResourceStore,
+               eventEmitter:          emitter,
+       }
+}
diff --git a/pkg/core/events/component.go b/pkg/core/events/component.go
index 1c4dcb82..6c1fff9a 100644
--- a/pkg/core/events/component.go
+++ b/pkg/core/events/component.go
@@ -31,13 +31,6 @@ func init() {
        runtime.RegisterComponent(&eventBus{})
 }
 
-type subscriber struct {
-       name         string
-       resourceKind model.ResourceKind
-       processFunc  ProcessEventFunc
-}
-type subscribers []subscriber
-
 type EventBusComponent interface {
        EventBus
        runtime.Component
@@ -47,7 +40,7 @@ var _ EventBusComponent = &eventBus{}
 
 type eventBus struct {
        rwMutex       sync.RWMutex
-       subscriberDir map[model.ResourceKind]subscribers
+       subscriberDir map[model.ResourceKind]Subscribers
 }
 
 func (b *eventBus) Type() runtime.ComponentType {
@@ -59,7 +52,7 @@ func (b *eventBus) Order() int {
 }
 
 func (b *eventBus) Init(_ runtime.BuilderContext) error {
-       b.subscriberDir = make(map[model.ResourceKind]subscribers)
+       b.subscriberDir = make(map[model.ResourceKind]Subscribers)
        return nil
 }
 
@@ -68,36 +61,34 @@ func (b *eventBus) Start(_ runtime.Runtime, _ <-chan 
struct{}) error {
 }
 
 // Subscribe subscribes to a resource kind, ProcessEventFunc is synchronous 
which is used to avoid event loss
-func (b *eventBus) Subscribe(rk model.ResourceKind, name string, process 
ProcessEventFunc) error {
+func (b *eventBus) Subscribe(subscriber Subscriber) error {
        b.rwMutex.Lock()
        defer b.rwMutex.Unlock()
-       subs, exists := b.subscriberDir[rk]
+       subs, exists := b.subscriberDir[subscriber.ResourceKind()]
        if !exists {
-               subs = make(subscribers, 0)
+               subs = make(Subscribers, 0)
        }
        // check name if is unique
        for _, sub := range subs {
-               if sub.name == name {
-                       return fmt.Errorf("duplicated subscriber name %s, 
skipped subscribing", name)
+               if sub.Name() == subscriber.Name() {
+                       return fmt.Errorf("duplicated subscriber name %s, 
skipped subscribing", subscriber.Name())
                }
        }
-       b.subscriberDir[rk] = append(subs, subscriber{
-               name:         name,
-               resourceKind: rk,
-               processFunc:  process,
-       })
+       b.subscriberDir[subscriber.ResourceKind()] = append(subs, subscriber)
        return nil
 }
 
-func (b *eventBus) Unsubscribe(rk model.ResourceKind, name string) error {
+func (b *eventBus) Unsubscribe(subscriber Subscriber) error {
        b.rwMutex.Lock()
        defer b.rwMutex.Unlock()
+       rk := subscriber.ResourceKind()
+       name := subscriber.Name()
        subs, exists := b.subscriberDir[rk]
        if !exists {
                return fmt.Errorf("no subscriber for resource %s, skipped 
unsubscribing", rk)
        }
        for i, sub := range subs {
-               if sub.name == name {
+               if sub.Name() == name {
                        b.subscriberDir[rk] = append(subs[:i], subs[i+1:]...)
                        return nil
                }
@@ -108,7 +99,12 @@ func (b *eventBus) Unsubscribe(rk model.ResourceKind, name 
string) error {
 func (b *eventBus) Send(event Event) {
        b.rwMutex.RLock()
        defer b.rwMutex.RUnlock()
-       rk := event.OldObj().ResourceKind()
+       var rk model.ResourceKind
+       if event.OldObj() != nil {
+               rk = event.OldObj().ResourceKind()
+       } else if event.NewObj() != nil {
+               rk = event.NewObj().ResourceKind()
+       }
        subs, exists := b.subscriberDir[rk]
        if !exists {
                logger.Warnf("no subscriber for resource %s, skipped sending 
event%v", rk, event)
@@ -116,8 +112,8 @@ func (b *eventBus) Send(event Event) {
        }
        for _, sub := range subs {
                // TODO Do we need to support reprocess
-               if err := sub.processFunc(event); err != nil {
-                       logger.Errorf("failed to process event in %s , skipped, 
event: %v", sub.name, event)
+               if err := sub.ProcessEvent(event); err != nil {
+                       logger.Errorf("failed to process event in %s , skipped, 
event: %v", sub.Name(), event)
                }
        }
 }
diff --git a/pkg/core/events/eventbus.go b/pkg/core/events/eventbus.go
index c9956e3f..552d1f47 100644
--- a/pkg/core/events/eventbus.go
+++ b/pkg/core/events/eventbus.go
@@ -18,18 +18,34 @@
 package events
 
 import (
+       "fmt"
+
+       "github.com/duke-git/lancet/v2/convertor"
        "k8s.io/client-go/tools/cache"
 
        "github.com/apache/dubbo-admin/pkg/core/resource/model"
 )
 
 type Event interface {
+       // Type returns the type of the event, see definitions in 
cache.DeltaType
        Type() cache.DeltaType
+       // OldObj returns the old object, nil if old object doesn't exist in 
store
        OldObj() model.Resource
+       // NewObj returns the new object, nil if event type is in 
[cache.Deleted]
        NewObj() model.Resource
+       // String returns the string representation of the event
+       String() string
+}
+
+type Subscriber interface {
+       ResourceKind() model.ResourceKind
+
+       Name() string
+
+       ProcessEvent(event Event) error
 }
 
-type ProcessEventFunc func(event Event) error
+type Subscribers []Subscriber
 
 type ResourceChangedEvent struct {
        typ    cache.DeltaType
@@ -37,6 +53,8 @@ type ResourceChangedEvent struct {
        newObj model.Resource
 }
 
+var _ Event = &ResourceChangedEvent{}
+
 func NewResourceChangedEvent(typ cache.DeltaType, oldObj model.Resource, 
newObj model.Resource) *ResourceChangedEvent {
        return &ResourceChangedEvent{
                typ:    typ,
@@ -57,13 +75,18 @@ func (e *ResourceChangedEvent) NewObj() model.Resource {
        return e.newObj
 }
 
+func (e *ResourceChangedEvent) String() string {
+       return fmt.Sprintf("[type]: %s, [oldObj]: %s, [newObj]: %s",
+               e.typ, convertor.ToString(e.oldObj), 
convertor.ToString(e.newObj))
+}
+
 type Emitter interface {
        Send(event Event)
 }
 
 type SubscriptionManager interface {
-       Subscribe(rk model.ResourceKind, name string, process ProcessEventFunc) 
error
-       Unsubscribe(rk model.ResourceKind, name string) error
+       Subscribe(subscriber Subscriber) error
+       Unsubscribe(subscriber Subscriber) error
 }
 
 type EventBus interface {
diff --git a/pkg/core/manager/component.go b/pkg/core/manager/component.go
index e1834428..e12f3c31 100644
--- a/pkg/core/manager/component.go
+++ b/pkg/core/manager/component.go
@@ -46,7 +46,7 @@ func (r *resourceManagerComponent) Type() 
runtime.ComponentType {
 }
 
 func (r *resourceManagerComponent) Order() int {
-       return math.MaxInt
+       return math.MaxInt - 4
 }
 
 func (r *resourceManagerComponent) Init(ctx runtime.BuilderContext) error {
diff --git a/pkg/core/resource/apis/mesh/v1alpha1/affinityroute_types.go 
b/pkg/core/resource/apis/mesh/v1alpha1/affinityroute_types.go
index ff9f2f28..46fa116b 100644
--- a/pkg/core/resource/apis/mesh/v1alpha1/affinityroute_types.go
+++ b/pkg/core/resource/apis/mesh/v1alpha1/affinityroute_types.go
@@ -21,6 +21,8 @@
 package v1alpha1
 
 import (
+       "encoding/json"
+
        "google.golang.org/protobuf/proto"
        metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
        k8sruntime "k8s.io/apimachinery/pkg/runtime"
@@ -106,6 +108,15 @@ func (r *AffinityRouteResource) DeepCopyObject() 
k8sruntime.Object {
        return out
 }
 
+func (r *AffinityRouteResource) String() string {
+       jsonStr, err := json.Marshal(r)
+       if err != nil {
+               logger.Errorf("failed to encode AffinityRouteResource: %s to 
json, err: %s", r.ResourceKey(), err)
+               return ""
+       }
+       return string(jsonStr)
+}
+
 func NewAffinityRouteResourceWithAttributes(name string, mesh string) 
*AffinityRouteResource {
        return &AffinityRouteResource{
                TypeMeta: metav1.TypeMeta{
diff --git a/pkg/core/resource/apis/mesh/v1alpha1/application_types.go 
b/pkg/core/resource/apis/mesh/v1alpha1/application_types.go
index 6aef4ccc..8fb5e9bb 100644
--- a/pkg/core/resource/apis/mesh/v1alpha1/application_types.go
+++ b/pkg/core/resource/apis/mesh/v1alpha1/application_types.go
@@ -21,6 +21,8 @@
 package v1alpha1
 
 import (
+       "encoding/json"
+
        "google.golang.org/protobuf/proto"
        metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
        k8sruntime "k8s.io/apimachinery/pkg/runtime"
@@ -106,6 +108,15 @@ func (r *ApplicationResource) DeepCopyObject() 
k8sruntime.Object {
        return out
 }
 
+func (r *ApplicationResource) String() string {
+       jsonStr, err := json.Marshal(r)
+       if err != nil {
+               logger.Errorf("failed to encode ApplicationResource: %s to 
json, err: %s", r.ResourceKey(), err)
+               return ""
+       }
+       return string(jsonStr)
+}
+
 func NewApplicationResourceWithAttributes(name string, mesh string) 
*ApplicationResource {
        return &ApplicationResource{
                TypeMeta: metav1.TypeMeta{
diff --git a/pkg/core/resource/apis/mesh/v1alpha1/conditionroute_types.go 
b/pkg/core/resource/apis/mesh/v1alpha1/conditionroute_types.go
index 83b6b8c3..27260d2c 100644
--- a/pkg/core/resource/apis/mesh/v1alpha1/conditionroute_types.go
+++ b/pkg/core/resource/apis/mesh/v1alpha1/conditionroute_types.go
@@ -21,6 +21,8 @@
 package v1alpha1
 
 import (
+       "encoding/json"
+
        "google.golang.org/protobuf/proto"
        metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
        k8sruntime "k8s.io/apimachinery/pkg/runtime"
@@ -106,6 +108,15 @@ func (r *ConditionRouteResource) DeepCopyObject() 
k8sruntime.Object {
        return out
 }
 
+func (r *ConditionRouteResource) String() string {
+       jsonStr, err := json.Marshal(r)
+       if err != nil {
+               logger.Errorf("failed to encode ConditionRouteResource: %s to 
json, err: %s", r.ResourceKey(), err)
+               return ""
+       }
+       return string(jsonStr)
+}
+
 func NewConditionRouteResourceWithAttributes(name string, mesh string) 
*ConditionRouteResource {
        return &ConditionRouteResource{
                TypeMeta: metav1.TypeMeta{
diff --git a/pkg/core/resource/apis/mesh/v1alpha1/dynamicconfig_types.go 
b/pkg/core/resource/apis/mesh/v1alpha1/dynamicconfig_types.go
index e2fa03fd..ab6766e5 100644
--- a/pkg/core/resource/apis/mesh/v1alpha1/dynamicconfig_types.go
+++ b/pkg/core/resource/apis/mesh/v1alpha1/dynamicconfig_types.go
@@ -21,6 +21,8 @@
 package v1alpha1
 
 import (
+       "encoding/json"
+
        "google.golang.org/protobuf/proto"
        metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
        k8sruntime "k8s.io/apimachinery/pkg/runtime"
@@ -106,6 +108,15 @@ func (r *DynamicConfigResource) DeepCopyObject() 
k8sruntime.Object {
        return out
 }
 
+func (r *DynamicConfigResource) String() string {
+       jsonStr, err := json.Marshal(r)
+       if err != nil {
+               logger.Errorf("failed to encode DynamicConfigResource: %s to 
json, err: %s", r.ResourceKey(), err)
+               return ""
+       }
+       return string(jsonStr)
+}
+
 func NewDynamicConfigResourceWithAttributes(name string, mesh string) 
*DynamicConfigResource {
        return &DynamicConfigResource{
                TypeMeta: metav1.TypeMeta{
diff --git a/pkg/core/resource/apis/mesh/v1alpha1/instance_types.go 
b/pkg/core/resource/apis/mesh/v1alpha1/instance_types.go
index 17f92e2e..3c451db6 100644
--- a/pkg/core/resource/apis/mesh/v1alpha1/instance_types.go
+++ b/pkg/core/resource/apis/mesh/v1alpha1/instance_types.go
@@ -21,6 +21,8 @@
 package v1alpha1
 
 import (
+       "encoding/json"
+
        "google.golang.org/protobuf/proto"
        metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
        k8sruntime "k8s.io/apimachinery/pkg/runtime"
@@ -106,6 +108,15 @@ func (r *InstanceResource) DeepCopyObject() 
k8sruntime.Object {
        return out
 }
 
+func (r *InstanceResource) String() string {
+       jsonStr, err := json.Marshal(r)
+       if err != nil {
+               logger.Errorf("failed to encode InstanceResource: %s to json, 
err: %s", r.ResourceKey(), err)
+               return ""
+       }
+       return string(jsonStr)
+}
+
 func NewInstanceResourceWithAttributes(name string, mesh string) 
*InstanceResource {
        return &InstanceResource{
                TypeMeta: metav1.TypeMeta{
diff --git a/pkg/core/resource/apis/mesh/v1alpha1/rpcinstance_types.go 
b/pkg/core/resource/apis/mesh/v1alpha1/rpcinstance_types.go
index 0c5d18ed..064d7745 100644
--- a/pkg/core/resource/apis/mesh/v1alpha1/rpcinstance_types.go
+++ b/pkg/core/resource/apis/mesh/v1alpha1/rpcinstance_types.go
@@ -21,6 +21,8 @@
 package v1alpha1
 
 import (
+       "encoding/json"
+
        "google.golang.org/protobuf/proto"
        metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
        k8sruntime "k8s.io/apimachinery/pkg/runtime"
@@ -106,6 +108,15 @@ func (r *RPCInstanceResource) DeepCopyObject() 
k8sruntime.Object {
        return out
 }
 
+func (r *RPCInstanceResource) String() string {
+       jsonStr, err := json.Marshal(r)
+       if err != nil {
+               logger.Errorf("failed to encode RPCInstanceResource: %s to 
json, err: %s", r.ResourceKey(), err)
+               return ""
+       }
+       return string(jsonStr)
+}
+
 func NewRPCInstanceResourceWithAttributes(name string, mesh string) 
*RPCInstanceResource {
        return &RPCInstanceResource{
                TypeMeta: metav1.TypeMeta{
diff --git a/pkg/core/resource/apis/mesh/v1alpha1/rpcinstancemetadata_types.go 
b/pkg/core/resource/apis/mesh/v1alpha1/rpcinstancemetadata_types.go
index b51fc268..c0e73826 100644
--- a/pkg/core/resource/apis/mesh/v1alpha1/rpcinstancemetadata_types.go
+++ b/pkg/core/resource/apis/mesh/v1alpha1/rpcinstancemetadata_types.go
@@ -21,6 +21,8 @@
 package v1alpha1
 
 import (
+       "encoding/json"
+
        "google.golang.org/protobuf/proto"
        metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
        k8sruntime "k8s.io/apimachinery/pkg/runtime"
@@ -30,13 +32,13 @@ import (
        coremodel "github.com/apache/dubbo-admin/pkg/core/resource/model"
 )
 
-const RpcInstanceMetadataKind coremodel.ResourceKind = "RpcInstanceMetadata"
+const RPCInstanceMetadataKind coremodel.ResourceKind = "RPCInstanceMetadata"
 
 func init() {
-       coremodel.RegisterResourceSchema(RpcInstanceMetadataKind, 
NewRpcInstanceMetadataResource)
+       coremodel.RegisterResourceSchema(RPCInstanceMetadataKind, 
NewRPCInstanceMetadataResource)
 }
 
-type RpcInstanceMetadataResource struct {
+type RPCInstanceMetadataResource struct {
        metav1.TypeMeta `json:",inline"`
 
        metav1.ObjectMeta `json:"metadata,omitempty"`
@@ -45,48 +47,48 @@ type RpcInstanceMetadataResource struct {
        // It may be omitted for cluster-scoped resources.
        Mesh string `json:"mesh,omitempty"`
 
-       // Spec is the specification of the Dubbo RPCInstanceMetaData resource.
-       Spec *meshproto.RPCInstanceMetaData `json:"spec,omitempty"`
+       // Spec is the specification of the Dubbo RPCInstanceMetadata resource.
+       Spec *meshproto.RPCInstanceMetadata `json:"spec,omitempty"`
 
-       // Status is the status of the Dubbo RpcInstanceMetadata resource.
-       Status RpcInstanceMetadataResourceStatus `json:"status,omitempty"`
+       // Status is the status of the Dubbo RPCInstanceMetadata resource.
+       Status RPCInstanceMetadataResourceStatus `json:"status,omitempty"`
 }
 
-type RpcInstanceMetadataResourceStatus struct {
+type RPCInstanceMetadataResourceStatus struct {
        // define resource-specific status here
 }
 
-type RpcInstanceMetadataResourceList struct {
+type RPCInstanceMetadataResourceList struct {
        metav1.TypeMeta `json:",inline"`
        metav1.ListMeta `json:"metadata,omitempty"`
-       Items           []RpcInstanceMetadataResource `json:"items"`
+       Items           []RPCInstanceMetadataResource `json:"items"`
 }
 
-func (r *RpcInstanceMetadataResource) ResourceKind() coremodel.ResourceKind {
-       return RpcInstanceMetadataKind
+func (r *RPCInstanceMetadataResource) ResourceKind() coremodel.ResourceKind {
+       return RPCInstanceMetadataKind
 }
 
-func (r *RpcInstanceMetadataResource) MeshName() string {
+func (r *RPCInstanceMetadataResource) MeshName() string {
        return r.Mesh
 }
 
-func (r *RpcInstanceMetadataResource) ResourceKey() string {
+func (r *RPCInstanceMetadataResource) ResourceKey() string {
        return coremodel.BuildResourceKey(r.Mesh, r.Name)
 }
 
-func (r *RpcInstanceMetadataResource) ResourceMeta() metav1.ObjectMeta {
+func (r *RPCInstanceMetadataResource) ResourceMeta() metav1.ObjectMeta {
        return r.ObjectMeta
 }
 
-func (r *RpcInstanceMetadataResource) ResourceSpec() coremodel.ResourceSpec {
+func (r *RPCInstanceMetadataResource) ResourceSpec() coremodel.ResourceSpec {
        return r.Spec
 }
-func (r *RpcInstanceMetadataResource) DeepCopyObject() k8sruntime.Object {
+func (r *RPCInstanceMetadataResource) DeepCopyObject() k8sruntime.Object {
        if r == nil {
                return nil
        }
 
-       out := &RpcInstanceMetadataResource{
+       out := &RPCInstanceMetadataResource{
                TypeMeta: r.TypeMeta,
                Mesh:     r.Mesh,
                Status:   r.Status,
@@ -95,7 +97,7 @@ func (r *RpcInstanceMetadataResource) DeepCopyObject() 
k8sruntime.Object {
        r.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
 
        if r.Spec != nil {
-               spec, ok := proto.Clone(r.Spec).(*meshproto.RPCInstanceMetaData)
+               spec, ok := proto.Clone(r.Spec).(*meshproto.RPCInstanceMetadata)
                if !ok {
                        logger.Warnf("failed to clone spec %v, spec is not 
conformed to %s", r.Spec, r.ResourceKind())
                        return out
@@ -106,10 +108,19 @@ func (r *RpcInstanceMetadataResource) DeepCopyObject() 
k8sruntime.Object {
        return out
 }
 
-func NewRpcInstanceMetadataResourceWithAttributes(name string, mesh string) 
*RpcInstanceMetadataResource {
-       return &RpcInstanceMetadataResource{
+func (r *RPCInstanceMetadataResource) String() string {
+       jsonStr, err := json.Marshal(r)
+       if err != nil {
+               logger.Errorf("failed to encode RPCInstanceMetadataResource: %s 
to json, err: %w", r.ResourceKey(), err)
+               return ""
+       }
+       return string(jsonStr)
+}
+
+func NewRPCInstanceMetadataResourceWithAttributes(name string, mesh string) 
*RPCInstanceMetadataResource {
+       return &RPCInstanceMetadataResource{
                TypeMeta: metav1.TypeMeta{
-                       Kind:       string(RpcInstanceMetadataKind),
+                       Kind:       string(RPCInstanceMetadataKind),
                        APIVersion: "v1alpha1",
                },
                ObjectMeta: metav1.ObjectMeta{
@@ -120,10 +131,10 @@ func NewRpcInstanceMetadataResourceWithAttributes(name 
string, mesh string) *Rpc
        }
 }
 
-func NewRpcInstanceMetadataResource() coremodel.Resource {
-       return &RpcInstanceMetadataResource{
+func NewRPCInstanceMetadataResource() coremodel.Resource {
+       return &RPCInstanceMetadataResource{
                TypeMeta: metav1.TypeMeta{
-                       Kind:       string(RpcInstanceMetadataKind),
+                       Kind:       string(RPCInstanceMetadataKind),
                        APIVersion: "v1alpha1",
                },
        }
diff --git a/pkg/core/resource/apis/mesh/v1alpha1/runtimeinstance_types.go 
b/pkg/core/resource/apis/mesh/v1alpha1/runtimeinstance_types.go
index 03e6cb53..113c8971 100644
--- a/pkg/core/resource/apis/mesh/v1alpha1/runtimeinstance_types.go
+++ b/pkg/core/resource/apis/mesh/v1alpha1/runtimeinstance_types.go
@@ -21,6 +21,8 @@
 package v1alpha1
 
 import (
+       "encoding/json"
+
        "google.golang.org/protobuf/proto"
        metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
        k8sruntime "k8s.io/apimachinery/pkg/runtime"
@@ -106,6 +108,15 @@ func (r *RuntimeInstanceResource) DeepCopyObject() 
k8sruntime.Object {
        return out
 }
 
+func (r *RuntimeInstanceResource) String() string {
+       jsonStr, err := json.Marshal(r)
+       if err != nil {
+               logger.Errorf("failed to encode RuntimeInstanceResource: %s to 
json, err: %s", r.ResourceKey(), err)
+               return ""
+       }
+       return string(jsonStr)
+}
+
 func NewRuntimeInstanceResourceWithAttributes(name string, mesh string) 
*RuntimeInstanceResource {
        return &RuntimeInstanceResource{
                TypeMeta: metav1.TypeMeta{
diff --git a/pkg/core/resource/apis/mesh/v1alpha1/service_types.go 
b/pkg/core/resource/apis/mesh/v1alpha1/service_types.go
index 364ffed8..a18e6a4a 100644
--- a/pkg/core/resource/apis/mesh/v1alpha1/service_types.go
+++ b/pkg/core/resource/apis/mesh/v1alpha1/service_types.go
@@ -21,6 +21,8 @@
 package v1alpha1
 
 import (
+       "encoding/json"
+
        "google.golang.org/protobuf/proto"
        metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
        k8sruntime "k8s.io/apimachinery/pkg/runtime"
@@ -106,6 +108,15 @@ func (r *ServiceResource) DeepCopyObject() 
k8sruntime.Object {
        return out
 }
 
+func (r *ServiceResource) String() string {
+       jsonStr, err := json.Marshal(r)
+       if err != nil {
+               logger.Errorf("failed to encode ServiceResource: %s to json, 
err: %s", r.ResourceKey(), err)
+               return ""
+       }
+       return string(jsonStr)
+}
+
 func NewServiceResourceWithAttributes(name string, mesh string) 
*ServiceResource {
        return &ServiceResource{
                TypeMeta: metav1.TypeMeta{
diff --git 
a/pkg/core/resource/apis/mesh/v1alpha1/serviceconsumermetadata_types.go 
b/pkg/core/resource/apis/mesh/v1alpha1/serviceconsumermetadata_types.go
index 82a6bf09..ef64a62f 100644
--- a/pkg/core/resource/apis/mesh/v1alpha1/serviceconsumermetadata_types.go
+++ b/pkg/core/resource/apis/mesh/v1alpha1/serviceconsumermetadata_types.go
@@ -21,6 +21,8 @@
 package v1alpha1
 
 import (
+       "encoding/json"
+
        "google.golang.org/protobuf/proto"
        metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
        k8sruntime "k8s.io/apimachinery/pkg/runtime"
@@ -106,6 +108,15 @@ func (r *ServiceConsumerMetadataResource) DeepCopyObject() 
k8sruntime.Object {
        return out
 }
 
+func (r *ServiceConsumerMetadataResource) String() string {
+       jsonStr, err := json.Marshal(r)
+       if err != nil {
+               logger.Errorf("failed to encode 
ServiceConsumerMetadataResource: %s to json, err: %s", r.ResourceKey(), err)
+               return ""
+       }
+       return string(jsonStr)
+}
+
 func NewServiceConsumerMetadataResourceWithAttributes(name string, mesh 
string) *ServiceConsumerMetadataResource {
        return &ServiceConsumerMetadataResource{
                TypeMeta: metav1.TypeMeta{
diff --git 
a/pkg/core/resource/apis/mesh/v1alpha1/serviceprovidermapping_types.go 
b/pkg/core/resource/apis/mesh/v1alpha1/serviceprovidermapping_types.go
index 23365fce..389ae8b1 100644
--- a/pkg/core/resource/apis/mesh/v1alpha1/serviceprovidermapping_types.go
+++ b/pkg/core/resource/apis/mesh/v1alpha1/serviceprovidermapping_types.go
@@ -21,6 +21,8 @@
 package v1alpha1
 
 import (
+       "encoding/json"
+
        "google.golang.org/protobuf/proto"
        metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
        k8sruntime "k8s.io/apimachinery/pkg/runtime"
@@ -106,6 +108,15 @@ func (r *ServiceProviderMappingResource) DeepCopyObject() 
k8sruntime.Object {
        return out
 }
 
+func (r *ServiceProviderMappingResource) String() string {
+       jsonStr, err := json.Marshal(r)
+       if err != nil {
+               logger.Errorf("failed to encode ServiceProviderMappingResource: 
%s to json, err: %s", r.ResourceKey(), err)
+               return ""
+       }
+       return string(jsonStr)
+}
+
 func NewServiceProviderMappingResourceWithAttributes(name string, mesh string) 
*ServiceProviderMappingResource {
        return &ServiceProviderMappingResource{
                TypeMeta: metav1.TypeMeta{
diff --git 
a/pkg/core/resource/apis/mesh/v1alpha1/serviceprovidermetadata_types.go 
b/pkg/core/resource/apis/mesh/v1alpha1/serviceprovidermetadata_types.go
index ab03f233..e0e97315 100644
--- a/pkg/core/resource/apis/mesh/v1alpha1/serviceprovidermetadata_types.go
+++ b/pkg/core/resource/apis/mesh/v1alpha1/serviceprovidermetadata_types.go
@@ -21,6 +21,8 @@
 package v1alpha1
 
 import (
+       "encoding/json"
+
        "google.golang.org/protobuf/proto"
        metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
        k8sruntime "k8s.io/apimachinery/pkg/runtime"
@@ -45,8 +47,8 @@ type ServiceProviderMetadataResource struct {
        // It may be omitted for cluster-scoped resources.
        Mesh string `json:"mesh,omitempty"`
 
-       // Spec is the specification of the Dubbo ServiceProviderMetaData 
resource.
-       Spec *meshproto.ServiceProviderMetaData `json:"spec,omitempty"`
+       // Spec is the specification of the Dubbo ServiceProviderMetadata 
resource.
+       Spec *meshproto.ServiceProviderMetadata `json:"spec,omitempty"`
 
        // Status is the status of the Dubbo ServiceProviderMetadata resource.
        Status ServiceProviderMetadataResourceStatus `json:"status,omitempty"`
@@ -95,7 +97,7 @@ func (r *ServiceProviderMetadataResource) DeepCopyObject() 
k8sruntime.Object {
        r.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
 
        if r.Spec != nil {
-               spec, ok := 
proto.Clone(r.Spec).(*meshproto.ServiceProviderMetaData)
+               spec, ok := 
proto.Clone(r.Spec).(*meshproto.ServiceProviderMetadata)
                if !ok {
                        logger.Warnf("failed to clone spec %v, spec is not 
conformed to %s", r.Spec, r.ResourceKind())
                        return out
@@ -106,6 +108,15 @@ func (r *ServiceProviderMetadataResource) DeepCopyObject() 
k8sruntime.Object {
        return out
 }
 
+func (r *ServiceProviderMetadataResource) String() string {
+       jsonStr, err := json.Marshal(r)
+       if err != nil {
+               logger.Errorf("failed to encode 
ServiceProviderMetadataResource: %s to json, err: %s", r.ResourceKey(), err)
+               return ""
+       }
+       return string(jsonStr)
+}
+
 func NewServiceProviderMetadataResourceWithAttributes(name string, mesh 
string) *ServiceProviderMetadataResource {
        return &ServiceProviderMetadataResource{
                TypeMeta: metav1.TypeMeta{
diff --git a/pkg/core/resource/apis/mesh/v1alpha1/tagroute_types.go 
b/pkg/core/resource/apis/mesh/v1alpha1/tagroute_types.go
index ab97c424..741f3af2 100644
--- a/pkg/core/resource/apis/mesh/v1alpha1/tagroute_types.go
+++ b/pkg/core/resource/apis/mesh/v1alpha1/tagroute_types.go
@@ -21,6 +21,8 @@
 package v1alpha1
 
 import (
+       "encoding/json"
+
        "google.golang.org/protobuf/proto"
        metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
        k8sruntime "k8s.io/apimachinery/pkg/runtime"
@@ -106,6 +108,15 @@ func (r *TagRouteResource) DeepCopyObject() 
k8sruntime.Object {
        return out
 }
 
+func (r *TagRouteResource) String() string {
+       jsonStr, err := json.Marshal(r)
+       if err != nil {
+               logger.Errorf("failed to encode TagRouteResource: %s to json, 
err: %s", r.ResourceKey(), err)
+               return ""
+       }
+       return string(jsonStr)
+}
+
 func NewTagRouteResourceWithAttributes(name string, mesh string) 
*TagRouteResource {
        return &TagRouteResource{
                TypeMeta: metav1.TypeMeta{
diff --git a/pkg/core/resource/model/resource.go 
b/pkg/core/resource/model/resource.go
index 9b1ad52d..fccdc30b 100644
--- a/pkg/core/resource/model/resource.go
+++ b/pkg/core/resource/model/resource.go
@@ -65,6 +65,8 @@ type Resource interface {
        ResourceMeta() metav1.ObjectMeta
        // ResourceSpec returns the resource spec
        ResourceSpec() ResourceSpec
+       // String returns the string representation of the resource
+       String() string
 }
 
 // BuildResourceKey build a unique identifier for a resource, usually is 
`mesh/name`
diff --git a/pkg/core/runtime/runtime.go b/pkg/core/runtime/runtime.go
index bf5c865e..260451ec 100644
--- a/pkg/core/runtime/runtime.go
+++ b/pkg/core/runtime/runtime.go
@@ -26,6 +26,7 @@ import (
        "github.com/pkg/errors"
 
        "github.com/apache/dubbo-admin/pkg/config/app"
+       "github.com/apache/dubbo-admin/pkg/core/logger"
 
        "github.com/apache/dubbo-admin/pkg/config/mode"
 )
@@ -115,13 +116,26 @@ func (rt *runtime) Add(components ...Component) {
 func (rt *runtime) Start(stop <-chan struct{}) error {
        components := maputil.Values(rt.components)
        slice.SortBy(components, func(a, b Component) bool {
-               return a.Order() < b.Order()
+               return a.Order() > b.Order()
        })
        for _, com := range components {
-               err := com.Start(rt, stop)
-               if err != nil {
-                       return err
-               }
+               go func() {
+                       err := com.Start(rt, stop)
+                       if err != nil {
+                               // if a core component failed to start, panic
+                               if slice.Contain(CoreComponentTypes, 
com.Type()) {
+                                       panic("core component " + com.Type() + 
" running failed with error: " + err.Error())
+                               } else {
+                                       logger.Errorf("component %s running 
failed with error: %s", com.Type(), err.Error())
+                               }
+                       } else {
+                               logger.Infof("component %s started 
successfully", com.Type())
+                       }
+               }()
+       }
+       logger.Info("Admin started successfully")
+       select {
+       case <-stop:
+               return nil
        }
-       return nil
 }
diff --git a/pkg/core/store/component.go b/pkg/core/store/component.go
index 5f09e8db..481de86b 100644
--- a/pkg/core/store/component.go
+++ b/pkg/core/store/component.go
@@ -60,7 +60,7 @@ func (sc *storeComponent) Type() runtime.ComponentType {
 }
 
 func (sc *storeComponent) Order() int {
-       return math.MaxInt
+       return math.MaxInt - 1
 }
 
 func (sc *storeComponent) Init(ctx runtime.BuilderContext) error {
diff --git a/pkg/core/store/index/registry.go b/pkg/core/store/index/registry.go
index 98f13de6..ea579c71 100644
--- a/pkg/core/store/index/registry.go
+++ b/pkg/core/store/index/registry.go
@@ -18,6 +18,7 @@
 package index
 
 import (
+       "github.com/duke-git/lancet/v2/maputil"
        "k8s.io/client-go/tools/cache"
 
        "github.com/apache/dubbo-admin/pkg/core/resource/model"
@@ -46,33 +47,26 @@ type MutableIndexerRegistry interface {
        IndexerRegistryMutator
 }
 
-// ResourceIndexers defines the rIndexers belong to a specific model.Resource
-type ResourceIndexers struct {
-       rk       model.ResourceKind
-       indexers cache.Indexers
-}
-
 var _ IndexerRegistry = &indexerRegistry{}
 
 type indexerRegistry struct {
-       rIndexers []ResourceIndexers
+       rIndexers map[model.ResourceKind]cache.Indexers
 }
 
 func newIndexRegistry() MutableIndexerRegistry {
        return &indexerRegistry{
-               rIndexers: make([]ResourceIndexers, 0),
+               rIndexers: make(map[model.ResourceKind]cache.Indexers),
        }
 }
 
 func (i *indexerRegistry) Indexers(k model.ResourceKind) cache.Indexers {
-       for _, rIndexer := range i.rIndexers {
-               if rIndexer.rk == k {
-                       return rIndexer.indexers
-               }
-       }
-       return nil
+       return i.rIndexers[k]
 }
 
 func (i *indexerRegistry) Register(k model.ResourceKind, indexers 
cache.Indexers) {
-       i.rIndexers = append(i.rIndexers, ResourceIndexers{rk: k, indexers: 
indexers})
+       if existedIndexers, exists := i.rIndexers[k]; !exists {
+               i.rIndexers[k] = indexers
+       } else {
+               i.rIndexers[k] = maputil.Merge(existedIndexers, indexers)
+       }
 }
diff --git a/pkg/diagnostics/server.go b/pkg/diagnostics/server.go
index a14fcfd8..4d707b36 100644
--- a/pkg/diagnostics/server.go
+++ b/pkg/diagnostics/server.go
@@ -19,16 +19,15 @@ package diagnostics
 
 import (
        "context"
+       "errors"
        "fmt"
        "math"
        "net/http"
        "net/http/pprof"
        "time"
 
-       "github.com/bakito/go-log-logr-adapter/adapter"
-
        diagnosticsconfig "github.com/apache/dubbo-admin/pkg/config/diagnostics"
-       "github.com/apache/dubbo-admin/pkg/core"
+       "github.com/apache/dubbo-admin/pkg/core/logger"
        "github.com/apache/dubbo-admin/pkg/core/runtime"
 )
 
@@ -36,8 +35,6 @@ func init() {
        runtime.RegisterComponent(&diagnosticsServer{})
 }
 
-var diagnosticsServerLog = core.Log.WithName("diagnostics")
-
 const DiagnosticsServer = "diagnostics server"
 
 type diagnosticsServer struct {
@@ -79,31 +76,30 @@ func (s *diagnosticsServer) Start(_ runtime.Runtime, stop 
<-chan struct{}) error
                Addr:              fmt.Sprintf(":%d", s.config.ServerPort),
                Handler:           mux,
                ReadHeaderTimeout: time.Second,
-               ErrorLog:          adapter.ToStd(diagnosticsServerLog),
        }
 
-       diagnosticsServerLog.Info("starting diagnostic server", "interface", 
"0.0.0.0", "port", s.config.ServerPort)
+       logger.Infof("starting diagnostic server, endpoint is 0.0.0.0: %d", 
s.config.ServerPort)
        errChan := make(chan error)
        go func() {
                defer close(errChan)
                var err error
                err = httpServer.ListenAndServe()
                if err != nil {
-                       switch err {
-                       case http.ErrServerClosed:
-                               diagnosticsServerLog.Info("shutting down 
server")
+                       switch {
+                       case errors.Is(err, http.ErrServerClosed):
+                               logger.Info("shutting down diagnostics server")
                        default:
-                               diagnosticsServerLog.Error(err, "could not 
start HTTP Server")
+                               logger.Error("could not start diagnostics http 
server, unknown err: %s", err)
                                errChan <- err
                        }
                        return
                }
-               diagnosticsServerLog.Info("terminated normally")
+               logger.Info("terminated normally")
        }()
 
        select {
        case <-stop:
-               diagnosticsServerLog.Info("stopping")
+               logger.Info("received stop signal, stopping diagnostics server 
...")
                return httpServer.Shutdown(context.Background())
        case err := <-errChan:
                return err
diff --git a/pkg/core/controller/listwatcher.go b/pkg/discovery/mock/factory.go
similarity index 56%
copy from pkg/core/controller/listwatcher.go
copy to pkg/discovery/mock/factory.go
index f15006b7..87c1ada2 100644
--- a/pkg/core/controller/listwatcher.go
+++ b/pkg/discovery/mock/factory.go
@@ -15,15 +15,26 @@
  * limitations under the License.
  */
 
-package controller
+package mock
 
 import (
-       "k8s.io/client-go/tools/cache"
-
-       coremodel "github.com/apache/dubbo-admin/pkg/core/resource/model"
+       discoverycfg "github.com/apache/dubbo-admin/pkg/config/discovery"
+       "github.com/apache/dubbo-admin/pkg/core/controller"
+       "github.com/apache/dubbo-admin/pkg/core/discovery"
 )
 
-type ResourceListerWatcher interface {
-       ResourceKind() coremodel.ResourceKind
-       cache.ListerWatcher
+func init() {
+       discovery.RegisterListWatcherFactory(&mockListerWaterFactory{})
+}
+
+type mockListerWaterFactory struct{}
+
+var _ discovery.Factory = &mockListerWaterFactory{}
+
+func (l *mockListerWaterFactory) Support(d discoverycfg.Type) bool {
+       return d == discoverycfg.Mock
+}
+
+func (l *mockListerWaterFactory) NewListWatchers(_ *discoverycfg.Config) 
([]controller.ResourceListerWatcher, error) {
+       return make([]controller.ResourceListerWatcher, 0), nil
 }
diff --git a/pkg/engine/kubernetes/engine.go b/pkg/engine/kubernetes/engine.go
new file mode 100644
index 00000000..14757c18
--- /dev/null
+++ b/pkg/engine/kubernetes/engine.go
@@ -0,0 +1,230 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package kubernetes
+
+import (
+       "fmt"
+       "reflect"
+
+       "github.com/duke-git/lancet/v2/slice"
+       "github.com/duke-git/lancet/v2/strutil"
+       v1 "k8s.io/api/core/v1"
+       metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+       "k8s.io/apimachinery/pkg/fields"
+       k8sruntime "k8s.io/apimachinery/pkg/runtime"
+       "k8s.io/apimachinery/pkg/watch"
+       "k8s.io/client-go/kubernetes"
+       "k8s.io/client-go/tools/cache"
+
+       meshproto "github.com/apache/dubbo-admin/api/mesh/v1alpha1"
+       "github.com/apache/dubbo-admin/pkg/common/bizerror"
+       enginecfg "github.com/apache/dubbo-admin/pkg/config/engine"
+       "github.com/apache/dubbo-admin/pkg/core/consts"
+       "github.com/apache/dubbo-admin/pkg/core/controller"
+       "github.com/apache/dubbo-admin/pkg/core/logger"
+       meshresource 
"github.com/apache/dubbo-admin/pkg/core/resource/apis/mesh/v1alpha1"
+       coremodel "github.com/apache/dubbo-admin/pkg/core/resource/model"
+)
+
+type PodListerWatcher struct {
+       cfg *enginecfg.Config
+       lw  cache.ListerWatcher
+}
+
+var _ controller.ResourceListerWatcher = &PodListerWatcher{}
+
+func NewPodListWatcher(clientset *kubernetes.Clientset, cfg *enginecfg.Config) 
(*PodListerWatcher, error) {
+       var selector fields.Selector
+       s := cfg.Properties.PodWatchSelector
+       if strutil.IsBlank(s) {
+               selector = fields.Everything()
+       }
+       selector, err := fields.ParseSelector(s)
+       if err != nil {
+               return nil, fmt.Errorf("parse selector %s failed: %v", s, err)
+       }
+       lw := cache.NewListWatchFromClient(
+               clientset.CoreV1().RESTClient(),
+               "pods",
+               metav1.NamespaceAll,
+               selector,
+       )
+       return &PodListerWatcher{
+               cfg: cfg,
+               lw:  lw,
+       }, nil
+}
+
+func (p *PodListerWatcher) List(options metav1.ListOptions) 
(k8sruntime.Object, error) {
+       return p.lw.List(options)
+}
+
+func (p *PodListerWatcher) Watch(options metav1.ListOptions) (watch.Interface, 
error) {
+       return p.lw.Watch(options)
+}
+
+func (p *PodListerWatcher) ResourceKind() coremodel.ResourceKind {
+       return meshresource.RuntimeInstanceKind
+}
+
+func (p *PodListerWatcher) TransformFunc() cache.TransformFunc {
+       return func(obj interface{}) (interface{}, error) {
+               pod, ok := obj.(*v1.Pod)
+               if !ok {
+                       objType := reflect.TypeOf(obj).Name()
+                       logger.Errorf("cannot transform %s to Pod", objType)
+                       return nil, bizerror.NewAssertionError("Pod", objType)
+               }
+               mainContainer := p.getMainContainer(pod)
+               appName := p.getDubboAppName(pod)
+               var startTime string
+               if pod.Status.StartTime != nil {
+                       startTime = 
pod.Status.StartTime.Format(consts.TimeFormatStr)
+               }
+               createTime := pod.CreationTimestamp.Format(consts.TimeFormatStr)
+               readyTime := ""
+               slice.ForEach(pod.Status.Conditions, func(_ int, c 
v1.PodCondition) {
+                       if c.Type == v1.PodReady && c.Status == 
v1.ConditionTrue {
+                               readyTime = 
c.LastTransitionTime.Format(consts.TimeFormatStr)
+                       }
+               })
+               phase := string(pod.Status.Phase)
+               if pod.DeletionTimestamp != nil {
+                       phase = meshproto.InstanceTerminating
+               }
+               var workloadName string
+               var workloadType string
+               if len(pod.GetOwnerReferences()) > 0 {
+                       workloadName = pod.GetOwnerReferences()[0].Name
+                       workloadType = pod.GetOwnerReferences()[0].Kind
+               }
+               conditions := slice.Map(pod.Status.Conditions, func(_ int, c 
v1.PodCondition) *meshproto.Condition {
+                       return &meshproto.Condition{
+                               Type:               string(c.Type),
+                               Status:             string(c.Status),
+                               LastTransitionTime: 
c.LastTransitionTime.Format(consts.TimeFormatStr),
+                               Reason:             c.Reason,
+                               Message:            c.Message,
+                       }
+               })
+               var image string
+               probes := make([]*meshproto.Probe, 0)
+               if mainContainer != nil {
+                       image = mainContainer.Image
+                       if mainContainer.LivenessProbe != nil {
+                               port := 
p.getProbePort(mainContainer.LivenessProbe)
+                               probes = append(probes, &meshproto.Probe{
+                                       Type: meshproto.LivenessProbe,
+                                       Port: port,
+                               })
+                       }
+                       if mainContainer.ReadinessProbe != nil {
+                               port := 
p.getProbePort(mainContainer.ReadinessProbe)
+                               probes = append(probes, &meshproto.Probe{
+                                       Type: meshproto.ReadinessProbe,
+                                       Port: port,
+                               })
+                       }
+                       if mainContainer.StartupProbe != nil {
+                               port := 
p.getProbePort(mainContainer.StartupProbe)
+                               probes = append(probes, &meshproto.Probe{
+                                       Type: meshproto.StartupProbe,
+                                       Port: port,
+                               })
+                       }
+               }
+               res := 
meshresource.NewRuntimeInstanceResourceWithAttributes(pod.Name, "default")
+               res.Spec = &meshproto.RuntimeInstance{
+                       Name:         pod.Name,
+                       Ip:           pod.Status.PodIP,
+                       Image:        image,
+                       AppName:      appName,
+                       CreateTime:   createTime,
+                       StartTime:    startTime,
+                       ReadyTime:    readyTime,
+                       Phase:        phase,
+                       WorkloadName: workloadName,
+                       WorkloadType: workloadType,
+                       Node:         pod.Spec.NodeName,
+                       Probes:       probes,
+                       Conditions:   conditions,
+               }
+               return res, nil
+       }
+}
+
+func (p *PodListerWatcher) getMainContainer(pod *v1.Pod) *v1.Container {
+       containers := pod.Spec.Containers
+       strategy := p.cfg.Properties.GetOrDefaultMainContainerChooseStrategy()
+       switch strategy.Type {
+       case enginecfg.ChooseByLast:
+               return &containers[len(containers)-1]
+       case enginecfg.ChooseByIndex:
+               return &containers[strategy.Index]
+       case enginecfg.ChooseByName:
+               c, ok := slice.FindBy[v1.Container](containers, func(_ int, c 
v1.Container) bool {
+                       return c.Name == strategy.Name
+               })
+               if !ok {
+                       logger.Warnf("pod %s has no container named %s, cannot 
retrieve the correct main container",
+                               pod.Name, strategy.Name)
+                       return nil
+               }
+               return &c
+       case enginecfg.ChooseByAnnotation:
+               value, exists := pod.Annotations[strategy.AnnotationKey]
+               if !exists {
+                       logger.Warnf("pod %s has no annotation %s, cannot 
retrieve the correct main container",
+                               pod.Name, strategy.AnnotationKey)
+                       return nil
+               }
+               c, ok := slice.FindBy[v1.Container](containers, func(_ int, c 
v1.Container) bool {
+                       return c.Name == value
+               })
+               if !ok {
+                       logger.Warnf("pod %s has no container named %s, cannot 
retrieve the correct main container",
+                               pod.Name, value)
+                       return nil
+               }
+               return &c
+       }
+       return nil
+}
+
+func (p *PodListerWatcher) getDubboAppName(pod *v1.Pod) string {
+       identifier := p.cfg.Properties.DubboAppIdentifier
+       switch identifier.Type {
+       case enginecfg.IdentifyByAnnotation:
+               return pod.Annotations[identifier.AnnotationKey]
+       case enginecfg.IdentifyByLabel:
+               return pod.Labels[identifier.LabelKey]
+       default:
+               return ""
+       }
+}
+
+func (p *PodListerWatcher) getProbePort(probe *v1.Probe) int32 {
+       if probe.TCPSocket != nil {
+               return probe.TCPSocket.Port.IntVal
+       } else if probe.HTTPGet != nil {
+               return probe.HTTPGet.Port.IntVal
+       } else if probe.GRPC != nil {
+               return probe.GRPC.Port
+       }
+       return 0
+}
diff --git a/pkg/engine/kubernetes/factory.go b/pkg/engine/kubernetes/factory.go
new file mode 100644
index 00000000..946f3e7a
--- /dev/null
+++ b/pkg/engine/kubernetes/factory.go
@@ -0,0 +1,75 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package kubernetes
+
+import (
+       "fmt"
+
+       "github.com/duke-git/lancet/v2/strutil"
+       "k8s.io/client-go/kubernetes"
+       "k8s.io/client-go/rest"
+       "k8s.io/client-go/tools/clientcmd"
+
+       enginecfg "github.com/apache/dubbo-admin/pkg/config/engine"
+       "github.com/apache/dubbo-admin/pkg/core/controller"
+       "github.com/apache/dubbo-admin/pkg/core/engine"
+)
+
+func init() {
+       engine.RegisterFactory(NewKubernetesEngineFactory())
+}
+
+var _ engine.Factory = &EngineFactory{}
+
+type EngineFactory struct{}
+
+func NewKubernetesEngineFactory() *EngineFactory {
+       return &EngineFactory{}
+}
+
+func (e *EngineFactory) Support(typ enginecfg.Type) bool {
+       return enginecfg.Kubernetes == typ
+}
+
+func (e *EngineFactory) NewListWatchers(cfg *enginecfg.Config) 
([]controller.ResourceListerWatcher, error) {
+       kubeconfigPath := cfg.Properties.KubeConfigPath
+
+       var config *rest.Config
+       var err error
+       if !strutil.IsBlank(kubeconfigPath) {
+               config, err = clientcmd.BuildConfigFromFlags("", kubeconfigPath)
+       } else {
+               config, err = rest.InClusterConfig()
+       }
+       if err != nil {
+               return nil, fmt.Errorf("failed to init kubeconfig in kubernetes 
engine, %w", err)
+       }
+
+       clientset, err := kubernetes.NewForConfig(config)
+       if err != nil {
+               return nil, fmt.Errorf("failed to init clientset in kubernetes 
engine, %w", err)
+       }
+
+       lwList := make([]controller.ResourceListerWatcher, 0)
+       podListerWatcher, err := NewPodListWatcher(clientset, cfg)
+       if err != nil {
+               return nil, fmt.Errorf("failed to init PodListerWatcher in 
kubernetes engine, %w", err)
+       }
+       lwList = append(lwList, podListerWatcher)
+       return lwList, nil
+}
diff --git a/pkg/store/memory/store_test.go b/pkg/store/memory/store_test.go
index f78c88c0..0596926e 100644
--- a/pkg/store/memory/store_test.go
+++ b/pkg/store/memory/store_test.go
@@ -18,6 +18,7 @@
 package memory
 
 import (
+       "encoding/json"
        "testing"
 
        "github.com/stretchr/testify/assert"
@@ -66,6 +67,13 @@ func (mr *mockResource) ResourceMeta() metav1.ObjectMeta {
 func (mr *mockResource) ResourceSpec() model.ResourceSpec {
        return mr.spec
 }
+func (mr *mockResource) String() string {
+       b, err := json.Marshal(mr)
+       if err != nil {
+               return ""
+       }
+       return string(b)
+}
 
 func TestNewMemoryResourceStore(t *testing.T) {
        store := NewMemoryResourceStore()
diff --git a/pkg/store/db/mysql.go b/pkg/store/mysql/mysql.go
similarity index 98%
rename from pkg/store/db/mysql.go
rename to pkg/store/mysql/mysql.go
index 43e59a33..484ead99 100644
--- a/pkg/store/db/mysql.go
+++ b/pkg/store/mysql/mysql.go
@@ -15,6 +15,6 @@
  * limitations under the License.
  */
 
-package db
+package mysql
 
 // TODO implement memory resource store, refer to GORM https://gorm.io/docs/
diff --git a/scripts/resourcegen/gen.go b/scripts/resourcegen/gen.go
index 3b9b5851..d6160606 100644
--- a/scripts/resourcegen/gen.go
+++ b/scripts/resourcegen/gen.go
@@ -63,6 +63,8 @@ var resourceTemplate = 
template.Must(template.New("dubbo-resource").Parse(`
 package v1alpha1
 
 import (
+       "encoding/json"
+
        "google.golang.org/protobuf/proto"
        metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
        k8sruntime "k8s.io/apimachinery/pkg/runtime"
@@ -150,6 +152,15 @@ func (r *{{.Name}}Resource) DeepCopyObject() 
k8sruntime.Object {
        return out
 }
 
+func (r *{{.Name}}Resource) String() string {
+    jsonStr, err := json.Marshal(r)
+       if err != nil {
+               logger.Errorf("failed to encode {{.Name}}Resource: %s to json, 
err: %w", r.ResourceKey(), err)
+               return ""
+       }
+       return string(jsonStr)
+}
+
 func New{{.Name}}ResourceWithAttributes(name string, mesh string) 
*{{.Name}}Resource{
        return &{{.Name}}Resource{
                TypeMeta: metav1.TypeMeta{

Reply via email to