704.1 Ansible (8)
Ansible 在考試中佔了 8 分之多,而且裡頭有很多小項目。Ansible 目前是由 Red Hat 所支持的開源專案。它是一個設定管理工具,由一個控制台 (conrol machine) 去控制多個管理節點,完成某些工作以讓它們達到一個特定的狀態。因為 Ansible 我之前也沒有接觸過,我們就先參考一下官網文件看看要如何開始吧。
我覺得要快速接觸一個軟體,如果官方文件有 Get Started 這個部分,它會是一個很好的開始,通常它會用一個簡單的範例,讓你可以很快地去實際「使用」這個軟體,而不用先閱讀很長的文件,瞭解一堆指令的用法或是背後的原理。這裡我們也從官方文件的 Get Started 開始,網址是 https://docs.ansible.com/ansible/latest/user_guide/intro_getting_started.html。
在開始之前,我們先來建立測試環境。因為 Ansible 要有控制台和管理節點,也就是說至少要有兩台機器,那我們就用虛擬機來搭建環境吧。這裡我想要開三台虛擬機(希望電腦撐得住),其中一台作為中控台,另兩台作為目的節點。當然也可以用本機作為控制台,然後只開一台虛擬機作為目的節點,這樣會比較節省硬體資源,不過我暫時還不想在本機安裝 Ansible,所以全部都在虛擬機裡面完成。接下來我們來建立這三台機器。既然學過 Vagrant,那我們就用 Vagrant 來作,首先開一個目錄,進到該目錄後用 vagrant init 產生 Vagrantfile,然後編輯它。
BOX_NAME = "ubuntu/xenial64"
Vagrant.configure("2") do |config|
config.vm.define "node1" do |node1|
node1.vm.box = BOX_NAME
node1.vm.hostname = "node-1"
node1.vm.network "private_network", ip: "192.168.50.10"
end
config.vm.define "node2" do |node2|
node2.vm.box = BOX_NAME
node2.vm.hostname = "node-2"
node2.vm.network "private_network", ip: "192.168.50.20"
end
config.vm.define "node3" do |node3|
node3.vm.box = BOX_NAME
node3.vm.hostname = "node-3"
node3.vm.network "private_network", ip: "192.168.50.30"
end
end
這裡 Vagrantfile 的重點是給它們不同的 private IP 及 host name,讓它們可以彼此溝通。接下來用 vagrant up 來啟動機器,待三台機器都啟動之後,我們登入到第一台機器 (node1),指令是 vagrant ssh node1,因為是多機環境,所以 vagrant ssh 要指定是那台機器。
現在我們可以開始 Get Started 了。Get Started 一起手就說,現在你應該已經讀過安裝指引,而且也安裝好 Ansible 了…。那就先來安裝 Ansible 唄。文件上說在 Ubuntu 以 apt 安裝 Ansible 的方式如下:
$ sudo apt-get update
$ sudo apt-get install software-properties-common
$ sudo apt-add-repository --yes --update ppa:ansible/ansible
$ sudo apt-get install ansible
在我的 Vagrant 環境中,會額外安裝以下套件,大部分和 Python 有關:
The following NEW packages will be installed:
ansible libpython-stdlib libpython2.7-minimal libpython2.7-stdlib python python-cffi-backend python-crypto python-cryptography python-ecdsa python-enum34
python-httplib2 python-idna python-ipaddress python-jinja2 python-markupsafe python-minimal python-paramiko python-pkg-resources python-pyasn1
python-setuptools python-six python-yaml python2.7 python2.7-minimal sshpass
接下來文件說明 Ansible 要怎麼和遠端機器溝通,基本上是透過 SSH,後面有一大段看不太懂,所以直接跳過去到下一段,告訴 Ansible 要管理的節點有那些。
首先編輯 /etc/ansible/hosts 這個檔案(需要 sudo),加上我們要連線過去管理的機器名稱 或 IP。這個檔案應該會有一些被註解掉的內容。因為 node2 和 node3 並沒有可以讓 node1 辨識的名稱,所以直接把 IP 加進去,以我的例子是 192.168.50.20 及 192.168.50.30。修改好之後存檔離開。接下來有兩個 SSH 相關的指令,它說可以設定 SSH agent 來避免需要重複輸入密碼,因為看不懂,所以先跳過去,但我是用 ssh key 作驗證,應該不用輸入密碼才對。最後終於要執行 Ansible,使用 $ ansible all -m ping 這個指令,結果看到如下的輸出後就停住沒反應了。
192.168.50.20 | UNREACHABLE! => {
"changed": false,
"msg": "Failed to connect to the host via ssh: Permission denied (publickey).\r\n",
"unreachable": true
}
先中斷執行,看一下這個訊息,它說 SSH 連線失敗,不被允許,而且和 public key 有關,所以是連的到,但認證出了問題,所以我們試一下如果不用 Ansible,直接以 ssh 能不能登入,指令是 ssh 192.168.50.20,結果訊息是一樣的。接下來試試看從本機直接用 ssh 連,不用要 vagrant ssh 指令。指令是 ssh vagrant@192.168.50.20。結果還是一樣,無法登入。因為訊息說和 public key 有關,所以我們查看一下 Vagrant 環境相關的 SSH 訊息,這裡有一個指令可以用:$vagrant ssh-config,加上機器名稱 node2。在我的環境中輸出如下:
Host node2
HostName 127.0.0.1
User vagrant
Port 2200
UserKnownHostsFile /dev/null
StrictHostKeyChecking no
PasswordAuthentication no
IdentityFile /Users/odie/multi-machine/.vagrant/machines/node2/virtualbox/private_key
IdentitiesOnly yes
LogLevel FATAL
這裡有一個檔名是 private_key 的檔案,看起來應該和這個有關係,因為一般 ssh 相關的 key 好像都是放在 ~/.ssh 這個目錄底下,但這個 key 放在目前工作目錄底下。man 一下 ssh 發現它有一個參數 -i 後面接的就是 identity_file,那就試試看吧。
ssh -i /Users/odie/multi-machine/.vagrant/machines/node2/virtualbox/private_key vagrant@192.168.50.20
喔,發現能登入了,所以應該是 ssh 要登入的時候找不到 key。
如果我們要從 node1 連到 node2,照理說把這個 key 放到 node1 的某個地方,然後 ssh 時指定這個 key 應該就可以了。不過還要把 key 複製一份到 node1,覺得有點麻煩,有沒有別的辦法?回到文件的上一段,有一個叫 ssh-agent 的東西,gogle 一下有個功能叫 ssh agent forwarding,看起來大概是這樣:你要從 A 連到 B,再從 B 連到 C、D、E 等等,但是要登入 C、D、E 的 key 都在 A 上,如果要把所有的 key 都搬到 B 可能不太安全,這時可利用 ssh agent forwarding,允許 A 讓 B 回頭來拿登入 C、D、E 所需要的 key,請注意這裡設定 ssh agent forward 是在 A 上設定,是 A 允許 B 來跟自己拿 key,而不是設定在 B。Vagrantfile 中可啟動 ssh agent forwarding 的功能,讓本機允許 Vagrant 虛擬機回來拿 key,請把 config.ssh.forward_agent = true 加在 Vagrantfile node1 的設定裡,然後重新啟動 node1。如果想要直接在本機的 ~/.ssh/config 中作設定,可參考下面內容,example.com 請輸入 node1,也就是允許回頭拿 key 的機器 IP。用這個方式設定的話,連入 node1 時要直接用 ssh,不要用 vagrant ssh,否則會吃不到設定值。
Host example.com
ForwardAgent yes
接下來用 ssh-add 在本機把剛才我們看到的 private key (identity file) 加到 agent 中,這樣 ssh agent forward 回來時才知道要去那裡找 key,指令是 ssh-add ,然後用 ssh-add -L 確認是否有成功加入。
到這邊差不多準備就緒了,我們來試一下,重新登入 node1,用 ssh-add -L 確認一下是不是有顯示剛剛在本機加入的 key,如果有的話 ssh agent forward 設定應該就沒問題了。用 ssh 連進 node2,已經可以登入。接下來我們在本機用 ssh-add 加入 node3 的 key,讓 node1 也可以連到 node3。
接下來再執行一次 $ ansible all -m ping,結果出現如下輸出
192.168.50.20 | FAILED! => {
"changed": false,
"module_stderr": "Shared connection to 192.168.50.20 closed.\r\n",
"module_stdout": "/bin/sh: 1: /usr/bin/python: not found\r\n",
"msg": "MODULE FAILURE\nSee stdout/stderr for the exact error",
"rc": 127
}
訊息寫 python not found,所以是沒有安裝 python。當然我們可以手動連進去一台一台安裝,不過這樣在機器數量很多時顯然不是一個好方法。想想看有什麼方法,首先想到的是透過 Vagrant 以 provision 的方式來作,在 provision 區段加入 apt install 指令,然後用 vagrant provision 在機器開啟的狀態安裝。那還有其他的方法嗎?回去看一下 Ansible 的安裝指引,看到這個指令 ansible myhost --sudo -m raw -a "yum install -y python2",文件說它可以透過 raw module 來安裝 Python。修改一下讓它適用於我們的 Ubuntu 環境:
$ ansible all --become -m raw -a "apt-get install -y minimal-python"
把 sudo 改成 become 是因為 sudo 這個旗標在新的 Ansible 已經 deprecated 所以用 become 來取代。執行後看看畫面,感覺有安裝成功,所以再執行一次 $ ansible all -m ping,希望可以成功執行,結果出現如下的回應:
192.168.50.20 | SUCCESS => {
"changed": false,
"ping": "pong"
}
192.168.50.30 | SUCCESS => {
"changed": false,
"ping": "pong"
}
出現 SUCCESS 了。拿去和 Get Started 的結果比比看,結果 Get Started 並沒有說這個指令出現什麼結果才算成功…。那我們試一下文件中的下一個指令吧。
$ ansible all -a "/bin/echo hello"
結果如下:
192.168.50.30 | CHANGED | rc=0 >>
hello
192.168.50.20 | CHANGED | rc=0 >>
hello
有 ehco hello 了,看起來是正確的。文件的下一段在說 Host Key Checking,當 SSH 連線到遠端主機會作 fingerprint 一類的檢查以確認它是不是原本的那一台主機,如果檢查不正確會禁止連線,另外在第一次連線時會問要不要把主機資訊記錄下來,有時會打斷 Ansible 的操作過程,例如我最先執行 ansible 的那次停住沒有反應,是因為它在等待回覆是否要紀錄主機資訊。這裡可以設定將這個檢查關掉,方法之一是去修改 /etc/ansible/ansible.cfg 設定的內容,將 host_key_checking = False 的註解拿掉。
結果 Get started 在這個地方就結束了,感覺有點虛,到目前所做的只是讓控制台透過 Ansible 和管理節點溝通,並沒有真正對機器進行配置。因此我從 Lorin Hochstein 和 Rene Moser 合著的 "Ansible: Up and Running"(中文版為《 Ansible 建置與執行第二版》,碁峰出版)找了一個實際配置機器的例子,我們跟著作一下,它會在管理節點上安裝並執行 nginx 伺服器,同時複製一個 HTML 到該管理節點作為 nginx 首頁,我們明天再繼續吧。