You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@rocketmq.apache.org by vo...@apache.org on 2020/08/04 07:02:22 UTC

[rocketmq-operator] branch master updated: [ISSUE #16] [ISSUE #27] [ISSUE #32] Open Resource Limit and HostNetwork Configurations in CRD (#33)

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

vongosling pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/rocketmq-operator.git


The following commit(s) were added to refs/heads/master by this push:
     new c144f86  [ISSUE #16] [ISSUE #27] [ISSUE #32] Open Resource Limit and HostNetwork Configurations in CRD  (#33)
c144f86 is described below

commit c144f86f7de3afcd377251e3bba90b7088badc2c
Author: Rui Liu <24...@qq.com>
AuthorDate: Tue Aug 4 15:02:15 2020 +0800

    [ISSUE #16] [ISSUE #27] [ISSUE #32] Open Resource Limit and HostNetwork Configurations in CRD  (#33)
    
    * feat(nameserver): exposure hostNetwork and DNSPolicy
    
    * feat(*): exposure resource limit and adapted to yoda
    
    * recover(*): recover subPath
    
    * feat(images): use root user in nameserver and broker images and open resource limit in CRD
    
    * docs(README): change default name server hostNetwork description
    
    * fix(name server): open dnsPolicy in name server CRD
    
    * fix(name server): fix crd
    
    * fix(go.mod): fix mod
    
    * fix(images): fix rocketmq release download address
    
    * fix(images): fix docker repo
    
    Co-authored-by: liurui <li...@B-R2T6MD6M-0047.local>
---
 README.md                                          | 205 ++++++++++-----------
 create-operator.sh                                 |   2 +-
 deploy/crds/rocketmq_v1alpha1_broker_crd.yaml      |  10 +-
 deploy/crds/rocketmq_v1alpha1_nameservice_crd.yaml |  12 ++
 deploy/operator.yaml                               |   2 +-
 docs/cn/README.md                                  |   4 +-
 example/rocketmq_v1alpha1_broker_cr.yaml           |  14 +-
 .../rocketmq_v1alpha1_cluster_service.yaml         |  18 +-
 example/rocketmq_v1alpha1_nameservice_cr.yaml      |  23 ++-
 example/rocketmq_v1alpha1_rocketmq_cluster.yaml    | 104 +++++++++++
 images/broker/{ => alpine}/Dockerfile              |  24 +--
 images/broker/{ => alpine}/brokerGenConfig.sh      |   0
 images/broker/{ => alpine}/brokerStart.sh          |   0
 images/broker/{ => alpine}/build-broker-image.sh   |   2 +-
 images/broker/{ => alpine}/runbroker-customize.sh  |   0
 images/namesrv/{ => alpine}/Dockerfile             |  24 +--
 images/namesrv/{ => alpine}/build-namesrv-image.sh |   2 +-
 images/namesrv/{ => alpine}/runserver-customize.sh |   0
 images/try-images.sh                               |   4 +-
 install-operator.sh                                |   5 +-
 pkg/apis/rocketmq/v1alpha1/broker_types.go         |   8 +-
 pkg/apis/rocketmq/v1alpha1/nameservice_types.go    |   6 +
 pkg/constants/constants.go                         |   8 +-
 pkg/controller/broker/broker_controller.go         |   5 +-
 pkg/controller/broker/broker_controller_test.go    |   4 +-
 .../nameservice/nameservice_controller.go          |  27 ++-
 purge-operator.sh                                  |   3 +-
 27 files changed, 330 insertions(+), 186 deletions(-)

diff --git a/README.md b/README.md
index 5a616c2..e82c4ab 100644
--- a/README.md
+++ b/README.md
@@ -68,40 +68,34 @@ Now you can use the CRDs provide by RocketMQ Operator to deploy your RocketMQ cl
 
 Before RocketMQ deployment, you may need to do some preparation steps for RocketMQ data persistence. 
 
-Currently we provide several options for your RocketMQ data persistence: ```EmptyDir```, ```HostPath``` and ```NFS```, which can be configured in CR files, for example in ```rocketmq_v1alpha1_nameservice_cr.yaml```:
+Currently we provide several options for your RocketMQ data persistence: ```EmptyDir```, ```HostPath``` and ```StorageClass```, which can be configured in CR files, for example in ```rocketmq_v1alpha1_nameservice_cr.yaml```:
 
 ```
 ...
- # storageMode can be EmptyDir, HostPath, NFS
+ # storageMode can be EmptyDir, HostPath, StorageClass
   storageMode: HostPath
 ...
 ```
 
+#### EmptyDir
+
 If you choose ```EmptyDir```, you don't need to do extra preparation steps for data persistence. But the data storage life is the same with the pod's life, if the pod is deleted you may lost the data.
 
 If you choose other storage modes, please refer to the following instructions to prepare the data persistence.
 
-#### Prepare HostPath
-
-This storage mode means the RocketMQ data (including all the logs and store files) is stored in each host where the pod lies on. In that case you need to create an dir where you want the RocketMQ data to be stored on. 
+#### HostPath
 
-We provide a script in ```deploy/storage/hostpath/prepare-host-path.sh```, which you can use to create the ```HostPath``` dir on every worker node of your Kubernetes cluster. 
+This storage mode means the RocketMQ data (including all the logs and store files) is stored in each host where the pod lies on. You need to create a directory on the host where you want the RocketMQ data to be stored. For example:
 
 ```
-$ cd deploy/storage/hostpath
-
-$ sudo su
-
-$ ./prepare-hostpath.sh 
-Changed hostPath /data/rocketmq/nameserver uid to 3000, gid to 3000
-Changed hostPath /data/rocketmq/broker uid to 3000, gid to 3000
+$ mkdir /data/rocketmq/broker
 ```
 
-You may refer to the instructions in the script for more information.
+You can configure the host path in the CRD yaml file like ```hostPath: /data/rocketmq/broker``` in the ```example/rocketmq_v1alpha1_rocketmq_cluster.yaml``` file.
 
-#### Prepare Storage Class of NFS
+#### StorageClass (Use NFS for Example)
 
-If you choose NFS as the storage mode, the first step is to prepare a storage class based on NFS provider to create PV and PVC where the RocketMQ data will be stored. 
+If you choose StorageClass as the storage mode, you need to prepare the storage class related provisioner and other dependencies. Using the NFS storage class as an example, the first step is to prepare a storage class based on NFS provider to create PV and PVC where the RocketMQ data will be stored. 
 
 1. Deploy NFS server and clients on your Kubernetes cluster. You can refer to [NFS deployment document](docs/en/nfs_install_en.md) for more details. Please make sure they are functional before you go to the next step. Here is a instruction on how to verify NFS service.
 
@@ -163,39 +157,7 @@ rocketmq-operator-564b5d75d-jllzk         1/1     Running   0          108s
 
 RocketMQ Operator provides several CRDs to allow users define their RocketMQ service component cluster, which includes the Name Server cluster and the Broker cluster.
 
-1. Check the file ```rocketmq_v1alpha1_nameservice_cr.yaml``` in the ```example``` directory, for example:
-```
-apiVersion: rocketmq.apache.org/v1alpha1
-kind: NameService
-metadata:
-  name: name-service
-spec:
-  # size is the the name service instance number of the name service cluster
-  size: 1
-  # nameServiceImage is the customized docker image repo of the RocketMQ name service
-  nameServiceImage: apacherocketmq/rocketmq-namesrv:4.5.0-alpine
-  # imagePullPolicy is the image pull policy
-  imagePullPolicy: Always
-  # storageMode can be EmptyDir, HostPath, NFS
-  storageMode: HostPath
-  # hostPath is the local path to store data
-  hostPath: /data/rocketmq/nameserver
-  # volumeClaimTemplates defines the storageClass
-  volumeClaimTemplates:
-    - metadata:
-        name: namesrv-storage
-        annotations:
-          volume.beta.kubernetes.io/storage-class: rocketmq-storage
-      spec:
-        accessModes: [ "ReadWriteOnce" ]
-        resources:
-          requests:
-            storage: 1Gi
-```
-
-which defines the RocketMQ name service (name server) cluster scale.
-
-2. Check the file ```rocketmq_v1alpha1_broker_cr.yaml``` in the ```example``` directory, for example:
+1. Check the file ```rocketmq_v1alpha1_rocketmq_cluster.yaml``` in the ```example``` directory, for example:
 ```
 apiVersion: rocketmq.apache.org/v1alpha1
 kind: Broker
@@ -204,21 +166,29 @@ metadata:
   name: broker
 spec:
   # size is the number of the broker cluster, each broker cluster contains a master broker and [replicaPerGroup] replica brokers.
-  size: 2
+  size: 1
   # nameServers is the [ip:port] list of name service
   nameServers: ""
   # replicationMode is the broker replica sync mode, can be ASYNC or SYNC
   replicationMode: ASYNC
-  # replicaPerGroup is the number of replica broker in each group
+  # replicaPerGroup is the number of each broker cluster
   replicaPerGroup: 1
   # brokerImage is the customized docker image repo of the RocketMQ broker
   brokerImage: apacherocketmq/rocketmq-broker:4.5.0-alpine
   # imagePullPolicy is the image pull policy
   imagePullPolicy: Always
+  # resources describes the compute resource requirements and limits
+  resources:
+    requests:
+      memory: "2048Mi"
+      cpu: "250m"
+    limits:
+      memory: "4096Mi"
+      cpu: "500m"
   # allowRestart defines whether allow pod restart
   allowRestart: true
-  # storageMode can be EmptyDir, HostPath, NFS
-  storageMode: HostPath
+  # storageMode can be EmptyDir, HostPath, StorageClass
+  storageMode: EmptyDir
   # hostPath is the local path to store data
   hostPath: /data/rocketmq/broker
   # scalePodName is broker-[broker group number]-master-0
@@ -227,77 +197,109 @@ spec:
   volumeClaimTemplates:
     - metadata:
         name: broker-storage
-        annotations:
-          volume.beta.kubernetes.io/storage-class: rocketmq-storage
       spec:
-        accessModes: [ "ReadWriteOnce" ]
+        accessModes:
+          - ReadWriteOnce
+        storageClassName: rocketmq-storage
         resources:
           requests:
             storage: 8Gi
-``` 
-which defines the RocketMQ broker cluster scale, the [ip:port] list of name service and so on. By default, the nameServers is an empty string which means it is automatically obtained by the operator.
+---
+apiVersion: rocketmq.apache.org/v1alpha1
+kind: NameService
+metadata:
+  name: name-service
+spec:
+  # size is the the name service instance number of the name service cluster
+  size: 1
+  # nameServiceImage is the customized docker image repo of the RocketMQ name service
+  nameServiceImage: apacherocketmq/rocketmq-namesrv:4.5.0-alpine
+  # imagePullPolicy is the image pull policy
+  imagePullPolicy: Always
+  # hostNetwork can be true or false
+  hostNetwork: true
+  #  Set DNS policy for the pod.
+  #  Defaults to "ClusterFirst".
+  #  Valid values are 'ClusterFirstWithHostNet', 'ClusterFirst', 'Default' or 'None'.
+  #  DNS parameters given in DNSConfig will be merged with the policy selected with DNSPolicy.
+  #  To have DNS options set along with hostNetwork, you have to specify DNS policy
+  #  explicitly to 'ClusterFirstWithHostNet'.
+  dnsPolicy: ClusterFirstWithHostNet
+  # resources describes the compute resource requirements and limits
+  resources:
+    requests:
+      memory: "512Mi"
+      cpu: "250m"
+    limits:
+      memory: "1024Mi"
+      cpu: "500m"
+  # storageMode can be EmptyDir, HostPath, StorageClass
+  storageMode: EmptyDir
+  # hostPath is the local path to store data
+  hostPath: /data/rocketmq/nameserver
+  # volumeClaimTemplates defines the storageClass
+  volumeClaimTemplates:
+    - metadata:
+        name: namesrv-storage
+      spec:
+        accessModes:
+          - ReadWriteOnce
+        storageClassName: rocketmq-storage
+        resources:
+          requests:
+            storage: 1Gi
+```
+
+which defines the RocketMQ name server cluster and the broker cluster scale, the [ip:port] list of name service and so on. By default, the nameServers is an empty string which means it is automatically obtained by the operator.
 
 ### Create RocketMQ Cluster
 
 1. Deploy the RocketMQ name service cluster by running:
 
 ``` 
-$ kubectl apply -f example/rocketmq_v1alpha1_nameservice_cr.yaml 
+$ kubectl apply -f example/rocketmq_v1alpha1_rocketmq_cluster.yaml
+broker.rocketmq.apache.org/broker created
 nameservice.rocketmq.apache.org/name-service created
 ```
 
+The name server cluster will be created first, after all name server cluster is in running state, the operator will create the broker cluster.
+
 Check the status:
 
 ```
 $ kubectl get pods -owide
-NAME                                      READY   STATUS    RESTARTS   AGE     IP               NODE        NOMINATED NODE   READINESS GATES
-name-service-0                            1/1     Running   0          3m18s   192.168.130.33   k2data-13   <none>           <none>
-nfs-client-provisioner-7cf858f754-7vxmm   1/1     Running   0          150m    10.244.2.114     k2data-14   <none>           <none>
-rocketmq-operator-564b5d75d-jllzk         1/1     Running   0          5m53s   10.244.2.116     k2data-14   <none>           <none>
+NAME                                 READY   STATUS    RESTARTS   AGE     IP             NODE             NOMINATED NODE   READINESS GATES
+broker-0-master-0                    1/1     Running   0          27s     10.1.2.27      docker-desktop   <none>           <none>
+broker-0-replica-1-0                 1/1     Running   0          27s     10.1.2.28      docker-desktop   <none>           <none>
+name-service-0                       1/1     Running   0          27s     192.168.65.3   docker-desktop   <none>           <none>
+rocketmq-operator-76b4b9f4db-x52mz   1/1     Running   0          3h25m   10.1.2.17      docker-desktop   <none>           <none>
 ```
 
-We can see We can see that there are 1 name service Pod running on 1 node.
-
-2. Deploy the RocketMQ broker clusters by running:
-```
-$ kubectl apply -f example/rocketmq_v1alpha1_broker_cr.yaml
-broker.rocketmq.apache.org/broker created 
-```
+Using the default yaml, we can see that there are 2 name server Pods and 1 master broker 1 replica(slave) broker running on the k8s cluster.
 
-After a while the Broker Containers will be created, the Kubernetes clusters status should be like:
+2. By default, the name server cluster is using host network ip(because ```hostNetwork: true```). If you set ```hostNetwork: true```, and need tp exposure the name server cluster to the outside, you can use the Service:
 
-``` 
-$ kubectl get pods -owide
-NAME                                      READY   STATUS    RESTARTS   AGE     IP               NODE        NOMINATED NODE   READINESS GATES
-broker-0-master-0                         1/1     Running   0          38s     10.244.4.18      k2data-11   <none>           <none>
-broker-0-replica-1-0                      1/1     Running   0          38s     10.244.1.128     k2data-13   <none>           <none>
-broker-1-master-0                         1/1     Running   0          38s     10.244.2.117     k2data-14   <none>           <none>
-broker-1-replica-1-0                      1/1     Running   0          38s     10.244.3.17      k2data-15   <none>           <none>
-name-service-0                            1/1     Running   0          6m7s    192.168.130.33   k2data-13   <none>           <none>
-nfs-client-provisioner-7cf858f754-7vxmm   1/1     Running   0          153m    10.244.2.114     k2data-14   <none>           <none>
-rocketmq-operator-564b5d75d-jllzk         1/1     Running   0          8m42s   10.244.2.116     k2data-14   <none>           <none>
+```
+$ kubectl apply -f example/rocketmq_cluster_service.yaml
+service/rocketmq-service created
 ```
 
-3. Check the PV and PVC status:
+3. If you are using storage class, check the PV and PVC status:
 ```
 $ kubectl get pvc
 NAME                                    STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS       AGE
 broker-storage-broker-0-master-0        Bound    pvc-7a74871b-c005-441a-bb15-8106566c9d19   8Gi        RWO            rocketmq-storage   78s
 broker-storage-broker-0-replica-1-0     Bound    pvc-521e7e9a-3795-487a-9f76-22da74db74dd   8Gi        RWO            rocketmq-storage   78s
-broker-storage-broker-1-master-0        Bound    pvc-d7b76efe-384c-4f8d-9e8a-ebe209ba826c   8Gi        RWO            rocketmq-storage   78s
-broker-storage-broker-1-replica-1-0     Bound    pvc-af266db9-83a9-4929-a2fe-e40fb5fdbfa4   8Gi        RWO            rocketmq-storage   78s
 namesrv-storage-name-service-0          Bound    pvc-c708cb49-aa52-4992-8cac-f46a48e2cc2e   1Gi        RWO            rocketmq-storage   79s
 
 $ kubectl get pv
 NAME                                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM                                       STORAGECLASS       REASON   AGE
 pvc-521e7e9a-3795-487a-9f76-22da74db74dd   8Gi        RWO            Delete           Bound    default/broker-storage-broker-0-replica-1-0 rocketmq-storage            79s
 pvc-7a74871b-c005-441a-bb15-8106566c9d19   8Gi        RWO            Delete           Bound    default/broker-storage-broker-0-master-0    rocketmq-storage            79s
-pvc-af266db9-83a9-4929-a2fe-e40fb5fdbfa4   8Gi        RWO            Delete           Bound    default/broker-storage-broker-1-replica-1-0 rocketmq-storage            78s
-pvc-c708cb49-aa52-4992-8cac-f46a48e2cc2e   1Gi        RWO            Delete           Bound    default/namesrv-storage-name-service-0      rocketmq-storage            79s
 pvc-d7b76efe-384c-4f8d-9e8a-ebe209ba826c   8Gi        RWO            Delete           Bound    default/broker-storage-broker-1-master-0    rocketmq-storage            78s
 ```
 
-> Notice: if you don't choose the NFS storage mode, then the above PV and PVC won't be created.
+> Notice: if you don't choose the StorageClass storage mode, then the above PV and PVC won't be created.
 
 Congratulations! You have successfully deployed your RocketMQ cluster by RocketMQ Operator.
 
@@ -322,14 +324,14 @@ Access the NFS server node of your cluster and verify whether the RocketMQ data
 $ cd /data/k8s/
 
 $ ls
-default-broker-storage-broker-0-master-0-pvc-7a74871b-c005-441a-bb15-8106566c9d19   default-broker-storage-broker-1-replica-1-0-pvc-af266db9-83a9-4929-a2fe-e40fb5fdbfa4
-default-broker-storage-broker-0-replica-1-0-pvc-521e7e9a-3795-487a-9f76-22da74db74dd  default-namesrv-storage-name-service-0-pvc-c708cb49-aa52-4992-8cac-f46a48e2cc2e
-default-broker-storage-broker-1-master-0-pvc-d7b76efe-384c-4f8d-9e8a-ebe209ba826c
+default-broker-storage-broker-0-master-0-pvc-7a74871b-c005-441a-bb15-8106566c9d19   
+default-broker-storage-broker-0-replica-1-0-pvc-521e7e9a-3795-487a-9f76-22da74db74dd  
+default-namesrv-storage-name-service-0-pvc-c708cb49-aa52-4992-8cac-f46a48e2cc2e
 
-$ ls default-broker-storage-broker-1-master-0-pvc-d7b76efe-384c-4f8d-9e8a-ebe209ba826c/logs/rocketmqlogs/
+$ ls default-broker-storage-broker-0-master-0-pvc-7a74871b-c005-441a-bb15-8106566c9d19/logs/rocketmqlogs/
 broker_default.log  broker.log  commercial.log  filter.log  lock.log  protection.log  remoting.log  stats.log  storeerror.log  store.log  transaction.log  watermark.log
 
-$ cat default-broker-storage-broker-1-master-0-pvc-d7b76efe-384c-4f8d-9e8a-ebe209ba826c/logs/rocketmqlogs/broker.log 
+$ cat default-broker-storage-broker-0-master-0-pvc-7a74871b-c005-441a-bb15-8106566c9d19/logs/rocketmqlogs/broker.log 
 ...
 2019-09-10 14:12:22 INFO main - The broker[broker-1-master-0, 10.244.2.117:10911] boot success. serializeType=JSON and name server is 192.168.130.33:9876
 ...
@@ -369,7 +371,7 @@ It is often the case that with the development of your business, the old broker
 
 3. Apply the new configurations:
 ```
-kubectl apply -f example/rocketmq_v1alpha1_broker_cr.yaml
+$ kubectl apply -f example/rocketmq_v1alpha1_broker_cr.yaml
 ```
 Then a new broker group of pods will be deployed and meanwhile the operator will copy the metadata from the source broker pod to the newly created broker pods before the new brokers are stared, so the new brokers will reload previous topic and subscription information.
 
@@ -431,16 +433,11 @@ $ sh bin/mqadmin consumerprogress -g [consumer-group] -n [name-server-ip]:9876
 
 ## Clean the Environment
 
-If you want to tear down the RocketMQ cluster, to remove the broker clusters run
-
-```
-$ kubectl delete -f example/rocketmq_v1alpha1_broker_cr.yaml
-```
-
-to remove the name service clusters:
+If you want to tear down the RocketMQ cluster, to remove the name server and broker clusters run
 
 ```
-$ kubectl delete -f example/rocketmq_v1alpha1_nameservice_cr.yaml
+$ kubectl delete -f example/rocketmq_v1alpha1_rocketmq_cluster.yaml
+$ kubectl delete -f example/rocketmq_cluster_service.yaml
 ```
 
 to remove the RocketMQ Operator:
@@ -456,7 +453,7 @@ $ cd deploy/storage
 $ ./remove-storage-class.sh
 ```
 
-> Note: the NFS and HostPath persistence data will not be deleted by default.
+> Note: the StorageClass and HostPath persistence data will not be deleted by default.
 
 ## Development
 
@@ -491,12 +488,12 @@ RocketMQ-Operator is based on customized images of ```Broker``` and ```Name Serv
 You can also modify the ```DOCKERHUB_REPO``` variable in the scripts to push the newly build images to your own repository:
 
 ```
-$ cd images/broker
+$ cd images/alpine/broker
 $ ./build-broker-image.sh
 ```
 
 ```
-$ cd images/namesrv
+$ cd images/alpine/namesrv
 $ ./build-namesrv-image.sh
 ```
 
diff --git a/create-operator.sh b/create-operator.sh
index b589ad4..8a21106 100755
--- a/create-operator.sh
+++ b/create-operator.sh
@@ -18,7 +18,7 @@
 set -eux;
 
 # You can change the DOCKERHUB_REPO to your docker repo for development purpose
-DOCKERHUB_REPO="apacherocketmq/rocketmq-operator:0.2.1"
+DOCKERHUB_REPO="apacherocketmq/rocketmq-operator:0.2.1-snapshot"
 # The version of RocketMQ including the Admin Tool
 ROCKETMQ_VERSION="4.5.0"
 
diff --git a/deploy/crds/rocketmq_v1alpha1_broker_crd.yaml b/deploy/crds/rocketmq_v1alpha1_broker_crd.yaml
index 01ec2d6..a85bbf4 100644
--- a/deploy/crds/rocketmq_v1alpha1_broker_crd.yaml
+++ b/deploy/crds/rocketmq_v1alpha1_broker_crd.yaml
@@ -33,13 +33,13 @@ spec:
               description: AllowRestart defines whether allow pod restart
               type: boolean
             brokerImage:
-              description: BaseImage is the broker image to use for the Pods.
+              description: BaseImage is the broker image to use for the Pods
               type: string
             hostPath:
               description: HostPath is the local path to store data
               type: string
             imagePullPolicy:
-              description: ImagePullPolicy defines how the image is pulled.
+              description: ImagePullPolicy defines how the image is pulled
               type: string
             nameServers:
               description: NameServers defines the name service list e.g. 192.168.1.1:9876;192.168.1.2:9876
@@ -51,6 +51,9 @@ spec:
             replicationMode:
               description: ReplicationMode is SYNC or ASYNC
               type: string
+            resources:
+              description: Resources describes the compute resource requirements
+              type: object
             scalePodName:
               description: The name of pod where the metadata from
               type: string
@@ -62,7 +65,7 @@ spec:
               format: int64
               type: integer
             storageMode:
-              description: StorageMode can be EmptyDir, HostPath, NFS
+              description: StorageMode can be EmptyDir, HostPath, StorageClass
               type: string
             volumeClaimTemplates:
               description: VolumeClaimTemplates defines the StorageClass
@@ -75,6 +78,7 @@ spec:
           - brokerImage
           - imagePullPolicy
           - allowRestart
+          - resources
           - storageMode
           - hostPath
           - volumeClaimTemplates
diff --git a/deploy/crds/rocketmq_v1alpha1_nameservice_crd.yaml b/deploy/crds/rocketmq_v1alpha1_nameservice_crd.yaml
index 10a82c1..437ce04 100644
--- a/deploy/crds/rocketmq_v1alpha1_nameservice_crd.yaml
+++ b/deploy/crds/rocketmq_v1alpha1_nameservice_crd.yaml
@@ -29,6 +29,12 @@ spec:
           type: object
         spec:
           properties:
+            dnsPolicy:
+              description: dnsPolicy defines how a pod's DNS will be configured
+              type: string
+            hostNetwork:
+              description: HostNetwork can be true or false
+              type: boolean
             hostPath:
               description: HostPath is the local path to store data
               type: string
@@ -38,6 +44,9 @@ spec:
             nameServiceImage:
               description: NameServiceImage is the name service image
               type: string
+            resources:
+              description: Resources describes the compute resource requirements
+              type: object
             size:
               description: 'INSERT ADDITIONAL SPEC FIELDS - desired state of cluster
                 Important: Run "operator-sdk generate k8s" to regenerate code after
@@ -58,6 +67,9 @@ spec:
           - size
           - nameServiceImage
           - imagePullPolicy
+          - hostNetwork
+          - dnsPolicy
+          - resources
           - storageMode
           - hostPath
           - volumeClaimTemplates
diff --git a/deploy/operator.yaml b/deploy/operator.yaml
index c096ad3..2f62851 100644
--- a/deploy/operator.yaml
+++ b/deploy/operator.yaml
@@ -31,7 +31,7 @@ spec:
       containers:
         - name: rocketmq-operator
           # Replace this with the built image name
-          image: apacherocketmq/rocketmq-operator:0.2.1
+          image: apacherocketmq/rocketmq-operator:0.2.1-snapshot
           command:
           - rocketmq-operator
           imagePullPolicy: Always
diff --git a/docs/cn/README.md b/docs/cn/README.md
index eee417b..2444f18 100644
--- a/docs/cn/README.md
+++ b/docs/cn/README.md
@@ -167,7 +167,7 @@ spec:
   # size is the the name service instance number of the name service cluster
   size: 1
   # nameServiceImage is the customized docker image repo of the RocketMQ name service
-  nameServiceImage: rocketmqinc/rocketmq-namesrv:4.5.0-alpine
+  nameServiceImage: apacherocketmq/rocketmq-namesrv:4.5.0-alpine
   # imagePullPolicy is the image pull policy
   imagePullPolicy: Always
   # storageMode can be EmptyDir, HostPath, NFS
@@ -205,7 +205,7 @@ spec:
   # replicaPerGroup is the number of replica broker in each group
   replicaPerGroup: 1
   # brokerImage is the customized docker image repo of the RocketMQ broker
-  brokerImage: rocketmqinc/rocketmq-broker:4.5.0-alpine
+  brokerImage: apacherocketmq/rocketmq-broker:4.5.0-alpine
   # imagePullPolicy is the image pull policy
   imagePullPolicy: Always
   # allowRestart defines whether allow pod restart
diff --git a/example/rocketmq_v1alpha1_broker_cr.yaml b/example/rocketmq_v1alpha1_broker_cr.yaml
index 44b37a7..1de157e 100644
--- a/example/rocketmq_v1alpha1_broker_cr.yaml
+++ b/example/rocketmq_v1alpha1_broker_cr.yaml
@@ -28,13 +28,21 @@ spec:
   # replicaPerGroup is the number of each broker cluster
   replicaPerGroup: 1
   # brokerImage is the customized docker image repo of the RocketMQ broker
-  brokerImage: rocketmqinc/rocketmq-broker:4.5.0-alpine
+  brokerImage: apacherocketmq/rocketmq-broker:4.5.0-alpine
   # imagePullPolicy is the image pull policy
   imagePullPolicy: Always
+  # resources describes the compute resource requirements and limits
+  resources:
+    requests:
+      memory: "2048Mi"
+      cpu: "250m"
+    limits:
+      memory: "4096Mi"
+      cpu: "500m"
   # allowRestart defines whether allow pod restart
   allowRestart: true
-  # storageMode can be EmptyDir, HostPath, NFS
-  storageMode: EmptyDir
+  # storageMode can be EmptyDir, HostPath, StorageClass
+  storageMode: HostPath
   # hostPath is the local path to store data
   hostPath: /data/rocketmq/broker
   # scalePodName is broker-[broker group number]-master-0
diff --git a/images/broker/brokerStart.sh b/example/rocketmq_v1alpha1_cluster_service.yaml
old mode 100755
new mode 100644
similarity index 73%
copy from images/broker/brokerStart.sh
copy to example/rocketmq_v1alpha1_cluster_service.yaml
index 188ecc9..479d3d8
--- a/images/broker/brokerStart.sh
+++ b/example/rocketmq_v1alpha1_cluster_service.yaml
@@ -1,5 +1,3 @@
-#!/bin/bash
-
 # 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.
@@ -15,5 +13,17 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-./brokerGenConfig.sh
-./mqbroker -n $NAMESRV_ADDR -c $ROCKETMQ_HOME/conf/broker.conf
\ No newline at end of file
+apiVersion: v1
+kind: Service
+metadata:
+  name: rocketmq-service
+  namespace: default
+spec:
+  type: NodePort
+  selector:
+    name_service_cr: name-service
+  ports:
+    - port: 9876
+      targetPort: 9876
+      # use this port to access the name server cluster
+      nodePort: 30080
diff --git a/example/rocketmq_v1alpha1_nameservice_cr.yaml b/example/rocketmq_v1alpha1_nameservice_cr.yaml
index 75c4a65..4c2c178 100644
--- a/example/rocketmq_v1alpha1_nameservice_cr.yaml
+++ b/example/rocketmq_v1alpha1_nameservice_cr.yaml
@@ -21,11 +21,28 @@ spec:
   # size is the the name service instance number of the name service cluster
   size: 1
   # nameServiceImage is the customized docker image repo of the RocketMQ name service
-  nameServiceImage: rocketmqinc/rocketmq-namesrv:4.5.0-alpine
+  nameServiceImage: apacherocketmq/rocketmq-namesrv:4.5.0-alpine
   # imagePullPolicy is the image pull policy
   imagePullPolicy: Always
-  # storageMode can be EmptyDir, HostPath, NFS
-  storageMode: EmptyDir
+  # hostNetwork can be true or false
+  hostNetwork: true
+  #  Set DNS policy for the pod.
+  #  Defaults to "ClusterFirst".
+  #  Valid values are 'ClusterFirstWithHostNet', 'ClusterFirst', 'Default' or 'None'.
+  #  DNS parameters given in DNSConfig will be merged with the policy selected with DNSPolicy.
+  #  To have DNS options set along with hostNetwork, you have to specify DNS policy
+  #  explicitly to 'ClusterFirstWithHostNet'.
+  dnsPolicy: ClusterFirstWithHostNet
+  # resources describes the compute resource requirements and limits
+  resources:
+    requests:
+      memory: "512Mi"
+      cpu: "250m"
+    limits:
+      memory: "1024Mi"
+      cpu: "500m"
+  # storageMode can be EmptyDir, HostPath, StorageClass
+  storageMode: HostPath
   # hostPath is the local path to store data
   hostPath: /data/rocketmq/nameserver
   # volumeClaimTemplates defines the storageClass
diff --git a/example/rocketmq_v1alpha1_rocketmq_cluster.yaml b/example/rocketmq_v1alpha1_rocketmq_cluster.yaml
new file mode 100644
index 0000000..f385832
--- /dev/null
+++ b/example/rocketmq_v1alpha1_rocketmq_cluster.yaml
@@ -0,0 +1,104 @@
+# 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.
+
+apiVersion: rocketmq.apache.org/v1alpha1
+kind: Broker
+metadata:
+  # name of broker cluster
+  name: broker
+spec:
+  # size is the number of the broker cluster, each broker cluster contains a master broker and [replicaPerGroup] replica brokers.
+  size: 1
+  # nameServers is the [ip:port] list of name service
+  nameServers: ""
+  # replicationMode is the broker replica sync mode, can be ASYNC or SYNC
+  replicationMode: ASYNC
+  # replicaPerGroup is the number of each broker cluster
+  replicaPerGroup: 1
+  # brokerImage is the customized docker image repo of the RocketMQ broker
+  brokerImage: apacherocketmq/rocketmq-broker:4.5.0-alpine
+  # imagePullPolicy is the image pull policy
+  imagePullPolicy: Always
+  # resources describes the compute resource requirements and limits
+  resources:
+    requests:
+      memory: "2048Mi"
+      cpu: "250m"
+    limits:
+      memory: "4096Mi"
+      cpu: "500m"
+  # allowRestart defines whether allow pod restart
+  allowRestart: true
+  # storageMode can be EmptyDir, HostPath, StorageClass
+  storageMode: EmptyDir
+  # hostPath is the local path to store data
+  hostPath: /data/rocketmq/broker
+  # scalePodName is broker-[broker group number]-master-0
+  scalePodName: broker-0-master-0
+  # volumeClaimTemplates defines the storageClass
+  volumeClaimTemplates:
+    - metadata:
+        name: broker-storage
+      spec:
+        accessModes:
+          - ReadWriteOnce
+        storageClassName: rocketmq-storage
+        resources:
+          requests:
+            storage: 8Gi
+---
+apiVersion: rocketmq.apache.org/v1alpha1
+kind: NameService
+metadata:
+  name: name-service
+spec:
+  # size is the the name service instance number of the name service cluster
+  size: 1
+  # nameServiceImage is the customized docker image repo of the RocketMQ name service
+  nameServiceImage: apacherocketmq/rocketmq-namesrv:4.5.0-alpine
+  # imagePullPolicy is the image pull policy
+  imagePullPolicy: Always
+  # hostNetwork can be true or false
+  hostNetwork: true
+  #  Set DNS policy for the pod.
+  #  Defaults to "ClusterFirst".
+  #  Valid values are 'ClusterFirstWithHostNet', 'ClusterFirst', 'Default' or 'None'.
+  #  DNS parameters given in DNSConfig will be merged with the policy selected with DNSPolicy.
+  #  To have DNS options set along with hostNetwork, you have to specify DNS policy
+  #  explicitly to 'ClusterFirstWithHostNet'.
+  dnsPolicy: ClusterFirstWithHostNet
+  # resources describes the compute resource requirements and limits
+  resources:
+    requests:
+      memory: "512Mi"
+      cpu: "250m"
+    limits:
+      memory: "1024Mi"
+      cpu: "500m"
+  # storageMode can be EmptyDir, HostPath, StorageClass
+  storageMode: EmptyDir
+  # hostPath is the local path to store data
+  hostPath: /data/rocketmq/nameserver
+  # volumeClaimTemplates defines the storageClass
+  volumeClaimTemplates:
+    - metadata:
+        name: namesrv-storage
+      spec:
+        accessModes:
+          - ReadWriteOnce
+        storageClassName: rocketmq-storage
+        resources:
+          requests:
+            storage: 1Gi
diff --git a/images/broker/Dockerfile b/images/broker/alpine/Dockerfile
similarity index 72%
rename from images/broker/Dockerfile
rename to images/broker/alpine/Dockerfile
index 0105df3..f25716f 100644
--- a/images/broker/Dockerfile
+++ b/images/broker/alpine/Dockerfile
@@ -19,32 +19,21 @@ FROM openjdk:8-alpine
 
 RUN apk add --no-cache bash gettext nmap-ncat openssl busybox-extras
 
-ARG user=rocketmq
-ARG group=rocketmq
-ARG uid=3000
-ARG gid=3000
-
-# RocketMQ is run with user `rocketmq`, uid = 1001
-# If you bind mount a volume from the host or a data container,
-# ensure you use the same uid
-RUN addgroup --gid ${gid} ${group} \
-    && adduser --uid ${uid} -G ${group} ${user} -s /bin/bash -D
-
 ARG version
 
 # Rocketmq version
 ENV ROCKETMQ_VERSION ${version}
 
 # Rocketmq home
-ENV ROCKETMQ_HOME  /home/rocketmq/rocketmq-${ROCKETMQ_VERSION}
+ENV ROCKETMQ_HOME  /root/rocketmq-${ROCKETMQ_VERSION}
 
 WORKDIR  ${ROCKETMQ_HOME}
 
 # Install
 RUN set -eux; \
     apk add --virtual .build-deps curl gnupg unzip; \
-    curl https://dist.apache.org/repos/dist/release/rocketmq/${ROCKETMQ_VERSION}/rocketmq-all-${ROCKETMQ_VERSION}-bin-release.zip -o rocketmq.zip; \
-    curl https://dist.apache.org/repos/dist/release/rocketmq/${ROCKETMQ_VERSION}/rocketmq-all-${ROCKETMQ_VERSION}-bin-release.zip.asc -o rocketmq.zip.asc; \
+    curl https://archive.apache.org/dist/rocketmq/${ROCKETMQ_VERSION}/rocketmq-all-${ROCKETMQ_VERSION}-bin-release.zip -o rocketmq.zip; \
+    curl https://archive.apache.org/dist/rocketmq/${ROCKETMQ_VERSION}/rocketmq-all-${ROCKETMQ_VERSION}-bin-release.zip.asc -o rocketmq.zip.asc; \
     #https://www.apache.org/dist/rocketmq/KEYS
 	curl https://www.apache.org/dist/rocketmq/KEYS -o KEYS; \
 	\
@@ -53,7 +42,8 @@ RUN set -eux; \
     unzip rocketmq.zip; \
 	mv rocketmq-all*/* . ; \
 	rmdir rocketmq-all* ; \
-	rm rocketmq.zip rocketmq.zip.asc KEYS; \
+	rm rocketmq.zip ; \
+	rm rocketmq.zip.asc KEYS; \
 	apk del .build-deps ; \
     rm -rf /var/cache/apk/* ; \
     rm -rf /tmp/*
@@ -61,8 +51,6 @@ RUN set -eux; \
 # Copy customized scripts
 COPY runbroker-customize.sh ${ROCKETMQ_HOME}/bin/
 
-RUN chown -R ${uid}:${gid} ${ROCKETMQ_HOME}
-
 # Expose broker ports
 EXPOSE 10909 10911 10912
 
@@ -82,8 +70,6 @@ COPY brokerGenConfig.sh brokerStart.sh ${ROCKETMQ_HOME}/bin/
 RUN chmod a+x ${ROCKETMQ_HOME}/bin/brokerGenConfig.sh \
  && chmod a+x ${ROCKETMQ_HOME}/bin/brokerStart.sh
 
-USER ${user}
-
 WORKDIR ${ROCKETMQ_HOME}/bin
 
 CMD ["/bin/bash", "./brokerStart.sh"]
\ No newline at end of file
diff --git a/images/broker/brokerGenConfig.sh b/images/broker/alpine/brokerGenConfig.sh
similarity index 100%
rename from images/broker/brokerGenConfig.sh
rename to images/broker/alpine/brokerGenConfig.sh
diff --git a/images/broker/brokerStart.sh b/images/broker/alpine/brokerStart.sh
similarity index 100%
rename from images/broker/brokerStart.sh
rename to images/broker/alpine/brokerStart.sh
diff --git a/images/broker/build-broker-image.sh b/images/broker/alpine/build-broker-image.sh
similarity index 96%
rename from images/broker/build-broker-image.sh
rename to images/broker/alpine/build-broker-image.sh
index 0b6f31d..e02c1ee 100755
--- a/images/broker/build-broker-image.sh
+++ b/images/broker/alpine/build-broker-image.sh
@@ -33,7 +33,7 @@ if [ $# -lt 1 ]; then
 fi
 
 ROCKETMQ_VERSION=$1
-DOCKERHUB_REPO=rocketmqinc/rocketmq-broker
+DOCKERHUB_REPO=apacherocketmq/rocketmq-broker
 
 checkVersion $ROCKETMQ_VERSION
 
diff --git a/images/broker/runbroker-customize.sh b/images/broker/alpine/runbroker-customize.sh
similarity index 100%
rename from images/broker/runbroker-customize.sh
rename to images/broker/alpine/runbroker-customize.sh
diff --git a/images/namesrv/Dockerfile b/images/namesrv/alpine/Dockerfile
similarity index 72%
rename from images/namesrv/Dockerfile
rename to images/namesrv/alpine/Dockerfile
index e56eba2..b0303f2 100644
--- a/images/namesrv/Dockerfile
+++ b/images/namesrv/alpine/Dockerfile
@@ -19,32 +19,21 @@ FROM openjdk:8-alpine
 
 RUN apk add --no-cache bash gettext nmap-ncat openssl busybox-extras
 
-ARG user=rocketmq
-ARG group=rocketmq
-ARG uid=3000
-ARG gid=3000
-
-# RocketMQ is run with user `rocketmq`, uid = 3000
-# If you bind mount a volume from the host or a data container,
-# ensure you use the same uid
-RUN addgroup --gid ${gid} ${group} \
-    && adduser --uid ${uid} -G ${group} ${user} -s /bin/bash -D
-
 ARG version
 
 # Rocketmq version
 ENV ROCKETMQ_VERSION ${version}
 
 # Rocketmq home
-ENV ROCKETMQ_HOME  /home/rocketmq/rocketmq-${ROCKETMQ_VERSION}
+ENV ROCKETMQ_HOME  /root/rocketmq-${ROCKETMQ_VERSION}
 
 WORKDIR  ${ROCKETMQ_HOME}
 
 # Install
 RUN set -eux; \
     apk add --virtual .build-deps curl gnupg unzip; \
-    curl https://dist.apache.org/repos/dist/release/rocketmq/${ROCKETMQ_VERSION}/rocketmq-all-${ROCKETMQ_VERSION}-bin-release.zip -o rocketmq.zip; \
-    curl https://dist.apache.org/repos/dist/release/rocketmq/${ROCKETMQ_VERSION}/rocketmq-all-${ROCKETMQ_VERSION}-bin-release.zip.asc -o rocketmq.zip.asc; \
+    curl https://archive.apache.org/dist/rocketmq/${ROCKETMQ_VERSION}/rocketmq-all-${ROCKETMQ_VERSION}-bin-release.zip -o rocketmq.zip; \
+    curl https://archive.apache.org/dist/rocketmq/${ROCKETMQ_VERSION}/rocketmq-all-${ROCKETMQ_VERSION}-bin-release.zip.asc -o rocketmq.zip.asc; \
     #https://www.apache.org/dist/rocketmq/KEYS
 	curl https://www.apache.org/dist/rocketmq/KEYS -o KEYS; \
 	\
@@ -53,7 +42,8 @@ RUN set -eux; \
     unzip rocketmq.zip; \
 	mv rocketmq-all*/* . ; \
 	rmdir rocketmq-all* ; \
-	rm rocketmq.zip rocketmq.zip.asc KEYS; \
+	rm rocketmq.zip ; \
+    rm rocketmq.zip.asc KEYS; \
 	apk del .build-deps ; \
     rm -rf /var/cache/apk/* ; \
     rm -rf /tmp/*
@@ -61,8 +51,6 @@ RUN set -eux; \
 # Copy customized scripts
 COPY runserver-customize.sh ${ROCKETMQ_HOME}/bin/
 
-RUN chown -R ${uid}:${gid} ${ROCKETMQ_HOME}
-
 # Expose namesrv port
 EXPOSE 9876
 
@@ -75,8 +63,6 @@ RUN mv ${ROCKETMQ_HOME}/bin/runserver-customize.sh ${ROCKETMQ_HOME}/bin/runserve
  && export JAVA_OPT=" -Duser.home=/opt" \
  && sed -i 's/${JAVA_HOME}\/jre\/lib\/ext/${JAVA_HOME}\/jre\/lib\/ext:${JAVA_HOME}\/lib\/ext/' ${ROCKETMQ_HOME}/bin/tools.sh
 
-USER ${user}
-
 WORKDIR ${ROCKETMQ_HOME}/bin
 
 CMD ["/bin/bash", "mqnamesrv"]
diff --git a/images/namesrv/build-namesrv-image.sh b/images/namesrv/alpine/build-namesrv-image.sh
similarity index 96%
rename from images/namesrv/build-namesrv-image.sh
rename to images/namesrv/alpine/build-namesrv-image.sh
index 8934f30..36f1bf3 100755
--- a/images/namesrv/build-namesrv-image.sh
+++ b/images/namesrv/alpine/build-namesrv-image.sh
@@ -33,7 +33,7 @@ if [ $# -lt 1 ]; then
 fi
 
 ROCKETMQ_VERSION=$1
-DOCKERHUB_REPO=rocketmqinc/rocketmq-namesrv
+DOCKERHUB_REPO=apacherocketmq/rocketmq-namesrv
 
 checkVersion $ROCKETMQ_VERSION
 
diff --git a/images/namesrv/runserver-customize.sh b/images/namesrv/alpine/runserver-customize.sh
similarity index 100%
rename from images/namesrv/runserver-customize.sh
rename to images/namesrv/alpine/runserver-customize.sh
diff --git a/images/try-images.sh b/images/try-images.sh
index 9a7275a..d018436 100755
--- a/images/try-images.sh
+++ b/images/try-images.sh
@@ -15,8 +15,8 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-NAMESRV_DOCKERHUB_REPO=rocketmqinc/rocketmq-namesrv
-BROKER_DOCKERHUB_REPO=rocketmqinc/rocketmq-broker
+NAMESRV_DOCKERHUB_REPO=apacherocketmq/rocketmq-namesrv
+BROKER_DOCKERHUB_REPO=apacherocketmq/rocketmq-broker
 ROCKETMQ_VERSION=4.5.0
 
 start_namesrv_broker()
diff --git a/install-operator.sh b/install-operator.sh
index cee05a6..76318e1 100755
--- a/install-operator.sh
+++ b/install-operator.sh
@@ -23,7 +23,4 @@ kubectl create -f deploy/role.yaml
 kubectl create -f deploy/role_binding.yaml
 kubectl create -f deploy/operator.yaml
 
-echo "Wait for operator being ready..."
-sleep 2
-#kubectl create -f example/rocketmq_v1alpha1_nameservice_cr.yaml
-#kubectl create -f example/rocketmq_v1alpha1_broker_cr.yaml
+#kubectl create -f example/rocketmq_v1alpha1_rocketmq_cluster.yaml
diff --git a/pkg/apis/rocketmq/v1alpha1/broker_types.go b/pkg/apis/rocketmq/v1alpha1/broker_types.go
index fc7be5d..8eb31de 100644
--- a/pkg/apis/rocketmq/v1alpha1/broker_types.go
+++ b/pkg/apis/rocketmq/v1alpha1/broker_types.go
@@ -38,13 +38,15 @@ type BrokerSpec struct {
 	ReplicationMode string `json:"replicationMode,omitempty"`
 	// ReplicaPerGroup each broker cluster's replica number
 	ReplicaPerGroup int `json:"replicaPerGroup"`
-	// BaseImage is the broker image to use for the Pods.
+	// BaseImage is the broker image to use for the Pods
 	BrokerImage string `json:"brokerImage"`
-	// ImagePullPolicy defines how the image is pulled.
+	// ImagePullPolicy defines how the image is pulled
 	ImagePullPolicy corev1.PullPolicy `json:"imagePullPolicy"`
 	// AllowRestart defines whether allow pod restart
 	AllowRestart bool `json:"allowRestart"`
-	// StorageMode can be EmptyDir, HostPath, NFS
+	// Resources describes the compute resource requirements
+	Resources corev1.ResourceRequirements `json:"resources"`
+	// StorageMode can be EmptyDir, HostPath, StorageClass
 	StorageMode string `json:"storageMode"`
 	// HostPath is the local path to store data
 	HostPath string `json:"hostPath"`
diff --git a/pkg/apis/rocketmq/v1alpha1/nameservice_types.go b/pkg/apis/rocketmq/v1alpha1/nameservice_types.go
index 7cb1a46..cb4d4f5 100644
--- a/pkg/apis/rocketmq/v1alpha1/nameservice_types.go
+++ b/pkg/apis/rocketmq/v1alpha1/nameservice_types.go
@@ -37,6 +37,12 @@ type NameServiceSpec struct {
 	NameServiceImage string `json:"nameServiceImage"`
 	// ImagePullPolicy defines how the image is pulled.
 	ImagePullPolicy corev1.PullPolicy `json:"imagePullPolicy"`
+	// HostNetwork can be true or false
+	HostNetwork bool `json:"hostNetwork"`
+	// dnsPolicy defines how a pod's DNS will be configured
+	DNSPolicy corev1.DNSPolicy `json:"dnsPolicy"`
+	// Resources describes the compute resource requirements
+	Resources corev1.ResourceRequirements `json:"resources"`
 	// StorageMode can be EmptyDir, HostPath, NFS
 	StorageMode string `json:"storageMode"`
 	// HostPath is the local path to store data
diff --git a/pkg/constants/constants.go b/pkg/constants/constants.go
index 555147b..233e9c2 100644
--- a/pkg/constants/constants.go
+++ b/pkg/constants/constants.go
@@ -59,10 +59,10 @@ const (
 	EnvBrokerName = "BROKER_NAME"
 
 	// LogMountPath is the directory of RocketMQ log files
-	LogMountPath = "/home/rocketmq/logs"
+	LogMountPath = "/root/logs"
 
 	// StoreMountPath is the directory of RocketMQ store files
-	StoreMountPath = "/home/rocketmq/store"
+	StoreMountPath = "/root/store"
 
 	// LogSubPathName is the sub-path name of log dir under mounted host dir
 	LogSubPathName = "logs"
@@ -94,8 +94,8 @@ const (
 	// BrokerHighAvailabilityContainerPortName is the high availability port name of broker container
 	BrokerHighAvailabilityContainerPortName = "ha"
 
-	// StorageModeNFS is the name of NFS storage mode
-	StorageModeNFS = "NFS"
+	// StorageModeStorageClass is the name of StorageClass storage mode
+	StorageModeStorageClass = "StorageClass"
 
 	// StorageModeEmptyDir is the name of EmptyDir storage mode
 	StorageModeEmptyDir = "EmptyDir"
diff --git a/pkg/controller/broker/broker_controller.go b/pkg/controller/broker/broker_controller.go
index 1879d64..9055692 100644
--- a/pkg/controller/broker/broker_controller.go
+++ b/pkg/controller/broker/broker_controller.go
@@ -399,6 +399,7 @@ func (r *ReconcileBroker) getBrokerStatefulSet(broker *rocketmqv1alpha1.Broker,
 				},
 				Spec: corev1.PodSpec{
 					Containers: []corev1.Container{{
+						Resources: broker.Spec.Resources,
 						Image: broker.Spec.BrokerImage,
 						Name:  cons.BrokerContainerName,
 						Lifecycle: &corev1.Lifecycle{
@@ -460,7 +461,7 @@ func (r *ReconcileBroker) getBrokerStatefulSet(broker *rocketmqv1alpha1.Broker,
 
 func getVolumeClaimTemplates(broker *rocketmqv1alpha1.Broker) []corev1.PersistentVolumeClaim {
 	switch broker.Spec.StorageMode {
-	case cons.StorageModeNFS:
+	case cons.StorageModeStorageClass:
 		return broker.Spec.VolumeClaimTemplates
 	case cons.StorageModeEmptyDir, cons.StorageModeHostPath:
 		fallthrough
@@ -471,7 +472,7 @@ func getVolumeClaimTemplates(broker *rocketmqv1alpha1.Broker) []corev1.Persisten
 
 func getVolumes(broker *rocketmqv1alpha1.Broker) []corev1.Volume {
 	switch broker.Spec.StorageMode {
-	case cons.StorageModeNFS:
+	case cons.StorageModeStorageClass:
 		return nil
 	case cons.StorageModeEmptyDir:
 		volumes := []corev1.Volume{{
diff --git a/pkg/controller/broker/broker_controller_test.go b/pkg/controller/broker/broker_controller_test.go
index fc28059..1ea721f 100644
--- a/pkg/controller/broker/broker_controller_test.go
+++ b/pkg/controller/broker/broker_controller_test.go
@@ -46,7 +46,7 @@ func TestBrokerController(t *testing.T) {
 	var (
 		name            = "rocketmq-operator"
 		namespace       = "broker"
-		replicas  int32 = 3
+		replicas   		= 3
 	)
 
 	// A Broker resource with metadata and spec.
@@ -96,7 +96,7 @@ func TestBrokerController(t *testing.T) {
 		t.Fatalf("get deployment: (%v)", err)
 	}
 	dsize := *dep.Spec.Replicas
-	if dsize != replicas {
+	if dsize != int32(replicas) {
 		t.Errorf("dep size (%d) is not the expected size (%d)", dsize, replicas)
 	}
 
diff --git a/pkg/controller/nameservice/nameservice_controller.go b/pkg/controller/nameservice/nameservice_controller.go
index 5b93f33..410515f 100644
--- a/pkg/controller/nameservice/nameservice_controller.go
+++ b/pkg/controller/nameservice/nameservice_controller.go
@@ -190,7 +190,6 @@ func (r *ReconcileNameService) updateNameServiceStatus(instance *rocketmqv1alpha
 
 		if len(oldNameServerListStr) <= cons.MinIpListLength {
 			oldNameServerListStr = share.NameServersStr
-			share.IsNameServersStrInitialized = true
 		} else if len(share.NameServersStr) > cons.MinIpListLength {
 			oldNameServerListStr = oldNameServerListStr[:len(oldNameServerListStr)-1]
 			share.IsNameServersStrUpdated = true
@@ -232,6 +231,11 @@ func (r *ReconcileNameService) updateNameServiceStatus(instance *rocketmqv1alpha
 		reqLogger.Info("NameServers IP " + strconv.Itoa(i) + ": " + value)
 	}
 
+	runningNameServerNum := getRunningNameServersNum(podList.Items)
+	if runningNameServerNum == instance.Spec.Size {
+		share.IsNameServersStrInitialized = true
+	}
+
 	if requeue {
 		return reconcile.Result{Requeue: true, RequeueAfter: time.Duration(cons.RequeueIntervalInSecond) * time.Second}, nil
 	}
@@ -241,7 +245,7 @@ func (r *ReconcileNameService) updateNameServiceStatus(instance *rocketmqv1alpha
 
 func getVolumeClaimTemplates(nameService *rocketmqv1alpha1.NameService) []corev1.PersistentVolumeClaim {
 	switch nameService.Spec.StorageMode {
-	case cons.StorageModeNFS:
+	case cons.StorageModeStorageClass:
 		return nameService.Spec.VolumeClaimTemplates
 	case cons.StorageModeEmptyDir, cons.StorageModeHostPath:
 		fallthrough
@@ -252,7 +256,7 @@ func getVolumeClaimTemplates(nameService *rocketmqv1alpha1.NameService) []corev1
 
 func getVolumes(nameService *rocketmqv1alpha1.NameService) []corev1.Volume {
 	switch nameService.Spec.StorageMode {
-	case cons.StorageModeNFS:
+	case cons.StorageModeStorageClass:
 		return nil
 	case cons.StorageModeEmptyDir:
 		volumes := []corev1.Volume{{
@@ -278,11 +282,21 @@ func getVolumes(nameService *rocketmqv1alpha1.NameService) []corev1.Volume {
 func getNameServers(pods []corev1.Pod) []string {
 	var nameServers []string
 	for _, pod := range pods {
-		nameServers = append(nameServers, pod.Status.HostIP)
+		nameServers = append(nameServers, pod.Status.PodIP)
 	}
 	return nameServers
 }
 
+func getRunningNameServersNum(pods []corev1.Pod) int32 {
+	var num int32 = 0
+	for _, pod := range pods {
+		if reflect.DeepEqual(pod.Status.Phase, corev1.PodRunning) {
+			num++
+		}
+	}
+	return num
+}
+
 func labelsForNameService(name string) map[string]string {
 	return map[string]string{"app": "name_service", "name_service_cr": name}
 }
@@ -304,9 +318,10 @@ func (r *ReconcileNameService) statefulSetForNameService(nameService *rocketmqv1
 					Labels: ls,
 				},
 				Spec: corev1.PodSpec{
-					HostNetwork: true,
-					DNSPolicy:   "ClusterFirstWithHostNet",
+					HostNetwork: nameService.Spec.HostNetwork,
+					DNSPolicy: nameService.Spec.DNSPolicy,
 					Containers: []corev1.Container{{
+						Resources: nameService.Spec.Resources,
 						Image: nameService.Spec.NameServiceImage,
 						// Name must be lower case !
 						Name:            "name-service",
diff --git a/purge-operator.sh b/purge-operator.sh
index f49bb32..34f4a8f 100755
--- a/purge-operator.sh
+++ b/purge-operator.sh
@@ -16,8 +16,7 @@
 # limitations under the License.
 
 echo "Stopping RocketMQ-Operator..."
-#kubectl delete -f example/rocketmq_v1alpha1_broker_cr.yaml
-#kubectl delete -f example/rocketmq_v1alpha1_nameservice_cr.yaml
+#kubectl delete -f example/rocketmq_v1alpha1_rocketmq_cluster.yaml
 
 kubectl delete -f deploy/operator.yaml
 kubectl delete -f deploy/role_binding.yaml