作者 修订时间
wjlin0 2024-12-31 23:26:58

Traefik资源跨命名空间调用

前沿

在研究traefik跨命名空间调用资源时,发现有一个非常坑人的点,就是 traefik文档有一个东西叫 跨服务商命名空间(Provider Namespace),这个是什么东西呢,就是如果你在 k3s/k8s中有需要对docker提供商创建的资源进行调用时,你可以开启跨服务商命名空间。还有一个就是Kubernetes自带的命名空间,我们需要操作的就是这个命名空间。

这里的namespace: default

apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
  name: default
  namespace: default # 就是这个字段
spec:
  entryPoints:
    - websecure  # 使用 HTTPS
    - web  # HTTP
  routes:
    - match: Host(`www.wjlin0.com`) &&  PathPrefix(`/`)  # 
      kind: Rule
      services:
        - name: default

利用

如何进行跨命名空间资源调用呢,在traefik文档中提到有个参数allowCrossNamespace,这个参数是控制跨命名空间资源调用,(默认关闭的,不允许跨命名空间资源调用)。

这是helm安装,参数所在位置.

......
......
......
# -- Define [Startup Probe](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/#define-startup-probes)
startupProbe: {}

providers:  # @schema additionalProperties: false
  kubernetesCRD:
    # -- Load Kubernetes IngressRoute provider
    enabled: true
    # -- Allows IngressRoute to reference resources in namespace other than theirs
    allowCrossNamespace: true
......
......

开启后,配置跨命名空间资源调度,需要遵守以下命名规则。

<资源命名空间>-<资源名称>@提供商

了解了上诉的操作步骤,我们应该怎么做呢,我接下来给出一个案例;

需求时,我将k3s-apiserverping目录,通过traefik,导出到外部访问。

apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
  name: kubernetes-ping-ingressroute
  namespace: default
spec:
  entryPoints:
    - websecure  # 使用 HTTPS
    - web  # HTTP
  routes:
    - match: Host(`kube.wjlin0.com`) &&  PathPrefix(`/ping`)  
      kind: Rule
      services:
        - name: kubernetes # 
          port: 443  
          scheme: https

在上诉配置中我们成功将服务kubernetes导出到外部访问,但是你访问之后会发现,该路由爆500的错误

➜  ~ curl https://kube.wjlin0.com/ping
Internal Server Error
➜  ~

这是因为kubernetes的证书是自签证书,你需要对该证书进行引用或者忽略。首先我们找到这个证书,它位于服务器的

/var/lib/rancher/k3s/server/tls/serving-kube-apiserver.crt

然后我们将 证书 base64 转换。

base64 -w 0 /var/lib/rancher/k3s/server/tls/serving-kube-apiserver.crt

然后通过rootCAsSecrets 引用进来,当然你可以都保存在default,这里是在演示如何跨命名空间调用。

apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
  name: kubernetes-ping-ingressroute
  namespace: default
spec:
  entryPoints:
    - websecure  # 使用 HTTPS
    - web  # HTTP
  routes:
    - match: Host(`kube.wjlin0.com`) &&  PathPrefix(`/ping`)  # 替换为你的域名
      kind: Rule
      services:
        - name: kubernetes  # 替换为你的服务名称
          port: 443  # 替换为你的服务端口
#          strategy: RoundRobin  # 负载均衡策略,默认为 RoundRobin
          serversTransport: kube-system-kubernetes@kubernetescrd
---
apiVersion: traefik.io/v1alpha1
kind: ServersTransport
metadata:
  name: kubernetes
  namespace: kube-system
spec:
  insecureSkipVerify: false
  rootCAsSecrets:
    - k3s-serving-kube-apiserver
---
apiVersion: v1
kind: Secret
metadata:
  name: k3s-serving-kube-apiserver
  namespace: kube-system
data:
  ca.crt: ......

再次进行命令

➜  ~ curl https://kube.wjlin0.com/ping
pong
➜  ~

小插曲

⚠️ 小插曲,这里遇到一个问题就是如下.

我使用下面的配置 通过 traefikkubernetes 服务端的 ping 目录导出来,然而 出现了证书错误 500

apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
  name: kubernetes-ping-ingressroute
  namespace: default
spec:
  entryPoints:
    - websecure  # 使用 HTTPS
    - web  # HTTP
  routes:
    - match: Host(`kube.wjlin0.com`) &&  PathPrefix(`/ping`)  # 替换为你的域名
      kind: Rule
      services:
        - name: kubernetes
          port: 443  # 替换为你的服务端口
          scheme: https
          serversTransport: kube-system-kubernetes@kubernetescrd
---
apiVersion: traefik.io/v1alpha1
kind: ServersTransport
metadata:
  name: kubernetes
  namespace: kube-system
spec:
  serverName: kubernetes.default.svc
  insecureSkipVerify: false
  rootCAsSecrets:
    - k3s-serving
  certificatesSecrets:
    - k3s-serving

这是我的错误

2024-12-31T19:01:08+08:00 DBG github.com/traefik/traefik/v3/pkg/proxy/httputil/proxy.go:113 > 500 Internal Server Error error="tls: failed to verify certificate: x509: certificate signed by unknown authority"

事实上 k3s-serving 这个是 k3s 的 的证书

➜  ~ k get secrets -n kube-system k3s-serving -o yaml
apiVersion: v1
data:
  tls.crt:  ..........
  tls.key:  .......
kind: Secret
metadata:
  .......
  .......
  .......
  name: k3s-serving
  namespace: kube-system
type: kubernetes.io/tls

我尝试去解决它 ,于是我创建了一个 sercert ,发现它 能够访问了

apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
  name: kubernetes-ping-ingressroute
  namespace: default
spec:
  entryPoints:
    - websecure  # 使用 HTTPS
    - web  # HTTP
  routes:
    - match: Host(`kube.wjlin0.com`) &&  PathPrefix(`/ping`)  # 替换为你的域名
      kind: Rule
      services:
        - name: kubernetes
          port: 443  # 替换为你的服务端口
          scheme: https
          serversTransport: kube-system-kubernetes@kubernetescrd
---
apiVersion: traefik.io/v1alpha1
kind: ServersTransport
metadata:
  name: kubernetes
  namespace: kube-system
spec:
  serverName: kubernetes.default.svc
  insecureSkipVerify: false
  rootCAsSecrets:
    - meta
  certificatesSecrets:
    - k3s-serving
---
apiVersion: v1
kind: Secret
metadata:
  name: meta
  namespace: kube-system
data:
  ca.crt:  .....  # the k3s crt base64

我找到一个类似的问题 #7788

翻了一下源代码,发现只对ca.crttls.ca和一个出现的密钥

总结

traefik默认不开启跨命名调用,如果需要,需要在安装时,打开配置allowCrossNamespacetrue,并使用命名规则

When you declare certain objects in the Traefik dynamic configuration, such as middleware, services, TLS options or server transports, they reside in their provider's namespace. For example, if you declare a middleware using a Docker label, it resides in the Docker provider namespace.

If you use multiple providers and wish to reference such an object declared in another provider (e.g. referencing a cross-provider object like middleware), then the object name should be suffixed by the @ separator, and the provider name.

For the list of the providers names, see the supported providers table below.

<resource-name>@<provider-name>

As Kubernetes also has its own notion of namespace, one should not confuse the provider namespace with the Kubernetes Namespace of a resource when in the context of cross-provider usage.

In this case, since the definition of a Traefik dynamic configuration object is not in Kubernetes, specifying a Kubernetes Namespace when referring to the resource does not make any sense.

On the other hand, if you were to declare a middleware as a Custom Resource in Kubernetes and use the non-CRD Ingress objects, you would have to add the Kubernetes Namespace of the middleware to the annotation like this <middleware-namespace>-<middleware-name>@kubernetescrd.

参考

results matching ""

    No results matching ""