在 Geecon 2018年, Mauricio Salatino谈到了 Spring Cloud Kubernetes项目 。这个项目有很多好主意。令人印象最深刻的是Spring Cloud K8如何进行 服务发现 。它的工作原理如下:
听起来很简单,所以让我们测试吧!
服务发现,相同的命名空间不同的pod
让我们看看那一个Spring Cloud Application:
<b>package</b> com.example.service2.mvc; <b>import</b> org.springframework.web.bind.annotation.GetMapping; <b>import</b> org.springframework.web.bind.annotation.RestController; @RestController <b>public</b> <b>class</b> Controller { @GetMapping(path = <font>"/service2"</font><font>) <b>public</b> String respondPoint() { <b>return</b> </font><font>"Hello I'm service2"</font><font>; } } </font>
配置中:spring.application.name.
spring.application.name=service2-chart server.port=8081
现在让我们构建并将应用程序安装到Kubernetes集群中。 为了使它变得美观和流畅,准备了 helm chart .
helm chart应该安装一切,但让我们检查一下服务:
$ kubectl -n <b>default</b> 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服务名称,就是这样:
<b>package</b> com.example.service1.mvc; <b>import</b> org.springframework.cloud.openfeign.FeignClient; <b>import</b> org.springframework.web.bind.annotation.GetMapping; @FeignClient(name = <font>"service2-chart"</font><font>) <b>public</b> <b>interface</b> Service2Client { @GetMapping(</font><font>"/service2"</font><font>) String invokeService2(); } </font>
现在调用这个 service2-chart K8s 远程服务:
<b>package</b> com.example.service1.mvc; <b>import</b> org.springframework.beans.factory.annotation.Autowired; <b>import</b> org.springframework.web.bind.annotation.GetMapping; <b>import</b> org.springframework.web.bind.annotation.RestController; @RestController <b>public</b> <b>class</b> Controller { @Autowired <b>private</b> Service2Client service2Client; @GetMapping(path = <font>"/service1"</font><font>) <b>public</b> String respondPoint() { <b>final</b> String service2Output = service2Client.invokeService2(); <b>return</b> </font><font>"Hello I'm Service1 ->"</font><font>+service2Output; } } </font>
一切准备就绪,让我们测试一下:
Helm应该再次安装所有内容,这是所需的输出:
$ kubectl -n <b>default</b> 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 <b>default</b> service2-chart 1 Sun Dec 23 01:05:17 2018 DEPLOYED service2-chart-0.1.0 1.0 <b>default</b>
现在调用/service1 端点,这个端点会调用service2-chart K8s服务:
$ minikube service service1-chart --url http:<font><i>//192.168.99.100:32391</i></font><font> tomask79:spring-service1 tomask79$ curl http:</font><font><i>//192.168.99.100:32391/service1</i></font><font> {</font><font>"timestamp"</font><font>:</font><font>"2018-12-23T19:57:12.020+0000"</font><font>, </font><font>"status"</font><font>:500,</font><font>"error"</font><font>:</font><font>"Internal Server Error"</font><font>, </font><font>"message"</font><font>:</font><font>"Error creating bean with name 'ribbhttps:</font><font><i>//github.com/fabric8io/kubernetes-client]fabric8 kubernetes客户端[/url] 无法在默认命名空间中检索端点数据。</i></font><font> 要理解为什么让我们重复关于Kubernetes的基本规则: <ul> <li>在pod内运行的每个进程都在[url=https:</font><font><i>//kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/]服务帐户[/url]标识下运行。</i></font><font> <li>如果未指定,则每个pod都在“<b>default</b>”服务账户下运行。 <li>为了使pod获得K8s端点元数据,对应的默认服务账户的特权 需要获得至少是“view”clusterrole。 </ul> 只要</font><font>"view"</font><font> readonly [url=https:</font><font><i>//kubernetes.io/docs/reference/access-authn-authz/rbac/#user-facing-roles]clusterrole[/url] 就好:</i></font><font> <p>[code]$ kubectl create rolebinding <b>default</b>-view-binding --clusterrole=view --serviceaccount=<b>default</b>:<b>default</b> --namespace=<b>default</b> rolebinding.rbac.authorization.k8s.io/<b>default</b>-view-binding created </font>
再次curl调用/service1 端点:
$ curl http:<font><i>//192.168.99.100:32391/service1</i></font><font> Hello I'm Service1 ->Hello I'm service2 </font>
成功,我们通过一个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集群,默认命名空间:
这是测试之前所需的输出(注意命名空间):
$ 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 <b>default</b> 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:<font><i>//192.168.99.100:30176</i></font><font> tomask79:spring-service1 tomask79$ curl http:</font><font><i>//192.168.99.100:30176/service1</i></font><font> {</font><font>"timestamp"</font><font>:</font><font>"2018-12-23T21:47:00.649+0000"</font><font>,</font><font>"status"</font><font>:500,</font><font>"error"</font><font>:</font><font>"Internal Server Error"</font><font>, </font><font>"message"</font><font>:</font><font>"Error creating bean with name 'ribbview --serviceaccount=<b>default</b>:<b>default</b> clusterrolebinding.rbac.authorization.k8s.io/test-view created </font>
现在让我们再次调用service1-chart:
$ curl http:<font><i>//192.168.99.100:30176/service1</i></font><font> Hello I'm Service1 ->Hello I'm service2 </font>
好的,这次我们通过知道它的名字来调用生活在分离命名空间中的kubernetes服务 。我喜欢这种方法,因为您可以在不更改代码的情况下将您的微服务服务发现机制迁移 到kubernetes。
点击标题见原文!