ingress traefik 的暴漏方式
K8s Ingress基本概念
Pod & Service 都会各自拥有一个 IP address 供读取,但这些 IP 仅在 K8s cluster 內部才有办法读取的到,但若要在 K8s cluster 上提供对外服务呢?
而目前可以外部存取 K8s 上服务的方式主要有三种:
-
Service NodePort: 这方法会在每个 master & worker node 上都开启指定的 port number (这样其实造成不少资源浪费), 不方便进行端口管理
-
Service LoadBalancer: 只有在 GCP or AWS 这类的 public cloud 平台才有用的功能
-
Ingress 就是被设计來处理这类的问题
在沒有 Ingress 之前,从外面到 K8s cluster 的流量会如下图:
internet
|
------------
[ Services ]
但在原有的模式下,如果是在公有云 使用 K8s 的话,还可以搭配 LoadBalancer 的 service type 动态取得 LB 对外提供服务;但如果是自己架设 K8s,那就只能透过 Service NodePort 的方式让使用者从外部访问运行在 K8s 上的服务。
Ingress 就是集群内所有服务的入口,rule 的集合,让外面进來的网路流量可以正确的被导到后方的 Service,架构如下图:
internet
|
[ Ingress ]
--|-----|--
[ Services ]
Ingress 可以负责以下工作:
- 基于http-header 的路由
- 基于 path 的路由
- 登录验证
- cros
- 请求速率limit
- rewrite 规则
- ssl
Service、Ingress与Ingress Controller的作用与关系
- Service 是后端真实服务的抽象,一个 Service 可以代表多个相同的后端服务
- Ingress 是反向代理规则,用来规定 HTTP/S 请求应该被转发到哪个 Service 上,比如根据请求中不同的 Host 和 url 路径让请求落到不同的 Service 上
- Ingress Controller 就是一个反向代理程序,它负责解析 Ingress 的反向代理规则,如果 Ingress 有增删改的变动,所有的 Ingress Controller 都会及时更新自己相应的转发规则,当 Ingress Controller 收到请求后就会根据这些规则将请求转发到对应的 Service。
请求流程:
Ingress Controller 收到请求,匹配 Ingress 转发规则,匹配到了就转发到后端 Service,而 Service 可能代表的后端 Pod 有多个,选出一个转发到那个 Pod,最终由那个 Pod 处理请求。
- Ingress Controller 用 Deployment 方式部署,给它添加一个 Service,类型为 LoadBalancer,这样会自动生成一个 IP 地址,通过这个 IP 就能访问到了,并且一般这个 IP 是高可用的(前提是集群支持 LoadBalancer,通常云服务提供商才支持,自建集群一般没有)
- 使用集群内部的某个或某些节点作为边缘节点,给 node 添加 label 来标识,Ingress Controller 用 DaemonSet 方式部署,使用 nodeSelector 绑定到边缘节点,保证每个边缘节点启动一个 Ingress Controller 实例,用 hostPort 直接在这些边缘节点宿主机暴露端口,然后我们可以访问边缘节点中 Ingress Controller 暴露的端口,这样外部就可以访问到 Ingress Controller 了
- Ingress Controller 用 Deployment 方式部署,给它添加一个 Service,类型为 NodePort,部署完成后查看会给出一个端口,通过 kubectl get svc 我们可以查看到这个端口,这个端口在集群的每个节点都可以访问,通过访问集群节点的这个端口就可以访问 Ingress Controller 了
traefik 类型规划
使用traffic-type label
- traffic-type: external
- traffic-type: internal
- traffic-type: public
lable 责任分工
lable | 描述 |
---|---|
traffic-type=internal | 集群内部访问, 仅限部门内程序之间互相调用 |
traffic-type=external | 集群外部访问, 有访问限制 |
traffic-type=public | 集群外部访问,无访问限制 |
traffic-type=devops | 运维部署基础服务使用, 内网类型, 无访问限制 |
traefik 节点label 规划
Key | Value |
---|---|
label | dedicated=edgenode department=devops edgenode=true |
taint | edgenode=true |
为 node 设置 taint 与 label:
kubectl taint nodes node -l edgenode=true dedicated=edgenode department=devops edgenode=true:NoSchedule
or
kubectl label nodes node edgenode=true dedicated=edgenode department=devops
kubectl taint nodes node edgenode=true:NoSchedule
删除taint:
kubectl taint nodes node edgenode:NoSchedule-
删除node的label
kubectl label node node edgenode-
查看 node上的 taint:
kubectl describe nodes node
查看node1的label
kubectl get nodes --show-labels
Traefik 端口范围
type | http | Https | Dashboard |
---|---|---|---|
internal | 10080 | 10443 | 18080 |
external | 20080 | 20443 | 28080 |
public | 30080 | 30443 | 38080 |
devops | 40080 | 40443 | 48080 |
Ingress 使用示例
分场景使用示例
ingress internal使用示例
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: internal
namespace: default
labels:
traffic-type: internal
annotations:
kubernetes.io/ingress.class: traefik
spec:
rules:
- host: ngx-internal.example.com
http:
paths:
- backend:
serviceName: nginx
servicePort: 80
ingress external 使用示例
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: internal
namespace: default
labels:
traffic-type: external
annotations:
kubernetes.io/ingress.class: traefik
spec:
rules:
- host: ngx-external.example.com
http:
paths:
- backend:
serviceName: nginx
servicePort: 80
ingress public 使用示例
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: internal
namespace: default
labels:
traffic-type: public
annotations:
kubernetes.io/ingress.class: traefik
spec:
rules:
- host: ngx-public.example.com
http:
paths:
- backend:
serviceName: nginx
servicePort: 80
ingress Devops 使用示例
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: devops
namespace: default
labels:
traffic-type: devops
annotations:
kubernetes.io/ingress.class: traefik
spec:
rules:
- host: ngx-devops.example.com
http:
paths:
- backend:
serviceName: nginx
servicePort: 80
Traefik 功能示例
Annotate的配置详解
通用配置
- kubernetes.io/ingress.class: traefik
Ingress声明,这里声明了ingress后端采用traefik实现,而不是nginx的controller - ingress.kubernetes.io/whitelist-source-range: "1.2.3.0/24, fe80::/16"
配置访问白名单,支持ipv4和ipv6 - ingress.kubernetes.io/auth-type: basic
http认证模式,此处为basic模式 - ingress.kubernetes.io/auth-secret: mysecret
basic认证的对应的username和password,这里对应的traefik所在kubernetes命名空间里的secrets
前端配置
- traefik.frontend.rule.type: PathPrefixStrip
对于在前端配置多个路径转发时,必须配置改选项。例如: - traefik.frontend.priority: "3"
配置前端的权重,值越高则优先匹配 - traefik.frontend.passHostHeader: "false"
关闭传入Hearder - traefik.protocol=https
使用https协议 - traefik.frontend.entryPoints=http,https
同时支持http和https
后端配置
- traefik.backend.loadbalancer.method=drr
后端Service的负载均衡策略,目前traefik支持的策略包括:wrr(加权轮训调度算法)和drr(动态加权循环调度算法) - traefik.backend.loadbalancer.stickiness=true
是否开启负载均衡器的session亲和性 - traefik.backend.loadbalancer.stickiness.cookieName=NAME
手动配置后端session亲和性的cookie名称 - traefik.backend.loadbalancer.sticky=true
弃用
健康检查
- traefik.backend.healthcheck.path=/health
traefik的监控检查路径 - traefik.backend.healthcheck.interval=5s
健康检查的时间间隔 - traefik.backend.circuitbreaker: "NetworkErrorRatio() > 0.5"
监测某台节点上的服务错误率达到50%时,自动下线该节点。 - traefik.backend.circuitbreaker: "LatencyAtQuantileMS(50.0) > 50"
监测某台节点上服务的延时大于50ms时,自动下线该节点。 - traefik.backend.circuitbreaker: "ResponseCodeRatio(500, 600, 0, 600) > 0.5"
监测某台节点上服务返回状态码为[500-600]在[0-600]区间占比超过50%时,自动下线该节点。
Traffik 自定义https证书
后期配置tls证书, 此证书只允许具有相同namespace ingress使用
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: traefik-web-ui
namespace: kube-system
annotations:
kubernetes.io/ingress.class: traefik
spec:
rules:
- host: traefik-ui.minikube
http:
paths:
- backend:
serviceName: traefik-web-ui
servicePort: 80
tls:
- secretName: traefik-ui-tls-cert
在ingress 创建的空间内创建secert
kubectl -n kube-system create secret tls traefik-ui-tls-cert --key=tls.key --cert=tls.crt
定义后端的分发策略
这里支持多种负载均衡方法:
wrr: 加权轮询
drr: 动态轮询: 这会为表现比其他服务器好的服务器增加权重。当服务器表现有变化的时,它也会会退到正常权重。
定义在service 资源中, 不能定义在ingress资源中
kind: Service
apiVersion: v1
metadata:
name: nginx
annotations:
traefik.ingress.kubernetes.io/load-balancer-method: drr
spec:
selector:
app: nginx
ports:
- protocol: TCP
port: 80
targetPort: 80
session 粘滞
所有的负载平衡器都支持粘滞会话(sticky sessions)。当粘滞会话被开启时,会有一个名称叫做_TRAEFIK_BACKEND的cookie在请求被初始化时被设置在请求初始化时。在随后的请求中,客户端会被直接转发到这个cookie中存储的后端(当然它要是健康可用的),如果这个后端不可用,将会指定一个新的后端。 开启的方法为添加traefik.ingress.kubernetes.io/affinity: "true"
的annotations
定义在service 资源中, 不能定义在ingress资源中
kind: Service
apiVersion: v1
metadata:
name: nginx
annotations:
traefik.ingress.kubernetes.io/affinity: "true"
traefik.ingress.kubernetes.io/load-balancer-method: drr
spec:
selector:
app: nginx
ports:
- protocol: TCP
port: 80
targetPort: 80
请求header 如下
➜ ~ curl -H "Host: ngx09.gxd88.cn" http://internal/api/ -v
GET /api/ HTTP/1.1
Host: ngx09.gxd88.cn
User-Agent: curl/7.51.0
Accept: /
< HTTP/1.1 200 OK
< Accept-Ranges: bytes
< Content-Length: 612
< Content-Type: text/html
< Date: Sun, 05 Aug 2018 04:07:11 GMT
< Etag: "54999765-264"
< Last-Modified: Tue, 23 Dec 2014 16:25:09 GMT
< Server: nginx/1.7.9
< Set-Cookie: _c43d4=http://172.20.0.162:80; Path=/. cookie 记录后端服务IP
< Vary: Accept-Encoding
http 强制跳转https
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: nginx05
namespace: default
labels:
traffic-type: internal
annotations:
traefik.ingress.kubernetes.io/redirect-entry-point: https
spec:
rules:
- host: ngx05.gxd88.cn
http:
paths:
- backend:
serviceName: nginx
servicePort: 80
或者使用rewrite
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: redirectdomain
namespace: default
labels:
traffic-type: internal
annotations:
traefik.ingress.kubernetes.io/redirect-permanent: "true"
traefik.ingress.kubernetes.io/redirect-regex: ^http://(.*)
traefik.ingress.kubernetes.io/redirect-replacement: https://$1
spec:
rules:
- host: redirectdomain.gxd88.cn
http:
paths:
- path: /image
backend:
serviceName: nginx
servicePort: 80
自定义请求header
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: internal
namespace: default
labels:
traffic-type: internal
annotations:
kubernetes.io/ingress.class: traefik
ingress.kubernetes.io/custom-request-headers: traffic-type:internal||team:devops
spec:
rules:
- host: ngx-internal.gxd88.cn
http:
paths:
- backend:
serviceName: nginx
servicePort: 80
请求路径前添加路径
---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: addpath
namespace: default
labels:
traffic-type: internal
annotations:
traefik.ingress.kubernetes.io/request-modifier: AddPrefix:/api
spec:
rules:
- host: ngx09.gxd88.com
http:
paths:
- path: /a
backend:
serviceName: nginx
servicePort: 80
请求ngx09.gxd88.cn/a
到后端服务为/api/a
请求路径删除前缀
---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: deletepath01
namespace: default
labels:
traffic-type: internal
annotations:
kubernetes.io/ingress.class: traefik
traefik.ingress.kubernetes.io/rule-type: PathPrefixStrip
spec:
rules:
- host: del.gxd88.cn
http:
paths:
- path: /api/v1
backend:
serviceName: nginx
servicePort: 80
请求del.gxd88.cn/api/v1/1
到后端为del.gxd88.cn/1
定义白名单
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: nginx03
namespace: default
annotations:
kubernetes.io/ingress.class: traefik-external
ingress.kubernetes.io/whitelist-x-forwarded-for: "false"
traefik.ingress.kubernetes.io/whitelist-source-range: "10.40.0.227"
spec:
rules:
- host: ngx03.gxd88.cn
http:
paths: /api
- backend:
serviceName: nginx
servicePort: 80