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
ClusterRole_Binding.yaml
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
traefik-deployment.yaml
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
traefik-ui.yaml
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
svc-rc
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/