写点什么

当 Kubernetes 遇见 Macvlan

作者:陆云
  • 2022-11-22
    上海
  • 本文字数:2596 字

    阅读完需:约 9 分钟

当Kubernetes遇见Macvlan

最近在研究 KubeVirt 和 Virtink 两个项目,计划做一个 Operator 管理虚拟机。Kubernetes API 有望成为云计算基础设施管理的事实标准,IaaS 关注计算、存储和网络,相比 OpenStack,Kubernetes 是一个可塑性更强的项目。


在 Kubernetes 管理虚拟机的场景下,容器网络就是虚拟机网络。目前没有做双网卡方案,我需要把容器网络拉平到物理网络,方便直接登录虚拟机。为了保持架构简单清爽,我放弃了 multus、coredns 和 kube-proxy。这个方案仅为兴趣使然,并不适用于生产环境。

实验准备

我的实验设备是一台 Dell 机架服务器,它的基础信息如下。如果你打算自己实验,下文中用到内网 IP 的地方换成自己的 IP 就可以。


安装 Kubernetes

你可以使用Sealos丝滑安装 Kubernetes。Sealos 是一个轻量的二进制工具,可以搞定 Kubernetes 安装中的一些常见痛点。包括但不限于 Linux 配置、组件镜像和高可用集群。 Sealos 的安装和使用请参考官方文档,这里不做赘述。我使用的 Sealos 版本为 4.1.3,Kubernetes 版本为 1.23.13,下面是我的 Clusterfile。


apiVersion: apps.sealos.io/v1beta1kind: Clustermetadata:  name: defaultspec:  # 我的环境只有一台机器  hosts:  - ips:    - 192.168.0.5:22    roles:    - master    - amd64  # 匹配sealos 4.1.3版本的kubernetes镜像  image:  - labring/kubernetes:v1.23.13-4.1.3  # 请确保ssh可以通过公钥直接登录  ssh:    pk: /root/.ssh/id_rsa    port: 22
---
apiVersion: kubeadm.k8s.io/v1beta3kind: ClusterConfigurationnetworking: # 这里设置为和物理网络相同的网段 podSubnet: 192.168.0.0/16---
apiVersion: kubeadm.k8s.io/v1beta3kind: InitConfiguration# 跳过coredns和kube-proxy的安装skipPhases:- addon/coredns- addon/kube-proxy
复制代码


你只需要一条命令就可以安装 Kubernetes 集群。


$ sealos apply -f Clusterfile
复制代码


macvlan 虚拟的设备插入到容器 network namespace 以后,其中的流量就不经过主机 network namespace 了,依赖 iptables/ipvs 实现的 service 全然无用,kube-proxy 和 coredns 自然也成了摆设。


我是单节点 Kubernetes,这里需要去掉 master 上的 taint,使得 Pod 可以调度到 master。


$ kubectl taint node lyr620 node-role.kubernetes.io/master-
复制代码

配置 CNI Plugin

你需要下载官方出品的CNI Plugins,我使用了 1.1.1 版本。将下载的压缩包解压到 Kubernetes 默认的 CNI 插件目录。


$ mkdir -p /opt/cni/bin$ tar -zxvf cni-plugins-linux-amd64-v1.1.1.tgz -C /opt/cni/bin
复制代码


在/etc/cni/net.d 目录下创建一个 00-default.conflist 文件,写入如下内容。


{    "cniVersion": "0.4.0",    "name": "default",    "plugins": [        {            "type": "macvlan",            "master": "eno1",            "ipam": {                "type": "host-local",                "ranges": [                    [                        {                            "subnet": "192.168.0.0/16",                            "rangeStart": "192.168.1.2",                            "rangeEnd": "192.168.1.254",                            "gateway": "192.168.0.1"                        }                    ]                ],                "routes": [                    {"dst": "0.0.0.0/0"}                ]            }        }    ]}
复制代码


我的机器上只有 eno1 这个网卡连接到了公司内网,所以指定 macvlan 插件在 eno1 上创建子设备分配给容器。这里的 IPAM 子网配置到主机网络 192.168.0.0/16,但是将 IP 池限制在 192.168.1.0/24 这个子网的 IP 范围。


之前也尝试过将 subnet 设置为 192.168.1.0/24,主机为之添加相应的路由,但是这个方案没能成功,其中有些问题以我的内功暂时还玩不动......

验证 Pod 网络

检查 Kubernetes Node 是否就绪。


$ kubectl get nodesNAME     STATUS   ROLES                  AGE     VERSIONlyr620   Ready    control-plane,master   5h33m   v1.23.13
复制代码


创建一个 Nginx Deployment,观察 Pod 是否 Running,查看容器的路由表。


$ kubectl create deployment nginx --image nginx:stable-alpine
$ kubectl get pods -o wideNAMESPACE NAME READY STATUS RESTARTS AGE IP default nginx-7bd849c599-cbgqn 1/1 Running 0 5s 192.168.1.2
$ kubectl exec nginx-7bd849c599-cbgqn -it -- ip routedefault via 192.168.0.1 dev eth0192.168.0.0/16 dev eth0 scope link src 192.168.1.2
复制代码


虽然 Pod 已经 Running,但这时从主机 ping 容器是不通的。


$ ping -c 3 192.168.1.2PING 192.168.1.2 (192.168.1.2) 56(84) bytes of data.From 192.168.0.5 icmp_seq=1 Destination Host UnreachableFrom 192.168.0.5 icmp_seq=2 Destination Host UnreachableFrom 192.168.0.5 icmp_seq=3 Destination Host Unreachable
--- 192.168.1.2 ping statistics ---3 packets transmitted, 0 received, +3 errors, 100% packet loss, time 2027mspipe 3
复制代码


从容器 ping 主机也不行。


$ kubectl exec -it nginx-7bd849c599-cbgqn -- ping -c 3 192.168.0.5PING 192.168.0.5 (192.168.0.5): 56 data bytes
--- 192.168.0.5 ping statistics ---3 packets transmitted, 0 packets received, 100% packet loss
复制代码


为了满足 Kubernetes 主机和容器网络互通的需求,我们需要在主机的 network namespace 创建并启动一个 bridge 模式的 macvlan 子设备。


$ ip link add eno1.host link eno1 type macvlan mode bridge$ ip link set dev eno1.host up
复制代码


然后在主机上写一条直通 Pod IP 的路由。


$ ip route add 192.168.1.2 dev eno1.host$ ip routedefault via 192.168.0.1 dev eno1 proto static192.168.0.0/16 dev eno1 proto kernel scope link src 192.168.0.5192.168.1.2 dev eno1.host scope link
复制代码


这时容器和主机就互通了,你不但可以 ping 通 Pod IP,而且访问 Pod IP 还可以看见 Nginx 的网页。


$ curl http://192.168.1.2<!DOCTYPE html><html>...</html>
复制代码

参考资料


发布于: 刚刚阅读数: 4
用户头像

陆云

关注

还未添加个人签名 2019-11-08 加入

SRE / DeoOps

评论

发布
暂无评论
当Kubernetes遇见Macvlan_陆云_InfoQ写作社区