ServiceMesh-初识Linkerd2.0

ServiceMesh-初识Linkerd2.0

十月 28, 2018

一、 Linkerd 2.0 介绍

     首先我们来看什么是 Service Mesh。根据Linkerd CEO William Morgan定义,“Service Mesh是用于处理服务间通信的基础设施层,用于在云原生应用复杂的服务拓扑中实现可靠的请求传递。在实践中,Service Mesh通常是一组与应用一起部署,但对应用透明的轻量级网络代理。”我们可以将其比作是用于处理服务间通信的专用基础设施层,负责服务之间的网络调用、限流、熔断和监控。但与传统基础设施层不同之处在于,它形成了一个分布式的互连代理网络,以sidecar形式部署在服务两侧,服务对于代理无感知,且服务间所有通信都由代理进行路由。
     如图中绿色方块为应用服务,蓝色方块为 Sidecar Proxy,应用服务之间通过 Sidecar Proxy 进行通信,整个服务通信形成图中的蓝色网络连线,图中所有蓝色部分就形成了 Service Mesh。

     如下图所示,Service Mesh中分为控制平面(Control plane)和数据平台(Data plane),类似结构可以和SDN(软件定义网络)对比。Control plane定义服务发现、路由、流量控制等策略。这些策略可以是全局的,也可以是限定的。Data plane负责在所有服务中通过sidecar代理进行服务通信,并应用和执行策略。

     当下微服务框架如Dubbo、Spring越来越流行,虽然技术也很成熟了,但是一个公司的不同应用系统或者一个应用系统中不同组件通常会使用多种技术栈,所以研发运营的技术成本较高,打通技术栈的服务治理显得越发重要。也不知道谁说的“没有什么问题不是抽象出一层解决不了的。如果有,那就再抽象一层。”,如上所说Service Mesh就是抽象出用于处理服务间通信的专用基础设施层,在不侵入应用代码的前提下,提供服务治理所需的服务注册发现、负载均衡、熔断降级、监控等功能,从而提升开发运维和服务间调用的效率。

     Linkerd是Service Mesh(服务网格)的一种实现方式,核心是一个高性能透明代理,支持Kubernetes等多种框架。Linkerd通过提供自动可观察性、可靠性和运行时诊断,而无需更改配置或代码,使得服务运行更加简单和安全。Linkerd基于Netty和Finagle构建,Finagle是经过生产测试的RPC框架,采用于Twitter、Pinterest、Tumblr、PagerDuty等高流量公司。目前2.0 版本正式GA已经一月有余,本次除了带来了性能、资源消耗和易用性方面的显着改进,更重大的变革是将目光从集群范围的 Service Mesh 转到了可组合的 Service Sidecar。主要更新内容如下:

  1. 独立的“Service Sidecar”设计,无需集群范围的安装即可增强单一服务。
  2. 集群范围 Service Mesh 的增量路径,跨多个服务的 Service Sidecar 链接成为 Service Mesh。
  3. 安装过程零配置,零代码更改。
  4. 自动 Grafana 仪表板和 Prometheus 监控服务“黄金指标”。
  5. 服务之间的自动 TLS,包括证书生成和分发。
  6. Rust 中完整的代理重写,在延迟、吞吐量和资源消耗方面有巨大改进。

     前面说到Service Mesh中分为控制平面和数据平面,Linkerd2.0中控制平面由一组运行在专用的Kubernetes命名空间(默认linkerd)的服务组成。这些服务汇集不同的遥测数据,提供一个面向用户的API,提供控制数据给数据平面的代理等。
控制平面有四个组件组成:

  • Controller的deployment中包含public-api, proxy-api, destination, tap四个容器,提供绝大部分控制平面的功能
  • Web提供Linkerd dashboard
  • Prometheus,透明代理暴露服务pod的/metrics,所有Metrics被收集(间隔10s)并存放在prometheus中,该prometheus实例专用来处理Linkerd生成的数据。
  • Grafana,Linkerd附带许多grafana dashboard(Metrics、Deployment、Pod和Linkerd),可以通过Linkerd dashboard中的链接进入。

     数据平面由轻量代理组成,代理以sidecar容器的形式部署在每个服务实例旁。为了添加一个服务到Linkerd服务网格,运行该服务的pod必须被注入代理后重新部署,通过代理透明地汇集来自每个实例的流量。这些代理透明的拦截pod之间的通信,可对流量进行监测和加密(TLS),也可以执行相关的策略拒绝请求。

     代理,基于Rust和Go编写的高性能轻量级透明代理,安装在每个服务的Pod中组成数据平面的一部分。代理接收所有进入服务的流量并拦截所有出流量,通过initcontainer配置的iptables规则转发流量。正因为这样,代理可以被添加到正在运行的服务中而代码不需要做任何修改。
代理的特性包括:

  • 透明的,无需任何配置的代理 HTTP, HTTP/2和几乎所有TCP协议的
  • 自动的针对HTTP和TCP流量暴露Prometheus Metrics
  • 透明的,无需任何配置的 WebSocket 代理
  • 自动的延迟感知,7层负载均衡
  • 自动的4层负载均衡
  • 自动加密(TLS)
  • 按需跟踪服务流量和诊断
  • 代理支持DNS服务发现和gRPC框架

     Linkerd CLI运行在本地,用于与控制平面和数据平面交互,也可以用来查看实时状态、debug,安装和升级。

     Linkerd Dashboard提供了一个高质量的前端界面实时展现你的服务运行状态,他能用来查看“黄金级别”的metrics(请求成功率、请求响应时间和延迟),视图化服务之间的依赖关系,查看特定服务路由的健康状况。

二、 安装Linkerd

本文搭建环境为kubernetes 1.11.2

  1. 安装CLI
    在线安装:
    1
    # curl -sL https://run.linkerd.io/install | sh

或下载二进制文件:https://github.com/linkerd/linkerd2/releases/

1
2
3
4
5
# chmod u+x linkerd2-cli-edge-18.10.4-linux
# mv linkerd2-cli-edge-18.10.4-linux /usr/local/bin/linkerd2
# linkerd2 version
Client version: edge-18.10.4
Server version: unavailable

  1. 做k8s集群检查,是否配置正确,能否满足安装控制平面
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    # linkerd2 check --pre
    kubernetes-api: can initialize the client..................................[ok]
    kubernetes-api: can query the Kubernetes API...............................[ok]
    kubernetes-api: is running the minimum Kubernetes API version..............[ok]
    kubernetes-setup: control plane namespace does not already exist...........[ok]
    kubernetes-setup: can create Namespaces....................................[ok]
    kubernetes-setup: can create ClusterRoles..................................[ok]
    kubernetes-setup: can create ClusterRoleBindings...........................[ok]
    kubernetes-setup: can create ServiceAccounts...............................[ok]
    kubernetes-setup: can create Services......................................[ok]
    kubernetes-setup: can create Deployments...................................[ok]
    kubernetes-setup: can create ConfigMaps....................................[ok]
    linkerd-version: can determine the latest version..........................[ok]
    linkerd-version: cli is up-to-date.........................................[ok]

    Status check results are [ok]

3.安装
镜像准备(感谢Troy Ying仗义相助),这里没有镜像工场只好每台主机拉取镜像:

1
2
3
4
5
6
7
8
9
10
11
12
docker pull heisenbergye/controller:edge-18.10.4   
docker pull heisenbergye/proxy:edge-18.10.4
docker pull heisenbergye/proxy-init:edge-18.10.4
docker pull heisenbergye/grafana:edge-18.10.4
docker pull heisenbergye/prometheus:v2.4.0
docker pull heisenbergye/web:edge-18.10.4
docker tag heisenbergye/controller:edge-18.10.4 gcr.io/linkerd-io/controller:edge-18.10.4
docker tag heisenbergye/proxy:edge-18.10.4 gcr.io/linkerd-io/proxy:edge-18.10.4
docker tag heisenbergye/proxy-init:edge-18.10.4 gcr.io/linkerd-io/proxy-init:edge-18.10.4
docker tag heisenbergye/grafana:edge-18.10.4 gcr.io/linkerd-io/grafana:edge-18.10.4
docker tag heisenbergye/prometheus:v2.4.0 prom/prometheus:v2.4.0
docker tag heisenbergye/web:edge-18.10.4 gcr.io/linkerd-io/web:edge-18.10.4

使用CLi安装轻量级控制平面,默认安装到linkerd的namespace,可以指定ns安装

1
2
3
# kubectl create ns linkerd
namespace/linkerd created
# linkerd2 install -l linkerd | kubectl apply -f -

待安装完成后执行命令检查Linkerd状态是否正常

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# kubectl get deploy -n linkerd
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
controller 1 1 1 1 5m
grafana 1 1 1 1 5m
prometheus 1 1 1 1 5m
web 1 1 1 1 5m

# kubectl get pod -n linkerd
NAME READY STATUS RESTARTS AGE
controller-8595c9f77d-2shbb 5/5 Running 0 5m
grafana-8958c89bb-hpwhl 2/2 Running 0 5m
prometheus-54d949788b-lpm7k 2/2 Running 0 5m
web-7844df8659-hvzdx 2/2 Running 0 5m

# linkerd2 check
kubernetes-api: can initialize the client..................................[ok]
kubernetes-api: can query the Kubernetes API...............................[ok]
kubernetes-api: is running the minimum Kubernetes API version..............[ok]
linkerd-api: control plane namespace exists................................[ok]
linkerd-api: control plane pods are ready..................................[ok]
linkerd-api: can initialize the client.....................................[ok]
linkerd-api: can query the control plane API...............................[ok]
linkerd-api[kubernetes]: control plane can talk to Kubernetes..............[ok]
linkerd-api[prometheus]: control plane can talk to Prometheus..............[ok]
linkerd-api: no invalid service profiles...................................[ok]
linkerd-version: can determine the latest version..........................[ok]
linkerd-version: cli is up-to-date.........................................[ok]
linkerd-version: control plane is up-to-date...............................[ok]

Status check results are [ok]

暴露Linkerd Dashboard端口,这里使用ingress方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: ingress-linkerd
namespace: linkerd
spec:
rules:
- host: web.linkerd.com
http:
paths:
- path: /
backend:
serviceName: web
servicePort: 8084
- host: grafana.linkerd.com
http:
paths:
- path: /
backend:
serviceName: grafana
servicePort: 3000

三、 安装demo

1
2
3
4
5
6
7
8
9
10
11
12
13
# curl -sL https://run.linkerd.io/emojivoto.yml | kubectl apply -f -

# kubectl get pod -n emojivoto
NAME READY STATUS RESTARTS AGE
emoji-667dc6f77-59w5s 1/1 Running 0 1m
vote-bot-5c5cfb764c-dvcxn 1/1 Running 0 1m
voting-86954dbfbd-52mgn 1/1 Running 0 1m
web-84dfc8b799-wp7rx 1/1 Running 0 1m
# kubectl get svc -n emojivoto
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
emoji-svc ClusterIP None <none> 8080/TCP 1m
voting-svc ClusterIP None <none> 8080/TCP 1m
web-svc LoadBalancer 10.96.251.49 <pending> 80:31293/TCP 1m

向服务注入sidecar

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# kubectl get -n emojivoto deploy -o yaml   | linkerd2 inject -   | kubectl apply -f -

hostNetwork: pods do not use host networking...............................[ok]
sidecar: pods do not have a proxy or initContainer already injected........[ok]
supported: at least one resource injected..................................[ok]
udp: pod specs do not include UDP ports....................................[ok]

Summary: 1 of 1 YAML document(s) injected
deployment/web

deployment.extensions/emoji configured
deployment.extensions/vote-bot configured
deployment.extensions/voting configured
deployment.extensions/web configured

检查代理注入的状态和暴露metrics

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# linkerd2 -n emojivoto check --proxy
kubernetes-api: can initialize the client..................................[ok]
kubernetes-api: can query the Kubernetes API...............................[ok]
kubernetes-api: is running the minimum Kubernetes API version..............[ok]
linkerd-api: control plane namespace exists................................[ok]
linkerd-api: control plane pods are ready..................................[ok]
linkerd-api: can initialize the client.....................................[ok]
linkerd-api: can query the control plane API...............................[ok]
linkerd-api[kubernetes]: control plane can talk to Kubernetes..............[ok]
linkerd-api[prometheus]: control plane can talk to Prometheus..............[ok]
linkerd-api: no invalid service profiles...................................[ok]
linkerd-data-plane: data plane namespace exists............................[ok]
linkerd-data-plane: data plane proxies are ready...........................[ok]
linkerd-data-plane: data plane proxy metrics are present in Prometheus.....[ok]
linkerd-version: can determine the latest version..........................[ok]
linkerd-version: cli is up-to-date.........................................[ok]
linkerd-version: data plane is up-to-date..................................[ok]

Status check results are [ok]

查看服务的网络流量统计情况:

1
2
3
4
5
6
# linkerd2 -n emojivoto stat deploy
NAME MESHED SUCCESS RPS LATENCY_P50 LATENCY_P95 LATENCY_P99 TLS
emoji 1/1 100.00% 2.0rps 1ms 1ms 2ms 0%
vote-bot 1/1 - - - - - -
voting 1/1 81.36% 1.0rps 1ms 1ms 1ms 0%
web 1/1 90.68% 2.0rps 4ms 5ms 9ms 0%

跟踪服务的网络流量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# linkerd2 -n emojivoto tap deploy
req id=0:1962 proxy=out src=10.244.3.111:45978 dst=10.244.3.112:80 tls=no_identity :method=GET :authority=web-svc.emojivoto:80 :path=/api/list
req id=0:4850 proxy=in src=10.244.3.111:38056 dst=10.244.3.112:80 tls=disabled :method=GET :authority=web-svc.emojivoto:80 :path=/api/list
req id=0:4851 proxy=out src=10.244.3.112:44754 dst=10.244.2.72:8080 tls=no_identity :method=POST :authority=emoji-svc.emojivoto:8080 :path=/emojivoto.v1.EmojiService/ListAll
req id=0:1940 proxy=in src=10.244.3.112:55692 dst=10.244.2.72:8080 tls=disabled :method=POST :authority=emoji-svc.emojivoto:8080 :path=/emojivoto.v1.EmojiService/ListAll
rsp id=0:1940 proxy=in src=10.244.3.112:55692 dst=10.244.2.72:8080 tls=disabled :status=200 latency=954µs
end id=0:1940 proxy=in src=10.244.3.112:55692 dst=10.244.2.72:8080 tls=disabled grpc-status=OK duration=33µs response-length=2161B
rsp id=0:4851 proxy=out src=10.244.3.112:44754 dst=10.244.2.72:8080 tls=no_identity :status=200 latency=3052µs
end id=0:4851 proxy=out src=10.244.3.112:44754 dst=10.244.2.72:8080 tls=no_identity grpc-status=OK duration=48µs response-length=2161B
rsp id=0:4850 proxy=in src=10.244.3.111:38056 dst=10.244.3.112:80 tls=disabled :status=200 latency=4378µs
rsp id=0:1962 proxy=out src=10.244.3.111:45978 dst=10.244.3.112:80 tls=no_identity :status=200 latency=4944µs
end id=0:4850 proxy=in src=10.244.3.111:38056 dst=10.244.3.112:80 tls=disabled duration=137µs response-length=4558B
end id=0:1962 proxy=out src=10.244.3.111:45978 dst=10.244.3.112:80 tls=no_identity duration=187µs response-length=4558B
req id=0:1963 proxy=out src=10.244.3.111:45978 dst=10.244.3.112:80 tls=no_identity :method=GET :authority=web-svc.emojivoto:80 :path=/api/vote
req id=0:4852 proxy=in src=10.244.3.111:38056 dst=10.244.3.112:80 tls=disabled :method=GET :authority=web-svc.emojivoto:80 :path=/api/vote
req id=0:4853 proxy=out src=10.244.3.112:44754 dst=10.244.2.72:8080 tls=no_identity :method=POST :authority=emoji-svc.emojivoto:8080 :path=/emojivoto.v1.EmojiService/FindByShortcode
req id=0:1941 proxy=in src=10.244.3.112:55692 dst=10.244.2.72:8080 tls=disabled :method=POST :authority=emoji-svc.emojivoto:8080 :path=/emojivoto.v1.EmojiService/FindByShortcode
rsp id=0:1941 proxy=in src=10.244.3.112:55692 dst=10.244.2.72:8080 tls=disabled :status=200 latency=467µs
end id=0:1941 proxy=in src=10.244.3.112:55692 dst=10.244.2.72:8080 tls=disabled grpc-status=OK duration=54µs response-length=30B
rsp id=0:4853 proxy=out src=10.244.3.112:44754 dst=10.244.2.72:8080 tls=no_identity :status=200 latency=2257µs

查看服务实时运行状态,基于路由请求的事件统计

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# linkerd2 -n emojivoto top deploy
Source Destination Method Path Count Best Worst Last Success Rate
web-b4748444d-6krr2 emoji-5bb698556b-7n8cp POST /emojivoto.v1.EmojiService/ListAll 30 907µs 4ms 3ms 100.00%
vote-bot-f477cbb66-hpb6v web-b4748444d-6krr2 GET /api/list 30 4ms 8ms 6ms 100.00%
web-b4748444d-6krr2 emoji-5bb698556b-7n8cp POST /emojivoto.v1.EmojiService/FindByShortcode 30 565µs 3ms 3ms 100.00%
vote-bot-f477cbb66-hpb6v web-b4748444d-6krr2 GET /api/vote 29 5ms 9s 7ms 100.00%
web-b4748444d-6krr2 voting-695f74678b-67pf8 POST /emojivoto.v1.VotingService/VoteDoughnut 8 839µs 9s 3ms 100.00%
web-b4748444d-6krr2 voting-695f74678b-67pf8 POST /emojivoto.v1.VotingService/VoteWalkingMan 2 1ms 3ms 3ms 100.00%
web-b4748444d-6krr2 voting-695f74678b-67pf8 POST /emojivoto.v1.VotingService/VoteBulb 2 708µs 2ms 2ms 100.00%
web-b4748444d-6krr2 voting-695f74678b-67pf8 POST /emojivoto.v1.VotingService/VoteBurrito 2 916µs 2ms 2ms 100.00%
web-b4748444d-6krr2 voting-695f74678b-67pf8 POST /emojivoto.v1.VotingService/VoteTumblerGlass 2 945µs 2ms 2ms 100.00%
web-b4748444d-6krr2 voting-695f74678b-67pf8 POST /emojivoto.v1.VotingService/VoteHearNoEvil 2 774µs 2ms 2ms 100.00%
web-b4748444d-6krr2 voting-695f74678b-67pf8 POST /emojivoto.v1.VotingService/VoteRocket 2 946µs 3ms 3ms 100.00%
web-b4748444d-6krr2 voting-695f74678b-67pf8 POST /emojivoto.v1.VotingService/VotePoliceman 2 2ms 3ms 3ms 100.00%
web-b4748444d-6krr2 voting-695f74678b-67pf8 POST /emojivoto.v1.VotingService/VoteTropicalDrink 2 1ms 3ms 3ms 100.00%
web-b4748444d-6krr2 voting-695f74678b-67pf8 POST /emojivoto.v1.VotingService/VoteStuckOutTongueWinkingEye 2 858µs 2ms 2ms 100.00%

来点击grafana的链接,诶?怎么连不进去。

看看grafana的ingress呢?还是打不开(抱歉,忘记截图了,就是空白的页面,里面几个grafana的提示)

在grafana的configmap里找到了罪魁祸首root_url

这是因为root_url是给Linkerd dashboard命令用的,他会自动创建一个代理使用本机的图形界面打开浏览器,把 http://127.0.0.1:xxxxx 传入,而这里用ingress所以用dashboard里的链接连不进grafana,只能注释root_url,之前我们已经创建了grafana的ingress来试试,可以看到界面了。但是linkerd dashboard里的grafana链接肯定是没办法用的。

今天先到这里,下一期我们分析proxy的注入