Dev Talks

Ansible 入門:簡介、解決問題、基本架構

Jeff Chen, Rails 工程師 Mar 22, 2023

今年因為負責了一個稍有年代的專案維護作業,深度接觸了許多 Ruby on Rails 之外的領域,維護過程中印象比較深刻的一門學問就是 Ansible 了。

如同前面所提,因為專案比較久了,Ansible 專案中負責加密解密的  password 已遺失,使得 Ansible 專案呈現運作沒有問題、但要改卻完全改不動的尷尬場面;再加上原先專案使用的 AWS EC2 instance 為 AWS Linux1 的版本,為了未來方便維護,決定要新開 EC2 instace 使用 AWS Linux2,因此有機會可以好好認識 Ansible。以下將會依序 「Ansible 是什麼」「解決了什麼問題」「搭配 Capistrano」「基本架構」 來簡單介紹 Ansible。

Ansible 是什麼

Ansible 是以 Python 開發的自動化組態管理工具。透過 ssh key 連線到目標 EC2 instance 後,可以輕鬆地自動管理多台 EC2 instance。在目前的專案中,主要使用 Ansible 來建置所需要的環境。那麼為什麼是選擇 Ansible?因為它的自動化與標準化為我們解決了許多問題。

解決了什麼問題

通常一個環境會有 3 台左右的 EC2 instance 甚至更多,不僅是為了流量分流,也可以讓特定機器只處理需要在背景處理的任務,但是總歸來說,都是為了讓網站可以流暢的運作。因此,確保每台機器所應用到的工具版本、細節設定都是一致的就非常重要了。

這就像是有天你父母一起買了新手機,並請你在兩台新手機安裝一樣的 app,並且該登入的 App 要以共用帳號登入,所以相關設定也都要一模一樣。如果只有兩台手機而且要裝的 app 也不多的話還可以快速處理完,但是如果所有親戚長輩都有同樣要求,就是個大工程了。

透過 Ansible,我們可以輕鬆的一次對多台機器進行所有的環境建置與工具安裝,並且確保每台機器的版本設定都是一致。

  • 自動化:一次為多台機器配置所需要的環境及工具,減少人工維運重複工作。

  • 標準化:確保每一台機器所安裝的環境、工具及工具版本都是一致的。

搭配 Capistrano

如同前面所提到,目前手上專案主要是讓 Ansible 來幫我們完成 EC2 instance 的環境建置以及設定,而專案的部屬則是交給 Capistrano 處理,並且也可以透過 Capistrano 來使用 Ansible 安裝的工具。舉例來說,Ansible 幫我們在 EC2 instance 安裝了 Puma、Sidekiq,而我們可以透過 cap production puma:status 等等的指令做到狀態確認、啟動、關閉、重啟等等動作。

基本架構

上圖為一個 Ansible 專案的基本架構,以下會進一步說明。

inventories

inventory 基本上可以看成機器列表,並且可以分 staging、production 環境,透過 inventory 檔案定義要連到哪一台 EC2 instance,當然,前置作業是需要在 ~/.ssh 先設定好 SSH 連線。

# inventories/production

[web]
ansible-demo
ansible-demo2

[bat]
ansible-demo-bat

[production:children]
web
bat

從以上範例來看,我已經事先在 ~/.ssh 設定好三台 EC2 instance,因此在 inventory 才可以直接用設定好的 Host 名稱。

在 inventory 裡面還可以幫機器設定代號,像是在範例中 ansible-demo ansible-demo2 這兩台機器的代號為 web;而 bat 則代表 ansible-demo-bat

設定好有什麼用呢?先記著這邊的代號,後面我們會用到。

group_vars

group_vars 用來設定變數,同樣可以分 staging、production 環境。

可以在與 staging、production 資料夾同一層的地方建立 all.yml 檔案,用來放一些不分環境的變數。

# group_vars/production/vars.yml

each_group:
  redis:
    host: {{ vault.redis.host }}
    port: 6379
    
# group_vars/production/vault.yml

vault:
  redis:
    host: xxxxxxxxxxxxx

在 vars.yml 檔案裡面,設定所有會用到的變數,要應用設定好的變數也非常簡單,只要在需要用到變數的地方輸入 {{each_group.redis.host }} 即可。

但是如果有敏感資訊的話,可以在 vault.yml 裡面另外設定變數,並且將 vault.yml 的內容加密。

加密的方式也非常簡單,首先可以在根目錄的地方建立 .vault_password 檔案,並且將密碼放在裡面,記得要把這個檔案放到 .gitignore 裡面,如此一來,就可以使用以下指令進行加密解密。

# 加密
ansible-vault encrypt group_vars/production/vault.yml --vault-password-file=.vault_password

# 解密
ansible-vault decrypt group_vars/production/vault.yml --vault-password-file=.vault_password

下圖即為加密後的樣子。

roles

roles 資料夾內設定了每個 role 所需要執行的任務,因此通常會用最終目的來為每個 role 命名,像是用來安裝設置 ruby 的 role 就取名為 ruby。

一個 role 裡面,會包含以下目錄及檔案:

- tasks/main.yml
  - role 執行的任務列表(一定會有)
- files
  - 存放當前 role 會使用到,需要一起上傳到機器的檔案
- handlers
  - 通常用來重啟服務(service)
- templates
  - 用來放置被當前 role 所使用的 .j2 檔案

最基本,每個 role 一定會有的就是 tasks/main.yml 了,裡面設置了這個 role 所需要執行的所有任務。

以下面範例為例,這邊設置了一個名稱為 add app-user 的任務,那在執行 Ansible 時,就會依照檔案內容,在每一台 EC2 instnce 建立 user。

# app_user/tasks/main.yml

- name: add app-user
  user:
    name: "app-user"

site.yml

在這個檔案,設定了哪些 role 要推上哪些 EC2 instance。
還記得前面 inventory 幫機器設定的代號嗎?Ansible 有一個預設代號 all,代表在其之下的每個 roles 都會推上 inventories 設定的每個 EC2 instance,由此可知, web 之下的 roles 會推上代號為 web 的機器;bat 之下的 roles 會推上代號為 bat 的機器。

# site.yml

- hosts: all
  become: yes
  roles:
    - app_user
    - nginx

- hosts: web
  become: yes
  roles:
    - ruby

- hosts: bat
  become: yes
  roles:
    - sidekiq

部署

最後,執行以下指令就會將專案推上 EC2 instance。

# production
ansible-playbook -i inventories/production site.yml --vault-password-file=.vault_password

# staging
ansible-playbook -i inventories/staging site.yml --vault-password-file=.vault_password

總結

希望以上介紹能讓剛接觸 Ansible 的朋友對 Ansible 有多些認識。我對 Ansible 也不敢說非常熟悉,所以盡量以最簡單的方式來介紹 Ansible 的整個架構以及在應用面上可以幫我們做到什麼事,希望能對大家有幫助。


分享