亚马逊AWS官方博客

在 Amazon EKS 上运行 Flannel 和 Weave Net 网络插件

一.背景描述

Amazon Elastic Kubernetes Service (Amazon EKS) 是一项托管服务,可让您在 AWS 上轻松运行 Kubernetes,而无需支持或维护您自己的 Kubernetes 控制层面。

Amazon EKS  默认使用适用于 Kubernetes 的AWS VPC容器网络接口(CNI)插件,此插件将虚拟私有云(VPC)的IP地址分配给Pod使用。使用 AWS VPC CNI 插件可以获得以下的优势:第一,跨主机通信时无需对Pod流量进行网络封装和解封装,减少开销;第二,每个Pod分配一个节点弹性网络接口(ENI)的辅助IP地址,来自VPC的流量可以直接路由到Pod;第三,由于较少的Pod共享弹性网络接口(ENI),可以减少对网络带宽的争用;第四,可以使用VPC流日志来捕获有关进出集群的Pod的IP流量的信息。

在大部分的场景下,由于AWS VPC CNI的上述优势,推荐在Amazon EKS 上使用此插件。但是在某些情况下,AWS VPC CNI插件有其自身的挑战。例如,EC2实例的类型和大小决定了可以在实例上运行的容器的数量;或者,您的VPC可能受到IP限制,以致于无法将VPC的IP地址分配给Pod,尽管AWS VPC CNI自定义网络功能允许您为Pod网络指定一组单独的子网来解决此问题,但这可能不适用于您的网络规划和要求。

您可以在Amazon EKS上部署其它的网络插件,比如 Flannel 和 Weave Net,但使用其它网络插件需要您额外的管理和维护工作,例如在Amazon EKS使用Flannel需要您自己维护一个etcd集群。这篇文章描述如何在Amazon EKS上部署和使用Flannel和Weave Net CNI。

二.在 Amazon EKS 上运行 Flannel

Flannel的部署和使用包括以下步骤:

  • 创建Amazon EKS集群,删除默认配置的 AWS VPC CNI
  • 创建 etcd Server 用于存储 Flannel 网络配置信息
  • 部署 Flannel DaemonSet
  • 创建 Amazon EKS 工作节点,创建 Pod并测试网络连通性

1.创建Amazon EKS集群,删除默认配置的 AWS VPC CNI

1)使用 eksctl 创建 Amazon EKS 集群,设置工作节点数为0;有关使用 eksctl 创建集群的更多详细信息可参考https://eksctl.io/

$ eksctl create cluster --name cnidemo --ssh-access --ssh-public-key <ec2_keypair_name> --nodes 0

Amazon EKS集群创建完成后,默认会配置使用 AWS VPC CNI,VPC CNI使用名为 aws-node 的 DaemonSet,当有工作节点加入集群时,每个工作节点上会启动这个 DaemonSet。为了不影响 Flannel CNI 的运行,需要在工作节点创建之前删除 aws-node 并配置使用 Flannel DaemonSet。

2)删除 aws-node DaemonSet

$ kubectl delete ds aws-node -n kube-system

2.创建 etcd Server 用于存储 Flannel 网络配置信息

Flannel 可以使用 Kubernetes API(kube subnet manager 模式)或者 etcd 集群作为其后台存储,由于 Amazon EKS 控制平面为AWS 托管,不能在 API Server 上设置 Pod CIDR 信息,因此需要部署一个额外的 etcd Server 来存储 Flannel的网络配置信息。

首先安装 CoreOS Config Transpiler 来为 etcd Server 准备所需的配置信息。

1)安装 Config Transpiler

$ brew install coreos-ct

2)获取 etcd集群的 TOKEN,在这里创建单节点的集群

$ TOKEN=$(curl -sw "\n" 'https://discovery.etcd.io/new?size=1' | cut -d "/" -f 4)

3)使用获取的 TOKEN 创建 yaml 文件。在以下 etcd.yaml 文件中替换 TOKEN为b步骤中获取的字符串

# This config is meant to be consumed by the config transpiler, which will

# generate the corresponding Ignition config. Do not pass this config directly

# to instances of Container Linux.

 

etcd:

  # All options get passed as command line flags to etcd.

  # Any information inside curly braces comes from the machine at boot time.

  

advertise_client_urls:       "http://{PRIVATE_IPV4}:2379"

  initial_advertise_peer_urls: "http://{PRIVATE_IPV4}:2380"

  listen_client_urls:          "http://0.0.0.0:2379"

  listen_peer_urls:            "http://{PRIVATE_IPV4}:2380"

  discovery:                   "https://discovery.etcd.io/<TOKEN>"

4)使用Config Transpiler将 yaml 转换成ignition configuration,作为etcd Server创建时的userdata

$ ct -platform=ec2 < etcd.yaml > ec2metadata

使用刚才创建的ec2metadata文件作为userdata,创建etcd Server实例。

5)创建 etcd Server 实例

$ aws ec2 run-instances --image-id <coreos_ami_id> --instance-type t2.small --key-name <ec2_keypair_name> --security-group-ids <sg_ids> --subnet-id <subnet_id> --user-data file://ec2metadata

其中:

  • coreos_ami_id:使用CoreOS官方提供的稳定版本,具体可参见https://coreos.com/os/docs/latest/booting-on-ec2.html
  • security-group-ids:将etcd Server加入Amazon EKS集群工作节点所在的安全组,这使得 etcd Server 和工作节点上的 Flannel DaemonSet 之间可以互相通信

3.部署Flannel DaemonSet

1)登录 etcd Server,写入Flannel所需的网络配置信息

$ ssh -i <ec2_keypair_name> core@<etcd_Server_ip>

$ etcdctl mk /flannel/vxlan/network/config '{"Network":"10.16.0.0/16", "SubnetLen": 24, "Backend": {"Type": "vxlan", "VNI": 1}}'

Flannel不支持etcd v3 API,如果使用 v3 API,Flannel会无法获取etcd上的配置信息。因此在配置etcd时使用默认的v2 API即可,保证网络配置的Key在v2 API中存在。

2)修改Flannel YAML文件中的配置信息

  • ConfigMap中net-conf.json:修改为您在步骤a中写入etcd的实际 network配置信息。在这里使用 Backend Type 为 VXLAN模式,Flannel 也支持其他模式,比如 aws-vpc。可参考 https://coreos.com/flannel/docs/latest/backends.html
  • DaemonSet中–etcd-endpoints:修改为您的 etcd Server endpoint 地址,可登录到etcd Server 上查看
$ ssh -i <ec2_keypair_name> core@<etcd_server_ip>

$ etcdctl member list

  • DaemonSet中–etcd-prefix:修改为您在步骤a中写入etcd的实际prefix(在上面的示例中prefix为/flannel/vxlan/network/),默认是/coreos.com/network/

kube-flannel-amd64.yml 文件如下:

kind: ClusterRole

apiVersion: rbac.authorization.k8s.io/v1beta1

metadata:

  name: flannel

rules:

  - apiGroups:

      - ""

    resources:

      - pods

    verbs:

      - get

  - apiGroups:

      - ""

    resources:

      - nodes

    verbs:

      - list

      - watch

  - apiGroups:

      - ""

    resources:

      - nodes/status

    verbs:

      - patch

---

kind: ClusterRoleBinding

apiVersion: rbac.authorization.k8s.io/v1beta1

metadata:

  name: flannel

roleRef:

  apiGroup: rbac.authorization.k8s.io

  kind: ClusterRole

  name: flannel

subjects:

- kind: ServiceAccount

  name: flannel

  namespace: kube-system

---

apiVersion: v1

kind: ServiceAccount

metadata:

  name: flannel

  namespace: kube-system

---

kind: ConfigMap

apiVersion: v1

metadata:

  name: kube-flannel-cfg

  namespace: kube-system

  labels:

    tier: node

    app: flannel

data:

  cni-conf.json: |

    {

      "name": "cbr0",

      "plugins": [

        {

          "type": "flannel",

          "delegate": {

            "hairpinMode": true,

            "isDefaultGateway": true

          }

        },

        {

          "type": "portmap",

          "capabilities": {

            "portMappings": true

          }

        }

      ]

    }

  net-conf.json: |

    {

      "Network": "10.16.0.0/16",

      "Backend": {

        "Type": "vxlan"

      }

    }

---

apiVersion: extensions/v1beta1

kind: DaemonSet

metadata:

  name: kube-flannel-ds-amd64

  namespace: kube-system

  labels:

    tier: node

    app: flannel

spec:

  template:

    metadata:

      labels:

        tier: node

        app: flannel

    spec:

      hostNetwork: true

      nodeSelector:

        beta.kubernetes.io/arch: amd64

      tolerations:

      - operator: Exists

        effect: NoSchedule

      serviceAccountName: flannel

      initContainers:

      - name: install-cni

        image: quay.io/coreos/flannel:v0.11.0-amd64

        command:

        - cp

        args:

        - -f

        - /etc/kube-flannel/cni-conf.json

        - /etc/cni/net.d/10-flannel.conflist

        volumeMounts:

        - name: cni

          mountPath: /etc/cni/net.d

        - name: flannel-cfg

          mountPath: /etc/kube-flannel/

      containers:

      - name: kube-flannel

        image: quay.io/coreos/flannel:v0.11.0-amd64

        command:

        - /opt/bin/flanneld

        args:

        - --ip-masq

        - --kube-subnet-mgr=false

        - --etcd-endpoints=http://192.168.42.131:2379

        - --etcd-prefix=/flannel/vxlan/network/

        resources:

          requests:

            cpu: "100m"

            memory: "50Mi"

          limits:

            cpu: "100m"

            memory: "50Mi"

        securityContext:

          privileged: true

        env:

        - name: POD_NAME

          valueFrom:

            fieldRef:

              fieldPath: metadata.name

        - name: POD_NAMESPACE

          valueFrom:

            fieldRef:

              fieldPath: metadata.namespace

        volumeMounts:

        - name: run

          mountPath: /run

        - name: flannel-cfg

          mountPath: /etc/kube-flannel/

      volumes:

        - name: run

          hostPath:

            path: /run

        - name: cni

          hostPath:

            path: /etc/cni/net.d

        - name: flannel-cfg

          configMap:

            name: kube-flannel-cfg

3)部署Flannel DaemonSet

$ kubectl apply -f kube-flannel-amd64.yml

4.创建Amazon EKS 工作节点,创建 Pod并测试网络连通性

1)在EC2界面上,修改工作节点所在的AutoScaling Group,将数量增加为2

2)工作节点就绪后,查看 Flannel DaemonSet 在工作节点上的运行情况。

通过 Flannel Pod日志可以看到 Flannel成功的从 etcd Server读取了网络配置信息,并且在每个工作节点上分配了子网写入了/run/flannel/subnet.env文件。

登录到工作节点上,可以看到两个节点的 /run/flannel/subnet.env 文件都已经正确写入:

两个节点分别分配了 10.16.85.1/24 和10.16.51.1/24两个网段。

登录到 etcd Server上,也可以查看到Flannel记录到etcd中的 Subnet信息。


3)创建Pod,并测试网络连通性

创建的Pod分布在两个节点上(两个节点位于不同的AZ),并且正确的分配了10.16.85.1/24 和10.16.51.1/24两个网段的IP地址。

测试结果:相同/不同节点上的Pod之间可以相互通信;Pod可以与各个节点互相通信。

三.在 Amazon EKS 上运行 Weave Net

Weave的部署和使用包括以下步骤:

  • 创建Amazon EKS集群,删除默认配置的 AWS VPC CNI
  • 部署 Weave DaemonSet
  • 创建 Amazon EKS 工作节点,创建 Pod并测试网络连通性

Weave CNI插件的部署比较简单,它不需要外部存储来存放网络配置,因此不需要像Flannel 那样部署额外的etcd集群。

1.创建Amazon EKS集群,删除默认配置的 AWS VPC CNI

1)使用 eksctl 创建 Amazon EKS 集群,设置工作节点数为0

$ eksctl create cluster --name cnidemo --ssh-access --ssh-public-key <ec2_keypair_name> --nodes 0

2)删除 aws-node DaemonSet

$ kubectl delete ds aws-node -n kube-system

2.部署 Weave Net DaemenSet

在部署插件之前,需要修改Amazon EKS工作节点所在安全组,允许TCP 6783和UDP 6783/6784端口,以便Weave Net控制平面可以和数据平面通信。

部署Weave Net CNI

$ kubectl apply -f "https://cloud.weave.works/k8s/net?k8s-version=$(kubectl version | base64 | tr -d '\n')"

3.创建Amazon EKS 工作节点,创建 Pod并测试网络连通性

1)在EC2界面上,修改工作节点所在的AutoScaling Group,将数量增加为2

2)工作节点就绪后,查看 Weave Net DaemonSet 在工作节点上的运行情况

通过在 Weave Net Pod里运行  weave status 命令可以看到其运行状况,默认使用的网段是 10.32.0.0/12,可以在部署 Weave Net时通过配置选项修改网段信息,或者下载 weave-daemonset.yaml 文件自己修改后部署。

在 kubectl apply -f 时增加配置选项修改网段信息,例如:

$ kubectl apply -f "https://cloud.weave.works/k8s/net?k8s-version=$(kubectl version | base64 | tr -d '\n')&env.IPALLOC_RANGE=20.16.0.0/16"

下载 weave-daemonset.yaml 文件,支持的配置信息可参考 https://www.weave.works/docs/net/latest/kubernetes/kube-addon/#-changing-configuration-options

$ curl -fsSLo weave-daemonset.yaml "https://cloud.weave.works/k8s/net?k8s-version=$(kubectl version | base64 | tr -d '\n')" 

3)创建Pod,并测试网络连通性

创建的Pod分布在两个节点上(两个节点位于不同的AZ),并且正确的分配了10.32.0.0/12网段的IP地址。

测试结果:相同/不同节点上的Pod之间可以相互通信;Pod可以与各个节点互相通信。

四.参考资料

本篇作者

郭勋

AWS 解决方案架构师,负责基于 AWS 的云计算方案的架构设计,同时致力于 AWS 云服务在移动应用与互联网行业的应用和推广,有十年的云计算和云管理平台解决方案架构经验。