springcoud-kubernetes实践之用kubernetes做注册中心(包括负载均衡熔断)
本文是spring-cloud-kubernetes实战,主要内容是在kubernetes上部署两个应用:provider-service和consumer-service,通过spring-cloud-kubernetes提供的注册发现能力,实现consumer-service调用provider-service提供的http服务;
springcoud-kubernetes实践之用kubernetes做注册中心(包括负载均衡熔断)
- 前提条件
- 开发provider-service
- 开发consumer-service
- 验证ribbon轮询能力
- 验证熔断能力
- 错误处理
前提条件
请确保你已经在服务器上搭建kubernetes集群
开发provider-service
1.创建maven项目,添加如下pom.xml
<?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.3.3.RELEASE</version><relativePath/> <!-- lookup parent from repository --></parent><groupId>com.purcotton</groupId><artifactId>k8sprovider</artifactId><version>0.0.1-SNAPSHOT</version><name>k8sprovider</name><description>Demo project for k8sprovider</description><properties><java.version>1.8</java.version><spring.cloud.k8s.version>1.1.6.RELEASE</spring.cloud.k8s.version></properties><dependencyManagement><dependencies><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-kubernetes-dependencies</artifactId><version>${spring.cloud.k8s.version}</version><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope><exclusions><exclusion><groupId>org.junit.vintage</groupId><artifactId>junit-vintage-engine</artifactId></exclusion></exclusions></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build></project>
2.application.properties如下:
spring.application.name=k8s-provider-service
server.port=8083
3.启动类ProviderApplication.java如下
@SpringBootApplication
public class ProviderApplication {public static void main(String[] args) {SpringApplication.run(ProviderApplication.class, args);}}
4.对外提供服务的是ProviderController ,方法getName返回了当前容器的hostname,方法health用于响应kubernetes的两个探针,方法ribbonPing用于响应使用了ribbon服务的调用方,它们会调用这个接口来确定当前服务是否正常
@RestController
public class ProviderController {Logger LOG = LoggerFactory.getLogger(ProviderController.class);private final String hostName = System.getenv("HOSTNAME");/*** 探针检查响应类* @return*/@RequestMapping("/health")public String health() {return "OK";}@RequestMapping("/")public String ribbonPing(){LOG.info("ribbonPing of {}", hostName);return hostName;}/*** 返回hostname* @return 当前应用所在容器的hostname.*/@RequestMapping("/name")public String getName() {return this.hostName+ ", "+ new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());}
}
5.Dockerfile文件如下:
FROM $REPOSITORY/jdk:1.0.0
COPY provider-0.0.1-SNAPSHOT.jar $TARGENAME.jar
RUN rm -rf /etc/localtime && ln -s /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
EXPOSE 8080
#ENTRYPOINT ["java","-jar","$TARGENAME.jar"]
ENTRYPOINT [ "sh", "-c", "exec java -jar $TARGENAME.jar"]
打包duocker镜像:docker build -t REPOSITORY/REPOSITORY/REPOSITORY/TARGENAME:1.0.0 .
推送镜像到私库:docker push REPOSITORY/REPOSITORY/REPOSITORY/TARGENAME:1.0.0
6.编写provider-service.yml文件如下:
apiVersion: apps/v1
kind: Deployment
metadata:name: provider-servicelabels:app: provider-service
spec:replicas: 1selector:matchLabels:app: provider-servicetemplate:metadata:labels:app: provider-servicespec:containers:- name: provider-serviceimage: "xxxx/provider-service:1.0.0"imagePullPolicy: Alwaysports:- name: httpcontainerPort: 8083protocol: TCP---apiVersion: v1
kind: Service
metadata:name: provider-service
spec:type: NodePortports:- port: 8083nodePort: 30082selector:app: provider-service
执行kubectl apply -f provider-service.yml
查看pod
kubectl get deployments
NAME READY UP-TO-DATE AVAILABLE AGE
provider-service 1/1 1 1 42m
查看service
kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
provider-service NodePort 10.105.30.208 <none> 8083:30082/TCP 42m
通过浏览器此时就可以访问服务了 http://{NodeIP}:30082/name
此时,我们的服务提供者就已经开发完成了,现在我们开始开发消费者服务。
开发consumer-service
consumer-service服务是个springboot应用,用到了spring-cloud-kubernetes提供的注册发现能力,以轮询的方式访问指定服务的全部pod
1.创建pom.xml文件
<?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.3.3.RELEASE</version><relativePath/> <!-- lookup parent from repository --></parent><groupId>com.purcotton</groupId><artifactId>consumer</artifactId><version>0.0.1-SNAPSHOT</version><name>sconsumer</name><description>Demo project for consumer</description><properties><java.version>1.8</java.version><spring-cloud.version>Hoxton.SR8</spring-cloud.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-kubernetes-core</artifactId><version>1.1.6.RELEASE</version></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-kubernetes-discovery</artifactId><version>1.1.6.RELEASE</version></dependency><!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-kubernetes-ribbon --><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-kubernetes-ribbon</artifactId><version>1.1.6.RELEASE</version></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-commons</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-ribbon</artifactId></dependency><!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-netflix-hystrix --><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-hystrix</artifactId><version>2.2.5.RELEASE</version></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></plugins></build></project>
2.application.properties如下:
spring.cloud.kubernetes.reload.enabled=true
#spring.cloud.kubernetes.reload.strategy=restart_context
#spring.cloud.kubernetes.reload.mode=pollingmanagement.endpoint.health.enabled=true
management.endpoint.info.enabled=true
management.endpoint.restart.enabled=true
3.application.yml如下:
spring:application:name: k8s-consumer-serviceserver:port: 8080backend:ribbon:eureka:enabled: falseclient:enabled: trueServerListRefreshInterval: 5000hystrix.command.BackendCall.execution.isolation.thread.timeoutInMilliseconds: 5000
hystrix.threadpool.BackendCallThread.coreSize: 5
4.ConsumerApplication .java启动类如下:
@SpringBootApplication
@EnableDiscoveryClient
@EnableCircuitBreaker
@RibbonClient(name="provider-service", configuration = RibbonConfiguration.class)
public class ConsumerApplication {public static void main(String[] args) {SpringApplication.run(ConsumerApplication.class, args);}@LoadBalanced@BeanRestTemplate restTemplate(){return new RestTemplate();}
}
5.创建一个ribbon的配置类RibbonConfiguration:
public class RibbonConfiguration {@AutowiredIClientConfig ribbonClientConfig;/*** 检查服务是否可用的实例,* 此地址返回的响应的返回码如果是200表示服务可用* @param config* @return*/@Beanpublic IPing ribbonPing(IClientConfig config){return new PingUrl();}/*** 轮询规则* @param config* @return*/@Beanpublic IRule ribbonRule(IClientConfig config){return new AvailabilityFilteringRule();}
}
6.创建ConsumerService 类如下:
@Service
public class ConsumerService {@Autowiredprivate RestTemplate restTemplate;@HystrixCommand(fallbackMethod = "getFallbackName" ,commandProperties = {@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "1000") })public String getDataFromSpringCloudK8SProvider(){return this.restTemplate.getForObject("http://k8s-provider-service/name", String.class);}/*** 熔断时调用的方法* @return*/private String getFallbackName() {return "Fallback"+ ", "+ new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());}
}
7.创建外部能访问的controller如下:
@RestController
public class WebServiceController {@Autowiredprivate ConsumerService consumerService ;/*** 探针检查响应类* @return*/@RequestMapping("/health")public String health() {return "OK";}/*** 远程调用account-service提供的服务* @return 多次远程调返回的所有结果.*/@RequestMapping("/account")public String account() {StringBuilder sbud = new StringBuilder();for(int i = 0; i < 10; i++){sbud.append(consumerService.getDataFromSpringCloudK8SProvider()).append("<br>");}return sbud.toString();}
}
8.创建Dockerfile文件如下:
FROM $REPOSITORY/jdk:1.0.0
COPY consumer-0.0.1-SNAPSHOT.jar $TARGENAME.jar
RUN rm -rf /etc/localtime && ln -s /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
EXPOSE 8080
#ENTRYPOINT ["java","-jar","$TARGENAME.jar"]
ENTRYPOINT [ "sh", "-c", "exec java -jar $TARGENAME.jar"]
打包duocker镜像:docker build -t REPOSITORY/REPOSITORY/REPOSITORY/TARGENAME:1.0.0 .
推送镜像到私库:docker push REPOSITORY/REPOSITORY/REPOSITORY/TARGENAME:1.0.0
9.编写consumer-service.yml文件如下:
apiVersion: v1
kind: Service
metadata:name: consumer-servicelabels:app: consumer-service
spec:type: NodePortports:- port: 8080nodePort: 30081protocol: TCPname: httpselector:app: consumer-service---
apiVersion: apps/v1
kind: Deployment
metadata:name: consumer-servicelabels:app: consumer-service
spec:replicas: 1selector:matchLabels:app: consumer-servicetemplate:metadata:labels:app: consumer-servicespec:containers:- name: consumer-serviceimage: "xxxx/consumer-service:1.0.0"imagePullPolicy: Alwaysports:- name: httpcontainerPort: 8080protocol: TCP
执行kubectl apply -f consumer-service.yml
查看pod
kubectl get deployments
NAME READY UP-TO-DATE AVAILABLE AGE
consumer-service 1/1 1 1 42m
查看service
kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
consumer-service NodePort 10.110.106.105 <none> 8080:30081/TCP 42m
通过浏览器此时就可以访问服务了 http://{NodeIP}:30081/account
可以看到可以访问到prodvider-service了
验证ribbon轮询能力
1.首先将prodvider-service扩容成两个,执行如下命令
kubectl scale --replicas=2 deployment provider-service
2.检查provider-service是不是两个
kubectl get pods
NAME READY STATUS RESTARTS AGE
consumer-service-9d46cbdd8-fct2v 1/1 Running 0 67m
provider-service-59ff66fd8b-bbm6p 1/1 Running 0 35m
provider-service-59ff66fd8b-g47hx 1/1 Running 0 5s
3.再次用浏览器访问 http://{NodeIP}:30081/account
可以看到已经轮询多个服务了,说明此时验证成功
验证熔断能力
1.我们运行如下命令,停掉服务
kubectl delete -f provider-service.yaml
2.再次进入浏览器访问 http://{NodeIP}:30081/account
我们已经看到访问了我们的熔断方法返回的内容,证明配置成功。
3.最后我们再次启动provider-service
执行 kubectl apply -f provider-service.yml
返回浏览器可以看到浏览器如下内容:
此时,spring-cloud-kubernetes的服务发现(轮询及熔断)就全部完成了,利用spring-cloud-kubernetes将原生的kubernetes服务带给了SpringCloud应用,帮助传统微服务更好的融合在kubernetes环境中。
错误处理
如果你遇到了如下错误
Message: Forbidden!Configured service account doesn't have access. Service account may have been revoked. services is forbidden: User "system:serviceaccount:default:default" cannot list resource "services" in API group "" in the namespace "default".
这表示了当前执行用户没有访问API得权限,具体可看
https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/
https://kubernetes.io/docs/reference/access-authn-authz/rbac/
解决:
新建一个endpoints-cluster-role.yml 如下:
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:namespace: defaultname: endpoints-reader
rules:
- apiGroups: [""]resources: ["endpoints"]verbs: ["get", "watch", "list"]
执行kubectl apply -f endpoints-cluster-role.yml
添加serviceacount的binding如下
kubectl create clusterrolebinding endpoints-reader-mydefault \--clusterrole=endpoints-reader \--serviceaccount=default:default
如上面还不能解决,也可以使用以下管理员权限(不推荐)
kubectl create clusterrolebinding permissive-binding \--clusterrole=cluster-admin \--user=admin \--user=kubelet \--group=system:serviceaccounts
springcoud-kubernetes实践之用kubernetes做注册中心(包括负载均衡熔断)相关推荐
- 【学习日记2023.6.9】之 SpringCloud入门(认识微服务_服务拆分和远程调用RestTemplate_Eureka注册中心_Ribbon负载均衡_Nacos注册中心)
文章目录 SpringCloud 1. 认识微服务 1.1 单体架构 1.2 分布式架构 1.3 微服务 1.4 SpringCloud 1.5 总结 2. 服务拆分和远程调用 2.1 服务拆分原则 ...
- 【微服务】Eureka+Ribbon实现注册中心与负载均衡
文章目录 前言 1.微服务引入 1.1.相关概念 1.2.软件架构的演进 1.2.1.单体架构 1.2.2.垂直架构 1.2.3.分布式架构 1.2.4.SOA架构 1.2.5.微服务架构 1.3.S ...
- Nacos作为服务注册中心及负载均衡、服务流量权重设置
如果我的博客对你有帮助,欢迎进行评论✏️✏️.点赞
- 为什么Eureka比ZooKeeper更适合做注册中心?
来源:https://www.cnblogs.com/jieqing/p/8394001.html 刚开始看到Eureka这个单词的时候真心不会念,查了后发现他有一个好听的名字,来,大家一起念 [ j ...
- java注册中心nacos_spring-cloud整合nacos做注册中心
前面讲了spring-cloud整合nacos做配置中心,这节讲一下nacos做注册中心 至于注册中心是什么,我就不讲了,不了解的可以去问度娘 下面我就直接开始了,也是比较简单的: 1.引入依赖 1. ...
- springboot整合dubbo\zookeeper做注册中心
springboot整合dubbo发布服务,zookeeper做注册中心.前期的安装zookeeper以及启动zookeeper集群就不说了. dubbo-admin-2.5.4.war:dubbo服 ...
- zookeeper注册中心 kerberos_ZooKeeper 并不适合做注册中心
zookeeper 的 CP 模型不适合注册中心 zookeeper 是一个非常优秀的项目,非常成熟,被大量的团队使用,但对于服务发现来讲,zookeeper 真的是一个错误的方案. 在 CAP 模型 ...
- 客户端启动报错java.lang.IllegalArgumentException: no server available的解决方案 SpringCloud中 Nacos做注册中心
客户端启动报错java.lang.IllegalArgumentException: no server available的解决方案 SpringCloud中 Nacos做注册中心(谷粒) 报错内容 ...
- e盾服务端源码_gRPC服务注册发现及负载均衡的实现方案与源码解析
今天聊一下gRPC的服务发现和负载均衡原理相关的话题,不同于Nginx.Lvs或者F5这些服务端的负载均衡策略,gRPC采用的是客户端实现的负载均衡.什么意思呢,对于使用服务端负载均衡的系统,客户端会 ...
最新文章
- 激光雷达基础-光探测和测距-遥感
- 常用MySQL函数存储过程_解析MySQL存储过程、常用函数代码
- 跟我学交换机配置(四)
- Spring Boot 13 之freemarker
- python带参装饰器的改良版
- Win7的市场份额终于超过XP了,以后可以逐渐考虑放弃ie6/7了!
- hibernate连接数据库配置
- 《计算机网络》学习笔记 ·004【网络层】
- Characteristics with cached values must be read-only
- 1005 Spell It Right (20)(20 分)
- 2022年计算机软件水平考试数据库系统工程师(中级)练习题及答案
- 宽凳公司关于无人驾驶高精地图的看法(2018.8)
- 数藏2.0故事中,元境开启“元宇宙丝绸之路”
- 百度面试题--度度熊想去商场买一顶帽子,商场里有N顶帽子,有些帽子的价格可能相同,度度熊想买一顶价格第三便宜的帽子,问第三便宜的帽子价格是多少?
- 物体尺寸测量-matlab
- codeforce 379C New Year Ratings Change 题解
- 模式识别-从贝叶斯决策理论看模式分类
- angular1的分页
- UPnP的功能和使用
- java抽取word,pdf的四种武器