在本地kvm运行CloudInit

CloudInit是最先由Amazon贡献,用于EC2的instance初始化,继而被各linux厂商(ubunturedhat)所采纳,用在各种linux的cloud image上。这篇文章基于Ubuntu 12.04,谈谈如何使用CloudInit以NoCould的方式初始化linux image,以及这种方式对我们可能有的启发。

安装KVM

首先按照这篇文章安装好KVM。

hweicdl@hweicdl-t430:~$ lsmod | grep kvm
kvm_intel             137888  0 
kvm                   422160  1 kvm_intel
hweicdl@hweicdl-t430:~$ kvm-ok
INFO: /dev/kvm exists
KVM acceleration can be used

如果无法安装很有可能是被BIOS禁掉了,那么需要在BIOS里打开:

安装cloud-init

  • 对于12.10之后的版本,只需要 sudo apt-get install cloud-utils
  • 由于cloud-localds是在ubuntu 12.10之后才加入的,对于12.04,除了上面的命令,还需要手工安装cloud-localds

    bzr branch lp:cloud-utils
    sudo cp cloud-utils/bin/cloud-localds /usr/local/bin
    sudo apt-get --assume-yes install genisoimage qemu-utils coreutils
    

下载ubuntu cloud image

我们选用13.10的cloud image下载:
wget http://cloud-images.ubuntu.com/releases/13.10/release/ubuntu-13.10-server-cloudimg-amd64-disk1.img

下载回来的是200多M的压缩qcow2格式,当然可以直接来用,只不过在启动的时候会做解压,影响启动速度,在这儿我们把它解压:qemu-img convert -O qcow2 ubuntu-13.10-server-cloudimg-amd64-disk1.img my_vm.img

之后,我们就都用这个解压后的my_vm.img

hweicdl@hweicdl-t430:~/projects/cloudinit/test$ qemu-img info my_vm.img 
image: my_vm.img
file format: qcow2
virtual size: 2.0G (2147483648 bytes)
disk size: 825M
cluster_size: 65536

cloud-init配置脚本

cloud-init的配置脚本可包含多种类型,其中最重要的是cloud config data,即配置密码,ssh key,网络,mount point等等,完整的信息参考link1link2

在这我们只选取部分信息来构建cloud config data:

hweicdl@hweicdl-t430:~/projects/cloudinit/test$ cat my-user-data 
#cloud-config
password: passw0rd
chpasswd: { expire: False }
ssh_pwauth: True

ssh_authorized_keys:
 - ssh-rsa 你的~/.ssh/id_rsa.pub内容

timezone: Asia/Chongqing

有了这部分信息,就可以构建一个no-cloud的metadata image(否则的话也能启动vm,但内部会一直尝试连接169.254.169.254几分钟):cloud-localds my-seed.img my-user-data

接着就可以以no-cloud的方式启动这个vm:kvm -net nic -net user,hostfwd=tcp::2222-:22 -hda my_vm.img -hdb my-seed.img -m 512

由于作了ssh port forward,除了有原生的QEMU窗口登录外,还可以直接ssh登录:ssh -p 2222 ubuntu@localhost

Go deep in cloud-init

先来看看cloud-localds的help信息:

hweicdl@hweicdl-t430:~/projects/cloudinit/test$ cloud-localds help
Usage: cloud-localds [ options ] output user-data [meta-data]

   Create a disk for cloud-init to utilize nocloud

   options:
     -h | --help            show usage
     -d | --disk-format D   disk format to output. default: raw
     -H | --hostname    H   set hostname in metadata to H
     -f | --filesystem  F   filesystem format (vfat or iso), default: iso9660

     -i | --interfaces  F   write network interfaces file into metadata
     -m | --dsmode      M   add 'dsmode' ('local' or 'net') to the metadata
                            default in cloud-init is 'net', meaning network is
                            required.
     -v | --verbose         increase verbosity

   Note, --dsmode, --hostname, and --interfaces are incompatible
   with metadata.

   Example:
    * cat my-user-data
      #cloud-config
      password: passw0rd
      chpasswd: { expire: False }
      ssh_pwauth: True
    * echo "instance-id: $(uuidgen || echo i-abcdefg)" > my-meta-data
    * cloud-localds my-seed.img my-user-data my-meta-data
    * kvm -net nic -net user,hostfwd=tcp::2222-:22 \
         -drive file=disk1.img,if=virtio -drive file=my-seed.img,if=virtio
    * ssh -p 2222 ubuntu@localhost
must provide output, userdata

可以看到cloud-localds还可以接收一个可选的参数:meta-data。这个文件里的内容是与instance相关的,例如hostname,instance-id等。一般情况下(也是绝大多数情况)它都应该只用来做初始化,即运行完一次就不要再修改它了。只要instance-id不变,即使以kvm -net nic -net user,hostfwd=tcp::2222-:22 -hda my_vm.img -hdb my-seed.img -m 512启动N遍,也再不会使用任何user-data和meta-data中的内容。这也是cloud-init这个词中init的意义,它只需要也应该run once。

但从另一个角度看,我们也可以以重新生成instance-id的方式去“强行”重新初始化这个cloud image/instance。即启动时像上面的uuidgen就重新生成一个id,然后用cloud-localds去重新生成my-seed.img

另外,上面说过cloud config data是最重要且必需的一类数据,若想加入其他初始化行为,就必须把所有的数据以MIME的方式写在同一个文件里。例如我们有一个shell,它在启动时echo一句话到某个文件:

hweicdl@hweicdl-t430:~/projects/cloudinit/test$ cat hello_world.sh 
#!/bin/bash
echo "hello world!" >> /home/ubuntu/test

我们可以把这种行为与cloud config data合并在一起:write-mime-multipart --output=combined-userdata.txt hello_world.sh:text/x-shellscript my-user-data。然后重新生成no cloud data:cloud-localds my-seed.img combined-userdata.txt,最后启动kvm即可。