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

wuzhiguo pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/bigtop-manager.git


The following commit(s) were added to refs/heads/main by this push:
     new a2bc56f0 BIGTOP-4445: Add Apache Doris to extra stack (#231)
a2bc56f0 is described below

commit a2bc56f031952ad6635c05d71238e98bbde68e90
Author: timyuer <[email protected]>
AuthorDate: Sat Jul 19 13:34:43 2025 +0800

    BIGTOP-4445: Add Apache Doris to extra stack (#231)
---
 .licenserc.yaml                                    |   2 +
 .../service/ComponentCommandServiceGrpcImpl.java   |   5 +-
 bigtop-manager-agent/src/main/resources/bin/env.sh |   4 +-
 bigtop-manager-bom/pom.xml                         |  13 ++
 .../bigtop/manager/common/constants/Constants.java |   2 +
 .../bigtop/manager/common/shell/ShellResult.java   |   4 +
 .../src/main/resources/scripts/setup-agent.sh      |   2 +
 .../services/doris/configuration/doris-be-conf.xml | 181 ++++++++++++++++++
 .../services/doris/configuration/doris-env.sh.xml  |  56 ++++++
 .../services/doris/configuration/doris-fe-conf.xml | 163 +++++++++++++++++
 .../doris/configuration/doris-sysctl.conf.xml      |  53 ++++++
 .../services/doris/configuration/doris.conf.xml    |  54 ++++++
 .../stacks/extra/1.0.0/services/doris/metainfo.xml |  75 ++++++++
 .../stacks/extra/1.0.0/services/doris/order.json   |   8 +
 .../bigtop-manager-stack-bigtop/pom.xml            | 108 -----------
 .../manager/stack/bigtop/utils/HdfsUtil.java       | 147 ---------------
 .../stack/core/utils/linux/LinuxFileUtils.java     |   1 +
 .../stack/core/utils/linux/LinuxOSUtils.java       |  11 ++
 .../bigtop-manager-stack-extra/pom.xml             |   4 +
 .../stack/extra/v1_0_0/doris/DorisBEScript.java    | 104 +++++++++++
 .../stack/extra/v1_0_0/doris/DorisFEScript.java    | 124 +++++++++++++
 .../stack/extra/v1_0_0/doris/DorisParams.java      | 202 +++++++++++++++++++++
 .../stack/extra/v1_0_0/doris/DorisService.java     | 185 +++++++++++++++++++
 .../stack/extra/v1_0_0/doris/DorisSetup.java       | 110 +++++++++++
 .../stack/extra/v1_0_0/doris/DorisTool.java        | 109 +++++++++++
 bigtop-manager-ui/src/assets/images/doris.png      | Bin 0 -> 5456 bytes
 26 files changed, 1470 insertions(+), 257 deletions(-)

diff --git a/.licenserc.yaml b/.licenserc.yaml
index d880a9c7..4276c965 100644
--- a/.licenserc.yaml
+++ b/.licenserc.yaml
@@ -50,6 +50,8 @@ dependency:
     - pom.xml
     - bigtop-manager-bom/pom.xml
   licenses:
+    - name: org.apache.arrow:flight-sql-jdbc-driver
+      license: Apache-2.0
     - name: org.apache.hadoop.thirdparty:hadoop-shaded-protobuf_3_7
       license: Apache-2.0
     - name: org.apache.hadoop.thirdparty:hadoop-shaded-guava
diff --git 
a/bigtop-manager-agent/src/main/java/org/apache/bigtop/manager/agent/grpc/service/ComponentCommandServiceGrpcImpl.java
 
b/bigtop-manager-agent/src/main/java/org/apache/bigtop/manager/agent/grpc/service/ComponentCommandServiceGrpcImpl.java
index 2a091a4e..50171d76 100644
--- 
a/bigtop-manager-agent/src/main/java/org/apache/bigtop/manager/agent/grpc/service/ComponentCommandServiceGrpcImpl.java
+++ 
b/bigtop-manager-agent/src/main/java/org/apache/bigtop/manager/agent/grpc/service/ComponentCommandServiceGrpcImpl.java
@@ -18,6 +18,7 @@
  */
 package org.apache.bigtop.manager.agent.grpc.service;
 
+import org.apache.bigtop.manager.agent.cache.Caches;
 import org.apache.bigtop.manager.common.shell.ShellResult;
 import org.apache.bigtop.manager.common.utils.JsonUtils;
 import org.apache.bigtop.manager.grpc.generated.ComponentCommandReply;
@@ -36,8 +37,10 @@ public class ComponentCommandServiceGrpcImpl extends 
ComponentCommandServiceGrpc
 
     @Override
     public void exec(ComponentCommandRequest request, 
StreamObserver<ComponentCommandReply> responseObserver) {
-        ComponentCommandPayload payload = 
JsonUtils.readFromString(request.getPayload(), ComponentCommandPayload.class);
         try {
+            log.info("Running task {}", Caches.RUNNING_TASK);
+            ComponentCommandPayload payload =
+                    JsonUtils.readFromString(request.getPayload(), 
ComponentCommandPayload.class);
             ShellResult shellResult = StackExecutor.execute(payload);
             ComponentCommandReply reply = ComponentCommandReply.newBuilder()
                     .setCode(shellResult.getExitCode())
diff --git a/bigtop-manager-agent/src/main/resources/bin/env.sh 
b/bigtop-manager-agent/src/main/resources/bin/env.sh
index 882b68eb..20efe35f 100755
--- a/bigtop-manager-agent/src/main/resources/bin/env.sh
+++ b/bigtop-manager-agent/src/main/resources/bin/env.sh
@@ -62,5 +62,7 @@ find_java() {
 
 find_java
 
-export JAVA_OPTS=""
+JAVA_OPTS="-server -Duser.timezone=${SPRING_JACKSON_TIME_ZONE} -Xms4g -Xmx4g 
-Xmn2g -XX:+IgnoreUnrecognizedVMOptions -XX:+PrintGCDateStamps 
-XX:+PrintGCDetails -Xloggc:gc.log -XX:+HeapDumpOnOutOfMemoryError 
-XX:HeapDumpPath=dump.hprof"
+JAVA_OPTS="${JAVA_OPTS} 
--add-opens=java.base/java.nio=org.apache.arrow.memory.core,ALL-UNNAMED"
+export JAVA_OPTS
 export JAVA_CMD
diff --git a/bigtop-manager-bom/pom.xml b/bigtop-manager-bom/pom.xml
index 4b078b9f..a361d541 100644
--- a/bigtop-manager-bom/pom.xml
+++ b/bigtop-manager-bom/pom.xml
@@ -57,6 +57,8 @@
         
<mybatis-spring-boot-starter.version>3.0.3</mybatis-spring-boot-starter.version>
         
<pagehelper-spring-boot-starter.version>2.1.0</pagehelper-spring-boot-starter.version>
         <victools.version>4.29.0</victools.version>
+        <arrow.version>18.3.0</arrow.version>
+        <netty-buffer.version>4.1.123.Final</netty-buffer.version>
     </properties>
 
     <dependencyManagement>
@@ -237,7 +239,18 @@
                 <scope>provided</scope>
             </dependency>
 
+            <dependency>
+                <groupId>org.apache.arrow</groupId>
+                <artifactId>flight-sql-jdbc-driver</artifactId>
+                <version>${arrow.version}</version>
+            </dependency>
+
             <!-- gRPC -->
+            <dependency>
+                <groupId>io.grpc</groupId>
+                <artifactId>grpc-netty</artifactId>
+                <version>${grpc.version}</version>
+            </dependency>
             <dependency>
                 <groupId>io.grpc</groupId>
                 <artifactId>grpc-stub</artifactId>
diff --git 
a/bigtop-manager-common/src/main/java/org/apache/bigtop/manager/common/constants/Constants.java
 
b/bigtop-manager-common/src/main/java/org/apache/bigtop/manager/common/constants/Constants.java
index d0dbf94c..e5ff45c7 100644
--- 
a/bigtop-manager-common/src/main/java/org/apache/bigtop/manager/common/constants/Constants.java
+++ 
b/bigtop-manager-common/src/main/java/org/apache/bigtop/manager/common/constants/Constants.java
@@ -33,4 +33,6 @@ public final class Constants {
     public static final String PERMISSION_777 = "777";
 
     public static final String ROOT_USER = "root";
+
+    public static final String ROOT_GROUP = "root";
 }
diff --git 
a/bigtop-manager-common/src/main/java/org/apache/bigtop/manager/common/shell/ShellResult.java
 
b/bigtop-manager-common/src/main/java/org/apache/bigtop/manager/common/shell/ShellResult.java
index eb998e1b..a5642b28 100644
--- 
a/bigtop-manager-common/src/main/java/org/apache/bigtop/manager/common/shell/ShellResult.java
+++ 
b/bigtop-manager-common/src/main/java/org/apache/bigtop/manager/common/shell/ShellResult.java
@@ -62,4 +62,8 @@ public class ShellResult {
     public static ShellResult fail() {
         return fail("Run shell fail.");
     }
+
+    public String formatMessage(String message) {
+        return MessageFormat.format(message + ", output: [{0}], err: [{1}]", 
output, errMsg);
+    }
 }
diff --git a/bigtop-manager-server/src/main/resources/scripts/setup-agent.sh 
b/bigtop-manager-server/src/main/resources/scripts/setup-agent.sh
index fdeda989..a7bdaef6 100644
--- a/bigtop-manager-server/src/main/resources/scripts/setup-agent.sh
+++ b/bigtop-manager-server/src/main/resources/scripts/setup-agent.sh
@@ -38,6 +38,8 @@ error () {
 }
 
 check_sudo() {
+    # Refresh sudo privileges, currently only appears in openEuler24.03
+    sudo visudo -c 2>/dev/null || true
     if ! sudo -n true 2>/dev/null; then
         error "User '$USER' doesn't have sudo privileges"
         exit 1
diff --git 
a/bigtop-manager-server/src/main/resources/stacks/extra/1.0.0/services/doris/configuration/doris-be-conf.xml
 
b/bigtop-manager-server/src/main/resources/stacks/extra/1.0.0/services/doris/configuration/doris-be-conf.xml
new file mode 100644
index 00000000..5fed4359
--- /dev/null
+++ 
b/bigtop-manager-server/src/main/resources/stacks/extra/1.0.0/services/doris/configuration/doris-be-conf.xml
@@ -0,0 +1,181 @@
+<?xml version="1.0"?>
+<!--
+  ~ 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.
+-->
+
+<configuration>
+    <property>
+        <name>storage_root_path</name>
+        <display-name>storage_root_path</display-name>
+        <value>${doris_be_home}/storage</value>
+        <description>
+            data root path, separate by ';'.you can specify the storage medium 
of each root path, HDD or SSD.
+            you can add capacity limit at the end of each root path, separate 
by ','.
+            If the user does not use a mix of SSD and HDD disks,
+            they do not need to configure the configuration methods in Example 
1 and Example 2 below, but only need to specify the storage directory;
+            they also do not need to modify the default storage media 
configuration of FE.
+        </description>
+    </property>
+    <property>
+        <name>be_port</name>
+        <value>9060</value>
+        <description>The port of the thrift server on BE which used to receive 
requests from FE.</description>
+    </property>
+    <property>
+        <name>webserver_port</name>
+        <value>8041</value>
+    </property>
+    <property>
+        <name>heartbeat_service_port</name>
+        <value>9050</value>
+        <description>Heartbeat service port (thrift) on BE, used to receive 
heartbeat from FE.</description>
+    </property>
+    <property>
+        <name>brpc_port</name>
+        <value>8060</value>
+        <description>The port of BRPC on BE, used for communication between 
BEs.</description>
+    </property>
+    <property>
+        <name>be_arrow_flight_sql_port</name>
+        <value>9091</value>
+        <description>be_arrow_flight_sql_port.</description>
+    </property>
+    <property>
+        <name>content</name>
+        <value>
+            <![CDATA[
+# 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_HOME=${java_home}
+
+CUR_DATE=`date +%Y%m%d-%H%M%S`
+
+JAVA_HOME=${java_home}
+
+# Log dir
+LOG_DIR=${doris_be_log_dir}
+PID_DIR=${doris_be_pid_dir}
+
+# For jdk 8
+JAVA_OPTS="-Dfile.encoding=UTF-8 -Xmx4096m -DlogPath=$LOG_DIR/jni.log 
-Xloggc:$DORIS_HOME/log/be.gc.log.$CUR_DATE 
-Djavax.security.auth.useSubjectCredsOnly=false -Dsun.security.krb5.debug=true 
-Dsun.java.command=DorisBE -XX:-CriticalJNINatives"
+
+# For jdk 9+, this JAVA_OPTS will be used as default JVM options
+JAVA_OPTS_FOR_JDK_9="-Dfile.encoding=UTF-8 -Xmx4096m 
-DlogPath=$DORIS_HOME/log/jni.log -Xlog:gc:$LOG_DIR/be.gc.log.$CUR_DATE 
-Djavax.security.auth.useSubjectCredsOnly=false -Dsun.security.krb5.debug=true 
-Dsun.java.command=DorisBE -XX:-CriticalJNINatives 
--add-opens=java.base/java.nio=ALL-UNNAMED"
+
+# For jdk 17+, this JAVA_OPTS will be used as default JVM options
+JAVA_OPTS_FOR_JDK_17="-Dfile.encoding=UTF-8 -Xmx4096m 
-DlogPath=$LOG_DIR/jni.log -Xlog:gc:$LOG_DIR/be.gc.log.$CUR_DATE 
-Djavax.security.auth.useSubjectCredsOnly=false -Dsun.security.krb5.debug=true 
-Dsun.java.command=DorisBE -XX:-CriticalJNINatives 
--add-opens=java.base/java.net=ALL-UNNAMED 
--add-opens=java.base/java.nio=ALL-UNNAMED"
+
+# since 1.2, the JAVA_HOME need to be set to run BE process.
+# JAVA_HOME=/path/to/jdk/
+
+# 
https://github.com/apache/doris/blob/master/docs/zh-CN/community/developer-guide/debug-tool.md#jemalloc-heap-profile
+# https://jemalloc.net/jemalloc.3.html
+JEMALLOC_CONF="percpu_arena:percpu,background_thread:true,metadata_thp:auto,muzzy_decay_ms:5000,dirty_decay_ms:5000,oversize_threshold:0,prof:false,lg_prof_interval:-1"
+JEMALLOC_PROF_PRFIX="jemalloc_heap_profile_"
+
+# ports for admin, web, heartbeat service
+be_port = ${be_port}
+webserver_port = ${webserver_port}
+heartbeat_service_port = ${heartbeat_service_port}
+brpc_port = ${brpc_port}
+arrow_flight_sql_port = ${be_arrow_flight_sql_port}
+
+# HTTPS configures
+enable_https = false
+# path of certificate in PEM format.
+ssl_certificate_path = "$DORIS_HOME/conf/cert.pem"
+# path of private key in PEM format.
+ssl_private_key_path = "$DORIS_HOME/conf/key.pem"
+
+
+# Choose one if there are more than one ip except loopback address.
+# Note that there should at most one ip match this list.
+# If no ip match this rule, will choose one randomly.
+# use CIDR format, e.g. 10.10.10.0/24 or IP format, e.g. 10.10.10.1
+# Default value is empty.
+# priority_networks = 10.10.10.0/24;192.168.0.0/16
+
+# data root path, separate by ';'
+# You can specify the storage type for each root path, HDD (cold data) or SSD 
(hot data)
+# eg:
+# storage_root_path = /home/disk1/doris;/home/disk2/doris;/home/disk2/doris
+# storage_root_path = 
/home/disk1/doris,medium:SSD;/home/disk2/doris,medium:SSD;/home/disk2/doris,medium:HDD
+# /home/disk2/doris,medium:HDD(default)
+#
+# you also can specify the properties by setting '<property>:<value>', 
separate by ','
+# property 'medium' has a higher priority than the extension of path
+#
+# Default value is ${DORIS_HOME}/storage, you should create it by hand.
+# storage_root_path = ${DORIS_HOME}/storage
+storage_root_path = ${storage_root_path}
+
+# Default dirs to put jdbc drivers,default value is ${DORIS_HOME}/jdbc_drivers
+# jdbc_drivers_dir = ${DORIS_HOME}/jdbc_drivers
+
+# Advanced configurations
+# INFO, WARNING, ERROR, FATAL
+sys_log_level = INFO
+# sys_log_roll_mode = SIZE-MB-1024
+# sys_log_roll_num = 10
+# sys_log_verbose_modules = *
+# log_buffer_level = -1
+# palo_cgroups
+
+# aws sdk log level
+#    Off = 0,
+#    Fatal = 1,
+#    Error = 2,
+#    Warn = 3,
+#    Info = 4,
+#    Debug = 5,
+#    Trace = 6
+# Default to turn off aws sdk log, because aws sdk errors that need to be 
cared will be output through Doris logs
+aws_log_level=0
+## If you are not running in aws cloud, you can disable EC2 metadata
+AWS_EC2_METADATA_DISABLED=true
+
+sys_log_dir = ${doris_be_log_dir}
+
+enable_query_memory_overcommit=true
+enable_single_replica_load =true
+
+enable_token_check = false
+
+]]>
+        </value>
+        <description>Template for be.conf</description>
+        <attrs>
+            <type>longtext</type>
+        </attrs>
+    </property>
+</configuration>
diff --git 
a/bigtop-manager-server/src/main/resources/stacks/extra/1.0.0/services/doris/configuration/doris-env.sh.xml
 
b/bigtop-manager-server/src/main/resources/stacks/extra/1.0.0/services/doris/configuration/doris-env.sh.xml
new file mode 100644
index 00000000..b4d9887a
--- /dev/null
+++ 
b/bigtop-manager-server/src/main/resources/stacks/extra/1.0.0/services/doris/configuration/doris-env.sh.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0"?>
+<!--
+  ~ 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.
+-->
+
+<configuration>
+    <property>
+        <name>doris_fe_log_dir</name>
+        <value>${doris_fe_home}/log</value>
+    </property>
+    <property>
+        <name>doris_be_log_dir</name>
+        <value>${doris_be_home}/log</value>
+    </property>
+    <property>
+        <name>doris_fe_pid_dir</name>
+        <value>/var/run/doris-fe</value>
+        <display-name>doris PID dir</display-name>
+    </property>
+    <property>
+        <name>doris_be_pid_dir</name>
+        <value>/var/run/doris-be</value>
+        <display-name>doris PID dir</display-name>
+    </property>
+    <property>
+        <name>doris_user_nofile_soft</name>
+        <value>262144</value>
+        <description>Max open files limit setting for doris user.</description>
+    </property>
+    <property>
+        <name>doris_user_nofile_hard</name>
+        <value>262144</value>
+        <description>Max number of processes limit setting for doris 
user.</description>
+    </property>
+    <property>
+        <name>vm_max_map_count</name>
+        <value>2000000</value>
+        <description>Max number of processes limit setting for doris 
user.</description>
+    </property>
+</configuration>
+
diff --git 
a/bigtop-manager-server/src/main/resources/stacks/extra/1.0.0/services/doris/configuration/doris-fe-conf.xml
 
b/bigtop-manager-server/src/main/resources/stacks/extra/1.0.0/services/doris/configuration/doris-fe-conf.xml
new file mode 100644
index 00000000..d6ee0452
--- /dev/null
+++ 
b/bigtop-manager-server/src/main/resources/stacks/extra/1.0.0/services/doris/configuration/doris-fe-conf.xml
@@ -0,0 +1,163 @@
+<?xml version="1.0"?>
+<!--
+  ~ 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.
+-->
+
+<configuration>
+    <property>
+        <name>meta_dir</name>
+        <display-name>meta_dir</display-name>
+        <value>${doris_fe_home}/doris-meta</value>
+        <description>Default: DORIS_HOME_DIR + "/doris-meta".
+            Doris meta data will be saved here.The storage of this dir is 
highly recommended as to be.</description>
+    </property>
+    <property>
+        <name>http_port</name>
+        <value>8030</value>
+        <description>HTTP bind port. All FE http ports must be same 
currently.</description>
+    </property>
+    <property>
+        <name>query_port</name>
+        <value>9030</value>
+        <description>FE MySQL server port.</description>
+    </property>
+    <property>
+        <name>rpc_port</name>
+        <value>9020</value>
+        <description>FE Thrift Server port.</description>
+    </property>
+    <property>
+        <name>edit_log_port</name>
+        <value>9010</value>
+        <description>edit log port.</description>
+    </property>
+    <property>
+        <name>fe_arrow_flight_sql_port</name>
+        <value>9090</value>
+        <description>fe_arrow_flight_sql_port.</description>
+    </property>
+    <property>
+        <name>content</name>
+        <value>
+            <![CDATA[
+# 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.
+
+#####################################################################
+## The uppercase properties are read and exported by bin/start_fe.sh.
+## To see all Frontend configurations,
+## see fe/src/org/apache/doris/common/Config.java
+#####################################################################
+
+JAVA_HOME=${java_home}
+
+CUR_DATE=`date +%Y%m%d-%H%M%S`
+
+# Log dir
+LOG_DIR = ${doris_fe_log_dir}
+PID_DIR=${doris_fe_pid_dir}
+
+# CMS JAVA OPTS
+# JAVA_OPTS="-Dsun.security.krb5.debug=true 
-Djavax.security.auth.useSubjectCredsOnly=false -Xss4m -Xmx8192m -XX:+UseMembar 
-XX:SurvivorRatio=8 -XX:MaxTenuringThreshold=7 -XX:+PrintGCDateStamps 
-XX:+PrintGCDetails -XX:+UseConcMarkSweepGC -XX:+UseParNewGC 
-XX:+CMSClassUnloadingEnabled -XX:-CMSParallelRemarkEnabled 
-XX:CMSInitiatingOccupancyFraction=80 -XX:SoftRefLRUPolicyMSPerMB=0 
-Xloggc:$DORIS_HOME/log/fe.gc.log.$CUR_DATE"
+
+# G1 JAVA OPTS
+JAVA_OPTS="-Dfile.encoding=UTF-8 
-Djavax.security.auth.useSubjectCredsOnly=false -Xss4m -Xmx4096m 
-XX:+UnlockExperimentalVMOptions -XX:+UseG1GC -XX:MaxGCPauseMillis=200 
-XX:+PrintGCDateStamps -XX:+PrintGCDetails -Xloggc:$LOG_DIR/fe.gc.log.$CUR_DATE 
-Dlog4j2.formatMsgNoLookups=true"
+
+# For jdk 9+, this JAVA_OPTS_FOR_JDK_9 will be used as default CMS JVM options
+# JAVA_OPTS_FOR_JDK_9="-Dsun.security.krb5.debug=true 
-Djavax.security.auth.useSubjectCredsOnly=false -Xss4m -Xmx8192m 
-XX:SurvivorRatio=8 -XX:MaxTenuringThreshold=7 -XX:+CMSClassUnloadingEnabled 
-XX:-CMSParallelRemarkEnabled -XX:CMSInitiatingOccupancyFraction=80 
-XX:SoftRefLRUPolicyMSPerMB=0 
-Xlog:gc*:$DORIS_HOME/log/fe.gc.log.$CUR_DATE:time"
+
+# For jdk 9+, this JAVA_OPTS_FOR_JDK_9 will be used as default G1 JVM options
+JAVA_OPTS_FOR_JDK_9="-Dfile.encoding=UTF-8 
-Djavax.security.auth.useSubjectCredsOnly=false -Xss4m -Xmx4096m -XX:+UseG1GC 
-XX:MaxGCPauseMillis=200 -Xlog:gc*:$LOG_DIR/fe.gc.log.$CUR_DATE:time 
-Dlog4j2.formatMsgNoLookups=true"
+
+# For jdk 17+, this JAVA_OPTS will be used as default JVM options
+JAVA_OPTS_FOR_JDK_17="-Dfile.encoding=UTF-8 
-Djavax.security.auth.useSubjectCredsOnly=false -XX:+UseZGC -Xmx4096m -Xms8192m 
-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=$LOG_DIR/ 
-Xlog:gc*:$LOG_DIR/fe.gc.log.$CUR_DATE:time"
+
+##
+## the lowercase properties are read by main program.
+##
+
+# store metadata, must be created before start FE.
+# Default value is ${DORIS_HOME}/doris-meta
+# meta_dir = ${DORIS_HOME}/doris-meta
+meta_dir = ${meta_dir}
+
+# Default dirs to put jdbc drivers,default value is ${DORIS_HOME}/jdbc_drivers
+# jdbc_drivers_dir = ${DORIS_HOME}/jdbc_drivers
+
+
+http_port = ${http_port}
+rpc_port = ${rpc_port}
+query_port = ${query_port}
+edit_log_port = ${edit_log_port}
+arrow_flight_sql_port = ${fe_arrow_flight_sql_port}
+
+# Choose one if there are more than one ip except loopback address.
+# Note that there should at most one ip match this list.
+# If no ip match this rule, will choose one randomly.
+# use CIDR format, e.g. 10.10.10.0/24 or IP format, e.g. 10.10.10.1
+# Default value is empty.
+# priority_networks = 10.10.10.0/24;192.168.0.0/16
+
+# Advanced configurations
+# log_roll_size_mb = 1024
+# INFO, WARN, ERROR, FATAL
+sys_log_level = INFO
+# NORMAL, BRIEF, ASYNC
+sys_log_mode = NORMAL
+# sys_log_roll_num = 10
+# sys_log_verbose_modules = org.apache.doris
+# audit_log_dir = $LOG_DIR
+# audit_log_modules = slow_query, query
+# audit_log_roll_num = 10
+# meta_delay_toleration_second = 10
+# qe_max_connection = 1024
+# qe_query_timeout_second = 300
+# qe_slow_log_ms = 5000
+
+sys_log_dir = ${doris_fe_log_dir}
+audit_log_dir = ${doris_fe_log_dir}
+
+# FQDN
+enable_fqdn_mode = true
+
+enable_single_replica_load = true
+
+enable_token_check = false
+
+]]>
+        </value>
+        <description>Template for fe.conf</description>
+        <attrs>
+            <type>longtext</type>
+        </attrs>
+    </property>
+</configuration>
diff --git 
a/bigtop-manager-server/src/main/resources/stacks/extra/1.0.0/services/doris/configuration/doris-sysctl.conf.xml
 
b/bigtop-manager-server/src/main/resources/stacks/extra/1.0.0/services/doris/configuration/doris-sysctl.conf.xml
new file mode 100644
index 00000000..d8e57eda
--- /dev/null
+++ 
b/bigtop-manager-server/src/main/resources/stacks/extra/1.0.0/services/doris/configuration/doris-sysctl.conf.xml
@@ -0,0 +1,53 @@
+<?xml version="1.0"?>
+<!--
+  ~ 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.
+-->
+
+<configuration>
+    <property>
+        <name>content</name>
+        <display-name>doris-sysctl.conf template</display-name>
+        <description>This is the freemarker template for 
/etc/sysctl.d/doris-sysctl.conf file</description>
+        <value><![CDATA[
+#
+# 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.
+#
+
+vm.max_map_count=${vm_max_map_count}
+
+]]>
+        </value>
+        <attrs>
+            <type>longtext</type>
+        </attrs>
+    </property>
+</configuration>
diff --git 
a/bigtop-manager-server/src/main/resources/stacks/extra/1.0.0/services/doris/configuration/doris.conf.xml
 
b/bigtop-manager-server/src/main/resources/stacks/extra/1.0.0/services/doris/configuration/doris.conf.xml
new file mode 100644
index 00000000..2822c641
--- /dev/null
+++ 
b/bigtop-manager-server/src/main/resources/stacks/extra/1.0.0/services/doris/configuration/doris.conf.xml
@@ -0,0 +1,54 @@
+<?xml version="1.0"?>
+<!--
+  ~ 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.
+-->
+
+<configuration>
+    <property>
+        <name>content</name>
+        <display-name>doris.conf template</display-name>
+        <description>This is the freemarker template for doris 
file</description>
+        <value><![CDATA[
+#
+# 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.
+#
+
+${doris_user}    - nofile   ${doris_user_nofile_soft}
+${doris_user}    - nproc    ${doris_user_nofile_hard}
+
+]]>
+        </value>
+        <attrs>
+            <type>longtext</type>
+        </attrs>
+    </property>
+</configuration>
diff --git 
a/bigtop-manager-server/src/main/resources/stacks/extra/1.0.0/services/doris/metainfo.xml
 
b/bigtop-manager-server/src/main/resources/stacks/extra/1.0.0/services/doris/metainfo.xml
new file mode 100644
index 00000000..8455abdf
--- /dev/null
+++ 
b/bigtop-manager-server/src/main/resources/stacks/extra/1.0.0/services/doris/metainfo.xml
@@ -0,0 +1,75 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ 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
+  ~
+  ~    https://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.
+-->
+
+<metainfo>
+    <service>
+        <name>doris</name>
+        <display-name>Doris</display-name>
+        <desc>
+            Apache Doris is a modern data warehouse for real-time analytics.
+            It delivers lightning-fast analytics on real-time data at scale.
+        </desc>
+        <version>2.1.10</version>
+        <user>doris</user>
+        <license>Apache-2.0</license>
+
+        <components>
+            <component>
+                <name>doris_fe</name>
+                <display-name>Doris Frontend</display-name>
+                <category>server</category>
+                <cardinality>1+</cardinality>
+            </component>
+
+            <component>
+                <name>doris_be</name>
+                <display-name>Doris Backend</display-name>
+                <category>server</category>
+                <cardinality>1+</cardinality>
+            </component>
+            
+        </components>
+
+        <package-specifics>
+            <package-specific>
+                <architectures>
+                    <arch>x86_64</arch>
+                </architectures>
+                <packages>
+                    <package>
+                        <name>apache-doris-2.1.10-bin-x64-noavx2.tar.gz</name>
+                        
<checksum>SHA-512:4238436ad0a6eedc4918018b90a71d39b59c640a96188a007ed109a8c317357bdb6bfd3ed7a8768ebf1d72df10dffd19f5c597235da5e693bd587f4326edcc14</checksum>
+                    </package>
+                </packages>
+            </package-specific>
+            <package-specific>
+                <architectures>
+                    <arch>aarch64</arch>
+                </architectures>
+                <packages>
+                    <package>
+                        <name>apache-doris-2.1.10-bin-arm64.tar.gz</name>
+                        
<checksum>SHA-512:bf9140c547d7b30ff25276fb8a44e443f8518876edd60d56460bc2e60f12c4200261ece60a43909b7c0cd4758621ba9fe85a58c29fb056a43947ee1d2fb27cea</checksum>
+                    </package>
+                </packages>
+            </package-specific>
+        </package-specifics>
+    </service>
+</metainfo>
diff --git 
a/bigtop-manager-server/src/main/resources/stacks/extra/1.0.0/services/doris/order.json
 
b/bigtop-manager-server/src/main/resources/stacks/extra/1.0.0/services/doris/order.json
new file mode 100644
index 00000000..dcb838c4
--- /dev/null
+++ 
b/bigtop-manager-server/src/main/resources/stacks/extra/1.0.0/services/doris/order.json
@@ -0,0 +1,8 @@
+{
+  "BE-START": [
+    "FE-START"
+  ],
+  "FE-STOP": [
+    "BE-STOP"
+  ]
+}
diff --git a/bigtop-manager-stack/bigtop-manager-stack-bigtop/pom.xml 
b/bigtop-manager-stack/bigtop-manager-stack-bigtop/pom.xml
index 3f5074e0..059ff7eb 100644
--- a/bigtop-manager-stack/bigtop-manager-stack-bigtop/pom.xml
+++ b/bigtop-manager-stack/bigtop-manager-stack-bigtop/pom.xml
@@ -39,114 +39,6 @@
             <groupId>org.apache.bigtop</groupId>
             <artifactId>bigtop-manager-stack-core</artifactId>
         </dependency>
-
-        <dependency>
-            <groupId>org.apache.hadoop</groupId>
-            <artifactId>hadoop-common</artifactId>
-            <version>${hadoop.version}</version>
-            <exclusions>
-                <exclusion>
-                    <groupId>log4j</groupId>
-                    <artifactId>log4j</artifactId>
-                </exclusion>
-                <exclusion>
-                    <groupId>org.slf4j</groupId>
-                    <artifactId>slf4j-log4j12</artifactId>
-                </exclusion>
-                <exclusion>
-                    <groupId>ch.qos.reload4j</groupId>
-                    <artifactId>reload4j</artifactId>
-                </exclusion>
-                <exclusion>
-                    <groupId>org.slf4j</groupId>
-                    <artifactId>slf4j-reload4j</artifactId>
-                </exclusion>
-                <exclusion>
-                    <groupId>org.apache.zookeeper</groupId>
-                    <artifactId>zookeeper</artifactId>
-                </exclusion>
-                <exclusion>
-                    <groupId>org.apache.zookeeper</groupId>
-                    <artifactId>zookeeper-jute</artifactId>
-                </exclusion>
-                <exclusion>
-                    <groupId>com.google.protobuf</groupId>
-                    <artifactId>protobuf-java</artifactId>
-                </exclusion>
-            </exclusions>
-        </dependency>
-
-        <dependency>
-            <groupId>org.apache.hadoop</groupId>
-            <artifactId>hadoop-hdfs</artifactId>
-            <version>${hadoop.version}</version>
-            <exclusions>
-                <exclusion>
-                    <groupId>log4j</groupId>
-                    <artifactId>log4j</artifactId>
-                </exclusion>
-                <exclusion>
-                    <groupId>org.slf4j</groupId>
-                    <artifactId>slf4j-log4j12</artifactId>
-                </exclusion>
-                <exclusion>
-                    <groupId>ch.qos.reload4j</groupId>
-                    <artifactId>reload4j</artifactId>
-                </exclusion>
-                <exclusion>
-                    <groupId>org.slf4j</groupId>
-                    <artifactId>slf4j-reload4j</artifactId>
-                </exclusion>
-                <exclusion>
-                    <groupId>org.apache.zookeeper</groupId>
-                    <artifactId>zookeeper</artifactId>
-                </exclusion>
-                <exclusion>
-                    <groupId>org.apache.zookeeper</groupId>
-                    <artifactId>zookeeper-jute</artifactId>
-                </exclusion>
-                <exclusion>
-                    <groupId>com.google.protobuf</groupId>
-                    <artifactId>protobuf-java</artifactId>
-                </exclusion>
-            </exclusions>
-        </dependency>
-
-        <dependency>
-            <groupId>org.apache.hadoop</groupId>
-            <artifactId>hadoop-client</artifactId>
-            <version>${hadoop.version}</version>
-            <exclusions>
-                <exclusion>
-                    <groupId>log4j</groupId>
-                    <artifactId>log4j</artifactId>
-                </exclusion>
-                <exclusion>
-                    <groupId>org.slf4j</groupId>
-                    <artifactId>slf4j-log4j12</artifactId>
-                </exclusion>
-                <exclusion>
-                    <groupId>ch.qos.reload4j</groupId>
-                    <artifactId>reload4j</artifactId>
-                </exclusion>
-                <exclusion>
-                    <groupId>org.slf4j</groupId>
-                    <artifactId>slf4j-reload4j</artifactId>
-                </exclusion>
-                <exclusion>
-                    <groupId>org.apache.zookeeper</groupId>
-                    <artifactId>zookeeper</artifactId>
-                </exclusion>
-                <exclusion>
-                    <groupId>org.apache.zookeeper</groupId>
-                    <artifactId>zookeeper-jute</artifactId>
-                </exclusion>
-                <exclusion>
-                    <groupId>com.google.protobuf</groupId>
-                    <artifactId>protobuf-java</artifactId>
-                </exclusion>
-            </exclusions>
-        </dependency>
     </dependencies>
 
 </project>
diff --git 
a/bigtop-manager-stack/bigtop-manager-stack-bigtop/src/main/java/org/apache/bigtop/manager/stack/bigtop/utils/HdfsUtil.java
 
b/bigtop-manager-stack/bigtop-manager-stack-bigtop/src/main/java/org/apache/bigtop/manager/stack/bigtop/utils/HdfsUtil.java
deleted file mode 100644
index d16b54ba..00000000
--- 
a/bigtop-manager-stack/bigtop-manager-stack-bigtop/src/main/java/org/apache/bigtop/manager/stack/bigtop/utils/HdfsUtil.java
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
- * 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
- *
- *    https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.bigtop.manager.stack.bigtop.utils;
-
-import org.apache.bigtop.manager.stack.core.exception.StackException;
-import org.apache.bigtop.manager.stack.core.utils.LocalSettings;
-
-import org.apache.commons.collections.CollectionUtils;
-import org.apache.hadoop.conf.Configuration;
-import org.apache.hadoop.fs.FileSystem;
-import org.apache.hadoop.fs.Path;
-import org.apache.hadoop.security.UserGroupInformation;
-
-import lombok.Data;
-import lombok.extern.slf4j.Slf4j;
-
-import java.io.File;
-import java.net.URI;
-import java.security.PrivilegedAction;
-import java.text.MessageFormat;
-import java.util.List;
-
-@Data
-@Slf4j
-public class HdfsUtil {
-
-    /**
-     * Create directory on hdfs if not exist
-     *
-     * @param user      the system user to create the directory, which will 
infect the directory permission
-     * @param directory the directory path on hdfs
-     */
-    public static void createDirectory(String user, String directory) {
-        UserGroupInformation ugi = UserGroupInformation.createRemoteUser(user);
-        try {
-            ugi.doAs((PrivilegedAction<Void>) () -> {
-                try (FileSystem fs = getFileSystem()) {
-                    // Create dest dir if not exist
-                    Path destDirPath = new Path(directory);
-                    if (!fs.exists(destDirPath)) {
-                        log.info("Creating directory [{}] on hdfs", 
destDirPath);
-                        fs.mkdirs(destDirPath);
-                    }
-                } catch (Exception e) {
-                    log.error("Error while creating directory on hdfs", e);
-                    throw new StackException(e);
-                }
-
-                return null;
-            });
-        } catch (Exception e) {
-            log.error("Error while creating directory on hdfs", e);
-            throw new StackException(e);
-        }
-    }
-
-    /**
-     * Upload file to hdfs, this will keep original filename on hdfs
-     *
-     * @param user          the system user to upload the file, which will 
infect the file permission
-     * @param localFilePath the local file path
-     * @param destDir       the destination directory on hdfs
-     */
-    public static void uploadFile(String user, String localFilePath, String 
destDir) {
-        uploadFile(user, localFilePath, destDir, null);
-    }
-
-    /**
-     * Upload file to hdfs
-     *
-     * @param user          the system user to upload the file, which will 
infect the file permission
-     * @param localFilePath the local file path
-     * @param destDir       the destination directory on hdfs
-     * @param destFilename  the destination filename on hdfs, if null, use the 
original filename
-     */
-    public static void uploadFile(String user, String localFilePath, String 
destDir, String destFilename) {
-        UserGroupInformation ugi = UserGroupInformation.createRemoteUser(user);
-        try {
-            ugi.doAs((PrivilegedAction<Void>) () -> {
-                try (FileSystem fs = getFileSystem()) {
-                    // Create dest dir if not exist
-                    Path destDirPath = new Path(destDir);
-                    if (!fs.exists(destDirPath)) {
-                        log.info("Creating directory [{}] on hdfs", 
destDirPath);
-                        fs.mkdirs(destDirPath);
-                    }
-
-                    // upload file
-                    String filename = destFilename == null
-                            ? 
localFilePath.substring(localFilePath.lastIndexOf(File.separator) + 1)
-                            : destFilename;
-                    Path destFilePath = new Path(destDir, filename);
-                    if (!fs.exists(destFilePath)) {
-                        log.info("Uploading [{}] to hdfs [{}]", localFilePath, 
destFilePath);
-                        fs.copyFromLocalFile(new Path(localFilePath), 
destFilePath);
-                    }
-                } catch (Exception e) {
-                    log.error("Error while uploading file to hdfs", e);
-                    throw new StackException(e);
-                }
-
-                return null;
-            });
-        } catch (Exception e) {
-            log.error("Error while uploading file to hdfs", e);
-            throw new StackException(e);
-        }
-    }
-
-    /**
-     * Get the hdfs FileSystem instance
-     *
-     * @return the hdfs FileSystem instance
-     * @throws Exception if any error occurs
-     */
-    private static FileSystem getFileSystem() throws Exception {
-        Configuration conf = new Configuration();
-        conf.addResource(new Path("/etc/hadoop/conf/core-site.xml"));
-        conf.addResource(new Path("/etc/hadoop/conf/hdfs-site.xml"));
-
-        List<String> namenodeList = LocalSettings.hosts("namenode");
-        if (CollectionUtils.isEmpty(namenodeList)) {
-            String msg = "No namenode found in the cluster";
-            log.error(msg);
-            throw new StackException(msg);
-        }
-
-        String hdfsUri = MessageFormat.format("hdfs://{0}:8020", 
namenodeList.get(0));
-        return FileSystem.get(new URI(hdfsUri), conf);
-    }
-}
diff --git 
a/bigtop-manager-stack/bigtop-manager-stack-core/src/main/java/org/apache/bigtop/manager/stack/core/utils/linux/LinuxFileUtils.java
 
b/bigtop-manager-stack/bigtop-manager-stack-core/src/main/java/org/apache/bigtop/manager/stack/core/utils/linux/LinuxFileUtils.java
index fbee45be..3d4d1b7f 100644
--- 
a/bigtop-manager-stack/bigtop-manager-stack-core/src/main/java/org/apache/bigtop/manager/stack/core/utils/linux/LinuxFileUtils.java
+++ 
b/bigtop-manager-stack/bigtop-manager-stack-core/src/main/java/org/apache/bigtop/manager/stack/core/utils/linux/LinuxFileUtils.java
@@ -178,6 +178,7 @@ public class LinuxFileUtils {
         try {
             ShellResult shellResult = sudoExecCmd(builderParameters);
             if (shellResult.getExitCode() != MessageConstants.SUCCESS_CODE) {
+                log.error(shellResult.formatMessage("Failed to create 
directory"));
                 throw new StackException(shellResult.getErrMsg());
             }
         } catch (IOException e) {
diff --git 
a/bigtop-manager-stack/bigtop-manager-stack-core/src/main/java/org/apache/bigtop/manager/stack/core/utils/linux/LinuxOSUtils.java
 
b/bigtop-manager-stack/bigtop-manager-stack-core/src/main/java/org/apache/bigtop/manager/stack/core/utils/linux/LinuxOSUtils.java
index 916dea6f..f105e659 100644
--- 
a/bigtop-manager-stack/bigtop-manager-stack-core/src/main/java/org/apache/bigtop/manager/stack/core/utils/linux/LinuxOSUtils.java
+++ 
b/bigtop-manager-stack/bigtop-manager-stack-core/src/main/java/org/apache/bigtop/manager/stack/core/utils/linux/LinuxOSUtils.java
@@ -39,6 +39,17 @@ import static 
org.apache.bigtop.manager.common.constants.Constants.ROOT_USER;
 @NoArgsConstructor(access = AccessLevel.PRIVATE)
 public class LinuxOSUtils {
 
+    /**
+     * Execute command with root user
+     *
+     * @param command command
+     * @return result of execute command
+     * @throws IOException errors
+     */
+    public static ShellResult sudoExecCmd(String command) throws IOException {
+        return sudoExecCmd(command, null);
+    }
+
     /**
      * Execute the sudo command
      *
diff --git a/bigtop-manager-stack/bigtop-manager-stack-extra/pom.xml 
b/bigtop-manager-stack/bigtop-manager-stack-extra/pom.xml
index 6666ed4f..656610e1 100644
--- a/bigtop-manager-stack/bigtop-manager-stack-extra/pom.xml
+++ b/bigtop-manager-stack/bigtop-manager-stack-extra/pom.xml
@@ -34,5 +34,9 @@
             <groupId>org.apache.bigtop</groupId>
             <artifactId>bigtop-manager-stack-core</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.apache.arrow</groupId>
+            <artifactId>flight-sql-jdbc-driver</artifactId>
+        </dependency>
     </dependencies>
 </project>
diff --git 
a/bigtop-manager-stack/bigtop-manager-stack-extra/src/main/java/org/apache/bigtop/manager/stack/extra/v1_0_0/doris/DorisBEScript.java
 
b/bigtop-manager-stack/bigtop-manager-stack-extra/src/main/java/org/apache/bigtop/manager/stack/extra/v1_0_0/doris/DorisBEScript.java
new file mode 100644
index 00000000..dd55b12a
--- /dev/null
+++ 
b/bigtop-manager-stack/bigtop-manager-stack-extra/src/main/java/org/apache/bigtop/manager/stack/extra/v1_0_0/doris/DorisBEScript.java
@@ -0,0 +1,104 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *    https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.bigtop.manager.stack.extra.v1_0_0.doris;
+
+import org.apache.bigtop.manager.common.constants.MessageConstants;
+import org.apache.bigtop.manager.common.shell.ShellResult;
+import org.apache.bigtop.manager.stack.core.exception.StackException;
+import org.apache.bigtop.manager.stack.core.spi.param.Params;
+import org.apache.bigtop.manager.stack.core.spi.script.AbstractServerScript;
+import org.apache.bigtop.manager.stack.core.spi.script.Script;
+import org.apache.bigtop.manager.stack.core.utils.linux.LinuxFileUtils;
+import org.apache.bigtop.manager.stack.core.utils.linux.LinuxOSUtils;
+
+import com.google.auto.service.AutoService;
+import lombok.extern.slf4j.Slf4j;
+
+import java.io.IOException;
+import java.text.MessageFormat;
+import java.util.Properties;
+
+@Slf4j
+@AutoService(Script.class)
+public class DorisBEScript extends AbstractServerScript {
+
+    @Override
+    public ShellResult add(Params params) {
+        Properties properties = new Properties();
+        properties.setProperty(PROPERTY_KEY_SKIP_LEVELS, "1");
+
+        return super.add(params, properties);
+    }
+
+    @Override
+    public ShellResult configure(Params params) {
+        super.configure(params);
+
+        try {
+            return DorisSetup.config(params, "doris_be");
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    @Override
+    public ShellResult start(Params params) {
+        configure(params);
+        DorisParams dorisParams = (DorisParams) params;
+        LinuxFileUtils.removeDirectories(dorisParams.dorisBePidFile());
+
+        String cmd = MessageFormat.format("{0}/start_be.sh --daemon", 
dorisParams.dorisBeBinDir());
+        try {
+            ShellResult sr = LinuxOSUtils.sudoExecCmd(cmd, dorisParams.user());
+            if (sr.getExitCode() != MessageConstants.SUCCESS_CODE) {
+                throw new StackException(sr.formatMessage("Failed to start 
Doris BE"));
+            }
+        } catch (Exception e) {
+            throw new StackException(e);
+        }
+
+        // Register BE
+        DorisService.registerBe(dorisParams);
+        return ShellResult.success();
+    }
+
+    @Override
+    public ShellResult stop(Params params) {
+        DorisParams dorisParams = (DorisParams) params;
+        String cmd = MessageFormat.format("{0}/stop_be.sh", 
dorisParams.dorisBeBinDir());
+        try {
+            ShellResult shellResult = LinuxOSUtils.sudoExecCmd(cmd, 
dorisParams.user());
+            LinuxFileUtils.removeDirectories(dorisParams.dorisBePidDir());
+            return shellResult;
+        } catch (Exception e) {
+            throw new StackException(e);
+        }
+    }
+
+    @Override
+    public ShellResult status(Params params) {
+        DorisParams dorisParams = (DorisParams) params;
+        return LinuxOSUtils.checkProcess(dorisParams.dorisBePidFile());
+    }
+
+    @Override
+    public String getComponentName() {
+        return "doris_be";
+    }
+}
diff --git 
a/bigtop-manager-stack/bigtop-manager-stack-extra/src/main/java/org/apache/bigtop/manager/stack/extra/v1_0_0/doris/DorisFEScript.java
 
b/bigtop-manager-stack/bigtop-manager-stack-extra/src/main/java/org/apache/bigtop/manager/stack/extra/v1_0_0/doris/DorisFEScript.java
new file mode 100644
index 00000000..204d2e64
--- /dev/null
+++ 
b/bigtop-manager-stack/bigtop-manager-stack-extra/src/main/java/org/apache/bigtop/manager/stack/extra/v1_0_0/doris/DorisFEScript.java
@@ -0,0 +1,124 @@
+/*
+ * 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
+ *
+ *    https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.bigtop.manager.stack.extra.v1_0_0.doris;
+
+import org.apache.bigtop.manager.common.shell.ShellResult;
+import org.apache.bigtop.manager.stack.core.exception.StackException;
+import org.apache.bigtop.manager.stack.core.spi.param.Params;
+import org.apache.bigtop.manager.stack.core.spi.script.AbstractServerScript;
+import org.apache.bigtop.manager.stack.core.spi.script.Script;
+import org.apache.bigtop.manager.stack.core.utils.linux.LinuxFileUtils;
+import org.apache.bigtop.manager.stack.core.utils.linux.LinuxOSUtils;
+
+import org.apache.commons.lang3.tuple.Pair;
+
+import com.google.auto.service.AutoService;
+import lombok.extern.slf4j.Slf4j;
+
+import java.io.IOException;
+import java.text.MessageFormat;
+import java.util.List;
+import java.util.Properties;
+
+@Slf4j
+@AutoService(Script.class)
+public class DorisFEScript extends AbstractServerScript {
+
+    @Override
+    public ShellResult add(Params params) {
+        Properties properties = new Properties();
+        properties.setProperty(PROPERTY_KEY_SKIP_LEVELS, "1");
+
+        return super.add(params, properties);
+    }
+
+    @Override
+    public ShellResult configure(Params params) {
+        super.configure(params);
+
+        try {
+            return DorisSetup.config(params, "doris_fe");
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    @Override
+    public ShellResult start(Params params) {
+        configure(params);
+        DorisParams dorisParams = (DorisParams) params;
+        String hostname = dorisParams.hostname();
+        String ip = dorisParams.ip();
+        LinuxFileUtils.removeDirectories(dorisParams.dorisFePidFile());
+
+        // Check if the FE is already registered
+        Pair<String, List<String>> masterAndFeList = 
DorisService.getMasterAndFeList(dorisParams);
+        List<String> feList = masterAndFeList.getRight();
+        String feMaster = masterAndFeList.getLeft();
+
+        try {
+            if (feMaster.equals(hostname) || feMaster.equals(ip) || 
feList.contains(hostname)) {
+                String cmd = MessageFormat.format("{0}/start_fe.sh --daemon", 
dorisParams.dorisFeBinDir());
+                return LinuxOSUtils.sudoExecCmd(cmd, dorisParams.user());
+            } else {
+                String cmd = MessageFormat.format(
+                        "{0}/start_fe.sh --helper {1}:{2,number,#} --daemon",
+                        dorisParams.dorisFeBinDir(), feMaster, 
dorisParams.dorisFeEditLogPort());
+
+                return LinuxOSUtils.sudoExecCmd(cmd, dorisParams.user());
+            }
+        } catch (IOException e) {
+            throw new StackException(e);
+        }
+    }
+
+    @Override
+    public ShellResult prepare(Params params) {
+        DorisParams dorisParams = (DorisParams) params;
+        // Register FE in Doris service
+        for (String dorisFeHost : dorisParams.dorisFeHosts()) {
+            DorisService.registerFollower(dorisParams, dorisFeHost);
+        }
+        return ShellResult.success();
+    }
+
+    @Override
+    public ShellResult stop(Params params) {
+        DorisParams dorisParams = (DorisParams) params;
+        String cmd = MessageFormat.format("{0}/stop_fe.sh", 
dorisParams.dorisFeBinDir());
+        try {
+            ShellResult shellResult = LinuxOSUtils.sudoExecCmd(cmd, 
dorisParams.user());
+            LinuxFileUtils.removeDirectories(dorisParams.dorisFePidDir());
+            return shellResult;
+        } catch (Exception e) {
+            throw new StackException(e);
+        }
+    }
+
+    @Override
+    public ShellResult status(Params params) {
+        DorisParams dorisParams = (DorisParams) params;
+        return LinuxOSUtils.checkProcess(dorisParams.dorisFePidFile());
+    }
+
+    @Override
+    public String getComponentName() {
+        return "doris_fe";
+    }
+}
diff --git 
a/bigtop-manager-stack/bigtop-manager-stack-extra/src/main/java/org/apache/bigtop/manager/stack/extra/v1_0_0/doris/DorisParams.java
 
b/bigtop-manager-stack/bigtop-manager-stack-extra/src/main/java/org/apache/bigtop/manager/stack/extra/v1_0_0/doris/DorisParams.java
new file mode 100644
index 00000000..8f1f200f
--- /dev/null
+++ 
b/bigtop-manager-stack/bigtop-manager-stack-extra/src/main/java/org/apache/bigtop/manager/stack/extra/v1_0_0/doris/DorisParams.java
@@ -0,0 +1,202 @@
+/*
+ * 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
+ *
+ *    https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.bigtop.manager.stack.extra.v1_0_0.doris;
+
+import org.apache.bigtop.manager.grpc.payload.ComponentCommandPayload;
+import org.apache.bigtop.manager.stack.core.annotations.GlobalParams;
+import org.apache.bigtop.manager.stack.core.spi.param.Params;
+import org.apache.bigtop.manager.stack.core.utils.LocalSettings;
+import org.apache.bigtop.manager.stack.core.utils.template.BaseTemplate;
+import org.apache.bigtop.manager.stack.extra.param.ExtraParams;
+
+import com.google.auto.service.AutoService;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.List;
+import java.util.Map;
+
+@Slf4j
+@Getter
+@AutoService(Params.class)
+@NoArgsConstructor
+public class DorisParams extends ExtraParams {
+
+    private final String limitsConfDir = "/etc/security/limits.d";
+    private final String sysctlConfDir = "/etc/sysctl.d";
+
+    public DorisParams(ComponentCommandPayload payload) {
+        super(payload);
+        globalParamsMap.put("java_home", javaHome());
+        globalParamsMap.put("doris_user", user());
+        globalParamsMap.put("doris_group", group());
+        globalParamsMap.put("doris_home", serviceHome());
+        globalParamsMap.put("doris_fe_home", dorisFeHome());
+        globalParamsMap.put("doris_be_home", dorisBeHome());
+    }
+
+    
/*================================FE===================================================*/
+    public String dorisFeHome() {
+        return serviceHome() + "/fe";
+    }
+
+    public String dorisFeBinDir() {
+        return dorisFeHome() + "/bin";
+    }
+
+    public String dorisFeConfDir() {
+        return dorisFeHome() + "/conf";
+    }
+
+    public String dorisFeMetaDir() {
+        return dorisFeConf().get("meta_dir") != null
+                ? BaseTemplate.writeCustomTemplateAsString(
+                        globalParamsMap, (String) 
dorisFeConf().get("meta_dir"))
+                : dorisFeHome() + "/doris-meta";
+    }
+
+    public String dorisFeLogDir() {
+        return dorisEnv().get("doris_fe_log_dir") != null
+                ? BaseTemplate.writeCustomTemplateAsString(
+                        globalParamsMap, (String) 
dorisEnv().get("doris_fe_log_dir"))
+                : dorisFeHome() + "/log";
+    }
+
+    public String dorisFePidDir() {
+        return (String) dorisEnv().get("doris_fe_pid_dir");
+    }
+
+    public String dorisFePidFile() {
+        return dorisFePidDir() + "/fe.pid";
+    }
+
+    public List<String> dorisFeHosts() {
+        return LocalSettings.hosts("doris_fe");
+    }
+
+    public int dorisFeHttpPort() {
+        return Integer.parseInt(dorisFeConf().get("http_port").toString());
+    }
+
+    public int dorisFeEditLogPort() {
+        return Integer.parseInt(dorisFeConf().get("edit_log_port").toString());
+    }
+
+    public int dorisFeQueryPort() {
+        return Integer.parseInt(dorisFeConf().get("query_port").toString());
+    }
+
+    public int dorisFeArrowFlightSqlPort() {
+        return 
Integer.parseInt(dorisFeConf().get("fe_arrow_flight_sql_port").toString());
+    }
+
+    
/*================================FE===================================================*/
+    
/*================================BE===================================================*/
+    public String dorisBeHome() {
+        return serviceHome() + "/be";
+    }
+
+    public String dorisBeBinDir() {
+        return dorisBeHome() + "/bin";
+    }
+
+    public String dorisBeConfDir() {
+        return dorisBeHome() + "/conf";
+    }
+
+    public String dorisBeStorage() {
+        return dorisBeConf().get("storage_root_path") != null
+                ? BaseTemplate.writeCustomTemplateAsString(
+                        globalParamsMap, (String) 
dorisBeConf().get("storage_root_path"))
+                : dorisBeHome() + "/storage";
+    }
+
+    public String dorisBeLogDir() {
+        return dorisEnv().get("doris_be_log_dir") != null
+                ? BaseTemplate.writeCustomTemplateAsString(
+                        globalParamsMap, (String) 
dorisEnv().get("doris_be_log_dir"))
+                : dorisBeHome() + "/log";
+    }
+
+    public String dorisBePidDir() {
+        return (String) dorisEnv().get("doris_be_pid_dir");
+    }
+
+    public String dorisBePidFile() {
+        return dorisBePidDir() + "/be.pid";
+    }
+
+    public int dorisBeHeartbeatPort() {
+        return 
Integer.parseInt(dorisBeConf().get("heartbeat_service_port").toString());
+    }
+
+    public int dorisBeArrowFlightSqlPort() {
+        return 
Integer.parseInt(dorisBeConf().get("be_arrow_flight_sql_port").toString());
+    }
+    
/*================================BE===================================================*/
+
+    public String ip() {
+        try {
+            return InetAddress.getLocalHost().getHostAddress();
+        } catch (UnknownHostException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    @Override
+    public String getServiceName() {
+        return "doris";
+    }
+
+    public String dorisConf() {
+        return (String)
+                LocalSettings.configurations(getServiceName(), 
"doris.conf").get("content");
+    }
+
+    public String dorisSysctlConf() {
+        return (String) LocalSettings.configurations(getServiceName(), 
"doris-sysctl.conf")
+                .get("content");
+    }
+
+    public String dorisFeConfContent() {
+        return (String) dorisFeConf().get("content");
+    }
+
+    public String dorisBeConfContent() {
+        return (String) dorisBeConf().get("content");
+    }
+
+    @GlobalParams
+    public Map<String, Object> dorisFeConf() {
+        return LocalSettings.configurations(getServiceName(), "doris-fe-conf");
+    }
+
+    @GlobalParams
+    public Map<String, Object> dorisBeConf() {
+        return LocalSettings.configurations(getServiceName(), "doris-be-conf");
+    }
+
+    @GlobalParams
+    public Map<String, Object> dorisEnv() {
+        return LocalSettings.configurations(getServiceName(), "doris-env.sh");
+    }
+}
diff --git 
a/bigtop-manager-stack/bigtop-manager-stack-extra/src/main/java/org/apache/bigtop/manager/stack/extra/v1_0_0/doris/DorisService.java
 
b/bigtop-manager-stack/bigtop-manager-stack-extra/src/main/java/org/apache/bigtop/manager/stack/extra/v1_0_0/doris/DorisService.java
new file mode 100644
index 00000000..ced0d533
--- /dev/null
+++ 
b/bigtop-manager-stack/bigtop-manager-stack-extra/src/main/java/org/apache/bigtop/manager/stack/extra/v1_0_0/doris/DorisService.java
@@ -0,0 +1,185 @@
+/*
+ * 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
+ *
+ *    https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.bigtop.manager.stack.extra.v1_0_0.doris;
+
+import org.apache.bigtop.manager.common.shell.ShellResult;
+import org.apache.bigtop.manager.stack.core.exception.StackException;
+import org.apache.bigtop.manager.stack.core.utils.linux.LinuxOSUtils;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.tuple.Pair;
+
+import lombok.extern.slf4j.Slf4j;
+
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.stream.Collectors;
+
+@Slf4j
+public class DorisService {
+    public static void registerBe(DorisParams dorisParams) {
+        String hostname = dorisParams.hostname();
+        log.info("Registering Doris BE: ip [{}], hostname [{}]", 
dorisParams.ip(), hostname);
+        String aliveFe = getAliveFe(dorisParams);
+        if (aliveFe == null) {
+            throw new StackException("Fail to register Doris BE: No FE 
alive!");
+        }
+
+        List<String> beList = DorisService.getBeList(aliveFe, dorisParams);
+        if (beList.contains(hostname)) {
+            log.info("Doris BE [{}] already registered", hostname);
+        }
+        String sql = MessageFormat.format(
+                "ALTER SYSTEM ADD BACKEND ''{0}:{1,number,#}'';", hostname, 
dorisParams.dorisBeHeartbeatPort());
+        DorisTool dorisTool = new DorisTool(aliveFe, "root", "", 
dorisParams.dorisFeArrowFlightSqlPort());
+        try {
+            dorisTool.executeQuery(sql);
+        } catch (Exception e) {
+            log.error("Error register Doris BE [{}] ", hostname, e);
+            throw new StackException(e);
+        }
+    }
+
+    public static List<String> getBeList(String aliveFe, DorisParams 
dorisParams) {
+        String sql = "SHOW BACKENDS;";
+        DorisTool dorisTool = new DorisTool(aliveFe, "root", "", 
dorisParams.dorisFeArrowFlightSqlPort());
+        List<String> beList;
+        try {
+            beList = dorisTool.executeQuery(sql).stream()
+                    .map(map -> (String) map.get("Host"))
+                    .collect(Collectors.toList());
+            log.info("BE hosts found: [{}]", beList);
+        } catch (Exception e) {
+            log.error("Error executing SQL query: [{}], [{}]", sql, 
e.getMessage());
+            throw new StackException(e);
+        }
+
+        return beList;
+    }
+
+    public static String getAliveFe(DorisParams dorisParams) {
+        int dorisFeHttpPort = dorisParams.dorisFeHttpPort();
+        List<String> feHosts = dorisParams.dorisFeHosts();
+        String aliveFe = null;
+
+        MessageFormat messageFormat =
+                new MessageFormat("curl -s -o /dev/null -w '%{http_code}' 
http://{0}:{1,number,#}/api/bootstrap";);
+        try {
+            for (String host : feHosts) {
+                String cmd = messageFormat.format(new Object[] {host, 
dorisFeHttpPort});
+                ShellResult shellResult;
+                int attempts = 0;
+                while (attempts < 5) {
+                    shellResult = LinuxOSUtils.execCmd(cmd);
+                    if (shellResult.getExitCode() == 0
+                            && 
StringUtils.equals(shellResult.getOutput().trim(), "200")) {
+                        aliveFe = host;
+                        break;
+                    }
+                    attempts++;
+                    try {
+                        log.info("Retry [{}] to connect [{}]", attempts, host);
+                        Thread.sleep(5000);
+                    } catch (InterruptedException ie) {
+                        Thread.currentThread().interrupt();
+                        break;
+                    }
+                }
+            }
+        } catch (Exception e) {
+            log.error("Error checking alive FE hosts: [{}] [{}]", 
e.getMessage(), e.getMessage());
+            throw new StackException(e);
+        }
+
+        if (aliveFe == null) {
+            log.warn("No alive FE host found in the list: [{}]", feHosts);
+        } else {
+            log.info("Alive FE host: [{}]", aliveFe);
+        }
+
+        return aliveFe;
+    }
+
+    /**
+     * Return MasterFeHost and AllFeHost
+     *
+     * @param dorisParams DorisParams
+     * @return (MasterFeHost, AllFeHost)
+     */
+    public static Pair<String, List<String>> getMasterAndFeList(DorisParams 
dorisParams) {
+        AtomicReference<String> masterHost =
+                new AtomicReference<>(dorisParams.dorisFeHosts().get(0));
+        String aliveFe = getAliveFe(dorisParams);
+        if (aliveFe == null) {
+            log.warn("No alive FE");
+            return Pair.of(masterHost.get(), List.of());
+        }
+        List<String> feList = new ArrayList<>();
+        String sql = "SHOW FRONTENDS;";
+        DorisTool dorisTool = new DorisTool(aliveFe, "root", "", 
dorisParams.dorisFeArrowFlightSqlPort());
+        try {
+            dorisTool.executeQuery(sql).stream()
+                    .map(map -> {
+                        String host = (String) map.get("Host");
+                        boolean isMaster = Boolean.parseBoolean((String) 
map.get("IsMaster"));
+                        if (isMaster) {
+                            masterHost.set(host);
+                        }
+                        return host;
+                    })
+                    .forEach(feList::add);
+        } catch (Exception e) {
+            log.error("Error executing SQL query: [{}], msg: [{}]", sql, 
e.getMessage());
+            throw new StackException(e);
+        }
+
+        log.info("FE hosts found: [{}]", feList);
+        return Pair.of(masterHost.get(), feList);
+    }
+
+    public static void registerFollower(DorisParams dorisParams, String 
hostname) {
+        String aliveFe = getAliveFe(dorisParams);
+        if (aliveFe == null) {
+            throw new StackException("Error registering follower: No FE 
alive!");
+        }
+
+        Pair<String, List<String>> masterAndFeList = 
getMasterAndFeList(dorisParams);
+        List<String> feList = masterAndFeList.getRight();
+        String feMaster = masterAndFeList.getLeft();
+
+        if (feList.contains(hostname)) {
+            log.info("Doris FE [{}] already registered", hostname);
+        } else {
+            DorisTool dorisTool = new DorisTool(feMaster, "root", "", 
dorisParams.dorisFeArrowFlightSqlPort());
+
+            try {
+                String sql = MessageFormat.format(
+                        "ALTER SYSTEM ADD FOLLOWER ''{0}:{1,number,#}'';", 
hostname, dorisParams.dorisFeEditLogPort());
+
+                dorisTool.executeQuery(sql);
+            } catch (Exception e) {
+                log.error("Error registering Doris Follower: [{}]", 
e.getMessage());
+                throw new StackException(e);
+            }
+        }
+    }
+}
diff --git 
a/bigtop-manager-stack/bigtop-manager-stack-extra/src/main/java/org/apache/bigtop/manager/stack/extra/v1_0_0/doris/DorisSetup.java
 
b/bigtop-manager-stack/bigtop-manager-stack-extra/src/main/java/org/apache/bigtop/manager/stack/extra/v1_0_0/doris/DorisSetup.java
new file mode 100644
index 00000000..ba7ee4d1
--- /dev/null
+++ 
b/bigtop-manager-stack/bigtop-manager-stack-extra/src/main/java/org/apache/bigtop/manager/stack/extra/v1_0_0/doris/DorisSetup.java
@@ -0,0 +1,110 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *    https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.bigtop.manager.stack.extra.v1_0_0.doris;
+
+import org.apache.bigtop.manager.common.constants.Constants;
+import org.apache.bigtop.manager.common.constants.MessageConstants;
+import org.apache.bigtop.manager.common.shell.ShellResult;
+import org.apache.bigtop.manager.stack.core.exception.StackException;
+import org.apache.bigtop.manager.stack.core.spi.param.Params;
+import org.apache.bigtop.manager.stack.core.utils.linux.LinuxFileUtils;
+import org.apache.bigtop.manager.stack.core.utils.linux.LinuxOSUtils;
+
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+
+import java.io.IOException;
+import java.text.MessageFormat;
+
+import static 
org.apache.bigtop.manager.common.constants.Constants.PERMISSION_755;
+
+@Slf4j
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+public class DorisSetup {
+
+    public static ShellResult config(Params params, String type) throws 
IOException {
+        DorisParams dorisParams = (DorisParams) params;
+        String user = dorisParams.user();
+        String group = dorisParams.group();
+
+        LinuxFileUtils.toFileByTemplate(
+                dorisParams.dorisConf(),
+                MessageFormat.format("{0}/doris.conf", 
dorisParams.getLimitsConfDir()),
+                Constants.ROOT_USER,
+                Constants.ROOT_GROUP,
+                Constants.PERMISSION_644,
+                dorisParams.getGlobalParamsMap());
+
+        LinuxFileUtils.toFileByTemplate(
+                dorisParams.dorisSysctlConf(),
+                MessageFormat.format("{0}/doris-sysctl.conf", 
dorisParams.getSysctlConfDir()),
+                Constants.ROOT_USER,
+                Constants.ROOT_GROUP,
+                Constants.PERMISSION_644,
+                dorisParams.getGlobalParamsMap());
+
+        ShellResult sr1 = LinuxOSUtils.sudoExecCmd("sysctl -p 
/etc/sysctl.d/doris-sysctl.conf");
+        if (sr1.getExitCode() != MessageConstants.SUCCESS_CODE) {
+            String errMsg = sr1.formatMessage("Failed to apply sysctl 
settings");
+            log.error(errMsg);
+            throw new StackException(errMsg);
+        }
+
+        ShellResult sr2 = LinuxOSUtils.sudoExecCmd("swapoff -a");
+        if (sr2.getExitCode() != MessageConstants.SUCCESS_CODE) {
+            String errMsg = sr2.formatMessage("Failed to run swapoff command");
+            log.error(errMsg);
+            throw new StackException(errMsg);
+        }
+
+        if (type.equals("doris_fe")) {
+            LinuxFileUtils.createDirectories(dorisParams.dorisFeConfDir(), 
user, group, PERMISSION_755, false);
+            LinuxFileUtils.createDirectories(dorisParams.dorisFePidDir(), 
user, group, PERMISSION_755, false);
+            LinuxFileUtils.createDirectories(dorisParams.dorisFeLogDir(), 
user, group, PERMISSION_755, false);
+            LinuxFileUtils.createDirectories(dorisParams.dorisFeMetaDir(), 
user, group, PERMISSION_755, false);
+
+            LinuxFileUtils.toFileByTemplate(
+                    dorisParams.dorisFeConfContent(),
+                    MessageFormat.format("{0}/fe.conf", 
dorisParams.dorisFeConfDir()),
+                    user,
+                    group,
+                    Constants.PERMISSION_644,
+                    dorisParams.getGlobalParamsMap(),
+                    dorisParams.getGlobalParamsMap());
+
+        } else if (type.equals("doris_be")) {
+            LinuxFileUtils.createDirectories(dorisParams.dorisBeConfDir(), 
user, group, PERMISSION_755, false);
+            LinuxFileUtils.createDirectories(dorisParams.dorisBePidDir(), 
user, group, PERMISSION_755, false);
+            LinuxFileUtils.createDirectories(dorisParams.dorisBeLogDir(), 
user, group, PERMISSION_755, false);
+            LinuxFileUtils.createDirectories(dorisParams.dorisBeStorage(), 
user, group, PERMISSION_755, false);
+
+            LinuxFileUtils.toFileByTemplate(
+                    dorisParams.dorisBeConfContent(),
+                    MessageFormat.format("{0}/be.conf", 
dorisParams.dorisBeConfDir()),
+                    user,
+                    group,
+                    Constants.PERMISSION_644,
+                    dorisParams.getGlobalParamsMap(),
+                    dorisParams.getGlobalParamsMap());
+        }
+
+        return ShellResult.success("Doris Configure success!");
+    }
+}
diff --git 
a/bigtop-manager-stack/bigtop-manager-stack-extra/src/main/java/org/apache/bigtop/manager/stack/extra/v1_0_0/doris/DorisTool.java
 
b/bigtop-manager-stack/bigtop-manager-stack-extra/src/main/java/org/apache/bigtop/manager/stack/extra/v1_0_0/doris/DorisTool.java
new file mode 100644
index 00000000..bab710aa
--- /dev/null
+++ 
b/bigtop-manager-stack/bigtop-manager-stack-extra/src/main/java/org/apache/bigtop/manager/stack/extra/v1_0_0/doris/DorisTool.java
@@ -0,0 +1,109 @@
+/*
+ * 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
+ *
+ *    https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.bigtop.manager.stack.extra.v1_0_0.doris;
+
+import lombok.extern.slf4j.Slf4j;
+
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.ResultSet;
+import java.sql.ResultSetMetaData;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+@Slf4j
+public class DorisTool {
+    private static final int MAX_RETRIES = 10;
+    private static final int RETRY_DELAY_MS = 10000; // milliseconds
+
+    private final String jdbcUrl;
+    private final String user;
+    private final String password;
+
+    public DorisTool(String host, String user, String password, int port) {
+        this.jdbcUrl = String.format(
+                
"jdbc:arrow-flight-sql://%s:%d?useServerPrepStmts=false&cachePrepStmts=true&useSSL=false&useEncryption=false",
+                host, port);
+        this.user = user;
+        this.password = password;
+        log.info("Connecting to database: [jdbc:arrow-flight-sql://{}:{}]", 
host, port);
+    }
+
+    public Connection connect() throws Exception {
+        int attempt = 0;
+        Exception lastException = null;
+
+        while (attempt < MAX_RETRIES) {
+            try {
+                Connection connection = DriverManager.getConnection(jdbcUrl, 
user, password);
+                if (connection != null && !connection.isClosed()) {
+                    log.info("Successfully connected to Doris");
+                    return connection;
+                } else {
+                    throw new Exception("Connection is null or closed");
+                }
+            } catch (Exception e) {
+                lastException = e;
+                attempt++;
+                log.warn("Connection attempt [{}] failed: [{}]", attempt, 
e.getMessage());
+
+                if (attempt < MAX_RETRIES) {
+                    try {
+                        Thread.sleep(RETRY_DELAY_MS);
+                    } catch (InterruptedException ie) {
+                        Thread.currentThread().interrupt();
+                        throw new SQLException("Connection interrupted", ie);
+                    }
+                }
+            }
+        }
+
+        throw new Exception("Failed to connect after " + MAX_RETRIES + " 
attempts", lastException);
+    }
+
+    public List<Map<String, Object>> executeQuery(String sql) throws Exception 
{
+        log.info("Executing SQL query: [{}]", sql);
+
+        List<Map<String, Object>> resultList = new ArrayList<>();
+
+        try (Connection conn = connect();
+                Statement stmt = conn.createStatement();
+                ResultSet rs = stmt.executeQuery(sql)) {
+            ResultSetMetaData metaData = rs.getMetaData();
+            int columnCount = metaData.getColumnCount();
+
+            while (rs.next()) {
+                Map<String, Object> row = new LinkedHashMap<>();
+                for (int i = 1; i <= columnCount; i++) {
+                    String columnName = metaData.getColumnLabel(i);
+                    Object value = rs.getObject(i);
+                    row.put(columnName, value);
+                }
+                resultList.add(row);
+            }
+
+            return resultList;
+        }
+    }
+}
diff --git a/bigtop-manager-ui/src/assets/images/doris.png 
b/bigtop-manager-ui/src/assets/images/doris.png
new file mode 100644
index 00000000..46f60cf4
Binary files /dev/null and b/bigtop-manager-ui/src/assets/images/doris.png 
differ

Reply via email to