運維自動化之ansible的安裝與使用html
隨着服務器數量的增加,咱們須要一個批量工具去提升工做效率,以前用的是puppet,ansible的簡單,適用讓我眼前一亮,決定寫一篇ansible從安裝到基本配置的文檔供新手參閱。python
1、安裝
1.安裝第三方epel源
centos 6的epel
[root@ansible ~]# wget http://dl.fedoraproject.org/pub/epel/6/x86_64/epel-release-6-8.noarch.rpm
[root@ansible ~]# rpm -ivh epel-release-6-8.noarch.rpm
centos5版本的安裝5的epel(不詳細解釋)
mysql
2.安裝ansible
[root@ansible ~]# yum install ansible -y
[root@ansible ~]# ll /etc/ansible
-rw-r--r-- 1 root root 8625 Oct 11 18:06 ansible.cfg
-rw-r--r-- 1 root root 1046 Oct 11 18:06 hosts
ansibles.cfg是配置文件,hosts是管理主機信息
建議密鑰認證
[root@ansible ~]# ssh-keygen (直接回車便可)
推送公鑰
[root@ansible ~]# for i in {1..4}; do ssh-copy-id -i 192.168.78.1$i; done
[root@ansible ~]# cat /etc/ansible/hosts
...
[web]
192.168.78.11
192.168.78.12
[mysql]
192.168.78.13
192.168.78.14
...
組名以及ip根本本身需求定義
linux
3.定義變量
1)定義主機變量
[root@ansible ansible]# cat hosts
...
[web]
192.168.78.11 http_port=80
192.168.78.12 http_port=303
...
**主機指定變量,以便後面供palybooks配置使用。定義兩臺web服務器的apache參數http_port,可讓兩臺服務器產生的apache配置文件httpd.conf差別化**
2)定義組變量
[root@ansible ansible]# cat hosts
...
[web]
192.168.78.11
192.168.78.12
[web:vars]
http_port=80
**組變量的做用域是覆蓋組全部成員,經過定義一個新塊,塊名由組名+ ":vars"組成。**
3)嵌套組
[root@ansible ~]# cat /etc/ansible/hosts
...
[web]
192.168.78.11
192.168.78.12
[mysql]
192.168.78.13
192.168.78.14
[nested:children]
web
mysql
[nested:vars]
ntp_server=s1b.time.edu.cn
...
**嵌套組定義一個新塊,塊名由組名+":chilren"組成。同是嵌套組也能夠定義組變量,做用域是嵌套組裏的全部組
嵌套組只能在/usr/bin/ansible-playbook中,在/usr/bin/ansible中不起做用,下面會介紹playbook**
4)分離主機與組特定數據
**爲了更好的規範定義的主機與組變量,咱們實際是不會在hosts裏直接寫的,將定義的主機名與組變量單獨剝離出來放到指定的文件中,將採用YAML格式存放,存放位置規定:"/etc/ansible/group\_vars/+組名"和"/etc/ansible/host\_vars/+主機名"分別存放指定組名或主機名定義的變量,以下:**
**注意目錄結構,規範目錄名**
[root@ansible host_vars]# cat 192.168.78.11.yml
---
http_port: 80git
[root@ansible group_vars]# cat mysql.yml
---
ntp_server: s1b.time.edu.cn
database_server: 192.168.78.14
[root@ansible group_vars]# cat web.yml
---
ntp_server: s1b.time.edu.cn
http_prot: 80
**能夠直接調用變量,規範目錄名的緣由是ansible會自動加載這幾個目錄下的變量,若是變量不放到這幾個目錄下,是不能調用的,咱們會在後面介紹到不放到特定目錄下,playbook如何調用這些變量**
2、命令參數web
Usage: ansible <host-pattern> [options]
Options:
-m MODULE\_NAME, --module-name=MODULE\_NAME 要執行的模塊,默認爲 command
-a MODULE_ARGS, --args=MODULE_ARGS 模塊的參數
-u REMOTE_USER, --user=REMOTE_USER ssh 鏈接的用戶名,默認用 root,ansible.cfg 中能夠配置
-k, --ask-pass 提示輸入 ssh 登陸密碼,當使用密碼驗證登陸的時候用
-s, --sudo sudo 運行
-U SUDO_USER, --sudo-user=SUDO_USER sudo 到哪一個用戶,默認爲 root
-K, --ask-sudo-pass 提示輸入 sudo 密碼,當不是 NOPASSWD 模式時使用
-B SECONDS, --background=SECONDS run asynchronously, failing after X seconds(default=N/A)
-P POLL_INTERVAL, --poll=POLL_INTERVAL set the poll interval if using
-B (default=15)
-C, --check 只是測試一下會改變什麼內容,不會真正去執行
-c CONNECTION 鏈接類型(default=smart)
-f FORKS, --forks=FORKS fork 多少個進程併發處理,默認 5
-i INVENTORY, --inventory-file=INVENTORY 指定 hosts 文件路徑,默認 default =/etc/ansible/hosts
-l SUBSET, --limit=SUBSET 指定一個 pattern,對<host_pattern>已經匹配的主機中再過濾一次
--list-hosts 只打印有哪些主機會執行這個 playbook 文件:不是實際執行該 playbook
-M MODULE_PATH, --module-path=MODULE_PATH 要執行的模塊的路徑,默認爲/usr/share/ansible/
-o, --one-line 壓縮輸出,摘要輸出
--private-key=PRIVATE_KEY_FILE 私鑰路徑
-T TIMEOUT, --timeout=TIMEOUT ssh 鏈接超時時間,默認 10 秒
-t TREE, --tree=TREE 日誌輸出到該目錄,日誌文件名會以主機名命名
-v, --verbose verbose mode (-vvv for more, -vvvv to enable connection debugging)
1)以 xb 身份 ping 全部主機
ansible all -m ping -u xb
2)用 xb 用戶以 root 身份 ping
ansible all -m ping -u xb --sudo
3)用 xb 用戶 sudo 到 bx 用戶 ping
ansible all -m ping -u xb --sudo --sudo-user bx
3、經常使用模塊
copy模塊:
目的:把主控端/root目錄下的a.sh文件拷貝到到指定節點上
命令:ansible 10.1.1.113 -m copy -a ‘src=/root/a.sh dest=/tmp/ owner=root group=root mode=0755‘
file模塊:
目的:更改指定節點上/tmp/t.sh的權限爲755,屬主和屬組爲root
命令:ansible all -m file -a "dest=/tmp/t.sh mode=755 owner=root group=root"
cron模塊:
目的:在指定節點上定義一個計劃任務,每隔3分鐘到主控端更新一次時間
命令:ansible all -m cron -a ‘name="custom job" minute=\*/3 hour=\* day=\* month=\* weekday=\* job="/usr/sbin/ntpdate 172.16.254.139"‘
group模塊:sql
目的:在全部節點上建立一個組名爲nolinux,gid爲2014的組
命令:ansible all -m group -a ‘gid=2014 name=nolinux‘
user模塊:
目的:在指定節點上建立一個用戶名爲nolinux,組爲nolinux的用戶
命令:ansible 10.1.1.113 -m user -a ‘name=nolinux groups=nolinux state=present‘
刪除用戶
命令:ansible 10.1.1.113 -m user -a ‘name=nolinux state=absent remove=yes‘
yum模塊:
目的:在指定節點上安裝 apache 服務
命令:ansible all -m yum -a "state=present name=httpd"
state=latest=>>安裝最新版本
service模塊:
目的:啓動指定節點上的 httpd 服務,並讓其開機自啓動
命令:ansible 10.1.1.113 -m service -a ‘name=httpd state=restarted enabled=yes‘
script模塊:
目的:在指定節點上執行/root/a.sh腳本(該腳本是在ansible主控端)
命令:ansible 10.1.1.113 -m script -a ‘/root/a.sh‘
ping模塊:
目的:檢查指定節點機器是否還能連通
命令:ansible 10.1.1.113 -m ping
command模塊:
目的:在指定節點上運行hostname命令
命令:ansible 10.1.1.113 -m command -a ‘hostname‘
raw模塊:
目的:在10.1.1.113節點上運行ifconfig命令
命令:ansible 10.1.1.113 -m raw-a ‘ifconfig|eth0‘
get_url模塊:shell
目的:將http://10.1.1.116/favicon.ico文件下載到指定節點的/tmp目錄下
命令:ansible 10.1.1.113 -m get_url -a ‘url=http://10.1.1.116/favicon.ico dest=/tmp‘
stat模塊:
目的:獲取遠程文件狀態信息,包括atime、ctime、mtime、md五、uid、gid等信息
ansible web -m stat -a ‘path=/etc/sysctl.conf‘
synchronize模塊:
目的:將主控方/root/a目錄推送到指定節點的/tmp目錄下
命令:ansible 10.1.1.113 -m synchronize -a ‘src=/root/a dest=/tmp/ compress=yes‘
執行效果:
delete=yes 使兩邊的內容同樣(即以推送方爲主)
compress=yes 開啓壓縮,默認爲開啓
--exclude=.git 忽略同步.git結尾的文件
mode=pull 更改推送模式爲拉取模式
目的:將10.1.1.113節點的/tmp/a目錄拉取到主控節點的/root目錄下
命令:ansible 10.1.1.113 -m synchronize -a ‘mode=pull src=/tmp/a dest=/root/‘
須要更多模塊請使用ansible-doc -l查詢
4、playbook配置管理
1.語法說明
- hosts: web #定義操做的對象,能夠是主機或組
vars: #這個是變量
http_port: 80
max_clients: 200
remote_user: root #遠端的執行權限,能夠理解爲遠程操做的用戶名
#任務列表,playbook將按定義的配置文件自上而下的執行,定義的主機都將獲得相同的任務,但執行的結果不必定保持一致,
取決於主機的環境及程序包狀態。建議每一個任務都要定義一個name標籤,加強可讀性,也便於觀察結果輸出時瞭解運行的位置。
tasks:
- name: ensure apache is at the latest version
yum: pkg=httpd state=latest #利用yum模塊來操做
- name: write the apache
template: src=/srv/httpd.j2 dest=/etc/httpd.conf
#觸發重啓服務器
notify:
- restart apache
- name: ensure apache is running
service: name=httpd state=started
#這裏的restart apache 和上面的觸發是配對的。這就是handlers的做用。至關於tag
handlers:
- name: restart apache
service: name=httpd state=restarted
#### 若是作了相關sudo限制,須要在playbook裏面開啓sudo ####
- hosts: web
remote_user: xiaobi
tasks:
- service: name=httpd state=started
sudo: yes
### 2.playbook實例 ###
**建立一個xiaobi的用戶,裏面引用了一個user的變量,用jinja2模板給賦值進去了。**
[root@ansible ansible]# cat user.yml
- name: create user
hosts: web
user: root
gather_facts: false
vars:
- user: "xiaobi"
tasks:
- name: create {{ user }}
user: name={{ user }}
**下面多一個service的調用**
[root@ansible ansible]# cat user.yml
- name: create user
hosts: web
user: root
gather_facts: false
vars:
- user: "xiaobi"
tasks
- name: create {{ user }}
user: name={{ user }}
- service: name=httpd state=started
apache
**再加一個copy模塊的調用**
[root@ansible ansible]# cat user.yml
- name: create user
hosts: web
user: root
gather_facts: false
vars:
- user: "xiaobi"
tasks:
- name: create {{ user }}
user: name={{ user }}
- service: name=httpd state=startedc
- name: Copy file to client
copy: src=/tmp/tiger dest=/tmp/tigress
**注意:使用copy傳送文件的時候,有可能會報錯:**
afewbug | FAILED >> {
"checksum": "4ee72f7427050dcd97068734d35ca7b2c651bc88",
"failed": true,
"msg": "Aborting, target uses selinux but python bindings (libselinux-python) aren‘t installed!"
**是由於ansible須要libselinux-python包。(被控端須要安裝libselinux-python**)
**能夠在copy前先調用yum模塊,安裝libselinux-python**
[root@ansible ansible]# cat user.yml
- name: create user
hosts: web
user: root
gather_facts: false
vars:
- user: "xiaobi"
tasks:
- name: create {{ user }}
user: name={{ user }}
- service: name=httpd state=started
- name: ensure libselinux-python is at the latest
yum: pkg=libselinux-python state=latest
- name: Copy file to client
copy: src=/tmp/tiger dest=/tmp/tigress
**template模板複製,支持jinja2,以變量say命名**
[root@ansible ansible]# cat user.yml
- name: create user
hosts: web
remote_user: root
gather_facts: false
vars:
- user: "xiaobi"
- say: "tiger"
tasks:
- name: create {{ user }}
user: name={{ user }}
- service: name=httpd state=started
- name: ensure libselinux-python is at the latest version
yum: pkg=libselinux-python state=latest
- name: Copy file to client
# copy: src=/tmp/tiger dest=/tmp/tigress
template: src=/tmp/tiger dest=/tmp/{{ say }}
**不僅是這樣,還能夠把剛纔的那個say變量傳到文件裏,其實和saltstack是同樣的**
**再加一個執行外部命令的模塊**
[root@ansible ansible]# cat user.yml
- name: create user
hosts: web
remote_user: root
gather_facts: false
vars:
- user: "xiaobi"
- say: "tiger"
tasks:
- name: create {{ user }}
user: name={{ user }}
- service: name=httpd state=started
- name: ensure libselinux-python is at the latest version
yum: pkg=libselinux-python state=latest
- name: Copy file to client
# copy: src=/tmp/tiger dest=/tmp/tigress
template: src=/tmp/tiger dest=/tmp/{{ say }}
- name: run this command and ignore the result
shell: /usr/bin/somecommand || /bin/true
- name: "cmd"
command: touch /tmp/tigress
# - name: "cmd"
# action: command touch /tmp/tigress
**註釋:
1./usr/bin/somecommand:執行某些命令 ||: 前面失敗的話/bin/true:返回true。當你執行一些特定的命令,獲得的結果是你可能沒法預測的,不但願他的結果爲false而中斷,而是繼續執行,這個true就有意義了。相似的判斷還有chenge_when參數
2.老版本的寫法是action: commadn touch 如今基本棄用了,ansible0.8或以上版本能夠直接調用shell,command模塊,結果是同樣的。**
)
**小節總結:已經完成的操做會提示綠色ok,沒有作過的操做會提示黃色changed。shell一類執行是沒有完整的行爲判斷的。只有結果輸出,全部永遠爲changed**
ansible-playbook user.yml -f 10
**ansible在多任務下,推薦使用多進程模式的。其實就是用multiprocess作的多進程池 ! -f 10 就是limit 10個任務併發。
fork默認是5,若是有5個客戶端,那麼這5個是同時執行的;若是是6個,那麼第6個要等前面5個執行完**
### 3.變量功能 ###
1)系統變量
**前言介紹:獲取遠程主機系統信息==>>Facts。
facts是一個很是有用的組件,相似於Saltstack的Grains功能,puppet的facter的功能。實現獲取遠程主機的系統信息,包括主機名、ip地址、操做系統、分區信息、硬件信息等,能夠配合playbook實現更加個性化、靈活的功能需求,好比在httpd.conf模板中引用Facts的主機名信息做爲ServerName參數的值。經過運行ansible web -m setup可獲取Facts信息,下面是一些實例:**
ansible web -m setup
**這裏只展現一部分,能夠獲得不少信息,這些信息是能夠做爲變量引用的**
**如下請看圈起來的地方對比的看就容易明白了**
2)自定義變量
**咱們能夠經過Facts來獲取目標主機的系統信息,當這些信息還不能知足咱們的功能需求時,經過編寫本身定義的的Facts模塊來實現。固然,還有一個更簡單的實現方法,就是經過本地Facts來實現。只需在目標設備/etc/ansible/facts.d目錄定義JSON、INI或可執行文件的JSON輸出,文件擴展名要求使用".fact",這些文件均可以做爲Ansible的本地Facts,看下面例子,在目標主機192.168.78.11定義三個變量,供之後playbook進行引用**
**①!!!注意:此操做是在目標主機,後面會介紹在主控端操做:**
[root@192 ~]# mkdir /etc/ansible/facts.d -p
[root@192 ~]# cd /etc/ansible/facts.d
[root@192 facts.d]# vim icsoc.fact
[general]
apple=1
banana=2
orange=3
**在主控端運行ansibles 192.168.78.11 -m setup -a ‘filter=ansible\_local‘**
**注意返回JSON的層次結構,icsoc(文件名前綴)→general(INI的節名)→key:value(INI的鍵與值),如今咱們就能夠在咱們的模板或playook中經過如下方式進行調用:**
**{{ ansible\_local.icsoc.general.apple }}**
**②下面來講一切操做都在主控端進行**
**在主控端建立icsoc\_new.fact文件,以下:(下面會提到爲何以icsoc\_new.fact命名而不能使用icsoc-new.fact命名緣由)**
[root@ansible ansible]# cat /etc/ansible/icsoc_new.fact
[general]
apple=11
banana=22
orange=33
**在user.yml中加入建立目錄,以及把主控端的icsoc_new.fact推送到目標主機**
[root@ansible ansible]# cat user.yml
- name: create user
hosts: web
remote_user: root
gather_facts: true
vars:
- user: "xiaobi"
- say: "tiger"
tasks:
- name: create {{ user }}
user: name={{ user }}
- service: name=httpd state=started
- name: ensure libselinux-python is ata the latest version
yum: pkg=libselinux-python state=latest
- name: Copy file to client
# copy: src=/tmp/tiger dest=/tmp/tigress
template: src=/tmp/tiger dest=/tmp/{{ say }}
- name: "cmd"
command: touch /tmp/tigree
- name: run this command and ignore the result
shell: /usr/bin/somecommand || /bin/true
- name: "reference facts variable"
template: src=/tmp/bbb dest=/tmp/{{ ansible_default_ipv4.address }}
- name: create directory for ansible custom facts
file: state=directory recurse=yes path=/etc/ansible/facts.d
- name: install custom impi fact
copy: src=/etc/ansible/icsoc_new.fact dest=/etc/ansible/facts.d
- name: re-read facts after adding custom fact
setup: filter=ansible_local
**運行ansible-playbook user.yml截圖太長不截圖了,和上面基本同樣**
此時在目標主機就有了/etc/ansible/facts.d/icsoc\_new.fact文件。
**運行ansible web -m setup -a ‘filter=ansible\_local‘**vim
**注意返回JSON的層次結構,icsoc_new(文件名前綴)→general(INI的節名)→key:value(INI的鍵與值),如今咱們就能夠在咱們的模板或playook中經過如下方式進行調用:**
**{{ ansible\_local.icsoc\_new.general.apple }}**
**!!!注意:變量名的命名規則由字母、數字和下劃線組合而成,變量必須以字母開頭,如:icsoc\_new,icsoc5都是能夠的,icsoc-new和5icsoc是不能夠的,這也是咱們建立本地facts的時候不使用icsoc-new.fact命名的緣由。**
3)註冊變量
**變量的另外一個用途是將一條命令的運行結果保存到變量中,供後面的playbook使用。下面介紹一個簡單的示例:(因爲截圖太長,咱們從新寫一個簡短的user1.yml,方便截圖)**
[root@ansible ansible]# cat user1.yml
- hosts: web
remote_user: root
tasks:
- shell: /usr/bin/foo
register: foo_result
ignore_errors: True
- shell: touch /tmp/kkkk
when: foo_result.rc == 5
**上述示例註釋:
1.註冊了一個foo\_resul變量,變量值爲shell: /usr/bin/foo的運行結果;
2.ignore\_errors: True爲忽略錯誤
3.當變量註冊完成後,就能夠在後面的playbook中使用了
4.當條件語句when: foo\_result.rc == 5成立時,shell: touch /tmp/kkkk命令纔會執行
5.foo\_result.rc爲返回/usr/bin/foo的resultcode(返回碼)返回"rc=0"的返回碼**
**因爲/usr/bin/foo的運行結果返回碼是127,因此shell: touch /tmp/kkkk命令沒有執行,這裏顯示跳過了。下面咱們再修改一下user1.yml把when: foo\_result.rc == 5改成127,再測試一下**
[root@ansible ansible]# cat user1.yml
- hosts: web
remote_user: root
tasks:
- shell: /usr/bin/foo
register: foo_result
ignore_errors: True
- shell: touch /tmp/kkkk
when: foo_result.rc == 127
### 4.語句 ###
####1)條件語句####
**前言:
1.有時候一個playbook的結果取決於一個變量,或者取決於上一個任務(task)的執行結果值,在某些狀況下,一個變量的值能夠依賴於其餘變量的值,固然也會影響ansible的執行過程
2.有時候咱們想跳過某些主機的執行步驟,好比符合特定版本的操做系統將不安裝某個軟件包,或者磁盤空間滿了將進行清理的步驟。
3.這些在ansible中很容易作到,經過when實現,其中將引用jinja2表達式。**
[root@ansible ansible]# cat when.yml
- name: when
hosts: web
remote_user: root
gather_facts: true
tasks:
- name: "shutdown Debian flavored systems"
command: /sbin/shutdown -t now
when: ansible_os_family == "Debian"
**經過變量ansible_os_family == "Debian"(操做系統版本名稱)是否爲Debian,結果將返回BOOL類型值,爲True時將執行上一條語句command: /sbin/shutdown -t now,爲False時該條語句都不會觸發。**
**下面再寫一個經過判斷一條命令執行結果作不一樣分支的二級處理**
[root@ansible ansible]# cat when1.yml
- name: when
hosts: web
remote_user: root
gather_facts: true
tasks:
- command: /sbin/ip a
register: result
ignore_errors: True
- command: /bin/something
when: result|failed
- command: /bin/something_else
when: result|success
- command: /bin/still/something_else
when: result|skipped
**"when: result|success"的意思爲當變量result執行結果爲成功狀態是,將執行/bin/something_else命令,其餘同理。其中success爲Ansible內部過濾器方法,返回True表明命令運行成功。**
#### 2)循環語句 ####
[root@ansible ansible]# cat wheel.yml
- name: whell
hosts: web
remote_user: root
gather_facts: true
tasks:
- name: "Batch add user"
user: name={{ item }} state=present groups=wheel
with_items:
- tiger1
- tiger2
**以上示例是批量建立系統用戶的功能。with\_items會自動循環執行上面的語句"user: name={{ item }} state=present groups=wheel",循環的次數爲with\_items的元素個數。這裏有2個元素,分別爲tiger一、tiger2,會分別替換{{ item }}項,這個示例與下面的示例是等價的:**
[root@ansible ansible]# cat wheel.yml
- name: whell
hosts: web
remote_user: root
gather_facts: true
tasks:
- name: "add user tiger1"
user: name=tiger1 state=present groups=wheel
- name: "add user tiger2"
user: name=tiger2 state=present groups=wheel
**元素也支持字典的形式,以下:**
[root@ansible ansible]# cat wheel.yml
- name: whell
hosts: web
remote_user: root
gather_facts: true
tasks:
- name: "Batch add user"
user: name={{ item.name }} state=present groups={{ item.groups }}
with_items:
- { name: ‘tiger1‘,groups: ‘wheel‘ }
- { name: ‘tiger2‘,groups: ‘root‘ }
**循環也支持列表(list)的形式,不過是經過with_flattened語句來實現的,以下:**
[root@ansible ansible]# cat /etc/ansible/123.yml
packages_base:
- [ ‘vsftpd‘, ‘vim‘ ]
packages_apps:
- [[ ‘mysql‘, ‘httpd‘ ]]
**以上定義了兩個列表變量,分別是須要安裝的軟件包名,以便後面進行引用,以下:**
[root@ansible ansible]# cat /etc/ansible/wheel1.yml
- name: whell
hosts: web
vars_files: #以前說的在特定的目錄下定義變量文件,能夠自動加載。若是在自定義路徑,咱們須要這裏指明具體路徑
- /etc/ansible/123.yml
remote_user: root
gather_facts: true
tasks:
- name: "Batch install rpms"
yum: name={{ item }} state=installed
with_flattened: #經過使用with_flattened語句循環引用定義好的列表變量
- packages_base
- packages_apps
**經過使用with_flattened語句循環引用定義好的列表變量**
### 5.handlers與include ###
**當多個playbook涉及複用的任務列表時,能夠將複用的內容剝離出來,寫到獨立的文件裏,須要的地方include進來便可**
**除了tasks以外,還有一個handlers的命令,handlers是在執行tasks以後服務器發生變化以後可供調用的handler,以下所示:**
[root@ansible ansible]# cat httpd.yml
- name: write the httpd config file
hosts: web
remote_user: root
gather_facts: true
tasks:
- name: write the httpd.conf to client
template: src=/httpd.conf.j2 dest=/etc/httpd/conf/httpd.conf
notify: # 若是copy執行完以後/etc/httpd/conf/httpd.conf文件發送了變化,則執行
- restart httpd # 調用handler
- include: playbook/tasks/httpd.yml
handlers:
- name: restart httpd #此處的標識必須和notify同樣才能夠引發觸發
service: name=httpd state=restarted
**注意上面使用的- include: playbook/tasks/httpd.yml,看一下這個文件的內容,**
[root@ansible ansible]# cat playbook/tasks/httpd.yml
- name: ensure httpd is running
service: name=httpd state=started
本文出自 「10995114」 博客,請務必保留此出處http://11005114.blog.51cto.com/10995114/1812386
原文地址:http://11005114.blog.51cto.com/10995114/1812386