本文为译文,英文原文地址:kublr.com/blog/implem…html
本文转载自:www.servicemesher.com/blog/hands-…git
更多 Service Mesh 文章请访问:www.servicemesher.comgithub
本文为该教程的第1部分。web
若是你以前没有据说过Service Mesh,不用担忧。虽然从可用文档、公开讨论和Github活跃度来看,它是一个相对较新的技术,与基于容器和微服务架构类似尚未被普遍采用,可是它将会对软件架构带来深远影响。本文将帮助您了解Service Mesh的基础知识和教程,以及如何实现它并从基础架构获益。redis
Service Mesh的两个主要目标是容许洞察先前不可见的服务通讯层,并获取对全部微服务间像动态服务发现、负债均衡、超时、回退、重试、断路器、分布式调用链路追踪和安全策略的执行等通讯逻辑的彻底控制。更多细节请查看Istio流量审计和分布式链路追踪相关资料。数据库
Kubernetes已经拥有开箱即用的“Service Mesh”。它的“service”资源,提供了针对指定须要的pod的服务发现功能和请求的负载均衡。经过在集群的每一个主机上配置管理iptables规则使一个“service”生效,只容许轮询式负载均衡途径,没有重试或回退逻辑,除此以外没有其余咱们可能想要的用一个现代的Service Mesh解决的功能。然而,若在集群中实现一个功能齐全的Service Mesh系统(Linkerd、Istio或Conduit),将为您提供如下可能性:windows
下面是两种部署Service Mesh的方式:后端
做为主机共享代理,Kubernetes术语中的DaemonSet。若是同一主机上存在许多容器,而且还可能利用链接池来提升吞吐量,则此类部署将使用较少的资源。可是,若是一个代理中的故障将搞垮该主机上的整个容器队列,而不是破坏单个服务(若是它被用做sidecar代理)。api
做为容器sidecar,将代理注入到每一个pod定义中与主服务一块儿运行。若是使用像Linkerd这样更加“重量级”的代理,这个部署将为每一个pod增长约200MB的内存。但若是使用较新的Conduit,每一个pod只需10MB左右。Conduit尚未Linkerd的全部功能,因此咱们尚未看到二者的最终比较。一般,“每一个pod中一个sidecar”是一个不错的选择,这样尽量的将代理故障限制在单个pod中,不要影响同一主机上的其余pod。浏览器
为何须要建立Service Mesh架构?让咱们看一下不一样类型的应用程序架构的两个图表来讲明需求。
第一个示例是一个老式基于MVC架构的Web服务,是做为单体架构all-in-one应用程序。可能天天服务数百万个请求,但没有复杂的功能,而且底层服务的通讯简单明了:Nginx均衡Apache实例的全部流量,Apache又从数据库/文件存储中获取数据并返回请求页面。这个示例所采用的架构不会从服务网格中获取太多收益。因为单体应用没有采用服务调用的方式,因此全部功能是耦合在一块的,开发者没有开发处理服务间路由和通讯的代码。在单体应用,全部核心组件都位于同一台机器上,不经过网络进行通讯,没有REST API或gRPC。全部“业务逻辑”都在一个应用程序中,在每一个Apache Web服务器上做为总体部署。
第二个例子是一个基于现代微服务架构的应用程序,它有不少进程和幕后逻辑。它作了不少事情,好比学习访问者模式和偏好来个性化他们在网站上的体验,通知用户他们最喜欢的topic更新,等等。您能够想象在全部这些微服务之间发生的许多复杂过程,分布在数千个容器和数百个节点上。请注意,咱们的插图很是简化。实际上,咱们显示大型云原生应用程序的真实架构中简化了不少细节。
在这个实例程序中咱们的每一个微服务都有一些代码用于处理彼此间的通讯,设置重试策略、超时、异常处理等等(在网络故障的状况下)。咱们还看到这是一个多语言环境,其中不一样团队使用Scala、Golang、Node.js或Python开发本身的服务组件。全部组件均可以经过REST API或gRPC相互通讯,每一个团队都花费时间和精力在他们本身的组件中实现通讯逻辑,使用他们各自的语言选择,所以他们不能共享彼此的库和函数,至少能够节省时间并使用插入应用程序的全部组件的统一解决方案做为依赖。此外,查询服务发现机制的函数(如Consul或ZooKeeper)或读取外部传递给应用程序的一些配置,须要向Prometheus/InfluxDB报告延迟和响应相关指标。这包括有关缓存响应时间(redis或memcached缓存)的信息,该缓存响应时间一般位于另外一个节点上,或者做为整个单独的群集,可能会过载并致使高延迟。除了团队爆炸日志和截止日期临近以外,全部这些都是服务代码的一部分,须要维护。开发人员不肯花时间在代码的运维相关部分任务上,例如添加分布式追踪和监控指标(不喜欢排除故障和分析)或处理可能的网络故障,实施回退和重试预算。
在这种环境中,Service Mesh将节省开发时间,并容许以统一的方式以集中式地控制通讯。那咱们如何将这种通讯层机制改成统一的“Service Mesh”?咱们把微服务间通讯、路由、服务发现、延迟指标、请求追踪、和微服务中的一些类似代码彻底抽取到服务外边,搞一个可以处理这些甚至更多功能的单例进程为每一个微服务去处理这些公共逻辑。幸运的是这些工具已经存在,像Twitter、Lyft、Netflix这样的公司已经开源了本身的工具,其余贡献者也能够基于这些库开发本身的工具。目前为止咱们有Linkerd、Conduit、Istio和Envoy供选择。Istio基于Envoy构建的,它是一个控制平面,Envoy和Linkerd均可以用做它的数据平面代理。控制平面容许集群运维人员以集中式地设置特定设置,而后将其分布在数据平面代理上并从新配置它们。
Linkerd和Conduct由Buoyant开发,开发者是一些曾经在Twitter工做的工程师。目前Linkerd是最经常使用的Service Mesh之一,而Conduit是从头开始专门为Kubernetes构建的轻量级sidecar,很是快速且很是适合Kubernetes环境。在撰写本文时,Conduit仍处于积极发展阶段。
让咱们看一下从依赖于应用程序的通讯逻辑到“Service Mesh”架构的变化。
最值得注意的是,全部代理均可以在同一个地方配置和更新,经过他们的控制平面(或经过某些存储库中的配置文件, 取决于所选的工具和部署方法),咱们能够在数千个代理配置特定规则。所以,路由、负载均衡、度量指标收集、安全策略实施、断路器、数据传输加密,全部这些操做都将严格遵循由集群管理员应用的一系列规则。
乍一看,这种将微服务通讯机制分离到单独的架构层的新概念引入了一个问题:是否值得配置和维护一整套复杂的特殊代理?要回答这个问题,您须要估算应用程序规模和复杂程度。若是您只有几个微服务和数据存储端点(例如,一个用于记录的ElasticSearch集群,一个用于度量的Prometheus集群,具备两个或三个主应用程序数据的数据库),那么实现服务网格可能对您的环境来讲没有太大必要。可是,若是您的应用程序组件分布在数百或数千个节点上,而且具备20+微服务,采用Service Mesh你将受益不浅。
即便在较小的环境中,若是您但愿将重试和断路行为与应用程序自己分离(例如,从管理链接和退出的代码,以免重试致使其余服务或数据库过载),您可使用服务网格 从您的应用程序开发人员中删除此网络逻辑维护负担,你可使用服务网格下降应用程序开发人员维护网络逻辑的负担。所以,他们将更多地关注业务逻辑,而不是参与管理和调整全部微服务的相互通讯。
运维团队一旦配置服务网络,就能够集中调整,最大限度地减小在应用程序组件通讯上花费的精力。
Istio是一个集中全部Service Mesh特性的完美例子,它有几个“主组件”来管理全部“数据平面”代理(这些代理能够是Envoy或Linkerd,但默认状况下,它是Envoy,这是咱们在教程中使用的内容,而Linkerd集成仍在进行中)。
如下是官方网站上Istio架构的图表:
译者注:图中的istio-auth
现已更名为citadel
。
您能够在官方文档中阅读更多内容,可是出于本教程的目的,如下是Istio组件及其功能的摘要:
控制平面
数据平面
在下面的教程中,咱们将使用Istio来演示一个最强大的功能:“按请求路由”。如前面说的那样,它容许将选定HTTP头标记的特定请求路由到仅可经过第7层代理实现的特定目标。没有第4层负载均衡器或代理能够实现该功能。
对于本教程,咱们假设您正在运行Kubernetes集群(提示:您能够在几分钟内遵循这些说明或启动新集群,或者使用“Kublr-in-a-box”经过几个简单的步骤设置本地群集)。对于本教程,有1个主节点和2个工做节点的小型集群应该足够了。
按官方教程安装在Kubernetes集群中安装控制平面。这个安装步骤依赖你的本地环境(windows、Linux仍是MAC),因此咱们不能复制使用本地标准指令设置应用程序,咱们使用istioct和kubectl两个CLI工具管理库尔netes和istio。请安装下面简明扼要的描述去作(若是不起做用,请逐步使用官方说明):
设置kubernetes集群(使用上面列出的方法,或使用您现有的测试/开发群集)
下载kubectl并配置到环境环境(用它管理你的kubernetes环境)
下载istioctl并配置到环境变量(使用它把Envoy代理注入到每一个pod中设置路由和策略)下面是简单安装说明:
(1)在MAC或Linux命令行上实行
curl -L https://git.io/getLatestIstio | sh -
复制代码
(2)在windows上下载istio.zip并解压文件,将文件路径配置到你的环境变量中
(3)切换到解压环境上面文件解压路径中,并执行
kubectl apply -f install/kubernetes/istio-demo.yaml
复制代码
另外一种安装方式是使用Kublr安装你的kubernetes集群环境——一个简单的方法是经过云提供商(阿里云、腾讯云、aws、azure、gcp或者quick start)上拉起一个kubernetes集群。 kublr。
找到%USERPROFILE%/.kube/config
文件拷贝到你的宿主机目录下(~/.kube/config
),调到以下页面:
使用配置文件中的管理员帐号和密码登录到kubernetes dashboard,你应该可以看到这个仪表盘,点击侧边栏显示的default这个 namespace:
Istio组件将安装到它们本身的namespace中。调到istio下载目录,并执行命令:
kubectl apply -f install/kubernetes/istio-demo.yaml
复制代码
你将看到一些列的组件被建立,详情请看官方文档或者你也能够打开yaml文件查看相应组件,每一个资源都记录在该文件中。而后咱们能够浏览namespace并查看全部已成功建立的内容:
在组件建立期间点击istio-system查看是否有错误或者issue,看起来应该和下面相似:
从图中能够看到有50个事件,你能滚动屏幕去看“成功”状态,并注意有些地方可能存在错误。若是有错误,你能够去github上提交issue。
咱们须要找到istio-ingress服务的入口,去了解那里发送流量。回到kubernetes dashboard的侧边栏并跳转到istio-system这个namespace下。若是建立后在这个namespace下不可见,刷新浏览器试试。点击“Services”找到external endpoint,以下图所示:
在咱们的例子中,这是AWS弹性负载均衡器,但你可能会看到IP地址,具体取决于集群设置。咱们将使用此端点地址访问咱们的演示Web服务。
这是本教程中最好玩的部分。咱们来检查一下这个Service Mesh的路由功能。首先咱们将像前面同样经过蓝绿发布咱们的demo实例服务。将如下内容复制到名为的my-websites.yaml文件中。
apiVersion: apps/v1beta1
kind: Deployment
metadata:
name: web-v1
namespace: default
spec:
replicas: 1
template:
metadata:
labels:
app: website
version: website-version-1
spec:
containers:
- name: website-version-1
image: aquamarine/kublr-tutorial-images:v1
resources:
requests:
cpu: 0.1
memory: 200
---
apiVersion: apps/v1beta1
kind: Deployment
metadata:
name: web-v2
namespace: default
spec:
replicas: 1
template:
metadata:
labels:
app: website
version: website-version-2
spec:
containers:
- name: website-version-2
image: aquamarine/kublr-tutorial-images:v2
resources:
requests:
cpu: 0.1
memory: 200
---
apiVersion: apps/v1beta1
kind: Deployment
metadata:
name: web-v3
namespace: default
spec:
replicas: 1
template:
metadata:
labels:
app: website
version: website-version-3
spec:
containers:
- name: website-version-3
image: aquamarine/kublr-tutorial-images:v3
resources:
requests:
cpu: 0.1
memory: 200
---
apiVersion: v1
kind: Service
metadata:
name: website
spec:
ports:
- port: 80
targetPort: 80
protocol: TCP
name: http
selector:
app: website
复制代码
在你的pod和Envoy代理一块儿使用时请注意,“app”这个label的存在(它用于请求跟踪功能),在服务中“spec.ports.name”的值要拼写正确(http、http二、grpc、redis、mongo),Enovy将像对待普通TCP同样代理这些服务,你不能对这些服务使用L7路由功能。pod在集群中只提供同一服务。从文件能够看到这个服务有三个版本(v1/v2/v3)。服务的每一个版本都有对应的Deployment。
如今咱们添加针对此pod的Envoy代理配置到这个文件中。使用“istioctl kube-inject”命令,它将生成一个可供kubectl部署使用包含Envoy代理额外组件的新yaml文件,运行命令:
istioctl kube-inject -f my-websites.yaml -o my-websites-with-proxy.yaml
复制代码
输出文件将包含额外配置,你能查看my-websites-with-proxy.yaml文件。此命令采用预约义的ConfigMap “istio-sidecar-injector”(它在定义istio以前已经定义)。并为咱们的deployment定义添加了所需的sidecar配置和参数。当咱们部署新文件“my-websites-with-proxy.yaml”时,每一个pod将有两个容器,一个咱们的实例程序,一个Envoy代理。运行下面命令部署咱们的服务程序和sidecar:
kubectl create -f my-websites-with-proxy.yaml
复制代码
若是它按预期工做,您将看到此输出:
deployment "web-v1" created
deployment "web-v2" created
deployment "web-v3" created
service "website" created
Let’s inspect the pods to see that the Envoy sidecar is present: kubectl get pods
复制代码
咱们能够看到每一个pod有两个容器,一个是网站容器,另外一个是代理sidecar:
咱们可以经过执行以下命令查看Envoy运行日志:
kubectl logs <your pod name> istio-proxy
复制代码
您将看到不少输出,最后几行与此相似:
add/update cluster outbound|80|version-1|website.default.svc.cluster.local starting warming
add/update cluster outbound|80|version-2|website.default.svc.cluster.local starting warming
add/update cluster outbound|80|version-3|website.default.svc.cluster.local starting warming
warming cluster outbound|80|version-3|website.default.svc.cluster.local complete
warming cluster outbound|80|version-2|website.default.svc.cluster.local complete
warming cluster outbound|80|version-1|website.default.svc.cluster.local complete
复制代码
这意味着sidecar在pod中运行良好。
如今咱们须要部署最小的Istio配置资源,须要将路由流量到咱们的service和pod。请把下面的文件保存到website-routing.yaml文件。
---
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: website-gateway
spec:
selector:
# Which pods we want to expose as Istio router
# This label points to the default one installed from file istio-demo.yaml
istio: ingressgateway
servers:
- port:
number: 80
name: http
protocol: HTTP
# Here we specify which Kubernetes service names
# we want to serve through this Gateway
hosts:
- "*"
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: website-virtual-service
spec:
hosts:
- "*"
gateways:
- website-gateway
http:
- route:
- destination:
host: website
subset: version-1
---
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
name: website
spec:
host: website
subsets:
- name: version-1
labels:
version: website-version-1
- name: version-2
labels:
version: website-version-2
- name: version-3
labels:
version: website-version-3
复制代码
该文件定义了Gateway、VirtualService和DestinationRule。这些是自定义Istio资源,用于管理和配置istio-ingressgateway pod的ingress行为。咱们将在下一个教程中更深刻地描述它们,这些教程将阐述Istio配置的技术细节。如今,部署这些资源以便可以访问咱们的示例网站:
kubectl create -f website-routing.yaml
复制代码
下一步是访问咱们的演示网站。咱们部署了三个版本,每一个都显示不一样的页面文字和颜色,但目前咱们只能经过Istio ingress访问v1。让咱们访问咱们的服务确保Web服务被部署了。
经过运行以下命令查看外部端点:
kubectl get services istio-ingressgateway -n istio-system
复制代码
或者经过浏览istio-ingressgateway服务找到它,以下所示(咱们也在本教程的开头看到过它)
经过点击它访问外部节点。您可能会看到多个连接,由于一个连接指向HTTPS,另外一个连接指向负载均衡器的HTTP端口。若是是这样,请仅使用HTTP连接,由于咱们没有为本教程设置TLS,您应该看到演示网站的v1页面:
为咱们demo示例明确配置kubernetes service指向单一部署istio VirtualService。它指明Envoy将访问网站的流量所有路由到v1版本(若是没有Envoy路由策略,kubernetes将会在三本版本的pods轮询请求)。您能够经过更改VirtualService配置的如下部分并从新部署它来更改咱们看到的网站版本:
http:
- route:
- destination:
host: website
subset: version-1
复制代码
“subset”是咱们选择要路由到的DestinationRule的正确地方。咱们将在下一个教程中深刻学习这些资源。
一般,当须要使用少许流量测试新版本的应用程序时(金丝雀部署)。vanilla Kubernetes方法使用新的Docker镜像,相同的pod标签,建立第二个deployment,将流量路由到有这个label标记的服务上。这不像Istio解决方案那样灵活。您没法轻松将10%的流量指向新deployment(为了达到精确的10%,您须要根据所需的百分比保持两个deployment之间的pod复制比例,例如9个“v1 pod”和1个“v2 pod”,或18个“v1 pod”和2个“v2 pod ”),而且不能使用HTTP头标记来将请求路由到特定版本。
在咱们的下一篇文章中,与Istio一块儿实践的金丝雀部署,咱们将自定义http头路由请求到正确的服务版本。经过这样作,咱们将彻底控制流量,并将分析Zipkin仪表板中的分布式追踪结果。
Istio的部署十分依赖Kubernetes,为了你们更好的理解 Kubernetes 原理,我推荐学习深刻剖析Kubernetes by 张磊,极客时间出品。
微信群:联系我入群
Slack:servicemesher.slack.com 须要邀请才能加入
Twitter: twitter.com/servicemesh…
GitHub:github.com/servicemesh…
更多Service Mesh咨询请扫码关注微信公众号ServiceMesher。