随着本文逐步学习使用Kubernetes开源平台和Docker创建用于构建微服务的持续交付配置。
在我之前的一篇文章中,描述了一个用Docker和Jenkins构建微服务的持续交付配置的例子。 这是一个简单的配置,只使用Docker Pipeline Plugin来构建和运行带有微服务的容器。 这个解决方案有一个很大的缺点 - 我们不得不链接所有的容器,以提供部署在这些容器内的微服务之间的通信。 今天,我将向您展示一个聪明的解决方案,帮助我们避免这个问题 - Kubernetes。
原理
Kubernetes是一个最初是由Google设计的开源平台,用于在主机集群之间自动部署、扩展和运行应用程序容器,提供以容器为中心的基础架构。 它具有许多对于在生产中运行的应用程序特别有用的功能,如服务命名和发现、负载均衡、应用程序运行状况检查、横向弹性伸缩和滚动更新等。 在进入例子之前,我们应该知道Kubernetes的几个重要概念。
Pod - Kubernetes的基本单元。 它可以由一个或多个容器组成,这些容器在同一个物理主机内,并共享相同的资源。 在pod内部署的所有容器都可以通过localhost看到其他容器。 每个Pod在集群中具有唯一的IP地址。
Service - 一组一起工作的Pod。 默认情况下,Service在集群内部公开,但也可以暴露在集群外部的外部IP地址上。 我们可以使用以下四种方式之一来暴露它:ClusterIP、NodePort、LoadBalancer和ExternalName。
Replication Controller (RC)- 一种特定类型的Kubernetes控制器。 它通过在集群中运行指定数目的pod副本来处理复制和扩展。 如果底层节点发生故障,它也负责替换失败Pod。
Kubernetes集群的高可用配置不是一件容易的任务。 幸运的是,有一个工具可以让本地运行Kubernetes更简单 - Minikube。 Minikube可以在虚拟机内部运行单节点集群,这对于想要尝试的开发人员来说非常重要。 开始真的很简单,对于Windows上的例子,您必须下载minikube.exe和kubectl.exe,并将它们添加到PATH环境变量中。 然后,您可以使用minikube start命令从命令行启动它,并通过调用kubectl命令来使用几乎所有的Kubernetes功能。 命令行选项的另一种选择是Kubernetes Dashboard。 它可以通过调用minikube仪表板命令启动。 我们可以从UI仪表板创建,更新或删除部署,还可以列出并查看所有Pod、Service、Ingress、RC等的配置。如下图所示是Kubernetes Dashboard,其中包含例子的部署列表:
应用
我们的例子中的微服务体系结构的概念与我在本文开头提到的有关Docker和Jenkins的持续交付的文章中的概念非常相似。 例子也有Account和Customer的微服务, Customer Service在搜索Customer帐户的同时与Customer Service进行交互。 我们不使用网关(Zuul)和发现(Eureka)Spring Boot服务,因为我们在Kubernetes中内置这些机制。 这是一张图解说明所提出解决方案的架构。 每个微服务的pod由两个容器组成:第一个是微服务应用程序,第二个是Mongo数据库。 Account和Customer的微服务都有自己的数据库存储所有的数据。 每个Pod都是作为服务暴露的,并且可以通过在Kubernetes上的名字进行搜索。 我们还配置Kubernetes Ingress,它充当我们微服务的网关。
此例子的源代码在GitHub上提供。 它由两个模块组成:Account Service和Customer Service。 它基于Spring Boot框架,但不使用除Feign客户端之外的任何Spring云项目。 这里是Account Service的dockerfile。 我们使用一个小的openjdk image - alpine。 因此,使用标准的openjdk作为base image时,我们的结果image大约有120MB而不是〜650MB。
FROM openjdk:alpine
ADD target/account-service.jar account-service.jar
ENTRYPOINT ["java", "-jar", "/account-service.jar"]
EXPOSE 2222
为了启用MongoDB支持,我将spring-boot-starter-data-mongodb依赖关系添加到了pom.xml中。 我们还必须提供连接数据到application.yml并用@Document注释实体类。 最后,声明存储库接口扩展MongoRepository,其中实现了基本的CRUD方法。 我们添加两个自定义查找方法:
public interface AccountRepository extends MongoRepository {
public Account findByNumber(String number);
public List findByCustomerId(String customerId);
}
在Customer Service中,我们打算从Account Service调用API方法。 这是声明式REST客户端@FeignClient声明。 所有具有Account Service的Pod在服务名称和默认服务端口2222下均可用。此类设置是Kubernetes上服务配置的结果。 我将在下一节中对其进行描述。
@FeignClient(name = "account-service", url = "http://account-service:2222")
public interface AccountClient {
@RequestMapping(method = RequestMethod.GET, value = "/accounts/customer/")
List getAccounts(@PathVariable("customerId") String customerId);
}
我们的微服务的docker image可以使用下面的命令来构建。 构建之后,您应该将该image推送到docker hub 或您的registry。 在下一节中,我将介绍如何在Kubernetes上使用它们。 所描述的微服务的Docker镜像也可以在我的Docker Hub公共存储库上用作piomin / account-service和piomin / customer-service。
docker build -t piomin/account-service .
docker push piomin/account-service
部署
您可以使用kubectl运行命令、Minikube dashboard或使用kubectl create命令的YAML配置文件在Kubernetes上创建部署。 我将向您展示如何从YAML配置文件创建所有资源,因为我们需要一步创建多容器部署。 这是Account Service的部署配置文件。 我们必须提供部署名称,image名称和暴露端口。 在副本属性中,我们正在设置创建的pod的请求数量。
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: account-service
labels:
run: account-service
spec:
replicas: 1
template:
metadata:
labels:
run: account-service
spec:
containers:
- name: account-service
image: piomin/account-service
ports:
- containerPort: 2222
protocol: TCP
- name: mongo
image: library/mongo
ports:
- containerPort: 27017
protocol: TCP
我们正在通过运行下面的命令来创建新的部署。 相同的命令用于创建Service和ingress。 只有YAML文件格式不同:
kubectl create -f deployment-account.yaml
现在,我们来看看Service配置文件。 我们已经创建了部署。 如您所见,dashboard image已从Docker Hub中取出; pod和副本集已经创建。 现在,我们想在外面暴露我们的微服务。 这就是为什么需要Service。 我们还在其默认端口上公开Mongo数据库,以便能够连接数据库并从MongoDB客户端创建集合。
kind: Service
apiVersion: v1
metadata:
name: account-service
spec:
selector:
run: account-service
ports:
- name: port1
protocol: TCP
port: 2222
targetPort: 2222
- name: port2
protocol: TCP
port: 27017
targetPort: 27017
type: NodePort
在为Customer Service创建类似的配置后,我们已经暴露了我们的微服务。在Kubernetes内部,它们在默认端口(2222和3333)和服务名称上可见。这就是为什么在客户服务REST客户端(@FeignClient)中,我们声明了URL http:// account-service:2222。无论创建了多少个Pod,服务将始终在该URL上可用,并且请求在所有Pod之间进行负载均衡。如果我们希望访问Kubernetes以外的每个服务,例如,在Web浏览器中,我们需要使用在容器默认端口下方可见的端口来调用它 - 在该Account Service的示例中,它是31638端口,并且对于Customer Service, 31171端口。如果您在Windows上运行Minikube,则您的Kubernetes可能位于192.168.99.100地址下,因此您可以尝试使用URL http://192.168.99.100:31638/accounts呼叫帐户服务。在进行这样的测试之前,您需要在Mongo数据库和用户微型/微型(在application.yml中为该服务设置)上创建一个集合。
好了,我们在两个不同的端口下有两个微服务,这不完全是我们所需要的。 我们需要一些IP可用的网关,通过匹配请求路径来代理我们的请求,以及确切的服务。 幸运的是,Kubernetes也提供这样的选项。 这个解决方案是Ingress。 这里是YAML入口配置文件。 定义了两个规则,第一个是Account Service,第二个是Customer Service。 我们的网关在micro.allhost名称和默认HTTP端口下可用。
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: gateway-ingress
spec:
backend:
serviceName: default-http-backend
servicePort: 80
rules:
- host: micro.all
http:
paths:
- path: /account
backend:
serviceName: account-service
servicePort: 2222
- path: /customer
backend:
serviceName: customer-service
servicePort: 3333
为了使网关能够正常工作,最后一件事就是将下列条目添加到系统主机文件(Linux的/ etc / hosts和windows的C: Windows System32 drivers etc hosts)中。 现在,您可以尝试从您的网络浏览器调用http://micro.all/accounts或http://micro.all/customers/ ,该帐户在后台也调用帐户服务。
[MINIKUBE_IP] micro.all
总之,Kubernetes是微服务集群管理和编排的好工具。 它在快速发展中,仍然是一个比较新的解决方案。 它可以与Spring Boot堆栈一起使用,或者作为Spring Cloud Netflix OSS(这似乎是目前最流行的微服务解决方案)的替代品。 它还有一个UIdashboard ,您可以在其中管理和监视所有资源。 生产级配置可能比使用Minikube的单一主机开发配置更复杂,但我不认为这是针对Kubernetes。
译者介绍:
楼炜 Jet,云技术社区金牌翻译,现任云星数据副总裁兼研发中心总监,业内资深的云计算专家, 10年云计算经验,7年+ IaaS、PaaS经验。著有: 《企业级IaaS架构的深度解析》、《企业级私有云构建的架构师阵型及架构策略》等文章
领取专属 10元无门槛券
私享最新 技术干货