# Linkerd 使用指南
本文是 Linkerd 使用指南,我們著重講解在 kubernetes 中如何使用 linkerd 作為 kubernetes 的 Ingress controller。
## 前言
Linkerd 作為一款 service mesh 與kubernetes 結合后主要有以下幾種用法:
1. 作為服務網關,可以監控 kubernetes 中的服務和實例
2. 使用 TLS 加密服務
3. 通過流量轉移到持續交付
4. 開發測試環境(Eat your own dog food)、Ingress 和邊緣路由
5. 給微服務做 staging
6. 分布式 tracing
7. 作為 Ingress controller
8. 使用 gRPC 更方便
以下我們著重講解在 kubernetes 中如何使用 linkerd 作為 kubernetes 的 Ingress controller,并作為邊緣節點代替 [Traefik](https://traefik.io) 的功能,詳見 [邊緣節點的配置](../practice/edge-node-configuration.md)。
## 準備
安裝測試時需要用到的鏡像有:
```ini
buoyantio/helloworld:0.1.4
buoyantio/jenkins-plus:2.60.1
buoyantio/kubectl:v1.4.0
buoyantio/linkerd:1.1.2
buoyantio/namerd:1.1.2
buoyantio/nginx:1.10.2
linkerd/namerctl:0.8.6
openzipkin/zipkin:1.20
tutum/dnsutils:latest
```
這些鏡像可以直接通過 Docker Hub 獲取,我將它們下載下來并上傳到了自己的私有鏡像倉庫 `harbor-001.jimmysong.io` 中,下文中用到的鏡像皆來自我的私有鏡像倉庫,yaml 配置見 linkerd目錄,并在使用時將配置中的鏡像地址修改為你自己的。
## 部署
首先需要先創建 RBAC,因為使用 namerd 和 ingress 時需要用到。
```bash
$ kubectl create -f linkerd-rbac-beta.yml
```
Linkerd 提供了 Jenkins 示例,在部署的時候使用以下命令:
```bash
$ kubectl create -f jenkins-rbac-beta.yml
$ kubectl create -f jenkins.yml
```
訪問 http://jenkins.jimmysong.io


**注意**:要訪問 Jenkins 需要在 Ingress 中增加配置,下文會提到。
在 kubernetes 中使用 Jenkins 的時候需要注意 Pipeline 中的配置:
```python
def currentVersion = getCurrentVersion()
def newVersion = getNextVersion(currentVersion)
def frontendIp = kubectl("get svc l5d -o jsonpath=\"{.status.loadBalancer.ingress[0].*}\"").trim()
def originalDst = getDst(getDtab())
```
`frontendIP` 的地址要配置成 service 的 Cluster IP ,因為我們沒有用到LoadBalancer。
需要安裝 namerd,namerd 負責 dtab 信息的存儲,當然也可以存儲在 etcd、consul中。dtab 保存的是路由規則信息,支持遞歸解析,詳見 [dtab](https://linkerd.io/in-depth/dtabs/)。
流量切換主要是通過 [dtab](https://linkerd.io/in-depth/dtabs/) 來實現的,通過在 HTTP 請求的 header 中增加 `l5d-dtab` 和 `Host` 信息可以對流量分離到 kubernetes 中的不同 service 上。
**遇到的問題**
Failed with the following error(s)
Error signal dtab is already marked as being deployed!
因為該 dtab entry 已經存在,需要刪除后再運行。
訪問 `http://namerd.jimmysong.io`

dtab 保存在 namerd 中,該頁面中的更改不會生效,需要使用命令行來操作。
使用 [namerctl](https://github.com/linkerd/namerctl) 來操作。
```bash
$ namerctl --base-url http://namerd-backend.jimmysong.io dtab update internal file
```
**注意**:update 時需要將更新文本先寫入文件中。
## 部署 Linkerd
直接使用 yaml 文件部署,注意修改鏡像倉庫地址。
```bash
# 創建 namerd
$ kubectl create -f namerd.yaml
# 創建 ingress
$ kubectl create -f linkerd-ingress.yml
# 創建測試服務 hello-world
$ kubectl create -f hello-world.yml
# 創建 API 服務
$ kubectl create -f api.yml
# 創建測試服務 world-v2
$ kubectl create -f world-v2.yml
```
為了在本地調試 linkerd,我們將 linkerd 的 service 加入到 ingress 中,詳見 [邊緣節點配置](../practice/edge-node-configuration.md)。
在 Ingress 中增加如下內容:
```yaml
- host: linkerd.jimmysong.io
http:
paths:
- path: /
backend:
serviceName: l5d
servicePort: 9990
- host: linkerd-viz.jimmysong.io
http:
paths:
- path: /
backend:
serviceName: linkerd-viz
servicePort: 80
- host: l5d.jimmysong.io
http:
paths:
- path: /
backend:
serviceName: l5d
servicePort: 4141
- host: jenkins.jimmysong.io
http:
paths:
- path: /
backend:
serviceName: jenkins
servicePort: 80
```
在本地`/etc/hosts`中添加如下內容:
```ini
172.20.0.119 linkerd.jimmysong.io
172.20.0.119 linkerd-viz.jimmysong.io
172.20.0.119 l5d.jimmysong.io
```
**測試路由功能**
使用 curl 簡單測試。
單條測試
```bash
$ curl -s -H "Host: www.hello.world" 172.20.0.120:4141
Hello (172.30.60.14) world (172.30.71.19)!!%
```
請注意請求返回的結果,表示訪問的是 `world-v1` service。
```bash
$ for i in $(seq 0 10000);do echo $i;curl -s -H "Host: www.hello.world" 172.20.0.120:4141;done
```
使用 ab test。
```bash
$ ab -c 4 -n 10000 -H "Host: www.hello.world" http://172.20.0.120:4141/
This is ApacheBench, Version 2.3 <$Revision: 1757674 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/
Benchmarking 172.20.0.120 (be patient)
Completed 1000 requests
Completed 2000 requests
Completed 3000 requests
Completed 4000 requests
Completed 5000 requests
Completed 6000 requests
Completed 7000 requests
Completed 8000 requests
Completed 9000 requests
Completed 10000 requests
Finished 10000 requests
Server Software:
Server Hostname: 172.20.0.120
Server Port: 4141
Document Path: /
Document Length: 43 bytes
Concurrency Level: 4
Time taken for tests: 262.505 seconds
Complete requests: 10000
Failed requests: 0
Total transferred: 2210000 bytes
HTML transferred: 430000 bytes
Requests per second: 38.09 [#/sec] (mean)
Time per request: 105.002 [ms] (mean)
Time per request: 26.250 [ms] (mean, across all concurrent requests)
Transfer rate: 8.22 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 36 51 91.1 39 2122
Processing: 39 54 29.3 46 585
Waiting: 39 52 20.3 46 362
Total: 76 105 96.3 88 2216
Percentage of the requests served within a certain time (ms)
50% 88
66% 93
75% 99
80% 103
90% 119
95% 146
98% 253
99% 397
100% 2216 (longest request)
```
## 監控 kubernets 中的服務與實例
訪問 `http://linkerd.jimmysong.io` 查看流量情況
Outcoming

Incoming

訪問 `http://linkerd-viz.jimmysong.io` 查看應用 metric 監控

## 測試路由
測試在 http header 中增加 dtab 規則。
```bash
$ curl -H "Host: www.hello.world" -H "l5d-dtab:/host/world => /srv/world-v2;" 172.20.0.120:4141
Hello (172.30.60.14) earth (172.30.94.40)!!
```
請注意調用返回的結果,表示調用的是 `world-v2` 的 service。
另外再對比 ab test 的結果與 `linkerd-viz ` 頁面上的結果,可以看到結果一致。
但是我們可能不想把該功能暴露給所有人,所以可以在前端部署一個 nginx 來過濾 header 中的 `l5d-dtab` 打頭的字段,并通過設置 cookie 的方式來替代 header 里的 `l5d-dtab` 字段。
```bash
$ http_proxy=http://172.20.0.120:4141 curl -s http:/hello
Hello (172.30.60.14) world (172.30.71.19)!!
```
## 將 Linkerd 作為 Ingress controller
將 Linkerd 作為 kubernetes ingress controller 的方式跟將 Treafik 作為 ingress controller 的過程過程完全一樣,可以直接參考 [邊緣節點配置](../practice/edge-node-configuration.md)。
架構如下圖所示。

*(圖片來自 A Service Mesh for Kubernetes - Buoyant.io)*
當然可以繞過 kubernetes ingress controller 直接使用 linkerd 作為邊界路由,通過 dtab 和 linkerd 前面的 nginx 來路由流量。
## 參考
- https://github.com/linkerd/linkerd-examples
- [dtab](https://linkerd.io/in-depth/dtabs/)
- 序言
- 云原生
- 云原生(Cloud Native)的定義
- CNCF - 云原生計算基金會簡介
- CNCF章程
- 云原生的設計哲學
- Play with Kubernetes
- 快速部署一個云原生本地實驗環境
- Kubernetes與云原生應用概覽
- 云原生應用之路——從Kubernetes到Cloud Native
- 云原生編程語言
- 云原生編程語言Ballerina
- 云原生編程語言Pulumi
- 云原生的未來
- Kubernetes架構
- 設計理念
- Etcd解析
- 開放接口
- CRI - Container Runtime Interface(容器運行時接口)
- CNI - Container Network Interface(容器網絡接口)
- CSI - Container Storage Interface(容器存儲接口)
- Kubernetes中的網絡
- Kubernetes中的網絡解析——以flannel為例
- Kubernetes中的網絡解析——以calico為例
- 具備API感知的網絡和安全性管理開源軟件Cilium
- Cilium架構設計與概念解析
- 資源對象與基本概念解析
- Pod狀態與生命周期管理
- Pod概覽
- Pod解析
- Init容器
- Pause容器
- Pod安全策略
- Pod的生命周期
- Pod Hook
- Pod Preset
- Pod中斷與PDB(Pod中斷預算)
- 集群資源管理
- Node
- Namespace
- Label
- Annotation
- Taint和Toleration(污點和容忍)
- 垃圾收集
- 控制器
- Deployment
- StatefulSet
- DaemonSet
- ReplicationController和ReplicaSet
- Job
- CronJob
- Horizontal Pod Autoscaling
- 自定義指標HPA
- 準入控制器(Admission Controller)
- 服務發現
- Service
- Ingress
- Traefik Ingress Controller
- 身份與權限控制
- ServiceAccount
- RBAC——基于角色的訪問控制
- NetworkPolicy
- 存儲
- Secret
- ConfigMap
- ConfigMap的熱更新
- Volume
- Persistent Volume(持久化卷)
- Storage Class
- 本地持久化存儲
- 集群擴展
- 使用自定義資源擴展API
- 使用CRD擴展Kubernetes API
- Aggregated API Server
- APIService
- Service Catalog
- 資源調度
- QoS(服務質量等級)
- 用戶指南
- 資源對象配置
- 配置Pod的liveness和readiness探針
- 配置Pod的Service Account
- Secret配置
- 管理namespace中的資源配額
- 命令使用
- Docker用戶過度到kubectl命令行指南
- kubectl命令概覽
- kubectl命令技巧大全
- 使用etcdctl訪問kubernetes數據
- 集群安全性管理
- 管理集群中的TLS
- kubelet的認證授權
- TLS bootstrap
- 創建用戶認證授權的kubeconfig文件
- IP偽裝代理
- 使用kubeconfig或token進行用戶身份認證
- Kubernetes中的用戶與身份認證授權
- Kubernetes集群安全性配置最佳實踐
- 訪問Kubernetes集群
- 訪問集群
- 使用kubeconfig文件配置跨集群認證
- 通過端口轉發訪問集群中的應用程序
- 使用service訪問群集中的應用程序
- 從外部訪問Kubernetes中的Pod
- Cabin - Kubernetes手機客戶端
- Kubernetic - Kubernetes桌面客戶端
- Kubernator - 更底層的Kubernetes UI
- 在Kubernetes中開發部署應用
- 適用于kubernetes的應用開發部署流程
- 遷移傳統應用到Kubernetes中——以Hadoop YARN為例
- 最佳實踐概覽
- 在CentOS上部署Kubernetes集群
- 創建TLS證書和秘鑰
- 創建kubeconfig文件
- 創建高可用etcd集群
- 安裝kubectl命令行工具
- 部署master節點
- 安裝flannel網絡插件
- 部署node節點
- 安裝kubedns插件
- 安裝dashboard插件
- 安裝heapster插件
- 安裝EFK插件
- 生產級的Kubernetes簡化管理工具kubeadm
- 使用kubeadm在Ubuntu Server 16.04上快速構建測試集群
- 服務發現與負載均衡
- 安裝Traefik ingress
- 分布式負載測試
- 網絡和集群性能測試
- 邊緣節點配置
- 安裝Nginx ingress
- 安裝配置DNS
- 安裝配置Kube-dns
- 安裝配置CoreDNS
- 運維管理
- Master節點高可用
- 服務滾動升級
- 應用日志收集
- 配置最佳實踐
- 集群及應用監控
- 數據持久化問題
- 管理容器的計算資源
- 集群聯邦
- 存儲管理
- GlusterFS
- 使用GlusterFS做持久化存儲
- 使用Heketi作為Kubernetes的持久存儲GlusterFS的external provisioner
- 在OpenShift中使用GlusterFS做持久化存儲
- GlusterD-2.0
- Ceph
- 用Helm托管安裝Ceph集群并提供后端存儲
- 使用Ceph做持久化存儲
- 使用rbd-provisioner提供rbd持久化存儲
- OpenEBS
- 使用OpenEBS做持久化存儲
- Rook
- NFS
- 利用NFS動態提供Kubernetes后端存儲卷
- 集群與應用監控
- Heapster
- 使用Heapster獲取集群和對象的metric數據
- Prometheus
- 使用Prometheus監控kubernetes集群
- Prometheus查詢語言PromQL使用說明
- 使用Vistio監控Istio服務網格中的流量
- 分布式跟蹤
- OpenTracing
- 服務編排管理
- 使用Helm管理Kubernetes應用
- 構建私有Chart倉庫
- 持續集成與發布
- 使用Jenkins進行持續集成與發布
- 使用Drone進行持續集成與發布
- 更新與升級
- 手動升級Kubernetes集群
- 升級dashboard
- 領域應用概覽
- 微服務架構
- 微服務中的服務發現
- 使用Java構建微服務并發布到Kubernetes平臺
- Spring Boot快速開始指南
- Service Mesh 服務網格
- 企業級服務網格架構
- Service Mesh基礎
- Service Mesh技術對比
- 采納和演進
- 定制和集成
- 總結
- Istio
- 安裝并試用Istio service mesh
- 配置請求的路由規則
- 安裝和拓展Istio service mesh
- 集成虛擬機
- Istio中sidecar的注入規范及示例
- 如何參與Istio社區及注意事項
- Istio教程
- Istio免費學習資源匯總
- 深入理解Istio Service Mesh中的Envoy Sidecar注入與流量劫持
- 深入理解Istio Service Mesh中的Envoy Sidecar代理的路由轉發
- Linkerd
- Linkerd 使用指南
- Conduit
- Condiut概覽
- 安裝Conduit
- Envoy
- Envoy的架構與基本術語
- Envoy作為前端代理
- Envoy mesh教程
- SOFAMesh
- SOFAMesh中的Dubbo on x-protocol
- SOFAMosn
- 使用 SOFAMosn 構建 SOFAMesh
- 大數據
- Spark standalone on Kubernetes
- 運行支持Kubernetes原生調度的Spark程序
- Serverless架構
- 理解Serverless
- FaaS-函數即服務
- OpenFaaS快速入門指南
- 邊緣計算
- 人工智能