\\\关键要点
\\
- 服务网格将所需的技术关注点透明地添加到微服务中。\\t
- 路由、弹性或认证等问题成为服务网格的职责。\\t
- 应用程序代码变得更加精简,并更多地关注实际的业务逻辑。\\t
- Istio通过边车代理容器增强工作负载,例如Kubernetes Pod。\\t
- Java EE通过支持开发人员实施精益业务逻辑与云原生技术完美地集成在一起。\
Java EE、云原生和服务网格——听起来似乎不应该把它们放在一起,又或者它们确实应该在一起呢?我们是否有可能在无需自己实现所有东西的情况下开发现代云原生Java企业应用程序来满足可扩展性、监控、跟踪或路由等问题?如果可以,那么该怎样实现?
\\采用微服务架构的企业面临着一个挑战,就是如何将服务发现、安全、监控、跟踪、路由或故障处理等技术问题以一致的方式添加到微服务当中。软件团队可以使用不同的技术来实现各自的服务,但他们需要遵守组织标准。通过添加共享资源(如API网关)将微服务耦合在一起,这在某种程度上破坏了微服务架构的原本意义。但不管怎样,我们应该避免冗余。
\\服务网格增强了每个微服务,而这些微服务是网格的一部分。这些增强功能以与技术无关的方式添加到系统中,不会影响到应用程序。应用程序专注于实现业务逻辑,由环境负责来处理技术依赖。
\\仪器和3D打印机
\\我们即将要给出的示例应用程序是仪器商店和3D打印机机器人。假设有这样的一个仪器商店SaaS应用程序,客户可以通过这个应用程序订购制作好的仪器。商店本身不直接提供仪器,而是将请求转发给通过3D打印技术生产仪器的机器人。
\\我们使用Java EE 8来实现这两种云原生微服务,部署到Kubernetes集群中,并由Istio来管理。
\\云原生技术简介
\\为了使用Kubernetes和Istio来管理Java EE应用程序,我们需要将它们打包成容器。 Docker镜像是通过定义Dockerfile文件来创建的。这些文件指定了整个应用程序的运行时,包括配置、Java运行时(即JRE和应用程序容器)以及所需的操作系统二进制文件。
\\下面的Dockerfile用于打包仪器商店应用程序,它使用了一个自定义基础镜像,其中包含了一个OpenLiberty应用服务器:
\\\FROM docker.example.com/open-liberty:1\\COPY target/instrument-craft-shop.war $DEPLOYMENT_DIR
\\
OpenLiberty基础镜像里已经包含了运行应用程序服务器所必需的东西。Dockerfile将添加可能需要用到的配置。通过使用这种简单的部署方法,我们不仅很好地利用了Docker的Copy-On-Write文件系统,而且带来了快速构建和缩短交付时间的可能性。
\\构建好的镜像将在编排环境中运行,在我们的例子里,就是要在Kubernetes群集中运行。
\\因此,与Kubernetes环境相关的文件也成为应用程序代码库的一部分。 YAML描述符包含了集群将如何运行、分布和组织我们的应用程序及Docker容器。
\\以下显示了仪器商店服务的定义,Kubernetes服务是对应用程序的逻辑抽象。
\\\kind: Service\apiVersion: v1\metadata:\ name: instrument-craft-shop\ labels:\ app: instrument-craft-shop\spec:\ selector:\ app: instrument-craft-shop\ ports:\ - port: 9080\ name: http
\\
该服务将请求分发给正在运行的实例,容器则由Kubernetes来管理。Kubernetes部署文件定义了如何执行Kubernetes Pod(也就是实际运行的工作负载)以及需要多少副本:
\\\kind: Deployment\apiVersion: apps/v1beta1\metadata:\ name: instrument-craft-shop\spec:\ replicas: 1\ template:\ metadata:\ labels:\ app: instrument-craft-shop\ version: v1\ spec:\ containers:\ - name: instrument-craft-shop\ image: docker.example.com/instrument-craft-shop:1\ imagePullPolicy: IfNotPresent\ restartPolicy: Always
\\
该服务将采用与定义的选择器相匹配的Pod。这里的应用程序标签实际上是标准名称,与我们的应用程序相匹配。我们最好可以再定义一个版本标签,以便在多个应用程序版本同时存在的时候能够进一步自定义服务路由。
\\集群外部的客户端将会调用仪器商店应用程序。Kubernetes的摄入资源将入口流量路由到相应的服务:
\\\kind: Ingress\apiVersion: extensions/v1beta1\metadata:\ name: instrument-craft-shop\ annotations:\ kubernetes.io/ingress.class: istio\spec:\ rules:\ - http:\ paths:\ - path: /instrument-craft-shop/.*\ backend:\ serviceName: instrument-craft-shop\ servicePort: 9080
\\
ingress.class注释指定了将istio作为入口实现,因此Kubernetes将为我们部署正确的Istio入口。
\\仪器商店应用程序将通过HTTP与后端的机器人应用程序进行通信。机器人应用程序定义了类似的Kubernetes服务和部署资源,名为maker-bot。
\\因为这两个应用程序都是Kubernetes群集的一部分,所以它们可以使用服务定义作为主机名进行通信。 Kubernetes通过DNS来解析服务名称。
\\下面是机器人客户端的代码:
\\\@ApplicationScoped\public class MakerBot {\\ private Client client;\ private WebTarget target;\\ @PostConstruct\ private void initClient() {\ client = ClientBuilder.newBuilder()\ .connectTimeout(1, TimeUnit.SECONDS)\ .readTimeout(3, TimeUnit.SECONDS)\ .build();\ target = client.target(\"http://maker-bot:9080/maker-bot/resources/jobs\");\ }\\ public void printInstrument(InstrumentType type) {\ JsonObject requestBody = createRequestBody(type);\ Response response = sendRequest(requestBody);\ validateResponse(response);\ }\\ private JsonObject createRequestBody(InstrumentType type) {\ return Json.createObjectBuilder()\ .add(\"instrument\