使用vagrant自动部署虚拟机

在虚拟机的日常使用和开发中,我们经常要做很多打包、发布、部署的操作。对于一定的规模之后,或者牵扯到多点分布之后,这个过程就会变成一个无比的痛苦的操作。当然,对于我个人来说,我的第一反应将会是采用container进行封装后发布。但这对于更为复杂的场景——比如虚机+容器的混合场景往往还是只能采用手工操作的方式。

vagrant就是一个针对这个场景下开发出来的快速发布工具。

目前,vagrant几乎可以在任何一个发行版中通过软件管理命令直接安装,比如我的Ubuntu:

sudo apt install vagrant

vagrant支持在virtualbox vmware openstack AWS 以及docker, LXC等多种虚机/容器环境上部署,在这里,我们就按照官方建议的方式,使用virtualbox作为默认的hyper visor. 这里需要注意的是我之前系统中默认安装了oracle virtaulbox,但无法被很好的支持,vagrant只支持开源版本的virtualbox.

sudo apt install virtualbox

这里提一下几个定义:

  • Box:虚拟机或者容器的基础镜像。有点类似于Dockerfile中FROM命令指定的参数。
  • Provider:虚拟化环境,如这里的virtualbox就是provider。
  • Provisioning:指的是虚拟机通过Box启动之后还需要进行的操作,类似于Dockerfile中的COPY, RUN等一系列命令。

还是以Docker的方式理解,Vagratfile就相当于Dockerfile,不同的是它的语法是通过ruby来实现的,这是一个标准的vargrantfile:

Vagrant.configure(2) do |config|

  # Variables
  vagrant_user       = ENV['VAGRANT_USER'] || 'vagrant'
  build_cached_image = ENV["BUILD_CACHED_IMAGE"] == 'true' ? true : false
  share_glide_cache  = ENV["SHARE_GLIDE_CACHE"] || false
  home_dir           = vagrant_user == 'root' ? '/root/' : "/home/#{vagrant_user}"

  provision_development_environment = ENV["SWAN_DEVELOPMENT_ENVIRONMENT"] == 'true' ? true : false

  # Vagrant Box configs
  config.vm.box_check_update = false

  # SSH agent forwarding (for host private keys)
  config.ssh.forward_agent = true

  # Share an additional folder to the guest VM. The first argument is
  # the path on the host to the actual folder. The second argument is
  # the path on the guest to mount the folder. And the optional third
  # argument is a set of non-required options.
  config.vm.synced_folder ".." ,
                          "#{home_dir}/go/src/github.com/intelsdi-x/swan",
                          mount_options: ["umask=0022,dmask=0022,fmask=0022"],
                          type: "rsync"

  # VirtualBox provider
  config.vm.provider "virtualbox" do |vb, override|

    # Vagrant Box config
    override.vm.box = "centos/7"

    # SSH config
    override.ssh.forward_x11 = true

    # Create a private network, which allows host-only access to the machine
    # using a specific IP.
    override.vm.network "private_network", ip: "10.141.141.10"

    vb.name = "swan"
    vb.gui  = false

    # NOTE: integration tests fail with less than 2 vCPUs
    #       integration tests tend to crash with less than 4GB RAM (gcc)
    vb.cpus   = (ENV['VBOX_CPUS'] != '' && ENV['VBOX_CPUS'] || 2)
    vb.memory = (ENV['VBOX_MEM']  != '' && ENV['VBOX_MEM']  || 4096)

    # Share glide cache with guest box
    if share_glide_cache
      override.vm.synced_folder "#{ENV['HOME']}/.glide",
                                "#{home_dir}/.glide",
                                :mount_options => ["umask=0022,dmask=0022,fmask=0022"],
                                type: "rsync"
    end

    override.vm.provision "shell",
     inline: "cd #{home_dir}/go/src/github.com/intelsdi-x/swan/vagrant; ./provision.sh",
     env:
        {
          'VAGRANT_USER' => vagrant_user,
          'HOME_DIR' => home_dir,
          'SWAN_DEVELOPMENT_ENVIRONMENT' => provision_development_environment
        }
  end
  # Env VirtualBox provider

  # OpenStack provider
  config.vm.provider :openstack do |os, override|

    # SSH config
    override.ssh.username = "centos"

    # Auth config
    os.identity_api_version = "3"
    os.openstack_auth_url   = ENV['OS_AUTH_URL']
    os.tenant_name          = ENV['OS_TENANT_NAME']
    os.project_name         = ENV['OS_PROJECT_NAME']
    os.domain_name          = ENV['OS_USER_DOMAIN_NAME']
    os.username             = ENV['OS_USERNAME']
    os.password             = ENV['OS_PASSWORD']
    os.region               = ENV['OS_REGION_NAME']

    # VM config
    os.server_name      = "swan-ci"
    os.image            = ENV['OS_IMAGE_ID'] || "08e833ae-90e7-44b0-9e60-8fec66b7ae65"
    os.flavor           = ENV['OS_FLAVOR_ID'] || "e4bc1e96-cd4d-4850-9ad8-686f7f3d6106"
    os.networks         = ENV['OS_NETWORK_ID'] || "2b5c51a4-0b22-43f7-af53-c2b5da32fa2d"
    os.floating_ip_pool = ENV['OS_FLOATING_POOL'] || "external"
    os.security_groups  = [ "default" ]

    # User data
    # requiretty cannot be set in sudoers for vagrant to work
    os.user_data = "#!/bin/bash\nsed -i 's/Defaults    requiretty/#Defaults    requiretty/' /etc/sudoers"

  end
  # End Openstack provider

end

说实话,对于ruby的语法我不是非常了解,这里就简单介绍几个关键项吧。

  • Vagrant.configure(2) 是一个最大也是这个文件中唯一的一个包含,意思是当vagrant版本大于2时,设定的配置参数。
  • config.vm.provider “virtualbox”,config.vm.provider :openstack, 定义了在两种不同的provider,virtual和openstack上部署时设定的不同。
  • override.vm.provision “shell” 就是provisioning,当虚机第一次部署完成后将会执行的命令。

当我执行vagrant up命令开始部署这个脚本时,首先的第一步是下载centos/7的镜像 (override.vm.box = “centos/7″):

litrin@litrin-de-xubuntu:~/workload/swan/vagrant$ vagrant up
Bringing machine 'default' up with 'virtualbox' provider...
==> default: Box 'centos/7' could not be found. Attempting to find and install...
 default: Box Provider: virtualbox
 default: Box Version: >= 0
==> default: Loading metadata for box 'centos/7'
 default: URL: https://atlas.hashicorp.com/centos/7
==> default: Adding box 'centos/7' (v1710.01) for provider: virtualbox
 default: Downloading: https://vagrantcloud.com/centos/boxes/7/versions/1710.01/providers/virtualbox.box
==> default: Box download is resuming from prior download progress
 default: Progress: 0% (Rate: 0/s, Estimated time remaining: --:--:--)

接下来的部分是设定网络(override.vm.network “private_network”, ip: “10.141.141.10”)和配置SSH认证:

==> default: Importing base box 'centos/7'...
==> default: Matching MAC address for NAT networking...
==> default: Setting the name of the VM: swan
==> default: Clearing any previously set network interfaces...
==> default: Preparing network interfaces based on configuration...
 default: Adapter 1: nat
 default: Adapter 2: hostonly
==> default: Forwarding ports...
 default: 22 (guest) => 2222 (host) (adapter 1)
==> default: Running 'pre-boot' VM customizations...
==> default: Booting VM...
==> default: Waiting for machine to boot. This may take a few minutes...
 default: SSH address: 127.0.0.1:2222
 default: SSH username: vagrant
 default: SSH auth method: private key
 default:
 default: Vagrant insecure key detected. Vagrant will automatically replace
 default: this with a newly generated keypair for better security.
 default:
 default: Inserting generated public key within guest...
 default: Removing insecure key from the guest if it's present...
 default: Key inserted! Disconnecting and reconnecting using new SSH key...
==> default: Machine booted and ready!

然后是设置sharefolder(override.vm.synced_folder) 和执行(override.vm.provision设定的)provisioning脚本:

==> default: Rsyncing folder: /home/litrin/Workloads/swan/vagrant/ => /vagrant
==> default: Rsyncing folder: /home/litrin/Workloads/swan/ => /home/vagrant/go/src/github.com/intelsdi-x/swan
==> default: Running provisioner: shell...
 default: Running: inline script
.....

对于关闭虚机,vagrant提供了几个命令:

  • 正常关机:vagrant halt
  • 暂停续集:vagrant suspending
  • 关机并删除主机:vagrant destroy

尽管定位有很大的不同,我个人还是喜欢将vagrant和docker相比较。跟docker关注软件stack的依赖不同,vagrant更关注的是虚机部署之后的配置。同时由于provider的网络配置要远高于docker,vagrant可以允许用户配置非常复杂的网络结构。

推荐阅读:
似乎每次开头都要讲述一下计算机
5月中旬,我参加了在加利福尼亚
长久以来,我们对计算机资源的理

发表评论

电子邮件地址不会被公开。 必填项已用*标注

请补全下列算式: *

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据