本博客主要介绍通过cloud-init工具实现在Ubuntu16.04操作系统和KVM虚拟化技术下实现创建虚拟机同时离线安装编程环境


1. 准备离线安装包

在可以联网的机器上准备好编程语言包,在这里我们以python3.6.8和java8为例

1)下载软件包

python下载链接java下载链接处下载好Python-3.6.8.tgz和jdk-8u321-linux-x64.tar.gz

2)创建放置软件包的磁盘

sudo qemu-img create -f qcow2 package.qcow2 1G

3)挂载磁盘并进行分区

将该磁盘挂载到一台虚拟机上,并对该磁盘进行分区,这里我们假设该磁盘挂载到虚拟机上后为/dev/vda,我们将该磁盘划分为一个区

sudo fdisk /dev/vda

输入n创建一个新分区,剩余选项全都默认回车,创建好之后输入w保存分区并退出,这样我们就在该磁盘上划分出一个1G的分区/dev/vda1,接着对该分区进行格式化

sudo mkfs.ext4 /dev/vda1

4)放置软件包并准备安装环境

我们将磁盘挂载到虚拟机的一个目录下,这里我们在/home/ubuntu下创建package目录,并挂载磁盘,之后创建不同的文件夹用于区别不同的软件包

cd ~
sudo mkdir package
sudo mount /dev/vda1 package
cd package
sudo mkdir java-8
sudo mkdir python-3.6.8

分别将python包和java包放到对应的目录下,因为我们这里采用离线安装python,所以需要预先准备好编译python的软件,同样在该目录下创建目录用于存放python编译软件,这里我们采用递归下载所有deb依赖的方式获取所有的软件包

mkdir python-pkgs
cd python-pkgs
sudo apt-get download $(apt-cache depends --recurse --no-recommends --no-suggests --no-conflicts --no-breaks --no-replaces --no-enhances --no-pre-depends libbz2-dev libssl-dev libreadline6 libreadline6-dev libsqlite3-dev | grep -v i386 | grep "^\w")

最终该磁盘的目录如下显示:

.
├── java-8
│   └── jdk-8u321-linux-x64.tar.gz #java源码包
├── lost+found
├── python-3.6.8
│   └── Python-3.6.8.tgz #python源码包
└── python-pkgs #python编译需要的软件包
    ├── cdebconf_0.198ubuntu1_amd64.deb
    ├── debconf_1.5.58ubuntu2_all.deb
    ├── dpkg_1.18.4ubuntu1.7_amd64.deb
    ├── gcc-6-base_6.0.1-0ubuntu1_amd64.deb
    ├── install-info_6.1.0.dfsg.1-5_amd64.deb
    ├── libbz2-1.0_1.0.6-8ubuntu0.2_amd64.deb
    ├── libbz2-dev_1.0.6-8ubuntu0.2_amd64.deb
    ├── libc6_2.23-0ubuntu11.3_amd64.deb
    ├── libc6-dev_2.23-0ubuntu11.3_amd64.deb
    ├── libc-dev-bin_2.23-0ubuntu11.3_amd64.deb
    ├── libdebian-installer4_0.102ubuntu1.1_amd64.deb
    ├── libgcc1_1%3a6.0.1-0ubuntu1_amd64.deb
    ├── libnewt0.52_0.52.18-1ubuntu2_amd64.deb
    ├── libpcre3_2%3a8.38-3.1_amd64.deb
    ├── libreadline6_6.3-8ubuntu2_amd64.deb
    ├── libreadline6-dev_6.3-8ubuntu2_amd64.deb
    ├── libselinux1_2.4-3build2_amd64.deb
    ├── libslang2_2.3.0-2ubuntu1.1_amd64.deb
    ├── libsqlite3-0_3.11.0-1ubuntu1.5_amd64.deb
    ├── libsqlite3-dev_3.11.0-1ubuntu1.5_amd64.deb
    ├── libssl1.0.0_1.0.2g-1ubuntu4.20_amd64.deb
    ├── libssl-dev_1.0.2g-1ubuntu4.20_amd64.deb
    ├── libtextwrap1_0.1-14_amd64.deb
    ├── libtinfo5_6.0+20160213-1ubuntu1_amd64.deb
    ├── libtinfo-dev_6.0+20160213-1ubuntu1_amd64.deb
    ├── linux-libc-dev_4.4.0-210.242_amd64.deb
    ├── ncurses-bin_6.0+20160213-1ubuntu1_amd64.deb
    ├── readline-common_6.3-8ubuntu2_all.deb
    ├── zlib1g_1%3a1.2.8.dfsg-2ubuntu4.3_amd64.deb
    └── zlib1g-dev_1%3a1.2.8.dfsg-2ubuntu4.3_amd64.deb

完成上述操作后,就可以把磁盘从虚拟机上卸载下来

2. 准备cloud-init环境

这里我们需要一台模板虚拟机,可以参考之前的文章进行安装

1)为虚拟机准备cloud-init环境

参考cloud-init中NoCloud配置中使用方法的第一、二点对一台初始化的虚拟机进行安装并初始化文件和修改cloud-init配置文件操作。

2)准备好安装软件的shell文件

在/etc/cloud目录下,我们准备好安装软件包的shell文件,通过NoCloud启动该脚本文件执行安装

cd /etc/cloud
sudo vim package.sh

文件中的内容如下显示:

#!/bin/bash

package=$1

install_python()
{
    dpkg -i /mnt/python-pkgs/*.deb
    package_full_name=$(ls /mnt/$package/)
    package_name=${package_full_name%.*}
    tar -zxf /mnt/$package/$package_full_name -C /tmp/
    cd /tmp/$package_name
    ./configure && make && make install && make clean | cat > /dev/null
}         
         
install_java()
{
    username=$(ls /home/)        
    java_path="/usr/lib/jvm"
    mkdir $java_path
    tar -zxf /mnt/$package/*.gz -C $java_path
    package_name=$(ls $java_path)
    echo '
#set oracle jdk environment
export JAVA_HOME='$java_path/$package_name >> /home/$username/.bashrc
    echo 'export JRE_HOME=${JAVA_HOME}/jre
export CLASSPATH=.:\${JAVA_HOME}/lib:\${JRE_HOME}/lib
export PATH=${JAVA_HOME}/bin:$PATH' >> /home/$username/.bashrc
}

package_type=${package%%-*}
case $package_type in
python)
    install_python
    ;;
java)
    install_java
    ;;
*)
    return
    ;;
esac

该文件主要定义两个函数,用于安装java和python,通过在启动脚本文件时加入参数来判断安装什么环境,$1代表脚本文件后面带的参数,可以为python-3.6.8或者java-8,其中/mnt目录为我们将上面准备好的磁盘文件到时候直接挂载在虚拟机的/mnt目录下。完成以上操作后关闭虚拟机。

3. 准备user-data文件

我们在物理机上准备好user-data文件,用于传输到虚拟机上配合cloud-init执行操作

sudo vim user-data

user-data文件内容如下:

#cloud-config

chpasswd: 
    list: 
        - ubuntu:root
        - root:root
    expire: false

mounts: 
  - [ /dev/vda1, /mnt, auto, "defaults", "0", "0" ]

runcmd: 
  - sh /etc/cloud/package.sh java-8

文件中chpasswd为配置用户名和密码,如果不需要可以删除,mounts为将磁盘挂载到/mnt目录下,即我们上面准备好的软件包磁盘,runcmd为执行脚本文件,后面的java-8是脚本参数,编写好文件后,创建一个空的meta-data文件,如果不创建,cloud-init会执行失败

touch meta-data

通过iso生成工具将user-data和meta-data封装到iso镜像中

genisoimage -output seed.iso -volid cidata -joliet -rock user-data meta-data

4. 磁盘挂载

将生成的seed.iso和包含安装包的磁盘挂载到虚拟机上,编辑虚拟机对应的xml文件,添加cdrom和disk内容,如果虚拟机已经有cdrom设备,则只需要添加源文件即可

virsh edit ubuntu16.04

添加内容如下:

<disk type='file' device='cdrom'> #如果已有cdrom设备,则只需要添加source file即可
  <driver name='qemu' type='raw'/>
  <source file='/home/xidian/static_file/cloud-init-file/package/seed.iso'/>
  <target dev='hdb' bus='ide'/>
  <readonly/>
  <address type='drive' controller='0' bus='0' target='0' unit='1'/>
</disk>
<disk type='file' device='disk'> #将生成的package.qcow2文件挂载到虚拟机上
  <driver name='qemu' type='qcow2'/>
  <source file='/var/lib/libvirt/images/package.qcow2'/> #packge.qcow2文件位置
  <target dev='vda' bus='virtio'/>
  <address type='pci' domain='0x0000' bus='0x00' slot='0x08' function='0x0'/>
</disk>

启动虚拟机,cloud-init读取cdrom设备的内容并执行user-data文件内容,触发脚本文件,安装编程环境

virsh start ubuntu16.04
Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐