1

Service Mesh Istio 初探

 2 years ago
source link: https://www.purewhite.io/2018/06/27/service-mesh-0/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

Service Mesh Istio 初探

发表于 2018-06-27 更新于 2021-12-02 分类于 kubernetes 阅读次数: Disqus:0 Comments 本文字数: 9.9k 阅读时长 ≈ 18 分钟

早在去年,Service Mesh 这个概念就开始火起来了,今年的时候 Service Mesh 更是爆发式地发展,Service Mesh 中的明星项目 Istio 更是只用了几个月的时间就已经从 0.1 到了 0.8 LTS 了。由于工作和毕业的压力,之前一直没有时间深入研究 Service Mesh。现在稍微有些时间了,所以打算写点什么关于 Service Mesh 的。

首先,我们需要了解一下什么是 Service Mesh。今天我们的主角是 Istio,Istio 的背景我不过多介绍,G 家等大厂搞出来并且在后面推动支持的肯定不会弱。

根据 Istio 的官方文档,是这么定义自己的:一个用来连接、管理和加密微服务(流量)的开放平台。

an open platform to connect, manage, and secure microservices

Istio 可以让你在不修改微服务源代码的情况之下,很轻松地给微服务加上诸如负载均衡、身份验证、监控等等的功能。Istio 通过在你的微服务中部署一个 sidecar 作为所有流量的代理来达成这个目标。

总结下来,Istio 提供了以下功能:

  • 流量管理(Traffic Management)
  • 服务的身份认证和安全(Service Identity and Security)
  • 策略配置(Policy Enforcement)
  • 遥感(Telemetry)

除了这些之外,Istio 还支持很多不同的平台(尤其是 Kubernetes),并且支持自定义的组件和集成。

通过这些功能,微服务的开发和迁移会变得非常容易,而运维人员也可以更方便的更改部署的策略。

Istio 是两层架构的,分别是数据层控制层

  • 数据层是由所有的部署为 sidecar 的 Envoy 所组成的。
  • 控制层有三个组件:Pilot、Mixer 和 Citadel,顾名思义是用来控制 Service Mesh 的行为的。

总体的架构如下图:

Istio Architecture

Istio Architecture

Envoy

Istio 用了一个扩展版本的 Envoy 作为底层的代理。Envoy 是一个用 C++ 开发的高性能的代理,具有非常多功能,具体的可以参考官方文档,在此不做赘述。

Envoy 在 Istio 中是以 sidecar 模式部署在 pod 里面的,Istio 通过控制 Envoy 来控制所有的流量,获取监控数据等。

Mixer

Mixer 是一个平台无关的组件,用来控制访问策略和使用策略,同时会收集监控信息,将收集到的信息传给用户可以自定义的后端进行处理。

Pilot

Pilot 为 Envoy 提供服务发现、智能路由(如 AB 测试、金丝雀部署)和弹性流量管理功能(如超时、重试、熔断)。它负责将高层的抽象的路由规则转化成低级的 envoy 的配置。

Citadel

Citadel 提供了服务间和服务到终端用户的认证,同时可以直接将 http 流量升级成 https 流量。具体的可以查看官方文档。

在这里我打算使用 helm 进行安装。

Prerequisite

首先,你得有一个可运行的 k8s 集群,我是在 gke 上开了一个三节点的集群作为测试使用。

其次,你得需要有 helm 的客户端。mac 用户可以通过 brew 来安装。

下载 release

Istio 提供了一个很方便的脚本来下载并解压最新版的 Istio,如下:

$ curl -L https://git.io/getLatestIstio | sh -

等下载完之后,我们可以进入文件夹,并把 bin 目录加到 path 里面:

$ cd istio-0.8.0
$ export PATH=$PWD/bin:$PATH

使用 helm 进行安装

要使用 helm 来安装 istio,首先需要在集群里面配置好 helm 和 tiller,如下:

$ kubectl create -f install/kubernetes/helm/helm-service-account.yaml
$ helm init --service-account tiller

等 helm 和 tiller 配置完之后,就可以使用 helm 来一键安装 Istio 了:

$ helm install install/kubernetes/helm/istio --name istio --namespace istio-system

这样,Istio 就安装好了。

为了验证安装是否成功,我们可以看一下是否部署了以下的 service:

$ kubectl get svc -n istio-system
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
istio-citadel ClusterIP 10.19.247.33 <none> 8060/TCP,9093/TCP 2m
istio-egressgateway ClusterIP 10.19.244.143 <none> 80/TCP,443/TCP 2m
istio-ingress LoadBalancer 10.19.248.42 104.199.155.220 80:32000/TCP,443:30434/TCP 2m
istio-ingressgateway LoadBalancer 10.19.254.155 35.229.183.83 80:31380/TCP,443:31390/TCP,31400:31400/TCP 2m
istio-pilot ClusterIP 10.19.252.30 <none> 15003/TCP,15005/TCP,15007/TCP,15010/TCP,15011/TCP,8080/TCP,9093/TCP 2m
istio-policy ClusterIP 10.19.242.187 <none> 9091/TCP,15004/TCP,9093/TCP 2m
istio-sidecar-injector ClusterIP 10.19.252.155 <none> 443/TCP 2m
istio-statsd-prom-bridge ClusterIP 10.19.246.99 <none> 9102/TCP,9125/UDP 2m
istio-telemetry ClusterIP 10.19.240.18 <none> 9091/TCP,15004/TCP,9093/TCP,42422/TCP 2m
prometheus ClusterIP 10.19.255.53 <none> 9090/TCP 2m

并且确认以下的 Pod 是否在 running 状态:

$ kubectl get pods -n istio-system
NAME READY STATUS RESTARTS AGE
istio-citadel-7bdc7775c7-ntfkf 1/1 Running 0 3m
istio-egressgateway-795fc9b47-2hw69 1/1 Running 0 3m
istio-ingress-84659cf44c-dkgf4 1/1 Running 0 3m
istio-ingressgateway-7d89dbf85f-9kgth 1/1 Running 0 3m
istio-mixer-post-install-vg5gh 0/1 Completed 0 3m
istio-pilot-66f4dd866c-nwr2j 2/2 Running 0 3m
istio-policy-76c8896799-7l9nz 2/2 Running 0 3m
istio-sidecar-injector-645c89bc64-6rs5k 1/1 Running 0 3m
istio-statsd-prom-bridge-949999c4c-mpk6d 1/1 Running 0 3m
istio-telemetry-6554768879-vqmjd 2/2 Running 0 3m
prometheus-86cb6dd77c-vhf9s 1/1 Running 0 3m

当然,我们也可以自定义一些参数,具体的请看 [官方文档]($ helm install install/kubernetes/helm/istio –name istio –namespace istio-system)。

让我们部署我们的一个样例应用来看看 Istio 到底干了啥。

我们的样例应用叫做 BookInfo,这个应用由四个微服务所组成,具体架构图如下:

Bookinfo Application without Istio

Bookinfo Application without Istio

这个应用是用不同的语言所写的,让我们来见识一下 Istio 的魔力吧。

安装这个应用非常简单,我们只要执行以下命令即可:

$ kubectl apply -f samples/bookinfo/kube/bookinfo.yaml
$ istioctl create -f samples/bookinfo/routing/bookinfo-gateway.yaml

我们可以注意一下,在 bookinfo.yaml 中的 manifest 如下:

# Copyright 2017 Istio Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

##################################################################################################
# Details service
##################################################################################################
apiVersion: v1
kind: Service
metadata:
name: details
labels:
app: details
spec:
ports:
- port: 9080
name: http
selector:
app: details
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: details-v1
spec:
replicas: 1
template:
metadata:
labels:
app: details
version: v1
spec:
containers:
- name: details
image: istio/examples-bookinfo-details-v1:1.5.0
imagePullPolicy: IfNotPresent
ports:
- containerPort: 9080
---
...

但是我们真正部署出来后,变成了这样:

apiVersion: v1
kind: Pod
metadata:
annotations:
sidecar.istio.io/status: '{"version":"55c9e544b52e1d4e45d18a58d0b34ba4b72531e45fb6d1572c77191422556ffc","initContainers":["istio-init"],"containers":["istio-proxy"],"volumes":["istio-envoy","istio-certs"],"imagePullSecrets":null}'
creationTimestamp: 2018-07-05T09:10:55Z
generateName: details-v1-5f94c6d66b-
labels:
app: details
pod-template-hash: "1950728226"
version: v1
name: details-v1-5f94c6d66b-jj6lz
namespace: default
ownerReferences:
- apiVersion: apps/v1
blockOwnerDeletion: true
controller: true
kind: ReplicaSet
name: details-v1-5f94c6d66b
uid: 528aa360-8033-11e8-8cec-0e04fb7e7092
resourceVersion: "15620"
selfLink: /api/v1/namespaces/default/pods/details-v1-5f94c6d66b-jj6lz
uid: 528d5618-8033-11e8-8cec-0e04fb7e7092
spec:
containers:
- image: istio/examples-bookinfo-details-v1:1.5.0
imagePullPolicy: IfNotPresent
name: details
ports:
- containerPort: 9080
protocol: TCP
resources: {}
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
volumeMounts:
- mountPath: /var/run/secrets/kubernetes.io/serviceaccount
name: default-token-f9mls
readOnly: true
- args:
- proxy
- sidecar
- --configPath
- /etc/istio/proxy
- --binaryPath
- /usr/local/bin/envoy
- --serviceCluster
- details
- --drainDuration
- 45s
- --parentShutdownDuration
- 1m0s
- --discoveryAddress
- istio-pilot.istio-system:15007
- --discoveryRefreshDelay
- 10s
- --zipkinAddress
- zipkin.istio-system:9411
- --connectTimeout
- 10s
- --statsdUdpAddress
- istio-statsd-prom-bridge.istio-system:9125
- --proxyAdminPort
- "15000"
- --controlPlaneAuthPolicy
- NONE
env:
- name: POD_NAME
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: metadata.name
- name: POD_NAMESPACE
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: metadata.namespace
- name: INSTANCE_IP
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: status.podIP
- name: ISTIO_META_POD_NAME
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: metadata.name
- name: ISTIO_META_INTERCEPTION_MODE
value: REDIRECT
image: docker.io/istio/proxyv2:0.8.0
imagePullPolicy: IfNotPresent
name: istio-proxy
resources:
requests:
cpu: 100m
memory: 128Mi
securityContext:
privileged: false
readOnlyRootFilesystem: true
runAsUser: 1337
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
volumeMounts:
- mountPath: /etc/istio/proxy
name: istio-envoy
- mountPath: /etc/certs/
name: istio-certs
readOnly: true
- mountPath: /var/run/secrets/kubernetes.io/serviceaccount
name: default-token-f9mls
readOnly: true
dnsPolicy: ClusterFirst
initContainers:
- args:
- -p
- "15001"
- -u
- "1337"
- -m
- REDIRECT
- -i
- '*'
- -x
- ""
- -b
- 9080,
- -d
- ""
image: docker.io/istio/proxy_init:0.8.0
imagePullPolicy: IfNotPresent
name: istio-init
resources: {}
securityContext:
capabilities:
add:
- NET_ADMIN
privileged: true
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
volumeMounts:
- mountPath: /var/run/secrets/kubernetes.io/serviceaccount
name: default-token-f9mls
readOnly: true
nodeName: ip-172-31-39-23
restartPolicy: Always
schedulerName: default-scheduler
securityContext: {}
serviceAccount: default
serviceAccountName: default
terminationGracePeriodSeconds: 30
tolerations:
- effect: NoExecute
key: node.kubernetes.io/not-ready
operator: Exists
tolerationSeconds: 300
- effect: NoExecute
key: node.kubernetes.io/unreachable
operator: Exists
tolerationSeconds: 300
volumes:
- emptyDir:
medium: Memory
name: istio-envoy
- name: istio-certs
secret:
defaultMode: 420
optional: true
secretName: istio.default
- name: default-token-f9mls
secret:
defaultMode: 420
secretName: default-token-f9mls

可以看到,本来只有一个 container 的,现在里面多了一个 container 和 initContainer。这个就是 Istio 的 Auto Injection,可以自动把 sidecar 注入到 Pod 里面,让我们不需要手动一个一个修改 yaml 文件,也防止手动修改过程中出错的可能。

这里我们以路由设置为例子。

首先我们打开刚才部署好的这个应用的网页,可以看到页面右方的 Book Reviews 部分里面每次刷新都会随机性地出现黑星星、红星星和没有星星三种情况,这是因为我们有三个不同的 backend,路由在默认情况下会随机路由到任意一个 backend 上。

我们先尝试把所有的路由都路由到 v1 版本上(就是没有星星的版本),路由规则如下:

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: details
...
spec:
hosts:
- details
http:
- route:
- destination:
host: details
subset: v1
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: productpage
...

命令如下:

$ istioctl create -f samples/bookinfo/routing/route-rule-all-v1.yaml

然后我们再去刷新,就会发现不管怎么刷新星星都不见了。

接着,假如我们有一个用户是 jason,我们希望他能测试 v2 的 backend,就可以用下面的路由规则:

kind: VirtualService
metadata:
name: reviews
...
spec:
hosts:
- reviews
http:
- match:
- headers:
cookie:
regex: ^(.*?;)?(user=jason)(;.*)?$
route:
- destination:
host: reviews
subset: v2
- route:
- destination:
host: reviews
subset: v1

命令如下:

$ istioctl replace -f samples/bookinfo/routing/route-rule-reviews-test-v2.yaml

这时候,我们打开网页,以 jason 这个用户登录(密码随便填),就会发现每一次访问到的都是带有黑星星的版本。

这就是 Istio 提供的路由功能。

本文中我们简单讲了 Service Mesh 的概念,如何创建 Istio 以及简单的使用过程,如果大家有兴趣探索 Istio 更多的功能,可以直接访问 Istio 的官网


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK