亚马逊AWS官方博客

使用 Amazon VPC CNI 插件搭建自定义网络环境的 Kubernetes 集群

背景介绍

在AWS上搭建Kubernetes(简称K8S)集群环境,推荐使用托管服务EKS

无论是使用托管还是自建K8S集群,在有些场景下,需要让Pod间的通信管理可以像EC2的网络地址和通信一样的灵活,从而实现在同一个K8S集群内:Pod间通信可以跨子网,跨VPC,主机与Pod分属不同子网和安全组的灵活配置。

通过Amazon VPC CNI插件的使用,Pod可以分配到在 VPC 网络上的 IP 地址。用户可以实现同一个K8S集群部署在:

  • 一个VPC内,主机与Pod使用相同子网及安全组
  • 一个VPC内,主机与Pod使用不同子网及安全组
  • 多个VPC内,主机与Pod使用相同子网及安全组
  • 多个VPC内,主机与Pod使用不同子网及安全组

在集群内,每台主机都可以使用单独的子网网段,同样每台主机内的Pod也可以使用各自独立的子网网段。

EKS目前不支持同个集群的worker节点部署在多VPC内。尽管通过CNI可以实现自建K8S集群的多VPC部署方案,仍然推荐同个集群单VPC的部署方式来降低复杂度和维护成本。

本文使用的示例环境基于CentOS7自建K8S集群部署CNI的默认及自定义网络配置。

 

1. 什么是CNI

AWS上建议使用EKS 搭建K8S集群环境,同时可以使用Amazon VPC CNI插件管理Pod的网络地址和通信。

使用了AWS VPC CNI插件允许Pod在Pod 内具有与其在 VPC 网络上相同的 IP 地址。此 CNI 插件是一个在 GitHub 上进行维护的开源项目。

更多细节可参考EKS Pod联网指南

 

2. CNI部署选项

针对EKS集群CNI的部署,可参考GitHub项目说明

针对自建K8S集群CNI的部署,官方用户指南是只针对EKS,使用了EKS的AMI镜像,在步骤上会与自建的有些差异。

CNI的配置变量提供了很多部署选项。默认情况下,在为 Pod 分配新的网络接口时,ipamD 将使用工作线程节点的主弹性网络接口的安全组和子网。但是,在一些使用案例中,Pod 网络接口将在控制层面安全组所在的 VPC 中使用不同的安全组或子网。详细信息可参考CNI自定义网络

 

3. 如何安装K8S及CNI插件

3.1 启动EC2

使用EKS托管服务推荐使用EKS节点的镜像,而自建则取决于系统要求,这里选用CentOS 7。

在EC2控制面板里启动实例,选用CentOS 7镜像。

在选择实例大小时,要注意每个实例类型的每个网络接口的 IP 地址是不一样的,会直接决定K8S所能分配给Pod的IP数量,所以一定要根据每个节点的Pod数量要求来选择实例大小。

为EC2创建好单独角色及配上所需策略。

3.2 配置EC2网络

根据是否要启用CNI自定义网络配置的业务场景,请参照不同步骤。

3.2.1 使用默认网络配置

1) 为主机创建子网和安全组,主机内Pod也会应用上与主机相同的子网和安全组。在这里要选好子网大小,Pod节点数目受限于子网大小。

2) 将EC2创建到该子网和安全组内。

网络接口数量及所分配IP数受实例大小限制,也取决于集群Pod数量要求。可根据需要添加更多数量的网络接口。

在默认网络配置模式下,主机的主网络接口将被分配到子网内多个IP,只有一个IP供主机使用。附加的其它网络接口也将被分配到同一子网内多个IP,除一个主机IP外,剩下IP都会分配给Pod使用。

3.2.2 使用自定义网络配置

1) 为主机创建子网和安全组,并为Pod单独创建子网和安全组。

K8S集群节点受限于主机子网大小,Pod节点数受限于Pod子网大小。

示例中:K8S主机所属子网为vpc1-private-3,Pod所属的子网(vpc1-private-pod)。

2) 将EC2创建到主机所属子网内。

网络接口数量及所分配IP数受实例大小限制,也取决于集群Pod数量要求。可根据需要添加更多数量的网络接口。

在自定义网络配置模式下,主机的主网络接口将被分配到主机子网内一个IP,只供主机使用。附加的其它网络接口将被分配到Pod子网内多个IP,都会分配给Pod使用。

3.3 安装K8S及CNI

实例启动后,运行以下命令安装K8S。

  • 更新yum包
sudo yum -y update
  • 定义k8s镜像源

编辑/etc/yum.repos.d/kubernetes.repo

国外可用

[kubernetes]

name=Kubernetes

baseurl=https://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64/

enabled=1

gpgcheck=0

国内可用

[kubernetes]

name=Kubernetes

baseurl=https://packages.cloud.google.com/yum/repos/kubernetes-el7-x86_64

enabled=1

gpgcheck=1

repo_gpgcheck=1

gpgkey=https://packages.cloud.google.com/yum/doc/yum-key.gpg

https://packages.cloud.google.com/yum/doc/rpm-package-key.gpg
  • 关闭selinux
sudo sed -i 's/SELINUX=enforcing/SELINUX=disabled/' /etc/selinux/config

sudo setenforce 0
  • 安装K8S及CNI插件
sudo yum install -y docker kubelet-1.15.0 kubeadm-1.15.0 kubectl-1.15.0 kubernetes-cni-0.7.5

注意指定了K8S 1.15.0版本

CNI插件目前最高支持K8S版本为1.15,不确定1.16支持程度。

https://github.com/aws/amazon-vpc-cni-k8s/tree/master/config

环境中安装完成版本如下

  • 启动docker及kubelet
sudo systemctl enable docker

sudo systemctl start docker

sudo systemctl enable kubelet

sudo systemctl start kubelet

3.4 初始化K8S

使用kubeadm配置,也可用二进制自定义配置。

sudo kubeadm init

配置目录

mkdir -p $HOME/.kube

sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config

sudo chown $(id -u):$(id -g) $HOME/.kube/config

3.5 配置CNI

下载CNI配置文件

curl -o aws-k8s-cni.yaml https://raw.githubusercontent.com/aws/amazon-vpc-cni-k8s/master/config/v1.5/aws-k8s-cni.yaml

示例使用了1.5版本https://github.com/aws/amazon-vpc-cni-k8s/tree/master/config/v1.5

CNI会接管EC2的网络接口,创建新的网络接口并分配指定子网内的IP,并附加到EC2上,在Pod创建时会将已分配给网络接口的IP分配给Pod

3.5.1 用默认网络配置

1) 应用默认配置

应用CNI配置

kubectl apply -f aws-k8s-cni.yaml

配好后,EC2会自动添加网络接口,并且自动分配IP池,都同属于与主机一样的子网资源。接下来通过K8S创建的Pod就会自动分配到这个IP池里的IP。

2) 添加worker节点

示例中若只有一个节点演示,可将master节点设为worker节点。

kubectl taint nodes --all node-role.kubernetes.io/master-

建议添加独立worker节点,为每个节点重复’启动EC2’, ‘配置EC2网络’, ‘安装K8S及CNI’的步骤。

在每个节点运行加入K8S集群的命令。(注意替换master节点IP及token)

sudo kubeadm join 10.0.2.120:6443 –token cxgdjx.2ytbx05a53e9ywhd \

--discovery-token-ca-cert-hash sha256:26da48cb3759b4eac65cc9b9b1145910a05a855acb296125875effe05b814f26

worker节点可以创建在:

  • 与master节点相同VPC相同的子网内

  • 与master节点相同VPC不同的子网内(需要设置master节点与worker节点的安全组允许相互通信)

  • 与master节点不同VPC不同的子网内(需要设置VPC之间的路由通信,通过VPC Peering或Transit Gateway,以及master节点与work节点的安全组允许相互通信)

分属不同网络的worker节点都可以加入到同一个集群内。在本演示集群里包含了与master节点相同VPC相同子网,相同VPC不同子网,不同VPC不同子网的3个worker节点。

在不同worker节点跑的pod可以分配到对应归属子网的IP。

各pod间可以相互通信。

3.5.2 使用自定义网络配置

1) 应用自定义配置

编辑aws-k8s-cni.yaml,添加AWS_VPC_K8S_CNI_CUSTOM_NETWORK_CFG 环境变量添加到节点容器规范并将它设置为 true,保存文件。


...

spec:

containers:

- env:

- name: AWS_VPC_K8S_CNI_CUSTOM_NETWORK_CFG

value: "true"

- name: AWS_VPC_K8S_CNI_LOGLEVEL

value: DEBUG

- name: MY_NODE_NAME

...

使用以下命令将该文件应用于集群。

kubectl apply -f aws-k8s-cni.yaml

Master节点会只有一个网络接口及IP。

2) 添加worker节点

添加独立worker节点,为每个节点重复’启动EC2’, ‘配置EC2网络’, ‘安装K8S及CNI’的步骤。

在每个节点运行加入K8S集群的命令。(注意替换master节点IP及token)

sudo kubeadm join 10.0.2.120:6443 –token cxgdjx.2ytbx05a53e9ywhd \

--discovery-token-ca-cert-hash sha256:26da48cb3759b4eac65cc9b9b1145910a05a855acb296125875effe05b814f26

在自定义网络配置下,Pod可以与主机分属不同的子网。

单独为每个worker节点创建独立的子网。

单独为每个worker节点创建独立的ENIConfig

  • 创建一个名为 custom-pod-netconfig-node-x.yaml的文件(x可为节点名称,做为每个节点网络配置的唯一标识,与文件中的metadata->name一致),并将以下内容粘贴到该文件中
  • 把安全组和子网替换成为该节点Pod单独创建的安全组和子网。
apiVersion: crd.k8s.amazonaws.com/v1alpha1

kind: ENIConfig

metadata:

name: custom-pod-netconfig-node-x

spec:

securityGroups:

- sg-0dff363a7d37c3c61

subnet: subnet-017b472c2f79fdf96

 

使用以下命令将该文件应用于集群

kubectl apply -f custom-pod-netconfig-node-x.yaml

单独为每个节点设置与其ENIConfig一致的注释。

注意替换节点名称和节点网络配置。

kubectl annotate node ip-10-0-3-239.ec2.internal

k8s.amazonaws.com/eniConfig=custom-pod-netconfig-node-x

CNI会自动为该节点创建自定义子网和安全组的网络接口并附到节点实例。

worker节点可以创建在:

与master节点相同VPC相同的子网内

与master节点相同VPC不同的子网内(需要设置master节点与worker节点的安全组允许相互通信)

与master节点不同VPC不同的子网内(需要设置VPC之间的路由通信,通过VPC Peering或Transit Gateway,以及master节点与work节点的安全组允许相互通信)

如果出现了在配置完节点,但节点并没有自动创建新的网络接口情况,可以通过手动添加在指定Pod子网的网络接口并附到主机上来解决。

注意:只有在CNI没有成功创建CNI接口时才需要手动操作。

添加网络接口,并将子网选定为为Pod所属的子网。

将网络接口附到主机实例上。

重启kubelet

分属不同网络的worker节点都可以加入到同一个集群内。在本演示集群里包含了与master节点相同VPC相同子网,相同VPC不同子网,不同VPC不同子网的3个worker节点。

在不同worker节点跑的pod可以分配到对应归属子网的IP。

各pod间可以相互通信。

3.6 检查网络通信

在iptables里默认把FORWARD设为DROP,需要手动改成ACCEPT。


 

另外需要检查主机和Pod所在的安全组,子网和路由的通信规则。

最终实现了Pod间在自定义网络下通过VPC区段的IP来互相通信。

 

4. 资料参考

K8S集群网络https://kubernetes.io/docs/concepts/cluster-administration/networking/

CNI自定义网络指南:https://docs.aws.amazon.com/zh_cn/eks/latest/userguide/cni-custom-network.html

CNI GitHub https://github.com/aws/amazon-vpc-cni-k8s

CNI 原理https://github.com/aws/amazon-vpc-cni-k8s/blob/master/docs/cni-proposal.md

CNI 排错https://github.com/aws/amazon-vpc-cni-k8s/blob/master/docs/troubleshooting.md

EKS workshop CNI配置https://eksworkshop.com/advanced-networking/secondary_cidr/eniconfig_crd/

本篇作者

林煜晨

AWS解决方案架构师,负责互联网行业云端架构咨询和设计。曾就职于汤森路透8年,参于金融数据平台设计研发,在元数据管理和流程自动化有丰富经验。从事微软解决方案开发及咨询5年,微软认证技术专家。