天天看點

「運維」超詳細的 Vagrant 上手指南

作者:架構思考
搭建 Linux 虛拟機,别再用 VirtualBox 從 .iso 檔案安裝了。

一、概述

也許你已經習慣了 docker,習慣了在 XX 雲上快速建立雲主機,但是如果你想在個人電腦上安裝虛拟機來搭建開發/測試環境,Vagrant 仍然不失高效之選。

文末有和 docker 的對比說明,本篇内容字數過萬,收藏的同時别忘了點個贊,謝謝!

二、安裝軟體

安裝 VirtualBox

進入 VirtualBox 的首頁,點選大大的下載下傳按鈕,即可進入下載下傳頁面。

VirtualBox 是一個跨平台的虛拟化工具,支援多個作業系統,根據自己的情況選擇對應的版本下載下傳即可。

注意,除了主程式,還要把對應的擴充包程式也一并下載下傳了。有些進階特性,比如 USB 3.0 等需要擴充包的支援。

「運維」超詳細的 Vagrant 上手指南

在安裝完主程式後,直接輕按兩下擴充封包件即可安裝擴充包。

下載下傳頁面先别關,後面還要用到。

安裝 Vagrant

在 Vagant 網站下載下傳最新的版本,根據自己的作業系統選擇對應的版本下載下傳即可。

注意,Vagrant 是沒有圖形界面的,是以安裝完成後也沒有桌面快捷方式。具體使用方法,接下來會詳細說明。

Vagrant 的安裝程式會自動把安裝路徑加入到 PATH 環境變量,是以,這時候可以通過指令行執行 vagrant version 檢查是否安裝成功:

> vagrant version
Installed Version: 2.2.7
Latest Version: 2.2.8           

三、配置虛機存放位置

建立虛拟機會占用較多的磁盤空間,在 Windows 系統下預設的虛機建立位置是在 C 盤,是以最好配置到其它地方。

配置 VirtualBox

啟動 VirtualBox 後,通過菜單 管理 -> 全局設定,或者按下快捷鍵 Ctrl + g,在全局設定對話框中,修改 預設虛拟電腦位置,指定一個容量較大的磁盤。

「運維」超詳細的 Vagrant 上手指南

配置 Vagrant

通過 Vagrant 建立虛機需要先導入鏡像檔案,也就是 box,它們預設存儲的位置在使用者目錄下的 .vagrant.d 目錄下,對于 Windows 系統來說,就是 C:\Users\使用者名\.vagrant.d。

如果後續可能會用到較多鏡像,或者你的 C 盤空間比較緊缺,可以通過設定環境變量 VAGRANT_HOME 來設定該目錄。

在 Windows 系統中,可以這樣操作:建立系統環境變量,環境變量名為 VAGRANT_HOME,變量值為 E:\VirtualBox\.vagrant.d

「運維」超詳細的 Vagrant 上手指南
注意,最後這個 .vagrant.d 目錄名稱不是必須的,但是建議保持一緻,這樣一眼看上去就能知道這個目錄是做什麼用處的了。

四、下載下傳虛機鏡像

使用 Vagrant 建立虛機時,需要指定一個鏡像,也就是 box。開始這個 box 不存在,是以 Vagrant 會先從網上下載下傳,然後緩存在本地目錄中。

Vagrant 有一個鏡像網站,裡面列出了都有哪些鏡像可以用,并且提供了操作文檔。

但是這裡預設下載下傳往往會比較慢,是以下面我會介紹如何在其它地方下載下傳到基礎鏡像,然後按照自己的需要重置。如果網速較好,下載下傳順利的朋友可以選擇性地跳過部分内容。

下面我給出最常用的兩個 Linux 作業系統鏡像的下載下傳位址:

CentOS

CentOS 的鏡像下載下傳網站是: http://cloud.centos.org/centos/

在其中選擇自己想要下載下傳的版本,清單中有一個 vagrant 目錄,裡面是專門為 vagrant 建構的鏡像。選擇其中的 .box 字尾的檔案下載下傳即可。這裡可以使用下載下傳工具,以較快的速度下載下傳下來。

這裡我們選擇下載下傳的是 CentOS 7 的最新版本

Ubuntu

Ubuntu 的鏡像下載下傳網站是: http://cloud-images.ubuntu.com/

同樣先選擇想要的版本,然後選擇針對 vagrant 的 .box 檔案即可。

如果這裡官網的速度較慢,還可以從 清華大學的鏡像站 下載下傳。

下面的例子以 CentOS 7 為例,使用其它版本作業系統的也可以參考。

五、添加 box

接下來我們需要将下載下傳後的 .box 檔案添加到 vagrant 中。

Vagrant 沒有 GUI,隻能從指令行通路,先啟動一個指令行,然後執行:

$ vagrant box list
There are no installed boxes! Use `vagrant box add` to add some.           

提示現在還沒有 box。如果這是第一次運作,此時 VAGRANT_HOME 目錄下會自動生成若幹的檔案和檔案夾,其中有一個 boxes 檔案夾,這就是要存放 box 檔案的地方。

執行 vagrant box add 指令添加 box:

$ vagrant box add e:\Downloads\CentOS-7.box --name centos-7
==> box: Box file was not detected as metadata. Adding it directly...
==> box: Adding box 'centos-7' (v0) for provider:
    box: Unpacking necessary files from: file:///e:/Downloads/CentOS-7.box
    box:
==> box: Successfully added box 'centos-7' (v0) for 'virtualbox'!           

指令後面跟着的是下載下傳的檔案路徑,并且通過 --name centos-7 為這個 box 指定一個名字。

後面建立虛機都需要指定這個名字,是以盡量把名字取得簡短一點,同時也要能辨別出這個鏡像的資訊(我們後面會定制自己的基礎鏡像,是以這裡可以簡單點)。

再次查詢,可以看到有了一個 box:

$ vagrant box list
centos-7 (virtualbox, 0)           

六、Vagrant 基本操作

建立虛機

建立一個目錄,先執行 vagrant init:

$ mkdir demo
$ cd demo
$ vagrant init centos-7
A `Vagrantfile` has been placed in this directory. You are now
ready to `vagrant up` your first virtual environment! Please read
the comments in the Vagrantfile as well as documentation on
`vagrantup.com` for more information on using Vagrant.           

其中的 centos-7 就是我們要使用的 box 名字。

這個指令隻是為我們生成一個 Vagrantfile,是以,這裡的名字沒指定或者寫錯了都沒關系,後面會介紹如何編輯這個 Vagrantfile 來修改。

啟動虛機

我們等會再來細看這個檔案,現在直接按照提示執行 vagrant up:

$ vagrant up
Bringing machine 'default' up with 'virtualbox' provider...
==> default: Importing base box 'centos-7'...
==> default: Matching MAC address for NAT networking...
==> default: Setting the name of the VM: demo_default_1588406874156_65036
==> default: Clearing any previously set network interfaces...
==> default: Preparing network interfaces based on configuration...
    default: Adapter 1: nat
==> default: Forwarding ports...
    default: 22 (guest) => 2222 (host) (adapter 1)
==> 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           

正常的情況下,不到一分鐘應該就能啟動成功了。

這裡我遇到點問題,2222 端口轉發出現未知錯誤,造成 vagrant 的啟動逾時。檢查了這個端口并沒被占用,同時更改大一點的端口可以轉發成功,是以應該是系統哪裡有點問題。在後面我介紹了如何處理,如果你也遇到和我一樣的情況,可先跳到下面檢視。

注意到這裡包含的資訊:

  • 虛機名稱:demo_default_1588406874156_65036(想改?最後有提)
  • 網卡:Adapter 1: nat,第一塊網卡,NAT 模式,這是固定的
  • 端口轉發:22 (guest) => 2222 (host) (adapter 1),把虛機的 22 端口,映射到主控端的 2222 端口上,這樣就可以通過 127.0.0.1:2222 通路虛拟機了
  • SSH 使用者名:vagrant,這裡使用 private key 登入
密碼也是 vagrant,但是密碼方式僅供直接登入,是不能通過 SSH 登入的。

檢視虛機狀态

執行下面的指令可以檢視虛機的狀态:

vagrant status

Current machine states:

default                   running (virtualbox)

The VM is running. To stop this VM, you can run `vagrant halt` to
shut it down forcefully, or you can run `vagrant suspend` to simply
suspend the virtual machine. In either case, to restart it again,
simply run `vagrant up`.           

該指令還提示了如何操作虛機,我們繼續一一介紹

連接配接虛機

如果啟動沒問題,接下來執行 vagrant ssh 就能以 vagrant 使用者直接登入虛機中。

root 使用者沒有預設密碼,也不能直接登入。需要 root 權限的指令可以通過在指令前添加 sudo 來執行,也可以執行 sudo -i 直接切換到 root 使用者。

這時候打開 VirtualBox 程式,可以看到自動建立的虛機:

「運維」超詳細的 Vagrant 上手指南

我們也可以在 VirtualBox 的終端上登入系統,預設的登入使用者名和密碼都是 vagrant。

當然還可以使用其它的 SSH 連接配接工具例如 XShell,SecureCRT 連接配接,但是這裡預設網卡使用的是 NAT 模式,沒有指定 IP,實際應用并不友善,我們在後面介紹網絡配置時再詳細介紹如何連接配接虛機。

停止虛機

執行下面的指令可以關閉虛機:

vagrant halt           

直接在 VirtualBox 上關閉虛機,或者直接在虛機内部執行 poweroff 指令也都是可以的。

暫停虛機

執行下面的指令可以暫停虛機:

vagrant suspend           

恢複虛機

執行下面的指令把暫停狀态的虛機恢複運作:

vagrant resume           

注意: 不管虛機是關閉還是暫停狀态,甚至是 error 狀态,都可以執行 vagrant up 來讓虛機恢複運作。

重載虛機

執行下面的指令會重新開機虛機,并且重新加載 Vagrantfile 中的配置資訊:

vagrant reload           

删除虛機

最後,執行下面的指令可以徹底删除虛機,包括整個虛機檔案:

vagrant destroy           

注意: 在目前這個小例子中,上面所有的 vagrant 指令都需要在 Vagrantfile 所在的目錄下執行。

七、初識 Vagrantfile

先來認識一下預設的 Vagrantfile 檔案,使用帶文法高亮的文本編輯器(例如 VSCode) 打開:

# -*- 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 = "centos-7"

  # 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
  # Ansible, Chef, Docker, Puppet and Salt 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           

這是一個 Ruby 文法的檔案,因為 Vagrant 就是用 Ruby 編寫的。如果編輯器沒有文法高亮可以手動設定檔案類型為 Ruby。

這個預設檔案内容幾乎都是注釋,提示有哪些配置項可以修改,我們不需要去學 Ruby 程式設計也可以照葫蘆畫瓢的完成基本的配置。

當然,如果會 Ruby 程式設計的可以在此實作更進階的作用,但是絕大多數人用不着。

刨除注釋,這個檔案的實際生效内容實際隻有 3 行:

Vagrant.configure("2") do |config|
  config.vm.box = "centos-7"
end           

首尾兩行組成一個代碼塊結構,不要去動它,除非你知道自己在幹什麼。我們平常隻需要編輯這其中的配置項。

這裡的 config.vm.box 對應的就是虛機的鏡像,也就是 box 檔案,這是唯一必填的配置項。

特别提醒,Vagrantfile 檔案名是固定的寫法,大小寫也要完全一樣,修改了就不認識了。

八、自定義配置 Vagrantfile

下面我将針對這份預設的 Vagrantfile 内容,逐個講解其中的配置含義和如何根據實際情況修改。

配置端口轉發

端口轉發(Port forward)又叫端口映射,就是把虛機的某個端口,映射到主控端的端口上。這樣就能在主控端上通路到虛拟機中的服務。

例如啟動虛機時,預設的 22 (guest) => 2222 (host) (adapter 1) 就是把虛機的 SSH 服務端口(22)映射到主控端的 2222 端口,這樣直接在主控端通過 ssh 用戶端通路 127.0.0.1:2222 端口就等價于通路虛拟機的 22 端口。

下面這兩段配置就是教我們如何配置額外的端口轉發規則,例如把 Web 服務也映射出來:

# 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"           

實際上設定端口轉發這個功能并不實用,一個很明顯的問題就是如果啟動多個虛機,很容易就出現主控端上端口沖突的問題。即使沒有端口沖突,使用起來也不友善,我個人不推薦使用的,可以把這部配置設定置直接删掉。直接使用下面的私有網絡。

這個功能是虛拟機軟體提供的,可以在虛機的網卡設定中展開進階選項,找到相關的配置:

「運維」超詳細的 Vagrant 上手指南

還有個地方需要注意,預設的 SSH 端口映射在這裡沒法直接修改。比如像我這樣,2222 端口出現莫名問題,如果想要把 22 端口轉發到其它端口如 22222,直接添加下面這樣的配置是沒用的:

config.vm.network "forwarded_port", guest: 22, host: 22222           

它會在原來的基礎上新加一個端口轉發規則,而不是替代原來的,必須要先強制關閉掉預設的那條規則:

config.vm.network "forwarded_port", guest: 22, host: 2222, id: "ssh", disabled: "true"
  config.vm.network "forwarded_port", guest: 22, host: 22222           

配置私有網絡

下面這段配置用來配置私有網絡,實際上對應的是 VirtualBox 的主機網絡,也就是 HostOnly 網絡。

# 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"           

取消注釋最下面一行,就可以為虛機設定指定的私有網絡位址:

config.vm.network "private_network", ip: "192.168.33.10"           

如果這個網段的主機網絡在 VirtualBox 中不存在,Vagrant 會在啟動虛機時自動建立。是以,如果你想要利用已有的網絡,請檢視現有主機網絡配置:

「運維」超詳細的 Vagrant 上手指南

最好這個網絡也不要啟用 DHCP,完全由自己來配置設定位址,這樣更加清楚。

config.vm.network "private_network", ip: "192.168.56.10"           

修改完成後,執行 vagrant reload 指令重建虛機,就能看到多出來的網卡了。

私有網絡實際也可以直接使用 DHCP,但是并不推薦:

config.vm.network "private_network", type: "dhcp"           

配置公共網絡

下面這條配置用來配置公共網絡:

# 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"           

正如注釋所說,這裡通常對應的就是橋接網絡。實際開發場景下,我們極少會需要把虛機暴露到公共網絡上,這樣既不安全,也沒有必要。

預設所起的第 1 個 NAT 網絡已經保證了虛機可以上網際網路,而私有網絡保證了主控端和虛機,以及虛機和虛機之間的通信。如果有對外暴露服務的需求,還可以使用端口轉發。我實在想不出什麼情況下是必須要用橋接網絡的。

是以這部配置設定置可以直接删除,如确有使用的,可以參考 官方文檔。

配置同步檔案夾

下面的配置項用來配置同步檔案夾:

# 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"           

在啟動虛機的時候,我們可以看到這樣的提示:

==> default: Machine booted and ready!
==> default: Checking for guest additions in VM...
    default: No guest additions were detected on the base box for this VM! Guest
    default: additions are required for forwarded ports, shared folders, host only
    default: networking, and more. If SSH fails on this machine, please install
    default: the guest additions and repackage the box to continue.
    default:
    default: This is not an error message; everything may continue to work properly,
    default: in which case you may ignore this message.
==> default: Configuring and enabling network interfaces...
==> default: Rsyncing folder: /cygdrive/c/Users/Davy/demo/ => /vagrant           

先注意最後一行的提示:Rsyncing folder: /cygdrive/c/Users/Davy/demo/ => /vagrant

  • /cygdrive/c/Users/Davy/demo/ 這是主控端的本地目錄,也就是 Vagrantfile 所在的目錄。
  • /vagrant 是虛拟機内部的路徑
  • Rsyncing 表示同步的方式是 Rsync
主控端目錄中出現 /cygdrive 是因為 Vagrant 程式用到了 Cygwin,它是在 Windows 系統中相容 Linux/POSIX 的模拟層。可以把 /cygdrive 看成是虛拟的根目錄。

這是 Vagrant 預設的同步檔案夾設定,别忘了 Vagrant 的作用是用來搭建開發環境的。是以它假定了目前目錄是我們的開發項目所在目錄,自動把本地的項目目錄同步到虛機中,就可以快速的開始開發調試工作了。

  1. 在 demo 目錄下建立一些檔案,例如 hello.py
  2. 執行 vagrant reload,重新開機虛機
  3. 在虛機啟動完成後登入到虛機内,操作如下:
$ vagrant ssh
Last login: Sat May  2 16:25:00 2020 from 10.0.2.2
[vagrant@localhost ~]$ cd /vagrant/
[vagrant@localhost vagrant]$ ls
hello.py  Vagrantfile
[vagrant@localhost vagrant]$ python hello.py
helloworld           

這種同步方式在大多數情況下都能提供便利,不過也有不足之處:

  • 同步是一次性的,即隻有啟動虛機的時候執行,也就是說改了代碼必須要重新開機一次虛機
  • 單向的,即隻能從主控端同步到虛拟機,也就是說在虛機内的改動不會同步到外面
  • 需要拷貝檔案,如果要同步的檔案數量較多,會占用更多的磁盤空間

讓我們按照預設配置的提示來新加一條同步檔案夾配置試試:

config.vm.synced_folder "../data", "/vagrant_data"           

注意,别忘了先在主控端上建立 data 檔案夾,重新開機虛機可能看到下面的錯誤提示:

==> default: Rsyncing folder: /cygdrive/c/Users/Davy/demo/ => /vagrant
==> default: Mounting shared folders...
    default: /vagrant_data => C:/Users/Davy/data
Vagrant was unable to mount VirtualBox shared folders. This is usually
because the filesystem "vboxsf" is not available. This filesystem is
made available via the VirtualBox Guest Additions and kernel module.
Please verify that these guest additions are properly installed in the
guest. This is not a bug in Vagrant and is usually caused by a faulty
Vagrant box. For context, the command attempted was:

mount -t vboxsf -o uid=1000,gid=1000 vagrant_data /vagrant_data

The error output from the command was:

mount: unknown filesystem type 'vboxsf'           

這是因為 Vagrant 提供了多種同步方式,在使用 VirtualBox 的時候,預設同步類型是 vboxsf 挂載檔案系統,它需要在虛拟機内部安裝客戶機增強包,也就是 VirtualBox Guest Additions(輸出資訊中也提示了)。

如何在虛機系統中安裝 guest additions 要分作業系統而定,有點小坑,後面會細說,現在修改一下配置,明确指定同步類型是 rsync:

config.vm.synced_folder "../data", "/vagrant_data", type: "rsync"           

這樣表示仍然使用 rsync 來單向同步。

更改虛機規格

VirtualBox 等虛拟機軟體在 Vagrant 中被稱為 Provider,虛機的規格等配置是和 Provider 相關的。因為 VirtualBox 用的最多,是以預設的配置提示是以 VirtualBox 舉例。

如果想要了解其它 Provider 的配置,請參考 文檔

把中間那一段取消注釋,其它的可以删掉:

# 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.           

使用 VSCode 時,選中它們,然後按下快捷鍵 Ctrl + / 即可:

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           

vb.gui = true 是在虛機啟動時自動打開 VirtualBox 的圖形界面,這對伺服器來說沒什麼用,直接删掉。

添加 CPU 的配置,同時修改記憶體大小:

config.vm.provider "virtualbox" do |vb|
    vb.cpus = 2
    vb.memory = 2048
  end           

注意到,記憶體的大小機關是 MB,值是數字,預設的示例中有引号,實際也可以不加。

特别提醒一下,在 說明文檔 裡給的例子,其中的變量名是 v,這其實是在雙豎線中定義的,直接拷貝的時候要看清楚。

config.vm.provider "virtualbox" do |v|
  v.memory = 1024
  v.cpus = 2
end           

Provision

Provision 是指在虛機初次建立的時候,Vagrant 自動去執行的構造任務,比如安裝軟體,更新系統配置等。

因為 box 往往隻提供基礎的系統(雖然我們可以自定義 box,但是并不是每次都要這麼做,而且這樣做會喪失一部分靈活性),有些東西仍然需要在建立虛機的時候完成。

# Enable provisioning with a shell script. Additional provisioners such as
  # Ansible, Chef, Docker, Puppet and Salt 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           

因為這部分完全是個開放的内容,是以我們這裡不過多讨論,來看一下什麼情況下會觸發 provision 的操作:

  • 某個環境初次執行 vagrant up 的時候
  • 執行 vagrant provision 指令
  • 重新開機的時候 vagrant reload --provision,帶上 --provision 選項

除了上面這些預設提示給出的配置項,Vagrantfile 還支援其它很多配置,具體請 檢視文檔。

由于 Vagrantfile 本身是 Ruby 腳本,是以它并不僅僅是靜态的配置檔案,而且可以包含程式邏輯,例如在 如何建立多個虛機 中就有應用,有興趣的可以自行研究。

九、定制帶客戶機增強的 box

下載下傳 Guest Addition

VirtualBox 的下載下傳頁面并沒有直接給出 Guest Addtion 的下載下傳連結,我們先在 VirtualBox 的任一下載下傳連結上右鍵,複制連結位址,例如得到 https://download.virtualbox.org/virtualbox/6.1.6/VirtualBox-6.1.6-137129-Win.exe,去掉最後的檔案名,把其中的路徑 https://download.virtualbox.org/virtualbox/6.1.6/ 在浏覽器中打開,就能看到所有可下載下傳的版本,在其中找到 VBoxGuestAdditions_6.1.6.iso 直接下載下傳。

「運維」超詳細的 Vagrant 上手指南

安裝 Guest Addition

重新使用 Vagrant 從原始的鏡像啟動一個幹淨的虛機。

VBoxGuestAdditions_6.1.6.iso 需要以CD光牒的形式挂載到虛機上,但是預設啟動的這個虛機是沒有光驅的。添加虛拟光驅需要先将虛機關閉。

然後在 VirtualBox 界面上操作,打開 設定,選擇 存儲,點選 添加虛拟光驅,點選 控制器: IDE,選擇 VBoxGuestAdditions_6.1.6.iso,點選 OK

直接在 VirtualBox 上啟動虛機,如果你在虛機菜單上選擇 裝置 - 安裝增強功能,大機率是會遇到下面這樣的錯誤,别管它,我們手動來安裝。

「運維」超詳細的 Vagrant 上手指南
「運維」超詳細的 Vagrant 上手指南

使用 vagrant/vagrant 登入到虛機内,切換到 root 使用者,檢視虛拟CD光牒是否已經挂載上來了:

$ sudo -i
# lsblk
NAME   MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
sda      8:0    0  40G  0 disk
└─sda1   8:1    0  40G  0 part /
sr0     11:0    1  57M  0 rom           

下面的 sr0 就是CD光牒裝置,要把它挂載到檔案系統中

# mount /dev/sr0 /mnt/
mount: /dev/sr0 is write-protected, mounting read-only
# cd /mnt/
# ls
AUTORUN.INF  cert  OS2           TRANS.TBL                VBoxDarwinAdditionsUninstall.tool  VBoxSolarisAdditions.pkg        VBoxWindowsAdditions.exe
autorun.sh   NT3x  runasroot.sh  VBoxDarwinAdditions.pkg  VBoxLinuxAdditions.run             VBoxWindowsAdditions-amd64.exe  VBoxWindowsAdditions-x86.exe           

在 Linux 系統中要運作 VBoxLinuxAdditions.run,這時候直接運作仍然會報錯:

「運維」超詳細的 Vagrant 上手指南

大緻意思是要它需要核心的頭檔案來建構。

頭檔案通過安裝 kernel-devel 就可以了,但是直接安裝的版本是最新版本的,可能會目前的核心版本不一緻,仍然是沒用的。例如:

[root@localhost mnt]# uname -r
3.10.0-1062.12.1.el7.x86_64
[root@localhost mnt]# yum info kernel-devel
Installed Packages
Name        : kernel-devel
Arch        : x86_64
Version     : 3.10.0
Release     : 1127.el7
Size        : 38 M
Repo        : installed
From repo   : base           

這裡 kernel-devel 的 Release 版本号和系統核心版本不一緻,是以仍然不行。

需要先更新一把,然後再安裝(也可以先安裝再更新):

# yum update -y
# yum install -y gcc kernel-devel           

這裡選擇的是更新到最新版本,如果你的開發環境需要特定的核心版本,你也可以根據情況安裝指定的版本,隻要保證核心版本和頭檔案版本完全比對。

Ubuntu 系統的安裝方式有所不同,可以參考 Vagrant 的文檔

更新核心後需要重新開機虛機,然後再次嘗試安裝 Additions:

[root@localhost mnt]# ./VBoxLinuxAdditions.run
Verifying archive integrity... All good.
Uncompressing VirtualBox 6.1.6 Guest Additions for Linux........
VirtualBox Guest Additions installer
Removing installed version 6.1.6 of VirtualBox Guest Additions...
Copying additional installer modules ...
Installing additional modules ...
VirtualBox Guest Additions: Starting.
VirtualBox Guest Additions: Building the VirtualBox Guest Additions kernel
modules.  This may take a while.
VirtualBox Guest Additions: To build modules for other installed kernels, run
VirtualBox Guest Additions:   /sbin/rcvboxadd quicksetup <version>
VirtualBox Guest Additions: or
VirtualBox Guest Additions:   /sbin/rcvboxadd quicksetup all
VirtualBox Guest Additions: Building the modules for kernel
3.10.0-1127.el7.x86_64.
VirtualBox Guest Additions: Running kernel modules will not be replaced until
the system is restarted

# 檢查子產品是否已經加載了
[root@localhost mnt]# lsmod |grep vbox
vboxvideo              35867  1
ttm                    96673  1 vboxvideo
drm_kms_helper        186531  1 vboxvideo
drm                   456166  4 ttm,drm_kms_helper,vboxvideo
vboxguest             349038  1
[root@localhost mnt]#           

能夠看到 vboxguest 就代表安裝成功了。

測試

在 Vagrantfile 中添加同步檔案夾設定,這次不再指定同步類型

config.vm.synced_folder "../data", "/vagrant_data"           

然後執行 vagrant reload

$ vagrant reload
...
==> default: Checking for guest additions in VM...
==> default: Rsyncing folder: /cygdrive/c/Users/Davy/demo/ => /vagrant
==> default: Mounting shared folders...
    default: /vagrant_data => C:/Users/Davy/data
==> default: Machine already provisioned. Run `vagrant provision` or use the `--provision`
==> default: flag to force provisioning. Provisioners marked to run always will still run.           

可以看到關于 additions 的提示資訊沒有了,新的同步檔案夾也能正常同步了,這次的同步是雙向的。我們可以先去同步檔案夾随便建立一個檔案:

$ vagrant ssh
Last login: Tue May  5 12:16:39 2020 from 10.0.2.2
[vagrant@localhost ~]$ cd /vagrant_data/
[vagrant@localhost vagrant_data]$ ls
data.txt
[vagrant@localhost vagrant_data]$ touch vm.txt   # 建立一個檔案
[vagrant@localhost vagrant_data]$ ls
data.txt  vm.txt           

回到 Windows 主控端上,data 檔案夾下面也能看到 vm.txt 檔案,

Davy@Davy-Desktop MINGW64 ~/data
$ ls
data.txt  vm.txt           

這樣,我們的 Guest Addition 就安裝成功了。

清理磁盤

接下來我們來把這個好不容易才裝上了增強包的虛機儲存為新的鏡像。

這裡你可能還想安裝點其它軟體,但是作為基礎鏡像,最好還是保持幹淨一點,不宜安裝太多東西。後續可以在這個基礎之上,再次建構其它特定的鏡像。

為了使做出來的鏡像檔案大小緊湊點,我們把剛才安裝過程中的緩存也删掉:

yum clean all           

我在打包過程中還遇到過 swapfile 占用磁盤空間的問題,導緻鏡像檔案過大,可以這樣檢查:

du /swapfile   # 檢視是否有占用
swapoff -a     # 關閉 SWAP
rm -f /swapfile           

使用 df -h 指令檢視磁盤占用情況,像我這次操作,磁盤根目錄不到 2GB 的空間占用:

# df -h
/dev/sda1        40G  1.5G   39G   4% /           

打包為 box

執行 vagrant package 就可以把目前環境打包生成新的 box 檔案:

$ vagrant  package
    ==> default: Attempting graceful shutdown of VM...
==> default: Clearing any previously set forwarded ports...
==> default: Exporting VM...
==> default: Compressing package to: C:/Users/Davy/demo/package.box           

生成的檔案就在 Dockerfile 所在的目錄,檔案名預設是 package.box。大小不到 600MB。

注意:,因為預設啟動虛機時本地目錄會 rsync 到虛機中,package.box 檔案也會同步(拷貝)到虛機中,占用虛機磁盤。這時候如果二次執行打包,生成的檔案大小會翻倍。

添加到 vagrant 中

繼續使用下面的指令把建立的 box 添加到 vagrant 中:

$ vagrant box add package.box --name davy/centos-7-base           

為了區分這是個人建立的基礎鏡像,加了個人使用者名作為字首,同時加了 base 字尾。

添加成功後,本地的 package.box 就可以删除了。

後續再建立虛機,使用下面的指令就可以了:

$ vagrant init davy/centos-7-base           

十、使用 SSH 用戶端

vagrant ssh 指令雖然很友善,但是在 Windows 環境下,因為預設的指令行終端不太好用,是以往往還需要使用更專業的 SSH 用戶端例如 XShell 或 SecureCRT。

預設的鏡像隻支援 private_key 的方式登入,vagrant/vagrant 可以在 VirtualBox 上登入系統,但是如果用來登入 SSH,會被拒絕。

當然你可以在制作鏡像的時候修改 ssh 服務的配置,讓它能夠用密碼登入,但是實際上用密鑰更加友善。

先使用 vagrant ssh-config 指令可以看到 SSH 的配置:

$ vagrant ssh-config
Host default
  HostName 127.0.0.1
  User vagrant
  Port 22222
  UserKnownHostsFile /dev/null
  StrictHostKeyChecking no
  PasswordAuthentication no
  IdentityFile E:/VirtualBox/.vagrant.d/boxes/davy-VAGRANTSLASH-centos-7-base/0/virtualbox/vagrant_private_key
  IdentitiesOnly yes
  LogLevel FATAL           

可以看到其中的 IdentityFile 就是私鑰檔案。

發現這個自定義 box 啟動的虛機的密鑰檔案是固定在 VAGRANT_HOME 下的相關目錄下。那麼就好辦了,直接在 SSH 用戶端軟體上導入這個私鑰檔案就可以了。

以 SecureCRT 為例:

「運維」超詳細的 Vagrant 上手指南

十一、使用模闆檔案

vagrant init 指令隻是用來生成 Vagrantfile 檔案,但是預設的配置選項每次都要修改也很麻煩。該指令提供了 --template 選項,可以指定一個模闆檔案,我們可以在自定義自己的模闆檔案。

這個模闆檔案的格式 ERB 是 Ruby 的模闆文法,如果有 Ruby on Rails 開發經驗的可能會比較熟悉。但是我們不用去學習這些細節。

可以從 這裡 拷貝一份原檔案,還能在 Vagrant 的安裝位置 Vagrant\embedded\gems\2.2.7\gems\vagrant-2.2.7\templates\commands\init 底下找到,并且有一個 Vagrantfile.min.erb 是去掉所有注釋的:

Vagrant.configure("2") do |config|
  config.vm.box = "<%= box_name %>"
  <% if box_version -%>
  config.vm.box_version = "<%= box_version %>"
  <% end -%>
  <% if box_url -%>
  config.vm.box_url = "<%= box_url %>"
  <% end -%>
end           

可以看到其中是怎麼配置 config.vm.box 的。 像 <% 這樣的文法有興趣可以自己去了解,這裡我們隻要把自己想要的配置項原樣寫上去就行了。

下面是我按照自己的需要寫的:

Vagrant.configure("2") do |config|
  config.vm.box = "<%= box_name %>"
  config.vm.network "forwarded_port", guest: 22, host: 2222, id: "ssh", disabled: "true"
  config.vm.network "forwarded_port", guest: 22, host: 22222

  # config.vm.network "private_network", ip: "192.168.56.10"
  # config.vm.synced_folder "../data", "/data"

  config.vm.provider "virtualbox" do |vb|
    # vb.name = "give me a better name"
    vb.memory = "1024"
  end
end           
不要有中文,不然會遇到編碼的麻煩。

其中像私有網絡和同步檔案夾配置,幾乎每次基本都要,但是又不好固定,是以仍然以注釋的形式保留,每次稍微改一下也很友善。

把這個檔案找個目錄,儲存為 vagrant.erb。

接着在使用 vagrant init 的時候通過 --tempate 指定它就可以了,例如:

vagrant init davy/centos-7-base --tempate "C:\Users\Davy\vagrant.erb"           

顯然,每次要記住并且輸入這個模闆檔案也很麻煩的。可以通過設定環境變量 VAGRANT_DEFAULT_TEMPLATE 來一勞永逸地解決這個問題。

尾聲

費了莫大的力氣,終于可以比較愉快地玩耍了。雖然也隻是剛把基礎鏡像搞定了,後面可能還要針對不同用途的環境編寫更加複雜的 Vagrantfile。

現在很多人剛認識到 Vagrant 之後都會問,Vagrant 和 Docker 的差別是什麼?

在容器流行之前,Vagrant 就是用來編排虛機和自動部署開發環境的,有了 Docker/Kubernetes 之後,直接用容器來編排應用确實更香。但是還有一些工作,例如容器平台自身的安裝,多節點叢集的部署測試等,更友善用虛機解決。

此外,現在 Windows 中還可以通過 WSL 使用 Linux 系統,但是使用場景上還是有所不同。Vagrant 更多地用于快速搭建可重用的開發環境,從這個角度看,Vagrant 其實好比 IaaS 雲平台,隻不過規模局限在個人電腦上。

文章來源:https://zhuanlan.zhihu.com/p/259833884

繼續閱讀