我想大多數人聽過 Node.js,但你聽過 NodeOS 嗎?沒錯,NodeOS,一個用 Node.js 寫的作業系統。好吧,實話說,NodeOS 用 Linux 核心來處理各種底層任務,像是硬體通訊什麼的,但除此之外,使用的都是 Node.js。 NodeOS 的開發始於兩年前,創建者的目的很簡單,他只是好奇,「是否有可能只使用 Node.js 創建一個作業系統呢?」
是否有可能只使用 Node.js 建立一個作業系統呢?
這個主意怎麼樣?
我們已經看到了 Node.js 在這幾年已經取得如此迅猛的發展,那麼我們為何不讓它更酷一些呢?例如用它做個作業系統。
用戶自主的獨立檔案系統
NodeOS 引入了一個有趣的特性:所有的使用者都有一個獨立的檔案系統,他們在一個簡單的檔案系統中完成各種工作。因為他們的「主目錄」事實上就是他們自己的檔案系統的根(root),所以他們可以不需要任何超級權限就可以將軟體包安裝到系統中,也不需要配置什麼,因為軟體包預設就安裝在他們自己的主目錄裡面。此外, 這樣也提供了良好的安全性,如果駭客攻入到了某個帳戶,那麼只能訪問到該用戶所在的部分,最終的結果就是駭客並不能由此影響到整個系統。
Node.js 和NPM
你可以想想,如果一個作業系統使用 Node.js,那就代表所有在 NPM 中可用的套件同時也都是 NodeOS 的軟體包。在寫作本文時,已經有了超過 21 萬的軟體包,而且每分鐘都在不斷增長。如果幾年以後,NodeOS 有了一百萬應用,那也沒什麼好奇怪的。
基於Linux 核心
這看起來並不算什麼,Linux 是大多數伺服器所採用的作業系統。因為 NodeOS 是基於 Linux 核心的,所以你只需要很少的修改就可以使用那些給其它的 Linux 發行版開發的應用程式了。
不好的消息
我非常希望 NodeOS 是一個已經完成的作品,但是,它現在還不是。它仍然缺少一些伺服器作業系統所需的關鍵功能。例如,缺少完整的 BASH 工具集,包括 ps、tail、nano 和 grep 等都沒有。更糟的是,你也不能把它當成桌面作業系統使用,因為它沒有 GUI。當然,你可以實作一些缺少的功能,只需要使用一點點 JavaScript,但是預設情況下,這些功能現在都還沒有,真是糟糕。
好吧,那我可以試試 NodeOS 嗎?
使用 Docker 體驗
最容易、最快捷的體驗 NodeOS 的方法如下:
1、一台運行 Mac OSX 或 Linux 計算機,也許 Windows 也可以,但我沒試過。
2、Docker。
當你安裝好 Docker 之後,執行一個 NodeOS 實例是很容易的。你只需要執行以下指令就可以了, Docker 會為你完成這魔法般的一切:
sudo docker run -t -i nodeos/nodeos
最容易、最快捷的体验 NodeOS 的方法是通过 Docker。
当你运行了上述命令,Docker 会自动从仓库下载 NodeOS 的镜像,并将其安装到一个虚拟环境中。安装好之后,会打开一个连接到 NodeOS 的 SSH 会话。
不用 docker 呢?
有些情况下你也许不能使用 Docker 来体验,或者是你想体验一下最新版本的 NodeOS 。在写作本文时,NodeOS 的镜像已经是两个月前生成的了,而开发版本则是六天前更新的。所以,如果你希望使用最新版本,你应该从源代码开始。这也不算很难,但是要花费一些时间。你 需要:
1、一台运行 Linux 的计算机。你可以在 OS X 上编译它,但是跨平台编译需要花费很多时间,对于 Windows 也如此。
2、Linux 编译构建相关的工具(make、g++、gcc、autoconf)。
3、Qemu。
4、时间,真的需要很多。
如果万事俱备,你就可以从源代码开始编译了:
1、使用下列命令编译: cd NodeOS 并 npm install。
2、我逐字引用了其官方文档的话:“拿上爆米花去看场电影吧,不开玩笑,真的。”,是的,它需要很多时间,做些有意思的事情去吧。
3、执行 bash npm start 来在 Qemu 中运行 NodeOS。
可以工作了吗?
当安装完成后,我们可以通过在 NodeOS 的 shell 中执行 ls命令来看看它是否工作了。输出类似如下:
[ 'etc', 'lib', 'lib64', 'root', 'bin', 'sys', 'usr', 'share', 'proc' ]
如果显示如上,说明一些基本的命令可以工作了。但是如果我们想要知道网卡地址呢?在 Linux 下,这个命令是 ifconfig ,让我们试试:
command not found: ifconfig
看起来没有 ifconfig 命令。这是因为 NodeOS 默认没有 ifconfig命令。现在怎么办?很简单,NodeOS 有一个集成的包管理器(类似 apt 或 yum) ,叫做 npkg,它是基于 Node 的 NPM 的,很容易使用。可以通过如下命令很方便的安装 ifconfig :
npkg install bin-ifconfig
如果一切正常, ifconfig 命令现在就可以在 shell 中使用了。我们再次试着执行一下,输出类似如下:(我替换了其中的 MAC 地址):
eth0: flags=8863 mtu 1500 ether 01:23:45:67:89:ab inet6 f0cd::ef01:0203:0405:181%en1 prefixlen 64 scopeid 0x5 inet 192.168.0.21 netmask 0xffffff00 broadcast 192.168.0.21 nd6 options=1 media: autoselect status: active
如果你的输出也类似如上,那说明它可以工作了。你已经成功地安装了你的第一个 NodeOS 应用: ifconfig。
它是可以工作了,然而我们可以用这个操作系统做什么呢?
如果我们只能拿这个用 Node.js 写的操作系统做到你在 Ubuntu 或其它 Linux 发行版上一样的(或更少的)事情,那它有什么价值?其实,整个事情中最有趣的地方是所有的东西都是 Node.js 开发的。这意味着我们可以只需要使用 Node.js 就可以开发我们的应用了。比如,NodeOS 里没有默认实现的 man 命令,它用于显示其它命令的帮助信息。不用担心,实现它很简单。
使用 Node.js 构建一个 NodeOS 应用
首先让我们来安装一个叫做 Hipster 的文本编辑器,以便我们可以创建和编辑文件。执行如下命令: npm install -g hipster@0.15.0。这个文本编辑器很简单,除了用作文本编辑之外啥也干不了,不过对于我们来说足够了。
用 Hipster 创建文件很简单,运行 hip filename即可,如: hip package.json。要保存文件请按下 Ctrl + s ,退出按下 Ctrl + q。
在这里,我们使用了一个 NodeOS 的主开发人员所开发的代码,我自己并没有真的去开发这个应用。我们例子中的原始代码可以在 node-bin-man Git 仓库中找到。
让我们回过头来创建我们的第一个 NodeOS 应用。像每个 Node.js 应用(或 NPM 包)一样,我们从创建一个 package.json 文件开始,内容如下:
{ "name": "bin-man", "version": "0.0.1", "description": "Format and display manual pages", "bin": { "man": "man.js" }, "repository": "https://github.com/groundwater/node-bin-man", "author": "groundwater", "license": "MIT", "dependencies": { "blessed": "~0.0.22" } }
这些参数 name、version、 author、 repository、 license和 description 是其意自明的。这个 bin 集合是一个 JSON 的键值对对象,包含了命令名及其关联的 JavaScript 文件。在我们的例子中, man 命令关联到 man.js文件。而 dependencies集合包含了这个应用所需要的 NPM 包的列表。在我们的例子中,代码的作者包含了 Blessed 包,这是一个类 curses 的库,可以让 Node.js 支持高级终端界面的 API。
现在我们进入了主要的部分,实际的代码。
#!/usr/bin/env node
这个部分叫做释伴(shebang)。NodeOS 实际上并不需要它,但是它用于告诉操作系统如何执行下面的代码。在这里的意思是,它告诉系统下面的每行代码都需要通过 /usr/bin/env node命令来解释执行。
var fs = require('fs'); var blessed = require('blessed');
像在 Node.js 中一样, require() 函数加载选定的包到内存中,并将其保存为特定的变量。
var arg = process.argv[2] || 'bin-man';
man 命令的标准行为是如果没有指定要查看的命令时,就显示它自己的帮助信息。在我们的代码示例中也一样:如果没有给出第二个参数(第一个参数是 man 本身),那么该参数的默认值是 bin-man。
var path = process.env.HOME + "/lib/node_modules/" + arg + "/README.md"; try{ var readme = fs.readFileSync(path, 'utf-8'); }catch(e){ console.log('No README.md for Package ',arg); process.exit(-1); }
在这里,程序检查给定的应用是否有一个 readme 文件。在 NodeOS 中,每个应用的安装路径是其主目录(/)下的 lib/node_modules。如果 README.md 文件存在,就将其内容保存到 readme变量中。否则,显示一个错误信息并退出。
// Create a screen object. var screen = blessed.screen(); var box = blessed.box({ content: readme, alwaysScroll:true, scrollable: true, }); // Append our box to the screen. screen.append(box);
Blessed 有一个非常简单的 API,要显示一个文件的内容很容易,只需要创建一个 box ,然后载入内容即可。
screen.key(['escape', 'q', 'C-c'], function(ch, key) { return process.exit(0); });
现在,让我们找个退出 man 应用的方法。我们组合了 escape、 q 或 emacs 风格的 C-c 来退出应用。
screen.key(['space','f','j','n'], function(ch, key) { box.scroll(box.height); screen.render(); }); screen.key(['down'], function(ch, key) { box.scroll(1); screen.render(); }); screen.key(['up'], function(ch, key) { box.scroll(-1); screen.render(); }); screen.key(['b','k','p'], function(ch, key) { box.scroll(-box.height); screen.render(); });
我们使用方向键来上滚和下滚,用 space、 f、 j 或 n 向下翻页,b、 k 或 p 向上翻页。
box.focus(); screen.render();
最后,我们让应用将输入焦点放到 box ,我们在这里创建和渲染所有内容。
把上面编辑的这个文件存放到 /lib/node_modules/bin-man 目录下(名字是 man.js),并加一个简单的 README.md ,类似如下:
# Man Author: @groundwater ## Install npkg install bin-man ## Usage ``` Usage: man PKGNAME Display a packages README.md file ```
我们已经基本完成了我们的第一个 NodeOS 定制应用。最后剩下一小步了,我们需要创建一个 NodeOS 应用需要的配置文件。很简单,把它创建到 /etc/bin-man/config.json ,内容只是一个空的 JSON 对象: {}。
现在我们可以试试我们的新应用了。在 NodeOS 中运行 man ,它将展示我们之前创建的 readme 文件。
总结
如你所见,在 NodeOS 中实现任何东西都很简单,你只需要懂得 Node.js 即可。
NodeOS 很有潜力,我认为当实现了更多的功能之后它会成为一个伟大的操作系统。目前仍然需要很多工作,但是在整个Node.js 生态系统兴盛发展的形势下,万一哪天它很快地成为一个流行的操作系统也没什么好惊奇的。