You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@doris.apache.org by mo...@apache.org on 2021/08/13 02:59:20 UTC

[incubator-doris] branch doris-manager updated: [Feature] Doris manager module (#6424)

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

morningman pushed a commit to branch doris-manager
in repository https://gitbox.apache.org/repos/asf/incubator-doris.git


The following commit(s) were added to refs/heads/doris-manager by this push:
     new 9f4293e  [Feature] Doris manager module (#6424)
9f4293e is described below

commit 9f4293e0b203004399e66318ca2a5297c9588aeb
Author: weajun <we...@gmail.com>
AuthorDate: Fri Aug 13 10:59:05 2021 +0800

    [Feature] Doris manager module (#6424)
    
    Server and agent framework.
    
    Doris Manager is a platform product that integrates one-click automatic installation, deployment, management,
    monitoring, and tuning of doris clusters. Its service is independent of Doris and aims to provide convenient user
    functions through a graphical interface. Manager is compatible with multi-cluster mode, and its functions are divided
    into general functions and single-cluster functions as a whole.
---
 .gitignore                                         |  11 +
 manager/README.md                                  |  52 +++
 manager/assembly/package.xml                       |  40 ++
 manager/assembly/pom.xml                           |  71 +++
 manager/dm-agent/pom.xml                           |  65 +++
 .../doris/manager/agent/DmAgentApplication.java    |  70 +++
 .../doris/manager/agent/api/CommandController.java |  67 +++
 .../doris/manager/agent/api/CommonControllder.java |  40 ++
 .../doris/manager/agent/command/BeCommand.java     |  34 ++
 .../manager/agent/command/BeInstallCommand.java    |  60 +++
 .../manager/agent/command/BeInstallTaskDesc.java   |  31 ++
 .../manager/agent/command/BeInstallTaskHook.java   |  52 +++
 .../manager/agent/command/BeStartCommand.java      |  49 +++
 .../doris/manager/agent/command/BeStopCommand.java |  49 +++
 .../doris/manager/agent/command/Command.java       |  52 +++
 .../manager/agent/command/CommandFactory.java      |  63 +++
 .../manager/agent/command/CommandListener.java     |  23 +
 .../doris/manager/agent/command/CommandResult.java |  57 +++
 .../agent/command/CommandResultService.java        |  98 +++++
 .../doris/manager/agent/command/FeCommand.java     |  34 ++
 .../manager/agent/command/FeInstallCommand.java    |  61 +++
 .../manager/agent/command/FeInstallTaskDesc.java   |  31 ++
 .../manager/agent/command/FeInstallTaskHook.java   |  53 +++
 .../manager/agent/command/FeStartCommand.java      |  64 +++
 .../doris/manager/agent/command/FeStopCommand.java |  48 ++
 .../manager/agent/command/ListenerCommand.java     |  27 ++
 .../doris/manager/agent/common/AgentConstants.java |  29 ++
 .../doris/manager/agent/common/PropertiesUtil.java |  51 +++
 .../manager/agent/exception/AgentException.java    |  42 ++
 .../agent/exception/GlobalExceptionHandler.java    |  42 ++
 .../doris/manager/agent/register/AgentContext.java | 139 ++++++
 .../manager/agent/register/AgentHeartbeat.java     |  62 +++
 .../manager/agent/register/AgentRegister.java      |  44 ++
 .../doris/manager/agent/register/AgentRole.java    |  40 ++
 .../manager/agent/register/ApplicationOption.java  |  33 ++
 .../doris/manager/agent/register/BaseRequest.java  |  66 +++
 .../doris/manager/agent/register/BeState.java      |  66 +++
 .../doris/manager/agent/register/FeState.java      |  69 +++
 .../doris/manager/agent/register/StateService.java |  39 ++
 .../manager/agent/task/AbsAsyncTaskHandler.java    |  38 ++
 .../manager/agent/task/ITaskHandlerFactory.java    |  21 +
 .../apache/doris/manager/agent/task/ITaskLog.java  |  36 ++
 .../org/apache/doris/manager/agent/task/LRU.java   |  55 +++
 .../manager/agent/task/QueuedTaskHandler.java      |  26 ++
 .../agent/task/QueuedTaskHandlerFactory.java       |  32 ++
 .../doris/manager/agent/task/ScriptTask.java       |  57 +++
 .../doris/manager/agent/task/ScriptTaskDesc.java   |  29 ++
 .../doris/manager/agent/task/SyncTaskHandler.java  |  25 ++
 .../manager/agent/task/SyncTaskHandlerFactory.java |  32 ++
 .../org/apache/doris/manager/agent/task/Task.java  |  84 ++++
 .../doris/manager/agent/task/TaskContext.java      |  35 ++
 .../apache/doris/manager/agent/task/TaskDesc.java  |  29 ++
 .../manager/agent/task/TaskExecutorService.java    |  28 ++
 .../doris/manager/agent/task/TaskHandler.java      |  29 ++
 .../manager/agent/task/TaskHandlerFactory.java     |  45 ++
 .../apache/doris/manager/agent/task/TaskHook.java  |   5 +
 .../doris/manager/agent/task/TaskLruLog.java       |  92 ++++
 .../doris/manager/agent/task/TaskResult.java       |  88 ++++
 .../apache/doris/manager/agent/task/TaskState.java |  30 ++
 .../src/main/resources/agent/bin/agent_start.sh    |  88 ++++
 .../src/main/resources/agent/bin/agent_stop.sh     |  40 ++
 .../src/main/resources/agent/bin/install_be.sh     |  68 +++
 .../src/main/resources/agent/bin/install_fe.sh     |  68 +++
 .../src/main/resources/application.properties      |   1 +
 .../dm-agent/src/main/resources/logback-spring.xml |  26 ++
 manager/dm-common/pom.xml                          |  15 +
 .../common/domain/BeInstallCommandRequestBody.java |  48 ++
 .../manager/common/domain/CommandRequest.java      |  38 ++
 .../doris/manager/common/domain/CommandType.java   |  40 ++
 .../common/domain/FeInstallCommandRequestBody.java |  47 ++
 .../common/domain/FeStartCommandRequestBody.java   |  38 ++
 .../doris/manager/common/domain/RResult.java       |  84 ++++
 .../apache/doris/manager/common/domain/Role.java   |  31 ++
 manager/dm-server/pom.xml                          |  83 ++++
 .../doris/manager/server/DmServerApplication.java  |  28 ++
 .../doris/manager/server/agent/AgentCache.java     |  68 +++
 .../manager/server/agent/AgentHeatbeatRunner.java  |  85 ++++
 .../doris/manager/server/agent/AgentRest.java      |  63 +++
 .../manager/server/config/RestTemplateConfig.java  |  30 ++
 .../manager/server/constants/AgentStatus.java      |  22 +
 .../manager/server/constants/CmdTypeEnum.java      |  32 ++
 .../doris/manager/server/constants/Constants.java  |  24 +
 .../manager/server/controller/AgentController.java |  79 ++++
 .../server/controller/ServerController.java        |  90 ++++
 .../apache/doris/manager/server/dao/ServerDao.java |  44 ++
 .../manager/server/dao/impl/ServerDaoImpl.java     | 160 +++++++
 .../doris/manager/server/entity/AgentEntity.java   | 103 +++++
 .../manager/server/entity/AgentRoleEntity.java     |  59 +++
 .../server/exceptions/GlobalExceptionHandler.java  |  42 ++
 .../manager/server/exceptions/ServerException.java |  42 ++
 .../manager/server/model/req/AgentCommon.java      |  40 ++
 .../doris/manager/server/model/req/DorisExec.java  |  50 +++
 .../manager/server/model/req/DorisExecReq.java     |  43 ++
 .../manager/server/model/req/DorisInstallReq.java  |  32 ++
 .../manager/server/model/req/InstallInfo.java      |  82 ++++
 .../doris/manager/server/model/req/SshInfo.java    |  62 +++
 .../manager/server/model/req/TaskInfoReq.java      |  40 ++
 .../doris/manager/server/model/req/TaskLogReq.java |  29 ++
 .../doris/manager/server/service/ServerAgent.java  |  54 +++
 .../manager/server/service/ServerProcess.java      |  53 +++
 .../server/service/impl/ServerAgentImpl.java       | 180 ++++++++
 .../server/service/impl/ServerProcessImpl.java     | 204 +++++++++
 .../doris/manager/server/shell/BaseCommand.java    |  85 ++++
 .../org/apache/doris/manager/server/shell/SCP.java |  54 +++
 .../org/apache/doris/manager/server/shell/SSH.java |  54 +++
 .../doris/manager/server/util/Preconditions.java   |  46 ++
 .../doris/manager/server/util/PropertiesUtil.java  |  51 +++
 .../src/main/resources/application.properties      |  15 +
 .../dm-server/src/main/resources/bin/startup.sh    |  60 +++
 manager/dm-server/src/main/resources/bin/stop.sh   |  39 ++
 manager/dm-server/src/main/resources/dm-server.sql |  18 +
 .../src/main/resources/logback-spring.xml          |  26 ++
 ...216\245\345\217\243\346\226\207\346\241\243.md" | 486 +++++++++++++++++++++
 manager/pom.xml                                    |  48 ++
 114 files changed, 6377 insertions(+)

diff --git a/.gitignore b/.gitignore
index e5b8456..5b6b800 100644
--- a/.gitignore
+++ b/.gitignore
@@ -63,6 +63,17 @@ docs/package-lock.json
 fe/fe-common/.classpath
 rpc_data/
 
+manager/assembly/target
+manager/assembly/output/*
+manager/assembly/assembly.iml
+manager/dm-agent/target
+manager/dm-agent/dm-agent.iml
+manager/dm-common/target
+manager/dm-common/dm-common.iml
+manager/dm-server/target
+manager/dm-server/dm-server.iml
+manager/.idea/
+manager/manager.iml
 
 #ignore vscode project file
 .vscode
diff --git a/manager/README.md b/manager/README.md
new file mode 100644
index 0000000..3a40c9c
--- /dev/null
+++ b/manager/README.md
@@ -0,0 +1,52 @@
+<!--
+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.
+-->
+
+# Apache Doris Manager (incubating)
+[![Join the chat at https://gitter.im/apache-doris/Lobby](https://badges.gitter.im/apache-doris/Lobby.svg)](https://gitter.im/apache-doris/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
+
+Apache Doris Manager is used to manage the doris cluster, such as installing the cluster, upgrading the cluster, starting and stopping services, etc.
+
+## 1.Database configuration
+
+*  Modify the database configuration in the manager/dm-server/src/main/resources/application.properties file.
+*  Create a new database, and then execute the table creation statement in the manager/dm-server/src/main/resources/dm-server.sql file
+
+## 2. Compile and install
+
+### Step1: build
+```
+$ mvn clean package -DskipTests
+```
+After compilation, a tar package will be generated in the assembly/output/ directory, For example doris-manager-1.0.0.tar.gz
+
+### Step2: install manager server
+Copy tar package to the the machine where the manager server needs to be installed, Start the manager service after decompression
+```
+$ tar zxf doris-manager-1.0.0.tar.gz
+$ sh bin/startup.sh
+```
+
+### Step3: install agent service
+After decompressing the tar package in the second step, there will be a directory called agent. copy the agent directory to the
+machine where the agent service is installed,
+```
+$ sh bin/agent_start.sh --agent ${agentIp} --server ${serverIp}:9601
+```
+${agentIp} is the IP of the machine where the agent is located, ${serverIp} is the IP of the machine where the manager server is located
+
diff --git a/manager/assembly/package.xml b/manager/assembly/package.xml
new file mode 100644
index 0000000..f948820
--- /dev/null
+++ b/manager/assembly/package.xml
@@ -0,0 +1,40 @@
+<assembly xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/assembly-1.0.0.xsd">
+    <id>package</id>
+    <formats>
+        <format>tar.gz</format>
+    </formats>
+    <includeBaseDirectory>false</includeBaseDirectory>
+    <fileSets>
+        <fileSet>
+            <directory>../dm-agent/src/main/resources/agent</directory>
+            <outputDirectory>./agent</outputDirectory>
+            <includes>
+                <include>**</include>
+            </includes>
+        </fileSet>
+        <fileSet>
+            <directory>../dm-server/src/main/resources/bin</directory>
+            <outputDirectory>./bin</outputDirectory>
+        </fileSet>
+        <fileSet>
+            <directory>log</directory>
+            <outputDirectory>./log</outputDirectory>
+            <includes>
+                <include>**</include>
+            </includes>
+        </fileSet>
+    </fileSets>
+    <files>
+        <file>
+            <source>../dm-agent/target/dm-agent-${project.parent.version}.jar</source>
+            <outputDirectory>./agent/lib</outputDirectory>
+            <destName>dm-agent.jar</destName>
+        </file>
+        <file>
+            <source>../dm-server/target/dm-server-${project.parent.version}.jar</source>
+            <outputDirectory>./lib</outputDirectory>
+            <destName>dm-server.jar</destName>
+        </file>
+    </files>
+</assembly>
\ No newline at end of file
diff --git a/manager/assembly/pom.xml b/manager/assembly/pom.xml
new file mode 100644
index 0000000..462b891
--- /dev/null
+++ b/manager/assembly/pom.xml
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <groupId>org.apache.doris</groupId>
+        <artifactId>doris-manager</artifactId>
+        <version>1.0.0</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>assembly</artifactId>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.doris</groupId>
+            <artifactId>dm-agent</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.doris</groupId>
+            <artifactId>dm-server</artifactId>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-antrun-plugin</artifactId>
+                <version>1.7</version>
+                <executions>
+                    <execution>
+                        <id>folder</id>
+                        <phase>validate</phase>
+                        <configuration>
+                            <tasks>
+                                <echo message="clean output directory"/>
+                                <delete dir="./output"/>
+                            </tasks>
+                        </configuration>
+                        <goals>
+                            <goal>run</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-assembly-plugin</artifactId>
+                <version>2.6</version>
+                <configuration>
+                    <finalName>doris-manager-${project.parent.version}</finalName>
+                    <appendAssemblyId>false</appendAssemblyId>
+                    <descriptors>
+                        <descriptor>assembly/package.xml</descriptor>
+                    </descriptors>
+                    <outputDirectory>./output</outputDirectory>
+                </configuration>
+                <executions>
+                    <execution>
+                        <id>make-assembly</id>
+                        <phase>package</phase>
+                        <goals>
+                            <goal>single</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+</project>
\ No newline at end of file
diff --git a/manager/dm-agent/pom.xml b/manager/dm-agent/pom.xml
new file mode 100644
index 0000000..890b71f
--- /dev/null
+++ b/manager/dm-agent/pom.xml
@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <groupId>org.apache.doris</groupId>
+        <artifactId>doris-manager</artifactId>
+        <version>1.0.0</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>dm-agent</artifactId>
+    <packaging>jar</packaging>
+
+    <name>dm-agent</name>
+
+    <properties>
+        <java.version>1.8</java.version>
+    </properties>
+    <dependencies>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-web</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-test</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.doris</groupId>
+            <artifactId>dm-common</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>com.alibaba</groupId>
+            <artifactId>fastjson</artifactId>
+            <version>1.2.61</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.httpcomponents</groupId>
+            <artifactId>httpclient</artifactId>
+            <version>4.5</version>
+        </dependency>
+
+        <dependency>
+            <groupId>args4j</groupId>
+            <artifactId>args4j</artifactId>
+            <version>2.33</version>
+        </dependency>
+
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+            </plugin>
+        </plugins>
+    </build>
+</project>
diff --git a/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/DmAgentApplication.java b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/DmAgentApplication.java
new file mode 100644
index 0000000..791ab1d
--- /dev/null
+++ b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/DmAgentApplication.java
@@ -0,0 +1,70 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.agent;
+
+import org.apache.doris.manager.agent.register.AgentContext;
+import org.apache.doris.manager.agent.register.AgentHeartbeat;
+import org.apache.doris.manager.agent.register.AgentRegister;
+import org.apache.doris.manager.agent.register.AgentRole;
+import org.apache.doris.manager.agent.register.ApplicationOption;
+import org.apache.doris.manager.common.domain.Role;
+import org.apache.doris.manager.agent.common.PropertiesUtil;
+import org.kohsuke.args4j.CmdLineException;
+import org.kohsuke.args4j.CmdLineParser;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.system.ApplicationHome;
+
+@SpringBootApplication
+public class DmAgentApplication {
+    private static final Logger log = LoggerFactory.getLogger(DmAgentApplication.class);
+
+    public static void main(String[] args) {
+        ApplicationOption option = new ApplicationOption();
+        CmdLineParser parser = new CmdLineParser(option);
+        try {
+            parser.parseArgument(args);
+        } catch (CmdLineException e) {
+            e.printStackTrace();
+            return;
+        }
+
+        String agentPort = PropertiesUtil.getPropValue("server.port");
+
+        ApplicationHome applicationHome = new ApplicationHome(DmAgentApplication.class);
+        String agentInstallDir = applicationHome.getSource().getParentFile().getParentFile().toString();
+
+        AgentContext.init(option.role, option.agentIp, Integer.valueOf(agentPort), option.agentServer, option.dorisHomeDir, agentInstallDir);
+
+
+        String role = AgentRole.queryRole();
+        AgentContext.setRole(Role.findByName(role));
+
+        // register agent
+        boolean register = AgentRegister.register();
+        if (register) {
+            SpringApplication.run(DmAgentApplication.class, args);
+            AgentHeartbeat.start();
+        } else {
+            log.error("agent register fail!");
+            return;
+        }
+    }
+
+}
diff --git a/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/api/CommandController.java b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/api/CommandController.java
new file mode 100644
index 0000000..368f95e
--- /dev/null
+++ b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/api/CommandController.java
@@ -0,0 +1,67 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.agent.api;
+
+import org.apache.doris.manager.agent.command.CommandFactory;
+import org.apache.doris.manager.agent.common.AgentConstants;
+import org.apache.doris.manager.common.domain.CommandRequest;
+import org.apache.doris.manager.agent.command.CommandResult;
+import org.apache.doris.manager.agent.command.CommandResultService;
+import org.apache.doris.manager.common.domain.CommandType;
+import org.apache.doris.manager.agent.task.Task;
+import org.apache.doris.manager.agent.task.TaskContext;
+import org.apache.doris.manager.common.domain.RResult;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.Objects;
+
+@RestController
+@RequestMapping("/command")
+public class CommandController {
+
+    @PostMapping("/execute")
+    public RResult execute(@RequestBody CommandRequest commandRequest) {
+        if (Objects.isNull(CommandType.findByName(commandRequest.getCommandType()))) {
+            return RResult.error("unkonwn command");
+        }
+        Task task = CommandFactory.get(commandRequest).setup().execute();
+        CommandResult commandResult = new CommandResult(task.getTaskResult(),
+                task.getTasklog().allStdLog(),
+                task.getTasklog().allErrLog());
+        return RResult.success(commandResult);
+    }
+
+    @GetMapping("/result")
+    public RResult commandResult(@RequestParam String taskId) {
+        return RResult.success(CommandResultService.commandResult(taskId));
+    }
+
+    @GetMapping("/stdlog")
+    public RResult getTaskStdLog(@RequestParam String taskId, @RequestParam int offset) {
+        return RResult.success(TaskContext.getTaskByTaskId(taskId) == null ? null : TaskContext.getTaskByTaskId(taskId).getTasklog().stdLog(offset, AgentConstants.COMMAND_LOG_PAGE_SIZE));
+    }
+
+    @GetMapping("/errlog")
+    public RResult getTaskErrLog(@RequestParam String taskId, @RequestParam int offset) {
+        return RResult.success(TaskContext.getTaskByTaskId(taskId) == null ? null : TaskContext.getTaskByTaskId(taskId).getTasklog().errLog(offset, AgentConstants.COMMAND_LOG_PAGE_SIZE));
+    }
+}
diff --git a/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/api/CommonControllder.java b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/api/CommonControllder.java
new file mode 100644
index 0000000..da6a843
--- /dev/null
+++ b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/api/CommonControllder.java
@@ -0,0 +1,40 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.agent.api;
+
+import org.apache.doris.manager.agent.register.AgentContext;
+import org.apache.doris.manager.agent.register.StateService;
+import org.apache.doris.manager.common.domain.RResult;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+
+@RestController
+@RequestMapping("/common")
+public class CommonControllder {
+
+    @GetMapping("/state")
+    public RResult state() {
+        return RResult.success(StateService.isHealth());
+    }
+
+    @GetMapping("/context")
+    public RResult context() {
+        return RResult.success(AgentContext.getContext());
+    }
+}
diff --git a/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/command/BeCommand.java b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/command/BeCommand.java
new file mode 100644
index 0000000..ee28f5b
--- /dev/null
+++ b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/command/BeCommand.java
@@ -0,0 +1,34 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.agent.command;
+
+import org.apache.doris.manager.agent.exception.AgentException;
+import org.apache.doris.manager.agent.register.AgentContext;
+import org.apache.doris.manager.common.domain.CommandType;
+import org.apache.doris.manager.common.domain.Role;
+
+import java.util.Objects;
+
+public abstract class BeCommand extends ListenerCommand {
+    @Override
+    public void beforeExecute(CommandType commandType) {
+        if (Objects.isNull(AgentContext.getServiceInstallDir()) || Objects.isNull(AgentContext.getRole()) ||
+                AgentContext.getRole() != Role.BE) {
+            throw new AgentException("service be not installed");
+        }
+    }
+}
diff --git a/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/command/BeInstallCommand.java b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/command/BeInstallCommand.java
new file mode 100644
index 0000000..2a582dd
--- /dev/null
+++ b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/command/BeInstallCommand.java
@@ -0,0 +1,60 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.agent.command;
+
+import org.apache.doris.manager.agent.register.AgentContext;
+import org.apache.doris.manager.agent.task.ITaskHandlerFactory;
+import org.apache.doris.manager.agent.task.QueuedTaskHandlerFactory;
+import org.apache.doris.manager.agent.task.ScriptTask;
+import org.apache.doris.manager.agent.task.Task;
+import org.apache.doris.manager.agent.task.TaskHandlerFactory;
+import org.apache.doris.manager.common.domain.BeInstallCommandRequestBody;
+import org.apache.doris.manager.common.domain.CommandType;
+
+public class BeInstallCommand extends Command {
+    private BeInstallCommandRequestBody requestBody;
+
+    public BeInstallCommand(BeInstallCommandRequestBody requestBody) {
+        this.requestBody = requestBody;
+    }
+
+    @Override
+    public Task setupTask() {
+        BeInstallTaskDesc taskDesc = new BeInstallTaskDesc();
+
+        String scriptCmd = AgentContext.getBashBin();
+        scriptCmd += AgentContext.getAgentInstallDir() + "/bin/install_be.sh ";
+        scriptCmd += " --installDir " + requestBody.getInstallDir();
+        scriptCmd += " --url " + requestBody.getPackageUrl();
+        if (requestBody.isMkBeStorageDir()) {
+            scriptCmd += " --mkBeStorageDir";
+        }
+        taskDesc.setScriptCmd(scriptCmd);
+        taskDesc.setInstallDir(requestBody.getInstallDir());
+        return new ScriptTask(taskDesc, new BeInstallTaskHook());
+    }
+
+    @Override
+    public ITaskHandlerFactory setupTaskHandlerFactory() {
+        return TaskHandlerFactory.getTaskHandlerFactory(QueuedTaskHandlerFactory.class);
+    }
+
+    @Override
+    public CommandType setupCommandType() {
+        return CommandType.INSTALL_BE;
+    }
+}
diff --git a/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/command/BeInstallTaskDesc.java b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/command/BeInstallTaskDesc.java
new file mode 100644
index 0000000..c6a1c9a
--- /dev/null
+++ b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/command/BeInstallTaskDesc.java
@@ -0,0 +1,31 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.agent.command;
+
+import org.apache.doris.manager.agent.task.ScriptTaskDesc;
+
+public class BeInstallTaskDesc extends ScriptTaskDesc {
+    private String installDir;
+
+    public String getInstallDir() {
+        return installDir;
+    }
+
+    public void setInstallDir(String installDir) {
+        this.installDir = installDir;
+    }
+}
diff --git a/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/command/BeInstallTaskHook.java b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/command/BeInstallTaskHook.java
new file mode 100644
index 0000000..33f874e
--- /dev/null
+++ b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/command/BeInstallTaskHook.java
@@ -0,0 +1,52 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.agent.command;
+
+import org.apache.doris.manager.agent.common.AgentConstants;
+import org.apache.doris.manager.agent.exception.AgentException;
+import org.apache.doris.manager.agent.register.AgentContext;
+import org.apache.doris.manager.common.domain.Role;
+import org.apache.doris.manager.agent.task.TaskHook;
+import org.apache.logging.log4j.util.Strings;
+
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.Properties;
+
+public class BeInstallTaskHook extends TaskHook<BeInstallTaskDesc> {
+    @Override
+    public void onSuccess(BeInstallTaskDesc taskDesc) {
+        AgentContext.setRole(Role.BE);
+        AgentContext.setServiceInstallDir(taskDesc.getInstallDir());
+
+        String configFile = AgentContext.getServiceInstallDir().endsWith("/") ? AgentContext.getServiceInstallDir() + "conf/be.conf" : AgentContext.getServiceInstallDir() + "/conf/be.conf";
+        Properties props = null;
+        try {
+            props = new Properties();
+            props.load(new FileReader(configFile));
+        } catch (IOException e) {
+            e.printStackTrace();
+            throw new AgentException("load be conf file fail:" + configFile);
+        }
+
+        if (props != null && Strings.isNotBlank(props.getProperty("http_port"))) {
+            AgentContext.setHealthCheckPort(Integer.valueOf(props.getProperty("http_port")));
+        } else {
+            AgentContext.setHealthCheckPort(AgentConstants.BE_HTTP_PORT_DEFAULT);
+        }
+    }
+}
\ No newline at end of file
diff --git a/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/command/BeStartCommand.java b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/command/BeStartCommand.java
new file mode 100644
index 0000000..8996cb6
--- /dev/null
+++ b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/command/BeStartCommand.java
@@ -0,0 +1,49 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.agent.command;
+
+import org.apache.doris.manager.agent.register.AgentContext;
+import org.apache.doris.manager.agent.task.ITaskHandlerFactory;
+import org.apache.doris.manager.agent.task.QueuedTaskHandlerFactory;
+import org.apache.doris.manager.agent.task.ScriptTask;
+import org.apache.doris.manager.agent.task.ScriptTaskDesc;
+import org.apache.doris.manager.agent.task.Task;
+import org.apache.doris.manager.agent.task.TaskHandlerFactory;
+import org.apache.doris.manager.common.domain.CommandType;
+
+public class BeStartCommand extends BeCommand {
+    @Override
+    public Task setupTask() {
+        ScriptTaskDesc taskDesc = new ScriptTaskDesc();
+
+        String scriptCmd = AgentContext.getBashBin();
+        scriptCmd += AgentContext.getServiceInstallDir() + "/bin/start_be.sh --daemon";
+        taskDesc.setScriptCmd(scriptCmd);
+        return new ScriptTask(taskDesc);
+    }
+
+    @Override
+    public ITaskHandlerFactory setupTaskHandlerFactory() {
+        return TaskHandlerFactory.getTaskHandlerFactory(QueuedTaskHandlerFactory.class);
+
+    }
+
+    @Override
+    public CommandType setupCommandType() {
+        return CommandType.START_BE;
+    }
+}
diff --git a/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/command/BeStopCommand.java b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/command/BeStopCommand.java
new file mode 100644
index 0000000..baa93e1
--- /dev/null
+++ b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/command/BeStopCommand.java
@@ -0,0 +1,49 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.agent.command;
+
+import org.apache.doris.manager.agent.register.AgentContext;
+import org.apache.doris.manager.agent.task.ITaskHandlerFactory;
+import org.apache.doris.manager.agent.task.QueuedTaskHandlerFactory;
+import org.apache.doris.manager.agent.task.ScriptTask;
+import org.apache.doris.manager.agent.task.ScriptTaskDesc;
+import org.apache.doris.manager.agent.task.Task;
+import org.apache.doris.manager.agent.task.TaskHandlerFactory;
+import org.apache.doris.manager.common.domain.CommandType;
+
+
+public class BeStopCommand extends BeCommand {
+    @Override
+    public Task setupTask() {
+        ScriptTaskDesc taskDesc = new ScriptTaskDesc();
+
+        String scriptCmd = AgentContext.getBashBin();
+        scriptCmd += AgentContext.getServiceInstallDir() + "/bin/stop_be.sh ";
+        taskDesc.setScriptCmd(scriptCmd);
+        return new ScriptTask(taskDesc);
+    }
+
+    @Override
+    public ITaskHandlerFactory setupTaskHandlerFactory() {
+        return TaskHandlerFactory.getTaskHandlerFactory(QueuedTaskHandlerFactory.class);
+    }
+
+    @Override
+    public CommandType setupCommandType() {
+        return CommandType.STOP_BE;
+    }
+}
diff --git a/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/command/Command.java b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/command/Command.java
new file mode 100644
index 0000000..e89c04a
--- /dev/null
+++ b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/command/Command.java
@@ -0,0 +1,52 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.agent.command;
+
+import org.apache.doris.manager.agent.task.ITaskHandlerFactory;
+import org.apache.doris.manager.agent.task.Task;
+import org.apache.doris.manager.common.domain.CommandType;
+
+
+public abstract class Command {
+    private Task task;
+    private ITaskHandlerFactory handlerFactory;
+    protected CommandType commandType;
+
+
+    public Command setup() {
+        task = setupTask();
+        commandType = setupCommandType();
+        task.getTaskDesc().setTaskName(commandType.name());
+        handlerFactory = setupTaskHandlerFactory();
+        return this;
+    }
+
+    public abstract Task setupTask();
+
+    public abstract CommandType setupCommandType();
+
+    public abstract ITaskHandlerFactory setupTaskHandlerFactory();
+
+    public Task execute() {
+        handlerFactory.createTaskHandler().handle(task);
+        return task;
+    }
+
+    public ITaskHandlerFactory getHandlerFactory() {
+        return handlerFactory;
+    }
+}
diff --git a/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/command/CommandFactory.java b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/command/CommandFactory.java
new file mode 100644
index 0000000..e42bb27
--- /dev/null
+++ b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/command/CommandFactory.java
@@ -0,0 +1,63 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.agent.command;
+
+import com.alibaba.fastjson.JSON;
+import org.apache.doris.manager.agent.exception.AgentException;
+import org.apache.doris.manager.common.domain.BeInstallCommandRequestBody;
+import org.apache.doris.manager.common.domain.CommandRequest;
+import org.apache.doris.manager.common.domain.CommandType;
+import org.apache.doris.manager.common.domain.FeInstallCommandRequestBody;
+import org.apache.doris.manager.common.domain.FeStartCommandRequestBody;
+import org.apache.logging.log4j.util.Strings;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URLDecoder;
+
+public class CommandFactory {
+    public static Command get(CommandRequest commandRequest) {
+        String body = null;
+        if (Strings.isNotBlank(commandRequest.getBody())) {
+            try {
+                body = URLDecoder.decode(commandRequest.getBody(), "UTF-8");
+            } catch (UnsupportedEncodingException e) {
+                e.printStackTrace();
+                throw new AgentException(e.getMessage());
+            }
+        }
+
+        switch (CommandType.valueOf(commandRequest.getCommandType())) {
+            case INSTALL_FE:
+                FeInstallCommandRequestBody feInstallCommandRequestBody = JSON.parseObject(body, FeInstallCommandRequestBody.class);
+                return new FeInstallCommand(feInstallCommandRequestBody);
+            case INSTALL_BE:
+                BeInstallCommandRequestBody beInstallCommandRequestBody = JSON.parseObject(body, BeInstallCommandRequestBody.class);
+                return new BeInstallCommand(beInstallCommandRequestBody);
+            case START_FE:
+                FeStartCommandRequestBody feStartCommandRequestBody = JSON.parseObject(body, FeStartCommandRequestBody.class);
+                return new FeStartCommand(feStartCommandRequestBody);
+            case STOP_FE:
+                return new FeStopCommand();
+            case START_BE:
+                return new BeStartCommand();
+            case STOP_BE:
+                return new BeStopCommand();
+            default:
+                throw new AgentException("unkown CommandType");
+        }
+    }
+}
diff --git a/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/command/CommandListener.java b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/command/CommandListener.java
new file mode 100644
index 0000000..9a1dce1
--- /dev/null
+++ b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/command/CommandListener.java
@@ -0,0 +1,23 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.agent.command;
+
+import org.apache.doris.manager.common.domain.CommandType;
+
+public interface CommandListener {
+    void beforeExecute(CommandType commandType);
+}
diff --git a/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/command/CommandResult.java b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/command/CommandResult.java
new file mode 100644
index 0000000..3575b24
--- /dev/null
+++ b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/command/CommandResult.java
@@ -0,0 +1,57 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.agent.command;
+
+import org.apache.doris.manager.agent.task.TaskResult;
+
+import java.util.List;
+
+public class CommandResult {
+    private TaskResult taskResult;
+    private List<String> stdlogs;
+    private List<String> errlogs;
+
+    public CommandResult(TaskResult taskResult, List<String> stdlogs, List<String> errlogs) {
+        this.taskResult = taskResult;
+        this.stdlogs = stdlogs;
+        this.errlogs = errlogs;
+    }
+
+    public TaskResult getTaskResult() {
+        return taskResult;
+    }
+
+    public void setTaskResult(TaskResult taskResult) {
+        this.taskResult = taskResult;
+    }
+
+    public List<String> getStdlogs() {
+        return stdlogs;
+    }
+
+    public void setStdlogs(List<String> stdlogs) {
+        this.stdlogs = stdlogs;
+    }
+
+    public List<String> getErrlogs() {
+        return errlogs;
+    }
+
+    public void setErrlogs(List<String> errlogs) {
+        this.errlogs = errlogs;
+    }
+}
diff --git a/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/command/CommandResultService.java b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/command/CommandResultService.java
new file mode 100644
index 0000000..451df4b
--- /dev/null
+++ b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/command/CommandResultService.java
@@ -0,0 +1,98 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.agent.command;
+
+import org.apache.doris.manager.agent.common.AgentConstants;
+import org.apache.doris.manager.agent.register.BeState;
+import org.apache.doris.manager.agent.register.FeState;
+import org.apache.doris.manager.agent.task.Task;
+import org.apache.doris.manager.agent.task.TaskContext;
+import org.apache.doris.manager.agent.task.TaskResult;
+import org.apache.doris.manager.common.domain.CommandType;
+
+import java.util.Objects;
+
+public class CommandResultService {
+    public static CommandResult commandResult(String taskId) {
+        if (Objects.isNull(TaskContext.getTaskByTaskId(taskId))) {
+            return null;
+        }
+
+        Task task = TaskContext.getTaskByTaskId(taskId);
+        CommandResult commandResult = new CommandResult(task.getTaskResult(),
+                task.getTasklog().allStdLog(),
+                task.getTasklog().allErrLog());
+
+        switch (CommandType.valueOf(task.getTaskDesc().getTaskName())) {
+            case INSTALL_FE:
+            case INSTALL_BE:
+                return commandResult;
+            case START_FE:
+                return feStateResult(task, false);
+            case STOP_FE:
+                return feStateResult(task, true);
+            case START_BE:
+                return beStateResult(task, false);
+            case STOP_BE:
+                return beStateResult(task, true);
+            default:
+                return null;
+        }
+    }
+
+    private static CommandResult feStateResult(Task task, boolean isStop) {
+        if (Objects.isNull(task.getTaskResult().getRetCode()) || task.getTaskResult().getRetCode() != 0) {
+            return new CommandResult(task.getTaskResult(),
+                    task.getTasklog().allStdLog(),
+                    task.getTasklog().allErrLog());
+        }
+
+        // todo: save final status
+        TaskResult tmpTaskResult = new TaskResult(task.getTaskResult());
+        boolean health = FeState.isHealth();
+        if (isStop) {
+            tmpTaskResult.setRetCode(!health ? 0 : AgentConstants.COMMAND_EXECUTE_UNHEALTH_CODE);
+        } else {
+            tmpTaskResult.setRetCode(health ? 0 : AgentConstants.COMMAND_EXECUTE_UNHEALTH_CODE);
+        }
+
+        return new CommandResult(tmpTaskResult,
+                task.getTasklog().allStdLog(),
+                task.getTasklog().allErrLog());
+    }
+
+    private static CommandResult beStateResult(Task task, boolean isStop) {
+        if (Objects.isNull(task.getTaskResult().getRetCode()) || task.getTaskResult().getRetCode() != 0) {
+            return new CommandResult(task.getTaskResult(),
+                    task.getTasklog().allStdLog(),
+                    task.getTasklog().allErrLog());
+        }
+
+        // todo: save final status
+        TaskResult tmpTaskResult = new TaskResult(task.getTaskResult());
+        boolean health = BeState.isHealth();
+        if (isStop) {
+            tmpTaskResult.setRetCode(!health ? 0 : AgentConstants.COMMAND_EXECUTE_UNHEALTH_CODE);
+        } else {
+            tmpTaskResult.setRetCode(health ? 0 : AgentConstants.COMMAND_EXECUTE_UNHEALTH_CODE);
+        }
+
+        return new CommandResult(task.getTaskResult(),
+                task.getTasklog().allStdLog(),
+                task.getTasklog().allErrLog());
+    }
+}
diff --git a/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/command/FeCommand.java b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/command/FeCommand.java
new file mode 100644
index 0000000..f25fdd9
--- /dev/null
+++ b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/command/FeCommand.java
@@ -0,0 +1,34 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.agent.command;
+
+import org.apache.doris.manager.agent.exception.AgentException;
+import org.apache.doris.manager.agent.register.AgentContext;
+import org.apache.doris.manager.common.domain.CommandType;
+import org.apache.doris.manager.common.domain.Role;
+
+import java.util.Objects;
+
+public abstract class FeCommand extends ListenerCommand {
+    @Override
+    public void beforeExecute(CommandType commandType) {
+        if (Objects.isNull(AgentContext.getServiceInstallDir()) || Objects.isNull(AgentContext.getRole()) ||
+                AgentContext.getRole() != Role.FE) {
+            throw new AgentException("service fe not installed");
+        }
+    }
+}
diff --git a/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/command/FeInstallCommand.java b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/command/FeInstallCommand.java
new file mode 100644
index 0000000..12dfb4d
--- /dev/null
+++ b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/command/FeInstallCommand.java
@@ -0,0 +1,61 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.agent.command;
+
+import org.apache.doris.manager.agent.register.AgentContext;
+import org.apache.doris.manager.agent.task.ITaskHandlerFactory;
+import org.apache.doris.manager.agent.task.QueuedTaskHandlerFactory;
+import org.apache.doris.manager.agent.task.ScriptTask;
+import org.apache.doris.manager.agent.task.Task;
+import org.apache.doris.manager.agent.task.TaskHandlerFactory;
+import org.apache.doris.manager.common.domain.CommandType;
+import org.apache.doris.manager.common.domain.FeInstallCommandRequestBody;
+
+public class FeInstallCommand extends Command {
+    private FeInstallCommandRequestBody requestBody;
+
+    public FeInstallCommand(FeInstallCommandRequestBody requestBody) {
+        this.requestBody = requestBody;
+    }
+
+    @Override
+    public Task setupTask() {
+        FeInstallTaskDesc taskDesc = new FeInstallTaskDesc();
+
+        String scriptCmd = AgentContext.getBashBin();
+        scriptCmd += AgentContext.getAgentInstallDir() + "/bin/install_fe.sh ";
+        scriptCmd += " --installDir " + requestBody.getInstallDir();
+        scriptCmd += " --url " + requestBody.getPackageUrl();
+        if (requestBody.getMkFeMetadir()) {
+            scriptCmd += " --mkFeMetadir";
+        }
+
+        taskDesc.setScriptCmd(scriptCmd);
+        taskDesc.setInstallDir(requestBody.getInstallDir());
+        return new ScriptTask(taskDesc, new FeInstallTaskHook());
+    }
+
+    @Override
+    public ITaskHandlerFactory setupTaskHandlerFactory() {
+        return TaskHandlerFactory.getTaskHandlerFactory(QueuedTaskHandlerFactory.class);
+    }
+
+    @Override
+    public CommandType setupCommandType() {
+        return CommandType.INSTALL_FE;
+    }
+}
diff --git a/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/command/FeInstallTaskDesc.java b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/command/FeInstallTaskDesc.java
new file mode 100644
index 0000000..551462c
--- /dev/null
+++ b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/command/FeInstallTaskDesc.java
@@ -0,0 +1,31 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.agent.command;
+
+import org.apache.doris.manager.agent.task.ScriptTaskDesc;
+
+public class FeInstallTaskDesc extends ScriptTaskDesc {
+    private String installDir;
+
+    public String getInstallDir() {
+        return installDir;
+    }
+
+    public void setInstallDir(String installDir) {
+        this.installDir = installDir;
+    }
+}
diff --git a/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/command/FeInstallTaskHook.java b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/command/FeInstallTaskHook.java
new file mode 100644
index 0000000..d2a96ae
--- /dev/null
+++ b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/command/FeInstallTaskHook.java
@@ -0,0 +1,53 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.agent.command;
+
+import org.apache.doris.manager.agent.common.AgentConstants;
+import org.apache.doris.manager.agent.exception.AgentException;
+import org.apache.doris.manager.agent.register.AgentContext;
+import org.apache.doris.manager.common.domain.Role;
+import org.apache.doris.manager.agent.task.TaskHook;
+import org.apache.logging.log4j.util.Strings;
+
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.Properties;
+
+
+public class FeInstallTaskHook extends TaskHook<FeInstallTaskDesc> {
+    @Override
+    public void onSuccess(FeInstallTaskDesc taskDesc) {
+        AgentContext.setRole(Role.FE);
+        AgentContext.setServiceInstallDir(taskDesc.getInstallDir());
+
+        String configFile = AgentContext.getServiceInstallDir().endsWith("/") ? AgentContext.getServiceInstallDir() + "conf/fe.conf" : AgentContext.getServiceInstallDir() + "/conf/fe.conf";
+        Properties props = null;
+        try {
+            props = new Properties();
+            props.load(new FileReader(configFile));
+        } catch (IOException e) {
+            e.printStackTrace();
+            throw new AgentException("load fe conf file fail:" + configFile);
+        }
+
+        if (props != null && Strings.isNotBlank(props.getProperty("http_port"))) {
+            AgentContext.setHealthCheckPort(Integer.valueOf(props.getProperty("http_port")));
+        } else {
+            AgentContext.setHealthCheckPort(AgentConstants.FE_HTTP_PORT_DEFAULT);
+        }
+    }
+}
diff --git a/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/command/FeStartCommand.java b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/command/FeStartCommand.java
new file mode 100644
index 0000000..f9eaf2a
--- /dev/null
+++ b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/command/FeStartCommand.java
@@ -0,0 +1,64 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.agent.command;
+
+import org.apache.doris.manager.agent.register.AgentContext;
+import org.apache.doris.manager.agent.task.ITaskHandlerFactory;
+import org.apache.doris.manager.agent.task.QueuedTaskHandlerFactory;
+import org.apache.doris.manager.agent.task.ScriptTask;
+import org.apache.doris.manager.agent.task.ScriptTaskDesc;
+import org.apache.doris.manager.agent.task.Task;
+import org.apache.doris.manager.agent.task.TaskHandlerFactory;
+import org.apache.doris.manager.common.domain.CommandType;
+import org.apache.doris.manager.common.domain.FeStartCommandRequestBody;
+import org.apache.logging.log4j.util.Strings;
+
+import java.util.Objects;
+
+public class FeStartCommand extends FeCommand {
+    private FeStartCommandRequestBody requestBody;
+
+    public FeStartCommand(FeStartCommandRequestBody requestBody) {
+        this.requestBody = requestBody;
+    }
+
+    @Override
+    public Task setupTask() {
+        ScriptTaskDesc taskDesc = new ScriptTaskDesc();
+
+        String scriptCmd = AgentContext.getBashBin();
+        scriptCmd += AgentContext.getServiceInstallDir() + "/bin/start_fe.sh ";
+        if (Objects.nonNull(requestBody)) {
+            if (requestBody.isHelper() && Strings.isNotBlank(requestBody.getHelpHostPort())) {
+                scriptCmd += " --help " + requestBody.getHelpHostPort();
+            }
+        }
+        scriptCmd += " --daemon";
+        taskDesc.setScriptCmd(scriptCmd);
+        return new ScriptTask(taskDesc);
+    }
+
+    @Override
+    public ITaskHandlerFactory setupTaskHandlerFactory() {
+        return TaskHandlerFactory.getTaskHandlerFactory(QueuedTaskHandlerFactory.class);
+    }
+
+    @Override
+    public CommandType setupCommandType() {
+        return CommandType.START_FE;
+    }
+}
diff --git a/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/command/FeStopCommand.java b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/command/FeStopCommand.java
new file mode 100644
index 0000000..d0c4126
--- /dev/null
+++ b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/command/FeStopCommand.java
@@ -0,0 +1,48 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.agent.command;
+
+import org.apache.doris.manager.agent.register.AgentContext;
+import org.apache.doris.manager.agent.task.ITaskHandlerFactory;
+import org.apache.doris.manager.agent.task.QueuedTaskHandlerFactory;
+import org.apache.doris.manager.agent.task.ScriptTask;
+import org.apache.doris.manager.agent.task.ScriptTaskDesc;
+import org.apache.doris.manager.agent.task.Task;
+import org.apache.doris.manager.agent.task.TaskHandlerFactory;
+import org.apache.doris.manager.common.domain.CommandType;
+
+public class FeStopCommand extends FeCommand {
+    @Override
+    public Task setupTask() {
+        ScriptTaskDesc taskDesc = new ScriptTaskDesc();
+
+        String scriptCmd = AgentContext.getBashBin();
+        scriptCmd += AgentContext.getServiceInstallDir() + "/bin/stop_fe.sh ";
+        taskDesc.setScriptCmd(scriptCmd);
+        return new ScriptTask(taskDesc);
+    }
+
+    @Override
+    public ITaskHandlerFactory setupTaskHandlerFactory() {
+        return TaskHandlerFactory.getTaskHandlerFactory(QueuedTaskHandlerFactory.class);
+    }
+
+    @Override
+    public CommandType setupCommandType() {
+        return CommandType.STOP_FE;
+    }
+}
diff --git a/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/command/ListenerCommand.java b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/command/ListenerCommand.java
new file mode 100644
index 0000000..d6fbade
--- /dev/null
+++ b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/command/ListenerCommand.java
@@ -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.
+package org.apache.doris.manager.agent.command;
+
+import org.apache.doris.manager.agent.task.Task;
+
+public abstract class ListenerCommand extends Command implements CommandListener {
+    @Override
+    public Task execute() {
+        beforeExecute(commandType);
+        return super.execute();
+    }
+}
\ No newline at end of file
diff --git a/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/common/AgentConstants.java b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/common/AgentConstants.java
new file mode 100644
index 0000000..716986f
--- /dev/null
+++ b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/common/AgentConstants.java
@@ -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.
+package org.apache.doris.manager.agent.common;
+
+public class AgentConstants {
+    public static final int COMMAND_LOG_PAGE_SIZE = 1000;
+    public static final int COMMAND_EXECUTE_UNHEALTH_CODE = -1;
+
+    public static final int FE_HTTP_PORT_DEFAULT = 8030;
+    public static final int BE_HTTP_PORT_DEFAULT = 8040;
+
+    public static final int COMMAND_HISTORY_SAVE_MAX_COUNT = 100;
+    public static final int TASK_LOG_ROW_MAX_COUNT = 1000;
+
+}
diff --git a/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/common/PropertiesUtil.java b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/common/PropertiesUtil.java
new file mode 100644
index 0000000..62d1796
--- /dev/null
+++ b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/common/PropertiesUtil.java
@@ -0,0 +1,51 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.agent.common;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.Properties;
+
+public class PropertiesUtil {
+
+    private static final Logger log = LoggerFactory.getLogger(PropertiesUtil.class);
+    private static final String DEFAULT_PROPERTIES = "/application.properties";
+
+    /**
+     * get properties key
+     *
+     * @param propKey
+     * @return
+     */
+    public static String getPropValue(String propKey) {
+        try {
+            Properties props = new Properties();
+            InputStream inputStream = PropertiesUtil.class.getResourceAsStream(DEFAULT_PROPERTIES);
+            BufferedReader bf = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));
+            props.load(bf);
+            return props.getProperty(propKey);
+        } catch (IOException e) {
+            log.error("get propKey error:", e);
+        }
+        return null;
+    }
+}
diff --git a/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/exception/AgentException.java b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/exception/AgentException.java
new file mode 100644
index 0000000..b68714d
--- /dev/null
+++ b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/exception/AgentException.java
@@ -0,0 +1,42 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.agent.exception;
+
+public class AgentException extends RuntimeException {
+    private static final long serialVersionUID = -1L;
+    private static final Integer DEAFULT_EXCEPTION_STATUS = 500;
+    private int status;
+
+
+    public AgentException(String message) {
+        this(message, DEAFULT_EXCEPTION_STATUS);
+    }
+
+    public AgentException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    public AgentException(String message, int status) {
+        super(message);
+        this.status = status;
+    }
+
+    public int getStatus() {
+        return status;
+    }
+
+}
diff --git a/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/exception/GlobalExceptionHandler.java b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/exception/GlobalExceptionHandler.java
new file mode 100644
index 0000000..b641d8c
--- /dev/null
+++ b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/exception/GlobalExceptionHandler.java
@@ -0,0 +1,42 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.agent.exception;
+
+import org.apache.doris.manager.common.domain.RResult;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.RestControllerAdvice;
+
+@RestControllerAdvice
+public class GlobalExceptionHandler {
+
+    private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);
+
+    @ExceptionHandler(AgentException.class)
+    public RResult handleException(AgentException exception) {
+        log.error(exception.getMessage(), exception);
+        return RResult.error(exception.getStatus(), exception.getMessage());
+    }
+
+    @ExceptionHandler(Throwable.class)
+    public RResult javaExceptionHandler(Exception ex) {
+        log.error("agent error ", ex);
+        return RResult.error(5000, "agent error");
+    }
+
+}
diff --git a/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/register/AgentContext.java b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/register/AgentContext.java
new file mode 100644
index 0000000..d090509
--- /dev/null
+++ b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/register/AgentContext.java
@@ -0,0 +1,139 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.agent.register;
+
+
+import org.apache.doris.manager.common.domain.Role;
+import org.apache.logging.log4j.util.Strings;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+
+public class AgentContext {
+    private static Role role = null;
+    private static String serviceInstallDir = null;
+    private static Integer healthCheckPort = null;
+    private static String agentIp = null;
+    private static Integer agentPort = null;
+    private static String agentServer = null;
+    private static String agentInstallDir = null;
+    private static String bashBin = "/bin/sh ";
+
+    public static void init(String role, String agentIp, Integer agentPort, String agentServer, String dorisHomeDir, String agentInstallDir) {
+        if (Strings.isNotBlank(role) && Objects.nonNull(Role.findByName(role))) {
+            AgentContext.setRole(Role.findByName(role));
+        }
+
+        if (Strings.isNotBlank(agentIp)) {
+            AgentContext.setAgentIp(agentIp);
+        }
+
+        if (Objects.nonNull(agentPort)) {
+            AgentContext.setAgentPort(agentPort);
+        }
+
+        if (Strings.isNotBlank(agentServer)) {
+            AgentContext.setAgentServer(agentServer);
+        }
+
+        if (Strings.isNotBlank(dorisHomeDir)) {
+            AgentContext.setServiceInstallDir(dorisHomeDir);
+        }
+
+        if (Strings.isNotBlank(agentInstallDir)) {
+            AgentContext.setAgentInstallDir(agentInstallDir);
+        }
+    }
+
+
+    public static String getBashBin() {
+        return bashBin;
+    }
+
+    public static void setBashBin(String bashBin) {
+        AgentContext.bashBin = bashBin;
+    }
+
+    public static String getAgentInstallDir() {
+        return agentInstallDir;
+    }
+
+    public static void setAgentInstallDir(String agentInstallDir) {
+        AgentContext.agentInstallDir = agentInstallDir;
+    }
+
+    public static Integer getAgentPort() {
+        return agentPort;
+    }
+
+    public static void setAgentPort(Integer agentPort) {
+        AgentContext.agentPort = agentPort;
+    }
+
+    public static void setRole(Role r) {
+        AgentContext.role = r;
+    }
+
+    public static Role getRole() {
+        return AgentContext.role;
+    }
+
+    public static void setServiceInstallDir(String dir) {
+        AgentContext.serviceInstallDir = dir;
+    }
+
+    public static String getServiceInstallDir() {
+        return AgentContext.serviceInstallDir;
+    }
+
+    public static Integer getHealthCheckPort() {
+        return AgentContext.healthCheckPort;
+    }
+
+    public static void setHealthCheckPort(Integer healthCheckPort) {
+        AgentContext.healthCheckPort = healthCheckPort;
+    }
+
+    public static String getAgentIp() {
+        return agentIp;
+    }
+
+    public static void setAgentIp(String agentIp) {
+        AgentContext.agentIp = agentIp;
+    }
+
+    public static String getAgentServer() {
+        return agentServer;
+    }
+
+    public static void setAgentServer(String agentServer) {
+        AgentContext.agentServer = agentServer;
+    }
+
+    public static Map<String, Object> getContext() {
+        HashMap<String, Object> context = new HashMap<>();
+        context.put("role", AgentContext.role);
+        context.put("serviceInstallDir", AgentContext.serviceInstallDir);
+        context.put("healthCheckPort", AgentContext.healthCheckPort);
+        context.put("agentIp", AgentContext.agentIp);
+        context.put("agentPort", AgentContext.agentPort);
+        context.put("agentServer", AgentContext.agentServer);
+        context.put("agentInstallDir", AgentContext.agentInstallDir);
+        return context;
+    }
+}
diff --git a/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/register/AgentHeartbeat.java b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/register/AgentHeartbeat.java
new file mode 100644
index 0000000..97ca69d
--- /dev/null
+++ b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/register/AgentHeartbeat.java
@@ -0,0 +1,62 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.agent.register;
+
+import org.apache.doris.manager.common.domain.RResult;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+
+public class AgentHeartbeat extends BaseRequest {
+
+    private static final Logger log = LoggerFactory.getLogger(AgentHeartbeat.class);
+    private static final long HEARTBEAT_TIME = 10000l;
+    private static final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
+
+    public static void start() {
+        scheduler.scheduleWithFixedDelay(() -> {
+            if (!heartbeat()) {
+                log.error("agent heartbeat fail!");
+            } else {
+                log.info("send heartbeat");
+            }
+        }, 0, HEARTBEAT_TIME, TimeUnit.MILLISECONDS);
+    }
+
+    private static boolean heartbeat() {
+        String requestUrl = "http://" + AgentContext.getAgentServer() + "/server/heartbeat";
+        Map<String, Object> map = new HashMap<>();
+        map.put("host", AgentContext.getAgentIp());
+        map.put("port", AgentContext.getAgentPort());
+
+        RResult res = null;
+        try{
+            res = sendRequest(requestUrl, map);
+        }catch (Exception ex){
+            return false;
+        }
+        if (res.getCode() == 0) {
+            return true;
+        }
+        return false;
+    }
+}
diff --git a/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/register/AgentRegister.java b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/register/AgentRegister.java
new file mode 100644
index 0000000..e6a32c4
--- /dev/null
+++ b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/register/AgentRegister.java
@@ -0,0 +1,44 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.agent.register;
+
+import org.apache.doris.manager.common.domain.RResult;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class AgentRegister extends BaseRequest {
+
+    public static boolean register() {
+
+        String requestUrl = "http://" + AgentContext.getAgentServer() + "/server/register";
+        Map<String, Object> map = new HashMap<>();
+        map.put("host", AgentContext.getAgentIp());
+        map.put("port", AgentContext.getAgentPort());
+
+        RResult res = null;
+        try{
+            res = sendRequest(requestUrl, map);
+        }catch (Exception ex){
+            return false;
+        }
+        if (res.getCode() == 0) {
+            return true;
+        }
+        return false;
+    }
+}
diff --git a/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/register/AgentRole.java b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/register/AgentRole.java
new file mode 100644
index 0000000..46f8d5f
--- /dev/null
+++ b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/register/AgentRole.java
@@ -0,0 +1,40 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.agent.register;
+
+import org.apache.doris.manager.common.domain.RResult;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * query agent role
+ **/
+public class AgentRole extends BaseRequest {
+
+    public static String queryRole() {
+        String requestUrl = "http://" + AgentContext.getAgentServer() + "/server/agentRole";
+        Map<String, Object> map = new HashMap<>();
+        map.put("host", AgentContext.getAgentIp());
+
+        RResult resultResp = sendRequest(requestUrl, map);
+        if (resultResp == null) {
+            return null;
+        }
+        return String.valueOf(resultResp.getData());
+    }
+}
diff --git a/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/register/ApplicationOption.java b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/register/ApplicationOption.java
new file mode 100644
index 0000000..e39ebf6
--- /dev/null
+++ b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/register/ApplicationOption.java
@@ -0,0 +1,33 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.agent.register;
+
+import org.kohsuke.args4j.Option;
+
+public class ApplicationOption {
+    @Option(name = "--agentIp", required = true, usage = "Specify agent agentIp")
+    public String agentIp;
+
+    @Option(name = "--agentServer", required = true, usage = "Specify agent agentServer agentIp:port")
+    public String agentServer;
+
+    @Option(name = "--dorisHomeDir", usage = "Specify service home dir")
+    public String dorisHomeDir;
+
+    @Option(name = "--role", usage = "Specify service role")
+    public String role;
+}
diff --git a/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/register/BaseRequest.java b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/register/BaseRequest.java
new file mode 100644
index 0000000..3601cec
--- /dev/null
+++ b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/register/BaseRequest.java
@@ -0,0 +1,66 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.agent.register;
+
+import com.alibaba.fastjson.JSON;
+import org.apache.doris.manager.common.domain.RResult;
+import org.apache.http.client.config.RequestConfig;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClients;
+import org.apache.http.util.EntityUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.util.Map;
+
+public class BaseRequest {
+
+    private static final Logger log = LoggerFactory.getLogger(BaseRequest.class);
+
+    public static RResult sendRequest(String requestUrl, Map<String, Object> params) {
+        CloseableHttpClient httpclient = HttpClients.createDefault();
+        HttpPost httpPost = new HttpPost(requestUrl);
+
+        RequestConfig requestConfig = RequestConfig.custom().
+                setConnectTimeout(5000).
+                setConnectionRequestTimeout(5000)
+                .setSocketTimeout(5000).build();
+        httpPost.setConfig(requestConfig);
+
+        httpPost.setEntity(new StringEntity(JSON.toJSONString(params), "utf-8"));
+        httpPost.addHeader("Content-Type", "application/json");
+
+        CloseableHttpResponse response = null;
+        String result = "";
+
+        try {
+            response = httpclient.execute(httpPost);
+            result = EntityUtils.toString(response.getEntity());
+        } catch (IOException e) {
+            log.error("request url error:{},param:{}",requestUrl,params,e);
+            throw new RuntimeException(e);
+        }
+
+        RResult res = JSON.parseObject(result, RResult.class);
+        return res;
+    }
+
+}
diff --git a/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/register/BeState.java b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/register/BeState.java
new file mode 100644
index 0000000..cadb973
--- /dev/null
+++ b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/register/BeState.java
@@ -0,0 +1,66 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.agent.register;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import org.apache.http.client.config.RequestConfig;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClients;
+import org.apache.http.util.EntityUtils;
+
+import java.io.IOException;
+
+public class BeState {
+    public static boolean isHealth() {
+        CloseableHttpClient httpclient = HttpClients.createDefault();
+
+        String requestUrl = "http://" + AgentContext.getAgentIp() + ":" + AgentContext.getHealthCheckPort() + "/api/health";
+
+        HttpGet httpget = new HttpGet(requestUrl);
+
+        RequestConfig requestConfig = RequestConfig.custom().
+                setConnectTimeout(5000).
+                setConnectionRequestTimeout(5000)
+                .setSocketTimeout(5000).build();
+        httpget.setConfig(requestConfig);
+
+        CloseableHttpResponse response = null;
+        String result = "";
+
+        try {
+            response = httpclient.execute(httpget);
+            result = EntityUtils.toString(response.getEntity());
+        } catch (IOException e) {
+            e.printStackTrace();
+            return false;
+        }
+
+        JSONObject jsonObject = JSON.parseObject(result);
+        if (jsonObject == null) {
+            return false;
+        }
+
+        String status = jsonObject.getString("status");
+        if ("ok".equalsIgnoreCase(status)) {
+            return true;
+        }
+        return false;
+    }
+}
diff --git a/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/register/FeState.java b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/register/FeState.java
new file mode 100644
index 0000000..3a1b23f
--- /dev/null
+++ b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/register/FeState.java
@@ -0,0 +1,69 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.agent.register;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import org.apache.http.client.config.RequestConfig;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClients;
+import org.apache.http.util.EntityUtils;
+
+import java.io.IOException;
+
+public class FeState {
+    public static boolean isHealth() {
+        CloseableHttpClient httpclient = HttpClients.createDefault();
+
+        String requestUrl = "http://" + AgentContext.getAgentIp() + ":" + AgentContext.getHealthCheckPort() + "/api/bootstrap";
+
+        HttpGet httpget = new HttpGet(requestUrl);
+
+        RequestConfig requestConfig = RequestConfig.custom().
+                setConnectTimeout(5000).
+                setConnectionRequestTimeout(5000)
+                .setSocketTimeout(5000).build();
+        httpget.setConfig(requestConfig);
+
+        CloseableHttpResponse response = null;
+        String result = "";
+
+        try {
+            response = httpclient.execute(httpget);
+            result = EntityUtils.toString(response.getEntity());
+
+        } catch (IOException e) {
+            e.printStackTrace();
+            return false;
+        }
+
+        JSONObject jsonObject = JSON.parseObject(result);
+        if (jsonObject == null) {
+            return false;
+        }
+
+        String code = jsonObject.getString("code");
+        String msg = jsonObject.getString("msg");
+        String status = jsonObject.getString("status");
+        if (("0".equals(code) && "success".equalsIgnoreCase(msg)) || "OK".equalsIgnoreCase(status)) {
+            return true;
+        }
+        return false;
+    }
+}
diff --git a/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/register/StateService.java b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/register/StateService.java
new file mode 100644
index 0000000..2f9002e
--- /dev/null
+++ b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/register/StateService.java
@@ -0,0 +1,39 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.agent.register;
+
+import org.apache.doris.manager.common.domain.Role;
+
+import java.util.Objects;
+
+public class StateService {
+
+    public static boolean isHealth() {
+        Role role = AgentContext.getRole();
+        if (Objects.isNull(role)) {
+            throw new RuntimeException("the service is not installed");
+        }
+        switch (role) {
+            case FE:
+                return FeState.isHealth();
+            case BE:
+                return BeState.isHealth();
+            default:
+                throw new RuntimeException("unkonw role:" + role);
+        }
+    }
+}
diff --git a/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/task/AbsAsyncTaskHandler.java b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/task/AbsAsyncTaskHandler.java
new file mode 100644
index 0000000..9303ca3
--- /dev/null
+++ b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/task/AbsAsyncTaskHandler.java
@@ -0,0 +1,38 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.agent.task;
+
+import java.util.concurrent.ExecutorService;
+
+public abstract class AbsAsyncTaskHandler extends TaskHandler {
+
+    @Override
+    public void doHandle(Task task) {
+        task.getTaskResult().setTaskState(TaskState.QUEUED);
+
+        TaskContext.register(task);
+        getExecutorService().submit(new Runnable() {
+            @Override
+            public void run() {
+                task.executeTask();
+            }
+        });
+    }
+
+    public abstract ExecutorService getExecutorService();
+
+}
diff --git a/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/task/ITaskHandlerFactory.java b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/task/ITaskHandlerFactory.java
new file mode 100644
index 0000000..7913676
--- /dev/null
+++ b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/task/ITaskHandlerFactory.java
@@ -0,0 +1,21 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.agent.task;
+
+public interface ITaskHandlerFactory {
+    TaskHandler createTaskHandler();
+}
diff --git a/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/task/ITaskLog.java b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/task/ITaskLog.java
new file mode 100644
index 0000000..d5dd206
--- /dev/null
+++ b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/task/ITaskLog.java
@@ -0,0 +1,36 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.agent.task;
+
+import javafx.util.Pair;
+
+import java.util.List;
+
+public interface ITaskLog {
+    Pair<Integer, List<String>> stdLog(int offset, int size);
+
+    List<String> errLog(int offset, int size);
+
+    void appendStdLog(String log);
+
+    void appendErrLog(String log);
+
+    List<String> allStdLog();
+
+    List<String> allErrLog();
+}
+
diff --git a/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/task/LRU.java b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/task/LRU.java
new file mode 100644
index 0000000..e81d737
--- /dev/null
+++ b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/task/LRU.java
@@ -0,0 +1,55 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.agent.task;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+public class LRU<K, V> {
+    private final float loadFactory = 0.75f;
+    private LinkedHashMap<K, V> map;
+
+    public LRU(int maxCacheSize) {
+        int capacity = (int) Math.ceil(maxCacheSize / this.loadFactory) + 1;
+        map = new LinkedHashMap<K, V>(capacity, loadFactory, false) {
+            @Override
+            protected boolean removeEldestEntry(Map.Entry eldest) {
+                return size() > maxCacheSize;
+            }
+        };
+    }
+
+    public void put(K key, V value) {
+        map.put(key, value);
+    }
+
+    public V get(K key) {
+        return map.get(key);
+    }
+
+    public void remove(K key) {
+        map.remove(key);
+    }
+
+    public boolean contain(K key) {
+        return map.containsKey(key);
+    }
+
+    public int size() {
+        return map.size();
+    }
+}
diff --git a/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/task/QueuedTaskHandler.java b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/task/QueuedTaskHandler.java
new file mode 100644
index 0000000..3fcebdf
--- /dev/null
+++ b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/task/QueuedTaskHandler.java
@@ -0,0 +1,26 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.agent.task;
+
+import java.util.concurrent.ExecutorService;
+
+public class QueuedTaskHandler extends AbsAsyncTaskHandler {
+    @Override
+    public ExecutorService getExecutorService() {
+        return TaskExecutorService.getSingleThreadExecutor();
+    }
+}
diff --git a/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/task/QueuedTaskHandlerFactory.java b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/task/QueuedTaskHandlerFactory.java
new file mode 100644
index 0000000..9246302
--- /dev/null
+++ b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/task/QueuedTaskHandlerFactory.java
@@ -0,0 +1,32 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.agent.task;
+
+public class QueuedTaskHandlerFactory implements ITaskHandlerFactory {
+    private static TaskHandler instance = null;
+
+    @Override
+    public TaskHandler createTaskHandler() {
+        if (instance == null) {
+            synchronized (QueuedTaskHandlerFactory.class) {
+                if (instance == null)
+                    instance = new QueuedTaskHandler();
+            }
+        }
+        return instance;
+    }
+}
diff --git a/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/task/ScriptTask.java b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/task/ScriptTask.java
new file mode 100644
index 0000000..41c6803
--- /dev/null
+++ b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/task/ScriptTask.java
@@ -0,0 +1,57 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.agent.task;
+
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+
+public class ScriptTask extends Task<ScriptTaskDesc> {
+
+    public ScriptTask(ScriptTaskDesc taskDesc) {
+        super(taskDesc, new TaskLruLog());
+    }
+
+    public ScriptTask(ScriptTaskDesc taskDesc, TaskHook taskHook) {
+        super(taskDesc, new TaskLruLog(), taskHook);
+    }
+
+    @Override
+    protected int execute() {
+        try {
+            Runtime rt = Runtime.getRuntime();
+            Process proc = rt.exec(taskDesc.getScriptCmd());
+            BufferedReader stdInput = new BufferedReader(new InputStreamReader(proc.getInputStream()));
+            BufferedReader stdError = new BufferedReader(new InputStreamReader(proc.getErrorStream()));
+
+
+            String s = null;
+            while ((s = stdInput.readLine()) != null) {
+                getTasklog().appendStdLog(s);
+            }
+
+            while ((s = stdError.readLine()) != null) {
+                getTasklog().appendErrLog(s);
+            }
+
+            int exitVal = proc.waitFor();
+            return exitVal;
+        } catch (Throwable t) {
+            t.printStackTrace();
+        }
+        return -1;
+    }
+}
diff --git a/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/task/ScriptTaskDesc.java b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/task/ScriptTaskDesc.java
new file mode 100644
index 0000000..b10a877
--- /dev/null
+++ b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/task/ScriptTaskDesc.java
@@ -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.
+package org.apache.doris.manager.agent.task;
+
+public class ScriptTaskDesc extends TaskDesc {
+    private String scriptCmd;
+
+    public String getScriptCmd() {
+        return scriptCmd;
+    }
+
+    public void setScriptCmd(String scriptCmd) {
+        this.scriptCmd = scriptCmd;
+    }
+}
diff --git a/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/task/SyncTaskHandler.java b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/task/SyncTaskHandler.java
new file mode 100644
index 0000000..69aaa26
--- /dev/null
+++ b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/task/SyncTaskHandler.java
@@ -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.
+package org.apache.doris.manager.agent.task;
+
+public class SyncTaskHandler extends TaskHandler {
+
+    @Override
+    public void doHandle(Task task) {
+        task.executeTask();
+    }
+}
diff --git a/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/task/SyncTaskHandlerFactory.java b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/task/SyncTaskHandlerFactory.java
new file mode 100644
index 0000000..2db5a13
--- /dev/null
+++ b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/task/SyncTaskHandlerFactory.java
@@ -0,0 +1,32 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.agent.task;
+
+public class SyncTaskHandlerFactory implements ITaskHandlerFactory {
+    private static TaskHandler instance = null;
+
+    @Override
+    public TaskHandler createTaskHandler() {
+        if (instance == null) {
+            synchronized (SyncTaskHandlerFactory.class) {
+                if (instance == null)
+                    instance = new SyncTaskHandler();
+            }
+        }
+        return instance;
+    }
+}
diff --git a/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/task/Task.java b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/task/Task.java
new file mode 100644
index 0000000..884317a
--- /dev/null
+++ b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/task/Task.java
@@ -0,0 +1,84 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.agent.task;
+
+import java.util.Date;
+import java.util.UUID;
+
+public abstract class Task<T extends TaskDesc> {
+    protected T taskDesc;
+    private TaskResult taskResult;
+    private ITaskLog tasklog;
+    private TaskHook taskHook;
+
+
+    private Task(T taskDesc) {
+        this.taskDesc = taskDesc;
+        this.taskResult = new TaskResult();
+        this.taskResult.setTaskId(UUID.randomUUID().toString().replace("-", ""));
+    }
+
+    public Task(T taskDesc, ITaskLog taskLruLog) {
+        this(taskDesc);
+        this.tasklog = taskLruLog;
+    }
+
+    public Task(T taskDesc, ITaskLog taskLruLog, TaskHook taskHook) {
+        this(taskDesc);
+        this.tasklog = taskLruLog;
+        this.taskHook = taskHook;
+    }
+
+
+    public ITaskLog getTasklog() {
+        return tasklog;
+    }
+
+    public String getTaskId() {
+        return this.taskResult.getTaskId();
+    }
+
+    public TaskResult getTaskResult() {
+        return taskResult;
+    }
+
+    public TaskResult executeTask() {
+        this.taskResult.setStartTime(new Date());
+        this.taskResult.setTaskState(TaskState.RUNNING);
+        int code = -501;
+        try {
+            code = execute();
+            if (0 == code && taskHook != null) {
+                taskHook.onSuccess(taskDesc);
+            }
+        } catch (Throwable e) {
+            e.printStackTrace();
+        } finally {
+            this.taskResult.setEndTime(new Date());
+            this.taskResult.setRetCode(code);
+            this.taskResult.setTaskState(TaskState.FINISHED);
+        }
+        return this.taskResult;
+    }
+
+    public T getTaskDesc() {
+        return taskDesc;
+    }
+
+    protected abstract int execute();
+
+}
diff --git a/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/task/TaskContext.java b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/task/TaskContext.java
new file mode 100644
index 0000000..967ab6a
--- /dev/null
+++ b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/task/TaskContext.java
@@ -0,0 +1,35 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.agent.task;
+
+import org.apache.doris.manager.agent.common.AgentConstants;
+
+public class TaskContext {
+    private static final LRU<String, Task> taskLRU = new LRU<>(AgentConstants.COMMAND_HISTORY_SAVE_MAX_COUNT);
+
+    public static synchronized void register(Task task) {
+        taskLRU.put(task.getTaskId(), task);
+    }
+
+    public static synchronized void unregister(Task task) {
+        taskLRU.remove(task.getTaskId());
+    }
+
+    public static synchronized Task getTaskByTaskId(String taskId) {
+        return taskLRU.get(taskId);
+    }
+}
diff --git a/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/task/TaskDesc.java b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/task/TaskDesc.java
new file mode 100644
index 0000000..5700811
--- /dev/null
+++ b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/task/TaskDesc.java
@@ -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.
+package org.apache.doris.manager.agent.task;
+
+public abstract class TaskDesc {
+    private String taskName;
+
+    public String getTaskName() {
+        return taskName;
+    }
+
+    public void setTaskName(String taskName) {
+        this.taskName = taskName;
+    }
+}
diff --git a/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/task/TaskExecutorService.java b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/task/TaskExecutorService.java
new file mode 100644
index 0000000..8afb633
--- /dev/null
+++ b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/task/TaskExecutorService.java
@@ -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.
+package org.apache.doris.manager.agent.task;
+
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+public class TaskExecutorService {
+    private static final ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
+
+    public static ExecutorService getSingleThreadExecutor() {
+        return singleThreadExecutor;
+    }
+}
diff --git a/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/task/TaskHandler.java b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/task/TaskHandler.java
new file mode 100644
index 0000000..6488f61
--- /dev/null
+++ b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/task/TaskHandler.java
@@ -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.
+package org.apache.doris.manager.agent.task;
+
+import java.util.Date;
+
+public abstract class TaskHandler {
+    public void handle(Task task) {
+        task.getTaskResult().setSubmitTime(new Date());
+        doHandle(task);
+    }
+
+    public abstract void doHandle(Task task);
+
+}
diff --git a/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/task/TaskHandlerFactory.java b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/task/TaskHandlerFactory.java
new file mode 100644
index 0000000..eba7df4
--- /dev/null
+++ b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/task/TaskHandlerFactory.java
@@ -0,0 +1,45 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.agent.task;
+
+import org.apache.doris.manager.agent.exception.AgentException;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+public final class TaskHandlerFactory {
+    private static Map<Class, ITaskHandlerFactory> factoryInstanceMap = new ConcurrentHashMap<>();
+
+    public static ITaskHandlerFactory getTaskHandlerFactory(Class<? extends ITaskHandlerFactory> className) {
+        synchronized (factoryInstanceMap) {
+            if (!factoryInstanceMap.containsKey(className)) {
+                ITaskHandlerFactory factory = null;
+                try {
+                    Class<? extends ITaskHandlerFactory> factoryClass = (Class<? extends ITaskHandlerFactory>) Class.forName(className.getName());
+                    factory = factoryClass.newInstance();
+                    factoryInstanceMap.put(className, factory);
+                } catch (Exception e) {
+                    e.printStackTrace();
+                    throw new AgentException("failed create factory:" + className.getName());
+                }
+                return factory;
+            }
+            return factoryInstanceMap.get(className);
+        }
+    }
+
+}
diff --git a/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/task/TaskHook.java b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/task/TaskHook.java
new file mode 100644
index 0000000..ccae3a5
--- /dev/null
+++ b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/task/TaskHook.java
@@ -0,0 +1,5 @@
+package org.apache.doris.manager.agent.task;
+
+public abstract class TaskHook<T extends TaskDesc> {
+    public abstract void onSuccess(T taskDesc);
+}
diff --git a/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/task/TaskLruLog.java b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/task/TaskLruLog.java
new file mode 100644
index 0000000..d4478d0
--- /dev/null
+++ b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/task/TaskLruLog.java
@@ -0,0 +1,92 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.agent.task;
+
+import org.apache.doris.manager.agent.common.AgentConstants;
+import javafx.util.Pair;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class TaskLruLog implements ITaskLog {
+    private LRU<Integer, String> stdlogs;
+    private LRU<Integer, String> errlogs;
+
+    private int currentStdPage = 0;
+    private int currentErrPage = 0;
+
+
+    public TaskLruLog() {
+        this(AgentConstants.TASK_LOG_ROW_MAX_COUNT, AgentConstants.TASK_LOG_ROW_MAX_COUNT);
+    }
+
+    public TaskLruLog(int maxStdCacheSize, int maxErrCacheSize) {
+        this.stdlogs = new LRU<>(maxStdCacheSize);
+        this.errlogs = new LRU<>(maxErrCacheSize);
+    }
+
+    @Override
+    public Pair<Integer, List<String>> stdLog(int offset, int size) {
+        int count = 0;
+        ArrayList<String> list = new ArrayList<>();
+        String temp = null;
+        if (offset > stdlogs.size()) {
+            return new Pair(stdlogs.size() - 1 > 0 ? stdlogs.size() - 1 : 0, list);
+        }
+
+        while (count < size && offset + count < stdlogs.size()) {
+            if ((temp = stdlogs.get(offset + count)) != null) {
+                list.add(temp);
+            }
+            count++;
+        }
+        Pair<Integer, List<String>> pair = new Pair(offset + count, list);
+        return pair;
+    }
+
+    @Override
+    public List<String> errLog(int offset, int size) {
+        int count = 0;
+        ArrayList<String> list = new ArrayList<>();
+        String temp = null;
+        while (count < size) {
+            if ((temp = errlogs.get(offset + count)) != null) {
+                list.add(temp);
+            }
+            count++;
+        }
+        return list;
+    }
+
+    public List<String> allStdLog() {
+        return stdLog(0, stdlogs.size()).getValue();
+    }
+
+    public List<String> allErrLog() {
+        return errLog(0, errlogs.size());
+    }
+
+    @Override
+    public void appendStdLog(String log) {
+        stdlogs.put(currentStdPage++, log);
+    }
+
+    @Override
+    public void appendErrLog(String log) {
+        errlogs.put(currentErrPage++, log);
+    }
+}
diff --git a/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/task/TaskResult.java b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/task/TaskResult.java
new file mode 100644
index 0000000..a4138e8
--- /dev/null
+++ b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/task/TaskResult.java
@@ -0,0 +1,88 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.agent.task;
+
+import java.util.Date;
+
+public class TaskResult {
+    private String taskId;
+    private Date submitTime;
+    private Date startTime;
+    private Date endTime;
+    private TaskState taskState;
+    private Integer retCode;
+
+    public TaskResult() {
+    }
+
+    public TaskResult(TaskResult taskResult) {
+        this.taskId = taskResult.getTaskId();
+        this.submitTime = taskResult.getSubmitTime();
+        this.startTime = taskResult.getStartTime();
+        this.endTime = taskResult.getEndTime();
+        this.taskState = taskResult.getTaskState();
+        this.retCode = taskResult.getRetCode();
+    }
+
+    public TaskState getTaskState() {
+        return taskState;
+    }
+
+    public void setTaskState(TaskState taskState) {
+        this.taskState = taskState;
+    }
+
+    public Date getStartTime() {
+        return startTime;
+    }
+
+    public void setStartTime(Date startTime) {
+        this.startTime = startTime;
+    }
+
+    public String getTaskId() {
+        return taskId;
+    }
+
+    public void setTaskId(String taskId) {
+        this.taskId = taskId;
+    }
+
+    public Date getEndTime() {
+        return endTime;
+    }
+
+    public void setEndTime(Date endTime) {
+        this.endTime = endTime;
+    }
+
+    public Integer getRetCode() {
+        return retCode;
+    }
+
+    public void setRetCode(Integer retCode) {
+        this.retCode = retCode;
+    }
+
+    public Date getSubmitTime() {
+        return submitTime;
+    }
+
+    public void setSubmitTime(Date submitTime) {
+        this.submitTime = submitTime;
+    }
+}
diff --git a/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/task/TaskState.java b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/task/TaskState.java
new file mode 100644
index 0000000..1fbb71b
--- /dev/null
+++ b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/task/TaskState.java
@@ -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.
+package org.apache.doris.manager.agent.task;
+
+public enum TaskState {
+    // Task has been queued for execution by the driver
+    INITIALIZED,
+    // Task has been queued for execution by the driver
+    QUEUED,
+    // Task is currently running
+    RUNNING,
+    // Task has completed
+    FINISHED,
+    // Task state is unkown
+    UNKNOWN
+}
diff --git a/manager/dm-agent/src/main/resources/agent/bin/agent_start.sh b/manager/dm-agent/src/main/resources/agent/bin/agent_start.sh
new file mode 100755
index 0000000..ff3bbfa
--- /dev/null
+++ b/manager/dm-agent/src/main/resources/agent/bin/agent_start.sh
@@ -0,0 +1,88 @@
+#!/usr/bin/env 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.
+
+curdir=`dirname "$0"`
+curdir=`cd "$curdir"; pwd`
+
+OPTS=$(getopt \
+  -n $0 \
+  -o '' \
+  -l 'server:' \
+  -l 'agent:' \
+  -- "$@")
+
+eval set -- "$OPTS"
+
+#host:port
+SERVER=
+AGENT=
+while true; do
+    case "$1" in
+        --server) SERVER=$2 ; shift 2;;
+        --agent) AGENT=$2 ; shift 2;;
+        --) shift ;  break ;;
+        *) echo "Internal error" ; exit 1 ;;
+    esac
+done
+
+if [ x"$SERVER" == x"" ]; then
+    echo "--server ip can not empty!"
+    exit 1
+fi
+
+if [ x"$AGENT" == x"" ]; then
+    echo "--agent ip can not empty!"
+    exit 1
+fi
+export AGENT_HOME=`cd "$curdir/.."; pwd`
+
+#
+# JAVA_OPTS
+# SERVER_PARAMS
+# LOG_DIR
+# PID_DIR
+export JAVA_OPTS="-Xmx1024m"
+export SERVER_PARAMS="--agentServer=$SERVER --agentIp=$AGENT"
+export LOG_DIR="$AGENT_HOME/log"
+export PID_DIR=`cd "$curdir"; pwd`
+
+# java
+if [ "$JAVA_HOME" = "" ]; then
+  echo "Error: JAVA_HOME is not set."
+  exit 1
+fi
+JAVA=$JAVA_HOME/bin/java
+
+# need check and create if the log directory existed before outing message to the log file.
+if [ ! -d $LOG_DIR ]; then
+    mkdir -p $LOG_DIR
+fi
+
+pidfile=$PID_DIR/agent.pid
+
+if [ -f $pidfile ]; then
+  if kill -0 `cat $pidfile` > /dev/null 2>&1; then
+    echo agent running as process `cat $pidfile`.  Stop it first.
+    exit 1
+  fi
+fi
+
+nohup $JAVA $JAVA_OPTS -jar ${AGENT_HOME}/lib/dm-agent.jar $SERVER_PARAMS >> $LOG_DIR/agent.out 2>&1  &
+echo `date` >> $LOG_DIR/agent.out
+
+echo $! > $pidfile
diff --git a/manager/dm-agent/src/main/resources/agent/bin/agent_stop.sh b/manager/dm-agent/src/main/resources/agent/bin/agent_stop.sh
new file mode 100755
index 0000000..e651584
--- /dev/null
+++ b/manager/dm-agent/src/main/resources/agent/bin/agent_stop.sh
@@ -0,0 +1,40 @@
+#!/usr/bin/env 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.
+
+curdir=`dirname "$0"`
+curdir=`cd "$curdir"; pwd`
+
+export AGENT_HOME=`cd "$curdir/.."; pwd`
+export PID_DIR=`cd "$curdir"; pwd`
+
+pidfile=$PID_DIR/agent.pid
+
+if [ -f $pidfile ]; then
+   pid=`cat $pidfile`
+   pidcomm=`ps -p $pid -o comm=`
+
+   if [ "java" != "$pidcomm" ]; then
+       echo "ERROR: pid process may not be agent. "
+   fi
+
+   if kill -9 $pid > /dev/null 2>&1; then
+        echo "stop $pidcomm, and remove pid file. "
+        rm $pidfile
+   fi
+fi
+
diff --git a/manager/dm-agent/src/main/resources/agent/bin/install_be.sh b/manager/dm-agent/src/main/resources/agent/bin/install_be.sh
new file mode 100755
index 0000000..a90725b
--- /dev/null
+++ b/manager/dm-agent/src/main/resources/agent/bin/install_be.sh
@@ -0,0 +1,68 @@
+#!/usr/bin/env 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.
+
+curdir=`dirname "$0"`
+curdir=`cd "$curdir"; pwd`
+
+OPTS=$(getopt \
+  -n $0 \
+  -o '' \
+  -l 'url:' \
+  -l 'installDir:' \
+  -l 'mkBeStorageDir' \
+  -- "$@")
+
+eval set -- "$OPTS"
+
+URL=
+DORIS_HOME=
+MKDIR_BE_STORAGE_DIR=0
+while true; do
+    case "$1" in
+        --url) URL=$2 ; shift 2;;
+        --installDir) DORIS_HOME=$2 ; shift 2;;
+        --mkBeStorageDir) MKDIR_BE_STORAGE_DIR=1 ; shift ;;
+        --) shift ;  break ;;
+        *) echo "Internal error" ; exit 1 ;;
+    esac
+done
+
+if [ x"$DORIS_HOME" == x"" ]; then
+    echo "--installDir can not empty!"
+    exit 1
+fi
+
+if [ x"$URL" == x"" ]; then
+    echo "--url can not empty!"
+    exit 1
+fi
+
+if [ ! -d $DORIS_HOME ]; then
+    mkdir -p $DORIS_HOME
+fi
+
+wget  $URL -O doris-be.tar.gz --quiet
+if [ $? -ne 0 ] ;then exit 1;fi
+
+tar -zxvf doris-be.tar.gz -C $DORIS_HOME
+if [ $? -ne 0 ] ;then exit 1;fi
+
+if [[ ${MKDIR_BE_STORAGE_DIR} -eq 1 ]] && [[ ! -d "$DORIS_HOME/storage" ]]; then
+  mkdir $DORIS_HOME/storage
+fi
+if [ $? -ne 0 ] ;then exit 1;fi
\ No newline at end of file
diff --git a/manager/dm-agent/src/main/resources/agent/bin/install_fe.sh b/manager/dm-agent/src/main/resources/agent/bin/install_fe.sh
new file mode 100755
index 0000000..36f5825
--- /dev/null
+++ b/manager/dm-agent/src/main/resources/agent/bin/install_fe.sh
@@ -0,0 +1,68 @@
+#!/usr/bin/env 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.
+
+curdir=`dirname "$0"`
+curdir=`cd "$curdir"; pwd`
+
+OPTS=$(getopt \
+  -n $0 \
+  -o '' \
+  -l 'url:' \
+  -l 'installDir:' \
+  -l 'mkFeMetadir' \
+  -- "$@")
+
+eval set -- "$OPTS"
+
+URL=
+DORIS_HOME=
+MKDIR_FE_META_DIR=0
+while true; do
+    case "$1" in
+        --url) URL=$2 ; shift 2;;
+        --installDir) DORIS_HOME=$2 ; shift 2;;
+        --mkFeMetadir) MKDIR_FE_META_DIR=1 ; shift ;;
+        --) shift ;  break ;;
+        *) echo "Internal error" ; exit 1 ;;
+    esac
+done
+
+if [ x"$DORIS_HOME" == x"" ]; then
+    echo "--installDir can not empty!"
+    exit 1
+fi
+
+if [ x"$URL" == x"" ]; then
+    echo "--url can not empty!"
+    exit 1
+fi
+
+if [ ! -d $DORIS_HOME ]; then
+    mkdir -p $DORIS_HOME
+fi
+
+wget  $URL -O doris-fe.tar.gz --quiet
+if [ $? -ne 0 ] ;then exit 1;fi
+
+tar -zxvf doris-fe.tar.gz  -C $DORIS_HOME
+if [ $? -ne 0 ] ;then exit 1;fi
+
+if [[ ${MKDIR_FE_META_DIR} -eq 1 ]] && [[ ! -d "$DORIS_HOME/doris-meta" ]]; then
+  mkdir $DORIS_HOME/doris-meta
+fi
+if [ $? -ne 0 ] ;then exit 1;fi
\ No newline at end of file
diff --git a/manager/dm-agent/src/main/resources/application.properties b/manager/dm-agent/src/main/resources/application.properties
new file mode 100644
index 0000000..542e0e3
--- /dev/null
+++ b/manager/dm-agent/src/main/resources/application.properties
@@ -0,0 +1 @@
+server.port=9602
\ No newline at end of file
diff --git a/manager/dm-agent/src/main/resources/logback-spring.xml b/manager/dm-agent/src/main/resources/logback-spring.xml
new file mode 100644
index 0000000..22cd80a
--- /dev/null
+++ b/manager/dm-agent/src/main/resources/logback-spring.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration debug="false">
+    <springProperty scope="context" name="springAppName" source="spring.application.name" defaultValue="agent" />
+    <property name="LOG_HOME" value="./log"/>
+    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
+        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
+            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
+        </encoder>
+    </appender>
+    <appender name="FILE"  class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
+            <FileNamePattern>${LOG_HOME}/${springAppName}.%d{yyyy-MM-dd}.%i.log</FileNamePattern>
+            <MaxHistory>30</MaxHistory>
+            <maxFileSize>50MB</maxFileSize>
+            <totalSizeCap>10GB</totalSizeCap>
+        </rollingPolicy>
+        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
+            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
+        </encoder>
+    </appender>
+
+    <root level="INFO">
+        <appender-ref ref="STDOUT" />
+        <appender-ref ref="FILE" />
+    </root>
+</configuration>
\ No newline at end of file
diff --git a/manager/dm-common/pom.xml b/manager/dm-common/pom.xml
new file mode 100644
index 0000000..b9dd5e1
--- /dev/null
+++ b/manager/dm-common/pom.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>doris-manager</artifactId>
+        <groupId>org.apache.doris</groupId>
+        <version>1.0.0</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>dm-common</artifactId>
+    <packaging>jar</packaging>
+
+</project>
\ No newline at end of file
diff --git a/manager/dm-common/src/main/java/org/apache/doris/manager/common/domain/BeInstallCommandRequestBody.java b/manager/dm-common/src/main/java/org/apache/doris/manager/common/domain/BeInstallCommandRequestBody.java
new file mode 100644
index 0000000..662c67c
--- /dev/null
+++ b/manager/dm-common/src/main/java/org/apache/doris/manager/common/domain/BeInstallCommandRequestBody.java
@@ -0,0 +1,48 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.common.domain;
+
+public class BeInstallCommandRequestBody {
+    private String installDir;
+    private String packageUrl;
+    private boolean mkBeStorageDir = false;
+
+
+    public boolean isMkBeStorageDir() {
+        return mkBeStorageDir;
+    }
+
+    public void setMkBeStorageDir(boolean mkBeStorageDir) {
+        this.mkBeStorageDir = mkBeStorageDir;
+    }
+
+    public String getPackageUrl() {
+        return packageUrl;
+    }
+
+    public void setPackageUrl(String packageUrl) {
+        this.packageUrl = packageUrl;
+    }
+
+    public String getInstallDir() {
+        return installDir;
+    }
+
+    public void setInstallDir(String installDir) {
+        this.installDir = installDir;
+    }
+}
diff --git a/manager/dm-common/src/main/java/org/apache/doris/manager/common/domain/CommandRequest.java b/manager/dm-common/src/main/java/org/apache/doris/manager/common/domain/CommandRequest.java
new file mode 100644
index 0000000..999990e
--- /dev/null
+++ b/manager/dm-common/src/main/java/org/apache/doris/manager/common/domain/CommandRequest.java
@@ -0,0 +1,38 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.common.domain;
+
+public class CommandRequest {
+    private String commandType;
+    private String body;
+
+    public String getCommandType() {
+        return commandType;
+    }
+
+    public void setCommandType(String commandType) {
+        this.commandType = commandType;
+    }
+
+    public String getBody() {
+        return body;
+    }
+
+    public void setBody(String body) {
+        this.body = body;
+    }
+}
diff --git a/manager/dm-common/src/main/java/org/apache/doris/manager/common/domain/CommandType.java b/manager/dm-common/src/main/java/org/apache/doris/manager/common/domain/CommandType.java
new file mode 100644
index 0000000..25738bd
--- /dev/null
+++ b/manager/dm-common/src/main/java/org/apache/doris/manager/common/domain/CommandType.java
@@ -0,0 +1,40 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.common.domain;
+
+public enum CommandType {
+    INSTALL_FE,
+
+    INSTALL_BE,
+
+    START_FE,
+
+    STOP_FE,
+
+    START_BE,
+
+    STOP_BE;
+
+    public static CommandType findByName(String name) {
+        for (CommandType type : CommandType.values()) {
+            if (type.name().equals(name)) {
+                return type;
+            }
+        }
+        return null;
+    }
+}
diff --git a/manager/dm-common/src/main/java/org/apache/doris/manager/common/domain/FeInstallCommandRequestBody.java b/manager/dm-common/src/main/java/org/apache/doris/manager/common/domain/FeInstallCommandRequestBody.java
new file mode 100644
index 0000000..0a68d62
--- /dev/null
+++ b/manager/dm-common/src/main/java/org/apache/doris/manager/common/domain/FeInstallCommandRequestBody.java
@@ -0,0 +1,47 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.common.domain;
+
+public class FeInstallCommandRequestBody {
+    private String packageUrl;
+    private String installDir;
+    private Boolean mkFeMetadir = false;
+
+    public String getInstallDir() {
+        return installDir;
+    }
+
+    public void setInstallDir(String installDir) {
+        this.installDir = installDir;
+    }
+
+    public String getPackageUrl() {
+        return packageUrl;
+    }
+
+    public void setPackageUrl(String packageUrl) {
+        this.packageUrl = packageUrl;
+    }
+
+    public Boolean getMkFeMetadir() {
+        return mkFeMetadir;
+    }
+
+    public void setMkFeMetadir(Boolean mkFeMetadir) {
+        this.mkFeMetadir = mkFeMetadir;
+    }
+}
diff --git a/manager/dm-common/src/main/java/org/apache/doris/manager/common/domain/FeStartCommandRequestBody.java b/manager/dm-common/src/main/java/org/apache/doris/manager/common/domain/FeStartCommandRequestBody.java
new file mode 100644
index 0000000..894c7e3
--- /dev/null
+++ b/manager/dm-common/src/main/java/org/apache/doris/manager/common/domain/FeStartCommandRequestBody.java
@@ -0,0 +1,38 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.common.domain;
+
+public class FeStartCommandRequestBody {
+    private boolean helper;
+    private String helpHostPort;
+
+    public boolean isHelper() {
+        return helper;
+    }
+
+    public void setHelper(boolean helper) {
+        this.helper = helper;
+    }
+
+    public String getHelpHostPort() {
+        return helpHostPort;
+    }
+
+    public void setHelpHostPort(String helpHostPort) {
+        this.helpHostPort = helpHostPort;
+    }
+}
diff --git a/manager/dm-common/src/main/java/org/apache/doris/manager/common/domain/RResult.java b/manager/dm-common/src/main/java/org/apache/doris/manager/common/domain/RResult.java
new file mode 100644
index 0000000..3818543
--- /dev/null
+++ b/manager/dm-common/src/main/java/org/apache/doris/manager/common/domain/RResult.java
@@ -0,0 +1,84 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.common.domain;
+
+import java.util.HashMap;
+import java.util.Objects;
+
+public class RResult extends HashMap<String, Object> {
+    private static final long serialVersionUID = 1L;
+    private static final int CODE_SUCCESS = 0;
+    public static final String CODE_TAG = "code";
+    public static final String MSG_TAG = "msg";
+    public static final String DATA_TAG = "data";
+
+    public RResult() {
+    }
+
+    public RResult(int code, String msg) {
+        super.put(CODE_TAG, code);
+        super.put(MSG_TAG, msg);
+    }
+
+    public RResult(int code, String msg, Object data) {
+        super.put(CODE_TAG, code);
+        super.put(MSG_TAG, msg);
+        if (!Objects.isNull(data)) {
+            super.put(DATA_TAG, data);
+        }
+    }
+
+    public static RResult success() {
+        return RResult.success("success");
+    }
+
+    public static RResult success(Object data) {
+        return RResult.success("success", data);
+    }
+
+    public static RResult success(String msg) {
+        return RResult.success(msg, null);
+    }
+
+    public static RResult success(String msg, Object data) {
+        return new RResult(CODE_SUCCESS, msg, data);
+    }
+
+    public static RResult error() {
+        return RResult.error("fail");
+    }
+
+    public static RResult error(String msg) {
+        return RResult.error(msg, null);
+    }
+
+    public static RResult error(String msg, Object data) {
+        return new RResult(CODE_SUCCESS, msg, data);
+    }
+
+    public static RResult error(int code, String msg) {
+        return new RResult(code, msg, null);
+    }
+
+    public Object getData() {
+        return this.get("data");
+    }
+
+    public int getCode() {
+        return (int) this.get("code");
+    }
+}
diff --git a/manager/dm-common/src/main/java/org/apache/doris/manager/common/domain/Role.java b/manager/dm-common/src/main/java/org/apache/doris/manager/common/domain/Role.java
new file mode 100644
index 0000000..683d7ac
--- /dev/null
+++ b/manager/dm-common/src/main/java/org/apache/doris/manager/common/domain/Role.java
@@ -0,0 +1,31 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.common.domain;
+
+public enum Role {
+    FE,
+    BE;
+
+    public static Role findByName(String name) {
+        for (Role type : Role.values()) {
+            if (type.name().equals(name)) {
+                return type;
+            }
+        }
+        return null;
+    }
+}
diff --git a/manager/dm-server/pom.xml b/manager/dm-server/pom.xml
new file mode 100644
index 0000000..cda05a9
--- /dev/null
+++ b/manager/dm-server/pom.xml
@@ -0,0 +1,83 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <groupId>org.apache.doris</groupId>
+        <artifactId>doris-manager</artifactId>
+        <version>1.0.0</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>dm-server</artifactId>
+    <packaging>jar</packaging>
+
+    <name>dm-server</name>
+
+    <properties>
+        <java.version>1.8</java.version>
+    </properties>
+    <dependencies>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-web</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-test</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-jdbc</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>mysql</groupId>
+            <artifactId>mysql-connector-java</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.doris</groupId>
+            <artifactId>dm-common</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>commons-io</groupId>
+            <artifactId>commons-io</artifactId>
+            <version>2.5</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-lang3</artifactId>
+            <version>3.9</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.httpcomponents</groupId>
+            <artifactId>httpclient</artifactId>
+            <version>4.5.6</version>
+        </dependency>
+        <dependency>
+            <groupId>com.alibaba</groupId>
+            <artifactId>fastjson</artifactId>
+            <version>1.2.76</version>
+        </dependency>
+
+    </dependencies>
+
+    <build>
+        <resources>
+            <resource>
+                <directory>src/main/resources</directory>
+            </resource>
+        </resources>
+        <plugins>
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+            </plugin>
+        </plugins>
+    </build>
+</project>
diff --git a/manager/dm-server/src/main/java/org/apache/doris/manager/server/DmServerApplication.java b/manager/dm-server/src/main/java/org/apache/doris/manager/server/DmServerApplication.java
new file mode 100644
index 0000000..af7801a
--- /dev/null
+++ b/manager/dm-server/src/main/java/org/apache/doris/manager/server/DmServerApplication.java
@@ -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.
+package org.apache.doris.manager.server;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class DmServerApplication {
+
+    public static void main(String[] args) {
+        SpringApplication.run(DmServerApplication.class, args);
+    }
+}
diff --git a/manager/dm-server/src/main/java/org/apache/doris/manager/server/agent/AgentCache.java b/manager/dm-server/src/main/java/org/apache/doris/manager/server/agent/AgentCache.java
new file mode 100644
index 0000000..b83e88b
--- /dev/null
+++ b/manager/dm-server/src/main/java/org/apache/doris/manager/server/agent/AgentCache.java
@@ -0,0 +1,68 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.server.agent;
+
+import org.apache.doris.manager.server.dao.ServerDao;
+import org.apache.doris.manager.server.entity.AgentEntity;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.PostConstruct;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.stream.Collectors;
+
+/**
+ * agent host port cache
+ **/
+@Component
+public class AgentCache {
+
+    private static final Map<String, AgentEntity> hostAgentCache = new ConcurrentHashMap<>();
+
+    @Autowired
+    private ServerDao serverDao;
+
+    @PostConstruct
+    public void init() {
+        loadAgents();
+    }
+
+    private void loadAgents() {
+        List<AgentEntity> agentEntities = serverDao.queryAgentNodes(new ArrayList<>());
+        if (agentEntities != null && !agentEntities.isEmpty()) {
+            Map<String, AgentEntity> agentsMap = agentEntities.stream().collect(Collectors.toMap(AgentEntity::getHost, v -> v));
+            hostAgentCache.putAll(agentsMap);
+        }
+    }
+
+    /**
+     * get agent from cache by host
+     */
+    public AgentEntity agentInfo(String host) {
+        return hostAgentCache.get(host);
+    }
+
+    /**
+     * put agent to cache
+     */
+    public void putAgent(AgentEntity agent) {
+        hostAgentCache.put(agent.getHost(),agent);
+    }
+}
diff --git a/manager/dm-server/src/main/java/org/apache/doris/manager/server/agent/AgentHeatbeatRunner.java b/manager/dm-server/src/main/java/org/apache/doris/manager/server/agent/AgentHeatbeatRunner.java
new file mode 100644
index 0000000..9808ab4
--- /dev/null
+++ b/manager/dm-server/src/main/java/org/apache/doris/manager/server/agent/AgentHeatbeatRunner.java
@@ -0,0 +1,85 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.server.agent;
+
+import org.apache.doris.manager.server.constants.AgentStatus;
+import org.apache.doris.manager.server.entity.AgentEntity;
+import org.apache.doris.manager.server.service.ServerProcess;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.ApplicationArguments;
+import org.springframework.boot.ApplicationRunner;
+import org.springframework.stereotype.Component;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * agent status check
+ **/
+@Component
+public class AgentHeatbeatRunner implements ApplicationRunner {
+
+    private static final Logger log = LoggerFactory.getLogger(AgentHeatbeatRunner.class);
+    private static final long HEALTH_TIME = 60 * 1000l;
+    private static final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
+
+    @Autowired
+    private ServerProcess serverProcess;
+
+    @Override
+    public void run(ApplicationArguments args) throws Exception {
+        this.scheduler.scheduleWithFixedDelay(() -> {
+            try {
+                heartbeatCheck();
+            } catch (Exception ex) {
+                log.error("heartbeat check fail:", ex);
+            }
+        }, 0, HEALTH_TIME, TimeUnit.MILLISECONDS);
+    }
+
+    /**
+     * The last heartbeat time exceeds the HEALTH_TIME and is recognized as unhealthy
+     */
+    private void heartbeatCheck() {
+        long currTime = System.currentTimeMillis();
+        List<AgentEntity> unHealthAgent = new ArrayList<>();
+        List<AgentEntity> agents = serverProcess.agentList();
+        for (AgentEntity agent : agents) {
+            Date lastReportedTime = agent.getLastReportedTime();
+            long diff = HEALTH_TIME + 1;
+            if(lastReportedTime != null){
+                diff = currTime - lastReportedTime.getTime();
+            }
+            if (diff > HEALTH_TIME) {
+                AgentEntity agentEntity = new AgentEntity();
+                agentEntity.setId(agent.getId());
+                agentEntity.setStatus(AgentStatus.STOP.name());
+                unHealthAgent.add(agentEntity);
+                log.warn("agent {} is unhealthly", agent.getHost());
+            }
+        }
+        if (!unHealthAgent.isEmpty()) {
+            serverProcess.updateBatchAgentStatus(unHealthAgent);
+        }
+    }
+}
diff --git a/manager/dm-server/src/main/java/org/apache/doris/manager/server/agent/AgentRest.java b/manager/dm-server/src/main/java/org/apache/doris/manager/server/agent/AgentRest.java
new file mode 100644
index 0000000..2043bb8
--- /dev/null
+++ b/manager/dm-server/src/main/java/org/apache/doris/manager/server/agent/AgentRest.java
@@ -0,0 +1,63 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.server.agent;
+
+import org.apache.doris.manager.common.domain.RResult;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+import org.springframework.web.client.RestTemplate;
+
+import java.util.Map;
+
+/**
+ * agent rest api
+ **/
+@Component
+public class AgentRest {
+
+    @Autowired
+    private RestTemplate restTemplate;
+
+    private static final String AGENT_COMMAND_EXEC = "http://%s:%s/command/execute";
+    private static final String AGENT_TASK_INFO = "http://%s:%s/command/result?taskId={taskId}";
+    private static final String AGENT_TASK_STD_LOG = "http://%s:%s/command/stdlog?taskId={taskId}&offset={offset}";
+    private static final String AGENT_TASK_ERR_LOG = "http://%s:%s/command/errlog?taskId={taskId}&offset={offset}";
+
+    public RResult commandExec(String host, Integer port, Object param) {
+        String restUrl = String.format(AGENT_COMMAND_EXEC, host, port);
+        RResult result = restTemplate.postForObject(restUrl, param, RResult.class);
+        return result;
+    }
+
+    public RResult taskInfo(String host, Integer port, Map<String, Object> param) {
+        String restUrl = String.format(AGENT_TASK_INFO, host, port);
+        RResult result = restTemplate.getForObject(restUrl, RResult.class, param);
+        return result;
+    }
+
+    public RResult taskStdLog(String host, Integer port, Map<String, Object> param) {
+        String restUrl = String.format(AGENT_TASK_STD_LOG, host, port);
+        RResult result = restTemplate.getForObject(restUrl, RResult.class, param);
+        return result;
+    }
+
+    public RResult taskErrLog(String host, Integer port, Map<String, Object> param) {
+        String restUrl = String.format(AGENT_TASK_ERR_LOG, host, port);
+        RResult result = restTemplate.getForObject(restUrl, RResult.class, param);
+        return result;
+    }
+}
diff --git a/manager/dm-server/src/main/java/org/apache/doris/manager/server/config/RestTemplateConfig.java b/manager/dm-server/src/main/java/org/apache/doris/manager/server/config/RestTemplateConfig.java
new file mode 100644
index 0000000..c6e82fa
--- /dev/null
+++ b/manager/dm-server/src/main/java/org/apache/doris/manager/server/config/RestTemplateConfig.java
@@ -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.
+package org.apache.doris.manager.server.config;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.client.RestTemplate;
+
+
+@Configuration
+public class RestTemplateConfig {
+    @Bean
+    public RestTemplate restTemplate() {
+        return new RestTemplate();
+    }
+}
diff --git a/manager/dm-server/src/main/java/org/apache/doris/manager/server/constants/AgentStatus.java b/manager/dm-server/src/main/java/org/apache/doris/manager/server/constants/AgentStatus.java
new file mode 100644
index 0000000..8da4e9e
--- /dev/null
+++ b/manager/dm-server/src/main/java/org/apache/doris/manager/server/constants/AgentStatus.java
@@ -0,0 +1,22 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.server.constants;
+
+public enum AgentStatus {
+    RUNNING,
+    STOP;
+}
diff --git a/manager/dm-server/src/main/java/org/apache/doris/manager/server/constants/CmdTypeEnum.java b/manager/dm-server/src/main/java/org/apache/doris/manager/server/constants/CmdTypeEnum.java
new file mode 100644
index 0000000..49d7c9b
--- /dev/null
+++ b/manager/dm-server/src/main/java/org/apache/doris/manager/server/constants/CmdTypeEnum.java
@@ -0,0 +1,32 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.server.constants;
+
+public enum CmdTypeEnum {
+    START,
+    STOP,
+    RESTART;
+
+    public static CmdTypeEnum findByName(String name) {
+        for (CmdTypeEnum type : CmdTypeEnum.values()) {
+            if (type.name().equals(name)) {
+                return type;
+            }
+        }
+        return null;
+    }
+}
diff --git a/manager/dm-server/src/main/java/org/apache/doris/manager/server/constants/Constants.java b/manager/dm-server/src/main/java/org/apache/doris/manager/server/constants/Constants.java
new file mode 100644
index 0000000..eabfc8f
--- /dev/null
+++ b/manager/dm-server/src/main/java/org/apache/doris/manager/server/constants/Constants.java
@@ -0,0 +1,24 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.server.constants;
+
+public class Constants {
+
+    public static String KEY_SERVER_PORT = "server.port";
+    public static String KEY_DORIS_AGENT_INSTALL_DIR = "doris.manager.agent.install.dir";
+    public static String KEY_DORIS_AGENT_START_SCRIPT = "doris.manager.agent.start-script";
+}
diff --git a/manager/dm-server/src/main/java/org/apache/doris/manager/server/controller/AgentController.java b/manager/dm-server/src/main/java/org/apache/doris/manager/server/controller/AgentController.java
new file mode 100644
index 0000000..b182cc7
--- /dev/null
+++ b/manager/dm-server/src/main/java/org/apache/doris/manager/server/controller/AgentController.java
@@ -0,0 +1,79 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.server.controller;
+
+import org.apache.doris.manager.common.domain.RResult;
+import org.apache.doris.manager.server.model.req.DorisExecReq;
+import org.apache.doris.manager.server.model.req.DorisInstallReq;
+import org.apache.doris.manager.server.model.req.TaskInfoReq;
+import org.apache.doris.manager.server.model.req.TaskLogReq;
+import org.apache.doris.manager.server.service.ServerAgent;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RestController;
+
+
+@RestController
+@RequestMapping("/agent")
+public class AgentController {
+
+    @Autowired
+    private ServerAgent serverAgent;
+
+    /**
+     * install doris
+     */
+    @RequestMapping(value = "/installDoris", method = RequestMethod.POST)
+    public RResult install(@RequestBody DorisInstallReq installReq) {
+        return RResult.success(serverAgent.install(installReq));
+    }
+
+    /**
+     * request agent:start stop fe/be
+     */
+    @RequestMapping(value = "/execute", method = RequestMethod.POST)
+    public RResult execute(@RequestBody DorisExecReq dorisExec) {
+        return RResult.success(serverAgent.execute(dorisExec));
+    }
+
+    /**
+     * request task detail
+     */
+    @RequestMapping(value = "/task", method = RequestMethod.POST)
+    public RResult taskInfo(@RequestBody TaskInfoReq taskInfo) {
+        return serverAgent.taskInfo(taskInfo);
+    }
+
+    /**
+     * request task stdout log
+     */
+    @RequestMapping(value = "/stdlog", method = RequestMethod.POST)
+    public RResult taskStdlog(@RequestBody TaskLogReq taskInfo) {
+        return serverAgent.taskStdlog(taskInfo);
+    }
+
+    /**
+     * request task error log
+     */
+    @RequestMapping(value = "/errlog", method = RequestMethod.POST)
+    public RResult taskErrlog(@RequestBody TaskLogReq taskInfo) {
+        return serverAgent.taskErrlog(taskInfo);
+    }
+
+}
diff --git a/manager/dm-server/src/main/java/org/apache/doris/manager/server/controller/ServerController.java b/manager/dm-server/src/main/java/org/apache/doris/manager/server/controller/ServerController.java
new file mode 100644
index 0000000..7a542c7
--- /dev/null
+++ b/manager/dm-server/src/main/java/org/apache/doris/manager/server/controller/ServerController.java
@@ -0,0 +1,90 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.server.controller;
+
+import org.apache.doris.manager.common.domain.RResult;
+import org.apache.doris.manager.server.model.req.AgentCommon;
+import org.apache.doris.manager.server.model.req.SshInfo;
+import org.apache.doris.manager.server.service.ServerProcess;
+import org.apache.doris.manager.server.util.Preconditions;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.Map;
+
+@RestController
+@RequestMapping("/server")
+public class ServerController {
+
+    private static final Logger log = LoggerFactory.getLogger(ServerController.class);
+
+    @Autowired
+    private ServerProcess serverProcess;
+
+    /**
+     * install and start agent
+     */
+    @RequestMapping(value = "/installAgent", method = RequestMethod.POST)
+    public RResult installAgent(@RequestBody SshInfo sshInfo) {
+        serverProcess.initAgent(sshInfo);
+        serverProcess.startAgent(sshInfo);
+        return RResult.success();
+    }
+
+    /**
+     * agent info list
+     */
+    @RequestMapping(value = "/agentList", method = RequestMethod.POST)
+    public RResult agentList() {
+        return RResult.success(serverProcess.agentList());
+    }
+
+    /**
+     * agent role info
+     */
+    @RequestMapping(value = "/agentRole", method = RequestMethod.POST)
+    public RResult agentRole(@RequestBody Map<String, Object> params) {
+        Preconditions.checkArgument(params.containsKey("host"), "host can not empty");
+        String host = params.get("host").toString();
+        return RResult.success(serverProcess.agentRole(host));
+    }
+
+    /**
+     * heatbeat report api
+     */
+    @RequestMapping(value = "/heartbeat", method = RequestMethod.POST)
+    public RResult heartbeat(@RequestBody AgentCommon agent) {
+        log.info("{} heartbeat.", agent.getHost());
+        serverProcess.heartbeat(agent.getHost(), agent.getPort());
+        return RResult.success();
+    }
+
+    /**
+     * register report api
+     */
+    @RequestMapping(value = "/register", method = RequestMethod.POST)
+    public RResult register(@RequestBody AgentCommon agent) {
+        log.info("{} register.", agent.getHost());
+        return serverProcess.register(agent.getHost(), agent.getPort());
+    }
+
+}
diff --git a/manager/dm-server/src/main/java/org/apache/doris/manager/server/dao/ServerDao.java b/manager/dm-server/src/main/java/org/apache/doris/manager/server/dao/ServerDao.java
new file mode 100644
index 0000000..38e9de9
--- /dev/null
+++ b/manager/dm-server/src/main/java/org/apache/doris/manager/server/dao/ServerDao.java
@@ -0,0 +1,44 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.server.dao;
+
+import org.apache.doris.manager.server.entity.AgentEntity;
+import org.apache.doris.manager.server.entity.AgentRoleEntity;
+
+import java.util.List;
+
+/**
+ * server dao
+ **/
+public interface ServerDao {
+
+    List<AgentEntity> queryAgentNodes(List<String> hosts);
+
+    AgentEntity agentInfo(String host, Integer port);
+
+    int refreshAgentStatus(String host, Integer port);
+
+    int registerAgent(String host, Integer port);
+
+    int updateBatchAgentStatus(List<AgentEntity> agents);
+
+    int insertAgentRole(List<AgentRoleEntity> agentRoles);
+
+    String agentRole(String host);
+
+    List<AgentRoleEntity> agentRoles();
+}
diff --git a/manager/dm-server/src/main/java/org/apache/doris/manager/server/dao/impl/ServerDaoImpl.java b/manager/dm-server/src/main/java/org/apache/doris/manager/server/dao/impl/ServerDaoImpl.java
new file mode 100644
index 0000000..c916eb1
--- /dev/null
+++ b/manager/dm-server/src/main/java/org/apache/doris/manager/server/dao/impl/ServerDaoImpl.java
@@ -0,0 +1,160 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.server.dao.impl;
+
+import org.apache.doris.manager.server.constants.AgentStatus;
+import org.apache.doris.manager.server.dao.ServerDao;
+import org.apache.doris.manager.server.entity.AgentEntity;
+import org.apache.doris.manager.server.entity.AgentRoleEntity;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.jdbc.core.BatchPreparedStatementSetter;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.stereotype.Repository;
+
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * server dao
+ **/
+@Repository
+public class ServerDaoImpl implements ServerDao {
+
+    @Autowired
+    private JdbcTemplate jdbcTemplate;
+
+    @Override
+    public List<AgentEntity> queryAgentNodes(List<String> hosts) {
+        String sql = "select id,host,port,status,register_time,last_reported_time" +
+                " from t_agent ";
+        if (hosts != null && !hosts.isEmpty()) {
+            sql = sql + " where host in (%s)";
+            String inSql = String.join(",", Collections.nCopies(hosts.size(), "?"));
+            sql = String.format(sql, inSql);
+        }
+        List<AgentEntity> agentEntities = jdbcTemplate.query(
+                sql, (resultSet, i) -> {
+                    Integer id = resultSet.getInt("id");
+                    String ht = resultSet.getString("host");
+                    Integer pt = resultSet.getInt("port");
+                    String status = resultSet.getString("status");
+                    Date registerTime = resultSet.getTimestamp("register_time");
+                    Date lastReportedTime = resultSet.getTimestamp("last_reported_time");
+                    return new AgentEntity(id, ht, pt, status, registerTime, lastReportedTime);
+                }, hosts.toArray());
+        return agentEntities;
+    }
+
+    @Override
+    public AgentEntity agentInfo(String host, Integer port) {
+        String sql = "select id,host,port,status,register_time,last_reported_time from t_agent where host = ? and port = ?";
+        List<AgentEntity> agents = jdbcTemplate.query(sql, (resultSet, i) -> {
+            Integer id = resultSet.getInt("id");
+            String ht = resultSet.getString("host");
+            Integer pt = resultSet.getInt("port");
+            String status = resultSet.getString("status");
+            Date registerTime = resultSet.getTimestamp("register_time");
+            Date lastReportedTime = resultSet.getTimestamp("last_reported_time");
+            return new AgentEntity(id, ht, pt, status, registerTime, lastReportedTime);
+        }, host, port);
+        if (agents != null && !agents.isEmpty()) {
+            return agents.get(0);
+        }
+        return null;
+    }
+
+    @Override
+    public int refreshAgentStatus(String host, Integer port) {
+        String sql = "update t_agent set last_reported_time = now(),status = ? where host = ? and port = ?";
+        return jdbcTemplate.update(sql, AgentStatus.RUNNING.name(), host, port);
+    }
+
+    @Override
+    public int registerAgent(String host, Integer port) {
+        String sql = "insert into t_agent(host,port,status,register_time) values(?,?,?,now())";
+        return jdbcTemplate.update(sql, host, port, AgentStatus.RUNNING.name());
+    }
+
+    @Override
+    public int updateBatchAgentStatus(List<AgentEntity> agents) {
+        String sql = "update t_agent set status = ? where id = ?";
+        int[] i = jdbcTemplate.batchUpdate(sql, new BatchPreparedStatementSetter() {
+            public void setValues(PreparedStatement ps, int i) throws SQLException {
+                AgentEntity agent = agents.get(i);
+                ps.setString(1, agent.getStatus());
+                ps.setInt(2, agent.getId());
+            }
+
+            public int getBatchSize() {
+                return agents.size();
+            }
+        });
+        return i.length;
+    }
+
+    @Override
+    public int insertAgentRole(List<AgentRoleEntity> agentRoles) {
+        String sql = "insert into t_agent_role(host,role,install_dir) values(?,?,?)";
+        int[] i = jdbcTemplate.batchUpdate(sql, new BatchPreparedStatementSetter() {
+            public void setValues(PreparedStatement ps, int i) throws SQLException {
+                AgentRoleEntity node = agentRoles.get(i);
+                ps.setString(1, node.getHost());
+                ps.setString(2, node.getRole());
+                ps.setString(3, node.getInstallDir());
+            }
+
+            public int getBatchSize() {
+                return agentRoles.size();
+            }
+        });
+        return i.length;
+    }
+
+    @Override
+    public String agentRole(String host) {
+        String sql = "select host,role,install_dir from t_agent_role where host = ?";
+        List<AgentRoleEntity> agentRoles = jdbcTemplate.query(sql, (resultSet, i) -> {
+            String ht = resultSet.getString("host");
+            String role = resultSet.getString("role");
+            String installDir = resultSet.getString("install_dir");
+            return new AgentRoleEntity(ht, role, installDir);
+        }, host);
+        if (agentRoles != null && !agentRoles.isEmpty()) {
+            return agentRoles.get(0).getRole();
+        }
+        return null;
+    }
+
+    @Override
+    public List<AgentRoleEntity> agentRoles() {
+        String sql = "select host,role,install_dir from t_agent_role";
+        List<AgentRoleEntity> agentRoles = jdbcTemplate.query(sql, (resultSet, i) -> {
+            String ht = resultSet.getString("host");
+            String role = resultSet.getString("role");
+            String installDir = resultSet.getString("install_dir");
+            return new AgentRoleEntity(ht, role, installDir);
+        });
+        if (agentRoles == null) {
+            return new ArrayList<>();
+        }
+        return agentRoles;
+    }
+}
diff --git a/manager/dm-server/src/main/java/org/apache/doris/manager/server/entity/AgentEntity.java b/manager/dm-server/src/main/java/org/apache/doris/manager/server/entity/AgentEntity.java
new file mode 100644
index 0000000..1e7c86a
--- /dev/null
+++ b/manager/dm-server/src/main/java/org/apache/doris/manager/server/entity/AgentEntity.java
@@ -0,0 +1,103 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.server.entity;
+
+import java.util.Date;
+
+/**
+ * agent entity
+ **/
+public class AgentEntity {
+
+    private Integer id;
+
+    private String host;
+
+    private Integer port;
+
+    private String status;
+
+    private Date registerTime;
+
+    private Date lastReportedTime;
+
+    public AgentEntity() {
+    }
+
+    public AgentEntity(Integer id, String host, Integer port, String status, Date registerTime, Date lastReportedTime) {
+        this.id = id;
+        this.host = host;
+        this.port = port;
+        this.status = status;
+        this.registerTime = registerTime;
+        this.lastReportedTime = lastReportedTime;
+    }
+
+    public AgentEntity(String host, Integer port, String status) {
+        this.host = host;
+        this.port = port;
+        this.status = status;
+    }
+
+    public Integer getId() {
+        return id;
+    }
+
+    public void setId(Integer id) {
+        this.id = id;
+    }
+
+    public String getHost() {
+        return host;
+    }
+
+    public void setHost(String host) {
+        this.host = host;
+    }
+
+    public Integer getPort() {
+        return port;
+    }
+
+    public void setPort(Integer port) {
+        this.port = port;
+    }
+
+    public String getStatus() {
+        return status;
+    }
+
+    public void setStatus(String status) {
+        this.status = status;
+    }
+
+    public Date getRegisterTime() {
+        return registerTime;
+    }
+
+    public void setRegisterTime(Date registerTime) {
+        this.registerTime = registerTime;
+    }
+
+    public Date getLastReportedTime() {
+        return lastReportedTime;
+    }
+
+    public void setLastReportedTime(Date lastReportedTime) {
+        this.lastReportedTime = lastReportedTime;
+    }
+}
diff --git a/manager/dm-server/src/main/java/org/apache/doris/manager/server/entity/AgentRoleEntity.java b/manager/dm-server/src/main/java/org/apache/doris/manager/server/entity/AgentRoleEntity.java
new file mode 100644
index 0000000..fd0c82c
--- /dev/null
+++ b/manager/dm-server/src/main/java/org/apache/doris/manager/server/entity/AgentRoleEntity.java
@@ -0,0 +1,59 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.server.entity;
+
+public class AgentRoleEntity {
+
+    private String host;
+
+    private String role;
+
+    private String installDir;
+
+    public AgentRoleEntity() {
+    }
+
+    public AgentRoleEntity(String host, String role,String installDir) {
+        this.host = host;
+        this.role = role;
+        this.installDir = installDir;
+    }
+
+    public String getHost() {
+        return host;
+    }
+
+    public void setHost(String host) {
+        this.host = host;
+    }
+
+    public String getRole() {
+        return role;
+    }
+
+    public void setRole(String role) {
+        this.role = role;
+    }
+
+    public String getInstallDir() {
+        return installDir;
+    }
+
+    public void setInstallDir(String installDir) {
+        this.installDir = installDir;
+    }
+}
diff --git a/manager/dm-server/src/main/java/org/apache/doris/manager/server/exceptions/GlobalExceptionHandler.java b/manager/dm-server/src/main/java/org/apache/doris/manager/server/exceptions/GlobalExceptionHandler.java
new file mode 100644
index 0000000..3a2657a
--- /dev/null
+++ b/manager/dm-server/src/main/java/org/apache/doris/manager/server/exceptions/GlobalExceptionHandler.java
@@ -0,0 +1,42 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.server.exceptions;
+
+import org.apache.doris.manager.common.domain.RResult;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.RestControllerAdvice;
+
+@RestControllerAdvice
+public class GlobalExceptionHandler {
+
+    private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);
+
+    @ExceptionHandler(ServerException.class)
+    public RResult handleException(ServerException exception) {
+        log.error(exception.getMessage(), exception);
+        return RResult.error(exception.getStatus(), exception.getMessage());
+    }
+
+    @ExceptionHandler(Throwable.class)
+    public RResult javaExceptionHandler(Exception ex) {
+        log.error("server error ", ex);
+        return RResult.error(5000, "server error");
+    }
+
+}
diff --git a/manager/dm-server/src/main/java/org/apache/doris/manager/server/exceptions/ServerException.java b/manager/dm-server/src/main/java/org/apache/doris/manager/server/exceptions/ServerException.java
new file mode 100644
index 0000000..fa84864
--- /dev/null
+++ b/manager/dm-server/src/main/java/org/apache/doris/manager/server/exceptions/ServerException.java
@@ -0,0 +1,42 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.server.exceptions;
+
+public class ServerException extends RuntimeException {
+    private static final long serialVersionUID = -1L;
+    private static final Integer DEAFULT_EXCEPTION_STATUS = 500;
+    private int status;
+
+
+    public ServerException(String message) {
+        this(message, DEAFULT_EXCEPTION_STATUS);
+    }
+
+    public ServerException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    public ServerException(String message, int status) {
+        super(message);
+        this.status = status;
+    }
+
+    public int getStatus() {
+        return status;
+    }
+
+}
diff --git a/manager/dm-server/src/main/java/org/apache/doris/manager/server/model/req/AgentCommon.java b/manager/dm-server/src/main/java/org/apache/doris/manager/server/model/req/AgentCommon.java
new file mode 100644
index 0000000..b5942f2
--- /dev/null
+++ b/manager/dm-server/src/main/java/org/apache/doris/manager/server/model/req/AgentCommon.java
@@ -0,0 +1,40 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.server.model.req;
+
+public class AgentCommon {
+
+    private String host;
+
+    private Integer port;
+
+    public String getHost() {
+        return host;
+    }
+
+    public void setHost(String host) {
+        this.host = host;
+    }
+
+    public Integer getPort() {
+        return port;
+    }
+
+    public void setPort(Integer port) {
+        this.port = port;
+    }
+}
diff --git a/manager/dm-server/src/main/java/org/apache/doris/manager/server/model/req/DorisExec.java b/manager/dm-server/src/main/java/org/apache/doris/manager/server/model/req/DorisExec.java
new file mode 100644
index 0000000..15cbd85
--- /dev/null
+++ b/manager/dm-server/src/main/java/org/apache/doris/manager/server/model/req/DorisExec.java
@@ -0,0 +1,50 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.server.model.req;
+
+public class DorisExec {
+
+    private String host;
+    //FE、BE
+    private String role;
+
+    private boolean master;
+
+    public String getHost() {
+        return host;
+    }
+
+    public void setHost(String host) {
+        this.host = host;
+    }
+
+    public String getRole() {
+        return role;
+    }
+
+    public void setRole(String role) {
+        this.role = role;
+    }
+
+    public boolean isMaster() {
+        return master;
+    }
+
+    public void setMaster(boolean master) {
+        this.master = master;
+    }
+}
diff --git a/manager/dm-server/src/main/java/org/apache/doris/manager/server/model/req/DorisExecReq.java b/manager/dm-server/src/main/java/org/apache/doris/manager/server/model/req/DorisExecReq.java
new file mode 100644
index 0000000..1d08ba3
--- /dev/null
+++ b/manager/dm-server/src/main/java/org/apache/doris/manager/server/model/req/DorisExecReq.java
@@ -0,0 +1,43 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.server.model.req;
+
+import java.util.List;
+
+public class DorisExecReq {
+
+    //START STOP RESTART
+    private String command;
+
+    private List<DorisExec> dorisExecs;
+
+    public String getCommand() {
+        return command;
+    }
+
+    public void setCommand(String command) {
+        this.command = command;
+    }
+
+    public List<DorisExec> getDorisExecs() {
+        return dorisExecs;
+    }
+
+    public void setDorisExecs(List<DorisExec> dorisExecs) {
+        this.dorisExecs = dorisExecs;
+    }
+}
diff --git a/manager/dm-server/src/main/java/org/apache/doris/manager/server/model/req/DorisInstallReq.java b/manager/dm-server/src/main/java/org/apache/doris/manager/server/model/req/DorisInstallReq.java
new file mode 100644
index 0000000..fcf0167
--- /dev/null
+++ b/manager/dm-server/src/main/java/org/apache/doris/manager/server/model/req/DorisInstallReq.java
@@ -0,0 +1,32 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.server.model.req;
+
+import java.util.List;
+
+public class DorisInstallReq {
+
+    private List<InstallInfo> installInfos;
+
+    public List<InstallInfo> getInstallInfos() {
+        return installInfos;
+    }
+
+    public void setInstallInfos(List<InstallInfo> installInfos) {
+        this.installInfos = installInfos;
+    }
+}
diff --git a/manager/dm-server/src/main/java/org/apache/doris/manager/server/model/req/InstallInfo.java b/manager/dm-server/src/main/java/org/apache/doris/manager/server/model/req/InstallInfo.java
new file mode 100644
index 0000000..4ea611f
--- /dev/null
+++ b/manager/dm-server/src/main/java/org/apache/doris/manager/server/model/req/InstallInfo.java
@@ -0,0 +1,82 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.server.model.req;
+
+public class InstallInfo {
+    //host
+    private String host;
+
+    //role  be  fe
+    private String role;
+
+    //package url
+    private String packageUrl;
+
+    private boolean mkFeMetadir;
+
+    private boolean mkBeStorageDir;
+
+    private String installDir;
+
+    public String getHost() {
+        return host;
+    }
+
+    public void setHost(String host) {
+        this.host = host;
+    }
+
+    public String getRole() {
+        return role;
+    }
+
+    public void setRole(String role) {
+        this.role = role;
+    }
+
+    public String getPackageUrl() {
+        return packageUrl;
+    }
+
+    public void setPackageUrl(String packageUrl) {
+        this.packageUrl = packageUrl;
+    }
+
+    public boolean isMkFeMetadir() {
+        return mkFeMetadir;
+    }
+
+    public void setMkFeMetadir(boolean mkFeMetadir) {
+        this.mkFeMetadir = mkFeMetadir;
+    }
+
+    public String getInstallDir() {
+        return installDir;
+    }
+
+    public void setInstallDir(String installDir) {
+        this.installDir = installDir;
+    }
+
+    public boolean isMkBeStorageDir() {
+        return mkBeStorageDir;
+    }
+
+    public void setMkBeStorageDir(boolean mkBeStorageDir) {
+        this.mkBeStorageDir = mkBeStorageDir;
+    }
+}
diff --git a/manager/dm-server/src/main/java/org/apache/doris/manager/server/model/req/SshInfo.java b/manager/dm-server/src/main/java/org/apache/doris/manager/server/model/req/SshInfo.java
new file mode 100644
index 0000000..8c805c1
--- /dev/null
+++ b/manager/dm-server/src/main/java/org/apache/doris/manager/server/model/req/SshInfo.java
@@ -0,0 +1,62 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.server.model.req;
+
+import java.util.List;
+
+public class SshInfo {
+
+    private List<String> hosts;
+
+    private String user;
+
+    private Integer sshPort;
+
+    private String sshKey;
+
+    public List<String> getHosts() {
+        return hosts;
+    }
+
+    public void setHosts(List<String> hosts) {
+        this.hosts = hosts;
+    }
+
+    public String getUser() {
+        return user;
+    }
+
+    public void setUser(String user) {
+        this.user = user;
+    }
+
+    public Integer getSshPort() {
+        return sshPort;
+    }
+
+    public void setSshPort(Integer sshPort) {
+        this.sshPort = sshPort;
+    }
+
+    public String getSshKey() {
+        return sshKey;
+    }
+
+    public void setSshKey(String sshKey) {
+        this.sshKey = sshKey;
+    }
+}
diff --git a/manager/dm-server/src/main/java/org/apache/doris/manager/server/model/req/TaskInfoReq.java b/manager/dm-server/src/main/java/org/apache/doris/manager/server/model/req/TaskInfoReq.java
new file mode 100644
index 0000000..ca31b11
--- /dev/null
+++ b/manager/dm-server/src/main/java/org/apache/doris/manager/server/model/req/TaskInfoReq.java
@@ -0,0 +1,40 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.server.model.req;
+
+public class TaskInfoReq {
+
+    private String host;
+
+    private String taskId;
+
+    public String getHost() {
+        return host;
+    }
+
+    public void setHost(String host) {
+        this.host = host;
+    }
+
+    public String getTaskId() {
+        return taskId;
+    }
+
+    public void setTaskId(String taskId) {
+        this.taskId = taskId;
+    }
+}
diff --git a/manager/dm-server/src/main/java/org/apache/doris/manager/server/model/req/TaskLogReq.java b/manager/dm-server/src/main/java/org/apache/doris/manager/server/model/req/TaskLogReq.java
new file mode 100644
index 0000000..91b63e6
--- /dev/null
+++ b/manager/dm-server/src/main/java/org/apache/doris/manager/server/model/req/TaskLogReq.java
@@ -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.
+package org.apache.doris.manager.server.model.req;
+
+public class TaskLogReq extends TaskInfoReq{
+    private int offset;
+
+    public int getOffset() {
+        return offset;
+    }
+
+    public void setOffset(int offset) {
+        this.offset = offset;
+    }
+}
diff --git a/manager/dm-server/src/main/java/org/apache/doris/manager/server/service/ServerAgent.java b/manager/dm-server/src/main/java/org/apache/doris/manager/server/service/ServerAgent.java
new file mode 100644
index 0000000..3ba41c6
--- /dev/null
+++ b/manager/dm-server/src/main/java/org/apache/doris/manager/server/service/ServerAgent.java
@@ -0,0 +1,54 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.server.service;
+
+import org.apache.doris.manager.common.domain.RResult;
+import org.apache.doris.manager.server.model.req.DorisExecReq;
+import org.apache.doris.manager.server.model.req.DorisInstallReq;
+import org.apache.doris.manager.server.model.req.TaskInfoReq;
+import org.apache.doris.manager.server.model.req.TaskLogReq;
+
+import java.util.List;
+
+
+/**
+ * server agent
+ **/
+public interface ServerAgent {
+
+    /**
+     * install doris
+     */
+    List<Object> install(DorisInstallReq installReq);
+
+    /**
+     * request agent rest api
+     */
+    List<Object> execute(DorisExecReq dorisExec);
+
+    /**
+     * fetch task info
+     */
+    RResult taskInfo(TaskInfoReq taskInfo);
+
+    /**
+     * fetch log
+     */
+    RResult taskStdlog(TaskLogReq taskInfo);
+
+    RResult taskErrlog(TaskLogReq taskInfo);
+}
diff --git a/manager/dm-server/src/main/java/org/apache/doris/manager/server/service/ServerProcess.java b/manager/dm-server/src/main/java/org/apache/doris/manager/server/service/ServerProcess.java
new file mode 100644
index 0000000..e8fc9b1
--- /dev/null
+++ b/manager/dm-server/src/main/java/org/apache/doris/manager/server/service/ServerProcess.java
@@ -0,0 +1,53 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.server.service;
+
+import org.apache.doris.manager.common.domain.RResult;
+import org.apache.doris.manager.server.entity.AgentEntity;
+import org.apache.doris.manager.server.model.req.SshInfo;
+
+import java.util.List;
+
+/**
+ * server
+ */
+public interface ServerProcess {
+
+
+    void initAgent(SshInfo sshInfo);
+
+    /**
+     * install agent
+     */
+    void startAgent(SshInfo sshInfo);
+
+    /**
+     * agent list
+     */
+    List<AgentEntity> agentList();
+
+    /**
+     * update agent status batch
+     */
+    int updateBatchAgentStatus(List<AgentEntity> agents);
+
+    String agentRole(String host);
+
+    void heartbeat(String host, Integer port);
+
+    RResult register(String host, Integer port);
+}
diff --git a/manager/dm-server/src/main/java/org/apache/doris/manager/server/service/impl/ServerAgentImpl.java b/manager/dm-server/src/main/java/org/apache/doris/manager/server/service/impl/ServerAgentImpl.java
new file mode 100644
index 0000000..515547e
--- /dev/null
+++ b/manager/dm-server/src/main/java/org/apache/doris/manager/server/service/impl/ServerAgentImpl.java
@@ -0,0 +1,180 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.server.service.impl;
+
+import com.alibaba.fastjson.JSON;
+import org.apache.doris.manager.common.domain.BeInstallCommandRequestBody;
+import org.apache.doris.manager.common.domain.CommandRequest;
+import org.apache.doris.manager.common.domain.CommandType;
+import org.apache.doris.manager.common.domain.FeInstallCommandRequestBody;
+import org.apache.doris.manager.common.domain.FeStartCommandRequestBody;
+import org.apache.doris.manager.common.domain.RResult;
+import org.apache.doris.manager.common.domain.Role;
+import org.apache.doris.manager.server.agent.AgentCache;
+import org.apache.doris.manager.server.agent.AgentRest;
+import org.apache.doris.manager.server.constants.CmdTypeEnum;
+import org.apache.doris.manager.server.dao.ServerDao;
+import org.apache.doris.manager.server.entity.AgentEntity;
+import org.apache.doris.manager.server.entity.AgentRoleEntity;
+import org.apache.doris.manager.server.exceptions.ServerException;
+import org.apache.doris.manager.server.model.req.DorisExec;
+import org.apache.doris.manager.server.model.req.DorisExecReq;
+import org.apache.doris.manager.server.model.req.DorisInstallReq;
+import org.apache.doris.manager.server.model.req.InstallInfo;
+import org.apache.doris.manager.server.model.req.TaskInfoReq;
+import org.apache.doris.manager.server.model.req.TaskLogReq;
+import org.apache.doris.manager.server.service.ServerAgent;
+import org.apache.doris.manager.server.util.Preconditions;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+
+/**
+ * server agent
+ **/
+@Service
+public class ServerAgentImpl implements ServerAgent {
+
+    private static final Logger log = LoggerFactory.getLogger(ServerAgentImpl.class);
+
+    @Autowired
+    private ServerDao serverDao;
+
+    @Autowired
+    private AgentRest agentRest;
+
+    @Autowired
+    private AgentCache agentCache;
+
+    @Override
+    public List<Object> install(DorisInstallReq installReq) {
+        List<String> agentRoleList = serverDao.agentRoles().stream()
+                .map(m -> (m.getHost() + "-" + m.getRole()))
+                .collect(Collectors.toList());
+        List<Object> results = new ArrayList<>();
+        List<InstallInfo> installInfos = installReq.getInstallInfos();
+        List<AgentRoleEntity> agentRoles = new ArrayList<>();
+        for (InstallInfo install : installInfos) {
+            String key = install.getHost() + "-" + install.getRole();
+            if (agentRoleList.contains(key)) {
+                log.warn("agent {} already install doris {}", install.getHost(), install.getRole());
+                continue;
+            }
+            RResult result = installDoris(install);
+            agentRoles.add(new AgentRoleEntity(install.getHost(), install.getRole(), install.getInstallDir()));
+            results.add(result.getData());
+        }
+        //save agent role
+        serverDao.insertAgentRole(agentRoles);
+        return results;
+    }
+
+    private RResult installDoris(InstallInfo install) {
+        CommandRequest creq = new CommandRequest();
+        if (Role.FE.name().equals(install.getRole())) {
+            FeInstallCommandRequestBody feBody = new FeInstallCommandRequestBody();
+            feBody.setMkFeMetadir(install.isMkFeMetadir());
+            feBody.setPackageUrl(install.getPackageUrl());
+            feBody.setInstallDir(install.getInstallDir());
+            creq.setCommandType(CommandType.INSTALL_FE.name());
+            creq.setBody(JSON.toJSONString(feBody));
+        } else if (Role.BE.name().equals(install.getRole())) {
+            BeInstallCommandRequestBody beBody = new BeInstallCommandRequestBody();
+            beBody.setMkBeStorageDir(install.isMkBeStorageDir());
+            beBody.setInstallDir(install.getInstallDir());
+            beBody.setPackageUrl(install.getPackageUrl());
+            creq.setCommandType(CommandType.INSTALL_BE.name());
+        }
+        RResult result = agentRest.commandExec(install.getHost(), agentPort(install.getHost()), creq);
+        return result;
+    }
+
+    @Override
+    public List<Object> execute(DorisExecReq dorisExec) {
+        List<Object> results = new ArrayList<>();
+        CmdTypeEnum cmdType = CmdTypeEnum.findByName(dorisExec.getCommand());
+        List<DorisExec> dorisExecs = dorisExec.getDorisExecs();
+        for (DorisExec exec : dorisExecs) {
+            CommandType commandType = transAgentCmd(cmdType, Role.findByName(exec.getRole()));
+            CommandRequest creq = new CommandRequest();
+            if (CommandType.START_FE.equals(commandType) && exec.isMaster()) {
+                FeStartCommandRequestBody feBody = new FeStartCommandRequestBody();
+                feBody.setHelper(true);
+                // request fe master ip and port
+                feBody.setHelpHostPort("");
+            }
+            creq.setCommandType(commandType.name());
+            RResult result = agentRest.commandExec(exec.getHost(), agentPort(exec.getHost()), creq);
+            Object data = result.getData();
+            results.add(data);
+        }
+        return results;
+    }
+
+    /**
+     * trans server command to agent command
+     */
+    public CommandType transAgentCmd(CmdTypeEnum cmdType, Role role) {
+        Preconditions.checkNotNull(cmdType, "unrecognized cmd type " + cmdType);
+        Preconditions.checkNotNull(role, "unrecognized role " + role);
+        String cmd = cmdType.name() + "_" + role.name();
+        return CommandType.findByName(cmd);
+    }
+
+    @Override
+    public RResult taskInfo(TaskInfoReq taskInfo) {
+        Map<String, Object> param = new HashMap<>();
+        param.put("taskId", taskInfo.getTaskId());
+        RResult result = agentRest.taskInfo(taskInfo.getHost(), agentPort(taskInfo.getHost()), param);
+        return result;
+    }
+
+    @Override
+    public RResult taskStdlog(TaskLogReq taskInfo) {
+        Map<String, Object> param = new HashMap<>();
+        param.put("taskId", taskInfo.getTaskId());
+        param.put("offset", taskInfo.getOffset());
+        RResult result = agentRest.taskStdLog(taskInfo.getHost(), agentPort(taskInfo.getHost()), param);
+        return result;
+    }
+
+    @Override
+    public RResult taskErrlog(TaskLogReq taskInfo) {
+        Map<String, Object> param = new HashMap<>();
+        param.put("taskId", taskInfo.getTaskId());
+        param.put("offset", taskInfo.getOffset());
+        RResult result = agentRest.taskErrLog(taskInfo.getHost(), agentPort(taskInfo.getHost()), param);
+        return result;
+    }
+
+    private Integer agentPort(String host) {
+        AgentEntity agent = agentCache.agentInfo(host);
+        if (agent == null) {
+            throw new ServerException("query agent port fail");
+        }
+        return agent.getPort();
+    }
+
+}
diff --git a/manager/dm-server/src/main/java/org/apache/doris/manager/server/service/impl/ServerProcessImpl.java b/manager/dm-server/src/main/java/org/apache/doris/manager/server/service/impl/ServerProcessImpl.java
new file mode 100644
index 0000000..a2ea855
--- /dev/null
+++ b/manager/dm-server/src/main/java/org/apache/doris/manager/server/service/impl/ServerProcessImpl.java
@@ -0,0 +1,204 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.server.service.impl;
+
+import org.apache.doris.manager.common.domain.RResult;
+import org.apache.doris.manager.server.agent.AgentCache;
+import org.apache.doris.manager.server.constants.AgentStatus;
+import org.apache.doris.manager.server.dao.ServerDao;
+import org.apache.doris.manager.server.entity.AgentEntity;
+import org.apache.doris.manager.server.exceptions.ServerException;
+import org.apache.doris.manager.server.model.req.SshInfo;
+import org.apache.doris.manager.server.service.ServerProcess;
+import org.apache.doris.manager.server.shell.SCP;
+import org.apache.doris.manager.server.shell.SSH;
+import org.apache.doris.manager.server.util.Preconditions;
+import org.apache.doris.manager.server.util.PropertiesUtil;
+import org.apache.commons.io.FileUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.system.ApplicationHome;
+import org.springframework.stereotype.Service;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.nio.charset.Charset;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.nio.file.attribute.PosixFilePermission;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import static org.apache.doris.manager.server.constants.Constants.KEY_DORIS_AGENT_INSTALL_DIR;
+import static org.apache.doris.manager.server.constants.Constants.KEY_DORIS_AGENT_START_SCRIPT;
+import static org.apache.doris.manager.server.constants.Constants.KEY_SERVER_PORT;
+
+/**
+ * server
+ **/
+@Service
+public class ServerProcessImpl implements ServerProcess {
+
+    private static final Logger log = LoggerFactory.getLogger(ServerProcessImpl.class);
+    private static final String AGENT_INSTALL_DIR = PropertiesUtil.getPropValue(KEY_DORIS_AGENT_INSTALL_DIR);
+    private static final String AGENT_START_SCRIPT = PropertiesUtil.getPropValue(KEY_DORIS_AGENT_START_SCRIPT);
+
+    @Autowired
+    private ServerDao serverDao;
+
+    @Autowired
+    private AgentCache agentCache;
+
+    @Override
+    public void initAgent(SshInfo sshInfo) {
+        ApplicationHome applicationHome = new ApplicationHome(ServerProcessImpl.class);
+        String dorisManagerHome = applicationHome.getSource().getParentFile().getParentFile().toString();
+        log.info("doris manager home : {}", dorisManagerHome);
+        String agentHome = dorisManagerHome + File.separator + "agent";
+        Preconditions.checkNotNull(sshInfo.getHosts(), "hosts is empty");
+        File sshKeyFile = buildSshKeyFile();
+        writeSshKeyFile(sshInfo.getSshKey(), sshKeyFile);
+        scpFile(sshInfo, agentHome, AGENT_INSTALL_DIR);
+    }
+
+    @Override
+    public void startAgent(SshInfo sshInfo) {
+        String command = "sh " + AGENT_INSTALL_DIR + File.separator + AGENT_START_SCRIPT + " --server " + getServerAddr() + " --agent %s";
+        List<String> hosts = sshInfo.getHosts();
+        for (String host : hosts) {
+            File sshKeyFile = buildSshKeyFile();
+            String cmd = String.format(command, host);
+            SSH ssh = new SSH(sshInfo.getUser(), sshInfo.getSshPort(),
+                    sshKeyFile.getAbsolutePath(), host, cmd);
+            Integer run = ssh.run();
+            if (run != 0) {
+                throw new ServerException("agent start failed");
+            } else {
+                log.info("agent start success");
+            }
+        }
+    }
+
+    @Override
+    public List<AgentEntity> agentList() {
+        List<AgentEntity> agentEntities = serverDao.queryAgentNodes(new ArrayList<>());
+        return agentEntities;
+    }
+
+    @Override
+    public int updateBatchAgentStatus(List<AgentEntity> agents) {
+        return serverDao.updateBatchAgentStatus(agents);
+    }
+
+    @Override
+    public String agentRole(String host) {
+        return serverDao.agentRole(host);
+    }
+
+    @Override
+    public void heartbeat(String host, Integer port) {
+        serverDao.refreshAgentStatus(host, port);
+    }
+
+    @Override
+    public RResult register(String host, Integer port) {
+        AgentEntity agentEntity = serverDao.agentInfo(host, port);
+        if (agentEntity != null) {
+            return RResult.success("agent already register");
+        }
+        serverDao.registerAgent(host, port);
+        agentCache.putAgent(new AgentEntity(host, port, AgentStatus.RUNNING.name()));
+        return RResult.success("agent register success");
+    }
+
+    /**
+     * scp agent package
+     */
+    private void scpFile(SshInfo sshDesc, String localPath, String remotePath) {
+        List<String> hosts = sshDesc.getHosts();
+        String checkFileExistCmd = "if test -e " + remotePath + "; then echo ok; else mkdir -p " + remotePath + " ;fi";
+        File sshKeyFile = buildSshKeyFile();
+        for (String host : hosts) {
+            //check remote dir exist
+            SSH ssh = new SSH(sshDesc.getUser(), sshDesc.getSshPort(),
+                    sshKeyFile.getAbsolutePath(), host, checkFileExistCmd);
+            if (ssh.run() != 0) {
+                throw new ServerException("scp create remote dir failed");
+            }
+            SCP scp = new SCP(sshDesc.getUser(), sshDesc.getSshPort(),
+                    sshKeyFile.getAbsolutePath(), host, localPath, remotePath);
+            Integer run = scp.run();
+            if (run != 0) {
+                log.error("scp agent package failed:{} to {}", localPath, remotePath);
+                throw new ServerException("scp agent package failed");
+            }
+        }
+    }
+
+    /**
+     * sshkey trans to file
+     */
+    private void writeSshKeyFile(String sshKey, File sshKeyFile) {
+        try {
+            if (sshKeyFile.exists()) {
+                sshKeyFile.delete();
+            }
+            FileUtils.writeStringToFile(sshKeyFile, sshKey, Charset.defaultCharset());
+        } catch (IOException e) {
+            log.error("build sshKey file failed:", e);
+            throw new ServerException("build sshKey file failed");
+        }
+    }
+
+    /**
+     * build sshkeyfile per request
+     */
+    private File buildSshKeyFile() {
+        File sshKeyFile = new File("conf", "sshkey");
+
+        // chmod ssh key file permission to 600
+        try {
+            Set<PosixFilePermission> permission = new HashSet<>();
+            permission.add(PosixFilePermission.OWNER_READ);
+            permission.add(PosixFilePermission.OWNER_WRITE);
+            Files.setPosixFilePermissions(Paths.get(sshKeyFile.getAbsolutePath()), permission);
+        } catch (IOException e) {
+            log.error("set ssh key file permission fail");
+        }
+        return sshKeyFile;
+    }
+
+    /**
+     * get server address
+     */
+    private String getServerAddr() {
+        String host = null;
+        try {
+            host = InetAddress.getLocalHost().getHostAddress();
+        } catch (UnknownHostException e) {
+            throw new ServerException("get server ip fail");
+        }
+        String port = PropertiesUtil.getPropValue(KEY_SERVER_PORT);
+        return host + ":" + port;
+    }
+
+}
diff --git a/manager/dm-server/src/main/java/org/apache/doris/manager/server/shell/BaseCommand.java b/manager/dm-server/src/main/java/org/apache/doris/manager/server/shell/BaseCommand.java
new file mode 100644
index 0000000..53d15d9
--- /dev/null
+++ b/manager/dm-server/src/main/java/org/apache/doris/manager/server/shell/BaseCommand.java
@@ -0,0 +1,85 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.server.shell;
+
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.stream.Collectors;
+
+/**
+ * base command
+ **/
+public abstract class BaseCommand {
+
+    private static final Logger log = LoggerFactory.getLogger(BaseCommand.class);
+
+    protected String[] resultCommand;
+    protected Long timeout = 10000L;
+
+    protected abstract void buildCommand();
+
+    public Integer run() {
+        buildCommand();
+        log.info("run command: {}", StringUtils.join(resultCommand, " "));
+        ProcessBuilder pb = new ProcessBuilder(resultCommand);
+        int exitCode = 1;
+        try {
+            Process process = pb.start();
+            if (waitForProcessTermination(process, timeout)) {
+                exitCode = process.exitValue();
+            } else {
+                process.destroy();
+            }
+            if (exitCode != 0) {
+                BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getErrorStream()));
+                String errorStream = bufferedReader.lines().parallel().collect(Collectors.joining(System.lineSeparator()));
+                log.info("shell command error response:{}", errorStream);
+            }
+        } catch (IOException ie) {
+            log.error("command execute fail", ie);
+        }
+        return exitCode;
+    }
+
+    /**
+     * Waits until the process has terminated or waiting time elapses.
+     *
+     * @param timeout time to wait in miliseconds
+     * @return true if process has exited, false otherwise
+     */
+    protected boolean waitForProcessTermination(Process process, long timeout) {
+        long startTime = System.currentTimeMillis();
+        do {
+            try {
+                process.exitValue();
+                return true;
+            } catch (IllegalThreadStateException ignored) {
+            }
+            // Check if process has terminated once per second
+            try {
+                Thread.sleep(1000);
+            } catch (InterruptedException e) {
+            }
+        } while (System.currentTimeMillis() - startTime < timeout);
+        return false;
+    }
+}
diff --git a/manager/dm-server/src/main/java/org/apache/doris/manager/server/shell/SCP.java b/manager/dm-server/src/main/java/org/apache/doris/manager/server/shell/SCP.java
new file mode 100644
index 0000000..815746e
--- /dev/null
+++ b/manager/dm-server/src/main/java/org/apache/doris/manager/server/shell/SCP.java
@@ -0,0 +1,54 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.server.shell;
+
+/**
+ * scp
+ **/
+public class SCP extends BaseCommand {
+
+    private String user;
+    private Integer sshPort;
+    private String sshKeyFile;
+    private String host;
+    private String localPath;
+    private String remotePath;
+
+    public SCP(String user, Integer sshPort, String sshKeyFile, String host, String localPath, String remotePath) {
+        this.user = user;
+        this.sshPort = sshPort;
+        this.sshKeyFile = sshKeyFile;
+        this.host = host;
+        this.localPath = localPath;
+        this.remotePath = remotePath;
+    }
+
+    @Override
+    protected void buildCommand() {
+        String[] command = new String[]{"scp",
+                "-r",
+                "-o", "ConnectTimeOut=60",
+                "-o", "StrictHostKeyChecking=no",
+                "-o", "BatchMode=yes",
+                "-P", this.sshPort.toString(),
+                "-i", this.sshKeyFile,
+                this.localPath,
+                this.user + "@" + this.host + ":" + this.remotePath
+        };
+        this.resultCommand = command;
+    }
+}
diff --git a/manager/dm-server/src/main/java/org/apache/doris/manager/server/shell/SSH.java b/manager/dm-server/src/main/java/org/apache/doris/manager/server/shell/SSH.java
new file mode 100644
index 0000000..e132c91
--- /dev/null
+++ b/manager/dm-server/src/main/java/org/apache/doris/manager/server/shell/SSH.java
@@ -0,0 +1,54 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.server.shell;
+
+/**
+ * ssh
+ **/
+public class SSH extends BaseCommand {
+
+    private String user;
+
+    private Integer sshPort;
+
+    private String sshKeyFile;
+
+    private String host;
+
+    private String command;
+
+    public SSH(String user, Integer sshPort, String sshKeyFile, String host, String command) {
+        this.user = user;
+        this.sshPort = sshPort;
+        this.sshKeyFile = sshKeyFile;
+        this.host = host;
+        this.command = command;
+    }
+
+    protected void buildCommand() {
+        String[] command = new String[]{"ssh",
+                "-o", "ConnectTimeOut=60",
+                "-o", "StrictHostKeyChecking=no",
+                "-o", "BatchMode=yes",
+                "-tt",
+                "-i", this.sshKeyFile,
+                "-p", this.sshPort.toString(),
+                this.user + "@" + this.host, this.command
+        };
+        this.resultCommand = command;
+    }
+}
diff --git a/manager/dm-server/src/main/java/org/apache/doris/manager/server/util/Preconditions.java b/manager/dm-server/src/main/java/org/apache/doris/manager/server/util/Preconditions.java
new file mode 100644
index 0000000..c45ae9f
--- /dev/null
+++ b/manager/dm-server/src/main/java/org/apache/doris/manager/server/util/Preconditions.java
@@ -0,0 +1,46 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.server.util;
+
+public class Preconditions {
+
+    public static <T> T checkNotNull(T reference) {
+        if (reference == null) {
+            throw new NullPointerException();
+        }
+        return reference;
+    }
+
+    public static <T> T checkNotNull(T reference, String errorMessage) {
+        if (reference == null) {
+            throw new NullPointerException(String.valueOf(errorMessage));
+        }
+        return reference;
+    }
+
+    public static void checkArgument(boolean condition) {
+        if (!condition) {
+            throw new IllegalArgumentException();
+        }
+    }
+
+    public static void checkArgument(boolean condition, Object errorMessage) {
+        if (!condition) {
+            throw new IllegalArgumentException(String.valueOf(errorMessage));
+        }
+    }
+}
diff --git a/manager/dm-server/src/main/java/org/apache/doris/manager/server/util/PropertiesUtil.java b/manager/dm-server/src/main/java/org/apache/doris/manager/server/util/PropertiesUtil.java
new file mode 100644
index 0000000..2dd1741
--- /dev/null
+++ b/manager/dm-server/src/main/java/org/apache/doris/manager/server/util/PropertiesUtil.java
@@ -0,0 +1,51 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.server.util;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.Properties;
+
+public class PropertiesUtil {
+
+    private static final Logger log = LoggerFactory.getLogger(PropertiesUtil.class);
+    private static final String DEFAULT_PROPERTIES = "/application.properties";
+
+    /**
+     * get properties key
+     *
+     * @param propKey
+     * @return
+     */
+    public static String getPropValue(String propKey) {
+        try {
+            Properties props = new Properties();
+            InputStream inputStream = PropertiesUtil.class.getResourceAsStream(DEFAULT_PROPERTIES);
+            BufferedReader bf = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));
+            props.load(bf);
+            return props.getProperty(propKey);
+        } catch (IOException e) {
+            log.error("get propKey error:", e);
+        }
+        return null;
+    }
+}
diff --git a/manager/dm-server/src/main/resources/application.properties b/manager/dm-server/src/main/resources/application.properties
new file mode 100644
index 0000000..a34d7cc
--- /dev/null
+++ b/manager/dm-server/src/main/resources/application.properties
@@ -0,0 +1,15 @@
+server.port=9601
+
+spring.datasource.url = jdbc:mysql://localhost:3306/doris_manager?allowMultiQueries=true&useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull&useSSL=false&serverTimezone=GMT%2B8
+spring.datasource.username = root
+spring.datasource.password = password
+
+doris.manager.agent.install.dir = /usr/local/doris-manager
+doris.manager.agent.start-script = agent/bin/agent_start.sh
+
+
+
+
+
+
+
diff --git a/manager/dm-server/src/main/resources/bin/startup.sh b/manager/dm-server/src/main/resources/bin/startup.sh
new file mode 100755
index 0000000..0967ee2
--- /dev/null
+++ b/manager/dm-server/src/main/resources/bin/startup.sh
@@ -0,0 +1,60 @@
+#!/usr/bin/env 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.
+
+curdir=`dirname "$0"`
+curdir=`cd "$curdir"; pwd`
+
+export DOIRS_MANAGER_HOME=`cd "$curdir/.."; pwd`
+
+#
+# JAVA_OPTS
+# SERVER_PARAMS
+# LOG_DIR
+# PID_DIR
+export JAVA_OPTS="-Xmx1024m"
+export LOG_DIR="$DOIRS_MANAGER_HOME/log"
+export PID_DIR=`cd "$curdir"; pwd`
+
+# java
+if [ "$JAVA_HOME" = "" ]; then
+  echo "Error: JAVA_HOME is not set."
+  exit 1
+fi
+JAVA=$JAVA_HOME/bin/java
+
+# need check and create if the log directory existed before outing message to the log file.
+if [ ! -d $LOG_DIR ]; then
+    mkdir -p $LOG_DIR
+fi
+
+echo $JAVA_OPTS >> $LOG_DIR/doris-manager.out
+
+pidfile=$PID_DIR/doris-manager.pid
+
+if [ -f $pidfile ]; then
+  if kill -0 `cat $pidfile` > /dev/null 2>&1; then
+    echo doris-manager running as process `cat $pidfile`.  Stop it first.
+    exit 1
+  fi
+fi
+
+echo `date` >> $LOG_DIR/doris-manager.out
+
+nohup $JAVA $JAVA_OPTS -jar ${DOIRS_MANAGER_HOME}/lib/dm-server.jar $SERVER_PARAMS >> $LOG_DIR/doris-manager.out 2>&1 </dev/null &
+
+echo $! > $pidfile
diff --git a/manager/dm-server/src/main/resources/bin/stop.sh b/manager/dm-server/src/main/resources/bin/stop.sh
new file mode 100755
index 0000000..6f15bba
--- /dev/null
+++ b/manager/dm-server/src/main/resources/bin/stop.sh
@@ -0,0 +1,39 @@
+#!/usr/bin/env 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.
+
+curdir=`dirname "$0"`
+curdir=`cd "$curdir"; pwd`
+
+export DORIS_MANAGER_HOME=`cd "$curdir/.."; pwd`
+export PID_DIR=`cd "$curdir"; pwd`
+
+pidfile=$PID_DIR/doris-manager.pid
+
+if [ -f $pidfile ]; then
+   pid=`cat $pidfile`
+   pidcomm=`ps -p $pid -o comm=`
+
+   if [ "java" != "$pidcomm" ]; then
+       echo "ERROR: pid process may not be doris manager. "
+   fi
+
+   if kill -9 $pid > /dev/null 2>&1; then
+        echo "stop $pidcomm, and remove pid file. "
+        rm $pidfile
+   fi
+fi
diff --git a/manager/dm-server/src/main/resources/dm-server.sql b/manager/dm-server/src/main/resources/dm-server.sql
new file mode 100644
index 0000000..f9af9e7
--- /dev/null
+++ b/manager/dm-server/src/main/resources/dm-server.sql
@@ -0,0 +1,18 @@
+CREATE TABLE `t_agent` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `host` varchar(128) DEFAULT NULL COMMENT 'agent host',
+  `port` int(8) DEFAULT NULL COMMENT 'agent port',
+  `status` varchar(256) DEFAULT NULL COMMENT 'agent status',
+  `register_time` timestamp  NULL  COMMENT 'register_time',
+  `last_reported_time` timestamp NULL  COMMENT 'last report time'
+  PRIMARY KEY (`id`)
+  UNIQUE KEY `agent_index` (`host`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
+
+
+CREATE TABLE `t_agent_role` (
+  `host` varchar(128) DEFAULT NULL COMMENT 'host',
+  `role` varchar(8) DEFAULT NULL COMMENT 'BE/FE',
+  `install_dir` varchar(256) DEFAULT NULL COMMENT 'doris install dir',
+  UNIQUE KEY `host_index` (`host`,`role`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
\ No newline at end of file
diff --git a/manager/dm-server/src/main/resources/logback-spring.xml b/manager/dm-server/src/main/resources/logback-spring.xml
new file mode 100644
index 0000000..e437501
--- /dev/null
+++ b/manager/dm-server/src/main/resources/logback-spring.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration debug="false">
+    <springProperty scope="context" name="springAppName" source="spring.application.name" defaultValue="server" />
+    <property name="LOG_HOME" value="./log"/>
+    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
+        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
+            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
+        </encoder>
+    </appender>
+    <appender name="FILE"  class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
+            <FileNamePattern>${LOG_HOME}/${springAppName}.%d{yyyy-MM-dd}.%i.log</FileNamePattern>
+            <MaxHistory>30</MaxHistory>
+            <maxFileSize>50MB</maxFileSize>
+            <totalSizeCap>10GB</totalSizeCap>
+        </rollingPolicy>
+        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
+            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
+        </encoder>
+    </appender>
+
+    <root level="INFO">
+        <appender-ref ref="STDOUT" />
+        <appender-ref ref="FILE" />
+    </root>
+</configuration>
\ No newline at end of file
diff --git "a/manager/doc/Doris Manager Server \346\216\245\345\217\243\346\226\207\346\241\243.md" "b/manager/doc/Doris Manager Server \346\216\245\345\217\243\346\226\207\346\241\243.md"
new file mode 100644
index 0000000..aeccad3
--- /dev/null
+++ "b/manager/doc/Doris Manager Server \346\216\245\345\217\243\346\226\207\346\241\243.md"	
@@ -0,0 +1,486 @@
+[TOC]
+
+---
+
+### Doris Manager Server 接口文档
+
+#### 1.安装Agent
+
+**接口功能**
+
+> 给指定机器安装Agent,并启动。
+
+**URL**
+
+> /server/installAgent
+
+**支持格式**
+
+> JSON
+
+**HTTP请求方式**
+
+> POST
+
+**请求参数**
+
+> |参数|必选|类型|说明|
+> |:-----  |:-------|:-----|-----                               |
+> |hosts    |ture    |List|机器列表                          |
+> |user    |true    |String   |ssh 用户|
+> |port |true |int |ssh 端口|
+> |sshKey |true |String |ssh 私钥|
+
+**返回字段**
+
+> |返回字段|字段类型|说明                              |
+|:-----   |:------|:-----------------------------   |
+|msg   |String    |调用信息   |
+|code  |String | 结果状态。0:正常  |
+
+**接口示例**
+
+> 地址:http://localhost:9601/server/installAgent
+
+> 请求参数:
+``` json
+{
+    "hosts":["10.10.10.11"],
+    "user":"root",
+    "sshPort":22,
+    "sshKey": "-----BEGIN RSA PRIVATE KEY-----....."
+}
+```
+> 返回参数:
+``` json
+{
+    "msg": "success",
+    "code": 0
+}
+```
+
+#### 2.查看Agent列表
+
+**接口功能**
+
+> 查看已安装的Agent列表
+
+**URL**
+
+> /server/agentList
+
+**支持格式**
+
+> JSON
+
+**HTTP请求方式**
+
+> POST
+
+**请求参数**
+
+无
+
+**返回字段**
+
+> |返回字段|字段类型|说明                              |
+|:-----   |:------|:-----------------------------   |
+|msg   |String    |调用信息   |
+|code  |String | 结果状态。0:正常  |
+|data.id  |int | agentId |
+|data.host  |String |agent host  |
+|data.port  |String | agent port |
+|data.status  |String | agent状态 :RUNNING STOP|
+|data.registerTime  |Date | agent注册时间  |
+|data.lastReportedTime  |Date | agent最后上报时间  |
+
+**接口示例**
+
+> 地址:http://localhost:9601/server/agentList
+
+> 请求参数:无
+
+> 返回参数:
+``` json
+{
+    "msg": "success",
+    "code": 0,
+    "data": [
+        {
+            "id": 1,
+            "host": "10.10.10.11",
+            "port": 9602,
+            "status": "RUNNING",
+            "registerTime": "2021-08-10T11:07:34.000+00:00",
+            "lastReportedTime": "2021-08-12T03:02:46.000+00:00"
+        }
+    ]
+}
+```
+
+#### 3.安装Doris
+
+**接口功能**
+
+> 给指定机器安装Doris
+
+**URL**
+
+> /agent/installDoris
+
+**支持格式**
+
+> JSON
+
+**HTTP请求方式**
+
+> POST
+
+**请求参数**
+
+> |参数|必选|类型|说明|
+> |:-----  |:-------|:-----|-----                               |
+> |host    |ture    | String  |指定安装doris的机器                          |
+> |role    |true    |String   |doris角色:FE、BE|
+> |packageUrl |true |String |doris编译包下载地址,只支持http方式。|
+> |mkFeMetadir |false |boolean |安装FE时是否新建 元数据目录|
+> |mkBeStorageDir |false |boolean |安装BE时是否新建 数据存储目录|
+> |installDir |true |String |安装路径|
+
+**返回字段**
+
+> |返回字段|字段类型|说明                              |
+> |:-----   |:------|:-----------------------------   |
+> |msg   |String    |调用信息   |
+> |code  |String | 结果状态。0:正常  |
+> |data.taskResult.taskId |String | 任务ID |
+> |data.taskResult.submitTime |Date | 任务提交时间 |
+> |data.taskResult.startTime |Date | 任务开始时间 |
+> |data.taskResult.endTime |Date | 任务终止时间      |
+> |data.taskResult.taskState |String | 任务状态 |
+> |data.taskResult.retCode |int | 任务返回状态。0:正常 |
+> |data.stdlogs |List | 任务输出日志 |
+> |data.errlogs |List | 任务错误日志 |
+
+**接口示例**
+
+> 地址:http://localhost:9601/agent/installDoris
+
+> 请求参数:
+``` json
+{
+    "installInfos":[{
+        "host":"10.10.10.11",
+        "role":"FE",
+        "packageUrl":"http://10.10.10.11/fileupload/doris-fe.tar.gz",
+        "mkFeMetadir":true,
+        "installDir":"/usr/local/doris-fe"
+    }]
+}
+```
+> 返回参数:
+``` json
+{
+    "msg": "success",
+    "code": 0,
+    "data": [
+        {
+            "taskResult": {
+                "taskId": "a3b966cc10794f4c8b9b2c0dc1fa9b26",
+                "submitTime": "2021-08-12T02:37:11.757+00:00",
+                "startTime": "2021-08-12T02:37:11.759+00:00",
+                "endTime": null,
+                "taskState": "RUNNING",
+                "retCode": null
+            },
+            "stdlogs": [],
+            "errlogs": []
+        }
+    ]
+}
+```
+
+#### 4.启停Doris
+
+**接口功能**
+
+> 对指定机器的doris进行启动、停止
+
+**URL**
+
+> /agent/execute
+
+**支持格式**
+
+> JSON
+
+**HTTP请求方式**
+
+> POST
+
+**请求参数**
+
+> |参数|必选|类型|说明|
+> |:-----  |:-------|:-----|-----                               |
+> |command    |ture    | String  | 执行命令: START STOP                          |
+> |dorisExecs.host    |true    |String   |指定的机器列表|
+> |dorisExecs.role |true |String |doris角色:FE、BE|
+
+**返回字段**
+
+> |返回字段|字段类型|说明                              |
+> |:-----   |:------|:-----------------------------   |
+> |msg   |String    |调用信息   |
+> |code  |String | 结果状态。0:正常  |
+> |data.taskResult.taskId |String | 任务ID |
+> |data.taskResult.submitTime |Date | 任务提交时间 |
+> |data.taskResult.startTime |Date | 任务开始时间 |
+> |data.taskResult.endTime |Date | 任务终止时间      |
+> |data.taskResult.taskState |String | 任务状态 |
+> |data.taskResult.retCode |int | 任务返回状态。0:正常 |
+> |data.stdlogs |List | 任务输出日志 |
+> |data.errlogs |List | 任务错误日志 |
+
+**接口示例**
+
+> 地址:http://localhost:9601/agent/execute
+
+> 请求参数:
+``` json
+{
+    "command":"START",
+    "dorisExecs":[{
+        "host":"10.10.10.11",
+        "role":"FE"
+    }]
+}
+```
+> 返回参数:
+``` json
+{
+    "msg": "success",
+    "code": 0,
+    "data": [
+        {
+            "taskResult": {
+                "taskId": "a3b966cc10794f4c8b9b2c0dc1fa9b26",
+                "submitTime": "2021-08-12T02:37:11.757+00:00",
+                "startTime": "2021-08-12T02:37:11.759+00:00",
+                "endTime": null,
+                "taskState": "RUNNING",
+                "retCode": null
+            },
+            "stdlogs": [],
+            "errlogs": []
+        }
+    ]
+}
+```
+
+#### 5.查看任务执行状态
+
+**接口功能**
+
+> 查看任务执行状态
+
+**URL**
+
+> /agent/task
+
+**支持格式**
+
+> JSON
+
+**HTTP请求方式**
+
+> POST
+
+**请求参数**
+
+> |参数|必选|类型|说明|
+> |:-----  |:-------|:-----|-----                               |
+> |host    |ture    | String  |agent 机器host                          |
+> |taskId    |true    |String   |任务id|
+
+**返回字段**
+
+> |返回字段|字段类型|说明                              |
+> |:-----   |:------|:-----------------------------   |
+> |msg   |String    |调用信息   |
+> |code  |String | 结果状态。0:正常  |
+> |data.taskResult.taskId |String | 任务ID |
+> |data.taskResult.submitTime |Date | 任务提交时间 |
+> |data.taskResult.startTime |Date | 任务开始时间 |
+> |data.taskResult.endTime |Date | 任务终止时间      |
+> |data.taskResult.taskState |String | 任务状态 |
+> |data.taskResult.retCode |int | 任务返回状态。0:正常 |
+> |data.stdlogs |List | 任务输出日志 |
+> |data.errlogs |List | 任务错误日志 |
+
+**接口示例**
+
+> 地址:http://localhost:9601/agent/task
+
+> 请求参数:
+``` json
+{
+    "host":"10.10.10.11",
+    "taskId":"a3b966cc10794f4c8b9b2c0dc1fa9b26"
+}
+```
+> 返回参数:
+``` json
+{
+    "msg": "success",
+    "code": 0,
+    "data": {
+        "taskResult": {
+            "taskId": "a3b966cc10794f4c8b9b2c0dc1fa9b26",
+            "submitTime": "2021-08-12T02:37:11.757+00:00",
+            "startTime": "2021-08-12T02:37:11.759+00:00",
+            "endTime": "2021-08-12T02:37:14.759+00:00",
+            "taskState": "FINISHED",
+            "retCode": 0
+        },
+        "stdlogs": [
+            "bin/",
+            "bin/start_fe.sh",
+            "bin/stop_fe.sh",
+            "conf/",
+            "conf/fe.conf",
+            "lib/",
+            "lib/RoaringBitmap-0.8.13.jar",
+            "lib/activation-1.1.1.jar",
+            "lib/aircompressor-0.10.jar",
+            "lib/amqp-client-5.7.3.jar",
+            "lib/annotations-2.15.45.jar"
+            .....
+        ],
+        "errlogs": []
+    }
+}
+```
+
+#### 6.查看任务输出日志
+
+**接口功能**
+
+> 查看任务输出日志
+
+**URL**
+
+> /agent/stdlog
+
+**支持格式**
+
+> JSON
+
+**HTTP请求方式**
+
+> POST
+
+**请求参数**
+
+> |参数|必选|类型|说明|
+> |:-----  |:-------|:-----|-----                               |
+> |host    |ture    | String  |agent 机器host                          |
+> |taskId    |true    |String   |任务id|
+> |offset    |false    |int   |日志偏移量|
+
+**返回字段**
+
+> |返回字段|字段类型|说明                              |
+> |:-----   |:------|:-----------------------------   |
+> |msg   |String    |调用信息   |
+> |code  |String | 结果状态。0:正常  |
+> |data.key |String | 下一页起始偏移量 |
+> |data.value |List | 日志 |
+
+**接口示例**
+
+> 地址:http://localhost:9601/agent/stdlog
+
+> 请求参数:
+``` json
+{
+    "host":"10.10.10.11",
+    "taskId":"a3b966cc10794f4c8b9b2c0dc1fa9b26",
+    "offset":10,
+}
+```
+> 返回参数:
+``` json
+{
+    "msg": "success",
+    "code": 0,
+    "data": {
+        "key": 366,
+        "value": [
+            "lib/annotations-2.15.45.jar",
+            "lib/antlr4-runtime-4.7.jar",
+            .....
+        ]
+    }
+}
+```
+
+#### 7.查看任务错误日志
+
+**接口功能**
+
+> 查看任务错误日志
+
+**URL**
+
+> /agent/errlog
+
+**支持格式**
+
+> JSON
+
+**HTTP请求方式**
+
+> POST
+
+**请求参数**
+
+> |参数|必选|类型|说明|
+> |:-----  |:-------|:-----|-----                               |
+> |host    |ture    | String  |agent 机器host                          |
+> |taskId    |true    |String   |任务id|
+> |offset    |false    |int   |日志偏移量|
+
+**返回字段**
+
+> |返回字段|字段类型|说明                              |
+> |:-----   |:------|:-----------------------------   |
+> |msg   |String    |调用信息   |
+> |code  |String | 结果状态。0:正常  |
+> |data.key |String | 下一页起始偏移量 |
+> |data.value |List | 日志 |
+
+**接口示例**
+
+> 地址:http://localhost:9601/agent/errlog
+
+> 请求参数:
+``` json
+{
+    "host":"10.10.10.11",
+    "taskId":"a3b966cc10794f4c8b9b2c0dc1fa9b26",
+    "offset":10,
+}
+```
+> 返回参数:
+``` json
+{
+    "msg": "success",
+    "code": 0,
+    "data": {
+        "key": 366,
+        "value": [
+            .....
+        ]
+    }
+}
+```
\ No newline at end of file
diff --git a/manager/pom.xml b/manager/pom.xml
new file mode 100644
index 0000000..a5eb07e
--- /dev/null
+++ b/manager/pom.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.springframework.boot</groupId>
+        <artifactId>spring-boot-starter-parent</artifactId>
+        <version>2.5.2</version>
+        <relativePath/> <!-- lookup parent from repository -->
+    </parent>
+
+    <groupId>org.apache.doris</groupId>
+    <artifactId>doris-manager</artifactId>
+    <version>1.0.0</version>
+    <packaging>pom</packaging>
+
+    <dependencyManagement>
+        <dependencies>
+            <dependency>
+                <groupId>org.apache.doris</groupId>
+                <artifactId>dm-common</artifactId>
+                <version>1.0.0</version>
+            </dependency>
+
+            <dependency>
+                <groupId>org.apache.doris</groupId>
+                <artifactId>dm-agent</artifactId>
+                <version>1.0.0</version>
+            </dependency>
+
+            <dependency>
+                <groupId>org.apache.doris</groupId>
+                <artifactId>dm-server</artifactId>
+                <version>1.0.0</version>
+            </dependency>
+        </dependencies>
+    </dependencyManagement>
+
+    <modules>
+        <module>dm-common</module>
+        <module>dm-agent</module>
+        <module>dm-server</module>
+        <module>assembly</module>
+    </modules>
+
+</project>
\ No newline at end of file

---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@doris.apache.org
For additional commands, e-mail: commits-help@doris.apache.org