谷歌大神为你解释Kubernetes, 微服务和容器化

来自谷歌云平台(Google Cloud Platform)的开发者布道师 Ray Tsang 和 Bret McGowen 在 SpringOne2GX 大会上分享了谷歌的 Kubernetes 的实践,来看看都有哪些内容吧!



谷歌大神为你解释Kubernetes, 微服务和容器化

微服务解决的痛点

谷歌大神为你解释Kubernetes, 微服务和容器化谷歌大神为你解释Kubernetes, 微服务和容器化


1. 包的大小和部署的难度成正比
传统 Java 开发将应用打成一个巨无霸的 Ear 或者 War 文件(Fat Jar),包的大小越大,部署的复杂度就越高。

在传统架构中,通常开发人员需要给测试人员一个部署文档,而这个文档通常是一个很长的 Wiki 或者 Doc。开发将部署的每一步都描述在这个文档里,如果漏掉了其中任何一步,测试就可能部署不成功,所以包越大,你花在部署的时间就越长,这种做法对两者都是一种伤害。

微服务架构,每个 jar 包独立部署,且非常小,导致部署简单,依赖清晰。通过声明的方式将环境用代码来描述(Infra as Code),自动化搭建环境,而不是依赖文档。

2. 包越大,启动速度越慢
这个很好理解,包越大,需要加载的内容就越多,有的项目启动时间甚至需要半个小时。

使用微服务架构,服务启动速度快,并且能够实现0宕机滚动升级。

谷歌大神为你解释Kubernetes, 微服务和容器化

微服务的搭建

谷歌大神为你解释Kubernetes, 微服务和容器化谷歌大神为你解释Kubernetes, 微服务和容器化


对于 Java 开发者,搭建微服务时建议使用 Spring Initializr (start.spring.io) 自动生成标准 Spring Boot 的框架代码,框架代码会声明所需要的依赖,例如 Mysql,Redis,Eureka,Zuul,Cloud messaging 等等,这样能够让开发者快速搭建一个微服务的项目,并且以此项目为规范,复制到其他项目,使得每个微服务的代码组织更规范,可读性更好。


如果不是 Spring 的开发者,也可以使用 Jboss Wildfly等其他微服务框架。


谷歌大神为你解释Kubernetes, 微服务和容器化

开始容器化

谷歌大神为你解释Kubernetes, 微服务和容器化

理论上来讲部署一个微服务,只需要执行 Java -jar 即可运行。但实际并没有人这么做,为什么?每个服务需要配置 JDBC 连接池,配置端口,做服务发现,服务隔离,如果人为的去维护每个微服务,那也将会是一场灾难。


容器和容器平台的诞生天生就能够解决这些问题。


1. 用代码描述环境 - DockerFile

谷歌大神为你解释Kubernetes, 微服务和容器化


DockerFile 解决的是用代码描述环境的问题。对这个 DockerFile 执行 Docker build 命令,可以构建出一个不变的镜像,这个镜像可以跑在任意的 Docker 环境里。这样就解决了基础设施即代码(Infra as Code)的问题。


2. 多容器应用的管理工具 - Compose

应用通常包含多个容器,Docker Compose 解决了应用里的多容器定义,运行的问题。 Compose 使用 YML 文件定义每个服务的依赖服务,自身暴露的端口等等。你只需要为你的微服务写好 YML 文件,然后执行 "docker-compose up", 那么你需要的所有容器都会启动起来,并且按照配置的方式去运行。


谷歌大神为你解释Kubernetes, 微服务和容器化

谷歌云平台的架构

谷歌大神为你解释Kubernetes, 微服务和容器化谷歌大神为你解释Kubernetes, 微服务和容器化


在谷歌,所有的服务都跑在容器里,每周谷歌启动20亿次容器。


谷歌大神为你解释Kubernetes, 微服务和容器化


从谷歌开发者的视角来看容器平台,当开发者需要部署一个应用时,他只需要声明这个应用运行的集群,集群中机器的配置,以及服务的拷贝数量。


谷歌大神为你解释Kubernetes, 微服务和容器化


谷歌云平台 Kubernetes 架构图:

1. 容器镜像存储在私有 Docker 镜像注册中心(目前使用的是 Artifactory)。
2. 写好 Config 文件,让 Kubernetes Master 执行部署任务。
3. Scheduler 定时从 Master 取出任务,并且找到终端(Kubelet,通常是虚拟机)实际执行这个任务。
4. 当找到Kubelet 之后,从 Artifactory 拉取镜像,启动容器。

谷歌大神为你解释Kubernetes, 微服务和容器化

Kubernetes 的特性

谷歌大神为你解释Kubernetes, 微服务和容器化

如何实现类似谷歌的微服务架构?光靠 Compose 肯定不够,因为 Compose 仅仅解决了应用的描述,运行的问题,但应用的编排,服务注册,服务发现,服务监控,故障恢复,DNS,负载均衡等等功能如何实现? Docker 的作用是计算资源和环境的描述和调度,Kubernetes 的作用是以应用为中心的生命周期的管理。


 Pods


Pods 的定义:Pods 包含一组容器,容器之间共享 namespace,共享存储,共享 IP 地址。


为什么会有 Pods?Pods 设计的目标是为了支持需要紧耦合容器的应用,让一个 Pods 里的多个容器变成对外服务的原子结构。例如 LAMP应用,这个应用依赖于多个不同的容器才能运行。


Pods 主要的目的,是为了解决一些辅助程序,例如内容管理系统,本地缓存管理,日志,备份,代理和更新等等,目的是让这几个集成的容器有统一的生命周期,降低独立维护容器的复杂度,所以 Pods 的初衷并不是运行同一个容器的多个副本。


Replication Controller


Replication Controller 会将集群保持在一个期望的状态。


传统的部署,需要一步一步部署好所有需要的东西,在 Kubernetes 里,你只需要描述你要部署生什么样,例如我要将某个服务部署6个实例。

谷歌大神为你解释Kubernetes, 微服务和容器化


此时的环境里有6个实例,突然,Node2节点发生了故障,导致集群里有2个节点挂掉。在传统项目里,我需要监控这个事件,并且手动去重启节点。


谷歌大神为你解释Kubernetes, 微服务和容器化


Replication Controller 会自动监控到这个事故,并且在可以的节点里寻找可用资源,部署这两个实例,直到最终集群里有6个实例。


谷歌大神为你解释Kubernetes, 微服务和容器化


Service


Service 是一组 Pods 的逻辑集合。在 Service 内部,Kubernetes 会创建负载均衡来将流量代理到可用的 Pods 上。Service 有一个固定的虚拟 IP( VIP)对外提供服务。


Service 的应用场景在于:假设后端有3个容器实例在运行,并且这3个实例是随时有可能坏掉的(Design for failure),前端的实例无需关注这三个实例各自的状态,而只需要声明它依赖的是后端某一个 Service 即可,让 Replication Controller 自动保证这个后端 Service 的可用性。


Labels


和名字和 UID 不同,Labels 不提供唯一性,通常,我们期望多个对象使用相同的 Label(s)。通过 Label 的设置和消费,可以轻松的过滤出需要找到的对象,例如:


谷歌大神为你解释Kubernetes, 微服务和容器化


这个命令能够从集群中所有的 Pods 里找出环境属于"Production",tier 等于"frontend"的 Pods。在前端服务的依赖声明里,和执行 Deploy 命令时,都可以用到 Labels 这个特性,实现服务或 Pods 的过滤。

谷歌大神为你解释Kubernetes, 微服务和容器化

金丝雀(Canary)部署

谷歌大神为你解释Kubernetes, 微服务和容器化谷歌大神为你解释Kubernetes, 微服务和容器化


金丝雀最早是矿工进煤矿时,会带一只金丝雀进去,如果金丝雀发生异常反应,则说明存在瓦斯泄露,如果金丝雀反应正常,则说明安全。


上图说明的是通过 Replication Controller,Labels 和 Service 实现金丝雀部署,通过 Label(Role=FE)找到 FE 服务的两个版本,V1和 V2,用 Service 来屏蔽版本的差异,并且将流量分发给 V1 和 V2 的 Pods。


谷歌内部的金丝雀发布的策略是将新的版本部署集群1%的机器,并且监控用户行为,如果用户对于新功能有更多的点击次数,则说明改功能可以部署更多实例,达到5-10%的比例,再根据监控结果决定是否部署到100%的机器。

谷歌大神为你解释Kubernetes, 微服务和容器化

服务发现

谷歌大神为你解释Kubernetes, 微服务和容器化

Kubernetes 里服务发现有多种方式:

1. 通过环境变量注入发现服务。
当 Pods 在集群的 Node 中运行时,Kubernetes 会为它增加一些列的环境变量。以 Redis 的服务发现为例:

谷歌大神为你解释Kubernetes, 微服务和容器化


上图的"redis-master"暴露了6379端口,以及在集群里的 IP 地址,如果你的容器声明了对"redis-master"服务的依赖,在你的 Pods 里就能够访问到这些环境变量。

2. 通过 Kubernetes DNS 服务器。
Kubernetes DNS 服务器会订阅 Kubernetes API创建 Service 的事件,并且为每个 Service 记录一个 DNS 的记录。这样做的好处是:只要 DNS 服务在集群里有访问权限,那么所有的 Pods 都能访问新注册的 Service。


举例:如果你有一个 Service 在 Kubernetes Namespace "my-ns"下 ,名字叫做叫 "my-service",那么一条叫做"my-service.my-ns"的记录就会被创建。所有在"my-ns" Namespace 里的 Pods 都能通过 DNS 查找到"my-service"。


谷歌大神为你解释Kubernetes, 微服务和容器化

总结

谷歌大神为你解释Kubernetes, 微服务和容器化谷歌大神为你解释Kubernetes, 微服务和容器化


Pod: 一组紧耦合的容器。

Replication Controller:持续的将当前的状态变成期望的状态。

Service:一组 Pod 的逻辑组合。

Labels:将 Pods 打上标签,进行多纬度的分组。


通过 Kubernetes 的这些特性,您可以轻松实现服务的服务注册,服务发现,高可用性,故障自动回滚,金丝雀发布等需求,实现微服务的落地。


本文转载自公众号【JFrog杰蛙DevOps】

推荐阅读

我最常用的Intellij IDEA快捷键

最好用的 IntelliJ 插件 Top 10

Jenkins Pipeline插件十大最佳实践!

Spring Cloud Hystrix的请求合并

白话:服务降级与熔断的区别


点击 “阅读原文” 搜搜本号内容