[From] https://blog.csdn.net/54powerman/article/details/50684844
從字面上來看,provision是准備,實現的功能是在原生鏡像的基礎上,進行一些附加的操作,以改變虛擬機的環境,比如安裝應用,發布程序等。
1 helloword
在vagrant的 Vagrant.configure(2) do |config| 節點內,加入如下代碼:
config.vm.provision "shell", inline: "echo hello provisio."
- 1
還有一種格式:
config.vm.provision "shell" do |s|
s.inline = "echo hello provision."
end
- 1
- 2
- 3
測試一下:
如果vm已經啟動,直接運行
vagrant provision
- 1
就可以看到控制台顯示的信息了。或者:
vagrant reload --provision
- 1
重啟vm,並自動執行provision操作。
Tips: 運行后可能會提示:default: stdin: is not a tty 錯誤,不影響執行效果,想要去除,在配置文件增加一行即可。
config.ssh.shell = "bash -c 'BASH_ENV=/etc/profile exec bash'"
- 1
什么是provision任務
provision任務是預先設置的一些操作指令,格式:
config.vm.provision 命令字 json格式參數
- 1
config.vm.provion 命令字 do |s|
s.參數名 = 參數值
end
- 1
- 2
- 3
每一個 config.vm.provision 命令字
代碼段,我們稱之為一個provisioner。
根據任務操作的對象,provisioner可以分為:
- Shell
- File
- Ansible
- CFEngine
- Chef
- Docker
- Puppet
- Salt
根據vagrantfile的層次,分為:
- configure級:它定義在
Vagrant.configure("2")
的下一層次,形如:config.vm.provision ...
- vm級:它定義在
config.vm.define "web" do |web|
的下一層次,web.vm.provision ...
執行的順序是先執行configure級任務,再執行vm級任務,即便configure級任務在vm定義的下面才定義。例如:
Vagrant.configure("2") do |config|
config.vm.provision "shell", inline: "echo foo"
config.vm.define "web" do |web|
web.vm.provision "shell", inline: "echo bar"
end
config.vm.provision "shell", inline: "echo baz"
end
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
輸出結果:
==> default: "foo"
==> default: "baz"
==> default: "bar"
- 1
- 2
- 3
2 如何執行provision任務
嘗試了helloword,我們來了解一下provision任務是怎么運行的。
- 啟動時自動執行,缺省地,任務只執行一次,第二次啟動就不會自動運行了。如果需要每次都自動運行,需要為provision指定
run:"always"
屬性 - 啟動時運行,在啟動命令加
--provision
參數,適用於vagrant up
和vagrant reload
- vm啟動狀態時,執行
vagrant provision
命令。
在編寫provision任務時,可能同時存在幾種類型的任務,但執行時可能只執行一種,如,我只執行shell類型的任務。可以如下操作:
vagrant provision --provision-with shell
- 1
3 shell
3.1 基本使用
3.1.1 數據類型
類型名 | 范例 |
---|---|
string | “arg1” |
hash | {key1:value1,key2:value2} |
array | [“arg1”,”arg2”] |
boolean | true,false |
3.1.2 參數:
必選:inline 或者 path
可選:
參數名 | 類型 | 說明 |
---|---|---|
args | string or array | 傳遞給shell或path的參數 |
env | hash | 傳遞給腳本的環境變量 |
binary | boolean | 是否替換windows的行結束符,這個參數名有點奇怪 |
privileged | boolean | 是否提權運行,如sudo執行,缺省為true |
upload_path | boolean | 上傳到vm中的路徑,缺省是/tmp/vagrant-shell |
keep_color | boolean | 設置是否腳本自身控制顏色,缺省為false,表示使用綠色和紅色來顯示輸出到stdout和stderr的消息 |
name | string | 給當前執行的腳本命名,與provisioner名稱無關 |
powershell_args | string | windows相關,略 |
powershell_elevated_interactive | boolean | windows相關,略 |
在有些情況下,vagrant會幫你處理引號,但建議,都匹配好雙引號,可讀性也好一些。
3.1.3 使用規則
3.1.3.1 單行腳本
helloword只是一個開始,對於inline模式,命令只能在寫在一行中。一個以上的命令,可以寫在同一行,用分號分隔,這屬於shell編程的范疇,在這里不多解釋。
單行腳本使用的基本格式:
config.vm.provision "shell", inline: "echo foo"
- 1
shell命令的參數還可以寫入do ... end
代碼塊中,如下:
config.vm.provision "shell" do |s|
s.inline = "echo hello provision."
end
- 1
- 2
- 3
其他,如后面提到的path參數也是一樣的。
一個shell代碼段,在1.7.0+版本,這個provisioner是可以命名的,如:
config.vm.provision "myshell,type:"shell" do |s| s.inline = "echo hello provision." end
- 1
- 2
- 3
Tips: provisioner命名塊如果重名,會有覆蓋問題。
一個shell節點內,如果連續寫一條以上s.inline,則只有最后一條有效,前面的會被后面的覆蓋掉。
3.1.3.2 內聯腳本
如果要執行腳本較多,可以在Vagrantfile中指定內聯腳本,在Vagrant.configure節點外面,寫入命名內聯腳本:
$script = <<SCRIPT
echo I am provisioning...
echo hello provision.
SCRIPT
- 1
- 2
- 3
- 4
然后,inline調用如下:
config.vm.provision "shell", inline: $script
- 1
3.1.3.3 外部腳本
也可以把代碼寫入代碼文件,並保存在一個shell里,進行調用:
config.vm.provision "shell", path: "script.sh"
- 1
script.sh的內容:
echo hello provision.
- 1
效果是一樣的。
Tips:path可以使用http/https來訪問遠程腳本,這個在部署時訪問一個腳本倉庫來做一些通用的操作,比較方便。如:
config.vm.provision "shell", path: "https://example.com/provisioner.sh"
- 1
Tips: 腳本文件在host機器上,而腳本實際上是在vm里運行的,做個測試驗證一下,在Vagrant.configure節點外面,寫入命名內聯腳本:
$script = <<SCRIPT
echo I am provisioning...
date > /etc/vagrant_provisioned_at
SCRIPT
- 1
- 2
- 3
- 4
檢查結果, /etc/vagrant_provisioned_at 這個文件不在host主機里,而是在vm虛機里。
3.2 腳本參數
如果要執行的腳本需要參數,那么使用args屬性進行傳遞:
config.vm.provision "shell" do |s|
s.inline = "echo $1"
s.args = "'hello, world!'"
end
- 1
- 2
- 3
- 4
Tips: 這兩args有兩層引號,如果去掉一層,字符串中的逗號會讓shell以為是兩個參數,那么后面的world會被丟掉。
你也可以使用方括號作為外層分隔符,而內層分隔符使用單引號或雙引號都可以,只要前后匹配即可,如:
s.args = ["hello, world!"]
- 1
Tips: 多個參數,你可以把args理解為一個json 數組,只要在inline里用 $x
進行引用即可。
2.3 環境變量
為命令行指定環境變量,env的格式為hash,是一個hash對象的列表,多個環境變量,多次配置env。
如:
config.vm.provision "shell" do |s|
s.inline = "echo $1 $JAVA_HOME"
s.env = {JAVA_HOME:"/opt/java"}
s.args = ["java_home is "]
end
- 1
- 2
- 3
- 4
- 5
執行結果:
==> default: java_home is /opt/java
- 1
多個環境變量的例子:
config.vm.provision "shell" do |s|
s.inline = "echo $1 $JAVA_HOME $2 $PATH"
s.env = {JAVA_HOME:"/opt/java",PATH:"$JAVA_HOME/bin:$PATH"}
s.args = ["java_home is ",";PATH ="]
end
- 1
- 2
- 3
- 4
- 5
執行結果:
==> default: java_home is /opt/java ;PATH = /opt/java/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games
- 1
Tips: 環境變量可以引用已經存在的環境變量,如 PATH:"/opt/java/bin:$PATH"
,結果是在原有的PATH環境變量前面增加了一個路徑。
Tips: env新增的環境變量,是順序執行賦值操作的,實例中JAVA_HOME,系統中原來是沒有的,如果JAVA_HOME和PATH這兩個參數順序換一下,把JAVA_HOME放在后面,PATH在拼接JAVA_HOME的時候取到的是系統原來的值,這里是null。
config.vm.provision "shell" do |s|
s.inline = "echo $1 $JAVA_HOME $2 $PATH"
s.env = {PATH:"$JAVA_HOME/bin:$PATH",JAVA_HOME:"/opt/java"}
s.args = ["java_home is ",";PATH ="]
end
- 1
- 2
- 3
- 4
- 5
結果是: ==> default: java_home is /opt/java ;PATH = /bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games
這里出錯了,本來應該是/opt/java/bin
,結果變成了/bin
。
同樣,如果在系統的/etc/profile中加入:export JAVA_HOME=/usr/local/jdk
那么上面例子的執行結果將是:
==> default: java_home is /usr/local/jdk ;PATH = /usr/local/jdk/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games
- 1
Tips: provision里設置的環境變量,只對provision自身操作有效,vagrant ssh
登錄vm,里邊的變量值是不會變的。
4 文件操作
file 操作有兩個參數:
- source : 源文件或文件夾
- destination : 目標文件或文件
config.vm.provision "file", source: "./Vagrantfile", destination: "Vagrantfile"
- 1
將host主機的 “./Vagrantfile” 上傳到 vm虛擬機的目標文件 “./Vagrantfile” 。
Tips: 文件是通過scp上傳到vm的,使用的是缺省用戶,可使用vagrant ssh-config
查看缺省用戶的名稱,一般為vagrant。所以,目的路徑需要讓默認用戶擁有寫權限。
5 擴展操作
vagrant可以集成其他服務器運維工具,來增強服務器管理能力。在使用這些技術之前,需要系統地學習這些技術。而每一套系統都有很多內容學習。本文只簡單介紹,不做詳細展開。
5.1 集群管理,自動化配置等系統
ansible,cfengine,Chef,puppet
每一套系統都可以寫本書了,所以這里不詳細說明。
簡單來說 Ansible 是一個極簡化的應用和系統部署工具,類似 Puppet、Chef、SaltStack。由於默認使用 ssh 管理服務器(集群),配置文件采用 yaml 而不是某一種特定語言制定。
cfengine是一個Linux的自動化配置系統。
Chef 是一套Linux的配置管理系統。
5.2 Docker 面向容器的虛擬解決方案
Docker 是一個開源的應用容器引擎,讓開發者可以打包他們的應用以及依賴包到一個可移植的容器中,然后發布到任何流行的 Linux 機器上。docker不會虛擬guest os系統,幾乎沒有性能開銷,最重要的是,他們不依賴於任何語言、框架包括系統。
Docker自身提供了很多優秀的工具和客戶端,目前vagant支持的操作並不方便,建議直接使用docker的客戶端工具學習和使用docker。
5.3 Salt
Salt 是一個強大的遠程執行管理器,用於快速和高效的服務器管理。