在Geecon 2018年, Mauricio Salatino谈到了Spring Cloud Kubernetes项目。这个项目有很多好主意。令人印象最深刻的是Spring Cloud K8如何进行服务发现。它的工作原理如下:
- 在K8s集群中,没有必要拥有Eureka。K8s中的ETCD拥有所有必要的信息。
- 您的应用程序将通过指定的K8s服务名称联系K8s API服务器以获取端点信息。
- 然后可以通过Feign调用返回的服务。
- 要让DiscoveryClient正常运行,您需要做的 就是将Kubernetes服务名称与spring.application.name属性对齐。
听起来很简单,所以让我们测试吧!服务发现,相同的命名空间不同的pod
让我们看看那一个Spring Cloud Application:
package com.example.service2.mvc;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController;
@RestController public class Controller {
@GetMapping(path = "/service2") public String respondPoint() { return "Hello I'm service2"; } }
|
配置中:spring.application.name.
spring.application.name=service2-chart server.port=8081
|
现在让我们构建并将应用程序安装到Kubernetes集群中。 为了使它变得美观和流畅,准备了helm chart.
- $ eval $(minikube docker-env)
- $ mvn clean install
- $ helm install -n service2-chart service2-chart-0.1.0.tgz
helm chart应该安装一切,但让我们检查一下服务:
$ kubectl -n default get services NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 58d service2-chart NodePort 10.100.48.206 <none> 8081:30467/TCP 18s
|
好的,我们将Kubernetes服务名称与spring.application.name对齐。
准备另外一个Spring Boot调用service2-chart app/K8s service.
首先,使用Feign客户端,请注意我们只需要知道K8s服务名称,就是这样:
package com.example.service1.mvc;
import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.GetMapping;
@FeignClient(name = "service2-chart") public interface Service2Client {
@GetMapping("/service2") String invokeService2(); }
|
现在调用这个 service2-chart K8s 远程服务:
package com.example.service1.mvc;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController;
@RestController public class Controller {
@Autowired private Service2Client service2Client;
@GetMapping(path = "/service1") public String respondPoint() { final String service2Output = service2Client.invokeService2(); return "Hello I'm Service1 ->"+service2Output; } }
|
一切准备就绪,让我们测试一下:
- $ eval $(minikube docker-env)
- $ mvn clean install
- $ helm install -n service1-chart service1-chart-0.1.0.tgz
Helm应该再次安装所有内容,这是所需的输出:
$ kubectl -n default get services NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 58d service1-chart NodePort 10.101.7.4 <none> 8082:32391/TCP 3m service2-chart NodePort 10.100.48.206 <none> 8081:30467/TCP 17h
|
Helm charts 已经安装:
$ helm list NAME REVISION UPDATED STATUS CHART APP VERSION NAMESPACE service1-chart 1 Sun Dec 23 18:03:30 2018 DEPLOYED service1-chart-0.1.0 1.0 default service2-chart 1 Sun Dec 23 01:05:17 2018 DEPLOYED service2-chart-0.1.0 1.0 default
|
现在调用/service1 端点,这个端点会调用service2-chart K8s服务:
$ minikube service service1-chart --url http://192.168.99.100:32391
tomask79:spring-service1 tomask79$ curl http://192.168.99.100:32391/service1 {"timestamp":"2018-12-23T19:57:12.020+0000", "status":500,"error":"Internal Server Error", "message":"Error creating bean with name 'ribbhttps://github.com/fabric8io/kubernetes-client]fabric8 kubernetes客户端[/url] 无法在默认命名空间中检索端点数据。 要理解为什么让我们重复关于Kubernetes的基本规则: <ul> <li>在pod内运行的每个进程都在[url=https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/]服务帐户[/url]标识下运行。 <li>如果未指定,则每个pod都在“default”服务账户下运行。 <li>为了使pod获得K8s端点元数据,对应的默认服务账户的特权 需要获得至少是“view”clusterrole。 </ul> 只要"view" readonly [url=https://kubernetes.io/docs/reference/access-authn-authz/rbac/user-facing-roles]clusterrole[/url] 就好:
[code]$ kubectl create rolebinding default-view-binding --clusterrole=view --serviceaccount=default:default --namespace=default rolebinding.rbac.authorization.k8s.io/default-view-binding created
|
再次curl调用/service1 端点:
$ curl http://192.168.99.100:32391/service1 Hello I'm Service1 ->Hello I'm service2
|
成功,我们通过一个K8s服务的名字调用在同一名称空间内的服务!
服务发现,不同的命名空间,不同的pods
这一次让我们通过知道它的名字来尝试调用生活在分离命名空间中的kubernetes服务 。只需很少的编码更改即可支持此功能!
首先让我们创建名为“test”的新命名空间:
$ kubectl create namespace test
|
现在让我们将service2-chart安装到新的命名空间中(这里你需要helm ):
$ helm install -n service2-chart --namespace test service2-chart-0.1.0.tgz
|
下一步是告诉service1中的ribbon在哪里查找刚刚安装的service2-chart服务。
默认情况下,它列出当前名称空间中的端点。要告诉他在另一个名称空间中搜索service2-chart, 您需要将以下属性添加到application.properties中:
service2-chart.ribbon.KubernetesNamespace=test
|
现在让我们重建并重新安装service1应用程序到K8s集群,默认命名空间:
- $ mvn clean install
- $ helm package ./service1-chart --debug
- $ helm install -n service1-chart service1-chart-0.1.0.tgz
这是测试之前所需的输出(注意命名空间):$ helm list NAME REVISION UPDATED STATUS CHART APP VERSION NAMESPACE service1-chart 1 Sun Dec 23 22:45:24 2018 DEPLOYED service1-chart-0.1.0 1.0 default service2-chart 1 Sun Dec 23 22:09:00 2018 DEPLOYED service2-chart-0.1.0 1.0 test
|
好的,让我们尝试调用service1-chart服务,该服务在另一个命名空间中调用service2-chart:
$ minikube service service1-chart --url http://192.168.99.100:30176 tomask79:spring-service1 tomask79$ curl http://192.168.99.100:30176/service1 {"timestamp":"2018-12-23T21:47:00.649+0000","status":500,"error":"Internal Server Error", "message":"Error creating bean with name 'ribbview --serviceaccount=default:default clusterrolebinding.rbac.authorization.k8s.io/test-view created
|
现在让我们再次调用service1-chart:
$ curl http://192.168.99.100:30176/service1 Hello I'm Service1 ->Hello I'm service2
|
好的,这次我们通过知道它的名字来调用生活在分离命名空间中的kubernetes服务 。我喜欢这种方法,因为您可以在不更改代码的情况下将您的微服务服务发现机制迁移 到kubernetes。
点击标题见原文!