Learn Chef Rally 學習筆記 part6 — 初始化及更新 node

Luyo
verybuy-dev
Published in
21 min readAug 23, 2017

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

[Bootstrap your node]

回憶一下在最早的章節學過的 chef-client,是裝在 node 上的指令,可以套用 cookbooks 來定義這個 node 應該要長成什麼樣子。

而對一個 node 做「安裝 chef-client」並且「向 Chef server 報到」的這個流程,Chef 把它稱做 bootstrapping

這一個章節我們將會 bootstrap 一個 node,並將 learn_chef_httpd 這個 cookbook 套用在它上面。

bootstrapping 的指令是 knife bootstrap ,因為這個指令是從工作站去對 Chef server 下的,而 Chef server 會需要 node 的登入權限,所以必須將 node 的帳密或密鑰帶入 knife bootstrap 的參數之中。Chef 推薦使用密鑰,因其是比較安全的選擇。

使用密鑰做 bootstrap

指令長這樣:

$ knife bootstrap ADDRESS --ssh-user USER --sudo --identity-file IDENTITY_FILE --node-name node1-centos --run-list 'recipe[learn_chef_httpd]'

把其中的 ADDRESSUSERIDENTITY_FILE 換成自己的,執行後結果如下:

$ knife bootstrap 13.229.51.21 --ssh-user centos --sudo --identity-file ~/.ssh/test.pem --node-name node1-centos --run-list 'recipe[learn_chef_httpd]'
Creating new client for node1-centos
Creating new node for node1-centos
Connecting to 13.229.51.21
13.229.51.21 -----> Installing Chef Omnibus (-v 13)
13.229.51.21 downloading https://omnitruck-direct.chef.io/chef/install.sh
13.229.51.21 to file /tmp/install.sh.9145/install.sh
13.229.51.21 trying curl...
13.229.51.21 el 7 x86_64
13.229.51.21 Getting information for chef stable 13 for el...
13.229.51.21 downloading https://omnitruck-direct.chef.io/stable/chef/metadata?v=13&p=el&pv=7&m=x86_64
13.229.51.21 to file /tmp/install.sh.9151/metadata.txt
13.229.51.21 trying curl...
13.229.51.21 sha1 d3d26412b6304c92f72749d00e62e0191ceada05
13.229.51.21 sha256 fe051b504856a74ccce1fd23ff92c296506cb8292a3933c71069ae915e7a4a00
13.229.51.21 url https://packages.chef.io/files/stable/chef/13.3.42/el/7/chef-13.3.42-1.el7.x86_64.rpm
13.229.51.21 version 13.3.42
13.229.51.21 downloaded metadata file looks valid...
13.229.51.21 downloading https://packages.chef.io/files/stable/chef/13.3.42/el/7/chef-13.3.42-1.el7.x86_64.rpm
13.229.51.21 to file /tmp/install.sh.9151/chef-13.3.42-1.el7.x86_64.rpm
13.229.51.21 trying curl...
13.229.51.21 Comparing checksum with sha256sum...
13.229.51.21 Installing chef 13
13.229.51.21 installing with rpm...
13.229.51.21 警告:/tmp/install.sh.9151/chef-13.3.42-1.el7.x86_64.rpm: 表頭 V4 DSA/SHA1 Signature, key ID 83ef826a: NOKEY
13.229.51.21 正在準備… ################################# [100%]
13.229.51.21 Updating / installing...
13.229.51.21 1:chef-13.3.42-1.el7 ################################# [100%]
13.229.51.21 Thank you for installing Chef!
13.229.51.21 Starting the first Chef Client run...
13.229.51.21 Starting Chef Client, version 13.3.42
13.229.51.21 resolving cookbooks for run list: ["learn_chef_httpd"]
13.229.51.21 Synchronizing Cookbooks:
13.229.51.21 - learn_chef_httpd (0.1.0)
13.229.51.21 Installing Cookbook Gems:
13.229.51.21 Compiling Cookbooks...
13.229.51.21 Converging 3 resources
13.229.51.21 Recipe: learn_chef_httpd::default
13.229.51.21 * yum_package[httpd] action install
13.229.51.21 - install version 2.4.6-45.el7.centos.4 of package httpd
13.229.51.21 * service[httpd] action enable
13.229.51.21 - enable service service[httpd]
13.229.51.21 * service[httpd] action start
13.229.51.21 - start service service[httpd]
13.229.51.21 * template[/var/www/html/index.html] action create
13.229.51.21 - create new file /var/www/html/index.html
13.229.51.21 - update content in file /var/www/html/index.html from none to ef4ffd
13.229.51.21 --- /var/www/html/index.html 2017-08-23 16:12:52.612599519 +0000
13.229.51.21 +++ /var/www/html/.chef-index20170823-9222-19jv4ip.html 2017-08-23 16:12:52.612599519 +0000
13.229.51.21 @@ -1 +1,6 @@
13.229.51.21 +<html>
13.229.51.21 + <body>
13.229.51.21 + <h1>hello world</h1>
13.229.51.21 + </body>
13.229.51.21 +</html>
13.229.51.21 - restore selinux security context
13.229.51.21
13.229.51.21 Running handlers:
13.229.51.21 Running handlers complete
13.229.51.21 Chef Client finished, 4/4 resources updated in 37 seconds

這樣就灌好一台 web server 了,對我這個 DevOps 的新手來說,覺得實在好恐怖。

用帳密做 bootstrap

就是把參數改掉用帳密如下:

$ knife bootstrap ADDRESS --ssh-user USER --ssh-password 'PASSWORD' --sudo --use-sudo-password --node-name node1-centos --run-list 'recipe[learn_chef_httpd]'

Bootstrap a local virtual machine 的部分目前用不到,跳過。

如果以上的指令失敗,有幾個可能的原因,除錯方法如下:

  • 確認目前執行 knife 指令所在的目錄在 learn-chef 或其子目錄底下
  • 確認 learn-chef/.chef 目錄存在,且其內有 knife.rb 及 RSA private key file
  • 確認 node 的 IP 正確且網路有通
  • 確認指令中使用的帳號具有 sudo 權限
  • 確認 node 的 22, 80, 443 這個 port 都有開啟

knife bootstrap 的文件在此,有比較詳細的參數說明。

確認結果

據說剛剛下完指令後發生了兩件事。第一,這個 node 跟 Chef server 之間做好了關聯,可以用 knife node list 確認:

$ knife node list
node1-centos

然後可以用 knife node show 觀看詳細的 node 資訊:

$ knife node show node1-centos
Node Name: node1-centos
Environment: _default
FQDN: ip-172-31-21-70.ap-southeast-1.compute.internal
IP: 13.229.51.21
Run List: recipe[learn_chef_httpd]
Roles:
Recipes: learn_chef_httpd, learn_chef_httpd::default
Platform: centos 7.3.1611
Tags:

第二件事是這個 node 去向 Chef server 做了初始的報到動作,並執行了 learn_chef_httpd 這個 cookbook,這是因為我們剛剛加了 --run-list learn_chef_httpd 這個參數。

現在可以來確認一下這個 node 的 web server 有沒有正常運作:

$ curl 13.229.51.21
<html>
<body>
<h1>hello world</h1>
</body>
</html>

已確認 web server 正常回應囉。

測驗

Which of the following most completely describes what happens during the bootstrap process?

  • The Chef client is installed on the node.
  • The node checks in with the Chef server for the first time.
  • The Chef client is installed on the node and the node then checks in with the Chef server.

Which argument to the knife bootstrap command specifies your node's run-list?

  • --run-list
  • --run_list
  • --cookbooks

答案是 3, 1。

[Update your node’s configuration]

要點:
1. 你可以用 knife bootstrap 建立 node 與 Chef server 的關聯並且做初始的報到動作,這個程序叫做 bootstrapping,是一個一次性的動作
2. 當 cookbook 有更動的時候,可以用 knife ssh 指令去更新 node 的設定。

Chef 可以提供 node 的資訊給 cookbooks,這裡的範例會將 node 的 FQDN 顯示在網頁上。

更新 HTML template

當你對一個 node 做完 bootstrap,Chef server 會產生一個叫 node object 的東西,它會包含一些關於這個 node 的屬性資訊,並存放於 Chef server 上。當一個 recipe 在 node 上跑起來的時候,Chef 程式就會回去 Chef server 上把這個 node 的屬性叫出來,並放入進 node 物件裡,我們就可以在 Chef recipes 之中去存取這些資訊。

現在先來更新 template 檔案 learn_chef_httpd/templates/index.html.erb

<html>
<body>
<h1>hello from <%= node['fqdn'] %></h1>
</body>
</html>

更新 cookbook 的 version metadata

在上傳一個修改過後的 cookbook 到 Chef server 之前,最好是每次都可以檢查一下 cookbook 的 version metadata,確保每個版本跟功能的記載無誤。

cookbook 的版本資訊會寫在 metadata.rb 之中,當你執行 chef generate cookbook 指令產生 cookbook 的時候,初始的版本會被訂為 0.1.0。用 cat 看一下 learn_chef_httpd/metadata.rb 的內容:

$ cat metadata.rb
name 'learn_chef_httpd'
maintainer 'The Authors'
maintainer_email 'you@example.com'
license 'all_rights'
description 'Installs/Configures learn_chef_httpd'
long_description 'Installs/Configures learn_chef_httpd'
version '0.1.0'
issues_url 'https://github.com/learn-chef/learn_chef_httpd/issues' if respond_to?(:issues_url)
source_url 'https://github.com/learn-chef/learn_chef_httpd' if respond_to?(:source_url)

可以看到 version 用前是 0.1.0。大部分 Chef cookbooks 的版號原則上會按照 Semantic Versioning 的原則來命名,也就是 MAJOR.MINOR.PATCH。

而剛剛我們更新了 HTML template,可以算是一個功能上的 minor change,所以我們可以將 metadata.rb 裡的 version 更新為 0.2.0:

version '0.2.0'

cookbook 版號的說明文件:https://docs.chef.io/cookbook_versions.html

上傳 cookbook 至 Chef server

執行上傳指令:

$ knife cookbook upload learn_chef_httpd
Uploading learn_chef_httpd [0.2.0]
Uploaded 1 cookbook.

在 node 上跑 cookbook

現在更新過的 cookbook 已經被傳上 Chef server 了,我們接著可以在 node 上跑 chef-client 指令,它會將這個 node 的 run-list 裡所列的最新版本的 cookbook 從 Chef server 上 pull 下來,然後套用 run-list 在這個 node 上。

若要在 node 上執行 chef-client,最基本的就是 ssh 進去 node 裡下 chef-client 指令。但既然我是們在學 DevOps 當然不能用這麼傻逼的方法!

Chef 提供比較厲害的方法叫做 knife ssh 指令,它可以一次讓多個 node 去執行 chef-client 指令。

更厲害的是 knife ssh 除了用 IP 以外,還可以用 search query 去指定要連到哪些機器去下指令,它提供了多種搜尋的 patterns,還可以包含多種搜尋條件。

knife bootstrap 一樣,我們可以用帳密或密鑰來做 ssh 連線。

以密鑰連線更新 node

指令的基本型態長這樣,要自己把 USERIDENTITY_FILE 換掉:

$ knife ssh 'name:node1-centos' 'sudo chef-client' --ssh-user USER --identity-file IDENTITY_FILE --attribute ipaddress

BUT!如果 node 機器是開在 Amazon EC2 或 Microsoft Azure 或 Google Compute Engine 這幾個平台上,就要把 --attribute 換成對應的值:

EC2 — cloud.public_hostname
Azure — cloud.public_ip
GCP — cloud_v2.public_ipv4

我的機器是開在 EC2 上,所以指令就會長這樣:

$ knife ssh 'name:node1-centos' 'sudo chef-client' --ssh-user centos --identity-file ~/.ssh/test.pem --attribute cloud.public_hostname
ec2-13-229-51-21.ap-southeast-1.compute.amazonaws.com Starting Chef Client, version 13.3.42
ec2-13-229-51-21.ap-southeast-1.compute.amazonaws.com resolving cookbooks for run list: ["learn_chef_httpd"]
...(略)
ec2-13-229-51-21.ap-southeast-1.compute.amazonaws.com + <h1>hello from ip-172-31-21-70.ap-southeast-1.compute.internal</h1>
...(略)

可以看到原本的 hello world 被換成 hello from ip-172-31-21-70.ap-southeast-1.compute.internal 了。

'name:node1-centos' 的部分是所謂的 “search query”,它會回傳名稱叫 “node1-centos” 的所有 nodes。

但實務上一個 name 應該只會對應一個 node,所以我們可以進一步用 'name:node1-*' 這樣的 wildcard parttern 來選出所有以 “node1-” 開頭的 nodes。

不過很好奇用 --attribute的值用 cloud.public_hostname 跟用 ipaddress 有什麼不一樣,所以再下一次指令來實驗一下:

$ knife ssh 'name:node1-centos' 'sudo chef-client' --ssh-user centos --identity-file ~/.ssh/test.pem --attribute ipaddress
172.31.21.70 Starting Chef Client, version 13.3.42
172.31.21.70 resolving cookbooks for run list: ["learn_chef_httpd"]
...(略)

看起來是都可以 work 的,差別是前者開頭寫的是 public dns,後者開頭是寫 private ip address。

接下來就解釋了,--attribute 是用來告訴 knife 要用什麼來開啟 ssh 連線。預設值是 FQDN,但因為你的 node 不一定會有可解析的 FQDN,如果沒有的話就可以用 ipaddress 去對應到 private IP 來建立連線。

但用 cloud.public_hostname 的好處這邊並沒有解釋,再實驗了一下不帶 --attribute 參數會怎樣:

$ knife ssh 'name:node1-centos' 'sudo chef-client' --ssh-user centos --identity-file ~/.ssh/test.pem
ec2-13-229-51-21.ap-southeast-1.compute.amazonaws.com Starting Chef Client, version 13.3.42
ec2-13-229-51-21.ap-southeast-1.compute.amazonaws.com resolving cookbooks for run list: ["learn_chef_httpd"]
...(略)

結果前面的 host 跟第一次帶 cloud.public_hostname 是一樣的,應該是因為這台機器的 FQDN 跟 public DNS是一樣的吧?

NOTE: node attributes 的文件 — https://docs.chef.io/attributes.html#automatic-ohai。但看了一下,發現這頁並沒有提到 cloud.public_hostname 這系列的說明。

確認結果

最後來看一下現在的 index 長什麼樣子:

$ curl 172.31.21.70
<html>
<body>
<h1>hello from ip-172-31-21-70.ap-southeast-1.compute.internal</h1>
</body>
</html>

結果有趣了,這裡顯示的結果 node[‘fqdn’] 居然是 private DNS!

好吧,只好再來試一次,將 --attribute 內的值改成 fqdn 看會發生什麼事:

$ knife ssh 'name:node1-centos' 'sudo chef-client' --ssh-user centos --identity-file ~/.ssh/test.pem --attribute fqdn
ip-172-31-21-70.ap-southeast-1.compute.internal Starting Chef Client, version 13.3.42
ip-172-31-21-70.ap-southeast-1.compute.internal resolving cookbooks for run list: ["learn_chef_httpd"]
...(略)

真相大白了,FQDN 的確是 EC2 instance 的 private DNS 而不是 public DNS!而且在這個 case 中 --attribute 的預值不是教學中說的 fqdn 而是 cloud.public_hostname

測驗

What is a node object?

  • Any system that is managed by Chef.
  • An object on the Chef server that contains attributes that describe a node.
  • The more formal name for “node”.

Where do you change a cookbook’s version?

  • In the metadata.rb file.
  • In the cookbook itself.
  • In the template file.

True or False: A template enables you to provide placeholders that are replaced with their values when chef-client runs.

  • True.
  • False.

答案是 2, 1, 1。

--

--