Istio 常见问题 - 集群内无法访问外部服务

原文:https://makeoptim.com/istio-faq/accessing-external-services

现象

集群内无法访问外部服务。

  1. 在集群中部署 sleep

    kubectl apply -f samples/sleep/sleep.yaml
    
    
  2. 设置环境变量

    export SOURCE_POD=$(kubectl get pod -l app=sleep -o jsonpath={.items..metadata.name})
    
    
  3. 访问外网服务

    $ kubectl exec -it $SOURCE_POD -c sleep -- curl http://www.baidu.com
    
    $ kubectl exec -it $SOURCE_POD -c sleep -- curl -I https://www.baidu.com | grep  "HTTP/"
    command terminated with exit code 35
    
    

进入 sleep 容器,执行 curl http://www.baidu.com,无数据返回;执行 curl -I https://www.baidu.com 也访问失败。这种现象就是集群内无法访问外部服务。

原因

由于默认情况下,来自 Istio-enable Pod 的所有出站流量都会重定向到其 Sidecar 代理,群集外部 URL 的可访问性取决于代理的配置。默认情况下,Istio 将 Envoy 代理配置为允许传递未知服务的请求。但这不是 Istio 推荐的做法,因此,服务商或者其他安装配置可能会修改默认设置为不允许传递未知服务的请求。

当遇到集群内无法访问外部服务时,可运行以下命令检查 Sidecar 的代理配置,查看是否允许传递未知服务的请求。

$ kubectl get configmap istio -n istio-system -o yaml | grep -o "mode: ALLOW_ANY"
mode: ALLOW_ANY
mode: ALLOW_ANY

# 或者

$ kubectl get configmap istio -n istio-system -o yaml | grep -o "mode: REGISTRY_ONLY"
mode: REGISTRY_ONLY
mode: REGISTRY_ONLY

如果命令输出有 mode: ALLOW_ANY 表示 Istio 代理允许调用未知的服务; 如果命令输出有 mode: REGISTRY_ONLY 那么 Istio 代理会阻止任何没有在网格中定义的 HTTP 服务或 service entry 的主机

方法

如果是因为 Istio 的配置项为 mode: REGISTRY_ONLY 而导致集群内无法访问外部服务。可有以下三种访问外部服务的方法:

  • 方法一:修改配置为 mode: ALLOW_ANY 以允许 Sidecar 将请求传递到未在网格内配置过的服务。
  • 方法二:配置 ServiceEntry 以提供对外部服务的受控访问。
  • 方法三:对于特定范围的 IP,完全绕过 Envoy 代理。

方法一

运行以下命令,修改配置为 mode: ALLOW_ANY

$ kubectl get configmap istio -n istio-system -o yaml | sed 's/mode: REGISTRY_ONLY/mode: ALLOW_ANY/g' | kubectl replace -n istio-system -f -
configmap/istio replaced

验证配置

$ kubectl get configmap istio -n istio-system -o yaml | grep -o "mode: ALLOW_ANY"
mode: ALLOW_ANY
mode: ALLOW_ANY

重启部署

$ kubectl rollout restart deployment sleep
deployment.extensions/sleep restarted

访问外部服务

$ export SOURCE_POD=$(kubectl get pod -l app=sleep -o jsonpath={.items..metadata.name})

$ kubectl exec -it $SOURCE_POD -c sleep -- curl http://www.baidu.com
<!DOCTYPE html>
......
京ICP证030173号&nbsp; <img src=//www.baidu.com/img/gs.gif> </p> </div> </div> </div> </body> </html>

$ kubectl exec -it $SOURCE_POD -c sleep -- curl -I https://www.baidu.com | grep  "HTTP/"
HTTP/1.1 200 OK

注:这种访问外部服务的简单方法有一个缺点,即丢失了对外部服务流量的 Istio 监控和控制

方法二

在开始方法二之前,需要先修改 Istio 的配置项为 mode: REGISTRY_ONLY

$ kubectl get configmap istio -n istio-system -o yaml | sed 's/mode: ALLOW_ANY/mode: REGISTRY_ONLY/g' | kubectl replace -n istio-system -f -
configmap "istio" replaced

允许访问外部 HTTP 服务

  1. 添加 ServiceEntry,允许访问 httpbin 的 HTTP 服务

    kubectl apply -f - <<EOF
    apiVersion: networking.istio.io/v1alpha3
    kind: ServiceEntry
    metadata:
      name: httpbin-ext
    spec:
      hosts:
      - httpbin.org
      ports:
      - number: 80
        name: http
        protocol: HTTP
      resolution: DNS
      location: MESH_EXTERNAL
    EOF
    
    
  2. 从 sleep 向外部发送 httpbin 的 HTTP 服务请求

    $ kubectl exec -it $SOURCE_POD -c sleep -- curl http://httpbin.org/headers
    {
      "headers": {
        "Accept": "*/*",
        "Content-Length": "0",
        "Host": "httpbin.org",
        "User-Agent": "curl/7.64.0",
        "X-Amzn-Trace-Id": "Root=1-5e89e3ba-e22faf007e305d9897cddf1e",
        "X-B3-Sampled": "1",
        "X-B3-Spanid": "338f3faa38eb194e",
        "X-B3-Traceid": "d0ff4841f30240b2338f3faa38eb194e",
        "X-Envoy-Decorator-Operation": "httpbin.org:80/*",
        "X-Envoy-Peer-Metadata": "ChwKDElOU1RBTkNFX0lQUxIMGgoxMC4xLjAuMjQ1CsMBCgZMQUJFTFMSuAEqtQEKDgoDYXBwEgcaBXNsZWVwCiAKEXBvZC10ZW1wbGF0ZS1oYXNoEgsaCWM2OWQ5NmM5YwokChlzZWN1cml0eS5pc3Rpby5pby90bHNNb2RlEgcaBWlzdGlvCioKH3NlcnZpY2UuaXN0aW8uaW8vY2Fub25pY2FsLW5hbWUSBxoFc2xlZXAKLwojc2VydmljZS5pc3Rpby5pby9jYW5vbmljYWwtcmV2aXNpb24SCBoGbGF0ZXN0ChoKB01FU0hfSUQSDxoNY2x1c3Rlci5sb2NhbAofCgROQU1FEhcaFXNsZWVwLWM2OWQ5NmM5Yy0yZnh6ZAoWCglOQU1FU1BBQ0USCRoHZGVmYXVsdApJCgVPV05FUhJAGj5rdWJlcm5ldGVzOi8vYXBpcy9hcHBzL3YxL25hbWVzcGFjZXMvZGVmYXVsdC9kZXBsb3ltZW50cy9zbGVlcAoaCg9TRVJWSUNFX0FDQ09VTlQSBxoFc2xlZXAKGAoNV09SS0xPQURfTkFNRRIHGgVzbGVlcA==",
        "X-Envoy-Peer-Metadata-Id": "sidecar~10.1.0.245~sleep-c69d96c9c-2fxzd.default~default.svc.cluster.local"
      }
    }
    
    

    注:返回数据中可以看到 Istio sidecar 代理添加的 headers: X-Envoy-Decorator-Operation,表示访问外部的流量经过了 sidecar

  3. 检查 sleep 的 sidecar 日志

    1
    2
    $  kubectl logs $SOURCE_POD -c istio-proxy | tail
    [2020-04-05T13:57:13.948Z] "GET /headers HTTP/1.1" 200 - "-" "-" 0 1117 629 628 "-" "curl/7.64.0" "d94cc283-11ef-949c-8ba0-d948ad5785ab" "httpbin.org" "52.202.2.199:80" outbound|80||httpbin.org 10.1.0.245:48116 34.230.193.231:80 10.1.0.245:56246 - default
    
    

允许访问外部 HTTPS 服务

  1. 添加 ServiceEntry,允许访问 httpbin 的 HTTPS 服务

    kubectl apply -f - <<EOF
    apiVersion: networking.istio.io/v1alpha3
    kind: ServiceEntry
    metadata:
      name: httpbin-https-ext
    spec:
      hosts:
      - httpbin.org
      ports:
      - number: 443
        name: https
        protocol: HTTPS
      resolution: DNS
      location: MESH_EXTERNAL
    EOF
    
    
  2. 从 sleep 向外部发送 httpbin 的 HTTPS 服务请求

    $ kubectl exec -it $SOURCE_POD -c sleep -- curl -I https://httpbin.org/headers
    HTTP/2 200
    date: Sun, 05 Apr 2020 14:10:25 GMT
    content-type: application/json
    content-length: 173
    server: gunicorn/19.9.0
    access-control-allow-origin: *
    access-control-allow-credentials: true
    
    
  3. 检查 sleep 的 sidecar 日志

    $ kubectl logs $SOURCE_POD -c istio-proxy | tail
    [2020-04-05T14:10:23.939Z] "- - -" 0 - "-" "-" 941 5597 1695 - "-" "-" "-" "-" "3.232.168.170:443" outbound|443||httpbin.org 10.1.0.245:36844 3.232.168.170:443 10.1.0.245:36838 httpbin.org -
    
    

管理到外部服务的流量

通过 ServiceEntry 配置访问的外部服务,可以向集群内的请求一样设置 Istio 路由规则。下面以 httpbin 为例,设置对服务访问的超时规则。

  1. 向外部服务 httpbin.org 的 /delay endpoint 发出 curl 请求:

    $ kubectl exec -it $SOURCE_POD -c sleep sh
    / # time curl -o /dev/null -s -w "%{http_code}\n" http://httpbin.org/delay/5
    200
    real    0m 6.12s
    user    0m 0.00s
    sys     0m 0.00s
    / #
    
    

    这个请求大约在 5 秒内返回 200 (OK)。

  2. 使用 kubectl 设置调用外部服务 httpbin.org 的超时时间为 3 秒。

    $ kubectl apply -f - <<EOF
    apiVersion: networking.istio.io/v1alpha3
    kind: VirtualService
    metadata:
      name: httpbin-ext
    spec:
      hosts:
        - httpbin.org
      http:
      - timeout: 3s
        route:
          - destination:
              host: httpbin.org
            weight: 100
    EOF
    
    
  3. 几秒后,重新发出 curl 请求:

    $ kubectl exec -it $SOURCE_POD -c sleep sh
    / # time curl -o /dev/null -s -w "%{http_code}\n" http://httpbin.org/delay/5
    504
    real    0m 3.28s
    user    0m 0.00s
    sys     0m 0.00s
    
    

这一次,在 3 秒后出现了 504 (Gateway Timeout)。Istio 在 3 秒后切断了响应时间为 5 秒的 httpbin.org 服务。

方法三

在开始方法三之前,需要先清理对外部服务的受控访问

$ kubectl delete serviceentry baidu-ext httpbin-ext httpbin-https-ext
serviceentry.networking.istio.io "baidu-ext" deleted
serviceentry.networking.istio.io "httpbin-ext" deleted
serviceentry.networking.istio.io "httpbin-https-ext" deleted

$ kubectl delete virtualservice httpbin-ext --ignore-not-found=true
virtualservice.networking.istio.io "httpbin-ext" deleted

直接访问外部服务

如果要让特定范围的 IP 完全绕过 Istio,则可以配置 Envoy sidecars 以防止它们拦截外部请求。要设置绕过 Istio,请更改 global.proxy.includeIPRangesglobal.proxy.excludeIPRanges 配置选项,并使用 kubectl apply 命令更新 istio-sidecar-injector 的配置。istio-sidecar-injector 配置的更新,影响的是新部署应用的 pod

注:与方法一使用 mode: ALLOW_ANY 流量策略来让 Istio sidecar 代理将调用传递给未知服务不同。更改 global.proxy.includeIPRangesglobal.proxy.excludeIPRanges 配置选项的方法,完全绕过了 sidecar,从而实质上禁用了指定 IP 的所有 Istio 功能。你不能mode: ALLOW_ANY 方法那样为特定的目标增量添加 service entries。 因此,仅当出于性能或其他原因无法使用 sidecar 配置外部访问时,才建议使用此配置方法

排除所有外部 IP 重定向到 Sidecar 代理的一种简单方法是将 global.proxy.includeIPRanges 配置选项设置为内部集群服务使用的 IP 范围。这些 IP 范围值取决于集群所在的平台

确定平台内部的 IP 范围
阿里云(AKS)

注:这里先提下阿里云,因为其设置与其他平台不同

  1. 查看集群信息,获取 Pod 网络 CIDR 和 Service CIDR,如 172.20.0.0/16 和 172.21.0.0/20

    faq
  2. 点击 Istio 管理,点击更新,找到 includeIPRanges 并设置为 Pod 网络 CIDR 和 Service CIDR

    faq
IBM Cloud Private
  1. 从 IBM Cloud Private 的配置文件 cluster/config.yaml 中获取你的 service_cluster_ip_range:

    $ cat cluster/config.yaml | grep service_cluster_ip_range
    service_cluster_ip_range: 10.0.0.1/24 //这里以 10.0.0.1/24 为例
    
    
  2. 使用 --set global.proxy.includeIPRanges="10.0.0.1/24"

IBM Cloud Kubernetes Service

使用 --set global.proxy.includeIPRanges="172.30.0.0/16\,172.21.0.0/16\,10.10.10.0/24"

Google Container Engine (GKE)

范围是不固定的,你需要运行 gcloud container clusters describe 命令来确定要使用的范围。举个例子:

$ gcloud container clusters describe XXXXXXX --zone=XXXXXX | grep -e clusterIpv4Cidr -e servicesIpv4Cidr
clusterIpv4Cidr: 10.4.0.0/14
servicesIpv4Cidr: 10.7.240.0/20

使用 --set global.proxy.includeIPRanges="10.4.0.0/14\,10.7.240.0/20"

Azure Container Service(ACS)

使用 --set global.proxy.includeIPRanges="10.244.0.0/16\,10.240.0.0/16

Minikube, Docker For Desktop, Bare Metal

默认值为 10.96.0.0/12,但不是固定的。使用以下命令确定您的实际值:

$ kubectl describe pod kube-apiserver -n kube-system | grep 'service-cluster-ip-range'
      --service-cluster-ip-range=10.96.0.0/12

使用 –set global.proxy.includeIPRanges=”10.96.0.0/12”

配置代理绕行

使用平台的 IP 范围更新 istio-sidecar-injector 的配置。比如,如果 IP 范围是 10.0.0.1/24,则使用一下命令:

istioctl manifest apply <the flags you used to install Istio> --set values.global.proxy.includeIPRanges="10.0.0.1/24"

安装 Istio 命令的基础上增加 --set values.global.proxy.includeIPRanges="10.0.0.1/24"

注:若你是按照本专栏开发环境搭建教程搭建环境的话,则使用 istioctl manifest apply --set profile=demo --set values.global.proxy.includeIPRanges="10.96.0.0/12" 命令配置代理绕行即可。

访问外部服务

由于绕行配置仅影响新的部署,因此需要重新部署 sleep 程序。

$ kubectl delete deployment sleep
deployment.extensions "sleep" deleted

$ kubectl apply -f samples/sleep/sleep.yaml
serviceaccount/sleep unchanged
service/sleep unchanged
deployment.apps/sleep created

在更新 istio-sidecar-injector configmap 和重新部署 sleep 程序后,Istio sidecar 将仅拦截和管理集群中的内部请求。 任何外部请求都会绕过 Sidecar,并直接到达其预期的目的地。举个例子:

$ export SOURCE_POD=$(kubectl get pod -l app=sleep -o jsonpath={.items..metadata.name})
$ kubectl exec -it $SOURCE_POD -c sleep curl http://httpbin.org/headers
{
  "headers": {
    "Accept": "*/*",
    "Host": "httpbin.org",
    "User-Agent": "curl/7.64.0",
    "X-Amzn-Trace-Id": "Root=1-5e89f4e2-524fd7a41c99025a43c403ce"
  }
}

与通过 HTTP 和 HTTPS 访问外部服务不同,你不会看到任何与 Istio sidecar 有关的请求头,并且发送到外部服务的请求不会出现在 Sidecar 的日志中。 绕过 Istio sidecar 意味着你不能再监视对外部服务的访问。

总结

本文先介绍了集群内无法访问外部服务的现象,然后阐述了该现象的原因,最后提供了三个方法供大家选用。

方法一通过修改 Istio sidecar 代理配置为 mode: ALLOW_ANY 以允许访问外部服务。使用这种方法时,你将无法监控对外部服务的访问无法利用 Istio 的流量控制功能

方法二通过添加 ServiceEntry,以允许访问外部服务。可以让你使用 Istio 服务网格所有的功能去调用集群内或集群外的服务,这是官方推荐的方法

方法三直接绕过了 Istio Sidecar 代理,使你的服务可以直接访问任意的外部服务。 但是,以这种方式配置代理需要了解集群提供商相关知识和配置。 与方法一类似,你也将失去对外部服务访问的监控,并且无法将 Istio 功能应用于外部服务的流量

方法二的做法类似于“白名单”,不但能达到访问外部服务的目的,并且可以像集群内部服务一样对待(可使用 Istio 的流量控制功能)。另外,即使服务受到入侵,由于“白名单”的设置入侵者也无法(或较难)将流量回传到入侵机器,进一步保证了服务的安全性。因此,强烈推荐大家使用方法二

最后,特别提醒一下大家。某些教程,如Istio 服务无法访问外网,开放外网权限includeOutboundIPRanges 设置为空是有问题的,这相当于将所有的服务都配置代理绕行,那 sidecar 就没起作用了,没了 sidecar 的 Istio 就没有灵魂了。

参考

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,743评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,296评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,285评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,485评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,581评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,821评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,960评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,719评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,186评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,516评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,650评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,329评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,936评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,757评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,991评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,370评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,527评论 2 349

推荐阅读更多精彩内容