Kubernetes 出站流量服务

Kubernetes ExternalName 服务和具有 端点 的 Kubernetes 服务可以让您创建到外部服务的本地 DNS 别名。此 DNS 别名与本地服务的 DNS 条目的形式相同,即 <服务名称>.<命名空间名称>.svc.cluster.local。DNS 别名为您的工作负载提供位置透明性:工作负载可以以相同的方式调用本地和外部服务。如果您在某个时间点决定在您的集群中部署外部服务,您只需更新其 Kubernetes 服务以引用本地版本。工作负载将继续运行而没有任何更改。

此任务说明了 Istio 仍然支持这些访问外部服务的 Kubernetes 机制。您必须执行的唯一配置步骤是使用除 Istio 的 双向 TLS 之外的 TLS 模式。外部服务不是 Istio 服务网格的一部分,因此它们无法执行 Istio 的双向 TLS。您必须根据外部服务的 TLS 要求以及工作负载访问外部服务的方式设置 TLS 模式。如果您的工作负载发出纯 HTTP 请求并且外部服务需要 TLS,您可能希望由 Istio 执行 TLS 发起。如果您的工作负载已使用 TLS,则流量已加密,您只需禁用 Istio 的双向 TLS。

虽然此任务中的示例使用 HTTP 协议,但 Kubernetes 服务用于出口流量也适用于其他协议。

在您开始之前

  • 按照 安装指南 中的说明设置 Istio。

  • 部署 curl 示例应用程序以用作发送请求的测试源。如果您已启用 自动 Sidecar 注入,请运行以下命令以部署示例应用程序

    压缩
    $ kubectl apply -f @samples/curl/curl.yaml@
    

    否则,请使用以下命令在部署 curl 应用程序之前手动注入 Sidecar

    压缩
    $ kubectl apply -f <(istioctl kube-inject -f @samples/curl/curl.yaml@)
    
  • SOURCE_POD 环境变量设置为您的源 Pod 的名称

    $ export SOURCE_POD=$(kubectl get pod -l app=curl -o jsonpath={.items..metadata.name})
    
  • 为没有 Istio 控制的源 Pod 创建命名空间

    $ kubectl create namespace without-istio
    
  • without-istio 命名空间中启动 curl 示例。

    压缩
    $ kubectl apply -f @samples/curl/curl.yaml@ -n without-istio
    
  • 要发送请求,请创建 SOURCE_POD_WITHOUT_ISTIO 环境变量以存储源 Pod 的名称

    $ export SOURCE_POD_WITHOUT_ISTIO="$(kubectl get pod -n without-istio -l app=curl -o jsonpath={.items..metadata.name})"
    
  • 验证 Istio Sidecar 是否未被注入,即 Pod 只有一个容器

    $ kubectl get pod "$SOURCE_POD_WITHOUT_ISTIO" -n without-istio
    NAME                     READY   STATUS    RESTARTS   AGE
    curl-66c8d79ff5-8tqrl    1/1     Running   0          32s
    

Kubernetes ExternalName 服务以访问外部服务

  1. httpbin.org 在默认命名空间中创建一个 Kubernetes ExternalName 服务

    $ kubectl apply -f - <<EOF
    kind: Service
    apiVersion: v1
    metadata:
      name: my-httpbin
    spec:
      type: ExternalName
      externalName: httpbin.org
      ports:
      - name: http
        protocol: TCP
        port: 80
    EOF
    
  2. 观察您的服务。请注意,它没有集群 IP。

    $ kubectl get svc my-httpbin
    NAME         TYPE           CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
    my-httpbin   ExternalName   <none>       httpbin.org   80/TCP    4s
    
  3. 从没有 Istio Sidecar 的源 Pod 通过 Kubernetes 服务的主机名访问 httpbin.org。请注意,以下 curl 命令使用 Kubernetes 服务的 DNS 格式<服务名称>.<命名空间>.svc.cluster.local

    $ kubectl exec "$SOURCE_POD_WITHOUT_ISTIO" -n without-istio -c curl -- curl -sS my-httpbin.default.svc.cluster.local/headers
    {
      "headers": {
        "Accept": "*/*",
        "Host": "my-httpbin.default.svc.cluster.local",
        "User-Agent": "curl/7.55.0"
      }
    }
    
  4. 在此示例中,未加密的 HTTP 请求被发送到 httpbin.org。出于示例目的,您禁用 TLS 模式并允许未加密的流量到达外部服务。在实际应用中,我们建议由 Istio 执行 出口 TLS 发起

    $ kubectl apply -f - <<EOF
    apiVersion: networking.istio.io/v1
    kind: DestinationRule
    metadata:
      name: my-httpbin
    spec:
      host: my-httpbin.default.svc.cluster.local
      trafficPolicy:
        tls:
          mode: DISABLE
    EOF
    
  5. 从具有 Istio Sidecar 的源 Pod 通过 Kubernetes 服务的主机名访问 httpbin.org。注意 Istio Sidecar 添加的标头,例如 X-Envoy-Peer-Metadata。还要注意 Host 标头等于您的服务的主机名。

    $ kubectl exec "$SOURCE_POD" -c curl -- curl -sS my-httpbin.default.svc.cluster.local/headers
    {
      "headers": {
        "Accept": "*/*",
        "Content-Length": "0",
        "Host": "my-httpbin.default.svc.cluster.local",
        "User-Agent": "curl/7.64.0",
        "X-B3-Sampled": "0",
        "X-B3-Spanid": "5795fab599dca0b8",
        "X-B3-Traceid": "5079ad3a4af418915795fab599dca0b8",
        "X-Envoy-Peer-Metadata": "...",
        "X-Envoy-Peer-Metadata-Id": "sidecar~10.28.1.74~curl-6bdb595bcb-drr45.default~default.svc.cluster.local"
      }
    }
    

清理 Kubernetes ExternalName 服务

$ kubectl delete destinationrule my-httpbin
$ kubectl delete service my-httpbin

使用具有端点的 Kubernetes 服务以访问外部服务

  1. 为 Wikipedia 创建一个没有选择器的 Kubernetes 服务

    $ kubectl apply -f - <<EOF
    kind: Service
    apiVersion: v1
    metadata:
      name: my-wikipedia
    spec:
      ports:
      - protocol: TCP
        port: 443
        name: tls
    EOF
    
  2. 为您的服务创建端点。从 Wikipedia 范围列表 中选择几个 IP。

    $ kubectl apply -f - <<EOF
    kind: Endpoints
    apiVersion: v1
    metadata:
      name: my-wikipedia
    subsets:
      - addresses:
          - ip: 198.35.26.96
          - ip: 208.80.153.224
        ports:
          - port: 443
            name: tls
    EOF
    
  3. 观察您的服务。请注意,它有一个集群 IP,您可以使用它访问 wikipedia.org

    $ kubectl get svc my-wikipedia
    NAME           TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)   AGE
    my-wikipedia   ClusterIP   172.21.156.230   <none>        443/TCP   21h
    
  4. 从没有 Istio Sidecar 的源 Pod 通过 Kubernetes 服务的集群 IP 向 wikipedia.org 发送 HTTPS 请求。使用 curl--resolve 选项通过集群 IP 访问 wikipedia.org

    $ kubectl exec "$SOURCE_POD_WITHOUT_ISTIO" -n without-istio -c curl -- curl -sS --resolve en.wikipedia.org:443:"$(kubectl get service my-wikipedia -o jsonpath='{.spec.clusterIP}')" https://en.wikipedia.org/wiki/Main_Page | grep -o "<title>.*</title>"
    <title>Wikipedia, the free encyclopedia</title>
    
  5. 在这种情况下,工作负载向 wikipedia.org 发送 HTTPS 请求(打开 TLS 连接)。流量已由工作负载加密,因此您可以安全地禁用 Istio 的双向 TLS

    $ kubectl apply -f - <<EOF
    apiVersion: networking.istio.io/v1
    kind: DestinationRule
    metadata:
      name: my-wikipedia
    spec:
      host: my-wikipedia.default.svc.cluster.local
      trafficPolicy:
        tls:
          mode: DISABLE
    EOF
    
  6. 从具有 Istio Sidecar 的源 Pod 通过 Kubernetes 服务的集群 IP 访问 wikipedia.org

    $ kubectl exec "$SOURCE_POD" -c curl -- curl -sS --resolve en.wikipedia.org:443:"$(kubectl get service my-wikipedia -o jsonpath='{.spec.clusterIP}')" https://en.wikipedia.org/wiki/Main_Page | grep -o "<title>.*</title>"
    <title>Wikipedia, the free encyclopedia</title>
    
  7. 检查访问是否确实通过集群 IP 执行。注意 curl -v 输出中的句子 Connected to en.wikipedia.org (172.21.156.230),它提到了在您服务输出中打印的 IP 作为集群 IP。

    $ kubectl exec "$SOURCE_POD" -c curl -- curl -sS -v --resolve en.wikipedia.org:443:"$(kubectl get service my-wikipedia -o jsonpath='{.spec.clusterIP}')" https://en.wikipedia.org/wiki/Main_Page -o /dev/null
    * Added en.wikipedia.org:443:172.21.156.230 to DNS cache
    * Hostname en.wikipedia.org was found in DNS cache
    *   Trying 172.21.156.230...
    * TCP_NODELAY set
    * Connected to en.wikipedia.org (172.21.156.230) port 443 (#0)
    ...
    

清理具有端点的 Kubernetes 服务

$ kubectl delete destinationrule my-wikipedia
$ kubectl delete endpoints my-wikipedia
$ kubectl delete service my-wikipedia

清理

  1. 关闭 curl 服务

    压缩
    $ kubectl delete -f @samples/curl/curl.yaml@
    
  2. 关闭 without-istio 命名空间中的 curl 服务

    压缩
    $ kubectl delete -f @samples/curl/curl.yaml@ -n without-istio
    
  3. 删除 without-istio 命名空间

    $ kubectl delete namespace without-istio
    
  4. 取消设置环境变量

    $ unset SOURCE_POD SOURCE_POD_WITHOUT_ISTIO
    
这些信息是否有用?
您有什么改进建议?

感谢您的反馈!