用ovs-docker让容器网络支持Vlan隔离

2024-06-12 13:38

本文主要是介绍用ovs-docker让容器网络支持Vlan隔离,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

参考文献:
https://blog.csdn.net/canxinghen/article/details/50321573

docker原生使用linux bridge来创建网桥,这样无法使用vlan容器间的网络进行网络隔离。
openvswitch社区提供了一个工具ovs-docker来给docker快速搭建ovs网络。

1、使用ovs创建网桥

ovs-vsctl add-br br0

2、创建3个容器,容器网络模型设置为none

2.1、拉取测试镜像busybox

docker pull busybox:latest

2.2、创建容器

docker run -it -d --name routerA --net=none --privileged busybox
docker run -it -d --name routerB --net=none --privileged busybox
docker run -it -d --name routerC --net=none --privileged busybox

3、使用ovs-docker给容器添加网口

ovs-docker add-port br0 eth0 routerA --ipaddress=192.168.100.1/24
ovs-docker add-port br0 eth0 routerB --ipaddress=192.168.100.2/24
ovs-docker add-port br0 eth1 routerB --ipaddress=192.168.200.2/24
ovs-docker add-port br0 eth0 routerC --ipaddress=192.168.100.3/24

上面给容器routeB,添加了两个网卡;


可见,通过ovs-docker 给容器添加网卡时,会在逻辑交换机上添加端口,在宿主机上添加接口信息

4、测试容器之间是否连通

5、设置vlan隔离

设置Vlan的参数为:网桥名、容器内网口名、容器名、vlan号

ovs-docker set-vlan br0 eth0 routerA 100
ovs-docker set-vlan br0 eth0 routerB 100
ovs-docker set-vlan br0 eth1 routerB 200
ovs-docker set-vlan br0 eth0 routerC 203


6、测试是否连通呢?

7、ovs-docker原理介绍

ovs-docker简单又好用,它的原理就是用netns和veth来作容器和ovs网桥间的桥接!

#!/bin/bash#检查对应的可执行程序有没有在$PATH目录下
#检查的可执行程序有 ovs-vsctl、docker、uuidgen
search_path () {save_IFS=$IFSIFS=:for dir in $PATH; doIFS=$save_IFSif test -x "$dir/$1"; thenreturn 0fidoneIFS=$save_IFSecho >&2 "$0: $1 not found in \$PATH, please install and try again"exit 1
}#给所有的ovs-vsctl命令增加超时时间
ovs_vsctl () {ovs-vsctl --timeout=60 "$@"
}#每个容器是一个netns
#但是只有在 /va/run/netns 下面建立链接,才能将veth挂在到该netns里面
#也只有了链接,才能用ip netns list查询到
create_netns_link () {mkdir -p /var/run/netnsif [ ! -e /var/run/netns/"$PID" ]; thenln -s /proc/"$PID"/ns/net /var/run/netns/"$PID"trap 'delete_netns_link' 0for signal in 1 2 3 13 14 15; do#在收到特定信号后,删掉链接#这些信号有:程序退出、ctrl+c、进程被杀掉等trap 'delete_netns_link; trap - $signal; kill -$signal $$' $signaldonefi
}#删除链接
delete_netns_link () {rm -f /var/run/netns/"$PID"
}#从ovs的数据库中查询port
#查询条件是在创建port的时候设进去的 external_ids 
get_port_for_container_interface () {CONTAINER="$1"INTERFACE="$2"PORT=`ovs_vsctl --data=bare --no-heading --columns=name find interface \external_ids:container_id="$CONTAINER"  \external_ids:container_iface="$INTERFACE"`if [ -z "$PORT" ]; thenecho >&2 "$UTIL: Failed to find any attached port" \"for CONTAINER=$CONTAINER and INTERFACE=$INTERFACE"fiecho "$PORT"
}#给容器添加port,原理是创建一个veth,一端挂在ovs网桥上,一端设到netns里面
add_port () {BRIDGE="$1"INTERFACE="$2"CONTAINER="$3"#参数验证if [ -z "$BRIDGE" ] || [ -z "$INTERFACE" ] || [ -z "$CONTAINER" ]; thenecho >&2 "$UTIL add-port: not enough arguments (use --help for help)"exit 1fi#获取附加参数:ip地址、mac地址、网关信息、mtu信息shift 3while [ $# -ne 0 ]; docase $1 in--ipaddress=*)ADDRESS=`expr X"$1" : 'X[^=]*=\(.*\)'`shift;;--macaddress=*)MACADDRESS=`expr X"$1" : 'X[^=]*=\(.*\)'`shift;;--gateway=*)GATEWAY=`expr X"$1" : 'X[^=]*=\(.*\)'`shift;;--mtu=*)MTU=`expr X"$1" : 'X[^=]*=\(.*\)'`shift;;*)echo >&2 "$UTIL add-port: unknown option \"$1\""exit 1;;esacdone#查看对应容器的特定端口是否已经存在# Check if a port is already attached for the given container and interfacePORT=`get_port_for_container_interface "$CONTAINER" "$INTERFACE" \2>/dev/null`if [ -n "$PORT" ]; thenecho >&2 "$UTIL: Port already attached" \"for CONTAINER=$CONTAINER and INTERFACE=$INTERFACE"exit 1fi#网桥不存在就创建网桥if ovs_vsctl br-exists "$BRIDGE" || \ovs_vsctl add-br "$BRIDGE"; then :; elseecho >&2 "$UTIL: Failed to create bridge $BRIDGE"exit 1fi#通过docker inspect命令获取容器的PID(netns的id)if PID=`docker inspect -f '{{.State.Pid}}' "$CONTAINER"`; then :; elseecho >&2 "$UTIL: Failed to get the PID of the container"exit 1fi#为后面将veth打入netns,需要建立链接create_netns_link#创建一个veth对,veth的名字用uuid,加了“_l”后缀的是挂在网桥上的,加了“_c”的是挂在容器内ID=`uuidgen | sed 's/-//g'`PORTNAME="${ID:0:13}"ip link add "${PORTNAME}_l" type veth peer name "${PORTNAME}_c"# 将“_l”挂到网桥上,挂时增加external_ids信息用于后面查找和删除if ovs_vsctl --may-exist add-port "$BRIDGE" "${PORTNAME}_l" \-- set interface "${PORTNAME}_l" \external_ids:container_id="$CONTAINER" \external_ids:container_iface="$INTERFACE"; then :; elseecho >&2 "$UTIL: Failed to add "${PORTNAME}_l" port to bridge $BRIDGE"ip link delete "${PORTNAME}_l"exit 1fi#拉起“_l”的veth端口ip link set "${PORTNAME}_l" up#将“_c”移到容器的netns里面ip link set "${PORTNAME}_c" netns "$PID"#将“_c”改名为用户设置的接口名,例如ethxip netns exec "$PID" ip link set dev "${PORTNAME}_c" name "$INTERFACE"ip netns exec "$PID" ip link set "$INTERFACE" up#设置mtuif [ -n "$MTU" ]; thenip netns exec "$PID" ip link set dev "$INTERFACE" mtu "$MTU"fi#设置ipif [ -n "$ADDRESS" ]; thenip netns exec "$PID" ip addr add "$ADDRESS" dev "$INTERFACE"fi#设置macif [ -n "$MACADDRESS" ]; thenip netns exec "$PID" ip link set dev "$INTERFACE" address "$MACADDRESS"fi#设置网关if [ -n "$GATEWAY" ]; thenip netns exec "$PID" ip route add default via "$GATEWAY"fi
}#根据添加port时的external_ids查询port后删除
del_port () {BRIDGE="$1"INTERFACE="$2"CONTAINER="$3"if [ "$#" -lt 3 ]; thenusageexit 1fiPORT=`get_port_for_container_interface "$CONTAINER" "$INTERFACE"`if [ -z "$PORT" ]; thenexit 1fiovs_vsctl --if-exists del-port "$PORT"ip link delete "$PORT"
}del_ports () {BRIDGE="$1"CONTAINER="$2"if [ "$#" -lt 2 ]; thenusageexit 1fiPORTS=`ovs_vsctl --data=bare --no-heading --columns=name find interface \external_ids:container_id="$CONTAINER"`if [ -z "$PORTS" ]; thenexit 0fifor PORT in $PORTS; doovs_vsctl --if-exists del-port "$PORT"ip link delete "$PORT"done
}#使用ovs的set port tag的方式设置vlan
set_vlan () {BRIDGE="$1"INTERFACE="$2"CONTAINER_ID="$3"VLAN="$4"if [ "$#" -lt 4 ]; thenusageexit 1fiPORT=`get_port_for_container_interface "$CONTAINER_ID" "$INTERFACE"`if [ -z "$PORT" ]; thenexit 1fiovs_vsctl set port "$PORT" tag="$VLAN"
}usage() {cat << EOF
${UTIL}: Performs integration of Open vSwitch with Docker.
usage: ${UTIL} COMMANDCommands:add-port BRIDGE INTERFACE CONTAINER [--ipaddress="ADDRESS"][--gateway=GATEWAY] [--macaddress="MACADDRESS"][--mtu=MTU]Adds INTERFACE inside CONTAINER and connects it as a portin Open vSwitch BRIDGE. Optionally, sets ADDRESS onINTERFACE. ADDRESS can include a '/' to represent networkprefix length. Optionally, sets a GATEWAY, MACADDRESSand MTU.  e.g.:${UTIL} add-port br-int eth1 c474a0e2830e--ipaddress=192.168.1.2/24 --gateway=192.168.1.1--macaddress="a2:c3:0d:49:7f:f8" --mtu=1450del-port BRIDGE INTERFACE CONTAINERDeletes INTERFACE inside CONTAINER and removes itsconnection to Open vSwitch BRIDGE. e.g.:${UTIL} del-port br-int eth1 c474a0e2830edel-ports BRIDGE CONTAINERRemoves all Open vSwitch interfaces from CONTAINER. e.g.:${UTIL} del-ports br-int c474a0e2830eset-vlan BRIDGE INTERFACE CONTAINER VLANConfigures the INTERFACE of CONTAINER attached to BRIDGEto become an access port of VLAN. e.g.:${UTIL} set-vlan br-int eth1 c474a0e2830e 5
Options:-h, --help        display this help message.
EOF
}#查看$PATH是否存在对应的命令
UTIL=$(basename $0)
search_path ovs-vsctl
search_path docker
search_path uuidgenif (ip netns) > /dev/null 2>&1; then :; elseecho >&2 "$UTIL: ip utility not found (or it does not support netns),"\"cannot proceed"exit 1
fiif [ $# -eq 0 ]; thenusageexit 0
fi#根据输入的参数决定动作
case $1 in"add-port")shiftadd_port "$@"exit 0;;"del-port")shiftdel_port "$@"exit 0;;"del-ports")shiftdel_ports "$@"exit 0;;"set-vlan")shiftset_vlan "$@"exit 0;;-h | --help)usageexit 0;;*)echo >&2 "$UTIL: unknown command \"$1\" (use --help for help)"exit 1;;
esac

把上面的脚本,放到这个目录下,就行
文件名是ovs-docker

这篇关于用ovs-docker让容器网络支持Vlan隔离的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1054376

相关文章

Spring核心思想之浅谈IoC容器与依赖倒置(DI)

《Spring核心思想之浅谈IoC容器与依赖倒置(DI)》文章介绍了Spring的IoC和DI机制,以及MyBatis的动态代理,通过注解和反射,Spring能够自动管理对象的创建和依赖注入,而MyB... 目录一、控制反转 IoC二、依赖倒置 DI1. 详细概念2. Spring 中 DI 的实现原理三、

SSID究竟是什么? WiFi网络名称及工作方式解析

《SSID究竟是什么?WiFi网络名称及工作方式解析》SID可以看作是无线网络的名称,类似于有线网络中的网络名称或者路由器的名称,在无线网络中,设备通过SSID来识别和连接到特定的无线网络... 当提到 Wi-Fi 网络时,就避不开「SSID」这个术语。简单来说,SSID 就是 Wi-Fi 网络的名称。比如

Java实现任务管理器性能网络监控数据的方法详解

《Java实现任务管理器性能网络监控数据的方法详解》在现代操作系统中,任务管理器是一个非常重要的工具,用于监控和管理计算机的运行状态,包括CPU使用率、内存占用等,对于开发者和系统管理员来说,了解这些... 目录引言一、背景知识二、准备工作1. Maven依赖2. Gradle依赖三、代码实现四、代码详解五

更改docker默认数据目录的方法步骤

《更改docker默认数据目录的方法步骤》本文主要介绍了更改docker默认数据目录的方法步骤,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一... 目录1.查看docker是否存在并停止该服务2.挂载镜像并安装rsync便于备份3.取消挂载备份和迁

Docker集成CI/CD的项目实践

《Docker集成CI/CD的项目实践》本文主要介绍了Docker集成CI/CD的项目实践,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学... 目录一、引言1.1 什么是 CI/CD?1.2 docker 在 CI/CD 中的作用二、Docke

如何在一台服务器上使用docker运行kafka集群

《如何在一台服务器上使用docker运行kafka集群》文章详细介绍了如何在一台服务器上使用Docker运行Kafka集群,包括拉取镜像、创建网络、启动Kafka容器、检查运行状态、编写启动和关闭脚本... 目录1.拉取镜像2.创建集群之间通信的网络3.将zookeeper加入到网络中4.启动kafka集群

如何用Docker运行Django项目

本章教程,介绍如何用Docker创建一个Django,并运行能够访问。 一、拉取镜像 这里我们使用python3.11版本的docker镜像 docker pull python:3.11 二、运行容器 这里我们将容器内部的8080端口,映射到宿主机的80端口上。 docker run -itd --name python311 -p

Linux 网络编程 --- 应用层

一、自定义协议和序列化反序列化 代码: 序列化反序列化实现网络版本计算器 二、HTTP协议 1、谈两个简单的预备知识 https://www.baidu.com/ --- 域名 --- 域名解析 --- IP地址 http的端口号为80端口,https的端口号为443 url为统一资源定位符。CSDNhttps://mp.csdn.net/mp_blog/creation/editor

ASIO网络调试助手之一:简介

多年前,写过几篇《Boost.Asio C++网络编程》的学习文章,一直没机会实践。最近项目中用到了Asio,于是抽空写了个网络调试助手。 开发环境: Win10 Qt5.12.6 + Asio(standalone) + spdlog 支持协议: UDP + TCP Client + TCP Server 独立的Asio(http://www.think-async.com)只包含了头文件,不依

poj 3181 网络流,建图。

题意: 农夫约翰为他的牛准备了F种食物和D种饮料。 每头牛都有各自喜欢的食物和饮料,而每种食物和饮料都只能分配给一头牛。 问最多能有多少头牛可以同时得到喜欢的食物和饮料。 解析: 由于要同时得到喜欢的食物和饮料,所以网络流建图的时候要把牛拆点了。 如下建图: s -> 食物 -> 牛1 -> 牛2 -> 饮料 -> t 所以分配一下点: s  =  0, 牛1= 1~