记一次容器环境下出现 Address not available

作者:郑明泉、余凯

困惑的源地址

pod 创建后一段时间一直是正常运行,突然有一天发现没有新的连接创建了,业务上是通过 pod A 访问 svc B 的 svc name 的方式,进入 pod 手动去 wget 一下,发现报错了 Address not available,为何会报错这个呢?

大概示例图如下:

在这里插入图片描述

为什么会出现 Address not available,是什么地址不可用,查了很多资料,根据 POSIX(Portable Operating System Interface for UNIX)标准的错误定义中找到了相关的定义,同样说的还不是很清楚。

错误代码参考连接:[errno.3 [ 1] ]

EADDRNOTAVAIL               Address not available (POSIX.1-2001).

容易被忽视的内核参数

通过 netstat -an 查看到连接 svc 的地址,其中 estab 状态的连接数,已经到达了可用的随机端口数量阈值,无法在新建连接了。

在这里插入图片描述

最后通过修改了内核参数随机端口 net.ipv4.ip_local_port_range 端口范围才得以解决的。

我们可以知道 Linux 的内核定义的随机端口 32768 ~ 60999,可能在业务设计场景中,比较容易被忽略的,我们都知道,每一个 TCP 连接都是由四元组(源 IP,源端口,目的 IP,目的端口)构成的,只要四元组中其中一个元组发生了变化,就可以创建一个 TCP 连接的。当一个 POD 要访问一个固定的目的 IP + 目的端口的时候,那么每一个 TCP 连接的变量就只剩下源端口是随机的了,所以如果在需求就是需要创建大量长连接的话,要么就调大内核随机端口,要么就调整业务。

相关内核参考连接:[ip-sysctl.txt [ 2] ]

ip_local_port_range - 2 INTEGERSDefines the local port range that is used by TCP and UDP tochoose the local port. The first number is the first, thesecond the last local port number.If possible, it is better these numbers have different parity(one even and one odd value).Must be greater than or equal to ip_unprivileged_port_start.The default values are 32768 and 60999 respectively.

同样的问题还可能出现什么类型的报错呢?

手动调小了 net.ipv4.ip_local_port_range,之后进行复现。

同样的问题,分别尝试了 curl,nc,wget 命令,报错都不一样,这就犯难了。

难道就不能统一一下吗?

  • curl: (7) Couldn’t connect to server
  • nc: bind: Address in use
  • wget: can’t connect to remote host (1.1.1.1): Address not available

在这里插入图片描述

那么就通过 strace 命令进程分析一下看看,跟踪指定系统调用名称 它们都会创建 socket(), 然后发现 wget/curl 命令是通过 connect() 函数,而 nc 命令先是是通过 bind() 函数调用, 如果报错就不会继续调用 connect() 函数了。

在这里插入图片描述

如图,通过对 B/S 架构的分析如下,connect() 是在客户端创建 socket 后建立的。

在这里插入图片描述

引发思考

为什么 wget/curl 同样调用的是 connect() 函数报错的,为何报错还是不一样的?

  • 每一个客户端程序都会有自定义的 errorcode,在同样的 connect() 函数报错后 ,wget 是直接输出了 POSIX 标准的错误定义 Address not available,而 curl 会输出自己的定义错误码和对应的提示信息 curl: (7) Couldn’t connect to server,错误代码是 7,curl 的报错定义在 lib/strerror.c。

在这里插入图片描述

在这里插入图片描述

为什么 connect() 函数和 bind() 函数报错不一样?

  • 函数不同,错误的定义也就不同,从 POSIX 标准的错误定义都能找到。
EADDRINUSE               Address already in use (POSIX.1-2001).        
EADDRNOTAVAIL               Address not available (POSIX.1-2001).

是不是所有情况下都是这样输出呢?

那么直接找了一台 Centos7.9 的系统,安装 curl 、wget、 nc 等工具,同样改小端口范围的情况下会出现如下报错 Cannot assign requested address,从这里可以得知某些镜像(alpine、busybox) 里,使用相同的命令工具对相同的情况下报错会不同。因为这些镜像里可能为了缩小整个镜像大小,对于一些基础命令都会选择 busybox 工具箱(上面的 wget 和 nc 就来自于 busybox 工具箱里的,参考 busybox 文档:Busybox Command Help [ 3] )来使用,所以就造成在问题定位方面困扰了。

Linux 系统中用于包含与错误码相关的定义:/usr/include/asm-generic/errno.h

在这里插入图片描述

#define  EADDRNOTAVAIL  99  /* Cannot assign requested address */

容器环境下,端口配置最佳实践

可修改范围

理论上来是 0~65535 都能使用, 但是 0~1023 是特权端口,已经预留给一下标准服务,如 HTTP:80,SSH:22 等,只能特权用户使用,同时也避免未授权的用户通过流量特征攻击等所以建议端口调大的话可以将随机端口范围限制在 1024-65535 之间。

如何正确配置 Pod 源端口

普通 Pod 源端口修改方法

从 kubernetes 社区得知可以通过安全上下文修改 securityContext [ 4] ,还有可以通过 initContainers 容器给特权模式 mount -o remount rw /proc/sys 的方式修改,此修改方式只会在 pod 的网络命名空间中生效。

  • securityContext
...
securityContext:sysctls:       - name: net.ipv4.ip_local_port_range           value: 1024 65535
  • initContainers
      initContainers:- command:- /bin/sh- '-c'- |sysctl -w net.core.somaxconn=65535sysctl -w net.ipv4.ip_local_port_range="1024 65535"securityContext:privileged: true
...

hostnetwork 模式 pod 修改注意事项

1.22+ 集群以上就不建议修改 net.ipv4.ip_local_port_range,因为这会和 ServiceNodePortRange 产生冲突。

Kubernetes 的 ServiceNodePortRange 默认是 30000~32767,Kubernetes 1.22 及以后的版本,去除了 kube-proxy 监听 NodePort 的逻辑,如果有监听的话,应用程序在选用随机端口的时候,会避开这些监听中的端口。如果 net.ipv4.ip_local_port_range 的范围和 ServiceNodePortRange 存在重叠,由于去掉了监听 NodePort 的逻辑,应用程序在选用随机端口的时候就可能选中重叠部分,比如 30000~32767,在当 NodePort 与内核 net.ipv4.ip_local_port_range 范围有冲突的情况下,可能会导致偶发的 TCP 无法连接的情况,可能导致健康检查失败、业务访问异常等问题。更多信息,请参见 Kubernetes 社区 PR [ 5]

大量创建 svc 的时候减少创建监听的步骤只是提交 ipvs/iptables 规则,这样可以优化连接性能 。另一个就解决某些场景下出现大量的 CLOSE_WAIT 占用 TCP 连接等问题。在 1.22 版本之后就去掉了 PortOpener 逻辑。

kubernetes/pkg/proxy/iptables/proxier.go

Line 1304 in f98f27b [ 6]

1304        proxier.openPort(lp, replacementPortsMap)

在这里插入图片描述

具体是如何冲突的呢?测试环境是 k8s 1.22.10,kube-proxy 网络模式 ipvs。以 kubelet 健康检查为例,调整了节点的内核参数 net.ipv4.ip_local_port_range 为1 024~65535。

在这里插入图片描述

部署 tcpdump 抓包,抓到有健康检查失败的事件后,停止抓包。

看到 kubelet 是用节点 IP(192.168.66.27)+随机端口 32582 向 pod 发起了 TCP 握手 podIP(192.168.66.65)+80,但是 pod 在 TCP 握手时回 SYN ACK 给 kubelet 的时候,目标端口是 32582,却一直在重传。因为这个随机端口刚好是某一个服务的nodeport,所以优先被 IPVS 拦截给规则后端的服务,但这个后端服务 (192.168.66.9) 并没有发起和 podIP(192.168.66.65)TCP 建连,所以后端服务 (192.168.66.9) 直接是丢弃的。那么 kubelet 就不会收到 SYN ACK 回应,TCP 无法建联,所以导致健康检查失败。

这个报文看 kubelet 发起 TCP 握手,pod 回 syn ack 的时候一直重传。

在这里插入图片描述

实际是发送到了 32582 这个 svc 的后端 pod 了,直接是丢弃。

在这里插入图片描述
在这里插入图片描述

增加前置判断

所以 hostnework 可以加上一个判断,通过 initContainers 容器修改的时候,如果 podIP 和 hostIP 不相等才修改 net.ipv4.ip_local_port_range 参数,避免误操作导致修改节点的内核参数。

      initContainers:- command:- /bin/sh- '-c'- |if [ "$POD_IP" != "$HOST_IP" ]; thenmount -o remount rw /proc/syssysctl -w net.ipv4.ip_local_port_range="1024 65535"fienv:- name: POD_IPvalueFrom:fieldRef:apiVersion: v1fieldPath: status.podIP- name: HOST_IPvalueFrom:fieldRef:apiVersion: v1fieldPath: status.hostIPsecurityContext:privileged: true
...

如何正确配置 NodePort 范围

在 Kubernetes中,APIServer 提供了 ServiceNodePortRange 参数(命令行参数 --service-node-port-range),该参数是用于限制 NodePort 或 LoadBalancer 类型的 Service 在节点上所监听的 NodePort 端口范围,该参数默认值为 30000~32767。在 ACK Pro 集群中,您可以通过自定义 Pro 集群的管控面参数修改该端口范围。具体操作,请参见自定义 ACK Pro 集群的管控面参数 [ 7]

在这里插入图片描述
在这里插入图片描述

  • 在修改 NodePort 端口范围时必须十分谨慎。务必保证 NodePort 端口范围与集群节点上 Linux 内核提供的 net.ipv4.ip_local_port_range 参数中的端口范围不冲突。该内核参数 ip_local_port_range 控制了 Linux 系统上任意应用程序可以使用的本地端口号范围。ip_local_port_range 的默认值为 32768~60999,Nodeport 默认值为 30000~32767。
  • ACK 集群在默认配置情况下,ServiceNodePortRange 参数和 ip_local_port_range 参数不会产生冲突。如果您此前为了提升端口数量限制调整了这两个参数中任意一个,导致两者范围出现重合,则可能会产生节点上的偶发网络异常,严重时会导致业务健康检查失败、集群节点离线等。建议您恢复默认值或同时调整两个端口范围到完全不重合。
  • 调整端口范围后,集群中可能存在部分 NodePort 或 LoadBalancer 类型的 Service 仍在使用 ip_local_port_range 参数端口范围内的端口作为 NodePort。此时您需要对这部分 Service 进行重新配置以避免冲突,可通过 kubectl edit 的方式直接将 spec.ports.nodePort 字段的值更改为未被占用的 NodePort。

相关链接:

[1] errno.3

https://man7.org/linux/man-pages/man3/errno.3.html

[2] ip-sysctl.txt

https://www.kernel.org/doc/Documentation/networking/ip-sysctl.txt

[3] Busybox Command Help

https://www.busybox.net/downloads/BusyBox.html

[4] securityContext

https://kubernetes.io/docs/tasks/administer-cluster/sysctl-cluster/

[5] Kubernetes社区PR

https://github.com/kubernetes/kubernetes/pull/108888

[6] f98f27b

https://github.com/kubernetes/kubernetes/blob/f98f27bc2f318add77118906f7595abab7ab5200/pkg/proxy/iptables/proxier.go#L1304

[7] 自定义ACK Pro集群的管控面参数

https://help.aliyun.com/zh/ack/ack-managed-and-ack-dedicated/user-guide/customize-ack-pro-control-plane-component-parameters

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/7389.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

jar 更新 jar包内的 class,以及如何修改class

一、提取Jar 内文件 #提取jar内的配置文件jar -xvf a.jar META-INF\plugin.xml-已解压: META-INF/plugin.xml#提取jar内的class文件, 提示:反编译为java文件,修改后再使用javac xxx.java编译为class,jar -xvf a.jar io.config.**…

单例模式类设计|什么是饿汉模式和懒汉模式

前言 那么这里博主先安利一些干货满满的专栏了! 首先是博主的高质量博客的汇总,这个专栏里面的博客,都是博主最最用心写的一部分,干货满满,希望对大家有帮助。 高质量干货博客汇总https://blog.csdn.net/yu_cblog/c…

在Vue-Element中引入jQuery的方法

一、在终端窗口执行安装命令 npm install jquery --save执行完后,npm会自动在package.json中加上jquery 二、在main.js中引入(或者在需要使用的页面中引入即可) import $ from jquery三、使用jquery

【Ansible 自动化配置管理实践】01、Ansible 快速入门

目录 一、Ansible 快速入门 1.1 什么是 Ansible ​1.2 Ansible 主要功能 1.3 Ansible 的特点 1.4 Ansible 基础架构 二、Ansible 安装与配置 2.1 Ansible 安装 2.2 确认安装 三、Ansible 配置解读 3.1 Ansible 配置路径 3.2 Ansible 主配置文件 3.3 Ansi…

Spring系列一:spring的安装与使用

文章目录 💞 官方资料🍊Spring5下载🍊文档介绍 💞Spring5🍊内容介绍🍊重要概念 💞快速入门🍊Spring操作演示🍊类加载路径🍊Debug配置🍊Spring容器…

《Docker资源限制和调度策略:性能优化与资源管理,打造高效稳定的容器环境》

🌷🍁 博主 libin9iOak带您 Go to New World.✨🍁 🦄 个人主页——libin9iOak的博客🎐 🐳 《面试题大全》 文章图文并茂🦕生动形象🦖简单易学!欢迎大家来踩踩~&#x1f33…

【Nodejs】Puppeteer\爬虫实践

puppeteer 文档:puppeteer.js中文文档|puppeteerjs中文网|puppeteer爬虫教程 Puppeteer本身依赖6.4以上的Node,但是为了异步超级好用的async/await,推荐使用7.6版本以上的Node。另外headless Chrome本身对服务器依赖的库的版本要求比较高,c…

高速数据采集专家-FMC140【产品手册】

FMC140是一款具有缓冲模拟输入的低功耗、12位、双通道(5.2GSPS/通道)、单通道10.4GSPS、射频采样ADC模块,该板卡为FMC标准,符合VITA57.1规范,该模块可以作为一个理想的IO单元耦合至FPGA前端,8通道的JESD204…

【jenkins】idea+jenkins+docker+dockerfile+compose流水线部署java应用

目录 整体架构 环境准备 安装docker以及docker-compose jenkins安裝 maven安装 portainer面板安装 sonarqube安装 在项目中增加dockerfile和compose.yml脚本 Dockerfile脚本内容 compose.yml脚本内容 jenkins安装必要插件 jenkins增加流水线任务 增加pipeline任务j…

iptables 防火墙

防火墙:隔离功能 部署在网络边缘或者主机边缘,在工作中,防火墙的主要作用,决定哪些数据可以被外网使用,以及哪些数据可以进入内网访问 主要工作在网络层 安全技术 1.入侵检测系统:检测出威胁&#xff0…

RISCV -3 RV32I/RV64I基本整型指令集

RISCV -3 RV32I/RV64I基本整型指令集 1 RV32I Base Integer Instruction Set1.1 Programmers’ Model for Base Integer ISA1.2 Base Instruction Formats1.3 Immediate Encoding Variants1.4 Integer Computational Instructions1.4.1 Integer Register-Immediate Instruction…

Windows 2012 R2 编辑ini文本遇到的编码问题

在编辑服务端配置文件时,发现对于ini文本文件: 需注意点一:如果另存为UTF-8保存的实际上格式是UTF-8-BOM编码格式; 但是两种格式是存在差异的: 因此造成在使用C#调用系统DLL读取文件时并未报错,但是当使用…

MySQL 数据库约束

目录 一、数据库约束 1、约束类型 二、NULL 约束 三、unique 约束 四、default 约束 五、primary key 约束 自增主键 六、foreign key 外键约束 七、check 约束 一、数据库约束 我们使用数据库来存储数据,一般是希望这里存储的数据是靠谱的,…

【梦辛工作室】IF判断优化、责任链模式 IfChain

大家好哇,我是梦辛工作室的灵,在最近的开发中,有许多需要判断的分支处理,且处理内容较多且复杂,代码就容易越写越复杂,导致后期无法继续更新跌打,然后基于这个环境,我用责任链模式写…

Stable Diffusion在各种显卡上的加速方式测试,最高可以提速211.2%

Stable Diffusion是一种基于扩散模型的图像生成技术,能够从文本生成高质量的图像,适用于CG,插图和高分辨率壁纸等领域。 但是它计算过程复杂,使得它的生成速度较慢。所以研究人员就创造了各种提高其速度的方式,比如Xf…

计算机视觉(二)图像特征提取

文章目录 颜色特征量化颜色直方图适用颜色空间:RGB、HSV等颜色空间操作 几何特征边缘 Edge边缘定义边缘提取 基于关键点的特征描述子引入几何特征:关键点几何特征:Harris角点FAST角点检测几何特征:斑点局部特征:SIFT预…

idea中Easy Code模版配置

首先找到模版位置 找到使用的模版,我用的是MybatisPlus-H,这是我新建的一个模版 controller.java.vm模版 ##导入宏定义 $!{define.vm}##设置表后缀(宏定义) #setTableSuffix("Controller")##保存文件(宏定义&#xff…

qemu搭建arm环境以及文件共享

几乎完全参照该文章 使用QEMU搭建ARM64实验环境 - 简书 ubuntu 14.04,linux3.16, busybox-1.31.0 arm-linux-gnueabi-gcc -v linux3.16以及busybox下载安装可参考链接 Ubuntu14.04安装qemu,运行linux-3.16gdb调试_qemu 安装 ubuntu 14_这个我…

【数学建模】相关是一个距离指标吗?

一、说明 本文探讨最平凡的数学模型--距离模型。我们知道,任何数学模型如果是个距离模型,那么它是:放心的、自动的、不加任意条件的指标项目。然而另一些度量参数不是距离空间,因此,使用起来必须外加若干条件&#xff…

一款好用的思维导图软件drawio

最近需要画思维导图,结果发现既然被人用来收费了。所以记录一下,免得大家上当。 首先说明,这个东东在github上是免费开源的,收费的是一些不法分子搞得。下面是收费版本得界面。 开源地址: https://github.com/jgraph…