Vagrant (二) - 日常操作

hedzr發表於2019-02-27

整個Vagrant系列,已經有四篇文章了:

  1. Vagrant (一) - 基本知識
  2. Vagrant (二) - 日常操作
  3. Vagrant (三) - 網路配置
  4. Vagrant (四) - Box的用法

立即上手

上一節中,我們介紹了怎樣安裝 Vagrant,安裝本身並不困難。本章節中我們首先要快速上手,以便獲得一個直觀的概念:

建立一個工作目錄

開啟命令列工具,終端工具,或者iTerm2等,建立一個我們將要新建虛機的專案目錄,例如 first-vm

cd $HOME
mkdir -p vms/first-vm
cd vms/first-vm
複製程式碼

Windows的命令可能像這樣:

    cd %HOME%
    mkdir -p vms\first-vm
    cd vms\first-vm
複製程式碼

我們需要一個完全空白的工作目錄作為開始。如上我們新建一個目錄當做專案目錄的基準位置。

初始化一個作業系統

以 Ubuntu 作業系統為虛擬機器的例子,我們可以這樣初始化:

vagrant init ubuntu/xenial64
複製程式碼

這個命令將會去下載 ubuntu 的 box 映象回來,然後以該映象為核心,在工作目錄下建立一份虛擬機器規範描述檔案 Vagrantfile。有關的描述我們稍後會加以介紹。

在這裡,你需要知道的是,你可以修改或檢視這個文字格式的檔案。本質上說,Vagrantfile採用ruby等價的語法,所以你可以選擇文字編輯器按照ruby進行語法加亮。在啟動這個vagrant虛機之前,可以修改Vagrantfile中的配置,例如新增更多網路卡。

啟動虛擬機器並操作它

那麼,我們可以啟動這個虛機或者關閉它:

vagrant up         #啟動虛機
vagrant halt       #停止虛機
vagrant destroy [-f]    #刪除虛機
複製程式碼

刪除虛機的指令將會全部刪除虛機的後端vmm中的全部相關檔案、快照等等,但並不會刪除專案目錄中的 Vagrantfile

當虛機啟動之後,在專案目錄執行命令 vagrant ssh 可以登入到虛擬機器中。

虛機目錄 /vagrant 和專案目錄是自動同步的,在虛機中寫入/vagrant中將會在宿主機中的專案目錄中找到相應的內容。

虛機是完整的 Ubuntu 作業系統,當使用 vagrant ssh 登入到虛擬機器中之後,你得到了一個虛擬機器的終端控制檯,現在你可以使用 Ubuntu 自身的shell指令了,並且可以隨時通過 exit 結束控制檯返回到宿主機的控制檯環境。

$ vagrant up
...
$ vagrant ssh
vagrant@vm1> ll /vagrant
...
vagrant@vm1> exit
$ ...
$ vagrant shutdown
複製程式碼

使用Vagrant

常用命令

vagrant init [name [url]]        # 初始化當前目錄到 vagrant 環境
vagrant up                       # 啟動虛擬機器
vagrant halt                     # 關閉虛擬機器
vagrant reload                   # 重啟虛擬機器
vagrant status                   # 檢視虛擬機器執行狀態
vagrant destroy [-f]              # 銷燬當前虛擬機器(但不刪除Vagrantfile)
vagrant suspend                  # 掛起當前虛擬機器
vagrant resume                   # 恢復被掛起的vm

vagrant ssh                      # SSH 登入至虛擬機器

vagrant box add ADDRESS          # 安裝box檔案/url到本地
vagrant box list                 # 列出所有本地已安裝的box列表
vagrant box outdated             # 檢查已安裝的box是否有更新的版本
vagrant box remove NAME          # 刪除某個已安裝的box

vagrant package         # 打包當前虛擬機器環境為box檔案以用於分發
vagrant plugin          # 安裝解除安裝vagrant外掛
vagrant provision       # 執行專門的環境初始化指令碼
vagrant ssh-config      # 輸出ssh連線的一些資訊
vagrant version         # 獲取vagrant的版本
複製程式碼

更多命令可以檢視 vagrant 官方的文件

轉換現有虛擬機器為box包

對於剛建立的第一個虛擬機器映象first-vm,它的專案目錄名稱為“first-vm”,並且已經至少使用 vagrant up 啟動過一次了,那麼我們現在可以將這個虛擬機器匯出為box包:

vagrant package --base=first-vm --output=first-vm-v1.box
複製程式碼

這個box同樣可以被新增到本機的vagrant boxes快取中:

vagrant box add first-vm-v1.box --name=first-vm-v1
複製程式碼

box檔案實際上是一個 OVF 包。

開源虛擬化格式OVF檔案是一種開源的檔案規範,它描述了一個開源、安全、有效、可擴充的行動式虛擬打包以及軟體分佈格式,它一般有幾個部分組成,分別是ovf檔案、mf檔案、cert檔案、vmdk檔案和iso檔案。

如果網路模式中使用 private_network 的話,在打包之前需要清除一下private_network的設定,避免不必要的錯誤:

vm$ sudo rm -f /etc/udev/rule.d/70-persistent-net.rules
複製程式碼

這條bash指令應該在虛機中被執行,對於不同的作業系統來說,檔案的位置可能是有變化的。

將這個box檔案分發給同事,則他們也可以建立一個完全等價的虛擬機器。

vagrant box add first-vm-v1.box --name=myteam/first-vm-v1
vagrant init my-team/first-vm-v1
vagrant up
複製程式碼

Vagrantfile 介紹

此前,我們通過 vagrant init 的指令建立了新的虛擬機器環境,在工作目錄中一個 Vagrantfile將被自動建立,如果它尚未存在的話。 這個檔案通常應該是這樣子的:

# -*- mode: ruby -*-
# vi: set ft=ruby :

# All Vagrant configuration is done below. The "2" in Vagrant.configure
# configures the configuration version (we support older styles for
# backwards compatibility). Please don't change it unless you know what
# you're doing.
Vagrant.configure("2") do |config|
  # The most common configuration options are documented and commented below.
  # For a complete reference, please see the online documentation at
  # https://docs.vagrantup.com.

  # Every Vagrant development environment requires a box. You can search for
  # boxes at https://vagrantcloud.com/search.
  config.vm.box = "ubuntu/xenial64"

  # Disable automatic box update checking. If you disable this, then
  # boxes will only be checked for updates when the user runs
  # `vagrant box outdated`. This is not recommended.
  # config.vm.box_check_update = false

  # Create a forwarded port mapping which allows access to a specific port
  # within the machine from a port on the host machine. In the example below,
  # accessing "localhost:8080" will access port 80 on the guest machine.
  # NOTE: This will enable public access to the opened port
  # config.vm.network "forwarded_port", guest: 80, host: 8080

  # Create a forwarded port mapping which allows access to a specific port
  # within the machine from a port on the host machine and only allow access
  # via 127.0.0.1 to disable public access
  # config.vm.network "forwarded_port", guest: 80, host: 8080, host_ip: "127.0.0.1"

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

  # Create a public network, which generally matched to bridged network.
  # Bridged networks make the machine appear as another physical device on
  # your network.
  # config.vm.network "public_network"

  # 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 "../data", "/vagrant_data"

  # Provider-specific configuration so you can fine-tune various
  # backing providers for Vagrant. These expose provider-specific options.
  # Example for VirtualBox:
  #
  # config.vm.provider "virtualbox" do |vb|
  #   # Display the VirtualBox GUI when booting the machine
  #   vb.gui = true
  #
  #   # Customize the amount of memory on the VM:
  #   vb.memory = "1024"
  # end
  #
  # View the documentation for the provider you are using for more
  # information on available options.

  # Enable provisioning with a shell script. Additional provisioners such as
  # Puppet, Chef, Ansible, Salt, and Docker are also available. Please see the
  # documentation for more information about their specific syntax and use.
  # config.vm.provision "shell", inline: <<-SHELL
  #   apt-get update
  #   apt-get install -y apache2
  # SHELL
end
複製程式碼

這個檔案的內容很容易讀懂。

  1. box

      config.vm.box = "ubuntu/xenial64"
    複製程式碼

    這句話是指定作業系統用的。換句話說,你用文字編輯器修改它也就會隨心替換系統了。

    只不過如果你真的要這麼做的話,需要執行 vagrant destroy; vagrant up 這樣的序列,以便清理舊的虛擬機器設施和以新的虛機配置建立相應的設施。

    對於 VirtualBox來說,它提供了 VBoxManage 命令列工具可以針對某個 VM 做很多事,modifyvm 就是一條可以修訂 VM 配置引數的子命令。而Vagrant也可以在配置檔案 Vagrantfile 中操作 virtualbox 以達到類似的目的。例如:

      config.vm.provider "virtualbox" do |v|
        v.customize ["modifyvm", :id, "--name", "bastion", "--memory", "2048"]
      end
    複製程式碼

這個示例可以修改 VM 的記憶體為 2GB。

  1. 網路設定 預設情況下,vagrant通知provider建立 NAT 型別的網路卡,這樣虛擬機器將能夠和主機之間相互通訊,同時VM能夠藉助宿主機的外網環境直接訪問公網。 在這種情況下,我們可以指定VM的埠轉發來暴露VM中的應用程式的埠,從而在宿主機上可以直接與該埠進行通訊。

      config.vm.network "forwarded_port", guest: 80, host: 8080
    複製程式碼

    例如,我們在VM中安裝了nginx的話,上面的埠轉發設定可以將其暴露為宿主機的 :8080 ,這樣我們從宿主機或者內網的其他主機都可以訪問VM中的nginx服務了。 網路配置是個大話題,我們稍後會專列一章更多地講述幾種最佳實踐。

  2. 同步資料夾 我們曾經提到過當 SSH 到 VM 中時,/vagrant 實際上和主機的VM工作目錄是等價的,也就是 Vagrantfile 所在的那個目錄。這種特性實際上就是 vagrant 建立的一個同步目錄的機制。一般來說,它是通過 provider 的所謂 共享資料夾(Shared Folder)的特性來實現的。 我們當然並不需要關心 provider 的特性,也不必關心 vagrant 是怎麼做的。我們只需要知道,這個連線點是可以被自定義的:

      config.vm.synced_folder "../data", "/vagrant_data"
    複製程式碼

    上面這一配置,會將宿主機的 VM工作目錄/../data 對映為 VM中的 /vagrant_data。 你還可以做到更多:

    • 同步資料夾支援符號連結,所以你可以通過符號連結聚合主機的其他位置到一個root連線點中。
  3. 使用ruby迴圈語句建立多個 VMs 在一個Vagrantfile配置中,建立一組VMs是很容易的事情:

    (1..3).each do |i|
      config.vm.define "node-#{i}" do |node|
        node.vm.provision "shell",
          inline: "echo hello from node #{i}"
      end
    end
    複製程式碼

    值得注意的是,使用ruby的 for i in 1..3 do 迴圈,你無法得到想要的結果。原因是 for i in 語句在每次迴圈迭代時為 i 賦新的值,並重用迴圈體的語句塊,這就導致 |node| 也並不得到新的副本,而是上一次迴圈時的 node,結果是你只能得到一個不斷修改後的單一的 VM。如下所示:

    # THIS DOES NOT WORK!
    for i in 1..3 do
      config.vm.define "node-#{i}" do |node|
        node.vm.provision "shell",
          inline: "echo hello from node #{i}"
      end
    end
    複製程式碼
  4. 替換 VM 的 Locale 一般情況下,SSH會話沿用宿主機控制檯的Locale,但你可以通過預定義覆蓋它,在會話中總是使用特定的語言:

    ENV["LC_ALL"] = "en_US.UTF-8"
    
    Vagrant.configure("2") do |config|
      # ...
    end
    複製程式碼
  5. Provisioning Provisioning 也是一個大話題。我會考慮單列一章。 不過在這裡,我們主要是提及這個機制能幹些什麼。 簡單地說,Provisioning是一個首次啟動時的後初始化點,它發生在 VM 作業系統被安裝就緒,並首次啟動完成時。你可以編寫 Shell 指令碼在這個點自動完成你的專屬環境初始化動作,例如安裝標準服務、安裝bash擴充套件元件(例如git-prompt)、建立必要的工作資料夾和拉取特定的分發包之類。 如果有必要,在今後,即使VM已經完成了首次初始化了,你也可以通過 vagrant up --provision 這樣的指令來強制 VM 開機和再次執行 Provisioning 指令碼。 在 Vagrantfile 中,典型地可以這樣指定 Provioning:

    $script = <<-SCRIPT
    echo I am provisioning...
    date > /etc/vagrant_provisioned_at
    SCRIPT
    
    Vagrant.configure("2") do |config|
      config.vm.provision "shell", inline: $script
    end
    複製程式碼

    也可以指定一個指令碼檔案,注意我們通過 /vagrant 傳遞 provision.sh 到 VM 中,而典型的 box 系統中,/vagrant 是在 $PATH 搜尋路徑中的:

    Vagrant.configure("2") do |config|
      config.vm.provision "shell", path: "provision.sh"
    end
    複製程式碼

    你也可以指定指令碼的全路徑名,甚至可以在 path 中指定一個 url。

參考