找回密码
 立即注册
首页 业界区 业界 istio初探以及解决http-426的问题

istio初探以及解决http-426的问题

挡缭 4 天前
前言

在之前的文章中,我们花了大量的篇幅,从记录后端pod真实ip开始说起,然后引入envoy,再解决了各种各样的需求:配置自动重载、流量劫持、sidecar自动注入,到envoy的各种能力:熔断、流控、分流、透明代理、可观测性等等,已经可以支撑起一个完整的服务治理框架了
而今天介绍的istio,正是前面提到的这些所有功能的集大成者,从本文开始,我们将详细介绍istio,并且与之前手搓的功能做一个详细的对比,为大家以后选择服务治理的某个功能提供参考
istio架构
  1.            ┌──────────────┐
  2.            │   istiod     │   ← 控制面
  3.            │ (Pilot+CA)   │
  4.            └──────┬───────┘
  5.                   │ xDS (gRPC / TLS)
  6.                   │
  7. ┌────────────┐    │    ┌────────────┐
  8. │  Envoy     │◄───┼───►│   Envoy    │  ← 数据面
  9. │ (Sidecar)  │         │ (Sidecar)  │
  10. └─────▲──────┘         └─────▲──────┘
  11.       │ iptables             │
  12.       │                      │
  13.    App Pod                App Pod
复制代码

  • 数据面就是之前一直在研究的envoy,包括4/7代理、熔断、限流、可观测性等等,envoy就是执行由控制面下发的配置
  • 控制面istiod主要的职责:将配置下发到每一个envoy去。由于istio中配置以crd的形式成为了k8s的资源,所以要不断的监听k8s apiserver,将资源的变化翻译成envoy看得懂的配置,并且下发到envoy去
至于其余istio的资源,我们后面详细介绍
istio安装

不说废话,先把istio安装上去再说
首先准备好k8s集群,其次下载istio(这一步有可能需要上网)
  1. curl -L https://istio.io/downloadIstio | sh -
  2. cd istio-*
  3. sudo ln -s $PWD/istioctl /usr/local/bin/istioctl
复制代码
验证兼容性
  1. istioctl x precheck
复制代码
开始安装
  1. istioctl install --set profile=default -y
复制代码
由于镜像仓库没法直接使用,所以需要一些特殊的方法,具体可以看这篇文章: 快速拉取docker镜像
需要的镜像有:
  1. docker.io/istio/pilot:1.28.2
  2. docker.io/istio/proxyv2:1.28.2
复制代码
安装完成:
  1. ▶ kubectl -n istio-system get pod
  2. NAME                                    READY   STATUS    RESTARTS   AGE
  3. istio-ingressgateway-865c448856-qs8s2   1/1     Running   0          8s
  4. istiod-86c75775bb-j7qbg                 1/1     Running   0          12s
复制代码
安装完成,要从哪儿开始呢?
istio的自动注入
  1. kubectl label namespace default istio-injection=enabled
复制代码
同之前envoy一样,给namespace打上标签之后,重启服务即可
  1. kubectl rollout restart deploy nginx-test
复制代码
重启之后sidecar已经注入进去了,我们来观察一下istio注入到底做了什么事情
先describe看看events
  1. Events:
  2.   Type    Reason     Age   From               Message
  3.   ----    ------     ----  ----               -------
  4.   Normal  Scheduled  8s    default-scheduler  Successfully assigned default/nginx-test-6f855b9bb9-9phsv to wilson
  5.   Normal  Pulled     8s    kubelet            Container image "docker.io/istio/proxyv2:1.28.2" already present on machine
  6.   Normal  Created    8s    kubelet            Created container: istio-init
  7.   Normal  Started    8s    kubelet            Started container istio-init
  8.   Normal  Pulled     8s    kubelet            Container image "docker.io/istio/proxyv2:1.28.2" already present on machine
  9.   Normal  Created    8s    kubelet            Created container: istio-proxy
  10.   Normal  Started    8s    kubelet            Started container istio-proxy
  11.   Normal  Pulled     6s    kubelet            Container image "registry.cn-beijing.aliyuncs.com/wilsonchai/nginx:latest" already present on machine
  12.   Normal  Created    6s    kubelet            Created container: nginx-test
  13.   Normal  Started    5s    kubelet            Started container nginx-test
复制代码
1个initContainer,1个业务container和1个sidecar
其中initContainer:
  1. Init Containers:
  2.   istio-init:
  3.     Container ID:  containerd://2bf56cd37703d82a2a43e94e8c8d683ed66b0afe22bf7148a597d67b89a727a8
  4.     Image:         docker.io/istio/proxyv2:1.28.2
  5.     Image ID:      docker.m.daocloud.io/istio/proxyv2@sha256:39065152d6bd3e7fbf6bb04be43c7a8bbd16b5c7181c84e3d78fa164a945ae7f
  6.     Port:          <none>
  7.     Host Port:     <none>
  8.     Args:
  9.       istio-iptables
  10.       -p
  11.       15001
  12.       -z
  13.       15006
  14.       -u
  15.       1337
  16.       -m
  17.       REDIRECT
  18.       -i
  19.       *
  20.       -x
  21.       -b
  22.       *
  23.       -d
  24.       15090,15021,15020
  25.       --log_output_level=default:info
  26. ...
复制代码
和之前envoy中劫持流量的做法一样,istio依然是使用iptables将端口流量导入到代理之中处理
尝试访问一下:
  1. ▶ curl 10.22.12.178:30785/test
  2. i am backend in backend-6d76f54494-g6srz
复制代码
成功,再次查看istio-proxy日志。空的?为了调试方便,将其打开并且输出至控制台
  1. kubectl -n istio-system edit cm istio
  2. apiVersion: v1
  3. data:
  4.   mesh: |-
  5.     accessLogFile: /dev/stdout
  6.   ...
复制代码
至此,istio的第一个功能探索完毕,自动注入sidecar container并且完成了流量劫持
Upgrade Required 426 的问题

当前的架构是左图,现在要前进到右图
1.png

其实就是在backend注入istio-proxy,直接重启就好
  1. ▶ kubectl get pod -owide
  2. NAME                          READY   STATUS        RESTARTS   AGE     IP            NODE     NOMINATED NODE   READINESS GATES
  3. backend-5d4d7b598c-f7852      2/2     Running       0          13s     10.244.0.49   wilson   <none>           <none>
  4. nginx-test-6f855b9bb9-9phsv   2/2     Running       0          58m     10.244.0.48   wilson   <none>           <none>
复制代码
注入完成,测试一下
  1. ▶ curl 10.22.12.178:30785/test
  2. Upgrade Required
复制代码
  1. ▶ kubectl logs -f -l app=nginx-test -c istio-proxy
  2. [2026-01-26T07:54:42.977Z] "GET /test HTTP/1.1" 426 - upstream=10.244.0.48:80 duration=6ms route=default
  3. [2026-01-26T07:54:42.978Z] "- - -" 0 - upstream=10.105.148.194:10000 duration=9ms route=-
复制代码
在nginx注入istio-proxy,backend没有注入的时候并没有报错。而一旦nginx与backend都注入的时候就会出现Upgrade Required (426)错误,Nginx Sidecar 发现目标(Backend)是一个纯文本服务,它会回退到“透明代理”模式,简单地把 Nginx 发出的流量透传出去
Nginx Sidecar 发现目标也有 Sidecar,它会尝试建立一个高度优化的、基于 mTLS 的隧道(关于mTLS后面会详细介绍)。如果此时 Nginx 发出的请求头(比如缺少 Host 字段,或者使用了 HTTP/1.0)不符合 Envoy 对这种隧道
协议的预期,Envoy 可能会向 Nginx 发送一个特殊的响应,或者 Nginx 在尝试通过这种隧道通信时,因为某些 Header 冲突(如 Connection: close)自发产生了 426 错误
想要解决这个问题有两种方法
改造nginx中加入标记
  1.         location /test {
  2.             proxy_http_version 1.1; # 必须添加这一行
  3.             proxy_set_header Host $host; # 这一行也是必须的
  4.             proxy_pass http://backend_ups;
  5.         }
复制代码
Nginx 的 proxy_pass 默认使用 HTTP/1.0。在 Istio 环境中,HTTP/1.0 不支持长连接(Keep-Alive)以及一些现代的协议协商,这与 Istio Sidecar(Envoy)默认的 L7 代理行为冲突,Istio 需要 HTTP/1.1 来支持复杂连接管理问题
改造backend service

如果nginx改造有难度,那也可以尝试改造backend-service
  1. apiVersion: v1
  2. kind: Service
  3. metadata:
  4.   name: backend-service
  5.   namespace: default
  6. spec:
  7.   ports:
  8.   - name: tcp-80 # 原为 http-80 改为 tcp-80
  9.     port: 10000
  10.     protocol: TCP
  11.     targetPort: 10000
  12.   selector:
  13.     app: backend
复制代码
Istio 只有在识别到流量是 HTTP 时才会进行深度的协议检查和转换。如果你把这个服务声明为 TCP,Istio 就会将其视为原始字节流进行透传,不再关心它是 HTTP/1.0 还是 1.1。优点就是彻底解决 426 问题,无需改 Nginx。
缺点则是你会失去 Istio 针对该服务的 HTTP 监控指标(如请求数、4xx/5xx 统计)、分布式追踪以及基于路径的路由功能
http 1.0 与 http 1.1

这里再简单介绍一下两个协议版本的区别

  • 连接管理(最显著的区别)

    • HTTP 1.0:短连接 (Short-lived),默认情况下,客户端每发起一个请求,都要与服务器建立一次 TCP 三次握手。请求结束并收到响应后,TCP 连接立即关闭。如果页面有 10 张图片,浏览器就要建立 10 次 TCP 连接。这带来了极高的延迟和资源开销。
    • HTTP 1.1:持久连接 (Persistent Connection / Keep-Alive)。默认开启 Connection: keep-alive。一个 TCP 连接可以被多个请求复用。只有在明确声明 Connection: close 或连接超时后才会关闭。
    • 在 Istio 中: Envoy 极度依赖持久连接来维持高性能的 Sidecar 间隧道。HTTP 1.0 的频繁断开会让 Envoy 感到“压力山大”,甚至认为这是一种非标准的协议行为。

  • Host Header

    • HTTP 1.0:人们认为一个 IP 对应一个网站,所以请求头里不需要带域名信息。
    • HTTP 1.1:随着虚拟主机(一个 IP 跑多个网站)的流行,HTTP 1.1 规定请求头必须包含 Host 字段。
    • 在 K8s/Istio 中: Istio 的路由决策、Service 的匹配完全依赖 Host 头。这也是为什么 Nginx 使用 HTTP 1.0 转发时,如果不手动补全 Host 头,后端往往会返回 404 或协议错误。

以上是istio必须要求HTTP 1.1最主要的两个因素,当然还有其他非常重要的区别
特性HTTP 1.0HTTP 1.1连接模型默认短连接,每次请求新开 TCP默认持久连接 (Keep-Alive),复用 TCPHost 头部可选 (导致无法支持虚拟主机)必须 (支持一 IP 多域名)流水线 (Pipelining)不支持支持 (但在实际应用中受限)断点续传不支持支持 (通过 Range 头部)缓存控制简单 (Expires)复杂且强大 (Cache-Control, ETag)默认协议版本许多旧软件(如 Nginx proxy)的默认值现代 Web 应用的基石标准小结

本章内容算是一个开胃小菜,成功安装了istio,并且解决了一个非常常见的426问题,至于怎么把之前在envoy的那些最佳实践搬迁到istio,那就是后面的内容了,敬请期待
后记

如果整个namespace都已经有了注入标签istio-injection=enabled,但是某个deployment不想让istio注入
  1. kubectl patch deployment nginx -p '{"spec":{"template":{"metadata":{"annotations":{"sidecar.istio.io/inject":"false"}}}}}'
复制代码
联系我


  • 联系我,做深入的交流
2.bmp

至此,本文结束
在下才疏学浅,有撒汤漏水的,请各位不吝赐教...

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

相关推荐

您需要登录后才可以回帖 登录 | 立即注册