Learn Chef Rally 學習筆記 part6 — 初始化及更新 node
本文記錄 Learn Chef Rally 以下章節的學習歷程:
- Track — Infrastructure Automation > Manage a node with Chef server > Bootstrap your node
- Track — Infrastructure Automation > Manage a node with Chef server > Update your node’s configuration
[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]'
把其中的 ADDRESS
及 USER
及 IDENTITY_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
指令的基本型態長這樣,要自己把 USER
、 IDENTITY_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。