### 一、Kubernetes 服務暴露介紹
**從 kubernetes 1.2 版本開始,kubernetes提供了 Ingress 對象來實現對外暴露服務;到目前為止 kubernetes 總共有三種暴露服務的方式:**
* LoadBlancer Service
* NodePort Service
* Ingress
#### 1.1、LoadBlancer Service
LoadBlancer Service 是 kubernetes 深度結合云平臺的一個組件;當使用 LoadBlancer Service 暴露服務時,實際上是通過向底層云平臺申請創建一個負載均衡器來向外暴露服務;目前 LoadBlancer Service 支持的云平臺已經相對完善,比如國外的 GCE、DigitalOcean,國內的 阿里云,私有云 Openstack 等等,由于 LoadBlancer Service 深度結合了云平臺,所以只能在一些云平臺上來使用
#### 1.2、NodePort Service
NodePort Service 顧名思義,實質上就是通過在集群的每個 node 上暴露一個端口,然后將這個端口映射到某個具體的 service 來實現的,雖然每個 node 的端口有很多(0~65535),但是由于安全性和易用性(服務多了就亂了,還有端口沖突問題)實際使用可能并不多
#### 1.3、Ingress
Ingress 這個東西是 1.2 后才出現的,通過 Ingress 用戶可以實現使用 nginx 等開源的反向代理負載均衡器實現對外暴露服務,以下詳細說一下 Ingress,畢竟 traefik 用的就是 Ingress
**使用 Ingress 時一般會有三個組件:**
* 反向代理負載均衡器
* Ingress Controller
* Ingress
#### 1.3.1、反向代理負載均衡器
反向代理負載均衡器很簡單,說白了就是 nginx、apache 什么的;在集群中反向代理負載均衡器可以自由部署,可以使用 Replication Controller、Deployment、DaemonSet 等等,不過個人喜歡以 DaemonSet 的方式部署,感覺比較方便
#### 1.3.2、Ingress Controller
Ingress Controller 實質上可以理解為是個監視器,Ingress Controller 通過不斷地跟 kubernetes API 打交道,實時的感知后端 service、pod 等變化,比如新增和減少 pod,service 增加與減少等;當得到這些變化信息后,Ingress Controller 再結合下文的 Ingress 生成配置,然后更新反向代理負載均衡器,并刷新其配置,達到服務發現的作用
#### 1.3.3、Ingress
Ingress 簡單理解就是個規則定義;比如說某個域名對應某個 service,即當某個域名的請求進來時轉發給某個 service;這個規則將與 Ingress Controller 結合,然后 Ingress Controller 將其動態寫入到負載均衡器配置中,從而實現整體的服務發現和負載均衡
懵逼就看圖

從上圖中可以很清晰的看到,實際上請求進來還是被負載均衡器攔截,比如 nginx,然后 Ingress Controller 通過跟 Ingress 交互得知某個域名對應哪個 service,再通過跟 kubernetes API 交互得知 service 地址等信息;綜合以后生成配置文件實時寫入負載均衡器,然后負載均衡器 reload 該規則便可實現服務發現,即動態映射
了解了以上內容以后,這也就很好的說明了我為什么喜歡把負載均衡器部署為 Daemon Set;因為無論如何請求首先是被負載均衡器攔截的,所以在每個 node 上都部署一下,同時 hostport 方式監聽 80 端口;那么就解決了其他方式部署不確定 負載均衡器在哪的問題,同時訪問每個 node 的 80 都能正確解析請求;如果前端再 放個 nginx 就又實現了一層負載均衡
### 二、Traefik 使用
由于微服務架構以及 Docker 技術和 kubernetes 編排工具最近幾年才開始逐漸流行,所以一開始的反向代理服務器比如 nginx、apache 并未提供其支持,畢竟他們也不是先知;所以才會出現 Ingress Controller 這種東西來做 kubernetes 和前端負載均衡器如 nginx 之間做銜接;即 Ingress Controller 的存在就是為了能跟 kubernetes 交互,又能寫 nginx 配置,還能 reload 它,這是一種折中方案;而最近開始出現的 traefik 天生就是提供了對 kubernetes 的支持,也就是說 traefik 本身就能跟 kubernetes API 交互,感知后端變化,因此可以得知: 在使用 traefik 時,Ingress Controller 已經無卵用了,所以整體架構如下


從上圖可以看出,在我們日常業務開發中,我們會部署一系列微服務,外部網絡要通過 domain、path、負載均衡等轉發到后端私有網絡中,微服務之所以稱為微,是因為它是動態變化的,它會經常被增加、刪除、干掉或者被更新。而且傳統的反向代理對服務動態變化的支持不是很方便,也就是服務變更后,我們不是很容易立馬改變配置和熱加載。traefik 的出現就是為了解決這個問題,它可以時刻監聽服務注冊或服務編排 API,隨時感知后端服務變化,自動重新更改配置并熱重新加載,期間服務不會暫停或停止,這對于用戶來說是無感知的。
Traefik 還有很多特性如下:
* 速度快
* 不需要安裝其他依賴,使用 GO 語言編譯可執行文件
* 支持最小化官方 Docker 鏡像
* 支持多種后臺,如 Docker, Swarm mode, Kubernetes, Marathon, Consul, Etcd, Rancher, Amazon ECS 等等
* 支持 REST API
* 配置文件熱重載,不需要重啟進程
* 支持自動熔斷功能
* 支持輪訓、負載均衡
* 提供簡潔的 UI 界面
* 支持 Websocket, HTTP/2, GRPC
* 自動更新 HTTPS 證書
* 支持高可用集群模式
### 2.1、部署 Traefik
#### 2.1.1、部署 Daemon Set
首先以 Daemon Set 的方式在每個 node 上啟動一個 traefik,并使用 hostPort 的方式讓其監聽每個 node 的 80 端口(有沒有感覺這就是個 NodePort? 不過區別就是這個 Port 后面有負載均衡器 )
```
cd /mnt
git clone https://github.com/containous/traefik.git
ls
-rw-r--r--. 1 root root 1805 11月 9 16:23 cheese-deployments.yaml
-rw-r--r--. 1 root root 1805 11月 9 16:23 cheese-default-ingress.yaml
-rw-r--r--. 1 root root 519 11月 9 16:23 cheese-ingress.yaml
-rw-r--r--. 1 root root 509 11月 9 16:23 cheese-services.yaml
-rw-r--r--. 1 root root 504 11月 9 16:23 cheeses-ingress.yaml
-rw-r--r--. 1 root root 978 11月 9 16:23 traefik-deployment.yaml
-rw-r--r--. 1 root root 1128 11月 9 16:23 traefik-ds.yaml
-rw-r--r--. 1 root root 694 11月 9 16:23 traefik-rbac.yaml
-rw-r--r--. 1 root root 466 11月 9 16:43 ui.yaml
```
* 官網一共給出了九個yaml文件,這里我們只需要最下面4個配置文件,
* traefik-deployment.yaml ------以deployment方式部署traefik
* traefik-ds.yaml----------以Daemon set 方式部署traefik
* traefik-rbac.yaml---------rbac授權
* ui.yaml------web-ui 的配置文件
以deployment和deamon方式部署,只需要選取一個配置文件
官網給出的配置文件可能會有端口沖突,這里我修改了以下
```
[root@localhost tk]# cat Depeloyment.yaml
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: traefik-ingress-lb
namespace: kube-system
labels:
k8s-app: traefik-ingress-lb
spec:
template:
metadata:
labels:
k8s-app: traefik-ingress-lb
name: traefik-ingress-lb
spec:
terminationGracePeriodSeconds: 60
hostNetwork: true
restartPolicy: Always
serviceAccountName: ingress
containers:
- image: traefik
name: traefik-ingress-lb
resources:
limits:
cpu: 200m
memory: 30Mi
requests:
cpu: 100m
memory: 20Mi
ports:
- name: http
containerPort: 80
hostPort: 80
- name: admin
containerPort: 8580
hostPort: 8580
args:
- --web
- --web.address=:8580
- --kubernetes
```
```
[root@localhost tk]# cat ingress-rbac.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
name: ingress
namespace: kube-system
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
name: ingress
subjects:
- kind: ServiceAccount
name: ingress
namespace: kube-system
roleRef:
kind: ClusterRole
name: cluster-admin
apiGroup: rbac.authorization.k8s.io
```
```
[root@localhost tk]# cat Traefik-ui.yaml
apiVersion: v1
kind: Service
metadata:
name: traefik-web-ui
namespace: kube-system
spec:
selector:
k8s-app: traefik-ingress-lb
ports:
- name: web
port: 80
targetPort: 8580
---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: traefik-web-ui
namespace: kube-system
spec:
rules:
- host: traefik-ui.local
http:
paths:
- path: /
backend:
serviceName: traefik-web-ui
servicePort: web
```
下面我們來部署這個三個程序
```
kubectl create -f .
[root@localhost tk]# kubectl get pod --all-namespaces
NAMESPACE NAME READY STATUS RESTARTS AGE
default aa-tqv77 1/1 Running 54 6d
default frontend-7mfsh 1/1 Running 3 10d
default frontend-m8fkw 1/1 Running 3 10d
default frontend-x4tzj 1/1 Running 3 10d
default mc-deployment-2805008544-bn05x 1/1 Running 57 6d
default my-nginx-543887649-4gh28 1/1 Running 17 29d
default my-nginx-543887649-lxxcw 1/1 Running 17 29d
default my-nginx-pod-2945913857-88lml 1/1 Running 17 29d
default my-nginx-pod-2945913857-nwrlv 1/1 Running 17 29d
default redis-master-r04fz 1/1 Running 3 10d
default redis-slave-w3zr1 1/1 Running 3 10d
default redis-slave-xq3pf 1/1 Running 3 10d
kube-system heapster-2315332064-xhtf5 1/1 Running 11 19d
kube-system kube-dns-3574069718-19d9v 3/3 Running 42 5d
kube-system kubernetes-dashboard-1211493743-c6pzc 1/1 Running 577 32d
kube-system monitoring-grafana-3319647107-7zrrw 1/1 Running 10 19d
kube-system monitoring-influxdb-3480804314-0d7dd 1/1 Running 12 19d
kube-system traefik-ingress-lb-4237248072-xtfpd 1/1 Running 0 1h
monitoring alertmanager-1970416631-psl30 1/1 Running 8 16d
monitoring grafana-core-83531447-8dc8d 1/1 Running 8 16d
monitoring grafana-import-dashboards-cj7l2 0/1 ImagePullBackOff 0 15d
monitoring kube-state-metrics-2949788559-m707v 1/1 Running 168 16d
monitoring kube-state-metrics-2949788559-qm500 1/1 Running 168 16d
monitoring node-directory-size-metrics-6c8vn 2/2 Running 16 16d
monitoring prometheus-core-3718210518-plh5b 1/1 Running 8 16d
monitoring prometheus-node-exporter-hx204 1/1 Running 8 16d
[root@localhost tk]# kubectl get svc --all-namespaces
NAMESPACE NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
default aa 10.254.110.166 <nodes> 8081:30002/TCP 6d
default frontend 10.254.198.99 <nodes> 80:30001/TCP 10d
default kubernetes 10.254.0.1 <none> 443/TCP 41d
default mc 10.254.226.32 <nodes> 8081:30008/TCP 6d
default my-nginx 10.254.78.8 <none> 80/TCP 29d
default redis-master 10.254.211.158 <none> 6379/TCP 10d
default redis-slave 10.254.160.65 <none> 6379/TCP 10d
kube-system heapster 10.254.108.150 <none> 80/TCP 19d
kube-system kube-dns 10.254.0.2 <none> 53/UDP,53/TCP 5d
kube-system kubernetes-dashboard 10.254.31.8 <nodes> 80:30946/TCP 32d
kube-system monitoring-grafana 10.254.195.244 <none> 80/TCP 19d
kube-system monitoring-influxdb 10.254.81.32 <none> 8086/TCP 19d
kube-system traefik-web-ui 10.254.169.196 <none> 80/TCP 1h
monitoring alertmanager 10.254.35.245 <nodes> 9093:32006/TCP 16d
monitoring grafana 10.254.125.218 <nodes> 3000:30474/TCP 16d
monitoring kube-state-metrics 10.254.67.171 <none> 8080/TCP 16d
monitoring prometheus 10.254.158.209 <nodes> 9090:31023/TCP 16d
monitoring prometheus-node-exporter None <none> 9100/TCP 16d
[root@localhost tk]# kubectl get endpoints --all-namespaces
NAMESPACE NAME ENDPOINTS AGE
default aa 172.30.72.18:8081 6d
default frontend 172.30.72.14:80,172.30.72.17:80,172.30.72.9:80 10d
default kubernetes 172.16.168.129:6443 41d
default mc <none> 6d
default my-nginx 172.30.72.20:80,172.30.72.23:80 29d
default redis-master 172.30.72.22:6379 10d
default redis-slave 172.30.72.21:6379,172.30.72.24:6379 10d
kube-system heapster 172.30.72.4:8082 19d
kube-system kube-controller-manager <none> 15h
kube-system kube-dns 172.30.72.6:53,172.30.72.6:53 5d
kube-system kube-scheduler <none> 15h
kube-system kubernetes-dashboard 172.30.72.8:9090 32d
kube-system monitoring-grafana 172.30.72.16:3000 19d
kube-system monitoring-influxdb 172.30.72.11:8086 19d
kube-system traefik-web-ui 172.16.168.129:8580 1h
monitoring alertmanager 172.30.72.10:9093 16d
monitoring grafana 172.30.72.15:3000 16d
monitoring kube-state-metrics 172.30.72.13:8080,172.30.72.7:8080 16d
monitoring prometheus 172.30.72.5:9090 16d
monitoring prometheus-node-exporter 172.16.168.129:9100 16d
```
下面我們做測試,看我們后端的服務是否可以通過dns服務發現,被ingress負載到
由于我之前在集群中部署過redis-frontend的留言版程序,還有nginx程序,這里就直接
創建ingress的yaml文件
```
[root@localhost tk]# cat frontend.ingress.yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: traefik-ingress
spec:
rules:
- host: traefik.nginx.io
http:
paths:
- path: /
backend:
serviceName: my-nginx
servicePort: 80
- host: traefik.frontend.io
http:
paths:
- path: /
backend:
serviceName: frontend
servicePort: 80
```
注意,server一定要寫對應的服務,serviceport就寫服務原始自帶的端口,比如nginx就是80端口。
```
kubectl create -f frontend.ingress.yaml
kubectl get ingress --all-namespaces
NAMESPACE NAME HOSTS ADDRESS PORTS AGE
default traefik-ingress traefik.nginx.io,traefik.frontend.io 80 1h
kube-system traefik-web-ui traefik-ui.local 80 1h
```
上圖可以看到,我們創建的ingress都創建成功了。
我們現在可以通過域名訪問我們的服務了
訪問之前一定要把host記錄編輯好,這里的主機可以填寫任意的node節點
·```
172.16.168.129 traefik.frontend.io
172.16.168.129 traefik.nginx.io
```


