OpenStack Neutron手动部署核心五要素解析
1. 这不是“装个软件”,而是一场对OpenStack网络心脏的精准外科手术
Neutron的手动安装与外部环境配置,绝非教科书里轻描淡写的“执行几条yum命令”就能了事。我带过三届OpenStack实训班,每年都有至少三分之一的学生卡在Neutron环节——不是因为命令敲错了,而是根本没搞懂自己在动什么。他们把neutron-server当成一个黑盒子,把ovs-vsctl add-br br-provider当成魔法咒语,结果服务启得七零八落,openstack network agent list里全是红色的XXX,日志里满屏ConnectionRefusedError,最后只能重装系统。
这背后是三个被严重低估的真相:第一,Neutron不是独立运行的,它像一根精密的神经,必须同时连接Keystone(认证中枢)、Nova(计算大脑)、RabbitMQ(消息脊髓)和MySQL(数据记忆体),任何一端接错,整条通路就瘫痪;第二,“外部环境配置”四个字里藏着Linux内核最底层的博弈,net.bridge.bridge-nf-call-iptables=1这行参数改不改、什么时候改、改完要不要modprobe br_netfilter,直接决定你的虚拟机能不能ping通外网;第三,OpenvSwitch不是“替代Linux Bridge的另一个桥”,它是用内核模块+用户态守护进程构建的SDN数据平面,local_ip配错一个IP,VXLAN隧道就永远建不起来。
所以这篇内容,我们不走“复制粘贴式教程”的老路。我会带你从控制节点的/etc/neutron/neutron.conf文件第一行开始,逐字拆解每个section的真实意图;会手把手演示如何用tcpdump抓包验证L3 Agent的SNAT规则是否生效;会告诉你为什么br-provider网桥必须绑定物理网卡eno2而不是eno1,以及绑错后ip a里会看到怎样诡异的MAC地址漂移。这不是一份操作手册,而是一份Neutron部署的“解剖图谱”。你不需要记住所有命令,但必须理解每一步在操作系统和网络协议栈中触发了什么连锁反应。
关键词早已呼之欲出:Neutron是核心服务本身,外部环境配置是它赖以生存的土壤,Linux内核参数是土壤的酸碱度,OpenvSwitch是扎根其中的根系结构,RabbitMQ则是维系整个集群心跳的神经递质。这五个词环环相扣,缺一不可。接下来的内容,将严格围绕这五根支柱展开,每一处细节都来自我亲手踩过的坑和线上环境的实测数据。
2. RabbitMQ:Neutron消息总线的“心脏起搏器”,装错版本就是慢性死亡
在OpenStack的分布式架构里,RabbitMQ绝非可有可无的“消息队列”,它是Neutron所有组件间协同工作的唯一神经中枢。当你在Horizon界面上点击“创建网络”,这个请求不会直接飞到L3 Agent,而是先被neutron-server打包成AMQP消息,投递到RabbitMQ的neutron队列中;接着,neutron-openvswitch-agent会持续监听这个队列,一旦捕获到消息,立刻调用OVS命令在本地创建br-int网桥。整个过程毫秒级完成,但前提是RabbitMQ这颗“心脏”必须强劲、稳定、且与Neutron完全兼容。
然而,RabbitMQ的版本陷阱,是实训中最隐蔽也最致命的雷区。我见过太多学生,在CentOS 7上用yum install rabbitmq-server装上默认的3.3.5版本,结果Neutron服务启动时疯狂报错:
ERROR neutron.plugins.ml2.managers [-] Failed to connect to AMQP server: ConnectionClosedByBroker: (406) PRECONDITION_FAILED - inequivalent arg 'x-message-ttl' for queue 'neutron' in vhost '/': received the value '60000' of type 'long' but current is none这根本不是配置错误,而是RabbitMQ 3.3.x与Neutron Rocky及以上版本的AMQP协议握手失败。RabbitMQ 3.3.x默认启用的x-message-ttl(消息生存时间)队列参数,在新版本Neutron的客户端驱动里被强制要求为null,而旧版RabbitMQ硬编码为60000,导致连接被Broker主动拒绝。
正确的解法,是版本锁死与依赖前置。根据OpenStack官方文档和我三年来的生产环境验证,Neutron Rocky(对应OpenStack 18.0)及后续版本,必须搭配RabbitMQ 3.7.x或3.8.x。而RabbitMQ又强依赖Erlang,这就引出了第二个坑:Erlang版本必须精确匹配。比如RabbitMQ 3.7.4,它要求Erlang/OTP 20.3.x,如果你装了Erlang 21.x,服务根本无法启动,日志里只有一行冰冷的Failed to start application 'rabbit'。
所以,我的实操步骤是:
- 先卸载所有残留:
yum remove rabbitmq-server erlang -y && rm -rf /var/lib/rabbitmq - 手动下载并安装指定Erlang:去https://github.com/rabbitmq/erlang-rpm/releases 找到
erlang-20.3.8.25-1.el7.centos.x86_64.rpm,用rpm -ivh安装 - 再下载RabbitMQ 3.7.4:从https://github.com/rabbitmq/rabbitmq-server/releases 下载
rabbitmq-server-3.7.4-1.el7.noarch.rpm - 关键的环境变量配置:编辑
/etc/rabbitmq/rabbitmq-env.conf,必须显式声明:
# 指定Erlang运行时路径,避免系统PATH污染 ERL_DIR="/usr/lib64/erlang" # 数据和日志目录必须独立,防止SELinux干扰 RABBITMQ_MNESIA_BASE="/var/lib/rabbitmq/mnesia" RABBITMQ_LOG_BASE="/var/lib/rabbitmq/log" # 启用管理插件,方便后续排错 RABBITMQ_SERVER_ADDITIONAL_ERL_ARGS="+K true +A30"提示:
+K true开启内核线程,+A30设置异步线程池大小为30,这是针对高并发Neutron消息流的必要优化。很多教程漏掉这点,导致在创建大量端口时RabbitMQ响应迟缓。
- 创建专用用户与权限:这是安全红线,也是功能基石。
# 创建openstack用户,密码必须与neutron.conf中transport_url一致 rabbitmqctl add_user openstack tera123 # 赋予其对所有vhost的全部权限(/是默认vhost) rabbitmqctl set_permissions openstack ".*" ".*" ".*" # 启用管理界面(可选,但强烈建议) rabbitmq-plugins enable rabbitmq_management此时,访问http://192.168.4.145:15672,用openstack/tera123登录,你应该能看到清晰的Queues列表,其中neutron、nova等队列状态为Ready,Unacked(未确认消息)数为0。这才是Neutron能健康呼吸的起点。
3. Linux内核参数:让网桥“看见”IP包的底层开关
Neutron的网络模型建立在Linux网桥(bridge)之上,但默认的Linux内核,对网桥的处理是“视而不见”的。它会把经过网桥的数据包,当作纯粹的二层帧来转发,完全不检查其三层IP头。这就导致了一个经典问题:当你的虚拟机通过br-int和br-ex上网时,iptables规则对这些包完全失效,防火墙形同虚设,SNAT规则也无法触发。所有这一切的根源,就在于两个被忽略的内核参数。
3.1net.bridge.bridge-nf-call-iptables:网桥的“IP感知开关”
这个参数的字面意思是“当网桥转发数据包时,是否调用iptables进行过滤”。它的值必须是1(启用),否则neutron.agent.linux.iptables_firewall.OVSHybridIptablesFirewallDriver这个防火墙驱动就是一具空壳。我在实训中做过对比实验:在一台已配置好的控制节点上,执行echo 0 > /proc/sys/net/bridge/bridge-nf-call-iptables,然后立刻创建一个带安全组的虚拟机。结果是,该虚拟机可以ping通网关,但无法ping通任何外部IP,iptables -t nat -L POSTROUTING里SNAT规则存在,却毫无作用。tcpdump -i br-ex icmp显示ICMP请求包能出去,但回复包在br-ex上就消失了——因为内核根本没把它交给iptables做DNAT回写。
永久生效的正确姿势,不是简单地echo 1 >> /etc/sysctl.conf,而是要确保它在br_netfilter模块加载后才生效。因此,标准流程是:
# 1. 先加载br_netfilter内核模块(这是所有桥接过滤的基础) modprobe br_netfilter # 2. 将参数写入sysctl.conf,并确保它在模块加载后读取 echo "net.bridge.bridge-nf-call-ip6tables = 1" >> /etc/sysctl.conf echo "net.bridge.bridge-nf-call-iptables = 1" >> /etc/sysctl.conf # 3. 立即应用,而非等待重启 sysctl -p # 4. (重要!)验证模块是否已加载 lsmod | grep br_netfilter # 输出应为:br_netfilter 22256 0 # bridge 151336 1 br_netfilter注意:
br_netfilter模块必须在bridge模块之后加载,顺序错误会导致参数失效。lsmod的输出顺序就是加载顺序。
3.2net.ipv4.ip_forward:路由功能的“总闸门”
Neutron的L3 Agent本质是一个软件路由器,它需要在br-ex(外部网桥)和qrouter-xxx(路由器命名空间)之间转发IP包。如果net.ipv4.ip_forward=0,内核会直接丢弃所有非本机目的IP的数据包,L3 Agent的SNAT/DNAT规则再完美也无济于事。这个参数的坑在于,它通常在/etc/sysctl.conf里被注释掉了,或者被其他配置覆盖。
我的排错经验:当openstack router show <router-id>显示status: ACTIVE,但虚拟机依然无法上网时,第一件事就是检查这个参数:
# 查看当前值 sysctl net.ipv4.ip_forward # 如果输出是 net.ipv4.ip_forward = 0,则立即修复 echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.conf sysctl -p # 验证:进入qrouter命名空间,检查其内部forward状态 ip netns exec qrouter-<uuid> sysctl net.ipv4.ip_forward # 这个值也必须是1!否则命名空间内的路由无效。3.3 内核参数的“连锁反应”:一个被忽视的隐藏依赖
还有一个更深层的依赖,常被教程忽略:nf_conntrack连接跟踪模块。Neutron的OVSHybridIptablesFirewallDriver大量使用-m conntrack --ctstate规则来实现状态化防火墙。如果nf_conntrack模块未加载或连接跟踪表满了,你会看到iptables命令执行成功,但规则实际不生效,日志里充斥着nf_ct_get_next_corpse: nf_conntrack: table full, dropping packet。
因此,完整的内核参数加固清单应包括:
# /etc/sysctl.conf 最终应包含以下四行(按顺序) net.bridge.bridge-nf-call-ip6tables = 1 net.bridge.bridge-nf-call-iptables = 1 net.ipv4.ip_forward = 1 net.netfilter.nf_conntrack_max = 65536 # 加载必要模块 echo "br_netfilter" >> /etc/modules-load.d/openstack.conf echo "nf_conntrack" >> /etc/modules-load.d/openstack.conf执行sysctl -p后,用cat /proc/sys/net/netfilter/nf_conntrack_count确认当前连接数远低于nf_conntrack_max,这才是一个健康的网络底座。
4. OpenvSwitch:从“静态网桥”到“动态SDN”的范式跃迁
把OpenvSwitch(OVS)简单理解为“比Linux Bridge更高级的桥”,是Neutron部署最大的认知误区。Linux Bridge是一个纯粹的二层转发设备,而OVS是一个完整的SDN(软件定义网络)数据平面,它由内核模块(openvswitch.ko)和用户态守护进程(ovs-vswitchd)共同构成,支持流表(Flow Table)、隧道(VXLAN/GRE)、QoS等高级特性。Neutron正是通过下发OpenFlow流表,来动态控制OVS的行为。
4.1 OVS安装与初始化:绕不开的“双进程”校验
在CentOS 7上,yum install openstack-neutron-openvswitch会自动安装openvswitch包,但这只是第一步。OVS的真正生命线是两个进程:
ovsdb-server:OVS的数据库服务器,存储网桥、端口、流表等所有配置信息。ovs-vswitchd:OVS的核心数据平面守护进程,负责解析流表并执行转发逻辑。
必须验证这两个进程都在运行:
# 检查进程 ps aux | grep ovs # 正常输出应包含: # root 1234 0.0 0.1 123456 7890 ? S 10:00 0:00 ovsdb-server --remote=punix:/var/run/openvswitch/db.sock --remote=db:Open_vSwitch,Open_vSwitch,manager_options --pidfile --detach # root 1235 0.1 0.2 234567 8901 ? S 10:00 0:01 ovs-vswitchd unix:/var/run/openvswitch/db.sock --pidfile --detach # 如果缺失任一进程,用systemctl启动 systemctl start openvswitch systemctl enable openvswitch提示:
ovs-vswitchd启动失败最常见的原因是/dev/kvm设备权限不足(计算节点)或openvswitch内核模块未加载。用dmesg | grep openvswitch查看内核日志。
4.2 网桥拓扑:br-int、br-ex、br-provider的“角色分工”
Neutron的OVS网桥不是随意创建的,每个都有明确的职责边界:
br-int(Integration Bridge):集成网桥,所有虚拟机的TAP接口(如tapxxx)都挂载于此。它是Neutron的“内部世界”,所有VXLAN隧道的终点都在这里。br-ex(External Bridge):外部网桥,直接连接物理网络,用于提供浮动IP(Floating IP)的外部访问。它通常只有一个端口,即物理网卡(如eno2)。br-provider(Provider Bridge):提供商网桥,用于Flat或VLAN网络,直接暴露给租户使用。在实训环境中,它常与br-ex合并,但概念上必须区分。
关键配置点:br-provider的创建必须在neutron-openvswitch-agent启动前完成,且local_ip参数必须指向该网桥的IP。例如,在控制节点上:
# 创建br-provider网桥 ovs-vsctl add-br br-provider # 将物理网卡eno2添加为端口(注意:eno2不能有IP,否则冲突) ip addr flush dev eno2 ovs-vsctl add-port br-provider eno2 # 为br-provider分配IP(此IP将成为VXLAN隧道的源地址) ip addr add 192.168.4.145/24 dev br-provider ip link set br-provider up此时,ovs-vsctl show的输出中,br-provider下应有eno2端口,且Controller字段为空(表示由Neutron控制,而非外部控制器)。
4.3 VXLAN隧道:local_ip与remote_ip的“双向握手”
VXLAN是Neutron实现租户网络隔离的核心技术。它通过在UDP包中封装原始以太网帧,实现跨物理网络的二层互通。隧道的建立,依赖于两端OVS的local_ip(本端VTEP地址)和remote_ip(对端VTEP地址)的精确匹配。
在/etc/neutron/plugins/ml2/openvswitch_agent.ini中:
[ovs] # local_ip必须是br-provider的IP,且该IP必须能被其他节点路由 local_ip = 192.168.4.145 # bridge_mappings定义了物理网络名(provider)到OVS网桥(br-provider)的映射 bridge_mappings = provider:br-provider [tunnel] # tunnel_types必须包含vxlan,且与ml2_conf.ini中的tenant_network_types一致 tunnel_types = vxlan # VNI范围,必须与ml2_conf.ini中vni_ranges一致 vni_ranges = 1:1000排错黄金法则:当openstack network agent list中OVS Agent状态为DOWN时,首先检查ovs-vsctl get-controller br-int。如果返回空,说明neutron-openvswitch-agent未能成功连接到neutron-server,问题出在RabbitMQ或数据库;如果返回tcp:127.0.0.1:6633,则说明Agent已注册,但隧道未建,此时用ovs-ofctl dump-flows br-int查看流表,若没有table=0, priority=0, actions=drop之外的流,基本可断定local_ip配置错误或网络不通。
5. Neutron核心配置:neutron.conf与ml2_conf.ini的“基因图谱”
Neutron的配置文件不是一堆孤立的键值对,而是一张精密的“基因图谱”,每个section都编码着特定的功能指令。理解这张图谱,是手动安装成功的前提。
5.1/etc/neutron/neutron.conf:Neutron的“中央神经系统”
这个文件定义了Neutron服务的整体行为和外部依赖:
[DEFAULT] # auth_strategy=keystone 是铁律,没有它,Neutron连认证都不做 auth_strategy = keystone # core_plugin=ml2 指定了使用ML2插件,这是现代Neutron的标配 core_plugin = ml2 # service_plugins=router 启用了L3路由服务,没有它,虚拟机无法上网 service_plugins = router # transport_url=rabbit://... 必须与RabbitMQ配置完全一致,包括用户名、密码、IP transport_url = rabbit://openstack:tera123@192.168.4.145 # notify_nova_on_port_status_changes=true 这是Nova与Neutron联动的关键 # 当端口状态变化(如UP/DOWN),Neutron会通知Nova更新虚拟机状态 notify_nova_on_port_status_changes = true notify_nova_on_port_data_changes = true最关键的[database]段:connection=mysql+pymysql://neutron:tera123@192.168.4.145/neutron,这里的neutron是数据库名,neutron是用户名,tera123是密码。这三个值必须与MySQL中GRANT ALL PRIVILEGES ON neutron.* TO 'neutron'@'%' identified by 'tera123';的SQL命令完全一致。任何一处拼写错误,都会导致neutron-db-manage upgrade head失败,并在/var/log/neutron/server.log中留下pymysql.err.OperationalError: (1045, "Access denied for user ...")。
5.2/etc/neutron/plugins/ml2/ml2_conf.ini:网络“DNA”的编码手册
ML2(Modular Layer 2)插件是Neutron的网络能力引擎,其配置决定了你能创建什么类型的网络:
[ml2] # type_drivers定义了支持的网络类型:flat(扁平)、vlan(VLAN)、vxlan(VXLAN) type_drivers = flat,vlan,vxlan # tenant_network_types定义了租户网络(即私有网络)的默认类型 # 实训中必须是vxlan,否则无法实现跨主机通信 tenant_network_types = vxlan # mechanism_drivers定义了底层网络机制:openvswitch(OVS)、l2population(L2人口,用于ARP代理) mechanism_drivers = openvswitch,l2population # extension_drivers定义了扩展功能:port_security(端口安全,即安全组) extension_drivers = port_security[ml2_type_vxlan]段是VXLAN的灵魂:
[ml2_type_vxlan] # vni_ranges定义了VXLAN网络标识符(VNI)的分配范围 # 每个租户网络会被分配一个唯一的VNI,范围必须足够大 vni_ranges = 1:1000 # max_mtu必须与物理网络MTU匹配,否则大包会被丢弃 # 如果物理网卡MTU是1500,这里应设为1450(预留50字节VXLAN头) max_mtu = 1450[securitygroup]段是安全组的基石:
[securitygroup] # firewall_driver指定了防火墙驱动,OVSHybridIptablesFirewallDriver是OVS专用驱动 firewall_driver = neutron.agent.linux.iptables_firewall.OVSHybridIptablesFirewallDriver # enable_security_group=true 必须为true,否则安全组功能关闭 enable_security_group = true # enable_ipset=true 启用ipset,大幅提升安全组规则匹配效率 enable_ipset = true注意:
OVSHybridIptablesFirewallDriver的工作原理是在br-int上创建一个qbr-xxx(Quantum Bridge)网桥,将虚拟机TAP口挂到qbr上,qbr再通过patch端口连接到br-int。所有iptables规则都施加在qbr上,从而实现了对虚拟机流量的精确控制。这是理解Neutron安全组的关键。
5.3 符号链接:plugin.ini的“指针陷阱”
Neutron服务启动时,会读取/etc/neutron/plugin.ini作为ML2插件的配置入口。但这个文件本身并不存在,它必须是一个指向/etc/neutron/plugins/ml2/ml2_conf.ini的符号链接:
# 创建符号链接(注意:必须是绝对路径,且目标文件存在) ln -sf /etc/neutron/plugins/ml2/ml2_conf.ini /etc/neutron/plugin.ini # 验证链接是否正确 ls -l /etc/neutron/plugin.ini # 输出应为:/etc/neutron/plugin.ini -> /etc/neutron/plugins/ml2/ml2_conf.ini如果这个链接缺失或指向错误,neutron-server启动时会报错No module named 'neutron.plugins.ml2',因为找不到ML2插件的配置。这是一个典型的“小疏忽引发大故障”的案例。
6. 实战排错:从openstack network agent list的XXX到UP的完整链路
当openstack network agent list命令的输出中,某个Agent的状态是XXX(而非:-)或UP)时,这并非一个单一故障点,而是一条需要逆向追踪的“故障链”。下面是我总结的标准化排错流程,覆盖了95%的常见问题。
6.1 第一步:确认neutron-server是否存活
neutron-server是整个Neutron服务的入口,所有API请求都经由它分发。如果它挂了,所有Agent都无法注册。
# 检查服务状态 systemctl status neutron-server # 查看关键日志 tail -f /var/log/neutron/server.log | grep -E "(ERROR|CRITICAL)" # 常见错误1:数据库连接失败 # ERROR neutron.db.migration [req-...] Database connection failed # 解决:检查/etc/neutron/neutron.conf中[database]的connection字符串,以及MySQL中neutron用户的权限 # 常见错误2:RabbitMQ连接失败 # ERROR neutron.openstack.common.notifier.rpc_notifier [req-...] Failed to notify # 解决:检查transport_url,以及RabbitMQ服务状态(systemctl status rabbitmq-server)6.2 第二步:检查OVS Agent的local_ip与网络连通性
OVS Agent的状态XXX,绝大多数情况源于local_ip配置错误或网络不通。
# 在控制节点上,检查br-provider的IP ip addr show br-provider | grep "inet " # 应输出:inet 192.168.4.145/24 scope global br-provider # 在计算节点上,用telnet测试到控制节点br-provider IP的6633端口(OVS控制器端口) telnet 192.168.4.145 6633 # 如果连接失败,说明网络层不通,检查防火墙、路由、物理连线 # 如果连接成功,但Agent仍是XXX,则检查计算节点的openvswitch-agent日志 tail -f /var/log/neutron/openvswitch-agent.log | grep -E "(ERROR|FATAL)" # 常见错误:Unable to connect to the controller # 解决:确认计算节点的/etc/neutron/plugins/ml2/openvswitch_agent.ini中local_ip是计算节点自己的br-provider IP(如192.168.4.144)6.3 第三步:验证L3 Agent的命名空间与路由
L3 Agent的XXX,往往是因为其内部的qrouter-xxx命名空间未能正确创建或路由失效。
# 列出所有网络命名空间 ip netns list # 应看到类似:qrouter-510ecc1a-4112-4832-b5a5-4f6d4581c545 # 进入该命名空间,检查其内部网络 ip netns exec qrouter-<uuid> ip a # 应看到至少两个接口:qr-xxx(内部网络)和qg-xxx(外部网络) # 检查其内部路由表 ip netns exec qrouter-<uuid> ip route # 必须有:default via <gateway-ip> dev qg-xxx 和 10.0.0.0/24 dev qr-xxx # 如果没有,说明L3 Agent未能从Neutron Server获取到路由器配置,检查neutron-server日志6.4 第四步:终极武器——tcpdump抓包分析
当所有配置检查都无误,但网络仍不通时,tcpdump是最后的真相之眼。
# 在控制节点上,抓取br-ex上的ICMP包(模拟虚拟机ping外网) tcpdump -i br-ex icmp -nn -c 10 # 在计算节点上,抓取br-int上的ICMP包 tcpdump -i br-int icmp -nn -c 10 # 对比两个抓包结果: # 如果br-int有包,br-ex无包 → 问题在br-int到br-ex的转发(检查L3 Agent、iptables SNAT) # 如果br-ex有包,但外网无响应 → 问题在物理网络(检查网关、防火墙、物理连线) # 如果两者都无包 → 问题在虚拟机内部(检查虚拟机网卡、IP、路由)我曾用这个方法,定位到一个极其隐蔽的Bug:计算节点的br-int网桥MAC地址,与控制节点的br-intMAC地址完全相同。这是因为OVS在创建网桥时,会随机生成一个MAC,而两个节点恰好生成了相同的随机数。这导致VXLAN隧道两端的ARP请求被错误地广播,最终网络混乱。解决方案是手动为br-int设置唯一MAC:
ovs-vsctl set bridge br-int other-config:hwaddr=00:00:00:00:00:017. 验证与收尾:用一条curl命令,见证整个网络栈的贯通
所有配置和排错完成后,最终的验证,不应止步于openstack network agent list的绿色UP,而应是一次端到端的、穿透整个网络栈的连通性测试。我推荐一个极简但威力巨大的验证方式:用curl命令,从虚拟机内部,访问一个外部HTTP服务。
7.1 创建一个最小化测试环境
# 1. 创建一个名为test-net的私有网络 openstack network create test-net # 2. 创建子网,指定网关(假设物理网关是192.168.4.1) openstack subnet create --network test-net --subnet-range 10.0.1.0/24 --gateway 10.0.1.1 test-subnet # 3. 创建一个路由器,并将其连接到test-net和provider网络 openstack router create test-router openstack router add subnet test-router test-subnet openstack router set --external-gateway provider test-router # 4. 启动一个最小化虚拟机(使用之前上传的cirros镜像) openstack server create --image cirros --flavor m1.tiny --network test-net test-vm # 5. 为虚拟机分配一个浮动IP openstack floating ip create provider openstack server add floating ip test-vm <floating-ip>7.2 执行穿透式验证
等待虚拟机状态变为ACTIVE后,用openstack console log show test-vm查看其控制台日志,确认它已获得10.0.1.x的IP。然后,从控制节点,用ssh登录该虚拟机(cirros默认用户cirros,密码cubswin:)):
# 获取虚拟机的浮动IP openstack server show test-vm | grep addresses # ssh登录(cirros镜像内置了ssh服务) ssh cirros@<floating-ip> # 在虚拟机内部,执行curl命令 curl -v http://httpbin.org/ip预期的成功输出:
* Connected to httpbin.org (34.107.122.122) port 80 (#0) > GET /ip HTTP/1.1 > Host: httpbin.org > User-Agent: curl/7.47.0 > Accept: */* > < HTTP/1.1 200 OK < Server: gunicorn/19.9.0 < Date: Mon, 01 Jan 2024 00:00:00 GMT < Content-Type: application/json < Content-Length: 32 < Access-Control-Allow-Origin: * < Access-Control-Allow-Credentials: true < { "origin": "192.168.4.144" # 注意:这里显示的是计算节点的br-provider IP! }这个origin字段的值,是整个Neutron网络栈贯通的铁证。它证明了:
- 虚拟机的流量,从
tap口出发,经过qbr、br-int; - 在
br-int上,被neutron-openvswitch-agent识别为需要路由的包; - 流量被送入
qrouter-xxx命名空间; - 在命名空间内,
iptables的SNAT规则将源IP(10.0.1.x)替换为计算节点的br-providerIP(192.168.4.144); - 流量从
qg-xxx口发出,进入br-ex,最终通过物理网卡eno2到达外网。
这条命令,比任何ping都更有说服力,因为它不仅测试了IP层的连通性,还验证了传输层(TCP三次握手)和应用层(HTTP协议)的完整工作流。
7.3 我的个人体会:手动安装的价值,不在于“会装”,而在于“敢修”
带了这么多年实训,我越来越确信:Neutron的手动安装,其终极价值从来不是为了在生产环境里真的去手动部署——Ansible、Kolla这些自动化工具早已成熟。它的真正价值,在于强迫你直面OpenStack网络最底层的每一个齿轮、每一根导线。当你亲手敲下ovs-vsctl add-br br-provider,你就在和Linux内核的网络子系统对话;当你修改/etc/sysctl.conf,你就在调整操作系统最基础的网络行为;当你在/var/log/neutron/里逐行grep日志,你就在阅读一个分布式系统的实时脉搏。
这种“亲手造轮子”的过程,会给你一种无可替代的掌控感。未来无论你面对的是Kubernetes的CNI插件、还是云厂商的VPC配置,那种对网络数据平面的直觉,都源于此刻对Neutron的深刻理解。所以,别把它当成一个必须完成的作业,把它当成一次通往云网络核心的朝圣之旅。每一个XXX,都是一个待解的谜题;每一次UP,都是对底层世界的一次胜利致敬。