SpringCloud on Kubernetes 索引目录

  1. 动手修改kubeam生成证书有效期为100年 已填坑
  2. 搭建高可用kubernetes 已填坑
  3. 部署kubernetes基本插件已填坑
  4. 从部署mysql聊一聊有状态服务和PV及PVC已填坑
  5. 搭建代码仓库gitlab服务器已填坑
  6. 如何构建SpringBoot的Docker镜像已填坑
  7. SC微服务内的java代码如何分层已填坑
  8. 在kubernetes上运行eureka集群已填坑
  9. 在kubernetes上运行SpringCloud配置中心已填坑
  10. SC微服务体系下异常透明处理
  11. Gitlab Runner 构建自动化CI/CD
  12. 在kubernetes中部署zookeeper集群
  13. Spring Cloud 的灰度发布
  14. 在kubernetes中部署Kafka集群
  15. Spring Gateway
  16. 在kubernetes上运行elasticsearch集群已填坑
  17. Zipkin分布式链路追踪
  18. EFK分布式日志管理
  19. Ingress Nginx
  20. kubernetes集群监控
  21. kubernetes dashboard ui图表

从部署mysql聊一聊有状态服务和PV及PVC

前言

部署mysql之前我们需要先了解一个概念有状态服务。这是一种特殊的服务,简单的归纳下就是会产生需要持久化的数据,并且有很强的I/O需求,且重启需要依赖上次存储到磁盘的数据。如典型的mysql,kafka,zookeeper等等。

在我们有比较优秀的商业存储的前提下,灰常推荐使用有状态服务进行部署,计算和存储分离那是相当的爽的。在实际生产中如果没有这种存储,才有localPV也是不错的选择,当然local pv其实呢和hostPath是一样的。当然我们在开发测试环境也是可以自己搭建一套简单的如NFS服务,来享受存储和计算分离的爽快感。

kubernetes中定义一种了资源类型Stateful Service即有状态服务,有状态服务需要的持久化数据动态绑定我们可以利用存储的API PersistentVolume(PV)和PersistentVolumeClaim(PVC)来进行需要的相关数据的绑定和存储。

阅读全文 »

在kubernetes运行分布式追踪zipkin

前言

Zipkin是一个开放源代码分布式的跟踪系统,每个服务向zipkin报告计时数据,zipkin会根据调用关系通过Zipkin UI生成依赖关系图。简单的来说就是个http服务器
它支持多种后端存储(”cassandra”,”mysql”,”elasticsearch”)持久化客户端推送过来的数据.

部署zipkin使用ES存储

使用ES作为后端存储需要先搭建一个ES环境。可以参考我的另一篇文章在kubernetes上运行elasticsearch集群

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50

---
apiVersion: v1
kind: Service
metadata:
name: zipkin-service
labels:
app: zipkin-service
spec:
ports:
- port: 9411
name: zipkin-service
clusterIP: 10.96.0.13
selector:
app: zipkin-service
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: zipkin-service
spec:
strategy:
type: Recreate
selector:
matchLabels:
app: zipkin-service
template:
metadata:
labels:
app: zipkin-service
spec:
containers:
- name: zipkin-service
image: openzipkin/zipkin
imagePullPolicy: IfNotPresent
livenessProbe:
tcpSocket:
port: 9411
timeoutSeconds: 5
readinessProbe:
tcpSocket:
port: 9411
timeoutSeconds: 5
ports:
- containerPort: 9411
env:
- name: STORAGE_TYPE
value: elasticsearch
- name: STORAGE_PORT_9200_TCP_ADDR
value: "es-m1"

部署zipkin使用Mysql存储

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58

---
apiVersion: v1
kind: Service
metadata:
name: zipkin-service
labels:
app: zipkin-service
spec:
ports:
- port: 9411
name: zipkin-service
clusterIP: 10.96.0.12
selector:
app: zipkin-service
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: zipkin-service
spec:
strategy:
type: Recreate
selector:
matchLabels:
app: zipkin-service
template:
metadata:
labels:
app: zipkin-service
spec:
containers:
- name: zipkin-service
image: openzipkin/zipkin
imagePullPolicy: IfNotPresent
livenessProbe:
tcpSocket:
port: 9411
timeoutSeconds: 5
readinessProbe:
tcpSocket:
port: 9411
timeoutSeconds: 5
ports:
- containerPort: 9411
env:
- name: STORAGE_TYPE
value: mysql
- name: MYSQL_DB
value: zipkin
- name: MYSQL_USER
value: root
- name: MYSQL_PASS
value: "root"
- name: MYSQL_HOST
value: "192.168.3.202"
- name: MYSQL_TCP_PORT
value: "3306"

在kubernetes上运行SpringCloud配置中心

前言

在分布式系统中,我们的配置管理起来是很麻烦的一件事儿,特别是在如果没有配置中心的时候。在我们java开发中,一般而言会将敏感配置信息(如DB的user,password),数据库的地址,redis地址等等,
一系列配置信息和项目代码解耦,根据每个环境单独配置,这样一来是方便不需要改代码,也不需要在项目中冗余多份,二来是更加的安全。那么分离之后我们将面临的问题是怎么读取这个配置文件:

阅读全文 »

在kubernetes上运行eureka集群

前言

eureka 在springcloud体系中,主要实现一个注册中心的角色,所有的服务都将注册到eureke中,调用用者将从这里通过名称获取到对应的服务的IP集合列表。
作为一个分布式系统eureka在CAP中,选中了AP,优先保证可用性,放弃了强一致性,这样设计也符合注册中心的需要。
当发生网络分区故障(15分钟内超过85%的节点都没有正常的心跳),eureka会启用注册保护,即维持住当前心跳虽然失败的服务列表,并不进行删除。并能正常的提供查询服务(虽然不是最新)和注册服务(即不会同步到其他eureka节点),当网络恢复时,eureka会正确的同步信息,和恢复删除过期节点信息。

阅读全文 »

在kubernetes上运行Spring Cloud Gateway

前言

https://github.com/spring-cloud/spring-cloud-gateway是Spring Cloud官方推出的一个网关项目,主要是基于reactor-netty实现。网关在微服务系统主要充当了一个入口”门”的作用,所有的IN/OUT都需要经过这一道门,才能访问到微服务池子中的功能api。
这样的设计方便了我们对业务功能的保护api资源的保护,我们可以在这里灵活的控制对外开放的API集合,而这些API集合就构成了我们的"系统"

我们还可以方便的在这里完成鉴权,如果是非法用户之间在这里干掉,从而避免了对业务的调用。

还可以对参数进行转换,比如从调用者带过来的是一个JWT我们可以解析这个Token,得到诸如currentUserId租户idusername,等等一些列参数后,再往后传递到具体的微服务上。

这里只是一些常用功能的列举,本质上来说呢,他就是一组Filters,我们可以通过扩展它的Filter,快速完成业务所需要的功能效果。

依赖

首先肯定是需要导入gateway

1
2
3
4
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>

我们还需要服务发现eureka,这里直接排除掉jersey的相关依赖,能少点jar就少点吧。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
<exclusions>
<exclusion>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-client</artifactId>
</exclusion>
<exclusion>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-core</artifactId>
</exclusion>
<exclusion>
<groupId>com.sun.jersey.contribs</groupId>
<artifactId>jersey-apache-client4</artifactId>
</exclusion>
</exclusions>
</dependency>

网关也是需要对服务进行LoadBalance,这里导入ribbon的依赖。这里他也依赖了jersey相关的东西,排除掉好了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
<exclusions>
<exclusion>
<artifactId>jersey-client</artifactId>
<groupId>com.sun.jersey</groupId>
</exclusion>
<exclusion>
<artifactId>jersey-apache-client4</artifactId>
<groupId>com.sun.jersey.contribs</groupId>
</exclusion>
</exclusions>
</dependency>

我们可以启用ribbon中的okhttpclent,需要加入okhttp的依赖

1
2
3
4
5
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>4.1.0</version>
</dependency>

需要分布式追踪功能加入zipkin和sleuth的依赖。

1
2
3
4
5
6
7
8
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zipkin</artifactId>
</dependency>

pom.xml

完整的pom长这样

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.7.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>io.qingmu</groupId>
<artifactId>demo-gateway</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>demo-gateway</name>
<description>Demo project for Spring Boot</description>

<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Greenwich.SR2</spring-cloud.version>
</properties>

<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
<exclusions>
<exclusion>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-client</artifactId>
</exclusion>
<exclusion>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-core</artifactId>
</exclusion>
<exclusion>
<groupId>com.sun.jersey.contribs</groupId>
<artifactId>jersey-apache-client4</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
<exclusions>
<exclusion>
<artifactId>jersey-client</artifactId>
<groupId>com.sun.jersey</groupId>
</exclusion>
<exclusion>
<artifactId>jersey-apache-client4</artifactId>
<groupId>com.sun.jersey.contribs</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zipkin</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>4.1.0</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.4</version>
<scope>provided</scope>
</dependency>
</dependencies>

<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>

<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>com.spotify</groupId>
<artifactId>docker-maven-plugin</artifactId>
<configuration>
<imageName>
freemanliu/demo-gatway:v1.0.0
</imageName>
<registryUrl></registryUrl>
<workdir>/work</workdir>
<rm>true</rm>
<env>
<TZ>Asia/Shanghai</TZ>
<JAVA_OPTS>
-XX:+UnlockExperimentalVMOptions \
-XX:+UseCGroupMemoryLimitForHeap \
-XX:MaxRAMFraction=2 \
-XX:CICompilerCount=8 \
-XX:ActiveProcessorCount=8 \
-XX:+UseG1GC \
-XX:+AggressiveOpts \
-XX:+UseFastAccessorMethods \
-XX:+UseStringDeduplication \
-XX:+UseCompressedOops \
-XX:+OptimizeStringConcat
</JAVA_OPTS>
</env>
<baseImage>freemanliu/openjre:8.212</baseImage>
<cmd>
/sbin/tini java ${JAVA_OPTS} -jar ${project.build.finalName}.jar
</cmd>
<!--是否推送image-->
<pushImage>true</pushImage>
<resources>
<resource>
<directory>${project.build.directory}</directory>
<include>${project.build.finalName}.jar</include>
</resource>
</resources>
<serverId>docker-hub</serverId>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>build</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

异常处理器

为什么要有异常处理?

  1. 需要将异常信息处理成我们所需要的格式。
  2. 统一处理自定义filter抛出的异常。

在不处理异常信息时,gateway默认返回的信息格式如下

1
2
3
4
5
6
7
{
"timestamp":"2019-08-21T06:46:19.819+0000"
,"path":"/demo1-service/hello"
,"status":504
,"error":"Gateway Timeout"
,"message":"Response took longer than timeout: PT20S"
}

这显然不太和我们一般定义的返回结构不同,一般常见的返回结构如下:

1
2
3
4
5
{
"code": 0
,"data"": {}
,"message": ""
}

CustomExceptionHandler.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75

package io.qingmu.demogateway.advice;

import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.web.reactive.error.ErrorWebExceptionHandler;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.web.reactive.function.client.WebClientResponseException;
import org.springframework.web.server.ResponseStatusException;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import javax.validation.ValidationException;
import java.nio.charset.Charset;

@Setter
@Slf4j
public class CustomExceptionHandler implements ErrorWebExceptionHandler {


@Override
public Mono<Void> handle(ServerWebExchange exchange, Throwable ex) {
// 按照异常类型进行处理
final ServerHttpRequest request = exchange.getRequest();
HttpStatus httpStatus;
String body;
int code = 500;
if (ex instanceof ResponseStatusException) {
ResponseStatusException responseStatusException = (ResponseStatusException) ex;
httpStatus = responseStatusException.getStatus();
if (httpStatus == HttpStatus.NOT_FOUND) {
body = "服务接口未找到-404,path:" + request.getPath().value();
} else
body = responseStatusException.getMessage();
} else if (ex instanceof CustomException) {
body = ((CustomException) ex).getMessage();
code = ((CustomException) ex).getCode();
} else if (ex instanceof WebClientResponseException) {
final Response result = JsonUtils.fromJson(((WebClientResponseException) ex).getResponseBodyAsString(), Response.class);
body = result.getMessage();
code = result.getCode();
} else if (ex instanceof ValidationException) {
body = ex.getMessage();
code = 400;
} else {
log.error(ex.getMessage(), ex);
body = "服务器繁忙-请稍后重试。";
}
log.error("[全局异常处理]异常请求路径:{},记录异常信息:{}", request.getPath(), ex.getMessage());
final ServerHttpResponse response = exchange.getResponse();
if (response.isCommitted()) {
return Mono.error(ex);
}
response.getHeaders()
.setContentType(MediaType
.APPLICATION_JSON_UTF8);
response.setStatusCode(HttpStatus
.INTERNAL_SERVER_ERROR);
return response
.writeWith(Mono
.just(response
.bufferFactory()
.wrap(JsonUtils
.toJson(Response
.builder()
.code(code)
.message(body)
.build())
.getBytes(Charset
.forName("UTF-8")))));
}
}

Response.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

package io.qingmu.demogateway.advice;

import lombok.*;
import java.io.Serializable;

@Getter
@Setter
@NoArgsConstructor
@Builder
@AllArgsConstructor
public class Response<T> implements Serializable {

protected int code;

protected String message;

protected T data;
}

DemoGatewayApplication

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package io.qingmu.demogateway;

import io.qingmu.demogateway.advice.CustomExceptionHandler;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.reactive.error.ErrorWebExceptionHandler;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Primary;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;

@SpringBootApplication
@EnableDiscoveryClient
public class DemoGatewayApplication {

public static void main(String[] args) {
SpringApplication.run(DemoGatewayApplication.class, args);
}

@Primary
@Bean
@Order(Ordered.HIGHEST_PRECEDENCE)
public ErrorWebExceptionHandler errorWebExceptionHandler() {
return new CustomExceptionHandler();
}

}

静态路由

服务发现动态路由

配置zipkin的采集率,1.0 表示100%,0.1表示采集10%。

1
2
3
4
5
6
spring:
zipkin:
base-url: ${ZIPKIN:http://10.96.0.13:9411/}
sleuth:
sampler:
probability: ${SAMPLER_PROBABILITY:1.0}

启用服务发现,自动配置路由。
比如我们有服务user-service中有api资源获取单个用户信息接口 /get
我们直接访问user-service的http接口为: http://ip:port/get
通过网关服务发现后的访问http接口为: http://gatewayip:gatwayport/user-service/get

1
2
3
4
5
6
7
spring:
cloud:
gateway:
discovery:
locator:
lowerCaseServiceId: true
enabled: true

配置gateway的http client的相关参数

1
2
3
4
5
6
7
8
spring:
cloud:
gateway:
httpclient:
pool:
max-connections: ${MAX_CONNECTIONS:300}
connect-timeout: ${CONNECT_TIMEOUT:10000}
response-timeout: ${RESPONSE_TIMEOUT:5s}

配置全局默认filters,这里我们可以激活retry filter。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
spring:
cloud:
gateway:
default-filters:
- StripPrefix=1
- name: Retry
args:
retries: 3
series:
- SERVER_ERROR
- CLIENT_ERROR
statuses:
- INTERNAL_SERVER_ERROR
methods:
- GET
- POST
exceptions:
- java.io.IOException
- java.util.concurrent.TimeoutException

完成的 application.yml 如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
server:
port: 8084
spring:
zipkin:
base-url: ${ZIPKIN:http://10.96.0.13:9411/}
sleuth:
sampler:
probability: ${SAMPLER_PROBABILITY:1.0}
cloud:
gateway:
discovery:
locator:
lowerCaseServiceId: true
enabled: true
httpclient:
pool:
max-connections: ${MAX_CONNECTIONS:300}
connect-timeout: ${CONNECT_TIMEOUT:10000}
response-timeout: ${RESPONSE_TIMEOUT:5s}
metrics:
enabled: true
default-filters:
- StripPrefix=1
- name: Retry
args:
retries: 3
series:
- SERVER_ERROR
- CLIENT_ERROR
statuses:
- INTERNAL_SERVER_ERROR
methods:
- GET
- POST
exceptions:
- java.io.IOException
- java.util.concurrent.TimeoutException
application:
name: demo-gateway
ribbon:
okhttp:
enabled: true
logging:
logPath: /var/log/${spring.application.name}
level:
com.netflix.discovery.shared.resolver.aws: ERROR
management:
endpoints:
web:
exposure:
include: "*"

DemoGatewayApplication

启动类如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package io.qingmu.demogateway;

import io.qingmu.demogateway.advice.CustomExceptionHandler;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.reactive.error.ErrorWebExceptionHandler;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Primary;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;

@SpringBootApplication
@EnableDiscoveryClient
public class DemoGatewayApplication {
public static void main(String[] args) {
SpringApplication.run(DemoGatewayApplication.class, args);
}
@Primary
@Bean
@Order(Ordered.HIGHEST_PRECEDENCE)
public ErrorWebExceptionHandler errorWebExceptionHandler() {
return new CustomExceptionHandler();
}
}

启动我们网关服务,等待他启动完成,我们就可以通过网关来统一业务服务的访问。
启动我们的之前的业务服务demo1-serivcedemo2-service,通过如下url即可访问到。

访问demo1服务的hello接口

script
1
2
3
4
5
6
7
8

$ curl -i http://127.0.0.1:8084/demo1-service/hello
HTTP/1.1 200 OK
Content-Type: text/plain;charset=UTF-8
Content-Length: 5
Date: Wed, 21 Aug 2019 10:41:45 GMT

hello

此时的调用链条,我们可以从zipkin中看到,如下图:

gateway1

访问demo2服务的hello接口

script
1
2
3
4
5
6
7
8

$ curl -i http://127.0.0.1:8084/demo2-service/world
HTTP/1.1 200 OK
Content-Type: text/plain;charset=UTF-8
Content-Length: 5
Date: Wed, 21 Aug 2019 10:47:05 GMT

world

这样我们就完成了网关的动态映射。

自定义Filter

在kubernetes上运行elasticsearch集群

像elasticsearch这种应用属于重度依赖IO,依赖磁盘,对磁盘敏感的应用,如果采用分布式文件系统(NFS/GlusterFS等)来进行数据的存储,对ES的性能会造成很大的影响。
elasticsearch是具有状态的应用,我们可以采用两种方式部署,STS+LocalPV 或者是Deployment+NodeSelector+HostPath 的方式进行部署,本质上来说两者区别不大。

阅读全文 »