Learn Chef Rally 學習筆記 part3 — 基本 cookbook 設定及使用

Luyo
verybuy-dev
Published in
17 min readJul 23, 2017

本文記錄 Learn Chef Rally 以下章節的學習歷程:

[Make your recipe more manageable]

本章節的開頭寫著:

KEY POINT: A cookbook provides structure to your recipes and enables you to more easily reference external files, such as our web server’s home page. In essence, a cookbook helps you stay organized.

意思是 cookbook 這東西可以幫助你保持 recipes 的結構化,並讓你能更輕鬆地調用外部檔案。

1. 新增 cookbook

進入 ~/chef-repo 開一個新資料夾 cookbooks

mkdir cookbooks

執行指令 chef generate cookbook 以產生一個叫 learn_chef_httpd 的 cookbook:

$ chef generate cookbook cookbooks/learn_chef_httpd
Generating cookbook learn_chef_httpd
- Ensuring correct cookbook file content
- Ensuring delivery configuration
- Ensuring correct delivery build cookbook content
Your cookbook is ready. Type `cd cookbooks/learn_chef_httpd` to enter it.
There are several commands you can run to get started locally developing and testing your cookbook.
Type `delivery local — help` to see a full list.
Why not start by writing a test? Tests for the default recipe are stored at:
test/recipes/default_test.rb
If you’d prefer to dive right in, the default recipe can be found at:
recipes/default.rb

先安裝一下 tree 這個套件,然後觀察 cookbooks 資料夾的結構:

$ sudo yum install tree -y
(略)
$ tree cookbooks
cookbooks
└── learn_chef_httpd
├── Berksfile
├── chefignore
├── metadata.rb
├── README.md
├── recipes
│ └── default.rb
├── spec
│ ├── spec_helper.rb
│ └── unit
│ └── recipes
│ └── default_spec.rb
└── test
└── recipes
└── default_test.rb
7 directories, 8 files

很好,跟本機執行結果跟教學長得一樣。 這邊有一個說明區塊,說 chef generate cookbook指令其實還會生成一個隱藏資料夾 .delivery,這個資料夾的用法在之後的 module 裡會說明,那我們就先不理它吧。

2. 新增 template

OMG 又來一個新的叫 template 的功能,好吧就照他說的下指令:

$ chef generate template cookbooks/learn_chef_httpd index.html
Recipe: code_generator::template
* directory[cookbooks/learn_chef_httpd/templates/default] action create
 — create new directory cookbooks/learn_chef_httpd/templates/default
 — restore selinux security context
* template[cookbooks/learn_chef_httpd/templates/index.html.erb] action create
 — create new file cookbooks/learn_chef_httpd/templates/index.html.erb
 — update content in file cookbooks/learn_chef_httpd/templates/index.html.erb from none to e3b0c4
(diff output suppressed by config)
 — restore selinux security context

目前看起來是 chef 幫我們產生了一個 cookbooks/learn_chef_httpd/templates 的資料夾。用 tree 看一下目前的狀況:

$ tree cookbooks
cookbooks
└── learn_chef_httpd
├── Berksfile
├── chefignore
├── metadata.rb
├── README.md
├── recipes
│ └── default.rb
├── spec
│ ├── spec_helper.rb
│ └── unit
│ └── recipes
│ └── default_spec.rb
├── templates
│ ├── default
│ └── index.html.erb
└── test
└── recipes
└── default_test.rb
9 directories, 9 files

跟之前的差別的確是多了 templates 資料夾,進去看一下,default 是個資料夾,裡面是空的,index.html.erb 檔案也是空的。 接下來打開 index.html.erb 新增 html 內容,應該也是可以自由發揮:

<html>
<body>
<h1>Hello <a href=”https://www.verybuy.cc">VeryBuy</a></h1>
</body>
</html>

接著又有個說明區塊,說在實際應用上,這些網站的檔案比較有可能會是 .zip 或 .tar 這類 build 過的檔案。你可以把新的 web 檔案從外部 pull 下來,然後 deploy 到你的 web server 上。

3. 把 HTML template 加進 recipe

更新 cookbooks/learn_chef_httpd/recipes/default.rb,打開之後發現裡面會有一些預設的註解內容,刪不刪應該都無所謂,加入下面幾行:

package 'httpd'service 'httpd' do
action [:enable, :start]
end
template '/var/www/html/index.html' do
source 'index.html.erb'
end

這裡出現了一個新的 resource 類型 template

仔細觀察一下語法,意思應該是我們要載入 template 到 /var/www/html/index.html 這個檔案中,內容是引用 index.html.erb 這個檔案。但問題是 index.html.erb 不是絕對路徑,又跟 default.rb 不在同一層目錄底下,而是在 templates 底下,有玄機,看來這個 source 不是吃一般所想的路徑,而是直接去抓 templates 底下的檔案?不知道,先繼續往下看吧。

4. 執行 cookbook

執行 chef-client 指令:

$ sudo chef-client --local-mode --runlist 'recipe[learn_chef_httpd]'
[2017-07-23T08:37:51+00:00] WARN: No config file found or specified on command line, using command line option
s.
Starting Chef Client, version 12.12.15
resolving cookbooks for run list: ["learn_chef_httpd"]
Synchronizing Cookbooks:
- learn_chef_httpd (0.1.0)
Installing Cookbook Gems:
Compiling Cookbooks...
Converging 3 resources
Recipe: learn_chef_httpd::default
* yum_package[httpd] action install (up to date)
* service[httpd] action enable (up to date)
* service[httpd] action start (up to date)
* template[/var/www/html/index.html] action create
- update content in file /var/www/html/index.html from 95172f to e3b0c4
--- /var/www/html/index.html 2017-07-22 11:49:46.214923159 +0000
+++ /var/www/html/.chef-index.html20170723-12981-cgfouc 2017-07-23 08:37:59.216236694 +0000
@@ -1,6 +1 @@
-<html>
- <body>
- <h1>Hello <a href="https://www.verybuy.cc">VeryBuy</a></h1>
- </body>
-</html>
- restore selinux security context
Running handlers:
Running handlers complete
Chef Client finished, 1/4 resources updated in 08 seconds

這次的範例用了一個新的參數 --runlist,用來一次跑多個 recipes。看起來語法是 recipe[cookbook的名稱],然後 chef 會自己去翻這個 cookbook 底下的 recipes 資料夾,但不知道是不是所有檔案都會被挖出來執行?看原文的語意應該是只會執行被指定的 recipe,但這邊卻又沒有特別指定。

底下解釋了,recipe[learn_chef_httpd] 等於 recipe[learn_chef_httpd::default] 的意思,也就是這個指令會去執行 default.rb

但我還是覺得沒有說得很清楚,只好自己來實驗一下,再加入另一個 recipe 到 recipes 資料夾裡,看它會不會被執行。新增一個檔案 cookbooks/learn_chef_httpd/recipes/test.rb

file '/tmp/test' do
content 'VeryBuy is good.'
end

然後再執行一次剛剛的 chef-client 指令:

$ sudo chef-client --local-mode --runlist 'recipe[learn_chef_httpd]'
[2017-07-23T08:55:13+00:00] WARN: No config file found or specified on command line, using command line options.
Starting Chef Client, version 12.12.15
resolving cookbooks for run list: ["learn_chef_httpd"]
Synchronizing Cookbooks:
- learn_chef_httpd (0.1.0)
Installing Cookbook Gems:
Compiling Cookbooks...
Converging 3 resources
Recipe: learn_chef_httpd::default
* yum_package[httpd] action install (up to date)
* service[httpd] action enable (up to date)
* service[httpd] action start (up to date)
* template[/var/www/html/index.html] action create (up to date)
Running handlers:
Running handlers complete
Chef Client finished, 0/4 resources updated in 04 seconds

看起來我的 test.rb 並沒有被執行,用 more 檢查一下:

$ more /tmp/test
/tmp/test: 沒有此一檔案或目錄

沒錯,並不是 recipes 底下的所有檔案都會被執行,不寫清楚的話就是只去執行預設的 recipe: recipes/default.rb

我想以後遇到這種情況似乎還是把完整的 recipe[learn_chef_httpd::default] 寫清楚會比較好理解,以免新手混淆。

結論

咦?已經來到 Conclusion 了?那我的 test.rb 要怎麼跟 default.rb 一起在同一行指令裡被執行?居然沒有說,只丟了一個 run-list 連結就棄我而去了。可惡,只好點開來看一下:

A run-list must be in one of the following formats: fully qualified, cookbook, or default. Both roles and recipes must be in quotes, for example:

'role[NAME]'

or

'recipe[COOKBOOK::RECIPE]'

Use a comma to separate roles and recipes when adding more than one item the run-list:

'recipe[COOKBOOK::RECIPE],COOKBOOK::RECIPE,role[NAME]'

, 分隔 COOKBOOK::RECIPE 就對了,感覺連 recipe[] 都可以不用加?來試試看:

$ sudo chef-client --local-mode --runlist 'learn_chef_httpd::default,learn_chef_httpd::test'
(略)
resolving cookbooks for run list: ["learn_chef_httpd::default", "learn_chef_httpd::test"]
(略)
Recipe: learn_chef_httpd::default
(略)
Recipe: learn_chef_httpd::test
* file[/tmp/test] action create
- create new file /tmp/test
- update content in file /tmp/test from none to 3a126d
--- /tmp/test 2017-07-23 09:13:04.429963485 +0000
+++ /tmp/.chef-test20170723-13711-1a8d0i7 2017-07-23 09:13:04.429963485 +0000
@@ -1 +1,2 @@
+VeryBuy is good.
- restore selinux security context
(略)

看起來不錯,再用 more 檢查一下:

$ more /tmp/test
VeryBuy is good.

可以確認 test.rb 順利地被執行囉!

不過 run-list 的文件裡還提到了一個 role[NAME] 的東西,目前還不知道是啥鬼但有點在意,先放在心上。

正港的結論

這個 Conclusion 不是這個章節的小結而是整個 module 的總結:

  1. 我們學到了 Chef 是如何以測試及修復系統的方式,讓整個系統能保持在我們想要的樣子。我們一開始直接拿 recipe 來執行,爾後利用 cookbook 來使得程式碼能更有組織性。
  2. 當我們有很多 cookbooks 的時候,我們可以利用 run-list 來一次執行多個 recipes,並且能按照我們想要的順序去執行。
  3. 這裡的 web server cookbook 範例你大概不太可能拿來用在你的 production 環境,只有你自己知道你的需求是什麼,Chef 會提供你必要的工具幫助你達到目的。
  4. 你可以繼續實驗一下這個 module 學到的東西,當你玩夠了的時候請往下一個 module Manage a node 前進,你將學到如何從你的工作站遠端管理另一台 server (Chef 將稱之為 node)。

測驗

What does a cookbook do?

  1. It includes recipes and external information and makes them easier to manage.
  2. It includes only external information, such as templates, and makes them easier to manage.
  3. It includes only recipes and makes them easier to manage.

What is a run-list?

  1. A run-list specifies which recipes to run.
  2. A run-list specifies which recipes to run and they order in which to run them.
  3. A run-list specifies which cookbooks to run.

What does test and repair mean?

  1. Chef applies changes only when they are necessary.
  2. Chef always applies changes and then tests to see if they are correct.
  3. Chef repairs incorrect states and then tests to see if they are now correct.

答案是 1, 2, 1。

[指令及語法整理]

1. 新增 cookbook:

chef generate cookbook COOKBOOK_PATH

例:

chef generate cookbook cookbooks/learn_chef_httpd

2. 在 cookbook 中新增 template:

chef generate template COOKBOOK_PATH TEMPLATE_NAME

例:

chef generate template cookbooks/learn_chef_httpd index.html

但產出的 template 檔案不會叫 index.html 而叫做 index.html.erb

3. 用 run-list 一次執行多個 recipes:

$ sudo chef-client --local-mode --runlist 'recipe[COOKBOOK::RECIPE],COOKBOOK::RECIPE'

例:

$ sudo chef-client --local-mode --runlist 'recipe[learn_chef_httpd::default],learn_chef_httpd::test'

4. recipe 中使用 template:

template 'FILE_PATH' do
source 'TEMPLATE_FILE_NAME'
end

例:

template '/var/www/html/index.html' do
source 'index.html.erb'
end

其中 index.html.erb 會在 cookbook 中的 templates 資料夾內。

--

--