├── README.md
├── account-service
├── Dockerfile
├── pom.xml
└── src
│ ├── main
│ ├── java
│ │ └── demo
│ │ │ └── ms
│ │ │ ├── AccountServiceApplication.java
│ │ │ ├── client
│ │ │ ├── AuthServiceClient.java
│ │ │ ├── AuthServiceClientFallback.java
│ │ │ └── AuthServiceRibbonClient.java
│ │ │ ├── domain
│ │ │ ├── Account.java
│ │ │ ├── Currency.java
│ │ │ ├── Item.java
│ │ │ ├── Saving.java
│ │ │ └── TimePeriod.java
│ │ │ ├── service
│ │ │ └── AccountService.java
│ │ │ ├── vo
│ │ │ └── User.java
│ │ │ └── web
│ │ │ └── controller
│ │ │ └── AccountController.java
│ └── resources
│ │ ├── bootstrap.yml
│ │ └── logback-spring.xml
│ └── test
│ └── java
│ └── demo
│ └── ms
│ └── AccountServiceApplicationTests.java
├── api-gateway
├── Dockerfile
├── pom.xml
└── src
│ ├── main
│ ├── java
│ │ └── demo
│ │ │ └── ms
│ │ │ ├── ApiGatewayApplication.java
│ │ │ └── fallback
│ │ │ ├── AccountServiceFallbackProvider.java
│ │ │ ├── AuthServiceFallbackProvider.java
│ │ │ └── SimpleClientHttpResponse.java
│ └── resources
│ │ ├── bootstrap.yml
│ │ └── logback-spring.xml
│ └── test
│ └── java
│ └── demo
│ └── ms
│ └── ApiGatewayApplicationTests.java
├── auth-service
├── Dockerfile
├── pom.xml
└── src
│ ├── main
│ ├── java
│ │ └── demo
│ │ │ └── ms
│ │ │ ├── AuthServiceApplication.java
│ │ │ ├── domain
│ │ │ └── User.java
│ │ │ ├── service
│ │ │ └── UserService.java
│ │ │ ├── util
│ │ │ └── IPUtils.java
│ │ │ └── web
│ │ │ └── controller
│ │ │ ├── ControllerExceptionHandler.java
│ │ │ └── UserController.java
│ └── resources
│ │ ├── bootstrap.yml
│ │ └── logback-spring.xml
│ └── test
│ └── java
│ └── demo
│ └── ms
│ └── AuthServiceApplicationTests.java
├── build-images.sh
├── cloud-gateway
├── Dockerfile
├── pom.xml
└── src
│ ├── main
│ ├── java
│ │ └── demo
│ │ │ └── ms
│ │ │ └── CloudGatewayApplication.java
│ └── resources
│ │ ├── bootstrap.yml
│ │ ├── logback-spring.xml
│ │ └── static
│ │ └── index.html
│ └── test
│ └── java
│ └── demo
│ └── ms
│ └── CloudGatewayApplicationTests.java
├── config-server
├── Dockerfile
├── pom.xml
└── src
│ ├── main
│ ├── java
│ │ └── demo
│ │ │ └── ms
│ │ │ └── ConfigServerApplication.java
│ └── resources
│ │ ├── application.yml
│ │ ├── bootstrap.yml
│ │ ├── logback-spring.xml
│ │ └── shared
│ │ ├── account-service.yml
│ │ ├── api-gateway.yml
│ │ ├── application.yml
│ │ ├── auth-service.yml
│ │ ├── cloud-gateway.yml
│ │ ├── monitor-dashboard.yml
│ │ ├── service-registry.yml
│ │ └── turbine-server.yml
│ └── test
│ └── java
│ └── demo
│ └── ms
│ └── ConfigServiceApplicationTests.java
├── deploy-docker.sh
├── deploy-kubernetes.sh
├── docker-compose.yml
├── docker
└── setup-docker-images.txt
├── kubernetes
├── account-service.yaml
├── api-gateway.yaml
├── auth-service.yaml
├── cloud-gateway.yaml
├── config-pv.yaml
├── config-secret.yaml
├── config-server.yaml
├── db-pv.yaml
├── env-configmap.yaml
├── log-pv.yaml
├── monitor-dashboard.yaml
├── mysql.yaml
├── rabbitmq.yaml
├── service-registry.yaml
├── turbine-server.yaml
└── zipkin.yaml
├── monitor-dashboard
├── Dockerfile
├── pom.xml
└── src
│ ├── main
│ ├── java
│ │ └── demo
│ │ │ └── ms
│ │ │ └── MonitorDashboardApplication.java
│ └── resources
│ │ ├── bootstrap.yml
│ │ └── logback-spring.xml
│ └── test
│ └── java
│ └── demo
│ └── ms
│ └── MonitorDashboardApplicationTests.java
├── pom.xml
├── push-images.sh
├── service-registry
├── Dockerfile
├── pom.xml
└── src
│ ├── main
│ ├── java
│ │ └── demo
│ │ │ └── ms
│ │ │ └── ServiceRegistryApplication.java
│ └── resources
│ │ ├── bootstrap.yml
│ │ └── logback-spring.xml
│ └── test
│ └── java
│ └── demo
│ └── ms
│ └── RegistryServiceApplicationTests.java
├── turbine-server
├── Dockerfile
├── pom.xml
└── src
│ └── main
│ ├── java
│ └── demo
│ │ └── ms
│ │ └── TurbineServerApplication.java
│ └── resources
│ ├── bootstrap.yml
│ └── logback-spring.xml
├── undeploy-docker.sh
└── undeploy-kubernetes.sh
/README.md:
--------------------------------------------------------------------------------
1 | # Microservices Demo
2 | Using Spring Cloud to develop microservices application and deploy to Kubernetes.
3 |
4 | * Externalized configuration: Spring Cloud Config
5 | * Service registry and discovery: Eureka
6 | * Client side load balancing: Ribbon, Feign
7 | * API gateway: Zuul, Spring Cloud Gateway
8 | * Circuit breaker: Hystrix, Turbine
9 | * Distributed tracing: Sleuth, Zipkin
10 |
11 | ## Deployment
12 | * `build-images.sh` is used to build docker images.
13 | It tags the images with `192.168.99.100:5000` prefix for uploading them to a local registry server on `192.168.99.100`.
14 | Update to the correct address if your registry server's address is not `192.168.99.100:5000`.
15 | If you don't deploy to Kubernetes, you can remove those prefix.
16 | * `push-images.sh` is used to push docker images to the registry server.
17 | * `deploy-docker.sh` is used to deploy the demo app to docker using `docker-compose.yml`.
18 | * `undeploy-docker.sh` is used to undeploy the demo app in docker.
19 | * `deploy-kubernetes.sh` is used to deploy the demo app to kubernetes.
20 | To deploy to Kubernetes, this demo uses `Minikube`.
21 | * `undeploy-kubernetes.sh` is used to undeploy the demo app in kubernetes.
22 | * This demo use Spring Cloud Gateway(cloud-gateway) as its api gateway, if you wants to use Zuul, using api-gateway instead.
23 |
24 | There are three ways to deploy this demo application.
25 | ### Local Deployment
26 | * You need to provide RabbitMQ and Zipkin services.
27 | - RabbitMQ:
28 |
29 | Please see https://www.rabbitmq.com/download.html
30 |
31 | If using docker, you can use the following command:
32 | ```
33 | docker run -d -p 5672:5672 -p 15672:15672 -e RABBITMQ_DEFAULT_USER=admin -e RABBITMQ_DEFAULT_PASS=amqp --name rabbitmq rabbitmq:management
34 | ```
35 |
36 | - Zipkin:
37 |
38 | Please see https://github.com/openzipkin/zipkin
39 | ```
40 | # Download Zipkin server
41 | curl -sSL https://zipkin.io/quickstart.sh | bash -s
42 | # Start Zipkin server
43 | RABBIT_ADDRESSES=localhost RABBIT_USER=admin RABBIT_PASSWORD=amqp java -jar zipkin.jar
44 | ```
45 |
46 | If using docker, you can use the following command:
47 | ```
48 | docker run -d -p 9411:9411 -e RABBIT_ADDRESSES=rabbitmq -e RABBIT_USER=admin -e RABBIT_PASSWORD=amqp --link rabbitmq:rabbitmq --name zipkin openzipkin/zipkin
49 | ```
50 |
51 | * Edit `config-server/src/main/resources/application.properties`:
52 | * Make sure `RABBITMQ_SERVICE_HOST`, `RABBITMQ_SERVICE_PORT`, `RABBITMQ_SERVICE_USERNAME` and `RABBITMQ_SERVICE_PASSWORD`
53 | match your RabbitMQ configuration.
54 | * Set `APP_CONFIG_DIR` and `APP_LOGGINH_DIR` to your correct file path.
55 | * Use `java -jar` to start each service, config-server should be started first, service-registry next, then other services.
56 | * Access services with its URL, eg:
57 | ```
58 | cloud-gateway: http://localhost:8080/
59 | auth-service: http://localhost:9000/
60 | account-service: http://localhost:9010/
61 | service-registry: http://localhost:8761/
62 | config-server: http://localhost:8888/
63 | turbine-server: http://localhost:8989/
64 | monitor-dashboard: http://localhost:7979/
65 | zipkin: http://localhost:9411/
66 | ```
67 |
68 | ### Docker Deployment
69 | * Download rabbitmq:management image.
70 | Tag the image with `192.168.99.100:5000/rabbitmq:management` if you use `192.168.99.100:5000` prefix in `build-images.sh`.
71 | * Download openzipkin/zipkin image.
72 | Tag the image with `192.168.99.100:5000/zipkin` if you use `192.168.99.100:5000` prefix in `build-images.sh`.
73 | * Edit `microservices-demo/deploy-docker.sh`, set `APP_CONFIG_DIR` and `APP_LOGGINH_DIR` to your correct file path.
74 | * Run the script `microservices-demo/build-images.sh` to build docker images.
75 | * Run the script `microservices-demo/deploy-docker.sh` to start containers.
76 | * Run the script `microservices-demo/undeploy-docker.sh` if you want to stop and remove the containers.
77 | * Access a service with its URL (same as Local Deployment)
78 |
79 | ### Kubernetes Deployment (v1.10.0)
80 | * Download rabbitmq:management image.
81 | Tag the image with `192.168.99.100:5000/rabbitmq:management`.
82 | * Download openzipkin/zipkin image.
83 | Tag the image with `192.168.99.100:5000/zipkin`.
84 | * Edit `microservices-demo/kubernetes/config-pv.yaml`, set `spec.hostPath.path` to your correct file path.
85 | Edit `microservices-demo/kubernetes/log-pv.yaml`, set `spec.hostPath.path` to your correct file path.
86 | * Run the script `microservices-demo/build-images.sh` to build docker images.
87 | * Run the script `microservices-demo/push-images.sh` to upload docker images to registry server.
88 | * Run the script `microservices-demo/deploy-kubernetes.sh` to deploy to Kubernetes.
89 | * Run the script `microservices-demo/undeploy-kubernetes.sh` if you want to stop and remove the containers.
90 | * Access services using command `minikube service SERVICE_NAME` eg:
91 | ```
92 | minikube service cloud-gateway
93 | minikube service auth-service
94 | minikube service account-service
95 | minikube service service-registry
96 | minikube service config-server
97 | minikube service monitor-dashboard
98 | minikube service zipkin
99 | ```
100 |
--------------------------------------------------------------------------------
/account-service/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM openjdk:8-jdk-alpine
2 |
3 | VOLUME /tmp
4 |
5 | # Set timezone
6 | ENV TIME_ZONE Asia/Taipei
7 | RUN apk --no-cache add \
8 | tzdata \
9 | && echo "${TIME_ZONE}" > /etc/timezone \
10 | && ln -sf /usr/share/zoneinfo/${TIME_ZONE} /etc/localtime
11 |
12 | RUN mkdir /msdemo
13 | WORKDIR /msdemo
14 | COPY ./target/account-service.jar ./account-service.jar
15 |
16 | CMD ["java", "-Djava.security.egd=file:/dev/./urandom", "-jar", "account-service.jar"]
--------------------------------------------------------------------------------
/account-service/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | account-service
7 | account-service
8 | Spring Cloud Microservices Demo
9 |
10 |
11 | demo.ms
12 | ms-demo
13 | 0.0.1
14 |
15 |
16 |
17 |
18 | org.springframework.boot
19 | spring-boot-starter-web
20 |
21 |
22 |
23 | org.springframework.boot
24 | spring-boot-starter-actuator
25 |
26 |
27 |
28 |
29 | org.springframework.cloud
30 | spring-cloud-starter-config
31 |
32 |
33 |
34 | org.springframework.cloud
35 | spring-cloud-starter-bus-amqp
36 |
37 |
38 |
39 |
40 | org.springframework.cloud
41 | spring-cloud-starter-netflix-eureka-client
42 |
43 |
44 |
45 |
46 | org.springframework.cloud
47 | spring-cloud-starter-netflix-hystrix
48 |
49 |
50 | org.springframework.cloud
51 | spring-cloud-netflix-hystrix-stream
52 |
53 |
54 | org.springframework.cloud
55 | spring-cloud-starter-stream-rabbit
56 |
57 |
58 |
59 |
60 | org.springframework.cloud
61 | spring-cloud-starter-zipkin
62 |
63 |
64 | org.springframework.amqp
65 | spring-rabbit
66 |
67 |
68 |
69 |
70 | org.springframework.cloud
71 | spring-cloud-starter-openfeign
72 |
73 |
74 |
75 | org.springframework.boot
76 | spring-boot-starter-test
77 | test
78 |
79 |
80 |
81 |
82 | ${project.name}
83 |
84 |
85 | org.springframework.boot
86 | spring-boot-maven-plugin
87 |
88 |
89 |
90 |
91 |
--------------------------------------------------------------------------------
/account-service/src/main/java/demo/ms/AccountServiceApplication.java:
--------------------------------------------------------------------------------
1 | package demo.ms;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 | import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
6 | import org.springframework.cloud.client.loadbalancer.LoadBalanced;
7 | import org.springframework.cloud.openfeign.EnableFeignClients;
8 | import org.springframework.context.annotation.Bean;
9 | import org.springframework.web.client.RestTemplate;
10 |
11 | @SpringBootApplication
12 | @EnableCircuitBreaker
13 | @EnableFeignClients
14 | public class AccountServiceApplication {
15 |
16 | public static void main(String[] args) {
17 | SpringApplication.run(AccountServiceApplication.class, args);
18 | }
19 |
20 | /**
21 | * to enable Ribbon support.
22 | */
23 | @LoadBalanced
24 | @Bean
25 | RestTemplate restTemplate() {
26 | return new RestTemplate();
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/account-service/src/main/java/demo/ms/client/AuthServiceClient.java:
--------------------------------------------------------------------------------
1 | package demo.ms.client;
2 |
3 | import static org.springframework.web.bind.annotation.RequestMethod.DELETE;
4 | import static org.springframework.web.bind.annotation.RequestMethod.GET;
5 | import static org.springframework.web.bind.annotation.RequestMethod.POST;
6 |
7 | import java.util.List;
8 |
9 | import org.springframework.cloud.openfeign.FeignClient;
10 | import org.springframework.http.MediaType;
11 | import org.springframework.web.bind.annotation.PathVariable;
12 | import org.springframework.web.bind.annotation.RequestMapping;
13 |
14 | import demo.ms.vo.User;
15 |
16 | @FeignClient(name = "auth-service", fallback = AuthServiceClientFallback.class)
17 | public interface AuthServiceClient {
18 |
19 | @RequestMapping(path = "/users", method = GET)
20 | List getUsers();
21 |
22 | @RequestMapping(path = "/users/{username}", method = GET)
23 | User getUser(@PathVariable("username") String username);
24 |
25 | @RequestMapping(path = "/users", method = POST, consumes = MediaType.APPLICATION_JSON_UTF8_VALUE)
26 | User createUser(User user);
27 |
28 | // deleteUser is used to demo circuit breaker fallback
29 | @RequestMapping(path = "/users/{username}", method = DELETE)
30 | void deleteUser(@PathVariable("username") String username);
31 |
32 | }
--------------------------------------------------------------------------------
/account-service/src/main/java/demo/ms/client/AuthServiceClientFallback.java:
--------------------------------------------------------------------------------
1 | package demo.ms.client;
2 |
3 | import java.util.ArrayList;
4 | import java.util.List;
5 |
6 | import org.slf4j.Logger;
7 | import org.slf4j.LoggerFactory;
8 | import org.springframework.stereotype.Component;
9 |
10 | import demo.ms.vo.User;
11 |
12 | @Component
13 | public class AuthServiceClientFallback implements AuthServiceClient {
14 |
15 | private static final Logger log = LoggerFactory.getLogger(AuthServiceClientFallback.class);
16 |
17 | @Override
18 | public List getUsers() {
19 | log.warn("Fallback method is called for getting users");
20 | return new ArrayList();
21 | }
22 |
23 | @Override
24 | public User getUser(String username) {
25 | log.warn("Fallback method is called for getting user {}", username);
26 | return new User();
27 | }
28 |
29 | @Override
30 | public User createUser(User user) {
31 | log.warn("Fallback method is called for creating user {}", user.getUsername());
32 | return user;
33 | }
34 |
35 | @Override
36 | public void deleteUser(String username) {
37 | log.warn("Fallback method is called for deleting user {}", username);
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/account-service/src/main/java/demo/ms/client/AuthServiceRibbonClient.java:
--------------------------------------------------------------------------------
1 | package demo.ms.client;
2 |
3 | import java.util.ArrayList;
4 | import java.util.Arrays;
5 | import java.util.List;
6 |
7 | import org.slf4j.Logger;
8 | import org.slf4j.LoggerFactory;
9 | import org.springframework.stereotype.Component;
10 | import org.springframework.web.client.RestTemplate;
11 |
12 | import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
13 |
14 | import demo.ms.vo.User;
15 |
16 | @Component
17 | public class AuthServiceRibbonClient {
18 |
19 | private static final Logger log = LoggerFactory.getLogger(AuthServiceRibbonClient.class);
20 |
21 | private RestTemplate restTemplate;
22 |
23 | public AuthServiceRibbonClient(RestTemplate restTemplate) {
24 | this.restTemplate = restTemplate;
25 | }
26 |
27 | @HystrixCommand(fallbackMethod = "defaultGetUsers")
28 | public List getUsers() {
29 | User[] users = restTemplate.getForObject("http://auth-service/users", User[].class);
30 | return Arrays.asList(users);
31 | }
32 |
33 | public List defaultGetUsers() {
34 | log.warn("Fallback method is called for getting users");
35 | return new ArrayList();
36 | }
37 |
38 | @HystrixCommand(fallbackMethod = "defaultGetUser")
39 | public User getUser(String username) {
40 | return restTemplate.getForObject("http://auth-service/users/{username}", User.class, username);
41 | }
42 |
43 | public User defaultGetUser(String username) {
44 | log.warn("Fallback method is called for getting user {}", username);
45 | return new User();
46 | }
47 |
48 | @HystrixCommand(fallbackMethod = "defaultDeleteUser")
49 | public void deleteUser(String username) {
50 | restTemplate.delete("http://auth-service/users/{username}", username);
51 | }
52 |
53 | public void defaultDeleteUser(String username) {
54 | log.warn("Fallback method is called for deleting user {}", username);
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/account-service/src/main/java/demo/ms/domain/Account.java:
--------------------------------------------------------------------------------
1 | package demo.ms.domain;
2 |
3 | import java.math.BigDecimal;
4 | import java.util.Date;
5 | import java.util.List;
6 | import java.util.Map;
7 |
8 | public class Account {
9 |
10 | private String name;
11 |
12 | private Date lastSeen;
13 |
14 | private List- incomes;
15 |
16 | private List
- expenses;
17 |
18 | private Saving saving;
19 |
20 | private String note;
21 |
22 | private Map extra;
23 |
24 | public Account() {
25 | }
26 |
27 | public Account(String name) {
28 | this.name = name;
29 | Saving saving = new Saving();
30 | saving.setAmount(new BigDecimal(0));
31 | saving.setCurrency(Currency.getDefault());
32 | saving.setInterest(new BigDecimal(0));
33 | saving.setDeposit(false);
34 | saving.setCapitalization(false);
35 | this.saving = saving;
36 | this.lastSeen = new Date();
37 | }
38 |
39 | public String getName() {
40 | return name;
41 | }
42 |
43 | public void setName(String name) {
44 | this.name = name;
45 | }
46 |
47 | public Date getLastSeen() {
48 | return lastSeen;
49 | }
50 |
51 | public void setLastSeen(Date lastSeen) {
52 | this.lastSeen = lastSeen;
53 | }
54 |
55 | public List
- getIncomes() {
56 | return incomes;
57 | }
58 |
59 | public void setIncomes(List
- incomes) {
60 | this.incomes = incomes;
61 | }
62 |
63 | public List
- getExpenses() {
64 | return expenses;
65 | }
66 |
67 | public void setExpenses(List
- expenses) {
68 | this.expenses = expenses;
69 | }
70 |
71 | public Saving getSaving() {
72 | return saving;
73 | }
74 |
75 | public void setSaving(Saving saving) {
76 | this.saving = saving;
77 | }
78 |
79 | public String getNote() {
80 | return note;
81 | }
82 |
83 | public void setNote(String note) {
84 | this.note = note;
85 | }
86 |
87 | public Map getExtra() {
88 | return extra;
89 | }
90 |
91 | public void setExtra(Map extra) {
92 | this.extra = extra;
93 | }
94 | }
95 |
--------------------------------------------------------------------------------
/account-service/src/main/java/demo/ms/domain/Currency.java:
--------------------------------------------------------------------------------
1 | package demo.ms.domain;
2 |
3 | public enum Currency {
4 |
5 | NT, RMB, USD, EUR;
6 |
7 | public static Currency getDefault() {
8 | return NT;
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/account-service/src/main/java/demo/ms/domain/Item.java:
--------------------------------------------------------------------------------
1 | package demo.ms.domain;
2 |
3 | import java.math.BigDecimal;
4 |
5 | public class Item {
6 |
7 | private String title;
8 |
9 | private BigDecimal amount;
10 |
11 | private Currency currency;
12 |
13 | private TimePeriod period;
14 |
15 | private String icon;
16 |
17 | public String getTitle() {
18 | return title;
19 | }
20 |
21 | public void setTitle(String title) {
22 | this.title = title;
23 | }
24 |
25 | public BigDecimal getAmount() {
26 | return amount;
27 | }
28 |
29 | public void setAmount(BigDecimal amount) {
30 | this.amount = amount;
31 | }
32 |
33 | public Currency getCurrency() {
34 | return currency;
35 | }
36 |
37 | public void setCurrency(Currency currency) {
38 | this.currency = currency;
39 | }
40 |
41 | public TimePeriod getPeriod() {
42 | return period;
43 | }
44 |
45 | public void setPeriod(TimePeriod period) {
46 | this.period = period;
47 | }
48 |
49 | public String getIcon() {
50 | return icon;
51 | }
52 |
53 | public void setIcon(String icon) {
54 | this.icon = icon;
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/account-service/src/main/java/demo/ms/domain/Saving.java:
--------------------------------------------------------------------------------
1 | package demo.ms.domain;
2 |
3 | import java.math.BigDecimal;
4 |
5 | public class Saving {
6 |
7 | private BigDecimal amount;
8 |
9 | private Currency currency;
10 |
11 | private BigDecimal interest;
12 |
13 | private Boolean deposit;
14 |
15 | private Boolean capitalization;
16 |
17 | public BigDecimal getAmount() {
18 | return amount;
19 | }
20 |
21 | public void setAmount(BigDecimal amount) {
22 | this.amount = amount;
23 | }
24 |
25 | public Currency getCurrency() {
26 | return currency;
27 | }
28 |
29 | public void setCurrency(Currency currency) {
30 | this.currency = currency;
31 | }
32 |
33 | public BigDecimal getInterest() {
34 | return interest;
35 | }
36 |
37 | public void setInterest(BigDecimal interest) {
38 | this.interest = interest;
39 | }
40 |
41 | public Boolean getDeposit() {
42 | return deposit;
43 | }
44 |
45 | public void setDeposit(Boolean deposit) {
46 | this.deposit = deposit;
47 | }
48 |
49 | public Boolean getCapitalization() {
50 | return capitalization;
51 | }
52 |
53 | public void setCapitalization(Boolean capitalization) {
54 | this.capitalization = capitalization;
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/account-service/src/main/java/demo/ms/domain/TimePeriod.java:
--------------------------------------------------------------------------------
1 | package demo.ms.domain;
2 |
3 | public enum TimePeriod {
4 |
5 | YEAR, QUARTER, MONTH, WEEK, DAY, HOUR
6 |
7 | }
8 |
--------------------------------------------------------------------------------
/account-service/src/main/java/demo/ms/service/AccountService.java:
--------------------------------------------------------------------------------
1 | package demo.ms.service;
2 |
3 | import java.util.ArrayList;
4 | import java.util.List;
5 | import java.util.Map;
6 | import java.util.Optional;
7 | import java.util.function.Function;
8 | import java.util.stream.Collectors;
9 | import java.util.stream.Stream;
10 |
11 | import javax.annotation.PostConstruct;
12 |
13 | import org.slf4j.Logger;
14 | import org.slf4j.LoggerFactory;
15 | import org.springframework.stereotype.Service;
16 | import org.springframework.util.StringUtils;
17 |
18 | import demo.ms.client.AuthServiceClient;
19 | import demo.ms.client.AuthServiceRibbonClient;
20 | import demo.ms.domain.Account;
21 | import demo.ms.vo.User;
22 |
23 | @Service
24 | public class AccountService {
25 |
26 | private static final Logger log = LoggerFactory.getLogger(AccountService.class);
27 |
28 | private AuthServiceClient authServiceClient;
29 |
30 | private AuthServiceRibbonClient authServiceRibbonClient;
31 |
32 | private Map accounts;
33 |
34 | public AccountService(AuthServiceClient authServiceClient, AuthServiceRibbonClient authServiceRibbonClient) {
35 | this.authServiceClient = authServiceClient;
36 | this.authServiceRibbonClient = authServiceRibbonClient;
37 | }
38 |
39 | @PostConstruct
40 | public void createAccounts() {
41 | accounts = Stream.of(
42 | new Account("albert"),
43 | new Account("alex"),
44 | new Account("andrew"))
45 | .collect(Collectors.toMap(Account::getName, Function.identity()));
46 | }
47 |
48 | public List getAccounts() {
49 | // to demo ribbon
50 | authServiceRibbonClient.getUsers();
51 | return new ArrayList(accounts.values());
52 | }
53 |
54 | public Account getAccount(String name) {
55 | // to demo feign
56 | User user = authServiceClient.getUser(name);
57 |
58 | return Optional.ofNullable(accounts.get(name))
59 | .map(account -> addUserInfo(account, user))
60 | .orElseGet(() -> {
61 | log.info("Can not find account {}", name);
62 | return new Account();
63 | });
64 | }
65 |
66 | private Account addUserInfo(Account account, User user) {
67 | if (!StringUtils.isEmpty(user.getUsername())) {
68 | // to show which user-service instance is connected
69 | Map extraInfo = user.getExtra();
70 | account.setExtra(extraInfo);
71 | }
72 | return account;
73 | }
74 |
75 | public Account createAccount(Account newAccount) {
76 | // to demo feign
77 | authServiceClient.createUser(new User(newAccount.getName()));
78 |
79 | accounts.put(newAccount.getName(), newAccount);
80 | return newAccount;
81 | }
82 |
83 | public Account updateAccount(Account account) {
84 | accounts.put(account.getName(), account);
85 | return account;
86 | }
87 |
88 | public void deleteAccount(String name) {
89 | // to demo ribbon with hystrix fallback
90 | authServiceRibbonClient.deleteUser(name);
91 | }
92 | }
93 |
--------------------------------------------------------------------------------
/account-service/src/main/java/demo/ms/vo/User.java:
--------------------------------------------------------------------------------
1 | package demo.ms.vo;
2 |
3 | import java.util.Map;
4 |
5 | public class User {
6 |
7 | private String username;
8 |
9 | private String password;
10 |
11 | private String email;
12 |
13 | private Map extra;
14 |
15 | public User() {
16 | }
17 |
18 | public User(String username) {
19 | super();
20 | this.username = username;
21 | }
22 |
23 | public String getUsername() {
24 | return username;
25 | }
26 |
27 | public void setUsername(String username) {
28 | this.username = username;
29 | }
30 |
31 | public String getPassword() {
32 | return password;
33 | }
34 |
35 | public void setPassword(String password) {
36 | this.password = password;
37 | }
38 |
39 | public String getEmail() {
40 | return email;
41 | }
42 |
43 | public void setEmail(String email) {
44 | this.email = email;
45 | }
46 |
47 | public Map getExtra() {
48 | return extra;
49 | }
50 |
51 | public void setExtra(Map extra) {
52 | this.extra = extra;
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/account-service/src/main/java/demo/ms/web/controller/AccountController.java:
--------------------------------------------------------------------------------
1 | package demo.ms.web.controller;
2 |
3 | import java.util.List;
4 |
5 | import org.slf4j.Logger;
6 | import org.slf4j.LoggerFactory;
7 | import org.springframework.web.bind.annotation.DeleteMapping;
8 | import org.springframework.web.bind.annotation.GetMapping;
9 | import org.springframework.web.bind.annotation.PathVariable;
10 | import org.springframework.web.bind.annotation.PostMapping;
11 | import org.springframework.web.bind.annotation.PutMapping;
12 | import org.springframework.web.bind.annotation.RequestBody;
13 | import org.springframework.web.bind.annotation.RestController;
14 |
15 | import demo.ms.domain.Account;
16 | import demo.ms.service.AccountService;
17 |
18 | @RestController
19 | public class AccountController {
20 |
21 | private static final Logger log = LoggerFactory.getLogger(AccountController.class);
22 |
23 | private AccountService accountService;
24 |
25 | public AccountController(AccountService accountService) {
26 | this.accountService = accountService;
27 | }
28 |
29 | @GetMapping({"", "/", "/accounts"})
30 | public List getAccounts() {
31 | return accountService.getAccounts();
32 | }
33 |
34 | @GetMapping("/accounts/{name}")
35 | public Account getAccount(@PathVariable String name) {
36 | // log is used to demo sleuth: add span and trace IDs to log
37 | log.debug("Get account {}", name);
38 | return accountService.getAccount(name);
39 | }
40 |
41 | @PostMapping("/accounts")
42 | public Account createAccount(@RequestBody Account account) {
43 | log.info("Create account {}", account.getName());
44 | return accountService.createAccount(account);
45 | }
46 |
47 | @PutMapping("/accounts/{name}")
48 | public Account updateAccount(@PathVariable String name, @RequestBody Account account) {
49 | log.info("Update account {}", name);
50 | return accountService.updateAccount(account);
51 | }
52 |
53 | @DeleteMapping("/accounts/{name}")
54 | public void deleteAccount(@PathVariable String name) {
55 | log.info("Delete account {}", name);
56 | accountService.deleteAccount(name);
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/account-service/src/main/resources/bootstrap.yml:
--------------------------------------------------------------------------------
1 | CONFIG_SERVER_URL: http://127.0.0.1:8888
2 |
3 | server:
4 | port: 9010
5 |
6 | spring:
7 | application:
8 | name: account-service
9 | main:
10 | banner-mode: "off"
11 | mvc:
12 | favicon.enabled: false
13 | cloud:
14 | config:
15 | uri: ${CONFIG_SERVER_URL}
16 | fail-fast: true
17 |
--------------------------------------------------------------------------------
/account-service/src/main/resources/logback-spring.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/account-service/src/test/java/demo/ms/AccountServiceApplicationTests.java:
--------------------------------------------------------------------------------
1 | package demo.ms;
2 |
3 | import org.junit.Test;
4 | import org.junit.runner.RunWith;
5 | import org.springframework.boot.test.context.SpringBootTest;
6 | import org.springframework.test.context.junit4.SpringRunner;
7 |
8 | @RunWith(SpringRunner.class)
9 | @SpringBootTest
10 | public class AccountServiceApplicationTests {
11 |
12 | @Test
13 | public void contextLoads() {
14 | }
15 |
16 | }
17 |
--------------------------------------------------------------------------------
/api-gateway/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM openjdk:8-jdk-alpine
2 |
3 | VOLUME /tmp
4 |
5 | # Set timezone
6 | ENV TIME_ZONE Asia/Taipei
7 | RUN apk --no-cache add \
8 | tzdata \
9 | && echo "${TIME_ZONE}" > /etc/timezone \
10 | && ln -sf /usr/share/zoneinfo/${TIME_ZONE} /etc/localtime
11 |
12 | RUN mkdir /msdemo
13 | WORKDIR /msdemo
14 | COPY ./target/api-gateway.jar ./api-gateway.jar
15 |
16 | CMD ["java", "-Djava.security.egd=file:/dev/./urandom", "-jar", "api-gateway.jar"]
--------------------------------------------------------------------------------
/api-gateway/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | api-gateway
7 | api-gateway
8 | Spring Cloud Microservices Demo
9 |
10 |
11 | demo.ms
12 | ms-demo
13 | 0.0.1
14 |
15 |
16 |
17 |
18 | org.springframework.boot
19 | spring-boot-starter-actuator
20 |
21 |
22 |
23 | org.springframework.cloud
24 | spring-cloud-starter-config
25 |
26 |
27 | org.springframework.cloud
28 | spring-cloud-starter-bus-amqp
29 |
30 |
31 |
32 | org.springframework.cloud
33 | spring-cloud-starter-netflix-eureka-client
34 |
35 |
36 |
37 | org.springframework.cloud
38 | spring-cloud-starter-netflix-hystrix
39 |
40 |
41 | org.springframework.cloud
42 | spring-cloud-netflix-hystrix-stream
43 |
44 |
45 | org.springframework.cloud
46 | spring-cloud-starter-stream-rabbit
47 |
48 |
49 |
50 | org.springframework.cloud
51 | spring-cloud-starter-zipkin
52 |
53 |
54 | org.springframework.amqp
55 | spring-rabbit
56 |
57 |
58 |
59 |
60 | org.springframework.cloud
61 | spring-cloud-starter-netflix-zuul
62 |
63 |
64 |
65 | org.springframework.boot
66 | spring-boot-starter-test
67 | test
68 |
69 |
70 |
71 |
72 | ${project.name}
73 |
74 |
75 | org.springframework.boot
76 | spring-boot-maven-plugin
77 |
78 |
79 |
80 |
81 |
--------------------------------------------------------------------------------
/api-gateway/src/main/java/demo/ms/ApiGatewayApplication.java:
--------------------------------------------------------------------------------
1 | package demo.ms;
2 |
3 | import javax.servlet.http.HttpServletRequest;
4 |
5 | import org.slf4j.Logger;
6 | import org.slf4j.LoggerFactory;
7 | import org.springframework.boot.SpringApplication;
8 | import org.springframework.boot.autoconfigure.SpringBootApplication;
9 | import org.springframework.boot.web.servlet.error.ErrorController;
10 | import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
11 | import org.springframework.cloud.client.loadbalancer.LoadBalanced;
12 | import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
13 | import org.springframework.context.annotation.Bean;
14 | import org.springframework.http.HttpHeaders;
15 | import org.springframework.http.HttpStatus;
16 | import org.springframework.http.MediaType;
17 | import org.springframework.http.ResponseEntity;
18 | import org.springframework.stereotype.Controller;
19 | import org.springframework.util.StringUtils;
20 | import org.springframework.web.bind.annotation.GetMapping;
21 | import org.springframework.web.client.RestTemplate;
22 |
23 | import demo.ms.fallback.AccountServiceFallbackProvider;
24 | import demo.ms.fallback.AuthServiceFallbackProvider;
25 |
26 | @SpringBootApplication
27 | @EnableZuulProxy
28 | @EnableCircuitBreaker
29 | public class ApiGatewayApplication {
30 |
31 | public static void main(String[] args) {
32 | SpringApplication.run(ApiGatewayApplication.class, args);
33 | }
34 |
35 | /**
36 | * To enable Ribbon and retry support.
37 | */
38 | @LoadBalanced
39 | @Bean
40 | RestTemplate restTemplate() {
41 | return new RestTemplate();
42 | }
43 |
44 | /**
45 | * To provide Hystrix fallback.
46 | */
47 | @Bean
48 | AuthServiceFallbackProvider authServiceFallbackProvider() {
49 | return new AuthServiceFallbackProvider();
50 | }
51 |
52 | @Bean
53 | AccountServiceFallbackProvider accountServiceFallbackProvider() {
54 | return new AccountServiceFallbackProvider();
55 | }
56 |
57 | @Controller
58 | static class WebController implements ErrorController {
59 |
60 | private static final Logger log = LoggerFactory.getLogger(WebController.class);
61 |
62 | private static final String ERROR_MAPPING = "/error";
63 |
64 | @Override
65 | public String getErrorPath() {
66 | return ERROR_MAPPING;
67 | }
68 |
69 | @GetMapping({ "", "/" })
70 | public String index() {
71 | // for demo
72 | return "redirect:/acct/accounts";
73 | }
74 |
75 | /**
76 | * Using JSON message instead of error page.
77 | * @param request
78 | * @return
79 | */
80 | @GetMapping(ERROR_MAPPING)
81 | public ResponseEntity error(HttpServletRequest request) {
82 | Integer statusCode = (Integer) request.getAttribute("javax.servlet.error.status_code");
83 | String errorMsg = (String) request.getAttribute("javax.servlet.error.message");
84 | log.warn("Got error: {} {}", statusCode, errorMsg);
85 |
86 | HttpStatus status = HttpStatus.valueOf(statusCode);
87 |
88 | if (StringUtils.isEmpty(errorMsg)) {
89 | errorMsg = status.name();
90 | }
91 |
92 | HttpHeaders headers = new HttpHeaders();
93 | headers.setContentType(MediaType.APPLICATION_JSON);
94 |
95 | return new ResponseEntity(errorMsg, headers, status);
96 | }
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/api-gateway/src/main/java/demo/ms/fallback/AccountServiceFallbackProvider.java:
--------------------------------------------------------------------------------
1 | package demo.ms.fallback;
2 |
3 | import java.io.ByteArrayInputStream;
4 | import java.io.IOException;
5 | import java.io.InputStream;
6 |
7 | import org.slf4j.Logger;
8 | import org.slf4j.LoggerFactory;
9 | import org.springframework.cloud.netflix.zuul.filters.route.FallbackProvider;
10 | import org.springframework.http.HttpStatus;
11 | import org.springframework.http.client.ClientHttpResponse;
12 |
13 | import com.netflix.hystrix.exception.HystrixTimeoutException;
14 |
15 | public class AccountServiceFallbackProvider implements FallbackProvider {
16 |
17 | private static final Logger log = LoggerFactory.getLogger(AccountServiceFallbackProvider.class);
18 |
19 | @Override
20 | public String getRoute() {
21 | return "account-service";
22 | }
23 |
24 | @Override
25 | public ClientHttpResponse fallbackResponse(String route, final Throwable cause) {
26 | log.error("Fallback for error: {}", cause.getMessage());
27 | if (cause instanceof HystrixTimeoutException) {
28 | return response(HttpStatus.GATEWAY_TIMEOUT);
29 | } else {
30 | return response(HttpStatus.INTERNAL_SERVER_ERROR);
31 | }
32 | }
33 |
34 | private ClientHttpResponse response(final HttpStatus status) {
35 | return new SimpleClientHttpResponse(status) {
36 | @Override
37 | public InputStream getBody() throws IOException {
38 | return new ByteArrayInputStream("Account Service Unavailabe!".getBytes());
39 | }
40 | };
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/api-gateway/src/main/java/demo/ms/fallback/AuthServiceFallbackProvider.java:
--------------------------------------------------------------------------------
1 | package demo.ms.fallback;
2 |
3 | import java.io.ByteArrayInputStream;
4 | import java.io.IOException;
5 | import java.io.InputStream;
6 |
7 | import org.slf4j.Logger;
8 | import org.slf4j.LoggerFactory;
9 | import org.springframework.cloud.netflix.zuul.filters.route.FallbackProvider;
10 | import org.springframework.http.HttpStatus;
11 | import org.springframework.http.client.ClientHttpResponse;
12 |
13 | import com.netflix.hystrix.exception.HystrixTimeoutException;
14 |
15 | public class AuthServiceFallbackProvider implements FallbackProvider {
16 |
17 | private static final Logger log = LoggerFactory.getLogger(AuthServiceFallbackProvider.class);
18 |
19 | @Override
20 | public String getRoute() {
21 | return "auth-service";
22 | }
23 |
24 | @Override
25 | public ClientHttpResponse fallbackResponse(String route, final Throwable cause) {
26 | log.error("Fallback for error: {}", cause.getMessage());
27 | if (cause instanceof HystrixTimeoutException) {
28 | return response(HttpStatus.GATEWAY_TIMEOUT);
29 | } else {
30 | return response(HttpStatus.INTERNAL_SERVER_ERROR);
31 | }
32 | }
33 |
34 | private ClientHttpResponse response(final HttpStatus status) {
35 | return new SimpleClientHttpResponse(status) {
36 | @Override
37 | public InputStream getBody() throws IOException {
38 | return new ByteArrayInputStream("Auth Service Unavailabe!".getBytes());
39 | }
40 | };
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/api-gateway/src/main/java/demo/ms/fallback/SimpleClientHttpResponse.java:
--------------------------------------------------------------------------------
1 | package demo.ms.fallback;
2 |
3 | import java.io.ByteArrayInputStream;
4 | import java.io.IOException;
5 | import java.io.InputStream;
6 |
7 | import org.springframework.http.HttpHeaders;
8 | import org.springframework.http.HttpStatus;
9 | import org.springframework.http.MediaType;
10 | import org.springframework.http.client.ClientHttpResponse;
11 |
12 | public class SimpleClientHttpResponse implements ClientHttpResponse {
13 |
14 | private final HttpStatus status;
15 |
16 | public SimpleClientHttpResponse(HttpStatus status) {
17 | super();
18 | this.status = status;
19 | }
20 |
21 | @Override
22 | public HttpStatus getStatusCode() throws IOException {
23 | return status;
24 | }
25 |
26 | @Override
27 | public int getRawStatusCode() throws IOException {
28 | return status.value();
29 | }
30 |
31 | @Override
32 | public String getStatusText() throws IOException {
33 | return status.getReasonPhrase();
34 | }
35 |
36 | @Override
37 | public void close() {
38 | }
39 |
40 | @Override
41 | public InputStream getBody() throws IOException {
42 | return new ByteArrayInputStream("fallback".getBytes());
43 | }
44 |
45 | @Override
46 | public HttpHeaders getHeaders() {
47 | HttpHeaders headers = new HttpHeaders();
48 | headers.setContentType(MediaType.APPLICATION_JSON);
49 | return headers;
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/api-gateway/src/main/resources/bootstrap.yml:
--------------------------------------------------------------------------------
1 | CONFIG_SERVER_URL: http://127.0.0.1:8888
2 |
3 | server:
4 | port: 8080
5 |
6 | spring:
7 | application:
8 | name: api-gateway
9 | main:
10 | banner-mode: "off"
11 | mvc:
12 | favicon.enabled: false
13 | cloud:
14 | config:
15 | uri: ${CONFIG_SERVER_URL}
16 | fail-fast: true
17 |
--------------------------------------------------------------------------------
/api-gateway/src/main/resources/logback-spring.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/api-gateway/src/test/java/demo/ms/ApiGatewayApplicationTests.java:
--------------------------------------------------------------------------------
1 | package demo.ms;
2 |
3 | import org.junit.Test;
4 | import org.junit.runner.RunWith;
5 | import org.springframework.boot.test.context.SpringBootTest;
6 | import org.springframework.test.context.junit4.SpringRunner;
7 |
8 | @RunWith(SpringRunner.class)
9 | @SpringBootTest
10 | public class ApiGatewayApplicationTests {
11 |
12 | @Test
13 | public void contextLoads() {
14 | }
15 |
16 | }
17 |
--------------------------------------------------------------------------------
/auth-service/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM openjdk:8-jdk-alpine
2 |
3 | VOLUME /tmp
4 |
5 | # Set timezone
6 | ENV TIME_ZONE Asia/Taipei
7 | RUN apk --no-cache add \
8 | tzdata \
9 | && echo "${TIME_ZONE}" > /etc/timezone \
10 | && ln -sf /usr/share/zoneinfo/${TIME_ZONE} /etc/localtime
11 |
12 | RUN mkdir /msdemo
13 | WORKDIR /msdemo
14 | COPY ./target/auth-service.jar ./auth-service.jar
15 |
16 | CMD ["java", "-Djava.security.egd=file:/dev/./urandom", "-jar", "auth-service.jar"]
--------------------------------------------------------------------------------
/auth-service/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | auth-service
7 | auth-service
8 | Spring Cloud Microservices Demo
9 |
10 |
11 | demo.ms
12 | ms-demo
13 | 0.0.1
14 |
15 |
16 |
17 |
18 | org.springframework.boot
19 | spring-boot-starter-web
20 |
21 |
22 |
23 | org.springframework.boot
24 | spring-boot-starter-actuator
25 |
26 |
27 |
28 | org.springframework.cloud
29 | spring-cloud-starter-config
30 |
31 |
32 | org.springframework.cloud
33 | spring-cloud-starter-bus-amqp
34 |
35 |
36 |
37 | org.springframework.cloud
38 | spring-cloud-starter-netflix-eureka-client
39 |
40 |
41 |
42 | org.springframework.cloud
43 | spring-cloud-starter-netflix-hystrix
44 |
45 |
46 | org.springframework.cloud
47 | spring-cloud-netflix-hystrix-stream
48 |
49 |
50 | org.springframework.cloud
51 | spring-cloud-starter-stream-rabbit
52 |
53 |
54 |
55 | org.springframework.cloud
56 | spring-cloud-starter-zipkin
57 |
58 |
59 | org.springframework.amqp
60 | spring-rabbit
61 |
62 |
63 |
64 | org.springframework.boot
65 | spring-boot-starter-test
66 | test
67 |
68 |
69 |
70 |
71 | ${project.name}
72 |
73 |
74 | org.springframework.boot
75 | spring-boot-maven-plugin
76 |
77 |
78 |
79 |
80 |
--------------------------------------------------------------------------------
/auth-service/src/main/java/demo/ms/AuthServiceApplication.java:
--------------------------------------------------------------------------------
1 | package demo.ms;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 | import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
6 |
7 | @SpringBootApplication
8 | @EnableCircuitBreaker
9 | public class AuthServiceApplication {
10 |
11 | public static void main(String[] args) {
12 | SpringApplication.run(AuthServiceApplication.class, args);
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/auth-service/src/main/java/demo/ms/domain/User.java:
--------------------------------------------------------------------------------
1 | package demo.ms.domain;
2 |
3 | import java.util.Map;
4 |
5 | public class User {
6 |
7 | private String username;
8 |
9 | private String password;
10 |
11 | private String email;
12 |
13 | private Map extra;
14 |
15 | public User() {
16 | }
17 |
18 | public User(String username) {
19 | this.username = username;
20 | }
21 |
22 | public String getUsername() {
23 | return username;
24 | }
25 |
26 | public void setUsername(String username) {
27 | this.username = username;
28 | }
29 |
30 | public String getPassword() {
31 | return password;
32 | }
33 |
34 | public void setPassword(String password) {
35 | this.password = password;
36 | }
37 |
38 | public String getEmail() {
39 | return email;
40 | }
41 |
42 | public void setEmail(String email) {
43 | this.email = email;
44 | }
45 |
46 | public Map getExtra() {
47 | return extra;
48 | }
49 |
50 | public void setExtra(Map extra) {
51 | this.extra = extra;
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/auth-service/src/main/java/demo/ms/service/UserService.java:
--------------------------------------------------------------------------------
1 | package demo.ms.service;
2 |
3 | import java.util.List;
4 | import java.util.Map;
5 | import java.util.stream.Collectors;
6 | import java.util.stream.Stream;
7 |
8 | import javax.annotation.PostConstruct;
9 |
10 | import org.springframework.stereotype.Service;
11 |
12 | import demo.ms.domain.User;
13 | import demo.ms.util.IPUtils;
14 |
15 | @Service
16 | public class UserService {
17 |
18 | private List users;
19 |
20 | @PostConstruct
21 | public void createUsers() {
22 | users = Stream.of(
23 | new User("albert"),
24 | new User("alex"),
25 | new User("andrew"))
26 | .collect(Collectors.toList());
27 | }
28 |
29 | public List getUsers() {
30 | return users;
31 | }
32 |
33 | public User getUser(String username) {
34 | return users.stream()
35 | .filter(user -> user.getUsername().equals(username))
36 | .findFirst()
37 | .map(this::addExtraInfo)
38 | .orElseThrow(() -> new IllegalArgumentException("Can not find user " + username));
39 | }
40 |
41 | private User addExtraInfo(User user) {
42 | // add service instance info to demo load balancing
43 | Map extra = IPUtils.getHostnameAndAddress();
44 | user.setExtra(extra);
45 | return user;
46 | }
47 |
48 | public User createUser(User user) {
49 | users.add(user);
50 | return user;
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/auth-service/src/main/java/demo/ms/util/IPUtils.java:
--------------------------------------------------------------------------------
1 | package demo.ms.util;
2 |
3 | import java.net.InetAddress;
4 | import java.net.UnknownHostException;
5 | import java.util.LinkedHashMap;
6 | import java.util.Map;
7 |
8 | import org.slf4j.Logger;
9 | import org.slf4j.LoggerFactory;
10 |
11 | public class IPUtils {
12 |
13 | private static final Logger log = LoggerFactory.getLogger(IPUtils.class);
14 |
15 | public static Map getHostnameAndAddress() {
16 | Map info = new LinkedHashMap<>();
17 | try {
18 | InetAddress inetAddress = InetAddress.getLocalHost();
19 | String serverAddress = inetAddress.getHostAddress();
20 | String serverName = inetAddress.getHostName();
21 |
22 | info.put("authServiceAddress", serverAddress);
23 | info.put("authServiceName", serverName);
24 | } catch (UnknownHostException e) {
25 | log.error(e.getMessage(), e);
26 | }
27 | return info;
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/auth-service/src/main/java/demo/ms/web/controller/ControllerExceptionHandler.java:
--------------------------------------------------------------------------------
1 | package demo.ms.web.controller;
2 |
3 | import org.springframework.http.HttpHeaders;
4 | import org.springframework.http.HttpStatus;
5 | import org.springframework.http.MediaType;
6 | import org.springframework.http.ResponseEntity;
7 | import org.springframework.web.bind.annotation.ControllerAdvice;
8 | import org.springframework.web.bind.annotation.ExceptionHandler;
9 |
10 | @ControllerAdvice
11 | public class ControllerExceptionHandler {
12 |
13 | @ExceptionHandler(Exception.class)
14 | public ResponseEntity handleException(Exception e) {
15 | String body = e.getMessage();
16 |
17 | HttpHeaders headers = new HttpHeaders();
18 | headers.setContentType(MediaType.APPLICATION_JSON);
19 |
20 | HttpStatus status = HttpStatus.INTERNAL_SERVER_ERROR;
21 |
22 | ResponseEntity responseEntity = new ResponseEntity(body, headers, status);
23 | return responseEntity;
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/auth-service/src/main/java/demo/ms/web/controller/UserController.java:
--------------------------------------------------------------------------------
1 | package demo.ms.web.controller;
2 |
3 | import java.util.List;
4 | import java.util.Map;
5 |
6 | import org.slf4j.Logger;
7 | import org.slf4j.LoggerFactory;
8 | import org.springframework.beans.factory.annotation.Value;
9 | import org.springframework.cloud.context.config.annotation.RefreshScope;
10 | import org.springframework.web.bind.annotation.GetMapping;
11 | import org.springframework.web.bind.annotation.PathVariable;
12 | import org.springframework.web.bind.annotation.PostMapping;
13 | import org.springframework.web.bind.annotation.RequestBody;
14 | import org.springframework.web.bind.annotation.RestController;
15 |
16 | import demo.ms.domain.User;
17 | import demo.ms.service.UserService;
18 | import demo.ms.util.IPUtils;
19 |
20 | @RefreshScope
21 | @RestController
22 | public class UserController {
23 |
24 | private static final Logger log = LoggerFactory.getLogger(UserController.class);
25 |
26 | // to demo @RefreshScope
27 | private String welcomeMsg;
28 |
29 | private UserService userService;
30 |
31 | public UserController(UserService userService, @Value("${welcome.msg}") String welcomeMsg) {
32 | this.userService = userService;
33 | this.welcomeMsg = welcomeMsg;
34 | }
35 |
36 | @GetMapping({"", "/"})
37 | public Map hello() {
38 | // add service instance info to show which service instance is refreshed
39 | Map info = IPUtils.getHostnameAndAddress();
40 | info.put("welcomeMessage", welcomeMsg);
41 | return info;
42 | }
43 |
44 | @GetMapping("/users")
45 | public List getUsers() {
46 | return userService.getUsers();
47 | }
48 |
49 | @GetMapping("/users/{username}")
50 | public User getUser(@PathVariable String username) {
51 | // log is used to demo sleuth: add span and trace IDs to log
52 | log.debug("Get user {}", username);
53 | return userService.getUser(username);
54 | }
55 |
56 | @PostMapping("/users")
57 | public User createUser(@RequestBody User user) {
58 | log.info("Create user {}", user);
59 | return userService.createUser(user);
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/auth-service/src/main/resources/bootstrap.yml:
--------------------------------------------------------------------------------
1 | CONFIG_SERVER_URL: http://127.0.0.1:8888
2 |
3 | server:
4 | port: 9000
5 |
6 | spring:
7 | application:
8 | name: auth-service
9 | main:
10 | banner-mode: "off"
11 | mvc:
12 | favicon.enabled: false
13 | cloud:
14 | config:
15 | uri: ${CONFIG_SERVER_URL}
16 | fail-fast: true
17 |
--------------------------------------------------------------------------------
/auth-service/src/main/resources/logback-spring.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/auth-service/src/test/java/demo/ms/AuthServiceApplicationTests.java:
--------------------------------------------------------------------------------
1 | package demo.ms;
2 |
3 | import org.junit.Test;
4 | import org.junit.runner.RunWith;
5 | import org.springframework.boot.test.context.SpringBootTest;
6 | import org.springframework.test.context.junit4.SpringRunner;
7 |
8 | @RunWith(SpringRunner.class)
9 | @SpringBootTest
10 | public class AuthServiceApplicationTests {
11 |
12 | @Test
13 | public void contextLoads() {
14 | }
15 |
16 | }
17 |
--------------------------------------------------------------------------------
/build-images.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -e
4 |
5 | docker build -t 192.168.99.100:5000/config-server ./config-server
6 | docker build -t 192.168.99.100:5000/service-registry ./service-registry
7 | docker build -t 192.168.99.100:5000/turbine-server ./turbine-server
8 | docker build -t 192.168.99.100:5000/monitor-dashboard ./monitor-dashboard
9 | docker build -t 192.168.99.100:5000/auth-service ./auth-service
10 | docker build -t 192.168.99.100:5000/account-service ./account-service
11 | docker build -t 192.168.99.100:5000/cloud-gateway ./cloud-gateway
12 |
13 | docker rmi $(docker images -f "dangling=true" -q)
14 |
--------------------------------------------------------------------------------
/cloud-gateway/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM openjdk:8-jdk-alpine
2 |
3 | VOLUME /tmp
4 |
5 | # Set timezone
6 | ENV TIME_ZONE Asia/Taipei
7 | RUN apk --no-cache add \
8 | tzdata \
9 | && echo "${TIME_ZONE}" > /etc/timezone \
10 | && ln -sf /usr/share/zoneinfo/${TIME_ZONE} /etc/localtime
11 |
12 | RUN mkdir /msdemo
13 | WORKDIR /msdemo
14 | COPY ./target/cloud-gateway.jar ./cloud-gateway.jar
15 |
16 | CMD ["java", "-Djava.security.egd=file:/dev/./urandom", "-jar", "cloud-gateway.jar"]
--------------------------------------------------------------------------------
/cloud-gateway/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | cloud-gateway
7 | cloud-gateway
8 | Spring Cloud Microservices Demo
9 |
10 |
11 | demo.ms
12 | ms-demo
13 | 0.0.1
14 |
15 |
16 |
17 |
18 | org.springframework.boot
19 | spring-boot-starter-actuator
20 |
21 |
22 |
23 | org.springframework.cloud
24 | spring-cloud-starter-config
25 |
26 |
27 | org.springframework.cloud
28 | spring-cloud-starter-bus-amqp
29 |
30 |
31 |
32 | org.springframework.cloud
33 | spring-cloud-starter-netflix-eureka-client
34 |
35 |
36 |
37 | org.springframework.cloud
38 | spring-cloud-starter-netflix-hystrix
39 |
40 |
41 | org.springframework.cloud
42 | spring-cloud-netflix-hystrix-stream
43 |
44 |
45 | org.springframework.cloud
46 | spring-cloud-starter-stream-rabbit
47 |
48 |
49 |
50 | org.springframework.cloud
51 | spring-cloud-starter-zipkin
52 |
53 |
54 | org.springframework.amqp
55 | spring-rabbit
56 |
57 |
58 |
59 | org.springframework.cloud
60 | spring-cloud-starter-gateway
61 |
62 |
63 |
64 | org.springframework.boot
65 | spring-boot-starter-test
66 | test
67 |
68 |
69 |
70 |
71 | ${project.name}
72 |
73 |
74 | org.springframework.boot
75 | spring-boot-maven-plugin
76 |
77 |
78 |
79 |
80 |
--------------------------------------------------------------------------------
/cloud-gateway/src/main/java/demo/ms/CloudGatewayApplication.java:
--------------------------------------------------------------------------------
1 | package demo.ms;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 | import org.springframework.cloud.gateway.route.RouteLocator;
6 | import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
7 | import org.springframework.context.annotation.Bean;
8 | import org.springframework.web.bind.annotation.GetMapping;
9 | import org.springframework.web.bind.annotation.RestController;
10 |
11 | import reactor.core.publisher.Mono;
12 |
13 | @SpringBootApplication
14 | public class CloudGatewayApplication {
15 |
16 | public static void main(String[] args) {
17 | SpringApplication.run(CloudGatewayApplication.class, args);
18 | }
19 |
20 | @Bean
21 | public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
22 | return builder.routes()
23 | // shortcut for index page
24 | // it may be better to use a UI microservice
25 | .route("index", p -> p.path("/").or().path("/index.html")
26 | .filters(f -> f.setPath("/static/index.html"))
27 | .uri("lb://cloud-gateway"))
28 | // set larger order to put this route to lower priority, so it wouldn't override other routes
29 | .route("not_found", p -> p.order(1000).path("/static/**").negate()
30 | .filters(f -> f.setPath("/not-found"))
31 | .uri("lb://cloud-gateway"))
32 | .build();
33 | }
34 |
35 | @RestController
36 | static class WebController {
37 |
38 | @GetMapping("/not-found")
39 | public Mono notFound() {
40 | return Mono.just("Not found!");
41 | }
42 |
43 | @GetMapping("/auth-service-fallback")
44 | public Mono authServiceFallback() {
45 | return Mono.just("Auth Service Unavailabe!");
46 | }
47 |
48 | @GetMapping("/account-service-fallback")
49 | public Mono accountServiceFallback() {
50 | return Mono.just("Account Service Unavailabe!");
51 | }
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/cloud-gateway/src/main/resources/bootstrap.yml:
--------------------------------------------------------------------------------
1 | CONFIG_SERVER_URL: http://127.0.0.1:8888
2 |
3 | server:
4 | port: 8080
5 |
6 | spring:
7 | application:
8 | name: cloud-gateway
9 | main:
10 | banner-mode: "off"
11 | mvc:
12 | favicon.enabled: false
13 | cloud:
14 | config:
15 | uri: ${CONFIG_SERVER_URL}
16 | fail-fast: true
17 |
--------------------------------------------------------------------------------
/cloud-gateway/src/main/resources/logback-spring.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/cloud-gateway/src/main/resources/static/index.html:
--------------------------------------------------------------------------------
1 | Hello World!
--------------------------------------------------------------------------------
/cloud-gateway/src/test/java/demo/ms/CloudGatewayApplicationTests.java:
--------------------------------------------------------------------------------
1 | package demo.ms;
2 |
3 | import org.junit.Test;
4 | import org.junit.runner.RunWith;
5 | import org.springframework.boot.test.context.SpringBootTest;
6 | import org.springframework.test.context.junit4.SpringRunner;
7 |
8 | @RunWith(SpringRunner.class)
9 | @SpringBootTest
10 | public class CloudGatewayApplicationTests {
11 |
12 | @Test
13 | public void contextLoads() {
14 | }
15 |
16 | }
17 |
--------------------------------------------------------------------------------
/config-server/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM openjdk:8-jdk-alpine
2 |
3 | VOLUME /tmp
4 |
5 | # Set timezone
6 | ENV TIME_ZONE Asia/Taipei
7 | RUN apk --no-cache add \
8 | tzdata \
9 | && echo "${TIME_ZONE}" > /etc/timezone \
10 | && ln -sf /usr/share/zoneinfo/${TIME_ZONE} /etc/localtime
11 |
12 | RUN mkdir /msdemo
13 | WORKDIR /msdemo
14 | COPY ./target/config-server.jar ./config-server.jar
15 |
16 | CMD ["java", "-Djava.security.egd=file:/dev/./urandom", "-jar", "config-server.jar"]
--------------------------------------------------------------------------------
/config-server/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | config-server
7 | config-server
8 | Spring Cloud Microservices Demo
9 |
10 |
11 | demo.ms
12 | ms-demo
13 | 0.0.1
14 |
15 |
16 |
17 |
18 | org.springframework.boot
19 | spring-boot-starter-actuator
20 |
21 |
22 |
23 |
24 | org.springframework.cloud
25 | spring-cloud-config-server
26 |
27 |
28 |
29 |
30 | org.springframework.cloud
31 | spring-cloud-config-monitor
32 |
33 |
34 |
35 |
36 | org.springframework.cloud
37 | spring-cloud-starter-bus-amqp
38 |
39 |
40 |
41 | org.springframework.boot
42 | spring-boot-starter-test
43 | test
44 |
45 |
46 |
47 |
48 | ${project.name}
49 |
50 |
51 | org.springframework.boot
52 | spring-boot-maven-plugin
53 |
54 |
55 |
56 |
57 |
--------------------------------------------------------------------------------
/config-server/src/main/java/demo/ms/ConfigServerApplication.java:
--------------------------------------------------------------------------------
1 | package demo.ms;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 | import org.springframework.cloud.config.server.EnableConfigServer;
6 | import org.springframework.stereotype.Controller;
7 | import org.springframework.web.bind.annotation.GetMapping;
8 |
9 | @SpringBootApplication
10 | @EnableConfigServer
11 | public class ConfigServerApplication {
12 |
13 | public static void main(String[] args) {
14 | SpringApplication.run(ConfigServerApplication.class, args);
15 | }
16 |
17 | @Controller
18 | static class WebController {
19 |
20 | @GetMapping({"", "/"})
21 | public String index() {
22 | return "redirect:/health";
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/config-server/src/main/resources/application.yml:
--------------------------------------------------------------------------------
1 | ### Default configuration, these properties should be set with environment variables in docker/Kubernetes.
2 | APP_CONFIG_DIR: /Users/yenchu/git/microservices-demo/config-server/src/main/resources/shared
3 | APP_LOGGING_DIR: /Users/yenchu/log/microservices-demo
4 | SERVICE_REGISTRY_URL: http://127.0.0.1:8761/eureka/
5 | RABBITMQ_SERVICE_HOST: localhost
6 | RABBITMQ_SERVICE_PORT: 5672
7 | RABBITMQ_SERVICE_USERNAME: admin
8 | RABBITMQ_SERVICE_PASSWORD: amqp
9 |
10 | logging:
11 | file: ${APP_LOGGING_DIR}/${spring.application.name}.log
12 | level:
13 | demo: DEBUG
14 |
15 | spring:
16 | rabbitmq:
17 | host: ${RABBITMQ_SERVICE_HOST}
18 | port: ${RABBITMQ_SERVICE_PORT}
19 | username: ${RABBITMQ_SERVICE_USERNAME}
20 | password: ${RABBITMQ_SERVICE_PASSWORD}
21 | cloud:
22 | config:
23 | server:
24 | native:
25 | search-locations: file:${APP_CONFIG_DIR}
26 | # To override downstream services configuration
27 | overrides:
28 | APP_LOGGING_DIR: ${APP_LOGGING_DIR}
29 | SERVICE_REGISTRY_URL: ${SERVICE_REGISTRY_URL}
30 | spring.rabbitmq.host: ${RABBITMQ_SERVICE_HOST}
31 | spring.rabbitmq.port: ${RABBITMQ_SERVICE_PORT}
32 | spring.rabbitmq.username: ${RABBITMQ_SERVICE_USERNAME}
33 | spring.rabbitmq.password: ${RABBITMQ_SERVICE_PASSWORD}
34 | profiles:
35 | # Using local filesystem for demo
36 | active: native
37 |
--------------------------------------------------------------------------------
/config-server/src/main/resources/bootstrap.yml:
--------------------------------------------------------------------------------
1 | server:
2 | port: 8888
3 |
4 | spring:
5 | application:
6 | name: config-server
7 | main:
8 | banner-mode: "off"
9 | mvc:
10 | favicon.enabled: false
11 |
--------------------------------------------------------------------------------
/config-server/src/main/resources/logback-spring.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/config-server/src/main/resources/shared/account-service.yml:
--------------------------------------------------------------------------------
1 | eureka:
2 | instance:
3 | metadata-map:
4 | # The turbine stream cluster it should be aggragated to
5 | cluster: USERS
6 |
7 | feign:
8 | client:
9 | config:
10 | default:
11 | loggerLevel: basic
12 | # To enable Hystrix in Feign
13 | hystrix:
14 | enabled: true
15 |
16 | # Enable retry for Feign client
17 | auth-service:
18 | ribbon:
19 | MaxAutoRetries: 1
20 | MaxAutoRetriesNextServer: 1
21 | ReadTimeout: 1000
22 |
23 | # Make sure the timeout of hystrix is longer then the retry of feign client
24 | hystrix:
25 | command.default.execution.isolation.thread.timeoutInMilliseconds: 5000
26 |
--------------------------------------------------------------------------------
/config-server/src/main/resources/shared/api-gateway.yml:
--------------------------------------------------------------------------------
1 | zuul:
2 | retryable: true
3 | ignoredServices: '*'
4 | host:
5 | connect-timeout-millis: 20000
6 | socket-timeout-millis: 20000
7 | routes:
8 | auth-service:
9 | path: /auth/**
10 | account-service:
11 | path: /acct/**
12 | static:
13 | path: /static/**
14 |
15 | ribbon:
16 | MaxAutoRetries: 1
17 | MaxAutoRetriesNextServer: 1
18 | ReadTimeout: 1000
19 |
20 | hystrix:
21 | command.default.execution.isolation.thread.timeoutInMilliseconds: 5000
22 |
--------------------------------------------------------------------------------
/config-server/src/main/resources/shared/application.yml:
--------------------------------------------------------------------------------
1 | logging:
2 | file: ${APP_LOGGING_DIR}/${spring.application.name}.log
3 | level:
4 | demo: DEBUG
5 |
6 | # eureka.client.healthcheck.enabled=true should only be set in application.yml
7 | eureka:
8 | instance:
9 | prefer-ip-address: true
10 | client:
11 | healthcheck:
12 | enabled: true
13 | serviceUrl:
14 | defaultZone: ${SERVICE_REGISTRY_URL}
15 |
16 | # Integrating rabbitmq for turbine stream and push refresh config
17 | # Being overrided by config server
18 | spring:
19 | rabbitmq:
20 | host: ${RABBITMQ_SERVICE_HOST}
21 | port: ${RABBITMQ_SERVICE_PORT}
22 | username: ${RABBITMQ_SERVICE_USERNAME}
23 | password: ${RABBITMQ_SERVICE_PASSWORD}
24 | sleuth:
25 | sampler:
26 | # Recording all spans for demo
27 | probability: 1.0
28 |
--------------------------------------------------------------------------------
/config-server/src/main/resources/shared/auth-service.yml:
--------------------------------------------------------------------------------
1 | # To demo @RefreshScope
2 | welcome.msg: Hello!
3 |
4 | eureka:
5 | instance:
6 | metadata-map:
7 | # The turbine stream cluster it should be aggragated to
8 | cluster: USERS
9 |
--------------------------------------------------------------------------------
/config-server/src/main/resources/shared/cloud-gateway.yml:
--------------------------------------------------------------------------------
1 | spring:
2 | cloud:
3 | gateway:
4 | discovery:
5 | locator:
6 | enabled: true
7 | routes:
8 | - id: auth_service
9 | uri: lb://auth-service
10 | predicates:
11 | - Path=/auth/**
12 | filters:
13 | # trim prifix path /auth
14 | - RewritePath=/auth/(?.*), /$\{segment}
15 | # retry 2 times for http status NOT_FOUND, INTERNAL_SERVER_ERROR
16 | - name: Retry
17 | args:
18 | retries: 2
19 | statuses: NOT_FOUND, INTERNAL_SERVER_ERROR
20 | # set fallback uri if the backend service cannot be connected
21 | - name: Hystrix
22 | args:
23 | name: auth-api
24 | fallbackUri: forward:/auth-service-fallback
25 | - id: account_service
26 | uri: lb://account-service
27 | predicates:
28 | - Path=/acct/**
29 | filters:
30 | - RewritePath=/acct/(?.*), /$\{segment}
31 | - name: Retry
32 | args:
33 | retries: 2
34 | statuses: NOT_FOUND, INTERNAL_SERVER_ERROR
35 | - name: Hystrix
36 | args:
37 | name: account-api
38 | fallbackUri: forward:/account-service-fallback
39 | # static resources path pattern
40 | webflux.static-path-pattern: /static/**
41 |
42 | # config global Hystrix timeout
43 | hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds: 5000
44 |
45 | # just for debug
46 | logging:
47 | level:
48 | org.springframework.cloud.gateway: DEBUG
49 | org.springframework.http.server.reactive: DEBUG
50 | org.springframework.web.reactive: DEBUG
51 |
52 | # demo actuator-related urls
53 | management.endpoints.web.exposure.include: '*'
54 |
--------------------------------------------------------------------------------
/config-server/src/main/resources/shared/monitor-dashboard.yml:
--------------------------------------------------------------------------------
1 | # for demo
2 | turbine:
3 | aggregator:
4 | clusterConfig: USERS
--------------------------------------------------------------------------------
/config-server/src/main/resources/shared/service-registry.yml:
--------------------------------------------------------------------------------
1 | eureka:
2 | client:
3 | # Disable the client side behaviour in standalone mode
4 | registerWithEureka: false
5 | fetchRegistry: false
6 | serviceUrl:
7 | defaultZone: http://127.0.0.1:8761/eureka/
8 |
--------------------------------------------------------------------------------
/config-server/src/main/resources/shared/turbine-server.yml:
--------------------------------------------------------------------------------
1 | turbine:
2 | aggregator:
3 | clusterConfig: USERS
4 | appConfig: account-service,auth-service
5 | # To find which cluster the apps should be aggragated to
6 | clusterNameExpression: metadata['cluster']
7 |
--------------------------------------------------------------------------------
/config-server/src/test/java/demo/ms/ConfigServiceApplicationTests.java:
--------------------------------------------------------------------------------
1 | package demo.ms;
2 |
3 | import org.junit.Test;
4 | import org.junit.runner.RunWith;
5 | import org.springframework.boot.test.context.SpringBootTest;
6 | import org.springframework.test.context.junit4.SpringRunner;
7 |
8 | @RunWith(SpringRunner.class)
9 | @SpringBootTest
10 | public class ConfigServiceApplicationTests {
11 |
12 | @Test
13 | public void contextLoads() {
14 | }
15 |
16 | }
17 |
--------------------------------------------------------------------------------
/deploy-docker.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -e
4 |
5 | export APP_CONFIG_DIR=/Users/yenchu/git/microservices-demo/config-server/src/main/resources/shared
6 | export APP_LOGGING_DIR=/Users/yenchu/log/microservices-demo
7 |
8 | docker-compose up -d
9 |
--------------------------------------------------------------------------------
/deploy-kubernetes.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -e
4 |
5 | kubectl create -f kubernetes/config-secret.yaml
6 |
7 | kubectl create -f kubernetes/env-configmap.yaml
8 |
9 | kubectl create -f kubernetes/config-pv.yaml
10 |
11 | kubectl create -f kubernetes/log-pv.yaml
12 |
13 | kubectl create -f kubernetes/rabbitmq.yaml
14 |
15 | kubectl create -f kubernetes/zipkin.yaml
16 |
17 | kubectl create -f kubernetes/config-server.yaml
18 |
19 | kubectl create -f kubernetes/service-registry.yaml
20 |
21 | kubectl create -f kubernetes/turbine-server.yaml
22 |
23 | kubectl create -f kubernetes/monitor-dashboard.yaml
24 |
25 | kubectl create -f kubernetes/auth-service.yaml
26 |
27 | kubectl create -f kubernetes/account-service.yaml
28 |
29 | kubectl create -f kubernetes/cloud-gateway.yaml
30 |
--------------------------------------------------------------------------------
/docker-compose.yml:
--------------------------------------------------------------------------------
1 | version: '2'
2 | services:
3 | rabbitmq:
4 | image: 192.168.99.100:5000/rabbitmq:management
5 | container_name: rabbitmq
6 | hostname: rabbitmq
7 | ports:
8 | - "5672:5672"
9 | - "15672:15672"
10 | environment:
11 | RABBITMQ_DEFAULT_USER: admin
12 | RABBITMQ_DEFAULT_PASS: amqp
13 |
14 | zipkin:
15 | image: 192.168.99.100:5000/zipkin
16 | container_name: zipkin
17 | hostname: zipkin
18 | depends_on:
19 | - rabbitmq
20 | ports:
21 | - "9411:9411"
22 | environment:
23 | RABBIT_ADDRESSES: rabbitmq
24 | RABBIT_USER: admin
25 | RABBIT_PASSWORD: amqp
26 |
27 | config-server:
28 | image: 192.168.99.100:5000/config-server
29 | container_name: config-server
30 | hostname: config-server
31 | restart: always
32 | depends_on:
33 | - rabbitmq
34 | ports:
35 | - "8888:8888"
36 | volumes:
37 | - $APP_CONFIG_DIR:/etc/msdemo
38 | - $APP_LOGGING_DIR:/var/log/msdemo
39 | environment:
40 | APP_CONFIG_DIR: /etc/msdemo
41 | APP_LOGGING_DIR: /var/log/msdemo
42 | SERVICE_REGISTRY_URL: http://service-registry:8761/eureka/
43 | RABBITMQ_SERVICE_HOST: rabbitmq
44 | RABBITMQ_SERVICE_PORT: 5672
45 | RABBITMQ_SERVICE_USERNAME: admin
46 | RABBITMQ_SERVICE_PASSWORD: amqp
47 |
48 | service-registry:
49 | image: 192.168.99.100:5000/service-registry
50 | container_name: service-registry
51 | hostname: service-registry
52 | restart: always
53 | depends_on:
54 | - config-server
55 | ports:
56 | - "8761:8761"
57 | volumes:
58 | - $APP_LOGGING_DIR:/var/log/msdemo
59 | environment:
60 | CONFIG_SERVER_URL: http://config-server:8888
61 |
62 | turbine-server:
63 | image: 192.168.99.100:5000/turbine-server
64 | container_name: turbine-server
65 | hostname: turbine-server
66 | restart: always
67 | depends_on:
68 | - service-registry
69 | ports:
70 | - "8989:8989"
71 | volumes:
72 | - $APP_LOGGING_DIR:/var/log/msdemo
73 | environment:
74 | CONFIG_SERVER_URL: http://config-server:8888
75 |
76 | monitor-dashboard:
77 | image: 192.168.99.100:5000/monitor-dashboard
78 | container_name: monitor-dashboard
79 | hostname: monitor-dashboard
80 | restart: always
81 | depends_on:
82 | - service-registry
83 | - turbine-server
84 | ports:
85 | - "7979:7979"
86 | volumes:
87 | - $APP_LOGGING_DIR:/var/log/msdemo
88 | environment:
89 | CONFIG_SERVER_URL: http://config-server:8888
90 |
91 | auth-service:
92 | image: 192.168.99.100:5000/auth-service
93 | container_name: auth-service
94 | hostname: auth-service
95 | restart: always
96 | depends_on:
97 | - service-registry
98 | ports:
99 | - "9000:9000"
100 | volumes:
101 | - $APP_LOGGING_DIR:/var/log/msdemo
102 | environment:
103 | CONFIG_SERVER_URL: http://config-server:8888
104 |
105 | account-service:
106 | image: 192.168.99.100:5000/account-service
107 | container_name: account-service
108 | hostname: account-service
109 | restart: always
110 | depends_on:
111 | - service-registry
112 | ports:
113 | - "9010:9010"
114 | volumes:
115 | - $APP_LOGGING_DIR:/var/log/msdemo
116 | environment:
117 | CONFIG_SERVER_URL: http://config-server:8888
118 |
119 | api-gateway:
120 | image: 192.168.99.100:5000/cloud-gateway
121 | container_name: cloud-gateway
122 | hostname: cloud-gateway
123 | restart: always
124 | depends_on:
125 | - service-registry
126 | ports:
127 | - "8080:8080"
128 | volumes:
129 | - $APP_LOGGING_DIR:/var/log/msdemo
130 | environment:
131 | CONFIG_SERVER_URL: http://config-server:8888
132 |
--------------------------------------------------------------------------------
/docker/setup-docker-images.txt:
--------------------------------------------------------------------------------
1 | ### RabbitMQ image
2 | docker pull rabbitmq:management
3 | docker tag rabbitmq:management 192.168.99.100:5000/rabbitmq:management
4 | docker push 192.168.99.100:5000/rabbitmq:management
5 |
6 | ### Zipkin image
7 | docker pull openzipkin/zipkin
8 | docker tag openzipkin/zipkin 192.168.99.100:5000/zipkin
9 | docker push 192.168.99.100:5000/zipkin
10 |
--------------------------------------------------------------------------------
/kubernetes/account-service.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Service
3 | metadata:
4 | name: account-service
5 | labels:
6 | app: account-service
7 | spec:
8 | type: NodePort
9 | ports:
10 | - port: 9010
11 | selector:
12 | app: account-service
13 | ---
14 | apiVersion: apps/v1beta2
15 | kind: Deployment
16 | metadata:
17 | name: account-service
18 | spec:
19 | replicas: 1
20 | selector:
21 | matchLabels:
22 | app: account-service
23 | template:
24 | metadata:
25 | labels:
26 | app: account-service
27 | spec:
28 | containers:
29 | - name: account-service
30 | image: 192.168.99.100:5000/account-service
31 | ports:
32 | - containerPort: 9010
33 | env:
34 | - name: CONFIG_SERVER_URL
35 | valueFrom:
36 | configMapKeyRef:
37 | name: env-config
38 | key: config-server-url
39 | volumeMounts:
40 | - name: log-vol
41 | mountPath: /var/log/msdemo
42 | volumes:
43 | - name: log-vol
44 | persistentVolumeClaim:
45 | claimName: log-claim
46 |
--------------------------------------------------------------------------------
/kubernetes/api-gateway.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Service
3 | metadata:
4 | name: api-gateway
5 | labels:
6 | app: api-gateway
7 | spec:
8 | type: NodePort
9 | ports:
10 | - port: 8080
11 | selector:
12 | app: api-gateway
13 | ---
14 | apiVersion: apps/v1beta2
15 | kind: Deployment
16 | metadata:
17 | name: api-gateway
18 | spec:
19 | replicas: 1
20 | selector:
21 | matchLabels:
22 | app: api-gateway
23 | template:
24 | metadata:
25 | labels:
26 | app: api-gateway
27 | spec:
28 | containers:
29 | - name: api-gateway
30 | image: 192.168.99.100:5000/api-gateway
31 | ports:
32 | - containerPort: 8080
33 | env:
34 | - name: CONFIG_SERVER_URL
35 | valueFrom:
36 | configMapKeyRef:
37 | name: env-config
38 | key: config-server-url
39 | volumeMounts:
40 | - name: log-vol
41 | mountPath: /var/log/msdemo
42 | volumes:
43 | - name: log-vol
44 | persistentVolumeClaim:
45 | claimName: log-claim
46 |
--------------------------------------------------------------------------------
/kubernetes/auth-service.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Service
3 | metadata:
4 | name: auth-service
5 | labels:
6 | app: auth-service
7 | spec:
8 | type: NodePort
9 | ports:
10 | - port: 9000
11 | selector:
12 | app: auth-service
13 | ---
14 | apiVersion: apps/v1beta2
15 | kind: Deployment
16 | metadata:
17 | name: auth-service
18 | spec:
19 | replicas: 1
20 | selector:
21 | matchLabels:
22 | app: auth-service
23 | template:
24 | metadata:
25 | labels:
26 | app: auth-service
27 | spec:
28 | containers:
29 | - name: auth-service
30 | image: 192.168.99.100:5000/auth-service
31 | ports:
32 | - containerPort: 9000
33 | env:
34 | - name: CONFIG_SERVER_URL
35 | valueFrom:
36 | configMapKeyRef:
37 | name: env-config
38 | key: config-server-url
39 | volumeMounts:
40 | - name: log-vol
41 | mountPath: /var/log/msdemo
42 | volumes:
43 | - name: log-vol
44 | persistentVolumeClaim:
45 | claimName: log-claim
46 |
--------------------------------------------------------------------------------
/kubernetes/cloud-gateway.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Service
3 | metadata:
4 | name: cloud-gateway
5 | labels:
6 | app: cloud-gateway
7 | spec:
8 | type: NodePort
9 | ports:
10 | - port: 8080
11 | selector:
12 | app: cloud-gateway
13 | ---
14 | apiVersion: apps/v1beta2
15 | kind: Deployment
16 | metadata:
17 | name: cloud-gateway
18 | spec:
19 | replicas: 1
20 | selector:
21 | matchLabels:
22 | app: cloud-gateway
23 | template:
24 | metadata:
25 | labels:
26 | app: cloud-gateway
27 | spec:
28 | containers:
29 | - name: cloud-gateway
30 | image: 192.168.99.100:5000/cloud-gateway
31 | ports:
32 | - containerPort: 8080
33 | env:
34 | - name: CONFIG_SERVER_URL
35 | valueFrom:
36 | configMapKeyRef:
37 | name: env-config
38 | key: config-server-url
39 | volumeMounts:
40 | - name: log-vol
41 | mountPath: /var/log/msdemo
42 | volumes:
43 | - name: log-vol
44 | persistentVolumeClaim:
45 | claimName: log-claim
46 |
--------------------------------------------------------------------------------
/kubernetes/config-pv.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: PersistentVolume
3 | metadata:
4 | name: config-pv
5 | labels:
6 | type: local
7 | name: config-pv
8 | spec:
9 | storageClassName: standard
10 | capacity:
11 | storage: 1Gi
12 | accessModes:
13 | - ReadWriteOnce
14 | hostPath:
15 | path: "/Users/yenchu/git/microservices-demo/config-server/src/main/resources/shared"
16 | ---
17 | apiVersion: v1
18 | kind: PersistentVolumeClaim
19 | metadata:
20 | name: config-claim
21 | spec:
22 | storageClassName: standard
23 | selector:
24 | matchLabels:
25 | name: "config-pv"
26 | accessModes:
27 | - ReadWriteOnce
28 | resources:
29 | requests:
30 | storage: 1Gi
31 |
--------------------------------------------------------------------------------
/kubernetes/config-secret.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Secret
3 | metadata:
4 | name: config-secret
5 | type: Opaque
6 | data:
7 | rabbitmq-user: YWRtaW4=
8 | rabbitmq-pwd: YW1xcA==
9 |
--------------------------------------------------------------------------------
/kubernetes/config-server.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Service
3 | metadata:
4 | name: config-server
5 | labels:
6 | app: config-server
7 | spec:
8 | type: NodePort
9 | ports:
10 | - port: 8888
11 | selector:
12 | app: config-server
13 | ---
14 | apiVersion: apps/v1beta2
15 | kind: Deployment
16 | metadata:
17 | name: config-server
18 | spec:
19 | replicas: 1
20 | selector:
21 | matchLabels:
22 | app: config-server
23 | template:
24 | metadata:
25 | labels:
26 | app: config-server
27 | spec:
28 | containers:
29 | - name: config-server
30 | image: 192.168.99.100:5000/config-server
31 | ports:
32 | - containerPort: 8888
33 | env:
34 | - name: APP_CONFIG_DIR
35 | valueFrom:
36 | configMapKeyRef:
37 | name: env-config
38 | key: app-config-dir
39 | - name: APP_LOGGING_DIR
40 | valueFrom:
41 | configMapKeyRef:
42 | name: env-config
43 | key: app-logging-dir
44 | - name: SERVICE_REGISTRY_URL
45 | valueFrom:
46 | configMapKeyRef:
47 | name: env-config
48 | key: service-registry-url
49 | - name: RABBITMQ_SERVICE_HOST
50 | valueFrom:
51 | configMapKeyRef:
52 | name: env-config
53 | key: rabbitmq-host
54 | - name: RABBITMQ_SERVICE_USERNAME
55 | valueFrom:
56 | secretKeyRef:
57 | name: config-secret
58 | key: rabbitmq-user
59 | - name: RABBITMQ_SERVICE_PASSWORD
60 | valueFrom:
61 | secretKeyRef:
62 | name: config-secret
63 | key: rabbitmq-pwd
64 | volumeMounts:
65 | - name: config-vol
66 | mountPath: /etc/msdemo
67 | - name: log-vol
68 | mountPath: /var/log/msdemo
69 | volumes:
70 | - name: config-vol
71 | persistentVolumeClaim:
72 | claimName: config-claim
73 | - name: log-vol
74 | persistentVolumeClaim:
75 | claimName: log-claim
76 |
--------------------------------------------------------------------------------
/kubernetes/db-pv.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: PersistentVolume
3 | metadata:
4 | name: db-pv
5 | labels:
6 | type: local
7 | name: db-pv
8 | spec:
9 | storageClassName: standard
10 | capacity:
11 | storage: 5Gi
12 | accessModes:
13 | - ReadWriteOnce
14 | hostPath:
15 | path: "/Users/yenchu/data/mysql"
16 | ---
17 | apiVersion: v1
18 | kind: PersistentVolumeClaim
19 | metadata:
20 | name: db-claim
21 | spec:
22 | storageClassName: standard
23 | selector:
24 | matchLabels:
25 | name: "db-pv"
26 | accessModes:
27 | - ReadWriteOnce
28 | resources:
29 | requests:
30 | storage: 2Gi
31 |
32 |
--------------------------------------------------------------------------------
/kubernetes/env-configmap.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: ConfigMap
3 | metadata:
4 | name: env-config
5 | data:
6 | app-config-dir: "/etc/msdemo"
7 | app-logging-dir: "/var/log/msdemo"
8 | config-server-url: http://config-server:8888
9 | service-registry-url: http://service-registry:8761/eureka/
10 | rabbitmq-host: rabbitmq
11 |
--------------------------------------------------------------------------------
/kubernetes/log-pv.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: PersistentVolume
3 | metadata:
4 | name: log-pv
5 | labels:
6 | type: local
7 | name: log-pv
8 | spec:
9 | storageClassName: standard
10 | capacity:
11 | storage: 5Gi
12 | accessModes:
13 | - ReadWriteOnce
14 | hostPath:
15 | path: "/Users/yenchu/log/microservices-demo"
16 | ---
17 | apiVersion: v1
18 | kind: PersistentVolumeClaim
19 | metadata:
20 | name: log-claim
21 | spec:
22 | storageClassName: standard
23 | selector:
24 | matchLabels:
25 | name: "log-pv"
26 | accessModes:
27 | - ReadWriteOnce
28 | resources:
29 | requests:
30 | storage: 2Gi
31 |
--------------------------------------------------------------------------------
/kubernetes/monitor-dashboard.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Service
3 | metadata:
4 | name: monitor-dashboard
5 | labels:
6 | app: monitor-dashboard
7 | spec:
8 | type: NodePort
9 | ports:
10 | - port: 7979
11 | selector:
12 | app: monitor-dashboard
13 | ---
14 | apiVersion: apps/v1beta2
15 | kind: Deployment
16 | metadata:
17 | name: monitor-dashboard
18 | spec:
19 | replicas: 1
20 | selector:
21 | matchLabels:
22 | app: monitor-dashboard
23 | template:
24 | metadata:
25 | labels:
26 | app: monitor-dashboard
27 | spec:
28 | containers:
29 | - name: monitor-dashboard
30 | image: 192.168.99.100:5000/monitor-dashboard
31 | ports:
32 | - containerPort: 7979
33 | env:
34 | - name: CONFIG_SERVER_URL
35 | valueFrom:
36 | configMapKeyRef:
37 | name: env-config
38 | key: config-server-url
39 | volumeMounts:
40 | - name: log-vol
41 | mountPath: /var/log/msdemo
42 | volumes:
43 | - name: log-vol
44 | persistentVolumeClaim:
45 | claimName: log-claim
46 |
--------------------------------------------------------------------------------
/kubernetes/mysql.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Service
3 | metadata:
4 | name: mysql
5 | labels:
6 | app: mysql
7 | spec:
8 | type: NodePort
9 | ports:
10 | - port: 3306
11 | selector:
12 | app: mysql
13 | ---
14 | apiVersion: apps/v1beta1
15 | kind: Deployment
16 | metadata:
17 | name: mysql
18 | spec:
19 | replicas: 1
20 | template:
21 | metadata:
22 | labels:
23 | app: mysql
24 | spec:
25 | containers:
26 | - name: mysql
27 | image: 192.168.99.100:5000/mysql:5.7
28 | ports:
29 | - containerPort: 3306
30 | env:
31 | - name: MYSQL_ROOT_PASSWORD
32 | valueFrom:
33 | secretKeyRef:
34 | name: pwd-secret
35 | key: mysql-root-pwd
36 | volumeMounts:
37 | - name: db-vol
38 | mountPath: /var/lib/mysql
39 | volumes:
40 | - name: db-vol
41 | persistentVolumeClaim:
42 | claimName: db-claim
43 |
--------------------------------------------------------------------------------
/kubernetes/rabbitmq.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Service
3 | metadata:
4 | name: rabbitmq
5 | labels:
6 | app: rabbitmq
7 | spec:
8 | type: NodePort
9 | ports:
10 | - name: service
11 | port: 5672
12 | targetPort: 5672
13 | - name: management
14 | port: 15672
15 | targetPort: 15672
16 | selector:
17 | app: rabbitmq
18 | ---
19 | apiVersion: apps/v1beta1
20 | kind: Deployment
21 | metadata:
22 | name: rabbitmq
23 | spec:
24 | replicas: 1
25 | template:
26 | metadata:
27 | labels:
28 | app: rabbitmq
29 | spec:
30 | containers:
31 | - name: rabbitmq
32 | image: 192.168.99.100:5000/rabbitmq:management
33 | ports:
34 | - name: service
35 | containerPort: 5672
36 | - name: management
37 | containerPort: 15672
38 | env:
39 | - name: RABBITMQ_DEFAULT_USER
40 | valueFrom:
41 | secretKeyRef:
42 | name: config-secret
43 | key: rabbitmq-user
44 | - name: RABBITMQ_DEFAULT_PASS
45 | valueFrom:
46 | secretKeyRef:
47 | name: config-secret
48 | key: rabbitmq-pwd
49 |
--------------------------------------------------------------------------------
/kubernetes/service-registry.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Service
3 | metadata:
4 | name: service-registry
5 | labels:
6 | app: service-registry
7 | spec:
8 | type: NodePort
9 | ports:
10 | - port: 8761
11 | selector:
12 | app: service-registry
13 | ---
14 | apiVersion: apps/v1beta2
15 | kind: Deployment
16 | metadata:
17 | name: service-registry
18 | spec:
19 | replicas: 1
20 | selector:
21 | matchLabels:
22 | app: service-registry
23 | template:
24 | metadata:
25 | labels:
26 | app: service-registry
27 | spec:
28 | containers:
29 | - name: service-registry
30 | image: 192.168.99.100:5000/service-registry
31 | ports:
32 | - containerPort: 8761
33 | env:
34 | - name: CONFIG_SERVER_URL
35 | valueFrom:
36 | configMapKeyRef:
37 | name: env-config
38 | key: config-server-url
39 | volumeMounts:
40 | - name: log-vol
41 | mountPath: /var/log/msdemo
42 | volumes:
43 | - name: log-vol
44 | persistentVolumeClaim:
45 | claimName: log-claim
46 |
--------------------------------------------------------------------------------
/kubernetes/turbine-server.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Service
3 | metadata:
4 | name: turbine-server
5 | labels:
6 | app: turbine-server
7 | spec:
8 | type: NodePort
9 | ports:
10 | - port: 8989
11 | selector:
12 | app: turbine-server
13 | ---
14 | apiVersion: apps/v1beta2
15 | kind: Deployment
16 | metadata:
17 | name: turbine-server
18 | spec:
19 | replicas: 1
20 | selector:
21 | matchLabels:
22 | app: turbine-server
23 | template:
24 | metadata:
25 | labels:
26 | app: turbine-server
27 | spec:
28 | containers:
29 | - name: turbine-server
30 | image: 192.168.99.100:5000/turbine-server
31 | ports:
32 | - containerPort: 8989
33 | env:
34 | - name: CONFIG_SERVER_URL
35 | valueFrom:
36 | configMapKeyRef:
37 | name: env-config
38 | key: config-server-url
39 | volumeMounts:
40 | - name: log-vol
41 | mountPath: /var/log/msdemo
42 | volumes:
43 | - name: log-vol
44 | persistentVolumeClaim:
45 | claimName: log-claim
46 |
--------------------------------------------------------------------------------
/kubernetes/zipkin.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Service
3 | metadata:
4 | name: zipkin
5 | labels:
6 | app: zipkin
7 | spec:
8 | type: NodePort
9 | ports:
10 | - port: 9411
11 | selector:
12 | app: zipkin
13 | ---
14 | apiVersion: apps/v1beta2
15 | kind: Deployment
16 | metadata:
17 | name: zipkin
18 | spec:
19 | replicas: 1
20 | selector:
21 | matchLabels:
22 | app: zipkin
23 | template:
24 | metadata:
25 | labels:
26 | app: zipkin
27 | spec:
28 | containers:
29 | - name: zipkin
30 | image: 192.168.99.100:5000/zipkin
31 | ports:
32 | - containerPort: 9411
33 | env:
34 | - name: RABBIT_ADDRESSES
35 | valueFrom:
36 | configMapKeyRef:
37 | name: env-config
38 | key: rabbitmq-host
39 | - name: RABBIT_USER
40 | valueFrom:
41 | secretKeyRef:
42 | name: config-secret
43 | key: rabbitmq-user
44 | - name: RABBIT_PASSWORD
45 | valueFrom:
46 | secretKeyRef:
47 | name: config-secret
48 | key: rabbitmq-pwd
49 |
--------------------------------------------------------------------------------
/monitor-dashboard/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM openjdk:8-jdk-alpine
2 |
3 | VOLUME /tmp
4 |
5 | # Set timezone
6 | ENV TIME_ZONE Asia/Taipei
7 | RUN apk --no-cache add \
8 | tzdata \
9 | && echo "${TIME_ZONE}" > /etc/timezone \
10 | && ln -sf /usr/share/zoneinfo/${TIME_ZONE} /etc/localtime
11 |
12 | RUN mkdir /msdemo
13 | WORKDIR /msdemo
14 | COPY ./target/monitor-dashboard.jar ./monitor-dashboard.jar
15 |
16 | CMD ["java", "-Djava.security.egd=file:/dev/./urandom", "-jar", "monitor-dashboard.jar"]
--------------------------------------------------------------------------------
/monitor-dashboard/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | monitor-dashboard
7 | monitor-dashboard
8 | Spring Cloud Microservices Demo
9 |
10 |
11 | demo.ms
12 | ms-demo
13 | 0.0.1
14 |
15 |
16 |
17 |
18 | org.springframework.boot
19 | spring-boot-starter-webflux
20 |
21 |
22 |
23 | org.springframework.boot
24 | spring-boot-starter-actuator
25 |
26 |
27 |
28 | org.springframework.cloud
29 | spring-cloud-starter-config
30 |
31 |
32 | org.springframework.cloud
33 | spring-cloud-starter-bus-amqp
34 |
35 |
36 |
37 | org.springframework.cloud
38 | spring-cloud-starter-netflix-eureka-client
39 |
40 |
41 |
42 |
43 | org.springframework.cloud
44 | spring-cloud-starter-netflix-hystrix
45 |
46 |
47 | org.springframework.cloud
48 | spring-cloud-starter-netflix-hystrix-dashboard
49 |
50 |
51 |
52 | org.springframework.boot
53 | spring-boot-starter-test
54 | test
55 |
56 |
57 |
58 |
59 | ${project.name}
60 |
61 |
62 | org.springframework.boot
63 | spring-boot-maven-plugin
64 |
65 |
66 |
67 |
68 |
--------------------------------------------------------------------------------
/monitor-dashboard/src/main/java/demo/ms/MonitorDashboardApplication.java:
--------------------------------------------------------------------------------
1 | package demo.ms;
2 |
3 | import org.springframework.beans.factory.annotation.Autowired;
4 | import org.springframework.beans.factory.annotation.Value;
5 | import org.springframework.boot.SpringApplication;
6 | import org.springframework.boot.autoconfigure.SpringBootApplication;
7 | import org.springframework.cloud.client.loadbalancer.LoadBalanced;
8 | import org.springframework.cloud.netflix.hystrix.dashboard.EnableHystrixDashboard;
9 | import org.springframework.context.annotation.Bean;
10 | import org.springframework.http.codec.ServerSentEvent;
11 | import org.springframework.stereotype.Controller;
12 | import org.springframework.web.bind.annotation.GetMapping;
13 | import org.springframework.web.reactive.function.client.WebClient;
14 |
15 | import reactor.core.publisher.Flux;
16 |
17 | @SpringBootApplication
18 | @EnableHystrixDashboard
19 | public class MonitorDashboardApplication {
20 |
21 | public static void main(String[] args) {
22 | SpringApplication.run(MonitorDashboardApplication.class, args);
23 | }
24 |
25 | @Bean
26 | @LoadBalanced
27 | public WebClient.Builder loadBalancedWebClientBuilder() {
28 | return WebClient.builder();
29 | }
30 |
31 | @Controller
32 | static class WebController {
33 |
34 | @Autowired
35 | private WebClient.Builder webClientBuilder;
36 |
37 | @Value("${server.port}")
38 | private Integer serverPort;
39 |
40 | @Value("${turbine.aggregator.clusterConfig}")
41 | private String clusterName;
42 |
43 | @GetMapping("/turbine-stream")
44 | public Flux turbineStream() {
45 | return webClientBuilder
46 | .build()
47 | .get()
48 | .uri("http://turbine-server/turbine.stream?cluster=" + clusterName)
49 | .retrieve()
50 | .bodyToFlux(ServerSentEvent.class);
51 | }
52 |
53 | @GetMapping({"", "/"})
54 | public String index() {
55 | return "redirect:/hystrix/monitor?stream=http://localhost:" + serverPort + "/turbine-stream";
56 | }
57 | }
58 | }
--------------------------------------------------------------------------------
/monitor-dashboard/src/main/resources/bootstrap.yml:
--------------------------------------------------------------------------------
1 | CONFIG_SERVER_URL: http://127.0.0.1:8888
2 |
3 | server:
4 | port: 7979
5 |
6 | spring:
7 | application:
8 | name: monitor-dashboard
9 | main:
10 | banner-mode: "off"
11 | mvc:
12 | favicon.enabled: false
13 | cloud:
14 | config:
15 | uri: ${CONFIG_SERVER_URL}
16 | fail-fast: true
17 |
--------------------------------------------------------------------------------
/monitor-dashboard/src/main/resources/logback-spring.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/monitor-dashboard/src/test/java/demo/ms/MonitorDashboardApplicationTests.java:
--------------------------------------------------------------------------------
1 | package demo.ms;
2 |
3 | import org.junit.Test;
4 | import org.junit.runner.RunWith;
5 | import org.springframework.boot.test.context.SpringBootTest;
6 | import org.springframework.test.context.junit4.SpringRunner;
7 |
8 | @RunWith(SpringRunner.class)
9 | @SpringBootTest
10 | public class MonitorDashboardApplicationTests {
11 |
12 | @Test
13 | public void contextLoads() {
14 | }
15 |
16 | }
17 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 4.0.0
4 |
5 | demo.ms
6 | ms-demo
7 | 0.0.1
8 | pom
9 |
10 |
11 | org.springframework.boot
12 | spring-boot-starter-parent
13 | 2.0.3.RELEASE
14 |
15 |
16 |
17 |
18 | UTF-8
19 | UTF-8
20 | Finchley.RELEASE
21 | 1.8
22 |
23 |
24 |
25 | account-service
26 | api-gateway
27 | cloud-gateway
28 | auth-service
29 | config-server
30 | turbine-server
31 | monitor-dashboard
32 | service-registry
33 |
34 |
35 |
36 |
37 |
38 | org.springframework.cloud
39 | spring-cloud-dependencies
40 | ${spring-cloud.version}
41 | pom
42 | import
43 |
44 |
45 |
46 |
47 |
48 |
49 | spring-snapshots
50 | Spring Snapshots
51 | http://repo.spring.io/snapshot
52 |
53 | true
54 |
55 |
56 |
57 | spring-milestones
58 | Spring Milestones
59 | http://repo.spring.io/milestone
60 |
61 | false
62 |
63 |
64 |
65 |
--------------------------------------------------------------------------------
/push-images.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -e
4 |
5 | docker push 192.168.99.100:5000/config-server
6 | docker push 192.168.99.100:5000/service-registry
7 | docker push 192.168.99.100:5000/turbine-server
8 | docker push 192.168.99.100:5000/monitor-dashboard
9 | docker push 192.168.99.100:5000/auth-service
10 | docker push 192.168.99.100:5000/account-service
11 | docker push 192.168.99.100:5000/cloud-gateway
12 |
--------------------------------------------------------------------------------
/service-registry/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM openjdk:8-jdk-alpine
2 |
3 | VOLUME /tmp
4 |
5 | # Set timezone
6 | ENV TIME_ZONE Asia/Taipei
7 | RUN apk --no-cache add \
8 | tzdata \
9 | && echo "${TIME_ZONE}" > /etc/timezone \
10 | && ln -sf /usr/share/zoneinfo/${TIME_ZONE} /etc/localtime
11 |
12 | RUN mkdir /msdemo
13 | WORKDIR /msdemo
14 | COPY ./target/service-registry.jar ./service-registry.jar
15 |
16 | CMD ["java", "-Djava.security.egd=file:/dev/./urandom", "-jar", "service-registry.jar"]
--------------------------------------------------------------------------------
/service-registry/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | service-registry
7 | service-registry
8 | Spring Cloud Microservices Demo
9 |
10 |
11 | demo.ms
12 | ms-demo
13 | 0.0.1
14 |
15 |
16 |
17 |
18 | org.springframework.boot
19 | spring-boot-starter-actuator
20 |
21 |
22 |
23 | org.springframework.cloud
24 | spring-cloud-starter-config
25 |
26 |
27 | org.springframework.cloud
28 | spring-cloud-starter-bus-amqp
29 |
30 |
31 |
32 | org.springframework.cloud
33 | spring-cloud-starter-netflix-eureka-client
34 |
35 |
36 |
37 | org.springframework.cloud
38 | spring-cloud-starter-netflix-eureka-server
39 |
40 |
41 |
42 | org.springframework.boot
43 | spring-boot-starter-test
44 | test
45 |
46 |
47 |
48 |
49 | ${project.name}
50 |
51 |
52 | org.springframework.boot
53 | spring-boot-maven-plugin
54 |
55 |
56 |
57 |
58 |
--------------------------------------------------------------------------------
/service-registry/src/main/java/demo/ms/ServiceRegistryApplication.java:
--------------------------------------------------------------------------------
1 | package demo.ms;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 | import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
6 |
7 | @SpringBootApplication
8 | @EnableEurekaServer
9 | public class ServiceRegistryApplication {
10 |
11 | public static void main(String[] args) {
12 | SpringApplication.run(ServiceRegistryApplication.class, args);
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/service-registry/src/main/resources/bootstrap.yml:
--------------------------------------------------------------------------------
1 | CONFIG_SERVER_URL: http://127.0.0.1:8888
2 |
3 | server:
4 | port: 8761
5 |
6 | spring:
7 | application:
8 | name: service-registry
9 | main:
10 | banner-mode: "off"
11 | mvc:
12 | favicon.enabled: false
13 | cloud:
14 | config:
15 | uri: ${CONFIG_SERVER_URL}
16 | fail-fast: true
17 |
--------------------------------------------------------------------------------
/service-registry/src/main/resources/logback-spring.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/service-registry/src/test/java/demo/ms/RegistryServiceApplicationTests.java:
--------------------------------------------------------------------------------
1 | package demo.ms;
2 |
3 | import org.junit.Test;
4 | import org.junit.runner.RunWith;
5 | import org.springframework.boot.test.context.SpringBootTest;
6 | import org.springframework.test.context.junit4.SpringRunner;
7 |
8 | @RunWith(SpringRunner.class)
9 | @SpringBootTest
10 | public class RegistryServiceApplicationTests {
11 |
12 | @Test
13 | public void contextLoads() {
14 | }
15 |
16 | }
17 |
--------------------------------------------------------------------------------
/turbine-server/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM openjdk:8-jdk-alpine
2 |
3 | VOLUME /tmp
4 |
5 | # Set timezone
6 | ENV TIME_ZONE Asia/Taipei
7 | RUN apk --no-cache add \
8 | tzdata \
9 | && echo "${TIME_ZONE}" > /etc/timezone \
10 | && ln -sf /usr/share/zoneinfo/${TIME_ZONE} /etc/localtime
11 |
12 | RUN mkdir /msdemo
13 | WORKDIR /msdemo
14 | COPY ./target/turbine-server.jar ./turbine-server.jar
15 |
16 | CMD ["java", "-Djava.security.egd=file:/dev/./urandom", "-jar", "turbine-server.jar"]
--------------------------------------------------------------------------------
/turbine-server/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | turbine-server
7 | turbine-server
8 | Spring Cloud Microservices Demo
9 |
10 |
11 | demo.ms
12 | ms-demo
13 | 0.0.1
14 |
15 |
16 |
17 |
18 | org.springframework.boot
19 | spring-boot-starter-actuator
20 |
21 |
22 |
23 | org.springframework.cloud
24 | spring-cloud-starter-config
25 |
26 |
27 | org.springframework.cloud
28 | spring-cloud-starter-bus-amqp
29 |
30 |
31 |
32 | org.springframework.cloud
33 | spring-cloud-starter-netflix-eureka-client
34 |
35 |
36 |
37 |
38 | org.springframework.cloud
39 | spring-cloud-starter-netflix-hystrix
40 |
41 |
42 | org.springframework.cloud
43 | spring-cloud-starter-netflix-turbine-stream
44 |
45 |
46 | org.springframework.cloud
47 | spring-cloud-starter-stream-rabbit
48 |
49 |
50 |
51 | org.springframework.boot
52 | spring-boot-starter-test
53 | test
54 |
55 |
56 |
57 |
58 | ${project.name}
59 |
60 |
61 | org.springframework.boot
62 | spring-boot-maven-plugin
63 |
64 |
65 |
66 |
67 |
--------------------------------------------------------------------------------
/turbine-server/src/main/java/demo/ms/TurbineServerApplication.java:
--------------------------------------------------------------------------------
1 | package demo.ms;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 | import org.springframework.cloud.netflix.turbine.stream.EnableTurbineStream;
6 |
7 | @SpringBootApplication
8 | @EnableTurbineStream
9 | public class TurbineServerApplication {
10 |
11 | public static void main(String[] args) {
12 | SpringApplication.run(TurbineServerApplication.class, args);
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/turbine-server/src/main/resources/bootstrap.yml:
--------------------------------------------------------------------------------
1 | CONFIG_SERVER_URL: http://127.0.0.1:8888
2 |
3 | server:
4 | port: 8989
5 |
6 | spring:
7 | application:
8 | name: turbine-server
9 | main:
10 | banner-mode: "off"
11 | mvc:
12 | favicon.enabled: false
13 | cloud:
14 | config:
15 | uri: ${CONFIG_SERVER_URL}
16 | fail-fast: true
17 |
--------------------------------------------------------------------------------
/turbine-server/src/main/resources/logback-spring.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/undeploy-docker.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -e
4 |
5 | docker-compose stop
6 |
7 | docker rm monitor-dashboard turbine-server cloud-gateway account-service auth-service service-registry config-server zipkin rabbitmq
8 |
--------------------------------------------------------------------------------
/undeploy-kubernetes.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -e
4 |
5 | kubectl delete deploy,svc cloud-gateway
6 | kubectl delete deploy,svc account-service
7 | kubectl delete deploy,svc auth-service
8 | kubectl delete deploy,svc monitor-dashboard
9 | kubectl delete deploy,svc turbine-server
10 | kubectl delete deploy,svc service-registry
11 | kubectl delete deploy,svc config-server
12 |
13 | kubectl delete deploy,svc zipkin
14 | kubectl delete deploy,svc rabbitmq
15 |
16 | kubectl delete pvc config-claim log-claim
17 | kubectl delete pv config-pv log-pv
18 |
19 | kubectl delete cm env-config
20 | kubectl delete secrets config-secret
21 |
--------------------------------------------------------------------------------