1 traefik理论概览
https://docs.traefik.io/
https://docs.traefik.cn/user-guide/kubernetes
假设你已经在你的基础设施上部署了一堆微服务。你可能使用了一个服务发现系统(例如 etcd 或 consul)或者一个资源管理框架(swarm,Mesos/Marathon)来管理所有这些服务。
如果你想让你的用户去从互联网访问你的某些微服务, 你就必需使用虚拟hosts或前缀路径来配置一个反向代理:
- 域名 api.domain.com 将指向你的私有网络中的微服务 api
- 路径 domain.com/web 将指向你的私有网络中的微服务 web
- 域名 backoffice.domain.com 将指向你的私有网络中的微服务 backoffice ,在你的多台实例之间负载均衡
但是,微服务在会经常被添加、移除、杀死或更新,可能一天之内就会发生许多次。
传统的反向代理原生不支持动态配置。你不可能轻易的通过热更新更改它们的配置。
这时,Træfɪk就诞生了。
2 安装配置
https://docs.traefik.io/getting-started/install-traefik/#use-the-binary-distribution
2.1 二进制安装
wget https://github.com/containous/traefik/releases/download/v2.2.8/traefik_v2.2.8_linux_amd64.tar.gz
tar xvfz traefik_v2.2.8_linux_amd64.tar.gz
./traefik --help
2.2 docker安装
docker run -d -p 8080:8080 -p 80:80 \
-v $PWD/traefik.toml:/etc/traefik/traefik.toml traefik:v2.2
2.3 helm3安装traefik v1
- 前提:k8s集群1.14+,helm 3.X
helm repo add stable https://kubernetes-charts.storage.googleapis.com/
helm repo update
helm install traefik stable/traefik --set dashboard.enabled=true,serviceType=NodePort,dashboard.domain=dashboard.traefik,rbac.enabled=true --namespace kube-system
查看service的端口
在本机的/etc/hosts中添加解析
172.16.212.11 dashboard.traefik
访问 http://dashboard.traefik:12577即可!
此时,无法访问https
2.4 helm3安装traefik v2
- 安装
helm repo add traefik https://containous.github.io/traefik-helm-chart
helm repo update
helm install traefik traefik/traefik
- 修改service端口暴露方式
kubectl edit service traefik
spec:
clusterIP: 192.168.255.168
externalTrafficPolicy: Cluster
ports:
- name: web
nodePort: 30080
port: 80
protocol: TCP
targetPort: web
- name: websecure
nodePort: 30443
port: 443
protocol: TCP
targetPort: websecure
selector:
app.kubernetes.io/instance: traefik
app.kubernetes.io/name: traefik
sessionAffinity: None
type: NodePort
- 转发dashboard
# dashboard.yaml
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
name: dashboard
spec:
entryPoints:
- web
routes:
- match: Host(`traefik.guici.com`) && (PathPrefix(`/dashboard`) || PathPrefix(`/api`))
kind: Rule
services:
- name: api@internal
kind: TraefikService
kubectl apply -f dashboard.yaml
在本机的/etc/hosts中添加解析
172.16.212.11 traefik.guici.com
访问 http://traefik.guici.com:30080/dashboard/ 即可!
此时无法访问https
2.5 yaml方式部署traefik v2
详见https://www.qikqiak.com/post/traefik-2.1-101/
- crd.yaml
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
name: ingressroutes.traefik.containo.us
spec:
group: traefik.containo.us
version: v1alpha1
names:
kind: IngressRoute
plural: ingressroutes
singular: ingressroute
scope: Namespaced
---
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
name: ingressroutetcps.traefik.containo.us
spec:
group: traefik.containo.us
version: v1alpha1
names:
kind: IngressRouteTCP
plural: ingressroutetcps
singular: ingressroutetcp
scope: Namespaced
---
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
name: middlewares.traefik.containo.us
spec:
group: traefik.containo.us
version: v1alpha1
names:
kind: Middleware
plural: middlewares
singular: middleware
scope: Namespaced
---
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
name: tlsoptions.traefik.containo.us
spec:
group: traefik.containo.us
version: v1alpha1
names:
kind: TLSOption
plural: tlsoptions
singular: tlsoption
scope: Namespaced
---
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
name: traefikservices.traefik.containo.us
spec:
group: traefik.containo.us
version: v1alpha1
names:
kind: TraefikService
plural: traefikservices
singular: traefikservice
scope: Namespaced
- rbac.yaml
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: traefik
rules:
- apiGroups:
- ""
resources:
- pods
- services
- endpoints
- secrets
verbs:
- get
- list
- watch
- apiGroups:
- extensions
resources:
- ingresses
verbs:
- get
- list
- watch
- apiGroups:
- extensions
resources:
- ingresses/status
verbs:
- update
- apiGroups:
- traefik.containo.us
resources:
- ingressroutes
- ingressroutetcps
- middlewares
- tlsoptions
- traefikservices
verbs:
- get
- list
- watch
---
kind: ServiceAccount
apiVersion: v1
metadata:
name: traefik
namespace: kube-system
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: traefik
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: traefik
subjects:
- kind: ServiceAccount
name: traefik
namespace: kube-system
- deployment.yaml (使用了下面提到的使用阿里云dns作为获取证书的途径,需要创建secret)
apiVersion: apps/v1
kind: Deployment
metadata:
name: traefik
namespace: kube-system
labels:
app: traefik
spec:
selector:
matchLabels:
app: traefik
strategy:
type: Recreate
template:
metadata:
labels:
app: traefik
spec:
serviceAccountName: traefik
tolerations:
- operator: "Exists"
nodeSelector:
kubernetes.io/hostname: node-name
volumes:
- name: acme
hostPath:
path: /data/k8s/traefik/acme
containers:
- image: traefik:2.2.1
name: traefik
ports:
- name: web
containerPort: 80
hostPort: 80
- name: websecure
containerPort: 443
hostPort: 443
- name: mongo
hostPort: 27017
containerPort: 27017
- name: postgres
hostPort: 5432
containerPort: 5432
- name: redis
hostPort: 6379
containerPort: 6379
args:
- --entryPoints.web.address=:80
- --entryPoints.websecure.address=:443
- --entryPoints.mongo.address=:27017
- --entryPoints.postgres.address=:5432
- --entryPoints.redis.address=:6379
- --api=true
- --api.dashboard=true
- --ping=true
- --providers.kubernetesingress
- --providers.kubernetescrd
- --serversTransport.insecureSkipVerify=true
# - --providers.file.filename=/config/traefik-tls.toml
- --log.level=INFO
- --accesslog
# 使用 dns 验证方式
- --certificatesResolvers.ali.acme.dnsChallenge.provider=alidns
# 邮箱配置
- --certificatesResolvers.ali.acme.email=ych_1024@163.com
# 保存 ACME 证书的位置
- --certificatesResolvers.ali.acme.storage=/etc/acme/acme.json
# 下面是用于测试的ca服务,如果https证书生成成功了,则移除下面参数
# - --certificatesresolvers.ali.acme.caserver=https://acme-staging-v02.api.letsencrypt.org/directory
envFrom:
- secretRef:
name: traefik-alidns-secret #这个secret是需要手动创建的,详见2.6.1
# ALICLOUD_ACCESS_KEY
# ALICLOUD_SECRET_KEY
# ALICLOUD_REGION_ID
volumeMounts:
- name: acme
mountPath: /etc/acme
# - name: config
# mountPath: /config
# - name: certs
# mountPath: /certs
resources:
requests:
cpu: "50m"
memory: "50Mi"
limits:
cpu: "200m"
memory: "100Mi"
securityContext:
allowPrivilegeEscalation: true
capabilities:
drop:
- ALL
add:
- NET_BIND_SERVICE
readinessProbe:
httpGet:
path: /ping
port: 8080
failureThreshold: 1
initialDelaySeconds: 10
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 2
livenessProbe:
httpGet:
path: /ping
port: 8080
failureThreshold: 3
initialDelaySeconds: 10
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 2
- dashboard.yaml
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
name: traefik-dashboard
spec:
routes:
- match: Host(`traefik.guici.com`)
kind: Rule
services:
- name: api@internal
kind: TraefikService
---
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
name: traefik-dashboard-tls
spec:
entryPoints:
- websecure
routes:
- match: Host(`traefik.qikqiak.com`)
kind: Rule
services:
- name: api@internal
kind: TraefikService
tls:
certResolver: ali
domains:
- main: "*.qikqiak.com"
# tls:
# secretName: who-tls
# ---
# apiVersion: traefik.containo.us/v1alpha1
# kind: Middleware
# metadata:
# name: auth
# spec:
# basicAuth:
# secret: secretName # Kubernetes secret named "secretName"
2.6 配置支持https访问
用 HTTPS 访问应用必然就需要证书
2.6.1 使用阿里云的dns提供商获取证书——这种方式是生产常用方式
- 准备工作
需要api接口的accesskey,secretkey和阿里云区域名称;
- 1)创建secret
kubectl -n default create secret generic traefik-alidns-secret \
--from-literal=ALICLOUD_ACCESS_KEY=<your-access-key> \
--from-literal=ALICLOUD_SECRET_KEY=<your-secret-key> \
--from-literal=ALICLOUD_REGION_ID=<aliyun-region>
- 2)编辑deploy
template:
metadata:
labels:
app: traefik
spec:
serviceAccountName: traefik
tolerations:
- operator: "Exists"
nodeSelector:
traefik: "true"
containers:
- image: traefik:v2.1.9
name: traefik
ports:
- name: web
containerPort: 80
hostPort: 80
- name: websecure
containerPort: 443
hostPort: 443
- name: metrics
hostPort: 8082
containerPort: 8082
args:
- --entryPoints.web.address=:80
- --entryPoints.websecure.address=:443
- --api=true
- --api.dashboard=true
- --ping=true
- --providers.kubernetesingress
- --providers.kubernetescrd
- --log.level=INFO
- --accesslog
- --accesslog.filepath=/logs/access.log
- --log
- --log.filepath=/logs/traefik.log
- --serverstransport.insecureskipverify=true
- --certificatesResolvers.ali.acme.dnsChallenge.provider=alidns #1
- --certificatesResolvers.ali.acme.email=example@qq.com #2
- --certificatesResolvers.ali.acme.storage=/etc/acme/acme.json #3
- --entryPoints.metrics.address=:8082
- --metrics.prometheus=true
- --metrics.prometheus.buckets=0.100000, 0.300000, 1.200000, 5.000000
- --metrics.prometheus.addEntryPointsLabels=true
- --metrics.prometheus.addServicesLabels=true
- --metrics.prometheus.entryPoint=metrics
- --metrics.prometheus.manualrouting=true
envFrom:
- secretRef:
name: traefik-alidns-secret #4
2.6.2 也可以使用自签名的证书——一般只在测试时用
#创建证书
openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout traefik-tls.key -out traefik-tls.crt -subj "/CN=traefik.qikqiak.com"
#通过 Secret 对象来引用证书文件
kubectl create secret tls traefik-tls --cert=traefik-tls.crt --key=traefik-tls.key
#修改 ingressroute
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
name: traefik-dashboard-tls
spec:
entryPoints:
- websecure
routes:
- match: Host(`traefik.qikqiak.com`)
kind: Rule
services:
- name: api@internal
kind: TraefikService
tls:
secretName: traefik-tls
由于用的是自签名证书,所以不受信任
3 ingressroute代理设置
3.1 http
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
name: ingressroute # 修改名称
namespace: default # 修改namespace
spec:
entryPoints:
- web
routes:
- match: Host(`name.domain.com`) # 域名
kind: Rule
services:
- name: nginx # ServiceName
port: 80 # ServicePort
3.2 https
- 阿里dns
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
name: ingressroute-tls # 修改名称
namespace: default # 修改namespace
spec:
entryPoints:
- websecure
routes:
- match: Host(`name.domain.com`) # 域名
kind: Rule
services:
- name: nginx # ServiceName
port: 80 # ServicePort
tls:
certResolver: ali
domains:
- main: "*.domain.com"
- 自签名证书
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
name: ingressroute-tls # 修改名称
namespace: default # 修改namespace
spec:
entryPoints:
- websecure
routes:
- match: Host(`name.domain.com`) # 域名
kind: Rule
services:
- name: nginx # ServiceName
port: 80 # ServicePort
tls:
secretName: traefik-tls #创建方式见 2.6.2
4 中间件的使用
4.1 如果只希望用户通过 https 来访问应用
- 创建中间件
apiVersion: traefik.containo.us/v1alpha1
kind: Middleware
metadata:
name: redirect-https
spec:
redirectScheme:
scheme: https
- 在ingressroute中使用即可
---
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
name: ingressroutetls-http
spec:
entryPoints:
- web #这里指的是http,websecure指的是https
routes:
- match: Host(`myapp.domain.com`) && PathPrefix(`/tls`)
kind: Rule
services:
- name: myapp
port: 80
middlewares:
- name: redirect-https