一、Playbook简介
1.Playbook是一种简单的配置管理系统与多台机器部署系统的基础,且非常适合
于复杂应用的部署
2.playbook中可以编排有序的执行过程,甚至可以做到在多组机器之间,来回有序的执行特别指定的步骤,并且可以同步或异步的发起任务
3.可以重用代码,可以移植到不同的机器上
4.通过YAML格式来描述定义
二、playbook编写
1.语法
- 文件的第一行应该以“- - -”三个连字符开始,表明YAML文件的开始
- 在同一行中,#之后的内容表示注释,类似于shell,python和ruby
- YAML中的列表元素以“-”开头然后紧跟着一个空格,同一个列表中的元素应该保持相同的缩进(通常是两个空格)
---
#一个美味的水果列表
- apple
- orange
- mango - 一个字典是由一个简单的键: 值的形式组成(这个冒号后面必须是一个空格)
---
#一位职工的记录
name: Example
job: Developer
skill: Elite - 字典也可以使用缩进形式来表示:
---
#一位职工的记录
{name: Example,job: Develop,skill: Elite}
2.Tasks列表
- play的主体部分是task列表,task列表中的各任务按次序逐个在hosts主机执行,即所有主机完成第一个任务后再开始第二个任务。如果一个hosts执行task失败,整个task都会回滚。
- 每一个task必须有一个名称name,这样在运行playbook的时候,从其输出的任务执行信息中可以很好的辨别出属于哪一个task的。
小知识1:针对不同文件设置Tab值不同
vim .vimrc #编写文件,ts空格,sw ,et将tab变成空格
autocmd FileType yaml setlo=cal ai ts=2 sw=2 et #设置为tab两个空格
3.第一个playbook文件
---
- hosts: prod
tasks:
- name: install apache
yum:
name: httpd
state: present
- name: start apache
service:
name: httpd
state: started
- name: create index.html
copy:
content: "www.westos.org"
dest: /var/www/html/index.html
ansible-playbook apache.yml --syntax-check | 检测是否有语法错误 |
ansible-playbook apache.yml --list-hosts | 列出主机 |
ansible-playbook apache.yml --list-tasks | 列出任务 |
ansible-playbook apache.yml | 执行任务 |
4 对第一个文件添加触发器,服务配置文件修改时触发
---
- hosts: prod
tasks:
- name: install apache
yum:
name: httpd
state: present
- name: configure
copy:
src: httpd.conf
dest: /etc/httpd/conf/httpd.conf
mode: 644
notify: restart apache
- name: start apache
service:
name: httpd
state: started
- name: create index.html
copy:
content: "www.westos.org"
dest: /var/www/html/index.html
handlers:
- name: restart apache
service:
name: httpd
state: restarted
[ansible@node1 ~]$ ansible-playbook apache.yml
5 添加防火墙
---
- hosts: prod
tasks:
- name: install apache
yum:
name: httpd
state: present
- name: configure
copy:
src: httpd.conf
dest: /etc/httpd/conf/httpd.conf
mode: 644
notify: restart apache
- name: start apache
service:
name: httpd
state: started
- name: create index.html
copy:
content: "www.westos.org"
dest: /var/www/html/index.html
- name: start firewalld #开启防火墙
service:
name: firewalld
state: started
enabled: yes
- name: custom firewalld #配置防火墙
firewalld:
service: http
permanent: yes
immediate: yes
state: enabled
handlers:
- name: restart apache
service:
name: httpd
state: restarted
node3上查看策略:
[root@node3 html]# netstat -antlupe
node1上测试:成功访问
6 添加标签,按标签执行任务
在5的代码基础上添加
handlers:
- name: restart apache
service:
name: httpd
state: restarte
- hosts: localhost #新添加的按标签执行任务
become: no #不变成超户
tasks:
- name: test apache
uri:
url: http://node3/index.html
return_content: yes
tags: test # 给test apache添加标签
tags: teeest #给整个任务添加标签
三、Playbook中的变量
- 变量的定义及引用
[ansible@node1 ~]$ cat hosts
[test]
node2
[prod]
node3 web=httpd #定义web变量对应的值是httpd
[ansible@node1 ~]$ vim apache.yml
---
- hosts: prod
tasks:
- name: install {{ web }} #名字,括号可以不加''
yum:
name: '{{ web }}' #此处安装模块必须加,不然找不到对应web=httpd
state: present
- name: configure
copy:
src: httpd.conf
dest: /etc/httpd/conf/httpd.conf
mode: 644
notify: restart apache
- name: start apache
service:
name: httpd
state: started
- name: create index.html
copy:
content: "www.westos.org"
dest: /var/www/html/index.html
ingore_error: yes用于在某个任务执行出错时自动忽略,继续执行接下来的操作(一般用于此个任务正确与否不影响接下来的任务)
在hosts文件中故意把变量定义错误: web=http,若没忽略参数,后续task会中段不执行,加上,则忽略此错误,继续执行。
变量也可以在apache.yml文件中定义,优先级高于hosts中定义的
2.预留变量facts查看
[ansible@node1 ~]$ ansible node2 -m setup
当playbook中不引入gather_fact的时候,可以把gather_facts禁掉,不会影响后续执行。
当引用fact变量的时候,facts必须打开,将apache.yml中gather_facts: no删除掉。否则无法识别
:
3.facts变量官方推荐写法
- {{ ansible_facts[“eth0”][“ipv4”][“address”] }}
- {{ ansible_facts.eth0.ipv4.address }}
- {{ ansible_facts[“hostname”] }}
- {{ ansible_facts[[‘dns’][‘nameservers’]] }}
- 禁用facts:
- -hosts: prod
- gather_facts: no
[ansible@node1 ~]$ vim apache.yml #最后添加一个测试
- hosts: all
tasks:
- name: create hostinfo
copy:
content: "{{ ansible_facts['eth0']['ipv4']['address'] }}"
dest: /tmp/hostinfo
tags: fact_info
[ansible@node1 ~]$ ansible-playbook apache.yml -t fact_info
[root@node2 ~]# cat /tmp/hostinfo #node2上查看
172.25.7.132[root@node2 ~]#
4.编写j2文件
[ansible@node1 ~]$ vim hostinfo.j2
主机ip: {{ ansible_facts['eth0']['ipv4']['address'] }}
主机名: {{ ansible_facts['hostname'] }}
dns: {{ ansible_facts['dns']['nameservers'] }}
内存: {{ ansible_facts['memfree_mb'] }}
[ansible@node1 ~]$ vim apache.yml
- hosts: all
tasks:
- name: create hostinfo
template:
src: hostinfo.j2
dest: /tmp/hostinfo
tags: fact_info
[ansible@node1 ~]$ ansible-playbook apache.yml -t fact_info #从标签fact_info开始执行
[root@node2 ~]# cat /tmp/hostinfo #node2上查看
主机ip: 172.25.7.132
主机名: node2
dns: [u'114.114.114.114']
内存: 677
[root@node3 ~]# cat /tmp/hostinfo #nod3上查看
主机ip: 172.25.7.133
主机名: node3
dns: [u'114.114.114.114']
内存: 716
5.编写j2文件。针对主机的不同分别改配置文件,以apache为例
[ansible@node1 ~]$ vim httpd.conf.j2
[ansible@node1 ~]$ vim apache.yml
[ansible@node1 ~]$ ansible-playbook apache.yml -t appache
[ansible@node1 ~]$ curl node2 #测试一下
node2
[ansible@node1 ~]$ curl node3
node3
[ansible@node1 ~]$ cat hosts #组信息
[test]
node2
[prod]
node3 web=http
[webserver:children]
test
prod
[webserver:vars]
http_port=80
在node2和node3上看配置文件,查看已更改。
6.registry注册变量,debug调试输出
- hosts: localhost
become: no
tasks:
- name: test apache
uri:
url: http://node3/index.html
return_content: yes
register: result #注册变量
- debug:
var: result
#var: result.content #去掉注释,只显示
#msg: this a message #印制信息
#msg: '{{ result.content }}'
tags: teeest
7.使用loop创建多个用户
[ansible@node1 ~]$ vim apache.yml
- hosts: test
#vars:
# u: user1
#pd: westos
tasks:
- name: create user
user:
name: '{{ item.user }}'
password: '{{ item.pd|password_hash("sha512") }}'
loop:
- { user: user01,pd: westos }
- { user: user02,pd: redhat }
tags: usercreate
[ansible@node1 ~]$ ansible-playbook apache.yml -t usercreate #执行
node2上检验有无:
[root@node2 ~]# cat /etc/passwd
用户可以创建成功,但是此法将密码裸露在文件中,不安全。
为了安全起见,将要创建的用户写入文件中
[ansible@node1 ~]$ cat vars/userlist.yml
---
userlist:
- user: yy1
pd: westos
- user: yy2
pd: redhat
- user: yy3
pd: redhat
[ansible@node1 ~]$ vim apache.yml
- hosts: test
vars_files:
- vars/userlist.yml
tasks:
- name: create user
user:
name: '{{ item.user }}'
password: '{{ item.pd|password_hash("sha512") }}'
loop: "{{ userlist }}"
tags: usercreate
[ansible@node1 ~]$ ansible-playbook apache.yml -t usercreate
node2上查看:
[root@node2 ~]# cat /etc/passwd
8. 魔术变量
[ansible@node1 ~]$ cat test.j2
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
{% for host in groups['webserver'] %}
{{ hostvars[host]['ansible_facts']['eth0']['ipv4']['address'] }} {{ hostvars[host]['ansible_facts']['hostname'] }}
{% endfor %}
[ansible@node1 ~]$ vim apache.yml
- hosts: all
tasks:
- name: create hosts
template:
src: test.j2
dest: /tmp/hosts
tags: hosts
[ansible@node1 ~]$ ansible-playbook apache.yml -t hosts
创建成功,node2上查看
9.yml文件部署haproxy
[ansible@node1 ~]$ cat hosts #主机的分组
[balance]
node1
[test]
node2
[prod]
node3 web=http
[webserver:children]
test
prod
[webserver:vars]
http_port=80
[ansible@node1 ~]$ vim haproxy.cfg.j2 #用魔术变量编辑配置文件
frontend main *:80
default_backend app
backend app
balance roundrobin
{% for host in groups['webserver'] %}
server {{ hostvars[host]['ansible_facts']['hostname'] }} {{ hostvars[host]['ansible_facts']['eth0']['ipv4']['address'] }}:80
{% endfor %}
[ansible@node1 ~]$ vim apache.yml
- hosts: all
tasks:
- name: install haproxy
yum:
name: haproxy
state: present
when: ansible_hostname == 'node1'
- name: config haproxy
template:
src: haproxy.cfg.j2
dest: /etc/haproxy/haproxy.cfg
notify: restart haproxy
when: ansible_hostname == 'node1'
- name: start haproxy
service:
name: haproxy
state: started
when: ansible_hostname == 'node1'
handlers:
- name: restart haproxy
service:
name: haproxy
state: restarted
tags: haproxy
执行
[ansible@node1 ~]$ ansible-playbook apache.yml -t haproxy
[ansible@node1 ~]$ vim haproxy.cfg.j2
测试:
[ansible@node1 ~]$ curl node1
node2
[ansible@node1 ~]$ curl node1
node3
[ansible@node1 ~]$ curl node1
node2
10. block模块
- hosts: all
tasks:
- name: deployment haproxy #下面三个任务合为
block:
- name: install haproxy
yum:
name: haproxy
state: present
- name: config haproxy
template:
src: haproxy.cfg.j2
dest: /etc/haproxy/haproxy.cfg
notify: restart haproxy
- name: start haproxy
service:
name: haproxy
state: started
enabled: yes
when: ansible_hostname == 'node1' #
handlers:
- name: restart haproxy
service:
name: haproxy
state: restarted
tags: haproxy
[ansible@node1 ~]$ ansible-playbook apache.yml -t haproxy
11. rescue ,当上述抛出异常,启用rescue任务
---
- hosts: localhost
become: no
tasks:
- name: localhost date
command: date
register: result
changed_when: false
- name: print name
debug:
var: result.stdout
- hosts: node2
tasks:
- name: deployment apache
block:
- name: install webserver
yum:
name: httpd
state: present
failed_when: yes #抑制更改,更改任务运行后的报告状态,但不会更改任务本身的行为
---
- hosts: localhost
become: no
tasks:
- name: localhost date
command: date
register: result
changed_when: false
- name: print name
debug:
var: result.stdout
- hosts: node2
tasks:
- name: deployment apache
block:
- name: install webserver
yum:
name: httpd
state: present
failed_when: yes
rescue: #当上述任务执行的时候有失败,运行拯救任务
- debug:
msg: rescue is running #拯救措施,此处随便填一条打印信息
12 .ansible-vault 加密
ansible-vault encrypt userlist.yml | 加密 |
ansible-vault view userlist.yml | 查看,需要输入密码 |
ansible-vault decrypt userlist.yml | 解密 |
[ansible@node1 ~]$ ansible-playbook apache.yml -t usercreate --ask-vault-pass #运行包含加密文件的yml的文件时,需要加--ask-vault-pass
13.变量文件推荐的管理方式
- host_vars:存放主机变量
- group_vars:存放主机组变量
- vars: 存放纯文本信息
- vault:存放加密信息
- hosts: test
# vars_files:
# - vars/userlist.yml
tasks:
- name: create user
user:
name: '{{ item.user }}'
password: '{{ item.pd|password_hash("sha512") }}'
loop: "{{ userlist }}"
tags: usercreate
14. 导入与包含任务
(1)导入playbook
[ansible@node1 ~]$ cat play1.yml
---
- hosts: localhost
become: no
tasks:
- name: localhost date
command: date
register: result
changed_when: false
- name: print name
debug:
var: result.stdout
- name: play2.yml
import_playbook: play2.yml
[ansible@node1 ~]$ cat play2.yml
---
- hosts: node3
tasks:
- name: deployment apache
block:
- name: install webserver
yum:
name: httpd
state: present
failed_when: yes
rescue:
- debug:
msg: rescue is running
(2)导入task
静态加载(import_tasks):所有导入进来的变量都会生效
动态加载(include_tasks):按顺序执行,执行到的时候才会生效
[ansible@node1 ~]$ cat play3.yml
---
- hosts: node1
tasks:
- include_tasks: task2.yml #动态加载
when: ansible_os_family == 'RedHat'
[ansible@node1 ~]$ cat task2.yml
---
- set_fact: ansible_os_family='Centos'
- debug:
var: ansible_os_family
[ansible@node1 ~]$ cat play3.yml
---
- hosts: node1
tasks:
- import_tasks: task2.yml #静态加载,加载所有任务变量,所以不会执行task2
- when: ansible_os_family == 'RedHat'
[ansible@node1 ~]$ cat task2.yml
---
- set_fact: ansible_os_family='Centos'
- debug:
var: ansible_os_family