Kourier 是一个基于 Envoy 架构实现的轻量级网关,是 Knative 社区提供的开源网关实现,提供 Knative Revisions 流量分发,支持 gRPC 服务、超时和重试、TLS 证书和外部认证授权等功能。
介绍
Kourier 已达到 GA 状态
Kourier 是 Knative Serving 的一个 Ingress。Kourier 是 Istio Ingress 的一个轻量级替代方案,因为它部署时只包含一个 Envoy 代理和一个用于它的控制平面。
Kourier 正在通过 Knative Serving 的端到端(e2e)和一致性测试:Kourier Testgrid。
功能
- 在 Knative 修订版本(revisions)之间进行流量拆分
- 自动更新随着扩展而变化的端点
- 支持 gRPC 服务
- 支持超时和重试
- 支持 TLS
- 支持密码套件
- 支持外部授权
- 支持 Proxy Protocol(一项实验性/Alpha 功能)
特点
- 轻量级:相比 Istio,Kourier 的部署更为轻量,减少了资源消耗和管理复杂度
- 高性能:基于 Envoy Proxy,Kourier 提供了高性能的流量管理和路由能力
- 易用性:Kourier 的安装和配置非常简单,适合快速上手和部署
- 灵活性:支持多种高级功能,如流量拆分、自动更新端点、gRPC 支持、TLS 配置等
- 实验性功能:Kourier 还提供了一些实验性功能,如 Proxy Protocol 支持,为用户提供更多选择
部署
默认情况下,Kourier 组件的部署被分割到两个不同的命名空间:
- Kourier 控制平面部署在
knative-serving
命名空间
- Kourier 网关部署在
kourier-system
命名空间
要更改 Kourier 网关的命名空间,需要:
-
修改 config/
目录下的文件,将所有带有 kourier-system
的命名空间字段替换为所需的命名空间
-
在 kourier-control 部署中,将 KOURIER_GATEWAY_NAMESPACE
环境变量设置为新的命名空间
-
安装 Knative Serving,最好不要包含 Istio:
kubectl apply -f https://github.com/knative/serving/releases/latest/download/serving-crds.yaml
kubectl apply -f https://github.com/knative/serving/releases/latest/download/serving-core.yaml
kubectl apply -f https://github.com/knative/net-kourier/releases/latest/download/kourier.yaml
- 配置 Knative Serving 以使用正确的 “ingress.class”:
kubectl patch configmap/config-network \
-n knative-serving \
--type merge \
-p '{"data":{"ingress.class":"kourier.ingress.networking.knative.dev"}}'
- (可选)设置你想要的域名(将 127.0.0.1.nip.io 替换为你偏好的域名):
kubectl patch configmap/config-domain \
-n knative-serving \
--type merge \
-p '{"data":{"127.0.0.1.nip.io":""}}'
- (可选)部署一个示例的 hello world 应用:
cat <<-EOF | kubectl apply -f -
apiVersion: serving.knative.dev/v1
kind: Service
metadata:
name: helloworld-go
spec:
template:
spec:
containers:
- image: gcr.io/knative-samples/helloworld-go
env:
- name: TARGET
value: Go Sample v1
EOF
- (可选)为了测试目的,你可以使用端口转发(port-forwarding)从你的机器向 Kourier 发出请求:
kubectl port-forward --namespace kourier-system $(kubectl get pod -n kourier-system -l "app=3scale-kourier-gateway" --output=jsonpath="{.items[0].metadata.name}") 8080:8080 19000:9000 8443:8443
curl -v -H "Host: helloworld-go.default.127.0.0.1.nip.io" http://localhost:8080
代码解析
配置解析
Envoy 动态配置 (dynamic_resources)的基本设置,主要用于通过 ADS (Aggregated Discovery Service) 动态发现服务、集群和监听器等资源。
dynamic_resources:
ads_config:
transport_api_version: V3
api_type: GRPC
rate_limit_settings: {}
grpc_services:
- envoy_grpc: {cluster_name: xds_cluster}
cds_config:
resource_api_version: V3
ads: {}
lds_config:
resource_api_version: V3
ads: {}
dynamic_resources
: 这个顶级字段表明 Envoy 正在使用动态配置,而不是静态文件。这意味着 Envoy 会在运行时从一个或多个 xDS (Discovery Service) 服务器获取配置信息。
ads_config
: 这是核心配置,定义了 ADS 的连接方式。ADS 是一种 聚合发现服务
,它允许 Envoy 通过一个单一的 gRPC 流同时接收所有类型的动态配置(如 CDS、LDS、RDS、EDS)。这简化了管理,因为你不需要为每种资源类型设置单独的连接。
transport_api_version: V3
: 指定了用于 xDS 通信的 API 版本,这里是 V3。V3 是 Envoy 目前推荐使用的最新版本,提供了更丰富的特性和更好的稳定性。
api_type: GRPC
: 明确了 Envoy 将使用 gRPC 协议与 xDS 服务器通信。gRPC 是一种高性能的 RPC(远程过程调用)框架,非常适合这种持续的、双向的数据流。
rate_limit_settings: {}
: 这是一个空对象,表示目前没有对 xDS 资源的请求速率进行限制。在生产环境中,可以配置这个字段来防止 xDS 服务器被过多的请求淹没。
grpc_services
: 定义了用于连接 xDS 服务器的 gRPC 服务。
envoy_grpc: {cluster_name: xds_cluster}
: 这表明 Envoy 将使用名为 xds_cluster
的上游集群来建立与 xDS 服务器的 gRPC 连接。xds_cluster
本身需要在配置的 static_resources
或其他动态配置中定义,以指定 xDS 服务器的地址、端口等信息。
cds_config
、lds_config
: 这两个字段是 ADS 的一个重要部分,它们告诉 Envoy 启用 CDS (Cluster Discovery Service) 和 LDS (Listener Discovery Service),并通过 ADS 来获取这些资源。
resource_api_version: V3
: 再次确认这些资源也将使用 V3 版本的 API。
ads: {}
: 这个空对象是关键,它指示 Envoy:
请不要为 CDS/LDS 建立单独的连接
请使用上面
ads_config 定义的统一连接来获取 CDS/LDS 资源
✅
- 工作流程 🔄
- Envoy 启动后,读取这份配置。
- 它看到
dynamic_resources
并找到了 ads_config
。
- 它根据
grpc_services
中指定的 xds_cluster
,向 xDS 服务器建立一个 gRPC 长连接。
- 通过这个单一连接,Envoy 会向 xDS 服务器发送 CDS 请求 和 LDS 请求。
- xDS 服务器接收到请求后,会通过同一个 gRPC 流 推送 相应的集群配置 (CDS) 和监听器配置 (LDS) 给 Envoy。
- 当集群或监听器配置在 xDS 服务器端发生变化时,它会主动通过这个流将更新推送到 Envoy,实现 配置的热更新。
核心思想是利用 ADS,通过一个统一的 gRPC 连接,高效且动态地管理 Envoy 的所有配置,这极大地简化了大规模微服务架构下的服务发现和流量管理。
使用
设置 TLS 证书
创建证书:
openssl genrsa -out tls.key 4096
openssl req -subj "/CN=*.xiexianbin.cn/L=*.xiexianbin.cn" -sha256 -new -key tls.key -out tls.csr
echo subjectAltName = DNS:default.xiexianbin.cn,DNS:*.default.xiexianbin.cn > extfile.cnf
openssl x509 -req -days 3650 -sha256 -in tls.csr -signkey tls.key -out tls.crt -extfile extfile.cnf
创建一个包含 TLS 证书和私钥的 Secret:
kubectl create secret tls ${CERT_NAME} --key ${KEY_FILE} --cert ${CERT_FILE}
kubectl -n knative-serving create secret tls kourier-cert --key tls.key --cert tls.crt
在 “kourier” 容器中,为 net-kourier-controller
添加以下环境变量(kubectl -n knative-serving edit deployment net-kourier-controller
):
...
spec:
containers:
- env:
- name: CERTS_SECRET_NAMESPACE
value: ${NAMESPACES_WHERE_THE_SECRET_HAS_BEEN_CREATED-knative-serving}
- name: CERTS_SECRET_NAME
value: ${CERT_NAME-kourier-cert}
...
访问:
curl -H "host: helloworld-go.default.127.0.0.1.nip.io" -k --cert tls.crt --key tls.key http://localhost:8080 -v
密码套件/Cipher Suites
可以为外部 TLS 监听器指定密码套件。要指定你想要允许的密码套件,请运行以下命令来修补 config-kourier
ConfigMap:
kubectl -n "knative-serving" patch configmap/config-kourier \
--type merge \
-p '{"data":{"cipher-suites":"ECDHE-ECDSA-AES128-GCM-SHA256,ECDHE-ECDSA-CHACHA20-POLY1305"}}'
默认情况下,它使用 Envoy 版本的默认密码套件。
外部授权配置
如果你想启用外部授权支持,可以在 net-kourier-controller
部署中设置以下环境变量:
KOURIER_EXTAUTHZ_HOST*
:外部授权服务及其端口,例如 my-auth:2222
。
KOURIER_EXTAUTHZ_FAILUREMODEALLOW*
:如果外部授权服务宕机,是否允许流量通过。接受 true
或 false
。
KOURIER_EXTAUTHZ_PROTOCOL
:用于查询外部授权服务的协议。可以是:grpc
、http
或 https
。默认为 grpc
。
KOURIER_EXTAUTHZ_MAXREQUESTBYTES
:最大请求字节数,如果未设置,默认为 8192 字节。更多信息请参阅 Envoy 文档。
KOURIER_EXTAUTHZ_TIMEOUT
:等待外部授权服务的最大时间(毫秒)。默认为 2 秒。
KOURIER_EXTAUTHZ_PATHPREFIX
:如果 KOURIER_EXTAUTHZ_PROTOCOL
等于 http
或 https
,此项为查询外部授权服务的路径。例如:如果设置为 /verify
,它将查询 /verify/
(注意末尾的斜杠)。如果未设置,它将查询 /
。
KOURIER_EXTAUTHZ_PACKASBYTES
:如果 KOURIER_EXTAUTHZ_PROTOCOL
等于 grpc
,此项将请求正文作为原始字节发送,而不是 UTF-8 字符串。仅接受 true
/false
、t
/f
或 1
/0
。尝试设置其他值会抛出错误。默认为 false
。更多信息请参阅 Envoy 文档。
*
为必填项。
Proxy Protocol 配置
注意:这是一项实验性/Alpha 功能。
要启用 Proxy Protocol 功能,请运行以下命令修补 config-kourier
ConfigMap:
kubectl patch configmap/config-kourier \
-n knative-serving \
--type merge \
-p '{"data":{"enable-proxy-protocol":"true"}}'
确保文件已成功更新:
kubectl get configmap config-kourier --namespace knative-serving --output yaml
LoadBalancer 配置
我们需要:
- 使用你的 LB 提供商的注解来启用 Proxy Protocol。
- 如果你计划启用外部域名 TLS,使用你的 LB 提供商的注解来指定一个自定义名称用于 LoadBalancer。这是为了解决 kube-proxy 将外部 LB 地址添加到节点本地 iptables 规则的问题,该问题会导致集群内部对 LB 的请求中断(如果 LB 期望终止 SSL 或 Proxy Protocol)。
- 将
externalTrafficPolicy
更改为 Local
,这样 LB 将保留客户端源 IP,并避免了对 LoadBalancer 的第二次跳跃。
示例 (Scaleway 提供商):
apiVersion: v1
kind: Service
metadata:
name: kourier
namespace: kourier-system
annotations:
service.beta.kubernetes.io/scw-loadbalancer-proxy-protocol-v2: '*'
service.beta.kubernetes.io/scw-loadbalancer-use-hostname: "true"
labels:
networking.knative.dev/ingress-provider: kourier
spec:
ports:
- name: http2
port: 80
protocol: TCP
targetPort: 8080
- name: https
port: 443
protocol: TCP
targetPort: 8443
selector:
app: 3scale-kourier-gateway
externalTrafficPolicy: Local
type: LoadBalancer
域名映射
域名映射(Domain Mapping)被配置为仅显式使用 http2
协议。通过向域名映射资源添加以下注解可以禁用此行为:
kubectl annotate domainmapping <domain_mapping_name> kourier.knative.dev/disable-http2=true --namespace <namespace>
此配置的一个很好用例是带有 Websocket 的域名映射。
注意:此注解是一项实验性/Alpha 功能。我们将来可能会更改注解名称。
日志采集
[%START_TIME%] "%REQ(:METHOD)% %REQ(X-ENVOY-ORIGINAL-PATH?:PATH)% %PROTOCOL%"
%RESPONSE_CODE% %RESPONSE_FLAGS% %BYTES_RECEIVED% %BYTES_SENT% %DURATION%
%RESP(X-ENVOY-UPSTREAM-SERVICE-TIME)% "%REQ(X-FORWARDED-FOR)%" "%REQ(USER-AGENT)%"
"%REQ(X-REQUEST-ID)%" "%REQ(:AUTHORITY)%" "%UPSTREAM_HOST%"\n
[2016-04-15T20:17:00.310Z] "POST /api/v1/locations HTTP/2" 204 - 154 0 226 100 "10.0.35.28"
"nsq2http" "cc21d9b0-cf5c-432b-8c7e-98aeb7988cd2" "locations" "tcp://10.0.2.1:80"
扩展