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

推荐订阅源

酷 壳 – CoolShell
酷 壳 – CoolShell
H
Hacker News: Front Page
P
Palo Alto Networks Blog
T
ThreatConnect
Apple Machine Learning Research
Apple Machine Learning Research
博客园_首页
T
True Tiger Recordings
P
Privacy & Cybersecurity Law Blog
B
Blog
IT之家
IT之家
Last Week in AI
Last Week in AI
F
Full Disclosure
Hacker News: Ask HN
Hacker News: Ask HN
C
Comments on: Blog
Microsoft Azure Blog
Microsoft Azure Blog
C
Cybersecurity and Infrastructure Security Agency CISA
Microsoft Security Blog
Microsoft Security Blog
博客园 - 【当耐特】
N
News and Events Feed by Topic
NISL@THU
NISL@THU
腾讯CDC
雷峰网
雷峰网
Security Latest
Security Latest
李成银的技术随笔
M
Microsoft Research Blog - Microsoft Research
L
LangChain Blog
L
Lohrmann on Cybersecurity
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
C
Check Point Blog
Y
Y Combinator Blog
Recent Announcements
Recent Announcements
博客园 - Franky
N
News | PayPal Newsroom
V
V2EX
A
About on SuperTechFans
The Register - Security
The Register - Security
月光博客
月光博客
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Google Online Security Blog
Google Online Security Blog
MyScale Blog
MyScale Blog
Cisco Talos Blog
Cisco Talos Blog
Vercel News
Vercel News
WordPress大学
WordPress大学
C
Cyber Attacks, Cyber Crime and Cyber Security
The Hacker News
The Hacker News
IntelliJ IDEA : IntelliJ IDEA – the Leading IDE for Professional Development in Java and Kotlin | The JetBrains Blog
IntelliJ IDEA : IntelliJ IDEA – the Leading IDE for Professional Development in Java and Kotlin | The JetBrains Blog
爱范儿
爱范儿
A
Arctic Wolf
L
LINUX DO - 最新话题
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More

博客园 - 衡子

Ubuntu24.04更改SSH端口 记录安装过程 - 衡子 Azure CLI创建管理员用户 创建VMSS中的instance 创建不带公网IP的VM Azure LSv3系列VM 自动挂载NVMe本地磁盘 Azure AD访问Azure Storage Azure Linux VM使用Managed Identity获取Key-vault的Secret Azure AD SSO with Google Cloud Identity 通过VM SWAP OS DISK升级VM 通过API获取Azure KeyVault Securet Azure Front Door添加自定义域名 VM间网络PPS和带宽测试 Azure获取access token的方法 VM间记录时延 Windows Terminal的一些配置 安装hping Azure解除不再使用Directory的关联 使用VSCode Remote Containers功能实现开发环境统一
Azure AKS容器网络详解
衡子 · 2021-11-13 · via 博客园 - 衡子

Azure的AKS是Azure托管的Kubernetes服务。AKS支持多种容器网络模式,可以很好的和Azure的VNET集成。AzureCNI增强版与其他云厂商的Kubernetes服务的容器网络方案相比有一定的优势,主要表现在:部署灵活、节省IP地址资源等。Azure的AKS容器网络实现有多种模式,包括:

  1. Kubenet
  2. Azure CNI
  3. Azure CNI 增强版

一 Kubenet模式

1 Kubenet实现方式

Kubenet是最基本的模式,Kubenet是最基本的模式,它使用 bridge 和host-local CNI 插件实现了基本的cbr0。

Kubenet主要有两个主要功能:

  1. 在K8s的worknode中创建cbr0的bridge,通过host-local实现container的IPAM的功能
  2. 通过ptp创建veth pair,一端放到container中,一端放到cbr0中

2 AKS Kubenet数据流

如下图中,两个Node,分别各有两个Pod,通过Kubenet创建cbr0,每个Pod通过Kubenet创建的veth pair连接到cbr0上,Node的eth0也挂载到cbr0上。具体Pod见通信流量走向如下:

  1. 同Node上Pod间通信,通过cbr0实现Pod间通讯。比如Node上,Pod1和Pod2的通讯,直接通过cbr0实现
  2. 跨Node的Pod间通信,需要在VNET中创建用户自定义路由(UDR),来实现每Node上Pod的路由。比如下图中,如果Pod1(10.0.0.1)和Pod3(10.0.1.1)进行通信,

3 AKS实现

A 创建VNET

首先创建相应的VNET:

az network vnet create -g whhk -n vnet01 \

--address-prefixes 10.0.0.0/16 -l eastus

az network vnet subnet create -g whhk -n vlan01 \

  --vnet-name vnet01 --address-prefixes 10.0.0.0/22

vnet_id=$(az network vnet show -g whhk -n vnet01 -o tsv --query id)

vlan_id=$(az network vnet subnet show -n vlan01 -g whhk \

  --vnet-name vnet01 -o tsv --query id)

创建Service Principal并授权:

az ad sp create-for-rbac -n whforaks --skip-assignment

appid=$(az ad sp list --display-name whforaks -o tsv --query "[0].appId")

az role assignment create --assignee $appid --scope $vnet_id --role "Network Contributor"

B 创建AKS

创建网络采用Kubenet的AKS:

az aks create \

  -g whhk \

  -n aks01 \

  -l eastus \

  --node-count 2 \

  --network-plugin kubenet \

  --service-cidr 172.16.1.0/24 \

  --dns-service-ip 172.16.1.10 \

  --pod-cidr 10.244.0.0/16 \

  --docker-bridge-address 172.17.0.1/16 \

  --vnet-subnet-id $vlan_id \

  --service-principal $appid \

  --client-secret $passwd

获取AKS管理权限:

az aks get-credentials -g whhk -n aks01

$ kubectl get node

NAME STATUS ROLES AGE VERSION

aks-nodepool1-52243381-vmss000000 Ready agent 4m54s v1.20.9

aks-nodepool1-52243381-vmss000001 Ready agent 5m40s v1.20.9

创建一个workload:

kubectl create deployment nginx --image nginx

kubectl scale deployment nginx --replicas=3

C 登录到Node上查看CNI配置

登录到一个node上:

nodename=$(kubectl get node \

  -o jsonpath='{.items[0].metadata.labels.kubernetes\.io\/hostname}')

kubectl debug node/$nodename -it \

  --image=mcr.microsoft.com/aks/fundamental/base-ubuntu:v0.0.11

查看网络配置情况,kubenet默认采用cbr0的bridge,地址分配了10.244.1.0/24的地址段给这个Node的pod使用:

cd /host/etc/cni/net.d/

# cat 10-containerd-net.conflist

{

  "cniVersion": "0.3.1",

  "name": "kubenet",

  "plugins": [{

    "type": "bridge",

    "bridge": "cbr0",

    "mtu": 1500,

    "addIf": "eth0",

    "isGateway": true,

    "ipMasq": false,

    "promiscMode": true,

    "hairpinMode": false,

    "ipam": {

      "type": "host-local",

      "subnet": "10.244.1.0/24",

      "routes": [{ "dst": "0.0.0.0/0" }]

      }

    },

  {

    "type": "portmap",

    "capabilities": {"portMappings": true},

    "externalSetMarkChain": "KUBE-MARK-MASQ"

  }]

}

D 采用Containerd工具crictl查看Node中的Pod

因为新版的AKS都采用containerd作为容器的runtime,我们安装containerd客户端crictl,由于是创建一个container进入的node,所以,要指定endpoint所在的位置/host/run/containerd/containerd.sock:

wget https://github.com/kubernetes-sigs/cri-tools/releases/download/v1.22.0/crictl-v1.22.0-linux-amd64.tar.gz

tar vxf crictl-v1.22.0-linux-amd64.tar.gz

cp crictl /usr/local/bin

#crictl -r unix:///host/run/containerd/containerd.sock ps

CONTAINER IMAGE CREATED STATE NAME ATTEMPT POD ID

eb53b4069ba54 81869ce15b0c7 3 minutes ago Running debugger 0 58009a9d2e180

22e1944b0c1a7 81869ce15b0c7 46 minutes ago Running debugger 0 421b2a77c8e3c

ade5453416e2f 87a94228f133e About an hour ago Running nginx 0 035488dda252d

0fac789b8c32b 87a94228f133e About an hour ago Running nginx 0 80e82d5d19e65

72bb25828d032 54b145bf08825 About an hour ago Running konnectivity-agent 0 e8d0f563161fb

a7c4e81f6250d e83e576296711 About an hour ago Running kube-proxy 0 f97a7109cbbeb

706dceab4bfae efd9c9d9e8376 About an hour ago Running azure-ip-masq-agent 0 dfdb927c75681

查看Pod信息:

# crictl -r unix:///host/run/containerd/containerd.sock pods

POD ID CREATED STATE NAME NAMESPACE ATTEMPT RUNTIME

58009a9d2e180 7 minutes ago Ready node-debugger-aks-nodepool1-52243381-vmss000000-r7cpt default 0

421b2a77c8e3c 50 minutes ago Ready node-debugger-aks-nodepool1-52243381-vmss000000-b9lgn default 0

035488dda252d About an hour ago Ready nginx-6799fc88d8-ltwhl default 0

80e82d5d19e65 About an hour ago Ready nginx-6799fc88d8-mr2q6 default 0

e8d0f563161fb About an hour ago Ready konnectivity-agent-7c8fdfddf4-xngd9 kube-system 0

dfdb927c75681 About an hour ago Ready azure-ip-masq-agent-k5gtp kube-system 0

f97a7109cbbeb About an hour ago Ready kube-proxy-6xznd kube-system 0

E 查看Pod内网络信息

进入到Pod内,查看IP和Mac地址:

# crictl -r unix:///host/run/containerd/containerd.sock exec \

-it ade5453416e2f sh

# ip a

1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000

  link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00

  inet 127.0.0.1/8 scope host lo

  valid_lft forever preferred_lft forever

  inet6 ::1/128 scope host

  valid_lft forever preferred_lft forever

3: eth0@if6: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default

  link/ether d6:12:5a:78:49:25 brd ff:ff:ff:ff:ff:ff link-netnsid 0

  inet 10.244.1.3/24 scope global eth0

  valid_lft forever preferred_lft forever

  inet6 fe80::d412:5aff:fe78:4925/64 scope link

  valid_lft forever preferred_lft forever

F Node上查看Bridge相关信息

再回到Node里查看bridge的mac表:

# brctl show

bridge name bridge id STP enabled interfaces

cbr0 8000.debc876c458c no vetha11a2630

vethaf749be9

# brctl showmacs cbr0

port no mac addr is local? ageing timer

2 86:a2:71:a1:60:b4 yes 0.00

2 86:a2:71:a1:60:b4 yes 0.00

1 ae:4d:2f:54:9c:07 yes 0.00

1 ae:4d:2f:54:9c:07 yes 0.00

2 d6:12:5a:78:49:25 no 19.94

可以看到,pod的mac地址在cbr0的mac转发表里。

$ kubectl get pod -o wide

NAME READY STATUS RESTARTS AGE IP NODE

nginx-6799fc88d8-fd5sq 1/1 Running 0 92m 10.244.0.6 aks-xxxx-vmss000001

nginx-6799fc88d8-ltwhl 1/1 Running 0 92m 10.244.1.3 aks-xxxx-vmss000000

nginx-6799fc88d8-mr2q6 1/1 Running 0 93m 10.244.1.2 aks-xxxx-vmss000000

G 检查联通性

在10.244.1.3的pod上ping其他两个pod,都能够ping通:

# ping 10.244.1.2

PING 10.244.1.2 (10.244.1.2) 56(84) bytes of data.

64 bytes from 10.244.1.2: icmp_seq=1 ttl=64 time=0.059 ms

64 bytes from 10.244.1.2: icmp_seq=2 ttl=64 time=0.090 ms

64 bytes from 10.244.1.2: icmp_seq=3 ttl=64 time=0.070 ms

^C

--- 10.244.1.2 ping statistics ---

3 packets transmitted, 3 received, 0% packet loss, time 55ms

rtt min/avg/max/mdev = 0.059/0.073/0.090/0.012 ms

# ping 10.244.0.6

PING 10.244.0.6 (10.244.0.6) 56(84) bytes of data.

64 bytes from 10.244.0.6: icmp_seq=1 ttl=62 time=0.983 ms

64 bytes from 10.244.0.6: icmp_seq=2 ttl=62 time=1.02 ms

64 bytes from 10.244.0.6: icmp_seq=3 ttl=62 time=0.985 ms

^C

--- 10.244.0.6 ping statistics ---

3 packets transmitted, 3 received, 0% packet loss, time 4ms

rtt min/avg/max/mdev = 0.983/0.994/1.016/0.039 ms

在node上抓包:

# tcpdump icmp -i eth0

tcpdump: verbose output suppressed, use -v or -vv for full protocol decode

listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes

10:45:01.811855 IP 10.244.1.3 > 10.244.0.6: ICMP echo request, id 488, seq 1, length 64

10:45:01.812767 IP 10.244.0.6 > 10.244.1.3: ICMP echo reply, id 488, seq 1, length 64

10:45:02.813014 IP 10.244.1.3 > 10.244.0.6: ICMP echo request, id 488, seq 2, length 64

10:45:02.813963 IP 10.244.0.6 > 10.244.1.3: ICMP echo reply, id 488, seq 2, length 64

10:45:03.814281 IP 10.244.1.3 > 10.244.0.6: ICMP echo request, id 488, seq 3, length 64

10:45:03.815166 IP 10.244.0.6 > 10.244.1.3: ICMP echo reply, id 488, seq 3, length 64

只能看到跨节点的包,node内的数据包只经过node内的Bridge,不经过eth0.

H 查看VNET中的用户自定义路由

查看VNET中的路由:

az network route-table list -g mc_whhk_aks01_eastus --query \

"[].{address:routes[].addressPrefix[],nextHop:routes[].nextHopIpAddress[]}"

[

{

  "address": [

    "10.244.0.0/24",

    "10.244.1.0/24"

  ],

  "nextHop": [

    "10.0.0.5",

    "10.0.0.4"

  ]

}]

可以看到指向不同node的Pod地址段。节点外访问Pod IP的路由都是有这些UDR完成的。AKS每创建一个Node,就会生成一条相应的路由。这种方式对UDR的数量有一定要求,扩展性受到一定的限制。

二 Azure CNI

1. Azure CNI的两种模式

AKS的第二种网络模式是Azure CNI模式。在Azure CNI 1.2.0之前,采用的是Bridge模式,之后采用了Transparent模式。Bridge模式中会存在Kube-DNS的5s延迟问题,而在Transparent模式中得到了解决。这两种模式的逻辑结构如下,可以看出在Transparent模式下,Azure CNI采用的是三层路由的方式:

           Bridge模式:                                                        Transparent模式:

在Azure CNI方案中,Pod和Node都在同一个VNET的Subnet中,Node在创建时,会预先预留Node中Pod所有所需要的地址。比如每个Node支持30个Pod,那每个Node创建时,就在VNET中预留30个IP地址给Pod使用。

2 Azure CNI网络互通实现方式

Pod的IP地址在VNET中是可见的,所以在VNET中的网络节点可以直接访问Pod,而不需要用户自定义路由(UDR)来帮助实现。

具体如下图:

可以看到VM和Pod的地址是在相同网段中的。Azure VNET中SDN的Network Manager会根据Pod的IP地址把流量转发到相应的Node上。

3 AKS实现

A 创建Azure CNI的AKS集群

创建VNET:

az network vnet create -g aks -n cni-vnet \

  --address-prefixes 10.0.0.0/16 -l eastus

创建Subnet:

az network vnet subnet create -g aks -n vlan01 \

  --vnet-name cni-vnet --address-prefixes 10.0.0.0/20

获取VNET和Subnet的值:

vnet_id=$(az network vnet show -g aks -n cni-vnet -o tsv --query id)

vlan_id=$(az network vnet subnet show -n vlan01 -g aks \

  --vnet-name cni-vnet -o tsv --query id)

B 创建AKS

创建AKS:

az aks create \

  -g aks -n aks-cni -l eastus \

  --network-plugin azure \

  --vnet-subnet-id $vlan_id \

  --docker-bridge-address 172.17.0.1/16 \

  --dns-service-ip 10.2.0.10 \

  --service-cidr 10.2.0.0/24 \

  --node-count 2

获取AKS管理密钥:

az aks get-credentials -g aks -n aks-cni

查看Node信息:

$ kubectl get node

NAME STATUS ROLES AGE VERSION

aks-nodepool1-14830056-vmss000000 Ready agent 3m21s v1.20.9

aks-nodepool1-14830056-vmss000001 Ready agent 3m51s v1.20.9

创建Deployment:

kubectl create deployment nginx --image nginx

kubectl scale deployment nginx --replicas=10

C 登录Node查看CNI配置

登录Node:

nodename=$(kubectl get node \

  -o jsonpath='{.items[0].metadata.labels.kubernetes\.io\/hostname}')

kubectl debug node/$nodename -it \

  --image=mcr.microsoft.com/aks/fundamental/base-ubuntu:v0.0.11

查看CNI的配置信息:

$ cd /host/etc/cni/net.d/

$ cat 10-azure.conflist

{

  "cniVersion":"0.3.0",

  "name":"azure",

  "plugins":[

  {

    "type":"azure-vnet",

    "mode":"transparent",

    "ipsToRouteViaHost":["169.254.20.10"],

    "ipam":{

      "type":"azure-vnet-ipam"

      }

  },

  {

    "type":"portmap",

    "capabilities":{

    "portMappings":true

  },

    "snat":true

  }

  ]

}

可以看到地址管理不再是host-local,而是有Azure-vnet-ipam来管理。CNI的类型也给成了Azure-vnet。

D 查看地址预留

查看Azure-vnet-ipam的日志,可以看到Node在启动时,从VNET中预留的地址。Kubenet默认时110个pod每Node,Azure CNI默认是30个Pod每Node。在日志中我们看到了预留的30个地址。由于Vnet的Subnet是新创建的,所以预留的地址是连续的:

$ more /host/var/log/azure-vnet-ipam.log

2021/11/04 09:54:50 [18965] [ipam] Pool request completed with pool:&{as:0xc0002bf740 Id:10.0.0.0/20 IfName:

eth0 Subnet:{IP:10.0.0.0 Mask:fffff000} Gateway:10.0.0.1 Addresses:map[

10.0.0.10:0xc000309180 10.0.0.11:0xc0003091c0 10.0.0.12:0xc000309200

10.0.0.13:0xc000309240 10.0.0.14:0xc000309280 10.0.0.15:0xc0003092c0

10.0.0.16:0xc000309300 10.0.0.17:0xc000309340 10.0.0.18:0xc000309380

10.0.0.19:0xc0003093c0 10.0.0.20:0xc000309400 10.0.0.21:0xc000309440

10.0.0.22:0xc000309480 10.0.0.23:0xc0003094c0 10.0.0.24:0xc000309500

10.0.0.25:0xc000309540 10.0.0.26:0xc000309580 10.0.0.27:0xc0003095c0

10.0.0.28:0xc000309600 10.0.0.29:0xc000309640 10.0.0.30:0xc000309680

10.0.0.31:0xc0003096c0 10.0.0.32:0xc000309700 10.0.0.33:0xc000309740

10.0.0.34:0xc000309780 10.0.0.5:0xc000309040 10.0.0.6:0xc000309080

10.0.0.7:0xc0003090c0 10.0.0.8:0xc000309100 10.0.0.9:0xc000309140]

addrsByID:map[] IsIPv6:false Priority:0 RefCount:1 epoch:0} err:<nil>.

查看Pod的IP地址,在vmss000000上的Pod,IP地址在预留的地址范围内:

E 检测网络连通性

Ping VNET中的其他Node和Pod,可以看到在没有用户自定义路由的情况下,网络都是通的:

root@hello-675bdb4bf9-9qxc7:/app# ifconfig eth0 | grep inet | grep -v inet6

inet 10.0.0.11 netmask 255.255.240.0 broadcast 0.0.0.0

root@hello-675bdb4bf9-9qxc7:/app# ping 10.0.0.4

PING 10.0.0.4 (10.0.0.4) 56(84) bytes of data.

64 bytes from 10.0.0.4: icmp_seq=1 ttl=64 time=0.040 ms

64 bytes from 10.0.0.4: icmp_seq=2 ttl=64 time=0.081 ms

64 bytes from 10.0.0.4: icmp_seq=3 ttl=64 time=0.054 ms

^C

--- 10.0.0.4 ping statistics ---

3 packets transmitted, 3 received, 0% packet loss, time 48ms

rtt min/avg/max/mdev = 0.040/0.058/0.081/0.018 ms

root@hello-675bdb4bf9-9qxc7:/app# ping 10.0.0.35

PING 10.0.0.35 (10.0.0.35) 56(84) bytes of data.

64 bytes from 10.0.0.35: icmp_seq=1 ttl=63 time=1.05 ms

64 bytes from 10.0.0.35: icmp_seq=2 ttl=63 time=1.13 ms

64 bytes from 10.0.0.35: icmp_seq=3 ttl=63 time=1.13 ms

^C

--- 10.0.0.35 ping statistics ---

3 packets transmitted, 3 received, 0% packet loss, time 4ms

rtt min/avg/max/mdev = 1.051/1.100/1.126/0.051 ms

root@hello-675bdb4bf9-9qxc7:/app# ping 10.0.0.37

PING 10.0.0.37 (10.0.0.37) 56(84) bytes of data.

64 bytes from 10.0.0.37: icmp_seq=1 ttl=62 time=1.08 ms

64 bytes from 10.0.0.37: icmp_seq=2 ttl=62 time=1.11 ms

^C

--- 10.0.0.37 ping statistics ---

2 packets transmitted, 2 received, 0% packet loss, time 2ms

rtt min/avg/max/mdev = 1.077/1.095/1.113/0.018 ms

三 Azure CNI增强版

1 Azure CNI存在的问题

Azure CNI虽然解决了Pod地址采用VNET地址的问题,使得Pod可以和VNET中的网络节点进行通信。但Azure CNI有以下一些问题:

  1. Azure CNI会大量占用VNET地址段的地址,每个Node创建时,都会预留大量的Pod地址。即使Pod没有创建,这些地址仍然不能使用
  2. AKS Azure CNI的Pod地址段与Node地址段在一起。没有办法针对Pod或Node进行安全配置
  3. Pod地址段是固定的,必须开始就设置大段地址,如果地址使用完,也不能追加新的地址段

2 增强版的Azure CNI

为了解决上面提到的几个问题,AKS推出了增强版的Azure CNI

增强版Azure CNI中,网卡和Pod的IP地址分别属于不同的Subnet,同时Node创建时不会预留大量的IP地址,每创建Pod时再获取相应的Pod IP地址:

目前Pod Subnet必须和Node的Subnet在一个VNET中,将来可以位于不同的VNET中。

Azure的Host Network采用VFP的方式实现主机的虚拟交换,增强版的Azure CNI模式下,VFP把同一个主机的Node和Pod作为两个不同的Network Container来进行处理,等于同一个VM上有两组不同的网络规则,如下图:

3 AKS实现

A 创建VNET

创建VNET,以及Node Subnet和Pod Subnet:

az group create -n cni -l eastus

az network vnet create -g cni -n whkubenet \

  --address-prefixes 10.1.0.0/16 -l eastus

az network vnet subnet create -g cni -n podvlan \

  --vnet-name whkubenet --address-prefixes 10.1.0.0/22

az network vnet subnet create -g cni -n nodevlan \

  --vnet-name whkubenet --address-prefixes 10.1.4.0/24

vnet_id=$(az network vnet show -g cni -n whkubenet -o tsv --query id)

podvlan=$(az network vnet subnet show -n podvlan -g cni \

  --vnet-name whkubenet -o tsv --query id)

nodevlan=$(az network vnet subnet show -n nodevlan -g cni \

  --vnet-name whkubenet -o tsv --query id)

B 安装AKS Preview的扩展插件

目前增强的Azure CNI是Preview阶段,需要安装Preview的扩展插件:

az extension add --name aks-preview

az extension update --name aks-preview

az feature register --namespace "Microsoft.ContainerService" \

  --name "PodSubnetPreview"

az feature list -o table \

  --query "[?contains(name, 'Microsoft.ContainerService/PodSubnetPreview')].{Name:name,State:properties.state}"

C 创建AKS集群

创建AKS集群:

az aks create -n akscni -g cni -l eastus \

  --max-pods 250 \

  --node-count 2 \

  --network-plugin azure \

  --vnet-subnet-id $nodevlan \

  --pod-subnet-id $podvlan

获取管理权限:

az aks get-credentials -n akscni -g cni

创建workload:

kubectl create deployment nginx --image nginx

kubectl scale deployment nginx --replicas=5

D 查看地址分配

查看Pod IP地址分配,Pod分配在两个Node上,地址段是预先定义的Pod地址段,与Node地址段不相同。

E 登录Node查看CNI信息

登录Node,

nodename=$(kubectl get node \

  -o jsonpath='{.items[0].metadata.labels.kubernetes\.io\/hostname}')

kubectl debug node/$nodename -it \

  --image=mcr.microsoft.com/aks/fundamental/base-ubuntu:v0.0.11

查看CNI信息,可以看到和普通的Azure CNI配置相同:

# cat 10-azure.conflist

{

  "cniVersion":"0.3.0",

  "name":"azure",

  "plugins":[

  {

    "type":"azure-vnet",

    "mode":"transparent",

    "ipsToRouteViaHost":["169.254.20.10"],

    "ipam":{

      "type":"azure-cns"

  }

  },

  {

    "type":"portmap",

    "capabilities":{

    "portMappings":true

  },

    "snat":true

  }

  ]

}

查看/host/var/log/zure-vnet.log,可以看到Node给Pod分配IP地址、添加路由等日志。

在Node中查看路由信息,可以看到每个Pod都有相应的静态路由:

4 添加Node Pool

增强版的CNI中,可以每个Node Pool采用不同的Pod Subnet,如下图:

新Node Pool的Node地址仍然在Node的Subnet中,但通过创建新的Pod地址段,新建Node Pool中的Pod,会采用新的地址段。

A 创建Pod Subnet

az network vnet subnet create -g cni -n podvlan2 \

  --vnet-name whkubenet --address-prefixes 10.1.8.0/22

podvlan2=$(az network vnet subnet show -n podvlan2 -g cni \

  --vnet-name whkubenet -o tsv --query id)

B 创建AKS Node Pool

az aks nodepool add --cluster-name akscni -g cni -n newnodepool \

  --max-pods 250 \

  --node-count 2 \

  --vnet-subnet-id $nodevlan \

  --pod-subnet-id $podvlan2 \

  --no-wait

C 查看IP地址分配

Node IP地址:

Pod IP地址:

可以看到,新的Node Pool中的Pod采用了新的地址段。

通过这种方法,可以非常方便的规划、扩展计算资源池,解决Pod地址不够用的问题。

D 测试安全规则

通过创建安全规则,允许第一个Node Pool中的Pod访问Node,禁止第二个Node Pool中的Pod访问Node。

I 创建NSG

创建NSG规则:

az network nsg create -n aksnsg -g cni -l eastus

az network nsg rule create -g cni \

  --nsg-name aksnsg \

  --name icmp_permit \

  --priority 200 \

  --source-address-prefixes '10.1.0.0/22' \

  --destination-address-prefixes '10.1.4.0/24' \

  --access Allow \

  --protocol ICMP \

  --direction Inbound

az network nsg rule create -g cni \

  --nsg-name aksnsg \

  --name icmp_deny \

  --priority 300 \

  --source-address-prefixes '10.1.8.0/22' \

  --destination-address-prefixes '10.1.4.0/24' \

  --access Deny \

  --protocol ICMP \

  --direction Inbound

az network vnet subnet update -n nodevlan \

  --vnet-name whkubenet -g cni \

  --network-security-group aksnsg

II Node Pool1中的Pod测试

登录第一个Node Pool的Pod:

地址段是10.1.0.0/22地址段的Pod,是第一个Node Pool中的Pod。

可以Ping通Node地址段中的VM。

III Node Pool2中的Pod测试

登录第二个Node Pool的Pod:

地址段是10.1.8.0/22地址段的Pod,是第二个Node Pool中的Pod。

Ping Node地址段的VM,网络不通,被NSG规则Deny。

由于Node Pool的Pod采用不同的Subnet,可以非常方便的对Workload进行一些规则的定义,实现精选的安全设计和部署。

四 结束语

Azure的AKS有多种容器网络的实现方式,包括:

  1. Kubenet:Kubenet的方式,实现起来简单,PodIP地址在创建AKS时指定。但每创建一个Node就需要增加一条UDR路由,使得扩展性受限

  2. Azure CNI:Azure CNI非常好的解决了Pod地址暴露在VNET的问题。VNET中的网络节点可以非常方便的和Pod进行通信。但这种方案PodIP地址消耗VNET地址段相对较多。在每个Node创建时,都要预留相应的IP地址段在Node中。同时不能追加Pod地址段,使得扩展性也受到一定的限制

  3. Azure CNI增强版:Azure CNI增强版非常好的解决了上面两种方法的问题,通过分离Node和Pod的Subnet,在新的NodePool中添加新的PodSubnet的方式,方便的实现了AKS网络层面的扩展需求,同时可以节约大量的IP地址段。

AKS的用户,可以根据业务的实际需求,可以选择不同的方式进行部署。