DevOps課程-Configuration Management with Ansible 21

Dynamic Inventory for EC2 Servers(使用EC2 inventory Plugin)

ZONGRU Li
14 min readOct 21, 2023

Dynamic Inventory

考量到我們透過Ansible管理InfraStructure,是非常動態的

上面說法是指,機台常態地被新增或被刪除

例如有依據業務需求設置auto-sacling機制

如果像下面這樣hard code就不合理(以下都是一些學習建立的動態機台IP):

真的寫的話注意不要暴露IP資訊到外面

也就是要動態地提供上面的IP位置,甚至是多組IP

然後考慮到以前製作的另一份EC2的Terraform Code

是有使用到user_data:

上面那個user_data不重要

這邊會嘗試將調整建立3台EC2(兩台是micro,一台small)

然後執行Ansible腳本而不要hard code IP位置

最終調整成:

terraform.tfvars:

先在主控機上面嘗試執行,最後看到:

看起來沒問題後,先移除,順便調整一下機台Tag

轉去調整Ansible腳本部分,但是想辦法動態提供機台IP給Ansible

Inventory Plugin V.S. Inventory Scrip

要做到前面描述的事情,需要Ansible自行連線到AWS上面拿到IP資訊

並透過AWS帳號去拿到特定region上面的機台IP等資訊,主要手段有兩個

  1. Inventory Plugin
  2. Inventory Scrip

找到關鍵文件:

建議選擇"Plugin"主要原因有幾個因素:

  1. 這會使用到Ansible的功能例如STATE MANGMENT
  2. Inventory Plugin是用YAML
  3. Inventory Script則是Python

所以以下就會依據Inventory Plugin來建置

然後不論選擇Inventory Plugin還是Inventory Script

都會對應到不同的InfraStructure Provider而有所不同

#可以透過以下指令來查看有哪些plugin清單:
ansible-doc -t inventory -l

所以這邊就是要找到連結AWS的Inventory Plugin

最終找到:

LINK

中間很多參數解釋,往下滾也會看到使用範例:

重點在於還要Python的module支援:

其中boto3是Python與AWS溝通使用的library

Boto3=AWS SDK for python

所以在驅動Ansible的主控機台上一定要具備上面要求的Python module

沒有的話就要pip工具來安裝

另外Ansible中的ansible.cfg要加入以下設定來使用aws_ec2這個Plugin:

Write plugin configuration

除了上述ansible.cfg設定檔內要有啟用aws_ec2 plugin設置外

還要建立一個設定檔,並且有一個嚴格的限制是

檔名結尾必須是"aws_ec2"的yaml檔案

例如:

inventory_aws_ec2.yaml

填寫以下內容:

#執行指令可以確認ansible是否可以連結到AWS該region上的機台資訊:
ansible-inventory -i inventory_aws_ec2.yaml --list

我看到缺乏boto3與botocore的python套件的警告

所以這邊額外加裝上述python套件:

#執行以下pip工具指令:
pip install boto3
pip install botocore

所以還要先安裝pip工具

#執行安裝pip工具(過程要輸入y):
sudo apt install python3-pip

繼續安裝前面的python套件:

再次執行確認inventory_aws_ec2.yaml檔案設定的指令

#執行指令可以確認ansible是否可以連結到AWS該region上的機台資訊:
ansible-inventory -i inventory_aws_ec2.yaml --list

我這時候先將三台機台建置起來,再次重跑上述指令會看到:

也就是還沒連線到真的三個被控機台

而只是透過boto3 module來取得到AWS EC2機台資訊

#如果只是要簡短看到機台,可以改下:
ansible-inventory -i inventory_aws_ec2.yaml --graph

如上這些DNS資訊就將會是Ansible之後連線取用的機台資訊

Assign public DNS to EC2 instance

上面拿到的目前是Private DNS,直接在EC2網頁

如果想透過這一個Private DNS或著IP去連線,必須在相同VPC內:

所以這時候我注意到,我的主控機用的VPC跟被控機用的VPC是不同

所以看到連不通:

但是我建立的目標機三台是使用相同的VPC

嘗試進到其中一台目標機去ping隔壁台目標機會看到:

後來研究了解到,即便是使用相同的VPC或SG的兩個機台之間

預設AWS不會允許兩台用private IP或private DNS互相溝通

需要額外在SG的inbound內設置以下允許所有ICMP的設置:

ICMP(Internet Control Message Protocol)

然後就可以透過內部IP或內部DNS與相同VPC的其他機台溝通:

Private DNS部分則是看VPC有無啟用以下兩個屬性設置:

另外也參考到這篇stackoverflow解說(LINK)

然後也看到這篇(LINK):

所以調整被控機的VPC設定加入:

最後重建所有被控機資源(機台還有VPC)後

新的被控機之間就可以透過private DNS溝通:

所以這時候被控機的main.tf變成:

以上只是個人研究,課程這邊則是要想辦法讓被控機有Public DNS

如上面範例,被控機建立出來後的Public DNS都是空的:

但是其實解法也就是一樣的啟用VPC上的

enable_dns_support = true

調整重建後重建被控機看到:

再次用指令檢視

#如果只是要簡短看到機台DNS,可以改下:
ansible-inventory -i inventory_aws_ec2.yaml --graph

Configure Ansible to use dynamic inventory

接著就是要讓ansible腳本可以吃到前面定義的inventory_aws_ec2.yaml檔案

然後得到剛剛弄好的三台的Public DNS

在ansible.cfg設定中,原本會固定執行機台指定到hosts檔案:

腳本中原本指定的機台是:

現在則要調整成:

每一個Play都要改到

然後對我來說現在就出現問題了,我必須要過濾掉主控機那台

所以研究aws_ec2 inventory的文件寫法(LINK)

所以我重新調整被控機的TF程式碼,新增tag:

總之三台都加上述tag

然後調整inventory_aws_ec2.yaml

#再次指令檢視:
ansible-inventory -i inventory_aws_ec2.yaml --graph

如上圖,主控機的部分消失了

接著回到課程

在執行腳本操作被控機台的時候

我們必須指定使用者帳號與連線ssh key的部分

除了直接打到ansible-playbook指令後面參數之外

也可以全域地打在ansible設定檔內:

並且為了避免Ansible使用到上面設定檔設置的預設的hosts檔案

執行指令要指定機台檔案-i參數指定到"inventory_aws_ec2.yaml"

#從主控機上執行playbook腳本:
ansible-playbook -i inventory_aws_ec2.yaml deploy-docker-new-user.yaml

最後看到成功完成:

以上就是動態地給予被控機的方式去執行Ansible腳本作業

如果我這時候調整Terraform,立刻地新增了第四台被控機:

執行:

等建置好之後,執行ansible腳本

#再次從主控機上執行playbook腳本:
ansible-playbook -i inventory_aws_ec2.yaml deploy-docker-new-user.yaml

可以看到只異動了第四台:

另外為了不要每次都指定到inventory_aws_ec2.yaml檔案

也可以設置到ansible設定檔內:

#這時候再次執行可改為不帶指定被控機相關檔案:
ansible-playbook deploy-docker-new-user.yaml

Target only specific servers

這邊講師用到的技術大概就是我前面研究到的

透過Terraform賦予機台的Tag

然後ansible的inventory_aws_ec2.yaml去過濾特定Tag的機台才作執行

例如如果某個AWS的region內有DEV機台群,與PROD機台群

可能要執行不同腳本:

在文件上有提供很詳細的filters條件:

LINK
LINK

上面這些attribute都可以當作過濾條件

最簡單就是我研究出來使用的tag的過濾方式

以下是講師設定的tag:

然後講師的過濾條件用到星:

上面文件中有很多有趣的過濾條件,有機會使用的時候可以參考

Create dynamic groups

在使用aws_ec2的Plugin對應建立inventory_aws_ec2.yaml

還有個問題是只有aws_ec2這個機台群組,如果要多個?

例如講師的設置有兩台DEV,還有兩台PROD

但是希望Ansible可以同時指定到這兩種機台

#用以下指令檢視,卻只有aws_ec2這個機台群組:
ansible-inventory -i inventory_aws_ec2.yaml --graph

希望可以是:

這邊就可以在inventory_aws_ec2.yaml檔案改用keyed_groups

但是他的過濾條件會跟filters使用的attribute不一樣

要從以下清單指令的條件去過濾:

#清單指令中的資訊去過濾:
ansible-inventory -i inventory_aws_ec2.yaml --list

這邊先參考講師的設置重建成DEV與PROD的機台群組

首先簡單過濾tag:

#拿取分群用過濾資訊用:
ansible-inventory -i inventory_aws_ec2.yaml --list

#看機台群分類結果用:
ansible-inventory -i inventory_aws_ec2.yaml --graph

如上,群組變多了,只是名稱上多了一個下底線"_Name_dev_server":

如果要避免下底線,可以給前綴字

這時候調整Ansible腳本指定機台為tag_Name_dev_server:

#直接執行:
ansible-playbook deploy-docker-new-user.yaml

最終正常跑完:

只作用在AWS網頁上定義的有Tag是"dev-server"

對應到Ansible機台群組變成"tag_Name_dev_server"

在分群上,我們只用到tag來分群,範例也還有好多種:

例如

#拿取分群用過濾資訊用:
ansible-inventory -i inventory_aws_ec2.yaml --list

#看機台群分類結果用:
ansible-inventory -i inventory_aws_ec2.yaml --graph

以上即是Ansible動態指定雲端機台的基本方式

參考課程reference

--

--

ZONGRU Li
ZONGRU Li

Written by ZONGRU Li

2022/11/17 開源部分個人筆記給LINE "Java程式語言討論區"社群,希望能對社群的技術學習做一點點貢獻.(掩面....記得退訂閱!

No responses yet