Traefik 是一个开源的可以使服务发布变得轻松有趣的边缘路由器。它负责接收你系统的请求,然后使用合适的组件来对这些请求进行处理。

除了众多的功能之外,Traefik 的与众不同之处还在于它会自动发现适合你服务的配置。当 Traefik 在检查你的服务时,会找到服务的相关信息并找到合适的服务来满足对应的请求。

Traefik 兼容所有主流的集群技术,比如 Kubernetes,Docker,Docker Swarm,AWS,Mesos,Marathon,等等;并且可以同时处理多种方式。(甚至可以用于在裸机上运行的比较旧的软件。)

使用 Traefik,不需要维护或者同步一个独立的配置文件:因为一切都会自动配置,实时操作的(无需重新启动,不会中断连接)。使用 Traefik,你可以花更多的时间在系统的开发和新功能上面,而不是在配置和维护工作状态上面花费大量时间。

核心概念

Traefik 是一个边缘路由器,是你整个平台的大门,拦截并路由每个传入的请求:它知道所有的逻辑和规则,这些规则确定哪些服务处理哪些请求;传统的反向代理需要一个配置文件,其中包含路由到你服务的所有可能路由,而 Traefik 会实时检测服务并自动更新路由规则,可以自动服务发现。

首先,当启动 Traefik 时,需要定义 entrypoints(入口点),然后,根据连接到这些 entrypoints 的路由来分析传入的请求,来查看他们是否与一组规则相匹配,如果匹配,则路由可能会将请求通过一系列中间件转换过后再转发到你的服务上去。在了解 Traefik 之前有几个核心概念我们必须要了解:

  • Providers 用来自动发现平台上的服务,可以是编排工具、容器引擎或者 key-value 存储等,比如 Docker、Kubernetes、File

  • Entrypoints 监听传入的流量(端口等…),是网络入口点,它们定义了接收请求的端口(HTTP 或者 TCP)。

  • Routers 分析请求(host, path, headers, SSL, …),负责将传入请求连接到可以处理这些请求的服务上去。

  • Services 将请求转发给你的应用(load balancing, …),负责配置如何获取最终将处理传入请求的实际服务。

  • Middlewares 中间件,用来修改请求或者根据请求来做出一些判断(authentication, rate limiting, headers, ...),中间件被附件到路由上,是一种在请求发送到你的服务之前(或者在服务的响应发送到客户端之前)调整请求的一种方法。

安装

由于 Traefik 2.X 版本和之前的 1.X 版本不兼容,我们这里选择功能更加强大的 2.X 版本来和大家进行讲解,我们这里使用的镜像是 traefik:2.1.1

在 Traefik 中的配置可以使用两种不同的方式:

  • 动态配置:完全动态的路由配置

  • 静态配置:启动配置

静态配置中的元素(这些元素不会经常更改)连接到 providers 并定义 Treafik 将要监听的 entrypoints。

在 Traefik 中有三种方式定义静态配置:在配置文件中、在命令行参数中、通过环境变量传递

动态配置包含定义系统如何处理请求的所有配置内容,这些配置是可以改变的,而且是无缝热更新的,没有任何请求中断或连接损耗。

安装 Traefik 到 Kubernetes 集群中的资源清单文件我这里提前准备好了,直接执行下面的安装命令即可:

$ kubectl apply -f https://www.qikqiak.com/k8strain/network/manifests/traefik/crd.yaml
$ kubectl apply -f https://www.qikqiak.com/k8strain/network/manifests/traefik/rbac.yaml
$ kubectl apply -f https://www.qikqiak.com/k8strain/network/manifests/traefik/deployment.yaml
$ kubectl apply -f https://www.qikqiak.com/k8strain/network/manifests/traefik/dashboard.yaml

其中 deployment.yaml 我这里是固定到 master 节点上的,如果你需要修改可以下载下来做相应的修改即可。我们这里是通过命令行参数来做的静态配置:

args:
- --entryPoints.web.address=:80
- --entryPoints.websecure.address=:443
- --api=true
- --api.dashboard=true
- --ping=true
- --providers.kubernetesingress
- --providers.kubernetescrd
- --log.level=INFO
- --accesslog

其中前两项配置是来定义 webwebsecure 这两个入口点的, --api=true 开启,=,就会创建一个名为 api@internal 的特殊 service,在 dashboard 中可以直接使用这个 service 来访问,然后其他比较重要的就是开启 kubernetesingresskubernetescrd 这两个 provider。

dashboard.yaml 中定义的是访问 dashboard 的资源清单文件,可以根据自己的需求修改。

$ kubectl get pods -n kube-system
NAME                                  READY   STATUS    RESTARTS   AGE
traefik-867bd6b9c-lbrlx               1/1     Running   0          6m17s
......
$ kubectl get ingressroute
NAME                 AGE
traefik-dashboard    30m

部署完成后我们可以通过在本地 /etc/hosts 中添加上域名 traefik.domain.com 的映射即可访问 Traefik 的 Dashboard 页面了:

ACME

Traefik 通过扩展 CRD 的方式来扩展 Ingress 的功能,除了默认的用 Secret 的方式可以支持应用的 HTTPS 之外,还支持自动生成 HTTPS 证书。

比如现在我们有一个如下所示的 whoami 应用:

apiVersion: v1
kind: Service
metadata:name: whoami
spec:ports:- protocol: TCPname: webport: 80selector:app: whoami
---
kind: Deployment
apiVersion: apps/v1
metadata:name: whoamilabels:app: whoami
spec:replicas: 2selector:matchLabels:app: whoamitemplate:metadata:labels:app: whoamispec:containers:- name: whoamiimage: containous/whoamiports:- name: webcontainerPort: 80

然后定义一个 IngressRoute 对象:

apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:name: simpleingressroute
spec:entryPoints:- webroutes:- match: Host(`who.qikqiak.com`) && PathPrefix(`/notls`)kind: Ruleservices:- name: whoamiport: 80

通过 entryPoints 指定了我们这个应用的入口点是 web,也就是通过 80 端口访问,然后访问的规则就是要匹配 who.qikqiak.com 这个域名,并且具有 /notls 的路径前缀的请求才会被 whoami 这个 Service 所匹配。我们可以直接创建上面的几个资源对象,然后对域名做对应的解析后,就可以访问应用了:

IngressRoute 对象中我们定义了一些匹配规则,这些规则在 Traefik 中有如下定义方式:

如果我们需要用 HTTPS 来访问我们这个应用的话,就需要监听 websecure 这个入口点,也就是通过 443 端口来访问,同样用 HTTPS 访问应用必然就需要证书,这里我们用 openssl 来创建一个自签名的证书:

$ openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout tls.key -out tls.crt -subj "/CN=who.qikqiak.com"

然后通过 Secret 对象来引用证书文件:

# 要注意证书文件名称必须是 tls.crt 和 tls.key
$ kubectl create secret tls who-tls --cert=tls.crt --key=tls.key
secret/who-tls created

这个时候我们就可以创建一个 HTTPS 访问应用的 IngressRoute 对象了:

apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:name: ingressroutetls
spec:entryPoints:- websecureroutes:- match: Host(`who.qikqiak.com`) && PathPrefix(`/tls`)kind: Ruleservices:- name: whoamiport: 80tls:secretName: who-tls

创建完成后就可以通过 HTTPS 来访问应用了,由于我们是自签名的证书,所以证书是不受信任的:

除了手动提供证书的方式之外 Traefik 还支持使用 Let’sEncrypt 自动生成证书,要使用 Let’sEncrypt 来进行自动化 HTTPS,就需要首先开启 ACME,开启 ACME 需要通过静态配置的方式,也就是说可以通过环境变量、启动参数等方式来提供,我们这里还是直接使用启动参数的形式来开启,在 Traefik 的部署文件中添加如下命令行参数:

args:
......
# 使用 dns 验证方式
- --certificatesResolvers.ali.acme.dnsChallenge.provider=alidns
# 邮箱配置
- --certificatesResolvers.ali.acme.email=ych_1024@163.com
# 保存 ACME 证书的位置
- --certificatesResolvers.ali.acme.storage=/etc/acme/acme.json

ACME 有多种校验方式 tlsChallengehttpChallengednsChallenge 三种验证方式,之前更常用的是 http 这种验证方式,关于这几种验证方式的使用可以查看文档:https://www.qikqiak.com/traefik-book/https/acme/ 了解他们之间的区别。要使用 tls 校验方式的话需要保证 Traefik 的 443 端口是可达的,dns 校验方式可以生成通配符的证书,只需要配置上 DNS 解析服务商的 API 访问密钥即可校验。我们这里用 DNS 校验的方式来为大家说明如何配置 ACME。

上面我们通过设置 --certificatesResolvers.ali.acme.dnsChallenge.provider=alidns 参数来指定指定阿里云的 DNS 校验,要使用阿里云的 DNS 校验我们还需要配置3个环境变量:ALICLOUD_ACCESS_KEYALICLOUD_SECRET_KEYALICLOUD_REGION_ID,分别对应我们平时开发阿里云应用的时候的密钥,可以登录阿里云后台获取,由于这是比较私密的信息,所以我们用 Secret 对象来创建:

$ kubectl create secret generic traefik-alidns-secret --from-literal=ALICLOUD_ACCESS_KEY=<aliyun ak> --from-literal=ALICLOUD_SECRET_KEY=<aliyun sk>--from-literal=ALICLOUD_REGION_ID=cn-beijing -n kube-system

创建完成后将这个 Secret 通过环境变量配置到 Traefik 的应用中。还有一个值得注意的是验证通过的证书我们这里存到 /etc/acme/acme.json 文件中,我们一定要将这个文件持久化,否则每次 Traefik 重建后就需要重新认证,而 Let’sEncrypt 本身校验次数是有限制的。最后我们这里完整的 Traefik 的配置资源清单如下所示:

apiVersion: apps/v1
kind: Deployment
metadata:name: traefiknamespace: kube-systemlabels:app: traefik
spec:selector:matchLabels:app: traefiktemplate:metadata:labels:app: traefikspec:serviceAccountName: traefikterminationGracePeriodSeconds: 60tolerations:- operator: "Exists"nodeSelector:kubernetes.io/hostname: ydzs-mastervolumes:- name: acmehostPath:path: /data/k8s/traefik/acmecontainers:- image: traefik:2.1.1name: traefikports:- name: webcontainerPort: 80hostPort: 80- name: websecurecontainerPort: 443hostPort: 443args:- --entryPoints.web.address=:80- --entryPoints.websecure.address=:443- --api=true- --api.dashboard=true- --ping=true- --providers.kubernetesingress- --providers.kubernetescrd- --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/directoryenvFrom:- secretRef:name: traefik-alidns-secret# ALICLOUD_ACCESS_KEY# ALICLOUD_SECRET_KEY# ALICLOUD_REGION_IDvolumeMounts:- name: acmemountPath: /etc/acmeresources:requests:cpu: "50m"memory: "50Mi"limits:cpu: "200m"memory: "100Mi"securityContext:allowPrivilegeEscalation: truecapabilities:drop:- ALLadd:- NET_BIND_SERVICEreadinessProbe:httpGet:path: /pingport: 8080failureThreshold: 1initialDelaySeconds: 10periodSeconds: 10successThreshold: 1timeoutSeconds: 2livenessProbe:httpGet:path: /pingport: 8080failureThreshold: 3initialDelaySeconds: 10periodSeconds: 10successThreshold: 1timeoutSeconds: 2

直接更新 Traefik 应用即可。更新完成后现在我们来修改上面我们的 whoami 应用:

apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:name: ingressroutetls
spec:entryPoints:- websecureroutes:- match: Host(`who.qikqiak.com`) && PathPrefix(`/tls`)kind: Ruleservices:- name: whoamiport: 80tls:certResolver: alidomains:- main: "*.qikqiak.com"

其他的都不变,只需要将 tls 部分改成我们定义的 ali 这个证书解析器,如果我们想要生成一个通配符的域名证书的话可以定义 domains 参数来指定,然后更新 IngressRoute 对象,这个时候我们再去用 HTTPS 访问我们的应用(当然需要将域名在阿里云 DNS 上做解析):

我们可以看到访问应用已经是受浏览器信任的证书了,查看证书我们还可以发现该证书是一个通配符的证书。

中间件

中间件是 Traefik2.0 中一个非常有特色的功能,我们可以根据自己的各种需求去选择不同的中间件来满足服务,Traefik 官方已经内置了许多不同功能的中间件,其中一些可以修改请求,头信息,一些负责重定向,一些添加身份验证等等,而且中间件还可以通过链式组合的方式来适用各种情况。

同样比如上面我们定义的 whoami 这个应用,我们可以通过 https://who.qikqiak.com/tls 来访问到应用,但是如果我们用 http 来访问的话呢就不行了,就会404了,因为我们根本就没有简单80端口这个入口点,所以要想通过 http 来访问应用的话自然我们需要监听下 web 这个入口点:

apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:name: ingressroutetls-http
spec:entryPoints:- webroutes:- match: Host(`who.qikqiak.com`) && PathPrefix(`/tls`)kind: Ruleservices:- name: whoamiport: 80

注意这里我们创建的 IngressRoute 的 entryPoints 是 web,然后创建这个对象,这个时候我们就可以通过 http 访问到这个应用了。

但是我们如果只希望用户通过 https 来访问应用的话呢?按照以前的知识,我们是不是可以让 http 强制跳转到 https 服务去,对的,在 Traefik 中也是可以配置强制跳转的,只是这个功能现在是通过中间件来提供的了。如下所示,我们使用 redirectScheme 中间件来创建提供强制跳转服务:

apiVersion: traefik.containo.us/v1alpha1
kind: Middleware
metadata:name: redirect-https
spec:redirectScheme:scheme: https

然后将这个中间件附加到 http 的服务上面去,因为 https 的不需要跳转:

---
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:name: ingressroutetls-http
spec:entryPoints:- webroutes:- match: Host(`who.qikqiak.com`) && PathPrefix(`/tls`)kind: Ruleservices:- name: whoamiport: 80middlewares: - name: redirect-https

这个时候我们再去访问 http 服务可以发现就会自动跳转到 https 去了。关于更多中间件的用法可以查看文档 Traefik Docs。

灰度发布

Traefik2.0 的一个更强大的功能就是灰度发布,灰度发布我们有时候也会称为金丝雀发布(Canary),主要就是让一部分测试的服务也参与到线上去,经过测试观察看是否符号上线要求。

比如现在我们有两个名为 appv1appv2 的服务,我们希望通过 Traefik 来控制我们的流量,将 3⁄4 的流量路由到 appv1,1/4 的流量路由到 appv2 去,这个时候就可以利用 Traefik2.0 中提供的带权重的轮询(WRR)来实现该功能,首先在 Kubernetes 集群中部署上面的两个服务。为了对比结果我们这里提供的两个服务一个是 whoami,一个是 nginx,方便测试。

appv1 服务的资源清单如下所示:(appv1.yaml)

apiVersion: apps/v1
kind: Deployment
metadata:name: appv1
spec:selector:matchLabels:app: appv1template:metadata:labels:use: testapp: appv1spec:containers:- name: whoamiimage: containous/whoamiports:- containerPort: 80name: portv1
---
apiVersion: v1
kind: Service
metadata:name: appv1
spec:selector:app: appv1ports:- name: httpport: 80targetPort: portv1

appv2 服务的资源清单如下所示:(appv2.yaml)

apiVersion: apps/v1
kind: Deployment
metadata:name: appv2
spec:selector:matchLabels:app: appv2template:metadata:labels:use: testapp: appv2spec:containers:- name: nginximage: nginxports:- containerPort: 80name: portv2
---
apiVersion: v1
kind: Service
metadata:name: appv2
spec:selector:app: appv2ports:- name: httpport: 80targetPort: portv2

直接创建上面两个服务:

$ kubectl apply -f appv1.yaml
$ kubectl apply -f appv2.yaml
# 通过下面的命令可以查看服务是否运行成功
$ kubectl get pods -l use=test
NAME                     READY   STATUS    RESTARTS   AGE
appv1-58f856c665-shm9j   1/1     Running   0          12s
appv2-ff5db55cf-qjtrf    1/1     Running   0          12s

在 Traefik2.1 中新增了一个 TraefikService 的 CRD 资源,我们可以直接利用这个对象来配置 WRR,之前的版本需要通过 File Provider,比较麻烦,新建一个描述 WRR 的资源清单:(wrr.yaml)

apiVersion: traefik.containo.us/v1alpha1
kind: TraefikService
metadata:name: app-wrr
spec:weighted:services:- name: appv1weight: 3  # 定义权重port: 80kind: Service  # 可选,默认就是 Service- name: appv2weight: 1port: 80

然后为我们的灰度发布的服务创建一个 IngressRoute 资源对象:(ingressroute.yaml)

apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:name: wrringressroutenamespace: default
spec:entryPoints:- webroutes:- match: Host(`wrr.qikqiak.com`)kind: Ruleservices:- name: app-wrrkind: TraefikService

不过需要注意的是现在我们配置的 Service 不再是直接的 Kubernetes 对象了,而是上面我们定义的 TraefikService 对象,直接创建上面的两个资源对象,这个时候我们对域名 wrr.qikqiak.com 做上解析,去浏览器中连续访问 4 次,我们可以观察到 appv1 这应用会收到 3 次请求,而 appv2 这个应用只收到 1 次请求,符合上面我们的 3:1 的权重配置。

流量复制

除了灰度发布之外,Traefik 2.0 还引入了流量镜像服务,是一种可以将流入流量复制并同时将其发送给其他服务的方法,镜像服务可以获得给定百分比的请求同时也会忽略这部分请求的响应。

同样的在 2.0 中只能通过 FileProvider 进行配置,在 2.1 版本中我们已经可以通过 TraefikService 资源对象来进行配置了,现在我们部署两个 whoami 的服务,资源清单文件如下所示:

apiVersion: v1
kind: Service
metadata:name: v1
spec:ports:- protocol: TCPname: webport: 80selector:app: v1
---
kind: Deployment
apiVersion: apps/v1
metadata:name: v1labels:app: v1
spec:selector:matchLabels:app: v1template:metadata:labels:app: v1spec:containers:- name: v1image: nginxports:- name: webcontainerPort: 80
---
apiVersion: v1
kind: Service
metadata:name: v2
spec:ports:- protocol: TCPname: webport: 80selector:app: v2
---
kind: Deployment
apiVersion: apps/v1
metadata:name: v2labels:app: v2
spec:selector:matchLabels:app: v2template:metadata:labels:app: v2spec:containers:- name: v2image: nginxports:- name: webcontainerPort: 80

直接创建上面的资源对象:

$ kubectl get pods
NAME                                      READY   STATUS    RESTARTS   AGE
v1-77cfb86999-wfbl2                       1/1     Running   0          94s
v2-6f45d498b7-g6qjt                       1/1     Running   0          91s
$ kubectl get svc
NAME            TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)     AGE
v1              ClusterIP   10.96.218.173   <none>        80/TCP      99s
v2              ClusterIP   10.99.98.48     <none>        80/TCP      96s

现在我们创建一个 IngressRoute 对象,将服务 v1 的流量复制 50% 到服务 v2,如下资源对象所示:(mirror-ingress-route.yaml)

apiVersion: traefik.containo.us/v1alpha1
kind: TraefikService
metadata:name: app-mirror
spec:mirroring:name: v1 # 发送 100% 的请求到 K8S 的 Service "v1"port: 80mirrors:- name: v2 # 然后复制 50% 的请求到 v2percent: 50port: 80
---
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:name: mirror-ingress-routenamespace: default
spec:entryPoints:- webroutes:   - match: Host(`mirror.qikqiak.com`)kind: Ruleservices:- name: app-mirrorkind: TraefikService # 使用声明的 TraefikService 服务,而不是 K8S 的 Service

然后直接创建这个资源对象即可:

$ kubectl apply -f mirror-ingress-route.yaml
ingressroute.traefik.containo.us/mirror-ingress-route created
traefikservice.traefik.containo.us/mirroring-example created

这个时候我们在浏览器中去连续访问4次 mirror.qikqiak.com 可以发现有一半的请求也出现在了 v2 这个服务中:

TCP

另外 Traefik2.0 已经支持了 TCP 服务的,下面我们以 mongo 为例来了解下 Traefik 是如何支持 TCP 服务的。

简单 TCP 服务

首先部署一个普通的 mongo 服务,资源清单文件如下所示:(mongo.yaml)

apiVersion: apps/v1
kind: Deployment
metadata:name: mongo-traefiklabels:app: mongo-traefik
spec:selector:matchLabels:app: mongo-traefiktemplate:metadata:labels:app: mongo-traefikspec:containers:- name: mongoimage: mongo:4.0ports:- containerPort: 27017
---
apiVersion: v1
kind: Service
metadata:name: mongo-traefik
spec:selector:app: mongo-traefikports:- port: 27017

直接创建 mongo 应用:

$ kubectl apply -f mongo.yaml
deployment.apps/mongo-traefik created
service/mongo-traefik created

创建成功后就可以来为 mongo 服务配置一个路由了。由于 Traefik 中使用 TCP 路由配置需要 SNI,而 SNI 又是依赖 TLS 的,所以我们需要配置证书才行,如果没有证书的话,我们可以使用通配符 * 进行配置,我们这里创建一个 IngressRouteTCP 类型的 CRD 对象(前面我们就已经安装了对应的 CRD 资源):(mongo-ingressroute-tcp.yaml)

apiVersion: traefik.containo.us/v1alpha1
kind: IngressRouteTCP
metadata:name: mongo-traefik-tcp
spec:entryPoints:- mongoroutes:- match: HostSNI(`*`)services:- name: mongo-traefikport: 27107

要注意的是这里的 entryPoints 部分,是根据我们启动的 Traefik 的静态配置中的 entryPoints 来决定的,我们当然可以使用前面我们定义的 80 和 443 这两个入口点,但是也可以可以自己添加一个用于 mongo 服务的专门入口点:

......
- image: traefik:2.1.1name: traefikports:- name: webcontainerPort: 80hostPort: 80- name: websecurecontainerPort: 443hostPort: 443- name: mongohostPort: 27017containerPort: 27017args:- --entryPoints.web.address=:80- --entryPoints.websecure.address=:443- --entryPoints.mongo.address=:27017......

这里给入口点添加 hostPort 是为了能够通过节点的端口访问到服务,关于 entryPoints 入口点的更多信息,可以查看文档 entrypoints 了解更多信息。

然后更新 Traefik 后我们就可以直接创建上面的资源对象:

$ mongo-ingressroute-tcp.yaml
ingressroutetcp.traefik.containo.us/mongo-traefik-tcp created

创建完成后,同样我们可以去 Traefik 的 Dashboard 页面上查看是否生效:

然后我们配置一个域名 mongo.local 解析到 Traefik 所在的节点,然后通过 27017 端口来连接 mongo 服务:

$ mongo --host mongo.local --port 27017
mongo(75243,0x1075295c0) malloc: *** malloc_zone_unregister() failed for 0x7fffa56f4000
MongoDB shell version: 2.6.1
connecting to: mongo.local:27017/test
> show dbs
admin   0.000GB
config  0.000GB
local   0.000GB

到这里我们就完成了将 mongo(TCP)服务暴露给外部用户了。

带 TLS 证书的 TCP

上面我们部署的 mongo 是一个普通的服务,然后用 Traefik 代理的,但是有时候为了安全 mongo 服务本身还会使用 TLS 证书的形式提供服务,下面是用来生成 mongo tls 证书的脚本文件:(generate-certificates.sh)

#!/bin/bash
#
# From https://medium.com/@rajanmaharjan/secure-your-mongodb-connections-ssl-tls-92e2addb3c89
set -eu -o pipefail
DOMAINS="${1}"
CERTS_DIR="${2}"
[ -d "${CERTS_DIR}" ]
CURRENT_DIR="$(cd "$(dirname "${0}")" && pwd -P)"
GENERATION_DIRNAME="$(echo "${DOMAINS}" | cut -d, -f1)"
rm -rf "${CERTS_DIR}/${GENERATION_DIRNAME:?}" "${CERTS_DIR}/certs"
echo "== Checking Requirements..."
command -v go >/dev/null 2>&1 || echo "Golang is required"
command -v minica >/dev/null 2>&1 || go get github.com/jsha/minica >/dev/null
echo "== Generating Certificates for the following domains: ${DOMAINS}..."
cd "${CERTS_DIR}"
minica --ca-cert "${CURRENT_DIR}/minica.pem" --ca-key="${CURRENT_DIR}/minica-key.pem" --domains="${DOMAINS}"
mv "${GENERATION_DIRNAME}" "certs"
cat certs/key.pem certs/cert.pem > certs/mongo.pem
echo "== Certificates Generated in the directory ${CERTS_DIR}/certs"

将上面证书放置到 certs 目录下面,然后我们新建一个 02-tls-mongo 的目录,在该目录下面执行如下命令来生成证书:

$ bash ../certs/generate-certificates.sh mongo.local .
== Checking Requirements...
== Generating Certificates for the following domains: mongo.local...

最后的目录如下所示,在 02-tls-mongo 目录下面会生成包含证书的 certs 目录:

$ tree .
.
├── 01-mongo
│   ├── mongo-ingressroute-tcp.yaml
│   └── mongo.yaml
├── 02-tls-mongo
│   └── certs
│       ├── cert.pem
│       ├── key.pem
│       └── mongo.pem
└── certs├── generate-certificates.sh├── minica-key.pem└── minica.pem

02-tls-mongo/certs 目录下面执行如下命令通过 Secret 来包含证书内容:

$ kubectl create secret tls traefik-mongo-certs --cert=cert.pem --key=key.pem
secret/traefik-mongo-certs created

然后重新更新 IngressRouteTCP 对象,增加 TLS 配置:

apiVersion: traefik.containo.us/v1alpha1
kind: IngressRouteTCP
metadata:name: mongo-traefik-tcp
spec:entryPoints:- mongoroutes:- match: HostSNI(`mongo.local`)services:- name: mongo-traefikport: 27017tls: secretName: traefik-mongo-certs

同样更新后,现在我们直接去访问应用就会被 hang 住,因为我们没有提供证书:

$ mongo --host mongo.local --port 27017
MongoDB shell version: 2.6.1
connecting to: mongo1.local:27017/test

这个时候我们可以带上证书来进行连接:

$ mongo --host mongo.local --port 27017 --ssl --sslCAFile=../certs/minica.pem --sslPEMKeyFile=./certs/mongo.pem
MongoDB shell version v4.0.3
connecting to: mongodb://mongo.local:27017/
Implicit session: session { "id" : UUID("e7409ef6-8ebe-4c5a-9642-42059bdb477b") }
MongoDB server version: 4.0.14
......
> show dbs;
admin   0.000GB
config  0.000GB
local   0.000GB

可以看到现在就可以连接成功了,这样就完成了一个使用 TLS 证书代理 TCP 服务的功能,这个时候如果我们使用其他的域名去进行连接就会报错了,因为现在我们指定的是特定的 HostSNI:

$ mongo --host mongo.k8s.local --port 27017 --ssl --sslCAFile=../certs/minica.pem --sslPEMKeyFile=./certs/mongo.pem
MongoDB shell version v4.0.3
connecting to: mongodb://mongo.k8s.local:27017/
2019-12-29T15:03:52.424+0800 E NETWORK  [js] SSL peer certificate validation failed: Certificate trust failure: CSSMERR_TP_NOT_TRUSTED; connection rejected
2019-12-29T15:03:52.429+0800 E QUERY    [js] Error: couldn't connect to server mongo.qikqiak.com:27017, connection attempt failed: SSLHandshakeFailed: SSL peer certificate validation failed: Certificate trust failure: CSSMERR_TP_NOT_TRUSTED; connection rejected :
connect@src/mongo/shell/mongo.js:257:13
@(connect):1:6
exception: connect failed

当然我们也可以使用 ACME 来为我们提供一个合法的证书,这样在连接的使用就不需要指定证书了,如下所示:

apiVersion: traefik.containo.us/v1alpha1
kind: IngressRouteTCP
metadata:name: mongo-traefik-tcp
spec:entryPoints:- mongoroutes:- match: HostSNI(`mongo.qikqiak.com`)services:- name: mongo-traefikport: 27017tls:certResolver: alidomains:- main: "*.qikqiak.com"

这样当我们连接的时候就只需要如下的命令即可:

$ mongo --host mongo.qikqiak.com --port 27017 --ssl

本文转载自:「k8s技术圈」,原文:https://url.cn/5TW4VQ7,版权归原作者所有。欢迎投稿,投稿邮箱: editor@hi-linux.com 。

你可能还喜欢

点击下方图片即可阅读

学会这三招,Docker 容器权限管理乐无忧!

可能是我见过最好的在 Kubernetes 中使用 Traefik 2.1 的中文文档 (强烈建议收藏)相关推荐

  1. python对象编程例子-这是我见过最详细的Python面向对象编程!建议收藏!

    原标题:这是我见过最详细的Python面向对象编程!建议收藏! 面向对象编程和函数式编程(面向过程编程)都是程序设计的方法,不过稍有区别. 面向过程编程: 1. 导入各种外部库 2. 设计各种全局变量 ...

  2. Spring Cloud Kubernetes 中文文档

    本参考指南介绍了如何使用Spring Cloud Kubernetes. 1.为什么需要Spring Cloud Kubernetes? Spring Cloud Kubernetes提供了使用Kub ...

  3. JAVA获取股票实时KDJ,炒股10年,这是我见过最简单透彻的KDJ分析【建议收藏】

    原标题:炒股10年,这是我见过最简单透彻的KDJ分析[建议收藏] KDJ定义: KDJ指标的中文名称又叫随机指标,最早起源于期货市场,由乔治·莱恩(George Lane)首创.随机指标KDJ最早是以 ...

  4. Kubernetes 中创建 Pod 时集群中到底发生了些什么?

    想象一下,如果我想将 nginx 部署到 Kubernetes 集群,我可能会在终端中输入类似这样的命令: $ kubectl run --image=nginx --replicas=3 然后回车. ...

  5. kubernetes 中 label的作用_Kubernetes生产环境的16条建议

    Kubernetes是用于构建高度可扩展系统的强大工具.结果,许多公司已经开始或正在计划使用它来协调生产服务.不幸的是,像大多数强大的技术一样,Kubernetes也很复杂.我们整理了以下清单,以帮助 ...

  6. 在 Kubernetes 上部署 Traefik Ingress

    Traefik 介绍 简单的说,Ingress 就是从 Kubernetes 集群外访问集群的入口,将用户的 URL 请求转发到不同的 Service上.Ingress 相当于 Nginx.Apach ...

  7. 京东云Kubernetes集群+Traefik实战

    Traefik支持丰富的annotations配置,可配置众多出色的特性,例如:自动熔断.负载均衡策略.黑名单.白名单.所以Traefik对于微服务来说简直就是一神器. 利用Traefik,并结合京东 ...

  8. Kubernetes 新玩法:在 yaml 中编程

    作者 | 悟鹏 引子 性能测试在日常的开发工作中是常规需求,用来摸底服务的性能. 那么如何做性能测试?要么是通过编码的方式完成,写一堆脚本,用完即弃:要么是基于平台,在平台定义的流程中进行.对于后者, ...

  9. tcpdump 抓二层包_可能是我见过的最简单易懂且实用的 TCPDump 和 Wireshark 抓包及分析教程!( 强烈建议收藏 )...

    公众号关注 「奇妙的 Linux 世界」设为「星标」,每天带你玩转 Linux ! 本文将展示如何使用 tcpdump 抓包,以及如何用 tcpdump 和 wireshark 分析网络流量.文中的例 ...

最新文章

  1. 集线器、路由器与交换机
  2. efcore调用函数_EFCore执行Sql语句的方法:FromSql与ExecuteSqlCommand
  3. 链队列的建立、判空、入队、出队、求长、访头、清空和销毁
  4. 基于NHibernate的UnitOfWork+Repository模式(AutoFac)–Part2
  5. 一键准备Oracle安装
  6. ICLR 2020 | “同步平均教学”框架为无监督学习提供更鲁棒的伪标签
  7. jzoj3319-[BOI2013]雪地踪迹【bfs】
  8. I.MX6 mkuserimg.sh hacking
  9. 独家|一文带你理解机器学习中的“归纳偏好”真正含义!
  10. 基于 HTML5 WebGL 的 3D 智慧隧道漫游巡检
  11. 学习笔记大型《构建高性能web站点》
  12. 01背包问题-一维数组实现原理
  13. 【Speedtest】网络测速工具(支持命令行测试)
  14. MATLAB向量运算
  15. 【vue+elementui】时间选择器:时间格式、设置时间最大日期或最小日期、设置时间选择范围
  16. 银行加息有什么影响(央行加息,对股市和房价有何影响?)
  17. java读取Excel2003和Excel2007内容
  18. 后台推送消息给app_小米加入统一推送联盟!避免多种APP后台运行,国产手机春天来了...
  19. 可用的公开 RTSP/ RTMP 在线视频流资源地址(亲测可行)
  20. 如何在Google表格中使用QUERY函数

热门文章

  1. Js将带声调的拼音转不带声调的拼音
  2. 网络嗅探器的设计(1)
  3. 学科实践活动感悟50字_最新中学生学科实践活动50字
  4. 计算机主板的mtbf,图文 罗洪元:联想电脑MTBF指标不少于6万小时
  5. static类别的局部变量
  6. 一个算法工程师在技术方面的反思!
  7. 20个公开课网址大全,值得收藏、慢慢学习
  8. GMGC数娱节前瞻,好玩好看有逼格
  9. SAP-CDS+Odata+BOPF 创建与使用介绍,fiori一体化测试
  10. 你有张良计,我有过墙梯之策略模式