使用 Kubernetes、Spring Boot 2.0 和 Docker 的微服务快速指南

【SFA官方翻译】使用 Kubernetes、Spring Boot 2.0 和 Docker 的微服务快速指南

原文链接:https://dzone.com/articles/quick-guide-to-microservices-with-kubernetes-sprin

作者:Piotr Mińkowski

译者:Darren Luo

在本教程中你将学习如何使用Kubernetes和Docker快速启动并运行Spring Boot微服务项目。

这是“xxx快速指南”系列的下一篇文章。这次,我们将讨论并在Kubernetes上运行Spring Boot微服务示例。本文的结构将和使用SpringBoot2.0、Eureka和SpringCloud的微服务快速指南非常相似,因为他们都描述了应用程序开发的相同方面。我将重点向你展示SpringCloud和Kubernetes在开发方面的异同。本文涉及的话题有:

1、在云原生开发中使用SpringBoot 2.0

2、使用SpringCloud Kubernetes项目为所有微服务提供服务发现

3、使用Kubernetes的Config Maps和Secrets为应用程序pod(Kubernetes中的最小管理单元)注入配置设置。

4、使用Docker构建应用程序镜像并使用YAML配置文件将他们部署到Kubernetes上。

5、将Spring Cloud Kubernetes和Zuul代理一起使用,为所有微服务公开一个独立的Swagger API文档。

当你构建微服务环境时,Spring Cloud和Kubernetes可能成为互相威胁的竞争解决方案。SpringCloud提供的如Eureka、Spring Cloud Config或Zuul等组件可能被Kubernetes的如service、Config maps、secrets或ingresses等内置对象所替代。但是即使你决定使用Kubernetes组件替代SpringCloud你也可以利用整个SpringCloud项目提供的一些有趣的功能。

在开发中帮助我们的一个非常有趣的项目是SpringCloud Kubernetes。虽然它还处于孵化阶段,但绝对值得在它上面献上一些时间。它将SpringCloud和Kubernetes集成在一起。我将向你展示如何使用客户端发现的实现,与Ribbon客户端的服务间通信以及使用Springcloud Kubernetes的Zipkin发现。

在我们处理源码之前,让我们看一下下面的图。它说明了我们示例程序的架构。它和之前文章提到的关于SpringCloud上的微服务架构非常相似。这里有三个独立应用程序(employee-service,department-service,organization-service),通过REST API互相通信。这些SpringBoot微服务使用一些Kubernetes内置机制:用于分发配置的config maps和secrets,用于服务发现的etcd和用于API网关的ingresses。

让我们继续执行。目前,SpringCloud的最新稳定版本是Finchley.RELEASE。该版本的spring-cloud-dependencies应该声明一个依赖管理的

BOM。

SpringCloud Kubernetes未在SpringCloud Release Trains发布,所以我们需要显式定义其版本。因为我们使用SpringBoot2.0,所以我们必须包含最新SNAPSHOT版本的spring-cloud-kubernetes工件,版本号为0.3.0.BUILD-SNAPSHOT。

本文提供的示例应用程序的源码可以在 Github 上的此 repository 获得。

前提要求

为了能部署和测试我们的示例微服务,我们需要准备一个开发环境。我们通过以下步骤实现:

1、你至少需要在你本地机器上运行的kubernetes(Minikube)or Openshift(Minishift)的单节点集群实例。你应该启动它并公开他们提供的嵌入式Docker客户端。有关Minishift的详细说明可以在我的在Openshift上部署Java应用程序的快速指南里找到。你也可以使用这份说明来运行Minikube,只需要用“minikube”替换单词“minishift”。事实上,如果你选择Kubernete或Openshift并没有关系,本教程的以下部分对他们都适用。

2、SpringCloud Kubernetes需要访问Kubernetes API,以便于能够检索为单个服务运行的pod的地址列表。如果你是用kubernetes,你应该只执行以下命令:

$ kubectl create clusterrolebinding admin --clusterrole=cluster-admin --serviceaccount=default:default


如果你在Minishift上部署你的微服务,首先你需要启用admin-user插件,然后以集群管理员身份登录并授予所需权限。

$ minishift addons enable admin-user

$ oc login -u system:admin

$ oc policy add-role-to-user cluster-reader system:serviceaccount:myproject:default

apiVersion: apps/v1

kind: Deployment

metadata:

 name: mongodb

 labels:

   app: mongodb

spec:

 replicas: 1

 selector:

   matchLabels:

     app: mongodb

 template:

   metadata:

     labels:

       app: mongodb

   spec:

     containers:

     - name: mongodb

       image: mongo:latest

       ports:

       - containerPort: 27017

       env:

       - name: MONGO_INITDB_DATABASE

         valueFrom:

           configMapKeyRef:

             name: mongodb

             key: database-name

       - name: MONGO_INITDB_ROOT_USERNAME

         valueFrom:

           secretKeyRef:

             name: mongodb

             key: database-user

       - name: MONGO_INITDB_ROOT_PASSWORD

         valueFrom:

           secretKeyRef:

             name: mongodb

             key: database-password

---

apiVersion: v1

kind: Service

metadata:

 name: mongodb

 labels:

   app: mongodb

spec:

 ports:

 - port: 27017

   protocol: TCP

 selector:

   app: mongodb

1、使用Config Maps和Secrets住配置

使用springcloud时,在你的系统中实现分发配置的最明显的选择是SpringCloud Config。用kubernetes,你可以使用Config Map。它保存了能在pod中使用或用户存储配置数据的配置数据键值对。它用于存储和共享非敏感,未加密的配置信息。要在你的集群中使用敏感信息,你必须使用Secrets。基于MongoDB链接设置的示例可以完美的演示使用这两个Kubernetes对象。在SpringBoot应用程序中,我们可以使用环境变量轻松注入它。这里是一个带有URI配置的application.yml文件的片段。


虽然用户名和密码是敏感字段,但数据库名不是,因此我们可以将其放在config map中。


当然,用户名和密码被定义在secrets中。


要将配置应用于Kubernetes集群,我们运行以下命令。

完成之后,我们应该将配置属性注入到应用 程序的pod中。在Deployment YAML文件中定义容器配置时,我们必须包含对环境变量和secrets的引用,如下所示。

apiVersion: apps/v1

kind: Deployment

metadata:

 name: employee

 labels:

   app: employee

spec:

 replicas: 1

 selector:

   matchLabels:

     app: employee

 template:

   metadata:

     labels:

       app: employee

   spec:

     containers:

     - name: employee

       image: piomin/employee:1.0

       ports:

       - containerPort: 8080

       env:

       - name: MONGO_DATABASE

         valueFrom:

           configMapKeyRef:

             name: mongodb

             key: database-name

       - name: MONGO_USERNAME

         valueFrom:

           secretKeyRef:

             name: mongodb

             key: database-user

       - name: MONGO_PASSWORD

         valueFrom:

           secretKeyRef:

             name: mongodb

             key: database-password


2、用Kubernetes构建服务发现

我们通常在kubernetes上用Docker容器运行为服务。一个或多个容器按pod分组,也是kubernetes中可被创建和管理的最小可部署单元。一个好的做法是在一个pod中只运行一个容器。如果你想扩展你的微服务,你只需要增加运行的pod数量。一个独立微服务的所有运行中的pod在逻辑上都被Kubernetes Service组合在一起。此服务可能在集群外可见,并且能够在所有运行中的pod之间对传入的请求进行负载均衡。下面的服务所有的pod组定义标记字段app等于employee。

服务可用于访问kubernetes集群外的应用程序或用于集群内的服务间通信。但是,使用SpringCloud Kubernetes可以更轻松的实现微服务之间的通信。首先,我们需要在项目pom.xml引入下面依赖。


然后我们微应用程序启用客户端发现,就像我们呢在Spring Cloud Netflix Eureka中一直做的发现一样。这允许你按名称查询Kubernetes endpoint。这种发现功能也被SpringCloud Kubernetes Ribbon或Zipkin项目用来分别微需要负载均衡的微服务获取已定义的pod列表,或者可用于追踪或聚合的Zipkin服务器。

本节最后一个重要事项是保证Spring应用程序名与Kubernetes服务名完全相同。对于应用程序employee-service就是employee。


使用Docker构建为服务并在Kubernetes上部署

在我们的示例微服务中没有任何不正常。我们已经包含了一些用于构建基于REST的微服务,集成MongoDB和使用Swagger2生成API文档的标准Spring依赖。


为了与MongoDB集成,我们应该创建一个继承了标准Spring Data CurdRepository接口。


实体类应该用Mongo的注解@Document,主键字段用@Id。

该repository bean已经被注入到controller类中。以下是我们呢employee-service中REST API的完整实现。

为了在kubernetes上运行我们的微服务,我们首先应该用mvn clean install 命令构建整个Maven项目。每个微服务都有一个放在根目录中的Dockerfile。这是为了employee-service定义的Dockerfile。

FROM open jdk:8-jre-alpine

ENV APP_FILE employee-service-1.0-SNAPSHOT.jar

ENV APP_HOME /usr/apps

EXPOSE 8080

COPY target//$APP_FILE  $APP_HOME/

WORKDIR $APP_HOME

ENTRYPOINT ["sh", "-c"]

CMD ["exec java -jar $APP_FILE"]

让我们为所有三个示例微服务构建 Docker 镜像。


最后一步是在 Kubernetes 上部署有应用程序的 Docker 容器。为此,只需在 YAML 配置文件上执行 kubectl apply 命令。 employee-service 的示例部署文件已经在步骤 1 中演示了。所有需要的部署字段都可以在项目repository的 kubernetes 目录中找到。


使用Spring Cloud Kubernetes Ribbon进行微服务之间的通信

所有微服务都部署在kubernetes上。现在,讨论服务间的通信相关的一些方面是很值得的。应用程序employee-service和其他微服务相比,它没有调用任何其他微服务。让我们看一下其他为服务调用由employee-service公开的API并与其它微服务进行通信(organization-service 调用 department-service API)。

首先,我们需要在项目中引入一些额外的依赖。我们使用SpringCloud Ribbon和OpenFegin。或者你也可以使用Spring的@LoadBalancedRestTemplate。


下面是department-service的主类。它使用@EnableFeignClients注解启用Fegin客户端。它的工作原理与基于 Spring Cloud Netflix Eureka 的服务发现相同。OpenFeign微客户端使用Ribbon进行负载均衡。Spring Cloud Kubernetes Ribbon 提供了一些 bean,通过 Fabric8 的 KubernetesClient 强制 Ribbon 使用 Kubernetes API 进行通信。


下面是用于调用 employee-service 公开的方法的 Feign 客户端实现。


最后,我们必须将Feign客户端的bean注入到REST controller。现在,我们可以调用 EmployeeClient 内部定义的方法,这相当于调用 REST endpoint。


5、使用Kubernetes Ingress构建API网关

Ingress是允许传入请求到达下游服务的一组规则。在我们的微服务架构中,ingress扮演API网关的角色。要创建它,我们应该首先准备一个YAML描述文件。描述文件应该包含网关可用的主机名和到达下游服务的映射规则。


你必须执行下面命令才能将该配置应用于 Kubernetes 集群。

$ kubectl apply -f kubernetes\ingress.yaml

要在本地测试本解决方案,我们必须在hosts文件里的 ingress 定义中插入 IP 地址和主机名之间的映射设置,如下所示。之后,我们可以使用自定义主机名通过 ingress 测试服务,如下所示:

http://microservices.info/employee


你可以通过执行 kubectl describe ing gateway-ingress 命令检查创建的 ingress 的详情。



使用 Swagger2 在网关上启用 API 规范


如果我们想为 Kubernetes 上部署的所有微服务公开一个 Swagger 文档该怎么做?好吧,这里的事情变复杂了。我们可以运行一个有 Swagger UI 的容器,并通过手动公开 ingress 映射所有路径,但是这不是一个好的解决方案。

在这种情况下,我们可以再次使用 Spring Cloud Kubernetes Ribbon,这次是与 Spring Cloud Netflix Zuul 一起使用。Zuul 将作为只为 Swagger API 服务的网关。


Kubernetes discovery 客户端将检测集群上公开的所有服务。我们只想显示三个微服务的文档。这就是我为什么为 Zuul 定义以下 route。


现在我们可以使用 ZuulProperties bean 从 Kubernetes discovery 中获取 route 的地址,并将他们配置为 Swagger 的资源,如下所示。


应用程序 gateway-service 应该和其他应用程序一样部署在集群上。你可以通过执行 kubectlgetsvc 命令来查看运行中的服务列表。Swagger 文档在地址 http://192.168.99.100:31237/swagger-ui.html 可以看见。

实际上我正在为 Spring Cloud Kubernetes 项目做准备,该项目仍处于孵化阶段。Kubernetes 作为一个平台的受欢迎程度在过去几个月中迅速增长,但是它仍有一些弱点。其中之一就是服务间通信。Kubernetes 没有给我们许多允许我们配置更高级规则的开箱即用的机制。这是 Kubernetes 上为服务网格创建如 Istio 或 Linkered 等框架的原因。这些项目仍然是相对较新的解决方案,但 Spring Cloud 是一个稳定坚固的框架。为什么不用它来提供服务发现、服务间通信或者负载均衡呢?感谢 Spring Cloud Kubernetes,这是可能的。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 198,322评论 5 465
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,288评论 2 375
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 145,227评论 0 327
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,015评论 1 268
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,936评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 47,534评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,995评论 3 389
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,616评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,907评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,923评论 2 315
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,741评论 1 328
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,525评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,016评论 3 301
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,141评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,453评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,054评论 2 343
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,249评论 2 339

推荐阅读更多精彩内容