前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >玩转tke的混合网络模式

玩转tke的混合网络模式

原创
作者头像
聂伟星
修改2021-02-05 19:05:16
1.6K0
修改2021-02-05 19:05:16
举报

tke上腾讯云有提供2中网络模式,分别是Global Router(下面我们简称GR)和vpc-cni,这2种网络模式的优劣,如何选型可以参考https://cloud.tencent.com/document/product/457/44966,那么什么是tke的混合网络模式呢,首先我们看看tke的网络模式有哪几种。

tke中可以存在以下几种网络模式:

  • GR类型
  • vpc-cni类型
  • GR+vpc-cni类型(注意这里只能是创建集群时候选择GR,后续再开启vpc-cni。如果创建集群选择的是vpc-cni,后续是无法再时区GR)

其实混合网络模式就是创建集群时候网络选择GR,然后后续开启vpc-cni这个网络模式附加到集群上,今天我们重点讲讲GR+vpc-cni的混合网络模式下如何使用,什么场景下我们需要用到它,使用的时候需要注意什么。

我们在部署应用到k8s中有个非常常见的场景,就是希望从应用程序中获取到真实的客户端ip信息,但是如果你的应用部署在GR模式的集群中,这点就无法实现,程序提供给外界访问通常是通过service或者ingress暴露,在腾讯云上都是创建一个lb来关联你的service和ingress,在GR的模式下,pod所在的容器网络是平行于vpc的一个虚拟网络,当客户端通过lb请求后端的是否,lb也是处于vpc网络中,所以lb只能将请求转发到后端cvm的nodeport上,然后再通过cni组件的虚拟网卡cbr0讲请求转发到pod里面,这样从pod端来看,客户端就变成了虚拟网卡cbr0的ip了,因此在GR上无法获取真是客户端ip,其实真实流量转发如下:

client----->clb----->cvm(nodeport)----->pod

那么如果我想在获取到客户端的真实ip那应该怎么办呢,其实去掉nodeport到pod直接这一层转发就可以,也就是让clb能直接访问到pod,这样clb可以直接将客户端ip透传给后端pod,pod就能拿到真实的客户端ip,但是要想clb直接将流量转发到pod,那么需要pod和clb处于同一个网络层面,都在vpc内,很明显在GR上这个是实现不了的,所以这里需要用到vpc-cni模式,其实vpc-cni模式就是从vpc中划分出一部分子网给pod作为ip,这样就可以让pod和clb都在vpc这个网络层面上了,那样流量转发就是下面这样:

client----->clb----->pod

如果你创建集群选的就是vpc-cni,那么这个问题就不用担心了,但是如果创建你选择的GR类型,那么想获取客户端ip,就需要做一些额外的操作了,就需要用到GR+vpc-cni这种混合网络模式了,下面我们来具体讲讲这种模式怎么使用。

1. 启用混合网络模式

首先我们创建一个GR模式的tke集群,然后在集群的基本信息中找到开启vpc-cni模式的按钮,点击开启

这里会让你选择一个空的子网来用于vpc-cni的模式下,pod ip也都是从这个子网中获取,混合模式下默认是启用固定ip功能的,如果你创建集群选择的是vpc-cni,那么这个功能可选可不选,如果你希望你的pod销毁后ip可以重复使用,可以配置ip回收策略,默认是不回收,pod销毁后最小回收时间是300s,这里我们配置成300,这里建议配置这个策略,避免后续子网ip不够分配给pod。

由于混合网络下只能添加一个子网的现在,我们后面就会面临一个问题,那就是我们节点只能部署在vpc-cni模式的子网相同可用区,为什么会有这个限制,其实你看下vpc-cni的网络架构就明白了

vpc-cni其实就是给每个节点分配一个辅助网卡,然后从网卡中分配ip给pod,由于腾讯云上弹性网卡需要和cvm处于同一个可用区,我这里选择的是广州4区的子网作为vpc-cni的子网,那么弹性网卡也是从广州4区分配,这也就意味着你的cvm也是要在广州4区,但是tke这边为了高可用,通常是多可用去部署,那么这个问题该怎么解决呢?

首先我么测试下看看,如果添加一个其他可用区的节点会发生什么情况,这里我们选择加入一个广州6区的节点

点击添加后会出现报错checkClusterNetworkScale failed, err:DashboardError,Code : -1100000 , Msg : Network scale error[IP for pods in Zone ap-guangzhou-6 is not enough to scale out 1 nodes.], err : nil

这个报错就是提示我们广州6区没有可用的ip分配给pod,因为我们vpc-cni模式没有广州6区的子网。

难道我们就无法添加其他可用区的机器了,其实了解一下vpc-cni的插件部署你就明白可以怎么处理了

从上图我们可以看出,vpc-cni其实就是部署一个server端和每个节点部署agent客户端,tke-eni-agent从tke-eni-ipamd获取可用的子网信息,然后挂上弹性网卡,从子网中分配一部分ip信息给节点作为pod ip,既然是这样,那就说明子网信息都是存在tke-eni-ipamd这个服务端pod里面的,如果我们加一个广州6区的子网到服务端中,那么后面就可以加广州6区的机器到集群了。

kube-system下有个cm记录这vpc-cni模式的子网信息,我们将广州6区的子网加到这个cm中,看看能不能加广州6区的节点到集群,我们在vpc下找到建好的广州6区的空子网,然后通过kubectl命令将子网信息加到cm中,kube-system只能通过命令操作

代码语言:javascript
复制
[root@VM-0-51-tlinux ~]# kubectl edit cm -n kube-system tke-eni-ipamd
configmap/tke-eni-ipamd edited

# Please edit the object below. Lines beginning with a '#' will be ignored,
# and an empty file will abort the edit. If an error occurs while saving this file will be
# reopened with the relevant failures.
#
apiVersion: v1
data:
  TKE_ENI_IPAMD_SUBNET_ID: subnet-f3m8i0xi:subnet-ef66oja6
  TKE_ENI_IPAMD_VPC_ID: vpc-p1v99tgl
  TKE_ENI_IPAMD_ZONE: ap-guangzhou-4:ap-guangzhou-6
kind: ConfigMap
metadata:
  creationTimestamp: "2021-02-05T09:16:25Z"
  managedFields:
  - apiVersion: v1
    fieldsType: FieldsV1
    fieldsV1:
      f:data:
        .: {}
        f:TKE_ENI_IPAMD_SUBNET_ID: {}
        f:TKE_ENI_IPAMD_VPC_ID: {}
        f:TKE_ENI_IPAMD_ZONE: {}
    manager: tke-controller-manager
    operation: Update
    time: "2021-02-05T09:16:25Z"
  name: tke-eni-ipamd
  namespace: kube-system
  resourceVersion: "1034266769"
  selfLink: /api/v1/namespaces/kube-system/configmaps/tke-eni-ipamd
  uid: 20392b09-3c24-4c4b-bd18-aaa0bef2b90a
代码语言:javascript
复制
[root@VM-0-51-tlinux ~]# kubectl delete pod tke-eni-ipamd-6ffbcf6f44-p6wk7 -n kube-system
pod "tke-eni-ipamd-6ffbcf6f44-p6wk7" deleted
[root@VM-0-51-tlinux ~]# kubectl get pod -n kube-system | grep eni
tke-eni-agent-7h6jm                 1/1     Running   0          28m
tke-eni-ipamd-6ffbcf6f44-mwphj      1/1     Running   0          100s

修改之后重建下让cm挂载生效,等待pod重启成功后,现在我们再加一下广州6区的节点到集群

这里我们再添加节点就没有校验报错了,说明我们添加广州6区节点到集群成功了。

2. deployment类型pod获取客户端ip

上面已经说过了,获取客户端ip只需要pod在vpc-cni的模式就行,那么deployment类型如果让pod部署在vpc-cni模式下呢?

首先我们正常创建一个pod,看看是什么样,如果直接通过service访问,能否获取到客户端ip。

代码语言:javascript
复制
[root@VM-0-3-centos ~]# ip addr | grep eth0
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
    inet 10.0.0.3/24 brd 10.0.0.255 scope global eth0
[root@VM-0-3-centos ~]# curl 10.0.8.11
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>

直接在控制台创建一个pod,然后创建service是没有直连的选项,因为pod默认还是在GR下,我们在客户端ip为10.0.0.3的机器上访问service,在pod的日志中发现ip并不是真是客户端ip,我们前面讲过这里请求到了node节点,再由cbr0这虚拟网卡将请求转发到pod,那么192.168.0.65这个ip就是虚拟网卡的ip,所以pod中日志的客户端ip就是虚拟网卡cbr0的ip

那么我们如何将pod部署在vpc-cni下呢?这里我们需要在yaml里面配置下才让让eni组件能识别到,这样才会部署到vpc-cni模式下

代码语言:javascript
复制
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deploy
  namespace: default
spec:
  progressDeadlineSeconds: 600
  replicas: 1
  revisionHistoryLimit: 10
  selector:
    matchLabels:
      k8s-app: nginx-deploy
      qcloud-app: nginx-deploy
  strategy:
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 0
    type: RollingUpdate
  template:
    metadata:
      annotations:
        tke.cloud.tencent.com/networks: tke-route-eni
      creationTimestamp: null
      labels:
        k8s-app: nginx-deploy
        qcloud-app: nginx-deploy
    spec:
      containers:
      - image: nginx
        imagePullPolicy: Always
        name: nginx-deploy
        resources:
          limits:
            cpu: 500m
            memory: 1Gi
            tke.cloud.tencent.com/eni-ip: "1"
          requests:
            cpu: 250m
            memory: 256Mi
            tke.cloud.tencent.com/eni-ip: "1"
        securityContext:
          privileged: false
        terminationMessagePath: /dev/termination-log
        terminationMessagePolicy: File
      dnsPolicy: ClusterFirst
      imagePullSecrets:
      - name: qcloudregistrykey
      restartPolicy: Always
      schedulerName: default-scheduler
      securityContext: {}
      terminationGracePeriodSeconds: 30

这里我们需要在spec.template.metadata.annotations这个字段加上tke.cloud.tencent.com/networks: tke-route-eni的注解,然后再

resources的requeset和limit加上tke.cloud.tencent.com/eni-ip:"1"的数量,保存后重建下pod

添加了字段后可以发现我们的pod和节点是同一个网段,说明pod在vpc-cni的模式下了。

下面我们分别给负载配置直连的service和ingress,然后通过ingress和service访问pod,看看pod能否获取到我们的客户端ip

代码语言:javascript
复制
[root@VM-0-51-tlinux ~]# kubectl get svc
NAME           TYPE           CLUSTER-IP     EXTERNAL-IP   PORT(S)        AGE
kubernetes     ClusterIP      192.168.12.1   <none>        443/TCP        86m
nginx-deploy   LoadBalancer   192.168.14.0   10.0.8.10     80:30535/TCP   50s
[root@VM-0-51-tlinux ~]# kubectl get ingress
NAME                   CLASS    HOSTS   ADDRESS    PORTS   AGE
nginx-deploy-ingress   <none>   *       10.0.8.8   80      19s

下面我们在其他vpc内集群访问下service看看,这里我们的客户端ip是10.0.0.13

代码语言:javascript
复制
[root@VM-0-13-centos ~]# ip addr | grep eth0
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
    inet 10.0.0.13/24 brd 10.0.0.255 scope global eth0
[root@VM-0-13-centos ~]# curl 10.0.8.10
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>

然后我们通过访问ingress的ip看看,这里我们的客户是10.0.0.3

代码语言:javascript
复制
[root@VM-0-3-centos ~]# ip addr | grep eth0
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
    inet 10.0.0.3/24 brd 10.0.0.255 scope global eth0
[root@VM-0-3-centos ~]# curl 10.0.8.8
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>

从上面来看,我们通过service和ingress都能在pod获取到客户端的真实ip。

3. StatefulSet类型pod获取客户端ip

下面我们说说StatefulSet的pod应该怎么操作,其实在tke控制提供了选项,是否将pod部署在vpc-cni下,因此StatefulSet就不需要通过修改yaml的方式

创建StatefulSet的时候我们可以在高级选项中勾选使用vpc-cni模式,并且选择固定ip,并配置一个直连的service。

下面我们在10.0.0.3中访问下StatefulSet的pod

代码语言:javascript
复制
[root@VM-0-3-centos ~]# ip addr | grep eth0
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
    inet 10.0.0.3/24 brd 10.0.0.255 scope global eth0
[root@VM-0-3-centos ~]# curl 10.0.0.239
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>

可以发现我们在pod中获取到了客户端的ip,说明pod现在是vpc-cni的模式下,这里我们也可以看看固定ip是怎么配置的

其实就是需要在spec.template.metadata.annotations这个字段加上注解tke.cloud.tencent.com/vpc-ip-claim-delete-policy: Never,这样pod ip就固定了。StatefulSet中配置ingress直连pod这个我们就不配置了,和deployment的一样配置一个直连ingress转发到后端的service就行。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. 启用混合网络模式
  • 2. deployment类型pod获取客户端ip
  • 3. StatefulSet类型pod获取客户端ip
相关产品与服务
弹性网卡
弹性网卡(Elastic Network Interface,ENI)是绑定私有网络内云服务器 的一种弹性网络接口,可在多个云服务器间自由迁移。您可以在云服务器上绑定多个弹性网卡,实现高可用网络方案;也可以在弹性网卡上绑定多个内网 IP,实现单主机多 IP 部署。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档