Ansible簡明教程

【空山新雨】發表於2020-04-20

Ansible是當下比較流行的自動化運維工具,可通過SSH協議對遠端伺服器進行集中化的配置管理、應用部署等,常結合Jenkins來實現自動化部署。

除了Ansible,還有像SaltStack、Fabric(曾經管理100多臺伺服器上的應用時也曾受益於它)、Puppet等自動化工具。相比之下,Ansible最大的優勢就是無需在被管理主機端部署任何客戶端代理程式,通過SSH通道就可以進行遠端命令的執行或配置的下發,足夠輕量級,但同時功能非常強大,且各項功能通過模組來實現,具備良好的擴充套件性。不足之處是Ansible只支援在Linux系統上安裝,不支援Windows。

如果你需要在多於一臺伺服器上做相同的操作,那麼建議你使用Ansible之類的自動化工具,這將極大提高你的操作效率。

環境搭建

1.找一臺主機用於做管理伺服器,在其上安裝Ansible

yum -y install ansible

Ansible基於Python實現,一般Linux系統都自帶Python,所以可以直接使用yum安裝或pip安裝。

安裝完後,在/etc/ansible/目錄下生成三個主要的檔案或目錄,

[root@tool-server ~]# ll /etc/ansible/
total 24
-rw-r--r--. 1 root root 19179 Jan 30  2018 ansible.cfg
-rw-r--r--. 1 root root  1136 Apr 17 15:17 hosts
drwxr-xr-x. 2 root root     6 Jan 30  2018 roles
  • ansible.cfg: Ansible的配置檔案
  • hosts:登記被管理的主機
  • roles:角色專案定義目錄,主要用於程式碼複用

2.在/etc/ansible/hosts檔案中新增需要被管理的伺服器節點

[root@tool-server ~]# vim /etc/ansible/hosts
[k8s]
192.168.40.201
192.168.40.202
192.168.40.205
192.168.40.206

[k8s]表示將下面的伺服器節點分到k8s的組中,後面執行命令時可指定針對某個組執行。

3.生成SSH KEY,並copy到被管理節點上,實現免密SSH訪問

在管理節點執行 ssh-keygen 生成SSH KEY,然後copy到各被管理節點上

ssh-copy-id -i ~/.ssh/id_rsa.pub root@192.168.40.201

上面命令將~/.ssh/id_rsa.pub檔案內容新增到被管理節點的/root/.ssh/authorized_keys檔案中,實現管理節點到被管理節點的免密SSH訪問。

4.除錯Ansible

針對k8s伺服器組執行ping,驗證Ansible到各被管理節點的連通性

[root@tool-server ~]# ansible k8s -m ping
192.168.40.201 | SUCCESS => {
    "changed": false,
    "ping": "pong"
}
192.168.40.205 | SUCCESS => {
    "changed": false,
    "ping": "pong"
}
192.168.40.202 | SUCCESS => {
    "changed": false,
    "ping": "pong"
}
192.168.40.206 | SUCCESS => {
    "changed": false,
    "ping": "pong"
}

Ansible只需要在管理主機上安裝,然後打通管理主機到各被管理主機的SSH免密訪問即可進行集中化的管理控制,不需在被管理主機安裝任何代理程式。

Ansible命令

Ansible的命令格式為, ansible 主機群組名 -m 命令模組名 -a "批量執行的操作"

其中-m不是必須的,預設為command模組,-a也不是必須的,表示命令模組的引數,比如前面的ping模組就沒有引數。

可以使用 ansible-doc -l 列出所有可用的命令模組, ansible-doc -s 模組名 檢視指定模組的引數資訊

常用命令模組

1.command
command是Ansible的預設模組,不指定-m引數時預設使用command。command可以執行遠端主機許可權範圍內的所有shell命令,但不支援管道操作

# 檢視k8s分組主機記憶體使用情況
ansible k8s -m command -a "free -g"

2.shell
shell基本與command相同,但shell支援管道操作

#shell支援管道操作 |grep Mem
ansible k8s -m shell -a "free -g|grep Mem"

3.script
script就是在遠端主機上執行管理端儲存的shell指令碼檔案,相當於scp+shell

# /root/echo.sh為管理端本地shell指令碼
ansible k8s -m script -a "/root/echo.sh"

4.copy
copy實現管理端到遠端主機的檔案拷貝,相當於scp

#拷貝本地echo.sh檔案到k8s組中遠端主機的/tmp目錄下,所屬使用者、組為 root ,許可權為 0755
ansible k8s -m copy -a "src=/root/echo.sh dest=/tmp/ owner=root group=root mode=0755"

5.yum
軟體包安裝或刪除

ansible k8s -m yum -a "name=wget state=latest"

其中state有如下取值:

  • 針對安裝,可取值“present,installed,latest”,present,installed即普通安裝,兩者無區別,latest是使用yum mirror上最新的版本進行安裝
  • 針對刪除,可取值“absent,removed”,兩者無差別

6.service
對遠端主機的服務進行管理

ansible k8s -m service -a "name=nginx state=stoped"

state可取值“started/stopped/restarted/reloaded”。

7.get_url
在遠端主機上下載指定URL到本地

ansible k8s -m get_url -a "url=http://www.baidu.com dest=/tmp/index.html mode=0440 force=yes"

8.setup
獲取遠端主機的資訊

ansible k8s -m setup

9.file
管理遠端主機的檔案或目錄

ansible k8s -m file -a "dest=/opt/test state=touch"

state可取值

  • directory:建立目錄
  • file:如果檔案不存在,則建立
  • link:建立symbolic link
  • absent:刪除檔案或目錄
  • touch: 建立一個不存在的空檔案

10.cron
管理遠端主機的crontab定時任務

ansible k8s -m cron -a "name='backup servcie' minute=*/5 job='/usr/sbin/ntpdate  time.nist.gov >/dev/null 2>&1'"

支援的引數

  • state: 取值present表示建立定時任務,absent表示刪除定時任務
  • disabled: yes表示註釋掉定時任務,no表示接觸註釋

Ansible playbook

Ansible的playbook由一個或多個play組成,play的功能就是為歸為一組的主機編排要執行的一系列task,其中每一個task就是呼叫Ansible的一個命令模組。

playbook的核心元素包括:

  • hosts:執行任務的遠端主機組或列表
  • tasks:要執行的任務列表
  • variables:內建變數或自定義的變數
  • templates:使用模板語法的檔案,通常為配置檔案
  • handlers:和notify結合使用,由特定條件觸發,一般用於配置檔案變更觸發服務重啟
  • tags:標籤,可在執行時通過標籤指定執行playbook中的部分任務
  • roles:

playbook檔案遵循yaml的語法格式,執行命令的格式為 ansible-playbook <filename.yml> ... [options], 常用options包括

  • --syntax 檢查playbook檔案語法是否正確
  • --check 或 -C 只檢測可能會發生的改變,但不真正執行操作
  • --list-hosts 列出執行任務的主機
  • --list-tags 列出playbook檔案中定義所有的tags
  • --list-tasks 列出playbook檔案中定義的所有任務集
  • --limit 只針對主機列表中的某個主機或者某個組執行
  • -f 指定併發數,預設為5個
  • -t 指定某個或多個tags執行(前提playbook中有定義tags)
  • -v 顯示過程 -vv -vvv更詳細

下面以批量安裝Nginx為例,儘可能介紹playbook各核心元素的用法。

定義palybook yaml檔案nginx_playbook.yml

---
- hosts: 192.168.40.201,192.168.40.205 # 主機列表,也可以是/etc/ansible/hosts中定義的主機分組名
  remote_user: root # 遠端使用者
  vars:             # 自定義變數
     version: 1.16.1
  vars_files:
     - ./templates/nginx_locations_vars.yml


  tasks:
     - name: install dependencies          # 定義任務的名稱
       yum: name={{item}} state=installed  # 呼叫模組,具體要做的事情,這裡使用with_items迭代多個yum任務安裝必要的依賴
       with_items:
          - gcc
          - gcc-c++
          - pcre
          - pcre-devel
          - zlib
          - zlib-devel
          - openssl
          - openssl-devel
     - name: download nginx                # 通過get_url模組下載nginx
       get_url: url=http://nginx.org/download/nginx-{{version}}.tar.gz dest=/tmp/ mode=0755 force=no
     - name: unarchive                     # 通過unarchive模組解壓nginx
       unarchive: src=/tmp/nginx-{{version}}.tar.gz dest=/tmp/ mode=0755 copy=no
     - name: configure,make and install    # 通過shell模組執行shell命令編譯安裝
       shell: cd /tmp/nginx-{{version}} && ./configure --prefix=/usr/local/nginx && make && make install
     - name: start nginx                   # 通過shell模組執行shell命令啟動nginx
       shell: /usr/local/nginx/sbin/nginx
     - name: update config                 # 通過template模組動態生成配置檔案下發到遠端主機目錄
       template: src=nginx.conf.j2 dest=/usr/local/nginx/conf/nginx.conf
       notify: reload nginx                # 在結束時觸發一個操作,具體操作通過handlers來定義
       tags: reload                        # 對任務定義一個標籤,執行時通過-t執行帶指定標籤的任務

  handlers:
     - name: reload nginx                  # 與notify定義的內容對應
       shell: /usr/local/nginx/sbin/nginx -s reload

1. 變數

在上面的示例中使用vars定義了變數version,在tasks中通過{{version}}進行引用。Ansible支援如下幾種定義變數的方式

1.在playbook檔案中定義
前面示例已經說明

2.命令列指定
在執行playbook時通過-e指定,如ansible-playbook -e "version=1.17.9" nginx_playbook.yml, 這裡指定的變數將覆蓋playbook中定義的同名變數的值

3.hosts檔案中定義變數
在/etc/ansible/hosts檔案中也可以定義針對單個主機或主機組的變數,如

[nginx]
192.168.40.201 version=1.17.9 # 定義單個主機的變數
192.168.40.205 
[nginx:vars]  # 定義整個組的統一變數
version=1.16.1

4.在獨立的yaml檔案中定義變數
專門定義一個yaml變數檔案,然後在playbook檔案中通過var_files引用,如

# 定義存放變數的檔案
[root@ansible ]# cat var.yml
version: 1.16.1

# 編寫playbook
[root@ansible ]# cat nginx_playbook.yml
---
- hosts: nginx
  remote_user: root
  vars_files:     # 引用變數檔案
    - ./var.yml   # 指定變數檔案的path(這裡可以是絕對路徑,也可以是相對路徑)

5.使用setup模組獲取到的變數
前面介紹setup模組可獲取遠端主機的資訊,可在playbook中直接引用setup模組獲取到的屬性,比如系統版本: ansible_distribution_major_version

2. 模板

playbook模板為我們提供了動態的配置服務,使用jinja2語言,支援多種條件判斷、迴圈、邏輯運算、比較操作等。應用場景就是定義一個模板配置檔案,然後在執行的時候動態生成最終的配置檔案下發到遠端主機。一般將模板檔案放在playbook檔案同級的templates目錄下,這樣在playbook檔案中可以直接引用,否則需要通過絕對路徑指定,模板檔案字尾名一般為 .j2。

本例中,我們將nginx.conf配置檔案作為模板檔案,新增需要動態配置的內容,並定義一個變數檔案,通過vars_files引入:vars_files: ./templates/nginx_locations_vars.yml

# 模板檔案
[root@tool-server nginx-deploy]# vim templates/nginx.conf.j2
 ...
 server {
        listen       80;
        server_name  localhost;

        #charset koi8-r;

        #access_log  logs/host.access.log  main;
        # 這裡的內容動態生成
        {% for location in nginx_locations %}
        location {{location.path}} {
           proxy_pass {{location.proxy}};
        }
        {% endfor %}

        location / {
            root   html;
            index  index.html index.htm;
        }
 ...
# 獨立的自定義變數檔案,用於填充模板檔案中的變數
[root@tool-server nginx-deploy]# vim templates/nginx_locations_vars.yml

nginx_locations:
  - {"path": "/cns", "proxy": "http://192.168.40.202/cns"}
  - {"path": "/admin", "proxy": "http://192.168.40.202/admin"}

3. handlers

handlers和notify結合使用,由特定條件觸發,一般用於配置檔案變更觸發服務重啟。在本例中我們在配置檔案變更時,通過notify定義了一個“reload nginx”的操作,然後在handlers部分定義“reload nginx”操作——通過shell模組呼叫nginx的reload來重新載入配置。

4. 標籤

playbook檔案中,如果只想執行某一個或幾個任務,則可以給任務打標籤,在執行的時候通過 -t 選擇帶指定標籤的任務執行,也可以通過 --skip-tags 選擇不帶指定標籤的任務執行。比如在本例中,我們在“update config”的task上加了“reload”的標籤,如果後面再修改配置,我們只需要執行“update config”的task並觸發reload nginx就行了,可以這麼執行playbook

[root@tool-server nginx-deploy]# ansible-playbook -t reload nginx_playbook.yml

5. when

可以在task上新增when表示當某個條件達到了該任務才執行,如

 tasks:
    - name: install nginx
      yum: name=nginx state=installed
    - name: update config for system6
      template: src=nginx.conf.j2 dest=/usr/local/nginx/conf/nginx.conf
      when: ansible_distribution_major_version == "6"   # 判斷系統版本,為6才執行上面的template配置的檔案

6. roles

roles就是將變數、檔案、任務、模板及處理器放置在單獨的目錄中,並可以在playbook中include的一種機制,一般用於主機構建服務的場景中,但也可以是用於構建守護程式等場景。

roles的目錄結構,預設的roles目錄為/etc/ansible/roles

roles:          # 所有的角色專案必須放在roles目錄下
  project:      # 具體的角色專案名稱,比如nginx、tomcat
    files:     # 用來存放由copy或script模組呼叫的檔案
    templates: # 用來存放jinjia2模板,template模組會自動在此目錄中尋找jinjia2模板檔案
    tasks:     # 此目錄應當包含一個main.yml檔案,用於定義此角色的任務列表,此檔案可以使用include包含其它的位於此目錄的task檔案。
      main.yml
    handlers:  # 此目錄應當包含一個main.yml檔案,用於定義此角色中觸發條件時執行的動作
      main.yml
    vars:      # 此目錄應當包含一個main.yml檔案,用於定義此角色用到的變數
      main.yml
    defaults:  # 此目錄應當包含一個main.yml檔案,用於為當前角色設定預設變數
      main.yml
    meta:      # 此目錄應當包含一個main.yml檔案,用於定義此角色的特殊設定及其依賴關係
      main.yml

我們將上面的例子通過roles改造一下

[root@tool-server ~]# cd /etc/ansible/roles/
[root@tool-server roles]# mkdir -p nginx/{tasks,vars,templates,handlers}
...#建立各目錄的mian.yml檔案,並將對應的內容加入檔案中

#最終目錄結構
[root@tool-server roles]# tree  .
.
└── nginx
    ├── handlers
    │   └── main.yml # 上例handlers部分的內容,直接 -name開頭,不需要再加 `handlers:`
    ├── tasks
    │   └── main.yml # tasks部分內容,直接-name開頭,不需要加tasks,可以將各個task拆分為多個檔案,然後在main.yml中通過 `- include: install.yml` 形式的列表引入
    ├── templates
    │   └── main.yml # templates/nginx.conf.j2的內容
    └── vars
        └── main.yml # templates/nginx_locations_vars.yml的內容

5 directories, 4 files

最後,在playbook中通過roles引入,

[root@ansible roles]# vim nginx_playbook.yml
---
- hosts: nginx
  remote_user: root
  roles:
    - role: nginx # 指定角色名稱

roles將playbook的各個部分進行拆分組織,主要用於程式碼複用度較高的場景。

總結

Ansible是功能強大但又很輕量級的自動化運維工具,基於SSH協議批量對遠端主機進行管理,不僅可用於日常的服務維護,也可與Jenkins等CI/CD工具結合實現自動化部署。如果你需要在多於一臺伺服器上做重複又稍顯複雜的操作,那麼建議你使用Ansible,這將極大提高你的操作效率,並且所有操作文件化,更易維護與遷移。

歡迎關注作者公眾號:空山新雨的技術空間
微信公眾號

相關文章