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 2019/08/05 06:46:52 UTC

[rocketmq-docker] 02/19: CP commit a583e2c2c015bc07862831b874b5f4d356871787

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-docker.git

commit 3ecf62c404bb8aef447d185d4fc019ed0a0fdc45
Author: Kevin Wang <wi...@gmail.com>
AuthorDate: Thu May 23 19:54:30 2019 +0800

    CP commit a583e2c2c015bc07862831b874b5f4d356871787
---
 .gitignore                                         |  1 +
 image-build/Dockerfile                             | 94 ++++++++++++++++++++++
 image-build/build-image.sh                         | 14 ++++
 image-build/scripts/runbroker-customize.sh         | 84 +++++++++++++++++++
 image-build/scripts/runserver-customize.sh         | 70 ++++++++++++++++
 product/README.md                                  | 88 ++++++++++++++++++++
 product/conf/2m-2s-async/broker-a-s.properties     | 30 +++++++
 product/conf/2m-2s-async/broker-a.properties       | 29 +++++++
 product/conf/2m-2s-async/broker-b-s.properties     | 29 +++++++
 product/conf/2m-2s-async/broker-b.properties       | 29 +++++++
 product/conf/2m-2s-sync/broker-a-s.properties      | 29 +++++++
 product/conf/2m-2s-sync/broker-a.properties        | 29 +++++++
 product/conf/2m-2s-sync/broker-b-s.properties      | 29 +++++++
 product/conf/2m-2s-sync/broker-b.properties        | 29 +++++++
 product/conf/2m-noslave/broker-a.properties        | 28 +++++++
 product/conf/2m-noslave/broker-b.properties        | 29 +++++++
 product/conf/2m-noslave/broker-trace.properties    | 30 +++++++
 product/conf/broker.conf                           | 25 ++++++
 product/start-broker.sh                            | 49 +++++++++++
 product/start-ns.sh                                | 37 +++++++++
 rocketmq-docker/.gitignore                         |  1 +
 rocketmq-docker/image-build/Dockerfile             | 94 ++++++++++++++++++++++
 rocketmq-docker/image-build/build-image.sh         | 14 ++++
 .../image-build/scripts/runbroker-customize.sh     | 84 +++++++++++++++++++
 .../image-build/scripts/runserver-customize.sh     | 70 ++++++++++++++++
 rocketmq-docker/product/README.md                  | 88 ++++++++++++++++++++
 .../product/conf/2m-2s-async/broker-a-s.properties | 30 +++++++
 .../product/conf/2m-2s-async/broker-a.properties   | 29 +++++++
 .../product/conf/2m-2s-async/broker-b-s.properties | 29 +++++++
 .../product/conf/2m-2s-async/broker-b.properties   | 29 +++++++
 .../product/conf/2m-2s-sync/broker-a-s.properties  | 29 +++++++
 .../product/conf/2m-2s-sync/broker-a.properties    | 29 +++++++
 .../product/conf/2m-2s-sync/broker-b-s.properties  | 29 +++++++
 .../product/conf/2m-2s-sync/broker-b.properties    | 29 +++++++
 .../product/conf/2m-noslave/broker-a.properties    | 28 +++++++
 .../product/conf/2m-noslave/broker-b.properties    | 29 +++++++
 .../conf/2m-noslave/broker-trace.properties        | 30 +++++++
 rocketmq-docker/product/conf/broker.conf           | 25 ++++++
 rocketmq-docker/product/start-broker.sh            | 49 +++++++++++
 rocketmq-docker/product/start-ns.sh                | 37 +++++++++
 rocketmq-docker/stage.sh                           | 58 +++++++++++++
 .../templates/data/broker/conf/broker.conf         |  8 ++
 .../templates/data/broker/conf/broker1.conf        |  9 +++
 .../data/broker0/conf/dledger/broker.conf          | 27 +++++++
 .../data/broker1/conf/dledger/broker.conf          | 27 +++++++
 .../data/broker2/conf/dledger/broker.conf          | 27 +++++++
 .../docker-compose/data/broker/conf/broker.conf    |  7 ++
 .../docker-compose/data1/broker/conf/broker.conf   |  7 ++
 .../templates/docker-compose/docker-compose.yml    | 46 +++++++++++
 .../templates/kubernetes/deployment.yaml           | 48 +++++++++++
 .../templates/kubernetes/deployment2.yaml          | 70 ++++++++++++++++
 rocketmq-docker/templates/play-consumer.sh         |  4 +
 rocketmq-docker/templates/play-docker-compose.sh   | 16 ++++
 rocketmq-docker/templates/play-docker-deledger.sh  | 40 +++++++++
 rocketmq-docker/templates/play-docker.sh           | 28 +++++++
 rocketmq-docker/templates/play-kubernetes.sh       |  8 ++
 rocketmq-docker/templates/play-producer.sh         |  4 +
 .../templates/scripts/runbroker-customize.sh       | 84 +++++++++++++++++++
 .../templates/scripts/runserver-customize.sh       | 70 ++++++++++++++++
 stage.sh                                           | 58 +++++++++++++
 templates/data/broker/conf/broker.conf             |  8 ++
 templates/data/broker/conf/broker1.conf            |  9 +++
 templates/data/broker0/conf/dledger/broker.conf    | 27 +++++++
 templates/data/broker1/conf/dledger/broker.conf    | 27 +++++++
 templates/data/broker2/conf/dledger/broker.conf    | 27 +++++++
 .../docker-compose/data/broker/conf/broker.conf    |  7 ++
 .../docker-compose/data1/broker/conf/broker.conf   |  7 ++
 templates/docker-compose/docker-compose.yml        | 46 +++++++++++
 templates/kubernetes/deployment.yaml               | 48 +++++++++++
 templates/kubernetes/deployment2.yaml              | 70 ++++++++++++++++
 templates/play-consumer.sh                         |  4 +
 templates/play-docker-compose.sh                   | 16 ++++
 templates/play-docker-deledger.sh                  | 40 +++++++++
 templates/play-docker.sh                           | 28 +++++++
 templates/play-kubernetes.sh                       |  8 ++
 templates/play-producer.sh                         |  4 +
 templates/scripts/runbroker-customize.sh           | 84 +++++++++++++++++++
 templates/scripts/runserver-customize.sh           | 70 ++++++++++++++++
 78 files changed, 2740 insertions(+)

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..b6889bb
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+stages/
diff --git a/image-build/Dockerfile b/image-build/Dockerfile
new file mode 100644
index 0000000..e2101e1
--- /dev/null
+++ b/image-build/Dockerfile
@@ -0,0 +1,94 @@
+#
+# 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.
+#
+
+FROM centos:7
+
+RUN yum install -y java-1.8.0-openjdk-devel.x86_64 unzip gettext nmap-ncat openssl, which gnupg, telnet \
+ && yum clean all -y
+
+# FROM openjdk:8-jdk
+# RUN apt-get update && apt-get install -y --no-install-recommends \
+#		bash libapr1 unzip telnet wget gnupg ca-certificates \
+#	&& rm -rf /var/lib/apt/lists/*
+
+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 groupadd -g ${gid} ${group} \
+    && useradd -u ${uid} -g ${gid} -m -s /bin/bash ${user}
+
+ARG version
+
+# Rocketmq version
+ENV ROCKETMQ_VERSION ${version}
+
+# Rocketmq home
+ENV ROCKETMQ_HOME  /opt/rocketmq-${ROCKETMQ_VERSION}
+
+# Java home
+ENV JAVA_HOME  /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.212.b04-0.el7_6.x86_64
+
+WORKDIR  ${ROCKETMQ_HOME}
+
+RUN set -eux; \
+    curl -s https://dist.apache.org/repos/dist/release/rocketmq/${ROCKETMQ_VERSION}/rocketmq-all-${ROCKETMQ_VERSION}-bin-release.zip -o rocketmq.zip; \
+    curl -s https://dist.apache.org/repos/dist/release/rocketmq/${ROCKETMQ_VERSION}/rocketmq-all-${ROCKETMQ_VERSION}-bin-release.zip.asc -o rocketmq.zip.asc; \
+    #https://www.apache.org/dist/rocketmq/KEYS
+	curl -s https://www.apache.org/dist/rocketmq/KEYS -o KEYS; \
+	\
+	gpg --import KEYS; \
+    gpg --batch --verify rocketmq.zip.asc rocketmq.zip ; \
+    unzip rocketmq.zip ; \
+	mv rocketmq-all*/* . ; \
+	rmdir rocketmq-all*  ; \
+	rm rocketmq.zip rocketmq.zip.asc KEYS
+
+# add scripts
+COPY scripts/ ${ROCKETMQ_HOME}/bin/
+
+RUN chown -R ${uid}:${gid} ${ROCKETMQ_HOME}/bin/
+
+# expose namesrv port
+EXPOSE 9876
+
+# add customized scripts for namesrv
+RUN mv ${ROCKETMQ_HOME}/bin/runserver-customize.sh ${ROCKETMQ_HOME}/bin/runserver.sh \
+ && chmod a+x ${ROCKETMQ_HOME}/bin/runserver.sh \
+ && chmod a+x ${ROCKETMQ_HOME}/bin/mqnamesrv
+
+# expose broker ports
+EXPOSE 10909 10911
+
+# add customized scripts for broker
+RUN mv ${ROCKETMQ_HOME}/bin/runbroker-customize.sh ${ROCKETMQ_HOME}/bin/runbroker.sh \
+ && chmod a+x ${ROCKETMQ_HOME}/bin/runbroker.sh \
+ && chmod a+x ${ROCKETMQ_HOME}/bin/mqbroker
+
+# export Java options
+RUN export JAVA_OPT=" -Duser.home=/opt"
+
+# Add ${JAVA_HOME}/lib/ext as java.ext.dirs
+RUN 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
diff --git a/image-build/build-image.sh b/image-build/build-image.sh
new file mode 100755
index 0000000..95cde95
--- /dev/null
+++ b/image-build/build-image.sh
@@ -0,0 +1,14 @@
+#!/bin/bash
+if [ $# -lt 1 ]; then
+    echo "Usage: sh $0 version#"
+    exit -1
+fi
+
+ROCKETMQ_VERSION=${1}
+if [ -z "${ROCKETMQ_VERSION}" ]
+then
+  ROCKETMQ_VERSION="4.5.0"
+fi
+
+# Build rocketmq
+docker build --no-cache -t rocketmqinc/rocketmq:${ROCKETMQ_VERSION} --build-arg version=${ROCKETMQ_VERSION} .
diff --git a/image-build/scripts/runbroker-customize.sh b/image-build/scripts/runbroker-customize.sh
new file mode 100755
index 0000000..8afa1ed
--- /dev/null
+++ b/image-build/scripts/runbroker-customize.sh
@@ -0,0 +1,84 @@
+#!/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.
+# 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.
+
+#===========================================================================================
+# Java Environment Setting
+#===========================================================================================
+error_exit ()
+{
+    echo "ERROR: $1 !!"
+    exit 1
+}
+
+[ ! -e "$JAVA_HOME/bin/java" ] && JAVA_HOME=$HOME/jdk/java
+[ ! -e "$JAVA_HOME/bin/java" ] && JAVA_HOME=/usr/java
+[ ! -e "$JAVA_HOME/bin/java" ] && error_exit "Please set the JAVA_HOME variable in your environment, We need java(x64)!"
+
+export JAVA_HOME
+export JAVA="$JAVA_HOME/bin/java"
+export BASE_DIR=$(dirname $0)/..
+export CLASSPATH=.:${BASE_DIR}/conf:${CLASSPATH}
+
+#===========================================================================================
+# JVM Configuration
+#===========================================================================================
+# Get the max heap used by a jvm, which used all the ram available to the container.
+if [ -z "$MAX_POSSIBLE_HEAP" ]
+then
+	MAX_POSSIBLE_RAM_STR=$(java -XX:+UnlockExperimentalVMOptions -XX:MaxRAMFraction=1 -XshowSettings:vm -version 2>&1 | awk '/Max\. Heap Size \(Estimated\): [0-9KMG]+/{ print $5}')
+	MAX_POSSIBLE_RAM=$MAX_POSSIBLE_RAM_STR
+	CAL_UNIT=${MAX_POSSIBLE_RAM_STR: -1}
+	if [ "$CAL_UNIT" == "G" -o "$CAL_UNIT" == "g" ]; then
+		MAX_POSSIBLE_RAM=$(echo ${MAX_POSSIBLE_RAM_STR:0:${#MAX_POSSIBLE_RAM_STR}-1} `expr 1 \* 1024 \* 1024 \* 1024` | awk '{printf "%d",$1*$2}')
+	elif [ "$CAL_UNIT" == "M" -o "$CAL_UNIT" == "m" ]; then
+		MAX_POSSIBLE_RAM=$(echo ${MAX_POSSIBLE_RAM_STR:0:${#MAX_POSSIBLE_RAM_STR}-1} `expr 1 \* 1024 \* 1024` | awk '{printf "%d",$1*$2}')
+	elif [ "$CAL_UNIT" == "K" -o "$CAL_UNIT" == "k" ]; then
+		MAX_POSSIBLE_RAM=$(echo ${MAX_POSSIBLE_RAM_STR:0:${#MAX_POSSIBLE_RAM_STR}-1} `expr 1 \* 1024` | awk '{printf "%d",$1*$2}')
+	fi
+	MAX_POSSIBLE_HEAP=$[MAX_POSSIBLE_RAM/4]
+fi
+
+# Dynamically calculate parameters, for reference.
+Xms=$MAX_POSSIBLE_HEAP
+Xmx=$MAX_POSSIBLE_HEAP
+Xmn=$[MAX_POSSIBLE_HEAP/2]
+MaxDirectMemorySize=$MAX_POSSIBLE_HEAP
+# Set for `JAVA_OPT`.
+JAVA_OPT="${JAVA_OPT} -server -Xms${Xms} -Xmx${Xmx} -Xmn${Xmn}"
+JAVA_OPT="${JAVA_OPT} -XX:+UseG1GC -XX:G1HeapRegionSize=16m -XX:G1ReservePercent=25 -XX:InitiatingHeapOccupancyPercent=30 -XX:SoftRefLRUPolicyMSPerMB=0 -XX:SurvivorRatio=8"
+JAVA_OPT="${JAVA_OPT} -verbose:gc -Xloggc:/dev/shm/mq_gc_%p.log -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCApplicationStoppedTime -XX:+PrintAdaptiveSizePolicy"
+JAVA_OPT="${JAVA_OPT} -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=5 -XX:GCLogFileSize=30m"
+JAVA_OPT="${JAVA_OPT} -XX:-OmitStackTraceInFastThrow"
+JAVA_OPT="${JAVA_OPT} -XX:+AlwaysPreTouch"
+JAVA_OPT="${JAVA_OPT} -XX:MaxDirectMemorySize=${MaxDirectMemorySize}"
+JAVA_OPT="${JAVA_OPT} -XX:-UseLargePages -XX:-UseBiasedLocking"
+JAVA_OPT="${JAVA_OPT} -Djava.ext.dirs=${JAVA_HOME}/jre/lib/ext:${BASE_DIR}/lib"
+#JAVA_OPT="${JAVA_OPT} -Xdebug -Xrunjdwp:transport=dt_socket,address=9555,server=y,suspend=n"
+JAVA_OPT="${JAVA_OPT} ${JAVA_OPT_EXT}"
+JAVA_OPT="${JAVA_OPT} -cp ${CLASSPATH}"
+
+numactl --interleave=all pwd > /dev/null 2>&1
+if [ $? -eq 0 ]
+then
+	if [ -z "$RMQ_NUMA_NODE" ] ; then
+		numactl --interleave=all $JAVA ${JAVA_OPT} $@
+	else
+		numactl --cpunodebind=$RMQ_NUMA_NODE --membind=$RMQ_NUMA_NODE $JAVA ${JAVA_OPT} $@
+	fi
+else
+	$JAVA ${JAVA_OPT} $@
+fi
diff --git a/image-build/scripts/runserver-customize.sh b/image-build/scripts/runserver-customize.sh
new file mode 100755
index 0000000..dd25b1a
--- /dev/null
+++ b/image-build/scripts/runserver-customize.sh
@@ -0,0 +1,70 @@
+#!/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.
+# 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.
+
+#===========================================================================================
+# Java Environment Setting
+#===========================================================================================
+error_exit ()
+{
+    echo "ERROR: $1 !!"
+    exit 1
+}
+
+[ ! -e "$JAVA_HOME/bin/java" ] && JAVA_HOME=$HOME/jdk/java
+[ ! -e "$JAVA_HOME/bin/java" ] && JAVA_HOME=/usr/java
+[ ! -e "$JAVA_HOME/bin/java" ] && error_exit "Please set the JAVA_HOME variable in your environment, We need java(x64)!"
+
+export JAVA_HOME
+export JAVA="$JAVA_HOME/bin/java"
+export BASE_DIR=$(dirname $0)/..
+export CLASSPATH=.:${BASE_DIR}/conf:${CLASSPATH}
+
+#===========================================================================================
+# JVM Configuration
+#===========================================================================================
+# Get the max heap used by a jvm, which used all the ram available to the container.
+if [ -z "$MAX_POSSIBLE_HEAP" ]
+then
+	MAX_POSSIBLE_RAM_STR=$(java -XX:+UnlockExperimentalVMOptions -XX:MaxRAMFraction=1 -XshowSettings:vm -version 2>&1 | awk '/Max\. Heap Size \(Estimated\): [0-9KMG]+/{ print $5}')
+	MAX_POSSIBLE_RAM=$MAX_POSSIBLE_RAM_STR
+	CAL_UNIT=${MAX_POSSIBLE_RAM_STR: -1}
+	if [ "$CAL_UNIT" == "G" -o "$CAL_UNIT" == "g" ]; then
+		MAX_POSSIBLE_RAM=$(echo ${MAX_POSSIBLE_RAM_STR:0:${#MAX_POSSIBLE_RAM_STR}-1} `expr 1 \* 1024 \* 1024 \* 1024` | awk '{printf "%d",$1*$2}')
+	elif [ "$CAL_UNIT" == "M" -o "$CAL_UNIT" == "m" ]; then
+		MAX_POSSIBLE_RAM=$(echo ${MAX_POSSIBLE_RAM_STR:0:${#MAX_POSSIBLE_RAM_STR}-1} `expr 1 \* 1024 \* 1024` | awk '{printf "%d",$1*$2}')
+	elif [ "$CAL_UNIT" == "K" -o "$CAL_UNIT" == "k" ]; then
+		MAX_POSSIBLE_RAM=$(echo ${MAX_POSSIBLE_RAM_STR:0:${#MAX_POSSIBLE_RAM_STR}-1} `expr 1 \* 1024` | awk '{printf "%d",$1*$2}')
+	fi
+	MAX_POSSIBLE_HEAP=$[MAX_POSSIBLE_RAM/4]
+fi
+
+# Dynamically calculate parameters, for reference.
+Xms=$MAX_POSSIBLE_HEAP
+Xmx=$MAX_POSSIBLE_HEAP
+Xmn=$[MAX_POSSIBLE_HEAP/2]
+# Set for `JAVA_OPT`.
+JAVA_OPT="${JAVA_OPT} -server -Xms${Xms} -Xmx${Xmx} -Xmn${Xmn}"
+JAVA_OPT="${JAVA_OPT} -XX:+UseConcMarkSweepGC -XX:+UseCMSCompactAtFullCollection -XX:CMSInitiatingOccupancyFraction=70 -XX:+CMSParallelRemarkEnabled -XX:SoftRefLRUPolicyMSPerMB=0 -XX:+CMSClassUnloadingEnabled -XX:SurvivorRatio=8  -XX:-UseParNewGC"
+JAVA_OPT="${JAVA_OPT} -verbose:gc -Xloggc:/dev/shm/rmq_srv_gc.log -XX:+PrintGCDetails"
+JAVA_OPT="${JAVA_OPT} -XX:-OmitStackTraceInFastThrow"
+JAVA_OPT="${JAVA_OPT}  -XX:-UseLargePages"
+JAVA_OPT="${JAVA_OPT} -Djava.ext.dirs=${JAVA_HOME}/jre/lib/ext:${BASE_DIR}/lib"
+#JAVA_OPT="${JAVA_OPT} -Xdebug -Xrunjdwp:transport=dt_socket,address=9555,server=y,suspend=n"
+JAVA_OPT="${JAVA_OPT} ${JAVA_OPT_EXT}"
+JAVA_OPT="${JAVA_OPT} -cp ${CLASSPATH}"
+
+$JAVA ${JAVA_OPT} $@
diff --git a/product/README.md b/product/README.md
new file mode 100644
index 0000000..446f890
--- /dev/null
+++ b/product/README.md
@@ -0,0 +1,88 @@
+# 生产级可用的RocketMQ Docker部署
+
+## 背景
+
+这是一个简单的使用说明,旨在说明如何在生产环境中使用可持久的存储和配置信息,在不同的网络节点下部署NameServer集群和主从模式的Broker集群。注意:这里只包含配置及启动容器,没有提及容器的监控和管理,容器机器的DNS配置,消息的分布和可靠性存储等细节。这一部分需要结合Kubernetes的功能实现RocketMQ-Operator相关的高级部署功能。
+
+## 部署和运行容器的步骤
+
+1. 确定要部署的宿主机(物理或虚拟机)的IP和DNS信息,宿主机的存储文件路径,确保相关的端口(9876, 10911, 10912, 10909)未被占用
+2. 准备broker启动的配置文件,根据Cluster的要求,选择参考的配置文件,并对必要属性参数进行修改
+3. 调用docker容器启动脚本,设置参数,启动容器 (从[这里](<https://hub.docker.com/apache/rocketmq>)查找RocketMQ镜像版本)
+4. 验证容器启动状态
+
+## 目录结构
+
+product /
+
+​    | -  conf / 几种典型的集群的配置 
+
+​    | - start-ns.sh 启动name-server容器的脚本,每个name-server容器调用一次该脚本
+
+​    | - start-broker.sh 启动broker容器的脚本,在不同的容器宿主机上执行该脚本,创建不同的broker集群成员
+
+   | - REAMD.md 说明文件
+
+## 一个具体的使用案例
+
+配置一个2m-2s-async的集群
+
+### 启动nameserver集群 
+
+注意:可以跳过此步骤,如果使用已经存在的nameserver集群
+
+1. 确认要部署nameserver的宿主机,确定需要映射容器持久化的目录(DATA_HOME)和RocketMQ镜像版本(ROCKETMQ_VERSION)
+
+2. 运行脚本 start-ns.sh, 例如:
+
+   ```
+   sh start-ns.sh /home/nameserver/data 4.5.0
+   ```
+
+3. 如果有多个nameserver要启动,重复上述步骤。
+
+### 启动broker集群
+
+1. 确定要连接的NameServer集群的地址
+
+2. 确认要部署broker-a master的宿主机,确定需要映射容器持久化的目录(DATA_HOME),例如,确定宿主机的DATA_HOME目录为 /home/broker/data/; 则需要把参考的conf/2m-2s-async/broker-a.properties 文件复制到 /home/broker/data/conf/2m-2s-async/broker-a.properties
+
+   修改broker-a.properties文件的brokerIP1配置为宿主机的dns-hostname(注 #3)
+
+3. 确定ROCKETMQ_VERSION, 运行脚本 start-broker.sh, 例如:
+
+   ```
+   sh start-broker.sh /home/broker/data 4.5.0 "ns1:9876;ns2:9876" conf/2m-2s-async/broker-a.properties
+   ```
+
+4. 确定broker容器正确启动 (注意: 宿主机目录DATA_HOME要对容器rocketmq用户开放读取权限)
+
+5. 确认要部署broker-a slave的宿主机,确定需要映射容器持久化的目录(DATA_HOME),例如,确定宿主机的DATA_HOME目录为 /home/broker/data/; 则需要把参考的conf/2m-2s-async/broker-a-s.properties 文件复制到 /home/broker/data/conf/2m-2s-async/broker-a-s.properties
+
+   修改broker-a.properties文件的brokerIP1配置为宿主机的dns-hostname, brokerIP2为master所在的宿主机dns-hostname
+
+6. 确定ROCKETMQ_VERSION, 运行脚本 start-broker.sh, 例如:
+
+   ```
+   sh start-broker.sh /home/broker/data 4.5.0 "ns1:9876;ns2:9876" conf/2m-2s-async/broker-a-s.properties
+   ```
+
+7. 确定broker容器正确启动 (注意: 宿主机目录DATA_HOME要对容器rocketmq用户开放读取权限)
+
+8. 重复上述步骤,创建broker-b的主从broker容器
+
+## 注意事项
+
+1. 保证宿主机存储目录的权限
+
+   由于broker容器需要在宿主机的DATA_HOME目录下要写如需要持久化的数据,如,操作日志和消息存储文件,所以要求开放DATA_HOME目录下的权限,确保broker启动和运行时能够写入相关的文件。
+
+   一个案例: 当启动broker后,一段时间时间后broker自动退出,没有任何日志写入,这个可能就是由于容器没有写入DATA_HOME/logs目录权限导致。
+
+2. 在脚本中(start-broker.sh, start-ns.sh)中声明外部映射端口
+
+   在相关的脚本中已经定义了相关的默认映射端口,如果用户有特别需求(如端口已经被其它应用占用),则需要修改shell脚本,定义新的端口映射。
+
+3. 建议使用DNS配置broker和name-server地址
+
+   运行在docker容器中的broker使用brokerIP1来指定所在的宿主机的地址,并将这个地址注册到NameServer中,以便RocketMQ客户端通过NameServer取得可以外部可用的broker地址,但是一个好的实践是使用dns-hostname,来定义相关的ip地址,这样在大规模broker进行变化或者ip地址迁移时,不会对已经部署的容器有影响。
\ No newline at end of file
diff --git a/product/conf/2m-2s-async/broker-a-s.properties b/product/conf/2m-2s-async/broker-a-s.properties
new file mode 100644
index 0000000..e5eef23
--- /dev/null
+++ b/product/conf/2m-2s-async/broker-a-s.properties
@@ -0,0 +1,30 @@
+# 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.
+brokerClusterName=DefaultCluster
+brokerName=broker-a
+brokerId=1
+deleteWhen=04
+fileReservedTime=48
+brokerRole=SLAVE
+flushDiskType=ASYNC_FLUSH
+
+
+#Slave host dns-name/ip
+brokerIP1=REPLACE_IT 
+#with Master's BroperIP1
+brokerIP2=REPLACE_IT 
+
+#with Master's haListenPort, default 10912
+#haListenPort=10912 
diff --git a/product/conf/2m-2s-async/broker-a.properties b/product/conf/2m-2s-async/broker-a.properties
new file mode 100644
index 0000000..39dc5bf
--- /dev/null
+++ b/product/conf/2m-2s-async/broker-a.properties
@@ -0,0 +1,29 @@
+# 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.
+brokerClusterName=DefaultCluster
+brokerName=broker-a
+brokerId=0
+deleteWhen=04
+fileReservedTime=48
+brokerRole=ASYNC_MASTER
+flushDiskType=ASYNC_FLUSH
+
+# Host node's dns-name or ip
+brokerIP1=REPLACE_IT
+
+# Optional config different value rather than default ports.
+# Caution: changing default ports need to update port mapping setting (-p) in start-broker.sh
+#listenPort=10911
+#haListenPort=10912
\ No newline at end of file
diff --git a/product/conf/2m-2s-async/broker-b-s.properties b/product/conf/2m-2s-async/broker-b-s.properties
new file mode 100644
index 0000000..50fb0fb
--- /dev/null
+++ b/product/conf/2m-2s-async/broker-b-s.properties
@@ -0,0 +1,29 @@
+# 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.
+brokerClusterName=DefaultCluster
+brokerName=broker-b
+brokerId=1
+deleteWhen=04
+fileReservedTime=48
+brokerRole=SLAVE
+flushDiskType=ASYNC_FLUSH
+
+#Slave host dns-name/ip
+brokerIP1=REPLACE_IT 
+#with Master's BroperIP1
+brokerIP2=REPLACE_IT 
+
+# with Master's haListenPort, default 10912
+#haListenPort=10912 
\ No newline at end of file
diff --git a/product/conf/2m-2s-async/broker-b.properties b/product/conf/2m-2s-async/broker-b.properties
new file mode 100644
index 0000000..c84cb76
--- /dev/null
+++ b/product/conf/2m-2s-async/broker-b.properties
@@ -0,0 +1,29 @@
+# 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.
+brokerClusterName=DefaultCluster
+brokerName=broker-b
+brokerId=0
+deleteWhen=04
+fileReservedTime=48
+brokerRole=ASYNC_MASTER
+flushDiskType=ASYNC_FLUSH
+
+# Host node's dns-name or ip
+brokerIP1=REPLACE_IT
+
+# Optional config different value rather than default ports.
+# Caution: changing default ports need to update port mapping setting (-p) in start-broker.sh
+#listenPort=10911
+#haListenPort=10912
\ No newline at end of file
diff --git a/product/conf/2m-2s-sync/broker-a-s.properties b/product/conf/2m-2s-sync/broker-a-s.properties
new file mode 100644
index 0000000..275f236
--- /dev/null
+++ b/product/conf/2m-2s-sync/broker-a-s.properties
@@ -0,0 +1,29 @@
+# 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.
+brokerClusterName=DefaultCluster
+brokerName=broker-a
+brokerId=1
+deleteWhen=04
+fileReservedTime=48
+brokerRole=SLAVE
+flushDiskType=ASYNC_FLUSH
+
+#Slave host dns-name/ip
+brokerIP1=REPLACE_IT 
+#with Master's BroperIP1
+brokerIP2=REPLACE_IT 
+
+#with Master's haListenPort, default 10912
+#haListenPort=10912 
\ No newline at end of file
diff --git a/product/conf/2m-2s-sync/broker-a.properties b/product/conf/2m-2s-sync/broker-a.properties
new file mode 100644
index 0000000..acdc008
--- /dev/null
+++ b/product/conf/2m-2s-sync/broker-a.properties
@@ -0,0 +1,29 @@
+# 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.
+brokerClusterName=DefaultCluster
+brokerName=broker-a
+brokerId=0
+deleteWhen=04
+fileReservedTime=48
+brokerRole=SYNC_MASTER
+flushDiskType=ASYNC_FLUSH
+
+# Host node's dns-name or ip
+brokerIP1=REPLACE_IT
+
+# Optional config different value rather than default ports.
+# Caution: changing default ports need to update port mapping setting (-p) in start-broker.sh
+#listenPort=10911
+#haListenPort=10912
\ No newline at end of file
diff --git a/product/conf/2m-2s-sync/broker-b-s.properties b/product/conf/2m-2s-sync/broker-b-s.properties
new file mode 100644
index 0000000..50fb0fb
--- /dev/null
+++ b/product/conf/2m-2s-sync/broker-b-s.properties
@@ -0,0 +1,29 @@
+# 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.
+brokerClusterName=DefaultCluster
+brokerName=broker-b
+brokerId=1
+deleteWhen=04
+fileReservedTime=48
+brokerRole=SLAVE
+flushDiskType=ASYNC_FLUSH
+
+#Slave host dns-name/ip
+brokerIP1=REPLACE_IT 
+#with Master's BroperIP1
+brokerIP2=REPLACE_IT 
+
+# with Master's haListenPort, default 10912
+#haListenPort=10912 
\ No newline at end of file
diff --git a/product/conf/2m-2s-sync/broker-b.properties b/product/conf/2m-2s-sync/broker-b.properties
new file mode 100644
index 0000000..29c4a28
--- /dev/null
+++ b/product/conf/2m-2s-sync/broker-b.properties
@@ -0,0 +1,29 @@
+# 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.
+brokerClusterName=DefaultCluster
+brokerName=broker-b
+brokerId=0
+deleteWhen=04
+fileReservedTime=48
+brokerRole=SYNC_MASTER
+flushDiskType=ASYNC_FLUSH
+
+# Host node's dns-name or ip
+brokerIP1=REPLACE_IT
+
+# Optional config different value rather than default ports.
+# Caution: changing default ports need to update port mapping setting (-p) in start-broker.sh
+#listenPort=10911
+#haListenPort=10912
\ No newline at end of file
diff --git a/product/conf/2m-noslave/broker-a.properties b/product/conf/2m-noslave/broker-a.properties
new file mode 100644
index 0000000..e1189b5
--- /dev/null
+++ b/product/conf/2m-noslave/broker-a.properties
@@ -0,0 +1,28 @@
+# 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.
+brokerClusterName=DefaultCluster
+brokerName=broker-a
+brokerId=0
+deleteWhen=04
+fileReservedTime=48
+brokerRole=ASYNC_MASTER
+flushDiskType=ASYNC_FLUSH
+
+# Host node's dns-name or ip
+brokerIP1=REPLACE_IT
+
+# Optional config different value rather than default ports.
+# Caution: changing default ports need to update port mapping setting (-p) in start-broker.sh
+#listenPort=10911
\ No newline at end of file
diff --git a/product/conf/2m-noslave/broker-b.properties b/product/conf/2m-noslave/broker-b.properties
new file mode 100644
index 0000000..c84cb76
--- /dev/null
+++ b/product/conf/2m-noslave/broker-b.properties
@@ -0,0 +1,29 @@
+# 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.
+brokerClusterName=DefaultCluster
+brokerName=broker-b
+brokerId=0
+deleteWhen=04
+fileReservedTime=48
+brokerRole=ASYNC_MASTER
+flushDiskType=ASYNC_FLUSH
+
+# Host node's dns-name or ip
+brokerIP1=REPLACE_IT
+
+# Optional config different value rather than default ports.
+# Caution: changing default ports need to update port mapping setting (-p) in start-broker.sh
+#listenPort=10911
+#haListenPort=10912
\ No newline at end of file
diff --git a/product/conf/2m-noslave/broker-trace.properties b/product/conf/2m-noslave/broker-trace.properties
new file mode 100644
index 0000000..966bb5f
--- /dev/null
+++ b/product/conf/2m-noslave/broker-trace.properties
@@ -0,0 +1,30 @@
+#
+# 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.
+#
+brokerClusterName=DefaultCluster
+brokerName=broker-trace
+brokerId=0
+deleteWhen=04
+fileReservedTime=48
+brokerRole=ASYNC_MASTER
+flushDiskType=ASYNC_FLUSH
+
+# Host node's dns-name or ip
+brokerIP1=REPLACE_IT
+
+# Optional config different value rather than default ports.
+# Caution: changing default ports need to update port mapping setting (-p) in start-broker.sh
+#listenPort=10911
\ No newline at end of file
diff --git a/product/conf/broker.conf b/product/conf/broker.conf
new file mode 100644
index 0000000..3a7676b
--- /dev/null
+++ b/product/conf/broker.conf
@@ -0,0 +1,25 @@
+# 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.
+
+brokerClusterName = DefaultCluster
+brokerName = broker-b
+brokerId = 0
+deleteWhen = 04
+fileReservedTime = 48
+brokerRole = ASYNC_MASTER
+flushDiskType = ASYNC_FLUSH
+
+# Set self-defined brokerIP address (e.g. the host node's) 
+#brokerIP1=30.25.90.82
diff --git a/product/start-broker.sh b/product/start-broker.sh
new file mode 100644
index 0000000..c7b4e93
--- /dev/null
+++ b/product/start-broker.sh
@@ -0,0 +1,49 @@
+#!/bin/sh
+
+# 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.
+
+## Main
+if [ $# -lt 4 ]; then
+    echo "Usage: sh $0 DATA_HOME ROCKETMQ_VERSION NAMESRV_ADDR CONF_FILE"
+    exit -1
+fi
+
+DATA_HOME=$1
+ROCKETMQ_VERSION=$2
+NAMESRV_ADDR=$3
+CONF_FILE=$4
+
+## Show Env Setting
+echo "ENV Setting: "
+echo "  DATA_HOME=${DATA_HOME} ROCKETMQ_VERSION=${ROCKETMQ_VERSION}"
+echo "  NAMESRV_ADDR=${NAMESRV_ADDR}"
+echo "  CONF_FILE=${CONF_FILE}" 
+
+## Check config file existing
+if [ ! -f "${DATA_HOME}/conf/${CONF_FILE}" ]; then
+    echo "You must ensure the broker config file [${DATA_HOME}/conf/${CONF_FILE}] is pre-defined!!!"
+    exit -1
+fi
+
+
+# Start Broker
+docker run -d  -v ${DATA_HOME}/logs:/home/rocketmq/logs -v ${DATA_HOME}/store:/home/rocketmq/store \
+  -v ${DATA_HOME}/conf:/home/rocketmq/conf \
+  --name rmqbroker \
+  -e "NAMESRV_ADDR=${NAMESRV_ADDR}" \
+  -p 10911:10911 -p 10912:10912 -p 10909:10909 \
+  rocketmqinc/rocketmq:${ROCKETMQ_VERSION} \
+  sh mqbroker -c /home/rocketmq/conf/${CONF_FILE}
diff --git a/product/start-ns.sh b/product/start-ns.sh
new file mode 100644
index 0000000..baa61f2
--- /dev/null
+++ b/product/start-ns.sh
@@ -0,0 +1,37 @@
+#!/bin/sh
+
+# 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.
+
+
+## Main
+if [ $# -lt 2 ]; then
+    echo "Usage: sh $0 DATA_HOME ROCKETMQ_VERSION"
+    exit -1
+fi
+
+DATA_HOME=$1
+ROCKETMQ_VERSION=$2
+
+## Show Env Setting
+echo "ENV Setting: "
+echo "DATA_HOME=${DATA_HOME} ROCKETMQ_VERSION=${ROCKETMQ_VERSION}"
+
+# Start nameserver
+docker run -d -v ${DATA_HOME}/logs:/home/rocketmq/logs \
+  --name rmqnamesrv \
+  -p 9876:9876 \
+  rocketmqinc/rocketmq:ROCKETMQ_VERSION \
+  sh mqnamesrv
\ No newline at end of file
diff --git a/rocketmq-docker/.gitignore b/rocketmq-docker/.gitignore
new file mode 100644
index 0000000..b6889bb
--- /dev/null
+++ b/rocketmq-docker/.gitignore
@@ -0,0 +1 @@
+stages/
diff --git a/rocketmq-docker/image-build/Dockerfile b/rocketmq-docker/image-build/Dockerfile
new file mode 100644
index 0000000..e2101e1
--- /dev/null
+++ b/rocketmq-docker/image-build/Dockerfile
@@ -0,0 +1,94 @@
+#
+# 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.
+#
+
+FROM centos:7
+
+RUN yum install -y java-1.8.0-openjdk-devel.x86_64 unzip gettext nmap-ncat openssl, which gnupg, telnet \
+ && yum clean all -y
+
+# FROM openjdk:8-jdk
+# RUN apt-get update && apt-get install -y --no-install-recommends \
+#		bash libapr1 unzip telnet wget gnupg ca-certificates \
+#	&& rm -rf /var/lib/apt/lists/*
+
+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 groupadd -g ${gid} ${group} \
+    && useradd -u ${uid} -g ${gid} -m -s /bin/bash ${user}
+
+ARG version
+
+# Rocketmq version
+ENV ROCKETMQ_VERSION ${version}
+
+# Rocketmq home
+ENV ROCKETMQ_HOME  /opt/rocketmq-${ROCKETMQ_VERSION}
+
+# Java home
+ENV JAVA_HOME  /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.212.b04-0.el7_6.x86_64
+
+WORKDIR  ${ROCKETMQ_HOME}
+
+RUN set -eux; \
+    curl -s https://dist.apache.org/repos/dist/release/rocketmq/${ROCKETMQ_VERSION}/rocketmq-all-${ROCKETMQ_VERSION}-bin-release.zip -o rocketmq.zip; \
+    curl -s https://dist.apache.org/repos/dist/release/rocketmq/${ROCKETMQ_VERSION}/rocketmq-all-${ROCKETMQ_VERSION}-bin-release.zip.asc -o rocketmq.zip.asc; \
+    #https://www.apache.org/dist/rocketmq/KEYS
+	curl -s https://www.apache.org/dist/rocketmq/KEYS -o KEYS; \
+	\
+	gpg --import KEYS; \
+    gpg --batch --verify rocketmq.zip.asc rocketmq.zip ; \
+    unzip rocketmq.zip ; \
+	mv rocketmq-all*/* . ; \
+	rmdir rocketmq-all*  ; \
+	rm rocketmq.zip rocketmq.zip.asc KEYS
+
+# add scripts
+COPY scripts/ ${ROCKETMQ_HOME}/bin/
+
+RUN chown -R ${uid}:${gid} ${ROCKETMQ_HOME}/bin/
+
+# expose namesrv port
+EXPOSE 9876
+
+# add customized scripts for namesrv
+RUN mv ${ROCKETMQ_HOME}/bin/runserver-customize.sh ${ROCKETMQ_HOME}/bin/runserver.sh \
+ && chmod a+x ${ROCKETMQ_HOME}/bin/runserver.sh \
+ && chmod a+x ${ROCKETMQ_HOME}/bin/mqnamesrv
+
+# expose broker ports
+EXPOSE 10909 10911
+
+# add customized scripts for broker
+RUN mv ${ROCKETMQ_HOME}/bin/runbroker-customize.sh ${ROCKETMQ_HOME}/bin/runbroker.sh \
+ && chmod a+x ${ROCKETMQ_HOME}/bin/runbroker.sh \
+ && chmod a+x ${ROCKETMQ_HOME}/bin/mqbroker
+
+# export Java options
+RUN export JAVA_OPT=" -Duser.home=/opt"
+
+# Add ${JAVA_HOME}/lib/ext as java.ext.dirs
+RUN 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
diff --git a/rocketmq-docker/image-build/build-image.sh b/rocketmq-docker/image-build/build-image.sh
new file mode 100755
index 0000000..95cde95
--- /dev/null
+++ b/rocketmq-docker/image-build/build-image.sh
@@ -0,0 +1,14 @@
+#!/bin/bash
+if [ $# -lt 1 ]; then
+    echo "Usage: sh $0 version#"
+    exit -1
+fi
+
+ROCKETMQ_VERSION=${1}
+if [ -z "${ROCKETMQ_VERSION}" ]
+then
+  ROCKETMQ_VERSION="4.5.0"
+fi
+
+# Build rocketmq
+docker build --no-cache -t rocketmqinc/rocketmq:${ROCKETMQ_VERSION} --build-arg version=${ROCKETMQ_VERSION} .
diff --git a/rocketmq-docker/image-build/scripts/runbroker-customize.sh b/rocketmq-docker/image-build/scripts/runbroker-customize.sh
new file mode 100755
index 0000000..8afa1ed
--- /dev/null
+++ b/rocketmq-docker/image-build/scripts/runbroker-customize.sh
@@ -0,0 +1,84 @@
+#!/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.
+# 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.
+
+#===========================================================================================
+# Java Environment Setting
+#===========================================================================================
+error_exit ()
+{
+    echo "ERROR: $1 !!"
+    exit 1
+}
+
+[ ! -e "$JAVA_HOME/bin/java" ] && JAVA_HOME=$HOME/jdk/java
+[ ! -e "$JAVA_HOME/bin/java" ] && JAVA_HOME=/usr/java
+[ ! -e "$JAVA_HOME/bin/java" ] && error_exit "Please set the JAVA_HOME variable in your environment, We need java(x64)!"
+
+export JAVA_HOME
+export JAVA="$JAVA_HOME/bin/java"
+export BASE_DIR=$(dirname $0)/..
+export CLASSPATH=.:${BASE_DIR}/conf:${CLASSPATH}
+
+#===========================================================================================
+# JVM Configuration
+#===========================================================================================
+# Get the max heap used by a jvm, which used all the ram available to the container.
+if [ -z "$MAX_POSSIBLE_HEAP" ]
+then
+	MAX_POSSIBLE_RAM_STR=$(java -XX:+UnlockExperimentalVMOptions -XX:MaxRAMFraction=1 -XshowSettings:vm -version 2>&1 | awk '/Max\. Heap Size \(Estimated\): [0-9KMG]+/{ print $5}')
+	MAX_POSSIBLE_RAM=$MAX_POSSIBLE_RAM_STR
+	CAL_UNIT=${MAX_POSSIBLE_RAM_STR: -1}
+	if [ "$CAL_UNIT" == "G" -o "$CAL_UNIT" == "g" ]; then
+		MAX_POSSIBLE_RAM=$(echo ${MAX_POSSIBLE_RAM_STR:0:${#MAX_POSSIBLE_RAM_STR}-1} `expr 1 \* 1024 \* 1024 \* 1024` | awk '{printf "%d",$1*$2}')
+	elif [ "$CAL_UNIT" == "M" -o "$CAL_UNIT" == "m" ]; then
+		MAX_POSSIBLE_RAM=$(echo ${MAX_POSSIBLE_RAM_STR:0:${#MAX_POSSIBLE_RAM_STR}-1} `expr 1 \* 1024 \* 1024` | awk '{printf "%d",$1*$2}')
+	elif [ "$CAL_UNIT" == "K" -o "$CAL_UNIT" == "k" ]; then
+		MAX_POSSIBLE_RAM=$(echo ${MAX_POSSIBLE_RAM_STR:0:${#MAX_POSSIBLE_RAM_STR}-1} `expr 1 \* 1024` | awk '{printf "%d",$1*$2}')
+	fi
+	MAX_POSSIBLE_HEAP=$[MAX_POSSIBLE_RAM/4]
+fi
+
+# Dynamically calculate parameters, for reference.
+Xms=$MAX_POSSIBLE_HEAP
+Xmx=$MAX_POSSIBLE_HEAP
+Xmn=$[MAX_POSSIBLE_HEAP/2]
+MaxDirectMemorySize=$MAX_POSSIBLE_HEAP
+# Set for `JAVA_OPT`.
+JAVA_OPT="${JAVA_OPT} -server -Xms${Xms} -Xmx${Xmx} -Xmn${Xmn}"
+JAVA_OPT="${JAVA_OPT} -XX:+UseG1GC -XX:G1HeapRegionSize=16m -XX:G1ReservePercent=25 -XX:InitiatingHeapOccupancyPercent=30 -XX:SoftRefLRUPolicyMSPerMB=0 -XX:SurvivorRatio=8"
+JAVA_OPT="${JAVA_OPT} -verbose:gc -Xloggc:/dev/shm/mq_gc_%p.log -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCApplicationStoppedTime -XX:+PrintAdaptiveSizePolicy"
+JAVA_OPT="${JAVA_OPT} -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=5 -XX:GCLogFileSize=30m"
+JAVA_OPT="${JAVA_OPT} -XX:-OmitStackTraceInFastThrow"
+JAVA_OPT="${JAVA_OPT} -XX:+AlwaysPreTouch"
+JAVA_OPT="${JAVA_OPT} -XX:MaxDirectMemorySize=${MaxDirectMemorySize}"
+JAVA_OPT="${JAVA_OPT} -XX:-UseLargePages -XX:-UseBiasedLocking"
+JAVA_OPT="${JAVA_OPT} -Djava.ext.dirs=${JAVA_HOME}/jre/lib/ext:${BASE_DIR}/lib"
+#JAVA_OPT="${JAVA_OPT} -Xdebug -Xrunjdwp:transport=dt_socket,address=9555,server=y,suspend=n"
+JAVA_OPT="${JAVA_OPT} ${JAVA_OPT_EXT}"
+JAVA_OPT="${JAVA_OPT} -cp ${CLASSPATH}"
+
+numactl --interleave=all pwd > /dev/null 2>&1
+if [ $? -eq 0 ]
+then
+	if [ -z "$RMQ_NUMA_NODE" ] ; then
+		numactl --interleave=all $JAVA ${JAVA_OPT} $@
+	else
+		numactl --cpunodebind=$RMQ_NUMA_NODE --membind=$RMQ_NUMA_NODE $JAVA ${JAVA_OPT} $@
+	fi
+else
+	$JAVA ${JAVA_OPT} $@
+fi
diff --git a/rocketmq-docker/image-build/scripts/runserver-customize.sh b/rocketmq-docker/image-build/scripts/runserver-customize.sh
new file mode 100755
index 0000000..dd25b1a
--- /dev/null
+++ b/rocketmq-docker/image-build/scripts/runserver-customize.sh
@@ -0,0 +1,70 @@
+#!/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.
+# 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.
+
+#===========================================================================================
+# Java Environment Setting
+#===========================================================================================
+error_exit ()
+{
+    echo "ERROR: $1 !!"
+    exit 1
+}
+
+[ ! -e "$JAVA_HOME/bin/java" ] && JAVA_HOME=$HOME/jdk/java
+[ ! -e "$JAVA_HOME/bin/java" ] && JAVA_HOME=/usr/java
+[ ! -e "$JAVA_HOME/bin/java" ] && error_exit "Please set the JAVA_HOME variable in your environment, We need java(x64)!"
+
+export JAVA_HOME
+export JAVA="$JAVA_HOME/bin/java"
+export BASE_DIR=$(dirname $0)/..
+export CLASSPATH=.:${BASE_DIR}/conf:${CLASSPATH}
+
+#===========================================================================================
+# JVM Configuration
+#===========================================================================================
+# Get the max heap used by a jvm, which used all the ram available to the container.
+if [ -z "$MAX_POSSIBLE_HEAP" ]
+then
+	MAX_POSSIBLE_RAM_STR=$(java -XX:+UnlockExperimentalVMOptions -XX:MaxRAMFraction=1 -XshowSettings:vm -version 2>&1 | awk '/Max\. Heap Size \(Estimated\): [0-9KMG]+/{ print $5}')
+	MAX_POSSIBLE_RAM=$MAX_POSSIBLE_RAM_STR
+	CAL_UNIT=${MAX_POSSIBLE_RAM_STR: -1}
+	if [ "$CAL_UNIT" == "G" -o "$CAL_UNIT" == "g" ]; then
+		MAX_POSSIBLE_RAM=$(echo ${MAX_POSSIBLE_RAM_STR:0:${#MAX_POSSIBLE_RAM_STR}-1} `expr 1 \* 1024 \* 1024 \* 1024` | awk '{printf "%d",$1*$2}')
+	elif [ "$CAL_UNIT" == "M" -o "$CAL_UNIT" == "m" ]; then
+		MAX_POSSIBLE_RAM=$(echo ${MAX_POSSIBLE_RAM_STR:0:${#MAX_POSSIBLE_RAM_STR}-1} `expr 1 \* 1024 \* 1024` | awk '{printf "%d",$1*$2}')
+	elif [ "$CAL_UNIT" == "K" -o "$CAL_UNIT" == "k" ]; then
+		MAX_POSSIBLE_RAM=$(echo ${MAX_POSSIBLE_RAM_STR:0:${#MAX_POSSIBLE_RAM_STR}-1} `expr 1 \* 1024` | awk '{printf "%d",$1*$2}')
+	fi
+	MAX_POSSIBLE_HEAP=$[MAX_POSSIBLE_RAM/4]
+fi
+
+# Dynamically calculate parameters, for reference.
+Xms=$MAX_POSSIBLE_HEAP
+Xmx=$MAX_POSSIBLE_HEAP
+Xmn=$[MAX_POSSIBLE_HEAP/2]
+# Set for `JAVA_OPT`.
+JAVA_OPT="${JAVA_OPT} -server -Xms${Xms} -Xmx${Xmx} -Xmn${Xmn}"
+JAVA_OPT="${JAVA_OPT} -XX:+UseConcMarkSweepGC -XX:+UseCMSCompactAtFullCollection -XX:CMSInitiatingOccupancyFraction=70 -XX:+CMSParallelRemarkEnabled -XX:SoftRefLRUPolicyMSPerMB=0 -XX:+CMSClassUnloadingEnabled -XX:SurvivorRatio=8  -XX:-UseParNewGC"
+JAVA_OPT="${JAVA_OPT} -verbose:gc -Xloggc:/dev/shm/rmq_srv_gc.log -XX:+PrintGCDetails"
+JAVA_OPT="${JAVA_OPT} -XX:-OmitStackTraceInFastThrow"
+JAVA_OPT="${JAVA_OPT}  -XX:-UseLargePages"
+JAVA_OPT="${JAVA_OPT} -Djava.ext.dirs=${JAVA_HOME}/jre/lib/ext:${BASE_DIR}/lib"
+#JAVA_OPT="${JAVA_OPT} -Xdebug -Xrunjdwp:transport=dt_socket,address=9555,server=y,suspend=n"
+JAVA_OPT="${JAVA_OPT} ${JAVA_OPT_EXT}"
+JAVA_OPT="${JAVA_OPT} -cp ${CLASSPATH}"
+
+$JAVA ${JAVA_OPT} $@
diff --git a/rocketmq-docker/product/README.md b/rocketmq-docker/product/README.md
new file mode 100644
index 0000000..446f890
--- /dev/null
+++ b/rocketmq-docker/product/README.md
@@ -0,0 +1,88 @@
+# 生产级可用的RocketMQ Docker部署
+
+## 背景
+
+这是一个简单的使用说明,旨在说明如何在生产环境中使用可持久的存储和配置信息,在不同的网络节点下部署NameServer集群和主从模式的Broker集群。注意:这里只包含配置及启动容器,没有提及容器的监控和管理,容器机器的DNS配置,消息的分布和可靠性存储等细节。这一部分需要结合Kubernetes的功能实现RocketMQ-Operator相关的高级部署功能。
+
+## 部署和运行容器的步骤
+
+1. 确定要部署的宿主机(物理或虚拟机)的IP和DNS信息,宿主机的存储文件路径,确保相关的端口(9876, 10911, 10912, 10909)未被占用
+2. 准备broker启动的配置文件,根据Cluster的要求,选择参考的配置文件,并对必要属性参数进行修改
+3. 调用docker容器启动脚本,设置参数,启动容器 (从[这里](<https://hub.docker.com/apache/rocketmq>)查找RocketMQ镜像版本)
+4. 验证容器启动状态
+
+## 目录结构
+
+product /
+
+​    | -  conf / 几种典型的集群的配置 
+
+​    | - start-ns.sh 启动name-server容器的脚本,每个name-server容器调用一次该脚本
+
+​    | - start-broker.sh 启动broker容器的脚本,在不同的容器宿主机上执行该脚本,创建不同的broker集群成员
+
+   | - REAMD.md 说明文件
+
+## 一个具体的使用案例
+
+配置一个2m-2s-async的集群
+
+### 启动nameserver集群 
+
+注意:可以跳过此步骤,如果使用已经存在的nameserver集群
+
+1. 确认要部署nameserver的宿主机,确定需要映射容器持久化的目录(DATA_HOME)和RocketMQ镜像版本(ROCKETMQ_VERSION)
+
+2. 运行脚本 start-ns.sh, 例如:
+
+   ```
+   sh start-ns.sh /home/nameserver/data 4.5.0
+   ```
+
+3. 如果有多个nameserver要启动,重复上述步骤。
+
+### 启动broker集群
+
+1. 确定要连接的NameServer集群的地址
+
+2. 确认要部署broker-a master的宿主机,确定需要映射容器持久化的目录(DATA_HOME),例如,确定宿主机的DATA_HOME目录为 /home/broker/data/; 则需要把参考的conf/2m-2s-async/broker-a.properties 文件复制到 /home/broker/data/conf/2m-2s-async/broker-a.properties
+
+   修改broker-a.properties文件的brokerIP1配置为宿主机的dns-hostname(注 #3)
+
+3. 确定ROCKETMQ_VERSION, 运行脚本 start-broker.sh, 例如:
+
+   ```
+   sh start-broker.sh /home/broker/data 4.5.0 "ns1:9876;ns2:9876" conf/2m-2s-async/broker-a.properties
+   ```
+
+4. 确定broker容器正确启动 (注意: 宿主机目录DATA_HOME要对容器rocketmq用户开放读取权限)
+
+5. 确认要部署broker-a slave的宿主机,确定需要映射容器持久化的目录(DATA_HOME),例如,确定宿主机的DATA_HOME目录为 /home/broker/data/; 则需要把参考的conf/2m-2s-async/broker-a-s.properties 文件复制到 /home/broker/data/conf/2m-2s-async/broker-a-s.properties
+
+   修改broker-a.properties文件的brokerIP1配置为宿主机的dns-hostname, brokerIP2为master所在的宿主机dns-hostname
+
+6. 确定ROCKETMQ_VERSION, 运行脚本 start-broker.sh, 例如:
+
+   ```
+   sh start-broker.sh /home/broker/data 4.5.0 "ns1:9876;ns2:9876" conf/2m-2s-async/broker-a-s.properties
+   ```
+
+7. 确定broker容器正确启动 (注意: 宿主机目录DATA_HOME要对容器rocketmq用户开放读取权限)
+
+8. 重复上述步骤,创建broker-b的主从broker容器
+
+## 注意事项
+
+1. 保证宿主机存储目录的权限
+
+   由于broker容器需要在宿主机的DATA_HOME目录下要写如需要持久化的数据,如,操作日志和消息存储文件,所以要求开放DATA_HOME目录下的权限,确保broker启动和运行时能够写入相关的文件。
+
+   一个案例: 当启动broker后,一段时间时间后broker自动退出,没有任何日志写入,这个可能就是由于容器没有写入DATA_HOME/logs目录权限导致。
+
+2. 在脚本中(start-broker.sh, start-ns.sh)中声明外部映射端口
+
+   在相关的脚本中已经定义了相关的默认映射端口,如果用户有特别需求(如端口已经被其它应用占用),则需要修改shell脚本,定义新的端口映射。
+
+3. 建议使用DNS配置broker和name-server地址
+
+   运行在docker容器中的broker使用brokerIP1来指定所在的宿主机的地址,并将这个地址注册到NameServer中,以便RocketMQ客户端通过NameServer取得可以外部可用的broker地址,但是一个好的实践是使用dns-hostname,来定义相关的ip地址,这样在大规模broker进行变化或者ip地址迁移时,不会对已经部署的容器有影响。
\ No newline at end of file
diff --git a/rocketmq-docker/product/conf/2m-2s-async/broker-a-s.properties b/rocketmq-docker/product/conf/2m-2s-async/broker-a-s.properties
new file mode 100644
index 0000000..e5eef23
--- /dev/null
+++ b/rocketmq-docker/product/conf/2m-2s-async/broker-a-s.properties
@@ -0,0 +1,30 @@
+# 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.
+brokerClusterName=DefaultCluster
+brokerName=broker-a
+brokerId=1
+deleteWhen=04
+fileReservedTime=48
+brokerRole=SLAVE
+flushDiskType=ASYNC_FLUSH
+
+
+#Slave host dns-name/ip
+brokerIP1=REPLACE_IT 
+#with Master's BroperIP1
+brokerIP2=REPLACE_IT 
+
+#with Master's haListenPort, default 10912
+#haListenPort=10912 
diff --git a/rocketmq-docker/product/conf/2m-2s-async/broker-a.properties b/rocketmq-docker/product/conf/2m-2s-async/broker-a.properties
new file mode 100644
index 0000000..39dc5bf
--- /dev/null
+++ b/rocketmq-docker/product/conf/2m-2s-async/broker-a.properties
@@ -0,0 +1,29 @@
+# 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.
+brokerClusterName=DefaultCluster
+brokerName=broker-a
+brokerId=0
+deleteWhen=04
+fileReservedTime=48
+brokerRole=ASYNC_MASTER
+flushDiskType=ASYNC_FLUSH
+
+# Host node's dns-name or ip
+brokerIP1=REPLACE_IT
+
+# Optional config different value rather than default ports.
+# Caution: changing default ports need to update port mapping setting (-p) in start-broker.sh
+#listenPort=10911
+#haListenPort=10912
\ No newline at end of file
diff --git a/rocketmq-docker/product/conf/2m-2s-async/broker-b-s.properties b/rocketmq-docker/product/conf/2m-2s-async/broker-b-s.properties
new file mode 100644
index 0000000..50fb0fb
--- /dev/null
+++ b/rocketmq-docker/product/conf/2m-2s-async/broker-b-s.properties
@@ -0,0 +1,29 @@
+# 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.
+brokerClusterName=DefaultCluster
+brokerName=broker-b
+brokerId=1
+deleteWhen=04
+fileReservedTime=48
+brokerRole=SLAVE
+flushDiskType=ASYNC_FLUSH
+
+#Slave host dns-name/ip
+brokerIP1=REPLACE_IT 
+#with Master's BroperIP1
+brokerIP2=REPLACE_IT 
+
+# with Master's haListenPort, default 10912
+#haListenPort=10912 
\ No newline at end of file
diff --git a/rocketmq-docker/product/conf/2m-2s-async/broker-b.properties b/rocketmq-docker/product/conf/2m-2s-async/broker-b.properties
new file mode 100644
index 0000000..c84cb76
--- /dev/null
+++ b/rocketmq-docker/product/conf/2m-2s-async/broker-b.properties
@@ -0,0 +1,29 @@
+# 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.
+brokerClusterName=DefaultCluster
+brokerName=broker-b
+brokerId=0
+deleteWhen=04
+fileReservedTime=48
+brokerRole=ASYNC_MASTER
+flushDiskType=ASYNC_FLUSH
+
+# Host node's dns-name or ip
+brokerIP1=REPLACE_IT
+
+# Optional config different value rather than default ports.
+# Caution: changing default ports need to update port mapping setting (-p) in start-broker.sh
+#listenPort=10911
+#haListenPort=10912
\ No newline at end of file
diff --git a/rocketmq-docker/product/conf/2m-2s-sync/broker-a-s.properties b/rocketmq-docker/product/conf/2m-2s-sync/broker-a-s.properties
new file mode 100644
index 0000000..275f236
--- /dev/null
+++ b/rocketmq-docker/product/conf/2m-2s-sync/broker-a-s.properties
@@ -0,0 +1,29 @@
+# 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.
+brokerClusterName=DefaultCluster
+brokerName=broker-a
+brokerId=1
+deleteWhen=04
+fileReservedTime=48
+brokerRole=SLAVE
+flushDiskType=ASYNC_FLUSH
+
+#Slave host dns-name/ip
+brokerIP1=REPLACE_IT 
+#with Master's BroperIP1
+brokerIP2=REPLACE_IT 
+
+#with Master's haListenPort, default 10912
+#haListenPort=10912 
\ No newline at end of file
diff --git a/rocketmq-docker/product/conf/2m-2s-sync/broker-a.properties b/rocketmq-docker/product/conf/2m-2s-sync/broker-a.properties
new file mode 100644
index 0000000..acdc008
--- /dev/null
+++ b/rocketmq-docker/product/conf/2m-2s-sync/broker-a.properties
@@ -0,0 +1,29 @@
+# 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.
+brokerClusterName=DefaultCluster
+brokerName=broker-a
+brokerId=0
+deleteWhen=04
+fileReservedTime=48
+brokerRole=SYNC_MASTER
+flushDiskType=ASYNC_FLUSH
+
+# Host node's dns-name or ip
+brokerIP1=REPLACE_IT
+
+# Optional config different value rather than default ports.
+# Caution: changing default ports need to update port mapping setting (-p) in start-broker.sh
+#listenPort=10911
+#haListenPort=10912
\ No newline at end of file
diff --git a/rocketmq-docker/product/conf/2m-2s-sync/broker-b-s.properties b/rocketmq-docker/product/conf/2m-2s-sync/broker-b-s.properties
new file mode 100644
index 0000000..50fb0fb
--- /dev/null
+++ b/rocketmq-docker/product/conf/2m-2s-sync/broker-b-s.properties
@@ -0,0 +1,29 @@
+# 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.
+brokerClusterName=DefaultCluster
+brokerName=broker-b
+brokerId=1
+deleteWhen=04
+fileReservedTime=48
+brokerRole=SLAVE
+flushDiskType=ASYNC_FLUSH
+
+#Slave host dns-name/ip
+brokerIP1=REPLACE_IT 
+#with Master's BroperIP1
+brokerIP2=REPLACE_IT 
+
+# with Master's haListenPort, default 10912
+#haListenPort=10912 
\ No newline at end of file
diff --git a/rocketmq-docker/product/conf/2m-2s-sync/broker-b.properties b/rocketmq-docker/product/conf/2m-2s-sync/broker-b.properties
new file mode 100644
index 0000000..29c4a28
--- /dev/null
+++ b/rocketmq-docker/product/conf/2m-2s-sync/broker-b.properties
@@ -0,0 +1,29 @@
+# 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.
+brokerClusterName=DefaultCluster
+brokerName=broker-b
+brokerId=0
+deleteWhen=04
+fileReservedTime=48
+brokerRole=SYNC_MASTER
+flushDiskType=ASYNC_FLUSH
+
+# Host node's dns-name or ip
+brokerIP1=REPLACE_IT
+
+# Optional config different value rather than default ports.
+# Caution: changing default ports need to update port mapping setting (-p) in start-broker.sh
+#listenPort=10911
+#haListenPort=10912
\ No newline at end of file
diff --git a/rocketmq-docker/product/conf/2m-noslave/broker-a.properties b/rocketmq-docker/product/conf/2m-noslave/broker-a.properties
new file mode 100644
index 0000000..e1189b5
--- /dev/null
+++ b/rocketmq-docker/product/conf/2m-noslave/broker-a.properties
@@ -0,0 +1,28 @@
+# 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.
+brokerClusterName=DefaultCluster
+brokerName=broker-a
+brokerId=0
+deleteWhen=04
+fileReservedTime=48
+brokerRole=ASYNC_MASTER
+flushDiskType=ASYNC_FLUSH
+
+# Host node's dns-name or ip
+brokerIP1=REPLACE_IT
+
+# Optional config different value rather than default ports.
+# Caution: changing default ports need to update port mapping setting (-p) in start-broker.sh
+#listenPort=10911
\ No newline at end of file
diff --git a/rocketmq-docker/product/conf/2m-noslave/broker-b.properties b/rocketmq-docker/product/conf/2m-noslave/broker-b.properties
new file mode 100644
index 0000000..c84cb76
--- /dev/null
+++ b/rocketmq-docker/product/conf/2m-noslave/broker-b.properties
@@ -0,0 +1,29 @@
+# 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.
+brokerClusterName=DefaultCluster
+brokerName=broker-b
+brokerId=0
+deleteWhen=04
+fileReservedTime=48
+brokerRole=ASYNC_MASTER
+flushDiskType=ASYNC_FLUSH
+
+# Host node's dns-name or ip
+brokerIP1=REPLACE_IT
+
+# Optional config different value rather than default ports.
+# Caution: changing default ports need to update port mapping setting (-p) in start-broker.sh
+#listenPort=10911
+#haListenPort=10912
\ No newline at end of file
diff --git a/rocketmq-docker/product/conf/2m-noslave/broker-trace.properties b/rocketmq-docker/product/conf/2m-noslave/broker-trace.properties
new file mode 100644
index 0000000..966bb5f
--- /dev/null
+++ b/rocketmq-docker/product/conf/2m-noslave/broker-trace.properties
@@ -0,0 +1,30 @@
+#
+# 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.
+#
+brokerClusterName=DefaultCluster
+brokerName=broker-trace
+brokerId=0
+deleteWhen=04
+fileReservedTime=48
+brokerRole=ASYNC_MASTER
+flushDiskType=ASYNC_FLUSH
+
+# Host node's dns-name or ip
+brokerIP1=REPLACE_IT
+
+# Optional config different value rather than default ports.
+# Caution: changing default ports need to update port mapping setting (-p) in start-broker.sh
+#listenPort=10911
\ No newline at end of file
diff --git a/rocketmq-docker/product/conf/broker.conf b/rocketmq-docker/product/conf/broker.conf
new file mode 100644
index 0000000..3a7676b
--- /dev/null
+++ b/rocketmq-docker/product/conf/broker.conf
@@ -0,0 +1,25 @@
+# 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.
+
+brokerClusterName = DefaultCluster
+brokerName = broker-b
+brokerId = 0
+deleteWhen = 04
+fileReservedTime = 48
+brokerRole = ASYNC_MASTER
+flushDiskType = ASYNC_FLUSH
+
+# Set self-defined brokerIP address (e.g. the host node's) 
+#brokerIP1=30.25.90.82
diff --git a/rocketmq-docker/product/start-broker.sh b/rocketmq-docker/product/start-broker.sh
new file mode 100644
index 0000000..c7b4e93
--- /dev/null
+++ b/rocketmq-docker/product/start-broker.sh
@@ -0,0 +1,49 @@
+#!/bin/sh
+
+# 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.
+
+## Main
+if [ $# -lt 4 ]; then
+    echo "Usage: sh $0 DATA_HOME ROCKETMQ_VERSION NAMESRV_ADDR CONF_FILE"
+    exit -1
+fi
+
+DATA_HOME=$1
+ROCKETMQ_VERSION=$2
+NAMESRV_ADDR=$3
+CONF_FILE=$4
+
+## Show Env Setting
+echo "ENV Setting: "
+echo "  DATA_HOME=${DATA_HOME} ROCKETMQ_VERSION=${ROCKETMQ_VERSION}"
+echo "  NAMESRV_ADDR=${NAMESRV_ADDR}"
+echo "  CONF_FILE=${CONF_FILE}" 
+
+## Check config file existing
+if [ ! -f "${DATA_HOME}/conf/${CONF_FILE}" ]; then
+    echo "You must ensure the broker config file [${DATA_HOME}/conf/${CONF_FILE}] is pre-defined!!!"
+    exit -1
+fi
+
+
+# Start Broker
+docker run -d  -v ${DATA_HOME}/logs:/home/rocketmq/logs -v ${DATA_HOME}/store:/home/rocketmq/store \
+  -v ${DATA_HOME}/conf:/home/rocketmq/conf \
+  --name rmqbroker \
+  -e "NAMESRV_ADDR=${NAMESRV_ADDR}" \
+  -p 10911:10911 -p 10912:10912 -p 10909:10909 \
+  rocketmqinc/rocketmq:${ROCKETMQ_VERSION} \
+  sh mqbroker -c /home/rocketmq/conf/${CONF_FILE}
diff --git a/rocketmq-docker/product/start-ns.sh b/rocketmq-docker/product/start-ns.sh
new file mode 100644
index 0000000..baa61f2
--- /dev/null
+++ b/rocketmq-docker/product/start-ns.sh
@@ -0,0 +1,37 @@
+#!/bin/sh
+
+# 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.
+
+
+## Main
+if [ $# -lt 2 ]; then
+    echo "Usage: sh $0 DATA_HOME ROCKETMQ_VERSION"
+    exit -1
+fi
+
+DATA_HOME=$1
+ROCKETMQ_VERSION=$2
+
+## Show Env Setting
+echo "ENV Setting: "
+echo "DATA_HOME=${DATA_HOME} ROCKETMQ_VERSION=${ROCKETMQ_VERSION}"
+
+# Start nameserver
+docker run -d -v ${DATA_HOME}/logs:/home/rocketmq/logs \
+  --name rmqnamesrv \
+  -p 9876:9876 \
+  rocketmqinc/rocketmq:ROCKETMQ_VERSION \
+  sh mqnamesrv
\ No newline at end of file
diff --git a/rocketmq-docker/stage.sh b/rocketmq-docker/stage.sh
new file mode 100644
index 0000000..dbf24f4
--- /dev/null
+++ b/rocketmq-docker/stage.sh
@@ -0,0 +1,58 @@
+#!/bin/sh
+
+# 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.
+
+function checkVersion()        
+{
+    echo "Stage version = $1"
+	echo $1 |grep -E "^[0-9]+\.[0-9]+\.[0-9]+" > /dev/null
+    if [ $? = 0 ]; then
+        return 1
+    fi
+            
+	echo "Version $1 illegal, it should be X.X.X format(e.g. 4.5.0), please check released versions in 'https://dist.apache.org/repos/dist/release/rocketmq/'"
+    return 0
+} 
+
+CURRENT_DIR="$(cd "$(dirname "$0")"; pwd)"
+
+[ ! -d "$STAGE_DIR" ] &&  STAGE_DIR=$CURRENT_DIR/stages
+mkdir -p $STAGE_DIR
+
+if [ $# -lt 1 ]; then
+    echo "Usage: sh $0 version"
+    exit -1
+fi
+
+version=$1
+checkVersion $version
+if [ $? = 0 ]; then
+	exit -1
+fi
+
+echo "mkdir $STAGE_DIR/$version"
+mkdir -p "$STAGE_DIR/$version"
+
+cp -rf "$CURRENT_DIR/templates/" "$STAGE_DIR/$version"
+
+echo "staged templates into folder $STAGE_DIR/$version"
+
+# Stage the real version
+# todo fix on linux (sed)
+#find "$STAGE_DIR/$version" -type f -exec sed -i "" "s/ROCKETMQ_VERSION/${version}/g" {} \;
+find "$STAGE_DIR/$version" -type f | xargs perl -pi -e "s/ROCKETMQ_VERSION/${version}/g"
+
+cd $STAGE_DIR
diff --git a/rocketmq-docker/templates/data/broker/conf/broker.conf b/rocketmq-docker/templates/data/broker/conf/broker.conf
new file mode 100644
index 0000000..e460e54
--- /dev/null
+++ b/rocketmq-docker/templates/data/broker/conf/broker.conf
@@ -0,0 +1,8 @@
+brokerClusterName = DefaultCluster
+brokerName = broker-abc
+brokerId = 0
+deleteWhen = 04
+fileReservedTime = 48
+brokerRole = ASYNC_MASTER
+flushDiskType = ASYNC_FLUSH
+brokerIP1 = 30.25.90.30
diff --git a/rocketmq-docker/templates/data/broker/conf/broker1.conf b/rocketmq-docker/templates/data/broker/conf/broker1.conf
new file mode 100644
index 0000000..7233af9
--- /dev/null
+++ b/rocketmq-docker/templates/data/broker/conf/broker1.conf
@@ -0,0 +1,9 @@
+brokerClusterName = DefaultCluster
+brokerName = broker-abc1
+brokerId = 1
+deleteWhen = 04
+fileReservedTime = 48
+brokerRole = ASYNC_MASTER
+flushDiskType = ASYNC_FLUSH
+brokerIP1 = m30
+listenPort = 10921
diff --git a/rocketmq-docker/templates/data/broker0/conf/dledger/broker.conf b/rocketmq-docker/templates/data/broker0/conf/dledger/broker.conf
new file mode 100644
index 0000000..7b21174
--- /dev/null
+++ b/rocketmq-docker/templates/data/broker0/conf/dledger/broker.conf
@@ -0,0 +1,27 @@
+# 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.
+
+brokerClusterName = RaftCluster
+brokerName=RaftNode00
+listenPort=30911
+#namesrvAddr=127.0.0.1:9876
+storePathRootDir=/tmp/rmqstore/node00
+storePathCommitLog=/tmp/rmqstore/node00/commitlog
+enableDLegerCommitLog=true
+dLegerGroup=RaftNode00
+dLegerPeers=n0-172.18.0.12:40911;n1-172.18.0.13:40912;n2-172.18.0.14:40913
+## must be unique
+dLegerSelfId=n0
+sendMessageThreadPoolNums=16
diff --git a/rocketmq-docker/templates/data/broker1/conf/dledger/broker.conf b/rocketmq-docker/templates/data/broker1/conf/dledger/broker.conf
new file mode 100644
index 0000000..8b32bb2
--- /dev/null
+++ b/rocketmq-docker/templates/data/broker1/conf/dledger/broker.conf
@@ -0,0 +1,27 @@
+# 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.
+
+brokerClusterName = RaftCluster
+brokerName=RaftNode01
+listenPort=30911
+#namesrvAddr=127.0.0.1:9876
+storePathRootDir=/tmp/rmqstore/node00
+storePathCommitLog=/tmp/rmqstore/node00/commitlog
+enableDLegerCommitLog=true
+dLegerGroup=RaftNode00
+dLegerPeers=n0-172.18.0.12:40911;n1-172.18.0.13:40912;n2-172.18.0.14:40913
+## must be unique
+dLegerSelfId=n1
+sendMessageThreadPoolNums=16
diff --git a/rocketmq-docker/templates/data/broker2/conf/dledger/broker.conf b/rocketmq-docker/templates/data/broker2/conf/dledger/broker.conf
new file mode 100644
index 0000000..6fec70e
--- /dev/null
+++ b/rocketmq-docker/templates/data/broker2/conf/dledger/broker.conf
@@ -0,0 +1,27 @@
+# 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.
+
+brokerClusterName = RaftCluster
+brokerName=RaftNode02
+listenPort=30911
+#namesrvAddr=127.0.0.1:9876
+storePathRootDir=/tmp/rmqstore/node00
+storePathCommitLog=/tmp/rmqstore/node00/commitlog
+enableDLegerCommitLog=true
+dLegerGroup=RaftNode00
+dLegerPeers=n0-172.18.0.12:40911;n1-172.18.0.13:40912;n2-172.18.0.14:40913
+## must be unique
+dLegerSelfId=n2
+sendMessageThreadPoolNums=16
diff --git a/rocketmq-docker/templates/docker-compose/data/broker/conf/broker.conf b/rocketmq-docker/templates/docker-compose/data/broker/conf/broker.conf
new file mode 100644
index 0000000..a8f04e2
--- /dev/null
+++ b/rocketmq-docker/templates/docker-compose/data/broker/conf/broker.conf
@@ -0,0 +1,7 @@
+brokerClusterName = DefaultCluster
+brokerName = broker-a
+brokerId = 0
+deleteWhen = 04
+fileReservedTime = 48
+brokerRole = ASYNC_MASTER
+flushDiskType = ASYNC_FLUSH
diff --git a/rocketmq-docker/templates/docker-compose/data1/broker/conf/broker.conf b/rocketmq-docker/templates/docker-compose/data1/broker/conf/broker.conf
new file mode 100644
index 0000000..acf84fb
--- /dev/null
+++ b/rocketmq-docker/templates/docker-compose/data1/broker/conf/broker.conf
@@ -0,0 +1,7 @@
+brokerClusterName = DefaultCluster
+brokerName = broker-b
+brokerId = 1
+deleteWhen = 04
+fileReservedTime = 48
+brokerRole = ASYNC_MASTER
+flushDiskType = ASYNC_FLUSH
diff --git a/rocketmq-docker/templates/docker-compose/docker-compose.yml b/rocketmq-docker/templates/docker-compose/docker-compose.yml
new file mode 100644
index 0000000..64271b9
--- /dev/null
+++ b/rocketmq-docker/templates/docker-compose/docker-compose.yml
@@ -0,0 +1,46 @@
+version: '2'
+services:
+  #Service for nameserver
+  namesrv:
+    image: rocketmqinc/rocketmq:ROCKETMQ_VERSION
+    container_name: rmqnamesrv
+    ports:
+      - 9876:9876
+    volumes:
+      - ./data/namesrv/logs:/home/rocketmq/logs
+      - ./data/namesrv/store:/home/rocketmq/store
+    command: sh mqnamesrv
+
+  #Service for broker
+  broker:
+    image: rocketmqinc/rocketmq:ROCKETMQ_VERSION
+    container_name: rmqbroker
+    links:
+      - namesrv
+    ports:
+      - 10909:10909
+      - 10911:10911 
+    environment:
+      - NAMESRV_ADDR=namesrv:9876
+    volumes:
+      - ./data/broker/logs:/home/rocketmq/logs
+      - ./data/broker/store:/home/rocketmq/store
+      - ./data/broker/conf/broker.conf:/opt/rocketmq-ROCKETMQ_VERSION/conf/broker.conf
+    command: sh mqbroker -c ../conf/broker.conf
+
+  #Service for another broker -- broker1
+  broker1:
+    image: rocketmqinc/rocketmq:ROCKETMQ_VERSION
+    container_name: rmqbroker1
+    links:
+      - namesrv
+    ports:
+      - 10929:10909
+      - 10931:10911 
+    environment:
+      - NAMESRV_ADDR=namesrv:9876
+    volumes:
+      - ./data1/broker/logs:/home/rocketmq/logs
+      - ./data1/broker/store:/home/rocketmq/store
+      - ./data1/broker/conf/broker.conf:/opt/rocketmq-ROCKETMQ_VERSION/conf/broker.conf
+    command: sh mqbroker -c ../conf/broker.conf
diff --git a/rocketmq-docker/templates/kubernetes/deployment.yaml b/rocketmq-docker/templates/kubernetes/deployment.yaml
new file mode 100644
index 0000000..a71e8b1
--- /dev/null
+++ b/rocketmq-docker/templates/kubernetes/deployment.yaml
@@ -0,0 +1,48 @@
+apiVersion: extensions/v1beta1
+kind: Deployment
+metadata:
+  name: rocketmq
+spec:
+  replicas: 1
+  template:
+    metadata:
+     labels:
+       app: rocketmq
+    spec:
+      containers:
+      - name: broker
+        image: rocketmqinc/rocketmq:ROCKETMQ_VERSION
+        command: ["sh","mqbroker", "-n","localhost:9876"]
+        imagePullPolicy: IfNotPresent
+        ports:
+          - containerPort: 10909
+          - containerPort: 10911
+        volumeMounts:
+          - mountPath: /home/rocketmq/logs
+            name: brokeroptlogs
+          - mountPath: /home/rocketmq/store
+            name: brokeroptstore
+      - name: namesrv
+        image: rocketmqinc/rocketmq:ROCKETMQ_VERSION
+        command: ["sh","mqnamesrv"]
+        imagePullPolicy: IfNotPresent
+        ports:
+          - containerPort: 9876
+        volumeMounts:
+          - mountPath: /home/rocketmq/logs
+            name: namesrvoptlogs
+          - mountPath: /home/rocketmq/store
+            name: namesrvoptstore
+      volumes:
+      - name: brokeroptlogs
+        hostPath:
+          path: /data/broker/logs
+      - name: brokeroptstore
+        hostPath:
+          path: /data/broker/store
+      - name: namesrvoptlogs
+        hostPath:
+          path: /data/namesrv/logs
+      - name: namesrvoptstore
+        hostPath:
+          path: /data/namesrv/store
diff --git a/rocketmq-docker/templates/kubernetes/deployment2.yaml b/rocketmq-docker/templates/kubernetes/deployment2.yaml
new file mode 100644
index 0000000..fa5db99
--- /dev/null
+++ b/rocketmq-docker/templates/kubernetes/deployment2.yaml
@@ -0,0 +1,70 @@
+kind: Deployment
+apiVersion: extensions/v1beta1
+metadata:
+  name: rocketmq-ns-deployment
+spec:
+  replicas: 1
+  selector:
+    matchLabels:
+      app: rocketmq-nameserver
+      name: rocketmq-nameserver
+  template:
+    metadata:
+     labels:
+      app: rocketmq-nameserver
+      name: rocketmq-nameserver
+    spec:
+      containers:
+      - name: rocketmq-nameserver
+        image: rocketmqinc/rocketmq:ROCKETMQ_VERSION
+        command: ["sh","mqnamesrv"]
+        imagePullPolicy: IfNotPresent
+        ports:
+          - containerPort: 9876
+        volumeMounts:
+          - mountPath: /home/rocketmq/logs
+            name: namesrvlogs
+          - mountPath: /home/rocketmq/store
+            name: namesrvstore
+      volumes:
+      - name: namesrvlogs
+        emptyDir: {}
+      - name: namesrvstore 
+        emptyDir: {}
+---          
+kind: Deployment
+apiVersion: extensions/v1beta1
+metadata:
+  name: rocketmq-broker-deployment
+spec:
+  replicas: 1
+  selector:
+    matchLabels:
+      app: rocketmq-broker
+      name: rocketmq-broker
+  template:
+    metadata:
+     labels:
+      app: rocketmq-broker
+      name: rocketmq-broker
+    spec:
+      containers:
+      - name: rocketmq-broker
+        image: rocketmqinc/rocketmq:ROCKETMQ_VERSION
+        command: ["sh","mqbroker", "-n","rocketmq-ns-deployment:9876"]
+        imagePullPolicy: IfNotPresent
+        ports:
+          - containerPort: 10909
+          - containerPort: 10911
+        volumeMounts:
+          - mountPath: /home/rocketmq/logs
+            name: brokerlogs
+          - mountPath: /home/rocketmq/store
+            name: brokerstore
+      volumes:
+      - name: brokerlogs
+        emptyDir: {}
+      - name: brokerstore
+        emptyDir: {}
+
+
diff --git a/rocketmq-docker/templates/play-consumer.sh b/rocketmq-docker/templates/play-consumer.sh
new file mode 100755
index 0000000..5f9f6e3
--- /dev/null
+++ b/rocketmq-docker/templates/play-consumer.sh
@@ -0,0 +1,4 @@
+#!/bin/bash
+
+# Consume messages
+docker exec -ti rmqbroker sh ./tools.sh org.apache.rocketmq.example.quickstart.Consumer
\ No newline at end of file
diff --git a/rocketmq-docker/templates/play-docker-compose.sh b/rocketmq-docker/templates/play-docker-compose.sh
new file mode 100755
index 0000000..f1b5c3a
--- /dev/null
+++ b/rocketmq-docker/templates/play-docker-compose.sh
@@ -0,0 +1,16 @@
+#!/bin/bash
+
+RMQ_CONTAINER=$(docker ps -a|awk '/rmq/ {print $1}')
+if [[ -n "$RMQ_CONTAINER" ]]; then
+   echo "Removing RocketMQ Container..."
+   docker rm -fv $RMQ_CONTAINER
+   # Wait till the existing containers are removed
+   sleep 5
+fi
+
+if [ ! -d "`pwd`/data" ]; then
+  mkdir -p "data"
+fi
+
+# Run namesrv and broker
+docker-compose -f ./docker-compose/docker-compose.yml up -d
diff --git a/rocketmq-docker/templates/play-docker-deledger.sh b/rocketmq-docker/templates/play-docker-deledger.sh
new file mode 100755
index 0000000..4be6521
--- /dev/null
+++ b/rocketmq-docker/templates/play-docker-deledger.sh
@@ -0,0 +1,40 @@
+#!/bin/bash
+
+RMQ_CONTAINER=$(docker ps -a|awk '/rmq/ {print $1}')
+if [[ -n "$RMQ_CONTAINER" ]]; then
+   echo "Removing RocketMQ Container..."
+   docker rm -fv $RMQ_CONTAINER
+   # Wait till the existing containers are removed
+   sleep 5
+fi
+
+DLEDGER_NET=$(docker network ls |awk '/dledger-br/ {print $1}')
+if [[ -n "$DLEDGER_NET" ]]; then
+   echo "Removing DLedger Bridge network..."
+   docker network rm $DLEDGER_NET
+   # Wait till the existing networks are removed
+   sleep 5
+fi
+
+if [ ! -d "`pwd`/data" ]; then
+  mkdir -p "data"
+fi
+
+echo "Starting RocketMQ nodes..."
+
+# Create network
+docker network create --subnet=172.18.0.0/16 dledger-br
+
+# Start nameserver
+docker run --net dledger-br --ip 172.18.0.11  -d -p 9876:9876 -v `pwd`/data/namesrv/logs:/home/rocketmq/logs -v `pwd`/data/namesrv/store:/home/rocketmq/store --name rmqnamesrv  rocketmqinc/rocketmq:ROCKETMQ_VERSION sh mqnamesrv
+
+# Start Brokers
+docker run --net dledger-br --ip 172.18.0.12 -d -p 30911:30911 -p 30909:30909 -v `pwd`/data/broker0/logs:/home/rocketmq/logs -v `pwd`/data/broker0/store:/home/rocketmq/store -v `pwd`/data/broker0/conf/dledger:/opt/rocketmq-ROCKETMQ_VERSION/conf/dledger --name rmqbroker --link rmqnamesrv:namesrv -e "MAX_POSSIBLE_HEAP=200000000" -e "NAMESRV_ADDR=namesrv:9876" rocketmqinc/rocketmq:ROCKETMQ_VERSION sh mqbroker  -c  ../conf/dledger/broker.conf
+docker run --net dledger-br --ip 172.18.0.13 -d -p 30921:30921 -p 30919:30919 -v `pwd`/data/broker1/logs:/home/rocketmq/logs -v `pwd`/data/broker1/store:/home/rocketmq/store -v `pwd`/data/broker1/conf/dledger:/opt/rocketmq-ROCKETMQ_VERSION/conf/dledger --name rmqbroker1 --link rmqnamesrv:namesrv -e "MAX_POSSIBLE_HEAP=200000000" -e "NAMESRV_ADDR=namesrv:9876" rocketmqinc/rocketmq:ROCKETMQ_VERSION sh mqbroker  -c  ../conf/dledger/broker.conf
+docker run --net dledger-br --ip 172.18.0.14 -d -p 30931:30931 -p 30929:30929 -v `pwd`/data/broker2/logs:/home/rocketmq/logs -v `pwd`/data/broker2/store:/home/rocketmq/store -v `pwd`/data/broker2/conf/dledger:/opt/rocketmq-ROCKETMQ_VERSION/conf/dledger --name rmqbroker2 --link rmqnamesrv:namesrv -e "MAX_POSSIBLE_HEAP=200000000" -e "NAMESRV_ADDR=namesrv:9876" rocketmqinc/rocketmq:ROCKETMQ_VERSION sh mqbroker  -c  ../conf/dledger/broker.conf
+
+# Servive unavailable when not ready
+# sleep 20
+
+# Produce messages
+# sh ./play-producer.sh
diff --git a/rocketmq-docker/templates/play-docker.sh b/rocketmq-docker/templates/play-docker.sh
new file mode 100755
index 0000000..dd2e7fd
--- /dev/null
+++ b/rocketmq-docker/templates/play-docker.sh
@@ -0,0 +1,28 @@
+#!/bin/bash
+
+RMQ_CONTAINER=$(docker ps -a|awk '/rmq/ {print $1}')
+if [[ -n "$RMQ_CONTAINER" ]]; then
+   echo "Removing RocketMQ Container..."
+   docker rm -fv $RMQ_CONTAINER
+   # Wait till the existing containers are removed
+   sleep 5
+fi
+
+if [ ! -d "`pwd`/data" ]; then
+  mkdir -p "data"
+fi
+
+echo "Starting RocketMQ nodes..."
+
+# Start nameserver
+# Start nameserver
+docker run -d -v `pwd`/data/namesrv/logs:/home/rocketmq/logs -v `pwd`/data/namesrv/store:/home/rocketmq/store --name rmqnamesrv rocketmqinc/rocketmq:ROCKETMQ_VERSION sh mqnamesrv
+
+# Start Broker
+docker run -d  -v `pwd`/data/broker/logs:/home/rocketmq/logs -v `pwd`/data/broker/store:/home/rocketmq/store --name rmqbroker --link rmqnamesrv:namesrv -e "NAMESRV_ADDR=namesrv:9876" rocketmqinc/rocketmq:ROCKETMQ_VERSION sh mqbroker
+
+# Servive unavailable when not ready
+# sleep 20
+
+# Produce messages
+# sh ./play-producer.sh
diff --git a/rocketmq-docker/templates/play-kubernetes.sh b/rocketmq-docker/templates/play-kubernetes.sh
new file mode 100755
index 0000000..6ddd5d5
--- /dev/null
+++ b/rocketmq-docker/templates/play-kubernetes.sh
@@ -0,0 +1,8 @@
+#!/bin/bash
+
+if [ ! -d "`pwd`/data" ]; then
+  mkdir -p "data"
+fi
+
+# Run nameserver and broker on your Kubernetes cluster
+kubectl apply -f kubernetes/deployment.yaml
diff --git a/rocketmq-docker/templates/play-producer.sh b/rocketmq-docker/templates/play-producer.sh
new file mode 100755
index 0000000..657195c
--- /dev/null
+++ b/rocketmq-docker/templates/play-producer.sh
@@ -0,0 +1,4 @@
+#!/bin/bash
+
+# Produce messages
+docker exec -ti rmqbroker sh ./tools.sh org.apache.rocketmq.example.quickstart.Producer
\ No newline at end of file
diff --git a/rocketmq-docker/templates/scripts/runbroker-customize.sh b/rocketmq-docker/templates/scripts/runbroker-customize.sh
new file mode 100755
index 0000000..7c625cf
--- /dev/null
+++ b/rocketmq-docker/templates/scripts/runbroker-customize.sh
@@ -0,0 +1,84 @@
+#!/bin/sh
+
+# 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.
+
+#===========================================================================================
+# Java Environment Setting
+#===========================================================================================
+error_exit ()
+{
+    echo "ERROR: $1 !!"
+    exit 1
+}
+
+[ ! -e "$JAVA_HOME/bin/java" ] && JAVA_HOME=$HOME/jdk/java
+[ ! -e "$JAVA_HOME/bin/java" ] && JAVA_HOME=/usr/java
+[ ! -e "$JAVA_HOME/bin/java" ] && error_exit "Please set the JAVA_HOME variable in your environment, We need java(x64)!"
+
+export JAVA_HOME
+export JAVA="$JAVA_HOME/bin/java"
+export BASE_DIR=$(dirname $0)/..
+export CLASSPATH=.:${BASE_DIR}/conf:${CLASSPATH}
+
+#===========================================================================================
+# JVM Configuration
+#===========================================================================================
+# Get the max heap used by a jvm, which used all the ram available to the container.
+if [ -z "$MAX_POSSIBLE_HEAP" ]
+then
+	MAX_POSSIBLE_RAM_STR=$(java -XX:+UnlockExperimentalVMOptions -XX:MaxRAMFraction=1 -XshowSettings:vm -version |& awk '/Max\. Heap Size \(Estimated\): [0-9KMG]+/{ print $5}')
+	MAX_POSSIBLE_RAM=$MAX_POSSIBLE_RAM_STR
+	CAL_UNIT=${MAX_POSSIBLE_RAM_STR: -1}
+	if [ "$CAL_UNIT" == "G" -o "$CAL_UNIT" == "g" ]; then
+		MAX_POSSIBLE_RAM=$(echo ${MAX_POSSIBLE_RAM_STR:0:${#MAX_POSSIBLE_RAM_STR}-1} `expr 1 \* 1024 \* 1024 \* 1024` | awk '{printf "%d",$1*$2}')
+	elif [ "$CAL_UNIT" == "M" -o "$CAL_UNIT" == "m" ]; then
+		MAX_POSSIBLE_RAM=$(echo ${MAX_POSSIBLE_RAM_STR:0:${#MAX_POSSIBLE_RAM_STR}-1} `expr 1 \* 1024 \* 1024` | awk '{printf "%d",$1*$2}')
+	elif [ "$CAL_UNIT" == "K" -o "$CAL_UNIT" == "k" ]; then
+		MAX_POSSIBLE_RAM=$(echo ${MAX_POSSIBLE_RAM_STR:0:${#MAX_POSSIBLE_RAM_STR}-1} `expr 1 \* 1024` | awk '{printf "%d",$1*$2}')
+	fi
+	MAX_POSSIBLE_HEAP=$[MAX_POSSIBLE_RAM/4]
+fi
+
+# Dynamically calculate parameters, for reference.
+Xms=$MAX_POSSIBLE_HEAP
+Xmx=$MAX_POSSIBLE_HEAP
+Xmn=$[MAX_POSSIBLE_HEAP/2]
+MaxDirectMemorySize=$MAX_POSSIBLE_HEAP
+# Set for `JAVA_OPT`.
+JAVA_OPT="${JAVA_OPT} -server -Xms${Xms} -Xmx${Xmx} -Xmn${Xmn}"
+JAVA_OPT="${JAVA_OPT} -XX:+UseG1GC -XX:G1HeapRegionSize=16m -XX:G1ReservePercent=25 -XX:InitiatingHeapOccupancyPercent=30 -XX:SoftRefLRUPolicyMSPerMB=0 -XX:SurvivorRatio=8"
+JAVA_OPT="${JAVA_OPT} -verbose:gc -Xloggc:/dev/shm/mq_gc_%p.log -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCApplicationStoppedTime -XX:+PrintAdaptiveSizePolicy"
+JAVA_OPT="${JAVA_OPT} -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=5 -XX:GCLogFileSize=30m"
+JAVA_OPT="${JAVA_OPT} -XX:-OmitStackTraceInFastThrow"
+JAVA_OPT="${JAVA_OPT} -XX:+AlwaysPreTouch"
+JAVA_OPT="${JAVA_OPT} -XX:MaxDirectMemorySize=${MaxDirectMemorySize}"
+JAVA_OPT="${JAVA_OPT} -XX:-UseLargePages -XX:-UseBiasedLocking"
+JAVA_OPT="${JAVA_OPT} -Djava.ext.dirs=${JAVA_HOME}/jre/lib/ext:${BASE_DIR}/lib"
+#JAVA_OPT="${JAVA_OPT} -Xdebug -Xrunjdwp:transport=dt_socket,address=9555,server=y,suspend=n"
+JAVA_OPT="${JAVA_OPT} ${JAVA_OPT_EXT}"
+JAVA_OPT="${JAVA_OPT} -cp ${CLASSPATH}"
+
+numactl --interleave=all pwd > /dev/null 2>&1
+if [ $? -eq 0 ]
+then
+	if [ -z "$RMQ_NUMA_NODE" ] ; then
+		numactl --interleave=all $JAVA ${JAVA_OPT} $@
+	else
+		numactl --cpunodebind=$RMQ_NUMA_NODE --membind=$RMQ_NUMA_NODE $JAVA ${JAVA_OPT} $@
+	fi
+else
+	$JAVA ${JAVA_OPT} $@
+fi
diff --git a/rocketmq-docker/templates/scripts/runserver-customize.sh b/rocketmq-docker/templates/scripts/runserver-customize.sh
new file mode 100755
index 0000000..4cefb00
--- /dev/null
+++ b/rocketmq-docker/templates/scripts/runserver-customize.sh
@@ -0,0 +1,70 @@
+#!/bin/sh
+
+# 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.
+
+#===========================================================================================
+# Java Environment Setting
+#===========================================================================================
+error_exit ()
+{
+    echo "ERROR: $1 !!"
+    exit 1
+}
+
+[ ! -e "$JAVA_HOME/bin/java" ] && JAVA_HOME=$HOME/jdk/java
+[ ! -e "$JAVA_HOME/bin/java" ] && JAVA_HOME=/usr/java
+[ ! -e "$JAVA_HOME/bin/java" ] && error_exit "Please set the JAVA_HOME variable in your environment, We need java(x64)!"
+
+export JAVA_HOME
+export JAVA="$JAVA_HOME/bin/java"
+export BASE_DIR=$(dirname $0)/..
+export CLASSPATH=.:${BASE_DIR}/conf:${CLASSPATH}
+
+#===========================================================================================
+# JVM Configuration
+#===========================================================================================
+# Get the max heap used by a jvm, which used all the ram available to the container.
+if [ -z "$MAX_POSSIBLE_HEAP" ]
+then
+	MAX_POSSIBLE_RAM_STR=$(java -XX:+UnlockExperimentalVMOptions -XX:MaxRAMFraction=1 -XshowSettings:vm -version |& awk '/Max\. Heap Size \(Estimated\): [0-9KMG]+/{ print $5}')
+	MAX_POSSIBLE_RAM=$MAX_POSSIBLE_RAM_STR
+	CAL_UNIT=${MAX_POSSIBLE_RAM_STR: -1}
+	if [ "$CAL_UNIT" == "G" -o "$CAL_UNIT" == "g" ]; then
+		MAX_POSSIBLE_RAM=$(echo ${MAX_POSSIBLE_RAM_STR:0:${#MAX_POSSIBLE_RAM_STR}-1} `expr 1 \* 1024 \* 1024 \* 1024` | awk '{printf "%d",$1*$2}')
+	elif [ "$CAL_UNIT" == "M" -o "$CAL_UNIT" == "m" ]; then
+		MAX_POSSIBLE_RAM=$(echo ${MAX_POSSIBLE_RAM_STR:0:${#MAX_POSSIBLE_RAM_STR}-1} `expr 1 \* 1024 \* 1024` | awk '{printf "%d",$1*$2}')
+	elif [ "$CAL_UNIT" == "K" -o "$CAL_UNIT" == "k" ]; then
+		MAX_POSSIBLE_RAM=$(echo ${MAX_POSSIBLE_RAM_STR:0:${#MAX_POSSIBLE_RAM_STR}-1} `expr 1 \* 1024` | awk '{printf "%d",$1*$2}')
+	fi
+	MAX_POSSIBLE_HEAP=$[MAX_POSSIBLE_RAM/4]
+fi
+
+# Dynamically calculate parameters, for reference.
+Xms=$MAX_POSSIBLE_HEAP
+Xmx=$MAX_POSSIBLE_HEAP
+Xmn=$[MAX_POSSIBLE_HEAP/2]
+# Set for `JAVA_OPT`.
+JAVA_OPT="${JAVA_OPT} -server -Xms${Xms} -Xmx${Xmx} -Xmn${Xmn}"
+JAVA_OPT="${JAVA_OPT} -XX:+UseConcMarkSweepGC -XX:+UseCMSCompactAtFullCollection -XX:CMSInitiatingOccupancyFraction=70 -XX:+CMSParallelRemarkEnabled -XX:SoftRefLRUPolicyMSPerMB=0 -XX:+CMSClassUnloadingEnabled -XX:SurvivorRatio=8  -XX:-UseParNewGC"
+JAVA_OPT="${JAVA_OPT} -verbose:gc -Xloggc:/dev/shm/rmq_srv_gc.log -XX:+PrintGCDetails"
+JAVA_OPT="${JAVA_OPT} -XX:-OmitStackTraceInFastThrow"
+JAVA_OPT="${JAVA_OPT}  -XX:-UseLargePages"
+JAVA_OPT="${JAVA_OPT} -Djava.ext.dirs=${JAVA_HOME}/jre/lib/ext:${BASE_DIR}/lib"
+#JAVA_OPT="${JAVA_OPT} -Xdebug -Xrunjdwp:transport=dt_socket,address=9555,server=y,suspend=n"
+JAVA_OPT="${JAVA_OPT} ${JAVA_OPT_EXT}"
+JAVA_OPT="${JAVA_OPT} -cp ${CLASSPATH}"
+
+$JAVA ${JAVA_OPT} $@
diff --git a/stage.sh b/stage.sh
new file mode 100644
index 0000000..dbf24f4
--- /dev/null
+++ b/stage.sh
@@ -0,0 +1,58 @@
+#!/bin/sh
+
+# 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.
+
+function checkVersion()        
+{
+    echo "Stage version = $1"
+	echo $1 |grep -E "^[0-9]+\.[0-9]+\.[0-9]+" > /dev/null
+    if [ $? = 0 ]; then
+        return 1
+    fi
+            
+	echo "Version $1 illegal, it should be X.X.X format(e.g. 4.5.0), please check released versions in 'https://dist.apache.org/repos/dist/release/rocketmq/'"
+    return 0
+} 
+
+CURRENT_DIR="$(cd "$(dirname "$0")"; pwd)"
+
+[ ! -d "$STAGE_DIR" ] &&  STAGE_DIR=$CURRENT_DIR/stages
+mkdir -p $STAGE_DIR
+
+if [ $# -lt 1 ]; then
+    echo "Usage: sh $0 version"
+    exit -1
+fi
+
+version=$1
+checkVersion $version
+if [ $? = 0 ]; then
+	exit -1
+fi
+
+echo "mkdir $STAGE_DIR/$version"
+mkdir -p "$STAGE_DIR/$version"
+
+cp -rf "$CURRENT_DIR/templates/" "$STAGE_DIR/$version"
+
+echo "staged templates into folder $STAGE_DIR/$version"
+
+# Stage the real version
+# todo fix on linux (sed)
+#find "$STAGE_DIR/$version" -type f -exec sed -i "" "s/ROCKETMQ_VERSION/${version}/g" {} \;
+find "$STAGE_DIR/$version" -type f | xargs perl -pi -e "s/ROCKETMQ_VERSION/${version}/g"
+
+cd $STAGE_DIR
diff --git a/templates/data/broker/conf/broker.conf b/templates/data/broker/conf/broker.conf
new file mode 100644
index 0000000..e460e54
--- /dev/null
+++ b/templates/data/broker/conf/broker.conf
@@ -0,0 +1,8 @@
+brokerClusterName = DefaultCluster
+brokerName = broker-abc
+brokerId = 0
+deleteWhen = 04
+fileReservedTime = 48
+brokerRole = ASYNC_MASTER
+flushDiskType = ASYNC_FLUSH
+brokerIP1 = 30.25.90.30
diff --git a/templates/data/broker/conf/broker1.conf b/templates/data/broker/conf/broker1.conf
new file mode 100644
index 0000000..7233af9
--- /dev/null
+++ b/templates/data/broker/conf/broker1.conf
@@ -0,0 +1,9 @@
+brokerClusterName = DefaultCluster
+brokerName = broker-abc1
+brokerId = 1
+deleteWhen = 04
+fileReservedTime = 48
+brokerRole = ASYNC_MASTER
+flushDiskType = ASYNC_FLUSH
+brokerIP1 = m30
+listenPort = 10921
diff --git a/templates/data/broker0/conf/dledger/broker.conf b/templates/data/broker0/conf/dledger/broker.conf
new file mode 100644
index 0000000..7b21174
--- /dev/null
+++ b/templates/data/broker0/conf/dledger/broker.conf
@@ -0,0 +1,27 @@
+# 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.
+
+brokerClusterName = RaftCluster
+brokerName=RaftNode00
+listenPort=30911
+#namesrvAddr=127.0.0.1:9876
+storePathRootDir=/tmp/rmqstore/node00
+storePathCommitLog=/tmp/rmqstore/node00/commitlog
+enableDLegerCommitLog=true
+dLegerGroup=RaftNode00
+dLegerPeers=n0-172.18.0.12:40911;n1-172.18.0.13:40912;n2-172.18.0.14:40913
+## must be unique
+dLegerSelfId=n0
+sendMessageThreadPoolNums=16
diff --git a/templates/data/broker1/conf/dledger/broker.conf b/templates/data/broker1/conf/dledger/broker.conf
new file mode 100644
index 0000000..8b32bb2
--- /dev/null
+++ b/templates/data/broker1/conf/dledger/broker.conf
@@ -0,0 +1,27 @@
+# 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.
+
+brokerClusterName = RaftCluster
+brokerName=RaftNode01
+listenPort=30911
+#namesrvAddr=127.0.0.1:9876
+storePathRootDir=/tmp/rmqstore/node00
+storePathCommitLog=/tmp/rmqstore/node00/commitlog
+enableDLegerCommitLog=true
+dLegerGroup=RaftNode00
+dLegerPeers=n0-172.18.0.12:40911;n1-172.18.0.13:40912;n2-172.18.0.14:40913
+## must be unique
+dLegerSelfId=n1
+sendMessageThreadPoolNums=16
diff --git a/templates/data/broker2/conf/dledger/broker.conf b/templates/data/broker2/conf/dledger/broker.conf
new file mode 100644
index 0000000..6fec70e
--- /dev/null
+++ b/templates/data/broker2/conf/dledger/broker.conf
@@ -0,0 +1,27 @@
+# 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.
+
+brokerClusterName = RaftCluster
+brokerName=RaftNode02
+listenPort=30911
+#namesrvAddr=127.0.0.1:9876
+storePathRootDir=/tmp/rmqstore/node00
+storePathCommitLog=/tmp/rmqstore/node00/commitlog
+enableDLegerCommitLog=true
+dLegerGroup=RaftNode00
+dLegerPeers=n0-172.18.0.12:40911;n1-172.18.0.13:40912;n2-172.18.0.14:40913
+## must be unique
+dLegerSelfId=n2
+sendMessageThreadPoolNums=16
diff --git a/templates/docker-compose/data/broker/conf/broker.conf b/templates/docker-compose/data/broker/conf/broker.conf
new file mode 100644
index 0000000..a8f04e2
--- /dev/null
+++ b/templates/docker-compose/data/broker/conf/broker.conf
@@ -0,0 +1,7 @@
+brokerClusterName = DefaultCluster
+brokerName = broker-a
+brokerId = 0
+deleteWhen = 04
+fileReservedTime = 48
+brokerRole = ASYNC_MASTER
+flushDiskType = ASYNC_FLUSH
diff --git a/templates/docker-compose/data1/broker/conf/broker.conf b/templates/docker-compose/data1/broker/conf/broker.conf
new file mode 100644
index 0000000..acf84fb
--- /dev/null
+++ b/templates/docker-compose/data1/broker/conf/broker.conf
@@ -0,0 +1,7 @@
+brokerClusterName = DefaultCluster
+brokerName = broker-b
+brokerId = 1
+deleteWhen = 04
+fileReservedTime = 48
+brokerRole = ASYNC_MASTER
+flushDiskType = ASYNC_FLUSH
diff --git a/templates/docker-compose/docker-compose.yml b/templates/docker-compose/docker-compose.yml
new file mode 100644
index 0000000..64271b9
--- /dev/null
+++ b/templates/docker-compose/docker-compose.yml
@@ -0,0 +1,46 @@
+version: '2'
+services:
+  #Service for nameserver
+  namesrv:
+    image: rocketmqinc/rocketmq:ROCKETMQ_VERSION
+    container_name: rmqnamesrv
+    ports:
+      - 9876:9876
+    volumes:
+      - ./data/namesrv/logs:/home/rocketmq/logs
+      - ./data/namesrv/store:/home/rocketmq/store
+    command: sh mqnamesrv
+
+  #Service for broker
+  broker:
+    image: rocketmqinc/rocketmq:ROCKETMQ_VERSION
+    container_name: rmqbroker
+    links:
+      - namesrv
+    ports:
+      - 10909:10909
+      - 10911:10911 
+    environment:
+      - NAMESRV_ADDR=namesrv:9876
+    volumes:
+      - ./data/broker/logs:/home/rocketmq/logs
+      - ./data/broker/store:/home/rocketmq/store
+      - ./data/broker/conf/broker.conf:/opt/rocketmq-ROCKETMQ_VERSION/conf/broker.conf
+    command: sh mqbroker -c ../conf/broker.conf
+
+  #Service for another broker -- broker1
+  broker1:
+    image: rocketmqinc/rocketmq:ROCKETMQ_VERSION
+    container_name: rmqbroker1
+    links:
+      - namesrv
+    ports:
+      - 10929:10909
+      - 10931:10911 
+    environment:
+      - NAMESRV_ADDR=namesrv:9876
+    volumes:
+      - ./data1/broker/logs:/home/rocketmq/logs
+      - ./data1/broker/store:/home/rocketmq/store
+      - ./data1/broker/conf/broker.conf:/opt/rocketmq-ROCKETMQ_VERSION/conf/broker.conf
+    command: sh mqbroker -c ../conf/broker.conf
diff --git a/templates/kubernetes/deployment.yaml b/templates/kubernetes/deployment.yaml
new file mode 100644
index 0000000..a71e8b1
--- /dev/null
+++ b/templates/kubernetes/deployment.yaml
@@ -0,0 +1,48 @@
+apiVersion: extensions/v1beta1
+kind: Deployment
+metadata:
+  name: rocketmq
+spec:
+  replicas: 1
+  template:
+    metadata:
+     labels:
+       app: rocketmq
+    spec:
+      containers:
+      - name: broker
+        image: rocketmqinc/rocketmq:ROCKETMQ_VERSION
+        command: ["sh","mqbroker", "-n","localhost:9876"]
+        imagePullPolicy: IfNotPresent
+        ports:
+          - containerPort: 10909
+          - containerPort: 10911
+        volumeMounts:
+          - mountPath: /home/rocketmq/logs
+            name: brokeroptlogs
+          - mountPath: /home/rocketmq/store
+            name: brokeroptstore
+      - name: namesrv
+        image: rocketmqinc/rocketmq:ROCKETMQ_VERSION
+        command: ["sh","mqnamesrv"]
+        imagePullPolicy: IfNotPresent
+        ports:
+          - containerPort: 9876
+        volumeMounts:
+          - mountPath: /home/rocketmq/logs
+            name: namesrvoptlogs
+          - mountPath: /home/rocketmq/store
+            name: namesrvoptstore
+      volumes:
+      - name: brokeroptlogs
+        hostPath:
+          path: /data/broker/logs
+      - name: brokeroptstore
+        hostPath:
+          path: /data/broker/store
+      - name: namesrvoptlogs
+        hostPath:
+          path: /data/namesrv/logs
+      - name: namesrvoptstore
+        hostPath:
+          path: /data/namesrv/store
diff --git a/templates/kubernetes/deployment2.yaml b/templates/kubernetes/deployment2.yaml
new file mode 100644
index 0000000..fa5db99
--- /dev/null
+++ b/templates/kubernetes/deployment2.yaml
@@ -0,0 +1,70 @@
+kind: Deployment
+apiVersion: extensions/v1beta1
+metadata:
+  name: rocketmq-ns-deployment
+spec:
+  replicas: 1
+  selector:
+    matchLabels:
+      app: rocketmq-nameserver
+      name: rocketmq-nameserver
+  template:
+    metadata:
+     labels:
+      app: rocketmq-nameserver
+      name: rocketmq-nameserver
+    spec:
+      containers:
+      - name: rocketmq-nameserver
+        image: rocketmqinc/rocketmq:ROCKETMQ_VERSION
+        command: ["sh","mqnamesrv"]
+        imagePullPolicy: IfNotPresent
+        ports:
+          - containerPort: 9876
+        volumeMounts:
+          - mountPath: /home/rocketmq/logs
+            name: namesrvlogs
+          - mountPath: /home/rocketmq/store
+            name: namesrvstore
+      volumes:
+      - name: namesrvlogs
+        emptyDir: {}
+      - name: namesrvstore 
+        emptyDir: {}
+---          
+kind: Deployment
+apiVersion: extensions/v1beta1
+metadata:
+  name: rocketmq-broker-deployment
+spec:
+  replicas: 1
+  selector:
+    matchLabels:
+      app: rocketmq-broker
+      name: rocketmq-broker
+  template:
+    metadata:
+     labels:
+      app: rocketmq-broker
+      name: rocketmq-broker
+    spec:
+      containers:
+      - name: rocketmq-broker
+        image: rocketmqinc/rocketmq:ROCKETMQ_VERSION
+        command: ["sh","mqbroker", "-n","rocketmq-ns-deployment:9876"]
+        imagePullPolicy: IfNotPresent
+        ports:
+          - containerPort: 10909
+          - containerPort: 10911
+        volumeMounts:
+          - mountPath: /home/rocketmq/logs
+            name: brokerlogs
+          - mountPath: /home/rocketmq/store
+            name: brokerstore
+      volumes:
+      - name: brokerlogs
+        emptyDir: {}
+      - name: brokerstore
+        emptyDir: {}
+
+
diff --git a/templates/play-consumer.sh b/templates/play-consumer.sh
new file mode 100755
index 0000000..5f9f6e3
--- /dev/null
+++ b/templates/play-consumer.sh
@@ -0,0 +1,4 @@
+#!/bin/bash
+
+# Consume messages
+docker exec -ti rmqbroker sh ./tools.sh org.apache.rocketmq.example.quickstart.Consumer
\ No newline at end of file
diff --git a/templates/play-docker-compose.sh b/templates/play-docker-compose.sh
new file mode 100755
index 0000000..f1b5c3a
--- /dev/null
+++ b/templates/play-docker-compose.sh
@@ -0,0 +1,16 @@
+#!/bin/bash
+
+RMQ_CONTAINER=$(docker ps -a|awk '/rmq/ {print $1}')
+if [[ -n "$RMQ_CONTAINER" ]]; then
+   echo "Removing RocketMQ Container..."
+   docker rm -fv $RMQ_CONTAINER
+   # Wait till the existing containers are removed
+   sleep 5
+fi
+
+if [ ! -d "`pwd`/data" ]; then
+  mkdir -p "data"
+fi
+
+# Run namesrv and broker
+docker-compose -f ./docker-compose/docker-compose.yml up -d
diff --git a/templates/play-docker-deledger.sh b/templates/play-docker-deledger.sh
new file mode 100755
index 0000000..4be6521
--- /dev/null
+++ b/templates/play-docker-deledger.sh
@@ -0,0 +1,40 @@
+#!/bin/bash
+
+RMQ_CONTAINER=$(docker ps -a|awk '/rmq/ {print $1}')
+if [[ -n "$RMQ_CONTAINER" ]]; then
+   echo "Removing RocketMQ Container..."
+   docker rm -fv $RMQ_CONTAINER
+   # Wait till the existing containers are removed
+   sleep 5
+fi
+
+DLEDGER_NET=$(docker network ls |awk '/dledger-br/ {print $1}')
+if [[ -n "$DLEDGER_NET" ]]; then
+   echo "Removing DLedger Bridge network..."
+   docker network rm $DLEDGER_NET
+   # Wait till the existing networks are removed
+   sleep 5
+fi
+
+if [ ! -d "`pwd`/data" ]; then
+  mkdir -p "data"
+fi
+
+echo "Starting RocketMQ nodes..."
+
+# Create network
+docker network create --subnet=172.18.0.0/16 dledger-br
+
+# Start nameserver
+docker run --net dledger-br --ip 172.18.0.11  -d -p 9876:9876 -v `pwd`/data/namesrv/logs:/home/rocketmq/logs -v `pwd`/data/namesrv/store:/home/rocketmq/store --name rmqnamesrv  rocketmqinc/rocketmq:ROCKETMQ_VERSION sh mqnamesrv
+
+# Start Brokers
+docker run --net dledger-br --ip 172.18.0.12 -d -p 30911:30911 -p 30909:30909 -v `pwd`/data/broker0/logs:/home/rocketmq/logs -v `pwd`/data/broker0/store:/home/rocketmq/store -v `pwd`/data/broker0/conf/dledger:/opt/rocketmq-ROCKETMQ_VERSION/conf/dledger --name rmqbroker --link rmqnamesrv:namesrv -e "MAX_POSSIBLE_HEAP=200000000" -e "NAMESRV_ADDR=namesrv:9876" rocketmqinc/rocketmq:ROCKETMQ_VERSION sh mqbroker  -c  ../conf/dledger/broker.conf
+docker run --net dledger-br --ip 172.18.0.13 -d -p 30921:30921 -p 30919:30919 -v `pwd`/data/broker1/logs:/home/rocketmq/logs -v `pwd`/data/broker1/store:/home/rocketmq/store -v `pwd`/data/broker1/conf/dledger:/opt/rocketmq-ROCKETMQ_VERSION/conf/dledger --name rmqbroker1 --link rmqnamesrv:namesrv -e "MAX_POSSIBLE_HEAP=200000000" -e "NAMESRV_ADDR=namesrv:9876" rocketmqinc/rocketmq:ROCKETMQ_VERSION sh mqbroker  -c  ../conf/dledger/broker.conf
+docker run --net dledger-br --ip 172.18.0.14 -d -p 30931:30931 -p 30929:30929 -v `pwd`/data/broker2/logs:/home/rocketmq/logs -v `pwd`/data/broker2/store:/home/rocketmq/store -v `pwd`/data/broker2/conf/dledger:/opt/rocketmq-ROCKETMQ_VERSION/conf/dledger --name rmqbroker2 --link rmqnamesrv:namesrv -e "MAX_POSSIBLE_HEAP=200000000" -e "NAMESRV_ADDR=namesrv:9876" rocketmqinc/rocketmq:ROCKETMQ_VERSION sh mqbroker  -c  ../conf/dledger/broker.conf
+
+# Servive unavailable when not ready
+# sleep 20
+
+# Produce messages
+# sh ./play-producer.sh
diff --git a/templates/play-docker.sh b/templates/play-docker.sh
new file mode 100755
index 0000000..dd2e7fd
--- /dev/null
+++ b/templates/play-docker.sh
@@ -0,0 +1,28 @@
+#!/bin/bash
+
+RMQ_CONTAINER=$(docker ps -a|awk '/rmq/ {print $1}')
+if [[ -n "$RMQ_CONTAINER" ]]; then
+   echo "Removing RocketMQ Container..."
+   docker rm -fv $RMQ_CONTAINER
+   # Wait till the existing containers are removed
+   sleep 5
+fi
+
+if [ ! -d "`pwd`/data" ]; then
+  mkdir -p "data"
+fi
+
+echo "Starting RocketMQ nodes..."
+
+# Start nameserver
+# Start nameserver
+docker run -d -v `pwd`/data/namesrv/logs:/home/rocketmq/logs -v `pwd`/data/namesrv/store:/home/rocketmq/store --name rmqnamesrv rocketmqinc/rocketmq:ROCKETMQ_VERSION sh mqnamesrv
+
+# Start Broker
+docker run -d  -v `pwd`/data/broker/logs:/home/rocketmq/logs -v `pwd`/data/broker/store:/home/rocketmq/store --name rmqbroker --link rmqnamesrv:namesrv -e "NAMESRV_ADDR=namesrv:9876" rocketmqinc/rocketmq:ROCKETMQ_VERSION sh mqbroker
+
+# Servive unavailable when not ready
+# sleep 20
+
+# Produce messages
+# sh ./play-producer.sh
diff --git a/templates/play-kubernetes.sh b/templates/play-kubernetes.sh
new file mode 100755
index 0000000..6ddd5d5
--- /dev/null
+++ b/templates/play-kubernetes.sh
@@ -0,0 +1,8 @@
+#!/bin/bash
+
+if [ ! -d "`pwd`/data" ]; then
+  mkdir -p "data"
+fi
+
+# Run nameserver and broker on your Kubernetes cluster
+kubectl apply -f kubernetes/deployment.yaml
diff --git a/templates/play-producer.sh b/templates/play-producer.sh
new file mode 100755
index 0000000..657195c
--- /dev/null
+++ b/templates/play-producer.sh
@@ -0,0 +1,4 @@
+#!/bin/bash
+
+# Produce messages
+docker exec -ti rmqbroker sh ./tools.sh org.apache.rocketmq.example.quickstart.Producer
\ No newline at end of file
diff --git a/templates/scripts/runbroker-customize.sh b/templates/scripts/runbroker-customize.sh
new file mode 100755
index 0000000..7c625cf
--- /dev/null
+++ b/templates/scripts/runbroker-customize.sh
@@ -0,0 +1,84 @@
+#!/bin/sh
+
+# 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.
+
+#===========================================================================================
+# Java Environment Setting
+#===========================================================================================
+error_exit ()
+{
+    echo "ERROR: $1 !!"
+    exit 1
+}
+
+[ ! -e "$JAVA_HOME/bin/java" ] && JAVA_HOME=$HOME/jdk/java
+[ ! -e "$JAVA_HOME/bin/java" ] && JAVA_HOME=/usr/java
+[ ! -e "$JAVA_HOME/bin/java" ] && error_exit "Please set the JAVA_HOME variable in your environment, We need java(x64)!"
+
+export JAVA_HOME
+export JAVA="$JAVA_HOME/bin/java"
+export BASE_DIR=$(dirname $0)/..
+export CLASSPATH=.:${BASE_DIR}/conf:${CLASSPATH}
+
+#===========================================================================================
+# JVM Configuration
+#===========================================================================================
+# Get the max heap used by a jvm, which used all the ram available to the container.
+if [ -z "$MAX_POSSIBLE_HEAP" ]
+then
+	MAX_POSSIBLE_RAM_STR=$(java -XX:+UnlockExperimentalVMOptions -XX:MaxRAMFraction=1 -XshowSettings:vm -version |& awk '/Max\. Heap Size \(Estimated\): [0-9KMG]+/{ print $5}')
+	MAX_POSSIBLE_RAM=$MAX_POSSIBLE_RAM_STR
+	CAL_UNIT=${MAX_POSSIBLE_RAM_STR: -1}
+	if [ "$CAL_UNIT" == "G" -o "$CAL_UNIT" == "g" ]; then
+		MAX_POSSIBLE_RAM=$(echo ${MAX_POSSIBLE_RAM_STR:0:${#MAX_POSSIBLE_RAM_STR}-1} `expr 1 \* 1024 \* 1024 \* 1024` | awk '{printf "%d",$1*$2}')
+	elif [ "$CAL_UNIT" == "M" -o "$CAL_UNIT" == "m" ]; then
+		MAX_POSSIBLE_RAM=$(echo ${MAX_POSSIBLE_RAM_STR:0:${#MAX_POSSIBLE_RAM_STR}-1} `expr 1 \* 1024 \* 1024` | awk '{printf "%d",$1*$2}')
+	elif [ "$CAL_UNIT" == "K" -o "$CAL_UNIT" == "k" ]; then
+		MAX_POSSIBLE_RAM=$(echo ${MAX_POSSIBLE_RAM_STR:0:${#MAX_POSSIBLE_RAM_STR}-1} `expr 1 \* 1024` | awk '{printf "%d",$1*$2}')
+	fi
+	MAX_POSSIBLE_HEAP=$[MAX_POSSIBLE_RAM/4]
+fi
+
+# Dynamically calculate parameters, for reference.
+Xms=$MAX_POSSIBLE_HEAP
+Xmx=$MAX_POSSIBLE_HEAP
+Xmn=$[MAX_POSSIBLE_HEAP/2]
+MaxDirectMemorySize=$MAX_POSSIBLE_HEAP
+# Set for `JAVA_OPT`.
+JAVA_OPT="${JAVA_OPT} -server -Xms${Xms} -Xmx${Xmx} -Xmn${Xmn}"
+JAVA_OPT="${JAVA_OPT} -XX:+UseG1GC -XX:G1HeapRegionSize=16m -XX:G1ReservePercent=25 -XX:InitiatingHeapOccupancyPercent=30 -XX:SoftRefLRUPolicyMSPerMB=0 -XX:SurvivorRatio=8"
+JAVA_OPT="${JAVA_OPT} -verbose:gc -Xloggc:/dev/shm/mq_gc_%p.log -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCApplicationStoppedTime -XX:+PrintAdaptiveSizePolicy"
+JAVA_OPT="${JAVA_OPT} -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=5 -XX:GCLogFileSize=30m"
+JAVA_OPT="${JAVA_OPT} -XX:-OmitStackTraceInFastThrow"
+JAVA_OPT="${JAVA_OPT} -XX:+AlwaysPreTouch"
+JAVA_OPT="${JAVA_OPT} -XX:MaxDirectMemorySize=${MaxDirectMemorySize}"
+JAVA_OPT="${JAVA_OPT} -XX:-UseLargePages -XX:-UseBiasedLocking"
+JAVA_OPT="${JAVA_OPT} -Djava.ext.dirs=${JAVA_HOME}/jre/lib/ext:${BASE_DIR}/lib"
+#JAVA_OPT="${JAVA_OPT} -Xdebug -Xrunjdwp:transport=dt_socket,address=9555,server=y,suspend=n"
+JAVA_OPT="${JAVA_OPT} ${JAVA_OPT_EXT}"
+JAVA_OPT="${JAVA_OPT} -cp ${CLASSPATH}"
+
+numactl --interleave=all pwd > /dev/null 2>&1
+if [ $? -eq 0 ]
+then
+	if [ -z "$RMQ_NUMA_NODE" ] ; then
+		numactl --interleave=all $JAVA ${JAVA_OPT} $@
+	else
+		numactl --cpunodebind=$RMQ_NUMA_NODE --membind=$RMQ_NUMA_NODE $JAVA ${JAVA_OPT} $@
+	fi
+else
+	$JAVA ${JAVA_OPT} $@
+fi
diff --git a/templates/scripts/runserver-customize.sh b/templates/scripts/runserver-customize.sh
new file mode 100755
index 0000000..4cefb00
--- /dev/null
+++ b/templates/scripts/runserver-customize.sh
@@ -0,0 +1,70 @@
+#!/bin/sh
+
+# 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.
+
+#===========================================================================================
+# Java Environment Setting
+#===========================================================================================
+error_exit ()
+{
+    echo "ERROR: $1 !!"
+    exit 1
+}
+
+[ ! -e "$JAVA_HOME/bin/java" ] && JAVA_HOME=$HOME/jdk/java
+[ ! -e "$JAVA_HOME/bin/java" ] && JAVA_HOME=/usr/java
+[ ! -e "$JAVA_HOME/bin/java" ] && error_exit "Please set the JAVA_HOME variable in your environment, We need java(x64)!"
+
+export JAVA_HOME
+export JAVA="$JAVA_HOME/bin/java"
+export BASE_DIR=$(dirname $0)/..
+export CLASSPATH=.:${BASE_DIR}/conf:${CLASSPATH}
+
+#===========================================================================================
+# JVM Configuration
+#===========================================================================================
+# Get the max heap used by a jvm, which used all the ram available to the container.
+if [ -z "$MAX_POSSIBLE_HEAP" ]
+then
+	MAX_POSSIBLE_RAM_STR=$(java -XX:+UnlockExperimentalVMOptions -XX:MaxRAMFraction=1 -XshowSettings:vm -version |& awk '/Max\. Heap Size \(Estimated\): [0-9KMG]+/{ print $5}')
+	MAX_POSSIBLE_RAM=$MAX_POSSIBLE_RAM_STR
+	CAL_UNIT=${MAX_POSSIBLE_RAM_STR: -1}
+	if [ "$CAL_UNIT" == "G" -o "$CAL_UNIT" == "g" ]; then
+		MAX_POSSIBLE_RAM=$(echo ${MAX_POSSIBLE_RAM_STR:0:${#MAX_POSSIBLE_RAM_STR}-1} `expr 1 \* 1024 \* 1024 \* 1024` | awk '{printf "%d",$1*$2}')
+	elif [ "$CAL_UNIT" == "M" -o "$CAL_UNIT" == "m" ]; then
+		MAX_POSSIBLE_RAM=$(echo ${MAX_POSSIBLE_RAM_STR:0:${#MAX_POSSIBLE_RAM_STR}-1} `expr 1 \* 1024 \* 1024` | awk '{printf "%d",$1*$2}')
+	elif [ "$CAL_UNIT" == "K" -o "$CAL_UNIT" == "k" ]; then
+		MAX_POSSIBLE_RAM=$(echo ${MAX_POSSIBLE_RAM_STR:0:${#MAX_POSSIBLE_RAM_STR}-1} `expr 1 \* 1024` | awk '{printf "%d",$1*$2}')
+	fi
+	MAX_POSSIBLE_HEAP=$[MAX_POSSIBLE_RAM/4]
+fi
+
+# Dynamically calculate parameters, for reference.
+Xms=$MAX_POSSIBLE_HEAP
+Xmx=$MAX_POSSIBLE_HEAP
+Xmn=$[MAX_POSSIBLE_HEAP/2]
+# Set for `JAVA_OPT`.
+JAVA_OPT="${JAVA_OPT} -server -Xms${Xms} -Xmx${Xmx} -Xmn${Xmn}"
+JAVA_OPT="${JAVA_OPT} -XX:+UseConcMarkSweepGC -XX:+UseCMSCompactAtFullCollection -XX:CMSInitiatingOccupancyFraction=70 -XX:+CMSParallelRemarkEnabled -XX:SoftRefLRUPolicyMSPerMB=0 -XX:+CMSClassUnloadingEnabled -XX:SurvivorRatio=8  -XX:-UseParNewGC"
+JAVA_OPT="${JAVA_OPT} -verbose:gc -Xloggc:/dev/shm/rmq_srv_gc.log -XX:+PrintGCDetails"
+JAVA_OPT="${JAVA_OPT} -XX:-OmitStackTraceInFastThrow"
+JAVA_OPT="${JAVA_OPT}  -XX:-UseLargePages"
+JAVA_OPT="${JAVA_OPT} -Djava.ext.dirs=${JAVA_HOME}/jre/lib/ext:${BASE_DIR}/lib"
+#JAVA_OPT="${JAVA_OPT} -Xdebug -Xrunjdwp:transport=dt_socket,address=9555,server=y,suspend=n"
+JAVA_OPT="${JAVA_OPT} ${JAVA_OPT_EXT}"
+JAVA_OPT="${JAVA_OPT} -cp ${CLASSPATH}"
+
+$JAVA ${JAVA_OPT} $@