Linkerd旨在使应用程序内部服务间的通信安全,快速和可靠。但是,这些目标同样适用于网络的接入层(应用程序对外的服务)。在这篇文章中,我们将展示Linkerd的一个新特性,Linkerd可以充当Kubernetes入口控制器,并展示Linkerd如何处理入站流量的能力。
这是关于Linkerd,Kubernetes和服务网格的一系列文章中的一篇文章。本系列的其他部分包括:
在 本系列的 前一篇文章中,我们探讨了如何通过将Linkerd部署为Kubernetes DaemonSet方式运行,并通过相应的Service VIP来接收外部请求。在这篇文章中,我们将通过利用Linkerd 0.9.1中引入的功能把Linkerd直接作为Kubernetes入口控制器来简化这个部署设置 ,这个针对小型网站部署特别方便快捷,因为不需要部署中间件。
这种部署方法可以使Linkerd与Kubernetes API紧密集成并且简单有效。然而,对于更复杂的需求,如按需TLS证书生成,SNI(Server Name Indication,即服务名称指示)或基于cookie值的路由(例如本系列第五部分讨论的员工采用的dogfooding方法 ),我们需要将Linkerd与网络接入层中间件应用程序结合使用,例如Nginx、Apache等。
那么我们先来思考下什么是Kubernetes入口控制器?入口控制器其本质上是一个网络接入层路由器,它接受来自外部的请求并将其转发到Kubernetes群集中的服务。入口控制器根据在Kubernetes的入口资源中定义的HTTP主机和路由规则来工作。
使用linkerd-例子中的Kubernetes配置,我们可以使Linkerd作为专用入口控制器。配置遵循与我们之前在k8s守护进程上的文章相同的模式 :它部署l5d-config
ConfigMap, l5d
DaemonSet和l5d
Service。
首先,我们来部署Linkerd。当然,您可以将其部署到默认名称空间中,但是在这里我们已经将Linkerd放在了自己的名称空间中,以便更好地分离问题:
$ kubectl create ns l5d-system # 创建名称空间
$ kubectl apply -f https://raw.githubusercontent.com/linkerd/linkerd-examples/master/k8s-daemonset/k8s/linkerd-ingress-controller.yml -n l5d-system
您可以通过运行来验证Linkerd窗格是否已启动:
$ kubectl get po -n l5d-system
NAME READY STATUS RESTARTS AGE
l5d-0w0f4 2/2 Running 0 5s
l5d-3cmfp 2/2 Running 0 5s
l5d-dj1sm 2/2 Running 0 5s
并查看管理控制台(运行该命令前需要确定您的集群支持LoadBalancer(负载均衡),入口LB(即LoadBalancer)可能需要几分钟才可以使用)。
$ L5D_SVC_IP = $(kubectl get svc l5d -n l5d-system -o jsonpath =“{.status.loadBalancer.ingress [0].*}”)
$ open http://$L5D_SVC_IP:9990 # on OS X
我们可以通过命令查看刚刚部署的ConfigMap。下面的配置内容存储在config.yaml文件中。
$ kubectl get cm l5d-config -n l5d-system -o yaml
apiVersion: v1
data:
config.yaml: |-
namers:
- kind: io.l5d.k8s
routers:
- protocol: http
identifier:
kind: io.l5d.ingress
servers:
- port: 80
ip: 0.0.0.0
clearContext: true
dtab: /svc => /#/io.l5d.k8s
usage:
orgId: linkerd-examples-ingress
您可以看到,此配置在端口80上定义了HTTP路由器。然后将得到的命名空间,端口和服务名称传递给Kubernetes编号器进行解析。我们还设置clearContext
为true
是为了拒绝任何不受信任的来源传入Linkerd的请求。
现在部署我们的应用程序,以便我们的入口控制器可以将请求流量分发给应用程序。我们将部署一个由hello和world两个服务组成的简单应用程序。
$ kubectl apply -f https://raw.githubusercontent.com/linkerd/linkerd-examples/master/k8s-daemonset/k8s/hello-world.yml
$ kubectl apply -f https://raw.githubusercontent.com/linkerd/linkerd-examples/master/k8s-daemonset/k8s/world-v2.yml
您可以再次验证Pods已启动并正在运行:
$ kubectl get po
NAME READY STATUS RESTARTS AGE
hello-0v0vx 1/1 Running 0 5s
hello-84wfp 1/1 Running 0 5s
hello-mrcfr 1/1 Running 0 5s
world-v1-105tl 1/1 Running 0 5s
world-v1-1t6jc 1/1 Running 0 5s
world-v1-htwsw 1/1 Running 0 5s
world-v2-5tl10 1/1 Running 0 5s
world-v2-6jc1t 1/1 Running 0 5s
world-v2-wswht 1/1 Running 0 5s
此时,如果您尝试发送入口请求,则会看到如下所示的内容:
$ curl $ L5D_SVC_IP
Unknown destination: Request("GET /", from /184.23.234.210:58081) / no ingress rule matches
为了使我们的Linkerd入口控制器正常工作,我们需要创建一个使用Linkerd作为接入层路由的入口资源。
$ kubectl apply -f https://raw.githubusercontent.com/linkerd/linkerd-examples/master/k8s-daemonset/k8s/hello-world-ingress.yml
验证资源是否创建成功:
$ kubectl get ingress
NAME HOSTS ADDRESS PORTS AGE
hello-world world.v2 80 7s
这样“你好,世界”的入口资源就引用了我们的后端程序(所以我们仅用了 world-v1
和 world-v2
这个demo):
apiVersion : extensions / v1beta1
kind: Ingress
metadata:
name: hello-world
annotations:
kubernetes.io/ingress.class: "linkerd"
spec:
backend:
serviceName: world-v1
servicePort: http
rules:
- host: world.v2
http:
paths:
- backend:
serviceName: world-v2
servicePort: http
资源
world.v2
主机header的所有请求都将被路由到world-v2
服务。kubernetes.io/ingress.class
注释设置为“linkerd”。请注意,只有在群集中运行多个入口控制器时,才需要此注释。GCE(Google Compute Engine)默认运行一个; 您可以按照这些说明选择禁用它 。至此!您可以通过分配给l5d服务负载均衡器的IP来验证这些规则。
$ curl $ L5D_SVC_IP
world (10.0.4.7)!
$ curl -H "Host: world.v2" $L5D_SVC_IP
earth (10.0.1.5)!
虽然这个例子是以全新的实例开始的,但是将入口标识符路由器添加到预先存在的链接设置也很简单。此外,尽管我们在此使用了一个DaemonSet(与Kubernetes系列的其余服务网格保持一致),但对使用Kubernetes 部署此demo也同样适用。使用Kubernetes部署留给读者一个练习。
Linkerd已经支持群集内客户端和服务器的TLS。本系列的第三部分详细介绍了如何设置TLS 。在该入口控制器配置,Linkerd需要的TLS证书是由名为ingress-certs
的Kubernetes secret定义 ,并遵循 描述为入口的用户指南的一部分的格式。请注意,不要将TLS部分指定为入口资源的一部分:Linkerd不支持入口资源配置中有关TLS的设置。所有的TLS配置都需要在l5d-config
ConfigMap中配置的。
Linkerd配置保持不变,更改服务器端口443
并添加TLS文件路径:
...
servers:
- port: 443
ip: 0.0.0.0
clearContext: true
tls:
certPath: /io.buoyant/linkerd/certs/tls.crt
keyPath: /io.buoyant/linkerd/certs/tls.key
...
l5d DaemonSet现在以ingress-certs
名字安装一个秘密卷:
spec:
volumes:
- name: certificates
secret:
secretName: ingress-certs
...
containers:
- name: l5d
...
ports:
- name: tls
containerPort: 443
hostPort: 443
...
volumeMounts:
- name: "certificates"
mountPath: "/io.buoyant/linkerd/certs"
readOnly: true
...
并更改的服务配置开放端口 443
。
创建Secret证书,删除原本的DaemonSet和ConfigMap,并重新载入入口控制器配置:
$ kubectl apply -f https://raw.githubusercontent.com/linkerd/linkerd-examples/master/k8s-daemonset/k8s/ingress-certificates.yml -n l5d-system
$ kubectl delete ds/l5d configmap/l5d-config -n l5d-system
$ kubectl apply -f https://raw.githubusercontent.com/linkerd/linkerd-examples/master/k8s-daemonset/k8s/linkerd-tls-ingress-controller.yml -n l5d-system
你现在应该可以做一个加密的请求(HTTPS):
# Example requires this development cert: https://raw.githubusercontent.com/linkerd/linkerd-examples/master/k8s-daemonset/certificates/cert.pem
# The cert expects "hello.world" host, so we add an /etc/hosts entry, eg:
# 104.198.196.230 hello.world
# where "104.198.196.230" is the ip stored in $L5D_SVC_IP
$ curl --cacert cert.pem -H "Host: world.v2" https://hello.world
$ earth (10.0.1.5)!
结论
Linkerd作为接入层路由器提供了许多好处。除了本文中介绍的动态路由和TLS终结外,它还 集中了连接,动态负载均衡,断路器和支持分布式跟踪。使用本文中引用的Linkerd入口控制器和Kubernetes配置,您可以使用易于使用的Kubernetes原生方法访问所有这些功能。最重要的是,这种方法可与服务网格的其余部分无缝协作,从而在几乎任何云架构中实现可操作性,可见性和高可用性。
该ingress identifier是新功能,所以我们很想得到你从入口控制器想要什么功能。你可以在 Linkerd社区松弛或在Linkerd话语找到我们。