
Kubernetes Calico IPAM
IPAM 简介
CNI的职责包括给 Container 分配网络设备,并且分配IP,IPAM(IP Address Management)就是指IP分配相关的功能和规范。
CNI本身只是一个规范,不同的实现在 IPAM 方面的功能集也不尽相同。下面将首先尝试说明下不同 CNI在这块的实现。
calico开发的IPAM组件叫 calico-ipam, 它使用 calico 的 IP pool resource来管理 IP.。它的主要优势就是可以将 pool 分割成小的 block, 并且可以动态对分配给不同的 node。node 上的 ip 利用率会更高,并且可扩展性也很好。calico 目前也支持给不同的namespace分配不同的 ip pool. 从大的方面来看,其实最终 各个CNI 实现要解决的问题都是类似的,一般区别只是 dataplane 以及具体的 CRD的设计不太一样。所以这些功能很可能(已经有了或者以后会有)出现在其他的 CNI 上面。
设置Calico IPAM
首先需要设置CNI IPAM的配置为calico-ipam
。
cd /etc/cni/net.d/
ls
cat 10-calico.conflist
关于calico ipam支持的方式有下列几种:
1.根据拓扑分配地址
2.为pod使用特定地址
3.从一个IP池迁移到另一个
4.使用IP范围与旧式防火墙互操作
5.查看IP地址利用率
6.更改IP地址块大小
根据拓扑分配地址
简单来讲:我们可以给我们的集群节点服务器打上标签,然后更具这些标签打上不同的ip段。
怎么打?
就在我们ippool里面的selector选标签决定了ip池的范围。
calicoctl get ippool -o wide
简单实践
首先我们禁用掉原有的default-ipv4-ippool
。
calicoctl get ippool -o yaml > default-ipv4-ippool.yaml
vim default-ipv4-ippool.yaml
# 添加disabled: true
calicoctl apply -f default-ipv4-ippool.yaml
禁用掉后我们现在ip池中没有一个可用的ip池,所以新的pod将分配不了IP。
接下来为我们的node打上标签。
# 为k8s-1打上rack=0的标签
kubectl label nodes k8s-1 rack=0
# 为k8s-2打上rack=0的标签
kubectl label nodes k8s-2 rack=1
接下来根据不同的节点标签使用不同的IP池子。
calicoctl create -f -<<EOF
apiVersion: projectcalico.org/v3
kind: IPPool
metadata:
name: rack-0-ippool
spec:
cidr: 192.168.0.0/24
ipipMode: Always
natOutgoing: true
nodeSelector: rack == "0"
EOF
calicoctl create -f -<<EOF
apiVersion: projectcalico.org/v3
kind: IPPool
metadata:
name: rack-1-ippool
spec:
cidr: 192.168.1.0/24
ipipMode: Always
natOutgoing: true
nodeSelector: rack == "1"
EOF
calicoctl get ippool -o wide
我们可以看到名为rack-0-ippool
的IP池子为拥有rack == "0"
标签的节点使用192.168.0.0/24
段,rack-1-ippool
的IP池子为拥有rack == "1"
标签的节点使用192.168.1.0/24
段。
我们改一下cni.yaml
,然后跑一下。
vim cni.yaml
kubectl apply -f cni.yaml
kubectl get pod
我们的两个pod跑起来了,可以发现在k8s-1节点上的IP为192.168.0.129
,k8s-2节点上的IP为192.168.1.193
,它们分配的IP是不同的IP池子。
ok,这就是基于拓扑分配IP地址。
为pod使用特定地址
当我们的Pod需要用到特定的IP地址时,Calico一般采用注释这个IP的方式来做的,下面我们将进行简单的实践。
简单实践
首先我们删除刚刚创建的ippools。
calicoctl delete ippool rack-0-ippool rack-1-ippool
创建一个新的IP池,值得注意的是这里的nodeSelector是选择不允许所有的节点"!all()"
。
vim net.yaml
apiversion: projectcalico.org/v3
kind: IPPool
metadata:
name: staticippool
spec:
cidr: 172.16.0.0/26
blockSize: 29
ipipMode: Always
natOutgoing: true
nodeSelector: "!all()"
然后应用一下。
calicoctl apply -f net.yaml
calicoctl get ippool -o wide
然后我们在我们的Pod上打上cni.projectcalico.org/ipAddrs
标签并设置为我们staticippool
IP 池中网段下的IP。
vim calico_static.yaml
apiVersion: v1
kind: Pod
metadata:
name: calico-static-pod
labels:
app: myapp
annotations:
cni.projectcalico.org/ipAddrs: "[\"172.16.0.2\"]"
spec:
containers:
- name: static-container
image: burlyluo/nettoolbox
kubectl apply -f calico_static.yaml
kubectl get pod -o wide
这就是为pod使用特定地址。
那要是使用Deployment怎么办?
在cni.projectcalico.org/ipAddrs
中定义了多少个ip,就可以replicas多少个pod。
apiVersion: apps/v1
kind: Deployment
metadata:
name: static-ip
spec:
selector:
matchLabels:
app: nginx
replicas: 1 # tells deployment to run 1 pods matching the template
template:
metadata:
labels:
app: nginx
annotations:
"cni.projectcalico.org/ipAddrs": "[\"172.16.0.5\"]"
spec:
containers:
- name: nginx
image: burlyluo/nettoolbox
从一个IP池迁移到另一个
简单来讲创建一个新的IP Pool,把老的的IP Pool禁用掉,再把Pod一个一个的删除。
这里我就不做多的演示了,自己可以参考文档:https://projectcalico.docs.tigera.io/networking/migrate-pools
使用IP范围与旧式防火墙互操作
简单来讲:与指定Pod特定的IP差不多,都是通过注释的方式进行。
只是这里指定的是IP Pools。
# ipv4
cni.projectcalico.org/ipv4pools: '["pool-1", "pool-2"]'
# ipv6
cni.projectcalico.org/ipv6pools: '["pool-1", "pool-2"]'
查看IP地址利用率(地址分配)
打印有关借用IP地址的详细信息。
calicoctl ipam show --show-borrowed
打印当前IPAM配置。
calicoctl ipam show --show-configuration
检测ipam的详细信息,以及存在的问题。
calicoctl ipam check
如果你的IP地址有问题了,比如IP Pool替换更新了,你需要将Pod重新Release一下,怎么做?
首先需要Lock一下,告诉其他人先不要分配IP地址。
calicoctl datastore migrate lock
然后把IPAM的检测以json的方式导出到report.json
文件中。
calicoctl ipam check -o report.json
cat report.json
然后我们释放未设置的ip地址。大概会检测20分钟。
calicoctl ipam release --from-report=report.json
然后我们解锁。
calicoctl datastore migrate unlock
最后验证一下。
calicoctl ipam check
欢迎加群讨论技术,1群:677373950(满了,可以加,但通过不了),2群:656732739

