惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

L
LINUX DO - 热门话题
Stack Overflow Blog
Stack Overflow Blog
B
Blog
WordPress大学
WordPress大学
Project Zero
Project Zero
P
Palo Alto Networks Blog
阮一峰的网络日志
阮一峰的网络日志
博客园 - 司徒正美
有赞技术团队
有赞技术团队
S
SegmentFault 最新的问题
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
小众软件
小众软件
T
Tailwind CSS Blog
Forbes - Security
Forbes - Security
F
Full Disclosure
SecWiki News
SecWiki News
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
Hacker News: Ask HN
Hacker News: Ask HN
C
Check Point Blog
Microsoft Security Blog
Microsoft Security Blog
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
F
Fortinet All Blogs
Cisco Talos Blog
Cisco Talos Blog
G
Google Developers Blog
J
Java Code Geeks
Google DeepMind News
Google DeepMind News
人人都是产品经理
人人都是产品经理
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
Recorded Future
Recorded Future
O
OpenAI News
Spread Privacy
Spread Privacy
MongoDB | Blog
MongoDB | Blog
H
Hackread – Cybersecurity News, Data Breaches, AI and More
C
Cybersecurity and Infrastructure Security Agency CISA
S
Securelist
V
Vulnerabilities – Threatpost
Y
Y Combinator Blog
IT之家
IT之家
U
Unit 42
腾讯CDC
S
Security Affairs
C
Cisco Blogs
Schneier on Security
Schneier on Security
The Last Watchdog
The Last Watchdog
B
Blog RSS Feed
宝玉的分享
宝玉的分享
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
S
Security @ Cisco Blogs
Cyberwarzone
Cyberwarzone
T
The Blog of Author Tim Ferriss

山山仙人博客

自己动手实现NAS公网访问 我的2024-2025 个人养老金年化收益计算 Apple Container实践 Mermaid 语法概要 组建WireGuard网络 使用GitHub存储Helm包 详解Nginx获取客户端真实IP 生如夏花——与技术人的精神远游 我的2022-2023 Gradle打包工具入门 基于阿里云RAM+ACK托管版集群的RBAC授权 服务网格和Istio初识-续 服务网格和Istio初识 2021总结与公众号文章回顾 Golang与非对称加密 Ack集群Terway网络场景下的vSwitch扩容 Golang与对称加密 Golang与散列算法
Ack集群Pod独占EIP实践
2024-04-29 · via 山山仙人博客

引入一个实际生产环境案例,介绍在阿里云Ack集群中如何实现Pod独占公网EIP

某线上应用部署在ack集群内,用于根据用户定义的http请求项配置,周期性检查http接口的请求响应状态,接口地址为内网或公网,当接口地址为公网时,频繁出现请求超时的报警错误。经过排查发现,在公网请求发生超时的时刻,集群vpc NAT带宽达到上限200Mbps,也就是25MB/s

20240429-01

分析:由于集群占用vpcvpc内所有ip(node和pod的ip)都属于vpc内各子网地址,这些地址出公网的请求共用vpc绑定的公网NAT,在某时刻子网ip请求公网使用的EIP是随机的,无法控制,会产生和其他ip同时请求公网使用同一个EIP的情况,由此发生了带宽内拥挤,超限的情况,因此上述超时报警其实是客户端带宽不够产生的误报

为了避免发生上述情况,解决办法是避免这些特定的pod请求公网时和其他ip发生公网带宽的争抢,走独立的公网出口,有以下两种方案:

  • 方案一

将这些pod调度到特定的子网nodenodeippodip会使用特定的子网,这个特定的子网由于在特定的vSwitch虚拟交换机下,因此可以为这个子网单独指定路由条目,也就是将请求公网地址的请求的下一跳路由到特定的公网NAT,特定的公网NAT使用特定的EIP且不和其他子网共用

  • 方案二

ack集群的网络使用的是阿里云Terway,在此前提下,阿里云提供了为Terway网络中的Pod挂载独立的公网EIP的解决方案,具体可以查看文档说明,简单来说就是阿里云提供了集群内的控制器,实现了通过k8s原生的声明式配置,调用EIP产品相关api动态为pod绑定EIP的功能

方案一,改动较大,需要将pod调度到特定的node上,且需要人工维护路由条目,维护性较差; 方案二,更为直接,在安装控制器插件后,通过给pod添加特定注解实现目的,主要分为两种方式:

  • 一种是根据声明式配置动态随机购买EIP

apiVersion: apps/v1

kind: Deployment

metadata:

name: example

labels:

app: example

spec:

replicas: 1

selector:

matchLabels:

app: example

template:

metadata:

labels:

app: example

annotations:

k8s.aliyun.com/pod-with-eip: "true" # 自动创建并绑定EIP

k8s.aliyun.com/eip-bandwidth: "200" # EIP峰值带宽

k8s.aliyun.com/eip-internet-charge-type: "PayByTraffic" # EIP的计量方式

k8s.aliyun.com/eip-instance-charge-type: "PostPaid" # EIP的计费方式

k8s.aliyun.com/eip-name: "app-eip" # EIP名称

k8s.aliyun.com/eip-description: "app-eip" # EIP描述

  • 一种是先购买EIP,pod注解中声明EIP的id

apiVersion: apps/v1

kind: Deployment

metadata:

name: example

labels:

app: example

spec:

replicas: 1

selector:

matchLabels:

app: example

template:

metadata:

labels:

app: example

annotations:

k8s.aliyun.com/pod-eip-instanceid: eip-2zeXXXXXx # EIP ID

配置RAM策略并安装插件

按照文档操作,配置挂载EIP所需的RAM权限 安装插件ack-extend-network-controller,安装时启用插件pod eip的能力,一键安装即可

20240429-02

购买EIP

由于业务目前只有1pod,为了后续排查方便,选择通过先购买EIP再根据EIP id绑定的方式 购买EIP,按量付费,带宽上限为200Mbps

20240429-03

为pod添加注解

deploymentyaml中为pod添加注解,根据EIP id绑定这个EIP即可

spec:

template:

metadata:

annotations:

k8s.aliyun.com/pod-eip-instanceid: eip-xxx

绑定后效果

  • 集群cr

控制器会自动创建一个和pod名称相同的PodEIPcr,从这个crstatus中可以看到和上面购买的EIP相关的信息

~ kubectl get pods -o wide|grep app

app-79dcf755fb-ks2ld 1/1 Running 0 47h 10.245.36.4 ack-010245035222packets-spot <none> 1/1

~ kubectl get podeips app-79dcf755fb-ks2ld -o yaml

apiVersion: alibabacloud.com/v1beta1

kind: PodEIP

metadata:

creationTimestamp: "2024-04-01T07:55:46Z"

finalizers:

- podeip-controller.alibabacloud.com/finalizer

generation: 1

name: app-79dcf755fb-ks2ld

namespace: dev

resourceVersion: "2389078403"

uid: 292773d3-80b4-4c88-b0ef-17f011a1530e

spec:

allocationID: eip-xxxxx

allocationType:

releaseStrategy: Follow

type: Static

status:

eipAddress: 101.xxx.xxx.5

internetChargeType: PayByTraffic

isp: BGP

name: app独享

networkInterfaceID: eni-2zexxxxxxxqvrrpxxx

podLastSeen: "2024-04-01T07:39:39Z"

privateIPAddress: 10.xxx.36.4

resourceGroupID: rg-xxxxx5afyhf3xky

status: InUse

  • EIP绑定情况,与从集群查看cr得到的状态一致

20240429-04

其他说明

以上实现了pod绑定特定EIP的功能,在此条件下,pod请求公网时会固定为此eip出公网,为了保障配置的稳定,经过测试,上面提到此业务pod只有一个副本,且通过deployment管理,属于无状态应用,只做上面为pod添加注解的方式会有以下问题

如何控制当pod状态变为ready后才绑定EIP?

控制器会在Pod IP分配后,为Pod配置EIP地址,Pod Ready状态可能早于EIP绑定成功时间。解决办法是为pod添加就绪前的检测

  • 一种方式是为Pod配置Readiness gates

kind: Pod

...

spec:

readinessGates:

- conditionType: "k8s.aliyun.com/eip"

...

status:

conditions:

- lastProbeTime: "2022-12-12T03:45:48Z"

lastTransitionTime: "2022-12-12T03:45:48Z"

reason: Associate eip succeed

status: "True"type: k8s.aliyun.com/eip

...

  • 一种方式是为Pod配置init container,在init container中检查EIP是否已经分配成功

apiVersion: v1

kind: Pod

metadata:

name: example

annotations:

k8s.aliyun.com/pod-with-eip: "true"

spec:

containers:

- name: example

image: busybox:1.28

command: ['sh', '-c', 'echo The app is running! && sleep 3600']

initContainers:

- name: init

image: busybox:1.28

command: ['timeout', '-t' ,'60', 'sh','-c', "until grep -E '^k8s.aliyun.com\\/allocated-eipAddress=\\S?[0-9]+\\S?' /etc/podinfo/annotations; do echo waiting for annotations; sleep 2; done"]

volumeMounts:

- name: podinfo

mountPath: /etc/podinfo

volumes:

- name: podinfo

downwardAPI:

items:

- path: "labels"

fieldRef:

fieldPath: metadata.labels

- path: "annotations"

fieldRef:

fieldPath: metadata.annotations

如何控制pod更新时,EIP始终只绑定了一个pod?

pod如果发生了滚动更新,且pod在配置有探针的情况下,可以保障始终只有一个pod接收流量,但是无法保证EIP的正常绑定,因为发布过程中有两个pod同时绑定了这个EIP,新pod启动后,老的pod下线调用了解绑EIP的动作,EIP绑定是需要调用接口到vpc去绑定,只有绑定了这个EIP pod的后续探针才会ready。在新pod滚动更新的过程中,会重新绑定EIP,但是旧pod的回收,又会卸载绑定这个EIP

这里EIP当做了创建pod所需的基础资源,实际上EIP并不是pod运行所必须的,解决办法:

  • A. 修改控制器实现支持在pod滚动更新结束后才将新的pod ipEIP绑定(下述C可以避免此问题)

  • B. 将pod的滚动更新模式修改为销毁重建Recreate,这样会损失一定流量

  • C. 控制器支持有状态应用的pod在一定时间内发生更新后仍然使用之前的EIP,因此把poddeployment改为statefulset,并声明pod在更新过程中仍然使用之前的EIP即可(固定EIP可以保证Pod重建后依然使用之前的EIP地址。该策略可与自动分配EIP能力结合,用于有状态应用的固定EIP

annotations:

k8s.aliyun.com/pod-with-eip: "true"

k8s.aliyun.com/pod-eip-release-strategy: "10m"

结合现状,业务pod如果支持多副本模式,可以切换到statefulset并创建2个副本,有状态应用的滚动更新本身就是副本销毁和重新创建,在多副本的情况下不会有流量丢失。目前只有一个(暂不支持多副本模式),且可以接受在升级的过程中丢失一定的流量,在不改变原有的无状态应用属性的情况下,选择的解决办法为B

最终配置如下:

apiVersion: apps/v1

kind: Deployment

metadata:

name: app

spec:

strategy:

type: Recreate

template:

metadata:

annotations:

k8s.aliyun.com/pod-eip-instanceid: eip-XXXXXXXlus72fax

spec:

readinessGates:

- conditionType: "k8s.aliyun.com/eip"

pod绑定EIP后pod本身监听的端口是否也就通过EIP暴露?

pod由于没有通过NAT请求公网,是EIPPod IP(ecs 弹性辅助网卡)直接绑定,因此默认情况下,通过pod ip(vpc内网):端口可以直接访问到pod暴露的接口,通过eip(公网):端口也可以访问到,但是由于EIP绑定的是ecs的弹性辅助网卡,因此和ecs共用了一个安全组,ecs是集群node,只开放了集群子网间互通,因此这个问题已经规避