1、简介
1.1 架构图
playbook主要是实现将多个ansible指令进行编排,让它们有顺序,有逻辑 的执行,采用yaml语言编写
playbook 剧本是由一个或多个“play”组成的列表
play 的主要功能在于将预定义的一组主机,装扮成事先通过ansible中的task定义好的角色。Task实际是调用ansible的一个module,将多个play组织在一个playbook中,即可以让它们联合起来,按事先编排的机制执行预定义的动作
1.2 格式
playbook由YMAL语言编写 :
- 1、文件的第一行应该以 “—-“ (三个连字符)开始,表明YMAL文件的开始。
- 2、在同一行中,#之后的内容表示注释,类似于shell,python和ruby。
- 3、YMAL中的列表元素以”-”开头然后紧跟着一个空格,后面为元素内容。
- 4、同一个列表中的元素应该保持相同的缩进。否则会被当做错误处理。
- 5、play中hosts,variables,roles,tasks等对象的表示方法都是键值中间以”:”分隔表示,“:”后面还要增加一个空格。 ```yaml
安装与运行mysql服务
- hosts: node1
remote_user: root
tasks:
- name: install mysql-server package yum: name=mysql-server state=present
- name: starting mysqld service service: name=mysql state=started
转换为json格式如下:
[ { “hosts”:”node1”, “remote_user”:”root”, “tasks”:[ { “name”:”install mysql-server package”, “yum”:”name=mysql-server state=present” }, { “name”:”starting mysqld service”, “service”:”name=mysql state=started” } ] } ]
使用ansible-playbook运行playbook文件,得到如下输出信息,输出内容为JSON格式。并且由不同颜色组成,便于识别。一般而言
- 绿色代表执行成功,系统保持原样
- 黄色代表系统代表系统状态发生改变
- 红色代表执行失败,显示错误输出
执行有三个步骤:1、收集facts 2、执行tasks 3、报告结果
<a name="Y4Xjl"></a>
# 2、核心元素
| 核心元素 | 作用 |
| --- | --- |
| Hosts | 主机列表 |
| Remoter_user,su sudo | 执行远程主机任务的用户 |
| Tasks | 任务列表 |
| Variables | 内置变量或自定义变量 |
| Templates | 模板文本 |
| Handlers,notify | 特定条件触发的操作,满足条件方才执行,否则不执行 |
| Tag | 标记式运行 |
<a name="xVcKa"></a>
## 2.1 hosts
- 使用 hosts 指示使用哪个主机或主机组来运行下面的 tasks ,每个 playbook 都必须指定 hosts
- 可以使用通配符格式,如:- hosts: websrvs:appsrvs
- Websrvs:dbsrvs # 或,两个组的并集
- Websrvs:&dbsrvs # 与,两个组的交集
- webservers:!dbsrvs # 非,在websrvs组,但不在dbsrvs组
- 加上`-i`选项,指定清单的位置即
<a name="o98rh"></a>
## 2.2 remote_user
可用于Host和task中。也可以通过指定其通过sudo的方式在远程主机上执行任务,其可用于play全局或某任务;此外,甚至可以在sudo时使用sudo_user指定sudo时切换的用户
```yaml
---
- hosts: websrvs
remote_user: root
tasks:
- name: test connection
ping:
remote_user: magedu
sudo: yes # 默认sudo为root
sudo_user: wang # sudo为wang
2.3 tasks
play的主体部分是task list,task list中有一个或多个task,各个task 按次序逐个在hosts中指定的所有主机上执行,即在所有主机上完成第一个task后,再开始第二个task。
task的目的是使用指定的参数执行模块,而在模块参数中可以使用变量。模块执行是幂等的,这意味着多次执行是安全的,因为其结果均一致。
---
- hosts: websrvs
remote_user: root
tasks:
- name: install httpd
yum: name=httpd
- name: start httpd
service: name=httpd state=started enabled=yes
3、命令相关
3.1 基础命令
ansible-playbook <filename.yml> ... [options]
-C --check #只检测可能会发生的改变,但不真正执行操作
--list-hosts #列出运行任务的主机
--list-tags #列出tag
--list-tasks #列出task
--limit 主机列表 #只针对主机列表中的主机执行
-v -vv -vvv #显示过程
ansible-playbook yml_name --syntax-host #检测语法错误
ansible-playbook yml_name --list-host #列出运行任务的主机
ansible-playbook yml_name --list-task #列出任务
ansible-playbook -t TAG_NAME PATH #运行playbook中指定的TAG
3.2 shell VS palybook
##### SHELL脚本实现 #####
#!/bin/bash
# 安装Apache
yum install --quiet -y httpd
# 复制配置文件
cp /tmp/httpd.conf /etc/httpd/conf/httpd.conf
cp /tmp/vhosts.conf /etc/httpd/conf.d/
# 启动Apache,并设置开机启动
systemctl enable --now httpd
##### Playbook实现 #####
---
- hosts: websrvs
remote_user: root
tasks:
- name: "安装Apache"
yum: name=httpd
- name: "复制配置文件"
copy: src=/tmp/httpd.conf dest=/etc/httpd/conf/
- name: "复制配置文件"
copy: src=/tmp/vhosts.conf dest=/etc/httpd/conf.d/
- name: "启动Apache,并设置开机启动"
service: name=httpd state=started enabled=yes
4、实战案例
4.1 新增用户
利用 playbook 创建 mysql 用户
---
- hosts: tx
remote_user: root
tasks:
- {name: create group, group: name=mysql system=yes gid=306}
- name: create user
user: name=mysql shell=/sbin/nologin system=yes group=mysql uid=306 home=/data/mysql create_home=no
4.2 安装 nginx
---
- hosts: tx
remote_user: root
tasks:
- name: add group nginx
group: name=nginx state=present
- name: add user nginx
user: name=nginx state=present group=nginx
- name: install nginx
yum: name=nginx state=present
- name: copy nginx.conf
copy: src=/tmp/nginx.conf dest=/etc/nginx/nginx.conf backup=yes
notify: reload #当nginx.conf发生改变时,通知给相应的handlers
tags: reloadnginx #打标签
- name: start nginx service
service: name=nginx state=started
tags: startnginx #打标签
handlers: #注意,前面没有-,是两个空格
- name: reload
service: name=nginx state=restarted #为了在进程中能看出来
# 执行palybook
ansible-playbook nginx.yml
# 查看端口
ansible web -m shell -a 'ss -nutlp |grep nginx'
# 引用标签
ansible-playbook nginx.yml -t startnginx
## 测试notify
# 修改配置文件
vim /tmp/nginx.conf # 修改监听端口
# 重新加载
ansible-playbook nginx.yml -t reloadnginx
# 发现监听端口已改变
4.3 安装卸载 httpd
---
#install httpd
- hosts: tx
remote_user: root
gather_facts: no
tasks:
- name: Install httpd
yum: name=httpd state=present
- name: Install configure file
copy: src=files/httpd.conf dest=/etc/httpd/conf/
- name: web html
copy: src=files/index.html dest=/var/www/html/
- name: start service
service: name=httpd state=started enabled=yes
ansible-playbook install_httpd.yml --limit 42.193.0.74
#remove_httpd.yml
---
- hosts: tx
remote_user: root
tasks:
- name: remove httpd package
yum: name=httpd state=absent
- name: remove apache user
user: name=apache state=absent
- name: remove config file
file: name=/etc/httpd state=absent
- name: remove web html
file: name=/var/www/html/index.html state=absent
4.4 安装 nfs
- hosts: 172.27.0.10
tasks:
- name: install nfs server
yum: name=nfs-utils state=present
- name: configure nfs server
copy: src=./exports.j2 dest=/etc/exports
- name: create directory for mount
file: path=/nfs_server state=directory
- name: create nfs group
group: name=www gid=1021
- name: create nfs user
user: name=www uid=1021 group=www
- name: start nfs server
service: name=nfs.service enabled=yes state=started
- hosts: 172.27.0.11
tasks:
- name: create mount directory
file: path=/nfs_client state=directory
- name: mount nfs_server
mount: src=172.27.0.10:/nfs_server path=/nfs_client opts=defaults fstype=nfs state=present
#客户端验证
df -hP
5、变量
5.1 变量使用
变量名:仅能由字母、数字和下划线组成,且只能以字母开头。
通过 {{ variable_name }} 调用变量,且变量名前后建议加空格,有时用“{{ variable_name }}”才生效
5.2 变量定义
5.2.1 facts
ansible 的 setup facts 远程主机的所有变量都可直接调用
[root@hchost ~]# ansible hw10 -m setup -a filter="ansible_default_ipv4"
[WARNING]: Invalid characters were found in group names but not replaced, use -vvvv to see details
124.71.193.36 | SUCCESS => {
"ansible_facts": {
"ansible_default_ipv4": {
"address": "192.168.0.10",
"alias": "eth0",
"broadcast": "192.168.0.255",
"gateway": "192.168.0.1",
"interface": "eth0",
"macaddress": "fa:16:3e:c4:61:11",
"mtu": 1500,
"netmask": "255.255.255.0",
"network": "192.168.0.0",
"type": "ether"
},
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false
}
# yml 格式如下
- hosts: hw10
remote_user: root
tasks:
- name: look up internal variable
#注意括号与变量名中间的空格
copy: content={{ ansible_default_ipv4 }} dest=/tmp/ansible.variable
5.2.2 命令行指定变量
通过命令行指定变量,优先级最高
使用-e VARS,--extra-vars=VARS来指定,使用key:value格式指定
ansible-playbook -e varname=value
[root@hchost ~]# vim install_package.yaml
- hosts: hw10
remote_user: root
tasks:
- name: install {{ package_name }}
yum: name={{ package_name }} state=installed
# package_name 会替换为nginx
[root@hchost ~]# ansible-playbook -e package_name=nginx install_package.yaml
5.2.3 playbook中自定义变量
1. 在playbook文件中定义
vars:
- var1: value1
- var2: value2
2. 在独立的变量YAML文件中定义
- hosts: all
vars_files:
- vars.yml
[root@hchost ~]# vim pb_var.yaml
- hosts: hw10
remote_user: root
vars: #定义变量
#变量是同一类元素,用列表,表示方法,key:value
- pb: palybook variable
tasks:
- name: palybook variable
copy: content={{ pb }} dest=/tmp/pb.var
[root@hchost ~]# ansible hw10 -m shell -a 'cat /tmp/pb.var' #查看变量名称是否正确
192.168.0.10 | CHANGED | rc=0 >>
palybook variable
5.2.4 Host Inventory
通过主机清单定义变量
- Inventory参数,用于定义 ansible 连接远程主机时使用的参数
主机清单自定义变量
| Inventory参数 | 作用 | | —- | —- | | ansible_ssh_host | 定义远程连接的主机 | | ansible_ssh_port | 远程连接的主机的端口 | | ansible_ssh_user | 远程连接登录的用户 | | ansible_ssh_pass | 远程连接登录的密码 | | ansible_sudo_pass | 远程连接提权密码 |主机(普通)变量:主机组中主机单独定义,优先级高于公共变量
- 组(公共)变量:针对主机组中所有主机定义统一变量
```yaml
向不同的主机传递不同的变量
IP/HOSTNAME varaiable=value var2=value2
向组中的主机传递相同的变量:
[groupname:vars] variable=value
```yaml
vim /etc/ansible/hosts
[web_server]
192.168.10.12 ipaddr=192.168.10.12 #ipaddr为主机清单自定义变量
192.168.10.13 ipaddr=192.168.10.13
[web_server]
domain=abc.com #自定义组变量
#将变量存在目标主机
[root@hchost ~]# ansible all -m copy -a 'content={{ ipaddr }} dest=/tmp/host.var'
#查看变量内容
[root@hchost ~]# ansible all -m shell -a 'cat /tmp/host.var'
192.168.10.13 | CHANGED | rc=0 >>
192.168.10.13
192.168.10.12 | CHANGED | rc=0 >>
192.168.10.12
6、模板
6.1 模板介绍
模板是一个文本文件,可以做为生成文件的模版,并且模板文件中还可嵌套 jinja 语法。Jinja2
:Jinja2是python的一种模板语言,以Django的模板语言为原本。
模板支持:
字符串:使用单引号或双引号; 数字:整数,浮点数; 列表:[item1, item2, …] 元组:(item1, item2, …) 字典:{key1:value1, key2:value2, …} 布尔型:true/false 算术运算: +, -, , /, //, %, * 比较操作: ==, !=, >, >=, <, <= 逻辑运算: and, or, not
通常来说,模板都是通过引用变量来运用的。
- template 功能:可以根据和参考模块文件,动态生成相类似的配置文件
- template 文件必须存放于templates目录下,且命名为 .j2 结尾
- yaml/yml 文件需和templates目录平级,目录结构如下示例:
./
├── temnginx.yml
└── templates
└── nginx.conf.j2
6.2 同步nginx配置文件
#准备templates/nginx.conf.j2文件
vim tem_nginx.yml
---
- hosts: websrvs
remote_user: root
tasks:
- name: template config to remote hosts
template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf
ansible-playbook tem_nginx.yml
#修改文件nginx.conf.j2
mkdir templates
vim templates/nginx.conf.j2
worker_processes {{ ansible_processor_vcpus }};
vim tem_nginx2.yml
---
- hosts: websrvs
remote_user: root
tasks:
- name: install nginx
yum: name=nginx
- name: template config to remote hosts
template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf
- name: start service
service: name=nginx state=started enable=yes
ansible-playbook tem_nginx2.yml
# template算术运算
[root@ansible ansible]#vim templates/nginx.conf.j2
worker_processes {{ ansible_processor_vcpus**2 }};
# worker_processes {{ ansible_processor_vcpus+2 }};
[root@ansible ansible]#cat templnginx.yml
---
- hosts: websrvs
remote_user: root
tasks:
- name: install nginx
yum: name=nginx
- name: template config to remote hosts
template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf
notify: restart nginx
- name: start service
service: name=nginx state=started enabled=yes
handlers:
- name: restart nginx
service: name=nginx state=restarted
ansible-playbook templnginx.yml --limit 192.168.0.10
6.3 流程控制 for 和 if
#templnginx5.yml
- hosts: websrvs
remote_user: root
vars:
nginx_vhosts:
- web1:
listen: 8080
root: "/var/www/nginx/web1/"
- web2:
listen: 8080
server_name: "web2.magedu.com"
root: "/var/www/nginx/web2/"
- web3:
listen: 8080
server_name: "web3.magedu.com"
root: "/var/www/nginx/web3/"
tasks:
- name: template config to
template: src=nginx.conf5.j2 dest=/data/nginx5.conf
#templates/nginx.conf5.j2
{% for vhost in nginx_vhosts %}
server {
listen {{ vhost.listen }}
{% if vhost.server_name is defined %} # 决定是否生成相关的配置信息
server_name {{ vhost.server_name }}
{% endif %}
root {{ vhost.root }}
}
{% endfor %}
ansible-playbook templnginx5.yml --limit 192.168.0.10
#生成的结果
server {
listen 8080
root /var/www/nginx/web1/
}
server {
listen 8080
server_name web2.magedu.com
root /var/www/nginx/web2/
}
server {
listen 8080
server_name web3.magedu.com
root /var/www/nginx/web3/
}
6.4 when 和 循环 with_items
when语句,可以实现条件测试。
如果需要根据变量、facts或此前任务的执行结果来做为某task执行与否的前提时要用到条件测试,通过在task后添加when子句即可使用条件测试,jinja2的语法格式
#需求:当系统是Centos7安装mariadb,Centos6安装mysql
# 1.使用ansible setup模块获取版本信息
"ansible_distribution_major_version": "7"
# 2.编写playbook
- hosts: all
remote_user: root
tasks:
- name: install mariadb
yum: name=mariadb state=installed
when: ansible_distribution_major_version == "7" #测试当前系统版本信息
- name: install mysql
yum: name=mysql state=installed
when: ansible_distribution_major_version == "6"
使用迭代 with_items
迭代:当有需要重复性执行的任务时,可以使用迭代机制
对迭代项的引用,固定变量名为”item“
要在task中使用with_items给定要迭代的元素列表
列表元素格式:
- 字符串
- 字典
cat with_item1.yml
---
- hosts: websrvs
remote_user: root
tasks:
- name: add several users
user: name={{ item }} state=present groups=wheel
with_items:
- testuser1
- testuser2
#上面语句的功能等同于下面的语句
- name: add user testuser1
user: name=testuser1 state=present groups=wheel
- name: add user testuser2
user: name=testuser2 state=present groups=wheel
cat with_item2.yml
---
- hosts: websrvs
remote_user: root
tasks:
- name: add some groups
group: name={{ item }} state=present
with_items:
- g1
- g2
- g3
- name: add some users
user: name={{ item.name }} group={{ item.group }} home={{ item.home }} create_home=yes state=present
with_items:
- { name: 'user1', group: 'g1', home: '/data/user1' }
- { name: 'user2', group: 'g2', home: '/data/user2' }
- { name: 'user3', group: 'g3', home: '/data/user3' }