使用 Kubernetes 和 Ambassador API 网关部署 Java 应用程序

在本文中,您将学习如何将三个简单的Java服务部署到Kubernetes(通过新的Docker for Mac / Windows集成在本地运行),以及如何通过Kubernetes原生的Ambassador API网关向最终用户公开前端服务。所以,拿起你选择的含咖啡因的饮料,在你的终端机前享受舒适吧!

快速回顾:体系结构和部署

去年10月,我在Kubernetes支持下扩展了基于Java微服务的简单Docker Java Shopping容器部署演示。如果您有时间完成本教程,则可以在Docker映像中打包三个简单的Java服务(店面和库存管理程序Spring Boot服务以及产品目录Java EE DropWizard服务),并将生成的容器部署到由本地minikube支持的容器中Kubernetes集群。我还向您展示了如何通过使用NodePort服务映射和公开Kubernetes集群端口来向最终用户开放店面服务。尽管这对演示很有用,但许多人都问如何在API网关后面部署应用程序。这是一个很大的问题,因此我很想在本系列教程中再添加一篇文章,目标是在开源的kubernet -native Ambassador API网关之后部署“Docker Java Shopping”Java应用程序。

使用 Kubernetes 和 Ambassador API 网关部署 Java 应用程序_第1张图片


图1.使用大使API网关部署的“ Docker Java Shopping”应用程序

快速说明:为什么要使用API​​网关?

我相信,你们中的许多人以前都会使用(或至少接触过)API网关的概念。克里斯·理查森(Chris Richardson)在microservices.io上对细节进行了很好的概述,而创建大使API网关Datawire的团队也谈到了使用Kubernetes原生API网关的好处。简而言之,API网关让您可以集中处理应用程序中的许多跨领域问题,例如负载平衡、安全性和速率限制。运行Kubernetes原生API网关还可以让您将与部署和维护网关相关的一些操作问题(例如实现弹性和可伸缩性)转移给Kubernetes本身。

Java开发人员有很多API网关选择,例如开源Netflix的Zuul、Spring Cloud Gateway和Mashape的Kong;有云供应商的实现(例如Amazon的API Gateway);当然还有NGINX和HAProxy的传统收藏; 最后,还有更现代的变体,例如Traefik。为您的用例选择最佳的API网关可能涉及大量工作,这是基础结构的关键部分,它将涉及进入应用程序的所有流量。与任何关键技术选择一样,有许多折衷考虑。尤其要当心潜在的高耦合点-例如,我已经看到了将 Netflix的Zuul中动态部署“过滤器”(Groovy脚本)的功能,可以使业务逻辑在服务和网关之间传播(耦合)。随着最终用户流量的增加,还需要部署复杂的数据存储,例如,Kong需要安装Cassandra集群或Postgres才能水平扩展。

为了简单起见,在本文中,我将使用开源的Kubernetes原生Ambassador API网关。我喜欢Ambassador,因为实现的简单性降低了意外地将任何业务逻辑耦合到其上的能力,而且我可以通过声明性方法(我在所有其他Kubernetes配置中使用的方法)指定服务路由这一事实感到更加“云本机”。我还可以轻松地将路由存储在版本控制中,并将其与所有其他代码更改一起发送到CI / CD构建管道。

入门:NodePorts和LoadBalancers 101

首先,确保您从一个新的(空的)Kubernetes集群开始。因为我喜欢不时拥抱我的内行,所以我将使用Docker for Mac中的新Kubernetes集成来运行此演示。如果要继续进行,则需要确保已安装Edge版本的Docker for Mac或Windows的Docker,并且还按照Docker Kubernetes文档中的说明启用了Kubernetes支持。

接下来,克隆我的“ Docker Java Shopfront” GitHub存储库。如果您想探索目录结构并了解组成该应用程序的三个服务中的每一个的更多信息,那么我建议您看一下本系列的上一篇文章或相关的迷你书《用Java进行容器化持续交付》,开始了所有的这一切。成功克隆存储库后,您可以导航到kubernetes目录。如果您按照本教程进行操作,则将在此目录中进行修改,因此欢迎您存储自己的repo副本并创建一个分支,以将工作推送到该分支。我不建议跳过(或作弊),但是kubernetes大使 目录包含完整的解决方案,以防您需要检查工作!

$ git clone [email protected]:danielbryantuk/oreilly-docker-java-shopping.git
$ cd oreilly-docker-java-shopping/kubernetes
(master) kubernetes $ ls -lsa
total 24
0 drwxr-xr-x   5 danielbryant  staff  160  5 Feb 18:18 .
0 drwxr-xr-x  18 danielbryant  staff  576  5 Feb 18:17 ..
8 -rw-r--r--   1 danielbryant  staff  710  5 Feb 18:22 productcatalogue-service.yaml
8 -rw-r--r--   1 danielbryant  staff  658  5 Feb 18:11 shopfront-service.yaml
8 -rw-r--r--   1 danielbryant  staff  677  5 Feb 18:22 stockmanager-service.yaml

如果在您选择的编辑器/ IDE中打开shopfront-service.yaml,您将看到我将店面服务公开为可通过TCP端口8010访问的NodePort。这意味着可通过任意端口上的端口8010访问该服务。公开的(而不是被防火墙阻止的)群集节点IP的数量。

---
apiVersion: v1
kind: Service
metadata:
 name: shopfront
 labels:
 app: shopfront
spec:
 type: NodePort
 selector:
 app: shopfront
 ports:
 — protocol: TCP
 port: 8010
 name: http

通过minikube运行此服务时,NodePort允许您通过群集外部IP访问该服务。通过Docker运行服务时,NodePort允许您通过localhost和Kubernetes分配的端口访问服务。假设已将Mac或Windows的Docker配置为成功运行Kubernetes,则现在可以部署此服务:

(master) kubernetes $ kubectl apply -f shopfront-service.yaml
service "shopfront" created
replicationcontroller "shopfront" created
(master) kubernetes $
(master) kubernetes $ kubectl get services
NAME         TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)          AGE
kubernetes   ClusterIP   10.96.0.1              443/TCP          19h
shopfront    NodePort    10.110.74.43           8010:31497/TCP   0s

您可以看到已经创建了店面服务,并且尽管未列出外部IP,但是您可以看到stockmanager-service.yaml(8010)中指定的端口已映射到端口31497(此处的端口号可能有所不同) )。如果您正在使用适用于Mac或Windows的Docker,现在可以从本地主机中卷曲数据(因为Docker应用在幕后起作用),如果您使用的是minikube,则可以通过minikube ip在终端中输入来获取集群IP地址。

假设您使用的是Docker,并且仅部署了一个店面服务,则应该使用从kubectl get svc命令中看到的端口号从curl看到此响应(对我而言为31497):

(master) kubernetes $ curl -v localhost:31497
* Rebuilt URL to: localhost:31497/
* Trying ::1…
* TCP_NODELAY set
* Connected to localhost (::1) port 31497 (#0)
> GET / HTTP/1.1
> Host: localhost:31497
> User-Agent: curl/7.54.0
> Accept: */*
>
< HTTP/1.1 500
< X-Application-Context: application:8010
< Content-Type: application/json;charset=UTF-8
< Transfer-Encoding: chunked
< Date: Tue, 06 Feb 2018 17:20:19 GMT
< Connection: close
<
* Closing connection 0
{“timestamp”:1517937619690,”status”:500,”error”:”Internal Server Error”,”exception”:”org.springframework.web.client.ResourceAccessException”,”message”:”I/O error on GET request for \”http://productcatalogue:8020/products\": productcatalogue; nested exception is java.net.UnknownHostException: productcatalogue”,”path”:”/”}

您会注意到,由于这种卷曲,您将收到HTTP 500错误响应,这是可以预期的,因为您尚未部署所有支持服务。但是,在部署其余服务之前,您需要将所有服务的NodePort配置更改为ClusterIP。这意味着每个服务只能在群集中的其他网络上访问。您当然可以使用防火墙来限制NodePort公开的服务,但是通过将ClusterIP与我们的本地开发环境一起使用,您将被迫不要欺骗我们通过将部署的API网关以外的任何方式来访问我们的服务。

在编辑器中打开shopfront-service.yaml,然后将NodePort更改为ClusterIP。您可以在下面看到文件内容的相关部分:

---
apiVersion: v1
kind: Service
metadata:
 name: shopfront
 labels:
 app: shopfront
spec:
 type: ClusterIP
 selector:
 app: shopfront
 ports:
 — protocol: TCP
 port: 8010
 name: http

现在,您可以将productcatalogue-service.yaml和stockmanager-service.yaml文件中包含的服务修改为ClusterIP。

现在,您还可以删除现有的店面服务,准备在本教程的下一部分中部署完整堆栈。

(master *) kubernetes $ kubectl delete -f shopfront-service.yaml
service “shopfront” deleted
replicationcontroller “shopfront” deleted

部署完整堆栈

现在有了一个空的Kubernetes集群,您现在可以部署完整的三服务堆栈并在每个服务上获取相关的Kubernetes信息:

(master *) kubernetes $ kubectl apply -f .
service "productcatalogue" created
replicationcontroller "productcatalogue" created
service "shopfront" created
replicationcontroller "shopfront" created
service "stockmanager" created
replicationcontroller "stockmanager" created
(master *) kubernetes $
(master *) kubernetes $ kubectl get services
NAME               TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)    AGE
kubernetes         ClusterIP   10.96.0.1               443/TCP    20h
productcatalogue   ClusterIP   10.106.8.35             8020/TCP   1s
shopfront          ClusterIP   10.98.189.230           8010/TCP   1s
stockmanager       ClusterIP   10.96.207.245           8030/TCP   1s

您可以看到服务中声明的端口按指定的方式可用(即8010、8020、8030)。每个运行的Pod都有自己的群集IP和关联的端口范围(即每个Pod都有自己的“网络名称空间”)。我们无法访问群集外部的该端口(就像使用NodePort一样),但是在群集内部一切正常。

您还可以看到使用ClusterIP不会通过尝试卷曲端点来向外部公开服务(这一次您应该收到“连接被拒绝”):

(master *) kubernetes $ curl -v localhost:8010
* Rebuilt URL to: localhost:8010/
* Trying ::1…
* TCP_NODELAY set
* Connection failed
* connect to ::1 port 8010 failed: Connection refused
* Trying 127.0.0.1…
* TCP_NODELAY set
* Connection failed
* connect to 127.0.0.1 port 8010 failed: Connection refused
* Failed to connect to localhost port 8010: Connection refused
* Closing connection 0
curl: (7) Failed to connect to localhost port 8010: Connection refused

部署大使API网关

现在是时候部署Ambassador API网关,以便向最终用户展示您的店面服务。其他两个服务可以在集群中保持私有状态,因为它们是支持服务,而不必公开展示。

首先,创建一个使用Kubernetes批注的LoadBalancer服务,将请求从集群外部路由到适当的服务。将以下内容保存在名为的新文件中ambassador-service.yaml。注意getambassador.io/config注释。您可以使用Kubernetes批注将任意非识别元数据附加到对象,并且诸如Ambassador之类的客户端可以检索此元数据。你能弄清楚这个注释在做什么吗?

大使批注是网关工作方式的关键-网关如何将“进入”流量从集群外部(例如,最终用户请求)路由到集群内的服务。让我们分解一下:

  • “ getambassador.io/config:|” -指定此注释用于大使
  • “--”-仅声明您对YAML的热爱!
  • “ apiVersion:ambassador / v0” —指定大使API /模式版本
  • “ kind:映射”-指定您正在创建“映射”(路由)配置
  • “ name:shopfront” —是此映射的名称(将显示在调试UI中)
  • “ prefix:/ shopfront /”-是您要内部路由的URI的外部前缀
  • “ service:sh​​opfront:8010” —是您要路由到的Kubernetes服务(和端口)

简而言之,该注释指出,对带有前缀的LoadBalancer服务的外部IP(在Docker for Mac / Windows示例中为“ localhost”)的任何请求/shopfront/都将被路由到在(ClusterIP上运行的Kubernetes店面服务。 )端口8010。在您的示例中,当您在网络浏览器中输入http:// localhost / shopfront /时,您应该看到shopfront服务提供的UI。希望这一切都说得通,但如果不这样做,请访问吉特大使并提出任何问题,或在Twitter上将我ping通!

通过对大使路由的新发现(和世界上所有API网关的主宰只有几步之遥),您可以部署大使服务:

(master *) kubernetes $ kubectl apply -f ambassador-service.yaml
service “ambassador” created

您还需要部署负责与路由相关的繁重工作的Ambassador Admin服务(以及关联的吊舱/容器)。值得注意的是,路由是由“ sidecar”代理执行的,在这种情况下,该代理是Envoy代理。特使负责所有内Lyft生产网络流量,它的创作者马特·克莱因,写了很多非常有趣的 内容有关的细节。您可能还听说过新兴的“ 服务网格 ”技术,并且流行的Istio项目也使用Envoy。

无论如何,回到教程!您可以在getambassador.io网站上找到Ambassador Admin预先准备好的Kubernetes配置文件(对于本演示,您将使用该服务的“ no RBAC”版本,但是您也可以找到启用了RBAC的版本的配置文件。如果您正在使用基于角色的访问控制(RBAC)启用Kubernetes集群您可以在提出申请前在其下载配置文件和外观的副本,或者直接通过Interwebs应用服务:

(master *) kubernetes $ kubectl apply -f https://getambassador.io/yaml/ambassador/ambassador-no-rbac.yaml
service “ambassador-admin” created
deployment “ambassador” created

如果发出a kubectl get svc,则可以看到您的Ambassador LoadBalancer和Ambassador Admin服务已成功部署:

(master *) kubernetes $ kubectl get svc
NAME               TYPE           CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE
ambassador         LoadBalancer   10.102.81.42         80:31053/TCP     5m
ambassador-admin   NodePort       10.105.58.255           8877:31516/TCP   1m
kubernetes         ClusterIP      10.96.0.1               443/TCP          20h
productcatalogue   ClusterIP      10.106.8.35             8020/TCP         22m
shopfront          ClusterIP      10.98.189.230           8010/TCP         22m
stockmanager       ClusterIP      10.96.207.245           8030/TCP         22m

你会注意到大使服务的外部ip被列出来,这是一个已知的错误Docker的Mac/Windows。您仍然可以通过localhost访问LoadBalancer服务——尽管您可能需要等待一两分钟,以便在后台成功部署一切。

现在,让我们尝试使用先前在Ambassador注释中配置的`/ shopfront /路线来访问店铺。您可以卷曲localhost / shopfront /(无需指定端口,因为您将Ambassador LoadBalancer服务配置为侦听端口80):

{%gist https://gist.github.com/kelseyevans/1ad64d89409c1deeb5ee985b7f30a1aa% }

是这样!您现在通过Ambassador访问隐藏在Kubernete集群中的店面服务。您还可以通过您的浏览器访问shopfront UI,这提供了一个更友好的视图!

使用 Kubernetes 和 Ambassador API 网关部署 Java 应用程序_第2张图片

好处:大使诊断

如果您想查看大使诊断UI,那么您可以使用端口转发。我将在以后的文章中详细说明如何使用它,但目前您可以自己环顾四周。首先,您需要找到大使吊舱的名称:

{%gist https://gist.github.com/kelseyevans/a8fd8d73dcbc97191ec71b55514b7d90% }

这里我选ambassador-6d9f98bc6c-5sppl。您现在可以将端口从本地网络适配器转发到群集内部,并公开在端口8877上运行的Ambassador Diagnostic UI。
(master *) kubernetes $ kubectl port-forward ambassador-6d9f98bc6c-5sppl 8877:8877
``

您现在可以在浏览器中访问http:// localhost:8877 / ambassador / v0 / diag并环顾四周!

使用 Kubernetes 和 Ambassador API 网关部署 Java 应用程序_第3张图片

完成后,您可以通过ctrl-c退出端口转发。您还可以通过kubectl delete -f .在kubernetes目录中发出一个,删除已部署到Kubernetes集群中的所有服务。您还需要删除已部署的ambassador-admin服务。

(master *) kubernetes $ kubectl delete -f .
service "ambassador" deleted
service "productcatalogue" deleted
replicationcontroller "productcatalogue" deleted
service "shopfront-canary" deleted
replicationcontroller "shopfront-canary" deleted
service "shopfront" deleted
replicationcontroller "shopfront" deleted
service "stockmanager" deleted
replicationcontroller "stockmanager" deleted
(master *) kubernetes $
(master *) kubernetes $ kubectl delete -f https://getambassador.io/yaml/ambassador/ambassador-no-rbac.yaml
service "ambassador-admin" deleted
deployment "ambassador" deleted
``

下一步是什么?

我计划很快再写一篇文章,讨论如何启动/测试一个服务,因为Ambassador使这变得非常容易。我希望探索的其他主题是将所有这些集成到CD管道中,以及探索如何最好地设置本地开发工作流。与此密切相关的是,我还希望研究如何调试通过Kubernetes部署的Java应用程序。

您还可以通过文档阅读有关Ambassador本身的更多详细信息,包括添加auth / security,gRPC支持和TLS终止。

原文链接:https://dev.to//datawireio/deploying-java-apps-with-kubernetes-and-the-ambassador-api-gateway--6pn

你可能感兴趣的:(使用 Kubernetes 和 Ambassador API 网关部署 Java 应用程序)