手动编译ONOS 2.5.0:从源码构建到部署的完整实战指南
1. 从零到一为什么我们需要手动编译ONOS如果你正在接触软件定义网络或者你的项目需要一个稳定、可深度定制的SDN控制器那么ONOSOpen Network Operating System大概率已经进入了你的视野。作为一个开源、分布式的网络操作系统ONOS在运营商级网络、数据中心互联等场景下有着广泛的应用。官方提供了预编译的发行版直接下载一个.oar文件通过onos-install脚本就能快速拉起一个集群这看起来非常方便。那么为什么我们还要大费周章地去手动编译它呢这恰恰是新手和老手之间的一个关键分水岭。直接使用预编译版本就像拿到了一台封装好的黑盒设备开机即用但你对它的内部一无所知。当你想深入理解ONOS的模块化架构、想为某个特定协议开发自己的应用App、或者需要针对你的硬件环境比如特定的芯片指令集进行性能优化时预编译版本就显得力不从心了。手动编译的过程本质上是一次对ONOS项目结构的深度探索。你会清晰地看到它如何用Maven管理数百个依赖如何用Bazel或Maven组织构建流程各个核心子系统如南向接口、北向API、分布式核心是如何被组装在一起的。这个过程能帮你建立起对ONOS代码库的“地图”未来无论是排查问题、阅读源码还是进行二次开发这张“地图”都至关重要。此外网络技术迭代很快你可能需要尝试ONOS主线上的最新特性或者应用某个尚未合并到主分支的社区补丁这些情况都要求你必须从源代码开始构建。因此这篇教程的目标不仅仅是让你成功地在机器上跑起一个ONOS更是带你走通从源码到可执行系统的完整路径理解其中的关键环节和常见“坑点”为后续的深入研究和开发打下坚实基础。我们将基于相对稳定且资料较多的ONOS 2.5.0版本进行但其中涉及的原理和方法具有通用性。2. 编译环境搭建避开依赖的“暗礁”手动编译ONOS 2.5.0第一步就是准备一个“干净”且“完备”的构建环境。这里的“干净”指的是避免系统已有杂乱的Java或Python环境干扰“完备”则意味着需要一次性装齐所有必要的工具链任何一个环节的缺失都可能导致编译过程在几十分钟后莫名失败非常打击信心。2.1 操作系统与基础环境选择ONOS官方推荐在Ubuntu或Debian系Linux发行版上进行开发构建这主要是因为其构建工具链和脚本对这些系统有最好的支持。虽然理论上macOS甚至Windows通过WSL也能完成但你会遇到更多依赖库和路径问题。为了最顺畅的体验我强烈建议使用Ubuntu 20.04 LTS或22.04 LTS作为编译主机。这两个版本有长期支持社区资源丰富且其自带的软件包版本与ONOS 2.5.0的需求匹配度较高。首先更新系统并安装一些基础编译工具sudo apt-get update sudo apt-get upgrade -y sudo apt-get install -y git curl wget zip unzip tar sudo apt-get install -y build-essential autoconf automake libtool2.2 Java开发套件JDK的精准匹配ONOS 2.5.0的核心语言是Java它对JDK版本有严格要求。根据官方文档2.5.0版本需要Java 8。请注意是Java 8而不是更高版本。使用Java 11或17会导致不兼容的编译错误。这里我推荐安装OpenJDK 8。sudo apt-get install -y openjdk-8-jdk安装完成后务必检查默认Java版本java -version预期输出应类似于openjdk version 1.8.0_382。如果你的系统安装了多个Java版本需要使用update-alternatives命令来设置默认版本sudo update-alternatives --config java # 在出现的菜单中选择编号对应 openjdk-8 的路径同样也需要设置javac的默认版本sudo update-alternatives --config javac注意这是编译过程中最容易出错的地方之一。很多现代Linux发行版默认安装的是Java 11。如果编译时遇到大量关于-source、-target或找不到符号的错误第一个要怀疑的就是JDK版本。2.3 构建工具Maven与Bazel的协作ONOS的构建体系经历了从纯Maven到MavenBazel混合的演变。2.5.0版本主要使用Maven 3.3.9来管理依赖和构建大部分模块同时使用Bazel来构建某些特定的原生组件或进行更高效的增量编译。安装Mavensudo apt-get install -y maven mvn -v # 确认版本为3.3.9或更高安装BazelONOS 2.5.0通常与Bazel 0.22.0左右版本兼容。安装Bazel相对复杂推荐通过Bazel官方提供的安装脚本# 1. 安装Bazel所需的依赖 sudo apt-get install -y pkg-config zip g zlib1g-dev unzip python3 # 2. 下载安装脚本并运行安装特定版本如0.22.0 wget https://github.com/bazelbuild/bazel/releases/download/0.22.0/bazel-0.22.0-installer-linux-x86_64.sh chmod x bazel-0.22.0-installer-linux-x86_64.sh ./bazel-0.22.0-installer-linux-x86_64.sh --user # 3. 将Bazel添加到PATH环境变量 echo export PATH$PATH:$HOME/bin ~/.bashrc source ~/.bashrc bazel version # 验证安装2.4 Python与其它必要工具ONOS的构建脚本和一些工具链需要Python。系统自带的Python 3即可满足要求。sudo apt-get install -y python3 python3-pip此外还需要安装Apache Karaf的定制化运行时依赖以及用于代码风格检查的工具sudo apt-get install -y libcurl4-openssl-dev sudo pip3 install flake8 # 可选用于代码规范检查环境变量检查清单编译前请确保以下关键环境变量已正确设置。环境变量推荐值/检查命令作用JAVA_HOMEecho $JAVA_HOME应指向JDK 8安装目录 (如/usr/lib/jvm/java-8-openjdk-amd64)告诉构建系统Java的根目录PATH包含$JAVA_HOME/bin和$HOME/bin(Bazel)确保命令行能找到java, javac, mvn, bazelMAVEN_OPTS可设置为-Xmx2048m -XX:MaxPermSize512m为Maven分配更多内存避免编译时内存不足你可以通过创建或编辑~/.bashrc文件来永久设置它们echo export JAVA_HOME/usr/lib/jvm/java-8-openjdk-amd64 ~/.bashrc echo export PATH$JAVA_HOME/bin:$PATH:$HOME/bin ~/.bashrc echo export MAVEN_OPTS-Xmx2048m -XX:MaxPermSize512m ~/.bashrc source ~/.bashrc3. 获取源码与项目结构初窥环境准备好后我们就可以获取ONOS的源代码了。ONOS使用Git进行版本管理代码托管在Gerrit上但对公众只读镜像在GitHub。3.1 克隆源代码仓库我们直接克隆ONOS在GitHub上的镜像仓库并切换到2.5.0这个标签Tag。使用标签而非分支能确保我们拿到的是该版本发布时冻结的、经过测试的代码状态。git clone https://github.com/opennetworkinglab/onos.git cd onos git checkout 2.5.0这个过程会下载数百兆的代码和历史记录请耐心等待。完成后你会看到一个名为onos的目录里面就是整个项目的源码。3.2 理解ONOS源码目录结构进入onos目录使用ls -la查看你会看到类似下面的结构。理解这个结构对后续编译和开发至关重要onos/ ├── apps/ # 各种ONOS应用程序如openflow, netconf, fwd (二层转发)等 ├── core/ # ONOS核心子系统如分布式存储、事件总线、安全框架等 ├── protocols/ # 协议相关的实现和抽象层 ├── drivers/ # 设备驱动负责与具体网络设备通信 ├── utils/ # 通用工具类库 ├── features/ # Karaf特性定义文件用于模块化部署 ├── tools/ # 构建、测试、开发工具脚本 ├── web/ # 图形用户界面GUI相关代码 ├── pom.xml # 顶层的Maven项目对象模型文件 ├── WORKSPACE # Bazel工作空间定义文件 └── BUILD # Bazel构建文件简单来说apps/目录下的每个子目录通常对应一个可以独立编译、打包、安装和卸载的ONOS应用.oar文件。core/是控制器的大脑。编译命令会递归地处理这些模块。3.3 初始化与下载依赖ONOS依赖大量的第三方Java库JAR包。Maven负责自动从中央仓库或镜像下载这些依赖。首次编译前建议先让Maven下载好所有依赖这能让你在后续正式编译时网络问题的影响降到最低。mvn dependency:go-offline -DskipTests这个命令会解析所有pom.xml文件下载依赖到本地的Maven仓库通常位于~/.m2/repository。根据网络情况这个过程可能需要较长时间会下载数GB的数据。-DskipTests参数告诉Maven跳过测试因为我们目前只关心编译依赖。实操心得依赖下载是编译过程中最耗时的步骤之一且容易因网络波动失败。可以考虑配置更快的Maven镜像源如阿里云镜像。编辑~/.m2/settings.xml文件没有则创建添加镜像配置。这能显著提升下载速度尤其是在国内网络环境下。4. 核心编译流程详解与问题破解一切就绪现在进入最核心的编译环节。ONOS的编译不是简单的一条命令而是一个有顺序、可配置的过程。4.1 使用Maven进行全量编译最标准、最彻底的编译方式是使用Maven进行全量编译。这会编译所有模块并运行所有单元测试。mvn clean compile如果一切顺利你会看到大量的[INFO] BUILD SUCCESS输出。但首次编译很可能不会一帆风顺。下面是一些常见错误及解决方案问题一java.lang.OutOfMemoryError: Java heap space这表明分配给Maven的堆内存不足。我们在环境变量中设置了MAVEN_OPTS如果还不够可以临时加大MAVEN_OPTS-Xmx4096m -XX:MaxPermSize1024m mvn clean compile或者直接修改~/.m2/settings.xml在profiles部分添加JVM配置。问题二依赖下载失败或超时症状是构建在某个依赖下载环节卡住很久最后报错。解决方法检查网络连接。删除本地有问题的依赖让Maven重新下载。错误信息通常会给出失败的依赖坐标如groupId:artifactId:version。你可以到~/.m2/repository目录下找到对应的文件夹并删除。如前所述配置国内镜像源是根本解决之道。问题三[ERROR] Failed to execute goal ... on project ...且错误与测试相关有时某个模块的单元测试可能失败。如果你确信只是暂时想跳过测试先完成编译可以使用mvn clean compile -DskipTests或者更彻底的mvn clean compile -Dmaven.test.skiptrue后者会跳过测试代码的编译。4.2 针对特定应用的编译全量编译耗时较长在性能较好的机器上可能也需要15-30分钟。如果你只修改了某个特定应用例如apps/fwd即转发应用可以进行局部编译。cd apps/fwd mvn clean install这条命令会在fwd目录下执行编译并将打包好的.oar文件安装到本地Maven仓库。之后在ONOS运行时可以通过onos-app install命令从本地仓库安装这个新编译的应用。4.3 使用Bazel进行快速构建对于某些原生模块或需要快速迭代的场景Bazel的增量构建优势明显。例如编译ONOS的核心可执行包bazel build onos这条命令会利用Bazel的缓存和并行化能力只编译发生变化的文件速度通常比Maven全量编译快。编译产物位于bazel-bin/onos.tar.gz。这个压缩包包含了运行ONOS所需的所有文件可以解压到任何地方运行。注意事项ONOS 2.5.0的构建系统是混合的。有些模块只能用Maven构建有些则推荐用Bazel。通常应用开发用Maven构建完整发行版用Bazel更方便。如果遇到Bazel版本不兼容的问题如no such target请核对WORKSPACE文件中声明的Bazel版本是否与你安装的一致。4.4 生成可部署的发行版包我们的最终目标是得到一个可以独立运行ONOS的包。这可以通过Bazel轻松实现bazel build onos完成后在bazel-bin/目录下会找到onos.tar.gz。这就是我们编译好的发行版。tar -xzf bazel-bin/onos.tar.gz -C /opt/这样就把ONOS解压到了/opt/目录下。你也可以解压到任何你喜欢的路径比如~/onos-dist。5. 安装、启动与基础验证编译产出物只是一个静态的文件包要让ONOS作为一个服务运行起来还需要进行安装和配置。5.1 安装ONOS服务进入解压后的ONOS目录你会看到bin/、etc/、lib/等子目录。bin/目录下有很多脚本其中onos-service脚本用于将ONOS安装为系统服务。cd /opt/onos-2.5.0 # 假设解压到此目录 sudo bin/onos-service install这个脚本会创建一个名为onos的系统服务Systemd或Upstart取决于你的Linux发行版。你可以使用系统服务命令来管理它sudo systemctl status onos # 查看状态 sudo systemctl start onos # 启动 sudo systemctl stop onos # 停止 sudo systemctl enable onos # 设置开机自启5.2 首次启动与日志观察启动服务后ONOS会在后台运行。默认的Web GUI访问地址是http://your-server-ip:8181/onos/ui默认用户名和密码是onos/rocks。在浏览器访问之前强烈建议先查看启动日志确认服务是否健康启动tail -f /opt/onos-2.5.0/apache-karaf-4.2.8/data/log/karaf.log你会看到Karaf容器ONOS的运行环境加载各种模块Bundles的信息。等待几分钟直到看到类似下面的日志表明核心系统已就绪... INFO [FeaturesServiceImpl] Started bundle: onos-api (222) ... INFO [Main] ONOS started in 12345 ms如果启动过程中有错误例如某个Bundle解析失败日志会明确打印出来这是排查问题的主要依据。5.3 基础功能验证访问Web UI (http://your-server-ip:8181/onos/ui) 并登录后你可以进行一些基础验证查看集群状态在UI顶部的“Applications”中找到“ONOS Core”应用组确保核心服务如Topology、Host、Link等都是Active状态。激活示例应用在“Applications”页面找到org.onosproject.fwd(二层转发) 应用点击“Activate”按钮。这个应用是ONOS最基础的转发应用激活后ONOS才能对网络流量做出转发决策。使用CLIONOS提供了一个强大的命令行接口。你可以通过SSH连接ssh -p 8101 onoslocalhost # 密码也是 rocks在CLI中可以运行apps -a查看所有应用nodes查看集群节点等。5.4 安装自定义编译的应用如果你编译了自己的应用比如在apps/目录下新建了一个应用并已通过mvn install将其打包的.oar文件安装到了本地Maven仓库~/.m2/repository你可以通过以下命令在运行的ONOS实例上安装它# 假设你的应用artifactId是my-app版本是1.0.0 onos-app localhost install! ~/.m2/repository/org/onosproject/my-app/1.0.0/my-app-1.0.0.oar或者如果ONOS服务配置了访问远程Maven仓库也可以直接从仓库安装onos-app localhost install org.onosproject my-app 1.0.06. 编译与部署中的进阶技巧与排坑指南即使按照上述步骤操作在实际环境中你可能还是会遇到一些独特的问题。这里分享一些从多次编译部署中积累的进阶技巧和排坑经验。6.1 依赖冲突与版本锁定Maven项目中最头疼的问题之一就是依赖冲突Dependency Hell。两个不同的模块可能引用了同一个库的不同版本导致运行时出现NoSuchMethodError或ClassNotFoundException。ONOS通过dependencyManagement在顶层pom.xml中锁定了大部分核心依赖的版本这大大减少了冲突概率。排查技巧如果你在开发自己的应用时遇到奇怪的类加载错误可以使用Maven命令分析依赖树cd /path/to/your/app mvn dependency:tree -Dverbose查看输出寻找被重复引入且版本不一致的库。然后可以在你自己应用的pom.xml中使用exclusions标签排除掉不需要的传递性依赖或者显式声明你需要的版本。6.2 内存与性能调优ONOS在编译和运行时都比较消耗资源。编译期如前所述给Maven分配足够的内存MAVEN_OPTS。此外使用mvn compile -T 4可以启用4线程并行编译充分利用多核CPU加快速度。运行期ONOS运行在Karaf容器内其JVM参数在bin/setenv文件中配置。对于生产环境或资源紧张的环境你可能需要调整堆内存大小-Xms和-Xmx、垃圾回收器等参数。例如将初始堆和最大堆都设为4GB# 在 bin/setenv 中找到 JAVA_MAX_MEM 等变量进行修改 export JAVA_MAX_MEM4G export JAVA_MIN_MEM4G6.3 清理与重建当你的代码修改没有生效或者遇到一些无法解释的构建错误时一个“干净”的重建往往能解决问题。清理Mavenmvn clean会删除每个模块下的target/目录。清理Bazelbazel clean --expunge会清除Bazel的所有输出和缓存非常彻底下次构建会慢。清理本地仓库极端情况下可以删除~/.m2/repository/org/onosproject目录下与你正在开发模块相关的所有内容强制Maven重新下载和解析依赖。6.4 网络代理配置如果你的编译环境处于公司内网需要通过代理访问互联网那么需要为Maven、Git和Bazel分别配置代理。Maven在~/.m2/settings.xml中配置proxies。Gitgit config --global http.proxy http://proxy.yourcompany.com:portBazel在WORKSPACE文件所在目录创建或修改.bazelrc文件添加startup --host_jvm_args-Dhttp.proxyHost...等参数。配置不当会导致依赖下载失败编译过程卡在第一步。手动编译安装ONOS 2.5.0远不止是输入几条命令。它是一次对复杂软件项目构建体系的实战演练。从环境配置的严谨性到依赖管理的复杂性再到构建工具的选择与配合每一步都蕴含着工程实践的经验。成功编译并运行起来的那一刻你获得的不仅仅是一个可用的SDN控制器更是一张通往其内部世界的“通行证”。当你再遇到官网文档语焉不详的问题或者需要深度定制某个功能时这份从源码开始构建的能力将成为你最可靠的倚仗。后续你可以尝试修改apps/fwd中的简单逻辑并重新编译部署亲眼看到你的代码如何影响网络转发行为那将是理解ONOS魅力的下一个里程碑。