Ansible專欄文章之二:初入Ansible世界,用法概覽和初體驗


回到:Ansible系列文章


各位讀者,請您:由於Ansible使用Jinja2模板,它的模板語法{% raw %} {{}} {% endraw %}和{% raw %} {%%} {% endraw %}和我博客系統hexo的模板使用的符號一樣,在渲染時會產生衝突,儘管我盡我努力地花了大量時間做了調整,但無法保證已經全部都調整。因此,如果各位閱讀時發現一些明顯的詭異的錯誤(比如像這樣的空的 行內代碼),請一定要回復我修正這些渲染錯誤。

2.初入Ansible世界:用法概覽和初體驗

Ansible是一個自動化管理工具,它的用法可以非常簡單,只需學幾個基本的模塊就能完成一些簡單的自動化任務,它的用法也可以非常難,不僅需要學習大量Ansible知識,還需要大量的實際應用去熟悉最優化、最完美的自動化管理邏輯。比較悲催的是Ansible的知識體系比較龐大,它的知識板塊也比較零散,想要構建一個比較完善的Ansible知識體系確實稍有難度。

但無論如何,千里之行始於足下,學習任何一個新知識,總歸要從最基本的用法循序漸進地深入,並輔以逐漸展開的宏觀結構,加上學習過程中的不斷練習,最終構建出完善的知識體系。

因Ansible的基礎知識內容較多,本文先介紹最基本的概念和最基本的用法,讓大家對Ansible的用法以及功能有一個基本且系統性的認識。之後的文章再逐步探討Ansible如何應用在配置管理上。

2.1 測試環境並配置ssh主機互信

Ansible的作用是批量控制其它遠程主機,並指揮遠程主機節點做一些操作、完成一些任務。

所以在這個結構中,分爲控制節點被控制節點。Ansible是Agentless的軟件,只需在控制節點安裝Ansible,被控制節點一般不需額外安裝任何程序,就像一個普通的命令一樣,隨裝隨用。

Ansible的模塊是用Python來執行的,且默認遠程連接的方式是ssh,所以控制端和被控制端都需要有Python環境,並且被控制端需要啓動sshd服務,但通常這兩個條件在安裝Linux系統時就已經具備了。所以使用Ansible的安裝過程只有一個:在控制端安裝Ansible。

在本文中,將配置如下測試環境:包括一個Ansible控制節點和7個被控制節點。後面的文章中如果沒有特別說明,也都使用此處的主機環境。

主機描述 IP地址 主機名 操作系統 Ansible版本
control_node 192.168.200.26 control_node CentOS 7.2 Ansible 2.9
node1 192.168.200.27 node1 CentOS 7.2 -
node2 192.168.200.28 node2 CentOS 7.2 -
node3 192.168.200.29 node3 CentOS 7.2 -
node4 192.168.200.30 node4 CentOS 7.2 -
node5 192.168.200.31 node5 CentOS 7.2 -
node6 192.168.200.32 node6 CentOS 7.2 -
node7 192.168.200.33 node7 CentOS 7.2 -

所有主機上都已啓動sshd服務並監聽在22端口上。

因爲有時候也會使用主機名去控制目標節點,所以這裏也在control_node節點上配置了其餘7個節點的DNS解析,可在control_node節點的/etc/hosts文件中加入如下內容:

$ cat >>/etc/hosts<<EOF
192.168.200.27 node1
192.168.200.28 node2
192.168.200.29 node3
192.168.200.30 node4
192.168.200.31 node5
192.168.200.32 node6
192.168.200.33 node7
EOF

2.1.1 安裝最新版的Ansible

Ansible依賴於SSH協議(默認),只需要在控制節點(即control_node主機上)安裝一次Ansible即可。

各種系統下安裝最新版Ansible的方式參見官方手冊:安裝手冊

對於RHEL系列的系統來說,配置好epel鏡像即可安裝最新版的Ansible。在我當前寫文章的時候,最新版是Ansible 2.9版本。

$ cat >>/etc/yum.repos.d/epel.repo<<'EOF'
[epel]
name=epel repo
baseurl=https://mirrors.tuna.tsinghua.edu.cn/epel/7/$basearch
enabled=1
gpgcheck=0
EOF

然後安裝即可:

$ yum install ansible

Ansible每個版本釋放出來之後,都首先提交到Pypi,所以任何操作系統,都可以使用pip工具來安裝最新版的Ansible。

$ pip3 install ansible

但要注意,使用各系統的包管理工具(如yum)安裝Ansible時自動會提供一些配置文件,如/etc/ansible/ansible.cfg。而使用pip安裝的Ansible默認不提供配置文件。

2.1.2 Ansible參數補全功能

從Ansible 2.9版本開始,它支持命令的選項補全功能,它依賴於python的argcomplete插件。

安裝argcomplete:

# CentOS/RHEL
yum -y install python-argcomplete

# 任何系統都可以使用pip工具安裝argcomplete
pip3 install argcomplete

安裝完成後,還需激活該插件:

# 要求bash版本大於等於4.2
sudo activate-global-python-argcomplete

# 如果bash版本低於4.2,則單獨爲每個ansible命令註冊補全功能
eval $(register-python-argcomplete ansible)
eval $(register-python-argcomplete ansible-config)
eval $(register-python-argcomplete ansible-console)
eval $(register-python-argcomplete ansible-doc)
eval $(register-python-argcomplete ansible-galaxy)
eval $(register-python-argcomplete ansible-inventory)
eval $(register-python-argcomplete ansible-playbook)
eval $(register-python-argcomplete ansible-pull)
eval $(register-python-argcomplete ansible-vault)

最後,退出當前Shell重新進入,或者簡單的直接執行如下命令即可:

exec $SHELL

然後就可以按tab一次或兩次補全參數或提示參數。例如,下面選項輸入到一半的時候,按一下tab鍵就會補全得到ansible --syntax-check

$ ansible --syn

2.1.3 配置主機互信

因爲Ansible默認是基於ssh連接的,所以要控制其它節點首先需要建立好ssh連接,而建立ssh連接要麼需要提供密碼,要麼需要配置好認證方式。爲了方便後文的測試,這裏先配置好control_node和其它被控節點之間的主機互信。

爲了避免配置主機互信過程中的交互式詢問,這裏使用ssh-keyscan工具添加主機認證信息以及sshpass工具(安裝Ansible時會自動安裝sshpass,也可以yum -y install sshpass安裝)直接指定ssh連接密碼。

  1. 在control_node節點上生成密鑰對:

    $ ssh-keygen -t rsa -f ~/.ssh/id_rsa -N ''
    
  2. 將各節點的主機信息(host key)寫入control_node的~/.ssh/known_hosts文件:

    for host in 192.168.200.{27..33} node{1..7};do
      ssh-keyscan $host >>~/.ssh/known_hosts 2>/dev/null
    done
    
  3. 將control_node上的ssh公鑰分發給各節點:

    # sshpass -p選項指定的是密碼
    for host in 192.168.200.{27..33} node{1..7};do
      sshpass -p'123456' ssh-copy-id root@$host &>/dev/null
    done
    

配置好ssh的主機互信之後,就可以開始體驗Ansible了。

2.2 Ansible初體驗

好了,第一個關於模塊的概念就先介紹這麼多,該是體驗一下Ansible是如何執行任務的時候了。

在控制節點上執行:

$ ansible localhost -m copy -a 'src=/etc/passwd dest=/tmp'
localhost | CHANGED => {
    "changed": true, 
    "checksum": "41a051362a32be1ec4266cc64de2c6e4ad06bc73", 
    "dest": "/tmp/passwd", 
    "gid": 0, 
    "group": "root", 
    "md5sum": "f042f8f7c120afd8c54f437944db1108", 
    "mode": "0644", 
    "owner": "root", 
    "size": 1656, 
    "src": "/root/.ansible/tmp/ansible-tmp-1575571772.47-60786643831265/source",
    "state": "file", 
    "uid": 0
}

該命令的作用是拷貝本機的/etc/passwd文件到本機的/tmp目錄下。

其中的ansible是一個命令,這個自不需要多做解釋。除ansible命令外,後面還會用到ansible-playbook命令。

localhost參數表示ansible要控制的節點,即ansible將指揮本機執行任務。

執行任務主要是執行模塊,模塊的執行可以還依賴一些模塊參數。在ansible命令行中,使用-m Module來指定要執行哪個模塊,即執行什麼任務,使用-a ARGS來指定模塊運行時的參數。

本示例中的模塊爲copy模塊,傳遞給copy模塊的參數包含兩項:

  • src=/etc/passwd指定源文件
  • dest=/tmp指定拷貝的目標路徑

初學Ansible,可能會有兩個疑惑:

  1. Ansible的模塊那麼多,我如何知道某個功能要找哪個模塊
  2. 如何知道某個模塊的用法,比如參數有哪些

初學之時,只需學習一些常用的模塊,在本文以及後面的文章中會介紹一些常見模塊的功能以及用法。熟悉了Ansible之後,再按需求到官方手冊中去尋找:https://docs.ansible.com/ansible/latest/modules/modules_by_category.html

有時候爲了方便快速尋找模塊,可以使用ansible-doc -l | grep 'xxx'命令來篩選模塊。例如,想要篩選具有拷貝功能的模塊:

$ ansible-doc -l | grep 'copy'
vsphere_copy          Copy a file to a VMware datastore
win_copy              Copies files to remote locations on windows hosts
bigip_file_copy       Manage files in datastores on a BIG-IP
ec2_ami_copy          copies AMI between AWS regions, return new image id
win_robocopy          Synchronizes the contents of two directories using Robocopy
copy                  Copy files to remote locations
na_ontap_lun_copy     NetApp ONTAP copy LUNs
icx_copy              Transfer files from or to remote Ruckus ICX 7000 series switches
unarchive             Unpacks an archive after (optionally) copying it from the local machine
postgresql_copy       Copy data between a file/program and a PostgreSQL table
ec2_snapshot_copy     copies an EC2 snapshot and returns the new Snapshot ID
nxos_file_copy        Copy a file to a remote NXOS device
netapp_e_volume_copy  NetApp E-Series create volume copy pairs

根據描述,大概找出是否有想要的模塊。

找到模塊後,想要看看它的功能描述以及用法,可以繼續使用ansible-doc命令。

# 詳細的模塊描述手冊
$ ansible-doc copy

# 只包含模塊參數用法的模塊描述手冊
$ ansible-doc -s copy

再來一個示例,通過Ansible刪除本地文件/tmp/passwd。需要使用的模塊是file模塊,file模塊的主要作用是創建或刪除文件/目錄。

$ ansible localhost -m file -a 'path=/tmp/passwd state=absent'

參數path=指定要操作的文件路徑,state=參數指定執行何種操作,此處指定爲absent表示刪除操作。

Ansible的很多模塊都提供了一個state參數,它是一個非常重要的參數。它的值一般都會包含present和absent兩種狀態值(並非一定),不同模塊的present和absent狀態表示的含義不同,但通常來說,present狀態表示肯定、存在、會、成功等含義,absent則相反,表示否定、不存在、不會、失敗等含義。

例如這裏的file模塊,absent狀態表示遞歸刪除文件/目錄,類似於rm -r命令,touch狀態和touch命令的功能一樣,directory狀態表示遞歸創建目錄,類似於mkdir -p命令。

所以,在本地創建文件、創建目錄的命令如下:

# 創建文件
$ ansible localhost -m file -a 'path=/tmp/a.log state=touch'

# 創建目錄
$ ansible localhost -m file -a 'path=/tmp/dir1/dir2 state=directory'

例如,輸出"hello world",需要使用msg參數:

$ ansible localhost -m debug -a 'msg="hello world"'
localhost | SUCCESS => {
    "msg": "hello world"
}

Ansible中也支持使用變量,這裏僅演示最簡單的設置變量和引用變量的方式。ansible命令的-e選項或--extra-vars選項可以設置變量,設置的方式爲-e 'var1="aaa" var2="bbb"'

例如,設置變量後使用debug的msg參數輸出:

$ ansible localhost -e 'str=world' -m debug -a 'msg="hello {{str}}"'
localhost | SUCCESS => {
    "msg": "hello world"
}

注意上面示例中的{% raw %} msg="hello {{str}}" {% endraw %},Ansible的字符串是可以不用引號去包圍的,例如msg=hello是允許的,但如果字符串中包含了特殊符號,則可能需要使用引號去包圍,例如此處的示例出現了會產生歧義的空格。此外,要區分變量名和普通的字符串,需要在變量名上加一點標註:用{% raw %} {{}} {% endraw %}包圍Ansible的變量,這其實是Jinja2模板(如果不知道,先別管這是什麼)的語法。其實不難理解,它的用法和Shell下引用變量使用$符號或${}是一樣的,例如echo "hello ${var}"

debug模塊除了msg參數,還有一個var參數,它只能用來輸出變量(還包括以後要介紹的Jinja2表達式),而且var參數引用變量的時候,不能使用{% raw %} {{}} {% endraw %}包圍,因爲var參數已經隱式地包圍了一層{% raw %} {{}} {% endraw %}。例如:

$ ansible localhost -e 'str="hello world"' -m debug -a 'var=str'
localhost | SUCCESS => {
    "str": "hello world"
}

體驗完Ansible模塊的基本用法後,下面將簡單說說Ansible中的配置文件。

2.3 Ansible配置文件

通過操作系統自帶的包管理器(比如yum、dnf、apt)安裝的Ansible一般都會提供好Ansible的配置文件/etc/ansible/ansible.cfg。

這是Ansible默認的全局配置文件。實際上,Ansible支持4種方式指定配置文件,它們的解析順序從上到下:

  • ANSIBLE_CFG: 環境變量指定的配置文件
  • ansible.cfg: 當前目錄下的ansible.cfg
  • ~/.ansible.cfg: 家目錄下的ansible.cfg
  • /etc/ansible/ansible.cfg:默認的全局配置文件

Ansible配置文件採用ini風格進行配置,每一項配置都使用key=value的方式進行配置。

例如,下面是我從默認的/etc/ansible/ansible.cfg中截取的[defaults]段落和[inventory]段落的部分配置信息。

[defaults]
# some basic default values...
#inventory      = /etc/ansible/hosts
#library        = /usr/share/my_modules/
#module_utils   = /usr/share/my_module_utils/
#remote_tmp     = ~/.ansible/tmp
#local_tmp      = ~/.ansible/tmp
#plugin_filters_cfg = /etc/ansible/plugin_filters.yml
#forks          = 5

[inventory]
#enable_plugins = host_list, virtualbox, yaml, constructed
#ignore_extensions = .pyc, .pyo, .swp, .bak, ~, .rpm, .md, .txt, ~, .orig, .ini, .cfg, .retry
#ignore_patterns=
#unparsed_is_failed=False

目前沒必要去了解配置文件裏的每項指令的含義,在後面需要的時候,我會介紹涉及到的相關配置項的含義。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章