轉載請注明出處:http://www.cnblogs.com/wayneiscoming/p/7707942.html
traefik 是一個前端http反向代理服務器以及負載均衡器,支持多種微服務后端(Docker,Swarm,Kubernetes,Marathon,Consul,Etcd,Rancher,Amazon ECS等);同 nginx 等相比,traefik 能夠自動感知后端服務新增刪除升級等變化,並實現自動配置。
一、Kubernetes 服務暴露介紹
本節內容節選自漠然博客Traefik-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 該規則便可實現服務發現,即動態映射。
二、Traefik 簡介及部署
由於微服務架構以及 Docker 技術和 kubernetes 編排工具最近幾年才開始逐漸流行,所以一開始的反向代理服務器比如 nginx、apache 並未提供其支持,畢竟他們也不是先知;所以才會出現 Ingress Controller 這種東西來做 kubernetes 和前端負載均衡器如 nginx 之間做銜接;即 Ingress Controller 的存在就是為了能跟 kubernetes 交互,又能寫 nginx 配置,還能 reload 它,這是一種折中方案;而最近開始出現的 traefik 天生就是提供了對 kubernetes 的支持,也就是說 traefik 本身就能跟 kubernetes API 交互,感知后端變化,因此可以得知: 在使用 traefik 時,Ingress Controller 已經無卵用了,所以整體架構如下:
2.1、部署 Traefik
由於我們需要將外部對於kubernetes的http請求全都轉換成https,不想更改服務的配置以及代碼,那我們可以選擇在traefik上配置域名證書,這樣通過域名對服務的訪問將會自動轉換成https請求。我的Kubernetes集群是在微軟雲上部署的,Node前端使用Azure負載均衡器來均衡請求,所以Traefik我將使用NodePort方式暴露服務。
2.1.1、創建ClusterRole以及ClusterRoleBinding(Kubernetes1.6+)
如果你的集群配置了RBAC,則需要賦予Traefik調用Kubernetes API的權限:
# kubectl create -f ./ClusterRole_Binding.yaml

---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
name: traefik-ingress-controller
rules:
- apiGroups:
- ""
resources:
- services
- endpoints
- secrets
verbs:
- get
- list
- watch
- apiGroups:
- extensions
resources:
- ingresses
verbs:
- get
- list
- watch
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
name: traefik-ingress-controller
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: traefik-ingress-controller
subjects:
- kind: ServiceAccount
name: traefik-ingress-controller
namespace: kube-system
2.1.2、創建secret保存HTTPS證書
若沒有證書請先生成證書,我本次使用的是現有的域名證書。
# openssl req -newkey rsa:2048 -nodes -keyout domain.com.key -x509 -days 365 -out domain.com.crt
# kubectl create secret generic traefik-cert --from-file=domain.com.crt --from-file=domain.com.key --namespace=kube-system
2.1.3、創建configmap保存Traefik配置文件
我們這里只做HTTP請求轉至HTTPS配置,關於Traefik詳細配置請參考官方文檔 https://docs.traefik.io/configuration/commons/
# kubectl create configmap traefik-conf --from-file=traefik.toml --namespace=kube-system
# cat traefik.toml
defaultEntryPoints = ["http","https"] [entryPoints] [entryPoints.http] address = ":80" [entryPoints.http.redirect] entryPoint = "https" [entryPoints.https] address = ":443" [entryPoints.https.tls] [[entryPoints.https.tls.certificates]] CertFile = "/ssl/domain.com.crt" KeyFile = "/ssl/domain.com.key"
2.1.4、通過Deployment部署Traefik
# kubectl create -f ./traefik-deployment.yaml

# cat traefik-deployment.yaml
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: traefik-ingress-controller
namespace: kube-system
---
kind: Deployment
apiVersion: extensions/v1beta1
metadata:
name: traefik-ingress-controller
namespace: kube-system
labels:
k8s-app: traefik-ingress-lb
spec:
replicas: 1
selector:
matchLabels:
k8s-app: traefik-ingress-lb
template:
metadata:
labels:
k8s-app: traefik-ingress-lb
name: traefik-ingress-lb
spec:
serviceAccountName: traefik-ingress-controller
terminationGracePeriodSeconds: 60
volumes:
- name: ssl
secret:
secretName: traefik-cert
- name: config
configMap:
name: traefik-conf
containers:
- image: traefik
name: traefik-ingress-lb
volumeMounts:
- mountPath: "/ssl"
name: "ssl"
- mountPath: "/config"
name: "config"
ports:
- containerPort: 80
- containerPort: 443
args:
- --configfile=/config/traefik.toml
- --web
- --kubernetes
---
kind: Service
apiVersion: v1
metadata:
name: traefik
namespace: kube-system
spec:
type: NodePort
ports:
- protocol: TCP
port: 80
name: http
- protocol: TCP
port: 443
name: https
selector:
k8s-app: traefik-ingress-lb
2.1.5、部署traefik-ui服務以及traefik-ui ingress
# kubectl create -f ./traefik-ui.yaml

# cat traefik-ui.yaml
apiVersion: v1
kind: Service
metadata:
name: traefik-web-ui
namespace: kube-system
spec:
selector:
k8s-app: traefik-ingress-lb
ports:
- port: 80
targetPort: 8080
---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: traefik-web-ui
namespace: kube-system
annotations:
kubernetes.io/ingress.class: traefik
spec:
tls:
- secretName: traefik-cert
rules:
- host: traefik-ui.domain.com
http:
paths:
- backend:
serviceName: traefik-web-ui
servicePort: 80
2.1.6、創建負載均衡規則后端綁定traefik端口,以及traefik域名解析到負載均衡前端公共IP
通過traefik-ui.domain.com訪問到traefik-ui服務,可以發現網址自動跳轉至https協議。
2.1.7、基於路徑訪問服務的ingress舉例
先創建3個后端服務:svc1、svc2、svc3,我們希望通過abcd.domain.com/s*的方式來訪問服務,因為這樣我們只需要添加一個abcd.domain.com域名解析,以下是配置示例:

# RC for svc1
kind: ReplicationController
apiVersion: v1
metadata:
name: svc1
spec:
replicas: 1
selector:
template:
metadata:
labels:
app: svc1
spec:
containers:
- name: svc1
image: docker.io/patrickeasters/example-web-service
env:
- name: APP_SVC
value: svc1
ports:
- containerPort: 8080
protocol: TCP
---
# RC for svc2
kind: ReplicationController
apiVersion: v1
metadata:
name: svc2
spec:
replicas: 1
selector:
template:
metadata:
labels:
app: svc2
spec:
containers:
- name: svc2
image: docker.io/patrickeasters/example-web-service
env:
- name: APP_SVC
value: svc2
ports:
- containerPort: 8080
protocol: TCP
---
# RC for svc3
kind: ReplicationController
apiVersion: v1
metadata:
name: svc3
spec:
replicas: 1
selector:
template:
metadata:
labels:
app: svc3
spec:
containers:
- name: svc3
image: docker.io/patrickeasters/example-web-service
env:
- name: APP_SVC
value: svc3
ports:
- containerPort: 8080
protocol: TCP
---
# Service for svc1
kind: Service
apiVersion: v1
metadata:
labels:
app: svc1
name: svc1
spec:
type: ClusterIP
ports:
- port: 8080
name: http
selector:
app: svc1
---
# Service for svc2
kind: Service
apiVersion: v1
metadata:
labels:
app: svc2
name: svc2
spec:
type: ClusterIP
ports:
- port: 8080
name: http
selector:
app: svc2
---
# Service for svc3
kind: Service
apiVersion: v1
metadata:
labels:
app: svc3
name: svc3
spec:
type: ClusterIP
ports:
- port: 8080
name: http
selector:
app: svc3
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: example-web-app
annotations:
kubernetes.io/ingress.class: "traefik"
spec:
tls:
- secretName: traefik-cert
rules:
- host: abcs.domain.com
http:
paths:
- path: /s1
backend:
serviceName: svc1
servicePort: 8080
- path: /s2
backend:
serviceName: svc2
servicePort: 8080
- path: /
backend:
serviceName: svc3
servicePort: 8080
$ curl -k https://abcd.domain.com/s1
Hi, I'm the svc1 service!
Hostname: svc1-sd123
$ curl -k https://abcd.domain.com/s2
Hi, I'm the svc2 service!
Hostname: svc2-isdf3
$ curl -k https://abcd.domain.com/
Hi, I'm the svc3 service!
Hostname: svc3-r23r
$ curl -k https://abcd.domain.com/xxxx
Hi, I'm the svc3 service!
Hostname: svc3-r23r
本文參考:
https://mritd.me/2016/12/06/try-traefik-on-kubernetes
https://medium.com/@patrickeasters/using-traefik-with-tls-on-kubernetes-cb67fb43a948
官方文檔:https://docs.traefik.io/