使用 noVNC 开发 Web 虚拟机控制台

OpenNebula 的控制面板 Sunstone 对 OpenNebula 私有云的管理员来说很方便实用,不用敲命令,但是对云计算、虚拟机不熟悉的用户来说有点复杂。所以,我们打算开发一个内部使用的 OpenNebula 控制面板,并和我们的其他内部服务集成起来。从不同 VPS 服务商那里用过 VPS 的用户都知道 VPS 控制面板的几个基本功能,创建、删除、重装、控制台访问。其中控制台访问功能的实现就是我们今天要讨论的主题。

我们知道不管是 VMware, Xen 还是 KVM,都可以配置 VNC 访问,然后通过 VNC 客户端访问这些虚拟机的控制台,这些 VNC 客户端往往需要下载安装,如果要开发虚拟机的 web 控制面板的话当然最好能配一个 web 的 VNC 客户端。

noVNC 正是我们需要的 HTML5 VNC 客户端,采用 HTML 5 WebSockets, Canvas 和 JavaScript 实现,noVNC 被普遍用在各大云计算、虚拟机控制面板中,比如 OpenStack Dashboard 和 OpenNebula Sunstone 都用的是 noVNC. 前面说了 noVNC 采用 WebSockets 实现,但是目前大多数 VNC 服务器都不支持 WebSockets,所以 noVNC 是不能直接连接 VNC 服务器的,怎么办呢?需要一个代理来做 WebSockets 和 TCP sockets 之间的转换,理解这一点很重要。这个代理也已经有了,在 noVNC 的目录里,叫做 websockify.

基本

下载 noVNC 代码后然后运行 noVNC/utils/websockify.py,把本机 VNC 服务(localhost)的端口(5900)和 noVNC 的代理端口(8000)连接起来,这样通过 noVNC/vnc.html 访问 8000 端口就自动转换到 5900 端口上(事实上 vnc.html 你可以放在任何机器上用浏览器直接打开用):

$ git clone https://github.com/kanaka/noVNC

$ cd utils
$ ./websockify.py 8000 localhost:5900
WARNING: no 'numpy' module, HyBi protocol is slower or disabled
WebSocket server settings:
  - Listen on :8000
  - Flash security policy server
  - No SSL/TLS support (no cert file)
  - proxying from :8000 to localhost:5900

流程大概是这样:

vnc.html -> 192.168.2.20:8000 -> websockify.py -> localhost:5900

当然代理和 VNC 服务可以不在同一机器上,比如代理在 192.168.2.20, VNC 服务在 192.168.2.21:

$ ./websockify.py 8000 192.168.2.21:5900

流程大概是这样:

vnc.html -> 192.168.2.20:8000 -> websockify.py -> 192.168.2.21:5900

理解了上面的过程,应该有想法如何集成 noVNC 到自己的程序了,很简单,先用 websockify 架一个代理,然后用 vnc.html 访问这个代理,vnc.html 和 vnc_auto.html 可以当作我们的范例程序参考。集成 noVNC 到自己的程序也没啥难度,按照官方文档修改相应参数就可以了,特别注意 INCLUDE_URI 这个变量。

如果想深入了解 OpenNebula 和 noVNC 请继续 ……

深入

如果给每个运行的 VNC 服务器开一个代理(和端口)是不是很繁琐?如果有成百上千个虚拟机呢?这么多虚拟机这么多端口怎么编程实现一一对应呢,是不是很麻烦?难道这么点东西还要个数据库来记录这些对应关系吗?我们来看一下 OpenNebula 是怎么实现 noVNC 集成的。

首先 OpenNebula 使用 websocketproxy.py 带 –target-config 参数的办法启动了代理,所有代理都在一个端口(29876)下,并会在指定的目录下(/var/lib/one/sunstone_vnc_tokens)生成一个对应的文件(one-96),打开这个文件就会看到前面的一串代码和后面的 VNC 服务(主机名:端口)对应起来。这样一个(启动了 VNC 服务的)虚拟机就对应在 sunstone_vnc_tokens 这个目录生成一个文件,文件内容能识别这个代理对应到哪个主机上的 VNC 服务。

# ps aux | grep websockify
oneadmin 13661  0.0  0.2 197576  8388 ?        S    Jul04   0:07 python /usr/share/one/websockify/websocketproxy.py --target-config=/var/lib/one/sunstone_vnc_tokens 29876

# cat /var/lib/one/sunstone_vnc_tokens/one-96
cirjhccnthfinxpdlig: cloud32:5900

修改 noVNC/vnc_auto.html 文件的 host, port, path 部分,注意 path 是带 token 的,token 的参数要和上面的那串奇怪的代码一致:

...
      host = "192.168.2.20";
      port = "29876";
...
      path = "websockify/?token=cirjhccnthfinxpdlig";
...

我们编程时只要改变上面的 token 参数就可以切换连接到不同的虚拟机 VNC,这样编程就方便多了。这个是我们利用 vnc_auto.html 修改过后的 VNC 连接界面(为了配合博客美观,截图有意缩小了):
novnc

如果对我们的控制面板感兴趣的话,可以看看截图,只完成了最最基本的几个功能,算作工作时间外的 side project,还在不紧张的开发中,开发工具是 Python/Flask/Bootstrap/MongoDB.
vpsee cloud

升级 OpenNebula 3.x 到 OpenNebula 4.0

正在测试 OpenNebula 的升级工作,安装和测试新版 OpenNebula 4.0 是一件事,还有一件事是测试升级过程中可能遇到的问题和解决办法。升级是危险操作,每一个阶段都可能会有问题,所以升级前的各种备份和测试工作都需要准备妥当,配置文件、虚拟机、数据库等等都是必须备份的。好的升级除了应该保证数据完整、各部分运行正常外还应该尽量让用户察觉不到。

OpenNebula 官方文档说如果要升级的话需要参考相关版本的文档然后逐个版本依次升级:

If you are upgrading from a version prior to 3.8, read the 3.4 upgrade guide, 3.6 upgrade guide and 3.8 upgrade guide for specific notes.

逐个版本升级的过程太麻烦,我们看看能不能一次升级到位。

先停掉 OpenNebula 3.x 的相关服务:

$ sunstone-server stop
$ econe-server stop
$ occi-server stop
$ oneacctd stop
$ one stop

导出数据库(会在 /var/lib/one 下生成一个名为 one.db.bck 的备份文件):

$ onedb backup -v -f --sqlite /var/lib/one/one.db

关闭所有虚拟机后,然后在控制节点和计算节点正常安装 OpenNebula 4.0.

安装完 OpenNebula 4.0 后用新版的 onedb 升级数据库(也就是升级 one.db.bck 里面的表结构、字段等),这个升级过程将会自动从 3.2.1 到 3.3.0 到 3.3.80 到 … 逐个版本升级到 3.9.80,整个过程完成后会纪录在当前目录的 one.upgrade.log 日志文件里:

$ onedb upgrade -v -f --sqlite one.db.bck

注意升级前(onedb upgrade)一定要关闭所有虚拟机,否则升级数据库会报错:

> Running migrator /usr/lib/one/ruby/onedb/3.3.0_to_3.3.80.rb
You can't have active VMs. Please shutdown or delete the following VMs:
...

如果不想(或者不允许)关闭所有虚拟机的话,可以通过直接修改数据库的办法 “骗过” 升级脚本(onedb),只需要到数据库里手动把所有 VMs 的状态(state)改成 shutdown 就可以了:

$ sqlite3 one.db.bck
sqlite> SELECT oid,name,state,lcm_state FROM vm_pool WHERE (state <> 1 AND state <> 6);
sqlite> UPDATE vm_pool set state=1 WHERE (state <>1 and state <>6);

数据库升级完后就要开始升级配置文件,OpenNebula 4.0 一些配置文件、参数以及目录结构有改动,比如 OpenNebula 配置文件里的一些驱动名改了,im_kvm 改成了 kvm、vmm_kvm 改成了 kvm,为了兼容,所以需要增加 im_kvm 和 vmm_kvm. 修改 oned.conf 配置文件:

$ vi /etc/one/oned.conf
...
IM_MAD = [
      name       = "kvm",
      executable = "one_im_ssh",
      arguments  = "-r 0 -t 15 kvm" ]
IM_MAD = [
      name       = "im_kvm",
      executable = "one_im_ssh",
      arguments  = "-r 0 -t 15 kvm" ]
...
VM_MAD = [
    name       = "kvm",
    executable = "one_vmm_exec",
    arguments  = "-t 15 -r 0 kvm",
    default    = "vmm_exec/vmm_exec_kvm.conf",
    type       = "kvm" ]
VM_MAD = [
    name       = "vmm_kvm",
    executable = "one_vmm_exec",
    arguments  = "-t 15 -r 0 kvm",
    default    = "vmm_exec/vmm_exec_kvm.conf",
    type       = "kvm" ]
...

注意 authn 这一行需要有 server_cipher:

$ vi /etc/one/oned.conf
...
AUTH_MAD = [
    executable = "one_auth_mad",
    authn = "ssh,x509,ldap,server_cipher,server_x509"
]
...

/var/lib/one 目录结构中增加了一些新目录,比如 datastore, vms 等,OpenNebula 3.x 老版本的虚拟机镜像在 /var/lib/one 需要移到新的 /var/lib/one/vms 下,所以需要登陆到每个 OpenNebula 节点移动虚拟机镜像目录:

$ mkdir /var/lib/one/vms
$ mv /var/lib/one/[0-9]* /var/lib/one/vms

然后启动所有服务和虚拟机、观察日志文件,看看新版 OpenNebula 有什么问题:

$ one start
$ occi-server start
$ sunstone-server start

在 CentOS 6.4 上安装和配置 OpenNebula 4.0

我们实验室的 OpenNebula 3.2 已经很稳定的运行了两年,除了开头一个月不熟悉这套云计算软件有点乱、容易犯错外接下来的时间里都很稳定,期间还包括一次防火演习(突然拉闸似断电)和安全检查(计划中的断电),服务器、虚拟机、存储设备、系统和服务都能自动起来并能正常工作。现在正在考虑升级的事情,OpenNebula 4.0 有很多新特性值得一试,现在的问题是升级很麻烦,官方文档貌似说要逐个版本升级,这个是小问题,更大的问题是如何升级整个运行中的生产环境,这里面有太多的因素需要考虑到,想了都头大~先安装一个 OpenNebula 4.0 试玩一下,看看数据库表结构、一些工具、配置文件,看看能不能琢磨出一个可行的升级方案出来,具体的升级操作将会在圣诞节期间进行(人最少的时候),不过现在应该开始计划和测试了。

下面的安装过程采用最小化的 CentOS 6.4 安装版本(CentOS-6.4-x86_64-minimal.iso)。不熟悉 OpenNebula 和云计算的朋友可以先看看 “在 CentOS 上安装和配置 OpenNebula” 的开头部分预热一下。

开始之前先装上 EPEL 源,然后升级系统:

# yum install wget
# wget http://dl.fedoraproject.org/pub/epel/6/x86_64/epel-release-6-8.noarch.rpm
# rpm -ivh epel-release-6-8.noarch.rpm
# yum update

到官网 http://downloads.opennebula.org/ 下载 OpenNebula 4.0 for CentOS 6.4 的安装包、解压后安装,因为有包依赖问题,所以最好用 yum localinstall 安装,不要用 rpm -ivh 命令直接安装。在控制节点(或叫做头节点)上安装 opennebula 和 opennebula-sunstone 等:

# cd /usr/src
# tar zxvf CentOS-6.4-opennebula-4.0.0-1.tar.gz
# cd opennebula-4.0.0-1

# yum localinstall opennebula-common-4.0.0-1.x86_64.rpm
# yum localinstall opennebula-ruby-4.0.0-1.x86_64.rpm
# yum localinstall opennebula-4.0.0-1.x86_64.rpm
# yum localinstall opennebula-sunstone-4.0.0-1.x86_64.rpm
# yum localinstall opennebula-server-4.0.0-1.x86_64.rpm

在计算节点上安装 kvm 和 opennebula-node-kvm:

# yum install qemu-kvm qemu-kvm-tools libvirt
# yum localinstall opennebula-node-kvm-4.0.0-1.x86_64.rpm

# /etc/init.d/libvirtd start

安装搞定,OpenNebula 4.0 的安装就是这么简单,开始在控制节点上启动服务吧:

# service opennebula start
Starting OpenNebula daemon:                                [  OK  ]
# service opennebula-sunstone start
Starting Sunstone Server daemon: VNC proxy started
sunstone-server started
                                                           [  OK  ]

我们通常都会通过 IP 访问(或者内部域名)访问 sunstone 界面,所以需要改变 sunstone 的默认接听地址,把 host: 127.0.0.1 换成机器所在 IP 地址,需要重启服务让设置生效。注意这里使用 9869 端口,CentOS 6.x 默认是开启防火墙的,所以可以把这个端口加到防火墙规则里也可以直接把防火墙关掉:

# vi /etc/one/sunstone-server.conf
...
# Server Configuration
#
:host: 192.168.2.150
:port: 9869

# service opennebula-sunstone restart
Stopping Sunstone Server daemon: VNC server is not running
sunstone-server stopped
                                                           [  OK  ]
Starting Sunstone Server daemon: VNC proxy started
sunstone-server started
                                                           [  OK  ]

# /etc/init.d/iptables stop
iptables: Flushing firewall rules:                         [  OK  ]
iptables: Setting chains to policy ACCEPT: filter          [  OK  ]
iptables: Unloading modules:                               [  OK  ]

打开浏览器,访问 http://192.168.2.150:9869 登陆界面,那登陆的用户名和密码是啥呢?用户名和密码在安装的时候已经随机生成,oneadmin 是用户名,后面的一串是密码:

# cat /var/lib/one/.one/one_auth
oneadmin:0dee417dfb22f2372866d686c7b12889

登陆成功后界面比以前的版本有很大改进:

opennebula 4.0 sunstone

调整 KVM 虚拟硬盘大小

在 OpenNebula 上创建 KVM 虚拟机如果没有事先规划好虚拟机硬盘,运行一段时间后可能过小的硬盘会成为麻烦,需要能自由的增加虚拟机硬盘容积,有两个办法:一是可以在 OpenNebula 上动态加入第二块硬盘解决第一块硬盘过小的问题;二是直接在第一块硬盘上扩大容积。第一种办法好办,直接用 virsh attach-disk 就可以。如果和调整 Xen 虚拟硬盘大小一样,不想加第二块硬盘,只想在第一块硬盘上扩大容积呢?这里只讨论虚拟机文件形式的硬盘,LVM 形式的 “硬盘” 更容易一些,可以用 lvextend + fsck 调整硬盘大小。

最简单的办法是使用 GParted,挂载 gparted-live iso 文件后启动图形化界面操作分区,很容易:

# kvm -m 512 -hda disk.0 -cdrom /root/gparted-live-0.12.1-5.iso -boot d -vnc :1

这里主要介绍不用 GParted 的办法,分区用 fdisk 就可以了,没有必要也不适合在服务器上使用图形化工具。扩大硬盘镜像:

# qemu-img resize disk.0 +100GB

找一个空闲的 loop 设备并挂上硬盘镜像:

# losetup -f
/dev/loop0

# losetup /dev/loop0 disk.0

用 fdisk 把以前的分区都删除,然后重新创建分区,如果有 swap 区依然要用类型 82 标注,boot 区要标明 bootable,要非常小心:

# fdisk /dev/loop0

挂载硬盘里面的 LVM 分区、强制校验文件系统并扩大文件系统:

# kpartx -av /dev/loop0 
# e2fsck -f /dev/mapper/loop0p1 
# resize2fs -f /dev/mapper/loop0p1 

用 mount 测试一下扩大后的文件系统是否能正常 mount:

# mount /dev/mapper/loop0p1 /mnt
# ls /mnt

卸载和清理:

# umount /mnt
# kpartx -dv /dev/loop0 
# losetup -d /dev/loop0

把上面的步骤弄个小脚本,只对 http://cloud-images.ubuntu.com/ 下载的镜像有效,如果是自己做的镜像需要调整 fdisk 分区时候的指令。注意这里 fdisk 分区的时候 d 是删除分区 n 是创建分区 p 是主分区 1 是第1个 2是第2个 w 是保存,具体看 fdisk 帮助:

#!/bin/bash

DISK=$1
SIZE=$2

qemu-img resize $DISK $SIZE

losetup /dev/loop0 $DISK
fdisk /dev/loop0 <<EOF
d
n
p
1
2

w
EOF

kpartx -av /dev/loop0
e2fsck -f /dev/mapper/loop0p1
resize2fs -f /dev/mapper/loop0p1
kpartx -dv /dev/loop0

losetup -d /dev/loop0

在 KVM 上访问 FreeBSD 虚拟机终端

在移植旧的物理服务器到虚拟机的时候还剩一些非 Linux 系统没有移,主要是 FreeBSD 和 Solaris 系统,还有几台 OpenBSD 的,这些系统大部分运行在很古老的机器上,有的甚至比我的 FreeBSD on IBM TP600E 还老,需要问一下管理员这些机器在干嘛,是否能合并到虚拟机,管理员刚好这周请假去了 WWDC 现场。

提到今年的 WWDC,看完发布会视频又要扯一下了,比较激动的是那个 2880×1800 屏幕的 MacBook Pro,码农实在太需要关怀了,任何每天看电脑8小时以上的人都需要好显示器,Life is short,对自己好点,Get a Mac:)

做了 FreeBSD for KVM 的镜像以后需要能在 KVM 上像访问 Linux 虚拟机终端那样访问 FreeBSD 的虚拟机终端,步骤和在 Linux 上差不多。

在 FreeBSD Guest 上配置

登陆 FreeBSD 后添加和编辑 loader.conf 文件:

# vi /boot/loader.conf
console="comconsole"

在 /etc/ttys 最后加上 ttyd0 一行:

# vi /etc/ttys
...
# Serial terminals
#ttyu0   "/usr/libexec/getty std.9600"   dialup   off secure
ttyu0   "/usr/libexec/getty std.9600"   vt100   on secure
...

重启 FreeBSD:

# reboot

确定 virsh edit 有下面这几行:

# virsh edit freebsd
...
    <serial type='pty'>
      <target port='0'/>
    </serial>
    <console type='pty'>
      <target type='serial' port='0'/>
    </console>
    <video>
      <model type='cirrus' vram='9216' heads='1'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/>
    </video>
...

必要时重启 libvirtd:

# /etc/init.d/libvirtd restart
Stopping libvirtd daemon:                                  [  OK  ]
Starting libvirtd daemon:                                  [  OK  ]

freebsd console on kvm

在 KVM 上访问 Linux 虚拟机终端

用 OpenNebula 制作 Ubuntu 镜像后可以用这个镜像当作模版来创建 OpenNebula 虚拟机,发现一个问题是,这个 KVM 虚拟机(guest)无法在母机(host)上用 virsh console 登陆和显示终端,这是因为那个模板没有引入 console 需要的参数,而且虚拟机里面也没有做相关的设置。解决办法分两步,首先登陆到虚拟机修改一些配置;然后在运行这个虚拟机的 KVM 节点(host)上修改虚拟机的 xml 配置文件。以下介绍虚拟机是 Ubuntu 和 CentOS 的两种配置情况,FreeBSD 配置情况可以参考:在 KVM 上访问 FreeBSD 虚拟机终端

在 Ubuntu Guest 上配置

登陆 ubuntu 虚拟机增加 ttyS0.conf 文件及其内容:

$ sudo vi /etc/init/ttyS0.conf
# ttyS0 - getty
#
# This service maintains a getty on ttyS0 from the point the system is
# started until it is shut down again.
start on stopped rc RUNLEVEL=[2345]
stop on runlevel [!2345]
respawn
exec /sbin/getty -L 38400 ttyS0 vt102

如果不只是希望 Linux login 后看到终端,也希望看到 Linux 的启动过程的话需要在 /etc/default/grub 加入 GRUB_CMDLINE_LINUX 一行,记得运行 update-grub2 自动配置 grub:

$ sudo vi /etc/default/grub
...
GRUB_CMDLINE_LINUX_DEFAULT="console=ttyS0"
...

$ sudo update-grub2

在 CentOS Guest 上配置

在 /etc/securetty 文件末尾追加 ttyS0 一行:

# echo “ttyS0″ >> /etc/securetty

在 /etc/grub.conf 文件里的 kernel 一行增加 console=ttyS0:

# vi /etc/grub.conf
...
title CentOS (2.6.32-220.el6.x86_64)
        root (hd0,0)
        kernel /vmlinuz-2.6.32-220.el6.x86_64 ro root=/dev/mapper/VolGroup-lv_roo
ot rd_NO_LUKS LANG=en_US.UTF-8 rd_NO_MD rd_LVM_LV=VolGroup/lv_swap SYSFONT=latarr
cyrheb-sun16 rhgb crashkernel=auto quiet rd_LVM_LV=VolGroup/lv_root  KEYBOARDTYPP
E=pc KEYTABLE=us rd_NO_DM console=ttyS0
        initrd /initramfs-2.6.32-220.el6.x86_64.img
...

在 /etc/inittab 中增加 ttyS0 一行:

# vi /etc/inittab
...
S0:12345:respawn:/sbin/agetty ttyS0 115200

在 KVM Host 上配置

登陆 KVM 母机(host)用 virsh edit 修改虚拟机的 KVM 启动配置文件,在 device 下面加上 serial 一栏:

# virsh list
Id Name State
----------------------------------
49 one-28 running

# virsh edit one-28
...
<device>
...
    <serial type='pty'>
        <target port='0'/>
    </serial>
    <console type='pty'>
        <target type='serial' port='0'/>
    </console>
...
</devices>

修改后重启 libvirtd,并手动关闭和启动虚拟机:

# /etc/init.d/libvirtd restart
Stopping libvirtd daemon:                                  [  OK  ]
Starting libvirtd daemon:                                  [  OK  ]

# virsh shutdown one-28
# virsh start one-28

修改 OpenNebula 虚拟机实例的内存大小

OpenNebula 创建虚拟机(实例)以后将不能直接更改虚拟机的配置参数,如 CPU、内存等。如果创建虚拟机以后发现内存给的太大,想改小怎么办呢?如何给 OpenNebula 上的虚拟机修改内存呢?(注:OpenNebula 没有直接操作的命令,需要到节点上用 virsh setmem 动态修改。)让人不可思议的是,OpenNebula 推荐的方法是删除原有虚拟机以后重新创建一个配置合适的虚拟机,一些云计算平台认为虚拟机(计算资源)应该像自来水一样打开就用,不用就关闭。个人觉得云计算应该至少能随时改变计算资源(配置),而不是删除+创建。

比如下面这个 id 为28的虚拟机实例用了 2GB 内存,想修改到 1GB:

# onevm list
ID USER     GROUP    NAME         STAT CPU     MEM        HOSTNAME        TIME
...
14 root     oneadmin queue        runn   3      1G         cloud06 40 20:38:50
18 root     oneadmin grid03       runn 144     24G         cloud18 39 00:47:01
19 root     oneadmin grid02       runn 143     32G         cloud21 39 00:26:26
28 root     oneadmin monitor      runn   9      2G         cloud03 05 22:04:14
...

首先找到这个28号虚拟机实例所在的 OpenNebula 计算节点(node),从上面的 HOSTNAME 看出 monitor 运行在 cloud03 这个节点上,我们 ssh 到这个节点操作发现这台 OpenNebula ID 为28的虚拟机实例在这个节点上名字为 one-28:

# ssh [email protected]

# virsh list
 Id Name                 State
----------------------------------
 39 one-20               running
 42 one-25               running
 45 one-28               running

可以动态修改 one-28 的内存参数为 1GB,但是这种办法重启后就会丢失配置重回到 2GB:

# virsh setmem one-28 1048576

所以最好关闭 one-28 后再修改 one-28 配置文件,改动 memory 部分为 1048576(1GB),修改完毕后启动虚拟机:

# virsh shutdown one-28

# virsh edit one-28
...
1048576
...

# virsh start one-28

修改完后 onevm list 会发现 one-28 内存大小依然是 2GB,没有变,这是因为这部分纪录在 OpenNebula 的数据库里,需要修改数据库,先 select 一下发现 OpenNebula 把 VM 的 XML 配置文件写在数据库里,这容易办,用 SQL 语句的 update 操作更新一下数据库:

# sqlite3 /var/lib/one/one.db

sqlite> select * from vm_pool where oid='28';
28|monitor|...2097152...|0|0|1337014904|3|3|1|0|0

sqlite> update vm_pool set body="...1048576..." where oid="28";

然后 onevm list 就会得到正确的、修改过内存的虚拟机实例了:

# onevm list
ID USER     GROUP    NAME         STAT CPU     MEM        HOSTNAME        TIME
...
14 root     oneadmin queue        runn   3      1G         cloud06 40 23:44:51
18 root     oneadmin grid03       runn 144     24G         cloud18 39 03:47:01
19 root     oneadmin grid02       runn 143     32G         cloud21 39 03:32:27
28 root     oneadmin monitor      runn   9   1024M         cloud03 05 01:10:15
...

如何让 OpenNebula 虚拟机自动获得 IP 等网络配置信息?

制作完 OpenNebula 的 Ubuntu 虚拟机镜像后需要对镜像配置一下以适应所在的网络运行环境,因为我们的 OpenNebula 虚拟机使用的是网桥的方式,所以虚拟机启动后会使用现有网络,并企图从 DHCP 服务器那里获得 IP 地址,如果 DHCP 服务器不做绑定的话这样随便获得的 IP 地址并不符合我们在 small_network.net (onevnet create small_network.net) 定义的要求,我们希望虚拟机启动后能从 small_network.net 这个网络配置文件中获得相应的 IP 地址。OpenNebula 里面的 Contextualizing 部分就是用来对付这种情况的,不过 VPSee 在这里介绍一个更简单的偷懒办法:直接用一个启动脚本来搞定。OpenNebula 已经为我们准备了类似的脚本,只需要根据自己的要求调整一下就可以了,这里介绍 for ubuntu 和 for centos 两个版本的脚本,还有 for debian 和 opensuse 的。

Ubuntu 虚拟机

下载 for ubuntu 的 context 文件后放在合适的地方,这个脚本有点问题需要在下载的 vmcontext.sh 文件最后加上重启网络(/etc/init.d/networking restart)这行:

$ wget http://dev.opennebula.org/attachments/download/378/vmcontext.sh 

$ sudo -i

# mv vmcontext.sh /etc/init.d/vmcontext
# chmod +x /etc/init.d/vmcontext
# ln -sf /etc/init.d/vmcontext /etc/rc2.d/S01vmcontext

# echo "/etc/init.d/networking restart" >> /etc/init.d/vmcontext

CentOS 虚拟机

下载 for centos 的 context 文件后放在合适的地方:

# wget http://dev.opennebula.org/projects/opennebula/repository/revisions/master/raw/share/scripts/centos-5/net-vmcontext/vmcontext

# mv vmcontext.sh /etc/init.d/vmcontext
# chmod +x /etc/init.d/vmcontext
# chkconfig --add vmcontext

# reboot

还记得上次说的给 OpenNebula 虚拟机增加 swap 分区的问题吗,直接把激活 swap 的部分放在 vmcontext 里就不必每次创建虚拟机后再增加 swap 的繁琐工作了。

# echo "swapon /dev/sdb" >> /etc/init.d/vmcontext

Hello World, OpenNebula Cloud API 编程

先报告一下我们云计算项目的进度。去年休假前订购的服务器和部件已经陆续到货了,计算节点采用的是 Dell PowerEdge M710HD 刀片服务器,特别为数据中心级虚拟应用设计,海量内存、密集 IO 吞吐等优势,特别适合云计算、虚拟机等应用。现在正在等 Dell 的售后技术人员过来安装服务器和存储阵列,有些电源和机柜问题需要解决,顺利的话下周服务器可以上线。

dell poweredge m710hd

OpenNebula 提供了 XML-RPC 的方式访问 OpenNebula Cloud Api (OCA),这样就允许不同操作系统、不同语言编写的客户端程序可以通过 XML-RPC 远程调用的方式来访问 OpenNebula 服务。下面通过两个不同语言编写的最简单例子抛砖引玉一下,来看看如何是如何与 OCA 打交道的。

OpenNebula 绝大部分是由 Ruby 编写的,其提供的 Ruby OCA API 实现当然是最丰富和完整的。先安装 Ruby OCA Bindings:

$ sudo gem install oca

用 Ruby 编写一小段代码试验一下,以下代码用来打印当前云里每个计算结点的 hostname:

#!/usr/bin/ruby

require 'rubygems'
require 'oca'

include OpenNebula

# OpenNebula credentials
CREDENTIALS = "oneadmin:vpsee"

# XML_RPC endpoint where OpenNebula is listening
ENDPOINT    = "http://localhost:2633/RPC2"

client = Client.new(CREDENTIALS, ENDPOINT)
host_pool = HostPool.new(client)
rc = host_pool.info

# Print all the hostname from the host pool
host_pool.each do |host|
     puts host.name
end

再来看看用 Python 如何编写上面类似功能的代码。安装 Python OCA Bindings:

$ sudo easy_install oca

用 Python 编写一小段代码看一下:

#!/usr/bin/python

import oca

# OpenNebula credentials
CREDENTIALS = "oneadmin:vpsee"

# XML_RPC endpoint where OpenNebula is listening
ENDPOINT    = "http://localhost:2633/RPC2"

client = oca.Client(CREDENTIALS, ENDPOINT)
host_pool = oca.HostPool(client)
host_pool.info()

# Print all the hostname from the host pool
for host in host_pool:
    print host.name

应该没人会想在这种情况下用 Java 或 C++ 吧,Programming Examples 里面提供的 Java OCA 和 C++ 例子比 Ruby, Python 复杂得多。

为 OpenNebula VM 添加 swap 分区

给 OpenNebula 制作 Ubuntu 模板的时候推荐只分一个单独区,不要交换区(swap),交换区可以以后在虚拟机外部由 OpenNebula 加上,这样把 root 区和 swap 区分开更灵活一些,方便以后创建不同大小 swap 的虚拟机。以下是在 OpenNebula 上为 Ubuntu 虚拟机增加 swap 的步骤:

修改 Ubuntu 模板文件,注意 DISK 一栏的 target 是 sda 不是 sda1,否则会出现 Boot Failed: 的错误。

$ vi ubuntu.one
NAME   = ubuntu
CPU    = 1
MEMORY = 512

OS = [ ARCH = x86_64,
        BOOT = hd,
        ROOT = sda1
]

DISK = [ source   = /var/lib/one/images/ubuntu.img,
         clone    = no,
         target   = sda,
         readonly = no ]

DISK = [ type     = swap,
         size     = 512,
         target   = sdb ]

GRAPHICS = [ type ="vnc",
             listen ="0.0.0.0",
             port = "5900" ]

启动 Ubuntu 虚拟机后,OpenNebula 就为这个虚拟机准备了一个大小为 512MB 的分区 /dev/sdb,现在登录虚拟机激活这个 swap,这样 Linux 就能识别 /dev/sdb 是个交换分区了(这个过程其实和在自己电脑上增加交换分区或用文件充当交换分区的过程差不多):

$ vncviewer 172.16.39.111:5900

$ sudo swapon /dev/sdb

$ free
             total       used       free     shared    buffers     cached
Mem:        504112      90896     413216          0      11440      33160
-/+ buffers/cache:      46296     457816
Swap:       524284          0     524284

最后可以在 /etc/fstab 里增加一条记录以便重启虚拟机以后系统能自动加上 swap:

$ sudo vi /etc/fstab
/dev/sdb    none    swap    sw    0    0