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

wusheng pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/skywalking-swck.git


The following commit(s) were added to refs/heads/master by this push:
     new d125f2e  [Feature] Add BanyanDB CRD & Controllers (#70)
d125f2e is described below

commit d125f2eaf28f96e895e85ff287ab3329facee8b0
Author: William Song <[email protected]>
AuthorDate: Sat Sep 24 10:46:23 2022 +0800

    [Feature] Add BanyanDB CRD & Controllers (#70)
    
    Co-authored-by: Gao Hongtao <[email protected]>
---
 .github/workflows/go.yml                           |   15 +
 operator/PROJECT                                   |    9 +
 operator/apis/operator/v1alpha1/banyandb_types.go  |  106 ++
 .../apis/operator/v1alpha1/banyandb_webhook.go     |   90 ++
 .../operator/v1alpha1/zz_generated.deepcopy.go     |  141 ++-
 .../operator.skywalking.apache.org_banyandbs.yaml  | 1312 ++++++++++++++++++++
 .../operator.skywalking.apache.org_swagents.yaml   |    2 +-
 operator/config/crd/kustomization.yaml             |    3 +
 operator/config/rbac/role.yaml                     |   40 +
 operator/config/samples/banyandb.yaml              |   37 +
 operator/config/webhook/manifests.yaml             |   40 +
 ...ellite_controller.go => banyandb_controller.go} |   80 +-
 .../controllers/operator/oapserver_controller.go   |    1 +
 .../controllers/operator/satellite_controller.go   |    1 +
 .../controllers/operator/storage_controller.go     |    1 +
 operator/controllers/operator/ui_controller.go     |    1 +
 operator/main.go                                   |   13 +
 .../manifests/banyandb/templates/deployment.yaml   |  118 ++
 .../manifests/banyandb/templates/grpc_service.yaml |   58 +
 .../manifests/banyandb/templates/http_service.yaml |   58 +
 .../manifests/banyandb/templates/ingress.yaml      |   53 +
 .../operator/manifests/banyandb/templates/pvc.yaml |   64 +
 .../banyandb/templates/service_account.yaml        |   27 +
 operator/pkg/operator/manifests/repo.go            |    2 +-
 test/e2e/banyandb/e2e.yaml                         |  110 ++
 test/e2e/deploy-banyandb.yaml                      |   66 +
 test/e2e/skywalking-components-with-banyandb.yaml  |   50 +
 test/e2e/verify/affinity.yaml                      |   16 +
 28 files changed, 2462 insertions(+), 52 deletions(-)

diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml
index 73aaa8d..e498c7c 100644
--- a/.github/workflows/go.yml
+++ b/.github/workflows/go.yml
@@ -146,6 +146,21 @@ jobs:
         uses: 
apache/skywalking-infra-e2e@996ed8902e941e2883fcf0ac5b3090364942d205
         with:
           e2e-file: test/e2e/oap-ui-agent-external-storage/e2e.yaml     
+  banyandb-e2e-tests:
+    name: e2e tests(oap+ui+agent+banyandb)
+    runs-on: ubuntu-latest
+    steps:
+      - name: Install Go
+        uses: actions/setup-go@v2
+        with:
+          go-version: 1.17
+        id: go
+      - name: Check out code into the Go module directory
+        uses: actions/checkout@v2
+      - name: Run E2E Test
+        uses: 
apache/skywalking-infra-e2e@996ed8902e941e2883fcf0ac5b3090364942d205
+        with:
+          e2e-file: test/e2e/banyandb/e2e.yaml
   adapter-hpa-e2e-tests:          
     name: e2e tests(oap+agent+adapter+hpa)
     runs-on: ubuntu-latest
diff --git a/operator/PROJECT b/operator/PROJECT
index 12e05a3..73b6a37 100644
--- a/operator/PROJECT
+++ b/operator/PROJECT
@@ -122,4 +122,13 @@ resources:
     defaulting: true
     validation: true
     webhookVersion: v1
+- api:
+    crdVersion: v1
+    namespaced: true
+  controller: true
+  domain: skywalking.apache.org
+  group: operator
+  kind: BanyanDB
+  path: github.com/apache/skywalking-swck/operator/apis/operator/v1alpha1
+  version: v1alpha1
 version: "3"
diff --git a/operator/apis/operator/v1alpha1/banyandb_types.go 
b/operator/apis/operator/v1alpha1/banyandb_types.go
new file mode 100644
index 0000000..05f5244
--- /dev/null
+++ b/operator/apis/operator/v1alpha1/banyandb_types.go
@@ -0,0 +1,106 @@
+// Licensed to 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. Apache Software Foundation (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 v1alpha1
+
+import (
+       appsv1 "k8s.io/api/apps/v1"
+       corev1 "k8s.io/api/core/v1"
+       metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+)
+
+// BanyanDBSpec defines the desired state of BanyanDB
+type BanyanDBSpec struct {
+       // Version of BanyanDB.
+       // +kubebuilder:validation:Required
+       Version string `json:"version"`
+
+       // Number of replicas
+       // +kubebuilder:validation:Required
+       Counts int `json:"counts"`
+
+       // Pod template of each BanyanDB instance
+       // +kubebuilder:validation:Required
+       Image string `json:"image"`
+
+       // Pod affinity
+       // +kubebuilder:validation:Optional
+       Affinity corev1.Affinity `json:"affinity"`
+
+       // BanyanDB startup parameters
+       // +kubebuilder:validation:Optional
+       Config []string `json:"config"`
+
+       // BanyanDB HTTP Service
+       // +kubebuilder:validation:Optional
+       HTTPSvc Service `json:"httpService,omitempty"`
+
+       // BanyanDB gRPC Serice
+       // +kubebuilder:validation:Optional
+       GRPCSvc Service `json:"gRPCService,omitempty"`
+
+       // BanyanDB Storage
+       // +kubebuilder:validation:Optional
+       Storages []StorageConfig `json:"storages,omitempty"`
+}
+
+type StorageConfig struct {
+       // the name of storage config
+       // +kubebuilder:validation:Optional
+       Name string `json:"name,omitempty"`
+
+       // mount path of the volume
+       // +kubebuilder:validation:Optional
+       Path string `json:"path,omitempty"`
+
+       // the persistent volume spec for the storage
+       // +kubebuilder:validation:Optional
+       PersistentVolumeClaimSpec corev1.PersistentVolumeClaimSpec 
`json:"persistentVolumeClaimSpec,omitempty"`
+}
+
+// BanyanDBStatus defines the observed state of BanyanDB
+type BanyanDBStatus struct {
+       AvailableReplicas int32 `json:"available_pods,omitempty"`
+       // Represents the latest available observations of the underlying 
statefulset's current state.
+       // +kubebuilder:validation:Optional
+       Conditions []appsv1.DeploymentCondition `json:"conditions,omitempty"`
+}
+
+//+kubebuilder:object:root=true
+//+kubebuilder:subresource:status
+
+// BanyanDB is the Schema for the banyandbs API
+type BanyanDB struct {
+       metav1.TypeMeta   `json:",inline"`
+       metav1.ObjectMeta `json:"metadata,omitempty"`
+
+       Spec   BanyanDBSpec   `json:"spec,omitempty"`
+       Status BanyanDBStatus `json:"status,omitempty"`
+}
+
+//+kubebuilder:object:root=true
+
+// BanyanDBList contains a list of BanyanDB
+type BanyanDBList struct {
+       metav1.TypeMeta `json:",inline"`
+       metav1.ListMeta `json:"metadata,omitempty"`
+       Items           []BanyanDB `json:"items"`
+}
+
+func init() {
+       SchemeBuilder.Register(&BanyanDB{}, &BanyanDBList{})
+}
diff --git a/operator/apis/operator/v1alpha1/banyandb_webhook.go 
b/operator/apis/operator/v1alpha1/banyandb_webhook.go
new file mode 100644
index 0000000..4e1b370
--- /dev/null
+++ b/operator/apis/operator/v1alpha1/banyandb_webhook.go
@@ -0,0 +1,90 @@
+// Licensed to 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. Apache Software Foundation (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 v1alpha1
+
+import (
+       "fmt"
+
+       "k8s.io/apimachinery/pkg/runtime"
+       ctrl "sigs.k8s.io/controller-runtime"
+       logf "sigs.k8s.io/controller-runtime/pkg/log"
+       "sigs.k8s.io/controller-runtime/pkg/webhook"
+)
+
+var banyandbLog = logf.Log.WithName("banyandb-resource")
+
+func (r *BanyanDB) SetupWebhookWithManager(mgr ctrl.Manager) error {
+       return ctrl.NewWebhookManagedBy(mgr).
+               For(r).
+               Complete()
+}
+
+// nolint: lll
+//+kubebuilder:webhook:path=/mutate-operator-skywalking-apache-org-v1alpha1-banyandb,mutating=true,failurePolicy=fail,sideEffects=None,groups=operator.skywalking.apache.org,resources=banyandbs,verbs=create;update,versions=v1alpha1,name=mbanyandb.kb.io,admissionReviewVersions=v1
+
+var _ webhook.Defaulter = &BanyanDB{}
+
+func (r *BanyanDB) Default() {
+       banyandbLog.Info("default", "name", r.Name)
+
+       if r.Spec.Version == "" {
+               // use the latest version by default
+               r.Spec.Version = "latest"
+       }
+
+       if r.Spec.Image == "" {
+               r.Spec.Image = fmt.Sprintf("apache/skywalking-banyandb:%s", 
r.Spec.Version)
+       }
+
+       if r.Spec.Counts == 0 {
+               // currently only support one data copy
+               r.Spec.Counts = 1
+       }
+}
+
+// nolint: lll
+// 
+kubebuilder:webhook:admissionReviewVersions=v1,sideEffects=None,verbs=create;update,path=/validate-operator-skywalking-apache-org-v1alpha1-banyandb,mutating=false,failurePolicy=fail,groups=operator.skywalking.apache.org,resources=banyandbs,versions=v1alpha1,name=vbanyandb.kb.io
+
+var _ webhook.Validator = &BanyanDB{}
+
+func (r *BanyanDB) ValidateCreate() error {
+       banyandbLog.Info("validate create", "name", r.Name)
+       return r.validate()
+}
+
+func (r *BanyanDB) ValidateUpdate(old runtime.Object) error {
+       banyandbLog.Info("validate update", "name", r.Name)
+       return r.validate()
+}
+
+func (r *BanyanDB) ValidateDelete() error {
+       banyandbLog.Info("validate delete", "name", r.Name)
+       return r.validate()
+}
+
+func (r *BanyanDB) validate() error {
+       if r.Spec.Image == "" {
+               return fmt.Errorf("image is absent")
+       }
+
+       if r.Spec.Counts != 1 {
+               return fmt.Errorf("banyandb only support 1 copy for now")
+       }
+
+       return nil
+}
diff --git a/operator/apis/operator/v1alpha1/zz_generated.deepcopy.go 
b/operator/apis/operator/v1alpha1/zz_generated.deepcopy.go
index 0a32237..11a476f 100644
--- a/operator/apis/operator/v1alpha1/zz_generated.deepcopy.go
+++ b/operator/apis/operator/v1alpha1/zz_generated.deepcopy.go
@@ -23,12 +23,123 @@
 package v1alpha1
 
 import (
-       appsv1 "k8s.io/api/apps/v1"
+       v1 "k8s.io/api/apps/v1"
        corev1 "k8s.io/api/core/v1"
-       v1 "k8s.io/api/networking/v1"
+       networkingv1 "k8s.io/api/networking/v1"
        "k8s.io/apimachinery/pkg/runtime"
 )
 
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, 
writing into out. in must be non-nil.
+func (in *BanyanDB) DeepCopyInto(out *BanyanDB) {
+       *out = *in
+       out.TypeMeta = in.TypeMeta
+       in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
+       in.Spec.DeepCopyInto(&out.Spec)
+       in.Status.DeepCopyInto(&out.Status)
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, 
creating a new BanyanDB.
+func (in *BanyanDB) DeepCopy() *BanyanDB {
+       if in == nil {
+               return nil
+       }
+       out := new(BanyanDB)
+       in.DeepCopyInto(out)
+       return out
+}
+
+// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, 
creating a new runtime.Object.
+func (in *BanyanDB) DeepCopyObject() runtime.Object {
+       if c := in.DeepCopy(); c != nil {
+               return c
+       }
+       return nil
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, 
writing into out. in must be non-nil.
+func (in *BanyanDBList) DeepCopyInto(out *BanyanDBList) {
+       *out = *in
+       out.TypeMeta = in.TypeMeta
+       in.ListMeta.DeepCopyInto(&out.ListMeta)
+       if in.Items != nil {
+               in, out := &in.Items, &out.Items
+               *out = make([]BanyanDB, len(*in))
+               for i := range *in {
+                       (*in)[i].DeepCopyInto(&(*out)[i])
+               }
+       }
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, 
creating a new BanyanDBList.
+func (in *BanyanDBList) DeepCopy() *BanyanDBList {
+       if in == nil {
+               return nil
+       }
+       out := new(BanyanDBList)
+       in.DeepCopyInto(out)
+       return out
+}
+
+// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, 
creating a new runtime.Object.
+func (in *BanyanDBList) DeepCopyObject() runtime.Object {
+       if c := in.DeepCopy(); c != nil {
+               return c
+       }
+       return nil
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, 
writing into out. in must be non-nil.
+func (in *BanyanDBSpec) DeepCopyInto(out *BanyanDBSpec) {
+       *out = *in
+       in.Affinity.DeepCopyInto(&out.Affinity)
+       if in.Config != nil {
+               in, out := &in.Config, &out.Config
+               *out = make([]string, len(*in))
+               copy(*out, *in)
+       }
+       in.HTTPSvc.DeepCopyInto(&out.HTTPSvc)
+       in.GRPCSvc.DeepCopyInto(&out.GRPCSvc)
+       if in.Storages != nil {
+               in, out := &in.Storages, &out.Storages
+               *out = make([]StorageConfig, len(*in))
+               for i := range *in {
+                       (*in)[i].DeepCopyInto(&(*out)[i])
+               }
+       }
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, 
creating a new BanyanDBSpec.
+func (in *BanyanDBSpec) DeepCopy() *BanyanDBSpec {
+       if in == nil {
+               return nil
+       }
+       out := new(BanyanDBSpec)
+       in.DeepCopyInto(out)
+       return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, 
writing into out. in must be non-nil.
+func (in *BanyanDBStatus) DeepCopyInto(out *BanyanDBStatus) {
+       *out = *in
+       if in.Conditions != nil {
+               in, out := &in.Conditions, &out.Conditions
+               *out = make([]v1.DeploymentCondition, len(*in))
+               for i := range *in {
+                       (*in)[i].DeepCopyInto(&(*out)[i])
+               }
+       }
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, 
creating a new BanyanDBStatus.
+func (in *BanyanDBStatus) DeepCopy() *BanyanDBStatus {
+       if in == nil {
+               return nil
+       }
+       out := new(BanyanDBStatus)
+       in.DeepCopyInto(out)
+       return out
+}
+
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, 
writing into out. in must be non-nil.
 func (in *Config) DeepCopyInto(out *Config) {
        *out = *in
@@ -194,7 +305,7 @@ func (in *Ingress) DeepCopyInto(out *Ingress) {
        }
        if in.TLS != nil {
                in, out := &in.TLS, &out.TLS
-               *out = make([]v1.IngressTLS, len(*in))
+               *out = make([]networkingv1.IngressTLS, len(*in))
                for i := range *in {
                        (*in)[i].DeepCopyInto(&(*out)[i])
                }
@@ -629,7 +740,7 @@ func (in *OAPServerStatus) DeepCopyInto(out 
*OAPServerStatus) {
        *out = *in
        if in.Conditions != nil {
                in, out := &in.Conditions, &out.Conditions
-               *out = make([]appsv1.DeploymentCondition, len(*in))
+               *out = make([]v1.DeploymentCondition, len(*in))
                for i := range *in {
                        (*in)[i].DeepCopyInto(&(*out)[i])
                }
@@ -764,7 +875,7 @@ func (in *SatelliteStatus) DeepCopyInto(out 
*SatelliteStatus) {
        *out = *in
        if in.Conditions != nil {
                in, out := &in.Conditions, &out.Conditions
-               *out = make([]appsv1.DeploymentCondition, len(*in))
+               *out = make([]v1.DeploymentCondition, len(*in))
                for i := range *in {
                        (*in)[i].DeepCopyInto(&(*out)[i])
                }
@@ -881,6 +992,22 @@ func (in *Storage) DeepCopyObject() runtime.Object {
        return nil
 }
 
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, 
writing into out. in must be non-nil.
+func (in *StorageConfig) DeepCopyInto(out *StorageConfig) {
+       *out = *in
+       
in.PersistentVolumeClaimSpec.DeepCopyInto(&out.PersistentVolumeClaimSpec)
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, 
creating a new StorageConfig.
+func (in *StorageConfig) DeepCopy() *StorageConfig {
+       if in == nil {
+               return nil
+       }
+       out := new(StorageConfig)
+       in.DeepCopyInto(out)
+       return out
+}
+
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, 
writing into out. in must be non-nil.
 func (in *StorageList) DeepCopyInto(out *StorageList) {
        *out = *in
@@ -942,7 +1069,7 @@ func (in *StorageStatus) DeepCopyInto(out *StorageStatus) {
        *out = *in
        if in.Conditions != nil {
                in, out := &in.Conditions, &out.Conditions
-               *out = make([]appsv1.StatefulSetCondition, len(*in))
+               *out = make([]v1.StatefulSetCondition, len(*in))
                for i := range *in {
                        (*in)[i].DeepCopyInto(&(*out)[i])
                }
@@ -1178,7 +1305,7 @@ func (in *UIStatus) DeepCopyInto(out *UIStatus) {
        }
        if in.Conditions != nil {
                in, out := &in.Conditions, &out.Conditions
-               *out = make([]appsv1.DeploymentCondition, len(*in))
+               *out = make([]v1.DeploymentCondition, len(*in))
                for i := range *in {
                        (*in)[i].DeepCopyInto(&(*out)[i])
                }
diff --git 
a/operator/config/crd/bases/operator.skywalking.apache.org_banyandbs.yaml 
b/operator/config/crd/bases/operator.skywalking.apache.org_banyandbs.yaml
new file mode 100644
index 0000000..3922932
--- /dev/null
+++ b/operator/config/crd/bases/operator.skywalking.apache.org_banyandbs.yaml
@@ -0,0 +1,1312 @@
+# Licensed to 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. Apache Software Foundation (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.
+
+---
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
+metadata:
+  annotations:
+    controller-gen.kubebuilder.io/version: v0.7.0
+  creationTimestamp: null
+  name: banyandbs.operator.skywalking.apache.org
+spec:
+  group: operator.skywalking.apache.org
+  names:
+    kind: BanyanDB
+    listKind: BanyanDBList
+    plural: banyandbs
+    singular: banyandb
+  scope: Namespaced
+  versions:
+  - name: v1alpha1
+    schema:
+      openAPIV3Schema:
+        description: BanyanDB is the Schema for the banyandbs API
+        properties:
+          apiVersion:
+            description: 'APIVersion defines the versioned schema of this 
representation
+              of an object. Servers should convert recognized schemas to the 
latest
+              internal value, and may reject unrecognized values. More info: 
https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
+            type: string
+          kind:
+            description: 'Kind is a string value representing the REST 
resource this
+              object represents. Servers may infer this from the endpoint the 
client
+              submits requests to. Cannot be updated. In CamelCase. More info: 
https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
+            type: string
+          metadata:
+            type: object
+          spec:
+            description: BanyanDBSpec defines the desired state of BanyanDB
+            properties:
+              affinity:
+                description: Pod affinity
+                properties:
+                  nodeAffinity:
+                    description: Describes node affinity scheduling rules for 
the
+                      pod.
+                    properties:
+                      preferredDuringSchedulingIgnoredDuringExecution:
+                        description: The scheduler will prefer to schedule 
pods to
+                          nodes that satisfy the affinity expressions 
specified by
+                          this field, but it may choose a node that violates 
one or
+                          more of the expressions. The node that is most 
preferred
+                          is the one with the greatest sum of weights, i.e. 
for each
+                          node that meets all of the scheduling requirements 
(resource
+                          request, requiredDuringScheduling affinity 
expressions,
+                          etc.), compute a sum by iterating through the 
elements of
+                          this field and adding "weight" to the sum if the 
node matches
+                          the corresponding matchExpressions; the node(s) with 
the
+                          highest sum are the most preferred.
+                        items:
+                          description: An empty preferred scheduling term 
matches
+                            all objects with implicit weight 0 (i.e. it's a 
no-op).
+                            A null preferred scheduling term matches no 
objects (i.e.
+                            is also a no-op).
+                          properties:
+                            preference:
+                              description: A node selector term, associated 
with the
+                                corresponding weight.
+                              properties:
+                                matchExpressions:
+                                  description: A list of node selector 
requirements
+                                    by node's labels.
+                                  items:
+                                    description: A node selector requirement 
is a
+                                      selector that contains values, a key, 
and an
+                                      operator that relates the key and values.
+                                    properties:
+                                      key:
+                                        description: The label key that the 
selector
+                                          applies to.
+                                        type: string
+                                      operator:
+                                        description: Represents a key's 
relationship
+                                          to a set of values. Valid operators 
are
+                                          In, NotIn, Exists, DoesNotExist. Gt, 
and
+                                          Lt.
+                                        type: string
+                                      values:
+                                        description: An array of string 
values. If
+                                          the operator is In or NotIn, the 
values
+                                          array must be non-empty. If the 
operator
+                                          is Exists or DoesNotExist, the 
values array
+                                          must be empty. If the operator is Gt 
or
+                                          Lt, the values array must have a 
single
+                                          element, which will be interpreted 
as an
+                                          integer. This array is replaced 
during a
+                                          strategic merge patch.
+                                        items:
+                                          type: string
+                                        type: array
+                                    required:
+                                    - key
+                                    - operator
+                                    type: object
+                                  type: array
+                                matchFields:
+                                  description: A list of node selector 
requirements
+                                    by node's fields.
+                                  items:
+                                    description: A node selector requirement 
is a
+                                      selector that contains values, a key, 
and an
+                                      operator that relates the key and values.
+                                    properties:
+                                      key:
+                                        description: The label key that the 
selector
+                                          applies to.
+                                        type: string
+                                      operator:
+                                        description: Represents a key's 
relationship
+                                          to a set of values. Valid operators 
are
+                                          In, NotIn, Exists, DoesNotExist. Gt, 
and
+                                          Lt.
+                                        type: string
+                                      values:
+                                        description: An array of string 
values. If
+                                          the operator is In or NotIn, the 
values
+                                          array must be non-empty. If the 
operator
+                                          is Exists or DoesNotExist, the 
values array
+                                          must be empty. If the operator is Gt 
or
+                                          Lt, the values array must have a 
single
+                                          element, which will be interpreted 
as an
+                                          integer. This array is replaced 
during a
+                                          strategic merge patch.
+                                        items:
+                                          type: string
+                                        type: array
+                                    required:
+                                    - key
+                                    - operator
+                                    type: object
+                                  type: array
+                              type: object
+                            weight:
+                              description: Weight associated with matching the 
corresponding
+                                nodeSelectorTerm, in the range 1-100.
+                              format: int32
+                              type: integer
+                          required:
+                          - preference
+                          - weight
+                          type: object
+                        type: array
+                      requiredDuringSchedulingIgnoredDuringExecution:
+                        description: If the affinity requirements specified by 
this
+                          field are not met at scheduling time, the pod will 
not be
+                          scheduled onto the node. If the affinity 
requirements specified
+                          by this field cease to be met at some point during 
pod execution
+                          (e.g. due to an update), the system may or may not 
try to
+                          eventually evict the pod from its node.
+                        properties:
+                          nodeSelectorTerms:
+                            description: Required. A list of node selector 
terms.
+                              The terms are ORed.
+                            items:
+                              description: A null or empty node selector term 
matches
+                                no objects. The requirements of them are 
ANDed. The
+                                TopologySelectorTerm type implements a subset 
of the
+                                NodeSelectorTerm.
+                              properties:
+                                matchExpressions:
+                                  description: A list of node selector 
requirements
+                                    by node's labels.
+                                  items:
+                                    description: A node selector requirement 
is a
+                                      selector that contains values, a key, 
and an
+                                      operator that relates the key and values.
+                                    properties:
+                                      key:
+                                        description: The label key that the 
selector
+                                          applies to.
+                                        type: string
+                                      operator:
+                                        description: Represents a key's 
relationship
+                                          to a set of values. Valid operators 
are
+                                          In, NotIn, Exists, DoesNotExist. Gt, 
and
+                                          Lt.
+                                        type: string
+                                      values:
+                                        description: An array of string 
values. If
+                                          the operator is In or NotIn, the 
values
+                                          array must be non-empty. If the 
operator
+                                          is Exists or DoesNotExist, the 
values array
+                                          must be empty. If the operator is Gt 
or
+                                          Lt, the values array must have a 
single
+                                          element, which will be interpreted 
as an
+                                          integer. This array is replaced 
during a
+                                          strategic merge patch.
+                                        items:
+                                          type: string
+                                        type: array
+                                    required:
+                                    - key
+                                    - operator
+                                    type: object
+                                  type: array
+                                matchFields:
+                                  description: A list of node selector 
requirements
+                                    by node's fields.
+                                  items:
+                                    description: A node selector requirement 
is a
+                                      selector that contains values, a key, 
and an
+                                      operator that relates the key and values.
+                                    properties:
+                                      key:
+                                        description: The label key that the 
selector
+                                          applies to.
+                                        type: string
+                                      operator:
+                                        description: Represents a key's 
relationship
+                                          to a set of values. Valid operators 
are
+                                          In, NotIn, Exists, DoesNotExist. Gt, 
and
+                                          Lt.
+                                        type: string
+                                      values:
+                                        description: An array of string 
values. If
+                                          the operator is In or NotIn, the 
values
+                                          array must be non-empty. If the 
operator
+                                          is Exists or DoesNotExist, the 
values array
+                                          must be empty. If the operator is Gt 
or
+                                          Lt, the values array must have a 
single
+                                          element, which will be interpreted 
as an
+                                          integer. This array is replaced 
during a
+                                          strategic merge patch.
+                                        items:
+                                          type: string
+                                        type: array
+                                    required:
+                                    - key
+                                    - operator
+                                    type: object
+                                  type: array
+                              type: object
+                            type: array
+                        required:
+                        - nodeSelectorTerms
+                        type: object
+                    type: object
+                  podAffinity:
+                    description: Describes pod affinity scheduling rules (e.g. 
co-locate
+                      this pod in the same node, zone, etc. as some other 
pod(s)).
+                    properties:
+                      preferredDuringSchedulingIgnoredDuringExecution:
+                        description: The scheduler will prefer to schedule 
pods to
+                          nodes that satisfy the affinity expressions 
specified by
+                          this field, but it may choose a node that violates 
one or
+                          more of the expressions. The node that is most 
preferred
+                          is the one with the greatest sum of weights, i.e. 
for each
+                          node that meets all of the scheduling requirements 
(resource
+                          request, requiredDuringScheduling affinity 
expressions,
+                          etc.), compute a sum by iterating through the 
elements of
+                          this field and adding "weight" to the sum if the 
node has
+                          pods which matches the corresponding 
podAffinityTerm; the
+                          node(s) with the highest sum are the most preferred.
+                        items:
+                          description: The weights of all of the matched 
WeightedPodAffinityTerm
+                            fields are added per-node to find the most 
preferred node(s)
+                          properties:
+                            podAffinityTerm:
+                              description: Required. A pod affinity term, 
associated
+                                with the corresponding weight.
+                              properties:
+                                labelSelector:
+                                  description: A label query over a set of 
resources,
+                                    in this case pods.
+                                  properties:
+                                    matchExpressions:
+                                      description: matchExpressions is a list 
of label
+                                        selector requirements. The 
requirements are
+                                        ANDed.
+                                      items:
+                                        description: A label selector 
requirement
+                                          is a selector that contains values, 
a key,
+                                          and an operator that relates the key 
and
+                                          values.
+                                        properties:
+                                          key:
+                                            description: key is the label key 
that
+                                              the selector applies to.
+                                            type: string
+                                          operator:
+                                            description: operator represents a 
key's
+                                              relationship to a set of values. 
Valid
+                                              operators are In, NotIn, Exists 
and
+                                              DoesNotExist.
+                                            type: string
+                                          values:
+                                            description: values is an array of 
string
+                                              values. If the operator is In or 
NotIn,
+                                              the values array must be 
non-empty.
+                                              If the operator is Exists or 
DoesNotExist,
+                                              the values array must be empty. 
This
+                                              array is replaced during a 
strategic
+                                              merge patch.
+                                            items:
+                                              type: string
+                                            type: array
+                                        required:
+                                        - key
+                                        - operator
+                                        type: object
+                                      type: array
+                                    matchLabels:
+                                      additionalProperties:
+                                        type: string
+                                      description: matchLabels is a map of 
{key,value}
+                                        pairs. A single {key,value} in the 
matchLabels
+                                        map is equivalent to an element of 
matchExpressions,
+                                        whose key field is "key", the operator 
is
+                                        "In", and the values array contains 
only "value".
+                                        The requirements are ANDed.
+                                      type: object
+                                  type: object
+                                namespaceSelector:
+                                  description: A label query over the set of 
namespaces
+                                    that the term applies to. The term is 
applied
+                                    to the union of the namespaces selected by 
this
+                                    field and the ones listed in the 
namespaces field.
+                                    null selector and null or empty namespaces 
list
+                                    means "this pod's namespace". An empty 
selector
+                                    ({}) matches all namespaces.
+                                  properties:
+                                    matchExpressions:
+                                      description: matchExpressions is a list 
of label
+                                        selector requirements. The 
requirements are
+                                        ANDed.
+                                      items:
+                                        description: A label selector 
requirement
+                                          is a selector that contains values, 
a key,
+                                          and an operator that relates the key 
and
+                                          values.
+                                        properties:
+                                          key:
+                                            description: key is the label key 
that
+                                              the selector applies to.
+                                            type: string
+                                          operator:
+                                            description: operator represents a 
key's
+                                              relationship to a set of values. 
Valid
+                                              operators are In, NotIn, Exists 
and
+                                              DoesNotExist.
+                                            type: string
+                                          values:
+                                            description: values is an array of 
string
+                                              values. If the operator is In or 
NotIn,
+                                              the values array must be 
non-empty.
+                                              If the operator is Exists or 
DoesNotExist,
+                                              the values array must be empty. 
This
+                                              array is replaced during a 
strategic
+                                              merge patch.
+                                            items:
+                                              type: string
+                                            type: array
+                                        required:
+                                        - key
+                                        - operator
+                                        type: object
+                                      type: array
+                                    matchLabels:
+                                      additionalProperties:
+                                        type: string
+                                      description: matchLabels is a map of 
{key,value}
+                                        pairs. A single {key,value} in the 
matchLabels
+                                        map is equivalent to an element of 
matchExpressions,
+                                        whose key field is "key", the operator 
is
+                                        "In", and the values array contains 
only "value".
+                                        The requirements are ANDed.
+                                      type: object
+                                  type: object
+                                namespaces:
+                                  description: namespaces specifies a static 
list
+                                    of namespace names that the term applies 
to. The
+                                    term is applied to the union of the 
namespaces
+                                    listed in this field and the ones selected 
by
+                                    namespaceSelector. null or empty 
namespaces list
+                                    and null namespaceSelector means "this 
pod's namespace".
+                                  items:
+                                    type: string
+                                  type: array
+                                topologyKey:
+                                  description: This pod should be co-located 
(affinity)
+                                    or not co-located (anti-affinity) with the 
pods
+                                    matching the labelSelector in the 
specified namespaces,
+                                    where co-located is defined as running on 
a node
+                                    whose value of the label with key 
topologyKey
+                                    matches that of any node on which any of 
the selected
+                                    pods is running. Empty topologyKey is not 
allowed.
+                                  type: string
+                              required:
+                              - topologyKey
+                              type: object
+                            weight:
+                              description: weight associated with matching the 
corresponding
+                                podAffinityTerm, in the range 1-100.
+                              format: int32
+                              type: integer
+                          required:
+                          - podAffinityTerm
+                          - weight
+                          type: object
+                        type: array
+                      requiredDuringSchedulingIgnoredDuringExecution:
+                        description: If the affinity requirements specified by 
this
+                          field are not met at scheduling time, the pod will 
not be
+                          scheduled onto the node. If the affinity 
requirements specified
+                          by this field cease to be met at some point during 
pod execution
+                          (e.g. due to a pod label update), the system may or 
may
+                          not try to eventually evict the pod from its node. 
When
+                          there are multiple elements, the lists of nodes 
corresponding
+                          to each podAffinityTerm are intersected, i.e. all 
terms
+                          must be satisfied.
+                        items:
+                          description: Defines a set of pods (namely those 
matching
+                            the labelSelector relative to the given 
namespace(s))
+                            that this pod should be co-located (affinity) or 
not co-located
+                            (anti-affinity) with, where co-located is defined 
as running
+                            on a node whose value of the label with key 
<topologyKey>
+                            matches that of any node on which a pod of the set 
of
+                            pods is running
+                          properties:
+                            labelSelector:
+                              description: A label query over a set of 
resources,
+                                in this case pods.
+                              properties:
+                                matchExpressions:
+                                  description: matchExpressions is a list of 
label
+                                    selector requirements. The requirements 
are ANDed.
+                                  items:
+                                    description: A label selector requirement 
is a
+                                      selector that contains values, a key, 
and an
+                                      operator that relates the key and values.
+                                    properties:
+                                      key:
+                                        description: key is the label key that 
the
+                                          selector applies to.
+                                        type: string
+                                      operator:
+                                        description: operator represents a 
key's relationship
+                                          to a set of values. Valid operators 
are
+                                          In, NotIn, Exists and DoesNotExist.
+                                        type: string
+                                      values:
+                                        description: values is an array of 
string
+                                          values. If the operator is In or 
NotIn,
+                                          the values array must be non-empty. 
If the
+                                          operator is Exists or DoesNotExist, 
the
+                                          values array must be empty. This 
array is
+                                          replaced during a strategic merge 
patch.
+                                        items:
+                                          type: string
+                                        type: array
+                                    required:
+                                    - key
+                                    - operator
+                                    type: object
+                                  type: array
+                                matchLabels:
+                                  additionalProperties:
+                                    type: string
+                                  description: matchLabels is a map of 
{key,value}
+                                    pairs. A single {key,value} in the 
matchLabels
+                                    map is equivalent to an element of 
matchExpressions,
+                                    whose key field is "key", the operator is 
"In",
+                                    and the values array contains only 
"value". The
+                                    requirements are ANDed.
+                                  type: object
+                              type: object
+                            namespaceSelector:
+                              description: A label query over the set of 
namespaces
+                                that the term applies to. The term is applied 
to the
+                                union of the namespaces selected by this field 
and
+                                the ones listed in the namespaces field. null 
selector
+                                and null or empty namespaces list means "this 
pod's
+                                namespace". An empty selector ({}) matches all 
namespaces.
+                              properties:
+                                matchExpressions:
+                                  description: matchExpressions is a list of 
label
+                                    selector requirements. The requirements 
are ANDed.
+                                  items:
+                                    description: A label selector requirement 
is a
+                                      selector that contains values, a key, 
and an
+                                      operator that relates the key and values.
+                                    properties:
+                                      key:
+                                        description: key is the label key that 
the
+                                          selector applies to.
+                                        type: string
+                                      operator:
+                                        description: operator represents a 
key's relationship
+                                          to a set of values. Valid operators 
are
+                                          In, NotIn, Exists and DoesNotExist.
+                                        type: string
+                                      values:
+                                        description: values is an array of 
string
+                                          values. If the operator is In or 
NotIn,
+                                          the values array must be non-empty. 
If the
+                                          operator is Exists or DoesNotExist, 
the
+                                          values array must be empty. This 
array is
+                                          replaced during a strategic merge 
patch.
+                                        items:
+                                          type: string
+                                        type: array
+                                    required:
+                                    - key
+                                    - operator
+                                    type: object
+                                  type: array
+                                matchLabels:
+                                  additionalProperties:
+                                    type: string
+                                  description: matchLabels is a map of 
{key,value}
+                                    pairs. A single {key,value} in the 
matchLabels
+                                    map is equivalent to an element of 
matchExpressions,
+                                    whose key field is "key", the operator is 
"In",
+                                    and the values array contains only 
"value". The
+                                    requirements are ANDed.
+                                  type: object
+                              type: object
+                            namespaces:
+                              description: namespaces specifies a static list 
of namespace
+                                names that the term applies to. The term is 
applied
+                                to the union of the namespaces listed in this 
field
+                                and the ones selected by namespaceSelector. 
null or
+                                empty namespaces list and null 
namespaceSelector means
+                                "this pod's namespace".
+                              items:
+                                type: string
+                              type: array
+                            topologyKey:
+                              description: This pod should be co-located 
(affinity)
+                                or not co-located (anti-affinity) with the 
pods matching
+                                the labelSelector in the specified namespaces, 
where
+                                co-located is defined as running on a node 
whose value
+                                of the label with key topologyKey matches that 
of
+                                any node on which any of the selected pods is 
running.
+                                Empty topologyKey is not allowed.
+                              type: string
+                          required:
+                          - topologyKey
+                          type: object
+                        type: array
+                    type: object
+                  podAntiAffinity:
+                    description: Describes pod anti-affinity scheduling rules 
(e.g.
+                      avoid putting this pod in the same node, zone, etc. as 
some
+                      other pod(s)).
+                    properties:
+                      preferredDuringSchedulingIgnoredDuringExecution:
+                        description: The scheduler will prefer to schedule 
pods to
+                          nodes that satisfy the anti-affinity expressions 
specified
+                          by this field, but it may choose a node that 
violates one
+                          or more of the expressions. The node that is most 
preferred
+                          is the one with the greatest sum of weights, i.e. 
for each
+                          node that meets all of the scheduling requirements 
(resource
+                          request, requiredDuringScheduling anti-affinity 
expressions,
+                          etc.), compute a sum by iterating through the 
elements of
+                          this field and adding "weight" to the sum if the 
node has
+                          pods which matches the corresponding 
podAffinityTerm; the
+                          node(s) with the highest sum are the most preferred.
+                        items:
+                          description: The weights of all of the matched 
WeightedPodAffinityTerm
+                            fields are added per-node to find the most 
preferred node(s)
+                          properties:
+                            podAffinityTerm:
+                              description: Required. A pod affinity term, 
associated
+                                with the corresponding weight.
+                              properties:
+                                labelSelector:
+                                  description: A label query over a set of 
resources,
+                                    in this case pods.
+                                  properties:
+                                    matchExpressions:
+                                      description: matchExpressions is a list 
of label
+                                        selector requirements. The 
requirements are
+                                        ANDed.
+                                      items:
+                                        description: A label selector 
requirement
+                                          is a selector that contains values, 
a key,
+                                          and an operator that relates the key 
and
+                                          values.
+                                        properties:
+                                          key:
+                                            description: key is the label key 
that
+                                              the selector applies to.
+                                            type: string
+                                          operator:
+                                            description: operator represents a 
key's
+                                              relationship to a set of values. 
Valid
+                                              operators are In, NotIn, Exists 
and
+                                              DoesNotExist.
+                                            type: string
+                                          values:
+                                            description: values is an array of 
string
+                                              values. If the operator is In or 
NotIn,
+                                              the values array must be 
non-empty.
+                                              If the operator is Exists or 
DoesNotExist,
+                                              the values array must be empty. 
This
+                                              array is replaced during a 
strategic
+                                              merge patch.
+                                            items:
+                                              type: string
+                                            type: array
+                                        required:
+                                        - key
+                                        - operator
+                                        type: object
+                                      type: array
+                                    matchLabels:
+                                      additionalProperties:
+                                        type: string
+                                      description: matchLabels is a map of 
{key,value}
+                                        pairs. A single {key,value} in the 
matchLabels
+                                        map is equivalent to an element of 
matchExpressions,
+                                        whose key field is "key", the operator 
is
+                                        "In", and the values array contains 
only "value".
+                                        The requirements are ANDed.
+                                      type: object
+                                  type: object
+                                namespaceSelector:
+                                  description: A label query over the set of 
namespaces
+                                    that the term applies to. The term is 
applied
+                                    to the union of the namespaces selected by 
this
+                                    field and the ones listed in the 
namespaces field.
+                                    null selector and null or empty namespaces 
list
+                                    means "this pod's namespace". An empty 
selector
+                                    ({}) matches all namespaces.
+                                  properties:
+                                    matchExpressions:
+                                      description: matchExpressions is a list 
of label
+                                        selector requirements. The 
requirements are
+                                        ANDed.
+                                      items:
+                                        description: A label selector 
requirement
+                                          is a selector that contains values, 
a key,
+                                          and an operator that relates the key 
and
+                                          values.
+                                        properties:
+                                          key:
+                                            description: key is the label key 
that
+                                              the selector applies to.
+                                            type: string
+                                          operator:
+                                            description: operator represents a 
key's
+                                              relationship to a set of values. 
Valid
+                                              operators are In, NotIn, Exists 
and
+                                              DoesNotExist.
+                                            type: string
+                                          values:
+                                            description: values is an array of 
string
+                                              values. If the operator is In or 
NotIn,
+                                              the values array must be 
non-empty.
+                                              If the operator is Exists or 
DoesNotExist,
+                                              the values array must be empty. 
This
+                                              array is replaced during a 
strategic
+                                              merge patch.
+                                            items:
+                                              type: string
+                                            type: array
+                                        required:
+                                        - key
+                                        - operator
+                                        type: object
+                                      type: array
+                                    matchLabels:
+                                      additionalProperties:
+                                        type: string
+                                      description: matchLabels is a map of 
{key,value}
+                                        pairs. A single {key,value} in the 
matchLabels
+                                        map is equivalent to an element of 
matchExpressions,
+                                        whose key field is "key", the operator 
is
+                                        "In", and the values array contains 
only "value".
+                                        The requirements are ANDed.
+                                      type: object
+                                  type: object
+                                namespaces:
+                                  description: namespaces specifies a static 
list
+                                    of namespace names that the term applies 
to. The
+                                    term is applied to the union of the 
namespaces
+                                    listed in this field and the ones selected 
by
+                                    namespaceSelector. null or empty 
namespaces list
+                                    and null namespaceSelector means "this 
pod's namespace".
+                                  items:
+                                    type: string
+                                  type: array
+                                topologyKey:
+                                  description: This pod should be co-located 
(affinity)
+                                    or not co-located (anti-affinity) with the 
pods
+                                    matching the labelSelector in the 
specified namespaces,
+                                    where co-located is defined as running on 
a node
+                                    whose value of the label with key 
topologyKey
+                                    matches that of any node on which any of 
the selected
+                                    pods is running. Empty topologyKey is not 
allowed.
+                                  type: string
+                              required:
+                              - topologyKey
+                              type: object
+                            weight:
+                              description: weight associated with matching the 
corresponding
+                                podAffinityTerm, in the range 1-100.
+                              format: int32
+                              type: integer
+                          required:
+                          - podAffinityTerm
+                          - weight
+                          type: object
+                        type: array
+                      requiredDuringSchedulingIgnoredDuringExecution:
+                        description: If the anti-affinity requirements 
specified by
+                          this field are not met at scheduling time, the pod 
will
+                          not be scheduled onto the node. If the anti-affinity 
requirements
+                          specified by this field cease to be met at some 
point during
+                          pod execution (e.g. due to a pod label update), the 
system
+                          may or may not try to eventually evict the pod from 
its
+                          node. When there are multiple elements, the lists of 
nodes
+                          corresponding to each podAffinityTerm are 
intersected, i.e.
+                          all terms must be satisfied.
+                        items:
+                          description: Defines a set of pods (namely those 
matching
+                            the labelSelector relative to the given 
namespace(s))
+                            that this pod should be co-located (affinity) or 
not co-located
+                            (anti-affinity) with, where co-located is defined 
as running
+                            on a node whose value of the label with key 
<topologyKey>
+                            matches that of any node on which a pod of the set 
of
+                            pods is running
+                          properties:
+                            labelSelector:
+                              description: A label query over a set of 
resources,
+                                in this case pods.
+                              properties:
+                                matchExpressions:
+                                  description: matchExpressions is a list of 
label
+                                    selector requirements. The requirements 
are ANDed.
+                                  items:
+                                    description: A label selector requirement 
is a
+                                      selector that contains values, a key, 
and an
+                                      operator that relates the key and values.
+                                    properties:
+                                      key:
+                                        description: key is the label key that 
the
+                                          selector applies to.
+                                        type: string
+                                      operator:
+                                        description: operator represents a 
key's relationship
+                                          to a set of values. Valid operators 
are
+                                          In, NotIn, Exists and DoesNotExist.
+                                        type: string
+                                      values:
+                                        description: values is an array of 
string
+                                          values. If the operator is In or 
NotIn,
+                                          the values array must be non-empty. 
If the
+                                          operator is Exists or DoesNotExist, 
the
+                                          values array must be empty. This 
array is
+                                          replaced during a strategic merge 
patch.
+                                        items:
+                                          type: string
+                                        type: array
+                                    required:
+                                    - key
+                                    - operator
+                                    type: object
+                                  type: array
+                                matchLabels:
+                                  additionalProperties:
+                                    type: string
+                                  description: matchLabels is a map of 
{key,value}
+                                    pairs. A single {key,value} in the 
matchLabels
+                                    map is equivalent to an element of 
matchExpressions,
+                                    whose key field is "key", the operator is 
"In",
+                                    and the values array contains only 
"value". The
+                                    requirements are ANDed.
+                                  type: object
+                              type: object
+                            namespaceSelector:
+                              description: A label query over the set of 
namespaces
+                                that the term applies to. The term is applied 
to the
+                                union of the namespaces selected by this field 
and
+                                the ones listed in the namespaces field. null 
selector
+                                and null or empty namespaces list means "this 
pod's
+                                namespace". An empty selector ({}) matches all 
namespaces.
+                              properties:
+                                matchExpressions:
+                                  description: matchExpressions is a list of 
label
+                                    selector requirements. The requirements 
are ANDed.
+                                  items:
+                                    description: A label selector requirement 
is a
+                                      selector that contains values, a key, 
and an
+                                      operator that relates the key and values.
+                                    properties:
+                                      key:
+                                        description: key is the label key that 
the
+                                          selector applies to.
+                                        type: string
+                                      operator:
+                                        description: operator represents a 
key's relationship
+                                          to a set of values. Valid operators 
are
+                                          In, NotIn, Exists and DoesNotExist.
+                                        type: string
+                                      values:
+                                        description: values is an array of 
string
+                                          values. If the operator is In or 
NotIn,
+                                          the values array must be non-empty. 
If the
+                                          operator is Exists or DoesNotExist, 
the
+                                          values array must be empty. This 
array is
+                                          replaced during a strategic merge 
patch.
+                                        items:
+                                          type: string
+                                        type: array
+                                    required:
+                                    - key
+                                    - operator
+                                    type: object
+                                  type: array
+                                matchLabels:
+                                  additionalProperties:
+                                    type: string
+                                  description: matchLabels is a map of 
{key,value}
+                                    pairs. A single {key,value} in the 
matchLabels
+                                    map is equivalent to an element of 
matchExpressions,
+                                    whose key field is "key", the operator is 
"In",
+                                    and the values array contains only 
"value". The
+                                    requirements are ANDed.
+                                  type: object
+                              type: object
+                            namespaces:
+                              description: namespaces specifies a static list 
of namespace
+                                names that the term applies to. The term is 
applied
+                                to the union of the namespaces listed in this 
field
+                                and the ones selected by namespaceSelector. 
null or
+                                empty namespaces list and null 
namespaceSelector means
+                                "this pod's namespace".
+                              items:
+                                type: string
+                              type: array
+                            topologyKey:
+                              description: This pod should be co-located 
(affinity)
+                                or not co-located (anti-affinity) with the 
pods matching
+                                the labelSelector in the specified namespaces, 
where
+                                co-located is defined as running on a node 
whose value
+                                of the label with key topologyKey matches that 
of
+                                any node on which any of the selected pods is 
running.
+                                Empty topologyKey is not allowed.
+                              type: string
+                          required:
+                          - topologyKey
+                          type: object
+                        type: array
+                    type: object
+                type: object
+              config:
+                description: BanyanDB startup parameters
+                items:
+                  type: string
+                type: array
+              counts:
+                description: Number of replicas
+                type: integer
+              gRPCService:
+                description: BanyanDB gRPC Serice
+                properties:
+                  ingress:
+                    description: Ingress defines the behavior of an ingress
+                    properties:
+                      annotations:
+                        additionalProperties:
+                          type: string
+                        description: Annotations is an unstructured key value 
map
+                          stored with a resource that may be set by external 
tools
+                          to store and retrieve arbitrary metadata. They are 
not queryable
+                          and should be preserved when modifying objects.
+                        type: object
+                      host:
+                        description: Host is the fully qualified domain name 
of a
+                          network host, as defined by RFC 3986. Note the 
following
+                          deviations from the "host" part of the URI as 
defined in
+                          RFC 3986
+                        type: string
+                      ingressClassName:
+                        description: IngressClassName is the name of the 
IngressClass
+                          cluster resource. The associated IngressClass 
defines which
+                          controller will implement the resource. This 
replaces the
+                          deprecated `kubernetes.io/ingress.class` annotation. 
For
+                          backwards compatibility, when that annotation is 
set, it
+                          must be given precedence over this field. The 
controller
+                          may emit a warning if the field and annotation have 
different
+                          values. Implementations of this API should ignore 
Ingresses
+                          without a class specified. An IngressClass resource 
may
+                          be marked as default, which can be used to set a 
default
+                          value for this field. For more information, refer to 
the
+                          IngressClass documentation.
+                        type: string
+                      tls:
+                        description: TLS configuration. Currently the Ingress 
only
+                          supports a single TLS port, 443. If multiple members 
of
+                          this list specify different hosts, they will be 
multiplexed
+                          on the same port according to the hostname specified 
through
+                          the SNI TLS extension, if the ingress controller 
fulfilling
+                          the ingress supports SNI.
+                        items:
+                          description: IngressTLS describes the transport 
layer security
+                            associated with an Ingress.
+                          properties:
+                            hosts:
+                              description: Hosts are a list of hosts included 
in the
+                                TLS certificate. The values in this list must 
match
+                                the name/s used in the tlsSecret. Defaults to 
the
+                                wildcard host setting for the loadbalancer 
controller
+                                fulfilling this Ingress, if left unspecified.
+                              items:
+                                type: string
+                              type: array
+                              x-kubernetes-list-type: atomic
+                            secretName:
+                              description: SecretName is the name of the 
secret used
+                                to terminate TLS traffic on port 443. Field is 
left
+                                optional to allow TLS routing based on SNI 
hostname
+                                alone. If the SNI host in a listener conflicts 
with
+                                the "Host" header field used by an 
IngressRule, the
+                                SNI host is used for termination and value of 
the
+                                Host header is used for routing.
+                              type: string
+                          type: object
+                        type: array
+                    type: object
+                  template:
+                    description: ServiceTemplate defines the behavior of a 
service.
+                    properties:
+                      clusterIP:
+                        description: clusterIP is the IP address of the 
service and
+                          is usually assigned randomly.
+                        type: string
+                      externalIPs:
+                        description: externalIPs is a list of IP addresses for 
which
+                          nodes in the cluster will also accept traffic for 
this service.
+                        items:
+                          type: string
+                        type: array
+                      loadBalancerIP:
+                        description: 'Only applies to Service Type: 
LoadBalancer LoadBalancer
+                          will get created with the IP specified in this 
field.'
+                        type: string
+                      loadBalancerSourceRanges:
+                        description: If specified and supported by the 
platform, this
+                          will restrict traffic through the cloud-provider 
load-balancer
+                          will be restricted to the specified client IPs.
+                        items:
+                          type: string
+                        type: array
+                      type:
+                        description: type determines how the Service is 
exposed.
+                        type: string
+                    type: object
+                type: object
+              httpService:
+                description: BanyanDB HTTP Service
+                properties:
+                  ingress:
+                    description: Ingress defines the behavior of an ingress
+                    properties:
+                      annotations:
+                        additionalProperties:
+                          type: string
+                        description: Annotations is an unstructured key value 
map
+                          stored with a resource that may be set by external 
tools
+                          to store and retrieve arbitrary metadata. They are 
not queryable
+                          and should be preserved when modifying objects.
+                        type: object
+                      host:
+                        description: Host is the fully qualified domain name 
of a
+                          network host, as defined by RFC 3986. Note the 
following
+                          deviations from the "host" part of the URI as 
defined in
+                          RFC 3986
+                        type: string
+                      ingressClassName:
+                        description: IngressClassName is the name of the 
IngressClass
+                          cluster resource. The associated IngressClass 
defines which
+                          controller will implement the resource. This 
replaces the
+                          deprecated `kubernetes.io/ingress.class` annotation. 
For
+                          backwards compatibility, when that annotation is 
set, it
+                          must be given precedence over this field. The 
controller
+                          may emit a warning if the field and annotation have 
different
+                          values. Implementations of this API should ignore 
Ingresses
+                          without a class specified. An IngressClass resource 
may
+                          be marked as default, which can be used to set a 
default
+                          value for this field. For more information, refer to 
the
+                          IngressClass documentation.
+                        type: string
+                      tls:
+                        description: TLS configuration. Currently the Ingress 
only
+                          supports a single TLS port, 443. If multiple members 
of
+                          this list specify different hosts, they will be 
multiplexed
+                          on the same port according to the hostname specified 
through
+                          the SNI TLS extension, if the ingress controller 
fulfilling
+                          the ingress supports SNI.
+                        items:
+                          description: IngressTLS describes the transport 
layer security
+                            associated with an Ingress.
+                          properties:
+                            hosts:
+                              description: Hosts are a list of hosts included 
in the
+                                TLS certificate. The values in this list must 
match
+                                the name/s used in the tlsSecret. Defaults to 
the
+                                wildcard host setting for the loadbalancer 
controller
+                                fulfilling this Ingress, if left unspecified.
+                              items:
+                                type: string
+                              type: array
+                              x-kubernetes-list-type: atomic
+                            secretName:
+                              description: SecretName is the name of the 
secret used
+                                to terminate TLS traffic on port 443. Field is 
left
+                                optional to allow TLS routing based on SNI 
hostname
+                                alone. If the SNI host in a listener conflicts 
with
+                                the "Host" header field used by an 
IngressRule, the
+                                SNI host is used for termination and value of 
the
+                                Host header is used for routing.
+                              type: string
+                          type: object
+                        type: array
+                    type: object
+                  template:
+                    description: ServiceTemplate defines the behavior of a 
service.
+                    properties:
+                      clusterIP:
+                        description: clusterIP is the IP address of the 
service and
+                          is usually assigned randomly.
+                        type: string
+                      externalIPs:
+                        description: externalIPs is a list of IP addresses for 
which
+                          nodes in the cluster will also accept traffic for 
this service.
+                        items:
+                          type: string
+                        type: array
+                      loadBalancerIP:
+                        description: 'Only applies to Service Type: 
LoadBalancer LoadBalancer
+                          will get created with the IP specified in this 
field.'
+                        type: string
+                      loadBalancerSourceRanges:
+                        description: If specified and supported by the 
platform, this
+                          will restrict traffic through the cloud-provider 
load-balancer
+                          will be restricted to the specified client IPs.
+                        items:
+                          type: string
+                        type: array
+                      type:
+                        description: type determines how the Service is 
exposed.
+                        type: string
+                    type: object
+                type: object
+              image:
+                description: Pod template of each BanyanDB instance
+                type: string
+              storages:
+                description: BanyanDB Storage
+                items:
+                  properties:
+                    name:
+                      description: the name of storage config
+                      type: string
+                    path:
+                      description: mount path of the volume
+                      type: string
+                    persistentVolumeClaimSpec:
+                      description: the persistent volume spec for the storage
+                      properties:
+                        accessModes:
+                          description: 'accessModes contains the desired 
access modes
+                            the volume should have. More info: 
https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1'
+                          items:
+                            type: string
+                          type: array
+                        dataSource:
+                          description: 'dataSource field can be used to 
specify either:
+                            * An existing VolumeSnapshot object 
(snapshot.storage.k8s.io/VolumeSnapshot)
+                            * An existing PVC (PersistentVolumeClaim) If the 
provisioner
+                            or an external controller can support the 
specified data
+                            source, it will create a new volume based on the 
contents
+                            of the specified data source. If the 
AnyVolumeDataSource
+                            feature gate is enabled, this field will always 
have the
+                            same contents as the DataSourceRef field.'
+                          properties:
+                            apiGroup:
+                              description: APIGroup is the group for the 
resource
+                                being referenced. If APIGroup is not 
specified, the
+                                specified Kind must be in the core API group. 
For
+                                any other third-party types, APIGroup is 
required.
+                              type: string
+                            kind:
+                              description: Kind is the type of resource being 
referenced
+                              type: string
+                            name:
+                              description: Name is the name of resource being 
referenced
+                              type: string
+                          required:
+                          - kind
+                          - name
+                          type: object
+                        dataSourceRef:
+                          description: 'dataSourceRef specifies the object 
from which
+                            to populate the volume with data, if a non-empty 
volume
+                            is desired. This may be any local object from a 
non-empty
+                            API group (non core object) or a 
PersistentVolumeClaim
+                            object. When this field is specified, volume 
binding will
+                            only succeed if the type of the specified object 
matches
+                            some installed volume populator or dynamic 
provisioner.
+                            This field will replace the functionality of the 
DataSource
+                            field and as such if both fields are non-empty, 
they must
+                            have the same value. For backwards compatibility, 
both
+                            fields (DataSource and DataSourceRef) will be set 
to the
+                            same value automatically if one of them is empty 
and the
+                            other is non-empty. There are two important 
differences
+                            between DataSource and DataSourceRef: * While 
DataSource
+                            only allows two specific types of objects, 
DataSourceRef   allows
+                            any non-core object, as well as 
PersistentVolumeClaim
+                            objects. * While DataSource ignores disallowed 
values
+                            (dropping them), DataSourceRef   preserves all 
values,
+                            and generates an error if a disallowed value is   
specified.
+                            (Beta) Using this field requires the 
AnyVolumeDataSource
+                            feature gate to be enabled.'
+                          properties:
+                            apiGroup:
+                              description: APIGroup is the group for the 
resource
+                                being referenced. If APIGroup is not 
specified, the
+                                specified Kind must be in the core API group. 
For
+                                any other third-party types, APIGroup is 
required.
+                              type: string
+                            kind:
+                              description: Kind is the type of resource being 
referenced
+                              type: string
+                            name:
+                              description: Name is the name of resource being 
referenced
+                              type: string
+                          required:
+                          - kind
+                          - name
+                          type: object
+                        resources:
+                          description: 'resources represents the minimum 
resources
+                            the volume should have. If 
RecoverVolumeExpansionFailure
+                            feature is enabled users are allowed to specify 
resource
+                            requirements that are lower than previous value 
but must
+                            still be higher than capacity recorded in the 
status field
+                            of the claim. More info: 
https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources'
+                          properties:
+                            limits:
+                              additionalProperties:
+                                anyOf:
+                                - type: integer
+                                - type: string
+                                pattern: 
^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+                                x-kubernetes-int-or-string: true
+                              description: 'Limits describes the maximum 
amount of
+                                compute resources allowed. More info: 
https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/'
+                              type: object
+                            requests:
+                              additionalProperties:
+                                anyOf:
+                                - type: integer
+                                - type: string
+                                pattern: 
^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+                                x-kubernetes-int-or-string: true
+                              description: 'Requests describes the minimum 
amount
+                                of compute resources required. If Requests is 
omitted
+                                for a container, it defaults to Limits if that 
is
+                                explicitly specified, otherwise to an 
implementation-defined
+                                value. More info: 
https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/'
+                              type: object
+                          type: object
+                        selector:
+                          description: selector is a label query over volumes 
to consider
+                            for binding.
+                          properties:
+                            matchExpressions:
+                              description: matchExpressions is a list of label 
selector
+                                requirements. The requirements are ANDed.
+                              items:
+                                description: A label selector requirement is a 
selector
+                                  that contains values, a key, and an operator 
that
+                                  relates the key and values.
+                                properties:
+                                  key:
+                                    description: key is the label key that the 
selector
+                                      applies to.
+                                    type: string
+                                  operator:
+                                    description: operator represents a key's 
relationship
+                                      to a set of values. Valid operators are 
In,
+                                      NotIn, Exists and DoesNotExist.
+                                    type: string
+                                  values:
+                                    description: values is an array of string 
values.
+                                      If the operator is In or NotIn, the 
values array
+                                      must be non-empty. If the operator is 
Exists
+                                      or DoesNotExist, the values array must 
be empty.
+                                      This array is replaced during a 
strategic merge
+                                      patch.
+                                    items:
+                                      type: string
+                                    type: array
+                                required:
+                                - key
+                                - operator
+                                type: object
+                              type: array
+                            matchLabels:
+                              additionalProperties:
+                                type: string
+                              description: matchLabels is a map of {key,value} 
pairs.
+                                A single {key,value} in the matchLabels map is 
equivalent
+                                to an element of matchExpressions, whose key 
field
+                                is "key", the operator is "In", and the values 
array
+                                contains only "value". The requirements are 
ANDed.
+                              type: object
+                          type: object
+                        storageClassName:
+                          description: 'storageClassName is the name of the 
StorageClass
+                            required by the claim. More info: 
https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1'
+                          type: string
+                        volumeMode:
+                          description: volumeMode defines what type of volume 
is required
+                            by the claim. Value of Filesystem is implied when 
not
+                            included in claim spec.
+                          type: string
+                        volumeName:
+                          description: volumeName is the binding reference to 
the
+                            PersistentVolume backing this claim.
+                          type: string
+                      type: object
+                  type: object
+                type: array
+              version:
+                description: Version of BanyanDB.
+                type: string
+            required:
+            - counts
+            - image
+            - version
+            type: object
+          status:
+            description: BanyanDBStatus defines the observed state of BanyanDB
+            properties:
+              available_pods:
+                format: int32
+                type: integer
+              conditions:
+                description: Represents the latest available observations of 
the underlying
+                  statefulset's current state.
+                items:
+                  description: DeploymentCondition describes the state of a 
deployment
+                    at a certain point.
+                  properties:
+                    lastTransitionTime:
+                      description: Last time the condition transitioned from 
one status
+                        to another.
+                      format: date-time
+                      type: string
+                    lastUpdateTime:
+                      description: The last time this condition was updated.
+                      format: date-time
+                      type: string
+                    message:
+                      description: A human readable message indicating details 
about
+                        the transition.
+                      type: string
+                    reason:
+                      description: The reason for the condition's last 
transition.
+                      type: string
+                    status:
+                      description: Status of the condition, one of True, 
False, Unknown.
+                      type: string
+                    type:
+                      description: Type of deployment condition.
+                      type: string
+                  required:
+                  - status
+                  - type
+                  type: object
+                type: array
+            type: object
+        type: object
+    served: true
+    storage: true
+    subresources:
+      status: {}
+status:
+  acceptedNames:
+    kind: ""
+    plural: ""
+  conditions: []
+  storedVersions: []
diff --git 
a/operator/config/crd/bases/operator.skywalking.apache.org_swagents.yaml 
b/operator/config/crd/bases/operator.skywalking.apache.org_swagents.yaml
index 0be60ff..4c5d3a6 100644
--- a/operator/config/crd/bases/operator.skywalking.apache.org_swagents.yaml
+++ b/operator/config/crd/bases/operator.skywalking.apache.org_swagents.yaml
@@ -57,7 +57,7 @@ spec:
                   which is to be injected.
                 type: string
               javaSidecar:
-                description: Java defines Java agent special configs.
+                description: JavaSidecar defines Java agent special configs.
                 properties:
                   args:
                     description: Args is the args for initContainer.
diff --git a/operator/config/crd/kustomization.yaml 
b/operator/config/crd/kustomization.yaml
index 578d342..468804a 100644
--- a/operator/config/crd/kustomization.yaml
+++ b/operator/config/crd/kustomization.yaml
@@ -28,6 +28,7 @@ resources:
 - bases/operator.skywalking.apache.org_swagents.yaml
 - bases/operator.skywalking.apache.org_oapserverconfigs.yaml
 - bases/operator.skywalking.apache.org_oapserverdynamicconfigs.yaml
+- bases/operator.skywalking.apache.org_banyandbs.yaml
 #+kubebuilder:scaffold:crdkustomizeresource
 
 patchesStrategicMerge:
@@ -42,6 +43,7 @@ patchesStrategicMerge:
 - patches/webhook_in_oapserverconfigs.yaml
 #- patches/webhook_in_oapserverdynamicconfigs.yaml
 #- patches/webhook_in_swagents.yaml
+#- patches/webhook_in_banyandbs.yaml
 #+kubebuilder:scaffold:crdkustomizewebhookpatch
 
 # [CERTMANAGER] To enable cert-manager, uncomment all the sections with 
[CERTMANAGER] prefix.
@@ -55,6 +57,7 @@ patchesStrategicMerge:
 - patches/cainjection_in_oapserverconfigs.yaml
 #- patches/cainjection_in_oapserverdynamicconfigs.yaml
 #- patches/cainjection_in_swagents.yaml
+#- patches/cainjection_in_banyandbs.yaml
 #+kubebuilder:scaffold:crdkustomizecainjectionpatch
 
 # the following config is for teaching kustomize how to do kustomization for 
CRDs.
diff --git a/operator/config/rbac/role.yaml b/operator/config/rbac/role.yaml
index 7b6d617..95f31ec 100644
--- a/operator/config/rbac/role.yaml
+++ b/operator/config/rbac/role.yaml
@@ -49,6 +49,20 @@ rules:
   verbs:
   - create
   - patch
+- apiGroups:
+  - ""
+  resources:
+  - persistentvolumeclaims
+  - serviceaccounts
+  - services
+  verbs:
+  - create
+  - delete
+  - get
+  - list
+  - patch
+  - update
+  - watch
 - apiGroups:
   - ""
   resources:
@@ -147,6 +161,32 @@ rules:
   - patch
   - update
   - watch
+- apiGroups:
+  - operator.skywalking.apache.org
+  resources:
+  - banyandbs
+  verbs:
+  - create
+  - delete
+  - get
+  - list
+  - patch
+  - update
+  - watch
+- apiGroups:
+  - operator.skywalking.apache.org
+  resources:
+  - banyandbs/finalizers
+  verbs:
+  - update
+- apiGroups:
+  - operator.skywalking.apache.org
+  resources:
+  - banyandbs/status
+  verbs:
+  - get
+  - patch
+  - update
 - apiGroups:
   - operator.skywalking.apache.org
   resources:
diff --git a/operator/config/samples/banyandb.yaml 
b/operator/config/samples/banyandb.yaml
new file mode 100644
index 0000000..4f00cd2
--- /dev/null
+++ b/operator/config/samples/banyandb.yaml
@@ -0,0 +1,37 @@
+# Licensed to 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. Apache Software Foundation (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.
+
+apiVersion: operator.skywalking.apache.org/v1alpha1
+kind: BanyanDB
+metadata:
+  name: banyandb-sample
+spec:
+  version: 1.0.9
+  counts: 1
+  image: apache/skywalking-banyandb:latest
+  config:
+    - "standalone"
+
+  affinity:
+    nodeAffinity:
+      requiredDuringSchedulingIgnoredDuringExecution:
+        nodeSelectorTerms:
+          - matchExpressions:
+              - key: storage
+                operator: In
+                values:
+                  - banyandb
diff --git a/operator/config/webhook/manifests.yaml 
b/operator/config/webhook/manifests.yaml
index f69f2fa..5c1811c 100644
--- a/operator/config/webhook/manifests.yaml
+++ b/operator/config/webhook/manifests.yaml
@@ -22,6 +22,26 @@ metadata:
   creationTimestamp: null
   name: mutating-webhook-configuration
 webhooks:
+- admissionReviewVersions:
+  - v1
+  clientConfig:
+    service:
+      name: webhook-service
+      namespace: system
+      path: /mutate-operator-skywalking-apache-org-v1alpha1-banyandb
+  failurePolicy: Fail
+  name: mbanyandb.kb.io
+  rules:
+  - apiGroups:
+    - operator.skywalking.apache.org
+    apiVersions:
+    - v1alpha1
+    operations:
+    - CREATE
+    - UPDATE
+    resources:
+    - banyandbs
+  sideEffects: None
 - admissionReviewVersions:
   - v1
   clientConfig:
@@ -230,6 +250,26 @@ metadata:
   creationTimestamp: null
   name: validating-webhook-configuration
 webhooks:
+- admissionReviewVersions:
+  - v1
+  clientConfig:
+    service:
+      name: webhook-service
+      namespace: system
+      path: /validate-operator-skywalking-apache-org-v1alpha1-banyandb
+  failurePolicy: Fail
+  name: vbanyandb.kb.io
+  rules:
+  - apiGroups:
+    - operator.skywalking.apache.org
+    apiVersions:
+    - v1alpha1
+    operations:
+    - CREATE
+    - UPDATE
+    resources:
+    - banyandbs
+  sideEffects: None
 - admissionReviewVersions:
   - v1
   clientConfig:
diff --git a/operator/controllers/operator/satellite_controller.go 
b/operator/controllers/operator/banyandb_controller.go
similarity index 51%
copy from operator/controllers/operator/satellite_controller.go
copy to operator/controllers/operator/banyandb_controller.go
index 46eafb7..7d2dc62 100644
--- a/operator/controllers/operator/satellite_controller.go
+++ b/operator/controllers/operator/banyandb_controller.go
@@ -23,8 +23,8 @@ import (
 
        "github.com/go-logr/logr"
        apps "k8s.io/api/apps/v1"
-       core "k8s.io/api/core/v1"
        apiequal "k8s.io/apimachinery/pkg/api/equality"
+       apierrors "k8s.io/apimachinery/pkg/api/errors"
        "k8s.io/apimachinery/pkg/runtime"
        "k8s.io/client-go/tools/record"
        "k8s.io/client-go/util/retry"
@@ -32,30 +32,34 @@ import (
        "sigs.k8s.io/controller-runtime/pkg/client"
        runtimelog "sigs.k8s.io/controller-runtime/pkg/log"
 
+       "github.com/apache/skywalking-swck/operator/apis/operator/v1alpha1"
        operatorv1alpha1 
"github.com/apache/skywalking-swck/operator/apis/operator/v1alpha1"
        "github.com/apache/skywalking-swck/operator/pkg/kubernetes"
 )
 
-// SatelliteReconciler reconciles a Satellite object
-type SatelliteReconciler struct {
+// BanyanDBReconciler reconciles a BanyanDB object
+type BanyanDBReconciler struct {
        client.Client
        Scheme   *runtime.Scheme
        FileRepo kubernetes.Repo
        Recorder record.EventRecorder
 }
 
-//+kubebuilder:rbac:groups=operator.skywalking.apache.org,resources=satellites,verbs=get;list;watch;create;update;patch;delete
-//+kubebuilder:rbac:groups=operator.skywalking.apache.org,resources=satellites/status,verbs=get;update;patch
-//+kubebuilder:rbac:groups=operator.skywalking.apache.org,resources=satellites/finalizers,verbs=update
+//+kubebuilder:rbac:groups=operator.skywalking.apache.org,resources=banyandbs,verbs=get;list;watch;create;update;patch;delete
+//+kubebuilder:rbac:groups=operator.skywalking.apache.org,resources=banyandbs/status,verbs=get;update;patch
+//+kubebuilder:rbac:groups=operator.skywalking.apache.org,resources=banyandbs/finalizers,verbs=update
+//+kubebuilder:rbac:groups="",resources=services;serviceaccounts;persistentvolumeclaims,verbs=get;list;watch;create;update;patch;delete
+//+kubebuilder:rbac:groups=rbac.authorization.k8s.io,resources=clusterroles;clusterrolebindings,verbs=*
 
-func (r *SatelliteReconciler) Reconcile(ctx context.Context, req ctrl.Request) 
(ctrl.Result, error) {
+func (r *BanyanDBReconciler) Reconcile(ctx context.Context, req ctrl.Request) 
(ctrl.Result, error) {
        log := runtimelog.FromContext(ctx)
-       log.Info("=====================satellite reconcile 
started================================")
+       log.Info("=====================reconcile 
started================================")
 
-       satellite := operatorv1alpha1.Satellite{}
-       if err := r.Client.Get(ctx, req.NamespacedName, &satellite); err != nil 
{
+       var banyanDB v1alpha1.BanyanDB
+       if err := r.Get(ctx, req.NamespacedName, &banyanDB); err != nil {
                return ctrl.Result{}, client.IgnoreNotFound(err)
        }
+
        ff, err := r.FileRepo.GetFilesRecursive("templates")
        if err != nil {
                log.Error(err, "failed to load resource templates")
@@ -63,9 +67,9 @@ func (r *SatelliteReconciler) Reconcile(ctx context.Context, 
req ctrl.Request) (
        }
        app := kubernetes.Application{
                Client:   r.Client,
+               CR:       &banyanDB,
                FileRepo: r.FileRepo,
-               CR:       &satellite,
-               GVK:      operatorv1alpha1.GroupVersion.WithKind("Satellite"),
+               GVK:      operatorv1alpha1.GroupVersion.WithKind("BanyanDB"),
                Recorder: r.Recorder,
        }
 
@@ -73,7 +77,7 @@ func (r *SatelliteReconciler) Reconcile(ctx context.Context, 
req ctrl.Request) (
                return ctrl.Result{}, err
        }
 
-       if err := r.checkState(ctx, log, &satellite); err != nil {
+       if err := r.checkState(ctx, log, &banyanDB); err != nil {
                log.Error(err, "failed to check sub resources state")
                return ctrl.Result{}, err
        }
@@ -81,61 +85,51 @@ func (r *SatelliteReconciler) Reconcile(ctx 
context.Context, req ctrl.Request) (
        return ctrl.Result{RequeueAfter: schedDuration}, nil
 }
 
-func (r *SatelliteReconciler) checkState(ctx context.Context, log logr.Logger, 
satellite *operatorv1alpha1.Satellite) error {
-       overlay := operatorv1alpha1.SatelliteStatus{}
+func (r *BanyanDBReconciler) checkState(ctx context.Context, log logr.Logger, 
banyanDB *operatorv1alpha1.BanyanDB) error {
+       overlay := operatorv1alpha1.BanyanDBStatus{}
        deployment := apps.Deployment{}
        errCol := new(kubernetes.ErrorCollector)
-       if err := r.Client.Get(ctx, client.ObjectKey{Namespace: 
satellite.Namespace, Name: satellite.Name + "-satellite"}, &deployment); err != 
nil {
-               errCol.Collect(fmt.Errorf("failed to get deployment :%v", err))
+       if err := r.Client.Get(ctx, client.ObjectKey{Namespace: 
banyanDB.Namespace, Name: banyanDB.Name + "-banyandb"}, &deployment); err != 
nil && !apierrors.IsNotFound(err) {
+               errCol.Collect(fmt.Errorf("failed to get deployment: %w", err))
        } else {
                overlay.Conditions = deployment.Status.Conditions
                overlay.AvailableReplicas = deployment.Status.AvailableReplicas
        }
-       service := core.Service{}
-       if err := r.Client.Get(ctx, client.ObjectKey{Namespace: 
satellite.Namespace, Name: satellite.Name + "-satellite"}, &service); err != 
nil {
-               errCol.Collect(fmt.Errorf("failed to get service :%v", err))
-       } else {
-               overlay.Address = fmt.Sprintf("%s.%s", service.Name, 
service.Namespace)
-       }
-       if apiequal.Semantic.DeepDerivative(overlay, satellite.Status) {
+       if apiequal.Semantic.DeepDerivative(overlay, banyanDB.Status) {
                log.Info("Status keeps the same as before")
-       }
-       satellite.Status = overlay
-       satellite.Kind = "Satellite"
-       if err := kubernetes.ApplyOverlay(satellite, 
&operatorv1alpha1.Satellite{Status: overlay}); err != nil {
-               errCol.Collect(fmt.Errorf("failed to apply overlay: %w", err))
                return errCol.Error()
        }
-       if err := r.updateStatus(ctx, satellite, overlay, errCol); err != nil {
-               errCol.Collect(fmt.Errorf("failed to update status of 
satellite: %w", err))
+
+       if err := r.updateStatus(ctx, banyanDB, overlay, errCol); err != nil {
+               errCol.Collect(fmt.Errorf("failed to update status of banyanDB: 
%w", err))
        }
+
        log.Info("updated Status sub resource")
 
        return errCol.Error()
 }
 
-func (r *SatelliteReconciler) updateStatus(ctx context.Context, satellite 
*operatorv1alpha1.Satellite,
-       overlay operatorv1alpha1.SatelliteStatus, errCol 
*kubernetes.ErrorCollector) error {
-       // avoid resource conflict
+func (r *BanyanDBReconciler) updateStatus(ctx context.Context, banyanDB 
*operatorv1alpha1.BanyanDB,
+       overlay operatorv1alpha1.BanyanDBStatus, errCol 
*kubernetes.ErrorCollector) error {
        return retry.RetryOnConflict(retry.DefaultBackoff, func() error {
-               if err := r.Client.Get(ctx, client.ObjectKey{Name: 
satellite.Name, Namespace: satellite.Namespace}, satellite); err != nil {
-                       errCol.Collect(fmt.Errorf("failed to get satellite: 
%w", err))
+               if err := r.Client.Get(ctx, client.ObjectKey{Namespace: 
banyanDB.Namespace, Name: banyanDB.Name}, banyanDB); err != nil {
+                       errCol.Collect(fmt.Errorf("failed to get banyanDB: %w", 
err))
                }
-               satellite.Status = overlay
-               satellite.Kind = "Satellite"
-               if err := kubernetes.ApplyOverlay(satellite, 
&operatorv1alpha1.Satellite{Status: overlay}); err != nil {
+               banyanDB.Status = overlay
+               banyanDB.Kind = "BanyanDB"
+               if err := kubernetes.ApplyOverlay(banyanDB, 
&operatorv1alpha1.BanyanDB{Status: overlay}); err != nil {
                        errCol.Collect(fmt.Errorf("failed to apply overlay: 
%w", err))
                }
-               if err := r.Status().Update(ctx, satellite); err != nil {
-                       errCol.Collect(fmt.Errorf("failed to update status of 
satellite: %w", err))
+               if err := r.Status().Update(ctx, banyanDB); err != nil {
+                       errCol.Collect(fmt.Errorf("failed to update status of 
banyandb: %w", err))
                }
                return errCol.Error()
        })
 }
 
 // SetupWithManager sets up the controller with the Manager.
-func (r *SatelliteReconciler) SetupWithManager(mgr ctrl.Manager) error {
+func (r *BanyanDBReconciler) SetupWithManager(mgr ctrl.Manager) error {
        return ctrl.NewControllerManagedBy(mgr).
-               For(&operatorv1alpha1.Satellite{}).
+               For(&operatorv1alpha1.BanyanDB{}).
                Complete(r)
 }
diff --git a/operator/controllers/operator/oapserver_controller.go 
b/operator/controllers/operator/oapserver_controller.go
index 02fb940..1315f24 100644
--- a/operator/controllers/operator/oapserver_controller.go
+++ b/operator/controllers/operator/oapserver_controller.go
@@ -113,6 +113,7 @@ func (r *OAPServerReconciler) checkState(ctx 
context.Context, log logr.Logger, o
        }
        if apiequal.Semantic.DeepDerivative(overlay, oapServer.Status) {
                log.Info("Status keeps the same as before")
+               return errCol.Error()
        }
 
        if err := r.updateStatus(ctx, oapServer, overlay, errCol); err != nil {
diff --git a/operator/controllers/operator/satellite_controller.go 
b/operator/controllers/operator/satellite_controller.go
index 46eafb7..4735aa4 100644
--- a/operator/controllers/operator/satellite_controller.go
+++ b/operator/controllers/operator/satellite_controller.go
@@ -99,6 +99,7 @@ func (r *SatelliteReconciler) checkState(ctx context.Context, 
log logr.Logger, s
        }
        if apiequal.Semantic.DeepDerivative(overlay, satellite.Status) {
                log.Info("Status keeps the same as before")
+               return errCol.Error()
        }
        satellite.Status = overlay
        satellite.Kind = "Satellite"
diff --git a/operator/controllers/operator/storage_controller.go 
b/operator/controllers/operator/storage_controller.go
index 1458595..4bb4136 100644
--- a/operator/controllers/operator/storage_controller.go
+++ b/operator/controllers/operator/storage_controller.go
@@ -138,6 +138,7 @@ func (r *StorageReconciler) checkState(ctx context.Context, 
log logr.Logger, sto
 
        if apiequal.Semantic.DeepDerivative(overlay, storage.Status) {
                log.Info("Status keeps the same as before")
+               return errCol.Error()
        }
        storage.Status = overlay
        storage.Kind = "Storage"
diff --git a/operator/controllers/operator/ui_controller.go 
b/operator/controllers/operator/ui_controller.go
index f03a20a..924e07d 100644
--- a/operator/controllers/operator/ui_controller.go
+++ b/operator/controllers/operator/ui_controller.go
@@ -110,6 +110,7 @@ func (r *UIReconciler) checkState(ctx context.Context, log 
logr.Logger, ui *uiv1
        }
        if apiequal.Semantic.DeepDerivative(overlay, ui.Status) {
                log.Info("Status keeps the same as before")
+               return errCol.Error()
        }
        ui.Status = overlay
        ui.Kind = "UI"
diff --git a/operator/main.go b/operator/main.go
index 97fab46..1da407f 100644
--- a/operator/main.go
+++ b/operator/main.go
@@ -165,6 +165,15 @@ func main() {
                os.Exit(1)
        }
 
+       if err = (&operatorcontrollers.BanyanDBReconciler{
+               Client:   mgr.GetClient(),
+               Scheme:   mgr.GetScheme(),
+               FileRepo: manifests.NewRepo("banyandb"),
+               Recorder: mgr.GetEventRecorderFor("banyandb-controller"),
+       }).SetupWithManager(mgr); err != nil {
+               setupLog.Error(err, "unable to create controller", 
"controller", "BanyanDB")
+               os.Exit(1)
+       }
        //+kubebuilder:scaffold:builder
        if os.Getenv("ENABLE_WEBHOOKS") != "false" {
                if err = 
(&operatorv1alpha1.OAPServer{}).SetupWebhookWithManager(mgr); err != nil {
@@ -203,6 +212,10 @@ func main() {
                        setupLog.Error(err, "unable to create webhook", 
"webhook", "OAPServerDynamicConfig")
                        os.Exit(1)
                }
+               if err = 
(&operatorv1alpha1.BanyanDB{}).SetupWebhookWithManager(mgr); err != nil {
+                       setupLog.Error(err, "unable to create webhook", 
"webhook", "BanyanDB")
+                       os.Exit(1)
+               }
                // register a webhook to enable the java agent injector
                setupLog.Info("registering /mutate-v1-pod webhook")
                mgr.GetWebhookServer().Register("/mutate-v1-pod",
diff --git a/operator/pkg/operator/manifests/banyandb/templates/deployment.yaml 
b/operator/pkg/operator/manifests/banyandb/templates/deployment.yaml
new file mode 100644
index 0000000..b0662ee
--- /dev/null
+++ b/operator/pkg/operator/manifests/banyandb/templates/deployment.yaml
@@ -0,0 +1,118 @@
+# Licensed to 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. Apache Software Foundation (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.
+
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: {{ .Name }}-banyandb
+  namespace: {{ .Namespace }}
+  labels:
+    app: banyandb
+    operator.skywalking.apache.org/banyandb-name: {{ .Name }}
+    operator.skywalking.apache.org/application: banyandb
+    operator.skywalking.apache.org/component: deployment
+spec:
+  replicas: {{ .Spec.Counts }}
+  selector:
+    matchLabels:
+      app: banyandb
+      operator.skywalking.apache.org/banyandb-name: {{ .Name }}
+  template:
+    metadata:
+      labels:
+        app: banyandb
+        operator.skywalking.apache.org/banyandb-name: {{ .Name }}
+        operator.skywalking.apache.org/application: banyandb
+        operator.skywalking.apache.org/component: pod
+    spec:
+      serviceAccountName: {{ .Name }}-banyandb
+
+      {{- if .Spec.Storages }}
+      volumes:
+        {{- range $storage := .Spec.Storages }}
+        - name: {{ $storage.Name }}
+          persistentVolumeClaim:
+            claimName: {{ $storage.Name }}-banyandb
+        {{- end }}
+      {{- end}}
+      containers:
+        - name: banyandb-container
+          image: {{ .Spec.Image }}
+          imagePullPolicy: IfNotPresent
+          args:
+            {{- range $value := .Spec.Config }}
+            - {{ $value }}
+            {{- end }}
+          ports:
+            - containerPort: 17912
+              name: grpc
+            - containerPort: 17913
+              name: http
+            - containerPort: 2121
+              name: observability
+            - containerPort: 6060
+              name: pprof
+
+          {{- if .Spec.Storages }}
+          volumeMounts:
+            {{- range $storage := .Spec.Storages }}
+            - mountPath: {{ $storage.Path }}
+              name: {{ $storage.Name }}
+            {{- end }}
+          {{- end }}
+
+      {{- if .Spec.Affinity }}
+      {{- $affinity := .Spec.Affinity }}
+      affinity:
+        {{- if $affinity.NodeAffinity }}
+        nodeAffinity:
+          requiredDuringSchedulingIgnoredDuringExecution:
+            nodeSelectorTerms:
+            {{- range $requirement := 
$affinity.NodeAffinity.RequiredDuringSchedulingIgnoredDuringExecution.NodeSelectorTerms}}
+              {{- range $matchExpression := $requirement.MatchExpressions }}
+                - matchExpressions:
+                    - key: {{ $matchExpression.Key }}
+                      operator: {{ $matchExpression.Operator }}
+                      values:
+                        {{- range $v := $matchExpression.Values }}
+                        - {{ $v }}
+                        {{- end}}
+              {{- end}}
+            {{- end}}
+        {{- end}}
+
+        {{- if $affinity.PodAffinity }}
+        podAffinity:
+          requiredDuringSchedulingIgnoredDuringExecution:
+            {{- range $term := 
$affinity.PodAffinity.RequiredDuringSchedulingIgnoredDuringExecution }}
+            - topologyKey: {{ $term.TopologyKey }}
+              namespaces:
+                {{- range $ns := $term.Namespaces }}
+                - {{ $ns }}
+                {{- end }}
+              labelSelector:
+                MatchLabels:
+                {{- range $key, $value := $term.LabelSelector.MatchLabels }}
+                  {{ $key }} : {{ $value }}
+                {{- end}}
+            {{- end}}
+
+        {{- end}}
+      {{- end}}
+
+
+
diff --git 
a/operator/pkg/operator/manifests/banyandb/templates/grpc_service.yaml 
b/operator/pkg/operator/manifests/banyandb/templates/grpc_service.yaml
new file mode 100644
index 0000000..2869bf2
--- /dev/null
+++ b/operator/pkg/operator/manifests/banyandb/templates/grpc_service.yaml
@@ -0,0 +1,58 @@
+# Licensed to 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. Apache Software Foundation (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.
+
+{{- if .Spec.GRPCSvc }}
+
+{{- $svc := .Spec.GRPCSvc.Template }}
+apiVersion: v1
+kind: Service
+metadata:
+  name: {{ .Name }}-banyandb-grpc
+  namespace: {{ .Namespace }}
+  labels:
+    app: banyandb
+    operator.skywalking.apache.org/banyandb-name: {{ .Name }}
+    operator.skywalking.apache.org/application: banyandb
+    operator.skywalking.apache.org/component: service
+spec:
+  type: {{ $svc.Type }}
+  selector:
+    app: banyandb
+    operator.skywalking.apache.org/banyandb-name: {{ .Name }}
+  ports:
+    - port: 17912
+      name: grpc
+
+  {{- if $svc.ExternalIPs }}
+  externalIPs:
+    {{- range $value := $svc.ExternalIPs }}
+    - {{ $value | quote }}
+    {{- end }}
+  {{- end }}
+
+  {{- if $svc.LoadBalancerIP }}
+  loadBalancerIP: {{ $svc.LoadBalancerIP }}
+  {{- end }}
+
+  {{- if $svc.LoadBalancerSourceRanges }}
+  loadBalancerSourceRanges:
+    {{- range $value := $svc.LoadBalancerSourceRanges }}
+    - {{ $value | quote }}
+    {{- end }}
+  {{- end }}
+
+{{- end }}
diff --git 
a/operator/pkg/operator/manifests/banyandb/templates/http_service.yaml 
b/operator/pkg/operator/manifests/banyandb/templates/http_service.yaml
new file mode 100644
index 0000000..f57aadc
--- /dev/null
+++ b/operator/pkg/operator/manifests/banyandb/templates/http_service.yaml
@@ -0,0 +1,58 @@
+# Licensed to 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. Apache Software Foundation (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.
+
+{{- if .Spec.HTTPSvc}}
+
+{{- $svc := .Spec.HTTPSvc.Template }}
+apiVersion: v1
+kind: Service
+metadata:
+  name: {{ .Name }}-banyandb-http
+  namespace: {{ .Namespace }}
+  labels:
+    app: banyandb
+    operator.skywalking.apache.org/banyandb-name: {{ .Name }}
+    operator.skywalking.apache.org/application: banyandb
+    operator.skywalking.apache.org/component: service
+spec:
+  type: {{ $svc.Type }}
+  selector:
+    app: banyandb
+    operator.skywalking.apache.org/banyandb-name: {{ .Name }}
+  ports:
+    - port: 17913
+      name: http
+
+  {{- if $svc.ExternalIPs }}
+  externalIPs:
+    {{- range $value := $svc.ExternalIPs }}
+    - {{ $value | quote }}
+    {{- end }}
+  {{- end }}
+
+  {{- if $svc.LoadBalancerIP }}
+  loadBalancerIP: {{ $svc.LoadBalancerIP }}
+  {{- end }}
+
+  {{- if $svc.LoadBalancerSourceRanges }}
+  loadBalancerSourceRanges:
+    {{- range $value := $svc.LoadBalancerSourceRanges }}
+    - {{ $value | quote }}
+    {{- end }}
+  {{- end }}
+
+{{- end}}
\ No newline at end of file
diff --git a/operator/pkg/operator/manifests/banyandb/templates/ingress.yaml 
b/operator/pkg/operator/manifests/banyandb/templates/ingress.yaml
new file mode 100644
index 0000000..0d09d86
--- /dev/null
+++ b/operator/pkg/operator/manifests/banyandb/templates/ingress.yaml
@@ -0,0 +1,53 @@
+# Licensed to 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. Apache Software Foundation (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.
+
+{{- $ingress := .Spec.HTTPSvc.Ingress }}
+{{ if $ingress.Host }}
+apiVersion: networking.k8s.io/v1
+kind: Ingress
+metadata:
+  name: {{ .Name }}-banyandb
+  namespace: {{ .Namespace }}
+  labels:
+    app: ui
+    operator.skywalking.apache.org/ui-name: {{ .Name }}
+    operator.skywalking.apache.org/application: ui
+    operator.skywalking.apache.org/component: deployment
+  annotations:
+    {{- range $key, $value := $ingress.Annotations }}
+      {{ $key }}: {{ $value | quote }}
+      {{- end }}
+spec:
+  rules:
+    - host: {{ $ingress.Host }}
+      http:
+        paths:
+          - backend:
+              service:
+                name: {{ .Name }}-banyandb-http
+                port:
+                  number: 17913
+            path: /
+            pathType: Prefix
+  {{- if $ingress.IngressClassName }}
+  ingressClassName: {{ $ingress.IngressClassName }}
+  {{end}}
+  {{- if $ingress.TLS }}
+  tls:
+  {{ toYAML $ingress.TLS | indent 4 }}
+  {{end}}
+  {{end}}
\ No newline at end of file
diff --git a/operator/pkg/operator/manifests/banyandb/templates/pvc.yaml 
b/operator/pkg/operator/manifests/banyandb/templates/pvc.yaml
new file mode 100644
index 0000000..19c555c
--- /dev/null
+++ b/operator/pkg/operator/manifests/banyandb/templates/pvc.yaml
@@ -0,0 +1,64 @@
+# Licensed to 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. Apache Software Foundation (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.
+
+{{- $banyandb := .}}
+{{- range $storage := .Spec.Storages }}
+
+---
+apiVersion: v1
+kind: PersistentVolumeClaim
+metadata:
+  name: {{ $storage.Name }}-banyandb
+  namespace: {{ $banyandb.Namespace }}
+  labels:
+    app: banyandb
+    operator.skywalking.apache.org/banyandb-name: {{ .Name }}
+    operator.skywalking.apache.org/application: banyandb
+    operator.skywalking.apache.org/component: persistentVolumeClaim
+spec:
+  {{- $spec := $storage.PersistentVolumeClaimSpec }}
+
+  {{- if $spec.AccessModes }}
+  accessModes:
+    {{- range $spec.AccessModes }}
+    - {{ . }}
+    {{- end }}
+  {{- end }}
+
+  {{- if $spec.Resources }}
+  resources:
+  {{- if $spec.Resources.Requests }}
+    requests:
+      {{- if $spec.Resources.Requests.Storage }}
+      storage: {{ $spec.Resources.Requests.Storage }}
+      {{- end }}
+    {{- end }}
+  {{- end }}
+
+  {{- if $spec.VolumeName }}
+  volumeName: {{ $spec.VolumeName }}
+  {{- end }}
+
+  {{- if $spec.StorageClassName }}
+  storageClassName: {{ $spec.StorageClassName }}
+  {{- end }}
+
+  {{- if $spec.VolumeMode }}
+  volumeMode: {{ $spec.VolumeMode }}
+  {{- end }}
+
+{{- end }}
\ No newline at end of file
diff --git 
a/operator/pkg/operator/manifests/banyandb/templates/service_account.yaml 
b/operator/pkg/operator/manifests/banyandb/templates/service_account.yaml
new file mode 100644
index 0000000..078d8d9
--- /dev/null
+++ b/operator/pkg/operator/manifests/banyandb/templates/service_account.yaml
@@ -0,0 +1,27 @@
+# Licensed to 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. Apache Software Foundation (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.
+
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+  name: {{ .Name }}-banyandb
+  namespace: {{ .Namespace }}
+  labels:
+    operator.skywalking.apache.org/oap-server-name: {{ .Name }}
+    operator.skywalking.apache.org/application: banyandb
+    operator.skywalking.apache.org/component: rbac
+
diff --git a/operator/pkg/operator/manifests/repo.go 
b/operator/pkg/operator/manifests/repo.go
index a263b6f..769697f 100644
--- a/operator/pkg/operator/manifests/repo.go
+++ b/operator/pkg/operator/manifests/repo.go
@@ -28,7 +28,7 @@ import (
 
 var _ kubernetes.Repo = &AssetsRepo{}
 
-//go:embed fetcher injector oapserver satellite storage ui
+//go:embed fetcher injector oapserver satellite storage ui banyandb
 var manifests embed.FS
 
 // AssetsRepo provides templates through assets
diff --git a/test/e2e/banyandb/e2e.yaml b/test/e2e/banyandb/e2e.yaml
new file mode 100644
index 0000000..3b95616
--- /dev/null
+++ b/test/e2e/banyandb/e2e.yaml
@@ -0,0 +1,110 @@
+# 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.
+
+setup:
+  env: kind
+  file: ../kind.yaml
+  steps:
+    - name: prepare e2e.yaml
+      command: bash hack/prepare-e2e.sh
+    - name: install cert-manager
+      command: |
+        # kind k8s cluster is in $TMPDIR
+        export KUBECONFIG=$TMPDIR/e2e-k8s.config
+        kubectl apply -f 
https://github.com/cert-manager/cert-manager/releases/download/v1.8.0/cert-manager.yaml
+      wait:
+        - namespace: cert-manager
+          resource: pod
+          for: condition=Ready
+    - name: install operator
+      command: |
+        export OPERATOR_IMG=controller
+        make -C operator docker-build   
+        kind load docker-image controller
+        make -C operator install
+        make -C operator deploy
+      wait:
+        - namespace: skywalking-swck-system
+          resource: pod
+          for: condition=Ready
+    - name: label control plane for banyandb affinity test
+      command: |
+        kubectl label nodes kind-control-plane storage=banyandb
+    - name: remove taint on control plane and enable shedule
+      command: |
+        kubectl taint nodes kind-control-plane node-role.kubernetes.io/master-
+    - name: setup banyandb
+      command: |
+        kubectl apply -f test/e2e/deploy-banyandb.yaml
+    - name: setup oapserver and ui
+      command: |
+        kubectl create namespace skywalking-system
+        kubectl apply -f test/e2e/skywalking-components-with-banyandb.yaml
+      wait:
+        - namespace: default
+          resource: OAPServer/default
+          for: condition=Available
+        - namespace: skywalking-system
+          resource: UI/skywalking-system
+          for: condition=Available
+    - name: setup java agent demo
+      command: |
+        kubectl label namespace skywalking-system swck-injection=enabled
+        sed 's/oap-service/default-oap.default/' test/e2e/demo.yaml | kubectl 
create -f -
+      wait:
+        - namespace: skywalking-system
+          resource: deployment/demo
+          for: condition=Available
+  kind:
+    expose-ports:
+      - namespace: skywalking-system
+        resource: service/demo
+        port: 8085
+      - namespace: default
+        resource: service/default-oap
+        port: 12800
+      - namespace: default
+        resource: service/banyandb-test-banyandb-grpc
+        port: 17912
+      - namespace: skywalking-system
+        resource: service/skywalking-system-ui
+        port: 80
+  timeout: 20m
+
+cleanup:
+  on: always
+
+trigger:
+  action: http
+  interval: 10s
+  times: 5
+  url: http://${service_demo_host}:${service_demo_8085}/hello
+  method: GET
+
+verify:
+  # verify with retry strategy
+  retry:
+    # max retry count
+    count: 10
+    # the interval between two attempts, e.g. 10s, 1m.
+    interval: 10s
+  cases:
+    - includes:
+        - ../oapserver-cases.yaml
+        - ../ui-cases.yaml
+    
+    # verify the affinity works: banyandb is scheduled to control-plane
+    - query: kubectl get pods -l app=banyandb -o yaml | yq e 
''.items[0].spec.nodeName''
+      expected: ../verify/affinity.yaml
\ No newline at end of file
diff --git a/test/e2e/deploy-banyandb.yaml b/test/e2e/deploy-banyandb.yaml
new file mode 100644
index 0000000..81252a5
--- /dev/null
+++ b/test/e2e/deploy-banyandb.yaml
@@ -0,0 +1,66 @@
+# Licensed to 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. Apache Software Foundation (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.
+
+apiVersion: operator.skywalking.apache.org/v1alpha1
+kind: BanyanDB
+metadata:
+  name: banyandb-test
+spec:
+  version: 1.0.0
+  counts: 1
+  image: apache/skywalking-banyandb:latest
+  config:
+    - "standalone"
+    - "--measure-root-path=/data/banyandb"
+    - "--metadata-root-path=/data/banyandb"
+  storages:
+    - name: banyandb-volume
+      path: "/data/banyandb"
+      persistentVolumeClaimSpec:
+        resources:
+          requests:
+            storage: 1Gi
+        volumeMode: Filesystem
+        accessModes:
+          - ReadWriteOnce
+  affinity:
+    nodeAffinity:
+      requiredDuringSchedulingIgnoredDuringExecution:
+        nodeSelectorTerms:
+        - matchExpressions:
+          - key: storage
+            operator: In
+            values:
+            - banyandb
+
+
+---
+apiVersion: v1
+kind: PersistentVolume
+metadata:
+  name: banyandb-pv
+  labels:
+    type: local
+spec:
+  capacity:
+    storage: 1Gi
+  volumeMode: Filesystem
+  accessModes:
+    - ReadWriteOnce
+  persistentVolumeReclaimPolicy: Recycle
+  hostPath:
+    path: "/tmp/banyandb/data1"
diff --git a/test/e2e/skywalking-components-with-banyandb.yaml 
b/test/e2e/skywalking-components-with-banyandb.yaml
new file mode 100644
index 0000000..1d8ba20
--- /dev/null
+++ b/test/e2e/skywalking-components-with-banyandb.yaml
@@ -0,0 +1,50 @@
+# Licensed to 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. Apache Software Foundation (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.
+
+apiVersion: operator.skywalking.apache.org/v1alpha1
+kind: OAPServer
+metadata:
+  name: default
+spec:
+  version: 9.2.0
+  instances: 1
+  image: apache/skywalking-oap-server:9.2.0
+  service:
+    template:
+      type: ClusterIP
+  config:
+    - name: SW_STORAGE_BANYANDB_HOST
+      value: banyandb-test-banyandb-grpc.default.svc.cluster.local
+    - name: SW_STORAGE
+      value: banyandb
+---
+apiVersion: operator.skywalking.apache.org/v1alpha1
+kind: UI 
+metadata:
+  name: skywalking-system
+  namespace: skywalking-system
+spec:
+  version: 9.0.0
+  instances: 1
+  image: apache/skywalking-ui:9.0.0
+  OAPServerAddress: http://default-oap.default:12800
+  service:
+    template:
+      type: ClusterIP
+    ingress:
+      host: demo.ui.skywalking
+    
\ No newline at end of file
diff --git a/test/e2e/verify/affinity.yaml b/test/e2e/verify/affinity.yaml
new file mode 100644
index 0000000..c33ae72
--- /dev/null
+++ b/test/e2e/verify/affinity.yaml
@@ -0,0 +1,16 @@
+# 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.
+
+kind-control-plane


Reply via email to