整個Vagrant系列,已經有四篇文章了:
立即上手
上一節中,我們介紹了怎樣安裝 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
複製程式碼
這個檔案的內容很容易讀懂。
-
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。
-
網路設定 預設情況下,vagrant通知provider建立 NAT 型別的網路卡,這樣虛擬機器將能夠和主機之間相互通訊,同時VM能夠藉助宿主機的外網環境直接訪問公網。 在這種情況下,我們可以指定VM的埠轉發來暴露VM中的應用程式的埠,從而在宿主機上可以直接與該埠進行通訊。
config.vm.network "forwarded_port", guest: 80, host: 8080 複製程式碼
例如,我們在VM中安裝了nginx的話,上面的埠轉發設定可以將其暴露為宿主機的 :8080 ,這樣我們從宿主機或者內網的其他主機都可以訪問VM中的nginx服務了。 網路配置是個大話題,我們稍後會專列一章更多地講述幾種最佳實踐。
-
同步資料夾 我們曾經提到過當 SSH 到 VM 中時,
/vagrant
實際上和主機的VM工作目錄是等價的,也就是Vagrantfile
所在的那個目錄。這種特性實際上就是 vagrant 建立的一個同步目錄的機制。一般來說,它是通過 provider 的所謂 共享資料夾(Shared Folder)的特性來實現的。 我們當然並不需要關心 provider 的特性,也不必關心 vagrant 是怎麼做的。我們只需要知道,這個連線點是可以被自定義的:config.vm.synced_folder "../data", "/vagrant_data" 複製程式碼
上面這一配置,會將宿主機的
VM工作目錄/../data
對映為 VM中的/vagrant_data
。 你還可以做到更多:- 同步資料夾支援符號連結,所以你可以通過符號連結聚合主機的其他位置到一個root連線點中。
-
使用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 複製程式碼
-
替換 VM 的 Locale 一般情況下,SSH會話沿用宿主機控制檯的Locale,但你可以通過預定義覆蓋它,在會話中總是使用特定的語言:
ENV["LC_ALL"] = "en_US.UTF-8" Vagrant.configure("2") do |config| # ... end 複製程式碼
-
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。