Linkerd服务网格中的Ingress流量管理与服务限制
Linkerd服务网格中的Ingress流量管理与服务限制
王先森Ingress 流量
出于简单性和可组合性的原因,Linkerd 本身没有提供内置的 Ingress 控制器。Linkerd 旨在与许多现有的 Kubernetes Ingress 解决方案一起使用。
将 Linkerd 和您选择的入口解决方案结合起来需要两件事:
- 配置您的 Ingress 以支持 Linkerd。
- 网格化你的 Ingress 控制器,以便它们安装 Linkerd 代理。
对 Ingress 控制器进行网格化将允许 Linkerd 在流量进入集群时提供 L7 指标和 mTLS 等功能,Linkerd 支持与大部分 Ingress 控制器进行集成,包括:
- Ambassador (aka Emissary)
- Nginx (community version)
- Nginx (F5 NGINX version)
- Traefik
- Traefik 1.x
- Traefik 2.x
- GCE
- Gloo
- Contour
- Kong
- Haproxy
- EnRoute
- ngrok
ingress-nginx
这里只演示如何开启 ingress-nginx 与 Linkerd 进行集成,不会深入使用。为 Pod 添加一个 linkerd.io/inject: enabled
注解,可以直接 kubectl edit
这个 Deployment。
1 | 对ingress-nginx进行注入 |
这样 ingress 控制器也被加入到网格中去了,所以也具有了 Linkerd 网格的相关功能:
- 为 Ingress 控制器提供黄金指标(每秒请求数等)。
- Ingress 控制器 Pod 和网格应用 Pod 之间的流量是加密的(并相互验证)。
- 可以看到 HTTP 流量
- 当应用程序返回错误(如 5xx HTTP 状态代码)时,这将在 Linkerd UI 中看到,不仅是应用程序,还有 nginx ingress 控制器,因为它向客户端返回错误代码。
Traefik
这里以集群中使用的 traefik 为例来说明如何将其与 Linkerd 进行集成使用。
1 | 对 traefik 进行注入 |
这里需要注意如果还是使用ingress-nginx这种注入方式是不行的,需要为 Pod 添加一个 linkerd.io/inject: ingress
注解,可以直接 kubectl edit
这个 Deployment。
在 Linkerd Dashboard 中也可以看到对应的指标数据了。
接下来我们为 Emojivoto
应用添加一个对应的 Ingress 资源对象来对外暴露服务。
vim nginx-emoji.yaml
1 | # vim nginx-emoji.yaml |
vim traefik-emoji.yaml
Traefik 将添加一个
l5d-dst-override
标头来指示 Linkerd 请求的目标服务。您需要包含 Kubernetes 服务 FQDN (web-svc.emojivoto.svc.cluster.local
)和目标端口servicePort
。
1 | # vim traefik-emoji.yaml |
限制对服务的访问
Linkerd policy 资源用于配置和管理服务间通信的安全策略,例如访问控制规则、流量控制以及故障恢复机制。同样我们还是使用 Emojivoto
应用来展示如何限制对 Voting
微服务的访问,使其只能从 Web 服务中调用。
首先为 Voting
服务创建一个 Server
资源,Server
是 Linkerd 的另外一个 CRD 自定义资源,它用于描述工作负载的特定端口。一旦 Server
资源被创建,只有被授权的客户端才能访问它。
创建一个如下所示的资源对象:
1 | # voting-server.yaml |
直接应用上面的资源对象即可:
1 | kubectl apply -f voting-server.yaml |
我们可以看到该 Server
使用了一个 podSelector
属性来选择它所描述的 Voting 服务的 Pod,它还指定了它适用的命名端口 (grpc),最后指定在此端口上提供服务的协议为 gRPC
, 这可确保代理正确处理流量并允许它跳过协议检测。
现在没有客户端被授权访问此服务,正常会看到成功率有所下降, 因为从 Web 服务到 Voting 的请求开始被拒绝,也可以直接查看 Web 服务的 Pod 日志来验证:
1 | kubectl logs -f -n emojivoto web-847cbcb586-rmbqw web-svc |
我们可以使用 linkerd viz authz
命令查看进入 Voting 服务的请求的授权状态:
1 | linkerd viz authz -n emojivoto deploy/voting |
可以看到所有传入的请求当前都处于未经授权状态。
接下来我们需要为客户端来授予访问该 Server 的权限,这里需要使用到另外一个 CRD 对象 ServerAuthorization
,创建该对象来授予 Web 服务访问我们上面创建的 Voting Server 的权限,对应的资源清单文件如下所示:
1 | # voting-server-auth.yaml |
上面对象中通过 spec.server.name
来关联上面的 Server 对象,由于 meshTLS 使用 ServiceAccounts 作为身份基础,因此我们的授权也将基于 ServiceAccounts,所以通过 spec.client.meshTLS.serviceAccounts
来指定允许从哪些服务来访问 Voting 服务。
同样直接应用该资源清单即可:
1 | kubectl apply -f voting-server-auth.yaml |
有了这个对象后,我们现在可以看到所有对 Voting 服务的请求都是由 voting-grpc
这个 ServerAuthorization
授权的。请注意,由于 linkerd viz auth
命令在一个时间窗口内查询,所以可能会看到一些未授权(UNAUTHORIZED)的请求在短时间内显示。
1 | linkerd viz authz -n emojivoto deploy/voting |
我们还可以通过创建一个 gRPC 客户端 Pod 来尝试从中访问 Voting 服务测试来自其他 Pod 的请求是否会被拒绝:
1 | kubectl run grpcurl --rm -it --image=networld/grpcurl --restart=Never --command -- ./grpcurl -plaintext voting-svc.emojivoto:8080 emojivoto.v1.VotingService/VoteDog |
由于该 client 未经授权,所以该请求将被拒绝并显示 PermissionDenied
错误。
我们可以根据需要创建任意数量的 ServerAuthorization
资源来授权许多不同的客户端,还可以指定是授权未经身份验证(即 unmeshed)的客户端、任何经过身份验证的客户端,还是仅授权具有特定身份的经过身份验证的客户端。
此外我们还可以为整个集群设置一个默认策略,该策略将应用于所有未定义 Server 资源的。Linkerd 在决定是否允许请求时会使用以下逻辑:
- 如果有一个 Server 资源并且客户端为其匹配一个
ServerAuthorization
资源,则为ALLOW
- 如果有一个 Server 资源,但客户端不匹配它的任何
ServerAuthorizations
,则为DENY
- 如果端口没有 Server 资源,则使用默认策略
比如我们可以使用 linkerd upgrade
命令将默认策略设置为 deny
:
1 | linkerd upgrade --set policyController.defaultAllowPolicy=deny | kubectl apply -f - |
另外我们也可以通过设置 config.linkerd.io/default-inbound-policy
注解,可以在单个工作负载或命名空间上设置默认策略。
意思就是除非通过创建 Server
和 ServerAuthorization
对象明确授权,否则所有请求都将被拒绝,这样的话对于 liveness
和 readiness
探针需要明确授权,否则 Kubernetes 将无法将 Pod 识别为 live 或 ready 状态,并将重新启动它们。我们可以创建如下所示的策略对象,来允许所有客户端访问 Linkerd admin 端口,以便 Kubernetes 可以执行 liveness
和 readiness
检查:
1 | $ cat << EOF | kubectl apply -f - |
如果你知道 Kubelet(执行健康检查)的 IP 地址或范围, 也可以进一步将 ServerAuthorization
限制为这些 IP 地址或范围,比如如果你知道 Kubelet 在 10.1.1.100
上运行,那么你的 ServerAuthorization
可以改为:
1 | # ServerAuthorization "admin-kublet": allows unauthenticated access to the |
另外有一个值得注意的是在我们创建 Server
资源之后,但在创建 ServerAuthorization
之前有一段时间,所有请求都被拒绝。为了避免在实时系统中出现这种情况,我们建议你在部署服务之前创建 policy 资源,或者在创建 Server
之前创建 ServiceAuthorizations
,以便立即授权客户端。