diff --git a/apollo-adminservice/src/main/resources/application-consul-discovery.properties b/apollo-adminservice/src/main/resources/application-consul-discovery.properties
new file mode 100644
index 00000000000..ab87bf1e8e8
--- /dev/null
+++ b/apollo-adminservice/src/main/resources/application-consul-discovery.properties
@@ -0,0 +1,7 @@
+eureka.client.enabled=false
+#consul enabled
+spring.cloud.consul.enabled=true
+spring.cloud.consul.discovery.enabled=true
+spring.cloud.consul.service-registry.enabled=true
+spring.cloud.consul.discovery.heartbeat.enabled=true
+spring.cloud.consul.discovery.instance-id=apollo-adminservice
diff --git a/apollo-adminservice/src/main/resources/application.yml b/apollo-adminservice/src/main/resources/application.yml
index ff5df0d7d6d..f497e2e8789 100644
--- a/apollo-adminservice/src/main/resources/application.yml
+++ b/apollo-adminservice/src/main/resources/application.yml
@@ -3,6 +3,9 @@ spring:
name: apollo-adminservice
profiles:
active: ${apollo_profile}
+ cloud:
+ consul:
+ enabled: false
ctrip:
appid: 100003172
diff --git a/apollo-adminservice/src/test/resources/application.properties b/apollo-adminservice/src/test/resources/application.properties
index 793e2b70b5f..b4cd6abd201 100644
--- a/apollo-adminservice/src/test/resources/application.properties
+++ b/apollo-adminservice/src/test/resources/application.properties
@@ -4,3 +4,4 @@ spring.jpa.properties.hibernate.show_sql=false
spring.h2.console.enabled = true
spring.h2.console.settings.web-allow-others=true
spring.main.allow-bean-definition-overriding=true
+spring.cloud.consul.enabled=false
\ No newline at end of file
diff --git a/apollo-biz/pom.xml b/apollo-biz/pom.xml
index 986e5ff1433..d98760b2e87 100644
--- a/apollo-biz/pom.xml
+++ b/apollo-biz/pom.xml
@@ -24,6 +24,10 @@
spring-cloud-starter-netflix-eureka-client
+
+ org.springframework.cloud
+ spring-cloud-starter-consul-discovery
+
com.h2database
h2
diff --git a/apollo-biz/src/test/resources/application.properties b/apollo-biz/src/test/resources/application.properties
index 51fb02a6bee..c5e5d2de78e 100644
--- a/apollo-biz/src/test/resources/application.properties
+++ b/apollo-biz/src/test/resources/application.properties
@@ -3,3 +3,4 @@ spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.Ph
spring.jpa.properties.hibernate.show_sql=false
spring.h2.console.enabled = true
spring.h2.console.settings.web-allow-others=true
+spring.cloud.consul.enabled=false
\ No newline at end of file
diff --git a/apollo-configservice/src/main/java/com/ctrip/framework/apollo/metaservice/controller/HomePageController.java b/apollo-configservice/src/main/java/com/ctrip/framework/apollo/metaservice/controller/HomePageController.java
index e5dd63c7be4..e5238eceef6 100644
--- a/apollo-configservice/src/main/java/com/ctrip/framework/apollo/metaservice/controller/HomePageController.java
+++ b/apollo-configservice/src/main/java/com/ctrip/framework/apollo/metaservice/controller/HomePageController.java
@@ -13,7 +13,7 @@
/**
* For non-eureka discovery services such as kubernetes and nacos, there is no eureka home page, so we need to add a default one
*/
-@Profile({"kubernetes", "nacos-discovery"})
+@Profile({"kubernetes", "nacos-discovery", "consul-discovery"})
@RestController
public class HomePageController {
private final DiscoveryService discoveryService;
diff --git a/apollo-configservice/src/main/java/com/ctrip/framework/apollo/metaservice/service/ConsulDiscoveryService.java b/apollo-configservice/src/main/java/com/ctrip/framework/apollo/metaservice/service/ConsulDiscoveryService.java
new file mode 100644
index 00000000000..df0edb9aca5
--- /dev/null
+++ b/apollo-configservice/src/main/java/com/ctrip/framework/apollo/metaservice/service/ConsulDiscoveryService.java
@@ -0,0 +1,49 @@
+package com.ctrip.framework.apollo.metaservice.service;
+
+import com.ctrip.framework.apollo.core.dto.ServiceDTO;
+import com.google.common.collect.Lists;
+import org.springframework.cloud.client.ServiceInstance;
+import org.springframework.cloud.consul.discovery.ConsulDiscoveryClient;
+import org.springframework.context.annotation.Profile;
+import org.springframework.stereotype.Service;
+import org.springframework.util.CollectionUtils;
+
+import java.util.List;
+
+/**
+ * @author : kl
+ * Service discovery consul implementation
+ **/
+@Service
+@Profile({"consul-discovery"})
+public class ConsulDiscoveryService implements DiscoveryService {
+
+ private final ConsulDiscoveryClient discoveryClient;
+
+ public ConsulDiscoveryService(ConsulDiscoveryClient discoveryClient) {
+ this.discoveryClient = discoveryClient;
+ }
+
+
+ @Override
+ public List getServiceInstances(String serviceId) {
+ List instances = discoveryClient.getInstances(serviceId);
+ List serviceDTOList = Lists.newLinkedList();
+ if (!CollectionUtils.isEmpty(instances)) {
+ instances.forEach(instance -> {
+ ServiceDTO serviceDTO = this.toServiceDTO(instance, serviceId);
+ serviceDTOList.add(serviceDTO);
+ });
+ }
+ return serviceDTOList;
+ }
+
+ private ServiceDTO toServiceDTO(ServiceInstance instance, String appName) {
+ ServiceDTO service = new ServiceDTO();
+ service.setAppName(appName);
+ service.setInstanceId(instance.getInstanceId());
+ String homePageUrl = "http://" + instance.getHost() + ":" + instance.getPort() + "/";
+ service.setHomepageUrl(homePageUrl);
+ return service;
+ }
+}
diff --git a/apollo-configservice/src/main/java/com/ctrip/framework/apollo/metaservice/service/DefaultDiscoveryService.java b/apollo-configservice/src/main/java/com/ctrip/framework/apollo/metaservice/service/DefaultDiscoveryService.java
index e142363b3a0..adb0d8682b6 100644
--- a/apollo-configservice/src/main/java/com/ctrip/framework/apollo/metaservice/service/DefaultDiscoveryService.java
+++ b/apollo-configservice/src/main/java/com/ctrip/framework/apollo/metaservice/service/DefaultDiscoveryService.java
@@ -17,7 +17,7 @@
* Default discovery service for Eureka
*/
@Service
-@ConditionalOnMissingProfile({"kubernetes", "nacos-discovery"})
+@ConditionalOnMissingProfile({"kubernetes", "nacos-discovery", "consul-discovery"})
public class DefaultDiscoveryService implements DiscoveryService {
private final EurekaClient eurekaClient;
diff --git a/apollo-configservice/src/main/resources/application-consul-discovery.properties b/apollo-configservice/src/main/resources/application-consul-discovery.properties
new file mode 100644
index 00000000000..0aed7660f43
--- /dev/null
+++ b/apollo-configservice/src/main/resources/application-consul-discovery.properties
@@ -0,0 +1,9 @@
+apollo.eureka.server.enabled=false
+eureka.client.enabled=false
+
+#consul enabled
+spring.cloud.consul.enabled=true
+spring.cloud.consul.discovery.enabled=true
+spring.cloud.consul.service-registry.enabled=true
+spring.cloud.consul.discovery.heartbeat.enabled=true
+spring.cloud.consul.discovery.instance-id=apollo-configservice
diff --git a/apollo-configservice/src/main/resources/application.yml b/apollo-configservice/src/main/resources/application.yml
index aecb367c3f3..52c0a5299ae 100644
--- a/apollo-configservice/src/main/resources/application.yml
+++ b/apollo-configservice/src/main/resources/application.yml
@@ -3,7 +3,9 @@ spring:
name: apollo-configservice
profiles:
active: ${apollo_profile}
-
+ cloud:
+ consul:
+ enabled: false
ctrip:
appid: 100003171
@@ -31,7 +33,6 @@ eureka:
healthcheck:
enabled: true
eurekaServiceUrlPollIntervalSeconds: 60
-
management:
health:
status:
diff --git a/apollo-configservice/src/test/java/com/ctrip/framework/apollo/metaservice/service/ConsulDiscoveryServiceTest.java b/apollo-configservice/src/test/java/com/ctrip/framework/apollo/metaservice/service/ConsulDiscoveryServiceTest.java
new file mode 100644
index 00000000000..289bdcc12e3
--- /dev/null
+++ b/apollo-configservice/src/test/java/com/ctrip/framework/apollo/metaservice/service/ConsulDiscoveryServiceTest.java
@@ -0,0 +1,75 @@
+package com.ctrip.framework.apollo.metaservice.service;
+
+import com.ctrip.framework.apollo.core.dto.ServiceDTO;
+import com.google.common.collect.Lists;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+import org.springframework.cloud.client.ServiceInstance;
+import org.springframework.cloud.consul.discovery.ConsulDiscoveryClient;
+
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+/**
+ * @author kl (http://kailing.pub)
+ * @since 2021/3/1
+ */
+@RunWith(MockitoJUnitRunner.class)
+public class ConsulDiscoveryServiceTest {
+
+ @Mock
+ private ConsulDiscoveryClient consulDiscoveryClient;
+
+ private ConsulDiscoveryService consulDiscoveryService;
+
+ private String someServiceId;
+
+ @Before
+ public void setUp() throws Exception {
+ consulDiscoveryService = new ConsulDiscoveryService(consulDiscoveryClient);
+ someServiceId = "someServiceId";
+ }
+
+ @Test
+ public void testGetServiceInstancesWithNullInstances() {
+ when(consulDiscoveryClient.getInstances(someServiceId)).thenReturn(null);
+ assertTrue(consulDiscoveryService.getServiceInstances(someServiceId).isEmpty());
+ }
+
+
+ @Test
+ public void testGetServiceInstances() {
+ String someIp = "1.2.3.4";
+ int somePort = 8080;
+ String someInstanceId = "someInstanceId";
+ ServiceInstance someServiceInstance = mockServiceInstance(someInstanceId, someIp, somePort);
+
+ when(consulDiscoveryClient.getInstances(someServiceId)).thenReturn(
+ Lists.newArrayList(someServiceInstance));
+
+ List serviceDTOList = consulDiscoveryService.getServiceInstances(someServiceId);
+ ServiceDTO serviceDTO = serviceDTOList.get(0);
+ assertEquals(1, serviceDTOList.size());
+ assertEquals(someServiceId, serviceDTO.getAppName());
+ assertEquals("http://1.2.3.4:8080/", serviceDTO.getHomepageUrl());
+
+ }
+
+ private ServiceInstance mockServiceInstance(String instanceId, String ip, int port) {
+ ServiceInstance serviceInstance = mock(ServiceInstance.class);
+ when(serviceInstance.getInstanceId()).thenReturn(instanceId);
+ when(serviceInstance.getHost()).thenReturn(ip);
+ when(serviceInstance.getPort()).thenReturn(port);
+
+ return serviceInstance;
+ }
+
+
+}
diff --git a/apollo-configservice/src/test/resources/application.properties b/apollo-configservice/src/test/resources/application.properties
index 959445d313e..01d0ae25e57 100644
--- a/apollo-configservice/src/test/resources/application.properties
+++ b/apollo-configservice/src/test/resources/application.properties
@@ -3,7 +3,7 @@ spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.Ph
spring.h2.console.enabled = true
spring.h2.console.settings.web-allow-others=true
spring.jpa.properties.hibernate.show_sql=false
-
+spring.cloud.consul.enabled=false
spring.main.allow-bean-definition-overriding=true
# for ReleaseMessageScanner test
diff --git a/docs/zh/deployment/distributed-deployment-guide.md b/docs/zh/deployment/distributed-deployment-guide.md
index dfa525f7c68..b9c93cfd7e6 100644
--- a/docs/zh/deployment/distributed-deployment-guide.md
+++ b/docs/zh/deployment/distributed-deployment-guide.md
@@ -442,6 +442,18 @@ mvn clean package -Pgithub,nacos-discovery -DskipTests -pl apollo-configservice,
```properties
nacos.discovery.server-addr=127.0.0.1:8848
```
+##### 2.2.1.2.8 启用外部Consul服务注册中心替换内置eureka
+
+1. 修改build.sh/build.bat,将config-service和admin-service的maven编译命令更改为
+```shell
+mvn clean package -Pgithub -DskipTests -pl apollo-configservice,apollo-adminservice -am -Dapollo_profile=github,consul-discovery -Dspring_datasource_url=$apollo_config_db_url -Dspring_datasource_username=$apollo_config_db_username -Dspring_datasource_password=$apollo_config_db_password
+```
+
+2. 分别修改apollo-configservice和apollo-adminservice安装包中config目录下的application-github.properties,配置consul服务器地址
+```properties
+spring.cloud.consul.host=127.0.0.1
+spring.cloud.consul.port=8500
+```
### 2.2.2 部署Apollo服务端