使用cloud-init在Linux上创建虚拟机

今天我们来聊一聊,如何使用cloud-init在Linux上创建虚拟机,我们会用到kvm和QEMU。

KVM 的全称是 Kernel-based Virtual Machine,即基于内核的虚拟机。它是一种内建于 Linux 内核的开源虚拟化技术。不过 KVM 只是一个内核模块,单独的 KVM 不能看作一个完整的虚拟机软件。好在 Linux 中还有另一个强大的工具 QEMU。QEMU 提供了完整的虚拟化能力,但原始的 QEMU 只提供软件模拟,性能不是很高。而当我们在 QEMU 中集成 KVM 后,就能获得接近裸机的性能,这正是我们想要的。

下面就以 Ubuntu 为例,来看一下如何开启和安装 KVM/QEMU 相关的软件。

  1. 检查硬件虚拟化支持

    在终端中运行如下命令,如果返回值大于 0,表示CPU 支持硬件虚拟化。如果返回 0,则需要在 BIOS 中开启虚拟化功能,不同品牌的主板位置可能有所不同,网上搜索一下即可找到对应指南。

    egrep -c '(vmx|svm)' /proc/cpuinfo
    
  2. 安装 KVM 相关软件包

    sudo apt install -y qemu-kvm libvirt-daemon-system libvirt-clients bridge-utils virt-manager
    

    下面详细介绍一下这些软件包的作用:

    • qemu-kvm: 提供 KVM 内核模块和 QEMU 用户空间程序,是虚拟化的核心组件。

    • libvirt-daemon-system: libvirt 守护进程,用于管理虚拟机。它会自动将 libvirtd 服务配置为开机自启。

    • libvirt-clients: 提供用于与 libvirt 守护进程交互的命令行工具,如 virsh

    • bridge-utils: 包含用于创建和管理网络桥接的工具,这对于配置虚拟机网络非常有用。

    • virt-manager: 一个图形用户界面 (GUI) 工具,用于创建和管理虚拟机(如果系统没有图形界面,可以不用安装这个)。

  3. 将当前用户添加到 libvirt 用户组

    这一步主要是为了让我们能够管理虚拟机而无需每次都使用 sudo。如果不介意使用 sudo 命令,可以跳过这一步。

    sudo adduser $USER libvirt
    

    添加后,重新登录使组成员身份生效。

  4. 验证运行状态

    使用以下命令检查 libvirtd 服务是否正常运行:

    sudo systemctl is-active libvirtd
    

    如果输出显示 active,就表示服务已成功启动并正常运行。

下面重头戏来了,如何批量创建虚拟机!

接下来我们将利用 cloud-init 工具来自动初始化虚拟机。我们选择 Ubuntu(我个人很喜欢这个发行版)来进行演示。

  1. ubuntu cloud 镜像下载

    wget -P ~/Downloads https://cloud-images.ubuntu.com/jammy/current/jammy-server-cloudimg-amd64.img
    
  2. 安装 cloud-localds 工具

    sudo apt install cloud-image-utils
    
  3. 创建默认的初始化数据

    # 创建基础目录
    mkdir -p ~/kvm/ubuntu-vms
    cd ~/kvm/ubuntu-vms
    
    # 使用的 cloud image
    cp ~/Downloads/jammy-server-cloudimg-amd64.img base.img
    
    authorized_key="ssh-rsa <你的系统的的公钥,使用ssh-keygen -t rsa 命令创建>"
    if [ -f ~/.ssh/id_rsa.pub ]; then
     	authorized_key=$(cat ~/.ssh/id_rsa.pub)
    fi
    
    # 用户名、公钥等自定义内容(示例)
    cat > user-data <<EOF
    #cloud-config
    users:
      - name: ubuntu
        ssh-authorized-keys:
          - ${authorized_key}
        sudo: ALL=(ALL) NOPASSWD:ALL
        groups: sudo
        shell: /bin/bash
        lock_passwd: false
        plain_text_passwd: "ubuntu"
    
    ssh_pwauth: true
    
    runcmd:
      - systemctl enable serial-getty@ttyS0.service
      - systemctl start serial-getty@ttyS0.service
      - sed -i 's/GRUB_CMDLINE_LINUX="/GRUB_CMDLINE_LINUX="console=ttyS0,115200n8 console=tty0 /' /etc/default/grub
      - update-grub
    EOF
    
  4. 创建虚拟机

    for i in 01 02 03; do
      name="ubuntu-$i"
      disk="$name.img"
      seed="$name-seed.iso"
    
      # 创建磁盘(基于 cloud image)
      qemu-img create -f qcow2 -b base.img -F qcow2 $disk 10G
    
      # 创建 cloud-init ISO(指定 hostname)
      cat > meta-data <<EOF
    instance-id: $name
    local-hostname: $name
    EOF
    
      cloud-localds $seed user-data meta-data
    
      # 创建虚拟机,参数可以自行调整
      virt-install \
        --name $name \
        --ram 2048 \
        --vcpus 2 \
        --os-variant ubuntu22.04 \
        --disk path=$disk,format=qcow2 \
        --disk path=$seed,device=cdrom \
        --network network=default,model=virtio \
        --graphics none \
        --console pty,target_type=serial \
        --import \
        --noautoconsole
    done
    
    • 使用 cloud-init 自动配置 SSH、公钥、串口终端等;
    • 镜像大小为 10GB(稀疏分配);
    • 使用 NAT 网络(default 网络);
    • –graphics none 和 --console 保证可以用 virsh console 登录。

    上面的脚本创建了三个虚拟机,分别为 ubuntu-01,ubuntu-02,ubuntu-03,使用下面命令看一下虚拟机运行情况

    sudo virsh list --all
    

    正常情况应该有类似如下的输出:

    Id   Name        State
    ---------------------------
     4    ubuntu-01   running
     5    ubuntu-02   running
     6    ubuntu-03   running
    

    我们试着连接一下虚拟机看一下

    sudo virsh console ubuntu-01
    

    会有下面的输出:

    Connected to domain 'ubuntu-01'
    Escape character is ^] (Ctrl + ])
    

    再按一下回车,进入登录界面:

    Connected to domain 'ubuntu-01'
    Escape character is ^] (Ctrl + ])
    
    ubuntu-01 login:
    

    输入我们预定义的用户 ubuntu,发现这里需要输入密码,输入我们预定义的密码即可以登录成功

    Connected to domain 'ubuntu-01'
    Escape character is ^] (Ctrl + ])
    
    ubuntu-01 login: ubuntu
    Password:
    

    也可以在宿主系统中直接使用 ssh 登录,虚拟机的 ip 地址可以在 console 使用密码登录后使用 ip address 命令获取,或者使用如下命令,不登录系统获取 ip 地址

    sudo virsh domifaddr ubuntu-01
    

    会得到类似下面的输出

    Name       MAC address          Protocol     Address
    -------------------------------------------------------------------------------
     vnet1      52:54:00:ae:aa:e8    ipv4         192.168.122.231/24
    

    在这个例子中我们可以直接使用 ssh ubuntu@192.168.122.231 然后输入密码之后,就可以使用 ssh 登录我们的虚拟机了。

注意:我们上面的演示默认都是使用 qemu 的system模式,所以操作的时候要使用sudo,除了 system 模式,qemu 还提供了一个session模式。session 模式的介绍不在本文中讨论。

其他:
附上几个有用的shell代码,放在~/.bashrc或者 ~/.zshrc文件中,方便操作虚拟机:

# 获取虚拟机对应的ip地址,使用方法 vmip <虚拟机名>
vmip() {
  local name="$1"
  sudo virsh domifaddr "$name" | awk '/ipv4/ {print $4}' | cut -d'/' -f1
}

# 登录虚拟机支持: ssh <虚拟机名> 登录,以及 ssh <用户名>@<虚拟机名> 登录
vmssh() {
  local input="$1"
  local user host ip

  if [[ "$input" == *"@"* ]]; then
    user="${input%@*}"
    host="${input#*@}"
  else
    user="ubuntu"
    host="$input"
  fi

  # 如果 host 是 IP 地址(纯数字加点)
  if [[ "$host" =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
    ip="$host"
  else
    ip=$(sudo virsh domifaddr "$host" | awk '/ipv4/ {print $4}' | cut -d'/' -f1)
    if [[ -z "$ip" ]]; then
      echo "❌ 无法获取虚拟机 $host 的 IP 地址" >&2
      return 1
    fi
  fi

  echo "🔗 正在连接 $user@$ip ..."
  ssh "$user@$ip"
}

# 删除虚拟机及其磁盘 使用方法 vmrm <虚拟机名>
vmrm() {
  local name="$1"
  if [[ -z "$name" ]]; then
    echo "⚠️ 请输入要删除的虚拟机名称,例如:vmrm ubuntu-01"
    return 1
  fi

  echo "⚠️ 即将删除虚拟机:$name"
  read "confirm?确认删除该虚拟机及其磁盘?[y/N]: "
  if [[ "$confirm" != "y" && "$confirm" != "Y" ]]; then
    echo "取消删除。"
    return 0
  fi

  # 获取磁盘路径
  local disk
  disk=$(sudo virsh domblklist "$name" | awk '/^vda/ {print $2}')

  echo "🔻 销毁虚拟机..."
  sudo virsh destroy "$name" 2>/dev/null

  echo "🧹 删除虚拟机定义..."
  sudo virsh undefine "$name" --remove-all-storage 2>/dev/null

  # 若磁盘未自动删除,尝试手动删除
  if [[ -n "$disk" && -f "$disk" ]]; then
    echo "🗑️ 删除磁盘文件 $disk"
    sudo rm -f "$disk"
  fi

  echo "✅ 虚拟机 $name 删除完成。"
}

alias vmall="sudo virsh list --all"
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值