介绍
springCloud使用k8s作为注册中心,实现服务的发现和注册。 本文使用Provider和Comsumer两个服务 官网:https://docs.spring.io/spring-cloud-kubernetes/docs/2.1.2/reference/html/
版本
springBoot:2.6.7 springCloud:2021.0.2
源码
https://gitee.com/wfh_fly/springcloud-k8s
Provider
主要依赖
dependencies {
implementation("org.springframework.boot:spring-boot-starter-actuator")
implementation("org.springframework.boot:spring-boot-starter-web")
implementation("org.springframework.cloud:spring-cloud-starter-kubernetes-client-all")
testImplementation("org.springframework.boot:spring-boot-starter-test")
}
也可以引入:spring-cloud-starter-kubernetes-client 添加 @EnableDiscoveryClient启用服务发现
@SpringBootApplication
@EnableDiscoveryClient
public class ProviderApplication {
public static void main(String[] args) {
SpringApplication.run(ProviderApplication.class, args);
}
}
application.yml
server:
port: 8811
spring:
application:
name: provider
management:
endpoints:
web:
exposure:
include: "*"
endpoint:
health:
show-details: ALWAYS
接口代码:
@RestController
public class TestController {
@Resource
private DiscoveryClient discoveryClient;
@GetMapping("service")
public List<String> getServiceList() {
return discoveryClient.getServices();
}
@GetMapping("instance")
public Object getInstance(@RequestParam("name") String name) {
return discoveryClient.getInstances(name);
}
@GetMapping("ping")
public String ping() {
try {
System.out.println("1---1");
discoveryClient.getServices();
return InetAddress.getLocalHost().getHostName();
} catch (UnknownHostException e) {
return "Pong";
}
}
@GetMapping("hello")
public String test() {
System.out.println("hello!!");
return "hello!!";
}
@GetMapping("error")
public String error() {
throw new RuntimeException("test run time exception");
}
}
k8s配置:
apiVersion: apps/v1
kind: Deployment
metadata:
name: provider
namespace: test
labels:
app: provider
spec:
replicas: 1
selector:
matchLabels:
app: provider
template:
metadata:
labels:
app: provider
spec:
serviceAccountName: testadmin
topologySpreadConstraints:
- maxSkew: 1
topologyKey: zone
whenUnsatisfiable: DoNotSchedule
labelSelector:
matchLabels:
app: provider
containers:
- name: provider
image: registry.com/test/provider:2.0.0-20220516164418-SNAPSHOT
imagePullPolicy: Always
ports:
- name: rest
containerPort: 8811
hostPort: 8811
readinessProbe:
httpGet:
path: /actuator/health/readiness
port: 8811
initialDelaySeconds: 50
livenessProbe:
httpGet:
path: /actuator/health/liveness
port: 8811
initialDelaySeconds: 50
resources:
limits:
cpu: '2'
memory: 700Mi
requests:
cpu: '0.3'
memory: 400Mi
---
apiVersion: v1
kind: Service
metadata:
name: provider
namespace: test
labels:
app: provider
spec:
type: NodePort
selector:
app: provider
ports:
- name: rest
protocol: TCP
port: 8811
targetPort: 8811
nodePort: 30881
Consumer
依赖
dependencies {
implementation("org.springframework.boot:spring-boot-starter-actuator")
implementation("org.springframework.boot:spring-boot-starter-web")
implementation("org.springframework.cloud:spring-cloud-starter-kubernetes-client-all")
implementation("org.springframework.cloud:spring-cloud-starter-openfeign")
implementation("org.springframework.cloud:spring-cloud-starter-loadbalancer")
implementation("io.github.openfeign:feign-httpclient")
implementation("org.apache.httpcomponents:httpclient")
implementation("org.apache.commons:commons-lang3")
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
testImplementation("org.springframework.boot:spring-boot-starter-test")
}
使用spring-cloud-starter-loadbalancer作为负载均衡器。
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class ConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(ConsumerApplication.class, args);
}
}
application.yml
server:
port: 8812
spring:
application:
name: consumer
management:
endpoints:
web:
exposure:
include: "*"
endpoint:
health:
show-details: ALWAYS
Spring Cloud OpenFeign 是一个声明式 REST 客户端。因此,您需要创建一个带有方法和 Spring MVC 注解的接口。@FeignClient在注解中设置正确的名称很重要。此名称需要与目标 Kubernetes Service 的名称相同
@FeignClient("provider")
public interface TestClient {
@GetMapping("hello")
String hello();
@GetMapping("error")
String error();
}
主要接口:
@Slf4j
@RestController
public class TestController {
@Resource
private TestClient testClient;
@GetMapping("hello")
public String hello() {
log.info("hello");
return testClient.hello();
}
@GetMapping("error")
public String error() {
log.info("error");
return testClient.error();
}
}
k8s:
apiVersion: apps/v1
kind: Deployment
metadata:
name: consumer
namespace: test
labels:
app: consumer
spec:
replicas: 1
selector:
matchLabels:
app: consumer
template:
metadata:
labels:
app: consumer
spec:
serviceAccountName: testadmin
topologySpreadConstraints:
- maxSkew: 1
topologyKey: zone
whenUnsatisfiable: DoNotSchedule
labelSelector:
matchLabels:
app: consumer
containers:
- name: consumer
image: registry.com/test/consumer:2.0.0-20220517094904-SNAPSHOT
imagePullPolicy: Always
ports:
- name: rest
containerPort: 8812
hostPort: 8812
readinessProbe:
httpGet:
path: /actuator/health/readiness
port: 8812
initialDelaySeconds: 50
livenessProbe:
httpGet:
path: /actuator/health/liveness
port: 8812
initialDelaySeconds: 50
resources:
limits:
cpu: '2'
memory: 700Mi
requests:
cpu: '0.3'
memory: 400Mi
---
apiVersion: v1
kind: Service
metadata:
name: consumer
namespace: test
labels:
app: consumer
spec:
type: NodePort
selector:
app: consumer
ports:
- name: rest
protocol: TCP
port: 8812
targetPort: 8812
nodePort: 30882
服务启动错误处理: User “test:serviceaccount:xxxx:default“ cannot get resource “namespaces“ in API group ““ 意思是使用 test 命名空间下的default用户进行资源操作但是default 用户没有权限 解决方案如下: 创建一个账号角色,其中test为空间,testadmin为账号
apiVersion: v1
kind: ServiceAccount
metadata:
name: testadmin
namespace: test
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: testadmin
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: cluster-admin
subjects:
- kind: ServiceAccount
name: testadmin
namespace: test
注意,此账号权限比较高!
|