ansible批量管理服務 下
- 2019 年 10 月 3 日
- 筆記
1 ansible-playbook 任務劇本
1.1 劇本文件概念
(1)playbook可以將多個批量操作模組功能整合,完成一件事情。
(2)簡化運維工作複雜度
(3)playbook通過yaml語法識別描述的狀態文件,擴展名是yaml
1.2 劇本文件組成部分
(1)劇本的角色(hosts)定義的是主機資訊
(2)劇本的任務(tasks)定義的是具體任務資訊
(3)一個劇本文件有多個hosts組成,一個hosts可以包含多個tasks任務
1.3 劇本文件優勢特點
(1)實現自動化功能更加全面
(2)可以更好的控制邏輯關係
(3)劇本展現命令語法更直觀
(4)擁有持久反覆執行的特性
1.4 劇本文件編寫規範
(1)縮進特點: 兩個空格表示一個縮進關係
(2)冒號用法: 冒號後面需要有空格 冒號結尾不需要有空格
主機資訊: 172.16.1.41 — key: value (鍵值寫法)
(3)列表用法: 利用短橫線加空格構建列表清單
1.5 劇本執行使用方法
(1)檢查劇本語法:ansible-playbook –syntax-check test.yaml
(2)劇本模擬執行:ansible-playbook -C test.yaml
(3)劇本真實運行:ansible-playbook test.yaml
1.6 劇本編寫擴展功能
(1)劇本變數編寫功能
(2)劇本資訊通知功能
(3)劇本資訊判斷功能
(4)劇本資訊循環功能
(5)劇本編寫忽略錯誤
(6)劇本標籤設置功能
(7)劇本忽略採集功能
(8)劇本資訊觸發功能
1.6.1 劇本變數編寫功能
設置變數方法一: 在劇本執行命令參數中設置變數,命令行最優先
[root@m01 ansible_playbook]#ansible-playbook -e dir=/etc -e file=rsyncd.conf test_變數編寫.yaml
設置變數方法二: 在劇本中設置變數,劇本變數其次優先
[root@m01 ansible_playbook]#vim test_變數編寫.yaml - hosts: 172.16.1.41 vars: dir: /etc file: rsyncd.conf tasks: - name: copy file copy: src={{ dir }}/{{ file }} dest={{ dir }}/ # {{}}調用變數
設置變數方法二: 在主機清單中設置變數,主機清單變數最不優先
[root@m01 ansible_playbook]#vim /etc/ansible/hosts [sersync_server] 172.16.1.31 [sersync_client] 172.16.1.41 [sersync_server:vars] dir=/etc file=rsyncd.conf # 直接給主機組設置變數,這樣主機組內的所有主機都可以調用變數了
1.6.2 劇本資訊通知功能
編輯劇本
[root@m01 ansible_playbook]#vim test_通知功能.yaml - hosts: 172.16.1.41 tasks: - name: boot server service: name=rsyncd state=started - name: check server boot shell: netstat -lntup|grep 873 register: oldboy - debug: msg={{ oldboy.stdout_lines }} # 將shell中命令執行結果通過register註冊給oldboy,oldboy相當於一個變數,{{}}調取oldboy # debug類似echo,輸出資訊 # stdout_lines 將輸出的資訊變得有格式
運行劇本
[root@m01 ansible_playbook]#ansible-playbook test_通知功能.yaml PLAY [172.16.1.41] *********************************************************************************** TASK [Gathering Facts] ******************************************************************************* ok: [172.16.1.41] TASK [boot server] *********************************************************************************** ok: [172.16.1.41] TASK [check server boot] ***************************************************************************** changed: [172.16.1.41] TASK [debug] ***************************************************************************************** ok: [172.16.1.41] => { "msg": [ "tcp 0 0 0.0.0.0:873 0.0.0.0:* LISTEN 3708/rsync ", "tcp6 0 0 :::873 :::* LISTEN 3708/rsync " ] } PLAY RECAP ******************************************************************************************* 172.16.1.41 : ok=4 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
1.6.3 劇本資訊判斷功能
nfs服務客戶端三台主機
centos7 10.0.0.7、centos6 10.0.0.8、centos7 10.0.0.9
此時在批量啟動的時候需要進行判斷,因為centos6,centos7啟動命令不一樣
判斷的格式
- hosts: nfs_client tasks: - name: boot centos7 nfs shell: systemctl start nfs 判斷: 如果是centos7 ??? - name: boot centos6 nfs shell: /etc/init.d/nfs start 判斷: 如果是centos6 ???
setup模組:收集遠程主機資訊
語法:
[root@m01 ansible_playbook]#ansible 172.16.1.41 -m setup -a "filter=ansible_hostname" 172.16.1.41 | SUCCESS => { "ansible_facts": { "ansible_hostname": "backup", "discovered_interpreter_python": "/usr/bin/python" }, "changed": false } # filter 過濾 篩選
實現收集子資訊的方法
問題: 獲取主機資訊,以及子資訊 方法一: - hosts: rsync tasks: - name: touch file file: path=/etc/oldboy01.txt state=touch when: (ansible_eth1.ipv4.address == "172.16.1.41") 方法二: - hosts: rsync tasks: - name: touch file file: path=/etc/oldboy01.txt state=touch when: (ansible_eth1["ipv4"]["address"] == "172.16.1.41")
setup模組常用來收集的資訊
根據 ip 地址進行判斷創建目錄
[root@m01 ansible_playbook]#vim test_判斷功能.yaml - hosts: nfs_client tasks: - name: create file for 41 host file: path=/tmp/172.16.1.41 state=directory when: (ansible_hostname == "backup") - name: create file for 7 host file: path=/tmp/172.16.1.7 state=directory when: (ansible_hostname == "web01")
運行劇本
root@m01 ansible_playbook]#ansible-playbook -C test_判斷功能.yaml PLAY [nfs_client] ************************************************************************************ TASK [Gathering Facts] ******************************************************************************* ok: [172.16.1.41] ok: [172.16.1.7] TASK [create file for 41 host] *********************************************************************** skipping: [172.16.1.7] changed: [172.16.1.41] TASK [create file for 7 host] ************************************************************************ skipping: [172.16.1.41] changed: [172.16.1.7] PLAY RECAP ******************************************************************************************* 172.16.1.41 : ok=2 changed=1 unreachable=0 failed=0 skipped=1 rescued=0 ignored=0 172.16.1.7 : ok=2 changed=1 unreachable=0 failed=0 skipped=1 rescued=0 ignored=0
1.6.4 劇本資訊循環功能
循環創建多個用戶
[root@m01 ansible_playbook]#vim test_循環功能.yaml - hosts: 172.16.1.41 tasks: - name: create user user: name={{ item }} with_items: - oldgirl01 - oldgirl02 - oldgirl03 - oldgirl04 - oldgirl05
循環創建多個用戶 多個用戶uid數值是不同的
[root@m01 ansible_playbook]#vim test_循環功能.yaml - hosts: 172.16.1.41 tasks: - name: create user user: name={{ item.name }} uid={{ item.uid }} with_items: - {name: "oldgirl06", uid: "3006"} - {name: "oldgirl07", uid: "3007"} - {name: "oldgirl08", uid: "3008"} - {name: "oldgirl09", uid: "3009"} - name: check create user info shell: grep oldgirl0 /etc/passwd register: user_info - debug: msg={{ user_info.stdout_lines }}
1.6.5 劇本編寫忽略錯誤功能
忽略功能主要用來調試劇本
[root@m01 ansible_playbook]#vim test_h忽略功能.yaml - hosts: 172.16.1.41 tasks: - name: create rsync user shell: useradd rsync -M -s /sbin/nologin ignore_errors: yes - name: create backup dir shell: mkdir /backup ignore_errors: yes - name: boot server shell: systemctl start rsyncd ignore_errors: yes
在使用shell進行一些操作時,shell產生的結果已經存在時,會導致劇本無法進行下去,因此使用忽略功能可以有效的使劇本進行下去。
1.6.6 劇本標籤設置功能
標籤功能主要用來調試劇本
tags:標籤
[root@m01 ansible_playbook]#vim test_標籤功能.yaml - hosts: 172.16.1.41 tasks: - name: 01:安裝軟體 yum: name=rsync state=installed ignore_errors: yes - name: 02:創建用戶 user: name=rsync create_home=no shell=/sbin/nologin ignore_errors: yes tags: create_user - name: 03:創建目錄 file: path=/backup state=directory
運行劇本
ansible-playbook -t create_user test_標籤功能.yaml --- 執行劇本中標籤任務 ansible-playbook --skip-tags create_user test_標籤功能.yaml --- 跳過指定標籤任務,執行其他任務 ansible-playbook -t create_user,create_dir test_標籤功能.yaml --- 執行多個標籤 # -t=tags
1.6.7 劇本忽略採集功能
[root@m01 ansible_playbook]#vim test_忽略採集.yaml - hosts: 172.16.1.41 gather_facts: no tasks: - name: 01:安裝軟體 yum: name=rsync state=installed ignore_errors: yes - name: 02:創建用戶 user: name=rsync create_home=no shell=/sbin/nologin ignore_errors: yes tags: create_user - name: 03:創建目錄 file: path=/backup state=directory tags: create_dir
當劇本採集大量主機資訊時,可能會變得卡,慢,影響劇本後面的操作執行的效率。所以在這個時候,可以忽略採集功能,提高效率,在hosts下面添加 gather_facts: no
如果劇本中有判斷功能,不能使用此參數,因為採集的資訊會與判讀資訊對比
1.6.8 劇本資訊觸發功能
編寫劇本
[root@m01 ansible_playbook]#vim test_觸發功能.yaml - hosts: 172.16.1.41 tasks: - name: 01:傳輸配置文件 copy: src=/etc/ansible/ansible_playbook/rsyncd.conf dest=/etc/ notify: rsync_restart - name: 02:啟動服務程式 service: name=rsyncd state=started handlers: - name: rsync_restart service: name=rsyncd state=restarted
handlers:一般用於配置文件修改時,才會進行觸發功能,對服務進行重啟
notify:傳輸配置文件過來,notify通知rsync_restart這個觸發器。然後handlers會進行重啟服務
說明: 整體任務執行完畢,才會執行觸發功能
1.7 編寫劇本練習題
要求:
(1)在172.16.1.41主機上操作:
①將定時任務服務停止
②創建一個/etc/目錄軟連接 在/opt目錄中生成
③將本地/etc/hosts文件分發給41主機 保存到/tmp目錄中
(2)在172.16.1.31主機上操作:
①將防火牆服務開機自動運行
②將主機上安裝keepalived軟體
實踐:
編寫劇本文件
[root@m01 ansible_playbook]#vim test.yaml - hosts: 172.16.1.41 tasks: - service: name=crond state=stopped - file: src=/etc path=/opt/etc_link state=link - copy: src=/etc/hosts dest=/tmp - hosts: 172.16.1.31 tasks: - service: name=firewalld enabled=yes - yum: name=keepalived state=installed
劇本語法檢查
# 語法檢查劇本文件 [root@m01 ansible_playbook]#ansible-playbook --syntax-check test.yaml playbook: test.yaml
劇本模擬執行
[root@m01 ansible_playbook]#ansible-playbook -C test.yaml PLAY [172.16.1.41] *********************************************************************************** TASK [Gathering Facts] ******************************************************************************* ok: [172.16.1.41] TASK [service] *************************************************************************************** ok: [172.16.1.41] TASK [file] ****************************************************************************************** ok: [172.16.1.41] TASK [copy] ****************************************************************************************** ok: [172.16.1.41] PLAY [172.16.1.31] *********************************************************************************** TASK [Gathering Facts] ******************************************************************************* ok: [172.16.1.31] TASK [service] *************************************************************************************** ok: [172.16.1.31] TASK [yum] ******************************************************************************************* ok: [172.16.1.31] PLAY RECAP ******************************************************************************************* 172.16.1.31 : ok=3 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 172.16.1.41 : ok=4 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
劇本真實執行
[root@m01 ansible_playbook]#ansible-playbook test.yaml PLAY [172.16.1.41] *********************************************************************************** TASK [Gathering Facts] ******************************************************************************* ok: [172.16.1.41] TASK [service] *************************************************************************************** ok: [172.16.1.41] TASK [file] ****************************************************************************************** ok: [172.16.1.41] TASK [copy] ****************************************************************************************** ok: [172.16.1.41] PLAY [172.16.1.31] *********************************************************************************** TASK [Gathering Facts] ******************************************************************************* ok: [172.16.1.31] TASK [service] *************************************************************************************** ok: [172.16.1.31] TASK [yum] ******************************************************************************************* ok: [172.16.1.31] PLAY RECAP ******************************************************************************************* 172.16.1.31 : ok=3 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 172.16.1.41 : ok=4 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
補充:
如果系統中裝有cowsay軟體,在執行命令時,會產生圖案資訊,影響查閱結果,可以關閉。
[root@m01 ansible]#vim ansible.cfg # don't like cows? that's unfortunate. # set to 1 if you don't want cowsay support or export ANSIBLE_NOCOWS=1 # nocows = 1 把# nocows = 1 中的 # 去掉即可。
1.8 ansible劇本實現rsync一鍵化部署
第一個歷程: 按照模組方式,完成服務每個步驟部署
第一步:服務端配置
# 安裝軟體程式 ansible rsync -m yum -a "name=rsync state=installed" # 編寫配置文件:要在批量管理主機上提前寫好,然後推送給服務端 # 在管理端準備好服務配置文件 ansible rsync_server -m copy -a "src=/etc/ansible/conf_file/rsyncd.conf dest=/etc/" # 創建虛擬用戶 ansible rsync_server -m user -a "name=rsync create_home=no shell=/sbin/nologin" # 創建密碼文件 (授權600) ansible rsync_server -m copy -a "content='rsync_backup:oldboy123' dest=/etc/rsync.password mode=600" # 創建備份目錄 (授權 屬主 屬組) ansible rsync_server -m file -a "path=/backup state=directory owner=rsync group=rsync" @ 啟動程式服務 ansible rsync_server -m service -a "name=rsyncd state=started enabled=yes"
第二步:客戶端配置
# 創建密鑰文件 (授權600) ansible rsync_client -m copy -a "content='oldboy123' dest=/etc/rsync.password mode=600" # 批量測試傳輸文件 ansible rsync_client -m shell -a "rsync -avz /etc/hosts [email protected]::backup --password-file=/etc/rsync.password"
第二個歷程: 編寫劇本資訊
[root@m01 ansible_playbook]#vim rsync_auto.yaml - hosts: rsync_server tasks: - name: 01:install rsync yum: name=rsync state=installed - name: 02:copy conf file copy: src=/etc/ansible/conf_file/rsyncd.conf dest=/etc/ - name: 03:create rsync user user: name=rsync create_home=no shell=/sbin/nologin - name: 04:create password file copy: content='rsync_backup:oldboy123' dest=/etc/rsync.password mode=600 - name: 05:create backup dir file: path=/backup state=directory owner=rsync group=rsync - name: 06:boot rsync server service: name=rsyncd state=started enabled=yes - hosts: rsync_client tasks: - name: 01:create password file copy: content='oldboy123' dest=/etc/rsync.password mode=600
恢復環境劇本
[root@m01 ansible_playbook]#vim rsync_backup.yaml - hosts: rsync_server tasks: - name: 01:delete conf file file: path=/etc/rsyncd.conf state=absent - name: 02:delete rsync user user: name=rsync state=absent - name: 03:delete password file file: path=/etc/rsync.password state=absent - name: 04:delete backup dir file: path=/backup/ state=absent - name: 05:boot rsync server service: name=rsyncd state=stopped enabled=no - hosts: rsync_client tasks: - name: 01:delete password file file: path=/etc/rsync.password state=absent
1.9 ansible劇本實現nfs一鍵化部署
第一個歷程: 按照模組方式,完成服務每個步驟部署
服務端配置 01. 安裝部署軟體程式: rpcbind nfs-utile ansible nfs_server -m yum -a "name=rpcbind state=installed" ansible nfs_server -m yum -a "name=nfs-utile state=installed" 02. 編寫配置文件:配置文件要提前寫好 # 批量管理主機寫好的配置文件推送給服務端/etc/ansible-playbook/nfs.conf ansible nfs_server -m copy -a "src=/etc/ansible/ansible_playbook/nfs.conf dest=/etc/exports" 03. 創建共享目錄: ansible nfs_server -m file -a "path=/data/ state=directory owner=nfsnobody group=nfsnobody" 04. 啟動程式服務: ansible nfs_server -m service -a "name=rpcbind state=started enabled=yes" ansible nfs_server -m service -a "name=nfs state=started enabled=yes" 客戶端配置: 01. 安裝部署軟體 ansible nfs_client -m yum -a "name=nfs-utile state=installed" 02. 掛載共享目錄 ansible nfs_client -m mount -a "src=172.16.1.31:/data/ path=/mnt fstype=nfs state=mounted"
第二個歷程編寫劇本:
[root@m01 ansible_playbook]#vim nfs_auto.yaml - hosts: nfs_server tasks: - name: 1:install rpcbind nsf-utils yum: name: - rpcbind - nfs-utils state: installed - name: 2:copy conf file copy: src=/etc/ansible/ansible_playbook/nfs.conf dest=/etc/exports - name: 3:create data dir file: path=/data/ state=directory owner=nfsnobody group=nfsnobody - name: 4:boot server rcbind service: name=rpcbind state=started enabled=yes - name: 4:boot server nfs service: name=nfs state=restarted enabled=yes - hosts: nfs_client tasks: - name: 1:install nfs yum: name=nfs-utils state=installed - name: 2:mount data dir mount: src=172.16.1.31:/data/ path=/mnt fstype=nfs state=mounted
恢復環境劇本
[root@m01 ansible_playbook]#vim nfs_backup.yaml - hosts: nfs_server tasks: - name: 01:install rpcbind nfs-utils yum: name: - rpcbind - nfs-utils state: removed - name: 02:copy conf file shell: echo "" >/etc/exports - name: 03:create data dir file: path=/data/ state=absent - hosts: nfs_client tasks: - name: 01:install nfs yum: name=nfs-utils state=removed - name: 02:mount data dir mount: src=172.16.1.31:/data/ path=/mnt fstype=nfs state=unmounted
優化劇本:
[root@m01 ansible_playbook]#vim nfs_auto.yaml - hosts: nfs_server vars: conf_file: exports data_dir: /data tasks: - name: 01:install nfs rpcbind yum: name: ['nfs-utils', 'rpcbind'] state: installed - name: 02:copy conf file copy: src=/etc/ansible/ansible_playbook/nfs.conf dest=/etc/{{ conf_file }} notify: - nfs_restart - name: 03:create data dir file: path={{ data_dir }} state=directory owner=nfsnobody group=nfsnobody - name: 04:boot server rpcbind service: name={{ item.name }} state={{ item.state }} enabled={{ item.enabled }} with_items: - {name: "rpcbind", state: "started", enabled: "yes"} - {name: "nfs", state: "started", enabled: "yes"} handlers: - name: nfs_restart service: name=nfs state=reloaded - hosts: nfs_client vars: data_dir: /data tasks: - name: 01:install nfs yum: name=nfs-utils state=installed - name: 02:mount data dir mount: src=172.16.1.31:{{ data_dir }} path=/mnt fstype=nfs state=mounted - name: 03:check mount info shell: df -h|grep mnt register: mount_info - debug: msg={{ mount_info.stdout_lines }}
1.10 ansible劇本實現sersync一鍵化部署
第一個歷程: 按照模組方式,完成服務每個步驟部署
配置hosts主機清單 [server_server] 172.16.1.31 [server_client] 172.16.1.41 #安裝rsync ansible backup_server -m yum -a "name=rsync state=installed" #在批量管理主機上下載sersync,解壓發送給客戶端 ansible backup_server -m file -a "src=/usr/local/sersync_installdir_64bit/sersync dest=/usr/local" #在批量管理主機上寫好sersync配置文件,發送給客戶端 ansible backup_server -m copy -a "src=/usr/local/sersync_installdir_64bit/sersync/conf/confxml.xml dest=/usr/local/sersync/conf/" #給sersync加上執行許可權 ansible backup_server -m file -a "path=/usr/local/sersync/bin/sersync mode=a+x" #給sersync創建軟鏈接 ansible backup_server -m file -a "src=/usr/local/sersync/bin/sersync path=/usr/local/sbin/sersync state=link" #啟動sersync 測試實時同步 ansible backup_server -m shell -a "sersync -dro /usr/local/sersync/conf/confxml.xml"
第二個歷程,編寫劇本
[root@m01 ansible_playbook]#vim sersync_auto.yaml - hosts: sersync_server tasks: - name: 安裝rsync yum: name=rsync state=installed - name: 將sersync傳輸到客戶端 file: src=/usr/local/sersync_installdir_64bit/sersync/ dest=/usr/local - name: 將寫好的配置文件傳輸到客戶端 copy: src=/usr/local/sersync_installdir_64bit/sersync/conf/confxml.xml dest=/usr/local/sersync/conf/ - name: 加上執行許可權 file: path=/usr/local/sersync/bin/sersync mode=a+x - name: 創建軟鏈接 file: src=/usr/local/sersync/bin/sersync path=/usr/local/sbin/sersync state=link - name: 啟動sersync 測試實時同步 shell: sersync -dro /usr/local/sersync/conf/confxml.xml
恢復環境劇本
[root@m01 ansible_playbook]#cat sersync_backup.yaml - hosts: sersync_server tasks: - name: 卸載rsync yum: name=rsync state=removed - name: 刪除sersync file: path=/usr/local/sersync
2 多個劇本如何進行整合
第一個歷程: 確保每個劇本執行成功
第二個歷程: 進行劇本整合
方法一:不建議使用
[root@m01 ansible_playbook]#vim zhenghe.yaml # ---角色里使用 - hosts: all remote_user: root tasks: - include_tasks: nfs_auto.yml - include_tasks: rsync_auto.yml # 不寫hosts資訊,只寫任務資訊
方法二:在以後的ansible中可能會取消include功能
[root@m01 ansible_playbook]#vim zhenghe.yaml - include:nfs_auto.yml - include:rsync_auto.yml
方法三:建議使用這個方法
[root@m01 ansible_playbook]#vim zhenghe.yaml - import_playbook: nfs_auto.yaml - import_playbook: rsync_auto.yaml
3 ansible劇本編寫方式:角色
(1)規範ansible程式目錄結構
(2)匯總劇本中有定義的主機資訊
3.1 角色調用流程圖
3.2 nfs服務角色編寫
第一個歷程: 創建角色目錄結構
cd roles/;mkdir {nfs,rsync,web,sersync} cd nfs/{vars,tasks,templates,handlers,files} # vars: 定義變數資訊 # tasks: 定義任務資訊 # templates: 定義模板文件(jinja2模板文件) # handlers: 定義觸發器資訊 # files: 定義需要分發的文件
第二個歷程: 編寫文件資訊
tasks: 任務資訊編寫方式一:
nfs服務編寫
vim main.yaml - name: 01:install nfs rpcbind yum: name: ['nfs-utils', 'rpcbind'] state: installed - name: 02:copy conf file copy: src=/etc/ansible/ansible_playbook/nfs.conf dest=/etc/{{ conf_file }} notify: - nfs_restart - name: 03:create data dir file: path={{ data_dir }} state=directory owner=nfsnobody group=nfsnobody - name: 04:boot server rpcbind service: name={{ item.name }} state={{ item.state }} enabled={{ item.enabled }} with_items: - {name: "rpcbind", state: "started", enabled: "yes"} - {name: "nfs", state: "started", enabled: "yes"} - name: 01:install nfs yum: name=nfs-utils state=installed - name: 02:mount data dir mount: src=172.16.1.31:{{ data_dir }} path=/mnt fstype=nfs state=mounted - name: 03:check mount info shell: df -h|grep mnt register: mount_info - debug: msg={{ mount_info.stdout_lines }}
tasks: 任務資訊編寫方式二:
tasks:定義任務資訊
cd tasks vim main.yaml vim nfs_boot.yaml vim nfs_conf.yaml vim nfs_datadir.yaml vim nfs_install.yaml vim nfs_mount.yaml ######################### vim main.yaml - include_tasks: nfs_install.yaml - include_tasks: nfs_conf.yaml - include_tasks: nfs_datadir.yaml - include_tasks: nfs_boot.yaml - include_tasks: nfs_mount.yaml
vars:定義變數資訊
vim main.yaml conf_file: exports data_dir: /data
files:定義需要分發的文件
[root@m01 files]# ll total 4 -rw-r--r-- 1 root root 42 Jul 29 10:34 nfs.conf
handlers:定義觸發器資訊
vim main.yaml - name: nfs_restart service: name=nfs state=reloaded