iT邦幫忙

2019 iT 邦幫忙鐵人賽

DAY 10
0

704.1 Ansible (8)

  • 瞭解自動化系統設置及軟體安裝的原則
  • 建立並維護 inventory 檔案
  • 瞭解 Ansible 如何和遠端系統互動
  • 管理 Ansible SSH 登入 credential,包含使用非特權 (unprivileged) 的登入帳號
  • 建立、維護並執行 Ansible playbook,包括 task、handler、conditional、loop 和 register
  • 建立並使用變數
  • 使用 Ansible vaults 維護 secrets
  • 編寫 Jinja2 templates,包括使用 common filter、loop 和 conditional
  • 瞭解並使用 Ansible 角色 (role),並從 Ansible Galaxy 安裝 Ansible role
  • 瞭解並使用重要的 Ansible task,包括 file、copy、template、ini_file、lineinfile、patch、replace、user、group、command、shell、service、systemd、cron、apt、debconf、yum、git 及 debug
  • 知道 dynamic inventory
  • 知道非 Linux 系統的 Ansible 特性
  • 知道 Ansible 容器

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 首頁,我們明天再繼續吧。


上一篇
[Day 09] Git (5)
下一篇
[Day 11] Ansible (2)
系列文
30 天準備 LPI DevOps Tools Engineer 證照30

尚未有邦友留言

立即登入留言