文章目录

  • 一、前言
  • 二、学会查看 ippool 整个yaml文件中,各个属性什么意思
  • 2.1 ippool整个yaml文件属性解释
  • 2.2 calico底层网络通信(相同Node和不同Node)
  • 2.3 小结
  • 三、实践应用:kubernetes设置指定IP的场景及方法
  • 3.1 基本语法(通过annotations指定)
  • 基本语法1:每个pod指定IP池
  • 基本语法2:每个pod指定静态IP地址
  • 基本语法3:每个pod申请浮动IP
  • 基本语法4:基于node节点指定IP池
  • 基本语法5:基于命名空间指定IP池
  • 3.2 实践应用
  • 应用一:为pod指定IP地址池
  • 步骤1:创建IP地址池
  • 步骤2:创建应用测试
  • 小结
  • 应用二:Pod设置静态IP/固定IP(设置的IP地址必须包含在已存在的IPPool中)
  • 应用三:删除或禁用已存在的IPPool
  • 禁用IPPool
  • 删除IPPool
  • 应用四:根据节点指定IP池
  • 步骤1:给节点打上标签
  • 步骤2:创建IPPool
  • 步骤3:创建应用测试
  • 应用五:基于namespace指定IP池
  • 步骤1:查看当前存在的IP池
  • 步骤2:创建新的IP池
  • 步骤3:创建新的namespace,并指定IP池
  • 步骤4:创建应用测试
  • 小结
  • 四、尾声


一、前言

Kubernetes中,除了daemonSet和运行在主节点的静态Pod(例如 apiserver controller-manager scheduler etcd),直接使用宿主机IP作为Pod之外,其他的,deployment statefulset job/cronjob replicaSet 控制器管理的Pod,都是需要使用虚拟IP的。这些Pod运行所需要的虚拟IP,都是cni网络插件生成的,如果使用的cni网络插件是Calico的,这些虚拟IP是一个crd自定义的 kind: IPPool 的资源生成的。

这篇文章就来看一下Calico中这个IPPool是怎样为Pod生成虚拟IP的。

本文把握两个知识点
第一,学会查看 ippool 整个yaml文件中,各个属性什么意思;(本文第二部分)
第二,对于各种业务需求,如果使用 IPPool 来完成。(本文第三部分)

二、学会查看 ippool 整个yaml文件中,各个属性什么意思

Pod一般不建议设置静态IP地址,若想要实现设置静态IP,可以参考下面的方法。像亚马逊、阿里云等厂家是支持静态IP的,但如果是自己的私有云,可以参考下面的方法。这里使用的是calico网络方案,其他的网络方案,好像并不支持,更详细的操作,可以看看calico的官方文档。

2.1 ippool整个yaml文件属性解释

IP Pool资源定义
IPPool资源yaml定义

apiVersion: crd.projectcalico.org/v1
kind: IPPool
metadata:  
   name: default-ipv4-ippool
spec:  
   blockSize: 26  
   cidr: 192.168.0.0/16  
   ipipMode: Always  
   natOutgoing: true  
   nodeSelector: all()  
   vxlanMode: Never  
   disabled: false

如果使用calicoctl定义,则将apiVersion更改为apiVersion: projectcalico.org/v3

字段说明

metadata:

Kubernetes_容器网络_Calico_01_Calico作为CNI插件如何为Pod生成虚拟IP_容器


spec:

Kubernetes_容器网络_Calico_01_Calico作为CNI插件如何为Pod生成虚拟IP_tcp/ip_02

要想看每个属性的默认值,就查看集群那个ippool

apiVersion: crd.projectcalico.org/v1
kind: IPPool
metadata:
  annotations:
    projectcalico.org/metadata: '{"uid":"7a74f733-5d33-47f9-8b13-5a379f6e290f","creationTimestamp":"2023-03-08T16:15:22Z"}'
  creationTimestamp: "2023-03-08T16:15:22Z"
  generation: 1
  name: default-ipv4-ippool
  resourceVersion: "737"
  uid: 21d4daf2-82a3-4c06-bbba-ea99c674005a
spec:
  blockSize: 26
  cidr: 192.168.0.0/16
  ipipMode: Always
  natOutgoing: true
  nodeSelector: all()
  vxlanMode: Never

blockSize 业务含义就是 块大小,默认的块大小是 64 。
32位的默认是 26位,32-26=6 位 ,2的6次方就是64,就是块大小

分块的目的是为了分机器node,每个机器node就分配一个块,证明如下:

Kubernetes_容器网络_Calico_01_Calico作为CNI插件如何为Pod生成虚拟IP_ico_03

Kubernetes_容器网络_Calico_01_Calico作为CNI插件如何为Pod生成虚拟IP_容器_04


Kubernetes_容器网络_Calico_01_Calico作为CNI插件如何为Pod生成虚拟IP_kubernetes_05

Kubernetes_容器网络_Calico_01_Calico作为CNI插件如何为Pod生成虚拟IP_kubernetes_06


Kubernetes_容器网络_Calico_01_Calico作为CNI插件如何为Pod生成虚拟IP_容器_07

2.2 calico底层网络通信(相同Node和不同Node)

IPv4 26和IPv6 122的默认块大小为64个地址的块。这允许将地址按组分配给在同一主机上运行的工作负载。通过对地址进行分组,主机之间以及与其他BGP对等方之间交换的路由更少。如果主机在一个块中分配所有地址,则将为其分配一个附加块。如果没有更多可用的块,则主机可以从分配给其他主机的块中获取地址。为借用的地址添加了特定的路由,这会影响路由表的大小。

情况一:将 myapp-pod 部署在主机 m 上,查看路由解释全过程(优先匹配长的,而不是匹配在前面的)

步骤1:对于具体IP,子网掩码长度24, 在机器m上,192.168.159.8/24、192.168.159.9/24、192.168.159.10/24、192.168.159.11/24、192.168.159.13/24、192.168.159.21/24、192.168.159.22/24、192.168.159.23/24 ,直接使用 calicoXxx 网卡,0.0.0.0 表示在 m 机器上自行处理
步骤2:当访问 192.168.55.64/26、192.168.159.0/26 的时候,m节点可以直接机器上处理(Gatway列为0.0.0.0),w1节点需要通过 tunl0 网卡跳转到 155 机器(Gateway列指出)
步骤3:当访问 192.168.190.64/26 的时候,w1节点可以直接机器上处理(Gatway列为0.0.0.0),m节点需要通过 tunl0 网卡跳转到 151 机器(Gateway列指出)
步骤4:当访问 192.168.100/24 的时候,两个机器都可以通过自己的 ens33 网卡,本机器 0.0.0.0 上处理 (因为这个 192.168.100/24 是通过 ipaddr+mask 配置指定的)
步骤5:当访问 172.17/16 的时候,两个机器都可以通过自己的 docker0 网卡,本机器 0.0.0.0 上处理
步骤6:当访问 0.0.0.0/0 任意地址 的时候,两个机器都可以通过自己的 ens33 网卡,本机器 0.0.0.0 上处理(因为这是通过 linux gateway 配置指定的)

[root@m ~]# route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         192.168.100.2   0.0.0.0         UG    100    0        0 ens33
172.17.0.0      0.0.0.0         255.255.0.0     U     0      0        0 docker0
192.168.55.64   0.0.0.0         255.255.255.192 U     0      0        0 *
192.168.100.0   0.0.0.0         255.255.255.0   U     100    0        0 ens33
192.168.159.0   0.0.0.0         255.255.255.192 U     0      0        0 *
192.168.159.8   0.0.0.0         255.255.255.255 UH    0      0        0 cali396dfe27aad
192.168.159.9   0.0.0.0         255.255.255.255 UH    0      0        0 calic32badc86da
192.168.159.10  0.0.0.0         255.255.255.255 UH    0      0        0 cali48e10e29d97
192.168.159.11  0.0.0.0         255.255.255.255 UH    0      0        0 cali0054af02df5
192.168.159.13  0.0.0.0         255.255.255.255 UH    0      0        0 cali22552fba529
192.168.159.21  0.0.0.0         255.255.255.255 UH    0      0        0 cali6ab633ce8cf
192.168.159.22  0.0.0.0         255.255.255.255 UH    0      0        0 cali505bb5c3e0a
192.168.159.23  0.0.0.0         255.255.255.255 UH    0      0        0 cali0027cc35f35
192.168.190.64  192.168.100.151 255.255.255.192 UG    0      0        0 tunl0
[root@w1 ~]# route
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
default         gateway         0.0.0.0         UG    100    0        0 ens33
172.17.0.0      0.0.0.0         255.255.0.0     U     0      0        0 docker0
192.168.55.64   192.168.100.155 255.255.255.192 UG    0      0        0 tunl0
192.168.100.0   0.0.0.0         255.255.255.0   U     100    0        0 ens33
192.168.159.0   192.168.100.155 255.255.255.192 UG    0      0        0 tunl0
192.168.190.64  0.0.0.0         255.255.255.192 U     0      0        0 *

Kubernetes_容器网络_Calico_01_Calico作为CNI插件如何为Pod生成虚拟IP_ico_08

情况二:将 myapp-pod 部署在主机 w1 上,查看路由:

步骤1:对于具体IP,子网掩码长度24, 在机器m上,192.168.159.8/24、192.168.159.9/24、192.168.159.10/24、192.168.159.11/24、192.168.159.13/24、192.168.159.21/24、192.168.159.22/24,直接使用 calicoXxx 网卡,0.0.0.0 表示在 m 机器上自行处理
步骤2:当访问 192.168.55.64/26、192.168.159.0/26 的时候,m节点可以直接机器上处理(Gatway列为0.0.0.0),w1节点需要通过 tunl0 网卡跳转到 155 机器(Gateway列指出)
步骤3:当访问 192.168.190.64/26 的时候,w1节点可以直接机器上处理(Gatway列为0.0.0.0),m节点需要通过 tunl0 网卡跳转到 151 机器(Gateway列指出)
步骤4:当访问 192.168.100/24 的时候,两个机器都可以通过自己的 ens33 网卡,本机器 0.0.0.0 上处理 (因为这个 192.168.100/24 是通过 ipaddr+mask 配置指定的)
步骤5:当访问 172.17/16 的时候,两个机器都可以通过自己的 docker0 网卡,本机器 0.0.0.0 上处理
步骤6:当访问 0.0.0.0/0 任意地址 的时候,两个机器都可以通过自己的 ens33 网卡,本机器 0.0.0.0 上处理(因为这是通过 linux gateway 配置指定的)

[root@m fixip]# route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         192.168.100.2   0.0.0.0         UG    100    0        0 ens33
172.17.0.0      0.0.0.0         255.255.0.0     U     0      0        0 docker0
192.168.55.64   0.0.0.0         255.255.255.192 U     0      0        0 *
192.168.100.0   0.0.0.0         255.255.255.0   U     100    0        0 ens33
192.168.159.0   0.0.0.0         255.255.255.192 U     0      0        0 *
192.168.159.8   0.0.0.0         255.255.255.255 UH    0      0        0 cali396dfe27aad
192.168.159.9   0.0.0.0         255.255.255.255 UH    0      0        0 calic32badc86da
192.168.159.10  0.0.0.0         255.255.255.255 UH    0      0        0 cali48e10e29d97
192.168.159.11  0.0.0.0         255.255.255.255 UH    0      0        0 cali0054af02df5
192.168.159.13  0.0.0.0         255.255.255.255 UH    0      0        0 cali22552fba529
192.168.159.21  0.0.0.0         255.255.255.255 UH    0      0        0 cali6ab633ce8cf
192.168.159.22  0.0.0.0         255.255.255.255 UH    0      0        0 cali505bb5c3e0a
192.168.190.64  192.168.100.151 255.255.255.192 UG    0      0        0 tunl0
[root@w1 ~]# route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         192.168.100.2   0.0.0.0         UG    100    0        0 ens33
172.17.0.0      0.0.0.0         255.255.0.0     U     0      0        0 docker0
192.168.55.64   192.168.100.155 255.255.255.192 UG    0      0        0 tunl0
192.168.100.0   0.0.0.0         255.255.255.0   U     100    0        0 ens33
192.168.159.0   192.168.100.155 255.255.255.192 UG    0      0        0 tunl0
192.168.190.64  0.0.0.0         255.255.255.192 U     0      0        0 *
192.168.190.74  0.0.0.0         255.255.255.255 UH    0      0        0 cali0027cc35f35

Kubernetes_容器网络_Calico_01_Calico作为CNI插件如何为Pod生成虚拟IP_tcp/ip_09

将块大小从默认值增加(例如,使用24IPv4为每个块提供256个地址)意味着每个主机更少的块,并且可能会减少路由。但是,请尝试确保池中至少有与主机一样多的块。【即确保 blockCount > HostCount ,否则会报错】

从默认值减小块大小(例如,使用28IPv4为每个块提供16个地址)意味着每个主机有更多块,因此可能有更多路由。如果它允许块在主机之间更公平地分布,那么这将是有益的。

关于cidr和blockSize设置

比如你新增一个IPPool,cidr设置为192.169.0.0/29,在没有设置blockSize情况下,默认是/26的blockSize,这样是不允许的,192.169.0.0/29可用地址为8个,而默认blockSize为26将会把IP段分为64块,没有足够的IP,所以是无效的,所以blockSize应该等于大于子网掩码。

新创建的IPPool,可以在原有的IPPool中某一子网,比如

apiVersion: crd.projectcalico.org/v1
kind: IPPool
metadata:  
   name: test-ipv4-ippool
spec:  
   blockSize: 29
   cidr: 192.168.0.0/29  
   ipipMode: Always  
   natOutgoing: true  
   nodeSelector: all()  
   vxlanMode: Never

2.3 小结

这里搞懂了两件事:

第一,ippool yaml文件的各个属性的含义
第二,整个 k8s 集群的网络路由,每个Pod都会有一个calico网卡,同一机器的Pod之间通信直接使用 calico网卡,不同机器的Pod之间通信要通过 tul0 网卡路由

如果开发中遇到问题,同一机器的Pod之间可以通信,不同机器的Pod之间无法通信,要么是tul0网卡缺失或错误,要么是路由route缺失或错误

三、实践应用:kubernetes设置指定IP的场景及方法

如果将这些方法中的一种以上用于IP地址分配,则它们将具有以下优先级,其中1为最高优先级:

1、Kubernetes批注 (annotations)
2、CNI配置
3、IP池节点选择器

本文主要通过annotations指定。

3.1 基本语法(通过annotations指定)

基本语法1:每个pod指定IP池

cni.projectcalico.org/ipv4pools:

annotations:
    "cni.projectcalico.org/ipv4pools": "[\"default-ipv4-ippool\"]"

cni.projectcalico.org/ipv6pools:

annotations:    
    "cni.projectcalico.org/ipv6pools": "[\"2001:db8::1/120\"]"

基本语法2:每个pod指定静态IP地址

cni.projectcalico.org/ipAddrs:

annotations:
      "cni.projectcalico.org/ipAddrs": "[\"192.168.0.1\"]"

cni.projectcalico.org/ipAddrsNoIpam:

annotations:
      "cni.projectcalico.org/ipAddrsNoIpam": "[\"10.0.0.1\"]"

说明:cni.projectcalico.org/ipAddrsNoIpam:绕过IPAM分配给Pod的IPv4和/或IPv6地址的列表。任何IP冲突和路由都必须手动或由其他系统来处理。Calico仅在其IP地址属于Calico IP池内时才将路由分配到Pod。如果分配的IP地址不在Calico IP池中,则必须确保通过另一种机制来处理到该IP地址的路由。

基本语法3:每个pod申请浮动IP

annotations:
      "cni.projectcalico.org/floatingIPs": "[\"10.0.0.1\"]"

基本语法4:基于node节点指定IP池

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"

基本语法5:基于命名空间指定IP池

# kubectl annotate namespace test-ippool "cni.projectcalico.org/ipv4pools"='["test-ipv4-ippool"]'
namespace/test-ippool annotated

将 ippool 和节点绑定,这样分配到这个节点的所有的pod,就都应用到这个 ippool
将 ippool 和 ns 绑定,这样分配到这个 ns 的所有的pod,就都应用到这个 ippool

3.2 实践应用

应用一:为pod指定IP地址池

步骤1:创建IP地址池
# cat> ippool.yaml <<EOF
apiVersion: crd.projectcalico.org/v1
kind: IPPool
metadata:
  name: test1-ipv4-ippool
spec:
  blockSize: 29  
  cidr: 192.169.0.0/29  
  ipipMode: Always  
  natOutgoing: true  
  nodeSelector: all()  
  vxlanMode: Never
EOF
# kubectl apply -f ippool.yaml
# kubectl exec -it -n kube-system calicoctl -- calicoctl ipam show 
+----------+----------------+-----------+------------+--------------+
| GROUPING |      CIDR      | IPS TOTAL | IPS IN USE |   IPS FREE   |
+----------+----------------+-----------+------------+--------------+
| IP Pool  | 192.168.0.0/16 |     65536 | 6 (0%)     | 65530 (100%) |
| IP Pool  | 170.252.0.0/29 |         8 | 0 (0%)     | 8 (100%)     |
| IP Pool  | 192.169.0.0/29 |         8 | 0 (0%)     | 8 (100%)     | # 新创建的IPPool
+----------+----------------+-----------+------------+--------------+
步骤2:创建应用测试

spec.template.metadata.annotations指定了使用的IPPool

# cat >tomcat.yaml<<EOF
apiVersion: apps/v1
kind: Deployment
metadata:
  name: tomcat  
  namespace: default
spec:
  replicas: 3  
  selector:
      matchLabels:
            app: tomcat
  template:
      metadata:
            annotations:
                    "cni.projectcalico.org/ipv4pools": "[\"test1-ipv4-ippool\"]"      
            labels:
                    app: tomcat
      spec:
            containers:
                  - name: tomcat        
                     image: tomcat:7.0.70        
                     ports:        
                     - containerPort: 8080          
                       protocol: TCP
apiVersion: v1
kind: Service
metadata:
  name: tomcat  
  namespace: default
spec:
  type: NodePort  
  ports:  
  - port: 8080    
     targetPort: 8080    
     nodePort: 32080  
  selector:
      app: tomcat
# kubectl apply -f tomcat.yaml
# kubectl get pods -o wide
NAME                      READY   STATUS    RESTARTS   AGE    IP            NODE      NOMINATED NODE   READINESS GATES
tomcat-7c9bc7f455-ccsvx   1/1     Running   0          127m   192.169.0.1   k8node1   <none>           <none>
tomcat-7c9bc7f455-nb4wr   1/1     Running   0          127m   192.169.0.3   k8node2   <none>           <none>
tomcat-7c9bc7f455-s4r9q   1/1     Running   0          127m   192.169.0.2   k8node1   <none>
小结

小结:
(1) 新建 ippool
(2) pod 通过annotations指定使用 ippool,这个 deployment 下的Pod 的 ip 都在 192.169.0.0/29 范围内

应用二:Pod设置静态IP/固定IP(设置的IP地址必须包含在已存在的IPPool中)

虽然官方说名 cni.projectcalico.org/ipAddrs:后面是IPv4或IPv6列表,实际并不支持,仅可以设置一个IP地址。所以Pod副本数超过1个是不行的。

# cat >tomcat.yaml<<EOF
apiVersion: apps/v1
kind: Deployment
metadata:
  name: tomcat  
  namespace: default
spec:
  replicas: 1  
  selector:
      matchLabels:
            app: tomcat  
  template:
      metadata:
            annotations:
                    "cni.projectcalico.org/ipAddrs": "[\"192.168.3.100\"]"      
            labels:
                 app: tomcat
      spec:
            containers:
            - name: tomcat        
               image: tomcat:7.0.70        
               ports:        
               - containerPort: 8080          
                 protocol: TCP

apiVersion: v1
kind: Service
metadata:
  name: tomcat  
  namespace: default
spec:
  type: NodePort  
  ports:  
  - port: 8080    
    targetPort: 8080    
    nodePort: 32080  
  selector:
      app: tomcat
# kubectl apply -f tomcat.yaml
# kubectl get pods -o wide
NAME                     READY   STATUS    RESTARTS   AGE   IP              NODE      NOMINATED NODE   READINESS GATES
tomcat-94f77b7db-vq7zl   1/1     Running   0          5s    192.168.3.100   k8node2   <none>           <none>

小结:
pod 通过annotations指定使用 ippool,这个 pod 的 ip 是指定的 192.168.3.100 。
注意:使用这种方式,这个 deployment 只能有一个 replicas 副本,就是只能有一个 pod ,只能指定一个 ip ,否则就会报错 more than one xxx (kubectl describe pod pod-name -n ns-name)

应用三:删除或禁用已存在的IPPool

理由:如果不禁用或删除,创建的Pod也有可能分配到其他IPPool中的地址段

# kubectl exec -it -n kube-system calicoctl -- calicoctl get ippool -o wide
NAME                  CIDR             NAT    IPIPMODE   VXLANMODE   DISABLED   SELECTOR   
default-ipv4-ippool   192.168.0.0/16   true   Always     Never       false       all()
禁用IPPool
# kubectl get ippools.crd.projectcalico.org default-ipv4-ippool -oyaml >default-ipv4-ippool.yaml
# 修改default-ipv4-ippool.yaml,添加disabled: true
# vim default-ipv4-ippool.yaml 
apiVersion: crd.projectcalico.org/v1
kind: IPPool
metadata:
  generation: 1  
  name: default-ipv4-ippool
spec:
  blockSize: 26  
  cidr: 192.168.0.0/16  
  disabled: true  
  ipipMode: Always  
  natOutgoing: true  
  nodeSelector: all()  
  vxlanMode: Never
# kubectl apply -f default-ipv4-ippool.yaml 
ippool.crd.projectcalico.org/default-ipv4-ippool configured
[root@k8master src]# kubectl exec -it -n kube-system calicoctl -- calicoctl get ippool -o wide
NAME                  CIDR             NAT    IPIPMODE   VXLANMODE   DISABLED   SELECTOR   
default-ipv4-ippool   192.168.0.0/16   true   Always     Never       true       all()
删除IPPool
# kubectl exec -it -n kube-system calicoctl -- calicoctl delete default-ipv4-ippool

小结:ippool 不仅可以新建,也可以被禁用(存在但不使用)和删除(直接变为不存在),这样做的目的是如果不禁用或删除,创建的Pod也有可能分配到其他IPPool中的地址段

应用四:根据节点指定IP池

步骤1:给节点打上标签
# kubectl label nodes k8node1 rack=0
node/k8node1 labeled
# kubectl label nodes k8node2 rack=1
node/k8node2 labeled

将 k8node1 节点打上标签 rack=0
将 k8node2 节点打上标签 rack=1

步骤2:创建IPPool
cat >ippool.yaml<<EOF
apiVersion: crd.projectcalico.org/v1
kind: IPPool
metadata:
  name: rack0-ippool
spec:
  blockSize: 26  
  cidr: 170.16.0.0/16  
  ipipMode: Always  
  natOutgoing: true  
  nodeSelector: rack == "0"    # 选择具有 rack=0 标签的节点
  vxlanMode: Never

apiVersion: crd.projectcalico.org/v1
kind: IPPool
metadata:  name: rack1-ippool
spec:
  blockSize: 26  
  cidr: 170.17.0.0/16  
  ipipMode: Always  
  natOutgoing: true  
  nodeSelector: rack == "1"   # 选择具有 rack=1 标签的节点
  vxlanMode: NeverEOF
# kubectl apply -f ippool.yaml
# kubectl exec -it -n kube-system calicoctl -- calicoctl get ippool -o wide
NAME                  CIDR             NAT    IPIPMODE   VXLANMODE   DISABLED   SELECTOR      
default-ipv4-ippool   192.168.0.0/16   true   Always     Never       true       all()         
rack0-ippool          170.16.0.0/16    true   Always     Never       false      rack == "0"   
rack1-ippool          170.17.0.0/16    true   Always     Never       false      rack == "1"
步骤3:创建应用测试
cat >tomcat.yaml<<EOF
apiVersion: apps/v1
kind: Deployment
metadata:
  name: tomcat
  namespace: default
spec:
  replicas: 4  
  selector:
      matchLabels:
            app: tomcat  
  template:
      metadata:
            labels:
                    app: tomcat
      spec:
            containers:
                  - name: tomcat
                     image: tomcat:7.0.70        
                     ports:        
                     - containerPort: 8080
                       protocol: TCP


apiVersion: v1
kind: Service
metadata:
  name: tomcat  
  namespace: default
spec:
  type: NodePort  
  ports:
    - port: 8080    
      targetPort: 8080    
      nodePort: 32080  
  selector:
      app: tomcatEOF
# kubectl apply -f tomcat.yaml
# kubectl get pods -o wide
NAME                     READY   STATUS    RESTARTS   AGE   IP               NODE      NOMINATED NODE   READINESS GATES
tomcat-f556bbb4d-56bd4   1/1     Running   0          8s    170.16.0.194     k8node1   <none>           <none>
tomcat-f556bbb4d-5nzkb   1/1     Running   0          8s    170.17.184.131   k8node2   <none>           <none>
tomcat-f556bbb4d-pn86t   1/1     Running   0          8s    170.16.0.193     k8node1   <none>           <none>
tomcat-f556bbb4d-wvf7c   1/1     Running   0          8s    170.17.184.130   k8node2   <none>           <none>

凡是分配到 k8node1 节点上的pod,ip 为 170.16.0.0/16 范围内,比如 170.16.0.194 和 170.16.0.193
凡是分配到 k8node2 节点上的pod,ip 为 170.17.0.0/16 范围内,比如 170.17.184.130 和 170.17.184.131

应用五:基于namespace指定IP池

步骤1:查看当前存在的IP池
# kubectl exec -it -n kube-system calicoctl -- calicoctl get ippools
NAME                  CIDR             SELECTOR   
default-ipv4-ippool   192.168.0.0/16   all()   
# kubectl get ippools.crd.projectcalico.org
NAME                  AGE
default-ipv4-ippool   18h
步骤2:创建新的IP池
# cat> ippool.yaml <<EOF
apiVersion: crd.projectcalico.org/v1
kind: IPPool
metadata:
  name: test-ipv4-ippool
spec:
  cidr: 170.252.0.0/29
  ipipMode: Always  
  natOutgoing: true  
  nodeSelector: all()  
  vxlanMode: NeverEOF
# kubectl apply -f ippool.yaml
# kubectl exec -it -n kube-system 
calicoctl -- calicoctl get ippools
NAME                  CIDR             SELECTOR   
default-ipv4-ippool   192.168.0.0/16   all()      
test-ipv4-ippool      170.252.0.0/29   all()     # 这个 ippool 是新创建的
步骤3:创建新的namespace,并指定IP池
# kubectl create ns test-ippool
namespace/test-ippool created
# kubectl annotate namespace test-ippool "cni.projectcalico.org/ipv4pools"='["test-ipv4-ippool"]'
namespace/test-ippool annotated
# kubectl describe ns test-ippool 
Name:         test-ippoolLabels:       <none>
Annotations:  cni.projectcalico.org/ipv4pools: ["test-ipv4-ippool"]
Status:       ActiveNo resource quota.No resource limits.
步骤4:创建应用测试

注意namespace设置test-ippool

# cat >tomcat.yaml<<EOF
apiVersion: apps/v1
kind: Deployment
metadata:
  name: tomcat
  namespace: test-ippool
spec:
  replicas: 3  
  selector:
      matchLabels:
            app: tomcat
  template:
      metadata:
            labels:
                    app: tomcat
      spec:
            containers:
                  - name: tomcat        
                     image: tomcat:7.0.70        
                     ports:        
                     - containerPort: 8080          
                       protocol: TCP
apiVersion: v1
kind: Service
metadata:
  name: tomcat  
  namespace: test-ippool
spec:
  type: NodePort  
  ports:  
  - port: 8080    
    targetPort: 8080    
    nodePort: 32080  
  selector:
      app: tomcat
# kubectl apply -f tomcat.yaml
# kubectl get pod -n test-ippool -o wide
NAME                     READY   STATUS    RESTARTS   AGE    IP            NODE      NOMINATED NODE   READINESS GATES
tomcat-f556bbb4d-fjdwn   1/1     Running   0          105s   170.252.0.5   k8node1   <none>           <none>
tomcat-f556bbb4d-sbcrr   1/1     Running   0          17m    170.252.0.3   k8node2   <none>           <none>
tomcat-f556bbb4d-zjw87   1/1     Running   0          105s   170.252.0.6   k8node1   <none>           <none>
小结

小结:
(1) 创建 ippool
(2) 创建命名空间
(3) ippool 和 ns 绑定
(4) 在这个 ns 下新建 deployment-service,这个ns下的pod,其 ip在 170.252.0.0/29 范围内

四、尾声

总结一下本文学到的,如下:

第一,学会查看 ippool 整个yaml文件中,各个属性什么意思:整个 k8s 集群的网络路由,每个Pod都会有一个calico网卡,同一机器的Pod之间通信直接使用 calico网卡,不同机器的Pod之间通信要通过 tul0 网卡路由。如果开发中遇到问题,同一机器的Pod之间可以通信,不同机器的Pod之间无法通信,要么是tul0网卡缺失或错误,要么是路由route缺失或错误

第二,对于各种业务需求,如果使用 IPPool 来完成:给Pod指定IP池、给Pod指定静态IP、将 ippool 绑定到 ns 上、将 ippool 绑定到 node 上

Calico的组成:一个deploy calico-kube-controller和一个daemonSet calico-node
Calico的功能:
(1) 作为一个 CNI 网络插件,像 Flannel 一样,需要完成Pod之间的网络通信,包括两种情况,在相同Node上的Pod、在不同Node上的Pod
(2) 相对于Flannel,提供了两个高级功能,网络策略NetworkPolicy和固定IP(通过IPPool)实现

这篇文章,我们学习了作为一个 CNI 网络插件,像 Flannel 一样,需要完成Pod之间的网络通信,包括两种情况,在相同Node上的Pod、在不同Node上的Pod,以及如果通过 IPPool 来给Pod配置固定IP,这个IPPool不是k8s的资源是,而是calico的自定义crd资源。

注意:K8S的资源通过 kubectl get api-resources 来查看

参考文档:pod设置静态IP以及设置IP范围