---
tags: 實作, 微服務
---
# Vagrant 手冊
本筆記參考課程:[Vagrant从入门到精通](https://www.udemy.com/course/vagrant-zh/)
虛擬化有兩種:Type 1 、Type 2
![](https://i.imgur.com/E0FLsO4.png)
Vagrant 的架構圖例:
![](https://i.imgur.com/FdzfgJ0.png)
# 簡介與快速入門
Vagrant 下載位置:[Install Vagrant](https://developer.hashicorp.com/vagrant/downloads)
下載完直接安裝就好。
記得 Bios 需要開啟虛擬化功能。
## Box 的下載與啟動
Box 想像成 Docker 的 Image 即可。
可以到以下位置去取得:[Discover Vagrant Boxes](https://app.vagrantup.com/boxes/search)
記得根據你的 Provider 去選,這裡以 VirtualBox 為例子,下載 RockyLinux9。
```shell=
vagrant init generic/rocky9
vagrant up --provider=virtualbox
vagrant status
```
* 使用 init 會在目前位置創建一個 Vagrantfile 檔案,這就是用來建立虛擬機的腳本檔案
* 請自行選擇適當的位置執行 init
* up 指令就會根據目前位置的 Vagrantfile 來建立虛擬機
* 記得可以手動指定 Provider,這裡指定 virtualBox
* 最後可以使用 status 查看虛擬機狀態。
## 常用指令
以下指令都必須於對應的資料夾下才會有用!!!
| 指令 | 說明 |
|--------------------------|--------------|
| vagrant up | 啟動虛擬機 |
| vagrant status | 查看虛擬機狀態 |
| vagrant ssh \<name\> | 連線虛擬機 |
| vagrant ssh-config | 查看虛擬機 ssh 設定 |
| vagrant suspend | 暫停 |
| vagrant resume | 回復 |
| vagrant reload | 重載 |
| vagrant halt | 關機 |
| vagrant destory \<name\> | 刪除 |
以下說明 SSH 的方法:
1. 最簡單的就是直接 vagrant ssh 就可以直接進入了。
2. 或者直接使用 ssh 指令
* 首先用 ssh-config 找到虛擬機的 ip 與 port
```shell=
# vagrant ssh-config
Host default
HostName 127.0.0.1
User vagrant
Port 2222
UserKnownHostsFile /dev/null
StrictHostKeyChecking no
PasswordAuthentication no
IdentityFile D:/VirtualBox/generic_rocky9/.vagrant/machines/default/virtualbox/private_key
IdentitiesOnly yes
LogLevel FATAL
```
再來使用 ssh 指令:
```shell=
ssh -i 'D:/VirtualBox/generic_rocky9/.vagrant/machines/default/virtualbox/private_key' vagrant@127.0.0.1 -p 2222
```
* -i 指定 key 的位置
* 從 IdentityFile 欄位複製就好
* 後面接使用者名稱+@+IP位置
* 如果 port 不是 22 就要用 -p 參數指定
登入後的使用者是 vagrant,如果要打密碼的話,也是一樣。
## HyperV 與 VirtualBox 哪個效能比較好??
可以參考此篇文章:[Hyper V vs VirtualBox: Understanding Their Differences](https://www.parallels.com/blogs/ras/hyperv-vs-virtualbox/)
# Vagrantfile
Vagrantfile 是用 Ruby 寫的。
## 目錄結構蓋覽
一共有兩個位置可以知道:
1. Box 儲存位置:\<home\>/.vagrand.d
2. 虛擬機資料位置
![](https://i.imgur.com/Ht72feu.png)
```shell=
tree /F
D:.
│ Vagrantfile
│
└─.vagrant
├─machines
│ └─default # 虛擬機名稱
│ └─virtualbox # 虛擬機 Provider
│ action_provision
│ action_set_name
│ box_meta
│ creator_uid
│ id
│ index_uuid
│ private_key # 虛擬機 SSH Key
│ synced_folders
│ vagrant_cwd # 虛擬機硬碟
│
└─rgloader
loader.rb
```
## 基本設定指引
可以參考官方文件:[Vagrantfile Documents](https://developer.hashicorp.com/vagrant/docs/vagrantfile)
從 init 指令生成的 Vagrantfile 檔案就有一大堆的註解可以參考,但是詳細的還是去看一下文件才會知道。
## SSH 相關設定
通常要用 SSH 指令是要先到該資料夾之下才可以使用,而且因為有設定 privateKey 了,所以不需要密碼,並且**有可能預設**就不給你用密碼登入。
### 密碼登入
要改變可以使用密碼登入,可以先進入該虛擬機,找到以下檔案:
```shell=
/etc/ssh/ssh_config
```
找到 PasswordAuthentication 後面改成 yes,然後重新啟動即可。
### 快速 Windows SSH 登入
vagrant ssh-config 指令得到的設定內容可以直接給 Windows 的 ssh 指令快速登入用。
```shell=
C:\VagrantNode\generic_rocky9>vagrant ssh-config
Host default
HostName 127.0.0.1
User vagrant
Port 2222
UserKnownHostsFile /dev/null
StrictHostKeyChecking no
PasswordAuthentication no
IdentityFile C:/VagrantNode/generic_rocky9/.vagrant/machines/default/virtualbox/private_key
IdentitiesOnly yes
LogLevel FATAL
```
將以上內容複製到 \<home\>/.ssh/config 的檔案內容中,如果沒有資料夾請自行創建。
把 default 改成你想要的名稱,之後只要使用『ssh \<名稱\>』,即可連線到該虛擬機。
> 不同 provider 的虛擬機,IP 位置等等可能不會是 localhost 等等,這時候需要注意需要回去更改檔案內容才可以正常。
### 共用 Private Key
預設的情況下,Vagrant 會有一個共用相同的 private key,是每個 Vagrant 使用者都一樣的 key。
其位置在以下路徑:
```shell=
<home>/vagrant.d/insecure_private_key
```
![](https://i.imgur.com/WXRvVWb.jpg)
這個 key 預設都是不使用的,而是每一個虛擬機建立的時候,都會去建立一個自己的 Key pair。
但如果是在測試環境的時候,需要大量的虛擬機,如果每一台都不一樣的 key 會讓管理及連線非常麻煩。
故可以於 Vagrantfile 中加入以下設定來使用共用的預設 insecure_private_key。
```shell!
config.ssh.insert_key = false
```
這個共用的 Key 當然也可以用自己生成的,這部分請參考後續章節。
## 單一設定,多台生成
只要使用以下設定即可:define
注意一下 Global 跟區域單獨的設定位置即可。
```ruby=
Vagrant.configure("2") do |config|
# Global 設定
config.vm.hostname = "custom_hostname"
# 局部設定,自訂名為 myVM1 虛擬機
config.vm.define "" do |custom_vm_name|
custom_vm_name.vm.hostname = "myVM1_host"
end
end
```
### 更好的寫法
上面的寫法,如果要多台設定的話,會要非常多行的 config.vm.define。
這一小節介紹透過 Ruby 的 Map 與 For 迴圈的寫法來改寫這一個設定:
```ruby=
boxes = [
{
:name => "k8s-master",
:eth1 => "192.168.56.10",
:mem => "4096",
:cpu => "2"
},
{
:name => "k8s-worker1",
:eth1 => "192.168.56.11",
:mem => "2048",
:cpu => "2"
},
{
:name => "k8s-worker2",
:eth1 => "192.168.56.12",
:mem => "2048",
:cpu => "2"
}
]
Vagrant.configure(2) do |config|
# config.vm.box = "ubuntu/jammy64"
config.vm.box = "ubuntu/focal64" #ubuntu 20.04
boxes.each do |opts|
config.vm.define opts[:name] do |config|
config.vm.hostname = opts[:name]
config.vm.provider "vmware_fusion" do |v|
v.vmx["memsize"] = opts[:mem]
v.vmx["numvcpus"] = opts[:cpu]
end
config.vm.provider "virtualbox" do |v|
v.customize ["modifyvm", :id, "--memory", opts[:mem]]
v.customize ["modifyvm", :id, "--cpus", opts[:cpu]]
end
config.vm.network :private_network, ip: opts[:eth1]
end
end
config.vm.provision "shell", privileged: true, path: "./setup.sh"
end
```
* 使用名為 boxes 的 map 儲存自訂設定
* 對 boxes 使用 foreach 來逐個設定
## 與虛擬機同步檔案
此小節說明同步本機的檔案到虛擬機中的方法,以 VirtualBox 為例。
事實上原本的 Box 檔案下載來之後,也會有一個 Vagrantfile,裡面一樣可以做設定,有可能裡面禁用了同步功能,或者是使用了名為 rsync 的同步機制。
該檔案的位置如下:
```shell=
C:\Users\<home>\.vagrant.d\boxes\generic-VAGRANTSLASH-rocky9\4.2.14\virtualbox\Vagrantfile
```
> rsync 的同步機制是一次性在創建虛擬機的時候複製檔案過去的,不符合人性。
這裡可以直接改設定,或者直接砍掉相關同步的設定,讓他跑預設的設定。
相關設定可參考官方文件:[
Synced Folders - Basic Usage](https://developer.hashicorp.com/vagrant/docs/synced-folders/basic_usage)
總之要達到同步效果總共有兩個要點:
1. 針對 Virtual Box 的 Box 設定移除 rSync 的同步功能設定部分,或者改設定
* 需要到該 Box 的目錄下設定
2. 安裝 virtualbox guest additions 這個外掛
* 安裝一次就可以了,不建議從 GUI 上安裝
外掛的安裝可以使用 plugin 指令來安裝:
```shell=
vagrant plugin install vagrant-vbguest
```
* 可以使用 --version 指定版本
> 時間點 2023/3/24 註記:
> 安裝的外掛版本是 0.31.0
> 啟動虛擬機的時候 Terminal 會顯示一些錯誤,關於你的版本 6.1.40 與 7.0.6 ( 我安裝的 VirtualBox 版本 ) 不相符
> 但是最後流程安裝好了之後還是可以正常運作。
為了要相容於其他人使用此檔案沒有裝外掛的情況,加入以下設定於 Vagrantfile 就可以在未安裝的情況下先行安裝後再執行:
```ruby=
# 如果沒有安裝 Virtual Box 外掛,則先安裝:
if Vagrant.has_plugin?("vagrant-vbguest") then
config.vbguest.auto_update = false
end
```
### HyperV 的同步設定
其實就是改同步方式設定而已,請於設定檔中使用以下設定即可:
```ruby=
config.vm.synced_folder ".", "/vagrant", type: "smb"
```
* 改成 smb 就好
### HyperV 與 VirtualBox 混合式設定
以下的範例設定加上去之後,就可以根據 provider 去判斷,要使用哪一種同步方式:
```ruby=
# 混合式同步設定,根據 provider 切換:
config.vm.provider "hyperv" do |v|
config.vm.synced_folder ".", "/vagrant", type: "smb"
end
config.vm.provider "" do |_, override|
override.vm.synced_folder ".", "/vagrant", type: "virtualbox"
end
```
# Vagrant Box
基本的指令當成 Image 來看就好:
| 指令 | 意義 | 可選參數 |
|------------------------------|---------------|--------------------------|
| vagrant box add \<boxName\> | 下載 Box | --provider、--box-version |
| vagrant box list | 列出目前系統現有的 Box | |
| vagrant box remove \<boxName\> | 移除 Box | |
## 自己建立 Box
一樣先以 Virtual Box 為例。
指令也很簡單,但有一些參數的數值跟條件要準備好:
1. 虛擬機需要安裝 virtualbox guest additions
* 參考前一小節的安裝法
2. 要打包的虛擬機,其 SSH 用的 Key ,必須要有包含 insecure_private_key 用的公鑰在裡面才行。
* 請查看 authorized_keys 這個檔案的內容,是否有insecure_private_key 存在。
```shell=
/home/vagrant/.ssh/authorized_keys
```
3. 請找出虛擬機的名稱,而且其網路的設定在網卡一必須要是 NAT
* 用 GUI 就可以看到名稱了
* 網路的設定也是 GUI 設定
![](https://i.imgur.com/AIrw2Id.jpg)
![](https://i.imgur.com/iZbAdRU.jpg)
以上設定完成後,使用以下指令就可以成功製作出 box 檔案:
```shell=
vagrant package --base <vmName>
```
有了製作好的 box 檔案,再來就把該檔案增加到系統的 box list 後就能夠使用了。
```shell=
# 增加 box 至系統
vagrant box add --name <自訂名稱> --provider=virtualbox <boxFileLocation>
# 啟動
vagrant init <自訂名稱>
vagrant up
```
## 上傳自建的 box 到 Vagrant Cloud
首先去 Vagrant Cloud 註冊。
創建並填寫 Box 資訊等等,非常簡單,就只是把你剛剛建立好的 Box 檔案上傳上去而已。
其中需要注意的填寫項目有一個 Checksum,這個可以透過以下指令取得:
```shell=
Get-FileHash <boxFileLocation>
```
完成後 Release 即可公開。
## 建立 hyperV 版本的 Box 檔案
Skip,有需要再看。
# 網路設定
網路設定部分,VirtualBox 與 HyperV 的預設網卡機制是不一樣的。
1. VirtualBox:使用的是 NAT,Port 轉發
* 多個虛擬機之間不可互 ping
* 虛擬機可以往外網 Ping,反之不行。
* ssh-config 可以看到轉發的 port 是多少,GUI 也可以
![](https://i.imgur.com/XITJqGl.jpg)
2. HyperV:使用的是 Switch 的方式
* 多個虛擬機是可以互 Ping 的。
* 由於限制很多,很多設定無法於 Vagrantfile 中設定,故此節不介紹 HyperV 的設定法。
## 轉發 Port 的設定
GUI 的設定方法參照上面的圖所示,直接加就可以。
* 虛擬機 -> 右鍵設定 -> 網路 -> 連接阜轉發 -> 新增
Vagrantfile 的設定使用以下 Code:
```ruby=
Vagrant.configure("2") do |config|
# 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"
end
```
* 這在 init 所生成的檔案中有註解,直接打開就可以用了。
* guest 設定虛擬機 port,host 設定本機的 port
## Private network
可以參照官方文件章節:[Private Networks](https://developer.hashicorp.com/vagrant/docs/networking/private_network)
這裡的針對 IP 設定有兩種:Static IP 或者 DHCP
DHCP 因為 IP 會變,有可能造成開發上的不便利,故常用的開發環境是使用指定固定 IP 的方式來設定。
有設定網路的話,你會看到 Windows 的網路設定中,看到有一個新的網卡被建立。
![](https://i.imgur.com/TCDO4r0.png)
也可以在虛擬機中查看網路卡的設定:
```shell=
ip a
```
### Static IP
```ruby=
Vagrant.configure("2") do |config|
config.vm.network "private_network", ip: "192.168.50.4"
end
```
* 直接指定想要的固定 IP 位置
### DHCP
```ruby=
Vagrant.configure("2") do |config|
config.vm.network "private_network", type: "dhcp"
end
```
在 Vagrant 中,已經有寫死預設的 DHCP 要使用的 IP 網段設定,所以每次的建立,都使用同一個預設的虛擬網卡,並不會另外建立新的。
## Public network
官方文件可以參考:[Public Networks](https://developer.hashicorp.com/vagrant/docs/networking/public_network)
這是直接將虛擬機連接到本機實體網路卡上,並不會使用自建的虛擬網卡。
所以如果進入到 Wifi Router 裡面看的話,是會看的到這台虛擬機的出現。
```ruby=
Vagrant.configure("2") do |config|
config.vm.network "public_network",
use_dhcp_assigned_default_route: true
end
```
# Provision
所謂 Provision 在 Vagrant 中就是創建完虛擬機後,需要做的一連串設定、安裝等等動作。
詳細可參考官方文件:[Provisioning](https://developer.hashicorp.com/vagrant/docs/provisioning)
以下介紹其中的兩種使用方法:
## Shell Provisioner
使用 ShellScript 去設定的方法有兩種:
1. inline:直接寫在 Vagrantfile 中。
2. path:另外寫一個 sh 檔案然後於 Vagrantfile 中指定該檔案位置去執行。
要令其執行,有三種指令:
```shell=
# 一起動創建的時候執行
vagrant up
# 當虛擬機已經創建後,可以使用更新的方式去執行。
vagrant provision
vagrant reload --provision.
```
### inline
在 init 產生出的 Vagranfile 中已經有註解了,打開來後就能使用:
```ruby=
Vagrant.configure("2") do |config|
# 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
sudo yum install -y epel-release
sudo yum install -y nginx
sudo yum install -y vim
sudo systemctl nginx start
SHELL
end
```
* epel 是一個 Repository ,安裝後就可以在裡面找到常用的安裝包
### path
```ruby=
Vagrant.configure("2") do |config|
config.vm.provision "shell", path: "./start.sh"
end
```
* path 相對位置是根據你的 Vagrantfile 檔案位置來看的。
## Ansible
Ansible 是一個自動化組態設定工具,本節不解釋這東西是什麼。
* 只能在 Linux 上跑
* Python 陣營的組態管理工具
```ruby=
Vagrant.configure("2") do |config|
# Run Ansible from the Vagrant Host
config.vm.provision "ansible" do |ansible|
ansible.playbook = "playbook.yml"
end
end
```
* 了解過 Ansible 再回頭看教學影片。